From f7fc42917e72a263eae1e841f4f2af74dd729510 Mon Sep 17 00:00:00 2001 From: Bruno Meneguele Date: Tue, 14 Jun 2016 14:27:57 -0300 Subject: [PATCH] ADD gpio: support to generic gpio path names In some platforms using old Kernel versions uses different gpio class path names, like in all Allwinner SoC based boards before Kernel 4.0 device trees weren't used, and therefore gpio paths in sysfs were different from the actual standard. Libmraa doesn't supports this kind of paths because all gpio operations were done with hard coded path names following the gpios standard. With this commit it's possible to run libmraa either on newer kernel version and older ones, with any formats of gpio sysfs paths, anyone can specify an specific path standard. Also, the API to other languages was modified to support the new getPath() method which returns the current path being used. Signed-off-by: Bruno E. O. Meneguele --- api/mraa/gpio.h | 8 ++++++ api/mraa/gpio.hpp | 15 +++++++++++ include/mraa_internal_types.h | 1 + src/gpio/gpio.c | 50 +++++++++++++++++++++++++++-------- tests/gpio_checks.py | 2 +- 5 files changed, 64 insertions(+), 12 deletions(-) diff --git a/api/mraa/gpio.h b/api/mraa/gpio.h index 32e1c6e44..6d71449ec 100644 --- a/api/mraa/gpio.h +++ b/api/mraa/gpio.h @@ -220,6 +220,14 @@ int mraa_gpio_get_pin(mraa_gpio_context dev); */ int mraa_gpio_get_pin_raw(mraa_gpio_context dev); +/** + * Get the SYSFS pin path, invalid will return NULL + * + * @param dev The Gpio context + * @return Gpio pin sysfs path or return NULL if invalid + */ +char* mraa_gpio_get_path(mraa_gpio_context dev); + #ifdef __cplusplus } #endif diff --git a/api/mraa/gpio.hpp b/api/mraa/gpio.hpp index e2d7ad537..728f11169 100644 --- a/api/mraa/gpio.hpp +++ b/api/mraa/gpio.hpp @@ -315,6 +315,21 @@ class Gpio } return mraa_gpio_get_pin(m_gpio); } + /** + * Get pin SYSFS path. + * + * @throw std::runtime_error in case of failure + * @return Pin path string + */ + std::string + getPath() + { + char* path = mraa_gpio_get_path(m_gpio); + if (path == NULL) { + throw std::logic_error("Failed to get GPIO path"); + } + return path; + } private: mraa_gpio_context m_gpio; diff --git a/include/mraa_internal_types.h b/include/mraa_internal_types.h index 2873d4a9c..394bb820f 100644 --- a/include/mraa_internal_types.h +++ b/include/mraa_internal_types.h @@ -59,6 +59,7 @@ struct _gpio { int pin; /**< the pin number, as known to the os. */ int phy_pin; /**< pin passed to clean init. -1 none and raw*/ int value_fp; /**< the file pointer to the value of the gpio */ + char *gpio_path; /**< Custom file path format to help with compatibility */ void (* isr)(void *); /**< the interrupt service request */ void *isr_args; /**< args return when interrupt service request triggered */ pthread_t thread_id; /**< the isr handler thread id */ diff --git a/src/gpio/gpio.c b/src/gpio/gpio.c index 2623c26db..c74a7ea0a 100644 --- a/src/gpio/gpio.c +++ b/src/gpio/gpio.c @@ -44,7 +44,7 @@ static mraa_result_t mraa_gpio_get_valfp(mraa_gpio_context dev) { char bu[MAX_SIZE]; - sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin); + sprintf(bu, SYSFS_CLASS_GPIO "%s/value", dev->gpio_path); dev->value_fp = open(bu, O_RDWR); if (dev->value_fp == -1) { syslog(LOG_ERR, "gpio%i: Failed to open 'value': %s", dev->pin, strerror(errno)); @@ -73,6 +73,14 @@ mraa_gpio_init_internal(mraa_adv_func_t* func_table, int pin) dev->advance_func = func_table; dev->pin = pin; + // GPIO sysfs path may store the default path names schema or any other specific to vendor + dev->gpio_path = (char*) calloc(MAX_SIZE, sizeof(char)); + if (dev->gpio_path == NULL) { + syslog(LOG_CRIT, "gpio%i: Failed to allocate memory for gpio_path attribute", pin); + status = MRAA_ERROR_INVALID_RESOURCE; + goto init_internal_cleanup; + } + if (IS_FUNC_DEFINED(dev, gpio_init_internal_replace)) { status = dev->advance_func->gpio_init_internal_replace(dev, pin); if (status == MRAA_SUCCESS) @@ -95,11 +103,12 @@ mraa_gpio_init_internal(mraa_adv_func_t* func_table, int pin) dev->isr_thread_terminating = 0; dev->phy_pin = -1; - // then check to make sure the pin is exported. - char directory[MAX_SIZE]; - snprintf(directory, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/", dev->pin); + snprintf(dev->gpio_path, MAX_SIZE, "/gpio%d", dev->pin); + snprintf(bu, sizeof(bu), SYSFS_CLASS_GPIO "%s", dev->gpio_path); struct stat dir; - if (stat(directory, &dir) == 0 && S_ISDIR(dir.st_mode)) { + + // check if the pin was already created, meaning another process may be the owner + if (stat(bu, &dir) == 0 && S_ISDIR(dir.st_mode)) { dev->owner = 0; // Not Owner } else { int export = open(SYSFS_CLASS_GPIO "/export", O_WRONLY); @@ -121,8 +130,14 @@ mraa_gpio_init_internal(mraa_adv_func_t* func_table, int pin) init_internal_cleanup: if (status != MRAA_SUCCESS) { - if (dev != NULL) + if (dev != NULL) { + if (dev->gpio_path != NULL) { + free(dev->gpio_path); + dev->gpio_path = NULL; + } free(dev); + dev = NULL; + } return NULL; } return dev; @@ -248,7 +263,7 @@ mraa_gpio_interrupt_handler(void* arg) } else { // open gpio value with open(3) char bu[MAX_SIZE]; - sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin); + sprintf(bu, SYSFS_CLASS_GPIO "%s/value", dev->gpio_path); fp = open(bu, O_RDONLY); if (fp < 0) { syslog(LOG_ERR, "gpio%i: interrupt_handler: failed to open 'value' : %s", dev->pin, strerror(errno)); @@ -337,7 +352,7 @@ mraa_gpio_edge_mode(mraa_gpio_context dev, mraa_gpio_edge_t mode) } char filepath[MAX_SIZE]; - snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/edge", dev->pin); + snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "%s/edge", dev->gpio_path); int edge = open(filepath, O_RDWR); if (edge == -1) { @@ -479,7 +494,7 @@ mraa_gpio_mode(mraa_gpio_context dev, mraa_gpio_mode_t mode) } char filepath[MAX_SIZE]; - snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/drive", dev->pin); + snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "%s/drive", dev->gpio_path); int drive = open(filepath, O_WRONLY); if (drive == -1) { @@ -542,7 +557,7 @@ mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir) dev->value_fp = -1; } char filepath[MAX_SIZE]; - snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", dev->pin); + snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "%s/direction", dev->gpio_path); int direction = open(filepath, O_RDWR); @@ -605,7 +620,7 @@ mraa_gpio_read_dir(mraa_gpio_context dev, mraa_gpio_dir_t *dir) return MRAA_ERROR_INVALID_HANDLE; } - snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", dev->pin); + snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "%s/direction", dev->gpio_path); fd = open(filepath, O_RDONLY); if (fd == -1) { syslog(LOG_ERR, "gpio%i: read_dir: Failed to open 'direction' for reading: %s", dev->pin, strerror(errno)); @@ -766,7 +781,10 @@ mraa_gpio_close(mraa_gpio_context dev) close(dev->value_fp); } mraa_gpio_unexport(dev); + free(dev->gpio_path); + dev->gpio_path = NULL; free(dev); + dev = NULL; return result; } @@ -817,3 +835,13 @@ mraa_gpio_get_pin_raw(mraa_gpio_context dev) } return dev->pin; } + +char* +mraa_gpio_get_path(mraa_gpio_context dev) +{ + if (dev == NULL) { + syslog(LOG_ERR, "gpio: get_path: context is invalid"); + return NULL; + } + return dev->gpio_path; +} diff --git a/tests/gpio_checks.py b/tests/gpio_checks.py index 506697c3b..9a78f9b0d 100755 --- a/tests/gpio_checks.py +++ b/tests/gpio_checks.py @@ -36,7 +36,7 @@ class GpioChecks(u.TestCase): def setUp(self): self.pin = m.Gpio(MRAA_GPIO) - self.gpio_path = "/sys/class/gpio/gpio" + str(self.pin.getPin(True)) + self.gpio_path = "/sys/class/gpio" + self.pin.getPath() def tearDown(self): # dereference pin to force cleanup