i2c: Support i2c_transfer in atomic contexts
[pandora-kernel.git] / drivers / i2c / i2c-core.c
index 3495ab4..ddd1b83 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
 #include <linux/completion.h>
+#include <linux/hardirq.h>
+#include <linux/irqflags.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
 #include "i2c-core.h"
 
 
-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,17 +321,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);
+       mutex_lock(&core_lock);
 
        /* Add the adapter to the driver core.
         * If the parent pointer is not set up,
@@ -355,15 +366,11 @@ 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:
@@ -392,11 +399,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)
@@ -441,7 +448,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
         */
@@ -450,7 +457,7 @@ retry:
                status = -EBUSY;
                idr_remove(&i2c_adapter_idr, id);
        }
-       mutex_unlock(&core_lists);
+       mutex_unlock(&core_lock);
        if (status == -EAGAIN)
                goto retry;
 
@@ -460,6 +467,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
@@ -471,11 +493,10 @@ EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
        struct list_head  *item, *_n;
-       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 */
        if (idr_find(&i2c_adapter_idr, adap->nr) != adap) {
@@ -485,16 +506,11 @@ int i2c_del_adapter(struct i2c_adapter *adap)
                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. */
@@ -532,7 +548,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);
@@ -575,9 +591,8 @@ 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 */
@@ -592,7 +607,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
                up(&i2c_adapter_class.sem);
        }
 
-       mutex_unlock(&core_lists);
+       mutex_unlock(&core_lock);
        return 0;
 }
 EXPORT_SYMBOL(i2c_register_driver);
@@ -608,7 +623,7 @@ void i2c_del_driver(struct i2c_driver *driver)
        struct i2c_client  *client;
        struct i2c_adapter *adap;
 
-       mutex_lock(&core_lists);
+       mutex_lock(&core_lock);
 
        /* new-style driver? */
        if (is_newstyle_driver(driver))
@@ -647,10 +662,9 @@ void i2c_del_driver(struct i2c_driver *driver)
 
  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);
 
@@ -849,7 +863,15 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
                }
 #endif
 
-               mutex_lock_nested(&adap->bus_lock, adap->level);
+               if (in_atomic() || irqs_disabled()) {
+                       ret = mutex_trylock(&adap->bus_lock);
+                       if (!ret)
+                               /* I2C activity is ongoing. */
+                               return -EAGAIN;
+               } else {
+                       mutex_lock_nested(&adap->bus_lock, adap->level);
+               }
+
                ret = adap->algo->master_xfer(adap,msgs,num);
                mutex_unlock(&adap->bus_lock);
 
@@ -1109,12 +1131,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);