资源分配
掌握用于管理资源的数据结构和函数
资源管理
数据结构分析
Linux提供通用框架,用于在内存中构建数据结构。这些结构描述了系统中可用的资源,使得内核代码能够管理和分配资源。其中关键的数据结构resource
源码如下:
-
用于连接
parent
,child
,sibling
成员规则如下:- 每个子节点都只有一个父节点。
- 一个父节点可以有任意数目的子节点。
- 同一个父节点的所有子节点,都会连接到兄弟节点链表上面。
-
在内存中表示数据结构时,我们必须要注意几个问题:
- 尽管每个子节点都有一个指针指向父节点,但是父节点只有一个指针指向第一个子节点。所有其他子节点都通过兄弟节点链表访问。
- 指向父节点的指针同样可以为NULL。
请求和释放资源
为了确保可靠地配置资源(无论何种类型),内核必须提供一种机制来分配和释放资源。一旦资源已经分配,则不能由任何其他驱动程序使用。
- 请求资源:内核提供了
__request_resource
函数,用于请求一个资源区域。
该函数用于分配一个request
实例,在此函数当中也会进行检查(起始地址大于结束地址,请求无法使用),则放弃操作。request_resource
这个函数负责必要的锁操作,主要工作还是由__request_resource
。它接连地扫描现存的资源,将新资源添加到正确的位置,或发现与已经分配区域的冲突。完成所有操作之后,需要遍历兄弟节点的链表。如果所需的资源区是空闲的,则插入新的resource
实例,这样就可以完成资源分析。如果区域不是空闲的,则分配失败。
在扫描特定父节点的子节点时,只会在一个层次上扫描兄弟节点链表。内核不会扫描更底层节点的链表。
- 释放资源:调用
release_resource
函数释放使用中的资源源码如下:
I/O内存
资源管理还有一个很重要的方面是I/O内存的分配方式,因为在所有平台上这都是与外设通信的主要办法(IA-32除外,其中I/O端口更重要)。I/O内存不仅包括与扩展设备通信直接使用的内存区域,还包括系统中可用的物理内存和ROM存储器,以及包含在资源列表中的内存(可以使用proc文件系统中的iomem文件,显示所有的I/O内存)
I/O端口
I/O端口是一种与设备和总线通信的流行方法,特别是在IA-32平台上。类似于I/O内存,按良好范例编写的驱动程序在访问所需的区域之前,相应的区域必须已经注册。糟糕的额是,处理器无法检查注册是否已经完成。kernel/resource.c
中的ioport_resource
充当资源树的根节点。proc
文件系统中的ioports
文件可以显示已经分配的端口地址。
总线系统
内核支持大量总线,可能设计多种硬件平台,也有可能只涉及一种平台。在Linux支持的大多数体系结构上都使用了PCI总线。
驱动程序模型
现代总线系统在布局和结构的细节上可能有所不同,但是也有许多共同之处,内核的数据结构反映了这个事实。结构中的许多成员用于所有的总线(以及相关设备的数据结构中)。在内核版本2.6
开发期间,一个通用驱动程序模型(设备模型,device module)并入内核,以防不必要的复制。所有总线共有的属性封装到特殊的、可以用通用方法处理的数据结构中,再关联到总线相关的成员。
设备表示
驱动程序模型采用一种特殊数据结构来表示几乎所有总线类型通用的设备属性。该结构直接嵌入到特定于总线的数据结构中,而不是通过指针引用。
通用驱动程序模型也为了设备驱动程序单独设计一种数据结构源码如下:
总线的表示
通用驱动程序模型不仅表示了设备,还用另外一个数据结构表示了总线,定义如下:
注册过程
为了说明表示总线、设备和设备驱动程序的各个数据结构之间彼此关联,了解各种类型数据结构的注册过程是很有用处的。
注册总线----->注册设备----->注册设备驱动程序
PCI总线
PCI(Peripheral Component Interconnect),是因特尔公司开发的一种标准总线,它迅速在系统组件和体系结构厂商中确立了自身的地位,成为一种非常流行的总线。其原因不在于市场策略方面的技巧,而是因为其技术水平。
Linux内核提供了几个数据结构来管理系统的PCI结构。这些结构声明在<pci.h>
中,通过一个由指针构成的网络相互连接。
- 设计目标:支持高传输带宽,以适合具有大数据流的多媒体应用;简单且易于自动化配置外设;平台独立性,即不绑定到特定的处理器类型或系统平台。
- PCI系统布局
- 设备标识:系统某个PCI总线上的每个设备,都由一组3个标号标识;
- 总线编号:设备所有总线的编号,编号从0开始,PCI规范准许每个系统最多255个总线;
- 插槽编号:总线内核的一个唯一标识编号,一个总线最多能够附接32个设备;
- 功能编号:用于在一个扩展卡上,实现包括多个扩展设备的设备。
- 地址空间
- 有三个地址空间支持与PCI设备的通信;
- IO空间通过32个比特位描述。对用于与设备通信端口地址,提供了最大4GB的空间;
- 取决于处理器类型,数据空间由32或64个比特位描述;
- 配置空间包含各个设备的类型和特征的详细信息;
- 内核提供几个数据结构类型来管理系统的PCI结构。
总线的表示
在内存中,每个PCI总线都通过pci_bus
数据结构的一个实例,该结构体定义如下:
设备管理
struct pci_dev
是一个关键的数据结构,用于表示系统中各个PCI设备。
驱动程序函数
PCI层中最后一个基本的数据结构是pci_driver
。它用于实现PCI驱动程序,表示了通用内核代码和设备的底层硬件驱动程序之间的接口。每个PCI驱动程序都必须将其函数填到该接口中,使得内核能够一致地控制可用的驱动程序。
USB
USB(Universal Serial Bus
,通用串行总线)开发于上个世纪90年代末。他是一种外部总线,用于满足不断发展的PC需求,并用于建立针对新类型计算机的解决方案,如手持设备、PDA等。作为一种通用的外部总线,在用于连接中低数据传输速率的设备时(如鼠标,网络摄像头,键盘),USB很有优势。但是带宽有更高要求的设备如外部硬盘、光驱、CD刻录机也可以通过USB总线运行。USB 1.1
的最大传输速率限于12兆比特/秒,该标准的2.0版本
最高速率提升到480兆比特/秒。
USB四种传输模式
- 控制传输
- 块传输
- 中断传输
- 同步传输
USB子系统的主要任务
- 注册和管理现存的设备驱动程序;
- 为USB设备查找适当的驱动程序,以及初始化和配置;
- 在内核内存中表示设备树;
- 与设备通信(交换数据)
驱动源码
usb_driver
是USB设备驱动程序和内核其余部分(特别是USB层)之间协作的起始点。
设备树的表示
下面的数据结构描述USB设备书以及内核中各种设备特征