Driver-Defined 인터페이스 사용

드라이버는 다른 드라이버가 액세스할 수 있는 디바이스별 인터페이스를 정의할 수 있습니다. 이러한 드라이버 정의 인터페이스는 호출 가능한 루틴 집합, 데이터 구조 집합 또는 둘 다로 구성됩니다. 드라이버는 일반적으로 드라이버가 다른 드라이버에서 사용할 수 있도록 하는 드라이버 정의 인터페이스 구조에서 이러한 루틴 및 구조에 대한 포인터를 제공합니다.

예를 들어, 버스 드라이버는 자식 디바이스의 리소스 목록에서 해당 정보를 사용할 수 없는 경우 상위 수준 드라이버가 자식 디바이스에 대한 정보를 얻기 위해 호출할 수 있는 하나 이상의 루틴을 제공할 수 있습니다.

WDK에 설명된 드라이버 정의 인터페이스 집합의 예제는 USB 루틴을 참조하세요. 또한 토스터 샘플의 프레임워크 기반 버전을 참조하세요.

인터페이스 만들기

각 드라이버 정의 인터페이스는 다음을 통해 지정됩니다.

  • GUID

  • 버전 번호

  • 드라이버 정의 인터페이스 구조

  • 참조 및 역참조 루틴

인터페이스를 만들고 다른 드라이버에서 사용할 수 있도록 프레임워크 기반 드라이버는 다음 단계를 사용할 수 있습니다.

  1. 인터페이스 구조를 정의합니다.

    이 드라이버 정의 구조체의 첫 번째 멤버는 INTERFACE 헤더 구조체여야 합니다. 추가 멤버에는 인터페이스 데이터와 다른 드라이버가 호출할 수 있는 추가 구조 또는 루틴에 대한 포인터가 포함될 수 있습니다.

    드라이버는 정의한 인터페이스를 설명하는 WDF_QUERY_INTERFACE_CONFIG 구조를 제공해야 합니다.

    참고

    WDF_QUERY_INTERFACE_CONFIG 사용하는 경우 WDF는 동일한 인터페이스 GUID를 사용하는 단일 인터페이스의 여러 버전을 지원하지 않습니다.

    따라서 기존 인터페이스의 새 버전을 도입할 때 INTERFACE 구조의크기 또는 버전 필드를 수정하는 대신 새 GUID를 만드는 것이 좋습니다.

    드라이버가 수정된 크기 또는 버전 필드에서 동일한 인터페이스 GUID를 다시 사용하는 경우 드라이버는 WDF_QUERY_INTERFACE_CONFIG 제공하지 않아야 하며 대신 IRP_MN_QUERY_INTERFACE대한 EvtDeviceWdmIrpPreprocess 콜백 루틴을 제공해야 합니다.

  2. WdfDeviceAddQueryInterface를 호출합니다.

    WdfDeviceAddQueryInterface 메서드는 다음을 수행합니다.

    • 해당 GUID, 버전 번호 및 구조 크기와 같은 인터페이스에 대한 정보를 저장하므로 프레임워크는 인터페이스에 대한 다른 드라이버의 요청을 인식할 수 있습니다.
    • 다른 드라이버가 인터페이스를 요청할 때 프레임워크에서 호출하는 선택적 EvtDeviceProcessQueryInterfaceRequest 이벤트 콜백 함수를 등록합니다.

드라이버 정의 인터페이스의 각 instance 개별 디바이스와 연결되므로 드라이버는 일반적으로 EvtDriverDeviceAdd 또는 EvtChildListCreateDevice 콜백 함수 내에서 WdfDeviceAddQueryInterface를 호출합니다.

인터페이스 액세스

드라이버가 인터페이스를 정의한 경우 다른 프레임워크 기반 드라이버는 WdfFdoQueryForInterface 를 호출하고 GUID, 버전 번호, 구조체에 대한 포인터 및 구조체 크기를 전달하여 인터페이스에 대한 액세스를 요청할 수 있습니다. 프레임워크는 I/O 요청을 만들어 드라이버 스택의 맨 위로 보냅니다.

드라이버는 일반적으로 EvtDriverDeviceAdd 콜백 함수 내에서 WdfFdoQueryForInterface를 호출합니다. 또는 디바이스가 작동 상태가 아닐 때 드라이버가 인터페이스를 해제해야 하는 경우 드라이버는 EvtDevicePrepareHardware 콜백 함수 내에서 WdfFdoQueryForInterface를 호출하고 EvtDeviceReleaseHardware 콜백 함수 내에서 인터페이스의 역참조 루틴을 호출할 수 있습니다.

드라이버 A가 드라이버 B에게 드라이버 B가 정의한 인터페이스를 요청하는 경우 프레임워크는 드라이버 B에 대한 요청을 처리합니다. 프레임워크는 GUID 및 버전이 지원되는 인터페이스를 나타내고 드라이버 A가 제공한 구조체 크기가 인터페이스를 보유할 수 있을 만큼 큰지 확인합니다.

드라이버가 WdfFdoQueryForInterface를 호출하면 프레임워크가 만드는 I/O 요청이 드라이버 스택의 맨 아래로 이동합니다. 간단한 드라이버 스택이 세 개의 드라이버(A, B 및 C)로 구성되고 드라이버 A가 인터페이스를 요청하는 경우 드라이버 B와 드라이버 C 모두 인터페이스를 지원할 수 있습니다. 예를 들어 드라이버 B는 드라이버 C에 요청을 전달하기 전에 드라이버 A의 인터페이스 구조를 채울 수 있습니다. 드라이버 C는 인터페이스 구조의 내용을 검사하고 수정하는 EvtDeviceProcessQueryInterfaceRequest 콜백 함수를 제공할 수 있습니다.

드라이버 A가 드라이버 B의 인터페이스에 액세스해야 하고 드라이버 B가 원격 I/O 대상(즉, 다른 드라이버 스택에 있는 드라이버)인 경우 드라이버 A는 WdfFdoQueryForInterface 대신 WdfIoTargetQueryForInterface를 호출해야 합니다.

One-Way 또는 Two-Way 통신 사용

단방향 통신을 제공하는 인터페이스 또는 양방향 통신을 제공하는 인터페이스를 정의할 수 있습니다. 양방향 통신을 지정하기 위해 드라이버는 WDF_QUERY_INTERFACE_CONFIG 구조체의 ImportInterface 멤버를 TRUE로 설정합니다.

인터페이스가 단방향 통신을 제공하고 드라이버 A가 드라이버 B의 인터페이스를 요청하는 경우 인터페이스 데이터는 드라이버 B에서 드라이버 A로만 흐릅니다. 프레임워크가 단방향 통신을 지원하는 인터페이스에 대한 드라이버 A의 요청을 받으면 프레임워크는 드라이버 정의 인터페이스 값을 드라이버 A의 인터페이스 구조에 복사합니다. 그런 다음, 드라이버 B의 EvtDeviceProcessQueryInterfaceRequest 콜백 함수가 있는 경우 호출하므로 인터페이스 값을 검사하고 수정할 수 있습니다.

인터페이스가 양방향 통신을 제공하는 경우 인터페이스 구조에는 드라이버 B에 요청을 보내기 전에 드라이버 A가 채우는 일부 멤버가 포함됩니다. 드라이버 B는 드라이버 A가 제공한 매개 변수 값을 읽고 해당 값에 따라 드라이버 A에 제공할 정보를 선택할 수 있습니다. 프레임워크가 양방향 통신을 지원하는 인터페이스에 대한 드라이버 A의 요청을 받으면 프레임워크는 받은 값을 검사하고 출력 값을 제공할 수 있도록 드라이버 B의 EvtDeviceProcessQueryInterfaceRequest 콜백 함수를 호출합니다. 양방향 통신의 경우 프레임워크가 인터페이스 값을 드라이버 A의 인터페이스 구조에 복사하지 않으므로 콜백 함수가 필요합니다.

참조 수 유지 관리

각 인터페이스에는 인터페이스에 대한 참조 수를 증가 및 감소시키는 참조 함수와 역참조 함수가 포함되어야 합니다. 인터페이스를 정의하는 드라이버는 인터페이스 구조에서 이러한 함수의 주소를 지정합니다.

드라이버 A가 드라이버 B에게 인터페이스를 요청하는 경우 프레임워크는 인터페이스를 드라이버 A에 사용할 수 있도록 하기 전에 인터페이스의 참조 함수를 호출합니다. 드라이버 A가 인터페이스 사용을 마쳤으면 인터페이스의 역참조 함수를 호출해야 합니다.

대부분의 인터페이스에 대한 참조 및 역참조 함수는 아무 작업도 하지 않는 no-op 함수일 수 있습니다. 프레임워크는 대부분의 드라이버에서 사용할 수 있는 no-op 참조 수 함수인 WdfDeviceInterfaceReferenceNoOpWdfDeviceInterfaceDereferenceNoOp을 제공합니다.

드라이버가 인터페이스의 참조 수를 추적하고 실제 참조 및 역참조 함수를 제공해야 하는 유일한 시간은 드라이버 A가 원격 I/O 대상(즉, 다른 드라이버 스택에 있는 드라이버)에서 인터페이스를 요청하는 경우입니다. 이 경우 드라이버 B(다른 스택)는 드라이버 A가 드라이버 B의 인터페이스를 사용하는 동안 디바이스가 제거되는 것을 방지할 수 있도록 참조 횟수를 구현해야 합니다.

인터페이스를 정의하는 드라이버 B를 디자인하는 경우 드라이버의 인터페이스가 다른 드라이버 스택에서 액세스할지 여부를 결정해야 합니다. (드라이버 B는 해당 인터페이스에 대한 요청이 로컬 드라이버 스택 또는 원격 스택에서 온 것인지 확인할 수 없습니다.) 드라이버가 원격 스택의 인터페이스 요청을 지원하는 경우 드라이버는 참조 횟수를 구현해야 합니다.

원격 I/O 대상의 인터페이스에 액세스하는 드라이버 A를 디자인하는 경우 드라이버는 드라이버 B의 디바이스가 제거될 때 인터페이스를 해제하는 EvtIoTargetQueryRemove 콜백 함수, 드라이버 B의 디바이스가 깜짝 제거될 때 인터페이스를 해제하는 EvtIoTargetRemoveComplete 콜백 함수 및 EvtIoTargetRemoveCance를 제공해야 합니다. 디바이스를 제거하려는 시도가 취소된 경우 인터페이스를 다시 요청하는 콜백 함수입니다.