From 7abd8f5529c62235309980f59b84ed4e785caa5c Mon Sep 17 00:00:00 2001 From: Thomas Ingleby Date: Tue, 20 May 2014 13:51:12 +0100 Subject: [PATCH] gpio: add ownership gaurd * Will not unexport if the context did not export it. Can be forced. * Checks if pin is already exported. Signed-off-by: Thomas Ingleby Signed-off-by: Brendan Le Foll --- api/gpio.h | 16 ++++++++++++++ api/gpio.hpp | 4 +++- src/gpio/gpio.c | 58 +++++++++++++++++++++++++++++++++++++------------ 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/api/gpio.h b/api/gpio.h index 599abef..adfe45b 100644 --- a/api/gpio.h +++ b/api/gpio.h @@ -159,6 +159,15 @@ maa_result_t maa_gpio_close(maa_gpio_context dev); */ maa_result_t maa_gpio_unexport(maa_gpio_context dev); +/** Unexport the GPIO context (maa_gpio_close() will call this function) + * Forces regardless to to ownership. + * + * @param dev The GPIO context. + * + * @return maa result type. + */ +maa_result_t maa_gpio_unexport_force(maa_gpio_context dev); + /** Read the GPIO value. * * @param dev The GPIO context. @@ -176,6 +185,13 @@ int maa_gpio_read(maa_gpio_context dev); */ maa_result_t maa_gpio_write(maa_gpio_context dev, int value); +/** Change ownership of the context. + * + * @param dev gpio context + * @param owner does this context own the pin. + */ +maa_result_t maa_gpio_owner(maa_gpio_context dev, maa_boolean_t owner); + #ifdef __cplusplus } #endif diff --git a/api/gpio.hpp b/api/gpio.hpp index 7262d83..8d156b8 100644 --- a/api/gpio.hpp +++ b/api/gpio.hpp @@ -56,11 +56,13 @@ typedef enum { class Gpio { public: - Gpio(int pin, bool raw=false) { + Gpio(int pin, bool owner=true, bool raw=false) { if (raw) m_gpio = maa_gpio_init_raw(pin); else m_gpio = maa_gpio_init(pin); + if (!owner) + maa_gpio_owner(m_gpio, 0); } ~Gpio() { maa_result_t x = maa_gpio_close(m_gpio); diff --git a/src/gpio/gpio.c b/src/gpio/gpio.c index 465a402..69181cb 100644 --- a/src/gpio/gpio.c +++ b/src/gpio/gpio.c @@ -31,13 +31,14 @@ #include #include #include +#include #define SYSFS_CLASS_GPIO "/sys/class/gpio" #define MAX_SIZE 64 #define POLL_TIMEOUT /** - * A strucutre representing a gpio pin. + * A structure representing a gpio pin. */ struct _gpio { @@ -47,6 +48,7 @@ struct _gpio { void (* isr)(); /**< the interupt service request */ pthread_t thread_id; /**< the isr handler thread id */ int isr_value_fp; /**< the isr file pointer on the value */ + maa_boolean_t owner; /**< If this context originally exported the pin */ /*@}*/ }; @@ -55,7 +57,6 @@ maa_gpio_get_valfp(maa_gpio_context dev) { char bu[MAX_SIZE]; sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin); - dev->value_fp = open(bu, O_RDWR); if (dev->value_fp == -1) { return MAA_ERROR_INVALID_RESOURCE; @@ -89,17 +90,27 @@ maa_gpio_init_raw(int pin) dev->isr_value_fp = -1; dev->pin = pin; - int export = open(SYSFS_CLASS_GPIO "/export", O_WRONLY); - if (export == -1) { - fprintf(stderr, "Failed to open export for writing!\n"); - return NULL; + char directory[MAX_SIZE]; + snprintf(directory, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/", dev->pin); + struct stat dir; + if (stat(directory, &dir) == 0 && S_ISDIR(dir.st_mode)) { + fprintf(stderr, "GPIO Pin already exporting, continuing.\n"); + dev->owner = 0; // Not Owner + } else { + int export = open(SYSFS_CLASS_GPIO "/export", O_WRONLY); + if (export == -1) { + fprintf(stderr, "Failed to open export for writing!\n"); + return NULL; + } + length = snprintf(bu, sizeof(bu), "%d", dev->pin); + if (write(export, bu, length*sizeof(char)) == -1) { + fprintf(stderr, "Failed to write to export\n"); + close(export); + return NULL; + } + dev->owner = 1; + close(export); } - length = snprintf(bu, sizeof(bu), "%d", dev->pin); - if (write(export, bu, length*sizeof(char)) == -1) { - fprintf(stderr, "Failed to write to export\n"); - } - - close(export); return dev; } @@ -160,11 +171,11 @@ maa_gpio_interrupt_handler(void* arg) #endif pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); } else { - // we must have got an error code so die nicely + // we must have got an error code so die nicely pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); close(dev->isr_value_fp); dev->isr_value_fp = -1; - return NULL; + return NULL; } } } @@ -401,6 +412,15 @@ maa_gpio_write(maa_gpio_context dev, int value) maa_result_t maa_gpio_unexport(maa_gpio_context dev) +{ + if(dev->owner) { + return maa_gpio_unexport_force(dev); + } + return MAA_ERROR_INVALID_RESOURCE; +} + +maa_result_t +maa_gpio_unexport_force(maa_gpio_context dev) { int unexport = open(SYSFS_CLASS_GPIO "/unexport", O_WRONLY); if (unexport == -1) { @@ -431,3 +451,13 @@ maa_gpio_close(maa_gpio_context dev) free(dev); return MAA_SUCCESS; } + +maa_result_t +maa_gpio_owner(maa_gpio_context dev, maa_boolean_t own) +{ + if (dev == NULL) + return MAA_ERROR_INVALID_RESOURCE; + dev->owner = own; + return MAA_SUCCESS; +} +