This changes how the I2C core iterates devices connected to a given
i2c_adapter, making it use driver model facilities instead of the
deprecated i2c_adapter.clients list.  The two functions affected are
i2c_del_adapter() and i2c_del_driver().

This is something of a bugfix:  updates to that list are protected by a
lock (i2c_adapter.clist_lock) which is completly ignored by those two
iteration loops ...

Signed-off-by: David Brownell <[EMAIL PROTECTED]>
---
Builds fine, and I have a hard time seeing this break.  But this
hasn't really been tested.

 drivers/i2c/i2c-core.c |   91 +++++++++++++++++++++++++------------------------
 1 file changed, 48 insertions(+), 43 deletions(-)

--- g26.orig/drivers/i2c/i2c-core.c     2008-05-04 20:51:58.000000000 -0700
+++ g26/drivers/i2c/i2c-core.c  2008-05-04 20:55:46.000000000 -0700
@@ -725,6 +725,44 @@ static int i2c_do_del_adapter(struct dev
        return res;
 }
 
+static int i2c_do_detach_client(struct device *dev, void *target)
+{
+       struct i2c_client       *client = i2c_verify_client(dev);
+       struct i2c_driver       *driver;
+       int                     status;
+
+       /* ignore non-i2c nodes */
+       if (!client)
+               return 0;
+
+       /* we may care only about one specific (legacy) driver */
+       driver = client->driver;
+       if (target && driver != target)
+               return 0;
+
+       /* cleanup new-style nodes */
+       if (!driver || is_newstyle_driver(driver)) {
+               i2c_unregister_device(client);
+               return 0;
+       }
+
+       /* detach legacy drivers */
+       if (driver->detach_client)
+               status = driver->detach_client(client);
+       else
+               status = -EOPNOTSUPP;
+       if (status < 0)
+               dev_err(&client->adapter->dev,
+                       "detach_client failed for client "
+                       "[%s] at address 0x%02x\n",
+                       client->name, client->addr);
+
+       /* backwards compat: ignore failure while removing a single
+        * legacy driver; maybe we can disconnect it from other devs.
+        */
+       return target ? 0 : status;
+}
+
 /**
  * i2c_del_adapter - unregister I2C adapter
  * @adap: the adapter being unregistered
@@ -735,8 +773,6 @@ static int i2c_do_del_adapter(struct dev
  */
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
-       struct list_head  *item, *_n;
-       struct i2c_client *client;
        int res = 0;
 
        mutex_lock(&core_lock);
@@ -749,34 +785,18 @@ int i2c_del_adapter(struct i2c_adapter *
                goto out_unlock;
        }
 
-       /* Tell drivers about this removal */
+       /* Tell legacy drivers about this removal.  They can fail...
+        * in which case, give up.
+        */
        res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
                               i2c_do_del_adapter);
        if (res)
                goto out_unlock;
 
-       /* detach any active clients. This must be done first, because
-        * it can fail; in which case we give up. */
-       list_for_each_safe(item, _n, &adap->clients) {
-               struct i2c_driver       *driver;
-
-               client = list_entry(item, struct i2c_client, list);
-               driver = client->driver;
-
-               /* new style, follow standard driver model */
-               if (!driver || is_newstyle_driver(driver)) {
-                       i2c_unregister_device(client);
-                       continue;
-               }
-
-               /* legacy drivers create and remove clients themselves */
-               if ((res = driver->detach_client(client))) {
-                       dev_err(&adap->dev, "detach_client failed for client "
-                               "[%s] at address 0x%02x\n", client->name,
-                               client->addr);
-                       goto out_unlock;
-               }
-       }
+       /* Detach any active clients, both legacy and new style. */
+       res = device_for_each_child(&adap->dev, NULL, i2c_do_detach_client);
+       if (res)
+               goto out_unlock;
 
        if (adap->has_alert_irq) {
                devm_free_irq(&adap->dev, adap->irq, adap);
@@ -868,8 +888,6 @@ EXPORT_SYMBOL(i2c_register_driver);
  */
 void i2c_del_driver(struct i2c_driver *driver)
 {
-       struct list_head   *item2, *_n;
-       struct i2c_client  *client;
        struct i2c_adapter *adap;
 
        mutex_lock(&core_lock);
@@ -890,22 +908,9 @@ void i2c_del_driver(struct i2c_driver *d
                                        "for driver [%s]\n",
                                        driver->driver.name);
                        }
-               } else {
-                       list_for_each_safe(item2, _n, &adap->clients) {
-                               client = list_entry(item2, struct i2c_client, 
list);
-                               if (client->driver != driver)
-                                       continue;
-                               dev_dbg(&adap->dev, "detaching client [%s] "
-                                       "at 0x%02x\n", client->name,
-                                       client->addr);
-                               if (driver->detach_client(client)) {
-                                       dev_err(&adap->dev, "detach_client "
-                                               "failed for client [%s] at "
-                                               "0x%02x\n", client->name,
-                                               client->addr);
-                               }
-                       }
-               }
+               } else
+                       device_for_each_child(&adap->dev, driver,
+                                       i2c_do_detach_client);
        }
        up(&i2c_adapter_class.sem);
 

_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c

Reply via email to