[i2c] [patch 2.6.19-rc6 7/11] i2c driver remove()
David Brownell
david-b at pacbell.net
Sun Nov 26 00:01:24 CET 2006
More update for new style driver support: add a remove() method, and
use it in the relevant code paths.
Signed-off-by: David Brownell <dbrownell at users.sourceforge.net>
---
drivers/i2c/i2c-core.c | 64 ++++++++++++++++++++++++++++++++++++++++++-------
include/linux/i2c.h | 1
2 files changed, 57 insertions(+), 8 deletions(-)
Index: at91/include/linux/i2c.h
===================================================================
--- at91.orig/include/linux/i2c.h 2006-11-25 08:05:59.000000000 -0800
+++ at91/include/linux/i2c.h 2006-11-25 08:06:00.000000000 -0800
@@ -129,6 +129,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: at91/drivers/i2c/i2c-core.c
===================================================================
--- at91.orig/drivers/i2c/i2c-core.c 2006-11-25 08:05:59.000000000 -0800
+++ at91/drivers/i2c/i2c-core.c 2006-11-25 08:06:00.000000000 -0800
@@ -119,7 +119,15 @@ static int i2c_device_probe(struct devic
static int i2c_device_remove(struct device *dev)
{
- return 0;
+ struct i2c_driver *driver = to_i2c_driver(dev->driver);
+ int status;
+
+ if (!dev->driver || !driver->remove)
+ return 0;
+ status = driver->remove(to_i2c_client(dev));
+ if (status == 0)
+ dev->driver = NULL;
+ return status;
}
static void i2c_device_shutdown(struct device *dev)
@@ -213,12 +221,44 @@ static const struct attribute_group i2c_
.attrs = i2c_dev_attrs,
};
-/* ---------------------------------------------------
- * registering functions
- * ---------------------------------------------------
- */
-/* -----
+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) {
+ 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_add_adapter is called from within the algorithm layer,
* when a new hw adapter registers. A new device is register to be
* available for clients.
@@ -341,8 +381,16 @@ int i2c_del_adapter(struct i2c_adapter *
* it can fail; in which case we give up. */
list_for_each_safe(item, _n, &adap->clients) {
client = list_entry(item, struct i2c_client, list);
+ driver = client->driver;
+
+ /* new style */
+ if (!driver || driver->remove) {
+ i2c_unregister_device(client);
+ continue;
+ }
- if ((res=client->driver->detach_client(client))) {
+ /* legacy drivers create clients themselves */
+ if ((res = driver->detach_client(client))) {
dev_err(dev, "detach_client failed for client "
"[%s] at address 0x%02x\n", client->name,
client->addr);
@@ -384,7 +432,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",
More information about the i2c
mailing list