d8c0e69b91bf6053075148d2553345f60446077a
[contrib/mraa.git] / src / gpio / gpio.c
1 /*
2  * Author: Thomas Ingleby <thomas.c.ingleby@intel.com>
3  * Author: Brendan Le Foll <brendan.le.foll@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(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     dev->isr_thread_terminating = 0;
91     dev->phy_pin = -1;
92
93     // then check to make sure the pin is exported.
94     char directory[MAX_SIZE];
95     snprintf(directory, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/", dev->pin);
96     struct stat dir;
97     if (stat(directory, &dir) == 0 && S_ISDIR(dir.st_mode)) {
98         dev->owner = 0; // Not Owner
99     } else {
100         int export = open(SYSFS_CLASS_GPIO "/export", O_WRONLY);
101         if (export == -1) {
102             syslog(LOG_ERR, "gpio: Failed to open export for writing");
103             status = MRAA_ERROR_NO_RESOURCES;
104             goto init_internal_cleanup;
105         }
106         length = snprintf(bu, sizeof(bu), "%d", dev->pin);
107         if (write(export, bu, length * sizeof(char)) == -1) {
108             syslog(LOG_ERR, "gpio: Failed to write %d to export", dev->pin);
109             close(export);
110             status = MRAA_ERROR_NO_RESOURCES;
111             goto init_internal_cleanup;
112         }
113         dev->owner = 1;
114         close(export);
115     }
116
117 init_internal_cleanup:
118     if (status != MRAA_SUCCESS) {
119         if (dev != NULL)
120             free(dev);
121         return NULL;
122     }
123     return dev;
124 }
125
126 mraa_gpio_context
127 mraa_gpio_init(int pin)
128 {
129     mraa_board_t* board = plat;
130     if (board == NULL) {
131         syslog(LOG_ERR, "gpio: platform not initialised");
132         return NULL;
133     }
134
135     if (mraa_is_sub_platform_id(pin)) {
136         syslog(LOG_NOTICE, "gpio: Using sub platform");
137         board = board->sub_platform;
138         if (board == NULL) {
139             syslog(LOG_ERR, "gpio: Sub platform Not Initialised");
140             return NULL;
141         }
142         pin = mraa_get_sub_platform_index(pin);
143     }
144
145     if (pin < 0 || pin > board->phy_pin_count) {
146         syslog(LOG_ERR, "gpio: pin %i beyond platform definition", pin);
147         return NULL;
148     }
149     if (board->pins[pin].capabilites.gpio != 1) {
150         syslog(LOG_ERR, "gpio: pin %i not capable of gpio", pin);
151         return NULL;
152     }
153     if (board->pins[pin].gpio.mux_total > 0) {
154         if (mraa_setup_mux_mapped(board->pins[pin].gpio) != MRAA_SUCCESS) {
155             syslog(LOG_ERR, "gpio: unable to setup muxes");
156             return NULL;
157         }
158     }
159
160     mraa_gpio_context r = mraa_gpio_init_internal(board->adv_func, board->pins[pin].gpio.pinmap);
161     if (r == NULL) {
162         syslog(LOG_CRIT, "gpio: mraa_gpio_init_raw(%d) returned error", pin);
163         return NULL;
164     }
165     r->phy_pin = pin;
166
167     if (IS_FUNC_DEFINED(r, gpio_init_post)) {
168         mraa_result_t ret = r->advance_func->gpio_init_post(r);
169         if (ret != MRAA_SUCCESS) {
170             free(r);
171             return NULL;
172         }
173     }
174     return r;
175 }
176
177 mraa_gpio_context
178 mraa_gpio_init_raw(int pin)
179 {
180     return mraa_gpio_init_internal(plat == NULL ? NULL : plat->adv_func , pin);
181 }
182
183
184 static mraa_result_t
185 mraa_gpio_wait_interrupt(int fd)
186 {
187     unsigned char c;
188     struct pollfd pfd;
189
190     if (fd < 0) {
191         return MRAA_ERROR_INVALID_RESOURCE;
192     }
193
194     // setup poll on POLLPRI
195     pfd.fd = fd;
196     pfd.events = POLLPRI;
197
198     // do an initial read to clear interrupt
199     lseek(fd, 0, SEEK_SET);
200     read(fd, &c, 1);
201
202     // Wait for it forever or until pthread_cancel
203     // poll is a cancelable point like sleep()
204     int x = poll(&pfd, 1, -1);
205
206     // do a final read to clear interrupt
207     read(fd, &c, 1);
208
209     return MRAA_SUCCESS;
210 }
211
212 static void*
213 mraa_gpio_interrupt_handler(void* arg)
214 {
215     mraa_gpio_context dev = (mraa_gpio_context) arg;
216     if (IS_FUNC_DEFINED(dev, gpio_interrupt_handler_replace))
217         return dev->advance_func->gpio_interrupt_handler_replace(dev);
218
219     mraa_result_t ret;
220
221     // open gpio value with open(3)
222     char bu[MAX_SIZE];
223     sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin);
224     int fp = open(bu, O_RDONLY);
225     if (fp < 0) {
226         syslog(LOG_ERR, "gpio: failed to open gpio%d/value", dev->pin);
227         return NULL;
228     }
229     dev->isr_value_fp = fp;
230
231     for (;;) {
232         ret = mraa_gpio_wait_interrupt(dev->isr_value_fp);
233         if (ret == MRAA_SUCCESS && !dev->isr_thread_terminating) {
234             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
235 #ifdef SWIGPYTHON
236             // In order to call a python object (all python functions are objects) we
237             // need to aquire the GIL (Global Interpreter Lock). This may not always be
238             // necessary but especially if doing IO (like print()) python will segfault
239             // if we do not hold a lock on the GIL
240             PyGILState_STATE gilstate = PyGILState_Ensure();
241             PyObject* arglist;
242             PyObject* ret;
243             arglist = Py_BuildValue("(O)", dev->isr_args);
244             if (arglist == NULL) {
245                 syslog(LOG_ERR, "gpio: Py_BuildValue NULL");
246             } else {
247                 ret = PyEval_CallObject((PyObject*) dev->isr, arglist);
248                 if (ret == NULL) {
249                     syslog(LOG_ERR, "gpio: PyEval_CallObject failed");
250                     PyObject *pvalue, *ptype, *ptraceback;
251                     PyObject *pvalue_pystr, *ptype_pystr, *ptraceback_pystr;
252                     char *pvalue_cstr, *ptype_cstr, *ptraceback_cstr;
253                     PyErr_Fetch(&pvalue, &ptype, &ptraceback);
254                     pvalue_pystr = PyObject_Str(pvalue);
255                     ptype_pystr = PyObject_Str(ptype);
256                     ptraceback_pystr = PyObject_Str(ptraceback);
257 // Python2
258 #if PY_VERSION_HEX < 0x03000000
259                     pvalue_cstr = PyString_AsString(pvalue_pystr);
260                     ptype_cstr = PyString_AsString(ptype_pystr);
261                     ptraceback_cstr = PyString_AsString(ptraceback_pystr);
262 // Python 3 and up
263 #elif PY_VERSION_HEX >= 0x03000000
264                     // In Python 3 we need one extra conversion
265                     PyObject *pvalue_ustr, *ptype_ustr, *ptraceback_ustr;
266                     pvalue_ustr = PyUnicode_AsUTF8String(pvalue_pystr);
267                     pvalue_cstr = PyBytes_AsString(pvalue_ustr);
268                     ptype_ustr = PyUnicode_AsUTF8String(ptype_pystr);
269                     ptype_cstr = PyBytes_AsString(ptype_ustr);
270                     ptraceback_ustr = PyUnicode_AsUTF8String(ptraceback_pystr);
271                     ptraceback_cstr = PyBytes_AsString(ptraceback_ustr);
272 #endif // PY_VERSION_HEX
273                     syslog(LOG_ERR, "gpio: the error was %s:%s:%s",
274                            pvalue_cstr,
275                            ptype_cstr,
276                            ptraceback_cstr
277                     );
278                     Py_XDECREF(pvalue);
279                     Py_XDECREF(ptype);
280                     Py_XDECREF(ptraceback);
281                     Py_XDECREF(pvalue_pystr);
282                     Py_XDECREF(ptype_pystr);
283                     Py_XDECREF(ptraceback_pystr);
284 // Python 3 and up
285 #if PY_VERSION_HEX >= 0x03000000
286                     Py_XDECREF(pvalue_ustr);
287                     Py_XDECREF(ptype_ustr);
288                     Py_XDECREF(ptraceback_ustr);
289 #endif // PY_VERSION_HEX
290                 } else {
291                     Py_DECREF(ret);
292                 }
293                 Py_DECREF(arglist);
294             }
295
296             PyGILState_Release(gilstate);
297 #else
298             dev->isr(dev->isr_args);
299 #endif
300             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
301         } else {
302             // we must have got an error code or exit request so die nicely
303             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
304             close(dev->isr_value_fp);
305             dev->isr_value_fp = -1;
306             return NULL;
307         }
308     }
309 }
310
311 mraa_result_t
312 mraa_gpio_edge_mode(mraa_gpio_context dev, mraa_gpio_edge_t mode)
313 {
314     if (IS_FUNC_DEFINED(dev, gpio_edge_mode_replace))
315         return dev->advance_func->gpio_edge_mode_replace(dev, mode);
316
317     if (dev->value_fp != -1) {
318         close(dev->value_fp);
319         dev->value_fp = -1;
320     }
321
322     char filepath[MAX_SIZE];
323     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/edge", dev->pin);
324
325     int edge = open(filepath, O_RDWR);
326     if (edge == -1) {
327         syslog(LOG_ERR, "gpio: Failed to open edge for writing");
328         return MRAA_ERROR_INVALID_RESOURCE;
329     }
330
331     char bu[MAX_SIZE];
332     int length;
333     switch (mode) {
334         case MRAA_GPIO_EDGE_NONE:
335             length = snprintf(bu, sizeof(bu), "none");
336             break;
337         case MRAA_GPIO_EDGE_BOTH:
338             length = snprintf(bu, sizeof(bu), "both");
339             break;
340         case MRAA_GPIO_EDGE_RISING:
341             length = snprintf(bu, sizeof(bu), "rising");
342             break;
343         case MRAA_GPIO_EDGE_FALLING:
344             length = snprintf(bu, sizeof(bu), "falling");
345             break;
346         default:
347             close(edge);
348             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
349     }
350     if (write(edge, bu, length * sizeof(char)) == -1) {
351         syslog(LOG_ERR, "gpio: Failed to write to edge");
352         close(edge);
353         return MRAA_ERROR_INVALID_RESOURCE;
354     }
355
356     close(edge);
357     return MRAA_SUCCESS;
358 }
359
360 mraa_result_t
361 mraa_gpio_isr(mraa_gpio_context dev, mraa_gpio_edge_t mode, void (*fptr)(void*), void* args)
362 {
363     // we only allow one isr per mraa_gpio_context
364     if (dev->thread_id != 0) {
365         return MRAA_ERROR_NO_RESOURCES;
366     }
367
368     if (MRAA_SUCCESS != mraa_gpio_edge_mode(dev, mode)) {
369         return MRAA_ERROR_UNSPECIFIED;
370     }
371
372     dev->isr = fptr;
373     dev->isr_args = args;
374     pthread_create(&dev->thread_id, NULL, mraa_gpio_interrupt_handler, (void*) dev);
375
376     return MRAA_SUCCESS;
377 }
378
379 mraa_result_t
380 mraa_gpio_isr_exit(mraa_gpio_context dev)
381 {
382     mraa_result_t ret = MRAA_SUCCESS;
383
384     // wasting our time, there is no isr to exit from
385     if (dev->thread_id == 0 && dev->isr_value_fp == -1) {
386         return ret;
387     }
388     // mark the beginning of the thread termination process for interested parties
389     dev->isr_thread_terminating = 1;
390
391     // stop isr being useful
392     ret = mraa_gpio_edge_mode(dev, MRAA_GPIO_EDGE_NONE);
393
394     if ((dev->thread_id != 0)) {
395         if ((pthread_cancel(dev->thread_id) != 0) || (pthread_join(dev->thread_id, NULL) != 0)) {
396             ret = MRAA_ERROR_INVALID_HANDLE;
397         }
398     }
399
400     // close the filehandle in case it's still open
401     if (dev->isr_value_fp != -1) {
402         if (close(dev->isr_value_fp) != 0) {
403             ret = MRAA_ERROR_INVALID_PARAMETER;
404         }
405     }
406
407     // assume our thread will exit either way we just lost it's handle
408     dev->thread_id = 0;
409     dev->isr_value_fp = -1;
410     dev->isr_thread_terminating = 0;
411     return ret;
412 }
413
414 mraa_result_t
415 mraa_gpio_mode(mraa_gpio_context dev, mraa_gpio_mode_t mode)
416 {
417     if (IS_FUNC_DEFINED(dev, gpio_mode_replace))
418         return dev->advance_func->gpio_mode_replace(dev, mode);
419
420     if (IS_FUNC_DEFINED(dev, gpio_mode_pre)) {
421         mraa_result_t pre_ret = (dev->advance_func->gpio_mode_pre(dev, mode));
422         if (pre_ret != MRAA_SUCCESS)
423             return pre_ret;
424     }
425
426     if (dev->value_fp != -1) {
427         close(dev->value_fp);
428         dev->value_fp = -1;
429     }
430
431     char filepath[MAX_SIZE];
432     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/drive", dev->pin);
433
434     int drive = open(filepath, O_WRONLY);
435     if (drive == -1) {
436         syslog(LOG_ERR, "gpio: Failed to open drive for writing");
437         return MRAA_ERROR_INVALID_RESOURCE;
438     }
439
440     char bu[MAX_SIZE];
441     int length;
442     switch (mode) {
443         case MRAA_GPIO_STRONG:
444             length = snprintf(bu, sizeof(bu), "strong");
445             break;
446         case MRAA_GPIO_PULLUP:
447             length = snprintf(bu, sizeof(bu), "pullup");
448             break;
449         case MRAA_GPIO_PULLDOWN:
450             length = snprintf(bu, sizeof(bu), "pulldown");
451             break;
452         case MRAA_GPIO_HIZ:
453             length = snprintf(bu, sizeof(bu), "hiz");
454             break;
455         default:
456             close(drive);
457             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
458     }
459     if (write(drive, bu, length * sizeof(char)) == -1) {
460         syslog(LOG_ERR, "gpio: Failed to write to drive mode");
461         close(drive);
462         return MRAA_ERROR_INVALID_RESOURCE;
463     }
464
465     close(drive);
466     if (IS_FUNC_DEFINED(dev, gpio_mode_post))
467         return dev->advance_func->gpio_mode_post(dev, mode);
468     return MRAA_SUCCESS;
469 }
470
471 mraa_result_t
472 mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
473 {
474     if (IS_FUNC_DEFINED(dev, gpio_dir_replace)) {
475         return dev->advance_func->gpio_dir_replace(dev, dir);
476     }
477
478     if (IS_FUNC_DEFINED(dev, gpio_dir_pre)) {
479         mraa_result_t pre_ret = (dev->advance_func->gpio_dir_pre(dev, dir));
480         if (pre_ret != MRAA_SUCCESS) {
481             return pre_ret;
482         }
483     }
484
485     if (dev == NULL) {
486         return MRAA_ERROR_INVALID_HANDLE;
487     }
488     if (dev->value_fp != -1) {
489         close(dev->value_fp);
490         dev->value_fp = -1;
491     }
492     char filepath[MAX_SIZE];
493     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", dev->pin);
494
495     int direction = open(filepath, O_RDWR);
496
497     if (direction == -1) {
498         // Direction Failed to Open. If HIGH or LOW was passed will try and set
499         // If not fail as usual.
500         switch (dir) {
501             case MRAA_GPIO_OUT_HIGH:
502                 return mraa_gpio_write(dev, 1);
503             case MRAA_GPIO_OUT_LOW:
504                 return mraa_gpio_write(dev, 0);
505             default:
506                 return MRAA_ERROR_INVALID_RESOURCE;
507         }
508     }
509
510     char bu[MAX_SIZE];
511     int length;
512     switch (dir) {
513         case MRAA_GPIO_OUT:
514             length = snprintf(bu, sizeof(bu), "out");
515             break;
516         case MRAA_GPIO_IN:
517             length = snprintf(bu, sizeof(bu), "in");
518             break;
519         case MRAA_GPIO_OUT_HIGH:
520             length = snprintf(bu, sizeof(bu), "high");
521             break;
522         case MRAA_GPIO_OUT_LOW:
523             length = snprintf(bu, sizeof(bu), "low");
524             break;
525         default:
526             close(direction);
527             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
528     }
529
530     if (write(direction, bu, length * sizeof(char)) == -1) {
531         close(direction);
532         return MRAA_ERROR_INVALID_RESOURCE;
533     }
534
535     close(direction);
536     if (IS_FUNC_DEFINED(dev, gpio_dir_post))
537         return dev->advance_func->gpio_dir_post(dev, dir);
538     return MRAA_SUCCESS;
539 }
540
541 int
542 mraa_gpio_read(mraa_gpio_context dev)
543 {
544     if (dev == NULL)
545         return -1;
546
547     if (IS_FUNC_DEFINED(dev, gpio_read_replace))
548         return dev->advance_func->gpio_read_replace(dev);
549
550     if (dev->mmap_read != NULL)
551         return dev->mmap_read(dev);
552
553     if (dev->value_fp == -1) {
554         if (mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) {
555             syslog(LOG_ERR, "gpio: Failed to get value file pointer");
556             return -1;
557         }
558     } else {
559         // if value_fp is new this is pointless
560         lseek(dev->value_fp, 0, SEEK_SET);
561     }
562     char bu[2];
563     if (read(dev->value_fp, bu, 2 * sizeof(char)) != 2) {
564         syslog(LOG_ERR, "gpio: Failed to read a sensible value from sysfs");
565         return -1;
566     }
567     lseek(dev->value_fp, 0, SEEK_SET);
568
569     return (int) strtol(bu, NULL, 10);
570 }
571
572 mraa_result_t
573 mraa_gpio_write(mraa_gpio_context dev, int value)
574 {
575     if (dev == NULL)
576         return MRAA_ERROR_INVALID_HANDLE;
577
578     if (dev->mmap_write != NULL)
579         return dev->mmap_write(dev, value);
580
581     if (IS_FUNC_DEFINED(dev, gpio_write_pre)) {
582         mraa_result_t pre_ret = (dev->advance_func->gpio_write_pre(dev, value));
583         if (pre_ret != MRAA_SUCCESS)
584             return pre_ret;
585     }
586
587     if (IS_FUNC_DEFINED(dev, gpio_write_replace)) {
588         return dev->advance_func->gpio_write_replace(dev, value);
589     }
590
591     if (dev->value_fp == -1) {
592         if (mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) {
593             return MRAA_ERROR_INVALID_RESOURCE;
594         }
595     }
596
597     if (lseek(dev->value_fp, 0, SEEK_SET) == -1) {
598         return MRAA_ERROR_INVALID_RESOURCE;
599     }
600
601     char bu[MAX_SIZE];
602     int length = snprintf(bu, sizeof(bu), "%d", value);
603     if (write(dev->value_fp, bu, length * sizeof(char)) == -1) {
604         return MRAA_ERROR_INVALID_HANDLE;
605     }
606
607     if (IS_FUNC_DEFINED(dev, gpio_write_post))
608         return dev->advance_func->gpio_write_post(dev, value);
609     return MRAA_SUCCESS;
610 }
611
612 static mraa_result_t
613 mraa_gpio_unexport_force(mraa_gpio_context dev)
614 {
615     int unexport = open(SYSFS_CLASS_GPIO "/unexport", O_WRONLY);
616     if (unexport == -1) {
617         syslog(LOG_ERR, "gpio: Failed to open unexport for writing");
618         return MRAA_ERROR_INVALID_RESOURCE;
619     }
620
621     char bu[MAX_SIZE];
622     int length = snprintf(bu, sizeof(bu), "%d", dev->pin);
623     if (write(unexport, bu, length * sizeof(char)) == -1) {
624         syslog(LOG_ERR, "gpio: Failed to write to unexport");
625         close(unexport);
626         return MRAA_ERROR_INVALID_RESOURCE;
627     }
628
629     close(unexport);
630     mraa_gpio_isr_exit(dev);
631     return MRAA_SUCCESS;
632 }
633 static mraa_result_t
634 mraa_gpio_unexport(mraa_gpio_context dev)
635 {
636     if (dev->owner) {
637         return mraa_gpio_unexport_force(dev);
638     }
639     return MRAA_ERROR_INVALID_RESOURCE;
640 }
641
642 mraa_result_t
643 mraa_gpio_close(mraa_gpio_context dev)
644 {
645     mraa_result_t result = MRAA_SUCCESS;
646
647     if (IS_FUNC_DEFINED(dev, gpio_close_pre)) {
648         result = dev->advance_func->gpio_close_pre(dev);
649     }
650
651     if (dev->value_fp != -1) {
652         close(dev->value_fp);
653     }
654     mraa_gpio_unexport(dev);
655     free(dev);
656     return result;
657 }
658
659 mraa_result_t
660 mraa_gpio_owner(mraa_gpio_context dev, mraa_boolean_t own)
661 {
662     if (dev == NULL) {
663         return MRAA_ERROR_INVALID_RESOURCE;
664     }
665     syslog(LOG_DEBUG, "gpio: Set owner to %d", (int) own);
666     dev->owner = own;
667     return MRAA_SUCCESS;
668 }
669
670 mraa_result_t
671 mraa_gpio_use_mmaped(mraa_gpio_context dev, mraa_boolean_t mmap_en)
672 {
673     if (IS_FUNC_DEFINED(dev, gpio_mmap_setup)) {
674         return dev->advance_func->gpio_mmap_setup(dev, mmap_en);
675     }
676
677     syslog(LOG_ERR, "gpio: mmap not implemented on this platform");
678     return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
679 }
680
681 int
682 mraa_gpio_get_pin(mraa_gpio_context dev)
683 {
684     if (dev == NULL) {
685         syslog(LOG_ERR, "gpio: context is invalid");
686         return -1;
687     }
688     return dev->phy_pin;
689 }
690
691 int
692 mraa_gpio_get_pin_raw(mraa_gpio_context dev)
693 {
694     if (dev == NULL) {
695         syslog(LOG_ERR, "gpio: context is invalid");
696         return -1;
697     }
698     return dev->pin;
699 }