gpio: add ownership gaurd
authorThomas Ingleby <thomas.c.ingleby@intel.com>
Tue, 20 May 2014 12:51:12 +0000 (13:51 +0100)
committerBrendan Le Foll <brendan.le.foll@intel.com>
Tue, 20 May 2014 13:11:41 +0000 (14:11 +0100)
* Will not unexport if the context did not export it. Can be forced.
* Checks if pin is already exported.

Signed-off-by: Thomas Ingleby <thomas.c.ingleby@intel.com>
Signed-off-by: Brendan Le Foll <brendan.le.foll@intel.com>
api/gpio.h
api/gpio.hpp
src/gpio/gpio.c

index 599abef..adfe45b 100644 (file)
@@ -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
index 7262d83..8d156b8 100644 (file)
@@ -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);
index 465a402..69181cb 100644 (file)
 #include <poll.h>
 #include <pthread.h>
 #include <signal.h>
+#include <sys/stat.h>
 
 #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;
-    }
-    length = snprintf(bu, sizeof(bu), "%d", dev->pin);
-    if (write(export, bu, length*sizeof(char)) == -1) {
-        fprintf(stderr, "Failed to write to export\n");
+    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);
     }
-
-    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;
         }
     }
 }
@@ -402,6 +413,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) {
         fprintf(stderr, "Failed to open unexport for writing!\n");
@@ -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;
+}
+