[i2c] [patch 2/5] i2c can remove()
Jean Delvare
khali at linux-fr.org
Fri Mar 2 18:09:41 CET 2007
Hi David,
On Thu, 15 Feb 2007 00:41:59 -0800, David Brownell wrote:
> 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;
> + }
I'm not sure I agree with this. Isn't it valid for a (device driver
model compliant) driver not to have a remove() method? Also, I don't
quite see how this method would ever be called for a legacy driver, as
you check explicitely against that at registration time.
> +
> + /* unbind driver */
> + if (driver) {
> + /* REVISIT driver model core would handle this for us, and
> + * once i2c_detach_client() stops updating lists, it should.
> + */
Actually my current i2c stack no longer has the faulty i2c_adapter
driver, so it should be possible to remove the duplicate list
management. Could you provide a patch doing this? Would it let you
make this one patch cleaner?
> + 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);
Am I right assuming that we're in big trouble if i2c_detach_client()
actually fails?
> +
Extra blank line.
> +}
> +
> +
> /* ------------------------------------------------------------------------- */
>
> 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.
I would avoid the extra caps. Don't want to be sued by some company for
using their trademark without permission ;)
> + */
> + 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;
> }
It's not correct for legacy drivers, I think. The original code did
_not_ call driver_unregister on error, and now it does. I don't think
your patch is supposed to change anything for legacy drivers, is it?
When the patches are ready, I think I'll fold this patch into the first
one (i2c stack can probe()). Each doesn't make much sense without the
other.
--
Jean Delvare
More information about the i2c
mailing list