From 3dc1e4e72b7da597c98761a7bb7cb5aa5c885584 Mon Sep 17 00:00:00 2001 From: Alexander Smirnov Date: Sun, 3 Apr 2022 20:29:56 +0100 Subject: [PATCH 1/2] Wait and retry until deplayed udev permission rule applies after exporting gpio pin --- src/linuxgpio.c | 54 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/src/linuxgpio.c b/src/linuxgpio.c index 86fefd76..36687612 100644 --- a/src/linuxgpio.c +++ b/src/linuxgpio.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "avrdude.h" #include "libavrdude.h" @@ -108,7 +109,8 @@ static int linuxgpio_dir(unsigned int gpio, unsigned int dir) fd = open(buf, O_WRONLY); if (fd < 0) { - perror("Can't open gpioX/direction"); + snprintf(buf, sizeof(buf), "Can't open gpio%u/direction", gpio); + perror(buf); return fd; } @@ -138,6 +140,11 @@ static int linuxgpio_dir_in(unsigned int gpio) #define N_GPIO (PIN_MAX + 1) +/* Delay between checks for successful GPIO export (100ms) */ +#define GPIO_SYSFS_OPEN_DELAY 100000 +/* Number of retries to check for successful GPIO exports */ +#define GPIO_SYSFS_OPEN_RETRIES 10 + /* * an array which holds open FDs to /sys/class/gpio/gpioXX/value for all needed pins */ @@ -245,6 +252,8 @@ static void linuxgpio_powerdown(PROGRAMMER *pgm) static int linuxgpio_open(PROGRAMMER *pgm, char *port) { int r, i, pin; + char gpio_path[60]; + struct stat stat_buf; if (bitbang_check_prerequisites(pgm) < 0) return -1; @@ -272,13 +281,46 @@ static int linuxgpio_open(PROGRAMMER *pgm, char *port) pin, strerror(errno)); return r; } - if (i == PIN_AVR_MISO) - r=linuxgpio_dir_in(pin); - else - r=linuxgpio_dir_out(pin); - if (r < 0) + /* Wait until GPIO directory appears */ + snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%u", pin); + unsigned int retry_count; + for (retry_count = 0; retry_count < GPIO_SYSFS_OPEN_RETRIES; retry_count++) { + int ret = stat(gpio_path, &stat_buf); + if (ret == 0) { + break; + } else if (ret < 0 && errno != ENOENT) { + linuxgpio_unexport(pin); + return ret; + } + + usleep(GPIO_SYSFS_OPEN_DELAY); + } + + /* Write direction, looping in case of EACCES errors due to delayed + * udev permission rule application after export */ + for (retry_count = GPIO_SYSFS_OPEN_RETRIES; retry_count > 0; retry_count--) { + usleep(GPIO_SYSFS_OPEN_DELAY); + if (i == PIN_AVR_MISO) + r=linuxgpio_dir_in(pin); + else + r=linuxgpio_dir_out(pin); + + if (r >= 0) { + break; + } else if (errno != EACCES) { + linuxgpio_unexport(pin); + return r; + } + if (retry_count > 1) { + printf("Retrying...\n"); + } + } + + if (r < 0) { + linuxgpio_unexport(pin); return r; + } if ((linuxgpio_fds[pin]=linuxgpio_openfd(pin)) < 0) return linuxgpio_fds[pin]; From 097c78098d33f19aecdd4ed41d7af7edd5ab9be3 Mon Sep 17 00:00:00 2001 From: Stefan Rueger Date: Fri, 23 Sep 2022 23:28:47 +0100 Subject: [PATCH 2/2] Change printf() to avrdude_message() in linuxgio.c --- src/linuxgpio.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/linuxgpio.c b/src/linuxgpio.c index 36687612..0d4057e7 100644 --- a/src/linuxgpio.c +++ b/src/linuxgpio.c @@ -299,24 +299,27 @@ static int linuxgpio_open(PROGRAMMER *pgm, char *port) /* Write direction, looping in case of EACCES errors due to delayed * udev permission rule application after export */ - for (retry_count = GPIO_SYSFS_OPEN_RETRIES; retry_count > 0; retry_count--) { + for (retry_count = 0; retry_count < GPIO_SYSFS_OPEN_RETRIES; retry_count++) { usleep(GPIO_SYSFS_OPEN_DELAY); if (i == PIN_AVR_MISO) r=linuxgpio_dir_in(pin); else r=linuxgpio_dir_out(pin); - if (r >= 0) { + if (r >= 0) break; - } else if (errno != EACCES) { + + if (errno != EACCES) { linuxgpio_unexport(pin); return r; } - if (retry_count > 1) { - printf("Retrying...\n"); - } } + if (retry_count) + avrdude_message(MSG_NOTICE2, "%s: needed %d retr%s for linuxgpio_dir_%s(%s)\n", + progname, retry_count, retry_count > 1? "ies": "y", + i == PIN_AVR_MISO? "in": "out", avr_pin_name(pin)); + if (r < 0) { linuxgpio_unexport(pin); return r;