다음을 통해 공유


사용자 지정 IOCTL에 SPB_TRANSFER_LIST 구조 사용

간단한 SPB(주변 버스) 컨트롤러 드라이버가 하나 이상의 IOCTL(사용자 지정 I/O 컨트롤) 요청을 지원하는 경우 SPB_TRANSFER_LIST 구조를 사용하여 이러한 요청의 읽기 및 쓰기 버퍼를 설명합니다. 이 구조체는 요청의 버퍼를 설명하는 균일한 방법을 제공하며 METHOD_BUFFERED I/O 작업과 관련된 버퍼 복사 오버헤드를 방지합니다.

사용자 지정 IOCTL 요청이 SPB_TRANSFER_LIST 구조를 사용하는 경우 SPB 컨트롤러 드라이버는 SpbRequestCaptureIoOtherTransferList 메서드를 호출하여 요청 생성자의 프로세스 컨텍스트에서 이러한 버퍼를 캡처해야 합니다. 드라이버는 SpbRequestGetTransferParameters 메서드를 호출하여 이러한 버퍼에 액세스할 수 있습니다.

SPB I/O 요청 인터페이스의 일부로 정의된 IOCTL_SPB_FULL_DUPLEXIOCTL_SPB_EXECUTE_SEQUENCE 요청은 SPB_TRANSFER_LIST 구조를 사용하여 읽기 및 쓰기 버퍼를 설명합니다. IOCTL_SPB_FULL_DUPLEX 요청에 대한 SPB_TRANSFER_LIST 구조는 요청의 쓰기 버퍼와 읽기 버퍼(해당 순서)를 모두 설명합니다. IOCTL_SPB_EXECUTE_SEQUENCE 요청에 대한 SPB_TRANSFER_LIST 구조는 임의의 읽기 및 쓰기 버퍼 시퀀스를 설명할 수 있습니다.

마찬가지로 사용자 지정 IOCTL을 정의하여 SPB_TRANSFER_LIST 구조가 읽기 및 쓰기 버퍼의 일부 조합을 사용하도록 요구하고, 목록에 필요할 수 있는 버퍼의 순서를 지정할 수 있습니다.

SPB 주변 디바이스에 대한 KMDF(Kernel-Mode Driver Foundation) 드라이버는 WdfIoTargetSendIoctlSynchronously 와 같은 메서드를 호출하여 IOCTL 요청을 SPB 컨트롤러에 보냅니다. 이 메서드에는 InputBufferOutputBuffer 매개 변수가 있습니다. 일부 유형의 디바이스에 대한 드라이버는 이러한 두 매개 변수를 사용하여 IOCTL 요청에 대해 각각 쓰기 버퍼 및 읽기 버퍼를 가리킬 수 있습니다. 그러나 SPB 컨트롤러에 IOCTL 요청을 보내기 위해 SPB 주변 장치 드라이버는 InputBuffer 매개 변수를 설정하여 SPB_TRANSFER_LIST 구조를 가리키는 메모리 설명자를 가리킵니다. 이 구조체는 I/O 컨트롤 작업에 필요한 모든 읽기 또는 쓰기 버퍼를 설명합니다. 드라이버는 OutputBuffer 매개 변수를 NULL로 설정합니다.

마찬가지로 SPB 주변 디바이스에 대한 UMDF(User-Mode Driver Foundation) 드라이버는 IWDFIoTarget::FormatRequestForIoctl 과 같은 메서드를 호출하여 I/O 컨트롤 작업에 대한 I/O 요청 형식을 지정합니다. 이 메서드에는 pInputMemorypOutputMemory 매개 변수가 있습니다. 일부 유형의 디바이스에 대한 드라이버는 이러한 두 매개 변수를 사용하여 IOCTL 요청에 대한 쓰기 버퍼 및 읽기 버퍼를 가리킬 수 있습니다. 그러나 SPB 컨트롤러에 IOCTL 요청을 보내기 위해 SPB 주변 장치 드라이버는 pInputMemory 매개 변수를 설정하여 SPB_TRANSFER_LIST 구조가 포함된 메모리 개체를 가리킵니다. 이 구조체는 I/O 컨트롤 작업에 필요한 모든 읽기 또는 쓰기 버퍼를 설명합니다. 드라이버는 pOutputMemory 매개 변수를 NULL로 설정합니다.

매개 변수 검사 및 버퍼 캡처

SPB 프레임워크 확장(SpbCx)이 IOCTL_SPB_EXECUTE_SEQUENCE 요청을 받으면 SpbCx는 드라이버의 EvtSpbControllerIoSequence 함수를 호출하여 SPB 컨트롤러 드라이버에 이 요청을 전달합니다. 이 호출 전에 SpbCx는 요청의 버퍼를 설명하는 SPB_TRANSFER_LIST 구조를 검사합니다. SpbCx는 요청 시작자의 프로세스 컨텍스트에서 이러한 버퍼를 캡처합니다. (사용자 모드 메모리의 버퍼는 메모리가 할당된 프로세스에서만 액세스할 수 있습니다.) 또한 SpbCx는 요청의 매개 변수 값이 유효한지 여부를 확인합니다.

SpbCx가 IOCTL_SPB_FULL_DUPLEX 요청 또는 사용자 지정 IOCTL 요청을 받으면 SpbCx는 드라이버의 EvtSpbControllerIoOther 콜백 함수를 호출하여 SPB 컨트롤러 드라이버에 이 요청을 전달합니다. 이 호출을 하기 전에 SpbCx는 요청의 매개 변수 값에 대한 유효성 검사를 수행하지 않으며, 시작자의 컨텍스트에서 요청의 버퍼를 캡처하지 않습니다. 이러한 요청에 대한 매개 변수 검사 및 버퍼 캡처는 SPB 컨트롤러 드라이버의 책임입니다.

SPB 컨트롤러 드라이버가 IOCTL_SPB_FULL_DUPLEX 요청을 지원하거나 버퍼에 SPB_TRANSFER_LIST 구조를 사용하는 사용자 지정 IOCTL 요청을 지원하는 경우 드라이버는 EvtIoInCallerContext 콜백 함수를 구현해야 합니다. 드라이버는 드라이버의 EvtSpbControllerIoOther 콜백 함수를 등록하는 SpbControllerSetIoOtherCallback 메서드 호출에서 이 함수에 대한 포인터를 입력 매개 변수로 제공합니다. SpbCx가 IOCTL_SPB_FULL_DUPLEX 요청 또는 사용자 지정 IOCTL 요청을 받으면 SpbCx는 시작자의 컨텍스트에서 드라이버의 EvtIoInCallerContext 함수를 호출합니다. IOCTL 요청이 SPB_TRANSFER_LIST 구조를 사용하는 경우 EvtIoInCallerContext 함수는 SpbRequestCaptureIoOtherTransferList 메서드를 호출하여 요청의 버퍼를 캡처합니다. EvtIoInCallerContext 함수는 요청의 일부 예비 처리를 수행할 수도 있습니다.

다음 코드 예제에서는 SPB 컨트롤러 드라이버에 의해 구현되는 EvtIoInCallerContext 함수를 보여 줍니다.

VOID
EvtIoInCallerContext(
    _In_  WDFDEVICE   SpbController,
    _In_  WDFREQUEST  FxRequest
    ) 
{
    NTSTATUS status = STATUS_SUCCESS;
    WDF_REQUEST_PARAMETERS fxParams;
  
    WDF_REQUEST_PARAMETERS_INIT(&fxParams);
    WdfRequestGetParameters(FxRequest, &fxParams);

    if ((fxParams.Type != WdfRequestTypeDeviceControl) &&
        (fxParams.Type != WdfRequestTypeDeviceControlInternal))
    {
        status = STATUS_NOT_SUPPORTED;
        goto exit;
    }

    //
    // The driver should check for custom IOCTLs that it handles.
    // If the IOCTL is not recognized, complete the request with a
    // status of STATUS_NOT_SUPPORTED.
    //

    switch (fxParams.Parameters.DeviceIoControl.IoControlCode)
    {
        ...

    default:
        status = STATUS_NOT_SUPPORTED;
        goto exit;
    }

    //
    // The IOCTL is recognized. Capture the buffers in the request.
    //

    status = SpbRequestCaptureIoOtherTransferList((SPBREQUEST)FxRequest);

    //
    // If the capture fails, the driver must complete the request instead
    // of placing it in the SPB controller's request queue.
    //

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    status = WdfDeviceEnqueueRequest(SpbController, FxRequest);

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

exit:

    if (!NT_SUCCESS(status))
    {
        WdfRequestComplete(FxRequest, status);
    }
}

앞의 코드 예제에서 문은 switch 요청에 SPB 컨트롤러 드라이버가 인식하는 IOCTL이 포함되어 있음을 확인합니다. 간단히 말하면 문의 본문 switch 이 표시되지 않습니다. 다음으로 SpbRequestCaptureIoOtherTransferList 메서드에 대한 호출은 요청의 버퍼를 캡처합니다. 이 호출이 성공하면 요청이 SPB 컨트롤러의 I/O 큐에 추가됩니다. 그렇지 않으면 요청이 오류 상태 코드로 완료됩니다.

EvtSpbControllerIoOther 함수의 매개 변수 검사를 보여 주는 코드 예제는 IOCTL_SPB_FULL_DUPLEX 요청 처리를 참조하세요.