Skip to content

Commit

Permalink
i2c-dev: Use standard bus notification mechanism
Browse files Browse the repository at this point in the history
Use the standard driver core mechanism to keep track of i2c adapters
present on the system: i2c_for_each_dev and a notifier. This will let
us deprecate and ultimately remove the legacy attach_adapter and
detach_adapter callbacks in i2c_driver.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
  • Loading branch information
Jean Delvare authored and Jean Delvare committed Mar 20, 2011
1 parent 7ae3148 commit 9ea3e94
Showing 1 changed file with 39 additions and 21 deletions.
60 changes: 39 additions & 21 deletions drivers/i2c/i2c-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
Expand All @@ -37,16 +39,13 @@
#include <linux/jiffies.h>
#include <linux/uaccess.h>

static struct i2c_driver i2cdev_driver;

/*
* An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
* slave (i2c_client) with which messages will be exchanged. It's coupled
* with a character special file which is accessed by user mode drivers.
*
* The list of i2c_dev structures is parallel to the i2c_adapter lists
* maintained by the driver model, and is updated using notifications
* delivered to the i2cdev_driver.
* maintained by the driver model, and is updated using bus notifications.
*/
struct i2c_dev {
struct list_head list;
Expand Down Expand Up @@ -491,7 +490,6 @@ static int i2cdev_open(struct inode *inode, struct file *file)
return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->driver = &i2cdev_driver;

client->adapter = adap;
file->private_data = client;
Expand Down Expand Up @@ -522,19 +520,18 @@ static const struct file_operations i2cdev_fops = {

/* ------------------------------------------------------------------------- */

/*
* The legacy "i2cdev_driver" is used primarily to get notifications when
* I2C adapters are added or removed, so that each one gets an i2c_dev
* and is thus made available to userspace driver code.
*/

static struct class *i2c_dev_class;

static int i2cdev_attach_adapter(struct i2c_adapter *adap)
static int i2cdev_attach_adapter(struct device *dev, void *dummy)
{
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
int res;

if (dev->type != &i2c_adapter_type)
return 0;
adap = to_i2c_adapter(dev);

i2c_dev = get_free_i2c_dev(adap);
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
Expand All @@ -561,10 +558,15 @@ static int i2cdev_attach_adapter(struct i2c_adapter *adap)
return res;
}

static int i2cdev_detach_adapter(struct i2c_adapter *adap)
static int i2cdev_detach_adapter(struct device *dev, void *dummy)
{
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;

if (dev->type != &i2c_adapter_type)
return 0;
adap = to_i2c_adapter(dev);

i2c_dev = i2c_dev_get_by_minor(adap->nr);
if (!i2c_dev) /* attach_adapter must have failed */
return 0;
Expand All @@ -577,12 +579,23 @@ static int i2cdev_detach_adapter(struct i2c_adapter *adap)
return 0;
}

static struct i2c_driver i2cdev_driver = {
.driver = {
.name = "dev_driver",
},
.attach_adapter = i2cdev_attach_adapter,
.detach_adapter = i2cdev_detach_adapter,
int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
void *data)
{
struct device *dev = data;

switch (action) {
case BUS_NOTIFY_ADD_DEVICE:
return i2cdev_attach_adapter(dev, NULL);
case BUS_NOTIFY_DEL_DEVICE:
return i2cdev_detach_adapter(dev, NULL);
}

return 0;
}

static struct notifier_block i2cdev_notifier = {
.notifier_call = i2cdev_notifier_call,
};

/* ------------------------------------------------------------------------- */
Expand All @@ -607,10 +620,14 @@ static int __init i2c_dev_init(void)
goto out_unreg_chrdev;
}

res = i2c_add_driver(&i2cdev_driver);
/* Keep track of adapters which will be added or removed later */
res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
if (res)
goto out_unreg_class;

/* Bind to already existing adapters right away */
i2c_for_each_dev(NULL, i2cdev_attach_adapter);

return 0;

out_unreg_class:
Expand All @@ -624,7 +641,8 @@ static int __init i2c_dev_init(void)

static void __exit i2c_dev_exit(void)
{
i2c_del_driver(&i2cdev_driver);
bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier);
i2c_for_each_dev(NULL, i2cdev_detach_adapter);
class_destroy(i2c_dev_class);
unregister_chrdev(I2C_MAJOR, "i2c");
}
Expand Down

0 comments on commit 9ea3e94

Please sign in to comment.