gpio: add getters and setters for bias, drive, inverted

resolves #23.
This commit is contained in:
Vanya A. Sergeev
2020-05-28 20:35:06 -05:00
parent 3719a82eb9
commit ecbd5aa85a
5 changed files with 386 additions and 24 deletions
+29 -2
View File
@@ -27,10 +27,16 @@ int gpio_poll_multiple(gpio_t **gpios, size_t count, int timeout_ms, bool *gpios
/* Getters */
int gpio_get_direction(gpio_t *gpio, gpio_direction_t *direction);
int gpio_get_edge(gpio_t *gpio, gpio_edge_t *edge);
int gpio_get_bias(gpio_t *gpio, gpio_bias_t *bias);
int gpio_get_drive(gpio_t *gpio, gpio_drive_t *drive);
int gpio_get_inverted(gpio_t *gpio, bool *inverted);
/* Setters */
int gpio_set_direction(gpio_t *gpio, gpio_direction_t direction);
int gpio_set_edge(gpio_t *gpio, gpio_edge_t edge);
int gpio_set_bias(gpio_t *gpio, gpio_bias_t edge);
int gpio_set_drive(gpio_t *gpio, gpio_drive_t drive);
int gpio_set_inverted(gpio_t *gpio, bool inverted);
/* Miscellaneous Properties */
unsigned int gpio_line(gpio_t *gpio);
@@ -61,6 +67,17 @@ const char *gpio_errmsg(gpio_t *gpio);
* `GPIO_EDGE_FALLING`: Falling edge (1 -> 0 transition)
* `GPIO_EDGE_BOTH`: Both edges (X -> !X transition)
* `gpio_bias_t`
* `GPIO_BIAS_DEFAULT`: Default line bias
* `GPIO_BIAS_PULL_UP`: Pull-up
* `GPIO_BIAS_PULL_DOWN`: Pull-down
* `GPIO_BIAS_DISABLE`: Disable line bias
* `gpio_drive_t`
* `GPIO_DRIVE_DEFAULT`: Default line drive (push-pull)
* `GPIO_DRIVE_OPEN_DRAIN`: Open drain
* `GPIO_DRIVE_OPEN_SOURCE`: Open source
### DESCRIPTION
``` c
@@ -188,8 +205,13 @@ Free a GPIO handle.
```c
int gpio_get_direction(gpio_t *gpio, gpio_direction_t *direction);
int gpio_get_edge(gpio_t *gpio, gpio_edge_t *edge);
int gpio_get_bias(gpio_t *gpio, gpio_bias_t *bias);
int gpio_get_drive(gpio_t *gpio, gpio_drive_t *drive);
int gpio_get_inverted(gpio_t *gpio, bool *inverted);
```
Get the configured direction or interrupt edge, respectively, of the GPIO.
Get the configured direction, interrupt edge, line bias, line drive, inverted (active low) properties, respectively, of the GPIO.
Line bias and line drive properties are not supported by sysfs GPIOs.
`gpio` should be a valid pointer to a GPIO handle opened with one of the `gpio_open*()` functions.
@@ -200,8 +222,13 @@ Returns 0 on success, or a negative [GPIO error code](#return-value) on failure.
```c
int gpio_set_direction(gpio_t *gpio, gpio_direction_t direction);
int gpio_set_edge(gpio_t *gpio, gpio_edge_t edge);
int gpio_set_bias(gpio_t *gpio, gpio_bias_t edge);
int gpio_set_drive(gpio_t *gpio, gpio_drive_t drive);
int gpio_set_inverted(gpio_t *gpio, bool inverted);
```
Set the direction or interrupt edge, respectively, of the GPIO.
Set the direction, interrupt edge, line bias, line drive, inverted (active low) properties, respectively, of the GPIO.
Line bias and line drive properties are not supported by sysfs GPIOs.
`gpio` should be a valid pointer to a GPIO handle opened with one of the `gpio_open*()` functions.
+251 -22
View File
@@ -34,8 +34,14 @@ struct gpio_ops {
int (*close)(gpio_t *gpio);
int (*get_direction)(gpio_t *gpio, gpio_direction_t *direction);
int (*get_edge)(gpio_t *gpio, gpio_edge_t *edge);
int (*get_bias)(gpio_t *gpio, gpio_bias_t *bias);
int (*get_drive)(gpio_t *gpio, gpio_drive_t *drive);
int (*get_inverted)(gpio_t *gpio, bool *inverted);
int (*set_direction)(gpio_t *gpio, gpio_direction_t direction);
int (*set_edge)(gpio_t *gpio, gpio_edge_t edge);
int (*set_bias)(gpio_t *gpio, gpio_bias_t bias);
int (*set_drive)(gpio_t *gpio, gpio_drive_t drive);
int (*set_inverted)(gpio_t *gpio, bool inverted);
unsigned int (*line)(gpio_t *gpio);
int (*fd)(gpio_t *gpio);
int (*name)(gpio_t *gpio, char *str, size_t len);
@@ -56,6 +62,10 @@ struct gpio_handle {
int chip_fd;
gpio_direction_t direction;
gpio_edge_t edge;
gpio_bias_t bias;
gpio_drive_t drive;
bool inverted;
char label[32];
} cdev;
struct {
unsigned int line;
@@ -130,6 +140,18 @@ int gpio_get_edge(gpio_t *gpio, gpio_edge_t *edge) {
return gpio->ops->get_edge(gpio, edge);
}
int gpio_get_bias(gpio_t *gpio, gpio_bias_t *bias) {
return gpio->ops->get_bias(gpio, bias);
}
int gpio_get_drive(gpio_t *gpio, gpio_drive_t *drive) {
return gpio->ops->get_drive(gpio, drive);
}
int gpio_get_inverted(gpio_t *gpio, bool *inverted) {
return gpio->ops->get_inverted(gpio, inverted);
}
int gpio_set_direction(gpio_t *gpio, gpio_direction_t direction) {
return gpio->ops->set_direction(gpio, direction);
}
@@ -138,6 +160,18 @@ int gpio_set_edge(gpio_t *gpio, gpio_edge_t edge) {
return gpio->ops->set_edge(gpio, edge);
}
int gpio_set_bias(gpio_t *gpio, gpio_bias_t bias) {
return gpio->ops->set_bias(gpio, bias);
}
int gpio_set_drive(gpio_t *gpio, gpio_drive_t drive) {
return gpio->ops->set_drive(gpio, drive);
}
int gpio_set_inverted(gpio_t *gpio, bool inverted) {
return gpio->ops->set_inverted(gpio, inverted);
}
unsigned int gpio_line(gpio_t *gpio) {
return gpio->ops->line(gpio);
}
@@ -479,6 +513,77 @@ static int gpio_sysfs_get_edge(gpio_t *gpio, gpio_edge_t *edge) {
return 0;
}
static int gpio_sysfs_set_bias(gpio_t *gpio, gpio_bias_t bias) {
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs does not support line bias attribute");
}
static int gpio_sysfs_get_bias(gpio_t *gpio, gpio_bias_t *bias) {
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs does not support line bias attribute");
}
static int gpio_sysfs_set_drive(gpio_t *gpio, gpio_drive_t drive) {
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs does not support line drive attribute");
}
static int gpio_sysfs_get_drive(gpio_t *gpio, gpio_drive_t *drive) {
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs does not support line drive attribute");
}
static int gpio_sysfs_set_inverted(gpio_t *gpio, bool inverted) {
char gpio_path[P_PATH_MAX];
static const char *inverted_str[2] = {"0\n", "1\n"};
int fd;
/* Write active_low */
snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%u/active_low", gpio->u.sysfs.line);
if ((fd = open(gpio_path, O_WRONLY)) < 0)
return _gpio_error(gpio, GPIO_ERROR_CONFIGURE, errno, "Opening GPIO 'active_low'");
if (write(fd, inverted_str[inverted], strlen(inverted_str[inverted])) < 0) {
int errsv = errno;
close(fd);
return _gpio_error(gpio, GPIO_ERROR_CONFIGURE, errsv, "Writing GPIO 'active_low'");
}
if (close(fd) < 0)
return _gpio_error(gpio, GPIO_ERROR_CONFIGURE, errno, "Closing GPIO 'active_low'");
return 0;
}
static int gpio_sysfs_get_inverted(gpio_t *gpio, bool *inverted) {
char gpio_path[P_PATH_MAX];
char buf[4];
int fd, ret;
/* Read active_low */
snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%u/active_low", gpio->u.sysfs.line);
if ((fd = open(gpio_path, O_RDONLY)) < 0)
return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Opening GPIO 'active_low'");
if ((ret = read(fd, buf, sizeof(buf))) < 0) {
int errsv = errno;
close(fd);
return _gpio_error(gpio, GPIO_ERROR_QUERY, errsv, "Reading GPIO 'active_low'");
}
if (close(fd) < 0)
return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Closing GPIO 'active_low'");
buf[ret] = '\0';
if (buf[0] == '0')
*inverted = false;
else if (buf[0] == '1')
*inverted = true;
else
return _gpio_error(gpio, GPIO_ERROR_QUERY, 0, "Unknown GPIO active_low value");
return 0;
}
static unsigned int gpio_sysfs_line(gpio_t *gpio) {
return gpio->u.sysfs.line;
}
@@ -560,6 +665,8 @@ static int gpio_sysfs_tostring(gpio_t *gpio, char *str, size_t len) {
const char *direction_str;
gpio_edge_t edge;
const char *edge_str;
bool inverted;
const char *inverted_str;
char chip_name[32];
const char *chip_name_str;
char chip_label[32];
@@ -579,6 +686,11 @@ static int gpio_sysfs_tostring(gpio_t *gpio, char *str, size_t len) {
(edge == GPIO_EDGE_FALLING) ? "falling" :
(edge == GPIO_EDGE_BOTH) ? "both" : "unknown";
if (gpio_sysfs_get_inverted(gpio, &inverted) < 0)
inverted_str = "<error>";
else
inverted_str = inverted ? "true" : "false";
if (gpio_sysfs_chip_name(gpio, chip_name, sizeof(chip_name)) < 0)
chip_name_str = "<error>";
else
@@ -589,8 +701,8 @@ static int gpio_sysfs_tostring(gpio_t *gpio, char *str, size_t len) {
else
chip_label_str = chip_label;
return snprintf(str, len, "GPIO %u (fd=%d, direction=%s, edge=%s, chip_name=\"%s\", chip_label=\"%s\", type=sysfs)",
gpio->u.sysfs.line, gpio->u.sysfs.line_fd, direction_str, edge_str, chip_name_str, chip_label_str);
return snprintf(str, len, "GPIO %u (fd=%d, direction=%s, edge=%s, inverted=%s, chip_name=\"%s\", chip_label=\"%s\", type=sysfs)",
gpio->u.sysfs.line, gpio->u.sysfs.line_fd, direction_str, edge_str, inverted_str, chip_name_str, chip_label_str);
}
static const struct gpio_ops gpio_sysfs_ops = {
@@ -601,8 +713,14 @@ static const struct gpio_ops gpio_sysfs_ops = {
.close = gpio_sysfs_close,
.get_direction = gpio_sysfs_get_direction,
.get_edge = gpio_sysfs_get_edge,
.get_bias = gpio_sysfs_get_bias,
.get_drive = gpio_sysfs_get_drive,
.get_inverted = gpio_sysfs_get_inverted,
.set_direction = gpio_sysfs_set_direction,
.set_edge = gpio_sysfs_set_edge,
.set_bias = gpio_sysfs_set_bias,
.set_drive = gpio_sysfs_set_drive,
.set_inverted = gpio_sysfs_set_inverted,
.line = gpio_sysfs_line,
.fd = gpio_sysfs_fd,
.name = gpio_sysfs_name,
@@ -713,12 +831,43 @@ int gpio_open_sysfs(gpio_t *gpio, unsigned int line, gpio_direction_t direction)
/* cdev implementation */
/*********************************************************************************/
static int _gpio_cdev_reopen(gpio_t *gpio, gpio_direction_t direction, gpio_edge_t edge) {
static const char gpio_label[] = "periphery";
static int _gpio_cdev_reopen(gpio_t *gpio, gpio_direction_t direction, gpio_edge_t edge, gpio_bias_t bias, gpio_drive_t drive, bool inverted) {
uint32_t flags = 0;
#ifdef GPIOHANDLE_REQUEST_BIAS_PULL_UP
if (bias == GPIO_BIAS_PULL_UP)
flags |= GPIOHANDLE_REQUEST_BIAS_PULL_UP;
else if (bias == GPIO_BIAS_PULL_DOWN)
flags |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN;
else if (bias == GPIO_BIAS_DISABLE)
flags |= GPIOHANDLE_REQUEST_BIAS_DISABLE;
#else
if (bias != GPIO_BIAS_DEFAULT)
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "Kernel version does not support configuring GPIO line bias");
#endif
#ifdef GPIOHANDLE_REQUEST_OPEN_DRAIN
if (drive == GPIO_DRIVE_OPEN_DRAIN)
flags |= GPIOHANDLE_REQUEST_OPEN_DRAIN;
else if (drive == GPIO_DRIVE_OPEN_SOURCE)
flags |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
#else
if (drive != GPIO_DRIVE_DEFAULT)
return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "Kernel version does not support configuring GPIO line drive");
#endif
if (inverted)
flags |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
/* FIXME this should really use GPIOHANDLE_SET_CONFIG_IOCTL instead of
* closing and reopening, especially to preserve output value on
* configuration changes */
if (gpio->u.cdev.line_fd >= 0) {
if (close(gpio->u.cdev.line_fd) < 0)
return _gpio_error(gpio, GPIO_ERROR_CLOSE, errno, "Closing GPIO line");
gpio->u.cdev.line_fd = -1;
}
if (direction == GPIO_DIR_IN) {
@@ -726,51 +875,52 @@ static int _gpio_cdev_reopen(gpio_t *gpio, gpio_direction_t direction, gpio_edge
struct gpiohandle_request request = {0};
request.lineoffsets[0] = gpio->u.cdev.line;
request.flags = GPIOHANDLE_REQUEST_INPUT;
strncpy(request.consumer_label, gpio_label, sizeof(request.consumer_label));
request.flags = flags | GPIOHANDLE_REQUEST_INPUT;
strncpy(request.consumer_label, gpio->u.cdev.label, sizeof(request.consumer_label));
request.lines = 1;
if (ioctl(gpio->u.cdev.chip_fd, GPIO_GET_LINEHANDLE_IOCTL, &request) < 0)
return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening input line handle");
gpio->u.cdev.line_fd = request.fd;
gpio->u.cdev.direction = GPIO_DIR_IN;
gpio->u.cdev.edge = GPIO_EDGE_NONE;
} else {
struct gpioevent_request request = {0};
request.lineoffset = gpio->u.cdev.line;
request.handleflags = GPIOHANDLE_REQUEST_INPUT;
request.handleflags = flags | GPIOHANDLE_REQUEST_INPUT;
request.eventflags = (edge == GPIO_EDGE_RISING) ? GPIOEVENT_REQUEST_RISING_EDGE :
(edge == GPIO_EDGE_FALLING) ? GPIOEVENT_REQUEST_FALLING_EDGE :
GPIOEVENT_REQUEST_BOTH_EDGES;
strncpy(request.consumer_label, gpio_label, sizeof(request.consumer_label));
strncpy(request.consumer_label, gpio->u.cdev.label, sizeof(request.consumer_label));
if (ioctl(gpio->u.cdev.chip_fd, GPIO_GET_LINEEVENT_IOCTL, &request) < 0)
return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening input event line handle");
gpio->u.cdev.line_fd = request.fd;
gpio->u.cdev.direction = GPIO_DIR_IN;
gpio->u.cdev.edge = edge;
}
} else {
struct gpiohandle_request request = {0};
bool initial_value = (direction == GPIO_DIR_OUT_HIGH) ? true : false;
initial_value ^= inverted;
request.lineoffsets[0] = gpio->u.cdev.line;
request.flags = GPIOHANDLE_REQUEST_OUTPUT;
request.flags = flags | GPIOHANDLE_REQUEST_OUTPUT;
request.default_values[0] = initial_value;
strncpy(request.consumer_label, gpio_label, sizeof(request.consumer_label));
strncpy(request.consumer_label, gpio->u.cdev.label, sizeof(request.consumer_label));
request.lines = 1;
if (ioctl(gpio->u.cdev.chip_fd, GPIO_GET_LINEHANDLE_IOCTL, &request) < 0)
return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening output line handle");
gpio->u.cdev.line_fd = request.fd;
gpio->u.cdev.direction = GPIO_DIR_OUT;
gpio->u.cdev.edge = GPIO_EDGE_NONE;
}
gpio->u.cdev.direction = (direction == GPIO_DIR_IN) ? GPIO_DIR_IN : GPIO_DIR_OUT;
gpio->u.cdev.edge = edge;
gpio->u.cdev.bias = bias;
gpio->u.cdev.drive = drive;
gpio->u.cdev.inverted = inverted;
return 0;
}
@@ -857,6 +1007,21 @@ static int gpio_cdev_get_edge(gpio_t *gpio, gpio_edge_t *edge) {
return 0;
}
static int gpio_cdev_get_bias(gpio_t *gpio, gpio_bias_t *bias) {
*bias = gpio->u.cdev.bias;
return 0;
}
static int gpio_cdev_get_drive(gpio_t *gpio, gpio_drive_t *drive) {
*drive = gpio->u.cdev.drive;
return 0;
}
static int gpio_cdev_get_inverted(gpio_t *gpio, bool *inverted) {
*inverted = gpio->u.cdev.inverted;
return 0;
}
static int gpio_cdev_set_direction(gpio_t *gpio, gpio_direction_t direction) {
if (direction != GPIO_DIR_IN && direction != GPIO_DIR_OUT && direction != GPIO_DIR_OUT_LOW && direction != GPIO_DIR_OUT_HIGH)
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO direction (can be in, out, low, high)");
@@ -864,7 +1029,7 @@ static int gpio_cdev_set_direction(gpio_t *gpio, gpio_direction_t direction) {
if (gpio->u.cdev.direction == direction)
return 0;
return _gpio_cdev_reopen(gpio, direction, GPIO_EDGE_NONE);
return _gpio_cdev_reopen(gpio, direction, GPIO_EDGE_NONE, gpio->u.cdev.bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
}
static int gpio_cdev_set_edge(gpio_t *gpio, gpio_edge_t edge) {
@@ -877,7 +1042,37 @@ static int gpio_cdev_set_edge(gpio_t *gpio, gpio_edge_t edge) {
if (gpio->u.cdev.edge == edge)
return 0;
return _gpio_cdev_reopen(gpio, GPIO_DIR_IN, edge);
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, edge, gpio->u.cdev.bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
}
static int gpio_cdev_set_bias(gpio_t *gpio, gpio_bias_t bias) {
if (bias != GPIO_BIAS_DEFAULT && bias != GPIO_BIAS_PULL_UP && bias != GPIO_BIAS_PULL_DOWN && bias != GPIO_BIAS_DISABLE)
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO line bias (can be default, pull_up, pull_down, disable)");
if (gpio->u.cdev.bias == bias)
return 0;
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, bias, gpio->u.cdev.drive, gpio->u.cdev.inverted);
}
static int gpio_cdev_set_drive(gpio_t *gpio, gpio_drive_t drive) {
if (drive != GPIO_DRIVE_DEFAULT && drive != GPIO_DRIVE_OPEN_DRAIN && drive != GPIO_DRIVE_OPEN_SOURCE)
return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO line drive (can be default, open_drain, open_source)");
if (gpio->u.cdev.direction != GPIO_DIR_OUT && drive != GPIO_DRIVE_DEFAULT)
return _gpio_error(gpio, GPIO_ERROR_INVALID_OPERATION, 0, "Invalid operation: cannot set line drive on input GPIO");
if (gpio->u.cdev.drive == drive)
return 0;
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, gpio->u.cdev.bias, drive, gpio->u.cdev.inverted);
}
static int gpio_cdev_set_inverted(gpio_t *gpio, bool inverted) {
if (gpio->u.cdev.inverted == inverted)
return 0;
return _gpio_cdev_reopen(gpio, gpio->u.cdev.direction, gpio->u.cdev.edge, gpio->u.cdev.bias, gpio->u.cdev.drive, inverted);
}
static unsigned int gpio_cdev_line(gpio_t *gpio) {
@@ -949,6 +1144,12 @@ static int gpio_cdev_tostring(gpio_t *gpio, char *str, size_t len) {
const char *direction_str;
gpio_edge_t edge;
const char *edge_str;
gpio_bias_t bias;
const char *bias_str;
gpio_drive_t drive;
const char *drive_str;
bool inverted;
const char *inverted_str;
char line_name[32];
const char *line_name_str;
char line_label[32];
@@ -972,6 +1173,26 @@ static int gpio_cdev_tostring(gpio_t *gpio, char *str, size_t len) {
(edge == GPIO_EDGE_FALLING) ? "falling" :
(edge == GPIO_EDGE_BOTH) ? "both" : "unknown";
if (gpio_cdev_get_bias(gpio, &bias) < 0)
bias_str = "<error>";
else
bias_str = (bias == GPIO_BIAS_DEFAULT) ? "default" :
(bias == GPIO_BIAS_PULL_UP) ? "pull_up" :
(bias == GPIO_BIAS_PULL_DOWN) ? "pull_down" :
(bias == GPIO_BIAS_DISABLE) ? "disable" : "unknown";
if (gpio_cdev_get_drive(gpio, &drive) < 0)
drive_str = "<error>";
else
drive_str = (drive == GPIO_DRIVE_DEFAULT) ? "default" :
(drive == GPIO_DRIVE_OPEN_DRAIN) ? "open_drain" :
(drive == GPIO_DRIVE_OPEN_SOURCE) ? "open_source" : "unknown";
if (gpio_cdev_get_inverted(gpio, &inverted) < 0)
inverted_str = "<error>";
else
inverted_str = inverted ? "true" : "false";
if (gpio_cdev_name(gpio, line_name, sizeof(line_name)) < 0)
line_name_str = "<error>";
else
@@ -992,8 +1213,8 @@ static int gpio_cdev_tostring(gpio_t *gpio, char *str, size_t len) {
else
chip_label_str = chip_label;
return snprintf(str, len, "GPIO %u (name=\"%s\", label=\"%s\", line_fd=%d, chip_fd=%d, direction=%s, edge=%s, chip_name=\"%s\", chip_label=\"%s\", type=cdev)",
gpio->u.cdev.line, line_name_str, line_label_str, gpio->u.cdev.line_fd, gpio->u.cdev.chip_fd, direction_str, edge_str, chip_name_str, chip_label_str);
return snprintf(str, len, "GPIO %u (name=\"%s\", label=\"%s\", line_fd=%d, chip_fd=%d, direction=%s, edge=%s, bias=%s, drive=%s, inverted=%s, chip_name=\"%s\", chip_label=\"%s\", type=cdev)",
gpio->u.cdev.line, line_name_str, line_label_str, gpio->u.cdev.line_fd, gpio->u.cdev.chip_fd, direction_str, edge_str, bias_str, drive_str, inverted_str, chip_name_str, chip_label_str);
}
static const struct gpio_ops gpio_cdev_ops = {
@@ -1004,8 +1225,14 @@ static const struct gpio_ops gpio_cdev_ops = {
.close = gpio_cdev_close,
.get_direction = gpio_cdev_get_direction,
.get_edge = gpio_cdev_get_edge,
.get_bias = gpio_cdev_get_bias,
.get_drive = gpio_cdev_get_drive,
.get_inverted = gpio_cdev_get_inverted,
.set_direction = gpio_cdev_set_direction,
.set_edge = gpio_cdev_set_edge,
.set_bias = gpio_cdev_set_bias,
.set_drive = gpio_cdev_set_drive,
.set_inverted = gpio_cdev_set_inverted,
.line = gpio_cdev_line,
.fd = gpio_cdev_fd,
.name = gpio_cdev_name,
@@ -1031,9 +1258,10 @@ int gpio_open(gpio_t *gpio, const char *path, unsigned int line, gpio_direction_
gpio->u.cdev.line = line;
gpio->u.cdev.line_fd = -1;
gpio->u.cdev.chip_fd = fd;
strncpy(gpio->u.cdev.label, "periphery", sizeof(gpio->u.cdev.label));
/* Open GPIO line */
ret = _gpio_cdev_reopen(gpio, direction, GPIO_EDGE_NONE);
ret = _gpio_cdev_reopen(gpio, direction, GPIO_EDGE_NONE, GPIO_BIAS_DEFAULT, GPIO_DRIVE_DEFAULT, false);
if (ret < 0) {
close(fd);
return ret;
@@ -1089,9 +1317,10 @@ int gpio_open_name(gpio_t *gpio, const char *path, const char *name, gpio_direct
gpio->u.cdev.line = line;
gpio->u.cdev.line_fd = -1;
gpio->u.cdev.chip_fd = fd;
strncpy(gpio->u.cdev.label, "periphery", sizeof(gpio->u.cdev.label));
/* Open GPIO line */
ret = _gpio_cdev_reopen(gpio, direction, GPIO_EDGE_NONE);
ret = _gpio_cdev_reopen(gpio, direction, GPIO_EDGE_NONE, GPIO_BIAS_DEFAULT, GPIO_DRIVE_DEFAULT, false);
if (ret < 0) {
close(fd);
return ret;
+19
View File
@@ -41,6 +41,19 @@ typedef enum gpio_edge {
GPIO_EDGE_BOTH /* Both edges X -> !X */
} gpio_edge_t;
typedef enum gpio_bias {
GPIO_BIAS_DEFAULT, /* Default line bias */
GPIO_BIAS_PULL_UP, /* Pull-up */
GPIO_BIAS_PULL_DOWN, /* Pull-down */
GPIO_BIAS_DISABLE, /* Disable line bias */
} gpio_bias_t;
typedef enum gpio_drive {
GPIO_DRIVE_DEFAULT, /* Default line drive (push-pull) */
GPIO_DRIVE_OPEN_DRAIN, /* Open drain */
GPIO_DRIVE_OPEN_SOURCE, /* Open source */
} gpio_drive_t;
typedef struct gpio_handle gpio_t;
/* Primary Functions */
@@ -63,10 +76,16 @@ int gpio_poll_multiple(gpio_t **gpios, size_t count, int timeout_ms, bool *gpios
/* Getters */
int gpio_get_direction(gpio_t *gpio, gpio_direction_t *direction);
int gpio_get_edge(gpio_t *gpio, gpio_edge_t *edge);
int gpio_get_bias(gpio_t *gpio, gpio_bias_t *bias);
int gpio_get_drive(gpio_t *gpio, gpio_drive_t *drive);
int gpio_get_inverted(gpio_t *gpio, bool *inverted);
/* Setters */
int gpio_set_direction(gpio_t *gpio, gpio_direction_t direction);
int gpio_set_edge(gpio_t *gpio, gpio_edge_t edge);
int gpio_set_bias(gpio_t *gpio, gpio_bias_t edge);
int gpio_set_drive(gpio_t *gpio, gpio_drive_t drive);
int gpio_set_inverted(gpio_t *gpio, bool inverted);
/* Miscellaneous Properties */
unsigned int gpio_line(gpio_t *gpio);
+69
View File
@@ -42,6 +42,9 @@ void test_open_config_close(void) {
gpio_direction_t direction;
gpio_edge_t edge;
char label[32];
gpio_bias_t bias;
gpio_drive_t drive;
bool inverted;
ptest();
@@ -69,6 +72,10 @@ void test_open_config_close(void) {
passert(gpio_set_direction(gpio, 5) == GPIO_ERROR_ARG);
/* Invalid interrupt edge */
passert(gpio_set_edge(gpio, 5) == GPIO_ERROR_ARG);
/* Invalid bias */
passert(gpio_set_bias(gpio, 5) == GPIO_ERROR_ARG);
/* Invalid drive */
passert(gpio_set_drive(gpio, 5) == GPIO_ERROR_ARG);
/* Set direction out, check direction out, check value low */
passert(gpio_set_direction(gpio, GPIO_DIR_OUT) == 0);
@@ -88,6 +95,29 @@ void test_open_config_close(void) {
passert(direction == GPIO_DIR_OUT);
passert(gpio_read(gpio, &value) == 0);
passert(value == true);
/* Set drive open drain, check drive open drain */
passert(gpio_set_drive(gpio, GPIO_DRIVE_OPEN_DRAIN) == 0);
passert(gpio_get_drive(gpio, &drive) == 0);
passert(drive == GPIO_DRIVE_OPEN_DRAIN);
/* Set drive open source, check drive open source */
passert(gpio_set_drive(gpio, GPIO_DRIVE_OPEN_SOURCE) == 0);
passert(gpio_get_drive(gpio, &drive) == 0);
passert(drive == GPIO_DRIVE_OPEN_SOURCE);
/* Set drive default, check drive default */
passert(gpio_set_drive(gpio, GPIO_DRIVE_DEFAULT) == 0);
passert(gpio_get_drive(gpio, &drive) == 0);
passert(drive == GPIO_DRIVE_DEFAULT);
/* Set inverted true, check inverted true */
passert(gpio_set_inverted(gpio, true) == 0);
passert(gpio_get_inverted(gpio, &inverted) == 0);
passert(inverted == true);
/* Set inverted false, check inverted false */
passert(gpio_set_inverted(gpio, false) == 0);
passert(gpio_get_inverted(gpio, &inverted) == 0);
passert(inverted == false);
/* Attempt to set interrupt edge on output GPIO */
passert(gpio_set_edge(gpio, GPIO_EDGE_RISING) == GPIO_ERROR_INVALID_OPERATION);
/* Attempt to read event on output GPIO */
@@ -120,6 +150,26 @@ void test_open_config_close(void) {
passert(gpio_get_edge(gpio, &edge) == 0);
passert(edge == GPIO_EDGE_NONE);
/* Set bias pull up, check bias pull up */
passert(gpio_set_bias(gpio, GPIO_BIAS_PULL_UP) == 0);
passert(gpio_get_bias(gpio, &bias) == 0);
passert(bias == GPIO_BIAS_PULL_UP);
/* Set bias pull down, check bias pull down */
passert(gpio_set_bias(gpio, GPIO_BIAS_PULL_DOWN) == 0);
passert(gpio_get_bias(gpio, &bias) == 0);
passert(bias == GPIO_BIAS_PULL_DOWN);
/* Set bias disable, check bias disable */
passert(gpio_set_bias(gpio, GPIO_BIAS_DISABLE) == 0);
passert(gpio_get_bias(gpio, &bias) == 0);
passert(bias == GPIO_BIAS_DISABLE);
/* Set bias default, check bias default */
passert(gpio_set_bias(gpio, GPIO_BIAS_DEFAULT) == 0);
passert(gpio_get_bias(gpio, &bias) == 0);
passert(bias == GPIO_BIAS_DEFAULT);
/* Attempt to set drive on input GPIO */
passert(gpio_set_drive(gpio, GPIO_DRIVE_OPEN_DRAIN) == GPIO_ERROR_INVALID_OPERATION);
/* Close GPIO */
passert(gpio_close(gpio) == 0);
@@ -265,6 +315,25 @@ void test_loopback(void) {
passert(gpio_close(gpio_in) == 0);
passert(gpio_close(gpio_out) == 0);
/* Open both GPIOs as inputs */
passert(gpio_open(gpio_in, device, pin_input, GPIO_DIR_IN) == 0);
passert(gpio_open(gpio_out, device, pin_output, GPIO_DIR_IN) == 0);
/* Set bias pull-up, check value is high */
passert(gpio_set_bias(gpio_in, GPIO_BIAS_PULL_UP) == 0);
usleep(1000);
passert(gpio_read(gpio_in, &value) == 0);
passert(value == true);
/* Set bias pull-down, check value is low */
passert(gpio_set_bias(gpio_in, GPIO_BIAS_PULL_DOWN) == 0);
usleep(1000);
passert(gpio_read(gpio_in, &value) == 0);
passert(value == false);
passert(gpio_close(gpio_in) == 0);
passert(gpio_close(gpio_out) == 0);
/* Free GPIO */
gpio_free(gpio_in);
gpio_free(gpio_out);
+18
View File
@@ -39,6 +39,9 @@ void test_open_config_close(void) {
bool value;
gpio_direction_t direction;
gpio_edge_t edge;
gpio_bias_t bias;
gpio_drive_t drive;
bool inverted;
ptest();
@@ -61,6 +64,12 @@ void test_open_config_close(void) {
passert(gpio_set_direction(gpio, 5) == GPIO_ERROR_ARG);
/* Invalid interrupt edge */
passert(gpio_set_edge(gpio, 5) == GPIO_ERROR_ARG);
/* Unsupported setting bias */
passert(gpio_set_bias(gpio, GPIO_BIAS_PULL_UP) == GPIO_ERROR_UNSUPPORTED);
passert(gpio_get_bias(gpio, &bias) == GPIO_ERROR_UNSUPPORTED);
/* Unsupported setting drive */
passert(gpio_set_drive(gpio, GPIO_DRIVE_OPEN_DRAIN) == GPIO_ERROR_UNSUPPORTED);
passert(gpio_get_drive(gpio, &drive) == GPIO_ERROR_UNSUPPORTED);
/* Unsupported property */
passert(gpio_chip_fd(gpio) == GPIO_ERROR_UNSUPPORTED);
/* Unsupported method */
@@ -85,6 +94,15 @@ void test_open_config_close(void) {
passert(gpio_read(gpio, &value) == 0);
passert(value == true);
/* Set inverted true, check inverted */
passert(gpio_set_inverted(gpio, true) == 0);
passert(gpio_get_inverted(gpio, &inverted) == 0);
passert(inverted == true);
/* Set inverted false, check inverted */
passert(gpio_set_inverted(gpio, false) == 0);
passert(gpio_get_inverted(gpio, &inverted) == 0);
passert(inverted == false);
/* Set direction in, check direction in */
passert(gpio_set_direction(gpio, GPIO_DIR_IN) == 0);
passert(gpio_get_direction(gpio, &direction) == 0);