linux/tools/gpio/gpio-hammer.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * gpio-hammer - example swiss army knife to shake GPIO lines on a system
   4 *
   5 * Copyright (C) 2016 Linus Walleij
   6 *
   7 * Usage:
   8 *      gpio-hammer -n <device-name> -o <offset1> -o <offset2>
   9 */
  10
  11#include <unistd.h>
  12#include <stdlib.h>
  13#include <stdbool.h>
  14#include <stdio.h>
  15#include <dirent.h>
  16#include <errno.h>
  17#include <string.h>
  18#include <poll.h>
  19#include <fcntl.h>
  20#include <getopt.h>
  21#include <sys/ioctl.h>
  22#include <linux/gpio.h>
  23#include "gpio-utils.h"
  24
  25int hammer_device(const char *device_name, unsigned int *lines, int num_lines,
  26                  unsigned int loops)
  27{
  28        struct gpio_v2_line_values values;
  29        struct gpio_v2_line_config config;
  30        char swirr[] = "-\\|/";
  31        int fd;
  32        int ret;
  33        int i, j;
  34        unsigned int iteration = 0;
  35
  36        memset(&config, 0, sizeof(config));
  37        config.flags = GPIO_V2_LINE_FLAG_OUTPUT;
  38
  39        ret = gpiotools_request_line(device_name, lines, num_lines,
  40                                     &config, "gpio-hammer");
  41        if (ret < 0)
  42                goto exit_error;
  43        else
  44                fd = ret;
  45
  46        values.mask = 0;
  47        values.bits = 0;
  48        for (i = 0; i < num_lines; i++)
  49                gpiotools_set_bit(&values.mask, i);
  50
  51        ret = gpiotools_get_values(fd, &values);
  52        if (ret < 0)
  53                goto exit_close_error;
  54
  55        fprintf(stdout, "Hammer lines [");
  56        for (i = 0; i < num_lines; i++) {
  57                fprintf(stdout, "%d", lines[i]);
  58                if (i != (num_lines - 1))
  59                        fprintf(stdout, ", ");
  60        }
  61        fprintf(stdout, "] on %s, initial states: [", device_name);
  62        for (i = 0; i < num_lines; i++) {
  63                fprintf(stdout, "%d", gpiotools_test_bit(values.bits, i));
  64                if (i != (num_lines - 1))
  65                        fprintf(stdout, ", ");
  66        }
  67        fprintf(stdout, "]\n");
  68
  69        /* Hammertime! */
  70        j = 0;
  71        while (1) {
  72                /* Invert all lines so we blink */
  73                for (i = 0; i < num_lines; i++)
  74                        gpiotools_change_bit(&values.bits, i);
  75
  76                ret = gpiotools_set_values(fd, &values);
  77                if (ret < 0)
  78                        goto exit_close_error;
  79
  80                /* Re-read values to get status */
  81                ret = gpiotools_get_values(fd, &values);
  82                if (ret < 0)
  83                        goto exit_close_error;
  84
  85                fprintf(stdout, "[%c] ", swirr[j]);
  86                j++;
  87                if (j == sizeof(swirr) - 1)
  88                        j = 0;
  89
  90                fprintf(stdout, "[");
  91                for (i = 0; i < num_lines; i++) {
  92                        fprintf(stdout, "%d: %d", lines[i],
  93                                gpiotools_test_bit(values.bits, i));
  94                        if (i != (num_lines - 1))
  95                                fprintf(stdout, ", ");
  96                }
  97                fprintf(stdout, "]\r");
  98                fflush(stdout);
  99                sleep(1);
 100                iteration++;
 101                if (loops && iteration == loops)
 102                        break;
 103        }
 104        fprintf(stdout, "\n");
 105        ret = 0;
 106
 107exit_close_error:
 108        gpiotools_release_line(fd);
 109exit_error:
 110        return ret;
 111}
 112
 113void print_usage(void)
 114{
 115        fprintf(stderr, "Usage: gpio-hammer [options]...\n"
 116                "Hammer GPIO lines, 0->1->0->1...\n"
 117                "  -n <name>  Hammer GPIOs on a named device (must be stated)\n"
 118                "  -o <n>     Offset[s] to hammer, at least one, several can be stated\n"
 119                " [-c <n>]    Do <n> loops (optional, infinite loop if not stated)\n"
 120                "  -?         This helptext\n"
 121                "\n"
 122                "Example:\n"
 123                "gpio-hammer -n gpiochip0 -o 4\n"
 124        );
 125}
 126
 127int main(int argc, char **argv)
 128{
 129        const char *device_name = NULL;
 130        unsigned int lines[GPIOHANDLES_MAX];
 131        unsigned int loops = 0;
 132        int num_lines;
 133        int c;
 134        int i;
 135
 136        i = 0;
 137        while ((c = getopt(argc, argv, "c:n:o:?")) != -1) {
 138                switch (c) {
 139                case 'c':
 140                        loops = strtoul(optarg, NULL, 10);
 141                        break;
 142                case 'n':
 143                        device_name = optarg;
 144                        break;
 145                case 'o':
 146                        /*
 147                         * Avoid overflow. Do not immediately error, we want to
 148                         * be able to accurately report on the amount of times
 149                         * '-o' was given to give an accurate error message
 150                         */
 151                        if (i < GPIOHANDLES_MAX)
 152                                lines[i] = strtoul(optarg, NULL, 10);
 153
 154                        i++;
 155                        break;
 156                case '?':
 157                        print_usage();
 158                        return -1;
 159                }
 160        }
 161
 162        if (i >= GPIOHANDLES_MAX) {
 163                fprintf(stderr,
 164                        "Only %d occurrences of '-o' are allowed, %d were found\n",
 165                        GPIOHANDLES_MAX, i + 1);
 166                return -1;
 167        }
 168
 169        num_lines = i;
 170
 171        if (!device_name || !num_lines) {
 172                print_usage();
 173                return -1;
 174        }
 175        return hammer_device(device_name, lines, num_lines, loops);
 176}
 177