Browse Source

Abstract Linux GPIO interface behind a new gpio.h

Luke Dashjr 12 years ago
parent
commit
c5576f6b6a
2 changed files with 138 additions and 0 deletions
  1. 79 0
      gpio-linux.c
  2. 59 0
      gpio.h

+ 79 - 0
gpio-linux.c

@@ -0,0 +1,79 @@
+#include <stdbool.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "logging.h"
+
+#include "gpio.h"
+
+extern struct bfg_gpio_controller _linux_gpio;
+
+bool bfg_gpio_init(void)
+{
+	const int fd = open("/dev/mem", O_RDWR | O_SYNC);
+	if (fd < 0)
+		applogr(false, LOG_ERR, "Failed to open /dev/mem");
+	volatile unsigned *gpio;
+	gpio = mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x20200000);
+	if (gpio == MAP_FAILED)
+		applogr(false, LOG_ERR, "Failed to mmap GPIO from /dev/mem");
+	close(fd);
+	
+	linux_gpio->all_gpios = gpio_bitmask_all;
+	linux_gpio->p = (void*)gpio;
+	
+	return true;
+}
+
+static
+bool linux_gpio_set_mode(struct bfg_gpio_controller * const gc, const gpio_bitmask_t pins, int mode)
+{
+	volatile unsigned * const gpio = gc->p;
+	if (mode > 1)
+	{
+		if (mode > 3)
+		{
+			if (mode > 5)
+				return false;
+			mode = 7 - mode;
+		}
+		else
+			mode |= 4;
+	}
+	for (int i = gpio_highest; i >= 0; --i)
+	{
+		volatile unsigned * const g = &gpio[i / 10];
+		const int sh = (i % 10) * 3;
+		*g = (*g & ~(7 << sh)) | (mode << sh);
+	}
+	return true;
+}
+
+static
+void linux_gpio_set_values(struct bfg_gpio_controller * const gc, const gpio_bitmask_t pins, const gpio_bitmask_t vals)
+{
+	volatile unsigned * const gpio = gc->p;
+	gpio[7] = pins & vals;
+	gpio[10] = pins & ~vals;
+}
+
+static
+gpio_bitmask_t linux_gpio_get_values(struct bfg_gpio_controller * const gc, const gpio_bitmask_t pins)
+{
+	volatile unsigned * const gpio = gc->p;
+	return gpio[13] & pins;
+}
+
+static
+const struct bfg_gpio_controller_drv linux_gpio_drv = {
+	.set_mode = linux_gpio_set_mode,
+	.set_values = linux_gpio_set_values,
+	.get_values = linux_gpio_get_values,
+};
+
+struct bfg_gpio_controller _linux_gpio = {
+	.drv = &linux_gpio_drv,
+};

+ 59 - 0
gpio.h

@@ -0,0 +1,59 @@
+#ifndef BFG_GPIO_H
+#define BFG_GPIO_H
+
+enum bfg_gpio_direction {
+	BGD_INPUT  = 0,
+	BGD_OUTPUT = 1,
+};
+#define BGD_ALT(n) (2 + n)
+
+typedef unsigned gpio_bitmask_t;
+static const gpio_bitmask_t gpio_bitmask_all = -1;
+static const int gpio_highest = ((sizeof(gpio_bitmask_t) * 8) - 1);
+
+#define gpio_bitmask(pin)  (1<<pin)
+
+struct bfg_gpio_controller;
+
+struct bfg_gpio_controller_drv {
+	bool (*set_mode)(struct bfg_gpio_controller *, gpio_bitmask_t, int);
+	void (*set_values)(struct bfg_gpio_controller *, gpio_bitmask_t, gpio_bitmask_t);
+	gpio_bitmask_t (*get_values)(struct bfg_gpio_controller *, gpio_bitmask_t);
+};
+
+struct bfg_gpio_controller {
+	gpio_bitmask_t all_gpios;
+	
+	const struct bfg_gpio_controller_drv *drv;
+	void *p;
+};
+
+static inline
+bool gpio_set_mode(struct bfg_gpio_controller * const gc, const gpio_bitmask_t pins, const int mode)
+{
+	return gc->drv->set_mode(gc, pins, mode);
+}
+
+static inline
+void gpio_set_values(struct bfg_gpio_controller * const gc, const gpio_bitmask_t pins, const gpio_bitmask_t vals)
+{
+	gc->drv->set_values(gc, pins, vals);
+}
+
+static inline
+void gpio_set_value(struct bfg_gpio_controller * const gc, const gpio_bitmask_t pins, const bool val)
+{
+	gc->drv->set_values(gc, pins, val ? pins : 0);
+}
+
+static inline
+gpio_bitmask_t gpio_get_values(struct bfg_gpio_controller * const gc, const gpio_bitmask_t pins)
+{
+	return gc->drv->get_values(gc, pins);
+}
+
+extern bool bfg_gpio_init(void);
+extern struct bfg_gpio_controller _linux_gpio;
+#define linux_gpio (&_linux_gpio)
+
+#endif