linux/tools/gpio/gpio-hammer.c
<<
>>
Prefs
   1/*
   2 * gpio-hammer - example swiss army knife to shake GPIO lines on a system
   3 *
   4 * Copyright (C) 2016 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 *
  10 * Usage:
  11 *      gpio-hammer -n <device-name> -o <offset1> -o <offset2>
  12 */
  13
  14#include <unistd.h>
  15#include <stdlib.h>
  16#include <stdbool.h>
  17#include <stdio.h>
  18#include <dirent.h>
  19#include <errno.h>
  20#include <string.h>
  21#include <poll.h>
  22#include <fcntl.h>
  23#include <getopt.h>
  24#include <sys/ioctl.h>
  25#include <linux/gpio.h>
  26
  27int hammer_device(const char *device_name, unsigned int *lines, int nlines,
  28                  unsigned int loops)
  29{
  30        struct gpiohandle_request req;
  31        struct gpiohandle_data data;
  32        char *chrdev_name;
  33        char swirr[] = "-\\|/";
  34        int fd;
  35        int ret;
  36        int i, j;
  37        unsigned int iteration = 0;
  38
  39        ret = asprintf(&chrdev_name, "/dev/%s", device_name);
  40        if (ret < 0)
  41                return -ENOMEM;
  42
  43        fd = open(chrdev_name, 0);
  44        if (fd == -1) {
  45                ret = -errno;
  46                fprintf(stderr, "Failed to open %s\n", chrdev_name);
  47                goto exit_close_error;
  48        }
  49
  50        /* Request lines as output */
  51        for (i = 0; i < nlines; i++)
  52                req.lineoffsets[i] = lines[i];
  53        req.flags = GPIOHANDLE_REQUEST_OUTPUT; /* Request as output */
  54        strcpy(req.consumer_label, "gpio-hammer");
  55        req.lines = nlines;
  56        ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
  57        if (ret == -1) {
  58                ret = -errno;
  59                fprintf(stderr, "Failed to issue GET LINEHANDLE "
  60                        "IOCTL (%d)\n",
  61                        ret);
  62                goto exit_close_error;
  63        }
  64
  65        /* Read initial states */
  66        ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
  67        if (ret == -1) {
  68                ret = -errno;
  69                fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE "
  70                        "VALUES IOCTL (%d)\n",
  71                        ret);
  72                goto exit_close_error;
  73        }
  74        fprintf(stdout, "Hammer lines [");
  75        for (i = 0; i < nlines; i++) {
  76                fprintf(stdout, "%d", lines[i]);
  77                if (i != (nlines - 1))
  78                        fprintf(stdout, ", ");
  79        }
  80        fprintf(stdout, "] on %s, initial states: [", device_name);
  81        for (i = 0; i < nlines; i++) {
  82                fprintf(stdout, "%d", data.values[i]);
  83                if (i != (nlines - 1))
  84                        fprintf(stdout, ", ");
  85        }
  86        fprintf(stdout, "]\n");
  87
  88        /* Hammertime! */
  89        j = 0;
  90        while (1) {
  91                /* Invert all lines so we blink */
  92                for (i = 0; i < nlines; i++)
  93                        data.values[i] = !data.values[i];
  94
  95                ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
  96                if (ret == -1) {
  97                        ret = -errno;
  98                        fprintf(stderr, "Failed to issue GPIOHANDLE SET LINE "
  99                                "VALUES IOCTL (%d)\n",
 100                                ret);
 101                        goto exit_close_error;
 102                }
 103                /* Re-read values to get status */
 104                ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
 105                if (ret == -1) {
 106                        ret = -errno;
 107                        fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE "
 108                                "VALUES IOCTL (%d)\n",
 109                                ret);
 110                        goto exit_close_error;
 111                }
 112
 113                fprintf(stdout, "[%c] ", swirr[j]);
 114                j++;
 115                if (j == sizeof(swirr)-1)
 116                        j = 0;
 117
 118                fprintf(stdout, "[");
 119                for (i = 0; i < nlines; i++) {
 120                        fprintf(stdout, "%d: %d", lines[i], data.values[i]);
 121                        if (i != (nlines - 1))
 122                                fprintf(stdout, ", ");
 123                }
 124                fprintf(stdout, "]\r");
 125                fflush(stdout);
 126                sleep(1);
 127                iteration++;
 128                if (loops && iteration == loops)
 129                        break;
 130        }
 131        fprintf(stdout, "\n");
 132        ret = 0;
 133
 134exit_close_error:
 135        if (close(fd) == -1)
 136                perror("Failed to close GPIO character device file");
 137        free(chrdev_name);
 138        return ret;
 139}
 140
 141void print_usage(void)
 142{
 143        fprintf(stderr, "Usage: gpio-hammer [options]...\n"
 144                "Hammer GPIO lines, 0->1->0->1...\n"
 145                "  -n <name>  Hammer GPIOs on a named device (must be stated)\n"
 146                "  -o <n>     Offset[s] to hammer, at least one, several can be stated\n"
 147                " [-c <n>]    Do <n> loops (optional, infinite loop if not stated)\n"
 148                "  -?         This helptext\n"
 149                "\n"
 150                "Example:\n"
 151                "gpio-hammer -n gpiochip0 -o 4\n"
 152        );
 153}
 154
 155int main(int argc, char **argv)
 156{
 157        const char *device_name = NULL;
 158        unsigned int lines[GPIOHANDLES_MAX];
 159        unsigned int loops = 0;
 160        int nlines;
 161        int c;
 162        int i;
 163
 164        i = 0;
 165        while ((c = getopt(argc, argv, "c:n:o:?")) != -1) {
 166                switch (c) {
 167                case 'c':
 168                        loops = strtoul(optarg, NULL, 10);
 169                        break;
 170                case 'n':
 171                        device_name = optarg;
 172                        break;
 173                case 'o':
 174                        lines[i] = strtoul(optarg, NULL, 10);
 175                        i++;
 176                        break;
 177                case '?':
 178                        print_usage();
 179                        return -1;
 180                }
 181        }
 182        nlines = i;
 183
 184        if (!device_name || !nlines) {
 185                print_usage();
 186                return -1;
 187        }
 188        return hammer_device(device_name, lines, nlines, loops);
 189}
 190