/*++
Copyright (c) 1997-1998 Microsoft Corporation
Module Name:
ENUM.C
Abstract:
This source file contains the routines which enumerate the USB bus
and populate the TreeView control.
The enumeration process goes like this:
(1) Enumerate Host Controllers and Root Hubs
Host controllers currently have symbolic link names of the form HCDx,
where x starts at 0. Use CreateFile() to open each host controller
symbolic link. Create a node in the TreeView to represent each host
controller.
After a host controller has been opened, send the host controller an
IOCTL_USB_GET_ROOT_HUB_NAME request to get the symbolic link name of
the root hub that is part of the host controller.
(2) Enumerate Hubs (Root Hubs and External Hubs)
Given the name of a hub, use CreateFile() to hub the hub. Send the
hub an IOCTL_USB_GET_NODE_INFORMATION request to get info about the
hub, such as the number of downstream ports. Create a node in the
TreeView to represent each hub.
(3) Enumerate Downstream Ports
Given an handle to an open hub and the number of downstream ports on
the hub, send the hub an IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX
request for each downstream port of the hub to get info about the
device (if any) attached to each port. If there is a device attached
to a port, send the hub an IOCTL_USB_GET_NODE_CONNECTION_NAME request
to get the symbolic link name of the hub attached to the downstream
port. If there is a hub attached to the downstream port, recurse to
step (2). Create a node in the TreeView to represent each hub port
and attached device.
Environment:
user mode
Revision History:
04-25-97 : created
--*/
//*****************************************************************************
// I N C L U D E S
//*****************************************************************************
#include <windows.h>
#include <basetyps.h>
#include <winioctl.h>
#include <setupapi.h>
#include "usbview.h"
//*****************************************************************************
// D E F I N E S
//*****************************************************************************
#define NUM_HCS_TO_CHECK 10
#define CONFIGNUMBER 0 // <-- What about other indices??
//*****************************************************************************
// L O C A L F U N C T I O N P R O T O T Y P E S
//*****************************************************************************
static void EnumerateHub(
HTREEITEM hTreeParent,
PTSTR HubName,
PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo,
PUSB_DESCRIPTOR_REQUEST ConfigDesc,
PSTRING_DESCRIPTOR_NODE StringDescs,
PTSTR DeviceDesc);
//*****************************************************************************
// G L O B A L S P R I V A T E T O T H I S F I L E
//*****************************************************************************
const PCHAR ConnectionStatuses[] = {
"NoDeviceConnected",
"DeviceConnected",
"DeviceFailedEnumeration",
"DeviceGeneralFailure",
"DeviceCausedOvercurrent",
"DeviceNotEnoughPower"
};
int TotalDevicesConnected;
int TotalHubs;
//*****************************************************************************
// WideStrToStr(), works like StrStr()
//*****************************************************************************
static PTSTR WideStrToStr(PWCHAR WideStr) {
ULONG nBytes;
PTSTR r;
#ifdef UNICODE
// StrStr() using ALLOC
nBytes=(lstrlen(WideStr)+1)*2;
r=ALLOC(nBytes);
CopyMemory(r,WideStr,nBytes);
#else
// Get the length of the converted string
nBytes=WideCharToMultiByte(CP_ACP,0,WideStr,-1,NULL,0,NULL,NULL);
if (!nBytes) return NULL;
// Allocate space to hold the converted string
r=ALLOC(nBytes);
if (!r) return NULL;
// Convert the string
WideCharToMultiByte(CP_ACP,0,WideStr,-1,r,nBytes,NULL,NULL);
#endif
return r;
}
//*****************************************************************************
//
// GetHCDDriverKeyName()
//
//*****************************************************************************
static PTSTR GetHCDDriverKeyName(HANDLE HCD) {
BOOL success;
ULONG nBytes;
USB_HCD_DRIVERKEY_NAME driverKeyName;
PUSB_HCD_DRIVERKEY_NAME driverKeyNameW=NULL;
PTSTR r;
// Get the length of the name of the driver key of the HCD
//
success = DeviceIoControl(HCD,IOCTL_GET_HCD_DRIVERKEY_NAME,
&driverKeyName,sizeof(driverKeyName),
&driverKeyName,sizeof(driverKeyName),
&nBytes,NULL);
if (!success) {
OOPS();
goto GetHCDDriverKeyNameError;
}
// Allocate space to hold the driver key name
//
nBytes = driverKeyName.ActualLength;
if (nBytes <= sizeof(driverKeyName)) {
OOPS();
goto GetHCDDriverKeyNameError;
}
driverKeyNameW = ALLOC(nBytes);
if (!driverKeyNameW) {
OOPS();
goto GetHCDDriverKeyNameError;
}
// Get the name of the driver key of the device attached to
// the specified port.
//
success = DeviceIoControl(HCD,IOCTL_GET_HCD_DRIVERKEY_NAME,
driverKeyNameW,nBytes,
driverKeyNameW,nBytes,
&nBytes,NULL);
if (!success) {
OOPS();
goto GetHCDDriverKeyNameError;
}
// Convert the driver key name
//
r = WideStrToStr(driverKeyNameW->DriverKeyName);
// All done, free the uncoverted driver key name and return the
// converted driver key name
//
FREE(driverKeyNameW);
return r;
GetHCDDriverKeyNameError:
// There was an error, free anything that was allocated
//
if (driverKeyNameW) driverKeyNameW = FREE(driverKeyNameW);
return NULL;
}
//*****************************************************************************
//
// GetRootHubName()
//
//*****************************************************************************
static PTSTR GetRootHubName(HANDLE HostController) {
BOOL success;
ULONG nBytes;
USB_ROOT_HUB_NAME rootHubName;
PUSB_ROOT_HUB_NAME rootHubNameW=NULL;
PTSTR r;
// Get the length of the name of the Root Hub attached to the
// Host Controller
//
success = DeviceIoControl(HostController,IOCTL_USB_GET_ROOT_HUB_NAME,
0,0,
&rootHubName,sizeof(rootHubName),
&nBytes,NULL);
if (!success) {
OOPS();
goto GetRootHubNameError;
}
// Allocate space to hold the Root Hub name
//
nBytes = rootHubName.ActualLength;
rootHubNameW = ALLOC(nBytes);
if (!rootHubNameW) {
OOPS();
goto GetRootHubNameError;
}
// Get the name of the Root Hub attached to the Host Controller
//
success = DeviceIoControl(HostController,IOCTL_USB_GET_ROOT_HUB_NAME,
NULL,0,
rootHubNameW,nBytes,
&nBytes,NULL);
if (!success) {
OOPS();
goto GetRootHubNameError;
}
// Convert the Root Hub name
//
r = WideStrToStr(rootHubNameW->RootHubName);
// All done, free the uncoverted Root Hub name and return the
// converted Root Hub name
//
FREE(rootHubNameW);
return r;
GetRootHubNameError:
// There was an error, free anything that was allocated
//
if (rootHubNameW) rootHubNameW = FREE(rootHubNameW);
return NULL;
}
//*****************************************************************************
// GetDriverKeyName()
//*****************************************************************************
static PTSTR GetDriverKeyName(HANDLE Hub, ULONG ConnectionIndex) {
BOOL success;
ULONG nBytes;
USB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyName;
PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyNameW=NULL;
PTSTR r;
// Get the length of the name of the driver key of the device attached to
// the specified port.
//
driverKeyName.ConnectionIndex = ConnectionIndex;
success = DeviceIoControl(Hub,IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
&driverKeyName,sizeof(driverKeyName),
&driverKeyName,sizeof(driverKeyName),
&nBytes,NULL);
if (!success) {
OOPS();
goto GetDriverKeyNameError;
}
// Allocate space to hold the driver key name
//
nBytes = driverKeyName.ActualLength;
if (nBytes <= sizeof(driverKeyName)) {
OOPS();
goto GetDriverKeyNameError;
}
driverKeyNameW = ALLOC(nBytes);
if (!driverKeyNameW) {
OOPS();
goto GetDriverKeyNameError;
}
// Get the name of the driver key of the device attached to
// the specified port.
//
driverKeyNameW->ConnectionIndex = ConnectionIndex;
success = DeviceIoControl(Hub,IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
driverKeyNameW,nBytes,
driverKeyNameW,nBytes,
&nBytes,NULL);
if (!success) {
OOPS();
goto GetDriverKeyNameError;
}
// Convert the driver key name
//
r = WideStrToStr(driverKeyNameW->DriverKeyName);
// All done, free the uncoverted driver key name and return the
// converted driver key name
//
FREE(driverKeyNameW);
return r;
GetDriverKeyNameError:
// There was an error, free anything that was allocated
//
if (driverKeyNameW) driverKeyNameW = FREE(driverKeyNameW);
return NULL;
}
// Universal routine to get a descriptor (with bmRequestType==0x80 and bRequest==0x06).
// The memory block is allocated with ALLOC() and must be freed (or re-allocated) by caller.
// If rlen==NULL the memory block is auto-shrinked
PUSB_DESCRIPTOR_REQUEST GetDescriptor(HANDLE h, ULONG idx, USHORT wValue, USHORT wIndex, DWORD wLength, DWORD *rlen) {
DWORD len=sizeof(USB_DESCRIPTOR_REQUEST)+wLength;
DWORD rret;
PUSB_DESCRIPTOR_REQUEST rq=ALLOC(len);
if (!rq) {
OOPS();
return NULL;
}
rq->ConnectionIndex=idx;
// USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this
// IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.
// USBD will automatically initialize these fields:
// bmRequest = 0x80
// bRequest = 0x06
// We must inititialize these fields:
// wValue = Descriptor Type (high) and Descriptor Index (low byte)
// wIndex = Zero (or Language ID for String Descriptors)
// wLength = Length of descriptor buffer
rq->SetupPacket.wValue=wValue;
rq->SetupPacket.wIndex=wIndex;
rq->SetupPacket.wLength=(USHORT)wLength;
if (!DeviceIoControl(h,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,rq,len,rq,len,&rret,NULL)) {
OOPS();
FREE(rq);
return NULL;
}
if (rlen) *rlen=rret-sizeof(USB_DESCRIPTOR_REQUEST); // report data length
else if (rret<len) rq=REALLOC(rq,rret); // shrink memory (should always succeed)
if (!rq) OOPS();
return rq;
}
//*****************************************************************************
// GetConfigDescriptor()
// h - Handle of the hub device containing the port from which the
// Configuration Descriptor will be requested.
// idx - Identifies the port on the hub to which a device is
// attached from which the Configuration Descriptor will be requested.
// ConfigNumber - Configuration Descriptor index, zero based.
//*****************************************************************************
PUSB_DESCRIPTOR_REQUEST GetConfigDescriptor(HANDLE h, ULONG idx, USHORT wValue) {
DWORD len=512,rlen;
PUSB_DESCRIPTOR_REQUEST prq; // request pointer with data
#define pcd ((PUSB_CONFIGURATION_DESCRIPTOR)(prq+1))
// Try to get entire descriptor, starting with 512 bytes length
prq = GetDescriptor(h,idx,wValue,0,len,&rlen);
if (!prq) {
OOPS();
return NULL;
}
if (rlen==len && pcd->wTotalLength>len) {
// Get entire descriptor with known length when buffer was too small
DWORD len = pcd->wTotalLength;
FREE(prq);
prq = GetDescriptor(h,idx,wValue,0,len,&rlen);
if (!prq) {
OOPS();
return NULL;
}
if (rlen!=len) OOPS();
}
if (rlen<len) prq=REALLOC(prq,sizeof(USB_DESCRIPTOR_REQUEST)+rlen); // make block smaller
if (rlen!=pcd->wTotalLength) { // must be the same now
OOPS();
FREE(prq);
return NULL;
}
return prq;
#undef pcd
}
//*****************************************************************************
//
// AreThereStringDescriptors()
//
// DeviceDesc - Device Descriptor for which String Descriptors should be
// checked.
//
// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor)
// for which String Descriptors should be checked.
//
//*****************************************************************************
bool AreThereStringDescriptors (
PUSB_DEVICE_DESCRIPTOR DeviceDesc,
PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc
)
{
PUCHAR descEnd;
PUSB_COMMON_DESCRIPTOR commonDesc;
//
// Check Device Descriptor strings
//
if (DeviceDesc->iManufacturer ||
DeviceDesc->iProduct ||
DeviceDesc->iSerialNumber
)
{
return TRUE;
}
//
// Check the Configuration and Interface Descriptor strings
//
descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;
commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;
while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&
(PUCHAR)commonDesc + commonDesc->bLength <= descEnd)
{
switch (commonDesc->bDescriptorType)
{
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR))
{
OOPS();
break;
}
if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration)
{
return TRUE;
}
(PUCHAR)commonDesc += commonDesc->bLength;
continue;
case USB_INTERFACE_DESCRIPTOR_TYPE:
if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) &&
commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2))
{
OOPS();
break;
}
if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface)
{
return TRUE;
}
(PUCHAR)commonDesc += commonDesc->bLength;
continue;
default:
(PUCHAR)commonDesc += commonDesc->bLength;
continue;
}
break;
}
return FALSE;
}
//*****************************************************************************
//
// GetStringDescriptor()
//
// hHubDevice - Handle of the hub device containing the port from which the
// String Descriptor will be requested.
//
// ConnectionIndex - Identifies the port on the hub to which a device is
// attached from which the String Descriptor will be requested.
//
// DescriptorIndex - String Descriptor index.
//
// LanguageID - Language in which the string should be requested.
//
//*****************************************************************************
PSTRING_DESCRIPTOR_NODE GetStringDescriptor (HANDLE h, ULONG idx, UCHAR StringIndex, USHORT LanguageID) {
DWORD rlen;
PUSB_DESCRIPTOR_REQUEST prq;
#define psd ((PUSB_STRING_DESCRIPTOR)(prq+1))
PSTRING_DESCRIPTOR_NODE ret;
prq = GetDescriptor(h,idx,MAKEWORD(StringIndex,USB_STRING_DESCRIPTOR_TYPE),LanguageID,256,&rlen);
if (!prq) {
OOPS();
return NULL;
}
if (rlen < 2
|| psd->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE
|| psd->bLength != rlen
|| rlen & 1) { // some sanity checks
OOPS();
FREE(prq);
return NULL;
}
// Looks good, allocate zero-filled space for the string descriptor
// node and copy the string descriptor to it.
ret = ALLOC(sizeof(STRING_DESCRIPTOR_NODE) + psd->bLength);
if (!ret) {
OOPS();
FREE(prq);
return NULL;
}
ret->DescriptorIndex = StringIndex;
ret->LanguageID = LanguageID;
CopyMemory(ret->StringDescriptor,psd,rlen);
FREE(prq);
#undef psd
return ret;
}
//*****************************************************************************
//
// GetStringDescriptors()
//
// h - Handle of the hub device containing the port from which the
// String Descriptor will be requested.
//
// idx - Identifies the port on the hub to which a device is
// attached from which the String Descriptor will be requested.
//
// StringIndex - String Descriptor index.
//
// StringDescList - Anchor of list with the language IDs
//
//*****************************************************************************
static void GetStringDescriptors(HANDLE h, ULONG idx, UCHAR StringIndex, PSTRING_DESCRIPTOR_NODE StringDescList) {
// Save first node with the language list
PSTRING_DESCRIPTOR_NODE Str0=StringDescList;
int i;
int NumLangIDs=(Str0->StringDescriptor->bLength>>1)-1;
// Search the end of list and bail out if DescriptorIndex is already in list
for (;;StringDescList=StringDescList->Next) {
if (StringDescList->DescriptorIndex==StringIndex) return;
if (!StringDescList->Next) break;
}
// Append all language versions at the end of the list
for (i=0; i<NumLangIDs; i++) {
StringDescList->Next=GetStringDescriptor(h,idx,StringIndex,Str0->StringDescriptor->bString[i]);
if (StringDescList->Next) StringDescList=StringDescList->Next;
}
}
//*****************************************************************************
//
// GetAllStringDescriptors()
//
// hHubDevice - Handle of the hub device containing the port from which the
// String Descriptors will be requested.
//
// ConnectionIndex - Identifies the port on the hub to which a device is
// attached from which the String Descriptors will be requested.
//
// DeviceDesc - Device Descriptor for which String Descriptors should be
// requested.
//
// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor)
// for which String Descriptors should be requested.
//
//*****************************************************************************
PSTRING_DESCRIPTOR_NODE GetAllStringDescriptors(HANDLE h, ULONG idx,
PUSB_DEVICE_DESCRIPTOR DeviceDesc,
PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc) {
PSTRING_DESCRIPTOR_NODE ret;
PUCHAR descEnd;
PUSB_COMMON_DESCRIPTOR commonDesc;
// Get the array of supported Language IDs, which is returned
// in String Descriptor 0
ret = GetStringDescriptor(h,idx,0,0);
if (!ret) return NULL;
// Get the Device Descriptor strings
if (DeviceDesc->iManufacturer) GetStringDescriptors(h,idx,DeviceDesc->iManufacturer,ret);
if (DeviceDesc->iProduct) GetStringDescriptors(h,idx,DeviceDesc->iProduct,ret);
if (DeviceDesc->iSerialNumber) GetStringDescriptors(h,idx,DeviceDesc->iSerialNumber,ret);
// Get the Configuration and Interface Descriptor strings
descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;
commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;
while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&
(PUCHAR)commonDesc + commonDesc->bLength <= descEnd) {
switch (commonDesc->bDescriptorType) {
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
OOPS();
break;
}
if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration)
GetStringDescriptors(h,idx,((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration,ret);
(PUCHAR)commonDesc += commonDesc->bLength;
continue;
case USB_INTERFACE_DESCRIPTOR_TYPE:
if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) &&
commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2)) {
OOPS();
break;
}
if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface)
GetStringDescriptors(h,idx,((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface,ret);
(PUCHAR)commonDesc += commonDesc->bLength;
continue;
default:
(PUCHAR)commonDesc += commonDesc->bLength;
continue;
}
break;
}
return ret;
}
//*****************************************************************************
// Get the pointer to HID report descriptor, NULL if none
//*****************************************************************************
const USB_HID_DESCRIPTOR* LocateHidDesc(const BYTE*desc, const BYTE*end, BYTE*iface) {
for (;;) {
desc+=desc[0]; // go to next descriptor
if (desc[0]<2) return NULL;
if (desc+desc[0]>end) return NULL;
switch (desc[1]) {
case USB_INTERFACE_DESCRIPTOR_TYPE: {
if (iface) *iface=((const USB_INTERFACE_DESCRIPTOR*)desc)->bInterfaceNumber;
}break;
case USB_HID_DESCRIPTOR_TYPE: {
if (desc[0] < sizeof(USB_HID_DESCRIPTOR)) OOPS();
else return (const USB_HID_DESCRIPTOR*)desc;
}break;
}
}
}
//*****************************************************************************
// Get all HID descriptors (concatenated byte stream)
//*****************************************************************************
static BYTE* GetHidDesc(HANDLE h, ULONG idx, BYTE iface, const USB_HID_DESCRIPTOR*hidDesc) {
BYTE *buf,*p;
int i,len;
if (!hidDesc) return NULL;
// count up the length of all descriptors
for (i=0,len=1; i<hidDesc->bNumDescriptors; i++)
len+=hidDesc->OptionalDescriptors[i].wDescriptorLength;
// TODO: count the extra physical descriptor 0 length
// allocate the necessary buffer
buf=ALLOC(len);
if (!buf) return NULL;
// get the descriptor(s)
p=buf;
*p++=iface;
for (i=0; i<hidDesc->bNumDescriptors; i++) {
USB_DESCRIPTOR_REQUEST *DescReq;
int l=hidDesc->OptionalDescriptors[i].wDescriptorLength;
len=sizeof(*DescReq)+l;
DescReq=ALLOC(len); // allocate DeviceIoControl data, size can exceed 64K
if (!DescReq) {
OOPS();
FREE(buf);
return NULL;
}else{
DWORD BytesRead;
DescReq->ConnectionIndex=idx;
// DescReq->SetupPacket.bmRequest = 0x81; // should be class specific, and addressed to interface!! (0xA1) - weird USB HID spec!
// DescReq->SetupPacket.bRequest = 0x06;
DescReq->SetupPacket.wValue=MAKEWORD(i,hidDesc->OptionalDescriptors[i].bDescriptorType);
DescReq->SetupPacket.wIndex=iface;
DescReq->SetupPacket.wLength=l;
if (DeviceIoControl(h,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, // <-- TODO: Search the right IOCTL for this!
DescReq,len,DescReq,len,&BytesRead,NULL) && len==(int)BytesRead) {
CopyMemory(p,DescReq->Data,l);
}else{
OOPS();
}
p+=l; // advance pointer
FREE(DescReq);
}
}
return buf;
}
#if 0
// IOCTL_USB_USER_REQUEST
// USBUSER_OP_SEND_RAW_COMMAND
{
PUSB_SEND_RAW_COMMAND_PARAMETERS getDescriptor;
PUSBUSER_REQUEST_HEADER requestHeader;
BOOL success;
ULONG nBytes;
ULONG nBytesReturned;
UCHAR getDescriptorBuf[sizeof(USBUSER_REQUEST_HEADER)
+ sizeof(USB_SEND_RAW_COMMAND_PARAMETERS) + 0x80];
nBytes = sizeof(getDescriptorBuf);
requestHeader = (PUSBUSER_REQUEST_HEADER) getDescriptorBuf;
getDescriptor = (PUSB_SEND_RAW_COMMAND_PARAMETERS) (requestHeader + 1);
memset(requestHeader, 0, nBytes);
requestHeader->UsbUserRequest = USBUSER_OP_SEND_RAW_COMMAND;
requestHeader->RequestBufferLength = nBytes;
getDescriptor->Usb_bmRequest = 0x81;
getDescriptor->Usb_bRequest = 0x6; //GET_DESCRIPTOR;
getDescriptor->Usb_wValue = MAKEWORD(0,USB_HID_REPORT_TYPE);
getDescriptor->Usb_wIndex = 0;
getDescriptor->Usb_wLength = 0x80;
// Not sure how to set these...
getDescriptor->Timeout = 0;
getDescriptor->DataLength = 0;
getDescriptor->DeviceAddress = 0;
getDescriptor->MaximumPacketSize = 0;
getDescriptor->UsbdStatusCode = 0;
HexDump(stdout, NULL, getDescriptor, 8);
success = DeviceIoControl(hHCDevice, IOCTL_USB_USER_REQUEST, requestHeader,
nBytes, requestHeader, nBytes, &nBytesReturned, NULL);
if (!success)
{
DWORD osErr;
osErr = GetLastError();
Printf("USER_REQUEST: result=%d, lasterr=%08x\n", osErr, osErr);
}
HexDump(stdout, NULL, getDescriptorBuf, sizeof(getDescriptorBuf));
return success;
}
#endif
//*****************************************************************************
//
// GetExternalHubName()
//
//*****************************************************************************
static PTSTR GetExternalHubName(HANDLE Hub, ULONG ConnectionIndex) {
BOOL success;
ULONG nBytes;
USB_NODE_CONNECTION_NAME extHubName;
PUSB_NODE_CONNECTION_NAME extHubNameW=NULL;
PTSTR r;
// Get the length of the name of the external hub attached to the
// specified port.
//
extHubName.ConnectionIndex = ConnectionIndex;
success = DeviceIoControl(Hub,
IOCTL_USB_GET_NODE_CONNECTION_NAME,
&extHubName,
sizeof(extHubName),
&extHubName,
sizeof(extHubName),
&nBytes,
NULL);
if (!success)
{
OOPS();
goto GetExternalHubNameError;
}
// Allocate space to hold the external hub name
//
nBytes = extHubName.ActualLength;
if (nBytes <= sizeof(extHubName))
{
OOPS();
goto GetExternalHubNameError;
}
extHubNameW = ALLOC(nBytes*sizeof(TCHAR)); // REALLY??
if (extHubNameW == NULL)
{
OOPS();
goto GetExternalHubNameError;
}
// Get the name of the external hub attached to the specified port
//
extHubNameW->ConnectionIndex = ConnectionIndex;
success = DeviceIoControl(Hub,
IOCTL_USB_GET_NODE_CONNECTION_NAME,
extHubNameW,
nBytes,
extHubNameW,
nBytes,
&nBytes,
NULL);
if (!success)
{
OOPS();
goto GetExternalHubNameError;
}
// Convert the External Hub name
//
r = WideStrToStr(extHubNameW->NodeName);
// All done, free the uncoverted external hub name and return the
// converted external hub name
//
FREE(extHubNameW);
return r;
GetExternalHubNameError:
// There was an error, free anything that was allocated
//
if (extHubNameW != NULL)
{
FREE(extHubNameW);
extHubNameW = NULL;
}
return NULL;
}
//*****************************************************************************
//
// EnumerateHubPorts()
//
// hTreeParent - Handle of the TreeView item under which the hub port should
// be added.
//
// hHubDevice - Handle of the hub device to enumerate.
//
// NumPorts - Number of ports on the hub.
//
//*****************************************************************************
static void EnumerateHubPorts (HTREEITEM hTreeParent, HANDLE h, ULONG NumPorts) {
HTREEITEM hItem;
ULONG idx;
BOOL success;
PTSTR driverKeyName;
PTSTR deviceDesc;
char leafName[512]; // XXXXX how big does this have to be?
// Loop over all ports of the hub.
//
// Port indices are 1 based, not 0 based.
//
for (idx=1; idx <= NumPorts; idx++) {
USBDEVICEINFO cur;
PUSBDEVICEINFO info;
ULONG nBytes;
int iImage=2; // image index for port without device
ZeroMemory(&cur,sizeof(cur));
// Allocate space to hold the connection info for this port.
// For now, allocate it big enough to hold info for 30 pipes.
//
// Endpoint numbers are 0-15. Endpoint number 0 is the standard
// control endpoint which is not explicitly listed in the Configuration
// Descriptor. There can be an IN endpoint and an OUT endpoint at
// endpoint numbers 1-15 so there can be a maximum of 30 endpoints
// per device configuration.
//
// Should probably size this dynamically at some point.
//
nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) +
sizeof(USB_PIPE_INFO) * 30;
cur.ConnectionInfo = (PUSB_NODE_CONNECTION_INFORMATION_EX)ALLOC(nBytes);
if (!cur.ConnectionInfo) {
OOPS();
break;
}
//
// Now query USBHUB for the USB_NODE_CONNECTION_INFORMATION_EX structure
// for this port. This will tell us if a device is attached to this
// port, among other things.
//
cur.ConnectionInfo->ConnectionIndex = idx;
success=DeviceIoControl(h,
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
cur.ConnectionInfo,nBytes,
cur.ConnectionInfo,nBytes,&nBytes,NULL);
if (!success) {
nBytes=sizeof(USB_NODE_CONNECTION_INFORMATION)+sizeof(USB_PIPE_INFO)*30;
success = DeviceIoControl(h,
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
cur.ConnectionInfo,nBytes,
cur.ConnectionInfo,nBytes,&nBytes,NULL);
if (success) cur.ConnectionInfo->Speed=1-cur.ConnectionInfo->Speed;
}
if (!success) {
FREE(cur.ConnectionInfo);
continue;
}
// Update the count of connected devices
//
if (cur.ConnectionInfo->ConnectionStatus == DeviceConnected) {
TotalDevicesConnected++;
iImage++; // A device is connected (3)
}
if (cur.ConnectionInfo->DeviceIsHub) {
TotalHubs++;
iImage++; // This device is a HUB (4)
}
// If there is a device connected, get the Device Description
//
deviceDesc = NULL;
if (cur.ConnectionInfo->ConnectionStatus != NoDeviceConnected) {
driverKeyName = GetDriverKeyName(h,idx);
if (driverKeyName) {
deviceDesc = DriverNameToDeviceDesc(driverKeyName);
FREE(driverKeyName);
}
}
// If there is a device connected to the port, try to retrieve the
// Configuration Descriptor from the device.
//
if (Config.flags&CFLAG_CONFIGDESC &&
cur.ConnectionInfo->ConnectionStatus == DeviceConnected) {
cur.ConfigDesc = GetConfigDescriptor(h,idx,
MAKEWORD(CONFIGNUMBER,USB_CONFIGURATION_DESCRIPTOR_TYPE));
}
if (cur.ConfigDesc && AreThereStringDescriptors(&cur.ConnectionInfo->DeviceDescriptor,
(PUSB_CONFIGURATION_DESCRIPTOR)(cur.ConfigDesc+1)))
cur.StringDescs = GetAllStringDescriptors(h,idx,
&cur.ConnectionInfo->DeviceDescriptor,
(PUSB_CONFIGURATION_DESCRIPTOR)(cur.ConfigDesc+1));
if (cur.ConfigDesc) {
const BYTE*desc=(const BYTE*)(cur.ConfigDesc+1);
const BYTE*end =desc+((const USB_CONFIGURATION_DESCRIPTOR*)desc)->wTotalLength;
BYTE iface;
const USB_HID_DESCRIPTOR* hd=LocateHidDesc(desc,end,&iface);
if (hd) {
int i;
cur.HidDescs=ALLOC(32*sizeof(BYTE*)); // reserve space for some interfaces
if (cur.HidDescs) {
for (i=0;i<31;i++) {
cur.HidDescs[i]=GetHidDesc(h,idx,iface,hd); // get descriptors
hd=LocateHidDesc((const BYTE*)hd,end,&iface); // locate next
if (!hd) break;
}
cur.HidDescs=REALLOC(cur.HidDescs,(i+2)*sizeof(BYTE*)); // reduce allocation
}
}
}
if (cur.ConfigDesc) {
DWORD rlen;
cur.DeviceQualifier = GetDescriptor(h,idx,MAKEWORD(0,6),0,256,&rlen);
if (cur.DeviceQualifier) cur.DeviceQualifier->SetupPacket.wLength=(USHORT)rlen;
cur.OtherSpeed = GetConfigDescriptor(h,idx,MAKEWORD(CONFIGNUMBER,7));
}
// If the device connected to the port is an external hub, get the
// name of the external hub and recursively enumerate it.
//
if (cur.ConnectionInfo->DeviceIsHub) {
PTSTR extHubName = GetExternalHubName(h,idx);
if (extHubName) {
EnumerateHub(hTreeParent, //hPortItem,
extHubName,
cur.ConnectionInfo,
cur.ConfigDesc,
cur.StringDescs,
deviceDesc);
// On to the next port
//
continue;
}
}
// Allocate some space for a USBDEVICEINFO structure to hold the
// hub info, hub name, and connection info pointers. GPTR zero
// initializes the structure for us.
//
info = (PUSBDEVICEINFO) ALLOC(sizeof(USBDEVICEINFO));
if (!info) {
OOPS();
if (cur.ConfigDesc) FREE(cur.ConfigDesc);
FREE(cur.ConnectionInfo);
break;
}
*info=cur;
wsprintfA(leafName, "[Port%d] ", idx);
lstrcatA(leafName, ConnectionStatuses[cur.ConnectionInfo->ConnectionStatus]);
if (deviceDesc) lstrcatA(leafName, " : %s");
hItem = AddLeaf(hTreeParent,(LPARAM)info,iImage,leafName,deviceDesc);
}
}
//*****************************************************************************
//
// EnumerateHub()
//
// hTreeParent - Handle of the TreeView item under which this hub should be
// added.
//
// HubName - Name of this hub. This pointer is kept so the caller can neither
// free nor reuse this memory.
//
// ConnectionInfo - NULL if this is a root hub, else this is the connection
// info for an external hub. This pointer is kept so the caller can neither
// free nor reuse this memory.
//
// ConfigDesc - NULL if this is a root hub, else this is the Configuration
// Descriptor for an external hub. This pointer is kept so the caller can
// neither free nor reuse this memory.
//
//*****************************************************************************
static void EnumerateHub (HTREEITEM hTreeParent, PTSTR HubName,
PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo,
PUSB_DESCRIPTOR_REQUEST ConfigDesc,
PSTRING_DESCRIPTOR_NODE StringDescs,
PTSTR DeviceDesc) {
HANDLE hHubDevice;
HTREEITEM hItem;
LPTSTR deviceName;
BOOL success;
ULONG nBytes;
PUSBDEVICEINFO info;
char leafName[512]; // XXXXX how big does this have to be?
// Initialize locals to not allocated state so the error cleanup routine
// only tries to cleanup things that were successfully allocated.
//
info = NULL;
hHubDevice = INVALID_HANDLE_VALUE;
// Allocate some space for a USBDEVICEINFO structure to hold the
// hub info, hub name, and connection info pointers. GPTR zero
// initializes the structure for us.
//
info = (PUSBDEVICEINFO) ALLOC(sizeof(USBDEVICEINFO));
if (!info) {
OOPS();
goto EnumerateHubError;
}
// Keep copies of the Hub Name, Connection Info, and Configuration
// Descriptor pointers
//
info->HubName = HubName;
info->ConnectionInfo = ConnectionInfo;
info->ConfigDesc = ConfigDesc;
info->StringDescs = StringDescs;
// Allocate some space for a USB_NODE_INFORMATION structure for this Hub,
//
info->HubInfo = (PUSB_NODE_INFORMATION)ALLOC(sizeof(USB_NODE_INFORMATION));
if (!info->HubInfo) {
OOPS();
goto EnumerateHubError;
}
// Allocate a temp buffer for the full hub device name.
//
deviceName = ALLOC((lstrlen(HubName)+5)*sizeof(TCHAR));
if (!deviceName) {
OOPS();
goto EnumerateHubError;
}
// Create the full hub device name
//
lstrcpy(deviceName, T("\\\\.\\"));
lstrcpy(deviceName + 4, info->HubName);
// Try to hub the open device
//
hHubDevice = CreateFile(deviceName,GENERIC_WRITE,FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,0,NULL);
// Done with temp buffer for full hub device name
//
FREE(deviceName);
if (hHubDevice == INVALID_HANDLE_VALUE) {
OOPS();
goto EnumerateHubError;
}
//
// Now query USBHUB for the USB_NODE_INFORMATION structure for this hub.
// This will tell us the number of downstream ports to enumerate, among
// other things.
//
success = DeviceIoControl(hHubDevice,IOCTL_USB_GET_NODE_INFORMATION,
info->HubInfo,sizeof(USB_NODE_INFORMATION),
info->HubInfo,sizeof(USB_NODE_INFORMATION),
&nBytes,NULL);
if (!success) {
OOPS();
goto EnumerateHubError;
}
// Build the leaf name from the port number and the device description
//
if (ConnectionInfo) {
wsprintfA(leafName, "[Port%d] ", ConnectionInfo->ConnectionIndex);
lstrcatA(leafName, ConnectionStatuses[ConnectionInfo->ConnectionStatus]);
lstrcatA(leafName, " : ");
}else leafName[0] = 0;
lstrcatA(leafName,"%s");
// Now add an item to the TreeView with the PUSBDEVICEINFO pointer info
// as the LPARAM reference value containing everything we know about the
// hub.
//
hItem = AddLeaf(hTreeParent,(LPARAM)info,4,leafName,DeviceDesc?DeviceDesc:info->HubName);
if (!hItem) {
OOPS();
goto EnumerateHubError;
}
// Now recursively enumrate the ports of this hub.
//
EnumerateHubPorts(
hItem,
hHubDevice,
info->HubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts);
CloseHandle(hHubDevice);
return;
EnumerateHubError:
//
// Clean up any stuff that got allocated
//
if (hHubDevice != INVALID_HANDLE_VALUE) {
CloseHandle(hHubDevice);
}
if (info) {
if (info->HubName) FREE(info->HubName);
if (info->HubInfo) FREE(info->HubInfo);
FREE(info);
}
if (ConnectionInfo) FREE(ConnectionInfo);
if (ConfigDesc) FREE(ConfigDesc);
if (StringDescs) {
PSTRING_DESCRIPTOR_NODE Next;
do{
Next = StringDescs->Next;
FREE(StringDescs);
StringDescs = Next;
}while (StringDescs);
}
}
//*****************************************************************************
// EnumerateHostController()
// hTreeInsert - Handle of the TreeView item under which host controllers
// should be added (normally MyComputer)
//*****************************************************************************
static void EnumerateHostController (HTREEITEM hTreeInsert, HANDLE hHCDev, PTSTR Name) {
PTSTR driverKeyName;
PTSTR deviceDesc;
PTSTR rootHubName;
driverKeyName = GetHCDDriverKeyName(hHCDev);
if (driverKeyName) {
deviceDesc = DriverNameToDeviceDesc(driverKeyName);
if (deviceDesc) Name = deviceDesc;
FREE(driverKeyName);
}
hTreeInsert = AddLeaf(hTreeInsert,0,1,"%s",Name);
if (hTreeInsert) {
rootHubName = GetRootHubName(hHCDev);
if (rootHubName) EnumerateHub(hTreeInsert,rootHubName,
NULL, // ConnectionInfo
NULL, // ConfigDesc
NULL, // StringDescs
T("RootHub")); // DeviceDesc
}
}
//*****************************************************************************
// EnumerateHostControllers()
// hTreeParent - Handle of the TreeView item under which host controllers
// should be added.
//*****************************************************************************
extern void EnumerateHostControllers (HTREEITEM hTreeParent,ULONG *DevicesConnected) {
HANDLE hHCDev;
PTSTR Name;
TCHAR HCName[16];
int HCNum;
HDEVINFO deviceInfo;
SP_DEVICE_INTERFACE_DATA deviceInfoData;
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetailData;
ULONG index;
ULONG requiredLength;
TotalDevicesConnected = 0;
TotalHubs = 0;
if (Config.flags&CFLAG_ENUM_NAME) {
// Iterate over some Host Controller names and try to open them.
//
for (HCNum = 0; HCNum < NUM_HCS_TO_CHECK; HCNum++) {
wsprintf(HCName,T("\\\\.\\HCD%d"), HCNum);
hHCDev = CreateFile(HCName,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
// If the handle is valid, then we've successfully opened a Host
// Controller. Display some info about the Host Controller itself,
// then enumerate the Root Hub attached to the Host Controller.
if (hHCDev != INVALID_HANDLE_VALUE) {
EnumerateHostController(hTreeParent,hHCDev,HCName+4);
CloseHandle(hHCDev);
}
}
}
if (Config.flags&CFLAG_ENUM_GUID) {
// Now iterate over host controllers using the new GUID based interface
deviceInfo=SetupDiGetClassDevs((LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER,NULL,NULL,DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
deviceInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
for (index=0; SetupDiEnumDeviceInterfaces(deviceInfo,0,
(LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER,index,&deviceInfoData);index++) {
SetupDiGetDeviceInterfaceDetail(deviceInfo,&deviceInfoData,NULL,0,&requiredLength,NULL);
deviceDetailData=ALLOC(requiredLength);
deviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SetupDiGetDeviceInterfaceDetail(deviceInfo,&deviceInfoData,deviceDetailData,requiredLength,&requiredLength,NULL);
hHCDev = CreateFile(deviceDetailData->DevicePath,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
// If the handle is valid, then we've successfully opened a Host
// Controller. Display some info about the Host Controller itself,
// then enumerate the Root Hub attached to the Host Controller.
if (hHCDev != INVALID_HANDLE_VALUE) {
Name = deviceDetailData->DevicePath;
EnumerateHostController(hTreeParent,hHCDev,Name);
CloseHandle(hHCDev);
}
FREE(deviceDetailData);
}
SetupDiDestroyDeviceInfoList(deviceInfo);
}
*DevicesConnected = TotalDevicesConnected;
}
//*****************************************************************************
// Frees the lParam pointer and the pointers inside
//*****************************************************************************
extern void CleanupItem(HWND Wnd, HTREEITEM hTreeItem) {
TV_ITEM tvi;
PUSBDEVICEINFO info;
tvi.mask = TVIF_HANDLE|TVIF_PARAM;
tvi.hItem = hTreeItem;
TreeView_GetItem(Wnd,&tvi);
info = (PUSBDEVICEINFO)tvi.lParam;
if (info) {
if (info->HubInfo) info->HubInfo=FREE(info->HubInfo);
if (info->HubName) info->HubName=FREE(info->HubName);
if (info->ConfigDesc) info->ConfigDesc=FREE(info->ConfigDesc);
if (info->StringDescs) {
PSTRING_DESCRIPTOR_NODE Next;
do {
Next = info->StringDescs->Next;
FREE(info->StringDescs);
info->StringDescs = Next;
} while (info->StringDescs);
}
if (info->ConnectionInfo) info->ConnectionInfo=FREE(info->ConnectionInfo);
if (info->HidDescs) info->HidDescs=FREE(info->HidDescs);
info=FREE(info);
}
}
Detected encoding: ASCII (7 bit) | 2
|