14dd39346SMartin Mares /*
24dd39346SMartin Mares * The PCI Library -- Initialization and related things
34dd39346SMartin Mares *
4f022f467SMartin Mares * Copyright (c) 1997--2024 Martin Mares <[email protected]>
54dd39346SMartin Mares *
661829219SMartin Mares * Can be freely distributed and used under the terms of the GNU GPL v2+.
761829219SMartin Mares *
861829219SMartin Mares * SPDX-License-Identifier: GPL-2.0-or-later
94dd39346SMartin Mares */
104dd39346SMartin Mares
114dd39346SMartin Mares #include <stdio.h>
124dd39346SMartin Mares #include <stdlib.h>
134dd39346SMartin Mares #include <stdarg.h>
144dd39346SMartin Mares #include <string.h>
154dd39346SMartin Mares
164dd39346SMartin Mares #include "internal.h"
174dd39346SMartin Mares
1843fd29c7SPali Rohár #ifdef PCI_OS_DJGPP
1943fd29c7SPali Rohár #include <crt0.h> /* for __dos_argv0 */
2043fd29c7SPali Rohár #endif
2143fd29c7SPali Rohár
222608d8f7SPali Rohár #ifdef PCI_OS_WINDOWS
23a7a7aaeaSPali Rohár
242608d8f7SPali Rohár #include <windows.h>
25a7a7aaeaSPali Rohár
26a7a7aaeaSPali Rohár /* Force usage of ANSI (char*) variant of GetModuleFileName() function */
27a7a7aaeaSPali Rohár #ifdef _WIN32
28a7a7aaeaSPali Rohár #ifdef GetModuleFileName
29a7a7aaeaSPali Rohár #undef GetModuleFileName
30a7a7aaeaSPali Rohár #endif
31a7a7aaeaSPali Rohár #define GetModuleFileName GetModuleFileNameA
32a7a7aaeaSPali Rohár #endif
33a7a7aaeaSPali Rohár
34a7a7aaeaSPali Rohár /* Define __ImageBase for all linkers */
35a7a7aaeaSPali Rohár #ifdef _WIN32
36a7a7aaeaSPali Rohár /* GNU LD provides __ImageBase symbol since 2.19, in previous versions it is
37a7a7aaeaSPali Rohár * under name _image_base__, so add weak alias for compatibility. */
38a7a7aaeaSPali Rohár #ifdef __GNUC__
39a7a7aaeaSPali Rohár asm(".weak\t" PCI_STRINGIFY(__MINGW_USYMBOL(__ImageBase)) "\n\t"
40a7a7aaeaSPali Rohár ".set\t" PCI_STRINGIFY(__MINGW_USYMBOL(__ImageBase)) "," PCI_STRINGIFY(__MINGW_USYMBOL(_image_base__)));
41a7a7aaeaSPali Rohár #endif
42a7a7aaeaSPali Rohár /*
43a7a7aaeaSPali Rohár * MSVC link.exe provides __ImageBase symbol since 12.00 (MSVC 6.0), for
44a7a7aaeaSPali Rohár * previous versions resolve it at runtime via GetModuleHandleA() which
45a7a7aaeaSPali Rohár * returns base for main executable or via VirtualQuery() for DLL builds.
46a7a7aaeaSPali Rohár */
47a7a7aaeaSPali Rohár #if defined(_MSC_VER) && _MSC_VER < 1200
48a7a7aaeaSPali Rohár static HMODULE
get_current_module_handle(void)49a7a7aaeaSPali Rohár get_current_module_handle(void)
50a7a7aaeaSPali Rohár {
51a7a7aaeaSPali Rohár #ifdef PCI_SHARED_LIB
52a7a7aaeaSPali Rohár MEMORY_BASIC_INFORMATION info;
53a7a7aaeaSPali Rohár size_t len = VirtualQuery(&get_current_module_handle, &info, sizeof(info));
54a7a7aaeaSPali Rohár if (len != sizeof(info))
55a7a7aaeaSPali Rohár return NULL;
56a7a7aaeaSPali Rohár return (HMODULE)info.AllocationBase;
57a7a7aaeaSPali Rohár #else
58a7a7aaeaSPali Rohár return GetModuleHandleA(NULL);
59a7a7aaeaSPali Rohár #endif
60a7a7aaeaSPali Rohár }
61a7a7aaeaSPali Rohár #define __ImageBase (*(IMAGE_DOS_HEADER *)get_current_module_handle())
62a7a7aaeaSPali Rohár #else
63a7a7aaeaSPali Rohár extern IMAGE_DOS_HEADER __ImageBase;
64a7a7aaeaSPali Rohár #endif
65a7a7aaeaSPali Rohár #endif
66a7a7aaeaSPali Rohár
67a7a7aaeaSPali Rohár #if defined(_WINDLL)
68a7a7aaeaSPali Rohár extern HINSTANCE _hModule;
69a7a7aaeaSPali Rohár #elif defined(_WINDOWS)
70a7a7aaeaSPali Rohár extern HINSTANCE _hInstance;
71a7a7aaeaSPali Rohár #endif
72a7a7aaeaSPali Rohár
732608d8f7SPali Rohár #endif
742608d8f7SPali Rohár
754dd39346SMartin Mares static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = {
764dd39346SMartin Mares NULL,
774dd39346SMartin Mares #ifdef PCI_HAVE_PM_LINUX_SYSFS
784dd39346SMartin Mares &pm_linux_sysfs,
794dd39346SMartin Mares #else
804dd39346SMartin Mares NULL,
814dd39346SMartin Mares #endif
824dd39346SMartin Mares #ifdef PCI_HAVE_PM_LINUX_PROC
834dd39346SMartin Mares &pm_linux_proc,
844dd39346SMartin Mares #else
854dd39346SMartin Mares NULL,
864dd39346SMartin Mares #endif
874dd39346SMartin Mares #ifdef PCI_HAVE_PM_INTEL_CONF
884dd39346SMartin Mares &pm_intel_conf1,
894dd39346SMartin Mares &pm_intel_conf2,
904dd39346SMartin Mares #else
914dd39346SMartin Mares NULL,
924dd39346SMartin Mares NULL,
934dd39346SMartin Mares #endif
944dd39346SMartin Mares #ifdef PCI_HAVE_PM_FBSD_DEVICE
954dd39346SMartin Mares &pm_fbsd_device,
964dd39346SMartin Mares #else
974dd39346SMartin Mares NULL,
984dd39346SMartin Mares #endif
994dd39346SMartin Mares #ifdef PCI_HAVE_PM_AIX_DEVICE
1004dd39346SMartin Mares &pm_aix_device,
1014dd39346SMartin Mares #else
1024dd39346SMartin Mares NULL,
1034dd39346SMartin Mares #endif
1044dd39346SMartin Mares #ifdef PCI_HAVE_PM_NBSD_LIBPCI
1054dd39346SMartin Mares &pm_nbsd_libpci,
1064dd39346SMartin Mares #else
1074dd39346SMartin Mares NULL,
1084dd39346SMartin Mares #endif
1094dd39346SMartin Mares #ifdef PCI_HAVE_PM_OBSD_DEVICE
1104dd39346SMartin Mares &pm_obsd_device,
1114dd39346SMartin Mares #else
1124dd39346SMartin Mares NULL,
1134dd39346SMartin Mares #endif
1144dd39346SMartin Mares #ifdef PCI_HAVE_PM_DUMP
1154dd39346SMartin Mares &pm_dump,
1164dd39346SMartin Mares #else
1174dd39346SMartin Mares NULL,
1184dd39346SMartin Mares #endif
1197cb1afbeSRichard Yao #ifdef PCI_HAVE_PM_DARWIN_DEVICE
12066e0afd0SMartin Mares &pm_darwin,
1217cb1afbeSRichard Yao #else
1227cb1afbeSRichard Yao NULL,
1237cb1afbeSRichard Yao #endif
12483fd885bSMartin Mares #ifdef PCI_HAVE_PM_SYLIXOS_DEVICE
12583fd885bSMartin Mares &pm_sylixos_device,
12683fd885bSMartin Mares #else
12783fd885bSMartin Mares NULL,
12883fd885bSMartin Mares #endif
1290a913370SJoan Lledó #ifdef PCI_HAVE_PM_HURD_CONF
1300a913370SJoan Lledó &pm_hurd,
1310a913370SJoan Lledó #else
1320a913370SJoan Lledó NULL,
1330a913370SJoan Lledó #endif
13426c8b543SPali Rohár #ifdef PCI_HAVE_PM_WIN32_CFGMGR32
13526c8b543SPali Rohár &pm_win32_cfgmgr32,
13626c8b543SPali Rohár #else
13726c8b543SPali Rohár NULL,
13826c8b543SPali Rohár #endif
139aa5a16efSPali Rohár #ifdef PCI_HAVE_PM_WIN32_KLDBG
140aa5a16efSPali Rohár &pm_win32_kldbg,
141aa5a16efSPali Rohár #else
142aa5a16efSPali Rohár NULL,
143aa5a16efSPali Rohár #endif
1442d0af6fcSPali Rohár #ifdef PCI_HAVE_PM_WIN32_SYSDBG
1452d0af6fcSPali Rohár &pm_win32_sysdbg,
1462d0af6fcSPali Rohár #else
1472d0af6fcSPali Rohár NULL,
1482d0af6fcSPali Rohár #endif
1490a7350fbSPali Rohár #ifdef PCI_HAVE_PM_MMIO_CONF
1500a7350fbSPali Rohár &pm_mmio_conf1,
151e2d9340bSPali Rohár &pm_mmio_conf1_ext,
1520a7350fbSPali Rohár #else
1530a7350fbSPali Rohár NULL,
154e2d9340bSPali Rohár NULL,
1550a7350fbSPali Rohár #endif
1562ba0f6f4SPali Rohár #if defined(PCI_HAVE_PM_ECAM)
1572ba0f6f4SPali Rohár &pm_ecam,
1582ba0f6f4SPali Rohár #else
1592ba0f6f4SPali Rohár NULL,
1602ba0f6f4SPali Rohár #endif
1615b52ae79SAgg242 #if defined(PCI_HAVE_PM_AOS_EXPANSION)
1625b52ae79SAgg242 &pm_aos_expansion,
1635b52ae79SAgg242 #else
1645b52ae79SAgg242 NULL,
1655b52ae79SAgg242 #endif
166*021d41cfSGuEe-GUI #ifdef PCI_HAVE_PM_RT_THREAD_SMART_DM
167*021d41cfSGuEe-GUI &pm_rt_thread_smart_dm,
168*021d41cfSGuEe-GUI #else
169*021d41cfSGuEe-GUI NULL,
170*021d41cfSGuEe-GUI #endif
1714dd39346SMartin Mares };
1724dd39346SMartin Mares
17359cfe93dSMartin Mares // If PCI_ACCESS_AUTO is selected, we probe the access methods in this order
17459cfe93dSMartin Mares static int probe_sequence[] = {
17559cfe93dSMartin Mares // System-specific methods
17659cfe93dSMartin Mares PCI_ACCESS_SYS_BUS_PCI,
17759cfe93dSMartin Mares PCI_ACCESS_PROC_BUS_PCI,
17859cfe93dSMartin Mares PCI_ACCESS_FBSD_DEVICE,
17959cfe93dSMartin Mares PCI_ACCESS_AIX_DEVICE,
18059cfe93dSMartin Mares PCI_ACCESS_NBSD_LIBPCI,
18159cfe93dSMartin Mares PCI_ACCESS_OBSD_DEVICE,
18259cfe93dSMartin Mares PCI_ACCESS_DARWIN,
18383fd885bSMartin Mares PCI_ACCESS_SYLIXOS_DEVICE,
1840a913370SJoan Lledó PCI_ACCESS_HURD,
18526c8b543SPali Rohár PCI_ACCESS_WIN32_CFGMGR32,
186aa5a16efSPali Rohár PCI_ACCESS_WIN32_KLDBG,
1872d0af6fcSPali Rohár PCI_ACCESS_WIN32_SYSDBG,
1885b52ae79SAgg242 PCI_ACCESS_AOS_EXPANSION,
189*021d41cfSGuEe-GUI PCI_ACCESS_RT_THREAD_SMART_DM,
19059cfe93dSMartin Mares // Low-level methods poking the hardware directly
1912ba0f6f4SPali Rohár PCI_ACCESS_ECAM,
19259cfe93dSMartin Mares PCI_ACCESS_I386_TYPE1,
19359cfe93dSMartin Mares PCI_ACCESS_I386_TYPE2,
194e2d9340bSPali Rohár PCI_ACCESS_MMIO_TYPE1_EXT,
1950a7350fbSPali Rohár PCI_ACCESS_MMIO_TYPE1,
19659cfe93dSMartin Mares -1,
19759cfe93dSMartin Mares };
19859cfe93dSMartin Mares
199eeef8fedSMartin Mares static void PCI_NONRET
pci_generic_error(char * msg,...)2004dd39346SMartin Mares pci_generic_error(char *msg, ...)
2014dd39346SMartin Mares {
2024dd39346SMartin Mares va_list args;
2034dd39346SMartin Mares
2044dd39346SMartin Mares va_start(args, msg);
2054dd39346SMartin Mares fputs("pcilib: ", stderr);
2064dd39346SMartin Mares vfprintf(stderr, msg, args);
207a42aea90SMichal Hlavinka va_end(args);
2084dd39346SMartin Mares fputc('\n', stderr);
2094dd39346SMartin Mares exit(1);
2104dd39346SMartin Mares }
2114dd39346SMartin Mares
2124dd39346SMartin Mares static void
pci_generic_warn(char * msg,...)2134dd39346SMartin Mares pci_generic_warn(char *msg, ...)
2144dd39346SMartin Mares {
2154dd39346SMartin Mares va_list args;
2164dd39346SMartin Mares
2174dd39346SMartin Mares va_start(args, msg);
2184dd39346SMartin Mares fputs("pcilib: ", stderr);
2194dd39346SMartin Mares vfprintf(stderr, msg, args);
220a42aea90SMichal Hlavinka va_end(args);
2214dd39346SMartin Mares fputc('\n', stderr);
2224dd39346SMartin Mares }
2234dd39346SMartin Mares
2244dd39346SMartin Mares static void
pci_generic_debug(char * msg,...)2254dd39346SMartin Mares pci_generic_debug(char *msg, ...)
2264dd39346SMartin Mares {
2274dd39346SMartin Mares va_list args;
2284dd39346SMartin Mares
2294dd39346SMartin Mares va_start(args, msg);
2304dd39346SMartin Mares vfprintf(stdout, msg, args);
2314dd39346SMartin Mares va_end(args);
2324dd39346SMartin Mares }
2334dd39346SMartin Mares
2344dd39346SMartin Mares static void
pci_null_debug(char * msg UNUSED,...)2354dd39346SMartin Mares pci_null_debug(char *msg UNUSED, ...)
2364dd39346SMartin Mares {
2374dd39346SMartin Mares }
2384dd39346SMartin Mares
239b9927f14SMartin Mares // Memory allocation functions are safe to call if pci_access is not fully initalized or even NULL
240b9927f14SMartin Mares
241b9927f14SMartin Mares void *
pci_malloc(struct pci_access * a,int size)242b9927f14SMartin Mares pci_malloc(struct pci_access *a, int size)
243b9927f14SMartin Mares {
244b9927f14SMartin Mares void *x = malloc(size);
245b9927f14SMartin Mares
246b9927f14SMartin Mares if (!x)
247b9927f14SMartin Mares (a && a->error ? a->error : pci_generic_error)("Out of memory (allocation of %d bytes failed)", size);
248b9927f14SMartin Mares return x;
249b9927f14SMartin Mares }
250b9927f14SMartin Mares
251b9927f14SMartin Mares void
pci_mfree(void * x)252b9927f14SMartin Mares pci_mfree(void *x)
253b9927f14SMartin Mares {
254b9927f14SMartin Mares if (x)
255b9927f14SMartin Mares free(x);
256b9927f14SMartin Mares }
257b9927f14SMartin Mares
258b9927f14SMartin Mares char *
pci_strdup(struct pci_access * a,const char * s)259b9927f14SMartin Mares pci_strdup(struct pci_access *a, const char *s)
260b9927f14SMartin Mares {
261b9927f14SMartin Mares int len = strlen(s) + 1;
262b9927f14SMartin Mares char *t = pci_malloc(a, len);
263b9927f14SMartin Mares memcpy(t, s, len);
264b9927f14SMartin Mares return t;
265b9927f14SMartin Mares }
266b9927f14SMartin Mares
2679ff67879SMartin Mares int
pci_lookup_method(char * name)2689ff67879SMartin Mares pci_lookup_method(char *name)
2699ff67879SMartin Mares {
2709ff67879SMartin Mares int i;
2719ff67879SMartin Mares
2729ff67879SMartin Mares for (i=0; i<PCI_ACCESS_MAX; i++)
2739ff67879SMartin Mares if (pci_methods[i] && !strcmp(pci_methods[i]->name, name))
2749ff67879SMartin Mares return i;
2759ff67879SMartin Mares return -1;
2769ff67879SMartin Mares }
2779ff67879SMartin Mares
2789ff67879SMartin Mares char *
pci_get_method_name(int index)2799ff67879SMartin Mares pci_get_method_name(int index)
2809ff67879SMartin Mares {
2819ff67879SMartin Mares if (index < 0 || index >= PCI_ACCESS_MAX)
2829ff67879SMartin Mares return NULL;
2839ff67879SMartin Mares else if (!pci_methods[index])
2849ff67879SMartin Mares return "";
2859ff67879SMartin Mares else
2869ff67879SMartin Mares return pci_methods[index]->name;
2879ff67879SMartin Mares }
2889ff67879SMartin Mares
28943fd29c7SPali Rohár #if defined(PCI_OS_WINDOWS) || defined(PCI_OS_DJGPP)
29079978004SMartin Mares
29179978004SMartin Mares static void
pci_init_name_list_path(struct pci_access * a)29279978004SMartin Mares pci_init_name_list_path(struct pci_access *a)
29379978004SMartin Mares {
2942608d8f7SPali Rohár if ((PCI_PATH_IDS_DIR)[0])
2952608d8f7SPali Rohár pci_set_name_list_path(a, PCI_PATH_IDS_DIR "\\" PCI_IDS, 0);
2962608d8f7SPali Rohár else
2972608d8f7SPali Rohár {
2982608d8f7SPali Rohár char *path, *sep;
29903829658SPali Rohár size_t len;
300a7a7aaeaSPali Rohár
30143fd29c7SPali Rohár #if defined(PCI_OS_WINDOWS) && (defined(_WIN32) || defined(_WINDLL) || defined(_WINDOWS))
302a7a7aaeaSPali Rohár
303a7a7aaeaSPali Rohár HMODULE module;
30403829658SPali Rohár size_t size;
3052608d8f7SPali Rohár
306a7a7aaeaSPali Rohár #if defined(_WIN32)
307a7a7aaeaSPali Rohár module = (HINSTANCE)&__ImageBase;
308a7a7aaeaSPali Rohár #elif defined(_WINDLL)
309a7a7aaeaSPali Rohár module = _hModule;
310a7a7aaeaSPali Rohár #elif defined(_WINDOWS)
311a7a7aaeaSPali Rohár module = _hInstance;
312a7a7aaeaSPali Rohár #endif
313a7a7aaeaSPali Rohár
31403829658SPali Rohár /*
31503829658SPali Rohár * Module file name can have arbitrary length despite all MS examples say
31603829658SPali Rohár * about MAX_PATH upper limit. This limit does not apply for example when
31703829658SPali Rohár * executable is running from network disk with very long UNC paths or
31803829658SPali Rohár * when using "\\??\\" prefix for specifying executable binary path.
31903829658SPali Rohár * Function GetModuleFileName() returns passed size argument when passed
32003829658SPali Rohár * buffer is too small and does not signal any error. In this case retry
32103829658SPali Rohár * again with larger buffer.
32203829658SPali Rohár */
3236cf9052eSPali Rohár size = 256; /* initial buffer size (more than sizeof(PCI_IDS)-4) */
32403829658SPali Rohár retry:
32503829658SPali Rohár path = pci_malloc(a, size);
3266cf9052eSPali Rohár len = GetModuleFileName(module, path, size-sizeof(PCI_IDS)-4); /* 4 for "\\\\?\\" */
3276cf9052eSPali Rohár if (len >= size-sizeof(PCI_IDS)-4)
32803829658SPali Rohár {
32903829658SPali Rohár free(path);
33003829658SPali Rohár size *= 2;
33103829658SPali Rohár goto retry;
33203829658SPali Rohár }
33303829658SPali Rohár else if (len == 0)
33403829658SPali Rohár path[0] = '\0';
33503829658SPali Rohár
3366cf9052eSPali Rohár /*
3376cf9052eSPali Rohár * GetModuleFileName() has bugs. On Windows 10 it prepends current drive
3386cf9052eSPali Rohár * letter if path is just pure NT namespace (with "\\??\\" prefix). Such
3396cf9052eSPali Rohár * extra drive letter makes path fully invalid and unusable. So remove
3406cf9052eSPali Rohár * extra drive letter to make path valid again.
3416cf9052eSPali Rohár * Reproduce: CreateProcessW("\\??\\C:\\lspci.exe", ...)
3426cf9052eSPali Rohár */
3436cf9052eSPali Rohár if (((path[0] >= 'a' && path[0] <= 'z') ||
3446cf9052eSPali Rohár (path[0] >= 'A' && path[0] <= 'Z')) &&
3456cf9052eSPali Rohár strncmp(path+1, ":\\??\\", 5) == 0)
3466cf9052eSPali Rohár {
3476cf9052eSPali Rohár memmove(path, path+2, len-2);
3486cf9052eSPali Rohár len -= 2;
3496cf9052eSPali Rohár path[len] = '\0';
3506cf9052eSPali Rohár }
3516cf9052eSPali Rohár
3526cf9052eSPali Rohár /*
3536cf9052eSPali Rohár * GetModuleFileName() has bugs. On Windows 10 it does not add "\\\\?\\"
3546cf9052eSPali Rohár * prefix when path is in native NT UNC namespace. Such path is treated by
3556cf9052eSPali Rohár * WinAPI/DOS functions as standard DOS path relative to the current
3566cf9052eSPali Rohár * directory, hence something completely different. So prepend missing
3576cf9052eSPali Rohár * "\\\\?\\" prefix to make path valid again.
3586cf9052eSPali Rohár * Reproduce: CreateProcessW("\\??\\UNC\\10.0.2.4\\qemu\\lspci.exe", ...)
35964d7bab6SPali Rohár *
36064d7bab6SPali Rohár * If path starts with DOS drive letter and with appended PCI_IDS is
36164d7bab6SPali Rohár * longer than 260 bytes and is without "\\\\?\\" prefix then append it.
36264d7bab6SPali Rohár * This prefix is required for paths and file names with DOS drive letter
36364d7bab6SPali Rohár * longer than 260 bytes.
3646cf9052eSPali Rohár */
3656cf9052eSPali Rohár if (strncmp(path, "\\UNC\\", 5) == 0 ||
36664d7bab6SPali Rohár strncmp(path, "UNC\\", 4) == 0 ||
36764d7bab6SPali Rohár (((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) &&
36864d7bab6SPali Rohár len + sizeof(PCI_IDS) >= 260))
3696cf9052eSPali Rohár {
3706cf9052eSPali Rohár memmove(path+4, path, len);
3716cf9052eSPali Rohár memcpy(path, "\\\\?\\", 4);
3726cf9052eSPali Rohár len += 4;
3736cf9052eSPali Rohár path[len] = '\0';
3746cf9052eSPali Rohár }
3756cf9052eSPali Rohár
37643fd29c7SPali Rohár #elif defined(PCI_OS_DJGPP) || defined(PCI_OS_WINDOWS)
377a7a7aaeaSPali Rohár
378a7a7aaeaSPali Rohár const char *exe_path;
379a7a7aaeaSPali Rohár
38043fd29c7SPali Rohár #ifdef PCI_OS_DJGPP
38143fd29c7SPali Rohár exe_path = __dos_argv0;
38243fd29c7SPali Rohár #else
383a7a7aaeaSPali Rohár exe_path = _pgmptr;
38443fd29c7SPali Rohár #endif
385a7a7aaeaSPali Rohár
386a7a7aaeaSPali Rohár len = strlen(exe_path);
387a7a7aaeaSPali Rohár path = pci_malloc(a, len+sizeof(PCI_IDS));
388a7a7aaeaSPali Rohár memcpy(path, exe_path, len+1);
389a7a7aaeaSPali Rohár
390a7a7aaeaSPali Rohár #endif
391a7a7aaeaSPali Rohár
39203829658SPali Rohár sep = strrchr(path, '\\');
39303829658SPali Rohár if (!sep)
3945f93596fSPali Rohár {
395a7a7aaeaSPali Rohár /*
396a7a7aaeaSPali Rohár * If current module path (current executable for static builds or
397a7a7aaeaSPali Rohár * current DLL library for shared build) cannot be determined then
398a7a7aaeaSPali Rohár * fallback to the current directory.
399a7a7aaeaSPali Rohár */
4002608d8f7SPali Rohár free(path);
4015f93596fSPali Rohár pci_set_name_list_path(a, PCI_IDS, 0);
4025f93596fSPali Rohár }
4032608d8f7SPali Rohár else
4042608d8f7SPali Rohár {
4052608d8f7SPali Rohár memcpy(sep+1, PCI_IDS, sizeof(PCI_IDS));
4062608d8f7SPali Rohár pci_set_name_list_path(a, path, 1);
4072608d8f7SPali Rohár }
4082608d8f7SPali Rohár }
40945152bc3SMartin Mares }
4105b52ae79SAgg242
4115b52ae79SAgg242 #elif defined PCI_OS_AMIGAOS
4125b52ae79SAgg242
4135b52ae79SAgg242 static void
pci_init_name_list_path(struct pci_access * a)4145b52ae79SAgg242 pci_init_name_list_path(struct pci_access *a)
4155b52ae79SAgg242 {
4165b52ae79SAgg242 int len = strlen(PCI_PATH_IDS_DIR);
4175b52ae79SAgg242
4185b52ae79SAgg242 if (!len)
4195b52ae79SAgg242 pci_set_name_list_path(a, PCI_IDS, 0);
4205b52ae79SAgg242 else
4215b52ae79SAgg242 {
4225b52ae79SAgg242 char last_char = PCI_PATH_IDS_DIR[len - 1];
4235b52ae79SAgg242 if (last_char == ':' || last_char == '/') // root or parent char
4245b52ae79SAgg242 pci_set_name_list_path(a, PCI_PATH_IDS_DIR PCI_IDS, 0);
4255b52ae79SAgg242 else
4265b52ae79SAgg242 pci_set_name_list_path(a, PCI_PATH_IDS_DIR "/" PCI_IDS, 0);
4275b52ae79SAgg242 }
42879978004SMartin Mares }
42979978004SMartin Mares
4302608d8f7SPali Rohár #else
43179978004SMartin Mares
43279978004SMartin Mares static void
pci_init_name_list_path(struct pci_access * a)43379978004SMartin Mares pci_init_name_list_path(struct pci_access *a)
43479978004SMartin Mares {
435d6dcc545SMartin Mares pci_set_name_list_path(a, PCI_PATH_IDS_DIR "/" PCI_IDS, 0);
43679978004SMartin Mares }
43779978004SMartin Mares
4382608d8f7SPali Rohár #endif
43979978004SMartin Mares
440f022f467SMartin Mares #ifdef PCI_USE_DNS
441f022f467SMartin Mares
442f022f467SMartin Mares static void
pci_init_dns(struct pci_access * a)443f022f467SMartin Mares pci_init_dns(struct pci_access *a)
444f022f467SMartin Mares {
445f022f467SMartin Mares pci_define_param(a, "net.domain", PCI_ID_DOMAIN, "DNS domain used for resolving of ID's");
446f022f467SMartin Mares a->id_lookup_mode = PCI_LOOKUP_CACHE;
447f022f467SMartin Mares
448f022f467SMartin Mares char *cache_dir = getenv("XDG_CACHE_HOME");
449f022f467SMartin Mares if (!cache_dir)
450f022f467SMartin Mares cache_dir = "~/.cache";
451f022f467SMartin Mares
452f022f467SMartin Mares int name_len = strlen(cache_dir) + 32;
453f022f467SMartin Mares char *cache_name = pci_malloc(NULL, name_len);
454f022f467SMartin Mares snprintf(cache_name, name_len, "%s/pci-ids", cache_dir);
455f022f467SMartin Mares struct pci_param *param = pci_define_param(a, "net.cache_name", cache_name, "Name of the ID cache file");
456f022f467SMartin Mares param->value_malloced = 1;
457f022f467SMartin Mares }
458f022f467SMartin Mares
459f022f467SMartin Mares #endif
460f022f467SMartin Mares
46179978004SMartin Mares struct pci_access *
pci_alloc(void)46279978004SMartin Mares pci_alloc(void)
46379978004SMartin Mares {
46479978004SMartin Mares struct pci_access *a = pci_malloc(NULL, sizeof(struct pci_access));
46579978004SMartin Mares int i;
46679978004SMartin Mares
46779978004SMartin Mares memset(a, 0, sizeof(*a));
46879978004SMartin Mares pci_init_name_list_path(a);
469d6dcc545SMartin Mares #ifdef PCI_USE_DNS
470f022f467SMartin Mares pci_init_dns(a);
471d6dcc545SMartin Mares #endif
472ac357d3bSMartin Mares #ifdef PCI_HAVE_HWDB
473ac357d3bSMartin Mares pci_define_param(a, "hwdb.disable", "0", "Do not look up names in UDEV's HWDB if non-zero");
474ac357d3bSMartin Mares #endif
475d6dcc545SMartin Mares for (i=0; i<PCI_ACCESS_MAX; i++)
476d6dcc545SMartin Mares if (pci_methods[i] && pci_methods[i]->config)
477d6dcc545SMartin Mares pci_methods[i]->config(a);
478d6dcc545SMartin Mares return a;
479fa182368SMartin Mares }
480fa182368SMartin Mares
481ea404c2aSMartin Mares int
pci_init_internal(struct pci_access * a,int skip_method)482ea404c2aSMartin Mares pci_init_internal(struct pci_access *a, int skip_method)
4834dd39346SMartin Mares {
4844dd39346SMartin Mares if (!a->error)
4854dd39346SMartin Mares a->error = pci_generic_error;
4864dd39346SMartin Mares if (!a->warning)
4874dd39346SMartin Mares a->warning = pci_generic_warn;
4884dd39346SMartin Mares if (!a->debug)
4894dd39346SMartin Mares a->debug = pci_generic_debug;
4904dd39346SMartin Mares if (!a->debugging)
4914dd39346SMartin Mares a->debug = pci_null_debug;
4924dd39346SMartin Mares
493ea404c2aSMartin Mares if (a->method != PCI_ACCESS_AUTO)
4944dd39346SMartin Mares {
4954dd39346SMartin Mares if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method])
4964dd39346SMartin Mares a->error("This access method is not supported.");
4974dd39346SMartin Mares a->methods = pci_methods[a->method];
4984dd39346SMartin Mares }
4994dd39346SMartin Mares else
5004dd39346SMartin Mares {
5014dd39346SMartin Mares unsigned int i;
50259cfe93dSMartin Mares for (i=0; probe_sequence[i] >= 0; i++)
5034dd39346SMartin Mares {
50459cfe93dSMartin Mares struct pci_methods *m = pci_methods[probe_sequence[i]];
50559cfe93dSMartin Mares if (!m)
50659cfe93dSMartin Mares continue;
507848123ebSPali Rohár if (skip_method == probe_sequence[i])
508848123ebSPali Rohár continue;
50959cfe93dSMartin Mares a->debug("Trying method %s...", m->name);
51059cfe93dSMartin Mares if (m->detect(a))
5114dd39346SMartin Mares {
5124dd39346SMartin Mares a->debug("...OK\n");
51359cfe93dSMartin Mares a->methods = m;
51459cfe93dSMartin Mares a->method = probe_sequence[i];
5154dd39346SMartin Mares break;
5164dd39346SMartin Mares }
5174dd39346SMartin Mares a->debug("...No.\n");
5184dd39346SMartin Mares }
5194dd39346SMartin Mares if (!a->methods)
520ea404c2aSMartin Mares return 0;
5214dd39346SMartin Mares }
5224dd39346SMartin Mares a->debug("Decided to use %s\n", a->methods->name);
5234dd39346SMartin Mares a->methods->init(a);
524ea404c2aSMartin Mares return 1;
5254dd39346SMartin Mares }
5264dd39346SMartin Mares
527848123ebSPali Rohár void
pci_init_v35(struct pci_access * a)528848123ebSPali Rohár pci_init_v35(struct pci_access *a)
529848123ebSPali Rohár {
5301249c980SMartin Mares if (!pci_init_internal(a, -1))
531ea404c2aSMartin Mares a->error("Cannot find any working access method.");
532848123ebSPali Rohár }
533848123ebSPali Rohár
5342afb0889SMartin Mares STATIC_ALIAS(void pci_init(struct pci_access *a), pci_init_v35(a));
53525471140SMartin Mares DEFINE_ALIAS(void pci_init_v30(struct pci_access *a), pci_init_v35);
53625471140SMartin Mares SYMBOL_VERSION(pci_init_v30, pci_init@LIBPCI_3.0);
5372afb0889SMartin Mares SYMBOL_VERSION(pci_init_v35, pci_init@@LIBPCI_3.5);
538ab61451dSKeith Busch
539ea404c2aSMartin Mares struct pci_access *
pci_clone_access(struct pci_access * a)540ea404c2aSMartin Mares pci_clone_access(struct pci_access *a)
541ea404c2aSMartin Mares {
542ea404c2aSMartin Mares struct pci_access *b = pci_alloc();
543ea404c2aSMartin Mares
544ea404c2aSMartin Mares b->writeable = a->writeable;
545ea404c2aSMartin Mares b->buscentric = a->buscentric;
546ea404c2aSMartin Mares b->debugging = a->debugging;
547ea404c2aSMartin Mares b->error = a->error;
548ea404c2aSMartin Mares b->warning = a->warning;
549ea404c2aSMartin Mares b->debug = a->debug;
550ea404c2aSMartin Mares
551ea404c2aSMartin Mares return b;
552ea404c2aSMartin Mares }
553ea404c2aSMartin Mares
5544dd39346SMartin Mares void
pci_cleanup(struct pci_access * a)5554dd39346SMartin Mares pci_cleanup(struct pci_access *a)
5564dd39346SMartin Mares {
5574dd39346SMartin Mares struct pci_dev *d, *e;
5584dd39346SMartin Mares
5594dd39346SMartin Mares for (d=a->devices; d; d=e)
5604dd39346SMartin Mares {
5614dd39346SMartin Mares e = d->next;
5624dd39346SMartin Mares pci_free_dev(d);
5634dd39346SMartin Mares }
5644dd39346SMartin Mares if (a->methods)
5654dd39346SMartin Mares a->methods->cleanup(a);
5664dd39346SMartin Mares pci_free_name_list(a);
567fa182368SMartin Mares pci_free_params(a);
5684dd39346SMartin Mares pci_set_name_list_path(a, NULL, 0);
5694dd39346SMartin Mares pci_mfree(a);
5704dd39346SMartin Mares }
571