diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..59f7998c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "sys/arm-linux/c-periphery"] + path = sys/arm-linux/c-periphery + url = https://github.com/vsergeev/c-periphery diff --git a/sys/arm-linux/c-periphery b/sys/arm-linux/c-periphery new file mode 160000 index 00000000..23795679 --- /dev/null +++ b/sys/arm-linux/c-periphery @@ -0,0 +1 @@ +Subproject commit 2379567960b9f72ccfb8f9db7271092612e89bdf diff --git a/sys/arm-linux/drivers b/sys/arm-linux/drivers new file mode 120000 index 00000000..3cb7783e --- /dev/null +++ b/sys/arm-linux/drivers @@ -0,0 +1 @@ +./c-periphery/src \ No newline at end of file diff --git a/sys/arm-linux/drivers/gpio.c b/sys/arm-linux/drivers/gpio.c deleted file mode 100644 index a248926f..00000000 --- a/sys/arm-linux/drivers/gpio.c +++ /dev/null @@ -1,1444 +0,0 @@ -/* - * c-periphery - * https://github.com/vsergeev/c-periphery - * License: MIT - */ - -#define _XOPEN_SOURCE 600 /* for POLLRDNORM */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#if PERIPHERY_GPIO_CDEV_SUPPORT -#include - -/* Disable cdev support when building with older kernel headers that don't yet - * support line events in the gpio-cdev abi */ -#ifndef GPIO_GET_LINEEVENT_IOCTL -#undef PERIPHERY_GPIO_CDEV_SUPPORT -#endif -#endif - -#include "gpio.h" - -/*********************************************************************************/ -/* Operations table and handle structure */ -/*********************************************************************************/ - -struct gpio_ops { - int (*read)(gpio_t *gpio, bool *value); - int (*write)(gpio_t *gpio, bool value); - int (*read_event)(gpio_t *gpio, gpio_edge_t *edge, uint64_t *timestamp); - int (*poll)(gpio_t *gpio, int timeout_ms); - 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); - int (*label)(gpio_t *gpio, char *str, size_t len); - int (*chip_fd)(gpio_t *gpio); - int (*chip_name)(gpio_t *gpio, char *str, size_t len); - int (*chip_label)(gpio_t *gpio, char *str, size_t len); - int (*tostring)(gpio_t *gpio, char *str, size_t len); -}; - -struct gpio_handle { - const struct gpio_ops *ops; - - union { - struct { - unsigned int line; - int line_fd; - 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; - int line_fd; - bool exported; - } sysfs; - } u; - - /* error state */ - struct { - int c_errno; - char errmsg[96]; - } error; -}; - -static const struct gpio_ops gpio_cdev_ops; -static const struct gpio_ops gpio_sysfs_ops; - -/*********************************************************************************/ -/* Public interface, except for open()s */ -/*********************************************************************************/ - -gpio_t *gpio_new(void) { - gpio_t *gpio = calloc(1, sizeof(gpio_t)); - if (gpio == NULL) - return NULL; - - gpio->ops = &gpio_cdev_ops; - gpio->u.cdev.line_fd = -1; - gpio->u.cdev.chip_fd = -1; - - return gpio; -} - -void gpio_free(gpio_t *gpio) { - free(gpio); -} - -const char *gpio_errmsg(gpio_t *gpio) { - return gpio->error.errmsg; -} - -int gpio_errno(gpio_t *gpio) { - return gpio->error.c_errno; -} - -int gpio_read(gpio_t *gpio, bool *value) { - return gpio->ops->read(gpio, value); -} - -int gpio_write(gpio_t *gpio, bool value) { - return gpio->ops->write(gpio, value); -} - -int gpio_read_event(gpio_t *gpio, gpio_edge_t *edge, uint64_t *timestamp) { - return gpio->ops->read_event(gpio, edge, timestamp); -} - -int gpio_poll(gpio_t *gpio, int timeout_ms) { - return gpio->ops->poll(gpio, timeout_ms); -} - -int gpio_close(gpio_t *gpio) { - return gpio->ops->close(gpio); -} - -int gpio_get_direction(gpio_t *gpio, gpio_direction_t *direction) { - return gpio->ops->get_direction(gpio, direction); -} - -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); -} - -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); -} - -int gpio_fd(gpio_t *gpio) { - return gpio->ops->fd(gpio); -} - -int gpio_name(gpio_t *gpio, char *str, size_t len) { - return gpio->ops->name(gpio, str, len); -} - -int gpio_label(gpio_t *gpio, char *str, size_t len) { - return gpio->ops->label(gpio, str, len); -} - -int gpio_chip_fd(gpio_t *gpio) { - return gpio->ops->chip_fd(gpio); -} - -int gpio_chip_name(gpio_t *gpio, char *str, size_t len) { - return gpio->ops->chip_name(gpio, str, len); -} - -int gpio_chip_label(gpio_t *gpio, char *str, size_t len) { - return gpio->ops->chip_label(gpio, str, len); -} - -int gpio_tostring(gpio_t *gpio, char *str, size_t len) { - return gpio->ops->tostring(gpio, str, len); -} - -/*********************************************************************************/ -/* Common error formatting function */ -/*********************************************************************************/ - -static int _gpio_error(gpio_t *gpio, int code, int c_errno, const char *fmt, ...) { - va_list ap; - - gpio->error.c_errno = c_errno; - - va_start(ap, fmt); - vsnprintf(gpio->error.errmsg, sizeof(gpio->error.errmsg), fmt, ap); - va_end(ap); - - /* Tack on strerror() and errno */ - if (c_errno) { - char buf[64]; - strerror_r(c_errno, buf, sizeof(buf)); - snprintf(gpio->error.errmsg+strlen(gpio->error.errmsg), sizeof(gpio->error.errmsg)-strlen(gpio->error.errmsg), ": %s [errno %d]", buf, c_errno); - } - - return code; -} - -/*********************************************************************************/ -/* GPIO Poll Multiple Implementation */ -/*********************************************************************************/ - -int gpio_poll_multiple(gpio_t **gpios, size_t count, int timeout_ms, bool *gpios_ready) { - struct pollfd fds[count]; - int ret; - - /* Setup pollfd structs */ - for (size_t i = 0; i < count; i++) { - fds[i].fd = gpio_fd(gpios[i]); - fds[i].events = (gpios[i]->ops == &gpio_sysfs_ops) ? - (POLLPRI | POLLERR) : (POLLIN | POLLRDNORM); - if (gpios_ready) - gpios_ready[i] = false; - } - - /* Poll */ - if ((ret = poll(fds, count, timeout_ms)) < 0) - return GPIO_ERROR_IO; - - /* Event occurred */ - if (ret) { - for (size_t i = 0; i < count; i++) { - /* Set ready GPIOs */ - if (gpios_ready) - gpios_ready[i] = fds[i].revents != 0; - - /* Rewind GPIO if it is a sysfs GPIO */ - if (gpios[i]->ops == &gpio_sysfs_ops) { - if (lseek(gpios[i]->u.sysfs.line_fd, 0, SEEK_SET) < 0) - return GPIO_ERROR_IO; - } - } - - return ret; - } - - /* Timed out */ - return 0; -} - -/*********************************************************************************/ -/* sysfs implementation */ -/*********************************************************************************/ - -#define P_PATH_MAX 256 - -/* 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 - -static int gpio_sysfs_close(gpio_t *gpio) { - char buf[16]; - int len, fd; - - if (gpio->u.sysfs.line_fd < 0) - return 0; - - /* Close fd */ - if (close(gpio->u.sysfs.line_fd) < 0) - return _gpio_error(gpio, GPIO_ERROR_CLOSE, errno, "Closing GPIO 'value'"); - - gpio->u.sysfs.line_fd = -1; - - /* Unexport the GPIO, if we exported it */ - if (gpio->u.sysfs.exported) { - len = snprintf(buf, sizeof(buf), "%u\n", gpio->u.sysfs.line); - - if ((fd = open("/sys/class/gpio/unexport", O_WRONLY)) < 0) - return _gpio_error(gpio, GPIO_ERROR_CLOSE, errno, "Closing GPIO: opening 'unexport'"); - - if (write(fd, buf, len) < 0) { - int errsv = errno; - close(fd); - return _gpio_error(gpio, GPIO_ERROR_CLOSE, errsv, "Closing GPIO: writing 'unexport'"); - } - - if (close(fd) < 0) - return _gpio_error(gpio, GPIO_ERROR_CLOSE, errno, "Closing GPIO: closing 'unexport'"); - - gpio->u.sysfs.exported = false; - } - - return 0; -} - -static int gpio_sysfs_read(gpio_t *gpio, bool *value) { - char buf[2]; - - /* Read fd */ - if (read(gpio->u.sysfs.line_fd, buf, 2) < 0) - return _gpio_error(gpio, GPIO_ERROR_IO, errno, "Reading GPIO 'value'"); - - /* Rewind */ - if (lseek(gpio->u.sysfs.line_fd, 0, SEEK_SET) < 0) - return _gpio_error(gpio, GPIO_ERROR_IO, errno, "Rewinding GPIO 'value'"); - - if (buf[0] == '0') - *value = false; - else if (buf[0] == '1') - *value = true; - else - return _gpio_error(gpio, GPIO_ERROR_IO, 0, "Unknown GPIO value"); - - return 0; -} - -static int gpio_sysfs_write(gpio_t *gpio, bool value) { - static const char *value_str[2] = {"0\n", "1\n"}; - - /* Write fd */ - if (write(gpio->u.sysfs.line_fd, value_str[value], 2) < 0) - return _gpio_error(gpio, GPIO_ERROR_IO, errno, "Writing GPIO 'value'"); - - /* Rewind */ - if (lseek(gpio->u.sysfs.line_fd, 0, SEEK_SET) < 0) - return _gpio_error(gpio, GPIO_ERROR_IO, errno, "Rewinding GPIO 'value'"); - - return 0; -} - -static int gpio_sysfs_read_event(gpio_t *gpio, gpio_edge_t *edge, uint64_t *timestamp) { - (void)edge; - (void)timestamp; - return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs does not support read event"); -} - -static int gpio_sysfs_poll(gpio_t *gpio, int timeout_ms) { - struct pollfd fds[1]; - int ret; - - /* Poll */ - fds[0].fd = gpio->u.sysfs.line_fd; - fds[0].events = POLLPRI | POLLERR; - if ((ret = poll(fds, 1, timeout_ms)) < 0) - return _gpio_error(gpio, GPIO_ERROR_IO, errno, "Polling GPIO 'value'"); - - /* GPIO edge interrupt occurred */ - if (ret) { - /* Rewind */ - if (lseek(gpio->u.sysfs.line_fd, 0, SEEK_SET) < 0) - return _gpio_error(gpio, GPIO_ERROR_IO, errno, "Rewinding GPIO 'value'"); - - return 1; - } - - /* Timed out */ - return 0; -} - -static int gpio_sysfs_set_direction(gpio_t *gpio, gpio_direction_t direction) { - char gpio_path[P_PATH_MAX]; - const char *buf; - int fd; - - if (direction == GPIO_DIR_IN) - buf = "in\n"; - else if (direction == GPIO_DIR_OUT) - buf = "out\n"; - else if (direction == GPIO_DIR_OUT_LOW) - buf = "low\n"; - else if (direction == GPIO_DIR_OUT_HIGH) - buf = "high\n"; - else - return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO direction (can be in, out, low, high)"); - - /* Write direction */ - snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%u/direction", gpio->u.sysfs.line); - - if ((fd = open(gpio_path, O_WRONLY)) < 0) - return _gpio_error(gpio, GPIO_ERROR_CONFIGURE, errno, "Opening GPIO 'direction'"); - - if (write(fd, buf, strlen(buf)) < 0) { - int errsv = errno; - close(fd); - return _gpio_error(gpio, GPIO_ERROR_CONFIGURE, errsv, "Writing GPIO 'direction'"); - } - - if (close(fd) < 0) - return _gpio_error(gpio, GPIO_ERROR_CONFIGURE, errno, "Closing GPIO 'direction'"); - - return 0; -} - -static int gpio_sysfs_get_direction(gpio_t *gpio, gpio_direction_t *direction) { - char gpio_path[P_PATH_MAX]; - char buf[8]; - int fd, ret; - - /* Read direction */ - snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%u/direction", gpio->u.sysfs.line); - - if ((fd = open(gpio_path, O_RDONLY)) < 0) - return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Opening GPIO 'direction'"); - - if ((ret = read(fd, buf, sizeof(buf))) < 0) { - int errsv = errno; - close(fd); - return _gpio_error(gpio, GPIO_ERROR_QUERY, errsv, "Reading GPIO 'direction'"); - } - - if (close(fd) < 0) - return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Closing GPIO 'direction'"); - - buf[ret] = '\0'; - - if (strcmp(buf, "in\n") == 0) - *direction = GPIO_DIR_IN; - else if (strcmp(buf, "out\n") == 0) - *direction = GPIO_DIR_OUT; - else - return _gpio_error(gpio, GPIO_ERROR_QUERY, 0, "Unknown GPIO direction"); - - return 0; -} - -static int gpio_sysfs_set_edge(gpio_t *gpio, gpio_edge_t edge) { - char gpio_path[P_PATH_MAX]; - const char *buf; - int fd; - - if (edge == GPIO_EDGE_NONE) - buf = "none\n"; - else if (edge == GPIO_EDGE_RISING) - buf = "rising\n"; - else if (edge == GPIO_EDGE_FALLING) - buf = "falling\n"; - else if (edge == GPIO_EDGE_BOTH) - buf = "both\n"; - else - return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO interrupt edge (can be none, rising, falling, both)"); - - /* Write edge */ - snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%u/edge", gpio->u.sysfs.line); - - if ((fd = open(gpio_path, O_WRONLY)) < 0) - return _gpio_error(gpio, GPIO_ERROR_CONFIGURE, errno, "Opening GPIO 'edge'"); - - if (write(fd, buf, strlen(buf)) < 0) { - int errsv = errno; - close(fd); - return _gpio_error(gpio, GPIO_ERROR_CONFIGURE, errsv, "Writing GPIO 'edge'"); - } - - if (close(fd) < 0) - return _gpio_error(gpio, GPIO_ERROR_CONFIGURE, errno, "Closing GPIO 'edge'"); - - return 0; -} - -static int gpio_sysfs_get_edge(gpio_t *gpio, gpio_edge_t *edge) { - char gpio_path[P_PATH_MAX]; - char buf[16]; - int fd, ret; - - /* Read edge */ - snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%u/edge", gpio->u.sysfs.line); - - if ((fd = open(gpio_path, O_RDONLY)) < 0) - return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Opening GPIO 'edge'"); - - if ((ret = read(fd, buf, sizeof(buf))) < 0) { - int errsv = errno; - close(fd); - return _gpio_error(gpio, GPIO_ERROR_QUERY, errsv, "Reading GPIO 'edge'"); - } - - if (close(fd) < 0) - return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Closing GPIO 'edge'"); - - buf[ret] = '\0'; - - if (strcmp(buf, "none\n") == 0) - *edge = GPIO_EDGE_NONE; - else if (strcmp(buf, "rising\n") == 0) - *edge = GPIO_EDGE_RISING; - else if (strcmp(buf, "falling\n") == 0) - *edge = GPIO_EDGE_FALLING; - else if (strcmp(buf, "both\n") == 0) - *edge = GPIO_EDGE_BOTH; - else - return _gpio_error(gpio, GPIO_ERROR_QUERY, 0, "Unknown GPIO edge"); - - return 0; -} - -static int gpio_sysfs_set_bias(gpio_t *gpio, gpio_bias_t bias) { - (void)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) { - (void)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) { - (void)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) { - (void)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; -} - -static int gpio_sysfs_fd(gpio_t *gpio) { - return gpio->u.sysfs.line_fd; -} - -static int gpio_sysfs_name(gpio_t *gpio, char *str, size_t len) { - (void)gpio; - if (len) - str[0] = '\0'; - - return 0; -} - -static int gpio_sysfs_label(gpio_t *gpio, char *str, size_t len) { - (void)gpio; - if (len) - str[0] = '\0'; - - return 0; -} - -static int gpio_sysfs_chip_fd(gpio_t *gpio) { - return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "GPIO of type sysfs has no chip fd"); -} - -static int gpio_sysfs_chip_name(gpio_t *gpio, char *str, size_t len) { - int ret; - char gpio_path[P_PATH_MAX]; - char gpiochip_path[P_PATH_MAX]; - - if (!len) - return 0; - - /* Form path to device */ - snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%u/device", gpio->u.sysfs.line); - - /* Resolve symlink to gpiochip */ - if ((ret = readlink(gpio_path, gpiochip_path, sizeof(gpiochip_path))) < 0) - return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Reading GPIO chip symlink"); - - /* Null-terminate symlink path */ - gpiochip_path[(ret < P_PATH_MAX) ? ret : (P_PATH_MAX - 1)] = '\0'; - - /* Find last / in symlink path */ - const char *sep = strrchr(gpiochip_path, '/'); - if (!sep) - return _gpio_error(gpio, GPIO_ERROR_QUERY, 0, "Invalid GPIO chip symlink"); - - strncpy(str, sep + 1, len - 1); - str[len - 1] = '\0'; - - return 0; -} - -static int gpio_sysfs_chip_label(gpio_t *gpio, char *str, size_t len) { - char gpio_path[P_PATH_MAX]; - char chip_name[32]; - int fd, ret; - - if (!len) - return 0; - - if ((ret = gpio_sysfs_chip_name(gpio, chip_name, sizeof(chip_name))) < 0) - return ret; - - /* Read gpiochip label */ - snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/%s/label", chip_name); - - if ((fd = open(gpio_path, O_RDONLY)) < 0) - return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Opening GPIO chip 'label'"); - - if ((ret = read(fd, str, len)) < 0) { - int errsv = errno; - close(fd); - return _gpio_error(gpio, GPIO_ERROR_QUERY, errsv, "Reading GPIO chip 'label'"); - } - - if (close(fd) < 0) - return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Closing GPIO 'label'"); - - str[ret - 1] = '\0'; - - return 0; -} - -static int gpio_sysfs_tostring(gpio_t *gpio, char *str, size_t len) { - gpio_direction_t direction; - 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]; - const char *chip_label_str; - - if (gpio_sysfs_get_direction(gpio, &direction) < 0) - direction_str = ""; - else - direction_str = (direction == GPIO_DIR_IN) ? "in" : - (direction == GPIO_DIR_OUT) ? "out" : "unknown"; - - if (gpio_sysfs_get_edge(gpio, &edge) < 0) - edge_str = ""; - else - edge_str = (edge == GPIO_EDGE_NONE) ? "none" : - (edge == GPIO_EDGE_RISING) ? "rising" : - (edge == GPIO_EDGE_FALLING) ? "falling" : - (edge == GPIO_EDGE_BOTH) ? "both" : "unknown"; - - if (gpio_sysfs_get_inverted(gpio, &inverted) < 0) - inverted_str = ""; - else - inverted_str = inverted ? "true" : "false"; - - if (gpio_sysfs_chip_name(gpio, chip_name, sizeof(chip_name)) < 0) - chip_name_str = ""; - else - chip_name_str = chip_name; - - if (gpio_sysfs_chip_label(gpio, chip_label, sizeof(chip_label)) < 0) - chip_label_str = ""; - else - chip_label_str = chip_label; - - 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 = { - .read = gpio_sysfs_read, - .write = gpio_sysfs_write, - .read_event = gpio_sysfs_read_event, - .poll = gpio_sysfs_poll, - .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, - .label = gpio_sysfs_label, - .chip_fd = gpio_sysfs_chip_fd, - .chip_name = gpio_sysfs_chip_name, - .chip_label = gpio_sysfs_chip_label, - .tostring = gpio_sysfs_tostring, -}; - -int gpio_open_sysfs(gpio_t *gpio, unsigned int line, gpio_direction_t direction) { - char gpio_path[P_PATH_MAX]; - struct stat stat_buf; - char buf[16]; - int len, fd, ret; - bool exported = false; - - 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)"); - - /* Check if GPIO directory exists */ - snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%u", line); - if (stat(gpio_path, &stat_buf) < 0) { - /* Write line number to export file */ - len = snprintf(buf, sizeof(buf), "%u\n", line); - - if ((fd = open("/sys/class/gpio/export", O_WRONLY)) < 0) - return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening GPIO: opening 'export'"); - - if (write(fd, buf, len) < 0) { - int errsv = errno; - close(fd); - return _gpio_error(gpio, GPIO_ERROR_OPEN, errsv, "Opening GPIO: writing 'export'"); - } - - if (close(fd) < 0) - return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening GPIO: closing 'export'"); - - /* Wait until GPIO directory appears */ - 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) { - exported = true; - break; - } else if (ret < 0 && errno != ENOENT) { - return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening GPIO: stat 'gpio%u/' after export", line); - } - - usleep(GPIO_SYSFS_OPEN_DELAY); - } - - if (retry_count == GPIO_SYSFS_OPEN_RETRIES) - return _gpio_error(gpio, GPIO_ERROR_OPEN, 0, "Opening GPIO: waiting for 'gpio%u/' timed out", line); - - /* Write direction, looping in case of EACCES errors due to delayed - * udev permission rule application after export */ - const char *dir = (direction == GPIO_DIR_OUT) ? "out\n" : - (direction == GPIO_DIR_OUT_HIGH) ? "high\n" : - (direction == GPIO_DIR_OUT_LOW) ? "low\n" : "in\n"; - - snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%u/direction", line); - - for (retry_count = 0; retry_count < GPIO_SYSFS_OPEN_RETRIES; retry_count++) { - if ((fd = open(gpio_path, O_WRONLY)) >= 0) { - if (write(fd, dir, strlen(dir)) < 0) { - int errsv = errno; - close(fd); - return _gpio_error(gpio, GPIO_ERROR_CONFIGURE, errsv, "Writing GPIO 'direction'"); - } - - if (close(fd) < 0) - return _gpio_error(gpio, GPIO_ERROR_CONFIGURE, errno, "Closing GPIO 'direction'"); - - break; - } else if (errno != EACCES) { - return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening GPIO: opening 'gpio%u/direction'", line); - } - - usleep(GPIO_SYSFS_OPEN_DELAY); - } - - if (retry_count == GPIO_SYSFS_OPEN_RETRIES) - return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening GPIO: opening 'gpio%u/direction'", line); - } - - /* Open value */ - snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%u/value", line); - if ((fd = open(gpio_path, O_RDWR)) < 0) - return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening GPIO 'gpio%u/value'", line); - - memset(gpio, 0, sizeof(gpio_t)); - gpio->ops = &gpio_sysfs_ops; - gpio->u.sysfs.line = line; - gpio->u.sysfs.line_fd = fd; - gpio->u.sysfs.exported = exported; - - if (!exported) { - ret = gpio_sysfs_set_direction(gpio, direction); - if (ret < 0) - return ret; - } - - ret = gpio_sysfs_set_inverted(gpio, false); - if (ret < 0) - return ret; - - return 0; -} - -/*********************************************************************************/ -/* cdev implementation */ -/*********************************************************************************/ - -#if PERIPHERY_GPIO_CDEV_SUPPORT - -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) { - if (edge == GPIO_EDGE_NONE) { - struct gpiohandle_request request = {0}; - - request.lineoffsets[0] = gpio->u.cdev.line; - request.flags = flags | GPIOHANDLE_REQUEST_INPUT; - strncpy(request.consumer_label, gpio->u.cdev.label, sizeof(request.consumer_label) - 1); - request.consumer_label[sizeof(request.consumer_label) - 1] = '\0'; - 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; - } else { - struct gpioevent_request request = {0}; - - request.lineoffset = gpio->u.cdev.line; - 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->u.cdev.label, sizeof(request.consumer_label) - 1); - request.consumer_label[sizeof(request.consumer_label) - 1] = '\0'; - - 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; - } - } 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 = flags | GPIOHANDLE_REQUEST_OUTPUT; - request.default_values[0] = initial_value; - strncpy(request.consumer_label, gpio->u.cdev.label, sizeof(request.consumer_label) - 1); - request.consumer_label[sizeof(request.consumer_label) - 1] = '\0'; - 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 = (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; -} - -static int gpio_cdev_read(gpio_t *gpio, bool *value) { - struct gpiohandle_data data = {0}; - - if (ioctl(gpio->u.cdev.line_fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data) < 0) - return _gpio_error(gpio, GPIO_ERROR_IO, errno, "Getting line value"); - - *value = data.values[0]; - - return 0; -} - -static int gpio_cdev_write(gpio_t *gpio, bool value) { - struct gpiohandle_data data = {0}; - - if (gpio->u.cdev.direction != GPIO_DIR_OUT) - return _gpio_error(gpio, GPIO_ERROR_INVALID_OPERATION, 0, "Invalid operation: cannot write to input GPIO"); - - data.values[0] = value; - - if (ioctl(gpio->u.cdev.line_fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data) < 0) - return _gpio_error(gpio, GPIO_ERROR_IO, errno, "Setting line value"); - - return 0; -} - -static int gpio_cdev_read_event(gpio_t *gpio, gpio_edge_t *edge, uint64_t *timestamp) { - struct gpioevent_data event_data = {0}; - - if (gpio->u.cdev.direction != GPIO_DIR_IN) - return _gpio_error(gpio, GPIO_ERROR_INVALID_OPERATION, 0, "Invalid operation: cannot read event of output GPIO"); - else if (gpio->u.cdev.edge == GPIO_EDGE_NONE) - return _gpio_error(gpio, GPIO_ERROR_INVALID_OPERATION, 0, "Invalid operation: GPIO edge not set"); - - if (read(gpio->u.cdev.line_fd, &event_data, sizeof(event_data)) < (ssize_t)sizeof(event_data)) - return _gpio_error(gpio, GPIO_ERROR_IO, errno, "Reading GPIO event"); - - if (edge) - *edge = (event_data.id == GPIOEVENT_EVENT_RISING_EDGE) ? GPIO_EDGE_RISING : - (event_data.id == GPIOEVENT_EVENT_FALLING_EDGE) ? GPIO_EDGE_FALLING : GPIO_EDGE_NONE; - if (timestamp) - *timestamp = event_data.timestamp; - - return 0; -} - -static int gpio_cdev_poll(gpio_t *gpio, int timeout_ms) { - struct pollfd fds[1]; - int ret; - - if (gpio->u.cdev.direction != GPIO_DIR_IN) - return _gpio_error(gpio, GPIO_ERROR_INVALID_OPERATION, 0, "Invalid operation: cannot poll output GPIO"); - - fds[0].fd = gpio->u.cdev.line_fd; - fds[0].events = POLLIN | POLLPRI | POLLERR; - if ((ret = poll(fds, 1, timeout_ms)) < 0) - return _gpio_error(gpio, GPIO_ERROR_IO, errno, "Polling GPIO line"); - - return ret > 0; -} - -static int gpio_cdev_close(gpio_t *gpio) { - /* Close line fd */ - 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; - } - - /* Close chip fd */ - if (gpio->u.cdev.chip_fd >= 0) { - if (close(gpio->u.cdev.chip_fd) < 0) - return _gpio_error(gpio, GPIO_ERROR_CLOSE, errno, "Closing GPIO chip"); - - gpio->u.cdev.chip_fd = -1; - } - - gpio->u.cdev.edge = GPIO_EDGE_NONE; - gpio->u.cdev.direction = GPIO_DIR_IN; - - return 0; -} - -static int gpio_cdev_get_direction(gpio_t *gpio, gpio_direction_t *direction) { - *direction = gpio->u.cdev.direction; - return 0; -} - -static int gpio_cdev_get_edge(gpio_t *gpio, gpio_edge_t *edge) { - *edge = gpio->u.cdev.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)"); - - if (gpio->u.cdev.direction == direction) - return 0; - - 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) { - if (edge != GPIO_EDGE_NONE && edge != GPIO_EDGE_RISING && edge != GPIO_EDGE_FALLING && edge != GPIO_EDGE_BOTH) - return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO interrupt edge (can be none, rising, falling, both)"); - - if (gpio->u.cdev.direction != GPIO_DIR_IN) - return _gpio_error(gpio, GPIO_ERROR_INVALID_OPERATION, 0, "Invalid operation: cannot set edge on output GPIO"); - - if (gpio->u.cdev.edge == edge) - return 0; - - 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) { - return gpio->u.cdev.line; -} - -static int gpio_cdev_fd(gpio_t *gpio) { - return gpio->u.cdev.line_fd; -} - -static int gpio_cdev_name(gpio_t *gpio, char *str, size_t len) { - struct gpioline_info line_info = {0}; - - if (!len) - return 0; - - line_info.line_offset = gpio->u.cdev.line; - - if (ioctl(gpio->u.cdev.chip_fd, GPIO_GET_LINEINFO_IOCTL, &line_info) < 0) - return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Querying GPIO line info for line %u", gpio->u.cdev.line); - - strncpy(str, line_info.name, len - 1); - str[len - 1] = '\0'; - - return 0; -} - -static int gpio_cdev_label(gpio_t *gpio, char *str, size_t len) { - struct gpioline_info line_info = {0}; - - if (!len) - return 0; - - line_info.line_offset = gpio->u.cdev.line; - - if (ioctl(gpio->u.cdev.chip_fd, GPIO_GET_LINEINFO_IOCTL, &line_info) < 0) - return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Querying GPIO line info for line %u", gpio->u.cdev.line); - - strncpy(str, line_info.consumer, len - 1); - str[len - 1] = '\0'; - - return 0; -} - -static int gpio_cdev_chip_fd(gpio_t *gpio) { - return gpio->u.cdev.chip_fd; -} - -static int gpio_cdev_chip_name(gpio_t *gpio, char *str, size_t len) { - struct gpiochip_info chip_info = {0}; - - if (!len) - return 0; - - if (ioctl(gpio->u.cdev.chip_fd, GPIO_GET_CHIPINFO_IOCTL, &chip_info) < 0) - return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Querying GPIO chip info"); - - strncpy(str, chip_info.name, len - 1); - str[len - 1] = '\0'; - - return 0; -} - -static int gpio_cdev_chip_label(gpio_t *gpio, char *str, size_t len) { - struct gpiochip_info chip_info = {0}; - - if (!len) - return 0; - - if (ioctl(gpio->u.cdev.chip_fd, GPIO_GET_CHIPINFO_IOCTL, &chip_info) < 0) - return _gpio_error(gpio, GPIO_ERROR_QUERY, errno, "Querying GPIO chip info"); - - strncpy(str, chip_info.label, len - 1); - str[len - 1] = '\0'; - - return 0; -} - -static int gpio_cdev_tostring(gpio_t *gpio, char *str, size_t len) { - gpio_direction_t direction; - 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]; - const char *line_label_str; - char chip_name[32]; - const char *chip_name_str; - char chip_label[32]; - const char *chip_label_str; - - if (gpio_cdev_get_direction(gpio, &direction) < 0) - direction_str = ""; - else - direction_str = (direction == GPIO_DIR_IN) ? "in" : - (direction == GPIO_DIR_OUT) ? "out" : "unknown"; - - if (gpio_cdev_get_edge(gpio, &edge) < 0) - edge_str = ""; - else - edge_str = (edge == GPIO_EDGE_NONE) ? "none" : - (edge == GPIO_EDGE_RISING) ? "rising" : - (edge == GPIO_EDGE_FALLING) ? "falling" : - (edge == GPIO_EDGE_BOTH) ? "both" : "unknown"; - - if (gpio_cdev_get_bias(gpio, &bias) < 0) - bias_str = ""; - 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 = ""; - 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 = ""; - else - inverted_str = inverted ? "true" : "false"; - - if (gpio_cdev_name(gpio, line_name, sizeof(line_name)) < 0) - line_name_str = ""; - else - line_name_str = line_name; - - if (gpio_cdev_label(gpio, line_label, sizeof(line_label)) < 0) - line_label_str = ""; - else - line_label_str = line_label; - - if (gpio_cdev_chip_name(gpio, chip_name, sizeof(chip_name)) < 0) - chip_name_str = ""; - else - chip_name_str = chip_name; - - if (gpio_cdev_chip_label(gpio, chip_label, sizeof(chip_label)) < 0) - chip_label_str = ""; - 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, 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 = { - .read = gpio_cdev_read, - .write = gpio_cdev_write, - .read_event = gpio_cdev_read_event, - .poll = gpio_cdev_poll, - .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, - .label = gpio_cdev_label, - .chip_fd = gpio_cdev_chip_fd, - .chip_name = gpio_cdev_chip_name, - .chip_label = gpio_cdev_chip_label, - .tostring = gpio_cdev_tostring, -}; - -int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const gpio_config_t *config) { - int ret, fd; - - if (config->direction != GPIO_DIR_IN && config->direction != GPIO_DIR_OUT && config->direction != GPIO_DIR_OUT_LOW && config->direction != GPIO_DIR_OUT_HIGH) - return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO direction (can be in, out, low, high)"); - - if (config->edge != GPIO_EDGE_NONE && config->edge != GPIO_EDGE_RISING && config->edge != GPIO_EDGE_FALLING && config->edge != GPIO_EDGE_BOTH) - return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO interrupt edge (can be none, rising, falling, both)"); - - if (config->direction != GPIO_DIR_IN && config->edge != GPIO_EDGE_NONE) - return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO edge for output GPIO"); - - if (config->bias != GPIO_BIAS_DEFAULT && config->bias != GPIO_BIAS_PULL_UP && config->bias != GPIO_BIAS_PULL_DOWN && config->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 (config->drive != GPIO_DRIVE_DEFAULT && config->drive != GPIO_DRIVE_OPEN_DRAIN && config->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 (config->direction == GPIO_DIR_IN && config->drive != GPIO_DRIVE_DEFAULT) - return _gpio_error(gpio, GPIO_ERROR_ARG, 0, "Invalid GPIO line drive for input GPIO"); - - /* Open GPIO chip */ - if ((fd = open(path, 0)) < 0) - return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening GPIO chip"); - - memset(gpio, 0, sizeof(gpio_t)); - gpio->ops = &gpio_cdev_ops; - gpio->u.cdev.line = line; - gpio->u.cdev.line_fd = -1; - gpio->u.cdev.chip_fd = fd; - strncpy(gpio->u.cdev.label, config->label ? config->label : "periphery", sizeof(gpio->u.cdev.label) - 1); - gpio->u.cdev.label[sizeof(gpio->u.cdev.label) - 1] = '\0'; - - /* Open GPIO line */ - ret = _gpio_cdev_reopen(gpio, config->direction, config->edge, config->bias, config->drive, config->inverted); - if (ret < 0) { - close(gpio->u.cdev.chip_fd); - gpio->u.cdev.chip_fd = -1; - return ret; - } - - return 0; -} - -int gpio_open_name_advanced(gpio_t *gpio, const char *path, const char *name, const gpio_config_t *config) { - int fd; - - /* Open GPIO chip */ - if ((fd = open(path, 0)) < 0) - return _gpio_error(gpio, GPIO_ERROR_OPEN, errno, "Opening GPIO chip"); - - /* Get chip info for number of lines */ - struct gpiochip_info chip_info = {0}; - if (ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip_info) < 0) { - int errsv = errno; - close(fd); - return _gpio_error(gpio, GPIO_ERROR_QUERY, errsv, "Querying GPIO chip info"); - } - - /* Loop through every line */ - struct gpioline_info line_info = {0}; - unsigned int line; - for (line = 0; line < chip_info.lines; line++) { - line_info.line_offset = line; - - /* Get the line info */ - if (ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &line_info) < 0) { - int errsv = errno; - close(fd); - return _gpio_error(gpio, GPIO_ERROR_QUERY, errsv, "Querying GPIO line info for line %u", line); - } - - /* Compare the name */ - if (strcmp(line_info.name, name) == 0) - break; - } - - /* If no matching line name was found */ - if (line == chip_info.lines) { - close(fd); - return _gpio_error(gpio, GPIO_ERROR_NOT_FOUND, 0, "GPIO line \"%s\" not found by name", name); - } - - if (close(fd) < 0) - return _gpio_error(gpio, GPIO_ERROR_CLOSE, errno, "Closing GPIO chip"); - - return gpio_open_advanced(gpio, path, line, config); -} - -int gpio_open(gpio_t *gpio, const char *path, unsigned int line, gpio_direction_t direction) { - gpio_config_t config = { - .direction = direction, - .edge = GPIO_EDGE_NONE, - .bias = GPIO_BIAS_DEFAULT, - .drive = GPIO_DRIVE_DEFAULT, - .inverted = false, - .label = NULL, - }; - - return gpio_open_advanced(gpio, path, line, &config); -} - -int gpio_open_name(gpio_t *gpio, const char *path, const char *name, gpio_direction_t direction) { - gpio_config_t config = { - .direction = direction, - .edge = GPIO_EDGE_NONE, - .bias = GPIO_BIAS_DEFAULT, - .drive = GPIO_DRIVE_DEFAULT, - .inverted = false, - .label = NULL, - }; - - return gpio_open_name_advanced(gpio, path, name, &config); -} - -#else /* PERIPHERY_GPIO_CDEV_SUPPORT */ - -int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const gpio_config_t *config) { - (void)path; - (void)line; - (void)config; - return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "c-periphery library built without character device GPIO support."); -} - -int gpio_open_name_advanced(gpio_t *gpio, const char *path, const char *name, const gpio_config_t *config) { - (void)path; - (void)name; - (void)config; - return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "c-periphery library built without character device GPIO support."); -} - -int gpio_open(gpio_t *gpio, const char *path, unsigned int line, gpio_direction_t direction) { - (void)path; - (void)line; - (void)direction; - return _gpio_error(gpio, GPIO_ERROR_UNSUPPORTED, 0, "c-periphery library built without character device GPIO support."); -} - -#endif diff --git a/sys/arm-linux/drivers/gpio.h b/sys/arm-linux/drivers/gpio.h deleted file mode 100644 index e18e7e52..00000000 --- a/sys/arm-linux/drivers/gpio.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * c-periphery - * https://github.com/vsergeev/c-periphery - * License: MIT - */ - -#ifndef _PERIPHERY_GPIO_H -#define _PERIPHERY_GPIO_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -enum gpio_error_code { - GPIO_ERROR_ARG = -1, /* Invalid arguments */ - GPIO_ERROR_OPEN = -2, /* Opening GPIO */ - GPIO_ERROR_NOT_FOUND = -3, /* Line name not found */ - GPIO_ERROR_QUERY = -4, /* Querying GPIO attributes */ - GPIO_ERROR_CONFIGURE = -5, /* Configuring GPIO attributes */ - GPIO_ERROR_UNSUPPORTED = -6, /* Unsupported attribute or operation */ - GPIO_ERROR_INVALID_OPERATION = -7, /* Invalid operation */ - GPIO_ERROR_IO = -8, /* Reading/writing GPIO */ - GPIO_ERROR_CLOSE = -9, /* Closing GPIO */ -}; - -typedef enum gpio_direction { - GPIO_DIR_IN, /* Input */ - GPIO_DIR_OUT, /* Output, initialized to low */ - GPIO_DIR_OUT_LOW, /* Output, initialized to low */ - GPIO_DIR_OUT_HIGH, /* Output, initialized to high */ -} gpio_direction_t; - -typedef enum gpio_edge { - GPIO_EDGE_NONE, /* No interrupt edge */ - GPIO_EDGE_RISING, /* Rising edge 0 -> 1 */ - GPIO_EDGE_FALLING, /* Falling edge 1 -> 0 */ - 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; - -/* Configuration structure for gpio_open_*advanced() functions */ -typedef struct gpio_config { - gpio_direction_t direction; - gpio_edge_t edge; - gpio_bias_t bias; - gpio_drive_t drive; - bool inverted; - const char *label; /* Can be NULL for default consumer label */ -} gpio_config_t; - -typedef struct gpio_handle gpio_t; - -/* Primary Functions */ -gpio_t *gpio_new(void); -int gpio_open(gpio_t *gpio, const char *path, unsigned int line, gpio_direction_t direction); -int gpio_open_name(gpio_t *gpio, const char *path, const char *name, gpio_direction_t direction); -int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const gpio_config_t *config); -int gpio_open_name_advanced(gpio_t *gpio, const char *path, const char *name, const gpio_config_t *config); -int gpio_open_sysfs(gpio_t *gpio, unsigned int line, gpio_direction_t direction); -int gpio_read(gpio_t *gpio, bool *value); -int gpio_write(gpio_t *gpio, bool value); -int gpio_poll(gpio_t *gpio, int timeout_ms); -int gpio_close(gpio_t *gpio); -void gpio_free(gpio_t *gpio); - -/* Read Event (for character device GPIOs) */ -int gpio_read_event(gpio_t *gpio, gpio_edge_t *edge, uint64_t *timestamp); - -/* Poll Multiple */ -int gpio_poll_multiple(gpio_t **gpios, size_t count, int timeout_ms, bool *gpios_ready); - -/* 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 bias); -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); -int gpio_fd(gpio_t *gpio); -int gpio_name(gpio_t *gpio, char *str, size_t len); -int gpio_label(gpio_t *gpio, char *str, size_t len); -int gpio_chip_fd(gpio_t *gpio); -int gpio_chip_name(gpio_t *gpio, char *str, size_t len); -int gpio_chip_label(gpio_t *gpio, char *str, size_t len); -int gpio_tostring(gpio_t *gpio, char *str, size_t len); - -/* Error Handling */ -int gpio_errno(gpio_t *gpio); -const char *gpio_errmsg(gpio_t *gpio); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/sys/arm-linux/drivers/i2c.c b/sys/arm-linux/drivers/i2c.c deleted file mode 100644 index 53929715..00000000 --- a/sys/arm-linux/drivers/i2c.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * c-periphery - * https://github.com/vsergeev/c-periphery - * License: MIT - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "i2c.h" - -struct i2c_handle { - int fd; - - struct { - int c_errno; - char errmsg[96]; - } error; -}; - -static int _i2c_error(i2c_t *i2c, int code, int c_errno, const char *fmt, ...) { - va_list ap; - - i2c->error.c_errno = c_errno; - - va_start(ap, fmt); - vsnprintf(i2c->error.errmsg, sizeof(i2c->error.errmsg), fmt, ap); - va_end(ap); - - /* Tack on strerror() and errno */ - if (c_errno) { - char buf[64]; - strerror_r(c_errno, buf, sizeof(buf)); - snprintf(i2c->error.errmsg+strlen(i2c->error.errmsg), sizeof(i2c->error.errmsg)-strlen(i2c->error.errmsg), ": %s [errno %d]", buf, c_errno); - } - - return code; -} - -i2c_t *i2c_new(void) { - i2c_t *i2c = calloc(1, sizeof(i2c_t)); - if (i2c == NULL) - return NULL; - - i2c->fd = -1; - - return i2c; -} - -void i2c_free(i2c_t *i2c) { - free(i2c); -} - -int i2c_open(i2c_t *i2c, const char *path) { - unsigned long supported_funcs; - - memset(i2c, 0, sizeof(i2c_t)); - - /* Open device */ - if ((i2c->fd = open(path, O_RDWR)) < 0) - return _i2c_error(i2c, I2C_ERROR_OPEN, errno, "Opening I2C device \"%s\"", path); - - /* Query supported functions */ - if (ioctl(i2c->fd, I2C_FUNCS, &supported_funcs) < 0) { - int errsv = errno; - close(i2c->fd); - i2c->fd = -1; - return _i2c_error(i2c, I2C_ERROR_QUERY, errsv, "Querying I2C functions"); - } - - if (!(supported_funcs & I2C_FUNC_I2C)) { - close(i2c->fd); - i2c->fd = -1; - return _i2c_error(i2c, I2C_ERROR_NOT_SUPPORTED, 0, "I2C not supported on %s", path); - } - - return 0; -} - -int i2c_transfer(i2c_t *i2c, struct i2c_msg *msgs, size_t count) { - struct i2c_rdwr_ioctl_data i2c_rdwr_data; - - /* Prepare I2C transfer structure */ - memset(&i2c_rdwr_data, 0, sizeof(struct i2c_rdwr_ioctl_data)); - i2c_rdwr_data.msgs = msgs; - i2c_rdwr_data.nmsgs = count; - - /* Transfer */ - if (ioctl(i2c->fd, I2C_RDWR, &i2c_rdwr_data) < 0) - return _i2c_error(i2c, I2C_ERROR_TRANSFER, errno, "I2C transfer"); - - return 0; -} - -int i2c_close(i2c_t *i2c) { - if (i2c->fd < 0) - return 0; - - /* Close fd */ - if (close(i2c->fd) < 0) - return _i2c_error(i2c, I2C_ERROR_CLOSE, errno, "Closing I2C device"); - - i2c->fd = -1; - - return 0; -} - -int i2c_tostring(i2c_t *i2c, char *str, size_t len) { - return snprintf(str, len, "I2C (fd=%d)", i2c->fd); -} - -const char *i2c_errmsg(i2c_t *i2c) { - return i2c->error.errmsg; -} - -int i2c_errno(i2c_t *i2c) { - return i2c->error.c_errno; -} - -int i2c_fd(i2c_t *i2c) { - return i2c->fd; -} - diff --git a/sys/arm-linux/drivers/i2c.h b/sys/arm-linux/drivers/i2c.h deleted file mode 100644 index 7383f5ea..00000000 --- a/sys/arm-linux/drivers/i2c.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * c-periphery - * https://github.com/vsergeev/c-periphery - * License: MIT - */ - -#ifndef _PERIPHERY_I2C_H -#define _PERIPHERY_I2C_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -#include -#include - -enum i2c_error_code { - I2C_ERROR_ARG = -1, /* Invalid arguments */ - I2C_ERROR_OPEN = -2, /* Opening I2C device */ - I2C_ERROR_QUERY = -3, /* Querying I2C device attributes */ - I2C_ERROR_NOT_SUPPORTED = -4, /* I2C not supported on this device */ - I2C_ERROR_TRANSFER = -5, /* I2C transfer */ - I2C_ERROR_CLOSE = -6, /* Closing I2C device */ -}; - -typedef struct i2c_handle i2c_t; - -/* Primary Functions */ -i2c_t *i2c_new(void); -int i2c_open(i2c_t *i2c, const char *path); -int i2c_transfer(i2c_t *i2c, struct i2c_msg *msgs, size_t count); -int i2c_close(i2c_t *i2c); -void i2c_free(i2c_t *i2c); - -/* Miscellaneous */ -int i2c_fd(i2c_t *i2c); -int i2c_tostring(i2c_t *i2c, char *str, size_t len); - -/* Error Handling */ -int i2c_errno(i2c_t *i2c); -const char *i2c_errmsg(i2c_t *i2c); - -/* struct i2c_msg from : - - struct i2c_msg { - __u16 addr; - __u16 flags; - #define I2C_M_TEN 0x0010 - #define I2C_M_RD 0x0001 - #define I2C_M_STOP 0x8000 - #define I2C_M_NOSTART 0x4000 - #define I2C_M_REV_DIR_ADDR 0x2000 - #define I2C_M_IGNORE_NAK 0x1000 - #define I2C_M_NO_RD_ACK 0x0800 - #define I2C_M_RECV_LEN 0x0400 - __u16 len; - __u8 *buf; - }; -*/ - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/sys/arm-linux/drivers/spi.c b/sys/arm-linux/drivers/spi.c deleted file mode 100644 index d71937eb..00000000 --- a/sys/arm-linux/drivers/spi.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * c-periphery - * https://github.com/vsergeev/c-periphery - * License: MIT - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "spi.h" - -struct spi_handle { - int fd; - - struct { - int c_errno; - char errmsg[96]; - } error; -}; - -static int _spi_error(spi_t *spi, int code, int c_errno, const char *fmt, ...) { - va_list ap; - - spi->error.c_errno = c_errno; - - va_start(ap, fmt); - vsnprintf(spi->error.errmsg, sizeof(spi->error.errmsg), fmt, ap); - va_end(ap); - - /* Tack on strerror() and errno */ - if (c_errno) { - char buf[64]; - strerror_r(c_errno, buf, sizeof(buf)); - snprintf(spi->error.errmsg+strlen(spi->error.errmsg), sizeof(spi->error.errmsg)-strlen(spi->error.errmsg), ": %s [errno %d]", buf, c_errno); - } - - return code; -} - -spi_t *spi_new(void) { - spi_t *spi = calloc(1, sizeof(spi_t)); - if (spi == NULL) - return NULL; - - spi->fd = -1; - - return spi; -} - -void spi_free(spi_t *spi) { - free(spi); -} - -int spi_open(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed) { - return spi_open_advanced(spi, path, mode, max_speed, MSB_FIRST, 8, 0); -} - -int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint8_t extra_flags) { - return spi_open_advanced2(spi, path, mode, max_speed, bit_order, bits_per_word, extra_flags); -} - -int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint32_t extra_flags) { - uint32_t data32; - uint8_t data8; - - /* Validate arguments */ - if (mode & ~0x3) - return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid mode (can be 0,1,2,3)"); - if (bit_order != MSB_FIRST && bit_order != LSB_FIRST) - return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid bit order (can be MSB_FIRST,LSB_FIRST)"); -#ifndef SPI_IOC_WR_MODE32 - if (extra_flags > 0xff) - return _spi_error(spi, SPI_ERROR_UNSUPPORTED, 0, "Kernel version does not support 32-bit SPI mode flags"); -#endif - - memset(spi, 0, sizeof(spi_t)); - - /* Open device */ - if ((spi->fd = open(path, O_RDWR)) < 0) - return _spi_error(spi, SPI_ERROR_OPEN, errno, "Opening SPI device \"%s\"", path); - - /* Set mode, bit order, extra flags */ -#ifndef SPI_IOC_WR_MODE32 - (void)data32; - - data8 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags; - if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0) { - int errsv = errno; - close(spi->fd); - spi->fd = -1; - return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode"); - } -#else - if (extra_flags > 0xff) { - /* Use 32-bit mode if extra_flags is wider than 8-bits */ - data32 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags; - if (ioctl(spi->fd, SPI_IOC_WR_MODE32, &data32) < 0) { - int errsv = errno; - close(spi->fd); - spi->fd = -1; - return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode"); - } - } else { - /* Prefer 8-bit mode, in case this library is inadvertently used on an - * older kernel. */ - data8 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags; - if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0) { - int errsv = errno; - close(spi->fd); - spi->fd = -1; - return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode"); - } - } -#endif - - /* Set max speed */ - if (ioctl(spi->fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed) < 0) { - int errsv = errno; - close(spi->fd); - spi->fd = -1; - return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI max speed"); - } - - /* Set bits per word */ - if (ioctl(spi->fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < 0) { - int errsv = errno; - close(spi->fd); - spi->fd = -1; - return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI bits per word"); - } - - return 0; -} - -int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len) { - struct spi_ioc_transfer spi_xfer; - - /* Prepare SPI transfer structure */ - memset(&spi_xfer, 0, sizeof(struct spi_ioc_transfer)); - spi_xfer.tx_buf = (uintptr_t)txbuf; - spi_xfer.rx_buf = (uintptr_t)rxbuf; - spi_xfer.len = len; - spi_xfer.delay_usecs = 0; - spi_xfer.speed_hz = 0; - spi_xfer.bits_per_word = 0; - spi_xfer.cs_change = 0; - - /* Transfer */ - if (ioctl(spi->fd, SPI_IOC_MESSAGE(1), &spi_xfer) < 1) - return _spi_error(spi, SPI_ERROR_TRANSFER, errno, "SPI transfer"); - - return 0; -} - -int spi_close(spi_t *spi) { - if (spi->fd < 0) - return 0; - - /* Close fd */ - if (close(spi->fd) < 0) - return _spi_error(spi, SPI_ERROR_CLOSE, errno, "Closing SPI device"); - - spi->fd = -1; - - return 0; -} - -int spi_get_mode(spi_t *spi, unsigned int *mode) { - uint8_t data8; - - if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0) - return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode"); - - *mode = data8 & (SPI_CPHA | SPI_CPOL); - - return 0; -} - -int spi_get_max_speed(spi_t *spi, uint32_t *max_speed) { - uint32_t data32; - - if (ioctl(spi->fd, SPI_IOC_RD_MAX_SPEED_HZ, &data32) < 0) - return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI max speed"); - - *max_speed = data32; - - return 0; -} - -int spi_get_bit_order(spi_t *spi, spi_bit_order_t *bit_order) { - uint8_t data8; - - if (ioctl(spi->fd, SPI_IOC_RD_LSB_FIRST, &data8) < 0) - return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI bit order"); - - if (data8) - *bit_order = LSB_FIRST; - else - *bit_order = MSB_FIRST; - - return 0; -} - -int spi_get_bits_per_word(spi_t *spi, uint8_t *bits_per_word) { - uint8_t data8; - - if (ioctl(spi->fd, SPI_IOC_RD_BITS_PER_WORD, &data8) < 0) - return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI bits per word"); - - *bits_per_word = data8; - - return 0; -} - -int spi_get_extra_flags(spi_t *spi, uint8_t *extra_flags) { - uint8_t data8; - - if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0) - return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode flags"); - - /* Extra mode flags without mode 0-3 and bit order */ - *extra_flags = data8 & ~( SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST ); - - return 0; -} - -int spi_get_extra_flags32(spi_t *spi, uint32_t *extra_flags) { -#ifdef SPI_IOC_RD_MODE32 - uint32_t mode32; - - if (ioctl(spi->fd, SPI_IOC_RD_MODE32, &mode32) < 0) - return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting 32-bit SPI mode flags"); - - /* Extra mode flags without mode 0-3 and bit order */ - *extra_flags = mode32 & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST); - - return 0; -#else - (void)extra_flags; - - return _spi_error(spi, SPI_ERROR_UNSUPPORTED, 0, "Kernel version does not support 32-bit SPI mode flags"); -#endif -} - -int spi_set_mode(spi_t *spi, unsigned int mode) { - uint8_t data8; - - if (mode & ~0x3) - return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid mode (can be 0,1,2,3)"); - - if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0) - return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode"); - - data8 &= ~(SPI_CPOL | SPI_CPHA); - data8 |= mode; - - if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0) - return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI mode"); - - return 0; -} - -int spi_set_bit_order(spi_t *spi, spi_bit_order_t bit_order) { - uint8_t data8; - - if (bit_order != MSB_FIRST && bit_order != LSB_FIRST) - return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid bit order (can be MSB_FIRST,LSB_FIRST)"); - - if (bit_order == LSB_FIRST) - data8 = 1; - else - data8 = 0; - - if (ioctl(spi->fd, SPI_IOC_WR_LSB_FIRST, &data8) < 0) - return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI bit order"); - - return 0; -} - -int spi_set_extra_flags(spi_t *spi, uint8_t extra_flags) { - uint8_t data8; - - if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0) - return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode flags"); - - /* Keep mode 0-3 and bit order */ - data8 &= (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST); - /* Set extra flags */ - data8 |= extra_flags; - - if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0) - return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI mode flags"); - - return 0; -} - -int spi_set_extra_flags32(spi_t *spi, uint32_t extra_flags) { -#ifdef SPI_IOC_WR_MODE32 - uint32_t mode32; - - if (ioctl(spi->fd, SPI_IOC_RD_MODE32, &mode32) < 0) - return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting 32-bit SPI mode flags"); - - /* Keep mode 0-3 and bit order */ - mode32 &= (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST); - /* Set extra flags */ - mode32 |= extra_flags; - - if (ioctl(spi->fd, SPI_IOC_WR_MODE32, &mode32) < 0) - return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting 32-bit SPI mode flags"); - - return 0; -#else - (void)extra_flags; - - return _spi_error(spi, SPI_ERROR_UNSUPPORTED, 0, "Kernel version does not support 32-bit SPI mode flags"); -#endif -} - -int spi_set_max_speed(spi_t *spi, uint32_t max_speed) { - - if (ioctl(spi->fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed) < 0) - return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI max speed"); - - return 0; -} - -int spi_set_bits_per_word(spi_t *spi, uint8_t bits_per_word) { - - if (ioctl(spi->fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < 0) - return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI bits per word"); - - return 0; -} - -int spi_tostring(spi_t *spi, char *str, size_t len) { - unsigned int mode; - char mode_str[2]; - uint32_t max_speed; - char max_speed_str[16]; - uint8_t bits_per_word; - char bits_per_word_str[4]; - spi_bit_order_t bit_order; - const char *bit_order_str; - uint8_t extra_flags8; - uint32_t extra_flags32; - char extra_flags_str[11]; - - if (spi_get_mode(spi, &mode) < 0) - strcpy(mode_str, "?"); - else - snprintf(mode_str, sizeof(mode_str), "%u", mode); - - if (spi_get_max_speed(spi, &max_speed) < 0) - strcpy(max_speed_str, "?"); - else - snprintf(max_speed_str, sizeof(max_speed_str), "%u", max_speed); - - if (spi_get_bit_order(spi, &bit_order) < 0) - bit_order_str = "?"; - else - bit_order_str = (bit_order == LSB_FIRST) ? "LSB_FIRST" : "MSB_FIRST"; - - if (spi_get_bits_per_word(spi, &bits_per_word) < 0) - strcpy(bits_per_word_str, "?"); - else - snprintf(bits_per_word_str, sizeof(bits_per_word_str), "%u", bits_per_word); - - if (spi_get_extra_flags32(spi, &extra_flags32) < 0) { - if (spi_get_extra_flags(spi, &extra_flags8) < 0) - strcpy(extra_flags_str, "?"); - else - snprintf(extra_flags_str, sizeof(extra_flags_str), "0x%02x", extra_flags8); - } else { - snprintf(extra_flags_str, sizeof(extra_flags_str), "0x%08x", extra_flags32); - } - - return snprintf(str, len, "SPI (fd=%d, mode=%s, max_speed=%s, bit_order=%s, bits_per_word=%s, extra_flags=%s)", spi->fd, mode_str, max_speed_str, bit_order_str, bits_per_word_str, extra_flags_str); -} - -const char *spi_errmsg(spi_t *spi) { - return spi->error.errmsg; -} - -int spi_errno(spi_t *spi) { - return spi->error.c_errno; -} - -int spi_fd(spi_t *spi) { - return spi->fd; -} - diff --git a/sys/arm-linux/drivers/spi.h b/sys/arm-linux/drivers/spi.h deleted file mode 100644 index 5b761c2e..00000000 --- a/sys/arm-linux/drivers/spi.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * c-periphery - * https://github.com/vsergeev/c-periphery - * License: MIT - */ - -#ifndef _PERIPHERY_SPI_H -#define _PERIPHERY_SPI_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -enum spi_error_code { - SPI_ERROR_ARG = -1, /* Invalid arguments */ - SPI_ERROR_OPEN = -2, /* Opening SPI device */ - SPI_ERROR_QUERY = -3, /* Querying SPI device attributes */ - SPI_ERROR_CONFIGURE = -4, /* Configuring SPI device attributes */ - SPI_ERROR_TRANSFER = -5, /* SPI transfer */ - SPI_ERROR_CLOSE = -6, /* Closing SPI device */ - SPI_ERROR_UNSUPPORTED = -7, /* Unsupported attribute or operation */ -}; - -typedef enum spi_bit_order { - MSB_FIRST, - LSB_FIRST, -} spi_bit_order_t; - -typedef struct spi_handle spi_t; - -/* Primary Functions */ -spi_t *spi_new(void); -int spi_open(spi_t *spi, const char *path, unsigned int mode, - uint32_t max_speed); -int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, - uint32_t max_speed, spi_bit_order_t bit_order, - uint8_t bits_per_word, uint8_t extra_flags); -int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode, - uint32_t max_speed, spi_bit_order_t bit_order, - uint8_t bits_per_word, uint32_t extra_flags); -int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len); -int spi_close(spi_t *spi); -void spi_free(spi_t *spi); - -/* Getters */ -int spi_get_mode(spi_t *spi, unsigned int *mode); -int spi_get_max_speed(spi_t *spi, uint32_t *max_speed); -int spi_get_bit_order(spi_t *spi, spi_bit_order_t *bit_order); -int spi_get_bits_per_word(spi_t *spi, uint8_t *bits_per_word); -int spi_get_extra_flags(spi_t *spi, uint8_t *extra_flags); -int spi_get_extra_flags32(spi_t *spi, uint32_t *extra_flags); - -/* Setters */ -int spi_set_mode(spi_t *spi, unsigned int mode); -int spi_set_max_speed(spi_t *spi, uint32_t max_speed); -int spi_set_bit_order(spi_t *spi, spi_bit_order_t bit_order); -int spi_set_bits_per_word(spi_t *spi, uint8_t bits_per_word); -int spi_set_extra_flags(spi_t *spi, uint8_t extra_flags); -int spi_set_extra_flags32(spi_t *spi, uint32_t extra_flags); - -/* Miscellaneous */ -int spi_fd(spi_t *spi); -int spi_tostring(spi_t *spi, char *str, size_t len); - -/* Error Handling */ -int spi_errno(spi_t *spi); -const char *spi_errmsg(spi_t *spi); - -#ifdef __cplusplus -} -#endif - -#endif -