Drivers Virtual USB Devices



-->

Virtual COM port (VCP) drivers cause the USB device to appear as an additional COM port available to the PC. Application software can access the USB device in the same way as it would access a standard COM port.

The USB Device Viewer shows all the USB host controllers in your system. More specifically: A Host Controller that is identified as eXtensible or xHCI is a USB 3.0 host controller.; A Host. D2XX drivers allow direct access to the USB device through a DLL. Application software can access the USB device through a series of DLL function calls. The functions available are listed in the D2XX Programmer’s Guide document which is available from the. Documents section of this site.

Summary

  • UDE objects and handles used by the class extension and client driver.
  • Creating an emulated host controller with features to query controller capabilities and reset the controller.
  • Creating a virtual USB device, setting it up for power management and data transfers through endpoints.

Applies to:

  • Windows 10

Last updated:

  • November 2015

Important APIs

Describes the behavior of USB Device Emulation(UDE) class extension and tasks that a client driver must perform for an emulated host controller and devices attached to it. It provides information about how the class driver and class extension communicate with each through a set of routines and callback functions. It also describes the features that the client driver is expected to implement.

Before you begin

  • Install the latest Windows Driver Kit (WDK) your development computer. The kit has the required header files and libraries for writing a UDE client driver, specifically, you'll need:
    • The stub library, (Udecxstub.lib). The library translates calls made by the client driver and pass them up to UdeCx.
    • The header file, Udecx.h.
  • Install Windows 10 on your target computer.
  • Familiarize yourself with UDE. See Architecture: USB Device Emulation(UDE).
  • Familiarize yourself with Windows Driver Foundation (WDF). Recommended reading: Developing Drivers with Windows Driver Foundation, written by Penny Orwick and Guy Smith.

UDE objects and handles

UDE class extension and the client driver use particular WDF objects that represent the emulated host controller and the virtual device, including its endpoints and URBs that are used to transfer data between the device and the host. The client driver requests the creation of the objects and lifetime of the object is managed by the class extension.

  • Emulated host controller object (WDFDEVICE)

    Represents the emulated host controller and is the main handle between the UDE class extension and the client driver.

  • UDE device object (UDECXUSBDEVICE)

    Represents a virtual USB device that is connected to a port on the emulated host controller.

  • UDE endpoint object (UDECXUSBENDPOINT)

    Represent sequential data pipes of USB devices. Used to receive software requests to send or receive data on an endpoint.

Initialize the emulated host controller

Here is the summary of the sequence in which the client driver retrieves a WDFDEVICE handle for the emulated host controller. We recommend that the driver perform these tasks in its EvtDriverDeviceAdd callback function.

  1. Call UdecxInitializeWdfDeviceInit by passing the reference to WDFDEVICE_INIT passed by the framework.

  2. Initialize the WDFDEVICE_INIT structure with setup information such that this device appears similar to other USB host controllers. For example assign an FDO name and a symbolic link, register a device interface with the Microsoft-provided GUID_DEVINTERFACE_USB_HOST_CONTROLLER GUID as the device interface GUID so that applications can open a handle to the device.

  3. Call WdfDeviceCreate to create the framework device object.

  4. Call UdecxWdfDeviceAddUsbDeviceEmulation and register the client driver's callback functions.

    Here are the callback functions associated with the host controller object, which are invoked by UDE class extension. These functions must be implemented by the client driver.

    EVT_UDECX_WDF_DEVICE_QUERY_USB_CAPABILITY
    Determines the capabilities supported by the host controller that the client driver must report to the class extension.

    EVT_UDECX_WDF_DEVICE_RESET
    Optional. Resets the host controller and/or the connected devices.

Handle user-mode IOCTL requests sent to the host controller

During initialization, the UDE client driver exposes the GUID_DEVINTERFACE_USB_HOST_CONTROLLER device interface GUID. This enables the driver to receive IOCTL requests from an application that opens a device handle by using that GUID. For a list of IOCTL control codes, see USB IOCTLs for applications and services with Device interface GUID: GUID_DEVINTERFACE_USB_HOST_CONTROLLER.

To handle those requests, the client driver registers the EvtIoDeviceControl event callback. In the implementation, instead of handling the request, the driver can opt to forward the request to the UDE class extension for processing. To forward the request, the driver must call UdecxWdfDeviceTryHandleUserIoctl. If the received IOCTL control code corresponds to a standard request, such as retrieving device descriptors, the class extension processes and completes the request successfully. In this case, UdecxWdfDeviceTryHandleUserIoctl completes with TRUE as the return value. Otherwise, the call returns FALSE and the driver must determine how to complete the request. In a simplest implementation, the driver can complete the request with an appropriate failure code by calling WdfRequestComplete.

Report the capabilities of the host controller

Before upper layer drivers can use the capabilities of a USB host controller, the drivers must determine whether those capabilities are supported by the controller. Drivers make such queries by calling WdfUsbTargetDeviceQueryUsbCapability and USBD_QueryUsbCapability. Those calls are forwarded to the USB Device Emulation(UDE) class extension. Upon getting the request, the class extension invokes the client driver's EVT_UDECX_WDF_DEVICE_QUERY_USB_CAPABILITY implementation. This call is made only after EvtDriverDeviceAdd completes, typically in EvtDevicePrepareHardware and not after EvtDeviceReleaseHardware. This is callback function is required.

In the implementation, the client driver must report whether it supports the requested capability. Certain capabilities are not supported by UDE such as static streams.

Create a virtual USB device

A virtual USB device behaves similar to a USB device. It supports a configuration with multiple interfaces and each interface supports alternate settings. Each setting can have one more endpoints that are used for data transfers. All descriptors (device, configuration, interface, endpoint) are set by the UDE client driver so that the device can report information much like a real USB device.

Note

The UDE client driver does not support external hubs

Here is the summary of the sequence in which the client driver creates a UDECXUSBDEVICE handle for a UDE device object. The driver must perform these steps after it has retrieved the WDFDEVICE handle for the emulated host controller. We recommend that the driver perform these tasks in its EvtDriverDeviceAdd callback function.

  1. Call UdecxUsbDeviceInitAllocate to get a pointer to the initialization parameters required to create the device. This structure is allocated by the UDE class extension.

  2. Register event callback functions by setting members of UDECX_USB_DEVICE_STATE_CHANGE_CALLBACKS and then calling UdecxUsbDeviceInitSetStateChangeCallbacks. Here are the callback functions associated with the UDE device object, which are invoked by the UDE class extension.

    These functions are implemented by the client driver to create or configure endpoints.

  3. Call UdecxUsbDeviceInitSetSpeed to set the USB device speed and also the type of device, USB 2.0 or a SuperSpeed device.

  4. Call UdecxUsbDeviceInitSetEndpointsType to specify the type of endpoints the device supports: simple or dynamic. If the client driver chooses to create simple endpoints, the driver must create all endpoint objects before plugging in the device. The device must have only one configuration and only one interface setting per interface. In the case of dynamic endpoints, the driver can create endpoints at anytime after plugging in the device when it receives an EVT_UDECX_USB_DEVICE_ENDPOINTS_CONFIGURE event callback. See Create dynamic endpoints.

  5. Call any of these methods to add necessary descriptors to the device.

    • If the UDE class extension receives a request for a standard descriptor that the client driver has provided during initialization by using one of the preceding methods, the class extension automatically completes the request. The class extension does not forward that request to the client driver. This design reduces the number of requests that the driver needs to process for control requests. Additionally, it also eliminates the need for the driver to implement descriptor logic that requires extensive parsing of the setup packet and handling wLength and TransferBufferLength correctly. This list includes the standard requests. The client driver does not need to check for these requests (only if the preceding methods were called to add descriptor):

    • USB_REQUEST_GET_DESCRIPTOR

    • USB_REQUEST_SET_CONFIGURATION

    • USB_REQUEST_SET_INTERFACE

    • USB_REQUEST_SET_ADDRESS

    • USB_REQUEST_SET_FEATURE

    • USB_FEATURE_FUNCTION_SUSPEND

    • USB_FEATURE_REMOTE_WAKEUP

    • USB_REQUEST_CLEAR_FEATURE

    • USB_FEATURE_ENDPOINT_STALL

    • USB_REQUEST_SET_SEL

    • USB_REQUEST_ISOCH_DELAY

      However, requests for the interface, class-specific, or vendor-defined descriptor, the UDE class extension forwards them to the client driver. The driver must handle those GET_DESCRIPTOR requests.

  6. Call UdecxUsbDeviceCreate to create the UDE device object and retrieve the UDECXUSBDEVICE handle.

  7. Create static endpoints by calling UdecxUsbEndpointCreate. See Create simple endpoints.

  8. Call UdecxUsbDevicePlugIn to indicate to the UDE class extension that the device is attached and can receive I/O requests on endpoints. After this call, the class extension can also invoke callback functions on endpoints and the USB device.Note If the USB device needs to be removed at runtime, the client driver can call UdecxUsbDevicePlugOutAndDelete. If the driver wants to use the device, it must create it by calling UdecxUsbDeviceCreate.

In this example, the descriptor declarations are assumed to be global variables, declared as shown here for a HID device just as an example:

Here is an example in which the client driver specifies initialization parameters by registering callback functions, setting device speed, indicating the type of endpoints, and finally setting some device descriptors.

Power management of the USB device

The UDE class extension invokes client driver's callback functions when it receives a request to send the device to low power state or bring it back to working state. These callback functions are required for USB devices that support wake. The client driver registered its implementation by in the previous call to UdecxUsbDeviceInitSetStateChangeCallbacks.

For more information, see USB Device Power States.

EVT_UDECX_USB_DEVICE_D0_ENTRY
The client driver transitions the device from a Dx state to D0 state.

EVT_UDECX_USB_DEVICE_D0_EXIT
The client driver transitions the device from D0 state to a Dx state.

EVT_UDECX_USB_DEVICE_SET_FUNCTION_SUSPEND_AND_WAKE
The client driver changes the function state of the specified interface of the virtual USB 3.0 device.

Drivers Virtual Usb Devices Wireless Adapter

A USB 3.0 device allows individual functions to enter lower power state. Each function is also capable of send a wake signal. The UDE class extension notifies the client driver by invoking EVT_UDECX_USB_DEVICE_SET_FUNCTION_SUSPEND_AND_WAKE. This event indicates a function power state change and informs the client driver of whether the function can wake from the new state. In the function, the class extension passes the interface number of the function that is waking up.The client driver can simulate the action of a virtual USB device initiating its own wake up from a low link power state, function suspend, or both. For a USB 2.0 device, the driver must call UdecxUsbDeviceSignalWake, if the driver enabled wake on the device in the most recent EVT_UDECX_USB_DEVICE_D0_EXIT. For a USB 3.0 device, the driver must call UdecxUsbDeviceSignalFunctionWake because the USB 3.0 wake feature is per-function. If the entire device is in a low power state, or entering such a state, UdecxUsbDeviceSignalFunctionWake wakes up the device.

Create simple endpoints

Drivers virtual usb devices pc camera

The client driver creates UDE endpoint objects to handle data transfers to and from the USB device. The driver creates simple endpoints after creating the UDE device and before reporting the device as plugged in.

Here is the summary of the sequence in which the client driver creates a UDECXUSBENDPOINT handle for a UDE endpoint object. The driver must perform these steps after it has retrieved the UDECXUSBDEVICE handle for the virtual USB device. We recommend that the driver perform these tasks in its EvtDriverDeviceAdd callback function.

  1. Call UdecxUsbSimpleEndpointInitAllocate to get a pointer to the initialization parameters allocated by the class extension.

  2. Call UdecxUsbEndpointInitSetEndpointAddress to set the endpoint address in the initialization parameters.

  3. Call UdecxUsbEndpointInitSetCallbacks to register the client driver-implemented callback functions.

    These functions are implemented by the client driver to handle queues and requests on an endpoint.

    EVT_UDECX_USB_ENDPOINT_RESET
    Resets an endpoint of the virtual USB device.

    EVT_UDECX_USB_ENDPOINT_START
    Optional. Starts processing I/O requests

    EVT_UDECX_USB_ENDPOINT_PURGE
    Optional. Stop queuing I/O requests to the endpoint's queue and cancel unprocessed requests.

  4. Call UdecxUsbEndpointCreate to create the endpoint object and retrieve the UDECXUSBENDPOINT handle.

  5. Call UdecxUsbEndpointSetWdfIoQueue to associate a framework queue object with the endpoint. If applicable, it can set the endpoint object to be the WDF parent object of the queue by setting appropriate attributes.

    Every endpoint object has a framework queue object in order to handle transfer requests. For each transfer request that the class extension receives, it queues a framework request object. The state of the queue (started, purged) is managed by the UDE class extension and the client driver must not change that state. Each request object contains an USB Request Block (URB) that contains details of the transfer.

In this example, the client driver creates the default control endpoint.

Create dynamic endpoints

The client driver can create dynamic endpoints at the request of the UDE class extension (on behalf of the hub driver and client drivers). The class extension makes the request by invoking any of these callback functions:

EVT_UDECX_USB_DEVICE_DEFAULT_ENDPOINT_ADD
The client driver creates the default control endpoint (Endpoint 0)

EVT_UDECX_USB_DEVICE_ENDPOINT_ADD
The client driver creates a dynamic endpoint.

EVT_UDECX_USB_DEVICE_ENDPOINTS_CONFIGURE
The client driver changes the configuration by selecting an alternate setting, disabling current endpoints, or adding dynamic endpoints.

The client driver registered the preceding callback during its call to UdecxUsbDeviceInitSetStateChangeCallbacks. See Create virtual USB device.This mechanism allows the client driver to dynamically change the USB configuration and interface settings on the device. For example, when a endpoint object is needed or an existing endpoint object must be released, the class extension calls the EVT_UDECX_USB_DEVICE_ENDPOINTS_CONFIGURE.

Here is the summary of the sequence in which the client driver creates a UDECXUSBENDPOINT handle for an endpoint object in its implementation of the callback function.

  1. Call UdecxUsbEndpointInitSetEndpointAddress to set the endpoint address in the initialization parameters.

  2. Call UdecxUsbEndpointInitSetCallbacks to register the client driver-implemented callback functions. Similar to simple endpoints, the driver can register these callback functions:

    • EVT_UDECX_USB_ENDPOINT_RESET (required).
  3. Call UdecxUsbEndpointCreate to create the endpoint object and retrieve the UDECXUSBENDPOINT handle.

  4. Call UdecxUsbEndpointSetWdfIoQueue to associate a framework queue object with the endpoint.

In this example implementation, the client driver creates a dynamic default control endpoint.

Perform error recovery by resetting an endpoint

At times, data transfers can fail due to various reasons, such as a stall condition in the endpoint. In the case of failed transfers, the endpoint cannot process requests until the error condition is cleared. When the UDE class extension experiences failed data transfers, it invokes the client driver's EVT_UDECX_USB_ENDPOINT_RESET callback function, which the driver registered in the previous call to UdecxUsbEndpointInitSetCallbacks. In the implementation, the driver can choose to clear the HALT state of the pipe and take other necessary steps to clear the error condition.

This call is asynchronous. After the client is finished with the reset operation, driver must complete the request with an appropriate failure code by calling WdfRequestComplete. That call notifies the UDE client extension about the completion of the reset operation with status.

Note If a complex solution is required for error recovery, the client driver has the option of resetting the host controller. This logic can be implemented in the EVT_UDECX_WDF_DEVICE_RESET callback function that the driver registered in its UdecxWdfDeviceAddUsbDeviceEmulation call. If applicable, the driver can reset the host controller and all downstream devices. If the client driver does not need to reset the controller but reset all downstream devices, the driver must specify UdeWdfDeviceResetActionResetEachUsbDevice in the configuration parameters during registration. In that case, the class extension invokes EVT_UDECX_WDF_DEVICE_RESET for each connected device.

Implement queue state management

The state of the framework queue object associated with a UDE endpoint object is managed by the UDE class extension. However, if the client driver forwards requests from endpoint queues to other internal queues, then the client must implement logic to handle changes in the endpoint’s I/O flow. These callback functions are registered with UdecxUsbEndpointInitSetCallbacks.

Endpoint purge operation

A UDE client driver with one queue per endpoint can implement EVT_UDECX_USB_ENDPOINT_PURGE as shown in this example:

In the EVT_UDECX_USB_ENDPOINT_PURGE implementation, the client driver is required to make sure all I/O forwarded from the endpoint’s queue has been completed, and that newly forwarded I/O also fails until the client driver's EVT_UDECX_USB_ENDPOINT_START is invoked. These requirements are met by calling UdecxUsbEndpointPurgeComplete, which make sure that all forwarded I/O is completed and future forwarded I/O are failed.

Endpoint start operation

In the EVT_UDECX_USB_ENDPOINT_START implementation, the client driver is required to begin processing I/O on the endpoint’s queue, and on any queues that receive forwarded I/O for the endpoint. After an endpoint is created, it does not receive any I/O until after this callback function returns. This callback returns the endpoint to a state of processing I/O after EVT_UDECX_USB_ENDPOINT_PURGE completes.

Handling data transfer requests (URBs)

To process USB I/O requests sent to the client device's endpoints, intercept the EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL callback on the queue object used with UdecxUsbEndpointInitSetCallbacks when associating the queue with the endpoint. In that callback, process I/O for the IOCTL_INTERNAL_USB_SUBMIT_URB IoControlCode (see sample code under URB handling methods).

URB handling methods

As part of processing URBs via IOCTL_INTERNAL_USB_SUBMIT_URB of a queue associated with an endpoint on a virtual device, A UDE client driver can get a pointer to the transfer buffer of an I/O request by using these methods:

These functions are implemented by the client driver to handle queues and requests on an endpoint.

UdecxUrbRetrieveControlSetupPacket
Retrieves a USB control setup packet from a specified framework request object.

UdecxUrbRetrieveBuffer
Retrieves the transfer buffer of an URB from the specified framework request object sent to the endpoint queue.

UdecxUrbSetBytesCompleted
Sets the number of bytes transferred for the URB contained within a framework request object.

Drivers Virtual USB Devices

UdecxUrbComplete
Completes the URB request with a USB-specific completion status code.

UdecxUrbCompleteWithNtStatus
Completes the URB request with an NTSTATUS code.

Drivers Virtual Usb Devices 3.0

Below is the flow of typical I/O processing for the URB of an USB OUT transfer.

The client driver can complete an I/O request on a separate with a DPC. Follow these best practices:

  • To ensure compatibility with existing USB drivers, the UDE client must call WdfRequestComplete at DISPATCH_LEVEL.
  • If the URB was added to an endpoint's queue and the driver starts processing it synchronously on the calling driver’s thread or DPC, the request must not be completed synchronously. A separate DPC is required for that purpose, which the driver queue by calling WdfDpcEnqueue.
  • When the UDE class extension invokes EvtIoCanceledOnQueue or EvtRequestCancel, the client driver must complete the received URB on a separate DPC from the caller's thread or DPC. To do this, the driver must provide an EvtIoCanceledOnQueue callback for its URB queues.