diff options
author | David Brownell <david-b@pacbell.net> | 2008-01-27 12:14:51 -0500 |
---|---|---|
committer | Jean Delvare <khali@hyperion.delvare> | 2008-01-27 12:14:51 -0500 |
commit | 9b766b814d6a5f31ca1e9da1ebc08164b9352941 (patch) | |
tree | ce6256c11002c356ee8b632f2a7d08793dd30f82 /drivers | |
parent | 0d227a7e724460bddcd603a1feb672267bcb0d6c (diff) |
i2c: Stop using the redundant client list
The i2c_adapter.clients list of i2c_client nodes duplicates driver
model state. This patch starts removing that list, letting us remove
most existing users of those i2c-core lists.
* The core I2C code now iterates over the driver model's list instead
of the i2c-internal one in some places where it's safe:
- Passing a command/ioctl to each client, a mechanims
used almost exclusively by DVB adapters;
- Device address checking, in both i2c-core and i2c-dev.
* Provide i2c_verify_client() to use with driver model iterators.
* Flag the relevant i2c_adapter and i2c_client fields as deprecated,
to help prevent new users from appearing.
For the moment the list needs to stick around, since some issues show
up when deleting devices created by legacy I2C drivers. (They don't
follow standard driver model rules. Removing those devices can cause
self-deadlocks.)
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/i2c-core.c | 78 | ||||
-rw-r--r-- | drivers/i2c/i2c-dev.c | 29 |
2 files changed, 58 insertions, 49 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index ddd1b83f44d4..c8bbd672226b 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -199,6 +199,25 @@ static struct bus_type i2c_bus_type = { | |||
199 | .resume = i2c_device_resume, | 199 | .resume = i2c_device_resume, |
200 | }; | 200 | }; |
201 | 201 | ||
202 | |||
203 | /** | ||
204 | * i2c_verify_client - return parameter as i2c_client, or NULL | ||
205 | * @dev: device, probably from some driver model iterator | ||
206 | * | ||
207 | * When traversing the driver model tree, perhaps using driver model | ||
208 | * iterators like @device_for_each_child(), you can't assume very much | ||
209 | * about the nodes you find. Use this function to avoid oopses caused | ||
210 | * by wrongly treating some non-I2C device as an i2c_client. | ||
211 | */ | ||
212 | struct i2c_client *i2c_verify_client(struct device *dev) | ||
213 | { | ||
214 | return (dev->bus == &i2c_bus_type) | ||
215 | ? to_i2c_client(dev) | ||
216 | : NULL; | ||
217 | } | ||
218 | EXPORT_SYMBOL(i2c_verify_client); | ||
219 | |||
220 | |||
202 | /** | 221 | /** |
203 | * i2c_new_device - instantiate an i2c device for use with a new style driver | 222 | * i2c_new_device - instantiate an i2c device for use with a new style driver |
204 | * @adap: the adapter managing the device | 223 | * @adap: the adapter managing the device |
@@ -670,28 +689,19 @@ EXPORT_SYMBOL(i2c_del_driver); | |||
670 | 689 | ||
671 | /* ------------------------------------------------------------------------- */ | 690 | /* ------------------------------------------------------------------------- */ |
672 | 691 | ||
673 | static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) | 692 | static int __i2c_check_addr(struct device *dev, void *addrp) |
674 | { | 693 | { |
675 | struct list_head *item; | 694 | struct i2c_client *client = i2c_verify_client(dev); |
676 | struct i2c_client *client; | 695 | int addr = *(int *)addrp; |
677 | 696 | ||
678 | list_for_each(item,&adapter->clients) { | 697 | if (client && client->addr == addr) |
679 | client = list_entry(item, struct i2c_client, list); | 698 | return -EBUSY; |
680 | if (client->addr == addr) | ||
681 | return -EBUSY; | ||
682 | } | ||
683 | return 0; | 699 | return 0; |
684 | } | 700 | } |
685 | 701 | ||
686 | static int i2c_check_addr(struct i2c_adapter *adapter, int addr) | 702 | static int i2c_check_addr(struct i2c_adapter *adapter, int addr) |
687 | { | 703 | { |
688 | int rval; | 704 | return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); |
689 | |||
690 | mutex_lock(&adapter->clist_lock); | ||
691 | rval = __i2c_check_addr(adapter, addr); | ||
692 | mutex_unlock(&adapter->clist_lock); | ||
693 | |||
694 | return rval; | ||
695 | } | 705 | } |
696 | 706 | ||
697 | int i2c_attach_client(struct i2c_client *client) | 707 | int i2c_attach_client(struct i2c_client *client) |
@@ -700,7 +710,7 @@ int i2c_attach_client(struct i2c_client *client) | |||
700 | int res = 0; | 710 | int res = 0; |
701 | 711 | ||
702 | mutex_lock(&adapter->clist_lock); | 712 | mutex_lock(&adapter->clist_lock); |
703 | if (__i2c_check_addr(client->adapter, client->addr)) { | 713 | if (i2c_check_addr(client->adapter, client->addr)) { |
704 | res = -EBUSY; | 714 | res = -EBUSY; |
705 | goto out_unlock; | 715 | goto out_unlock; |
706 | } | 716 | } |
@@ -804,24 +814,28 @@ void i2c_release_client(struct i2c_client *client) | |||
804 | } | 814 | } |
805 | EXPORT_SYMBOL(i2c_release_client); | 815 | EXPORT_SYMBOL(i2c_release_client); |
806 | 816 | ||
817 | struct i2c_cmd_arg { | ||
818 | unsigned cmd; | ||
819 | void *arg; | ||
820 | }; | ||
821 | |||
822 | static int i2c_cmd(struct device *dev, void *_arg) | ||
823 | { | ||
824 | struct i2c_client *client = i2c_verify_client(dev); | ||
825 | struct i2c_cmd_arg *arg = _arg; | ||
826 | |||
827 | if (client && client->driver && client->driver->command) | ||
828 | client->driver->command(client, arg->cmd, arg->arg); | ||
829 | return 0; | ||
830 | } | ||
831 | |||
807 | void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) | 832 | void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) |
808 | { | 833 | { |
809 | struct list_head *item; | 834 | struct i2c_cmd_arg cmd_arg; |
810 | struct i2c_client *client; | ||
811 | 835 | ||
812 | mutex_lock(&adap->clist_lock); | 836 | cmd_arg.cmd = cmd; |
813 | list_for_each(item,&adap->clients) { | 837 | cmd_arg.arg = arg; |
814 | client = list_entry(item, struct i2c_client, list); | 838 | device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd); |
815 | if (!try_module_get(client->driver->driver.owner)) | ||
816 | continue; | ||
817 | if (NULL != client->driver->command) { | ||
818 | mutex_unlock(&adap->clist_lock); | ||
819 | client->driver->command(client,cmd,arg); | ||
820 | mutex_lock(&adap->clist_lock); | ||
821 | } | ||
822 | module_put(client->driver->driver.owner); | ||
823 | } | ||
824 | mutex_unlock(&adap->clist_lock); | ||
825 | } | 839 | } |
826 | EXPORT_SYMBOL(i2c_clients_command); | 840 | EXPORT_SYMBOL(i2c_clients_command); |
827 | 841 | ||
@@ -1087,7 +1101,7 @@ i2c_new_probed_device(struct i2c_adapter *adap, | |||
1087 | } | 1101 | } |
1088 | 1102 | ||
1089 | /* Check address availability */ | 1103 | /* Check address availability */ |
1090 | if (__i2c_check_addr(adap, addr_list[i])) { | 1104 | if (i2c_check_addr(adap, addr_list[i])) { |
1091 | dev_dbg(&adap->dev, "Address 0x%02x already in " | 1105 | dev_dbg(&adap->dev, "Address 0x%02x already in " |
1092 | "use, not probing\n", addr_list[i]); | 1106 | "use, not probing\n", addr_list[i]); |
1093 | continue; | 1107 | continue; |
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index df540d5dfaf4..393e679d9faa 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c | |||
@@ -182,27 +182,22 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c | |||
182 | return ret; | 182 | return ret; |
183 | } | 183 | } |
184 | 184 | ||
185 | static int i2cdev_check(struct device *dev, void *addrp) | ||
186 | { | ||
187 | struct i2c_client *client = i2c_verify_client(dev); | ||
188 | |||
189 | if (!client || client->addr != *(unsigned int *)addrp) | ||
190 | return 0; | ||
191 | |||
192 | return dev->driver ? -EBUSY : 0; | ||
193 | } | ||
194 | |||
185 | /* This address checking function differs from the one in i2c-core | 195 | /* This address checking function differs from the one in i2c-core |
186 | in that it considers an address with a registered device, but no | 196 | in that it considers an address with a registered device, but no |
187 | bound driver, as NOT busy. */ | 197 | driver bound to it, as NOT busy. */ |
188 | static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) | 198 | static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) |
189 | { | 199 | { |
190 | struct list_head *item; | 200 | return device_for_each_child(&adapter->dev, &addr, i2cdev_check); |
191 | struct i2c_client *client; | ||
192 | int res = 0; | ||
193 | |||
194 | mutex_lock(&adapter->clist_lock); | ||
195 | list_for_each(item, &adapter->clients) { | ||
196 | client = list_entry(item, struct i2c_client, list); | ||
197 | if (client->addr == addr) { | ||
198 | if (client->driver) | ||
199 | res = -EBUSY; | ||
200 | break; | ||
201 | } | ||
202 | } | ||
203 | mutex_unlock(&adapter->clist_lock); | ||
204 | |||
205 | return res; | ||
206 | } | 201 | } |
207 | 202 | ||
208 | static int i2cdev_ioctl(struct inode *inode, struct file *file, | 203 | static int i2cdev_ioctl(struct inode *inode, struct file *file, |