I’ve gone through all of the i2c drivers I can find in the source tree and audited their auto configuration scheme. Each of the drivers has been updated to return the “match quality” values introduced in the previous set of changes. To review, those “match quality” values are:
— Address-only: “Yes, this is a valid address for this device”. Used in indirect-config.
— Address-and-probe: “Yes, this is a valid address for this device, and I’ve looked at it and it seems to be what I expect”. Used in indirect-config.
— Compatible-match: “One of the ‘compatible’ properties of the device matched one of my ‘compatible-with’ strings.”. Used in direct-config.
— Specific-match: “A specific device driver was requested, and I’m it.” Used in direct-config.
For a lot of drivers, the changes were purely mechanical, i.e. returning the correct I2C_MATCH_* constant.
I did introduce a new helper function to centralize the direct-config matching logic for drivers that support it:
bool iic_use_direct_match(const struct i2c_attach_args *ia, const cfdata_t cf, const char **compats, int *match_resultp);
This function checks to see if the attach_args indicate direct-config. If they don’t, it returns false. If they do, it returns true and places the match quality result into *match_resultp. The match is first done against specific-driver, which compares ia->ia_name to the driver name retrieved via the passed-in cfdata_t (cf->cf_driver->cd_name). Failing that, the passed-in compats array is checked as the old iic_compat_match() did. If there is a match there, a match quality is computed and returned. The match quality is computed by adding the reverse-index of the device’s matching compatible property to the base I2C_MATCH_DIRECT_COMPATIBLE value. The reason for this is that a more-specific driver can match a device with a higher “compatible” match quality. Take for example a device with the following “compatible” properties:
foo,foo666-phy
generic-phy
…and we have to drivers: “foo666phy” and “genericphy”, with compats arrays of { “foo,foo666-phy”, NULL }, and { “generic-phy”, NULL } respectively. The “genericphy” driver would of course work with the foo666 device, but may have reduced functionality. By weighting the match in this way we guarantee that a driver that matches the more-specific compatible string is the one that’s selected to drive the device. I adjusted some of the match quality base values to provide plenty of weighting-space between compatible and specific.
The general pattern that most drivers can use now is:
const char *foo_compats[] = { “foo,foo666phy”, NULL };
int
foo_match(device_t parent, cfdata_t cf, void *aux)
{
struct i2c_attach_args *ia = aux;
int match_result;
if (iic_use_direct_match(ia, cf, foo_compats, &match_result))
return (match_result);
if (ia->ia_addr == FOO_ADDR1 || ia->ia_addr == FOO_ADDR2)
return (I2C_MATCH_ADDRESS_ONLY);
return (0);
}
I’ve made sure all of this at least compiles (well, I’m pretty sure I didn’t miss anything), including the machine-dependent drivers for sparc64, macppc, and various ARM and MIPS devices. I still have some testing to do (I need to fake up some direct-config info for my particular RPI configuration to test out that logic thoroughly). But I want to get some eyeballs on the changes and feedback early.
!DSPAM:5b22bf1039632101812905!