ImageVerifierCode 换一换
格式:DOCX , 页数:53 ,大小:53.28KB ,
资源ID:9941412      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-9941412.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Linux I2C驱动分析.docx)为本站会员(b****8)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

Linux I2C驱动分析.docx

1、Linux I2C驱动分析一:前言I2c是philips提出的外设总线.I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL.正因为这样,它方便了工程人员的布线.另外,I2C是一种多主机控制总线.它和USB总线不同,USB是基于master-slave机制,任何设备的通信必须由主机发起才可以.而I2C是基于multi master机制.一同总线上可允许多个master.关于I2C协议的知识,这里不再赘述.可自行下载spec阅读即可. 二:I2C架构概述在linux中,I2C驱动架构如下所示: 如上图所示,每一条I2C对应一个adapter.在kernel中,每一个adapter提供了一

2、个描述的结构(struct i2c_adapter),也定义了adapter支持的操作(struct i2c_adapter).再通过i2c core层将i2c设备与i2c adapter关联起来.这个图只是提供了一个大概的框架.在下面的代码分析中,从下至上的来分析这个框架图.以下的代码分析是基于linux 2.6.26.分析的代码基本位于: linux-2.6.26.3/drivers/i2c/位置. 三:adapter注册在kernel中提供了两个adapter注册接口,分别为i2c_add_adapter()和i2c_add_numbered_adapter().由于在系统中可能存在多个

3、adapter,因为将每一条I2C总线对应一个编号,下文中称为I2C总线号.这个总线号的PCI中的总线号不同.它和硬件无关,只是软件上便于区分而已.对于i2c_add_adapter()而言,它使用的是动态总线号,即由系统给其分析一个总线号,而i2c_add_numbered_adapter()则是自己指定总线号,如果这个总线号非法或者是被占用,就会注册失败.分别来看一下这两个函数的代码:int i2c_add_adapter(struct i2c_adapter *adapter) int id, res = 0; retry: if (idr_pre_get(&i2c_adapter_id

4、r, GFP_KERNEL) = 0) return -ENOMEM; mutex_lock(&core_lock); /* above here means above or equal to, sigh */ res = idr_get_new_above(&i2c_adapter_idr, adapter, _i2c_first_dynamic_bus_num, &id); mutex_unlock(&core_lock); if (res nr = id; return i2c_register_adapter(adapter);在这里涉及到一个idr结构.idr结构本来是为了配合pa

5、ge cache中的radix tree而设计的.在这里我们只需要知道,它是一种高效的搜索树,且这个树预先存放了一些内存.避免在内存不够的时候出现问题.所在,在往idr中插入结构的时候,首先要调用idr_pre_get()为它预留足够的空闲内存,然后再调用idr_get_new_above()将结构插入idr中,该函数以参数的形式返回一个id.以后凭这个id就可以在idr中找到相对应的结构了.对这个数据结构操作不太理解的可以查阅本站中有关radix tree的分析.注意一下idr_get_new_above(&i2c_adapter_idr, adapter,_i2c_first_dynami

6、c_bus_num, &id)的参数的含义,它是将adapter结构插入到i2c_adapter_idr中,存放位置的id必须要大于或者等于_i2c_first_dynamic_bus_num,然后将对应的id号存放在adapter-nr中.调用i2c_register_adapter(adapter)对这个adapter进行进一步注册. 看一下另外一人注册函数: i2c_add_numbered_adapter( ),如下所示:int i2c_add_numbered_adapter(struct i2c_adapter *adap) int id; int status; if (adap

7、-nr & MAX_ID_MASK) return -EINVAL; retry: if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) = 0) return -ENOMEM; mutex_lock(&core_lock); /* above here means above or equal to, sigh; * we need the equal to result to force the result */ status = idr_get_new_above(&i2c_adapter_idr, adap, adap-nr, &id); if

8、(status = 0 & id != adap-nr) status = -EBUSY; idr_remove(&i2c_adapter_idr, id); mutex_unlock(&core_lock); if (status = -EAGAIN) goto retry; if (status = 0) status = i2c_register_adapter(adap); return status;对比一下就知道差别了,在这里它已经指定好了adapter-nr了.如果分配的id不和指定的相等,便返回错误. 过一步跟踪i2c_register_adapter().代码如下:stati

9、c int i2c_register_adapter(struct i2c_adapter *adap) int res = 0, dummy; mutex_init(&adap-bus_lock); mutex_init(&adap-clist_lock); INIT_LIST_HEAD(&adap-clients); mutex_lock(&core_lock); /* Add the adapter to the driver core. * If the parent pointer is not set up, * we add this adapter to the host bu

10、s. */ if (adap-dev.parent = NULL) adap-dev.parent = &platform_bus; pr_debug(I2C adapter driver %s forgot to specify physical devicen, adap-name); sprintf(adap-dev.bus_id, i2c-%d, adap-nr); adap-dev.release = &i2c_adapter_dev_release; adap-dev.class = &i2c_adapter_class; res = device_register(&adap-d

11、ev); if (res) goto out_list; dev_dbg(&adap-dev, adapter %s registeredn, adap-name); /* create pre-declared device nodes for new-style drivers */ if (adap-nr nr); goto out_unlock;首先对adapter和adapter中内嵌的struct device结构进行必须的初始化.之后将adapter内嵌的struct device注册.在这里注意一下adapter-dev的初始化.它的类别为i2c_adapter_class,如

12、果没有父结点,则将其父结点设为platform_bus.adapter-dev的名字为i2c + 总线号.测试一下:ericmochow i2c$ cd /sys/class/i2c-adapter/ericmochow i2c-adapter$ lsi2c-0可以看到,在我的PC上,有一个I2C adapter,看下详细信息:ericmochow i2c-adapter$ tree.- i2c-0 |- device - ./././devices/pci0000:00/0000:00:1f.3/i2c-0 |- name |- subsystem - ./././class/i2c-ada

13、pter - uevent3 directories, 2 files可以看到,该adapter是一个PCI设备.继续往下看:之后,在注释中看到,有两种类型的driver,一种是new-style drivers,另外一种是legacy driversNew-style drivers是在2.6近版的kernel加入的.它们最主要的区别是在adapter和i2c driver的匹配上. 3.1: new-style 形式的adapter注册对于第一种,也就是new-style drivers,将相关代码再次列出如下: if (adap-nr nr 小于_i2c_first_dynamic_bu

14、s_num的话,就会进入到i2c_scan_static_board_info().结合我们之前分析的adapter的两种注册分式: i2c_add_adapter()所分得的总线号肯会不会小于_i2c_first_dynamic_bus_num.只有i2c_add_numbered_adapter()才有可能满足:(adap-nr = _i2c_first_dynamic_bus_num) _i2c_first_dynamic_bus_num = busnum + 1; for (status = 0; len; len-, info+) struct i2c_devinfo *devinf

15、o; devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); if (!devinfo) pr_debug(i2c-core: cant register boardinfo!n); status = -ENOMEM; break; devinfo-busnum = busnum; devinfo-board_info = *info; list_add_tail(&devinfo-list, &_i2c_board_list); mutex_unlock(&_i2c_board_lock); return status;这个函数比较简单, struc

16、t i2c_board_info用来表示I2C设备的一些情况,比如所在的总线.名称,地址,中断号等.最后,这些信息会被存放到_i2c_board_list链表. 跟踪i2c_scan_static_board_info():代码如下:static void i2c_scan_static_board_info(struct i2c_adapter *adapter) struct i2c_devinfo *devinfo; mutex_lock(&_i2c_board_lock); list_for_each_entry(devinfo, &_i2c_board_list, list) if

17、(devinfo-busnum = adapter-nr & !i2c_new_device(adapter, &devinfo-board_info) printk(KERN_ERR i2c-core: cant create i2c%d-%04xn, i2c_adapter_id(adapter), devinfo-board_info.addr); mutex_unlock(&_i2c_board_lock);该函数遍历挂在_i2c_board_list链表上面的i2c设备的信息,也就是我们在启动的时候指出的i2c设备的信息.如果指定设备是位于adapter所在的I2C总线上,那么,就调

18、用i2c_new_device().代码如下:struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) struct i2c_client *client; int status; client = kzalloc(sizeof *client, GFP_KERNEL); if (!client) return NULL; client-adapter = adap; client-dev.platform_data = info-platform_data; d

19、evice_init_wakeup(&client-dev, info-flags & I2C_CLIENT_WAKE); client-flags = info-flags & I2C_CLIENT_WAKE; client-addr = info-addr; client-irq = info-irq; strlcpy(client-name, info-type, sizeof(client-name); /* a new style driver may be bound to this device when we * return from this function, or an

20、y later moment (e.g. maybe * hotplugging will load the driver module). and the device * refcount model is the standard driver model one. */ status = i2c_attach_client(client); if (status adapter指向了它所在的adapter.特别的,clinet-name为info-name.也是指定好了的.一切初始化完成之后,便会调用i2c_attach_client( ).看这个函数的字面意思,是将clinet关联起

21、来.到底怎么样关联呢?继续往下看:int i2c_attach_client(struct i2c_client *client) struct i2c_adapter *adapter = client-adapter; int res = 0; /初始化client内嵌的dev结构 /父结点为所在的adapter,所在bus为i2c_bus_type client-dev.parent = &client-adapter-dev; client-dev.bus = &i2c_bus_type; /如果client已经指定了driver,将driver和内嵌的dev关联起来 if (clie

22、nt-driver) client-dev.driver = &client-driver-driver; /指定了driver, 但不是newstyle的 if (client-driver & !is_newstyle_driver(client-driver) client-dev.release = i2c_client_release; client-dev.uevent_suppress = 1; else client-dev.release = i2c_client_dev_release; /clinet-dev的名称 snprintf(&client-dev.bus_id0

23、, sizeof(client-dev.bus_id), %d-%04x, i2c_adapter_id(adapter), client-addr); /将内嵌的dev注册 res = device_register(&client-dev); if (res) goto out_err; /将clinet链到adapter-clients中 mutex_lock(&adapter-clist_lock); list_add_tail(&client-list, &adapter-clients); mutex_unlock(&adapter-clist_lock); dev_dbg(&ad

24、apter-dev, client %s registered with bus id %sn, client-name, client-dev.bus_id); /如果adapter-cleinet_reqister存在,就调用它 if (adapter-client_register) if (adapter-client_register(client) dev_dbg(&adapter-dev, client_register failed for client %s at 0x%02xn, client-name, client-addr); return 0; out_err: d

25、ev_err(&adapter-dev, Failed to attach i2c client %s at 0x%02x (%d)n, client-name, client-addr, res); return res; 参考上面添加的注释,应该很容易理解这段代码了,就不加详细分析了.这个函数的名字不是i2c_attach_client()么?怎么没看到它的关系过程呢?这是因为:在代码中设置了client-dev所在的bus为i2c_bus_type .以为只需要有bus为i2c_bus_type的driver注册,就会产生probe了.这个过程呆后面分析i2c driver的时候再来详细

26、分析.3.2: legacy形式的adapter注册Legacy形式的adapter注册代码片段如下: dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_add_adapter); 这段代码遍历挂在i2c_bus_type上的驱动,然后对每一个驱动和adapter调用i2c_do_add_adapter().代码如下:static int i2c_do_add_adapter(struct device_driver *d, void *data) struct i2c_driver *driver = to_i2c_driver(d); struct i2c_adapter *adap = data; if (driver-attach_adapter) /* We ignore the return code; if it fails, too bad */ driver-attach_adapter(adap); return 0; 该函数很简单,就是调用driver的attach_adapter(

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2