@@ -77,6 +77,29 @@ struct DriverInfo {
7777 }
7878};
7979
80+ bool IsHexString (const std::wstring& str) {
81+ for (const wchar_t & c : str) {
82+ if (!((c >= L' 0' && c <= L' 9' ) || (c >= L' A' && c <= L' F' ) || (c >= L' a' && c <= L' f' ))) {
83+ return false ;
84+ }
85+ }
86+ return true ;
87+ }
88+
89+ // Converts a wide string ACPI (up to 4 characters) representing a hardware ID component from into a uint32_t.
90+ // e.g., "QCOM" from "VEN_QCOM". The conversion is done in a little-endian manner, meaning the first character
91+ // of the string becomes the least significant byte of the integer, and the fourth character
92+ // becomes the most significant byte.
93+ uint32_t AcpiWStringToUint32Id (const std::wstring& vendor_name) {
94+ uint32_t vendor_id = 0 ;
95+ for (size_t i = 0 ; i < 4 && i < vendor_name.size (); ++i) {
96+ // For little-endian, place each character at the appropriate byte position
97+ // First character goes into lowest byte, last character into highest byte
98+ vendor_id |= static_cast <unsigned char >(vendor_name[i] & 0xFF ) << (i * 8 );
99+ }
100+ return vendor_id;
101+ }
102+
80103uint64_t GetDeviceKey (uint32_t vendor_id, uint32_t device_id) {
81104 return (uint64_t (vendor_id) << 32 ) | device_id;
82105}
@@ -134,25 +157,35 @@ std::unordered_map<uint64_t, DeviceInfo> GetDeviceInfoSetupApi(const std::unorde
134157 // PCI\VEN_xxxx&DEV_yyyy&...
135158 // ACPI\VEN_xxxx&DEV_yyyy&... if we're lucky.
136159 // ACPI values seem to be very inconsistent, so we check fairly carefully and always require a device id.
137- const auto get_id = [](const std::wstring& hardware_id, const std::wstring& prefix) -> uint32_t {
160+ const auto get_id = [](bool is_pci, const std::wstring& hardware_id, const std::wstring& prefix) -> uint32_t {
138161 if (auto idx = hardware_id.find (prefix); idx != std::wstring::npos) {
139162 auto id = hardware_id.substr (idx + prefix.size (), 4 );
163+
140164 if (id.size () == 4 ) {
141- return static_cast <uint32_t >(std::stoul (id, nullptr , 16 ));
165+ if (is_pci || IsHexString (id)) {
166+ // PCI entries have hex numbers. ACPI might.
167+ return static_cast <uint32_t >(std::stoul (id, nullptr , 16 ));
168+ } else {
169+ // ACPI can have things like "VEN_QCOM". Fallback to using this conversion where the characters
170+ // are converted in little-endian order.
171+ return AcpiWStringToUint32Id (id);
172+ }
142173 }
143174 }
144175
145176 return 0 ;
146177 };
147178
148- // Processor ID should come from CPUID mapping.
179+ const bool is_pci = std::wstring (buffer, 3 ) == std::wstring (L" PCI" );
180+
149181 if (guid == GUID_DEVCLASS_PROCESSOR) {
182+ // Processor ID should come from CPUID mapping.
150183 vendor_id = CPUIDInfo::GetCPUIDInfo ().GetCPUVendorId ();
151184 } else {
152- vendor_id = get_id (buffer, L" VEN_" );
185+ vendor_id = get_id (is_pci, buffer, L" VEN_" );
153186 }
154187
155- device_id = get_id (buffer, L" DEV_" );
188+ device_id = get_id (is_pci, buffer, L" DEV_" );
156189
157190 // Won't always have a vendor id from an ACPI entry. ACPI is not defined for this purpose.
158191 if (vendor_id == 0 && device_id == 0 ) {
0 commit comments