diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /usb/usbview/display.c | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'usb/usbview/display.c')
| -rw-r--r-- | usb/usbview/display.c | 4814 |
1 files changed, 4814 insertions, 0 deletions
diff --git a/usb/usbview/display.c b/usb/usbview/display.c new file mode 100644 index 00000000..67c215e4 --- /dev/null +++ b/usb/usbview/display.c @@ -0,0 +1,4814 @@ +/*++ + +Copyright (c) 1997-2011 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 +03-28-03 : extensive changes to support new USBVCD +03-28-08 : extensive changes to support new USB Video Class 1.1 + +--*/ + +/***************************************************************************** +I N C L U D E S +*****************************************************************************/ + +#include "uvcview.h" +#include "h264.h" +#include <usb200.h> + +#include "vndrlist.h" +#include "langidlist.h" + +/***************************************************************************** +D E F I N E S +*****************************************************************************/ + +#define BUFFERALLOCINCREMENT 0x10000 +#define BUFFERMINFREESPACE 0x1000 + +/***************************************************************************** +T Y P E D E F S +*****************************************************************************/ + +// +// Hardcoded information about specific EHCI controllers +// +typedef struct _EHCI_CONTROLLER_DATA +{ + USHORT VendorID; + USHORT DeviceID; + UCHAR DebugPortNumber; +} EHCI_CONTROLLER_DATA, *PEHCI_CONTROLLER_DATA; + + +/***************************************************************************** +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 +// +CHAR *TextBuffer = NULL; +UINT TextBufferLen = 0; +UINT TextBufferPos = 0; + +STRINGLIST slPowerState [] = +{ + {WdmUsbPowerNotMapped, "S? (unmapped) ", ""}, + + {WdmUsbPowerSystemUnspecified, "S? (unspecified)", ""}, + {WdmUsbPowerSystemWorking, "S0 (working) ", ""}, + {WdmUsbPowerSystemSleeping1, "S1 (sleep) ", ""}, + {WdmUsbPowerSystemSleeping2, "S2 (sleep) ", ""}, + {WdmUsbPowerSystemSleeping3, "S3 (sleep) ", ""}, + {WdmUsbPowerSystemHibernate, "S4 (Hibernate) ", ""}, + {WdmUsbPowerSystemShutdown, "S5 (shutdown) ", ""}, + + {WdmUsbPowerDeviceUnspecified, "D? (unspecified)", ""}, + {WdmUsbPowerDeviceD0, "D0 ", ""}, + {WdmUsbPowerDeviceD1, "D1 ", ""}, + {WdmUsbPowerDeviceD2, "D2 ", ""}, + {WdmUsbPowerDeviceD3, "D3 ", ""}, +}; + +STRINGLIST slControllerFlavor[] = +{ + { USB_HcGeneric, "USB_HcGeneric", "" }, + { OHCI_Generic, "OHCI_Generic", "" }, + { OHCI_Hydra, "OHCI_Hydra", "" }, + { OHCI_NEC, "OHCI_NEC", "" }, + { UHCI_Generic, "UHCI_Generic", "" }, + { UHCI_Piix4, "UHCI_Piix4", "" }, + { UHCI_Piix3, "UHCI_Piix3", "" }, + { UHCI_Ich2, "UHCI_Ich2", "" }, + { UHCI_Reserved204, "UHCI_Reserved204", "" }, + { UHCI_Ich1, "UHCI_Ich1", "" }, + { UHCI_Ich3m, "UHCI_Ich3m", "" }, + { UHCI_Ich4, "UHCI_Ich4", "" }, + { UHCI_Ich5, "UHCI_Ich5", "" }, + { UHCI_Ich6, "UHCI_Ich6", "" }, + { UHCI_Intel, "UHCI_Intel", "" }, + { UHCI_VIA, "UHCI_VIA", "" }, + { UHCI_VIA_x01, "UHCI_VIA_x01", "" }, + { UHCI_VIA_x02, "UHCI_VIA_x02", "" }, + { UHCI_VIA_x03, "UHCI_VIA_x03", "" }, + { UHCI_VIA_x04, "UHCI_VIA_x04", "" }, + { UHCI_VIA_x0E_FIFO, "UHCI_VIA_x0E_FIFO", "" }, + { EHCI_Generic, "EHCI_Generic", "" }, + { EHCI_NEC, "EHCI_NEC", "" }, + { EHCI_Lucent, "EHCI_Lucent", "" }, + { EHCI_NVIDIA_Tegra2, "EHCI_NVIDIA_Tegra2", "" }, + { EHCI_NVIDIA_Tegra3, "EHCI_NVIDIA_Tegra3", "" }, + { EHCI_Intel_Medfield, "EHCI_Intel_Medfield", "" } +}; + +// +// For supporting pre Win8 versions of Windows, a hardcoded list is maintained for determining +// debug port numbers. As usbport.inf is augmented with new host controllers, this list should +// be updated. +// +// The following entries do not have a debug port: +// PCI\VEN_8086&DEV_0806 - "Intel(R) SM35 Express Chipset USB2 Enhanced Host Controller MPH - 0806" +// PCI\VEN_8086&DEV_0811 - "Intel(R) SM35 Express Chipset USB2 Enhanced Host Controller SPM - 0811" +// + +EHCI_CONTROLLER_DATA EhciControllerData[] = +{ + {0x8086, 0x24CD, 1}, // ICH4 - Intel(R) 82801DB/DBM USB 2.0 Enhanced Host Controller - 24CD + {0x8086, 0x24DD, 1}, // ICH5 - Intel(R) 82801EB USB2 Enhanced Host Controller - 24DD + {0x8086, 0x25AD, 1}, // ICH5 - Intel(R) 6300ESB USB2 Enhanced Host Controller - 25AD + {0x8086, 0x265C, 1}, // ICH6 - Intel(R) 82801FB/FBM USB2 Enhanced Host Controller - 265C + {0x8086, 0x268C, 1}, // Intel(R) 631xESB/6321ESB/3100 Chipset USB2 Enhanced Host Controller - 268C + {0x8086, 0x27CC, 1}, // ICH7 - Intel(R) 82801G (ICH7 Family) USB2 Enhanced Host Controller - 27CC + {0x8086, 0x2836, 1}, // ICH8 - Intel(R) ICH8 Family USB2 Enhanced Host Controller - 2836 + {0x8086, 0x283A, 1}, // ICH8 - Intel(R) ICH8 Family USB2 Enhanced Host Controller - 283A + {0x8086, 0x293A, 1}, // ICH9 - Intel(R) ICH9 Family USB2 Enhanced Host Controller - 293A + {0x8086, 0x293C, 1}, // ICH9 - Intel(R) ICH9 Family USB2 Enhanced Host Controller - 293C + {0x8086, 0x3A3A, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A3A + {0x8086, 0x3A3C, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A3C + {0x8086, 0x3A6A, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A6A + {0x8086, 0x3A6C, 1}, // ICH10 - Intel(R) ICH10 Family USB Enhanced Host Controller - 3A6C + {0x8086, 0x3B34, 2}, // 5 series - Intel(R) 5 Series/3400 Series Chipset Family USB Enhanced Host Controller - 3B34 + {0x8086, 0x3B36, 2}, // 5 series - Intel(R) 5 Series/3400 Series Chipset Family USB Universal Host Controller - 3B36 + {0x8086, 0x1C26, 2}, // 6 series - Intel(R) 6 Series/C200 Series Chipset Family USB Enhanced Host Controller - 1C26 + {0x8086, 0x1C2D, 2}, // 6 series - Intel(R) 6 Series/C200 Series Chipset Family USB Enhanced Host Controller - 1C2D + {0x8086, 0x1D26, 2}, // Intel(R) C600/X79 series chipset USB2 Enhanced Host Controller #1 - 1D26 + {0x8086, 0x1D2D, 2}, // Intel(R) C600/X79 series chipset USB2 Enhanced Host Controller #2 - 1D2D + {0x8086, 0x268C, 1}, // Intel(R) 631xESB/6321ESB/3100 Chipset USB2 Enhanced Host Controller - 268C + {0x10DE, 0x00D8, 1}, + {0,0,0}, +}; + + +/***************************************************************************** +L O C A L F U N C T I O N P R O T O T Y P E S +*****************************************************************************/ + +VOID +DisplayPortConnectorProperties ( + _In_ PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 + ); + +void +DisplayDevicePowerState ( + _In_ PDEVICE_INFO_NODE DeviceInfoNode + ); + +VOID +DisplayHubInfo ( + PUSB_HUB_INFORMATION HubInfo, + BOOL DisplayDescriptor + ); + +VOID +DisplayHubInfoEx ( + PUSB_HUB_INFORMATION_EX HubInfoEx + ); + +VOID +DisplayHubCapabilityEx ( + PUSB_HUB_CAPABILITIES_EX HubCapabilityEx + ); + +VOID +DisplayPowerState( + PUSB_POWER_INFO pUPI + ); + +VOID +DisplayConnectionInfo ( + _In_ PUSB_NODE_CONNECTION_INFORMATION_EX ConnectInfo, + _In_ PUSBDEVICEINFO info, + _In_ PSTRING_DESCRIPTOR_NODE StringDescs, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 + ); + +VOID +DisplayPipeInfo ( + ULONG NumPipes, + USB_PIPE_INFO *PipeInfo + ); + +VOID +DisplayConfigDesc ( + PUSBDEVICEINFO info, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + PSTRING_DESCRIPTOR_NODE StringDescs + ); + +VOID +DisplayBosDescriptor ( + PUSB_BOS_DESCRIPTOR BosDesc + ); + +VOID +DisplayDeviceQualifierDescriptor ( + PUSB_DEVICE_QUALIFIER_DESCRIPTOR DevQualDesc + ); + +VOID +DisplayConfigurationDescriptor ( + PUSBDEVICEINFO info, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + PSTRING_DESCRIPTOR_NODE StringDescs + ); + +VOID +DisplayInterfaceDescriptor ( + PUSB_INTERFACE_DESCRIPTOR InterfaceDesc, + PSTRING_DESCRIPTOR_NODE StringDescs, + DEVICE_POWER_STATE LatestDevicePowerState + ); + +VOID +DisplayEndpointDescriptor ( + _In_ PUSB_ENDPOINT_DESCRIPTOR + EndpointDesc, + _In_opt_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR + EpCompDesc, + _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR + SspIsochCompDesc, + _In_ UCHAR InterfaceClass, + _In_ BOOLEAN EpCompDescAvail + ); + +VOID +DisplaySuperSpeedPlusIsochEndpointCompanionDescriptor( + _In_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochEpCompDesc + ); + +VOID +DisplayEndointCompanionDescriptor ( + _In_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR EpCompDesc, + _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR + SspIsochEpCompDesc, + _In_ UCHAR DescType + ); + + +VOID +DisplayHidDescriptor ( + PUSB_HID_DESCRIPTOR HidDesc + ); + +VOID +DisplayOTGDescriptor ( + PUSB_OTG_DESCRIPTOR OTGDesc + ); + +void +InitializePerDeviceSettings ( + PUSBDEVICEINFO info + ); + +UINT +IsUVCDevice ( + PUSBDEVICEINFO info + ); + +VOID +DisplayIADDescriptor ( + PUSB_IAD_DESCRIPTOR IADDesc, + PSTRING_DESCRIPTOR_NODE StringDescs, + int nInterfaces, + DEVICE_POWER_STATE LatestDevicePowerState + ); + +VOID +DisplayUSEnglishStringDescriptor ( + UCHAR Index, + PSTRING_DESCRIPTOR_NODE USStringDescs, + DEVICE_POWER_STATE LatestDevicePowerState + ); + +VOID +DisplayUnknownDescriptor ( + PUSB_COMMON_DESCRIPTOR CommonDesc + ); + +VOID +DisplayRemainingUnknownDescriptor( + PUCHAR DescriptorData, + ULONG Start, + ULONG Stop + ); + +PCHAR +GetVendorString ( + USHORT idVendor + ); + +PCHAR +GetLangIDString ( + USHORT idLang + ); + +UINT +GetConfigurationSize ( + PUSBDEVICEINFO info + ); + +UINT +GetInterfaceCount ( + PUSBDEVICEINFO info + ); + + +/***************************************************************************** +L O C A L F U N C T I O N S +*****************************************************************************/ + +/***************************************************************************** + +NextDescriptor() + +*****************************************************************************/ +//__forceinline +PUSB_COMMON_DESCRIPTOR +NextDescriptor( + _In_ PUSB_COMMON_DESCRIPTOR Descriptor + ) +{ + if (Descriptor->bLength == 0) + { + return NULL; + } + return (PUSB_COMMON_DESCRIPTOR)((PUCHAR)Descriptor + Descriptor->bLength); +} + +/***************************************************************************** + +GetNextDescriptor() + +*****************************************************************************/ +PUSB_COMMON_DESCRIPTOR +GetNextDescriptor( + _In_reads_bytes_(TotalLength) + PUSB_COMMON_DESCRIPTOR FirstDescriptor, + _In_ + ULONG TotalLength, + _In_ + PUSB_COMMON_DESCRIPTOR StartDescriptor, + _In_ long + DescriptorType + ) +{ + PUSB_COMMON_DESCRIPTOR currentDescriptor = NULL; + PUSB_COMMON_DESCRIPTOR endDescriptor = NULL; + + endDescriptor = (PUSB_COMMON_DESCRIPTOR)((PUCHAR)FirstDescriptor + TotalLength); + + if (StartDescriptor >= endDescriptor || + NextDescriptor(StartDescriptor)>= endDescriptor) + { + return NULL; + } + + if (DescriptorType == -1) // -1 means any type + { + return NextDescriptor(StartDescriptor); + } + + currentDescriptor = StartDescriptor; + + while (((currentDescriptor = NextDescriptor(currentDescriptor)) < endDescriptor) + && currentDescriptor != NULL) + { + if (currentDescriptor->bDescriptorType == (UCHAR)DescriptorType) + { + return currentDescriptor; + } + } + return NULL; +} + + + +/***************************************************************************** + +CreateTextBuffer() + +*****************************************************************************/ + +BOOL +CreateTextBuffer ( + ) +{ + // Allocate the buffer + // + TextBuffer = ALLOC(BUFFERALLOCINCREMENT); + + if (TextBuffer == NULL) + { + OOPS(); + + return FALSE; + } + + TextBufferLen = BUFFERALLOCINCREMENT; + + // Reset the buffer position and terminate the buffer + // + memset(TextBuffer, 0, BUFFERALLOCINCREMENT); + TextBufferPos = 0; + + return TRUE; +} + + +/***************************************************************************** + +DestroyTextBuffer() + +*****************************************************************************/ + +VOID +DestroyTextBuffer ( + ) +{ + if (TextBuffer != NULL) + { + FREE(TextBuffer); + + TextBuffer = NULL; + } +} + + +/***************************************************************************** + +ResetTextBuffer() + +*****************************************************************************/ + +BOOL +ResetTextBuffer ( + ) +{ + // Fail if the text buffer has not been allocated + // + if (TextBuffer == NULL) + { + OOPS(); + + return FALSE; + } + + // Reset the buffer position and terminate the buffer + // + *TextBuffer = 0; + TextBufferPos = 0; + + return TRUE; +} + + +/***************************************************************************** + +GetTextBufferPos() + +*****************************************************************************/ + +UINT +GetTextBufferPos ( + ) +{ + return TextBufferPos; +} + + +/***************************************************************************** + +AppendTextBuffer() + +*****************************************************************************/ + +VOID __cdecl +AppendTextBuffer ( + LPCTSTR lpFormat, + ... + ) +{ + va_list arglist; + HRESULT hr = S_OK; + int nPos = TextBufferPos; + char LocalTextBuffer[512]; + + 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) + { + CHAR *TextBufferTmp; + UINT uNewTextBufferLen = 0; + hr = UIntAdd(TextBufferLen, BUFFERALLOCINCREMENT, &uNewTextBufferLen); + + if (hr != S_OK) + { + // we've exceeded DWORD length of (2^32)-1 for buffer + OOPS(); + + return; + } + + TextBufferTmp = REALLOC(TextBuffer, uNewTextBufferLen); + + if (TextBufferTmp != NULL) + { + TextBuffer = TextBufferTmp; + TextBufferLen += BUFFERALLOCINCREMENT; // update TextBufferLen to reflect the new, bigger size of the text buffer + } + 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 + // + hr = StringCchVPrintf(LocalTextBuffer, sizeof(LocalTextBuffer), lpFormat, arglist); + if (SUCCEEDED(hr)) + { + size_t cbMax = 512; + size_t pcb = 0; + + // Ensure TextBuffer is zero terminated + // The text buffer size is specified by TextBufferLen. + // the text buffer size will be bigger than BUFFERALLOCINCREMENT if the buffer has been reallocated more than + // once (which would happen if it had to be made bigger to hold more text) + hr = StringCbLength((LPCTSTR) TextBuffer, + TextBufferLen, // the maximum number of bytes allowed in TextBuffer. + &pcb); + + if (FAILED(hr)) // buffer is not null-terminated, go ahead and do that + { + TextBuffer[TextBufferLen-1] = 0; + } + hr = StringCbLength((LPCTSTR) LocalTextBuffer, cbMax, &pcb); + if (SUCCEEDED(hr)) + { + StringCbCatN(TextBuffer, TextBufferLen, LocalTextBuffer, pcb); + + // Increment the text position by the number of charcters we just added to it. + TextBufferPos += (UINT) pcb; + } + + // If DebugLog flag set, send output to the debugger + // + if (gLogDebug) + { + OutputDebugString(TextBuffer + nPos); // print the string just added to the text buffer + } + } +} + +//***************************************************************************** +// +// GetTextBuffer +// +// Returns the display text buffer +// +//***************************************************************************** +PCHAR GetTextBuffer(void) +{ + return (TextBuffer); +} + + +//***************************************************************************** +// +// GetEhciDebugPort +// +// Returns debug port value if present for EHCI controller. 0 if its not present +// +//***************************************************************************** +ULONG GetEhciDebugPort(ULONG vendorId, ULONG deviceId) +{ + int i = 0; + ULONG debugPort = 0; + + for (i = 0; EhciControllerData[i].VendorID != 0; i++) + { + if (vendorId == EhciControllerData[i].VendorID && + deviceId == EhciControllerData[i].DeviceID) + { + debugPort = EhciControllerData[i].DebugPortNumber; + break; + } + } + + return debugPort; +} + +//***************************************************************************** +// +// UpdateTreeItemDeviceInfo +// +// hTreeItem - Handle of selected TreeView item for which information should +// be added to the TextBuffer global +// +// The functions returns error status if AppendTextBuffer() used in Display*() functions +// fails. The display text would be missing or truncated in such cases. +//***************************************************************************** +HRESULT +UpdateTreeItemDeviceInfo( + HWND hTreeWnd, + HTREEITEM hTreeItem + ) +{ + TV_ITEM tvi; + PVOID info; + ULONG i; + HRESULT hr = S_OK; + PCHAR tviName = NULL; + + SetLastError(0); + +#ifndef H264_SUPPORT + UNREFERENCED_PARAMETER(bShowVersion) +#endif + +#ifdef H264_SUPPORT + ResetErrorCounts(); +#endif + + tviName = ALLOC(256); + + if(NULL == tviName) + { + OOPS(); + hr = E_OUTOFMEMORY; + return hr; + } + + // + // 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 = (LPSTR) tviName; + tvi.cchTextMax = 256; + + TreeView_GetItem(hTreeWnd, + &tvi); + + info = (PVOID)tvi.lParam; + + AppendTextBuffer(tviName); + AppendTextBuffer("\r\n"); + + // + // 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 (NULL != info) + { + PUSB_NODE_INFORMATION HubInfo = NULL; + PCHAR HubName = NULL; + PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo = NULL; + PUSB_DESCRIPTOR_REQUEST ConfigDesc = NULL; + PSTRING_DESCRIPTOR_NODE StringDescs = NULL; + PUSB_HUB_INFORMATION_EX HubInfoEx = NULL; + PUSB_HUB_CAPABILITIES_EX HubCapabilityEx = NULL; + PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps = NULL; + PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 = NULL; + PUSB_DESCRIPTOR_REQUEST BosDesc = NULL; + PDEVICE_INFO_NODE DeviceInfoNode = NULL; + + // The TextBuffer has the TreeView name; add 2 lines for display + AppendTextBuffer("\r\n\r\n"); + + switch (*(PUSBDEVICEINFOTYPE)info) + { + case HostControllerInfo: + { + HTREEITEM rootHubItem = NULL; + BOOL dbgPortFound = FALSE; + + AppendTextBuffer("DriverKey: %s\r\n", + ((PUSBHOSTCONTROLLERINFO)info)->DriverKey); + + AppendTextBuffer("VendorID: %04X\r\n", + ((PUSBHOSTCONTROLLERINFO)info)->VendorID); + + AppendTextBuffer("DeviceID: %04X\r\n", + ((PUSBHOSTCONTROLLERINFO)info)->DeviceID); + + AppendTextBuffer("SubSysID: %08X\r\n", + ((PUSBHOSTCONTROLLERINFO)info)->SubSysID); + + AppendTextBuffer("Revision: %02X\r\n", + ((PUSBHOSTCONTROLLERINFO)info)->Revision); + + // + // Search for the debug port number. If running on Win8 or later, + // the USB_PORT_CONNECTOR_PROPERTIES structure will contain the + // port number. If that fails, the list of known host controllers + // with debug ports will be searched. + // + + AppendTextBuffer("\r\nDebug Port Number: "); + + rootHubItem = TreeView_GetChild(hTreeWnd, hTreeItem); + + if (rootHubItem != NULL) + { + HTREEITEM portItem = NULL; + PVOID portInfo; + + portItem = TreeView_GetChild(hTreeWnd, rootHubItem); + + while (portItem != NULL) + { + tvi.mask = TVIF_PARAM; + tvi.hItem = portItem; + tvi.pszText = NULL; + tvi.cchTextMax = 0; + + TreeView_GetItem(hTreeWnd, &tvi); + + portInfo = (PVOID)tvi.lParam; + + // + // Note that an empty port is a port without a device attached + // is still a DeviceInfo instance. + // + + if ((*(PUSBDEVICEINFOTYPE)portInfo) == DeviceInfo) + { + ConnectionInfo = ((PUSBDEVICEINFO)portInfo)->ConnectionInfo; + PortConnectorProps = ((PUSBDEVICEINFO)portInfo)->PortConnectorProps; + } + else if ((*(PUSBDEVICEINFOTYPE)portInfo) == ExternalHubInfo) + { + ConnectionInfo = ((PUSBEXTERNALHUBINFO)portInfo)->ConnectionInfo; + PortConnectorProps = ((PUSBEXTERNALHUBINFO)portInfo)->PortConnectorProps; + + } + + if (ConnectionInfo != NULL && + PortConnectorProps != NULL && + PortConnectorProps->UsbPortProperties.PortIsDebugCapable) + { + dbgPortFound = TRUE; + AppendTextBuffer("%d\r\n", ((PUSBDEVICEINFO)portInfo)->ConnectionInfo->ConnectionIndex); + break; + } + portItem = TreeView_GetNextSibling(hTreeWnd, portItem); + } + + // + // Resetting ConnectionInfo and PortConnectorProps to NULL so that they won't be erroneously + // be displayed below. + // + + ConnectionInfo = NULL; + PortConnectorProps = NULL; + } + if (dbgPortFound == FALSE) + { + for (i = 0; EhciControllerData[i].VendorID; i++) + { + if (((PUSBHOSTCONTROLLERINFO)info)->VendorID == + EhciControllerData[i].VendorID && + ((PUSBHOSTCONTROLLERINFO)info)->DeviceID == + EhciControllerData[i].DeviceID) + { + dbgPortFound = TRUE; + AppendTextBuffer("%d\r\n", EhciControllerData[i].DebugPortNumber); + break; + } + } + } + if (dbgPortFound == FALSE) + { + AppendTextBuffer("None\r\n"); + } + + // + // Display bus/device/function to help with setting debug + // settings. + // + if (((PUSBHOSTCONTROLLERINFO)info)->BusDeviceFunctionValid) + { + AppendTextBuffer("Bus.Device.Function (in decimal): %d.%d.%d\r\n", + ((PUSBHOSTCONTROLLERINFO)info)->BusNumber, + ((PUSBHOSTCONTROLLERINFO)info)->BusDevice, + ((PUSBHOSTCONTROLLERINFO)info)->BusFunction); + } + + // Display the USB Host Controller Power State Info + { + PUSB_POWER_INFO pUPI = (PUSB_POWER_INFO) &((PUSBHOSTCONTROLLERINFO)info)->USBPowerInfo[0]; + int nIndex = 0; + int nPowerState = WdmUsbPowerSystemWorking; + + AppendTextBuffer("\r\nHost Controller Power State Mappings\r\n"); + AppendTextBuffer("System State\t\tHost Controller\t\tRoot Hub\tUSB wakeup\tPowered\r\n"); + for ( ; nPowerState < WdmUsbPowerSystemShutdown; nIndex++, nPowerState++, pUPI++) + { + DisplayPowerState(pUPI); + } + + AppendTextBuffer("%s\t%s\r\n", + "Last Sleep State", + GetPowerStateString(pUPI->LastSystemSleepState) + ); + } + + break; + } + + case RootHubInfo: + HubInfo = ((PUSBROOTHUBINFO)info)->HubInfo; + HubName = ((PUSBROOTHUBINFO)info)->HubName; + HubCapabilityEx = ((PUSBROOTHUBINFO)info)->HubCapabilityEx; + + AppendTextBuffer("Root Hub: %s\r\n", + HubName); + + break; + + case ExternalHubInfo: + HubInfo = ((PUSBEXTERNALHUBINFO)info)->HubInfo; + HubName = ((PUSBEXTERNALHUBINFO)info)->HubName; + HubInfoEx = ((PUSBEXTERNALHUBINFO)info)->HubInfoEx; + HubCapabilityEx = ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx; + ConnectionInfo = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfo; + ConnectionInfoV2 = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfoV2; + PortConnectorProps = ((PUSBEXTERNALHUBINFO)info)->PortConnectorProps; + ConfigDesc = ((PUSBEXTERNALHUBINFO)info)->ConfigDesc; + StringDescs = ((PUSBEXTERNALHUBINFO)info)->StringDescs; + BosDesc = ((PUSBEXTERNALHUBINFO)info)->BosDesc; + DeviceInfoNode = ((PUSBEXTERNALHUBINFO)info)->DeviceInfoNode; + + AppendTextBuffer("External Hub: %s\r\n", + HubName); + break; + + case DeviceInfo: + ConnectionInfo = ((PUSBDEVICEINFO)info)->ConnectionInfo; + ConnectionInfoV2 = ((PUSBDEVICEINFO)info)->ConnectionInfoV2; + PortConnectorProps = ((PUSBDEVICEINFO)info)->PortConnectorProps; + ConfigDesc = ((PUSBDEVICEINFO)info)->ConfigDesc; + StringDescs = ((PUSBDEVICEINFO)info)->StringDescs; + BosDesc = ((PUSBDEVICEINFO)info)->BosDesc; + DeviceInfoNode = ((PUSBDEVICEINFO)info)->DeviceInfoNode; + break; + } + + if (PortConnectorProps) + { + DisplayPortConnectorProperties(PortConnectorProps, ConnectionInfoV2); + } + + if (DeviceInfoNode) + { + DisplayDevicePowerState(DeviceInfoNode); + } + + if (HubInfo) + { + DisplayHubInfo(&HubInfo->u.HubInformation, + (HubInfoEx == NULL)); + } + + if (HubInfoEx) + { + DisplayHubInfoEx(HubInfoEx); + } + + if(HubCapabilityEx) + { + DisplayHubCapabilityEx(HubCapabilityEx); + } + + if (ConnectionInfo) + { + DisplayConnectionInfo(ConnectionInfo, + (PUSBDEVICEINFO)info, + StringDescs, + ConnectionInfoV2); + } + + if (ConfigDesc) + { + DisplayConfigDesc((PUSBDEVICEINFO)info, + (PUSB_CONFIGURATION_DESCRIPTOR)(ConfigDesc + 1), + StringDescs); + } + + if (BosDesc) + { + DisplayBosDescriptor((PUSB_BOS_DESCRIPTOR)(BosDesc + 1)); + } + } + + if(tviName != NULL) + { + FREE(tviName); + } + + // AppendTextBuffer() which is used in Display*() functions uses GlobalRealloc() which can fail if realloc fails. + // Obtain last error code from GetLastError() and propagate the error to caller. + hr = HRESULT_FROM_WIN32(GetLastError()); + + return hr; +} + +//***************************************************************************** +// +// UpdateEditControl() +// +// hTreeItem - Handle of selected TreeView item for which information should +// be displayed in the edit control. +// +//***************************************************************************** + +VOID +UpdateEditControl ( + HWND hEditWnd, + HWND hTreeWnd, + HTREEITEM hTreeItem +) +{ + HRESULT hr = S_OK; + + // Start with an empty text buffer. + // + if (!ResetTextBuffer()) + { + return; + } + + // Get the item information in global TextBuffer + hr = UpdateTreeItemDeviceInfo(hTreeWnd, hTreeItem); + + if(FAILED(hr)) + { + OOPS(); + } + + // All done formatting text buffer with info, now update the edit + // control with the contents of the text buffer + // + SetWindowText(hEditWnd, TextBuffer); + +} + +/***************************************************************************** + +DisplayPortConnectorProperties() + +PortConnectorProps - Info about the port connector properties. + +*****************************************************************************/ + +void +DisplayPortConnectorProperties ( + _In_ PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 + ) +{ + AppendTextBuffer("Is Port User Connectable: %s\r\n", + PortConnectorProps->UsbPortProperties.PortIsUserConnectable + ? "yes" : "no"); + + AppendTextBuffer("Is Port Debug Capable: %s\r\n", + PortConnectorProps->UsbPortProperties.PortIsDebugCapable + ? "yes" : "no"); + AppendTextBuffer("Companion Port Number: %d\r\n", + PortConnectorProps->CompanionPortNumber); + AppendTextBuffer("Companion Hub Symbolic Link Name: %ws\r\n", + PortConnectorProps->CompanionHubSymbolicLinkName); + if (ConnectionInfoV2 != NULL) + { + AppendTextBuffer("Protocols Supported:\r\n"); + AppendTextBuffer(" USB 1.1: %s\r\n", + ConnectionInfoV2->SupportedUsbProtocols.Usb110 + ? "yes" : "no"); + AppendTextBuffer(" USB 2.0: %s\r\n", + ConnectionInfoV2->SupportedUsbProtocols.Usb200 + ? "yes" : "no"); + AppendTextBuffer(" USB 3.0: %s\r\n", + ConnectionInfoV2->SupportedUsbProtocols.Usb300 + ? "yes" : "no"); + } + + AppendTextBuffer("\r\n"); +} + +/***************************************************************************** + +DisplayDevicePowerState() + +DeviceInfoNode - Structure containing info used to acquire device state + +*****************************************************************************/ + +void +DisplayDevicePowerState ( + _In_ PDEVICE_INFO_NODE DeviceInfoNode + ) +{ + + DEVICE_POWER_STATE powerState; + + powerState = AcquireDevicePowerState(DeviceInfoNode); + + AppendTextBuffer("Device Power State: "); + if (powerState >= PowerDeviceD0 && powerState <= PowerDeviceD3) + { + AppendTextBuffer("PowerDeviceD%d\r\n", powerState-1); + } + else + { + AppendTextBuffer("Invalid Device Power State Value %d\r\n", powerState); + } + + AppendTextBuffer("\r\n"); +} + + +/***************************************************************************** + +DisplayHubDescriptorBase() + +HubDescriptor - hub descriptor, could also be PUSB_30_HUB_DESCRIPTOR which has + these field in common at the beginning of the data structure: + + - UCHAR bLength; + - UCHAR bDescriptorType; + - UCHAR bNumberOfPorts; + - USHORT wHubCharacteristics; + - UCHAR bPowerOnToPowerGood; + - UCHAR bHubControlCurrent; + +*****************************************************************************/ +VOID +DisplayHubDescriptorBase( + PUSB_HUB_DESCRIPTOR HubDescriptor + ) +{ + USHORT wHubChar = 0; + + AppendTextBuffer("Number of Ports: %d\r\n", + HubDescriptor->bNumberOfPorts); + + wHubChar = HubDescriptor->wHubCharacteristics; + + switch (wHubChar & 0x0003) + { + case 0x0000: + AppendTextBuffer("Power switching: Ganged\r\n"); + break; + + case 0x0001: + AppendTextBuffer("Power switching: Individual\r\n"); + break; + + case 0x0002: + case 0x0003: + AppendTextBuffer("Power switching: None\r\n"); + break; + } + + switch (wHubChar & 0x0004) + { + case 0x0000: + AppendTextBuffer("Compound device: No\r\n"); + break; + + case 0x0004: + AppendTextBuffer("Compound device: Yes\r\n"); + break; + } + + switch (wHubChar & 0x0018) + { + case 0x0000: + AppendTextBuffer("Over-current Protection: Global\r\n"); + break; + + case 0x0008: + AppendTextBuffer("Over-current Protection: Individual\r\n"); + break; + + case 0x0010: + case 0x0018: + AppendTextBuffer("No Over-current Protection (Bus Power Only)\r\n"); + break; + } +} + + + +/***************************************************************************** + +DisplayHubInfo() + +HubInfo - Info about the hub. + +*****************************************************************************/ + +VOID +DisplayHubInfo ( + PUSB_HUB_INFORMATION HubInfo, + BOOL DisplayDescriptor + ) +{ + AppendTextBuffer("Hub Power: %s\r\n", + HubInfo->HubIsBusPowered ? + "Bus Power" : "Self Power"); + + if (DisplayDescriptor == TRUE) + { + DisplayHubDescriptorBase(&HubInfo->HubDescriptor); + } +} + +/***************************************************************************** + +DisplayHubInfoEx() + +HubInfo - Extended info about the hub. + +*****************************************************************************/ + + +VOID +DisplayHubInfoEx ( + PUSB_HUB_INFORMATION_EX HubInfoEx + ) +{ + AppendTextBuffer("Hub type: "); + + switch (HubInfoEx->HubType) { + + case UsbRootHub: + AppendTextBuffer("USB Root Hub\r\n"); + break; + + case Usb20Hub: + AppendTextBuffer("USB 2.0 Hub\r\n"); + DisplayHubDescriptorBase((PUSB_HUB_DESCRIPTOR)&HubInfoEx->u.UsbHubDescriptor); + break; + + case Usb30Hub: + AppendTextBuffer("USB 3.0 Hub\r\n"); + + // + // Note that the DisplayHubDescriptorBase will display the fields of either + // the legacy hub descriptor and the USB 3.0 descriptor which have the same + // offset + // + + DisplayHubDescriptorBase((PUSB_HUB_DESCRIPTOR)&HubInfoEx->u.UsbHubDescriptor); + AppendTextBuffer("Packet Header Decode Latency: 0x%x\r\n", HubInfoEx->u.Usb30HubDescriptor.bHubHdrDecLat); + AppendTextBuffer("Delay: 0x%x ns\r\n", HubInfoEx->u.Usb30HubDescriptor.wHubDelay); + + break; + + default: + AppendTextBuffer("ERROR: Unknown hub type %d\r\n", HubInfoEx->HubType); + break; + } + + AppendTextBuffer("\r\n"); +} + + + +/***************************************************************************** + +DisplayHubCapabilityEx() + +HubCapabilityInfo - Hub capability information + +*****************************************************************************/ + +VOID +DisplayHubCapabilityEx ( + PUSB_HUB_CAPABILITIES_EX HubCapabilityEx + ) +{ + if(HubCapabilityEx != NULL) + { + AppendTextBuffer("High speed capable: %s\r\n", + HubCapabilityEx->CapabilityFlags.HubIsHighSpeedCapable + ? "Yes" : "No"); + AppendTextBuffer("High speed: %s\r\n", + HubCapabilityEx->CapabilityFlags.HubIsHighSpeed + ? "Yes" : "No"); + AppendTextBuffer("Multiple transaction translations capable: %s\r\n", + HubCapabilityEx->CapabilityFlags.HubIsMultiTtCapable + ? "Yes" : "No"); + AppendTextBuffer("Performs multiple transaction translations simultaneously: %s\r\n", + HubCapabilityEx->CapabilityFlags.HubIsMultiTt + ? "Yes" : "No"); + AppendTextBuffer("Hub wakes when device is connected: %s\r\n", + HubCapabilityEx->CapabilityFlags.HubIsArmedWakeOnConnect + ? "Yes" : "No"); + AppendTextBuffer("Hub is bus powered: %s\r\n", + HubCapabilityEx->CapabilityFlags.HubIsBusPowered + ? "Yes" : "No"); + AppendTextBuffer("Hub is root: %s\r\n", + HubCapabilityEx->CapabilityFlags.HubIsRoot + ? "Yes" : "No"); + } +} + +/***************************************************************************** + +DisplayConnectionInfo() + +ConnectInfo - Info about the connection. + +PUSB_NODE_CONNECTION_INFORMATION_EX ConnectInfo, +PSTRING_DESCRIPTOR_NODE StringDescs + +DisplayConnectionInfo(info->ConnectionInfo, +info->StringDescs); + +DisplayConnectionInfo ( +PUSB_NODE_CONNECTION_INFORMATION_EX ConnectInfo, +PSTRING_DESCRIPTOR_NODE StringDescs +) + +*****************************************************************************/ + +VOID +DisplayConnectionInfo ( + _In_ PUSB_NODE_CONNECTION_INFORMATION_EX ConnectInfo, + _In_ PUSBDEVICEINFO info, + _In_ PSTRING_DESCRIPTOR_NODE StringDescs, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 +) +{ + + //@@DisplayConnectionInfo - Device Information + PCHAR VendorString = NULL; + UINT tog = 1; + UINT uIADcount = 0; + + // No device connected + if (ConnectInfo->ConnectionStatus == NoDeviceConnected) + { + AppendTextBuffer("ConnectionStatus: NoDeviceConnected\r\n"); + return; + } + + // This is the entry point to the device display functions. + // First, save this device's PUSBDEVICEINFO address + // In a future version of this test, we will keep track of the the + // descriptor that we're parsing (# of bytes from beginning of info->configuration descriptor) + // Then we can linked descriptors by reading forward through the remaining descriptors + // while still keeping our place in this main DisplayConnectionInfo() and called + // functions. + // + // We also initialize some global flags in uvcview.h that are used to + // verify items in MJPEG, Uncompressed and Vendor Frame descriptors + // + InitializePerDeviceSettings(info); + + if(gDoAnnotation) + { + + AppendTextBuffer(" ---===>Device Information<===---\r\n"); + + if (ConnectInfo->DeviceDescriptor.iProduct) + { + DisplayUSEnglishStringDescriptor(ConnectInfo->DeviceDescriptor.iProduct, + StringDescs, + info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); + } + + AppendTextBuffer("\r\nConnectionStatus: %s\r\n", + ConnectionStatuses[ConnectInfo->ConnectionStatus]); + + AppendTextBuffer("Current Config Value: 0x%02X", + ConnectInfo->CurrentConfigurationValue); + } + + switch (ConnectInfo->Speed){ + case UsbLowSpeed: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Device Bus Speed: Low\r\n"); + } + else + { + AppendTextBuffer("\r\n"); + } + gDeviceSpeed = UsbLowSpeed; + break; + + case UsbFullSpeed: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Device Bus Speed: Full"); + if (ConnectionInfoV2 != NULL) + { + if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedPlusCapableOrHigher) + { + AppendTextBuffer(" (is SuperSpeedPlus or higher capable)\r\n"); + } + else if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedCapableOrHigher) + { + AppendTextBuffer(" (is SuperSpeed or higher capable)\r\n"); + } + else + { + AppendTextBuffer(" (is not SuperSpeed or higher capable)\r\n"); + } + } + else + { + AppendTextBuffer("\r\n"); + } + } + else + { + AppendTextBuffer("\r\n"); + } + gDeviceSpeed = UsbFullSpeed; + break; + case UsbHighSpeed: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Device Bus Speed: High"); + if (ConnectionInfoV2 != NULL) + { + if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedPlusCapableOrHigher) + { + AppendTextBuffer(" (is SuperSpeedPlus or higher capable)\r\n"); + } + else if (ConnectionInfoV2->Flags.DeviceIsSuperSpeedCapableOrHigher) + { + AppendTextBuffer(" (is SuperSpeed or higher capable)\r\n"); + } + else + { + AppendTextBuffer(" (is not SuperSpeed or higher capable)\r\n"); + } + } + else + { + AppendTextBuffer("\r\n"); + } + } + else + { + AppendTextBuffer("\r\n"); + } + gDeviceSpeed = UsbHighSpeed; + break; + + case UsbSuperSpeed: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Device Bus Speed: Super%s\r\n", + ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher + ? "SpeedPlus" + : "Speed"); + } + else + { + AppendTextBuffer("\r\n"); + } + gDeviceSpeed = UsbSuperSpeed; + break; + + default: + if(gDoAnnotation){AppendTextBuffer(" -> Device Bus Speed: Unknown\r\n");} + else {AppendTextBuffer("\r\n");} + } + + if(gDoAnnotation){ + AppendTextBuffer("Device Address: 0x%02X\r\n", + ConnectInfo->DeviceAddress); + + AppendTextBuffer("Open Pipes: %2d\r\n", + ConnectInfo->NumberOfOpenPipes); + } + + // No open pipes means the USB stack has not loaded the device + if (ConnectInfo->NumberOfOpenPipes == 0) + { + AppendTextBuffer("*!*ERROR: No open pipes!\r\n"); + } + + AppendTextBuffer("\r\n ===>Device Descriptor<===\r\n"); + //@@DisplayConnectionInfo - Device Descriptor + + if (ConnectInfo->DeviceDescriptor.bLength != 18) + { + //@@TestCase A1.1 + //@@ERROR + //@@Descriptor Field - bLength + //@@The declared length in the device descriptor is not equal to the + //@@ required length in the USB Device Specification + AppendTextBuffer("*!*ERROR: bLength of %d incorrect, should be %d\r\n", + ConnectInfo->DeviceDescriptor.bLength, + 18); + OOPS(); + } + + AppendTextBuffer("bLength: 0x%02X\r\n", + ConnectInfo->DeviceDescriptor.bLength); + + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + ConnectInfo->DeviceDescriptor.bDescriptorType); + + //@@TestCase A1.2 + //@@Not implemented - Priority 1 + //@@Descriptor Field - bcdUSB + //@@Need to check that any UVC device is set to 0x0200 or later. + AppendTextBuffer("bcdUSB: 0x%04X\r\n", + ConnectInfo->DeviceDescriptor.bcdUSB); + + AppendTextBuffer("bDeviceClass: 0x%02X", + ConnectInfo->DeviceDescriptor.bDeviceClass); + + // Quit on these device failures + if ((ConnectInfo->ConnectionStatus == DeviceFailedEnumeration) || + (ConnectInfo->ConnectionStatus == DeviceGeneralFailure)) + { + AppendTextBuffer("\r\n*!*ERROR: Device enumeration failure\r\n"); + return; + } + + // Is this an IAD device? + uIADcount = IsIADDevice((PUSBDEVICEINFO) info); + + if (uIADcount) + { + // this device configuration has 1 or more IAD descriptors + if (ConnectInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE) + { + tog = 0; + if (gDoAnnotation) + { + AppendTextBuffer(" -> This is a Multi-interface Function Code Device\r\n"); + } + else + { + AppendTextBuffer("\r\n"); + } + } else { + AppendTextBuffer("\r\n*!*ERROR: device class should be Multi-interface Function 0x%02X\r\n"\ + " When IAD descriptor is used\r\n", + USB_MISCELLANEOUS_DEVICE); + } + // Is this a UVC device? + g_chUVCversion = IsUVCDevice((PUSBDEVICEINFO) info); + } + else + { + // this is not an IAD device + switch (ConnectInfo->DeviceDescriptor.bDeviceClass) + { + case USB_INTERFACE_CLASS_DEVICE: + if(gDoAnnotation) + {AppendTextBuffer(" -> This is an Interface Class Defined Device\r\n");} + else {AppendTextBuffer("\r\n");} + break; + + case USB_COMMUNICATION_DEVICE: + tog = 0; + if(gDoAnnotation) + {AppendTextBuffer(" -> This is a Communication Device\r\n");} + else {AppendTextBuffer("\r\n");} + break; + + case USB_HUB_DEVICE: + tog = 0; + if(gDoAnnotation) + {AppendTextBuffer(" -> This is a HUB Device\r\n");} + else {AppendTextBuffer("\r\n");} + break; + + case USB_DIAGNOSTIC_DEVICE: + tog = 0; + if(gDoAnnotation) + {AppendTextBuffer(" -> This is a Diagnostic Device\r\n");} + else {AppendTextBuffer("\r\n");} + break; + + case USB_WIRELESS_CONTROLLER_DEVICE: + tog = 0; + if(gDoAnnotation) + {AppendTextBuffer(" -> This is a Wireless Controller(Bluetooth) Device\r\n");} + else {AppendTextBuffer("\r\n");} + break; + + case USB_VENDOR_SPECIFIC_DEVICE: + tog = 0; + if(gDoAnnotation) + {AppendTextBuffer(" -> This is a Vendor Specific Device\r\n");} + else {AppendTextBuffer("\r\n");} + break; + + case USB_MISCELLANEOUS_DEVICE: + tog = 0; + //@@TestCase A1.3 + //@@ERROR + //@@Descriptor Field - bDeviceClass + //@@Multi-interface Function code used for non-IAD device + AppendTextBuffer("\r\n*!*ERROR: Multi-interface Function code %d used for "\ + "device with no IAD descriptors\r\n", + ConnectInfo->DeviceDescriptor.bDeviceClass); + break; + + default: + //@@TestCase A1.4 + //@@ERROR + //@@Descriptor Field - bDeviceClass + //@@An unknown device class has been defined + AppendTextBuffer("\r\n*!*ERROR: unknown bDeviceClass %d\r\n", + ConnectInfo->DeviceDescriptor.bDeviceClass); + OOPS(); + break; + } + } + + AppendTextBuffer("bDeviceSubClass: 0x%02X", + ConnectInfo->DeviceDescriptor.bDeviceSubClass); + + // check the subclass + if (uIADcount) + { + // this device configuration has 1 or more IAD descriptors + if (ConnectInfo->DeviceDescriptor.bDeviceSubClass == USB_COMMON_SUB_CLASS) + { + if (gDoAnnotation) + { + AppendTextBuffer(" -> This is the Common Class Sub Class\r\n"); + } else + { + AppendTextBuffer("\r\n"); + } + } + else + { + //@@TestCase A1.5 + //@@ERROR + //@@Descriptor Field - bDeviceSubClass + //@@An invalid device sub class used for Multi-interface Function (IAD) device + AppendTextBuffer("\r\n*!*ERROR: device SubClass should be USB Common Sub Class %d\r\n"\ + " When IAD descriptor is used\r\n", + USB_COMMON_SUB_CLASS); + OOPS(); + } + } + else + { + // Not an IAD device, so all subclass values are invalid + if(ConnectInfo->DeviceDescriptor.bDeviceSubClass > 0x00 && + ConnectInfo->DeviceDescriptor.bDeviceSubClass < 0xFF) + { + //@@TestCase A1.6 + //@@ERROR + //@@Descriptor Field - bDeviceSubClass + //@@An invalid device sub class has been defined + AppendTextBuffer("\r\n*!*ERROR: bDeviceSubClass of %d is invalid\r\n", + ConnectInfo->DeviceDescriptor.bDeviceSubClass); + OOPS(); + } else + { + AppendTextBuffer("\r\n"); + } + } + + AppendTextBuffer("bDeviceProtocol: 0x%02X", + ConnectInfo->DeviceDescriptor.bDeviceProtocol); + + // check the protocol + if (uIADcount) + { + // this device configuration has 1 or more IAD descriptors + if (ConnectInfo->DeviceDescriptor.bDeviceProtocol == USB_IAD_PROTOCOL) + { + if (gDoAnnotation) + { + AppendTextBuffer(" -> This is the Interface Association Descriptor protocol\r\n"); + } + else + { + AppendTextBuffer("\r\n"); + } + } + else + { + //@@TestCase A1.7 + //@@ERROR + //@@Descriptor Field - bDeviceSubClass + //@@An invalid device sub class used for Multi-interface Function (IAD) device + AppendTextBuffer("\r\n*!*ERROR: device Protocol should be USB IAD Protocol %d\r\n"\ + " When IAD descriptor is used\r\n", + USB_IAD_PROTOCOL); + OOPS(); + } + } + else + { + // Not an IAD device, so all subclass values are invalid + if(ConnectInfo->DeviceDescriptor.bDeviceProtocol > 0x00 && + ConnectInfo->DeviceDescriptor.bDeviceProtocol < 0xFF && tog==1) + { + //@@TestCase A1.8 + //@@ERROR + //@@Descriptor Field - bDeviceProtocol + //@@An invalid device protocol has been defined + AppendTextBuffer("\r\n*!*ERROR: bDeviceProtocol of %d is invalid\r\n", + ConnectInfo->DeviceDescriptor.bDeviceProtocol); + OOPS(); + } + else + { + AppendTextBuffer("\r\n"); + } + } + + AppendTextBuffer("bMaxPacketSize0: 0x%02X", + ConnectInfo->DeviceDescriptor.bMaxPacketSize0); + + if(gDoAnnotation) + { + AppendTextBuffer(" = (%d) Bytes\r\n", + ConnectInfo->DeviceDescriptor.bMaxPacketSize0); + } + else + { + AppendTextBuffer("\r\n"); + } + + switch (gDeviceSpeed){ + case UsbLowSpeed: + if(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 != 8) + { + //@@TestCase A1.9 + //@@ERROR + //@@Descriptor Field - bMaxPacketSize0 + //@@An invalid bMaxPacketSize0 has been defined for a low speed device + AppendTextBuffer("*!*ERROR: Low Speed Devices require bMaxPacketSize0 = 8\r\n"); + OOPS(); + } + break; + case UsbFullSpeed: + if(!(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 8 || + ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 16 || + ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 32 || + ConnectInfo->DeviceDescriptor.bMaxPacketSize0 == 64)) + { + //@@TestCase A1.10 + //@@ERROR + //@@Descriptor Field - bMaxPacketSize0 + //@@An invalid bMaxPacketSize0 has been defined for a full speed device + AppendTextBuffer("*!*ERROR: Full Speed Devices require bMaxPacketSize0 = 8, 16, 32, or 64\r\n"); + OOPS(); + } + break; + case UsbHighSpeed: + if(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 != 64) + { + //@@TestCase A1.11 + //@@ERROR + //@@Descriptor Field - bMaxPacketSize0 + //@@An invalid bMaxPacketSize0 has been defined for a high speed device + AppendTextBuffer("*!*ERROR: High Speed Devices require bMaxPacketSize0 = 64\r\n"); + OOPS(); + } + break; + case UsbSuperSpeed: + if(ConnectInfo->DeviceDescriptor.bMaxPacketSize0 != 9) + { + AppendTextBuffer("*!*ERROR: SuperSpeed Devices require bMaxPacketSize0 = 9 (512)\r\n"); + OOPS(); + } + break; + } + + AppendTextBuffer("idVendor: 0x%04X", + ConnectInfo->DeviceDescriptor.idVendor); + + if (gDoAnnotation) + { + VendorString = GetVendorString(ConnectInfo->DeviceDescriptor.idVendor); + if (VendorString != NULL) + { + AppendTextBuffer(" = %s\r\n", + VendorString); + } + } + else {AppendTextBuffer("\r\n");} + + AppendTextBuffer("idProduct: 0x%04X\r\n", + ConnectInfo->DeviceDescriptor.idProduct); + + AppendTextBuffer("bcdDevice: 0x%04X\r\n", + ConnectInfo->DeviceDescriptor.bcdDevice); + + AppendTextBuffer("iManufacturer: 0x%02X\r\n", + ConnectInfo->DeviceDescriptor.iManufacturer); + + if (ConnectInfo->DeviceDescriptor.iManufacturer && gDoAnnotation) + { + DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iManufacturer, + StringDescs, + info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); + } + + AppendTextBuffer("iProduct: 0x%02X\r\n", + ConnectInfo->DeviceDescriptor.iProduct); + + if (ConnectInfo->DeviceDescriptor.iProduct && gDoAnnotation) + { + DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iProduct, + StringDescs, + info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); + } + + AppendTextBuffer("iSerialNumber: 0x%02X\r\n", + ConnectInfo->DeviceDescriptor.iSerialNumber); + + if (ConnectInfo->DeviceDescriptor.iSerialNumber && gDoAnnotation) + { + DisplayStringDescriptor(ConnectInfo->DeviceDescriptor.iSerialNumber, + StringDescs, + info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); + } + + AppendTextBuffer("bNumConfigurations: 0x%02X\r\n", + ConnectInfo->DeviceDescriptor.bNumConfigurations); + + if(ConnectInfo->DeviceDescriptor.bNumConfigurations != 1) + { + //@@TestCase A1.12 + //@@CAUTION + //@@Descriptor Field - bNumConfigurations + //@@Most host controllers do not handle more than one configuration + AppendTextBuffer("*!*CAUTION: Most host controllers will only work with "\ + "one configuration per speed\r\n"); + OOPS(); + } + + if (ConnectInfo->NumberOfOpenPipes) + { + AppendTextBuffer("\r\n ---===>Open Pipes<===---\r\n"); + DisplayPipeInfo(ConnectInfo->NumberOfOpenPipes, + ConnectInfo->PipeList); + } + + return; +} + +/***************************************************************************** + +DisplayPipeInfo() + +NumPipes - Number of pipe for we info should be displayed. + +PipeInfo - Info about the pipes. + +*****************************************************************************/ + +VOID +DisplayPipeInfo ( + ULONG NumPipes, + USB_PIPE_INFO *PipeInfo + ) +{ + ULONG i = 0; + + for (i = 0; i < NumPipes; i++) + { + DisplayEndpointDescriptor(&PipeInfo[i].EndpointDescriptor, NULL, NULL, 0, FALSE); + } + +} + +/***************************************************************************** + +GetControllerFlavorString() + +Returns the text for given controller flavor + +*****************************************************************************/ +PCHAR GetControllerFlavorString(USB_CONTROLLER_FLAVOR flavor) +{ + return(GetStringFromList(slControllerFlavor, + sizeof(slControllerFlavor) / sizeof(STRINGLIST), + flavor, + STR_UNKNOWN_CONTROLLER_FLAVOR)); +} + + + +/***************************************************************************** + +GetPowerStateString() + +Returns the descriptive string for given power state + +*****************************************************************************/ +PCHAR GetPowerStateString(WDMUSB_POWER_STATE powerState) +{ + return(GetStringFromList(slPowerState, + sizeof(slPowerState) / sizeof(STRINGLIST), + powerState, + STR_INVALID_POWER_STATE)); +} + +/***************************************************************************** + +DisplayPowerState() + +PUSB_POWER_INFO pUPI - USBUSER.H USB_Power_Info data + +*****************************************************************************/ + +VOID +DisplayPowerState( + PUSB_POWER_INFO pUPI + ) +{ + AppendTextBuffer("%s\t%s\t%s%s\t\t%s\r\n", + GetPowerStateString(pUPI->SystemState), + GetPowerStateString(pUPI->HcDevicePowerState), + GetPowerStateString(pUPI->RhDevicePowerState), + pUPI->CanWakeup ? "Yes" : "", + pUPI->IsPowered ? "Yes" : "" + ); + return; +} + + + +/***************************************************************************** + +ValidateDescAddress() + +Given a descriptor address and the Configuration Descriptor length + (saved in DisplayConfigDesc(), and initialized for each new device) +return TRUE if the descriptor is within the Configuration length +else FALSE + +*****************************************************************************/ + +BOOL +ValidateDescAddress ( + PUSB_COMMON_DESCRIPTOR commonDesc + ) +{ + if ((PUCHAR) commonDesc + commonDesc->bLength <= g_descEnd) + { + return TRUE; + } + return FALSE; +} + +/***************************************************************************** + +DisplayConfigDesc() + +ConfigDesc - The Configuration Descriptor, and associated Interface and +Endpoint Descriptors + +*****************************************************************************/ + +VOID +DisplayConfigDesc ( + PUSBDEVICEINFO info, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + PSTRING_DESCRIPTOR_NODE StringDescs + ) +{ + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + UCHAR bInterfaceClass = 0; + UCHAR bInterfaceSubClass = 0; + UCHAR bInterfaceProtocol = 0; + BOOL displayUnknown = FALSE; + + BOOL isSS; + + isSS = info->ConnectionInfoV2 + && info->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher + ? TRUE + : FALSE; + + commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; + + // initialize global Configuration start/end address and string desc address + g_pConfigDesc = ConfigDesc; + g_pStringDescs = StringDescs; + g_descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; + + AppendTextBuffer("\r\n ---===>Full Configuration Descriptor<===---\r\n"); + + do + { + displayUnknown = FALSE; + + switch (commonDesc->bDescriptorType) + { + case USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE: + //@@DisplayConfigDesc - Device Qualifier Descriptor + if (commonDesc->bLength != sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR)) + { + //@@TestCase A2.1 + //@@ERROR + //@@Descriptor Field - bLength + //@@The declared length in the device descriptor is not equal to the + //@@ required length in the USB Device Specification + AppendTextBuffer("*!*ERROR: bLength of %d for Device Qualifier incorrect, "\ + "should be %d\r\n", + commonDesc->bLength, + sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR)); + OOPS(); + displayUnknown = TRUE; + break; + } + DisplayDeviceQualifierDescriptor((PUSB_DEVICE_QUALIFIER_DESCRIPTOR)commonDesc); + break; + + case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE: + //@@DisplayConfigDesc - Other Speed Configuration Descriptor + if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + //@@TestCase A2.2 + //@@ERROR + //@@Descriptor Field - bLength + //@@The declared length in the device descriptor is not equal to the + //@@ required length in the USB Device Specification + AppendTextBuffer("*!*ERROR: bLength of %d for Other Speed Configuration "\ + "incorrect, should be %d\r\n", + commonDesc->bLength, + sizeof(USB_CONFIGURATION_DESCRIPTOR)); + OOPS(); + displayUnknown = TRUE; + } + DisplayConfigurationDescriptor( + (PUSBDEVICEINFO) info, + (PUSB_CONFIGURATION_DESCRIPTOR)commonDesc, + StringDescs); + break; + + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + //@@DisplayConfigDesc - Configuration Descriptor + if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + //@@TestCase A2.3 + //@@ERROR + //@@Descriptor Field - bLength + //@@The declared length in the device descriptor is not equal to the + //@@required length in the USB Device Specification + AppendTextBuffer("*!*ERROR: bLength of %d for Configuration incorrect, "\ + "should be %d\r\n", + commonDesc->bLength, + sizeof(USB_CONFIGURATION_DESCRIPTOR)); + OOPS(); + displayUnknown = TRUE; + break; + } + DisplayConfigurationDescriptor((PUSBDEVICEINFO)info, + (PUSB_CONFIGURATION_DESCRIPTOR)commonDesc, + StringDescs); + break; + + case USB_INTERFACE_DESCRIPTOR_TYPE: + //@@DisplayConfigDesc - Interface Descriptor + if ((commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR)) && + (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2))) + { + //@@TestCase A2.4 + //@@ERROR + //@@Descriptor Field - bLength + //@@The declared length in the device descriptor is not equal to the + //@@required length in the USB Device Specification + AppendTextBuffer("*!*ERROR: bLength of %d for Interface incorrect, "\ + "should be %d or %d\r\n", + commonDesc->bLength, + sizeof(USB_INTERFACE_DESCRIPTOR), + sizeof(USB_INTERFACE_DESCRIPTOR2)); + OOPS(); + displayUnknown = TRUE; + break; + } + bInterfaceClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceClass; + bInterfaceSubClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceSubClass; + bInterfaceProtocol = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceProtocol; + + DisplayInterfaceDescriptor( + (PUSB_INTERFACE_DESCRIPTOR)commonDesc, + StringDescs, + info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); + + break; + + case USB_ENDPOINT_DESCRIPTOR_TYPE: + { + PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR epCompDesc = NULL; + PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR + sspIsochCompDesc = NULL; + + + //@@DisplayConfigDesc - Endpoint Descriptor + if ((commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR)) && + (commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR2))) + { + //@@TestCase A2.5 + //@@ERROR + //@@Descriptor Field - bLength + //@@The declared length in the device descriptor is not equal to + //@@ the required length in the USB Device Specification + AppendTextBuffer("*!*ERROR: bLength of %d for Endpoint incorrect, "\ + "should be %d or %d\r\n", + commonDesc->bLength, + sizeof(USB_ENDPOINT_DESCRIPTOR), + sizeof(USB_ENDPOINT_DESCRIPTOR2)); + OOPS(); + displayUnknown = TRUE; + break; + } + + if (isSS) + { + epCompDesc = (PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR) + GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)ConfigDesc, ConfigDesc->wTotalLength, commonDesc, -1); + } + + if (epCompDesc != NULL && + epCompDesc->bmAttributes.Isochronous.SspCompanion == 1) + { + sspIsochCompDesc = (PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR) + GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)ConfigDesc, + ConfigDesc->wTotalLength, + (PUSB_COMMON_DESCRIPTOR)epCompDesc, + -1); + } + + DisplayEndpointDescriptor((PUSB_ENDPOINT_DESCRIPTOR)commonDesc, + epCompDesc, + sspIsochCompDesc, + bInterfaceClass, + TRUE); + + if (sspIsochCompDesc != NULL) + { + commonDesc = (PUSB_COMMON_DESCRIPTOR)sspIsochCompDesc; + } + else if (epCompDesc != NULL) + { + commonDesc = (PUSB_COMMON_DESCRIPTOR)epCompDesc; + } + } + + break; + + case USB_HID_DESCRIPTOR_TYPE: + if (commonDesc->bLength < sizeof(USB_HID_DESCRIPTOR)) + { + OOPS(); + displayUnknown = TRUE; + break; + } + DisplayHidDescriptor((PUSB_HID_DESCRIPTOR)commonDesc); + break; + + case USB_OTG_DESCRIPTOR_TYPE: + if (commonDesc->bLength < sizeof(USB_OTG_DESCRIPTOR)) + { + OOPS(); + displayUnknown = TRUE; + break; + } + DisplayOTGDescriptor((PUSB_OTG_DESCRIPTOR)commonDesc); + break; + + case USB_IAD_DESCRIPTOR_TYPE: + if (commonDesc->bLength < sizeof(USB_IAD_DESCRIPTOR)) + { + OOPS(); + displayUnknown = TRUE; + break; + } + DisplayIADDescriptor((PUSB_IAD_DESCRIPTOR)commonDesc, StringDescs, + ConfigDesc->bNumInterfaces, + info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); + break; + + default: + //@@DisplayConfigDesc - Interface Class Device + // TODO: BUG: bInterfaceClass is initialized before this code + switch (bInterfaceClass) + { + case USB_DEVICE_CLASS_AUDIO: + displayUnknown = ! DisplayAudioDescriptor( + (PUSB_AUDIO_COMMON_DESCRIPTOR)commonDesc, + bInterfaceSubClass); + break; + + case USB_DEVICE_CLASS_VIDEO: + displayUnknown = ! DisplayVideoDescriptor( + (PVIDEO_SPECIFIC)commonDesc, + bInterfaceSubClass, + StringDescs, + info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); + break; + + case USB_DEVICE_CLASS_RESERVED: + //@@TestCase A2.6 + //@@ERROR + //@@Descriptor Field - bInterfaceClass + //@@An unknown interface class has been defined + AppendTextBuffer("*!*ERROR: %d is a Reserved USB Device Interface Class\r\n", + USB_DEVICE_CLASS_RESERVED); + displayUnknown = TRUE; + break; + + case USB_DEVICE_CLASS_COMMUNICATIONS: + AppendTextBuffer(" -> This is a Communications (CDC Control) USB Device Interface Class\r\n"); + displayUnknown = TRUE; + break; + + case USB_DEVICE_CLASS_HUMAN_INTERFACE: + AppendTextBuffer(" -> This is a HID USB Device Interface Class\r\n"); + displayUnknown = TRUE; + break; + + case USB_DEVICE_CLASS_MONITOR: + AppendTextBuffer(" -> This is a Monitor USB Device Interface Class (This may be obsolete)\r\n"); + displayUnknown = TRUE; + break; + + case USB_DEVICE_CLASS_PHYSICAL_INTERFACE: + AppendTextBuffer(" -> This is a Physical Interface USB Device Interface Class\r\n"); + displayUnknown = TRUE; + break; + + case USB_DEVICE_CLASS_POWER: + if(bInterfaceSubClass == 1 && bInterfaceProtocol == 1) + { + AppendTextBuffer(" -> This is an Image USB Device Interface Class\r\n"); + } + else + { + AppendTextBuffer(" -> This is a Power USB Device Interface Class (This may be obsolete)\r\n"); + } + displayUnknown = TRUE; + break; + + case USB_DEVICE_CLASS_PRINTER: + AppendTextBuffer(" -> This is a Printer USB Device Interface Class\r\n"); + displayUnknown = TRUE; + break; + + case USB_DEVICE_CLASS_STORAGE: + AppendTextBuffer(" -> This is a Mass Storage USB Device Interface Class\r\n"); + displayUnknown = TRUE; + break; + + case USB_DEVICE_CLASS_HUB: + AppendTextBuffer(" -> This is a HUB USB Device Interface Class\r\n"); + displayUnknown = TRUE; + break; + + case USB_CDC_DATA_INTERFACE: + AppendTextBuffer(" -> This is a CDC Data USB Device Interface Class\r\n"); + displayUnknown = TRUE; + break; + + case USB_CHIP_SMART_CARD_INTERFACE: + AppendTextBuffer(" -> This is a Chip/Smart Card USB Device Interface Class\r\n"); + displayUnknown = TRUE; + break; + + case USB_CONTENT_SECURITY_INTERFACE: + AppendTextBuffer(" -> This is a Content Security USB Device Interface Class\r\n"); + displayUnknown = TRUE; + break; + + case USB_DIAGNOSTIC_DEVICE_INTERFACE: + if(bInterfaceSubClass == 1 && bInterfaceProtocol == 1) + { + AppendTextBuffer(" -> This is a Reprogrammable USB2 Compliance Diagnostic Device USB Device\r\n"); + } + else + { + //@@TestCase A2.7 + //@@CAUTION + //@@Descriptor Field - bInterfaceClass + //@@An unknown diagnostic interface class device has been defined + AppendTextBuffer("*!*CAUTION: This appears to be an invalid Interface Class\r\n"); + OOPS(); + } + displayUnknown = TRUE; + break; + + case USB_WIRELESS_CONTROLLER_INTERFACE: + if(bInterfaceSubClass == 1 && bInterfaceProtocol == 1) + { + AppendTextBuffer(" -> This is a Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface\r\n"); + } + else + { + //@@TestCase A2.8 + //@@CAUTION + //@@Descriptor Field - bInterfaceClass + //@@An unknown wireless controller interface class device has been defined + AppendTextBuffer("*!*CAUTION: This appears to be an invalid Interface Class\r\n"); + OOPS(); + } + displayUnknown = TRUE; + break; + + case USB_APPLICATION_SPECIFIC_INTERFACE: + AppendTextBuffer(" -> This is an Application Specific USB Device Interface Class\r\n"); + + switch(bInterfaceSubClass) + { + case 1: + AppendTextBuffer(" -> This is a Device Firmware Application Specific USB Device Interface Class\r\n"); + break; + case 2: + AppendTextBuffer(" -> This is an IrDA Bridge Application Specific USB Device Interface Class\r\n"); + break; + case 3: + AppendTextBuffer(" -> This is a Test & Measurement Class (USBTMC) Application Specific USB Device Interface Class\r\n"); + break; + default: + //@@TestCase A2.9 + //@@CAUTION + //@@Descriptor Field - bInterfaceClass + //@@A possibly invalid interface class has been defined + AppendTextBuffer("*!*CAUTION: This appears to be an invalid Interface Class\r\n"); + OOPS(); + } + displayUnknown = TRUE; + break; + + default: + if (bInterfaceClass == USB_DEVICE_CLASS_VENDOR_SPECIFIC) + { + AppendTextBuffer(" -> This is a Vendor Specific USB Device Interface Class\r\n"); + } + else + { + //@@TestCase A2.10 + //@@CAUTION + //@@Descriptor Field - bInterfaceClass + //@@An unknown interface class has been defined + AppendTextBuffer("*!*CAUTION: This appears to be an invalid Interface Class\r\n"); + OOPS(); + } + displayUnknown = TRUE; + break; + } + break; + } + + if (displayUnknown) + { + DisplayUnknownDescriptor(commonDesc); + } + } while ((commonDesc = GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)ConfigDesc, + ConfigDesc->wTotalLength, + commonDesc, + -1)) != NULL); + +#ifdef H264_SUPPORT + DoAdditionalErrorChecks(); +#endif +} + + +/***************************************************************************** + +DisplayDeviceQualifierDescriptor() + +*****************************************************************************/ + +VOID +DisplayDeviceQualifierDescriptor ( + PUSB_DEVICE_QUALIFIER_DESCRIPTOR DevQualDesc + ) +{ + //@@DisplayDeviceQualifierDescriptor - Device Qualifier Descriptor + + AppendTextBuffer("\r\n ===>Device Qualifier Descriptor<===\r\n"); + + //length checked in DisplayConfigDesc() + + AppendTextBuffer("bLength: 0x%02X\r\n", + DevQualDesc->bLength); + + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + DevQualDesc->bDescriptorType); + + AppendTextBuffer("bcdUSB: 0x%04X\r\n", + DevQualDesc->bcdUSB); + + AppendTextBuffer("bDeviceClass: 0x%02X", + DevQualDesc->bDeviceClass); + + switch (DevQualDesc->bDeviceClass) + { + case USB_INTERFACE_CLASS_DEVICE: + if(gDoAnnotation) + { + AppendTextBuffer(" -> This is an Interface Class Defined Device\r\n"); + } + break; + + case USB_COMMUNICATION_DEVICE: + if(gDoAnnotation) + { + AppendTextBuffer(" -> This is a Communication Device\r\n"); + } + break; + + case USB_HUB_DEVICE: + if(gDoAnnotation) + { + AppendTextBuffer(" -> This is a HUB Device\r\n"); + } + break; + + case USB_DIAGNOSTIC_DEVICE: + if(gDoAnnotation) + { + AppendTextBuffer(" -> This is a Diagnostic Device\r\n"); + } + break; + + case USB_WIRELESS_CONTROLLER_DEVICE: + if(gDoAnnotation) + { + AppendTextBuffer(" -> This is a Wireless Controller(Bluetooth) Device\r\n"); + } + break; + + case USB_VENDOR_SPECIFIC_DEVICE: + if(gDoAnnotation) + { + AppendTextBuffer(" -> This is a Vendor Specific Device\r\n"); + } + break; + + default: + //@@TestCase A3.1 + //@@ERROR + //@@Descriptor Field - bDeviceClass + //@@An unknown device class has been defined + AppendTextBuffer("*!*ERROR: bDeviceClass of %d is invalid\r\n", + DevQualDesc->bDeviceClass); + OOPS(); + break; + } + + AppendTextBuffer("bDeviceSubClass: 0x%02X\r\n", + DevQualDesc->bDeviceSubClass); + + if(DevQualDesc->bDeviceSubClass > 0x00 && DevQualDesc->bDeviceSubClass < 0xFF) + { + //@@TestCase A3.2 + //@@ERROR + //@@Descriptor Field - bDeviceSubClass + //@@An unknown device sub class has been defined + AppendTextBuffer("*!*ERROR: bDeviceSubClass of %d is invalid\r\n", + DevQualDesc->bDeviceSubClass); + OOPS(); + } + + AppendTextBuffer("bDeviceProtocol: 0x%02X\r\n", + DevQualDesc->bDeviceProtocol); + + if(DevQualDesc->bDeviceProtocol > 0x00 && DevQualDesc->bDeviceProtocol < 0xFF) + { + //@@TestCase A3.4 + //@@ERROR + //@@Descriptor Field - bDeviceProtocol + //@@An invalid device protocol has been defined + AppendTextBuffer("*!*ERROR: bDeviceProtocol of %d is invalid", + DevQualDesc->bDeviceProtocol); + OOPS(); + } + + //@@TestCase A3.5 + //@@Priority 1 + //@@Descriptor Field - bcdDevice + //@@We should test to verify a valid bMaxPacketSize0 based on speed + AppendTextBuffer("bMaxPacketSize0: 0x%02X", + DevQualDesc->bMaxPacketSize0); + + if(gDoAnnotation) + { + AppendTextBuffer(" = (%d) Bytes\r\n", + DevQualDesc->bMaxPacketSize0); + } + else {AppendTextBuffer("\r\n");} + + AppendTextBuffer("bNumConfigurations: 0x%02X\r\n", + DevQualDesc->bNumConfigurations); + + if(DevQualDesc->bNumConfigurations != 1) + { + //@@TestCase A3.6 + //@@CAUTION + //@@Descriptor Field - bNumConfigurations + //@@Most host controllers do not handle more than one configuration + AppendTextBuffer("*!*CAUTION: Most host controllers will only work with one configuration per speed\r\n"); + OOPS(); + } + + AppendTextBuffer("bReserved: 0x%02X\r\n", + DevQualDesc->bReserved); + + if(DevQualDesc->bReserved != 0) + { + AppendTextBuffer("*!*WARNING: bReserved needs to be set to 0 to be valid\r\n"); + OOPS(); + } + + +} + +VOID +DisplayUsb20CapabilityExtensionDescriptor ( + PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR extCapDesc + ) +{ + AppendTextBuffer("\r\n ===>USB 2.0 Extension Descriptor<===\r\n"); + + AppendTextBuffer("bLength: 0x%02X\r\n", + extCapDesc->bLength); + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + extCapDesc->bDescriptorType); + AppendTextBuffer("bDevCapabilityType: 0x%02X\r\n", + extCapDesc->bDevCapabilityType); + AppendTextBuffer("bmAttributes: 0x%08X", + extCapDesc->bmAttributes); + if (extCapDesc->bmAttributes.AsUlong & USB_DEVICE_CAPABILITY_USB20_EXTENSION_BMATTRIBUTES_RESERVED_MASK) + { + if(gDoAnnotation) + { + AppendTextBuffer("\r\n*!*ERROR: bits 31..2 and bit 0 are reserved and must be 0\r\n"); + } + } + if (extCapDesc->bmAttributes.LPMCapable == 1) + { + if(gDoAnnotation) + { + AppendTextBuffer(" -> Supports Link Power Management protocol\r\n"); + } + } + if (extCapDesc->bmAttributes.AsUlong == 0) + { + AppendTextBuffer("\r\n"); + } +} + +VOID +DisplaySuperSpeedCapabilityExtensionDescriptor ( + PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR ssCapDesc + ) +{ + AppendTextBuffer("\r\n ===>SuperSpeed USB Device Capability Descriptor<===\r\n"); + + AppendTextBuffer("bLength: 0x%02X\r\n", + ssCapDesc->bLength); + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + ssCapDesc->bDescriptorType); + AppendTextBuffer("bDevCapabilityType: 0x%02X\r\n", + ssCapDesc->bDevCapabilityType); + AppendTextBuffer("bmAttributes: 0x%02X\r\n", + ssCapDesc->bmAttributes); + if (ssCapDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_RESERVED_MASK) + { + if(gDoAnnotation) + { + AppendTextBuffer("\r\n*!*ERROR: bits 7:2 and bit 0 are reserved\r\n"); + } + } + if (ssCapDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_LTM_CAPABLE) + { + if(gDoAnnotation) + { + AppendTextBuffer(" -> capable of generating Latency Tolerance Messages\r\n"); + } + } + AppendTextBuffer("wSpeedsSupported: 0x%02X\r\n", + ssCapDesc->wSpeedsSupported); + + if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_LOW) + { + if(gDoAnnotation) + { + AppendTextBuffer(" -> Supports low-speed operation\r\n"); + } + } + if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_FULL) + { + if(gDoAnnotation) + { + AppendTextBuffer(" -> Supports full-speed operation\r\n"); + } + } + if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_HIGH) + { + if(gDoAnnotation) + { + AppendTextBuffer(" -> Supports high-speed operation\r\n"); + } + } + if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_SUPER) + { + if(gDoAnnotation) + { + AppendTextBuffer(" -> Supports SuperSpeed operation\r\n"); + } + } + if (ssCapDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_RESERVED_MASK) + { + if(gDoAnnotation) + { + AppendTextBuffer("\r\n*!*ERROR: bits 15:4 are reserved\r\n"); + } + } + if (!gDoAnnotation) + { + AppendTextBuffer("\r\n"); + } + AppendTextBuffer("bFunctionalitySupport: 0x%02X", + ssCapDesc->bFunctionalitySupport); + if(gDoAnnotation) + { + switch (ssCapDesc->bFunctionalitySupport) + { + case UsbLowSpeed: + AppendTextBuffer(" -> lowest speed = low-speed\r\n"); + break; + case UsbFullSpeed: + AppendTextBuffer(" -> lowest speed = full-speed\r\n"); + break; + case UsbHighSpeed: + AppendTextBuffer(" -> lowest speed = high-speed\r\n"); + break; + case UsbSuperSpeed: + AppendTextBuffer(" -> lowest speed = SuperSpeed\r\n"); + break; + default: + AppendTextBuffer("\r\n*!*ERROR: Invalid value\r\n"); + break; + } + } + else + { + AppendTextBuffer("\r\n"); + } + + AppendTextBuffer("bU1DevExitLat: 0x%02X", + ssCapDesc->bU1DevExitLat); + if(gDoAnnotation) + { + if (ssCapDesc->bU1DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U1_DEVICE_EXIT_MAX_VALUE) + { + AppendTextBuffer(" -> less than %d micro-seconds\r\n", + ssCapDesc->bU1DevExitLat); + } + else + { + AppendTextBuffer("\r\n*!*ERROR: Invalid value\r\n"); + } + } + else + { + AppendTextBuffer("\r\n"); + } + + AppendTextBuffer("wU2DevExitLat: 0x%04X", + ssCapDesc->wU2DevExitLat); + if(gDoAnnotation) + { + if (ssCapDesc->wU2DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U2_DEVICE_EXIT_MAX_VALUE) + { + AppendTextBuffer(" -> less than %d micro-seconds\r\n", + ssCapDesc->wU2DevExitLat); + } + else + { + AppendTextBuffer("\r\n*!*ERROR: Invalid value\r\n"); + } + } + else + { + AppendTextBuffer("\r\n"); + } +} + + +VOID +DisplayContainerIdCapabilityExtensionDescriptor ( + PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR containerIdCapDesc + ) +{ + LPGUID pGuid; + + AppendTextBuffer("\r\n ===>Container ID Capability Descriptor<===\r\n"); + + AppendTextBuffer("bLength: 0x%02X\r\n", + containerIdCapDesc->bLength); + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + containerIdCapDesc->bDescriptorType); + AppendTextBuffer("bDevCapabilityType: 0x%02X\r\n", + containerIdCapDesc->bDevCapabilityType); + AppendTextBuffer("bReserved: 0x%02X\r\n", + containerIdCapDesc->bReserved); + if (containerIdCapDesc->bReserved != 0) + { + if(gDoAnnotation) + { + AppendTextBuffer("*!*ERROR: field is reserved\r\n"); + } + } + + pGuid = (LPGUID)containerIdCapDesc->ContainerID; + AppendTextBuffer("Container ID: "); + AppendTextBuffer("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\r\n", + pGuid->Data1, + pGuid->Data2, + pGuid->Data3, + pGuid->Data4[0], + pGuid->Data4[1], + pGuid->Data4[2], + pGuid->Data4[3], + pGuid->Data4[4], + pGuid->Data4[5], + pGuid->Data4[6], + pGuid->Data4[7]); +} + +/***************************************************************************** + +DisplayBosDescriptor() + +BosDesc - The Binary Object Store (BOS) Descriptor, and associated Descriptors + +*****************************************************************************/ + +VOID +DisplayBosDescriptor ( + PUSB_BOS_DESCRIPTOR BosDesc + ) +{ + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + PUSB_DEVICE_CAPABILITY_DESCRIPTOR capDesc = NULL; + + AppendTextBuffer("\r\n ===>BOS Descriptor<===\r\n"); + + AppendTextBuffer("bLength: 0x%02X\r\n", + BosDesc->bLength); + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + BosDesc->bDescriptorType); + AppendTextBuffer("wTotalLength: 0x%04X\r\n", + BosDesc->wTotalLength); + AppendTextBuffer("bNumDeviceCaps: 0x%02X\r\n", + BosDesc->bNumDeviceCaps); + + commonDesc = (PUSB_COMMON_DESCRIPTOR)BosDesc; + + while ((commonDesc = GetNextDescriptor((PUSB_COMMON_DESCRIPTOR)BosDesc, + BosDesc->wTotalLength, + commonDesc, + -1)) != NULL) + { + switch (commonDesc->bDescriptorType) + { + case USB_DEVICE_CAPABILITY_DESCRIPTOR_TYPE: + + capDesc = (PUSB_DEVICE_CAPABILITY_DESCRIPTOR)commonDesc; + + switch (capDesc->bDevCapabilityType) + { + case USB_DEVICE_CAPABILITY_USB20_EXTENSION: + DisplayUsb20CapabilityExtensionDescriptor((PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR)capDesc); + break; + case USB_DEVICE_CAPABILITY_SUPERSPEED_USB: + DisplaySuperSpeedCapabilityExtensionDescriptor((PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR)capDesc); + break; + case USB_DEVICE_CAPABILITY_CONTAINER_ID: + DisplayContainerIdCapabilityExtensionDescriptor((PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR)capDesc); + break; + default: + AppendTextBuffer("\r\n ===>Unknown Capability Descriptor<===\r\n"); + + AppendTextBuffer("bLength: 0x%02X\r\n", + capDesc->bLength); + AppendTextBuffer("bType: 0x%02X\r\n", + capDesc->bLength); + AppendTextBuffer("bDevCapabilityType: 0x%02X\r\n", + capDesc->bDevCapabilityType); + + DisplayRemainingUnknownDescriptor((PUCHAR)commonDesc, + (ULONG)sizeof(USB_DEVICE_CAPABILITY_DESCRIPTOR), + commonDesc->bLength); + break; + } + break; + + default: + DisplayUnknownDescriptor(commonDesc); + break; + } + } +} + + +/***************************************************************************** + +DisplayConfigurationDescriptor() + +*****************************************************************************/ + +VOID +DisplayConfigurationDescriptor ( + PUSBDEVICEINFO info, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + PSTRING_DESCRIPTOR_NODE StringDescs + ) +{ + UINT uCount = 0; + BOOL isSS; + + + isSS = info->ConnectionInfoV2 + && (info->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher || + info->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher) + ? TRUE + : FALSE; + + AppendTextBuffer("\r\n ===>Configuration Descriptor<===\r\n"); + //@@DisplayConfigurationDescriptor - Configuration Descriptor + + //length checked in DisplayConfigDesc() + + AppendTextBuffer("bLength: 0x%02X\r\n", + ConfigDesc->bLength); + + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + ConfigDesc->bDescriptorType); + + //@@TestCase A4.1 + //@@Priority 1 + //@@Descriptor Field - wTotalLength + //@@Verify Configuration length is valid + AppendTextBuffer("wTotalLength: 0x%04X", + ConfigDesc->wTotalLength); + uCount = GetConfigurationSize(info); + if (uCount != ConfigDesc->wTotalLength) { + AppendTextBuffer("\r\n*!*ERROR: Invalid total configuration size 0x%02X, should be 0x%02X\r\n", + ConfigDesc->wTotalLength, uCount); + } else { + AppendTextBuffer(" -> Validated\r\n"); + } + + //@@TestCase A4.2 + //@@Priority 1 + //@@Descriptor Field - bNumInterfaces + //@@Verify the number of interfaces is valid + AppendTextBuffer("bNumInterfaces: 0x%02X\r\n", + ConfigDesc->bNumInterfaces); + +/* Need to check spec vs composite devices + uCount = GetInterfaceCount(info); + if (uCount != ConfigDesc->bNumInterfaces) { + AppendTextBuffer("\r\n*!*ERROR: Invalid total Interfaces %d, should be %d\r\n", + ConfigDesc->bNumInterfaces, uCount); + } else { + AppendTextBuffer(" -> Validated\r\n"); + } +*/ + + AppendTextBuffer("bConfigurationValue: 0x%02X\r\n", + ConfigDesc->bConfigurationValue); + + if(ConfigDesc->bConfigurationValue != 1) + { + //@@TestCase A4.3 + //@@CAUTION + //@@Descriptor Field - bConfigurationValue + //@@Most host controllers do not handle more than one configuration + AppendTextBuffer("*!*CAUTION: Most host controllers will only work with one configuration per speed\r\n"); + OOPS(); + } + + AppendTextBuffer("iConfiguration: 0x%02X\r\n", + ConfigDesc->iConfiguration); + + if (ConfigDesc->iConfiguration && gDoAnnotation) + { + DisplayStringDescriptor(ConfigDesc->iConfiguration, + StringDescs, + info->DeviceInfoNode != NULL? info->DeviceInfoNode->LatestDevicePowerState: PowerDeviceUnspecified); + } + + AppendTextBuffer("bmAttributes: 0x%02X", + ConfigDesc->bmAttributes); + + if (info->ConnectionInfo->DeviceDescriptor.bcdUSB == 0x0100) + { + if (ConfigDesc->bmAttributes & USB_CONFIG_SELF_POWERED) + { + if(gDoAnnotation) + { + AppendTextBuffer(" -> Self Powered\r\n"); + } + } + if (ConfigDesc->bmAttributes & USB_CONFIG_BUS_POWERED) + { + if(gDoAnnotation) + { + AppendTextBuffer(" -> Bus Powered\r\n"); + } + } + } + else + { + if (ConfigDesc->bmAttributes & USB_CONFIG_SELF_POWERED) + { + if(gDoAnnotation) + { + AppendTextBuffer(" -> Self Powered\r\n"); + } + } + else + { + if(gDoAnnotation) + { + AppendTextBuffer(" -> Bus Powered\r\n"); + } + } + if ((ConfigDesc->bmAttributes & USB_CONFIG_BUS_POWERED) == 0) + { + AppendTextBuffer("\r\n*!*ERROR: Bit 7 is reserved and must be set\r\n"); + OOPS(); + } + } + + if (ConfigDesc->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) + { + if(gDoAnnotation) + { + AppendTextBuffer(" -> Remote Wakeup\r\n"); + } + } + + if (ConfigDesc->bmAttributes & USB_CONFIG_RESERVED) + { + //@@TestCase A4.4 + //@@WARNING + //@@Descriptor Field - bmAttributes + //@@A bit has been set in reserved space + AppendTextBuffer("\r\n*!*ERROR: Bits 4...0 are reserved\r\n"); + OOPS(); + } + + AppendTextBuffer("MaxPower: 0x%02X", + ConfigDesc->MaxPower); + + if(gDoAnnotation) + { + AppendTextBuffer(" = %3d mA\r\n", + isSS ? ConfigDesc->MaxPower * 8 : ConfigDesc->MaxPower * 2); + } + else {AppendTextBuffer("\r\n");} + +} + +/***************************************************************************** + +DisplayInterfaceDescriptor() + +*****************************************************************************/ + +VOID +DisplayInterfaceDescriptor ( + PUSB_INTERFACE_DESCRIPTOR InterfaceDesc, + PSTRING_DESCRIPTOR_NODE StringDescs, + DEVICE_POWER_STATE LatestDevicePowerState + ) +{ + //@@DisplayInterfaceDescriptor - Interface Descriptor + AppendTextBuffer("\r\n ===>Interface Descriptor<===\r\n"); + + //length checked in DisplayConfigDesc() + AppendTextBuffer("bLength: 0x%02X\r\n", + InterfaceDesc->bLength); + + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + InterfaceDesc->bDescriptorType); + + //@@TestCase A5.1 + //@@Priority 1 + //@@Descriptor Field - bInterfaceNumber + //@@Question - Should we test to verify bInterfaceNumber is valid? + AppendTextBuffer("bInterfaceNumber: 0x%02X\r\n", + InterfaceDesc->bInterfaceNumber); + + //@@TestCase A5.2 + //@@Priority 1 + //@@Descriptor Field - bAlternateSetting + //@@Question - Should we test to verify bAlternateSetting is valid? + AppendTextBuffer("bAlternateSetting: 0x%02X\r\n", + InterfaceDesc->bAlternateSetting); + + //@@TestCase A5.3 + //@@Priority 1 + //@@Descriptor Field - bNumEndpoints + //@@Question - Should we test to verify bNumEndpoints is valid? + AppendTextBuffer("bNumEndpoints: 0x%02X\r\n", + InterfaceDesc->bNumEndpoints); + + AppendTextBuffer("bInterfaceClass: 0x%02X", + InterfaceDesc->bInterfaceClass); + + switch (InterfaceDesc->bInterfaceClass) + { + case USB_DEVICE_CLASS_AUDIO: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Audio Interface Class\r\n"); + } + + AppendTextBuffer("bInterfaceSubClass: 0x%02X", + InterfaceDesc->bInterfaceSubClass); + + if(gDoAnnotation) + { + switch (InterfaceDesc->bInterfaceSubClass) + { + case USB_AUDIO_SUBCLASS_AUDIOCONTROL: + AppendTextBuffer(" -> Audio Control Interface SubClass\r\n"); + break; + + case USB_AUDIO_SUBCLASS_AUDIOSTREAMING: + AppendTextBuffer(" -> Audio Streaming Interface SubClass\r\n"); + break; + + case USB_AUDIO_SUBCLASS_MIDISTREAMING: + AppendTextBuffer(" -> MIDI Streaming Interface SubClass\r\n"); + break; + + default: + //@@TestCase A5.4 + //@@CAUTION + //@@Descriptor Field - bInterfaceSubClass + //@@Invalid bInterfaceSubClass + AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid bInterfaceSubClass\r\n"); + OOPS(); + break; + } + } + break; + + case USB_DEVICE_CLASS_VIDEO: + if(gDoAnnotation) + AppendTextBuffer(" -> Video Interface Class\r\n"); + + AppendTextBuffer("bInterfaceSubClass: 0x%02X", + InterfaceDesc->bInterfaceSubClass); + + switch(InterfaceDesc->bInterfaceSubClass) + { + case VIDEO_SUBCLASS_CONTROL: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Video Control Interface SubClass\r\n"); + } + break; + + case VIDEO_SUBCLASS_STREAMING: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Video Streaming Interface SubClass\r\n"); + } + break; + + default: + //@@TestCase A5.5 + //@@CAUTION + //@@Descriptor Field - bInterfaceSubClass + //@@Invalid bInterfaceSubClass + AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid bInterfaceSubClass\r\n"); + OOPS(); + break; + } + break; + + case USB_DEVICE_CLASS_HUMAN_INTERFACE: + if(gDoAnnotation) + { + AppendTextBuffer(" -> HID Interface Class\r\n"); + } + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_DEVICE_CLASS_HUB: + if(gDoAnnotation) + { + AppendTextBuffer(" -> HUB Interface Class\r\n"); + } + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_DEVICE_CLASS_RESERVED: + //@@TestCase A5.6 + //@@CAUTION + //@@Descriptor Field - bInterfaceClass + //@@A reserved USB Device Interface Class has been defined + AppendTextBuffer("\r\n*!*CAUTION: %d is a Reserved USB Device Interface Class\r\n", + USB_DEVICE_CLASS_RESERVED); + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_DEVICE_CLASS_COMMUNICATIONS: + AppendTextBuffer(" -> This is Communications (CDC Control) USB Device Interface Class\r\n"); + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_DEVICE_CLASS_MONITOR: + AppendTextBuffer(" -> This is a Monitor USB Device Interface Class*** (This may be obsolete)\r\n"); + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_DEVICE_CLASS_PHYSICAL_INTERFACE: + AppendTextBuffer(" -> This is a Physical Interface USB Device Interface Class\r\n"); + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_DEVICE_CLASS_POWER: + if(InterfaceDesc->bInterfaceSubClass == 1 && InterfaceDesc->bInterfaceProtocol == 1) + { + AppendTextBuffer(" -> This is an Image USB Device Interface Class\r\n"); + } + else + { + AppendTextBuffer(" -> This is a Power USB Device Interface Class (This may be obsolete)\r\n"); + } + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_DEVICE_CLASS_PRINTER: + AppendTextBuffer(" -> This is a Printer USB Device Interface Class\r\n"); + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_DEVICE_CLASS_STORAGE: + AppendTextBuffer(" -> This is a Mass Storage USB Device Interface Class\r\n"); + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_CDC_DATA_INTERFACE: + AppendTextBuffer(" -> This is a CDC Data USB Device Interface Class\r\n"); + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_CHIP_SMART_CARD_INTERFACE: + AppendTextBuffer(" -> This is a Chip/Smart Card USB Device Interface Class\r\n"); + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_CONTENT_SECURITY_INTERFACE: + AppendTextBuffer(" -> This is a Content Security USB Device Interface Class\r\n"); + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_DIAGNOSTIC_DEVICE_INTERFACE: + if(InterfaceDesc->bInterfaceSubClass == 1 && InterfaceDesc->bInterfaceProtocol == 1) + { + AppendTextBuffer(" -> This is a Reprogrammable USB2 Compliance Diagnostic Device USB Device\r\n"); + } + else + { + //@@TestCase A5.7 + //@@CAUTION + //@@Descriptor Field - bInterfaceClass + //@@Invalid Interface Class + AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); + OOPS(); + } + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_WIRELESS_CONTROLLER_INTERFACE: + if(InterfaceDesc->bInterfaceSubClass == 1 && InterfaceDesc->bInterfaceProtocol == 1) + { + AppendTextBuffer(" -> This is a Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface\r\n"); + } + else + { + //@@TestCase A5.8 + //@@CAUTION + //@@Descriptor Field - bInterfaceClass + //@@Invalid Interface Class + AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); + OOPS(); + } + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + case USB_APPLICATION_SPECIFIC_INTERFACE: + AppendTextBuffer(" -> This is an Application Specific USB Device Interface Class\r\n"); + + switch(InterfaceDesc->bInterfaceSubClass) + { + case 1: + AppendTextBuffer(" -> This is a Device Firmware Application Specific USB Device Interface Class\r\n"); + break; + case 2: + AppendTextBuffer(" -> This is an IrDA Bridge Application Specific USB Device Interface Class\r\n"); + break; + case 3: + AppendTextBuffer(" -> This is a Test & Measurement Class (USBTMC) Application Specific USB Device Interface Class\r\n"); + break; + default: + //@@TestCase A5.9 + //@@CAUTION + //@@Descriptor Field - bInterfaceClass + //@@Invalid Interface Class + AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); + OOPS(); + } + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + + default: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Interface Class Unknown to USBView\r\n"); + } + AppendTextBuffer("bInterfaceSubClass: 0x%02X\r\n", + InterfaceDesc->bInterfaceSubClass); + break; + } + + AppendTextBuffer("bInterfaceProtocol: 0x%02X\r\n", + InterfaceDesc->bInterfaceProtocol); + + //This is basically the check for PC_PROTOCOL_UNDEFINED + if ((InterfaceDesc->bInterfaceClass == USB_DEVICE_CLASS_VIDEO) || + (InterfaceDesc->bInterfaceClass == USB_DEVICE_CLASS_AUDIO)) + { + if(InterfaceDesc->bInterfaceProtocol != PC_PROTOCOL_UNDEFINED) + { + //@@TestCase A5.10 + //@@WARNING + //@@Descriptor Field - iInterface + //@@bInterfaceProtocol must be set to PC_PROTOCOL_UNDEFINED + AppendTextBuffer("*!*WARNING: must be set to PC_PROTOCOL_UNDEFINED %d for this class\r\n", + PC_PROTOCOL_UNDEFINED); + OOPS(); + } + } + + AppendTextBuffer("iInterface: 0x%02X\r\n", + InterfaceDesc->iInterface); + + if(gDoAnnotation) + { + if (InterfaceDesc->iInterface) + { + DisplayStringDescriptor(InterfaceDesc->iInterface, + StringDescs, + LatestDevicePowerState); + } + } + + if (InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR2)) + { + PUSB_INTERFACE_DESCRIPTOR2 interfaceDesc2; + + interfaceDesc2 = (PUSB_INTERFACE_DESCRIPTOR2)InterfaceDesc; + + AppendTextBuffer("wNumClasses: 0x%04X\r\n", + interfaceDesc2->wNumClasses); + } + +} + +/***************************************************************************** + +DisplayEndpointDescriptor() + +*****************************************************************************/ + +VOID +DisplayEndpointDescriptor ( + _In_ PUSB_ENDPOINT_DESCRIPTOR + EndpointDesc, + _In_opt_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR + EpCompDesc, + _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR + SspIsochEpCompDesc, + _In_ UCHAR InterfaceClass, + _In_ BOOLEAN EpCompDescAvail + ) +{ + UCHAR epType = EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK; + PUSB_HIGH_SPEED_MAXPACKET hsMaxPacket; + + AppendTextBuffer("\r\n ===>Endpoint Descriptor<===\r\n"); + //@@DisplayEndpointDescriptor - Endpoint Descriptor + //length checked in DisplayConfigDesc() + + AppendTextBuffer("bLength: 0x%02X\r\n", + EndpointDesc->bLength); + + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + EndpointDesc->bDescriptorType); + + AppendTextBuffer("bEndpointAddress: 0x%02X", + EndpointDesc->bEndpointAddress); + + if(gDoAnnotation) + { + if(USB_ENDPOINT_DIRECTION_OUT(EndpointDesc->bEndpointAddress)) + { + AppendTextBuffer(" -> Direction: OUT - EndpointID: %d\r\n", + (EndpointDesc->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK)); + } + else if(USB_ENDPOINT_DIRECTION_IN(EndpointDesc->bEndpointAddress)) + { + AppendTextBuffer(" -> Direction: IN - EndpointID: %d\r\n", + (EndpointDesc->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK)); + } + else + { + //@@TestCase A6.1 + //@@ERROR + //@@Descriptor Field - bEndpointAddress + //@@An invalid endpoint addressl has been defined + AppendTextBuffer("\r\n*!*ERROR: This appears to be an invalid bEndpointAddress\r\n"); + OOPS(); + } + } + else {AppendTextBuffer("\r\n");} + + AppendTextBuffer("bmAttributes: 0x%02X", + EndpointDesc->bmAttributes); + + if(gDoAnnotation) + { + AppendTextBuffer(" -> "); + + switch (epType) + { + case USB_ENDPOINT_TYPE_CONTROL: + AppendTextBuffer("Control Transfer Type\r\n"); + if (EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_CONTROL_RESERVED_MASK) + { + AppendTextBuffer("\r\n*!*ERROR: Bits 7..2 are reserved and must be set to 0\r\n"); + OOPS(); + } + break; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + AppendTextBuffer("Isochronous Transfer Type, Synchronization Type = "); + + switch (USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION(EndpointDesc->bmAttributes)) + { + case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_NO_SYNCHRONIZATION: + AppendTextBuffer("No Synchronization"); + break; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_ASYNCHRONOUS: + AppendTextBuffer("Asynchronous"); + break; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_ADAPTIVE: + AppendTextBuffer("Adaptive"); + break; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_SYNCHRONOUS: + AppendTextBuffer("Synchronous"); + break; + } + AppendTextBuffer(", Usage Type = "); + + switch (USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE(EndpointDesc->bmAttributes)) + { + case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_DATA_ENDOINT: + AppendTextBuffer("Data Endpoint\r\n"); + break; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_FEEDBACK_ENDPOINT: + AppendTextBuffer("Feedback Endpoint\r\n"); + break; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_IMPLICIT_FEEDBACK_DATA_ENDPOINT: + AppendTextBuffer("Implicit Feedback Data Endpoint\r\n"); + break; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_RESERVED: + //@@TestCase A6.2 + //@@ERROR + //@@Descriptor Field - bmAttributes + //@@A reserved bit has a value + AppendTextBuffer("\r\n*!*ERROR: This value is Reserved\r\n"); + OOPS(); + break; + } + if (EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_ISOCHRONOUS_RESERVED_MASK) + { + AppendTextBuffer("\r\n*!*ERROR: Bits 7..6 are reserved and must be set to 0\r\n"); + OOPS(); + } + break; + + case USB_ENDPOINT_TYPE_BULK: + AppendTextBuffer("Bulk Transfer Type\r\n"); + if (EndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_BULK_RESERVED_MASK) + { + AppendTextBuffer("\r\n*!*ERROR: Bits 7..2 are reserved and must be set to 0\r\n"); + OOPS(); + } + break; + + case USB_ENDPOINT_TYPE_INTERRUPT: + + if (gDeviceSpeed != UsbSuperSpeed) + { + AppendTextBuffer("Interrupt Transfer Type\r\n"); + if (EndpointDesc->bmAttributes & USB_20_ENDPOINT_TYPE_INTERRUPT_RESERVED_MASK) + { + AppendTextBuffer("\r\n*!*ERROR: Bits 7..2 are reserved and must be set to 0\r\n"); + OOPS(); + } + } + else + { + AppendTextBuffer("Interrupt Transfer Type, Usage Type = "); + + switch (USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE(EndpointDesc->bmAttributes)) + { + case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_PERIODIC: + AppendTextBuffer("Periodic\r\n"); + break; + + case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_NOTIFICATION: + AppendTextBuffer("Notification\r\n"); + break; + + case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_RESERVED10: + case USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_RESERVED11: + AppendTextBuffer("\r\n*!*ERROR: This value is Reserved\r\n"); + OOPS(); + break; + } + + if (EndpointDesc->bmAttributes & USB_30_ENDPOINT_TYPE_INTERRUPT_RESERVED_MASK) + { + AppendTextBuffer("\r\n*!*ERROR: Bits 7..6 and 3..2 are reserved and must be set to 0\r\n"); + OOPS(); + } + + if (EpCompDescAvail) + { + if (EpCompDesc == NULL) + { + AppendTextBuffer("\r\n*!*ERROR: Endpoint Companion Descriptor missing\r\n"); + OOPS(); + } + else if (EpCompDesc->bmAttributes.Isochronous.SspCompanion == 1 && + SspIsochEpCompDesc == NULL) + { + AppendTextBuffer("\r\n*!*ERROR: SuperSpeedPlus Isoch Endpoint Companion Descriptor missing\r\n"); + OOPS(); + } + } + } + break; + } + } + else + { + AppendTextBuffer("\r\n"); + } + + //@@TestCase A6.3 + //@@Priority 1 + //@@Descriptor Field - bInterfaceNumber + //@@Question - Should we test to verify bInterfaceNumber is valid? + AppendTextBuffer("wMaxPacketSize: 0x%04X", + EndpointDesc->wMaxPacketSize); + if(gDoAnnotation) + { + switch (gDeviceSpeed) + { + case UsbSuperSpeed: + switch (epType) + { + case USB_ENDPOINT_TYPE_BULK: + if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_BULK_MAX_PACKET_SIZE) + { + AppendTextBuffer("\r\n*!*ERROR: SuperSpeed Bulk endpoints must be %d bytes\r\n", + USB_ENDPOINT_SUPERSPEED_BULK_MAX_PACKET_SIZE); + } + else + { + AppendTextBuffer("\r\n"); + } + break; + + case USB_ENDPOINT_TYPE_CONTROL: + if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_CONTROL_MAX_PACKET_SIZE) + { + AppendTextBuffer("\r\n*!*ERROR: SuperSpeed Control endpoints must be %d bytes\r\n", + USB_ENDPOINT_SUPERSPEED_CONTROL_MAX_PACKET_SIZE); + } + else + { + AppendTextBuffer("\r\n"); + } + break; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + + if (EpCompDesc != NULL) + { + if (EpCompDesc->bMaxBurst > 0) + { + if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE) + { + AppendTextBuffer("\r\n*!*ERROR: SuperSpeed isochronous endpoints must have wMaxPacketSize value of %d bytes\r\n", + USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE); + AppendTextBuffer(" when the SuperSpeed endpoint companion descriptor bMaxBurst value is greater than 0\r\n"); + } + else + { + AppendTextBuffer("\r\n"); + } + } + else if (EndpointDesc->wMaxPacketSize > USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE) + { + AppendTextBuffer("\r\n*!*ERROR: Invalid SuperSpeed isochronous maximum packet size\r\n"); + } + else + { + AppendTextBuffer("\r\n"); + } + } + else + { + AppendTextBuffer("\r\n"); + } + break; + + case USB_ENDPOINT_TYPE_INTERRUPT: + + if (EpCompDesc != NULL) + { + if (EpCompDesc->bMaxBurst > 0) + { + if (EndpointDesc->wMaxPacketSize != USB_ENDPOINT_SUPERSPEED_INTERRUPT_MAX_PACKET_SIZE) + { + AppendTextBuffer("\r\n*!*ERROR: SuperSpeed interrupt endpoints must have wMaxPacketSize value of %d bytes\r\n", + USB_ENDPOINT_SUPERSPEED_INTERRUPT_MAX_PACKET_SIZE); + AppendTextBuffer(" when the SuperSpeed endpoint companion descriptor bMaxBurst value is greater than 0\r\n"); + } + else + { + AppendTextBuffer("\r\n"); + } + } + else if (EndpointDesc->wMaxPacketSize > USB_ENDPOINT_SUPERSPEED_INTERRUPT_MAX_PACKET_SIZE) + { + AppendTextBuffer("\r\n*!*ERROR: Invalid SuperSpeed interrupt maximum packet size\r\n"); + } + else + { + AppendTextBuffer("\r\n"); + } + } + else + { + AppendTextBuffer("\r\n"); + } + break; + } + break; + + case UsbHighSpeed: + hsMaxPacket = (PUSB_HIGH_SPEED_MAXPACKET)&EndpointDesc->wMaxPacketSize; + + switch (epType) + { + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + case USB_ENDPOINT_TYPE_INTERRUPT: + switch (hsMaxPacket->HSmux) { + case 0: + if ((hsMaxPacket->MaxPacket < 1) || (hsMaxPacket->MaxPacket >1024)) + { + AppendTextBuffer("*!*ERROR: Invalid maximum packet size, should be between 1 and 1024\r\n"); + } + break; + + case 1: + if ((hsMaxPacket->MaxPacket < 513) || (hsMaxPacket->MaxPacket >1024)) + { + AppendTextBuffer("*!*ERROR: Invalid maximum packet size, should be between 513 and 1024\r\n"); + } + break; + + case 2: + if ((hsMaxPacket->MaxPacket < 683) || (hsMaxPacket->MaxPacket >1024)) + { + AppendTextBuffer("*!*ERROR: Invalid maximum packet size, should be between 683 and 1024\r\n"); + } + break; + + case 3: + AppendTextBuffer("*!*ERROR: Bits 12-11 set to Reserved value in wMaxPacketSize\r\n"); + break; + } + + AppendTextBuffer(" = %d transactions per microframe, 0x%02X max bytes\r\n", hsMaxPacket->HSmux + 1, hsMaxPacket->MaxPacket); + break; + + case USB_ENDPOINT_TYPE_BULK: + case USB_ENDPOINT_TYPE_CONTROL: + AppendTextBuffer(" = 0x%02X max bytes\r\n", hsMaxPacket->MaxPacket); + break; + } + break; + + case UsbFullSpeed: + // full speed + AppendTextBuffer(" = 0x%02X bytes\r\n", + EndpointDesc->wMaxPacketSize & 0x7FF); + break; + default: + // low or invalid speed + if (InterfaceClass == USB_DEVICE_CLASS_VIDEO) + { + AppendTextBuffer(" = Invalid bus speed for USB Video Class\r\n"); + } + else + { + AppendTextBuffer("\r\n"); + } + break; + } + } + else + { + AppendTextBuffer("\r\n"); + } + + if (EndpointDesc->wMaxPacketSize & 0xE000) + { + //@@TestCase A6.4 + //@@Priority 1 + //@@OTG Descriptor Field - wMaxPacketSize + //@@Attribute bits D7-2 reserved (reset to 0) + AppendTextBuffer("*!*ERROR: wMaxPacketSize bits 15-13 should be 0\r\n"); + } + + if (EndpointDesc->bLength == sizeof(USB_ENDPOINT_DESCRIPTOR)) + { + //@@TestCase A6.5 + //@@Priority 1 + //@@Descriptor Field - bInterfaceNumber + //@@Question - Should we test to verify bInterfaceNumber is valid? + 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); + } + + if (EpCompDesc != NULL) + { + DisplayEndointCompanionDescriptor(EpCompDesc, SspIsochEpCompDesc, epType); + } + if (SspIsochEpCompDesc != NULL) + { + DisplaySuperSpeedPlusIsochEndpointCompanionDescriptor(SspIsochEpCompDesc); + } + +} + +/***************************************************************************** + +DisplaySuperSpeedPlusIsochEndpointCompanionDescriptor() + +*****************************************************************************/ +VOID +DisplaySuperSpeedPlusIsochEndpointCompanionDescriptor( + _In_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochEpCompDesc + ) + { + AppendTextBuffer("\r\n ===>SuperSpeedPlus Isochronous Endpoint Companion Descriptor<===\r\n"); + + AppendTextBuffer("bLength: 0x%02X\r\n", + SspIsochEpCompDesc->bLength); + + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + SspIsochEpCompDesc->bDescriptorType); + + AppendTextBuffer("wReserved: 0x%02X\r\n", + SspIsochEpCompDesc->wReserved); + + if (gDoAnnotation) + { + if (SspIsochEpCompDesc->wReserved != 0) + { + AppendTextBuffer("*!*ERROR: field is reserved\r\n"); + } + } + + AppendTextBuffer("dwBytesPerInterval: 0x%04X\r\n", + SspIsochEpCompDesc->dwBytesPerInterval); +} + +/***************************************************************************** + +DisplayEndointCompanionDescriptor() + +*****************************************************************************/ +VOID +DisplayEndointCompanionDescriptor ( + _In_ PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR EpCompDesc, + _In_opt_ PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR SspIsochEpCompDesc, + _In_ UCHAR DescType + ) +{ + AppendTextBuffer("\r\n ===>SuperSpeed Endpoint Companion Descriptor<===\r\n"); + + AppendTextBuffer("bLength: 0x%02X\r\n", + EpCompDesc->bLength); + + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + EpCompDesc->bDescriptorType); + + AppendTextBuffer("bMaxBurst: 0x%02X\r\n", + EpCompDesc->bMaxBurst); + + AppendTextBuffer("bmAttributes: 0x%02X", + EpCompDesc->bmAttributes.AsUchar); + if(gDoAnnotation) + { + switch (DescType) + { + case USB_ENDPOINT_TYPE_CONTROL: + case USB_ENDPOINT_TYPE_INTERRUPT: + if (EpCompDesc->bmAttributes.AsUchar != 0) + { + AppendTextBuffer("*!*ERROR: Control/Interrupt SuperSpeed endpoints do not support streams\r\n"); + } + else + { + AppendTextBuffer("\r\n"); + } + break; + case USB_ENDPOINT_TYPE_BULK: + if(EpCompDesc->bmAttributes.Bulk.MaxStreams == 0) + { + AppendTextBuffer("The bulk endpoint does not define streams (MaxStreams == 0)\r\n"); + } + else + { + AppendTextBuffer(" = %d streams supported\r\n", 1 << EpCompDesc->bmAttributes.Bulk.MaxStreams); + } + + if (EpCompDesc->bmAttributes.Bulk.Reserved1 != 0) + { + AppendTextBuffer("*!*ERROR: bmAttributes bits 7-5 should be 0\r\n"); + } + break; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + if (EpCompDesc->bmAttributes.Isochronous.SspCompanion == 0) + { + if (EpCompDesc->bMaxBurst == 0 && + EpCompDesc->bmAttributes.Isochronous.Mult != 0) + { + AppendTextBuffer("*!*ERROR: SuperSpeed isochronous endpoint multiplier value should be zero if bMaxBurst is zero\r\n"); + } + else + { + AppendTextBuffer(" = %d maximum number of packets within a service interval\r\n", + (EpCompDesc->bmAttributes.Isochronous.Mult + 1)*(EpCompDesc->bMaxBurst + 1)); + + if (EpCompDesc->bmAttributes.Isochronous.Mult > USB_SUPERSPEED_ISOCHRONOUS_MAX_MULTIPLIER) + { + AppendTextBuffer("*!*ERROR: Maximum SuperSpeed isochronous endpoint multiplier value exceeded\r\n"); + } + } + } + else + { + if (EpCompDesc->bMaxBurst != 0) + { + AppendTextBuffer(" = %d maximum number of packets within a service interval\r\n", + (SspIsochEpCompDesc->dwBytesPerInterval*USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE) / + EpCompDesc->bMaxBurst); + } + } + + if (EpCompDesc->bmAttributes.Isochronous.Reserved2 != 0) + { + AppendTextBuffer("*!*ERROR: bmAttributes bits 7-2 should be 0\r\n"); + } + else + { + AppendTextBuffer("\r\n"); + } + break; + } + } + AppendTextBuffer("wBytesPerInterval: 0x%04X\r\n", + EpCompDesc->wBytesPerInterval); + + if (EpCompDesc->bmAttributes.Isochronous.SspCompanion == 1 && + EpCompDesc->wBytesPerInterval != 0x1) + { + AppendTextBuffer("*!*ERROR: SuperSpeed endpoint wBytesPerInterval value should be 1 if \ + SuperSpeedPlus Isoch companion descriptor is present\r\n"); + } +} + + +/***************************************************************************** + +DisplayHidDescriptor() + +*****************************************************************************/ + +VOID +DisplayHidDescriptor ( + PUSB_HID_DESCRIPTOR HidDesc + ) +{ + UCHAR i = 0; + + AppendTextBuffer("\r\n ===>HID Descriptor<===\r\n"); + + //length checked in DisplayConfigDesc() + + AppendTextBuffer("bLength: 0x%02X\r\n", + HidDesc->bLength); + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + HidDesc->bDescriptorType); + AppendTextBuffer("bcdHID: 0x%04X\r\n", + HidDesc->bcdHID); + AppendTextBuffer("bCountryCode: 0x%02X\r\n", + HidDesc->bCountryCode); + AppendTextBuffer("bNumDescriptors: 0x%02X\r\n", + HidDesc->bNumDescriptors); + + for (i=0; i<HidDesc->bNumDescriptors; i++) + { + if (HidDesc->OptionalDescriptors[i].bDescriptorType == 0x22) { + AppendTextBuffer("bDescriptorType: 0x%02X (Report Descriptor)\r\n", + HidDesc->OptionalDescriptors[i].bDescriptorType); + } + else { + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + HidDesc->OptionalDescriptors[i].bDescriptorType); + } + + AppendTextBuffer("wDescriptorLength: 0x%04X\r\n", + HidDesc->OptionalDescriptors[i].wDescriptorLength); + } +} + +/***************************************************************************** + +DisplayOTGDescriptor() + +*****************************************************************************/ + +VOID +DisplayOTGDescriptor ( + PUSB_OTG_DESCRIPTOR OTGDesc + ) +{ + AppendTextBuffer("\r\n ===>OTG Descriptor<===\r\n"); + + //length checked in DisplayConfigDesc() + + AppendTextBuffer("bLength: 0x%02X\r\n", + OTGDesc->bLength); + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + OTGDesc->bDescriptorType); + AppendTextBuffer("bmAttributes: 0x%02X", + OTGDesc->bmAttributes); + + switch (OTGDesc->bmAttributes) + { + case 0: + break; + case 1: + if(gDoAnnotation) + { + AppendTextBuffer(" -> SRP support\r\n"); + } + break; + case 2: + if(gDoAnnotation) + { + AppendTextBuffer(" -> HNP support\r\n"); + } + break; + case 3: + if(gDoAnnotation) + { + AppendTextBuffer(" -> SRP and HNP support\r\n"); + } + break; + default: + //@@TestCase A6.5 + //@@Priority 1 + //@@OTG Descriptor Field - bmAttributes + //@@Attribute bits D7-2 reserved (reset to 0) + AppendTextBuffer("*!*ERROR: bmAttributes bits 2-7 are reserved "\ + "(should be 0)\r\n"); + OOPS(); + break; + } +} + +/***************************************************************************** + +InitializeGlobalFlags () + +Initialize the global device flags in UVCView.h + +*****************************************************************************/ + +void +InitializePerDeviceSettings ( + PUSBDEVICEINFO info + ) +{ + // Save base address for this current device's info (including Configuration descriptor) + CurrentUSBDeviceInfo = info; + + // Initialize Configuration descriptor length + dwConfigLength = 0; + + // Save # of bytes from start of Configuration descriptor + // (Update this in the descriptor parsing routines) + dwConfigIndex = 0; + + // Flags used in dispvid.c to display default Frame descriptor for MJPEG, + // Uncompressed, Vendor and FrameBased Formats + g_chMJPEGFrameDefault = 0; + g_chUNCFrameDefault = 0; + g_chVendorFrameDefault = 0; + g_chFrameBasedFrameDefault = 0; + + // Spec version of UVC device + g_chUVCversion = 0; + + // Start and end address of the configuration descriptor and start of the string descriptors + g_pConfigDesc = NULL; + g_pStringDescs = NULL; + g_descEnd = NULL; + + // + // The GetConfigDescriptor() function in enum.c does not always work + // If that fails, the Configuration descriptor will be NULL + // and we can only display the device descriptor + // + CurrentConfigDesc = NULL; + if (NULL != info) + { + if (NULL != info->ConfigDesc) + { + CurrentConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1); + + // Save the LENGTH of the Config descriptor + // Note that IsIADDevice() saves the ADDRESS of the END of the Config desc + // Be aware of the difference + dwConfigLength = CurrentConfigDesc->wTotalLength; + } + } + + return; +} + +/***************************************************************************** + +IsUVCDevice() + +Return Spec version of UVC device + 0x0 = Not a UVC device + 0x10 = UVC 1.0 + 0x11 = UVC 1.1 + + *****************************************************************************/ + +UINT +IsUVCDevice ( + PUSBDEVICEINFO info + ) +{ + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc = NULL; + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + PUCHAR descEnd = NULL; + UINT uUVCversion = 0; + + // + // The GetConfigDescriptor() function in enum.c does not always work + // If that fails, the Configuration descriptor will be NULL + // and we can only display the device descriptor + // + if (NULL == info) + { + return 0; + } + if (NULL == info->ConfigDesc) + { + return 0; + } + ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1); + if (NULL == ConfigDesc) + { + return 0; + } + + // We've got a good Configuration Descriptor + commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; + descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; + + // walk through all the descriptors looking for the VIDEO_CONTROL_HEADER_UNIT + while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && + (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) + { + if ((commonDesc->bDescriptorType == CS_INTERFACE) && + (commonDesc->bLength > sizeof(VIDEO_CONTROL_HEADER_UNIT))) + { + // Right type, size. Now check subtype + PVIDEO_CONTROL_HEADER_UNIT pCSVC = NULL; + pCSVC = (PVIDEO_CONTROL_HEADER_UNIT) commonDesc; + if (VC_HEADER == pCSVC->bDescriptorSubtype) + { + // found the Class-specific VC Interface Header descriptor + uUVCversion = pCSVC->bcdVideoSpec; + // Save the version to global + g_chUVCversion = uUVCversion; + // We're done + break; + } + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + } + return (uUVCversion); +} + +/***************************************************************************** + +IsIADDevice() + +*****************************************************************************/ + +UINT +IsIADDevice ( + PUSBDEVICEINFO info + ) +{ + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc = NULL; + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + PUCHAR descEnd = NULL; + UINT uIADcount = 0; + + // + // The GetConfigDescriptor() function in enum.c does not always work + // If that fails, the Configuration descriptor will be NULL + // and we can only display the device descriptor + // + if (NULL == info) + { + return 0; + } + if (NULL == info->ConfigDesc) + { + return 0; + } + + ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1); + if (NULL != ConfigDesc) + { + commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; + descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; + } + + // return total number of IAD descriptors in this device configuration + while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && + (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) + { + if (commonDesc->bDescriptorType == USB_IAD_DESCRIPTOR_TYPE) + { + uIADcount++; + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + } + return (uIADcount); +} + +/***************************************************************************** + +DisplayIADDescriptor() + +*****************************************************************************/ + +VOID +DisplayIADDescriptor ( + PUSB_IAD_DESCRIPTOR IADDesc, + PSTRING_DESCRIPTOR_NODE StringDescs, + int nInterfaces, + DEVICE_POWER_STATE LatestDevicePowerState + ) +{ + AppendTextBuffer("\r\n ===>IAD Descriptor<===\r\n"); + + //length checked in DisplayConfigDesc() + + AppendTextBuffer("bLength: 0x%02X\r\n", + IADDesc->bLength); + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + IADDesc->bDescriptorType); + AppendTextBuffer("bFirstInterface: 0x%02X\r\n", + IADDesc->bFirstInterface); + AppendTextBuffer("bInterfaceCount: 0x%02X\r\n", + IADDesc->bInterfaceCount); + if (IADDesc->bInterfaceCount == 1) + { + //@@TestCase A7.1 + //@@Priority 1 + //@@Standard IAD Descriptor Field - bInterfaceCount + //@@The number of interfaces must be greater than 1 + AppendTextBuffer("*!*ERROR: bInterfaceCount must be greater than 1 \r\n"); + OOPS(); + } + if (nInterfaces < IADDesc->bFirstInterface + IADDesc->bInterfaceCount) + { + //@@TestCase A7.2 + //@@Priority 1 + //@@Standard IAD Descriptor Field - bInterfaceCount + //@@The total number of interfaces must be greater than or equal to + //@@ the highest linked interface number (base interface number plus count) + AppendTextBuffer("*!*ERROR: The total number of interfaces (%d) must be greater "\ + "than or equal to\r\n", + nInterfaces); + AppendTextBuffer(" the highest linked interface number (base %d + "\ + "count %d = %d)\r\n", + IADDesc->bFirstInterface, IADDesc->bInterfaceCount, + (IADDesc->bFirstInterface + IADDesc->bInterfaceCount)); + OOPS(); + } + AppendTextBuffer("bFunctionClass: 0x%02X", + IADDesc->bFunctionClass); + if (IADDesc->bFunctionClass == 0) + { + //@@TestCase A7.3 + //@@Priority 1 + //@@Standard IAD Descriptor Field - bFunctionClass + //@@"A value of zero is not allowed in this descriptor" + AppendTextBuffer("\r\n*!*ERROR: bFunctionClass contains an illegal value 0 \r\n"); + OOPS(); + } + + switch (IADDesc->bFunctionClass) + { + case USB_DEVICE_CLASS_AUDIO: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Audio Interface Class\r\n"); + } + + AppendTextBuffer("bFunctionSubClass: 0x%02X", + IADDesc->bFunctionSubClass); + + if(gDoAnnotation) + { + switch (IADDesc->bFunctionSubClass) + { + case USB_AUDIO_SUBCLASS_AUDIOCONTROL: + AppendTextBuffer(" -> Audio Control Interface SubClass\r\n"); + break; + + case USB_AUDIO_SUBCLASS_AUDIOSTREAMING: + AppendTextBuffer(" -> Audio Streaming Interface SubClass\r\n"); + break; + + case USB_AUDIO_SUBCLASS_MIDISTREAMING: + AppendTextBuffer(" -> MIDI Streaming Interface SubClass\r\n"); + break; + + default: + //@@TestCase A7.4 + //@@CAUTION + //@@Descriptor Field - bFunctionSubClass + //@@Invalid bFunctionSubClass + AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid bFunctionSubClass\r\n"); + OOPS(); + break; + } + } + break; + + case USB_DEVICE_CLASS_VIDEO: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Video Interface Class\r\n"); + } + + AppendTextBuffer("bFunctionSubClass: 0x%02X", + IADDesc->bFunctionSubClass); + + switch(IADDesc->bFunctionSubClass) + { + case SC_VIDEO_INTERFACE_COLLECTION: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Video Interface Collection\r\n"); + } + break; + + default: + //@@TestCase A7.5 + //@@CAUTION + //@@Descriptor Field - bFunctionSubClass + //@@Invalid bFunctionSubClass + AppendTextBuffer("\r\n*!*ERROR: This should be USB_VIDEO_SC_VIDEO_INTERFACE_COLLECTION %d\r\n", + SC_VIDEO_INTERFACE_COLLECTION); + OOPS(); + break; + } + break; + + case USB_DEVICE_CLASS_HUMAN_INTERFACE: + if(gDoAnnotation) + { + AppendTextBuffer(" -> HID Interface Class\r\n"); + } + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_DEVICE_CLASS_HUB: + if(gDoAnnotation) + { + AppendTextBuffer(" -> HUB Interface Class\r\n"); + } + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_DEVICE_CLASS_RESERVED: + //@@TestCase A7.6 + //@@CAUTION + //@@Descriptor Field - bFunctionClass + //@@A reserved USB Device Interface Class has been defined + AppendTextBuffer("\r\n*!*CAUTION: %d is a Reserved USB Device Interface Class\r\n", + USB_DEVICE_CLASS_RESERVED); + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_DEVICE_CLASS_COMMUNICATIONS: + AppendTextBuffer(" -> This is Communications (CDC Control) USB Device Interface Class\r\n"); + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_DEVICE_CLASS_MONITOR: + AppendTextBuffer(" -> This is a Monitor USB Device Interface Class*** (This may be obsolete)\r\n"); + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_DEVICE_CLASS_PHYSICAL_INTERFACE: + AppendTextBuffer(" -> This is a Physical Interface USB Device Interface Class\r\n"); + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_DEVICE_CLASS_POWER: + if(IADDesc->bFunctionSubClass == 1 && IADDesc->bFunctionProtocol == 1) + { + AppendTextBuffer(" -> This is an Image USB Device Interface Class\r\n"); + } + else + { + AppendTextBuffer(" -> This is a Power USB Device Interface Class (This may be obsolete)\r\n"); + } + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_DEVICE_CLASS_PRINTER: + AppendTextBuffer(" -> This is a Printer USB Device Interface Class\r\n"); + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_DEVICE_CLASS_STORAGE: + AppendTextBuffer(" -> This is a Mass Storage USB Device Interface Class\r\n"); + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_CDC_DATA_INTERFACE: + AppendTextBuffer(" -> This is a CDC Data USB Device Interface Class\r\n"); + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_CHIP_SMART_CARD_INTERFACE: + AppendTextBuffer(" -> This is a Chip/Smart Card USB Device Interface Class\r\n"); + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_CONTENT_SECURITY_INTERFACE: + AppendTextBuffer(" -> This is a Content Security USB Device Interface Class\r\n"); + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_DIAGNOSTIC_DEVICE_INTERFACE: + if(IADDesc->bFunctionSubClass == 1 && IADDesc->bFunctionProtocol == 1) + { + AppendTextBuffer(" -> This is a Reprogrammable USB2 Compliance Diagnostic Device USB Device\r\n"); + } + else + { + //@@TestCase A7.7 + //@@CAUTION + //@@Descriptor Field - bFunctionClass + //@@Invalid Interface Class + AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); + OOPS(); + } + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_WIRELESS_CONTROLLER_INTERFACE: + if(IADDesc->bFunctionSubClass == 1 && IADDesc->bFunctionProtocol == 1) + { + AppendTextBuffer(" -> This is a Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface\r\n"); + } + else + { + //@@TestCase A7.8 + //@@CAUTION + //@@Descriptor Field - bFunctionClass + //@@Invalid Interface Class + AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); + OOPS(); + } + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + case USB_APPLICATION_SPECIFIC_INTERFACE: + AppendTextBuffer(" -> This is an Application Specific USB Device Interface Class\r\n"); + + switch(IADDesc->bFunctionSubClass) + { + case 1: + AppendTextBuffer(" -> This is a Device Firmware Application Specific USB Device Interface Class\r\n"); + break; + case 2: + AppendTextBuffer(" -> This is an IrDA Bridge Application Specific USB Device Interface Class\r\n"); + break; + case 3: + AppendTextBuffer(" -> This is a Test & Measurement Class (USBTMC) Application Specific USB Device Interface Class\r\n"); + break; + default: + //@@TestCase A7.9 + //@@CAUTION + //@@Descriptor Field - bFunctionClass + //@@Invalid Interface Class + AppendTextBuffer("\r\n*!*CAUTION: This appears to be an invalid Interface Class\r\n"); + OOPS(); + } + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + + default: + if(gDoAnnotation) + { + AppendTextBuffer(" -> Interface Class Unknown to USBView\r\n"); + } + AppendTextBuffer("bFunctionSubClass: 0x%02X\r\n", + IADDesc->bFunctionSubClass); + break; + } + + AppendTextBuffer("bFunctionProtocol: 0x%02X", + IADDesc->bFunctionProtocol); + + // check protocol for our class + if ((IADDesc->bFunctionClass == USB_DEVICE_CLASS_VIDEO)) + { + // USB Video Class + if(IADDesc->bFunctionProtocol == PC_PROTOCOL_UNDEFINED) + { + // correct protocol for UVC + if(gDoAnnotation) + { + AppendTextBuffer(" -> PC_PROTOCOL_UNDEFINED protocol\r\n"); + } else { + AppendTextBuffer("\r\n"); + } + } else { + // incorrect protocol for UVC + //@@TestCase A7.10 + //@@WARNING + //@@Descriptor Field - iInterface + //@@bFunctionProtocol must be set to PC_PROTOCOL_UNDEFINED + AppendTextBuffer("*!*WARNING: must be set to PC_PROTOCOL_UNDEFINED %d for this class\r\n", + PC_PROTOCOL_UNDEFINED); + OOPS(); + } + } else { + AppendTextBuffer("\r\n"); + } + + AppendTextBuffer("iFunction: 0x%02X\r\n", + IADDesc->iFunction); + + if(gDoAnnotation) + { + if (IADDesc->iFunction) + { + DisplayStringDescriptor(IADDesc->iFunction, + StringDescs, + LatestDevicePowerState); + } + } +} + +/***************************************************************************** + +GetConfigurationSize() + +*****************************************************************************/ + +UINT +GetConfigurationSize ( + PUSBDEVICEINFO info + ) +{ + PUSB_CONFIGURATION_DESCRIPTOR + ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1); + PUSB_COMMON_DESCRIPTOR + commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; + PUCHAR + descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; + UINT uCount = 0; + + // return this device configuration's total sum of descriptor lengths + while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && + (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) + { + uCount += commonDesc->bLength; + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + } + return (uCount); +} + +/***************************************************************************** + +GetInterfaceCount() + +*****************************************************************************/ + +UINT +GetInterfaceCount ( + PUSBDEVICEINFO info + ) +{ + // how do we handle composite devices? + PUSB_CONFIGURATION_DESCRIPTOR + ConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(info->ConfigDesc + 1); + PUSB_COMMON_DESCRIPTOR + commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; + PUCHAR + descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; + UINT uCount = 0; + + // return this device configuration's total number of interface descriptors + while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && + (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) + { + if (commonDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) + { + uCount++; + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + } + return (uCount); +} + + +/***************************************************************************** + +DisplayUSEnglishStringDescriptor() + +*****************************************************************************/ + +VOID +DisplayUSEnglishStringDescriptor ( + UCHAR Index, + PSTRING_DESCRIPTOR_NODE USStringDescs, + DEVICE_POWER_STATE LatestDevicePowerState + ) +{ + ULONG nBytes = 0; + BOOLEAN FoundMatchingString = FALSE; + CHAR pString[512]; + + //@@DisplayUSEnglishStringDescriptor - String Descriptor + while (USStringDescs) + { + if (USStringDescs->DescriptorIndex == Index) + { + if (USStringDescs->LanguageID != 0x0409) + continue; + + FoundMatchingString = TRUE; + + AppendTextBuffer("English product name: \""); + memset(pString, 0, 512); + nBytes = WideCharToMultiByte( + CP_ACP, // CodePage + WC_NO_BEST_FIT_CHARS, + USStringDescs->StringDescriptor->bString, + (USStringDescs->StringDescriptor->bLength - 2) / 2, + pString, + 512, + NULL, // lpDefaultChar + NULL); // pUsedDefaultChar + if (nBytes) + AppendTextBuffer("%s\"\r\n", pString); + else + AppendTextBuffer("\"\r\n", pString); + return; + } + USStringDescs = USStringDescs->Next; + } + + //@@TestCase A8.1 + //@@WARNING + //@@Descriptor Field - string index + //@@No support for english + if (!FoundMatchingString) + { + if (LatestDevicePowerState == PowerDeviceD0) + { + AppendTextBuffer("*!*ERROR: No String Descriptor for index %d!\r\n", Index); + OOPS(); + } + else + { + AppendTextBuffer("String Descriptor for index %d not available while device is in low power state.\r\n", Index); + } + } + else + { + AppendTextBuffer("*!*ERROR: The index selected does not support English(US)\r\n"); + OOPS(); + } + return; + +} + + +/***************************************************************************** + +DisplayStringDescriptor() + +*****************************************************************************/ +VOID +DisplayStringDescriptor ( + UCHAR Index, + PSTRING_DESCRIPTOR_NODE StringDescs, + DEVICE_POWER_STATE LatestDevicePowerState + ) +{ + ULONG nBytes = 0; + BOOLEAN FoundMatchingString = FALSE; + PCHAR pStr = NULL; + CHAR pString[512]; + + //@@DisplayStringDescriptor - String Descriptor + + while (StringDescs) + { + if (StringDescs->DescriptorIndex == Index) + { + FoundMatchingString = TRUE; + if(gDoAnnotation) + { + pStr= GetLangIDString(StringDescs->LanguageID); + if(pStr) + { + AppendTextBuffer(" %s \"", + pStr); + } + else + { + //@@TestCase A9.1 + //@@WARNING + //@@Descriptor Field - string index + //@@The Language ID does not match any known languages supported by USB ORG + AppendTextBuffer("*!*WARNING: %d is an invalid Language ID\r\n", + Index); + OOPS(); + } + } + else + { + AppendTextBuffer(" 0x%04X: \"", StringDescs->LanguageID); + } + memset(pString, 0, 512); + + if (StringDescs->StringDescriptor->bLength > sizeof(USHORT)) + { + nBytes = WideCharToMultiByte( + CP_ACP, // CodePage + WC_NO_BEST_FIT_CHARS, + StringDescs->StringDescriptor->bString, + (StringDescs->StringDescriptor->bLength - 2) / 2, + pString, + 512, + NULL, // lpDefaultChar + NULL); // pUsedDefaultChar + if (nBytes) + { + AppendTextBuffer("%s\"\r\n", pString); + } + else + { + AppendTextBuffer("\"\r\n"); + } + } + else + { + // + // This is NULL string which is invalid + // + AppendTextBuffer("\"\r\n"); + } + } + StringDescs = StringDescs->Next; + } + + if (!FoundMatchingString) + { + if (LatestDevicePowerState == PowerDeviceD0) + { + AppendTextBuffer("*!*ERROR: No String Descriptor for index %d!\r\n", Index); + OOPS(); + } + else + { + AppendTextBuffer("String Descriptor for index %d not available while device is in low power state.\r\n", Index); + } + } +} + +/***************************************************************************** + +DisplayUnknownDescriptor() + +*****************************************************************************/ +VOID +DisplayUnknownDescriptor ( + PUSB_COMMON_DESCRIPTOR CommonDesc + ) +{ + AppendTextBuffer("\r\n ===>Descriptor Hex Dump<===\r\n"); + + AppendTextBuffer("bLength: 0x%02X\r\n", + CommonDesc->bLength); + + AppendTextBuffer("bDescriptorType: 0x%02X\r\n", + CommonDesc->bDescriptorType); + + DisplayRemainingUnknownDescriptor((PUCHAR)CommonDesc, 0, CommonDesc->bLength); +} + +VOID +DisplayRemainingUnknownDescriptor( + PUCHAR DescriptorData, + ULONG Start, + ULONG Stop + ) +{ + ULONG i; + + for (i = Start; i < Stop; i++) + { + AppendTextBuffer("%02X ", + DescriptorData[i]); + + if (i % 16 == 15) + { + AppendTextBuffer("\r\n"); + } + } + + if (i % 16 != 0) + { + AppendTextBuffer("\r\n"); + } +} + + + +/***************************************************************************** + +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. + +*****************************************************************************/ + +PCHAR +GetVendorString ( + USHORT idVendor + ) +{ + PUSBVENDORID vendorID = NULL; + + if (idVendor == 0x0000) + { + return NULL; + } + + vendorID = USBVendorIDs; + + while (vendorID->usVendorID != 0x0000) + { + if (vendorID->usVendorID == idVendor) + { + break; + } + vendorID++; + } + + return (vendorID->szVendor); +} + +/***************************************************************************** + +GetLangIDString() + +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. + +*****************************************************************************/ + +PCHAR +GetLangIDString ( + USHORT idLang + ) +{ + PUSBLANGID langID = NULL; + + if (idLang != 0x0000) + { + langID = USBLangIDs; + + while (langID->usLangID != 0x0000) + { + if (langID->usLangID == idLang) + { + return (langID->szLanguage); + } + langID++; + } + } + + return NULL; +} + +/***************************************************************************** + +GetStringFromList() + +PSTRINGLIST slList, - pointer to STRINGLIST used + +ULONG ulNumElements, - + number of elements in that STRINGLIST calc before call with sizeof(slList) / sizeof(STRINGLIST), +ULONG or ULONGLONG (if H264_SUPPORT is defined)ulFlag - - flag to look for +PCHAR szDefault - string to return if no match + +Return a string associated with a value from a stringtable. + +example: + GetStringFromList(slPowerState, + sizeof(slPowerState) / sizeof(STRINGLIST), + pUPI->SystemState, + "Invalid Power State") + +*****************************************************************************/ + +PCHAR +GetStringFromList( + PSTRINGLIST slList, + ULONG ulNumElements, +#ifdef H264_SUPPORT + ULONGLONG ulFlag, +#else + ULONG ulFlag, +#endif + _In_ PCHAR szDefault + ) +{ + // ulIndex is zero based, but ulNumElements is 1 based + // subtract 1 from ulNumElements so that are same base +#ifdef H264_SUPPORT + ULONGLONG ulIndex = 0; +#else + ULONG ulIndex = 0; +#endif + ulNumElements--; + + + for ( ; ulIndex <= ulNumElements; ulIndex++) + { + if (ulFlag == slList[ulIndex].ulFlag) + { + return (slList[ulIndex].pszString); + } + } + + return szDefault; +} + |
