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);