如何使用 WinUSB 與 USB 設備 (USBDevice) 通信


選擇 USB 設備的驅動程序模型

https://github.com/libusbx/libusbx/wiki/Windows-Backend

  • WinUSB does not support Windows 2003 ( 32bit/64bit )
  • WinUSB does not support Windows XP 64 bit ( not officially support on 64bit Windows XP)
  • WinUSB cannot be used to send an actual reset command to an USB device.
    This is a limitation of WinUSB.
  • WinUSB does not support isochronous transfers.
  • WinUSB cannot be used to set a device configuration that is different from the first one.
    This is a limitation of KMDF USB I/O Target.
  • WinUSB does not support multiple concurrent applications
  • WinUSB does not support USB 1.0 or USB 1.1
    If the USB Device Descriptor’s bcdUSB field is equal to 0x0100 or 0x0110,
    the hub driver will skip the query for the MS OS Descriptor and
    move to the “Serial Number String Descriptor Query” state

https://github.com/pbatard/libwdi/wiki/WCID-Devices

What is WCID?

A WCID device, where WCID stands for "Windows Compatible ID", is an USB device that provides extra information to a Windows system, in order to facilitate automated driver installation and, in some circumstances, allow immediate access.

WCID allows a device to be used by a Windows application almost as soon as it is plugged in, as opposed to the the usual scenario where an USB device that is neither HID nor Mass Storage requires end-users to perform a manual driver installation. As such, WCID can bring the 'Plug-and-Play' functionality of HID and Mass Storage to any USB device (that sports a WCID aware firmware).

WCID is an extension of the WinUSB Device functionality, put forward by Microsoft during the Windows 8 Developer Preview. However, it uses capabilities (Microsoft OS Descriptors, or MODs) that have been part of Windows since Windows XP SP2.

As of May 2012, an automated WinUSB WCID driver is provided on all platforms starting with Windows Vista. 
On Windows 8, it is native to the system (i.e. there's no need to fetch the driver online) whereas,
for Vista and Windows 7, it will be obtained from the internet, through Windows Update.


Microsoft Winusb Device Driver 1.0.0.0

http://download.windowsupdate.com/msdownload/update/driver/drvs/2012/05/20484220_5f2718fc6d44c5ae61d4275d679bbf1ededf58e5.cab http://de.drivers.exdat.com/download/17651/20484220_5f2718fc6d44c5ae61d4275d679bbf1ededf58e5.cab The package provides the installation files for Microsoft WinUSB Device Driver version 1.0.0.0. In order to manually update your driver, follow the steps below (the next steps): 1. Go to Device Manager (right click on My Computer, choose Manage and then find Device Manager in the left panel)
2. Right click on the hardware device you wish to update
and choose Update Driver Software
3. Choose to select the location of the new driver manually
and browse to the folder where you downloaded the driver

 

 

制造 USB 設備的獨立硬件供應商 (IHV) 必須經常為應用程序提供訪問設備功能的途徑。
在過去,這意味着使用 Windows 驅動程序模型 (WDM) 為設備實現一個功能驅動程序,
並將該驅動程序安裝在設備棧中系統提供的協議驅動程序之上。
Windows 驅動程序基礎 (WDF) 現在是 USB 驅動程序的首選模型。

它為 IHV 提供 3 個選項來提供訪問 USB 設備的途徑:

  • 使用 WDF 用戶模式驅動程序框架 (UMDF) 實現用戶模式驅動程序。

  • 使用 WDF 內核模式驅動程序框架 (KMDF) 實現內核模式驅動程序。

  • WinUsb.sys 作為設備的功能驅動程序安裝,
    並提供一個使用 WinUSB API <WinUsb.dll> 訪問設備的應用程序。

    WinUSB 在 Windows XP 上不支持 WinUSB 選擇性暫停

Windows 8 USB 驅動程序堆棧體系結構

該圖分別顯示了 USB 2.0 和 USB 3.0 的 USB 驅動程序堆棧。
當設備附加到 xHCI 控制器時,Windows 會加載 USB 3.0 驅動程序堆棧。
USB 3.0 堆棧是 Windows 8 中的新功能。

當設備連接到 eHCI、oHCI 或 uHCI 控制器時,Windows 會加載 USB 2.0 驅動程序堆棧。
USB 2.0 驅動程序堆棧隨 Windows XP Service Pack 1 (SP1) 及更高版本的 Windows 操作系統一起提供。

Windows 8 USB 驅動程序堆棧

對於自定義 USB 設備應該使用哪個設備安裝程序類?

獨立硬件供應商 IHV 必須使用與 USB 設備類型(而不是總線類型)相關的安裝程序類
如果要開發一個 Microsoft 還沒有為其提供現有類 GUID 的設備類型,可以定義一個新的設備安裝程序類

Windows 8 中定義了一個名為 USBDevice 
( ClassGuid = {88BAE032-5A81-49f0-BC3D-A4FF138216D6} ) 的新安裝程序類
如果您正在開發一個設備類型,請將您的設備與 <USBDevice> 而不是 <安裝程序類 USB> 關聯。 
USBDevice 類支持 Windows Vista 以及更高版本的操作系統。

安裝程序類 USB ( ClassGuid = {36fc9e60-c465-11cf-8056-444553540000} )
僅為 USB 主控制器和 USB 集線器保留,並且不能用於其他設備類別。
不正確地使用此安裝程序類可能導致設備驅動程序無法通過 Windows 徽標測試。 

WinUSB 架構和模塊

Windows USB (WinUSB) 是 Microsoft 提供的 USB 設備的通用驅動程序。

WinUSB 體系結構由內核模式驅動程序 (Winusb.sys) 和用戶模式動態鏈接庫 (Winusb.dll) 組成。

  • Winusb.sys 是一種內核模式驅動程序,可在 USB 設備的內核模式設備堆棧的協議驅動程序之上
    作為篩選器驅動程序或功能驅動程序進行安裝。
  • Winusb.dll 是一種公開 WinUSB 功能的用戶模式 DLL。
    當 Winusb.sys 作為設備的功能驅動程序安裝后,應用程序可以使用這些功能與其進行通信。

對於不要求自定義功能驅動程序的設備,Winusb.sys 可以在該設備的內核模式堆棧中作為功能驅動程序進行安裝。
隨后,用戶模式流程通過使用一組設備 I/O 控制請求調用 WinUSB 功能 ( WinUsb_Xxx 函數 )來與 Winusb.sys 進行通信。

 

上圖顯示了實施三個設備接口類的示例 WinUSB 配置,其中每個類都有單個注冊設備接口:

  • Winusb.sys 的實例 1 注冊設備接口 A,設備接口 A 支持用戶模式驅動程序 (Usboem.dll)。
  • Winusb.sys 的實例 2 注冊設備接口 B,設備接口 B 支持通過使用系統服務 (SVCHOST)
    與 Winusb.dll 進行通信的掃描儀的用戶模式驅動程序 (Usbscan.exe)。
  • Winusb.sys 的實例 3 注冊設備接口 C,設備接口 C 支持固件更新實用程序 (Usbfw.exe)。

僅加載了 Winusb.sys 的一個實例。
PDO 可以表示非復合設備(例如,上圖中的示例 1),
也可以表示復合設備上的接口或接口集合(例如,實例 2 和 3)。
對於 USB 無線移動通信設備類 (WMCDC) 設備,PDO 甚至可以表示多個接口集合。

所有用戶模式應用程序都可以與 USB 堆棧進行通信,
方法是加載 WinUSB 動態鏈接庫 (Winusb.dll) 並調用由此模塊公開的 WinUSB 功能。
  

WinUSB 驅動程序 (Winusb.sys)

 

WinUSB 動態鏈接庫 (Winusb.dll)

This section describes the following functions, exposed by Winusb.dll,
which user-mode client drivers and applications can use
to communicate with USB devices.
WinUSB functions require Windows XP or later.
You can use these functions in your C/C++ application
to communicate with your USB device.
Microsoft does not provide a managed API for WinUSB.

Routine                               Description

WinUsb_Initialize                     Creates a WinUSB handle for the device specified by a file handle.
WinUsb_Free                           Releases all of the resources that WinUsb_Initialize allocated.

WinUsb_ControlTransfer                Transmits control data over a default control endpoint.
WinUsb_ReadPipe                       Reads data from the specified pipe.
WinUsb_WritePipe                      Writes data to a pipe.

WinUsb_GetOverlappedResult            Retrieves the results of an overlapped operation on the specified file.

WinUsb_ResetPipe                      Resets the data toggle and clears the stall condition on a pipe.
WinUsb_AbortPipe                      Aborts all of the pending transfers for a pipe.
WinUsb_FlushPipe                      Discards any data that is cached in a pipe.

WinUsb_QueryPipe                      Retrieves information about a pipe that is associated with an interface.
WinUsb_QueryDeviceInformation         Retrieves information about the physical device 
                                      that is associated with a WinUSB handle.

WinUsb_GetDescriptor                  Gets the requested descriptor.
WinUsb_GetAssociatedInterface         Retrieves a handle for an associated interface.

WinUsb_QueryInterfaceSettings         Retrieves the interface descriptor for 
                                      the specified alternate interface settings for a particular interface handle.
WinUsb_GetCurrentAlternateSetting     Gets the current alternate interface setting for an interface.
WinUsb_SetCurrentAlternateSetting     Sets the alternate setting of an interface.

WinUsb_GetPowerPolicy                 Gets the power policy for a device.
WinUsb_SetPowerPolicy                 Sets the power policy for a device.

WinUsb_GetPipePolicy                  Gets the policy for a specific pipe (endpoint).
WinUsb_SetPipePolicy                  Sets the policy for a specific pipe (endpoint).
View Code
/*++

Copyright (c) 2002 Microsoft Corporation

Module Name:

        wusb.h

Abstract:

        Public interface to winusb.dll

Environment:

        Kernel Mode Only

Notes:

        THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
        KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
        IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
        PURPOSE.

        Copyright (c) 2001 Microsoft Corporation.  All Rights Reserved.


Revision History:

        11/19/2002 : created

Authors:

--*/

#ifndef __WUSB_H__
#define __WUSB_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <windows.h>
#include <winusbio.h>


typedef PVOID WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;

   
#pragma pack(1)

typedef struct _WINUSB_SETUP_PACKET {
    UCHAR   RequestType;
    UCHAR   Request;
    USHORT  Value;
    USHORT  Index;
    USHORT  Length;
} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET;

#pragma pack()



BOOL __stdcall
WinUsb_Initialize(
    IN HANDLE DeviceHandle,
    OUT PWINUSB_INTERFACE_HANDLE InterfaceHandle
    );


BOOL __stdcall
WinUsb_Free(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle
    );


BOOL __stdcall
WinUsb_GetAssociatedInterface(
    IN WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN UCHAR AssociatedInterfaceIndex,
    OUT PWINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle
    );



BOOL __stdcall
WinUsb_GetDescriptor(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN  UCHAR DescriptorType,
    IN  UCHAR Index,
    IN  USHORT LanguageID,
    OUT PUCHAR Buffer,
    IN  ULONG BufferLength,
    OUT PULONG LengthTransferred
    );

BOOL __stdcall
WinUsb_QueryInterfaceSettings(
    IN WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN UCHAR AlternateInterfaceNumber,
    OUT PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor
    );

BOOL __stdcall
WinUsb_QueryDeviceInformation(
    IN WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN ULONG InformationType,
    IN OUT PULONG BufferLength,
    OUT PVOID Buffer
    );

BOOL __stdcall
WinUsb_SetCurrentAlternateSetting(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN  UCHAR SettingNumber
    );

BOOL __stdcall
WinUsb_GetCurrentAlternateSetting(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    OUT PUCHAR SettingNumber
    );


BOOL __stdcall
WinUsb_QueryPipe(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN  UCHAR AlternateInterfaceNumber,
    IN  UCHAR PipeIndex,
    OUT PWINUSB_PIPE_INFORMATION PipeInformation
    );


BOOL __stdcall
WinUsb_SetPipePolicy(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN  UCHAR PipeID,
    IN  ULONG PolicyType,
    IN  ULONG ValueLength,
    IN  PVOID Value
    );

BOOL __stdcall
WinUsb_GetPipePolicy(
    IN WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN UCHAR PipeID,
    IN ULONG PolicyType,
    IN OUT PULONG ValueLength,
    OUT PVOID Value
    );

BOOL __stdcall
WinUsb_ReadPipe(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN  UCHAR PipeID,
    IN  PUCHAR Buffer,
    IN  ULONG BufferLength,
    OUT PULONG LengthTransferred,
    IN  LPOVERLAPPED Overlapped
    );

BOOL __stdcall
WinUsb_WritePipe(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN  UCHAR PipeID,
    IN  PUCHAR Buffer,
    IN  ULONG BufferLength,
    OUT PULONG LengthTransferred,
    IN  LPOVERLAPPED Overlapped    
    );

BOOL __stdcall
WinUsb_ControlTransfer(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN  WINUSB_SETUP_PACKET SetupPacket,
    IN  PUCHAR Buffer,
    IN  ULONG BufferLength,
    OUT PULONG LengthTransferred,
    IN  LPOVERLAPPED Overlapped    
    );

BOOL __stdcall
WinUsb_ResetPipe(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN  UCHAR PipeID
    );

BOOL __stdcall
WinUsb_AbortPipe(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN  UCHAR PipeID
    );

BOOL __stdcall
WinUsb_FlushPipe(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN  UCHAR PipeID
    );

BOOL __stdcall
WinUsb_SetPowerPolicy(
    IN  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN  ULONG PolicyType,
    IN  ULONG ValueLength,
    IN  PVOID Value
    );

BOOL __stdcall
WinUsb_GetPowerPolicy(
    IN WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN ULONG PolicyType,
    IN OUT PULONG ValueLength,
    OUT PVOID Value
    );

BOOL __stdcall
WinUsb_GetOverlappedResult(
    IN WINUSB_INTERFACE_HANDLE InterfaceHandle,
    IN LPOVERLAPPED lpOverlapped,
    OUT LPDWORD lpNumberOfBytesTransferred,
    BOOL bWait
    );
    

PUSB_INTERFACE_DESCRIPTOR __stdcall
WinUsb_ParseConfigurationDescriptor(
    IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
    IN PVOID StartPosition,
    IN LONG InterfaceNumber,
    IN LONG AlternateSetting,
    IN LONG InterfaceClass,
    IN LONG InterfaceSubClass,
    IN LONG InterfaceProtocol
    );

PUSB_COMMON_DESCRIPTOR __stdcall
WinUsb_ParseDescriptors(
    IN PVOID    DescriptorBuffer,
    IN ULONG    TotalLength,
    IN PVOID    StartPosition,
    IN LONG     DescriptorType
    );


#ifdef __cplusplus
}
#endif

                   
#endif //__WUSB_H__

在 Windows 8 中,Microsoft 為 WinUSB 提供的信息 (INF) 文件 (Winusb.inf) 

包含 USB\MS_COMP_WINUSB(作為設備標識符字符串)。
這可為 MS 操作系統描述符中擁有匹配的 WinUSB 兼容 ID 的那些設備
自動加載 Winusb.sys 作為功能驅動程序。此類設備稱為 WinUSB 設備。
硬件制造商不需要為其 WinUSB 設備分發 INF 文件,從而使最終用戶的驅動程序安裝過程更為簡單。

如果你是開發設備的 OEM 或獨立硬件供應商 (IHV),想要將 Winusb.sys 用作功能驅動程序,
並且想要自動加載驅動程序而不必提供自定義 INF,本主題中的信息對你適用。

什么是 WinUSB 設備

WinUSB 設備是一種通用串行總線 (USB) 設備,其 固件 定義了某些 Microsoft 操作系統 (OS) 特征描述符,
這些描述符將兼容 ID 報告為 "WINUSB"。

WinUSB 設備的用途是讓 Windows 將 Winusb.sys 作為設備的功能驅動程序載入,而無需自定義 INF 文件。
對於 WinUSB 設備,你無須為設備分發 INF 文件,對最終用戶而言,這大大簡化了驅動程序安裝過程。
相反,如果你需要提供自定義 INF,則不應將設備定義為 WinUSB 設備和在 INF 中指定設備的硬件 ID。

Microsoft 提供了 Winusb.inf,其中包含將 Winusb.sys 作為 USB 設備的設備驅動程序安裝所需的信息。

在 Windows 8 之前,要將 Winusb.sys 作為功能驅動程序加載,你需要提供自定義 INF。
自定義 INF 指定設備特定的硬件 ID,同時包括內置 Winusb.inf 的部分。
這些部分是實例化服務、復制內置二進制文件以及注冊設備接口 GUID(應用程序查找設備和與設備通訊必須使用 GUID)所必需的。
有關編寫自定義 INF 的信息,請參閱 WinUSB (Winusb.sys) 安裝。

在 Windows 8 中,內置 Winusb.inf 文件經過更新后可讓 Windows 自動將 INF 與 WinUSB 設備匹配。

使用內置 Winusb.inf 安裝 WinUSB 設備

在 Windows 8 中,內置 Winusb.inf 文件已更新。
INF 包括引用稱為 "USB\MS_COMP_WINUSB" 的兼容 ID 的安裝部分。

[Generic.Section.NTamd64]

%USB\MS_COMP_WINUSB.DeviceDesc%=WINUSB,USB\MS_COMP_WINUSB

更新的 INF 還包括稱為 "USBDevice" 的新安裝程序類。
"USBDevice" 安裝程序類可供這些 Microsoft 未提供內置驅動程序的設備使用。
通常,此類設備不屬於定義良好的 USB 類(如音頻、Bluetooth 等),並且需要自定義驅動程序。
如果你的設備是 WinUSB 設備,則該設備很可能不屬於 USB 類。
因此,你的設備必須安裝在 "USBDevice" 安裝程序類下。更新的 Winusb.inf 便於實現該要求。
注意,"USBDevice" 類不僅限於 WinUSB。
如果你有設備的自定義驅動程序,則可在自定義 INF 中使用 "USBDevice" 安裝程序類。

在設備枚舉過程中,USB 驅動程序堆棧會從設備讀取兼容 ID。
如果兼容 ID 是 "WINUSB",Windows 會將其用作設備標識符,
並在更新的內置 Winusb.inf 中查找匹配,然后將 Winusb.sys 作為設備的功能驅動程序加載。

對於 Windows 8 之前的 Windows 版本,更新的 Winusb.inf 可通過 Windows 更新提供。
如果你的計算機配置為自動獲取驅動程序更新,WinUSB 驅動程序將使用新的 INF 程序包進行安裝,無需任何用戶干預。

For versions of Windows earlier than Windows 8, the updated Winusb.inf is available through Windows Update.
If your computer is configured to get driver update automatically,
WinUSB driver will get installed without any user intervention by using the new INF package.

 

About using the USBDevice class:  
Do not use the "USB" setup class for unclassified devices.

That class is reserved for installing controllers, hubs, and composite devices.
Misusing the "USB" class can lead to significant reliability and performance issues.
For unclassified devices, use "USBDevice".
In Windows
8, to use "USBDevice" device class, simply add this to your INF.
[Version] Class
=USBDevice ClassGuid={88BAE032-5A81-49f0-BC3D-A4FF138216D6}
In Device Manager you will see a
new node USB Universal Serial Bus devices
and your device appears under that node.
In Windows
7, in addition to the preceding lines, you need to create these registry settings in the INF:

[Version]
Class=USBDevice
ClassGuid={88BAE032-5A81-49f0-BC3D-A4FF138216D6}
;---------- Add Registry Section ----------
[USBDeviceClassReg]
HKR,,,,"Universal Serial Bus devices"
HKR,,NoInstallClass,,1
HKR,,SilentInstall,,1
HKR,,IconPath,%REG_MULTI_SZ%," %systemroot%\system32\setupapi.dll,-20"

In Device Manager, you will see your device appear under USB Universal Serial Bus devices.
However, the device
class description is derived from the registry setting specified in your INF.
--Eliyas Yakub, Microsoft Windows USB Core Team

 


; winusbcompat.inf
; winusbcompat.cat
; Copyright (c) Microsoft Corporation. All rights reserved.
[Version] Signature="$Windows NT$" Class=USB Device ClassGuid={88BAE032-5A81-49f0-BC3D-A4FF138216D6} Provider=%WinPhone% CatalogFile=winusbcompat.cat DriverVer=05/11/2012,1.0 ; =============== Class section needed for downlevel OS =============== [ClassInstall32] AddReg = ClassInstall_AddReg [ClassInstall_AddReg] HKR,,,0,%ClassName% HKR,,IconPath,%REG_MULTI_SZ%,"%systemroot%\system32\setupapi.dll,-20" HKR,,NoInstallClass,,1 HKR,,BootCritical,,0 HKR,,Configurable,,1 ; ======================= End of Class section ======================== [DestinationDirs] DefaultDestDir = 12 [Manufacturer] %Generic.Mfg%=Generic.Section,NTx86,NTamd64,NTx86.6.0,NTamd64.6.0 ; =========================== Generic ================================= [Generic.Section.NTx86] ; Windows 2000 and XP %NULL.DeviceDesc%=NULL,USB\MS_COMP_WINUSB [Generic.Section.NTx86.6.0] ; Vista and later %USB\MS_COMP_WINUSB.DeviceDesc%=WinUsbDriver,USB\MS_COMP_WINUSB [Generic.Section.NTamd64] ; Windows 2000 and XP %NULL.DeviceDesc%=NULL,USB\MS_COMP_WINUSB [Generic.Section.NTamd64.6.0] ; Vista and later %USB\MS_COMP_WINUSB.DeviceDesc%=WinUsbDriver,USB\MS_COMP_WINUSB ; ======================= WinUsbDriver Sections ======================= [WinUsbDriver.NT] Include = Winusb.inf Needs = WINUSB.NT [WinUsbDriver.NT.Services] Include = Winusb.inf Needs = WINUSB.NT.Services ; =========================== NULL Sections =========================== [DummyReg] [NULL.NT] AddReg = DummyReg [NULL.NT.Services] AddService = , %NULL_SERVICE_INSTALL% ; ========================== Strings Section ========================== [Strings] ;Not localizable WinPhone="Windows Phone" REG_MULTI_SZ = 0x00010000 NULL_SERVICE_INSTALL = 0x00000002 ;Localizable Generic.Mfg="WinUsb Device" USB\MS_COMP_WINUSB.DeviceDesc="WinUsb Device" NULL.DeviceDesc="WinUsb Device (NULL)" ClassName = "Universal Serial Bus devices"

 

 

 

 

 

 

如何更改 WinUSB 設備的設備說明

對於 WinUSB 設備,設備管理器會顯示“WinUsb 設備”作為設備說明。
該字符串是從 Winusb.inf 派生出來的。如果有多個 WinUSB 設備,所有設備都會獲得相同的設備說明。

為了分別標識和區分設備管理器中的設備,Windows 8 在設備類中提供了一個新的屬性,
指示系統優先使用設備報告的說明(在設備的 iProduct 字符串描述符中),而不是 INF 中的說明。
Windows 8 中定義的 "USBDevice" 類設置此屬性。換句話說,
如果設備在 "USBDevice" 類下安裝,系統會查詢設備的設備說明,
並將設備管理器字符串設置為通過查詢檢索到的任何字符串。
在這種情況下,INF 中提供的設備說明將被忽略。 

新類屬性在 Windows 的較早版本中不受支持。在較早版本的 Windows 上,若要自定義設備說明,
你必須編寫自己的自定義 INF。( 不能自動加載 Winusb.sys 作為功能驅動程序 )

如何配置 WinUSB 設備

USB 設備在固件中存儲設備、設備接口和端點的標准描述符。 
獨立硬件供應商 (IHV) 還可以存儲特定於類和供應商的描述符。 
但是,這些描述符可以包含的信息類型有限。 

通常,IHV 必須使用 Windows Update 或 CD 之類的介質向他們的用戶
提供各種特定於設備的信息,比如圖片、按鈕、自定義驅動程序等等。

為了幫助 IHV 解決此問題,Microsoft 定義了 Microsoft 操作系統描述符。
IHV 可以使用這些描述符在固件中存儲如今通常單獨提供給客戶的大部分信息。
支持 Microsoft 操作系統描述符的 Windows 版本使用控制請求檢索信息,
使用它安裝和配置設備,無需任何用戶交互

Microsoft OS 描述符是什么?

Microsoft OS 描述符為 IHV 提供了一種方法,可以在設備固件中
將各種特定於供應商的信息存儲為 OS 功能描述符,而不是與設備分開提供給用戶。
可感知 Microsoft OS 描述符的 Windows 或 Windows 應用程序的版本
可以使用控制請求從設備中檢索該描述符,而無需其他的用戶交互。
尤其是,當初次插入設備時,Windows 可以自動檢索該描述符,
並使用該信息給用戶提供更完美的“即插即用”體驗。

Windows 支持什么類型的 OS 功能描述符?
任何作為功能描述符存儲的信息必須符合 Microsoft 已定義的標准格式之一。
未經 Microsoft 許可,不能定義或實現其他功能描述符。
Microsoft 已經定義了以下功能描述符。

Genre  -- 0x0000
此描述符是為 Windows 的未來版本設計的,現在還沒有規范。

Extended Compat ID   -- 0x0004
Windows 使用類和子類代碼幫助找到適合於 USB 設備的默認驅動程序。
但是,USB 設備工作組必須分配這些代碼。這意味着實現了新功能的設備常常沒有合適的類和子類代碼,
所以 Windows 無法使用該代碼選擇默認驅動程序。IHV 可以通過將該信息作為擴展的兼容 ID OS
功能描述符存儲在固件中來避免此問題。
然后 Windows 可以在設備插入時檢索此信息,並使用它幫助確定加載哪個默認驅動程序。

Extended Properties  -- 0x0005 
目前,可以在兩個層次上聲明 USB 設備的屬性:類層次和 devnode 層次。
該擴展屬性 OS 功能描述符允許供應商將其他屬性(比如幫助頁面、URL 和圖標)存儲在設備固件中。

 

哪些 Windows 版本支持 Microsoft OS 描述符?

描述符                        Windows 版本
OS 字符串描述符                Windows XP SP1 及更高版本
擴展兼容 ID OS 功能描述符       Windows XP SP2 及更高版本
擴展屬性 OS 功能描述符          Windows XP SP2 及更高版本
Genre OS 功能描述符           可能受未來的 Windows 版本支持

若要將 USB 設備標識為 WinUSB 設備,設備固件必須具有這些 Microsoft OS 描述符。

1) 支持 OS 字符串描述符

為了讓 USB 驅動程序堆棧了解設備支持擴展的特征描述符,
設備必須定義存儲在字符串索引 0xEE 處的 OS 字符串描述符
在枚舉過程中,驅動程序堆棧查詢字符串描述符。
如果存在描述符,驅動程序堆棧會假定設備包含一個或多個
OS 特征描述符和檢索這些特征描述符所需要的數據。

檢索的字符串描述符具有 bMS_VendorCode 字段值。
該值表示 USB 驅動程序堆棧必須用來檢索擴展特征描述符的供應商代碼。

 
         
#define bMS_VendorCode              ( 0x01 )
// "MSFT100" : index : 0xEE : langId : 0x0000
const U8 OS_StringDescritpor[ ] =
{ 0x12,  0x03,  'M',  0,  'S',  0,  'F',  0,  'T',  0,  '1',  0,  '0',  0,  '0',  0,  bMS_VendorCode,  0 };
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\<VVVVPPPPRRRR>

osvc
: 01 01

Indicates whether the operating system queried the device for Microsoft-Defined USB Descriptors.
If the previously-attempted OS descriptor query was successful, the value contains the vendor code
from the OS string descriptor.

  • 0x0000: The device did not provide a valid response to the Microsoft OS string descriptor request.

  • 0x01xx: The device provided a valid response to the Microsoft OS string descriptor request,
    where xx is the bMS_VendorCode contained in the response.

為什么必須將 OS 字符串描述符存儲在索引 0xEE 上?
一台支持 Microsoft OS 描述符的設備必須包含一個 OS 字符串描述符,
存儲在字符串索引 0xEE 位置。
該 OS 字符串描述符是一個標准的 USB 字符串描述符,具有以下功能:
1) 其存在表明該設備包含一個或多個 OS 功能描述符。
2) 它包含檢索相關的 OS 功能描述符所需的數據。
3) 它包含一個簽名字段,該字段可將 OS 字符串描述符和其他 IHV 可能選擇存儲在 0xEE 的字符串別開來。
4) 它包含一個允許未來修改 Microsoft OS 描述符的版本號。

如果在 0xEE 沒有字符串描述符,或者該索引位置的字符串描述符
不是有效的 OS 字符串描述符,則 Windows 假設該設備不包含任何 OS 功能描述符

 

2) 設置兼容 ID 特征描述符

匹配內置 Winusb.inf 和加載 WinUSB 驅動程序模塊所需要的擴展兼容 ID OS 特征描述符

擴展兼容 ID OS 特征描述符包含緊跟一個或多個功能部分的標題部分,具體取決於是否是復合設備。
標題部分指定整個描述符的長度、功能部分的數量以及版本號。

對於非復合設備,標題后緊跟一個僅與設備的接口關聯的功能部分。
該部分的 compatibleID 字段必須指定 "WINUSB" 作為字段值。

復合設備有多個功能部分。
每個功能部分的 compatibleID 字段必須指定 "WINUSB"

// "WINUSB\0\0" : wIndex : 0x0004
const U8 WINUSB_ExtendedCompatId_Descritpor[ ] =
{
  0x28, 0x00, 0x00, 0x00,                         // dwLength
  0x00, 0x01,                                     // bcdVersion
  0x04, 0x00,                                     // wIndex
  0x01,                                           // bCount
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,       // Reserved[7]
  0x00,                                           // bFirstInterfaceNumber
  0x01,                                           // RESERVED ( 0x01 )
  'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,       // compactiableID[8]
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subCompactiableID[8]
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00              // Reserved[6]
};

3) 注冊設備接口 GUID

注冊設備接口 GUID 所需要的擴展屬性 OS 特征描述符。
需要使用 GUID 從應用程序或服務查找設備、配置設備以及執行 I/O 操作。
在以前版本的 Windows 中,設備接口 GUID 注冊通過自定義 INF 完成。
從 Windows 8 開始,你的設備應使用擴展屬性 OS 特征描述符報告接口 GUID。

擴展屬性 OS 特征描述符包含緊跟一個或多個自定義屬性部分的標題部分。
標題部分描述整個擴展屬性描述符,包含其總長度、版本號以及自定義屬性部分的數量。
若要注冊設備接口 GUID,使用 GUID 生成唯一的設備接口 GUID, 請添加將 

bPropertyName 字段設置為 "DeviceInterfaceGUID" 且將 
wPropertyNameLength 設置為 40 字節的自定義屬性部分。
bPropertyData 字段設置為該 GUID,如 "{8FE6D4D7-49DD-41E7-9486-49AFC6BFE475}"。

注意,GUID 指定為 Unicode 字符串,且字符串長度為 78 字節(包括 Null 終止符)。
在設備枚舉過程中,USB 驅動程序堆棧隨后從擴展屬性 OS 特征描述符檢索 
DeviceInterfaceGUID 值,並在設備硬件注冊表項中注冊設備。
應用程序通過使用 
SetupDiXxx API 檢索該值。

// L"DeviceInterfaceGUID" : wIndex = 0x0005
// L"{12345678-1234-1234-1234-123456789ABC}"
const U8 WINUSB_ExtendedProperty_InterfaceGUID_Descritpor[ ] =
{
  0x8E, 0x00, 0x00, 0x00,     // dwTotalSize = Header + All sections
  0x00, 0x01,                 // bcdVersion
  0x05, 0x00,                 // wIndex
  0x01, 0x00,                 // wCount
  
  0x84, 0x00, 0x00, 0x00,     // dwSize -- this section
  
  0x01, 0x00, 0x00, 0x00,     // dwPropertyDataType
  
  0x28, 0x00,                 // wPropertyNameLength
  
  'D', 0x00, 'e', 0x00,       // bProperytName : WCHAR : L"DeviceInterfaceGUID"
  'v', 0x00, 'i', 0x00,       // bProperytName : WCHAR
  'c', 0x00, 'e', 0x00,       // bProperytName : WCHAR
  'I', 0x00, 'n', 0x00,       // bProperytName : WCHAR
  't', 0x00, 'e', 0x00,       // bProperytName : WCHAR
  'r', 0x00, 'f', 0x00,       // bProperytName : WCHAR
  'a', 0x00, 'c', 0x00,       // bProperytName : WCHAR
  'e', 0x00, 'G', 0x00,       // bProperytName : WCHAR
  'U', 0x00, 'I', 0x00,       // bProperytName : WCHAR
  'D', 0x00, 0x00, 0x00,      // bProperytName : WCHAR
  
  0x4E, 0x00, 0x00, 0x00,     // dwPropertyDataLength : 78 Bytes = 0x0000004E
  
  '{', 0x00, '1', 0x00,       // bPropertyData : WCHAR : L"{12345678-1234-1234-1234-123456789ABC}"
  '2', 0x00, '3', 0x00,       // bPropertyData
  '4', 0x00, '5', 0x00,       // bPropertyData
  '6', 0x00, '7', 0x00,       // bPropertyData
  '8', 0x00, '-', 0x00,       // bPropertyData
  '1', 0x00, '2', 0x00,       // bPropertyData
  '3', 0x00, '4', 0x00,       // bPropertyData
  '-', 0x00, '1', 0x00,       // bPropertyData
  '3', 0x00, '4', 0x00,       // bPropertyData
  '4', 0x00, '-', 0x00,       // bPropertyData
  '1', 0x00, '2', 0x00,       // bPropertyData
  '3', 0x00, '4', 0x00,       // bPropertyData
  '-', 0x00, '1', 0x00,       // bPropertyData
  '2', 0x00, '3', 0x00,       // bPropertyData
  '4', 0x00, '5', 0x00,       // bPropertyData
  '6', 0x00, '7', 0x00,       // bPropertyData
  '8', 0x00, '9', 0x00,       // bPropertyData
  'A', 0x00, 'B', 0x00,       // bPropertyData
  'C', 0x00, '}', 0x00,       // bPropertyData
  0x00, 0x00                  // bPropertyData
};

 

在枚舉過程中,USB 驅動程序堆棧會讀取擴展屬性特征描述符並在該項下創建注冊表項。 

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Enum\USB
\<Device Identifier>\<Instance Identifier>\Device Parameters

DeviceInterfaceGUID : {12345678-1234-1344-1234-123456789ABC}

啟用或禁用 WinUSB 電源管理功能

在 Windows 8 之前,要配置 WinUSB 的電源管理功能,
你必須在自定義 INF 的 HW.AddReg 部分中編寫注冊表項值。
在 Windows 8 中,你可以在設備中指定電源設置。
你可以通過擴展屬性 OS 特征描述符報告值,從而為該設備啟用或禁用 WinUSB 中的功能。
可配置的功能有兩個:選擇性掛起和系統喚醒。

選擇性掛起允許設備在閑置時進入低能耗狀態。
系統喚醒是指在系統處於低能耗狀態時,設備喚醒系統的功能。

屬性名 描述
DeviceIdleEnabled 此值設置為 1 表示設備在閑置時可關閉(選擇性掛起)。
DefaultIdleState 此值設置為 1 表示設備在閑置時可掛起(默認情況下)。
DefaultIdleTimeout 此值設置為 5000 毫秒表示確定設備處於閑置狀態所需等待的毫秒時長。
UserSetDeviceIdleEnabled 此值設置為 1 允許用戶控制設備啟用或禁用 USB 選擇性掛起的功能。設備“電源管理”屬性頁面上的復選框“允許計算機關閉此設備以節約電源”,用戶可選中或取消選中該復選框以啟用或禁用 USB 選擇性掛起。
SystemWakeEnabled

此值設置為 1 允許用戶控制設備從低能耗狀態喚醒系統的功能。如果啟用,“允許此設備喚醒計算機”復選框將顯示在設備電源管理屬性頁面中。用戶可選中或取消選中此復選框以啟用或禁用 USB 系統喚醒。

例如,要在設備上啟用選擇性掛起,請添加一個自定義屬性部分,將 

bPropertyName 字段設置為 Unicode 字符串,並將 "DeviceIdleEnabled" 和 
wPropertyNameLength 設置為 36 字節。 將 
bPropertyData 字段設置為 "0x00000001"。這些屬性值會存儲為 little-endian 32 位整數。

在枚舉過程中,USB 驅動程序堆棧會讀取擴展屬性特征描述符並在該項下創建注冊表項。 

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Enum\USB
\<Device Identifier>\<Instance Identifier>\Device Parameters

DeviceIdleEnabled : 0x00000001

 

 

成功枚舉 USB Device

 

 

枚舉過程

80 06 00 01 00 00 40 00 : GET_DESCRIPTOR - device
12 01 00 02 ff ff ff 40 ff ff ff ff 00 01 01 02 03 01
                        -----------          |  | serial number
00 05 01 00 00 00 00 00 : SET_ADDRESS | product string ** 80 06 00 01 00 00 12 00 : GET_DESCRIPTOR - device
12 01 00 02 ff ff ff 40 ff ff ff ff 00 01 01 02 03 01

80 06 00 02 00 00 ff 00 : GET_DESCRIPTOR  - configuration
09 02 20 00 01 01 00 80 fa
09 04 00 00 02 ff ff ff ff
07 05 81 02 40 00 00
07 05 02 02 40 00 00

80 06 ee 03 00 00 12 00 : GET_DESCRIPTOR - string : OS
      *****
12 03 4d 00 53 00 46 00 54 00 31 00 30 00 30 00 01 00 : "MSFT100"
                                                ** bMS_VendorCode

80 06 03 03 09 04 ff 00 : GET_DESCRIPTOR - string : serial number
16 03 30 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 00 : "0123456789"

c0 01 00 00 04 00 10 00 : CompactID - Header
28 00 00 00 00 01 04 00 01 00 00 00 00 00 00 00

c0 01 00 00 04 00 28 00 : CompactID - Header + Function
28 00 00 00 00 01 04 00 01 00 00 00 00 00 00 00 00 01 57 49 4e 55 53 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                                                      ****"WINUSB"*****       ***********************

80 06 00 03 00 00 ff 00 : GET_DESCRIPTOR - string : language ID
04 03 09 04

80 06 02 03 09 04 ff 00 : GET_DESCRIPTOR - string : product
16 03 55 00 53 00 42 00 20 00 44 00 65 00 76 00 69 00 63 00 65 00 : "USB Device"

80 06 00 06 00 00 0a 00 : GET_DESCRIPTOR - device_qualifier
stall

c1 01 00 00 05 00 0a 00 : Property - Header
8e 00 00 00 00 01 05 00 01 00

c1 01 00 00 05 00 8e 00 : Property - Header + Data : L"DeviceInterfaceGUID"
8e 00 00 00 00 01 05 00 01 00
84 00 00 00
01 00 00 00
28 00
44 00 65 00 76 00 69 00 63 00 65 00 49 00 6e 00 74 00 65 00 72 00 66 00 61 00 63 00 65 00 47 00 55 00 49 00 44 00 00 00

4e 00 00 00 : L"{12345678-1234-1234-1234-123456789ABC"
7b 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 00
2d 00 31 00 32 00 33 00 34 00
2d 00 31 00 33 00 34 00 34 00
2d 00 31 00 32 00 33 00 34 00 2d 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 00 41 00 42 00 43 00
7d 00 00 00

80 06 00 01 00 00 12 00 : GET_DESCRIPTOR - device
12 01 00 02 ff ff ff 40 ff ff ff ff 00 01 01 02 03 01

80 06 00 02 00 00 09 00 : GET_DESCRIPTOR  - configuration only
09 02 20 00 01 01 00 80 fa

80 06 00 02 00 00 20 00 : GET_DESCRIPTOR  - configuration full
09 02 20 00 01 01 00 80 fa 09 04 00 00 02 ff ff ff ff 07 05 81 02 40 00 00 07 05 02 02 40 00 00

80 00 00 00 00 00 02 00 : GET_STATUS - device
01 00 : Self Power

00 09 01 00 00 00 00 00 : SET_CONFIGURATION **

自定義 Winusb.inf 安裝 WinUSB.sys 作為設備的功能驅動程序

若要使用 WinUSB 作為設備的功能驅動程序,請創建一個驅動程序包。該驅動程序包必須包含下列文件:

  • WinUSB 輔助安裝程序 (Winusbcoinstaller.dll)
  • KMDF 輔助安裝程序 (WdfcoinstallerXXX.dll)
  • 用來安裝 Winusb.sys 作為設備的功能驅動程序的 .inf 文件。
  • 簽名的數據包目錄文件。 在 x64 版本的 Windows Vista 上安裝 WinUSB 時需要此文件。

A. 編寫 WinUSB 安裝的自定義 INF

作為驅動程序包的一部分,你需要提供 .inf 文件,該文件將安裝 Winusb.sys 作為 USB 設備的功能驅動程序。

下面的示例 .inf 文件西那是的針對大多數 USB 設備的 WinUSB 安裝,但進行了一些修改,
例如將相應部分名稱中的 USB_Install 更改為相應的DDInstall 值。
你還應根據需要更改版本、制造商和型號部分。例如,提供相應的制造商名稱、已簽名目錄文件的名稱、
正確的設備類以及設備的供應商標識 (VID) 和產品標識 (PID)。

還應通知安裝程序類已設置為 "USBDevice"。
供應商可以對不屬於其他類以及不是 USB 主控制器或集線器的設備使用 "USBDevice" 安裝程序類
如果要安裝 WinUSB 作為 USB 復合設備中任一功能的功能驅動程序,必須在 INF 中提供中與該功能關聯的硬件 ID。
可以從“設備管理器”的 devnode 屬性中獲取該功能的硬件 ID。硬件 ID 字符串格式為 "USB\VID_vvvv&PID_pppp"。

下面的 INF 安裝 WinUSB 作為基於 x64 系統上 OSR USB FX2 主板的功能驅動程序。

;
;
; Installs WinUsb
;

[Version]
Signature = "$Windows NT$"
Class     = USBDevice
ClassGUID = {88BAE032-5A81-49f0-BC3D-A4FF138216D6}
Provider  = %ManufacturerName%
CatalogFile = WinUSBInstallation.cat
DriverVer=09/04/2012,13.54.20.543

; ========== Manufacturer/Models sections ===========

[Manufacturer]
%ManufacturerName% = Standard,NTamd64

[Standard.NTamd64]
%DeviceName% =USB_Install, USB\VID_0547&PID_1002

; ========== Class definition ===========

[ClassInstall32]
AddReg = ClassInstall_AddReg

[ClassInstall_AddReg]
HKR,,,,%ClassName%
HKR,,NoInstallClass,,1
HKR,,IconPath,%REG_MULTI_SZ%,"%systemroot%\system32\setupapi.dll,-20"
HKR,,LowerLogoVersion,,5.2

; =================== Installation ===================

[USB_Install]
Include = winusb.inf
Needs   = WINUSB.NT

[USB_Install.Services]
Include =winusb.inf
Needs   = WINUSB.NT.Services

[USB_Install.HW]
AddReg=Dev_AddReg

[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{9f543223-cede-4fa3-b376-a25ce9a30e74}"

; [DestinationDirs]
; If your INF needs to copy files, you must not use the DefaultDestDir directive here.  
; You must explicitly reference all file-list-section names in this section.

; =================== Strings ===================

[Strings]
ManufacturerName=""
ClassName="Universal Serial Bus devices"
DeviceName="Fx2 Learning Kit Device"
REG_MULTI_SZ = 0x00010000

除了特定於設備的值和以下列表中記錄的若干問題,你可以使用這些部分和指令為任何 USB 設備安裝 WinUSB。
這些列表項介紹了前面的 .inf 文件中的 Includes 和 Directives

  • USB_Install
    安裝 WinUSB 需要 USB_Install 部分中的 Include 和 Needs 指令。不應修改這些指令。
  • USB_Install.ServicesUSB_Install.Services 部分中的 
    Include 指令包含系統提供的用於 WinUSB 的 .inf (WinUSB.inf)。
    如果該 .inf 文件在目標系統中尚未准備就緒,將由 WinUSB 輔助安裝程序進行安裝。
    Needs 指令可指定 WinUSB.inf 中包含安裝 Winusb.sys 作為設備的功能驅動程序所需的信息的部分。不應修改這些指令。

    注意  
    由於 Windows XP 不提供 WinUSB.inf,因此需要通過輔助安裝程序將該文件復制到 Windows XP 系統,
    或為 Windows XP 提供單獨修改的部分。

  • USB_Install.HW:此部分是 .inf 文件的密鑰,可為你的設備指定設備接口全局唯一標識符。
    AddReg 指令在標准注冊表值中設置指定的接口 GUID。
    當 Winusb.sys 作為設備的功能驅動程序加載之后,它讀取注冊表項 DeviceInterfaceGUIDs
    的值並使用指定的 GUID 來表示設備接口。你應將此示例中的 GUID 替換為專門為設備指定的 GUID。
    如果設備的協議更改,請創建新的設備接口 GUID。
    注意  
    用戶模式軟件必須調用 SetupDiGetClassDevs 才能枚舉與在 DeviceInterfaceGUIDs
    項下指定的任一設備接口類關聯的注冊設備接口。
    SetupDiGetClassDevs 返回用戶模式軟件稍后必須傳遞給 WinUsb_Initialize 
    例程的設備的設備句柄,才能獲得設備接口的 WinUSB 句柄。

下面的 INF 安裝 WinUSB 作為基於 x64 系統上 OSR USB FX2 主板的功能驅動程序。
該示例顯示包含 WDF 輔助安裝程序的 INF。

;
;
; Installs WinUsb
;

[Version]
Signature = "$Windows NT$"
Class     = USBDevice
ClassGUID = {88BAE032-5A81-49f0-BC3D-A4FF138216D6}
Provider  = %ManufacturerName%
CatalogFile = WinUSBInstallation.cat
DriverVer=09/04/2012,13.54.20.543

; ========== Manufacturer/Models sections ===========

[Manufacturer]
%ManufacturerName% = Standard,NTamd64

[Standard.NTamd64]
%DeviceName% =USB_Install, USB\VID_0547&PID_1002

; ========== Class definition ===========

[ClassInstall32]
AddReg = ClassInstall_AddReg

[ClassInstall_AddReg]
HKR,,,,%ClassName%
HKR,,NoInstallClass,,1
HKR,,IconPath,%REG_MULTI_SZ%,"%systemroot%\system32\setupapi.dll,-20"
HKR,,LowerLogoVersion,,5.2

; =================== Installation ===================

[USB_Install]
Include = winusb.inf
Needs   = WINUSB.NT

[USB_Install.Services]
Include =winusb.inf
Needs   = WINUSB.NT.Services

[USB_Install.HW]
AddReg=Dev_AddReg

[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{9f543223-cede-4fa3-b376-a25ce9a30e74}"

[USB_Install.CoInstallers]
AddReg=CoInstallers_AddReg
CopyFiles=CoInstallers_CopyFiles

[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01011.dll,WdfCoInstaller","WinUsbCoInstaller2.dll"

[CoInstallers_CopyFiles]
WinUsbCoInstaller2.dll
WdfCoInstaller01011.dll

[DestinationDirs]
; If your INF needs to copy files, you must not use the DefaultDestDir directive here.  
CoInstallers_CopyFiles=11
; ================= Source Media Section =====================

[SourceDisksNames]
1 = %DiskName%

[SourceDisksFiles]
WinUsbCoInstaller2.dll=1
WdfCoInstaller01011.dll=1


; =================== Strings ===================

[Strings]
ManufacturerName=""
ClassName="Universal Serial Bus devices"
DeviceName="Fx2 Learning Kit Device"
REG_MULTI_SZ = 0x00010000
  • USB_Install.CoInstallers
    此部分(包含引用的 AddReg 和 CopyFiles 部分)包含安裝 WinUSB 和 KMDF 輔助安裝程序所需的數據和說明,
    並將它們與設備關聯。大多數 USB 設備可以使用這些部分和指令,不用進行任何修改。
  • 基於 x86 和 x64 版本的 Windows 有單獨的輔助安裝程序。

    注意  
    每個輔助安裝程序都有免費的檢查版本。
    使用免費版本在免費 Windows 版本(包括所有的零售版本)上安裝 WinUSB。
    使用檢查版本(帶有“_chk”后綴)在檢查版本的 Windows 上安裝 WinUSB。

Winusb.sys 在每次加載時都會注冊一個設備接口,
該設備接口具有在注冊表中的 DeviceInterfaceGUIDs 項下面指定的設備接口類。

HKR,,DeviceInterfaceGUIDs, 0x10000,"{D696BFEB-1734-417d-8A04-86D01071C512}"

注意  
如果將可再發行版本 WinUSB 數據包用於 Windows XP 或 Windows Server 2003,
請確保未在卸載程序包里卸載 WinUSB。其他 USB 設備可能正在使用 WinUSB,
因此其二進制文件必須保留在共享文件夾中。

B. 安裝 Winusb.sys 設備的功能驅動程序

  1. 安裝 Windows 驅動程序工具包。

  2. 在連有 USB 的計算機上創建驅動程序包文件夾。例如,c:\UsbDevice。
  3. 將 WinUSB 輔助安裝程序(WinusbcoinstallerX.dll)從 WinDDK\BuildNumber\redist\winusb 
    文件夾復制到驅動程序包文件夾。

    如有必要,WinUSB 輔助安裝程序 (Winusbcoinstaller.dll) 在目標系統中安裝 WinUSB。
    WDK 根據系統架構的不同(基於 x86、基於 x64 和基於 Itanium 的系統)包含三個版本的輔助安裝程序。
    它們共同的名字是 WinusbcoinstallerX.dll,位於WinDDK\BuildNumber\redist\winusb 文件夾中相應的子目錄下。

  4. 將 KMDF 輔助安裝程序 (WdfcoinstallerXXX.dll) 從 WinDDK\BuildNumber\redist\wdf
    文件夾復制到驅動程序包文件夾中。

    如有必要,KMDF 輔助安裝程序 (WdfcoinstallerXXX.dll) 在目標系統中安裝正確版本的 KMDF。
    WinUSB 輔助安裝程序的版本必須與 KMDF 輔助安裝程序的版本匹配,
    因為基於 KMDF 的客戶端驅動程序(如 Winusb.sys)要求在系統中正確安裝對應版本的 KMDF 架構。
    例如,Winusbcoinstaller2.dll 要求 KMDF 版本為 1.9,該輔助安裝程序由 Wdfcoinstaller01009.dll 安裝。
    x86 和 x64 版本的 WdfcoinstallerXXX.dll 包含在 WinDDK\BuildNumber\redist\wdf 文件夾下的 WDK 中。
    下表顯示要用於目標系統的 WinUSB 輔助安裝程序及其關聯的 KMDF 輔助安裝程序

    WinUSB 輔助安裝程序 KMDF 庫版本 KMDF 輔助安裝程序
    Winusbcoinstaller.dll 要求 KMDF 1.5 或更高版本

    Wdfcoinstaller01005.dll

    Wdfcoinstaller01007.dll

    Wdfcoinstaller01009.dll

    Winusbcoinstaller2.dll 要求 KMDF 1.9 或更高版本 Wdfcoinstaller01009.dll
    Winusbcoinstaller2.dll 要求 KMDF 1.11 或更高版本 WdfCoInstaller01011.dll

     

  5. 編寫 .inf 文件,該文件安裝 Winusb.sys 作為 USB 設備的功能驅動程序。
  6. 為數據包創建簽名的目錄文件 在 x64 版本的 Windows 上安裝 WinUSB 時需要此文件。
  7. 將 USB 設備連接到計算機。
  8. 打開“設備管理器”安裝驅動程序。
    根據“更新驅動程序軟件”向導的說明執行操作,並選擇手動安裝。
    你需要提供驅動程序包文件夾的位置才能完成安裝。

如何通過 WinUSB 功能訪問 USB 設備 < WinUsb.dll >

與構建設備 I/O 控制請求來執行標准 USB 操作(如配置設備、發送控制請求以及與設備互傳數據)不同,應用程序調用等效的 WinUSB 功能。

Winusb.dll 使用應用程序提供的數據構建適當的設備 I/O 控制請求,然后將請求發送到 Winusb.sys 進行處理。
為與 USB 堆棧通信,WinUSB 功能使用與應用程序的請求對應的適當 IOCTL 調用 DeviceIoControl
當請求完成時,WinUSB 功能將 Winusb.sys 返回的任何信息(例如來自讀請求的數據)再回傳到調用進程。
如果調用 DeviceIoControl 成功,它將返回非零值。如果調用失敗或者掛起(不立即處理),DeviceIoControl 將返回零值。
如果出現錯誤,應用程序可以調用 GetLastError 以獲得更詳細的錯誤消息。

使用 WinUSB 功能與設備通信比實現驅動程序更簡單。不過,請注意以下限制:

  • WinUSB 功能一次僅允許一個應用程序與設備通信。如果需要多個應用程序同時與設備通信,則必須實現一個函數驅動程序。
  • WinUSB 功能不支持在同步終結點之間傳輸流數據。同步傳輸需要一個內核模式的函數驅動程序。
  • WinUSB 功能不支持已經提供內核模式支持的設備。此類設備的示例包括調制解調器和網絡適配器,二者分別由電話服務 API (TAPI) 和 NDIS 支持。
  • 對於多功能設備,可以使用設備的 INF 文件分別為每個 USB 函數指定內置內核模式驅動程序或 Winusb.sys。
    不過,對於某個特定函數,只能指定其中一個選項,而不能同時指定兩個。

可以將 Winusb.sys 安裝為 USB 復合設備中函數的函數驅動程序。
這需要在 INF 中進行一些硬件 ID 修改。

Winusb.sys 也是 UMDF 函數驅動程序與關聯的設備之間鏈接的關鍵部分。
Winusb.sys 作為高層篩選器驅動程序安裝在設備的內核模式堆棧中。
應用程序通過與設備的 UMDF 函數驅動程序通信來發送讀、寫或設備 I/O 控制請求。
驅動程序與框架交互,后者將請求傳遞到 Winusb.sys。
Winusb.sys 隨后處理該請求並將其傳遞到協議驅動程序,最后傳遞到設備。
任何響應都通過反向路徑返回。
Winusb.sys 還作為設備堆棧的即插即用和電源所有者 (PPO)。

注意  
WinUSB 功能需要 Windows XP 或更高版本。
你可以在 C/C++ 應用程序中使用這些函數與你的 USB 設備通信。
Microsoft 不支持為 WinUSB 提供托管 API。

創建設備的文件句柄

要訪問 USB 設備,需要設備的有效文件句柄。可以通過調用 CreateFile 創建此句柄。
此函數向 Winusb.sys 請求一個應用程序可用來與設備通信的設備句柄。
CreateFile 需要請求句柄的設備的設備路徑。
要獲取設備路徑,你需要用於安裝 Winusb.sys 的 INF 文件中指定的設備接口 GUID。
通過使用 SetupAPI 例程,你可以枚舉指定設備接口類中的所有設備並檢索設備的設備路徑。

使用以下步驟可創建 USB 設備的文件句柄。

  1. 調用 SetupDiGetClassDevs 獲取“設備信息集”的句柄,“設備信息集”是一個陣列,
    包含有關與指定的設備接口類匹配的所有安裝的設備的信息。
    陣列中名為“設備接口”的每個元素對應於一個已經安裝並向系統注冊的設備。
    設備接口類通過傳遞在 INF 文件中定義的設備接口 GUID 進行標識。該函數將 HDEVINFO 句柄返回到設備信息集。

  2. 調用 SetupDiEnumDeviceInterfaces 枚舉設備信息集中的設備接口並獲取有關設備接口的信息。

    此調用需要以下各項:

    • 已初始化的調用程序分配的 SP_DEVICE_INTERFACE_DATA 結構,其 cbSize 成員設置為結構的大小。
    • 步驟 1 中的 HDEVINFO 句柄。
    • 在 INF 文件中定義的接口 GUID。

    SetupDiEnumDeviceInterfaces 查找設備接口的指定索引的設備信息集陣列,
    並使用有關該接口的基本數據填充初始化SP_DEVICE_INTERFACE_DATA 結構。

    注意  
    要枚舉設備信息集中的所有設備接口,請在循環中調用  SetupDiEnumDeviceInterfaces
    直到函數返回  FALSE 並且失敗錯誤代碼為 ERROR_NO_MORE_ITEMS。
    通過調用  GetLastError 可以檢索 ERROR_NO_MORE_ITEMS 錯誤代碼。
    每迭代一次,將遞增一次成員索引。

    或者,你可以調用 SetupDiEnumDeviceInfo,該函數可以枚舉設備信息集並返回調用方分配的 
    SP_DEVINFO_DATA 結構中索引指定的有關設備接口元素的信息。
    然后可以將引用傳遞到 
    SetupDiEnumDeviceInterfaces 函數的 DeviceInfoData 參數中的此結構。

  3. 調用 SetupDiGetDeviceInterfaceDetail 獲取設備接口的詳細信息。
    信息在 SP_DEVICE_INTERFACE_DETAIL_DATA 結構中返回。
    由於 SP_DEVICE_INTERFACE_DETAIL_DATA 結構的大小各不相同,
    你需要調用 SetupDiGetDeviceInterfaceDetail 兩次。
    第一次調用獲取要為 SP_DEVICE_INTERFACE_DETAIL_DATA 結構分配的緩沖區大小。
    第二次調用使用有關接口的詳細信息填充分配的緩沖區。調用 CreateFile 創建設備的文件句柄。在此步驟中,你需要一個 Null 結尾的字符串,
    1. 調用 SetupDiGetDeviceInterfaceDetail 並將 DeviceInterfaceDetailData 參數設置為 NULL
      此函數在requiredlength 參數中返回正確的緩沖區大小。此調用失敗並顯示 ERROR_INSUFFICIENT_BUFFER 錯誤代碼。
      此錯誤代碼是預期行為。
    2. 基於在 requiredlength 參數中檢索的正確緩沖區大小為 SP_DEVICE_INTERFACE_DETAIL_DATA 結構分配內存。
    3. 再次調用 SetupDiGetDeviceInterfaceDetail 並將其作為引用傳遞到 DeviceInterfaceDetailData 參數中的初始化結構。
      在該函數返回時,該結構將填充有關接口的詳細信息。
      設備路徑在 SP_DEVICE_INTERFACE_DETAIL_DATA 結構的 DevicePath成員中。


  4. 其中包含在SP_DEVICE_INTERFACE_DETAIL_DATA 結構的 DevicePath 成員中接收的設備路徑。
    將設備路徑傳遞到 CreateFile 以獲取設備的文件句柄。
    確保設置了 FILE_FLAG_OVERLAPPED 標志,因為 WinUSB 信賴於此設置。

下面的示例代碼創建一個支持對設備進行同步讀寫訪問的文件句柄。

View Code
BOOL GetDeviceHandle( GUID guidDeviceInterface, PHANDLE hDeviceHandle )
{
  if ( guidDeviceInterface == GUID_NULL )
  {
    return FALSE;
  }

  BOOL bResult = TRUE;
  HDEVINFO hDeviceInfo;
  SP_DEVINFO_DATA DeviceInfoData;

  SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
  PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = NULL;

  ULONG requiredLength = 0;

  LPTSTR lpDevicePath = NULL;

  DWORD index = 0;

  // Get information about all the installed devices for the specified
  // device interface class.
  hDeviceInfo = SetupDiGetClassDevs( &guidDeviceInterface, NULL, NULL,
    DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );

  if ( hDeviceInfo == INVALID_HANDLE_VALUE )
  {
    // ERROR 
    printf( "Error SetupDiGetClassDevs: %d.\n", GetLastError( ) );
    goto done;
  }

  //Enumerate all the device interfaces in the device information set.
  DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

  for ( index = 0; SetupDiEnumDeviceInfo( hDeviceInfo, index, &DeviceInfoData );
      index++ )
  {
    //Reset for this iteration
    if ( lpDevicePath )
    {
      LocalFree( lpDevicePath );
    }
    if ( pInterfaceDetailData )
    {
      LocalFree( pInterfaceDetailData );
    }

    deviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);

    //Get information about the device interface.
    bResult = SetupDiEnumDeviceInterfaces( hDeviceInfo, &DeviceInfoData,
      &guidDeviceInterface, 0, &deviceInterfaceData );

    // Check if last item
    if ( GetLastError( ) == ERROR_NO_MORE_ITEMS )
    {
      break;
    }

    //Check for some other error
    if ( !bResult )
    {
      printf( "Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError( ) );
      goto done;
    }

    //Interface data is returned in SP_DEVICE_INTERFACE_DETAIL_DATA
    //which we need to allocate, so we have to call this function twice.
    //First to get the size so that we know how much to allocate
    //Second, the actual call with the allocated buffer

    bResult = SetupDiGetDeviceInterfaceDetail( hDeviceInfo,
      &deviceInterfaceData, NULL, 0, &requiredLength, NULL );

    //Check for some other error
    if ( !bResult )
    {
      if ( ( ERROR_INSUFFICIENT_BUFFER == GetLastError( ) )
        && ( requiredLength > 0 ) )
      {
        //we got the size, allocate buffer
        pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc(
          LPTR, requiredLength );

        if ( !pInterfaceDetailData )
        {
          // ERROR 
          printf( "Error allocating memory for the device detail buffer.\n" );
          goto done;
        }
      }
      else
      {
        printf( "Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError( ) );
        goto done;
      }
    }

    //get the interface detailed data
    pInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

    //Now call it with the correct size and allocated buffer
    bResult = SetupDiGetDeviceInterfaceDetail( hDeviceInfo,
      &deviceInterfaceData, pInterfaceDetailData, requiredLength, NULL,
      &DeviceInfoData );

    //Check for some other error
    if ( !bResult )
    {
      printf( "Error SetupDiGetDeviceInterfaceDetail: %d.\n", GetLastError( ) );
      goto done;
    }

    //copy device path

    size_t nLength = wcslen( pInterfaceDetailData->DevicePath ) + 1;
    lpDevicePath = (TCHAR *) LocalAlloc( LPTR, nLength * sizeof(TCHAR) );
    StringCchCopy( lpDevicePath, nLength, pInterfaceDetailData->DevicePath );
    lpDevicePath[ nLength - 1 ] = 0;

    printf( "Device path:  %s\n", lpDevicePath );

  }

  if ( !lpDevicePath )
  {
    //Error.
    printf( "Error %d.", GetLastError( ) );
    goto done;
  }

  //Open the device
  *hDeviceHandle = CreateFile( lpDevicePath, GENERIC_READ | GENERIC_WRITE,
    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
    FILE_FLAG_OVERLAPPED, NULL );

  if ( *hDeviceHandle == INVALID_HANDLE_VALUE )
  {
    //Error.
    printf( "Error %d.", GetLastError( ) );
    goto done;
  }

  done: LocalFree( lpDevicePath );
  LocalFree( pInterfaceDetailData );
  bResult = SetupDiDestroyDeviceInfoList( hDeviceInfo );

  return bResult;
}

獲取設備的 WinUSB 接口句柄

接下來,使用設備的文件句柄創建設備上第一個(默認)接口的 WinUSB 接口句柄。
WinUSB 例程使用此句柄標識目標設備而非文件句柄。要獲取 WinUSB 接口句柄,
請通過傳遞在創建設備的文件句柄中創建的文件句柄調用 WinUsb_Initialize
使用后續調用中收到的句柄從設備中獲取信息,然后將 I/O 請求發送到該設備。

以下示例代碼使用上一步中創建的文件句柄初始化 WinUSB,並檢索設備接口的 WinUSB 接口句柄的指針。

BOOL GetWinUSBHandle( HANDLE hDeviceHandle,
  PWINUSB_INTERFACE_HANDLE phWinUSBHandle )
{
  if ( hDeviceHandle == INVALID_HANDLE_VALUE )
  {
    return FALSE;
  }

  BOOL bResult = WinUsb_Initialize( hDeviceHandle, phWinUSBHandle );
  if ( !bResult )
  {
    //Error.
    printf( "WinUsb_Initialize Error %d.", GetLastError( ) );
    return FALSE;
  }

  return bResult;
}

查詢設備以獲取 USB 描述符

接下來,查詢設備以獲取特定於 USB 的信息,如設備速度、接口描述符、相關終結點及其管道。
此過程類似於 USB 設備驅動程序使用的過程。不過,應用程序通過調用 WinUSB 功能
而非 WDF 框架庫或任何 Windows WDM USB 客戶端支持例程完成設備查詢。

下表顯示了你可以調用以獲取特定於 USB 的信息的 WinUSB 功能:

  • 設備描述符

    調用 WinUsb_QueryDeviceInformation 從設備的設備描述符請求信息。
    要獲取設備的速度,可在 InformationType 參數中設置 DEVICE_SPEED (0x01)。
    此函數返回 LowSpeed (0x01) 或 HighSpeed (0x03)。

  • 接口描述符

    調用 WinUsb_QueryInterfaceSettings 並傳遞設備的接口句柄,以獲得對應的接口描述符。
    WinUSB 接口句柄對應於第一個接口。一些 USB 設備(如 OSR Fx2 設備)僅支持一個沒有任何備用設置的接口。
    因此,對於這些設備,AlternateSettingNumber 參數設置為零,並且僅調用一次該函數。
    WinUsb_QueryInterfaceSettings 使用有關接口的信息填充調用方分配的 USB_INTERFACE_DESCRIPTOR 
    結構(在 
    UsbAltInterfaceDescriptor 參數中傳入)。
    例如,接口中的終結點數在 
    USB_INTERFACE_DESCRIPTOR 的 bNumEndpoints成員中設置。

    對於支持多個接口的設備,通過在 AssociatedInterfaceIndex 參數中指定備用設置調用 
    WinUsb_GetAssociatedInterface 以獲取關聯接口的接口句柄。

  • 終結點

    調用 WinUsb_QueryPipe 獲取有關每個接口每個終結點的信息。
    WinUsb_QueryPipe 使用有關指定終結點的管道填充調用方分配的 WINUSB_PIPE_INFORMATION 結構。
    終結點的管道由從零開始的索引標識,並且必須小於在上次調用
    WinUsb_QueryInterfaceSettings 
    中檢索的接口描述符的 
    bNumEndpoints 成員中的值。
    OSR Fx2 設備有一個具有三個終結點的接口。對於此設備,
    函數的 
    AlternateInterfaceNumber 參數設置為 0,並且 PipeIndex 參數的值從 0 到 2 變化。

    若要確定管道類型,請檢查 WINUSB_PIPE_INFORMATION 結構的 PipeInfo 成員。
    此成員設置為 USBD_PIPE_TYPE 枚舉值之一:

    UsbdPipeTypeControl、UsbdPipeTypeIsochronous、UsbdPipeTypeBulk 或 UsbdPipeTypeInterrupt。

    OSR USB FX2 設備支持中斷管道、批量傳入管道和批量傳出管道,
    因此 PipeInfo 設置為 UsbdPipeTypeInterrupt 或 UsbdPipeTypeBulk。

    UsbdPipeTypeBulk 值標識批量管道,但不提供管道的方向。
    方向信息在管道地址的高位編碼,該地址存儲在 WINUSB_PIPE_INFORMATION結構的 PipeId 成員中。
    確定管道方向的最簡單方法是將 PipeId 值從 Usb100.h 傳遞到下列宏之一:

    • 如果方向是傳入,則 USB_ENDPOINT_DIRECTION_IN (PipeId) 宏返回 TRUE
    • 如果方向是傳出,則 USB_ENDPOINT_DIRECTION_OUT(PipeId) 宏返回 TRUE

    應用程序使用 PipeId 值在對 WinUsb_ReadPipe 等 WinUSB 功能的調用中標識哪個管道用於數據傳輸
    因此該示例存儲所有三個 PipeId 值以供日后使用。

以下示例代碼獲取由 WinUSB 接口句柄指定的設備的速度。

View Code
BOOL GetUSBDeviceSpeed( WINUSB_INTERFACE_HANDLE hDeviceHandle,
  UCHAR* pDeviceSpeed )
{
  if ( !pDeviceSpeed || hDeviceHandle == INVALID_HANDLE_VALUE )
  {
    return FALSE;
  }

  BOOL bResult = TRUE;

  ULONG length = sizeof(UCHAR);

  bResult = WinUsb_QueryDeviceInformation( hDeviceHandle, DEVICE_SPEED, &length,
    pDeviceSpeed );
  if ( !bResult )
  {
    printf( "Error getting device speed: %d.\n", GetLastError( ) );
    goto done;
  }

  if ( *pDeviceSpeed == LowSpeed )
  {
    printf( "Device speed: %d (Low speed).\n", *pDeviceSpeed );
    goto done;
  }
  if ( *pDeviceSpeed == FullSpeed )
  {
    printf( "Device speed: %d (Full speed).\n", *pDeviceSpeed );
    goto done;
  }
  if ( *pDeviceSpeed == HighSpeed )
  {
    printf( "Device speed: %d (High speed).\n", *pDeviceSpeed );
    goto done;
  }

  done: return bResult;
}

以下示例代碼查詢由 WinUSB 接口句柄指定的 USB 設備的各種描述符。
此示例函數檢索支持的終結點類型及其管道標識符。
該示例存儲所有三個 PipeId 值以供日后使用。

View Code
struct PIPE_ID
{
  UCHAR PipeInId;
  UCHAR PipeOutId;
};

BOOL QueryDeviceEndpoints( WINUSB_INTERFACE_HANDLE hDeviceHandle,
  PIPE_ID* pipeid )
{
  if ( hDeviceHandle == INVALID_HANDLE_VALUE )
  {
    return FALSE;
  }

  BOOL bResult = TRUE;

  USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
  ZeroMemory( &InterfaceDescriptor, sizeof(USB_INTERFACE_DESCRIPTOR) );

  WINUSB_PIPE_INFORMATION Pipe;
  ZeroMemory( &Pipe, sizeof(WINUSB_PIPE_INFORMATION) );

  bResult = WinUsb_QueryInterfaceSettings( hDeviceHandle, 0,
    &InterfaceDescriptor );

  if ( bResult )
  {
    for ( int index = 0; index < InterfaceDescriptor.bNumEndpoints; index++ )
    {
      bResult = WinUsb_QueryPipe( hDeviceHandle, 0, index, &Pipe );

      if ( bResult )
      {
        if ( Pipe.PipeType == UsbdPipeTypeControl )
        {
          printf( "Endpoint index: %d Pipe type: Control Pipe ID: %d.\n", index,
            Pipe.PipeType, Pipe.PipeId );
        }
        if ( Pipe.PipeType == UsbdPipeTypeIsochronous )
        {
          printf( "Endpoint index: %d Pipe type: Isochronous Pipe ID: %d.\n",
            index, Pipe.PipeType, Pipe.PipeId );
        }
        if ( Pipe.PipeType == UsbdPipeTypeBulk )
        {
          if ( USB_ENDPOINT_DIRECTION_IN( Pipe.PipeId ) )
          {
            printf( "Endpoint index: %d Pipe type: Bulk Pipe ID: %c.\n", index,
              Pipe.PipeType, Pipe.PipeId );
            pipeid->PipeInId = Pipe.PipeId;
          }
          if ( USB_ENDPOINT_DIRECTION_OUT( Pipe.PipeId ) )
          {
            printf( "Endpoint index: %d Pipe type: Bulk Pipe ID: %c.\n", index,
              Pipe.PipeType, Pipe.PipeId );
            pipeid->PipeOutId = Pipe.PipeId;
          }

        }
        if ( Pipe.PipeType == UsbdPipeTypeInterrupt )
        {
          printf( "Endpoint index: %d Pipe type: Interrupt Pipe ID: %d.\n",
            index, Pipe.PipeType, Pipe.PipeId );
        }
      }
      else
      {
        continue;
      }
    }
  }

  done: return bResult;
}

向默認終結點發送控制傳輸

接下來,通過向默認終結點發送控制請求來與設備通信。
除了與接口關聯的終結點之外,所有 USB 設備都有一個默認終結點。
默認終結點的主要目的是為主機提供可用於配置設備的信息。
不過,設備還可以將默認終結點用於特定於設備的目的。

控制命令包含一個 8 字節的設置數據包,其中包括用於指定特定請求的請求代碼和一個可選數據緩沖區。
請求代碼和緩沖區格式由供應商定義。在本例中,應用程序將數據發送到設備來控制燈條。
設置燈條的代碼是 0xD8,為簡便起見將其定義為 SET_BARGRAPH_DISPLAY。
對於此請求,設備需要一個 1 字節的數據緩沖區,以通過設置適當的位指定哪些元素應亮起。

應用程序可以通過用戶界面 (UI) 執行此設置,例如通過提供一組由八個復選框構成的控件來指定應亮起燈條的哪些元素。
指定的元素對應於緩沖區中適當的位。 為避開 UI 代碼,本節中的示例代碼設置位時,采用了使備用燈亮起的設置。

使用以下步驟發送控制請求。

  1. 分配一個 1 字節的數據緩沖區,並將數據加載到緩沖區,該緩沖區通過設置適當的位指定應亮起的元素。
  2. 在調用方分配的 WINUSB_SETUP_PACKET 結構中構建一個安裝包。
    如下所示初始化成員以表示請求類型和數據:調用 WinUsb_ControlTransfer 以通過傳遞設備的 WinUSB 接口句柄、安裝包和數據緩沖區,
    • RequestType 成員指定請求方向。
      它設置為 0,指示主機到設備數據傳輸。
      對於設備到主機傳輸,將 RequestType 設置為 1。
    • Request 成員設置為此請求的供應商定義的代碼 0xD8。
      為簡便起見將其定義為 SET_BARGRAPH_DISPLAY。
    • Length 成員設置為數據緩沖區的大小。
    • 此請求不需要 Index 和 Value 成員,
      因此它們設置為零。

  3. 將請求傳輸到默認終結點。此函數在LengthTransferred 參數中接收傳輸到設備的字節數。

以下代碼示例將控制請求發送到指定的 USB 設備來控制燈條上的燈。

BOOL SendDatatoDefaultEndpoint( WINUSB_INTERFACE_HANDLE hDeviceHandle )
{
  if ( hDeviceHandle == INVALID_HANDLE_VALUE )
  {
    return FALSE;
  }

  BOOL bResult = TRUE;

  UCHAR bars = 0;

  WINUSB_SETUP_PACKET SetupPacket;
  ZeroMemory( &SetupPacket, sizeof(WINUSB_SETUP_PACKET) );
  ULONG cbSent = 0;

  //Set bits to light alternate bars
  for ( short i = 0; i < 7; i += 2 )
  {
    bars += 1 << i;
  }

  //Create the setup packet
  SetupPacket.RequestType = 0;
  SetupPacket.Request = 0xD8;
  SetupPacket.Value = 0;
  SetupPacket.Index = 0;
  SetupPacket.Length = sizeof(UCHAR);

  bResult = WinUsb_ControlTransfer( hDeviceHandle, SetupPacket, &bars,
    sizeof(UCHAR), &cbSent, 0 );
  if ( !bResult )
  {
    goto done;
  }

  printf( "Data sent: %d \nActual data transferred: %d.\n", sizeof( bars ),
    cbSent );

  done: return bResult;

}

 

發送 I/O 請求

接下來,將數據發送到設備的批量傳入和批量傳出終結點,這些終結點可分別用於讀取請求和寫入請求。
在 OSR USB FX2 設備上,這兩個終結點配置為用於環回,因此該設備可將數據從批量傳入終結點移動到批量傳出終結點。
它不更改數據的值或添加任何新數據。對於環回配置,讀取請求將讀取由最近的寫入請求發送的數據。
WinUSB 提供以下函數用於發送讀取請求和寫入請求:

  • WinUsb_WritePipe
  • WinUsb_ReadPipe

Ff540174.wedge(zh-cn,VS.85).gif發送寫入請求

  1. 分配一個緩沖區,並使用希望寫入設備的數據填充該緩沖區。
    如果應用程序沒有將 RAW_IO 設置為管道的策略類型,則對緩沖區大小沒有限制。
    WinUSB 根據需要將緩沖區拆分為適當大小的區塊。
    如果設置了 RAW_IO,則緩沖區的大小受 WinUSB 支持的最大緩沖區大小的限制。
  2. 調用 WinUsb_WritePipe 將緩沖區寫入設備。
    傳遞設備的 WinUSB 接口句柄、批量傳出管道的管道標識符和緩沖區。
    此函數返回在 bytesWritten 參數中實際寫入設備的字節數。 
    Overlapped 參數設置為 NULL 以請求同步操作。
    要執行異步寫請求,請將 
    Overlapped 設置為指向 OVERLAPPED 結構的指針。

包含零長度數據的寫入請求向下轉發到 USB 堆棧。
如果傳輸長度大於最大傳輸長度,WinUSB 會將請求拆分為具有最大傳輸長度的較小請求,並連續提交它們。

以下代碼示例分配一個字符串,並將其發送到設備的批量傳出終結點。

BOOL WriteToBulkEndpoint( WINUSB_INTERFACE_HANDLE hDeviceHandle, UCHAR* pID,
  ULONG* pcbWritten )
{
  if ( hDeviceHandle == INVALID_HANDLE_VALUE || !pID || !pcbWritten )
  {
    return FALSE;
  }

  BOOL bResult = TRUE;

  UCHAR szBuffer[ ] = "Hello World";
  ULONG cbSize = strlen( szBuffer );
  ULONG cbSent = 0;

  bResult = WinUsb_WritePipe( hDeviceHandle, *pID, szBuffer, cbSize, &cbSent,
    0 );
  if ( !bResult )
  {
    goto done;
  }

  printf( "Wrote to pipe %d: %s \nActual data transferred: %d.\n", *pID,
    szBuffer, cbSent );
  *pcbWritten = cbSent;

  done: return bResult;

}

發送讀取請求

調用 WinUsb_ReadPipe 從設備的批量傳入終結點讀取數據。
傳遞設備的 WinUSB 接口句柄、批量傳入終結點的管道標識符和適當大小的空緩沖區。
當該函數返回時,緩沖區包含從設備讀取的數據。讀取的字節數返回函數的 bytesRead 參數。
對於讀取請求,緩沖區必須是最大包大小的倍數。

零長度讀請求將立即成功完成,並且不向下發送到堆棧。
如果傳輸長度大於最大傳輸長度,WinUSB 會將請求拆分為具有最大傳輸長度的較小請求,
並連續提交它們。如果傳輸長度不是終結點的 MaxPacketSize 的倍數,
WinUSB 會將傳輸大小增加到 MaxPacketSize 的下一個倍數。
如果設備返回的數據比請求的多,WinUSB 會保存超過的數據。
如果數據從以前的讀請求中保留,WinUSB 會將其復制到下一個讀請求的開頭,並根據需要完成請求。

以下代碼示例從設備的批量傳入終結點讀取數據。

BOOL ReadFromBulkEndpoint( WINUSB_INTERFACE_HANDLE hDeviceHandle, UCHAR* pID,
  ULONG cbSize )
{
  if ( hDeviceHandle == INVALID_HANDLE_VALUE )
  {
    return FALSE;
  }

  BOOL bResult = TRUE;

  UCHAR* szBuffer = (UCHAR*) LocalAlloc( LPTR, sizeof(UCHAR) * cbSize );

  ULONG cbRead = 0;

  bResult = WinUsb_ReadPipe( hDeviceHandle, *pID, szBuffer, cbSize, &cbRead,
    0 );
  if ( !bResult )
  {
    goto done;
  }

  printf( "Read from pipe %d: %s \nActual data read: %d.\n", *pID, szBuffer,
    cbRead );

  done: LocalFree( szBuffer );
  return bResult;

}

釋放設備句柄

在完成對設備的所有必要的調用之后,釋放設備的文件句柄和 WinUSB 接口句柄。 為此,調用以下函數:

  • CloseHandle 釋放由 CreateFile 創建的句柄,如本演練的創建設備的文件句柄一節中所述。
  • WinUsb_Free 釋放由 WinUsb_Initialize 返回的設備的 WinUSB 接口句柄。

實現主函數

以下代碼示例顯示了控制台應用程序的主函數。

int _tmain( int argc, _TCHAR* argv[ ] )
{

  GUID guidDeviceInterface = OSR_DEVICE_INTERFACE; //in the INF file

  BOOL bResult = TRUE;

  PIPE_ID PipeID;

  HANDLE hDeviceHandle = INVALID_HANDLE_VALUE;
  WINUSB_INTERFACE_HANDLE hWinUSBHandle = INVALID_HANDLE_VALUE;

  UCHAR DeviceSpeed;
  ULONG cbSize = 0;

  bResult = GetDeviceHandle( guidDeviceInterface, &hDeviceHandle );
  if ( !bResult )
  {
    goto done;
  }

  bResult = GetWinUSBHandle( hDeviceHandle, &hWinUSBHandle );
  if ( !bResult )
  {
    goto done;
  }

  bResult = GetUSBDeviceSpeed( hWinUSBHandle, &DeviceSpeed );
  if ( !bResult )
  {
    goto done;
  }

  bResult = QueryDeviceEndpoints( hWinUSBHandle, &PipeID );
  if ( !bResult )
  {
    goto done;
  }

  bResult = SendDatatoDefaultEndpoint( hWinUSBHandle );
  if ( !bResult )
  {
    goto done;
  }

  bResult = WriteToBulkEndpoint( hWinUSBHandle, &PipeID.PipeOutId, &cbSize );
  if ( !bResult )
  {
    goto done;
  }

  bResult = ReadFromBulkEndpoint( hWinUSBHandle, &PipeID.PipeInId, cbSize );
  if ( !bResult )
  {
    goto done;
  }

  system( "PAUSE" );

  done: CloseHandle( hDeviceHandle );
  WinUsb_Free( hWinUSBHandle );

  return 0;
}

用於管道策略修改的 WinUSB 功能

為了使應用程序獲取並設置終結點管道的默認策略參數,Winusb.dll 公開 WinUsb_GetPipePolicy
功能來檢索管道的默認策略。WinUsb_SetPipePolicy 功能允許應用程序將策略參數設置為新值。
使用 WinUSB,你可以通過將策略應用到終結點的管道來修改其默認行為。
你可以使用這些策略來配置 WinUSB,使你的設備與其功能以最佳方式匹配。
下表提供了 WinUSB 支持的管道策略的列表。
注意
下表中介紹的策略僅對指定的終結點有效。
設置其他終結點上的策略不會影響 WinUSB 對讀取或寫入請求的行為。

0x01 SHORT_PACKET_TERMINATE < FALSE > 批量 (OUT)/中斷 (OUT)
發送一個零長度數據包的寫入請求,其中緩沖區是終結點支持的最大數據包大小的倍數。
如果設備要求通過零長度的數據包終止向外傳輸。啟用(策略參數值為 TRUE 或非零),
每個寫入請求(為終結點支持的最大數據包大小的倍數)后都會跟一個零長度的數據包。
在將所有請求的數據發送到主控制器后,WinUSB 會發送帶有零長度數據包的寫入請求,
然后完成由 WinUsb_WritePipe 創建的請求。

0x02 AUTO_CLEAR_STALL < FALSE > 批量 (IN)/中斷 (IN)
你不希望失敗的傳輸將終結點保持在停止狀態, 在不終止數據流的情況下自動清除停止的管道。
只有當 RAW_IO 處於禁用狀態而且有多個針對終結點的掛起讀取請求時,此策略才會有用。

如果啟用(策略參數值為 TRUE 或非零),停止狀態將自動清除。
當讀取請求失敗,主控制器返回除 STATUS_CANCELLED 或 STATUS_DEVICE_NOT_CONNECTED 以外的狀態時,
WinUSB 在完成失敗的請求之前將重置該管道。
重置管道將在不中斷數據流的情況下清除停止狀態。只要設備持續進行新傳輸,
數據就不斷流向終結點。新的傳輸可以包含出現停止狀態時位於隊列中的請求。
啟用此策略不會對性能產生嚴重影響。此策略參數不影響控制管道。

如果禁用(策略參數值為 FALSE 或零),在調用方通過調用 WinUsb_ResetPipe
手動重置終結點的管道之前,在停止傳輸后到達終結點的所有傳輸都會失敗。

0x03 PIPE_TRANSFER_TIMEOUT 控制:5 秒 批量 (IN)/批量 (OUT)
在取消請求之前,等待超時間隔。 其他:0 秒 中斷 (IN)/中斷 (OUT)
你希望到達終結點的傳輸在指定的時間內完成。

如果設置為零(默認值),傳輸將不會超時,原因是主控制器不會取消傳輸。
在這種情況下,傳輸將一直處於等待狀態,直到被手動取消或傳輸過程正常完成。

如果設置為非零值(超時間隔),主控制器將在接收到傳輸請求后開始計時。
當計時器超出設定的時間間隔,請求就會取消。計時器管理會對性能產生較小的影響。

注意 在 WinUSB 隊列中等候的請求不會超時。
在 Windows Vista 中,對於所有的傳輸(不包含啟用了 RAW_IO 的傳輸),WinUSB 會將請求包含在隊列中,
直到目標終結點上所有之前的傳輸都完成。主控制器在計算超時間隔時不考慮排隊時間。

啟用 RAW_IO 后,WinUSB 不會將請求包含在隊列中。相反,它會直接將請求傳遞給 USB 堆棧,
無論 USB 堆棧是否正在忙於處理之前的請求。如果 USB 堆棧忙碌,它可以延遲處理新的請求。
請注意,這樣會導致超時。

0x04 IGNORE_SHORT_PACKETS < FALSE > 批量 (IN)/中斷 (IN)
在接收短數據包或讀取一定數量的字節時,完成讀取請求。如果文件大小未知,請求將在短數據包時中止。
RAW_IO 已禁用,並且你不希望短數據包完成讀取請求。

如果啟用(策略參數值為 TRUE 或非零),主控制器在收到短數據包后不會立即完成讀取操作。
相反,僅當下列情況出現時它才會完成操作:1) 出現錯誤。2) 請求被取消。3) 所有請求的字節都已收到。

如果禁用(策略參數值為 FALSE 或零),主控制器在讀取請求的字節數量或收到短數據包后才完成讀取操作。

0x05 ALLOW_PARTIAL_READS < TRUE > 批量 (IN)/中斷 (IN)
允許來自設備的讀取請求,該設備返回的數據多於調用方請求的數據。
設備發送的數據多於請求的數據。當請求緩沖區的大小是最大終結點數據包大小的倍數時,會出現這種情況。
當應用程序希望讀取少量字節以確定要讀取的總字節數量時,可以使用此策略。

如果禁用(策略參數值為 FALSE 或零)並且設備返回除請求數據之外的多余數據,WinUSB 將完成請求並報錯。

如果啟用(策略參數值為 TRUE 或非零)並且設備返回除請求數據之外的多余數據,
WinUSB 可以將來自讀取請求的多余數據添加到下一個請求的開頭 ( AUTO_FLUSH == TRUE )
或放棄這些多余的數據。( AUTO_FLUSH == FALSE )
如果啟用,WinUSB 將立即成功完成零字節的讀取請求,並且不會向堆棧發送請求。

0x06 AUTO_FLUSH < FALSE > 批量 (IN)/中斷 (IN)
保存來自讀取請求的多余數據,並將其添加到下一個讀取請求或放棄多余的數據。
啟用 ALLOW_PARTIAL _READS 策略。設備可以發送除請求數據之外的多余數據,
你的應用程序不需要任何額外的數據。當請求緩沖區的大小是最大終結點數據包大小的倍數時,會出現這種情況。

當 ALLOW_PARTIAL_READS 啟用時,AUTO_FLUSH 將定義 WinUSB 的行為。
如果禁用 ALLOW_PARTIAL_READS,WinUSB 將忽略 AUTO_FLUSH 值。
WinUSB 可以放棄剩余的數據,也可以將其發送到調用方的下一個讀取請求。
如果啟用(策略參數值為 TRUE 或非零),WinUSB 將放棄多余的字節並且不顯示任何錯誤代碼。
如果禁用(策略參數值為 FALSE 或零),WinUSB 將保存多余的字節,
將其發送到該調用方下一個讀取請求的開頭,然后將數據發送給下一個讀取操作的調用方。

ALLOW_PARTIAL_READS AUTO_FLUSH
禁用                 無關     設備返回除請求數據之外的多余數據,WinUSB 將完成請求並報錯。
啟用                 禁用     設備返回除請求數據之外的多余數據,WinUSB 將放棄這些多余的數據。
啟用                 啟用     將來自讀取請求的多余數據添加到下一個請求的開頭

0x07 RAW_IO < FALSE > 批量 (IN)/中斷 (IN)
跳過隊列和錯誤處理以提高多個讀取請求的執行速度。
性能優先,同時應用程序向同一終結點提交同步讀取請求。
RAW_IO 對調用方在 WinUsb_ReadPipe 中傳遞的緩沖區有一些限制:
緩沖區的長度必須是最大終結點數據包大小的倍數。
長度必須小於或等於 WinUsb_GetPipePolicy 檢索的 MAXIMUM_TRANSFER_SIZE 的值。

如果啟用,傳輸將跳過隊列和錯誤處理,以提高多個讀取請求的性能。
WinUSB 按如下所示處理讀取請求:
1) 不是最大終結點數據包大小倍數的請求失敗。
2) 大於 WinUSB 支持的最大傳輸大小的請求失敗。
3) 格式標准的請求將立即發送到要在主控制器中計划的 USB 核心堆棧。

啟用此設置能夠明顯提高多個讀取請求的性能,
方法是減少一個傳輸的最后一個數據包和下一個傳輸的第一個數據包之間的延遲。

0x08 MAXIMUM_TRANSFER_SIZE 批量 (IN)/批量 (OUT)/中斷 (IN)/中斷 (OUT)
獲取 WinUSB 支持的最大大小的 USB 傳輸。
這是一個只讀策略,可以通過調用 WinUsb_GetPipePolicy 來檢索。

0x09 RESET_PIPE_ON_RESUME < FALSE > 批量 (IN)/批量 (OUT)/中斷 (IN)/中斷 (OUT)
在重新開始掛起之后、接受新請求之前,重置終結點的管道。
如果啟用,設備不會在掛起之后保留其數據切換狀態。
從掛起狀態恢復時,WinUSB 會重置終結點,然后才允許調用方向該終結點發送新請求。

 

http://sourceforge.net/projects/winusb-delphi

unit WinUsbDll;

{ Quick wrapper for WinUSB.DLL by Panu-Kristian Poiksalo }

{ WARNING: Mostly untested - Only initialize, readpipe and writepipe work ok }
{ License: LGPL. Assume that it doesn't work and don't blame me for any errors. }
{ Most data types were manually converted from strange types to Pascal types.
  Much of it was jus a quick hack. Those types that were not known or interesting
  to me were guessed so don't rely on any structured type to work properly.
  This is very early and very untested code. Only use it as basis for bad ideas. }

{ P.S. Instead of using winusb.dll, I think someone should make a delphi
  implementation for the WinUSB COM interface. }

{ Version: 0.01 Date: 18.11(November).2007 }

interface

uses
{$IFDEF WIN32}
  Windows, Dialogs;
{$ELSE}
  Wintypes, WinProcs, Dialogs;
{$ENDIF}

type
  HANDLE = THandle;
  PWINUSB_INTERFACE_HANDLE = ^THandle;
  WINUSB_INTERFACE_HANDLE = HANDLE;

  PVOID = Pointer;
  LPOVERLAPPED = Pointer;
  LONG = Cardinal;

  { #pragma pack(1) }

  // not tested so don't use
type
  _WINUSB_SETUP_PACKET = record
    RequestType_UNTESTED_DO_NOT_USE : Byte;
    Request_UNTESTED_DO_NOT_USE : Byte;
    Value_UNTESTED_DO_NOT_USE : Word;
    Index_UNTESTED_DO_NOT_USE : Word;
    Length_UNTESTED_DO_NOT_USE : Word;
  end { _WINUSB_SETUP_PACKET };

  WINUSB_SETUP_PACKET = _WINUSB_SETUP_PACKET;
  PWINUSB_SETUP_PACKET = ^_WINUSB_SETUP_PACKET;

type
  DESCRIPTOR = record // Generic descriptor
    Length : Byte;
    DescriptorType : Byte;
    Data : Array [ 0 .. 1000 ] of Byte; // will crash if descriptor is longer.
  end;

  { #pragma pack() }
type
  USBD_PIPE_TYPE = ( UsbdPipeTypeControl, UsbdPipeTypeIsochronous,
    UsbdPipeTypeBulk, UsbdPipeTypeInterrupt );

type
  _WINUSB_PIPE_INFORMATION = record
    PipeType : Cardinal;
    PipeId : Word; // strange, I know, but seems to fit the data
    MaximumPacketSize : Word;
    Interval : Word; // (?)
  end { _WINUSB_PIPE_INFORMATION };

type
  WINUSB_PIPE_INFORMATION = _WINUSB_PIPE_INFORMATION;
  PWINUSB_PIPE_INFORMATION = ^_WINUSB_PIPE_INFORMATION;
  USB_INTERFACE_DESCRIPTOR = DESCRIPTOR;
  PUSB_INTERFACE_DESCRIPTOR = ^USB_INTERFACE_DESCRIPTOR;
  USB_CONFIGURATION_DESCRIPTOR = DESCRIPTOR;
  PUSB_CONFIGURATION_DESCRIPTOR = ^USB_CONFIGURATION_DESCRIPTOR;

type
  BufferArray = Array of Byte;
  PBufferArray = ^BufferArray;

var
  WinUsb_Initialize : function( DeviceHandle : HANDLE;
    var InterfaceHandle : WINUSB_INTERFACE_HANDLE ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_Free_NotYetTested : function( InterfaceHandle
    : WINUSB_INTERFACE_HANDLE ) : Bool cdecl {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_GetAssociatedInterface_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    AssociatedInterfaceIndex : Byte;
    AssociatedInterfaceHandle : PWINUSB_INTERFACE_HANDLE ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_GetDescriptor : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    DescriptorType : Byte; Index : Byte; LanguageID : Word; Buffer : PUCHAR;
    BufferLength : Cardinal; var LengthTransferred : Cardinal ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_QueryInterfaceSettings_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    AlternateInterfaceNumber : Byte;
    UsbAltInterfaceDescriptor : PUSB_INTERFACE_DESCRIPTOR ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_QueryDeviceInformation_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    InformationType : Cardinal; BufferLength : PULONG; Buffer : PVOID )
    : Bool cdecl {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_SetCurrentAlternateSetting_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    SettingNumber : Byte ) : Bool cdecl {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_GetCurrentAlternateSetting_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    SettingNumber : PUCHAR ) : Bool cdecl {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_QueryPipe : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    AlternateInterfaceNumber : Byte; PipeIndex : Byte;
    PipeInformation : PWINUSB_PIPE_INFORMATION ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_SetPipePolicy_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE; PipeId : Byte;
    PolicyType : Cardinal; ValueLength : Cardinal; Value : PVOID ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_GetPipePolicy_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE; PipeId : Byte;
    PolicyType : Cardinal; ValueLength : PULONG; Value : PVOID ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_ReadPipe : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    PipeId : Byte; Buffer : PBufferArray; BufferLength : Cardinal;
    var LengthTransferred : Cardinal; Overlapped : LPOVERLAPPED ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_WritePipe : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    PipeId : Byte; Buffer : PBufferArray; BufferLength : Cardinal;
    var LengthTransferred : Cardinal; Overlapped : LPOVERLAPPED ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_ControlTransfer_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    SetupPacket : WINUSB_SETUP_PACKET; Buffer : PUCHAR; BufferLength : Cardinal;
    LengthTransferred : PULONG; Overlapped : LPOVERLAPPED ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_ResetPipe : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    PipeId : Byte ) : Bool cdecl {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_AbortPipe_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE; PipeId : Byte )
    : Bool cdecl {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_FlushPipe_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE; PipeId : Byte )
    : Bool cdecl {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_SetPowerPolicy_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    PolicyType : Cardinal; ValueLength : Cardinal; Value : PVOID ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_GetPowerPolicy_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    PolicyType : Cardinal; ValueLength : PULONG; Value : PVOID ) : Bool cdecl
  {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_GetOverlappedResult_NotYetTested
    : function( InterfaceHandle : WINUSB_INTERFACE_HANDLE;
    LPOVERLAPPED : LPOVERLAPPED; lpNumberOfBytesTransferred : LPDWORD;
    bWait : Bool ) : Bool cdecl {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_ParseConfigurationDescriptor_NotYetTested
    : function( ConfigurationDescriptor : PUSB_CONFIGURATION_DESCRIPTOR;
    StartPosition : PVOID; InterfaceNumber : LONG; AlternateSetting : LONG;
    InterfaceClass : LONG; InterfaceSubClass : LONG; InterfaceProtocol : LONG )
    : USB_INTERFACE_DESCRIPTOR cdecl {$IFDEF WIN32} stdcall {$ENDIF};

var
  WinUsb_ParseDescriptors_NotYetTested : function( DescriptorBuffer : PVOID;
    TotalLength : Cardinal; StartPosition : PVOID; DescriptorType : LONG )
    : DESCRIPTOR cdecl {$IFDEF WIN32} stdcall {$ENDIF};

var
  DLLLoaded : Boolean { is DLL (dynamically) loaded already? }
{$IFDEF WIN32} = False; {$ENDIF}

implementation

var
  SaveExit : Pointer;
  DLLHandle : THandle;
{$IFNDEF MSDOS}
  ErrorMode : Integer;
{$ENDIF}

procedure NewExit; far;
begin
  ExitProc := SaveExit;
  FreeLibrary( DLLHandle )
end { NewExit };

procedure LoadDLL;
begin
  if DLLLoaded then
    Exit;
{$IFNDEF MSDOS}
  ErrorMode := SetErrorMode( $8000 { SEM_NoOpenFileErrorBox } );
{$ENDIF}
  DLLHandle := LoadLibrary( 'WINUSB.DLL' );
  if DLLHandle >= 32 then
  begin
    DLLLoaded := True;
    SaveExit := ExitProc;
    ExitProc := @NewExit;
    @WinUsb_Initialize := GetProcAddress( DLLHandle, 'WinUsb_Initialize' );
{$IFDEF WIN32}
    Assert( @WinUsb_Initialize <> nil );
{$ENDIF}
    @WinUsb_Free_NotYetTested := GetProcAddress( DLLHandle, 'WinUsb_Free' );
{$IFDEF WIN32}
    Assert( @WinUsb_Free_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_GetAssociatedInterface_NotYetTested :=
      GetProcAddress( DLLHandle, 'WinUsb_GetAssociatedInterface' );
{$IFDEF WIN32}
    Assert( @WinUsb_GetAssociatedInterface_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_GetDescriptor := GetProcAddress( DLLHandle,
      'WinUsb_GetDescriptor' );
{$IFDEF WIN32}
    Assert( @WinUsb_GetDescriptor <> nil );
{$ENDIF}
    @WinUsb_QueryInterfaceSettings_NotYetTested :=
      GetProcAddress( DLLHandle, 'WinUsb_QueryInterfaceSettings' );
{$IFDEF WIN32}
    Assert( @WinUsb_QueryInterfaceSettings_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_QueryDeviceInformation_NotYetTested :=
      GetProcAddress( DLLHandle, 'WinUsb_QueryDeviceInformation' );
{$IFDEF WIN32}
    Assert( @WinUsb_QueryDeviceInformation_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_SetCurrentAlternateSetting_NotYetTested :=
      GetProcAddress( DLLHandle, 'WinUsb_SetCurrentAlternateSetting' );
{$IFDEF WIN32}
    Assert( @WinUsb_SetCurrentAlternateSetting_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_GetCurrentAlternateSetting_NotYetTested :=
      GetProcAddress( DLLHandle, 'WinUsb_GetCurrentAlternateSetting' );
{$IFDEF WIN32}
    Assert( @WinUsb_GetCurrentAlternateSetting_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_QueryPipe := GetProcAddress( DLLHandle, 'WinUsb_QueryPipe' );
{$IFDEF WIN32}
    Assert( @WinUsb_QueryPipe <> nil );
{$ENDIF}
    @WinUsb_SetPipePolicy_NotYetTested := GetProcAddress( DLLHandle,
      'WinUsb_SetPipePolicy' );
{$IFDEF WIN32}
    Assert( @WinUsb_SetPipePolicy_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_GetPipePolicy_NotYetTested := GetProcAddress( DLLHandle,
      'WinUsb_GetPipePolicy' );
{$IFDEF WIN32}
    Assert( @WinUsb_GetPipePolicy_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_ReadPipe := GetProcAddress( DLLHandle, 'WinUsb_ReadPipe' );
{$IFDEF WIN32}
    Assert( @WinUsb_ReadPipe <> nil );
{$ENDIF}
    @WinUsb_WritePipe := GetProcAddress( DLLHandle, 'WinUsb_WritePipe' );
{$IFDEF WIN32}
    Assert( @WinUsb_WritePipe <> nil );
{$ENDIF}
    @WinUsb_ControlTransfer_NotYetTested := GetProcAddress( DLLHandle,
      'WinUsb_ControlTransfer' );
{$IFDEF WIN32}
    Assert( @WinUsb_ControlTransfer_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_ResetPipe := GetProcAddress( DLLHandle, 'WinUsb_ResetPipe' );
{$IFDEF WIN32}
    Assert( @WinUsb_ResetPipe <> nil );
{$ENDIF}
    @WinUsb_AbortPipe_NotYetTested := GetProcAddress( DLLHandle,
      'WinUsb_AbortPipe' );
{$IFDEF WIN32}
    Assert( @WinUsb_AbortPipe_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_FlushPipe_NotYetTested := GetProcAddress( DLLHandle,
      'WinUsb_FlushPipe' );
{$IFDEF WIN32}
    Assert( @WinUsb_FlushPipe_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_SetPowerPolicy_NotYetTested := GetProcAddress( DLLHandle,
      'WinUsb_SetPowerPolicy' );
{$IFDEF WIN32}
    Assert( @WinUsb_SetPowerPolicy_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_GetPowerPolicy_NotYetTested := GetProcAddress( DLLHandle,
      'WinUsb_GetPowerPolicy' );
{$IFDEF WIN32}
    Assert( @WinUsb_GetPowerPolicy_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_GetOverlappedResult_NotYetTested :=
      GetProcAddress( DLLHandle, 'WinUsb_GetOverlappedResult' );
{$IFDEF WIN32}
    Assert( @WinUsb_GetOverlappedResult_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_ParseConfigurationDescriptor_NotYetTested :=
      GetProcAddress( DLLHandle, 'WinUsb_ParseConfigurationDescriptor' );
{$IFDEF WIN32}
    Assert( @WinUsb_ParseConfigurationDescriptor_NotYetTested <> nil );
{$ENDIF}
    @WinUsb_ParseDescriptors_NotYetTested := GetProcAddress( DLLHandle,
      'WinUsb_ParseDescriptors' );
{$IFDEF WIN32}
    Assert( @WinUsb_ParseDescriptors_NotYetTested <> nil );
{$ENDIF}
  end
  else
  begin
    DLLLoaded := False;
    ShowMessage( 'Error: WINUSB.DLL could not be loaded !!' );
    { Error: WINUSB.DLL could not be loaded !! }
  end;
{$IFNDEF MSDOS}
  SetErrorMode( ErrorMode )
{$ENDIF}
end { LoadDLL };

begin
  LoadDLL;

end.

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM