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