| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * lsgpio - example on how to list the GPIO lines on a system |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2015 Linus Walleij |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 7 | | - * under the terms of the GNU General Public License version 2 as published by |
|---|
| 8 | | - * the Free Software Foundation. |
|---|
| 9 | 6 | * |
|---|
| 10 | 7 | * Usage: |
|---|
| 11 | 8 | * lsgpio <-n device-name> |
|---|
| .. | .. |
|---|
| 28 | 25 | |
|---|
| 29 | 26 | struct gpio_flag { |
|---|
| 30 | 27 | char *name; |
|---|
| 31 | | - unsigned long mask; |
|---|
| 28 | + unsigned long long mask; |
|---|
| 32 | 29 | }; |
|---|
| 33 | 30 | |
|---|
| 34 | 31 | struct gpio_flag flagnames[] = { |
|---|
| 35 | 32 | { |
|---|
| 36 | | - .name = "kernel", |
|---|
| 37 | | - .mask = GPIOLINE_FLAG_KERNEL, |
|---|
| 33 | + .name = "used", |
|---|
| 34 | + .mask = GPIO_V2_LINE_FLAG_USED, |
|---|
| 35 | + }, |
|---|
| 36 | + { |
|---|
| 37 | + .name = "input", |
|---|
| 38 | + .mask = GPIO_V2_LINE_FLAG_INPUT, |
|---|
| 38 | 39 | }, |
|---|
| 39 | 40 | { |
|---|
| 40 | 41 | .name = "output", |
|---|
| 41 | | - .mask = GPIOLINE_FLAG_IS_OUT, |
|---|
| 42 | + .mask = GPIO_V2_LINE_FLAG_OUTPUT, |
|---|
| 42 | 43 | }, |
|---|
| 43 | 44 | { |
|---|
| 44 | 45 | .name = "active-low", |
|---|
| 45 | | - .mask = GPIOLINE_FLAG_ACTIVE_LOW, |
|---|
| 46 | + .mask = GPIO_V2_LINE_FLAG_ACTIVE_LOW, |
|---|
| 46 | 47 | }, |
|---|
| 47 | 48 | { |
|---|
| 48 | 49 | .name = "open-drain", |
|---|
| 49 | | - .mask = GPIOLINE_FLAG_OPEN_DRAIN, |
|---|
| 50 | + .mask = GPIO_V2_LINE_FLAG_OPEN_DRAIN, |
|---|
| 50 | 51 | }, |
|---|
| 51 | 52 | { |
|---|
| 52 | 53 | .name = "open-source", |
|---|
| 53 | | - .mask = GPIOLINE_FLAG_OPEN_SOURCE, |
|---|
| 54 | + .mask = GPIO_V2_LINE_FLAG_OPEN_SOURCE, |
|---|
| 55 | + }, |
|---|
| 56 | + { |
|---|
| 57 | + .name = "pull-up", |
|---|
| 58 | + .mask = GPIO_V2_LINE_FLAG_BIAS_PULL_UP, |
|---|
| 59 | + }, |
|---|
| 60 | + { |
|---|
| 61 | + .name = "pull-down", |
|---|
| 62 | + .mask = GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN, |
|---|
| 63 | + }, |
|---|
| 64 | + { |
|---|
| 65 | + .name = "bias-disabled", |
|---|
| 66 | + .mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED, |
|---|
| 54 | 67 | }, |
|---|
| 55 | 68 | }; |
|---|
| 56 | 69 | |
|---|
| 57 | | -void print_flags(unsigned long flags) |
|---|
| 70 | +static void print_attributes(struct gpio_v2_line_info *info) |
|---|
| 58 | 71 | { |
|---|
| 59 | 72 | int i; |
|---|
| 60 | | - int printed = 0; |
|---|
| 73 | + const char *field_format = "%s"; |
|---|
| 61 | 74 | |
|---|
| 62 | 75 | for (i = 0; i < ARRAY_SIZE(flagnames); i++) { |
|---|
| 63 | | - if (flags & flagnames[i].mask) { |
|---|
| 64 | | - if (printed) |
|---|
| 65 | | - fprintf(stdout, " "); |
|---|
| 66 | | - fprintf(stdout, "%s", flagnames[i].name); |
|---|
| 67 | | - printed++; |
|---|
| 76 | + if (info->flags & flagnames[i].mask) { |
|---|
| 77 | + fprintf(stdout, field_format, flagnames[i].name); |
|---|
| 78 | + field_format = ", %s"; |
|---|
| 68 | 79 | } |
|---|
| 80 | + } |
|---|
| 81 | + |
|---|
| 82 | + if ((info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING) && |
|---|
| 83 | + (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING)) |
|---|
| 84 | + fprintf(stdout, field_format, "both-edges"); |
|---|
| 85 | + else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING) |
|---|
| 86 | + fprintf(stdout, field_format, "rising-edge"); |
|---|
| 87 | + else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING) |
|---|
| 88 | + fprintf(stdout, field_format, "falling-edge"); |
|---|
| 89 | + |
|---|
| 90 | + for (i = 0; i < info->num_attrs; i++) { |
|---|
| 91 | + if (info->attrs[i].id == GPIO_V2_LINE_ATTR_ID_DEBOUNCE) |
|---|
| 92 | + fprintf(stdout, ", debounce_period=%dusec", |
|---|
| 93 | + info->attrs[i].debounce_period_us); |
|---|
| 69 | 94 | } |
|---|
| 70 | 95 | } |
|---|
| 71 | 96 | |
|---|
| .. | .. |
|---|
| 85 | 110 | if (fd == -1) { |
|---|
| 86 | 111 | ret = -errno; |
|---|
| 87 | 112 | fprintf(stderr, "Failed to open %s\n", chrdev_name); |
|---|
| 88 | | - goto exit_close_error; |
|---|
| 113 | + goto exit_free_name; |
|---|
| 89 | 114 | } |
|---|
| 90 | 115 | |
|---|
| 91 | 116 | /* Inspect this GPIO chip */ |
|---|
| .. | .. |
|---|
| 100 | 125 | |
|---|
| 101 | 126 | /* Loop over the lines and print info */ |
|---|
| 102 | 127 | for (i = 0; i < cinfo.lines; i++) { |
|---|
| 103 | | - struct gpioline_info linfo; |
|---|
| 128 | + struct gpio_v2_line_info linfo; |
|---|
| 104 | 129 | |
|---|
| 105 | 130 | memset(&linfo, 0, sizeof(linfo)); |
|---|
| 106 | | - linfo.line_offset = i; |
|---|
| 131 | + linfo.offset = i; |
|---|
| 107 | 132 | |
|---|
| 108 | | - ret = ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &linfo); |
|---|
| 133 | + ret = ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &linfo); |
|---|
| 109 | 134 | if (ret == -1) { |
|---|
| 110 | 135 | ret = -errno; |
|---|
| 111 | 136 | perror("Failed to issue LINEINFO IOCTL\n"); |
|---|
| 112 | 137 | goto exit_close_error; |
|---|
| 113 | 138 | } |
|---|
| 114 | | - fprintf(stdout, "\tline %2d:", linfo.line_offset); |
|---|
| 139 | + fprintf(stdout, "\tline %2d:", linfo.offset); |
|---|
| 115 | 140 | if (linfo.name[0]) |
|---|
| 116 | 141 | fprintf(stdout, " \"%s\"", linfo.name); |
|---|
| 117 | 142 | else |
|---|
| .. | .. |
|---|
| 122 | 147 | fprintf(stdout, " unused"); |
|---|
| 123 | 148 | if (linfo.flags) { |
|---|
| 124 | 149 | fprintf(stdout, " ["); |
|---|
| 125 | | - print_flags(linfo.flags); |
|---|
| 150 | + print_attributes(&linfo); |
|---|
| 126 | 151 | fprintf(stdout, "]"); |
|---|
| 127 | 152 | } |
|---|
| 128 | 153 | fprintf(stdout, "\n"); |
|---|
| .. | .. |
|---|
| 132 | 157 | exit_close_error: |
|---|
| 133 | 158 | if (close(fd) == -1) |
|---|
| 134 | 159 | perror("Failed to close GPIO character device file"); |
|---|
| 160 | +exit_free_name: |
|---|
| 135 | 161 | free(chrdev_name); |
|---|
| 136 | 162 | return ret; |
|---|
| 137 | 163 | } |
|---|