[i2c] [patch 2.6.19-rc6 1/11] i2c_adapter class/nonclass driver cleanup

David Brownell david-b at pacbell.net
Sat Nov 25 23:55:34 CET 2006


Some I2C driver model core cleanup, removing:

  - Inappropriate "i2c_adapter.dev"; users of that should have been
    providing (or using) i2c_adapter.class_dev.dev instead.

  - The non-class "i2c-adapter" driver, which should never have been
    needed given the i2c_adapter class.

That's primarily debris from the first incarnation of class devices,
which didn't work as cleanly as they should have.  Separate patches will
update the other i2c driver codes appropriately (LOTS of one-liners).

This shrinks the data footprint for each I2C adapter by a fair amount,
and i2c core code (and data) space by a bit.  A later patch can shrink
the core more, using driver core lists instead of its own versions.

To cope with incomplete driver model conversions in I2C bus drivers, if
there's no real device associated with the adapter, a warning is issued
and a "legacy_i2c_adapter" platform device is created.  One hopes all
the I2C bus drivers will be fixed over the next year or so, letting that
hack be removed.

Signed-off-by: David Brownell <dbrownell at users.sourceforge.net>

----
 drivers/i2c/i2c-core.c |  161 +++++++++++++++++++++++--------------------------
 drivers/i2c/i2c-dev.c  |   12 ++-
 include/linux/i2c.h    |    9 +-
 3 files changed, 89 insertions(+), 93 deletions(-)

Index: at91/include/linux/i2c.h
===================================================================
--- at91.orig/include/linux/i2c.h	2006-11-25 08:05:38.000000000 -0800
+++ at91/include/linux/i2c.h	2006-11-25 08:05:48.000000000 -0800
@@ -37,8 +37,6 @@
 
 /* --- For i2c-isa ---------------------------------------------------- */
 
-extern void i2c_adapter_dev_release(struct device *dev);
-extern struct device_driver i2c_adapter_driver;
 extern struct class i2c_adapter_class;
 extern struct bus_type i2c_bus_type;
 
@@ -221,8 +219,9 @@ struct i2c_adapter {
 
 	int timeout;
 	int retries;
-	struct device dev;		/* the adapter device */
 	struct class_device class_dev;	/* the class device */
+	struct platform_device *legacy_hack;
+	void *adapdata;
 
 	int nr;
 	struct list_head clients;
@@ -236,12 +235,12 @@ struct i2c_adapter {
 
 static inline void *i2c_get_adapdata (struct i2c_adapter *dev)
 {
-	return dev_get_drvdata (&dev->dev);
+	return dev->adapdata;
 }
 
 static inline void i2c_set_adapdata (struct i2c_adapter *dev, void *data)
 {
-	dev_set_drvdata (&dev->dev, data);
+	dev->adapdata = data;
 }
 
 /*flags for the client struct: */
Index: at91/drivers/i2c/i2c-core.c
===================================================================
--- at91.orig/drivers/i2c/i2c-core.c	2006-11-25 08:05:38.000000000 -0800
+++ at91/drivers/i2c/i2c-core.c	2006-11-25 08:05:48.000000000 -0800
@@ -83,36 +83,29 @@ struct bus_type i2c_bus_type = {
 	.resume =       i2c_bus_resume,
 };
 
-void i2c_adapter_dev_release(struct device *dev)
-{
-	struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
-	complete(&adap->dev_released);
-}
-
-struct device_driver i2c_adapter_driver = {
-	.owner = THIS_MODULE,
-	.name =	"i2c_adapter",
-	.bus = &i2c_bus_type,
-};
-
 static void i2c_adapter_class_dev_release(struct class_device *dev)
 {
 	struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev);
 	complete(&adap->class_dev_released);
 }
 
-struct class i2c_adapter_class = {
-	.owner =	THIS_MODULE,
-	.name =		"i2c-adapter",
-	.release =	&i2c_adapter_class_dev_release,
-};
-
-static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_adapter_name(struct class_device *cdev, char *buf)
 {
-	struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
+	struct i2c_adapter *adap = class_dev_to_i2c_adapter(cdev);
 	return sprintf(buf, "%s\n", adap->name);
 }
-static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
+
+static struct class_device_attribute adapter_attrs[] = {
+	__ATTR(name, S_IRUGO, show_adapter_name, NULL),
+	{ },
+};
+
+struct class i2c_adapter_class = {
+	.name =			"i2c-adapter",
+	.owner =		THIS_MODULE,
+	.class_dev_attrs =	adapter_attrs,
+	.release =		&i2c_adapter_class_dev_release,
+};
 
 
 static void i2c_client_release(struct device *dev)
@@ -148,8 +141,10 @@ static struct device_attribute dev_attr_
  * when a new hw adapter registers. A new device is register to be
  * available for clients.
  */
+
 int i2c_add_adapter(struct i2c_adapter *adap)
 {
+	struct device *dev = adap->class_dev.dev;
 	int id, res = 0;
 	struct list_head   *item;
 	struct i2c_driver  *driver;
@@ -174,32 +169,37 @@ int i2c_add_adapter(struct i2c_adapter *
 	list_add_tail(&adap->list,&adapters);
 	INIT_LIST_HEAD(&adap->clients);
 
-	/* Add the adapter to the driver core.
-	 * If the parent pointer is not set up,
-	 * we add this adapter to the host bus.
+	/* Caller must have zero-initialized adap->class_dev, then
+	 * initialized adap->class_dev.dev as the real device so we
+	 * can properly add this adapter to the i2c_adapter class.
+	 *
+	 * As a **TEMPORARY migration aid** we create a platform
+	 * device for drivers that don't yet use the driver model.
+	 * Expect this to vanish by January 2008.
 	 */
-	if (adap->dev.parent == NULL)
-		adap->dev.parent = &platform_bus;
-	sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
-	adap->dev.driver = &i2c_adapter_driver;
-	adap->dev.release = &i2c_adapter_dev_release;
-	res = device_register(&adap->dev);
-	if (res)
-		goto out_list;
-	res = device_create_file(&adap->dev, &dev_attr_name);
-	if (res)
-		goto out_unregister;
+	if (!dev) {
+		printk(KERN_WARNING "I2C bus '%s' has no device; "
+			"convert it to the driver model\n",
+			adap->name);
+		adap->legacy_hack = platform_device_register_simple(
+			"legacy_i2c_adapter", adap->nr, NULL, 0);
+		if (adap->legacy_hack) {
+			dev = &adap->legacy_hack->dev;
+			adap->class_dev.dev = dev;
+		} else {
+			res = -ENODEV;
+			goto out_unlock;
+		}
+	}
 
-	/* Add this adapter to the i2c_adapter class */
-	memset(&adap->class_dev, 0x00, sizeof(struct class_device));
-	adap->class_dev.dev = &adap->dev;
+	sprintf(adap->class_dev.class_id, "i2c-%d", adap->nr);
 	adap->class_dev.class = &i2c_adapter_class;
-	strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
 	res = class_device_register(&adap->class_dev);
 	if (res)
-		goto out_remove_name;
+		goto out_list;
 
-	dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
+	dev_dbg(dev, "adapter %s [%s] registered\n",
+			adap->class_dev.class_id, adap->name);
 
 	/* inform drivers of new adapters */
 	list_for_each(item,&drivers) {
@@ -213,14 +213,9 @@ out_unlock:
 	mutex_unlock(&core_lists);
 	return res;
 
-out_remove_name:
-	device_remove_file(&adap->dev, &dev_attr_name);
-out_unregister:
-	init_completion(&adap->dev_released); /* Needed? */
-	device_unregister(&adap->dev);
-	wait_for_completion(&adap->dev_released);
 out_list:
 	list_del(&adap->list);
+	platform_device_put(adap->legacy_hack);
 	idr_remove(&i2c_adapter_idr, adap->nr);
 	goto out_unlock;
 }
@@ -228,6 +223,7 @@ out_list:
 
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
+	struct device *dev = adap->class_dev.dev;
 	struct list_head  *item, *_n;
 	struct i2c_adapter *adap_from_list;
 	struct i2c_driver *driver;
@@ -252,7 +248,7 @@ int i2c_del_adapter(struct i2c_adapter *
 		driver = list_entry(item, struct i2c_driver, list);
 		if (driver->detach_adapter)
 			if ((res = driver->detach_adapter(adap))) {
-				dev_err(&adap->dev, "detach_adapter failed "
+				dev_err(dev, "detach_adapter failed "
 					"for driver [%s]\n",
 					driver->driver.name);
 				goto out_unlock;
@@ -265,7 +261,7 @@ int i2c_del_adapter(struct i2c_adapter *
 		client = list_entry(item, struct i2c_client, list);
 
 		if ((res=client->driver->detach_client(client))) {
-			dev_err(&adap->dev, "detach_client failed for client "
+			dev_err(dev, "detach_client failed for client "
 				"[%s] at address 0x%02x\n", client->name,
 				client->addr);
 			goto out_unlock;
@@ -276,8 +272,6 @@ int i2c_del_adapter(struct i2c_adapter *
 	init_completion(&adap->dev_released);
 	init_completion(&adap->class_dev_released);
 	class_device_unregister(&adap->class_dev);
-	device_remove_file(&adap->dev, &dev_attr_name);
-	device_unregister(&adap->dev);
 	list_del(&adap->list);
 
 	/* wait for sysfs to drop all references */
@@ -287,7 +281,8 @@ int i2c_del_adapter(struct i2c_adapter *
 	/* free dynamically allocated bus id */
 	idr_remove(&i2c_adapter_idr, adap->nr);
 
-	dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
+	dev_dbg(dev, "adapter %s [%s] unregistered\n",
+			adap->class_dev.class_id, adap->name);
 
  out_unlock:
 	mutex_unlock(&core_lists);
@@ -348,10 +343,13 @@ int i2c_del_driver(struct i2c_driver *dr
 	 * afterwards.
 	 */
 	list_for_each(item1,&adapters) {
+		struct device *dev;
+
 		adap = list_entry(item1, struct i2c_adapter, list);
+		dev = adap->class_dev.dev;
 		if (driver->detach_adapter) {
 			if ((res = driver->detach_adapter(adap))) {
-				dev_err(&adap->dev, "detach_adapter failed "
+				dev_err(dev, "detach_adapter failed "
 					"for driver [%s]\n",
 					driver->driver.name);
 				goto out_unlock;
@@ -361,11 +359,11 @@ int i2c_del_driver(struct i2c_driver *dr
 				client = list_entry(item2, struct i2c_client, list);
 				if (client->driver != driver)
 					continue;
-				dev_dbg(&adap->dev, "detaching client [%s] "
+				dev_dbg(dev, "detaching client [%s] "
 					"at 0x%02x\n", client->name,
 					client->addr);
 				if ((res = driver->detach_client(client))) {
-					dev_err(&adap->dev, "detach_client "
+					dev_err(dev, "detach_client "
 						"failed for client [%s] at "
 						"0x%02x\n", client->name,
 						client->addr);
@@ -422,16 +420,16 @@ int i2c_attach_client(struct i2c_client 
 
 	client->usage_count = 0;
 
-	client->dev.parent = &client->adapter->dev;
+	client->dev.parent = adapter->class_dev.dev;
 	client->dev.driver = &client->driver->driver;
 	client->dev.bus = &i2c_bus_type;
 	client->dev.release = &i2c_client_release;
 
 	snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
 		"%d-%04x", i2c_adapter_id(adapter), client->addr);
-	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
-		client->name, client->dev.bus_id);
 	res = device_register(&client->dev);
+	dev_dbg(&client->dev, "attach client [%s] --> %d\n",
+		client->name, res);
 	if (res)
 		goto out_list;
 	res = device_create_file(&client->dev, &dev_attr_client_name);
@@ -441,7 +439,7 @@ int i2c_attach_client(struct i2c_client 
 
 	if (adapter->client_register)  {
 		if (adapter->client_register(client)) {
-			dev_dbg(&adapter->dev, "client_register "
+			dev_dbg(&client->dev, "client_register "
 				"failed for client [%s] at 0x%02x\n",
 				client->name, client->addr);
 		}
@@ -455,7 +453,7 @@ out_unregister:
 	wait_for_completion(&client->released);
 out_list:
 	list_del(&client->list);
-	dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
+	dev_err(&client->dev, "Failed to attach i2c client %s at 0x%02x "
 		"(%d)\n", client->name, client->addr, res);
 out_unlock:
 	mutex_unlock(&adapter->clist_lock);
@@ -569,16 +567,12 @@ static int __init i2c_init(void)
 	retval = bus_register(&i2c_bus_type);
 	if (retval)
 		return retval;
-	retval = driver_register(&i2c_adapter_driver);
-	if (retval)
-		return retval;
 	return class_register(&i2c_adapter_class);
 }
 
 static void __exit i2c_exit(void)
 {
 	class_unregister(&i2c_adapter_class);
-	driver_unregister(&i2c_adapter_driver);
 	bus_unregister(&i2c_bus_type);
 }
 
@@ -592,12 +586,13 @@ module_exit(i2c_exit);
 
 int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
 {
+	struct device *dev = adap->class_dev.dev;
 	int ret;
 
 	if (adap->algo->master_xfer) {
 #ifdef DEBUG
 		for (ret = 0; ret < num; ret++) {
-			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
+			dev_dbg(dev, "master_xfer[%d] %c, addr=0x%02x, "
 				"len=%d\n", ret, msgs[ret].flags & I2C_M_RD ?
 				'R' : 'W', msgs[ret].addr, msgs[ret].len);
 		}
@@ -609,7 +604,7 @@ int i2c_transfer(struct i2c_adapter * ad
 
 		return ret;
 	} else {
-		dev_dbg(&adap->dev, "I2C level transfers not supported\n");
+		dev_dbg(dev, "I2C transfers not supported\n");
 		return -ENOSYS;
 	}
 }
@@ -658,7 +653,7 @@ int i2c_control(struct i2c_client *clien
 	int ret = 0;
 	struct i2c_adapter *adap = client->adapter;
 
-	dev_dbg(&client->adapter->dev, "i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg);
+	dev_dbg(&client->dev, "i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg);
 	switch (cmd) {
 		case I2C_RETRIES:
 			adap->retries = arg;
@@ -681,12 +676,12 @@ int i2c_control(struct i2c_client *clien
 static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
 			     int (*found_proc) (struct i2c_adapter *, int, int))
 {
+	struct device *dev = adapter->class_dev.dev;
 	int err;
 
 	/* Make sure the address is valid */
 	if (addr < 0x03 || addr > 0x77) {
-		dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
-			 addr);
+		dev_warn(dev, "Invalid probe address 0x%02x\n", addr);
 		return -EINVAL;
 	}
 
@@ -715,8 +710,8 @@ static int i2c_probe_address(struct i2c_
 		err = 0;
 
 	if (err)
-		dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n",
-			 addr, err);
+		dev_warn(dev, "found_proc %p failed at 0x%x (%d)\n",
+			 found_proc, addr, err);
 	return err;
 }
 
@@ -724,6 +719,7 @@ int i2c_probe(struct i2c_adapter *adapte
 	      struct i2c_client_address_data *address_data,
 	      int (*found_proc) (struct i2c_adapter *, int, int))
 {
+	struct device *dev = adapter->class_dev.dev;
 	int i, err;
 	int adap_id = i2c_adapter_id(adapter);
 
@@ -738,7 +734,7 @@ int i2c_probe(struct i2c_adapter *adapte
 			     i += 2) {
 				if (forces[kind][i] == adap_id
 				 || forces[kind][i] == ANY_I2C_BUS) {
-					dev_dbg(&adapter->dev, "found force "
+					dev_dbg(dev, "found force "
 						"parameter for adapter %d, "
 						"addr 0x%02x, kind %d\n",
 						adap_id, forces[kind][i + 1],
@@ -759,7 +755,7 @@ int i2c_probe(struct i2c_adapter *adapte
 		 && address_data->normal_i2c[0] == I2C_CLIENT_END)
 			return 0;
 
-		dev_warn(&adapter->dev, "SMBus Quick command not supported, "
+		dev_warn(dev, "SMBus Quick command not supported, "
 			 "can't probe for chips\n");
 		return -1;
 	}
@@ -769,7 +765,7 @@ int i2c_probe(struct i2c_adapter *adapte
 	for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
 		if (address_data->probe[i] == adap_id
 		 || address_data->probe[i] == ANY_I2C_BUS) {
-			dev_dbg(&adapter->dev, "found probe parameter for "
+			dev_dbg(dev, "found probe parameter for "
 				"adapter %d, addr 0x%02x\n", adap_id,
 				address_data->probe[i + 1]);
 			err = i2c_probe_address(adapter,
@@ -791,7 +787,7 @@ int i2c_probe(struct i2c_adapter *adapte
 			     address_data->ignore[j] == ANY_I2C_BUS)
 			 && address_data->ignore[j + 1]
 			    == address_data->normal_i2c[i]) {
-				dev_dbg(&adapter->dev, "found ignore "
+				dev_dbg(dev, "found ignore "
 					"parameter for adapter %d, "
 					"addr 0x%02x\n", adap_id,
 					address_data->ignore[j + 1]);
@@ -802,7 +798,7 @@ int i2c_probe(struct i2c_adapter *adapte
 		if (ignore)
 			continue;
 
-		dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
+		dev_dbg(dev, "found normal entry for adapter %d, "
 			"addr 0x%02x\n", adap_id,
 			address_data->normal_i2c[i]);
 		err = i2c_probe_address(adapter, address_data->normal_i2c[i],
@@ -1015,6 +1011,7 @@ static s32 i2c_smbus_xfer_emulated(struc
 	                        };
 	int i;
 	u8 partial_pec = 0;
+	struct device *dev = adapter->class_dev.dev;
 
 	msgbuf0[0] = command;
 	switch(size) {
@@ -1058,13 +1055,13 @@ static s32 i2c_smbus_xfer_emulated(struc
 		break;
 	case I2C_SMBUS_BLOCK_DATA:
 		if (read_write == I2C_SMBUS_READ) {
-			dev_err(&adapter->dev, "Block read not supported "
+			dev_err(dev, "Block read not supported "
 			       "under I2C emulation!\n");
 			return -1;
 		} else {
 			msg[0].len = data->block[0] + 2;
 			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
-				dev_err(&adapter->dev, "smbus_access called with "
+				dev_err(dev, "smbus_access called with "
 				       "invalid block write size (%d)\n",
 				       data->block[0]);
 				return -1;
@@ -1074,7 +1071,7 @@ static s32 i2c_smbus_xfer_emulated(struc
 		}
 		break;
 	case I2C_SMBUS_BLOCK_PROC_CALL:
-		dev_dbg(&adapter->dev, "Block process call not supported "
+		dev_dbg(dev, "Block process call not supported "
 		       "under I2C emulation!\n");
 		return -1;
 	case I2C_SMBUS_I2C_BLOCK_DATA:
@@ -1083,7 +1080,7 @@ static s32 i2c_smbus_xfer_emulated(struc
 		} else {
 			msg[0].len = data->block[0] + 1;
 			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
-				dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with "
+				dev_err(dev, "i2c_smbus_xfer_emulated called with "
 				       "invalid block write size (%d)\n",
 				       data->block[0]);
 				return -1;
@@ -1093,7 +1090,7 @@ static s32 i2c_smbus_xfer_emulated(struc
 		}
 		break;
 	default:
-		dev_err(&adapter->dev, "smbus_access called with invalid size (%d)\n",
+		dev_err(dev, "smbus_access called with invalid size (%d)\n",
 		       size);
 		return -1;
 	}
@@ -1167,8 +1164,6 @@ s32 i2c_smbus_xfer(struct i2c_adapter * 
 
 
 /* Next four are needed by i2c-isa */
-EXPORT_SYMBOL_GPL(i2c_adapter_dev_release);
-EXPORT_SYMBOL_GPL(i2c_adapter_driver);
 EXPORT_SYMBOL_GPL(i2c_adapter_class);
 EXPORT_SYMBOL_GPL(i2c_bus_type);
 
Index: at91/drivers/i2c/i2c-dev.c
===================================================================
--- at91.orig/drivers/i2c/i2c-dev.c	2006-11-25 08:05:38.000000000 -0800
+++ at91/drivers/i2c/i2c-dev.c	2006-11-25 08:05:48.000000000 -0800
@@ -164,8 +164,9 @@ static int i2cdev_ioctl(struct inode *in
 	u8 __user **data_ptrs;
 	int i,datasize,res;
 	unsigned long funcs;
+	struct device *dev = client->adapter->class_dev.dev;
 
-	dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
+	dev_dbg(dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
 		cmd, arg);
 
 	switch ( cmd ) {
@@ -285,7 +286,7 @@ static int i2cdev_ioctl(struct inode *in
 		    (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
 		    (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
 		    (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
-			dev_dbg(&client->adapter->dev,
+			dev_dbg(dev,
 				"size out of range (%x) in ioctl I2C_SMBUS.\n",
 				data_arg.size);
 			return -EINVAL;
@@ -294,7 +295,7 @@ static int i2cdev_ioctl(struct inode *in
 		   so the check is valid if size==I2C_SMBUS_QUICK too. */
 		if ((data_arg.read_write != I2C_SMBUS_READ) &&
 		    (data_arg.read_write != I2C_SMBUS_WRITE)) {
-			dev_dbg(&client->adapter->dev,
+			dev_dbg(dev,
 				"read_write out of range (%x) in ioctl I2C_SMBUS.\n",
 				data_arg.read_write);
 			return -EINVAL;
@@ -313,7 +314,7 @@ static int i2cdev_ioctl(struct inode *in
 					      data_arg.size, NULL);
 
 		if (data_arg.data == NULL) {
-			dev_dbg(&client->adapter->dev,
+			dev_dbg(dev,
 				"data is NULL pointer in ioctl I2C_SMBUS.\n");
 			return -EINVAL;
 		}
@@ -407,6 +408,7 @@ static int i2cdev_attach_adapter(struct 
 {
 	struct i2c_dev *i2c_dev;
 	int res;
+	struct device *dev = adap->class_dev.dev;
 
 	i2c_dev = get_free_i2c_dev(adap);
 	if (IS_ERR(i2c_dev))
@@ -415,7 +417,7 @@ static int i2cdev_attach_adapter(struct 
 	/* register this i2c device with the driver core */
 	i2c_dev->class_dev = class_device_create(i2c_dev_class, NULL,
 						 MKDEV(I2C_MAJOR, adap->nr),
-						 &adap->dev, "i2c-%d",
+						 dev, "i2c-%d",
 						 adap->nr);
 	if (!i2c_dev->class_dev) {
 		res = -ENODEV;



More information about the i2c mailing list