gpio: move gpio setup from core into module
[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 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 mraa_gpio_context
56 mraa_gpio_init(int pin)
57 {
58     if (plat == NULL) {
59         syslog(LOG_ERR, "gpio: platform not initialised");
60         return NULL;
61     }
62     if (pin < 0 || pin > plat->phy_pin_count) {
63         syslog(LOG_ERR, "gpio: pin %i beyond platform definition", pin);
64         return NULL;
65     }
66     if (plat->pins[pin].capabilites.gpio != 1) {
67         syslog(LOG_ERR, "gpio: pin %i not capable of gpio", pin);
68         return NULL;
69     }
70     if (plat->pins[pin].gpio.mux_total > 0) {
71         if (mraa_setup_mux_mapped(plat->pins[pin].gpio) != MRAA_SUCCESS) {
72             syslog(LOG_ERR, "gpio: unable to setup muxes");
73             return NULL;
74         }
75     }
76
77     mraa_gpio_context r = mraa_gpio_init_raw(plat->pins[pin].gpio.pinmap);
78     r->phy_pin = pin;
79
80     if (advance_func->gpio_init_post != NULL) {
81         mraa_result_t ret = advance_func->gpio_init_post(r);
82         if (ret != MRAA_SUCCESS) {
83             free(r);
84             return NULL;
85         }
86     }
87     return r;
88 }
89
90 mraa_gpio_context
91 mraa_gpio_init_raw(int pin)
92 {
93     if (advance_func->gpio_init_pre != NULL) {
94         if (advance_func->gpio_init_pre(pin) != MRAA_SUCCESS)
95             return NULL;
96     }
97
98     if (pin < 0)
99         return NULL;
100
101     char bu[MAX_SIZE];
102     int length;
103
104     mraa_gpio_context dev = (mraa_gpio_context) malloc(sizeof(struct _gpio));
105     if (dev == NULL) {
106         syslog(LOG_CRIT, "gpio: Failed to allocate memory for context");
107         return NULL;
108     }
109
110     memset(dev, 0, sizeof(struct _gpio));
111     dev->value_fp = -1;
112     dev->isr_value_fp = -1;
113     dev->pin = pin;
114     dev->phy_pin = -1;
115
116     char directory[MAX_SIZE];
117     snprintf(directory, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/", dev->pin);
118     struct stat dir;
119     if (stat(directory, &dir) == 0 && S_ISDIR(dir.st_mode)) {
120         dev->owner = 0; // Not Owner
121     } else {
122         int export = open(SYSFS_CLASS_GPIO "/export", O_WRONLY);
123         if (export == -1) {
124             syslog(LOG_ERR, "gpio: Failed to open export for writing");
125             free(dev);
126             return NULL;
127         }
128         length = snprintf(bu, sizeof(bu), "%d", dev->pin);
129         if (write(export, bu, length*sizeof(char)) == -1) {
130             syslog(LOG_ERR, "gpio: Failed to write to export");
131             close(export);
132             return NULL;
133         }
134         dev->owner = 1;
135         close(export);
136     }
137
138     return dev;
139 }
140
141 static mraa_result_t
142 mraa_gpio_write_register(mraa_gpio_context dev,int value)
143 {
144     if (advance_func->gpio_mmaped_write_replace != NULL)
145         return advance_func->gpio_mmaped_write_replace(dev,value);
146     if (advance_func->gpio_mmaped_write_pre != NULL) {
147         mraa_result_t pre_ret = (advance_func->gpio_mmaped_write_pre(dev,value));
148         if(pre_ret != MRAA_SUCCESS)
149             return pre_ret;
150     }
151     if (value == 1) {
152         *((unsigned *)dev->reg) |= (1<<dev->reg_bit_pos);
153         return MRAA_SUCCESS;
154     }
155     *((unsigned *)dev->reg) &= ~(1<<dev->reg_bit_pos);
156
157     if (advance_func->gpio_mmaped_write_post != NULL)
158         return advance_func->gpio_mmaped_write_post(dev,value);
159     return MRAA_SUCCESS;
160 }
161
162 static mraa_result_t
163 mraa_gpio_wait_interrupt(int fd)
164 {
165     unsigned char c;
166     struct pollfd pfd;
167
168     // setup poll on POLLPRI
169     pfd.fd = fd;
170     pfd.events = POLLPRI;
171
172     // do an initial read to clear interupt
173     read (fd, &c, 1);
174
175     if (fd <= 0) {
176         return MRAA_ERROR_INVALID_RESOURCE;
177     }
178
179     // Wait for it forever or until pthread_cancel
180     // poll is a cancelable point like sleep()
181     int x = poll (&pfd, 1, -1);
182
183     // do a final read to clear interupt
184     read (fd, &c, 1);
185
186     return MRAA_SUCCESS;
187 }
188
189 static void*
190 mraa_gpio_interrupt_handler(void* arg)
191 {
192     mraa_gpio_context dev = (mraa_gpio_context) arg;
193     mraa_result_t ret;
194
195     // open gpio value with open(3)
196     char bu[MAX_SIZE];
197     sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin);
198     dev->isr_value_fp = open(bu, O_RDONLY);
199
200     for (;;) {
201         ret = mraa_gpio_wait_interrupt(dev->isr_value_fp);
202         if (ret == MRAA_SUCCESS) {
203             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
204 #ifdef SWIGPYTHON
205             // In order to call a python object (all python functions are objects) we
206             // need to aquire the GIL (Global Interpreter Lock). This may not always be
207             // nessecary but especially if doing IO (like print()) python will segfault
208             // if we do not hold a lock on the GIL
209             PyGILState_STATE gilstate = PyGILState_Ensure();
210             PyObject *arglist;
211             PyObject *ret;
212             arglist = Py_BuildValue("(i)", dev->isr_args);
213             if (arglist == NULL) {
214                 syslog(LOG_ERR, "gpio: Py_BuildValue NULL");
215             } else {
216                 ret = PyEval_CallObject((PyObject*)dev->isr, arglist);
217                 if (ret == NULL) {
218                     syslog(LOG_ERR, "gpio: PyEval_CallObject failed");
219                 } else {
220                     Py_DECREF(ret);
221                 }
222                 Py_DECREF(arglist);
223             }
224
225             PyGILState_Release (gilstate);
226 #else
227             dev->isr(dev->isr_args);
228 #endif
229             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
230         } else {
231         // we must have got an error code so die nicely
232             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
233             close(dev->isr_value_fp);
234             dev->isr_value_fp = -1;
235             return NULL;
236         }
237     }
238 }
239
240 mraa_result_t
241 mraa_gpio_edge_mode(mraa_gpio_context dev, gpio_edge_t mode)
242 {
243     if (dev->value_fp != -1) {
244          close(dev->value_fp);
245          dev->value_fp = -1;
246     }
247
248     char filepath[MAX_SIZE];
249     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/edge", dev->pin);
250
251     int edge = open(filepath, O_RDWR);
252     if (edge == -1) {
253         syslog(LOG_ERR, "gpio: Failed to open edge for writing");
254         return MRAA_ERROR_INVALID_RESOURCE;
255     }
256
257     char bu[MAX_SIZE];
258     int length;
259     switch(mode) {
260         case MRAA_GPIO_EDGE_NONE:
261             length = snprintf(bu, sizeof(bu), "none");
262             break;
263         case MRAA_GPIO_EDGE_BOTH:
264             length = snprintf(bu, sizeof(bu), "both");
265             break;
266         case MRAA_GPIO_EDGE_RISING:
267             length = snprintf(bu, sizeof(bu), "rising");
268             break;
269         case MRAA_GPIO_EDGE_FALLING:
270             length = snprintf(bu, sizeof(bu), "falling");
271             break;
272         default:
273             close(edge);
274             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
275     }
276     if (write(edge, bu, length*sizeof(char)) == -1) {
277         syslog(LOG_ERR, "gpio: Failed to write to edge");
278         close(edge);
279         return MRAA_ERROR_INVALID_RESOURCE;
280     }
281
282     close(edge);
283     return MRAA_SUCCESS;
284 }
285
286 mraa_result_t
287 mraa_gpio_isr(mraa_gpio_context dev, gpio_edge_t mode, void (*fptr)(void *), void * args)
288 {
289     // we only allow one isr per mraa_gpio_context
290     if (dev->thread_id != 0) {
291         return MRAA_ERROR_NO_RESOURCES;
292     }
293
294     if (MRAA_SUCCESS != mraa_gpio_edge_mode(dev, mode)) {
295         return MRAA_ERROR_UNSPECIFIED;
296     }
297
298     dev->isr = fptr;
299     dev->isr_args = args;
300     pthread_create (&dev->thread_id, NULL, mraa_gpio_interrupt_handler, (void *) dev);
301
302     return MRAA_SUCCESS;
303 }
304
305 mraa_result_t
306 mraa_gpio_isr_exit(mraa_gpio_context dev)
307 {
308     mraa_result_t ret = MRAA_SUCCESS;
309
310     // wasting our time, there is no isr to exit from
311     if (dev->thread_id == 0 && dev->isr_value_fp == -1) {
312         return ret;
313     }
314
315     // stop isr being useful
316     ret = mraa_gpio_edge_mode(dev, MRAA_GPIO_EDGE_NONE);
317
318     if ((dev->thread_id != 0)) {
319         if ((pthread_cancel(dev->thread_id) != 0) || (pthread_join(dev->thread_id, NULL) != 0)) {
320             ret = MRAA_ERROR_INVALID_HANDLE;
321         }
322     }
323
324     // close the filehandle in case it's still open
325     if (dev->isr_value_fp != -1) {
326           if (close(dev->isr_value_fp) != 0) {
327               ret = MRAA_ERROR_INVALID_PARAMETER;
328           }
329     }
330
331 #ifdef SWIGPYTHON
332     // Dereference our Python call back function
333     Py_DECREF(dev->isr);
334 #endif
335
336     // assume our thread will exit either way we just lost it's handle
337     dev->thread_id = 0;
338     dev->isr_value_fp = -1;
339     return ret;
340 }
341
342 mraa_result_t
343 mraa_gpio_mode(mraa_gpio_context dev, gpio_mode_t mode)
344 {
345     if (advance_func->gpio_mode_replace != NULL)
346         return advance_func->gpio_mode_replace(dev,mode);
347
348     if (advance_func->gpio_mode_pre != NULL) {
349         mraa_result_t pre_ret = (advance_func->gpio_mode_pre(dev,mode));
350         if(pre_ret != MRAA_SUCCESS)
351             return pre_ret;
352     }
353
354     if (dev->value_fp != -1) {
355          close(dev->value_fp);
356          dev->value_fp = -1;
357     }
358
359     char filepath[MAX_SIZE];
360     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/drive", dev->pin);
361
362     int drive = open(filepath, O_WRONLY);
363     if (drive == -1) {
364         syslog(LOG_ERR, "gpio: Failed to open drive for writing");
365         return MRAA_ERROR_INVALID_RESOURCE;
366     }
367
368     char bu[MAX_SIZE];
369     int length;
370     switch(mode) {
371         case MRAA_GPIO_STRONG:
372             length = snprintf(bu, sizeof(bu), "strong");
373             break;
374         case MRAA_GPIO_PULLUP:
375             length = snprintf(bu, sizeof(bu), "pullup");
376             break;
377         case MRAA_GPIO_PULLDOWN:
378             length = snprintf(bu, sizeof(bu), "pulldown");
379             break;
380         case MRAA_GPIO_HIZ:
381             length = snprintf(bu, sizeof(bu), "hiz");
382             break;
383         default:
384             close(drive);
385             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
386     }
387     if (write(drive, bu, length*sizeof(char)) == -1) {
388         syslog(LOG_ERR, "gpio: Failed to write to drive mode");
389         close(drive);
390         return MRAA_ERROR_INVALID_RESOURCE;
391
392     }
393
394     close(drive);
395     if (advance_func->gpio_mode_post != NULL)
396         return advance_func->gpio_mode_post(dev,mode);
397     return MRAA_SUCCESS;
398 }
399
400 mraa_result_t
401 mraa_gpio_dir(mraa_gpio_context dev, gpio_dir_t dir)
402 {
403     if (advance_func->gpio_dir_replace != NULL)
404         return advance_func->gpio_dir_replace(dev,dir);
405     if (advance_func->gpio_dir_pre != NULL) {
406         mraa_result_t pre_ret = (advance_func->gpio_dir_pre(dev,dir));
407         if(pre_ret != MRAA_SUCCESS)
408             return pre_ret;
409     }
410
411     if (dev == NULL) {
412         return MRAA_ERROR_INVALID_HANDLE;
413     }
414     if (dev->value_fp != -1) {
415          close(dev->value_fp);
416          dev->value_fp = -1;
417     }
418     char filepath[MAX_SIZE];
419     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", dev->pin);
420
421     int direction = open(filepath, O_RDWR);
422
423     if (direction == -1) {
424         return MRAA_ERROR_INVALID_RESOURCE;
425     }
426
427     char bu[MAX_SIZE];
428     int length;
429     switch(dir) {
430         case MRAA_GPIO_OUT:
431             length = snprintf(bu, sizeof(bu), "out");
432             break;
433         case MRAA_GPIO_IN:
434             length = snprintf(bu, sizeof(bu), "in");
435             break;
436         default:
437             close(direction);
438             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
439     }
440
441     if (write(direction, bu, length*sizeof(char)) == -1) {
442         close(direction);
443         return MRAA_ERROR_INVALID_RESOURCE;
444     }
445
446     close(direction);
447     if (advance_func->gpio_dir_post != NULL)
448         return advance_func->gpio_dir_post(dev,dir);
449     return MRAA_SUCCESS;
450 }
451
452 int
453 mraa_gpio_read(mraa_gpio_context dev)
454 {
455     if (dev == NULL)
456         return -1;
457
458     if (dev->value_fp == -1) {
459         if (mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) {
460              syslog(LOG_ERR, "gpio: Failed to get value file pointer");
461         }
462     }
463     else {
464         // if value_fp is new this is pointless
465         lseek(dev->value_fp, 0, SEEK_SET);
466     }
467     char bu[2];
468     if (read(dev->value_fp, bu, 2*sizeof(char)) != 2) {
469         syslog(LOG_ERR, "gpio: Failed to read a sensible value from sysfs");
470         return -1;
471     }
472     lseek(dev->value_fp, 0, SEEK_SET);
473
474     return strtol(bu, NULL, 10);
475 }
476
477 mraa_result_t
478 mraa_gpio_write(mraa_gpio_context dev, int value)
479 {
480     if (dev == NULL)
481         return MRAA_ERROR_INVALID_HANDLE;
482
483     if (dev->mmap == 1)
484         return mraa_gpio_write_register(dev,value);
485
486     if (advance_func->gpio_write_pre != NULL) {
487         mraa_result_t pre_ret = (advance_func->gpio_write_pre(dev,value));
488         if(pre_ret != MRAA_SUCCESS)
489             return pre_ret;
490     }
491
492     if (dev->value_fp == -1) {
493         mraa_gpio_get_valfp(dev);
494     }
495     if (lseek(dev->value_fp, 0, SEEK_SET) == -1) {
496         return MRAA_ERROR_INVALID_RESOURCE;
497     }
498
499     char bu[MAX_SIZE];
500     int length = snprintf(bu, sizeof(bu), "%d", value);
501     if (write(dev->value_fp, bu, length*sizeof(char)) == -1) {
502         return MRAA_ERROR_INVALID_HANDLE;
503     }
504
505     if (advance_func->gpio_write_post != NULL)
506         return advance_func->gpio_write_post(dev,value);
507     return MRAA_SUCCESS;
508 }
509
510 static mraa_result_t
511 mraa_gpio_unexport_force(mraa_gpio_context dev)
512 {
513     int unexport = open(SYSFS_CLASS_GPIO "/unexport", O_WRONLY);
514     if (unexport == -1) {
515         syslog(LOG_ERR, "gpio: Failed to open unexport for writing");
516         return MRAA_ERROR_INVALID_RESOURCE;
517     }
518
519     char bu[MAX_SIZE];
520     int length = snprintf(bu, sizeof(bu), "%d", dev->pin);
521     if (write(unexport, bu, length*sizeof(char)) == -1) {
522         syslog(LOG_ERR, "gpio: Failed to write to unexport");
523         close(unexport);
524         return MRAA_ERROR_INVALID_RESOURCE;
525     }
526
527     close(unexport);
528     mraa_gpio_isr_exit(dev);
529     return MRAA_SUCCESS;
530 }
531 static mraa_result_t
532 mraa_gpio_unexport(mraa_gpio_context dev)
533 {
534     if(dev->owner) {
535         return mraa_gpio_unexport_force(dev);
536     }
537     return MRAA_ERROR_INVALID_RESOURCE;
538 }
539
540 mraa_result_t
541 mraa_gpio_close(mraa_gpio_context dev)
542 {
543     if (dev->value_fp != -1) {
544         close(dev->value_fp);
545     }
546     mraa_gpio_unexport(dev);
547     free(dev);
548     return MRAA_SUCCESS;
549 }
550
551 mraa_result_t
552 mraa_gpio_owner(mraa_gpio_context dev, mraa_boolean_t own)
553 {
554     if (dev == NULL)
555         return MRAA_ERROR_INVALID_RESOURCE;
556     dev->owner = own;
557     return MRAA_SUCCESS;
558 }
559
560 mraa_result_t
561 mraa_gpio_use_mmaped(mraa_gpio_context dev, mraa_boolean_t mmap_en)
562 {
563     if (dev ==  NULL) {
564         return MRAA_ERROR_INVALID_RESOURCE;
565     }
566
567     if (mraa_pin_mode_test(dev->phy_pin, MRAA_PIN_FAST_GPIO) == 0)
568         return MRAA_ERROR_NO_RESOURCES;
569
570     mraa_mmap_pin_t *mmp = mraa_setup_mmap_gpio(dev->phy_pin);
571     if (mmp == NULL)
572         return MRAA_ERROR_INVALID_RESOURCE;
573
574     if (mmap_en == 1) {
575         if (dev->mmap == 0) {
576             close(dev->value_fp);
577             int fd;
578             fd = open(mmp->mem_dev, O_RDWR);
579             if (fd < 1) {
580                 syslog(LOG_ERR, "gpio: Unable to open memory device");
581                 close(fd);
582                 return MRAA_ERROR_INVALID_RESOURCE;
583             }
584             dev->reg_sz = mmp->mem_sz;
585             dev->reg = mmap(NULL, dev->reg_sz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
586             dev->reg_bit_pos = mmp->bit_pos;
587             dev->mmap = 1;
588             close(fd);
589             return MRAA_SUCCESS;
590         }
591         return MRAA_ERROR_INVALID_PARAMETER;
592     }
593
594     if (mmap_en == 0) {
595         if (dev ->mmap == 1) {
596             munmap(dev->reg, dev->reg_sz);
597             dev->mmap = 0;
598         }
599         return MRAA_ERROR_INVALID_PARAMETER;
600     }
601
602     return MRAA_SUCCESS;
603 }