您的位置:首页 > 运维架构 > Linux

i2c驱动注册过程---GSL3680为例进行详析---步骤1

2013-06-19 16:06 465 查看
Linux下i2c驱动的加载过程,分为i2c设备层、i2c adapter层与i2c核心层。

I2C设备驱动层也就是我们为特定i2c设备写的驱动。下面是i2c驱动的注册过程。

1:在我们写的i2c设备驱动中,我们会调用i2c_add_driver()开始i2c设备驱动的注册,该函数调用i2c_register_driver()完成所有注册操作。

2:i2c_register_driver会调用driver_register()来将设备驱动添加到总线的设备驱动列链中。

3:在driver_register()中,通过driver_find()来判断驱动是否已经注册,然后会调用bus_add_driver()将设备驱动添加到总线上。

4:在bus_add_driver()中初始化priv->klist_devices的值,并将priv赋值给drv->p,通过调用klist_add_tail(&priv->knode_bus,&bus->p->klist_drivers)将驱动信息保存到总线结构中,在此之前将调用driver_attach()。

5:在driver_attach()中,通过调用bus_for_each_dev(),遍历在总线上挂载的所有设备,并对每个设备(dev)调用__driver_attach()。

6:在__driver_attach()里会调用driver_match_device()来判断dev与driv的id是否相同,在i2c驱动里就会调用i2c_bus_type->match程序进行判断,当id相同时,将会调用driver_probe_device()。

7:在driver_probe_device(),首先会调用device_is_registered()判断dev是否注册,如没有注册则返回;若已经注册,则调用really_probe()。

8:在really_probe()里,首先将drv赋值给dev->driver,然后会调用总线的probe函数,在i2c驱动里,此时将会调用i2c总线的probe函数:i2c_device_probe()。

9:在i2c_device_probe()里,会根据to_i2c_driver(dev->driver)获取i2c驱动,也就是我们编写的具体的i2c设备驱动的结构体:static struct i2c_drivergsl_ts_driver{};。

10:这样就调用了我们驱动的probe()了,这就是我们在驱动里调用i2c_add_driver(),通过driver_register()的一系列调用,最后执行我们所写的probe():gsl_ts_probe()。

函数流程分析:


步骤1:分析驱动注册函数:i2c_add_driver()

函数分析:

/*此处的owner在i2c_add_driver调用的时候默认传入的是THIS_MODULE,这里的dirver就是i2c_add_driver传入的参数gsl_ts_driver。*/
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 */
//把驱动注册到内核驱动的i2c驱动列表中
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.
*/
/*注册设备驱动到总线的i2c设备驱动链中(内核中),它可以去匹配内中已经存在的client而后执行probe函数*/
res = driver_register(&driver->driver);/*注册驱动*/
if (res)
return res;

/* Drivers should switch to dev_pm_ops instead. */
//警告,用的休眠和唤醒的函数不是最新定义的,即传入的i2c驱动结构体中的休眠唤醒函数为空或者不能用
if (driver->suspend)
pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
driver->driver.name);
if (driver->resume)
pr_warn("i2c-core: driver [%s] using legacy resume method\n",
driver->driver.name);

pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

//初始化链表头用于挂接client,这是一个循环队列
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
//会尝试和i2c总线上所有的dev进行一次匹配,只要获取的dev为adapter时,就可执行后续操作
i2c_for_each_dev(driver, __process_new_driver);

return 0;
}


未完待续。。。

参考文章:

1:http://blog.csdn.net/bingqingsuimeng/article/details/7920593

2:http://blog.csdn.net/lickylin/article/details/6692691

3:http://soft.chinabyte.com/os/455/12259955.shtml

4:http://blog.csdn.net/rockrockwu/article/details/7460407
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息