On Tue, 21 Oct 2008 09:50:06 +1100 Ben Nizette <bn@xxxxxxxxxxxxxxx> wrote: > > This adds pin change notification to the gpiolib sysfs interface. It > requires 16 extra bytes in gpio_desc iff CONFIG_GPIO_SYSFS which in turn > means, eg, 4k of .bss usage on AVR32. Due to limitations in sysfs, this > patch makes poll(2) and friends work as expected on the "value" > attribute, though reads on "value" will never block and there is no > facility for async reads and writes. > > > ... > > +struct poll_desc *work_to_poll(struct work_struct *ws) static > +{ > + return container_of((struct delayed_work *)ws, struct poll_desc, work); > +} > + > +void gpio_poll_work(struct work_struct *ws) static > +{ > + struct poll_desc *poll = work_to_poll(ws); > + > + unsigned gpio = poll->gpio; > + struct gpio_desc *desc = &gpio_desc[gpio]; > + > + int new = gpio_get_value_cansleep(gpio); > + int old = desc->val; > + > + if ((new && !old && test_bit(ASYNC_RISING, &desc->flags)) || > + (!new && old && test_bit(ASYNC_FALLING, &desc->flags))) > + sysfs_notify(&desc->dev->kobj, NULL, "value"); > + > + desc->val = new; > + schedule_delayed_work(&poll->work, desc->timeout); > +} > + > +static irqreturn_t gpio_irq_handler(int irq, void *dev_id) > +{ > + struct gpio_desc *desc = dev_id; > + int gpio = desc - gpio_desc; > + int new, old; > + > + if (!gpio_is_valid(gpio)) > + return IRQ_NONE; > + > + new = gpio_get_value(gpio); > + old = desc->val; > + > + if ((new && !old && test_bit(ASYNC_RISING, &desc->flags)) || > + (!new && old && test_bit(ASYNC_FALLING, &desc->flags))) > + sysfs_notify(&desc->dev->kobj, NULL, "value"); eekeekeek! sysfs_notify() does mutex_lock() and will die horridly if called from an interrupt handler. You should have got a storm of warnings when runtime testing this code. Please ensure that all debug options are enabled when testing code. Documentation/SubmitChecklist has help. > + desc->val = new; > + > + return IRQ_HANDLED; > +} > + > static ssize_t gpio_direction_show(struct device *dev, > struct device_attribute *attr, char *buf) > { > @@ -284,9 +351,162 @@ static ssize_t gpio_value_store(struct d > static /*const*/ DEVICE_ATTR(value, 0644, > gpio_value_show, gpio_value_store); > > +static ssize_t gpio_notify_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + const struct gpio_desc *desc = dev_get_drvdata(dev); > + ssize_t ret; > + > + mutex_lock(&sysfs_lock); > + > + if (test_bit(ASYNC_MODE_IRQ, &desc->flags)) > + ret = sprintf(buf, "irq\n"); > + else if (test_bit(ASYNC_MODE_POLL, &desc->flags)) > + ret = sprintf(buf, "%ld\n", desc->timeout * 1000 / HZ); > + else > + ret = sprintf(buf, "none\n"); > + > + mutex_unlock(&sysfs_lock); > + return ret; > +} <panics> oh, sysfs_lock is a gpiolib-local thing, not a sysfs-core thing. Crappy name. -- To unsubscribe from this list: send the line "unsubscribe linux-embedded" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html