Share via


ダイレクト I/O を使用する安全なデジタル要求

次のコード例は、ドライバーがコマンド要求を使用して、デバイスの関数基本レジスタ (FBR) の内容を取得する方法を示しています。 取得されるデータの量が少ないため、この例ではダイレクト I/O コマンド (SD 仕様では CMD52 と呼ばれます) を使用します。このコマンドは、CMD ラインにかけてデータを送信するようにバス ドライバーに指示します。 拡張 I/O (SD 仕様では CMD53 と呼ばれます) の使用方法を示すコード例については、「 拡張 I/O を使用する安全なデジタル要求」を参照してください。

    const SDCMD_DESCRIPTOR ReadIoDirectDesc =
    {SDCMD_IO_RW_DIRECT, SDCC_STANDARD, SDTD_READ,
    SDTT_CMD_ONLY, SDRT_5};
    
    PSDBUS_REQUEST_PACKET sdrp = NULL;
    SD_RW_DIRECT_ARGUMENT sdIoArgument;
    
    sdrp = ExAllocatePool(NonPagedPool, 
        sizeof(SDBUS_REQUEST_PACKET));
    if (!sdrp) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    RtlZeroMemory(sdrp, sizeof(SDBUS_REQUEST_PACKET));
    sdrp->RequestFunction = SDRF_DEVICE_COMMAND;
    sdrp->Parameters.DeviceCommand.CmdDesc = ReadIoDirectDesc;
    
    // Set up the argument and command descriptor
    
    sdIoArgument.u.AsULONG = 0;
    sdIoArgument.u.bits.Address = Offset;
    
    // Function # must be initialized by SdBus GetProperty call
    
    sdIoArgument.u.bits.Function = pDevExt->FunctionNumber;
    sdrp->Parameters.DeviceCommand.Argument = sdIoArgument.u.AsULONG;
    
    // Submit the request
    
    status = SdBusSubmitRequest(pDevExt->BusInterface.Context, sdrp);
    
    if (NT_SUCCESS(status)) {
        // for direct I/O, the data comes in the response
        *Data = sdrp->ResponseData.AsUCHAR[0];
    }
    ExFreePool(sdrp);

FBR を読み取るために、このコード例では次の手順を実行します。

  1. 記述子の初期化

    device-command 要求を送信する最初の手順は、SD コマンド記述子 "SDCMD_DESCRIPTOR" を定義することです。 通常、記述子は定数のデータ構造として定義されます。 このコード例の記述子は、次の要素を使用して読み取り操作を定義します。

    要素 説明

    SD_COMMAND_CODE

    記述子が定義した操作は FBR から 1 バイトのデータを読み取るため、このコード例ではダイレクト I/O コマンド (CMD52) を使用します。このコマンドは、DAT ラインではなく CMD ラインにかけて要求されたデータを報告するよう、カードに指示します。 これは、"SDCMD_IO_RW_DIRECT" の値をこのメンバーに割り当てることによって、ダイレクト I/O コマンドであることを示すコード例です。

    SD_COMMAND_CLASS

    読み取り操作は標準コマンド セット (コマンド コード 0 から 63) に属しているため、記述子のこのメンバーに割り当てられる値は "SDCC_STANDARD" です。

    SD_TRANSFER_DIRECTION

    読み取り操作ではデバイスからホストへの転送が必要であるため、記述子のこのメンバーに割り当てられる値は "SDTD_READ" です。

    SD_TRANSFER_TYPE

    この操作は、CMD ラインを介してレジスタから少量のデータを読み取ります。 カードは DAT ラインを介してデータを送信する必要がないため、このメンバーには "SDTT_CMD_ONLY" の値が割り当てられます。

    SD_RESPONSE_TYPE

    記述子は SDRT_5 の応答の種類を指定します。つまり、操作が割り込み要求で完了したことをカードがホストに通知する必要があります。 R5 応答の説明については、マルチメディア・カード・アソシエーションの仕様を参照してください。

  2. 次の手順を実行して、要求パケットを初期化します。

    1. 要求関数の定義:

      このコード例では、SD 記述子を作成した後、要求パケット "SDBUS_REQUEST_PACKET" を初期化します。 要求パケットの RequestFunction メンバーは、要求にデバイス コマンド (SDRF_DEVICE_COMMAND の値) またはプロパティ操作 (SDRF_GET_PROPERTY または SDRF_SET_PROPERTY の値) が含まれているかどうかを指定します。 このコード例では、デバイス コマンドを開始するため、RequestFunction メンバーを "SDRF_DEVICE_COMMAND" に設定します。

    2. コマンド記述子を読み込む: 次に、新しく初期化された記述子を要求パケットの Parameters.DeviceCommand.CmdDesc メンバーに格納します。

    3. 読み取り/書き込み引数を初期化する:

      要求パケットには、バス ドライバーが取得するデータの場所を保持する SD_RW_DIRECT_ARGUMENT 構造体が含まれています。 この構造体には、バス ドライバーの読み取り先となる I/O 空間を持つファンクション番号も格納されます。 このコード例では、デバイス拡張機能からファンクション番号を取得します。これは、ドライバーが以前に (おそらくデバイスを起動したときに) SDRF_GET_PROPERTY 要求を使用してカードから情報を取得し、デバイス拡張機能に格納したことを意味します。

  3. 要求の送信

    このコード例では、記述子と要求パケットを初期化した後、同期要求ルーチン "SdBusSubmitRequest" を使用して要求を送信します。 要求ルーチンは、システムが SD インターフェイスを開いたときにドライバーに提供した要求パケットとインターフェイス コンテキスト情報を渡します。 これは同期要求であるため、ドライバーが DISPATCH_LEVEL 未満の IRQL で実行されている必要があります。

  4. コマンドの結果

    このコード例ではダイレクト I/O を使用するため、SD 要求パケットの ResponseData フィールド以外にデータ バッファーは必要ありません。