i2c-core driver-model simplified

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In 2.6.0-test10 i2c-core maintains its own list of adapters and drivers.
I think these are unneccessary as the generic driver-model maintains
those too, and it can also detach/attach clients when necessary.

The resulting i2c-core does not yet compile nor work, and I have not yet
reflected these changes to header file. But no changes in adapter or
client code is required at this time.

I could use some leftover hardware for 2.6 test setup. Anyone?


 < ChangeLog >

i2c-core driver-model

	Attempt to fit i2c-core better with driver-model.


patch-1

	Remove list of adapters and drivers in i2c-core. Driver-model
	maintains these for us.

patch-2

	No functional changes, just make it more readable by moving code
	here and there.

patch-3

	Figure out how to make client drivers probe the bus with no
	devices. Register and remove a (dummy) device on the bus with the
	adapter.


-- 
  Ky?sti M?lkki  <kyosti.malkki at welho.com>  +358 50 462 8786
-------------- next part --------------
diff -ur lk-2.6.0-test10-lab-2/drivers/i2c/i2c-core.c lk-2.6.0-test10-lab/drivers/i2c/i2c-core.c
--- lk-2.6.0-test10-lab-2/drivers/i2c/i2c-core.c	2003-11-28 21:15:38.000000000 +0200
+++ lk-2.6.0-test10-lab/drivers/i2c/i2c-core.c	2003-11-29 23:33:32.000000000 +0200
@@ -118,6 +118,7 @@
  */
 int i2c_add_adapter(struct i2c_adapter *adap)
 {
+	struct i2c_client *client = &adap->dummy_client;
 	static int nr = 0;
 
 	adap->nr = nr++;
@@ -134,6 +135,7 @@
 	adap->dev.release = &i2c_adapter_dev_release;
 	device_register(&adap->dev);
 	device_create_file(&adap->dev, &dev_attr_name);
+	DEB(dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr));
 
 	/* Add this adapter to the i2c_adapter class */
 	memset(&adap->class_dev, 0x00, sizeof(struct class_device));
@@ -142,13 +144,45 @@
 	strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
 	class_device_register(&adap->class_dev);
 
-	DEB(dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr));
+	/* Add the dummy client on the bus. */	
+	sprintf(client->dev.bus_id, "i2c-%d-probe", adap->nr);
+	client->dev.parent = &adap->dev;
+	client->dev.bus = &i2c_bus_type;
+	client->dev.release = &i2c_client_release;
+	client->adapter = adapter;
+	device_register(&client->dev);
 	return 0;
 }
 
+/* @dev client
+ * @data NULL
+ *
+ * 1. device_unregister(dev)
+ *   
+ *    driver->remove(dev)
+ */
+static int _i2c_device_unregister(struct device *dev, void *data)
+{
+	/* in device_for_each_child(), down_read( &devices_subsys.rwsem ) 
+	 * in device_unregister(),  device_del() : down_write( &devices_subsys.rwsem )
+	 *
+	 * So.. are we stuck here?
+	 */
+	device_unregister(dev);
+}
 
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
+	struct i2c_client *client = &adap->dummy_client;
+
+	/* unregister the dummy client */
+	init_completion(&client->released);
+	device_unregister(&client->dev);
+	wait_for_completion(&client->released);
+
+	/* unregister the real clients */
+	device_for_each_child(&adap->dev, NULL, _i2c_device_unregister);
+
 	/* clean up the sysfs representation */
 	init_completion(&adap->dev_released);
 	init_completion(&adap->class_dev_released);
@@ -165,22 +199,6 @@
 }
 
 
-int i2c_add_driver(struct i2c_driver *driver)
-{
-	/* add the driver to the list of i2c drivers in the driver core */
-	driver->driver.name = driver->name;
-	driver->driver.bus = &i2c_bus_type;
-	driver->driver.probe = i2c_driver_probe;
-	driver->driver.remove = i2c_driver_remove;
-
-	return driver_register(&driver->driver);
-}
-
-int i2c_del_driver(struct i2c_driver *driver)
-{
-	return driver_unregister(&driver->driver);
-}
-
 /* A bus has no (client) devices until a (client) driver creates one.
  * With driver-model, a device must exist before the probe will take place. 
  * 
@@ -193,7 +211,8 @@
  *
  * 1. in driver->attach_adapter(adapter)
  * 
- *    i2c_probe(adapter, address_list, device_probe)
+ *    i2c_probe(adapter, address_list, found_proc)
+ *    i2c_replicate_client(dummy, real)
  *
  * 2. in i2c_attach_client(client)
  *
@@ -205,8 +224,12 @@
 {
 	struct i2c_driver *driver = to_i2c_driver(&dev->driver);
 	struct i2c_adapter *adapter = to_i2c_adapter(&dev->parent.dev);
+	
+	driver->attach_adapter(adapter);
 
-	return driver->attach_adapter(adapter);
+	/* Dummy device never binds to any driver */
+	dev->driver = NULL;
+	return -ENODEV;
 }
 
 
@@ -227,7 +250,40 @@
 	return driver->detach_client(client);
 }
 
+int i2c_add_driver(struct i2c_driver *driver)
+{
+	driver->driver.name = driver->name;
+	driver->driver.bus = &i2c_bus_type;
+	driver->driver.probe = i2c_driver_probe;
+	driver->driver.remove = i2c_driver_remove;
+
+	return driver_register(&driver->driver);
+}
+
+int i2c_del_driver(struct i2c_driver *driver)
+{
+	return driver_unregister(&driver->driver);
+}
+
+
 /* i2c_driver_probe will eventually get here in driver->attach_adapter
+ * 
+ * At this point, i2c_driver has succesfully probed the bus and has 
+ * found a device it can bind to. We give up using the dummy device 
+ * and allocate a real one.
+ *
+ * @dummy  The dummy device
+ * @client The real device 
+ *
+ */
+static int i2c_replicate_client(struct i2c_client *dummy, struct i2c_client *real)
+{
+	memcpy(real, dummy, sizeof(struct i2c_client));
+	return 0;
+}
+
+/* i2c_driver_probe will eventually get here in driver->attach_adapter
+ *
  */
 int i2c_attach_client(struct i2c_client *client)
 {
@@ -250,6 +306,7 @@
 	if (client->flags & I2C_CLIENT_ALLOW_USE)
 		client->usage_count = 0;
 
+	/* The dummy device had these already setup */
 	client->dev.parent = &client->adapter->dev;
 	client->dev.driver = &client->driver->driver;
 	client->dev.bus = &i2c_bus_type;
@@ -336,16 +393,18 @@
 
 /* @dev client
  */ 
-static int _i2c_client_command(struct device *dev, struct _i2c_client_cmd *data)
+static int _i2c_client_command(struct device *dev, void *data)
 {
-	struct i2c_client *client = to_i2c_client(dev); 
+	struct i2c_client *client;
+	struct _i2c_client_cmd *cmd = data:
 
- 	/* Bus has one device template to probe drivers */
-	if (! client) 
+ 	/* We hit the dummy device */
+	if (! dev->driver) 
 	    return 0;
 
+	client = to_i2c_client(dev); 
 	if (NULL != client->driver->command)
-		return client->driver->command(client,data->cmd,data->arg);
+		return client->driver->command(client,cmd->cmd,cmd->arg);
 	
 	return 0;
 }
@@ -355,21 +414,22 @@
 	struct device *dev = &adap->dev;
 	struct _i2c_cmd_data data = { .cmd = cmd, .arg = arg };
 
-	bus_for_each_dev(&i2c_bus_type, &dev->children, &data, _i2c_client_command);
+	device_for_each_child(dev, &data, _i2c_client_command);
 }
 
 /* @dev client
  */ 
-static int _i2c_check_addr(struct device *dev, int *data)
+static int _i2c_check_addr(struct device *dev, void *data)
 {
 	struct i2c_client*client;
+	int addr = *data;
 
  	/* We hit the dummy device */
 	if (! dev->driver) 
 	    return 0;
 
 	client = to_i2c_client(dev);
-	if (client->addr == *data)
+	if (client->addr == addr)
 		return -EBUSY;
 	else
 		return 0;
@@ -378,7 +438,8 @@
 /* returns -EBUSY if some client on @adapter has address @addr */
 int i2c_check_addr(struct i2c_adapter *adapter, int addr)
 {
-	return bus_for_each_dev(&i2c_bus_type, &adapter->dev.children, &addr, _i2c_check_addr);
+	int data = addr;
+	device_for_each_child(&adapter->dev, &data, _i2c_check_addr);
 }
 
 /* ----------------------------------------------------
@@ -517,26 +578,33 @@
 
 struct _i2c_id_data {
 	struct i2c_adapter *adap;
-	int id;
+	int nr;
 }
 
 /* @dev adapter
  */ 
-static int _i2c_get_adapter_id(struct device *dev, struct _i2c_id_data *data)
+static int _i2c_get_adapter_id(struct device *dev, void *data)
 {	
-	data->adap = to_i2c_adapter(dev);
-	
-	if  ((data->adap->nr == data->id) && get_device(dev))
+	struct i2c_adapter *adap;
+	struct _i2c_id_data *id = data;
+
+ 	/* We may hit the dummy device. Or can we? */
+	if (! dev->driver)
+		return 0;
+
+	adap = to_i2c_adapter(dev);
+	if  ((adap->nr == id->nr) && get_device(dev)) {
+		id->adap = adap;
 		return 1;
-	
+	}	
 	return 0;
 }
 
 struct i2c_adapter* i2c_get_adapter(int id)
 {
-	struct _i2c_id_data data = { .id = id };
+	struct _i2c_id_data data = { .nr = id };
 	
-	if ( bus_for_each_dev(&i2c_bus_type, &i2c_adapter_class->children , &data, _i2c_adapter_id) )
+	if ( device_for_each_child(&i2c_adapter_class->dev, &data, _i2c_get_adapter_id) )
 		return data->adap;
 	else
 		return NULL;
Only in lk-2.6.0-test10-lab/drivers/i2c: i2c-core.c~
-------------- next part --------------
diff -ur lk-2.6.0-test10-lab-1/drivers/i2c/i2c-core.c lk-2.6.0-test10-lab/drivers/i2c/i2c-core.c
--- lk-2.6.0-test10-lab-1/drivers/i2c/i2c-core.c	2003-11-28 20:50:41.000000000 +0200
+++ lk-2.6.0-test10-lab/drivers/i2c/i2c-core.c	2003-11-28 21:06:15.000000000 +0200
@@ -41,12 +41,12 @@
 /**** debug level */
 static int i2c_debug;
 
-int i2c_device_probe(struct device *dev)
+static int i2c_adapter_probe(struct device *dev)
 {
 	return -ENODEV;
 }
 
-int i2c_device_remove(struct device *dev)
+static int i2c_adapter_remove(struct device *dev)
 {
 	return 0;
 }
@@ -60,8 +60,8 @@
 static struct device_driver i2c_adapter_driver = {
 	.name =	"i2c_adapter",
 	.bus = &i2c_bus_type,
-	.probe = i2c_device_probe,
-	.remove = i2c_device_remove,
+	.probe = i2c_adapter_probe,
+	.remove = i2c_adapter_remove,
 };
 
 static void i2c_adapter_class_dev_release(struct class_device *dev)
@@ -165,12 +165,6 @@
 }
 
 
-/* -----
- * What follows is the "upwards" interface: commands for talking to clients,
- * which implement the functions to access the physical information of the
- * chips.
- */
-
 int i2c_add_driver(struct i2c_driver *driver)
 {
 	/* add the driver to the list of i2c drivers in the driver core */
@@ -187,27 +181,50 @@
 	return driver_unregister(&driver->driver);
 }
 
-/* @dev client
- */ 
-static int _i2c_check_addr(struct device *dev, int *data)
-{
-	struct i2c_client*client;
+/* A bus has no (client) devices until a (client) driver creates one.
+ * With driver-model, a device must exist before the probe will take place. 
+ * 
+ * With the creation of dummy device, drivers will try to bind with possible
+ * (clients) on this bus. This device will never bind to any driver,
+ * a real device is allocated and registered within driver->probe routines.
+ */
 
- 	/* We hit the dummy device */
-	if (! dev->driver) 
-	    return 0;
+/* @dev The dummy device
+ *
+ * 1. in driver->attach_adapter(adapter)
+ * 
+ *    i2c_probe(adapter, address_list, device_probe)
+ *
+ * 2. in i2c_attach_client(client)
+ *
+ *    adapter->client_register(client)
+ *    device_register(&client->dev)
+ *
+ */
+static int i2c_driver_probe(struct device *dev) 
+{
+	struct i2c_driver *driver = to_i2c_driver(&dev->driver);
+	struct i2c_adapter *adapter = to_i2c_adapter(&dev->parent.dev);
 
-	client = to_i2c_client(dev);
-	if (client->addr == *data)
-		return -EBUSY;
-	else
-		return 0;
+	return driver->attach_adapter(adapter);
 }
 
-/* returns -EBUSY if some client on @adapter has address @addr */
-int i2c_check_addr(struct i2c_adapter *adapter, int addr)
+
+/* @dev client
+ *
+ * 1. driver->detach_client(client)
+ * 
+ * 2. in i2c_detach_client(client)
+ *	adapter->client_unregister(client)
+ *	device_unregister(&client->dev)
+ *
+ */
+static int i2c_driver_remove(struct device *dev)
 {
-	return bus_for_each_dev(&i2c_bus_type, &adapter->dev.children, &addr, _i2c_check_addr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct i2c_driver *driver = to_i2c_driver(&dev->driver);
+
+	return driver->detach_client(client);
 }
 
 /* i2c_driver_probe will eventually get here in driver->attach_adapter
@@ -341,194 +358,27 @@
 	bus_for_each_dev(&i2c_bus_type, &dev->children, &data, _i2c_client_command);
 }
 
-/* A bus has no (client) devices until a (client) driver creates one.
- * With driver-model, a device must exist before the probe will take place. 
- * 
- * With the creation of dummy device, drivers will try to bind with possible
- * (clients) on this bus. This device will never bind to any driver,
- * a real device is allocated and registered within driver->probe routines.
- */
-
-/* @dev The dummy device
- *
- * 1. in driver->attach_adapter(adapter)
- * 
- *    i2c_probe(adapter, address_list, device_probe)
- *
- * 2. in i2c_attach_client(client)
- *
- *    adapter->client_register(client)
- *    device_register(&client->dev)
- *
- */
-static int i2c_driver_probe(struct device *dev) 
-{
-	struct i2c_driver *driver = to_i2c_driver(&dev->driver);
-	struct i2c_adapter *adapter = to_i2c_adapter(&dev->parent.dev);
-
-	return driver->attach_adapter(adapter);
-}
-
-
 /* @dev client
- *
- * 1. driver->detach_client(client)
- * 
- * 2. in i2c_detach_client(client)
- *	adapter->client_unregister(client)
- *	device_unregister(&client->dev)
- *
- */
-static int i2c_driver_remove(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct i2c_driver *driver = to_i2c_driver(&dev->driver);
-
-	return driver->detach_client(client);
-}
-
-
-
-
-
-/* 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 bus_type i2c_bus_type = {
-	.name =		"i2c",
-	.match =	i2c_device_match,
-};
-
-static int __init i2c_init(void)
-{
-	int retval;
-
-	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);
-}
-
-subsys_initcall(i2c_init);
-module_exit(i2c_exit);
-
-/* ----------------------------------------------------
- * the functional interface to the i2c busses.
- * ----------------------------------------------------
- */
-
-int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num)
-{
-	int ret;
-
-	if (adap->algo->master_xfer) {
- 	 	DEB2(dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num));
-
-		down(&adap->bus_lock);
-		ret = adap->algo->master_xfer(adap,msgs,num);
-		up(&adap->bus_lock);
-
-		return ret;
-	} else {
-		DEB2(dev_dbg(&adap->dev, "I2C level transfers not supported\n"));
-		return -ENOSYS;
-	}
-}
-
-int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
+ */ 
+static int _i2c_check_addr(struct device *dev, int *data)
 {
-	int ret;
-	struct i2c_adapter *adap=client->adapter;
-	struct i2c_msg msg;
-
-	if (client->adapter->algo->master_xfer) {
-		msg.addr   = client->addr;
-		msg.flags = client->flags & I2C_M_TEN;
-		msg.len = count;
-		msg.buf = (char *)buf;
-	
-		DEB2(dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n",
-				count));
-	
-		down(&adap->bus_lock);
-		ret = adap->algo->master_xfer(adap,&msg,1);
-		up(&adap->bus_lock);
-
-		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
-		 * transmitted, else error code.
-		 */
-		return (ret == 1 )? count : ret;
-	} else {
-		dev_err(&client->adapter->dev, "I2C level transfers not supported\n");
-		return -ENOSYS;
-	}
-}
+	struct i2c_client*client;
 
-int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
-{
-	struct i2c_adapter *adap=client->adapter;
-	struct i2c_msg msg;
-	int ret;
-	if (client->adapter->algo->master_xfer) {
-		msg.addr   = client->addr;
-		msg.flags = client->flags & I2C_M_TEN;
-		msg.flags |= I2C_M_RD;
-		msg.len = count;
-		msg.buf = buf;
+ 	/* We hit the dummy device */
+	if (! dev->driver) 
+	    return 0;
 
-		DEB2(dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n",
-				count));
-	
-		down(&adap->bus_lock);
-		ret = adap->algo->master_xfer(adap,&msg,1);
-		up(&adap->bus_lock);
-	
-		DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n",
-			ret, count, client->addr));
-	
-		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
-	 	* transmitted, else error code.
-	 	*/
-		return (ret == 1 )? count : ret;
-	} else {
-		dev_err(&client->adapter->dev, "I2C level transfers not supported\n");
-		return -ENOSYS;
-	}
+	client = to_i2c_client(dev);
+	if (client->addr == *data)
+		return -EBUSY;
+	else
+		return 0;
 }
 
-
-int i2c_control(struct i2c_client *client,
-	unsigned int cmd, unsigned long arg)
+/* returns -EBUSY if some client on @adapter has address @addr */
+int i2c_check_addr(struct i2c_adapter *adapter, int addr)
 {
-	int ret = 0;
-	struct i2c_adapter *adap = client->adapter;
-
-	DEB2(printk(KERN_DEBUG "i2c-core.o: i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg));
-	switch ( cmd ) {
-		case I2C_RETRIES:
-			adap->retries = arg;
-			break;
-		case I2C_TIMEOUT:
-			adap->timeout = arg;
-			break;
-		default:
-			if (adap->algo->algo_control!=NULL)
-				ret = adap->algo->algo_control(adap,cmd,arg);
-	}
-	return ret;
+	return bus_for_each_dev(&i2c_bus_type, &adapter->dev.children, &addr, _i2c_check_addr);
 }
 
 /* ----------------------------------------------------
@@ -697,6 +547,158 @@
 	put_device(&adap->dev);
 }
 
+
+
+
+/* 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 bus_type i2c_bus_type = {
+	.name =		"i2c",
+	.match =	i2c_device_match,
+};
+
+static int __init i2c_init(void)
+{
+	int retval;
+
+	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);
+}
+
+subsys_initcall(i2c_init);
+module_exit(i2c_exit);
+
+/* ----------------------------------------------------
+ * the functional interface to the i2c busses.
+ * ----------------------------------------------------
+ */
+
+/* -----
+ * What follows is the "upwards" interface: commands for talking to clients,
+ * which implement the functions to access the physical information of the
+ * chips.
+ */
+
+
+int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num)
+{
+	int ret;
+
+	if (adap->algo->master_xfer) {
+ 	 	DEB2(dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num));
+
+		down(&adap->bus_lock);
+		ret = adap->algo->master_xfer(adap,msgs,num);
+		up(&adap->bus_lock);
+
+		return ret;
+	} else {
+		DEB2(dev_dbg(&adap->dev, "I2C level transfers not supported\n"));
+		return -ENOSYS;
+	}
+}
+
+int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
+{
+	int ret;
+	struct i2c_adapter *adap=client->adapter;
+	struct i2c_msg msg;
+
+	if (client->adapter->algo->master_xfer) {
+		msg.addr   = client->addr;
+		msg.flags = client->flags & I2C_M_TEN;
+		msg.len = count;
+		msg.buf = (char *)buf;
+	
+		DEB2(dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n",
+				count));
+	
+		down(&adap->bus_lock);
+		ret = adap->algo->master_xfer(adap,&msg,1);
+		up(&adap->bus_lock);
+
+		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
+		 * transmitted, else error code.
+		 */
+		return (ret == 1 )? count : ret;
+	} else {
+		dev_err(&client->adapter->dev, "I2C level transfers not supported\n");
+		return -ENOSYS;
+	}
+}
+
+int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
+{
+	struct i2c_adapter *adap=client->adapter;
+	struct i2c_msg msg;
+	int ret;
+	if (client->adapter->algo->master_xfer) {
+		msg.addr   = client->addr;
+		msg.flags = client->flags & I2C_M_TEN;
+		msg.flags |= I2C_M_RD;
+		msg.len = count;
+		msg.buf = buf;
+
+		DEB2(dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n",
+				count));
+	
+		down(&adap->bus_lock);
+		ret = adap->algo->master_xfer(adap,&msg,1);
+		up(&adap->bus_lock);
+	
+		DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n",
+			ret, count, client->addr));
+	
+		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
+	 	* transmitted, else error code.
+	 	*/
+		return (ret == 1 )? count : ret;
+	} else {
+		dev_err(&client->adapter->dev, "I2C level transfers not supported\n");
+		return -ENOSYS;
+	}
+}
+
+
+int i2c_control(struct i2c_client *client,
+	unsigned int cmd, unsigned long arg)
+{
+	int ret = 0;
+	struct i2c_adapter *adap = client->adapter;
+
+	DEB2(printk(KERN_DEBUG "i2c-core.o: i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg));
+	switch ( cmd ) {
+		case I2C_RETRIES:
+			adap->retries = arg;
+			break;
+		case I2C_TIMEOUT:
+			adap->timeout = arg;
+			break;
+		default:
+			if (adap->algo->algo_control!=NULL)
+				ret = adap->algo->algo_control(adap,cmd,arg);
+	}
+	return ret;
+}
+
+
+
 /* The SMBus parts */
 
 #define POLY    (0x1070U << 3) 
Only in lk-2.6.0-test10-lab/drivers/i2c: i2c-core.c~
-------------- next part --------------
Only in lk-2.6.0-test10-lab/drivers/i2c/chips: lm78-dev-model.c
Only in lk-2.6.0-test10-lab/drivers/i2c/chips: via686a-dev-model.c
diff -ur linux-2.6.0-test10/drivers/i2c/i2c-core.c lk-2.6.0-test10-lab/drivers/i2c/i2c-core.c
--- linux-2.6.0-test10/drivers/i2c/i2c-core.c	2003-11-24 13:33:19.000000000 +0200
+++ lk-2.6.0-test10-lab/drivers/i2c/i2c-core.c	2003-11-28 20:41:20.000000000 +0200
@@ -38,10 +38,6 @@
 #define DEB(x) if (i2c_debug>=1) x;
 #define DEB2(x) if (i2c_debug>=2) x;
 
-static LIST_HEAD(adapters);
-static LIST_HEAD(drivers);
-static DECLARE_MUTEX(core_lists);
-
 /**** debug level */
 static int i2c_debug;
 
@@ -123,16 +119,9 @@
 int i2c_add_adapter(struct i2c_adapter *adap)
 {
 	static int nr = 0;
-	struct list_head   *item;
-	struct i2c_driver  *driver;
-
-	down(&core_lists);
 
 	adap->nr = nr++;
 	init_MUTEX(&adap->bus_lock);
-	init_MUTEX(&adap->clist_lock);
-	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,
@@ -153,15 +142,6 @@
 	strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
 	class_device_register(&adap->class_dev);
 
-	/* inform drivers of new adapters */
-	list_for_each(item,&drivers) {
-		driver = list_entry(item, struct i2c_driver, list);
-		if (driver->flags & I2C_DF_NOTIFY)
-			/* We ignore the return code; if it fails, too bad */
-			driver->attach_adapter(adap);
-	}
-	up(&core_lists);
-
 	DEB(dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr));
 	return 0;
 }
@@ -169,59 +149,19 @@
 
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
-	struct list_head  *item, *_n;
-	struct i2c_driver *driver;
-	struct i2c_client *client;
-	int res = 0;
-
-	down(&core_lists);
-
-	list_for_each(item,&drivers) {
-		driver = list_entry(item, struct i2c_driver, list);
-		if (driver->detach_adapter)
-			if ((res = driver->detach_adapter(adap))) {
-				dev_warn(&adap->dev, "can't detach adapter"
-					 "while detaching driver %s: driver not "
-					 "detached!", driver->name);
-				goto out_unlock;
-			}
-	}
-
-	/* detach any active clients. This must be done first, because
-	 * it can fail; in which case we give upp. */
-	list_for_each_safe(item, _n, &adap->clients) {
-		client = list_entry(item, struct i2c_client, list);
-
-		/* detaching devices is unconditional of the set notify
-		 * flag, as _all_ clients that reside on the adapter
-		 * must be deleted, as this would cause invalid states.
-		 */
-		if ((res=client->driver->detach_client(client))) {
-			dev_err(&adap->dev, "adapter not "
-				"unregistered, because client at "
-				"address %02x can't be detached. ",
-				client->addr);
-			goto out_unlock;
-		}
-	}
-
 	/* clean up the sysfs representation */
 	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 */
 	wait_for_completion(&adap->dev_released);
 	wait_for_completion(&adap->class_dev_released);
 
 	DEB(dev_dbg(&adap->dev, "adapter unregistered\n"));
-
- out_unlock:
-	up(&core_lists);
-	return res;
+	return 0;
 }
 
 
@@ -233,136 +173,51 @@
 
 int i2c_add_driver(struct i2c_driver *driver)
 {
-	struct list_head   *item;
-	struct i2c_adapter *adapter;
-	int res = 0;
-
-	down(&core_lists);
-
 	/* add the driver to the list of i2c drivers in the driver core */
 	driver->driver.name = driver->name;
 	driver->driver.bus = &i2c_bus_type;
-	driver->driver.probe = i2c_device_probe;
-	driver->driver.remove = i2c_device_remove;
-
-	res = driver_register(&driver->driver);
-	if (res)
-		goto out_unlock;
-	
-	list_add_tail(&driver->list,&drivers);
-	DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
-
-	/* now look for instances of driver on our adapters */
-	if (driver->flags & I2C_DF_NOTIFY) {
-		list_for_each(item,&adapters) {
-			adapter = list_entry(item, struct i2c_adapter, list);
-			driver->attach_adapter(adapter);
-		}
-	}
+	driver->driver.probe = i2c_driver_probe;
+	driver->driver.remove = i2c_driver_remove;
 
- out_unlock:
-	up(&core_lists);
-	return res;
+	return driver_register(&driver->driver);
 }
 
 int i2c_del_driver(struct i2c_driver *driver)
 {
-	struct list_head   *item1, *item2, *_n;
-	struct i2c_client  *client;
-	struct i2c_adapter *adap;
-	
-	int res = 0;
-
-	down(&core_lists);
-
-	/* Have a look at each adapter, if clients of this driver are still
-	 * attached. If so, detach them to be able to kill the driver 
-	 * afterwards.
-	 */
-	DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n"));
-	/* removing clients does not depend on the notify flag, else 
-	 * invalid operation might (will!) result, when using stale client
-	 * pointers.
-	 */
-	list_for_each(item1,&adapters) {
-		adap = list_entry(item1, struct i2c_adapter, list);
-		DEB2(dev_dbg(&adap->dev, "examining adapter\n"));
-		if (driver->detach_adapter) {
-			if ((res = driver->detach_adapter(adap))) {
-				dev_warn(&adap->dev, "while unregistering "
-				       "dummy driver %s, adapter could "
-				       "not be detached properly; driver "
-				       "not unloaded!",driver->name);
-				goto out_unlock;
-			}
-		} else {
-			list_for_each_safe(item2, _n, &adap->clients) {
-				client = list_entry(item2, struct i2c_client, list);
-				if (client->driver != driver)
-					continue;
-				DEB2(printk(KERN_DEBUG "i2c-core.o: "
-					    "detaching client %s:\n",
-					    client->name));
-				if ((res = driver->detach_client(client))) {
-					dev_err(&adap->dev, "while "
-						"unregistering driver "
-						"`%s', the client at "
-						"address %02x of "
-						"adapter could not "
-						"be detached; driver "
-						"not unloaded!",
-						driver->name,
-						client->addr);
-					goto out_unlock;
-				}
-			}
-		}
-	}
-
-	driver_unregister(&driver->driver);
-	list_del(&driver->list);
-	DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name));
-
- out_unlock:
-	up(&core_lists);
-	return 0;
+	return driver_unregister(&driver->driver);
 }
 
-static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
+/* @dev client
+ */ 
+static int _i2c_check_addr(struct device *dev, int *data)
 {
-	struct list_head   *item;
-	struct i2c_client  *client;
+	struct i2c_client*client;
 
-	list_for_each(item,&adapter->clients) {
-		client = list_entry(item, struct i2c_client, list);
-		if (client->addr == addr)
-			return -EBUSY;
-	}
-	return 0;
+ 	/* We hit the dummy device */
+	if (! dev->driver) 
+	    return 0;
+
+	client = to_i2c_client(dev);
+	if (client->addr == *data)
+		return -EBUSY;
+	else
+		return 0;
 }
 
+/* returns -EBUSY if some client on @adapter has address @addr */
 int i2c_check_addr(struct i2c_adapter *adapter, int addr)
 {
-	int rval;
-
-	down(&adapter->clist_lock);
-	rval = __i2c_check_addr(adapter, addr);
-	up(&adapter->clist_lock);
-
-	return rval;
+	return bus_for_each_dev(&i2c_bus_type, &adapter->dev.children, &addr, _i2c_check_addr);
 }
 
+/* i2c_driver_probe will eventually get here in driver->attach_adapter
+ */
 int i2c_attach_client(struct i2c_client *client)
 {
-	struct i2c_adapter *adapter = client->adapter;
-
-	down(&adapter->clist_lock);
-	if (__i2c_check_addr(client->adapter, client->addr)) {
-		up(&adapter->clist_lock);
+	int res = 0;
+	if (i2c_check_addr(adapter, client->addr) ) {
 		return -EBUSY;
 	}
-	list_add_tail(&client->list,&adapter->clients);
-	up(&adapter->clist_lock);
 	
 	if (adapter->client_register)  {
 		if (adapter->client_register(client))  {
@@ -392,7 +247,7 @@
 	return 0;
 }
 
-
+/* i2c_driver_remove will eventually get here in driver->detach_client */
 int i2c_detach_client(struct i2c_client *client)
 {
 	struct i2c_adapter *adapter = client->adapter;
@@ -407,44 +262,21 @@
 			printk(KERN_ERR
 			       "i2c-core.o: client_unregister [%s] failed, "
 			       "client not detached", client->name);
-			goto out;
+			return res;
 		}
 	}
 
-	down(&adapter->clist_lock);
-	list_del(&client->list);
 	init_completion(&client->released);
 	device_remove_file(&client->dev, &dev_attr_client_name);
 	device_unregister(&client->dev);
-	up(&adapter->clist_lock);
 	wait_for_completion(&client->released);
 
- out:
 	return res;
 }
 
-static int i2c_inc_use_client(struct i2c_client *client)
-{
-
-	if (!try_module_get(client->driver->owner))
-		return -ENODEV;
-	if (!try_module_get(client->adapter->owner)) {
-		module_put(client->driver->owner);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static void i2c_dec_use_client(struct i2c_client *client)
-{
-	module_put(client->driver->owner);
-	module_put(client->adapter->owner);
-}
-
 int i2c_use_client(struct i2c_client *client)
 {
-	if (!i2c_inc_use_client(client))
+	if (! get_device(&client->dev))
 		return -ENODEV;
 
 	if (client->flags & I2C_CLIENT_ALLOW_USE) {
@@ -457,8 +289,9 @@
 	}
 
 	return 0;
+
  busy:
-	i2c_dec_use_client(client);
+	put_device(&client->dev);
 	return -EBUSY;
 }
 
@@ -474,32 +307,90 @@
 		}
 	}
 	
-	i2c_dec_use_client(client);
+	put_device(&client->dev);
+	
+	return 0;
+}
+
+struct _i2c_client_cmd {
+	unsigned int cmd;
+	void * arg;
+};
+
+/* @dev client
+ */ 
+static int _i2c_client_command(struct device *dev, struct _i2c_client_cmd *data)
+{
+	struct i2c_client *client = to_i2c_client(dev); 
+
+ 	/* Bus has one device template to probe drivers */
+	if (! client) 
+	    return 0;
+
+	if (NULL != client->driver->command)
+		return client->driver->command(client,data->cmd,data->arg);
 	
 	return 0;
 }
 
 void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
 {
-	struct list_head  *item;
-	struct i2c_client *client;
+	struct device *dev = &adap->dev;
+	struct _i2c_cmd_data data = { .cmd = cmd, .arg = arg };
 
-	down(&adap->clist_lock);
-	list_for_each(item,&adap->clients) {
-		client = list_entry(item, struct i2c_client, list);
-		if (!try_module_get(client->driver->owner))
-			continue;
-		if (NULL != client->driver->command) {
-			up(&adap->clist_lock);
-			client->driver->command(client,cmd,arg);
-			down(&adap->clist_lock);
-		}
-		module_put(client->driver->owner);
-       }
-       up(&adap->clist_lock);
+	bus_for_each_dev(&i2c_bus_type, &dev->children, &data, _i2c_client_command);
+}
+
+/* A bus has no (client) devices until a (client) driver creates one.
+ * With driver-model, a device must exist before the probe will take place. 
+ * 
+ * With the creation of dummy device, drivers will try to bind with possible
+ * (clients) on this bus. This device will never bind to any driver,
+ * a real device is allocated and registered within driver->probe routines.
+ */
+
+/* @dev The dummy device
+ *
+ * 1. in driver->attach_adapter(adapter)
+ * 
+ *    i2c_probe(adapter, address_list, device_probe)
+ *
+ * 2. in i2c_attach_client(client)
+ *
+ *    adapter->client_register(client)
+ *    device_register(&client->dev)
+ *
+ */
+static int i2c_driver_probe(struct device *dev) 
+{
+	struct i2c_driver *driver = to_i2c_driver(&dev->driver);
+	struct i2c_adapter *adapter = to_i2c_adapter(&dev->parent.dev);
+
+	return driver->attach_adapter(adapter);
 }
 
 
+/* @dev client
+ *
+ * 1. driver->detach_client(client)
+ * 
+ * 2. in i2c_detach_client(client)
+ *	adapter->client_unregister(client)
+ *	device_unregister(&client->dev)
+ *
+ */
+static int i2c_driver_remove(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct i2c_driver *driver = to_i2c_driver(&dev->driver);
+
+	return driver->detach_client(client);
+}
+
+
+
+
+
 /* 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)
 {
@@ -774,27 +665,36 @@
 	return adap->nr;
 }
 
+struct _i2c_id_data {
+	struct i2c_adapter *adap;
+	int id;
+}
+
+/* @dev adapter
+ */ 
+static int _i2c_get_adapter_id(struct device *dev, struct _i2c_id_data *data)
+{	
+	data->adap = to_i2c_adapter(dev);
+	
+	if  ((data->adap->nr == data->id) && get_device(dev))
+		return 1;
+	
+	return 0;
+}
+
 struct i2c_adapter* i2c_get_adapter(int id)
 {
-	struct list_head   *item;
-	struct i2c_adapter *adapter;
+	struct _i2c_id_data data = { .id = id };
 	
-	down(&core_lists);
-	list_for_each(item,&adapters) {
-		adapter = list_entry(item, struct i2c_adapter, list);
-		if (id == adapter->nr &&
-		    try_module_get(adapter->owner)) {
-			up(&core_lists);
-			return adapter;
-		}
-	}
-	up(&core_lists);
-	return NULL;
+	if ( bus_for_each_dev(&i2c_bus_type, &i2c_adapter_class->children , &data, _i2c_adapter_id) )
+		return data->adap;
+	else
+		return NULL;
 }
 
 void i2c_put_adapter(struct i2c_adapter *adap)
 {
-	module_put(adap->owner);
+	put_device(&adap->dev);
 }
 
 /* The SMBus parts */


[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux