diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpiolib.c | 80 |
1 files changed, 27 insertions, 53 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 1a8c18cbf20..8a29404985f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -57,9 +57,9 @@ struct gpio_desc { #define FLAG_TRIG_RISE 6 /* trigger on rising edge */ #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */ -#define PDESC_ID_SHIFT 16 /* add new flags before this one */ +#define ID_SHIFT 16 /* add new flags before this one */ -#define GPIO_FLAGS_MASK ((1 << PDESC_ID_SHIFT) - 1) +#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1) #define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE)) #ifdef CONFIG_DEBUG_FS @@ -69,12 +69,7 @@ struct gpio_desc { static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; #ifdef CONFIG_GPIO_SYSFS -struct poll_desc { - struct work_struct work; - struct sysfs_dirent *value_sd; -}; - -static struct idr pdesc_idr; +static DEFINE_IDR(dirent_idr); #endif static inline void desc_set_label(struct gpio_desc *d, const char *label) @@ -325,24 +320,16 @@ static const DEVICE_ATTR(value, 0644, static irqreturn_t gpio_sysfs_irq(int irq, void *priv) { - struct work_struct *work = priv; + struct sysfs_dirent *value_sd = priv; - schedule_work(work); + sysfs_notify_dirent(value_sd); return IRQ_HANDLED; } -static void gpio_notify_sysfs(struct work_struct *work) -{ - struct poll_desc *pdesc; - - pdesc = container_of(work, struct poll_desc, work); - sysfs_notify_dirent(pdesc->value_sd); -} - static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, unsigned long gpio_flags) { - struct poll_desc *pdesc; + struct sysfs_dirent *value_sd; unsigned long irq_flags; int ret, irq, id; @@ -353,18 +340,16 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, if (irq < 0) return -EIO; - id = desc->flags >> PDESC_ID_SHIFT; - pdesc = idr_find(&pdesc_idr, id); - if (pdesc) { - free_irq(irq, &pdesc->work); - cancel_work_sync(&pdesc->work); - } + id = desc->flags >> ID_SHIFT; + value_sd = idr_find(&dirent_idr, id); + if (value_sd) + free_irq(irq, value_sd); desc->flags &= ~GPIO_TRIGGER_MASK; if (!gpio_flags) { ret = 0; - goto free_sd; + goto free_id; } irq_flags = IRQF_SHARED; @@ -375,55 +360,46 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; - if (!pdesc) { - pdesc = kmalloc(sizeof(*pdesc), GFP_KERNEL); - if (!pdesc) { - ret = -ENOMEM; + if (!value_sd) { + value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value"); + if (!value_sd) { + ret = -ENODEV; goto err_out; } do { ret = -ENOMEM; - if (idr_pre_get(&pdesc_idr, GFP_KERNEL)) - ret = idr_get_new_above(&pdesc_idr, - pdesc, 1, &id); + if (idr_pre_get(&dirent_idr, GFP_KERNEL)) + ret = idr_get_new_above(&dirent_idr, value_sd, + 1, &id); } while (ret == -EAGAIN); if (ret) - goto free_mem; + goto free_sd; desc->flags &= GPIO_FLAGS_MASK; - desc->flags |= (unsigned long)id << PDESC_ID_SHIFT; + desc->flags |= (unsigned long)id << ID_SHIFT; - if (desc->flags >> PDESC_ID_SHIFT != id) { + if (desc->flags >> ID_SHIFT != id) { ret = -ERANGE; goto free_id; } - - pdesc->value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value"); - if (!pdesc->value_sd) { - ret = -ENODEV; - goto free_id; - } - INIT_WORK(&pdesc->work, gpio_notify_sysfs); } ret = request_irq(irq, gpio_sysfs_irq, irq_flags, - "gpiolib", &pdesc->work); + "gpiolib", value_sd); if (ret) - goto free_sd; + goto free_id; desc->flags |= gpio_flags; return 0; -free_sd: - if (pdesc) - sysfs_put(pdesc->value_sd); free_id: - idr_remove(&pdesc_idr, id); + idr_remove(&dirent_idr, id); desc->flags &= GPIO_FLAGS_MASK; -free_mem: - kfree(pdesc); +free_sd: + if (value_sd) + sysfs_put(value_sd); err_out: return ret; } @@ -994,8 +970,6 @@ static int __init gpiolib_sysfs_init(void) unsigned long flags; unsigned gpio; - idr_init(&pdesc_idr); - status = class_register(&gpio_class); if (status < 0) return status; |