|
1 // Copyright (c) 2014 Adafruit Industries |
|
2 // Author: Tony DiCola |
|
3 // Based on code from Gert van Loo & Dom: http://elinux.org/RPi_Low-level_peripherals#GPIO_Code_examples |
|
4 |
|
5 // Permission is hereby granted, free of charge, to any person obtaining a copy |
|
6 // of this software and associated documentation files (the "Software"), to deal |
|
7 // in the Software without restriction, including without limitation the rights |
|
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
9 // copies of the Software, and to permit persons to whom the Software is |
|
10 // furnished to do so, subject to the following conditions: |
|
11 |
|
12 // The above copyright notice and this permission notice shall be included in all |
|
13 // copies or substantial portions of the Software. |
|
14 |
|
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
21 // SOFTWARE. |
|
22 #include <fcntl.h> |
|
23 #include <stdlib.h> |
|
24 #include <stdio.h> |
|
25 #include <string.h> |
|
26 #include <sys/mman.h> |
|
27 #include <sys/stat.h> |
|
28 #include <sys/types.h> |
|
29 #include <unistd.h> |
|
30 |
|
31 #include "pi_2_mmio.h" |
|
32 |
|
33 #define GPIO_BASE_OFFSET 0x200000 |
|
34 #define GPIO_LENGTH 4096 |
|
35 |
|
36 volatile uint32_t* pi_2_mmio_gpio = NULL; |
|
37 |
|
38 int pi_2_mmio_init(void) { |
|
39 if (pi_2_mmio_gpio == NULL) { |
|
40 // Check for GPIO and peripheral addresses from device tree. |
|
41 // Adapted from code in the RPi.GPIO library at: |
|
42 // http://sourceforge.net/p/raspberry-gpio-python/ |
|
43 FILE *fp = fopen("/proc/device-tree/soc/ranges", "rb"); |
|
44 if (fp == NULL) { |
|
45 return MMIO_ERROR_OFFSET; |
|
46 } |
|
47 fseek(fp, 4, SEEK_SET); |
|
48 unsigned char buf[4]; |
|
49 if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) { |
|
50 return MMIO_ERROR_OFFSET; |
|
51 } |
|
52 uint32_t peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0; |
|
53 uint32_t gpio_base = peri_base + GPIO_BASE_OFFSET; |
|
54 fclose(fp); |
|
55 |
|
56 int fd = open("/dev/mem", O_RDWR | O_SYNC); |
|
57 if (fd == -1) { |
|
58 // Error opening /dev/mem. Probably not running as root. |
|
59 return MMIO_ERROR_DEVMEM; |
|
60 } |
|
61 // Map GPIO memory to location in process space. |
|
62 pi_2_mmio_gpio = (uint32_t*)mmap(NULL, GPIO_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, gpio_base); |
|
63 close(fd); |
|
64 if (pi_2_mmio_gpio == MAP_FAILED) { |
|
65 // Don't save the result if the memory mapping failed. |
|
66 pi_2_mmio_gpio = NULL; |
|
67 return MMIO_ERROR_MMAP; |
|
68 } |
|
69 } |
|
70 return MMIO_SUCCESS; |
|
71 } |