您的位置:首页 > 其它

基于高通MSM 8x60的I2C驱动终极讲解(7)

2014-01-16 19:54 344 查看
上面讲完控制器设备的注册,下面继续接着上面的,讲下控制器平台驱动的注册。

static struct platform_driver qup_i2c_driver = {

.probe = qup_i2c_probe,

.remove = __devexit_p(qup_i2c_remove),//如果编译为静态的,则__devexit_p为空

.driver = {

.name = "qup_i2c",

.owner = THIS_MODULE,

.pm = &i2c_qup_dev_pm_ops,

},

};

/* QUP may be needed to bring up other drivers */

static int __init qup_i2c_init_driver(void)

{

return platform_driver_register(&qup_i2c_driver);//平台驱动的注册函数

}


arch_initcall(qup_i2c_init_driver);//注:该初始化的优先级别为3 .initcall3.init

下面开始分析,平台驱动如何注册驱动的。
int platform_driver_register(struct platform_driver *drv)

{

drv->driver.bus = &platform_bus_type;//把该driver的bus类型赋值为平台总线类型

if (drv->probe)//platform的探测函数不为空,则该driver的probe函数赋值为platform_drv_probe

drv->driver.probe = platform_drv_probe;

if (drv->remove)//同上

drv->driver.remove = platform_drv_remove;

if (drv->shutdown)//同上

drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver);

}
注册该platform中的driver成员,下面跟踪下注册的过程。
int driver_register(struct device_driver *drv)

{

other = driver_find(drv->name, drv->bus);//判读查找该驱动是否已经在该总线上注册过?

ret = bus_add_driver(drv);//如果没有注册过,就把该drv加入到总线上

}
继续分析,加入的过程:
int bus_add_driver(struct device_driver *drv)

{

struct bus_type *bus;

struct driver_private *priv;

priv = kzalloc(sizeof(*priv), GFP_KERNEL);//分配一个priv私有数据结构,并初始化

klist_init(&priv->klist_devices, NULL, NULL);

priv->driver = drv;//把该私有结构挂到driver上

drv->p = priv;

priv->kobj.kset = bus->p->drivers_kset;

if (drv->bus->p->drivers_autoprobe) {//如果bus设置了drivers的自动探测,则执行探测绑定

error = driver_attach(drv);

}

klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);//到处已经探测成功,把该驱动加入bus的driver的链表中

return 0;
}
继续跟踪探测,绑定函数,该函数是取出总线设备链表的每一个设备,和该驱动匹配
int driver_attach(struct device_driver *drv)

{

return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

}

继续看_driver_attach函数
static int __driver_attach(struct device *dev, void *data)

{

struct device_driver *drv = data;
if (!driver_match_device(drv, dev))//该函数调用总线的match函数,进行匹配

return 0;
if (!dev->driver)//到此匹配成功,并且dev的driver为空,则执行如下探测函数

driver_probe_device(drv, dev);

return 0;

}
下面就跟踪下探测函数的实现:
int driver_probe_device(struct device_driver *drv, struct device *dev)

{
dev->driver = drv;//关联二者

ret = really_probe(dev, drv);

}
继续跟踪:
static int really_probe(struct device *dev, struct device_driver *drv)

{

if (dev->bus->probe) {//如果总线上有probe函数,优先调用总线的该函数

ret = dev->bus->probe(dev);

if (ret)

goto probe_failed;

} else if (drv->probe) {//如果drv的不为空,则调用driver的探测函数

ret = drv->probe(dev);

if (ret)

goto probe_failed;

}
driver_bound(dev);//探测成功后,绑定,也就是把该dev加入到driver的device链表

}
到处平台驱动的注册函数完毕,已经把该平台驱动加入到对应的总线中,以及和对应的平台设备绑定。
因为此处为平台设备,所以还有一点需要分析:就是探测函数
此时执行的是:drv->driver.probe = platform_drv_probe;

函数,下面分析下,该函数干了什么活:
static int platform_drv_probe(struct device *_dev)

{

struct platform_driver *drv = to_platform_driver(_dev->driver);

struct platform_device *dev = to_platform_device(_dev);
return drv->probe(dev);

}
这个函数没什么东西,就是折腾下,去执行platform中的探测函数。到处算是驱动框架分析完毕,下一节开始分析具体的probe探测函数,由于注册设备和注册驱动时,都要调用对应驱动的探测函数,所以重点看的就是探测函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: