edison: add mmap support. read & write
authorThomas Ingleby <thomas.c.ingleby@intel.com>
Wed, 12 Nov 2014 16:33:56 +0000 (16:33 +0000)
committerThomas Ingleby <thomas.c.ingleby@intel.com>
Mon, 17 Nov 2014 17:45:46 +0000 (17:45 +0000)
Closes #27

Signed-off-by: Thomas Ingleby <thomas.c.ingleby@intel.com>
src/intel_edison_fab_c.c

index f9dec4d..0070447 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
 
 #include "common.h"
 #include "intel_edison_fab_c.h"
 #define MAX_SIZE 64
 #define MAX_MODE_SIZE 8
 
+// This is an absolute path to a resource file found within sysfs.
+// Might not always be correct. First thing to check if mmap stops
+// working. Check the device for 0x1199 and Intel Vendor (0x8086)
+#define MMAP_PATH "/sys/devices/pci0000:00/0000:00:0c.0/resource0"
+
 typedef struct {
     int sysfs;
     int mode;
@@ -53,6 +60,12 @@ static unsigned int outputen[] = {248,249,250,251,252,253,254,255,256,257,258,25
 static unsigned int pullup_map[] = {216,217,218,219,220,221,222,223,224,225,226,227,228,229,208,209,210,211,212,213};
 static int miniboard = 0;
 
+//MMAP
+static uint8_t *mmap_reg = NULL;
+static int mmap_fd = 0;
+static int mmap_size;
+static unsigned int mmap_count = 0;
+
 static mraa_result_t
 mraa_intel_edison_pinmode_change(int sysfs, int mode)
 {
@@ -486,6 +499,108 @@ mraa_intel_edison_uart_init_post(mraa_uart_context uart)
     return mraa_gpio_write(tristate, 1);
 }
 
+static mraa_result_t
+mraa_intel_edsion_mmap_unsetup()
+{
+    if (mmap_reg == NULL) {
+        syslog(LOG_ERR, "edison mmap: null register cant unsetup");
+        return MRAA_ERROR_INVALID_RESOURCE;
+    }
+    munmap(mmap_reg, mmap_size);
+    mmap_reg == NULL;
+    close(mmap_fd);
+    return MRAA_SUCCESS;
+}
+
+mraa_result_t
+mraa_intel_edison_mmap_write(mraa_gpio_context dev, int value)
+{
+    uint8_t offset = ((dev->pin / 32) * sizeof(uint32_t));
+    uint8_t valoff;
+
+    if (value) {
+        valoff = 0x34;
+    } else {
+        valoff = 0x4c;
+    }
+
+    *(volatile uint32_t*) (mmap_reg + offset + valoff) =
+        (uint32_t)(1 << (dev->pin % 32));
+
+    return MRAA_SUCCESS;
+}
+
+int
+mraa_intel_edison_mmap_read(mraa_gpio_context dev)
+{
+    uint8_t offset = ((dev->pin / 32) * sizeof(uint32_t));
+    uint32_t value;
+
+    value = *(volatile uint32_t*) (mmap_reg +0x04+ offset);
+    if (value&(uint32_t)(1 << (dev->pin % 32)))
+        return 1;
+    return 0;
+}
+
+mraa_result_t
+mraa_intel_edison_mmap_setup(mraa_gpio_context dev, mraa_boolean_t en)
+{
+    if (dev == NULL) {
+        syslog(LOG_ERR, "edison mmap: context not valid");
+        return MRAA_ERROR_INVALID_HANDLE;
+    }
+
+    if (en == 0) {
+        if (dev->mmap_write == NULL && dev->mmap_read == NULL) {
+            syslog(LOG_ERR, "edison mmap: can't disable disabled mmap gpio");
+            return MRAA_ERROR_INVALID_PARAMETER;
+        }
+        dev->mmap_write = NULL;
+        dev->mmap_read = NULL;
+        mmap_count--;
+        if (mmap_count == 0) {
+            return mraa_intel_edsion_mmap_unsetup();
+        }
+        return MRAA_SUCCESS;
+    }
+
+    if (dev->mmap_write != NULL && dev->mmap_read != NULL) {
+        syslog(LOG_ERR, "edison mmap: can't enable enabled mmap gpio");
+        return MRAA_ERROR_INVALID_PARAMETER;
+    }
+
+    //Might need to make some elements of this thread safe.
+    //For example only allow one thread to enter the following block
+    //to prevent mmap'ing twice.
+    if (mmap_reg == NULL) {
+        if ((mmap_fd = open(MMAP_PATH, O_RDWR)) < 0) {
+            syslog(LOG_ERR, "edison map: unable to open resource0 file");
+            return MRAA_ERROR_INVALID_HANDLE;
+        }
+
+        struct stat fd_stat;
+        fstat(mmap_fd, &fd_stat);
+        mmap_size = fd_stat.st_size;
+
+        mmap_reg = (uint8_t*) mmap(NULL, fd_stat.st_size,
+                                   PROT_READ | PROT_WRITE,
+                                   MAP_FILE | MAP_SHARED,
+                                   mmap_fd, 0);
+        if (mmap_reg == MAP_FAILED) {
+            syslog(LOG_ERR, "edison mmap: failed to mmap");
+            mmap_reg = NULL;
+            close(mmap_fd);
+            return MRAA_ERROR_NO_RESOURCES;
+        }
+    }
+    dev->mmap_write = &mraa_intel_edison_mmap_write;
+    dev->mmap_read = &mraa_intel_edison_mmap_read;
+    mmap_count++;
+
+
+    return MRAA_SUCCESS;
+}
+
 mraa_result_t
 mraa_intel_edsion_miniboard(mraa_board_t* b)
 {
@@ -506,6 +621,7 @@ mraa_intel_edsion_miniboard(mraa_board_t* b)
     advance_func->spi_init_pre = &mraa_intel_edison_spi_init_pre;
     advance_func->gpio_mode_replace = &mraa_intel_edsion_mb_gpio_mode;
     advance_func->uart_init_post = &mraa_intel_edison_uart_init_post;
+    advance_func->gpio_mmap_setup = &mraa_intel_edison_mmap_setup;
 
     int pos = 0;
     strncpy(b->pins[pos].name, "J17-1", 8);
@@ -886,6 +1002,7 @@ mraa_intel_edison_fab_c()
     advance_func->gpio_mode_replace = &mraa_intel_edison_gpio_mode_replace;
     advance_func->uart_init_pre = &mraa_intel_edison_uart_init_pre;
     advance_func->uart_init_post = &mraa_intel_edison_uart_init_post;
+    advance_func->gpio_mmap_setup = &mraa_intel_edison_mmap_setup;
 
     b->pins = (mraa_pininfo_t*) malloc(sizeof(mraa_pininfo_t)*MRAA_INTEL_EDISON_PINCOUNT);