Home | History | Annotate | Download | only in gpio
      1 /*
      2  * Author: Thomas Ingleby <thomas.c.ingleby (at) intel.com>
      3  * Author: Brendan Le Foll <brendan.le.foll (at) intel.com>
      4  * Copyright (c) 2014, 2015 Intel Corporation.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining
      7  * a copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sublicense, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be
     15  * included in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24  */
     25 #include "gpio.h"
     26 #include "mraa_internal.h"
     27 
     28 #include <stdlib.h>
     29 #include <fcntl.h>
     30 #include <string.h>
     31 #include <unistd.h>
     32 #include <poll.h>
     33 #include <pthread.h>
     34 #include <signal.h>
     35 #include <sys/stat.h>
     36 #include <sys/mman.h>
     37 
     38 #define SYSFS_CLASS_GPIO "/sys/class/gpio"
     39 #define MAX_SIZE 64
     40 #define POLL_TIMEOUT
     41 
     42 static mraa_result_t
     43 mraa_gpio_get_valfp(mraa_gpio_context dev)
     44 {
     45     char bu[MAX_SIZE];
     46     sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin);
     47     dev->value_fp = open(bu, O_RDWR);
     48     if (dev->value_fp == -1) {
     49         return MRAA_ERROR_INVALID_RESOURCE;
     50     }
     51 
     52     return MRAA_SUCCESS;
     53 }
     54 
     55 static mraa_gpio_context
     56 mraa_gpio_init_internal(mraa_adv_func_t* func_table, int pin)
     57 {
     58     if (pin < 0)
     59         return NULL;
     60 
     61     mraa_result_t status = MRAA_SUCCESS;
     62     char bu[MAX_SIZE];
     63     int length;
     64 
     65     mraa_gpio_context dev = (mraa_gpio_context) calloc(1, sizeof(struct _gpio));
     66     if (dev == NULL) {
     67         syslog(LOG_CRIT, "gpio: Failed to allocate memory for context");
     68         return NULL;
     69     }
     70 
     71     dev->advance_func = func_table;
     72     dev->pin = pin;
     73 
     74     if (IS_FUNC_DEFINED(dev, gpio_init_internal_replace)) {
     75         status = dev->advance_func->gpio_init_internal_replace(dev, pin);
     76         if (status == MRAA_SUCCESS)
     77             return dev;
     78         else
     79             goto init_internal_cleanup;
     80     }
     81 
     82     if (IS_FUNC_DEFINED(dev, gpio_init_pre)) {
     83         status = dev->advance_func->gpio_init_pre(pin);
     84         if (status != MRAA_SUCCESS)
     85             goto init_internal_cleanup;
     86     }
     87 
     88     dev->value_fp = -1;
     89     dev->isr_value_fp = -1;
     90 #ifndef HAVE_PTHREAD_CANCEL
     91     dev->isr_control_pipe[0] = dev->isr_control_pipe[1] = -1;
     92 #endif
     93     dev->isr_thread_terminating = 0;
     94     dev->phy_pin = -1;
     95 
     96     // then check to make sure the pin is exported.
     97     char directory[MAX_SIZE];
     98     snprintf(directory, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/", dev->pin);
     99     struct stat dir;
    100     if (stat(directory, &dir) == 0 && S_ISDIR(dir.st_mode)) {
    101         dev->owner = 0; // Not Owner
    102     } else {
    103         int export = open(SYSFS_CLASS_GPIO "/export", O_WRONLY);
    104         if (export == -1) {
    105             syslog(LOG_ERR, "gpio: Failed to open export for writing");
    106             status = MRAA_ERROR_NO_RESOURCES;
    107             goto init_internal_cleanup;
    108         }
    109         length = snprintf(bu, sizeof(bu), "%d", dev->pin);
    110         if (write(export, bu, length * sizeof(char)) == -1) {
    111             syslog(LOG_ERR, "gpio: Failed to write %d to export", dev->pin);
    112             close(export);
    113             status = MRAA_ERROR_NO_RESOURCES;
    114             goto init_internal_cleanup;
    115         }
    116         dev->owner = 1;
    117         close(export);
    118     }
    119 
    120 init_internal_cleanup:
    121     if (status != MRAA_SUCCESS) {
    122         if (dev != NULL)
    123             free(dev);
    124         return NULL;
    125     }
    126     return dev;
    127 }
    128 
    129 mraa_gpio_context
    130 mraa_gpio_init(int pin)
    131 {
    132     mraa_board_t* board = plat;
    133     if (board == NULL) {
    134         syslog(LOG_ERR, "gpio: platform not initialised");
    135         return NULL;
    136     }
    137 
    138     if (mraa_is_sub_platform_id(pin)) {
    139         syslog(LOG_NOTICE, "gpio: Using sub platform");
    140         board = board->sub_platform;
    141         if (board == NULL) {
    142             syslog(LOG_ERR, "gpio: Sub platform Not Initialised");
    143             return NULL;
    144         }
    145         pin = mraa_get_sub_platform_index(pin);
    146     }
    147 
    148     if (pin < 0 || pin > board->phy_pin_count) {
    149         syslog(LOG_ERR, "gpio: pin %i beyond platform definition", pin);
    150         return NULL;
    151     }
    152     if (board->pins[pin].capabilites.gpio != 1) {
    153         syslog(LOG_ERR, "gpio: pin %i not capable of gpio", pin);
    154         return NULL;
    155     }
    156     if (board->pins[pin].gpio.mux_total > 0) {
    157         if (mraa_setup_mux_mapped(board->pins[pin].gpio) != MRAA_SUCCESS) {
    158             syslog(LOG_ERR, "gpio: unable to setup muxes");
    159             return NULL;
    160         }
    161     }
    162 
    163     mraa_gpio_context r = mraa_gpio_init_internal(board->adv_func, board->pins[pin].gpio.pinmap);
    164     if (r == NULL) {
    165         syslog(LOG_CRIT, "gpio: mraa_gpio_init_raw(%d) returned error", pin);
    166         return NULL;
    167     }
    168     if (r->phy_pin == -1)
    169         r->phy_pin = pin;
    170 
    171     if (IS_FUNC_DEFINED(r, gpio_init_post)) {
    172         mraa_result_t ret = r->advance_func->gpio_init_post(r);
    173         if (ret != MRAA_SUCCESS) {
    174             free(r);
    175             return NULL;
    176         }
    177     }
    178     return r;
    179 }
    180 
    181 mraa_gpio_context
    182 mraa_gpio_init_raw(int pin)
    183 {
    184     return mraa_gpio_init_internal(plat == NULL ? NULL : plat->adv_func , pin);
    185 }
    186 
    187 
    188 static mraa_result_t
    189 mraa_gpio_wait_interrupt(int fd
    190 #ifndef HAVE_PTHREAD_CANCEL
    191         , int control_fd
    192 #endif
    193         )
    194 {
    195     unsigned char c;
    196 #ifdef HAVE_PTHREAD_CANCEL
    197     struct pollfd pfd[1];
    198 #else
    199     struct pollfd pfd[2];
    200 
    201     if (control_fd < 0) {
    202         return MRAA_ERROR_INVALID_RESOURCE;
    203     }
    204 #endif
    205 
    206     if (fd < 0) {
    207         return MRAA_ERROR_INVALID_RESOURCE;
    208     }
    209 
    210     // setup poll on POLLPRI
    211     pfd[0].fd = fd;
    212     pfd[0].events = POLLPRI;
    213 
    214     // do an initial read to clear interrupt
    215     lseek(fd, 0, SEEK_SET);
    216     read(fd, &c, 1);
    217 
    218 #ifdef HAVE_PTHREAD_CANCEL
    219     // Wait for it forever or until pthread_cancel
    220     // poll is a cancelable point like sleep()
    221     int x = poll(pfd, 1, -1);
    222 #else
    223     // setup poll on the controling fd
    224     pfd[1].fd = control_fd;
    225     pfd[1].events = 0; //  POLLHUP, POLLERR, and POLLNVAL
    226 
    227     // Wait for it forever or until control fd is closed
    228     int x = poll(pfd, 2, -1);
    229 #endif
    230 
    231     // do a final read to clear interrupt
    232     read(fd, &c, 1);
    233 
    234     return MRAA_SUCCESS;
    235 }
    236 
    237 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
    238 pthread_key_t env_key;
    239 
    240 extern JavaVM *globVM;
    241 static pthread_once_t env_key_init = PTHREAD_ONCE_INIT;
    242 
    243 jmethodID runGlobal;
    244 
    245 static void make_env_key(void)
    246 {
    247 
    248     JNIEnv *jenv;
    249     (*globVM)->GetEnv(globVM, (void **)&jenv, JNI_VERSION_1_8);
    250 
    251     jclass rcls = (*jenv)->FindClass(jenv, "java/lang/Runnable");
    252     jmethodID runm = (*jenv)->GetMethodID(jenv, rcls, "run", "()V");
    253 
    254     runGlobal = (jmethodID)(*jenv)->NewGlobalRef(jenv, (jobject)runm);
    255 
    256     pthread_key_create(&env_key, NULL);
    257 }
    258 
    259 void mraa_java_isr_callback(void* data)
    260 {
    261     JNIEnv *jenv = (JNIEnv *) pthread_getspecific(env_key);
    262     (*jenv)->CallVoidMethod(jenv, (jobject)data, runGlobal);
    263 }
    264 
    265 #endif
    266 
    267 static void*
    268 mraa_gpio_interrupt_handler(void* arg)
    269 {
    270     mraa_gpio_context dev = (mraa_gpio_context) arg;
    271     if (IS_FUNC_DEFINED(dev, gpio_interrupt_handler_replace))
    272         return dev->advance_func->gpio_interrupt_handler_replace(dev);
    273 
    274     mraa_result_t ret;
    275 
    276     // open gpio value with open(3)
    277     char bu[MAX_SIZE];
    278     sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin);
    279     int fp = open(bu, O_RDONLY);
    280     if (fp < 0) {
    281         syslog(LOG_ERR, "gpio: failed to open gpio%d/value", dev->pin);
    282         return NULL;
    283     }
    284 
    285 #ifndef HAVE_PTHREAD_CANCEL
    286     if (pipe(dev->isr_control_pipe)) {
    287         syslog(LOG_ERR, "gpio: failed to create isr control pipe");
    288         close(fp);
    289         return NULL;
    290     }
    291 #endif
    292 
    293     dev->isr_value_fp = fp;
    294 
    295 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
    296     JNIEnv *jenv;
    297     if(dev->isr == mraa_java_isr_callback) {
    298         jint err = (*globVM)->AttachCurrentThreadAsDaemon(globVM, (void **)&jenv, NULL);
    299 
    300         if (err != JNI_OK) {
    301                 close(dev->isr_value_fp);
    302                 dev->isr_value_fp = -1;
    303                 return NULL;
    304         }
    305 
    306         pthread_once(&env_key_init, make_env_key);
    307         pthread_setspecific(env_key, jenv);
    308     }
    309 #endif
    310 
    311     for (;;) {
    312         ret = mraa_gpio_wait_interrupt(dev->isr_value_fp
    313 #ifndef HAVE_PTHREAD_CANCEL
    314                 , dev->isr_control_pipe[0]
    315 #endif
    316                 );
    317         if (ret == MRAA_SUCCESS && !dev->isr_thread_terminating) {
    318 #ifdef HAVE_PTHREAD_CANCEL
    319             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    320 #endif
    321 #ifdef SWIGPYTHON
    322             // In order to call a python object (all python functions are objects) we
    323             // need to aquire the GIL (Global Interpreter Lock). This may not always be
    324             // necessary but especially if doing IO (like print()) python will segfault
    325             // if we do not hold a lock on the GIL
    326             PyGILState_STATE gilstate = PyGILState_Ensure();
    327             PyObject* arglist;
    328             PyObject* ret;
    329             arglist = Py_BuildValue("(O)", dev->isr_args);
    330             if (arglist == NULL) {
    331                 syslog(LOG_ERR, "gpio: Py_BuildValue NULL");
    332             } else {
    333                 ret = PyEval_CallObject((PyObject*) dev->isr, arglist);
    334                 if (ret == NULL) {
    335                     syslog(LOG_ERR, "gpio: PyEval_CallObject failed");
    336                     PyObject *pvalue, *ptype, *ptraceback;
    337                     PyObject *pvalue_pystr, *ptype_pystr, *ptraceback_pystr;
    338                     char *pvalue_cstr, *ptype_cstr, *ptraceback_cstr;
    339                     PyErr_Fetch(&pvalue, &ptype, &ptraceback);
    340                     pvalue_pystr = PyObject_Str(pvalue);
    341                     ptype_pystr = PyObject_Str(ptype);
    342                     ptraceback_pystr = PyObject_Str(ptraceback);
    343 // Python2
    344 #if PY_VERSION_HEX < 0x03000000
    345                     pvalue_cstr = PyString_AsString(pvalue_pystr);
    346                     ptype_cstr = PyString_AsString(ptype_pystr);
    347                     ptraceback_cstr = PyString_AsString(ptraceback_pystr);
    348 // Python 3 and up
    349 #elif PY_VERSION_HEX >= 0x03000000
    350                     // In Python 3 we need one extra conversion
    351                     PyObject *pvalue_ustr, *ptype_ustr, *ptraceback_ustr;
    352                     pvalue_ustr = PyUnicode_AsUTF8String(pvalue_pystr);
    353                     pvalue_cstr = PyBytes_AsString(pvalue_ustr);
    354                     ptype_ustr = PyUnicode_AsUTF8String(ptype_pystr);
    355                     ptype_cstr = PyBytes_AsString(ptype_ustr);
    356                     ptraceback_ustr = PyUnicode_AsUTF8String(ptraceback_pystr);
    357                     ptraceback_cstr = PyBytes_AsString(ptraceback_ustr);
    358 #endif // PY_VERSION_HEX
    359                     syslog(LOG_ERR, "gpio: the error was %s:%s:%s",
    360                            pvalue_cstr,
    361                            ptype_cstr,
    362                            ptraceback_cstr
    363                     );
    364                     Py_XDECREF(pvalue);
    365                     Py_XDECREF(ptype);
    366                     Py_XDECREF(ptraceback);
    367                     Py_XDECREF(pvalue_pystr);
    368                     Py_XDECREF(ptype_pystr);
    369                     Py_XDECREF(ptraceback_pystr);
    370 // Python 3 and up
    371 #if PY_VERSION_HEX >= 0x03000000
    372                     Py_XDECREF(pvalue_ustr);
    373                     Py_XDECREF(ptype_ustr);
    374                     Py_XDECREF(ptraceback_ustr);
    375 #endif // PY_VERSION_HEX
    376                 } else {
    377                     Py_DECREF(ret);
    378                 }
    379                 Py_DECREF(arglist);
    380             }
    381 
    382             PyGILState_Release(gilstate);
    383 #else
    384             dev->isr(dev->isr_args);
    385 #endif
    386 #ifdef HAVE_PTHREAD_CANCEL
    387             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    388 #endif
    389         } else {
    390             // we must have got an error code or exit request so die nicely
    391 #ifdef HAVE_PTHREAD_CANCEL
    392             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    393 #endif
    394             close(dev->isr_value_fp);
    395             dev->isr_value_fp = -1;
    396 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
    397 
    398             if(dev->isr == mraa_java_isr_callback) {
    399                 (*jenv)->DeleteGlobalRef(jenv, (jobject)dev->isr_args);
    400                 (*globVM)->DetachCurrentThread(globVM);
    401             }
    402 #endif
    403             return NULL;
    404         }
    405     }
    406 }
    407 
    408 mraa_result_t
    409 mraa_gpio_edge_mode(mraa_gpio_context dev, mraa_gpio_edge_t mode)
    410 {
    411     if (IS_FUNC_DEFINED(dev, gpio_edge_mode_replace))
    412         return dev->advance_func->gpio_edge_mode_replace(dev, mode);
    413 
    414     if (dev->value_fp != -1) {
    415         close(dev->value_fp);
    416         dev->value_fp = -1;
    417     }
    418 
    419     char filepath[MAX_SIZE];
    420     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/edge", dev->pin);
    421 
    422     int edge = open(filepath, O_RDWR);
    423     if (edge == -1) {
    424         syslog(LOG_ERR, "gpio: Failed to open edge for writing");
    425         return MRAA_ERROR_INVALID_RESOURCE;
    426     }
    427 
    428     char bu[MAX_SIZE];
    429     int length;
    430     switch (mode) {
    431         case MRAA_GPIO_EDGE_NONE:
    432             length = snprintf(bu, sizeof(bu), "none");
    433             break;
    434         case MRAA_GPIO_EDGE_BOTH:
    435             length = snprintf(bu, sizeof(bu), "both");
    436             break;
    437         case MRAA_GPIO_EDGE_RISING:
    438             length = snprintf(bu, sizeof(bu), "rising");
    439             break;
    440         case MRAA_GPIO_EDGE_FALLING:
    441             length = snprintf(bu, sizeof(bu), "falling");
    442             break;
    443         default:
    444             close(edge);
    445             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
    446     }
    447     if (write(edge, bu, length * sizeof(char)) == -1) {
    448         syslog(LOG_ERR, "gpio: Failed to write to edge");
    449         close(edge);
    450         return MRAA_ERROR_INVALID_RESOURCE;
    451     }
    452 
    453     close(edge);
    454     return MRAA_SUCCESS;
    455 }
    456 
    457 mraa_result_t
    458 mraa_gpio_isr(mraa_gpio_context dev, mraa_gpio_edge_t mode, void (*fptr)(void*), void* args)
    459 {
    460     // we only allow one isr per mraa_gpio_context
    461     if (dev->thread_id != 0) {
    462         return MRAA_ERROR_NO_RESOURCES;
    463     }
    464 
    465     if (MRAA_SUCCESS != mraa_gpio_edge_mode(dev, mode)) {
    466         return MRAA_ERROR_UNSPECIFIED;
    467     }
    468 
    469     dev->isr = fptr;
    470 #if defined(SWIGJAVA) || defined(JAVACALLBACK)
    471     JNIEnv *jenv;
    472     /* Most UPM sensors use the C API, the global ref must be created here. */
    473     /* The reason for checking the callback function is internal callbacks. */
    474     if (fptr == mraa_java_isr_callback) {
    475         (*globVM)->GetEnv(globVM, (void **)&jenv, JNI_VERSION_1_8);
    476         jobject grunnable = (*jenv)->NewGlobalRef(jenv, (jobject) args);
    477         args = (void *) grunnable;
    478     }
    479 #endif
    480     dev->isr_args = args;
    481     pthread_create(&dev->thread_id, NULL, mraa_gpio_interrupt_handler, (void*) dev);
    482 
    483     return MRAA_SUCCESS;
    484 }
    485 
    486 mraa_result_t
    487 mraa_gpio_isr_exit(mraa_gpio_context dev)
    488 {
    489     mraa_result_t ret = MRAA_SUCCESS;
    490 
    491     // wasting our time, there is no isr to exit from
    492     if (dev->thread_id == 0 && dev->isr_value_fp == -1) {
    493         return ret;
    494     }
    495     // mark the beginning of the thread termination process for interested parties
    496     dev->isr_thread_terminating = 1;
    497 
    498     // stop isr being useful
    499     ret = mraa_gpio_edge_mode(dev, MRAA_GPIO_EDGE_NONE);
    500 
    501     if ((dev->thread_id != 0)) {
    502 #ifdef HAVE_PTHREAD_CANCEL
    503         if ((pthread_cancel(dev->thread_id) != 0) || (pthread_join(dev->thread_id, NULL) != 0)) {
    504             ret = MRAA_ERROR_INVALID_HANDLE;
    505         }
    506 #else
    507         close(dev->isr_control_pipe[1]);
    508         if (pthread_join(dev->thread_id, NULL) != 0)
    509             ret = MRAA_ERROR_INVALID_HANDLE;
    510 
    511         close(dev->isr_control_pipe[0]);
    512         dev->isr_control_pipe[0] =  dev->isr_control_pipe[1] = -1;
    513 #endif
    514     }
    515 
    516     // close the filehandle in case it's still open
    517     if (dev->isr_value_fp != -1) {
    518         if (close(dev->isr_value_fp) != 0) {
    519             ret = MRAA_ERROR_INVALID_PARAMETER;
    520         }
    521     }
    522 
    523     // assume our thread will exit either way we just lost it's handle
    524     dev->thread_id = 0;
    525     dev->isr_value_fp = -1;
    526     dev->isr_thread_terminating = 0;
    527     return ret;
    528 }
    529 
    530 mraa_result_t
    531 mraa_gpio_mode(mraa_gpio_context dev, mraa_gpio_mode_t mode)
    532 {
    533     if (IS_FUNC_DEFINED(dev, gpio_mode_replace))
    534         return dev->advance_func->gpio_mode_replace(dev, mode);
    535 
    536     if (IS_FUNC_DEFINED(dev, gpio_mode_pre)) {
    537         mraa_result_t pre_ret = (dev->advance_func->gpio_mode_pre(dev, mode));
    538         if (pre_ret != MRAA_SUCCESS)
    539             return pre_ret;
    540     }
    541 
    542     if (dev->value_fp != -1) {
    543         close(dev->value_fp);
    544         dev->value_fp = -1;
    545     }
    546 
    547     char filepath[MAX_SIZE];
    548     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/drive", dev->pin);
    549 
    550     int drive = open(filepath, O_WRONLY);
    551     if (drive == -1) {
    552         syslog(LOG_ERR, "gpio: Failed to open drive for writing");
    553         return MRAA_ERROR_INVALID_RESOURCE;
    554     }
    555 
    556     char bu[MAX_SIZE];
    557     int length;
    558     switch (mode) {
    559         case MRAA_GPIO_STRONG:
    560             length = snprintf(bu, sizeof(bu), "strong");
    561             break;
    562         case MRAA_GPIO_PULLUP:
    563             length = snprintf(bu, sizeof(bu), "pullup");
    564             break;
    565         case MRAA_GPIO_PULLDOWN:
    566             length = snprintf(bu, sizeof(bu), "pulldown");
    567             break;
    568         case MRAA_GPIO_HIZ:
    569             length = snprintf(bu, sizeof(bu), "hiz");
    570             break;
    571         default:
    572             close(drive);
    573             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
    574     }
    575     if (write(drive, bu, length * sizeof(char)) == -1) {
    576         syslog(LOG_ERR, "gpio: Failed to write to drive mode");
    577         close(drive);
    578         return MRAA_ERROR_INVALID_RESOURCE;
    579     }
    580 
    581     close(drive);
    582     if (IS_FUNC_DEFINED(dev, gpio_mode_post))
    583         return dev->advance_func->gpio_mode_post(dev, mode);
    584     return MRAA_SUCCESS;
    585 }
    586 
    587 mraa_result_t
    588 mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
    589 {
    590     if (IS_FUNC_DEFINED(dev, gpio_dir_replace)) {
    591         return dev->advance_func->gpio_dir_replace(dev, dir);
    592     }
    593 
    594     if (IS_FUNC_DEFINED(dev, gpio_dir_pre)) {
    595         mraa_result_t pre_ret = (dev->advance_func->gpio_dir_pre(dev, dir));
    596         if (pre_ret != MRAA_SUCCESS) {
    597             return pre_ret;
    598         }
    599     }
    600 
    601     if (dev == NULL) {
    602         return MRAA_ERROR_INVALID_HANDLE;
    603     }
    604     if (dev->value_fp != -1) {
    605         close(dev->value_fp);
    606         dev->value_fp = -1;
    607     }
    608     char filepath[MAX_SIZE];
    609     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", dev->pin);
    610 
    611     int direction = open(filepath, O_RDWR);
    612 
    613     if (direction == -1) {
    614         // Direction Failed to Open. If HIGH or LOW was passed will try and set
    615         // If not fail as usual.
    616         switch (dir) {
    617             case MRAA_GPIO_OUT_HIGH:
    618                 return mraa_gpio_write(dev, 1);
    619             case MRAA_GPIO_OUT_LOW:
    620                 return mraa_gpio_write(dev, 0);
    621             default:
    622                 return MRAA_ERROR_INVALID_RESOURCE;
    623         }
    624     }
    625 
    626     char bu[MAX_SIZE];
    627     int length;
    628     switch (dir) {
    629         case MRAA_GPIO_OUT:
    630             length = snprintf(bu, sizeof(bu), "out");
    631             break;
    632         case MRAA_GPIO_IN:
    633             length = snprintf(bu, sizeof(bu), "in");
    634             break;
    635         case MRAA_GPIO_OUT_HIGH:
    636             length = snprintf(bu, sizeof(bu), "high");
    637             break;
    638         case MRAA_GPIO_OUT_LOW:
    639             length = snprintf(bu, sizeof(bu), "low");
    640             break;
    641         default:
    642             close(direction);
    643             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
    644     }
    645 
    646     if (write(direction, bu, length * sizeof(char)) == -1) {
    647         close(direction);
    648         return MRAA_ERROR_INVALID_RESOURCE;
    649     }
    650 
    651     close(direction);
    652     if (IS_FUNC_DEFINED(dev, gpio_dir_post))
    653         return dev->advance_func->gpio_dir_post(dev, dir);
    654     return MRAA_SUCCESS;
    655 }
    656 
    657 int
    658 mraa_gpio_read(mraa_gpio_context dev)
    659 {
    660     if (dev == NULL)
    661         return -1;
    662 
    663     if (IS_FUNC_DEFINED(dev, gpio_read_replace))
    664         return dev->advance_func->gpio_read_replace(dev);
    665 
    666     if (dev->mmap_read != NULL)
    667         return dev->mmap_read(dev);
    668 
    669     if (dev->value_fp == -1) {
    670         if (mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) {
    671             syslog(LOG_ERR, "gpio: Failed to get value file pointer");
    672             return -1;
    673         }
    674     } else {
    675         // if value_fp is new this is pointless
    676         lseek(dev->value_fp, 0, SEEK_SET);
    677     }
    678     char bu[2];
    679     if (read(dev->value_fp, bu, 2 * sizeof(char)) != 2) {
    680         syslog(LOG_ERR, "gpio: Failed to read a sensible value from sysfs");
    681         return -1;
    682     }
    683     lseek(dev->value_fp, 0, SEEK_SET);
    684 
    685     return (int) strtol(bu, NULL, 10);
    686 }
    687 
    688 mraa_result_t
    689 mraa_gpio_write(mraa_gpio_context dev, int value)
    690 {
    691     if (dev == NULL)
    692         return MRAA_ERROR_INVALID_HANDLE;
    693 
    694     if (dev->mmap_write != NULL)
    695         return dev->mmap_write(dev, value);
    696 
    697     if (IS_FUNC_DEFINED(dev, gpio_write_pre)) {
    698         mraa_result_t pre_ret = (dev->advance_func->gpio_write_pre(dev, value));
    699         if (pre_ret != MRAA_SUCCESS)
    700             return pre_ret;
    701     }
    702 
    703     if (IS_FUNC_DEFINED(dev, gpio_write_replace)) {
    704         return dev->advance_func->gpio_write_replace(dev, value);
    705     }
    706 
    707     if (dev->value_fp == -1) {
    708         if (mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) {
    709             return MRAA_ERROR_INVALID_RESOURCE;
    710         }
    711     }
    712 
    713     if (lseek(dev->value_fp, 0, SEEK_SET) == -1) {
    714         return MRAA_ERROR_INVALID_RESOURCE;
    715     }
    716 
    717     char bu[MAX_SIZE];
    718     int length = snprintf(bu, sizeof(bu), "%d", value);
    719     if (write(dev->value_fp, bu, length * sizeof(char)) == -1) {
    720         return MRAA_ERROR_INVALID_HANDLE;
    721     }
    722 
    723     if (IS_FUNC_DEFINED(dev, gpio_write_post))
    724         return dev->advance_func->gpio_write_post(dev, value);
    725     return MRAA_SUCCESS;
    726 }
    727 
    728 static mraa_result_t
    729 mraa_gpio_unexport_force(mraa_gpio_context dev)
    730 {
    731     int unexport = open(SYSFS_CLASS_GPIO "/unexport", O_WRONLY);
    732     if (unexport == -1) {
    733         syslog(LOG_ERR, "gpio: Failed to open unexport for writing");
    734         return MRAA_ERROR_INVALID_RESOURCE;
    735     }
    736 
    737     char bu[MAX_SIZE];
    738     int length = snprintf(bu, sizeof(bu), "%d", dev->pin);
    739     if (write(unexport, bu, length * sizeof(char)) == -1) {
    740         syslog(LOG_ERR, "gpio: Failed to write to unexport");
    741         close(unexport);
    742         return MRAA_ERROR_INVALID_RESOURCE;
    743     }
    744 
    745     close(unexport);
    746     mraa_gpio_isr_exit(dev);
    747     return MRAA_SUCCESS;
    748 }
    749 static mraa_result_t
    750 mraa_gpio_unexport(mraa_gpio_context dev)
    751 {
    752     if (dev->owner) {
    753         return mraa_gpio_unexport_force(dev);
    754     }
    755     return MRAA_ERROR_INVALID_RESOURCE;
    756 }
    757 
    758 mraa_result_t
    759 mraa_gpio_close(mraa_gpio_context dev)
    760 {
    761     mraa_result_t result = MRAA_SUCCESS;
    762 
    763     if (IS_FUNC_DEFINED(dev, gpio_close_pre)) {
    764         result = dev->advance_func->gpio_close_pre(dev);
    765     }
    766 
    767     if (dev->value_fp != -1) {
    768         close(dev->value_fp);
    769     }
    770     mraa_gpio_unexport(dev);
    771     free(dev);
    772     return result;
    773 }
    774 
    775 mraa_result_t
    776 mraa_gpio_owner(mraa_gpio_context dev, mraa_boolean_t own)
    777 {
    778     if (dev == NULL) {
    779         return MRAA_ERROR_INVALID_RESOURCE;
    780     }
    781     syslog(LOG_DEBUG, "gpio: Set owner to %d", (int) own);
    782     dev->owner = own;
    783     return MRAA_SUCCESS;
    784 }
    785 
    786 mraa_result_t
    787 mraa_gpio_use_mmaped(mraa_gpio_context dev, mraa_boolean_t mmap_en)
    788 {
    789     if (IS_FUNC_DEFINED(dev, gpio_mmap_setup)) {
    790         return dev->advance_func->gpio_mmap_setup(dev, mmap_en);
    791     }
    792 
    793     syslog(LOG_ERR, "gpio: mmap not implemented on this platform");
    794     return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
    795 }
    796 
    797 int
    798 mraa_gpio_get_pin(mraa_gpio_context dev)
    799 {
    800     if (dev == NULL) {
    801         syslog(LOG_ERR, "gpio: context is invalid");
    802         return -1;
    803     }
    804     return dev->phy_pin;
    805 }
    806 
    807 int
    808 mraa_gpio_get_pin_raw(mraa_gpio_context dev)
    809 {
    810     if (dev == NULL) {
    811         syslog(LOG_ERR, "gpio: context is invalid");
    812         return -1;
    813     }
    814     return dev->pin;
    815 }
    816