*
* Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
*
- * Can be freely distributed and used under the terms of the GNU GPL.
+ * Can be freely distributed and used under the terms of the GNU GPL v2+.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <stdio.h>
NULL,
NULL,
#endif
+#if defined(PCI_HAVE_PM_ECAM)
+ &pm_ecam,
+#else
+ NULL,
+#endif
};
// If PCI_ACCESS_AUTO is selected, we probe the access methods in this order
PCI_ACCESS_WIN32_KLDBG,
PCI_ACCESS_WIN32_SYSDBG,
// Low-level methods poking the hardware directly
+ PCI_ACCESS_ECAM,
PCI_ACCESS_I386_TYPE1,
PCI_ACCESS_I386_TYPE2,
PCI_ACCESS_MMIO_TYPE1_EXT,
* buffer is too small and does not signal any error. In this case retry
* again with larger buffer.
*/
- size = 256; /* initial buffer size (more than sizeof(PCI_IDS)) */
+ size = 256; /* initial buffer size (more than sizeof(PCI_IDS)-4) */
retry:
path = pci_malloc(a, size);
- len = GetModuleFileName(module, path, size-sizeof(PCI_IDS));
- if (len >= size-sizeof(PCI_IDS))
+ len = GetModuleFileName(module, path, size-sizeof(PCI_IDS)-4); /* 4 for "\\\\?\\" */
+ if (len >= size-sizeof(PCI_IDS)-4)
{
free(path);
size *= 2;
else if (len == 0)
path[0] = '\0';
+ /*
+ * GetModuleFileName() has bugs. On Windows 10 it prepends current drive
+ * letter if path is just pure NT namespace (with "\\??\\" prefix). Such
+ * extra drive letter makes path fully invalid and unusable. So remove
+ * extra drive letter to make path valid again.
+ * Reproduce: CreateProcessW("\\??\\C:\\lspci.exe", ...)
+ */
+ if (((path[0] >= 'a' && path[0] <= 'z') ||
+ (path[0] >= 'A' && path[0] <= 'Z')) &&
+ strncmp(path+1, ":\\??\\", 5) == 0)
+ {
+ memmove(path, path+2, len-2);
+ len -= 2;
+ path[len] = '\0';
+ }
+
+ /*
+ * GetModuleFileName() has bugs. On Windows 10 it does not add "\\\\?\\"
+ * prefix when path is in native NT UNC namespace. Such path is treated by
+ * WinAPI/DOS functions as standard DOS path relative to the current
+ * directory, hence something completely different. So prepend missing
+ * "\\\\?\\" prefix to make path valid again.
+ * Reproduce: CreateProcessW("\\??\\UNC\\10.0.2.4\\qemu\\lspci.exe", ...)
+ *
+ * If path starts with DOS drive letter and with appended PCI_IDS is
+ * longer than 260 bytes and is without "\\\\?\\" prefix then append it.
+ * This prefix is required for paths and file names with DOS drive letter
+ * longer than 260 bytes.
+ */
+ if (strncmp(path, "\\UNC\\", 5) == 0 ||
+ strncmp(path, "UNC\\", 4) == 0 ||
+ (((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) &&
+ len + sizeof(PCI_IDS) >= 260))
+ {
+ memmove(path+4, path, len);
+ memcpy(path, "\\\\?\\", 4);
+ len += 4;
+ path[len] = '\0';
+ }
+
#elif defined(PCI_OS_DJGPP) || defined(PCI_OS_WINDOWS)
const char *exe_path;
return a;
}
-void
-pci_init_v35(struct pci_access *a)
+int
+pci_init_internal(struct pci_access *a, int skip_method)
{
if (!a->error)
a->error = pci_generic_error;
if (!a->debugging)
a->debug = pci_null_debug;
- if (a->method)
+ if (a->method != PCI_ACCESS_AUTO)
{
if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method])
a->error("This access method is not supported.");
struct pci_methods *m = pci_methods[probe_sequence[i]];
if (!m)
continue;
+ if (skip_method == probe_sequence[i])
+ continue;
a->debug("Trying method %s...", m->name);
if (m->detect(a))
{
a->debug("...No.\n");
}
if (!a->methods)
- a->error("Cannot find any working access method.");
+ return 0;
}
a->debug("Decided to use %s\n", a->methods->name);
a->methods->init(a);
+ return 1;
+}
+
+void
+pci_init_v35(struct pci_access *a)
+{
+ if (!pci_init_internal(a, -1))
+ a->error("Cannot find any working access method.");
}
STATIC_ALIAS(void pci_init(struct pci_access *a), pci_init_v35(a));
SYMBOL_VERSION(pci_init_v30, pci_init@LIBPCI_3.0);
SYMBOL_VERSION(pci_init_v35, pci_init@@LIBPCI_3.5);
+struct pci_access *
+pci_clone_access(struct pci_access *a)
+{
+ struct pci_access *b = pci_alloc();
+
+ b->writeable = a->writeable;
+ b->buscentric = a->buscentric;
+ b->debugging = a->debugging;
+ b->error = a->error;
+ b->warning = a->warning;
+ b->debug = a->debug;
+
+ return b;
+}
+
void
pci_cleanup(struct pci_access *a)
{