diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2cecbd --- /dev/null +++ b/.gitignore @@ -0,0 +1,399 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +build*/ +out/ +samples/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7a9ae71 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,64 @@ +# CMakeList.txt : CMake project for Win32Test, include source and define +# project specific logic here. +# +cmake_minimum_required (VERSION 3.16) +cmake_policy(SET CMP0091 NEW) +project ("Win32Test" LANGUAGES C CXX VERSION 0.1) +include(FetchContent) + +# find static libraries (so MT can work ??) +# set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +# set(BUILD_SHARED_LIBS OFF) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") + +FetchContent_Declare(json + GIT_REPOSITORY https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent + GIT_TAG v3.9.1) + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + add_compile_options(/ZH:SHA_256 /W4 /permissive- /Zc:__cplusplus) +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + add_compile_options(-Wall -Werror -fno-permissive) +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + add_compile_options(-Wall -Werror -fno-permissive) +endif() + +if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release") + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + add_compile_options(/O2 /Ot /Oi /Ob3 /GL) + add_link_options(/LTCG) + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + add_compile_options(-O3 -fsanitize=undefined,address) + add_link_options(-fsanitize=undefined,address) + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + add_compile_options(-O3 -fsanitize=undefined,address -fsanitize-blacklist=C:/Users/dhina/Documents/GitHub/Win32Testv2/fsanitize-blacklist.txt) + add_link_options(-fsanitize=undefined,address -fsanitize-blacklist=C:/Users/dhina/Documents/GitHub/Win32Testv2/fsanitize-blacklist.txt) + endif() +endif() + +FetchContent_GetProperties(json) +if(NOT json_POPULATED) + FetchContent_Populate(json) + add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL) +endif() + +add_compile_definitions(UNICODE) + +# Add source to this project's executable. +add_executable (usbdump "Win32Test.cpp" "enum.cpp" "devnode.cpp" "Win32Test.h" "usbdesc.h" "uvcdesc.h" "uvcview.h") +set_property(TARGET usbdump PROPERTY + MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + +target_link_libraries(usbdump + PRIVATE + setupapi + nlohmann_json::nlohmann_json +) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..efcd4c4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,23 @@ +The Microsoft Public License (MS-PL) +Copyright (c) 2015 Microsoft + +This license governs use of the accompanying software. If you use the software, you + accept this license. If you do not accept the license, do not use the software. + +1. Definitions + The terms "reproduce," "reproduction," "derivative works," and "distribution" have the + same meaning here as under U.S. copyright law. + A "contribution" is the original software, or any additions or changes to the software. + A "contributor" is any person that distributes its contribution under this license. + "Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights + (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations + (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. + (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. + (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. + (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..fc309f7 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# usbdump + +Tool to serialize USB info to JSON. Modified from [USBView](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/usbview) from [Windows driver samples](https://github.com/Microsoft/Windows-driver-samples/tree/master/usb/usbview). Additional modifications (besides serialization) include Unicode support. + +## Known Issues + +Basically nothing is freed + +## Credits + +Microsoft for USBView + +@nlohmann for [the json library](https://github.com/nlohmann/json) diff --git a/Win32Test.cpp b/Win32Test.cpp new file mode 100644 index 0000000..4c39023 --- /dev/null +++ b/Win32Test.cpp @@ -0,0 +1,40 @@ +// Win32Test.cpp : Defines the entry point for the application. +// + +#include "Win32Test.h" + +using namespace std; +using json = nlohmann::json; + +void initGlobals() { + gHubList.DeviceInfo = INVALID_HANDLE_VALUE; + InitializeListHead(&gHubList.ListHead); + gDeviceList.DeviceInfo = INVALID_HANDLE_VALUE; + InitializeListHead(&gDeviceList.ListHead); +} + +int main(int argc, char* argv[]) { + if (argc >= 2) { + if (std::string(argv[1]) == "--version" || std::string(argv[1]) == "-v") { + std::cout << TOOL_VERSION << std::endl; + return 0; + } else { + return 1; + } + } + initGlobals(); + + ULONG devicesConnected; + + std::vector hostControllers = EnumerateHostControllers((HTREEITEM)1, &devicesConnected); + json ree = hostControllers; + std::cout << ree.dump(4) << std::endl; + /* for (const auto& hostController : hostControllers) { + // std::cout << hostController->DriverKey << std::endl; + json ree = hostController; + std::cout << ree.dump(4) << std::endl; + } */ + + // std::cout << "Done" << std::endl; + return 0; +} diff --git a/Win32Test.h b/Win32Test.h new file mode 100644 index 0000000..d43b66a --- /dev/null +++ b/Win32Test.h @@ -0,0 +1,50 @@ +// Win32Test.h : Include file for standard system include files, +// or project specific include files. + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uvcview.h" +#include "specializations.hpp" +#include "nlohmann/json.hpp" + +#define TOOL_VERSION "0.1.0" + + +#define QUICKCOUT(...) std::cout << __VA_ARGS__ << std::endl + + +extern DEVICE_GUID_LIST gHubList; +extern DEVICE_GUID_LIST gDeviceList; + +struct HandleDeleter +{ + // By defining the pointer type, we can delete a type other than T*. + // In other words, we can declare unique_ptr instead of + // unique_ptr which leaks the HANDLE abstraction. + typedef HANDLE pointer; + + void operator()(HANDLE h) + { + if(h != INVALID_HANDLE_VALUE) + { + CloseHandle(h); + } + } +}; + +typedef std::unique_ptr handle_unique_ptr; + diff --git a/devnode.cpp b/devnode.cpp new file mode 100644 index 0000000..014b970 --- /dev/null +++ b/devnode.cpp @@ -0,0 +1,349 @@ +/*++ + + Copyright (c) 1998-2011 Microsoft Corporation + + Module Name: + + DEVNODE.C + + --*/ + +/***************************************************************************** + I N C L U D E S + *****************************************************************************/ + +#include "uvcview.h" + +/***************************************************************************** + + DriverNameToDeviceInst() + + Finds the Device instance of the DevNode with the matching DriverName. + Returns FALSE if the matching DevNode is not found and TRUE if found + + *****************************************************************************/ +BOOL +DriverNameToDeviceInst( + _In_reads_bytes_(cbDriverName) PWCHAR DriverName, + _In_ size_t cbDriverName, + _Out_ HDEVINFO *pDevInfo, + _Out_writes_bytes_(sizeof(SP_DEVINFO_DATA)) PSP_DEVINFO_DATA pDevInfoData + ) +{ + HDEVINFO deviceInfo = INVALID_HANDLE_VALUE; + BOOL status = TRUE; + ULONG deviceIndex; + SP_DEVINFO_DATA deviceInfoData; + BOOL bResult = FALSE; + PWCHAR pDriverName = NULL; + PWSTR buf = NULL; + BOOL done = FALSE; + + if (pDevInfo == NULL) + { + return FALSE; + } + + if (pDevInfoData == NULL) + { + return FALSE; + } + + memset(pDevInfoData, 0, sizeof(SP_DEVINFO_DATA)); + + *pDevInfo = INVALID_HANDLE_VALUE; + + // Use local string to guarantee zero termination + pDriverName = (PWCHAR) ALLOC((DWORD) cbDriverName + sizeof(WCHAR)); + if (NULL == pDriverName) + { + status = FALSE; + goto Done; + } + StringCbCopyN(pDriverName, cbDriverName + sizeof(WCHAR), DriverName, cbDriverName); + + // + // We cannot walk the device tree with CM_Get_Sibling etc. unless we assume + // the device tree will stabilize. Any devnode removal (even outside of USB) + // would force us to retry. Instead we use Setup API to snapshot all + // devices. + // + + // Examine all present devices to see if any match the given DriverName + // + deviceInfo = SetupDiGetClassDevs(NULL, + NULL, + NULL, + DIGCF_ALLCLASSES | DIGCF_PRESENT); + + if (deviceInfo == INVALID_HANDLE_VALUE) + { + status = FALSE; + goto Done; + } + + deviceIndex = 0; + deviceInfoData.cbSize = sizeof(deviceInfoData); + + while (done == FALSE) + { + // + // Get devinst of the next device + // + + status = SetupDiEnumDeviceInfo(deviceInfo, + deviceIndex, + &deviceInfoData); + + deviceIndex++; + + if (!status) + { + // + // This could be an error, or indication that all devices have been + // processed. Either way the desired device was not found. + // + + done = TRUE; + break; + } + + // + // Get the DriverName value + // + + bResult = GetDeviceProperty(deviceInfo, + &deviceInfoData, + SPDRP_DRIVER, + &buf); + + // If the DriverName value matches, return the DeviceInstance + // + if (bResult == TRUE && buf != NULL && _wcsicmp(pDriverName, buf) == 0) + { + done = TRUE; + *pDevInfo = deviceInfo; + CopyMemory(pDevInfoData, &deviceInfoData, sizeof(deviceInfoData)); + FREE(buf); + break; + } + + if(buf != NULL) + { + FREE(buf); + buf = NULL; + } + } + +Done: + + if (bResult == FALSE) + { + if (deviceInfo != INVALID_HANDLE_VALUE) + { + SetupDiDestroyDeviceInfoList(deviceInfo); + } + } + + if (pDriverName != NULL) + { + FREE(pDriverName); + } + + return status; +} + +/***************************************************************************** + + DriverNameToDeviceProperties() + + Returns the Device properties of the DevNode with the matching DriverName. + Returns NULL if the matching DevNode is not found. + + The caller should free the returned structure using FREE() macro + + *****************************************************************************/ +PUSB_DEVICE_PNP_STRINGS +DriverNameToDeviceProperties( + _In_reads_bytes_(cbDriverName) PWCHAR DriverName, + _In_ size_t cbDriverName + ) +{ + HDEVINFO deviceInfo = INVALID_HANDLE_VALUE; + SP_DEVINFO_DATA deviceInfoData = {0}; + ULONG len; + BOOL status; + PUSB_DEVICE_PNP_STRINGS DevProps = NULL; + DWORD lastError; + + // Allocate device propeties structure + DevProps = (PUSB_DEVICE_PNP_STRINGS) ALLOC(sizeof(USB_DEVICE_PNP_STRINGS)); + + if(NULL == DevProps) + { + status = FALSE; + goto Done; + } + + // Get device instance + status = DriverNameToDeviceInst(DriverName, cbDriverName, &deviceInfo, &deviceInfoData); + if (status == FALSE) + { + goto Done; + } + + len = 0; + status = SetupDiGetDeviceInstanceId(deviceInfo, + &deviceInfoData, + NULL, + 0, + &len); + lastError = GetLastError(); + + + if (status != FALSE && lastError != ERROR_INSUFFICIENT_BUFFER) + { + status = FALSE; + goto Done; + } + + // + // An extra byte is required for the terminating character + // + + len++; + DevProps->DeviceId = (PWCHAR)ALLOC(len * sizeof(WCHAR)); + + if (DevProps->DeviceId == NULL) + { + status = FALSE; + goto Done; + } + + status = SetupDiGetDeviceInstanceId(deviceInfo, + &deviceInfoData, + DevProps->DeviceId, + len, + &len); + if (status == FALSE) + { + goto Done; + } + + status = GetDeviceProperty(deviceInfo, + &deviceInfoData, + SPDRP_DEVICEDESC, + &DevProps->DeviceDesc); + + if (status == FALSE) + { + goto Done; + } + + + // + // We don't fail if the following registry query fails as these fields are additional information only + // + #ifdef SERIALIZE_VERBOSE + GetDeviceProperty(deviceInfo, + &deviceInfoData, + SPDRP_HARDWAREID, + &DevProps->HwId); + + GetDeviceProperty(deviceInfo, + &deviceInfoData, + SPDRP_SERVICE, + &DevProps->Service); + + GetDeviceProperty(deviceInfo, + &deviceInfoData, + SPDRP_CLASS, + &DevProps->DeviceClass); + #endif +Done: + + if (deviceInfo != INVALID_HANDLE_VALUE) + { + SetupDiDestroyDeviceInfoList(deviceInfo); + } + + if (status == FALSE) + { + if (DevProps != NULL) + { + FreeDeviceProperties(&DevProps); + } + } + return DevProps; +} + +/***************************************************************************** + + FreeDeviceProperties() + + Free the device properties structure + + *****************************************************************************/ +VOID FreeDeviceProperties(_In_ PUSB_DEVICE_PNP_STRINGS *ppDevProps) +{ + if(ppDevProps == NULL) + { + return; + } + + if(*ppDevProps == NULL) + { + return; + } + + if ((*ppDevProps)->DeviceId != NULL) + { + FREE((*ppDevProps)->DeviceId); + } + + if ((*ppDevProps)->DeviceDesc != NULL) + { + FREE((*ppDevProps)->DeviceDesc); + } + + // + // The following are not necessary, but left in case + // in the future there is a later failure where these + // pointer fields would be allocated. + // + + if ((*ppDevProps)->HwId != NULL) + { + FREE((*ppDevProps)->HwId); + } + + if ((*ppDevProps)->Service != NULL) + { + FREE((*ppDevProps)->Service); + } + + if ((*ppDevProps)->DeviceClass != NULL) + { + FREE((*ppDevProps)->DeviceClass); + } + + if ((*ppDevProps)->PowerState != NULL) + { + FREE((*ppDevProps)->PowerState); + } + + FREE(*ppDevProps); + *ppDevProps = NULL; +} + + +HTREEITEM +AddLeaf ( + HTREEITEM hTreeParent, + LPARAM lParam, + _In_ LPTSTR lpszText, + TREEICON TreeIcon +) { + // std::cout << lpszText << std::endl; + return (HTREEITEM)1; +}; \ No newline at end of file diff --git a/enum.cpp b/enum.cpp new file mode 100644 index 0000000..8c3e9cd --- /dev/null +++ b/enum.cpp @@ -0,0 +1,3197 @@ +/*++ + +Copyright (c) 1997-2011 Microsoft Corporation + +Module Name: + + ENUM.C + +Abstract: + + This source file contains the routines which enumerate the USB bus + and populate the TreeView control. + + The enumeration process goes like this: + + (1) Enumerate Host Controllers and Root Hubs + EnumerateHostControllers() + EnumerateHostController() + Host controllers currently have symbolic link names of the form HCDx, + where x starts at 0. Use CreateFile() to open each host controller + symbolic link. Create a node in the TreeView to represent each host + controller. + + GetRootHubName() + After a host controller has been opened, send the host controller an + IOCTL_USB_GET_ROOT_HUB_NAME request to get the symbolic link name of + the root hub that is part of the host controller. + + (2) Enumerate Hubs (Root Hubs and External Hubs) + EnumerateHub() + Given the name of a hub, use CreateFile() to map the hub. Send the + hub an IOCTL_USB_GET_NODE_INFORMATION request to get info about the + hub, such as the number of downstream ports. Create a node in the + TreeView to represent each hub. + + (3) Enumerate Downstream Ports + EnumerateHubPorts() + Given an handle to an open hub and the number of downstream ports on + the hub, send the hub an IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX + request for each downstream port of the hub to get info about the + device (if any) attached to each port. If there is a device attached + to a port, send the hub an IOCTL_USB_GET_NODE_CONNECTION_NAME request + to get the symbolic link name of the hub attached to the downstream + port. If there is a hub attached to the downstream port, recurse to + step (2). + + GetAllStringDescriptors() + GetConfigDescriptor() + Create a node in the TreeView to represent each hub port + and attached device. + + +Environment: + + user mode + +Revision History: + + 04-25-97 : created + +--*/ + +//***************************************************************************** +// I N C L U D E S +//***************************************************************************** + +#include "uvcview.h" + +//***************************************************************************** +// D E F I N E S +//***************************************************************************** + +#define NUM_STRING_DESC_TO_GET 32 + +//***************************************************************************** +// L O C A L F U N C T I O N P R O T O T Y P E S +//***************************************************************************** + +std::vector +EnumerateHostControllers ( + HTREEITEM hTreeParent, + ULONG *DevicesConnected +); + +PUSBHOSTCONTROLLERINFO +EnumerateHostController ( + HTREEITEM hTreeParent, + HANDLE hHCDev, + _Inout_ PWCHAR leafName, + _In_ HANDLE deviceInfo, + _In_ PSP_DEVINFO_DATA deviceInfoData +); + +PUSBROOTHUBINFO +EnumerateHub ( + HTREEITEM hTreeParent, + _In_reads_(cbHubName) PWCHAR HubName, + _In_ size_t cbHubName, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2, + _In_opt_ PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps, + _In_opt_ PUSB_DESCRIPTOR_REQUEST ConfigDesc, + _In_opt_ PUSB_DESCRIPTOR_REQUEST BosDesc, + _In_opt_ PSTRING_DESCRIPTOR_NODE StringDescs, + _In_opt_ PUSB_DEVICE_PNP_STRINGS DevProps +); + +std::vector +EnumerateHubPorts ( + HTREEITEM hTreeParent, + HANDLE hHubDevice, + ULONG NumPorts +); + +PWCHAR GetRootHubName ( + HANDLE HostController +); + +PWCHAR GetExternalHubName ( + HANDLE Hub, + ULONG ConnectionIndex +); + +PWCHAR GetHCDDriverKeyName ( + HANDLE HCD +); + +PWCHAR GetDriverKeyName ( + HANDLE Hub, + ULONG ConnectionIndex +); + +PUSB_DESCRIPTOR_REQUEST +GetConfigDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + UCHAR DescriptorIndex + ); + +PUSB_DESCRIPTOR_REQUEST +GetBOSDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex + ); + +DWORD +GetHostControllerPowerMap( + HANDLE hHCDev, + PUSBHOSTCONTROLLERINFO hcInfo); + +DWORD +GetHostControllerInfo( + HANDLE hHCDev, + PUSBHOSTCONTROLLERINFO hcInfo); + +PCHAR WideStrToMultiStr ( + _In_reads_bytes_(cbWideStr) PWCHAR WideStr, + _In_ size_t cbWideStr + ); + +BOOL +AreThereStringDescriptors ( + PUSB_DEVICE_DESCRIPTOR DeviceDesc, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc +); + +PSTRING_DESCRIPTOR_NODE +GetAllStringDescriptors ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + PUSB_DEVICE_DESCRIPTOR DeviceDesc, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc +); + +PSTRING_DESCRIPTOR_NODE +GetStringDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + UCHAR DescriptorIndex, + USHORT LanguageID +); + +HRESULT +GetStringDescriptors ( + _In_ HANDLE hHubDevice, + _In_ ULONG ConnectionIndex, + _In_ UCHAR DescriptorIndex, + _In_ ULONG NumLanguageIDs, + _In_reads_(NumLanguageIDs) USHORT *LanguageIDs, + _In_ PSTRING_DESCRIPTOR_NODE StringDescNodeHead +); + +void +EnumerateAllDevices(); + + +void +EnumerateAllDevicesWithGuid( + PDEVICE_GUID_LIST DeviceList, + LPGUID Guid + ); + +void +FreeDeviceInfoNode( + _In_ PDEVICE_INFO_NODE *ppNode + ); + +PDEVICE_INFO_NODE +FindMatchingDeviceNodeForDriverName( + _In_ PWSTR DriverKeyName, + _In_ BOOLEAN IsHub + ); + + +//***************************************************************************** +// G L O B A L S +//***************************************************************************** + +// List of enumerated host controllers. +// +LIST_ENTRY EnumeratedHCListHead = +{ + &EnumeratedHCListHead, + &EnumeratedHCListHead +}; + +DEVICE_GUID_LIST gHubList; +DEVICE_GUID_LIST gDeviceList; + + +//***************************************************************************** +// G L O B A L S P R I V A T E T O T H I S F I L E +//***************************************************************************** + +ULONG TotalDevicesConnected; + + +//***************************************************************************** +// +// EnumerateHostControllers() +// +// hTreeParent - Handle of the TreeView item under which host controllers +// should be added. +// +//***************************************************************************** + +std::vector +EnumerateHostControllers ( + HTREEITEM hTreeParent, + ULONG *DevicesConnected +) +{ + HANDLE hHCDev = NULL; + HDEVINFO deviceInfo = NULL; + SP_DEVINFO_DATA deviceInfoData; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetailData = NULL; + ULONG index = 0; + ULONG requiredLength = 0; + BOOL success; + std::vector hostControllers; + + TotalDevicesConnected = 0; + TotalHubs = 0; + + EnumerateAllDevices(); + + // Iterate over host controllers using the new GUID based interface + // + deviceInfo = SetupDiGetClassDevs((LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER, + NULL, + NULL, + (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); + + deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + for (index=0; + SetupDiEnumDeviceInfo(deviceInfo, + index, + &deviceInfoData); + index++) + { + deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + success = SetupDiEnumDeviceInterfaces(deviceInfo, + 0, + (LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER, + index, + &deviceInterfaceData); + + if (!success) + { + OOPS(); + break; + } + + success = SetupDiGetDeviceInterfaceDetail(deviceInfo, + &deviceInterfaceData, + NULL, + 0, + &requiredLength, + NULL); + + if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + OOPS(); + break; + } + + deviceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)ALLOC(requiredLength); + if (deviceDetailData == NULL) + { + OOPS(); + break; + } + + deviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + success = SetupDiGetDeviceInterfaceDetail(deviceInfo, + &deviceInterfaceData, + deviceDetailData, + requiredLength, + &requiredLength, + NULL); + + if (!success) + { + OOPS(); + break; + } + + hHCDev = CreateFile(deviceDetailData->DevicePath, + GENERIC_WRITE, + FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + + // If the handle is valid, then we've successfully opened a Host + // Controller. Display some info about the Host Controller itself, + // then enumerate the Root Hub attached to the Host Controller. + // + if (hHCDev != INVALID_HANDLE_VALUE) + { + PUSBHOSTCONTROLLERINFO info = EnumerateHostController(hTreeParent, + hHCDev, + deviceDetailData->DevicePath, + deviceInfo, + &deviceInfoData); + hostControllers.push_back(info); + + CloseHandle(hHCDev); + } + + FREE(deviceDetailData); + } + + SetupDiDestroyDeviceInfoList(deviceInfo); + + *DevicesConnected = TotalDevicesConnected; + + return hostControllers; +} + +//***************************************************************************** +// +// EnumerateHostController() +// +// hTreeParent - Handle of the TreeView item under which host controllers +// should be added. +// +//***************************************************************************** + +PUSBHOSTCONTROLLERINFO +EnumerateHostController ( + HTREEITEM hTreeParent, + HANDLE hHCDev, _Inout_ PWCHAR leafName, + _In_ HANDLE deviceInfo, + _In_ PSP_DEVINFO_DATA deviceInfoData +) +{ + PWCHAR driverKeyName = NULL; + HTREEITEM hHCItem = NULL; + PWCHAR rootHubName = NULL; + PLIST_ENTRY listEntry = NULL; + PUSBHOSTCONTROLLERINFO hcInfo = NULL; + PUSBHOSTCONTROLLERINFO hcInfoInList = NULL; + DWORD dwSuccess; + BOOL success = FALSE; + ULONG deviceAndFunction = 0; + PUSB_DEVICE_PNP_STRINGS DevProps = NULL; + + + // Allocate a structure to hold information about this host controller. + // + hcInfo = (PUSBHOSTCONTROLLERINFO)ALLOC(sizeof(USBHOSTCONTROLLERINFO)); + + // just return if could not alloc memory + if (NULL == hcInfo) + return NULL; + + hcInfo->DeviceInfoType = HostControllerInfo; + + // Obtain the driver key name for this host controller. + // + driverKeyName = GetHCDDriverKeyName(hHCDev); + + if (NULL == driverKeyName) + { + // Failure obtaining driver key name. + OOPS(); + FREE(hcInfo); + return NULL; + } + + // Don't enumerate this host controller again if it already + // on the list of enumerated host controllers. + // + listEntry = EnumeratedHCListHead.Flink; + + if (!listEntry) return NULL; + while (listEntry != &EnumeratedHCListHead) + { + hcInfoInList = CONTAINING_RECORD(listEntry, + USBHOSTCONTROLLERINFO, + ListEntry); + + if (hcInfoInList && wcscmp(driverKeyName, hcInfoInList->DriverKey) == 0) + { + // Already on the list, exit + // + FREE(driverKeyName); + FREE(hcInfo); + return NULL; + } + + listEntry = listEntry->Flink; + } + + // Obtain host controller device properties + { + size_t cbDriverName = 0; + HRESULT hr = S_OK; + + hr = StringCbLength(driverKeyName, MAX_DRIVER_KEY_NAME, &cbDriverName); + if (SUCCEEDED(hr)) + { + DevProps = DriverNameToDeviceProperties(driverKeyName, cbDriverName); + } + } + + hcInfo->DriverKey = driverKeyName; + + if (DevProps) + { + ULONG ven, dev, subsys, rev; + ven = dev = subsys = rev = 0; + + if (swscanf_s(DevProps->DeviceId, + L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", + &ven, &dev, &subsys, &rev) != 4) + { + OOPS(); + } + + hcInfo->VendorID = ven; + hcInfo->DeviceID = dev; + hcInfo->SubSysID = subsys; + hcInfo->Revision = rev; + hcInfo->UsbDeviceProperties = DevProps; + } + else + { + OOPS(); + } + + if (DevProps != NULL && DevProps->DeviceDesc != NULL) + { + leafName = DevProps->DeviceDesc; + } + else + { + OOPS(); + } + #ifdef SERIALIZE_VERBOSE + // Get the USB Host Controller power map + dwSuccess = GetHostControllerPowerMap(hHCDev, hcInfo); + + if (ERROR_SUCCESS != dwSuccess) + { + OOPS(); + } + #endif + + // Get bus, device, and function + // + hcInfo->BusDeviceFunctionValid = FALSE; + + success = SetupDiGetDeviceRegistryProperty(deviceInfo, + deviceInfoData, + SPDRP_BUSNUMBER, + NULL, + (PBYTE)&hcInfo->BusNumber, + sizeof(hcInfo->BusNumber), + NULL); + + if (success) + { + success = SetupDiGetDeviceRegistryProperty(deviceInfo, + deviceInfoData, + SPDRP_ADDRESS, + NULL, + (PBYTE)&deviceAndFunction, + sizeof(deviceAndFunction), + NULL); + } + + if (success) + { + hcInfo->BusDevice = deviceAndFunction >> 16; + hcInfo->BusFunction = deviceAndFunction & 0xffff; + hcInfo->BusDeviceFunctionValid = TRUE; + } + + // #ifdef SERIALIZE_VERBOSE + // Get the USB Host Controller info + dwSuccess = GetHostControllerInfo(hHCDev, hcInfo); + + if (ERROR_SUCCESS != dwSuccess) + { + OOPS(); + } + // #endif + + // Add this host controller to the USB device tree view. + // + hHCItem = AddLeaf(hTreeParent, + (LPARAM)hcInfo, + leafName, + hcInfo->Revision == UsbSuperSpeed ? GoodSsDeviceIcon : GoodDeviceIcon); + + if (NULL == hHCItem) + { + // Failure adding host controller to USB device tree + // view. + + OOPS(); + FREE(driverKeyName); + FREE(hcInfo); + return NULL; + } + + // Add this host controller to the list of enumerated + // host controllers. + // + InsertTailList(&EnumeratedHCListHead, + &hcInfo->ListEntry); + + // Get the name of the root hub for this host + // controller and then enumerate the root hub. + // + rootHubName = GetRootHubName(hHCDev); + + if (rootHubName != NULL) + { + size_t cbHubName = 0; + HRESULT hr = S_OK; + + hr = StringCbLength(rootHubName, MAX_DRIVER_KEY_NAME, &cbHubName); + if (SUCCEEDED(hr)) + { + PUSBROOTHUBINFO info = EnumerateHub(hHCItem, + rootHubName, + cbHubName, + NULL, // ConnectionInfo + NULL, // ConnectionInfoV2 + NULL, // PortConnectorProps + NULL, // ConfigDesc + NULL, // BosDesc + NULL, // StringDescs + NULL); // We do not pass DevProps for RootHub + hcInfo->RootHub = info; + } + } + else + { + // Failure obtaining root hub name. + + OOPS(); + } + + return hcInfo; +} + + +//***************************************************************************** +// +// EnumerateHub() +// +// hTreeParent - Handle of the TreeView item under which this hub should be +// added. +// +// HubName - Name of this hub. This pointer is kept so the caller can neither +// free nor reuse this memory. +// +// ConnectionInfo - NULL if this is a root hub, else this is the connection +// info for an external hub. This pointer is kept so the caller can neither +// free nor reuse this memory. +// +// ConfigDesc - NULL if this is a root hub, else this is the Configuration +// Descriptor for an external hub. This pointer is kept so the caller can +// neither free nor reuse this memory. +// +// StringDescs - NULL if this is a root hub. +// +// DevProps - Device properties of the hub +// +//***************************************************************************** + +PUSBROOTHUBINFO +EnumerateHub ( + HTREEITEM hTreeParent, + _In_reads_(cbHubName) PWCHAR HubName, + _In_ size_t cbHubName, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2, + _In_opt_ PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps, + _In_opt_ PUSB_DESCRIPTOR_REQUEST ConfigDesc, + _In_opt_ PUSB_DESCRIPTOR_REQUEST BosDesc, + _In_opt_ PSTRING_DESCRIPTOR_NODE StringDescs, + _In_opt_ PUSB_DEVICE_PNP_STRINGS DevProps + ) +{ + // Initialize locals to not allocated state so the error cleanup routine + // only tries to cleanup things that were successfully allocated. + // + PUSB_NODE_INFORMATION hubInfo = NULL; + PUSB_HUB_INFORMATION_EX hubInfoEx = NULL; + #ifdef SERIALIZE_VERBOSE + PUSB_HUB_CAPABILITIES_EX hubCapabilityEx = NULL; + #endif + HANDLE hHubDevice = INVALID_HANDLE_VALUE; + HTREEITEM hItem = NULL; + PUSBROOTHUBINFO info = NULL; + PWCHAR deviceName = NULL; + ULONG nBytes = 0; + BOOL success = 0; + DWORD dwSizeOfLeafName = 0; + WCHAR leafName[512] = {0}; + HRESULT hr = S_OK; + size_t cchHeader = 0; + size_t cchFullHubName = 0; + std::vector ports; + + // Allocate some space for a USBDEVICEINFO structure to hold the + // hub info, hub name, and connection info pointers. GPTR zero + // initializes the structure for us. + // + info = (PUSBROOTHUBINFO)ALLOC(sizeof(USBEXTERNALHUBINFO)); + if (info == NULL) + { + OOPS(); + goto EnumerateHubError; + } + + // Allocate some space for a USB_NODE_INFORMATION structure for this Hub + // + hubInfo = (PUSB_NODE_INFORMATION)ALLOC(sizeof(USB_NODE_INFORMATION)); + if (hubInfo == NULL) + { + OOPS(); + goto EnumerateHubError; + } + + hubInfoEx = (PUSB_HUB_INFORMATION_EX)ALLOC(sizeof(USB_HUB_INFORMATION_EX)); + if (hubInfoEx == NULL) + { + OOPS(); + goto EnumerateHubError; + } + + #ifdef SERIALIZE_VERBOSE + hubCapabilityEx = (PUSB_HUB_CAPABILITIES_EX)ALLOC(sizeof(USB_HUB_CAPABILITIES_EX)); + if(hubCapabilityEx == NULL) + { + OOPS(); + goto EnumerateHubError; + } + #endif + + // Keep copies of the Hub Name, Connection Info, and Configuration + // Descriptor pointers + // + ((PUSBROOTHUBINFO)info)->HubInfo = hubInfo; + ((PUSBROOTHUBINFO)info)->HubName = HubName; + + if (ConnectionInfo != NULL) + { + ((PUSBEXTERNALHUBINFO)info)->DeviceInfoType = ExternalHubInfo; + ((PUSBEXTERNALHUBINFO)info)->ConnectionInfo = ConnectionInfo; + ((PUSBEXTERNALHUBINFO)info)->StringDescs = StringDescs; + ((PUSBEXTERNALHUBINFO)info)->PortConnectorProps = PortConnectorProps; + ((PUSBEXTERNALHUBINFO)info)->HubInfoEx = hubInfoEx; + ((PUSBEXTERNALHUBINFO)info)->ConnectionInfoV2 = ConnectionInfoV2; + ((PUSBEXTERNALHUBINFO)info)->UsbDeviceProperties = DevProps; + #ifdef SERIALIZE_VERBOSE + ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx = hubCapabilityEx; + ((PUSBEXTERNALHUBINFO)info)->ConfigDesc = ConfigDesc; + ((PUSBEXTERNALHUBINFO)info)->BosDesc = BosDesc; + #endif + } + else + { + ((PUSBROOTHUBINFO)info)->DeviceInfoType = RootHubInfo; + ((PUSBROOTHUBINFO)info)->HubInfoEx = hubInfoEx; + ((PUSBROOTHUBINFO)info)->PortConnectorProps = PortConnectorProps; + #ifdef SERIALIZE_VERBOSE + ((PUSBROOTHUBINFO)info)->HubCapabilityEx = hubCapabilityEx; + ((PUSBROOTHUBINFO)info)->UsbDeviceProperties = DevProps; + #endif + } + + // Allocate a temp buffer for the full hub device name. + // + hr = StringCbLength(L"\\\\.\\", MAX_DEVICE_PROP, &cchHeader); + if (FAILED(hr)) + { + goto EnumerateHubError; + } + cchFullHubName = cchHeader + cbHubName + sizeof(WCHAR); + deviceName = (PWCHAR)ALLOC((DWORD) cchFullHubName); + if (deviceName == NULL) + { + OOPS(); + goto EnumerateHubError; + } + + // Create the full hub device name + // + hr = StringCchCopyN(deviceName, cchFullHubName, L"\\\\.\\", cchHeader); + if (FAILED(hr)) + { + goto EnumerateHubError; + } + hr = StringCchCatN(deviceName, cchFullHubName, HubName, cbHubName); + if (FAILED(hr)) + { + goto EnumerateHubError; + } + + // Try to hub the open device + // + hHubDevice = CreateFile(deviceName, + GENERIC_WRITE, + FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + + // Done with temp buffer for full hub device name + // + FREE(deviceName); + + if (hHubDevice == INVALID_HANDLE_VALUE) + { + OOPS(); + goto EnumerateHubError; + } + + // + // Now query USBHUB for the USB_NODE_INFORMATION structure for this hub. + // This will tell us the number of downstream ports to enumerate, among + // other things. + // + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_NODE_INFORMATION, + hubInfo, + sizeof(USB_NODE_INFORMATION), + hubInfo, + sizeof(USB_NODE_INFORMATION), + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto EnumerateHubError; + } + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_HUB_INFORMATION_EX, + hubInfoEx, + sizeof(USB_HUB_INFORMATION_EX), + hubInfoEx, + sizeof(USB_HUB_INFORMATION_EX), + &nBytes, + NULL); + + // + // Fail gracefully for downlevel OS's from Win8 + // + if (!success || nBytes < sizeof(USB_HUB_INFORMATION_EX)) + { + FREE(hubInfoEx); + hubInfoEx = NULL; + if (ConnectionInfo != NULL) + { + ((PUSBEXTERNALHUBINFO)info)->HubInfoEx = NULL; + } + else + { + ((PUSBROOTHUBINFO)info)->HubInfoEx = NULL; + } + } + + // + // Obtain Hub Capabilities + // + #ifdef SERIALIZE_VERBOSE + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_HUB_CAPABILITIES_EX, + hubCapabilityEx, + sizeof(USB_HUB_CAPABILITIES_EX), + hubCapabilityEx, + sizeof(USB_HUB_CAPABILITIES_EX), + &nBytes, + NULL); + // + // Fail gracefully + // + if (!success || nBytes < sizeof(USB_HUB_CAPABILITIES_EX)) + { + FREE(hubCapabilityEx); + hubCapabilityEx = NULL; + if (ConnectionInfo != NULL) + { + ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx = NULL; + } + else + { + ((PUSBROOTHUBINFO)info)->HubCapabilityEx = NULL; + } + } + #endif + + // Build the leaf name from the port number and the device description + // + dwSizeOfLeafName = sizeof(leafName); + if (ConnectionInfo) + { + StringCchPrintf(leafName, dwSizeOfLeafName, L"[Port%d] ", ConnectionInfo->ConnectionIndex); + StringCchCat(leafName, + dwSizeOfLeafName, + ConnectionStatuses[ConnectionInfo->ConnectionStatus]); + StringCchCatN(leafName, + dwSizeOfLeafName, + L" : ", + sizeof(L" : ")); + } + + if (DevProps) + { + size_t cbDeviceDesc = 0; + hr = StringCbLength(DevProps->DeviceDesc, MAX_DRIVER_KEY_NAME, &cbDeviceDesc); + if(SUCCEEDED(hr)) + { + StringCchCatN(leafName, + dwSizeOfLeafName, + DevProps->DeviceDesc, + cbDeviceDesc); + } + } + else + { + if(ConnectionInfo != NULL) + { + // External hub + StringCchCatN(leafName, + dwSizeOfLeafName, + HubName, + cbHubName); + } + else + { + // Root hub + StringCchCatN(leafName, + dwSizeOfLeafName, + L"RootHub", + sizeof(L"RootHub")); + } + } + + // Now add an item to the TreeView with the PUSBDEVICEINFO pointer info + // as the LPARAM reference value containing everything we know about the + // hub. + // + hItem = AddLeaf(hTreeParent, + (LPARAM)info, + leafName, + HubIcon); + + if (hItem == NULL) + { + OOPS(); + goto EnumerateHubError; + } + + // Now recursively enumerate the ports of this hub. + // + ports = EnumerateHubPorts( + hItem, + hHubDevice, + hubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts + ); + info->HubPorts = ports; + + + CloseHandle(hHubDevice); + return info; + +EnumerateHubError: + // + // Clean up any stuff that got allocated + // + + if (hHubDevice != INVALID_HANDLE_VALUE) + { + CloseHandle(hHubDevice); + hHubDevice = INVALID_HANDLE_VALUE; + } + + if (hubInfo) + { + FREE(hubInfo); + } + + if (hubInfoEx) + { + FREE(hubInfoEx); + } + + if (info) + { + FREE(info); + } + + if (HubName) + { + FREE(HubName); + } + + if (ConnectionInfo) + { + FREE(ConnectionInfo); + } + + if (ConfigDesc) + { + FREE(ConfigDesc); + } + + if (BosDesc) + { + FREE(BosDesc); + } + + if (StringDescs != NULL) + { + PSTRING_DESCRIPTOR_NODE Next; + + do { + + Next = StringDescs->Next; + FREE(StringDescs); + StringDescs = Next; + + } while (StringDescs != NULL); + } + + return NULL; +} + +//***************************************************************************** +// +// EnumerateHubPorts() +// +// hTreeParent - Handle of the TreeView item under which the hub port should +// be added. +// +// hHubDevice - Handle of the hub device to enumerate. +// +// NumPorts - Number of ports on the hub. +// +//***************************************************************************** + +std::vector +EnumerateHubPorts ( + HTREEITEM hTreeParent, + HANDLE hHubDevice, + ULONG NumPorts +) +{ + ULONG index = 0; + BOOL success = 0; + HRESULT hr = S_OK; + PWCHAR driverKeyName = NULL; + PUSB_DEVICE_PNP_STRINGS DevProps; + DWORD dwSizeOfLeafName = 0; + WCHAR leafName[512]; + int icon = 0; + + PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfoEx; + PUSB_PORT_CONNECTOR_PROPERTIES pPortConnectorProps; + USB_PORT_CONNECTOR_PROPERTIES portConnectorProps; + PUSB_DESCRIPTOR_REQUEST configDesc; + PUSB_DESCRIPTOR_REQUEST bosDesc; + PSTRING_DESCRIPTOR_NODE stringDescs; + PUSBDEVICEINFO info; + PUSB_NODE_CONNECTION_INFORMATION_EX_V2 connectionInfoExV2; + PDEVICE_INFO_NODE pNode; + std::vector ports; + + // Loop over all ports of the hub. + // + // Port indices are 1 based, not 0 based. + // + for (index = 1; index <= NumPorts; index++) + { + ULONG nBytesEx; + ULONG nBytes = 0; + + connectionInfoEx = NULL; + pPortConnectorProps = NULL; + ZeroMemory(&portConnectorProps, sizeof(portConnectorProps)); + configDesc = NULL; + bosDesc = NULL; + stringDescs = NULL; + info = NULL; + connectionInfoExV2 = NULL; + pNode = NULL; + DevProps = NULL; + ZeroMemory(leafName, sizeof(leafName)); + + // + // Allocate space to hold the connection info for this port. + // For now, allocate it big enough to hold info for 30 pipes. + // + // Endpoint numbers are 0-15. Endpoint number 0 is the standard + // control endpoint which is not explicitly listed in the Configuration + // Descriptor. There can be an IN endpoint and an OUT endpoint at + // endpoint numbers 1-15 so there can be a maximum of 30 endpoints + // per device configuration. + // + // Should probably size this dynamically at some point. + // + + nBytesEx = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) + + (sizeof(USB_PIPE_INFO) * 30); + + connectionInfoEx = (PUSB_NODE_CONNECTION_INFORMATION_EX)ALLOC(nBytesEx); + + if (connectionInfoEx == NULL) + { + OOPS(); + break; + } + + connectionInfoExV2 = (PUSB_NODE_CONNECTION_INFORMATION_EX_V2) + ALLOC(sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2)); + + if (connectionInfoExV2 == NULL) + { + OOPS(); + FREE(connectionInfoEx); + break; + } + + // + // Now query USBHUB for the structures + // for this port. This will tell us if a device is attached to this + // port, among other things. + // The fault tolerate code is executed first. + // + + portConnectorProps.ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_PORT_CONNECTOR_PROPERTIES, + &portConnectorProps, + sizeof(USB_PORT_CONNECTOR_PROPERTIES), + &portConnectorProps, + sizeof(USB_PORT_CONNECTOR_PROPERTIES), + &nBytes, + NULL); + + if (success && nBytes == sizeof(USB_PORT_CONNECTOR_PROPERTIES)) + { + pPortConnectorProps = (PUSB_PORT_CONNECTOR_PROPERTIES) + ALLOC(portConnectorProps.ActualLength); + + if (pPortConnectorProps != NULL) + { + pPortConnectorProps->ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_PORT_CONNECTOR_PROPERTIES, + pPortConnectorProps, + portConnectorProps.ActualLength, + pPortConnectorProps, + portConnectorProps.ActualLength, + &nBytes, + NULL); + + if (!success || nBytes < portConnectorProps.ActualLength) + { + FREE(pPortConnectorProps); + pPortConnectorProps = NULL; + } + } + } + + connectionInfoExV2->ConnectionIndex = index; + connectionInfoExV2->Length = sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2); + connectionInfoExV2->SupportedUsbProtocols.Usb300 = 1; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, + connectionInfoExV2, + sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2), + connectionInfoExV2, + sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2), + &nBytes, + NULL); + + if (!success || nBytes < sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2)) + { + FREE(connectionInfoExV2); + connectionInfoExV2 = NULL; + } + + connectionInfoEx->ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, + connectionInfoEx, + nBytesEx, + connectionInfoEx, + nBytesEx, + &nBytesEx, + NULL); + + if (success) + { + // + // Since the USB_NODE_CONNECTION_INFORMATION_EX is used to display + // the device speed, but the hub driver doesn't support indication + // of superspeed, we overwrite the value if the super speed + // data structures are available and indicate the device is operating + // at SuperSpeed. + // + + if (connectionInfoEx->Speed == UsbHighSpeed + && connectionInfoExV2 != NULL + && (connectionInfoExV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher || + connectionInfoExV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher)) + { + connectionInfoEx->Speed = UsbSuperSpeed; + } + } + else + { + PUSB_NODE_CONNECTION_INFORMATION connectionInfo = NULL; + + // Try using IOCTL_USB_GET_NODE_CONNECTION_INFORMATION + // instead of IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX + // + + + nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) + + sizeof(USB_PIPE_INFO) * 30; + + connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)ALLOC(nBytes); + + if (connectionInfo == NULL) + { + OOPS(); + + FREE(connectionInfoEx); + if (pPortConnectorProps != NULL) + { + FREE(pPortConnectorProps); + } + if (connectionInfoExV2 != NULL) + { + FREE(connectionInfoExV2); + } + continue; + } + + connectionInfo->ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, + connectionInfo, + nBytes, + connectionInfo, + nBytes, + &nBytes, + NULL); + + if (!success) + { + OOPS(); + + FREE(connectionInfo); + FREE(connectionInfoEx); + if (pPortConnectorProps != NULL) + { + FREE(pPortConnectorProps); + } + if (connectionInfoExV2 != NULL) + { + FREE(connectionInfoExV2); + } + continue; + } + + // Copy IOCTL_USB_GET_NODE_CONNECTION_INFORMATION into + // IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX structure. + // + connectionInfoEx->ConnectionIndex = connectionInfo->ConnectionIndex; + connectionInfoEx->DeviceDescriptor = connectionInfo->DeviceDescriptor; + connectionInfoEx->Speed = connectionInfo->LowSpeed ? UsbLowSpeed : UsbFullSpeed; + connectionInfoEx->ConnectionStatus = connectionInfo->ConnectionStatus; + connectionInfoEx->CurrentConfigurationValue = connectionInfo->CurrentConfigurationValue; + #ifdef SERIALIZE_VERBOSE + connectionInfoEx->DeviceIsHub = connectionInfo->DeviceIsHub; + connectionInfoEx->DeviceAddress = connectionInfo->DeviceAddress; + connectionInfoEx->NumberOfOpenPipes = connectionInfo->NumberOfOpenPipes; + + memcpy(&connectionInfoEx->PipeList[0], + &connectionInfo->PipeList[0], + sizeof(USB_PIPE_INFO) * 30); + #endif + + FREE(connectionInfo); + } + + // Update the count of connected devices + // + if (connectionInfoEx->ConnectionStatus == DeviceConnected) + { + TotalDevicesConnected++; + } + + if (connectionInfoEx->DeviceIsHub) + { + TotalHubs++; + } + + // If there is a device connected, get the Device Description + // + if (connectionInfoEx->ConnectionStatus != NoDeviceConnected) + { + driverKeyName = GetDriverKeyName(hHubDevice, index); + + if (driverKeyName) + { + size_t cbDriverName = 0; + + hr = StringCbLength(driverKeyName, MAX_DRIVER_KEY_NAME, &cbDriverName); + if (SUCCEEDED(hr)) + { + DevProps = DriverNameToDeviceProperties(driverKeyName, cbDriverName); + pNode = FindMatchingDeviceNodeForDriverName(driverKeyName, connectionInfoEx->DeviceIsHub); + } + FREE(driverKeyName); + } + + } + + // If there is a device connected to the port, try to retrieve the + // Configuration Descriptor from the device. + // + + if (gDoConfigDesc && + connectionInfoEx->ConnectionStatus == DeviceConnected) + { + configDesc = GetConfigDescriptor(hHubDevice, + index, + 0); + } + else + { + configDesc = NULL; + } + + #ifdef SERIALIZE_VERBOSE + if (configDesc != NULL && + connectionInfoEx->DeviceDescriptor.bcdUSB > 0x0200) + { + bosDesc = GetBOSDescriptor(hHubDevice, + index); + } + else + { + bosDesc = NULL; + } + #endif + + if (configDesc != NULL && + AreThereStringDescriptors(&connectionInfoEx->DeviceDescriptor, + (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc+1))) + { + stringDescs = GetAllStringDescriptors ( + hHubDevice, + index, + &connectionInfoEx->DeviceDescriptor, + (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc+1)); + } + else + { + stringDescs = NULL; + } + + // If the device connected to the port is an external hub, get the + // name of the external hub and recursively enumerate it. + // + if (connectionInfoEx->DeviceIsHub) + { + PWCHAR extHubName; + size_t cbHubName = 0; + + extHubName = GetExternalHubName(hHubDevice, index); + if (extHubName != NULL) + { + hr = StringCbLength(extHubName, MAX_DRIVER_KEY_NAME, &cbHubName); + if (SUCCEEDED(hr)) + { + info = static_cast(EnumerateHub(hTreeParent, //hPortItem, + extHubName, + cbHubName, + connectionInfoEx, + connectionInfoExV2, + pPortConnectorProps, + configDesc, + bosDesc, + stringDescs, + DevProps)); + } + } + } + else + { + // Allocate some space for a USBDEVICEINFO structure to hold the + // hub info, hub name, and connection info pointers. GPTR zero + // initializes the structure for us. + // + info = (PUSBDEVICEINFO) ALLOC(sizeof(USBDEVICEINFO)); + + if (info == NULL) + { + OOPS(); + if (configDesc != NULL) + { + FREE(configDesc); + } + if (bosDesc != NULL) + { + FREE(bosDesc); + } + FREE(connectionInfoEx); + + if (pPortConnectorProps != NULL) + { + FREE(pPortConnectorProps); + } + if (connectionInfoExV2 != NULL) + { + FREE(connectionInfoExV2); + } + break; + } + + info->DeviceInfoType = DeviceInfo; + info->ConnectionInfo = connectionInfoEx; + info->PortConnectorProps = pPortConnectorProps; + info->ConfigDesc = configDesc; + info->StringDescs = stringDescs; + info->BosDesc = bosDesc; + info->ConnectionInfoV2 = connectionInfoExV2; + info->UsbDeviceProperties = DevProps; + info->DeviceInfoNode = pNode; + + StringCchPrintf(leafName, sizeof(leafName), L"[Port%d] ", index); + + // Add error description if ConnectionStatus is other than NoDeviceConnected / DeviceConnected + StringCchCat(leafName, + sizeof(leafName), + ConnectionStatuses[connectionInfoEx->ConnectionStatus]); + + if (DevProps) + { + size_t cchDeviceDesc = 0; + + hr = StringCbLength(DevProps->DeviceDesc, MAX_DEVICE_PROP, &cchDeviceDesc); + if (FAILED(hr)) + { + OOPS(); + } + dwSizeOfLeafName = sizeof(leafName); + StringCchCatN(leafName, + dwSizeOfLeafName - sizeof(WCHAR), + L" : ", + sizeof(L" : ")); + StringCchCatN(leafName, + dwSizeOfLeafName - sizeof(WCHAR), + DevProps->DeviceDesc, + cchDeviceDesc ); + } + + if (connectionInfoEx->ConnectionStatus == NoDeviceConnected) + { + if (connectionInfoExV2 != NULL && + connectionInfoExV2->SupportedUsbProtocols.Usb300 == 1) + { + icon = NoSsDeviceIcon; + } + else + { + icon = NoDeviceIcon; + } + } + else if (connectionInfoEx->CurrentConfigurationValue) + { + if (connectionInfoEx->Speed == UsbSuperSpeed) + { + icon = GoodSsDeviceIcon; + } + else + { + icon = GoodDeviceIcon; + } + } + else + { + icon = BadDeviceIcon; + } + + AddLeaf(hTreeParent, //hPortItem, + (LPARAM)info, + leafName, + static_cast(icon)); + } + ports.push_back(info); + } // for + + return ports; +} + + +//***************************************************************************** +// +// WideStrToMultiStr() +// +//***************************************************************************** + +PCHAR WideStrToMultiStr ( + _In_reads_bytes_(cbWideStr) PWCHAR WideStr, + _In_ size_t cbWideStr + ) +{ + ULONG nBytes = 0; + PCHAR MultiStr = NULL; + PWCHAR pWideStr = NULL; + + // Use local string to guarantee zero termination + pWideStr = (PWCHAR) ALLOC((DWORD) cbWideStr + sizeof(WCHAR)); + if (NULL == pWideStr) + { + return NULL; + } + memset(pWideStr, 0, cbWideStr + sizeof(WCHAR)); + memcpy(pWideStr, WideStr, cbWideStr); + + // Get the length of the converted string + // + nBytes = WideCharToMultiByte( + CP_ACP, + WC_NO_BEST_FIT_CHARS, + pWideStr, + -1, + NULL, + 0, + NULL, + NULL); + + if (nBytes == 0) + { + FREE(pWideStr); + return NULL; + } + + // Allocate space to hold the converted string + // + MultiStr = (PCHAR)ALLOC(nBytes); + if (MultiStr == NULL) + { + FREE(pWideStr); + return NULL; + } + + // Convert the string + // + nBytes = WideCharToMultiByte( + CP_ACP, + WC_NO_BEST_FIT_CHARS, + pWideStr, + -1, + MultiStr, + nBytes, + NULL, + NULL); + + if (nBytes == 0) + { + FREE(MultiStr); + FREE(pWideStr); + return NULL; + } + + FREE(pWideStr); + return MultiStr; +} + +//***************************************************************************** +// +// GetRootHubName() +// +//***************************************************************************** + +PWCHAR GetRootHubName ( + HANDLE HostController +) +{ + BOOL success = 0; + ULONG nBytes = 0; + USB_ROOT_HUB_NAME rootHubName; + PUSB_ROOT_HUB_NAME rootHubNameW = NULL; + // PCHAR rootHubNameA = NULL; + + // Get the length of the name of the Root Hub attached to the + // Host Controller + // + success = DeviceIoControl(HostController, + IOCTL_USB_GET_ROOT_HUB_NAME, + 0, + 0, + &rootHubName, + sizeof(rootHubName), + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetRootHubNameError; + } + + // Allocate space to hold the Root Hub name + // + nBytes = rootHubName.ActualLength; + + rootHubNameW = (PUSB_ROOT_HUB_NAME)ALLOC(nBytes); + if (rootHubNameW == NULL) + { + OOPS(); + goto GetRootHubNameError; + } + + // Get the name of the Root Hub attached to the Host Controller + // + success = DeviceIoControl(HostController, + IOCTL_USB_GET_ROOT_HUB_NAME, + NULL, + 0, + rootHubNameW, + nBytes, + &nBytes, + NULL); + if (!success) + { + OOPS(); + goto GetRootHubNameError; + } + + // Convert the Root Hub name + // + return rootHubNameW->RootHubName; + +GetRootHubNameError: + // There was an error, free anything that was allocated + // + if (rootHubNameW != NULL) + { + FREE(rootHubNameW); + rootHubNameW = NULL; + } + return NULL; +} + + +//***************************************************************************** +// +// GetExternalHubName() +// +//***************************************************************************** + +PWCHAR GetExternalHubName ( + HANDLE Hub, + ULONG ConnectionIndex +) +{ + BOOL success = 0; + ULONG nBytes = 0; + USB_NODE_CONNECTION_NAME extHubName; + PUSB_NODE_CONNECTION_NAME extHubNameW = NULL; + // PCHAR extHubNameA = NULL; + + // Get the length of the name of the external hub attached to the + // specified port. + // + extHubName.ConnectionIndex = ConnectionIndex; + + success = DeviceIoControl(Hub, + IOCTL_USB_GET_NODE_CONNECTION_NAME, + &extHubName, + sizeof(extHubName), + &extHubName, + sizeof(extHubName), + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetExternalHubNameError; + } + + // Allocate space to hold the external hub name + // + nBytes = extHubName.ActualLength; + + if (nBytes <= sizeof(extHubName)) + { + OOPS(); + goto GetExternalHubNameError; + } + + extHubNameW = (PUSB_NODE_CONNECTION_NAME)ALLOC(nBytes); + + if (extHubNameW == NULL) + { + OOPS(); + goto GetExternalHubNameError; + } + + // Get the name of the external hub attached to the specified port + // + extHubNameW->ConnectionIndex = ConnectionIndex; + + success = DeviceIoControl(Hub, + IOCTL_USB_GET_NODE_CONNECTION_NAME, + extHubNameW, + nBytes, + extHubNameW, + nBytes, + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetExternalHubNameError; + } + + // Convert the External Hub name + // + return extHubNameW->NodeName; + + +GetExternalHubNameError: + // There was an error, free anything that was allocated + // + if (extHubNameW != NULL) + { + FREE(extHubNameW); + extHubNameW = NULL; + } + + return NULL; +} + + +//***************************************************************************** +// +// GetDriverKeyName() +// +//***************************************************************************** + +PWCHAR GetDriverKeyName ( + HANDLE Hub, + ULONG ConnectionIndex +) +{ + BOOL success = 0; + ULONG nBytes = 0; + USB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyName; + PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyNameW = NULL; + // PCHAR driverKeyNameA = NULL; + + // Get the length of the name of the driver key of the device attached to + // the specified port. + // + driverKeyName.ConnectionIndex = ConnectionIndex; + + success = DeviceIoControl(Hub, + IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, + &driverKeyName, + sizeof(driverKeyName), + &driverKeyName, + sizeof(driverKeyName), + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetDriverKeyNameError; + } + + // Allocate space to hold the driver key name + // + nBytes = driverKeyName.ActualLength; + + if (nBytes <= sizeof(driverKeyName)) + { + OOPS(); + goto GetDriverKeyNameError; + } + + driverKeyNameW = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)ALLOC(nBytes); + if (driverKeyNameW == NULL) + { + OOPS(); + goto GetDriverKeyNameError; + } + + // Get the name of the driver key of the device attached to + // the specified port. + // + driverKeyNameW->ConnectionIndex = ConnectionIndex; + + success = DeviceIoControl(Hub, + IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, + driverKeyNameW, + nBytes, + driverKeyNameW, + nBytes, + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetDriverKeyNameError; + } + + // Convert the driver key name + // + return driverKeyNameW->DriverKeyName; + + +GetDriverKeyNameError: + // There was an error, free anything that was allocated + // + if (driverKeyNameW != NULL) + { + FREE(driverKeyNameW); + driverKeyNameW = NULL; + } + + return NULL; +} + + +//***************************************************************************** +// +// GetHCDDriverKeyName() +// +//***************************************************************************** + +PWCHAR GetHCDDriverKeyName ( + HANDLE HCD +) +{ + BOOL success = 0; + ULONG nBytes = 0; + USB_HCD_DRIVERKEY_NAME driverKeyName = {0}; + PUSB_HCD_DRIVERKEY_NAME driverKeyNameW = NULL; + // PWCHAR pWideStr = NULL; + + ZeroMemory(&driverKeyName, sizeof(driverKeyName)); + + // Get the length of the name of the driver key of the HCD + // + success = DeviceIoControl(HCD, + IOCTL_GET_HCD_DRIVERKEY_NAME, + &driverKeyName, + sizeof(driverKeyName), + &driverKeyName, + sizeof(driverKeyName), + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetHCDDriverKeyNameError; + } + + // Allocate space to hold the driver key name + // + nBytes = driverKeyName.ActualLength; + if (nBytes <= sizeof(driverKeyName)) + { + OOPS(); + goto GetHCDDriverKeyNameError; + } + + driverKeyNameW = (PUSB_HCD_DRIVERKEY_NAME)ALLOC(nBytes); + if (driverKeyNameW == NULL) + { + OOPS(); + goto GetHCDDriverKeyNameError; + } + + // Get the name of the driver key of the device attached to + // the specified port. + // + + success = DeviceIoControl(HCD, + IOCTL_GET_HCD_DRIVERKEY_NAME, + driverKeyNameW, + nBytes, + driverKeyNameW, + nBytes, + &nBytes, + NULL); + if (!success) + { + OOPS(); + goto GetHCDDriverKeyNameError; + } + + // + // Convert the driver key name + // Pass the length of the DriverKeyName string + // + + + // Use local string to guarantee zero termination + // pWideStr = (PWCHAR) ALLOC((DWORD) nBytes - sizeof(USB_HCD_DRIVERKEY_NAME) + sizeof(WCHAR) + sizeof(WCHAR)); + // if (NULL == pWideStr) + // { + // return NULL; + // } + // memset(pWideStr, 0, nBytes - sizeof(USB_HCD_DRIVERKEY_NAME) + sizeof(WCHAR) + sizeof(WCHAR)); + // memcpy(pWideStr, driverKeyNameW->DriverKeyName, nBytes - sizeof(USB_HCD_DRIVERKEY_NAME) + sizeof(WCHAR)); +// + // FREE(driverKeyNameW); +// + // return pWideStr; + + return driverKeyNameW->DriverKeyName; + +GetHCDDriverKeyNameError: + // There was an error, free anything that was allocated + // + if (driverKeyNameW != NULL) + { + FREE(driverKeyNameW); + driverKeyNameW = NULL; + } + + return NULL; +} + + +//***************************************************************************** +// +// GetConfigDescriptor() +// +// hHubDevice - Handle of the hub device containing the port from which the +// Configuration Descriptor will be requested. +// +// ConnectionIndex - Identifies the port on the hub to which a device is +// attached from which the Configuration Descriptor will be requested. +// +// DescriptorIndex - Configuration Descriptor index, zero based. +// +//***************************************************************************** + +PUSB_DESCRIPTOR_REQUEST +GetConfigDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + UCHAR DescriptorIndex +) +{ + BOOL success = 0; + ULONG nBytes = 0; + ULONG nBytesReturned = 0; + + UCHAR configDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + + sizeof(USB_CONFIGURATION_DESCRIPTOR)]; + + PUSB_DESCRIPTOR_REQUEST configDescReq = NULL; + PUSB_CONFIGURATION_DESCRIPTOR configDesc = NULL; + + + // Request the Configuration Descriptor the first time using our + // local buffer, which is just big enough for the Cofiguration + // Descriptor itself. + // + nBytes = sizeof(configDescReqBuf); + + configDescReq = (PUSB_DESCRIPTOR_REQUEST)configDescReqBuf; + configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1); + + // Zero fill the entire request structure + // + memset(configDescReq, 0, nBytes); + + // Indicate the port from which the descriptor will be requested + // + configDescReq->ConnectionIndex = ConnectionIndex; + + // + // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this + // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. + // + // USBD will automatically initialize these fields: + // bmRequest = 0x80 + // bRequest = 0x06 + // + // We must inititialize these fields: + // wValue = Descriptor Type (high) and Descriptor Index (low byte) + // wIndex = Zero (or Language ID for String Descriptors) + // wLength = Length of descriptor buffer + // + configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) + | DescriptorIndex; + + configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); + + // Now issue the get descriptor request. + // + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + configDescReq, + nBytes, + configDescReq, + nBytes, + &nBytesReturned, + NULL); + + if (!success) + { + OOPS(); + return NULL; + } + + if (nBytes != nBytesReturned) + { + OOPS(); + return NULL; + } + + if (configDesc->wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + OOPS(); + return NULL; + } + + // Now request the entire Configuration Descriptor using a dynamically + // allocated buffer which is sized big enough to hold the entire descriptor + // + nBytes = sizeof(USB_DESCRIPTOR_REQUEST) + configDesc->wTotalLength; + + configDescReq = (PUSB_DESCRIPTOR_REQUEST)ALLOC(nBytes); + + if (configDescReq == NULL) + { + OOPS(); + return NULL; + } + + configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1); + + // Indicate the port from which the descriptor will be requested + // + configDescReq->ConnectionIndex = ConnectionIndex; + + // + // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this + // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. + // + // USBD will automatically initialize these fields: + // bmRequest = 0x80 + // bRequest = 0x06 + // + // We must inititialize these fields: + // wValue = Descriptor Type (high) and Descriptor Index (low byte) + // wIndex = Zero (or Language ID for String Descriptors) + // wLength = Length of descriptor buffer + // + configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) + | DescriptorIndex; + + configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); + + // Now issue the get descriptor request. + // + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + configDescReq, + nBytes, + configDescReq, + nBytes, + &nBytesReturned, + NULL); + + if (!success) + { + OOPS(); + FREE(configDescReq); + return NULL; + } + + if (nBytes != nBytesReturned) + { + OOPS(); + FREE(configDescReq); + return NULL; + } + + if (configDesc->wTotalLength != (nBytes - sizeof(USB_DESCRIPTOR_REQUEST))) + { + OOPS(); + FREE(configDescReq); + return NULL; + } + + return configDescReq; +} + + + +//***************************************************************************** +// +// GetBOSDescriptor() +// +// hHubDevice - Handle of the hub device containing the port from which the +// Configuration Descriptor will be requested. +// +// ConnectionIndex - Identifies the port on the hub to which a device is +// attached from which the BOS Descriptor will be requested. +// +//***************************************************************************** + +PUSB_DESCRIPTOR_REQUEST +GetBOSDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex +) +{ + BOOL success = 0; + ULONG nBytes = 0; + ULONG nBytesReturned = 0; + + UCHAR bosDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + + sizeof(USB_BOS_DESCRIPTOR)]; + + PUSB_DESCRIPTOR_REQUEST bosDescReq = NULL; + PUSB_BOS_DESCRIPTOR bosDesc = NULL; + + + // Request the BOS Descriptor the first time using our + // local buffer, which is just big enough for the BOS + // Descriptor itself. + // + nBytes = sizeof(bosDescReqBuf); + + bosDescReq = (PUSB_DESCRIPTOR_REQUEST)bosDescReqBuf; + bosDesc = (PUSB_BOS_DESCRIPTOR)(bosDescReq+1); + + // Zero fill the entire request structure + // + memset(bosDescReq, 0, nBytes); + + // Indicate the port from which the descriptor will be requested + // + bosDescReq->ConnectionIndex = ConnectionIndex; + + // + // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this + // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. + // + // USBD will automatically initialize these fields: + // bmRequest = 0x80 + // bRequest = 0x06 + // + // We must inititialize these fields: + // wValue = Descriptor Type (high) and Descriptor Index (low byte) + // wIndex = Zero (or Language ID for String Descriptors) + // wLength = Length of descriptor buffer + // + bosDescReq->SetupPacket.wValue = (USB_BOS_DESCRIPTOR_TYPE << 8); + + bosDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); + + // Now issue the get descriptor request. + // + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + bosDescReq, + nBytes, + bosDescReq, + nBytes, + &nBytesReturned, + NULL); + + if (!success) + { + OOPS(); + return NULL; + } + + if (nBytes != nBytesReturned) + { + OOPS(); + return NULL; + } + + if (bosDesc->wTotalLength < sizeof(USB_BOS_DESCRIPTOR)) + { + OOPS(); + return NULL; + } + + // Now request the entire BOS Descriptor using a dynamically + // allocated buffer which is sized big enough to hold the entire descriptor + // + nBytes = sizeof(USB_DESCRIPTOR_REQUEST) + bosDesc->wTotalLength; + + bosDescReq = (PUSB_DESCRIPTOR_REQUEST)ALLOC(nBytes); + + if (bosDescReq == NULL) + { + OOPS(); + return NULL; + } + + bosDesc = (PUSB_BOS_DESCRIPTOR)(bosDescReq+1); + + // Indicate the port from which the descriptor will be requested + // + bosDescReq->ConnectionIndex = ConnectionIndex; + + // + // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this + // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. + // + // USBD will automatically initialize these fields: + // bmRequest = 0x80 + // bRequest = 0x06 + // + // We must inititialize these fields: + // wValue = Descriptor Type (high) and Descriptor Index (low byte) + // wIndex = Zero (or Language ID for String Descriptors) + // wLength = Length of descriptor buffer + // + bosDescReq->SetupPacket.wValue = (USB_BOS_DESCRIPTOR_TYPE << 8); + + bosDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); + + // Now issue the get descriptor request. + // + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + bosDescReq, + nBytes, + bosDescReq, + nBytes, + &nBytesReturned, + NULL); + + if (!success) + { + OOPS(); + FREE(bosDescReq); + return NULL; + } + + if (nBytes != nBytesReturned) + { + OOPS(); + FREE(bosDescReq); + return NULL; + } + + if (bosDesc->wTotalLength != (nBytes - sizeof(USB_DESCRIPTOR_REQUEST))) + { + OOPS(); + FREE(bosDescReq); + return NULL; + } + + return bosDescReq; +} + + +//***************************************************************************** +// +// AreThereStringDescriptors() +// +// DeviceDesc - Device Descriptor for which String Descriptors should be +// checked. +// +// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor) +// for which String Descriptors should be checked. +// +//***************************************************************************** + +BOOL +AreThereStringDescriptors ( + PUSB_DEVICE_DESCRIPTOR DeviceDesc, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc +) +{ + PUCHAR descEnd = NULL; + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + + // + // Check Device Descriptor strings + // + + if (DeviceDesc->iManufacturer || + DeviceDesc->iProduct || + DeviceDesc->iSerialNumber + ) + { + return TRUE; + } + + + // + // Check the Configuration and Interface Descriptor strings + // + + descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; + + commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; + + while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && + (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) + { + switch (commonDesc->bDescriptorType) + { + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + OOPS(); + break; + } + if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration) + { + return TRUE; + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + + case USB_INTERFACE_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) && + commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2)) + { + OOPS(); + break; + } + if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface) + { + return TRUE; + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + + default: + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + } + break; + } + + return FALSE; +} + + +//***************************************************************************** +// +// GetAllStringDescriptors() +// +// hHubDevice - Handle of the hub device containing the port from which the +// String Descriptors will be requested. +// +// ConnectionIndex - Identifies the port on the hub to which a device is +// attached from which the String Descriptors will be requested. +// +// DeviceDesc - Device Descriptor for which String Descriptors should be +// requested. +// +// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor) +// for which String Descriptors should be requested. +// +//***************************************************************************** + +PSTRING_DESCRIPTOR_NODE +GetAllStringDescriptors ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + PUSB_DEVICE_DESCRIPTOR DeviceDesc, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc +) +{ + PSTRING_DESCRIPTOR_NODE supportedLanguagesString = NULL; + ULONG numLanguageIDs = 0; + USHORT *languageIDs = NULL; + + PUCHAR descEnd = NULL; + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + UCHAR uIndex = 1; + UCHAR bInterfaceClass = 0; + BOOL getMoreStrings = FALSE; + HRESULT hr = S_OK; + + // + // Get the array of supported Language IDs, which is returned + // in String Descriptor 0 + // + supportedLanguagesString = GetStringDescriptor(hHubDevice, + ConnectionIndex, + 0, + 0); + + if (supportedLanguagesString == NULL) + { + return NULL; + } + + numLanguageIDs = (supportedLanguagesString->StringDescriptor->bLength - 2) / 2; + + languageIDs = (USHORT*)(&supportedLanguagesString->StringDescriptor->bString[0]); + + // + // Get the Device Descriptor strings + // + + if (DeviceDesc->iManufacturer) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + DeviceDesc->iManufacturer, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + + if (DeviceDesc->iProduct) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + DeviceDesc->iProduct, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + + if (DeviceDesc->iSerialNumber) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + DeviceDesc->iSerialNumber, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + + // + // Get the Configuration and Interface Descriptor strings + // + + descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; + + commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; + + while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && + (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) + { + switch (commonDesc->bDescriptorType) + { + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + OOPS(); + break; + } + if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + ((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + + case USB_IAD_DESCRIPTOR_TYPE: + if (commonDesc->bLength < sizeof(USB_IAD_DESCRIPTOR)) + { + OOPS(); + break; + } + if (((PUSB_IAD_DESCRIPTOR)commonDesc)->iFunction) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + ((PUSB_IAD_DESCRIPTOR)commonDesc)->iFunction, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + + case USB_INTERFACE_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) && + commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2)) + { + OOPS(); + break; + } + if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + + // + // We need to display more string descriptors for the following + // interface classes + // + bInterfaceClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceClass; + if (bInterfaceClass == USB_DEVICE_CLASS_VIDEO) + { + getMoreStrings = TRUE; + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + + default: + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + } + break; + } + + if (getMoreStrings) + { + // + // We might need to display strings later that are referenced only in + // class-specific descriptors. Get String Descriptors 1 through 32 (an + // arbitrary upper limit for Strings needed due to "bad devices" + // returning an infinite repeat of Strings 0 through 4) until one is not + // found. + // + // There are also "bad devices" that have issues even querying 1-32, but + // historically USBView made this query, so the query should be safe for + // video devices. + // + for (uIndex = 1; SUCCEEDED(hr) && (uIndex < NUM_STRING_DESC_TO_GET); uIndex++) + { + hr = GetStringDescriptors(hHubDevice, + ConnectionIndex, + uIndex, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + } + + return supportedLanguagesString; +} + + + +//***************************************************************************** +// +// GetStringDescriptor() +// +// hHubDevice - Handle of the hub device containing the port from which the +// String Descriptor will be requested. +// +// ConnectionIndex - Identifies the port on the hub to which a device is +// attached from which the String Descriptor will be requested. +// +// DescriptorIndex - String Descriptor index. +// +// LanguageID - Language in which the string should be requested. +// +//***************************************************************************** + +PSTRING_DESCRIPTOR_NODE +GetStringDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + UCHAR DescriptorIndex, + USHORT LanguageID +) +{ + BOOL success = 0; + ULONG nBytes = 0; + ULONG nBytesReturned = 0; + + UCHAR stringDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + + MAXIMUM_USB_STRING_LENGTH]; + + PUSB_DESCRIPTOR_REQUEST stringDescReq = NULL; + PUSB_STRING_DESCRIPTOR stringDesc = NULL; + PSTRING_DESCRIPTOR_NODE stringDescNode = NULL; + + nBytes = sizeof(stringDescReqBuf); + + stringDescReq = (PUSB_DESCRIPTOR_REQUEST)stringDescReqBuf; + stringDesc = (PUSB_STRING_DESCRIPTOR)(stringDescReq+1); + + // Zero fill the entire request structure + // + memset(stringDescReq, 0, nBytes); + + // Indicate the port from which the descriptor will be requested + // + stringDescReq->ConnectionIndex = ConnectionIndex; + + // + // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this + // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. + // + // USBD will automatically initialize these fields: + // bmRequest = 0x80 + // bRequest = 0x06 + // + // We must inititialize these fields: + // wValue = Descriptor Type (high) and Descriptor Index (low byte) + // wIndex = Zero (or Language ID for String Descriptors) + // wLength = Length of descriptor buffer + // + stringDescReq->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) + | DescriptorIndex; + + stringDescReq->SetupPacket.wIndex = LanguageID; + + stringDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); + + // Now issue the get descriptor request. + // + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + stringDescReq, + nBytes, + stringDescReq, + nBytes, + &nBytesReturned, + NULL); + + // + // Do some sanity checks on the return from the get descriptor request. + // + + if (!success) + { + OOPS(); + return NULL; + } + + if (nBytesReturned < 2) + { + OOPS(); + return NULL; + } + + if (stringDesc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE) + { + OOPS(); + return NULL; + } + + if (stringDesc->bLength != nBytesReturned - sizeof(USB_DESCRIPTOR_REQUEST)) + { + OOPS(); + return NULL; + } + + if (stringDesc->bLength % 2 != 0) + { + OOPS(); + return NULL; + } + + // + // Looks good, allocate some (zero filled) space for the string descriptor + // node and copy the string descriptor to it. + // + + stringDescNode = (PSTRING_DESCRIPTOR_NODE)ALLOC(sizeof(STRING_DESCRIPTOR_NODE) + + stringDesc->bLength); + + if (stringDescNode == NULL) + { + OOPS(); + return NULL; + } + + stringDescNode->DescriptorIndex = DescriptorIndex; + stringDescNode->LanguageID = LanguageID; + + memcpy(stringDescNode->StringDescriptor, + stringDesc, + stringDesc->bLength); + + return stringDescNode; +} + + +//***************************************************************************** +// +// GetStringDescriptors() +// +// hHubDevice - Handle of the hub device containing the port from which the +// String Descriptor will be requested. +// +// ConnectionIndex - Identifies the port on the hub to which a device is +// attached from which the String Descriptor will be requested. +// +// DescriptorIndex - String Descriptor index. +// +// NumLanguageIDs - Number of languages in which the string should be +// requested. +// +// LanguageIDs - Languages in which the string should be requested. +// +// StringDescNodeHead - First node in linked list of device's string descriptors +// +// Return Value: HRESULT indicating whether the string is on the list +// +//***************************************************************************** + +HRESULT +GetStringDescriptors ( + _In_ HANDLE hHubDevice, + _In_ ULONG ConnectionIndex, + _In_ UCHAR DescriptorIndex, + _In_ ULONG NumLanguageIDs, + _In_reads_(NumLanguageIDs) USHORT *LanguageIDs, + _In_ PSTRING_DESCRIPTOR_NODE StringDescNodeHead +) +{ + PSTRING_DESCRIPTOR_NODE tail = NULL; + PSTRING_DESCRIPTOR_NODE trailing = NULL; + ULONG i = 0; + + // + // Go to the end of the linked list, searching for the requested index to + // see if we've already retrieved it + // + for (tail = StringDescNodeHead; tail != NULL; tail = tail->Next) + { + if (tail->DescriptorIndex == DescriptorIndex) + { + return S_OK; + } + + trailing = tail; + } + + tail = trailing; + + // + // Get the next String Descriptor. If this is NULL, then we're done (return) + // Otherwise, loop through all Language IDs + // + for (i = 0; (tail != NULL) && (i < NumLanguageIDs); i++) + { + tail->Next = GetStringDescriptor(hHubDevice, + ConnectionIndex, + DescriptorIndex, + LanguageIDs[i]); + + tail = tail->Next; + } + + if (tail == NULL) + { + return E_FAIL; + } else { + return S_OK; + } +} + +//***************************************************************************** +// +// GetHostControllerPowerMap() +// +// HANDLE hHCDev +// - handle to USB Host Controller +// +// PUSBHOSTCONTROLLERINFO hcInfo +// - data structure to receive the Power Map Info +// +// return DWORD dwError +// - return ERROR_SUCCESS or last error +// +//***************************************************************************** + +DWORD +GetHostControllerPowerMap( + HANDLE hHCDev, + PUSBHOSTCONTROLLERINFO hcInfo) +{ + USBUSER_POWER_INFO_REQUEST UsbPowerInfoRequest; + PUSB_POWER_INFO pUPI = &UsbPowerInfoRequest.PowerInformation ; + DWORD dwError = 0; + DWORD dwBytes = 0; + BOOL bSuccess = FALSE; + int nIndex = 0; + int nPowerState = WdmUsbPowerSystemWorking; + + for ( ; nPowerState <= WdmUsbPowerSystemShutdown; nIndex++, nPowerState++) + { + // zero initialize our request + memset(&UsbPowerInfoRequest, 0, sizeof(UsbPowerInfoRequest)); + + // set the header and request sizes + UsbPowerInfoRequest.Header.UsbUserRequest = USBUSER_GET_POWER_STATE_MAP; + UsbPowerInfoRequest.Header.RequestBufferLength = sizeof(UsbPowerInfoRequest); + UsbPowerInfoRequest.PowerInformation.SystemState = static_cast(nPowerState); + + // + // Now query USBHUB for the USB_POWER_INFO structure for this hub. + // For Selective Suspend support + // + bSuccess = DeviceIoControl(hHCDev, + IOCTL_USB_USER_REQUEST, + &UsbPowerInfoRequest, + sizeof(UsbPowerInfoRequest), + &UsbPowerInfoRequest, + sizeof(UsbPowerInfoRequest), + &dwBytes, + NULL); + + if (!bSuccess) + { + dwError = GetLastError(); + OOPS(); + } + else + { + // copy the data into our USB Host Controller's info structure + memcpy( &(hcInfo->USBPowerInfo[nIndex]), pUPI, sizeof(USB_POWER_INFO)); + } + } + + return dwError; +} + +void +EnumerateAllDevices() +{ + EnumerateAllDevicesWithGuid(&gDeviceList, + (LPGUID)&GUID_DEVINTERFACE_USB_DEVICE); + + EnumerateAllDevicesWithGuid(&gHubList, + (LPGUID)&GUID_DEVINTERFACE_USB_HUB); +} + + +//***************************************************************************** +// +// GetHostControllerInfo() +// +// HANDLE hHCDev +// - handle to USB Host Controller +// +// PUSBHOSTCONTROLLERINFO hcInfo +// - data structure to receive the Power Map Info +// +// return DWORD dwError +// - return ERROR_SUCCESS or last error +// +//***************************************************************************** + +DWORD +GetHostControllerInfo( + HANDLE hHCDev, + PUSBHOSTCONTROLLERINFO hcInfo) +{ + USBUSER_CONTROLLER_INFO_0 UsbControllerInfo; + DWORD dwError = 0; + DWORD dwBytes = 0; + BOOL bSuccess = FALSE; + + memset(&UsbControllerInfo, 0, sizeof(UsbControllerInfo)); + + // set the header and request sizes + UsbControllerInfo.Header.UsbUserRequest = USBUSER_GET_CONTROLLER_INFO_0; + UsbControllerInfo.Header.RequestBufferLength = sizeof(UsbControllerInfo); + + // + // Query for the USB_CONTROLLER_INFO_0 structure + // + bSuccess = DeviceIoControl(hHCDev, + IOCTL_USB_USER_REQUEST, + &UsbControllerInfo, + sizeof(UsbControllerInfo), + &UsbControllerInfo, + sizeof(UsbControllerInfo), + &dwBytes, + NULL); + + if (!bSuccess) + { + dwError = GetLastError(); + OOPS(); + } + else + { + hcInfo->ControllerInfo = (PUSB_CONTROLLER_INFO_0) ALLOC(sizeof(USB_CONTROLLER_INFO_0)); + if(NULL == hcInfo->ControllerInfo) + { + dwError = GetLastError(); + OOPS(); + } + else + { + // copy the data into our USB Host Controller's info structure + memcpy(hcInfo->ControllerInfo, &UsbControllerInfo.Info0, sizeof(USB_CONTROLLER_INFO_0)); + } + } + return dwError; +} + +_Success_(return == TRUE) +BOOL +GetDeviceProperty( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData, + _In_ DWORD Property, + _Outptr_ LPWSTR *ppBuffer + ) +{ + BOOL bResult; + DWORD requiredLength = 0; + DWORD lastError; + + if (ppBuffer == NULL) + { + return FALSE; + } + + *ppBuffer = NULL; + + bResult = SetupDiGetDeviceRegistryProperty(DeviceInfoSet, + DeviceInfoData, + Property , + NULL, + NULL, + 0, + &requiredLength); + lastError = GetLastError(); + + if ((requiredLength == 0) || (bResult != FALSE && lastError != ERROR_INSUFFICIENT_BUFFER)) + { + return FALSE; + } + + *ppBuffer = (LPTSTR)ALLOC(requiredLength); + + if (*ppBuffer == NULL) + { + return FALSE; + } + + bResult = SetupDiGetDeviceRegistryProperty(DeviceInfoSet, + DeviceInfoData, + Property , + NULL, + (PBYTE) *ppBuffer, + requiredLength, + &requiredLength); + if(bResult == FALSE) + { + FREE(*ppBuffer); + *ppBuffer = NULL; + return FALSE; + } + + return TRUE; +} + + +void +EnumerateAllDevicesWithGuid( + PDEVICE_GUID_LIST DeviceList, + LPGUID Guid + ) +{ + if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE) + { + ClearDeviceList(DeviceList); + } + + DeviceList->DeviceInfo = SetupDiGetClassDevs(Guid, + NULL, + NULL, + (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); + + if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE) + { + ULONG index; + DWORD error; + + error = 0; + index = 0; + + while (error != ERROR_NO_MORE_ITEMS) + { + BOOL success; + PDEVICE_INFO_NODE pNode; + + pNode = (PDEVICE_INFO_NODE)ALLOC(sizeof(DEVICE_INFO_NODE)); + if (pNode == NULL) + { + OOPS(); + break; + } + pNode->DeviceInfo = DeviceList->DeviceInfo; + pNode->DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + pNode->DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + success = SetupDiEnumDeviceInfo(DeviceList->DeviceInfo, + index, + &pNode->DeviceInfoData); + + index++; + + if (success == FALSE) + { + error = GetLastError(); + + if (error != ERROR_NO_MORE_ITEMS) + { + OOPS(); + } + + FreeDeviceInfoNode(&pNode); + } + else + { + BOOL bResult; + ULONG requiredLength; + + bResult = GetDeviceProperty(DeviceList->DeviceInfo, + &pNode->DeviceInfoData, + SPDRP_DEVICEDESC, + &pNode->DeviceDescName); + if (bResult == FALSE) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + bResult = GetDeviceProperty(DeviceList->DeviceInfo, + &pNode->DeviceInfoData, + SPDRP_DRIVER, + &pNode->DeviceDriverName); + if (bResult == FALSE) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + pNode->DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + success = SetupDiEnumDeviceInterfaces(DeviceList->DeviceInfo, + 0, + Guid, + index-1, + &pNode->DeviceInterfaceData); + if (!success) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + success = SetupDiGetDeviceInterfaceDetail(DeviceList->DeviceInfo, + &pNode->DeviceInterfaceData, + NULL, + 0, + &requiredLength, + NULL); + + error = GetLastError(); + + if (!success && error != ERROR_INSUFFICIENT_BUFFER) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + pNode->DeviceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)ALLOC(requiredLength); + + if (pNode->DeviceDetailData == NULL) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + pNode->DeviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + success = SetupDiGetDeviceInterfaceDetail(DeviceList->DeviceInfo, + &pNode->DeviceInterfaceData, + pNode->DeviceDetailData, + requiredLength, + &requiredLength, + NULL); + if (!success) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + InsertTailList(&DeviceList->ListHead, &pNode->ListEntry); + } + } + } +} + +DEVICE_POWER_STATE +AcquireDevicePowerState( + _Inout_ PDEVICE_INFO_NODE pNode + ) +{ + CM_POWER_DATA cmPowerData = {0}; + BOOL bResult; + + bResult = SetupDiGetDeviceRegistryProperty(pNode->DeviceInfo, + &pNode->DeviceInfoData, + SPDRP_DEVICE_POWER_DATA, + NULL, + (PBYTE)&cmPowerData, + sizeof(cmPowerData), + NULL); + + pNode->LatestDevicePowerState = bResult ? cmPowerData.PD_MostRecentPowerState : PowerDeviceUnspecified; + + return pNode->LatestDevicePowerState; +} + + +void +ClearDeviceList( + PDEVICE_GUID_LIST DeviceList + ) +{ + if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE) + { + SetupDiDestroyDeviceInfoList(DeviceList->DeviceInfo); + DeviceList->DeviceInfo = INVALID_HANDLE_VALUE; + } + + while (!IsListEmpty(&DeviceList->ListHead)) + { + PDEVICE_INFO_NODE pNode = NULL; + PLIST_ENTRY pEntry; + + pEntry = RemoveHeadList(&DeviceList->ListHead); + + pNode = CONTAINING_RECORD(pEntry, + DEVICE_INFO_NODE, + ListEntry); + + FreeDeviceInfoNode(&pNode); + } +} + +VOID +FreeDeviceInfoNode( + _In_ PDEVICE_INFO_NODE *ppNode + ) +{ + if (ppNode == NULL) + { + return; + } + + if (*ppNode == NULL) + { + return; + } + + if ((*ppNode)->DeviceDetailData != NULL) + { + FREE((*ppNode)->DeviceDetailData); + } + + if ((*ppNode)->DeviceDescName != NULL) + { + FREE((*ppNode)->DeviceDescName); + } + + if ((*ppNode)->DeviceDriverName != NULL) + { + FREE((*ppNode)->DeviceDriverName); + } + + FREE(*ppNode); + *ppNode = NULL; +} + +PDEVICE_INFO_NODE +FindMatchingDeviceNodeForDriverName( + _In_ PWSTR DriverKeyName, + _In_ BOOLEAN IsHub + ) +{ + PDEVICE_INFO_NODE pNode = NULL; + PDEVICE_GUID_LIST pList = NULL; + PLIST_ENTRY pEntry = NULL; + + pList = IsHub ? &gHubList : &gDeviceList; + + pEntry = pList->ListHead.Flink; + + if (!pEntry) return NULL; + + while (pEntry != &pList->ListHead) + { + pNode = CONTAINING_RECORD(pEntry, + DEVICE_INFO_NODE, + ListEntry); + if (pNode && _wcsicmp(DriverKeyName, pNode->DeviceDriverName) == 0) + { + return pNode; + } + + pEntry = pEntry->Flink; + } + + return NULL; +} + diff --git a/specializations.hpp b/specializations.hpp new file mode 100644 index 0000000..cd2fda3 --- /dev/null +++ b/specializations.hpp @@ -0,0 +1,521 @@ +#pragma once + +#include "uvcview.h" +#include "nlohmann/json.hpp" +#include "debugapi.h" + +#include +#include + + +using json = nlohmann::json; + +// https://stackoverflow.com/a/3999597 +// Thank you tfinniga! + +// Convert a wide Unicode string to an UTF8 string +static std::string utf8_encode(const std::wstring &wstr) +{ + if (wstr.empty()) return std::string(); + int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL); + std::string strTo(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL); + return strTo; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +// Convert an UTF8 string to a wide Unicode String +static std::wstring utf8_decode(const std::string &str) +{ + if (str.empty()) return std::wstring(); + int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0); + std::wstring wstrTo(size_needed, 0); + MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed); + return wstrTo; +} +#pragma clang diagnostic pop + + +#define VA_LIST(...) __VA_ARGS__ + +#define ADD_JSON_STRUCT(a, unsafe, safe) \ +template<> \ +struct adl_serializer { \ + static void to_json(json& j, const a& p) { \ + if (p == NULL) { \ + j = nullptr; \ + } else { \ + j = json { \ + unsafe \ + }; \ + safe \ + } \ + } \ +}; + + +#define ADD_JSON_STRUCT_DIRECT(a, unsafe, safe) \ +template<> \ +struct adl_serializer { \ + static void to_json(json& j, const a& p) { \ + j = json { \ + unsafe \ + }; \ + safe \ + } \ +}; + +#define _ADD_JSON_ENTRY(a, b) {#a, b}, +#define ADD_JSON_ENTRY(a) _ADD_JSON_ENTRY(a, p->a) +#define ADD_JSON_ENTRY_DIRECT(a) _ADD_JSON_ENTRY(a, p.a) + +#ifdef SERIALIZE_VERBOSE +#define ADD_JSON_ENTRY_VERBOSE(a) ADD_JSON_ENTRY(a) +#define ADD_JSON_ENTRY_DIRECT_VERBOSE(a) ADD_JSON_ENTRY_DIRECT(a) +#else +#define ADD_JSON_ENTRY_VERBOSE(a) +#define ADD_JSON_ENTRY_DIRECT_VERBOSE(a) +#endif + +#define _ADD_JSON_ENTRY_SAFE(a, b) \ +do { \ + if (b == NULL) { \ + j[#a] = nullptr; \ + } else { \ + j[#a] = b; \ + } \ +} while (0); + +#define ADD_JSON_ENTRY_SAFE(a) _ADD_JSON_ENTRY_SAFE(a, p->a) +#define ADD_JSON_ENTRY_DIRECT_SAFE(a) _ADD_JSON_ENTRY_SAFE(a, p.a) + + + +#define _ADD_JSON_ENTRY_SAFE_WIDE(a, b) \ +do { \ + if (b == NULL) { \ + j[#a] = nullptr; \ + } else { \ + j[#a] = utf8_encode(std::wstring(b)); \ + } \ +} while (0); + + +#define ADD_JSON_ENTRY_SAFE_WIDE(a) _ADD_JSON_ENTRY_SAFE_WIDE(a, p->a) +#define ADD_JSON_ENTRY_DIRECT_SAFE_WIDE(a) _ADD_JSON_ENTRY_SAFE_WIDE(a, p.a) + +#ifdef SERIALIZE_VERBOSE +#define ADD_JSON_ENTRY_SAFE_VERBOSE(a) ADD_JSON_ENTRY_SAFE(a) +#define ADD_JSON_ENTRY_DIRECT_SAFE_VERBOSE(a) ADD_JSON_ENTRY_DIRECT_SAFE(a) + +#define ADD_JSON_ENTRY_SAFE_WIDE_VERBOSE(a) ADD_JSON_ENTRY_SAFE_WIDE(a) +#define ADD_JSON_ENTRY_DIRECT_SAFE_WIDE_VERBOSE(a) ADD_JSON_ENTRY_DIRECT_SAFE_WIDE(a) +#else +#define ADD_JSON_ENTRY_SAFE_VERBOSE(a) +#define ADD_JSON_ENTRY_DIRECT_SAFE_VERBOSE(a) + +#define ADD_JSON_ENTRY_SAFE_WIDE_VERBOSE(a) +#define ADD_JSON_ENTRY_DIRECT_SAFE_WIDE_VERBOSE(a) +#endif + +#define ADD_JSON_ENUM_ENTRY(a) {a, #a} + +NLOHMANN_JSON_SERIALIZE_ENUM( USBDEVICEINFOTYPE, { + ADD_JSON_ENUM_ENTRY(HostControllerInfo), + ADD_JSON_ENUM_ENTRY(RootHubInfo), + ADD_JSON_ENUM_ENTRY(ExternalHubInfo), + ADD_JSON_ENUM_ENTRY(DeviceInfo), +}) + +NLOHMANN_JSON_SERIALIZE_ENUM( USB_HUB_NODE, { + ADD_JSON_ENUM_ENTRY(UsbHub), + ADD_JSON_ENUM_ENTRY(UsbMIParent) +}) + +NLOHMANN_JSON_SERIALIZE_ENUM(USB_CONNECTION_STATUS, { + ADD_JSON_ENUM_ENTRY(NoDeviceConnected), + ADD_JSON_ENUM_ENTRY(DeviceConnected), + ADD_JSON_ENUM_ENTRY(DeviceFailedEnumeration), + ADD_JSON_ENUM_ENTRY(DeviceGeneralFailure), + ADD_JSON_ENUM_ENTRY(DeviceCausedOvercurrent), + ADD_JSON_ENUM_ENTRY(DeviceNotEnoughPower), + ADD_JSON_ENUM_ENTRY(DeviceNotEnoughBandwidth), + ADD_JSON_ENUM_ENTRY(DeviceHubNestedTooDeeply), + ADD_JSON_ENUM_ENTRY(DeviceInLegacyHub), + ADD_JSON_ENUM_ENTRY(DeviceEnumerating), + ADD_JSON_ENUM_ENTRY(DeviceReset) +}) + +NLOHMANN_JSON_SERIALIZE_ENUM(USB_CONTROLLER_FLAVOR, { + ADD_JSON_ENUM_ENTRY(USB_HcGeneric), + ADD_JSON_ENUM_ENTRY(OHCI_Generic), + ADD_JSON_ENUM_ENTRY(OHCI_Hydra), + ADD_JSON_ENUM_ENTRY(OHCI_NEC), + ADD_JSON_ENUM_ENTRY(UHCI_Generic), + ADD_JSON_ENUM_ENTRY(UHCI_Piix4), + ADD_JSON_ENUM_ENTRY(UHCI_Piix3), + ADD_JSON_ENUM_ENTRY(UHCI_Ich2), + ADD_JSON_ENUM_ENTRY(UHCI_Reserved204), + ADD_JSON_ENUM_ENTRY(UHCI_Ich1), + ADD_JSON_ENUM_ENTRY(UHCI_Ich3m), + ADD_JSON_ENUM_ENTRY(UHCI_Ich4), + ADD_JSON_ENUM_ENTRY(UHCI_Ich5), + ADD_JSON_ENUM_ENTRY(UHCI_Ich6), + ADD_JSON_ENUM_ENTRY(UHCI_Intel), + ADD_JSON_ENUM_ENTRY(UHCI_VIA), + ADD_JSON_ENUM_ENTRY(UHCI_VIA_x01), + ADD_JSON_ENUM_ENTRY(UHCI_VIA_x02), + ADD_JSON_ENUM_ENTRY(UHCI_VIA_x03), + ADD_JSON_ENUM_ENTRY(UHCI_VIA_x04), + ADD_JSON_ENUM_ENTRY(UHCI_VIA_x0E_FIFO), + ADD_JSON_ENUM_ENTRY(EHCI_Generic), + ADD_JSON_ENUM_ENTRY(EHCI_NEC), + ADD_JSON_ENUM_ENTRY(EHCI_Lucent), + ADD_JSON_ENUM_ENTRY(EHCI_NVIDIA_Tegra2), + ADD_JSON_ENUM_ENTRY(EHCI_NVIDIA_Tegra3), + ADD_JSON_ENUM_ENTRY(EHCI_Intel_Medfield) +}) + +NLOHMANN_JSON_SERIALIZE_ENUM(DEVICE_POWER_STATE, { + ADD_JSON_ENUM_ENTRY(PowerDeviceUnspecified), + ADD_JSON_ENUM_ENTRY(PowerDeviceD0), + ADD_JSON_ENUM_ENTRY(PowerDeviceD1), + ADD_JSON_ENUM_ENTRY(PowerDeviceD2), + ADD_JSON_ENUM_ENTRY(PowerDeviceD3), + ADD_JSON_ENUM_ENTRY(PowerDeviceMaximum) +}) + +namespace nlohmann { + ADD_JSON_STRUCT(PUSB_CONTROLLER_INFO_0, + VA_LIST( + ADD_JSON_ENTRY(PciVendorId) + ADD_JSON_ENTRY(PciDeviceId) + ADD_JSON_ENTRY(PciRevision) + ADD_JSON_ENTRY(NumberOfRootPorts) + ADD_JSON_ENTRY(ControllerFlavor) + ADD_JSON_ENTRY(HcFeatureFlags) + ), + ) + + ADD_JSON_STRUCT(PUSB_DEVICE_PNP_STRINGS, ,VA_LIST( + ADD_JSON_ENTRY_SAFE_WIDE(DeviceId) + ADD_JSON_ENTRY_SAFE_WIDE(DeviceDesc) + ADD_JSON_ENTRY_SAFE_WIDE_VERBOSE(HwId) + ADD_JSON_ENTRY_SAFE_WIDE_VERBOSE(Service) + ADD_JSON_ENTRY_SAFE_WIDE_VERBOSE(DeviceClass) + ADD_JSON_ENTRY_SAFE_WIDE_VERBOSE(PowerState) + )) + + ADD_JSON_STRUCT_DIRECT(USB_HUB_DESCRIPTOR, VA_LIST( + ADD_JSON_ENTRY_DIRECT_VERBOSE(bDescriptorLength) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bDescriptorType) + ADD_JSON_ENTRY_DIRECT(bNumberOfPorts) + ADD_JSON_ENTRY_DIRECT_VERBOSE(wHubCharacteristics) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bPowerOnToPowerGood) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bHubControlCurrent) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bRemoveAndPowerMask) + ),) + + ADD_JSON_STRUCT_DIRECT(USB_30_HUB_DESCRIPTOR, VA_LIST( + ADD_JSON_ENTRY_DIRECT_VERBOSE(bLength) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bDescriptorType) + ADD_JSON_ENTRY_DIRECT(bNumberOfPorts) + ADD_JSON_ENTRY_DIRECT_VERBOSE(wHubCharacteristics) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bPowerOnToPowerGood) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bHubControlCurrent) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bHubHdrDecLat) + ADD_JSON_ENTRY_DIRECT_VERBOSE(wHubDelay) + ADD_JSON_ENTRY_DIRECT(DeviceRemovable) + ),) + + ADD_JSON_STRUCT_DIRECT(USB_HUB_INFORMATION, VA_LIST( + ADD_JSON_ENTRY_DIRECT(HubDescriptor) + ADD_JSON_ENTRY_DIRECT_VERBOSE(HubIsBusPowered) + ),) + + ADD_JSON_STRUCT_DIRECT(USB_MI_PARENT_INFORMATION, VA_LIST( + ADD_JSON_ENTRY_DIRECT(NumberOfInterfaces) + ),) + + template<> + struct adl_serializer { + static void to_json(json& j, const PUSB_NODE_INFORMATION& p) { + if (p == NULL) { + j = nullptr; + } else { + j = json { + ADD_JSON_ENTRY(NodeType) + }; + if (p->NodeType == UsbHub) { + j["HubInformation"] = p->u.HubInformation; + } + #ifdef SERIALIZE_VERBOSE + else { + j["MiParentInformation"] = p->u.MiParentInformation; + } + #endif + } + } + }; + template<> + struct adl_serializer { + static void to_json(json& j, const PUSB_HUB_INFORMATION_EX& p) { + if (p == NULL) { + j = nullptr; + } else { + j = json { + ADD_JSON_ENTRY(HubType) + ADD_JSON_ENTRY(HighestPortNumber) + }; + if (p->HubType == Usb30Hub) { + j["Usb30HubDescriptor"] = p->u.Usb30HubDescriptor; + } else { + j["UsbHubDescriptor"] = p->u.UsbHubDescriptor; + } + } + } + }; + + ADD_JSON_STRUCT_DIRECT(USB_PORT_PROPERTIES, VA_LIST( + ADD_JSON_ENTRY_DIRECT(PortIsUserConnectable) + ADD_JSON_ENTRY_DIRECT_VERBOSE(PortIsDebugCapable) + ADD_JSON_ENTRY_DIRECT(PortHasMultipleCompanions) + ADD_JSON_ENTRY_DIRECT(PortConnectorIsTypeC) + ADD_JSON_ENTRY_DIRECT_VERBOSE(ReservedMBZ) + ),) + + template <> + struct adl_serializer { + static void to_json(json& j, const PUSB_PORT_CONNECTOR_PROPERTIES& p) { + if (p == 0) { + j = nullptr; + } else { + j = json{ + ADD_JSON_ENTRY(ConnectionIndex) + ADD_JSON_ENTRY_VERBOSE(ActualLength) + ADD_JSON_ENTRY(UsbPortProperties) + ADD_JSON_ENTRY_VERBOSE(CompanionIndex) + ADD_JSON_ENTRY(CompanionPortNumber) + }; + j["CompanionHubSymbolicLinkName"] = utf8_encode(std::wstring(p->CompanionHubSymbolicLinkName)); + } + } + }; + + ADD_JSON_STRUCT(PDEVICE_INFO_NODE, VA_LIST( + ADD_JSON_ENTRY_VERBOSE(DeviceDescNameLength) + ADD_JSON_ENTRY_VERBOSE(DeviceDriverNameLength) + ADD_JSON_ENTRY_VERBOSE(LatestDevicePowerState) + ), + VA_LIST( + ADD_JSON_ENTRY_SAFE_WIDE(DeviceDescName) + ADD_JSON_ENTRY_SAFE_WIDE(DeviceDriverName) + ) + ) + + ADD_JSON_STRUCT_DIRECT(USB_HUB_CAP_FLAGS, VA_LIST( + ADD_JSON_ENTRY_DIRECT(HubIsHighSpeedCapable) + ADD_JSON_ENTRY_DIRECT(HubIsHighSpeed) + ADD_JSON_ENTRY_DIRECT(HubIsMultiTtCapable) + ADD_JSON_ENTRY_DIRECT(HubIsMultiTt) + ADD_JSON_ENTRY_DIRECT(HubIsRoot) + ADD_JSON_ENTRY_DIRECT(HubIsArmedWakeOnConnect) + ADD_JSON_ENTRY_DIRECT(HubIsBusPowered) + ADD_JSON_ENTRY_DIRECT_VERBOSE(ReservedMBZ) + ),) + + ADD_JSON_STRUCT(PUSB_HUB_CAPABILITIES_EX, VA_LIST( + ADD_JSON_ENTRY(CapabilityFlags) + ),) + + template + struct adl_serializer> { + static void to_json(json& j, const std::vector& p) { + for (const auto& element : p) { + j.push_back(element); + } + } + }; + + ADD_JSON_STRUCT(PUSBROOTHUBINFO, VA_LIST( + ADD_JSON_ENTRY(DeviceInfoType) + ADD_JSON_ENTRY(HubPorts) + ), + VA_LIST( + ADD_JSON_ENTRY_SAFE(HubInfo) + ADD_JSON_ENTRY_SAFE(HubInfoEx) + ADD_JSON_ENTRY_SAFE_WIDE(HubName) + ADD_JSON_ENTRY_SAFE(PortConnectorProps) + ADD_JSON_ENTRY_SAFE_VERBOSE(UsbDeviceProperties) + ADD_JSON_ENTRY_SAFE(DeviceInfoNode) + ADD_JSON_ENTRY_SAFE_VERBOSE(HubCapabilityEx) + ) + ) + + + ADD_JSON_STRUCT_DIRECT(USB_DEVICE_DESCRIPTOR, VA_LIST( + ADD_JSON_ENTRY_DIRECT_VERBOSE(bLength) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bDescriptorType) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bcdUSB) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bDeviceClass) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bDeviceSubClass) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bDeviceProtocol) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bMaxPacketSize0) + ADD_JSON_ENTRY_DIRECT_VERBOSE(idVendor) + ADD_JSON_ENTRY_DIRECT_VERBOSE(idProduct) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bcdDevice) + ADD_JSON_ENTRY_DIRECT(iManufacturer) + ADD_JSON_ENTRY_DIRECT(iProduct) + ADD_JSON_ENTRY_DIRECT(iSerialNumber) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bNumConfigurations) + ),) + + + ADD_JSON_STRUCT_DIRECT(USB_ENDPOINT_DESCRIPTOR, VA_LIST( + ADD_JSON_ENTRY_DIRECT(bLength) + ADD_JSON_ENTRY_DIRECT(bDescriptorType) + ADD_JSON_ENTRY_DIRECT(bEndpointAddress) + ADD_JSON_ENTRY_DIRECT(bmAttributes) + ADD_JSON_ENTRY_DIRECT(wMaxPacketSize) + ADD_JSON_ENTRY_DIRECT(bInterval) + ),) + + ADD_JSON_STRUCT(PUSB_PIPE_INFO, VA_LIST( + ADD_JSON_ENTRY(EndpointDescriptor) + ADD_JSON_ENTRY(ScheduleOffset) + ),) + ADD_JSON_STRUCT_DIRECT(USB_PIPE_INFO, VA_LIST( + ADD_JSON_ENTRY_DIRECT(EndpointDescriptor) + ADD_JSON_ENTRY_DIRECT(ScheduleOffset) + ),) + + + template<> + struct adl_serializer { + static void to_json(json& j, const PUSB_NODE_CONNECTION_INFORMATION_EX& p) { + if (p == NULL) { + j = nullptr; + } else { + j = json { + ADD_JSON_ENTRY(ConnectionIndex) + ADD_JSON_ENTRY(DeviceDescriptor) + ADD_JSON_ENTRY_VERBOSE(CurrentConfigurationValue) + ADD_JSON_ENTRY(Speed) + ADD_JSON_ENTRY_VERBOSE(DeviceIsHub) + ADD_JSON_ENTRY_VERBOSE(DeviceAddress) + ADD_JSON_ENTRY_VERBOSE(NumberOfOpenPipes) + ADD_JSON_ENTRY(ConnectionStatus) + }; + #ifdef SERIALIZE_VERBOSE + j["PipeList"] = json::array(); + for (ULONG i = 0; i < p->NumberOfOpenPipes; i++) { + j["PipeList"].push_back(p->PipeList[i]); + } + #endif + } + } + }; + + ADD_JSON_STRUCT(PUSB_DESCRIPTOR_REQUEST, VA_LIST( + ADD_JSON_ENTRY(ConnectionIndex) + ADD_JSON_ENTRY(SetupPacket.bmRequest) + ADD_JSON_ENTRY(SetupPacket.bRequest) + ADD_JSON_ENTRY(SetupPacket.wValue) + ADD_JSON_ENTRY(SetupPacket.wIndex) + ADD_JSON_ENTRY(SetupPacket.wLength) //, + // ADD_JSON_ENTRY(Data) + ),) + + template <> + struct adl_serializer { + static void to_json(json& j, const USB_STRING_DESCRIPTOR& p) { + j = json{ + ADD_JSON_ENTRY_DIRECT_VERBOSE(bLength) + ADD_JSON_ENTRY_DIRECT_VERBOSE(bDescriptorType) + }; + j["bString"] = utf8_encode(std::wstring(p.bString)); + } + }; + template<> + struct adl_serializer { + static void to_json(json& j, const PSTRING_DESCRIPTOR_NODE& p) { + PSTRING_DESCRIPTOR_NODE current = p; + j = json::array(); + do { + j.push_back({ + {"DescriptorIndex", current->DescriptorIndex}, + #ifdef SERIALIZE_VERBOSE + {"LanguageID", current->LanguageID}, + #endif + {"StringDescriptor", current->StringDescriptor} + }); + current = current->Next; + } while (current); + } + }; + + + ADD_JSON_STRUCT_DIRECT(USB_PROTOCOLS, VA_LIST( + ADD_JSON_ENTRY_DIRECT(Usb110) + ADD_JSON_ENTRY_DIRECT(Usb200) + ADD_JSON_ENTRY_DIRECT(Usb300) + ADD_JSON_ENTRY_DIRECT_VERBOSE(ReservedMBZ) + ),) + + + ADD_JSON_STRUCT_DIRECT(USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS, VA_LIST( + ADD_JSON_ENTRY_DIRECT(DeviceIsOperatingAtSuperSpeedOrHigher) + ADD_JSON_ENTRY_DIRECT(DeviceIsSuperSpeedCapableOrHigher) + ADD_JSON_ENTRY_DIRECT(DeviceIsOperatingAtSuperSpeedPlusOrHigher) + ADD_JSON_ENTRY_DIRECT(DeviceIsSuperSpeedPlusCapableOrHigher) + ADD_JSON_ENTRY_DIRECT_VERBOSE(ReservedMBZ) + ),) + + ADD_JSON_STRUCT(PUSB_NODE_CONNECTION_INFORMATION_EX_V2, VA_LIST( + ADD_JSON_ENTRY(ConnectionIndex) + ADD_JSON_ENTRY_VERBOSE(Length) + ADD_JSON_ENTRY(SupportedUsbProtocols) + ADD_JSON_ENTRY(Flags) + ),) + + ADD_JSON_STRUCT(PUSBEXTERNALHUBINFO, VA_LIST( + ADD_JSON_ENTRY(DeviceInfoType) + ADD_JSON_ENTRY(HubPorts) + ), + VA_LIST( + ADD_JSON_ENTRY_SAFE(HubInfo) + ADD_JSON_ENTRY_SAFE(HubInfoEx) + ADD_JSON_ENTRY_SAFE_WIDE(HubName) + ADD_JSON_ENTRY_SAFE(PortConnectorProps) + ADD_JSON_ENTRY_SAFE(UsbDeviceProperties) + ADD_JSON_ENTRY_SAFE(DeviceInfoNode) + ADD_JSON_ENTRY_SAFE_VERBOSE(HubCapabilityEx) + ADD_JSON_ENTRY_SAFE(ConnectionInfo) + ADD_JSON_ENTRY_SAFE_VERBOSE(ConfigDesc) + ADD_JSON_ENTRY_SAFE_VERBOSE(BosDesc) + ADD_JSON_ENTRY_SAFE(StringDescs) + ADD_JSON_ENTRY_SAFE(ConnectionInfoV2) + ) + ) + + ADD_JSON_STRUCT(PUSBHOSTCONTROLLERINFO, VA_LIST( + ADD_JSON_ENTRY(DeviceInfoType) + ADD_JSON_ENTRY(VendorID) + ADD_JSON_ENTRY(DeviceID) + ADD_JSON_ENTRY(SubSysID) + ADD_JSON_ENTRY(Revision) + ADD_JSON_ENTRY(BusDeviceFunctionValid) + ADD_JSON_ENTRY(BusNumber) + ADD_JSON_ENTRY(BusDevice) + ADD_JSON_ENTRY(BusFunction) + ), + VA_LIST( + ADD_JSON_ENTRY_SAFE_WIDE(DriverKey) + ADD_JSON_ENTRY_SAFE(ControllerInfo) + ADD_JSON_ENTRY_SAFE(UsbDeviceProperties) + ADD_JSON_ENTRY_SAFE(RootHub) + ) + ) + +} \ No newline at end of file diff --git a/usbdesc.h b/usbdesc.h new file mode 100644 index 0000000..7e5c6c0 --- /dev/null +++ b/usbdesc.h @@ -0,0 +1,394 @@ +/*++ + +Copyright (c) 1997-2008 Microsoft Corporation + +Module Name: + + USBDESC.H + +Abstract: + + This is a header file for USB descriptors which are not yet in + a standard system header file. + +Environment: + + user mode + +Revision History: + + 03-06-1998 : created + 03-28-2003 : minor changes to support UVC and USB200 + +--*/ +#pragma once +#pragma pack(push, 1) + +/***************************************************************************** + D E F I N E S +*****************************************************************************/ + +// +//Device Descriptor bDeviceClass values +// +#define USB_INTERFACE_CLASS_DEVICE 0x00 +#define USB_COMMUNICATION_DEVICE 0x02 +#define USB_HUB_DEVICE 0x09 +#define USB_DEVICE_CLASS_BILLBOARD 0x11 +#define USB_DIAGNOSTIC_DEVICE 0xDC +#define USB_WIRELESS_CONTROLLER_DEVICE 0xE0 +#define USB_MISCELLANEOUS_DEVICE 0xEF +#define USB_VENDOR_SPECIFIC_DEVICE 0xFF + +// +//Device Descriptor bDeviceSubClass values +// +#define USB_COMMON_SUB_CLASS 0x02 + +// +//Interface Descriptor bInterfaceClass values: +// +//#define USB_AUDIO_INTERFACE 0x01 +//#define USB_CDC_CONTROL_INTERFACE 0x02 +//#define USB_HID_INTERFACE 0x03 +//#define USB_PHYSICAL_INTERFACE 0x05 +//#define USB_IMAGE_INTERFACE 0x06 +//#define USB_PRINTER_INTERFACE 0x07 +//#define USB_MASS_STORAGE_INTERFACE 0x08 +//#define USB_HUB_INTERFACE 0x09 +#define USB_CDC_DATA_INTERFACE 0x0A +#define USB_CHIP_SMART_CARD_INTERFACE 0x0B +#define USB_CONTENT_SECURITY_INTERFACE 0x0D +#define USB_DIAGNOSTIC_DEVICE_INTERFACE 0xDC +#define USB_WIRELESS_CONTROLLER_INTERFACE 0xE0 +#define USB_APPLICATION_SPECIFIC_INTERFACE 0xFE +//#define USB_VENDOR_SPECIFIC_INTERFACE 0xFF +#define USB_HID_DESCRIPTOR_TYPE 0x21 + +// +//IAD protocol values +// +#define USB_IAD_PROTOCOL 0x01 + +// +//Device class specific values +// +#define BILLBOARD_MAX_NUM_ALT_MODE 0x34 + +// +//USB 2.0 Specification Changes - New Descriptors +// +#define USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE 0x07 +#define USB_INTERFACE_POWER_DESCRIPTOR_TYPE 0x08 +#define USB_OTG_DESCRIPTOR_TYPE 0x09 +#define USB_DEBUG_DESCRIPTOR_TYPE 0x0A +#define USB_IAD_DESCRIPTOR_TYPE 0x0B + +// +// USB Device Class Definition for Audio Devices +// Appendix A. Audio Device Class Codes +// + +// A.2 Audio Interface Subclass Codes +// +#define USB_AUDIO_SUBCLASS_UNDEFINED 0x00 +#define USB_AUDIO_SUBCLASS_AUDIOCONTROL 0x01 +#define USB_AUDIO_SUBCLASS_AUDIOSTREAMING 0x02 +#define USB_AUDIO_SUBCLASS_MIDISTREAMING 0x03 + +// A.4 Audio Class-Specific Descriptor Types +// +#define USB_AUDIO_CS_UNDEFINED 0x20 +#define USB_AUDIO_CS_DEVICE 0x21 +#define USB_AUDIO_CS_CONFIGURATION 0x22 +#define USB_AUDIO_CS_STRING 0x23 +#define USB_AUDIO_CS_INTERFACE 0x24 +#define USB_AUDIO_CS_ENDPOINT 0x25 + +// A.5 Audio Class-Specific AC (Audio Control) Interface Descriptor Subtypes +// +#define USB_AUDIO_AC_UNDEFINED 0x00 +#define USB_AUDIO_AC_HEADER 0x01 +#define USB_AUDIO_AC_INPUT_TERMINAL 0x02 +#define USB_AUDIO_AC_OUTPUT_TERMINAL 0x03 +#define USB_AUDIO_AC_MIXER_UNIT 0x04 +#define USB_AUDIO_AC_SELECTOR_UNIT 0x05 +#define USB_AUDIO_AC_FEATURE_UNIT 0x06 +#define USB_AUDIO_AC_PROCESSING_UNIT 0x07 +#define USB_AUDIO_AC_EXTENSION_UNIT 0x08 + +// A.6 Audio Class-Specific AS (Audio Streaming) Interface Descriptor Subtypes +// +#define USB_AUDIO_AS_UNDEFINED 0x00 +#define USB_AUDIO_AS_GENERAL 0x01 +#define USB_AUDIO_AS_FORMAT_TYPE 0x02 +#define USB_AUDIO_AS_FORMAT_SPECIFIC 0x03 + +// A.7 Processing Unit Process Types +// +#define USB_AUDIO_PROCESS_UNDEFINED 0x00 +#define USB_AUDIO_PROCESS_UPDOWNMIX 0x01 +#define USB_AUDIO_PROCESS_DOLBYPROLOGIC 0x02 +#define USB_AUDIO_PROCESS_3DSTEREOEXTENDER 0x03 +#define USB_AUDIO_PROCESS_REVERBERATION 0x04 +#define USB_AUDIO_PROCESS_CHORUS 0x05 +#define USB_AUDIO_PROCESS_DYNRANGECOMP 0x06 + + +/***************************************************************************** + T Y P E D E F S +*****************************************************************************/ + +// HID Class HID Descriptor +// +typedef struct _USB_HID_DESCRIPTOR +{ + UCHAR bLength; + UCHAR bDescriptorType; + USHORT bcdHID; + UCHAR bCountryCode; + UCHAR bNumDescriptors; + struct + { + UCHAR bDescriptorType; + USHORT wDescriptorLength; + } OptionalDescriptors[1]; +} USB_HID_DESCRIPTOR, *PUSB_HID_DESCRIPTOR; + + +// OTG Descriptor +// +typedef struct _USB_OTG_DESCRIPTOR +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bmAttributes; +} USB_OTG_DESCRIPTOR, *PUSB_OTG_DESCRIPTOR; + +// IAD Descriptor +// +typedef struct _USB_IAD_DESCRIPTOR +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bFirstInterface; + UCHAR bInterfaceCount; + UCHAR bFunctionClass; + UCHAR bFunctionSubClass; + UCHAR bFunctionProtocol; + UCHAR iFunction; +} USB_IAD_DESCRIPTOR, *PUSB_IAD_DESCRIPTOR; + + +// Common Class Endpoint Descriptor +// +typedef struct _USB_ENDPOINT_DESCRIPTOR2 { + UCHAR bLength; // offset 0, size 1 + UCHAR bDescriptorType; // offset 1, size 1 + UCHAR bEndpointAddress; // offset 2, size 1 + UCHAR bmAttributes; // offset 3, size 1 + USHORT wMaxPacketSize; // offset 4, size 2 + USHORT wInterval; // offset 6, size 2 + UCHAR bSyncAddress; // offset 8, size 1 +} USB_ENDPOINT_DESCRIPTOR2, *PUSB_ENDPOINT_DESCRIPTOR2; + +// Common Class Interface Descriptor +// +typedef struct _USB_INTERFACE_DESCRIPTOR2 { + UCHAR bLength; // offset 0, size 1 + UCHAR bDescriptorType; // offset 1, size 1 + UCHAR bInterfaceNumber; // offset 2, size 1 + UCHAR bAlternateSetting; // offset 3, size 1 + UCHAR bNumEndpoints; // offset 4, size 1 + UCHAR bInterfaceClass; // offset 5, size 1 + UCHAR bInterfaceSubClass; // offset 6, size 1 + UCHAR bInterfaceProtocol; // offset 7, size 1 + UCHAR iInterface; // offset 8, size 1 + USHORT wNumClasses; // offset 9, size 2 +} USB_INTERFACE_DESCRIPTOR2, *PUSB_INTERFACE_DESCRIPTOR2; + + +// +// USB Device Class Definition for Audio Devices +// + +typedef struct _USB_AUDIO_COMMON_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; +} USB_AUDIO_COMMON_DESCRIPTOR, +*PUSB_AUDIO_COMMON_DESCRIPTOR; + +// 4.3.2 Class-Specific AC (Audio Control) Interface Descriptor +// +typedef struct _USB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + USHORT bcdADC; + USHORT wTotalLength; + UCHAR bInCollection; + UCHAR baInterfaceNr[1]; +} USB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR, +*PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR; + +// 4.3.2.1 Input Terminal Descriptor +// +typedef struct _USB_AUDIO_INPUT_TERMINAL_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bTerminalID; + USHORT wTerminalType; + UCHAR bAssocTerminal; + UCHAR bNrChannels; + USHORT wChannelConfig; + UCHAR iChannelNames; + UCHAR iTerminal; +} USB_AUDIO_INPUT_TERMINAL_DESCRIPTOR, +*PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR; + +// 4.3.2.2 Output Terminal Descriptor +// +typedef struct _USB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bTerminalID; + USHORT wTerminalType; + UCHAR bAssocTerminal; + UCHAR bSourceID; + UCHAR iTerminal; +} USB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR, +*PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR; + +// 4.3.2.3 Mixer Unit Descriptor +// +typedef struct _USB_AUDIO_MIXER_UNIT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bUnitID; + UCHAR bNrInPins; + UCHAR baSourceID[1]; +} USB_AUDIO_MIXER_UNIT_DESCRIPTOR, +*PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR; + +// 4.3.2.4 Selector Unit Descriptor +// +typedef struct _USB_AUDIO_SELECTOR_UNIT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bUnitID; + UCHAR bNrInPins; + UCHAR baSourceID[1]; +} USB_AUDIO_SELECTOR_UNIT_DESCRIPTOR, +*PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR; + +// 4.3.2.5 Feature Unit Descriptor +// +typedef struct _USB_AUDIO_FEATURE_UNIT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bUnitID; + UCHAR bSourceID; + UCHAR bControlSize; + UCHAR bmaControls[1]; +} USB_AUDIO_FEATURE_UNIT_DESCRIPTOR, +*PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR; + +// 4.3.2.6 Processing Unit Descriptor +// +typedef struct _USB_AUDIO_PROCESSING_UNIT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bUnitID; + USHORT wProcessType; + UCHAR bNrInPins; + UCHAR baSourceID[1]; +} USB_AUDIO_PROCESSING_UNIT_DESCRIPTOR, +*PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR; + +// 4.3.2.7 Extension Unit Descriptor +// +typedef struct _USB_AUDIO_EXTENSION_UNIT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bUnitID; + USHORT wExtensionCode; + UCHAR bNrInPins; + UCHAR baSourceID[1]; +} USB_AUDIO_EXTENSION_UNIT_DESCRIPTOR, +*PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR; + +// 4.5.2 Class-Specific AS Interface Descriptor +// +typedef struct _USB_AUDIO_GENERAL_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bTerminalLink; + UCHAR bDelay; + USHORT wFormatTag; +} USB_AUDIO_GENERAL_DESCRIPTOR, +*PUSB_AUDIO_GENERAL_DESCRIPTOR; + +// 4.6.1.2 Class-Specific AS Endpoint Descriptor +// +typedef struct _USB_AUDIO_ENDPOINT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bmAttributes; + UCHAR bLockDelayUnits; + USHORT wLockDelay; +} USB_AUDIO_ENDPOINT_DESCRIPTOR, +*PUSB_AUDIO_ENDPOINT_DESCRIPTOR; + +// +// USB Device Class Definition for Audio Data Formats +// + +typedef struct _USB_AUDIO_COMMON_FORMAT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatType; +} USB_AUDIO_COMMON_FORMAT_DESCRIPTOR, +*PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR; + + +// 2.1.5 Type I Format Type Descriptor +// 2.3.1 Type III Format Type Descriptor +// +typedef struct _USB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatType; + UCHAR bNrChannels; + UCHAR bSubframeSize; + UCHAR bBitResolution; + UCHAR bSamFreqType; +} USB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR, +*PUSB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR; + + +// 2.2.6 Type II Format Type Descriptor +// +typedef struct _USB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatType; + USHORT wMaxBitRate; + USHORT wSamplesPerFrame; + UCHAR bSamFreqType; +} USB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR, +*PUSB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR; + +#pragma pack(pop) diff --git a/uvcdesc.h b/uvcdesc.h new file mode 100644 index 0000000..b1d197a --- /dev/null +++ b/uvcdesc.h @@ -0,0 +1,1106 @@ +//+------------------------------------------------------------------------- +// +// Microsoft Windows +// +// Copyright (C) Microsoft Corporation, 1999 - 2008 +// +// File: uvcdesc.h +// +// This header is from the UVC 1.1 USBVideo driver +// +//-------------------------------------------------------------------------- + +#ifndef ___UVCDESC_H___ +#define ___UVCDESC_H___ + + +// USB Video Device Class Code +#define USB_DEVICE_CLASS_VIDEO 0x0E + +// Video sub-classes +#define SUBCLASS_UNDEFINED 0x00 +#define VIDEO_SUBCLASS_CONTROL 0x01 +#define VIDEO_SUBCLASS_STREAMING 0x02 + +// Video Class-Specific Descriptor Types +#define CS_UNDEFINED 0x20 +#define CS_DEVICE 0x21 +#define CS_CONFIGURATION 0x22 +#define CS_STRING 0x23 +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +// Video Class-Specific VC Interface Descriptor Subtypes +#define VC_HEADER 0x01 +#define INPUT_TERMINAL 0x02 +#define OUTPUT_TERMINAL 0x03 +#define SELECTOR_UNIT 0x04 +#define PROCESSING_UNIT 0x05 +#define EXTENSION_UNIT 0x06 +#define MAX_TYPE_UNIT 0x07 + +// Video Class-Specific VS Interface Descriptor Subtypes +#define VS_DESCRIPTOR_UNDEFINED 0x00 +#define VS_INPUT_HEADER 0x01 +#define VS_OUTPUT_HEADER 0x02 +#define VS_STILL_IMAGE_FRAME 0x03 +#define VS_FORMAT_UNCOMPRESSED 0x04 +#define VS_FRAME_UNCOMPRESSED 0x05 +#define VS_FORMAT_MJPEG 0x06 +#define VS_FRAME_MJPEG 0x07 +#define VS_FORMAT_MPEG1 0x08 +#define VS_FORMAT_MPEG2PS 0x09 +#define VS_FORMAT_MPEG2TS 0x0A +#define VS_FORMAT_MPEG4SL 0x0B +#define VS_FORMAT_DV 0x0C +#define VS_COLORFORMAT 0x0D +#define VS_FORMAT_VENDOR 0x0E +#define VS_FRAME_VENDOR 0x0F + +// Video Class-Specific Endpoint Descriptor Subtypes +#define EP_UNDEFINED 0x00 +#define EP_GENERAL 0x01 +#define EP_ENDPOINT 0x02 +#define EP_INTERRUPT 0x03 + +// Video Class-Specific Terminal Types +#define TERMINAL_TYPE_VENDOR_SPECIFIC 0x0100 +#define TERMINAL_TYPE_USB_STREAMING 0x0101 +#define TERMINAL_TYPE_INPUT_MASK 0x0200 +#define TERMINAL_TYPE_INPUT_VENDOR_SPECIFIC 0x0200 +#define TERMINAL_TYPE_INPUT_CAMERA 0x0201 +#define TERMINAL_TYPE_INPUT_MEDIA_TRANSPORT 0x0202 +#define TERMINAL_TYPE_OUTPUT_MASK 0x0300 +#define TERMINAL_TYPE_OUTPUT_VENDOR_SPECIFIC 0x0300 +#define TERMINAL_TYPE_OUTPUT_DISPLAY 0x0301 +#define TERMINAL_TYPE_OUTPUT_MEDIA_TRANSPORT 0x0302 +#define TERMINAL_TYPE_EXTERNAL_VENDOR_SPECIFIC 0x0400 +#define TERMINAL_TYPE_EXTERNAL_UNDEFINED 0x0400 +#define TERMINAL_TYPE_EXTERNAL_COMPOSITE 0x0401 +#define TERMINAL_TYPE_EXTERNAL_SVIDEO 0x0402 +#define TERMINAL_TYPE_EXTERNAL_COMPONENT 0x0403 + + +// Controls for error checking only +#define DEV_SPECIFIC_CONTROL 0x1001 + +// Map KSNODE_TYPE GUIDs to Indexes +#define NODE_TYPE_NONE 0 +#define NODE_TYPE_STREAMING 1 +#define NODE_TYPE_INPUT_TERMINAL 2 +#define NODE_TYPE_OUTPUT_TERMINAL 3 +#define NODE_TYPE_SELECTOR 4 +#define NODE_TYPE_PROCESSING 5 +#define NODE_TYPE_CAMERA_TERMINAL 6 +#define NODE_TYPE_INPUT_MTT 7 +#define NODE_TYPE_OUTPUT_MTT 8 +#define NODE_TYPE_DEV_SPEC 9 +#define NODE_TYPE_MAX 9 + +// USB bmRequestType values +#define USBVIDEO_INTERFACE_SET 0x21 +#define USBVIDEO_ENDPOINT_SET 0x22 +#define USBVIDEO_INTERFACE_GET 0xA1 +#define USBVIDEO_ENDPOINT_GET 0xA2 + +// Video Class-specific specific requests +#define CLASS_SPECIFIC_GET_MASK 0x80 + +#define RC_UNDEFINED 0x00 +#define SET_CUR 0x01 +#define GET_CUR 0x81 +#define GET_MIN 0x82 +#define GET_MAX 0x83 +#define GET_RES 0x84 +#define GET_LEN 0x85 +#define GET_INFO 0x86 +#define GET_DEF 0x87 + +// Power Mode Control constants +#define POWER_MODE_CONTROL_FULL 0x0 +#define POWER_MODE_CONTROL_DEV_DEPENDENT 0x1 + +// Video Class-specific Processing Unit Controls +#define PU_CONTROL_UNDEFINED 0x00 +#define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01 +#define PU_BRIGHTNESS_CONTROL 0x02 +#define PU_CONTRAST_CONTROL 0x03 +#define PU_GAIN_CONTROL 0x04 +#define PU_POWER_LINE_FREQUENCY_CONTROL 0x05 +#define PU_HUE_CONTROL 0x06 +#define PU_SATURATION_CONTROL 0x07 +#define PU_SHARPNESS_CONTROL 0x08 +#define PU_GAMMA_CONTROL 0x09 +#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0A +#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0B +#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0C +#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0D +#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0E +#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0F +#define PU_HUE_AUTO_CONTROL 0x10 +#define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11 +#define PU_ANALOG_LOCK_STATUS_CONTROL 0x12 + +// Video Class-specific Camera Terminal Controls +#define CT_CONTROL_UNDEFINED 0x00 +#define CT_SCANNING_MODE_CONTROL 0x01 +#define CT_AE_MODE_CONTROL 0x02 +#define CT_AE_PRIORITY_CONTROL 0x03 +#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04 +#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05 +#define CT_FOCUS_ABSOLUTE_CONTROL 0x06 +#define CT_FOCUS_RELATIVE_CONTROL 0x07 +#define CT_FOCUS_AUTO_CONTROL 0x08 +#define CT_IRIS_ABSOLUTE_CONTROL 0x09 +#define CT_IRIS_RELATIVE_CONTROL 0x0A +#define CT_ZOOM_ABSOLUTE_CONTROL 0x0B +#define CT_ZOOM_RELATIVE_CONTROL 0x0C +#define CT_PANTILT_ABSOLUTE_CONTROL 0x0D +#define CT_PANTILT_RELATIVE_CONTROL 0x0E +#define CT_ROLL_ABSOLUTE_CONTROL 0x0F +#define CT_ROLL_RELATIVE_CONTROL 0x10 +#define CT_PRIVACY_CONTROL 0x11 + +#define CT_RELATIVE_INCREASE 0x01 +#define CT_RELATIVE_DECREASE 0xff +#define CT_RELATIVE_STOP 0x00 + +// Selector Unit Control Selector +#define SU_INPUT_SELECT_CONTROL 0x01 + +// Media Tape Transport Control Selector +#define MTT_CONTROL_UNDEFINED 0x00 +#define MTT_TRANSPORT_CONTROL 0x01 +#define MTT_ATN_INFORMATION_CONTROL 0x02 +#define MTT_MEDIA_INFORMATION_CONTROL 0x03 +#define MTT_TIME_CODE_INFORMATION_CONTROL 0x04 + +// Media Transport Terminal States +#define MTT_STATE_PLAY_NEXT_FRAME 0x00 +#define MTT_STATE_PLAY_FWD_SLOWEST 0x01 +#define MTT_STATE_PLAY_SLOW_FWD_4 0x02 +#define MTT_STATE_PLAY_SLOW_FWD_3 0x03 +#define MTT_STATE_PLAY_SLOW_FWD_2 0x04 +#define MTT_STATE_PLAY_SLOW_FWD_1 0x05 +#define MTT_STATE_PLAY_X1 0x06 +#define MTT_STATE_PLAY_FAST_FWD_1 0x07 +#define MTT_STATE_PLAY_FAST_FWD_2 0x08 +#define MTT_STATE_PLAY_FAST_FWD_3 0x09 +#define MTT_STATE_PLAY_FAST_FWD_4 0x0A +#define MTT_STATE_PLAY_FASTEST_FWD 0x0B +#define MTT_STATE_PLAY_PREV_FRAME 0x0C +#define MTT_STATE_PLAY_SLOWEST_REV 0x0D +#define MTT_STATE_PLAY_SLOW_REV_4 0x0E +#define MTT_STATE_PLAY_SLOW_REV_3 0x0F +#define MTT_STATE_PLAY_SLOW_REV_2 0x10 +#define MTT_STATE_PLAY_SLOW_REV_1 0x11 +#define MTT_STATE_PLAY_REV 0x12 +#define MTT_STATE_PLAY_FAST_REV_1 0x13 +#define MTT_STATE_PLAY_FAST_REV_2 0x14 +#define MTT_STATE_PLAY_FAST_REV_3 0x15 +#define MTT_STATE_PLAY_FAST_REV_4 0x16 +#define MTT_STATE_PLAY_FASTEST_REV 0x17 +#define MTT_STATE_PLAY 0x18 +#define MTT_STATE_PAUSE 0x19 +#define MTT_STATE_PLAY_REVERSE_PAUSE 0x1A + + +#define MTT_STATE_STOP 0x40 +#define MTT_STATE_FAST_FORWARD 0x41 +#define MTT_STATE_REWIND 0x42 +#define MTT_STATE_HIGH_SPEED_REWIND 0x43 + +#define MTT_STATE_RECORD_START 0x50 +#define MTT_STATE_RECORD_PAUSE 0x51 + +#define MTT_STATE_EJECT 0x60 + +#define MTT_STATE_PLAY_SLOW_FWD_X 0x70 +#define MTT_STATE_PLAY_FAST_FWD_X 0x71 +#define MTT_STATE_PLAY_SLOW_REV_X 0x72 +#define MTT_STATE_PLAY_FAST_REV_X 0x73 +#define MTT_STATE_STOP_START 0x74 +#define MTT_STATE_STOP_END 0x75 +#define MTT_STATE_STOP_EMERGENCY 0x76 +#define MTT_STATE_STOP_CONDENSATION 0x77 +#define MTT_STATE_UNSPECIFIED 0x7F + +// Video Control Interface Control Selectors +#define VC_UNDEFINED_CONTROL 0x00 +#define VC_VIDEO_POWER_MODE_CONTROL 0x01 +#define VC_REQUEST_ERROR_CODE_CONTROL 0x02 + +// VideoStreaming Interface Control Selectors +#define VS_CONTROL_UNDEFINED 0x00 +#define VS_PROBE_CONTROL 0x01 +#define VS_COMMIT_CONTROL 0x02 +#define VS_STILL_PROBE_CONTROL 0x03 +#define VS_STILL_COMMIT_CONTROL 0x04 +#define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05 +#define VS_STREAM_ERROR_CODE_CONTROL 0x06 +#define VS_GENERATE_KEY_FRAME_CONTROL 0x07 +#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08 +#define VS_SYNC_DELAY_CONTROL 0x09 + +// Probe commit bitmap framing info +#define VS_PROBE_COMMIT_BIT_FID 0x01 +#define VS_PROBE_COMMIT_BIT_EOF 0x02 + +// Stream payload header Bit Field Header bits +#define BFH_FID 0x01 // Frame ID bit +#define BFH_EOF 0x02 // End of Frame bit +#define BFH_PTS 0x04 // Presentation Time Stamp bit +#define BFH_SCR 0x08 // Source Clock Reference bit +#define BFH_RES 0x10 // Reserved bit +#define BFH_STI 0x20 // Still image bit +#define BFH_ERR 0x40 // Error bit +#define BFH_EOH 0x80 // End of header bit + +#define HDR_LENGTH 1 // Length of header length field in bytes +#define BFH_LENGTH 1 // Length of BFH field in bytes +#define PTS_LENGTH 4 // Length of PTS field in bytes +#define SCR_LENGTH 6 // Length of SCR field in bytes + +// USB Video Status Codes (Request Error Code Control) +#define USBVIDEO_RE_STATUS_NOERROR 0x00 +#define USBVIDEO_RE_STATUS_NOT_READY 0x01 +#define USBVIDEO_RE_STATUS_WRONG_STATE 0x02 +#define USBVIDEO_RE_STATUS_POWER 0x03 +#define USBVIDEO_RE_STATUS_OUT_OF_RANGE 0x04 +#define USBVIDEO_RE_STATUS_INVALID_UNIT 0x05 +#define USBVIDEO_RE_STATUS_INVALID_CONTROL 0x06 +#define USBVIDEO_RE_STATUS_UNKNOWN 0x07 + +// USB Video Device Status Codes (Stream Error Code Control) +#define USBVIDEO_SE_STATUS_NOERROR 0x00 +#define USBVIDEO_SE_STATUS_PROTECTED_CONTENT 0x01 +#define USBVIDEO_SE_STATUS_INPUT_BUFFER_UNDERRUN 0x02 +#define USBVIDEO_SE_STATUS_DATA_DICONTINUITY 0x03 +#define USBVIDEO_SE_STATUS_OUTPUT_BUFFER_UNDERRUN 0x04 +#define USBVIDEO_SE_STATUS_OUTPUT_BUFFER_OVERRUN 0x05 +#define USBVIDEO_SE_STATUS_FORMAT_CHANGE 0x06 +#define USBVIDEO_SE_STATUS_STILL_IMAGE_ERROR 0x07 +#define USBVIDEO_SE_STATUS_UNKNOWN 0x08 + +// Status Interrupt Types +#define STATUS_INTERRUPT_VC 1 +#define STATUS_INTERRUPT_VS 2 + +// Status Interrupt Attributes +#define STATUS_INTERRUPT_ATTRIBUTE_VALUE 0x00 +#define STATUS_INTERRUPT_ATTRIBUTE_INFO 0x01 +#define STATUS_INTERRUPT_ATTRIBUTE_FAILURE 0x02 + +// VideoStreaming interface interrupt types +#define VS_INTERRUPT_EVENT_BUTTON_PRESS 0x00 +#define VS_INTERRUPT_VALUE_BUTTON_RELEASE 0x00 +#define VS_INTERRUPT_VALUE_BUTTON_PRESS 0x01 + +// Get Info Values +#define USBVIDEO_ASYNC_CONTROL 0x10 +#define USBVIDEO_SETTABLE_CONTROL 0x2 + +#define MAX_INTERRUPT_PACKET_VALUE_SIZE 8 + +// Frame descriptor frame interval array offsets +#define MIN_FRAME_INTERVAL_OFFSET 0 +#define MAX_FRAME_INTERVAL_OFFSET 1 +#define FRAME_INTERVAL_STEP_OFFSET 2 + +// Still image capture methods +#define STILL_CAPTURE_METHOD_NONE 0 +#define STILL_CAPTURE_METHOD_1 1 +#define STILL_CAPTURE_METHOD_2 2 +#define STILL_CAPTURE_METHOD_3 3 + +// Still image trigger control states +#define STILL_IMAGE_TRIGGER_NORMAL 0 +#define STILL_IMAGE_TRIGGER_TRANSMIT 1 +#define STILL_IMAGE_TRIGGER_TRANSMIT_BULK 2 +#define STILL_IMAGE_TRIGGER_TRANSMIT_ABORT 3 + +// Endpoint descriptor masks +#define EP_DESCRIPTOR_TRANSACTION_SIZE_MASK 0x07ff +#define EP_DESCRIPTOR_NUM_TRANSACTION_MASK 0x1800 +#define EP_DESCRIPTOR_NUM_TRANSACTION_OFFSET 11 + + +// Copy protection flag defined in the Uncompressed Payload Spec +#define USB_VIDEO_UNCOMPRESSED_RESTRICT_DUPLICATION 1 + +// Interlace flags +#define INTERLACE_FLAGS_SUPPORTED_MASK 0x01 +#define INTERLACE_FLAGS_FIELDS_PER_FRAME_MASK 0x02 +#define INTERLACE_FLAGS_FIELDS_PER_FRAME_2 0x00 +#define INTERLACE_FLAGS_FIELDS_PER_FRAME_1 0x02 +#define INTERLACE_FLAGS_FIELD_1_FIRST_MASK 0x04 +#define INTERLACE_FLAGS_FIELD_PATTERN_MASK 0x30 +#define INTERLACE_FLAGS_FIELD_PATTERN_FIELD1 0x00 +#define INTERLACE_FLAGS_FIELD_PATTERN_FIELD2 0x10 +#define INTERLACE_FLAGS_FIELD_PATTERN_REGULAR 0x20 +#define INTERLACE_FLAGS_FIELD_PATTERN_RANDOM 0x30 +#define INTERLACE_FLAGS_DISPLAY_MODE_MASK 0xC0 +#define INTERLACE_FLAGS_DISPLAY_MODE_BOB 0x00 +#define INTERLACE_FLAGS_DISPLAY_MODE_WEAVE 0x40 +#define INTERLACE_FLAGS_DISPLAY_MODE_BOB_WEAVE 0x80 + +// Color Matching Flags +#define UVC_PRIMARIES_UNKNOWN 0x0 +#define UVC_PRIMARIES_BT709 0x1 +#define UVC_PRIMARIES_BT470_2M 0x2 +#define UVC_PRIMARIES_BT470_2BG 0x3 +#define UVC_PRIMARIES_SMPTE_170M 0x4 +#define UVC_PRIMARIES_SMPTE_240M 0x5 + +#define UVC_GAMMA_UNKNOWN 0x0 +#define UVC_GAMMA_BT709 0x1 +#define UVC_GAMMA_BT470_2M 0x2 +#define UVC_GAMMA_BT470_2BG 0x3 +#define UVC_GAMMA_SMPTE_170M 0x4 +#define UVC_GAMMA_SMPTE_240M 0x5 +#define UVC_GAMMA_LINEAR 0x6 +#define UVC_GAMMA_sRGB 0x7 + +#define UVC_TRANSFER_MATRIX_UNKNOWN 0x0 +#define UVC_TRANSFER_MATRIX_BT709 0x1 +#define UVC_TRANSFER_MATRIX_FCC 0x2 +#define UVC_TRANSFER_MATRIX_BT470_2BG 0x3 +#define UVC_TRANSFER_MATRIX_BT601 0x4 +#define UVC_TRANSFER_MATRIX_SMPTE_240M 0x5 + +// +// BEGIN - VDC Descriptor and Control Structures +// +#pragma warning( disable : 4200 ) // Allow zero-sized arrays at end of structs +#pragma pack( push, vdc_descriptor_structs, 1) + +// Video Specific Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // descriptor subtype +} VIDEO_SPECIFIC, *PVIDEO_SPECIFIC; + +#define SIZEOF_VIDEO_SPECIFIC(pDesc) sizeof(VIDEO_SPECIFIC) + + +// Video Unit Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // descriptor subtype + UCHAR bUnitID; // Constant uniquely identifying the Unit +} VIDEO_UNIT, *PVIDEO_UNIT; + +#define SIZEOF_VIDEO_UNIT(pDesc) sizeof(VIDEO_UNIT) + +// VideoControl Header Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // VC_HEADER descriptor subtype + USHORT bcdVideoSpec; // USB video class spec revision number + USHORT wTotalLength; // Total length, including all units and terminals + ULONG dwClockFreq; // Device clock frequency in Hz + UCHAR bInCollection; // number of video streaming interfaces + UCHAR baInterfaceNr[]; // interface number array +} VIDEO_CONTROL_HEADER_UNIT, *PVIDEO_CONTROL_HEADER_UNIT; + +#define SIZEOF_VIDEO_CONTROL_HEADER_UNIT(pDesc) \ + ((sizeof(VIDEO_CONTROL_HEADER_UNIT) + (pDesc)->bInCollection)) + + +// VideoControl Input Terminal Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // INPUT_TERMINAL descriptor subtype + UCHAR bTerminalID; // Constant uniquely identifying the Terminal + USHORT wTerminalType; // Constant characterizing the terminal type + UCHAR bAssocTerminal; // ID of associated output terminal + UCHAR iTerminal; // Index of string descriptor +} VIDEO_INPUT_TERMINAL, *PVIDEO_INPUT_TERMINAL; + +#define SIZEOF_VIDEO_INPUT_TERMINAL(pDesc) sizeof(VIDEO_INPUT_TERMINAL) + + +// VideoControl Output Terminal Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // OUTPUT_TERMINAL descriptor subtype + UCHAR bTerminalID; // Constant uniquely identifying the Terminal + USHORT wTerminalType; // Constant characterizing the terminal type + UCHAR bAssocTerminal; // ID of associated input terminal + UCHAR bSourceID; // ID of source unit/terminal + UCHAR iTerminal; // Index of string descriptor +} VIDEO_OUTPUT_TERMINAL, *PVIDEO_OUTPUT_TERMINAL; + +#define SIZEOF_VIDEO_OUTPUT_TERMINAL(pDesc) sizeof(VIDEO_OUTPUT_TERMINAL) + + +// VideoControl Camera Terminal Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // INPUT_TERMINAL descriptor subtype + UCHAR bTerminalID; // Constant uniquely identifying the Terminal + USHORT wTerminalType; // Sensor type + UCHAR bAssocTerminal; // ID of associated output terminal + UCHAR iTerminal; // Index of string descriptor + USHORT wObjectiveFocalLengthMin; // Min focal length for zoom + USHORT wObjectiveFocalLengthMax; // Max focal length for zoom + USHORT wOcularFocalLength; // Ocular focal length for zoom + UCHAR bControlSize; // Size of bmControls field + UCHAR bmControls[]; // Bitmap of controls supported +} VIDEO_CAMERA_TERMINAL, *PVIDEO_CAMERA_TERMINAL; + +#define SIZEOF_VIDEO_CAMERA_TERMINAL(pDesc) \ + (sizeof(VIDEO_CAMERA_TERMINAL) + (pDesc)->bControlSize) + + +// Media Transport Input Terminal Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // INPUT_TERMINAL descriptor subtype + UCHAR bTerminalID; // Constant uniquely identifying the Terminal + USHORT wTerminalType; // Media Transport type + UCHAR bAssocTerminal; // ID of associated output terminal + UCHAR iTerminal; // Index of string descriptor + UCHAR bControlSize; // Size of bmControls field + UCHAR bmControls[]; // Bitmap of controls supported +} VIDEO_INPUT_MTT, *PVIDEO_INPUT_MTT; + + +__inline size_t SizeOfVideoInputMTT(_In_ PVIDEO_INPUT_MTT pDesc) +{ + UCHAR bTransportModeSize; + PUCHAR pbCurr; + + pbCurr = pDesc->bmControls + pDesc->bControlSize; + bTransportModeSize = *pbCurr; + + return sizeof(VIDEO_INPUT_MTT) + pDesc->bControlSize + 1 + bTransportModeSize; +} + +#define SIZEOF_VIDEO_INPUT_MTT(pDesc) SizeOfVideoInputMTT(pDesc) + + +// Media Transport Output Terminal Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // OUTPUT_TERMINAL descriptor subtype + UCHAR bTerminalID; // Constant uniquely identifying the Terminal + USHORT wTerminalType; // Media Transport type + UCHAR bAssocTerminal; // ID of associated output terminal + UCHAR bSourceID; // ID of source unit/terminal + UCHAR iTerminal; // Index of string descriptor + UCHAR bControlSize; // Size of bmControls field + UCHAR bmControls[]; // Bitmap of controls supported +} VIDEO_OUTPUT_MTT, *PVIDEO_OUTPUT_MTT; + + +__inline size_t SizeOfVideoOutputMTT(_In_ PVIDEO_OUTPUT_MTT pDesc) +{ + UCHAR bTransportModeSize; + PUCHAR pbCurr; + + pbCurr = pDesc->bmControls + pDesc->bControlSize; + bTransportModeSize = *pbCurr; + + return sizeof(VIDEO_OUTPUT_MTT) + pDesc->bControlSize + 1+ bTransportModeSize; +} + +#define SIZEOF_VIDEO_OUTPUT_MTT(pDesc) SizeOfVideoOutputMTT(pDesc) + + +// VideoControl Selector Unit Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // SELECTOR_UNIT descriptor subtype + UCHAR bUnitID; // Constant uniquely identifying the Unit + UCHAR bNrInPins; // Number of input pins + UCHAR baSourceID[]; // IDs of connected units/terminals +} VIDEO_SELECTOR_UNIT, *PVIDEO_SELECTOR_UNIT; + +#define SIZEOF_VIDEO_SELECTOR_UNIT(pDesc) \ + (sizeof(VIDEO_SELECTOR_UNIT) + (pDesc)->bNrInPins + 1) + + +// VideoControl Processing Unit Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // PROCESSING_UNIT descriptor subtype + UCHAR bUnitID; // Constant uniquely identifying the Unit + UCHAR bSourceID; // ID of connected unit/terminal + USHORT wMaxMultiplier; // Maximum digital magnification + UCHAR bControlSize; // Size of bmControls field + UCHAR bmControls[]; // Bitmap of controls supported +} VIDEO_PROCESSING_UNIT, *PVIDEO_PROCESSING_UNIT; + +#define SIZEOF_VIDEO_PROCESSING_UNIT(pDesc) \ + (sizeof(VIDEO_PROCESSING_UNIT) + 1 + (pDesc)->bControlSize) + + +// VideoControl Extension Unit Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // EXTENSION_UNIT descriptor subtype + UCHAR bUnitID; // Constant uniquely identifying the Unit + GUID guidExtensionCode; // Vendor-specific code identifying extension unit + UCHAR bNumControls; // Number of controls in Extension Unit + UCHAR bNrInPins; // Number of input pins + UCHAR baSourceID[]; // IDs of connected units/terminals +} VIDEO_EXTENSION_UNIT, *PVIDEO_EXTENSION_UNIT; +// this is followed by bControlSize, bmControls and iExtension (1 byte) + +__inline size_t SizeOfVideoExtensionUnit(PVIDEO_EXTENSION_UNIT pDesc) +{ + UCHAR bControlSize; + PUCHAR pbCurr; + + // baSourceID is an array, and hence understood to be an address + pbCurr = pDesc->baSourceID + pDesc->bNrInPins; + if (((ULONG_PTR) pbCurr < (ULONG_PTR) pDesc->baSourceID) || + (ULONG_PTR) pbCurr >= (ULONG_PTR)((UCHAR *) pDesc + pDesc->bLength)) + return 0; + + bControlSize = *pbCurr; + return 24 + pDesc->bNrInPins + bControlSize; +} + +#define SIZEOF_VIDEO_EXTENSION_UNIT(pDesc) SizeOfVideoExtensionUnit(pDesc) + + +// Class-specific Interrupt Endpoint Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_ENDPOINT descriptor type + UCHAR bDescriptorSubtype; // EP_INTERRUPT descriptor subtype + USHORT wMaxTransferSize; // Max interrupt payload size +} VIDEO_CS_INTERRUPT, *PVIDEO_CS_INTERRUPT; + +#define SIZEOF_VIDEO_CS_INTERRUPT(pDesc) sizeof(VIDEO_CS_INTERRUPT) + + +// VideoStreaming Input Header Descriptor +typedef struct _VIDEO_STREAMING_INPUT_HEADER +{ + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // VS_INPUT_HEADER descriptor subtype + UCHAR bNumFormats; + USHORT wTotalLength; + UCHAR bEndpointAddress; + UCHAR bmInfo; + UCHAR bTerminalLink; + UCHAR bStillCaptureMethod; + UCHAR bTriggerSupport; + UCHAR bTriggerUsage; + UCHAR bControlSize; + UCHAR bmaControls[]; +} VIDEO_STREAMING_INPUT_HEADER, *PVIDEO_STREAMING_INPUT_HEADER; + +#define SIZEOF_VIDEO_STREAMING_INPUT_HEADER(pDesc) \ + (sizeof(VIDEO_STREAMING_INPUT_HEADER) + (pDesc->bNumFormats * pDesc->bControlSize)) + + +// VideoStreaming Output Header Descriptor +typedef struct _VIDEO_STREAMING_OUTPUT_HEADER +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bNumFormats; + USHORT wTotalLength; + UCHAR bEndpointAddress; + UCHAR bTerminalLink; +} VIDEO_STREAMING_OUTPUT_HEADER, *PVIDEO_STREAMING_OUTPUT_HEADER; + +#define SIZEOF_VIDEO_STREAMING_OUTPUT_HEADER(pDesc) sizeof(VIDEO_STREAMING_OUTPUT_HEADER) + + +typedef struct _VIDEO_STILL_IMAGE_RECT +{ + USHORT wWidth; + USHORT wHeight; +} VIDEO_STILL_IMAGE_RECT; + +// VideoStreaming Still Image Frame Descriptor +typedef struct _VIDEO_STILL_IMAGE_FRAME +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bEndpointAddress; + UCHAR bNumImageSizePatterns; + VIDEO_STILL_IMAGE_RECT aStillRect[]; +} VIDEO_STILL_IMAGE_FRAME, *PVIDEO_STILL_IMAGE_FRAME; + +__inline size_t SizeOfVideoStillImageFrame(PVIDEO_STILL_IMAGE_FRAME pDesc) +{ + UCHAR bNumCompressionPatterns; + PUCHAR pbCurr; + + pbCurr = (PUCHAR) pDesc->aStillRect + (sizeof(VIDEO_STILL_IMAGE_RECT) * pDesc->bNumImageSizePatterns); + bNumCompressionPatterns = *pbCurr; + + return (sizeof(VIDEO_STILL_IMAGE_FRAME) + + (sizeof(VIDEO_STILL_IMAGE_RECT) * pDesc->bNumImageSizePatterns) + + 1 + bNumCompressionPatterns); +} + +#define SIZEOF_VIDEO_STILL_IMAGE_FRAME(pDesc) SizeOfVideoStillImageFrame(pDesc) + + +// VideoStreaming Color Matching Descriptor +typedef struct _VIDEO_COLORFORMAT +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bColorPrimaries; + UCHAR bTransferCharacteristics; + UCHAR bMatrixCoefficients; +} VIDEO_COLORFORMAT, *PVIDEO_COLORFORMAT; + +#define SIZEOF_VIDEO_COLORFORMAT(pDesc) sizeof(VIDEO_COLORFORMAT) + + +// VideoStreaming Uncompressed Format Descriptor +typedef struct _VIDEO_FORMAT_UNCOMPRESSED +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bNumFrameDescriptors; + GUID guidFormat; + UCHAR bBitsPerPixel; + UCHAR bDefaultFrameIndex; + UCHAR bAspectRatioX; + UCHAR bAspectRatioY; + UCHAR bmInterlaceFlags; + UCHAR bCopyProtect; +} VIDEO_FORMAT_UNCOMPRESSED, *PVIDEO_FORMAT_UNCOMPRESSED; + +#define SIZEOF_VIDEO_FORMAT_UNCOMPRESSED(pDesc) sizeof(VIDEO_FORMAT_UNCOMPRESSED) + + +// VideoStreaming Uncompressed Frame Descriptor +typedef struct _VIDEO_FRAME_UNCOMPRESSED +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFrameIndex; + UCHAR bmCapabilities; + USHORT wWidth; + USHORT wHeight; + ULONG dwMinBitRate; + ULONG dwMaxBitRate; + ULONG dwMaxVideoFrameBufferSize; + ULONG dwDefaultFrameInterval; + UCHAR bFrameIntervalType; + ULONG adwFrameInterval[]; +} VIDEO_FRAME_UNCOMPRESSED, *PVIDEO_FRAME_UNCOMPRESSED; + + +__inline size_t SizeOfVideoFrameUncompressed(_In_ PVIDEO_FRAME_UNCOMPRESSED pDesc) +{ + if (pDesc->bFrameIntervalType == 0) { // Continuous + return sizeof(VIDEO_FRAME_UNCOMPRESSED) + (3 * sizeof(ULONG)); + } + else { // Discrete + return sizeof(VIDEO_FRAME_UNCOMPRESSED) + (pDesc->bFrameIntervalType * sizeof(ULONG)); + } +} + +#define SIZEOF_VIDEO_FRAME_UNCOMPRESSED(pDesc) SizeOfVideoFrameUncompressed(pDesc) + + +// VideoStreaming MJPEG Format Descriptor +typedef struct _VIDEO_FORMAT_MJPEG +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bNumFrameDescriptors; + UCHAR bmFlags; + UCHAR bDefaultFrameIndex; + UCHAR bAspectRatioX; + UCHAR bAspectRatioY; + UCHAR bmInterlaceFlags; + UCHAR bCopyProtect; +} VIDEO_FORMAT_MJPEG, *PVIDEO_FORMAT_MJPEG; + +#define SIZEOF_VIDEO_FORMAT_MJPEG(pDesc) sizeof(VIDEO_FORMAT_MJPEG) + + +// VideoStreaming MJPEG Frame Descriptor +typedef struct _VIDEO_FRAME_MJPEG +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFrameIndex; + UCHAR bmCapabilities; + USHORT wWidth; + USHORT wHeight; + ULONG dwMinBitRate; + ULONG dwMaxBitRate; + ULONG dwMaxVideoFrameBufferSize; + ULONG dwDefaultFrameInterval; + UCHAR bFrameIntervalType; + ULONG adwFrameInterval[]; +} VIDEO_FRAME_MJPEG, *PVIDEO_FRAME_MJPEG; + + +__inline size_t SizeOfVideoFrameMjpeg(_In_ PVIDEO_FRAME_MJPEG pDesc) +{ + if (pDesc->bFrameIntervalType == 0) { // Continuous + return sizeof(VIDEO_FRAME_MJPEG) + (3 * sizeof(ULONG)); + } + else { // Discrete + return sizeof(VIDEO_FRAME_MJPEG) + (pDesc->bFrameIntervalType * sizeof(ULONG)); + } +} + +#define SIZEOF_VIDEO_FRAME_MJPEG(pDesc) SizeOfVideoFrameMjpeg(pDesc) + + +// VideoStreaming Vendor Format Descriptor +typedef struct _VIDEO_FORMAT_VENDOR +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bNumFrameDescriptors; + GUID guidMajorFormat; + GUID guidSubFormat; + GUID guidSpecifier; + UCHAR bPayloadClass; + UCHAR bDefaultFrameIndex; + UCHAR bCopyProtect; +} VIDEO_FORMAT_VENDOR, *PVIDEO_FORMAT_VENDOR; + +#define SIZEOF_VIDEO_FORMAT_VENDOR(pDesc) sizeof(VIDEO_FORMAT_VENDOR) + + +// VideoStreaming Vendor Frame Descriptor +typedef struct _VIDEO_FRAME_VENDOR +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFrameIndex; + UCHAR bmCapabilities; + USHORT wWidth; + USHORT wHeight; + ULONG dwMinBitRate; + ULONG dwMaxBitRate; + ULONG dwMaxVideoFrameBufferSize; + ULONG dwDefaultFrameInterval; + UCHAR bFrameIntervalType; + DWORD adwFrameInterval[]; +} VIDEO_FRAME_VENDOR, *PVIDEO_FRAME_VENDOR; + +__inline size_t SizeOfVideoFrameVendor(_In_ PVIDEO_FRAME_VENDOR pDesc) +{ + if (pDesc->bFrameIntervalType == 0) { // Continuous + return sizeof(VIDEO_FRAME_VENDOR) + (3 * sizeof(ULONG)); + } + else { // Discrete + return sizeof(VIDEO_FRAME_VENDOR) + (pDesc->bFrameIntervalType * sizeof(ULONG)); + } +} + +#define SIZEOF_VIDEO_FRAME_VENDOR(pDesc) SizeOfVideoFrameVendor(pDesc) + + +// VideoStreaming DV Format Descriptor +typedef struct _VIDEO_FORMAT_DV +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + ULONG dwMaxVideoFrameBufferSize; + UCHAR bFormatType; +} VIDEO_FORMAT_DV, *PVIDEO_FORMAT_DV; + +#define SIZEOF_VIDEO_FORMAT_DV(pDesc) sizeof(VIDEO_FORMAT_DV) + + +// VideoStreaming MPEG2-TS Format Descriptor +typedef struct _VIDEO_FORMAT_MPEG2TS +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bDataOffset; + UCHAR bPacketLength; + UCHAR bStrideLength; +} VIDEO_FORMAT_MPEG2TS, *PVIDEO_FORMAT_MPEG2TS; + +#define SIZEOF_VIDEO_FORMAT_MPEG2TS(pDesc) sizeof(VIDEO_FORMAT_MPEG2TS) + + +// VideoStreaming MPEG1 System Stream Format Descriptor +typedef struct _VIDEO_FORMAT_MPEG1SS +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bPacketLength; + UCHAR bPackLength; + UCHAR bPackDataType; +} VIDEO_FORMAT_MPEG1SS, *PVIDEO_FORMAT_MPEG1SS; + +#define SIZEOF_VIDEO_FORMAT_MPEG1SS(pDesc) sizeof(VIDEO_FORMAT_MPEG1SS) + + +// VideoStreaming MPEG2-PS Format Descriptor +typedef struct _VIDEO_FORMAT_MPEG2PS +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bPacketLength; + UCHAR bPackLength; + UCHAR bPackDataType; +} VIDEO_FORMAT_MPEG2PS, *PVIDEO_FORMAT_MPEG2PS; + +#define SIZEOF_VIDEO_FORMAT_MPEG2PS(pDesc) sizeof(VIDEO_FORMAT_MPEG2PS) + + +// VideoStreaming MPEG4-SL Format Descriptor +typedef struct _VIDEO_FORMAT_MPEG4SL +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bPacketLength; +} VIDEO_FORMAT_MPEG4SL, *PVIDEO_FORMAT_MPEG4SL; + +#define SIZEOF_VIDEO_FORMAT_MPEG4SL(pDesc) sizeof(VIDEO_FORMAT_MPEG4SL) + +// VideoStreaming Probe/Commit Control +typedef struct _VS_PROBE_COMMIT_CONTROL +{ + USHORT bmHint; + UCHAR bFormatIndex; + UCHAR bFrameIndex; + ULONG dwFrameInterval; + USHORT wKeyFrameRate; + USHORT wPFrameRate; + USHORT wCompQuality; + USHORT wCompWindowSize; + USHORT wDelay; + ULONG dwMaxVideoFrameSize; + ULONG dwMaxPayloadTransferSize; +} VS_PROBE_COMMIT_CONTROL, *PVS_PROBE_COMMIT_CONTROL; + +// VideoStreaming Still Probe/Commit Control +typedef struct _VS_STILL_PROBE_COMMIT_CONTROL +{ + UCHAR bFormatIndex; + UCHAR bFrameIndex; + UCHAR bCompressionIndex; + ULONG dwMaxVideoFrameSize; + ULONG dwMaxPayloadTransferSize; +} VS_STILL_PROBE_COMMIT_CONTROL, *PVS_STILL_PROBE_COMMIT_CONTROL; + + +// Status Interrupt Packet (Video Control) +typedef struct _VC_INTERRUPT_PACKET +{ + UCHAR bStatusType; + UCHAR bOriginator; + UCHAR bEvent; + UCHAR bSelector; + UCHAR bAttribute; + UCHAR bValue[1]; +} VC_INTERRUPT_PACKET, *PVC_INTERRUPT_PACKET; + +// Status Interrupt Packet (Video Control) +typedef struct _VC_INTERRUPT_PACKET_EX +{ + UCHAR bStatusType; + UCHAR bOriginator; + UCHAR bEvent; + UCHAR bSelector; + UCHAR bAttribute; + UCHAR bValue[MAX_INTERRUPT_PACKET_VALUE_SIZE]; +} VC_INTERRUPT_PACKET_EX, *PVC_INTERRUPT_PACKET_EX; + +// Status Interrupt Packet (Video Streaming) +typedef struct _VS_INTERRUPT_PACKET +{ + UCHAR bStatusType; + UCHAR bOriginator; + UCHAR bEvent; + UCHAR bValue[1]; +} VS_INTERRUPT_PACKET, *PVS_INTERRUPT_PACKET; + +// Status Interrupt Packet (Generic) +typedef struct _VIDEO_INTERRUPT_PACKET +{ + UCHAR bStatusType; + UCHAR bOriginator; +} VIDEO_INTERRUPT_PACKET, *PVIDEO_INTERRUPT_PACKET; + + +// Relative property struct +typedef struct _VIDEO_RELATIVE_PROPERTY +{ + UCHAR bValue; + UCHAR bSpeed; +} VIDEO_RELATIVE_PROPERTY, *PVIDEO_RELATIVE_PROPERTY; + +// Relative Zoom control struct +typedef struct _ZOOM_RELATIVE_PROPERTY +{ + UCHAR bZoom; + UCHAR bDigitalZoom; + UCHAR bSpeed; +} ZOOM_RELATIVE_PROPERTY, *PZOOM_RELATIVE_PROPERTY; + +// Relative pan-tilt struct +typedef struct _PANTILT_RELATIVE_PROPERTY +{ + UCHAR bPanRelative; + UCHAR bPanSpeed; + UCHAR bTiltRelative; + UCHAR bTiltSpeed; +} PANTILT_RELATIVE_PROPERTY, *PPANTILT_RELATIVE_PROPERTY; + +typedef struct _MEDIA_INFORMATION_CONTROL +{ + UCHAR bmMediaType; + UCHAR bmWriteProtect; +} MEDIA_INFORMATION_CONTROL, *PMEDIA_INFORMATION_CONTROL; + +typedef struct _TIME_CODE_INFORMATION_CONTROL +{ + UCHAR bcdFrame; + UCHAR bcdSecond; + UCHAR bcdMinute; + UCHAR bcdHour; +} TIME_CODE_INFORMATION_CONTROL, *PTIME_CODE_INFORMATION_CONTROL; + +typedef struct _ATN_INFORMATION_CONTROL +{ + UCHAR bmMediaType; + DWORD dwATN_Data; +} ATN_INFORMATION_CONTROL, *PATN_INFORMATION_CONTROL; + +#define VS_FORMAT_FRAME_BASED 0x10 +#define VS_FRAME_FRAME_BASED 0x11 +#define VS_FORMAT_STREAM_BASED 0x12 + +// Format Descriptor for UVC 1.1 frame based format +typedef struct _VIDEO_FORMAT_FRAME +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bNumFrameDescriptors; + GUID guidFormat; + UCHAR bBitsPerPixel; + UCHAR bDefaultFrameIndex; + UCHAR bAspectRatioX; + UCHAR bAspectRatioY; + UCHAR bmInterlaceFlags; + UCHAR bCopyProtect; + UCHAR bVariableSize; +} VIDEO_FORMAT_FRAME, *PVIDEO_FORMAT_FRAME; + +#define SIZEOF_VIDEO_FORMAT_FRAME(pDesc) sizeof(VIDEO_FORMAT_FRAME) + + +// Frame Descriptor for UVC 1.1 frame based format +typedef struct _VIDEO_FRAME_FRAME +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFrameIndex; + UCHAR bmCapabilities; + USHORT wWidth; + USHORT wHeight; + ULONG dwMinBitRate; + ULONG dwMaxBitRate; + ULONG dwDefaultFrameInterval; + UCHAR bFrameIntervalType; + ULONG dwBytesPerLine; + ULONG adwFrameInterval[]; +} VIDEO_FRAME_FRAME, *PVIDEO_FRAME_FRAME; + +__inline size_t SizeOfVideoFrameFrame(_In_ PVIDEO_FRAME_FRAME pDesc) +{ + if (pDesc->bFrameIntervalType == 0) { // Continuous + return sizeof(VIDEO_FRAME_FRAME) + (3 * sizeof(ULONG)); + } + else { // Discrete + return sizeof(VIDEO_FRAME_FRAME) + (pDesc->bFrameIntervalType * sizeof(ULONG)); + } +} + +#define SIZEOF_VIDEO_FRAME_FRAME(pDesc) SizeOfVideoFrameFrame(pDesc) + +// VideoStreaming Stream Based Format Descriptor +typedef struct _VIDEO_FORMAT_STREAM +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + GUID guidFormat; + ULONG dwPacketLength; +} VIDEO_FORMAT_STREAM, *PVIDEO_FORMAT_STREAM; + +#define SIZEOF_VIDEO_FORMAT_STREAM(pDesc) sizeof(VIDEO_FORMAT_STREAM) + +// VideoStreaming Probe/Commit Control +typedef struct _VS_PROBE_COMMIT_CONTROL2 +{ + USHORT bmHint; + UCHAR bFormatIndex; + UCHAR bFrameIndex; + ULONG dwFrameInterval; + USHORT wKeyFrameRate; + USHORT wPFrameRate; + USHORT wCompQuality; + USHORT wCompWindowSize; + USHORT wDelay; + ULONG dwMaxVideoFrameSize; + ULONG dwMaxPayloadTransferSize; + ULONG dwClockFrequency; + UCHAR bmFramingInfo; + UCHAR bPreferredVersion; + UCHAR bMinVersion; + UCHAR bMaxVersion; +} VS_PROBE_COMMIT_CONTROL2, *PVS_PROBE_COMMIT_CONTROL2; + +#pragma pack( pop, vdc_descriptor_structs ) +#pragma warning( default : 4200 ) + + +// +// END - VDC Descriptor and Control Structures +// + +#endif // ___UVCDESC_H___ diff --git a/uvcview.h b/uvcview.h new file mode 100644 index 0000000..8699778 --- /dev/null +++ b/uvcview.h @@ -0,0 +1,672 @@ +/*++ + +Copyright (c) 1997-2008 Microsoft Corporation + +Module Name: + + UVCVIEW.H + +Abstract: + + This is the header file for UVCVIEW + +Environment: + + user mode + +Revision History: + + 04-25-97 : created + 04/13/2005 : major bug fixing + +--*/ + +/***************************************************************************** + I N C L U D E S +*****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// This is mostly a private USB Audio descriptor header +#include "usbdesc.h" + +// This is the inbox USBVideo driver descriptor header (copied locally) +#include "uvcdesc.h" + +/***************************************************************************** + P R A G M A S +*****************************************************************************/ + +#pragma once + +/***************************************************************************** + D E F I N E S +*****************************************************************************/ + +// define H264_SUPPORT to add H.264 support to uvcview.exe +#define H264_SUPPORT + +#define TEXT_ITEM_LENGTH 64 + +#ifdef DEBUG +#undef DBG +#define DBG 1 +#endif + +#if DBG +#define OOPS() Oops(__FILE__, __LINE__) +#else +#define OOPS() +#endif + +#if DBG + +#define ALLOC(dwBytes) MyAlloc(__FILE__, __LINE__, (dwBytes)) + +#define REALLOC(hMem, dwBytes) MyReAlloc((hMem), (dwBytes)) + +#define FREE(hMem) MyFree((hMem)) + +#define CHECKFORLEAKS() MyCheckForLeaks() + +#else + +#define ALLOC(dwBytes) GlobalAlloc(GPTR,(dwBytes)) + +#define REALLOC(hMem, dwBytes) GlobalReAlloc((hMem), (dwBytes), (GMEM_MOVEABLE|GMEM_ZEROINIT)) + +#define FREE(hMem) GlobalFree((hMem)) + +#define CHECKFORLEAKS() + +#endif + +#define DEVICE_CONFIGURATION_TEXT_LENGTH 10240 + +#define STR_INVALID_POWER_STATE "(invalid state) " +#define STR_UNKNOWN_CONTROLLER_FLAVOR "Unknown" + +FORCEINLINE +VOID +InitializeListHead( + _Out_ PLIST_ENTRY ListHead + ) +{ + ListHead->Flink = ListHead->Blink = ListHead; +} + +// +// BOOLEAN +// IsListEmpty( +// PLIST_ENTRY ListHead +// ); +// + +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + +// +// PLIST_ENTRY +// RemoveHeadList( +// PLIST_ENTRY ListHead +// ); +// + +#define RemoveHeadList(ListHead) \ + (ListHead)->Flink;\ + {RemoveEntryList((ListHead)->Flink)} + +// +// VOID +// RemoveEntryList( +// PLIST_ENTRY Entry +// ); +// + +#define RemoveEntryList(Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_Flink;\ + _EX_Flink = (Entry)->Flink;\ + _EX_Blink = (Entry)->Blink;\ + _EX_Blink->Flink = _EX_Flink;\ + _EX_Flink->Blink = _EX_Blink;\ + } + +// +// VOID +// InsertTailList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertTailList(ListHead,Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_ListHead;\ + _EX_ListHead = (ListHead);\ + _EX_Blink = _EX_ListHead->Blink;\ + (Entry)->Flink = _EX_ListHead;\ + (Entry)->Blink = _EX_Blink;\ + _EX_Blink->Flink = (Entry);\ + _EX_ListHead->Blink = (Entry);\ + } + +// global version for USB Video Class spec version (pre-release) +#define BCDVDC 0x0083 + +// A.2 Video Interface Subclass Codes +#define SC_VIDEO_INTERFACE_COLLECTION 0x03 + +// A.3 Video Interface Protocol Codes +#define PC_PROTOCOL_UNDEFINED 0x00 + +// USB Video Class spec version +#define NOT_UVC 0x0 +#define UVC10 0x100 +#define UVC11 0x110 + +#ifdef H264_SUPPORT +#define UVC15 0x150 +#endif + +#define OUTPUT_MESSAGE_MAX_LENGTH 1024 +#define MAX_DEVICE_PROP 200 +#define MAX_DRIVER_KEY_NAME 256 + +/***************************************************************************** + T Y P E D E F S +*****************************************************************************/ + +typedef enum _TREEICON +{ + ComputerIcon, + HubIcon, + NoDeviceIcon, + GoodDeviceIcon, + BadDeviceIcon, + GoodSsDeviceIcon, + NoSsDeviceIcon +} TREEICON; + +// Callback function for walking TreeView items +// +typedef VOID +(*LPFNTREECALLBACK)( + HWND hTreeWnd, + HTREEITEM hTreeItem, + PVOID pContext +); + + +// Callback notification function called at end of every tree depth +typedef VOID +(*LPFNTREENOTIFYCALLBACK)(PVOID pContext); + +// +// Structure used to build a linked list of String Descriptors +// retrieved from a device. +// + +typedef struct _STRING_DESCRIPTOR_NODE +{ + struct _STRING_DESCRIPTOR_NODE *Next; + UCHAR DescriptorIndex; + USHORT LanguageID; + USB_STRING_DESCRIPTOR StringDescriptor[1]; +} STRING_DESCRIPTOR_NODE, *PSTRING_DESCRIPTOR_NODE; + +// +// A collection of device properties. The device can be hub, host controller or usb device +// +typedef struct _USB_DEVICE_PNP_STRINGS +{ + PWCHAR DeviceId; + PWCHAR DeviceDesc; + PWCHAR HwId; + PWCHAR Service; + PWCHAR DeviceClass; + PWCHAR PowerState; +} USB_DEVICE_PNP_STRINGS, *PUSB_DEVICE_PNP_STRINGS; + +typedef struct _DEVICE_INFO_NODE { + HDEVINFO DeviceInfo; + LIST_ENTRY ListEntry; + SP_DEVINFO_DATA DeviceInfoData; + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceDetailData; + PWSTR DeviceDescName; + ULONG DeviceDescNameLength; + PWSTR DeviceDriverName; + ULONG DeviceDriverNameLength; + DEVICE_POWER_STATE LatestDevicePowerState; +} DEVICE_INFO_NODE, *PDEVICE_INFO_NODE; + +// +// Structures assocated with TreeView items through the lParam. When an item +// is selected, the lParam is retrieved and the structure it which it points +// is used to display information in the edit control. +// + +typedef enum _USBDEVICEINFOTYPE +{ + HostControllerInfo, + RootHubInfo, + ExternalHubInfo, + DeviceInfo +} USBDEVICEINFOTYPE, *PUSBDEVICEINFOTYPE; + +struct _USBROOTHUBINFO; +struct _USBEXTERNALHUBINFO; + +typedef _USBEXTERNALHUBINFO USBDEVICEINFO, *PUSBDEVICEINFO; + + +typedef struct _USBROOTHUBINFO +{ + USBDEVICEINFOTYPE DeviceInfoType; + PUSB_NODE_INFORMATION HubInfo; + PUSB_HUB_INFORMATION_EX HubInfoEx; + PWCHAR HubName; + PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps; + PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties; + PDEVICE_INFO_NODE DeviceInfoNode; + PUSB_HUB_CAPABILITIES_EX HubCapabilityEx; + std::vector HubPorts; +} USBROOTHUBINFO, *PUSBROOTHUBINFO; + + +typedef struct _USBEXTERNALHUBINFO : public _USBROOTHUBINFO +{ + PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo; + PUSB_DESCRIPTOR_REQUEST ConfigDesc; + PUSB_DESCRIPTOR_REQUEST BosDesc; + PSTRING_DESCRIPTOR_NODE StringDescs; + PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2; // NULL if root HUB +} USBEXTERNALHUBINFO, *PUSBEXTERNALHUBINFO; + +typedef struct _USBHOSTCONTROLLERINFO +{ + USBDEVICEINFOTYPE DeviceInfoType; + LIST_ENTRY ListEntry; + PWCHAR DriverKey; + ULONG VendorID; + ULONG DeviceID; + ULONG SubSysID; + ULONG Revision; + USB_POWER_INFO USBPowerInfo[6]; + BOOL BusDeviceFunctionValid; + ULONG BusNumber; + USHORT BusDevice; + USHORT BusFunction; + PUSB_CONTROLLER_INFO_0 ControllerInfo; + PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties; + PUSBROOTHUBINFO RootHub; +} USBHOSTCONTROLLERINFO, *PUSBHOSTCONTROLLERINFO; + +typedef struct _STRINGLIST +{ +#ifdef H264_SUPPORT + ULONGLONG ulFlag; +#else + ULONG ulFlag; +#endif + PCHAR pszString; + PCHAR pszModifier; + +} STRINGLIST, * PSTRINGLIST; + +typedef struct _DEVICE_GUID_LIST { + HDEVINFO DeviceInfo; + LIST_ENTRY ListHead; +} DEVICE_GUID_LIST, *PDEVICE_GUID_LIST; + + +/***************************************************************************** + G L O B A L S +*****************************************************************************/ + +// +// USBVIEW.C +// + +static BOOL gDoConfigDesc = TRUE; +static BOOL gDoAnnotation = TRUE; +static BOOL gLogDebug = TRUE; +static int TotalHubs; + +// +// ENUM.C +// + +static constexpr const wchar_t* ConnectionStatuses[] = +{ + L"", // 0 - NoDeviceConnected + L"", // 1 - DeviceConnected + L"FailedEnumeration", // 2 - DeviceFailedEnumeration + L"GeneralFailure", // 3 - DeviceGeneralFailure + L"Overcurrent", // 4 - DeviceCausedOvercurrent + L"NotEnoughPower", // 5 - DeviceNotEnoughPower + L"NotEnoughBandwidth", // 6 - DeviceNotEnoughBandwidth + L"HubNestedTooDeeply", // 7 - DeviceHubNestedTooDeeply + L"InLegacyHub", // 8 - DeviceInLegacyHub + L"Enumerating", // 9 - DeviceEnumerating + L"Reset" // 10 - DeviceReset +}; + +// +// DISPVID.C +// +DEFINE_GUID(YUY2_Format,0x32595559L,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71); +DEFINE_GUID(NV12_Format,0x3231564EL,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71); + +#ifdef H264_SUPPORT +DEFINE_GUID(H264_Format,0x34363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +#endif + +// The following flags/variables are all initialized in Display.c InitializePerDeviceSettings() +// +// Save the default frame from the MJPEG, Uncompressed, Vendor and Frame Based Format descriptor +// Check for this when processing the individual Frame descriptors +static UCHAR g_chMJPEGFrameDefault; +static UCHAR g_chUNCFrameDefault; +static UCHAR g_chVendorFrameDefault; +static UCHAR g_chFrameBasedFrameDefault; + +// Spec version of UVC device +static UINT g_chUVCversion; + +// Base address of the USBDEVICEINFO for device we're parsing +static PUSBDEVICEINFO CurrentUSBDeviceInfo; + +// Base address of the Configuration descriptor we're parsing +static PUSB_CONFIGURATION_DESCRIPTOR CurrentConfigDesc; + +// Length of the current configuration descriptor +static DWORD dwConfigLength; +// Our current position from the beginning of the config descriptor +static DWORD dwConfigIndex; + +// +// DISPLAY.C +// +static int gDeviceSpeed; + +// Save the current Configuration starting and ending addresses +// Used in ValidateDescAddress() +// +static PUSB_CONFIGURATION_DESCRIPTOR g_pConfigDesc; +static PSTRING_DESCRIPTOR_NODE g_pStringDescs; +static PUCHAR g_descEnd; + +/***************************************************************************** + F U N C T I O N P R O T O T Y P E S +*****************************************************************************/ + +// +// USBVIEW.C +// + +HTREEITEM +AddLeaf ( + HTREEITEM hTreeParent, + LPARAM lParam, + _In_ LPTSTR lpszText, + TREEICON TreeIcon +); + +VOID +Oops +( + _In_ PCHAR File, + ULONG Line +); + +// +// DISPLAY.C +// + +EXTERN_C UINT IsIADDevice (PUSBDEVICEINFO info); +EXTERN_C UINT IsUVCDevice (PUSBDEVICEINFO info); +EXTERN_C PCHAR GetVendorString(USHORT idVendor); +EXTERN_C PCHAR GetLangIDString(USHORT idLang); +EXTERN_C UINT GetConfigurationSize (PUSBDEVICEINFO info); +EXTERN_C PUSB_COMMON_DESCRIPTOR +GetNextDescriptor( + _In_reads_bytes_(TotalLength) + PUSB_COMMON_DESCRIPTOR FirstDescriptor, + _In_ + ULONG TotalLength, + _In_ + PUSB_COMMON_DESCRIPTOR StartDescriptor, + _In_ long + DescriptorType + ); + +HRESULT +UpdateTreeItemDeviceInfo( + HWND hTreeWnd, + HTREEITEM hTreeItem + ); + +PCHAR +GetTextBuffer( +); + +BOOL +ResetTextBuffer( +); + +BOOL +CreateTextBuffer ( +); + +VOID +DestroyTextBuffer ( +); + +UINT +GetTextBufferPos ( +); + +VOID +UpdateEditControl ( + HWND hEditWnd, + HWND hTreeWnd, + HTREEITEM hTreeItem +); + + +VOID __cdecl +AppendBuffer ( + LPCTSTR lpFormat, + ... +); + +VOID __cdecl +AppendTextBuffer ( + LPCTSTR lpFormat, + ... +); + +VOID +DisplayStringDescriptor ( + UCHAR Index, + PSTRING_DESCRIPTOR_NODE StringDescs, + DEVICE_POWER_STATE LatestDevicePowerState +); + +PCHAR +GetStringFromList( + PSTRINGLIST slPowerState, + ULONG ulNumElements, + +#ifdef H264_SUPPORT + ULONGLONG ulFlag, +#else + ULONG ulFlag, +#endif + _In_ PCHAR szDefault + ); + +EXTERN_C PCHAR GetPowerStateString( + WDMUSB_POWER_STATE powerState + ); + +EXTERN_C PCHAR GetControllerFlavorString( + USB_CONTROLLER_FLAVOR flavor + ); + +EXTERN_C ULONG GetEhciDebugPort( + ULONG vendorId, + ULONG deviceId + ); + +VOID +WalkTreeTopDown( + _In_ HTREEITEM hTreeItem, + _In_ LPFNTREECALLBACK lpfnTreeCallback, + _In_opt_ PVOID pContext, + _In_opt_ LPFNTREENOTIFYCALLBACK lpfnTreeNotifyCallback + ); + +VOID RefreshTree (VOID); + +// +// ENUM.C +// + +std::vector +EnumerateHostControllers ( + HTREEITEM hTreeParent, + ULONG *DevicesConnected + ); + + +VOID +CleanupItem ( + HWND hTreeWnd, + HTREEITEM hTreeItem, + PVOID pContext + ); + +DEVICE_POWER_STATE +AcquireDevicePowerState( + _Inout_ PDEVICE_INFO_NODE pNode + ); + +_Success_(return == TRUE) +BOOL +GetDeviceProperty( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData, + _In_ DWORD Property, + _Outptr_ LPWSTR *ppBuffer + ); + +void +ClearDeviceList( + PDEVICE_GUID_LIST DeviceList + ); + +// +// DEBUG.C +// + +_Success_(return != NULL) +_Post_writable_byte_size_(dwBytes) +HGLOBAL +MyAlloc ( + _In_ LPCCH File, + ULONG Line, + DWORD dwBytes + ); + +_Success_(return != NULL) +_Post_writable_byte_size_(dwBytes) +HGLOBAL +MyReAlloc ( + HGLOBAL hMem, + DWORD dwBytes + ); + +HGLOBAL +MyFree ( + HGLOBAL hMem + ); + +VOID +MyCheckForLeaks ( + VOID + ); + +// +// DEVNODE.C +// + + +PUSB_DEVICE_PNP_STRINGS +DriverNameToDeviceProperties( + _In_reads_bytes_(cbDriverName) PWCHAR DriverName, + _In_ size_t cbDriverName + ); + +VOID FreeDeviceProperties( + _In_ PUSB_DEVICE_PNP_STRINGS *ppDevProps + ); +// +// DISPAUD.C +// + +BOOL +DisplayAudioDescriptor ( + PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc, + UCHAR bInterfaceSubClass + ); + +// +// DISPVID.C +// + +BOOL +DisplayVideoDescriptor ( + PVIDEO_SPECIFIC VidCommonDesc, + UCHAR bInterfaceSubClass, + PSTRING_DESCRIPTOR_NODE StringDescs, + DEVICE_POWER_STATE LatestDevicePowerState + ); + +// +// DISPLAY.C +// + +BOOL +ValidateDescAddress ( + PUSB_COMMON_DESCRIPTOR commonDesc + );