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:
@@ -1218,6 +1218,31 @@ mraa_gpio_chardev_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
|
||||
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_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
|
||||
{
|
||||
@@ -1267,30 +1292,38 @@ mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
|
||||
}
|
||||
}
|
||||
|
||||
char bu[MAX_SIZE];
|
||||
int length;
|
||||
switch (dir) {
|
||||
case MRAA_GPIO_OUT:
|
||||
length = snprintf(bu, sizeof(bu), "out");
|
||||
break;
|
||||
case MRAA_GPIO_IN:
|
||||
length = snprintf(bu, sizeof(bu), "in");
|
||||
break;
|
||||
case MRAA_GPIO_OUT_HIGH:
|
||||
length = snprintf(bu, sizeof(bu), "high");
|
||||
break;
|
||||
case MRAA_GPIO_OUT_LOW:
|
||||
length = snprintf(bu, sizeof(bu), "low");
|
||||
break;
|
||||
default:
|
||||
close(direction);
|
||||
return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
|
||||
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 (write(direction, bu, length * sizeof(char)) == -1) {
|
||||
close(direction);
|
||||
syslog(LOG_ERR, "gpio%i: dir: Failed to write to 'direction': %s", it->pin, strerror(errno));
|
||||
return MRAA_ERROR_UNSPECIFIED;
|
||||
if (cur_dir != dir) {
|
||||
char bu[MAX_SIZE];
|
||||
int length;
|
||||
switch (dir) {
|
||||
case MRAA_GPIO_OUT:
|
||||
length = snprintf(bu, sizeof(bu), "out");
|
||||
break;
|
||||
case MRAA_GPIO_IN:
|
||||
length = snprintf(bu, sizeof(bu), "in");
|
||||
break;
|
||||
case MRAA_GPIO_OUT_HIGH:
|
||||
length = snprintf(bu, sizeof(bu), "high");
|
||||
break;
|
||||
case MRAA_GPIO_OUT_LOW:
|
||||
length = snprintf(bu, sizeof(bu), "low");
|
||||
break;
|
||||
default:
|
||||
close(direction);
|
||||
return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
if (write(direction, bu, length * sizeof(char)) == -1) {
|
||||
close(direction);
|
||||
syslog(LOG_ERR, "gpio%i: dir: Failed to write to 'direction': %s", it->pin, strerror(errno));
|
||||
return MRAA_ERROR_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
close(direction);
|
||||
@@ -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;
|
||||
} else {
|
||||
char value[5];
|
||||
char filepath[MAX_SIZE];
|
||||
int fd, rc;
|
||||
int fd;
|
||||
|
||||
if (dev == NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
memset(value, '\0', sizeof(value));
|
||||
rc = read(fd, value, sizeof(value));
|
||||
result = gpio_sysfs_read_dir(dev, fd, dir);
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user