[i2c] [patch 2.6.21-rc3-git +i2c 2/5] i2c stack can remove()
David Brownell
david-b at pacbell.net
Fri Mar 9 06:11:09 CET 2007
More update for new style driver support: add a remove() method, and
use it in the relevant code paths. Also add i2c_unregister_driver()
for the exclusive use of new-style drivers.
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 | 100 +++++++++++++++++++++++++++++++++++++++++++++++--
include/linux/i2c.h | 3 +
2 files changed, 99 insertions(+), 4 deletions(-)
Index: at91/include/linux/i2c.h
===================================================================
--- at91.orig/include/linux/i2c.h 2007-03-08 13:47:48.000000000 -0800
+++ at91/include/linux/i2c.h 2007-03-08 13:47:49.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 *);
@@ -302,6 +303,8 @@ extern int i2c_add_adapter(struct i2c_ad
extern int i2c_del_adapter(struct i2c_adapter *);
extern int i2c_register_driver(struct module *, struct i2c_driver *);
+extern void i2c_unregister_driver(struct i2c_driver *);
+
extern int i2c_del_driver(struct i2c_driver *);
static inline int i2c_add_driver(struct i2c_driver *driver)
Index: at91/drivers/i2c/i2c-core.c
===================================================================
--- at91.orig/drivers/i2c/i2c-core.c 2007-03-08 13:47:48.000000000 -0800
+++ at91/drivers/i2c/i2c-core.c 2007-03-08 13:47:49.000000000 -0800
@@ -100,7 +100,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 +194,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 && !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);
+}
+
+
/* ------------------------------------------------------------------------- */
/* I2C bus adapters -- one roots each I2C or SMBUS segment */
@@ -311,9 +364,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 || driver->remove) {
+ 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 +419,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) {
printk(KERN_WARNING
@@ -392,6 +455,32 @@ int i2c_register_driver(struct module *o
}
EXPORT_SYMBOL(i2c_register_driver);
+/**
+ * i2c_unregister_driver - unregister non-legacy I2C driver
+ * @driver: the driver being unregistered
+ *
+ * Following the normal driver model conventions, when drivers are
+ * unregistered they receive remove() calls to unbind each i2c_client
+ * that had previously been bound to them by probe(). Those i2c_client
+ * handles must not be used after remove() returns; a different driver
+ * could have been bound to that device after remove() returns.
+ */
+void i2c_unregister_driver(struct i2c_driver *driver)
+{
+ if (!driver->remove) {
+ printk(KERN_WARNING "i2c-core: legacy driver [%s] "
+ "can't use i2c_unregister_driver\n",
+ driver->driver.name);
+ return;
+ }
+ driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL(i2c_unregister_driver);
+
+/**
+ * i2c_del_driver - unregister legacy I2C driver
+ * @driver: the driver being unregistered
+ */
int i2c_del_driver(struct i2c_driver *driver)
{
struct list_head *item1, *item2, *_n;
@@ -400,12 +489,15 @@ int i2c_del_driver(struct i2c_driver *dr
int res = 0;
- mutex_lock(&core_lists);
+ /* new-style drivers use i2c_unregister_driver() */
+ if (driver->remove)
+ return -EINVAL;
/* 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) {
More information about the i2c
mailing list