LINUX平台下IIC子系统的经典分布图如下:
下面主要针对内核中IIC新模式(new style)进行分析.
下面以S3C2440平台搭载的24C08进行整个LINUX IIC子系统的分析.
1.如何生成用户空间的设备节点:
1-1.24c08驱动端:
24c08的驱动代码位于drivers/misc/eeprom/at24.c
入口函数:
module_init(at24_init);
static int __init at24_init(void)
{
return i2c_add_driver(&at24_driver);
}
在LINUX内核中,每个IIC驱动对应的结构体为struct i2c_driver.24c08也不例外:
static struct i2c_driver at24_driver = {
.driver = {
.name = "at24",
.owner = THIS_MODULE,
},
.probe = at24_probe,
.remove = __devexit_p(at24_remove),
.id_table = at24_ids,
};
这里有一个很重要的域:id_table:
static const struct i2c_device_id at24_ids[] = {
/* needs 8 addresses as A0-A2 are ignored */
{ "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },
/* old variants can't be handled with this generic entry! */
{ "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) },
{ "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) },
/* spd is a 24c02 in memory DIMMs */
{ "spd", AT24_DEVICE_MAGIC(2048 / 8,
AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
{ "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) },
/* 24rf08 quirk is handled at i2c-core */
{ "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) },
{ "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },
{ "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },
{ "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },
{ "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },
{ "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
{ "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
{ "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },
{ "at24", 0 },
{ /* END OF LIST */ }
};
id_table域是探测此驱动支持哪些设备的依据,下面便是整个系统的调用流程追踪,主要是函数i2c_add_driver(&at24_driver):
static inline int i2c_add_driver(struct i2c_driver *driver)
{
return i2c_register_driver(THIS_MODULE, driver);
}
-->
/*
* 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.
*/
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
/* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p)))
return -EAGAIN;
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
/* When registration returns, the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver);
if (res)
return res;
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
mutex_lock(&core_lock);
bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
mutex_unlock(&core_lock);
return 0;
}
linux每个IIC驱动都是挂在IIC这条总线上的,见上面代码:
driver->driver.bus = &i2c_bus_type;
类似usb、spi等子系统一样,每个驱动都会标明其所属的总线类型.这种驱动依附总线的一个重要意义在于匹配条件:IIC有IIC的匹配条件、USB和USB的匹配条件等.在这里需要铭记我们这个24c08属于iic driver,而iic driver是隶属IIC BUS的.下面继承跟踪域id_table的意义,在函数i2c_register_driver()函数里面第二个关注的地方语句是:
res = driver_register(&driver->driver);
其实,这是LINUX驱动里面一个"核心基类"函数,所有的隶属总线的驱动(像uart、spi、usb等)均路由此函数,因此,可以独立来理解,因为此函数与子系统无关.其最重大的意义在于回调到具体调用此函数的总线的match函数的执行.下面通过代码验证这一点:
int driver_register(struct device_driver *drv)
{
... ...;
ret = bus_add_driver(drv);
... ...;
}
展开函数bus_add_driver():
int bus_add_driver(struct device_driver *drv)
{
... ...;
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
... ...;
}
展开函数driver_attach():
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
函数bus_for_each_dev会遍历挂在此总线上的设备,再根据一定的"匹配条件"(主要通过回调函数__driver_attach)来看这个设备是否被这个驱动所支持.展开如下:
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
if (!bus)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}
下面我们来看函数__driver_attach():
static int __driver_attach(struct device *dev, void *data)
{
if (!driver_match_device(drv, dev))
return 0;
if (!dev->driver)
driver_probe_device(drv, dev);
}
这里有两个比较重要的函数:driver_match_device()和driver_probe_device().其中和id_table域相关的函数是driver_match_device()函数;而后者是device和driver相关的函数.
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
可以看到,这里将会回调总线上的match函数,对于IIC总线而言,其match函数是:i2c_device_match()
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.suspend = i2c_device_suspend,
.resume = i2c_device_resume,
};
展开函数i2c_device_match():
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
return 0;
}
继续展开函数i2c_match_id():
static const struct i2c_d