]> err.no Git - linux-2.6/blobdiff - drivers/i2c/i2c-core.c
Merge branch 'upstream' of git://electric-eye.fr.zoreil.com/home/romieu/linux-2.6...
[linux-2.6] / drivers / i2c / i2c-core.c
index d16b4998c4c2f69ae9a17b21d8ec20fd53b9e369..a45155f799d4405dae2d67ca06d7168f64fe9d3d 100644 (file)
 #include <linux/idr.h>
 #include <linux/seq_file.h>
 #include <linux/platform_device.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 
 static LIST_HEAD(adapters);
 static LIST_HEAD(drivers);
-static DECLARE_MUTEX(core_lists);
+static DEFINE_MUTEX(core_lists);
 static DEFINE_IDR(i2c_adapter_idr);
 
 /* match always succeeds, as we want the probe() to tell if we really accept this match */
@@ -63,13 +64,6 @@ static int i2c_bus_resume(struct device * dev)
        return rc;
 }
 
-struct bus_type i2c_bus_type = {
-       .name =         "i2c",
-       .match =        i2c_device_match,
-       .suspend =      i2c_bus_suspend,
-       .resume =       i2c_bus_resume,
-};
-
 static int i2c_device_probe(struct device *dev)
 {
        return -ENODEV;
@@ -80,6 +74,15 @@ static int i2c_device_remove(struct device *dev)
        return 0;
 }
 
+struct bus_type i2c_bus_type = {
+       .name =         "i2c",
+       .match =        i2c_device_match,
+       .probe =        i2c_device_probe,
+       .remove =       i2c_device_remove,
+       .suspend =      i2c_bus_suspend,
+       .resume =       i2c_bus_resume,
+};
+
 void i2c_adapter_dev_release(struct device *dev)
 {
        struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
@@ -90,8 +93,6 @@ struct device_driver i2c_adapter_driver = {
        .owner = THIS_MODULE,
        .name = "i2c_adapter",
        .bus = &i2c_bus_type,
-       .probe = i2c_device_probe,
-       .remove = i2c_device_remove,
 };
 
 static void i2c_adapter_class_dev_release(struct class_device *dev)
@@ -153,7 +154,7 @@ int i2c_add_adapter(struct i2c_adapter *adap)
        struct list_head   *item;
        struct i2c_driver  *driver;
 
-       down(&core_lists);
+       mutex_lock(&core_lists);
 
        if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) {
                res = -ENOMEM;
@@ -168,8 +169,8 @@ int i2c_add_adapter(struct i2c_adapter *adap)
        }
 
        adap->nr =  id & MAX_ID_MASK;
-       init_MUTEX(&adap->bus_lock);
-       init_MUTEX(&adap->clist_lock);
+       mutex_init(&adap->bus_lock);
+       mutex_init(&adap->clist_lock);
        list_add_tail(&adap->list,&adapters);
        INIT_LIST_HEAD(&adap->clients);
 
@@ -203,7 +204,7 @@ int i2c_add_adapter(struct i2c_adapter *adap)
        }
 
 out_unlock:
-       up(&core_lists);
+       mutex_unlock(&core_lists);
        return res;
 }
 
@@ -216,7 +217,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
        struct i2c_client *client;
        int res = 0;
 
-       down(&core_lists);
+       mutex_lock(&core_lists);
 
        /* First make sure that this adapter was ever added */
        list_for_each_entry(adap_from_list, &adapters, list) {
@@ -235,7 +236,8 @@ int i2c_del_adapter(struct i2c_adapter *adap)
                if (driver->detach_adapter)
                        if ((res = driver->detach_adapter(adap))) {
                                dev_err(&adap->dev, "detach_adapter failed "
-                                       "for driver [%s]\n", driver->name);
+                                       "for driver [%s]\n",
+                                       driver->driver.name);
                                goto out_unlock;
                        }
        }
@@ -245,10 +247,6 @@ int i2c_del_adapter(struct i2c_adapter *adap)
        list_for_each_safe(item, _n, &adap->clients) {
                client = list_entry(item, struct i2c_client, list);
 
-               /* detaching devices is unconditional of the set notify
-                * flag, as _all_ clients that reside on the adapter
-                * must be deleted, as this would cause invalid states.
-                */
                if ((res=client->driver->detach_client(client))) {
                        dev_err(&adap->dev, "detach_client failed for client "
                                "[%s] at address 0x%02x\n", client->name,
@@ -275,7 +273,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
        dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
 
  out_unlock:
-       up(&core_lists);
+       mutex_unlock(&core_lists);
        return res;
 }
 
@@ -286,27 +284,24 @@ int i2c_del_adapter(struct i2c_adapter *adap)
  * chips.
  */
 
-int i2c_add_driver(struct i2c_driver *driver)
+int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
 {
        struct list_head   *item;
        struct i2c_adapter *adapter;
-       int res = 0;
-
-       down(&core_lists);
+       int res;
 
        /* add the driver to the list of i2c drivers in the driver core */
-       driver->driver.owner = driver->owner;
-       driver->driver.name = driver->name;
+       driver->driver.owner = owner;
        driver->driver.bus = &i2c_bus_type;
-       driver->driver.probe = i2c_device_probe;
-       driver->driver.remove = i2c_device_remove;
 
        res = driver_register(&driver->driver);
        if (res)
-               goto out_unlock;
+               return res;
        
+       mutex_lock(&core_lists);
+
        list_add_tail(&driver->list,&drivers);
-       pr_debug("i2c-core: driver [%s] registered\n", driver->name);
+       pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
 
        /* now look for instances of driver on our adapters */
        if (driver->attach_adapter) {
@@ -316,10 +311,10 @@ int i2c_add_driver(struct i2c_driver *driver)
                }
        }
 
- out_unlock:
-       up(&core_lists);
-       return res;
+       mutex_unlock(&core_lists);
+       return 0;
 }
+EXPORT_SYMBOL(i2c_register_driver);
 
 int i2c_del_driver(struct i2c_driver *driver)
 {
@@ -329,22 +324,19 @@ int i2c_del_driver(struct i2c_driver *driver)
        
        int res = 0;
 
-       down(&core_lists);
+       mutex_lock(&core_lists);
 
        /* 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.
-        *
-        * Removing clients does not depend on the notify flag, else
-        * invalid operation might (will!) result, when using stale client
-        * pointers.
         */
        list_for_each(item1,&adapters) {
                adap = list_entry(item1, struct i2c_adapter, list);
                if (driver->detach_adapter) {
                        if ((res = driver->detach_adapter(adap))) {
                                dev_err(&adap->dev, "detach_adapter failed "
-                                       "for driver [%s]\n", driver->name);
+                                       "for driver [%s]\n",
+                                       driver->driver.name);
                                goto out_unlock;
                        }
                } else {
@@ -368,10 +360,10 @@ int i2c_del_driver(struct i2c_driver *driver)
 
        driver_unregister(&driver->driver);
        list_del(&driver->list);
-       pr_debug("i2c-core: driver [%s] unregistered\n", driver->name);
+       pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
 
  out_unlock:
-       up(&core_lists);
+       mutex_unlock(&core_lists);
        return 0;
 }
 
@@ -392,9 +384,9 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr)
 {
        int rval;
 
-       down(&adapter->clist_lock);
+       mutex_lock(&adapter->clist_lock);
        rval = __i2c_check_addr(adapter, addr);
-       up(&adapter->clist_lock);
+       mutex_unlock(&adapter->clist_lock);
 
        return rval;
 }
@@ -403,13 +395,13 @@ int i2c_attach_client(struct i2c_client *client)
 {
        struct i2c_adapter *adapter = client->adapter;
 
-       down(&adapter->clist_lock);
+       mutex_lock(&adapter->clist_lock);
        if (__i2c_check_addr(client->adapter, client->addr)) {
-               up(&adapter->clist_lock);
+               mutex_unlock(&adapter->clist_lock);
                return -EBUSY;
        }
        list_add_tail(&client->list,&adapter->clients);
-       up(&adapter->clist_lock);
+       mutex_unlock(&adapter->clist_lock);
        
        if (adapter->client_register)  {
                if (adapter->client_register(client))  {
@@ -458,12 +450,12 @@ int i2c_detach_client(struct i2c_client *client)
                }
        }
 
-       down(&adapter->clist_lock);
+       mutex_lock(&adapter->clist_lock);
        list_del(&client->list);
        init_completion(&client->released);
        device_remove_file(&client->dev, &dev_attr_client_name);
        device_unregister(&client->dev);
-       up(&adapter->clist_lock);
+       mutex_unlock(&adapter->clist_lock);
        wait_for_completion(&client->released);
 
  out:
@@ -473,10 +465,10 @@ int i2c_detach_client(struct i2c_client *client)
 static int i2c_inc_use_client(struct i2c_client *client)
 {
 
-       if (!try_module_get(client->driver->owner))
+       if (!try_module_get(client->driver->driver.owner))
                return -ENODEV;
        if (!try_module_get(client->adapter->owner)) {
-               module_put(client->driver->owner);
+               module_put(client->driver->driver.owner);
                return -ENODEV;
        }
 
@@ -485,7 +477,7 @@ static int i2c_inc_use_client(struct i2c_client *client)
 
 static void i2c_dec_use_client(struct i2c_client *client)
 {
-       module_put(client->driver->owner);
+       module_put(client->driver->driver.owner);
        module_put(client->adapter->owner);
 }
 
@@ -497,14 +489,9 @@ int i2c_use_client(struct i2c_client *client)
        if (ret)
                return ret;
 
-       if (client->usage_count > 0)
-               goto busy;
        client->usage_count++;
 
        return 0;
- busy:
-       i2c_dec_use_client(client);
-       return -EBUSY;
 }
 
 int i2c_release_client(struct i2c_client *client)
@@ -526,19 +513,19 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
        struct list_head  *item;
        struct i2c_client *client;
 
-       down(&adap->clist_lock);
+       mutex_lock(&adap->clist_lock);
        list_for_each(item,&adap->clients) {
                client = list_entry(item, struct i2c_client, list);
-               if (!try_module_get(client->driver->owner))
+               if (!try_module_get(client->driver->driver.owner))
                        continue;
                if (NULL != client->driver->command) {
-                       up(&adap->clist_lock);
+                       mutex_unlock(&adap->clist_lock);
                        client->driver->command(client,cmd,arg);
-                       down(&adap->clist_lock);
+                       mutex_lock(&adap->clist_lock);
                }
-               module_put(client->driver->owner);
+               module_put(client->driver->driver.owner);
        }
-       up(&adap->clist_lock);
+       mutex_unlock(&adap->clist_lock);
 }
 
 static int __init i2c_init(void)
@@ -582,9 +569,9 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
                }
 #endif
 
-               down(&adap->bus_lock);
+               mutex_lock(&adap->bus_lock);
                ret = adap->algo->master_xfer(adap,msgs,num);
-               up(&adap->bus_lock);
+               mutex_unlock(&adap->bus_lock);
 
                return ret;
        } else {
@@ -792,12 +779,12 @@ struct i2c_adapter* i2c_get_adapter(int id)
 {
        struct i2c_adapter *adapter;
        
-       down(&core_lists);
+       mutex_lock(&core_lists);
        adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
        if (adapter && !try_module_get(adapter->owner))
                adapter = NULL;
 
-       up(&core_lists);
+       mutex_unlock(&core_lists);
        return adapter;
 }
 
@@ -929,15 +916,14 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
 }
 
 s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
-                              u8 length, u8 *values)
+                              u8 length, const u8 *values)
 {
        union i2c_smbus_data data;
-       int i;
+
        if (length > I2C_SMBUS_BLOCK_MAX)
                length = I2C_SMBUS_BLOCK_MAX;
-       for (i = 1; i <= length; i++)
-               data.block[i] = values[i-1];
        data.block[0] = length;
+       memcpy(&data.block[1], values, length);
        return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
                              I2C_SMBUS_WRITE,command,
                              I2C_SMBUS_BLOCK_DATA,&data);
@@ -947,16 +933,28 @@ s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
 s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values)
 {
        union i2c_smbus_data data;
-       int i;
+
        if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
                              I2C_SMBUS_READ,command,
                              I2C_SMBUS_I2C_BLOCK_DATA,&data))
                return -1;
-       else {
-               for (i = 1; i <= data.block[0]; i++)
-                       values[i-1] = data.block[i];
-               return data.block[0];
-       }
+
+       memcpy(values, &data.block[1], data.block[0]);
+       return data.block[0];
+}
+
+s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command,
+                                  u8 length, const u8 *values)
+{
+       union i2c_smbus_data data;
+
+       if (length > I2C_SMBUS_BLOCK_MAX)
+               length = I2C_SMBUS_BLOCK_MAX;
+       data.block[0] = length;
+       memcpy(data.block + 1, values, length);
+       return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+                             I2C_SMBUS_WRITE, command,
+                             I2C_SMBUS_I2C_BLOCK_DATA, &data);
 }
 
 /* Simulate a SMBus command using the i2c protocol 
@@ -1117,10 +1115,10 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
        flags &= I2C_M_TEN | I2C_CLIENT_PEC;
 
        if (adapter->algo->smbus_xfer) {
-               down(&adapter->bus_lock);
+               mutex_lock(&adapter->bus_lock);
                res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
                                                command,size,data);
-               up(&adapter->bus_lock);
+               mutex_unlock(&adapter->bus_lock);
        } else
                res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
                                              command,size,data);
@@ -1137,7 +1135,6 @@ EXPORT_SYMBOL_GPL(i2c_bus_type);
 
 EXPORT_SYMBOL(i2c_add_adapter);
 EXPORT_SYMBOL(i2c_del_adapter);
-EXPORT_SYMBOL(i2c_add_driver);
 EXPORT_SYMBOL(i2c_del_driver);
 EXPORT_SYMBOL(i2c_attach_client);
 EXPORT_SYMBOL(i2c_detach_client);
@@ -1164,6 +1161,7 @@ EXPORT_SYMBOL(i2c_smbus_read_word_data);
 EXPORT_SYMBOL(i2c_smbus_write_word_data);
 EXPORT_SYMBOL(i2c_smbus_write_block_data);
 EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
+EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
 
 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C-Bus main module");