diff options
Diffstat (limited to 'drivers/i2c/i2c-dev.c')
-rw-r--r-- | drivers/i2c/i2c-dev.c | 109 |
1 files changed, 50 insertions, 59 deletions
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 58ccddd5c237..3f869033ed70 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c | |||
@@ -32,43 +32,35 @@ | |||
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 <linux/platform_device.h> | ||
38 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
39 | 39 | ||
40 | static struct i2c_client i2cdev_client_template; | 40 | static struct i2c_driver i2cdev_driver; |
41 | 41 | ||
42 | struct i2c_dev { | 42 | struct i2c_dev { |
43 | int minor; | 43 | struct list_head list; |
44 | struct i2c_adapter *adap; | 44 | struct i2c_adapter *adap; |
45 | struct class_device *class_dev; | 45 | struct class_device *class_dev; |
46 | }; | 46 | }; |
47 | #define to_i2c_dev(d) container_of(d, struct i2c_dev, class_dev) | ||
48 | 47 | ||
49 | #define I2C_MINORS 256 | 48 | #define I2C_MINORS 256 |
50 | static struct i2c_dev *i2c_dev_array[I2C_MINORS]; | 49 | static LIST_HEAD(i2c_dev_list); |
51 | static DEFINE_SPINLOCK(i2c_dev_array_lock); | 50 | static DEFINE_SPINLOCK(i2c_dev_list_lock); |
52 | 51 | ||
53 | static struct i2c_dev *i2c_dev_get_by_minor(unsigned index) | 52 | static struct i2c_dev *i2c_dev_get_by_minor(unsigned index) |
54 | { | 53 | { |
55 | struct i2c_dev *i2c_dev; | 54 | struct i2c_dev *i2c_dev; |
56 | 55 | ||
57 | spin_lock(&i2c_dev_array_lock); | 56 | spin_lock(&i2c_dev_list_lock); |
58 | i2c_dev = i2c_dev_array[index]; | 57 | list_for_each_entry(i2c_dev, &i2c_dev_list, list) { |
59 | spin_unlock(&i2c_dev_array_lock); | 58 | if (i2c_dev->adap->nr == index) |
60 | return i2c_dev; | 59 | goto found; |
61 | } | 60 | } |
62 | 61 | i2c_dev = NULL; | |
63 | static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap) | 62 | found: |
64 | { | 63 | spin_unlock(&i2c_dev_list_lock); |
65 | struct i2c_dev *i2c_dev = NULL; | ||
66 | |||
67 | spin_lock(&i2c_dev_array_lock); | ||
68 | if ((i2c_dev_array[adap->nr]) && | ||
69 | (i2c_dev_array[adap->nr]->adap == adap)) | ||
70 | i2c_dev = i2c_dev_array[adap->nr]; | ||
71 | spin_unlock(&i2c_dev_array_lock); | ||
72 | return i2c_dev; | 64 | return i2c_dev; |
73 | } | 65 | } |
74 | 66 | ||
@@ -76,30 +68,28 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap) | |||
76 | { | 68 | { |
77 | struct i2c_dev *i2c_dev; | 69 | struct i2c_dev *i2c_dev; |
78 | 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 | |||
79 | i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL); | 77 | i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL); |
80 | if (!i2c_dev) | 78 | if (!i2c_dev) |
81 | return ERR_PTR(-ENOMEM); | 79 | return ERR_PTR(-ENOMEM); |
80 | i2c_dev->adap = adap; | ||
82 | 81 | ||
83 | spin_lock(&i2c_dev_array_lock); | 82 | spin_lock(&i2c_dev_list_lock); |
84 | if (i2c_dev_array[adap->nr]) { | 83 | list_add_tail(&i2c_dev->list, &i2c_dev_list); |
85 | spin_unlock(&i2c_dev_array_lock); | 84 | spin_unlock(&i2c_dev_list_lock); |
86 | dev_err(&adap->dev, "i2c-dev already has a device assigned to this adapter\n"); | ||
87 | goto error; | ||
88 | } | ||
89 | i2c_dev->minor = adap->nr; | ||
90 | i2c_dev_array[adap->nr] = i2c_dev; | ||
91 | spin_unlock(&i2c_dev_array_lock); | ||
92 | return i2c_dev; | 85 | return i2c_dev; |
93 | error: | ||
94 | kfree(i2c_dev); | ||
95 | return ERR_PTR(-ENODEV); | ||
96 | } | 86 | } |
97 | 87 | ||
98 | static void return_i2c_dev(struct i2c_dev *i2c_dev) | 88 | static void return_i2c_dev(struct i2c_dev *i2c_dev) |
99 | { | 89 | { |
100 | spin_lock(&i2c_dev_array_lock); | 90 | spin_lock(&i2c_dev_list_lock); |
101 | i2c_dev_array[i2c_dev->minor] = NULL; | 91 | list_del(&i2c_dev->list); |
102 | spin_unlock(&i2c_dev_array_lock); | 92 | spin_unlock(&i2c_dev_list_lock); |
103 | } | 93 | } |
104 | 94 | ||
105 | 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) |
@@ -375,12 +365,13 @@ static int i2cdev_open(struct inode *inode, struct file *file) | |||
375 | if (!adap) | 365 | if (!adap) |
376 | return -ENODEV; | 366 | return -ENODEV; |
377 | 367 | ||
378 | client = kmalloc(sizeof(*client), GFP_KERNEL); | 368 | client = kzalloc(sizeof(*client), GFP_KERNEL); |
379 | if (!client) { | 369 | if (!client) { |
380 | i2c_put_adapter(adap); | 370 | i2c_put_adapter(adap); |
381 | return -ENOMEM; | 371 | return -ENOMEM; |
382 | } | 372 | } |
383 | memcpy(client, &i2cdev_client_template, sizeof(*client)); | 373 | snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr); |
374 | client->driver = &i2cdev_driver; | ||
384 | 375 | ||
385 | /* registered with adapter, passed as client to user */ | 376 | /* registered with adapter, passed as client to user */ |
386 | client->adapter = adap; | 377 | client->adapter = adap; |
@@ -415,41 +406,47 @@ static struct class *i2c_dev_class; | |||
415 | static int i2cdev_attach_adapter(struct i2c_adapter *adap) | 406 | static int i2cdev_attach_adapter(struct i2c_adapter *adap) |
416 | { | 407 | { |
417 | struct i2c_dev *i2c_dev; | 408 | struct i2c_dev *i2c_dev; |
418 | struct device *dev; | 409 | int res; |
419 | 410 | ||
420 | i2c_dev = get_free_i2c_dev(adap); | 411 | i2c_dev = get_free_i2c_dev(adap); |
421 | if (IS_ERR(i2c_dev)) | 412 | if (IS_ERR(i2c_dev)) |
422 | return PTR_ERR(i2c_dev); | 413 | return PTR_ERR(i2c_dev); |
423 | 414 | ||
424 | pr_debug("i2c-dev: adapter [%s] registered as minor %d\n", | ||
425 | adap->name, i2c_dev->minor); | ||
426 | |||
427 | /* register this i2c device with the driver core */ | 415 | /* register this i2c device with the driver core */ |
428 | i2c_dev->adap = adap; | ||
429 | dev = &adap->dev; | ||
430 | i2c_dev->class_dev = class_device_create(i2c_dev_class, NULL, | 416 | i2c_dev->class_dev = class_device_create(i2c_dev_class, NULL, |
431 | MKDEV(I2C_MAJOR, i2c_dev->minor), | 417 | MKDEV(I2C_MAJOR, adap->nr), |
432 | dev, "i2c-%d", i2c_dev->minor); | 418 | &adap->dev, "i2c-%d", |
433 | if (!i2c_dev->class_dev) | 419 | adap->nr); |
420 | if (!i2c_dev->class_dev) { | ||
421 | res = -ENODEV; | ||
434 | goto error; | 422 | goto error; |
435 | class_device_create_file(i2c_dev->class_dev, &class_device_attr_name); | 423 | } |
424 | res = class_device_create_file(i2c_dev->class_dev, &class_device_attr_name); | ||
425 | if (res) | ||
426 | goto error_destroy; | ||
427 | |||
428 | pr_debug("i2c-dev: adapter [%s] registered as minor %d\n", | ||
429 | adap->name, adap->nr); | ||
436 | return 0; | 430 | return 0; |
431 | error_destroy: | ||
432 | class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr)); | ||
437 | error: | 433 | error: |
438 | return_i2c_dev(i2c_dev); | 434 | return_i2c_dev(i2c_dev); |
439 | kfree(i2c_dev); | 435 | kfree(i2c_dev); |
440 | return -ENODEV; | 436 | return res; |
441 | } | 437 | } |
442 | 438 | ||
443 | static int i2cdev_detach_adapter(struct i2c_adapter *adap) | 439 | static int i2cdev_detach_adapter(struct i2c_adapter *adap) |
444 | { | 440 | { |
445 | struct i2c_dev *i2c_dev; | 441 | struct i2c_dev *i2c_dev; |
446 | 442 | ||
447 | i2c_dev = i2c_dev_get_by_adapter(adap); | 443 | i2c_dev = i2c_dev_get_by_minor(adap->nr); |
448 | if (!i2c_dev) | 444 | if (!i2c_dev) /* attach_adapter must have failed */ |
449 | return -ENODEV; | 445 | return 0; |
450 | 446 | ||
447 | class_device_remove_file(i2c_dev->class_dev, &class_device_attr_name); | ||
451 | return_i2c_dev(i2c_dev); | 448 | return_i2c_dev(i2c_dev); |
452 | class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, i2c_dev->minor)); | 449 | class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr)); |
453 | kfree(i2c_dev); | 450 | kfree(i2c_dev); |
454 | 451 | ||
455 | pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name); | 452 | pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name); |
@@ -471,12 +468,6 @@ static struct i2c_driver i2cdev_driver = { | |||
471 | .detach_client = i2cdev_detach_client, | 468 | .detach_client = i2cdev_detach_client, |
472 | }; | 469 | }; |
473 | 470 | ||
474 | static struct i2c_client i2cdev_client_template = { | ||
475 | .name = "I2C /dev entry", | ||
476 | .addr = -1, | ||
477 | .driver = &i2cdev_driver, | ||
478 | }; | ||
479 | |||
480 | static int __init i2c_dev_init(void) | 471 | static int __init i2c_dev_init(void) |
481 | { | 472 | { |
482 | int res; | 473 | int res; |