]> Zhao Yanbai Git Server - minix.git/commitdiff
libi2cdriver: library for i2c device drivers 78/678/2
authorThomas Cort <tcort@minix3.org>
Mon, 15 Jul 2013 14:29:24 +0000 (10:29 -0400)
committerThomas Cort <tcort@minix3.org>
Mon, 15 Jul 2013 21:02:57 +0000 (17:02 -0400)
Change-Id: Ib6d5617e4b62e0bc5b25e6fa92b44baf536b1961

distrib/sets/lists/minix/md.evbarm
distrib/sets/lists/minix/mi
include/minix/Makefile
include/minix/i2cdriver.h [new file with mode: 0644]
lib/Makefile
lib/libi2cdriver/Makefile [new file with mode: 0644]
lib/libi2cdriver/i2cdriver.c [new file with mode: 0644]

index 7a63dee4624bdd528afecded940286d4c6334127..841f92b7a637c1b977c2895e9eb6eaa00ef862db 100644 (file)
@@ -97,6 +97,8 @@
 ./usr/lib/libclkconf_pic.a             minix-sys
 ./usr/lib/libgpio.a                    minix-sys
 ./usr/lib/libgpio_pic.a                        minix-sys
+./usr/lib/libi2cdriver.a               minix-sys
+./usr/lib/libi2cdriver_pic.a           minix-sys
 ./usr/lib/libpadconf.a                 minix-sys
 ./usr/lib/libpadconf_pic.a             minix-sys
 ./usr/mdec                             minix-sys
index fd849bda43e378df047f6dc44fe18855d938b7d9..ecbe78608fba4c9a5c17f4512efd7630e23e4bca 100644 (file)
 ./usr/include/minix/hash.h             minix-sys
 ./usr/include/minix/hgfs.h             minix-sys
 ./usr/include/minix/i2c.h              minix-sys
+./usr/include/minix/i2cdriver.h                minix-sys
 ./usr/include/minix/input.h            minix-sys
 ./usr/include/minix/ioctl.h            minix-sys
 ./usr/include/minix/ipcconst.h         minix-sys
index e1b65cc4f1664ef147a65cabdceece6d65fab9e6..c2de2a71cd24743cf7530782bf750ccf14f4d3fa 100644 (file)
@@ -11,7 +11,7 @@ INCS+=        acpi.h audio_fw.h bitmap.h \
        debug.h devio.h devman.h dmap.h \
        driver.h drivers.h drvlib.h ds.h \
        endpoint.h fb.h fslib.h gpio.h gcov.h hash.h \
-       hgfs.h i2c.h ioctl.h input.h ipc.h ipcconst.h \
+       hgfs.h i2c.h i2cdriver.h ioctl.h input.h ipc.h ipcconst.h \
        keymap.h log.h mmio.h mount.h mthread.h minlib.h \
        netdriver.h optset.h padconf.h partition.h portio.h \
        priv.h procfs.h profile.h queryparam.h \
diff --git a/include/minix/i2cdriver.h b/include/minix/i2cdriver.h
new file mode 100644 (file)
index 0000000..3dd902c
--- /dev/null
@@ -0,0 +1,21 @@
+/* Prototypes and definitions for i2c drivers. */
+
+#ifndef _MINIX_I2CDRIVER_H
+#define _MINIX_I2CDRIVER_H
+
+#include <minix/endpoint.h>
+#include <minix/i2c.h>
+#include <minix/ipc.h>
+
+/* Functions defined by i2cdriver.c: */
+int i2cdriver_env_parse(uint32_t * bus, i2c_addr_t * address,
+                                               i2c_addr_t * valid_addrs);
+void i2cdriver_announce(uint32_t bus);
+endpoint_t i2cdriver_bus_endpoint(uint32_t bus);
+int i2cdriver_subscribe_bus_updates(uint32_t bus);
+void i2cdriver_handle_bus_update(endpoint_t * bus_endpoint, uint32_t bus,
+                                                       i2c_addr_t address);
+int i2cdriver_reserve_device(endpoint_t bus_endpoint, i2c_addr_t address);
+int i2cdriver_exec(endpoint_t bus_endpoint, minix_i2c_ioctl_exec_t *ioctl_exec);
+
+#endif /* _MINIX_I2CDRIVER_H */
index eeccc41c6bfdf64c3484b5fe3f7de6d1cb623875..ad747ec15701fada753b68ede6382a05b753f834 100644 (file)
@@ -54,7 +54,7 @@ SUBDIR += libvassert libhgfs libvboxfs libvirtio
 .endif
 
 .if (${MACHINE_ARCH} == "earm")
-SUBDIR += libclkconf libgpio libpadconf
+SUBDIR += libclkconf libgpio libi2cdriver libpadconf
 .endif
 
 .if (${MKRUMP} != "no")
diff --git a/lib/libi2cdriver/Makefile b/lib/libi2cdriver/Makefile
new file mode 100644 (file)
index 0000000..c4abd72
--- /dev/null
@@ -0,0 +1,7 @@
+# Makefile for libi2cdriver
+
+LIB=   i2cdriver
+
+SRCS=  i2cdriver.c
+
+.include <bsd.lib.mk>
diff --git a/lib/libi2cdriver/i2cdriver.c b/lib/libi2cdriver/i2cdriver.c
new file mode 100644 (file)
index 0000000..755bd8a
--- /dev/null
@@ -0,0 +1,195 @@
+/* This file contains device independent i2c device driver helpers. */
+
+#include <minix/drivers.h>
+#include <minix/endpoint.h>
+#include <minix/i2c.h>
+#include <minix/i2cdriver.h>
+#include <minix/ipc.h>
+#include <minix/ds.h>
+
+void
+i2cdriver_announce(uint32_t bus)
+{
+       /* Announce we are up after a fresh start or restart. */
+       int r;
+       char key[DS_MAX_KEYLEN];
+       char label[DS_MAX_KEYLEN];
+       char *driver_prefix = "drv.i2c.";
+
+       /* Callers are allowed to use sendrec to communicate with drivers.
+        * For this reason, there may blocked callers when a driver restarts.
+        * Ask the kernel to unblock them (if any).
+        */
+#if USE_STATECTL
+       if ((r = sys_statectl(SYS_STATE_CLEAR_IPC_REFS)) != OK) {
+               panic("chardriver_init: sys_statectl failed: %d", r);
+       }
+#endif
+
+       /* Publish a driver up event. */
+       r = ds_retrieve_label_name(label, getprocnr());
+       if (r != OK) {
+               panic("unable to get own label: %d\n", r);
+       }
+       /* example key: drv.i2c.1.cat24c245.0x50 */
+       snprintf(key, DS_MAX_KEYLEN, "%s%d.%s", driver_prefix, bus, label);
+       r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE);
+       if (r != OK) {
+               panic("unable to publish driver up event: %d\n", r);
+       }
+}
+
+int
+i2cdriver_env_parse(uint32_t * bus, i2c_addr_t * address,
+    i2c_addr_t * valid_addrs)
+{
+       /* fill in bus and address with the values passed on the command line */
+       int r;
+       int found;
+       long int busl;
+       long int addressl;
+
+       r = env_parse("bus", "d", 0, &busl, 1, 3);
+       if (r != EP_SET) {
+               return -1;
+       }
+       *bus = (uint32_t) busl;
+
+       r = env_parse("address", "x", 0, &addressl, 0x0000, 0x03ff);
+       if (r != EP_SET) {
+               return -1;
+       }
+       *address = addressl;
+
+       found = 0;
+       while (*valid_addrs != 0x0000) {
+
+               if (*address == *valid_addrs) {
+                       found = 1;
+                       break;
+               }
+
+               valid_addrs++;
+       }
+
+       if (!found) {
+               return 1;
+       }
+
+       return 0;
+}
+
+endpoint_t
+i2cdriver_bus_endpoint(uint32_t bus)
+{
+       /* locate the driver for the i2c bus itself */
+       int r;
+       char *label_prefix = "i2c.";
+       char label[DS_MAX_KEYLEN];
+       endpoint_t bus_endpoint;
+
+       snprintf(label, DS_MAX_KEYLEN, "%s%d", label_prefix, bus);
+
+       r = ds_retrieve_label_endpt(label, &bus_endpoint);
+       if (r != OK) {
+               return 0;
+       }
+
+       return bus_endpoint;
+}
+
+int
+i2cdriver_subscribe_bus_updates(uint32_t bus)
+{
+       int r;
+       char regex[DS_MAX_KEYLEN];
+
+       /* only capture events for the specified bus */
+       snprintf(regex, DS_MAX_KEYLEN, "drv\\.chr\\.i2c\\.%d", bus);
+
+       /* Subscribe to driver events from the i2c bus */
+       r = ds_subscribe(regex, DSF_INITIAL | DSF_OVERWRITE);
+       if (r != OK) {
+               return r;
+       }
+
+       return OK;
+}
+
+void
+i2cdriver_handle_bus_update(endpoint_t * bus_endpoint, uint32_t bus,
+    i2c_addr_t address)
+{
+       char key[DS_MAX_KEYLEN];
+       u32_t value;
+       int type;
+       endpoint_t owner_endpoint, old_endpoint;
+       int r;
+
+       /* check for pending events */
+       while ((r = ds_check(key, &type, &owner_endpoint)) == OK) {
+
+               r = ds_retrieve_u32(key, &value);
+               if (r != OK) {
+                       return;
+               }
+
+               if (value == DS_DRIVER_UP) {
+                       old_endpoint = *bus_endpoint;
+
+                       /* look up the bus's (potentially new) endpoint */
+                       *bus_endpoint = i2cdriver_bus_endpoint(bus);
+
+                       /* was updated endpoint? */
+                       if (old_endpoint != *bus_endpoint) {
+                               /* re-reserve device to allow the driver to
+                                * continue working, even through a manual
+                                * down/up.
+                                */
+                               i2cdriver_reserve_device(*bus_endpoint,
+                                   address);
+                       }
+               }
+       }
+}
+
+int
+i2cdriver_reserve_device(endpoint_t bus_endpoint, i2c_addr_t address)
+{
+       int r;
+       message m;
+
+       m.m_type = BUSC_I2C_RESERVE;
+       m.DEVICE = address;
+
+       r = sendrec(bus_endpoint, &m);
+       if (r != OK) {
+               return EIO;
+       }
+
+       return m.REP_STATUS;    /* return reply code OK, EBUSY, EINVAL, etc. */
+}
+
+int
+i2cdriver_exec(endpoint_t bus_endpoint, minix_i2c_ioctl_exec_t * ioctl_exec)
+{
+       int r;
+       message m;
+       cp_grant_id_t grant_nr;
+
+       grant_nr = cpf_grant_direct(bus_endpoint, (vir_bytes) ioctl_exec,
+           sizeof(minix_i2c_ioctl_exec_t), CPF_READ | CPF_WRITE);
+
+       memset(&m, '\0', sizeof(message));
+
+       m.m_type = BUSC_I2C_EXEC;
+       m.IO_GRANT = (char *) grant_nr;
+
+       r = sendrec(bus_endpoint, &m);
+       cpf_revoke(grant_nr);
+       if (r != OK) {
+               return EIO;
+       }
+
+       return m.REP_STATUS;
+}