#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(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)
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,
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;
}
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)
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
*/
status = -EBUSY;
idr_remove(&i2c_adapter_idr, id);
}
- mutex_unlock(&core_lists);
+ mutex_unlock(&core_lock);
if (status == -EAGAIN)
goto 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
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. */
/* 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);
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);
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);
*/
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))
* 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 "
}
}
}
+ 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);
}
list_add_tail(&client->list,&adapter->clients);
- client->usage_count = 0;
-
client->dev.parent = &client->adapter->dev;
client->dev.bus = &i2c_bus_type;
struct i2c_adapter *adapter = client->adapter;
int res = 0;
- if (client->usage_count > 0) {
- dev_warn(&client->dev, "Client [%s] still busy, "
- "can't detach\n", client->name);
- return -EBUSY;
- }
-
if (adapter->client_unregister) {
res = adapter->client_unregister(client);
if (res) {
}
EXPORT_SYMBOL(i2c_detach_client);
-static int i2c_inc_use_client(struct i2c_client *client)
-{
-
- if (!try_module_get(client->driver->driver.owner))
- return -ENODEV;
- if (!try_module_get(client->adapter->owner)) {
- module_put(client->driver->driver.owner);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void i2c_dec_use_client(struct i2c_client *client)
-{
- module_put(client->driver->driver.owner);
- module_put(client->adapter->owner);
-}
-
-int i2c_use_client(struct i2c_client *client)
+/**
+ * i2c_use_client - increments the reference count of the i2c client structure
+ * @client: the client being referenced
+ *
+ * Each live reference to a client should be refcounted. The driver model does
+ * that automatically as part of driver binding, so that most drivers don't
+ * need to do this explicitly: they hold a reference until they're unbound
+ * from the device.
+ *
+ * A pointer to the client with the incremented reference counter is returned.
+ */
+struct i2c_client *i2c_use_client(struct i2c_client *client)
{
- int ret;
-
- ret = i2c_inc_use_client(client);
- if (ret)
- return ret;
-
- client->usage_count++;
-
- return 0;
+ get_device(&client->dev);
+ return client;
}
EXPORT_SYMBOL(i2c_use_client);
-int i2c_release_client(struct i2c_client *client)
+/**
+ * i2c_release_client - release a use of the i2c client structure
+ * @client: the client being no longer referenced
+ *
+ * Must be called when a user of a client is finished with it.
+ */
+void i2c_release_client(struct i2c_client *client)
{
- if (!client->usage_count) {
- pr_debug("i2c-core: %s used one too many times\n",
- __FUNCTION__);
- return -EPERM;
- }
-
- client->usage_count--;
- i2c_dec_use_client(client);
-
- return 0;
+ put_device(&client->dev);
}
EXPORT_SYMBOL(i2c_release_client);
}
#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);
}
int i2c_probe(struct i2c_adapter *adapter,
- struct i2c_client_address_data *address_data,
+ const struct i2c_client_address_data *address_data,
int (*found_proc) (struct i2c_adapter *, int, int))
{
int i, err;
/* Force entries are done first, and are not affected by ignore
entries */
if (address_data->forces) {
- unsigned short **forces = address_data->forces;
+ const unsigned short * const *forces = address_data->forces;
int kind;
for (kind = 0; forces[kind]; kind++) {
{
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);