1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * GPIO mockup cdev test helper
4 *
5 * Copyright (C) 2020 Kent Gibson
6 */
7
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <signal.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <sys/ioctl.h>
17 #include <linux/gpio.h>
18
19 #define CONSUMER "gpio-mockup-cdev"
20
request_line_v2(int cfd,unsigned int offset,uint64_t flags,unsigned int val)21 static int request_line_v2(int cfd, unsigned int offset,
22 uint64_t flags, unsigned int val)
23 {
24 struct gpio_v2_line_request req;
25 int ret;
26
27 memset(&req, 0, sizeof(req));
28 req.num_lines = 1;
29 req.offsets[0] = offset;
30 req.config.flags = flags;
31 strcpy(req.consumer, CONSUMER);
32 if (flags & GPIO_V2_LINE_FLAG_OUTPUT) {
33 req.config.num_attrs = 1;
34 req.config.attrs[0].mask = 1;
35 req.config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES;
36 if (val)
37 req.config.attrs[0].attr.values = 1;
38 }
39 ret = ioctl(cfd, GPIO_V2_GET_LINE_IOCTL, &req);
40 if (ret == -1)
41 return -errno;
42 return req.fd;
43 }
44
45
get_value_v2(int lfd)46 static int get_value_v2(int lfd)
47 {
48 struct gpio_v2_line_values vals;
49 int ret;
50
51 memset(&vals, 0, sizeof(vals));
52 vals.mask = 1;
53 ret = ioctl(lfd, GPIO_V2_LINE_GET_VALUES_IOCTL, &vals);
54 if (ret == -1)
55 return -errno;
56 return vals.bits & 0x1;
57 }
58
request_line_v1(int cfd,unsigned int offset,uint32_t flags,unsigned int val)59 static int request_line_v1(int cfd, unsigned int offset,
60 uint32_t flags, unsigned int val)
61 {
62 struct gpiohandle_request req;
63 int ret;
64
65 memset(&req, 0, sizeof(req));
66 req.lines = 1;
67 req.lineoffsets[0] = offset;
68 req.flags = flags;
69 strcpy(req.consumer_label, CONSUMER);
70 if (flags & GPIOHANDLE_REQUEST_OUTPUT)
71 req.default_values[0] = val;
72
73 ret = ioctl(cfd, GPIO_GET_LINEHANDLE_IOCTL, &req);
74 if (ret == -1)
75 return -errno;
76 return req.fd;
77 }
78
get_value_v1(int lfd)79 static int get_value_v1(int lfd)
80 {
81 struct gpiohandle_data vals;
82 int ret;
83
84 memset(&vals, 0, sizeof(vals));
85 ret = ioctl(lfd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &vals);
86 if (ret == -1)
87 return -errno;
88 return vals.values[0];
89 }
90
usage(char * prog)91 static void usage(char *prog)
92 {
93 printf("Usage: %s [-l] [-b <bias>] [-s <value>] [-u <uAPI>] <gpiochip> <offset>\n", prog);
94 printf(" -b: set line bias to one of pull-down, pull-up, disabled\n");
95 printf(" (default is to leave bias unchanged):\n");
96 printf(" -l: set line active low (default is active high)\n");
97 printf(" -s: set line value (default is to get line value)\n");
98 printf(" -u: uAPI version to use (default is 2)\n");
99 exit(-1);
100 }
101
wait_signal(void)102 static int wait_signal(void)
103 {
104 int sig;
105 sigset_t wset;
106
107 sigemptyset(&wset);
108 sigaddset(&wset, SIGHUP);
109 sigaddset(&wset, SIGINT);
110 sigaddset(&wset, SIGTERM);
111 sigwait(&wset, &sig);
112
113 return sig;
114 }
115
main(int argc,char * argv[])116 int main(int argc, char *argv[])
117 {
118 char *chip;
119 int opt, ret, cfd, lfd;
120 unsigned int offset, val = 0, abiv;
121 uint32_t flags_v1;
122 uint64_t flags_v2;
123
124 abiv = 2;
125 ret = 0;
126 flags_v1 = GPIOHANDLE_REQUEST_INPUT;
127 flags_v2 = GPIO_V2_LINE_FLAG_INPUT;
128
129 while ((opt = getopt(argc, argv, "lb:s:u:")) != -1) {
130 switch (opt) {
131 case 'l':
132 flags_v1 |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
133 flags_v2 |= GPIO_V2_LINE_FLAG_ACTIVE_LOW;
134 break;
135 case 'b':
136 if (strcmp("pull-up", optarg) == 0) {
137 flags_v1 |= GPIOHANDLE_REQUEST_BIAS_PULL_UP;
138 flags_v2 |= GPIO_V2_LINE_FLAG_BIAS_PULL_UP;
139 } else if (strcmp("pull-down", optarg) == 0) {
140 flags_v1 |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN;
141 flags_v2 |= GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN;
142 } else if (strcmp("disabled", optarg) == 0) {
143 flags_v1 |= GPIOHANDLE_REQUEST_BIAS_DISABLE;
144 flags_v2 |= GPIO_V2_LINE_FLAG_BIAS_DISABLED;
145 }
146 break;
147 case 's':
148 val = atoi(optarg);
149 flags_v1 &= ~GPIOHANDLE_REQUEST_INPUT;
150 flags_v1 |= GPIOHANDLE_REQUEST_OUTPUT;
151 flags_v2 &= ~GPIO_V2_LINE_FLAG_INPUT;
152 flags_v2 |= GPIO_V2_LINE_FLAG_OUTPUT;
153 break;
154 case 'u':
155 abiv = atoi(optarg);
156 break;
157 default:
158 usage(argv[0]);
159 }
160 }
161
162 if (argc < optind + 2)
163 usage(argv[0]);
164
165 chip = argv[optind];
166 offset = atoi(argv[optind + 1]);
167
168 cfd = open(chip, 0);
169 if (cfd == -1) {
170 fprintf(stderr, "Failed to open %s: %s\n", chip, strerror(errno));
171 return -errno;
172 }
173
174 if (abiv == 1)
175 lfd = request_line_v1(cfd, offset, flags_v1, val);
176 else
177 lfd = request_line_v2(cfd, offset, flags_v2, val);
178
179 close(cfd);
180
181 if (lfd < 0) {
182 fprintf(stderr, "Failed to request %s:%d: %s\n", chip, offset, strerror(-lfd));
183 return lfd;
184 }
185
186 if (flags_v2 & GPIO_V2_LINE_FLAG_OUTPUT) {
187 wait_signal();
188 } else {
189 if (abiv == 1)
190 ret = get_value_v1(lfd);
191 else
192 ret = get_value_v2(lfd);
193 }
194
195 close(lfd);
196
197 return ret;
198 }
199