Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 77346
b: refs/heads/master
c: 9b766b8
h: refs/heads/master
v: v3
  • Loading branch information
David Brownell authored and Jean Delvare committed Jan 27, 2008
1 parent 5d7a7c9 commit 4d2597a
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 53 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0d227a7e724460bddcd603a1feb672267bcb0d6c
refs/heads/master: 9b766b814d6a5f31ca1e9da1ebc08164b9352941
78 changes: 46 additions & 32 deletions trunk/drivers/i2c/i2c-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,25 @@ static struct bus_type i2c_bus_type = {
.resume = i2c_device_resume,
};


/**
* i2c_verify_client - return parameter as i2c_client, or NULL
* @dev: device, probably from some driver model iterator
*
* When traversing the driver model tree, perhaps using driver model
* iterators like @device_for_each_child(), you can't assume very much
* about the nodes you find. Use this function to avoid oopses caused
* by wrongly treating some non-I2C device as an i2c_client.
*/
struct i2c_client *i2c_verify_client(struct device *dev)
{
return (dev->bus == &i2c_bus_type)
? to_i2c_client(dev)
: NULL;
}
EXPORT_SYMBOL(i2c_verify_client);


/**
* i2c_new_device - instantiate an i2c device for use with a new style driver
* @adap: the adapter managing the device
Expand Down Expand Up @@ -670,28 +689,19 @@ EXPORT_SYMBOL(i2c_del_driver);

/* ------------------------------------------------------------------------- */

static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
static int __i2c_check_addr(struct device *dev, void *addrp)
{
struct list_head *item;
struct i2c_client *client;
struct i2c_client *client = i2c_verify_client(dev);
int addr = *(int *)addrp;

list_for_each(item,&adapter->clients) {
client = list_entry(item, struct i2c_client, list);
if (client->addr == addr)
return -EBUSY;
}
if (client && client->addr == addr)
return -EBUSY;
return 0;
}

static int i2c_check_addr(struct i2c_adapter *adapter, int addr)
{
int rval;

mutex_lock(&adapter->clist_lock);
rval = __i2c_check_addr(adapter, addr);
mutex_unlock(&adapter->clist_lock);

return rval;
return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr);
}

int i2c_attach_client(struct i2c_client *client)
Expand All @@ -700,7 +710,7 @@ int i2c_attach_client(struct i2c_client *client)
int res = 0;

mutex_lock(&adapter->clist_lock);
if (__i2c_check_addr(client->adapter, client->addr)) {
if (i2c_check_addr(client->adapter, client->addr)) {
res = -EBUSY;
goto out_unlock;
}
Expand Down Expand Up @@ -804,24 +814,28 @@ void i2c_release_client(struct i2c_client *client)
}
EXPORT_SYMBOL(i2c_release_client);

struct i2c_cmd_arg {
unsigned cmd;
void *arg;
};

static int i2c_cmd(struct device *dev, void *_arg)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_cmd_arg *arg = _arg;

if (client && client->driver && client->driver->command)
client->driver->command(client, arg->cmd, arg->arg);
return 0;
}

void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
{
struct list_head *item;
struct i2c_client *client;
struct i2c_cmd_arg cmd_arg;

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->driver.owner))
continue;
if (NULL != client->driver->command) {
mutex_unlock(&adap->clist_lock);
client->driver->command(client,cmd,arg);
mutex_lock(&adap->clist_lock);
}
module_put(client->driver->driver.owner);
}
mutex_unlock(&adap->clist_lock);
cmd_arg.cmd = cmd;
cmd_arg.arg = arg;
device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd);
}
EXPORT_SYMBOL(i2c_clients_command);

Expand Down Expand Up @@ -1087,7 +1101,7 @@ i2c_new_probed_device(struct i2c_adapter *adap,
}

/* Check address availability */
if (__i2c_check_addr(adap, addr_list[i])) {
if (i2c_check_addr(adap, addr_list[i])) {
dev_dbg(&adap->dev, "Address 0x%02x already in "
"use, not probing\n", addr_list[i]);
continue;
Expand Down
29 changes: 12 additions & 17 deletions trunk/drivers/i2c/i2c-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,27 +182,22 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c
return ret;
}

static int i2cdev_check(struct device *dev, void *addrp)
{
struct i2c_client *client = i2c_verify_client(dev);

if (!client || client->addr != *(unsigned int *)addrp)
return 0;

return dev->driver ? -EBUSY : 0;
}

/* This address checking function differs from the one in i2c-core
in that it considers an address with a registered device, but no
bound driver, as NOT busy. */
driver bound to it, as NOT busy. */
static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
{
struct list_head *item;
struct i2c_client *client;
int res = 0;

mutex_lock(&adapter->clist_lock);
list_for_each(item, &adapter->clients) {
client = list_entry(item, struct i2c_client, list);
if (client->addr == addr) {
if (client->driver)
res = -EBUSY;
break;
}
}
mutex_unlock(&adapter->clist_lock);

return res;
return device_for_each_child(&adapter->dev, &addr, i2cdev_check);
}

static int i2cdev_ioctl(struct inode *inode, struct file *file,
Expand Down
8 changes: 5 additions & 3 deletions trunk/include/linux/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ struct i2c_driver {
* @irq: indicates the IRQ generated by this device (if any)
* @driver_name: Identifies new-style driver used with this device; also
* used as the module name for hotplug/coldplug modprobe support.
* @list: list of active/busy clients
* @list: list of active/busy clients (DEPRECATED)
* @released: used to synchronize client releases & detaches and references
*
* An i2c_client identifies a single device (i.e. chip) connected to an
Expand All @@ -176,11 +176,13 @@ struct i2c_client {
struct device dev; /* the device structure */
int irq; /* irq issued by device (or -1) */
char driver_name[KOBJ_NAME_LEN];
struct list_head list;
struct list_head list; /* DEPRECATED */
struct completion released;
};
#define to_i2c_client(d) container_of(d, struct i2c_client, dev)

extern struct i2c_client *i2c_verify_client(struct device *dev);

static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj)
{
struct device * const dev = container_of(kobj, struct device, kobj);
Expand Down Expand Up @@ -315,7 +317,7 @@ struct i2c_adapter {
struct device dev; /* the adapter device */

int nr;
struct list_head clients;
struct list_head clients; /* DEPRECATED */
char name[48];
struct completion dev_released;
};
Expand Down

0 comments on commit 4d2597a

Please sign in to comment.