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;
|
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,30 +1292,38 @@ mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char bu[MAX_SIZE];
|
mraa_gpio_dir_t cur_dir;
|
||||||
int length;
|
mraa_result_t result = gpio_sysfs_read_dir(dev, direction, &cur_dir);
|
||||||
switch (dir) {
|
if (result != MRAA_SUCCESS) {
|
||||||
case MRAA_GPIO_OUT:
|
return result;
|
||||||
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) {
|
if (cur_dir != dir) {
|
||||||
close(direction);
|
char bu[MAX_SIZE];
|
||||||
syslog(LOG_ERR, "gpio%i: dir: Failed to write to 'direction': %s", it->pin, strerror(errno));
|
int length;
|
||||||
return MRAA_ERROR_UNSPECIFIED;
|
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);
|
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;
|
*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;
|
||||||
|
|||||||
Reference in New Issue
Block a user