浅析Linux下PCI设备驱动的访问

浅析Linux下PCI设备驱动的访问

本文主要是基于笔者最近在实现Linux系统中PCI设备驱动过程中的一些学习总结,总共分成三部分,下面依次对这三部分进行介绍。

一、PCI总线

众所周知,PCI总线体系结构是一种层次式的体系结构,而在这种结构中,PCI桥设备则占据着重要的位置,它将父总线与子总线连接在一起,从而使整个系统看起来像一颗倒置的树形结构。树的顶端是系统的CPU,它通过一个较为特殊的PCI桥设备—Host/PCI桥设备与根PCI总线连接起来,如下图1所示。可以看出CPU通过Host/PCI桥与一条PCI总线相连,处在这种位置上的PCI总线为根总线。PC机中通常只有一个Host/PCI桥,在一条PCI总线的基础上,可以再通过PCI桥连接到其他次一层的总线。

浅析Linux下PCI设备驱动的访问

 

1   PCI总线结构图

 Linux系统中,当前存在的所有根总线都通过pci_bus结构体中的node成员链接成一条全局的根总线链表,pci_bus结构体如图2所示,其在linux\include\pci.h下定义。node表头由list类型的全局变量pci_root_buses来描述。而根总线下面的所有下级总线则都通过pci_bus结构体中的node成员链接到其父总线的children链表中,如图3所示。

浅析Linux下PCI设备驱动的访问

  内核pci_bus结构体的部分成员

     浅析Linux下PCI设备驱动的访问

  PCI总线链表

二、PCI设备

对于所有种类的PCI设备来说,它们都可以用内核中pci_dev结构体来描述,图4给出了结构体中的部分内容,其在linux\include\pci.h下定义。由于一个PCI接口卡上可能包括多个功能模块,每个功能都被当作一个独立的逻辑设备,因此,每一个PCI逻辑设备都唯一地对应一个pci_dev结构体。同时,在pci_dev结构体中的bus_list成员将当前PCI总线上的PCI设备链接成一个链表,表头则有该PCI总线的pci_bus结构体中的devices成员所定义,如图5所示。

浅析Linux下PCI设备驱动的访问

 内核pci_dev结构体的部分成员

      浅析Linux下PCI设备驱动的访问

 PCI设备链表

    需要值得注意的是,在较低版本的内核中pci_dev结构体还保留着global_list这个成员变量,它的作用就是将所有的PCI设备链接成一个链表,事实上,这个已经完全没有必要,后续第四部分将会介绍原因。

三、访问PCI设备驱动

关于访问系统中的任意PCI设备,就笔者目前所掌握的知识来说,大体可分为三种方法。

    利用内核提供的表头为list类型的pci_root_buses全局变量,结合pci_buspci_dev结构体的成员,利用PCI总线和PCI设备在内核中的组织形式,可参照第一、二部分,即可实现对系统中存在的任意PCI设备进行访问。这也是最为简单的一种方法。

    利用PCI驱动中获取到一个PCI桥设备的pci_dev结构体,如可通过pci_driverprobe函数获取等。对于一个通过PCI总线与系统连接的设备的驱动至少应该包括两部分内容,一是PCI设备驱动,另一部分则是设备本身的驱动,关于设备本身的驱动则是对应实现设备文件操作接口函数以及驱动模块的加卸载等,如readwriteioctl等函数。而对应与PCI设备驱动,则是对应于内核中的pci_driver结构体,通常关系较大的主要有id_tableproberemovesuspendresume等成员。

id_table表示驱动模块所针对的硬件设备。probe函数负责硬件的检测工作并保存配置信息。remove表示驱动模块移除时移除具体的设备的操作。suspend表示设备挂起,resume表示唤醒设备。

如何获取到PCI桥设备,一种可通过查询PCI手册了解PCI桥设备的Base Class,如图6是摘自PCI Local Bus Specification Revision 3.0手册。

浅析Linux下PCI设备驱动的访问

 PCI设备的部分Base Class

通过这段描述,结合Class Code的编码规则:bit[7:0]为编程接口,bit[15:8]为子类别代码,bit[23:16]为基类别代码,bit[31:24]无意义。组合得知PCI-PCI桥的Class Code0x00060400。由于PCI-PCI桥是用于PCI主总线与次总线的。结合本文前两部分内容,PCI设备之间是以链表形式链接的,因此通过遍历系统所有PCI桥设备,实现对任意PCI设备的访问。

另一种则是利用内核中的提供PCI桥设备的宏定义,其在linux\include\linux\pci_ids.h中定义,如图7所示,事实上还是和手册相关的,只是内核将其宏常量化,便于程序的理解。

浅析Linux下PCI设备驱动的访问

 PCI桥设备的宏定义

    Linux内核实现了一套关于PCI设备的枚举。它的代码分为两个部份。一个部份是与平台相关的部份,存放在linux\arch\XXX\pci,如在x86则对应为linux\arch\x86\pci\。另一个部份是平台无关的代码,存放在linux\driver\pci\下面。其中提供了诸如pcibios_scan_root()等函数,实现从某一总线开始枚举,如pcibios_scan_root(0)则表示从根总线开始枚举,通过此种方法,亦可实现对PCI设备的访问。不过这种方法最有难度,需要分析内核的源码,这个笔者也还未认真分析。

有了这三点,我们知道在较低版本的内核中pci_dev结构体保留的global_list这个成员变量确实用处不大。当然,由于笔者水平所限,可能并不止这三种方法,望能与各位读者相互交流,共同进步。

至此,关于LinuxPCI设备的访问的内容介绍的差不多了,事实上,关于Linux系统下PCI设备驱动的开发还是有相当一部分内容值得研究,包括内核中实现的关于PCI设备的枚举,PCI设备的中断处理等内容,后续若有时间定要在深入研究。

转载请注明出处:http://blog.sina.com.cn/huangjiadong19880706

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值