svn commit: r308041 - stable/11/sys/dev/smbus

Andriy Gapon avg at FreeBSD.org
Fri Oct 28 14:50:24 UTC 2016


Author: avg
Date: Fri Oct 28 14:50:23 2016
New Revision: 308041
URL: https://svnweb.freebsd.org/changeset/base/308041

Log:
  MFC r307130: smbus: allow child devices to be added via hints

Modified:
  stable/11/sys/dev/smbus/smbconf.h
  stable/11/sys/dev/smbus/smbus.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/smbus/smbconf.h
==============================================================================
--- stable/11/sys/dev/smbus/smbconf.h	Fri Oct 28 14:49:54 2016	(r308040)
+++ stable/11/sys/dev/smbus/smbconf.h	Fri Oct 28 14:50:23 2016	(r308041)
@@ -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().
  */

Modified: stable/11/sys/dev/smbus/smbus.c
==============================================================================
--- stable/11/sys/dev/smbus/smbus.c	Fri Oct 28 14:49:54 2016	(r308040)
+++ stable/11/sys/dev/smbus/smbus.c	Fri Oct 28 14:50:23 2016	(r308041)
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/lock.h>
+#include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/mutex.h>
 #include <sys/bus.h>
@@ -41,54 +42,16 @@ __FBSDID("$FreeBSD$");
 #include "smbus_if.h"
 #include "bus_if.h"
 
+struct smbus_ivar
+{
+	uint8_t	addr;
+};
 
 /*
  * Autoconfiguration and support routines for System Management bus
  */
+static void smbus_probe_device(device_t dev, u_char addr);
 
-/*
- * Device methods
- */
-static int smbus_probe(device_t);
-static int smbus_attach(device_t);
-static int smbus_detach(device_t);
-
-static int smbus_child_location_str(device_t parent, device_t child,
-		    char *buf, size_t buflen);
-static int smbus_print_child(device_t parent, device_t child);
-static void smbus_probe_device(device_t dev, u_char* addr);
-static int smbus_read_ivar(device_t parent, device_t child, int which,
-		    uintptr_t *result);
-
-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(bus_child_location_str, smbus_child_location_str),
-	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
-	DEVMETHOD(bus_print_child,	smbus_print_child),
-	DEVMETHOD(bus_read_ivar,	smbus_read_ivar),
-
-	DEVMETHOD_END
-};
-
-driver_t smbus_driver = {
-        "smbus",
-        smbus_methods,
-        sizeof(struct smbus_softc),
-};
-
-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.
- */
 static int
 smbus_probe(device_t dev)
 {
@@ -107,9 +70,9 @@ smbus_attach(device_t dev)
 	mtx_init(&sc->lock, device_get_nameunit(dev), "smbus", MTX_DEF);
 	bus_generic_probe(dev);
 	for (addr = SMBUS_ADDR_MIN; addr < SMBUS_ADDR_MAX; ++addr) {
-		sc->addrs[addr] = addr;
-		smbus_probe_device(dev, &sc->addrs[addr]);
+		smbus_probe_device(dev, addr);
 	}
+	bus_enumerate_hinted_children(dev);
 	bus_generic_attach(dev);
 
 	return (0);
@@ -124,6 +87,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);
@@ -135,34 +99,78 @@ smbus_generic_intr(device_t dev, u_char 
 }
 
 static void
-smbus_probe_device(device_t dev, u_char* addr)
+smbus_probe_device(device_t dev, u_char addr)
 {
 	device_t child;
 	int error;
 	u_char cmd;
 	u_char buf[2];
+	struct smbus_ivar *devi;
 
 	cmd = 0x01;
-	error = smbus_trans(dev, *addr, cmd,
+	error = smbus_trans(dev, addr, cmd,
 			    SMB_TRANS_NOCNT | SMB_TRANS_NOREPORT,
 			    NULL, 0, buf, 1, NULL);
 	if (error == 0) {
 		if (bootverbose)
-			device_printf(dev, "Probed address 0x%02x\n", *addr);
-		child = device_add_child(dev, NULL, -1);
-		device_set_ivars(child, addr);
+			device_printf(dev, "Probed address 0x%02x\n", addr);
+		child = BUS_ADD_CHILD(dev, SMBUS_ORDER_PNP, NULL, -1);
+		if (child == NULL)
+			return;
+		devi = device_get_ivars(child);
+		devi->addr = addr;
+	}
+}
+
+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)
 {
-	unsigned char *addr;
+	struct smbus_ivar *devi;
 
-	addr = device_get_ivars(child);
-	if (addr)
-		snprintf(buf, buflen, "addr=0x%x", *addr);
+	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);
@@ -171,28 +179,49 @@ smbus_child_location_str(device_t parent
 static int
 smbus_print_child(device_t parent, device_t child)
 {
-	unsigned char *addr;
+	struct smbus_ivar *devi;
 	int retval;
 
-	addr = device_get_ivars(child);
+	devi = device_get_ivars(child);
 	retval = bus_print_child_header(parent, child);
-	if (addr)
-		retval += printf(" at addr 0x%x", *addr);
+	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)
+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)
 {
-	unsigned char *addr;
+	struct smbus_ivar *devi;
 
-	addr = device_get_ivars(child);
+	devi = device_get_ivars(child);
 	switch (which) {
 	case SMBUS_IVAR_ADDR:
-		*result = (addr == NULL) ? -1 : *addr;
+		/* Allow to set but no change the slave address. */
+		if (devi->addr != 0)
+			return (EINVAL);
+		devi->addr = value;
 		break;
 	default:
 		return (ENOENT);
@@ -200,4 +229,47 @@ smbus_read_ivar(device_t parent, device_
 	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, "<unknown device> 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);


More information about the svn-src-all mailing list