第二十七篇:Windows驱动中的PCI, DMA, ISR, DPC, ScatterGater, MapRegsiter, CommonBuffer, ConfigSpace

来源:互联网 发布:linux mac地址 编辑:程序博客网 时间:2024/06/04 19:13

最近有些人问我PCI设备驱动的问题, 和他们交流过后, 我建议他们先看一看<<The Windows NT Device Driver Book>>这本书, 个人感觉, 这本书写得非常连贯流畅.


PCI设备驱动基本包括了PCI的资源获取, 配置空间的读写, 中断的处理, 中断后半部在DPC中的处理.

同时, 也必须了解DMA, ScatterGater, MapRegister, Common Buffer等基础.


1.1 PCI设备资源获取

PCI设备的资源是系统根据设备的属性(配置空间中寄存器的值)来动态分配的.

驱动中只需在PNP START中获取这些系统分配的资源:

例如: 笔者开发的PCI电视卡驱动中, 就使用到了其中了两类资源, CmResourceTypePort与CmResourceTypeInterrupt.

Port地址作为设备寄存器首地址, 之后, 可以使用WRITE_PORT_ULONG与READ_PORT_ULONG加上相应的OFFSET来对设备寄存器进行访问.

Interrupt资源中解释出来的内容, 则主要作为IoConnectInterrupt系统函数的参数, 将设备的硬件中断与ISR相关联, KINTERRUPT的实例则是设备中断的软件形式的载体.


1.2 DMA

DMA设备, 在系统中分为MASTER与SLAVE, 另外一个很重要的能力就是是否支持Scatter/Gather.

这些能力最终表现在DEVICE_DESCRIPTION所定义的数据结构的成员中, 例如:DmaWidth, ScatterGather, Master, Dma32BitAddresses, Dma64BitAddresses.

系统最终将各种不同类型的设备DMA抽象为DMA_ADAPTER的实例, 它是设备DMA软件形式的载体.

驱动代码通过IoGetDmaAdapter系统调用, 将物理设备对象PDO与DMA描述结构作为参数, 最终得到这个DMA_ADAPTER对象, 作为后续一系列DMA相关操作的实体对象.


1.3 Map Register

用户空间, 内核空间的虚拟内存与物理内存的关联是通过页表来映射的, 驱动程序员常常会使用MDL, 它也是某一特定区域虚拟内存与物理内存的映射关系.

而DMA设备则需要从总线地址(MSDN中又叫逻辑地址)与内存物理的映射关系角度去看待系统内存.

这个映射的关系就是由Map Register承担的.

不过, 这批Map Register则根据系统而定, 有些是硬件实现, 有些是软件中划分出来的特定的一块内存.

IoGetDmaAdapter的调用, 也是向系统申请Map Register的过程.


1.4 Common Buffer

这也是大家问得最多的问题

简单地讲, Common buffer是以DMA_ADAPTER为代表所申请的, 申请成功后, 既能通过虚拟地址访问, 也可以通过DMA控制器所属逻辑地址空间的地址来访问的连续物理内存.

它的好处就是物理上连续, 存在的问题是系统中连续物理内存是随着系统的运行时间的流逝, 越来越稀缺.

AllocateCommonBuffer系统调用是作为DMA_ADAPTER的DmaOperations形式存在的, 所以, 具体的一块Common Buffer可以说, 是与具体的一个DMA控制器所关联的.

AllocateCommonBuffer成功调用后, 会返回虚拟地址与DMA控制器所属逻辑空间的逻辑地址.

笔者开发的PCI电视卡, 就是通过AllocateCommonBuffer分配一块较小的连续物理内存, 用来存放Scatter/Gather列表 (某块内存的逻辑地址SCATTER_GATHER_LIST.Elements[i].Address.LowPart 与该内存的长度SCATTER_GATHER_LIST.Elements[i].Length, 相应操作通过common buffer的虚拟地址 ).

这个Scatter/Gather List列表最终由具有S/G能力的DMA控制器来读取(相应操作通过common buffer的逻辑地址), 根据其中的表项, 进行DMA读/写操作.


1.5 S/G

S/G的能力是DMA控制器的特性, 如果具有S/G的能力, 则可以批量地DMA操作, 否则, 必须一次一次地使用MapTransfer来完成DMA操作.

系统空间的中虚拟内存与物理内存之间的联系通过IoAllocateMdl与MmBuildMdlForNonPagedPool建立特定的MDL来表示.

其后,通过DMA_ADAPTER的DmaOperations中的GetScatterGatherList获取MDL所描述的虚拟地址内存的S/G列表, 最后, 在GetScatterGatherList的

ExecutionRoutine 函数中, 将该列表填入Common buffer的TABLE(起始逻辑地址 与 长度)中, 以供DMA Controller所用.


1.6 ISR与DPC
刚才已经提到, ISR是通过IoConnectInterrupt注册的.
ISR在设备中断到来时实调用, 但具体的事项则交由(KeInsertQueueDpc)DPC来处理.
而DPC则是通过KeInitializeDpc系统调用, 将DPC对象KDPC与具体的KDEFERRED_ROUTINE DPC处理函数相关联的.

1.7 PCI设备配置空间的访问

事实上, 一般情况下, Windows PCI设备并不需要访问PCI设备配置空间.
但作为一个完整的PCI设备驱动, 这里提及一下.

由于PCI设备的配置空间与IO/MEM空间是分开的, 前面已经提及IO/MEM的访问方式, 配置空间的访问如下:
定义变量:BUS_INTERFACE_STANDARD m_BusInterfaceStandard;
建立: IRP, 主与次分别为IRP_MJ_PNP, IRP_MN_QUERY_INTERFACE, 得到BUS_INTERFACE_STANDARD数据结构.
之后, 通过BUS_INTERFACE_STANDARD中的SetBusData与GetBusData来进行PCI配置空间的寄存器读写.

 

PCI设备驱动完全可以用在PCIe设备上, 毕竟上层来讲, 他们没有太多的区别.

与USB驱动不同, PCI设备需要考虑驱动设计中的方方面面, 希望这篇文章对大家有所借鉴作用.







0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 平板摔了花屏怎么办 新手机开不了机怎么办 三星a9屏幕漏液怎么办 小米note后面玻璃碎了怎么办 换手机微信钱包怎么办 内外屏一体手机屏幕碎了怎么办 苹果手机显示屏坏了怎么办 华为手机屏裂了怎么办 乐视手机屏坏了怎么办 红米手机触屏失灵怎么办 小米4排线断了怎么办 红米3x屏幕难点怎么办 华为p7屏幕不亮怎么办 红米5外屏碎了怎么办 小米电视碎屏了怎么办 oppo手机第二屏幕打不开怎么办 红米note3屏幕裂了怎么办 小米3屏幕烂了怎么办 苹果x屏幕触屏不灵怎么办 票买好了身份证丢了怎么办 广发信用卡身份证到期了怎么办 人在外地身份证丢了怎么办 人在国外身份证丢了怎么办 身份证丢了户口本不在怎么办 在北京身份证过期了怎么办 没社保卡怎么办厦门健康卡 扬州市民卡丢了怎么办 扬州市民卡坏了怎么办 重庆社保卡坏了怎么办 社保卡丢了看病怎么办 社保卡丢了买药怎么办 常州社保卡丢了怎么办 深圳社保卡掉了怎么办 上海医保卡丢了怎么办 户口转到西安后医保怎么办 上海医保卡掉了怎么办 上海医保本丢了怎么办? 新版医保卡丢了怎么办 武汉社保卡掉了怎么办 职工社保卡丢了怎么办 杭州社保卡丢了怎么办