이 항목에서는 Windows 8에 포함된 USB 드라이버 스택에 URB를 할당, 빌드 및 보내기 위한 클라이언트 드라이버에 대한 모범 사례를 설명합니다.
Windows 8에는 USB(유니버설 직렬 버스) 3.0 디바이스를 지원하는 새로운 USB 드라이버 스택이 포함되어 있습니다. 새 USB 3.0 드라이버 스택은 USB 3.0 사양에 따라 몇 가지 새로운 기능을 구현합니다. 또한 드라이버 스택에는 클라이언트 드라이버가 일반적인 작업을 효율적으로 수행할 수 있도록 하는 다른 기능이 포함되어 있습니다. 예를 들어 새 드라이버 스택은 클라이언트 드라이버가 실제 메모리의 불연결 페이지에 전송 버퍼를 보낼 수 있도록 하는 체인 MDL을 허용합니다.
클라이언트 드라이버가 Windows 8용 USB 드라이버 스택의 새로운 기능을 사용하려면 먼저 드라이버가 장치에 대해 Windows에서 로드하는 기본 USB 드라이버 스택에 등록해야 합니다. 클라이언트 드라이버를 등록하려면 USBD_CreateHandle 호출하고 계약 버전을 지정합니다. 클라이언트 드라이버가 Windows 8에서 향상된 기능과 새로운 기능을 빌드, 실행 및 사용하도록 의도된 경우 클라이언트 계약 버전이 USBD_CLIENT_CONTRACT_VERSION_602.
USBD_CLIENT_CONTRACT_VERSION_602 버전 클라이언트 드라이버의 경우 USB 드라이버 스택은 클라이언트 드라이버가 다음 규칙 집합을 준수한다고 가정합니다.
- 부실 또는 잘못된 파이프 핸들을 사용하여 I/O 요청을 보내지 마세요.
- Windows 8에서 할당 루틴을 호출하여 URB를 할당
- 보류 중인 요청과 연결된 활성 URL을 다시 사용하지 마세요.
- 고속 및 슈퍼스피드 등시 전송에 8보다 큰 폴링 주기를 사용하지 마세요.
- 등시 패킷의 수가 프레임당 패킷 수의 정확한 배수인지 확인합니다.
- 문서화된 IRQL 수준에서 루틴 호출
- 관련 항목
USB 드라이버 스택은 수신된 요청에 대한 유효성 검사를 수행하고 가능한 한 위반을 처리합니다. 이렇게 하지 않으면 정의되지 않은 동작이 발생할 수 있습니다.
부실 또는 잘못된 파이프 핸들을 사용하여 I/O 요청을 보내지 마세요.
클라이언트 드라이버는 오래된 파이프 핸들을 사용하여 USB 드라이버 스택에 I/O 요청을 보내면 안 됩니다. 오래된 파이프 핸들은 장치에서 더 이상 선택되지 않은 구성, 인터페이스 또는 대체 설정을 선택하기 위한 요청으로 얻어진 파이프 핸들을 나타냅니다. 부실 파이프 핸들을 방지하려면 클라이언트 드라이버가 구성 또는 인터페이스를 선택할 때마다 드라이버가 파이프 핸들의 캐시를 새로 고쳐야 합니다(일반적으로 디바이스 컨텍스트에 저장됨). 특정 경합 조건으로 인해 부실 파이프 핸들이 발생할 수도 있습니다. 예를 들어 클라이언트 드라이버는 선택한 인터페이스의 파이프 핸들을 사용하여 I/O 요청을 보냅니다. 요청이 완료되기 전에 클라이언트 드라이버는 사용 중인 파이프 핸들과 연결된 동일한 엔드포인트를 사용하지 않는 대체 설정을 선택합니다. 보류 중인 두 요청으로 인해 경합 상태가 발생하여 파이프 핸들이 유효하지 않게 될 수 있습니다.
Windows 8에서 할당 루틴을 호출하여 URB를 할당하십시오.
Windows 8은 URL(USB 요청 블록)을 할당, 빌드 및 해제하기 위한 새로운 루틴을 제공합니다. URL을 할당하려면 WDM(Windows 드라이버 모델) 클라이언트 드라이버가 항상 다음 목록에 표시된 새 루틴을 사용해야 합니다.
- USBD_UrbAllocate
- USBD_IsochUrbAllocate
- USBD_SelectConfigUrbAllocateAndBuild
- USBD_SelectInterfaceUrbAllocateAndBuild
- USBD_UrbFree
- USBD_AssignUrbToIoStackLocation
이전 목록의 루틴은 추적 및 처리를 개선하기 위해 할당된 URB에 불투명 URB 컨텍스트를 연결할 수 있습니다. 클라이언트 드라이버는 URB 컨텍스트의 내용을 보거나 수정할 수 없습니다. Windows 8의 URB 할당에 대한 자세한 내용은 URL 할당 및 빌드를 참조하세요.
등록하는 동안 해당 버전을 USBD_CLIENT_CONTRACT_VERSION_602 식별하는 WDF(Windows 드라이버 프레임워크) 클라이언트 드라이버( WdfUsbTargetDeviceCreateWithParameters 참조)의 경우 USB 드라이버 스택은 클라이언트 드라이버가 새 WdfUsbTargetDeviceCreateUrb을 호출하여 URB에 대한 메모리를 할당해야 합니다.
보류 중인 요청과 연결된 활성 URL을 다시 사용하지 마세요.
USB 드라이버 스택은 URB와 연결된 요청 전에 다시 제출된 활성 URB가 감지되면 의도적으로 버그를 검사합니다. URB는 요청이 보류 중이고 클라이언트 드라이버의 IRP 완료 루틴이 호출되지 않은 한 활성화됩니다. 활성 URB에서 다음 작업을 수행하지 마세요.
- 다른 요청에 대해 활성 URB를 다시 제출 하지 마세요 (URB를 다른 IRP와 연결).
- 활성 URB의 내용을 수정 하지 마세요.
- 활성 URB를 해제 하지 마세요 .
클라이언트 드라이버의 완료 루틴이 호출되면 드라이버는 완료 루틴 내에서 특정 유형의 요청에 대한 URL을 다시 제출할 수 있습니다. 다시 제출에는 다음 규칙이 적용됩니다.
클라이언트 드라이버는 동일한 구성을 선택하기 위해 선택 구성 요청 이외의 모든 유형의 요청에 대해 USBD_SelectConfigUrbAllocateAndBuild 의해 할당된 URB를 다시 사용해서는 안 됩니다.
클라이언트 드라이버는 인터페이스에서 동일한 대체 설정을 선택하기 위해 선택 인터페이스 요청 이외의 모든 유형의 요청에 대해 USBD_SelectInterfaceUrbAllocateAndBuild 의해 할당된 URB를 다시 사용하면 안됩니다. 예제는 USBD_SelectInterfaceUrbAllocateAndBuild 비고를 참조하세요.
USBD_IsochUrbAllocate 할당된 URB는 등시 전송 요청에만 다시 사용해야 합니다. 반대로 다른 유형의 I/O 요청(컨트롤, 대량 또는 인터럽트)에 할당된 URB는 등시 요청에 사용해서는 안 됩니다.
예를 들어 클라이언트 드라이버는 대량 전송 요청에 대한 URB 구조를 할당하고 빌드합니다. 또한 클라이언트 드라이버는 디바이스의 등시 엔드포인트에 데이터를 보내려고 합니다. 대량 전송 요청이 완료된 후, 클라이언트 드라이버는 동기화 요청을 위해 URB의 서식을 다시 지정하여 제출하지 말아야 합니다. 이는 등시 요청에 연결된 URB가 패킷 수에 따라 길이가 달라지기 때문입니다. 또한 패킷은 프레임 경계에서 시작 및 종료해야 합니다. 할당된 URB(대량 전송용)가 등시 전송에 필요한 버퍼 레이아웃에 맞지 않을 수 있으며 요청이 실패할 수 있습니다.
USBD_UrbAllocate에 의해 할당된 URB는 등시성 전송 요청, 선택 구성 요청 또는 선택 인터페이스 요청에 다시 사용해서는 안 됩니다. 디바이스에서 선택한 구성을 사용하지 않도록 설정하기 위해 NULL 구성을 선택하는 데 URB를 다시 사용할 수 있습니다. URB는 활성화되어 있지 않아야 하며 클라이언트 드라이버는 UsbBuildSelectConfigurationRequest 매크로를 호출하고 ConfigurationDescriptor 매개 변수에서 NULL을 전달하여 URB의 서식을 다시 지정해야 합니다.
URB를 다시 제출하기 전에 클라이언트 드라이버는 요청 유형에 대해 정의된 적절한 UsbBuildXxx 매크로를 사용하여 URB의 서식을 다시 지정해야 합니다. USB 스택이 일부 콘텐츠를 변경했을 수 있으므로 드라이버가 URB의 형식을 지정하는 것이 중요합니다.
예를 들어 드라이버가 UsbBuildInterruptOrBulkTransferRequest 를 호출하여 대량 전송 요청에 대한 URB를 초기화한다고 가정합니다( _URB_BULK_OR_INTERRUPT_TRANSFER 참조). 드라이버가 URB 구조의 TransferBufferMDL 멤버를 NULL로 초기화하는 경우 USB 드라이버 스택은 MDL 대신 디바이스와 데이터를 교환하기 위해 전송 버퍼(지정된 TransferBuffer)를 사용합니다. 그러나 내부적으로 USB 드라이버 스택은 MDL을 만들고, TransferBufferMDL에 MDL에 대한 포인터를 저장하고, MDL을 사용하여 데이터를 스택 아래로 전달할 수 있습니다. USB 드라이버 스택이 MDL 메모리를 해제하더라도 클라이언트 드라이버가 완료 루틴에서 URB를 처리할 때 TransferBufferMDL 이 NULL이 아닐 수 있습니다. URB의 멤버의 형식이 올바르게 지정되도록 하려면 드라이버는 요청을 제출하기 전에 UsbBuildInterruptOrBulkTransferRequest 를 다시 호출하여 URB의 서식을 다시 지정해야 합니다.
고속 및 슈퍼스피드 등시 전송에서 폴링 주기를 8보다 크게 설정하지 마세요.
USB 드라이버 스택은 고속 및 SuperSpeed 등시 파이프를 지원하며, 폴링 주기가 1, 2, 4 또는 8로 설정될 수 있습니다. 클라이언트 드라이버는 기간이 8보다 큰 엔드포인트로 IO를 보내면 안됩니다. 이렇게 하면 버그 검사가 발생할 수 있습니다.
프레임당 패킷 수의 배수인 등시 패킷의 수인지 확인합니다.
고속 및 SuperSpeed 등시 전송의 경우 프레임당 등시 패킷 수는 8/폴링 기간으로 계산됩니다. 클라이언트 드라이버는 URB에 지정된 NumberOfPackets 값( _URB_ISOCH_TRANSFER 참조)이 프레임당 패킷 수의 배수인지 확인해야 합니다.
USB 드라이버 스택은 NumberOfPackets 가 프레임당 패킷 수의 배수가 아닌 등시 전송 URL을 지원하지 않습니다.
문서화된 IRQL 수준에서 루틴 호출
클라이언트 드라이버를 USBD_CLIENT_CONTRACT_VERSION_602 계약 버전으로 등록하는 경우 USB 드라이버 스택은 클라이언트 드라이버가 적절한 IRQL 수준에서 요청을 보냈다고 가정합니다. 클라이언트 드라이버가 DISPATCH_LEVEL에서 요청을 보낼 때, 이는 원래 PASSIVE_LEVEL에서 보내야 합니다. 요청을 받으면 USB 드라이버 스택이 IRQL 값의 유효성을 검사하고 요청에 실패하는 경우도 있습니다. 그러나 다른 경우에는 USB 드라이버 스택이 버그 검사를 생성할 수 있습니다.
관련 항목
USB 디바이스에 요청 보내기