[i2c] [patch 2.6.21-rc3-git +i2c 2/5] i2c stack can remove()
David Brownell
david-b at pacbell.net
Mon Mar 12 17:49:25 CET 2007
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 <dbrownell at users.sourceforge.net>
---
UPDATED: address the del_driver() issue, don't add separate interface
to unregister newstyle drivers, add and use is_newstyle_driver() for
better internal consistency
--- at91.orig/include/linux/i2c.h 2007-03-11 22:33:14.000000000 -0700
+++ at91/include/linux/i2c.h 2007-03-11 22:52:32.000000000 -0700
@@ -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 *);
--- at91.orig/drivers/i2c/i2c-core.c 2007-03-11 22:33:14.000000000 -0700
+++ at91/drivers/i2c/i2c-core.c 2007-03-11 23:24:15.000000000 -0700
@@ -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,42 @@ struct bus_type i2c_bus_type = {
.resume = i2c_device_resume,
};
+static void i2c_unregister_device(struct i2c_client *client)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct i2c_driver *driver = client->driver;
+ int status;
+
+ if (driver && !is_newstyle_driver(driver)) {
+ dev_err(&client->dev, "can't unregister devices "
+ "with legacy drivers\n");
+ WARN_ON(1);
+ return;
+ }
+
+ /* unbind driver */
+ if (driver) {
+ /* REVISIT driver model core would handle this for us, and
+ * once i2c_detach_client() stops updating lists, it should.
+ */
+ status = i2c_device_remove(&client->dev);
+ if (status < 0) {
+ dev_err(&client->dev, "unbind failed (%d)\n", status);
+ return;
+ }
+ }
+
+ /* now remove the device, and free its memory */
+ status = i2c_detach_client(client);
+ if (status < 0)
+ dev_err(&adap->dev, "detach failed (%d) for client [%s] "
+ "at address 0x%02x\n",
+ status, client->name, client->addr);
+ else
+ put_device(&client->dev);
+}
+
+
/* ------------------------------------------------------------------------- */
/* I2C bus adapters -- one roots each I2C or SMBUS segment */
@@ -311,9 +365,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);
@@ -356,7 +420,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 +456,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 +470,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 +506,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);
More information about the i2c
mailing list