您的位置:首页 > 其它

遍历USB devcie,读取设备描述符 device descriptor

2015-12-09 18:47 477 查看
http://blog.csdn.net/jtujtujtu/article/details/4836900

理论:

对于USB接口的设备,现在越来越多了。本篇我们就通过获取一个USB扫描仪设备中的序列号,来介绍如何获取usb设备的一些硬件信息。对于usb设备都是采用HCD0,HCD1,HCD2,HCD3等符号描述的。如下图:



因此,有了这个名字,我们就可以使用CreateFile来打开usb设备。然后使用DeviceIoControl函数与usb设备通讯了。HCD是host controller driver的简写。需要了解详情的,还要仔细的阅读usb协议。

usb的通讯基本步骤如下图所示:



基本步骤:

1)打开HCD%X

2) 得到上面的USB root hub

3) 遍历usb root hub上连接的usb 设备。获取信息

4)如果有多个usb口,循环前3步。

下面介绍通讯用的几个IOCTL:

1)USB_HCD_DRIVERKEY_NAME ,用于获取USB设备驱动在注册表中的键名。相应的一个结构体是:

typedef struct _USB_HCD_DRIVERKEY_NAME

{

ULONG ActualLength;

WCHAR DriverKeyName[1];

} USB_HCD_DRIVERKEY_NAME, *PUSB_HCD_DRIVERKEY_NAME;

2)IOCTL_USB_GET_ROOT_HUB_NAME,用于获取root hub 键名。使用的结构体,跟上面一样。

typedef struct _USB_ROOT_HUB_NAME

{

ULONG ActualLength;

WCHAR RootHubName[1];

} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME;

3)IOCTL_USB_GET_NODE_INFORMATION,用于获取连接在root hub上的节点设备信息。也就是我们接在usb口上的所有usb设备的信息,对应的结构体:

typedef struct _USB_NODE_INFORMATION

{

USB_HUB_NODE NodeType;

union {

USB_HUB_INFORMATION HubInformation;

USB_MI_PARENT_INFORMATION MiParentInformation;

} u;

} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION;

typedef struct _USB_MI_PARENT_INFORMATION

{

ULONG NumberOfInterfaces;

} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION;

typedef struct _USB_HUB_INFORMATION

{

USB_HUB_DESCRIPTOR HubDescriptor;

BOOLEAN HubIsBusPowered;

} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION;

typedef struct _USB_HUB_DESCRIPTOR

{

UCHAR bDescriptorLength; // Length of this descriptor

UCHAR bDescriptorType; // Hub configuration type

UCHAR bNumberOfPorts; // number of ports on this hub

USHORT wHubCharacteristics; // Hub Charateristics

UCHAR bPowerOnToPowerGood; // port power on till power good in 2ms

UCHAR bHubControlCurrent; // max current in mA

//

// room for 255 ports power control and removable bitmask

UCHAR bRemoveAndPowerMask[64];

} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;

4) IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, 用于获取接在usb口上的单个usb设备的信息,对应的结构体:

typedef struct _USB_NODE_CONNECTION_INFORMATION

{

ULONG ConnectionIndex;

USB_DEVICE_DESCRIPTOR DeviceDescriptor;

UCHAR CurrentConfigurationValue;

BOOLEAN LowSpeed;

BOOLEAN DeviceIsHub;

USHORT DeviceAddress;

ULONG NumberOfOpenPipes;

USB_CONNECTION_STATUS ConnectionStatus;

USB_PIPE_INFO PipeList[0];

} USB_NODE_CONNECTION_INFORMATION, *PUSB_NODE_CONNECTION_INFORMATION;

4)IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, 用于获取usb设备的描述信息。

typedef struct _USB_DEVICE_DESCRIPTOR

{

UCHAR bLength;

UCHAR bDescriptorType;

USHORT bcdUSB;

UCHAR bDeviceClass;

UCHAR bDeviceSubClass;

UCHAR bDeviceProtocol;

UCHAR bMaxPacketSize0;

USHORT idVendor;

USHORT idProduct;

USHORT bcdDevice;

UCHAR iManufacturer;

UCHAR iProduct;

UCHAR iSerialNumber;

UCHAR bNumConfigurations;

} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;

typedef struct _USB_DEVICE_DESCRIPTOR

{

UCHAR bLength;

UCHAR bDescriptorType;

USHORT bcdUSB;

UCHAR bDeviceClass;

UCHAR bDeviceSubClass;

UCHAR bDeviceProtocol;

UCHAR bMaxPacketSize0;

USHORT idVendor;

USHORT idProduct;

USHORT bcdDevice;

UCHAR iManufacturer;

UCHAR iProduct;

UCHAR iSerialNumber;

UCHAR bNumConfigurations;

} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;

typedef enum _USB_CONNECTION_STATUS

{

NoDeviceConnected,

DeviceConnected,

/* failure codes, these map to fail reasons */

DeviceFailedEnumeration,

DeviceGeneralFailure,

DeviceCausedOvercurrent,

DeviceNotEnoughPower,

DeviceNotEnoughBandwidth,

DeviceHubNestedTooDeeply,

DeviceInLegacyHub

} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS;

typedef struct _USB_PIPE_INFO

{

USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;

ULONG ScheduleOffset;

} USB_PIPE_INFO, *PUSB_PIPE_INFO;

typedef struct _USB_ENDPOINT_DESCRIPTOR

{

UCHAR bLength;

UCHAR bDescriptorType;

UCHAR bEndpointAddress;

UCHAR bmAttributes;

USHORT wMaxPacketSize;

UCHAR bInterval;

} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR;

需要注意一点,如果要得到pid,vid,则直接从USB_DEVICE_DESCRIPTOR结构中取出idVendor,idProduct这两项的值就行了。如果要得到序列号,则不是取出 iSerialNumber就可以的。这里的
iSerialNumber仅仅是一个索引值。如果想得到序列号,就需要定义一个结构,然后给设备发送个请求。请求的结构如下图:



代码参照GetStringDescriptor函数。可以根据iSerialNumber偏移,取出其对应的字符串,存放在上图USB_STRING_DESCRIPTOR结构中。
#include "windows.h"

#include "PlkUsbIo.h"

#include <malloc.h>

#define NUM_HCS_TO_CHECK 10

/******************************************************************/

bool EnumUsbDevice();

PCHAR GetDriverKeyName(HANDLE Hub, ULONG ConnectionIndex);

PCHAR GetHCDDriverKeyName(HANDLE HCD);

PCHAR GetRootHubName(HANDLE HostController);

PCHAR WideStrToMultiStr(PWCHAR WideStr);

bool GetStringDescriptor (

HANDLE hHubDevice,

ULONG ConnectionIndex,

UCHAR DescriptorIndex ,

CHAR * outBuff);

/******************************************************************/

int main(int argc, char* argv[])

{

EnumUsbDevice();

return 0;

}

bool EnumUsbDevice()

{

char HCName[16];

int HCNum;

HANDLE hHCDev;

PCHAR rootHubName;

ULONG index;

BOOL success;

PUSB_NODE_CONNECTION_INFORMATION connectionInfo;

HANDLE hHubDevice;

for (HCNum = 0; HCNum < NUM_HCS_TO_CHECK; HCNum++)

{

wsprintf(HCName, "////.//HCD%d", HCNum);

hHCDev = CreateFile(HCName,

GENERIC_WRITE,

FILE_SHARE_WRITE,

NULL,

OPEN_EXISTING,

0,

NULL);

if (hHCDev == INVALID_HANDLE_VALUE)

break;

PCHAR driverKeyName, deviceDesc;

driverKeyName = GetHCDDriverKeyName(hHCDev);

if(driverKeyName == NULL)

goto end;

ULONG nBytes;

rootHubName =(char*) GetRootHubName(hHCDev);

if(rootHubName==NULL)

goto end;

PUSB_NODE_INFORMATION HubInfo;

HubInfo = (PUSB_NODE_INFORMATION)malloc(sizeof(USB_NODE_INFORMATION));

PCHAR deviceName;

deviceName = (PCHAR)malloc(strlen(rootHubName) + sizeof("////.//"));

if (rootHubName != NULL)

{

strcpy(deviceName, "////.//");

strcpy(deviceName + sizeof("////.//") - 1, rootHubName);

hHubDevice = CreateFile(deviceName,

GENERIC_WRITE,

FILE_SHARE_WRITE,

NULL,

OPEN_EXISTING,

0,

NULL);

free(deviceName);

if (hHubDevice == INVALID_HANDLE_VALUE)

goto end;

success = DeviceIoControl(hHubDevice,

IOCTL_USB_GET_NODE_INFORMATION,

HubInfo,

sizeof(USB_NODE_INFORMATION),

HubInfo,

sizeof(USB_NODE_INFORMATION),

&nBytes,

NULL);

if (!success)

goto end;

}

int port;

port=HubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts;

for (index=1; index <= port; index++)

{

ULONG nBytes;

nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) +

sizeof(USB_PIPE_INFO) * 30;

connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)malloc(nBytes);

if (connectionInfo == NULL)

goto end;

connectionInfo->ConnectionIndex = index;

success = DeviceIoControl(hHubDevice,

IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,

connectionInfo,

nBytes,

connectionInfo,

nBytes,

&nBytes,

NULL);

if (!success)

{

free(connectionInfo);

goto end;

}

deviceDesc = NULL;

if (connectionInfo->ConnectionStatus != NoDeviceConnected)

{

driverKeyName = GetDriverKeyName(hHubDevice,

index);

if (driverKeyName)

{

free(driverKeyName);

}

}

if (connectionInfo->ConnectionStatus == DeviceConnected)

{

//取出序列号索引

UCHAR nSerialno = connectionInfo->DeviceDescriptor.iSerialNumber;

CHAR OutBuff[20] = {0};

GetStringDescriptor(hHubDevice,connectionInfo->ConnectionIndex,nSerialno,OutBuff);

//判断序列号是否有效

if(序列号是否有效)

{

CloseHandle(hHubDevice);

CloseHandle(hHCDev);

return true;

}

}

}

end:;

}

CloseHandle(hHubDevice);

CloseHandle(hHCDev);

return false;

}

PCHAR GetDriverKeyName(HANDLE Hub, ULONG ConnectionIndex)

{

BOOL success;

ULONG nBytes;

USB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyName;

PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyNameW;

PCHAR driverKeyNameA;

driverKeyNameW = NULL;

driverKeyNameA = NULL;

driverKeyName.ConnectionIndex = ConnectionIndex;

success = DeviceIoControl(Hub,

IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,

&driverKeyName,

sizeof(driverKeyName),

&driverKeyName,

sizeof(driverKeyName),

&nBytes,

NULL);

if (!success)

{

goto GetDriverKeyNameError;

}

nBytes = driverKeyName.ActualLength;

if (nBytes <= sizeof(driverKeyName))

{

goto GetDriverKeyNameError;

}

driverKeyNameW = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)malloc(nBytes);

if (driverKeyNameW == NULL)

{

goto GetDriverKeyNameError;

}

driverKeyNameW->ConnectionIndex = ConnectionIndex;

success = DeviceIoControl(Hub,

IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,

driverKeyNameW,

nBytes,

driverKeyNameW,

nBytes,

&nBytes,

NULL);

if (!success)

{

goto GetDriverKeyNameError;

}

driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName);

free(driverKeyNameW);

return driverKeyNameA;

GetDriverKeyNameError:

if (driverKeyNameW != NULL)

{

free(driverKeyNameW);

driverKeyNameW = NULL;

}

return NULL;

}

PCHAR GetRootHubName(HANDLE HostController)

{

BOOL success;

ULONG nBytes;

USB_ROOT_HUB_NAME rootHubName;

PUSB_ROOT_HUB_NAME rootHubNameW;

PCHAR rootHubNameA;

rootHubNameW = NULL;

rootHubNameA = NULL;

success = DeviceIoControl(HostController,

IOCTL_USB_GET_ROOT_HUB_NAME,

0,

0,

&rootHubName,

sizeof(rootHubName),

&nBytes,

NULL);

if (!success)

{

goto GetRootHubNameError;

}

nBytes = rootHubName.ActualLength;

rootHubNameW =(PUSB_ROOT_HUB_NAME) malloc(nBytes);

if (rootHubNameW == NULL)

{

goto GetRootHubNameError;

}

success = DeviceIoControl(HostController,

IOCTL_USB_GET_ROOT_HUB_NAME,

NULL,

0,

rootHubNameW,

nBytes,

&nBytes,

NULL);

if (!success)

{

goto GetRootHubNameError;

}

rootHubNameA = WideStrToMultiStr(rootHubNameW->RootHubName);

free(rootHubNameW);

return rootHubNameA;

GetRootHubNameError:

if (rootHubNameW != NULL)

{

free(rootHubNameW);

rootHubNameW = NULL;

}

return NULL;

}

PCHAR GetHCDDriverKeyName(HANDLE HCD)

{

BOOL success;

ULONG nBytes;

USB_HCD_DRIVERKEY_NAME driverKeyName;

PUSB_HCD_DRIVERKEY_NAME driverKeyNameW;

PCHAR driverKeyNameA;

driverKeyNameW = NULL;

driverKeyNameA = NULL;

success = DeviceIoControl(HCD,

IOCTL_GET_HCD_DRIVERKEY_NAME,

&driverKeyName,

sizeof(driverKeyName),

&driverKeyName,

sizeof(driverKeyName),

&nBytes,

NULL);

if (!success)

{

goto GetHCDDriverKeyNameError;

}

nBytes = driverKeyName.ActualLength;

if (nBytes <= sizeof(driverKeyName))

{

goto GetHCDDriverKeyNameError;

}

driverKeyNameW =(PUSB_HCD_DRIVERKEY_NAME) malloc(nBytes);

if (driverKeyNameW == NULL)

{

goto GetHCDDriverKeyNameError;

}

success = DeviceIoControl(HCD,

IOCTL_GET_HCD_DRIVERKEY_NAME,

driverKeyNameW,

nBytes,

driverKeyNameW,

nBytes,

&nBytes,

NULL);

if (!success)

{

goto GetHCDDriverKeyNameError;

}

driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName);

free(driverKeyNameW);

return driverKeyNameA;

GetHCDDriverKeyNameError:

if (driverKeyNameW != NULL)

{

free(driverKeyNameW);

driverKeyNameW = NULL;

}

return NULL;

}

PCHAR WideStrToMultiStr(PWCHAR WideStr)

{

ULONG nBytes;

PCHAR MultiStr;

nBytes = WideCharToMultiByte(

CP_ACP,

0,

WideStr,

-1,

NULL,

0,

NULL,

NULL);

if (nBytes == 0)

{

return NULL;

}

MultiStr =(PCHAR) malloc(nBytes);

if (MultiStr == NULL)

{

return NULL;

}

nBytes = WideCharToMultiByte(

CP_ACP,

0,

WideStr,

-1,

MultiStr,

nBytes,

NULL,

NULL);

if (nBytes == 0)

{

free(MultiStr);

return NULL;

}

return MultiStr;

}

bool GetStringDescriptor (

HANDLE hHubDevice,

ULONG ConnectionIndex,

UCHAR DescriptorIndex ,

CHAR * outBuff

)

{

BOOL success;

ULONG nBytes;

ULONG nBytesReturned;

UCHAR stringDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + MAXIMUM_USB_STRING_LENGTH];

PUSB_DESCRIPTOR_REQUEST stringDescReq;

PUSB_STRING_DESCRIPTOR stringDesc;

nBytes = sizeof(stringDescReqBuf);

stringDescReq = (PUSB_DESCRIPTOR_REQUEST)stringDescReqBuf;

stringDesc = (PUSB_STRING_DESCRIPTOR)(stringDescReq+1);

::ZeroMemory(stringDescReq,nBytes);

stringDescReq->ConnectionIndex = ConnectionIndex;

stringDescReq->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) | DescriptorIndex;

stringDescReq->SetupPacket.wIndex = GetSystemDefaultLangID();

stringDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST));

success = DeviceIoControl(hHubDevice,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,

stringDescReq,nBytes,

stringDescReq,nBytes,

&nBytesReturned,NULL);

if (!success || nBytesReturned < 2)

return false;

if (stringDesc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE)

return false;

if (stringDesc->bLength != nBytesReturned - sizeof(USB_DESCRIPTOR_REQUEST))

return false;

if (stringDesc->bLength % 2 != 0)

return false;

WCHAR * wChar = new WCHAR[stringDesc->bLength + 1];

memcpy(wChar,stringDesc->bString,stringDesc->bLength);

char *szTemp = WideStrToMultiStr(wChar);

lstrcpy(outBuff, szTemp);

if(szTemp)

delete []szTemp;

if(wChar)

delete []wChar;

return true;

}

分析:

1)首先假定有10个usb接口

#define NUM_HCS_TO_CHECK 10

2)循环打开这10个usb端口,如果端口没有这么多,调用CreateFile,就会返回
INVALID_HANDLE_VALUE。

for (HCNum = 0; HCNum < NUM_HCS_TO_CHECK; HCNum++)

{

wsprintf(HCName, "////.//HCD%d", HCNum);

hHCDev = CreateFile(HCName,

GENERIC_WRITE,

FILE_SHARE_WRITE,

NULL,

OPEN_EXISTING,

0,

NULL);

if (hHCDev == INVALID_HANDLE_VALUE)

break;

3)获取root hub

ULONG nBytes;

rootHubName =(char*) GetRootHubName(hHCDev);

if(rootHubName==NULL)

goto end;

4) 遍历连接在root hub上的节点

int port;

port=HubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts;

for (index=1; index <= port; index++)

{

ULONG nBytes;

nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) +

sizeof(USB_PIPE_INFO) * 30;

connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)malloc(nBytes);

if (connectionInfo == NULL)

goto end;

connectionInfo->ConnectionIndex = index;

success = DeviceIoControl(hHubDevice,

IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,

connectionInfo,

nBytes,

connectionInfo,

nBytes,

&nBytes,

NULL);

if (!success)

{

free(connectionInfo);

goto end;

}

5)根据节点的连接状态,获取节点信息,得到序列号。

if (connectionInfo->ConnectionStatus == DeviceConnected)

{

//取出序列号索引

UCHAR nSerialno = connectionInfo->DeviceDescriptor.iSerialNumber;

CHAR OutBuff[20] = {0};

GetStringDescriptor(hHubDevice,connectionInfo->ConnectionIndex,nSerialno,OutBuff);

6)得到序列号的方法在理论部分已经详细说明了,对应的函数是GetStringDescriptor,这里不再重复。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: