1 /*
2 * The PCI Library -- List PCI devices on Win32 via Configuration Manager
3 *
4 * Copyright (c) 2021 Pali Rohár <[email protected]>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL v2+.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include <windows.h>
12 #include <cfgmgr32.h>
13
14 #include <ctype.h> /* for isxdigit() */
15 #include <stdio.h> /* for sprintf() */
16 #include <string.h> /* for strlen(), strchr(), strncmp() */
17 #include <wchar.h> /* for wcslen(), wcscpy() */
18
19 #include "internal.h"
20 #include "win32-helpers.h"
21
22 /* Unfortunately MinGW32 toolchain does not provide these cfgmgr32 constants. */
23
24 #ifndef RegDisposition_OpenExisting
25 #define RegDisposition_OpenExisting 0x00000001
26 #endif
27
28 #ifndef CM_REGISTRY_SOFTWARE
29 #define CM_REGISTRY_SOFTWARE 0x00000001
30 #endif
31
32 #ifndef CM_DRP_HARDWAREID
33 #define CM_DRP_HARDWAREID 0x00000002
34 #endif
35 #ifndef CM_DRP_SERVICE
36 #define CM_DRP_SERVICE 0x00000005
37 #endif
38 #ifndef CM_DRP_BUSNUMBER
39 #define CM_DRP_BUSNUMBER 0x00000016
40 #endif
41 #ifndef CM_DRP_ADDRESS
42 #define CM_DRP_ADDRESS 0x0000001D
43 #endif
44
45 #ifndef CR_INVALID_CONFLICT_LIST
46 #define CR_INVALID_CONFLICT_LIST 0x00000039
47 #endif
48 #ifndef CR_INVALID_INDEX
49 #define CR_INVALID_INDEX 0x0000003A
50 #endif
51 #ifndef CR_INVALID_STRUCTURE_SIZE
52 #define CR_INVALID_STRUCTURE_SIZE 0x0000003B
53 #endif
54
55 #ifndef fIOD_10_BIT_DECODE
56 #define fIOD_10_BIT_DECODE 0x0004
57 #endif
58 #ifndef fIOD_12_BIT_DECODE
59 #define fIOD_12_BIT_DECODE 0x0008
60 #endif
61 #ifndef fIOD_16_BIT_DECODE
62 #define fIOD_16_BIT_DECODE 0x0010
63 #endif
64 #ifndef fIOD_POSITIVE_DECODE
65 #define fIOD_POSITIVE_DECODE 0x0020
66 #endif
67 #ifndef fIOD_PASSIVE_DECODE
68 #define fIOD_PASSIVE_DECODE 0x0040
69 #endif
70 #ifndef fIOD_WINDOW_DECODE
71 #define fIOD_WINDOW_DECODE 0x0080
72 #endif
73 #ifndef fIOD_PORT_BAR
74 #define fIOD_PORT_BAR 0x0100
75 #endif
76
77 #ifndef fMD_WINDOW_DECODE
78 #define fMD_WINDOW_DECODE 0x0040
79 #endif
80 #ifndef fMD_MEMORY_BAR
81 #define fMD_MEMORY_BAR 0x0080
82 #endif
83
84 #ifndef mMD_Prefetchable
85 #define mMD_Prefetchable fMD_Prefetchable
86 #endif
87
88 /*
89 * Unfortunately MinGW32 toolchain does not provide import library for these
90 * cfgmgr32.dll functions. So resolve pointers to these functions at runtime.
91 * MinGW-w64 toolchain provides them also in 32-bit mode.
92 */
93
94 #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
95
96 #ifdef CM_Get_DevNode_Registry_PropertyA
97 #undef CM_Get_DevNode_Registry_PropertyA
98 #endif
99 static CONFIGRET (WINAPI *MyCM_Get_DevNode_Registry_PropertyA)(DEVINST dnDevInst, ULONG ulProperty, PULONG pulRegDataType, PVOID Buffer, PULONG pulLength, ULONG ulFlags);
100 #define CM_Get_DevNode_Registry_PropertyA MyCM_Get_DevNode_Registry_PropertyA
101
102 #ifdef CM_Get_DevNode_Registry_PropertyW
103 #undef CM_Get_DevNode_Registry_PropertyW
104 #endif
105 static CONFIGRET (WINAPI *MyCM_Get_DevNode_Registry_PropertyW)(DEVINST dnDevInst, ULONG ulProperty, PULONG pulRegDataType, PVOID Buffer, PULONG pulLength, ULONG ulFlags);
106 #define CM_Get_DevNode_Registry_PropertyW MyCM_Get_DevNode_Registry_PropertyW
107
108 #ifndef CM_Open_DevNode_Key
109 #undef CM_Open_DevNode_Key
110 #endif
111 static CONFIGRET (WINAPI *MyCM_Open_DevNode_Key)(DEVINST dnDevNode, REGSAM samDesired, ULONG ulHardwareProfile, REGDISPOSITION Disposition, PHKEY phkDevice, ULONG ulFlags);
112 #define CM_Open_DevNode_Key MyCM_Open_DevNode_Key
113
114 static BOOL
resolve_cfgmgr32_functions(void)115 resolve_cfgmgr32_functions(void)
116 {
117 HMODULE cfgmgr32;
118
119 if (CM_Get_DevNode_Registry_PropertyA && CM_Get_DevNode_Registry_PropertyW && CM_Open_DevNode_Key)
120 return TRUE;
121
122 cfgmgr32 = GetModuleHandleA("cfgmgr32.dll");
123 if (!cfgmgr32)
124 return FALSE;
125
126 CM_Get_DevNode_Registry_PropertyA = (void *)GetProcAddress(cfgmgr32, "CM_Get_DevNode_Registry_PropertyA");
127 CM_Get_DevNode_Registry_PropertyW = (void *)GetProcAddress(cfgmgr32, "CM_Get_DevNode_Registry_PropertyW");
128 CM_Open_DevNode_Key = (void *)GetProcAddress(cfgmgr32, "CM_Open_DevNode_Key");
129 if (!CM_Get_DevNode_Registry_PropertyA || !CM_Get_DevNode_Registry_PropertyW || !CM_Open_DevNode_Key)
130 return FALSE;
131
132 return TRUE;
133 }
134
135 #endif
136
137 /*
138 * cfgmgr32.dll uses custom non-Win32 error numbers which are unsupported by
139 * Win32 APIs like GetLastError() and FormatMessage() functions.
140 *
141 * Windows 7 introduced new cfgmgr32.dll function CM_MapCrToWin32Err() for
142 * translating mapping CR_* errors to Win32 errors but most error codes are
143 * not mapped. So this function is unusable.
144 *
145 * Error strings for CR_* errors are defined in cmapi.rc file which is
146 * statically linked into some system libraries (e.g. filemgmt.dll,
147 * acledit.dll, netui0.dll or netui2.dll) but due to static linking it is
148 * not possible to access these error strings easily at runtime.
149 *
150 * So define own function for translating CR_* errors directly to strings.
151 */
152 static const char *
cr_strerror(CONFIGRET cr_error_id)153 cr_strerror(CONFIGRET cr_error_id)
154 {
155 static char unknown_error[sizeof("Unknown CR error XXXXXXXXXX")];
156 static const char *cr_errors[] = {
157 "The operation completed successfully",
158 "CR_DEFAULT",
159 "Not enough memory is available to process this command",
160 "A required pointer parameter is invalid",
161 "The ulFlags parameter specified is invalid for this operation",
162 "The device instance handle parameter is not valid",
163 "The supplied resource descriptor parameter is invalid",
164 "The supplied logical configuration parameter is invalid",
165 "CR_INVALID_ARBITRATOR",
166 "CR_INVALID_NODELIST",
167 "CR_DEVNODE_HAS_REQS/CR_DEVINST_HAS_REQS",
168 "The RESOURCEID parameter does not contain a valid RESOURCEID",
169 "CR_DLVXD_NOT_FOUND",
170 "The specified device instance handle does not correspond to a present device",
171 "There are no more logical configurations available",
172 "There are no more resource descriptions available",
173 "This device instance already exists",
174 "The supplied range list parameter is invalid",
175 "CR_INVALID_RANGE",
176 "A general internal error occurred",
177 "CR_NO_SUCH_LOGICAL_DEV",
178 "The device is disabled for this configuration",
179 "CR_NOT_SYSTEM_VM",
180 "A service or application refused to allow removal of this device",
181 "CR_APM_VETOED",
182 "CR_INVALID_LOAD_TYPE",
183 "An output parameter was too small to hold all the data available",
184 "CR_NO_ARBITRATOR",
185 "CR_NO_REGISTRY_HANDLE",
186 "A required entry in the registry is missing or an attempt to write to the registry failed",
187 "The specified Device ID is not a valid Device ID",
188 "One or more parameters were invalid",
189 "CR_INVALID_API",
190 "CR_DEVLOADER_NOT_READY",
191 "CR_NEED_RESTART",
192 "There are no more hardware profiles available",
193 "CR_DEVICE_NOT_THERE",
194 "The specified value does not exist in the registry",
195 "CR_WRONG_TYPE",
196 "The specified priority is invalid for this operation",
197 "This device cannot be disabled",
198 "CR_FREE_RESOURCES",
199 "CR_QUERY_VETOED",
200 "CR_CANT_SHARE_IRQ",
201 "CR_NO_DEPENDENT",
202 "CR_SAME_RESOURCES",
203 "The specified key does not exist in the registry",
204 "The specified machine name does not meet the UNC naming conventions",
205 "A general remote communication error occurred",
206 "The machine selected for remote communication is not available at this time",
207 "The Plug and Play service or another required service is not available",
208 "Access denied",
209 "This routine is not implemented in this version of the operating system",
210 "The specified property type is invalid for this operation",
211 "Device interface is active",
212 "No such device interface",
213 "Invalid reference string",
214 "Invalid conflict list",
215 "Invalid index",
216 "Invalid structure size"
217 };
218 if (cr_error_id <= 0 || cr_error_id >= sizeof(cr_errors)/sizeof(*cr_errors))
219 {
220 sprintf(unknown_error, "Unknown CR error %lu", cr_error_id);
221 return unknown_error;
222 }
223 return cr_errors[cr_error_id];
224 }
225
226 static int
fmt_validate(const char * s,int len,const char * fmt)227 fmt_validate(const char *s, int len, const char *fmt)
228 {
229 int i;
230
231 for (i = 0; i < len; i++)
232 if (!fmt[i] || (fmt[i] == '#' ? !isxdigit(s[i]) : fmt[i] != s[i]))
233 return 0;
234
235 return 1;
236 }
237
238 static int
seq_xdigit_validate(const char * s,int mult,int min)239 seq_xdigit_validate(const char *s, int mult, int min)
240 {
241 int i, len;
242
243 len = strlen(s);
244 if (len < min*mult || len % mult)
245 return 0;
246
247 for (i = 0; i < len; i++)
248 if (!isxdigit(s[i]))
249 return 0;
250
251 return 1;
252 }
253
254 static LPWSTR
get_device_service_name(struct pci_access * a,DEVINST devinst,DEVINSTID_A devinst_id,BOOL * supported)255 get_device_service_name(struct pci_access *a, DEVINST devinst, DEVINSTID_A devinst_id, BOOL *supported)
256 {
257 ULONG reg_type, reg_size, reg_len;
258 LPWSTR service_name;
259 CONFIGRET cr;
260
261 /*
262 * All data are stored as 7-bit ASCII strings in system but service name is
263 * exception. It can contain UNICODE. Moreover it is passed to other Win32 API
264 * functions and therefore it cannot be converted to 8-bit ANSI string without
265 * data loss. So use wide function CM_Get_DevNode_Registry_PropertyW() in this
266 * case and deal with all wchar_t problems...
267 */
268
269 reg_size = 0;
270 cr = CM_Get_DevNode_Registry_PropertyW(devinst, CM_DRP_SERVICE, ®_type, NULL, ®_size, 0);
271 if (cr == CR_CALL_NOT_IMPLEMENTED)
272 {
273 *supported = FALSE;
274 return NULL;
275 }
276 else if (cr == CR_NO_SUCH_VALUE)
277 {
278 *supported = TRUE;
279 return NULL;
280 }
281 else if (cr != CR_SUCCESS &&
282 cr != CR_BUFFER_SMALL)
283 {
284 a->warning("Cannot retrieve service name for PCI device %s: %s.", devinst_id, cr_strerror(cr));
285 *supported = TRUE;
286 return NULL;
287 }
288 else if (reg_type != REG_SZ)
289 {
290 a->warning("Cannot retrieve service name for PCI device %s: Service name is stored as unknown type 0x%lx.", devinst_id, reg_type);
291 *supported = TRUE;
292 return NULL;
293 }
294
295 retry:
296 /*
297 * Returned size is on older Windows versions without nul-term char.
298 * So explicitly increase size and fill nul-term byte.
299 */
300 reg_size += sizeof(service_name[0]);
301 service_name = pci_malloc(a, reg_size);
302 reg_len = reg_size;
303 cr = CM_Get_DevNode_Registry_PropertyW(devinst, CM_DRP_SERVICE, ®_type, service_name, ®_len, 0);
304 service_name[reg_size/sizeof(service_name[0]) - 1] = 0;
305 if (reg_len > reg_size)
306 {
307 pci_mfree(service_name);
308 reg_size = reg_len;
309 goto retry;
310 }
311 else if (cr != CR_SUCCESS)
312 {
313 a->warning("Cannot retrieve service name for PCI device %s: %s.", devinst_id, cr_strerror(cr));
314 pci_mfree(service_name);
315 *supported = TRUE;
316 return NULL;
317 }
318 else if (reg_type != REG_SZ)
319 {
320 a->warning("Cannot retrieve service name for PCI device %s: Service name is stored as unknown type 0x%lx.", devinst_id, reg_type);
321 pci_mfree(service_name);
322 *supported = TRUE;
323 return NULL;
324 }
325
326
327 return service_name;
328 }
329
330 static char*
get_driver_path_for_service(struct pci_access * a,LPCWSTR service_name,SC_HANDLE manager)331 get_driver_path_for_service(struct pci_access *a, LPCWSTR service_name, SC_HANDLE manager)
332 {
333 UINT (WINAPI *get_system_root_path)(LPWSTR buffer, UINT size) = NULL;
334 DWORD service_config_size, service_config_len;
335 LPQUERY_SERVICE_CONFIGW service_config = NULL;
336 LPWSTR service_image_path = NULL;
337 SERVICE_STATUS service_status;
338 SC_HANDLE service = NULL;
339 char *driver_path = NULL;
340 int trim_system32 = 0;
341 UINT systemroot_len;
342 int driver_path_len;
343 UINT system32_len;
344 HMODULE kernel32;
345 WCHAR *trim_ptr;
346 DWORD error;
347
348 service = OpenServiceW(manager, service_name, SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS);
349 if (!service)
350 {
351 error = GetLastError();
352 if (error != ERROR_SERVICE_DOES_NOT_EXIST)
353 a->warning("Cannot open service %ls with query rights: %s.", service_name, win32_strerror(error));
354 goto out;
355 }
356
357 if (!QueryServiceStatus(service, &service_status))
358 {
359 error = GetLastError();
360 a->warning("Cannot query status of service %ls: %s.", service_name, win32_strerror(error));
361 goto out;
362 }
363
364 if (service_status.dwCurrentState == SERVICE_STOPPED)
365 goto out;
366
367 if (service_status.dwServiceType != SERVICE_KERNEL_DRIVER)
368 goto out;
369
370 if (!QueryServiceConfigW(service, NULL, 0, &service_config_size))
371 {
372 error = GetLastError();
373 if (error != ERROR_INSUFFICIENT_BUFFER)
374 {
375 a->warning("Cannot query config of service %ls: %s.", service_name, win32_strerror(error));
376 goto out;
377 }
378 }
379
380 retry_service_config:
381 service_config = pci_malloc(a, service_config_size);
382 if (!QueryServiceConfigW(service, service_config, service_config_size, &service_config_len))
383 {
384 error = GetLastError();
385 if (error == ERROR_INSUFFICIENT_BUFFER)
386 {
387 pci_mfree(service_config);
388 service_config_size = service_config_len;
389 goto retry_service_config;
390 }
391 a->warning("Cannot query config of service %ls: %s.", service_name, win32_strerror(error));
392 goto out;
393 }
394
395 if (service_config->dwServiceType != SERVICE_KERNEL_DRIVER)
396 goto out;
397
398 /*
399 * Despite QueryServiceConfig() is Win32 API, it returns lpBinaryPathName
400 * (ImagePath registry) in NT format. Unfortunately there is no Win32
401 * function for converting NT paths to Win32 paths. So do it manually and
402 * convert this NT format to human-readable Win32 path format.
403 */
404
405 /*
406 * GetSystemWindowsDirectoryW() returns path to NT SystemRoot namespace.
407 * Alternativelly path to NT SystemRoot namespace can be constructed by
408 * GetSystemDirectoryW() by trimming "\\system32" from the end of path.
409 * GetSystemWindowsDirectoryW() is not provided in old Windows versions,
410 * so use GetProcAddress() for compatibility with all Windows versions.
411 */
412 kernel32 = GetModuleHandleW(L"kernel32.dll");
413 if (kernel32)
414 get_system_root_path = (void *)GetProcAddress(kernel32, "GetSystemWindowsDirectoryW");
415 else
416 {
417 get_system_root_path = &GetSystemDirectoryW;
418 trim_system32 = 1;
419 }
420
421 if (!service_config->lpBinaryPathName || !service_config->lpBinaryPathName[0])
422 {
423 /* No ImagePath is specified, NT kernel assumes implicit kernel driver path by service name, which is relative to "\\system32\\drivers". */
424 /* GetSystemDirectoryW() returns path to "\\system32" directory on all Windows versions. */
425 system32_len = GetSystemDirectoryW(NULL, 0); /* Returns number of WCHARs plus 1 for nul-term. */
426 service_image_path = pci_malloc(a, sizeof(WCHAR) * (system32_len + sizeof("\\drivers\\")-1 + wcslen(service_name) + sizeof(".sys")-1));
427 system32_len = GetSystemDirectoryW(service_image_path, system32_len); /* Now it returns number of WCHARs without nul-term. */
428 if (system32_len && service_image_path[system32_len-1] != L'\\')
429 service_image_path[system32_len++] = L'\\';
430 wcscpy(service_image_path + system32_len, L"drivers\\");
431 wcscpy(service_image_path + system32_len + sizeof("drivers\\")-1, service_name);
432 wcscpy(service_image_path + system32_len + sizeof("drivers\\")-1 + wcslen(service_name), L".sys");
433 }
434 else if (wcsncmp(service_config->lpBinaryPathName, L"\\SystemRoot\\", sizeof("\\SystemRoot\\")-1) == 0)
435 {
436 /* ImagePath is in NT SystemRoot namespace, convert to Win32 path via GetSystemWindowsDirectoryW()/GetSystemDirectoryW(). */
437 systemroot_len = get_system_root_path(NULL, 0); /* Returns number of WCHARs plus 1 for nul-term. */
438 service_image_path = pci_malloc(a, sizeof(WCHAR) * (systemroot_len + wcslen(service_config->lpBinaryPathName) - (sizeof("\\SystemRoot")-1)));
439 systemroot_len = get_system_root_path(service_image_path, systemroot_len); /* Now it returns number of WCHARs without nul-term. */
440 if (trim_system32 && systemroot_len && (trim_ptr = wcsrchr(service_image_path, L'\\')) != NULL)
441 systemroot_len = trim_ptr - service_image_path;
442 if (systemroot_len && service_image_path[systemroot_len-1] != L'\\')
443 service_image_path[systemroot_len++] = L'\\';
444 wcscpy(service_image_path + systemroot_len, service_config->lpBinaryPathName + sizeof("\\SystemRoot\\")-1);
445 }
446 else if (wcsncmp(service_config->lpBinaryPathName, L"\\??\\UNC\\", sizeof("\\??\\UNC\\")-1) == 0 ||
447 wcsncmp(service_config->lpBinaryPathName, L"\\??\\\\UNC\\", sizeof("\\??\\\\UNC\\")-1) == 0)
448 {
449 /* ImagePath is in NT UNC namespace, convert to Win32 UNC path via "\\\\" prefix. */
450 service_image_path = pci_malloc(a, sizeof(WCHAR) * (sizeof("\\\\") + wcslen(service_config->lpBinaryPathName) - (sizeof("\\??\\UNC\\")-1)));
451 /* Namespace separator may be single or double backslash. */
452 driver_path_len = sizeof("\\??\\")-1;
453 if (service_config->lpBinaryPathName[driver_path_len] == L'\\')
454 driver_path_len++;
455 driver_path_len += sizeof("UNC\\")-1;
456 wcscpy(service_image_path, L"\\\\");
457 wcscpy(service_image_path + sizeof("\\\\")-1, service_config->lpBinaryPathName + driver_path_len);
458 }
459 else if (wcsncmp(service_config->lpBinaryPathName, L"\\??\\", sizeof("\\??\\")-1) == 0)
460 {
461 /* ImagePath is in NT Global?? namespace, root of the Win32 file namespace, so just remove "\\??\\" prefix to get Win32 path. */
462 service_image_path = pci_malloc(a, sizeof(WCHAR) * (wcslen(service_config->lpBinaryPathName) - (sizeof("\\??\\")-1)));
463 /* Namespace separator may be single or double backslash. */
464 driver_path_len = sizeof("\\??\\")-1;
465 if (service_config->lpBinaryPathName[driver_path_len] == L'\\')
466 driver_path_len++;
467 wcscpy(service_image_path, service_config->lpBinaryPathName + driver_path_len);
468 }
469 else if (service_config->lpBinaryPathName[0] != L'\\')
470 {
471 /* ImagePath is relative to the NT SystemRoot namespace, convert to Win32 path via GetSystemWindowsDirectoryW()/GetSystemDirectoryW(). */
472 systemroot_len = get_system_root_path(NULL, 0); /* Returns number of WCHARs plus 1 for nul-term. */
473 service_image_path = pci_malloc(a, sizeof(WCHAR) * (systemroot_len + sizeof("\\")-1 + wcslen(service_config->lpBinaryPathName)));
474 systemroot_len = get_system_root_path(service_image_path, systemroot_len); /* Now it returns number of WCHARs without nul-term. */
475 if (trim_system32 && systemroot_len && (trim_ptr = wcsrchr(service_image_path, L'\\')) != NULL)
476 systemroot_len = trim_ptr - service_image_path;
477 if (systemroot_len && service_image_path[systemroot_len-1] != L'\\')
478 service_image_path[systemroot_len++] = L'\\';
479 wcscpy(service_image_path + systemroot_len, service_config->lpBinaryPathName);
480 }
481 else
482 {
483 /* ImagePath is in some unhandled NT namespace, copy it as is. It cannot be used in Win32 API but libpci user can be still interested in it. */
484 service_image_path = pci_malloc(a, sizeof(WCHAR) * wcslen(service_config->lpBinaryPathName));
485 wcscpy(service_image_path, service_config->lpBinaryPathName);
486 }
487
488 /* Calculate len of buffer needed for conversion from LPWSTR to char*. */
489 driver_path_len = WideCharToMultiByte(CP_ACP, 0, service_image_path, -1, NULL, 0, NULL, NULL);
490 if (driver_path_len <= 0)
491 {
492 error = GetLastError();
493 a->warning("Cannot convert kernel driver path from wide string to 8-bit string: %s.", win32_strerror(error));
494 goto out;
495 }
496
497 driver_path = pci_malloc(a, driver_path_len);
498 driver_path_len = WideCharToMultiByte(CP_ACP, 0, service_image_path, -1, driver_path, driver_path_len, NULL, NULL);
499 if (driver_path_len <= 0)
500 {
501 error = GetLastError();
502 a->warning("Cannot convert kernel driver path from wide string to 8-bit string: %s.", win32_strerror(error));
503 pci_mfree(driver_path);
504 driver_path = NULL;
505 goto out;
506 }
507
508 out:
509 if (service_image_path)
510 pci_mfree(service_image_path);
511 if (service_config)
512 pci_mfree(service_config);
513 if (service)
514 CloseServiceHandle(service);
515 return driver_path;
516 }
517
518 static HKEY
get_device_driver_devreg(struct pci_access * a,DEVINST devinst,DEVINSTID_A devinst_id)519 get_device_driver_devreg(struct pci_access *a, DEVINST devinst, DEVINSTID_A devinst_id)
520 {
521 CONFIGRET cr;
522 HKEY key;
523
524 cr = CM_Open_DevNode_Key(devinst, KEY_READ, 0, RegDisposition_OpenExisting, &key, CM_REGISTRY_SOFTWARE);
525 if (cr != CR_SUCCESS)
526 {
527 if (cr != CR_NO_SUCH_VALUE)
528 a->warning("Cannot retrieve driver key for device %s: %s.", devinst_id, cr_strerror(cr));
529 return NULL;
530 }
531
532 return key;
533 }
534
535 static char*
read_reg_key_string_value(struct pci_access * a,HKEY key,const char * name,DWORD * unkn_reg_type)536 read_reg_key_string_value(struct pci_access *a, HKEY key, const char *name, DWORD *unkn_reg_type)
537 {
538 DWORD reg_type, reg_size, reg_len;
539 char *value;
540 LONG error;
541
542 reg_size = 0;
543 error = RegQueryValueExA(key, name, NULL, ®_type, NULL, ®_size);
544 if (error != ERROR_SUCCESS &&
545 error != ERROR_MORE_DATA)
546 {
547 SetLastError(error);
548 return NULL;
549 }
550 else if (reg_type != REG_SZ)
551 {
552 SetLastError(0);
553 *unkn_reg_type = reg_type;
554 return NULL;
555 }
556
557 retry:
558 value = pci_malloc(a, reg_size + 1);
559 reg_len = reg_size;
560 error = RegQueryValueExA(key, name, NULL, ®_type, (PBYTE)value, ®_len);
561 if (error != ERROR_SUCCESS)
562 {
563 pci_mfree(value);
564 if (error == ERROR_MORE_DATA)
565 {
566 reg_size = reg_len;
567 goto retry;
568 }
569 SetLastError(error);
570 return NULL;
571 }
572 else if (reg_type != REG_SZ)
573 {
574 pci_mfree(value);
575 SetLastError(0);
576 *unkn_reg_type = reg_type;
577 return NULL;
578 }
579 value[reg_len] = '\0';
580
581 return value;
582 }
583
584 static int
driver_cmp(const char * driver,const char * match)585 driver_cmp(const char *driver, const char *match)
586 {
587 int len = strlen(driver);
588 if (driver[0] == '*')
589 driver++;
590 if (len >= 4 && strcasecmp(driver + len - 4, ".vxd") == 0)
591 len -= 4;
592 return strncasecmp(driver, match, len);
593 }
594
595 static char*
get_driver_path_for_regkey(struct pci_access * a,DEVINSTID_A devinst_id,HKEY key)596 get_driver_path_for_regkey(struct pci_access *a, DEVINSTID_A devinst_id, HKEY key)
597 {
598 char *driver_list, *driver, *driver_next;
599 char *subdriver, *subname;
600 char *driver_ptr;
601 char *driver_path;
602 DWORD unkn_reg_type;
603 UINT systemdir_len;
604 HKEY subkey;
605 LONG error;
606 BOOL vmm32;
607 BOOL noext;
608 int len;
609
610 driver_list = read_reg_key_string_value(a, key, "DevLoader", &unkn_reg_type);
611 if (!driver_list)
612 {
613 error = GetLastError();
614 if (error == 0)
615 a->warning("Cannot read driver DevLoader key for PCI device %s: DevLoader key is stored as unknown type 0x%lx.", devinst_id, unkn_reg_type);
616 else if (error != ERROR_FILE_NOT_FOUND)
617 a->warning("Cannot read driver DevLoader key for PCI device %s: %s.", devinst_id, win32_strerror(error));
618 return NULL;
619 }
620
621 subdriver = NULL;
622 driver = driver_list;
623 while (*driver)
624 {
625 driver_next = strchr(driver, ',');
626 if (driver_next)
627 *(driver_next++) = '\0';
628
629 if (driver_cmp(driver, "ios") == 0 ||
630 driver_cmp(driver, "vcomm") == 0)
631 subname = "PortDriver";
632 else if (driver_cmp(driver, "ntkern") == 0)
633 subname = "NTMPDriver";
634 else if (driver_cmp(driver, "ndis") == 0)
635 subname = "DeviceVxDs";
636 else if (driver_cmp(driver, "vdd") == 0)
637 subname = "minivdd";
638 else
639 subname = NULL;
640
641 subkey = key;
642 if (subname && strcmp(subname, "minivdd") == 0)
643 {
644 error = RegOpenKeyA(key, "Default", &subkey);
645 if (error != ERROR_SUCCESS)
646 {
647 a->warning("Cannot open driver subkey Default for PCI device %s: %s.", devinst_id, win32_strerror(error));
648 subkey = NULL;
649 }
650 }
651
652 if (!subname)
653 break;
654
655 if (subkey)
656 {
657 retry_subname:
658 subdriver = read_reg_key_string_value(a, subkey, subname, &unkn_reg_type);
659 if (!subdriver)
660 {
661 error = GetLastError();
662 if (error == 0)
663 a->warning("Cannot read driver %s key for PCI device %s: %s key is stored as unknown type 0x%lx.", subname, devinst_id, subname, unkn_reg_type);
664 else if (error != ERROR_FILE_NOT_FOUND)
665 a->warning("Cannot read driver %s key for PCI device %s: %s.", subname, devinst_id, win32_strerror(error));
666 else if (strcmp(subname, "minivdd") == 0)
667 {
668 subname = "drv";
669 goto retry_subname;
670 }
671 else if (strcmp(subname, "drv") == 0)
672 {
673 subname = "vdd";
674 goto retry_subname;
675 }
676 }
677
678 if (subkey != key)
679 RegCloseKey(subkey);
680
681 if (subdriver)
682 {
683 char *endptr = strchr(subdriver, ',');
684 if (endptr)
685 *endptr = '\0';
686 break;
687 }
688 }
689
690 driver = driver_next;
691 }
692
693 if (subdriver && subdriver[0])
694 driver_ptr = subdriver;
695 else if (driver[0])
696 driver_ptr = driver;
697 else
698 driver_ptr = NULL;
699
700 if (driver_ptr && driver_ptr[0] == '*')
701 {
702 vmm32 = TRUE;
703 driver_ptr++;
704 }
705 else
706 vmm32 = FALSE;
707
708 if (!driver_ptr[0])
709 driver_ptr = NULL;
710
711 len = driver_ptr ? strlen(driver_ptr) : 0;
712 noext = driver_ptr && (len < 4 || driver_ptr[len-4] != '.');
713
714 if (!driver_ptr)
715 driver_path = NULL;
716 else
717 {
718 if (tolower(driver_ptr[0]) >= 'a' && tolower(driver_ptr[0]) <= 'z' && driver_ptr[1] == ':')
719 {
720 /* Driver is already with absolute path. */
721 driver_path = pci_strdup(a, driver_ptr);
722 }
723 else if (driver_cmp(driver, "ntkern") == 0 && subdriver)
724 {
725 /* Driver is relative to system32\drivers\ directory which is relative to windows directory. */
726 systemdir_len = GetWindowsDirectoryA(NULL, 0);
727 driver_path = pci_malloc(a, systemdir_len + 1 + sizeof("system32\\drivers\\")-1 + strlen(driver_ptr) + 4 + 1);
728 systemdir_len = GetWindowsDirectoryA(driver_path, systemdir_len + 1);
729 if (systemdir_len && driver_path[systemdir_len - 1] != '\\')
730 driver_path[systemdir_len++] = '\\';
731 sprintf(driver_path + systemdir_len, "system32\\drivers\\%s%s", driver_ptr, noext ? ".sys" : "");
732 }
733 else if (vmm32)
734 {
735 /* Driver is packed in vmm32.vxd which is stored in system directory. */
736 systemdir_len = GetSystemDirectoryA(NULL, 0);
737 driver_path = pci_malloc(a, systemdir_len + 1 + sizeof("vmm32.vxd ()")-1 + strlen(driver_ptr) + 4 + 1);
738 systemdir_len = GetSystemDirectoryA(driver_path, systemdir_len + 1);
739 if (systemdir_len && driver_path[systemdir_len - 1] != '\\')
740 driver_path[systemdir_len++] = '\\';
741 sprintf(driver_path + systemdir_len, "vmm32.vxd (%s%s)", driver_ptr, noext ? ".vxd" : "");
742 }
743 else
744 {
745 /* Otherwise driver is relative to system directory. */
746 systemdir_len = GetSystemDirectoryA(NULL, 0);
747 driver_path = pci_malloc(a, systemdir_len + 1 + strlen(driver_ptr) + 4 + 1);
748 systemdir_len = GetSystemDirectoryA(driver_path, systemdir_len + 1);
749 if (systemdir_len && driver_path[systemdir_len - 1] != '\\')
750 driver_path[systemdir_len++] = '\\';
751 sprintf(driver_path + systemdir_len, "%s%s", driver_ptr, noext ? ".vxd" : "");
752 }
753 }
754
755 if (subdriver)
756 pci_mfree(subdriver);
757 pci_mfree(driver_list);
758 return driver_path;
759 }
760
761 static char *
get_device_driver_path(struct pci_dev * d,SC_HANDLE manager,BOOL manager_supported)762 get_device_driver_path(struct pci_dev *d, SC_HANDLE manager, BOOL manager_supported)
763 {
764 struct pci_access *a = d->access;
765 BOOL service_supported = TRUE;
766 DEVINSTID_A devinst_id = NULL;
767 LPWSTR service_name = NULL;
768 ULONG devinst_id_len = 0;
769 char *driver_path = NULL;
770 DEVINST devinst = (DEVINST)d->backend_data;
771 ULONG problem = 0;
772 ULONG status = 0;
773 HKEY key = NULL;
774
775 if (CM_Get_DevNode_Status(&status, &problem, devinst, 0) != CR_SUCCESS || !(status & DN_DRIVER_LOADED))
776 return NULL;
777
778 if (CM_Get_Device_ID_Size(&devinst_id_len, devinst, 0) == CR_SUCCESS)
779 {
780 devinst_id = pci_malloc(a, devinst_id_len + 1);
781 if (CM_Get_Device_IDA(devinst, devinst_id, devinst_id_len + 1, 0) != CR_SUCCESS)
782 {
783 pci_mfree(devinst_id);
784 devinst_id = pci_strdup(a, "UNKNOWN");
785 }
786 }
787 else
788 devinst_id = pci_strdup(a, "UNKNOWN");
789
790 service_name = get_device_service_name(d->access, devinst, devinst_id, &service_supported);
791 if ((!service_name || !manager) && service_supported && manager_supported)
792 goto out;
793 else if (service_name && manager)
794 {
795 driver_path = get_driver_path_for_service(d->access, service_name, manager);
796 goto out;
797 }
798
799 key = get_device_driver_devreg(d->access, devinst, devinst_id);
800 if (key)
801 {
802 driver_path = get_driver_path_for_regkey(d->access, devinst_id, key);
803 goto out;
804 }
805
806 out:
807 if (key)
808 RegCloseKey(key);
809 if (service_name)
810 pci_mfree(service_name);
811 pci_mfree(devinst_id);
812 return driver_path;
813 }
814
815 static void
fill_drivers(struct pci_access * a)816 fill_drivers(struct pci_access *a)
817 {
818 BOOL manager_supported;
819 SC_HANDLE manager;
820 struct pci_dev *d;
821 char *driver;
822 DWORD error;
823
824 /* ERROR_CALL_NOT_IMPLEMENTED is returned on systems without Service Manager support. */
825 manager_supported = TRUE;
826 manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
827 if (!manager)
828 {
829 error = GetLastError();
830 if (error != ERROR_CALL_NOT_IMPLEMENTED)
831 a->warning("Cannot open Service Manager with connect right: %s.", win32_strerror(error));
832 else
833 manager_supported = FALSE;
834 }
835
836 for (d = a->devices; d; d = d->next)
837 {
838 driver = get_device_driver_path(d, manager, manager_supported);
839 if (driver)
840 {
841 pci_set_property(d, PCI_FILL_DRIVER, driver);
842 pci_mfree(driver);
843 }
844 d->known_fields |= PCI_FILL_DRIVER;
845 }
846
847 if (manager)
848 CloseServiceHandle(manager);
849 }
850
851 static const char *
res_id_to_str(RESOURCEID res_id)852 res_id_to_str(RESOURCEID res_id)
853 {
854 static char hex_res_id[sizeof("0xffffffff")];
855
856 if (res_id == ResType_IO)
857 return "IO";
858 else if (res_id == ResType_Mem)
859 return "MEM";
860 else if (res_id == ResType_IRQ)
861 return "IRQ";
862
863 sprintf(hex_res_id, "0x%lx", res_id);
864 return hex_res_id;
865 }
866
867 static void
fill_resources(struct pci_dev * d,DEVINST devinst,DEVINSTID_A devinst_id)868 fill_resources(struct pci_dev *d, DEVINST devinst, DEVINSTID_A devinst_id)
869 {
870 struct pci_access *a = d->access;
871
872 CONFIGRET cr;
873
874 LOG_CONF config;
875 ULONG problem;
876 ULONG status;
877
878 RES_DES prev_res_des;
879 RES_DES res_des;
880 RESOURCEID res_id;
881 DWORD bar_res_count;
882
883 BOOL is_bar_res;
884 BOOL non_nt_system;
885
886 int last_irq = -1;
887 int last_shared_irq = -1;
888
889 cr = CM_Get_DevNode_Status(&status, &problem, devinst, 0);
890 if (cr != CR_SUCCESS)
891 {
892 a->warning("Cannot retrieve status of PCI device %s: %s.", devinst_id, cr_strerror(cr));
893 return;
894 }
895
896 cr = CR_NO_MORE_LOG_CONF;
897
898 /*
899 * If the device is running then retrieve allocated configuration by PnP
900 * manager which is currently in use by a device.
901 */
902 if (!(status & DN_HAS_PROBLEM))
903 cr = CM_Get_First_Log_Conf(&config, devinst, ALLOC_LOG_CONF);
904
905 /*
906 * If the device is not running or it does not have allocated configuration by
907 * PnP manager then retrieve forced configuration which prevents PnP manager
908 * from assigning resources.
909 */
910 if (cr == CR_NO_MORE_LOG_CONF)
911 cr = CM_Get_First_Log_Conf(&config, devinst, FORCED_LOG_CONF);
912
913 /*
914 * If the device does not have neither allocated configuration by PnP manager
915 * nor forced configuration and it is not disabled in the BIOS then retrieve
916 * boot configuration supplied by the BIOS.
917 */
918 if (cr == CR_NO_MORE_LOG_CONF &&
919 (!(status & DN_HAS_PROBLEM) || problem != CM_PROB_HARDWARE_DISABLED))
920 cr = CM_Get_First_Log_Conf(&config, devinst, BOOT_LOG_CONF);
921
922 if (cr != CR_SUCCESS)
923 {
924 /*
925 * Note: Starting with Windows 8, CM_Get_First_Log_Conf returns
926 * CR_CALL_NOT_IMPLEMENTED when used in a Wow64 scenario.
927 * To request information about the hardware resources on a local machine
928 * it is necessary implement an architecture-native version of the
929 * application using the hardware resource APIs. For example: An AMD64
930 * application for AMD64 systems.
931 */
932 if (cr == CR_CALL_NOT_IMPLEMENTED && win32_is_32bit_on_win8_64bit_system())
933 {
934 static BOOL warn_once = FALSE;
935 if (!warn_once)
936 {
937 warn_once = TRUE;
938 a->warning("Cannot retrieve resources of PCI devices from 32-bit application on 64-bit system.");
939 }
940 }
941 else if (cr != CR_NO_MORE_LOG_CONF)
942 a->warning("Cannot retrieve resources of PCI device %s: %s.", devinst_id, cr_strerror(cr));
943 return;
944 }
945
946 bar_res_count = 0;
947 non_nt_system = win32_is_non_nt_system();
948
949 is_bar_res = TRUE;
950 if (non_nt_system)
951 {
952 BOOL has_child;
953 DEVINST child;
954 ULONG child_name_len;
955 PSTR child_name;
956 BOOL is_bridge;
957
958 if (CM_Get_Child(&child, devinst, 0) != CR_SUCCESS)
959 has_child = FALSE;
960 else if (CM_Get_Device_ID_Size(&child_name_len, child, 0) != CR_SUCCESS)
961 has_child = FALSE;
962 else
963 {
964 child_name_len++;
965 child_name = pci_malloc(a, child_name_len);
966 if (CM_Get_Device_IDA(child, child_name, child_name_len, 0) != CR_SUCCESS)
967 has_child = FALSE;
968 else if (strncmp(child_name, "PCI\\", 4) != 0)
969 has_child = FALSE;
970 else
971 has_child = TRUE;
972 pci_mfree(child_name);
973 }
974
975 if (has_child || d->device_class == PCI_CLASS_BRIDGE_PCI || d->device_class == PCI_CLASS_BRIDGE_CARDBUS)
976 is_bridge = TRUE;
977 else
978 is_bridge = FALSE;
979
980 if (is_bridge)
981 is_bar_res = FALSE;
982 }
983
984 prev_res_des = (RES_DES)config;
985 while ((cr = CM_Get_Next_Res_Des(&res_des, prev_res_des, ResType_All, &res_id, 0)) == CR_SUCCESS)
986 {
987 pciaddr_t start, end, size, flags;
988 ULONG res_des_data_size;
989 PBYTE res_des_data;
990
991 if (prev_res_des != config)
992 CM_Free_Res_Des_Handle(prev_res_des);
993
994 prev_res_des = res_des;
995
996 /* Skip other resources early */
997 if (res_id != ResType_IO && res_id != ResType_Mem && res_id != ResType_IRQ)
998 continue;
999
1000 cr = CM_Get_Res_Des_Data_Size(&res_des_data_size, res_des, 0);
1001 if (cr != CR_SUCCESS)
1002 {
1003 a->warning("Cannot retrieve %s resource data of PCI device %s: %s.", res_id_to_str(res_id), devinst_id, cr_strerror(cr));
1004 continue;
1005 }
1006
1007 if (!res_des_data_size)
1008 {
1009 a->warning("Cannot retrieve %s resource data of PCI device %s: %s.", res_id_to_str(res_id), devinst_id, "Empty data");
1010 continue;
1011 }
1012
1013 res_des_data = pci_malloc(a, res_des_data_size);
1014 cr = CM_Get_Res_Des_Data(res_des, res_des_data, res_des_data_size, 0);
1015 if (cr != CR_SUCCESS)
1016 {
1017 a->warning("Cannot retrieve %s resource data of PCI device %s: %s.", res_id_to_str(res_id), devinst_id, cr_strerror(cr));
1018 pci_mfree(res_des_data);
1019 continue;
1020 }
1021
1022 /*
1023 * There can be more resources with the same id. In this case we are
1024 * interested in the last one in the list as at the beginning of the list
1025 * can be some virtual resources (which are not set in PCI config space).
1026 */
1027
1028 if (res_id == ResType_IO)
1029 {
1030 PIO_RESOURCE io_data = (PIO_RESOURCE)res_des_data;
1031
1032 start = io_data->IO_Header.IOD_Alloc_Base;
1033 end = io_data->IO_Header.IOD_Alloc_End;
1034 size = (end > start) ? (end - start + 1) : 0;
1035 flags = PCI_IORESOURCE_IO;
1036
1037 /*
1038 * If neither 10-bit, 12-bit, nor 16-bit support is presented then
1039 * expects that this is 32-bit I/O resource. If resource does not fit
1040 * into 16-bit space then it must be 32-bit. If PCI I/O resource is
1041 * not 32-bit then it is 16-bit.
1042 */
1043 if (end <= 0xffff && (io_data->IO_Header.IOD_DesFlags & (fIOD_10_BIT_DECODE|fIOD_12_BIT_DECODE|fIOD_16_BIT_DECODE)))
1044 flags |= PCI_IORESOURCE_IO_16BIT_ADDR;
1045
1046 /*
1047 * 16/32-bit non-NT systems do not support these two flags.
1048 * Most NT-based Windows versions support only the fIOD_WINDOW_DECODE
1049 * flag and put all BAR resources before window resources in this
1050 * resource list. So use this fIOD_WINDOW_DECODE flag as separator
1051 * between IO/MEM windows and IO/MEM BARs of PCI Bridges.
1052 */
1053 if (io_data->IO_Header.IOD_DesFlags & fIOD_WINDOW_DECODE)
1054 is_bar_res = FALSE;
1055 else if (io_data->IO_Header.IOD_DesFlags & fIOD_PORT_BAR)
1056 is_bar_res = TRUE;
1057
1058 if (is_bar_res && bar_res_count < 6)
1059 {
1060 d->flags[bar_res_count] = flags;
1061 d->base_addr[bar_res_count] = start;
1062 d->size[bar_res_count] = size;
1063 bar_res_count++;
1064 }
1065 else if (!is_bar_res)
1066 {
1067 d->bridge_flags[0] = flags;
1068 d->bridge_base_addr[0] = start;
1069 d->bridge_size[0] = size;
1070 d->known_fields |= PCI_FILL_BRIDGE_BASES;
1071 }
1072 }
1073 else if (res_id == ResType_Mem)
1074 {
1075 PMEM_RESOURCE mem_data = (PMEM_RESOURCE)res_des_data;
1076
1077 start = mem_data->MEM_Header.MD_Alloc_Base;
1078 end = mem_data->MEM_Header.MD_Alloc_End;
1079 size = (end > start) ? (end - start + 1) : 0;
1080 flags = PCI_IORESOURCE_MEM;
1081
1082 /*
1083 * If fMD_PrefetchAllowed flag is set then this is
1084 * PCI Prefetchable Memory resource.
1085 */
1086 if ((mem_data->MEM_Header.MD_Flags & mMD_Prefetchable) == fMD_PrefetchAllowed)
1087 flags |= PCI_IORESOURCE_PREFETCH;
1088
1089 /* If resource does not fit into 32-bit space then it must be 64-bit. */
1090 if (is_bar_res && end > 0xffffffff)
1091 flags |= PCI_IORESOURCE_MEM_64;
1092
1093 /*
1094 * These two flags (fMD_WINDOW_DECODE and fMD_MEMORY_BAR) are
1095 * unsupported on most Windows versions, so distinguish between
1096 * window and BAR based on previous resource type.
1097 */
1098 if (mem_data->MEM_Header.MD_Flags & fMD_WINDOW_DECODE)
1099 is_bar_res = FALSE;
1100 else if (mem_data->MEM_Header.MD_Flags & fMD_MEMORY_BAR)
1101 is_bar_res = TRUE;
1102
1103 /* 64-bit BAR resource must be at even position. */
1104 if (is_bar_res && (flags & PCI_IORESOURCE_MEM_64) && bar_res_count % 2)
1105 bar_res_count++;
1106
1107 if (is_bar_res && bar_res_count < 6)
1108 {
1109 d->flags[bar_res_count] = flags;
1110 d->base_addr[bar_res_count] = start;
1111 d->size[bar_res_count] = size;
1112 bar_res_count++;
1113 /* 64-bit BAR resource occupies two slots. */
1114 if (flags & PCI_IORESOURCE_MEM_64)
1115 bar_res_count++;
1116 }
1117 else if (!is_bar_res && !(flags & PCI_IORESOURCE_PREFETCH))
1118 {
1119 d->bridge_flags[1] = flags;
1120 d->bridge_base_addr[1] = start;
1121 d->bridge_size[1] = size;
1122 d->known_fields |= PCI_FILL_BRIDGE_BASES;
1123 }
1124 else if (!is_bar_res && (flags & PCI_IORESOURCE_PREFETCH))
1125 {
1126 d->bridge_flags[2] = flags;
1127 d->bridge_base_addr[2] = start;
1128 d->bridge_size[2] = size;
1129 d->known_fields |= PCI_FILL_BRIDGE_BASES;
1130 }
1131 }
1132 else if (res_id == ResType_IRQ)
1133 {
1134 PIRQ_RESOURCE irq_data = (PIRQ_RESOURCE)res_des_data;
1135
1136 /*
1137 * libpci's d->irq should be set to the non-MSI PCI IRQ and therefore
1138 * it should be level IRQ which may be shared with other PCI devices
1139 * and drivers in the system. As always we want to retrieve the last
1140 * IRQ number from the resource list.
1141 *
1142 * On 16/32-bit non-NT systems is fIRQD_Level set to 2 but on NT
1143 * systems to 0. Moreover it looks like that different PCI drivers
1144 * on both NT and non-NT systems set bits 0 and 1 to wrong values
1145 * and so reported value in this list may be incorrect.
1146 *
1147 * Therefore take the last level-shared IRQ number from the resource
1148 * list and if there is none of this type then take the last IRQ
1149 * number from the list.
1150 */
1151 last_irq = irq_data->IRQ_Header.IRQD_Alloc_Num;
1152 if ((irq_data->IRQ_Header.IRQD_Flags & (mIRQD_Share|mIRQD_Edge_Level)) == (fIRQD_Share|fIRQD_Level))
1153 last_shared_irq = irq_data->IRQ_Header.IRQD_Alloc_Num;
1154
1155 /*
1156 * IRQ resource on 16/32-bit non-NT systems is separator between
1157 * IO/MEM windows and IO/MEM BARs of PCI Bridges. After the IRQ
1158 * resource are IO/MEM BAR resources.
1159 */
1160 if (!is_bar_res && non_nt_system)
1161 is_bar_res = TRUE;
1162 }
1163
1164 pci_mfree(res_des_data);
1165 }
1166 if (cr != CR_NO_MORE_RES_DES)
1167 a->warning("Cannot retrieve resources of PCI device %s: %s.", devinst_id, cr_strerror(cr));
1168
1169 if (prev_res_des != config)
1170 CM_Free_Res_Des_Handle(prev_res_des);
1171
1172 CM_Free_Log_Conf_Handle(config);
1173
1174 /* Set the last IRQ from the resource list to pci_dev. */
1175 if (last_shared_irq >= 0)
1176 d->irq = last_shared_irq;
1177 else if (last_irq >= 0)
1178 d->irq = last_irq;
1179 if (last_shared_irq >= 0 || last_irq >= 0)
1180 d->known_fields |= PCI_FILL_IRQ;
1181
1182 if (bar_res_count > 0)
1183 d->known_fields |= PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS;
1184 }
1185
1186 static BOOL
get_device_location(struct pci_access * a,DEVINST devinst,DEVINSTID_A devinst_id,unsigned int * domain,unsigned int * bus,unsigned int * dev,unsigned int * func)1187 get_device_location(struct pci_access *a, DEVINST devinst, DEVINSTID_A devinst_id, unsigned int *domain, unsigned int *bus, unsigned int *dev, unsigned int *func)
1188 {
1189 ULONG reg_type, reg_len;
1190 CONFIGRET cr;
1191 BOOL have_bus, have_devfunc;
1192 DWORD drp_bus_num, drp_address;
1193
1194 *domain = 0;
1195 have_bus = FALSE;
1196 have_devfunc = FALSE;
1197
1198 /*
1199 * DRP_BUSNUMBER consists of PCI domain number in high 24 bits
1200 * and PCI bus number in low 8 bits.
1201 */
1202 reg_len = sizeof(drp_bus_num);
1203 cr = CM_Get_DevNode_Registry_PropertyA(devinst, CM_DRP_BUSNUMBER, ®_type, &drp_bus_num, ®_len, 0);
1204 if (cr == CR_SUCCESS && reg_type == REG_DWORD && reg_len == sizeof(drp_bus_num))
1205 {
1206 *domain = drp_bus_num >> 8;
1207 *bus = drp_bus_num & 0xff;
1208 have_bus = TRUE;
1209 }
1210
1211 /*
1212 * DRP_ADDRESS consists of PCI device number in high 16 bits
1213 * and PCI function number in low 16 bits.
1214 */
1215 reg_len = sizeof(drp_address);
1216 cr = CM_Get_DevNode_Registry_PropertyA(devinst, CM_DRP_ADDRESS, ®_type, &drp_address, ®_len, 0);
1217 if (cr == CR_SUCCESS && reg_type == REG_DWORD && reg_len == sizeof(drp_address))
1218 {
1219 *dev = drp_address >> 16;
1220 *func = drp_address & 0xffff;
1221 have_devfunc = TRUE;
1222 }
1223
1224 /*
1225 * Device Instance Id for PCI devices is of format:
1226 * "<enumerator>\\<device_id>\\<instance_id>"
1227 * where:
1228 * "<enumerator>" is "PCI"
1229 * "<device_id>" is "VEN_####&DEV_####&SUBSYS_########&REV_##"
1230 * and "<instance_id>" for PCI devices is at least in one of following format:
1231 * "BUS_##&DEV_##&FUNC_##"
1232 * "##.." (sequence of devfn hex bytes, where bytes represents tree path to the root)
1233 * "#..&#..&#..&#.." (four hex numbers separated by "&"; meaning is unknown yet)
1234 *
1235 * First two formats are used only on systems without support for multiple
1236 * domains. The second format uses intel-conf encoding of device and function
1237 * number: Low 3 bits is function number and high 5 bits is device number.
1238 * Bus number is not really encoded in second format!
1239 *
1240 * The third format is used on systems with support for multiple domains but
1241 * format is variable length and currently its meaning is unknown. Apparently
1242 * it looks like that DRP_BUSNUMBER and DRP_ADDRESS registry properties are
1243 * supported on these systems.
1244 *
1245 * If DRP_BUSNUMBER or DRP_ADDRESS failed then try to parse PCI bus, device
1246 * and function numbers from Instance Id part.
1247 */
1248 if (!have_bus || !have_devfunc)
1249 {
1250 const char *device_id0 = strchr(devinst_id, '\\');
1251 const char *instance_id0 = device_id0 ? strchr(device_id0 + 1, '\\') : NULL;
1252 const char *instance_id = instance_id0 ? instance_id0 + 1 : NULL;
1253 unsigned int devfn;
1254
1255 if (instance_id)
1256 {
1257 if (fmt_validate(instance_id, strlen(instance_id), "BUS_##&DEV_##&FUNC_##") &&
1258 sscanf(instance_id, "BUS_%x&DEV_%x&FUNC_%x", bus, dev, func) == 3)
1259 {
1260 have_bus = TRUE;
1261 have_devfunc = TRUE;
1262 }
1263 else if (seq_xdigit_validate(instance_id, 2, 2) &&
1264 sscanf(instance_id, "%2x", &devfn) == 1)
1265 {
1266 *dev = devfn >> 3;
1267 *func = devfn & 0x7;
1268 have_devfunc = TRUE;
1269 }
1270 }
1271 }
1272
1273 /*
1274 * Virtual IRQ holder devices do not have assigned any bus/dev/func number and
1275 * have "IRQHOLDER" in their Device Id part. So skip them.
1276 */
1277 if (!have_bus && !have_devfunc && strncmp(devinst_id, "PCI\\IRQHOLDER\\", 14) == 0)
1278 return FALSE;
1279
1280 /*
1281 * When some numbers cannot be retrieved via cfgmgr32 then set them to zeros
1282 * to have structure initialized. It makes sense to report via libpci also
1283 * such "incomplete" device as cfgmgr32 can provide additional information
1284 * like device/vendor ids or assigned resources.
1285 */
1286 if (!have_bus && !have_devfunc)
1287 {
1288 *bus = *dev = *func = 0;
1289 a->warning("Cannot retrieve bus, device and function numbers for PCI device %s: %s.", devinst_id, cr_strerror(cr));
1290 }
1291 else if (!have_bus)
1292 {
1293 *bus = 0;
1294 a->warning("Cannot retrieve bus number for PCI device %s: %s.", devinst_id, cr_strerror(cr));
1295 }
1296 else if (!have_devfunc)
1297 {
1298 *dev = *func = 0;
1299 a->warning("Cannot retrieve device and function numbers for PCI device %s: %s.", devinst_id, cr_strerror(cr));
1300 }
1301
1302 return TRUE;
1303 }
1304
1305 static void
fill_data_from_string(struct pci_dev * d,const char * str)1306 fill_data_from_string(struct pci_dev *d, const char *str)
1307 {
1308 BOOL have_device_id;
1309 BOOL have_vendor_id;
1310 BOOL have_prog_if;
1311 BOOL have_rev_id;
1312 const char *endptr, *endptr2;
1313 unsigned int hex;
1314 int len;
1315
1316 have_device_id = have_vendor_id = (d->known_fields & PCI_FILL_IDENT);
1317 have_prog_if = have_rev_id = (d->known_fields & PCI_FILL_CLASS_EXT);
1318
1319 while (1)
1320 {
1321 endptr = strchr(str, '&');
1322 endptr2 = strchr(str, '\\');
1323 if (endptr2 && (!endptr || endptr > endptr2))
1324 endptr = endptr2;
1325 len = endptr ? endptr-str : (int)strlen(str);
1326
1327 if (!have_vendor_id &&
1328 fmt_validate(str, len, "VEN_####") &&
1329 sscanf(str, "VEN_%x", &hex) == 1)
1330 {
1331 d->vendor_id = hex;
1332 have_vendor_id = TRUE;
1333 }
1334 else if (!have_device_id &&
1335 fmt_validate(str, len, "DEV_####") &&
1336 sscanf(str, "DEV_%x", &hex) == 1)
1337 {
1338 d->device_id = hex;
1339 have_device_id = TRUE;
1340 }
1341 else if (!(d->known_fields & PCI_FILL_SUBSYS) &&
1342 fmt_validate(str, len, "SUBSYS_########") &&
1343 sscanf(str, "SUBSYS_%x", &hex) == 1)
1344 {
1345 d->subsys_vendor_id = hex & 0xffff;
1346 d->subsys_id = hex >> 16;
1347 d->known_fields |= PCI_FILL_SUBSYS;
1348 }
1349 else if (!have_rev_id &&
1350 fmt_validate(str, len, "REV_##") &&
1351 sscanf(str, "REV_%x", &hex) == 1)
1352 {
1353 d->rev_id = hex;
1354 have_rev_id = TRUE;
1355 }
1356 else if (!((d->known_fields & PCI_FILL_CLASS) && have_prog_if) &&
1357 (fmt_validate(str, len, "CC_####") || fmt_validate(str, len, "CC_######")) &&
1358 sscanf(str, "CC_%x", &hex) == 1)
1359 {
1360 if (len == 9)
1361 {
1362 if (!have_prog_if)
1363 {
1364 d->prog_if = hex & 0xff;
1365 have_prog_if = TRUE;
1366 }
1367 hex >>= 8;
1368 }
1369 if (!(d->known_fields & PCI_FILL_CLASS))
1370 {
1371 d->device_class = hex;
1372 d->known_fields |= PCI_FILL_CLASS;
1373 }
1374 }
1375
1376 if (!endptr || endptr == endptr2)
1377 break;
1378
1379 str = endptr + 1;
1380 }
1381
1382 if ((have_device_id || d->device_id) && (have_vendor_id || d->vendor_id))
1383 d->known_fields |= PCI_FILL_IDENT;
1384
1385 if ((have_prog_if || d->prog_if) && (have_rev_id || d->rev_id))
1386 d->known_fields |= PCI_FILL_CLASS_EXT;
1387 }
1388
1389 static void
fill_data_from_devinst_id(struct pci_dev * d,DEVINSTID_A devinst_id)1390 fill_data_from_devinst_id(struct pci_dev *d, DEVINSTID_A devinst_id)
1391 {
1392 const char *device_id;
1393
1394 device_id = strchr(devinst_id, '\\');
1395 if (!device_id)
1396 return;
1397 device_id++;
1398
1399 /*
1400 * Device Id part of Device Instance Id is in format:
1401 * "VEN_####&DEV_####&SUBSYS_########&REV_##"
1402 */
1403 fill_data_from_string(d, device_id);
1404 }
1405
1406 static void
fill_data_from_hardware_ids(struct pci_dev * d,DEVINST devinst,DEVINSTID_A devinst_id)1407 fill_data_from_hardware_ids(struct pci_dev *d, DEVINST devinst, DEVINSTID_A devinst_id)
1408 {
1409 ULONG reg_type, reg_size, reg_len;
1410 struct pci_access *a = d->access;
1411 char *hardware_ids = NULL;
1412 const char *str;
1413 CONFIGRET cr;
1414
1415 reg_size = 0;
1416 cr = CM_Get_DevNode_Registry_PropertyA(devinst, CM_DRP_HARDWAREID, ®_type, NULL, ®_size, 0);
1417 if (cr != CR_SUCCESS && cr != CR_BUFFER_SMALL)
1418 {
1419 a->warning("Cannot retrieve hardware ids for PCI device %s: %s.", devinst_id, cr_strerror(cr));
1420 return;
1421 }
1422 else if (reg_type != REG_MULTI_SZ && reg_type != REG_SZ) /* Older Windows versions return REG_SZ and new versions REG_MULTI_SZ. */
1423 {
1424 a->warning("Cannot retrieve hardware ids for PCI device %s: Hardware ids are stored as unknown type 0x%lx.", devinst_id, reg_type);
1425 return;
1426 }
1427
1428 retry:
1429 /*
1430 * Returned size is on older Windows versions without nul-term char.
1431 * So explicitly increase size and fill nul-term byte.
1432 */
1433 reg_size++;
1434 hardware_ids = pci_malloc(a, reg_size);
1435 reg_len = reg_size;
1436 cr = CM_Get_DevNode_Registry_PropertyA(devinst, CM_DRP_HARDWAREID, ®_type, hardware_ids, ®_len, 0);
1437 hardware_ids[reg_size - 1] = 0;
1438 if (reg_len > reg_size)
1439 {
1440 pci_mfree(hardware_ids);
1441 reg_size = reg_len;
1442 goto retry;
1443 }
1444 else if (cr != CR_SUCCESS)
1445 {
1446 a->warning("Cannot retrieve hardware ids for PCI device %s: %s.", devinst_id, cr_strerror(cr));
1447 pci_mfree(hardware_ids);
1448 return;
1449 }
1450 else if (reg_type != REG_MULTI_SZ && reg_type != REG_SZ) /* Older Windows versions return REG_SZ and new versions REG_MULTI_SZ. */
1451 {
1452 a->warning("Cannot retrieve hardware ids for PCI device %s: Hardware ids are stored as unknown type 0x%lx.", devinst_id, reg_type);
1453 pci_mfree(hardware_ids);
1454 return;
1455 }
1456
1457 /*
1458 * Hardware ids is nul-separated nul-term string list where each string has
1459 * one of the following format:
1460 * "PCI\\VEN_####&DEV_####&SUBSYS_########&REV_##"
1461 * "PCI\\VEN_####&DEV_####&SUBSYS_########"
1462 * "PCI\\VEN_####&DEV_####&REV_##&CC_####"
1463 * "PCI\\VEN_####&DEV_####&CC_######"
1464 * "PCI\\VEN_####&DEV_####&CC_####"
1465 * "PCI\\VEN_####&DEV_####&REV_##"
1466 * "PCI\\VEN_####&DEV_####"
1467 */
1468 for (str = hardware_ids; *str != '\0'; str += strlen(str) + 1)
1469 {
1470 if (strncmp(str, "PCI\\", 4) != 0)
1471 continue;
1472 str += 4;
1473 fill_data_from_string(d, str);
1474 }
1475
1476 pci_mfree(hardware_ids);
1477 }
1478
1479 static void
scan_devinst_id(struct pci_access * a,DEVINSTID_A devinst_id)1480 scan_devinst_id(struct pci_access *a, DEVINSTID_A devinst_id)
1481 {
1482 unsigned int domain, bus, dev, func;
1483 struct pci_dev *d;
1484 DEVINST devinst;
1485 CONFIGRET cr;
1486
1487 cr = CM_Locate_DevNodeA(&devinst, devinst_id, CM_LOCATE_DEVNODE_NORMAL);
1488 if (cr != CR_SUCCESS)
1489 {
1490 /* Do not show warning when device is not present (= does not match NORMAL flag). */
1491 if (cr != CR_NO_SUCH_DEVNODE)
1492 a->warning("Cannot retrieve handle for device %s: %s.", devinst_id, cr_strerror(cr));
1493 return;
1494 }
1495
1496 /* get_device_location() returns FALSE if devinst is not real PCI device. */
1497 if (!get_device_location(a, devinst, devinst_id, &domain, &bus, &dev, &func))
1498 return;
1499
1500 d = pci_get_dev(a, domain, bus, dev, func);
1501 pci_link_dev(a, d);
1502 if (!d->access->backend_data)
1503 d->no_config_access = 1;
1504 d->backend_data = (void *)devinst;
1505
1506 /* Parse device id part of devinst id and fill details into pci_dev. */
1507 if (!a->buscentric)
1508 fill_data_from_devinst_id(d, devinst_id);
1509
1510 /* Retrieve hardware ids of devinst, parse them and fill details into pci_dev. */
1511 if (!a->buscentric)
1512 fill_data_from_hardware_ids(d, devinst, devinst_id);
1513
1514 if (!a->buscentric)
1515 fill_resources(d, devinst, devinst_id);
1516
1517 /*
1518 * Set parent field to cfgmgr32 parent devinst handle and backend_data field to current
1519 * devinst handle. At later stage in win32_cfgmgr32_scan() when all pci_dev
1520 * devices are linked, change every devinst handle by pci_dev.
1521 */
1522 if (!a->buscentric)
1523 {
1524 DEVINST parent_devinst;
1525 if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS)
1526 {
1527 parent_devinst = 0;
1528 a->warning("Cannot retrieve parent handle for device %s: %s.", devinst_id, cr_strerror(cr));
1529 }
1530 d->parent = (void *)parent_devinst;
1531 }
1532 }
1533
1534 static void
win32_cfgmgr32_scan(struct pci_access * a)1535 win32_cfgmgr32_scan(struct pci_access *a)
1536 {
1537 ULONG devinst_id_list_size;
1538 PCHAR devinst_id_list;
1539 DEVINSTID_A devinst_id;
1540 struct pci_dev *d;
1541 CONFIGRET cr;
1542
1543 #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
1544 if (!resolve_cfgmgr32_functions())
1545 {
1546 a->warning("Required cfgmgr32.dll functions are unavailable.");
1547 return;
1548 }
1549 #endif
1550
1551 /*
1552 * Explicitly initialize size to zero as wine cfgmgr32 implementation does not
1553 * support this API but returns CR_SUCCESS without touching size argument.
1554 */
1555 devinst_id_list_size = 0;
1556 cr = CM_Get_Device_ID_List_SizeA(&devinst_id_list_size, "PCI", CM_GETIDLIST_FILTER_ENUMERATOR);
1557 if (cr != CR_SUCCESS)
1558 {
1559 a->warning("Cannot retrieve list of PCI devices: %s.", cr_strerror(cr));
1560 return;
1561 }
1562 else if (devinst_id_list_size <= 1)
1563 {
1564 a->warning("Cannot retrieve list of PCI devices: No device was found.");
1565 return;
1566 }
1567
1568 devinst_id_list = pci_malloc(a, devinst_id_list_size);
1569 cr = CM_Get_Device_ID_ListA("PCI", devinst_id_list, devinst_id_list_size, CM_GETIDLIST_FILTER_ENUMERATOR);
1570 if (cr != CR_SUCCESS)
1571 {
1572 a->warning("Cannot retrieve list of PCI devices: %s.", cr_strerror(cr));
1573 pci_mfree(devinst_id_list);
1574 return;
1575 }
1576
1577 /* Register pci_dev for each cfgmgr32 devinst handle. */
1578 for (devinst_id = devinst_id_list; *devinst_id; devinst_id += strlen(devinst_id) + 1)
1579 scan_devinst_id(a, devinst_id);
1580
1581 /* Fill all drivers. */
1582 if (!a->buscentric)
1583 fill_drivers(a);
1584
1585 /* Switch parent fields from cfgmgr32 devinst handle to pci_dev. */
1586 if (!a->buscentric)
1587 {
1588 struct pci_dev *d1, *d2;
1589 for (d1 = a->devices; d1; d1 = d1->next)
1590 {
1591 for (d2 = a->devices; d2; d2 = d2->next)
1592 if ((DEVINST)d1->parent == (DEVINST)d2->backend_data)
1593 break;
1594 d1->parent = d2;
1595 if (d1->parent)
1596 d1->known_fields |= PCI_FILL_PARENT;
1597 }
1598 }
1599
1600 /* devinst stored in ->backend_data is not needed anymore, clear it. */
1601 for (d = a->devices; d; d = d->next)
1602 d->backend_data = NULL;
1603
1604 pci_mfree(devinst_id_list);
1605 }
1606
1607 static void
win32_cfgmgr32_config(struct pci_access * a)1608 win32_cfgmgr32_config(struct pci_access *a)
1609 {
1610 pci_define_param(a, "win32.cfgmethod", "auto", "PCI config space access method");
1611 }
1612
1613 static int
win32_cfgmgr32_detect(struct pci_access * a)1614 win32_cfgmgr32_detect(struct pci_access *a)
1615 {
1616 ULONG devinst_id_list_size;
1617 CONFIGRET cr;
1618
1619 #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
1620 if (!resolve_cfgmgr32_functions())
1621 {
1622 a->debug("Required cfgmgr32.dll functions are unavailable.");
1623 return 0;
1624 }
1625 #endif
1626
1627 /*
1628 * Explicitly initialize size to zero as wine cfgmgr32 implementation does not
1629 * support this API but returns CR_SUCCESS without touching size argument.
1630 */
1631 devinst_id_list_size = 0;
1632 cr = CM_Get_Device_ID_List_SizeA(&devinst_id_list_size, "PCI", CM_GETIDLIST_FILTER_ENUMERATOR);
1633 if (cr != CR_SUCCESS)
1634 {
1635 a->debug("CM_Get_Device_ID_List_SizeA(\"PCI\"): %s.", cr_strerror(cr));
1636 return 0;
1637 }
1638 else if (devinst_id_list_size <= 1)
1639 {
1640 a->debug("CM_Get_Device_ID_List_SizeA(\"PCI\"): No device was found.");
1641 return 0;
1642 }
1643
1644 return 1;
1645 }
1646
1647 static void
win32_cfgmgr32_fill_info(struct pci_dev * d,unsigned int flags)1648 win32_cfgmgr32_fill_info(struct pci_dev *d, unsigned int flags)
1649 {
1650 /*
1651 * All available flags were filled by win32_cfgmgr32_scan().
1652 * Filling more flags is possible only from config space.
1653 */
1654 if (!d->access->backend_data)
1655 return;
1656
1657 pci_generic_fill_info(d, flags);
1658 }
1659
1660 static int
win32_cfgmgr32_read(struct pci_dev * d,int pos,byte * buf,int len)1661 win32_cfgmgr32_read(struct pci_dev *d, int pos, byte *buf, int len)
1662 {
1663 struct pci_access *a = d->access;
1664 struct pci_access *acfg = a->backend_data;
1665 struct pci_dev *dcfg = d->backend_data;
1666
1667 if (!acfg)
1668 return pci_emulated_read(d, pos, buf, len);
1669
1670 if (!dcfg)
1671 d->backend_data = dcfg = pci_get_dev(acfg, d->domain, d->bus, d->dev, d->func);
1672
1673 return pci_read_block(dcfg, pos, buf, len);
1674 }
1675
1676 static int
win32_cfgmgr32_write(struct pci_dev * d,int pos,byte * buf,int len)1677 win32_cfgmgr32_write(struct pci_dev *d, int pos, byte *buf, int len)
1678 {
1679 struct pci_access *a = d->access;
1680 struct pci_access *acfg = a->backend_data;
1681 struct pci_dev *dcfg = d->backend_data;
1682
1683 if (!acfg)
1684 return 0;
1685
1686 if (!dcfg)
1687 d->backend_data = dcfg = pci_get_dev(acfg, d->domain, d->bus, d->dev, d->func);
1688
1689 return pci_write_block(dcfg, pos, buf, len);
1690 }
1691
1692 static void
win32_cfgmgr32_cleanup_dev(struct pci_dev * d)1693 win32_cfgmgr32_cleanup_dev(struct pci_dev *d)
1694 {
1695 struct pci_dev *dcfg = d->backend_data;
1696
1697 if (dcfg)
1698 pci_free_dev(dcfg);
1699 }
1700
1701 static void
win32_cfgmgr32_init(struct pci_access * a)1702 win32_cfgmgr32_init(struct pci_access *a)
1703 {
1704 char *cfgmethod = pci_get_param(a, "win32.cfgmethod");
1705 struct pci_access *acfg;
1706
1707 if (strcmp(cfgmethod, "") == 0 ||
1708 strcmp(cfgmethod, "auto") == 0)
1709 {
1710 acfg = pci_clone_access(a);
1711 acfg->method = PCI_ACCESS_AUTO;
1712 }
1713 else if (strcmp(cfgmethod, "none") == 0 ||
1714 strcmp(cfgmethod, "win32-cfgmgr32") == 0)
1715 {
1716 if (a->writeable)
1717 a->error("Write access requested but option win32.cfgmethod was not set.");
1718 return;
1719 }
1720 else
1721 {
1722 int m = pci_lookup_method(cfgmethod);
1723 if (m < 0)
1724 a->error("Option win32.cfgmethod is set to an unknown access method \"%s\".", cfgmethod);
1725 acfg = pci_clone_access(a);
1726 acfg->method = m;
1727 }
1728
1729 a->debug("Loading config space access method...\n");
1730 if (!pci_init_internal(acfg, PCI_ACCESS_WIN32_CFGMGR32))
1731 {
1732 pci_cleanup(acfg);
1733 a->debug("Cannot find any working config space access method.\n");
1734 if (a->writeable)
1735 a->error("Write access requested but no usable access method found.");
1736 return;
1737 }
1738
1739 a->backend_data = acfg;
1740 }
1741
1742 static void
win32_cfgmgr32_cleanup(struct pci_access * a)1743 win32_cfgmgr32_cleanup(struct pci_access *a)
1744 {
1745 struct pci_access *acfg = a->backend_data;
1746
1747 if (acfg)
1748 pci_cleanup(acfg);
1749 }
1750
1751 struct pci_methods pm_win32_cfgmgr32 = {
1752 .name = "win32-cfgmgr32",
1753 .help = "Win32 device listing via Configuration Manager",
1754 .config = win32_cfgmgr32_config,
1755 .detect = win32_cfgmgr32_detect,
1756 .init = win32_cfgmgr32_init,
1757 .cleanup = win32_cfgmgr32_cleanup,
1758 .scan = win32_cfgmgr32_scan,
1759 .fill_info = win32_cfgmgr32_fill_info,
1760 .read = win32_cfgmgr32_read,
1761 .write = win32_cfgmgr32_write,
1762 .cleanup_dev = win32_cfgmgr32_cleanup_dev,
1763 };
1764