summaryrefslogtreecommitdiff
path: root/packages/linux/linux-2.6.18/gpio-dev-blocking-read.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/linux-2.6.18/gpio-dev-blocking-read.patch')
-rw-r--r--packages/linux/linux-2.6.18/gpio-dev-blocking-read.patch187
1 files changed, 187 insertions, 0 deletions
diff --git a/packages/linux/linux-2.6.18/gpio-dev-blocking-read.patch b/packages/linux/linux-2.6.18/gpio-dev-blocking-read.patch
new file mode 100644
index 0000000000..9508d9e3aa
--- /dev/null
+++ b/packages/linux/linux-2.6.18/gpio-dev-blocking-read.patch
@@ -0,0 +1,187 @@
+---
+ arch/avr32/mach-at32ap/pio.c | 113 +++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 113 insertions(+)
+
+Index: linux-2.6.18-avr32/arch/avr32/mach-at32ap/pio.c
+===================================================================
+--- linux-2.6.18-avr32.orig/arch/avr32/mach-at32ap/pio.c 2006-11-30 13:16:43.000000000 +0100
++++ linux-2.6.18-avr32/arch/avr32/mach-at32ap/pio.c 2006-11-30 17:15:24.000000000 +0100
+@@ -250,7 +250,11 @@ EXPORT_SYMBOL(gpio_set_value);
+ #ifdef CONFIG_PIO_DEV
+ #include <linux/configfs.h>
+ #include <linux/cdev.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/poll.h>
+ #include <linux/uaccess.h>
++#include <linux/wait.h>
+
+ #define GPIO_DEV_MAX 8
+
+@@ -267,6 +271,13 @@ struct gpio_item {
+ u32 pin_mask;
+ u32 oe_mask;
+
++ /* Pin state last time we read it (for blocking reads) */
++ u32 pin_state;
++ int changed;
++
++ wait_queue_head_t change_wq;
++ struct fasync_struct *async_queue;
++
+ int id;
+ struct class_device *gpio_dev;
+ struct cdev char_dev;
+@@ -279,36 +290,135 @@ struct gpio_attribute {
+ ssize_t (*store)(struct gpio_item *, const char *, size_t);
+ };
+
++static irqreturn_t gpio_dev_interrupt(int irq, void *dev_id,
++ struct pt_regs *regs)
++{
++ struct gpio_item *gpio = dev_id;
++ u32 old_state, new_state;
++
++ old_state = gpio->pin_state;
++ new_state = pio_readl(gpio->pio, PDSR);
++ gpio->pin_state = new_state;
++
++ if (new_state != old_state) {
++ gpio->changed = 1;
++ wake_up_interruptible(&gpio->change_wq);
++
++ if (gpio->async_queue)
++ kill_fasync(&gpio->async_queue, SIGIO, POLL_IN);
++ }
++
++ return IRQ_HANDLED;
++}
++
+ static int gpio_dev_open(struct inode *inode, struct file *file)
+ {
+ struct gpio_item *gpio = container_of(inode->i_cdev,
+ struct gpio_item,
+ char_dev);
++ unsigned int irq;
++ unsigned int i;
++ int ret;
+
++ nonseekable_open(inode, file);
+ config_item_get(&gpio->item);
+ file->private_data = gpio;
++
++ gpio->pin_state = pio_readl(gpio->pio, PDSR) & gpio->pin_mask;
++ gpio->changed = 1;
++
++ for (i = 0; i < 32; i++) {
++ if (gpio->pin_mask & (1 << i)) {
++ irq = gpio_to_irq(32 * pio_id(gpio->pio) + i);
++ ret = request_irq(irq, gpio_dev_interrupt, 0,
++ "gpio-dev", gpio);
++ if (ret)
++ goto err_irq;
++ }
++ }
++
+ return 0;
++
++err_irq:
++ while (i--) {
++ if (gpio->pin_mask & (1 << i)) {
++ irq = gpio_to_irq(32 * pio_id(gpio->pio) + i);
++ free_irq(irq, gpio);
++ }
++ }
++
++ config_item_put(&gpio->item);
++
++ return ret;
++}
++
++static int gpio_dev_fasync(int fd, struct file *file, int mode)
++{
++ struct gpio_item *gpio = file->private_data;
++
++ return fasync_helper(fd, file, mode, &gpio->async_queue);
+ }
+
+ static int gpio_dev_release(struct inode *inode, struct file *file)
+ {
+ struct gpio_item *gpio = file->private_data;
++ unsigned int irq;
++ unsigned int i;
++
++ gpio_dev_fasync(-1, file, 0);
++
++ for (i = 0; i < 32; i++) {
++ if (gpio->pin_mask & (1 << i)) {
++ irq = gpio_to_irq(32 * pio_id(gpio->pio) + i);
++ free_irq(irq, gpio);
++ }
++ }
+
+ config_item_put(&gpio->item);
++
+ return 0;
+ }
+
++static unsigned int gpio_dev_poll(struct file *file, poll_table *wait)
++{
++ struct gpio_item *gpio = file->private_data;
++ unsigned int mask = 0;
++
++ poll_wait(file, &gpio->change_wq, wait);
++ if (gpio->changed)
++ mask |= POLLIN | POLLRDNORM;
++
++ return mask;
++}
++
+ static ssize_t gpio_dev_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offset)
+ {
+ struct gpio_item *gpio = file->private_data;
+ u32 value;
+
++ spin_lock_irq(&gpio->lock);
++ while (!gpio->changed) {
++ spin_unlock_irq(&gpio->lock);
++
++ if (file->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++
++ if (wait_event_interruptible(gpio->change_wq, gpio->changed))
++ return -ERESTARTSYS;
++
++ spin_lock_irq(&gpio->lock);
++ }
++
++ gpio->changed = 0;
+ value = pio_readl(gpio->pio, PDSR) & gpio->pin_mask;
+
++ spin_unlock_irq(&gpio->lock);
++
+ count = min(count, (size_t)4);
+ if (copy_to_user(buf, &value, count))
+ return -EFAULT;
++
+ return count;
+ }
+
+@@ -338,6 +448,8 @@ static struct file_operations gpio_dev_f
+ .llseek = no_llseek,
+ .open = gpio_dev_open,
+ .release = gpio_dev_release,
++ .fasync = gpio_dev_fasync,
++ .poll = gpio_dev_poll,
+ .read = gpio_dev_read,
+ .write = gpio_dev_write,
+ };
+@@ -632,6 +744,7 @@ static struct config_item *gpio_make_ite
+ gpio->id = next_id++;
+ config_item_init_type_name(&gpio->item, name, &gpio_item_type);
+ spin_lock_init(&gpio->lock);
++ init_waitqueue_head(&gpio->change_wq);
+
+ return &gpio->item;
+ }