diff options
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, |