Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1380214
  • 博文数量: 860
  • 博客积分: 425
  • 博客等级: 下士
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-20 19:57
个人简介

对技术执着

文章分类

全部博文(860)

文章存档

2019年(16)

2018年(12)

2015年(732)

2013年(85)

2012年(15)

我的朋友

分类: LINUX

2015-03-14 15:37:48

上面讲完控制器设备的注册,下面继续接着上面的,讲下控制器平台驱动的注册。
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探测函数,由于注册设备和注册驱动时,都要调用对应驱动的探测函数,所以重点看的就是探测函数。

阅读(535) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~