Source file: /~heha/hs/usbview.zip/src/display.c

/*++

Copyright (c) 1997-1998 Microsoft Corporation

Module Name:

DISPLAY.C

Abstract:

This source file contains the routines which update the edit control
to display information about the selected USB 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 <shlwapi.h>

#include "usbview.h"
#include "usb100.h"
#include "usb200.h"

//*****************************************************************************
// D E F I N E S
//*****************************************************************************

#define BUFFERALLOCINCREMENT        8192
#define BUFFERMINFREESPACE          1024

//*****************************************************************************
// G L O B A L S    P R I V A T E    T O    T H I S    F I L E
//*****************************************************************************

// Workspace for text info which is used to update the edit control
TCHAR *TextBuffer;
int TextBufferLen;
int TextBufferPos;

//*****************************************************************************
// L O C A L    F U N C T I O N S
//*****************************************************************************


//*****************************************************************************
//
// CreateTextBuffer()
//
//*****************************************************************************

bool CreateTextBuffer() {
    // Allocate the buffer
    //
 TextBuffer = ALLOC(BUFFERALLOCINCREMENT*sizeof(TCHAR));

 if (!TextBuffer) {
  OOPS();
  return false;
 }

 TextBufferLen = BUFFERALLOCINCREMENT;

    // Reset the buffer position and terminate the buffer
    //
 *TextBuffer = 0;
 TextBufferPos = 0;

 return true;
}


//*****************************************************************************
//
// DestroyTextBuffer()
//
//*****************************************************************************

void DestroyTextBuffer() {
 if (TextBuffer) TextBuffer=FREE(TextBuffer);
}


//*****************************************************************************
//
// ResetTextBuffer()
//
//*****************************************************************************

bool ResetTextBuffer () {
    // Fail if the text buffer has not been allocated
    //
 if (!TextBuffer) {
  OOPS();
  return false;
 }

    // Reset the buffer position and terminate the buffer
    //
 *TextBuffer = 0;
 TextBufferPos = 0;

 return true;
}

//*****************************************************************************
// Append text to buffer, the template ist 7-bit ONLY!
//*****************************************************************************

void _cdecl AppendTextBuffer(LPCSTR lpFormat,...) {
 va_list arglist;

 va_start(arglist, lpFormat);

    // Make sure we have a healthy amount of space free in the buffer,
    // reallocating the buffer if necessary.
    //
 if (TextBufferLen - TextBufferPos < BUFFERMINFREESPACE) {
  TCHAR *TextBufferTmp;

  TextBufferTmp = REALLOC(TextBuffer,(TextBufferLen+BUFFERALLOCINCREMENT)*sizeof(TCHAR));

  if (TextBufferTmp) {
   TextBuffer = TextBufferTmp;
   TextBufferLen += BUFFERALLOCINCREMENT;
  }else{
            // If GlobalReAlloc fails, the original memory is not freed,
            // and the original handle and pointer are still valid.
            //
   OOPS();
   return;
  }
 }
// Add the text to the end of the buffer, updating the buffer position.
#ifdef UNICODE
 {
  WCHAR t[256];
  MultiByteToWideChar(CP_ACP,0,lpFormat,-1,t,elemof(t));
  TextBufferPos += wvsprintf(TextBuffer+TextBufferPos,t,arglist);
 }
#else
 TextBufferPos += wvsprintf(TextBuffer+TextBufferPos,lpFormat,arglist);
#endif
}

// Replace non-printable characters by C typical escape sequences
// Needed for some Chinese vendor and product strings
int EscapeStr(LPCTSTR s, int slen, LPTSTR buf, int buflen) {
 int i=0,r=0;
 if (slen<0) slen=lstrlen(s);
 for (;i<slen;i++) {
  TCHAR c=*s++;			// fetch character
  if (c<0x20) {			// non-displayable?
   LPCTSTR t=T("\\%c");		// set a default template
   switch (c) {
    case '\0': c='0'; break;	// change characters
    case '\a': c='a'; break;	// 7
    case '\b': c='b'; break;	// 8
    case '\t': c='t'; break;	// 9
    case '\r': c='r'; break;	// 10
    case '\v': c='v'; break;	// 11
    case '\f': c='f'; break;	// 12
    case '\n': c='n'; break;	// 13
    case 27:   c='e'; break;	// Escape (gcc, not ANSI C)
    default: t=T("\\x%02X");	// template for hex output
   }
   r+=wnsprintf(buf+r,buflen-r,t,c);	// append (either version of template)
  }else if (buflen-r>1) buf[r++]=c;	// append printable character
 }
 buf[r]=0;
 return r;
}

// Append a Unicode string (escaping it) using template <t>
void AppendTextBufferStringW(LPCSTR t, LPCWSTR s, int slen) {
 TCHAR s1[256];
#ifdef UNICODE
 if (slen<0) slen=lstrlenW(s);
 EscapeStr(s,slen,s1,elemof(s1));
#else
 char s2[256];
 if (slen<0) slen=lstrlenW(s);
 slen=WideCharToMultiByte(CP_ACP,0,s,slen,s2,sizeof(s2),NULL,NULL);
 EscapeStr(s2,slen,s1,elemof(s1));
#endif
 AppendTextBuffer(t,s1);
}

extern void AppendHexDump(const BYTE*data, int len) {
 char line[80],*p=line;
 int w=0;
 while (len) {
  p+=wsprintfA(p," %02X",*data++);
  len--;
  w++;
  if (w==16 || !len) {
   AppendTextBuffer(ASTR"\r\n",line);
   p=line;
   w=0;
  }
 }
}

//*****************************************************************************
// DisplayUnknownDescriptor()
//*****************************************************************************
static void DisplayUnknownDescriptor (const USB_COMMON_DESCRIPTOR*CommonDesc, int len) {
 AppendTextBuffer("\r\nUnknown Descriptor:");
 if (!len || CommonDesc->bLength!=len) AppendTextBuffer(" Length = %d",len);
 if (len>=1) AppendTextBuffer("\r\n bLength:              0x%02X", CommonDesc->bLength);
 if (len>=2) AppendTextBuffer("\r\n bDescriptorType:      0x%02X", CommonDesc->bDescriptorType);
 AppendTextBuffer("\r\n");
 if (len>2) {
  if (len>CommonDesc->bLength-2) len=CommonDesc->bLength-2;
  AppendHexDump((const BYTE*)(CommonDesc+1),len);
 }
}

#if 1
//*****************************************************************************
// DisplayStringDescriptor()
//*****************************************************************************
static void DisplayStringDescriptor(UCHAR Index, PSTRING_DESCRIPTOR_NODE StringDescs) {
 for (;StringDescs; StringDescs=StringDescs->Next) {
  if (StringDescs->DescriptorIndex == Index) {
   const char*p;
   AppendTextBuffer("0x%04X: ",StringDescs->LanguageID);
   AppendTextBufferStringW("\"%s\"",
     StringDescs->StringDescriptor->bString,
     (StringDescs->StringDescriptor->bLength-2)>>1);
   p = Lookup('L',StringDescs->LanguageID&0x3FF,-1,-1);
   if (p) {
    const char*q = Lookup('L',StringDescs->LanguageID&0x3FF,StringDescs->LanguageID>>10,-1);
    AppendTextBuffer(q?" (" ASTR "," ASTR ")":" (" ASTR ")",p,q);
   }
   AppendTextBuffer("\r\n");
  }
 }
}

#else

VOID
DisplayStringDescriptor (
    UCHAR                       Index,
    PSTRING_DESCRIPTOR_NODE     StringDescs
)
{
    UCHAR i;

    while (StringDescs)
    {
        if (StringDescs->DescriptorIndex == Index)
        {
            AppendTextBuffer("String Descriptor:\r\n");

            AppendTextBuffer("LanguageID:         0x%04X\r\n",
                             StringDescs->LanguageID);

            AppendTextBuffer("bLength:              0x%02X\r\n",
                             StringDescs->StringDescriptor->bLength);

            for (i = 0; i < StringDescs->StringDescriptor->bLength-2; i++)
            {
                AppendTextBuffer("%02X ",
                                 ((PUCHAR)StringDescs->StringDescriptor->bString)[i]);

                if (i % 16 == 15)
                {
                    AppendTextBuffer("\r\n");
                }
            }

            if (i % 16 != 0)
            {
                AppendTextBuffer("\r\n");
            }
        }

        StringDescs = StringDescs->Next;
    }

}

#endif

//*****************************************************************************
//
// DisplayConfigurationDescriptor()
//
//*****************************************************************************

static void DisplayConfigurationDescriptor (
    PUSB_CONFIGURATION_DESCRIPTOR   ConfigDesc,
    PSTRING_DESCRIPTOR_NODE         StringDescs) {

 AppendTextBuffer("\r\n"ASTR" Descriptor:\r\n", ConfigDesc->bDescriptorType==7?"Other Speed":"Configuration");

 AppendTextBuffer(" wTotalLength:      0x%04X (%d)\r\n", ConfigDesc->wTotalLength,ConfigDesc->wTotalLength);

 AppendTextBuffer(" bNumInterfaces:      0x%02X\r\n", ConfigDesc->bNumInterfaces);

 AppendTextBuffer(" bConfigurationValue: 0x%02X\r\n", ConfigDesc->bConfigurationValue);

 AppendTextBuffer(" iConfiguration:      0x%02X\r\n", ConfigDesc->iConfiguration);

 if (ConfigDesc->iConfiguration)
   DisplayStringDescriptor(ConfigDesc->iConfiguration, StringDescs);

 AppendTextBuffer(" bmAttributes:        0x%02X (",ConfigDesc->bmAttributes);
 if (ConfigDesc->bmAttributes & 0x80) AppendTextBuffer("Bus Powered ");
 if (ConfigDesc->bmAttributes & 0x40) AppendTextBuffer("Self Powered ");
 if (ConfigDesc->bmAttributes & 0x20) AppendTextBuffer("Remote Wakeup");
 AppendTextBuffer(")\r\n");

 AppendTextBuffer(" MaxPower:            0x%02X (%d mA)\r\n",
   ConfigDesc->MaxPower,
   ConfigDesc->MaxPower*2);
}

//*****************************************************************************
//
// DisplayInterfaceDescriptor()
//
//*****************************************************************************

static void DisplayInterfaceDescriptor(
    PUSB_INTERFACE_DESCRIPTOR   InterfaceDesc,
    PSTRING_DESCRIPTOR_NODE     StringDescs) {
 const char *p;

 AppendTextBuffer("\r\nInterface Descriptor:\r\n");

 AppendTextBuffer(" bInterfaceNumber:    0x%02X\r\n", InterfaceDesc->bInterfaceNumber);

 AppendTextBuffer(" bAlternateSetting:   0x%02X\r\n", InterfaceDesc->bAlternateSetting);

 AppendTextBuffer(" bNumEndpoints:       0x%02X\r\n", InterfaceDesc->bNumEndpoints);

 AppendTextBuffer(" bInterfaceClass:     0x%02X", InterfaceDesc->bInterfaceClass);
 p = Lookup('C',InterfaceDesc->bInterfaceClass,-1,-1);
 if (!p) switch (InterfaceDesc->bInterfaceClass) {
  case USB_DEVICE_CLASS_AUDIO:		p = "Audio";	break;
  case USB_DEVICE_CLASS_HUMAN_INTERFACE:p = "HID";	break;
  case USB_DEVICE_CLASS_HUB:		p = "Hub";	break;
 }
 if (p) AppendTextBuffer(" ("ASTR")",p);
 AppendTextBuffer("\r\n");

 AppendTextBuffer(" bInterfaceSubClass:  0x%02X", InterfaceDesc->bInterfaceSubClass);
 p = Lookup('C',InterfaceDesc->bInterfaceClass,
		InterfaceDesc->bInterfaceSubClass,-1);
 if (!p) switch (InterfaceDesc->bInterfaceClass) {
  case USB_DEVICE_CLASS_AUDIO: switch (InterfaceDesc->bInterfaceSubClass) {
   case USB_AUDIO_SUBCLASS_AUDIOCONTROL:	p = "Audio Control";	break;
   case USB_AUDIO_SUBCLASS_AUDIOSTREAMING:	p = "Audio Streaming";	break;
   case USB_AUDIO_SUBCLASS_MIDISTREAMING:	p = "MIDI Streaming";	break;
  }break;
 }
 if (p) AppendTextBuffer(" ("ASTR")",p);
 AppendTextBuffer("\r\n");

 AppendTextBuffer(" bInterfaceProtocol:  0x%02X", InterfaceDesc->bInterfaceProtocol);
 p = Lookup('C',InterfaceDesc->bInterfaceClass,
		InterfaceDesc->bInterfaceSubClass,
		InterfaceDesc->bInterfaceProtocol);
 if (p) AppendTextBuffer(" ("ASTR")",p);
 AppendTextBuffer("\r\n");

 AppendTextBuffer(" iInterface:          0x%02X\r\n", InterfaceDesc->iInterface);
 if (InterfaceDesc->iInterface)
   DisplayStringDescriptor(InterfaceDesc->iInterface,StringDescs);

 if (InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR2)) {
  PUSB_INTERFACE_DESCRIPTOR2 interfaceDesc2 = (PUSB_INTERFACE_DESCRIPTOR2)InterfaceDesc;
  AppendTextBuffer(" wNumClasses:       0x%04X\r\n", interfaceDesc2->wNumClasses);
 }
}

//*****************************************************************************
//
// DisplayEndpointDescriptor()
//
//*****************************************************************************

static void DisplayEndpointDescriptor (PUSB_ENDPOINT_DESCRIPTOR EndpointDesc) {
 static const PCTSTR sAttr[4]={
   T("Control"),T("Isochronous"),T("Bulk"),T("Interrupt")};

 AppendTextBuffer("\r\nEndpoint Descriptor:\r\n");

 AppendTextBuffer(" bEndpointAddress:    0x%02X  (EP%d%s)\r\n",
   EndpointDesc->bEndpointAddress,
   EndpointDesc->bEndpointAddress&0x0F,
   EndpointDesc->bEndpointAddress&0x80?T("IN"):T("OUT"));

 AppendTextBuffer(" Transfer Type:%11s\r\n",
   sAttr[EndpointDesc->bmAttributes&0x03]);

 AppendTextBuffer(" wMaxPacketSize:    0x%04X (%d)\r\n",
   EndpointDesc->wMaxPacketSize,
   EndpointDesc->wMaxPacketSize);

 if (EndpointDesc->bLength==sizeof(USB_ENDPOINT_DESCRIPTOR)) {
  AppendTextBuffer(" bInterval:           0x%02X\r\n",
    EndpointDesc->bInterval);
 }else{
  PUSB_ENDPOINT_DESCRIPTOR2 endpointDesc2;

  endpointDesc2 = (PUSB_ENDPOINT_DESCRIPTOR2)EndpointDesc;

  AppendTextBuffer(" wInterval:         0x%04X\r\n",
    endpointDesc2->wInterval);

  AppendTextBuffer(" bSyncAddress:        0x%02X\r\n",
    endpointDesc2->bSyncAddress);
 }
}

static void DisplayQualifier(const USB_DEVICE_QUALIFIER_DESCRIPTOR*qual) {
 AppendTextBuffer("\r\nDevice Qualifier:\r\n");
 if (qual->bDescriptorType!=USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE) OOPS();
 if (qual->bLength<sizeof(*qual)) OOPS();
 AppendTextBuffer(" USB Spec. Version:   0x%04X\r\n",qual->bcdUSB);
 AppendTextBuffer(" bDeviceClass:          0x%02X\r\n",qual->bDeviceClass);
 AppendTextBuffer(" bDeviceSubclass:       0x%02X\r\n",qual->bDeviceSubClass);
 AppendTextBuffer(" bDeviceProtocol:       0x%02X\r\n",qual->bDeviceProtocol);
 AppendTextBuffer(" bMaxPacketSize0:       0x%02X\r\n",qual->bMaxPacketSize0);
 AppendTextBuffer(" bNumConfigurations:    0x%02X\r\n",qual->bNumConfigurations);
 if (qual->bReserved) {
  AppendTextBuffer(" bReserved:             0x%02X\r\n",qual->bReserved);
 }
}

static void DisplayPowerDescriptor(const BYTE*p0) {
 char *t;
 const BYTE *p=p0+2, *e=p0+p0[0];
 int i;
 switch (p0[1]) {
  case 7: t="Configuration"; break;
  case 8: t="Interface"; break;
 }
 AppendTextBuffer("\r\n"ASTR" Power Descriptor:",t);
 switch (p0[1]) {
  case 7: {
   AppendTextBuffer("\r\n SelfPowerConsumedD0:  0x%02X, 0x%02X, 0x%02X",p[0],p[1],p[2]);
   AppendTextBuffer("\r\n bPowerSummaryId:      0x%02X",p[3]);
   p+=4;
  }break;
  case 8: {
   AppendTextBuffer("\r\n bmCapabilitiesFlags:  0x%02X",*p++);
  }break;
 }
 for (i=1; i<=3; i++) {
  if (p>=e) goto exi;
  AppendTextBuffer("\r\n bBusPowerSavingD%i:    0x%02X",i,*p++);
  AppendTextBuffer("\r\n bSelfPowerSavingD%i:   0x%02X",i,*p++);
 }
 for (i=1; i<=3; i++) {
  if (p>=e) break;
  AppendTextBuffer("\r\n TransitionTimeFromD%i: 0x%02X",i,*((USHORT*)p)++);
 }
exi:
 AppendTextBuffer("\r\n");
}

//*****************************************************************************
// ConfigDesc - The Configuration Descriptor, and associated Interface and
// EndpointDescriptors
//*****************************************************************************
static void DisplayConfigDesc (
    PUSB_CONFIGURATION_DESCRIPTOR   ConfigDesc,
    PSTRING_DESCRIPTOR_NODE         StringDescs,
    const BYTE**HidDescs
)
{
 const BYTE*	descEnd;	// pointer to end of descriptor
 BYTE		iface=0;	// current interface number
 PUSB_COMMON_DESCRIPTOR  commonDesc;
 UCHAR		bInterfaceClass;
 UCHAR		bInterfaceSubClass;
 BOOL           displayUnknown;

 bInterfaceClass = 0;

 descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength;

 commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc;

 while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd &&
           (PUCHAR)commonDesc + commonDesc->bLength <= descEnd)
 {
  displayUnknown = FALSE;

  switch (commonDesc->bDescriptorType) {
   case USB_CONFIGURATION_DESCRIPTOR_TYPE:
   case 7:	// OTHER_SPEED_CONFIGURATION
   if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR))
   {
    OOPS();
    displayUnknown = TRUE;
    break;
   }
   DisplayConfigurationDescriptor((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc,
                                               StringDescs);
   break;

   case USB_INTERFACE_DESCRIPTOR_TYPE:
   if ((commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR)) &&
                    (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2)))
   {
    OOPS();
    displayUnknown = TRUE;
    break;
   }
   bInterfaceClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceClass;
   bInterfaceSubClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceSubClass;

   DisplayInterfaceDescriptor((PUSB_INTERFACE_DESCRIPTOR)commonDesc,
                                           StringDescs);
   break;

   case USB_ENDPOINT_DESCRIPTOR_TYPE:
   if ((commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR)) &&
                    (commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR2)))
   {
    OOPS();
    displayUnknown = TRUE;
    break;
   }
   DisplayEndpointDescriptor((PUSB_ENDPOINT_DESCRIPTOR)commonDesc);
   break;

   case USB_HID_DESCRIPTOR_TYPE:
   if (commonDesc->bLength < sizeof(USB_HID_DESCRIPTOR))
   {
    OOPS();
    displayUnknown = TRUE;
    break;
   }
   {int i;
    if (HidDescs) for (i=0;HidDescs[i];i++) {
     if (HidDescs[i][0]==iface) {
      DisplayHidDescriptor((PUSB_HID_DESCRIPTOR)commonDesc,HidDescs[i]+1);
      goto shown;
     }
    }
    DisplayHidDescriptor((PUSB_HID_DESCRIPTOR)commonDesc,NULL);
shown:;
   }break;
   
   case USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE: {
    if (commonDesc->bLength!=sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE)) {
     OOPS();
     displayUnknown = TRUE;
     break;
    }
    DisplayQualifier((const USB_DEVICE_QUALIFIER_DESCRIPTOR*)commonDesc);
   }break;

   //case USB_CONFIG_POWER_DESCRIPTOR_TYPE:	// 7 - wrong!
   case USB_INTERFACE_POWER_DESCRIPTOR_TYPE:	// 8
     DisplayPowerDescriptor((const BYTE*)commonDesc); break;

   default: switch (bInterfaceClass) {
    case USB_DEVICE_CLASS_AUDIO:
    displayUnknown = !DisplayAudioDescriptor(
                                              (PUSB_AUDIO_COMMON_DESCRIPTOR)commonDesc,
                                              bInterfaceSubClass);
    break;

    default: displayUnknown = TRUE;
   }
  }

  if (displayUnknown) DisplayUnknownDescriptor(commonDesc,(int)(descEnd-(const BYTE*)commonDesc));

  (PUCHAR)commonDesc += commonDesc->bLength;
 }
}


//*****************************************************************************
//
// DisplayHubInfo()
//
// HubInfo - Info about the hub.
//
//*****************************************************************************

static void DisplayHubInfo(PUSB_HUB_INFORMATION HubInfo) {
 USHORT wHubChar;
 const char *p;

 p = HubInfo->HubIsBusPowered ? "Bus" : "Self";
 AppendTextBuffer("Hub Power:               "ASTR" Power\r\n",p);

 AppendTextBuffer("Number of Ports:         %d\r\n", HubInfo->HubDescriptor.bNumberOfPorts);

 wHubChar = HubInfo->HubDescriptor.wHubCharacteristics;
 switch (wHubChar & 3) {
  case 0: p="Ganged"; break;
  case 1: p="Individual"; break;
  default:p="None";
 }
 AppendTextBuffer("Power switching:         "ASTR"\r\n",p);

 p = wHubChar & 4 ? "Yes" : "No";
 AppendTextBuffer("Compound device:         "ASTR"\r\n",p);

 switch (wHubChar & 0x0018) {
  case 0x0000: p="Over-current Protection: Global"; break;
  case 0x0008: p="Over-current Protection: Individual"; break;
  default:     p="No Over-current Protection (Bus Power Only)"; break;
 }
 AppendTextBuffer(ASTR"\r\n\r\n",p);
}

//*****************************************************************************
//
// GetVendorString()
//
// idVendor - USB Vendor ID
//
// Return Value - Vendor name string associated with idVendor, or NULL if
// no vendor name string is found which is associated with idVendor.
//*****************************************************************************

static const char* GetVendorString (USHORT vid) {
 const char *p=Lookup(0,vid,-1,-1);
 USHORT i;
 if (p) return p;
// The following cast requires unaligned WORD data access (true for x86 and x64)
 for(p=USBVendorIDs;i=*((const USHORT*)p)++; p+=lstrlenA(p)+1) {
  if (i==vid) return p;
 }
 return NULL;
}

//*****************************************************************************
//
// DisplayPipeInfo()
//
// NumPipes - Number of pipe for we info should be displayed.
//
// PipeInfo - Info about the pipes.
//
//*****************************************************************************

static void DisplayPipeInfo (
    ULONG           NumPipes,
    USB_PIPE_INFO  *PipeInfo) {
 ULONG i;

 for (i=0; i<NumPipes; i++) {
  DisplayEndpointDescriptor(&PipeInfo[i].EndpointDescriptor);
 }
}


//*****************************************************************************
//
// DisplayConnectionInfo()
//
// ConnectInfo - Info about the connection.
//
//*****************************************************************************

static void DisplayConnectionInfo (
    PUSB_NODE_CONNECTION_INFORMATION_EX    ConnectInfo,
    PSTRING_DESCRIPTOR_NODE             StringDescs
) {
    if (ConnectInfo->ConnectionStatus == NoDeviceConnected)
    {
        AppendTextBuffer("ConnectionStatus: NoDeviceConnected\r\n");
    }
 else{
  const char *p;

        AppendTextBuffer("Device Descriptor:\r\n");

        AppendTextBuffer(" bcdUSB:            0x%04X\r\n",
                         ConnectInfo->DeviceDescriptor.bcdUSB);

  AppendTextBuffer(" bDeviceClass:        0x%02X", ConnectInfo->DeviceDescriptor.bDeviceClass);
  p = Lookup('C', ConnectInfo->DeviceDescriptor.bDeviceClass,-1,-1);
  if (p) AppendTextBuffer(" ("ASTR")",p);
  AppendTextBuffer("\r\n");

  AppendTextBuffer(" bDeviceSubClass:     0x%02X", ConnectInfo->DeviceDescriptor.bDeviceSubClass);
  p = Lookup('C',ConnectInfo->DeviceDescriptor.bDeviceClass,
		 ConnectInfo->DeviceDescriptor.bDeviceSubClass,-1);
  if (p) AppendTextBuffer(" ("ASTR")",p);
  AppendTextBuffer("\r\n");

  AppendTextBuffer(" bDeviceProtocol:     0x%02X", ConnectInfo->DeviceDescriptor.bDeviceProtocol);
  p = Lookup('C',ConnectInfo->DeviceDescriptor.bDeviceClass,
		 ConnectInfo->DeviceDescriptor.bDeviceSubClass,
		 ConnectInfo->DeviceDescriptor.bDeviceProtocol);
  if (p) AppendTextBuffer(" ("ASTR")",p);
  AppendTextBuffer("\r\n");

  AppendTextBuffer(" bMaxPacketSize0:     0x%02X (%d)\r\n",
	ConnectInfo->DeviceDescriptor.bMaxPacketSize0,
	ConnectInfo->DeviceDescriptor.bMaxPacketSize0);

  AppendTextBuffer(" idVendor:          0x%04X", ConnectInfo->DeviceDescriptor.idVendor);
  p = GetVendorString(ConnectInfo->DeviceDescriptor.idVendor);
  if (p) AppendTextBuffer(" ("ASTR")",p);
  AppendTextBuffer("\r\n");

  AppendTextBuffer(" idProduct:         0x%04X", ConnectInfo->DeviceDescriptor.idProduct);
  p = Lookup(0, ConnectInfo->DeviceDescriptor.idVendor,
		ConnectInfo->DeviceDescriptor.idProduct,-1);
  if (p) AppendTextBuffer(" ("ASTR")",p);
  AppendTextBuffer("\r\n");

  AppendTextBuffer(" bcdDevice:         0x%04X", ConnectInfo->DeviceDescriptor.bcdDevice);
  p = Lookup(0, ConnectInfo->DeviceDescriptor.idVendor,
		ConnectInfo->DeviceDescriptor.idProduct,
		ConnectInfo->DeviceDescriptor.bcdDevice);
  if (p) AppendTextBuffer(" ("ASTR")",p);
  AppendTextBuffer("\r\n");

  AppendTextBuffer(" iManufacturer:       0x%02X\r\n", ConnectInfo->DeviceDescriptor.iManufacturer);
  if (ConnectInfo->DeviceDescriptor.iManufacturer)
    DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iManufacturer,StringDescs);

  AppendTextBuffer(" iProduct:            0x%02X\r\n", ConnectInfo->DeviceDescriptor.iProduct);
  if (ConnectInfo->DeviceDescriptor.iProduct)
    DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iProduct,StringDescs);

  AppendTextBuffer(" iSerialNumber:       0x%02X\r\n", ConnectInfo->DeviceDescriptor.iSerialNumber);
  if (ConnectInfo->DeviceDescriptor.iSerialNumber)
    DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iSerialNumber,StringDescs);

  AppendTextBuffer(" bNumConfigurations:  0x%02X\r\n", ConnectInfo->DeviceDescriptor.bNumConfigurations);
  AppendTextBuffer("\r\nConnectionStatus: "ASTR"\r\n", ConnectionStatuses[ConnectInfo->ConnectionStatus]);
  AppendTextBuffer("Current Config Value: 0x%02X\r\n", ConnectInfo->CurrentConfigurationValue);

  switch (ConnectInfo->Speed) {
   case UsbLowSpeed: p="Low"; break;
   case UsbFullSpeed: p="Full"; break;
   case UsbHighSpeed: p="High"; break;
   case 3: p="Super"; break;
   default: p="unknown";
  }
  AppendTextBuffer("Device Bus Speed:     "ASTR"\r\n",p);
  AppendTextBuffer("Device Address:       0x%02X\r\n", ConnectInfo->DeviceAddress);
  AppendTextBuffer("Open Pipes:             %2d\r\n",  ConnectInfo->NumberOfOpenPipes);
  if (ConnectInfo->NumberOfOpenPipes)
    DisplayPipeInfo(ConnectInfo->NumberOfOpenPipes,ConnectInfo->PipeList);
 }
}

//*****************************************************************************
//
// UpdateEditControl()
//
// hTreeItem - Handle of selected TreeView item for which information should
// be displayed in the edit control.
//
//*****************************************************************************

extern void UpdateEditControl(HWND hEditWnd, HWND hTreeWnd, HTREEITEM hTreeItem) {
 TV_ITEM         tvi;
 PUSBDEVICEINFO  info;

    // Start with an empty text buffer.
    //
 if (!ResetTextBuffer()) return;

    // Get the name of the TreeView item, along with the a pointer to the
    // info we stored about the item in the item's lParam.
    //

 tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM;
 tvi.hItem = hTreeItem;
 tvi.pszText = TextBuffer;
 tvi.cchTextMax = TextBufferLen-2;  // leave space for "\r\n"

 TreeView_GetItem(hTreeWnd,&tvi);

 info = (PUSBDEVICEINFO)tvi.lParam;

    //
    // If we didn't store any info for the item, just display the item's
    // name, else display the info we stored for the item.
    //
 if (info) {
  if (!info->ConnectionInfo) {
            // Must be Root HUB, external devices have Connection Info
            //
   AppendTextBuffer("Root Hub: %s\r\n",info->HubName);

   DisplayHubInfo(&info->HubInfo->u.HubInformation);
  }else{
   if (info->HubInfo) {
                // Must be external HUB external
                //
    AppendTextBuffer("External Hub: %s\r\n",info->HubName);
    DisplayHubInfo(&info->HubInfo->u.HubInformation);
   }else{
                // Must be external non-HUB device.  Nothing special to
                // display here that isn't displayed in connection info
                // below.
   }

            // Display info common to any external device
            //
   DisplayConnectionInfo(info->ConnectionInfo,
                                  info->StringDescs);

   AppendTextBuffer("\r\n****************************\r\n");

   if (info->ConfigDesc) {
    DisplayConfigDesc((PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1),
                                  info->StringDescs,info->HidDescs);
   }

   if (info->DeviceQualifier) {
    const USB_COMMON_DESCRIPTOR *p=(void*)(info->DeviceQualifier+1);
    if (p->bLength!=sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR)		// 10
    || p->bDescriptorType!=USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE) {	// 6
     OOPS();
     AppendTextBuffer("\r\n"
       "Device Firmware Laxity: \"Get Device Qualifier\" not STALLed!");
     DisplayUnknownDescriptor(p,info->DeviceQualifier->SetupPacket.wLength);
    }else DisplayQualifier((const USB_DEVICE_QUALIFIER_DESCRIPTOR*)p);
   }

   if (info->OtherSpeed) {
    AppendTextBuffer("\r\n\n"
      "****************************\r\n"
      "** Other Speed Descriptor **\r\n"
      "****************************\r\n");
    DisplayConfigDesc((PUSB_CONFIGURATION_DESCRIPTOR)(info->OtherSpeed + 1),NULL,NULL);
   }
  }
 }

    // All done formatting text buffer with info, now update the edit
    // control with the contents of the text buffer
    //
 SetWindowText(hEditWnd, TextBuffer);
}



#if 0
//*****************************************************************************
//
// DisplayPowerDescriptor()
//
//*****************************************************************************

PCHAR PowerUnits[] =
{
    "0.001 mW",
    "0.01 mW",
    "0.1 mW",
    "1 mW",
    "10 mW",
    "100 mW",
    "1 W"
};

VOID
DisplayPowerDescriptor (
    PUSB_POWER_DESCRIPTOR       PowerDesc
)
{
    UCHAR i;

    AppendTextBuffer("\r\nPower Descriptor:\r\n");

    AppendTextBuffer("bCapabilitiesFlags:   0x%02X (",
                     PowerDesc->bCapabilitiesFlags);

    if (PowerDesc->bCapabilitiesFlags & USB_SUPPORT_D2_WAKEUP)
    {
        AppendTextBuffer("WakeD2 ");
    }
    if (PowerDesc->bCapabilitiesFlags & USB_SUPPORT_D1_WAKEUP)
    {
        AppendTextBuffer("WakeD1 ");
    }
    if (PowerDesc->bCapabilitiesFlags & USB_SUPPORT_D3_COMMAND)
    {
        AppendTextBuffer("D3 ");
    }
    if (PowerDesc->bCapabilitiesFlags & USB_SUPPORT_D2_COMMAND)
    {
        AppendTextBuffer("D2 ");
    }
    if (PowerDesc->bCapabilitiesFlags & USB_SUPPORT_D1_COMMAND)
    {
        AppendTextBuffer("D1 ");
    }
    if (PowerDesc->bCapabilitiesFlags & USB_SUPPORT_D0_COMMAND)
    {
        AppendTextBuffer("D0 ");
    }
    AppendTextBuffer(")\r\n");

    AppendTextBuffer("EventNotification:  0x%04X\r\n",
                     PowerDesc->EventNotification);

    AppendTextBuffer("D1LatencyTime:      0x%04X\r\n",
                     PowerDesc->D1LatencyTime);

    AppendTextBuffer("D2LatencyTime:      0x%04X\r\n",
                     PowerDesc->D2LatencyTime);

    AppendTextBuffer("D3LatencyTime:      0x%04X\r\n",
                     PowerDesc->D3LatencyTime);

    AppendTextBuffer("PowerUnit:            0x%02X (" ASTR ")\r\n",
                     PowerDesc->PowerUnit,
                     PowerDesc->PowerUnit < sizeof(PowerUnits)/sizeof(PowerUnits[0])
                     ? PowerUnits[PowerDesc->PowerUnit]
                     : "?");

    AppendTextBuffer("D0PowerConsumption: 0x%04X (%5d)\r\n",
                     PowerDesc->D0PowerConsumption,
                     PowerDesc->D0PowerConsumption);

    AppendTextBuffer("D1PowerConsumption: 0x%04X (%5d)\r\n",
                     PowerDesc->D1PowerConsumption,
                     PowerDesc->D1PowerConsumption);

    AppendTextBuffer("D2PowerConsumption: 0x%04X (%5d)\r\n",
                     PowerDesc->D2PowerConsumption,
                     PowerDesc->D2PowerConsumption);

}
#endif

Detected encoding: ASCII (7 bit)2