[i2c] [patch 2/5] i2c can remove()
David Brownell
david-b at pacbell.net
Thu Feb 15 09:41:59 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>
---
drivers/i2c/i2c-core.c | 77 +++++++++++++++++++++++++++++++++++++++++++++----
include/linux/i2c.h | 1
2 files changed, 72 insertions(+), 6 deletions(-)
Index: i2c/include/linux/i2c.h
===================================================================
--- i2c.orig/include/linux/i2c.h 2007-02-15 00:00:03.000000000 -0800
+++ i2c/include/linux/i2c.h 2007-02-15 00:00:04.000000000 -0800
@@ -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 *);
Index: i2c/drivers/i2c/i2c-core.c
===================================================================
--- i2c.orig/drivers/i2c/i2c-core.c 2007-02-15 00:00:03.000000000 -0800
+++ i2c/drivers/i2c/i2c-core.c 2007-02-15 00:00:04.000000000 -0800
@@ -99,7 +99,19 @@ 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)
+ return 0;
+ status = driver->remove(client);
+ if (status == 0)
+ client->driver = NULL;
+ return status;
}
static void i2c_device_shutdown(struct device *dev)
@@ -168,6 +180,43 @@ 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 && !driver->remove) {
+ 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);
+
+}
+
+
/* ------------------------------------------------------------------------- */
void i2c_adapter_dev_release(struct device *dev)
@@ -321,9 +370,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;
+
+ /* new style, follow standard driver model */
+ if (!driver || driver->remove) {
+ 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 "
"[%s] at address 0x%02x\n", client->name,
client->addr);
@@ -367,7 +426,7 @@ int i2c_register_driver(struct module *o
int res;
/* new style driver methods can't mix with legacy ones */
- if (driver->probe) {
+ if (driver->probe || driver->remove) {
if (driver->attach_adapter || driver->detach_adapter
|| driver->detach_client) {
pr_debug("i2c-core: driver [%s] is confused\n",
@@ -411,12 +470,17 @@ int i2c_del_driver(struct i2c_driver *dr
int res = 0;
- mutex_lock(&core_lists);
+ /* For new-style drivers, driver model unregistration handles
+ * all the unbind-from-device logic. Just Do It.
+ */
+ if (driver->remove)
+ 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.
*/
+ mutex_lock(&core_lists);
list_for_each(item1,&adapters) {
adap = list_entry(item1, struct i2c_adapter, list);
if (driver->detach_adapter) {
@@ -444,12 +508,13 @@ int i2c_del_driver(struct i2c_driver *dr
}
}
}
+out_unlock:
+ mutex_unlock(&core_lists);
+unregister:
driver_unregister(&driver->driver);
pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
- out_unlock:
- mutex_unlock(&core_lists);
return 0;
}
More information about the i2c
mailing list