]> err.no Git - linux-2.6/blobdiff - drivers/i2c/i2c-core.c
i2c-i801: Document which chip support what feature
[linux-2.6] / drivers / i2c / i2c-core.c
index f75344ac4663af1a753255767964199a1aac30d5..7161f913de1498ff8ba857b89ecdc184013392be 100644 (file)
 #include <linux/mutex.h>
 #include <linux/completion.h>
 #include <asm/uaccess.h>
+#include <asm/semaphore.h>
 
 #include "i2c-core.h"
 
 
-static LIST_HEAD(adapters);
-static LIST_HEAD(drivers);
-static DEFINE_MUTEX(core_lists);
+static DEFINE_MUTEX(core_lock);
 static DEFINE_IDR(i2c_adapter_idr);
 
 #define is_newstyle_driver(d) ((d)->probe || (d)->remove)
@@ -320,18 +319,27 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
        mutex_unlock(&__i2c_board_lock);
 }
 
+static int i2c_do_add_adapter(struct device_driver *d, void *data)
+{
+       struct i2c_driver *driver = to_i2c_driver(d);
+       struct i2c_adapter *adap = data;
+
+       if (driver->attach_adapter) {
+               /* We ignore the return code; if it fails, too bad */
+               driver->attach_adapter(adap);
+       }
+       return 0;
+}
+
 static int i2c_register_adapter(struct i2c_adapter *adap)
 {
-       int res = 0;
-       struct list_head   *item;
-       struct i2c_driver  *driver;
+       int res = 0, dummy;
 
        mutex_init(&adap->bus_lock);
        mutex_init(&adap->clist_lock);
        INIT_LIST_HEAD(&adap->clients);
 
-       mutex_lock(&core_lists);
-       list_add_tail(&adap->list, &adapters);
+       mutex_lock(&core_lock);
 
        /* Add the adapter to the driver core.
         * If the parent pointer is not set up,
@@ -356,19 +364,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
                i2c_scan_static_board_info(adap);
 
        /* let legacy drivers scan this bus for matching devices */
-       list_for_each(item,&drivers) {
-               driver = list_entry(item, struct i2c_driver, list);
-               if (driver->attach_adapter)
-                       /* We ignore the return code; if it fails, too bad */
-                       driver->attach_adapter(adap);
-       }
+       dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
+                                i2c_do_add_adapter);
 
 out_unlock:
-       mutex_unlock(&core_lists);
+       mutex_unlock(&core_lock);
        return res;
 
 out_list:
-       list_del(&adap->list);
        idr_remove(&i2c_adapter_idr, adap->nr);
        goto out_unlock;
 }
@@ -394,11 +397,11 @@ retry:
        if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
                return -ENOMEM;
 
-       mutex_lock(&core_lists);
+       mutex_lock(&core_lock);
        /* "above" here means "above or equal to", sigh */
        res = idr_get_new_above(&i2c_adapter_idr, adapter,
                                __i2c_first_dynamic_bus_num, &id);
-       mutex_unlock(&core_lists);
+       mutex_unlock(&core_lock);
 
        if (res < 0) {
                if (res == -EAGAIN)
@@ -443,7 +446,7 @@ retry:
        if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
                return -ENOMEM;
 
-       mutex_lock(&core_lists);
+       mutex_lock(&core_lock);
        /* "above" here means "above or equal to", sigh;
         * we need the "equal to" result to force the result
         */
@@ -452,7 +455,7 @@ retry:
                status = -EBUSY;
                idr_remove(&i2c_adapter_idr, id);
        }
-       mutex_unlock(&core_lists);
+       mutex_unlock(&core_lock);
        if (status == -EAGAIN)
                goto retry;
 
@@ -462,6 +465,21 @@ retry:
 }
 EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
 
+static int i2c_do_del_adapter(struct device_driver *d, void *data)
+{
+       struct i2c_driver *driver = to_i2c_driver(d);
+       struct i2c_adapter *adapter = data;
+       int res;
+
+       if (!driver->detach_adapter)
+               return 0;
+       res = driver->detach_adapter(adapter);
+       if (res)
+               dev_err(&adapter->dev, "detach_adapter failed (%d) "
+                       "for driver [%s]\n", res, driver->driver.name);
+       return res;
+}
+
 /**
  * i2c_del_adapter - unregister I2C adapter
  * @adap: the adapter being unregistered
@@ -473,35 +491,24 @@ EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
        struct list_head  *item, *_n;
-       struct i2c_adapter *adap_from_list;
-       struct i2c_driver *driver;
        struct i2c_client *client;
        int res = 0;
 
-       mutex_lock(&core_lists);
+       mutex_lock(&core_lock);
 
        /* First make sure that this adapter was ever added */
-       list_for_each_entry(adap_from_list, &adapters, list) {
-               if (adap_from_list == adap)
-                       break;
-       }
-       if (adap_from_list != adap) {
+       if (idr_find(&i2c_adapter_idr, adap->nr) != adap) {
                pr_debug("i2c-core: attempting to delete unregistered "
                         "adapter [%s]\n", adap->name);
                res = -EINVAL;
                goto out_unlock;
        }
 
-       list_for_each(item,&drivers) {
-               driver = list_entry(item, struct i2c_driver, list);
-               if (driver->detach_adapter)
-                       if ((res = driver->detach_adapter(adap))) {
-                               dev_err(&adap->dev, "detach_adapter failed "
-                                       "for driver [%s]\n",
-                                       driver->driver.name);
-                               goto out_unlock;
-                       }
-       }
+       /* Tell drivers about this removal */
+       res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
+                              i2c_do_del_adapter);
+       if (res)
+               goto out_unlock;
 
        /* detach any active clients. This must be done first, because
         * it can fail; in which case we give up. */
@@ -529,7 +536,6 @@ int i2c_del_adapter(struct i2c_adapter *adap)
        /* clean up the sysfs representation */
        init_completion(&adap->dev_released);
        device_unregister(&adap->dev);
-       list_del(&adap->list);
 
        /* wait for sysfs to drop all references */
        wait_for_completion(&adap->dev_released);
@@ -540,7 +546,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
        dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
 
  out_unlock:
-       mutex_unlock(&core_lists);
+       mutex_unlock(&core_lock);
        return res;
 }
 EXPORT_SYMBOL(i2c_del_adapter);
@@ -583,21 +589,23 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
        if (res)
                return res;
 
-       mutex_lock(&core_lists);
+       mutex_lock(&core_lock);
 
-       list_add_tail(&driver->list,&drivers);
        pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
 
        /* legacy drivers scan i2c busses directly */
        if (driver->attach_adapter) {
                struct i2c_adapter *adapter;
 
-               list_for_each_entry(adapter, &adapters, list) {
+               down(&i2c_adapter_class.sem);
+               list_for_each_entry(adapter, &i2c_adapter_class.devices,
+                                   dev.node) {
                        driver->attach_adapter(adapter);
                }
+               up(&i2c_adapter_class.sem);
        }
 
-       mutex_unlock(&core_lists);
+       mutex_unlock(&core_lock);
        return 0;
 }
 EXPORT_SYMBOL(i2c_register_driver);
@@ -609,11 +617,11 @@ EXPORT_SYMBOL(i2c_register_driver);
  */
 void i2c_del_driver(struct i2c_driver *driver)
 {
-       struct list_head   *item1, *item2, *_n;
+       struct list_head   *item2, *_n;
        struct i2c_client  *client;
        struct i2c_adapter *adap;
 
-       mutex_lock(&core_lists);
+       mutex_lock(&core_lock);
 
        /* new-style driver? */
        if (is_newstyle_driver(driver))
@@ -623,8 +631,8 @@ void i2c_del_driver(struct i2c_driver *driver)
         * attached. If so, detach them to be able to kill the driver
         * afterwards.
         */
-       list_for_each(item1,&adapters) {
-               adap = list_entry(item1, struct i2c_adapter, list);
+       down(&i2c_adapter_class.sem);
+       list_for_each_entry(adap, &i2c_adapter_class.devices, dev.node) {
                if (driver->detach_adapter) {
                        if (driver->detach_adapter(adap)) {
                                dev_err(&adap->dev, "detach_adapter failed "
@@ -648,13 +656,13 @@ void i2c_del_driver(struct i2c_driver *driver)
                        }
                }
        }
+       up(&i2c_adapter_class.sem);
 
  unregister:
        driver_unregister(&driver->driver);
-       list_del(&driver->list);
        pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
 
-       mutex_unlock(&core_lists);
+       mutex_unlock(&core_lock);
 }
 EXPORT_SYMBOL(i2c_del_driver);
 
@@ -1113,12 +1121,12 @@ struct i2c_adapter* i2c_get_adapter(int id)
 {
        struct i2c_adapter *adapter;
 
-       mutex_lock(&core_lists);
+       mutex_lock(&core_lock);
        adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
        if (adapter && !try_module_get(adapter->owner))
                adapter = NULL;
 
-       mutex_unlock(&core_lists);
+       mutex_unlock(&core_lock);
        return adapter;
 }
 EXPORT_SYMBOL(i2c_get_adapter);