[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