aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/i2c-dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/i2c-dev.c')
-rw-r--r--drivers/i2c/i2c-dev.c109
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
40static struct i2c_client i2cdev_client_template; 40static struct i2c_driver i2cdev_driver;
41 41
42struct i2c_dev { 42struct 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
50static struct i2c_dev *i2c_dev_array[I2C_MINORS]; 49static LIST_HEAD(i2c_dev_list);
51static DEFINE_SPINLOCK(i2c_dev_array_lock); 50static DEFINE_SPINLOCK(i2c_dev_list_lock);
52 51
53static struct i2c_dev *i2c_dev_get_by_minor(unsigned index) 52static 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;
63static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap) 62found:
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;
93error:
94 kfree(i2c_dev);
95 return ERR_PTR(-ENODEV);
96} 86}
97 87
98static void return_i2c_dev(struct i2c_dev *i2c_dev) 88static 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
105static ssize_t show_adapter_name(struct class_device *class_dev, char *buf) 95static 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;
415static int i2cdev_attach_adapter(struct i2c_adapter *adap) 406static 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;
431error_destroy:
432 class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
437error: 433error:
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
443static int i2cdev_detach_adapter(struct i2c_adapter *adap) 439static 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
474static struct i2c_client i2cdev_client_template = {
475 .name = "I2C /dev entry",
476 .addr = -1,
477 .driver = &i2cdev_driver,
478};
479
480static int __init i2c_dev_init(void) 471static int __init i2c_dev_init(void)
481{ 472{
482 int res; 473 int res;