[i2c] [patch 2.6.20-rc1 2/6] part II: I2C supports remove()

David Brownell david-b at pacbell.net
Tue Dec 19 00:05:13 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 |   70 +++++++++++++++++++++++++++++++++++++++++++------
 include/linux/i2c.h    |    1 
 2 files changed, 63 insertions(+), 8 deletions(-)

Index: g26/include/linux/i2c.h
===================================================================
--- g26.orig/include/linux/i2c.h	2006-12-18 13:26:27.000000000 -0800
+++ g26/include/linux/i2c.h	2006-12-18 13:26:33.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: g26/drivers/i2c/i2c-core.c
===================================================================
--- g26.orig/drivers/i2c/i2c-core.c	2006-12-18 13:26:27.000000000 -0800
+++ g26/drivers/i2c/i2c-core.c	2006-12-18 13:26:33.000000000 -0800
@@ -124,7 +124,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)
@@ -215,12 +227,45 @@ 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) {
+		/* REVISIT driver model core should handle this for us ... */
+		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.
@@ -342,8 +387,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);
@@ -385,7 +438,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",
@@ -466,6 +519,7 @@ int i2c_del_driver(struct i2c_driver *dr
 						client->addr);
 					goto out_unlock;
 				}
+				/* for old-style drivers, device is now gone */
 			}
 		}
 	}



More information about the i2c mailing list