199 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * GPIO mockup cdev test helper4 *5 * Copyright (C) 2020 Kent Gibson6 */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 21static 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 46static 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 59static 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 79static 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 91static 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 102static 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 116int 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 else177 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 else192 ret = get_value_v2(lfd);193 }194 195 close(lfd);196 197 return ret;198}199