From d4fa68402e6fe4211c26d4c95246943c8c77ebf5 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Mar 2007 23:08:28 +0000 Subject: [PATCH] MFp4: Make the iicbus fully hinted. We no longer automatically add some devices (and not others). To get instances onto the iicbus, one now needs hints or an identify routine. We also do not probe the bus for devices because many iic devices cannot be safely probed (and when they can, the probe order turns out to be somewhat difficult to get right). # I'm not 100% sure that the iicsmb removal is right. Please contact me if # this causes difficulty. --- sys/dev/iicbus/iic.c | 9 +-- sys/dev/iicbus/iicbus.c | 165 +++++++++++++++++++++++++++++----------- 2 files changed, 123 insertions(+), 51 deletions(-) diff --git a/sys/dev/iicbus/iic.c b/sys/dev/iicbus/iic.c index 3d3f28f4498e..57b071738430 100644 --- a/sys/dev/iicbus/iic.c +++ b/sys/dev/iicbus/iic.c @@ -249,9 +249,8 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t if (!sc) return (EINVAL); - if ((error = iicbus_request_bus(device_get_parent(iicdev), iicdev, - (flags & O_NONBLOCK) ? IIC_DONTWAIT : - (IIC_WAIT | IIC_INTR)))) + if ((error = iicbus_request_bus(parent, iicdev, + (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR)))) return (error); switch (cmd) { @@ -314,7 +313,7 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t if (!(m->flags & IIC_M_RD)) copyin(usrbufs[i], m->buf, m->len); } - error = iicbus_transfer(parent, (struct iic_msg *)buf, d->nmsgs); + error = iicbus_transfer(iicdev, (struct iic_msg *)buf, d->nmsgs); /* Copyout all read segments, free up kernel buffers */ for (i = 0; i < d->nmsgs; i++) { m = &((struct iic_msg *)buf)[i]; @@ -328,7 +327,7 @@ iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *t error = ENOTTY; } - iicbus_release_bus(device_get_parent(iicdev), iicdev); + iicbus_release_bus(parent, iicdev); if (buf != NULL) free(buf, M_TEMP); diff --git a/sys/dev/iicbus/iicbus.c b/sys/dev/iicbus/iicbus.c index 563f53b1e9ca..8594b8d46c60 100644 --- a/sys/dev/iicbus/iicbus.c +++ b/sys/dev/iicbus/iicbus.c @@ -34,52 +34,18 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include - #include #include #include "iicbus_if.h" -#define DEVTOIICBUS(dev) ((struct iicbus_device*)device_get_ivars(dev)) - -devclass_t iicbus_devclass; - /* See comments below for why auto-scanning is a bad idea. */ #define SCAN_IICBUS 0 -/* - * Device methods - */ -static int iicbus_probe(device_t); -static int iicbus_attach(device_t); -static int iicbus_detach(device_t); -static int iicbus_add_child(device_t dev, int order, const char *name, int unit); - -static device_method_t iicbus_methods[] = { - /* device interface */ - DEVMETHOD(device_probe, iicbus_probe), - DEVMETHOD(device_attach, iicbus_attach), - DEVMETHOD(device_detach, iicbus_detach), - - /* bus interface */ - DEVMETHOD(bus_add_child, iicbus_add_child), - DEVMETHOD(bus_driver_added, bus_generic_driver_added), - DEVMETHOD(bus_print_child, bus_generic_print_child), - - DEVMETHOD(iicbus_transfer, iicbus_transfer_gen), - - { 0, 0 } -}; - -driver_t iicbus_driver = { - "iicbus", - iicbus_methods, - sizeof(struct iicbus_softc), -}; - static int iicbus_probe(device_t dev) { @@ -121,7 +87,9 @@ iicbus_attach(device_t dev) #if SCAN_IICBUS unsigned char addr; #endif + struct iicbus_softc *sc = IICBUS_SOFTC(dev); + sc->dev = dev; iicbus_reset(dev, IIC_FASTEST, 0, NULL); /* device probing is meaningless since the bus is supposed to be @@ -140,15 +108,13 @@ iicbus_attach(device_t dev) } printf("\n"); #endif - - device_add_child(dev, "ic", -1); - device_add_child(dev, "iicsmb", -1); - device_add_child(dev, "ds1672", -1); - device_add_child(dev, "ad7418", -1); -#if 0 + /* Always attach the iicsmb children */ + BUS_ADD_CHILD(dev, 0, "iicsmb", -1); /* attach any known device */ - device_add_child(dev, "iic", -1); -#endif + BUS_ADD_CHILD(dev, 0, "iic", -1); + /* Attach the wired devices via hints */ + bus_enumerate_hinted_children(dev); + /* Now probe and attach them */ bus_generic_attach(dev); return (0); } @@ -163,12 +129,89 @@ iicbus_detach(device_t dev) } static int +iicbus_print_child(device_t dev, device_t child) +{ + struct iicbus_ivar *devi = IICBUS_IVAR(child); + int retval = 0; + + retval += bus_print_child_header(dev, child); + if (devi->addr != 0) + retval += printf(" at addr %#x", devi->addr); + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static void +iicbus_probe_nomatch(device_t bus, device_t child) +{ + struct iicbus_ivar *devi = IICBUS_IVAR(child); + + device_printf(bus, ""); + printf(" at addr %#x\n", devi->addr); + return; +} + +static int +iicbus_child_location_str(device_t bus, device_t child, char *buf, + size_t buflen) +{ + struct iicbus_ivar *devi = IICBUS_IVAR(child); + + snprintf(buf, buflen, "addr=%#x", devi->addr); + return (0); +} + +static int +iicbus_child_pnpinfo_str(device_t bus, device_t child, char *buf, + size_t buflen) +{ + *buf = '\0'; + return (0); +} + +static int +iicbus_read_ivar(device_t bus, device_t child, int which, u_char *result) +{ + struct iicbus_ivar *devi = IICBUS_IVAR(child); + + switch (which) { + default: + return (EINVAL); + case IICBUS_IVAR_ADDR: + *(uint32_t *)result = devi->addr; + break; + } + return (0); +} + +static device_t iicbus_add_child(device_t dev, int order, const char *name, int unit) { + device_t child; + struct iicbus_ivar *devi; - device_add_child_ordered(dev, order, name, unit); - bus_generic_attach(dev); - return (0); + child = device_add_child_ordered(dev, order, name, unit); + if (child == NULL) + return (child); + devi = malloc(sizeof(struct iicbus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO); + if (devi == NULL) { + device_delete_child(dev, child); + return (0); + } + device_set_ivars(child, devi); + return (child); +} + +static void +iicbus_hinted_child(device_t bus, const char *dname, int dunit) +{ + device_t child; + struct iicbus_ivar *devi; + + child = BUS_ADD_CHILD(bus, 0, dname, dunit); + devi = IICBUS_IVAR(child); + resource_int_value(dname, dunit, "addr", &devi->addr); } int @@ -192,6 +235,36 @@ iicbus_null_repeated_start(device_t dev, u_char addr) return (IIC_ENOTSUPP); } +static device_method_t iicbus_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, iicbus_probe), + DEVMETHOD(device_attach, iicbus_attach), + DEVMETHOD(device_detach, iicbus_detach), + + /* bus interface */ + DEVMETHOD(bus_add_child, iicbus_add_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + DEVMETHOD(bus_print_child, iicbus_print_child), + DEVMETHOD(bus_probe_nomatch, iicbus_probe_nomatch), + DEVMETHOD(bus_read_ivar, iicbus_read_ivar), + DEVMETHOD(bus_child_pnpinfo_str, iicbus_child_pnpinfo_str), + DEVMETHOD(bus_child_location_str, iicbus_child_location_str), + DEVMETHOD(bus_hinted_child, iicbus_hinted_child), + + /* iicbus interface */ + DEVMETHOD(iicbus_transfer, iicbus_transfer), + + { 0, 0 } +}; + +driver_t iicbus_driver = { + "iicbus", + iicbus_methods, + sizeof(struct iicbus_softc), +}; + +devclass_t iicbus_devclass; + DRIVER_MODULE(iicbus, envctrl, iicbus_driver, iicbus_devclass, 0, 0); DRIVER_MODULE(iicbus, iicbb, iicbus_driver, iicbus_devclass, 0, 0); MODULE_VERSION(iicbus, IICBUS_MODVER);