[i2c] [patch 5/5] i2c_register_adapter()
Jean Delvare
khali at linux-fr.org
Sun Mar 4 10:58:41 CET 2007
Hi David,
On Thu, 15 Feb 2007 00:46:43 -0800, David Brownell wrote:
> This adds a new call, i2c_register_adapter(), to register an I2C adapter
> using a specific bus number and then create I2C device nodes for any
> pre-declared devices on that bus. It builds on previous patches adding
> I2C probe() and remove() support, and pre-declaration of devices.
>
> There's also a minor related cleanup, using class infrastructure to
> create and remove the device attribute and associated code movement.
As usual, I will ask for a separate patch for this. This is not
specifically related to the rest of what the patch does.
>
> This completes the basic support for "new style" I2C device drivers.
> Those follow the standard driver model for binding devices to drivers
> (using probe and remove methods) rather than a legacy model (where the
> driver tries to autoconfigure each bus, and registers devices itself).
>
> Signed-off-by: David Brownell <dbrownell at users.sourceforge.net>
>
> ---
> drivers/i2c/i2c-core.c | 156 +++++++++++++++++++++++++++++++++++--------------
> include/linux/i2c.h | 1
> 2 files changed, 115 insertions(+), 42 deletions(-)
>
> Index: i2c/include/linux/i2c.h
> ===================================================================
> --- i2c.orig/include/linux/i2c.h 2007-02-15 00:00:08.000000000 -0800
> +++ i2c/include/linux/i2c.h 2007-02-15 00:00:08.000000000 -0800
> @@ -354,6 +354,7 @@ struct i2c_client_address_data {
> */
> extern int i2c_add_adapter(struct i2c_adapter *);
> extern int i2c_del_adapter(struct i2c_adapter *);
> +extern int i2c_register_adapter(struct i2c_adapter *);
>
> extern int i2c_register_driver(struct module *, struct i2c_driver *);
> extern int i2c_del_driver(struct i2c_driver *);
> Index: i2c/drivers/i2c/i2c-core.c
> ===================================================================
> --- i2c.orig/drivers/i2c/i2c-core.c 2007-02-15 00:00:08.000000000 -0800
> +++ i2c/drivers/i2c/i2c-core.c 2007-02-15 00:00:08.000000000 -0800
> @@ -268,28 +268,32 @@ EXPORT_SYMBOL_GPL(i2c_unregister_device)
>
> /* ------------------------------------------------------------------------- */
>
> +/* I2C bus adapters -- one roots each I2C or SMBUS segment */
> +
> void i2c_adapter_dev_release(struct device *dev)
> {
> struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
> complete(&adap->dev_released);
> }
>
> -/* ------------------------------------------------------------------------- */
> +static ssize_t
> +show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> + struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
> + return sprintf(buf, "%s\n", adap->name);
> +}
>
> -/* I2C bus adapters -- one roots each I2C or SMBUS segment */
> +static struct device_attribute i2c_adapter_attrs[] = {
> + __ATTR(name, S_IRUGO, show_adapter_name, NULL),
> + { },
> +};
>
> struct class i2c_adapter_class = {
> .owner = THIS_MODULE,
> .name = "i2c-adapter",
> + .dev_attrs = i2c_adapter_attrs,
> };
>
> -static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> - struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
> - return sprintf(buf, "%s\n", adap->name);
> -}
> -static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
> -
>
> static int i2c_do_add_adapter(struct device_driver *d, void *data)
> {
> @@ -306,35 +310,17 @@ static int i2c_do_add_adapter(struct dev
> return res;
> }
>
> -/* -----
> - * i2c_add_adapter is called from within the algorithm layer,
> - * when a new hw adapter registers. A new device is register to be
> - * available for clients.
> - */
> -int i2c_add_adapter(struct i2c_adapter *adap)
> +static int __i2c_register_adapter(struct i2c_adapter *adap)
> {
> - int id, res = 0;
> -
> - mutex_lock(&core_lists);
> -
> - if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) {
> - res = -ENOMEM;
> - goto out_unlock;
> - }
> -
> - res = idr_get_new(&i2c_adapter_idr, adap, &id);
> - if (res < 0) {
> - if (res == -EAGAIN)
> - res = -ENOMEM;
> - goto out_unlock;
> - }
> + int res = 0;
>
> - adap->nr = id & MAX_ID_MASK;
> mutex_init(&adap->bus_lock);
> mutex_init(&adap->clist_lock);
> list_add_tail(&adap->list,&adapters);
> INIT_LIST_HEAD(&adap->clients);
>
> + mutex_lock(&core_lists);
> +
Looks like a bug to me, I think you must hold the code_lists mutex for
the list_add_tail instruction above.
> /* Add the adapter to the driver core.
> * If the parent pointer is not set up,
> * we add this adapter to the host bus.
> @@ -350,9 +336,6 @@ int i2c_add_adapter(struct i2c_adapter *
> res = device_register(&adap->dev);
> if (res)
> goto out_list;
> - res = device_create_file(&adap->dev, &dev_attr_name);
> - if (res)
> - goto out_unregister;
>
> dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
>
> @@ -364,16 +347,50 @@ out_unlock:
> mutex_unlock(&core_lists);
> return res;
>
> -out_unregister:
> - init_completion(&adap->dev_released); /* Needed? */
> - device_unregister(&adap->dev);
> - wait_for_completion(&adap->dev_released);
> out_list:
> list_del(&adap->list);
> idr_remove(&i2c_adapter_idr, adap->nr);
> goto out_unlock;
> }
>
> +/**
> + * i2c_add_adapter - declare i2c adapter, use dynamic bus number
> + * @adap: the adapter to add
> + *
> + * This routine is used to declare an I2C adapter when its bus number
> + * doesn't matter. Examples: for I2C adapters dynamically added by
> + * USB links or PCI plugin cards.
> + *
> + * When this returns zero, a new bus number was allocated and stored
> + * in adap->nr, and the specified adapter became available for clients.
> + * Otherwise, a negative errno value is returned.
> + */
> +int i2c_add_adapter(struct i2c_adapter *adap)
> +{
> + int id, res = 0;
> +
> +retry:
> + if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
> + return -ENOMEM;
> +
> + mutex_lock(&core_lists);
> + /* "above" here means "above or equal to", sigh */
> + res = idr_get_new_above(&i2c_adapter_idr, adap,
> + __i2c_first_dynamic_bus_num, &id);
> + adap->nr = id;
> + mutex_unlock(&core_lists);
> + if (res < 0) {
> + if (res == -EAGAIN)
> + goto retry;
> + return res;
> + }
You should not set adap->nr before checking that the call to
idr_get_new_above was successful.
> +
> + if (res == 0)
Isn't this always true?
> + res = __i2c_register_adapter(adap);
> + return res;
> +}
> +EXPORT_SYMBOL(i2c_add_adapter);
> +
> static void i2c_scan_static_board_info(struct i2c_adapter *adap)
> {
> struct boardinfo *bi;
> @@ -392,6 +409,59 @@ static void i2c_scan_static_board_info(s
> mutex_unlock(&__i2c_board_lock);
> }
>
> +/**
> + * i2c_register_adapter - declare i2c adapter, use static bus number
> + * @adap: the adapter to register (with adap->nr initialized)
> + *
> + * This routine is used to declare an I2C adapter when its bus number
> + * matters. Example: for I2C adapters from system-on-chip CPUs, or
> + * otherwise built in to the system's mainboard, and where i2c_board_info
> + * is used to properly configure I2C devices.
> + *
> + * If no devices have pre-been declared for this bus, then be sure to
> + * register the adapter before any dynamically allocated ones. Otherwise
> + * the required bus ID may not be available.
> + *
> + * When this returns zero, the specified adapter became available for
> + * clients using the bus number provided in adap->nr. Also, the table
> + * of I2C devices pre-declared using i2c_register_board_info() is scanned,
> + * and the appropriate driver model device nodes are created. Otherwise, a
> + * negative errno value is returned.
> + */
> +int i2c_register_adapter(struct i2c_adapter *adap)
> +{
> + int id;
> + int status;
> +
> + if (adap->nr & ~MAX_ID_MASK)
> + return -EINVAL;
> +
> +retry:
> + if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
> + return -ENOMEM;
> +
> + mutex_lock(&core_lists);
> + /* "above" here means "above or equal to", sigh;
> + * we need the "equal to" result to force the result
> + */
> + status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
> + if (status == 0 && id != adap->nr) {
> + status = -EBUSY;
> + idr_remove(&i2c_adapter_idr, id);
> + }
> + mutex_unlock(&core_lists);
> + if (status == -EAGAIN)
> + goto retry;
> +
> + if (status == 0)
> + status = __i2c_register_adapter(adap);
> + if (status == 0)
> + i2c_scan_static_board_info(adap);
> + return status;
> +}
> +EXPORT_SYMBOL_GPL(i2c_register_adapter);
> +
> +
> static int i2c_do_del_adapter(struct device_driver *d, void *data)
> {
> struct i2c_driver *driver = to_i2c_driver(d);
> @@ -459,14 +529,13 @@ int i2c_del_adapter(struct i2c_adapter *
>
> /* clean up the sysfs representation */
> init_completion(&adap->dev_released);
> - device_remove_file(&adap->dev, &dev_attr_name);
> device_unregister(&adap->dev);
> list_del(&adap->list);
>
> /* wait for sysfs to drop all references */
> wait_for_completion(&adap->dev_released);
>
> - /* free dynamically allocated bus id */
> + /* free bus id */
> idr_remove(&i2c_adapter_idr, adap->nr);
>
> dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
> @@ -506,6 +575,9 @@ int i2c_register_driver(struct module *o
> driver->driver.owner = owner;
> driver->driver.bus = &i2c_bus_type;
>
> + /* for new style drivers, when registration returns the driver core
> + * will have called probe() for all matching-but-unbound devices.
> + */
> res = driver_register(&driver->driver);
> pr_debug("i2c-core: register driver [%s] --> %d\n",
> driver->driver.name, res);
> @@ -626,7 +698,8 @@ int i2c_attach_client(struct i2c_client
> client->usage_count = 0;
>
> client->dev.parent = &client->adapter->dev;
> - client->dev.driver = &client->driver->driver;
> + if (client->driver)
> + client->dev.driver = &client->driver->driver;
> client->dev.bus = &i2c_bus_type;
> client->dev.release = &i2c_client_release;
>
> @@ -1362,7 +1435,6 @@ EXPORT_SYMBOL_GPL(i2c_adapter_dev_releas
> EXPORT_SYMBOL_GPL(i2c_adapter_class);
> EXPORT_SYMBOL_GPL(i2c_bus_type);
>
> -EXPORT_SYMBOL(i2c_add_adapter);
> EXPORT_SYMBOL(i2c_del_adapter);
> EXPORT_SYMBOL(i2c_del_driver);
> EXPORT_SYMBOL(i2c_attach_client);
--
Jean Delvare
More information about the i2c
mailing list