summaryrefslogtreecommitdiff
path: root/drivers/gpio/gpiolib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r--drivers/gpio/gpiolib.c51
1 files changed, 49 insertions, 2 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 797c790aa750..3580c0de9d5a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -331,14 +331,15 @@ 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;
- struct gpiochip_info chipinfo;
/* We fail any subsequent ioctl():s when the chip is gone */
if (!chip)
return -ENODEV;
+ /* Fill in the struct and pass to userspace */
if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
- /* Fill in the struct and pass to userspace */
+ struct gpiochip_info chipinfo;
+
strncpy(chipinfo.name, dev_name(&gdev->dev),
sizeof(chipinfo.name));
chipinfo.name[sizeof(chipinfo.name)-1] = '\0';
@@ -349,6 +350,52 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
return -EFAULT;
return 0;
+ } else if (cmd == GPIO_GET_LINEINFO_IOCTL) {
+ struct gpioline_info lineinfo;
+ struct gpio_desc *desc;
+
+ if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
+ return -EFAULT;
+ if (lineinfo.line_offset > gdev->ngpio)
+ return -EINVAL;
+
+ desc = &gdev->descs[lineinfo.line_offset];
+ if (desc->name) {
+ strncpy(lineinfo.name, desc->name,
+ sizeof(lineinfo.name));
+ lineinfo.name[sizeof(lineinfo.name)-1] = '\0';
+ } else {
+ lineinfo.name[0] = '\0';
+ }
+ if (desc->label) {
+ strncpy(lineinfo.label, desc->label,
+ sizeof(lineinfo.label));
+ lineinfo.label[sizeof(lineinfo.label)-1] = '\0';
+ } else {
+ lineinfo.label[0] = '\0';
+ }
+
+ /*
+ * Userspace only need to know that the kernel is using
+ * this GPIO so it can't use it.
+ */
+ lineinfo.flags = 0;
+ if (desc->flags & (FLAG_REQUESTED | FLAG_IS_HOGGED |
+ FLAG_USED_AS_IRQ | FLAG_EXPORT |
+ FLAG_SYSFS))
+ lineinfo.flags |= GPIOLINE_FLAG_KERNEL;
+ if (desc->flags & FLAG_IS_OUT)
+ lineinfo.flags |= GPIOLINE_FLAG_IS_OUT;
+ if (desc->flags & FLAG_ACTIVE_LOW)
+ lineinfo.flags |= GPIOLINE_FLAG_ACTIVE_LOW;
+ if (desc->flags & FLAG_OPEN_DRAIN)
+ lineinfo.flags |= GPIOLINE_FLAG_OPEN_DRAIN;
+ if (desc->flags & FLAG_OPEN_SOURCE)
+ lineinfo.flags |= GPIOLINE_FLAG_OPEN_SOURCE;
+
+ if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
+ return -EFAULT;
+ return 0;
}
return -EINVAL;
}