diff options
Diffstat (limited to 'arch/cris')
-rw-r--r-- | arch/cris/arch-v10/drivers/gpio.c | 80 |
1 files changed, 48 insertions, 32 deletions
diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c index 080927f..a07b6d2 100644 --- a/arch/cris/arch-v10/drivers/gpio.c +++ b/arch/cris/arch-v10/drivers/gpio.c @@ -16,7 +16,6 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/fs.h> -#include <linux/smp_lock.h> #include <linux/string.h> #include <linux/poll.h> #include <linux/init.h> @@ -46,7 +45,7 @@ static char gpio_name[] = "etrax gpio"; static wait_queue_head_t *gpio_wq; #endif -static int gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg); static ssize_t gpio_write(struct file *file, const char __user *buf, size_t count, loff_t *off); static int gpio_open(struct inode *inode, struct file *filp); @@ -323,7 +322,6 @@ gpio_open(struct inode *inode, struct file *filp) if (!priv) return -ENOMEM; - lock_kernel(); priv->minor = p; /* initialize the io/alarm struct */ @@ -358,7 +356,6 @@ gpio_open(struct inode *inode, struct file *filp) alarmlist = priv; spin_unlock_irqrestore(&gpio_lock, flags); - unlock_kernel(); return 0; } @@ -503,8 +500,7 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg); -static int -gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) +static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { unsigned long flags; unsigned long val; @@ -514,54 +510,65 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) return -EINVAL; - spin_lock_irqsave(&gpio_lock, flags); - switch (_IOC_NR(cmd)) { case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ // read the port + spin_lock_irqsave(&gpio_lock, flags); if (USE_PORTS(priv)) { ret = *priv->port; } else if (priv->minor == GPIO_MINOR_G) { ret = (*R_PORT_G_DATA) & 0x7FFFFFFF; } + spin_unlock_irqrestore(&gpio_lock, flags); + break; case IO_SETBITS: // set changeable bits with a 1 in arg + spin_lock_irqsave(&gpio_lock, flags); + if (USE_PORTS(priv)) { - *priv->port = *priv->shadow |= + *priv->port = *priv->shadow |= ((unsigned char)arg & priv->changeable_bits); } else if (priv->minor == GPIO_MINOR_G) { *R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits); } + spin_unlock_irqrestore(&gpio_lock, flags); + break; case IO_CLRBITS: // clear changeable bits with a 1 in arg + spin_lock_irqsave(&gpio_lock, flags); if (USE_PORTS(priv)) { - *priv->port = *priv->shadow &= + *priv->port = *priv->shadow &= ~((unsigned char)arg & priv->changeable_bits); } else if (priv->minor == GPIO_MINOR_G) { *R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits); } + spin_unlock_irqrestore(&gpio_lock, flags); break; case IO_HIGHALARM: // set alarm when bits with 1 in arg go high + spin_lock_irqsave(&gpio_lock, flags); priv->highalarm |= arg; gpio_some_alarms = 1; + spin_unlock_irqrestore(&gpio_lock, flags); break; case IO_LOWALARM: // set alarm when bits with 1 in arg go low + spin_lock_irqsave(&gpio_lock, flags); priv->lowalarm |= arg; gpio_some_alarms = 1; + spin_unlock_irqrestore(&gpio_lock, flags); break; case IO_CLRALARM: - // clear alarm for bits with 1 in arg + /* clear alarm for bits with 1 in arg */ + spin_lock_irqsave(&gpio_lock, flags); priv->highalarm &= ~arg; priv->lowalarm &= ~arg; { /* Must update gpio_some_alarms */ struct gpio_private *p = alarmlist; int some_alarms; - spin_lock_irq(&gpio_lock); p = alarmlist; some_alarms = 0; while (p) { @@ -572,11 +579,12 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) p = p->next; } gpio_some_alarms = some_alarms; - spin_unlock_irq(&gpio_lock); } + spin_unlock_irqrestore(&gpio_lock, flags); break; case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ /* Read direction 0=input 1=output */ + spin_lock_irqsave(&gpio_lock, flags); if (USE_PORTS(priv)) { ret = *priv->dir_shadow; } else if (priv->minor == GPIO_MINOR_G) { @@ -585,30 +593,40 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) */ ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; } + spin_unlock_irqrestore(&gpio_lock, flags); break; case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ - /* Set direction 0=unchanged 1=input, - * return mask with 1=input + /* Set direction 0=unchanged 1=input, + * return mask with 1=input */ + spin_lock_irqsave(&gpio_lock, flags); ret = setget_input(priv, arg) & 0x7FFFFFFF; + spin_unlock_irqrestore(&gpio_lock, flags); break; case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ - /* Set direction 0=unchanged 1=output, - * return mask with 1=output + /* Set direction 0=unchanged 1=output, + * return mask with 1=output */ + spin_lock_irqsave(&gpio_lock, flags); ret = setget_output(priv, arg) & 0x7FFFFFFF; + spin_unlock_irqrestore(&gpio_lock, flags); break; case IO_SHUTDOWN: + spin_lock_irqsave(&gpio_lock, flags); SOFT_SHUTDOWN(); + spin_unlock_irqrestore(&gpio_lock, flags); break; case IO_GET_PWR_BT: + spin_lock_irqsave(&gpio_lock, flags); #if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); #else ret = 0; #endif + spin_unlock_irqrestore(&gpio_lock, flags); break; case IO_CFG_WRITE_MODE: + spin_lock_irqsave(&gpio_lock, flags); priv->clk_mask = arg & 0xFF; priv->data_mask = (arg >> 8) & 0xFF; priv->write_msb = (arg >> 16) & 0x01; @@ -624,28 +642,33 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) priv->data_mask = 0; ret = -EPERM; } + spin_unlock_irqrestore(&gpio_lock, flags); break; - case IO_READ_INBITS: + case IO_READ_INBITS: /* *arg is result of reading the input pins */ + spin_lock_irqsave(&gpio_lock, flags); if (USE_PORTS(priv)) { val = *priv->port; } else if (priv->minor == GPIO_MINOR_G) { val = *R_PORT_G_DATA; } + spin_unlock_irqrestore(&gpio_lock, flags); if (copy_to_user((void __user *)arg, &val, sizeof(val))) ret = -EFAULT; break; case IO_READ_OUTBITS: /* *arg is result of reading the output shadow */ + spin_lock_irqsave(&gpio_lock, flags); if (USE_PORTS(priv)) { val = *priv->shadow; } else if (priv->minor == GPIO_MINOR_G) { val = port_g_data_shadow; } + spin_unlock_irqrestore(&gpio_lock, flags); if (copy_to_user((void __user *)arg, &val, sizeof(val))) ret = -EFAULT; break; - case IO_SETGET_INPUT: + case IO_SETGET_INPUT: /* bits set in *arg is set to input, * *arg updated with current input pins. */ @@ -654,7 +677,9 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) ret = -EFAULT; break; } + spin_lock_irqsave(&gpio_lock, flags); val = setget_input(priv, val); + spin_unlock_irqrestore(&gpio_lock, flags); if (copy_to_user((void __user *)arg, &val, sizeof(val))) ret = -EFAULT; break; @@ -666,34 +691,25 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) ret = -EFAULT; break; } + spin_lock_irqsave(&gpio_lock, flags); val = setget_output(priv, val); + spin_unlock_irqrestore(&gpio_lock, flags); if (copy_to_user((void __user *)arg, &val, sizeof(val))) ret = -EFAULT; break; default: + spin_lock_irqsave(&gpio_lock, flags); if (priv->minor == GPIO_MINOR_LEDS) ret = gpio_leds_ioctl(cmd, arg); else ret = -EINVAL; + spin_unlock_irqrestore(&gpio_lock, flags); } /* switch */ - spin_unlock_irqrestore(&gpio_lock, flags); return ret; } static int -gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - long ret; - - lock_kernel(); - ret = gpio_ioctl_unlocked(file, cmd, arg); - unlock_kernel(); - - return ret; -} - -static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg) { unsigned char green; |