Using WinUSB for your USB Devices Randy Aull Principal Software Design Engineer Device Connectivity Team Device & Storage Technologies Group
Agenda Overview of WinUSB WinUSB Architecture and OS Support WinUSB Default Behavior and How to Modify It WinUSB Advanced Power Management WinUSB Installation Call to Action
Intro to WinUSB WinUSB – A generic KMDF USB Driver that exposes interfaces in user mode. PNP and Power Management are handled by this driver and can be adjusted through policies Control, Bulk and Interrupt endpoints are supported 32 and 64 bit support 3 ways of implementation UMDF: USBOEM.dll is an example of a UMDF driver talking to a USB device function Service: USBSCAN.EXE is an imaginary service talking to a USB device function Standalone Application: USBFW is an example of a stand-alone application talking to a USB device function
Operating System Support for WinUSB Driver stacks in Microsoft leveraging WinUSB USBSCAN Wireless USB MTP Works with wired and wireless USB Active Sync Sideshow Biometrics Driver Framework Feature Windows XP Windows Vista Windows 7 Isochronous transfers Not supported Bulk, control, and interrupt transfers Supported Selective suspend Not Supported Remote wake Inbox Support Not In-Box Inbox
WinUSB, UMDF, and KMDF Capabilities Requirements WinUSB UMDF KMDF Supports multiple concurrent applications No Yes Isolates driver address space from application address space Supports bulk, interrupt, and control transfers Supports isochronous transfers Supports the installation of kernel-mode drivers such as filter drivers above the USB driver Supports selective suspend and wait/wake
Prototype Code Sample Prototype code. Error handling removed. deviceHandle = CreateFile(devicePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); <Boilerplate SetupAPI calls to get device path> devInfo.winUSBHandle= WinUsb_Initialize(deviceHandle, &usbHandle); NULL, NULL); dataBufferLength, dataBuffer, setupPacket, bResult = WinUsb_ControlTransfer (devInfo.winUSBHandle, Prototype code. Error handling removed.
Default Read Behavior After being presented a request from the primary parallel queue, WinUSB forwards the request to an endpoint-specific serial queue. Zero-length reads complete immediately with success and are not sent down the stack. If the transfer length is greater than a maximum transfer length, WinUSB breaks up the request into smaller requests of maximum transfer length and submits them serially. If the transfer length is not a multiple of the endpoint’s MaxPacketSize, WinUSB rounds the size down to the next multiple. On successful completion (without short packet), WinUSB submits another request for MaxPacketSize bytes. If a device returns more data than requested, WinUSB saves the excess data. If data is left over from previous read, WinUSB copies it to the beginning of the next read and completes the read if necessary.
Default Write Behavior After being presented a request from the primary parallel queue, WinUSB forwards the request to an endpoint-specific serial queue. Zero-length writes are forwarded down the stack. If the transfer length is greater than a maximum transfer length, WinUSB breaks up the request into smaller requests of maximum transfer length and submits them serially.
Pipe Policies WinUSB driver allows modifications to its default behavior through policies that can be applied to a pipe (endpoint). Defined policies include: 0x01 – SHORT_PACKET_TERMINATE (Default: Off) 0x02 – AUTO_CLEAR_STALL (Default: Off) 0x03 – PIPE_TRANSFER_TIMEOUT (Default: 5 Seconds for Control, 0 for others) 0x04 – IGNORE_SHORT_PACKETS (Default: Off) 0x05 – ALLOW_PARTIAL_READS (Default: On) 0x06 – AUTO_FLUSH (Default: Off) 0x07 – RAW_IO (Default: Off) 0x09 – RESET_PIPE_ON_RESUME (Default: Off) Additional Details: WinUsb_GetPipePolicy http://msdn.microsoft.com/en-us/library/aa476439.aspx new
Pipe Policy – SHORT_PACKET_TERMINATE When should it be used? If your device requires that OUT transfers be terminated with a short packet (most don’t require this) Only valid for bulk and interrupt OUT endpoints (setting on IN endpoints has no effect) Impact of enabling this policy All writes to the endpoint will be terminated with a short packet When an OUT transfer completes back to WinUSB, if the transfer was an exact multiple of the endpoint’s MaxPacketSize, WinUSB resubmits the request to the USB stack, but this time with the length set to 0 bytes. Results in performance penalty only for writes that are an exact multiple of MaxPacketSize (all writes are serialized by WinUsb anyway)
Pipe Policy – AUTO_CLEAR_STALL When should it be used? If you want failed transfers NOT to leave the endpoint in a STALLed state Only valid for bulk and interrupt IN endpoints Generally useful only when pending multiple reads to the endpoint when RAW_IO is disabled Impact of enabling/disabling this policy If enabled, when an IN transfer fails with a status other than STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED, WinUSB queues a work item to reset the endpoint before completing the failed transfer. If disabled, subsequent transfers to the endpoint fail until the endpoint is manually reset with WinUsb_ResetPipe(). No significant performance difference between enabling/disabling this policy.
Pipe Policy – PIPE_TRANSFER_TIMEOUT When should it be used? If you have an endpoint for which you expect transfers to complete within a specific time. Impact of enabling/disabling this policy If set to 0, transfers may pend indefinitely until manually cancelled or completed normally. If set to a non-zero value, a timer will start when the request is sent down to the core USB stack (requests will not timeout while in a WinUSB queue). When the timer expires, the request will be cancelled. Minor performance penalty due to managing timers
Pipe Policy – IGNORE_SHORT_PACKETS When should it be used? If you don’t want short packets to complete your read requests (rare) Only valid for bulk and interrupt IN endpoints with RAW_IO disabled Impact of enabling this policy Reads will complete only if an error occurs, the request is cancelled, or all requested bytes have been received. When a request is completed by the USB stack with a short packet, WinUSB resubmits the request, but adjusts the length and buffer pointers to start at the buffer location for the next expected byte.
Pipe Policy – ALLOW_PARTIAL_READS When should it be used? If your device can legally send more data than requested (only possible if requesting non-multiple of MaxPacketSize) If the application wants to read a few bytes to determine how many total bytes to read Only valid for bulk and interrupt IN endpoints Impact of enabling/disabling this policy If disabled, and the device returns more data than was requested, the request completes with an error If enabled, WinUSB immediately completes read requests for zero bytes with success and does not send the requests down the stack. If enabled, and the device returns more data than was requested, WinUSB saves the excess data and prepends it to the subsequent read request.
Pipe Policy – AUTO_FLUSH When should it be used? If the device can send more bytes than requested, and the application does not care about the extra bytes (only possible if requesting non-multiple of MaxPacketSize) Only valid for bulk and interrupt IN endpoints with ALLOW_PARTIAL_READS enabled Impact of enabling this policy If an endpoint returns more bytes than requested, WinUSB discards those bytes without error Has no effect if ALLOW_PARTIAL_READS is disabled
Pipe Policy – RAW_IO When should it be used? If read performance is a priority and application submits multiple simultaneous reads to the same endpoint Only valid for bulk and interrupt IN endpoints (setting on OUT endpoints has no effect) Impact of enabling this policy Requests to the endpoint that are not a multiple of MaxPacketSize will fail Requests to the endpoint that are greater than the maximum transfer size (retrievable through MAXIMUM_TRANSFER_SIZE pipe policy) will fail All well-formed reads to the endpoint are immediately sent down the stack to be scheduled in the host controller Significant performance improvement when submitting multiple read requests Reduces the delay between the last packet of one transfer and the first packet of the next
Pipe Policy – RESET_PIPE_ON_RESUME When should it be used? If the device doesn’t preserve its data toggle state across suspend Only valid for bulk and interrupt endpoints Impact of enabling/disabling this policy On resume from suspend (Dx), WinUSB resets the endpoint before allowing requests to be sent to the endpoint
Power Management Uses the KMDF state machines for power Power policy is managed through calls to WinUsb_SetPowerPolicy, as well as defaults set in the registry To allow device to wake the system from Sx: Add SystemWakeEnabled DWORD registry value and set to non-zero value Checkbox in device Properties page is automatically enabled so that user can override
Selective Suspend Selective suspend can be disabled by any one system or WinUSB setting. A single setting cannot force WinUSB to enable Selective Suspend. Power Policy Settings AUTO_SUSPEND – If zero, the device will not be selectively suspended SUSPEND_DELAY – Sets the time between the device becoming idle and WinUSB requesting selective suspend
Selective Suspend (contd.) Registry Keys for Selective Suspend DeviceIdleEnabled – if zero, the device will never be selectively suspended DeviceIdleIgnoreWakeEnable – if non-zero, the device can be suspended even if it does not support RemoteWake UserSetDeviceIdleEnabled – if non-zero, checkbox is enabled in device Properties page to allow user to override idle defaults DefaultIdleState – Sets the default value of the AUTO_SUSPEND power policy setting. Used to enable/disable selective suspend when handle is not open to the device. DefaultIdleTimeout – Sets the default state of the SUSPEND_DELAY power policy setting.
Selective Suspend (contd.) Detecting Idle Currently all IOCTLs to WinUSB result in device being active (requires D0) and resets the idle timer This behavior may change in the future to allow IOCTLs that don’t require D0 to avoid impact on idleness All writes and control transfers force the device into D0 and reset the idle timer IN endpoint queues are not power-managed Reads wake the device when submitted However, a device can idle out while a read request is pending
Driver Package Content KMDF co-installer and WinUSB co-installer must come from same WDK version Use the co-installer from latest WDK to support ALL latest Windows releases All contents of package should have a WHQL release signature Driver package content Vendor INF (using include/needs) + CAT File WinUSB Co-installer KMDF Co-installer
Future of WinUSB Feature considerations Isochronous endpoint support USB3 feature extensions Please submit your requests for additional extensions and requirements to WinUSBFB@microsoft.com
Call To Action Use WinUSB or UMDF for future USB driver design Do not write a kernel-mode driver unless you have to Some device classes may require a user-mode driver per the Windows Logo Program. Use sample INF and general SetupAPI calls to install your drivers properly Key errors to watch out for Ensure correct file flags in createfile APIs Remember to create your own unique interface GUID
Additional Resources Web Resources USB on the WHDC Web Site How to use WinUSB to Communicate with a USB Device http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx Summary of white papers and presentations http://www.microsoft.com/whdc/connect/usb/default.mspx USB on MSDN Device Installation Design Guide http://msdn.microsoft.com/en-us/library/ms790231.aspx Finish-Install Wizard Pages http://msdn.microsoft.com/en-us/library/aa477003.aspx Finish-Install Actions (Windows Vista) http://msdn.microsoft.com/en-us/library/aa477001.aspx
EXTRA SLIDES FROM HERE ONWARDS
Sample INF for WinUSB (Part 1) The following is a sample INF for WinUSB. (Details in Whitepaper) [Version] Signature = "$Windows NT$" Class = MyDeviceClass ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} Provider = %ProviderName% CatalogFile=MyCatFile.cat ; ========== Manufacturer/Models sections =========== [Manufacturer] %ProviderName% = MyDevice_WinUSB,NTx86,NTamd64 [MyDevice_WinUSB.NTx86] %USB\MyDevice.DeviceDesc% =USB_Install, USB\VID_0547&PID_1002 [MyDevice_WinUSB.NTamd64] ; =================== Installation =================== ;[1] [USB_Install] Include=winusb.inf Needs=WINUSB.NT ;[2] [USB_Install.Services] AddService=WinUSB,0x00000002,WinUSB_ServiceInstall #1. Required for Windows Vista. Ignored for Windows XP (Do Not Modify) #2. The add service director should point to WinUSB. (Do Not Modify)
Sample INF for WinUSB (Part 2) ;[3] [WinUSB_ServiceInstall] DisplayName = %WinUSB_SvcDesc% ServiceType = 1 ErrorControl = 1 ServiceBinary = %12%\WinUSB.sys ;[4] [USB_Install.Wdf] KmdfService=WINUSB, WinUsb_Install [WinUSB_Install] KmdfLibraryVersion=1.5 ;[5] [USB_Install.HW] AddReg=Dev_AddReg [Dev_AddReg] HKR,,DeviceInterfaceGUIDs,0x10000,"{b35924d6-3e16-4a9e-9782-5524a4b79bac}" ;[6] [USB_Install.CoInstallers] AddReg=CoInstallers_AddReg CopyFiles=CoInstallers_CopyFiles [CoInstallers_AddReg] HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01005.dll,WdfCoInstaller","WinUSBCoInstaller.dll" [CoInstallers_CopyFiles] WinUSBCoInstaller.dll WdfCoInstaller01005.dll #3. Actually sets winusb.sys as the service. Ensure tight start types. (Do Not Modify) #4. Associates WinUSB with a KMDF Service. (Ensure right version) #5. Associates WinUSB with a GUID that your App needs. (Ensure correct GUID) #6. Associates correct WDF Co-Installers. (Do not Modify)
Sample INF for WinUSB (Part 3) ; =============== Source Media Section ================= ;[7] [SourceDisksNames] 1 = %DISK_NAME%,,,\i386 2 = %DISK_NAME%,,,\amd64 [SourceDisksFiles.x86] WinUSBCoInstaller.dll=1 WdfCoInstaller01005.dll=1 [SourceDisksFiles.NTamd64] WinUSBCoInstaller.dll=2 WdfCoInstaller01005.dll=2 [DestinationDirs] CoInstallers_CopyFiles=11 ; =================== Strings =================== [Strings] ProviderName="MyWinUsbTest" USB\MyDevice.DeviceDesc="Test using WinUSB only" WinUSB_SvcDesc="WinUSB Test" DISK_NAME="My Install Disk" #7. Separate Co-Installers for x86 and x64. (Do not Modify)