Commit 7b4fbc50 authored by David Brownell's avatar David Brownell Committed by Jean Delvare
Browse files

i2c: i2c stack can probe()



One of a series of I2C infrastructure updates to support enumeration using
the standard Linux driver model.

This patch updates probe() and associated hotplug/coldplug support, but
not remove().  Nothing yet _uses_ it to create I2C devices, so those
hotplug/coldplug mechanisms will be the only externally visible change.
This patch will be an overall NOP since the I2C stack doesn't yet create
clients/devices except as part of binding them to legacy drivers.

Some code is moved earlier in the source code, helping group more of the
per-device infrastructure in one place and simplifying handling per-device
attributes.

Terminology being adopted:  "legacy drivers" create devices (i2c_client)
themselves, while "new style" ones follow the driver model (the i2c_client
is handed to the probe routine).  It's an either/or thing; the two models
don't mix, and drivers that try mixing them won't even be registered.

Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
parent 5cedb05d
Loading
Loading
Loading
Loading
+99 −42
Original line number Diff line number Diff line
@@ -44,15 +44,58 @@ static DEFINE_IDR(i2c_adapter_idr);

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

/* match always succeeds, as we want the probe() to tell if we really accept this match */
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
	return 1;
	struct i2c_client	*client = to_i2c_client(dev);
	struct i2c_driver	*driver = to_i2c_driver(drv);

	/* make legacy i2c drivers bypass driver model probing entirely;
	 * such drivers scan each i2c adapter/bus themselves.
	 */
	if (!driver->probe)
		return 0;

	/* new style drivers use the same kind of driver matching policy
	 * as platform devices or SPI:  compare device and driver IDs.
	 */
	return strcmp(client->driver_name, drv->name) == 0;
}

#ifdef	CONFIG_HOTPLUG

/* uevent helps with hotplug: modprobe -q $(MODALIAS) */
static int i2c_device_uevent(struct device *dev, char **envp, int num_envp,
		      char *buffer, int buffer_size)
{
	struct i2c_client	*client = to_i2c_client(dev);
	int			i = 0, length = 0;

	/* by definition, legacy drivers can't hotplug */
	if (dev->driver || !client->driver_name)
		return 0;

	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
			"MODALIAS=%s", client->driver_name))
		return -ENOMEM;
	envp[i] = NULL;
	dev_dbg(dev, "uevent\n");
	return 0;
}

#else
#define i2c_device_uevent	NULL
#endif	/* CONFIG_HOTPLUG */

static int i2c_device_probe(struct device *dev)
{
	struct i2c_client	*client = to_i2c_client(dev);
	struct i2c_driver	*driver = to_i2c_driver(dev->driver);

	if (!driver->probe)
		return -ENODEV;
	client->driver = driver;
	dev_dbg(dev, "probe\n");
	return driver->probe(client);
}

static int i2c_device_remove(struct device *dev)
@@ -95,9 +138,38 @@ static int i2c_device_resume(struct device * dev)
	return driver->resume(to_i2c_client(dev));
}

static void i2c_client_release(struct device *dev)
{
	struct i2c_client *client = to_i2c_client(dev);
	complete(&client->released);
}

static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	return sprintf(buf, "%s\n", client->name);
}

static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	return client->driver_name
		? sprintf(buf, "%s\n", client->driver_name)
		: 0;
}

static struct device_attribute i2c_dev_attrs[] = {
	__ATTR(name, S_IRUGO, show_client_name, NULL),
	/* modalias helps coldplug:  modprobe $(cat .../modalias) */
	__ATTR(modalias, S_IRUGO, show_modalias, NULL),
	{ },
};

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.dev_attrs	= i2c_dev_attrs,
	.match		= i2c_device_match,
	.uevent		= i2c_device_uevent,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
@@ -134,31 +206,6 @@ struct class i2c_adapter_class = {
};


static void i2c_client_release(struct device *dev)
{
	struct i2c_client *client = to_i2c_client(dev);
	complete(&client->released);
}

static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	return sprintf(buf, "%s\n", client->name);
}

/*
 * We can't use the DEVICE_ATTR() macro here, as we used the same name for
 * an i2c adapter attribute (above).
 */
static struct device_attribute dev_attr_client_name =
	__ATTR(name, S_IRUGO, &show_client_name, NULL);


/* ---------------------------------------------------
 * registering functions
 * ---------------------------------------------------
 */

/* -----
 * i2c_add_adapter is called from within the algorithm layer,
 * when a new hw adapter registers. A new device is register to be
@@ -208,7 +255,7 @@ int i2c_add_adapter(struct i2c_adapter *adap)

	dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);

	/* inform drivers of new adapters */
	/* let legacy drivers scan this bus for matching devices */
	list_for_each(item,&drivers) {
		driver = list_entry(item, struct i2c_driver, list);
		if (driver->attach_adapter)
@@ -292,16 +339,32 @@ int i2c_del_adapter(struct i2c_adapter *adap)
}


/* -----
 * What follows is the "upwards" interface: commands for talking to clients,
 * which implement the functions to access the physical information of the
 * chips.
/* ------------------------------------------------------------------------- */

/*
 * An i2c_driver is used with one or more i2c_client (device) nodes to access
 * i2c slave chips, on a bus instance associated with some i2c_adapter.  There
 * are two models for binding the driver to its device:  "new style" drivers
 * follow the standard Linux driver model and just respond to probe() calls
 * issued if the driver core sees they match(); "legacy" drivers create device
 * nodes themselves.
 */

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
	int res;

	/* new style driver methods can't mix with legacy ones */
	if (driver->probe) {
		if (driver->attach_adapter || driver->detach_adapter
				|| driver->detach_client) {
			printk(KERN_WARNING
					"i2c-core: driver [%s] is confused\n",
					driver->driver.name);
			return -EINVAL;
		}
	}

	/* add the driver to the list of i2c drivers in the driver core */
	driver->driver.owner = owner;
	driver->driver.bus = &i2c_bus_type;
@@ -315,7 +378,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
	list_add_tail(&driver->list,&drivers);
	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

	/* now look for instances of driver on our adapters */
	/* legacy drivers scan i2c busses directly */
	if (driver->attach_adapter) {
		struct i2c_adapter *adapter;

@@ -380,6 +443,8 @@ int i2c_del_driver(struct i2c_driver *driver)
	return 0;
}

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

static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
{
	struct list_head   *item;
@@ -430,9 +495,6 @@ int i2c_attach_client(struct i2c_client *client)
	res = device_register(&client->dev);
	if (res)
		goto out_list;
	res = device_create_file(&client->dev, &dev_attr_client_name);
	if (res)
		goto out_unregister;
	mutex_unlock(&adapter->clist_lock);

	if (adapter->client_register)  {
@@ -445,10 +507,6 @@ int i2c_attach_client(struct i2c_client *client)

	return 0;

out_unregister:
	init_completion(&client->released); /* Needed? */
	device_unregister(&client->dev);
	wait_for_completion(&client->released);
out_list:
	list_del(&client->list);
	dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
@@ -483,7 +541,6 @@ int i2c_detach_client(struct i2c_client *client)
	mutex_lock(&adapter->clist_lock);
	list_del(&client->list);
	init_completion(&client->released);
	device_remove_file(&client->dev, &dev_attr_client_name);
	device_unregister(&client->dev);
	mutex_unlock(&adapter->clist_lock);
	wait_for_completion(&client->released);
+11 −2
Original line number Diff line number Diff line
@@ -113,7 +113,7 @@ struct i2c_driver {
	 * can be used by the driver to test if the bus meets its conditions
	 * & seek for the presence of the chip(s) it supports. If found, it
	 * registers the client(s) that are on the bus to the i2c admin. via
	 * i2c_attach_client.
	 * i2c_attach_client.  (LEGACY I2C DRIVERS ONLY)
	 */
	int (*attach_adapter)(struct i2c_adapter *);
	int (*detach_adapter)(struct i2c_adapter *);
@@ -121,10 +121,16 @@ struct i2c_driver {
	/* tells the driver that a client is about to be deleted & gives it
	 * the chance to remove its private data. Also, if the client struct
	 * has been dynamically allocated by the driver in the function above,
	 * it must be freed here.
	 * it must be freed here.  (LEGACY I2C DRIVERS ONLY)
	 */
	int (*detach_client)(struct i2c_client *);

	/* Standard driver model interfaces, for "new style" i2c drivers.
	 * With the driver model, device enumeration is NEVER done by drivers;
	 * it's done by infrastructure.  (NEW STYLE DRIVERS ONLY)
	 */
	int (*probe)(struct i2c_client *);

	/* driver model interfaces that don't relate to enumeration  */
	void (*shutdown)(struct i2c_client *);
	int (*suspend)(struct i2c_client *, pm_message_t mesg);
@@ -148,6 +154,8 @@ struct i2c_driver {
 * @name: Indicates the type of the device, usually a chip name that's
 *	generic enough to hide second-sourcing and compatible revisions.
 * @dev: Driver model device node for the slave.
 * @driver_name: Identifies new-style driver used with this device; also
 *	used as the module name for hotplug/coldplug modprobe support.
 *
 * An i2c_client identifies a single device (i.e. chip) connected to an
 * i2c bus. The behaviour is defined by the routines of the driver.
@@ -163,6 +171,7 @@ struct i2c_client {
	int usage_count;		/* How many accesses currently  */
					/* to the client		*/
	struct device dev;		/* the device structure		*/
	char driver_name[KOBJ_NAME_LEN];
	struct list_head list;
	struct completion released;
};