共用方式為


使用擴充 I/O 的安全數位要求

安全數位 (SD) 讀取或寫入多個字節的數據要求,必須在 SD 規格) 中使用稱為 CMD53 的擴充 I/O (命令) 。 擴充 I/O 命令會指示總線驅動程式透過 SD 記憶卡的 DAT 線路傳輸數據。 數據傳輸的特性取決於 SD 控制器的功能。 例如,某些控制器只允許可程式化 I/O (PIO) ;其他允許直接記憶體存取 (DMA) 。 為了達到不同 SD 控制器類型的最大相容性,設備驅動器應該使用描述數據緩衝區的 MDL 指標載入要求封包。 除非較高層中的驅動程式建構 MDL,否則設備驅動器必須建構自己的 MDL,並將它傳遞至設備驅動器。

下列程式代碼範例示範驅動程式如何使用 MDL 描述的數據緩衝區來執行擴充 I/O 要求。 此程式代碼範例的格式類似於 使用直接 I/O 的安全數位要求中所述的直接 I/O 程式代碼範例,因此在研究擴充 I/O 程式代碼範例之前,研究直接 I/O 程式代碼範例可能會很有説明。

這兩個範例之間的原則差異在於擴充 I/O 程式代碼範例說明如何搭配 SD 要求使用 MDL。 描述元和要求封包定義的方式也有一些微差異,適用於直接和擴充的 I/O。

    const SDCMD_DESCRIPTOR WriteIoExtendedDesc =
    {SDCMD_IO_RW_EXTENDED, SDCC_STANDARD,
    SDTD_WRITE, SDTT_SINGLE_BLOCK, SDRT_1};
    
    // first, get an MDL to map the data. Call IoAllocateMdl to
    // allocate an MDL and pass in a pointer to a buffer  
    // allocated from the non-paged pool.
    
    mdl = IoAllocateMdl(Data, Length, FALSE, FALSE, NULL);
    
    if (mdl == NULL) {
      return STATUS_INSUFFICIENT_RESOURCES;
    }
    
    MmBuildMdlForNonPagedPool (mdl);
    
    // next, allocate a request packet for the arguments of the command
     
    sdrp = ExAllocatePool(NonPagedPool, sizeof(SDBUS_REQUEST_PACKET));
    
    if (!sdrp) {
      IoFreeMdl(mdl);
      return STATUS_INSUFFICIENT_RESOURCES;
    }
    RtlZeroMemory(sdrp, sizeof(SDBUS_REQUEST_PACKET));
    sdrp->RequestFunction = SDRF_DEVICE_COMMAND;
    sdrp->Parameters.DeviceCommand.CmdDesc = 
    WriteIoExtendedDesc;
    
    // then, set up the argument and command descriptor
    sdIoArgument.u.AsULONG = 0;
    sdIoArgument.u.bits.Address = Offset;
    
    // retrieve function number, the driver previously initialized 
    // this value with the SdBus GetProperty call
    sdIoArgument.u.bits.Function = pDevExt->FunctionNumber;
    sdIoArgument.u.bits.WriteToDevice = 1;
    
    sdrp->Parameters.DeviceCommand.Argument = 
        sdIoArgument.u.AsULONG;
    
    sdrp->Parameters.DeviceCommand.Mdl = mdl;
    sdrp->Parameters.DeviceCommand.Length = Length;
    // finally, submit the request
    status = SdBusSubmitRequest(pDevExt->BusInterface.Context,sdrp);
    
    IoFreeMdl(mdl);
    ExFreePool(sdrp);

此程式代碼範例包含下列步驟:

  1. 初始化描述元

    傳送裝置命令要求的第一個步驟是定義 SD 命令描述元 ,SDCMD_DESCRIPTOR。 程式代碼範例中的描述項會使用下列元素定義擴充 I/O 寫入作業:

    元素 Description

    SD_COMMAND_CODE

    描述項所定義的作業會執行擴充的 I/O 寫入,因此命令程式代碼的值會SDCMD_IO_RW_DIRECT。

    SD_COMMAND_CLASS

    擴充 I/O 寫入作業屬於標準命令集 (命令代碼 0 到 63) ,因此指派給描述元成員的值會SDCC_STANDARD。

    SD_TRANSFER_DIRECTION

    寫入作業需要從主機傳輸到裝置,因此指派給描述項成員的值會SDTD_WRITE。

    SD_TRANSFER_TYPE

    擴充 I/O 寫入作業的描述項必須包含傳輸類型。 程式代碼範例會指定單一區塊寫入SDTT_SINGLE_BLOCK,表示主機會將一個數據區塊寫入裝置。 驅動程式已透過先前的 SET_BLOCKLEN 命令建立區塊的大小 (本程式代碼範例中未說明) 。 如需SET_BLOCKLEN命令和SDTT_SINGLE_BLOCK傳輸類型的說明,請參閱多媒體卡片關聯 (MMCA) 技術委員會所發佈的 多媒體卡片 規格。

    SD_RESPONSE_TYPE

    描述項會指定SDRT_1的回應類型,它會指定命令的標準 R1 回應,並包含狀態數據。 如需 R1 回應的說明,請參閱 多媒體卡片關聯 規格。

  2. 設定 MDL

    呼叫 IoAllocateMdl 以配置 MDL,並將指標傳入從非分頁集區配置的緩衝區。 接下來, MmBuildMdlForNonPagedPool 例程會採用新配置的 MDL,以指定非分頁集區中的虛擬記憶體緩衝區,並更新它來描述基礎實體頁面。 MmBuildMdlForNonPagedPool 的呼叫端必須在 IRQL <= DISPATCH_LEVEL執行。

  3. 完成下列步驟來初始化要求封包

    • 定義要求函式

      建立 SD 描述元之後,程式代碼範例會初始化要求封包 ,SDBUS_REQUEST_PACKET。 要求封包的 RequestFunction 成員會指定要求是否包含裝置命令 (值SDRF_DEVICE_COMMAND) 或属性作业 (值SDRF_GET_PROPERTY或SDRF_SET_PROPERTY) 。 程式代碼範例正在傳送裝置命令,因此會將 RequestFunction 成員設定為 SDRF_DEVICE_COMMAND。

    • 載入命令描述元。 接下來,程式代碼範例會將新初始化的描述元儲存在要求封包的 Parameters.DeviceCommand.CmdDesc 成員中。

    • 初始化讀取/寫入自變數

      要求封包包含具有總線驅動程式寫入位置 的SD_RW_DIRECT_ARGUMENT 結構。 這個結構也會儲存其總線驅動程式讀取其 I/O 空間的函式數目。 程式代碼範例會從裝置擴充功能擷取函式號碼,這表示驅動程式先前從 (卡片擷取這項資訊,可能是在啟動具有SDRF_GET_PROPERTY要求的裝置時,並將它儲存在裝置擴充功能中。

  4. 提交要求

    初始化描述元和要求封包之後,此範例會使用同步要求例程 SdBusSubmitRequest 來提交要求。 它會傳入要求封包,以及系統在開啟 SD 介面時提供給驅動程式的介面內容資訊。 因為這是同步要求,所以驅動程式必須在 IRQL 執行小於 DISPATCH_LEVEL。

  5. 命令的結果

    由於程式代碼範例使用直接 I/O 命令,所以 SD 要求封包中 ResponseData 欄位以外的數據緩衝區除外。

程式代碼範例會從非分頁集區配置數據傳輸緩衝區。 驅動程式可以使用 PagedPool 進行數據傳輸緩衝區,前提是它會鎖定頁面。 不過,當執行SDRF_GET_PROPERTY和SDRF_SET_PROPERTY要求時,驅動程序必須 一律 從非分頁集區配置數據傳輸緩衝區。 驅動程式也必須從非分頁集區配置 SD 要求封包,因為隨附 SD 要求的 IRP 完成例程可能會在延遲的程式調用中執行, (DPC) 。

針對所有類型的要求,當緩衝區很小且驅動程式會短暫保留緩衝區時,從非分頁集區配置緩衝區有效能優點。