--- /dev/null
+I2C device driver binding control from user-space
+=================================================
+
+Up to kernel 2.6.32, many i2c drivers used helper macros provided by
+<linux/i2c.h> which created standard module parameters to let the user
+control how the driver would probe i2c buses and attach to devices. These
+parameters were known as "probe" (to let the driver probe for an extra
+address), "force" (to forcibly attach the driver to a given device) and
+"ignore" (to prevent a driver from probing a given address).
+
+With the conversion of the i2c subsystem to the standard device driver
+binding model, it became clear that these per-module parameters were no
+longer needed, and that a centralized implementation was possible. The new,
+sysfs-based interface is described in the documentation file
+"instantiating-devices", section "Method 4: Instantiate from user-space".
+
+Below is a mapping from the old module parameters to the new interface.
+
+Attaching a driver to an I2C device
+-----------------------------------
+
+Old method (module parameters):
+# modprobe <driver> probe=1,0x2d
+# modprobe <driver> force=1,0x2d
+# modprobe <driver> force_<device>=1,0x2d
+
+New method (sysfs interface):
+# echo <device> 0x2d > /sys/bus/i2c/devices/i2c-1/new_device
+
+Preventing a driver from attaching to an I2C device
+---------------------------------------------------
+
+Old method (module parameters):
+# modprobe <driver> ignore=1,0x2f
+
+New method (sysfs interface):
+# echo dummy 0x2f > /sys/bus/i2c/devices/i2c-1/new_device
+# modprobe <driver>
+
+Of course, it is important to instantiate the "dummy" device before loading
+the driver. The dummy device will be handled by i2c-core itself, preventing
+other drivers from binding to it later on. If there is a real device at the
+problematic address, and you want another driver to bind to it, then simply
+pass the name of the device in question instead of "dummy".
return -ENOMEM;
temp_client->adapter = adapter;
- /* Force entries are done first, and are not affected by ignore
- entries */
- if (address_data->forces) {
- const unsigned short * const *forces = address_data->forces;
- int kind;
-
- for (kind = 0; forces[kind]; kind++) {
- for (i = 0; forces[kind][i] != I2C_CLIENT_END;
- i += 2) {
- if (forces[kind][i] == adap_id
- || forces[kind][i] == ANY_I2C_BUS) {
- dev_dbg(&adapter->dev, "found force "
- "parameter for adapter %d, "
- "addr 0x%02x, kind %d\n",
- adap_id, forces[kind][i + 1],
- kind);
- temp_client->addr = forces[kind][i + 1];
- err = i2c_detect_address(temp_client,
- kind, driver);
- if (err)
- goto exit_free;
- }
- }
- }
- }
-
/* Stop here if the classes do not match */
if (!(adapter->class & driver->class))
goto exit_free;
/* Stop here if we can't use SMBUS_QUICK */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
- if (address_data->probe[0] == I2C_CLIENT_END
- && address_data->normal_i2c[0] == I2C_CLIENT_END)
+ if (address_data->normal_i2c[0] == I2C_CLIENT_END)
goto exit_free;
dev_warn(&adapter->dev, "SMBus Quick command not supported, "
goto exit_free;
}
- /* Probe entries are done second, and are not affected by ignore
- entries either */
- for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
- if (address_data->probe[i] == adap_id
- || address_data->probe[i] == ANY_I2C_BUS) {
- dev_dbg(&adapter->dev, "found probe parameter for "
- "adapter %d, addr 0x%02x\n", adap_id,
- address_data->probe[i + 1]);
- temp_client->addr = address_data->probe[i + 1];
- err = i2c_detect_address(temp_client, -1, driver);
- if (err)
- goto exit_free;
- }
- }
-
- /* Normal entries are done last, unless shadowed by an ignore entry */
for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
- int j, ignore;
-
- ignore = 0;
- for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;
- j += 2) {
- if ((address_data->ignore[j] == adap_id ||
- address_data->ignore[j] == ANY_I2C_BUS)
- && address_data->ignore[j + 1]
- == address_data->normal_i2c[i]) {
- dev_dbg(&adapter->dev, "found ignore "
- "parameter for adapter %d, "
- "addr 0x%02x\n", adap_id,
- address_data->ignore[j + 1]);
- ignore = 1;
- break;
- }
- }
- if (ignore)
- continue;
-
dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
"addr 0x%02x\n", adap_id,
address_data->normal_i2c[i]);
* @driver: Device driver model driver
* @id_table: List of I2C devices supported by this driver
* @detect: Callback for device detection
- * @address_data: The I2C addresses to probe, ignore or force (for detect)
+ * @address_data: The I2C addresses to probe (for detect)
* @clients: List of detected clients we created (for i2c-core use only)
*
* The driver.owner field should be set to the module owner of this driver.
*/
struct i2c_client_address_data {
const unsigned short *normal_i2c;
- const unsigned short *probe;
- const unsigned short *ignore;
- const unsigned short * const *forces;
};
/* Internal numbers to terminate lists */
module_param_array(var, short, &var##_num, 0); \
MODULE_PARM_DESC(var, desc)
-#define I2C_CLIENT_MODULE_PARM_FORCE(name) \
-I2C_CLIENT_MODULE_PARM(force_##name, \
- "List of adapter,address pairs which are " \
- "unquestionably assumed to contain a `" \
- # name "' chip")
-
-
#define I2C_CLIENT_INSMOD_COMMON \
-I2C_CLIENT_MODULE_PARM(probe, "List of adapter,address pairs to scan " \
- "additionally"); \
-I2C_CLIENT_MODULE_PARM(ignore, "List of adapter,address pairs not to " \
- "scan"); \
static const struct i2c_client_address_data addr_data = { \
.normal_i2c = normal_i2c, \
- .probe = probe, \
- .ignore = ignore, \
- .forces = forces, \
}
-#define I2C_CLIENT_FORCE_TEXT \
- "List of adapter,address pairs to boldly assume to be present"
-
/* These are the ones you want to use in your own drivers. Pick the one
which matches the number of devices the driver differenciates between. */
#define I2C_CLIENT_INSMOD \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-static const unsigned short * const forces[] = { force, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_1(chip1) \
enum chips { any_chip, chip1 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_2(chip1, chip2) \
enum chips { any_chip, chip1, chip2 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_3(chip1, chip2, chip3) \
enum chips { any_chip, chip1, chip2, chip3 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_4(chip1, chip2, chip3, chip4) \
enum chips { any_chip, chip1, chip2, chip3, chip4 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, \
- force_##chip4, NULL}; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_5(chip1, chip2, chip3, chip4, chip5) \
enum chips { any_chip, chip1, chip2, chip3, chip4, chip5 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, \
- force_##chip4, force_##chip5, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_6(chip1, chip2, chip3, chip4, chip5, chip6) \
enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip6); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, \
- force_##chip4, force_##chip5, force_##chip6, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_7(chip1, chip2, chip3, chip4, chip5, chip6, chip7) \
enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, \
chip7 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip6); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip7); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, \
- force_##chip4, force_##chip5, force_##chip6, \
- force_##chip7, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#define I2C_CLIENT_INSMOD_8(chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8) \
enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, \
chip7, chip8 }; \
-I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip1); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip2); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip3); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip4); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip5); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip6); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip7); \
-I2C_CLIENT_MODULE_PARM_FORCE(chip8); \
-static const unsigned short * const forces[] = { force, \
- force_##chip1, force_##chip2, force_##chip3, \
- force_##chip4, force_##chip5, force_##chip6, \
- force_##chip7, force_##chip8, NULL }; \
I2C_CLIENT_INSMOD_COMMON
#endif /* __KERNEL__ */
#endif /* _LINUX_I2C_H */