From 7a7b027da3a50bbdfc238bfad50a2073f5cd0845 Mon Sep 17 00:00:00 2001 From: avg Date: Fri, 28 Oct 2016 15:02:24 +0000 Subject: [PATCH] MFC r307130: smbus: allow child devices to be added via hints Note that r281985 has never been MFC-ed to this branch, so this commit contains a couple of bits from that commit. git-svn-id: svn://svn.freebsd.org/base/stable/10@308042 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/smbus/smbconf.h | 4 + sys/dev/smbus/smbus.c | 191 +++++++++++++++++++++++++++++++++------- 2 files changed, 163 insertions(+), 32 deletions(-) diff --git a/sys/dev/smbus/smbconf.h b/sys/dev/smbus/smbconf.h index a3d403d56..0d573602e 100644 --- a/sys/dev/smbus/smbconf.h +++ b/sys/dev/smbus/smbconf.h @@ -34,6 +34,10 @@ #define n(flags) (~(flags) & (flags)) +/* Order constants for smbus children. */ +#define SMBUS_ORDER_HINTED 20 +#define SMBUS_ORDER_PNP 40 + /* * How tsleep() is called in smb_request_bus(). */ diff --git a/sys/dev/smbus/smbus.c b/sys/dev/smbus/smbus.c index a111332c6..89d0a73b7 100644 --- a/sys/dev/smbus/smbus.c +++ b/sys/dev/smbus/smbus.c @@ -31,49 +31,24 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include -#include +#include #include #include -/* - * Autoconfiguration and support routines for System Management bus - */ -/* - * Device methods - */ -static int smbus_probe(device_t); -static int smbus_attach(device_t); -static int smbus_detach(device_t); - -static device_method_t smbus_methods[] = { - /* device interface */ - DEVMETHOD(device_probe, smbus_probe), - DEVMETHOD(device_attach, smbus_attach), - DEVMETHOD(device_detach, smbus_detach), - - /* bus interface */ - DEVMETHOD(bus_add_child, bus_generic_add_child), - - DEVMETHOD_END -}; - -driver_t smbus_driver = { - "smbus", - smbus_methods, - sizeof(struct smbus_softc), +struct smbus_ivar +{ + uint8_t addr; }; -devclass_t smbus_devclass; - /* - * At 'probe' time, we add all the devices which we know about to the - * bus. The generic attach routine will probe and attach them if they - * are alive. + * Autoconfiguration and support routines for System Management bus */ + static int smbus_probe(device_t dev) { @@ -90,6 +65,7 @@ smbus_attach(device_t dev) mtx_init(&sc->lock, device_get_nameunit(dev), "smbus", MTX_DEF); bus_generic_probe(dev); + bus_enumerate_hinted_children(dev); bus_generic_attach(dev); return (0); @@ -104,6 +80,7 @@ smbus_detach(device_t dev) error = bus_generic_detach(dev); if (error) return (error); + device_delete_children(dev); mtx_destroy(&sc->lock); return (0); @@ -114,4 +91,154 @@ smbus_generic_intr(device_t dev, u_char devaddr, char low, char high, int err) { } +static device_t +smbus_add_child(device_t dev, u_int order, const char *name, int unit) +{ + struct smbus_ivar *devi; + device_t child; + + child = device_add_child_ordered(dev, order, name, unit); + if (child == NULL) + return (child); + devi = malloc(sizeof(struct smbus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO); + if (devi == NULL) { + device_delete_child(dev, child); + return (NULL); + } + device_set_ivars(child, devi); + return (child); +} + +static void +smbus_hinted_child(device_t bus, const char *dname, int dunit) +{ + struct smbus_ivar *devi; + device_t child; + int addr; + + addr = 0; + resource_int_value(dname, dunit, "addr", &addr); + if (addr > UINT8_MAX) { + device_printf(bus, "ignored incorrect slave address hint 0x%x" + " for %s%d\n", addr, dname, dunit); + return; + } + child = BUS_ADD_CHILD(bus, SMBUS_ORDER_HINTED, dname, dunit); + if (child == NULL) + return; + devi = device_get_ivars(child); + devi->addr = addr; +} + + +static int +smbus_child_location_str(device_t parent, device_t child, char *buf, + size_t buflen) +{ + struct smbus_ivar *devi; + + devi = device_get_ivars(child); + if (devi->addr != 0) + snprintf(buf, buflen, "addr=0x%x", devi->addr); + else if (buflen) + buf[0] = 0; + return (0); +} + +static int +smbus_print_child(device_t parent, device_t child) +{ + struct smbus_ivar *devi; + int retval; + + devi = device_get_ivars(child); + retval = bus_print_child_header(parent, child); + if (devi->addr != 0) + retval += printf(" at addr 0x%x", devi->addr); + retval += bus_print_child_footer(parent, child); + + return (retval); +} + +static int +smbus_read_ivar(device_t parent, device_t child, int which, uintptr_t *result) +{ + struct smbus_ivar *devi; + + devi = device_get_ivars(child); + switch (which) { + case SMBUS_IVAR_ADDR: + if (devi->addr != 0) + *result = devi->addr; + else + *result = -1; + break; + default: + return (ENOENT); + } + return (0); +} + +static int +smbus_write_ivar(device_t parent, device_t child, int which, uintptr_t value) +{ + struct smbus_ivar *devi; + + devi = device_get_ivars(child); + switch (which) { + case SMBUS_IVAR_ADDR: + /* Allow to set but no change the slave address. */ + if (devi->addr != 0) + return (EINVAL); + devi->addr = value; + break; + default: + return (ENOENT); + } + return (0); +} + +static void +smbus_probe_nomatch(device_t bus, device_t child) +{ + struct smbus_ivar *devi = device_get_ivars(child); + + /* + * Ignore (self-identified) devices without a slave address set. + * For example, smb(4). + */ + if (devi->addr != 0) + device_printf(bus, " at addr %#x\n", + devi->addr); +} + +/* + * Device methods + */ +static device_method_t smbus_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, smbus_probe), + DEVMETHOD(device_attach, smbus_attach), + DEVMETHOD(device_detach, smbus_detach), + + /* bus interface */ + DEVMETHOD(bus_add_child, smbus_add_child), + DEVMETHOD(bus_hinted_child, smbus_hinted_child), + DEVMETHOD(bus_probe_nomatch, smbus_probe_nomatch), + DEVMETHOD(bus_child_location_str, smbus_child_location_str), + DEVMETHOD(bus_print_child, smbus_print_child), + DEVMETHOD(bus_read_ivar, smbus_read_ivar), + DEVMETHOD(bus_write_ivar, smbus_write_ivar), + + DEVMETHOD_END +}; + +driver_t smbus_driver = { + "smbus", + smbus_methods, + sizeof(struct smbus_softc), +}; + +devclass_t smbus_devclass; + MODULE_VERSION(smbus, SMBUS_MODVER); -- 2.45.0