Commit 22f0b1c0 authored by Gerd Knorr's avatar Gerd Knorr Committed by Greg Kroah-Hartman

[PATCH] i2c #1/3: listify i2c core

This is the first of tree patches for i2c.  Trying to get the i2c
cleanups finshed before 2.6.x, so we (hopefully) don't have a
ever-changing i2c subsystem in 2.7.x again (which is very annonying for
driver maintainance).

Changes:

 * listify i2c-core, i.e. make it use <linux/list.h> instead of
   statically-sized arrays, removed lots of ugly code :)
 * added i2c_(get|put)_adapter, changed i2c-dev.c to use these
   functions instead maintaining is own adapter list.
 * killed the I2C_DF_DUMMY flag which had the strange semantics to
   make the i2c subsystem call driver->attach_adapter on detaches.
   Added a detach_adapter() callback instead.
 * some other minor cleanups along the way ...
parent 6230bb01
...@@ -38,8 +38,8 @@ ...@@ -38,8 +38,8 @@
#define DEB(x) if (i2c_debug>=1) x; #define DEB(x) if (i2c_debug>=1) x;
#define DEB2(x) if (i2c_debug>=2) x; #define DEB2(x) if (i2c_debug>=2) x;
static struct i2c_adapter *adapters[I2C_ADAP_MAX]; static LIST_HEAD(adapters);
static struct i2c_driver *drivers[I2C_DRIVER_MAX]; static LIST_HEAD(drivers);
static DECLARE_MUTEX(core_lists); static DECLARE_MUTEX(core_lists);
/**** debug level */ /**** debug level */
...@@ -75,23 +75,17 @@ static struct device_driver i2c_generic_driver = { ...@@ -75,23 +75,17 @@ static struct device_driver i2c_generic_driver = {
*/ */
int i2c_add_adapter(struct i2c_adapter *adap) int i2c_add_adapter(struct i2c_adapter *adap)
{ {
int res = 0, i, j; static int nr = 0;
struct list_head *item;
struct i2c_driver *driver;
down(&core_lists); down(&core_lists);
for (i = 0; i < I2C_ADAP_MAX; i++)
if (NULL == adapters[i])
break;
if (I2C_ADAP_MAX == i) {
dev_warn(&adap->dev,
"register_adapter - enlarge I2C_ADAP_MAX.\n");
res = -ENOMEM;
goto out_unlock;
}
adapters[i] = adap; adap->nr = nr++;
init_MUTEX(&adap->bus_lock);
init_MUTEX(&adap->bus); init_MUTEX(&adap->clist_lock);
init_MUTEX(&adap->list); list_add_tail(&adap->list,&adapters);
INIT_LIST_HEAD(&adap->clients);
/* Add the adapter to the driver core. /* Add the adapter to the driver core.
* If the parent pointer is not set up, * If the parent pointer is not set up,
...@@ -99,77 +93,65 @@ int i2c_add_adapter(struct i2c_adapter *adap) ...@@ -99,77 +93,65 @@ int i2c_add_adapter(struct i2c_adapter *adap)
*/ */
if (adap->dev.parent == NULL) if (adap->dev.parent == NULL)
adap->dev.parent = &legacy_bus; adap->dev.parent = &legacy_bus;
sprintf(adap->dev.bus_id, "i2c-%d", i); sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
adap->dev.driver = &i2c_generic_driver; adap->dev.driver = &i2c_generic_driver;
device_register(&adap->dev); device_register(&adap->dev);
/* inform drivers of new adapters */ /* inform drivers of new adapters */
for (j=0;j<I2C_DRIVER_MAX;j++) list_for_each(item,&drivers) {
if (drivers[j]!=NULL && driver = list_entry(item, struct i2c_driver, list);
(drivers[j]->flags&(I2C_DF_NOTIFY|I2C_DF_DUMMY))) if (driver->flags & I2C_DF_NOTIFY)
/* We ignore the return code; if it fails, too bad */ /* We ignore the return code; if it fails, too bad */
drivers[j]->attach_adapter(adap); driver->attach_adapter(adap);
}
up(&core_lists); up(&core_lists);
DEB(dev_dbg(&adap->dev, "registered as adapter %d.\n", i));
out_unlock: DEB(dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr));
up(&core_lists); return 0;
return res;;
} }
int i2c_del_adapter(struct i2c_adapter *adap) int i2c_del_adapter(struct i2c_adapter *adap)
{ {
int res = 0, i, j; struct list_head *item;
struct i2c_driver *driver;
struct i2c_client *client;
int res = 0;
down(&core_lists); down(&core_lists);
for (i = 0; i < I2C_ADAP_MAX; i++)
if (adap == adapters[i])
break;
if (I2C_ADAP_MAX == i) {
dev_warn(&adap->dev, "unregister_adapter adap not found.\n");
res = -ENODEV;
goto out_unlock;
}
/* DUMMY drivers do not register their clients, so we have to list_for_each(item,&drivers) {
* use a trick here: we call driver->attach_adapter to driver = list_entry(item, struct i2c_driver, list);
* *detach* it! Of course, each dummy driver should know about if (driver->detach_adapter)
* this or hell will break loose... if ((res = driver->detach_adapter(adap))) {
*/
for (j = 0; j < I2C_DRIVER_MAX; j++)
if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY))
if ((res = drivers[j]->attach_adapter(adap))) {
dev_warn(&adap->dev, "can't detach adapter" dev_warn(&adap->dev, "can't detach adapter"
"while detaching driver %s: driver not " "while detaching driver %s: driver not "
"detached!", drivers[j]->name); "detached!", driver->name);
goto out_unlock; goto out_unlock;
} }
}
/* detach any active clients. This must be done first, because /* detach any active clients. This must be done first, because
* it can fail; in which case we give upp. */ * it can fail; in which case we give upp. */
for (j=0;j<I2C_CLIENT_MAX;j++) { list_for_each(item,&adap->clients) {
struct i2c_client *client = adap->clients[j]; client = list_entry(item, struct i2c_client, list);
if (client!=NULL) {
/* detaching devices is unconditional of the set notify /* detaching devices is unconditional of the set notify
* flag, as _all_ clients that reside on the adapter * flag, as _all_ clients that reside on the adapter
* must be deleted, as this would cause invalid states. * must be deleted, as this would cause invalid states.
*/ */
if ((res=client->driver->detach_client(client))) { if ((res=client->driver->detach_client(client))) {
dev_err(&adap->dev, "adapter not " dev_err(&adap->dev, "adapter not "
"unregistered, because client at " "unregistered, because client at "
"address %02x can't be detached. ", "address %02x can't be detached. ",
client->addr); client->addr);
goto out_unlock; goto out_unlock;
}
} }
} }
/* clean up the sysfs representation */ /* clean up the sysfs representation */
device_unregister(&adap->dev); device_unregister(&adap->dev);
list_del(&adap->list);
adapters[i] = NULL;
DEB(dev_dbg(&adap->dev, "adapter unregistered\n")); DEB(dev_dbg(&adap->dev, "adapter unregistered\n"));
...@@ -187,24 +169,11 @@ int i2c_del_adapter(struct i2c_adapter *adap) ...@@ -187,24 +169,11 @@ int i2c_del_adapter(struct i2c_adapter *adap)
int i2c_add_driver(struct i2c_driver *driver) int i2c_add_driver(struct i2c_driver *driver)
{ {
int res = 0, i; struct list_head *item;
struct i2c_adapter *adapter;
int res = 0;
down(&core_lists); down(&core_lists);
for (i = 0; i < I2C_DRIVER_MAX; i++)
if (NULL == drivers[i])
break;
if (I2C_DRIVER_MAX == i) {
printk(KERN_WARNING
" i2c-core.o: register_driver(%s) "
"- enlarge I2C_DRIVER_MAX.\n",
driver->name);
res = -ENOMEM;
goto out_unlock;
}
drivers[i] = driver;
DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
/* add the driver to the list of i2c drivers in the driver core */ /* add the driver to the list of i2c drivers in the driver core */
driver->driver.name = driver->name; driver->driver.name = driver->name;
...@@ -216,13 +185,14 @@ int i2c_add_driver(struct i2c_driver *driver) ...@@ -216,13 +185,14 @@ int i2c_add_driver(struct i2c_driver *driver)
if (res) if (res)
goto out_unlock; goto out_unlock;
/* now look for instances of driver on our adapters list_add_tail(&driver->list,&drivers);
*/ DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) {
for (i=0;i<I2C_ADAP_MAX;i++) { /* now look for instances of driver on our adapters */
if (adapters[i]!=NULL) if (driver->flags & I2C_DF_NOTIFY) {
/* Ignore errors */ list_for_each(item,&adapters) {
driver->attach_adapter(adapters[i]); adapter = list_entry(item, struct i2c_adapter, list);
driver->attach_adapter(adapter);
} }
} }
...@@ -233,44 +203,29 @@ int i2c_add_driver(struct i2c_driver *driver) ...@@ -233,44 +203,29 @@ int i2c_add_driver(struct i2c_driver *driver)
int i2c_del_driver(struct i2c_driver *driver) int i2c_del_driver(struct i2c_driver *driver)
{ {
int res = 0, i, j, k; struct list_head *item1;
struct list_head *item2;
struct i2c_client *client;
struct i2c_adapter *adap;
int res = 0;
down(&core_lists); down(&core_lists);
for (i = 0; i < I2C_DRIVER_MAX; i++)
if (driver == drivers[i])
break;
if (I2C_DRIVER_MAX == i) {
printk(KERN_WARNING " i2c-core.o: unregister_driver: "
"[%s] not found\n",
driver->name);
res = -ENODEV;
goto out_unlock;
}
driver_unregister(&driver->driver);
/* Have a look at each adapter, if clients of this driver are still /* 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 * attached. If so, detach them to be able to kill the driver
* afterwards. * afterwards.
*/ */
DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n")); DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n"));
/* removing clients does not depend on the notify flag, else /* removing clients does not depend on the notify flag, else
* invalid operation might (will!) result, when using stale client * invalid operation might (will!) result, when using stale client
* pointers. * pointers.
*/ */
for (k=0;k<I2C_ADAP_MAX;k++) { list_for_each(item1,&adapters) {
struct i2c_adapter *adap = adapters[k]; adap = list_entry(item1, struct i2c_adapter, list);
if (adap == NULL) /* skip empty entries. */
continue;
DEB2(dev_dbg(&adap->dev, "examining adapter\n")); DEB2(dev_dbg(&adap->dev, "examining adapter\n"));
if (driver->flags & I2C_DF_DUMMY) { if (driver->detach_adapter) {
/* DUMMY drivers do not register their clients, so we have to if ((res = driver->detach_adapter(adap))) {
* use a trick here: we call driver->attach_adapter to
* *detach* it! Of course, each dummy driver should know about
* this or hell will break loose...
*/
if ((res = driver->attach_adapter(adap))) {
dev_warn(&adap->dev, "while unregistering " dev_warn(&adap->dev, "while unregistering "
"dummy driver %s, adapter could " "dummy driver %s, adapter could "
"not be detached properly; driver " "not be detached properly; driver "
...@@ -278,31 +233,31 @@ int i2c_del_driver(struct i2c_driver *driver) ...@@ -278,31 +233,31 @@ int i2c_del_driver(struct i2c_driver *driver)
goto out_unlock; goto out_unlock;
} }
} else { } else {
for (j=0;j<I2C_CLIENT_MAX;j++) { list_for_each(item2,&adap->clients) {
struct i2c_client *client = adap->clients[j]; client = list_entry(item2, struct i2c_client, list);
if (client != NULL && if (client->driver != driver)
client->driver == driver) { continue;
DEB2(printk(KERN_DEBUG "i2c-core.o: " DEB2(printk(KERN_DEBUG "i2c-core.o: "
"detaching client %s:\n", "detaching client %s:\n",
client->dev.name)); client->dev.name));
if ((res = driver->detach_client(client))) { if ((res = driver->detach_client(client))) {
dev_err(&adap->dev, "while " dev_err(&adap->dev, "while "
"unregistering driver " "unregistering driver "
"`%s', the client at " "`%s', the client at "
"address %02x of " "address %02x of "
"adapter could not " "adapter could not "
"be detached; driver " "be detached; driver "
"not unloaded!", "not unloaded!",
driver->name, driver->name,
client->addr); client->addr);
goto out_unlock; goto out_unlock;
}
} }
} }
} }
} }
drivers[i] = NULL;
driver_unregister(&driver->driver);
list_del(&driver->list);
DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name)); DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name));
out_unlock: out_unlock:
...@@ -310,14 +265,16 @@ int i2c_del_driver(struct i2c_driver *driver) ...@@ -310,14 +265,16 @@ int i2c_del_driver(struct i2c_driver *driver)
return 0; return 0;
} }
static int __i2c_check_addr(struct i2c_adapter *adapter, int addr) static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
{ {
int i; struct list_head *item;
struct i2c_client *client;
for (i = 0; i < I2C_CLIENT_MAX ; i++) list_for_each(item,&adapter->clients) {
if (adapter->clients[i] && (adapter->clients[i]->addr == addr)) client = list_entry(item, struct i2c_client, list);
if (client->addr == addr)
return -EBUSY; return -EBUSY;
}
return 0; return 0;
} }
...@@ -325,9 +282,9 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr) ...@@ -325,9 +282,9 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr)
{ {
int rval; int rval;
down(&adapter->list); down(&adapter->clist_lock);
rval = __i2c_check_addr(adapter, addr); rval = __i2c_check_addr(adapter, addr);
up(&adapter->list); up(&adapter->clist_lock);
return rval; return rval;
} }
...@@ -335,28 +292,14 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr) ...@@ -335,28 +292,14 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr)
int i2c_attach_client(struct i2c_client *client) int i2c_attach_client(struct i2c_client *client)
{ {
struct i2c_adapter *adapter = client->adapter; struct i2c_adapter *adapter = client->adapter;
int i;
down(&adapter->list);
if (__i2c_check_addr(client->adapter, client->addr))
goto out_unlock_list;
for (i = 0; i < I2C_CLIENT_MAX; i++) { down(&adapter->clist_lock);
if (!adapter->clients[i]) if (__i2c_check_addr(client->adapter, client->addr)) {
goto free_slot; up(&adapter->clist_lock);
return -EBUSY;
} }
list_add_tail(&client->list,&adapter->clients);
printk(KERN_WARNING up(&adapter->clist_lock);
" i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n",
client->dev.name);
out_unlock_list:
up(&adapter->list);
return -EBUSY;
free_slot:
adapter->clients[i] = client;
up(&adapter->list);
if (adapter->client_register) { if (adapter->client_register) {
if (adapter->client_register(client)) { if (adapter->client_register(client)) {
...@@ -388,7 +331,7 @@ int i2c_attach_client(struct i2c_client *client) ...@@ -388,7 +331,7 @@ int i2c_attach_client(struct i2c_client *client)
int i2c_detach_client(struct i2c_client *client) int i2c_detach_client(struct i2c_client *client)
{ {
struct i2c_adapter *adapter = client->adapter; struct i2c_adapter *adapter = client->adapter;
int res = 0, i; int res = 0;
if ((client->flags & I2C_CLIENT_ALLOW_USE) && (client->usage_count > 0)) if ((client->flags & I2C_CLIENT_ALLOW_USE) && (client->usage_count > 0))
return -EBUSY; return -EBUSY;
...@@ -403,22 +346,11 @@ int i2c_detach_client(struct i2c_client *client) ...@@ -403,22 +346,11 @@ int i2c_detach_client(struct i2c_client *client)
} }
} }
down(&adapter->list); down(&adapter->clist_lock);
for (i = 0; i < I2C_CLIENT_MAX; i++) { list_del(&client->list);
if (client == adapter->clients[i]) {
adapter->clients[i] = NULL;
goto out_unlock;
}
}
printk(KERN_WARNING
" i2c-core.o: unregister_client [%s] not found\n",
client->dev.name);
res = -ENODEV;
out_unlock:
device_unregister(&client->dev); device_unregister(&client->dev);
up(&adapter->list); up(&adapter->clist_lock);
out: out:
return res; return res;
} }
...@@ -516,9 +448,9 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num) ...@@ -516,9 +448,9 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num)
if (adap->algo->master_xfer) { if (adap->algo->master_xfer) {
DEB2(dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num)); DEB2(dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num));
down(&adap->bus); down(&adap->bus_lock);
ret = adap->algo->master_xfer(adap,msgs,num); ret = adap->algo->master_xfer(adap,msgs,num);
up(&adap->bus); up(&adap->bus_lock);
return ret; return ret;
} else { } else {
...@@ -542,9 +474,9 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count) ...@@ -542,9 +474,9 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
DEB2(dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n", DEB2(dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n",
count)); count));
down(&adap->bus); down(&adap->bus_lock);
ret = adap->algo->master_xfer(adap,&msg,1); ret = adap->algo->master_xfer(adap,&msg,1);
up(&adap->bus); up(&adap->bus_lock);
/* if everything went ok (i.e. 1 msg transmitted), return #bytes /* if everything went ok (i.e. 1 msg transmitted), return #bytes
* transmitted, else error code. * transmitted, else error code.
...@@ -572,9 +504,9 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count) ...@@ -572,9 +504,9 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
DEB2(dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n", DEB2(dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n",
count)); count));
down(&adap->bus); down(&adap->bus_lock);
ret = adap->algo->master_xfer(adap,&msg,1); ret = adap->algo->master_xfer(adap,&msg,1);
up(&adap->bus); up(&adap->bus_lock);
DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n",
ret, count, client->addr)); ret, count, client->addr));
...@@ -743,11 +675,30 @@ int i2c_probe(struct i2c_adapter *adapter, ...@@ -743,11 +675,30 @@ int i2c_probe(struct i2c_adapter *adapter,
*/ */
int i2c_adapter_id(struct i2c_adapter *adap) int i2c_adapter_id(struct i2c_adapter *adap)
{ {
int i; return adap->nr;
for (i = 0; i < I2C_ADAP_MAX; i++) }
if (adap == adapters[i])
return i; struct i2c_adapter* i2c_get_adapter(int id)
return -1; {
struct list_head *item;
struct i2c_adapter *adapter;
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;
}
void i2c_put_adapter(struct i2c_adapter *adap)
{
module_put(adap->owner);
} }
/* The SMBus parts */ /* The SMBus parts */
...@@ -1189,10 +1140,10 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, ...@@ -1189,10 +1140,10 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
} }
if (adapter->algo->smbus_xfer) { if (adapter->algo->smbus_xfer) {
down(&adapter->bus); down(&adapter->bus_lock);
res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
command,size,data); command,size,data);
up(&adapter->bus); up(&adapter->bus_lock);
} else } else
res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
command,size,data); command,size,data);
...@@ -1239,6 +1190,8 @@ EXPORT_SYMBOL(i2c_master_recv); ...@@ -1239,6 +1190,8 @@ EXPORT_SYMBOL(i2c_master_recv);
EXPORT_SYMBOL(i2c_control); EXPORT_SYMBOL(i2c_control);
EXPORT_SYMBOL(i2c_transfer); EXPORT_SYMBOL(i2c_transfer);
EXPORT_SYMBOL(i2c_adapter_id); EXPORT_SYMBOL(i2c_adapter_id);
EXPORT_SYMBOL(i2c_get_adapter);
EXPORT_SYMBOL(i2c_put_adapter);
EXPORT_SYMBOL(i2c_probe); EXPORT_SYMBOL(i2c_probe);
EXPORT_SYMBOL(i2c_smbus_xfer); EXPORT_SYMBOL(i2c_smbus_xfer);
......
...@@ -58,6 +58,7 @@ static int i2cdev_open (struct inode *inode, struct file *file); ...@@ -58,6 +58,7 @@ static int i2cdev_open (struct inode *inode, struct file *file);
static int i2cdev_release (struct inode *inode, struct file *file); static int i2cdev_release (struct inode *inode, struct file *file);
static int i2cdev_attach_adapter(struct i2c_adapter *adap); static int i2cdev_attach_adapter(struct i2c_adapter *adap);
static int i2cdev_detach_adapter(struct i2c_adapter *adap);
static int i2cdev_detach_client(struct i2c_client *client); static int i2cdev_detach_client(struct i2c_client *client);
static int i2cdev_command(struct i2c_client *client, unsigned int cmd, static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
void *arg); void *arg);
...@@ -72,15 +73,13 @@ static struct file_operations i2cdev_fops = { ...@@ -72,15 +73,13 @@ static struct file_operations i2cdev_fops = {
.release = i2cdev_release, .release = i2cdev_release,
}; };
#define I2CDEV_ADAPS_MAX I2C_ADAP_MAX
static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX];
static struct i2c_driver i2cdev_driver = { static struct i2c_driver i2cdev_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "dev driver", .name = "dev driver",
.id = I2C_DRIVERID_I2CDEV, .id = I2C_DRIVERID_I2CDEV,
.flags = I2C_DF_DUMMY, .flags = I2C_DF_NOTIFY,
.attach_adapter = i2cdev_attach_adapter, .attach_adapter = i2cdev_attach_adapter,
.detach_adapter = i2cdev_detach_adapter,
.detach_client = i2cdev_detach_client, .detach_client = i2cdev_detach_client,
.command = i2cdev_command, .command = i2cdev_command,
}; };
...@@ -340,35 +339,31 @@ static int i2cdev_open(struct inode *inode, struct file *file) ...@@ -340,35 +339,31 @@ static int i2cdev_open(struct inode *inode, struct file *file)
{ {
unsigned int minor = minor(inode->i_rdev); unsigned int minor = minor(inode->i_rdev);
struct i2c_client *client; struct i2c_client *client;
struct i2c_adapter *adap;
if ((minor >= I2CDEV_ADAPS_MAX) || !(i2cdev_adaps[minor])) adap = i2c_get_adapter(minor);
if (NULL == adap)
return -ENODEV; return -ENODEV;
client = kmalloc(sizeof(*client), GFP_KERNEL); client = kmalloc(sizeof(*client), GFP_KERNEL);
if (!client) if (!client) {
i2c_put_adapter(adap);
return -ENOMEM; return -ENOMEM;
}
memcpy(client, &i2cdev_client_template, sizeof(*client)); memcpy(client, &i2cdev_client_template, sizeof(*client));
/* registered with adapter, passed as client to user */ /* registered with adapter, passed as client to user */
client->adapter = i2cdev_adaps[minor]; client->adapter = adap;
file->private_data = client; file->private_data = client;
/* use adapter module, i2c-dev handled with fops */
if (!try_module_get(client->adapter->owner))
goto out_kfree;
return 0; return 0;
out_kfree:
kfree(client);
return -ENODEV;
} }
static int i2cdev_release(struct inode *inode, struct file *file) static int i2cdev_release(struct inode *inode, struct file *file)
{ {
struct i2c_client *client = file->private_data; struct i2c_client *client = file->private_data;
module_put(client->adapter->owner); i2c_put_adapter(client->adapter);
kfree(client); kfree(client);
file->private_data = NULL; file->private_data = NULL;
...@@ -377,33 +372,28 @@ static int i2cdev_release(struct inode *inode, struct file *file) ...@@ -377,33 +372,28 @@ static int i2cdev_release(struct inode *inode, struct file *file)
int i2cdev_attach_adapter(struct i2c_adapter *adap) int i2cdev_attach_adapter(struct i2c_adapter *adap)
{ {
int i;
char name[12]; char name[12];
int i;
if ((i = i2c_adapter_id(adap)) < 0) { i = i2c_adapter_id(adap);
dev_dbg(&adap->dev, "Unknown adapter ?!?\n");
return -ENODEV;
}
if (i >= I2CDEV_ADAPS_MAX) {
dev_dbg(&adap->dev, "Adapter number too large?!? (%d)\n",i);
return -ENODEV;
}
sprintf (name, "i2c/%d", i); sprintf (name, "i2c/%d", i);
if (! i2cdev_adaps[i]) {
i2cdev_adaps[i] = adap; devfs_register (NULL, name,
devfs_register (NULL, name,
DEVFS_FL_DEFAULT, I2C_MAJOR, i, DEVFS_FL_DEFAULT, I2C_MAJOR, i,
S_IFCHR | S_IRUSR | S_IWUSR, S_IFCHR | S_IRUSR | S_IWUSR,
&i2cdev_fops, NULL); &i2cdev_fops, NULL);
dev_dbg(&adap->dev, "Registered as minor %d\n", i); dev_dbg(&adap->dev, "Registered as minor %d\n", i);
} else { return 0;
/* This is actually a detach_adapter call! */ }
devfs_remove("i2c/%d", i);
i2cdev_adaps[i] = NULL; int i2cdev_detach_adapter(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "Adapter unregistered\n"); {
} int i;
i = i2c_adapter_id(adap);
devfs_remove("i2c/%d", i);
dev_dbg(&adap->dev, "Adapter unregistered\n");
return 0; return 0;
} }
......
...@@ -96,7 +96,8 @@ struct dpc ...@@ -96,7 +96,8 @@ struct dpc
static int dpc_probe(struct saa7146_dev* dev) static int dpc_probe(struct saa7146_dev* dev)
{ {
struct dpc* dpc = 0; struct dpc* dpc = 0;
int i = 0; struct i2c_client *client;
struct list_head *item;
dpc = (struct dpc*)kmalloc(sizeof(struct dpc), GFP_KERNEL); dpc = (struct dpc*)kmalloc(sizeof(struct dpc), GFP_KERNEL);
if( NULL == dpc ) { if( NULL == dpc ) {
...@@ -117,12 +118,10 @@ static int dpc_probe(struct saa7146_dev* dev) ...@@ -117,12 +118,10 @@ static int dpc_probe(struct saa7146_dev* dev)
} }
/* loop through all i2c-devices on the bus and look who is there */ /* loop through all i2c-devices on the bus and look who is there */
for(i = 0; i < I2C_CLIENT_MAX; i++) { list_for_each(item,&dpc->i2c_adapter.clients) {
if( NULL == dpc->i2c_adapter.clients[i] ) { client = list_entry(item, struct i2c_client, list);
continue; if( I2C_SAA7111A == client->addr )
} dpc->saa7111a = client;
if( I2C_SAA7111A == dpc->i2c_adapter.clients[i]->addr )
dpc->saa7111a = dpc->i2c_adapter.clients[i];
} }
/* check if all devices are present */ /* check if all devices are present */
......
...@@ -208,7 +208,8 @@ static int mxb_vbi_bypass(struct saa7146_dev* dev) ...@@ -208,7 +208,8 @@ static int mxb_vbi_bypass(struct saa7146_dev* dev)
static int mxb_probe(struct saa7146_dev* dev) static int mxb_probe(struct saa7146_dev* dev)
{ {
struct mxb* mxb = 0; struct mxb* mxb = 0;
int i = 0; struct i2c_client *client;
struct list_head *item;
request_module("tuner"); request_module("tuner");
request_module("tea6420"); request_module("tea6420");
...@@ -235,22 +236,20 @@ static int mxb_probe(struct saa7146_dev* dev) ...@@ -235,22 +236,20 @@ static int mxb_probe(struct saa7146_dev* dev)
} }
/* loop through all i2c-devices on the bus and look who is there */ /* loop through all i2c-devices on the bus and look who is there */
for(i = 0; i < I2C_CLIENT_MAX; i++) { list_for_each(item,&mxb->i2c_adapter.clients) {
if( NULL == mxb->i2c_adapter.clients[i] ) { client = list_entry(item, struct i2c_client, list);
continue; if( I2C_TEA6420_1 == client->addr )
} mxb->tea6420_1 = client;
if( I2C_TEA6420_1 == mxb->i2c_adapter.clients[i]->addr ) if( I2C_TEA6420_2 == client->addr )
mxb->tea6420_1 = mxb->i2c_adapter.clients[i]; mxb->tea6420_2 = client;
if( I2C_TEA6420_2 == mxb->i2c_adapter.clients[i]->addr ) if( I2C_TEA6415C_2 == client->addr )
mxb->tea6420_2 = mxb->i2c_adapter.clients[i]; mxb->tea6415c = client;
if( I2C_TEA6415C_2 == mxb->i2c_adapter.clients[i]->addr ) if( I2C_TDA9840 == client->addr )
mxb->tea6415c = mxb->i2c_adapter.clients[i]; mxb->tda9840 = client;
if( I2C_TDA9840 == mxb->i2c_adapter.clients[i]->addr ) if( I2C_SAA7111A == client->addr )
mxb->tda9840 = mxb->i2c_adapter.clients[i]; mxb->saa7111a = client;
if( I2C_SAA7111A == mxb->i2c_adapter.clients[i]->addr ) if( 0x60 == client->addr )
mxb->saa7111a = mxb->i2c_adapter.clients[i]; mxb->tuner = client;
if( 0x60 == mxb->i2c_adapter.clients[i]->addr )
mxb->tuner = mxb->i2c_adapter.clients[i];
} }
/* check if all devices are present */ /* check if all devices are present */
......
...@@ -217,8 +217,9 @@ static struct i2c_driver driver = { ...@@ -217,8 +217,9 @@ static struct i2c_driver driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "tv card mixer driver", .name = "tv card mixer driver",
.id = I2C_DRIVERID_TVMIXER, .id = I2C_DRIVERID_TVMIXER,
.flags = I2C_DF_DUMMY, .flags = I2C_DF_NOTIFY,
.attach_adapter = tvmixer_adapters, .attach_adapter = tvmixer_adapters,
.detach_adapter = tvmixer_adapters,
.detach_client = tvmixer_clients, .detach_client = tvmixer_clients,
}; };
...@@ -234,14 +235,15 @@ static struct file_operations tvmixer_fops = { ...@@ -234,14 +235,15 @@ static struct file_operations tvmixer_fops = {
static int tvmixer_adapters(struct i2c_adapter *adap) static int tvmixer_adapters(struct i2c_adapter *adap)
{ {
int i; struct list_head *item;
struct i2c_client *client;
if (debug) if (debug)
printk("tvmixer: adapter %s\n",adap->dev.name); printk("tvmixer: adapter %s\n",adap->dev.name);
for (i=0; i<I2C_CLIENT_MAX; i++) {
if (!adap->clients[i]) list_for_each(item,&adap->clients) {
continue; client = list_entry(item, struct i2c_client, list);
tvmixer_clients(adap->clients[i]); tvmixer_clients(client);
} }
return 0; return 0;
} }
...@@ -264,7 +266,8 @@ static int tvmixer_clients(struct i2c_client *client) ...@@ -264,7 +266,8 @@ static int tvmixer_clients(struct i2c_client *client)
client->adapter->dev.name); client->adapter->dev.name);
return -1; return -1;
} }
printk("tvmixer: debug: %s\n",client->dev.name); if (debug)
printk("tvmixer: debug: %s\n",client->dev.name);
/* unregister ?? */ /* unregister ?? */
for (i = 0; i < DEV_MAX; i++) { for (i = 0; i < DEV_MAX; i++) {
......
...@@ -39,12 +39,6 @@ ...@@ -39,12 +39,6 @@
/* --- General options ------------------------------------------------ */ /* --- General options ------------------------------------------------ */
#define I2C_ALGO_MAX 4 /* control memory consumption */
#define I2C_ADAP_MAX 16
#define I2C_DRIVER_MAX 16
#define I2C_CLIENT_MAX 32
#define I2C_DUMMY_MAX 4
struct i2c_msg; struct i2c_msg;
struct i2c_algorithm; struct i2c_algorithm;
struct i2c_adapter; struct i2c_adapter;
...@@ -131,6 +125,7 @@ struct i2c_driver { ...@@ -131,6 +125,7 @@ struct i2c_driver {
* i2c_attach_client. * i2c_attach_client.
*/ */
int (*attach_adapter)(struct i2c_adapter *); int (*attach_adapter)(struct i2c_adapter *);
int (*detach_adapter)(struct i2c_adapter *);
/* tells the driver that a client is about to be deleted & gives it /* 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 * the chance to remove its private data. Also, if the client struct
...@@ -145,6 +140,7 @@ struct i2c_driver { ...@@ -145,6 +140,7 @@ struct i2c_driver {
int (*command)(struct i2c_client *client,unsigned int cmd, void *arg); int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
struct device_driver driver; struct device_driver driver;
struct list_head list;
}; };
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver) #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
...@@ -169,6 +165,7 @@ struct i2c_client { ...@@ -169,6 +165,7 @@ struct i2c_client {
int usage_count; /* How many accesses currently */ int usage_count; /* How many accesses currently */
/* to the client */ /* to the client */
struct device dev; /* the device structure */ struct device dev; /* the device structure */
struct list_head list;
}; };
#define to_i2c_client(d) container_of(d, struct i2c_client, dev) #define to_i2c_client(d) container_of(d, struct i2c_client, dev)
...@@ -236,12 +233,10 @@ struct i2c_adapter { ...@@ -236,12 +233,10 @@ struct i2c_adapter {
int (*client_unregister)(struct i2c_client *); int (*client_unregister)(struct i2c_client *);
/* data fields that are valid for all devices */ /* data fields that are valid for all devices */
struct semaphore bus; struct semaphore bus_lock;
struct semaphore list; struct semaphore clist_lock;
unsigned int flags;/* flags specifying div. data */ unsigned int flags;/* flags specifying div. data */
struct i2c_client *clients[I2C_CLIENT_MAX];
int timeout; int timeout;
int retries; int retries;
struct device dev; /* the adapter device */ struct device dev; /* the adapter device */
...@@ -250,6 +245,10 @@ struct i2c_adapter { ...@@ -250,6 +245,10 @@ struct i2c_adapter {
/* No need to set this when you initialize the adapter */ /* No need to set this when you initialize the adapter */
int inode; int inode;
#endif /* def CONFIG_PROC_FS */ #endif /* def CONFIG_PROC_FS */
int nr;
struct list_head clients;
struct list_head list;
}; };
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
...@@ -265,7 +264,11 @@ static inline void i2c_set_adapdata (struct i2c_adapter *dev, void *data) ...@@ -265,7 +264,11 @@ static inline void i2c_set_adapdata (struct i2c_adapter *dev, void *data)
/*flags for the driver struct: */ /*flags for the driver struct: */
#define I2C_DF_NOTIFY 0x01 /* notify on bus (de/a)ttaches */ #define I2C_DF_NOTIFY 0x01 /* notify on bus (de/a)ttaches */
#define I2C_DF_DUMMY 0x02 /* do not connect any clients */ #if 0
/* this flag is gone -- there is a (optional) driver->detach_adapter
* callback now which can be used instead */
# define I2C_DF_DUMMY 0x02
#endif
/*flags for the client struct: */ /*flags for the client struct: */
#define I2C_CLIENT_ALLOW_USE 0x01 /* Client allows access */ #define I2C_CLIENT_ALLOW_USE 0x01 /* Client allows access */
...@@ -352,7 +355,8 @@ extern int i2c_control(struct i2c_client *,unsigned int, unsigned long); ...@@ -352,7 +355,8 @@ extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
* or -1 if the adapter was not registered. * or -1 if the adapter was not registered.
*/ */
extern int i2c_adapter_id(struct i2c_adapter *adap); extern int i2c_adapter_id(struct i2c_adapter *adap);
extern struct i2c_adapter* i2c_get_adapter(int id);
extern void i2c_put_adapter(struct i2c_adapter *adap);
/* Return the functionality mask */ /* Return the functionality mask */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment