diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/i2c-dev.c | 45 |
1 files changed, 25 insertions, 20 deletions
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 6e90dec02567..206e8052f90f 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/smp_lock.h> | 33 | #include <linux/smp_lock.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/list.h> | ||
35 | #include <linux/i2c.h> | 36 | #include <linux/i2c.h> |
36 | #include <linux/i2c-dev.h> | 37 | #include <linux/i2c-dev.h> |
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
@@ -39,21 +40,27 @@ | |||
39 | static struct i2c_client i2cdev_client_template; | 40 | static struct i2c_client i2cdev_client_template; |
40 | 41 | ||
41 | struct i2c_dev { | 42 | struct i2c_dev { |
43 | struct list_head list; | ||
42 | struct i2c_adapter *adap; | 44 | struct i2c_adapter *adap; |
43 | struct class_device *class_dev; | 45 | struct class_device *class_dev; |
44 | }; | 46 | }; |
45 | 47 | ||
46 | #define I2C_MINORS 256 | 48 | #define I2C_MINORS 256 |
47 | static struct i2c_dev *i2c_dev_array[I2C_MINORS]; | 49 | static LIST_HEAD(i2c_dev_list); |
48 | static DEFINE_SPINLOCK(i2c_dev_array_lock); | 50 | static DEFINE_SPINLOCK(i2c_dev_list_lock); |
49 | 51 | ||
50 | static struct i2c_dev *i2c_dev_get_by_minor(unsigned index) | 52 | static struct i2c_dev *i2c_dev_get_by_minor(unsigned index) |
51 | { | 53 | { |
52 | struct i2c_dev *i2c_dev; | 54 | struct i2c_dev *i2c_dev; |
53 | 55 | ||
54 | spin_lock(&i2c_dev_array_lock); | 56 | spin_lock(&i2c_dev_list_lock); |
55 | i2c_dev = i2c_dev_array[index]; | 57 | list_for_each_entry(i2c_dev, &i2c_dev_list, list) { |
56 | spin_unlock(&i2c_dev_array_lock); | 58 | if (i2c_dev->adap->nr == index) |
59 | goto found; | ||
60 | } | ||
61 | i2c_dev = NULL; | ||
62 | found: | ||
63 | spin_unlock(&i2c_dev_list_lock); | ||
57 | return i2c_dev; | 64 | return i2c_dev; |
58 | } | 65 | } |
59 | 66 | ||
@@ -61,30 +68,28 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap) | |||
61 | { | 68 | { |
62 | struct i2c_dev *i2c_dev; | 69 | struct i2c_dev *i2c_dev; |
63 | 70 | ||
71 | if (adap->nr >= I2C_MINORS) { | ||
72 | printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n", | ||
73 | adap->nr); | ||
74 | return ERR_PTR(-ENODEV); | ||
75 | } | ||
76 | |||
64 | i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL); | 77 | i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL); |
65 | if (!i2c_dev) | 78 | if (!i2c_dev) |
66 | return ERR_PTR(-ENOMEM); | 79 | return ERR_PTR(-ENOMEM); |
67 | |||
68 | spin_lock(&i2c_dev_array_lock); | ||
69 | if (i2c_dev_array[adap->nr]) { | ||
70 | spin_unlock(&i2c_dev_array_lock); | ||
71 | dev_err(&adap->dev, "i2c-dev already has a device assigned to this adapter\n"); | ||
72 | goto error; | ||
73 | } | ||
74 | i2c_dev->adap = adap; | 80 | i2c_dev->adap = adap; |
75 | i2c_dev_array[adap->nr] = i2c_dev; | 81 | |
76 | spin_unlock(&i2c_dev_array_lock); | 82 | spin_lock(&i2c_dev_list_lock); |
83 | list_add_tail(&i2c_dev->list, &i2c_dev_list); | ||
84 | spin_unlock(&i2c_dev_list_lock); | ||
77 | return i2c_dev; | 85 | return i2c_dev; |
78 | error: | ||
79 | kfree(i2c_dev); | ||
80 | return ERR_PTR(-ENODEV); | ||
81 | } | 86 | } |
82 | 87 | ||
83 | static void return_i2c_dev(struct i2c_dev *i2c_dev) | 88 | static void return_i2c_dev(struct i2c_dev *i2c_dev) |
84 | { | 89 | { |
85 | spin_lock(&i2c_dev_array_lock); | 90 | spin_lock(&i2c_dev_list_lock); |
86 | i2c_dev_array[i2c_dev->adap->nr] = NULL; | 91 | list_del(&i2c_dev->list); |
87 | spin_unlock(&i2c_dev_array_lock); | 92 | spin_unlock(&i2c_dev_list_lock); |
88 | } | 93 | } |
89 | 94 | ||
90 | static ssize_t show_adapter_name(struct class_device *class_dev, char *buf) | 95 | static ssize_t show_adapter_name(struct class_device *class_dev, char *buf) |