在分析完drivers\base\文件夹下的内容之后,我们对驱动的基本操作已经有了一个大概的印象,现在,我们再重新复习一遍IIC设备的注册过程,用一个实例来将这条线融会贯通,同样的,用我们熟悉的ds1337为例来说说明,这一章的内容就比较散了,将会跳转在几大文件之间,所以要看明白这一章的内容,那么前面的东西就得先消化消化了。
其实驱动的注册过程,在网上以probe函数的调用过程为关键字做搜索,可以找到很多资料,将其过程描述得很清楚,所以我这里的很多内容,会和网上一些资料大部分雷同。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
流程小记:
1、 I2C设备的注册(DS13337),注册的驱动为ds1337_driver
2、 驱动的注册是在i2c-core.c中调用i2c_register_driver函数实现的,这里要特别注意的是,设置驱动所属的总线为i2c_bus_type,该总线的函数实现都在本文件中找。设置完成后,调用driver_register对设备驱动进行注册,注意传递给注册函数时的驱动结构成员已经变成了如下格式:
.driver = {
.name = "ds1337",
.owner = THIS_MODULE
.bus = &i2c_bus_type
},
3、 driver_register中的工作很简单,只是检查一下驱动和总线是否重复设置了probe等函数,如果重复设置了,则打印一个警告信息提示使用者,将使用总线上的操作函数。然后将驱动关联的设备链表挂空(这个概念请参考代码分析文件drivers\base\dd.c)。最后调用bus_add_driver函数将驱动添加到总线上
4、 在bus_add_driver函数的实现中,核心的操作有:
Ø 驱动drv->kobj.kset的设置——&bus->drivers,以及kobj的注册
Ø 如果总线有autoprobe属性,则执行driver_attach(drv),由于I2C驱动不是用probe探测的,所以不会probe函数,更不会有这个属性,所以以下(5、6可以跳过)
Ø klist_add_tail(&drv->knode_bus, &bus->klist_drivers);将驱动节点挂到总线的驱动链表中,完成驱动注册的实际操作
Ø 为驱动创建一些属性操作文件
5、 driver_attach的具体实现是:遍历总线bus的设备链表klist_devices,使每一个设备都执行一次__driver_attach(dev, data),这里的dev是当前设备,data则是驱动地址drv(因为一个驱动可以关联上很多设备,所以这里将遍历总线上的所有设备进行探测,而不是探测到一个后就中断循环)。而这个函数的具体实现只有一句,即先判断dev->driver是否指定,如果没有关联上,则执行driver_probe_device(drv, dev)关联设备和驱动。
6、 在driver_probe_device中,就有对总线关联函数的调用了
Ø bus->match函数的调用,i2c_device_match
Ø bus->probe或drv->probe(really_probe函数中),i2c_device_probe
Ø 以上两个函数调用成功,则认为该设备可以绑定该驱动,则最终调用klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);将设备关联到驱动的设备链表中
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
一切一切的入口,都从ds1337.c的驱动注册开始:
static int __init ds1337_init(void)
{
return i2c_add_driver(&ds1337_driver);
}
关联一下驱动:
static struct i2c_driver ds1337_driver = {
.driver = {
.name = "ds1337",
},
.attach_adapter = ds1337_attach_adapter,
.detach_client = ds1337_detach_client,
.command = ds1337_command,
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
我们关联一下注册函数的实现(include\linux\i2c.h):
static inline int i2c_add_driver(struct i2c_driver *driver)
{
return i2c_register_driver(THIS_MODULE, driver);
}
//drivers\i2c\i2c-core.c
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
if (is_newstyle_driver(driver)) { //这个宏的代码很简单,就不COPY了
//如果driver设置了probe或remove函数,则不能再设置下面三个函数
if (driver->attach_adapter || driver->detach_adapter || driver->detach_client) {
return -EINVAL;
}
}
//设置驱动所属模块,设置驱动所属的总线
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type; //这里我们要特别记住这个总线,因为base中的操作会直接调用这个总线设置的函数
//调用base中的函数注册驱动,因为下面的函数比较简单,所以我们先看一下后面的函数,然后在到这个函数里面看他具体的实现过程
//这里要注意的是,传入的参数是driver->driver,加上上面两行代码设置的参数,也就只是:
.driver = {
.name = "ds1337",
.owner = THIS_MODULE
.bus = &i2c_bus_type
},
res = driver_register(&driver->driver);
if (res) return res;
//加锁
mutex_lock(&core_lists);
list_add_tail(&driver->list,&drivers); //将驱动的节点加入到静态链表drivers中
//如果驱动关联了attach_adapter函数,进该if
//本驱动中有设置这个函数:.attach_adapter = ds1337_attach_adapter,所以将取出适配器adapters中所有的adapter,并执行驱动的attach_adapter函数(适配器绑定)
if (driver->attach_adapter) {
struct i2c_adapter *adapter;
list_for_each_entry(adapter, &adapters, list) {
driver->attach_adapter(adapter);
//在本范例中,这里调用的是ds1337.c中的ds1337_attach_adapter函数
}
}
mutex_unlock(&core_lists);
return 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
我们大概了解了i2c驱动注册的过程,然后我们将具体的范例代入代码中,再分析一次驱动的注册函数driver_register(drivers\base\driver.c)
int driver_register(struct device_driver * drv)
{
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown)) {
//打印警告:将执行总线的probe,remove,shutdown函数
}
klist_init(&drv->klist_devices, NULL, NULL); //驱动上没有关联设备
return bus_add_driver(drv);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
继续,进drivers\base\bus.c中看bus_add_driver的具体实现
再复习一次,这里的参数drv的数据内容只是如下:
.driver = {
.name = "ds1337",
.owner = THIS_MODULE
.bus = &i2c_bus_type
},
int bus_add_driver(struct device_driver *drv)
{
//驱动的总线引用加1,这里得到的是i2c_bus_type,其关联的代码在drivers\i2c\i2c-core.c
struct bus_type * bus = bus_get(drv->bus);
int error = 0;
if (!bus) return -EINVAL; //驱动没有所属的总线,错误返回
error = kobject_set_name(&drv->kobj, "%s", drv->name); //设置kobj为”ds1337”
drv->kobj.kset = &bus->drivers; //驱动kobj的set宿主为总线的驱动链表
error = kobject_register(&drv->kobj); //注册kobj
//如果驱动所属的总线有自动探测属性,则这里会执行自动探测函数
//虽然i2c总线上没有设置这个属性,但是为了了解驱动的一般过程,所以我们也会看进这个函数中
//由于后面的函数比较简单,为了保持函数分析的完成,我们先看后面的代码
if (drv->bus->drivers_autoprobe) {
error = driver_attach(drv);
if (error) goto out_unregister;
}
//将驱动的节点添加到总线的驱动链表中
//注1:这里的总线是I2C的总线——i2c_bus_type
//注2:这一步操作,实际也就是注册的实质——链表的挂接
//注3:虽然在驱动中并没有设置knode_bus,但因为取驱动实际只是取结构体中的一个成员,然后根据其成员反取整个结构体(container_of的操作对玩LINUX的人来说应该不陌生吧),所以knode_bus成员是否设置有值其实并无意义,有意义的只是该地址是属于哪个结构体。
klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
//这个函数在编译到内核中时候为空函数,所以我们认为他不是关键的部分,暂时不做研究
module_add_driver(drv->owner, drv);
//这三个属性操作文件的创建在分析drivers\base\bus.c时已经分析过了
error = driver_create_file(drv, &driver_attr_uevent); //为驱动关联属性操作函数
error = driver_add_attrs(bus, drv); //将总线的属性继承给驱动
error = add_bind_files(drv); //给驱动绑定bind和unbind函数
return error;
out_unregister:
kobject_unregister(&drv->kobj);
out_put_bus:
bus_put(bus);
return error;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
我们看看driver_attach的实现,drivers\base\dd.c中:
int driver_attach(struct device_driver * drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
@@@@@
drivers\base\bus.c中
int bus_for_each_dev(
struct bus_type * bus, // i2c_bus_type
struct device * start, //NULL
void * data, //驱动
int (*fn)(struct device *, void *)) //__driver_attach
{
struct klist_iter i;
struct device * dev;
int error = 0;
if (!bus) return -EINVAL; //没有所属总线,错误返回
//初始化klist的遍历,i->cur = NULL,即从头开始
klist_iter_init_node(&bus->klist_devices, &i,
(start ? &start->knode_bus : NULL));
//遍历总线上的每一个设备,执行fn函数,这里的fn就是:__driver_attach
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}
@@@@@
我们现在回过头来看看__driver_attach的具体实现,也是在drivers\base\bus.c中
//这里的参数,dev为总线上提取出来的设备,data为驱动,也就是ds1337的drv
//可见,关键的函数就一句:如果设备的驱动没有关联,则执行driver_probe_device函数
static int __driver_attach(struct device * dev, void * data)
{
struct device_driver * drv = data;
if (dev->parent) down(&dev->parent->sem);
down(&dev->sem);
if (!dev->driver) driver_probe_device(drv, dev);
up(&dev->sem);
if (dev->parent) up(&dev->parent->sem);
return 0;
}
@@@@@
继续探进去,在drivers\base\dd.c中
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
int ret = 0;
if (!device_is_registered(dev)) return -ENODEV; //设备未注册,错误返回
//执行总线的match函数对设备和驱动进行匹配
if (drv->bus->match && !drv->bus->match(dev, drv))
goto done;
ret = really_probe(dev, drv);
done:
return ret;
}
@@@@@
继续,同一文件中
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = 0;
atomic_inc(&probe_count); //有probe工作正在进行
WARN_ON(!list_empty(&dev->devres_head)); //设备的资源链表有资源,出警告
dev->driver = drv; //试探性的绑上驱动
if (driver_sysfs_add(dev)) { //添加驱动和设备的link文件
goto probe_failed;
}
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret) goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret) goto probe_failed;
}
//成功,设备和驱动完成绑定
//其核心实现代码:klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
driver_bound(dev);
ret = 1;
goto done;
probe_failed:
//探测失败的代码就不复制了,无非就是之前创建的文件的删除
ret = 0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}
至此,驱动的注册工作便全部完成。
至于ds1337_attach_adapter的具体实现,之前的代码已经有过分析了