diff options
Diffstat (limited to 'usb/usbview/xmlhelper.cpp')
| -rw-r--r-- | usb/usbview/xmlhelper.cpp | 3058 |
1 files changed, 3058 insertions, 0 deletions
diff --git a/usb/usbview/xmlhelper.cpp b/usb/usbview/xmlhelper.cpp new file mode 100644 index 00000000..4221aeb0 --- /dev/null +++ b/usb/usbview/xmlhelper.cpp @@ -0,0 +1,3058 @@ +/*++ + + Copyright (c) 1997-2011 Microsoft Corporation + + Module Name: + + XMLHELPER.CPP + +Abstract: + +This source file contains helper APIs for reading writing XML + +Environment: + +user mode + +Revision History: + +05-05-11 : created + +--*/ + +/***************************************************************************** + I N C L U D E S + *****************************************************************************/ +#include "uvcview.h" +#include "h264.h" +#include "xmlhelper.h" + +// usbschema.hpp is autogenerated from schema during build PASS0 +#include "usbschema.hpp" + +// Include code analysis suppressions +#include "codeanalysis.h" + +/***************************************************************************** + D E F I N E S + *****************************************************************************/ +#define COBJMACROS + +#define PACHAR_TO_STRING(X) ((X != NULL)? gcnew String(Marshal::PtrToStringAnsi((IntPtr) X )):nullptr) +#define PWCHAR_TO_STRING(X) ((X != NULL)? gcnew String(Marshal::PtrToStringUni((IntPtr) X )):nullptr) + +#define MAX_STRING_DESCRIPTOR_LENGTH 512 +#define STRING_DESCRIPTOR_EN_LANGUAGE_ID 0x0409 +#define DEVICE_DESCRIPTOR_LENGTH 18 + +#define SERVICE_EHCI "usbehci" +#define SERVICE_XHCI "usbxhci" +#define SERVICE_OHCI "usbohci" +#define SERVICE_UHCI "usbuhci" + +#define USB_1_1 "USB 1.1" +#define USB_2_0 "USB 2.0" +#define USB_3_0 "USB 3.0" +#define USB_GENERIC "USB GENERIC (UNKNOWN)" + +/***************************************************************************** + N A M E S P A C E S + *****************************************************************************/ + +using namespace System; +using namespace System::IO; +using namespace System::Runtime::InteropServices; +using namespace System::Collections; +using namespace Microsoft::Kits::Samples::Usb; + + +/***************************************************************************** + G L O B A L S + *****************************************************************************/ + +namespace Microsoft +{ + namespace Kits + { + namespace Samples + { + namespace Usb + { + public ref class XmlGlobal sealed + { + private: + static XmlGlobal ^ pInstance = gcnew XmlGlobal(); + + // Empty private constructor + XmlGlobal() + { + } + + public: + // + // Globals for XML view + // + property UvcViewAll ^ ViewAll; + property bool XmlViewInitialized; + + // + // Stack of parents of a given node. This is used for finding + // where a given object should be added + // + +#if CODE_ANALYSIS + // ParentStack need not be constant since we will only have one instance of this object + [SuppressMessage("Microsoft.Usage", "CA2211:NonConstantFieldsShouldNotBeVisible")] +#endif + static Stack ^ ParentStack = gcnew Stack(); + + static XmlGlobal ^ Instance() + { + return pInstance; + } + }; + }; + }; + }; +}; + +#define gXmlView ((XmlGlobal::Instance())->ViewAll->UvcView) +#define gXmlViewInitialized ((XmlGlobal::Instance())->XmlViewInitialized) +#define gXmlStack ((XmlGlobal::Instance())->ParentStack) + +/***************************************************************************** + D E C L A R A T I O N S + *****************************************************************************/ + +String ^ XmlGetStringDescriptor(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc, bool enOnly); +void XmlAddHostControllerPowerMapping( UsbHCPowerStateMappingType ^xmlPwrInfo, PUSB_POWER_INFO usbHCPowerInfo); +String ^ XmlGetDeviceClassString(UCHAR deviceClass); +void XmlAddHostControllerPowerMapping(UsbHCPowerStateMappingType ^xmlPwrInfo, PUSB_POWER_INFO usbHCPowerInfo); +void XmlAddHub30Descriptor(Hub30DescriptorType ^hub30Desc, PUSB_30_HUB_DESCRIPTOR hub30Descriptor); +void XmlAddHubDescriptor(HubDescriptorType ^hubDesc, PUSB_HUB_DESCRIPTOR hubDescriptor); +void XmlAddPortConnectorProps(PortConnectorType ^portXmlProps, PUSB_PORT_CONNECTOR_PROPERTIES portProps); +void XmlAddHubCharacteristics(HubInformationType ^hubI, WORD hubChar); +HRESULT XmlAddHubNodeInformation(HubNodeInformationType ^ni, PUSB_NODE_INFORMATION nodeInfo); +HRESULT XmlAddHubInformationEx(HubInformationExType ^ex, PUSB_HUB_INFORMATION_EX hubInfoEx); +HRESULT XmlAddHubCapabilitiesEx(HubCapabilitiesExType ^ex, USB_HUB_CAPABILITIES_EX hubCapEx); +ExternalHubType ^ AddExternalHub(Object ^parent); +NoDeviceType ^ AddDisconnectedPort(Object ^parent); +UsbDeviceType ^ AddUsbDevice(Object ^parent); +void XmlAddEndpointDescriptor( + EndpointDescriptorType ^usbXmlEndpointDescriptor, + PUSB_ENDPOINT_DESCRIPTOR endPointDescriptor, + UCHAR connectionSpeed); +void XmlAddPipeInformation( + array< UsbPipeInfoType ^> ^ usbXmlPipeInfoList, + PUSB_PIPE_INFO pipeInfo, + ULONG numPipes, + UCHAR connectionSpeed); +void XmlAddUsbDeviceDescriptor( + UsbDeviceDescriptorType ^usbXmlDeviceDescriptor, + PUSB_DEVICE_DESCRIPTOR usbDeviceDescriptor); +void XmlAddConfigurationDescriptor( + UsbConfigurationDescriptorType ^ confXmlDesc, + PUSBDEVICEINFO deviceInfo, + PUSB_CONFIGURATION_DESCRIPTOR configDesc, + PSTRING_DESCRIPTOR_NODE stringDesc); +void XmlAddDeviceQualDescriptor( + UsbDeviceQualifierDescriptorType ^ qualXmlDesc, + PUSB_DEVICE_QUALIFIER_DESCRIPTOR qualDesc); +void XmlAddDeviceConfiguration( + UsbDeviceConfigurationType ^ confXmlDesc, + PUSBDEVICEINFO deviceInfo, + PUSB_CONFIGURATION_DESCRIPTOR configDesc, + PSTRING_DESCRIPTOR_NODE stringDesc, + int numInterfaces); +void XmlAddConnectionInfoSt( + NodeConnectionInfoExStructType ^xmlConnectionInfoSt, + PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, + PDEVICE_INFO_NODE pNode); +String ^ XmlGetLangIdString(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc); +String ^ XmlGetStringDescriptor(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc, bool enOnly); +String ^ XmlGetDeviceClassString(UCHAR deviceClass); +bool XmlAddDeviceClassDetails( + UsbDeviceClassDetailsType ^ deviceDetails, + PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, + PUSBDEVICEINFO deviceInfo); +void XmlAddConnectionInfo( + NodeConnectionInfoExType ^xmlConnectionInfo, + PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, + PUSBDEVICEINFO deviceInfo, + PSTRING_DESCRIPTOR_NODE stringDesc, + PDEVICE_INFO_NODE pNode); +void XmlAddHidDescriptor( + UsbDeviceHidDescriptorType ^ hidXmlDesc, + PUSB_HID_DESCRIPTOR hidDesc); +void XmlAddDeviceInterfaceDescriptor( + UsbDeviceInterfaceDescriptorType ^ ifXmlDesc, + PUSB_INTERFACE_DESCRIPTOR ifDesc, + PSTRING_DESCRIPTOR_NODE stringDesc); +void XmlAddOTGDescriptor( + UsbDeviceOTGDescriptorType ^ otgXmlDesc, + PUSB_OTG_DESCRIPTOR otgDesc); +void XmlAddIADDescriptor( + UsbDeviceIADDescriptorType ^ iadXmlDesc, + PUSB_IAD_DESCRIPTOR iadDesc, + PSTRING_DESCRIPTOR_NODE stringDesc, + int nInterfaces); +array < UsbDeviceConfigurationType ^> ^ XmlGetConfigDescriptors( + PUSBDEVICEINFO deviceInfo, + PUSB_CONFIGURATION_DESCRIPTOR configDescs, + PSTRING_DESCRIPTOR_NODE stringDesc); +UsbBosDescriptorType ^ XmlGetBosDescriptor(PUSB_BOS_DESCRIPTOR bosDesc); +UsbDeviceClassType ^ XmlGetDeviceClass(UCHAR deviceClass, UCHAR deviceSubClass, UCHAR deviceProtocol); +UsbDeviceUnknownDescriptorType ^ XmlGetUnknownDescriptor( + PUSB_COMMON_DESCRIPTOR unknownDesc + ); +UsbUsb20ExtensionDescriptorType ^ XmlGetUsb20CapabilityExtensionDescriptor( + PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR capDesc + ); +UsbSuperSpeedExtensionDescriptorType ^ XmlGetSuperSpeedCapabilityExtensionDescriptor( + PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR capDesc + ); +UsbDispContIdCapExtDescriptorType ^ XmlGetContainerIdCapabilityExtensionDescriptor( + PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR capDesc + ); + +/***************************************************************************** + D E F I N I T I O N S + *****************************************************************************/ + +/***************************************************************************** + XmlNotifyEndOfNodeList + + This function is called back by WalkTreeTopDown() function to notify us + that there are no more children to add for the current parent + + *****************************************************************************/ +VOID XmlNotifyEndOfNodeList(PVOID pContext) +{ + UNREFERENCED_PARAMETER(pContext); + + if (gXmlStack != nullptr && gXmlStack->Count > 0) + { + // Remove the last parent on the stack + gXmlStack->Pop(); + } +} + +/***************************************************************************** + + XmlAddHostControllerPowerMapping() + + add power info to xml structure + *****************************************************************************/ +void XmlAddHostControllerPowerMapping(UsbHCPowerStateMappingType ^xmlPwrInfo, PUSB_POWER_INFO usbHCPowerInfo) +{ + int i, powerState; + PUSB_POWER_INFO pUPI = usbHCPowerInfo; + UsbHCPowerStateType ^ pwrState = nullptr; + + xmlPwrInfo->PowerMap = gcnew array<UsbHCPowerStateType ^> (WdmUsbPowerSystemShutdown); + + for(i = 0, powerState = WdmUsbPowerSystemWorking; powerState < WdmUsbPowerSystemShutdown; i++, powerState++, pUPI++) + { + xmlPwrInfo->PowerMap[i] = gcnew UsbHCPowerStateType(); + pwrState = xmlPwrInfo->PowerMap[i]; + pwrState->SystemState = PACHAR_TO_STRING(GetPowerStateString(pUPI->SystemState)); + pwrState->HostControllerState = PACHAR_TO_STRING(GetPowerStateString(pUPI->HcDevicePowerState)); + pwrState->HubState = PACHAR_TO_STRING(GetPowerStateString(pUPI->RhDevicePowerState)); + pwrState->CanWakeUp = pUPI->CanWakeup? true:false; + pwrState->IsPowered = pUPI->IsPowered? true:false; + } + + xmlPwrInfo->LastSleepState = PACHAR_TO_STRING(GetPowerStateString(pUPI->LastSystemSleepState)); + return; +} + +/***************************************************************************** + + XmlAddHostController() + + Add an host controller to XML view + *****************************************************************************/ + +HRESULT XmlAddHostController(PSTR hcName, PUSBHOSTCONTROLLERINFO hcInfo) +{ + HRESULT hr = S_OK; + + UNREFERENCED_PARAMETER(hcName); + + HostControllerType ^ hc = nullptr; + // + // Check if the USB Tree array has been initialized + // It would have been great if XSD had a way of generating a list instead of array, but it does not + // So we have to do array.Resize everytime + // + if (gXmlView->UsbTree == nullptr) + { + // This is the first time we are being called, initialize the array with 1 element + gXmlView->UsbTree = gcnew array<HostControllerType ^>(1); + gXmlView->UsbTree[0] = gcnew HostControllerType(); + hc = gXmlView->UsbTree[0]; + } + else + { + // Create a new array every time as Array.Resize does not seem to work in our case (CLI) + // We do this using ArrayList. + ArrayList ^hcList = gcnew ArrayList; + hcList->AddRange(gXmlView->UsbTree); + hc = gcnew HostControllerType(); + hcList->Add(hc); + gXmlView->UsbTree = reinterpret_cast<array<HostControllerType ^>^> (hcList->ToArray(HostControllerType::typeid)); + } + + if (hc != nullptr) + { + ULONG debugPort = 0; + + UsbHCDeviceInfoType ^ ci = nullptr; + UsbHCPowerStateMappingType ^ pm = nullptr; + + if (NULL != hcInfo->UsbDeviceProperties) + { + hc->HwId = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->HwId); + hc->DeviceId = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->DeviceId); + hc->ServiceName = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->Service); + hc->DeviceName = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->DeviceDesc); + hc->DeviceClass = PACHAR_TO_STRING(hcInfo->UsbDeviceProperties->DeviceClass); + + if (_stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_OHCI) == 0) + { + hc->UsbProtocol = gcnew String(USB_1_1); + } + else if(_stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_EHCI) == 0 || + _stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_UHCI) == 0) + { + hc->UsbProtocol = gcnew String(USB_2_0); + } + else if (_stricmp(hcInfo->UsbDeviceProperties->Service, SERVICE_XHCI) == 0) + { + hc->UsbProtocol = gcnew String(USB_3_0); + } + else + { + USB_CONTROLLER_FLAVOR flavor = hcInfo->ControllerInfo->ControllerFlavor; + + // If protocol lookup failed based on service name, try Controller flavor + if(NULL != hcInfo->ControllerInfo) + { + if(flavor == USB_HcGeneric) + { + hc->UsbProtocol = gcnew String(USB_GENERIC); + } + else if(flavor >= OHCI_Generic && flavor < UHCI_Generic) + { + hc->UsbProtocol = gcnew String(USB_1_1); + } + else if(flavor >= UHCI_Generic && flavor < EHCI_Generic) + { + hc->UsbProtocol = gcnew String(USB_2_0); + } + else if(flavor >= EHCI_Generic) + { + hc->UsbProtocol = gcnew String(USB_3_0); + } + } + } + } + + hc->ControllerInfo = gcnew UsbHCDeviceInfoType(); + hc->PowerMapping = gcnew UsbHCPowerStateMappingType(); + ci = hc->ControllerInfo; + pm = hc->PowerMapping; + + ci->VendorId = hcInfo->VendorID; + ci->DeviceId = hcInfo->DeviceID; + ci->DriverKey = PACHAR_TO_STRING(hcInfo->DriverKey); + ci->SubSysId = hcInfo->SubSysID; + ci->Revision = hcInfo->Revision; + + if(NULL != hcInfo->ControllerInfo) + { + ci->NumberOfRootPorts = hcInfo->ControllerInfo->NumberOfRootPorts; + ci->ControllerFlavor = hcInfo->ControllerInfo->ControllerFlavor; + ci->PortSwitchingEnabled = (hcInfo->ControllerInfo->HcFeatureFlags & USB_HC_FEATURE_FLAG_PORT_POWER_SWITCHING)? true: false; + ci->SelectiveSuspendEnabled = (hcInfo->ControllerInfo->HcFeatureFlags & USB_HC_FEATURE_FLAG_SEL_SUSPEND)? true: false; + ci->LegacyBios = (hcInfo->ControllerInfo->HcFeatureFlags & USB_HC_FEATURE_LEGACY_BIOS)? true: false; + ci->ControllerFlavorString = PACHAR_TO_STRING(GetControllerFlavorString(hcInfo->ControllerInfo->ControllerFlavor)); + } + + // Add power mappings + XmlAddHostControllerPowerMapping(pm, (PUSB_POWER_INFO) (&(hcInfo->USBPowerInfo[0]))); + + // Add debug port + debugPort = GetEhciDebugPort(hcInfo->VendorID, hcInfo->DeviceID); + if (debugPort > 0) + { + ci->DebugPort = debugPort; + } + + gXmlStack->Push(hc); + + } + else + { + hr = E_FAIL; + } + + return hr; +} + +/***************************************************************************** + + XmlAddHub30Descriptor() + + Adds the hub 3.0 descriptor to the given hub object + *****************************************************************************/ +void XmlAddHub30Descriptor(Hub30DescriptorType ^hub30Desc, PUSB_30_HUB_DESCRIPTOR hub30Descriptor) +{ + + if (nullptr != hub30Desc && NULL != hub30Descriptor) + { + hub30Desc->Length = hub30Descriptor->bLength; + hub30Desc->DescriptorType = hub30Descriptor->bDescriptorType; + hub30Desc->NumberOfPorts = hub30Descriptor->bNumberOfPorts; + hub30Desc->HubCharacteristics = hub30Descriptor->wHubCharacteristics; + hub30Desc->PowerOntoPowerGood = hub30Descriptor->bPowerOnToPowerGood; + hub30Desc->HubControlCurrent = hub30Descriptor->bHubControlCurrent; + hub30Desc->HubHdrDecLat = hub30Descriptor->bHubHdrDecLat; + hub30Desc->DeviceRemovable = hub30Descriptor->DeviceRemovable; + } +} + +/***************************************************************************** + + XmlAddHubDescriptor() + + Adds the hub descriptor to the given hub object + *****************************************************************************/ +void XmlAddHubDescriptor(HubDescriptorType ^hubDesc, PUSB_HUB_DESCRIPTOR hubDescriptor) +{ + if (nullptr != hubDesc && NULL != hubDescriptor) + { + hubDesc->DescriptorLength = hubDescriptor->bDescriptorLength; + hubDesc->DescriptorType = hubDescriptor->bDescriptorType; + hubDesc->NumberOfPorts = hubDescriptor->bNumberOfPorts; + hubDesc->PowerOntoPowerGood = hubDescriptor->bPowerOnToPowerGood; + hubDesc->HubControlCurrent = hubDescriptor->bHubControlCurrent; + } +} + +/***************************************************************************** + + XmlAddPortConnectorProps() + + Adds the port connector properties to XML file + *****************************************************************************/ +void XmlAddPortConnectorProps(PortConnectorType ^portXmlProps, PUSB_PORT_CONNECTOR_PROPERTIES portProps) +{ + if (NULL != portProps) + { + portXmlProps->UsbPortProperties = gcnew UsbPortPropertiesType(); + + portXmlProps->ConnectionIndex = portProps->ConnectionIndex; + portXmlProps->ActualLength = portProps->ActualLength; + portXmlProps->CompanionIndex = portProps->CompanionIndex; + portXmlProps->CompanionPortNumber = portProps->CompanionPortNumber; + portXmlProps->CompanionHubSymbolicLinkName = PWCHAR_TO_STRING(portProps->CompanionHubSymbolicLinkName); + + portXmlProps->UsbPortProperties->PortIsUserConnectable = portProps->UsbPortProperties.PortIsUserConnectable? true:false; + portXmlProps->UsbPortProperties->PortIsDebugCapable = portProps->UsbPortProperties.PortIsDebugCapable? true:false; + } + return; +} + +/***************************************************************************** + + XmlAddConnectionInfoV2() + + Adds the V2 connection info structure + *****************************************************************************/ +void XmlAddConnectionInfoV2(NodeConnectionInfoExV2Type ^ connectionXmlInfo, PUSB_NODE_CONNECTION_INFORMATION_EX_V2 connectionInfo) +{ + if (NULL != connectionInfo) + { + connectionXmlInfo->ConnectionIndex = connectionInfo->ConnectionIndex; + connectionXmlInfo->Length = connectionInfo->Length; + + connectionXmlInfo->Usb110Supported = connectionInfo->SupportedUsbProtocols.Usb110? true:false; + connectionXmlInfo->Usb200Supported = connectionInfo->SupportedUsbProtocols.Usb200? true:false; + connectionXmlInfo->Usb300Supported = connectionInfo->SupportedUsbProtocols.Usb300? true:false; + + connectionXmlInfo->DeviceIsOperatingAtSuperSpeedOrHigher = + connectionInfo->Flags.DeviceIsOperatingAtSuperSpeedOrHigher; + + connectionXmlInfo->DeviceIsSuperSpeedCapableOrHigher = + connectionInfo->Flags.DeviceIsSuperSpeedCapableOrHigher; + + connectionXmlInfo->DeviceIsOperatingAtSuperSpeedPlusOrHigher = + connectionInfo->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher; + + connectionXmlInfo->DeviceIsSuperSpeedPlusCapableOrHigher = + connectionInfo->Flags.DeviceIsSuperSpeedPlusCapableOrHigher; + + } + return; +} + +/***************************************************************************** + + XmlAddHubCharacteristics() + + Adds the hub characteristics to the given hub object + *****************************************************************************/ +void XmlAddHubCharacteristics(HubInformationType ^hubI, WORD hubChar) +{ + HubCharacteristicsType ^hubC = nullptr; + + hubI->HubCharacteristics = gcnew HubCharacteristicsType(); + hubC = hubI->HubCharacteristics; + hubC->HubCharacteristicsValue = hubChar; + switch(hubChar & 0x3) + { + case 0x0: + hubC->PowerSwitching = gcnew String("Ganged"); + break; + case 0x1: + hubC->PowerSwitching = gcnew String("Individual"); + break; + case 0x2: + case 0x3: + hubC->PowerSwitching = gcnew String("None"); + break; + default: + hubC->PowerSwitching = gcnew String("Unknown"); + } + + hubC->CompoundDevice = (hubChar & 0x4)? true:false; + + switch(hubChar & 0x18) + { + case 0x0: + hubC->OverCurrentProtection = gcnew String("Global"); + break; + case 0x8: + hubC->OverCurrentProtection = gcnew String("Individual"); + break; + case 0x10: + case 0x18: + hubC->OverCurrentProtection = gcnew String("No protection, bus power only"); + break; + default: + hubC->OverCurrentProtection = gcnew String("Unknown"); + } +} + +/***************************************************************************** + + XmlAddHubNodeInformation() + + Adds the node information to the hub object + *****************************************************************************/ +HRESULT XmlAddHubNodeInformation(HubNodeInformationType ^ni, PUSB_NODE_INFORMATION nodeInfo) +{ + PUSB_HUB_INFORMATION hubInfo = NULL; + + if (NULL == nodeInfo) + { + return E_FAIL; + } + + hubInfo = &(nodeInfo->u.HubInformation); + ni->HubNode = static_cast<HubNodeType> (nodeInfo->NodeType); + + ni->HubInformation = gcnew HubInformationType(); + ni->HubInformation->IsRootHub = true; + ni->HubInformation->IsBusPowered = hubInfo->HubIsBusPowered? true:false; + + // Add hub characteristics + XmlAddHubCharacteristics(ni->HubInformation, hubInfo->HubDescriptor.wHubCharacteristics); + // Add descriptor + ni->HubInformation->HubDescriptor = gcnew HubDescriptorType(); + XmlAddHubDescriptor(ni->HubInformation->HubDescriptor, &(hubInfo->HubDescriptor)); + + return S_OK; +} + +/***************************************************************************** + + XmlAddHubInformation() + + Adds the node information to the hub object + *****************************************************************************/ +HRESULT XmlAddHubInformationEx(HubInformationExType ^ex, PUSB_HUB_INFORMATION_EX hubInfoEx) +{ + HubDescriptorType ^hubDesc = nullptr; + Hub30DescriptorType ^hub30Desc = nullptr; + + if (NULL == hubInfoEx) + { + return E_FAIL; + } + + ex->HubType = static_cast<HubTypeType> (hubInfoEx->HubType); + ex->HighestPortNumber = hubInfoEx->HighestPortNumber; + switch(hubInfoEx->HubType) + { + case UsbRootHub: + case Usb20Hub: + ex->HubDescriptor = hubDesc = gcnew HubDescriptorType(); + XmlAddHubDescriptor(hubDesc, &(hubInfoEx->u.UsbHubDescriptor)); + break; + case Usb30Hub: + ex->Hub30Descriptor = hub30Desc = gcnew Hub30DescriptorType(); + XmlAddHub30Descriptor(hub30Desc, &(hubInfoEx->u.Usb30HubDescriptor)); + break; + } + return S_OK; +} + +/***************************************************************************** + + XmlAddHubCapabilitiesEx() + + Adds the hub capabilities information to the hub object + *****************************************************************************/ +HRESULT XmlAddHubCapabilitiesEx(HubCapabilitiesExType ^ex, PUSB_HUB_CAPABILITIES_EX hubCapEx) +{ + if(NULL != hubCapEx) + { + ex->HubIsHighSpeedCapable = hubCapEx->CapabilityFlags.HubIsHighSpeedCapable?true:false; + ex->HubIsHighSpeed = hubCapEx->CapabilityFlags.HubIsHighSpeed?true:false; + ex->HubIsMultiTtCapable = hubCapEx->CapabilityFlags.HubIsMultiTtCapable?true:false; + ex->HubIsMultiTt = hubCapEx->CapabilityFlags.HubIsMultiTt?true:false; + ex->HubIsRoot = hubCapEx->CapabilityFlags.HubIsRoot?true:false; + ex->HubIsArmedWakeOnConnect = hubCapEx->CapabilityFlags.HubIsArmedWakeOnConnect?true:false; + ex->HubIsBusPowered = hubCapEx->CapabilityFlags.HubIsBusPowered?true:false; + } + return S_OK; +} + +/***************************************************************************** + + ExternalHubType ^ AddExternalHub(Object ^parent) + + This routine finds the type of the parent and adds an external hub object to the + parent's list of external hubs. The newly created object is returned + We are using arrays insted of better types of collections becaused the code generated + by xsd.exe does not support other types. + *****************************************************************************/ +ExternalHubType ^ AddExternalHub(Object ^parent) +{ + RootHubType ^ rhParent = nullptr; + ExternalHubType ^ ehParent = nullptr; + array<ExternalHubType ^> ^ exHubArray = nullptr; + ExternalHubType ^ exHub = nullptr; + boolean arrayCreated = false; + + // An external hub can be connected to a Root Hub or another External Hub + // We need to determine the type of the object. + + // Try root hub first + + rhParent = dynamic_cast<RootHubType ^> (parent); + if (rhParent == nullptr) + { + // RootHub cast was not successfult, try external hub + ehParent = dynamic_cast<ExternalHubType ^> (parent); + if (ehParent != nullptr) + { + // External hub parent + if (ehParent->ExternalHub == nullptr) + { + // First hub in the list of external hubs + ehParent->ExternalHub = gcnew array<ExternalHubType ^> (1); + arrayCreated = true; + } + exHubArray = ehParent->ExternalHub; + } + + } + else + { + // Parent is a root hub + if (rhParent->ExternalHub == nullptr) + { + // First hub in root hub list + rhParent->ExternalHub = gcnew array<ExternalHubType ^>(1); + arrayCreated = true; + } + exHubArray = rhParent->ExternalHub; + } + + if (exHubArray != nullptr) + { + if (arrayCreated) + { + // We created the array in this function, so we use offset 0 + exHubArray[0] = gcnew ExternalHubType(); + exHub = exHubArray[0]; + } + else + { + // The array was already present, we need to do elaborate things + // as array.resize does not work. + ArrayList ^exList = gcnew ArrayList(); + exList->AddRange(exHubArray); + exHub = gcnew ExternalHubType(); + exList->Add(exHub); + + if (rhParent != nullptr) + { + rhParent->ExternalHub = reinterpret_cast<array<ExternalHubType ^>^> (exList->ToArray(ExternalHubType::typeid)); + } + else + { + ehParent->ExternalHub = reinterpret_cast<array<ExternalHubType ^>^> (exList->ToArray(ExternalHubType::typeid)); + } + } + } + return exHub; +} +/***************************************************************************** + + NoDeviceType ^ AddDisconnectedPort(Object ^parent) + + This routine finds the type of the parent and adds a empty port connection object to the + parent's list of devices. The newly created object is returned + We are using arrays insted of better types of collections becaused the code generated + by xsd.exe does not support other types. + *****************************************************************************/ +NoDeviceType ^ AddDisconnectedPort(Object ^parent) +{ + RootHubType ^ rhParent = nullptr; + ExternalHubType ^ ehParent = nullptr; + array<NoDeviceType ^> ^ devicesArray = nullptr; + NoDeviceType ^ noD = nullptr; + boolean arrayCreated = false; + + // An external hub can be connected to a Root Hub or another External Hub + // We need to determine the type of the object. + + // Try RH first + + rhParent = dynamic_cast<RootHubType ^> (parent); + if (rhParent == nullptr) + { + // RootHub cast was not successfult, try external hub + ehParent = dynamic_cast<ExternalHubType ^> (parent); + if (ehParent != nullptr) + { + // External hub parent + if (ehParent->NoDevice == nullptr) + { + // First hub in the list of external hubs + ehParent->NoDevice = gcnew array<NoDeviceType ^> (1); + arrayCreated = true; + } + devicesArray = ehParent->NoDevice; + } + + } + else + { + // Parent is a root hub + if (rhParent->NoDevice == nullptr) + { + // First hub in root hub list + rhParent->NoDevice = gcnew array<NoDeviceType ^>(1); + arrayCreated = true; + } + devicesArray = rhParent->NoDevice; + } + + if (devicesArray != nullptr) + { + if (arrayCreated) + { + // We created the array in this function, so we use offset 0 + devicesArray[0] = gcnew NoDeviceType(); + noD = devicesArray[0]; + } + else + { + // The array was already present, we need to do elaborate things + // as array.resize does not work. + ArrayList ^exList = gcnew ArrayList(); + exList->AddRange(devicesArray); + noD = gcnew NoDeviceType(); + exList->Add(noD); + + if (rhParent != nullptr) + { + rhParent->NoDevice = reinterpret_cast<array<NoDeviceType ^>^> (exList->ToArray(NoDeviceType::typeid)); + } + else + { + ehParent->NoDevice = reinterpret_cast<array<NoDeviceType ^>^> (exList->ToArray(NoDeviceType::typeid)); + } + } + } + return noD; +} + +/***************************************************************************** + + UsbDeviceType ^ AddUsbDevice(Object ^parent) + + This routine finds the type of the parent and adds a port connection object to the + parent's list of port connectors. The newly created object is returned + We are using arrays insted of better types of collections becaused the code generated + by xsd.exe does not support other types. + *****************************************************************************/ +UsbDeviceType ^ AddUsbDevice(Object ^parent) +{ + RootHubType ^ rhParent = nullptr; + ExternalHubType ^ ehParent = nullptr; + array<UsbDeviceType ^> ^ devicesArray = nullptr; + UsbDeviceType ^ usbD = nullptr; + boolean arrayCreated = false; + + // An external hub can be connected to a Root Hub or another External Hub + // We need to determine the type of the object. + + // Try RH first + + rhParent = dynamic_cast<RootHubType ^> (parent); + if (rhParent == nullptr) + { + // RootHub cast was not successfult, try external hub + ehParent = dynamic_cast<ExternalHubType ^> (parent); + if (ehParent != nullptr) + { + // External hub parent + if (ehParent->UsbDevice == nullptr) + { + // First hub in the list of external hubs + ehParent->UsbDevice = gcnew array<UsbDeviceType ^> (1); + arrayCreated = true; + } + devicesArray = ehParent->UsbDevice; + } + + } + else + { + // Parent is a root hub + if (rhParent->UsbDevice == nullptr) + { + // First hub in root hub list + rhParent->UsbDevice = gcnew array<UsbDeviceType ^>(1); + arrayCreated = true; + } + devicesArray = rhParent->UsbDevice; + } + + if (devicesArray != nullptr) + { + if (arrayCreated) + { + // We created the array in this function, so we use offset 0 + devicesArray[0] = gcnew UsbDeviceType(); + usbD = devicesArray[0]; + } + else + { + // The array was already present, we need to do elaborate things + // as array.resize does not work. + ArrayList ^exList = gcnew ArrayList(); + exList->AddRange(devicesArray); + usbD = gcnew UsbDeviceType(); + exList->Add(usbD); + + if (rhParent != nullptr) + { + rhParent->UsbDevice = reinterpret_cast<array<UsbDeviceType ^>^> (exList->ToArray(UsbDeviceType::typeid)); + } + else + { + ehParent->UsbDevice = reinterpret_cast<array<UsbDeviceType ^>^> (exList->ToArray(UsbDeviceType::typeid)); + } + } + } + return usbD; +} + +/***************************************************************************** + + XmlAddIADDescriptor() + + This routine adds usb IAD descriptor + *****************************************************************************/ +void XmlAddIADDescriptor( + UsbDeviceIADDescriptorType ^ iadXmlDesc, + PUSB_IAD_DESCRIPTOR iadDesc, + PSTRING_DESCRIPTOR_NODE stringDesc, + int nInterfaces) +{ + if (NULL == iadDesc || NULL == stringDesc) + { + return; + } + + // Update structure fields + iadXmlDesc->BLength = iadDesc->bLength; + iadXmlDesc->BDescriptorType = iadDesc->bDescriptorType; + iadXmlDesc->BFirstInterface = iadDesc->bFirstInterface; + iadXmlDesc->BInterfaceCount = iadDesc->bInterfaceCount; + iadXmlDesc->BFunctionClass = iadDesc->bFunctionClass; + iadXmlDesc->BFunctionSubclass = iadDesc->bFunctionSubClass; + iadXmlDesc->BFunctionProtocol = iadDesc->bFunctionProtocol; + iadXmlDesc->IFunction = iadDesc->iFunction; + + // Validate fields + if (iadDesc->bInterfaceCount == 1) + { + iadXmlDesc->InterfaceError = gcnew String("ERROR: bInterfaceCount must be greater than 1"); + } + if (nInterfaces < iadDesc->bFirstInterface + iadDesc->bInterfaceCount) + { + iadXmlDesc->InterfaceError = gcnew String("ERROR: The total number of interfaces"); + iadXmlDesc->InterfaceError += nInterfaces; + iadXmlDesc->InterfaceError += " must be greater than or equal to the highest linked interface number (base "; + iadXmlDesc->InterfaceError += iadDesc->bFirstInterface; + iadXmlDesc->InterfaceError += " + count "; + iadXmlDesc->InterfaceError += iadDesc->bInterfaceCount; + iadXmlDesc->InterfaceError += " = "; + iadXmlDesc->InterfaceError += (iadDesc->bFirstInterface + iadDesc->bInterfaceCount); + iadXmlDesc->InterfaceError += " )"; + } + if (iadDesc->bFunctionClass == 0) + { + iadXmlDesc->FunctionClassError = gcnew String("ERROR: bFunctionClass contains an illegal value 0"); + } + + iadXmlDesc->FunctionDetails = XmlGetDeviceClass( + iadDesc->bFunctionClass, + iadDesc->bFunctionSubClass, + iadDesc->bFunctionProtocol); + + // Protocol check + if (iadDesc->bFunctionClass == USB_DEVICE_CLASS_VIDEO) + { + if (iadDesc->bFunctionProtocol != PC_PROTOCOL_UNDEFINED) + { + iadXmlDesc->Protocol= gcnew String("WARNING: Protocol must be set to PC_PROTOCOL_UNDEFINED"); + iadXmlDesc->Protocol+= " for this class but is set to: "; + iadXmlDesc->Protocol+= iadDesc->bFunctionProtocol; + } + else + { + iadXmlDesc->Protocol = gcnew String("PC_PROTOCOL_UNDEFINED protocol"); + } + } + + if (iadDesc->iFunction) + { + // Add String descriptor + iadXmlDesc->StringDesc = XmlGetStringDescriptor( + iadDesc->iFunction, + stringDesc, + false); + } + + return; +} + +/***************************************************************************** + + XmlAddOTGDescriptor() + + This routine adds usb OTG descriptor + *****************************************************************************/ +void XmlAddOTGDescriptor( + UsbDeviceOTGDescriptorType ^ otgXmlDesc, + PUSB_OTG_DESCRIPTOR otgDesc) +{ + if (NULL == otgDesc) + { + return; + } + + otgXmlDesc->BLength = otgDesc->bLength; + otgXmlDesc->BDescriptorType = otgDesc->bDescriptorType; + otgXmlDesc->BmAttributes = otgDesc->bmAttributes; + + // Add descriptive fields + switch (otgDesc->bmAttributes) + { + case 0: + break; + case 1: + otgXmlDesc->AttributesString = gcnew String("SRP support"); + break; + case 2: + otgXmlDesc->AttributesString = gcnew String("HNP support"); + break; + case 3: + otgXmlDesc->AttributesString = gcnew String("SRP and HNP support"); + break; + default: + otgXmlDesc->AttributesString = gcnew String("ERROR: bmAttributes bits 2-7 are reserved should be 0)"); + break; + } + return; +} + +/***************************************************************************** + + XmlAddHidDescriptor() + + This routine adds usb HID descriptor + *****************************************************************************/ +void XmlAddHidDescriptor( + UsbDeviceHidDescriptorType ^ hidXmlDesc, + PUSB_HID_DESCRIPTOR hidDesc + ) +{ + int i = 0; + + if (NULL == hidDesc) + { + return; + } + + hidXmlDesc->BLength = hidDesc->bLength; + hidXmlDesc->BDescriptorType = hidDesc->bDescriptorType; + hidXmlDesc->BcdHID = hidDesc->bcdHID; + hidXmlDesc->BCountryCode = hidDesc->bCountryCode; + hidXmlDesc->BNumDescriptors = hidDesc->bNumDescriptors; + + // Add optional descriptors + if (hidDesc->bNumDescriptors > 0) + { + hidXmlDesc->OptionalDescriptor = gcnew array <UsbDeviceHidOptionalDescriptorsType ^>(hidDesc->bNumDescriptors); + for(i=0; i < hidDesc->bNumDescriptors; i++) + { + hidXmlDesc->OptionalDescriptor[i] = gcnew UsbDeviceHidOptionalDescriptorsType(); + hidXmlDesc->OptionalDescriptor[i]->BDescriptorType = hidDesc->OptionalDescriptors[i].bDescriptorType; + hidXmlDesc->OptionalDescriptor[i]->WDescriptorLength = hidDesc->OptionalDescriptors[i].wDescriptorLength; + } + } + return; +} + +/***************************************************************************** + + XmlGetUnknownDescriptor() + + This routine gets a usb unknown descriptor object form unknown descriptor + *****************************************************************************/ +UsbDeviceUnknownDescriptorType ^ XmlGetUnknownDescriptor( + PUSB_COMMON_DESCRIPTOR unknownDesc + ) +{ + int i = 0; + UsbDeviceUnknownDescriptorType ^ unknownXmlDesc = nullptr; + + if (NULL == unknownDesc) + { + return nullptr; + } + + unknownXmlDesc = gcnew UsbDeviceUnknownDescriptorType(); + unknownXmlDesc->BLength = unknownDesc->bLength; + unknownXmlDesc->BDescriptorType = unknownDesc->bDescriptorType; + + // Add optional descriptors + if (unknownDesc->bLength > 0) + { + unknownXmlDesc->UnknownDescriptor = gcnew String("Unknown descriptor->"); + for(i=0; i < unknownDesc->bLength; i++) + { + unknownXmlDesc->UnknownDescriptor += String::Format("0x{0:X} ", ((PUCHAR) unknownDesc)[i]); + } + } + return unknownXmlDesc; +} + +/***************************************************************************** + + XmlAddEndpointDescriptor() + + This routine adds usb endpoint descriptor and verbose fields + *****************************************************************************/ +void XmlAddEndpointDescriptor( + EndpointDescriptorType ^usbXmlEndpointDescriptor, + PUSB_ENDPOINT_DESCRIPTOR endPointDescriptor, + UCHAR connectionSpeed + ) +{ + EndpointDescriptorType ^ue = usbXmlEndpointDescriptor; + ULONG maxBytes = endPointDescriptor->wMaxPacketSize & 0x7FF; + + // Add structure values + ue->Length = endPointDescriptor->bLength; + ue->DescriptorType = endPointDescriptor->bDescriptorType; + ue->EndpointAddress = endPointDescriptor->bEndpointAddress; + ue->Attributes = endPointDescriptor->bmAttributes; + ue->MaxPacketSize = endPointDescriptor->wMaxPacketSize; + + // Add verbose fields + ue->EndpointId = endPointDescriptor->bEndpointAddress & 0x0F; + + // Add endpoint direction + if (USB_ENDPOINT_DIRECTION_OUT(endPointDescriptor->bEndpointAddress)) + { + ue->EndpointDirection = gcnew String("Out"); + } + else if (USB_ENDPOINT_DIRECTION_IN(endPointDescriptor->bEndpointAddress)) + { + ue->EndpointDirection = gcnew String("In"); + } + + // Add endpoint type + switch (endPointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) + { + case USB_ENDPOINT_TYPE_CONTROL: + ue->EndpointType = gcnew String("Control Transfer Type"); + break; + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + switch (endPointDescriptor->bmAttributes & 0x0C) + { + case 0x00: + ue->EndpointType = gcnew String("Ischronous Transfer Type - No Synchronization"); + break; + + case 0x04: + ue->EndpointType = gcnew String("Ischronous Transfer Type - Asynchronous"); + break; + + case 0x08: + ue->EndpointType = gcnew String("Ischronous Transfer Type - Adaptive"); + break; + + case 0x0C: + ue->EndpointType = gcnew String("Ischronous Transfer Type - Synchronous"); + break; + } + break; + case USB_ENDPOINT_TYPE_BULK: + ue->EndpointType = gcnew String("Bulk Transfer Type"); + break; + + case USB_ENDPOINT_TYPE_INTERRUPT: + ue->EndpointType = gcnew String("Interrupt Transfer Type"); + break; + } + + // Add packet info + switch (connectionSpeed) + { + case UsbHighSpeed: + if (endPointDescriptor->bmAttributes & 1) { + ULONG transactions = ((endPointDescriptor->wMaxPacketSize & 0x1800) >> 11) + 1; + // Isoc or Interrupt endpoint + ue->EndpointPacketInfo = gcnew String( + transactions + " transactions per microframe, " + + maxBytes + " max bytes"); + } + else + { + // Bulk endpoint + ue->EndpointPacketInfo = gcnew String(maxBytes + " max bytes"); + } + break; + case UsbFullSpeed: + ue->EndpointPacketInfo = gcnew String(maxBytes + " max bytes"); + break; + default: + // Low or Invalid speed + ue->EndpointPacketInfo = gcnew String("Invalid bus speed"); + break; + } + + // Add validation + if (endPointDescriptor->wMaxPacketSize & 0xE000) + { + ue->EndpointPacketSizeValidation = gcnew String("ERROR: wMaxPacketSize bits 15-13 should be 0"); + } else if (connectionSpeed==UsbHighSpeed) + { + USHORT hsMux; + + hsMux = (endPointDescriptor->wMaxPacketSize >> 11) & 0x03; + + switch (endPointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) + { + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + case USB_ENDPOINT_TYPE_INTERRUPT: + switch (hsMux) { + case 0: + if ((maxBytes < 1) || (maxBytes > 1024)) + { + ue->EndpointPacketSizeValidation = gcnew String("ERROR: Invalid maximum packet size, should be between 1 and 1024"); + } + break; + + case 1: + if ((maxBytes < 513) || (maxBytes > 1024)) + { + ue->EndpointPacketSizeValidation = gcnew String("ERROR: Invalid maximum packet size, should be between 513 and 1024"); + } + break; + + case 2: + if ((maxBytes < 683) || (maxBytes > 1024)) + { + ue->EndpointPacketSizeValidation = gcnew String("ERROR: Invalid maximum packet size, should be between 683 and 1024"); + } + break; + + case 3: + ue->EndpointPacketSizeValidation = gcnew String("ERROR: Bits 12-11 set to reserved value\r\n"); + break; + } + } + } + + // Add interval + if (endPointDescriptor->bLength == sizeof(USB_ENDPOINT_DESCRIPTOR)) + { + ue->Interval = endPointDescriptor->bInterval; + } + else + { + PUSB_ENDPOINT_DESCRIPTOR2 endpointDesc2 = (PUSB_ENDPOINT_DESCRIPTOR2) endPointDescriptor; + ue->WInterval = endpointDesc2->wInterval; + ue->SyncAddress = endpointDesc2->bSyncAddress; + } + return; +} + +/***************************************************************************** + + XmlAddPipeInformation() + + This routine adds all the pipe information for device + *****************************************************************************/ +void XmlAddPipeInformation( + array< UsbPipeInfoType ^> ^ usbXmlPipeInfoList, + PUSB_PIPE_INFO pipeInfo, + ULONG numPipes, + UCHAR connectionSpeed + ) +{ + ULONG i = 0; + + for(i = 0; i< numPipes; i++) + { + // Add all pipe in the list + usbXmlPipeInfoList[i] = gcnew UsbPipeInfoType(); + usbXmlPipeInfoList[i]->EndpointDescriptor = gcnew EndpointDescriptorType(); + XmlAddEndpointDescriptor( + usbXmlPipeInfoList[i]->EndpointDescriptor, + &pipeInfo[i].EndpointDescriptor, + connectionSpeed); + usbXmlPipeInfoList[i]->ScheduleOffset = pipeInfo->ScheduleOffset; + } + return; +} + +/***************************************************************************** + + XmlAddUsbDeviceDescriptor() + + This routine adds usb device descriptor + *****************************************************************************/ +void XmlAddUsbDeviceDescriptor( + UsbDeviceDescriptorType ^usbXmlDeviceDescriptor, + PUSB_DEVICE_DESCRIPTOR usbDeviceDescriptor) +{ + UsbDeviceDescriptorType ^ud = usbXmlDeviceDescriptor; + + // Map all fields explicitly + + ud->Length = usbDeviceDescriptor->bLength; + ud->DescriptorType = usbDeviceDescriptor->bDescriptorType; + ud->CdUSB= usbDeviceDescriptor->bcdUSB; + ud->DeviceClass = usbDeviceDescriptor->bDeviceClass; + ud->DeviceSubclass = usbDeviceDescriptor->bDeviceSubClass; + ud->DeviceProtocol = usbDeviceDescriptor->bDeviceProtocol; + ud->MaxPacketSize0 = usbDeviceDescriptor->bMaxPacketSize0; + ud->IdVendor = usbDeviceDescriptor->idVendor; + ud->IdProduct = usbDeviceDescriptor->idProduct ; + ud->CdDevice = usbDeviceDescriptor->bcdDevice; + ud->IManufacturer = usbDeviceDescriptor->iManufacturer; + ud->IProduct = usbDeviceDescriptor->iProduct; + ud->ISerialNumber = usbDeviceDescriptor->iSerialNumber; + ud->NumConfigurations = usbDeviceDescriptor->bNumConfigurations; + return; +} + +/***************************************************************************** + + XmlAddConfigurationDescriptor() + + This routine adds the configuration descriptor + *****************************************************************************/ +void XmlAddConfigurationDescriptor( + UsbConfigurationDescriptorType ^ confXmlDesc, + PUSBDEVICEINFO deviceInfo, + PUSB_CONFIGURATION_DESCRIPTOR configDesc, + PSTRING_DESCRIPTOR_NODE stringDesc + ) + +{ + UINT uCount = 0; + BOOL isSuperSpeed = FALSE; + + if (NULL == configDesc || NULL == deviceInfo) + { + return; + } + + if(deviceInfo->ConnectionInfoV2 && + (deviceInfo->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher || + deviceInfo->ConnectionInfoV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher)) + { + isSuperSpeed = TRUE; + } + + confXmlDesc->BLength = configDesc->bLength; + confXmlDesc->BDescriptorType = configDesc->bDescriptorType; + confXmlDesc->WTotalLength = configDesc->wTotalLength; + confXmlDesc->BNumInterfaces = configDesc->bNumInterfaces; + confXmlDesc->BConfigurationValue = configDesc->bConfigurationValue; + confXmlDesc->IConfiguration = configDesc->iConfiguration; + confXmlDesc->BmAttributes = configDesc->bmAttributes; + confXmlDesc->MaxPower = configDesc->MaxPower; + + uCount = GetConfigurationSize(deviceInfo); + + if (uCount != configDesc->wTotalLength) + { + confXmlDesc->ConfigDescError = gcnew String("ERROR: Invalid total configuration size " + + configDesc->wTotalLength + ", should be " + uCount); + } + + if (configDesc->bConfigurationValue != 1) + { + confXmlDesc->ConfValueError = gcnew String("CAUTION: Most host controllers will only work with one configuration per speed"); + } + + if (configDesc->iConfiguration) + { + confXmlDesc->ConfStringDesc = XmlGetStringDescriptor( + configDesc->iConfiguration, + stringDesc, + false); + } + + if (configDesc->bmAttributes & USB_CONFIG_BUS_POWERED) + { + confXmlDesc->AttributesStr = gcnew String("Bus Powered"); + } + else if (configDesc->bmAttributes & USB_CONFIG_SELF_POWERED) + { + confXmlDesc->AttributesStr = gcnew String("Self Powered"); + } + else if (configDesc->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) + { + confXmlDesc->AttributesStr = gcnew String("Remote Wakeup"); + } + else + { + confXmlDesc->AttributesStr = gcnew String("WARNING: bmAttributes is using reserved space"); + } + + confXmlDesc->MaxCurrent = gcnew String(""); + confXmlDesc->MaxCurrent += (isSuperSpeed?configDesc->MaxPower * 8:configDesc->MaxPower * 2); + confXmlDesc->MaxCurrent += " mA"; + + return; +} + +/***************************************************************************** + + XmlGetDeviceClass() + + This routine returns the interface class and subclass for given interface descriptor + *****************************************************************************/ +UsbDeviceClassType ^ XmlGetDeviceClass(UCHAR bInterfaceClass, UCHAR bInterfaceSubclass, UCHAR bInterfaceProtocol) +{ + String ^ deviceClass = nullptr; + String ^ deviceSubclass = nullptr; + UsbDeviceClassType ^ deviceDetails = gcnew UsbDeviceClassType(); + + switch (bInterfaceClass) + { + case USB_DEVICE_CLASS_AUDIO: + deviceClass = gcnew String("Audio Interface"); + + switch (bInterfaceSubclass) + { + case USB_AUDIO_SUBCLASS_AUDIOCONTROL: + deviceSubclass = gcnew String("Audio Control Interface"); + break; + + case USB_AUDIO_SUBCLASS_AUDIOSTREAMING: + deviceSubclass = gcnew String("Audio Streaming Interface"); + break; + + case USB_AUDIO_SUBCLASS_MIDISTREAMING: + deviceSubclass = gcnew String("MIDI Streaming Interface"); + break; + + default: + deviceSubclass = gcnew String("CAUTION: This appears to be an invalid bInterfaceSubclass : "); + deviceSubclass += bInterfaceSubclass; + break; + } + break; + + case USB_DEVICE_CLASS_VIDEO: + deviceClass = gcnew String("Video Interface"); + + switch(bInterfaceSubclass) + { + case VIDEO_SUBCLASS_CONTROL: + deviceSubclass = gcnew String("Video Control"); + break; + + case VIDEO_SUBCLASS_STREAMING: + deviceSubclass = gcnew String("Video Streaming"); + break; + + default: + deviceSubclass = gcnew String("CAUTION: This appears to be an invalid bInterfaceSubclass : "); + deviceSubclass += bInterfaceSubclass; + break; + } + break; + + case USB_DEVICE_CLASS_VENDOR_SPECIFIC: + deviceClass = gcnew String("Vendor Specific Device"); + break; + + case USB_DEVICE_CLASS_HUMAN_INTERFACE: + + deviceClass = gcnew String("HID Interface"); + break; + + case USB_DEVICE_CLASS_HUB: + deviceClass = gcnew String("HUB Interface"); + break; + + case USB_DEVICE_CLASS_RESERVED: + deviceClass = gcnew String("CAUTION: Reserved USB Device Interface Class"); + break; + + case USB_DEVICE_CLASS_COMMUNICATIONS: + deviceClass = gcnew String("Communications (CDC Control) USB Device\r\n"); + break; + + case USB_DEVICE_CLASS_MONITOR: + deviceClass = gcnew String("Monitor USB Device Interface Class*** (This may be obsolete)"); + break; + + case USB_DEVICE_CLASS_PHYSICAL_INTERFACE: + deviceClass = gcnew String("Physical Interface USB Device"); + break; + + case USB_DEVICE_CLASS_POWER: + if (bInterfaceSubclass == 1 && bInterfaceProtocol == 1) + { + deviceClass = gcnew String("Image USB Device"); + } + else + { + deviceClass = gcnew String("Power USB Device (This may be obsolete)"); + } + break; + + case USB_DEVICE_CLASS_PRINTER: + deviceClass = gcnew String("Printer USB Device"); + break; + + case USB_DEVICE_CLASS_STORAGE: + deviceClass = gcnew String("Mass Storage USB Device"); + break; + + case USB_CDC_DATA_INTERFACE: + deviceClass = gcnew String("CDC Data USB Device"); + break; + + case USB_CHIP_SMART_CARD_INTERFACE: + deviceClass = gcnew String("Chip/Smart Card USB Device"); + break; + + case USB_CONTENT_SECURITY_INTERFACE: + deviceClass = gcnew String("Content Security USB Device"); + break; + + case USB_DIAGNOSTIC_DEVICE_INTERFACE: + if (bInterfaceSubclass == 1 && bInterfaceProtocol == 1) + { + deviceClass = gcnew String("Reprogrammable USB2 Compliance Diagnostic Device USB Device"); + } + else + { + deviceClass = gcnew String("CAUTION: This appears to be an invalid device class: "); + deviceClass += bInterfaceClass; + } + break; + + case USB_WIRELESS_CONTROLLER_INTERFACE: + if (bInterfaceSubclass == 1 && bInterfaceProtocol == 1) + { + deviceClass = gcnew String("Wireless RF Controller USB Device Interface Class with Bluetooth Programming Interface"); + } + else + { + deviceClass = gcnew String("CAUTION: This appears to be an invalid device class: "); + deviceClass += bInterfaceClass; + } + break; + + case USB_APPLICATION_SPECIFIC_INTERFACE: + deviceClass = gcnew String("Application Specific USB Device"); + + switch(bInterfaceSubclass) + { + case 1: + deviceSubclass = gcnew String("Device Firmware Application Specific USB Device"); + break; + case 2: + deviceSubclass = gcnew String("IrDA Bridge Application Specific USB Device"); + break; + case 3: + deviceSubclass = gcnew String("Test & Measurement Class (USBTMC) Application Specific USB Device"); + break; + default: + deviceSubclass = gcnew String("CAUTION: This appears to be an invalid bInterfaceSubclass : "); + deviceSubclass += bInterfaceSubclass; + } + break; + + default: + + deviceClass = gcnew String("Interface Class unknown : "); + deviceClass += bInterfaceClass; + break; + } + + // Return class and subclass + + deviceDetails->DeviceClass = deviceClass; + deviceDetails->DeviceSubclass = deviceSubclass; + + return deviceDetails; +} + +/***************************************************************************** + + XmlAddInterfaceDescriptor() + + This routine adds the device interface descriptor + *****************************************************************************/ +void XmlAddDeviceInterfaceDescriptor( + UsbDeviceInterfaceDescriptorType ^ ifXmlDesc, + PUSB_INTERFACE_DESCRIPTOR ifDesc, + PSTRING_DESCRIPTOR_NODE stringDesc) +{ + if (NULL == ifDesc || NULL == stringDesc) + { + return; + } + + // Update structure fields + ifXmlDesc->BLength = ifDesc->bLength; + ifXmlDesc->BDescriptorType = ifDesc->bDescriptorType; + ifXmlDesc->BInterfaceNumber = ifDesc->bInterfaceNumber; + ifXmlDesc->BAlternateSetting = ifDesc->bAlternateSetting; + ifXmlDesc->BNumEndpoints = ifDesc->bNumEndpoints; + ifXmlDesc->BInterfaceClass = ifDesc->bInterfaceClass; + ifXmlDesc->BInterfaceSubclass = ifDesc->bInterfaceSubClass; + ifXmlDesc->BInterfaceProtocol = ifDesc->bInterfaceProtocol; + ifXmlDesc->IInterface = ifDesc->iInterface; + + // Update class and sub class + ifXmlDesc->InterfaceDetails = XmlGetDeviceClass( + ifDesc->bInterfaceClass, + ifDesc->bInterfaceSubClass, + ifDesc->bInterfaceProtocol); + + //This is basically the check for PC_PROTOCOL_UNDEFINED + if ((ifDesc->bInterfaceClass == USB_DEVICE_CLASS_VIDEO) || + (ifDesc->bInterfaceClass == USB_DEVICE_CLASS_AUDIO)) + { + if (ifDesc->bInterfaceProtocol != PC_PROTOCOL_UNDEFINED) + { + ifXmlDesc->ProtocolError = gcnew String("WARNING: Protocol must be set to PC_PROTOCOL_UNDEFINED"); + ifXmlDesc->ProtocolError += " for this class but is set to: "; + ifXmlDesc->ProtocolError += ifDesc->bInterfaceProtocol; + } + } + + if (ifDesc->iInterface) + { + // Add String descriptor + ifXmlDesc->StringDesc = XmlGetStringDescriptor( + ifDesc->iInterface, + stringDesc, + false); + } + + if (ifDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR2)) + { + PUSB_INTERFACE_DESCRIPTOR2 interfaceDesc2; + + interfaceDesc2 = (PUSB_INTERFACE_DESCRIPTOR2)ifDesc; + + ifXmlDesc->WNumClasses = interfaceDesc2->wNumClasses; + } + return; +} + +/***************************************************************************** + + XmlAddDeviceQualDescriptor() + + This routine adds the device qualifier descriptor + *****************************************************************************/ + +void XmlAddDeviceQualDescriptor( + UsbDeviceQualifierDescriptorType ^ qualXmlDesc, + PUSB_DEVICE_QUALIFIER_DESCRIPTOR qualDesc) +{ + if (NULL == qualDesc) + { + return; + } + + // Add structure fields + qualXmlDesc->BLength = qualDesc->bLength; + qualXmlDesc->BDescriptorType = qualDesc->bDescriptorType; + qualXmlDesc->BcdUSB = qualDesc->bcdUSB; + qualXmlDesc->BDeviceClass = qualDesc->bDeviceClass; + qualXmlDesc->BDeviceSubclass = qualDesc->bDeviceSubClass; + qualXmlDesc->BDeviceProtocol = qualDesc->bDeviceProtocol; + qualXmlDesc->BMaxPacketSize0 = qualDesc->bMaxPacketSize0; + qualXmlDesc->NumConfigurations = qualDesc->bNumConfigurations; + + // Get device class string + qualXmlDesc->DeviceClass = XmlGetDeviceClassString(qualDesc->bDeviceClass); + + if (qualDesc->bDeviceSubClass > 0x00 && qualDesc->bDeviceSubClass < 0xFF) + { + qualXmlDesc->DeviceSubclassError = gcnew String("ERROR: bDeviceSubClass is invalid : "); + qualXmlDesc->DeviceSubclassError += qualDesc->bDeviceSubClass; + } + + if (qualDesc->bDeviceProtocol > 0x00 && qualDesc->bDeviceProtocol < 0xFF) + { + qualXmlDesc->DeviceProtocolError = gcnew String("ERROR: bDeviceProtocol is invalid : "); + qualXmlDesc->DeviceProtocolError += qualDesc->bDeviceProtocol; + } + + qualXmlDesc->MaxPacketSizeInBytes = qualDesc->bMaxPacketSize0; + + if (qualDesc->bNumConfigurations != 1) + { + qualXmlDesc->DeviceNumConfigError = gcnew String( + "CAUTION: Most host controllers will only work with one configuration per speed"); + } + + if (qualDesc->bReserved != 0) + { + qualXmlDesc->ReservedError = gcnew String("WARNING: bReserved needs to be set to 0 to be valid - " + + qualDesc->bReserved); + } + + return; +} + +/***************************************************************************** + + XmlAddAddConfigDescriptors() + + This routine adds the all the config descriptors + *****************************************************************************/ +array < UsbDeviceConfigurationType ^> ^ XmlGetConfigDescriptors( + PUSBDEVICEINFO deviceInfo, + PUSB_CONFIGURATION_DESCRIPTOR configDescs, + PSTRING_DESCRIPTOR_NODE stringDesc + ) +{ + array < UsbDeviceConfigurationType ^> ^ confXmlDescs = nullptr; + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + PUCHAR descEnd = NULL; + ArrayList ^confList = gcnew ArrayList; + UsbDeviceConfigurationType ^ deviceConf = nullptr; + + commonDesc = (PUSB_COMMON_DESCRIPTOR) configDescs; + descEnd = (PUCHAR) configDescs + configDescs->wTotalLength; + + while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && + (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) + { + // Add the config descriptor + deviceConf = gcnew UsbDeviceConfigurationType(); + + XmlAddDeviceConfiguration( + deviceConf, + deviceInfo, + (PUSB_CONFIGURATION_DESCRIPTOR) commonDesc, + stringDesc, + configDescs->bNumInterfaces + ); + + confList->Add(deviceConf); + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + } + + confXmlDescs = reinterpret_cast<array<UsbDeviceConfigurationType ^>^> (confList->ToArray(UsbDeviceConfigurationType::typeid)); + return confXmlDescs; +} + +/***************************************************************************** + + XmlAddDeviceConfiguration() + + This routine adds the device configuration + *****************************************************************************/ +void XmlAddDeviceConfiguration( + UsbDeviceConfigurationType ^ confXmlDesc, + PUSBDEVICEINFO deviceInfo, + PUSB_CONFIGURATION_DESCRIPTOR configDesc, + PSTRING_DESCRIPTOR_NODE stringDesc, + int numInterfaces + ) +{ + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + UCHAR bInterfaceClass = 0; + UCHAR bInterfaceSubclass = 0; + UCHAR bInterfaceProtocol = 0; + BOOL displayUnknown = FALSE; + + if (NULL == deviceInfo || NULL == configDesc || NULL == stringDesc) + { + return; + } + + commonDesc = (PUSB_COMMON_DESCRIPTOR)configDesc; + displayUnknown = FALSE; + + switch (commonDesc->bDescriptorType) + { + case USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR)) + { + // Validate descriptor + confXmlDesc->DeviceQualifierError = String::Format( + "ERROR: Device Qualifier bLength value incorrect Obtained: {0} Expected {1}", + commonDesc->bLength, + sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR)); + displayUnknown = TRUE; + break; + } + // Add device Qual descriptor + confXmlDesc->DeviceQualifierDescriptor = gcnew UsbDeviceQualifierDescriptorType(); + + XmlAddDeviceQualDescriptor( + confXmlDesc->DeviceQualifierDescriptor, + (PUSB_DEVICE_QUALIFIER_DESCRIPTOR) commonDesc); + break; + + case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + // Validate descriptor + confXmlDesc->SpeedConfigurationError = String::Format( + "ERROR: Other speed configuration bLength value incorrect Obtained: {0} Expected {1}", + commonDesc->bLength, + sizeof(USB_CONFIGURATION_DESCRIPTOR)); + displayUnknown = TRUE; + } + + // Add configuration desc + confXmlDesc->ConfigurationDescriptor = gcnew UsbConfigurationDescriptorType(); + + XmlAddConfigurationDescriptor( + confXmlDesc->ConfigurationDescriptor, + deviceInfo, + (PUSB_CONFIGURATION_DESCRIPTOR) commonDesc, + stringDesc); + break; + + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + // Validate descriptor + confXmlDesc->SpeedConfigurationError = String::Format( + "ERROR: Configuration bLength value incorrect Obtained: {0} Expected {1}", + commonDesc->bLength, + sizeof(USB_CONFIGURATION_DESCRIPTOR)); + displayUnknown = TRUE; + break; + } + + // Add configuration desc + confXmlDesc->ConfigurationDescriptor = gcnew UsbConfigurationDescriptorType(); + XmlAddConfigurationDescriptor( + confXmlDesc->ConfigurationDescriptor, + deviceInfo, + (PUSB_CONFIGURATION_DESCRIPTOR) commonDesc, + stringDesc); + break; + + case USB_INTERFACE_DESCRIPTOR_TYPE: + if ((commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR)) && + (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2))) + { + // Validate descriptor + confXmlDesc->InterfaceError = String::Format( + "ERROR: Interface bLength value incorrect Obtained: {0} Expected: {1} or {2}", + commonDesc->bLength, + sizeof(USB_INTERFACE_DESCRIPTOR), + sizeof(USB_INTERFACE_DESCRIPTOR2)); + displayUnknown = TRUE; + break; + } + + // Add interface descriptor + bInterfaceClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceClass; + bInterfaceSubclass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceSubClass; + bInterfaceProtocol = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceProtocol; + + confXmlDesc->InterfaceDescriptor = gcnew UsbDeviceInterfaceDescriptorType(); + XmlAddDeviceInterfaceDescriptor( + confXmlDesc->InterfaceDescriptor, + (PUSB_INTERFACE_DESCRIPTOR) commonDesc, + stringDesc + ); + + case USB_ENDPOINT_DESCRIPTOR_TYPE: + if ((commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR)) && + (commonDesc->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR2))) + { + // Validate endpoint descriptor + confXmlDesc->EndpointError = String::Format( + "ERROR: Endpoint bLength value incorrect Obtained: {0} Expected: {1} or {2}", + commonDesc->bLength, + sizeof(USB_ENDPOINT_DESCRIPTOR), + sizeof(USB_ENDPOINT_DESCRIPTOR2)); + displayUnknown = TRUE; + break; + } + + confXmlDesc->EndpointDescriptor = gcnew EndpointDescriptorType(); + + if (NULL != deviceInfo->ConnectionInfo) + { + // Add endpoint descriptor + XmlAddEndpointDescriptor( + confXmlDesc->EndpointDescriptor, + (PUSB_ENDPOINT_DESCRIPTOR) commonDesc, + deviceInfo->ConnectionInfo->Speed); + } + + break; + + case USB_HID_DESCRIPTOR_TYPE: + if (commonDesc->bLength < sizeof(USB_HID_DESCRIPTOR)) + { + // Validate HID + confXmlDesc->HidError = String::Format( + "ERROR: HID bLength value incorrect Obtained: {0} Expected: {1}", + commonDesc->bLength, + sizeof(USB_HID_DESCRIPTOR)); + displayUnknown = TRUE; + break; + } + + // Add HID descriptor + confXmlDesc->HidDescriptor = gcnew UsbDeviceHidDescriptorType(); + XmlAddHidDescriptor( + confXmlDesc->HidDescriptor, + (PUSB_HID_DESCRIPTOR) commonDesc + ); + break; + + case USB_OTG_DESCRIPTOR_TYPE: + if (commonDesc->bLength < sizeof(USB_OTG_DESCRIPTOR)) + { + // Validate length + confXmlDesc->HidError = String::Format( + "ERROR: OTG bLength value incorrect Obtained: {0} Expected: {1}", + commonDesc->bLength, + sizeof(USB_OTG_DESCRIPTOR)); + displayUnknown = TRUE; + break; + } + + // Add OTG descriptor + confXmlDesc->OtgDescriptor = gcnew UsbDeviceOTGDescriptorType(); + XmlAddOTGDescriptor( + confXmlDesc->OtgDescriptor, + (PUSB_OTG_DESCRIPTOR) commonDesc + ); + break; + + case USB_IAD_DESCRIPTOR_TYPE: + if (commonDesc->bLength < sizeof(USB_IAD_DESCRIPTOR)) + { + // Validate length + confXmlDesc->IadError = String::Format( + "ERROR: IAD bLength value incorrect", + commonDesc->bLength, + sizeof(USB_OTG_DESCRIPTOR)); + displayUnknown = TRUE; + } + + // Add IAD descriptor + confXmlDesc->IadDescriptor = gcnew UsbDeviceIADDescriptorType(); + XmlAddIADDescriptor( + confXmlDesc->IadDescriptor, + (PUSB_IAD_DESCRIPTOR) commonDesc, + stringDesc, + numInterfaces + ); + break; + + default: + // Interface class device (?) + confXmlDesc->DeviceDetails = XmlGetDeviceClass( + ((PUSB_INTERFACE_DESCRIPTOR) commonDesc)->bInterfaceClass, + ((PUSB_INTERFACE_DESCRIPTOR) commonDesc)->bInterfaceSubClass, + ((PUSB_INTERFACE_DESCRIPTOR) commonDesc)->bInterfaceProtocol + ); + break; + } + + if (displayUnknown) + { + // Add unknown descriptor + confXmlDesc->UnknownDescriptor = XmlGetUnknownDescriptor(commonDesc); + } + return; +} + +/***************************************************************************** + + XmlAddConnectionInfoSt() + + This routine adds connection information structures for the device + *****************************************************************************/ +void XmlAddConnectionInfoSt( + NodeConnectionInfoExStructType ^xmlConnectionInfoSt, + PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, + PDEVICE_INFO_NODE pNode) +{ + NodeConnectionInfoExStructType ^nS = xmlConnectionInfoSt; + + nS->ConnectionIndex = connectionInfo->ConnectionIndex; + + nS->DeviceDescriptor = gcnew UsbDeviceDescriptorType(); + + XmlAddUsbDeviceDescriptor(nS->DeviceDescriptor, &(connectionInfo->DeviceDescriptor)); + + nS->CurrentConfigurationValue = connectionInfo->CurrentConfigurationValue; + nS->Speed = connectionInfo->Speed; + nS->SpeedStr = static_cast<UsbConnectionSpeedType> (connectionInfo->Speed); + nS->DeviceIsHub = connectionInfo->DeviceIsHub? true: false; + nS->NumOfOpenPipes = connectionInfo->NumberOfOpenPipes; + nS->UsbConnectionStatus = static_cast<UsbConnectionStatusType> (connectionInfo->ConnectionStatus); + + if(NULL != pNode) + { + nS->DevicePowerState = static_cast<DevicePowerStateType>(pNode->LatestDevicePowerState); + } + else + { + nS->DevicePowerState = static_cast<DevicePowerStateType>(PowerDeviceUnspecified); + } + + // Add the pipe list + if (connectionInfo->NumberOfOpenPipes > 0) + { + nS->Pipe = gcnew array <UsbPipeInfoType ^>(connectionInfo->NumberOfOpenPipes); + XmlAddPipeInformation( + nS->Pipe, + connectionInfo->PipeList, + connectionInfo->NumberOfOpenPipes, + connectionInfo->Speed + ); + } + + return; +} + +/***************************************************************************** + + XmlGetLangIdString() + + Obtains the language string for given string descriptor index + *****************************************************************************/ +String ^ XmlGetLangIdString(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc) +{ + String ^langIdStr = nullptr; + bool foundDescriptor = false; + + while(stringDesc) + { + if (stringDesc->DescriptorIndex == index) + { + langIdStr = PACHAR_TO_STRING(GetLangIDString(stringDesc->LanguageID)); + + if (langIdStr == nullptr) + { + langIdStr = gcnew String("WARNING: Invalid language ID: " + stringDesc->LanguageID); + } + foundDescriptor = true; + break; + } + stringDesc = stringDesc->Next; + } + + if (foundDescriptor == false) + { + // If no descriptor was found, return error message in field + langIdStr = gcnew String("ERROR: No String descriptor for index " + index); + } + + return langIdStr; +} + +/***************************************************************************** + + XmlGetStringDescriptor() + + Obtains the string descriptor for given string descriptor index + *****************************************************************************/ + +String ^ XmlGetStringDescriptor(UCHAR index, PSTRING_DESCRIPTOR_NODE stringDesc, bool enOnly) +{ + ULONG nBytes = 0; + + CHAR pString[MAX_STRING_DESCRIPTOR_LENGTH]; + String ^desc = nullptr; + bool foundDescriptor = false; + bool foundNonEnglishDescriptor = false; + + ZeroMemory(pString, MAX_STRING_DESCRIPTOR_LENGTH); + + while(stringDesc) + { + if (stringDesc->DescriptorIndex == index) + { + if (enOnly && stringDesc->LanguageID != STRING_DESCRIPTOR_EN_LANGUAGE_ID) + { + // If we are required to return only english descriptor, continue + foundNonEnglishDescriptor = true; + continue; + } + + nBytes = WideCharToMultiByte( + CP_ACP, + WC_NO_BEST_FIT_CHARS, + stringDesc->StringDescriptor->bString, + (stringDesc->StringDescriptor->bLength -2)/2, + pString, + MAX_STRING_DESCRIPTOR_LENGTH, + NULL, + NULL + ); + + if (nBytes) + { + foundDescriptor = true; + desc = PACHAR_TO_STRING(pString); + } + break; + } + stringDesc = stringDesc->Next; + } + + if ((foundDescriptor == false) && (foundNonEnglishDescriptor == false)) + { + // If no descriptor was found, return error message in field + desc = gcnew String("ERROR: No String descriptor for index " + + index); + } + else if ((foundDescriptor == false) && (foundNonEnglishDescriptor == true) && (enOnly)) + { + desc = gcnew String("ERROR: The index " + index + " does not support English(US)"); + } + + return desc; +} + +/***************************************************************************** + + XmlGetDeviceClassString() + + Returns the device class string for given device class ID + *****************************************************************************/ + +String ^ XmlGetDeviceClassString(UCHAR deviceClass) +{ + String ^ deviceClassStr = nullptr; + + // Not an IAD device + switch (deviceClass) + { + case USB_INTERFACE_CLASS_DEVICE: + deviceClassStr = gcnew String("Interface Class Defined Device"); + break; + + case USB_COMMUNICATION_DEVICE: + deviceClassStr = gcnew String("Communication Device"); + break; + + case USB_HUB_DEVICE: + deviceClassStr = gcnew String("Hub Device"); + break; + + case USB_DIAGNOSTIC_DEVICE: + deviceClassStr = gcnew String("Diagnostic Device"); + break; + + case USB_WIRELESS_CONTROLLER_DEVICE: + deviceClassStr = gcnew String("Wireless Controller(Bluetooth) Device"); + break; + + case USB_VENDOR_SPECIFIC_DEVICE: + deviceClassStr = gcnew String("Vendor specific device"); + break; + + default: + deviceClassStr= gcnew String("ERROR: unknown bDeviceClass" + deviceClass); + break; + } + return deviceClassStr; +} + + +/***************************************************************************** + + XmlAddDeviceClassDetails() + + This routine adds device class details + *****************************************************************************/ +bool XmlAddDeviceClassDetails( + UsbDeviceClassDetailsType ^ deviceDetails, + PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, + PUSBDEVICEINFO deviceInfo) +{ + UINT uIADcount = 0; + bool tog = true; + + uIADcount = IsIADDevice((PUSBDEVICEINFO) deviceInfo); + + if (uIADcount) + { + // IAD device, check validity of device class + if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE) + { + tog = false; + deviceDetails->DeviceType = gcnew String("Multi-interface Function Code Device"); + } + else { + deviceDetails->DeviceTypeError = gcnew String("ERROR: device class should be Multi-interface Function " + + USB_MISCELLANEOUS_DEVICE + + "is used"); + } + deviceDetails->UvcVersion = IsUVCDevice((PUSBDEVICEINFO) deviceInfo); + + // This device configuration has 1 or more IAD descriptors + if (connectionInfo->DeviceDescriptor.bDeviceSubClass == USB_COMMON_SUB_CLASS) + { + deviceDetails->SubclassType = gcnew String("Common Class Sub Class"); + } + else + { + deviceDetails->SubclassTypeError = gcnew String("ERROR: device SubClass should be USB Common Sub Class" + + USB_COMMON_SUB_CLASS + + " when IAD descriptor is used"); + } + + // Check device protocol + if (connectionInfo->DeviceDescriptor.bDeviceProtocol == USB_IAD_PROTOCOL) + { + deviceDetails->DeviceProtocol = gcnew String("Interface Association Descriptor protocol"); + } + else + { + deviceDetails->DeviceProtocolError = gcnew String("ERROR: device Protocol should be USB IAD Protocol " + + USB_IAD_PROTOCOL + + " when IAD descriptor is used"); + } + + } + else + { + deviceDetails->DeviceType = XmlGetDeviceClassString(connectionInfo->DeviceDescriptor.bDeviceClass); + + if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE) + { + deviceDetails->DeviceTypeError = gcnew String("ERROR: Multi-interface Function code " + + connectionInfo->DeviceDescriptor.bDeviceClass + + " used for device with no IAD descriptors"); + } + + if (connectionInfo->DeviceDescriptor.bDeviceClass == USB_COMMUNICATION_DEVICE || + connectionInfo->DeviceDescriptor.bDeviceClass == USB_HUB_DEVICE || + connectionInfo->DeviceDescriptor.bDeviceClass == USB_DIAGNOSTIC_DEVICE || + connectionInfo->DeviceDescriptor.bDeviceClass == USB_WIRELESS_CONTROLLER_DEVICE || + connectionInfo->DeviceDescriptor.bDeviceClass == USB_MISCELLANEOUS_DEVICE || + connectionInfo->DeviceDescriptor.bDeviceClass == USB_VENDOR_SPECIFIC_DEVICE) + { + tog = false; + } + + // Not an IAD device, so all subclass values are invalid + if (connectionInfo->DeviceDescriptor.bDeviceSubClass > 0x00 && + connectionInfo->DeviceDescriptor.bDeviceSubClass < 0xFF) + { + deviceDetails->SubclassTypeError = gcnew String("ERROR: bDeviceSubClass is invalid - " + + connectionInfo->DeviceDescriptor.bDeviceSubClass); + } + + // Not an IAD device, so all subclass values are invalid, check protocol + if (connectionInfo->DeviceDescriptor.bDeviceProtocol > 0x00 && + connectionInfo->DeviceDescriptor.bDeviceProtocol < 0xFF && tog==1) + { + deviceDetails->DeviceProtocolError = gcnew String("ERROR: bDeviceProtocol is invalid - " + + connectionInfo->DeviceDescriptor.bDeviceProtocol); + } + } + + return tog; +} + +/***************************************************************************** + + XmlAddConnectionInfo() + + This routine adds connection information for the device + *****************************************************************************/ +void XmlAddConnectionInfo( + NodeConnectionInfoExType ^xmlConnectionInfo, + PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfo, + PUSBDEVICEINFO deviceInfo, + PSTRING_DESCRIPTOR_NODE stringDesc, + PDEVICE_INFO_NODE pNode) +{ + NodeConnectionInfoExType ^ nc = xmlConnectionInfo; + bool tog = true; + nc->ConnectionInfoStruct = gcnew NodeConnectionInfoExStructType(); + + // Update the structure + XmlAddConnectionInfoSt(nc->ConnectionInfoStruct, connectionInfo, pNode); + + // Add verbose fields + if (connectionInfo->ConnectionStatus == NoDeviceConnected) + { + // No device connected, nothing to do + return; + } + + if (connectionInfo->DeviceDescriptor.iProduct) + { + // Add EN version of string descriptor + + nc->IProductStringDescEn = XmlGetStringDescriptor( + connectionInfo->DeviceDescriptor.iProduct, + stringDesc, + true); + } + + // Check open pipes count + if (connectionInfo->NumberOfOpenPipes == 0) + { + nc->PipeInfoError = gcnew String("ERROR: No open pipes"); + } + + // Check device descriptor length + if (connectionInfo->DeviceDescriptor.bLength != DEVICE_DESCRIPTOR_LENGTH) + { + nc->LengthError = gcnew String("ERROR: bLength " + + connectionInfo->DeviceDescriptor.bLength + + " incorrect, should be " + + DEVICE_DESCRIPTOR_LENGTH + ); + } + + // Check for device error + if ((connectionInfo->ConnectionStatus == DeviceFailedEnumeration) || + (connectionInfo->ConnectionStatus == DeviceGeneralFailure)) + { + nc->DeviceError = gcnew String("ERROR: Device enumeration failure"); + } + else + { + nc->DeviceClassDetails = gcnew UsbDeviceClassDetailsType(); + + // Add device class details + tog = XmlAddDeviceClassDetails( + nc->DeviceClassDetails, + connectionInfo, + deviceInfo); + + nc->MaxPacketSizeInBytes = connectionInfo->DeviceDescriptor.bMaxPacketSize0; + + // Validate speed + switch (connectionInfo->Speed) + { + case UsbLowSpeed: + if (connectionInfo->DeviceDescriptor.bMaxPacketSize0 != 8) + { + nc->PacketSizeError = gcnew String("ERROR: Low Speed Devices require bMaxPacketSize0 = 8"); + } + break; + case UsbFullSpeed: + if (!(connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 8 || + connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 16 || + connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 32 || + connectionInfo->DeviceDescriptor.bMaxPacketSize0 == 64)) + { + nc->PacketSizeError = gcnew String("ERROR: Full Speed Devices require bMaxPacketSize0 = 8, 16, 32, or 64"); + } + break; + case UsbHighSpeed: + if (connectionInfo->DeviceDescriptor.bMaxPacketSize0 != 64) + { + nc->PacketSizeError = gcnew String("ERROR: High Speed Devices require bMaxPacketSize0 = 64"); + } + break; + } + + // Get string descriptors + nc->VendorString = PACHAR_TO_STRING(GetVendorString(connectionInfo->DeviceDescriptor.idVendor)); + + nc->ManufacturerString = XmlGetStringDescriptor(connectionInfo->DeviceDescriptor.iManufacturer, stringDesc, false); + nc->ProductString = XmlGetStringDescriptor(connectionInfo->DeviceDescriptor.iProduct, stringDesc, false); + nc->LangIdString = XmlGetLangIdString(connectionInfo->DeviceDescriptor.iProduct, stringDesc); + nc->SerialString = XmlGetStringDescriptor(connectionInfo->DeviceDescriptor.iSerialNumber, stringDesc, false); + + // Validate configuration + if (connectionInfo->DeviceDescriptor.bNumConfigurations != 1) + { + nc->ConfigurationCountError = gcnew String("WARNING: Most host controllers will only work with "\ + "one configuration per speed"); + } + } + return; +} + + +/***************************************************************************** + + XmlAddExternalHub() + + Add a external to the parent Host Controller or hub. This is determined by the + last object pushed on the stack + *****************************************************************************/ +HRESULT XmlAddExternalHub(PSTR ehName, PUSBEXTERNALHUBINFO ehInfo) +{ + HRESULT hr = S_OK; + Object ^ parent = gXmlStack->Peek(); + ExternalHubType ^exHub = nullptr; + + UNREFERENCED_PARAMETER(ehName); + + if (NULL == ehInfo) + { + return E_FAIL; + } + + exHub = AddExternalHub(parent); + + if (exHub != nullptr) + { + exHub->HubName = PACHAR_TO_STRING(ehInfo->HubName); + + if (NULL != ehInfo->UsbDeviceProperties) + { + exHub->HwId = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->HwId); + exHub->DeviceId = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->DeviceId); + exHub->ServiceName = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->Service); + exHub->DeviceName = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->DeviceDesc); + exHub->DeviceClass = PACHAR_TO_STRING(ehInfo->UsbDeviceProperties->DeviceClass); + } + + exHub->HubNodeInformation = gcnew HubNodeInformationType(); + XmlAddHubNodeInformation(exHub->HubNodeInformation, ehInfo->HubInfo); + + exHub->HubInformationEx = gcnew HubInformationExType(); + XmlAddHubInformationEx(exHub->HubInformationEx, ehInfo->HubInfoEx); + + exHub->HubCapabilityEx = gcnew HubCapabilitiesExType(); + XmlAddHubCapabilitiesEx(exHub->HubCapabilityEx, ehInfo->HubCapabilityEx); + + exHub->ConnectionInfo = gcnew NodeConnectionInfoExType(); + + // Update protocol + if (NULL != ehInfo->ConnectionInfo) + { + switch(ehInfo->ConnectionInfo->Speed) + { + case UsbLowSpeed: + case UsbFullSpeed: + exHub->UsbProtocol = gcnew String(USB_1_1); + break; + case UsbHighSpeed: + exHub->UsbProtocol = gcnew String(USB_2_0); + break; + case UsbSuperSpeed: + exHub->UsbProtocol = gcnew String(USB_3_0); + break; + } + } + + // Add connection info + XmlAddConnectionInfo( + exHub->ConnectionInfo, + ehInfo->ConnectionInfo, + (PUSBDEVICEINFO) ehInfo, + ehInfo->StringDescs, + ehInfo->DeviceInfoNode + ); + + // Add port connectors + if (NULL != ehInfo->PortConnectorProps) + { + exHub->PortConnector = gcnew PortConnectorType(); + + XmlAddPortConnectorProps( + exHub->PortConnector, + ehInfo->PortConnectorProps + ); + } + // Add connection info V2 + exHub->ConnectionInfoV2 = gcnew NodeConnectionInfoExV2Type(); + + XmlAddConnectionInfoV2( + exHub->ConnectionInfoV2, + ehInfo->ConnectionInfoV2 + ); + + // Add configuration descriptor + if (NULL != ehInfo->ConfigDesc) + { + exHub->DeviceConfiguration = XmlGetConfigDescriptors( + (PUSBDEVICEINFO) ehInfo, + (PUSB_CONFIGURATION_DESCRIPTOR) (ehInfo->ConfigDesc + 1), + ehInfo->StringDescs + ); + } + + // Add BOS descriptor + if (NULL != ehInfo->BosDesc) + { + exHub->BosDescriptor = XmlGetBosDescriptor((PUSB_BOS_DESCRIPTOR) (ehInfo->BosDesc + 1)); + } + + gXmlStack->Push(exHub); + } + else + { + hr = E_FAIL; + } + return hr; +} + +/***************************************************************************** + + XmlGetBosDescriptor() + + Gets the Bos descriptor object for given BOS descriptor + *****************************************************************************/ +UsbBosDescriptorType ^ XmlGetBosDescriptor(PUSB_BOS_DESCRIPTOR bosDesc) +{ + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + PUSB_DEVICE_CAPABILITY_DESCRIPTOR capDesc = NULL; + UsbBosDescriptorType ^ bosXmlDesc = nullptr; + ArrayList ^usb20CapExtDescList = gcnew ArrayList(); + ArrayList ^usbSuperSpeedExtDescList = gcnew ArrayList(); + ArrayList ^usbContIdCapExtDescList = gcnew ArrayList(); + ArrayList ^usbUnknownDescList = gcnew ArrayList(); + + if(NULL == bosDesc) + { + return nullptr; + } + + // Initialize attributes + bosXmlDesc = gcnew UsbBosDescriptorType(); + bosXmlDesc->BLength = bosDesc->bLength; + bosXmlDesc->BDescriptorType = bosDesc->bDescriptorType; + bosXmlDesc->WTotalLength = bosDesc->wTotalLength; + bosXmlDesc->BNumDeviceCaps = 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: + usb20CapExtDescList->Add( + XmlGetUsb20CapabilityExtensionDescriptor( + (PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR)capDesc + ) + ); + break; + case USB_DEVICE_CAPABILITY_SUPERSPEED_USB: + usbSuperSpeedExtDescList->Add( + XmlGetSuperSpeedCapabilityExtensionDescriptor( + (PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR)capDesc + ) + ); + break; + case USB_DEVICE_CAPABILITY_CONTAINER_ID: + usbContIdCapExtDescList->Add( + XmlGetContainerIdCapabilityExtensionDescriptor( + (PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR)capDesc + ) + ); + break; + default: + usbUnknownDescList->Add( + XmlGetUnknownDescriptor( + (PUSB_COMMON_DESCRIPTOR) capDesc + ) + ); + break; + } + break; + default: + usbUnknownDescList->Add(XmlGetUnknownDescriptor(commonDesc)); + break; + } + } + + // Convert lists to arrays for and add to Bos Descriptor + bosXmlDesc->UnknownDescriptor = reinterpret_cast<array<UsbDeviceUnknownDescriptorType ^>^> ( + usbUnknownDescList->ToArray(UsbDeviceUnknownDescriptorType::typeid) + ); + bosXmlDesc->UsbSuperSpeedExtensionDescriptor = reinterpret_cast<array<UsbSuperSpeedExtensionDescriptorType ^>^> ( + usbSuperSpeedExtDescList->ToArray(UsbSuperSpeedExtensionDescriptorType::typeid) + ); + bosXmlDesc->UsbUsb20ExtensionDescriptor = reinterpret_cast<array<UsbUsb20ExtensionDescriptorType ^>^> ( + usb20CapExtDescList->ToArray(UsbUsb20ExtensionDescriptorType::typeid) + ); + bosXmlDesc->UsbDispContIdCapExtDescriptor = reinterpret_cast<array<UsbDispContIdCapExtDescriptorType ^>^> ( + usbContIdCapExtDescList->ToArray(UsbDispContIdCapExtDescriptorType::typeid) + ); + + return bosXmlDesc; +} + + +/***************************************************************************** + + XmlGetUsb20CapabilityExtensionDescriptor() + + Gets a Usb20Capability extension descriptor object from the given descriptor + *****************************************************************************/ +UsbUsb20ExtensionDescriptorType ^ XmlGetUsb20CapabilityExtensionDescriptor( + PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR capDesc + ) +{ + UsbUsb20ExtensionDescriptorType ^ capXmlDesc = nullptr; + + if(NULL == capDesc) + { + return nullptr; + } + + capXmlDesc = gcnew UsbUsb20ExtensionDescriptorType(); + + capXmlDesc->BLength = capDesc->bLength; + capXmlDesc->BDescriptorType = capDesc->bDescriptorType; + capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType; + capXmlDesc->BmAttributes = capDesc->bmAttributes.AsUlong; + + if (capDesc->bmAttributes.AsUlong & USB_DEVICE_CAPABILITY_USB20_EXTENSION_BMATTRIBUTES_RESERVED_MASK) + { + capXmlDesc->ReservedBitError = gcnew String("ERROR: bits 31..2 and bit 0 are reserved and must be 0"); + } + if (capDesc->bmAttributes.LPMCapable == 1) + { + capXmlDesc->SupportsLinkPowerManagement = true; + } + + return capXmlDesc; +} + +/***************************************************************************** + + XmlGetSuperSpeedCapabilityExtensionDescriptor() + + Gets a Super speed capability extension descriptor object from the given descriptor + *****************************************************************************/ +UsbSuperSpeedExtensionDescriptorType ^ XmlGetSuperSpeedCapabilityExtensionDescriptor( + PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR capDesc + ) +{ + UsbSuperSpeedExtensionDescriptorType ^ capXmlDesc = nullptr; + + if(NULL == capDesc) + { + return nullptr; + } + + capXmlDesc = gcnew UsbSuperSpeedExtensionDescriptorType(); + + capXmlDesc->BLength = capDesc->bLength; + capXmlDesc->BDescriptorType = capDesc->bDescriptorType; + capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType; + capXmlDesc->BmAttributes = capDesc->bmAttributes; + capXmlDesc->BU1DevExitLat = capDesc->bU1DevExitLat; + capXmlDesc->WSpeedsSupported = capDesc->wSpeedsSupported; + capXmlDesc->WU2DevExitLat = capDesc->wU2DevExitLat; + capXmlDesc->BFunctionalitySupport = capDesc->bFunctionalitySupport; + + // Add descriptive fields + if (capDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_RESERVED_MASK) + { + capXmlDesc->ReservedAttributesBitError = gcnew String("ERROR: bits 7:2 and bit 0 are reserved"); + } + if (capDesc->bmAttributes & USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_LTM_CAPABLE) + { + capXmlDesc->LatencyToleranceMsgCapable = true; + } + if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_LOW) + { + capXmlDesc->SupportsLowSpeed = true; + } + if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_FULL) + { + capXmlDesc->SupportsFullSpeed = true; + } + if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_HIGH) + { + capXmlDesc->SupportsHighSpeed = true; + } + if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_SUPER) + { + capXmlDesc->SupportsSuperSpeed = true; + } + if (capDesc->wSpeedsSupported & USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_RESERVED_MASK) + { + capXmlDesc->ReservedSpeedError = gcnew String("ERROR: bits 15:4 are reserved"); + } + + + switch (capDesc->bFunctionalitySupport) + { + case UsbLowSpeed: + capXmlDesc->LowestSpeed = gcnew String("low-speed"); + break; + case UsbFullSpeed: + capXmlDesc->LowestSpeed = gcnew String("full-speed"); + break; + case UsbHighSpeed: + capXmlDesc->LowestSpeed = gcnew String("high-speed"); + break; + case UsbSuperSpeed: + capXmlDesc->LowestSpeed = gcnew String("SuperSpeed"); + break; + default: + capXmlDesc->LowestSpeed = gcnew String("ERROR: Invalid value"); + break; + } + + if (capDesc->bU1DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U1_DEVICE_EXIT_MAX_VALUE) + { + capXmlDesc->U1DevExitLatencyString = String::Format("Less than {0} micro-seconds", capDesc->bU1DevExitLat); + } + else + { + capXmlDesc->U1DevExitLatencyString = gcnew String("ERROR: Invalid value"); + } + + if (capDesc->wU2DevExitLat <= USB_DEVICE_CAPABILITY_SUPERSPEED_U2_DEVICE_EXIT_MAX_VALUE) + { + capXmlDesc->U2DevExitLatencyString = String::Format("Less than {0} micro-seconds", capDesc->wU2DevExitLat); + } + else + { + capXmlDesc->U2DevExitLatencyString = gcnew String("ERROR: Invalid value"); + } + + return capXmlDesc; +} + +/***************************************************************************** + + XmlGetContainerIdCapabilityExtensionDescriptor() + + Gets a Usb20Capability extension descriptor object from the given descriptor + *****************************************************************************/ +UsbDispContIdCapExtDescriptorType ^ XmlGetContainerIdCapabilityExtensionDescriptor( + PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR capDesc + ) +{ + UsbDispContIdCapExtDescriptorType ^ capXmlDesc = nullptr; + LPGUID pGuid = NULL; + + if(NULL == capDesc) + { + return nullptr; + } + + capXmlDesc = gcnew UsbDispContIdCapExtDescriptorType(); + + capXmlDesc->BLength = capDesc->bLength; + capXmlDesc->BDescriptorType = capDesc->bDescriptorType; + capXmlDesc->BDevCapabilityType = capDesc->bDevCapabilityType; + capXmlDesc->BReserved = capDesc->bReserved; + + if (capDesc->bReserved != 0) + { + capXmlDesc->ReservedBitError = gcnew String("ERROR: field is reserved and should be zero"); + } + + pGuid = (LPGUID) capDesc->ContainerID; + + capXmlDesc->ContainerIdStr = String::Format("{0:X}-{1:X}-{2:X}-{3:X}{4:X}-{5:X}{6:X}{7:X}{8:X}{9:X}{10:X}", + 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]); + + return capXmlDesc; +} + +/***************************************************************************** + + XmlAddUsbDevice() + + Add a external to the parent Host Controller or hub. This is determined by the + last object pushed on the stack + *****************************************************************************/ +HRESULT XmlAddUsbDevice(PSTR devName, PUSBDEVICEINFO deviceInfo) +{ + HRESULT hr = S_OK; + Object ^ parent = gXmlStack->Peek(); + UsbDeviceType ^usbDevice = nullptr; + NoDeviceType ^noDevice = nullptr; + + if (NULL == deviceInfo) + { + return E_FAIL; + } + + if (deviceInfo->ConfigDesc == NULL) + { + // There is no USB device on this port, add a NoDevice type here instead of USB device + noDevice = AddDisconnectedPort(parent); + + if (nullptr != noDevice) + { + noDevice->UsbPortNumber = gcnew String(""); + noDevice->UsbPortNumber += deviceInfo->ConnectionInfo->ConnectionIndex; + noDevice->Name = PACHAR_TO_STRING(devName); + } + else + { + hr = E_FAIL; + } + } + + else + { + usbDevice = AddUsbDevice(parent); + + if (nullptr != usbDevice) + { + // Update device information + if (NULL != deviceInfo->UsbDeviceProperties) + { + usbDevice->HwId = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->HwId); + usbDevice->DeviceId = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->DeviceId); + usbDevice->ServiceName = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->Service); + usbDevice->DeviceName = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->DeviceDesc); + usbDevice->DeviceClass = PACHAR_TO_STRING(deviceInfo->UsbDeviceProperties->DeviceClass); + } + + // Update port number + usbDevice->UsbPortNumber = gcnew String(""); + usbDevice->UsbPortNumber += deviceInfo->ConnectionInfo->ConnectionIndex; + usbDevice->ConnectionInfo = gcnew NodeConnectionInfoExType(); + + // Update protocol + if (NULL != deviceInfo->ConnectionInfo) + { + switch(deviceInfo->ConnectionInfo->Speed) + { + case UsbLowSpeed: + case UsbFullSpeed: + usbDevice->UsbProtocol = gcnew String(USB_1_1); + break; + case UsbHighSpeed: + usbDevice->UsbProtocol = gcnew String(USB_2_0); + break; + case UsbSuperSpeed: + usbDevice->UsbProtocol = gcnew String(USB_3_0); + break; + } + } + + // Add connection info + XmlAddConnectionInfo( + usbDevice->ConnectionInfo, + deviceInfo->ConnectionInfo, + (PUSBDEVICEINFO) deviceInfo, + deviceInfo->StringDescs, + deviceInfo->DeviceInfoNode + ); + + // Add port connector + if (NULL != deviceInfo->PortConnectorProps) + { + usbDevice->PortConnector = gcnew PortConnectorType(); + + XmlAddPortConnectorProps( + usbDevice->PortConnector, + deviceInfo->PortConnectorProps + ); + } + + // Add connectiontion info V2 + if (NULL != deviceInfo->ConnectionInfoV2) + { + usbDevice->ConnectionInfoV2 = gcnew NodeConnectionInfoExV2Type(); + XmlAddConnectionInfoV2( + usbDevice->ConnectionInfoV2, + deviceInfo->ConnectionInfoV2 + ); + } + + // Add configuration descriptor + if (NULL != deviceInfo->ConfigDesc) + { + // The device configuration is allocated by XmlGetConfigDescriptors() + usbDevice->DeviceConfiguration = XmlGetConfigDescriptors( + (PUSBDEVICEINFO) deviceInfo, + (PUSB_CONFIGURATION_DESCRIPTOR) (deviceInfo->ConfigDesc + 1), + deviceInfo->StringDescs + ); + } + + // Add BOS descriptor + if (NULL != deviceInfo->BosDesc) + { + usbDevice->BosDescriptor = XmlGetBosDescriptor((PUSB_BOS_DESCRIPTOR) (deviceInfo->BosDesc + 1)); + } + } + else + { + hr = E_FAIL; + } + } + return hr; +} + +/***************************************************************************** + + XmlAddRootHub() + + Add a root hub to the parent Host Controller + *****************************************************************************/ +HRESULT XmlAddRootHub(PSTR rhName, PUSBROOTHUBINFO rhInfo) +{ + HRESULT hr = S_OK; + Object ^ parent = gXmlStack->Peek(); + HostControllerType ^ hcParent = nullptr; + PSTR rootHubName = rhInfo->HubName; + + UNREFERENCED_PARAMETER(rhName); + + hcParent = dynamic_cast<HostControllerType ^> (parent); + + if (hcParent != nullptr) + { + RootHubType ^ rh = nullptr; + hcParent = (HostControllerType ^) parent; + hcParent->RootHub = gcnew RootHubType(); + + rh = hcParent->RootHub; + rh->HubName = PACHAR_TO_STRING(rootHubName); + + if (NULL != rhInfo->UsbDeviceProperties) + { + rh->HwId = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->HwId); + rh->DeviceId = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->DeviceId); + rh->ServiceName = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->Service); + rh->DeviceName = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->DeviceDesc); + rh->DeviceClass = PACHAR_TO_STRING(rhInfo->UsbDeviceProperties->DeviceClass); + + // Roothub protocol is same as HC protocol + rh->UsbProtocol = hcParent->UsbProtocol; + } + + rh->HubNodeInformation = gcnew HubNodeInformationType(); + XmlAddHubNodeInformation(rh->HubNodeInformation, rhInfo->HubInfo); + + rh->HubInformationEx = gcnew HubInformationExType(); + XmlAddHubInformationEx(rh->HubInformationEx, rhInfo->HubInfoEx); + + rh->HubCapabilityEx = gcnew HubCapabilitiesExType(); + XmlAddHubCapabilitiesEx(rh->HubCapabilityEx, rhInfo->HubCapabilityEx); + + // Push root hub on to stack + gXmlStack->Push(rh); + } + else + { + // Root hub should be connected to a host controller + hr = E_FAIL; + } + return S_OK; +} + +/***************************************************************************** + + XmlSetVersion() + + Set version information in XML tree + *****************************************************************************/ +VOID XmlSetVersion( + UCHAR uvcMajorVersion, + UCHAR uvcMinorVersion, + UCHAR uvcMajorSpecVersion, + UCHAR uvcMinorSpecVersion + ) +{ + MachineInfoType ^ mInfo; + gXmlView->MachineInfo = gcnew MachineInfoType(); + + mInfo = gXmlView->MachineInfo; + + mInfo->UvcMajorVersion = uvcMajorVersion; + mInfo->UvcMinorVersion = uvcMinorVersion; + mInfo->UvcMajorSpecVersion = uvcMajorSpecVersion; + mInfo->UvcMinorSpecVersion = uvcMinorSpecVersion; + +} + +/***************************************************************************** + + InitXmlHelper() + + Initialize XML helper + *****************************************************************************/ +HRESULT InitXmlHelper() +{ + HRESULT hr = S_OK; + + (XmlGlobal::Instance())->ViewAll = gcnew UvcViewAll(); + (XmlGlobal::Instance())->ViewAll->UvcView = gcnew UvcViewType(); + + // + // Initialize fields to null so we can check against them for allocation + // + (XmlGlobal::Instance())->ViewAll->UvcView->MachineInfo = nullptr; + (XmlGlobal::Instance())->ViewAll->UvcView->UsbTree = nullptr; + + XmlSetVersion( + UVC_SPEC_MAJOR_VERSION, + UVC_SPEC_MINOR_VERSION, + USBVIEW_MAJOR_VERSION, + USBVIEW_MINOR_VERSION + ); + + gXmlStack->Push(gXmlView); + + gXmlViewInitialized = TRUE; + + return hr; +} + +/***************************************************************************** + + SaveXml() + + Saves the inmemory USB view as XML file + *****************************************************************************/ +HRESULT SaveXml(LPTSTR szfileName, DWORD dwCreationDisposition) +{ + HRESULT hr = S_OK; + + if (gXmlViewInitialized) + { + try + { + String ^fileName = PACHAR_TO_STRING(szfileName); + XmlSerializer ^ serializer = gcnew XmlSerializer(UvcViewAll::typeid); + TextWriter ^ writer = nullptr; + + if (dwCreationDisposition != CREATE_ALWAYS) + { + // Check if file exits and return failure if it does + if (File::Exists(fileName)) + { + hr = HRESULT_FROM_WIN32(ERROR_FILE_EXISTS); + } + } + + // Check if file name is NULL + if (String::IsNullOrEmpty(fileName)) + { + hr = E_INVALIDARG; + } + + if (SUCCEEDED(hr)) + { + writer = gcnew StreamWriter(fileName); + serializer->Serialize(writer, (XmlGlobal::Instance())->ViewAll); + writer->Close(); + } + + // Release and reinit XML View for next iteration if requested + ReleaseXmlWriter(); + InitXmlHelper(); + + } + catch(Exception ^ ex) + { + hr = (HRESULT) Marshal::GetHRForException(ex); + } + } + else + { + hr = E_FAIL; + } + + return hr; +} + + +/***************************************************************************** + + ReleaseXmlWriter() + + *****************************************************************************/ +HRESULT ReleaseXmlWriter() +{ + HRESULT hr = S_OK; + + if (gXmlViewInitialized) + { + gXmlViewInitialized = FALSE; + delete XmlGlobal::Instance(); + } + + return hr; +} + |
