i2c: Support i2c_transfer in atomic contexts
authorMike Rapoport <mike@compulab.co.il>
Sun, 27 Jan 2008 17:14:50 +0000 (18:14 +0100)
committerJean Delvare <khali@hyperion.delvare>
Sun, 27 Jan 2008 17:14:50 +0000 (18:14 +0100)
Allow i2c_transfer to be called in contexts where sleeping is not allowed.
It is the reponsability of the caller to ensure that the underlying i2c bus
driver will not sleep either.

Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
drivers/i2c/i2c-core.c

index 7161f913de1498ff8ba857b89ecdc184013392be..ddd1b83f44d45ef4913eae28141daa8daeef60cb 100644 (file)
@@ -33,6 +33,8 @@
 #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>
 
@@ -861,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);