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 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 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 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 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 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 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 116 int main(int argc, char *argv[]) 117 { 118 char *chip; 119 int opt, ret, cfd, lfd; 120 unsigned int offset, val, 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