需要为USB外围设备编写驱动程序?
Need to write driver for USB peripheral device?
我正在设计一个 USB 外围设备,它偶尔会连接到 Windows PC,并在每个方向上传输几 KB 的数据。将有一个自定义 PC 应用程序使用专有协议(即用于 USB 有效负载)控制数据传输。
我在下面的 link 中看到 Microsoft 描述了如何 为 USB 设备编写驱动程序。但是我需要一个吗?
Developing Windows client drivers for USB devices
PC 应用程序是我们打算知道如何与设备通信的唯一应用程序,因此从应用程序共享的角度来看,不需要驱动程序。
我能否直接将自定义协议烘焙到应用程序中,让应用程序与设备对话 "raw USB",而不需要单独的驱动程序?
“原始 USB”,不,您不能从应用程序中执行此操作。
但是因为您也控制该设备,所以您可以使它显示为 类 设备之一,Windows 为其提供了一个足够通用的设备驱动程序,可以执行您想要的任何操作。
这些设备 类 是 HID(人机接口设备)和“WinUSB”。其中,HID 是跨平台的,但功能更有限,WinUSB 允许高性能数据传输以及中断端点。
有关设置设备的字符串描述符以便 Windows 自动将其绑定到 WinUSB 驱动程序的说明是 on MSDN
A WinUSB device is a Universal Serial Bus (USB) device whose firmware defines certain Microsoft operating system (OS) feature descriptors that report the compatible ID as "WINUSB"
.
The purpose of a WinUSB device is to enable Windows to load Winusb.sys as the device's function driver without a custom INF file. For a WinUSB device, you are not required to distribute INF files for your device, making the driver installation process simple for end users.
还有另一种方法 无需编写驱动程序 来使用 WriteFile function:WinUSB 写入您想要的设备,具体操作方法:
- 包括WinUsb.h
- 将 WinUsb.lib 添加到链接库列表。
- 在 Usb100.h 一些宏中。
- 使用设备接口GUID获取设备路径。正确的 GUID 是您在用于安装 WinUsb.sys.
的 INF 中指定的那个
- 通过将您在 INF 中定义的设备接口 GUID 传递给 SetupDiGetClassDevs 来获取设备信息集的句柄。函数returns一个HDEVINFO句柄。
- 调用SetupDiEnumDeviceInterfaces来枚举系统的设备接口,获取你的设备接口信息。
- 调用 SetupDiGetDeviceInterfaceDetail 获取设备接口的详细数据。
- 调用GetDevicePath函数获取设备路径
- 将设备路径传递给CreateFile 以获得设备的文件句柄。 使用 ReadFile 和 Write File 与设备通信!
- 将文件句柄传递给WinUsb_Initialize以初始化WinUSB并获得WinUSB句柄。当您调用 WinUSB API 函数时,您使用设备的 WinUSB 句柄来识别设备,而不是设备的文件句柄。
对于更高级的解决方案 - 使用函数:
- WinUsb_QueryDeviceInformation获取设备的速度。
- WinUsb_QueryInterfaceSettings获取对应的接口描述符。 WinUSB句柄对应第一个接口
- WinUsb_QueryPipe 获取有关每个端点的信息。
- WinUsb_WritePipe 将缓冲区写入设备 - 默认行为:zero-length 写入向下转发到堆栈。如果传输长度大于最大传输长度,WinUSB 将请求分成最大传输长度的更小请求并依次提交。
- 更多功能和信息:http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/winusb_howto.docx
出于调试目的,您可能需要:
winusbtrace_tool https://blogs.msdn.microsoft.com/usbcoreblog/2010/02/05/how-to-generate-and-view-a-winusb-debug-trace-log/;
带 USBPcap 插件的 Wireshark https://www.wireshark.org。
其他示例:
http://searchingforbit.blogspot.com/2012/04/winusb-communication-with-stm32-part-1.html。
示例模板附带 Visual Studio.
您还需要具备编写 .inf 文件的知识。
另一种与 USB 通信的简单方法 - libusb-win32 https://sourceforge.net/projects/libusb-win32/
我的简单控制台应用程序将块发送到设备(原始数据绕过堆栈立即写入设备):
#include "stdafx.h"
#include <SetupAPI.h>
#include <Hidsdi.h>
#include <devguid.h>
#include <winusb.h>
#include <usb.h>
#pragma comment(lib, "hid.lib")
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "winusb.lib")
#include <iUString.h>
iString<char> DevicePath;
bool WinusbHandle_Open=false;
bool DeviceHandle_Open = false;
WINUSB_INTERFACE_HANDLE WinusbHandle;
HANDLE DeviceHandle;
UCHAR usb_out_buffer[64];
DEFINE_GUID(GUID_DEVCLASS_WINUSB, 0x88bae032L, 0x5a81, 0x49f0, 0xbc, 0x3d, 0xa4, 0xff, 0x13, 0x82, 0x16, 0xd6);
DEFINE_GUID(GUID_DEVCLASS_STL, 0xf177724dL, 0x74d3, 0x430e, 0x86, 0xb5, 0xf0, 0x36, 0x89, 0x10, 0xeb, 0x23);
GUID winusb_guid;
GUID stl_guid;
bool connectusb();
void disconnectusb();
int main()
{
DWORD n;
DWORD numEvents;
HANDLE rHnd;
WinusbHandle_Open = false;
DeviceHandle_Open = false;
winusb_guid = GUID_DEVCLASS_WINUSB;
stl_guid = GUID_DEVCLASS_STL;
usb_out_buffer[0] = 0;
usb_out_buffer[1] = 1;
usb_out_buffer[2] = 2;
usb_out_buffer[3] = 3;
ULONG bytesWritten;
ULONG timeout;
timeout = 100;
rHnd = GetStdHandle(STD_INPUT_HANDLE);
WinUsb_SetPipePolicy(WinusbHandle, 0x01, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout);
timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, AUTO_CLEAR_STALL, sizeof(ULONG), &timeout);
timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, RAW_IO, sizeof(ULONG), &timeout);//Bypasses queuing and error handling to boost performance for multiple read requests.
while (true)
{
if ((!WinusbHandle_Open) || (!WinusbHandle_Open)) { if (!connectusb())Sleep(2000); }
if ((!WinusbHandle_Open) || (!WinusbHandle_Open))continue;
bytesWritten = 0;
if (!WinUsb_WritePipe(WinusbHandle, 0x01, &usb_out_buffer[0], 2, &bytesWritten, NULL))
{
n = GetLastError();
disconnectusb();
}
Sleep(2000);
}
disconnectusb();
return 0;
}
bool connectusb()
{
BOOL bResult = FALSE;
HDEVINFO deviceInfo;
SP_DEVICE_INTERFACE_DATA interfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
DWORD n;
SP_DEVINFO_DATA devinfo;
BYTE devdetailbuffer[4096];
bool found;
deviceInfo = SetupDiGetClassDevs(&stl_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (deviceInfo == INVALID_HANDLE_VALUE) { return false; }
found = false;
for (n = 0;; n++)
{
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (!SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &stl_guid, n, &interfaceData))
{
n = GetLastError();
break;
}
detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)devdetailbuffer;
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
devinfo.cbSize = sizeof(devinfo);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, detailData, sizeof(devdetailbuffer), NULL, &devinfo)) { printf("SetupDiGetDeviceInterfaceDetail: %u\n", GetLastError()); break; }
if (IsEqualGUID(devinfo.ClassGuid, winusb_guid))
{
if ((-1 != iStrPos(detailData->DevicePath, "VID_0483")) || (-1 != iStrPos(detailData->DevicePath, "vid_0483")))
{
if ((-1 != iStrPos(detailData->DevicePath, "PID_576B")) || (-1 != iStrPos(detailData->DevicePath, "pid_576b")))
{
DevicePath = detailData->DevicePath;
found = true;
break;
}
}
}
}
SetupDiDestroyDeviceInfoList(deviceInfo);
if (!found)return false;
DeviceHandle = CreateFile(DevicePath.Buffer() ,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == DeviceHandle) {
n = GetLastError();
}
if (INVALID_HANDLE_VALUE == DeviceHandle) return false;
DeviceHandle_Open = true;
if (!WinUsb_Initialize(DeviceHandle, &WinusbHandle))
{
n = GetLastError();
CloseHandle(DeviceHandle); DeviceHandle_Open = false;
return false;
}
WinusbHandle_Open = true;
return true;
}
void disconnectusb()
{
if (WinusbHandle_Open) { WinUsb_Free(WinusbHandle); WinusbHandle_Open = false; }
if (DeviceHandle_Open) { CloseHandle(DeviceHandle); DeviceHandle_Open = false; }
}
使您的固件被枚举为 WINUSB(winusb 通用驱动程序)设备让生活更轻松。
我相信如果你有演示和代码就很清楚了所以我给你做了一个:)
我的 KEIL 项目 使用 STM32F4 Discovery 开发板与 WINUSB 作为 USB CDC 设备。您可以查看更多信息并获得来自 my GitHub.
的 源代码
我正在设计一个 USB 外围设备,它偶尔会连接到 Windows PC,并在每个方向上传输几 KB 的数据。将有一个自定义 PC 应用程序使用专有协议(即用于 USB 有效负载)控制数据传输。
我在下面的 link 中看到 Microsoft 描述了如何 为 USB 设备编写驱动程序。但是我需要一个吗?
Developing Windows client drivers for USB devices
PC 应用程序是我们打算知道如何与设备通信的唯一应用程序,因此从应用程序共享的角度来看,不需要驱动程序。
我能否直接将自定义协议烘焙到应用程序中,让应用程序与设备对话 "raw USB",而不需要单独的驱动程序?
“原始 USB”,不,您不能从应用程序中执行此操作。
但是因为您也控制该设备,所以您可以使它显示为 类 设备之一,Windows 为其提供了一个足够通用的设备驱动程序,可以执行您想要的任何操作。
这些设备 类 是 HID(人机接口设备)和“WinUSB”。其中,HID 是跨平台的,但功能更有限,WinUSB 允许高性能数据传输以及中断端点。
有关设置设备的字符串描述符以便 Windows 自动将其绑定到 WinUSB 驱动程序的说明是 on MSDN
A WinUSB device is a Universal Serial Bus (USB) device whose firmware defines certain Microsoft operating system (OS) feature descriptors that report the compatible ID as
"WINUSB"
.The purpose of a WinUSB device is to enable Windows to load Winusb.sys as the device's function driver without a custom INF file. For a WinUSB device, you are not required to distribute INF files for your device, making the driver installation process simple for end users.
还有另一种方法 无需编写驱动程序 来使用 WriteFile function:WinUSB 写入您想要的设备,具体操作方法:
- 包括WinUsb.h
- 将 WinUsb.lib 添加到链接库列表。
- 在 Usb100.h 一些宏中。
- 使用设备接口GUID获取设备路径。正确的 GUID 是您在用于安装 WinUsb.sys. 的 INF 中指定的那个
- 通过将您在 INF 中定义的设备接口 GUID 传递给 SetupDiGetClassDevs 来获取设备信息集的句柄。函数returns一个HDEVINFO句柄。
- 调用SetupDiEnumDeviceInterfaces来枚举系统的设备接口,获取你的设备接口信息。
- 调用 SetupDiGetDeviceInterfaceDetail 获取设备接口的详细数据。
- 调用GetDevicePath函数获取设备路径
- 将设备路径传递给CreateFile 以获得设备的文件句柄。 使用 ReadFile 和 Write File 与设备通信!
- 将文件句柄传递给WinUsb_Initialize以初始化WinUSB并获得WinUSB句柄。当您调用 WinUSB API 函数时,您使用设备的 WinUSB 句柄来识别设备,而不是设备的文件句柄。
对于更高级的解决方案 - 使用函数:
- WinUsb_QueryDeviceInformation获取设备的速度。
- WinUsb_QueryInterfaceSettings获取对应的接口描述符。 WinUSB句柄对应第一个接口
- WinUsb_QueryPipe 获取有关每个端点的信息。
- WinUsb_WritePipe 将缓冲区写入设备 - 默认行为:zero-length 写入向下转发到堆栈。如果传输长度大于最大传输长度,WinUSB 将请求分成最大传输长度的更小请求并依次提交。
- 更多功能和信息:http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/winusb_howto.docx
出于调试目的,您可能需要: winusbtrace_tool https://blogs.msdn.microsoft.com/usbcoreblog/2010/02/05/how-to-generate-and-view-a-winusb-debug-trace-log/; 带 USBPcap 插件的 Wireshark https://www.wireshark.org。
其他示例: http://searchingforbit.blogspot.com/2012/04/winusb-communication-with-stm32-part-1.html。 示例模板附带 Visual Studio.
您还需要具备编写 .inf 文件的知识。
另一种与 USB 通信的简单方法 - libusb-win32 https://sourceforge.net/projects/libusb-win32/
我的简单控制台应用程序将块发送到设备(原始数据绕过堆栈立即写入设备):
#include "stdafx.h"
#include <SetupAPI.h>
#include <Hidsdi.h>
#include <devguid.h>
#include <winusb.h>
#include <usb.h>
#pragma comment(lib, "hid.lib")
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "winusb.lib")
#include <iUString.h>
iString<char> DevicePath;
bool WinusbHandle_Open=false;
bool DeviceHandle_Open = false;
WINUSB_INTERFACE_HANDLE WinusbHandle;
HANDLE DeviceHandle;
UCHAR usb_out_buffer[64];
DEFINE_GUID(GUID_DEVCLASS_WINUSB, 0x88bae032L, 0x5a81, 0x49f0, 0xbc, 0x3d, 0xa4, 0xff, 0x13, 0x82, 0x16, 0xd6);
DEFINE_GUID(GUID_DEVCLASS_STL, 0xf177724dL, 0x74d3, 0x430e, 0x86, 0xb5, 0xf0, 0x36, 0x89, 0x10, 0xeb, 0x23);
GUID winusb_guid;
GUID stl_guid;
bool connectusb();
void disconnectusb();
int main()
{
DWORD n;
DWORD numEvents;
HANDLE rHnd;
WinusbHandle_Open = false;
DeviceHandle_Open = false;
winusb_guid = GUID_DEVCLASS_WINUSB;
stl_guid = GUID_DEVCLASS_STL;
usb_out_buffer[0] = 0;
usb_out_buffer[1] = 1;
usb_out_buffer[2] = 2;
usb_out_buffer[3] = 3;
ULONG bytesWritten;
ULONG timeout;
timeout = 100;
rHnd = GetStdHandle(STD_INPUT_HANDLE);
WinUsb_SetPipePolicy(WinusbHandle, 0x01, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout);
timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, AUTO_CLEAR_STALL, sizeof(ULONG), &timeout);
timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, RAW_IO, sizeof(ULONG), &timeout);//Bypasses queuing and error handling to boost performance for multiple read requests.
while (true)
{
if ((!WinusbHandle_Open) || (!WinusbHandle_Open)) { if (!connectusb())Sleep(2000); }
if ((!WinusbHandle_Open) || (!WinusbHandle_Open))continue;
bytesWritten = 0;
if (!WinUsb_WritePipe(WinusbHandle, 0x01, &usb_out_buffer[0], 2, &bytesWritten, NULL))
{
n = GetLastError();
disconnectusb();
}
Sleep(2000);
}
disconnectusb();
return 0;
}
bool connectusb()
{
BOOL bResult = FALSE;
HDEVINFO deviceInfo;
SP_DEVICE_INTERFACE_DATA interfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
DWORD n;
SP_DEVINFO_DATA devinfo;
BYTE devdetailbuffer[4096];
bool found;
deviceInfo = SetupDiGetClassDevs(&stl_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (deviceInfo == INVALID_HANDLE_VALUE) { return false; }
found = false;
for (n = 0;; n++)
{
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (!SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &stl_guid, n, &interfaceData))
{
n = GetLastError();
break;
}
detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)devdetailbuffer;
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
devinfo.cbSize = sizeof(devinfo);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, detailData, sizeof(devdetailbuffer), NULL, &devinfo)) { printf("SetupDiGetDeviceInterfaceDetail: %u\n", GetLastError()); break; }
if (IsEqualGUID(devinfo.ClassGuid, winusb_guid))
{
if ((-1 != iStrPos(detailData->DevicePath, "VID_0483")) || (-1 != iStrPos(detailData->DevicePath, "vid_0483")))
{
if ((-1 != iStrPos(detailData->DevicePath, "PID_576B")) || (-1 != iStrPos(detailData->DevicePath, "pid_576b")))
{
DevicePath = detailData->DevicePath;
found = true;
break;
}
}
}
}
SetupDiDestroyDeviceInfoList(deviceInfo);
if (!found)return false;
DeviceHandle = CreateFile(DevicePath.Buffer() ,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == DeviceHandle) {
n = GetLastError();
}
if (INVALID_HANDLE_VALUE == DeviceHandle) return false;
DeviceHandle_Open = true;
if (!WinUsb_Initialize(DeviceHandle, &WinusbHandle))
{
n = GetLastError();
CloseHandle(DeviceHandle); DeviceHandle_Open = false;
return false;
}
WinusbHandle_Open = true;
return true;
}
void disconnectusb()
{
if (WinusbHandle_Open) { WinUsb_Free(WinusbHandle); WinusbHandle_Open = false; }
if (DeviceHandle_Open) { CloseHandle(DeviceHandle); DeviceHandle_Open = false; }
}
使您的固件被枚举为 WINUSB(winusb 通用驱动程序)设备让生活更轻松。
我相信如果你有演示和代码就很清楚了所以我给你做了一个:)
我的 KEIL 项目 使用 STM32F4 Discovery 开发板与 WINUSB 作为 USB CDC 设备。您可以查看更多信息并获得来自 my GitHub.
的 源代码