내 연락처 정보
우편메소피아@프로톤메일.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
USB 2.0 및 이전 장치에서 대량 끝점은 끝점을 통해 단일 데이터 스트림을 보내거나 받을 수 있습니다. USB 3.0 장치에서 벌크 엔드포인트는 엔드포인트를 통해 여러 데이터 스트림을 보내고 받을 수 있습니다.
Windows에서 Microsoft가 제공하는 USB 드라이버 스택은 다중 스트림을 지원합니다. 이를 통해 클라이언트 드라이버는 요청을 다른 스트림에 직렬화하지 않고도 USB 3.0 장치의 대량 끝점과 연결된 각 스트림에 독립적인 I/O 요청을 보낼 수 있습니다.
클라이언트 드라이버에게 스트림은 동일한 특성 집합을 가진 여러 논리적 끝점을 나타냅니다. 특정 스트림으로 요청을 보내려면 클라이언트 드라이버에 해당 스트림에 대한 핸들이 필요합니다(엔드포인트의 파이프 핸들과 유사). 스트리밍 I/O 요청용 URB는 대량 엔드포인트에 대한 I/O 요청용 URB와 유사합니다. 유일한 차이점은 파이프 핸들입니다. I/O 요청을 스트림으로 보내기 위해 드라이버는 스트림에 파이프 핸들을 지정합니다.
장치 구성 중에 클라이언트 드라이버는 구성 선택 요청을 보내고 선택적으로 인터페이스 선택 요청도 보냅니다. 이러한 요청은 인터페이스의 활동 설정에 정의된 엔드포인트에 대한 파이프 핸들 세트를 검색합니다. 스트림 인식 끝점의 경우 끝점 파이프 핸들을 사용하여 드라이버가 스트림을 열 때까지 기본 스트림(첫 번째 스트림)에 I/O 요청을 보낼 수 있습니다.
클라이언트 드라이버가 기본 스트림이 아닌 스트림에 요청을 보내려는 경우 드라이버는 모든 스트림에 대한 핸들을 열고 얻어야 합니다. 이를 위해 클라이언트 드라이버는 열려는 스트림 수를 지정하여 스트림 열기 요청을 보냅니다. 클라이언트 드라이버가 스트림 사용을 마친 후 드라이버는 스트림 닫기 요청을 보내 스트림을 닫도록 선택할 수 있습니다.
KMDF(커널 모드 드라이버 프레임워크)는 기본적으로 정적 스트림을 지원하지 않습니다. 클라이언트 드라이버는 WDM(Windows 드라이버 모델)을 사용하여 스트림을 열고 닫아야 합니다. UMDF(사용자 모드 드라이버 프레임워크) 클라이언트 드라이버는 정적 스트리밍 기능을 사용할 수 없습니다.
다음에는 WDM 드라이버라고 표시된 일부 설명이 포함될 수 있습니다. 이 지침은 스트리밍 요청을 보내려는 WDM 기반 USB 클라이언트 드라이버에 대한 루틴을 설명합니다.
클라이언트 드라이버가 스트림을 열거나 닫으려면 먼저 드라이버에 다음이 있어야 합니다.
1. WdfUsbTargetDeviceCreateWithParameters 메서드를 호출합니다. 방법에는 USBD_CLIENT_CONTRACT_VERSION_602 클라이언트 프로토콜 버전이 필요합니다. 이 버전을 지정하면 클라이언트 드라이버가 일련의 규칙을 준수해야 합니다.
프레임워크의 USB 대상 장치 개체의 WDFUSBDEVICE 핸들을 검색하기 위해 호출합니다. 오픈 스트림에 대한 후속 호출에는 핸들이 필요합니다. 일반적으로 클라이언트 드라이버는 드라이버의 EVT_WDF_DEVICE_PREPARE_HARDWARE 이벤트 콜백 루틴에 자신을 등록합니다.
WDM 드라이버: USBD_CreateHandle 루틴을 호출하고 USB 드라이버 스택의 드라이버에 의해 등록된 USBD 핸들을 얻습니다.
2. 장치를 구성하고 스트리밍을 지원하는 벌크 엔드포인트에 대한 WDFUSBPIPE 파이프 핸들을 얻었습니다. 파이프 핸들을 얻으려면 선택한 구성에 있는 인터페이스의 현재 대체 설정에서 WdfUsbInterfaceGetConfiguredPipe 메소드를 호출하십시오.
WDM 드라이버: 선택 구성 또는 선택 인터페이스 요청을 보내 USBD 파이프 핸들을 얻습니다.
1. WdfUsbTargetDeviceQueryUsbCapability 메서드를 호출하여 기본 USB 드라이버 스택과 호스트 컨트롤러가 정적 스트리밍 기능을 지원하는지 확인합니다. 일반적으로 클라이언트 드라이버는 드라이버의 EVT_WDF_DEVICE_PREPARE_HARDWARE 이벤트 콜백 루틴에서 루틴을 호출합니다.
WDM 드라이버: USBD_QueryUsbCapability 루틴을 호출합니다. 일반적으로 드라이버는 드라이버의 시작 장치 루틴(IRP_MN_START_DEVICE)에서 사용할 함수를 쿼리합니다.
다음 정보를 제공하세요.
WDM 드라이버: 이전 호출에서 검색된 USBD 핸들을 USBD_CreateHandle에 전달합니다.
클라이언트 드라이버가 특정 기능을 사용하려는 경우 드라이버는 먼저 기본 USB 드라이버 스택을 쿼리하여 드라이버 스택과 호스트 컨트롤러가 해당 기능을 지원하는지 확인해야 합니다. 기능이 지원되는 경우에만 드라이버가 기능 사용 요청을 보내야 합니다. 특정 요청에는 5단계에서 설명한 스트리밍 기능과 같은 URB가 필요합니다. 이러한 요청의 경우 동일한 핸들을 사용하여 함수를 쿼리하고 URB를 할당해야 합니다. 이는 드라이버 스택이 핸들을 사용하여 드라이버가 사용할 수 있는 지원 기능을 추적하기 때문입니다.
예를 들어 USBD_CreateHandle을 호출하여 USBD_HANDLE을 얻은 경우 USBD_QueryUsbCapability를 호출하여 드라이버 스택을 쿼리하고 USBD_UrbAllocate를 호출하여 URB를 할당합니다. 두 호출 모두에서 동일한 USBD_HANDLE을 전달합니다.
KMDF 메서드, WdfUsbTargetDeviceQueryUsbCapability 및 WdfUsbTargetDeviceCreateUrb를 호출하는 경우 이러한 메서드 호출에서 프레임워크 대상 개체에 대해 동일한 WDFUSBDEVICE 핸들을 지정합니다.
2. 반환된 NTSTATUS 값을 평가합니다. 루틴이 성공적으로 완료되면 STATUS_SUCCESS가 반환되고 정적 스트리밍 기능이 지원됩니다. 그렇지 않으면 메서드는 적절한 오류 코드를 반환합니다.
3. 열려는 스트림 수를 결정합니다. 열 수 있는 최대 스트림 수는 다음과 같이 제한됩니다.
최대 흐름 수를 결정하려면 호스트 컨트롤러와 엔드포인트에서 지원하는 두 값 중 더 작은 값을 선택하세요.
4. n 요소 USBD_STREAM_INFORMATION 구조의 배열을 할당합니다. 여기서 n은 열려는 스트림 수입니다. 클라이언트 드라이버는 드라이버가 스트림 사용을 마친 후 이 배열을 해제해야 합니다.
5. WdfUsbTargetDeviceCreateUrb 메소드를 호출하여 오픈 스트림 요청에 대한 URB를 할당합니다. 호출이 성공적으로 완료되면 메서드는 WDF 메모리 개체와 USB 드라이버 스택에 의해 할당된 URB 구조의 주소를 검색합니다.
WDM 드라이버: USBD_UrbAllocate 루틴을 호출합니다.
6. 오픈 스트림 요청의 URB 형식을 설정합니다. URB는 _URB_OPEN_STATIC_STREAMS 구조를 사용하여 요청을 정의합니다. URB를 포맷하려면 다음이 필요합니다.
URB의 형식을 지정하려면 UsbBuildOpenStaticStreamsRequest를 호출하고 필수 정보를 매개변수 값으로 전달합니다. UsbBuildOpenStaticStreamsRequest에 지정된 스트림 수가 지원되는 최대 스트림 수를 초과하지 않는지 확인하십시오.
7. WdfRequestSend 메소드를 호출하여 URB를 WDF 요청 객체로 보냅니다. 요청을 동기적으로 보내려면 대신 WdfUsbTargetDeviceSendUrbSynchronously 메서드를 호출하세요.
WDM 드라이버: URB를 IRP와 연결하고 IRP를 USB 드라이버 스택에 제출합니다.
8. 요청이 완료된 후 요청 상태를 확인하세요.USB 드라이버 스택 요청이 실패하면 URB 상태에 관련 오류 코드가 포함됩니다.
요청(IRP 또는 WDF 요청 개체) 상태가 USBD_STATUS_SUCCESS를 나타내면 요청이 성공적으로 완료된 것입니다. 확인이 완료되면 수신된 USBD_STREAM_INFORMATION 구조의 배열입니다. 배열은 요청된 스트림에 대한 정보로 채워집니다. USB 드라이버 스택은 USBD_PIPE_HANDLE 수신 핸들, 스트림 식별자 및 최대 숫자 전송 크기와 같은 스트림 정보로 배열의 각 구조를 채웁니다. 이제 스트림에서 데이터를 전송할 수 있습니다.
오픈 스트림 요청의 경우 URB 및 어레이를 할당해야 합니다. 오픈 스트림 요청이 완료된 후 클라이언트 드라이버는 연관된 WDF 메모리 개체에 대해 WdfObjectDelete 메서드를 호출하여 URB를 해제해야 합니다. 드라이버가 WdfUsbTargetDeviceSendUrbSynchronously를 호출하여 요청을 동기적으로 보내는 경우 WDF 메모리 개체는 메서드가 반환된 후 해제되어야 합니다. 클라이언트 드라이버가 WdfRequestSend를 호출하여 비동기적으로 요청을 보내는 경우 드라이버는 요청과 관련된 드라이버 구현 완료 루틴에서 WDF 메모리 개체를 해제해야 합니다.
클라이언트 드라이버가 스트림 사용을 마친 후 스트림 배열을 해제하거나 I/O 요청을 위해 저장할 수 있습니다. 아래에 포함된 코드 예제에서 드라이버는 장치 컨텍스트에 스트림 배열을 저장합니다. 드라이버는 장치 개체를 해제하기 전에 장치 컨텍스트를 해제합니다.
특정 스트림으로 데이터를 전송하는 방법
특정 스트림으로 데이터 전송 요청을 보내려면 WDF 요청 개체가 필요합니다. 일반적으로 클라이언트 드라이버는 WDF 요청 개체를 할당할 필요가 없습니다. I/O 관리자가 애플리케이션으로부터 요청을 받으면 I/O 관리자는 해당 요청에 대한 IRP를 생성합니다. IRP가 프레임워크에 의해 차단되었습니다. 그런 다음 프레임워크는 IRP를 나타내기 위해 WDF 요청 개체를 할당합니다. 그 후 프레임워크는 WDF 요청 개체를 클라이언트 드라이버에 전달합니다. 그런 다음 클라이언트 드라이버는 요청 개체를 데이터 전송 URB와 연결하고 이를 USB 드라이버 스택으로 보낼 수 있습니다.
클라이언트 드라이버가 프레임워크로부터 WDF 요청 개체를 수신하지 않고 요청을 비동기적으로 보내려는 경우 드라이버는 WdfRequestCreate 메서드를 호출하여 WDF 요청 개체를 할당해야 합니다. WdfUsbTargetPipeFormatRequestForUrb를 호출하여 새 객체의 형식을 지정하고 WdfRequestSend를 호출하여 요청을 보냅니다.
동기식 경우 WDF 요청 개체 전달은 선택 사항입니다.
데이터를 스트림으로 전송하려면 URB를 사용해야 합니다. URB는 WdfUsbTargetPipeFormatRequestForUrb를 호출하여 형식을 지정해야 합니다.
스트림은 다음 WDF 방법을 지원하지 않습니다.
다음 절차에서는 클라이언트 드라이버가 프레임워크로부터 요청 개체를 수신한다고 가정합니다.
WDM 드라이버: USBD_UrbAllocate를 호출하여 URB를 할당하고 대량 전송을 위해 형식을 지정합니다(_URB_BULK_OR_INTERRUPT_TRANSFER 참조). URB를 포맷하려면 UsbBuildInterruptOrBulkTransferRequest를 호출하거나 URB 구조를 수동으로 포맷하면 됩니다. URB의 UrbBulkOrInterruptTransfer.PipeHandle 멤버에 스트림 핸들을 지정합니다.
클라이언트 드라이버는 스트림 사용을 마친 후 스트림을 닫을 수 있습니다. 그러나 스트리밍 요청을 종료하는 것은 선택 사항입니다. USB 드라이버 스택은 스트림과 연결된 엔드포인트가 구성 해제되면 모든 스트림을 닫습니다. 대체 구성이나 인터페이스를 선택하거나 장치를 삭제하는 등의 경우 엔드포인트가 구성 해제됩니다. 클라이언트 드라이버가 다른 개수의 스트림을 열려고 하면 스트림을 닫아야 합니다. 스트림 닫기 요청을 보냅니다.
1. WdfUsbTargetDeviceCreateUrb를 호출하여 URB 구조를 할당합니다.
2. 스트림 요청을 종료하기 위한 URB 형식을 설정합니다. URB 구조의 UrbPipeRequest 멤버는 _URB_PIPE_REQUEST 구조입니다. 다음과 같이 구성원을 입력합니다.
3. WdfRequestSend 또는 WdfUsbTargetDeviceSendUrbSynchronously를 호출하여 URB를 WDF 요청으로 보냅니다.
닫기 핸들은 클라이언트 드라이버가 이전에 연 모든 스트림을 닫도록 요청합니다. 클라이언트 드라이버는 요청을 사용하여 끝점의 특정 스트림을 닫을 수 없습니다.
USB 드라이버 스택은 수신된 URB에 대해 검증을 수행합니다. 유효성 검사 오류를 방지하려면 다음을 수행하십시오.
경우에 따라 엔드포인트와의 전송이 실패할 수 있습니다. 이러한 실패는 정지 또는 중지 조건과 같은 엔드포인트 또는 호스트 컨트롤러의 오류 조건으로 인해 발생할 수 있습니다. 오류 조건을 지우기 위해 클라이언트 드라이버는 먼저 보류 중인 전송을 취소한 다음 끝점과 연결된 파이프를 재설정합니다. 보류 중인 전송을 취소하려면 클라이언트 드라이버가 중단 파이프 요청을 보낼 수 있습니다. 파이프를 재설정하려면 클라이언트 드라이버가 파이프 재설정 요청을 보내야 합니다.
스트리밍의 경우 대량 엔드포인트와 연결된 개별 스트림에 대해서는 중단 파이프 및 파이프 재설정 요청이 지원되지 않습니다. 특정 스트림 파이프의 전송이 실패하면 호스트 컨트롤러는 다른 스트림에 대한 다른 모든 파이프의 전송을 중지합니다. 오류 조건을 복구하려면 클라이언트 드라이버가 각 스트림으로의 전송을 수동으로 취소해야 합니다. 대량 엔드포인트에 파이프 재설정 요청을 보내기 위한 파이프 핸들. 이 요청의 경우 클라이언트 드라이버는 _URB_PIPE_REQUEST 구조에 엔드포인트의 파이프 핸들을 지정하고 URB 함수(Hdr.Function)를 URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL로 설정해야 합니다.
다음 코드 예제에서는 스트림을 여는 방법을 보여줍니다.
- NTSTATUS
- OpenStreams (
- _In_ WDFDEVICE Device,
- _In_ WDFUSBPIPE Pipe)
- {
- NTSTATUS status;
- PDEVICE_CONTEXT deviceContext;
- PPIPE_CONTEXT pipeContext;
- USHORT cStreams = 0;
- USBD_PIPE_HANDLE usbdPipeHandle;
- WDFMEMORY urbMemory = NULL;
- PURB urb = NULL;
-
- PAGED_CODE();
-
- deviceContext =GetDeviceContext(Device);
- pipeContext = GetPipeContext (Pipe);
-
- if (deviceContext->MaxStreamsController == 0)
- {
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Static streams are not supported.");
-
- status = STATUS_NOT_SUPPORTED;
- goto Exit;
- }
-
- // If static streams are not supported, number of streams supported is zero.
-
- if (pipeContext->MaxStreamsSupported == 0)
- {
- status = STATUS_DEVICE_CONFIGURATION_ERROR;
-
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Static streams are not supported by the endpoint.");
-
- goto Exit;
- }
-
- // Determine the number of streams to open.
- // Compare the number of streams supported by the endpoint with the
- // number of streams supported by the host controller, and choose the
- // lesser of the two values. The deviceContext->MaxStreams value was
- // obtained in a previous call to WdfUsbTargetDeviceQueryUsbCapability
- // that determined whether or not static streams is supported and
- // retrieved the maximum number of streams supported by the
- // host controller. The device context stores the values for IN and OUT
- // endpoints.
-
- // Allocate an array of USBD_STREAM_INFORMATION structures to store handles to streams.
- // The number of elements in the array is the number of streams to open.
- // The code snippet stores the array in its device context.
-
- cStreams = min(deviceContext->MaxStreamsController, pipeContext->MaxStreamsSupported);
-
- // Allocate an array of streams associated with the IN bulk endpoint
- // This array is released in CloseStreams.
-
- pipeContext->StreamInfo = (PUSBD_STREAM_INFORMATION) ExAllocatePoolWithTag (
- NonPagedPool,
- sizeof (USBD_STREAM_INFORMATION) * cStreams,
- USBCLIENT_TAG);
-
- if (pipeContext->StreamInfo == NULL)
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
-
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Could not allocate stream information array.");
-
- goto Exit;
- }
-
- RtlZeroMemory (pipeContext->StreamInfo,
- sizeof (USBD_STREAM_INFORMATION) * cStreams);
-
- // Get USBD pipe handle from the WDF target pipe object. The client driver received the
- // endpoint pipe handles during device configuration.
-
- usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle (Pipe);
-
- // Allocate an URB for the open streams request.
- // WdfUsbTargetDeviceCreateUrb returns the address of the
- // newly allocated URB and the WDFMemory object that
- // contains the URB.
-
- status = WdfUsbTargetDeviceCreateUrb (
- deviceContext->UsbDevice,
- NULL,
- &urbMemory,
- &urb);
-
- if (status != STATUS_SUCCESS)
- {
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Could not allocate URB for an open-streams request.");
-
- goto Exit;
- }
-
- // Format the URB for the open-streams request.
- // The UsbBuildOpenStaticStreamsRequest inline function formats the URB by specifying the
- // pipe handle to the entire bulk endpoint, number of streams to open, and the array of stream structures.
-
- UsbBuildOpenStaticStreamsRequest (
- urb,
- usbdPipeHandle,
- (USHORT)cStreams,
- pipeContext->StreamInfo);
-
- // Send the request synchronously.
- // Upon completion, the USB driver stack populates the array of with handles to streams.
-
- status = WdfUsbTargetPipeSendUrbSynchronously (
- Pipe,
- NULL,
- NULL,
- urb);
-
- if (status != STATUS_SUCCESS)
- {
- goto Exit;
- }
-
- Exit:
- if (urbMemory)
- {
- WdfObjectDelete (urbMemory);
- }
-
- return status;
- }