함수 컨트롤러 클라이언트 드라이버 작성

이 문서에서는 UFX(USB 함수 컨트롤러 확장)와 상호 작용하는 동안 함수 컨트롤러 클라이언트 드라이버가 수행하는 다양한 작업에 대해 설명합니다.

중요 API

UFX(USB 함수 컨트롤러 확장)와 상호 작용하는 동안 함수 컨트롤러 클라이언트 드라이버가 수행하는 다양한 작업을 설명합니다. UFX와 클라이언트 드라이버는 내보내기 메서드 및 이벤트 콜백 함수를 사용하여 서로 통신합니다. 내보내기 메서드( UfxDeviceXxx 또는 UfxEndpointXxx라는 이름)는 UFX에서 내보내고 클라이언트 드라이버에서 호출합니다. 콜백 함수( EVT_UFX_Xxx)는 클라이언트 드라이버에서 구현되고 UFX에서 호출됩니다.

UFX는 모든 클라이언트 드라이버의 콜백 함수를 비동기적으로 호출하고 개체당 한 번에 하나의 콜백을 호출합니다. 예를 들어 USB 디바이스 개체와 세 개의 엔드포인트 개체가 있습니다. 최대 4개의 콜백 함수(디바이스용 및 각 엔드포인트에 대해 하나씩)가 한 번에 호출될 수 있습니다. 각 콜백 메서드에 대해 UFX는 클라이언트 드라이버가 UfxDeviceEventComplete 를 호출하여 드라이버가 요청을 완료했음을 나타낼 때까지 기다립니다. 이러한 내보내기를 기다리는 동안 UFX가 수신 대기하는 유일한 내보내기 방법은 UfxDeviceNotifyHardwareFailure입니다. 많은 클라이언트 콜백 함수는 선택 사항입니다. 필수 함수는 다음과 같습니다.

초기화

  1. 함수 컨트롤러 클라이언트 드라이버는 WDF(Windows Driver Foundation)가 클라이언트 드라이버의 EVT_WDF_DRIVER_DEVICE_ADD 콜백 구현을 호출할 때 초기화 프로세스를 시작합니다. 이 구현에서 클라이언트 드라이버는 UfxFdoInit 를 호출한 다음 WdfDeviceCreate를 호출하여 디바이스 개체를 만들어야 합니다.
  2. 클라이언트 드라이버는 UfxDeviceCreate 를 호출하여 USB 디바이스 개체를 만들고 UFXDEVICE 핸들을 검색합니다.
  3. 클라이언트 드라이버는 UfxDeviceNotifyHardwareReady 를 호출하여 이제 클라이언트 드라이버의 콜백 함수를 호출할 수 있음을 UFX에 나타냅니다.
  4. UFX는 다음과 같은 초기화 작업을 수행합니다.
    • UFX는 클라이언트 드라이버의 EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD 구현을 호출하여 기본 엔드포인트를 만듭니다.
    • UFX는 디바이스에서 지원하는 인터페이스에 대한 자식 PDO(물리적 디바이스 개체)를 만듭니다.
    • UFX는 IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS 요청을 보낼 때 디바이스 클래스 드라이버 활성화를 기다립니다. 또한 클라이언트 드라이버가 디바이스가 연결되었음을 나타내는 UfxDeviceNotifyAttach 를 호출할 때까지 기다립니다.

클래스 드라이버 알림

설치 패킷 및 버스의 상태 알리려면 클래스 드라이버가 IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS 요청을 보내야 합니다. UFX는 이러한 요청을 클래스 드라이버별 알림 큐에 큐에 넣습니다. 클라이언트 드라이버에서 버스 이벤트에 대한 알림을 받으면 UFX가 각 적절한 큐에서 팝업되고 요청을 완료합니다. 클래스 드라이버에 알림이 누락되지 않도록 UFX는 클래스 드라이버에 대한 고정 크기 알림 큐를 유지합니다.

디바이스 연결 및 분리 이벤트

UFX는 함수 컨트롤러 클라이언트 드라이버가 UfxDeviceNotifyAttach를 호출할 때까지 디바이스가 분리된 것으로 가정합니다.

이 호출 후 UFX는 USB 사양에 정의된 대로 디바이스 상태를 전원 으로 설정합니다. 상태 변경에 대해 클라이언트 드라이버에 알리기 위해 UFX는 클라이언트 드라이버의 EVT_UFX_DEVICE_USB_STATE_CHANGE 구현을 호출합니다.

UFX는 충전기 드라이버(Cad.sys)에게 디바이스 충전을 지원하도록 알 수 있습니다. 또한 UFX는 클래스 드라이버에서 이전에 보낸 IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION 요청을 완료하여 클래스 드라이버에 알 수 있습니다.

클라이언트 드라이버는 버스가 분리될 때 UfxDeviceNotifyDetach 를 호출해야 합니다. 클라이언트는 UfxDeviceNotifyAttach를 호출할 때마다 분리를 한 번만 호출해야 합니다. UfxDeviceNotifyDetach 호출 후 UFX는 EVT_UFX_DEVICE_HOST_DISCONNECT 호출합니다(인터페이스 변경이 아닌 경우). 그런 다음 UFX는 모든 엔드포인트 큐 제거 및 기본 엔드포인트 큐 시작과 같은 모든 클린 작업을 진행합니다. UFX는 EVT_UFX_DEVICE_USB_STATE_CHANGE 호출하고 IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION 요청을 완료하여 클래스 드라이버에 알립니다.

하드웨어 오류

하드웨어 오류가 발생하면 클라이언트 드라이버가 UfxDeviceNotifyHardwareFailure를 호출해야 합니다. 이에 대한 응답으로 UFX는 디바이스 스택을 해체하고 클라이언트 드라이버의 EVT_UFX_DEVICE_CONTROLLER_RESET 호출하여 이 상황에서 복구하려고 시도할 수 있습니다. 클라이언트는 컨트롤러를 초기 상태로 다시 설정해야 합니다. 다른 하드웨어 오류가 발생하는 경우 클라이언트는 UfxDeviceNotifyHardwareFailure를 다시 호출해야 합니다. 두 번째 호출에서 UFX는 상태 및 버그 검사 기록합니다.

포트 검색

포트 검색은 UFX에 의해 수행됩니다. 함수 컨트롤러 클라이언트 드라이버의 EVT_UFX_DEVICE_PORT_DETECT 콜백 함수를 호출하여 디바이스가 연결된 포트 유형을 확인합니다. 클라이언트는 USBFN_PORT_TYPE 정의된 포트 유형 중 하나를 사용하여 UfxDevicePortDetectComplete 또는 UfxDevicePortDetectCompleteEx를 호출하여 응답합니다.

클라이언트가 포트 유형을 확인할 수 없는 경우 클라이언트는 UsbfnUnknownPort를 보고해야 합니다. 포트를 알 수 없거나 다운스트림 포트인 경우 UFX는 클라이언트 드라이버의 EVT_UFX_DEVICE_HOST_CONNECT 함수를 호출합니다. UFX는 일정 시간 동안 버스를 수신 대기합니다. 포트를 알 수 없지만 설치 패킷과 같은 트래픽이 있는 경우 UFX는 UsbfnStandardDownstreamPort를 가정합니다. 그렇지 않으면 UFX는 포트를 UsbfnInvalidDedicatedChargingPort로 할당합니다. 포트 유형이 결정되면 UFX는 Cad.sys 알리고 클라이언트 드라이버의 EVT_UFX_DEVICE_PORT_CHANGE 함수를 호출합니다. 함수에서 클라이언트 드라이버는 UFX 포트 유형과 일치하도록 하드웨어 상태를 변경해야 합니다.

엔드포인트 만들기

UFX는 호스트에서 보낸 설정 패킷을 처리할 수 있도록 클라이언트 드라이버의 EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD 호출하여 기본 엔드포인트(엔드포인트 0)를 만듭니다. UFX는 EVT_UFX_DEVICE_ENDPOINT_ADD 호출하여 다른 엔드포인트를 만듭니다. UFX는 클라이언트 드라이버가 UfxDeviceNotifyHardwareReady를 호출한 후에만 엔드포인트를 만듭니다. 이러한 콜백 함수에서 클라이언트 드라이버는 UfxEndpointCreate 를 엔드포인트 개체에 호출하고 해당 UFXENDPOINT 핸들을 가져와야 합니다. UFX는 부모를 엔드포인트가 속한 인터페이스와 연결된 클래스 드라이버 PDO로 설정합니다. 기본 엔드포인트의 부모는 USB 디바이스 개체입니다. 엔드포인트에는 전송 큐와 명령 큐라는 두 개의 프레임워크 큐 개체가 포함되며, 둘 다 디바이스가 구성된 상태일 때만 액세스할 수 있습니다(UFX 호출 EVT_UFX_DEVICE_HOST_CONNECT 후에 액세스할 수 있는 Endpoint 0 제외).

디바이스 열거형

클라이언트 드라이버는 UFX가 드라이버의 EVT_UFX_DEVICE_HOST_CONNECT 호출하기 전에 호스트에 대한 연결을 허용해서는 안 됩니다. 디바이스 열거형은 클라이언트 드라이버가 UfxDeviceNotifyReset을 호출할 때 시작됩니다. 기본 상태에서 UFX는 표준 설정 패킷을 처리합니다.

다시 설정

UFX는 모든 엔드포인트 큐를 제거하고 클라이언트 드라이버에 IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE 요청을 보내 엔드포인트 0의 wMaxPacketSize 를 업데이트합니다. UFX는 기본 엔드포인트의 큐를 시작하고 상태를 Default로 설정합니다.

Default

UFX는 클라이언트 드라이버의 EVT_UFX_DEVICE_USB_STATE_CHANGE 함수를 호출합니다. 또한 상태의 클래스 드라이버를 알 수 있습니다. UFX가 SET_ADDRESS 표준 설정 패킷을 받으면 UFX는 상태를 Addressed로 설정합니다.

해결

UFX는 클라이언트 드라이버의 EVT_UFX_DEVICE_ADDRESSED 함수를 호출하여 클라이언트에 사용해야 하는 주소를 나타냅니다. - 주소가 0이면 UFX는 상태를 다시 Default 로 설정하고 EVT_UFX_DEVICE_USB_STATE_CHANGE 호출하고 클래스 드라이버에 알 수 있습니다. SET_CONFIGURATION 표준 설정 패킷을 받으면 UFX는 상태를 구성됨으로 설정합니다.

구성됨

선택한 구성이 0이면 UFX는 인터페이스 엔드포인트를 제거하고 상태를 Addressed로 설정합니다. UFX는 클라이언트 드라이버에 IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE 요청을 보내 인터페이스 엔드포인트의 wMaxPacketSize 를 업데이트합니다. UFX는 모든 인터페이스 엔드포인트 큐가 제거를 완료하고 인터페이스 엔드포인트 큐를 시작했는지 확인합니다. 포트 유형이 UsbfnStandardDownstreamPort 또는 UsbfnChargingDownstreamPort가 아닌 경우 UFX는 포트 유형을 UsbfnStandardDownstreamPort 로 변경하고 Cad.sys 알려줍니다. EVT_UFX_DEVICE_PORT_CHANGE호출하여 클라이언트 드라이버를 EVT_UFX_DEVICE_USB_STATE_CHANGE 상태를 업데이트합니다. 구성된 상태의 클래스 드라이버입니다.

표준 제어 전송

UFX는 클라이언트 드라이버가 를 사용하여 기본 엔드포인트를 만드는 EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD 호출한 후 언제든지 기본 엔드포인트에서 제어 전송을 처리할 수 있습니다. 모든 컨트롤 전송은 8 바이트 설정 패킷으로 시작합니다. 호스트에 설치 패킷을 보내려면 클라이언트 드라이버가 UfxEndpointNotifySetup을 호출해야 합니다. 표준 제어 전송은 UFX에 의해 완료됩니다. 컨트롤 전송과 연결된 데이터가 있는 경우 UFX는 에서 를 읽고 기본 컨트롤 엔드포인트에 적절하게 씁니다.

비표준 제어 전송

UFX가 컨트롤 전송을 처리할 수 없는 경우 전송은 IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION 요청을 완료하여 적절한 클래스 드라이버로 전달됩니다. 컨트롤 전송은 엔드포인트 설명자의 컨트롤 엔드포인트로 정의된 모든 엔드포인트에서 발생할 수 있습니다. 기본 컨트롤 엔드포인트가 아닌 엔드포인트의 컨트롤 전송은 항상 비표준 제어 전송입니다. 컨트롤 엔드포인트가 기본 컨트롤 엔드포인트인 경우 UFX는 클래스 드라이버에 대한 클래스 요청으로 표시된 설치 패킷의 클래스 드라이버에 알립니다. 컨트롤 엔드포인트가 인터페이스에 속하는 경우 UFX는 해당 인터페이스와 연결된 클래스 드라이버를 알 수 있습니다. 필요한 경우 클래스 드라이버는 컨트롤 엔드포인트에서 읽고 컨트롤 엔드포인트에 기록해야 합니다.

데이터 전송

데이터 전송은 클래스 드라이버에서 IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT 또는 IOCTL_INTERNAL_USBFN_TRANSFER_OUT 요청을 전송하여 시작됩니다. 이러한 각 요청의 유효성을 검사한 후 UFX는 클라이언트 드라이버에서 처리할 적절한 엔드포인트 큐에 전달합니다. 클라이언트 드라이버는 추가 유효성 검사를 수행해야 합니다. 클라이언트 드라이버는 엔드포인트 큐에서 전송 요청을 받습니다. 클라이언트 드라이버는 버스 사용률을 최대화하는 데 필요한 만큼 이 큐에서 요청을 검색할 수 있습니다. 클라이언트 드라이버는 STATUS_SUCCESS 사용하여 성공적인 요청을 완료해야 합니다. 드라이버는 요청을 취소하고 취소된 경우 STATUS_CANCELLED 취소된 요청을 완료하기 위해 최선을 다해야 합니다. 잘못된 매개 변수가 전달되면 클라이언트 드라이버는 STATUS_INVALID_PARAMETER 사용하여 요청을 완료합니다.

제어 전송

제어 전송은 8 바이트 설정 패킷으로 시작합니다. 호스트에 설치 패킷을 보내려면 클라이언트 드라이버가 UfxEndpointNotifySetup을 호출해야 합니다. UFX는 알림 요청을 완료하여 클래스 드라이버에 비표준 제어 전송을 알 수 있습니다. 클라이언트와 UFX는 모두 IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT 또는 IOCTL_INTERNAL_USBFN_TRANSFER_OUT 사용하여 기본 컨트롤 엔드포인트에서 읽고 씁니다. 그러나 인터페이스는 해당 클래스 드라이버만 사용할 수 있는 다른 컨트롤 엔드포인트를 정의할 수 있습니다. 설정 패킷에 대한 응답으로 제어 엔드포인트가 중단될 수 있습니다. 클래스 드라이버는 엔드포인트를 중단하기 위해 IOCTL_INTERNAL_USBFN_SET_PIPE_STATE 요청을 보냅니다. 하드웨어 또는 클라이언트 드라이버는 중단이 전송된 후 엔드포인트에서 트래픽을 즉시 다시 시작할 것으로 예상됩니다. 컨트롤 엔드포인트는 이전 데이터 없이 ZLP(길이가 0인 패킷)를 보내고 받을 수도 있습니다. 클라이언트 드라이버와 UFX는 IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_INIOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT 사용하여 이 작업을 수행할 수 있습니다.

대량 및 인터럽트 전송

대량 전송은 데이터 배달을 보장하며 대량의 데이터를 보내는 데 사용됩니다. IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT 또는IOCTL_INTERNAL_USBFN_TRANSFER_OUT 사용하여 대량 엔드포인트에서 전송을 보낼 수 있습니다. 대량 엔드포인트는 IOCTL_INTERNAL_USBFN_SET_PIPE_STATE 사용하여 엔드포인트를 제어하는 것과 유사하게 중단될 수 있습니다. 클라이언트 드라이버는 모든 호스트 요청에 대한 응답으로 STALL 패킷을 보내고 IOCTL 요청을 보유해야 합니다. 제어 엔드포인트와 달리 중단된 대량 엔드포인트는 중단 상태가 명시적으로 지워지게 될 때까지 중단된 상태로 유지됩니다.

인터럽트 전송 인터럽트 전송은 대량 전송과 비슷하지만 대기 시간이 보장됩니다. 인터럽트 전송에는 대량 전송과 동일한 인터페이스가 있지만 스트리밍 기능이 없습니다.

등시 전송

클라이언트 드라이버는 이 버전에서 등시 전송을 지원하지 않을 것으로 예상됩니다.

전원 관리

클라이언트 드라이버는 전원 관리의 모든 측면을 소유합니다. 콜백 함수는 비동기적이므로 클라이언트 드라이버는 적절한 전원 상태로 돌아와서 UfxDeviceEventComplete와 같은 적절한 이벤트 완료 내보내기 함수를 호출하기 전에 요청을 완료해야 합니다.

디바이스 상태( USBFN_DEVICE_STATE 정의됨)가 UsbfnDeviceStateSuspendedUsbfnDeviceStateAttached이고 포트 유형을 보고하지 않은 경우 UFX는 작업 상태입니다. 또는 UFX는 포트 유형( USBFN_PORT_TYPE 정의됨) UsbfnStandardDownstreamPort 또는 UsbfnChargingDownstreamPort를 보고했습니다.

UFX는 EVT_UFX_DEVICE_USB_STATE_CHANGE 또는EVT_UFX_DEVICE_PORT_CHANGE 구현을 호출하여 작업 상태를 입력하고 종료합니다. 클라이언트 드라이버가 UfxDeviceEventComplete를 호출하면 작업 상태로 또는 작업 상태에서의 전환이 완료됩니다.

작업 상태에서 UFX는 모든 콜백을 호출할 수 있습니다. 작업 상태가 아닌 동안 UFX는 EVT_UFX_DEVICE_USB_STATE_CHANGE 호출하여 작업 상태로 들어갑니다. EVT_UFX_DEVICE_REMOTE_WAKEUP_SIGNAL 일시 중단 중에 원격 절전 모드 해제를 실행합니다(지원되는 경우).

디바이스 일시 중단

3밀리초 동안 버스에 트래픽이 없을 때 디바이스 일시 중단이 발생합니다. 이 경우 클라이언트 드라이버는 UfxDeviceNotifySuspend 및 UfxDeviceNotifyResume 를 호출하여 일시 중단 및 다시 시작을 감지할 때 UFX에 알려야 합니다. 이러한 호출을 받으면 UFX는 EVT_UFX_DEVICE_USB_STATE_CHANGE 호출하고 IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION 요청을 완료하여 클래스 드라이버에 알 수 있습니다. 디바이스에서 원격 절전 모드 해제를 지원하고 호스트에서 사용하도록 설정한 경우 UFX는 일시 중단된 동안 EVT_UFX_DEVICE_USB_STATE_CHANGE 호출을 호출하여 원격 절전 모드 해제 신호를 실행할 수 있습니다.