From 3c333c47041c905b81860478d2d8c0c3e8623b40 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Mon, 28 Sep 2020 08:28:01 +0800 Subject: tools: gpio: port lsgpio to v2 uAPI Port the lsgpio tool to the latest GPIO uAPI. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- tools/gpio/lsgpio.c | 60 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 22 deletions(-) (limited to 'tools') diff --git a/tools/gpio/lsgpio.c b/tools/gpio/lsgpio.c index b08d7a5e779b..5a05a454d0c9 100644 --- a/tools/gpio/lsgpio.c +++ b/tools/gpio/lsgpio.c @@ -25,57 +25,73 @@ struct gpio_flag { char *name; - unsigned long mask; + unsigned long long mask; }; struct gpio_flag flagnames[] = { { - .name = "kernel", - .mask = GPIOLINE_FLAG_KERNEL, + .name = "used", + .mask = GPIO_V2_LINE_FLAG_USED, + }, + { + .name = "input", + .mask = GPIO_V2_LINE_FLAG_INPUT, }, { .name = "output", - .mask = GPIOLINE_FLAG_IS_OUT, + .mask = GPIO_V2_LINE_FLAG_OUTPUT, }, { .name = "active-low", - .mask = GPIOLINE_FLAG_ACTIVE_LOW, + .mask = GPIO_V2_LINE_FLAG_ACTIVE_LOW, }, { .name = "open-drain", - .mask = GPIOLINE_FLAG_OPEN_DRAIN, + .mask = GPIO_V2_LINE_FLAG_OPEN_DRAIN, }, { .name = "open-source", - .mask = GPIOLINE_FLAG_OPEN_SOURCE, + .mask = GPIO_V2_LINE_FLAG_OPEN_SOURCE, }, { .name = "pull-up", - .mask = GPIOLINE_FLAG_BIAS_PULL_UP, + .mask = GPIO_V2_LINE_FLAG_BIAS_PULL_UP, }, { .name = "pull-down", - .mask = GPIOLINE_FLAG_BIAS_PULL_DOWN, + .mask = GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN, }, { .name = "bias-disabled", - .mask = GPIOLINE_FLAG_BIAS_DISABLE, + .mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED, }, }; -void print_flags(unsigned long flags) +static void print_attributes(struct gpio_v2_line_info *info) { int i; - int printed = 0; + const char *field_format = "%s"; for (i = 0; i < ARRAY_SIZE(flagnames); i++) { - if (flags & flagnames[i].mask) { - if (printed) - fprintf(stdout, " "); - fprintf(stdout, "%s", flagnames[i].name); - printed++; + if (info->flags & flagnames[i].mask) { + fprintf(stdout, field_format, flagnames[i].name); + field_format = ", %s"; } } + + if ((info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING) && + (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING)) + fprintf(stdout, field_format, "both-edges"); + else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING) + fprintf(stdout, field_format, "rising-edge"); + else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING) + fprintf(stdout, field_format, "falling-edge"); + + for (i = 0; i < info->num_attrs; i++) { + if (info->attrs[i].id == GPIO_V2_LINE_ATTR_ID_DEBOUNCE) + fprintf(stdout, ", debounce_period=%dusec", + info->attrs[0].debounce_period_us); + } } int list_device(const char *device_name) @@ -109,18 +125,18 @@ int list_device(const char *device_name) /* Loop over the lines and print info */ for (i = 0; i < cinfo.lines; i++) { - struct gpioline_info linfo; + struct gpio_v2_line_info linfo; memset(&linfo, 0, sizeof(linfo)); - linfo.line_offset = i; + linfo.offset = i; - ret = ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &linfo); + ret = ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &linfo); if (ret == -1) { ret = -errno; perror("Failed to issue LINEINFO IOCTL\n"); goto exit_close_error; } - fprintf(stdout, "\tline %2d:", linfo.line_offset); + fprintf(stdout, "\tline %2d:", linfo.offset); if (linfo.name[0]) fprintf(stdout, " \"%s\"", linfo.name); else @@ -131,7 +147,7 @@ int list_device(const char *device_name) fprintf(stdout, " unused"); if (linfo.flags) { fprintf(stdout, " ["); - print_flags(linfo.flags); + print_attributes(&linfo); fprintf(stdout, "]"); } fprintf(stdout, "\n"); -- cgit v1.2.3 From e86a863b337c50713b674007f74dc1854701eb93 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Mon, 28 Sep 2020 08:28:02 +0800 Subject: tools: gpio: port gpio-watch to v2 uAPI Port the gpio-watch tool to the latest GPIO uAPI. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- tools/gpio/gpio-watch.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/gpio/gpio-watch.c b/tools/gpio/gpio-watch.c index 5cea24fddfa7..f229ec62301b 100644 --- a/tools/gpio/gpio-watch.c +++ b/tools/gpio/gpio-watch.c @@ -21,8 +21,8 @@ int main(int argc, char **argv) { - struct gpioline_info_changed chg; - struct gpioline_info req; + struct gpio_v2_line_info_changed chg; + struct gpio_v2_line_info req; struct pollfd pfd; int fd, i, j, ret; char *event, *end; @@ -40,11 +40,11 @@ int main(int argc, char **argv) for (i = 0, j = 2; i < argc - 2; i++, j++) { memset(&req, 0, sizeof(req)); - req.line_offset = strtoul(argv[j], &end, 0); + req.offset = strtoul(argv[j], &end, 0); if (*end != '\0') goto err_usage; - ret = ioctl(fd, GPIO_GET_LINEINFO_WATCH_IOCTL, &req); + ret = ioctl(fd, GPIO_V2_GET_LINEINFO_WATCH_IOCTL, &req); if (ret) { perror("unable to set up line watch"); return EXIT_FAILURE; @@ -71,13 +71,13 @@ int main(int argc, char **argv) } switch (chg.event_type) { - case GPIOLINE_CHANGED_REQUESTED: + case GPIO_V2_LINE_CHANGED_REQUESTED: event = "requested"; break; - case GPIOLINE_CHANGED_RELEASED: + case GPIO_V2_LINE_CHANGED_RELEASED: event = "released"; break; - case GPIOLINE_CHANGED_CONFIG: + case GPIO_V2_LINE_CHANGED_CONFIG: event = "config changed"; break; default: @@ -87,7 +87,7 @@ int main(int argc, char **argv) } printf("line %u: %s at %llu\n", - chg.info.line_offset, event, chg.timestamp); + chg.info.offset, event, chg.timestamp_ns); } } -- cgit v1.2.3 From ed60aee0edcda1fabc39ab27c9650fa172f461b4 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Mon, 28 Sep 2020 08:28:03 +0800 Subject: tools: gpio: rename nlines to num_lines Rename nlines to num_lines to be consistent with other usage for fields describing the number of entries in an array. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- tools/gpio/gpio-hammer.c | 26 +++++++++++++------------- tools/gpio/gpio-utils.c | 20 ++++++++++---------- tools/gpio/gpio-utils.h | 6 +++--- 3 files changed, 26 insertions(+), 26 deletions(-) (limited to 'tools') diff --git a/tools/gpio/gpio-hammer.c b/tools/gpio/gpio-hammer.c index 9fd926e8cb52..a2c7577fad5c 100644 --- a/tools/gpio/gpio-hammer.c +++ b/tools/gpio/gpio-hammer.c @@ -22,7 +22,7 @@ #include #include "gpio-utils.h" -int hammer_device(const char *device_name, unsigned int *lines, int nlines, +int hammer_device(const char *device_name, unsigned int *lines, int num_lines, unsigned int loops) { struct gpiohandle_data data; @@ -33,7 +33,7 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines, unsigned int iteration = 0; memset(&data.values, 0, sizeof(data.values)); - ret = gpiotools_request_linehandle(device_name, lines, nlines, + ret = gpiotools_request_linehandle(device_name, lines, num_lines, GPIOHANDLE_REQUEST_OUTPUT, &data, "gpio-hammer"); if (ret < 0) @@ -46,15 +46,15 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines, goto exit_close_error; fprintf(stdout, "Hammer lines ["); - for (i = 0; i < nlines; i++) { + for (i = 0; i < num_lines; i++) { fprintf(stdout, "%d", lines[i]); - if (i != (nlines - 1)) + if (i != (num_lines - 1)) fprintf(stdout, ", "); } fprintf(stdout, "] on %s, initial states: [", device_name); - for (i = 0; i < nlines; i++) { + for (i = 0; i < num_lines; i++) { fprintf(stdout, "%d", data.values[i]); - if (i != (nlines - 1)) + if (i != (num_lines - 1)) fprintf(stdout, ", "); } fprintf(stdout, "]\n"); @@ -63,7 +63,7 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines, j = 0; while (1) { /* Invert all lines so we blink */ - for (i = 0; i < nlines; i++) + for (i = 0; i < num_lines; i++) data.values[i] = !data.values[i]; ret = gpiotools_set_values(fd, &data); @@ -81,9 +81,9 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines, j = 0; fprintf(stdout, "["); - for (i = 0; i < nlines; i++) { + for (i = 0; i < num_lines; i++) { fprintf(stdout, "%d: %d", lines[i], data.values[i]); - if (i != (nlines - 1)) + if (i != (num_lines - 1)) fprintf(stdout, ", "); } fprintf(stdout, "]\r"); @@ -121,7 +121,7 @@ int main(int argc, char **argv) const char *device_name = NULL; unsigned int lines[GPIOHANDLES_MAX]; unsigned int loops = 0; - int nlines; + int num_lines; int c; int i; @@ -158,11 +158,11 @@ int main(int argc, char **argv) return -1; } - nlines = i; + num_lines = i; - if (!device_name || !nlines) { + if (!device_name || !num_lines) { print_usage(); return -1; } - return hammer_device(device_name, lines, nlines, loops); + return hammer_device(device_name, lines, num_lines, loops); } diff --git a/tools/gpio/gpio-utils.c b/tools/gpio/gpio-utils.c index 16a5d9cb9da2..d527980bcb94 100644 --- a/tools/gpio/gpio-utils.c +++ b/tools/gpio/gpio-utils.c @@ -38,7 +38,7 @@ * such as "gpiochip0" * @lines: An array desired lines, specified by offset * index for the associated GPIO device. - * @nline: The number of lines to request. + * @num_lines: The number of lines to request. * @flag: The new flag for requsted gpio. Reference * "linux/gpio.h" for the meaning of flag. * @data: Default value will be set to gpio when flag is @@ -56,7 +56,7 @@ * On failure return the errno. */ int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, - unsigned int nlines, unsigned int flag, + unsigned int num_lines, unsigned int flag, struct gpiohandle_data *data, const char *consumer_label) { @@ -78,12 +78,12 @@ int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, goto exit_free_name; } - for (i = 0; i < nlines; i++) + for (i = 0; i < num_lines; i++) req.lineoffsets[i] = lines[i]; req.flags = flag; strcpy(req.consumer_label, consumer_label); - req.lines = nlines; + req.lines = num_lines; if (flag & GPIOHANDLE_REQUEST_OUTPUT) memcpy(req.default_values, data, sizeof(req.default_values)); @@ -194,20 +194,20 @@ int gpiotools_get(const char *device_name, unsigned int line) * such as "gpiochip0". * @lines: An array desired lines, specified by offset * index for the associated GPIO device. - * @nline: The number of lines to request. + * @num_lines: The number of lines to request. * @data: The array of values get from gpiochip. * * Return: On success return 0; * On failure return the errno. */ int gpiotools_gets(const char *device_name, unsigned int *lines, - unsigned int nlines, struct gpiohandle_data *data) + unsigned int num_lines, struct gpiohandle_data *data) { int fd; int ret; int ret_close; - ret = gpiotools_request_linehandle(device_name, lines, nlines, + ret = gpiotools_request_linehandle(device_name, lines, num_lines, GPIOHANDLE_REQUEST_INPUT, data, CONSUMER); if (ret < 0) @@ -245,7 +245,7 @@ int gpiotools_set(const char *device_name, unsigned int line, * such as "gpiochip0". * @lines: An array desired lines, specified by offset * index for the associated GPIO device. - * @nline: The number of lines to request. + * @num_lines: The number of lines to request. * @data: The array of values set to gpiochip, must be * 0(low) or 1(high). * @@ -253,11 +253,11 @@ int gpiotools_set(const char *device_name, unsigned int line, * On failure return the errno. */ int gpiotools_sets(const char *device_name, unsigned int *lines, - unsigned int nlines, struct gpiohandle_data *data) + unsigned int num_lines, struct gpiohandle_data *data) { int ret; - ret = gpiotools_request_linehandle(device_name, lines, nlines, + ret = gpiotools_request_linehandle(device_name, lines, num_lines, GPIOHANDLE_REQUEST_OUTPUT, data, CONSUMER); if (ret < 0) diff --git a/tools/gpio/gpio-utils.h b/tools/gpio/gpio-utils.h index cf37f13f3dcb..324729577865 100644 --- a/tools/gpio/gpio-utils.h +++ b/tools/gpio/gpio-utils.h @@ -23,7 +23,7 @@ static inline int check_prefix(const char *str, const char *prefix) } int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, - unsigned int nlines, unsigned int flag, + unsigned int num_lines, unsigned int flag, struct gpiohandle_data *data, const char *consumer_label); int gpiotools_set_values(const int fd, struct gpiohandle_data *data); @@ -32,10 +32,10 @@ int gpiotools_release_linehandle(const int fd); int gpiotools_get(const char *device_name, unsigned int line); int gpiotools_gets(const char *device_name, unsigned int *lines, - unsigned int nlines, struct gpiohandle_data *data); + unsigned int num_lines, struct gpiohandle_data *data); int gpiotools_set(const char *device_name, unsigned int line, unsigned int value); int gpiotools_sets(const char *device_name, unsigned int *lines, - unsigned int nlines, struct gpiohandle_data *data); + unsigned int num_lines, struct gpiohandle_data *data); #endif /* _GPIO_UTILS_H_ */ -- cgit v1.2.3 From 7ff6d1d25a9ea3a03f795d383889ac34fbc601d5 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Mon, 28 Sep 2020 08:28:04 +0800 Subject: tools: gpio: port gpio-hammer to v2 uAPI Port the gpio-hammer tool to the latest GPIO uAPI. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- tools/gpio/gpio-hammer.c | 32 +++++---- tools/gpio/gpio-utils.c | 164 ++++++++++++++++++++++++++++++++++++++--------- tools/gpio/gpio-utils.h | 46 +++++++++++-- 3 files changed, 197 insertions(+), 45 deletions(-) (limited to 'tools') diff --git a/tools/gpio/gpio-hammer.c b/tools/gpio/gpio-hammer.c index a2c7577fad5c..54fdf59dd320 100644 --- a/tools/gpio/gpio-hammer.c +++ b/tools/gpio/gpio-hammer.c @@ -25,23 +25,30 @@ int hammer_device(const char *device_name, unsigned int *lines, int num_lines, unsigned int loops) { - struct gpiohandle_data data; + struct gpio_v2_line_values values; + struct gpio_v2_line_config config; char swirr[] = "-\\|/"; int fd; int ret; int i, j; unsigned int iteration = 0; - memset(&data.values, 0, sizeof(data.values)); - ret = gpiotools_request_linehandle(device_name, lines, num_lines, - GPIOHANDLE_REQUEST_OUTPUT, &data, - "gpio-hammer"); + memset(&config, 0, sizeof(config)); + config.flags = GPIO_V2_LINE_FLAG_OUTPUT; + + ret = gpiotools_request_line(device_name, lines, num_lines, + &config, "gpio-hammer"); if (ret < 0) goto exit_error; else fd = ret; - ret = gpiotools_get_values(fd, &data); + values.mask = 0; + values.bits = 0; + for (i = 0; i < num_lines; i++) + gpiotools_set_bit(&values.mask, i); + + ret = gpiotools_get_values(fd, &values); if (ret < 0) goto exit_close_error; @@ -53,7 +60,7 @@ int hammer_device(const char *device_name, unsigned int *lines, int num_lines, } fprintf(stdout, "] on %s, initial states: [", device_name); for (i = 0; i < num_lines; i++) { - fprintf(stdout, "%d", data.values[i]); + fprintf(stdout, "%d", gpiotools_test_bit(values.bits, i)); if (i != (num_lines - 1)) fprintf(stdout, ", "); } @@ -64,14 +71,14 @@ int hammer_device(const char *device_name, unsigned int *lines, int num_lines, while (1) { /* Invert all lines so we blink */ for (i = 0; i < num_lines; i++) - data.values[i] = !data.values[i]; + gpiotools_change_bit(&values.bits, i); - ret = gpiotools_set_values(fd, &data); + ret = gpiotools_set_values(fd, &values); if (ret < 0) goto exit_close_error; /* Re-read values to get status */ - ret = gpiotools_get_values(fd, &data); + ret = gpiotools_get_values(fd, &values); if (ret < 0) goto exit_close_error; @@ -82,7 +89,8 @@ int hammer_device(const char *device_name, unsigned int *lines, int num_lines, fprintf(stdout, "["); for (i = 0; i < num_lines; i++) { - fprintf(stdout, "%d: %d", lines[i], data.values[i]); + fprintf(stdout, "%d: %d", lines[i], + gpiotools_test_bit(values.bits, i)); if (i != (num_lines - 1)) fprintf(stdout, ", "); } @@ -97,7 +105,7 @@ int hammer_device(const char *device_name, unsigned int *lines, int num_lines, ret = 0; exit_close_error: - gpiotools_release_linehandle(fd); + gpiotools_release_line(fd); exit_error: return ret; } diff --git a/tools/gpio/gpio-utils.c b/tools/gpio/gpio-utils.c index d527980bcb94..37187e056c8b 100644 --- a/tools/gpio/gpio-utils.c +++ b/tools/gpio/gpio-utils.c @@ -100,20 +100,87 @@ exit_free_name: free(chrdev_name); return ret < 0 ? ret : req.fd; } + +/** + * gpiotools_request_line() - request gpio lines in a gpiochip + * @device_name: The name of gpiochip without prefix "/dev/", + * such as "gpiochip0" + * @lines: An array desired lines, specified by offset + * index for the associated GPIO device. + * @num_lines: The number of lines to request. + * @config: The new config for requested gpio. Reference + * "linux/gpio.h" for config details. + * @consumer: The name of consumer, such as "sysfs", + * "powerkey". This is useful for other users to + * know who is using. + * + * Request gpio lines through the ioctl provided by chardev. User + * could call gpiotools_set_values() and gpiotools_get_values() to + * read and write respectively through the returned fd. Call + * gpiotools_release_line() to release these lines after that. + * + * Return: On success return the fd; + * On failure return the errno. + */ +int gpiotools_request_line(const char *device_name, unsigned int *lines, + unsigned int num_lines, + struct gpio_v2_line_config *config, + const char *consumer) +{ + struct gpio_v2_line_request req; + char *chrdev_name; + int fd; + int i; + int ret; + + ret = asprintf(&chrdev_name, "/dev/%s", device_name); + if (ret < 0) + return -ENOMEM; + + fd = open(chrdev_name, 0); + if (fd == -1) { + ret = -errno; + fprintf(stderr, "Failed to open %s, %s\n", + chrdev_name, strerror(errno)); + goto exit_free_name; + } + + memset(&req, 0, sizeof(req)); + for (i = 0; i < num_lines; i++) + req.offsets[i] = lines[i]; + + req.config = *config; + strcpy(req.consumer, consumer); + req.num_lines = num_lines; + + ret = ioctl(fd, GPIO_V2_GET_LINE_IOCTL, &req); + if (ret == -1) { + ret = -errno; + fprintf(stderr, "Failed to issue %s (%d), %s\n", + "GPIO_GET_LINE_IOCTL", ret, strerror(errno)); + } + + if (close(fd) == -1) + perror("Failed to close GPIO character device file"); +exit_free_name: + free(chrdev_name); + return ret < 0 ? ret : req.fd; +} + /** * gpiotools_set_values(): Set the value of gpio(s) * @fd: The fd returned by - * gpiotools_request_linehandle(). - * @data: The array of values want to set. + * gpiotools_request_line(). + * @values: The array of values want to set. * * Return: On success return 0; * On failure return the errno. */ -int gpiotools_set_values(const int fd, struct gpiohandle_data *data) +int gpiotools_set_values(const int fd, struct gpio_v2_line_values *values) { int ret; - ret = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, data); + ret = ioctl(fd, GPIO_V2_LINE_SET_VALUES_IOCTL, values); if (ret == -1) { ret = -errno; fprintf(stderr, "Failed to issue %s (%d), %s\n", @@ -127,17 +194,17 @@ int gpiotools_set_values(const int fd, struct gpiohandle_data *data) /** * gpiotools_get_values(): Get the value of gpio(s) * @fd: The fd returned by - * gpiotools_request_linehandle(). - * @data: The array of values get from hardware. + * gpiotools_request_line(). + * @values: The array of values get from hardware. * * Return: On success return 0; * On failure return the errno. */ -int gpiotools_get_values(const int fd, struct gpiohandle_data *data) +int gpiotools_get_values(const int fd, struct gpio_v2_line_values *values) { int ret; - ret = ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, data); + ret = ioctl(fd, GPIO_V2_LINE_GET_VALUES_IOCTL, values); if (ret == -1) { ret = -errno; fprintf(stderr, "Failed to issue %s (%d), %s\n", @@ -169,6 +236,27 @@ int gpiotools_release_linehandle(const int fd) return ret; } +/** + * gpiotools_release_line(): Release the line(s) of gpiochip + * @fd: The fd returned by + * gpiotools_request_line(). + * + * Return: On success return 0; + * On failure return the errno. + */ +int gpiotools_release_line(const int fd) +{ + int ret; + + ret = close(fd); + if (ret == -1) { + perror("Failed to close GPIO LINE device file"); + ret = -errno; + } + + return ret; +} + /** * gpiotools_get(): Get value from specific line * @device_name: The name of gpiochip without prefix "/dev/", @@ -180,11 +268,14 @@ int gpiotools_release_linehandle(const int fd) */ int gpiotools_get(const char *device_name, unsigned int line) { - struct gpiohandle_data data; + int ret; + unsigned int value; unsigned int lines[] = {line}; - gpiotools_gets(device_name, lines, 1, &data); - return data.values[0]; + ret = gpiotools_gets(device_name, lines, 1, &value); + if (ret) + return ret; + return value; } @@ -195,27 +286,35 @@ int gpiotools_get(const char *device_name, unsigned int line) * @lines: An array desired lines, specified by offset * index for the associated GPIO device. * @num_lines: The number of lines to request. - * @data: The array of values get from gpiochip. + * @values: The array of values get from gpiochip. * * Return: On success return 0; * On failure return the errno. */ int gpiotools_gets(const char *device_name, unsigned int *lines, - unsigned int num_lines, struct gpiohandle_data *data) + unsigned int num_lines, unsigned int *values) { - int fd; + int fd, i; int ret; int ret_close; + struct gpio_v2_line_config config; + struct gpio_v2_line_values lv; - ret = gpiotools_request_linehandle(device_name, lines, num_lines, - GPIOHANDLE_REQUEST_INPUT, data, - CONSUMER); + memset(&config, 0, sizeof(config)); + config.flags = GPIO_V2_LINE_FLAG_INPUT; + ret = gpiotools_request_line(device_name, lines, num_lines, + &config, CONSUMER); if (ret < 0) return ret; fd = ret; - ret = gpiotools_get_values(fd, data); - ret_close = gpiotools_release_linehandle(fd); + for (i = 0; i < num_lines; i++) + gpiotools_set_bit(&lv.mask, i); + ret = gpiotools_get_values(fd, &lv); + if (!ret) + for (i = 0; i < num_lines; i++) + values[i] = gpiotools_test_bit(lv.bits, i); + ret_close = gpiotools_release_line(fd); return ret < 0 ? ret : ret_close; } @@ -232,11 +331,9 @@ int gpiotools_gets(const char *device_name, unsigned int *lines, int gpiotools_set(const char *device_name, unsigned int line, unsigned int value) { - struct gpiohandle_data data; unsigned int lines[] = {line}; - data.values[0] = value; - return gpiotools_sets(device_name, lines, 1, &data); + return gpiotools_sets(device_name, lines, 1, &value); } /** @@ -246,22 +343,31 @@ int gpiotools_set(const char *device_name, unsigned int line, * @lines: An array desired lines, specified by offset * index for the associated GPIO device. * @num_lines: The number of lines to request. - * @data: The array of values set to gpiochip, must be + * @value: The array of values set to gpiochip, must be * 0(low) or 1(high). * * Return: On success return 0; * On failure return the errno. */ int gpiotools_sets(const char *device_name, unsigned int *lines, - unsigned int num_lines, struct gpiohandle_data *data) + unsigned int num_lines, unsigned int *values) { - int ret; + int ret, i; + struct gpio_v2_line_config config; - ret = gpiotools_request_linehandle(device_name, lines, num_lines, - GPIOHANDLE_REQUEST_OUTPUT, data, - CONSUMER); + memset(&config, 0, sizeof(config)); + config.flags = GPIO_V2_LINE_FLAG_OUTPUT; + config.num_attrs = 1; + config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES; + for (i = 0; i < num_lines; i++) { + gpiotools_set_bit(&config.attrs[0].mask, i); + gpiotools_assign_bit(&config.attrs[0].attr.values, + i, values[i]); + } + ret = gpiotools_request_line(device_name, lines, num_lines, + &config, CONSUMER); if (ret < 0) return ret; - return gpiotools_release_linehandle(ret); + return gpiotools_release_line(ret); } diff --git a/tools/gpio/gpio-utils.h b/tools/gpio/gpio-utils.h index 324729577865..6c69a9f1c253 100644 --- a/tools/gpio/gpio-utils.h +++ b/tools/gpio/gpio-utils.h @@ -12,7 +12,9 @@ #ifndef _GPIO_UTILS_H_ #define _GPIO_UTILS_H_ +#include #include +#include #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -26,16 +28,52 @@ int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, unsigned int num_lines, unsigned int flag, struct gpiohandle_data *data, const char *consumer_label); -int gpiotools_set_values(const int fd, struct gpiohandle_data *data); -int gpiotools_get_values(const int fd, struct gpiohandle_data *data); int gpiotools_release_linehandle(const int fd); +int gpiotools_request_line(const char *device_name, + unsigned int *lines, + unsigned int num_lines, + struct gpio_v2_line_config *config, + const char *consumer); +int gpiotools_set_values(const int fd, struct gpio_v2_line_values *values); +int gpiotools_get_values(const int fd, struct gpio_v2_line_values *values); +int gpiotools_release_line(const int fd); + int gpiotools_get(const char *device_name, unsigned int line); int gpiotools_gets(const char *device_name, unsigned int *lines, - unsigned int num_lines, struct gpiohandle_data *data); + unsigned int num_lines, unsigned int *values); int gpiotools_set(const char *device_name, unsigned int line, unsigned int value); int gpiotools_sets(const char *device_name, unsigned int *lines, - unsigned int num_lines, struct gpiohandle_data *data); + unsigned int num_lines, unsigned int *values); + +/* helper functions for gpio_v2_line_values bits */ +static inline void gpiotools_set_bit(__u64 *b, int n) +{ + *b |= _BITULL(n); +} + +static inline void gpiotools_change_bit(__u64 *b, int n) +{ + *b ^= _BITULL(n); +} + +static inline void gpiotools_clear_bit(__u64 *b, int n) +{ + *b &= ~_BITULL(n); +} + +static inline int gpiotools_test_bit(__u64 b, int n) +{ + return !!(b & _BITULL(n)); +} + +static inline void gpiotools_assign_bit(__u64 *b, int n, bool value) +{ + if (value) + gpiotools_set_bit(b, n); + else + gpiotools_clear_bit(b, n); +} #endif /* _GPIO_UTILS_H_ */ -- cgit v1.2.3 From 0acda979df8d065f9cb16bbc723723b036697e57 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Mon, 28 Sep 2020 08:28:05 +0800 Subject: tools: gpio: port gpio-event-mon to v2 uAPI Port the gpio-event-mon tool to the latest GPIO uAPI. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- tools/gpio/gpio-event-mon.c | 91 +++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 44 deletions(-) (limited to 'tools') diff --git a/tools/gpio/gpio-event-mon.c b/tools/gpio/gpio-event-mon.c index 1a303a81aeef..b230af889f26 100644 --- a/tools/gpio/gpio-event-mon.c +++ b/tools/gpio/gpio-event-mon.c @@ -23,17 +23,16 @@ #include #include #include +#include "gpio-utils.h" int monitor_device(const char *device_name, unsigned int line, - uint32_t handleflags, - uint32_t eventflags, + struct gpio_v2_line_config *config, unsigned int loops) { - struct gpioevent_request req; - struct gpiohandle_data data; + struct gpio_v2_line_values values; char *chrdev_name; - int fd; + int cfd, lfd; int ret; int i = 0; @@ -41,44 +40,39 @@ int monitor_device(const char *device_name, if (ret < 0) return -ENOMEM; - fd = open(chrdev_name, 0); - if (fd == -1) { + cfd = open(chrdev_name, 0); + if (cfd == -1) { ret = -errno; fprintf(stderr, "Failed to open %s\n", chrdev_name); goto exit_free_name; } - req.lineoffset = line; - req.handleflags = handleflags; - req.eventflags = eventflags; - strcpy(req.consumer_label, "gpio-event-mon"); - - ret = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &req); - if (ret == -1) { - ret = -errno; - fprintf(stderr, "Failed to issue GET EVENT " - "IOCTL (%d)\n", - ret); - goto exit_close_error; - } + ret = gpiotools_request_line(device_name, &line, 1, config, + "gpio-event-mon"); + if (ret < 0) + goto exit_device_close; + else + lfd = ret; /* Read initial states */ - ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); - if (ret == -1) { - ret = -errno; - fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE " - "VALUES IOCTL (%d)\n", + values.mask = 1; + values.bits = 0; + ret = gpiotools_get_values(lfd, &values); + if (ret < 0) { + fprintf(stderr, + "Failed to issue GPIO LINE GET VALUES IOCTL (%d)\n", ret); - goto exit_close_error; + goto exit_line_close; } fprintf(stdout, "Monitoring line %d on %s\n", line, device_name); - fprintf(stdout, "Initial line value: %d\n", data.values[0]); + fprintf(stdout, "Initial line value: %d\n", + gpiotools_test_bit(values.bits, 0)); while (1) { - struct gpioevent_data event; + struct gpio_v2_line_event event; - ret = read(req.fd, &event, sizeof(event)); + ret = read(lfd, &event, sizeof(event)); if (ret == -1) { if (errno == -EAGAIN) { fprintf(stderr, "nothing available\n"); @@ -96,12 +90,14 @@ int monitor_device(const char *device_name, ret = -EIO; break; } - fprintf(stdout, "GPIO EVENT %llu: ", event.timestamp); + fprintf(stdout, "GPIO EVENT at %llu on line %d (%d|%d) ", + event.timestamp_ns, event.offset, event.line_seqno, + event.seqno); switch (event.id) { - case GPIOEVENT_EVENT_RISING_EDGE: + case GPIO_V2_LINE_EVENT_RISING_EDGE: fprintf(stdout, "rising edge"); break; - case GPIOEVENT_EVENT_FALLING_EDGE: + case GPIO_V2_LINE_EVENT_FALLING_EDGE: fprintf(stdout, "falling edge"); break; default: @@ -114,8 +110,11 @@ int monitor_device(const char *device_name, break; } -exit_close_error: - if (close(fd) == -1) +exit_line_close: + if (close(lfd) == -1) + perror("Failed to close line file"); +exit_device_close: + if (close(cfd) == -1) perror("Failed to close GPIO character device file"); exit_free_name: free(chrdev_name); @@ -140,15 +139,20 @@ void print_usage(void) ); } +#define EDGE_FLAGS \ + (GPIO_V2_LINE_FLAG_EDGE_RISING | \ + GPIO_V2_LINE_FLAG_EDGE_FALLING) + int main(int argc, char **argv) { const char *device_name = NULL; unsigned int line = -1; unsigned int loops = 0; - uint32_t handleflags = GPIOHANDLE_REQUEST_INPUT; - uint32_t eventflags = 0; + struct gpio_v2_line_config config; int c; + memset(&config, 0, sizeof(config)); + config.flags = GPIO_V2_LINE_FLAG_INPUT; while ((c = getopt(argc, argv, "c:n:o:dsrf?")) != -1) { switch (c) { case 'c': @@ -161,16 +165,16 @@ int main(int argc, char **argv) line = strtoul(optarg, NULL, 10); break; case 'd': - handleflags |= GPIOHANDLE_REQUEST_OPEN_DRAIN; + config.flags |= GPIO_V2_LINE_FLAG_OPEN_DRAIN; break; case 's': - handleflags |= GPIOHANDLE_REQUEST_OPEN_SOURCE; + config.flags |= GPIO_V2_LINE_FLAG_OPEN_SOURCE; break; case 'r': - eventflags |= GPIOEVENT_REQUEST_RISING_EDGE; + config.flags |= GPIO_V2_LINE_FLAG_EDGE_RISING; break; case 'f': - eventflags |= GPIOEVENT_REQUEST_FALLING_EDGE; + config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING; break; case '?': print_usage(); @@ -182,11 +186,10 @@ int main(int argc, char **argv) print_usage(); return -1; } - if (!eventflags) { + if (!(config.flags & EDGE_FLAGS)) { printf("No flags specified, listening on both rising and " "falling edges\n"); - eventflags = GPIOEVENT_REQUEST_BOTH_EDGES; + config.flags |= EDGE_FLAGS; } - return monitor_device(device_name, line, handleflags, - eventflags, loops); + return monitor_device(device_name, line, &config, loops); } -- cgit v1.2.3 From 62757c32d5db33fa3abb7b7b88201f9b4ecbc85b Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Mon, 28 Sep 2020 08:28:06 +0800 Subject: tools: gpio: add multi-line monitoring to gpio-event-mon Extend gpio-event-mon to support monitoring multiple lines. This would require multiple lineevent requests to implement using uAPI v1, but can be performed with a single line request using uAPI v2. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- tools/gpio/gpio-event-mon.c | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/tools/gpio/gpio-event-mon.c b/tools/gpio/gpio-event-mon.c index b230af889f26..0c34f18f511c 100644 --- a/tools/gpio/gpio-event-mon.c +++ b/tools/gpio/gpio-event-mon.c @@ -26,7 +26,8 @@ #include "gpio-utils.h" int monitor_device(const char *device_name, - unsigned int line, + unsigned int *lines, + unsigned int num_lines, struct gpio_v2_line_config *config, unsigned int loops) { @@ -47,7 +48,7 @@ int monitor_device(const char *device_name, goto exit_free_name; } - ret = gpiotools_request_line(device_name, &line, 1, config, + ret = gpiotools_request_line(device_name, lines, num_lines, config, "gpio-event-mon"); if (ret < 0) goto exit_device_close; @@ -55,8 +56,10 @@ int monitor_device(const char *device_name, lfd = ret; /* Read initial states */ - values.mask = 1; + values.mask = 0; values.bits = 0; + for (i = 0; i < num_lines; i++) + gpiotools_set_bit(&values.mask, i); ret = gpiotools_get_values(lfd, &values); if (ret < 0) { fprintf(stderr, @@ -65,9 +68,23 @@ int monitor_device(const char *device_name, goto exit_line_close; } - fprintf(stdout, "Monitoring line %d on %s\n", line, device_name); - fprintf(stdout, "Initial line value: %d\n", - gpiotools_test_bit(values.bits, 0)); + if (num_lines == 1) { + fprintf(stdout, "Monitoring line %d on %s\n", lines[0], device_name); + fprintf(stdout, "Initial line value: %d\n", + gpiotools_test_bit(values.bits, 0)); + } else { + fprintf(stdout, "Monitoring lines %d", lines[0]); + for (i = 1; i < num_lines - 1; i++) + fprintf(stdout, ", %d", lines[i]); + fprintf(stdout, " and %d on %s\n", lines[i], device_name); + fprintf(stdout, "Initial line values: %d", + gpiotools_test_bit(values.bits, 0)); + for (i = 1; i < num_lines - 1; i++) + fprintf(stdout, ", %d", + gpiotools_test_bit(values.bits, i)); + fprintf(stdout, " and %d\n", + gpiotools_test_bit(values.bits, i)); + } while (1) { struct gpio_v2_line_event event; @@ -126,7 +143,7 @@ void print_usage(void) fprintf(stderr, "Usage: gpio-event-mon [options]...\n" "Listen to events on GPIO lines, 0->1 1->0\n" " -n Listen on GPIOs on a named device (must be stated)\n" - " -o Offset to monitor\n" + " -o Offset of line to monitor (may be repeated)\n" " -d Set line as open drain\n" " -s Set line as open source\n" " -r Listen for rising edges\n" @@ -146,7 +163,8 @@ void print_usage(void) int main(int argc, char **argv) { const char *device_name = NULL; - unsigned int line = -1; + unsigned int lines[GPIO_V2_LINES_MAX]; + unsigned int num_lines = 0; unsigned int loops = 0; struct gpio_v2_line_config config; int c; @@ -162,7 +180,12 @@ int main(int argc, char **argv) device_name = optarg; break; case 'o': - line = strtoul(optarg, NULL, 10); + if (num_lines >= GPIO_V2_LINES_MAX) { + print_usage(); + return -1; + } + lines[num_lines] = strtoul(optarg, NULL, 10); + num_lines++; break; case 'd': config.flags |= GPIO_V2_LINE_FLAG_OPEN_DRAIN; @@ -182,7 +205,7 @@ int main(int argc, char **argv) } } - if (!device_name || line == -1) { + if (!device_name || num_lines == 0) { print_usage(); return -1; } @@ -191,5 +214,5 @@ int main(int argc, char **argv) "falling edges\n"); config.flags |= EDGE_FLAGS; } - return monitor_device(device_name, line, &config, loops); + return monitor_device(device_name, lines, num_lines, &config, loops); } -- cgit v1.2.3 From cf048e05b68789e9fa35f246f8ecbe95d79f4173 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Mon, 28 Sep 2020 08:28:07 +0800 Subject: tools: gpio: add debounce support to gpio-event-mon Add support for debouncing monitored lines to gpio-event-mon. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- tools/gpio/gpio-event-mon.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/gpio/gpio-event-mon.c b/tools/gpio/gpio-event-mon.c index 0c34f18f511c..90c3155f05b1 100644 --- a/tools/gpio/gpio-event-mon.c +++ b/tools/gpio/gpio-event-mon.c @@ -148,11 +148,12 @@ void print_usage(void) " -s Set line as open source\n" " -r Listen for rising edges\n" " -f Listen for falling edges\n" + " -b Debounce the line with period n microseconds\n" " [-c ] Do loops (optional, infinite loop if not stated)\n" " -? This helptext\n" "\n" "Example:\n" - "gpio-event-mon -n gpiochip0 -o 4 -r -f\n" + "gpio-event-mon -n gpiochip0 -o 4 -r -f -b 10000\n" ); } @@ -167,11 +168,12 @@ int main(int argc, char **argv) unsigned int num_lines = 0; unsigned int loops = 0; struct gpio_v2_line_config config; - int c; + int c, attr, i; + unsigned long debounce_period_us = 0; memset(&config, 0, sizeof(config)); config.flags = GPIO_V2_LINE_FLAG_INPUT; - while ((c = getopt(argc, argv, "c:n:o:dsrf?")) != -1) { + while ((c = getopt(argc, argv, "c:n:o:b:dsrf?")) != -1) { switch (c) { case 'c': loops = strtoul(optarg, NULL, 10); @@ -187,6 +189,9 @@ int main(int argc, char **argv) lines[num_lines] = strtoul(optarg, NULL, 10); num_lines++; break; + case 'b': + debounce_period_us = strtoul(optarg, NULL, 10); + break; case 'd': config.flags |= GPIO_V2_LINE_FLAG_OPEN_DRAIN; break; @@ -205,6 +210,15 @@ int main(int argc, char **argv) } } + if (debounce_period_us) { + attr = config.num_attrs; + config.num_attrs++; + for (i = 0; i < num_lines; i++) + gpiotools_set_bit(&config.attrs[attr].mask, i); + config.attrs[attr].attr.id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; + config.attrs[attr].attr.debounce_period_us = debounce_period_us; + } + if (!device_name || num_lines == 0) { print_usage(); return -1; -- cgit v1.2.3