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