linux/tools/testing/selftests/gpio/gpio-mockup-cdev.c
<<
>>
Prefs
   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
  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, 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