PLX 9x5x PCI 驱动程序执行流程详解(Qoder生成)
PLX 9x5x PCI 驱动程序执行流程详解(Qoder生成)
为了些PCI9054驱动,先要阅读官方示例程序,让Qoder先出个流程文件方便后续阅读程序。
大家想要尝试Qoder进行AI编程,可以在官网下载,也可以通过下面链接注册后下载安装:
Qoder下载链接
以下为Qoder自动生成部分:
概述
这是一个基于 Windows WDF(Windows Driver Framework)的 PLX PCI9656RDK-Lite 参考适配器驱动程序。主要功能是通过 PCI 接口进行 Scatter/Gather DMA 操作,支持读写操作和中断处理。
文件结构
| 文件 | 功能 |
|---|---|
| Pci9656.c | 驱动入口、设备初始化、电源管理 |
| Init.c | 设备初始化、硬件资源映射、DMA 配置 |
| IsrDpc.c | 中断服务例程(ISR)和延迟过程调用(DPC) |
| Read.c | 读操作处理和 DMA 编程 |
| Write.c | 写操作处理和 DMA 编程 |
| Control.c | 设备控制(IOCTL)处理 |
| Pci9656.h / Public.h / Private.h | 头文件定义 |
| Reg9656.h | PLX 9656 芯片寄存器定义 |
| trace.h | WPP 跟踪配置 |
初始化流程
1. DriverEntry(驱动程序入口)
文件: Pci9656.c
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
执行流程:
DriverEntry
├─ WPP_INIT_TRACING() // 初始化 WPP 跟踪
├─ WDF_DRIVER_CONFIG_INIT() // 初始化驱动配置
├─ 设置 EvtDeviceAdd 回调 // 设置设备添加事件
├─ 设置 EvtCleanupCallback // 设置驱动清理事件
└─ WdfDriverCreate() // 创建 WDF 驱动对象
关键点:
- 初始化 WPP 跟踪系统用于调试输出
- 注册
PLxEvtDeviceAdd作为设备检测回调 - 注册
PlxEvtDriverContextCleanup作为驱动卸载清理回调 - 返回 STATUS_SUCCESS 表示驱动加载成功
2. PLxEvtDeviceAdd(设备添加事件)
文件: Pci9656.c
NTSTATUS PLxEvtDeviceAdd(
IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit
)
执行流程:
PLxEvtDeviceAdd
├─ WdfDeviceInitSetIoType() // 设置 I/O 类型为直接访问
├─ 初始化 PnP/电源回调
│ ├─ EvtDevicePrepareHardware // 硬件准备
│ ├─ EvtDeviceReleaseHardware // 硬件释放
│ ├─ EvtDeviceD0Entry // 进入 D0 状态
│ └─ EvtDeviceD0Exit // 离开 D0 状态
├─ WdfDeviceCreate() // 创建设备对象
├─ 获取设备上下文 (DeviceExtension)
├─ WdfDeviceCreateDeviceInterface() // 创建设备接口
├─ PLxSetIdleAndWakeSettings() // 设置空闲和唤醒策略
└─ PLxInitializeDeviceExtension() // 初始化设备扩展
关键点:
- 设置 I/O 直接访问模式以提高 DMA 性能
- 创建 WDFDEVICE 对象并获取其上下文(DEVICE_EXTENSION)
- 注册 PnP 和电源管理回调
- 创建设备接口以供应用程序通过 GUID 访问
3. PLxInitializeDeviceExtension(设备扩展初始化)
文件: Init.c
NTSTATUS PLxInitializeDeviceExtension(
IN PDEVICE_EXTENSION DevExt
)
执行流程:
PLxInitializeDeviceExtension
├─ 初始化最大传输长度
│ └─ MaximumTransferLength = min(8KB, SRAM_SIZE)
├─ 计算 DMA_TRANSFER_ELEMENTS (DTE) 数量
├─ 创建顺序分发队列(Sequential Dispatch Queue)
│ ├─ 创建写队列 (WriteQueue)
│ │ └─ 设置 EvtIoWrite 回调
│ ├─ 创建读队列 (ReadQueue)
│ │ └─ 设置 EvtIoRead 回调
│ └─ 创建控制队列 (ControlQueue)
│ └─ 设置 EvtIoDeviceControl 回调
├─ PLxInterruptCreate() // 创建中断对象
└─ PLxInitializeDMA() // 初始化 DMA
数据结构 (DEVICE_EXTENSION):
typedef struct _DEVICE_EXTENSION {
WDFDEVICE Device; // WDF 设备对象
// 硬件资源
PPCI9656_REGS Regs; // 寄存器地址指针
PUCHAR RegsBase; // 寄存器基地址
ULONG RegsLength; // 寄存器长度
PUCHAR SRAMBase; // SRAM 基地址
ULONG SRAMLength; // SRAM 长度
// 中断和 DMA
WDFINTERRUPT Interrupt; // 中断对象
WDFDMAENABLER DmaEnabler; // DMA 启用器
// 读写队列
WDFQUEUE ReadQueue, WriteQueue; // 读写请求队列
WDFQUEUE ControlQueue; // 控制请求队列
// 读写 DMA 事务
WDFDMATRANSACTION ReadDmaTransaction;
WDFDMATRANSACTION WriteDmaTransaction;
// 公共缓冲区(用于 DTE 列表)
WDFCOMMONBUFFER ReadCommonBuffer; // 读 DTE 列表缓冲
WDFCOMMONBUFFER WriteCommonBuffer; // 写 DTE 列表缓冲
PUCHAR ReadCommonBufferBase;
PUCHAR WriteCommonBufferBase;
} DEVICE_EXTENSION;
4. PLxInterruptCreate(中断创建)
文件: IsrDpc.c
NTSTATUS PLxInterruptCreate(
IN PDEVICE_EXTENSION DevExt
)
执行流程:
PLxInterruptCreate
├─ WDF_INTERRUPT_CONFIG_INIT()
│ ├─ 设置 ISR 回调: PLxEvtInterruptIsr
│ ├─ 设置 DPC 回调: PLxEvtInterruptDpc
│ ├─ 设置 Enable 回调: PLxEvtInterruptEnable
│ ├─ 设置 Disable 回调: PLxEvtInterruptDisable
│ └─ AutomaticSerialization = TRUE
└─ WdfInterruptCreate()
关键点:
- ISR 在 DIRQL 级别执行(中断级)
- DPC 用于处理非时间关键的中断处理
- 自动串行化确保 ISR 和 DPC 不会并发执行
5. PLxInitializeDMA(DMA 初始化)
文件: Init.c
NTSTATUS PLxInitializeDMA(
IN PDEVICE_EXTENSION DevExt
)
执行流程:
PLxInitializeDMA
├─ WdfDeviceSetAlignmentRequirement(16字节对齐)
├─ 创建 DMA 启用器
│ ├─ 配置: WdfDmaProfileScatterGather64Duplex
│ │ 支持双工 Scatter/Gather DMA,64位地址
│ ├─ 最大传输长度: 8KB
│ └─ DMA 版本 3(支持单次传输限制)
├─ 为读操作创建公共缓冲区
│ ├─ 大小: sizeof(DMA_TRANSFER_ELEMENT) × ReadTransferElements
│ ├─ 获取虚拟地址: ReadCommonBufferBase
│ └─ 获取逻辑地址: ReadCommonBufferBaseLA
├─ 为写操作创建公共缓冲区
│ └─ 类似读缓冲区
├─ 创建读 DMA 事务对象
│ └─ WdfDmaTransactionCreate()
└─ 创建写 DMA 事务对象
└─ WdfDmaTransactionCreate()
DMA_TRANSFER_ELEMENT 结构 (Reg9656.h):
typedef struct _DMA_TRANSFER_ELEMENT {
unsigned int PciAddressLow; // PCI 地址低32位
unsigned int LocalAddress; // 本地 SRAM 地址
unsigned int TransferSize; // 传输字节数
DESC_PTR DescPtr; // 描述符指针(含控制位)
unsigned int PciAddressHigh; // PCI 地址高32位
unsigned int pad[3]; // 对齐填充
} DMA_TRANSFER_ELEMENT;
6. PLxEvtDevicePrepareHardware(硬件准备)
文件: Pci9656.c
NTSTATUS PLxEvtDevicePrepareHardware(
WDFDEVICE Device,
WDFCMRESLIST Resources,
WDFCMRESLIST ResourcesTranslated
)
执行流程:
PLxEvtDevicePrepareHardware
└─ PLxPrepareHardware()
├─ 遍历资源列表
│ ├─ 查找 BAR0 (寄存器, 0x200 字节)
│ ├─ 查找 BAR2 (SRAM, 128KB)
│ └─ 可选: BAR3 (备用 SRAM)
├─ 映射寄存器内存到系统地址空间
│ └─ LocalMmMapIoSpace() / MmMapIoSpace()
└─ 映射 SRAM 内存到系统地址空间
PCI 资源分配:
| BAR | 类型 | 大小 | 用途 |
|---|---|---|---|
| BAR0 | Memory | 0x200 | PCI9656 寄存器 |
| BAR1 | I/O Port | 0x100+ | I/O 端口(未使用) |
| BAR2 | Memory | 128KB | SRAM(读写缓冲) |
| BAR3 | Memory | 128KB | 备用 SRAM |
7. PLxEvtDeviceD0Entry(进入 D0 电源状态)
文件: Pci9656.c
NTSTATUS PLxEvtDeviceD0Entry(
IN WDFDEVICE Device,
IN WDF_POWER_DEVICE_STATE PreviousState
)
执行流程:
PLxEvtDeviceD0Entry
├─ PLxInitWrite()
│ ├─ 清零 DMA0 DAC 寄存器
│ └─ 清零 Dma0Csr 副本
└─ PLxInitRead()
├─ 清零 DMA1 DAC 寄存器
└─ 清零 Dma1Csr 副本
关键点:
- 在设备进入 D0(工作状态)时调用
- 初始化 DMA 通道 0(写)和通道 1(读)
- 中断尚未启用,将在此函数后由框架启用
读写操作流程
写操作流程
1. PLxEvtIoWrite(写请求处理)
文件: Write.c
VOID PLxEvtIoWrite(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t Length
)
执行流程:
PLxEvtIoWrite
├─ 验证数据长度
│ └─ if (Length > SRAM_SIZE) 返回 STATUS_INVALID_BUFFER_SIZE
├─ 设置单次传输要求
│ └─ WdfDmaTransactionSetSingleTransferRequirement()
├─ 初始化 DMA 事务
│ └─ WdfDmaTransactionInitializeUsingRequest()
│ 或 WdfDmaTransactionInitialize()(如果使用 MDL)
├─ 执行 DMA 事务
│ └─ WdfDmaTransactionExecute(WriteDmaTransaction)
│ // 触发 PLxEvtProgramWriteDma 调用
└─ 错误处理
├─ WdfDmaTransactionRelease()
└─ WdfRequestComplete()
关键点:
- 在顺序队列中执行,一次处理一个请求
- DMA 事务的初始化可绑定到 WDF 请求
- 执行后立即返回,完成由 DPC 处理
2. PLxEvtProgramWriteDma(写 DMA 编程)
文件: Write.c
BOOLEAN PLxEvtProgramWriteDma(
IN WDFDMATRANSACTION Transaction,
IN WDFDEVICE Device,
IN PVOID Context,
IN WDF_DMA_DIRECTION Direction,
IN PSCATTER_GATHER_LIST SgList
)
执行流程:
PLxEvtProgramWriteDma
├─ 获取字节偏移量
│ └─ offset = WdfDmaTransactionGetBytesTransferred()
├─ 设置 DTE 指针
│ ├─ dteVA: 虚拟地址
│ └─ dteLA: 逻辑地址
├─ 遍历 Scatter/Gather 列表
│ └─ for (i=0; i < SgList->NumberOfElements; i++)
│ ├─ dteVA->PciAddressLow = SgList[i].Address.LowPart
│ ├─ dteVA->PciAddressHigh = SgList[i].Address.HighPart
│ ├─ dteVA->TransferSize = SgList[i].Length
│ ├─ dteVA->LocalAddress = offset // SRAM 偏移
│ ├─ dteVA->DescPtr.DirOfTransfer = TO_DEVICE
│ └─ 设置 LastElement 标志(最后一个元素)
├─ 锁定中断自旋锁
│ └─ WdfInterruptAcquireLock()
├─ 配置硬件寄存器
│ ├─ DMA0_Mode: 启用 S/G、中断、路由到 PCI
│ ├─ Int_Csr: 启用 PCI 中断和 DMA0 通道中断
│ ├─ DMA0_Desc_Ptr: 设置 DTE 列表地址
│ └─ DMA0_Csr: 启动 DMA (Enable + Start)
├─ 释放中断自旋锁
│ └─ WdfInterruptReleaseLock()
└─ 返回 TRUE(成功)
硬件寄存器配置:
// DMA0_Mode (0x080)
dmaMode.bits.SgModeEnable = TRUE; // 启用 Scatter/Gather
dmaMode.bits.DoneIntEnable = TRUE; // 传输完成时中断
dmaMode.bits.IntToPci = TRUE; // 中断路由到 PCI
// Int_Csr (0x068)
intCSR.bits.PciIntEnable = TRUE; // 启用 PCI 中断
intCSR.bits.DmaChan0IntEnable = TRUE; // 启用 DMA0 中断
// DMA0_Desc_Ptr (0x090)
ptr.bits.DescLocation = PCI; // DTE 在 PCI 内存中
ptr.bits.TermCountInt = TRUE; // 终端计数中断
ptr.bits.Address = DTE_BASE_ADDRESS; // DTE 列表基地址
// DMA0_Csr (0x0A8)
dmaCSR.bits.Enable = TRUE; // 启用 DMA 通道
dmaCSR.bits.Start = TRUE; // 启动 DMA 操作
关键点:
- 构建 Scatter/Gather DMA 传输元素列表
- 在临界区内(中断锁定下)配置硬件
- 保持 DTE 列表 16 字节对齐
- 最后一个 DTE 需设置 LastElement 标志
3. PLxWriteRequestComplete(写请求完成)
文件: Write.c
VOID PLxWriteRequestComplete(
IN WDFDMATRANSACTION DmaTransaction,
IN NTSTATUS Status
)
执行流程:
PLxWriteRequestComplete
├─ 获取关联的 WDF 请求
│ └─ request = WdfDmaTransactionGetRequest()
├─ 获取已传输字节数
│ └─ bytesTransferred = WdfDmaTransactionGetBytesTransferred()
├─ 释放 DMA 事务
│ └─ WdfDmaTransactionRelease()
└─ 完成请求
└─ WdfRequestCompleteWithInformation(request, Status, bytesTransferred)
读操作流程
1. PLxEvtIoRead(读请求处理)
文件: Read.c
VOID PLxEvtIoRead(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t Length
)
执行流程 (类似写操作):
PLxEvtIoRead
├─ 验证数据长度
├─ 设置单次传输要求
├─ 初始化 DMA 事务(ReadFromDevice 方向)
├─ 执行 DMA 事务
│ └─ 触发 PLxEvtProgramReadDma
└─ 错误处理
2. PLxEvtProgramReadDma(读 DMA 编程)
文件: Read.c
BOOLEAN PLxEvtProgramReadDma(
IN WDFDMATRANSACTION Transaction,
IN WDFDEVICE Device,
IN WDFCONTEXT Context,
IN WDF_DMA_DIRECTION Direction,
IN PSCATTER_GATHER_LIST SgList
)
主要区别:
// 写操作使用 DMA 通道 0,读操作使用 DMA 通道 1
// 读方向(从设备读取)
dteVA->DescPtr.DirOfTransfer = FROM_DEVICE;
// 配置的寄存器
// DMA1_Mode (0x094)
// Int_Csr: DmaChan1IntEnable
// DMA1_Desc_Ptr (0x0A4)
// DMA1_Csr (0x0A9)
// 清空计数模式(读操作特有)
dmaMode.bits.ClearCountMode = TRUE;
中断处理流程
1. PLxEvtInterruptIsr(中断服务例程)
文件: IsrDpc.c
BOOLEAN PLxEvtInterruptIsr(
IN WDFINTERRUPT Interrupt,
IN ULONG MessageID
)
执行流程:
PLxEvtInterruptIsr (在 DIRQL 执行)
├─ 读取中断 CSR 寄存器
│ └─ intCsr.ulong = READ_REGISTER_ULONG(&Regs->Int_Csr)
├─ 检查 DMA0 中断(写完成)
│ ├─ if (intCsr.bits.DmaChan0IntActive)
│ ├─ 标记: devExt->IntCsr.bits.DmaChan0IntActive = TRUE
│ ├─ 读取并清除 DMA0_Csr
│ │ └─ dmaCSR.bits.Clear = TRUE
│ └─ isRecognized = TRUE
├─ 检查 DMA1 中断(读完成)
│ ├─ if (intCsr.bits.DmaChan1IntActive)
│ ├─ 标记: devExt->IntCsr.bits.DmaChan1IntActive = TRUE
│ ├─ 读取并清除 DMA1_Csr
│ └─ isRecognized = TRUE
├─ 如果有中断且 DMA 完成
│ └─ if (isRecognized && (Dma0Done || Dma1Done))
│ └─ WdfInterruptQueueDpcForIsr() // 队列 DPC
└─ 返回 isRecognized
关键点:
- 快速确定中断来源,避免处理不相关中断
- 清除硬件中断标志防止重复
- 如果有数据完成,队列 DPC 进行后续处理
- 应尽快返回以提高系统响应性
2. PLxEvtInterruptDpc(延迟过程调用)
文件: IsrDpc.c
VOID PLxEvtInterruptDpc(
WDFINTERRUPT Interrupt,
WDFOBJECT Device
)
执行流程:
PLxEvtInterruptDpc (在较低 IRQL 执行,可分页)
├─ 锁定中断自旋锁
│ └─ WdfInterruptAcquireLock()
├─ 检查写中断(DMA0)
│ ├─ if (DmaChan0IntActive && Dma0Done)
│ ├─ 清除标志
│ └─ writeInterrupt = TRUE
├─ 检查读中断(DMA1)
│ ├─ if (DmaChan1IntActive && Dma1Done)
│ ├─ 清除标志
│ └─ readInterrupt = TRUE
├─ 释放中断自旋锁
│ └─ WdfInterruptReleaseLock()
├─ 处理写中断
│ ├─ if (writeInterrupt)
│ ├─ dmaTransaction = WriteDmaTransaction
│ ├─ transactionComplete = WdfDmaTransactionDmaCompleted()
│ │ // 检查是否有更多数据需传输
│ └─ if (transactionComplete)
│ └─ PLxWriteRequestComplete() // 完成请求
├─ 处理读中断
│ ├─ if (readInterrupt)
│ ├─ 计算传输的实际字节数
│ │ └─ 遍历 DTE 列表,从 TransferSize 中减去
│ ├─ transactionComplete =
│ │ WdfDmaTransactionDmaCompletedWithLength()
│ └─ if (transactionComplete)
│ └─ PLxReadRequestComplete() // 完成请求
└─ 返回
关键点:
- 读操作需要计算实际传输字节数(因为 ClearCountMode)
- 如果 DMA 事务未完成,框架将自动重新启动 DMA
- DMA 事务完成时,执行完成回调完成用户请求
控制和电源管理
IOCTL 处理
文件: Control.c
VOID PLxEvtIoDeviceControl(
_In_ WDFQUEUE Queue,
_In_ WDFREQUEST Request,
_In_ size_t OutputBufferLength,
_In_ size_t InputBufferLength,
_In_ ULONG IoControlCode
)
支持的 IOCTL:
IOCTL_PLX9X5X_TOGGLE_SINGLE_TRANSFER: 切换单次传输模式
电源状态管理
D0 状态 (工作)
- 设备初始化完成
- 中断已启用
- DMA 可用
D0 -> Dx 转换
PLxEvtDeviceD0Exit被调用- 根据目标状态执行相应操作
D3 状态 (关闭)
PLxShutdown(): 执行硬件复位PLxHardwareReset(): 软件复位流程// 进入复位 EEPROM_Ctrl_Stat.SoftwareReset = TRUE WRITE_REGISTER_ULONG(&Regs->EEPROM_Ctrl_Stat) // 延迟 100 毫秒 KeDelayExecutionThread() // 退出复位 EEPROM_Ctrl_Stat.SoftwareReset = FALSE WRITE_REGISTER_ULONG(&Regs->EEPROM_Ctrl_Stat)
内存管理
公共缓冲区 (Common Buffer)
用于存储 DMA 传输元素列表,必须满足以下条件:
- 物理上连续
- 非缓存(适用于 DMA)
- 16 字节对齐
// 创建公共缓冲区
WdfCommonBufferCreate(
DmaEnabler,
sizeof(DMA_TRANSFER_ELEMENT) * NumElements,
...
)
// 获取虚拟地址(用于 CPU 访问)
PUCHAR virtAddr = WdfCommonBufferGetAlignedVirtualAddress()
// 获取逻辑地址(用于 DMA/硬件)
PHYSICAL_ADDRESS logAddr = WdfCommonBufferGetAlignedLogicalAddress()
Scatter/Gather 列表
由 WDF DMA 框架自动从用户 I/O 请求生成,描述用户缓冲区的物理分段。
驱动清理和卸载
PlxEvtDriverContextCleanup(驱动清理)
文件: Pci9656.c
VOID PlxEvtDriverContextCleanup(
WDFOBJECT Driver
)
执行流程:
PlxEvtDriverContextCleanup
└─ WPP_CLEANUP() // 清理 WPP 跟踪
PLxEvtDeviceReleaseHardware(硬件释放)
文件: Pci9656.c
NTSTATUS PLxEvtDeviceReleaseHardware(
IN WDFDEVICE Device,
IN WDFCMRESLIST ResourcesTranslated
)
执行流程:
PLxEvtDeviceReleaseHardware
├─ 取消映射寄存器内存
│ └─ MmUnmapIoSpace(RegsBase, RegsLength)
└─ 取消映射 SRAM 内存
└─ MmUnmapIoSpace(SRAMBase, SRAMLength)
关键数据结构
INT_CSR (Interrupt Control Status Register) - 0x068
typedef struct _INT_CSR_ {
unsigned int EnableIntSources : 2; // 位 0-1
unsigned int GenPciBusSerrInt : 1; // 位 2
unsigned int DmaChan0IntActive : 1; // 位 21 - DMA 通道 0 中断活跃
unsigned int DmaChan1IntActive : 1; // 位 22 - DMA 通道 1 中断活跃
unsigned int DmaChan0IntEnable : 1; // 位 18 - 启用 DMA0 中断
unsigned int DmaChan1IntEnable : 1; // 位 19 - 启用 DMA1 中断
unsigned int PciIntEnable : 1; // 位 8 - PCI 中断启用
// ... 其他字段
} INT_CSR;
DMA_CSR (DMA Control Status Register) - 0x0A8/0x0A9
typedef struct _DMA_CSR_ {
unsigned char Enable : 1; // 位 0 - DMA 启用
unsigned char Start : 1; // 位 1 - DMA 启动
unsigned char Abort : 1; // 位 2 - DMA 中止
unsigned char Clear : 1; // 位 3 - 清除中断
unsigned char Done : 1; // 位 4 - DMA 完成(只读)
} DMA_CSR;
DMA_MODE (DMA Mode Register) - 0x080/0x094
typedef struct _DMA_MODE_ {
unsigned int SgModeEnable : 1; // Scatter/Gather 模式
unsigned int DoneIntEnable : 1; // 完成时中断
unsigned int IntToPci : 1; // 中断路由到 PCI
unsigned int ClearCountMode : 1; // 清空计数模式(读操作)
// ... 其他字段
} DMA_MODE;
执行时序图
写操作完整时序
应用程序
│
├─> WriteFile()
│
用户模式到内核模式转换
│
├─> I/O Manager 队列请求到 WriteQueue
│
框架处理
│
├─> PLxEvtIoWrite()
│ ├─ 初始化 WriteDmaTransaction
│ ├─ WdfDmaTransactionExecute()
│ │ ├─> 框架生成 Scatter/Gather 列表
│ │ └─> 调用 PLxEvtProgramWriteDma()
│ │ ├─ 构建 DTE 列表
│ │ ├─ 配置硬件寄存器
│ │ ├─ 启动 DMA
│ │ └─ 返回
│ └─ 返回(不等待完成)
│
硬件执行
│
├─> PLX 芯片执行 DMA 传输
│ ├─ 读取 PCI 内存
│ ├─ 写入 SRAM
│ └─ 完成时产生中断
│
中断处理
│
├─> PLxEvtInterruptIsr() [DIRQL]
│ ├─ 读取 Int_Csr
│ ├─ 检测 DMA0 中断
│ ├─ 清除中断标志
│ └─ 队列 DPC
│
├─> PLxEvtInterruptDpc() [IRQL < DIRQL]
│ ├─ 标记中断处理完成
│ ├─ PLxWriteRequestComplete()
│ └─ WdfRequestCompleteWithInformation()
│
└─> 应用程序解除阻塞并获取完成状态
关键配置和参数
| 参数 | 值 | 说明 |
|---|---|---|
| 最大传输长度 | 8 KB | 可根据需求调整 |
| SRAM 大小 | 128 KB | PLX 芯片配置 |
| DTE 对齐 | 16 字节 | PLX 硬件要求 |
| DMA 通道 | 2 | 通道 0(写),通道 1(读) |
| 传输方向 | 双工 | 支持并发读写 |
| 地址宽度 | 64 位 | 支持高地址 |
故障排查
常见问题
-
写入失败 (STATUS_INVALID_BUFFER_SIZE)
- 原因: 请求大小超过 SRAM 大小
- 解决: 分割大请求
-
中断未触发
- 原因: 中断未启用或硬件故障
- 检查:
Int_Csr.PciIntEnableInt_Csr.DmaChanXIntEnable
-
DMA 超时
- 原因: DTE 配置错误或硬件故障
- 检查:
- DTE 地址对齐
- 传输大小有效性
- 硬件寄存器状态
总结
PLX 9x5x 驱动程序的核心机制:
- 初始化阶段: 映射硬件资源、创建 WDF 对象、配置中断和 DMA
- 读写操作: 构建 Scatter/Gather DTE 列表,配置硬件寄存器启动 DMA
- 中断处理: ISR 快速识别中断并队列 DPC,DPC 处理完成事务并完成请求
- 电源管理: 支持 D0/Dx 状态转换及硬件复位
此驱动展示了现代 Windows 驱动开发的最佳实践,包括 WDF 框架使用、DMA 操作、中断处理和设备管理。
浙公网安备 33010602011771号