USB应用程序开发
Posted skdev
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了USB应用程序开发相关的知识,希望对你有一定的参考价值。
1 前言
USB开发跟其他文件设备(如串口)开发一样,难点是找到该USB设备的路径,本文以DDK里src/usb/bulkusb例子为参考,阐述一个非HID的USB调试器软件的开发过程。
2 设备GUID
一般设备会有两个GUID, 一个为Class GUID, 在INF文件中,另一个为Device GUID,在SYS文件中。
CreateFile使用的是SYS中的GUID,想得到它有两个办法:
1 跟设备的提供者索要。
2在注册表里找,一般在:
HKEY_LOCAL_MACHINE/SYSTEM/ControlSet001/Control/DeviceClasses/
3 设备路径
根据设备GUID,枚举所有USB HOST,找匹配的USB设备,然后获取其路径。
3.1 头文件 usbport.h
#define WINVER 0x0500
#include <windows.h>
#include <setupapi.h>
#include <basetyps.h>
#include <usbdi.h>
#include <initguid.h>
#include <stdio.h>
#pragma comment(lib,"setupapi.lib")
#pragma comment(lib,"hid.lib")
#pragma comment(lib,"comctl32.lib")
#ifndef BULKUSBH_INC
#define BULKUSBH_INC
#define BULKUSB_IOCTL_INDEX 0x0000
#define IOCTL_BULKUSB_GET_CONFIG_DESCRIPTOR
CTL_CODE(FILE_DEVICE_UNKNOWN, /
BULKUSB_IOCTL_INDEX,/
METHOD_BUFFERED, /
FILE_ANY_ACCESS)
#define IOCTL_BULKUSB_RESET_DEVICE
CTL_CODE(FILE_DEVICE_UNKNOWN, /
BULKUSB_IOCTL_INDEX+1,/
METHOD_BUFFERED, /
FILE_ANY_ACCESS)
#define IOCTL_BULKUSB_RESET_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN, /
BULKUSB_IOCTL_INDEX+2,/
METHOD_BUFFERED, /
FILE_ANY_ACCESS)
extern HANDLE
open_file(char *filename);
extern int
GetUsbPath(char *path);
extern int
WriteUsb(HANDLE hUsb,char *Outbuff, int len);
extern int
ReadUsb(HANDLE hUsb,BYTE inbuff[],DWORD &nBytesRead,int nToRead);
3.2 源文件 usbport.cpp
#include "usbport.h"
//8a3bf75d-83c7-440e-8276-5ae3f3ea6e77
DEFINE_GUID(GUID_CLASS_I82930_BULK,0x8a3bf75d, 0x83c7, 0x440e,0x82, 0x76, 0x5a, 0xe3, 0xf3, 0xea, 0x6e, 0x77);
BOOL
GetUsbDeviceFileName( LPGUID pGuid, char *outNameBuf);
HANDLE
OpenUsbDevice( LPGUID pGuid, char *outNameBuf);
HANDLE
OpenOneDevice (HDEVINFO HardwareDeviceInfo, PSP_INTERFACE_DEVICE_DATA DeviceInfoData,char *devName);
int
GetUsbPath(char *path);
int
WriteUsb(HANDLE hUsb,char *Outbuff, int len);
int
ReadUsb(HANDLE hUsb,BYTE inbuff[], DWORD &nBytesRead,int nToRead);
/*名称:open_file
功能:打开USB设备
参数:filename 定义为”PIPE00” pipe name for bulk input pipe on our test board ,”PIPE01” pipe name for bulk output pipe on our test board。
PIPE00 和 PIPE01 是参考src/usb/bulkusb,我实际在用时这两个效果一样,为了避免USB异常引起的死机,我文件打开采用非阻塞模式。
*/
HANDLE open_file( char *filename)
{
int success = 1;
HANDLE h;
char completeDeviceName[256] = ""; //generated from the GUID registered by the driver itself
if ( !GetUsbDeviceFileName((LPGUID) &GUID_CLASS_I82930_BULK,completeDeviceName) )
{
//NOISY(("Failed to GetUsbDeviceFileName/n", GetLastError()));
return INVALID_HANDLE_VALUE;
}
strcat (completeDeviceName, "//");
strcat (completeDeviceName, filename);
//printf("completeDeviceName = (%s)/n", completeDeviceName);
h = CreateFile(completeDeviceName,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (h == INVALID_HANDLE_VALUE) {
//NOISY(("Failed to open (%s) = %d", completeDeviceName, GetLastError()));
success = 0;
} else {
//NOISY(("Opened successfully./n"));
}
return h;
}
/*名称:GetUsbDeviceFileName
功能:获取USB设备路径
参数:pGUID
返回:outNameBuf USB设备路径
*/
BOOL GetUsbDeviceFileName( LPGUID pGuid, char *outNameBuf)
{
HANDLE hDev = OpenUsbDevice( pGuid, outNameBuf );
if ( hDev != INVALID_HANDLE_VALUE )
{
CloseHandle( hDev );
return TRUE;
}
return FALSE;
}
/*名称:OpenUsbDevice
功能:获取
USB设备路径
参数:
pGUID 设备GUID
返回:
outNameBuf USB设备路径
*/
HANDLE OpenUsbDevice( LPGUID pGuid, char *outNameBuf)
{
ULONG NumberDevices;
HANDLE hOut = INVALID_HANDLE_VALUE;
HDEVINFO hardwareDeviceInfo;
SP_INTERFACE_DEVICE_DATA deviceInfoData;
ULONG i;
BOOLEAN done;
PUSB_DEVICE_DESCRIPTOR usbDeviceInst;
PUSB_DEVICE_DESCRIPTOR *UsbDevices = &usbDeviceInst;
*UsbDevices = NULL;
NumberDevices = 0;
//
// Open a handle to the plug and play dev node.
// SetupDiGetClassDevs() returns a device information set that contains info on all
// installed devices of a specified class.
//
hardwareDeviceInfo = SetupDiGetClassDevs (
pGuid,
NULL, // Define no enumerator (global)
NULL, // Define no
(DIGCF_PRESENT | // Only Devices present
DIGCF_INTERFACEDEVICE)); // Function class devices.
//
// Take a wild guess at the number of devices we have;
// Be prepared to realloc and retry if there are more than we guessed
//
NumberDevices = 4;
done = FALSE;
deviceInfoData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);
i=0;
while (!done)
{
NumberDevices *= 2;
if (*UsbDevices)
{
*UsbDevices = (PUSB_DEVICE_DESCRIPTOR)realloc (*UsbDevices, (NumberDevices * sizeof (USB_DEVICE_DESCRIPTOR)));
}
else
{
*UsbDevices = (PUSB_DEVICE_DESCRIPTOR)calloc (NumberDevices, sizeof (USB_DEVICE_DESCRIPTOR));
}
if (NULL == *UsbDevices)
{
// SetupDiDestroyDeviceInfoList destroys a device information set
// and frees all associated memory.
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
return INVALID_HANDLE_VALUE;
}
usbDeviceInst = *UsbDevices + i;
for (; i < NumberDevices; i++)
{
// SetupDiEnumDeviceInterfaces() returns information about device interfaces
// exposed by one or more devices. Each call returns information about one interface;
// the routine can be called repeatedly to get information about several interfaces
// exposed by one or more devices.
if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo,
0, // We don't care about specific PDOs
pGuid,
i,
&deviceInfoData)) {
hOut = OpenOneDevice (hardwareDeviceInfo, &deviceInfoData, outNameBuf);
if ( hOut != INVALID_HANDLE_VALUE )
{
done = TRUE;
break;
}
}
else
{
if (ERROR_NO_MORE_ITEMS == GetLastError())
{
done = TRUE;
break;
}
}
}
}
NumberDevices = i;
// SetupDiDestroyDeviceInfoList() destroys a device information set
// and frees all associated memory.
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
free ( *UsbDevices );
return hOut;
}
HANDLE OpenOneDevice (
IN HDEVINFO HardwareDeviceInfo,
IN PSP_INTERFACE_DEVICE_DATA DeviceInfoData,
IN char *devName
)
{
PSP_INTERFACE_DEVICE_DETAIL_DATA functionClassDeviceData = NULL;
ULONG predictedLength = 0;
ULONG requiredLength = 0;
HANDLE hOut = INVALID_HANDLE_VALUE;
//
// allocate a function class device data structure to receive the
// goods about this particular device.
//
SetupDiGetInterfaceDeviceDetail (
HardwareDeviceInfo,
DeviceInfoData,
NULL, // probing so no output buffer yet
0, // probing so output buffer length of zero
&requiredLength,
NULL); // not interested in the specific dev-node
predictedLength = requiredLength;
// sizeof (SP_FNCLASS_DEVICE_DATA) + 512;
functionClassDeviceData = (PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc (predictedLength);
functionClassDeviceData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);
//
// Retrieve the information from Plug and Play.
//
if (! SetupDiGetInterfaceDeviceDetail (
HardwareDeviceInfo,
DeviceInfoData,
functionClassDeviceData,
predictedLength,
&requiredLength,
NULL)) {
free( functionClassDeviceData );
return INVALID_HANDLE_VALUE;
}
strcpy( devName,functionClassDeviceData->DevicePath) ;
//printf( "Attempting to open %s/n", devName );
hOut = CreateFile (
functionClassDeviceData->DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // no SECURITY_ATTRIBUTES structure
OPEN_EXISTING, // No special create flags
0, // No special attributes
NULL); // No template file
if (INVALID_HANDLE_VALUE == hOut)
{
//printf( "FAILED to open %s/n", devName );
}
free( functionClassDeviceData );
return hOut;
}
/*名称:
GetUsbPath
功能:返回
USB设备路径
参数:
pGUID
返回:
path 路径
*/
int
GetUsbPath(char *path)
{
if ( !GetUsbDeviceFileName((LPGUID) &GUID_CLASS_I82930_BULK,path) )
{
return 0;
}
return 1;
}
/*名称:
WriteUsb
功能:向
USB写数据
参数:
hUsb USB句柄,Outbut 数据指针,len 数据长度
*/
int WriteUsb(HANDLE hUsb,char *Outbuff, int len)
{
DWORD nBytesWrite,endtime,lrc;
static OVERLAPPED ol;
DWORD dwErrorMask,dwError;
COMSTAT comstat;
if(hUsb==NULL)
return 0;
ol.Offset=0; //设备使用指定
0
ol.OffsetHigh=0; //设备使用指定
0
ol.hEvent=NULL; //标识事件为非信号状态,数据传送完成时,它将被设为信号状态
ol.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
if(!WriteFile(hUsb,Outbuff,len,&nBytesWrite,&ol))
{
//出错信息处理
--------------------------------
if((lrc=GetLastError())==ERROR_IO_PENDING)
{
endtime=GetTickCount()+1000;
while(!GetOverlappedResult(hUsb,&ol,&nBytesWrite,FALSE))
{
dwError=GetLastError();
if(GetTickCount()>endtime)
{
MessageBox(NULL,"写串口时间过长,目前串口发送缓冲区中的数据数目为空
",NULL,NULL);
break;
}
if(dwError=ERROR_IO_INCOMPLETE)
continue; //未完全读完时的正常返回结果
else
{
// 发生错误,尝试恢复!
break;
}
}
}
//-------------------------------------------------//
}
CloseHandle(ol.hEvent);
FlushFileBuffers(hUsb);
return 1;
}
/*名称:
ReadUsb
功能:读取
USB设备发来的数据
参数:
hUsb USB句柄,nToRead读取的长度
返回:
inbuff 读到的数据,nBytesRead 读到的长度
*/
int ReadUsb(HANDLE hUsb,BYTE inbuff[], DWORD &nBytesRead,int nToRead)
{
DWORD lrc; ///纵向冗余校验
DWORD endtime; /jiesuo
static OVERLAPPED ol;
int ReadNumber=0;
int numCount=0 ; //控制读取的数目
DWORD dwErrorMask;
DWORD dwEvtMask=0 ;
DWORD ntoread;
int ReadTime;
ReadTime=2000;
ntoread=nToRead;
ol.Offset=0; ///相对文件开始的字节偏移量
ol.OffsetHigh=0; ///开始传送数据的字节偏移量的高位字,管道和通信时调用进程可忽略。
ol.hEvent=NULL; ///标识事件,数据传送完成时设为信号状态
ol.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
if(!ReadFile(hUsb,inbuff,ntoread,&nBytesRead,&ol))
{
if((lrc=GetLastError())==ERROR_IO_PENDING)
{
///
endtime=GetTickCount()+ReadTime;//GetTickCount()取回系统开始至此所用的时间
(毫秒)
while(!GetOverlappedResult(hUsb,&ol,&nBytesRead,FALSE))//该函数取回重叠操作的结果
{
if(GetTickCount()>endtime)
break;
}
}
}
CloseHandle(ol.hEvent);
return 1;
}
4 编译前提
开发
USB程序,需要下载Microsotft的DDK(DRIVER DEVELOP KIT)库,该库的配置请参考http://blog.csdn.net/skdev/archive/2007/01/26/1494635.aspx
5 效果
以上是关于USB应用程序开发的主要内容,如果未能解决你的问题,请参考以下文章