tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

modular i2c device driver: direct match



Hello,

What do you think of the following, at least the idea, the patch is probably not very clean?
With this, i2c device driver module can use information gathered at i2cbus attachment.
direct match is then possible for modules, not only for builtins.

I only tested it on rpi: direct match with fdt information. And I did not really think about this on other platforms.

diff --git a/sys/dev/i2c/i2c.c b/sys/dev/i2c/i2c.c
index fc5ca267d1d5..e94cc0b5bb4b 100644
--- a/sys/dev/i2c/i2c.c
+++ b/sys/dev/i2c/i2c.c
@@ -378,9 +378,82 @@ iic_child_detach(device_t parent, device_t child)
 		}
 }
 
+static void
+iic_direct(device_t self, prop_array_t child_devices)
+{
+	unsigned int i, count;
+	prop_dictionary_t dev;
+	prop_data_t cdata;
+	uint32_t addr;
+	uint64_t cookie;
+	const char *name;
+	struct i2c_attach_args ia;
+	int loc[IICCF_NLOCS];
+	char* buf;
+	struct iic_softc *sc = device_private(self);
+	i2c_tag_t ic = sc->sc_tag;
+
+	memset(loc, 0, sizeof loc);
+	count = prop_array_count(child_devices);
+	for (i = 0; i < count; ++i) {
+		dev = prop_array_get(child_devices, i);
+		if (!dev) continue;
+		if (!prop_dictionary_get_cstring_nocopy(
+		    dev, "name", &name)) {
+			/* "name" property is optional. */
+			name = NULL;
+		}
+		if (!prop_dictionary_get_uint32(dev, "addr", &addr))
+			continue;
+		if (!prop_dictionary_get_uint64(dev, "cookie", &cookie))
+			cookie = 0;
+		loc[IICCF_ADDR] = addr;
+
+		memset(&ia, 0, sizeof ia);
+		ia.ia_addr = addr;
+		ia.ia_type = sc->sc_type;
+		ia.ia_tag = ic;
+		ia.ia_name = name;
+		ia.ia_cookie = cookie;
+		ia.ia_prop = dev;
+
+		buf = NULL;
+		cdata = prop_dictionary_get(dev, "compatible");
+		if (cdata)
+			iic_fill_compat(&ia,
+			    prop_data_data_nocopy(cdata),
+			    prop_data_size(cdata), &buf);
+
+		if (name == NULL && cdata == NULL) {
+			aprint_error_dev(self,
+			    "WARNING: ignoring bad child device entry "
+			    "for address 0x%02x\n", addr);
+		} else {
+			if (addr > I2C_MAX_ADDR) {
+				aprint_error_dev(self,
+				    "WARNING: ignoring bad device "
+				    "address @ 0x%02x\n", addr);
+			} else if (sc->sc_devices[addr] == NULL) {
+				sc->sc_devices[addr] =
+				    config_found_sm_loc(self, "iic",
+					loc, &ia, iic_print_direct,
+					NULL);
+			}
+		}
+
+		if (ia.ia_compat)
+			free(ia.ia_compat, M_TEMP);
+		if (buf)
+			free(buf, M_TEMP);
+	}
+}
+
 static int
 iic_rescan(device_t self, const char *ifattr, const int *locators)
 {
+	prop_array_t child_devices = prop_dictionary_get(device_properties(self), "i2c-child-devices");
+	if (child_devices)
+		iic_direct(self, child_devices);
 	config_search_ia(iic_search, self, ifattr, NULL);
 	return 0;
 }
@@ -399,7 +472,6 @@ iic_attach(device_t parent, device_t self, void *aux)
 	struct i2cbus_attach_args *iba = aux;
 	prop_array_t child_devices;
 	prop_dictionary_t props;
-	char *buf;
 	i2c_tag_t ic;
 	int rv;
 	bool indirect_config;
@@ -437,68 +509,8 @@ iic_attach(device_t parent, device_t self, void *aux)
 	}
 
 	if (child_devices) {
-		unsigned int i, count;
-		prop_dictionary_t dev;
-		prop_data_t cdata;
-		uint32_t addr;
-		uint64_t cookie;
-		const char *name;
-		struct i2c_attach_args ia;
-		int loc[IICCF_NLOCS];
-
-		memset(loc, 0, sizeof loc);
-		count = prop_array_count(child_devices);
-		for (i = 0; i < count; i++) {
-			dev = prop_array_get(child_devices, i);
-			if (!dev) continue;
- 			if (!prop_dictionary_get_cstring_nocopy(
-			    dev, "name", &name)) {
-				/* "name" property is optional. */
-				name = NULL;
-			}
-			if (!prop_dictionary_get_uint32(dev, "addr", &addr))
-				continue;
-			if (!prop_dictionary_get_uint64(dev, "cookie", &cookie))
-				cookie = 0;
-			loc[IICCF_ADDR] = addr;
-
-			memset(&ia, 0, sizeof ia);
-			ia.ia_addr = addr;
-			ia.ia_type = sc->sc_type;
-			ia.ia_tag = ic;
-			ia.ia_name = name;
-			ia.ia_cookie = cookie;
-			ia.ia_prop = dev;
-
-			buf = NULL;
-			cdata = prop_dictionary_get(dev, "compatible");
-			if (cdata)
-				iic_fill_compat(&ia,
-				    prop_data_data_nocopy(cdata),
-				    prop_data_size(cdata), &buf);
-
-			if (name == NULL && cdata == NULL) {
-				aprint_error_dev(self,
-				    "WARNING: ignoring bad child device entry "
-				    "for address 0x%02x\n", addr);
-			} else {
-				if (addr > I2C_MAX_ADDR) {
-					aprint_error_dev(self,
-					    "WARNING: ignoring bad device "
-					    "address @ 0x%02x\n", addr);
-				} else if (sc->sc_devices[addr] == NULL) {
-					sc->sc_devices[addr] =
-					    config_found_sm_loc(self, "iic",
-					        loc, &ia, iic_print_direct,
-						NULL);
-				}
-			}
-
-			if (ia.ia_compat)
-				free(ia.ia_compat, M_TEMP);
-			if (buf)
-				free(buf, M_TEMP);
-		}
+		prop_dictionary_set(device_properties(self), "i2c-child-devices", child_devices);
+		iic_direct(self, child_devices);
 	} else if (indirect_config) {
 		/*
 		 * Attach all i2c devices described in the kernel


Thank you
yarl




Home | Main Index | Thread Index | Old Index