모범 사례: URL 사용

이 항목에서는 Windows 8 포함된 USB 드라이버 스택에 URB를 할당, 빌드 및 보내기 위한 클라이언트 드라이버에 대한 모범 사례를 설명합니다.

Windows 8 USB(유니버설 직렬 버스) 3.0 디바이스를 지원하는 새 USB 드라이버 스택이 포함되어 있습니다. 새 USB 3.0 드라이버 스택은 USB 3.0 사양에 따라 몇 가지 새로운 기능을 구현합니다. 또한 드라이버 스택에는 클라이언트 드라이버가 일반적인 작업을 효율적으로 수행할 수 있는 다른 기능이 포함되어 있습니다. instance 경우 새 드라이버 스택은 클라이언트 드라이버가 물리적 메모리의 불연발 페이지에 전송 버퍼를 보낼 수 있도록 하는 연결된 MDL을 허용합니다.

클라이언트 드라이버가 Windows 8 USB 드라이버 스택의 새로운 기능을 사용하려면 먼저 드라이버가 디바이스용 Windows에서 로드하는 기본 USB 드라이버 스택에 등록해야 합니다. 클라이언트 드라이버를 등록하려면 USBD_CreateHandle 호출하고 계약 버전을 지정합니다. 클라이언트 드라이버가 Windows 8 향상된 기능과 새로운 기능을 빌드, 실행 및 사용하려는 경우 클라이언트 계약 버전이 USBD_CLIENT_CONTRACT_VERSION_602.

USBD_CLIENT_CONTRACT_VERSION_602 버전 클라이언트 드라이버의 경우 USB 드라이버 스택은 클라이언트 드라이버가 다음 규칙 집합을 준수한다고 가정합니다.

USB 드라이버 스택은 수신된 요청에 대한 유효성 검사를 수행하고 가능한 한 위반을 처리합니다. 이렇게 하지 않으면 정의되지 않은 동작이 발생할 수 있습니다.

부실 또는 잘못된 파이프 핸들을 사용하여 I/O 요청을 보내지 마세요.

클라이언트 드라이버는 부실 파이프 핸들을 사용하여 USB 드라이버 스택에 I/O 요청을 보내면 됩니다. 부실 파이프 핸들은 더 이상 디바이스에서 선택되지 않는 구성, 인터페이스 또는 대체 설정을 선택하라는 요청에서 가져온 파이프 핸들을 나타냅니다. 부실 파이프 핸들을 방지하려면 클라이언트 드라이버가 구성 또는 인터페이스를 선택할 때마다 드라이버는 파이프 핸들의 캐시를 새로 고쳐야 합니다(일반적으로 디바이스 컨텍스트에 저장됨). 특정 경합 조건으로 인해 부실 파이프 핸들이 발생할 수도 있습니다. instance 경우 클라이언트 드라이버는 선택한 인터페이스의 파이프 핸들을 사용하여 I/O 요청을 보냅니다. 요청이 완료되기 전에 클라이언트 드라이버는 사용 중인 파이프 핸들과 연결된 동일한 엔드포인트를 사용하지 않는 대체 설정을 선택합니다. 보류 중인 두 요청은 모두 경합 상태로 인해 파이프 핸들이 유효하지 않을 수 있습니다.

Windows 8 할당 루틴을 호출하여 URL 할당

Windows 8 URL(USB 요청 블록)을 할당, 빌드 및 해제하기 위한 새로운 루틴을 제공합니다. URL을 할당하려면 WDM(Windows 드라이버 모델) 클라이언트 드라이버는 항상 다음 목록에 표시된 새 루틴을 사용해야 합니다.

이전 목록의 루틴은 추적 및 처리를 개선하기 위해 할당된 URB에 불투명 URB 컨텍스트를 연결할 수 있습니다. 클라이언트 드라이버는 URB 컨텍스트의 내용을 보거나 수정할 수 없습니다. Windows 8 URB 할당에 대한 자세한 내용은 URL 할당 및 빌드를 참조하세요.

등록 중에 해당 버전을 USBD_CLIENT_CONTRACT_VERSION_602 식별하는 WDF(Windows Driver Framework) 클라이언트 드라이버( WdfUsbTargetDeviceCreateWithParameters 참조)의 경우 USB 드라이버 스택은 클라이언트 드라이버가 새 WdfUsbTargetDeviceCreateUrb를 호출하여 URB에 대한 메모리를 할당할 것으로 예상합니다.

보류 중인 요청과 연결된 활성 URL을 다시 사용하지 마세요.

USB 드라이버 스택은 URB와 연결된 요청 전에 다시 제출된 활성 URB가 감지되면 의도적으로 버그 검사를 합니다. URB는 요청이 보류 중이고 클라이언트 드라이버의 IRP 완료 루틴이 호출되지 않은 한 활성화됩니다. 활성 URB에서 다음 작업을 수행하지 마세요.

  • 다른 요청에 대해 활성 URB를 다시 제출 하지 마세요(URB를 다른 IRP와 연결).
  • 활성 URB의 내용을 수정 하지 마세요.
  • 활성 URB를 해제 하지 마세요.

클라이언트 드라이버의 완료 루틴이 호출되면 드라이버는 완료 루틴 내에서 특정 유형의 요청에 대한 URL을 다시 제출할 수 있습니다. 재제출에는 다음 규칙이 적용됩니다.

  • 클라이언트 드라이버는 select-configuration 요청 이외의 모든 유형의 요청에 대해 USBD_SelectConfigUrbAllocateAndBuild 의해 할당된 URB를 다시 사용하여 동일한 구성을 선택해서는 안됩니다.

  • 클라이언트 드라이버는 USBD_SelectInterfaceUrbAllocateAndBuild 의해 할당된 URB select-interface 요청 이외의 모든 유형의 요청에 다시 사용하여 인터페이스에서 동일한 대체 설정을 선택해서는 안 됩니다. 예제는 USBD_SelectInterfaceUrbAllocateAndBuild 설명을 참조하세요.

  • USBD_IsochUrbAllocate 의해 할당된 URB는 등시 전송 요청에 대해서만 다시 사용해야 합니다. 반대로 다른 유형의 I/O 요청(제어, 대량 또는 인터럽트)에 할당된 URB는 등시 요청에 사용하면 안 됩니다.

    instance 경우 클라이언트 드라이버는 대량 전송 요청에 대한 URB 구조를 할당하고 빌드합니다. 또한 클라이언트 드라이버는 디바이스의 등시 엔드포인트에 데이터를 보내려고 합니다. 대량 전송 요청이 완료되면 클라이언트 드라이버는 등시 요청에 대한 URB를 다시 포맷하고 제출 해서는 안 됩니다. 이는 등시 요청과 연결된 URB가 패킷 수에 따라 길이가 가변적이기 때문입니다. 또한 프레임 경계에서 시작 및 종료하려면 패킷이 필요합니다. 할당된 URB(대량 전송용)가 등시 전송에 필요한 버퍼 레이아웃에 맞지 않을 수 있으며 요청이 실패할 수 있습니다.

  • USBD_UrbAllocate 의해 할당된 URB는 등시성, select-configuration 또는 select-interface 요청에 다시 사용해서는 안 됩니다. 디바이스에서 선택한 구성을 사용하지 않도록 설정하기 위해 NULL 구성을 선택하는 데 URB를 다시 사용할 수 있습니다. URB는 활성화되어 있지 않아야 하며 클라이언트 드라이버는 UsbBuildSelectConfigurationRequest 매크로를 호출하고 ConfigurationDescriptor 매개 변수에서 NULL을 전달하여 URB의 서식을 다시 지정해야 합니다.

  • URB를 다시 제출하기 전에 클라이언트 드라이버는 요청 유형에 대해 정의된 적절한 UsbBuildXxx 매크로를 사용하여 URB의 서식을 다시 지정해야 합니다. USB 스택이 일부 콘텐츠를 변경했을 수 있으므로 드라이버에서 URB의 서식을 지정하는 것이 중요합니다.

    instance 경우 드라이버가 UsbBuildInterruptOrBulkTransferRequest를 호출하여 대량 전송 요청에 대한 URB를 초기화한다고 가정합니다(_URB_BULK_OR_INTERRUPT_TRANSFER 참조). 드라이버가 URB 구조의 TransferBufferMDL 멤버를 NULL로 초기화하는 경우 USB 드라이버 스택은 에서 지정된 TransferBuffer 전송 버퍼를 사용하여 MDL 대신 디바이스와 데이터를 교환합니다. 그러나 내부적으로 USB 드라이버 스택은 MDL을 만들고, TransferBufferMDL에 MDL에 대한 포인터를 저장하고, MDL을 사용하여 데이터를 스택 아래로 전달할 수 있습니다. USB 드라이버 스택이 MDL 메모리를 해제하더라도 클라이언트 드라이버가 완료 루틴에서 URB를 처리할 때 TransferBufferMDL 은 NULL이 아닐 수 있습니다. URB의 멤버의 형식이 올바르게 지정되도록 하려면 드라이버가 UsbBuildInterruptOrBulkTransferRequest 를 다시 호출하여 요청을 제출하기 전에 URB를 다시 포맷해야 합니다.

고속 및 SuperSpeed 등시 전송에는 8보다 큰 폴링 기간을 사용하지 마세요.

USB 드라이버 스택은 폴링 기간 번호가 1, 2, 4 또는 8인 고속 및 SuperSpeed 등시 파이프를 지원합니다. 클라이언트 드라이버는 기간이 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 디바이스에 요청 보내기