Private
Public Access
2
0

gpio: Avoid spurious value reset without output mode changes

When a GPIO controlled via sysfs is set again to output mode, the kernel
also sets the value to 0. This can cause spurious output or mux changes,
e.g. when calling "mraa-gpio set <n> 1" for a pin that was already set.

Avoid this by checking the current direction, only writing it when
actually needed.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
This commit is contained in:
Jan Kiszka
2021-04-30 18:57:44 +02:00
committed by Tom Ingleby
parent aaa0a5cd4e
commit e446cf0110

View File

@@ -1218,6 +1218,31 @@ mraa_gpio_chardev_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
return MRAA_SUCCESS; return MRAA_SUCCESS;
} }
static mraa_result_t
gpio_sysfs_read_dir(mraa_gpio_context dev, int dir_fd, mraa_gpio_dir_t *dir)
{
char value[5];
int rc;
memset(value, '\0', sizeof(value));
rc = read(dir_fd, value, sizeof(value));
if (rc <= 0) {
syslog(LOG_ERR, "gpio%i: read_dir: Failed to read 'direction': %s", dev->pin, strerror(errno));
return MRAA_ERROR_INVALID_RESOURCE;
}
if (strcmp(value, "out\n") == 0) {
*dir = MRAA_GPIO_OUT;
} else if (strcmp(value, "in\n") == 0) {
*dir = MRAA_GPIO_IN;
} else {
syslog(LOG_ERR, "gpio%i: read_dir: unknown direction: %s", dev->pin, value);
return MRAA_ERROR_UNSPECIFIED;
}
return MRAA_SUCCESS;
}
mraa_result_t mraa_result_t
mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir) mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
{ {
@@ -1267,6 +1292,13 @@ mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
} }
} }
mraa_gpio_dir_t cur_dir;
mraa_result_t result = gpio_sysfs_read_dir(dev, direction, &cur_dir);
if (result != MRAA_SUCCESS) {
return result;
}
if (cur_dir != dir) {
char bu[MAX_SIZE]; char bu[MAX_SIZE];
int length; int length;
switch (dir) { switch (dir) {
@@ -1292,6 +1324,7 @@ mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
syslog(LOG_ERR, "gpio%i: dir: Failed to write to 'direction': %s", it->pin, strerror(errno)); syslog(LOG_ERR, "gpio%i: dir: Failed to write to 'direction': %s", it->pin, strerror(errno));
return MRAA_ERROR_UNSPECIFIED; return MRAA_ERROR_UNSPECIFIED;
} }
}
close(direction); close(direction);
it = it->next; it = it->next;
@@ -1340,9 +1373,8 @@ mraa_gpio_read_dir(mraa_gpio_context dev, mraa_gpio_dir_t* dir)
*dir = flags & GPIOLINE_FLAG_IS_OUT ? MRAA_GPIO_OUT : MRAA_GPIO_IN; *dir = flags & GPIOLINE_FLAG_IS_OUT ? MRAA_GPIO_OUT : MRAA_GPIO_IN;
} else { } else {
char value[5];
char filepath[MAX_SIZE]; char filepath[MAX_SIZE];
int fd, rc; int fd;
if (dev == NULL) { if (dev == NULL) {
syslog(LOG_ERR, "gpio: read_dir: context is invalid"); syslog(LOG_ERR, "gpio: read_dir: context is invalid");
@@ -1362,22 +1394,8 @@ mraa_gpio_read_dir(mraa_gpio_context dev, mraa_gpio_dir_t* dir)
return MRAA_ERROR_INVALID_RESOURCE; return MRAA_ERROR_INVALID_RESOURCE;
} }
memset(value, '\0', sizeof(value)); result = gpio_sysfs_read_dir(dev, fd, dir);
rc = read(fd, value, sizeof(value));
close(fd); close(fd);
if (rc <= 0) {
syslog(LOG_ERR, "gpio%i: read_dir: Failed to read 'direction': %s", dev->pin, strerror(errno));
return MRAA_ERROR_INVALID_RESOURCE;
}
if (strcmp(value, "out\n") == 0) {
*dir = MRAA_GPIO_OUT;
} else if (strcmp(value, "in\n") == 0) {
*dir = MRAA_GPIO_IN;
} else {
syslog(LOG_ERR, "gpio%i: read_dir: unknown direction: %s", dev->pin, value);
result = MRAA_ERROR_UNSPECIFIED;
}
} }
return result; return result;