From: David Brownell Subject: 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 Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 65 +++++++++++++++++++++++++++++++++++++++++++++--- include/linux/i2c.h | 1 2 files changed, 62 insertions(+), 4 deletions(-) --- linux-2.6.21.orig/include/linux/i2c.h 2007-04-27 07:33:31.000000000 +0200 +++ linux-2.6.21/include/linux/i2c.h 2007-04-27 07:33:43.000000000 +0200 @@ -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 *); --- linux-2.6.21.orig/drivers/i2c/i2c-core.c 2007-04-27 07:33:31.000000000 +0200 +++ linux-2.6.21/drivers/i2c/i2c-core.c 2007-04-27 07:33:43.000000000 +0200 @@ -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 devic /* 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 devic 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 * /* 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 *o 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 *o } 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 *dr 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 *dr } } + unregister: driver_unregister(&driver->driver); list_del(&driver->list); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);