diff --git a/api/mraa/gpio.h b/api/mraa/gpio.h index 06b5d0e..95277ed 100644 --- a/api/mraa/gpio.h +++ b/api/mraa/gpio.h @@ -124,6 +124,14 @@ typedef mraa_gpio_event* mraa_gpio_events_t; */ mraa_gpio_context mraa_gpio_init(int pin); +/** + * Initialise gpio_context, based on gpio line name + * + * @param name GPIO line name, i.e GPIO-A + * @returns gpio context or NULL + */ +mraa_gpio_context mraa_gpio_init_by_name(char* name); + /** * Initialise gpio_context, based on board number, for multiple pins (can be one). * diff --git a/include/gpio/gpio_chardev.h b/include/gpio/gpio_chardev.h index ebcffb0..ccad15d 100644 --- a/include/gpio/gpio_chardev.h +++ b/include/gpio/gpio_chardev.h @@ -64,6 +64,7 @@ mraa_boolean_t mraa_is_gpio_line_open_drain(mraa_gpiod_line_info *linfo); mraa_boolean_t mraa_is_gpio_line_open_source(mraa_gpiod_line_info *linfo); int mraa_get_number_of_gpio_chips(); +int mraa_get_chip_infos(mraa_gpiod_chip_info*** cinfos); /* Multiple gpio support. */ typedef struct _gpio_group* mraa_gpiod_group_t; diff --git a/include/mraa_internal_types.h b/include/mraa_internal_types.h index beee8ad..4032221 100644 --- a/include/mraa_internal_types.h +++ b/include/mraa_internal_types.h @@ -174,6 +174,11 @@ struct _gpio { ++k) \ if (dev->gpio_group[k].is_required) +#define for_each_gpio_chip(cinfo, cinfos, num_chips) \ + for (int idx = 0; \ + idx < num_chips && (cinfo = cinfos[idx]); \ + (idx++)) + /** * A structure representing a I2C bus */ diff --git a/src/gpio/gpio.c b/src/gpio/gpio.c index a6862a3..6b44474 100644 --- a/src/gpio/gpio.c +++ b/src/gpio/gpio.c @@ -163,6 +163,122 @@ init_internal_cleanup: return dev; } +mraa_gpio_context +mraa_gpio_init_by_name(char* name) +{ + mraa_board_t* board = plat; + mraa_gpio_context dev; + mraa_gpiod_group_t gpio_group; + mraa_gpiod_line_info* linfo = NULL; + mraa_gpiod_chip_info* cinfo; + mraa_gpiod_chip_info** cinfos; + int i, line_found, line_offset; + + if (name == NULL) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: Gpio name not valid"); + return NULL; + } + + if (!board->chardev_capable) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: gpio_init_by_name not available for this platform!"); + return NULL; + } + + dev = (mraa_gpio_context) calloc(1, sizeof(struct _gpio)); + if (dev == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for context"); + return NULL; + } + + dev->pin_to_gpio_table = malloc(sizeof(int)); + if (dev->pin_to_gpio_table == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member"); + mraa_gpio_close(dev); + return NULL; + } + + dev->num_chips = mraa_get_chip_infos(&cinfos); + if (dev->num_chips <= 0) { + mraa_gpio_close(dev); + return NULL; + } + + /* We are dealing with a single GPIO */ + dev->num_pins = 1; + + gpio_group = calloc(dev->num_chips, sizeof(struct _gpio_group)); + if (gpio_group == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member"); + mraa_gpio_close(dev); + return NULL; + } + + dev->gpio_group = gpio_group; + for (i = 0; i < dev->num_chips; ++i) { + gpio_group[i].gpio_chip = i; + gpio_group[i].gpio_lines = NULL; + } + + /* Iterate over all gpiochips in the platform to find the requested line */ + for_each_gpio_chip(cinfo, cinfos, dev->num_chips) + { + for (i = 0; i < cinfo->chip_info.lines; i++) { + linfo = mraa_get_line_info_by_chip_name(cinfo->chip_info.name, i); + if (!strncmp(linfo->name, name, 32)) { + /* idx is coming from `for_each_gpio_chip` definition */ + syslog(LOG_DEBUG, "[GPIOD_INTERFACE]: Chip: %d Line: %d", idx, i); + if (!gpio_group[idx].is_required) { + gpio_group[idx].dev_fd = cinfo->chip_fd; + gpio_group[idx].is_required = 1; + gpio_group[idx].gpiod_handle = -1; + } + + /* Map pin to _gpio_group structure. */ + dev->pin_to_gpio_table[0] = idx; + gpio_group[idx].gpio_lines = realloc(gpio_group[idx].gpio_lines, sizeof(unsigned int)); + gpio_group[idx].gpio_lines[0] = i; + gpio_group[idx].num_gpio_lines++; + + line_found = 1; + line_offset = i; + + break; + } + } + } + + if (!line_found) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: Gpio not found!"); + return NULL; + } + + /* Initialize rw_values for read / write multiple functions */ + for (i = 0; i < dev->num_chips; ++i) { + gpio_group[i].rw_values = calloc(gpio_group[i].num_gpio_lines, sizeof(unsigned char)); + if (gpio_group[i].rw_values == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member"); + mraa_gpio_close(dev); + return NULL; + } + + gpio_group[i].event_handles = NULL; + } + + /* Save the provided array from the user to our internal structure. */ + dev->provided_pins = malloc(dev->num_pins * sizeof(int)); + if (dev->provided_pins == NULL) { + syslog(LOG_CRIT, "[GPIOD_INTERFACE]: Failed to allocate memory for internal member"); + mraa_gpio_close(dev); + return NULL; + } + + memcpy(dev->provided_pins, &line_offset, dev->num_pins * sizeof(int)); + + dev->events = NULL; + + return dev; +} + mraa_gpio_context mraa_gpio_init(int pin) { diff --git a/src/gpio/gpio_chardev.c b/src/gpio/gpio_chardev.c index f3893cb..003b24b 100644 --- a/src/gpio/gpio_chardev.c +++ b/src/gpio/gpio_chardev.c @@ -22,9 +22,9 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "gpio/gpio_chardev.h" #include "linux/gpio.h" #include "mraa_internal.h" -#include "gpio/gpio_chardev.h" #include #include @@ -52,7 +52,8 @@ _mraa_free_gpio_groups(mraa_gpio_context dev) { mraa_gpiod_group_t gpio_iter; - for_each_gpio_group(gpio_iter, dev) { + for_each_gpio_group(gpio_iter, dev) + { if (gpio_iter->gpio_lines) { free(gpio_iter->gpio_lines); } @@ -105,7 +106,8 @@ _mraa_close_gpio_event_handles(mraa_gpio_context dev) { mraa_gpiod_group_t gpio_iter; - for_each_gpio_group(gpio_iter, dev) { + for_each_gpio_group(gpio_iter, dev) + { if (gpio_iter->event_handles != NULL) { for (int j = 0; j < gpio_iter->num_gpio_lines; ++j) { close(gpio_iter->event_handles[j]); @@ -124,7 +126,8 @@ _mraa_close_gpio_desc(mraa_gpio_context dev) { mraa_gpiod_group_t gpio_iter; - for_each_gpio_group(gpio_iter, dev) { + for_each_gpio_group(gpio_iter, dev) + { if (gpio_iter->gpiod_handle != -1) { close(gpio_iter->gpiod_handle); gpio_iter->gpiod_handle = -1; @@ -376,56 +379,85 @@ mraa_get_line_values(int line_handle, unsigned int num_lines, unsigned char outp mraa_boolean_t -mraa_is_gpio_line_kernel_owned(mraa_gpiod_line_info *linfo) +mraa_is_gpio_line_kernel_owned(mraa_gpiod_line_info* linfo) { return (linfo->flags & GPIOLINE_FLAG_KERNEL); } mraa_boolean_t -mraa_is_gpio_line_dir_out(mraa_gpiod_line_info *linfo) +mraa_is_gpio_line_dir_out(mraa_gpiod_line_info* linfo) { return (linfo->flags & GPIOLINE_FLAG_IS_OUT); } mraa_boolean_t -mraa_is_gpio_line_active_low(mraa_gpiod_line_info *linfo) +mraa_is_gpio_line_active_low(mraa_gpiod_line_info* linfo) { return (linfo->flags & GPIOLINE_FLAG_ACTIVE_LOW); } mraa_boolean_t -mraa_is_gpio_line_open_drain(mraa_gpiod_line_info *linfo) +mraa_is_gpio_line_open_drain(mraa_gpiod_line_info* linfo) { return (linfo->flags & GPIOLINE_FLAG_OPEN_DRAIN); } mraa_boolean_t -mraa_is_gpio_line_open_source(mraa_gpiod_line_info *linfo) +mraa_is_gpio_line_open_source(mraa_gpiod_line_info* linfo) { return (linfo->flags & GPIOLINE_FLAG_OPEN_SOURCE); } +static int +dir_filter(const struct dirent* dir) +{ + return !strncmp(dir->d_name, CHIP_DEV_PREFIX, strlen(CHIP_DEV_PREFIX)); +} + int mraa_get_number_of_gpio_chips() { - int num_chips = 0; - DIR* dev_dir; - struct dirent* dir; - const unsigned int len = strlen(CHIP_DEV_PREFIX); + int num_chips; + struct dirent** dirs; - dev_dir = opendir(DEV_DIR); - if (dev_dir) { - while ((dir = readdir(dev_dir)) != NULL) { - if (!strncmp(dir->d_name, CHIP_DEV_PREFIX, len)) { - num_chips++; - } - } - closedir(dev_dir); - } else { - syslog(LOG_ERR, "[GPIOD_INTERFACE]: opendir() error"); + num_chips = scandir("/dev", &dirs, dir_filter, alphasort); + if (num_chips < 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: scandir() error"); return -1; } - /* Assume opendir() error. */ + return num_chips; +} + +int +mraa_get_chip_infos(mraa_gpiod_chip_info*** cinfos) +{ + int num_chips, i; + struct dirent** dirs; + mraa_gpiod_chip_info** cinfo; + + num_chips = scandir("/dev", &dirs, dir_filter, alphasort); + if (num_chips < 0) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: scandir() error"); + return -1; + } + + cinfo = (mraa_gpiod_chip_info**) calloc(num_chips, sizeof(mraa_gpiod_chip_info*)); + if (!cinfo) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: Failed to allocate memory for chip info"); + return -1; + } + + /* Get chip info for all gpiochips present in the platform */ + for (i = 0; i < num_chips; i++) { + cinfo[i] = mraa_get_chip_info_by_name(dirs[i]->d_name); + if (!cinfo[i]) { + syslog(LOG_ERR, "[GPIOD_INTERFACE]: invalid chip %s", dirs[i]->d_name); + return 0; + } + } + + *cinfos = cinfo; + return num_chips; }