Module: xenomai-3 Branch: wip/drivers Commit: cb10960b91a8a935342779211d62d8387a89c596 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=cb10960b91a8a935342779211d62d8387a89c596
Author: Philippe Gerum <r...@xenomai.org> Date: Tue Jun 28 12:16:02 2016 +0200 drivers/gpio: allow setting trigger type w/ GPIO_RTIOC_IRQEN --- include/rtdm/uapi/gpio.h | 9 ++++++++- kernel/drivers/gpio/gpio-core.c | 31 +++++++++++++++++++++++++++---- testsuite/gpiotest/gpiotest.c | 34 +++++++++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/include/rtdm/uapi/gpio.h b/include/rtdm/uapi/gpio.h index b0d4899..307e190 100644 --- a/include/rtdm/uapi/gpio.h +++ b/include/rtdm/uapi/gpio.h @@ -22,7 +22,14 @@ #define GPIO_RTIOC_DIR_OUT _IOW(RTDM_CLASS_GPIO, 0, int) #define GPIO_RTIOC_DIR_IN _IO(RTDM_CLASS_GPIO, 1) -#define GPIO_RTIOC_IRQEN _IO(RTDM_CLASS_GPIO, 2) +#define GPIO_RTIOC_IRQEN _IOW(RTDM_CLASS_GPIO, 2, int) /* GPIO trigger */ #define GPIO_RTIOC_IRQDIS _IO(RTDM_CLASS_GPIO, 3) +#define GPIO_TRIGGER_NONE 0x0 /* unspecified */ +#define GPIO_TRIGGER_EDGE_RISING 0x1 +#define GPIO_TRIGGER_EDGE_FALLING 0x2 +#define GPIO_TRIGGER_LEVEL_HIGH 0x4 +#define GPIO_TRIGGER_LEVEL_LOW 0x8 +#define GPIO_TRIGGER_MASK 0xf + #endif /* !_RTDM_UAPI_GPIO_H */ diff --git a/kernel/drivers/gpio/gpio-core.c b/kernel/drivers/gpio/gpio-core.c index e8a7ba1..6c1f351 100644 --- a/kernel/drivers/gpio/gpio-core.c +++ b/kernel/drivers/gpio/gpio-core.c @@ -44,10 +44,20 @@ static int gpio_pin_interrupt(rtdm_irq_t *irqh) return RTDM_IRQ_HANDLED; } -static int request_gpio_irq(unsigned int gpio, struct rtdm_gpio_pin *pin) +static int request_gpio_irq(unsigned int gpio, struct rtdm_gpio_pin *pin, + int trigger) { + static const int trigger_flags[] = { + IRQ_TYPE_EDGE_RISING, + IRQ_TYPE_EDGE_FALLING, + IRQ_TYPE_LEVEL_HIGH, + IRQ_TYPE_LEVEL_LOW, + }; + int irq_trigger, ret; unsigned int irq; - int ret; + + if (trigger & ~GPIO_TRIGGER_MASK) + return -EINVAL; ret = gpio_request(gpio, pin->name); if (ret) { @@ -66,6 +76,15 @@ static int request_gpio_irq(unsigned int gpio, struct rtdm_gpio_pin *pin) rtdm_event_clear(&pin->event); irq = gpio_to_irq(gpio); + /* + * Assumes GPIO_TRIGGER_xx values are forming a continuous + * sequence of bits starting at bit #0. + */ + if (trigger) { + irq_trigger = trigger_flags[ffs(trigger) - 1]; + irq_set_irq_type(irq, irq_trigger); + } + ret = rtdm_irq_request(&pin->irqh, irq, gpio_pin_interrupt, 0, pin->name, pin); if (ret) { @@ -93,8 +112,8 @@ static int gpio_pin_ioctl_nrt(struct rtdm_fd *fd, { struct rtdm_device *dev = rtdm_fd_device(fd); unsigned int gpio = rtdm_fd_minor(fd); + int ret = 0, val, trigger; struct rtdm_gpio_pin *pin; - int ret = 0, val; pin = container_of(dev, struct rtdm_gpio_pin, dev); @@ -109,7 +128,11 @@ static int gpio_pin_ioctl_nrt(struct rtdm_fd *fd, ret = gpio_direction_input(gpio); break; case GPIO_RTIOC_IRQEN: - ret = request_gpio_irq(gpio, pin); + ret = rtdm_safe_copy_from_user(fd, &trigger, + arg, sizeof(trigger)); + if (ret) + return ret; + ret = request_gpio_irq(gpio, pin, trigger); break; case GPIO_RTIOC_IRQDIS: release_gpio_irq(gpio, pin); diff --git a/testsuite/gpiotest/gpiotest.c b/testsuite/gpiotest/gpiotest.c index 0bdd39f..6e9ce5b 100644 --- a/testsuite/gpiotest/gpiotest.c +++ b/testsuite/gpiotest/gpiotest.c @@ -55,8 +55,21 @@ smokey_test_plugin(write_value, static int run_interrupt(struct smokey_test *t, int argc, char *const argv[]) { - const char *device = NULL; - int fd, ret; + static struct { + const char *name; + int flag; + } trigger_types[] = { + { .name = "edge", .flag = GPIO_TRIGGER_EDGE_RISING }, + { .name = "edge-rising", .flag = GPIO_TRIGGER_EDGE_RISING }, + { .name = "edge-falling", .flag = GPIO_TRIGGER_EDGE_FALLING }, + { .name = "edge-both", .flag = GPIO_TRIGGER_EDGE_FALLING|GPIO_TRIGGER_EDGE_RISING }, + { .name = "level", .flag = GPIO_TRIGGER_LEVEL_LOW }, + { .name = "level-low", .flag = GPIO_TRIGGER_LEVEL_LOW }, + { .name = "level-high", .flag = GPIO_TRIGGER_LEVEL_HIGH }, + { NULL, 0 }, + }; + const char *device = NULL, *trigname; + int fd, ret, trigger, n; fd_set set; smokey_parse_args(t, argc, argv); @@ -75,7 +88,22 @@ static int run_interrupt(struct smokey_test *t, int argc, char *const argv[]) return ret; } - ret = ioctl(fd, GPIO_RTIOC_IRQEN); + trigger = GPIO_TRIGGER_NONE; + if (SMOKEY_ARG_ISSET(interrupt, trigger)) { + trigname = SMOKEY_ARG_STRING(interrupt, trigger); + for (n = 0; trigger_types[n].name; n++) { + if (strcmp(trigger_types[n].name, trigname) == 0) { + trigger = trigger_types[n].flag; + break; + } + } + if (trigger == GPIO_TRIGGER_NONE) { + warning("invalid trigger type %s", trigname); + return -EINVAL; + } + } + + ret = ioctl(fd, GPIO_RTIOC_IRQEN, &trigger); if (ret) { ret = -errno; warning("GPIO_RTIOC_IRQEN failed on %s [%s]", _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org https://xenomai.org/mailman/listinfo/xenomai-git