WDF-SDHC存储驱动框架设计:初始化、I/O流水与电源管理
概述
本文从 WDF SD Host Controller 驱动的三条核心主线出发,梳理驱动与硬件 SD Host 资源及 OS 上下游的完整调用流水:
- 初始化路径:从 PnP 枚举到 SD 卡就绪
- I/O 数据路径:从用户读写请求到 SDHCI 寄存器操作
- 电源状态管理:D-state 转换与硬件上下文保存/恢复
1. 驱动分层架构总览
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| ┌─────────────────────────────────────────────────────────────────────────┐ │ WDF-sdhcstor 完整驱动栈 │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ OS 上游: File System (NTFS/exFAT) → Disk.sys → PartMgr.sys │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ IRP_MJ_SCSI (SRB: READ/WRITE/INQUIRY/READ_CAPACITY) │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ sdhcstor/ (自建 WDM Port Driver) │ │ │ │ SCSI 命令解析 → 转换为扇区地址 + 块数 │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ Read/Write Request (sector_addr, sector_cnt, direction) │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ o2sdhc/ (KMDF Storage Driver) │ │ │ │ ┌─────────────┐ ┌──────────────┐ ┌────────────────────┐ │ │ │ │ │ sdhc_queue.c│ │ sdhc_isr.c │ │ sdhc_init.c │ │ │ │ │ │ I/O Queue │ │ ISR + DPC │ │ DMA + Queue Init │ │ │ │ │ └─────────────┘ └──────────────┘ └────────────────────┘ │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ SD 命令 + DMA 描述符 │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ sdstor_legacy/ (SD 协议栈复用层) │ │ │ │ ┌──────────┐ ┌──────────────┐ ┌──────────────────────┐ │ │ │ │ │ host.c │ │ cmdhandler.c │ │ transhandler.c │ │ │ │ │ │ 寄存器IO │ │ SD命令生成 │ │ ADMA2描述符构建 │ │ │ │ │ └──────────┘ └──────────────┘ └──────────────────────┘ │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ MMIO: READ_REGISTER / WRITE_REGISTER │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ Hardware: PCIe SD Host Controller (Bayhub GG8) │ │ │ │ BAR0: SDHCI 标准寄存器 (0x00-0x7F) │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘
|
2. 初始化路径:从 PnP 枚举到 SD 卡就绪
2.1 完整初始化时序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| PnP Manager WDF Framework o2sdhc Driver │ │ │ │ IRP_MN_START_DEVICE │ │ ├─────────────────────────────►│ │ │ │ EvtDevicePrepareHardware │ │ ├─────────────────────────────►│ │ │ │ ① 映射BAR0寄存器 │ │ │ ② 初始化Host能力 │ │ │ ③ 初始化Card结构 │ │ │ ④ 配置Host寄存器 │ │◄─────────────────────────────┤ │ │ │ │ │ (框架连接中断) │ │ │ │ │ │ EvtDeviceD0Entry │ │ ├─────────────────────────────►│ │ │ │ ⑤ 设备进入D0 │ │◄─────────────────────────────┤ │ │ │ │ │ (框架使能中断) │ │ │ │ │ │ EvtDeviceSelfManagedIoInit │ │ ├─────────────────────────────►│ │ │ │ ⑥ 检测卡是否在位 │ │ │ ⑦ card_init (SD协议) │ │ │ ⑧ MediaReadCapacity │ │ │ ⑨ 创建Child PDO │ │◄─────────────────────────────┤ │ │ │ │ PnP枚举子设备 │ │ │◄─────────────────────────────┤ │ │ │ │
|
2.2 各阶段详解
① EvtDevicePrepareHardware — 硬件资源映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| for (Index = 0; Index < ResourceCount; Index++) { Descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, Index); if (Descriptor->Type == CmResourceTypeMemory) { devExt->pdx.host.pci_dev.membase = LocalMmMapIoSpace( Descriptor->u.Memory.Start, Descriptor->u.Memory.Length); devExt->RegsBase[BAR0] = devExt->pdx.host.pci_dev.membase; } }
host_init_capbility(&devExt->pdx.host);
card_stuct_init(&devExt->pdx);
host_init(&devExt->pdx.host);
|
与硬件的交互:
| 操作 |
SDHCI 寄存器 |
偏移 |
说明 |
| 读取能力 |
CAPABILITIES |
0x40 |
获取 ADMA2/HS/8bit 等支持标志 |
| 软复位 |
SOFTWARE_RESET |
0x2F |
复位 Host 控制器 |
| 时钟配置 |
CLOCK_CONTROL |
0x2C |
设置初始 400KHz 时钟 |
| 电源配置 |
POWER_CONTROL |
0x29 |
设置 3.3V/1.8V 供电 |
| 中断使能 |
INT_ENABLE |
0x34 |
使能卡插入/移除中断 |
| 信号使能 |
SIGNAL_ENABLE |
0x38 |
使能中断信号到 PCIe |
② EvtDeviceSelfManagedIoInit — SD 卡初始化
1 2 3 4 5 6 7 8
| reg32 = SDHCReadRegULong(devExt, BAR0, SDHCI_PRESENT_STATE); if (reg32 & SDHCI_CARD_PRESENT) { card_init(&devExt->pdx.card, 1, 1); MediaReadCapacity(Device); WdfChildListAddOrUpdateChildDescriptionAsPresent(list, &Description.Header, NULL); }
|
card_init 内部 SD 协议流程:
1 2 3 4 5 6 7 8 9 10 11 12
| card_init() │ ├── CMD0 (GO_IDLE_STATE) ← 复位卡到 Idle 状态 ├── CMD8 (SEND_IF_COND) ← 检测 SD 2.0+ 电压兼容 ├── ACMD41 (SD_SEND_OP_COND) ← 获取 OCR,等待卡上电完成 ├── CMD2 (ALL_SEND_CID) ← 获取卡唯一标识 ├── CMD3 (SEND_RELATIVE_ADDR) ← 获取 RCA 地址 ├── CMD9 (SEND_CSD) ← 获取卡参数(容量、速度等级) ├── CMD7 (SELECT_CARD) ← 选中卡,进入 Transfer 状态 ├── ACMD6 (SET_BUS_WIDTH) ← 切换 4-bit 总线宽度 └── CMD6 (SWITCH_FUNC) ← 协商速度模式 (HS/SDR50/SDR104) └── Tuning (CMD19) ← SDR50/SDR104 需要执行调谐
|
3. I/O 数据路径:从用户请求到硬件传输
3.1 完整 I/O 流水线
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| ┌─────────────────────────────────────────────────────────────────────────┐ │ I/O 请求完整流水线 │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ 用户进程 ReadFile/WriteFile │ │ │ │ │ ▼ │ │ NTFS → Disk.sys → sdhcstor (SCSI→扇区转换) │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ SequentialQueueEvtIoReadWrite (sdhc_queue.c:185) │ │ │ │ • 提取 DeviceOffset → sec_addr │ │ │ │ • 提取 Length → sec_cnt │ │ │ │ • 判断方向: Read=1, Write=2 │ │ │ └──────────────────────────────┬──────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ WdfDmaTransactionInitializeUsingRequest │ │ │ │ → WdfDmaTransactionExecute │ │ │ │ → 框架构建 Scatter-Gather List │ │ │ └──────────────────────────────┬──────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ SDEvtProgramDmaFunction (sdhc_queue.c:117) │ │ │ │ • 接收 SCATTER_GATHER_LIST │ │ │ │ • 调用 card_adma2_rw_data (复用层) │ │ │ │ └── build_adma2_desc: 构建 ADMA2 描述符表 │ │ │ │ └── cmd_generate_reg: 生成 SDHCI 命令寄存器值 │ │ │ │ └── cmd_execute_sync: 写入寄存器,等待完成 │ │ │ └──────────────────────────────┬──────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ SDHCI 寄存器写入序列 (硬件操作) │ │ │ │ 1. SDHCI_DMA_ADDRESS (0x00) ← ADMA2 描述符表物理地址 │ │ │ │ 2. SDHCI_BLOCK_SIZE (0x04) ← 512 bytes │ │ │ │ 3. SDHCI_BLOCK_COUNT (0x06) ← sec_cnt │ │ │ │ 4. SDHCI_ARGUMENT (0x08) ← sec_addr │ │ │ │ 5. SDHCI_TRANSFER_MODE(0x0C) ← DMA_EN|BLK_CNT_EN|DIR|MULTI │ │ │ │ 6. SDHCI_COMMAND (0x0E) ← CMD18/CMD25 + 响应类型 │ │ │ └──────────────────────────────┬──────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ 硬件执行 DMA 传输 │ │ │ │ SD Host Controller 按 ADMA2 描述符自动搬运数据 │ │ │ │ 完成后产生 Transfer Complete 中断 │ │ │ └──────────────────────────────┬──────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ SDHCEvtInterruptIsr (sdhc_isr.c:93) │ │ │ │ • 读 SDHCI_INT_STATUS (0x30) │ │ │ │ • 写回清除中断位 │ │ │ │ • WdfInterruptQueueDpcForIsr → 调度 DPC │ │ │ └──────────────────────────────┬──────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ SDHCEvtInterruptDpc (sdhc_isr.c:168) │ │ │ │ • WdfDmaTransactionDmaCompletedFinal │ │ │ │ • RequestCompletion(request, STATUS_SUCCESS, Length) │ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────┘
|
3.2 ADMA2 描述符格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ADMA2 描述符表 (每项 8 字节): ┌───────────────────────────────────────────────────────────────┐ │ Word 0 (Low 32-bit): │ │ [31:16] Transfer Length (0 = 65536 bytes) │ │ [15:6] Reserved │ │ [5:4] Act: 00=Nop, 01=Reserved, 10=Tran, 11=Link │ │ [3] Int (中断使能) │ │ [2] End (最后一项) │ │ [1] Valid │ │ [0] Reserved │ ├───────────────────────────────────────────────────────────────┤ │ Word 1 (High 32-bit): │ │ [31:0] Physical Address (数据缓冲区物理地址) │ └───────────────────────────────────────────────────────────────┘
示例: 读取 4 个扇区 (2048 bytes) 的描述符: ┌──────────────────────────────────────┐ │ Entry 0: Len=2048, Act=Tran, End=1 │ │ Addr=0x12345000 │ └──────────────────────────────────────┘
|
3.3 ADMA2 描述符中的两块内存:描述符表 vs 数据缓冲区
ADMA2 传输涉及两块独立的物理内存,容易混淆:
| 内存 |
分配时机 |
分配者 |
物理地址写到哪 |
用途 |
| 描述符表 (4KB) |
驱动初始化时 |
WdfCommonBufferCreate |
SDHCI_DMA_ADDRESS (0x00) |
存放 ADMA2 描述符条目 |
| 数据缓冲区 |
每次 I/O 请求时 |
用户进程 (ReadFile 的 buffer) |
ADMA2 描述符的 Address 字段 |
SD 卡数据的实际搬运目标/来源 |
描述符表在初始化时一次性分配:
1 2 3 4
| WdfCommonBufferCreate(DevExt->DmaEnabler, 4096, ..., &DevExt->dmadescbuf); pdev_ext->dma_buff.va = WdfCommonBufferGetAlignedVirtualAddress(...); pdev_ext->dma_buff.pa = WdfCommonBufferGetAlignedLogicalAddress(...);
|
数据缓冲区的物理地址则是每次 I/O 请求时动态获取的,来源是用户进程的 buffer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| 用户进程: ReadFile(hFile, userBuffer, 4096, ...) │ │ userBuffer 是用户态虚拟地址 (如 0x7FF6`12340000) ▼ ┌─────────────────────────────────────────────────────────────────┐ │ NT I/O Manager │ │ │ │ 因为 o2sdhc 设置了 Direct I/O (O2SDHC.C:435): │ │ ioConfig.ReadWriteIoType = WdfDeviceIoDirect; │ │ │ │ I/O Manager 做两件事: │ │ 1. MmProbeAndLockPages — 把用户虚拟页锁定到物理内存 │ │ 2. 创建 MDL (Memory Descriptor List) — 记录虚拟页→物理页帧映射 │ └──────────────────────────────┬──────────────────────────────────┘ │ IRP + MDL ▼ ┌─────────────────────────────────────────────────────────────────┐ │ WdfDmaTransactionExecute │ │ │ │ WDF 框架调用 HAL DMA Adapter: │ │ - 从 MDL 的物理页帧号 (PFN) 计算物理地址 │ │ - 如果有 IOMMU,做 PA → Bus Address 映射 │ │ - 生成 SCATTER_GATHER_LIST: │ │ Elements[0] = { Address: 0x1A340000, Length: 4096 } │ │ Elements[1] = { Address: 0x2B780000, Length: 4096 } │ │ (用户 buffer 在物理上可能不连续,所以是 scatter-gather) │ └──────────────────────────────┬──────────────────────────────────┘ │ PSCATTER_GATHER_LIST ▼ ┌─────────────────────────────────────────────────────────────────┐ │ SDEvtProgramDmaFunction → card_adma2_rw_data │ │ │ │ // 遍历 SGL,把每个物理地址写入 ADMA2 描述符表 │ │ pTable = pdx->dma_buff.va; // 描述符表的虚拟地址(CPU写入用) │ │ │ │ for (i = 0; i < lbuffer->NumberOfElements; i++) { │ │ itemTotalLen = lbuffer->Elements[i].Length; │ │ itemAddrHdr = lbuffer->Elements[i].Address.LowPart; │ │ ↑ 用户 buffer 对应的物理地址 │ │ │ │ *(pTable++) = gen_adma2_desc_low_32bit(itemTotalLen, TRAN); │ │ *(pTable++) = (u32)itemAddrHdr; // ★ 写入描述符 │ │ } │ │ │ │ // 最后告诉硬件描述符表的物理地址 │ │ sd_data.data_mng.sys_addr = pdx->dma_buff.pa; │ │ // → 写入 SDHCI_DMA_ADDRESS (0x00) 寄存器 │ └─────────────────────────────────────────────────────────────────┘
|
硬件执行时的读取顺序:
1 2 3 4 5 6 7 8
| SD Host Controller: 1. 从 SDHCI_DMA_ADDRESS (0x00) 读到描述符表物理地址 → 0xABC00000 2. 从物理地址 0xABC00000 读取第一个描述符条目: - Length = 4096, Address = 0x1A340000 3. 把 SD 卡数据 DMA 搬运到物理地址 0x1A340000 (这就是用户 ReadFile buffer 的第一个物理页) 4. 读取下一个描述符条目,继续搬运... 5. 遇到 End=1 的描述符,产生 Transfer Complete 中断
|
总结:用户 ReadFile 的 buffer 虚拟地址 → I/O Manager 锁页生成 MDL → WDF/HAL 翻译为物理地址 SGL → 驱动填入 ADMA2 描述符 → 硬件按描述符 DMA 搬运数据到用户 buffer 的物理页。整个过程中数据零拷贝,直接从 SD 卡搬到用户内存。
3.4 PIO 传输模式(备选路径)
当 ADMA2 不可用时,使用 PIO 模式通过 CPU 逐字搬运:
1 2 3 4 5 6 7 8 9
| for (block = 0; block < sec_cnt; block++) { while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_DATA_AVAILABLE)); for (i = 0; i < 512/4; i++) { *buf++ = sdhci_readl(host, SDHCI_BUFFER); } }
|
4. 电源状态管理
4.1 WDF 电源状态机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| ┌─────────────────────────────────────────────────────────────────────────┐ │ WDF 电源状态转换 │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ │ │ ┌─────────│ D0 (Working)│─────────┐ │ │ │ └──────────────┘ │ │ │ │EvtDeviceD0Entry EvtDeviceD0Exit│ │ │ │ │ │ │ │ ┌──────────────┐ │ │ │ └─────────│ Dx (Sleep) │◄────────┘ │ │ └──────────────┘ │ │ │ │ PrepareHardware ──► D0Entry ──► SelfManagedIoInit ──► 正常工作 │ │ │ │ 正常工作 ──► D0Exit ──► Dx (休眠/待机) │ │ │ │ Dx ──► D0Entry ──► 恢复工作 │ │ │ │ SelfManagedIoCleanup ──► ReleaseHardware ──► 设备移除 │ │ │ └─────────────────────────────────────────────────────────────────────────┘
|
4.2 各回调的硬件操作
| 回调 |
方向 |
硬件操作 |
EvtDevicePrepareHardware |
首次启动 |
映射 BAR0,初始化 Host 寄存器,配置时钟/电源 |
EvtDeviceD0Entry |
Dx → D0 |
恢复 Host 寄存器状态,重新使能时钟和中断 |
EvtDeviceSelfManagedIoInit |
首次 D0 后 |
检测卡、执行 card_init、创建 Child PDO |
EvtDeviceD0Exit |
D0 → Dx |
保存寄存器上下文,关闭时钟,禁用中断 |
EvtDeviceReleaseHardware |
设备移除 |
取消映射 BAR0,释放 DMA 资源 |
4.3 框架自动管理的中断生命周期
1 2 3 4 5 6 7
| D0Entry 完成后: → 框架自动调用 EvtInterruptEnable (使能 SDHCI 中断) → 中断已连接,可以响应卡插拔
D0Exit 之前: → 框架自动调用 EvtInterruptDisable (禁用 SDHCI 中断) → 框架自动断开中断连接
|
1 2 3 4 5 6 7 8 9 10
| NTSTATUS SDHCEvtInterruptEnable(WDFINTERRUPT Interrupt, WDFDEVICE Device) { PDEVICE_EXTENSION devExt = GetDeviceContext(Device); SDHCWriteRegULong(devExt, BAR0, SDHCI_INT_ENABLE, SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | SDHCI_INT_CMD_COMP | SDHCI_INT_TRANSFER_COMP); SDHCWriteRegULong(devExt, BAR0, SDHCI_SIGNAL_ENABLE, ...); return STATUS_SUCCESS; }
|
4.4 Power Policy 配置
1 2 3
|
WdfDeviceInitSetPowerPolicyOwnership(DeviceInit, FALSE);
|
在存储驱动栈中,Power Policy Owner 通常是 Port Driver(sdhcstor),它决定何时进入低功耗状态。o2sdhc 作为 Function Driver 响应电源 IRP 但不主动发起。
5. WDF 对象模型与设备上下文
5.1 对象层次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| WDFDRIVER (O2SDHC) │ └── WDFDEVICE (SD Host Controller FDO) │ ├── WDFINTERRUPT ─── ISR + DPC 回调 │ ├── WDFQUEUE (Sequential) ─── EvtIoRead/Write/DeviceControl │ ├── WDFDMAENABLER │ ├── WDFCOMMONBUFFER (4KB, ADMA2 描述符表) │ ├── WDFDMATRANSACTION (Read) │ └── WDFDMATRANSACTION (Write) │ └── WDFCHILDLIST └── Child PDO (SD Card) ─── 触发 sdhcstor 加载
|
5.2 DEVICE_EXTENSION 核心字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| typedef struct _DEVICE_EXTENSION { WDFDEVICE WdfDevice; WDFINTERRUPT WdfInterrupt; WDFQUEUE WdfQueue; WDFDMAENABLER DmaEnabler; WDFDMATRANSACTION ReadDmaTransaction; WDFDMATRANSACTION WriteDmaTransaction;
PUCHAR RegsBase[2]; ULONG RegsLength[2];
bht_dev_ext_t pdx;
u8 dir; u32 sec_addr; u16 sec_cnt;
BOOLEAN CardPresentState; DISK_GEOMETRY DiskGeometry; LARGE_INTEGER PartitionLength; } DEVICE_EXTENSION;
|
6. SDHCI 关键寄存器映射
| 偏移 |
名称 |
宽度 |
初始化使用 |
I/O使用 |
电源使用 |
| 0x00 |
DMA_ADDRESS |
32 |
|
✅ ADMA2表地址 |
|
| 0x04 |
BLOCK_SIZE |
16 |
|
✅ 512 |
|
| 0x06 |
BLOCK_COUNT |
16 |
|
✅ sec_cnt |
|
| 0x08 |
ARGUMENT |
32 |
|
✅ sec_addr |
|
| 0x0C |
TRANSFER_MODE |
16 |
|
✅ DMA/方向/多块 |
|
| 0x0E |
COMMAND |
16 |
|
✅ CMD18/CMD25 |
|
| 0x10 |
RESPONSE |
128 |
✅ CID/CSD |
✅ 命令响应 |
|
| 0x20 |
BUFFER |
32 |
|
✅ PIO数据 |
|
| 0x24 |
PRESENT_STATE |
32 |
✅ 卡检测 |
✅ 忙等待 |
|
| 0x28 |
HOST_CONTROL |
8 |
✅ 总线宽度 |
|
|
| 0x29 |
POWER_CONTROL |
8 |
✅ 电压设置 |
|
✅ 开/关电源 |
| 0x2C |
CLOCK_CONTROL |
16 |
✅ 时钟频率 |
|
✅ 开/关时钟 |
| 0x2F |
SOFTWARE_RESET |
8 |
✅ 复位 |
|
|
| 0x30 |
INT_STATUS |
32 |
|
✅ ISR读取 |
|
| 0x34 |
INT_ENABLE |
32 |
✅ 使能中断 |
|
✅ 禁用中断 |
| 0x38 |
SIGNAL_ENABLE |
32 |
✅ 使能信号 |
|
✅ 禁用信号 |
| 0x3E |
HOST_CONTROL2 |
16 |
✅ UHS模式 |
|
|
| 0x40 |
CAPABILITIES |
64 |
✅ 读取能力 |
|
|
7. 总结
WDF SD Host Controller 驱动的核心职责可归纳为三条主线:
| 主线 |
触发条件 |
核心操作 |
涉及硬件 |
| 初始化 |
PnP 枚举 |
BAR映射 → Host配置 → Card识别 → PDO创建 |
CAPABILITIES, CLOCK, POWER, CMD寄存器 |
| I/O 传输 |
用户读写 |
Queue接收 → DMA事务 → ADMA2描述符 → SD命令 → 中断完成 |
DMA_ADDR, BLOCK, COMMAND, INT_STATUS |
| 电源管理 |
系统休眠/唤醒 |
保存/恢复寄存器 → 开关时钟 → 开关中断 |
CLOCK, POWER, INT_ENABLE |
三条主线共享同一套 sdstor_legacy 协议栈,通过 devExt->pdx.host.pci_dev.membase 统一访问硬件寄存器。