Wait and retry until deplayed udev permission rule applies after exporting gpio pin

This commit is contained in:
Alexander Smirnov 2022-04-03 20:29:56 +01:00
parent e069871c8e
commit 3dc1e4e72b
1 changed files with 48 additions and 6 deletions

View File

@ -27,6 +27,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <sys/stat.h>
#include "avrdude.h" #include "avrdude.h"
#include "libavrdude.h" #include "libavrdude.h"
@ -108,7 +109,8 @@ static int linuxgpio_dir(unsigned int gpio, unsigned int dir)
fd = open(buf, O_WRONLY); fd = open(buf, O_WRONLY);
if (fd < 0) { if (fd < 0) {
perror("Can't open gpioX/direction"); snprintf(buf, sizeof(buf), "Can't open gpio%u/direction", gpio);
perror(buf);
return fd; return fd;
} }
@ -138,6 +140,11 @@ static int linuxgpio_dir_in(unsigned int gpio)
#define N_GPIO (PIN_MAX + 1) #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 * 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) static int linuxgpio_open(PROGRAMMER *pgm, char *port)
{ {
int r, i, pin; int r, i, pin;
char gpio_path[60];
struct stat stat_buf;
if (bitbang_check_prerequisites(pgm) < 0) if (bitbang_check_prerequisites(pgm) < 0)
return -1; return -1;
@ -272,13 +281,46 @@ static int linuxgpio_open(PROGRAMMER *pgm, char *port)
pin, strerror(errno)); pin, strerror(errno));
return r; return r;
} }
/* 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) if (i == PIN_AVR_MISO)
r=linuxgpio_dir_in(pin); r=linuxgpio_dir_in(pin);
else else
r=linuxgpio_dir_out(pin); r=linuxgpio_dir_out(pin);
if (r < 0) if (r >= 0) {
break;
} else if (errno != EACCES) {
linuxgpio_unexport(pin);
return r; 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) if ((linuxgpio_fds[pin]=linuxgpio_openfd(pin)) < 0)
return linuxgpio_fds[pin]; return linuxgpio_fds[pin];