]> Zhao Yanbai Git Server - minix.git/commitdiff
gpio:Initial GPIO driver.(ARM) 67/267/3
authorKees Jongenburger <keesj@minix3.org>
Mon, 28 Jan 2013 11:54:44 +0000 (12:54 +0100)
committerKees Jongenburger <keesj@minix3.org>
Mon, 28 Jan 2013 14:51:20 +0000 (15:51 +0100)
Small GPIO driver that exports a few pins using a virtual file
system. Currently the two user leds and the user button are exported.

Change-Id: I001d017ae27cd17b635587873f7da981054da459

13 files changed:
distrib/sets/lists/minix/md.evbarm
drivers/Makefile
drivers/gpio/Makefile [new file with mode: 0644]
drivers/gpio/README.txt [new file with mode: 0644]
drivers/gpio/gpio.c [new file with mode: 0644]
drivers/gpio/gpio.h [new file with mode: 0644]
drivers/gpio/gpio_omap.c [new file with mode: 0644]
drivers/gpio/log.h [new file with mode: 0644]
drivers/gpio/mmio.h [new file with mode: 0644]
drivers/ramdisk/Makefile
drivers/ramdisk/proto.arm.small
drivers/ramdisk/rc.arm
etc/system.conf

index 85c5eecbe9666210a585616c6a5112ef8a51572d..cebc658bafee12249962f42a7cc6891fd1ebc6b6 100644 (file)
@@ -90,4 +90,5 @@
 ./usr/include/evbarm/vmparam.h         minix-sys
 ./usr/include/evbarm/wchar_limits.h    minix-sys
 ./usr/include/i386                     minix-sys       obsolete
+./usr/sbin/gpio                                minix-sys
 ./usr/mdec                             minix-sys
index da5efe001819f4a095bc275f823b3a7c845def1c..37398ac6db21f4d46126b7718ed0f024ecc1b4b3 100644 (file)
@@ -23,7 +23,7 @@ SUBDIR= ahci amddev atl2 at_wini audio dec21140A dp8390 dpeth \
 .endif
 
 .if ${MACHINE_ARCH} == "earm"
-SUBDIR=  mmc log tty
+SUBDIR=  gpio mmc log tty
 .endif
 
 .endif # ${MKIMAGEONLY} != "yes"
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
new file mode 100644 (file)
index 0000000..a7f87f5
--- /dev/null
@@ -0,0 +1,16 @@
+# Makefile for the gpio driver.
+PROG=  gpio
+SRCS=  gpio.c gpio_omap.c
+
+DPADD+=        ${LIBBLOCKDRIVER} ${LIBSYS}
+LDADD+=        -lvtreefs -lsys
+
+#
+# This is a system driver.
+CPPFLAGS+= -D_SYSTEM=1
+
+MAN=
+
+BINDIR?= /usr/sbin
+
+.include <minix.service.mk>
diff --git a/drivers/gpio/README.txt b/drivers/gpio/README.txt
new file mode 100644 (file)
index 0000000..338dc7c
--- /dev/null
@@ -0,0 +1,35 @@
+General Purpose Input and Output
+
+To make MINIX more usable on embedded hardware we need some way to access the
+GPIO features of the system on chip’s. Generally System on Chips (SoC) designs
+provide some way configure pads to perform basic Input/Output configuration on
+selected ports. These ports are also usually grouped into a bank. The end
+result is that you have a functional general input output block where you need
+to configure some the following functions.
+
+Functional requirements
+
+We envision that the short term usage of the GPIO library will be booth input
+and output handling. Input handling as we want to be able to listen to button
+presses and genrate key events and output handling because we want to be able
+to control leds.
+
+GPIO required functionality
+-Configure pins as input or output.
+-Configure the impedance of the pins.
+-Get or set the values of the pins(possibly in a single call).
+-Configure interrupt levels for input pins.
+
+Configure debouncing of pins.
+
+Additional kernel requirements
+-Manage the GPIO resources (who may access what)
+-Access the GPIO pins from within driver (for the keyboard)
+-Access the GPIO pins from within userland (for toggeling leds)
+
+
+Usage: 
+You have to manualy mount the gpio fs using the following command
+
+# mount -t gpio none /gpio
+
diff --git a/drivers/gpio/gpio.c b/drivers/gpio/gpio.c
new file mode 100644 (file)
index 0000000..724b266
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * GPIO driver. This driver acts as a file system to allow
+ * reading and toggling of GPIO's.
+ */
+/* kernel headers */
+#include <minix/driver.h>
+#include <minix/drvlib.h>
+#include <minix/vtreefs.h>
+
+/* system headers */
+#include <sys/stat.h>
+#include <sys/queue.h>
+
+/* usr headers */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+
+/* local headers */
+#include "log.h"
+#include "mmio.h"
+#include "gpio.h"
+
+/* used for logging */
+static struct log log = {
+       .name = "gpio",
+       .log_level = LEVEL_INFO,
+       .log_func = default_log
+};
+
+#define GPIO_CB_READ 0
+#define GPIO_CB_ON 1
+#define GPIO_CB_OFF 2
+
+/* The vtreefs library provides callback data when calling
+ * the read function of inode. gpio_cbdata is used here to
+ * map between inodes and gpio's. VTreeFS is read-only. to work
+ * around that issue for a single GPIO we create multiple virtual
+ * files that can be *read* to read the gpio value and power on
+ * and off the gpio.
+ */
+struct gpio_cbdata
+{
+       struct gpio *gpio;      /* obtained from the driver */
+       int type;               /* read=0/on=1/off=2 */
+           TAILQ_ENTRY(gpio_cbdata) next;
+};
+
+/* list of inodes used in this driver */
+TAILQ_HEAD(gpio_cbdata_head, gpio_cbdata)
+    gpio_cbdata_list = TAILQ_HEAD_INITIALIZER(gpio_cbdata_list);
+
+static struct gpio_driver drv;
+
+/* Sane file stats for a directory */
+static struct inode_stat default_file_stat = {
+       .mode = S_IFREG | 04,
+       .uid = 0,
+       .gid = 0,
+       .size = 0,
+       .dev = NO_DEV,
+};
+
+int
+add_gpio_inode(char *name, int nr, int mode)
+{
+       /* Create 2 files nodes for "name" "nameon" and "nameoff" to read and
+        * set values as we don't support writing yet */
+       char tmpname[200];
+       struct gpio_cbdata *cb;
+       struct gpio *gpio;
+
+       /* claim and configure the gpio */
+       if (drv.claim("gpiofs", nr, &gpio)) {
+               log_warn(&log, "Failed to claim GPIO %d\n", nr);
+               return EIO;
+       }
+       assert(gpio != NULL);
+
+       if (drv.pin_mode(gpio, mode)) {
+               log_warn(&log, "Failed to switch GPIO %d to mode %d\n", nr,
+                   mode);
+               return EIO;
+       }
+
+       /* read value */
+       cb = malloc(sizeof(struct gpio_cbdata));
+       if (cb == NULL) {
+               return ENOMEM;
+       }
+       memset(cb, 0, sizeof(*cb));
+
+       cb->type = GPIO_CB_READ;
+       cb->gpio = gpio;
+
+       snprintf(tmpname, 200, "%s", name);
+       add_inode(get_root_inode(), tmpname, NO_INDEX, &default_file_stat, 0,
+           (cbdata_t) cb);
+       TAILQ_INSERT_HEAD(&gpio_cbdata_list, cb, next);
+
+       if (mode == GPIO_MODE_OUTPUT) {
+               /* if we configured the GPIO pin as output mode also create
+                * two additional files to turn on and off the GPIO. */
+               /* turn on */
+               cb = malloc(sizeof(struct gpio_cbdata));
+               if (cb == NULL) {
+                       return ENOMEM;
+               }
+               memset(cb, 0, sizeof(*cb));
+
+               cb->type = GPIO_CB_ON;
+               cb->gpio = gpio;
+
+               snprintf(tmpname, 200, "%son", name);
+               add_inode(get_root_inode(), tmpname, NO_INDEX,
+                   &default_file_stat, 0, (cbdata_t) cb);
+               TAILQ_INSERT_HEAD(&gpio_cbdata_list, cb, next);
+
+               /* turn off */
+               cb = malloc(sizeof(struct gpio_cbdata));
+               if (cb == NULL) {
+                       return ENOMEM;
+               }
+               memset(cb, 0, sizeof(*cb));
+
+               cb->type = GPIO_CB_OFF;
+               cb->gpio = gpio;
+
+               snprintf(tmpname, 200, "%soff", name);
+               add_inode(get_root_inode(), tmpname, NO_INDEX,
+                   &default_file_stat, 0, (cbdata_t) cb);
+               TAILQ_INSERT_HEAD(&gpio_cbdata_list, cb, next);
+       }
+       return OK;
+}
+
+static void
+init_hook(void)
+{
+       /* This hook will be called once, after VTreeFS has initialized. */
+       if (omap_gpio_init(&drv)) {
+               log_warn(&log, "Failed to init gpio driver\n");
+       }
+       add_gpio_inode("USR0", 149, GPIO_MODE_OUTPUT);
+       add_gpio_inode("USR1", 150, GPIO_MODE_OUTPUT);
+       add_gpio_inode("Button", 4, GPIO_MODE_INPUT);
+
+#if 0
+       add_gpio_inode("input1", 139, GPIO_MODE_INPUT);
+       add_gpio_inode("input2", 144, GPIO_MODE_INPUT);
+#endif
+}
+
+static int
+    read_hook
+    (struct inode *inode, off_t offset, char **ptr, size_t * len,
+    cbdata_t cbdata)
+{
+       /* This hook will be called every time a regular file is read. We use
+        * it to dyanmically generate the contents of our file. */
+       static char data[26];
+       int value;
+       struct gpio_cbdata *gpio_cbdata = (struct gpio_cbdata *) cbdata;
+       assert(gpio_cbdata->gpio != NULL);
+
+       if (gpio_cbdata->type == GPIO_CB_ON) {
+               /* turn on */
+               if (drv.set(gpio_cbdata->gpio, 1)) {
+                       *len = 0;
+                       return EIO;
+               }
+               *len = 0;
+               return OK;
+       } else if (gpio_cbdata->type == GPIO_CB_OFF) {
+               /* turn off */
+               if (drv.set(gpio_cbdata->gpio, 0)) {
+                       *len = 0;
+                       return EIO;
+               }
+               *len = 0;
+               return OK;
+       }
+
+       /* reading */
+       if (drv.read(gpio_cbdata->gpio, &value)) {
+               *len = 0;
+               return EIO;
+       }
+       snprintf(data, 26, "%d\n", value);
+
+       /* If the offset is beyond the end of the string, return EOF. */
+       if (offset > strlen(data)) {
+               *len = 0;
+
+               return OK;
+       }
+
+       /* Otherwise, return a pointer into 'data'. If necessary, bound the
+        * returned length to the length of the rest of the string. Note that
+        * 'data' has to be static, because it will be used after this
+        * function returns. */
+       *ptr = data + offset;
+
+       if (*len > strlen(data) - offset)
+               *len = strlen(data) - offset;
+
+       return OK;
+}
+
+int
+main(int argc, char **argv)
+{
+
+       struct fs_hooks hooks;
+       struct inode_stat root_stat;
+
+       /* Set and apply the environment */
+       env_setargs(argc, argv);
+
+       /* fill in the hooks */
+       memset(&hooks, 0, sizeof(hooks));
+       hooks.init_hook = init_hook;
+       hooks.read_hook = read_hook;
+
+       root_stat.mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH;
+       root_stat.uid = 0;
+       root_stat.gid = 0;
+       root_stat.size = 0;
+       root_stat.dev = NO_DEV;
+
+       /* limit the number of indexed entries */
+       start_vtreefs(&hooks, 10, &root_stat, 0);
+
+       return EXIT_SUCCESS;
+}
diff --git a/drivers/gpio/gpio.h b/drivers/gpio/gpio.h
new file mode 100644 (file)
index 0000000..5984ca8
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __INCLUDE_GPIO_H__
+#define __INCLUDE_GPIO_H__
+
+struct gpio
+{
+       int nr;                 /* GPIO number */
+       int mode;               /* GPIO mode (input=0/output=1) */
+       void *data;             /* data pointer (not used in the omap driver) */
+};
+
+#define GPIO_MODE_INPUT 0
+#define GPIO_MODE_OUTPUT 1
+
+struct gpio_driver
+{
+       /* request access to a gpio */
+       int (*claim) (char *owner, int nr, struct gpio ** gpio);
+
+       /* Configure the GPIO for a certain purpose */
+       int (*pin_mode) (struct gpio * gpio, int mode);
+
+       /* Set the value for a GPIO */
+       int (*set) (struct gpio * gpio, int value);
+
+       /* Read the value of the GPIO */
+       int (*read) (struct gpio * gpio, int *value);
+};
+
+int omap_gpio_init(struct gpio_driver *gpio_driver);
+#endif /* __INCLUDE_GPIO_H__ */
diff --git a/drivers/gpio/gpio_omap.c b/drivers/gpio/gpio_omap.c
new file mode 100644 (file)
index 0000000..e2063a7
--- /dev/null
@@ -0,0 +1,236 @@
+/* kernel headers */
+#include <minix/syslib.h>
+#include <minix/drvlib.h>
+
+/* system headers */
+#include <sys/mman.h>
+#include <sys/types.h>
+
+/* usr headers */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+/* local headers */
+#include "log.h"
+#include "mmio.h"
+#include "gpio.h"
+
+/* used for logging */
+static struct log log = {
+       .name = "gpio_omap",
+       .log_level = LEVEL_INFO,
+       .log_func = default_log
+};
+
+struct omap_gpio_bank
+{
+       const char *name;
+       uint32_t register_address;
+       uint32_t base_address;
+       uint32_t disabled;
+};
+
+static struct omap_gpio_bank omap_gpio_banks[] = {
+       {"GPIO1", 0x48310000, 0, 0},
+       {"GPIO2", 0x49050000, 0, 0},
+       {"GPIO3", 0x49052000, 0, 0},
+       {"GPIO4", 0x49054000, 0, 0},
+       {"GPIO5", 0x49056000, 0, 0},
+       {"GPIO6", 0x49058000, 0, 0},
+       {NULL, 0, 0}
+};
+
+#define GPIO_REVISION 0x00
+#define GPIO_REVISION_MAJOR(X) ((X & 0xF0) >> 4)
+#define GPIO_REVISION_MINOR(X) (X & 0XF)
+
+#define GPIO_DATAOUT 0x3c
+#define GPIO_DATAIN 0x38
+#define GPIO_OE 0x34           /* Output Data Enable */
+#define GPIO_CLEARDATAOUT 0x90
+#define GPIO_SETDATAOUT 0x94
+
+#define LED_USR0 (1 << 21)
+#define LED_USR1 (1 << 22)
+
+struct omap_gpio_bank *
+omap_gpio_bank_get(int gpio_nr)
+{
+       struct omap_gpio_bank *bank;
+       assert(gpio_nr >= 0 && gpio_nr <= 32 * 6);
+       bank = &omap_gpio_banks[gpio_nr / 32];
+       return bank;
+}
+
+int
+omap_gpio_claim(char *owner, int nr, struct gpio **gpio)
+{
+       log_trace(&log, "%s s claiming %d\n", owner, nr);
+
+       if (nr < 0 && nr >= 32 * 6) {
+               log_warn(&log, "%s is claiming unknown GPIO number %d\n", owner,
+                   nr);
+               return EINVAL;
+       }
+
+       if ( omap_gpio_bank_get(nr)->disabled == 1) {
+               log_warn(&log, "%s is claiming GPIO %d from disabled bank\n", owner,
+                   nr);
+               return EINVAL;
+       }
+
+       struct gpio *tmp = malloc(sizeof(struct gpio));
+       memset(tmp, 0, sizeof(*tmp));
+
+       tmp->nr = nr;
+       *gpio = tmp;
+       return OK;
+}
+
+int
+omap_gpio_pin_mode(struct gpio *gpio, int mode)
+{
+       struct omap_gpio_bank *bank;
+       assert(gpio != NULL);
+       gpio->mode = mode;
+
+       bank = omap_gpio_bank_get(gpio->nr);
+       log_debug(&log,
+           "pin mode bank %s, base address 0x%x -> register address (0x%x,0x%x,0x%x)\n",
+           bank->name, bank->base_address, bank->register_address, GPIO_OE,
+           bank->register_address + GPIO_OE);
+
+       if (mode == GPIO_MODE_OUTPUT) {
+               set32(bank->base_address + GPIO_OE, BIT(gpio->nr % 32), 0);
+       } else {
+               set32(bank->base_address + GPIO_OE, BIT(gpio->nr % 32),
+                   0xffffffff);
+       }
+       return 0;
+}
+
+int
+omap_gpio_set(struct gpio *gpio, int value)
+{
+       struct omap_gpio_bank *bank;
+       assert(gpio != NULL);
+       assert(gpio->nr >= 0 && gpio->nr <= 32 * 6);
+
+       bank = omap_gpio_bank_get(gpio->nr);
+       if (value == 1) {
+               write32(bank->base_address + GPIO_SETDATAOUT,
+                   BIT(gpio->nr % 32));
+       } else {
+               write32(bank->base_address + GPIO_CLEARDATAOUT,
+                   BIT(gpio->nr % 32));
+       }
+       return OK;
+}
+
+int
+omap_gpio_read(struct gpio *gpio, int *value)
+{
+       struct omap_gpio_bank *bank;
+       assert(gpio != NULL);
+       assert(gpio->nr >= 0 && gpio->nr <= 32 * 6);
+
+       bank = omap_gpio_bank_get(gpio->nr);
+       log_trace(&log, "mode=%d OU/IN 0x%08x 0x%08x\n", gpio->mode,
+           read32(bank->base_address + GPIO_DATAIN),
+           read32(bank->base_address + GPIO_DATAOUT));
+
+       if (gpio->mode == GPIO_MODE_INPUT) {
+               *value =
+                   (read32(bank->base_address +
+                       GPIO_DATAIN) >> (gpio->nr % 32)) & 0x1;
+       } else {
+               *value =
+                   (read32(bank->base_address +
+                       GPIO_DATAOUT) >> (gpio->nr % 32)) & 0x1;
+       }
+
+       return OK;
+}
+
+int
+omap_gpio_init(struct gpio_driver *drv)
+{
+       u32_t revision;
+       int i;
+       struct minix_mem_range mr;
+       struct omap_gpio_bank *bank;
+
+       bank = &omap_gpio_banks[0];
+       for (i = 0; omap_gpio_banks[i].name != NULL; i++) {
+               bank = &omap_gpio_banks[i];
+               mr.mr_base = bank->register_address;
+               mr.mr_limit = bank->register_address + 0x400;
+
+               if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
+                       log_warn(&log,
+                           "Unable to request permission to map memory\n");
+                       return EPERM;   /* fixme */
+               }
+
+               /* Set the base address to use */
+               bank->base_address =
+                   (uint32_t) vm_map_phys(SELF,
+                   (void *) bank->register_address, 0x400);
+
+               if (bank->base_address == (uint32_t) MAP_FAILED) {
+                       log_warn(&log, "Unable to map GPIO memory\n");
+                       return EPERM;   /* fixme */
+               }
+
+               revision = 0;
+               revision = read32(bank->base_address + GPIO_REVISION);
+               /* test if we can access it */
+               if (GPIO_REVISION_MAJOR(revision) != 2
+                   || GPIO_REVISION_MINOR(revision) != 5) {
+                       log_warn(&log,
+                           "Failed to read the revision of GPIO bank %s.. disabling\n",
+                           bank->name);
+                       bank->disabled = 1;
+               }
+               bank->disabled = 0;
+               log_trace(&log, "bank %s mapped on 0x%x\n", bank->name,
+                   bank->base_address);
+       }
+
+/* the following code need to move to a power management/clock service */
+#define CM_BASE 0x48004000
+#define CM_FCLKEN_WKUP 0xC00
+#define CM_ICLKEN_WKUP 0xC10
+
+       u32_t base;
+       mr.mr_base = CM_BASE;
+       mr.mr_limit = CM_BASE + 0x1000;
+
+       if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
+               log_warn(&log, "Unable to request permission to map memory\n");
+               return EPERM;
+       }
+
+       base = (uint32_t) vm_map_phys(SELF, (void *) CM_BASE, 0x1000);
+
+       if (base == (uint32_t) MAP_FAILED) {
+               log_warn(&log, "Unable to map GPIO memory\n");
+               return EPERM;
+       }
+
+       /* enable the interface and functional clock on GPIO bank 1 */
+       set32(base + CM_FCLKEN_WKUP, BIT(3), 0xffffffff);
+       set32(base + CM_ICLKEN_WKUP, BIT(3), 0xffffffff);
+/* end power management/clock service stuff */
+
+
+       drv->claim = omap_gpio_claim;
+       drv->pin_mode = omap_gpio_pin_mode;
+       drv->set = omap_gpio_set;
+       drv->read = omap_gpio_read;
+       return 0;
+}
diff --git a/drivers/gpio/log.h b/drivers/gpio/log.h
new file mode 100644 (file)
index 0000000..b3d0c17
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef __LOG_H__
+#define __LOG_H__
+/*
+ * Simple logging functions
+ */
+
+/*
+ * LEVEL_NONE  do not log anything.
+ * LEVEL_WARN  Information that needs to be known.
+ * LEVEL_INFO  Basic information like startup messages and occasional events.
+ * LEVEL_DEBUG debug statements about things happening that are less expected.
+ * LEVEL_TRACE Way to much information for anybody.
+ */
+
+#define LEVEL_NONE 0
+#define LEVEL_WARN 1
+#define LEVEL_INFO 2
+#define LEVEL_DEBUG 3
+#define LEVEL_TRACE 4
+
+static const char *level_string[5] = {
+       "none",
+       "warn",
+       "info",
+       "debug",
+       "trace"
+};
+
+/*
+ * struct to be initialized by the user of the logging system.
+ *
+ * name: The name attribute is used in logging statements do differentiate
+ * drivers
+ *
+ * log_level The level attribute describes the requested logging level. a level
+ * of 1 will only print warnings while a level of 4 will print all the trace
+ * information.
+ *
+ * log_func The logging function to use to log, log.h provides default_log
+ * to display information on the kernel output buffer. As a bonus if the
+ * requested log level is debug or trace the method , file and line number will
+ * be printed to the steam.
+ */
+struct log { const char *name; int log_level;
+
+       /* the logging function itself */
+       void (*log_func) (struct log * driver,
+           int level,
+           const char *file,
+           const char *function, int line, const char *fmt, ...);
+
+};
+
+#define __log(driver,log_level, fmt, args...) \
+               ((driver)->log_func(driver,log_level, \
+                               __FILE__, __FUNCTION__, __LINE__,\
+                               fmt, ## args))
+
+/* Log a warning */
+#define log_warn(driver, fmt, args...) \
+               __log(driver, LEVEL_WARN, fmt, ## args)
+
+/* Log an information message  */
+#define log_info(driver, fmt, args...) \
+               __log(driver, LEVEL_INFO, fmt, ## args)
+
+/* log debugging output  */
+#define log_debug(driver, fmt, args...) \
+               __log(driver, LEVEL_DEBUG, fmt, ## args)
+
+/* log trace output  */
+#define log_trace(driver, fmt, args...) \
+               __log(driver, LEVEL_TRACE, fmt, ## args)
+
+#endif /* __LOG_H__ */
+
+static void
+default_log(struct log *driver,
+    int level,
+    const char *file, const char *function, int line, const char *fmt, ...)
+{
+       va_list args;
+
+       if (level > driver->log_level) {
+               return;
+       }
+       /* If the wanted level is debug also display line/method information */
+       if (driver->log_level >= LEVEL_DEBUG) {
+               fprintf(stderr, "%s(%s):%s+%d(%s):", driver->name,
+                   level_string[level], file, line, function);
+       } else {
+               fprintf(stderr, "%s(%s)", driver->name, level_string[level]);
+       }
+
+       va_start(args, fmt);
+       vfprintf(stderr, fmt, args);
+       va_end(args);
+}
+
+#ifdef hacks
+static void
+hexdump(unsigned char *d, unsigned int size)
+{
+       int s;
+       for (s = 0; s < size; s += 4) {
+               fprintf(stdout, "0x%04x 0x%02X%02X%02X%02X %c%c%c%c\n", s,
+                   (unsigned int) d[s], (unsigned int) d[s + 1],
+                   (unsigned int) d[s + 2], (unsigned int) d[s + 3], d[s],
+                   d[s + 1], d[s + 2], d[s + 3]);
+       }
+}
+#endif
diff --git a/drivers/gpio/mmio.h b/drivers/gpio/mmio.h
new file mode 100644 (file)
index 0000000..f40262a
--- /dev/null
@@ -0,0 +1,30 @@
+#define REG(x)(*((volatile uint32_t *)(x)))
+#define BIT(x)(0x1 << x)
+
+/* Write a uint32_t value to a memory address. */
+static inline void
+write32(uint32_t address, uint32_t value)
+{
+       REG(address) = value;
+}
+
+/* Read an uint32_t from a memory address */
+static inline uint32_t
+read32(uint32_t address)
+{
+
+       return REG(address);
+}
+
+/* Set a 32 bits value depending on a mask */
+static inline void
+set32(uint32_t address, uint32_t mask, uint32_t value)
+{
+       uint32_t val;
+       val = read32(address);
+       /* clear the bits */
+       val &= ~(mask);
+       /* apply the value using the mask */
+       val |= (value & mask);
+       write32(address, val);
+}
index 700f388ababb20cb054653a2a97137caa1e746c7..5d81eccf561a57ac2dc072bd65c6234f6883dda0 100644 (file)
@@ -57,7 +57,7 @@ PROG_DRIVERS+=        acpi
 
 .if ${MACHINE_ARCH} == "earm"
 EXTRA+=                rc.arm mylogin.sh ttys
-PROG_DRIVERS+= mmc tty
+PROG_DRIVERS+= mmc tty gpio
 PROG_COMMANDS+=        cp dd getty ls time sync sleep stty umount
 PROG_BIN+=     cat rm
 PROTO=         proto.arm.small
index df58d91b8d19fec7258f6b35e01e508570a4ac82..1fad54302ee40cf2b5e1b40799affe2bc4111012 100644 (file)
@@ -20,9 +20,13 @@ d--755 0 0
        sbin d--755 0 0
                mmc ---755 0 0 mmc
                mfs ---755 0 0 mfs
+               gpio ---755 0 0 gpio
+               
        $
        mnt d--755 0 0
        $
+       gpio d--755 0 0
+       $       
        usr d--755 0 0
                bin d--755 0 0
                        login ---755 0 0 mylogin.sh
index 5f8de51e33fa4815b5b1aa4e689da5ff4274e79d..3a40acccf0a221a107e11b6db04d6fa35cbc15a6 100755 (executable)
@@ -12,5 +12,7 @@ exec </dev/null
 #/bin/service -c up /sbin/mmc  -dev /dev/c0d0 
 #/bin/fsck.mfs  -p /dev/c0d0p1
 #/bin/mount  /dev/c0d0p1 /mnt
+#gpio
+#mount -t gpio none /gpio
 
 exit
index de37c66b14f2a7a9cee06f3c171fc8edfd1a4a99..5bd104950e17bae8aa3125abb5d43db80487e82b 100644 (file)
@@ -552,6 +552,13 @@ service mmc
        ;
 };
 
+service gpio
+{
+       system
+               PRIVCTL         #  4
+       ;
+};
+
 service vbox
 {
        system