Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=a1d9e6e49f4b473a6945a6b553f5070e8c793e0a
Commit:     a1d9e6e49f4b473a6945a6b553f5070e8c793e0a
Parent:     7b4fbc50fabb810523be522fe7ec5cc40f85c7a1
Author:     David Brownell <[EMAIL PROTECTED]>
AuthorDate: Tue May 1 23:26:30 2007 +0200
Committer:  Jean Delvare <[EMAIL PROTECTED]>
CommitDate: Tue May 1 23:26:30 2007 +0200

    i2c: i2c stack can remove()
    
    More update for new style driver support:  add a remove() method, and
    use it in the relevant code paths.
    
    Again, nothing will use this yet since there's nothing to create devices
    feeding this infrastructure.
    
    Signed-off-by: David Brownell <[EMAIL PROTECTED]>
    Signed-off-by: Jean Delvare <[EMAIL PROTECTED]>
---
 drivers/i2c/i2c-core.c |   65 +++++++++++++++++++++++++++++++++++++++++++++---
 include/linux/i2c.h    |    1 +
 2 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index a2ad83a..3aac1b5 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -41,6 +41,7 @@ static LIST_HEAD(drivers);
 static DEFINE_MUTEX(core_lists);
 static DEFINE_IDR(i2c_adapter_idr);
 
+#define is_newstyle_driver(d) ((d)->probe || (d)->remove)
 
 /* ------------------------------------------------------------------------- */
 
@@ -52,7 +53,7 @@ static int i2c_device_match(struct device *dev, struct 
device_driver *drv)
        /* make legacy i2c drivers bypass driver model probing entirely;
         * such drivers scan each i2c adapter/bus themselves.
         */
-       if (!driver->probe)
+       if (!is_newstyle_driver(driver))
                return 0;
 
        /* new style drivers use the same kind of driver matching policy
@@ -100,7 +101,24 @@ static int i2c_device_probe(struct device *dev)
 
 static int i2c_device_remove(struct device *dev)
 {
-       return 0;
+       struct i2c_client       *client = to_i2c_client(dev);
+       struct i2c_driver       *driver;
+       int                     status;
+
+       if (!dev->driver)
+               return 0;
+
+       driver = to_i2c_driver(dev->driver);
+       if (driver->remove) {
+               dev_dbg(dev, "remove\n");
+               status = driver->remove(client);
+       } else {
+               dev->driver = NULL;
+               status = 0;
+       }
+       if (status == 0)
+               client->driver = NULL;
+       return status;
 }
 
 static void i2c_device_shutdown(struct device *dev)
@@ -177,6 +195,26 @@ struct bus_type i2c_bus_type = {
        .resume         = i2c_device_resume,
 };
 
+static void i2c_unregister_device(struct i2c_client *client)
+{
+       struct i2c_adapter      *adapter = client->adapter;
+       struct i2c_driver       *driver = client->driver;
+
+       if (driver && !is_newstyle_driver(driver)) {
+               dev_err(&client->dev, "can't unregister devices "
+                       "with legacy drivers\n");
+               WARN_ON(1);
+               return;
+       }
+
+       mutex_lock(&adapter->clist_lock);
+       list_del(&client->list);
+       mutex_unlock(&adapter->clist_lock);
+
+       device_unregister(&client->dev);
+}
+
+
 /* ------------------------------------------------------------------------- */
 
 /* I2C bus adapters -- one roots each I2C or SMBUS segment */
@@ -310,9 +348,19 @@ int i2c_del_adapter(struct i2c_adapter *adap)
        /* 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;
 
-               if ((res=client->driver->detach_client(client))) {
+               /* 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);
@@ -355,7 +403,7 @@ int i2c_register_driver(struct module *owner, struct 
i2c_driver *driver)
        int res;
 
        /* new style driver methods can't mix with legacy ones */
-       if (driver->probe) {
+       if (is_newstyle_driver(driver)) {
                if (driver->attach_adapter || driver->detach_adapter
                                || driver->detach_client) {
                        printk(KERN_WARNING
@@ -392,6 +440,10 @@ int i2c_register_driver(struct module *owner, struct 
i2c_driver *driver)
 }
 EXPORT_SYMBOL(i2c_register_driver);
 
+/**
+ * i2c_del_driver - unregister I2C driver
+ * @driver: the driver being unregistered
+ */
 int i2c_del_driver(struct i2c_driver *driver)
 {
        struct list_head   *item1, *item2, *_n;
@@ -402,6 +454,10 @@ int i2c_del_driver(struct i2c_driver *driver)
 
        mutex_lock(&core_lists);
 
+       /* new-style driver? */
+       if (is_newstyle_driver(driver))
+               goto unregister;
+
        /* Have a look at each adapter, if clients of this driver are still
         * attached. If so, detach them to be able to kill the driver
         * afterwards.
@@ -434,6 +490,7 @@ int i2c_del_driver(struct i2c_driver *driver)
                }
        }
 
+ unregister:
        driver_unregister(&driver->driver);
        list_del(&driver->list);
        pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 8dcccc0..6802c3a 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -130,6 +130,7 @@ struct i2c_driver {
         * it's done by infrastructure.  (NEW STYLE DRIVERS ONLY)
         */
        int (*probe)(struct i2c_client *);
+       int (*remove)(struct i2c_client *);
 
        /* driver model interfaces that don't relate to enumeration  */
        void (*shutdown)(struct i2c_client *);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to