Commit a1d9e6e4 authored by David Brownell's avatar David Brownell Committed by Jean Delvare

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: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
parent 7b4fbc50
...@@ -41,6 +41,7 @@ static LIST_HEAD(drivers); ...@@ -41,6 +41,7 @@ static LIST_HEAD(drivers);
static DEFINE_MUTEX(core_lists); static DEFINE_MUTEX(core_lists);
static DEFINE_IDR(i2c_adapter_idr); 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) ...@@ -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; /* make legacy i2c drivers bypass driver model probing entirely;
* such drivers scan each i2c adapter/bus themselves. * such drivers scan each i2c adapter/bus themselves.
*/ */
if (!driver->probe) if (!is_newstyle_driver(driver))
return 0; return 0;
/* new style drivers use the same kind of driver matching policy /* new style drivers use the same kind of driver matching policy
...@@ -100,7 +101,24 @@ static int i2c_device_probe(struct device *dev) ...@@ -100,7 +101,24 @@ static int i2c_device_probe(struct device *dev)
static int i2c_device_remove(struct device *dev) static int i2c_device_remove(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev);
struct i2c_driver *driver;
int status;
if (!dev->driver)
return 0; 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) static void i2c_device_shutdown(struct device *dev)
...@@ -177,6 +195,26 @@ struct bus_type i2c_bus_type = { ...@@ -177,6 +195,26 @@ struct bus_type i2c_bus_type = {
.resume = i2c_device_resume, .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 */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */
...@@ -310,9 +348,19 @@ int i2c_del_adapter(struct i2c_adapter *adap) ...@@ -310,9 +348,19 @@ int i2c_del_adapter(struct i2c_adapter *adap)
/* detach any active clients. This must be done first, because /* detach any active clients. This must be done first, because
* it can fail; in which case we give up. */ * it can fail; in which case we give up. */
list_for_each_safe(item, _n, &adap->clients) { list_for_each_safe(item, _n, &adap->clients) {
struct i2c_driver *driver;
client = list_entry(item, struct i2c_client, list); 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;
}
if ((res=client->driver->detach_client(client))) { /* legacy drivers create and remove clients themselves */
if ((res = driver->detach_client(client))) {
dev_err(&adap->dev, "detach_client failed for client " dev_err(&adap->dev, "detach_client failed for client "
"[%s] at address 0x%02x\n", client->name, "[%s] at address 0x%02x\n", client->name,
client->addr); client->addr);
...@@ -355,7 +403,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) ...@@ -355,7 +403,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
int res; int res;
/* new style driver methods can't mix with legacy ones */ /* 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 if (driver->attach_adapter || driver->detach_adapter
|| driver->detach_client) { || driver->detach_client) {
printk(KERN_WARNING printk(KERN_WARNING
...@@ -392,6 +440,10 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) ...@@ -392,6 +440,10 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
} }
EXPORT_SYMBOL(i2c_register_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) int i2c_del_driver(struct i2c_driver *driver)
{ {
struct list_head *item1, *item2, *_n; struct list_head *item1, *item2, *_n;
...@@ -402,6 +454,10 @@ int i2c_del_driver(struct i2c_driver *driver) ...@@ -402,6 +454,10 @@ int i2c_del_driver(struct i2c_driver *driver)
mutex_lock(&core_lists); 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 /* 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 * attached. If so, detach them to be able to kill the driver
* afterwards. * afterwards.
...@@ -434,6 +490,7 @@ int i2c_del_driver(struct i2c_driver *driver) ...@@ -434,6 +490,7 @@ int i2c_del_driver(struct i2c_driver *driver)
} }
} }
unregister:
driver_unregister(&driver->driver); driver_unregister(&driver->driver);
list_del(&driver->list); list_del(&driver->list);
pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
......
...@@ -130,6 +130,7 @@ struct i2c_driver { ...@@ -130,6 +130,7 @@ struct i2c_driver {
* it's done by infrastructure. (NEW STYLE DRIVERS ONLY) * it's done by infrastructure. (NEW STYLE DRIVERS ONLY)
*/ */
int (*probe)(struct i2c_client *); int (*probe)(struct i2c_client *);
int (*remove)(struct i2c_client *);
/* driver model interfaces that don't relate to enumeration */ /* driver model interfaces that don't relate to enumeration */
void (*shutdown)(struct i2c_client *); void (*shutdown)(struct i2c_client *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment