summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>2023-03-04 16:58:35 +0100
committerMartin Mares <mj@ucw.cz>2023-03-04 16:58:35 +0100
commita2da3682755e13d2f02290b7c77e7dbb4179c441 (patch)
tree165bd9eae0dd9f2adbfdcafb2f02d2eb2163ccbd
parent85f05a7c92b23d7e306be5feb5a5ae26a47afe67 (diff)
parent848123ebb5a034c48797fb67ad1b19f36e2cb80c (diff)
downloadpciutils-a2da3682755e13d2f02290b7c77e7dbb4179c441.tar.gz
Merge remote-tracking branch 'pali/win32-cfgmgr32'
-rw-r--r--lib/init.c22
-rw-r--r--lib/internal.h1
-rw-r--r--lib/win32-cfgmgr32.c117
-rw-r--r--pcilib.man17
4 files changed, 140 insertions, 17 deletions
diff --git a/lib/init.c b/lib/init.c
index 4d28a2e..ffb55e8 100644
--- a/lib/init.c
+++ b/lib/init.c
@@ -421,7 +421,7 @@ pci_alloc(void)
}
void
-pci_init_v35(struct pci_access *a)
+pci_init_internal(struct pci_access *a, int throw_errors, int skip_method)
{
if (!a->error)
a->error = pci_generic_error;
@@ -435,7 +435,11 @@ pci_init_v35(struct pci_access *a)
if (a->method)
{
if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method])
- a->error("This access method is not supported.");
+ {
+ if (throw_errors)
+ a->error("This access method is not supported.");
+ return;
+ }
a->methods = pci_methods[a->method];
}
else
@@ -446,6 +450,8 @@ pci_init_v35(struct pci_access *a)
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))
{
@@ -457,12 +463,22 @@ pci_init_v35(struct pci_access *a)
a->debug("...No.\n");
}
if (!a->methods)
- a->error("Cannot find any working access method.");
+ {
+ if (throw_errors)
+ a->error("Cannot find any working access method.");
+ return;
+ }
}
a->debug("Decided to use %s\n", a->methods->name);
a->methods->init(a);
}
+void
+pci_init_v35(struct pci_access *a)
+{
+ pci_init_internal(a, 1, -1);
+}
+
STATIC_ALIAS(void pci_init(struct pci_access *a), pci_init_v35(a));
DEFINE_ALIAS(void pci_init_v30(struct pci_access *a), pci_init_v35);
SYMBOL_VERSION(pci_init_v30, pci_init@LIBPCI_3.0);
diff --git a/lib/internal.h b/lib/internal.h
index e9e413e..7f19db4 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -81,6 +81,7 @@ int pci_emulated_read(struct pci_dev *d, int pos, byte *buf, int len);
void *pci_malloc(struct pci_access *, int);
void pci_mfree(void *);
char *pci_strdup(struct pci_access *a, const char *s);
+void pci_init_internal(struct pci_access *a, int throw_errors, int skip_method);
void pci_init_v30(struct pci_access *a) VERSIONED_ABI;
void pci_init_v35(struct pci_access *a) VERSIONED_ABI;
diff --git a/lib/win32-cfgmgr32.c b/lib/win32-cfgmgr32.c
index a3404d1..d63756b 100644
--- a/lib/win32-cfgmgr32.c
+++ b/lib/win32-cfgmgr32.c
@@ -1531,7 +1531,8 @@ scan_devinst_id(struct pci_access *a, DEVINSTID_A devinst_id)
d = pci_get_dev(a, domain, bus, dev, func);
pci_link_dev(a, d);
- d->no_config_access = 1;
+ if (!d->access->aux)
+ d->no_config_access = 1;
d->aux = (void *)devinst;
/* Parse device id part of devinst id and fill details into pci_dev. */
@@ -1633,6 +1634,12 @@ win32_cfgmgr32_scan(struct pci_access *a)
pci_mfree(devinst_id_list);
}
+static void
+win32_cfgmgr32_config(struct pci_access *a)
+{
+ pci_define_param(a, "win32.cfgmethod", "auto", "PCI config space access method");
+}
+
static int
win32_cfgmgr32_detect(struct pci_access *a)
{
@@ -1666,43 +1673,129 @@ win32_cfgmgr32_detect(struct pci_access *a)
}
static void
-win32_cfgmgr32_fill_info(struct pci_dev *d UNUSED, unsigned int flags UNUSED)
+win32_cfgmgr32_fill_info(struct pci_dev *d, unsigned int flags)
{
/*
- * All available flags were filled by win32_cfgmgr32_scan()
- * and reading config space is not supported via cfgmgr32.
+ * All available flags were filled by win32_cfgmgr32_scan().
+ * Filling more flags is possible only from config space.
*/
+ if (!d->access->aux)
+ return;
+
+ pci_generic_fill_info(d, flags);
+}
+
+static int
+win32_cfgmgr32_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ struct pci_access *a = d->access;
+ struct pci_access *acfg = a->aux;
+ struct pci_dev *dcfg = d->aux;
+
+ if (!acfg)
+ return pci_emulated_read(d, pos, buf, len);
+
+ if (!dcfg)
+ d->aux = dcfg = pci_get_dev(acfg, d->domain, d->bus, d->dev, d->func);
+
+ return pci_read_block(dcfg, pos, buf, len);
}
static int
-win32_cfgmgr32_write(struct pci_dev *d UNUSED, int pos UNUSED, byte *buf UNUSED, int len UNUSED)
+win32_cfgmgr32_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ struct pci_access *a = d->access;
+ struct pci_access *acfg = a->aux;
+ struct pci_dev *dcfg = d->aux;
+
+ if (!acfg)
+ return 0;
+
+ if (!dcfg)
+ d->aux = dcfg = pci_get_dev(acfg, d->domain, d->bus, d->dev, d->func);
+
+ return pci_write_block(dcfg, pos, buf, len);
+}
+
+static void
+win32_cfgmgr32_cleanup_dev(struct pci_dev *d)
{
- /* Writing to config space is not supported via cfgmgr32. */
- return 0;
+ struct pci_dev *dcfg = d->aux;
+
+ if (dcfg)
+ pci_free_dev(dcfg);
}
static void
-win32_cfgmgr32_init(struct pci_access *a UNUSED)
+win32_cfgmgr32_init(struct pci_access *a)
{
+ char *cfgmethod = pci_get_param(a, "win32.cfgmethod");
+ struct pci_access *acfg;
+
+ if (strcmp(cfgmethod, "") == 0 ||
+ strcmp(cfgmethod, "auto") == 0)
+ {
+ acfg = pci_alloc();
+ acfg->method = PCI_ACCESS_AUTO;
+ }
+ else if (strcmp(cfgmethod, "none") != 0 &&
+ strcmp(cfgmethod, "win32-cfgmgr32") != 0)
+ {
+ int m = pci_lookup_method(cfgmethod);
+ if (m < 0)
+ a->error("Option win32.cfgmethod is set to unknown access method \"%s\".", cfgmethod);
+ acfg = pci_alloc();
+ acfg->method = m;
+ }
+ else
+ {
+ if (a->writeable)
+ a->error("Write access requested but option win32.cfgmethod was not set.");
+ return;
+ }
+
+ acfg->writeable = a->writeable;
+ acfg->buscentric = a->buscentric;
+ acfg->debugging = a->debugging;
+ acfg->error = a->error;
+ acfg->warning = a->warning;
+ acfg->debug = a->debug;
+
+ a->debug("Loading config space access method...\n");
+ pci_init_internal(acfg, 0, PCI_ACCESS_WIN32_CFGMGR32);
+ if (!acfg->methods)
+ {
+ pci_cleanup(acfg);
+ a->debug("Cannot find any working config space access method.\n");
+ if (a->writeable)
+ a->error("Write access requested but no usable access method.");
+ return;
+ }
+
+ a->aux = acfg;
}
static void
-win32_cfgmgr32_cleanup(struct pci_access *a UNUSED)
+win32_cfgmgr32_cleanup(struct pci_access *a)
{
+ struct pci_access *acfg = a->aux;
+
+ if (acfg)
+ pci_cleanup(acfg);
}
struct pci_methods pm_win32_cfgmgr32 = {
"win32-cfgmgr32",
"Win32 device listing via Configuration Manager",
- NULL, /* config */
+ win32_cfgmgr32_config,
win32_cfgmgr32_detect,
win32_cfgmgr32_init,
win32_cfgmgr32_cleanup,
win32_cfgmgr32_scan,
win32_cfgmgr32_fill_info,
- pci_emulated_read, /* Reading of config space is not supported via cfgmgr32. */
+ win32_cfgmgr32_read,
win32_cfgmgr32_write,
NULL, /* read_vpd */
NULL, /* init_dev */
- NULL, /* cleanup_dev */
+ win32_cfgmgr32_cleanup_dev,
};
diff --git a/pcilib.man b/pcilib.man
index b4c9f56..3d1b49a 100644
--- a/pcilib.man
+++ b/pcilib.man
@@ -86,8 +86,12 @@ Device listing on Windows systems using the Windows Configuration Manager
via cfgmgr32.dll system library. This method does not require any special
Administrator rights or privileges. Configuration Manager provides only basic
information about devices, assigned resources and device tree structure. There
-is no access to the PCI configuration space but libpci provides read-only
-virtual emulation based on information from Configuration Manager. Starting
+is no access to the PCI configuration space but libpci either tries to use
+other access method to access configuration space or it provides read-only
+virtual emulation based on information from Configuration Manager. Other
+access method can be chosen by the
+.B win32.cfgmethod
+parameter. By default the first working one is selected (if any). Starting
with Windows 8 (NT 6.2) it is not possible to retrieve resources from 32-bit
application or library on 64-bit system.
.TP
@@ -165,6 +169,15 @@ Physical addresses of memory-mapped I/O ports for Extended PCIe Intel configurat
It has same format as
.B mmio-conf1.addrs
parameter.
+.TP
+.B win32.cfgmethod
+Config space access method for win32-cfgmgr32 on Windows systems. Value
+.I auto
+or emtpy string probe and choose the first access method which supports access
+to the config space access on Windows. Value
+.I win32-cfgmgr32
+only builds read-only virtual emulated config space with information from the
+Configuration Manager.
.SS Parameters for resolving of ID's via DNS
.TP