IOCTL_SPB_FULL_DUPLEX 요청 처리
SPI와 같은 일부 버스는 버스 컨트롤러와 버스의 디바이스 간에 동시에 읽기 및 쓰기 전송을 사용하도록 설정합니다. 이러한 전체 이중 전송을 지원하기 위해 SPB(단순 주변 버스) I/O 요청 인터페이스의 정의에는 옵션으로 IOCTL(IOCTL_SPB_FULL_DUPLEX I/O 제어 코드)이 포함됩니다. 하드웨어에서 완전 이중 전송을 구현하는 버스 컨트롤러용 SPB 컨트롤러 드라이버만 IOCTL_SPB_FULL_DUPLEX IOCTL을 지원해야 합니다.
SPB 컨트롤러 드라이버가 전체 이중 전송에 대한 I/O 요청을 지원하는 경우 드라이버는 이러한 요청에 IOCTL_SPB_FULL_DUPLEX IOCTL을 사용해야 하며 이 항목에 제시된 구현 지침을 따라야 합니다. 이러한 지침의 목적은 IOCTL_SPB_FULL_DUPLEX 요청을 지원하는 모든 하드웨어 플랫폼에서 균일한 동작을 장려하는 것입니다. SPB 연결 주변 장치용 드라이버는 이러한 요청에 의존하여 실행되는 플랫폼에 관계없이 유사한 결과를 생성할 수 있습니다.
버퍼 요구 사항
IOCTL_SPB_FULL_DUPLEX 요청의 형식은 IOCTL_SPB_EXECUTE_SEQUENCE 요청과 동일하지만 다음 제약 조건을 사용합니다.
- 요청의 SPB_TRANSFER_LIST 구조에는 정확히 두 개의 항목이 포함되어야 합니다. 첫 번째 항목은 디바이스에 쓸 데이터가 포함된 버퍼에 대해 설명합니다. 두 번째 항목은 디바이스에서 데이터를 읽는 데 사용되는 버퍼에 대해 설명합니다.
- 전송 목록의 각 SPB_TRANSFER_LIST_ENTRY 구조체는 DelayInUs 값을 0으로 지정해야 합니다.
전체 이중 전송 중에 읽기 및 쓰기 전송이 한눈에 시작됩니다. 쓰기 데이터의 첫 번째 바이트는 읽기 데이터의 첫 번째 바이트와 동시에 버스를 통해 전송됩니다.
IOCTL_SPB_FULL_DUPLEX 요청의 쓰기 및 읽기 버퍼는 길이가 같을 필요가 없습니다.
읽기 버퍼가 쓰기 버퍼보다 짧은 경우 쓰기 버퍼의 전체 내용이 디바이스에 기록될 때까지 전체 이중 버스 전송이 계속됩니다. 읽기 버퍼가 가득 찬 후 버스 컨트롤러는 전체 이중 버스 전송이 완료될 때까지 디바이스에서 받은 모든 추가 데이터를 삭제합니다.
쓰기 버퍼가 읽기 버퍼보다 짧은 경우 읽기 버퍼가 가득 찼을 때까지 전체 이중 버스 전송이 계속됩니다. 쓰기 버퍼의 전체 내용이 디바이스에 기록되면 버스 컨트롤러는 전체 이중 버스 전송이 완료될 때까지 디바이스에 0을 씁니다.
IOCTL_SPB_FULL_DUPLEX 요청이 성공적으로 완료되면 SPB 컨트롤러 드라이버는 I/O 상태 블록의 Status 멤버를 STATUS_SUCCESS 설정하고 전체 이중 전송 중에 전송된 총 바이트 수(바이트 읽기 및 쓴 바이트)로 정보 멤버를 설정합니다. 정보 멤버의 개수 값은 읽기 버퍼 크기와 쓰기 버퍼 크기의 합계를 초과해서는 안 됩니다.
읽기 버퍼가 쓰기 버퍼보다 짧은 경우 정보 멤버의 개수 값에는 읽기 버퍼가 가득 찬 후 버스 컨트롤러가 디바이스에서 읽고 삭제하는 데이터의 바이트를 포함하지 않아야 합니다. 예를 들어 1 바이트 쓰기 버퍼와 4 바이트 읽기 버퍼가 있는 전체 이중 전송이 성공적으로 완료되면 count 값은 8이 아닌 5여야 합니다. 마찬가지로 쓰기 버퍼가 읽기 버퍼보다 짧은 경우 쓰기 버퍼가 비워진 후 개수 값에 디바이스에 기록된 0이 포함되지 않아야 합니다.
매개 변수 검사
IOCTL_SPB_EXECUTE_SEQUENCE 및 IOCTL_SPB_FULL_DUPLEX 요청은 형식이 비슷하지만 SPB 프레임워크 확장(SpbCx)에 의해 다르게 처리됩니다. IOCTL_SPB_EXECUTE_SEQUENCE 요청의 경우 SpbCx는 요청의 매개 변수 값의 유효성을 검사하고 요청 시작자의 프로세스 컨텍스트에서 요청의 버퍼를 캡처합니다. SpbCx 는 이러한 요청 전용인 드라이버의 EvtSpbControllerIoSequence 콜백 함수를 통해 spB 컨트롤러 드라이버에 IOCTL_SPB_EXECUTE_SEQUENCE 요청을 전달합니다.
반면 SpbCx는 IOCTL_SPB_FULL_DUPLEX 요청을 사용자 지정 드라이버 정의 IOCTL 요청으로 처리합니다. SpbCx는 드라이버의 EvtSpbControllerIoOther 콜백 함수를 통해 SPB 컨트롤러 드라이버에 IOCTL_SPB_FULL_DUPLEX 요청을 전달합니다. 이 콜백 함수는 드라이버가 지원하는 모든 사용자 지정 IOCTL 요청도 처리합니다. SpbCx는 이러한 요청에 대한 매개 변수 검사 또는 버퍼 캡처를 수행하지 않습니다. 드라이버는 드라이버가 EvtSpbControllerIoOther 함수를 통해 수신하는 IOCTL 요청에 필요할 수 있는 매개 변수 검사 또는 버퍼 캡처를 담당합니다. 버퍼 캡처를 사용하도록 설정하려면 드라이버가 EvtSpbControllerIoOther 함수를 등록할 때 드라이버가 EvtIoInCallerContext 콜백 함수를 제공해야 합니다. 자세한 내용은 사용자 지정 IOCTL에 SPB_TRANSFER_LIST 구조 사용을 참조하세요.
일반적으로 SPB 컨트롤러 드라이버는 EvtIoInCallerContext 함수 대신 EvtSpbControllerIoOther 함수의 IOCTL_SPB_FULL_DUPLEX 요청에서 매개 변수 값의 유효성을 검사합니다. 다음 코드 예제에서는 드라이버 매개 변수 검사를 구현 하는 방법을 보여 줍니다. 이 예제에서 드라이버는 다음 매개 변수 요구 사항이 충족되는지 확인합니다.
- 요청의 전송 목록에는 정확히 두 개의 항목이 포함됩니다.
- 전송 목록의 첫 번째 항목은 쓰기 버퍼용이고, 두 번째 항목은 읽기 버퍼용입니다.
- 두 항목의 DelayInUs 값은 0입니다.
//
// Validate the transfer count.
//
SPB_REQUEST_PARAMETERS params;
SPB_REQUEST_PARAMETERS_INIT(¶ms);
SpbRequestGetParameters(SpbRequest, ¶ms);
if (params.SequenceTransferCount != 2)
{
//
// The full-duplex request must have
// exactly two transfer descriptors.
//
status = STATUS_INVALID_PARAMETER;
goto exit;
}
//
// Retrieve the write and read transfer descriptors.
//
const ULONG fullDuplexWriteIndex = 0;
const ULONG fullDuplexReadIndex = 1;
SPB_TRANSFER_DESCRIPTOR writeDescriptor;
SPB_TRANSFER_DESCRIPTOR readDescriptor;
PMDL pWriteMdl;
PMDL pReadMdl;
SPB_TRANSFER_DESCRIPTOR_INIT(&writeDescriptor);
SPB_TRANSFER_DESCRIPTOR_INIT(&readDescriptor);
SpbRequestGetTransferParameters(
SpbRequest,
fullDuplexWriteIndex,
&writeDescriptor,
&pWriteMdl);
SpbRequestGetTransferParameters(
SpbRequest,
fullDuplexReadIndex,
&readDescriptor,
&pReadMdl);
//
// Validate the transfer direction of each descriptor.
//
if ((writeDescriptor.Direction != SpbTransferDirectionToDevice) ||
(readDescriptor.Direction != SpbTransferDirectionFromDevice))
{
//
// For full-duplex I/O, the direction of the first transfer
// must be SpbTransferDirectionToDevice, and the direction
// of the second must be SpbTransferDirectionFromDevice.
//
status = STATUS_INVALID_PARAMETER;
goto exit;
}
//
// Validate the delay for each transfer descriptor.
//
if ((writeDescriptor.DelayInUs != 0) || (readDescriptor.DelayInUs != 0))
{
//
// The write and read buffers for full-duplex I/O are transferred
// simultaneously over the bus. The delay parameter in each transfer
// descriptor must be set to 0.
//
status = STATUS_INVALID_PARAMETER;
goto exit;
}
MyDriverPerformFullDuplexTransfer(
pDevice,
pRequest,
writeDescriptor,
pWriteMdl,
readDescriptor,
pReadMdl);
매개 변수 값을 확인한 후 앞의 코드 예제는 라는 MyDriverPerformFullDuplexTransfer
드라이버 내부 루틴을 호출하여 전체 이중 I/O 전송을 시작합니다.