基于高通MSM 8x60的I2C驱动终极讲解(7)
来源:互联网 发布:网络银行的交易额 编辑:程序博客网 时间:2024/05/08 14:18
上面讲完控制器设备的注册,下面继续接着上面的,讲下控制器平台驱动的注册。
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,
},
};
.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);//平台驱动的注册函数
}
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;
{
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加入到总线上
}
{
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;
{
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函数
{
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;
{
struct device_driver *drv = data;
if (!driver_match_device(drv, dev))//该函数调用总线的match函数,进行匹配
return 0;
return 0;
if (!dev->driver)//到此匹配成功,并且dev的driver为空,则执行如下探测函数
driver_probe_device(drv, dev);
return 0;
}
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);
}
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;
}
{
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);
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
return drv->probe(dev);
}
}
这个函数没什么东西,就是折腾下,去执行platform中的探测函数。到处算是驱动框架分析完毕,下一节开始分析具体的probe探测函数,由于注册设备和注册驱动时,都要调用对应驱动的探测函数,所以重点看的就是探测函数。
0 0
- 基于高通MSM 8x60的I2C驱动终极讲解(7)
- 基于高通MSM 8x60的I2C驱动终极讲解(8)
- 基于高通MSM 8x60的I2C驱动终极讲解(1)
- 基于高通MSM 8x60的I2C驱动终极讲解(2)
- 基于高通MSM 8x60的I2C驱动终极讲解(3)
- 基于高通MSM 8x60的I2C驱动终极讲解(4)
- 基于高通MSM 8x60的I2C驱动终极讲解(5)
- 基于高通MSM 8x60的I2C驱动终极讲解(6)
- 基于高通MSM 8x60的I2C驱动终极讲解(9)
- 基于高通MSM 8x60的I2C驱动终极讲解(10)
- 基于高通MSM 8x60的I2C驱动终极讲解(11)
- 基于高通MSM 8x60的I2C驱动终极讲解(12)
- 基于高通MSM 8x60的I2C驱动终极讲解(13)
- 基于高通MSM 8x60的I2C驱动终极讲解总结
- 基于高通MSM 8x60的I2C驱动终极讲解(1)
- 基于MSM平台的振动器驱动移植
- 高通7x27a的I2c驱动电流更改
- Linux的I2C驱动讲解
- POJ 1008 Edge detection
- 基于高通MSM 8x60的I2C驱动终极讲解(6)
- floyd两题:POJ1125 Stockbroker Grapevine 和VIJOS P1046 观光旅游
- magento 如何上传file/image/video
- ,就走在雨里,不快不慢,任其洗尽满心疲惫
- 基于高通MSM 8x60的I2C驱动终极讲解(7)
- 基于高通MSM 8x60的I2C驱动终极讲解(8)
- 【GamingAnywhere源码分析之知识补充一】静态链接库与动态链接库
- 解决Eclipse项目图标上的红色感叹号,红叉
- Magento调试模式 - 页面空白,打开错误报告的方法
- php实现session入库
- HDU 1269(tarjan求强连通)
- 程序员转型路上的十条建议
- 寻找真正的入口(OEP)---广义ESP定律