Sample Code
Windows Driver Samples/ USBView sample application/ C++/ display.c/
/*++ 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_ UCHAR InterfaceClass, _In_ BOOLEAN EpCompDescAvail ); VOID DisplayEndointCompanionDescriptor ( PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR EpCompDesc, 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) { AppendTextBuffer(" (is %sSuperSpeed or higher capable)\r\n", ConnectionInfoV2->Flags.DeviceIsSuperSpeedCapableOrHigher ? "" : "not "); } else { AppendTextBuffer("\r\n"); } } else { AppendTextBuffer("\r\n"); } gDeviceSpeed = UsbFullSpeed; break; case UsbHighSpeed: if(gDoAnnotation) { AppendTextBuffer(" -> Device Bus Speed: High"); if (ConnectionInfoV2 != NULL) { AppendTextBuffer(" (is %sSuperSpeed or higher capable)\r\n", ConnectionInfoV2->Flags.DeviceIsSuperSpeedCapableOrHigher ? "" : "not "); } else { AppendTextBuffer("\r\n"); } } else { AppendTextBuffer("\r\n"); } gDeviceSpeed = UsbHighSpeed; break; case UsbSuperSpeed: if(gDoAnnotation) { AppendTextBuffer(" -> Device Bus Speed: Super\r\n"); } 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, 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; //@@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); } DisplayEndpointDescriptor((PUSB_ENDPOINT_DESCRIPTOR)commonDesc, epCompDesc, bInterfaceClass, TRUE); 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 ? 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_ 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 && EpCompDesc == NULL) { AppendTextBuffer("\r\n*!*ERROR: 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, epType); } } /***************************************************************************** DisplayEndointCompanionDescriptor() *****************************************************************************/ VOID DisplayEndointCompanionDescriptor ( PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR EpCompDesc, 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: AppendTextBuffer(" = %d maximum number of packets within a service interval\r\n", (EpCompDesc->bmAttributes.Isochronous.Mult+1)*EpCompDesc->bMaxBurst); if (EpCompDesc->bmAttributes.Isochronous.Mult > USB_SUPERSPEED_ISOCHRONOUS_MAX_MULTIPLIER) { AppendTextBuffer("*!*ERROR: Maximum SuperSpeed isochronous endpoint multiplier value exceeded\r\n"); } 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); } /***************************************************************************** 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; }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials