gpio: of: Allow overriding the device node
[cascardo/linux.git] / drivers / gpio / gpiolib.c
index d407f90..6dc3917 100644 (file)
 #include <linux/cdev.h>
 #include <linux/fs.h>
 #include <linux/uaccess.h>
+#include <linux/compat.h>
+#include <linux/anon_inodes.h>
+#include <linux/kfifo.h>
+#include <linux/poll.h>
+#include <linux/timekeeping.h>
 #include <uapi/linux/gpio.h>
 
 #include "gpiolib.h"
@@ -309,6 +314,497 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
        return 0;
 }
 
+/*
+ * GPIO line handle management
+ */
+
+/**
+ * struct linehandle_state - contains the state of a userspace handle
+ * @gdev: the GPIO device the handle pertains to
+ * @label: consumer label used to tag descriptors
+ * @descs: the GPIO descriptors held by this handle
+ * @numdescs: the number of descriptors held in the descs array
+ */
+struct linehandle_state {
+       struct gpio_device *gdev;
+       const char *label;
+       struct gpio_desc *descs[GPIOHANDLES_MAX];
+       u32 numdescs;
+};
+
+static long linehandle_ioctl(struct file *filep, unsigned int cmd,
+                            unsigned long arg)
+{
+       struct linehandle_state *lh = filep->private_data;
+       void __user *ip = (void __user *)arg;
+       struct gpiohandle_data ghd;
+       int i;
+
+       if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
+               int val;
+
+               /* TODO: check if descriptors are really input */
+               for (i = 0; i < lh->numdescs; i++) {
+                       val = gpiod_get_value_cansleep(lh->descs[i]);
+                       if (val < 0)
+                               return val;
+                       ghd.values[i] = val;
+               }
+
+               if (copy_to_user(ip, &ghd, sizeof(ghd)))
+                       return -EFAULT;
+
+               return 0;
+       } else if (cmd == GPIOHANDLE_SET_LINE_VALUES_IOCTL) {
+               int vals[GPIOHANDLES_MAX];
+
+               /* TODO: check if descriptors are really output */
+               if (copy_from_user(&ghd, ip, sizeof(ghd)))
+                       return -EFAULT;
+
+               /* Clamp all values to [0,1] */
+               for (i = 0; i < lh->numdescs; i++)
+                       vals[i] = !!ghd.values[i];
+
+               /* Reuse the array setting function */
+               gpiod_set_array_value_complex(false,
+                                             true,
+                                             lh->numdescs,
+                                             lh->descs,
+                                             vals);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+#ifdef CONFIG_COMPAT
+static long linehandle_ioctl_compat(struct file *filep, unsigned int cmd,
+                            unsigned long arg)
+{
+       return linehandle_ioctl(filep, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static int linehandle_release(struct inode *inode, struct file *filep)
+{
+       struct linehandle_state *lh = filep->private_data;
+       struct gpio_device *gdev = lh->gdev;
+       int i;
+
+       for (i = 0; i < lh->numdescs; i++)
+               gpiod_free(lh->descs[i]);
+       kfree(lh->label);
+       kfree(lh);
+       put_device(&gdev->dev);
+       return 0;
+}
+
+static const struct file_operations linehandle_fileops = {
+       .release = linehandle_release,
+       .owner = THIS_MODULE,
+       .llseek = noop_llseek,
+       .unlocked_ioctl = linehandle_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = linehandle_ioctl_compat,
+#endif
+};
+
+static int linehandle_create(struct gpio_device *gdev, void __user *ip)
+{
+       struct gpiohandle_request handlereq;
+       struct linehandle_state *lh;
+       int fd, i, ret;
+
+       if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
+               return -EFAULT;
+       if ((handlereq.lines == 0) || (handlereq.lines > GPIOHANDLES_MAX))
+               return -EINVAL;
+
+       lh = kzalloc(sizeof(*lh), GFP_KERNEL);
+       if (!lh)
+               return -ENOMEM;
+       lh->gdev = gdev;
+       get_device(&gdev->dev);
+
+       /* Make sure this is terminated */
+       handlereq.consumer_label[sizeof(handlereq.consumer_label)-1] = '\0';
+       if (strlen(handlereq.consumer_label)) {
+               lh->label = kstrdup(handlereq.consumer_label,
+                                   GFP_KERNEL);
+               if (!lh->label) {
+                       ret = -ENOMEM;
+                       goto out_free_lh;
+               }
+       }
+
+       /* Request each GPIO */
+       for (i = 0; i < handlereq.lines; i++) {
+               u32 offset = handlereq.lineoffsets[i];
+               u32 lflags = handlereq.flags;
+               struct gpio_desc *desc;
+
+               desc = &gdev->descs[offset];
+               ret = gpiod_request(desc, lh->label);
+               if (ret)
+                       goto out_free_descs;
+               lh->descs[i] = desc;
+
+               if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
+                       set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+               if (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN)
+                       set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+               if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
+                       set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+
+               /*
+                * Lines have to be requested explicitly for input
+                * or output, else the line will be treated "as is".
+                */
+               if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
+                       int val = !!handlereq.default_values[i];
+
+                       ret = gpiod_direction_output(desc, val);
+                       if (ret)
+                               goto out_free_descs;
+               } else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
+                       ret = gpiod_direction_input(desc);
+                       if (ret)
+                               goto out_free_descs;
+               }
+               dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
+                       offset);
+       }
+       /* Let i point at the last handle */
+       i--;
+       lh->numdescs = handlereq.lines;
+
+       fd = anon_inode_getfd("gpio-linehandle",
+                             &linehandle_fileops,
+                             lh,
+                             O_RDONLY | O_CLOEXEC);
+       if (fd < 0) {
+               ret = fd;
+               goto out_free_descs;
+       }
+
+       handlereq.fd = fd;
+       if (copy_to_user(ip, &handlereq, sizeof(handlereq))) {
+               ret = -EFAULT;
+               goto out_free_descs;
+       }
+
+       dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
+               lh->numdescs);
+
+       return 0;
+
+out_free_descs:
+       for (; i >= 0; i--)
+               gpiod_free(lh->descs[i]);
+       kfree(lh->label);
+out_free_lh:
+       kfree(lh);
+       put_device(&gdev->dev);
+       return ret;
+}
+
+/*
+ * GPIO line event management
+ */
+
+/**
+ * struct lineevent_state - contains the state of a userspace event
+ * @gdev: the GPIO device the event pertains to
+ * @label: consumer label used to tag descriptors
+ * @desc: the GPIO descriptor held by this event
+ * @eflags: the event flags this line was requested with
+ * @irq: the interrupt that trigger in response to events on this GPIO
+ * @wait: wait queue that handles blocking reads of events
+ * @events: KFIFO for the GPIO events
+ * @read_lock: mutex lock to protect reads from colliding with adding
+ * new events to the FIFO
+ */
+struct lineevent_state {
+       struct gpio_device *gdev;
+       const char *label;
+       struct gpio_desc *desc;
+       u32 eflags;
+       int irq;
+       wait_queue_head_t wait;
+       DECLARE_KFIFO(events, struct gpioevent_data, 16);
+       struct mutex read_lock;
+};
+
+static unsigned int lineevent_poll(struct file *filep,
+                                  struct poll_table_struct *wait)
+{
+       struct lineevent_state *le = filep->private_data;
+       unsigned int events = 0;
+
+       poll_wait(filep, &le->wait, wait);
+
+       if (!kfifo_is_empty(&le->events))
+               events = POLLIN | POLLRDNORM;
+
+       return events;
+}
+
+
+static ssize_t lineevent_read(struct file *filep,
+                             char __user *buf,
+                             size_t count,
+                             loff_t *f_ps)
+{
+       struct lineevent_state *le = filep->private_data;
+       unsigned int copied;
+       int ret;
+
+       if (count < sizeof(struct gpioevent_data))
+               return -EINVAL;
+
+       do {
+               if (kfifo_is_empty(&le->events)) {
+                       if (filep->f_flags & O_NONBLOCK)
+                               return -EAGAIN;
+
+                       ret = wait_event_interruptible(le->wait,
+                                       !kfifo_is_empty(&le->events));
+                       if (ret)
+                               return ret;
+               }
+
+               if (mutex_lock_interruptible(&le->read_lock))
+                       return -ERESTARTSYS;
+               ret = kfifo_to_user(&le->events, buf, count, &copied);
+               mutex_unlock(&le->read_lock);
+
+               if (ret)
+                       return ret;
+
+               /*
+                * If we couldn't read anything from the fifo (a different
+                * thread might have been faster) we either return -EAGAIN if
+                * the file descriptor is non-blocking, otherwise we go back to
+                * sleep and wait for more data to arrive.
+                */
+               if (copied == 0 && (filep->f_flags & O_NONBLOCK))
+                       return -EAGAIN;
+
+       } while (copied == 0);
+
+       return copied;
+}
+
+static int lineevent_release(struct inode *inode, struct file *filep)
+{
+       struct lineevent_state *le = filep->private_data;
+       struct gpio_device *gdev = le->gdev;
+
+       free_irq(le->irq, le);
+       gpiod_free(le->desc);
+       kfree(le->label);
+       kfree(le);
+       put_device(&gdev->dev);
+       return 0;
+}
+
+static long lineevent_ioctl(struct file *filep, unsigned int cmd,
+                           unsigned long arg)
+{
+       struct lineevent_state *le = filep->private_data;
+       void __user *ip = (void __user *)arg;
+       struct gpiohandle_data ghd;
+
+       /*
+        * We can get the value for an event line but not set it,
+        * because it is input by definition.
+        */
+       if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
+               int val;
+
+               val = gpiod_get_value_cansleep(le->desc);
+               if (val < 0)
+                       return val;
+               ghd.values[0] = val;
+
+               if (copy_to_user(ip, &ghd, sizeof(ghd)))
+                       return -EFAULT;
+
+               return 0;
+       }
+       return -EINVAL;
+}
+
+#ifdef CONFIG_COMPAT
+static long lineevent_ioctl_compat(struct file *filep, unsigned int cmd,
+                                  unsigned long arg)
+{
+       return lineevent_ioctl(filep, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static const struct file_operations lineevent_fileops = {
+       .release = lineevent_release,
+       .read = lineevent_read,
+       .poll = lineevent_poll,
+       .owner = THIS_MODULE,
+       .llseek = noop_llseek,
+       .unlocked_ioctl = lineevent_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = lineevent_ioctl_compat,
+#endif
+};
+
+static irqreturn_t lineevent_irq_thread(int irq, void *p)
+{
+       struct lineevent_state *le = p;
+       struct gpioevent_data ge;
+       int ret;
+
+       ge.timestamp = ktime_get_real_ns();
+
+       if (le->eflags & GPIOEVENT_REQUEST_BOTH_EDGES) {
+               int level = gpiod_get_value_cansleep(le->desc);
+
+               if (level)
+                       /* Emit low-to-high event */
+                       ge.id = GPIOEVENT_EVENT_RISING_EDGE;
+               else
+                       /* Emit high-to-low event */
+                       ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
+       } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) {
+               /* Emit low-to-high event */
+               ge.id = GPIOEVENT_EVENT_RISING_EDGE;
+       } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
+               /* Emit high-to-low event */
+               ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
+       } else {
+               return IRQ_NONE;
+       }
+
+       ret = kfifo_put(&le->events, ge);
+       if (ret != 0)
+               wake_up_poll(&le->wait, POLLIN);
+
+       return IRQ_HANDLED;
+}
+
+static int lineevent_create(struct gpio_device *gdev, void __user *ip)
+{
+       struct gpioevent_request eventreq;
+       struct lineevent_state *le;
+       struct gpio_desc *desc;
+       u32 offset;
+       u32 lflags;
+       u32 eflags;
+       int fd;
+       int ret;
+       int irqflags = 0;
+
+       if (copy_from_user(&eventreq, ip, sizeof(eventreq)))
+               return -EFAULT;
+
+       le = kzalloc(sizeof(*le), GFP_KERNEL);
+       if (!le)
+               return -ENOMEM;
+       le->gdev = gdev;
+       get_device(&gdev->dev);
+
+       /* Make sure this is terminated */
+       eventreq.consumer_label[sizeof(eventreq.consumer_label)-1] = '\0';
+       if (strlen(eventreq.consumer_label)) {
+               le->label = kstrdup(eventreq.consumer_label,
+                                   GFP_KERNEL);
+               if (!le->label) {
+                       ret = -ENOMEM;
+                       goto out_free_le;
+               }
+       }
+
+       offset = eventreq.lineoffset;
+       lflags = eventreq.handleflags;
+       eflags = eventreq.eventflags;
+
+       /* This is just wrong: we don't look for events on output lines */
+       if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
+               ret = -EINVAL;
+               goto out_free_label;
+       }
+
+       desc = &gdev->descs[offset];
+       ret = gpiod_request(desc, le->label);
+       if (ret)
+               goto out_free_desc;
+       le->desc = desc;
+       le->eflags = eflags;
+
+       if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
+               set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+       if (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN)
+               set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+       if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
+               set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+
+       ret = gpiod_direction_input(desc);
+       if (ret)
+               goto out_free_desc;
+
+       le->irq = gpiod_to_irq(desc);
+       if (le->irq <= 0) {
+               ret = -ENODEV;
+               goto out_free_desc;
+       }
+
+       if (eflags & GPIOEVENT_REQUEST_RISING_EDGE)
+               irqflags |= IRQF_TRIGGER_RISING;
+       if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE)
+               irqflags |= IRQF_TRIGGER_FALLING;
+       irqflags |= IRQF_ONESHOT;
+       irqflags |= IRQF_SHARED;
+
+       INIT_KFIFO(le->events);
+       init_waitqueue_head(&le->wait);
+       mutex_init(&le->read_lock);
+
+       /* Request a thread to read the events */
+       ret = request_threaded_irq(le->irq,
+                       NULL,
+                       lineevent_irq_thread,
+                       irqflags,
+                       le->label,
+                       le);
+       if (ret)
+               goto out_free_desc;
+
+       fd = anon_inode_getfd("gpio-event",
+                             &lineevent_fileops,
+                             le,
+                             O_RDONLY | O_CLOEXEC);
+       if (fd < 0) {
+               ret = fd;
+               goto out_free_irq;
+       }
+
+       eventreq.fd = fd;
+       if (copy_to_user(ip, &eventreq, sizeof(eventreq))) {
+               ret = -EFAULT;
+               goto out_free_irq;
+       }
+
+       return 0;
+
+out_free_irq:
+       free_irq(le->irq, le);
+out_free_desc:
+       gpiod_free(le->desc);
+out_free_label:
+       kfree(le->label);
+out_free_le:
+       kfree(le);
+       put_device(&gdev->dev);
+       return ret;
+}
+
 /**
  * gpio_ioctl() - ioctl handler for the GPIO chardev
  */
@@ -316,7 +812,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct gpio_device *gdev = filp->private_data;
        struct gpio_chip *chip = gdev->chip;
-       int __user *ip = (int __user *)arg;
+       void __user *ip = (void __user *)arg;
 
        /* We fail any subsequent ioctl():s when the chip is gone */
        if (!chip)
@@ -384,10 +880,22 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
                        return -EFAULT;
                return 0;
+       } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) {
+               return linehandle_create(gdev, ip);
+       } else if (cmd == GPIO_GET_LINEEVENT_IOCTL) {
+               return lineevent_create(gdev, ip);
        }
        return -EINVAL;
 }
 
+#ifdef CONFIG_COMPAT
+static long gpio_ioctl_compat(struct file *filp, unsigned int cmd,
+                             unsigned long arg)
+{
+       return gpio_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
 /**
  * gpio_chrdev_open() - open the chardev for ioctl operations
  * @inode: inode for this chardev
@@ -431,7 +939,9 @@ static const struct file_operations gpio_fileops = {
        .owner = THIS_MODULE,
        .llseek = noop_llseek,
        .unlocked_ioctl = gpio_ioctl,
-       .compat_ioctl = gpio_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = gpio_ioctl_compat,
+#endif
 };
 
 static void gpiodevice_release(struct device *dev)
@@ -539,13 +1049,14 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
        if (chip->parent) {
                gdev->dev.parent = chip->parent;
                gdev->dev.of_node = chip->parent->of_node;
-       } else {
+       }
+
 #ifdef CONFIG_OF_GPIO
        /* If the gpiochip has an assigned OF node this takes precedence */
-               if (chip->of_node)
-                       gdev->dev.of_node = chip->of_node;
+       if (chip->of_node)
+               gdev->dev.of_node = chip->of_node;
 #endif
-       }
+
        gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL);
        if (gdev->id < 0) {
                status = gdev->id;
@@ -618,6 +1129,8 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
                goto err_free_label;
        }
 
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
        for (i = 0; i < chip->ngpio; i++) {
                struct gpio_desc *desc = &gdev->descs[i];
 
@@ -649,8 +1162,6 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
                }
        }
 
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
 #ifdef CONFIG_PINCTRL
        INIT_LIST_HEAD(&gdev->pin_ranges);
 #endif
@@ -999,6 +1510,25 @@ static int gpiochip_irq_reqres(struct irq_data *d)
        if (!try_module_get(chip->gpiodev->owner))
                return -ENODEV;
 
+       /*
+        * If it is possible to switch this GPIO to an input
+        * this is a good time to do it.
+        */
+       if (chip->direction_input) {
+               struct gpio_desc *desc;
+               int ret;
+
+               desc = gpiochip_get_desc(chip, d->hwirq);
+               if (IS_ERR(desc))
+                       return PTR_ERR(desc);
+
+               ret = chip->direction_input(chip, d->hwirq);
+               if (ret)
+                       return ret;
+
+               clear_bit(FLAG_IS_OUT, &desc->flags);
+       }
+
        if (gpiochip_lock_as_irq(chip, d->hwirq)) {
                chip_err(chip,
                        "unable to lock HW IRQ %lu for IRQ\n",
@@ -1356,10 +1886,13 @@ done:
 /*
  * This descriptor validation needs to be inserted verbatim into each
  * function taking a descriptor, so we need to use a preprocessor
- * macro to avoid endless duplication.
+ * macro to avoid endless duplication. If the desc is NULL it is an
+ * optional GPIO and calls should just bail out.
  */
 #define VALIDATE_DESC(desc) do { \
-       if (!desc || !desc->gdev) { \
+       if (!desc) \
+               return 0; \
+       if (!desc->gdev) { \
                pr_warn("%s: invalid GPIO\n", __func__); \
                return -EINVAL; \
        } \
@@ -1370,7 +1903,9 @@ done:
        } } while (0)
 
 #define VALIDATE_DESC_VOID(desc) do { \
-       if (!desc || !desc->gdev) { \
+       if (!desc) \
+               return; \
+       if (!desc->gdev) { \
                pr_warn("%s: invalid GPIO\n", __func__); \
                return; \
        } \
@@ -2066,17 +2601,30 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq);
  */
 int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
 {
-       if (offset >= chip->ngpio)
-               return -EINVAL;
+       struct gpio_desc *desc;
+
+       desc = gpiochip_get_desc(chip, offset);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       /* Flush direction if something changed behind our back */
+       if (chip->get_direction) {
+               int dir = chip->get_direction(chip, offset);
+
+               if (dir)
+                       clear_bit(FLAG_IS_OUT, &desc->flags);
+               else
+                       set_bit(FLAG_IS_OUT, &desc->flags);
+       }
 
-       if (test_bit(FLAG_IS_OUT, &chip->gpiodev->descs[offset].flags)) {
+       if (test_bit(FLAG_IS_OUT, &desc->flags)) {
                chip_err(chip,
                          "%s: tried to flag a GPIO set as output for IRQ\n",
                          __func__);
                return -EIO;
        }
 
-       set_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags);
+       set_bit(FLAG_USED_AS_IRQ, &desc->flags);
        return 0;
 }
 EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq);