summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <mail@daniel-baumann.ch>2021-08-31 18:08:58 +0000
committerDaniel Baumann <mail@daniel-baumann.ch>2021-08-31 18:08:58 +0000
commitdcaffdf6f5a1e66abd0bd0f5b0661a6f761c0935 (patch)
tree0c9a9bb4e84072b329dc04e3474f08a21281b286
parentInitial commit. (diff)
downloadpciutils-dcaffdf6f5a1e66abd0bd0f5b0661a6f761c0935.tar.xz
pciutils-dcaffdf6f5a1e66abd0bd0f5b0661a6f761c0935.zip
Adding upstream version 1:3.7.0.upstream/1%3.7.0upstream
Signed-off-by: Daniel Baumann <mail@daniel-baumann.ch>
-rw-r--r--.gitignore9
-rw-r--r--COPYING339
-rw-r--r--ChangeLog2275
-rw-r--r--Makefile168
-rw-r--r--README146
-rw-r--r--README.Windows23
-rw-r--r--TODO22
-rw-r--r--common.c135
-rw-r--r--compat/README2
-rw-r--r--compat/getopt.c693
-rw-r--r--compat/getopt.h127
-rw-r--r--example.c37
-rw-r--r--lib/.gitignore3
-rw-r--r--lib/Makefile102
-rw-r--r--lib/access.c266
-rw-r--r--lib/aix-device.c274
-rw-r--r--lib/caps.c147
-rwxr-xr-xlib/configure274
-rw-r--r--lib/darwin.c211
-rw-r--r--lib/dump.c189
-rw-r--r--lib/fbsd-device.c369
-rw-r--r--lib/filter.c240
-rw-r--r--lib/generic.c225
-rw-r--r--lib/header.h1395
-rw-r--r--lib/hurd.c380
-rw-r--r--lib/i386-io-beos.h67
-rw-r--r--lib/i386-io-cygwin.h30
-rw-r--r--lib/i386-io-djgpp.h45
-rw-r--r--lib/i386-io-haiku.h132
-rw-r--r--lib/i386-io-hurd.h35
-rw-r--r--lib/i386-io-linux.h30
-rw-r--r--lib/i386-io-sunos.h74
-rw-r--r--lib/i386-io-windows.h77
-rw-r--r--lib/i386-ports.c315
-rw-r--r--lib/init.c269
-rw-r--r--lib/internal.h97
-rw-r--r--lib/libpci.pc.in11
-rw-r--r--lib/libpci.ver84
-rw-r--r--lib/names-cache.c204
-rw-r--r--lib/names-hash.c128
-rw-r--r--lib/names-hwdb.c109
-rw-r--r--lib/names-net.c250
-rw-r--r--lib/names-parse.c252
-rw-r--r--lib/names.c226
-rw-r--r--lib/names.h75
-rw-r--r--lib/nbsd-libpci.c157
-rw-r--r--lib/obsd-device.c152
-rw-r--r--lib/params.c87
-rw-r--r--lib/pci.h284
-rw-r--r--lib/pread.h57
-rw-r--r--lib/proc.c212
-rw-r--r--lib/sylixos-device.c158
-rw-r--r--lib/sysdep.h112
-rw-r--r--lib/sysfs.c517
-rw-r--r--lib/types.h75
-rw-r--r--ls-caps-vendor.c82
-rw-r--r--ls-caps.c1778
-rw-r--r--ls-ecaps.c1093
-rw-r--r--ls-kernel.c323
-rw-r--r--ls-map.c181
-rw-r--r--ls-tree.c279
-rw-r--r--ls-vpd.c222
-rw-r--r--lspci.c1132
-rw-r--r--lspci.h114
-rw-r--r--lspci.man369
-rw-r--r--maint/RELEASE18
-rwxr-xr-xmaint/gen-zone52
-rwxr-xr-xmaint/release58
-rw-r--r--maint/release.pm328
-rwxr-xr-xmaint/tag-release6
-rw-r--r--pci.ids32854
-rw-r--r--pci.ids.man92
-rw-r--r--pcilib.man119
-rw-r--r--pciutils.h48
-rw-r--r--pciutils.lsm14
-rw-r--r--pciutils.spec49
-rw-r--r--setpci.c819
-rw-r--r--setpci.man190
-rw-r--r--tests/PCI-X-bridges-and-domains558
-rw-r--r--tests/bridge-ctl-vga16129
-rw-r--r--tests/broken-ecaps257
-rw-r--r--tests/cap-MSI-mapping17
-rw-r--r--tests/cap-address-xlation298
-rw-r--r--tests/cap-aer-ecrc-label327
-rw-r--r--tests/cap-aer-hdr322
-rw-r--r--tests/cap-aer-log323
-rw-r--r--tests/cap-aer-root626
-rw-r--r--tests/cap-atomicops54
-rw-r--r--tests/cap-debug-port17
-rw-r--r--tests/cap-dpc91
-rw-r--r--tests/cap-dvsec-cxl353
-rw-r--r--tests/cap-ea-1324
-rw-r--r--tests/cap-exp-aspm-latencies327
-rw-r--r--tests/cap-exp-dev2333
-rw-r--r--tests/cap-exp-lnkcap21317
-rw-r--r--tests/cap-exp-rev-slot288
-rw-r--r--tests/cap-ht99
-rw-r--r--tests/cap-l1-pm305
-rw-r--r--tests/cap-multicast257
-rw-r--r--tests/cap-pasid-pri293
-rw-r--r--tests/cap-pci-af29
-rw-r--r--tests/cap-pcie-1312
-rw-r--r--tests/cap-pcie-2314
-rwxr-xr-xtests/cap-ptm-1292
-rwxr-xr-xtests/cap-ptm-2284
-rw-r--r--tests/cap-rebar258
-rw-r--r--tests/cap-vc-and-rcl2317
-rw-r--r--tests/cap-vc-pat257
-rw-r--r--tests/cap-vendor-virtio41
-rw-r--r--tests/tree-asus-p6t65514
-rw-r--r--tests/tree-fujitsu-p80101836
-rw-r--r--update-pciids.man33
-rwxr-xr-xupdate-pciids.sh75
-rw-r--r--win32/config.h6
-rw-r--r--win32/config.mk13
115 files changed, 71088 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a797910
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*.a
+*.o
+*.so
+*.[0-9]
+lspci
+setpci
+example
+update-pciids
+pci.ids.gz
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..54f7fde
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,2275 @@
+2020-05-31 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.7.0.
+
+ * Added or improved the following capabilities: Designated Vendor-Specific,
+ Compute eXpress Link, Resizable BARs, VF Resizable BARs, Link
+ Capabilities 2, Link Status 2.
+
+ * On Linux, lspci can show IOMMU groups.
+
+ * setpci can be asked to skip bus scan and operate on a device
+ completely specified by its domain/bus/dev/func address. This
+ involved major internal cleanup.
+
+ * The above feature of setpci uses the pci_get_dev() function,
+ which obtains a struct pci_dev without doing a bus scan. This was
+ always possible, but apparently little used, because back-ends
+ frequently choked when operating on such devices. Fixed a lot
+ of minor bugs related to this.
+
+ * Also, back-ends which do not support domains now correctly fail when
+ trying to access devices outside domain 0.
+
+ * Semantics of pci_fill_info() and pci_dev->known_fields was underspecified,
+ which lead to inconsistencies between back-ends. Improved documentation
+ to give a more precise definition and updated all back-ends to conform
+ to it. Most importantly, pci_dev->known_fields shows all fields requested
+ over the lifetime of the pci_dev, but never those which are not supported
+ by the back-end.
+
+ * As usually, updated pci.ids to the current snapshot of the database.
+
+2020-01-25 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.6.4.
+
+ * A new back-end for the GNU Hurd was contributed by Joan Lledó.
+
+ * When printing VPD item identifiers, non-ASCII characters are escaped.
+
+2020-01-22 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.6.3.
+
+ * `lspci -t' (tree mode) can be combined with `-s' to show a sub-tree.
+ We also fixed potential buffer overflows in the tree dumper.
+
+ * Cleaned messy code for dumping of I/O, memory, and ROM regions.
+ This helped fixing a bug, which caused some 64-bit regions to be
+ reported as virtual. All flags are now printed after the address
+ (previously, "[virtual]" and "[enhanced]" were before it for no good
+ reason).
+
+ * Added pci_find_cap_nr() to the library, which handles capabilities
+ which occur multiple times in a single device.
+
+ * Minor improvements in printing of PCIe capabilities.
+
+ * We now decode the Multicast and Secondary PCI Express extended
+ capabilities.
+
+ * The list of capability names available to setpci was updated.
+
+ * Minor bugs were fixed in FreeBSD and Solaris ports.
+
+ * We now prefer HTTPS URLs in all documentation
+
+ * The pci.ids file has a man page.
+
+ * As usually, updated pci.ids to the current snapshot of the database.
+
+2018-08-12 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.6.2.
+
+ * Added "-P" and "-PP" switches to lspci, which display the path
+ through bridges to each device.
+
+ * Fixed a couple of bugs in computation of bus topology. It was
+ previously used only for the tree display, but we re-use it for
+ computing the paths.
+
+ * As usually, updated pci.ids to the current snapshot of the database.
+
+2018-07-12 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.6.1.
+
+ * Fixed compilation issues on Linux systems with MUSL libc.
+
+2018-06-30 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.6.0.
+
+ * BARs reported by the OS, but not set on the device itself are
+ reliably marked with "[virtual]".
+
+ * Library: Introduced a generic mechanism of string properties. This
+ avoids lots of special cases and makes ABI compatibility easier.
+
+ * On Linux systems with OpenFirmware, report corresponding device tree nodes
+ as device properties.
+
+ * VPD decoder knows several non-standard extensions.
+
+ * When PCIe link speed is less than the maximum supported by the
+ device, it is explicitly marked as "downgraded".
+
+ * Several new capabilities are not decoded yet, but at least their
+ names are printed.
+
+ * The Null capability is easily decoded.
+
+ * Formatting of several capabilities was cleaned up.
+
+ * The VGA16 bit in the bridge control register is now supported.
+
+ * Added a port to SylixOS. Thanks to YuJian Gong for contribution.
+
+ * Added a port to DOS/DJGPP. Thanks to Rudolf Marek for contribution.
+
+ * The order in which back-ends are probed was decoupled from the
+ internal back-end IDs. This helps, because new back-ends must have
+ their ID allocated at the end to keep the ABI, but they might need
+ to be probed earlier.
+
+ * The fbsd-device back-end should work again.
+
+ * Fixed a couple of bugs. Most notably, DeviceName was not printed.
+
+ * As usually, updated pci.ids to the current snapshot of the database.
+
+2017-11-17 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.5.6.
+
+ * Improvements of the FreeBSD back-end: read-only access for non-root,
+ support DragonFly BSD, support extended config space.
+
+ * MN VPD keyword is decoded correctly.
+
+ * As usually, updated pci.ids to the current snapshot of the database.
+
+2017-07-05 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.5.5.
+
+ * Better decoding of AER capability.
+
+ * "Slot Implemented" flag is decoded for PCI/PCI-X to PCIe bridges.
+
+ * Minor fixes of decoding other capabilities.
+
+ * As usually, updated pci.ids to the current snapshot of the database.
+
+2017-02-25 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.5.4.
+
+ * Previous version broke compilation on systems, for which lib/types.h
+ did not provide a 64-bit integer type. It is provided everywhere now.
+
+2017-02-15 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.5.3.
+
+ * When lspci looks for Linux kernel modules, it uses the default
+ path to module directory provided by libkmod. Previously,
+ it tried to construct the path explicitly, which need not
+ work on all systems.
+
+ * Improved formatting of memory and I/O ranges behind a bridge.
+
+ * PCIe link capabilities now display GEN4 speed (16GT/s).
+
+ * PCIe device capabilities now show bits related to atomic operations.
+ Thanks to Satanand Burla for a patch.
+
+ * As usually, updated pci.ids to the current snapshot of the database.
+
+2016-10-03 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.5.2.
+
+ * The L1 power management capability is now decoded more
+ thoroughly. Thanks to Rajat Jain for the patch.
+
+ * The table of configuration registers used by setpci
+ had a bug in the definition of SUBSYSTEM_VENDOR_ID.
+
+2016-05-22 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.5.1.
+
+ * Fixed symbol versioning of pci_init().
+
+2016-05-19 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.5.0.
+
+ * New capabilities decoded: Downstream Port Containment,
+ Precision Time Measurement. Thanks to Keith Busch and
+ Jonathan Yong.
+
+ * Domain numbers extended to 31 bits. This will be used by the
+ Linux kernel on some machines in near future.
+
+ * Enhanced allocation regions are now decoded on Linux.
+
+ * The NetBSD back-end supports PCIe extended configuration space.
+
+ * Updated pci.ids to the current snapshot of the database.
+
+2016-01-03 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.4.1.
+
+ * New capabilities decoded: Process Address Space, Page Request
+ Interface, Enhanced Allocation. Thanks to David Daney and
+ David Woodhouse.
+
+ * DevCap SlotPowerLimit is now decoded for all components with
+ upstream ports.
+
+ * Database mirror at SourceForge moved to GitHub.
+
+ * Updated pci.ids to the current snapshot of the database.
+
+2015-09-14 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.4.0.
+
+ * On Linux, we report NUMA nodes of devices.
+
+ * The sysfs back-end does not die on read errors
+ of optional attributes. Instead, a warning is produced.
+
+ * Fixed several minor bugs.
+
+ * Updated pci.ids to the current snapshot of the database.
+
+2015-04-09 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.3.1.
+
+ * Removed hacks for backward compatibility with Linux libc5,
+ which were breaking newer non-glibc Linux systems. Thanks
+ to Felix Janda.
+
+ * Display VirtIO vendor-specific capability. Patch by Gerd
+ Hoffmann.
+
+ * Fixed memory leak in name cache.
+
+ * Updated pci.ids to the current snapshot of the database.
+
+2014-11-10 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.3.0.
+ (celebrating a one-year anniversary of the previous version :))
+
+ * Device names exported by BIOS are displayed on Linux.
+
+ * On Linux systems, HWDB is used to look up device names
+ when our ID database gives no match. (More precisely,
+ HWDB is consulted after local pci.ids, but before using
+ network to query online pci.ids.) Thanks to Tom Gundersen
+ for the initial patch.
+
+ * Added experimental back-end for OS X / Darwin. Thanks to
+ Richard Yao for providing it.
+
+ * Filters now support matching by device class. Original
+ patch by Matthew Wilcox, wrappers for ABI compatibility
+ by me.
+
+ * Interrupt Pin and Interrupt Line registers are displayed
+ for bridge devices, too.
+
+ * Several portability bugs have been fixed.
+
+ * Several typos have been fixed. Also, use of questionable
+ constructs in man pages has been reduced.
+
+ * PCIe link capabilities now include the ASPMOptComp bit.
+
+ * The "CRS Software Visibility" bit is now decoded properly.
+
+ * Updated pci.ids to the current snapshot of the database.
+
+2013-11-10 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.2.1.
+
+ * CardBus bridge capabilities are displayed.
+
+ * PCIe L1 PM substates are decoded.
+
+ * Various bugs were fixed in decoding of PCIe capabilities.
+
+ * The sysfs back-end does not spit out unnecessary warnings when
+ empty slots report only a partial device address. This actually
+ happens on IBM pSeries.
+
+ * Updated pci.ids to the today's snapshot of the database.
+
+2013-04-19 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.2.0.
+
+ * On newer Linux systems, we use libkmod to look up kernel modules
+ (modules.pcimap no longer exists). To facilitate this, libpci
+ is able to look up module aliases in sysfs.
+
+ * Various minor bug fixes.
+
+ * Updated pci.ids to the today's snapshot of the database.
+
+2012-06-25 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.1.10.
+
+ * Decoding of LTR/OBFF in PCIe capabilities.
+
+ * Various minor bug fixes.
+
+ * Updated pci.ids to the today's snapshot of the database.
+
+2012-01-14 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.1.9.
+
+ * Updated README.
+
+ * Wherever we mention the PCI ID database, we now refer to
+ http://pci-ids.ucw.cz/ and the sf.net site is mentioned only
+ as a mirror. This includes update-pciids.
+
+ * Decode PCIe Gen 3 speeds and link status fields.
+
+ * Various minor bug fixes.
+
+ * Updated pci.ids to the today's snapshot of the database.
+
+2011-10-02 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.1.8.
+
+ * More capabilities: Transaction Processing Hints, Latency Tolerance
+ Reporting. Thanks to Jesse Barnes.
+
+ * Added BeOS and Haiku ports. Contributed by Francois Revol.
+
+ * pciutils.pc now uses Libs.private properly.
+
+ * When we format a name and it does not fit in the buffer, we truncate
+ it instead of returning "buffer too small" instead. This works on all
+ platforms with sane (i.e., C99-compatible) snprintf().
+
+ * Various minor bug fixes.
+
+ * Updated pci.ids to the today's snapshot of the database.
+
+2010-01-31 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.1.7.
+
+ * Minor improvements and bug fixes in decoding of the Virtual Channel
+ capability.
+
+2010-01-24 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.1.6.
+
+ * More capabilities decoded: Virtual Channel (except arbitration
+ tables), Root Complex Link, Vendor-Specific (header only), SATA HBA.
+
+ * All extended capabilities have their version displayed (-vv or more).
+
+2010-01-19 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.1.5.
+
+ * Updated pci.ids to the today's snapshot of the database.
+
+ * When scanning extended capabilities, properly mask the lowest 2 bits,
+ which are currently reserved. This avoids unaligned access errors on
+ broken hardware (see tests/broken-ecaps).
+
+ * Large bar sizes are displayed in human-readable format (with units).
+ Thanks to Matthew Wilcox.
+
+ * Physical slot information is displayed correctly for multi-function cards.
+ Fixed by Matthew Wilcox.
+
+ * Fixed a couple of typos everywhere.
+
+ * Library: Fixed bugs in freeing of capabilities.
+
+ * Windows back-end compiles again.
+
+2009-08-14 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.1.4.
+ (sorry that I have missed 22/7 and released it later :-))
+
+ * Updated pci.ids to the today's snapshot of the database.
+
+ * Fixed memory and file descriptor leak in the dump back-end.
+
+ * The SR-IOV capability decoder now prints the VF BAR's.
+ Patch by Chris Wright, cleaned up by me.
+
+ * On request of certain company's lawyers, we now include a copy
+ of the GPL with our package. It seems that the pciutils are getting
+ mature if the most important bug of the month was this one ;-)
+
+2009-07-04 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.1.3.
+
+ * Updated pci.ids to the current snapshot of the database.
+
+ * The VPD parser now reports unknown and vendor-defined items
+ properly. It also stops on any item in unknown format, avoiding long
+ output on bogus VPD data. Thanks to Ben Hutchings and Matthew Wilcox.
+
+ * The MSI-X table size now matches the spec. Thanks to Michael S.
+ Tsirkin.
+
+ * The Power Management capability now includes the soft reset bit.
+ Thanks to Yu Zhao.
+
+ * Decoding of the Advanced Features capability has been added.
+ Thanks to Yu Zhao.
+
+ * The whole package compiles on GNU/kFreeBSD again.
+
+ The following patches have been contributed by Matthew Wilcox:
+
+ * The procfs back-end is able to cope with /proc/bus/pci
+ containing names with domains, which occur on sparc64 and
+ possibly other architectures due to a kernel bug.
+
+ * The sysfs back-end no longer complains when a slot address
+ is missing, which happens with old versions of Linux fakephp.
+
+ * The Device Serial Number capability is printed in the right
+ byte order.
+
+ * The MSI and MSI-X capabilities are printed in a prettier way.
+
+ * The tree output mode (`lspci -t') shows domain numbers only
+ at the root, which makes the output more compact.
+
+ * Updated documentation on the bus mapping mode (`lspci -M').
+
+2009-02-01 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.1.2.
+
+ * Fixed another silly bug in the command-line parser of setpci.
+
+2009-01-30 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.1.1.
+
+ * Updated pci.ids to the current snapshot of the database.
+
+ * The configure script now sets LC_ALL to avoid being fooled by
+ locale-dependent behavior of `tr'.
+
+ * The command-line parser of setpci did sometimes segfault on invalid
+ input. Thanks to Andreas Wiese for a fix.
+
+2009-01-18 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.1.0.
+
+ * Updated pci.ids to the current snapshot of the database.
+
+ * The Cygwin backend now works on Windows Vista. Thanks to Jonathan
+ Kotta.
+
+ * Fixed a bug in decoding of the SR-IOV capability. Patch by Yu Zhao.
+
+ * Details of some PCIe capabilities are displayed only with -vv.
+
+ * When a BAR is reported by the OS, but not by the device (i.e.,
+ it is marked as [virtual] in lspci), the [disabled] flag is
+ suppressed, because it does not make sense in such cases.
+ Patch by Yu Zhao.
+
+2008-12-13 Martin Mares <mj@ucw.cz>
+
+ * The source code of lspci has been split to multiple files, hopefully
+ making it easier to maintain.
+
+ * The library and lspci now know about physical slot names. So far,
+ they are provided by the sysfs back-end only. Thanks go to Alex Chiang.
+
+ * When a device has the VPD (Vital Product Data) capability and the
+ VPD data are supplied by the OS, they are decoded and printed in the
+ verbose mode. This currently works only on Linux with the sysfs
+ back-end. Thanks to Ben Hutchings of Solarflare for the patch.
+
+ * `setpci --version' now works properly.
+
+ * `setpci --dumpregs' prints a table of all known names of
+ registers and capabilities. This replaces the table of registers
+ in the setpci man page.
+
+ * The dry-run mode of setpci gives better feedback.
+
+ * The setpci utility is now able to address registers stored in PCI
+ capabilities (actually it allows a more general form of relative
+ addressing).
+
+ * The library has gained functions for working with PCI capabilities.
+
+ * Address Translation Services capability is now decoded. Patch by
+ Yu Zhao.
+
+2008-11-09 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.0.3.
+
+ * `lspci -k' now displays the subsystem ID, too. This makes `-k'
+ show everything needed to identify the device and the available
+ drivers, which was called for by many users.
+
+ * Fixed spelling of MSI. Patch by Matthew Wilcox.
+
+ * Better support for cross-compilation. Thanks to Alon Bar-Lev
+ for the patch.
+
+ * Fixed printing of the AER capability. Patch by Max Asbock.
+
+ * HT 1.02 capabilities are decoded as HT 1.03. Suggested by
+ Carl-Daniel Hailfinger.
+
+ * Fixed Cygwin build. Thanks to Steve Elliott for reporting the bug.
+
+ * Updated pci.ids to the current snapshot of the database.
+
+2008-09-19 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.0.2.
+
+ * Fixed a minor bug in the configure script, which caused warnings
+ about redefinition of symbols during compilation.
+
+2008-09-11 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.0.1.
+
+ * Updated pci.ids to the most recent snapshot.
+
+ * Added a Cygwin port. Patch by Christopher Voltz, ported to the
+ current tree by Martin Mares.
+
+ * Worked around compatibility problems with various default settings
+ of wget (we have to set --no-timestamping explicitly). Thanks to Ville
+ Skytta for pointing that out.
+
+ * Fixed printing of MSI capabilities. Thanks to Matthew Wilcox for
+ a patch.
+
+ * Added decoding of several PCI-X capabilities: device/link/slot 2,
+ Advanced Error Reporting, Access Control Services, Alternative Routing-ID,
+ Single Root I/O Virtualization. Thanks to Yu Zhao for patches.
+
+ * Fixed bug in filters which caused them to refuse vendor/device ID 0xffff.
+
+ * README: The linux-pci mailing list has moved to linux-pci@vger.kernel.org.
+
+ * Fixed several build problems: builds without PCI_USE_DNS on Linux
+ and with PCI_USE_DNS on Solaris and *BSD. Static library mode also
+ compiles again on old versions of GCC.
+
+2008-04-10 Martin Mares <mj@ucw.cz>
+
+ * Released as 3.0.0.
+
+ * Updated API and ABI version.
+
+2008-02-20 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.99.1-alpha2.
+
+ * Changed the default domain for the DNS resolver.
+
+2008-02-18 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.99.1-alpha1.
+
+ * The makefile system has been reworked. All configuration settings
+ are now passed to the configure script in environment variables,
+ allowing for easy tweaking in the top-level Makefile. All control
+ knobs are now described in the README.
+
+ * The libpci can be built as a shared library with properly restricted
+ symbol exports. Use `make SHARED=yes' to enable that or `make SHARED=local'
+ for a local testing build (with hardwired paths to the library, so that
+ it does not need installation).
+
+ * The example program has been moved from lib/example.c to the top-level
+ directory, because it should be built exactly as the other utilities
+ are. It has been also improved slightly to educate better.
+
+ * The i386-ports method is enabled on Linux/x86_64 as well.
+
+2008-02-13 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.10-net2.
+
+ * Support for resolving of PCI ID's using DNS together with a local
+ cache of resolved entries has been added. See the `-q' and `-Q' options
+ of lspci.
+
+ * The library now has a generic system of settable parameters, which
+ also include settings of the DNS resolver and cache. An `-O' option
+ has been added to lspci and setpci to allow setting of these options.
+
+ * Configuration of the access methods are now specified by the new
+ parameter system, replacing the pci_access->method_params array.
+
+ * Access methods now also have sensible names and help texts and it
+ is possible to look up method ID by a name.
+
+ * An `-A' switch has been added to both lspci and setpci, allowing to
+ select an arbitrary access method. The `-P' switch (configure proc
+ backend) has been removed as it is no longer needed and I do not know
+ any its user.
+
+ * Several source files have been split for better maintainability
+ (most notably the resolving of ID's).
+
+ * Man pages and help texts have been updated. A new man page `pcilib(7)'
+ has been added and description of library options has been moved there.
+
+ * When an unknown device ID is encountered, we print `Device <id>'
+ instead of `Unknown device <id>'. It uses less space and it also
+ should reduce the number of inexperienced users complaining that
+ the device is not supported by the OS. To lookup up OS drivers,
+ use the `-k' option.
+
+ * PCI_LIB_VERSION has been bumped to 0x020299.
+
+ * Makefile: stripping of the binaries during installation can be
+ overridden by the STRIP variable.
+
+ * lib/types.h: We use the integer types from <stdint.h> if the
+ compiler claims C99 support.
+
+2008-02-11 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.10.
+
+ * lspci.c, setpci.c: Cleaned up the list of options.
+
+ * lib/names.c: Fix displaying of errors reported by zlib.
+ Previously, the buffer containing the error message had
+ been deallocated by gzclose() before the message was printed.
+
+2008-01-07 Martin Mares <mj@ucw.cz>
+
+ * update-pciids.sh: Added quiet mode (-q). Clean up uncompressed
+ files left by previous versions of the pciutils. Patch by Mike
+ Frysinger.
+
+ * update-pciids.man: Mention the -q switch.
+
+2007-11-29 Martin Mares <mj@ucw.cz>
+
+ * lib/dump.c: Squashed compiler warnings about code with
+ no effect (there really were surplus *'s).
+
+2007-11-06 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.9.
+
+ * lspci.c: Added a new switch `-k' which requests printing
+ of information on kernel drivers attached to each device
+ and on kernel modules reporting the ability to handle the
+ device. So far, this is supported only on Linux with the
+ sysfs back-end, so it is implemented internally in the lspci
+ instead of the libpci. Thanks to Anicka <anicka@anicka.net>
+ for help.
+
+2007-10-19 Martin Mares <mj@ucw.cz>
+
+ * Makefile, lib/Makefile: Moved -lz from LDFLAGS to LDLIBS.
+ Also added an explicit pattern rule for linking to make sure
+ that LDLIBS is used on all platforms. Thanks to Dan Nicholson
+ for the suggestion.
+
+2007-10-19 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.8.
+
+ * pci.ids: Revised class codes to match Conventional PCI 3.0 specs.
+ Added a couple of new ones, renumbered `ADMA continuous operation'
+ prog-if to 0x30 (even the old SATA Class Code ECN doesn't mention
+ 0x40) and renumbered the satellite communication controllers.
+
+ * lib/header.h: Include `PCI hot-plug' and `Secure device'
+ capabilities from PCI 3.0 specs. Also added `SATA HBA' and
+ `Advanced features' caps from various ECN's.
+
+ * lspci.c: All known capabilities have at least their name displayed
+ now. When we are unable to decode them completely, we signalize it
+ with a `<?>' mark.
+
+ * lspci.man: Document `<?>' and also mention that extended config
+ space is currently available only with the linux_sysfs back-end.
+
+ * lspci.c: Decode the Debug port capability (per EHCI 0.96 spec).
+
+ * lspci.c: Big code cleanup: re-arranged functions in the code,
+ renamed everything related to capabilities to cap_* and
+ all options except verbose to opt_*.
+
+2007-10-14 Martin Mares <mj@ucw.cz>
+
+ * lib/[fno]bsd-*: Removed extraneous braces.
+
+2007-10-12 Martin Mares <mj@ucw.cz>
+
+ * Capability loop detection introduced 2.2.7 did not work
+ properly with extended capabilities. Fixed.
+
+2007-10-05 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.7.
+
+ * lspci.c (show_caps, show_ext_caps): Detect and report loops in
+ capability lists.
+
+ * lspci.c, lib/header.h: Finished decoding of the PCI Express
+ capability. The extended capabilities remain undecoded for now,
+ but at least the list of them has been updated to reflect the
+ current PCI Express 2.0 spec.
+
+ * lspci.c, lib/header.h: Decode new bits of traditional registers
+ as defined by PCIE / PCI-X. This includes discard timers in the bridge
+ control register and INTx enable/status in device control/status
+ registers.
+
+ * lib/fbsd-device.c: Support domains on new FreeBSD's. Contributed
+ by Marius Strobl.
+
+2007-09-12 Hasso Tepper <hasso@estpak.ee>
+
+ * Extended the fbsd-device backend to run on Dragonfly BSD.
+
+ * lspci.c: alloca() is declared in <stdlib.h> on BSD's, not <alloca.h>.
+
+2007-09-03 Martin Mares <mj@ucw.cz>
+
+ * Resurrected the Windows port, including cross-compilation by MinGW.
+ Patch by Samuel Bronson <naesten@gmail.com>.
+
+2007-08-31 Martin Mares <mj@ucw.cz>
+
+ * Makefile, lib/Makefile: `ar' and `ranlib' can be overriden to allow
+ cross-compilation.
+
+2007-08-27 Martin Mares <mj@ucw.cz>
+
+ * lib/names.c (pci_open): When calling gzopen(), use "rb" file mode
+ instead of "r". This is needed on DOS systems, where this function
+ somewhat illogically uses the binary flag for the compressed file
+ instead of the decompressed stream inside, where binariness really
+ matters.
+
+2007-08-14 Martin Mares <mj@ucw.cz>
+
+ * lspci.c (show_ht): Added decoding of Hypertransport MSI mapping capability,
+ based on a patch by Jason Gunthorpe.
+
+ * tests/cap-MSI-mapping: Added a test case. I plan to add test cases
+ (which are dumps of config space) for all new features.
+
+2007-06-20 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.6.
+
+ * Makefile: Added an "install-lib" target. Thanks to Dan Nicholson
+ for a patch.
+
+ * Makefile, lib/Makefile: Generate and install pkg-config file
+ for libpci. Again by Dan Nicholson.
+
+2007-06-20 Thomas Schwinge <tschwinge@gnu.org>
+
+ * lib/i386-io-hurd.h: Rewritten for new Hurd kernels.
+
+2007-05-04 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.5.
+
+ * pci.ids: Updated to the current snapshot of the database.
+
+2007-02-14 Martin Mares <mj@ucw.cz>
+
+ * lspci.c (show_express): Added PCI/PCI-X to PCI-Express Bridge type.
+ Patch by Mark Glines.
+
+2007-02-09 Martin Mares <mj@ucw.cz>
+
+ * pci.ids: Updated to the current snapshot of the database.
+
+2007-02-06 Martin Mares <mj@ucw.cz>
+
+ * Replaced bzero() by memset() everywhere, it's better to lose a tiny
+ bit of readability than maintain hacks to make it work on various systems.
+
+ * lib/configure: tr on Solaris is a bit weird and it requires `[A-Z]'
+ instead of `A-Z'. Fortunately, the extra brackets don't hurt otherwise.
+
+ * lib/types.h, lib/configure: Solaris should use <stdint.h> to get precise
+ integer types.
+
+2007-02-04 Martin Mares <mj@ucw.cz>
+
+ * lspci.c: alloca() needs <alloca.h>.
+
+2006-09-17 Martin Mares <mj@ucw.cz>
+
+ * lib/dump.c: Fixed a couple of bugs in the dump backend which caused
+ devices with domains or with extended config space to be read incorrectly.
+ Also, dumps with partial lines are allowed now.
+
+2006-09-10 Martin Mares <mj@ucw.cz>
+
+ * pci.ids: Updated to the current database snapshot.
+
+ * lspci.c (scan_device): If an error occurs when reading the standard config
+ header of a device, report it and ignore the device and return with exit
+ code 2 at the end.
+
+2006-09-09 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.4.
+
+ * maint/release: Remind the maintainer about the current PCI_LIB_VERSION.
+
+ * lib/pci.h: Updated PCI_LIB_VERSION.
+
+ * lspci.c (show_machine): In the `-m' mode, do proper shell escaping
+ if the fields printed contain quotes or backslashes.
+
+ * lspci.c (show_machine): Added a `-vmm' mode, which removes the misuse
+ of the `Device' tag for two different purposes.
+
+ * Makefile: Moved all system-dependent decisions to lib/configure,
+ since config.mk is included in the top-level Makefile anyway.
+
+ * lib/configure: When configuring for Linux, ignore the kernel version
+ and always build all access methods.
+
+ * Makefile (CFLAGS): Removed -Winline, it's not needed and triggers
+ at many non-interesting places with gcc 3.4.
+
+ * Whitespace cleanup of all source files.
+
+ * The pci.ids file can be stored compressed if zlib is available.
+ Added transparent decompression to lib/names.c, modified update-pciids.sh
+ to keep the file compressed if applicable, updated Makefiles.
+ Based on a patch by Matthew Wilcox, but all the bugs are mine.
+
+ * Makefile, README: Allow installation to be done to a different directory
+ from the one we will eventually be placed in by setting DESTDIR.
+ Patch by Matthew Wilcox.
+
+ * Added .gitignore files.
+
+ * Makefile (clean): Clean *.orig, too.
+
+ * Cleaned up usage of `char' and `byte'.
+
+ * lib/header.h: PCI_CLASS_DOCKING_OTHER should be 0x0a80, not 0x0a01.
+
+ * lib/header.h: Added PCI_CLASS_xxx constants for all classes currently
+ defined in the pci.ids file.
+
+2006-08-01 Martin Mares <mj@ucw.cz>
+
+ * lib/i386-io-hurd.h: Fixed a silly typo.
+
+2006-07-30 Martin Mares <mj@ucw.cz>
+
+ * lib/Makefile: Added a missing rule for obsd-device.o.
+
+ * lspci.c, lib/header.h: Added support for MSI per-vector masking.
+ Contributed by Petr Vandrovec.
+
+ * lspci.c, lib/header.h: Added support for the `bridge subsystem ID'
+ capability. Contributed by Petr Vandrovec.
+
+ * lspci.c (show_htype1): Fixed bug in printing of 64-bit prefetchable
+ memory windows. Fix by Petr Vandrovec.
+
+ * maint/release.pm: Exclude .git directory from releases.
+
+ * lib/i386-ports.c, lib/i386-io-*: Report failures during port access
+ initialization by a->warn() instead of calling printf() or perror()
+ directly.
+
+ * lib/i386-ports.c, lib/i386-io-*: Moved the logic which keeps track of
+ the port access state to generic code.
+
+ * lib/i386-io-hurd.h: Ask the kernel for I/O port access appropriately.
+ Contributed by Thomas Schwinge and Samuel Thibault.
+
+ * lib/i386-ports.c: Define _GNU_SOURCE, it's needed by the Hurd module.
+
+ * lib/header.h: Whitespace cleanups.
+
+ * lib/i386-io-windows.h: Fixed indentation and spelling.
+
+ * README.Windows: Mention that WinIO.dll is needed and where to get it.
+
+2006-06-27 Martin Mares <mj@ucw.cz>
+
+ * lib/Makefile, Makefile: Added rules for building and cleaning the example.
+
+ * lib/example.c: Show how to use PCI_FILL_CLASS and used another register
+ for demonstrating the config space accesses. The example is still very
+ incomplete, though.
+
+ * lib/pci.h, lib/generic.c: Added PCI_FILL_CLASS.
+
+ * lib/sysfs.c: Fetch device ID and class from sysfs, because they can
+ be modified by kernel fixups.
+
+ * lspci.c: Use PCI_FILL_CLASS. Thanks to Matthew Willcox for the patch.
+
+2006-06-03 Martin Mares <mj@ucw.cz>
+
+ * lspci.c: Introduced the -nn switch. Thanks to David N. Welton
+ for the idea.
+
+ * lib/names.c (pci_lookup_name): Introduced PCI_LOOKUP_MIXED and
+ cleaned up the name selection code.
+
+ * lib/names.c (pci_lookup_name): If PCI_LOOKUP_NO_NUMBERS is given,
+ pci_access->numeric_ids is ignored.
+
+ * lib/names.c (pci_lookup_name): When class is identified and
+ subclass isn't, display class name and subclass number.
+
+2006-05-31 Martin Mares <mj@ucw.cz>
+
+ * setpci.c (main): Don't crash when an invalid width is specified.
+
+ * lspci.c, setpci.c, common.c: die() now uses the right program
+ name when printing an error message.
+
+2006-05-19 Martin Mares <mj@ucw.cz>
+
+ * README: Mention the public GIT tree.
+
+ * README: Updated the list of ports.
+
+2006-05-10 Martin Mares <mj@ucw.cz>
+
+ * lib/configure, lib/fbsd-device.c: Added support for GNU/kFreeBSD.
+ Thanks to Petr Salinger for the patch.
+
+2006-05-05 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.3.
+
+ * lspci.c (scan_device): The -D switch didn't work as intended
+ in -m mode.
+
+2006-05-05 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.2.
+
+ * pci.ids: Updated to the current database snapshot.
+
+ * lib/obsd-device.c (and other files in lib/*): Added OpenBSD
+ interface by Matthieu Herrb <matthieu.herrb@laas.fr>, based on
+ the existing FreeBSD interface.
+
+ * Moved pciutils to a GIT repository, which now contains merged
+ history from both CVS and Arch. Good bye, TLA!
+
+2006-03-21 Martin Mares <mj@ucw.cz>
+
+ * lspci.c (show_slot_name): Avoid the previous changes in default
+ display of domain name when in machine-readable mode. However, `-D'
+ forces domain display even there.
+
+ * lspci.man: Added a warning on -m being the only format, which is
+ guaranteed to be stable between lspci versions.
+
+2006-03-13 Martin Mares <mj@ucw.cz>
+
+ * lspci.man: Documented the -D switch.
+
+ * lspci.c (show_slot_name, scan_device): If there are multiple PCI
+ domains or if the `-D' switch is used, show the domain number for
+ all devices.
+
+ * lspci.c (show_verbose): Report cache line size in bytes.
+
+ * update-pciids.sh: Use curl if available. Patch by Matthew Wilcox.
+
+2006-01-04 Martin Mares <mj@ucw.cz>
+
+ * lspci.c (show_express_link): Fixed decoding of link status register.
+ Thanks to Roland Dreier for his report.
+
+2005-12-12 Martin Mares <mj@ucw.cz>
+
+ * lib/nbsd-libpci.c: If libpci is used by an ordinary user, allow
+ at least read-only access. Patch by Pavel Celeda <celeda@liberouter.org>.
+
+ * Makefile: Corrected library path on NetBSD.
+
+2005-11-26 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.1.
+
+ * lspci.c (show_machine): Subsystem vendors were printed incorrectly
+ in machine-readable modes. Thanks to Pavel Celeda for a bug report.
+
+2005-10-11 Martin Mares <mj@ucw.cz>
+
+ * lspci.c (new_bus): Fixed a memory leak. Thanks to Paul Sangree for reporting it.
+
+2005-09-21 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.2.0.
+
+ * pci.ids: Updated copyright header.
+
+ * lib/sysfs.c (sysfs_get_resources): Removed warning about unsupported
+ 64-bit addresses, they are now always supported.
+
+ * lspci.c (show_bases): Corrected printing of 64-bit addresses
+ in bus-centric mode.
+
+ * lib/configure: Enable 64-bit addresses on all Linux systems.
+
+ * lib/types.h: Don't pad 64-bit addresses to 16 xigits, only to 8 if they
+ are shorter.
+
+2005-09-11 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.99-test11.
+
+ * lspci.c: Removed unnecessary trailing zeros in pci_lookup_name() calls.
+
+2005-09-10 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.99-test10.
+
+ * pci.ids: Synchronized with the current database snapshot.
+
+ * update-pciids.sh: Changed the default URL for downloading pci.ids
+ to http://pciids.sourceforge.net/v2.2/pci.ids.
+
+ * lib/pci.h (PCI_LIB_VERSION): Added version identifier.
+
+ * lib/names.c: Rewritten the name database module almost from scratch.
+ Everything is much cleaner and there are hopefully no more memory leaks;
+ pci_lookup_name() now uses varargs in a backward compatible fashion.
+ Introduced PCI_LOOKUP_NO_NUMBERS.
+
+ The new code supports subsystem entries not tied to a specific device.
+ I had to extend the format of pci.ids in order to support it, so I have
+ extended the idea of the "C" (class) blocks and introduced "S" blocks
+ for subsystems. To avoid doing more incompatible changes in the future,
+ the parser skips unknown single-letter blocks without reporting errors.
+
+2005-08-23 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.99-test9.
+
+ * Makefile (OPT): Removed -fomit-frame-pointer, it's default in recent
+ gcc versions when optimizing anyway.
+
+ * Made the path to pci.ids customizable and independent on the SHAREDIR.
+ Just override IDSDIR in the top-level Makefile.
+
+ * pci.ids: Synchronized with the current database snapshot.
+
+ * lspci.man, setpci.man: Improved the man pages. Documented all access
+ methods and which operations are privileged.
+
+ * lspci.c: Another rewrite of config register caching, now also including
+ lots of internal checks. It should be now perfectly able to cope with
+ portions of the configuration space being inaccessible, for example
+ due to insufficient access rights.
+
+ * lspci.c (show_pcix_nobridge, show_pcix_bridge): Cleaned up dumping of PCI-X
+ capabilities. Includes partial support for PCI-X 2.0 (probably incomplete
+ as I haven't seen the spec).
+
+ * lspci.c: Quell warnings about unused parameters.
+
+ * lspci.c: Removed C++ comments.
+
+ * lib/header.h: Merged definitions of extended capabilities and some new
+ PCI-X capability bits from linux-2.6.11/include/pci.h.
+
+ * lspci.c (show_caps): Try to scan extended capabilities only if the
+ device has either PCI-X or PCI Express capability in its normal capability
+ list.
+
+ * lib/dump.c (dump_init): Reading of dumps works again. The dump reader
+ now also remembers how much data it has read and refuses attempts to
+ access more than that.
+
+ * setpci.man, lspci.c, README: prefer spelling "buses" over "busses".
+
+ * lspci.c: If alloca() is not available, use xmalloc(), not malloc().
+
+ * lib/configure: Added x86_64 on Linux.
+
+2005-08-22 Martin Mares <mj@ucw.cz>
+
+ * lib/filter.c (pci_filter_parse_slot): Fixed parsing of domain filters.
+ Thanks to Matthew Wilcox for bug report.
+
+ * lspci.c: Corrected spelling of "Hz" (it was "hz" at several places).
+ Thanks to Krzysztof Oledzki for pointing that out.
+
+2004-08-19 Martin Mares <mj@ucw.cz>
+
+ * pciutils.spec (%attr): Setting attributes for /sbin/* is an anachronism,
+ because pciutils by default install to /usr/sbin. Update.
+
+2004-08-13 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.99-test8.
+
+ * lib/types.h, lib/pci.h, lib/sysdep.h: `byte' and `word' are
+ no longer exported to the outside world.
+
+ * README.Windows: Updated.
+
+ * maint/release: Substitute version number in win32/config.h.
+
+ * win32/config.h: Added.
+
+ * lib/sysdep.h (bzero, strcasecmp): are macros on Windows.
+
+ * compat/getopt.[ch]: Added copies of getopt.[ch] from the GNU
+ C library for use on systems where the default libraries lack
+ proper getopt. Currently used by the Windows port.
+
+ * lib/sysdep.h, lib/types.h: Updates of the Windows port from
+ Alexander Stock.
+
+ * lib/types.h: If PCI_HAVE_Uxx_TYPES is defined, libpci doesn't define
+ its own u8, u16, u32, byte and word types and uses what the user
+ has supplied instead. With this change, all namespace clashes should
+ be gone.
+
+ * Makefile, lib/Makefile: Updated dependencies.
+
+ * pciutils.h: Include lib/sysdep.h and move NONRET et al. there.
+
+ * lib/sysdep.h: No need to include <sys/types.h> on FreeBSD, because
+ it is included unconditionally in lib/types.h.
+
+ * Moved system-dependent stuff from lib/internal.h to lib/sysdep.h,
+ which is also used by the utilities. Also moved type declarations
+ from lib/pci.h to lib/types.h.
+
+ * All files: Prepend a "PCI_" prefix in front of all configuration
+ defines to avoid namespace clashes. CAVEAT: If there is any libpci
+ application using the (undocumented) defines, it has to be updated.
+
+ * lib/Makefile: Killed HAVE_OWN_HEADER_H, since we stopped sharing
+ headers with the kernel a couple of years ago.
+
+ * lib/sysfs.c (sysfs_get_resources): We have 7 resources, not 6.
+
+ * lspci.c (show_rom): Use the same logic for printing disabled
+ or unassigned ROM's as we do in show_bases() for the other BAR's.
+
+ * lib/generic.c (pci_generic_fill_info): Better reaction to
+ invalid 64-bit addresses. Also d->hdrtype should not include
+ bit 7, which caused mysterious errors on multi-function devices.
+
+ * lib/generic.c (pci_generic_fill_info): Fill in base addresses
+ even if the regions are known to be disabled. It is the client's
+ job to interpret them. (And it is not a trivial job if you want
+ to do it correctly, since you need to check I/O and memory enables
+ on all upstream bridges, too.) However, it could be interesting to
+ introduce functions for interpreting the addresses and even for
+ mapping the regions and doing I/O on them.
+
+2004-07-30 Martin Mares <mj@ucw.cz>
+
+ * lspci.c: HyperTransport improvements from Maciej.
+
+2004-07-11 Martin Mares <mj@ucw.cz>
+
+ * lib/sysfs.c (sysfs_get_resources): Arguments now correspond
+ to the format string. [Patch by Bill Nottingham]
+
+2004-07-05 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.99-test7.
+
+ * lspci.c (config_fetch): Wanted to merge Matthew's bug fix, but
+ ended up with rewriting the fetching mechanism to be fully dynamic,
+ but avoid reading config space registers not explicitly requested.
+
+2004-06-29 Matthew Wilcox <willy@debian.org>
+
+ * lspci.c: More work on PCI Express dumping.
+
+ * lib/header.h: Updated PCI Express capability definitions.
+
+ * lib/proc.c (proc_read): Removed bogus warning.
+
+ * common.c (xrealloc): Introduced.
+
+ * lspci.man: Added -xxxx.
+
+2004-06-27 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.99-test6.
+
+ * lspci.c (show_msix), lib/header.h: Added dumping of MSI-X cap.
+ Patch by Roland Dreier <roland@topspin.com>, cleaned up by me.
+
+ * lspci.c (show_pcix_nobridge, show_pcix_bridge): Handle config_fetch()
+ failures.
+
+ * lib/header.h: Added PCI Express extended capabilities. Again by Matthew.
+
+ * lspci.c (show_express): Added dumping of PCI Express cap.
+ Patch by Matthew Wilcox.
+
+ * lib/header.h: Added a list of PCI 3.0 capabilities and also details
+ on PCI Express caps. Patch by Matthew Wilcox <willy@debian.org>.
+
+ * lspci.c (check_root): Gone. No explicit checks for root are needed,
+ report correct errors reported by the libpci instead.
+
+ * lspci.c: Added dumping of the extended config space on "-xxxx".
+ Better caching of config registers.
+
+ * setpci.c (main): Allow access to whole 4096 bytes of the config space.
+
+ * lib/sysfs.c, lib/proc.c: Don't print error messages on short reads,
+ just return the appropriate error code.
+
+ * lib: Added support for extended (4096-byte) configuration space,
+ currently implemented only in Linux proc and sysfs access methods
+ and of course in the dump reader.
+
+2004-05-29 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.99-test5.
+
+ * lib/pci.h: Windows don't have the standard u_int* types.
+
+ * lib/internal.h: <sys/param.h> required on Windows for endianity
+ macros.
+
+ * lib/i386-ports.c: Connected i386-io-windows.h.
+
+ * lspci.c (check_root): geteuid() is not available on Windows.
+
+ * lib/i386-io-windows.h: Added Windows port contributed by Alexander
+ Stock <stock.alexander@gmx.de>.
+
+ * lib/configure: Hopefully fixed SunOS port broken by various
+ changes to the configure script.
+
+ * Makefile, lib/configure: Cross-compilation support, patch by Maciej.
+
+2004-05-28 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.99-test4.
+
+ * lspci.c (show_verbose): Header type 1 is probably legal for all
+ types of bridges, not only for PCI-to-PCI bridges.
+
+ * lspci.c (format_agp_rate): Write "x16", not "x@".
+ (show_agp): rate[] could overflow.
+ Bugs reported by Jakub Bogusz <qboosh@pld-linux.org>.
+
+ * lspci.c (show_ht_*): Show HyperTransport capability with all its
+ details. Once again code by Maciej simplified (i.e., possibly broken)
+ by me.
+
+ * lib/header.h: Added declarations of HyperTransport capability.
+ Again thanks to Maciej.
+
+ * lspci.c: Decode all bits of the secondary status word in type 1 headers.
+ Thanks to Maciej W. Rozycki <macro@ds2.pg.gda.pl> for the patch.
+
+2003-12-27 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.99-test3.
+
+ * lspci.man, setpci.man: Document domains and correct spelling.
+
+ * lib/dump.c (dump_init): Added ability to read domain numbers.
+
+ * lspci.c: Devices in domains different from 0 have their slot number
+ printed as "<domain>:<bus>:<slot>.<func>". Tree view supports domains
+ as well.
+
+ * lib/filter.c: Slot filters understand domains.
+
+ * lib/generic.c: Mention the domain in slot numbers in all error messages.
+
+ * lib/internal.h: The #ifdef for Linux <asm/byteorder.h> was wrong.
+
+ * lib/access.c (pci_get_dev): Added support for domains.
+
+ * lib/sysfs.c (sysfs_scan): Read vendor and device ID from the config
+ registers (or to be precise, leave it for the generic parts of the pcilib
+ to do so) instead of reading them from the sysfs. It's faster this way.
+
+ * lspci.c (show_pcix): Don't touch pci_dev->hdrtype, it's an internal
+ variable. Better read it from the config registers (it's cached anyway).
+
+ * lib/sysfs.c (sysfs_scan), lib/proc.c (proc_scan): Don't read the hdrtype.
+ lib/generic.c (pci_generic_fill_info): If hdrtype is -1 (unset), read it.
+ Saves lots of unnecessary file accesses.
+
+ * lib/pci.h (PCIADDR_PORT_FMT): Use %llx instead of %Lx, because the latter
+ is not supported by all C libraries.
+
+ * Makefile: Always enter the lib directory (remember that we don't have
+ full dependecies for the library in the top-level Makefile; hmmm, another
+ thing to rewrite some day).
+
+ * lib/sysfs.c: Added Linux sysfs access method based on the patch
+ written by Matthew Wilcox <willy@fc.hp.com>.
+
+ * lib/proc.c: Renamed the access method name from "/proc/bus/pci" to "Linux-proc".
+
+ * lib/pread.h: The hacks to support pread on various versions
+ of Linux libc moved there.
+
+ * lib/proc.c (proc_setup): The return value of snprintf() varies
+ between glibc versions, so we need to check both for a negative
+ values and for too large values.
+
+ * Removed last few references to the "Linux PCI Utilities", the
+ package is pretty cross-platform now :)
+
+2003-12-27 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.99-test2.
+
+ * README, pciutils.lsm, pciutils.spec: Use @VERSION@ to make the
+ release scripts insert the current version. "make release" is gone.
+
+ * maint/release, maint/release.pm: Added a new system of scripts for
+ making releases including inter-version diffs etc.
+
+ * Makefile: Cleaned up.
+
+ * lib/fbsd-device.c: I patched another copy of this file by mistake,
+ this time the version checks should be right.
+
+2003-12-27 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.99-test1.
+
+ * pciutils.h, common.c, lspci.man, setpci.man, lib/internal.h:
+ Remove shadows of the syscall access method which was never
+ implemented.
+
+ * update-pciids.sh: Try to preserve permissions of the old file
+ if chmod supports --reference. Should close Debian Bug #223740.
+
+ * lib/proc.c (proc_setup): Increased path name length limit to 1024.
+ Thanks for Redhat and Mandrake for inspiration.
+
+ * lib/configure: Recognize ppc and ppc64, both have 64-bit addresses.
+ Grabbed from Redhat (Fedora) patches.
+
+2003-12-27 Martin Mares <mj@ucw.cz>
+
+ Merged bug fixes from Debian patches:
+
+ * lspci.c (show_verbose): "Cache Line Size" should be capitalized.
+
+ * lspci.c (show_pcix_nobridge): Added a missing newline.
+
+ * lib/proc.c (proc_scan): When reading the header type, don't
+ forget to clear the topmost bit indicating that the device has
+ multiple functions.
+
+2003-12-27 Martin Mares <mj@ucw.cz>
+
+ Updated the FreeBSD port. Thanks to Samy Al Bahra <samy@kerneled.com>
+ for the patches:
+
+ * lib/Makefile: Add ${FREEBSD_SYS} to the include path if it's defined.
+ * lib/fbsd-device.c: Select the right set of system includes according
+ to __FreeBSD_version.
+
+2003-12-27 Martin Mares <mj@ucw.cz>
+
+ Merged support for Solaris on i386 by Bill Moore <billm@eng.sun.com>
+ and cleaned up:
+
+ * lib/configure: Recognize SunOS.
+ * lib/internal.h: Learn how to recognize byte order on SunOS.
+ * lib/i386-ports.c: Split OS-dependent I/O port access from i386-ports.c.
+ * lib/i386-io-linux.h: Linux specific part.
+ * lib/i386-io-hurd.h: GNU/Hurd specific part.
+ * lib/i386-io-sunos.h: SunOS specific part.
+
+2003-12-26 Martin Mares <mj@ucw.cz>
+
+ * lib/header.h (PCI_*_MASK): Cast to pciaddr_t explicitly.
+
+ * lib/pci.h: Types declared in <sys/types.h> should be usable on all
+ platforms we currently support, so kill the forest of #ifdef's and
+ use them in all cases.
+
+ * lib/pci.h: Use ULONG_MASK to decide whether we should use long
+ or long long to represent a 64-bit address. Killed HAVE_LONG_ADDRESS.
+ Define format strings for addresses, port numbers and IRQ numbers
+ directly in pci.h.
+
+ * lib/proc.c (proc_scan): Use PCIADDR_T_FMT for scanf'ing addresses.
+
+2003-12-26 Marco Gerards <metgerards@student.han.nl>
+
+ Added support for the GNU Hurd (cleaned up by Martin Mares):
+
+ * lib/configure [GNU]: Use the i386 ports for configuration access.
+ * lib/i386-ports.c: Don't call iopl() on the Hurd.
+ * lib/pci.h [OS_GNU]: Include <sys/types.h> and use it for defining
+ u8 to u32.
+
+2003-12-26 Martin Mares <mj@ucw.cz>
+
+ * lspci.c (show_pcix_bridge, show_pcix_nobridge): Don't forget to call
+ config_fetch() to ensure that the registers have been read. Thanks to
+ Bill Wood <bill.wood@hp.com> for the patch.
+
+ * lspci.c: Ensure that failure of config_fetch() is handled correctly
+ at all places.
+
+ * lspci.man: There was one more explicit reference to /usr/share/pci.ids.
+ Changed to @SHAREDIR@. Patch from Maciej W. Rozycki <macro@ds2.pg.gda.pl>.
+
+ * setpci.c (main): Better error messages.
+
+ * setpci.c (ex_op): The demo mode should disable only writing, not reading.
+
+ * setpci.man: The documentation was inconsistent on what should -D do.
+ Document the new behaviour.
+
+ * pciutils.h, common.c, setpci.c: Introduced a NONRET macro encapsulating
+ the GCC specific __attribute__((noreturn)) and killed the hack with
+ redefining __attribute__ on non-GCC compilers.
+
+ * Makefile: Added missing dependencies. Parallel builds work now.
+ Problem reported by Andreas Haumer <andreas@xss.co.at>, but I chose
+ a different fix.
+
+ * Makefile (MANDIR): Use `:=' instead of `=' to avoid executing the shell
+ command every time $(MANDIR) is referenced.
+
+ * lspci.c (main): The error message for `lspci -s' incorrectly mentioned
+ a `-f' switch. Reported by Steve Finney <Steve.Finney@SpirentCom.COM>.
+
+ * lib/generic.c: Removed memory leak in pci_generic_bus_scan().
+ Reported by Gary Parnes <gary_parnes@terago.com>.
+
+ * Replaced obsolete syntax of __attribute__((unused)) in the middle of
+ parameter declarations (which is no longer supported by GCC 3.1) by the
+ current syntax (attribute at the end). Thanks to pixel@mandrakesoft.com
+ for reporting this problem.
+
+ * Removed CVS $Id$ tags from all files.
+
+ * Makefile: Added some more warnings.
+
+ * setpci.c: Cleaned up mask/value code.
+
+2003-12-08 Thayne Harbaugh <tharbaugh@lnxi.com>
+
+ * setpci.c: Individual bits to be set can be specified as <value>:<mask>.
+
+2003-11-29 Martin Mares <mj@ucw.cz>
+
+ * Imported the pciutils sources to my Arch repository. Good-bye, CVS.
+
+2003-01-04 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.11.
+
+ * Makefile: Changed configuration of installation directories --
+ all paths are now set at the top of the Makefile instead of being
+ scattered between the installation rules. The default installation
+ now goes always to /usr/local regardless of the OS as most distributions
+ already contain some version of pciutils and we don't want custom
+ installations to interfere with the default ones.
+
+ * Makefile: Removed a couple of ancient install hacks: we no longer
+ try to avoid overwriting a newer pci.ids file (users are now expected
+ to use update-ids) and we don't try to remove /etc/pci.ids (a long time
+ has passed since the last version which used it).
+
+ * Makefile: Paths to pci.ids in man pages automatically get the right path.
+
+ * Added the update-ids utility.
+
+ * lib: Removed partially implemented "syscall" access method which will
+ probably never be needed.
+
+2002-12-27 Martin Mares <mj@ucw.cz>
+
+ * lib/nbsd-libpci.c: Cleaned up and hopefully made it endian safe.
+
+ * lib/generic.c (pci_generic_scan_bus): Added work-around for devices with
+ discontiguous numbering of functions. This is already present in the Linux
+ kernel for several years, but I forgot to update pciutils as well.
+
+2002-12-26 Martin Mares <mj@ucw.cz>
+
+ * lib/header.h, lspci.c: Dump AGP3 flags and speeds.
+
+ * lib/pci.h, Makefile: Removed HAVE_OWN_HEADER_H. Always use our own header,
+ there is no reason to prefer the kernel version.
+
+ * lib/proc.c (proc_scan): Don't forget to initialize hdrtype.
+
+ * Added preliminary version of NetBSD support by Quentin Garnier
+ <netbsd@quatriemek.com>.
+
+2002-04-06 Martin Mares <mj@ucw.cz>
+
+ * lspci.c: Mention "-xxx" in the help.
+
+2002-03-30 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.10.
+
+ * Removed pci.ids from the CVS as they are now maintained separately.
+ They are still included in the tarball, but if you are building pciutils
+ from CVS sources or you want to get a newer ID file than the one distributed,
+ just use "make update-ids" to download the most recent snapshot from
+ pciids.sf.net.
+
+ * Makefile, README: Updated accordingly.
+
+ * Makefile: Added a couple of maintenance targets.
+
+ * maint/*: Maintainer's utilities now reside here (present only in CVS,
+ not in the tarball).
+
+ * lib/names.c (parse_name_list): End-of-line comments are no longer
+ supported. Hashes are now perfectly valid in all names and they start
+ a comment only at the start of the line.
+
+2002-03-26 Martin Mares <mj@ucw.cz>
+
+ * README: Rewritten.
+
+ * Makefile: When the currently installed pci.ids file is newer than
+ the version to be installed, don't overwrite it. Suggested by
+ Jean Delvare <khali@linux-fr.org>.
+
+2002-03-24 Martin Mares <mj@ucw.cz>
+
+ * lspci.c (show_pcix_bridge): Added PCI-X capability display.
+ Contributed by Jeff Garzik <jgarzik@mandrakesoft.com>.
+
+ * lib/header.h: Added PCI-X stuff. Again by Jeff.
+
+ * Makefile (CFLAGS): -Werror is gone.
+
+ * lspci.c (format_agp_rate): Fixed AGP rate reporting.
+
+ * lib/filter.c (pci_filter_parse_slot): Allow bus 0xff, slot 0x1f and
+ function 7.
+
+ * lib/names.c (pci_lookup_name): When printing unknown subsystem vendor
+ or device hexadecimally, don't confuse it with chip vendor/device ID.
+ First reported by Marc Boucher <marc@mbsi.ca>.
+
+2001-11-04 Martin Mares <mj@ucw.cz>
+
+ * Released as 2.1.9.
+
+ * pci.ids: Synced with the PCI ID Repository at SourceForge
+ (http://pciids.sourceforge.net/).
+
+2000-08-25 Martin Mares <mj@albireo.ucw.cz>
+
+ * pci.ids: Updated ID's, synced with kernel 2.4.0-test7.
+
+2000-06-13 Martin Mares <mj@albireo.ucw.cz>
+
+ * Makefile (uninstall): Fixed.
+
+ * pci.ids: ID updates.
+
+2000-05-20 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as 2.1.8.
+
+ * pci.ids: ID updates.
+
+ * lspci.c (show_verbose): Min/max latency is now printed in nanoseconds.
+
+2000-05-04 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_verbose): If the header type doesn't match device
+ class, just print a warning and still use the header type, assuming
+ bogus class info.
+
+2000-05-01 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_pm): Updated according to PCI PM specs 1.1.
+
+ * pci.ids: Updated Contemporary Control ARCnet card entries.
+
+ * pci.ids: Synchronized class list with latest PCI SIG documents.
+
+2000-04-29 Martin Mares <mj@albireo.ucw.cz>
+
+ * lib/names.c (pci_lookup_name): Fixed the cheat.
+
+ * lib/internal.h: Moved UNUSED/inline hacks above all other declarations.
+
+ * pci.ids: Various ID updates.
+
+2000-04-21 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as 2.1.7.
+
+ * pciutils.spec: Added German description.
+
+ * lib/names.c (pci_lookup_name): Added a cheat for case that subsystem ID's
+ are the same as device ID and just output subsystem name according to
+ device name.
+
+ * lib/proc.c: Use UNUSED instead of __attribute__((unused)).
+
+ * lib/pci.h: Added the correct typedefs for AIX.
+
+ * lib/generic.c (pci_generic_scan_bus): Export.
+
+ * lib/configure: Detect AIX. Use "echo '...\c'" instead of
+ "echo -n" if the shell isn't bash.
+
+ * lspci.c: Avoid using alloca() if not compiled by GCC.
+ (insert_dev): Avoid returning a void value.
+
+ * Makefile: Choose which install utility to use according to
+ OS type. Also use `-o' instead of `-or' in find arguments.
+ Part of the AIX port.
+
+ * lib/aix-device.c: Added AIX low-level interface. Contributed
+ by Dave Johnson <ddj@brown.edu>, thanks a lot!
+
+ * pci.ids: Few new ID's.
+
+ * pciutils.h, lib/internal.h: Redefine __attribute__ and inline
+ when not compiled by GCC.
+
+2000-04-17 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as 2.1.6.
+
+ * pci.ids: Added a large batch of ID's contributed by Gunther
+ Mayer <gunther.mayer@braunschweig.netsurf.de> and synced the
+ list with the 2.3.99pre6 kernel.
+
+Thu Mar 9 13:11:39 2000 Martin Mares <mj@albireo.ucw.cz>
+
+ * lib/example.c: Added a simple example of how to use
+ the library.
+
+ * lspci.man, setpci.man: Revealed --version. Well spotted
+ by Adam Sulmicki.
+
+ * pci.ids: Added lots of new ID's and synced with 2.3.50.
+
+Tue Feb 15 00:16:21 2000 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as 2.1.5.
+
+ * pciutils.spec: Updated spec file from Andreas Jaeger. Now using
+ %{_mandir} to find the right location to install manual pages to.
+
+ * pci.ids: New ID's.
+
+ * setpci.c (main): Don't crash when `-s' or `-d' is given with
+ no argument.
+
+Mon Jan 24 20:04:11 2000 Andreas Jaeger <aj@suse.de>
+
+ * lib/i386-ports.c: Include <asm/io.h> only on systems without
+ glibc.
+
+Mon Jan 24 11:24:43 2000 Martin Mares <mj@albireo.ucw.cz>
+
+ * Makefile: Modified to work with the Linux FHS brain-damaged idea
+ of putting man pages to /usr/share/man. Now we choose either /usr/man
+ or /usr/share/man depending on which one exists.
+
+Sun Jan 23 10:52:34 2000 Martin Mares <mj@albireo.ucw.cz>
+
+ * pci.ids: Synced with Linux 2.3.40.
+
+ * Released as version 2.1.4.
+
+Thu Jan 20 11:08:32 2000 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (scan_device): Fixed bug in reading of cardbus extensions.
+
+ * lib/proc.c: pread/pwrite fixed again, this time on libc5 :(
+
+ * lspci.c (format_agp_rate): Better formatting of AGP rates.
+
+ * pci.ids: New ID's.
+
+ * lib/configure: Added configuration for ia64 (the same as for Alpha).
+ Patch from Stephane Eranian <eranian@cello.hpl.hp.com>.
+
+Thu Jan 13 23:01:52 2000 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as version 2.1.3.
+
+ * pci.ids: New ID's.
+
+ * lspci.c: Alpha IO_FORMAT fix by Andrea Arcangeli.
+
+ * lib/access.c: Corrected order of access methods -- it's wonderful how
+ long could such a bug remain unspotted. Thanks go to Andreas Schockenhoff.
+
+Sat Dec 11 23:34:48 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as version 2.1.2.
+
+ * lib/names.c (pci_lookup_name): Fixed printing of unknown subsystem ID's.
+
+Sat Dec 4 13:11:03 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as version 2.1.1.
+
+ * pci.ids: Several new ID's.
+
+ * setpci.c (exec_op): Don't forget to increment address after writing
+ single value, so that `30.b=12,34,56,78' works as expected. Reported
+ by Petr Soucek <petr@ryston.cz>.
+
+Wed Nov 3 10:24:38 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_terse): If prog-if is zero, but it's present in the
+ ID list, show it.
+
+Sat Oct 30 11:06:35 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as version 2.1.
+
+ * pci.ids: Synced to devlist.h in 2.3.24 kernel. Merged in
+ lots of contributed entries.
+
+Thu Oct 14 10:40:12 1999 Dave Jones <dave@powertweak.com>
+
+ * pci.ids: Added lots of subsystem definitions.
+
+Sat Oct 9 14:32:28 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * setpci.man: Better example.
+
+ * lspci.c: Resolve prog-if names.
+
+ * lib/names.c: Adapted to new pci.ids syntax.
+
+ * pci.ids: Reorganized the pci.ids file. Subsystems are listed
+ under devices, classes can optionally contain prog-if information.
+ New ID's, as usually.
+
+Wed Sep 22 09:45:24 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * pci.ids: New ID's. As usually.
+
+ * lspci.c (show_htype1, show_htype2): Don't show `closed' bridge windows
+ unless we're vvvery verbose.
+
+Mon Sep 20 11:22:54 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_htype2): Don't forget a TAB before the "I/O window" line.
+
+Tue Sep 14 09:31:01 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * pci.ids: New ID's. Again.
+
+Thu Aug 5 17:45:42 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_size): Don't show size if it's zero (usually
+ due to bus-centric mode being enabled).
+
+Tue Jul 20 13:25:09 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lib/pci.h: Types are OS dependent.
+
+ * lib/internal.h: Byte order hacks are OS dependent.
+
+ * lib/configure: Recognize FreeBSD. Also set OS_XXX according to the OS.
+
+ * lib/Makefile, lib/access.c: Added fbsd-device target.
+
+ * pci.ids: Added an entry for PLX 9080 bridges with subsystem ID
+ incorrectly set to device ID.
+
+ * README: Added a note that we support FreeBSD.
+
+ * Makefile (PREFIX, ROOT): Set it depending on the OS.
+ (%.8): Grrr, BSD date is not able to convert date formats the same way
+ as GNU date does. Use sed instead.
+ (install): Use `-c' when calling install.
+
+ * lib/fbsd-device.c: Added FreeBSD /dev/pci access module contributed
+ by Jari Kirma <kirma@cs.hut.fi>.
+
+ * lib/proc.c: Rewrote the pread/pwrite things once again. Use pread
+ and pwrite only when we are certain it's safe (i.e., glibc 2.1
+ on all architectures or any libc on a i386 where we really know
+ how to use syscalls directly). In all other cases, emulate it
+ with lseek/read/write.
+
+ * pci.ids: Some more IDs.
+
+Mon Jul 19 14:10:36 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * pci.ids: Added IDs of parallel port controller cards as sent
+ by Tim Waugh <tim@cyberelk.demon.co.uk>.
+
+Wed Jul 7 00:55:48 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lib/proc.c (proc_scan): HAVE_LONG_ADDRESS instead of HAVE_64BIT_ADDRESS.
+
+ * lspci.c: ADDR_FORMAT now depends on both HAVE_64BIT_ADDRESS and
+ HAVE_LONG_ADDRESS.
+
+ * lib/configure: HAVE_64BIT_ADDRESS now doesn't imply that the addresses
+ are represented as long long. Introduced a new flag HAVE_LONG_ADDRESS
+ to indicate this. Both Sparc architectures now use both 64BIT_ADDRESS
+ and LONG_ADDRESS since they have 32-bit userland, but don't set LONG_ADDRESS
+ on Alpha.
+
+ * lspci.c (show_msi): Added dumping of the MSI capability.
+ (show_slotid): The same for SlotID capability.
+ (show_caps): Seperated capability dumping, because it should
+ be used for both htype0 and htype1. Even PCI 2.2 doesn't mention
+ layout of htype2, so I'm a bit unsure about it wrt capabilities
+ -- they at least have to live somewhere else since address 0x34
+ is already defined differently in htype2.
+
+ * lib/header.h (PCI_STATUS_UDF): Marked as obsolete (PCI 2.2).
+ (PCI_BASE_ADDRESS_MEM_TYPE_1M): Ditto.
+ (PCI_CAP_ID_*): Added some new capabilities defined in PCI 2.2.
+
+ * lspci.c (show_htype0): Mask out lowest 2 bits from all capability pointers
+ (required by the PCI 2.2 specs).
+
+Mon Jul 5 12:45:19 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_size): Added new function for dumping of region sizes.
+ (show_rom): Added. Now correctly dumps unassigned ROM addresses, disabled
+ ROMs et cetera.
+
+ * lib/pci.h (struct pci_dev): known_fields moved to the public part
+ of the structure.
+
+ * Added support for region sizes. Needs support in the kernel, because
+ sizes have to be scanned before drivers initialize yourself. pci_fill_info()
+ now returns a bitmask of what fields were really read.
+
+Mon Jun 28 18:37:51 1999 Dave Jones <dave@powertweak.com>
+
+ * Makefile:
+ Added `uninstall' target - removes all traces of pciutils.
+ * pci.ids:
+ - Lots of cleanups in the ATI, S3, Adaptec vendors.
+ - Changed Compaq QVision 1280/p definitions, as it's not possible
+ to determine the revision from the device ID.
+ - Same for the Tseng ET4000.
+ The id's said I had a rev C, when it was actually a rev B.
+ - Removed some unnecessary strings
+ `PCI'. Unless it's an AGP card, it should be obvious that it's PCI.
+ `Ethernet card'. This should be determined from config space.
+ - Lots of other new vendors & devices
+ - Other additional small cleanups.
+
+Mon Jun 21 22:11:10 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lib/names.c (pci_lookup_name): When device ID lookup
+ fails, return hexadecimal device ID instead of vendor ID.
+ Well spotted by Axel Bodemann <Axel.Bodemann@ruhr-uni-bochum.de>,
+ I've just extended the fix to subsystem ID's.
+
+Thu Jun 17 19:48:21 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_agp): Bug fix from Petr Vandrovec
+ <vandrove@vc.cvut.cz>. The command register was displayed
+ incorrectly.
+
+Wed Jun 2 22:42:44 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lib/proc.c (SYS_pread, SYS_pwrite): Use hard-coded
+ numbers if not supplied by the libc.
+
+Wed May 19 13:24:39 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released the whole package as version 2.0.
+
+Fri May 14 22:42:02 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * pci.ids: Added several new ID's contributed by people
+ on the linux-pci list.
+
+Mon Apr 19 15:21:08 1999 Jakub Jelinek <jj@ultra.linux.cz>
+
+ * lspci.c: Display I/O addresses correctly on sparc64.
+ * lib/header.h: Ditto.
+
+ * lib/configure: On sparc set HAVE_64BIT* as well, we want
+ a binary which works on both 32bit and 64bit SPARCs.
+
+Sun Apr 18 21:14:58 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c, lib/proc.c: Alpha compilation fixes from Matthew Jacob
+ <mjacob@feral.com>.
+
+ * pci.ids: A lot of updates from Adam J. Richter <adam@yggdrasil.com>.
+
+Sun Feb 28 22:26:21 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (do_map_bus): Don't dump functions 1--7 if not flagged
+ as a multi-function device, because several single-function devices
+ don't decode the function bits at all.
+
+Sun Feb 14 23:48:22 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Makefile (install): Don't use "-o root -g root" for installation
+ since it breaks on machines where programs are not installed by root.
+ Reported by Richard Gooch <rgooch@atnf.csiro.au>
+
+Tue Feb 9 15:54:39 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_bases): Use new address masking macros and pciaddr_t.
+
+ * lib/pci.h: Using pciaddr_t for bus addresses, which are 32-bit
+ or 64-bit depending on CPU.
+
+ * lib/pci.h (PCI_ADDR_MEM_MASK): Added macros for address masks
+ according to bus address width.
+
+Thu Jan 28 20:54:16 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as 1.99.4.
+
+ * lspci.c: Capability list parser now recognizes both AGP
+ registers and PCI Power Management registers (the latter
+ is mainly guesswork based on DEC/Intel 21153 bridge specs
+ since I don't have the PCI Power Management document).
+
+ * lspci.c: Replaced numerous occurences of (x & flag) ? '+' : '-'
+ by FLAG macro.
+
+ * lspci.c: Added bridge checks to bus mapping code.
+
+Wed Jan 27 14:59:16 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c: Implemented bus mapping mode (-M).
+
+ * lspci.c (scan_devices): Split to scan_devices() and scan_device().
+ (show): Split to show() and show_device().
+
+ * lib/access.c (pci_init): When a->method == PCI_ACCESS_AUTO,
+ set it to the real access method afterwards.
+
+Mon Jan 25 23:46:13 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lib/generic.c (pci_generic_fill_info): If in buscentric mode,
+ don't check PCI_COMMAND for I/O and memory enables.
+
+Mon Jan 25 21:28:49 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Makefile: Added target `release' which substitutes new version
+ number to .spec, .lsm and README. Also rewrote target `dist'.
+
+ * Released as 1.99.3.
+
+Sun Jan 24 22:10:36 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lib/header.h: Until kernel adopts new layout of PCI
+ includes (i.e., separate declaration of header structure,
+ functions and device IDs), which is not going to happen
+ before 2.3, we'll use our own definiton of the header.
+
+ * lspci.c (show_verbose): Display `Cap' flag in device status.
+
+ * lspci.c (show_htype0): Display capability lists whereever
+ available. The only capability name we recognize now is `AGP'.
+ Unfortunately, capabilities are stored in device-dependent
+ portion of the configuration space and are thus available
+ only to root unless you read a dump.
+
+ * lspci.c (scan_devices): Use cache instead of buffering.
+
+ * lib/buffer.c: Removed (obsoleted by the cache).
+
+ * lib/access.c: Added general caching mechanism.
+
+Sat Jan 23 21:30:54 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * pci.ids: Added few devices.
+
+Fri Jan 22 19:29:31 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Version string is now defined in top-level Makefile, exported
+ to the configure script and also substituted to man pages.
+
+ * lspci.c (show_bases): Rewrote displaying of 64-bit addresses.
+ (show_verbose): Rewrote interrupt display logic.
+
+ * lib/i386-ports.c: Include sys/io.h only on glibc systems.
+
+ * lib/configure: Rewrote detection of Linux versions. Now it
+ works on 2.0 kernels (only with direct/dump access, of course).
+
+ * lib/internal.h: New bytesex macros using <asm/byteorder.h>
+ whenever available.
+
+ * lib/proc.c (proc_read, proc_write): Distinguish between short
+ read/write and real errors.
+
+ * lspci.c (show_htype{0,1}): Always use d->dev->rom_base_addr since
+ libpci respects buscentric mode automatically.
+
+ * lspci.c (show_hex_dump): For CardBus bridges, print out 128
+ bytes of header (the whole standard part).
+
+ * common.c: pcilib options are now all uppercase. Also moved
+ PCI access debugging option here.
+
+ * Released as 1.99.2.
+
+Wed Jan 20 22:50:35 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Wrote configure script and rewrote Makefiles.
+
+ * Removed few unused variables.
+
+Wed Jan 20 12:21:56 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * common.c: Moved several functions used in both setpci and lspci
+ here. This includes parsing of libpci-related options.
+
+ * More library tweaks.
+
+ * filter.c, names.c: Moved to library.
+
+ * setpci: Rewritten to use the library.
+
+ * Released as 1.99.1.
+
+Tue Jan 19 23:00:12 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (scan_devices): For cardbus bridges, read first 128
+ bytes of config space to get full standard header.
+
+ * Makefile (CFLAGS): Removed "-Wno-unused".
+
+ * Started the "New Generation" branch and introduced the
+ PCI library.
+
+ * lspci: Rewritten to use the library.
+
+Tue Jan 19 22:24:08 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as version 1.10.
+
+Mon Jan 18 08:51:17 1999 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.8, setpci.8: Miscellaneous fixes as suggested by
+ Dag Wieers <dag@digibel.be>.
+
+Sun Nov 29 20:05:56 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * pciutils.spec (Name): Update from Krzysztof G. Baranowski.
+
+Sun Nov 22 10:49:56 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * Makefile, pciutils.h: Moved pci.ids to /usr/share.
+
+ * Released as version 1.09.
+
+Wed Nov 18 15:47:05 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_htype1): Fixed displaying of prefetchable memory behind
+ bridge. Thanks to Petr Vandrovec <vandrove@vc.cvut.cz> for bug report.
+
+Fri Oct 23 18:59:19 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * setpci.c: Don't include <syscall-list.h> with glibc >= 2.1.
+
+Mon Oct 19 21:53:30 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as version 1.08.
+
+ * setpci.c: glibc 2.1.x already defines pread() and pwrite().
+
+ * lspci.8: Changed warning about lspci -xxx.
+
+ * lspci.c: Require "-xxx" for full configuration space dump, so that
+ it's impossible to crash the machine by single typo.
+
+ * specs: Added (courtesy of Krzysztof G. Baranowski <kgb@knm.org.pl>).
+
+Wed Sep 9 12:03:24 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_bases): Better displaying of unassigned and
+ disabled bases. Thanks to Gabriel Paubert <paubert@iram.es>
+ for an idea.
+
+Wed Sep 2 10:58:01 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * setpci.c (pread): Recognize glibc 1.99 numbered as 2.0 on the PPC.
+ (thanks to Geert Uytterhoeven for finding this out)
+
+Fri Jul 17 10:43:30 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_verbose): Print subsystem ID using the new resolver.
+ (show_machine): Print subsystem ID.
+
+ * names.c: New name resolution engine supporting subsystem IDs.
+
+ * Released as version 1.07.
+
+Wed Jul 15 15:37:21 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_htype2 etc.): Displaying of CardBus headers.
+ (show_bases): Honor the `cnt' argument.
+ (grow_tree): Parse CardBus headers in tree mode as well.
+
+ * pci.h: Updated CardBus header field description. I still don't
+ have the CardBus standard available, but OZ6832 specs contain
+ full description of all header fields supported by the chip.
+
+Tue Jun 9 22:53:59 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as 1.06.
+
+ * names.c (parse_name_list): Killed an unused variable.
+
+ * setpci.c (pread, pwrite): Define SYS_(pread|pwrite) as __NR_\1
+ if they are not defined by glibc (needed for glibc built on older
+ kernels). Ugly.
+
+ * setpci.c (exec_op): Fixed error messages. Thanks, Steve!
+
+Mon Jun 8 10:59:22 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as 1.05.
+
+ * setpci.c: Problems with pread()/pwrite() with glibc on Alpha
+ should be gone. Again thanks to Steve for bug report.
+
+ * filter.c (filter_parse_slot): Fixed ":x" type filters.
+
+ * pci.ids: Killed duplicate entry. Thanks to Stephen Williams
+ <steve@icarus.com> for reporting this.
+
+Sun Jun 7 19:27:51 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (main), setpci.c (main): Implemented "--version".
+
+ * Released as 1.04.
+
+ * pciutils.h (PCIUTILS_VERSION): Added version string.
+
+ * filter.c, names.c: Extraneous #include <linux/pci.h> removed.
+ Thanks to Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be>
+ for bug report.
+
+Thu May 28 14:45:58 1998 Martin Mares <mj@lomikel.karlin.mff.cuni.cz>
+
+ * pci.ids: More updates from Jens Maurer.
+
+Wed Apr 22 10:00:39 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * pci.ids: Updates from Jens Maurer.
+
+Sun Apr 19 11:14:25 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * Released as 1.03.
+
+ * setpci.8: Written.
+
+ * setpci.c: Finished.
+
+ * lspci.c: Now able to fetch expansion ROM base from kernel device list
+ and print it if not in buscentric mode.
+
+Tue Mar 31 23:11:57 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * setpci.c: Added.
+
+Sun Mar 22 15:39:08 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.8: Updated the documentation.
+
+ * lspci.c: Modified to use the new filtering mechanism (options -f and -d).
+
+ * filter.c: Introduced new generic device filter.
+
+Thu Mar 19 17:03:48 1998 Martin Mares <mj@lomikel.karlin.mff.cuni.cz>
+
+ * lspci.c (grow_tree, show_tree_dev, print_it): Fixed displaying
+ of PCI-to-PCI bridges in the tree format.
+
+Sun Feb 15 10:12:25 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * lspci.c (show_machine): Added non-verbose mode of machine-readable
+ dump.
+
+ * pci.ids: Updates from Jens Maurer.
+
+ * Released as version 1.02.
+
+Thu Feb 12 16:53:28 1998 Martin Mares <mj@lomikel.karlin.mff.cuni.cz>
+
+ * lspci.c: Added a "-m" switch for dumping machine-readable
+ configuration data (requested by Bjoern Kriews <bkr@cut.de>).
+
+Mon Feb 9 13:17:43 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * Makefile, pciutils.h: Include local pci.h instead of <linux/pci.h>
+ if available. This should avoid all problems with official kernel
+ not synchronized to newer PCI code in CVS -- standard distribution
+ of pciutils now contains pci.h from current CVS kernel, pciutils
+ in CVS contain no pci.h and use the correct kernel include.
+
+ * Makefile: Fixed installation path for man pages.
+
+Sat Feb 7 15:15:46 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * README: Updated.
+
+ * lspci.8: Created a man page.
+
+ * Releasing as version 1.0.
+
+Tue Feb 3 20:56:00 1998 Martin Mares <mj@albireo.ucw.cz>
+
+ * Makefile: Recognize architecture by calling uname and pass it as ARCH_xxx
+ to all the C sources. This should eliminate problems with 32-bit compilers
+ on sparc64.
+
+ * lspci.c (show_verbose): Recognize CardBus bridge header type.
+ (show_htype2): Stub routine.
+ (scan_config): Write sensible error message if the kernel denies reading of
+ upper part of the PCI config space.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c06eca7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,168 @@
+# Makefile for The PCI Utilities
+# (c) 1998--2020 Martin Mares <mj@ucw.cz>
+
+OPT=-O2
+CFLAGS=$(OPT) -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes
+
+VERSION=3.7.0
+DATE=2020-05-31
+
+# Host OS and release (override if you are cross-compiling)
+HOST=
+RELEASE=
+CROSS_COMPILE=
+
+# Support for compressed pci.ids (yes/no, default: detect)
+ZLIB=
+
+# Support for resolving ID's by DNS (yes/no, default: detect)
+DNS=
+
+# Build libpci as a shared library (yes/no; or local for testing; requires GCC)
+SHARED=no
+
+# Use libkmod to resolve kernel modules on Linux (yes/no, default: detect)
+LIBKMOD=
+
+# Use libudev to resolve device names using hwdb on Linux (yes/no, default: detect)
+HWDB=
+
+# ABI version suffix in the name of the shared library
+# (as we use proper symbol versioning, this seldom needs changing)
+ABI_VERSION=.3
+
+# Installation directories
+PREFIX=/usr/local
+SBINDIR=$(PREFIX)/sbin
+SHAREDIR=$(PREFIX)/share
+IDSDIR=$(SHAREDIR)
+MANDIR:=$(shell if [ -d $(PREFIX)/share/man ] ; then echo $(PREFIX)/share/man ; else echo $(PREFIX)/man ; fi)
+INCDIR=$(PREFIX)/include
+LIBDIR=$(PREFIX)/lib
+PKGCFDIR=$(LIBDIR)/pkgconfig
+
+# Commands
+INSTALL=install
+DIRINSTALL=install -d
+STRIP=-s
+CC=$(CROSS_COMPILE)gcc
+AR=$(CROSS_COMPILE)ar
+RANLIB=$(CROSS_COMPILE)ranlib
+
+# Base name of the library (overriden on NetBSD, which has its own libpci)
+LIBNAME=libpci
+
+-include lib/config.mk
+
+PCIINC=lib/config.h lib/header.h lib/pci.h lib/types.h lib/sysdep.h
+PCIINC_INS=lib/config.h lib/header.h lib/pci.h lib/types.h
+
+export
+
+all: lib/$(PCILIB) lspci setpci example lspci.8 setpci.8 pcilib.7 pci.ids.5 update-pciids update-pciids.8 $(PCI_IDS)
+
+lib/$(PCILIB): $(PCIINC) force
+ $(MAKE) -C lib all
+
+force:
+
+lib/config.h lib/config.mk:
+ cd lib && ./configure
+
+lspci: lspci.o ls-vpd.o ls-caps.o ls-caps-vendor.o ls-ecaps.o ls-kernel.o ls-tree.o ls-map.o common.o lib/$(PCILIB)
+setpci: setpci.o common.o lib/$(PCILIB)
+
+LSPCIINC=lspci.h pciutils.h $(PCIINC)
+lspci.o: lspci.c $(LSPCIINC)
+ls-vpd.o: ls-vpd.c $(LSPCIINC)
+ls-caps.o: ls-caps.c $(LSPCIINC)
+ls-ecaps.o: ls-ecaps.c $(LSPCIINC)
+ls-kernel.o: ls-kernel.c $(LSPCIINC)
+ls-tree.o: ls-tree.c $(LSPCIINC)
+ls-map.o: ls-map.c $(LSPCIINC)
+
+setpci.o: setpci.c pciutils.h $(PCIINC)
+common.o: common.c pciutils.h $(PCIINC)
+
+lspci: LDLIBS+=$(LIBKMOD_LIBS)
+ls-kernel.o: CFLAGS+=$(LIBKMOD_CFLAGS)
+
+update-pciids: update-pciids.sh
+ sed <$< >$@ "s@^DEST=.*@DEST=$(IDSDIR)/$(PCI_IDS)@;s@^PCI_COMPRESSED_IDS=.*@PCI_COMPRESSED_IDS=$(PCI_COMPRESSED_IDS)@"
+ chmod +x $@
+
+# The example of use of libpci
+example: example.o lib/$(PCILIB)
+example.o: example.c $(PCIINC)
+
+%: %.o
+ $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o $@
+
+%.8 %.7 %.5: %.man
+ M=`echo $(DATE) | sed 's/-01-/-January-/;s/-02-/-February-/;s/-03-/-March-/;s/-04-/-April-/;s/-05-/-May-/;s/-06-/-June-/;s/-07-/-July-/;s/-08-/-August-/;s/-09-/-September-/;s/-10-/-October-/;s/-11-/-November-/;s/-12-/-December-/;s/\(.*\)-\(.*\)-\(.*\)/\3 \2 \1/'` ; sed <$< >$@ "s/@TODAY@/$$M/;s/@VERSION@/pciutils-$(VERSION)/;s#@IDSDIR@#$(IDSDIR)#"
+
+ctags:
+ rm -f tags
+ find . -name '*.[hc]' -exec ctags --append {} +
+
+TAGS:
+ rm -f TAGS
+ find . -name '*.[hc]' -exec etags --append {} +
+
+clean:
+ rm -f `find . -name "*~" -o -name "*.[oa]" -o -name "\#*\#" -o -name TAGS -o -name core -o -name "*.orig"`
+ rm -f update-pciids lspci setpci example lib/config.* *.[578] pci.ids.gz lib/*.pc lib/*.so lib/*.so.* tags
+ rm -rf maint/dist
+
+distclean: clean
+
+install: all
+# -c is ignored on Linux, but required on FreeBSD
+ $(DIRINSTALL) -m 755 $(DESTDIR)$(SBINDIR) $(DESTDIR)$(IDSDIR) $(DESTDIR)$(MANDIR)/man8 $(DESTDIR)$(MANDIR)/man7 $(DESTDIR)/$(MANDIR)/man5
+ $(INSTALL) -c -m 755 $(STRIP) lspci setpci $(DESTDIR)$(SBINDIR)
+ $(INSTALL) -c -m 755 update-pciids $(DESTDIR)$(SBINDIR)
+ $(INSTALL) -c -m 644 $(PCI_IDS) $(DESTDIR)$(IDSDIR)
+ $(INSTALL) -c -m 644 lspci.8 setpci.8 update-pciids.8 $(DESTDIR)$(MANDIR)/man8
+ $(INSTALL) -c -m 644 pcilib.7 $(DESTDIR)$(MANDIR)/man7
+ $(INSTALL) -c -m 644 pci.ids.5 $(DESTDIR)$(MANDIR)/man5
+ifeq ($(SHARED),yes)
+ifeq ($(LIBEXT),dylib)
+ ln -sf $(PCILIB) $(DESTDIR)$(LIBDIR)/$(LIBNAME)$(ABI_VERSION).$(LIBEXT)
+else
+ ln -sf $(PCILIB) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT)$(ABI_VERSION)
+endif
+endif
+
+ifeq ($(SHARED),yes)
+install: install-pcilib
+endif
+
+install-pcilib: lib/$(PCILIB)
+ $(DIRINSTALL) -m 755 $(DESTDIR)$(LIBDIR)
+ $(INSTALL) -c -m 644 lib/$(PCILIB) $(DESTDIR)$(LIBDIR)
+
+install-lib: $(PCIINC_INS) lib/$(PCILIBPC) install-pcilib
+ $(DIRINSTALL) -m 755 $(DESTDIR)$(INCDIR)/pci $(DESTDIR)$(PKGCFDIR)
+ $(INSTALL) -c -m 644 $(PCIINC_INS) $(DESTDIR)$(INCDIR)/pci
+ $(INSTALL) -c -m 644 lib/$(PCILIBPC) $(DESTDIR)$(PKGCFDIR)
+ifeq ($(SHARED),yes)
+ifeq ($(LIBEXT),dylib)
+ ln -sf $(LIBNAME)$(ABI_VERSION).$(LIBEXT) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT)
+else
+ ln -sf $(LIBNAME).$(LIBEXT)$(ABI_VERSION) $(DESTDIR)$(LIBDIR)/$(LIBNAME).$(LIBEXT)
+endif
+endif
+
+uninstall: all
+ rm -f $(DESTDIR)$(SBINDIR)/lspci $(DESTDIR)$(SBINDIR)/setpci $(DESTDIR)$(SBINDIR)/update-pciids
+ rm -f $(DESTDIR)$(IDSDIR)/$(PCI_IDS)
+ rm -f $(DESTDIR)$(MANDIR)/man8/lspci.8 $(DESTDIR)$(MANDIR)/man8/setpci.8 $(DESTDIR)$(MANDIR)/man8/update-pciids.8
+ rm -f $(DESTDIR)$(MANDIR)/man7/pcilib.7
+ifeq ($(SHARED),yes)
+ rm -f $(DESTDIR)$(LIBDIR)/$(PCILIB) $(DESTDIR)$(LIBDIR)/$(LIBNAME).so$(ABI_VERSION)
+endif
+
+pci.ids.gz: pci.ids
+ gzip -9n <$< >$@
+
+.PHONY: all clean distclean install install-lib uninstall force tags TAGS
diff --git a/README b/README
new file mode 100644
index 0000000..a6f7dcf
--- /dev/null
+++ b/README
@@ -0,0 +1,146 @@
+This package contains the PCI Utilities, version 3.7.0.
+
+Copyright (c) 1997--2020 Martin Mares <mj@ucw.cz>
+
+All files in this package can be freely distributed and used according
+to the terms of the GNU General Public License, either version 2 or
+(at your opinion) any newer version. See https://www.gnu.org/ for details.
+
+
+1. What's that?
+~~~~~~~~~~~~~~~
+The PCI Utilities package contains a library for portable access to PCI bus
+configuration registers and several utilities based on this library.
+
+In runs on the following systems:
+
+ Linux (via /sys/bus/pci, /proc/bus/pci or i386 ports)
+ FreeBSD (via /dev/pci)
+ NetBSD (via libpci)
+ OpenBSD (via /dev/pci)
+ GNU/kFreeBSD (via /dev/pci)
+ Solaris/i386 (direct port access)
+ Aix (via /dev/pci and odmget)
+ GNU Hurd (direct port access)
+ Windows (direct port access, see README.Windows for caveats)
+ CYGWIN (direct port access)
+ BeOS (via syscalls)
+ Haiku (via /dev/misc/poke)
+ Darwin (via IOKit)
+ DOS/DJGPP (via i386 ports)
+ SylixOS (via /proc/pci)
+
+It should be very easy to add support for other systems as well (volunteers
+wanted; if you want to try that, I'll be very glad to see the patches and
+include them in the next version).
+
+The utilities include: (See manual pages for more details)
+
+ - lspci: displays detailed information about all PCI buses and devices.
+
+ - setpci: allows to read from and write to PCI device configuration
+ registers. For example, you can adjust the latency timers with it.
+ CAUTION: There is a couple of dangerous points and caveats, please read
+ the manual page first!
+
+ - update-pciids: download the current version of the pci.ids file.
+
+
+2. Compiling and (un)installing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Just run "make" to compile the package and then "make install" to install it.
+Please note that GNU make is needed on most platforms.
+
+If you want to change the default installation location, please override
+the PREFIX variable specified in the Makefile -- e.g., you can use
+"make PREFIX=/opt/pciutils install" to create a separate installation
+not interfering with the rest of your system. Setting the DESTDIR variable
+will allow you to install to a different directory from the one you intend
+to eventually run it from. This is useful for people who are packaging
+pciutils to install on other computers.
+
+There are several options which can be set in the Makefile or overridden
+when running make:
+
+ ZLIB=yes/no Enable support for compressed pci.ids (requires zlib).
+ If it is enabled, pciutils will use pci.ids.gz in preference to
+ pci.ids, even if the pci.ids file is newer. If the pci.ids.gz
+ file is missing, it will use pci.ids instead. If you do not
+ specify this option, the configure script will try to guess
+ automatically based on the presence of zlib.
+
+ DNS=yes/no Enable support for querying the central database of PCI IDs
+ using DNS. Requires libresolv (which is available on most
+ systems as a part of the standard libraries) and tries to
+ autodetect its presence if the option is not specified.
+
+ SHARED=yes/ Build libpci as a shared library. Requires GCC 4.0 or newer.
+ no/local The ABI of the shared library is intended to remain backward
+ compatible for a long time (we use symbol versioning to achieve
+ that, like GNU libc does). The value `local' includes the
+ right directory name in the binaries, so the utilities can be
+ run without installation. This is not recommended for any
+ production builds.
+
+"make install-lib" installs the library together with its header files
+for use by other programs.
+
+When you are bored of dumping PCI registers, just use "make uninstall".
+
+
+3. Getting new IDs
+~~~~~~~~~~~~~~~~~~~
+The database of PCI IDs (the pci.ids file) gets out of date much faster
+than I release new versions of this package, so it is maintained separately.
+
+It lives at https://pci-ids.ucw.cz/, where you can browse the database,
+download the most recent pci.ids file (e.g., by running the update-ids utility)
+and also submit new entries.
+
+Alternatively, you can use `lspci -q' to query the central database
+for new entries via network.
+
+The pci.ids file is also mirrored at https://github.com/pciutils/pciids.
+
+On Linux systems with a recent enough version of libudev, UDEV's HWDB
+database is consulted when pci.ids lacks the device.
+
+
+4. Getting new versions
+~~~~~~~~~~~~~~~~~~~~~~~
+The current version of pciutils is available at:
+
+ https://mj.ucw.cz/sw/pciutils/
+
+The tarball can be downloaded at the following places:
+
+ https://mj.ucw.cz/download/linux/pci/
+ ftp://ftp.ucw.cz/pub/mj/linux/pci/
+ https://www.kernel.org/pub/software/utils/pciutils/ (expect a couple of hours delay)
+
+There is also a public GIT tree at:
+
+ https://git.kernel.org/pub/scm/utils/pciutils/pciutils.git
+ https://github.com/pciutils/pciutils
+
+
+5. Using the library
+~~~~~~~~~~~~~~~~~~~~
+So far, there is only a little documentation for the library except for the
+general introduction in the pcilib(7) man page. If you want to use the
+library in your programs, please follow the comments in lib/pci.h and in
+the example program example.c.
+
+
+6. Feedback
+~~~~~~~~~~~
+If you have any bug reports or suggestions, send them to the author.
+
+If you have any new IDs, I'll be very glad to add them to the database.
+Just submit them at https://pci-ids.ucw.cz/.
+
+Announcements of new versions are sent to linux-pci@vger.kernel.org
+(see http://vger.kernel.org/ for instructions).
+
+ Have fun
+ Martin
diff --git a/README.Windows b/README.Windows
new file mode 100644
index 0000000..e73762b
--- /dev/null
+++ b/README.Windows
@@ -0,0 +1,23 @@
+Since 2.1.99-test5, pciutils should also be compilable on Windows. Thanks
+to Alexander Stock for contributing the port.
+
+Updated after version 2.2.6 to compile again, and with MinGW, even (only?)
+cross-compiling. (Hopefully it works with MSVC too.)
+
+To use this port, you need to install WinIO.dll first. You can get it here:
+
+ https://github.com/starofrainnight/winio
+ https://github.com/vaptu/winio
+
+However, you need to use win32/config.{h,mk} instead of the automatically
+generated lib/config.{h,mk} as lib/configure does not run on Windows.
+
+================================================================================
+BEWARE: The current implementation pokes I/O ports to access the PCI devices
+directly. This leads to several problems: some devices are invisible, extended
+PCIe configuration space is not available, and there are many potential race
+conditions. Instead, libpci should use the proper Windows drivers.
+
+Unfortunately, the Windows port currently lacks a maintainer. If you are willing
+to step up and fix the issues, please let me know. -- Martin Mares
+================================================================================
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..d9efa20
--- /dev/null
+++ b/TODO
@@ -0,0 +1,22 @@
+- review class names
+
+Setpci:
+- auto-width
+- extend the register table
+
+Capabilities with partial decoding:
+- PCIe 2nd set of control/status registers (have spec)
+- HyperTransport caps (have spec)
+
+Capabilities with no decoding:
+- CompactPCI hot-swap
+- CompactPCI central resource control
+- AGP3
+- Secure device
+- Power Budgeting (ext'd, needs write access to enumerate)
+- Root Complex * (ext'd)
+- Multi-Function Virtual Channel (ext'd)
+- Root Bridge Control Block (ext'd)
+
+PCIIDS:
+- delete old DB at SF
diff --git a/common.c b/common.c
new file mode 100644
index 0000000..c5a3c8f
--- /dev/null
+++ b/common.c
@@ -0,0 +1,135 @@
+/*
+ * The PCI Utilities -- Common Functions
+ *
+ * Copyright (c) 1997--2016 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "pciutils.h"
+
+void NONRET
+die(char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ fprintf(stderr, "%s: ", program_name);
+ vfprintf(stderr, msg, args);
+ fputc('\n', stderr);
+ exit(1);
+}
+
+void *
+xmalloc(size_t howmuch)
+{
+ void *p = malloc(howmuch);
+ if (!p)
+ die("Unable to allocate %d bytes of memory", (int) howmuch);
+ return p;
+}
+
+void *
+xrealloc(void *ptr, size_t howmuch)
+{
+ void *p = realloc(ptr, howmuch);
+ if (!p)
+ die("Unable to allocate %d bytes of memory", (int) howmuch);
+ return p;
+}
+
+char *
+xstrdup(const char *str)
+{
+ int len = strlen(str) + 1;
+ char *copy = xmalloc(len);
+ memcpy(copy, str, len);
+ return copy;
+}
+
+static void
+set_pci_method(struct pci_access *pacc, char *arg)
+{
+ char *name;
+ int i;
+
+ if (!strcmp(arg, "help"))
+ {
+ printf("Known PCI access methods:\n\n");
+ for (i=0; name = pci_get_method_name(i); i++)
+ if (name[0])
+ printf("%s\n", name);
+ exit(0);
+ }
+ else
+ {
+ i = pci_lookup_method(arg);
+ if (i < 0)
+ die("No such PCI access method: %s (see `-A help' for a list)", arg);
+ pacc->method = i;
+ }
+}
+
+static void
+set_pci_option(struct pci_access *pacc, char *arg)
+{
+ if (!strcmp(arg, "help"))
+ {
+ struct pci_param *p;
+ printf("Known PCI access parameters:\n\n");
+ for (p=NULL; p=pci_walk_params(pacc, p);)
+ printf("%-20s %s (%s)\n", p->param, p->help, p->value);
+ exit(0);
+ }
+ else
+ {
+ char *sep = strchr(arg, '=');
+ if (!sep)
+ die("Invalid PCI access parameter syntax: %s", arg);
+ *sep++ = 0;
+ if (pci_set_param(pacc, arg, sep) < 0)
+ die("Unrecognized PCI access parameter: %s (see `-O help' for a list)", arg);
+ }
+}
+
+int
+parse_generic_option(int i, struct pci_access *pacc, char *arg)
+{
+ switch (i)
+ {
+#ifdef PCI_HAVE_PM_INTEL_CONF
+ case 'H':
+ if (!strcmp(arg, "1"))
+ pacc->method = PCI_ACCESS_I386_TYPE1;
+ else if (!strcmp(arg, "2"))
+ pacc->method = PCI_ACCESS_I386_TYPE2;
+ else
+ die("Unknown hardware configuration type %s", arg);
+ break;
+#endif
+#ifdef PCI_HAVE_PM_DUMP
+ case 'F':
+ pci_set_param(pacc, "dump.name", arg);
+ pacc->method = PCI_ACCESS_DUMP;
+ break;
+#endif
+ case 'A':
+ set_pci_method(pacc, arg);
+ break;
+ case 'G':
+ pacc->debugging++;
+ break;
+ case 'O':
+ set_pci_option(pacc, arg);
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
diff --git a/compat/README b/compat/README
new file mode 100644
index 0000000..6660945
--- /dev/null
+++ b/compat/README
@@ -0,0 +1,2 @@
+This directory contains implementations of standard library functions
+for systems where the default C libraries lack them.
diff --git a/compat/getopt.c b/compat/getopt.c
new file mode 100644
index 0000000..1d0beb7
--- /dev/null
+++ b/compat/getopt.c
@@ -0,0 +1,693 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef __STDC__
+# ifndef const
+# define const
+# endif
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#endif /* GNU C library. */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+#define BAD_OPTION '\0'
+int optopt = BAD_OPTION;
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum {
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#define my_strlen strlen
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+#if __STDC__ || defined(PROTO)
+extern char *getenv(const char *name);
+extern int strcmp(const char *s1, const char *s2);
+extern int strncmp(const char *s1, const char *s2, int n);
+
+static int my_strlen(const char *s);
+static char *my_index(const char *str, int chr);
+#else
+extern char *getenv();
+#endif
+
+static int my_strlen(const char *str)
+{
+ int n = 0;
+ while (*str++)
+ n++;
+ return n;
+}
+
+static char *my_index(const char *str, int chr)
+{
+ while (*str) {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+#endif /* GNU C library. */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved.
+
+ To perform the swap, we first reverse the order of all elements. So
+ all options now come before all non options, but they are in the
+ wrong order. So we put back the options and non options in original
+ order by reversing them again. For example:
+ original input: a b c -x -y
+ reverse all: -y -x c b a
+ reverse options: -x -y c b a
+ reverse non options: -x -y a b c
+*/
+
+#if __STDC__ || defined(PROTO)
+static void exchange(char **argv);
+#endif
+
+static void exchange(char **argv)
+{
+ char *temp, **first, **last;
+
+ /* Reverse all the elements [first_nonopt, optind) */
+ first = &argv[first_nonopt];
+ last = &argv[optind - 1];
+ while (first < last) {
+ temp = *first;
+ *first = *last;
+ *last = temp;
+ first++;
+ last--;
+ }
+ /* Put back the options in order */
+ first = &argv[first_nonopt];
+ first_nonopt += (optind - last_nonopt);
+ last = &argv[first_nonopt - 1];
+ while (first < last) {
+ temp = *first;
+ *first = *last;
+ *last = temp;
+ first++;
+ last--;
+ }
+
+ /* Put back the non options in order */
+ first = &argv[first_nonopt];
+ last_nonopt = optind;
+ last = &argv[last_nonopt - 1];
+ while (first < last) {
+ temp = *first;
+ *first = *last;
+ *last = temp;
+ first++;
+ last--;
+ }
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return BAD_OPTION after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return BAD_OPTION.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int _getopt_internal(int argc, char *const *argv, const char *optstring,
+ const struct option *longopts, int *longind, int long_only)
+{
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (optind == 0) {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-') {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ } else if (optstring[0] == '+') {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ } else if (getenv("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == NULL || *nextchar == '\0') {
+ if (ordering == PERMUTE) {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp(argv[optind], "--")) {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc) {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ ) {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ if (longopts != NULL && ((argv[optind][0] == '-' && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ )) {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = NULL;
+ int indfound = 0;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp(p->name, nextchar, s - nextchar)) {
+ if (s - nextchar == my_strlen(p->name)) {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ } else if (pfound == NULL) {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ } else
+ /* Second nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact) {
+ if (opterr)
+ fprintf(stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += my_strlen(nextchar);
+ optind++;
+ return BAD_OPTION;
+ }
+
+ if (pfound != NULL) {
+ option_index = indfound;
+ optind++;
+ if (*s) {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = s + 1;
+ else {
+ if (opterr) {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf(stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf(stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0],
+ pfound->name);
+ }
+ nextchar += my_strlen(nextchar);
+ return BAD_OPTION;
+ }
+ } else if (pfound->has_arg == 1) {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else {
+ if (opterr)
+ fprintf(stderr,
+ "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += my_strlen(nextchar);
+ return optstring[0] == ':' ? ':' : BAD_OPTION;
+ }
+ }
+ nextchar += my_strlen(nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag) {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ || my_index(optstring, *nextchar) == NULL) {
+ if (opterr) {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf(stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf(stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return BAD_OPTION;
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index(optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':') {
+ if (opterr) {
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf(stderr,
+ "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf(stderr, "%s: unrecognized option `-%c'\n", argv[0],
+ c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf(stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+ }
+ optopt = c;
+ return BAD_OPTION;
+ }
+ if (temp[1] == ':') {
+ if (temp[2] == ':') {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0') {
+ optarg = nextchar;
+ optind++;
+ } else
+ optarg = 0;
+ nextchar = NULL;
+ } else {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0') {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ } else if (optind == argc) {
+ if (opterr) {
+#if 0
+ fprintf(stderr,
+ "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = BAD_OPTION;
+ } else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int getopt(int argc, char *const *argv, const char *optstring)
+{
+ return _getopt_internal(argc, argv, optstring, (const struct option *) 0, (int *) 0, 0);
+}
+
+int getopt_long(int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index)
+{
+ return _getopt_internal(argc, argv, options, long_options, opt_index, 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int main(int argc, char **argv)
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1) {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt(argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf("option %c\n", c);
+ break;
+
+ case 'a':
+ printf("option a\n");
+ break;
+
+ case 'b':
+ printf("option b\n");
+ break;
+
+ case 'c':
+ printf("option c with value `%s'\n", optarg);
+ break;
+
+ case BAD_OPTION:
+ break;
+
+ default:
+ printf("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc) {
+ printf("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf("%s ", argv[optind++]);
+ printf("\n");
+ }
+
+ exit(0);
+}
+
+#endif /* TEST */
diff --git a/compat/getopt.h b/compat/getopt.h
new file mode 100644
index 0000000..0abce6e
--- /dev/null
+++ b/compat/getopt.h
@@ -0,0 +1,127 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__ || defined(PROTO)
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/example.c b/example.c
new file mode 100644
index 0000000..7780e55
--- /dev/null
+++ b/example.c
@@ -0,0 +1,37 @@
+/*
+ * The PCI Library -- Example of use (simplistic lister of PCI devices)
+ *
+ * Written by Martin Mares and put to public domain. You can do
+ * with it anything you want, but I don't give you any warranty.
+ */
+
+#include <stdio.h>
+
+#include "lib/pci.h"
+
+int main(void)
+{
+ struct pci_access *pacc;
+ struct pci_dev *dev;
+ unsigned int c;
+ char namebuf[1024], *name;
+
+ pacc = pci_alloc(); /* Get the pci_access structure */
+ /* Set all options you want -- here we stick with the defaults */
+ pci_init(pacc); /* Initialize the PCI library */
+ pci_scan_bus(pacc); /* We want to get the list of devices */
+ for (dev=pacc->devices; dev; dev=dev->next) /* Iterate over all devices */
+ {
+ pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); /* Fill in header info we need */
+ c = pci_read_byte(dev, PCI_INTERRUPT_PIN); /* Read config register directly */
+ printf("%04x:%02x:%02x.%d vendor=%04x device=%04x class=%04x irq=%d (pin %d) base0=%lx",
+ dev->domain, dev->bus, dev->dev, dev->func, dev->vendor_id, dev->device_id,
+ dev->device_class, dev->irq, c, (long) dev->base_addr[0]);
+
+ /* Look up and print the full name of the device */
+ name = pci_lookup_name(pacc, namebuf, sizeof(namebuf), PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
+ printf(" (%s)\n", name);
+ }
+ pci_cleanup(pacc); /* Close everything */
+ return 0;
+}
diff --git a/lib/.gitignore b/lib/.gitignore
new file mode 100644
index 0000000..9bed745
--- /dev/null
+++ b/lib/.gitignore
@@ -0,0 +1,3 @@
+config.h
+config.mk
+libpci.pc
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 0000000..d89cd6c
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,102 @@
+# Makefile for The PCI Library
+# (c) 1999--2014 Martin Mares <mj@ucw.cz>
+
+# Expects to be invoked from the top-level Makefile and uses lots of its variables.
+
+OBJS=init access generic dump names filter names-hash names-parse names-net names-cache names-hwdb params caps
+INCL=internal.h pci.h config.h header.h sysdep.h types.h
+
+ifdef PCI_HAVE_PM_LINUX_SYSFS
+OBJS += sysfs
+endif
+
+ifdef PCI_HAVE_PM_LINUX_PROC
+OBJS += proc
+endif
+
+ifdef PCI_HAVE_PM_INTEL_CONF
+OBJS += i386-ports
+endif
+
+ifdef PCI_HAVE_PM_DUMP
+OBJS += dump
+endif
+
+ifdef PCI_HAVE_PM_FBSD_DEVICE
+OBJS += fbsd-device
+CFLAGS += -I/usr/src/sys
+ifdef FREEBSD_SYS
+CFLAGS += -I${FREEBSD_SYS}
+endif
+endif
+
+ifdef PCI_HAVE_PM_OBSD_DEVICE
+OBJS += obsd-device
+endif
+
+ifdef PCI_HAVE_PM_AIX_DEVICE
+OBJS += aix-device
+endif
+
+ifdef PCI_HAVE_PM_NBSD_LIBPCI
+OBJS += nbsd-libpci
+endif
+
+ifdef PCI_HAVE_PM_DARWIN_DEVICE
+OBJS += darwin
+endif
+
+ifdef PCI_HAVE_PM_SYLIXOS_DEVICE
+OBJS += sylixos-device
+endif
+
+ifdef PCI_HAVE_PM_HURD_CONF
+OBJS += hurd
+endif
+
+all: $(PCILIB) $(PCILIBPC)
+
+ifeq ($(SHARED),no)
+$(PCILIB): $(addsuffix .o,$(OBJS))
+ rm -f $@
+ $(AR) rcs $@ $^
+ $(RANLIB) $@
+else
+CFLAGS += -fPIC -fvisibility=hidden
+$(PCILIB): $(addsuffix .o,$(OBJS))
+ ifdef PCI_HAVE_PM_DARWIN_DEVICE
+ $(CC) -shared $(LDFLAGS) $(SONAME) -Wl,-install_name,$(LIBDIR)/$(PCILIB) -o $@ $^ $(LIB_LDLIBS)
+ else
+ $(CC) -shared $(LDFLAGS) $(SONAME) -Wl,--version-script=libpci.ver -o $@ $^ $(LIB_LDLIBS)
+ endif
+endif
+
+$(PCILIBPC): libpci.pc.in
+ sed <$< >$@ -e 's,@PREFIX@,$(PREFIX),' \
+ -e 's,@INCDIR@,$(INCDIR),' \
+ -e 's,@LIBDIR@,$(LIBDIR),' \
+ -e 's,@IDSDIR@,$(IDSDIR),' \
+ -e 's,@VERSION@,$(VERSION),' \
+ -e 's,@LDLIBS@,$(LDLIBS),'
+
+init.o: init.c $(INCL)
+access.o: access.c $(INCL)
+params.o: params.c $(INCL)
+i386-ports.o: i386-ports.c $(INCL) i386-io-hurd.h i386-io-linux.h i386-io-sunos.h i386-io-windows.h i386-io-cygwin.h
+proc.o: proc.c $(INCL) pread.h
+sysfs.o: sysfs.c $(INCL) pread.h
+generic.o: generic.c $(INCL)
+syscalls.o: syscalls.c $(INCL)
+obsd-device.o: obsd-device.c $(INCL)
+fbsd-device.o: fbsd-device.c $(INCL)
+aix-device.o: aix-device.c $(INCL)
+dump.o: dump.c $(INCL)
+names.o: names.c $(INCL) names.h
+names-cache.o: names-cache.c $(INCL) names.h
+names-hash.o: names-hash.c $(INCL) names.h
+names-net.o: names-net.c $(INCL) names.h
+names-parse.o: names-parse.c $(INCL) names.h
+names-hwdb.o: names-hwdb.c $(INCL) names.h
+filter.o: filter.c $(INCL)
+nbsd-libpci.o: nbsd-libpci.c $(INCL)
+hurd.o: hurd.c $(INCL)
diff --git a/lib/access.c b/lib/access.c
new file mode 100644
index 0000000..b257849
--- /dev/null
+++ b/lib/access.c
@@ -0,0 +1,266 @@
+/*
+ * The PCI Library -- User Access
+ *
+ * Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "internal.h"
+
+void
+pci_scan_bus(struct pci_access *a)
+{
+ a->methods->scan(a);
+}
+
+struct pci_dev *
+pci_alloc_dev(struct pci_access *a)
+{
+ struct pci_dev *d = pci_malloc(a, sizeof(struct pci_dev));
+
+ memset(d, 0, sizeof(*d));
+ d->access = a;
+ d->methods = a->methods;
+ d->hdrtype = -1;
+ d->numa_node = -1;
+ if (d->methods->init_dev)
+ d->methods->init_dev(d);
+ return d;
+}
+
+int
+pci_link_dev(struct pci_access *a, struct pci_dev *d)
+{
+ d->next = a->devices;
+ a->devices = d;
+
+ /*
+ * Applications compiled with older versions of libpci do not expect
+ * 32-bit domain numbers. To keep them working, we keep a 16-bit
+ * version of the domain number at the previous location in struct
+ * pci_dev. This will keep backward compatibility on systems which
+ * don't require large domain numbers.
+ */
+ if (d->domain > 0xffff)
+ d->domain_16 = 0xffff;
+ else
+ d->domain_16 = d->domain;
+
+ return 1;
+}
+
+struct pci_dev *
+pci_get_dev(struct pci_access *a, int domain, int bus, int dev, int func)
+{
+ struct pci_dev *d = pci_alloc_dev(a);
+
+ d->domain = domain;
+ d->bus = bus;
+ d->dev = dev;
+ d->func = func;
+ return d;
+}
+
+static void
+pci_free_properties(struct pci_dev *d)
+{
+ struct pci_property *p;
+
+ while (p = d->properties)
+ {
+ d->properties = p->next;
+ pci_mfree(p);
+ }
+}
+
+void pci_free_dev(struct pci_dev *d)
+{
+ if (d->methods->cleanup_dev)
+ d->methods->cleanup_dev(d);
+
+ pci_free_caps(d);
+ pci_free_properties(d);
+ pci_mfree(d);
+}
+
+static inline void
+pci_read_data(struct pci_dev *d, void *buf, int pos, int len)
+{
+ if (pos & (len-1))
+ d->access->error("Unaligned read: pos=%02x, len=%d", pos, len);
+ if (pos + len <= d->cache_len)
+ memcpy(buf, d->cache + pos, len);
+ else if (!d->methods->read(d, pos, buf, len))
+ memset(buf, 0xff, len);
+}
+
+byte
+pci_read_byte(struct pci_dev *d, int pos)
+{
+ byte buf;
+ pci_read_data(d, &buf, pos, 1);
+ return buf;
+}
+
+word
+pci_read_word(struct pci_dev *d, int pos)
+{
+ word buf;
+ pci_read_data(d, &buf, pos, 2);
+ return le16_to_cpu(buf);
+}
+
+u32
+pci_read_long(struct pci_dev *d, int pos)
+{
+ u32 buf;
+ pci_read_data(d, &buf, pos, 4);
+ return le32_to_cpu(buf);
+}
+
+int
+pci_read_block(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ return d->methods->read(d, pos, buf, len);
+}
+
+int
+pci_read_vpd(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ return d->methods->read_vpd ? d->methods->read_vpd(d, pos, buf, len) : 0;
+}
+
+static inline int
+pci_write_data(struct pci_dev *d, void *buf, int pos, int len)
+{
+ if (pos & (len-1))
+ d->access->error("Unaligned write: pos=%02x,len=%d", pos, len);
+ if (pos + len <= d->cache_len)
+ memcpy(d->cache + pos, buf, len);
+ return d->methods->write(d, pos, buf, len);
+}
+
+int
+pci_write_byte(struct pci_dev *d, int pos, byte data)
+{
+ return pci_write_data(d, &data, pos, 1);
+}
+
+int
+pci_write_word(struct pci_dev *d, int pos, word data)
+{
+ word buf = cpu_to_le16(data);
+ return pci_write_data(d, &buf, pos, 2);
+}
+
+int
+pci_write_long(struct pci_dev *d, int pos, u32 data)
+{
+ u32 buf = cpu_to_le32(data);
+ return pci_write_data(d, &buf, pos, 4);
+}
+
+int
+pci_write_block(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ if (pos < d->cache_len)
+ {
+ int l = (pos + len >= d->cache_len) ? (d->cache_len - pos) : len;
+ memcpy(d->cache + pos, buf, l);
+ }
+ return d->methods->write(d, pos, buf, len);
+}
+
+static void
+pci_reset_properties(struct pci_dev *d)
+{
+ d->known_fields = 0;
+ d->phy_slot = NULL;
+ d->module_alias = NULL;
+ d->label = NULL;
+ pci_free_caps(d);
+ pci_free_properties(d);
+}
+
+int
+pci_fill_info_v35(struct pci_dev *d, int flags)
+{
+ unsigned int uflags = flags;
+ if (uflags & PCI_FILL_RESCAN)
+ {
+ uflags &= ~PCI_FILL_RESCAN;
+ pci_reset_properties(d);
+ }
+ if (uflags & ~d->known_fields)
+ d->known_fields |= d->methods->fill_info(d, flags & ~d->known_fields);
+ return d->known_fields;
+}
+
+/* In version 3.1, pci_fill_info got new flags => versioned alias */
+/* In versions 3.2, 3.3, 3.4 and 3.5, the same has happened */
+STATIC_ALIAS(int pci_fill_info(struct pci_dev *d, int flags), pci_fill_info_v35(d, flags));
+DEFINE_ALIAS(int pci_fill_info_v30(struct pci_dev *d, int flags), pci_fill_info_v35);
+DEFINE_ALIAS(int pci_fill_info_v31(struct pci_dev *d, int flags), pci_fill_info_v35);
+DEFINE_ALIAS(int pci_fill_info_v32(struct pci_dev *d, int flags), pci_fill_info_v35);
+DEFINE_ALIAS(int pci_fill_info_v33(struct pci_dev *d, int flags), pci_fill_info_v35);
+DEFINE_ALIAS(int pci_fill_info_v34(struct pci_dev *d, int flags), pci_fill_info_v35);
+SYMBOL_VERSION(pci_fill_info_v30, pci_fill_info@LIBPCI_3.0);
+SYMBOL_VERSION(pci_fill_info_v31, pci_fill_info@LIBPCI_3.1);
+SYMBOL_VERSION(pci_fill_info_v32, pci_fill_info@LIBPCI_3.2);
+SYMBOL_VERSION(pci_fill_info_v33, pci_fill_info@LIBPCI_3.3);
+SYMBOL_VERSION(pci_fill_info_v34, pci_fill_info@LIBPCI_3.4);
+SYMBOL_VERSION(pci_fill_info_v35, pci_fill_info@@LIBPCI_3.5);
+
+void
+pci_setup_cache(struct pci_dev *d, byte *cache, int len)
+{
+ d->cache = cache;
+ d->cache_len = len;
+}
+
+char *
+pci_set_property(struct pci_dev *d, u32 key, char *value)
+{
+ struct pci_property *p;
+ struct pci_property **pp = &d->properties;
+
+ while (p = *pp)
+ {
+ if (p->key == key)
+ {
+ *pp = p->next;
+ pci_mfree(p);
+ }
+ else
+ pp = &p->next;
+ }
+
+ if (!value)
+ return NULL;
+
+ p = pci_malloc(d->access, sizeof(*p) + strlen(value));
+ *pp = p;
+ p->next = NULL;
+ p->key = key;
+ strcpy(p->value, value);
+
+ return p->value;
+}
+
+char *
+pci_get_string_property(struct pci_dev *d, u32 prop)
+{
+ struct pci_property *p;
+
+ for (p = d->properties; p; p = p->next)
+ if (p->key == prop)
+ return p->value;
+
+ return NULL;
+}
diff --git a/lib/aix-device.c b/lib/aix-device.c
new file mode 100644
index 0000000..f7d8e78
--- /dev/null
+++ b/lib/aix-device.c
@@ -0,0 +1,274 @@
+/*
+ * The PCI Library -- AIX /dev/pci[0-n] access
+ *
+ * Copyright (c) 1999 Jari Kirma <kirma@cs.hut.fi>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+/*
+ * Read functionality of this driver is briefly tested, and seems
+ * to supply basic information correctly, but I promise no more.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/mdio.h>
+
+#include "internal.h"
+
+#define AIX_LSDEV_CMD "/usr/sbin/lsdev -C -c bus -t pci\\* -S available -F name"
+#define AIX_ODMGET_CMD \
+ "/usr/bin/odmget -q 'name=%s and attribute=bus_number' CuAt | \
+ /usr/bin/awk '$1 == \"value\" { print $3 }'"
+
+
+/* AIX PCI bus device information */
+
+typedef struct aix_pci_bus {
+ char *bus_name;
+ int bus_number;
+ int bus_fd;
+} aix_pci_bus;
+
+#define PCI_BUS_MAX 16 /* arbitrary choice */
+static aix_pci_bus pci_buses[PCI_BUS_MAX];
+static int pci_bus_count = 0;
+
+
+/* Utility Routines */
+
+static aix_pci_bus *
+aix_find_bus(struct pci_access *a, int bus_number)
+{
+ int i;
+
+ for (i = 0; i < pci_bus_count; i++)
+ {
+ if (pci_buses[i].bus_number == bus_number)
+ {
+ return &pci_buses[i];
+ }
+ }
+
+ a->error("aix_find_bus: bus number %d not found", bus_number);
+}
+
+static int
+aix_bus_open(struct pci_dev *d)
+{
+ struct pci_access *a = d->access;
+ aix_pci_bus *bp = aix_find_bus(a, d->bus);
+
+ if (bp->bus_fd < 0)
+ {
+ char devbuf[256];
+ int mode = a->writeable ? O_RDWR : O_RDONLY;
+
+ snprintf(devbuf, sizeof (devbuf), "/dev/%s", bp->bus_name);
+ bp->bus_fd = open(devbuf, mode, 0);
+ if (bp->bus_fd < 0)
+ a->error("aix_open_bus: %s open failed", devbuf);
+ }
+
+ return bp->bus_fd;
+}
+
+static int
+aix_bus_number(char *name)
+{
+ int bus_number;
+ FILE *odmget_pipe;
+ char command[256];
+ char buf[256];
+ char *bp;
+ char *ep;
+
+ snprintf(command, sizeof (command), AIX_ODMGET_CMD, name);
+ odmget_pipe = popen(command, "r");
+ if (odmget_pipe == NULL)
+ {
+ /* popen failed */
+ return -1;
+ }
+
+ if (fgets(buf, sizeof (buf) - 1, odmget_pipe) != NULL)
+ {
+ bp = buf + 1; /* skip leading double quote */
+ bus_number = strtol(bp, &ep, 0);
+ if (bp == ep)
+ {
+ /* strtol failed */
+ bus_number = -1;
+ }
+ }
+ else
+ {
+ /* first PCI bus_number is not recorded in ODM CuAt; default to 0 */
+ bus_number = 0;
+ }
+
+ (void) pclose(odmget_pipe);
+
+ return bus_number;
+}
+
+
+/* Method entries */
+
+static int
+aix_detect(struct pci_access *a)
+{
+ int len;
+ int mode = a->writeable ? W_OK : R_OK;
+ char *command = AIX_LSDEV_CMD;
+ FILE *lsdev_pipe;
+ char buf[256];
+ char *name;
+
+ lsdev_pipe = popen(command, "r");
+ if (lsdev_pipe == NULL)
+ {
+ a->error("aix_config: popen(\"%s\") failed", command);
+ }
+
+ while (fgets(buf, sizeof (buf) - 1, lsdev_pipe) != NULL)
+ {
+ len = strlen(buf);
+ while (buf[len-1] == '\n' || buf[len-1] == '\r')
+ len--;
+ buf[len] = '\0'; /* clobber the newline */
+
+ name = (char *) pci_malloc(a, len + 1);
+ strcpy(name, buf);
+ pci_buses[pci_bus_count].bus_name = name;
+ pci_buses[pci_bus_count].bus_number = 0;
+ pci_buses[pci_bus_count].bus_fd = -1;
+ if (!pci_bus_count)
+ a->debug("...using %s", name);
+ else
+ a->debug(", %s", name);
+ pci_bus_count++;
+ if (pci_bus_count >= PCI_BUS_MAX)
+ break;
+ }
+
+ (void) pclose(lsdev_pipe);
+
+ return pci_bus_count;
+}
+
+static void
+aix_init(struct pci_access *a)
+{
+ char *name;
+ int i;
+
+ for (i = 0; i < pci_bus_count; i++)
+ {
+ name = pci_buses[i].bus_name;
+ pci_buses[i].bus_number = aix_bus_number(name);
+ }
+}
+
+static void
+aix_cleanup(struct pci_access *a)
+{
+ aix_pci_bus *bp;
+
+ while (pci_bus_count-- > 0)
+ {
+ bp = &pci_buses[pci_bus_count];
+ (void) free(bp->bus_name);
+ if (bp->bus_fd >= 0)
+ {
+ (void) close(bp->bus_fd);
+ bp->bus_fd = -1;
+ }
+ }
+}
+
+void
+aix_scan(struct pci_access *a)
+{
+ int i;
+ int bus_number;
+ byte busmap[256];
+
+ memset(busmap, 0, sizeof(busmap));
+ for (i = 0; i < pci_bus_count; i++)
+ {
+ bus_number = pci_buses[i].bus_number;
+ if (!busmap[bus_number])
+ {
+ pci_generic_scan_bus(a, busmap, bus_number);
+ }
+ }
+}
+
+static int
+aix_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ struct mdio mdio;
+ int fd;
+
+ if (d->domain || pos + len > 256)
+ return 0;
+
+ fd = aix_bus_open(d);
+ mdio.md_addr = (ulong) pos;
+ mdio.md_size = len;
+ mdio.md_incr = MV_BYTE;
+ mdio.md_data = (char *) buf;
+ mdio.md_sla = PCI_DEVFN(d->dev, d->func);
+
+ if (ioctl(fd, MIOPCFGET, &mdio) < 0)
+ d->access->error("aix_read: ioctl(MIOPCFGET) failed");
+
+ return 1;
+}
+
+static int
+aix_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ struct mdio mdio;
+ int fd;
+
+ if (d->domain || pos + len > 256)
+ return 0;
+
+ fd = aix_bus_open(d);
+ mdio.md_addr = (ulong) pos;
+ mdio.md_size = len;
+ mdio.md_incr = MV_BYTE;
+ mdio.md_data = (char *) buf;
+ mdio.md_sla = PCI_DEVFN(d->dev, d->func);
+
+ if (ioctl(fd, MIOPCFPUT, &mdio) < 0)
+ {
+ d->access->error("aix_write: ioctl(MIOPCFPUT) failed");
+ }
+
+ return 1;
+}
+
+struct pci_methods pm_aix_device = {
+ "aix-device",
+ "AIX /dev/pci[0-n]",
+ NULL,
+ aix_detect,
+ aix_init,
+ aix_cleanup,
+ aix_scan,
+ pci_generic_fill_info,
+ aix_read,
+ aix_write,
+ NULL, /* read_vpd */
+ NULL, /* dev_init */
+ NULL /* dev_cleanup */
+};
diff --git a/lib/caps.c b/lib/caps.c
new file mode 100644
index 0000000..1fca141
--- /dev/null
+++ b/lib/caps.c
@@ -0,0 +1,147 @@
+/*
+ * The PCI Library -- Capabilities
+ *
+ * Copyright (c) 2008 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <string.h>
+
+#include "internal.h"
+
+static void
+pci_add_cap(struct pci_dev *d, unsigned int addr, unsigned int id, unsigned int type)
+{
+ struct pci_cap *cap = pci_malloc(d->access, sizeof(*cap));
+
+ if (d->last_cap)
+ d->last_cap->next = cap;
+ else
+ d->first_cap = cap;
+ d->last_cap = cap;
+ cap->next = NULL;
+ cap->addr = addr;
+ cap->id = id;
+ cap->type = type;
+ d->access->debug("%04x:%02x:%02x.%d: Found capability %04x of type %d at %04x\n",
+ d->domain, d->bus, d->dev, d->func, id, type, addr);
+}
+
+static void
+pci_scan_trad_caps(struct pci_dev *d)
+{
+ word status = pci_read_word(d, PCI_STATUS);
+ byte been_there[256];
+ int where;
+
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return;
+
+ memset(been_there, 0, 256);
+ where = pci_read_byte(d, PCI_CAPABILITY_LIST) & ~3;
+ while (where)
+ {
+ byte id = pci_read_byte(d, where + PCI_CAP_LIST_ID);
+ byte next = pci_read_byte(d, where + PCI_CAP_LIST_NEXT) & ~3;
+ if (been_there[where]++)
+ break;
+ if (id == 0xff)
+ break;
+ pci_add_cap(d, where, id, PCI_CAP_NORMAL);
+ where = next;
+ }
+}
+
+static void
+pci_scan_ext_caps(struct pci_dev *d)
+{
+ byte been_there[0x1000];
+ int where = 0x100;
+
+ if (!pci_find_cap(d, PCI_CAP_ID_EXP, PCI_CAP_NORMAL))
+ return;
+
+ memset(been_there, 0, 0x1000);
+ do
+ {
+ u32 header;
+ int id;
+
+ header = pci_read_long(d, where);
+ if (!header || header == 0xffffffff)
+ break;
+ id = header & 0xffff;
+ if (been_there[where]++)
+ break;
+ pci_add_cap(d, where, id, PCI_CAP_EXTENDED);
+ where = (header >> 20) & ~3;
+ }
+ while (where);
+}
+
+unsigned int
+pci_scan_caps(struct pci_dev *d, unsigned int want_fields)
+{
+ if ((want_fields & PCI_FILL_EXT_CAPS) && !(d->known_fields & PCI_FILL_CAPS))
+ want_fields |= PCI_FILL_CAPS;
+
+ if (want_fields & PCI_FILL_CAPS)
+ pci_scan_trad_caps(d);
+ if (want_fields & PCI_FILL_EXT_CAPS)
+ pci_scan_ext_caps(d);
+ return want_fields;
+}
+
+void
+pci_free_caps(struct pci_dev *d)
+{
+ struct pci_cap *cap;
+
+ while (cap = d->first_cap)
+ {
+ d->first_cap = cap->next;
+ pci_mfree(cap);
+ }
+}
+
+struct pci_cap *
+pci_find_cap(struct pci_dev *d, unsigned int id, unsigned int type)
+{
+ return pci_find_cap_nr(d, id, type, NULL);
+}
+
+/**
+ * Finds a particular capability of a device
+ *
+ * To select one capability if there are more than one with the same id, you
+ * can provide a pointer to an unsigned int that contains the index which you
+ * want as cap_number. If you don't care and are fine with the first one you
+ * can supply NULL. The cap_number will be replaced by the acutal number
+ * of capablities with that id.
+ */
+struct pci_cap *
+pci_find_cap_nr(struct pci_dev *d, unsigned int id, unsigned int type,
+ unsigned int *cap_number)
+{
+ struct pci_cap *c;
+ struct pci_cap *found = NULL;
+ unsigned int target = (cap_number ? *cap_number : 0);
+ unsigned int index = 0;
+
+ pci_fill_info_v35(d, ((type == PCI_CAP_NORMAL) ? PCI_FILL_CAPS : PCI_FILL_EXT_CAPS));
+
+ for (c=d->first_cap; c; c=c->next)
+ {
+ if (c->type == type && c->id == id)
+ {
+ if (target == index)
+ found = c;
+ index++;
+ }
+ }
+
+ if (cap_number)
+ *cap_number = index;
+ return found;
+}
diff --git a/lib/configure b/lib/configure
new file mode 100755
index 0000000..08b9462
--- /dev/null
+++ b/lib/configure
@@ -0,0 +1,274 @@
+#!/bin/sh
+# Configuration script for the PCI library
+# (c) 1998--2013 Martin Mares <mj@ucw.cz>
+
+LC_ALL=C
+export LC_ALL
+
+echo_n() {
+ printf '%s' "$*"
+}
+
+if [ -z "$VERSION" -o -z "$IDSDIR" ] ; then
+ echo >&2 "Please run the configure script from the top-level Makefile"
+ exit 1
+fi
+
+echo_n "Configuring libpci for your system..."
+if [ -z "$HOST" ] ; then
+ sys=`uname -s`
+ rel=`uname -r`
+ realsys="$sys"
+ if [ "$sys" = "AIX" -a -x /usr/bin/oslevel -a -x /usr/sbin/lsattr ]
+ then
+ rel=`/usr/bin/oslevel`
+ proc=`/usr/sbin/lsdev -C -c processor -S available -F name | head -1`
+ cpu=`/usr/sbin/lsattr -F value -l $proc -a type | sed 's/_.*//'`
+ else
+ cpu=`uname -m | sed 's/^i.86$/i386/;s/^sun4u$/sparc64/;s/^i86pc$/i386/;s/^BePC$/i386/;s/^BeMac$/powerpc/;s/^BeBox$/powerpc/'`
+ fi
+ if [ "$sys" = "GNU/kFreeBSD" -o "$sys" = "DragonFly" ]
+ then
+ sys=freebsd
+ fi
+ if [ "$sys" = "CYGWIN_NT-5.1" -o "$sys" = "CYGWIN_NT-6.0" ]
+ then
+ sys=cygwin
+ fi
+ HOST=${3:-$cpu-$sys}
+fi
+[ -n "$RELEASE" ] && rel="${RELEASE}"
+# CAVEAT: tr on Solaris is a bit weird and the extra [] is otherwise harmless.
+host=`echo $HOST | sed -e 's/^\([^-]*\)-\([^-]*\)-\([^-]*\)-\([^-]*\)$/\1-\3/' -e 's/^\([^-]*\)-\([^-]*\)-\([^-]*\)$/\1-\2/' -e 's/^\([^-]*\)-\([^-]*\)$/\1--\2/' | tr '[A-Z]' '[a-z]'`
+cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+sys=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo " $host $rel $cpu $sys"
+
+c=config.h
+m=config.mk
+echo >$c '#define PCI_CONFIG_H'
+echo >>$c "#define PCI_ARCH_`echo $cpu | tr '[a-z]' '[A-Z]'`"
+echo >>$c "#define PCI_OS_`echo $sys | tr '[a-z]' '[A-Z]'`"
+echo >$m 'WITH_LIBS='
+
+echo_n "Looking for access methods..."
+LIBRESOLV=-lresolv
+LIBEXT=so
+
+case $sys in
+ linux*)
+ echo_n " sysfs proc"
+ echo >>$c '#define PCI_HAVE_PM_LINUX_SYSFS'
+ echo >>$c '#define PCI_HAVE_PM_LINUX_PROC'
+ echo >>$c '#define PCI_HAVE_LINUX_BYTEORDER_H'
+ echo >>$c '#define PCI_PATH_PROC_BUS_PCI "/proc/bus/pci"'
+ echo >>$c '#define PCI_PATH_SYS_BUS_PCI "/sys/bus/pci"'
+ case $cpu in
+ i?86|x86_64) echo_n " i386-ports"
+ echo >>$c '#define PCI_HAVE_PM_INTEL_CONF'
+ ;;
+ esac
+ echo >>$c '#define PCI_HAVE_64BIT_ADDRESS'
+ ;;
+ sunos)
+ case $cpu in
+ i?86) echo_n " i386-ports"
+ echo >>$c "#define PCI_HAVE_PM_INTEL_CONF"
+ ;;
+ *)
+ echo " The PCI library does not support Solaris for this architecture: $cpu"
+ exit 1
+ ;;
+ esac
+ echo >>$c '#define PCI_HAVE_STDINT_H'
+ ;;
+ freebsd*)
+ echo_n " fbsd-device"
+ echo >>$c '#define PCI_HAVE_PM_FBSD_DEVICE'
+ echo >>$c '#define PCI_PATH_FBSD_DEVICE "/dev/pci"'
+ if [ "$realsys" != "GNU/kFreeBSD" ] ; then
+ LIBRESOLV=
+ fi
+ ;;
+ openbsd)
+ echo_n " obsd-device"
+ echo >>$c '#define PCI_HAVE_PM_OBSD_DEVICE'
+ echo >>$c '#define PCI_PATH_OBSD_DEVICE "/dev/pci"'
+ LIBRESOLV=
+ ;;
+
+ darwin*)
+ echo_n " darwin"
+ echo >>$c '#define PCI_HAVE_PM_DARWIN_DEVICE'
+ echo >>$m 'WITH_LIBS+=-lresolv -framework CoreFoundation -framework IOKit'
+ echo >>$c '#define PCI_HAVE_64BIT_ADDRESS'
+ LIBRESOLV=
+ LIBEXT=dylib
+ ;;
+ aix)
+ echo_n " aix-device"
+ echo >>$c '#define PCI_HAVE_PM_AIX_DEVICE'
+ echo >>$m 'CFLAGS=-g'
+ echo >>$m 'INSTALL=installbsd'
+ echo >>$m 'DIRINSTALL=mkdir -p'
+ ;;
+ netbsd)
+ echo_n " nbsd-libpci"
+ echo >>$c '#define PCI_HAVE_PM_NBSD_LIBPCI'
+ echo >>$c '#define PCI_PATH_NBSD_DEVICE "/dev/pci0"'
+ echo >>$c '#define PCI_HAVE_64BIT_ADDRESS'
+ echo >>$m 'LIBNAME=libpciutils'
+ echo >>$m 'WITH_LIBS+=-lpci'
+ LIBRESOLV=
+ ;;
+ gnu)
+ echo_n " hurd i386-ports"
+ echo >>$c '#define PCI_HAVE_PM_HURD_CONF'
+ echo >>$c '#define PCI_HAVE_PM_INTEL_CONF'
+ ;;
+ djgpp)
+ echo_n " i386-ports"
+ echo >>$c '#define PCI_HAVE_PM_INTEL_CONF'
+ ;;
+ cygwin)
+ echo_n " i386-ports"
+ echo >>$c '#define PCI_HAVE_PM_INTEL_CONF'
+ echo >>$m 'WITH_LIBS+=-lioperm'
+ ;;
+ beos|haiku)
+ case $cpu in
+ i?86|x86_64) echo_n " i386-ports"
+ echo >>$c '#define PCI_HAVE_PM_INTEL_CONF'
+ ;;
+ esac
+ echo >>$c '#define PCI_HAVE_STDINT_H'
+ ;;
+ sylixos)
+ echo >>$c '#define PCI_PATH_SYLIXOS_DEVICE "/proc/pci"'
+ echo >>$c '#define PCI_HAVE_64BIT_ADDRESS'
+ echo >>$c '#define PCI_HAVE_PM_SYLIXOS_DEVICE'
+ IDSDIR="/etc/pci"
+ LIBRESOLV=
+ ;;
+ *)
+ echo " Unfortunately, your OS is not supported by the PCI Library"
+ exit 1
+ ;;
+esac
+
+echo >>$m "LIBEXT="$LIBEXT
+echo >>$c '#define PCI_HAVE_PM_DUMP'
+echo " dump"
+
+echo_n "Checking for zlib support... "
+if [ "$ZLIB" = yes -o "$ZLIB" = no ] ; then
+ echo "$ZLIB (set manually)"
+else
+ if [ -f /usr/include/zlib.h -o -f /usr/local/include/zlib.h ] ; then
+ ZLIB=yes
+ else
+ ZLIB=no
+ fi
+ echo "$ZLIB (auto-detected)"
+fi
+if [ "$ZLIB" = yes ] ; then
+ echo >>$c '#define PCI_COMPRESSED_IDS'
+ echo >>$c '#define PCI_IDS "pci.ids.gz"'
+ echo >>$m 'LIBZ=-lz'
+ echo >>$m 'WITH_LIBS+=$(LIBZ)'
+else
+ echo >>$c '#define PCI_IDS "pci.ids"'
+fi
+echo >>$c "#define PCI_PATH_IDS_DIR \"$IDSDIR\""
+
+echo_n "Checking for DNS support... "
+if [ "$DNS" = yes -o "$DNS" = no ] ; then
+ echo "$DNS (set manually)"
+else
+ if [ -f /usr/include/resolv.h ] ; then
+ DNS=yes
+ else
+ DNS=no
+ fi
+ echo "$DNS (auto-detected)"
+fi
+if [ "$DNS" = yes ] ; then
+ echo >>$c "#define PCI_USE_DNS"
+ echo >>$c "#define PCI_ID_DOMAIN \"pci.id.ucw.cz\""
+ echo >>$m "WITH_LIBS+=$LIBRESOLV"
+fi
+
+if [ "$sys" = linux ] ; then
+ echo_n "Checking for libkmod... "
+ LIBKMOD_DETECTED=
+ if [ -z "$PKG_CONFIG" ] ; then
+ PKG_CONFIG=pkg-config
+ fi
+ if [ "$LIBKMOD" != no ] ; then
+ if ! which $PKG_CONFIG >/dev/null ; then
+ echo_n "($PKG_CONFIG not found) "
+ elif $PKG_CONFIG libkmod ; then
+ LIBKMOD_DETECTED=1
+ fi
+ fi
+ if [ "$LIBKMOD" = yes -o "$LIBKMOD" = no ] ; then
+ echo "$LIBKMOD (set manually)"
+ if [ "$LIBKMOD" = yes -a -z "$LIBKMOD_DETECTED" ] ; then
+ echo "Requested use of libkmod, but it is not available. Giving up."
+ exit 1
+ fi
+ else
+ if [ -n "$LIBKMOD_DETECTED" ] ; then
+ LIBKMOD=yes
+ else
+ LIBKMOD=no
+ fi
+ echo "$LIBKMOD (auto-detected)"
+ fi
+ if [ "$LIBKMOD" = yes ] ; then
+ echo >>$c "#define PCI_USE_LIBKMOD"
+ echo >>$m "LIBKMOD_CFLAGS=$($PKG_CONFIG --cflags libkmod)"
+ echo >>$m "LIBKMOD_LIBS=$($PKG_CONFIG --libs libkmod)"
+ fi
+
+ echo_n "Checking for udev hwdb support... "
+ if [ "$HWDB" = yes -o "$HWDB" = no ] ; then
+ echo "$HWDB (set manually)"
+ else
+ if `which pkg-config >/dev/null && pkg-config --atleast-version=196 libudev` ; then
+ HWDB=yes
+ else
+ HWDB=no
+ fi
+ echo "$HWDB (auto-detected)"
+ fi
+ if [ "$HWDB" = yes ] ; then
+ echo >>$c '#define PCI_HAVE_HWDB'
+ echo >>$m 'LIBUDEV=-ludev'
+ echo >>$m 'WITH_LIBS+=$(LIBUDEV)'
+ fi
+fi
+
+echo "Checking whether to build a shared library... $SHARED (set manually)"
+if [ "$SHARED" = no ] ; then
+ echo >>$m 'PCILIB=$(LIBNAME).a'
+ echo >>$m 'LDLIBS=$(WITH_LIBS)'
+ echo >>$m 'LIB_LDLIBS='
+else
+ if [ "$LIBEXT" = so ]; then
+ echo >>$m 'PCILIB=$(LIBNAME).$(LIBEXT).$(VERSION)'
+ else
+ echo >>$m 'PCILIB=$(LIBNAME).$(VERSION).$(LIBEXT)'
+ fi
+ # We link the dependencies _to_ the library, so we do not need explicit deps in .pc
+ echo >>$m 'LDLIBS='
+ echo >>$m 'LIB_LDLIBS=$(WITH_LIBS)'
+ echo >>$c '#define PCI_SHARED_LIB'
+ if [ "$SHARED" = yes -a "$LIBEXT" = so ]; then
+ echo >>$m 'SONAME=-Wl,-soname,$(LIBNAME).$(LIBEXT)$(ABI_VERSION)'
+ fi
+fi
+echo >>$m 'PCILIBPC=$(LIBNAME).pc'
+
+echo >>$c "#define PCILIB_VERSION \"$VERSION\""
+sed '/"/{s/^#define \([^ ]*\) "\(.*\)"$/\1=\2/;p;d;};s/^#define \(.*\)/\1=1/' <$c >>$m
diff --git a/lib/darwin.c b/lib/darwin.c
new file mode 100644
index 0000000..9167393
--- /dev/null
+++ b/lib/darwin.c
@@ -0,0 +1,211 @@
+/*
+ * The PCI Library -- Darwin kIOACPI access
+ *
+ * Copyright (c) 2013 Apple, Inc.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "internal.h"
+
+#include <mach/mach_error.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOKitKeys.h>
+
+enum {
+ kACPIMethodAddressSpaceRead = 0,
+ kACPIMethodAddressSpaceWrite = 1,
+ kACPIMethodDebuggerCommand = 2,
+ kACPIMethodCount
+};
+
+#pragma pack(1)
+
+typedef UInt32 IOACPIAddressSpaceID;
+
+enum {
+ kIOACPIAddressSpaceIDSystemMemory = 0,
+ kIOACPIAddressSpaceIDSystemIO = 1,
+ kIOACPIAddressSpaceIDPCIConfiguration = 2,
+ kIOACPIAddressSpaceIDEmbeddedController = 3,
+ kIOACPIAddressSpaceIDSMBus = 4
+};
+
+/*
+ * 64-bit ACPI address
+ */
+union IOACPIAddress {
+ UInt64 addr64;
+ struct {
+ unsigned int offset :16;
+ unsigned int function :3;
+ unsigned int device :5;
+ unsigned int bus :8;
+ unsigned int segment :16;
+ unsigned int reserved :16;
+ } pci;
+};
+typedef union IOACPIAddress IOACPIAddress;
+
+#pragma pack()
+
+struct AddressSpaceParam {
+ UInt64 value;
+ UInt32 spaceID;
+ IOACPIAddress address;
+ UInt32 bitWidth;
+ UInt32 bitOffset;
+ UInt32 options;
+};
+typedef struct AddressSpaceParam AddressSpaceParam;
+
+static void
+darwin_config(struct pci_access *a UNUSED)
+{
+}
+
+static int
+darwin_detect(struct pci_access *a)
+{
+ io_registry_entry_t service;
+ io_connect_t connect;
+ kern_return_t status;
+
+ service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleACPIPlatformExpert"));
+ if (service)
+ {
+ status = IOServiceOpen(service, mach_task_self(), 0, &connect);
+ IOObjectRelease(service);
+ }
+
+ if (!service || (kIOReturnSuccess != status))
+ {
+ a->warning("Cannot open AppleACPIPlatformExpert (add boot arg debug=0x144 & run as root)");
+ return 0;
+ }
+ a->debug("...using AppleACPIPlatformExpert");
+ a->fd = connect;
+ return 1;
+}
+
+static void
+darwin_init(struct pci_access *a UNUSED)
+{
+}
+
+static void
+darwin_cleanup(struct pci_access *a UNUSED)
+{
+}
+
+static int
+darwin_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ if (!(len == 1 || len == 2 || len == 4))
+ return pci_generic_block_read(d, pos, buf, len);
+
+ AddressSpaceParam param;
+ kern_return_t status;
+
+ param.spaceID = kIOACPIAddressSpaceIDPCIConfiguration;
+ param.bitWidth = len * 8;
+ param.bitOffset = 0;
+ param.options = 0;
+
+ param.address.pci.offset = pos;
+ param.address.pci.function = d->func;
+ param.address.pci.device = d->dev;
+ param.address.pci.bus = d->bus;
+ param.address.pci.segment = d->domain;
+ param.address.pci.reserved = 0;
+ param.value = -1ULL;
+
+ size_t outSize = sizeof(param);
+ status = IOConnectCallStructMethod(d->access->fd, kACPIMethodAddressSpaceRead,
+ &param, sizeof(param),
+ &param, &outSize);
+ if ((kIOReturnSuccess != status))
+ d->access->error("darwin_read: kACPIMethodAddressSpaceRead failed: %s", mach_error_string(status));
+
+ switch (len)
+ {
+ case 1:
+ buf[0] = (u8) param.value;
+ break;
+ case 2:
+ ((u16 *) buf)[0] = cpu_to_le16((u16) param.value);
+ break;
+ case 4:
+ ((u32 *) buf)[0] = cpu_to_le32((u32) param.value);
+ break;
+ }
+ return 1;
+}
+
+static int
+darwin_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ if (!(len == 1 || len == 2 || len == 4))
+ return pci_generic_block_write(d, pos, buf, len);
+
+ AddressSpaceParam param;
+ kern_return_t status;
+
+ param.spaceID = kIOACPIAddressSpaceIDPCIConfiguration;
+ param.bitWidth = len * 8;
+ param.bitOffset = 0;
+ param.options = 0;
+
+ param.address.pci.offset = pos;
+ param.address.pci.function = d->func;
+ param.address.pci.device = d->dev;
+ param.address.pci.bus = d->bus;
+ param.address.pci.segment = d->domain;
+ param.address.pci.reserved = 0;
+
+ switch (len)
+ {
+ case 1:
+ param.value = buf[0];
+ break;
+ case 2:
+ param.value = le16_to_cpu(((u16 *) buf)[0]);
+ break;
+ case 4:
+ param.value = le32_to_cpu(((u32 *) buf)[0]);
+ break;
+ }
+
+ size_t outSize = 0;
+ status = IOConnectCallStructMethod(d->access->fd, kACPIMethodAddressSpaceWrite,
+ &param, sizeof(param),
+ NULL, &outSize);
+ if ((kIOReturnSuccess != status))
+ d->access->error("darwin_read: kACPIMethodAddressSpaceWrite failed: %s", mach_error_string(status));
+
+ return 1;
+}
+
+struct pci_methods pm_darwin = {
+ "darwin",
+ "Darwin",
+ darwin_config,
+ darwin_detect,
+ darwin_init,
+ darwin_cleanup,
+ pci_generic_scan,
+ pci_generic_fill_info,
+ darwin_read,
+ darwin_write,
+ NULL, /* read_vpd */
+ NULL, /* dev_init */
+ NULL /* dev_cleanup */
+};
diff --git a/lib/dump.c b/lib/dump.c
new file mode 100644
index 0000000..59cf7ed
--- /dev/null
+++ b/lib/dump.c
@@ -0,0 +1,189 @@
+/*
+ * The PCI Library -- Reading of Bus Dumps
+ *
+ * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include "internal.h"
+
+struct dump_data {
+ int len, allocated;
+ byte data[1];
+};
+
+static void
+dump_config(struct pci_access *a)
+{
+ pci_define_param(a, "dump.name", "", "Name of the bus dump file to read from");
+}
+
+static int
+dump_detect(struct pci_access *a)
+{
+ char *name = pci_get_param(a, "dump.name");
+ return name && name[0];
+}
+
+static void
+dump_alloc_data(struct pci_dev *dev, int len)
+{
+ struct dump_data *dd = pci_malloc(dev->access, sizeof(struct dump_data) + len - 1);
+ dd->allocated = len;
+ dd->len = 0;
+ memset(dd->data, 0xff, len);
+ dev->aux = dd;
+}
+
+static int
+dump_validate(char *s, char *fmt)
+{
+ while (*fmt)
+ {
+ if (*fmt == '#' ? !isxdigit(*s) : *fmt != *s)
+ return 0;
+ fmt++, s++;
+ }
+ return 1;
+}
+
+static void
+dump_init(struct pci_access *a)
+{
+ char *name = pci_get_param(a, "dump.name");
+ FILE *f;
+ char buf[256];
+ struct pci_dev *dev = NULL;
+ int len, mn, bn, dn, fn, i, j;
+
+ if (!name)
+ a->error("dump: File name not given.");
+ if (!(f = fopen(name, "r")))
+ a->error("dump: Cannot open %s: %s", name, strerror(errno));
+ while (fgets(buf, sizeof(buf)-1, f))
+ {
+ char *z = strchr(buf, '\n');
+ if (!z)
+ {
+ fclose(f);
+ a->error("dump: line too long or unterminated");
+ }
+ *z-- = 0;
+ if (z >= buf && *z == '\r')
+ *z-- = 0;
+ len = z - buf + 1;
+ mn = 0;
+ if (dump_validate(buf, "##:##.# ") && sscanf(buf, "%x:%x.%d", &bn, &dn, &fn) == 3 ||
+ dump_validate(buf, "####:##:##.# ") && sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4)
+ {
+ dev = pci_get_dev(a, mn, bn, dn, fn);
+ dump_alloc_data(dev, 256);
+ pci_link_dev(a, dev);
+ }
+ else if (!len)
+ dev = NULL;
+ else if (dev &&
+ (dump_validate(buf, "##: ") || dump_validate(buf, "###: ")) &&
+ sscanf(buf, "%x: ", &i) == 1)
+ {
+ struct dump_data *dd = dev->aux;
+ z = strchr(buf, ' ') + 1;
+ while (isxdigit(z[0]) && isxdigit(z[1]) && (!z[2] || z[2] == ' ') &&
+ sscanf(z, "%x", &j) == 1 && j < 256)
+ {
+ if (i >= 4096)
+ {
+ fclose(f);
+ a->error("dump: At most 4096 bytes of config space are supported");
+ }
+ if (i >= dd->allocated) /* Need to re-allocate the buffer */
+ {
+ dump_alloc_data(dev, 4096);
+ memcpy(((struct dump_data *) dev->aux)->data, dd->data, 256);
+ pci_mfree(dd);
+ dd = dev->aux;
+ }
+ dd->data[i++] = j;
+ if (i > dd->len)
+ dd->len = i;
+ z += 2;
+ if (*z)
+ z++;
+ }
+ if (*z)
+ {
+ fclose(f);
+ a->error("dump: Malformed line");
+ }
+ }
+ }
+ fclose(f);
+}
+
+static void
+dump_cleanup(struct pci_access *a UNUSED)
+{
+}
+
+static void
+dump_scan(struct pci_access *a UNUSED)
+{
+}
+
+static int
+dump_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ struct dump_data *dd;
+ if (!(dd = d->aux))
+ {
+ struct pci_dev *e = d->access->devices;
+ while (e && (e->domain != d->domain || e->bus != d->bus || e->dev != d->dev || e->func != d->func))
+ e = e->next;
+ if (!e)
+ return 0;
+ dd = e->aux;
+ }
+ if (pos + len > dd->len)
+ return 0;
+ memcpy(buf, dd->data + pos, len);
+ return 1;
+}
+
+static int
+dump_write(struct pci_dev *d UNUSED, int pos UNUSED, byte *buf UNUSED, int len UNUSED)
+{
+ d->access->error("Writing to dump files is not supported.");
+ return 0;
+}
+
+static void
+dump_cleanup_dev(struct pci_dev *d)
+{
+ if (d->aux)
+ {
+ pci_mfree(d->aux);
+ d->aux = NULL;
+ }
+}
+
+struct pci_methods pm_dump = {
+ "dump",
+ "Reading of register dumps (set the `dump.name' parameter)",
+ dump_config,
+ dump_detect,
+ dump_init,
+ dump_cleanup,
+ dump_scan,
+ pci_generic_fill_info,
+ dump_read,
+ dump_write,
+ NULL, /* read_vpd */
+ NULL, /* init_dev */
+ dump_cleanup_dev
+};
diff --git a/lib/fbsd-device.c b/lib/fbsd-device.c
new file mode 100644
index 0000000..cffab69
--- /dev/null
+++ b/lib/fbsd-device.c
@@ -0,0 +1,369 @@
+/*
+ * The PCI Library -- FreeBSD /dev/pci access
+ *
+ * Copyright (c) 1999 Jari Kirma <kirma@cs.hut.fi>
+ * Updated in 2003 by Samy Al Bahra <samy@kerneled.com>
+ * Updated in 2017 by Imre Vadász <imrevdsz@gmail.com>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <osreldate.h>
+#include <stdint.h>
+
+#ifdef __FreeBSD_kernel_version
+# ifndef __FreeBSD_version
+# define __FreeBSD_version __FreeBSD_kernel_version
+# endif
+#endif
+
+#if __FreeBSD_version < 430000 && !defined(__DragonFly__)
+# include <pci/pcivar.h>
+# include <pci/pci_ioctl.h>
+#else
+# include <sys/pciio.h>
+#endif
+
+#include "internal.h"
+
+static void
+fbsd_config(struct pci_access *a)
+{
+ pci_define_param(a, "fbsd.path", PCI_PATH_FBSD_DEVICE, "Path to the FreeBSD PCI device");
+}
+
+static int
+fbsd_detect(struct pci_access *a)
+{
+ char *name = pci_get_param(a, "fbsd.path");
+
+ if (access(name, R_OK))
+ {
+ a->warning("Cannot open %s", name);
+ return 0;
+ }
+ a->debug("...using %s", name);
+ return 1;
+}
+
+static void
+fbsd_init(struct pci_access *a)
+{
+ char *name = pci_get_param(a, "fbsd.path");
+ int fd;
+
+ a->fd = -1;
+ a->fd_rw = -1;
+ /*
+ * When opening /dev/pci as read-write fails, retry with readonly which
+ * will still allow us to gain some information via the PCIOCGETCONF and
+ * PCIOCGETBAR IOCTLs, even without generic read access to the PCI config
+ * space.
+ */
+ fd = open(name, O_RDWR, 0);
+ if (fd < 0)
+ {
+ fd = open(name, O_RDONLY, 0);
+ if (fd < 0)
+ a->error("fbsd_init: %s open failed", name);
+ else
+ {
+ a->debug("fbsd_init: Fallback to read-only opened %s", name);
+ a->fd = fd;
+ }
+ }
+ else
+ a->fd_rw = fd;
+}
+
+static void
+fbsd_cleanup(struct pci_access *a)
+{
+ if (a->fd >= 0)
+ {
+ close(a->fd);
+ a->fd = -1;
+ }
+ if (a->fd_rw >= 0)
+ {
+ close(a->fd_rw);
+ a->fd_rw = -1;
+ }
+}
+
+static void
+fbsd_scan(struct pci_access *a)
+{
+ struct pci_conf_io conf;
+ struct pci_conf *matches;
+ struct pci_dev *t;
+ uint32_t offset = 0;
+ unsigned int i;
+
+ matches = calloc(32, sizeof(struct pci_conf));
+ if (matches == NULL)
+ {
+ a->error("calloc: %s", strerror(errno));
+ return;
+ }
+
+ conf.generation = 0;
+ do
+ {
+ conf.pat_buf_len = 0;
+ conf.num_patterns = 0;
+ conf.patterns = NULL;
+ conf.match_buf_len = 32 * sizeof(struct pci_conf);
+ conf.num_matches = 32;
+ conf.matches = matches;
+ conf.offset = offset;
+ conf.status = 0;
+ if (ioctl(a->fd_rw >= 0 ? a->fd_rw : a->fd, PCIOCGETCONF, &conf) < 0)
+ {
+ if (errno == ENODEV)
+ break;
+ a->error("fbsd_scan: ioctl(PCIOCGETCONF) failed: %s",
+ strerror(errno));
+ }
+ /* PCI_GETCONF_LIST_CHANGED would require us to start over. */
+ if (conf.status == PCI_GETCONF_ERROR ||
+ conf.status == PCI_GETCONF_LIST_CHANGED)
+ {
+ a->error("fbsd_scan: ioctl(PCIOCGETCONF) failed");
+ break;
+ }
+ for (i = 0; i < conf.num_matches; i++)
+ {
+ t = pci_alloc_dev(a);
+ t->bus = matches[i].pc_sel.pc_bus;
+ t->dev = matches[i].pc_sel.pc_dev;
+ t->func = matches[i].pc_sel.pc_func;
+ t->domain = matches[i].pc_sel.pc_domain;
+ t->domain_16 = matches[i].pc_sel.pc_domain;
+ t->vendor_id = matches[i].pc_vendor;
+ t->device_id = matches[i].pc_device;
+ t->known_fields = PCI_FILL_IDENT;
+ t->hdrtype = matches[i].pc_hdr;
+ pci_link_dev(a, t);
+ }
+ offset += conf.num_matches;
+ }
+ while (conf.status == PCI_GETCONF_MORE_DEVS);
+
+ free(matches);
+}
+
+static int
+fbsd_fill_info(struct pci_dev *d, int flags)
+{
+ struct pci_conf_io conf;
+ struct pci_bar_io bar;
+ struct pci_match_conf pattern;
+ struct pci_conf match;
+ int i;
+
+ if (d->access->fd_rw >= 0)
+ return pci_generic_fill_info(d, flags);
+
+ /*
+ * Can only handle PCI_FILL_IDENT, PCI_FILL_CLASS, PCI_FILL_BASES and
+ * PCI_FILL_SIZES requests with the PCIOCGETCONF and PCIOCGETBAR IOCTLs.
+ */
+
+ conf.pat_buf_len = sizeof(struct pci_match_conf);
+ conf.num_patterns = 1;
+ conf.patterns = &pattern;
+ conf.match_buf_len = sizeof(struct pci_conf);
+ conf.num_matches = 1;
+ conf.matches = &match;
+ conf.offset = 0;
+ conf.generation = 0;
+ conf.status = 0;
+
+ pattern.pc_sel.pc_domain = d->domain;
+ pattern.pc_sel.pc_bus = d->bus;
+ pattern.pc_sel.pc_dev = d->dev;
+ pattern.pc_sel.pc_func = d->func;
+ pattern.flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS |
+ PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC;
+
+ if (ioctl(d->access->fd, PCIOCGETCONF, &conf) < 0)
+ {
+ if (errno == ENODEV)
+ return 0;
+ d->access->error("fbsd_fill_info: ioctl(PCIOCGETCONF) failed: %s", strerror(errno));
+ }
+
+ if (flags & PCI_FILL_IDENT)
+ {
+ d->vendor_id = match.pc_vendor;
+ d->device_id = match.pc_device;
+ }
+ if (flags & PCI_FILL_CLASS)
+ {
+ d->device_class = (match.pc_class << 8) | match.pc_subclass;
+ }
+ if (flags & (PCI_FILL_BASES | PCI_FILL_SIZES))
+ {
+ d->rom_base_addr = 0;
+ d->rom_size = 0;
+ for (i = 0; i < 6; i++)
+ {
+ bar.pbi_sel.pc_domain = d->domain;
+ bar.pbi_sel.pc_bus = d->bus;
+ bar.pbi_sel.pc_dev = d->dev;
+ bar.pbi_sel.pc_func = d->func;
+ bar.pbi_reg = 0x10 + 4*i;
+ bar.pbi_enabled = 0;
+ bar.pbi_base = 0;
+ bar.pbi_length = 0;
+ if (ioctl(d->access->fd, PCIOCGETBAR, &bar) < 0)
+ {
+ if (errno == ENODEV)
+ return 0;
+ if (errno == EINVAL)
+ {
+ d->base_addr[i] = 0;
+ d->size[i] = 0;
+ }
+ else
+ d->access->error("fbsd_fill_info: ioctl(PCIOCGETBAR) failed: %s", strerror(errno));
+ }
+ else
+ {
+ d->base_addr[i] = bar.pbi_base;
+ d->size[i] = bar.pbi_length;
+ }
+ }
+ }
+
+ return flags & (PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_BASES |
+ PCI_FILL_SIZES);
+}
+
+static int
+fbsd_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ struct pci_io pi;
+
+ if (d->access->fd_rw < 0)
+ {
+ d->access->warning("fbsd_read: missing permissions");
+ return 0;
+ }
+
+ if (!(len == 1 || len == 2 || len == 4))
+ return pci_generic_block_read(d, pos, buf, len);
+
+ if (pos >= 4096)
+ return 0;
+
+#if __FreeBSD_version >= 700053 || defined(__DragonFly__)
+ pi.pi_sel.pc_domain = d->domain;
+#else
+ if (d->domain)
+ return 0;
+#endif
+ pi.pi_sel.pc_bus = d->bus;
+ pi.pi_sel.pc_dev = d->dev;
+ pi.pi_sel.pc_func = d->func;
+
+ pi.pi_reg = pos;
+ pi.pi_width = len;
+
+ if (ioctl(d->access->fd_rw, PCIOCREAD, &pi) < 0)
+ {
+ if (errno == ENODEV)
+ return 0;
+ d->access->error("fbsd_read: ioctl(PCIOCREAD) failed: %s", strerror(errno));
+ }
+
+ switch (len)
+ {
+ case 1:
+ buf[0] = (u8) pi.pi_data;
+ break;
+ case 2:
+ ((u16 *) buf)[0] = cpu_to_le16((u16) pi.pi_data);
+ break;
+ case 4:
+ ((u32 *) buf)[0] = cpu_to_le32((u32) pi.pi_data);
+ break;
+ }
+ return 1;
+}
+
+static int
+fbsd_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ struct pci_io pi;
+
+ if (d->access->fd_rw < 0)
+ {
+ d->access->warning("fbsd_write: missing permissions");
+ return 0;
+ }
+
+ if (!(len == 1 || len == 2 || len == 4))
+ return pci_generic_block_write(d, pos, buf, len);
+
+ if (pos >= 4096)
+ return 0;
+
+#if __FreeBSD_version >= 700053 || defined(__DragonFly__)
+ pi.pi_sel.pc_domain = d->domain;
+#else
+ if (d->domain)
+ return 0;
+#endif
+ pi.pi_sel.pc_bus = d->bus;
+ pi.pi_sel.pc_dev = d->dev;
+ pi.pi_sel.pc_func = d->func;
+
+ pi.pi_reg = pos;
+ pi.pi_width = len;
+
+ switch (len)
+ {
+ case 1:
+ pi.pi_data = buf[0];
+ break;
+ case 2:
+ pi.pi_data = le16_to_cpu(((u16 *) buf)[0]);
+ break;
+ case 4:
+ pi.pi_data = le32_to_cpu(((u32 *) buf)[0]);
+ break;
+ }
+
+ if (ioctl(d->access->fd_rw, PCIOCWRITE, &pi) < 0)
+ {
+ if (errno == ENODEV)
+ return 0;
+ d->access->error("fbsd_write: ioctl(PCIOCWRITE) failed: %s", strerror(errno));
+ }
+
+ return 1;
+}
+
+struct pci_methods pm_fbsd_device = {
+ "fbsd-device",
+ "FreeBSD /dev/pci device",
+ fbsd_config,
+ fbsd_detect,
+ fbsd_init,
+ fbsd_cleanup,
+ fbsd_scan,
+ fbsd_fill_info,
+ fbsd_read,
+ fbsd_write,
+ NULL, /* read_vpd */
+ NULL, /* dev_init */
+ NULL /* dev_cleanup */
+};
diff --git a/lib/filter.c b/lib/filter.c
new file mode 100644
index 0000000..573fb28
--- /dev/null
+++ b/lib/filter.c
@@ -0,0 +1,240 @@
+/*
+ * The PCI Library -- Device Filtering
+ *
+ * Copyright (c) 1998--2014 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "internal.h"
+
+void pci_filter_init_v33(struct pci_access *a UNUSED, struct pci_filter *f) VERSIONED_ABI;
+char *pci_filter_parse_slot_v33(struct pci_filter *f, char *str) VERSIONED_ABI;
+char *pci_filter_parse_id_v33(struct pci_filter *f, char *str) VERSIONED_ABI;
+int pci_filter_match_v33(struct pci_filter *f, struct pci_dev *d) VERSIONED_ABI;
+
+void
+pci_filter_init_v33(struct pci_access *a UNUSED, struct pci_filter *f)
+{
+ f->domain = f->bus = f->slot = f->func = -1;
+ f->vendor = f->device = f->device_class = -1;
+}
+
+/* Slot filter syntax: [[[domain]:][bus]:][slot][.[func]] */
+
+char *
+pci_filter_parse_slot_v33(struct pci_filter *f, char *str)
+{
+ char *colon = strrchr(str, ':');
+ char *dot = strchr((colon ? colon + 1 : str), '.');
+ char *mid = str;
+ char *e, *bus, *colon2;
+
+ if (colon)
+ {
+ *colon++ = 0;
+ mid = colon;
+ colon2 = strchr(str, ':');
+ if (colon2)
+ {
+ *colon2++ = 0;
+ bus = colon2;
+ if (str[0] && strcmp(str, "*"))
+ {
+ long int x = strtol(str, &e, 16);
+ if ((e && *e) || (x < 0 || x > 0x7fffffff))
+ return "Invalid domain number";
+ f->domain = x;
+ }
+ }
+ else
+ bus = str;
+ if (bus[0] && strcmp(bus, "*"))
+ {
+ long int x = strtol(bus, &e, 16);
+ if ((e && *e) || (x < 0 || x > 0xff))
+ return "Invalid bus number";
+ f->bus = x;
+ }
+ }
+ if (dot)
+ *dot++ = 0;
+ if (mid[0] && strcmp(mid, "*"))
+ {
+ long int x = strtol(mid, &e, 16);
+ if ((e && *e) || (x < 0 || x > 0x1f))
+ return "Invalid slot number";
+ f->slot = x;
+ }
+ if (dot && dot[0] && strcmp(dot, "*"))
+ {
+ long int x = strtol(dot, &e, 16);
+ if ((e && *e) || (x < 0 || x > 7))
+ return "Invalid function number";
+ f->func = x;
+ }
+ return NULL;
+}
+
+/* ID filter syntax: [vendor]:[device][:class] */
+
+char *
+pci_filter_parse_id_v33(struct pci_filter *f, char *str)
+{
+ char *s, *c, *e;
+
+ if (!*str)
+ return NULL;
+ s = strchr(str, ':');
+ if (!s)
+ return "':' expected";
+ *s++ = 0;
+ if (str[0] && strcmp(str, "*"))
+ {
+ long int x = strtol(str, &e, 16);
+ if ((e && *e) || (x < 0 || x > 0xffff))
+ return "Invalid vendor ID";
+ f->vendor = x;
+ }
+ c = strchr(s, ':');
+ if (c)
+ *c++ = 0;
+ if (s[0] && strcmp(s, "*"))
+ {
+ long int x = strtol(s, &e, 16);
+ if ((e && *e) || (x < 0 || x > 0xffff))
+ return "Invalid device ID";
+ f->device = x;
+ }
+ if (c && c[0] && strcmp(s, "*"))
+ {
+ long int x = strtol(c, &e, 16);
+ if ((e && *e) || (x < 0 || x > 0xffff))
+ return "Invalid class code";
+ f->device_class = x;
+ }
+ return NULL;
+}
+
+int
+pci_filter_match_v33(struct pci_filter *f, struct pci_dev *d)
+{
+ if ((f->domain >= 0 && f->domain != d->domain) ||
+ (f->bus >= 0 && f->bus != d->bus) ||
+ (f->slot >= 0 && f->slot != d->dev) ||
+ (f->func >= 0 && f->func != d->func))
+ return 0;
+ if (f->device >= 0 || f->vendor >= 0)
+ {
+ pci_fill_info_v35(d, PCI_FILL_IDENT);
+ if ((f->device >= 0 && f->device != d->device_id) ||
+ (f->vendor >= 0 && f->vendor != d->vendor_id))
+ return 0;
+ }
+ if (f->device_class >= 0)
+ {
+ pci_fill_info(d, PCI_FILL_CLASS);
+ if (f->device_class != d->device_class)
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Before pciutils v3.3, struct pci_filter had fewer fields,
+ * so we have to provide compatibility wrappers.
+ */
+
+struct pci_filter_v30 {
+ int domain, bus, slot, func; /* -1 = ANY */
+ int vendor, device;
+};
+
+void pci_filter_init_v30(struct pci_access *a, struct pci_filter_v30 *f) VERSIONED_ABI;
+char *pci_filter_parse_slot_v30(struct pci_filter_v30 *f, char *str) VERSIONED_ABI;
+char *pci_filter_parse_id_v30(struct pci_filter_v30 *f, char *str) VERSIONED_ABI;
+int pci_filter_match_v30(struct pci_filter_v30 *f, struct pci_dev *d) VERSIONED_ABI;
+
+static void
+pci_filter_import_v30(struct pci_filter_v30 *old, struct pci_filter *new)
+{
+ new->domain = old->domain;
+ new->bus = old->bus;
+ new->slot = old->slot;
+ new->func = old->func;
+ new->vendor = old->vendor;
+ new->device = old->device;
+ new->device_class = -1;
+}
+
+static void
+pci_filter_export_v30(struct pci_filter *new, struct pci_filter_v30 *old)
+{
+ old->domain = new->domain;
+ old->bus = new->bus;
+ old->slot = new->slot;
+ old->func = new->func;
+ old->vendor = new->vendor;
+ old->device = new->device;
+}
+
+void
+pci_filter_init_v30(struct pci_access *a, struct pci_filter_v30 *f)
+{
+ struct pci_filter new;
+ pci_filter_init_v33(a, &new);
+ pci_filter_export_v30(&new, f);
+}
+
+char *
+pci_filter_parse_slot_v30(struct pci_filter_v30 *f, char *str)
+{
+ struct pci_filter new;
+ char *err;
+ pci_filter_import_v30(f, &new);
+ if (err = pci_filter_parse_slot_v33(&new, str))
+ return err;
+ pci_filter_export_v30(&new, f);
+ return NULL;
+}
+
+char *
+pci_filter_parse_id_v30(struct pci_filter_v30 *f, char *str)
+{
+ struct pci_filter new;
+ char *err;
+ pci_filter_import_v30(f, &new);
+ if (err = pci_filter_parse_id_v33(&new, str))
+ return err;
+ if (new.device_class >= 0)
+ return "Filtering by class not supported in this program";
+ pci_filter_export_v30(&new, f);
+ return NULL;
+}
+
+int
+pci_filter_match_v30(struct pci_filter_v30 *f, struct pci_dev *d)
+{
+ struct pci_filter new;
+ pci_filter_import_v30(f, &new);
+ return pci_filter_match_v33(&new, d);
+}
+
+STATIC_ALIAS(void pci_filter_init(struct pci_access *a, struct pci_filter *f), pci_filter_init_v33(a, f));
+SYMBOL_VERSION(pci_filter_init_v30, pci_filter_init@LIBPCI_3.0);
+SYMBOL_VERSION(pci_filter_init_v33, pci_filter_init@@LIBPCI_3.3);
+
+STATIC_ALIAS(char *pci_filter_parse_slot(struct pci_filter *f, char *str), pci_filter_parse_slot_v33(f, str));
+SYMBOL_VERSION(pci_filter_parse_slot_v30, pci_filter_parse_slot@LIBPCI_3.0);
+SYMBOL_VERSION(pci_filter_parse_slot_v33, pci_filter_parse_slot@@LIBPCI_3.3);
+
+STATIC_ALIAS(char *pci_filter_parse_id(struct pci_filter *f, char *str), pci_filter_parse_id_v33(f, str));
+SYMBOL_VERSION(pci_filter_parse_id_v30, pci_filter_parse_id@LIBPCI_3.0);
+SYMBOL_VERSION(pci_filter_parse_id_v33, pci_filter_parse_id@@LIBPCI_3.3);
+
+STATIC_ALIAS(int pci_filter_match(struct pci_filter *f, struct pci_dev *d), pci_filter_match_v33(f, d));
+SYMBOL_VERSION(pci_filter_match_v30, pci_filter_match@LIBPCI_3.0);
+SYMBOL_VERSION(pci_filter_match_v33, pci_filter_match@@LIBPCI_3.3);
diff --git a/lib/generic.c b/lib/generic.c
new file mode 100644
index 0000000..ef9e2a3
--- /dev/null
+++ b/lib/generic.c
@@ -0,0 +1,225 @@
+/*
+ * The PCI Library -- Generic Direct Access Functions
+ *
+ * Copyright (c) 1997--2000 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <string.h>
+
+#include "internal.h"
+
+void
+pci_generic_scan_bus(struct pci_access *a, byte *busmap, int bus)
+{
+ int dev, multi, ht;
+ struct pci_dev *t;
+
+ a->debug("Scanning bus %02x for devices...\n", bus);
+ if (busmap[bus])
+ {
+ a->warning("Bus %02x seen twice (firmware bug). Ignored.", bus);
+ return;
+ }
+ busmap[bus] = 1;
+ t = pci_alloc_dev(a);
+ t->bus = bus;
+ for (dev=0; dev<32; dev++)
+ {
+ t->dev = dev;
+ multi = 0;
+ for (t->func=0; !t->func || multi && t->func<8; t->func++)
+ {
+ u32 vd = pci_read_long(t, PCI_VENDOR_ID);
+ struct pci_dev *d;
+
+ if (!vd || vd == 0xffffffff)
+ continue;
+ ht = pci_read_byte(t, PCI_HEADER_TYPE);
+ if (!t->func)
+ multi = ht & 0x80;
+ ht &= 0x7f;
+ d = pci_alloc_dev(a);
+ d->bus = t->bus;
+ d->dev = t->dev;
+ d->func = t->func;
+ d->vendor_id = vd & 0xffff;
+ d->device_id = vd >> 16U;
+ d->known_fields = PCI_FILL_IDENT;
+ d->hdrtype = ht;
+ pci_link_dev(a, d);
+ switch (ht)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ case PCI_HEADER_TYPE_CARDBUS:
+ pci_generic_scan_bus(a, busmap, pci_read_byte(t, PCI_SECONDARY_BUS));
+ break;
+ default:
+ a->debug("Device %04x:%02x:%02x.%d has unknown header type %02x.\n", d->domain, d->bus, d->dev, d->func, ht);
+ }
+ }
+ }
+ pci_free_dev(t);
+}
+
+void
+pci_generic_scan(struct pci_access *a)
+{
+ byte busmap[256];
+
+ memset(busmap, 0, sizeof(busmap));
+ pci_generic_scan_bus(a, busmap, 0);
+}
+
+unsigned int
+pci_generic_fill_info(struct pci_dev *d, unsigned int flags)
+{
+ struct pci_access *a = d->access;
+ unsigned int done = 0;
+
+ if ((flags & (PCI_FILL_BASES | PCI_FILL_ROM_BASE)) && d->hdrtype < 0)
+ d->hdrtype = pci_read_byte(d, PCI_HEADER_TYPE) & 0x7f;
+
+ if (flags & PCI_FILL_IDENT)
+ {
+ d->vendor_id = pci_read_word(d, PCI_VENDOR_ID);
+ d->device_id = pci_read_word(d, PCI_DEVICE_ID);
+ done |= PCI_FILL_IDENT;
+ }
+
+ if (flags & PCI_FILL_CLASS)
+ {
+ d->device_class = pci_read_word(d, PCI_CLASS_DEVICE);
+ done |= PCI_FILL_CLASS;
+ }
+
+ if (flags & PCI_FILL_IRQ)
+ {
+ d->irq = pci_read_byte(d, PCI_INTERRUPT_LINE);
+ done |= PCI_FILL_IRQ;
+ }
+
+ if (flags & PCI_FILL_BASES)
+ {
+ int cnt = 0, i;
+ memset(d->base_addr, 0, sizeof(d->base_addr));
+ switch (d->hdrtype)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ cnt = 6;
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ cnt = 2;
+ break;
+ case PCI_HEADER_TYPE_CARDBUS:
+ cnt = 1;
+ break;
+ }
+ if (cnt)
+ {
+ for (i=0; i<cnt; i++)
+ {
+ u32 x = pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4);
+ if (!x || x == (u32) ~0)
+ continue;
+ if ((x & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+ d->base_addr[i] = x;
+ else
+ {
+ if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) != PCI_BASE_ADDRESS_MEM_TYPE_64)
+ d->base_addr[i] = x;
+ else if (i >= cnt-1)
+ a->warning("%04x:%02x:%02x.%d: Invalid 64-bit address seen for BAR %d.", d->domain, d->bus, d->dev, d->func, i);
+ else
+ {
+ u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i)*4);
+#ifdef PCI_HAVE_64BIT_ADDRESS
+ d->base_addr[i-1] = x | (((pciaddr_t) y) << 32);
+#else
+ if (y)
+ a->warning("%04x:%02x:%02x.%d 64-bit device address ignored.", d->domain, d->bus, d->dev, d->func);
+ else
+ d->base_addr[i-1] = x;
+#endif
+ }
+ }
+ }
+ }
+ done |= PCI_FILL_BASES;
+ }
+
+ if (flags & PCI_FILL_ROM_BASE)
+ {
+ int reg = 0;
+ d->rom_base_addr = 0;
+ switch (d->hdrtype)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ reg = PCI_ROM_ADDRESS;
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ reg = PCI_ROM_ADDRESS1;
+ break;
+ }
+ if (reg)
+ {
+ u32 u = pci_read_long(d, reg);
+ if (u != 0xffffffff)
+ d->rom_base_addr = u;
+ }
+ done |= PCI_FILL_ROM_BASE;
+ }
+
+ if (flags & (PCI_FILL_CAPS | PCI_FILL_EXT_CAPS))
+ done |= pci_scan_caps(d, flags);
+
+ return done;
+}
+
+static int
+pci_generic_block_op(struct pci_dev *d, int pos, byte *buf, int len,
+ int (*r)(struct pci_dev *d, int pos, byte *buf, int len))
+{
+ if ((pos & 1) && len >= 1)
+ {
+ if (!r(d, pos, buf, 1))
+ return 0;
+ pos++; buf++; len--;
+ }
+ if ((pos & 3) && len >= 2)
+ {
+ if (!r(d, pos, buf, 2))
+ return 0;
+ pos += 2; buf += 2; len -= 2;
+ }
+ while (len >= 4)
+ {
+ if (!r(d, pos, buf, 4))
+ return 0;
+ pos += 4; buf += 4; len -= 4;
+ }
+ if (len >= 2)
+ {
+ if (!r(d, pos, buf, 2))
+ return 0;
+ pos += 2; buf += 2; len -= 2;
+ }
+ if (len && !r(d, pos, buf, 1))
+ return 0;
+ return 1;
+}
+
+int
+pci_generic_block_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ return pci_generic_block_op(d, pos, buf, len, d->access->methods->read);
+}
+
+int
+pci_generic_block_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ return pci_generic_block_op(d, pos, buf, len, d->access->methods->write);
+}
diff --git a/lib/header.h b/lib/header.h
new file mode 100644
index 0000000..472816e
--- /dev/null
+++ b/lib/header.h
@@ -0,0 +1,1395 @@
+/*
+ * The PCI Library -- PCI Header Structure (based on <linux/pci.h>)
+ *
+ * Copyright (c) 1997--2010 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+#define PCI_VENDOR_ID 0x00 /* 16 bits */
+#define PCI_DEVICE_ID 0x02 /* 16 bits */
+#define PCI_COMMAND 0x04 /* 16 bits */
+#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
+#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
+#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
+#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */
+#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */
+#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */
+#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */
+#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */
+#define PCI_COMMAND_SERR 0x100 /* Enable SERR */
+#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */
+#define PCI_COMMAND_DISABLE_INTx 0x400 /* PCIE: Disable INTx interrupts */
+
+#define PCI_STATUS 0x06 /* 16 bits */
+#define PCI_STATUS_INTx 0x08 /* PCIE: INTx interrupt pending */
+#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
+#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
+#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */
+#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
+#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
+#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
+#define PCI_STATUS_DEVSEL_FAST 0x000
+#define PCI_STATUS_DEVSEL_MEDIUM 0x200
+#define PCI_STATUS_DEVSEL_SLOW 0x400
+#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
+#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
+#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
+#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
+#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
+
+#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8
+ revision */
+#define PCI_REVISION_ID 0x08 /* Revision ID */
+#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE 0x0a /* Device class */
+
+#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
+#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
+#define PCI_HEADER_TYPE 0x0e /* 8 bits */
+#define PCI_HEADER_TYPE_NORMAL 0
+#define PCI_HEADER_TYPE_BRIDGE 1
+#define PCI_HEADER_TYPE_CARDBUS 2
+
+#define PCI_BIST 0x0f /* 8 bits */
+#define PCI_BIST_CODE_MASK 0x0f /* Return result */
+#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */
+#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of
+ * 0xffffffff to the register, and reading it back. Only
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
+#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
+#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
+#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
+#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */
+#define PCI_BASE_ADDRESS_SPACE_IO 0x01
+#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
+#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
+#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
+#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */
+#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
+#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
+#define PCI_BASE_ADDRESS_MEM_MASK (~(pciaddr_t)0x0f)
+#define PCI_BASE_ADDRESS_IO_MASK (~(pciaddr_t)0x03)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS 0x28
+#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
+#define PCI_SUBSYSTEM_ID 0x2e
+#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */
+#define PCI_ROM_ADDRESS_ENABLE 0x01
+#define PCI_ROM_ADDRESS_MASK (~(pciaddr_t)0x7ff)
+
+#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */
+
+/* 0x35-0x3b are reserved */
+#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
+#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
+#define PCI_MIN_GNT 0x3e /* 8 bits */
+#define PCI_MAX_LAT 0x3f /* 8 bits */
+
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */
+#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */
+#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */
+#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */
+#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
+#define PCI_IO_LIMIT 0x1d
+#define PCI_IO_RANGE_TYPE_MASK 0x0f /* I/O bridging type */
+#define PCI_IO_RANGE_TYPE_16 0x00
+#define PCI_IO_RANGE_TYPE_32 0x01
+#define PCI_IO_RANGE_MASK ~0x0f
+#define PCI_SEC_STATUS 0x1e /* Secondary status register */
+#define PCI_MEMORY_BASE 0x20 /* Memory range behind */
+#define PCI_MEMORY_LIMIT 0x22
+#define PCI_MEMORY_RANGE_TYPE_MASK 0x0f
+#define PCI_MEMORY_RANGE_MASK ~0x0f
+#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT 0x26
+#define PCI_PREF_RANGE_TYPE_MASK 0x0f
+#define PCI_PREF_RANGE_TYPE_32 0x00
+#define PCI_PREF_RANGE_TYPE_64 0x01
+#define PCI_PREF_RANGE_MASK ~0x0f
+#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */
+#define PCI_PREF_LIMIT_UPPER32 0x2c
+#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */
+#define PCI_IO_LIMIT_UPPER16 0x32
+/* 0x34 same as for htype 0 */
+/* 0x35-0x3b is reserved */
+#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_BRIDGE_CONTROL 0x3e
+#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */
+#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */
+#define PCI_BRIDGE_CTL_NO_ISA 0x04 /* Disable bridging of ISA ports */
+#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */
+#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */
+#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */
+#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */
+#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */
+#define PCI_BRIDGE_CTL_PRI_DISCARD_TIMER 0x100 /* PCI-X? */
+#define PCI_BRIDGE_CTL_SEC_DISCARD_TIMER 0x200 /* PCI-X? */
+#define PCI_BRIDGE_CTL_DISCARD_TIMER_STATUS 0x400 /* PCI-X? */
+#define PCI_BRIDGE_CTL_DISCARD_TIMER_SERR_EN 0x800 /* PCI-X? */
+
+/* Header type 2 (CardBus bridges) */
+#define PCI_CB_CAPABILITY_LIST 0x14
+/* 0x15 reserved */
+#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */
+#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */
+#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */
+#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */
+#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */
+#define PCI_CB_MEMORY_BASE_0 0x1c
+#define PCI_CB_MEMORY_LIMIT_0 0x20
+#define PCI_CB_MEMORY_BASE_1 0x24
+#define PCI_CB_MEMORY_LIMIT_1 0x28
+#define PCI_CB_IO_BASE_0 0x2c
+#define PCI_CB_IO_BASE_0_HI 0x2e
+#define PCI_CB_IO_LIMIT_0 0x30
+#define PCI_CB_IO_LIMIT_0_HI 0x32
+#define PCI_CB_IO_BASE_1 0x34
+#define PCI_CB_IO_BASE_1_HI 0x36
+#define PCI_CB_IO_LIMIT_1 0x38
+#define PCI_CB_IO_LIMIT_1_HI 0x3a
+#define PCI_CB_IO_RANGE_MASK ~0x03
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_CB_BRIDGE_CONTROL 0x3e
+#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */
+#define PCI_CB_BRIDGE_CTL_SERR 0x02
+#define PCI_CB_BRIDGE_CTL_ISA 0x04
+#define PCI_CB_BRIDGE_CTL_VGA 0x08
+#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20
+#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */
+#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
+#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
+#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
+#define PCI_CB_SUBSYSTEM_ID 0x42
+#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */
+/* 0x48-0x7f reserved */
+
+/* Capability lists */
+
+#define PCI_CAP_LIST_ID 0 /* Capability ID */
+#define PCI_CAP_ID_NULL 0x00 /* Null Capability */
+#define PCI_CAP_ID_PM 0x01 /* Power Management */
+#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */
+#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */
+#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */
+#define PCI_CAP_ID_MSI 0x05 /* Message Signaled Interrupts */
+#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
+#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
+#define PCI_CAP_ID_HT 0x08 /* HyperTransport */
+#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */
+#define PCI_CAP_ID_DBG 0x0A /* Debug port */
+#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */
+#define PCI_CAP_ID_HOTPLUG 0x0C /* PCI hot-plug */
+#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */
+#define PCI_CAP_ID_AGP3 0x0E /* AGP 8x */
+#define PCI_CAP_ID_SECURE 0x0F /* Secure device (?) */
+#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
+#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
+#define PCI_CAP_ID_SATA 0x12 /* Serial-ATA HBA */
+#define PCI_CAP_ID_AF 0x13 /* Advanced features of PCI devices integrated in PCIe root cplx */
+#define PCI_CAP_ID_EA 0x14 /* Enhanced Allocation */
+#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
+#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */
+#define PCI_CAP_SIZEOF 4
+
+/* Capabilities residing in the PCI Express extended configuration space */
+
+#define PCI_EXT_CAP_ID_NULL 0x00 /* Null Capability */
+#define PCI_EXT_CAP_ID_AER 0x01 /* Advanced Error Reporting */
+#define PCI_EXT_CAP_ID_VC 0x02 /* Virtual Channel */
+#define PCI_EXT_CAP_ID_DSN 0x03 /* Device Serial Number */
+#define PCI_EXT_CAP_ID_PB 0x04 /* Power Budgeting */
+#define PCI_EXT_CAP_ID_RCLINK 0x05 /* Root Complex Link Declaration */
+#define PCI_EXT_CAP_ID_RCILINK 0x06 /* Root Complex Internal Link Declaration */
+#define PCI_EXT_CAP_ID_RCECOLL 0x07 /* Root Complex Event Collector */
+#define PCI_EXT_CAP_ID_MFVC 0x08 /* Multi-Function Virtual Channel */
+#define PCI_EXT_CAP_ID_VC2 0x09 /* Virtual Channel (2nd ID) */
+#define PCI_EXT_CAP_ID_RCRB 0x0a /* Root Complex Register Block */
+#define PCI_EXT_CAP_ID_VNDR 0x0b /* Vendor specific */
+#define PCI_EXT_CAP_ID_ACS 0x0d /* Access Controls */
+#define PCI_EXT_CAP_ID_ARI 0x0e /* Alternative Routing-ID Interpretation */
+#define PCI_EXT_CAP_ID_ATS 0x0f /* Address Translation Service */
+#define PCI_EXT_CAP_ID_SRIOV 0x10 /* Single Root I/O Virtualization */
+#define PCI_EXT_CAP_ID_MRIOV 0x11 /* Multi-Root I/O Virtualization */
+#define PCI_EXT_CAP_ID_MCAST 0x12 /* Multicast */
+#define PCI_EXT_CAP_ID_PRI 0x13 /* Page Request Interface */
+#define PCI_EXT_CAP_ID_REBAR 0x15 /* Resizable BAR */
+#define PCI_EXT_CAP_ID_DPA 0x16 /* Dynamic Power Allocation */
+#define PCI_EXT_CAP_ID_TPH 0x17 /* Transaction processing hints */
+#define PCI_EXT_CAP_ID_LTR 0x18 /* Latency Tolerance Reporting */
+#define PCI_EXT_CAP_ID_SECPCI 0x19 /* Secondary PCI Express */
+#define PCI_EXT_CAP_ID_PMUX 0x1a /* Protocol Multiplexing */
+#define PCI_EXT_CAP_ID_PASID 0x1b /* Process Address Space ID */
+#define PCI_EXT_CAP_ID_LNR 0x1c /* LN Requester */
+#define PCI_EXT_CAP_ID_DPC 0x1d /* Downstream Port Containment */
+#define PCI_EXT_CAP_ID_L1PM 0x1e /* L1 PM Substates */
+#define PCI_EXT_CAP_ID_PTM 0x1f /* Precision Time Measurement */
+#define PCI_EXT_CAP_ID_M_PCIE 0x20 /* PCIe over M-PHY */
+#define PCI_EXT_CAP_ID_FRS 0x21 /* FRS Queuing */
+#define PCI_EXT_CAP_ID_RTR 0x22 /* Readiness Time Reporting */
+#define PCI_EXT_CAP_ID_DVSEC 0x23 /* Designated Vendor-Specific */
+#define PCI_EXT_CAP_ID_VF_REBAR 0x24 /* VF Resizable BAR */
+#define PCI_EXT_CAP_ID_DLNK 0x25 /* Data Link Feature */
+#define PCI_EXT_CAP_ID_16GT 0x26 /* Physical Layer 16.0 GT/s */
+#define PCI_EXT_CAP_ID_LMR 0x27 /* Lane Margining at Receiver */
+#define PCI_EXT_CAP_ID_HIER_ID 0x28 /* Hierarchy ID */
+#define PCI_EXT_CAP_ID_NPEM 0x29 /* Native PCIe Enclosure Management */
+
+/*** Definitions of capabilities ***/
+
+/* Power Management Registers */
+
+#define PCI_PM_CAP_VER_MASK 0x0007 /* Version (2=PM1.1) */
+#define PCI_PM_CAP_PME_CLOCK 0x0008 /* Clock required for PME generation */
+#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization required */
+#define PCI_PM_CAP_AUX_C_MASK 0x01c0 /* Maximum aux current required in D3cold */
+#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */
+#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */
+#define PCI_PM_CAP_PME_D0 0x0800 /* PME can be asserted from D0 */
+#define PCI_PM_CAP_PME_D1 0x1000 /* PME can be asserted from D1 */
+#define PCI_PM_CAP_PME_D2 0x2000 /* PME can be asserted from D2 */
+#define PCI_PM_CAP_PME_D3_HOT 0x4000 /* PME can be asserted from D3hot */
+#define PCI_PM_CAP_PME_D3_COLD 0x8000 /* PME can be asserted from D3cold */
+#define PCI_PM_CTRL 4 /* PM control and status register */
+#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */
+#define PCI_PM_CTRL_NO_SOFT_RST 0x0008 /* No Soft Reset from D3hot to D0 */
+#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */
+#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* PM table data index */
+#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* PM table data scaling factor */
+#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */
+#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions */
+#define PCI_PM_PPB_B2_B3 0x40 /* If bridge enters D3hot, bus enters: 0=B3, 1=B2 */
+#define PCI_PM_BPCC_ENABLE 0x80 /* Secondary bus is power managed */
+#define PCI_PM_DATA_REGISTER 7 /* PM table contents read here */
+#define PCI_PM_SIZEOF 8
+
+/* AGP registers */
+
+#define PCI_AGP_VERSION 2 /* BCD version number */
+#define PCI_AGP_RFU 3 /* Rest of capability flags */
+#define PCI_AGP_STATUS 4 /* Status register */
+#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */
+#define PCI_AGP_STATUS_ISOCH 0x10000 /* Isochronous transactions supported */
+#define PCI_AGP_STATUS_ARQSZ_MASK 0xe000 /* log2(optimum async req size in bytes) - 4 */
+#define PCI_AGP_STATUS_CAL_MASK 0x1c00 /* Calibration cycle timing */
+#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */
+#define PCI_AGP_STATUS_ITA_COH 0x0100 /* In-aperture accesses always coherent */
+#define PCI_AGP_STATUS_GART64 0x0080 /* 64-bit GART entries supported */
+#define PCI_AGP_STATUS_HTRANS 0x0040 /* If 0, core logic can xlate host CPU accesses thru aperture */
+#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing cycles supported */
+#define PCI_AGP_STATUS_FW 0x0010 /* Fast write transfers supported */
+#define PCI_AGP_STATUS_AGP3 0x0008 /* AGP3 mode supported */
+#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported (RFU in AGP3 mode) */
+#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported (8x in AGP3 mode) */
+#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported (4x in AGP3 mode) */
+#define PCI_AGP_COMMAND 8 /* Control register */
+#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */
+#define PCI_AGP_COMMAND_ARQSZ_MASK 0xe000 /* log2(optimum async req size in bytes) - 4 */
+#define PCI_AGP_COMMAND_CAL_MASK 0x1c00 /* Calibration cycle timing */
+#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */
+#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */
+#define PCI_AGP_COMMAND_GART64 0x0080 /* 64-bit GART entries enabled */
+#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow generation of 64-bit addr cycles */
+#define PCI_AGP_COMMAND_FW 0x0010 /* Enable FW transfers */
+#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate (RFU in AGP3 mode) */
+#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate (8x in AGP3 mode) */
+#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate (4x in AGP3 mode) */
+#define PCI_AGP_SIZEOF 12
+
+/* Vital Product Data */
+
+#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */
+#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */
+#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */
+#define PCI_VPD_DATA 4 /* 32-bits of data returned here */
+
+/* Slot Identification */
+
+#define PCI_SID_ESR 2 /* Expansion Slot Register */
+#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */
+#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */
+#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */
+
+/* Message Signaled Interrupts registers */
+
+#define PCI_MSI_FLAGS 2 /* Various flags */
+#define PCI_MSI_FLAGS_MASK_BIT 0x100 /* interrupt masking & reporting supported */
+#define PCI_MSI_FLAGS_64BIT 0x080 /* 64-bit addresses allowed */
+#define PCI_MSI_FLAGS_QSIZE 0x070 /* Message queue size configured */
+#define PCI_MSI_FLAGS_QMASK 0x00e /* Maximum queue size available */
+#define PCI_MSI_FLAGS_ENABLE 0x001 /* MSI feature enabled */
+#define PCI_MSI_RFU 3 /* Rest of capability flags */
+#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */
+#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
+#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
+#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
+#define PCI_MSI_MASK_BIT_32 12 /* per-vector masking for 32-bit devices */
+#define PCI_MSI_MASK_BIT_64 16 /* per-vector masking for 64-bit devices */
+#define PCI_MSI_PENDING_32 16 /* per-vector interrupt pending for 32-bit devices */
+#define PCI_MSI_PENDING_64 20 /* per-vector interrupt pending for 64-bit devices */
+
+/* PCI-X */
+#define PCI_PCIX_COMMAND 2 /* Command register offset */
+#define PCI_PCIX_COMMAND_DPERE 0x0001 /* Data Parity Error Recover Enable */
+#define PCI_PCIX_COMMAND_ERO 0x0002 /* Enable Relaxed Ordering */
+#define PCI_PCIX_COMMAND_MAX_MEM_READ_BYTE_COUNT 0x000c /* Maximum Memory Read Byte Count */
+#define PCI_PCIX_COMMAND_MAX_OUTSTANDING_SPLIT_TRANS 0x0070
+#define PCI_PCIX_COMMAND_RESERVED 0xf80
+#define PCI_PCIX_STATUS 4 /* Status register offset */
+#define PCI_PCIX_STATUS_FUNCTION 0x00000007
+#define PCI_PCIX_STATUS_DEVICE 0x000000f8
+#define PCI_PCIX_STATUS_BUS 0x0000ff00
+#define PCI_PCIX_STATUS_64BIT 0x00010000
+#define PCI_PCIX_STATUS_133MHZ 0x00020000
+#define PCI_PCIX_STATUS_SC_DISCARDED 0x00040000 /* Split Completion Discarded */
+#define PCI_PCIX_STATUS_UNEXPECTED_SC 0x00080000 /* Unexpected Split Completion */
+#define PCI_PCIX_STATUS_DEVICE_COMPLEXITY 0x00100000 /* 0 = simple device, 1 = bridge device */
+#define PCI_PCIX_STATUS_DESIGNED_MAX_MEM_READ_BYTE_COUNT 0x00600000 /* 0 = 512 bytes, 1 = 1024, 2 = 2048, 3 = 4096 */
+#define PCI_PCIX_STATUS_DESIGNED_MAX_OUTSTANDING_SPLIT_TRANS 0x03800000
+#define PCI_PCIX_STATUS_DESIGNED_MAX_CUMULATIVE_READ_SIZE 0x1c000000
+#define PCI_PCIX_STATUS_RCVD_SC_ERR_MESS 0x20000000 /* Received Split Completion Error Message */
+#define PCI_PCIX_STATUS_266MHZ 0x40000000 /* 266 MHz capable */
+#define PCI_PCIX_STATUS_533MHZ 0x80000000 /* 533 MHz capable */
+#define PCI_PCIX_SIZEOF 4
+
+/* PCI-X Bridges */
+#define PCI_PCIX_BRIDGE_SEC_STATUS 2 /* Secondary bus status register offset */
+#define PCI_PCIX_BRIDGE_SEC_STATUS_64BIT 0x0001
+#define PCI_PCIX_BRIDGE_SEC_STATUS_133MHZ 0x0002
+#define PCI_PCIX_BRIDGE_SEC_STATUS_SC_DISCARDED 0x0004 /* Split Completion Discarded on secondary bus */
+#define PCI_PCIX_BRIDGE_SEC_STATUS_UNEXPECTED_SC 0x0008 /* Unexpected Split Completion on secondary bus */
+#define PCI_PCIX_BRIDGE_SEC_STATUS_SC_OVERRUN 0x0010 /* Split Completion Overrun on secondary bus */
+#define PCI_PCIX_BRIDGE_SEC_STATUS_SPLIT_REQUEST_DELAYED 0x0020
+#define PCI_PCIX_BRIDGE_SEC_STATUS_CLOCK_FREQ 0x01c0
+#define PCI_PCIX_BRIDGE_SEC_STATUS_RESERVED 0xfe00
+#define PCI_PCIX_BRIDGE_STATUS 4 /* Primary bus status register offset */
+#define PCI_PCIX_BRIDGE_STATUS_FUNCTION 0x00000007
+#define PCI_PCIX_BRIDGE_STATUS_DEVICE 0x000000f8
+#define PCI_PCIX_BRIDGE_STATUS_BUS 0x0000ff00
+#define PCI_PCIX_BRIDGE_STATUS_64BIT 0x00010000
+#define PCI_PCIX_BRIDGE_STATUS_133MHZ 0x00020000
+#define PCI_PCIX_BRIDGE_STATUS_SC_DISCARDED 0x00040000 /* Split Completion Discarded */
+#define PCI_PCIX_BRIDGE_STATUS_UNEXPECTED_SC 0x00080000 /* Unexpected Split Completion */
+#define PCI_PCIX_BRIDGE_STATUS_SC_OVERRUN 0x00100000 /* Split Completion Overrun */
+#define PCI_PCIX_BRIDGE_STATUS_SPLIT_REQUEST_DELAYED 0x00200000
+#define PCI_PCIX_BRIDGE_STATUS_RESERVED 0xffc00000
+#define PCI_PCIX_BRIDGE_UPSTREAM_SPLIT_TRANS_CTRL 8 /* Upstream Split Transaction Register offset */
+#define PCI_PCIX_BRIDGE_DOWNSTREAM_SPLIT_TRANS_CTRL 12 /* Downstream Split Transaction Register offset */
+#define PCI_PCIX_BRIDGE_STR_CAPACITY 0x0000ffff
+#define PCI_PCIX_BRIDGE_STR_COMMITMENT_LIMIT 0xffff0000
+#define PCI_PCIX_BRIDGE_SIZEOF 12
+
+/* HyperTransport (as of spec rev. 2.00) */
+#define PCI_HT_CMD 2 /* Command Register */
+#define PCI_HT_CMD_TYP_HI 0xe000 /* Capability Type high part */
+#define PCI_HT_CMD_TYP_HI_PRI 0x0000 /* Slave or Primary Interface */
+#define PCI_HT_CMD_TYP_HI_SEC 0x2000 /* Host or Secondary Interface */
+#define PCI_HT_CMD_TYP 0xf800 /* Capability Type */
+#define PCI_HT_CMD_TYP_SW 0x4000 /* Switch */
+#define PCI_HT_CMD_TYP_IDC 0x8000 /* Interrupt Discovery and Configuration */
+#define PCI_HT_CMD_TYP_RID 0x8800 /* Revision ID */
+#define PCI_HT_CMD_TYP_UIDC 0x9000 /* UnitID Clumping */
+#define PCI_HT_CMD_TYP_ECSA 0x9800 /* Extended Configuration Space Access */
+#define PCI_HT_CMD_TYP_AM 0xa000 /* Address Mapping */
+#define PCI_HT_CMD_TYP_MSIM 0xa800 /* MSI Mapping */
+#define PCI_HT_CMD_TYP_DR 0xb000 /* DirectRoute */
+#define PCI_HT_CMD_TYP_VCS 0xb800 /* VCSet */
+#define PCI_HT_CMD_TYP_RM 0xc000 /* Retry Mode */
+#define PCI_HT_CMD_TYP_X86 0xc800 /* X86 (reserved) */
+
+ /* Link Control Register */
+#define PCI_HT_LCTR_CFLE 0x0002 /* CRC Flood Enable */
+#define PCI_HT_LCTR_CST 0x0004 /* CRC Start Test */
+#define PCI_HT_LCTR_CFE 0x0008 /* CRC Force Error */
+#define PCI_HT_LCTR_LKFAIL 0x0010 /* Link Failure */
+#define PCI_HT_LCTR_INIT 0x0020 /* Initialization Complete */
+#define PCI_HT_LCTR_EOC 0x0040 /* End of Chain */
+#define PCI_HT_LCTR_TXO 0x0080 /* Transmitter Off */
+#define PCI_HT_LCTR_CRCERR 0x0f00 /* CRC Error */
+#define PCI_HT_LCTR_ISOCEN 0x1000 /* Isochronous Flow Control Enable */
+#define PCI_HT_LCTR_LSEN 0x2000 /* LDTSTOP# Tristate Enable */
+#define PCI_HT_LCTR_EXTCTL 0x4000 /* Extended CTL Time */
+#define PCI_HT_LCTR_64B 0x8000 /* 64-bit Addressing Enable */
+
+ /* Link Configuration Register */
+#define PCI_HT_LCNF_MLWI 0x0007 /* Max Link Width In */
+#define PCI_HT_LCNF_LW_8B 0x0 /* Link Width 8 bits */
+#define PCI_HT_LCNF_LW_16B 0x1 /* Link Width 16 bits */
+#define PCI_HT_LCNF_LW_32B 0x3 /* Link Width 32 bits */
+#define PCI_HT_LCNF_LW_2B 0x4 /* Link Width 2 bits */
+#define PCI_HT_LCNF_LW_4B 0x5 /* Link Width 4 bits */
+#define PCI_HT_LCNF_LW_NC 0x7 /* Link physically not connected */
+#define PCI_HT_LCNF_DFI 0x0008 /* Doubleword Flow Control In */
+#define PCI_HT_LCNF_MLWO 0x0070 /* Max Link Width Out */
+#define PCI_HT_LCNF_DFO 0x0080 /* Doubleword Flow Control Out */
+#define PCI_HT_LCNF_LWI 0x0700 /* Link Width In */
+#define PCI_HT_LCNF_DFIE 0x0800 /* Doubleword Flow Control In Enable */
+#define PCI_HT_LCNF_LWO 0x7000 /* Link Width Out */
+#define PCI_HT_LCNF_DFOE 0x8000 /* Doubleword Flow Control Out Enable */
+
+ /* Revision ID Register */
+#define PCI_HT_RID_MIN 0x1f /* Minor Revision */
+#define PCI_HT_RID_MAJ 0xe0 /* Major Revision */
+
+ /* Link Frequency/Error Register */
+#define PCI_HT_LFRER_FREQ 0x0f /* Transmitter Clock Frequency */
+#define PCI_HT_LFRER_200 0x00 /* 200MHz */
+#define PCI_HT_LFRER_300 0x01 /* 300MHz */
+#define PCI_HT_LFRER_400 0x02 /* 400MHz */
+#define PCI_HT_LFRER_500 0x03 /* 500MHz */
+#define PCI_HT_LFRER_600 0x04 /* 600MHz */
+#define PCI_HT_LFRER_800 0x05 /* 800MHz */
+#define PCI_HT_LFRER_1000 0x06 /* 1.0GHz */
+#define PCI_HT_LFRER_1200 0x07 /* 1.2GHz */
+#define PCI_HT_LFRER_1400 0x08 /* 1.4GHz */
+#define PCI_HT_LFRER_1600 0x09 /* 1.6GHz */
+#define PCI_HT_LFRER_VEND 0x0f /* Vendor-Specific */
+#define PCI_HT_LFRER_ERR 0xf0 /* Link Error */
+#define PCI_HT_LFRER_PROT 0x10 /* Protocol Error */
+#define PCI_HT_LFRER_OV 0x20 /* Overflow Error */
+#define PCI_HT_LFRER_EOC 0x40 /* End of Chain Error */
+#define PCI_HT_LFRER_CTLT 0x80 /* CTL Timeout */
+
+ /* Link Frequency Capability Register */
+#define PCI_HT_LFCAP_200 0x0001 /* 200MHz */
+#define PCI_HT_LFCAP_300 0x0002 /* 300MHz */
+#define PCI_HT_LFCAP_400 0x0004 /* 400MHz */
+#define PCI_HT_LFCAP_500 0x0008 /* 500MHz */
+#define PCI_HT_LFCAP_600 0x0010 /* 600MHz */
+#define PCI_HT_LFCAP_800 0x0020 /* 800MHz */
+#define PCI_HT_LFCAP_1000 0x0040 /* 1.0GHz */
+#define PCI_HT_LFCAP_1200 0x0080 /* 1.2GHz */
+#define PCI_HT_LFCAP_1400 0x0100 /* 1.4GHz */
+#define PCI_HT_LFCAP_1600 0x0200 /* 1.6GHz */
+#define PCI_HT_LFCAP_VEND 0x8000 /* Vendor-Specific */
+
+ /* Feature Register */
+#define PCI_HT_FTR_ISOCFC 0x0001 /* Isochronous Flow Control Mode */
+#define PCI_HT_FTR_LDTSTOP 0x0002 /* LDTSTOP# Supported */
+#define PCI_HT_FTR_CRCTM 0x0004 /* CRC Test Mode */
+#define PCI_HT_FTR_ECTLT 0x0008 /* Extended CTL Time Required */
+#define PCI_HT_FTR_64BA 0x0010 /* 64-bit Addressing */
+#define PCI_HT_FTR_UIDRD 0x0020 /* UnitID Reorder Disable */
+
+ /* Error Handling Register */
+#define PCI_HT_EH_PFLE 0x0001 /* Protocol Error Flood Enable */
+#define PCI_HT_EH_OFLE 0x0002 /* Overflow Error Flood Enable */
+#define PCI_HT_EH_PFE 0x0004 /* Protocol Error Fatal Enable */
+#define PCI_HT_EH_OFE 0x0008 /* Overflow Error Fatal Enable */
+#define PCI_HT_EH_EOCFE 0x0010 /* End of Chain Error Fatal Enable */
+#define PCI_HT_EH_RFE 0x0020 /* Response Error Fatal Enable */
+#define PCI_HT_EH_CRCFE 0x0040 /* CRC Error Fatal Enable */
+#define PCI_HT_EH_SERRFE 0x0080 /* System Error Fatal Enable (B */
+#define PCI_HT_EH_CF 0x0100 /* Chain Fail */
+#define PCI_HT_EH_RE 0x0200 /* Response Error */
+#define PCI_HT_EH_PNFE 0x0400 /* Protocol Error Nonfatal Enable */
+#define PCI_HT_EH_ONFE 0x0800 /* Overflow Error Nonfatal Enable */
+#define PCI_HT_EH_EOCNFE 0x1000 /* End of Chain Error Nonfatal Enable */
+#define PCI_HT_EH_RNFE 0x2000 /* Response Error Nonfatal Enable */
+#define PCI_HT_EH_CRCNFE 0x4000 /* CRC Error Nonfatal Enable */
+#define PCI_HT_EH_SERRNFE 0x8000 /* System Error Nonfatal Enable */
+
+/* HyperTransport: Slave or Primary Interface */
+#define PCI_HT_PRI_CMD 2 /* Command Register */
+#define PCI_HT_PRI_CMD_BUID 0x001f /* Base UnitID */
+#define PCI_HT_PRI_CMD_UC 0x03e0 /* Unit Count */
+#define PCI_HT_PRI_CMD_MH 0x0400 /* Master Host */
+#define PCI_HT_PRI_CMD_DD 0x0800 /* Default Direction */
+#define PCI_HT_PRI_CMD_DUL 0x1000 /* Drop on Uninitialized Link */
+
+#define PCI_HT_PRI_LCTR0 4 /* Link Control 0 Register */
+#define PCI_HT_PRI_LCNF0 6 /* Link Config 0 Register */
+#define PCI_HT_PRI_LCTR1 8 /* Link Control 1 Register */
+#define PCI_HT_PRI_LCNF1 10 /* Link Config 1 Register */
+#define PCI_HT_PRI_RID 12 /* Revision ID Register */
+#define PCI_HT_PRI_LFRER0 13 /* Link Frequency/Error 0 Register */
+#define PCI_HT_PRI_LFCAP0 14 /* Link Frequency Capability 0 Register */
+#define PCI_HT_PRI_FTR 16 /* Feature Register */
+#define PCI_HT_PRI_LFRER1 17 /* Link Frequency/Error 1 Register */
+#define PCI_HT_PRI_LFCAP1 18 /* Link Frequency Capability 1 Register */
+#define PCI_HT_PRI_ES 20 /* Enumeration Scratchpad Register */
+#define PCI_HT_PRI_EH 22 /* Error Handling Register */
+#define PCI_HT_PRI_MBU 24 /* Memory Base Upper Register */
+#define PCI_HT_PRI_MLU 25 /* Memory Limit Upper Register */
+#define PCI_HT_PRI_BN 26 /* Bus Number Register */
+#define PCI_HT_PRI_SIZEOF 28
+
+/* HyperTransport: Host or Secondary Interface */
+#define PCI_HT_SEC_CMD 2 /* Command Register */
+#define PCI_HT_SEC_CMD_WR 0x0001 /* Warm Reset */
+#define PCI_HT_SEC_CMD_DE 0x0002 /* Double-Ended */
+#define PCI_HT_SEC_CMD_DN 0x0076 /* Device Number */
+#define PCI_HT_SEC_CMD_CS 0x0080 /* Chain Side */
+#define PCI_HT_SEC_CMD_HH 0x0100 /* Host Hide */
+#define PCI_HT_SEC_CMD_AS 0x0400 /* Act as Slave */
+#define PCI_HT_SEC_CMD_HIECE 0x0800 /* Host Inbound End of Chain Error */
+#define PCI_HT_SEC_CMD_DUL 0x1000 /* Drop on Uninitialized Link */
+
+#define PCI_HT_SEC_LCTR 4 /* Link Control Register */
+#define PCI_HT_SEC_LCNF 6 /* Link Config Register */
+#define PCI_HT_SEC_RID 8 /* Revision ID Register */
+#define PCI_HT_SEC_LFRER 9 /* Link Frequency/Error Register */
+#define PCI_HT_SEC_LFCAP 10 /* Link Frequency Capability Register */
+#define PCI_HT_SEC_FTR 12 /* Feature Register */
+#define PCI_HT_SEC_FTR_EXTRS 0x0100 /* Extended Register Set */
+#define PCI_HT_SEC_FTR_UCNFE 0x0200 /* Upstream Configuration Enable */
+#define PCI_HT_SEC_ES 16 /* Enumeration Scratchpad Register */
+#define PCI_HT_SEC_EH 18 /* Error Handling Register */
+#define PCI_HT_SEC_MBU 20 /* Memory Base Upper Register */
+#define PCI_HT_SEC_MLU 21 /* Memory Limit Upper Register */
+#define PCI_HT_SEC_SIZEOF 24
+
+/* HyperTransport: Switch */
+#define PCI_HT_SW_CMD 2 /* Switch Command Register */
+#define PCI_HT_SW_CMD_VIBERR 0x0080 /* VIB Error */
+#define PCI_HT_SW_CMD_VIBFL 0x0100 /* VIB Flood */
+#define PCI_HT_SW_CMD_VIBFT 0x0200 /* VIB Fatal */
+#define PCI_HT_SW_CMD_VIBNFT 0x0400 /* VIB Nonfatal */
+#define PCI_HT_SW_PMASK 4 /* Partition Mask Register */
+#define PCI_HT_SW_SWINF 8 /* Switch Info Register */
+#define PCI_HT_SW_SWINF_DP 0x0000001f /* Default Port */
+#define PCI_HT_SW_SWINF_EN 0x00000020 /* Enable Decode */
+#define PCI_HT_SW_SWINF_CR 0x00000040 /* Cold Reset */
+#define PCI_HT_SW_SWINF_PCIDX 0x00000f00 /* Performance Counter Index */
+#define PCI_HT_SW_SWINF_BLRIDX 0x0003f000 /* Base/Limit Range Index */
+#define PCI_HT_SW_SWINF_SBIDX 0x00002000 /* Secondary Base Range Index */
+#define PCI_HT_SW_SWINF_HP 0x00040000 /* Hot Plug */
+#define PCI_HT_SW_SWINF_HIDE 0x00080000 /* Hide Port */
+#define PCI_HT_SW_PCD 12 /* Performance Counter Data Register */
+#define PCI_HT_SW_BLRD 16 /* Base/Limit Range Data Register */
+#define PCI_HT_SW_SBD 20 /* Secondary Base Data Register */
+#define PCI_HT_SW_SIZEOF 24
+
+ /* Counter indices */
+#define PCI_HT_SW_PC_PCR 0x0 /* Posted Command Receive */
+#define PCI_HT_SW_PC_NPCR 0x1 /* Nonposted Command Receive */
+#define PCI_HT_SW_PC_RCR 0x2 /* Response Command Receive */
+#define PCI_HT_SW_PC_PDWR 0x3 /* Posted DW Receive */
+#define PCI_HT_SW_PC_NPDWR 0x4 /* Nonposted DW Receive */
+#define PCI_HT_SW_PC_RDWR 0x5 /* Response DW Receive */
+#define PCI_HT_SW_PC_PCT 0x6 /* Posted Command Transmit */
+#define PCI_HT_SW_PC_NPCT 0x7 /* Nonposted Command Transmit */
+#define PCI_HT_SW_PC_RCT 0x8 /* Response Command Transmit */
+#define PCI_HT_SW_PC_PDWT 0x9 /* Posted DW Transmit */
+#define PCI_HT_SW_PC_NPDWT 0xa /* Nonposted DW Transmit */
+#define PCI_HT_SW_PC_RDWT 0xb /* Response DW Transmit */
+
+ /* Base/Limit Range indices */
+#define PCI_HT_SW_BLR_BASE0_LO 0x0 /* Base 0[31:1], Enable */
+#define PCI_HT_SW_BLR_BASE0_HI 0x1 /* Base 0 Upper */
+#define PCI_HT_SW_BLR_LIM0_LO 0x2 /* Limit 0 Lower */
+#define PCI_HT_SW_BLR_LIM0_HI 0x3 /* Limit 0 Upper */
+
+ /* Secondary Base indices */
+#define PCI_HT_SW_SB_LO 0x0 /* Secondary Base[31:1], Enable */
+#define PCI_HT_SW_S0_HI 0x1 /* Secondary Base Upper */
+
+/* HyperTransport: Interrupt Discovery and Configuration */
+#define PCI_HT_IDC_IDX 2 /* Index Register */
+#define PCI_HT_IDC_DATA 4 /* Data Register */
+#define PCI_HT_IDC_SIZEOF 8
+
+ /* Register indices */
+#define PCI_HT_IDC_IDX_LINT 0x01 /* Last Interrupt Register */
+#define PCI_HT_IDC_LINT 0x00ff0000 /* Last interrupt definition */
+#define PCI_HT_IDC_IDX_IDR 0x10 /* Interrupt Definition Registers */
+ /* Low part (at index) */
+#define PCI_HT_IDC_IDR_MASK 0x10000001 /* Mask */
+#define PCI_HT_IDC_IDR_POL 0x10000002 /* Polarity */
+#define PCI_HT_IDC_IDR_II_2 0x1000001c /* IntrInfo[4:2]: Message Type */
+#define PCI_HT_IDC_IDR_II_5 0x10000020 /* IntrInfo[5]: Request EOI */
+#define PCI_HT_IDC_IDR_II_6 0x00ffffc0 /* IntrInfo[23:6] */
+#define PCI_HT_IDC_IDR_II_24 0xff000000 /* IntrInfo[31:24] */
+ /* High part (at index + 1) */
+#define PCI_HT_IDC_IDR_II_32 0x00ffffff /* IntrInfo[55:32] */
+#define PCI_HT_IDC_IDR_PASSPW 0x40000000 /* PassPW setting for messages */
+#define PCI_HT_IDC_IDR_WEOI 0x80000000 /* Waiting for EOI */
+
+/* HyperTransport: Revision ID */
+#define PCI_HT_RID_RID 2 /* Revision Register */
+#define PCI_HT_RID_SIZEOF 4
+
+/* HyperTransport: UnitID Clumping */
+#define PCI_HT_UIDC_CS 4 /* Clumping Support Register */
+#define PCI_HT_UIDC_CE 8 /* Clumping Enable Register */
+#define PCI_HT_UIDC_SIZEOF 12
+
+/* HyperTransport: Extended Configuration Space Access */
+#define PCI_HT_ECSA_ADDR 4 /* Configuration Address Register */
+#define PCI_HT_ECSA_ADDR_REG 0x00000ffc /* Register */
+#define PCI_HT_ECSA_ADDR_FUN 0x00007000 /* Function */
+#define PCI_HT_ECSA_ADDR_DEV 0x000f1000 /* Device */
+#define PCI_HT_ECSA_ADDR_BUS 0x0ff00000 /* Bus Number */
+#define PCI_HT_ECSA_ADDR_TYPE 0x10000000 /* Access Type */
+#define PCI_HT_ECSA_DATA 8 /* Configuration Data Register */
+#define PCI_HT_ECSA_SIZEOF 12
+
+/* HyperTransport: Address Mapping */
+#define PCI_HT_AM_CMD 2 /* Command Register */
+#define PCI_HT_AM_CMD_NDMA 0x000f /* Number of DMA Mappings */
+#define PCI_HT_AM_CMD_IOSIZ 0x01f0 /* I/O Size */
+#define PCI_HT_AM_CMD_MT 0x0600 /* Map Type */
+#define PCI_HT_AM_CMD_MT_40B 0x0000 /* 40-bit */
+#define PCI_HT_AM_CMD_MT_64B 0x0200 /* 64-bit */
+
+ /* Window Control Register bits */
+#define PCI_HT_AM_SBW_CTR_COMP 0x1 /* Compat */
+#define PCI_HT_AM_SBW_CTR_NCOH 0x2 /* NonCoherent */
+#define PCI_HT_AM_SBW_CTR_ISOC 0x4 /* Isochronous */
+#define PCI_HT_AM_SBW_CTR_EN 0x8 /* Enable */
+
+/* HyperTransport: 40-bit Address Mapping */
+#define PCI_HT_AM40_SBNPW 4 /* Secondary Bus Non-Prefetchable Window Register */
+#define PCI_HT_AM40_SBW_BASE 0x000fffff /* Window Base */
+#define PCI_HT_AM40_SBW_CTR 0xf0000000 /* Window Control */
+#define PCI_HT_AM40_SBPW 8 /* Secondary Bus Prefetchable Window Register */
+#define PCI_HT_AM40_DMA_PBASE0 12 /* DMA Window Primary Base 0 Register */
+#define PCI_HT_AM40_DMA_CTR0 15 /* DMA Window Control 0 Register */
+#define PCI_HT_AM40_DMA_CTR_CTR 0xf0 /* Window Control */
+#define PCI_HT_AM40_DMA_SLIM0 16 /* DMA Window Secondary Limit 0 Register */
+#define PCI_HT_AM40_DMA_SBASE0 18 /* DMA Window Secondary Base 0 Register */
+#define PCI_HT_AM40_SIZEOF 12 /* size is variable: 12 + 8 * NDMA */
+
+/* HyperTransport: 64-bit Address Mapping */
+#define PCI_HT_AM64_IDX 4 /* Index Register */
+#define PCI_HT_AM64_DATA_LO 8 /* Data Lower Register */
+#define PCI_HT_AM64_DATA_HI 12 /* Data Upper Register */
+#define PCI_HT_AM64_SIZEOF 16
+
+ /* Register indices */
+#define PCI_HT_AM64_IDX_SBNPW 0x00 /* Secondary Bus Non-Prefetchable Window Register */
+#define PCI_HT_AM64_W_BASE_LO 0xfff00000 /* Window Base Lower */
+#define PCI_HT_AM64_W_CTR 0x0000000f /* Window Control */
+#define PCI_HT_AM64_IDX_SBPW 0x01 /* Secondary Bus Prefetchable Window Register */
+#define PCI_HT_AM64_IDX_PBNPW 0x02 /* Primary Bus Non-Prefetchable Window Register */
+#define PCI_HT_AM64_IDX_DMAPB0 0x04 /* DMA Window Primary Base 0 Register */
+#define PCI_HT_AM64_IDX_DMASB0 0x05 /* DMA Window Secondary Base 0 Register */
+#define PCI_HT_AM64_IDX_DMASL0 0x06 /* DMA Window Secondary Limit 0 Register */
+
+/* HyperTransport: MSI Mapping */
+#define PCI_HT_MSIM_CMD 2 /* Command Register */
+#define PCI_HT_MSIM_CMD_EN 0x0001 /* Mapping Active */
+#define PCI_HT_MSIM_CMD_FIXD 0x0002 /* MSI Mapping Address Fixed */
+#define PCI_HT_MSIM_ADDR_LO 4 /* MSI Mapping Address Lower Register */
+#define PCI_HT_MSIM_ADDR_HI 8 /* MSI Mapping Address Upper Register */
+#define PCI_HT_MSIM_SIZEOF 12
+
+/* HyperTransport: DirectRoute */
+#define PCI_HT_DR_CMD 2 /* Command Register */
+#define PCI_HT_DR_CMD_NDRS 0x000f /* Number of DirectRoute Spaces */
+#define PCI_HT_DR_CMD_IDX 0x01f0 /* Index */
+#define PCI_HT_DR_EN 4 /* Enable Vector Register */
+#define PCI_HT_DR_DATA 8 /* Data Register */
+#define PCI_HT_DR_SIZEOF 12
+
+ /* Register indices */
+#define PCI_HT_DR_IDX_BASE_LO 0x00 /* DirectRoute Base Lower Register */
+#define PCI_HT_DR_OTNRD 0x00000001 /* Opposite to Normal Request Direction */
+#define PCI_HT_DR_BL_LO 0xffffff00 /* Base/Limit Lower */
+#define PCI_HT_DR_IDX_BASE_HI 0x01 /* DirectRoute Base Upper Register */
+#define PCI_HT_DR_IDX_LIMIT_LO 0x02 /* DirectRoute Limit Lower Register */
+#define PCI_HT_DR_IDX_LIMIT_HI 0x03 /* DirectRoute Limit Upper Register */
+
+/* HyperTransport: VCSet */
+#define PCI_HT_VCS_SUP 4 /* VCSets Supported Register */
+#define PCI_HT_VCS_L1EN 5 /* Link 1 VCSets Enabled Register */
+#define PCI_HT_VCS_L0EN 6 /* Link 0 VCSets Enabled Register */
+#define PCI_HT_VCS_SBD 8 /* Stream Bucket Depth Register */
+#define PCI_HT_VCS_SINT 9 /* Stream Interval Register */
+#define PCI_HT_VCS_SSUP 10 /* Number of Streaming VCs Supported Register */
+#define PCI_HT_VCS_SSUP_0 0x00 /* Streaming VC 0 */
+#define PCI_HT_VCS_SSUP_3 0x01 /* Streaming VCs 0-3 */
+#define PCI_HT_VCS_SSUP_15 0x02 /* Streaming VCs 0-15 */
+#define PCI_HT_VCS_NFCBD 12 /* Non-FC Bucket Depth Register */
+#define PCI_HT_VCS_NFCINT 13 /* Non-FC Bucket Interval Register */
+#define PCI_HT_VCS_SIZEOF 16
+
+/* HyperTransport: Retry Mode */
+#define PCI_HT_RM_CTR0 4 /* Control 0 Register */
+#define PCI_HT_RM_CTR_LRETEN 0x01 /* Link Retry Enable */
+#define PCI_HT_RM_CTR_FSER 0x02 /* Force Single Error */
+#define PCI_HT_RM_CTR_ROLNEN 0x04 /* Rollover Nonfatal Enable */
+#define PCI_HT_RM_CTR_FSS 0x08 /* Force Single Stomp */
+#define PCI_HT_RM_CTR_RETNEN 0x10 /* Retry Nonfatal Enable */
+#define PCI_HT_RM_CTR_RETFEN 0x20 /* Retry Fatal Enable */
+#define PCI_HT_RM_CTR_AA 0xc0 /* Allowed Attempts */
+#define PCI_HT_RM_STS0 5 /* Status 0 Register */
+#define PCI_HT_RM_STS_RETSNT 0x01 /* Retry Sent */
+#define PCI_HT_RM_STS_CNTROL 0x02 /* Count Rollover */
+#define PCI_HT_RM_STS_SRCV 0x04 /* Stomp Received */
+#define PCI_HT_RM_CTR1 6 /* Control 1 Register */
+#define PCI_HT_RM_STS1 7 /* Status 1 Register */
+#define PCI_HT_RM_CNT0 8 /* Retry Count 0 Register */
+#define PCI_HT_RM_CNT1 10 /* Retry Count 1 Register */
+#define PCI_HT_RM_SIZEOF 12
+
+/* Vendor-Specific Capability (see PCI_EVNDR_xxx for the PCIe version) */
+#define PCI_VNDR_LENGTH 2 /* Length byte */
+
+/* PCI Express */
+#define PCI_EXP_FLAGS 0x2 /* Capabilities register */
+#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */
+#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */
+#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */
+#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */
+#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */
+#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */
+#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */
+#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCIe to PCI/PCI-X Bridge */
+#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIe Bridge */
+#define PCI_EXP_TYPE_ROOT_INT_EP 0x9 /* Root Complex Integrated Endpoint */
+#define PCI_EXP_TYPE_ROOT_EC 0xa /* Root Complex Event Collector */
+#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */
+#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */
+#define PCI_EXP_DEVCAP 0x4 /* Device capabilities */
+#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */
+#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */
+#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */
+#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */
+#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */
+#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */
+#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */
+#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */
+#define PCI_EXP_DEVCAP_RBE 0x8000 /* Role-Based Error Reporting */
+#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */
+#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */
+#define PCI_EXP_DEVCAP_FLRESET 0x10000000 /* Function-Level Reset */
+#define PCI_EXP_DEVCTL 0x8 /* Device Control */
+#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */
+#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */
+#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */
+#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */
+#define PCI_EXP_DEVCTL_RELAXED 0x0010 /* Enable Relaxed Ordering */
+#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */
+#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */
+#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */
+#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */
+#define PCI_EXP_DEVCTL_NOSNOOP 0x0800 /* Enable No Snoop */
+#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */
+#define PCI_EXP_DEVCTL_BCRE 0x8000 /* Bridge Configuration Retry Enable */
+#define PCI_EXP_DEVCTL_FLRESET 0x8000 /* Function-Level Reset [bit shared with BCRE] */
+#define PCI_EXP_DEVSTA 0xa /* Device Status */
+#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */
+#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */
+#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */
+#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */
+#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */
+#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */
+#define PCI_EXP_LNKCAP 0xc /* Link Capabilities */
+#define PCI_EXP_LNKCAP_SPEED 0x0000f /* Maximum Link Speed */
+#define PCI_EXP_LNKCAP_WIDTH 0x003f0 /* Maximum Link Width */
+#define PCI_EXP_LNKCAP_ASPM 0x00c00 /* Active State Power Management */
+#define PCI_EXP_LNKCAP_L0S 0x07000 /* L0s Exit Latency */
+#define PCI_EXP_LNKCAP_L1 0x38000 /* L1 Exit Latency */
+#define PCI_EXP_LNKCAP_CLOCKPM 0x40000 /* Clock Power Management */
+#define PCI_EXP_LNKCAP_SURPRISE 0x80000 /* Surprise Down Error Reporting */
+#define PCI_EXP_LNKCAP_DLLA 0x100000 /* Data Link Layer Active Reporting */
+#define PCI_EXP_LNKCAP_LBNC 0x200000 /* Link Bandwidth Notification Capability */
+#define PCI_EXP_LNKCAP_AOC 0x400000 /* ASPM Optionality Compliance */
+#define PCI_EXP_LNKCAP_PORT 0xff000000 /* Port Number */
+#define PCI_EXP_LNKCTL 0x10 /* Link Control */
+#define PCI_EXP_LNKCTL_ASPM 0x0003 /* ASPM Control */
+#define PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */
+#define PCI_EXP_LNKCTL_DISABLE 0x0010 /* Link Disable */
+#define PCI_EXP_LNKCTL_RETRAIN 0x0020 /* Retrain Link */
+#define PCI_EXP_LNKCTL_CLOCK 0x0040 /* Common Clock Configuration */
+#define PCI_EXP_LNKCTL_XSYNCH 0x0080 /* Extended Synch */
+#define PCI_EXP_LNKCTL_CLOCKPM 0x0100 /* Clock Power Management */
+#define PCI_EXP_LNKCTL_HWAUTWD 0x0200 /* Hardware Autonomous Width Disable */
+#define PCI_EXP_LNKCTL_BWMIE 0x0400 /* Bandwidth Mgmt Interrupt Enable */
+#define PCI_EXP_LNKCTL_AUTBWIE 0x0800 /* Autonomous Bandwidth Mgmt Interrupt Enable */
+#define PCI_EXP_LNKSTA 0x12 /* Link Status */
+#define PCI_EXP_LNKSTA_SPEED 0x000f /* Negotiated Link Speed */
+#define PCI_EXP_LNKSTA_WIDTH 0x03f0 /* Negotiated Link Width */
+#define PCI_EXP_LNKSTA_TR_ERR 0x0400 /* Training Error (obsolete) */
+#define PCI_EXP_LNKSTA_TRAIN 0x0800 /* Link Training */
+#define PCI_EXP_LNKSTA_SL_CLK 0x1000 /* Slot Clock Configuration */
+#define PCI_EXP_LNKSTA_DL_ACT 0x2000 /* Data Link Layer in DL_Active State */
+#define PCI_EXP_LNKSTA_BWMGMT 0x4000 /* Bandwidth Mgmt Status */
+#define PCI_EXP_LNKSTA_AUTBW 0x8000 /* Autonomous Bandwidth Mgmt Status */
+#define PCI_EXP_SLTCAP 0x14 /* Slot Capabilities */
+#define PCI_EXP_SLTCAP_ATNB 0x0001 /* Attention Button Present */
+#define PCI_EXP_SLTCAP_PWRC 0x0002 /* Power Controller Present */
+#define PCI_EXP_SLTCAP_MRL 0x0004 /* MRL Sensor Present */
+#define PCI_EXP_SLTCAP_ATNI 0x0008 /* Attention Indicator Present */
+#define PCI_EXP_SLTCAP_PWRI 0x0010 /* Power Indicator Present */
+#define PCI_EXP_SLTCAP_HPS 0x0020 /* Hot-Plug Surprise */
+#define PCI_EXP_SLTCAP_HPC 0x0040 /* Hot-Plug Capable */
+#define PCI_EXP_SLTCAP_PWR_VAL 0x00007f80 /* Slot Power Limit Value */
+#define PCI_EXP_SLTCAP_PWR_SCL 0x00018000 /* Slot Power Limit Scale */
+#define PCI_EXP_SLTCAP_INTERLOCK 0x020000 /* Electromechanical Interlock Present */
+#define PCI_EXP_SLTCAP_NOCMDCOMP 0x040000 /* No Command Completed Support */
+#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */
+#define PCI_EXP_SLTCTL 0x18 /* Slot Control */
+#define PCI_EXP_SLTCTL_ATNB 0x0001 /* Attention Button Pressed Enable */
+#define PCI_EXP_SLTCTL_PWRF 0x0002 /* Power Fault Detected Enable */
+#define PCI_EXP_SLTCTL_MRLS 0x0004 /* MRL Sensor Changed Enable */
+#define PCI_EXP_SLTCTL_PRSD 0x0008 /* Presence Detect Changed Enable */
+#define PCI_EXP_SLTCTL_CMDC 0x0010 /* Command Completed Interrupt Enable */
+#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */
+#define PCI_EXP_SLTCTL_ATNI 0x00c0 /* Attention Indicator Control */
+#define PCI_EXP_SLTCTL_PWRI 0x0300 /* Power Indicator Control */
+#define PCI_EXP_SLTCTL_PWRC 0x0400 /* Power Controller Control */
+#define PCI_EXP_SLTCTL_INTERLOCK 0x0800 /* Electromechanical Interlock Control */
+#define PCI_EXP_SLTCTL_LLCHG 0x1000 /* Data Link Layer State Changed Enable */
+#define PCI_EXP_SLTSTA 0x1a /* Slot Status */
+#define PCI_EXP_SLTSTA_ATNB 0x0001 /* Attention Button Pressed */
+#define PCI_EXP_SLTSTA_PWRF 0x0002 /* Power Fault Detected */
+#define PCI_EXP_SLTSTA_MRLS 0x0004 /* MRL Sensor Changed */
+#define PCI_EXP_SLTSTA_PRSD 0x0008 /* Presence Detect Changed */
+#define PCI_EXP_SLTSTA_CMDC 0x0010 /* Command Completed */
+#define PCI_EXP_SLTSTA_MRL_ST 0x0020 /* MRL Sensor State */
+#define PCI_EXP_SLTSTA_PRES 0x0040 /* Presence Detect State */
+#define PCI_EXP_SLTSTA_INTERLOCK 0x0080 /* Electromechanical Interlock Status */
+#define PCI_EXP_SLTSTA_LLCHG 0x0100 /* Data Link Layer State Changed */
+#define PCI_EXP_RTCTL 0x1c /* Root Control */
+#define PCI_EXP_RTCTL_SECEE 0x0001 /* System Error on Correctable Error */
+#define PCI_EXP_RTCTL_SENFEE 0x0002 /* System Error on Non-Fatal Error */
+#define PCI_EXP_RTCTL_SEFEE 0x0004 /* System Error on Fatal Error */
+#define PCI_EXP_RTCTL_PMEIE 0x0008 /* PME Interrupt Enable */
+#define PCI_EXP_RTCTL_CRSVIS 0x0010 /* Configuration Request Retry Status Visible to SW */
+#define PCI_EXP_RTCAP 0x1e /* Root Capabilities */
+#define PCI_EXP_RTCAP_CRSVIS 0x0001 /* Configuration Request Retry Status Visible to SW */
+#define PCI_EXP_RTSTA 0x20 /* Root Status */
+#define PCI_EXP_RTSTA_PME_REQID 0x0000ffff /* PME Requester ID */
+#define PCI_EXP_RTSTA_PME_STATUS 0x00010000 /* PME Status */
+#define PCI_EXP_RTSTA_PME_PENDING 0x00020000 /* PME is Pending */
+#define PCI_EXP_DEVCAP2 0x24 /* Device capabilities 2 */
+#define PCI_EXP_DEVCAP2_NROPRPRP 0x0400 /* No RO-enabled PR-PR Passing */
+#define PCI_EXP_DEVCAP2_LTR 0x0800 /* LTR supported */
+#define PCI_EXP_DEVCAP2_TPH_COMP(x) (((x) >> 12) & 3) /* TPH Completer Supported */
+#define PCI_EXP_DEVCAP2_LN_CLS(x) (((x) >> 14) & 3) /* LN System CLS Supported */
+#define PCI_EXP_DEVCAP2_10BIT_TAG_COMP 0x00010000 /* 10 Bit Tag Completer */
+#define PCI_EXP_DEVCAP2_10BIT_TAG_REQ 0x00020000 /* 10 Bit Tag Requester */
+#define PCI_EXP_DEVCAP2_OBFF(x) (((x) >> 18) & 3) /* OBFF supported */
+#define PCI_EXP_DEVCAP2_EXTFMT 0x00100000 /* Extended Fmt Field Supported */
+#define PCI_EXP_DEVCAP2_EE_TLP 0x00200000 /* End-End TLP Prefix Supported */
+#define PCI_EXP_DEVCAP2_MEE_TLP(x) (((x) >> 22) & 3) /* Max End-End TLP Prefixes */
+#define PCI_EXP_DEVCAP2_EPR(x) (((x) >> 24) & 3) /* Emergency Power Reduction Supported */
+#define PCI_EXP_DEVCAP2_EPR_INIT 0x04000000 /* Emergency Power Reduction Initialization Required */
+#define PCI_EXP_DEVCAP2_FRS 0x80000000 /* FRS supported */
+#define PCI_EXP_DEVCTL2 0x28 /* Device Control */
+#define PCI_EXP_DEV2_TIMEOUT_RANGE(x) ((x) & 0xf) /* Completion Timeout Ranges Supported */
+#define PCI_EXP_DEV2_TIMEOUT_VALUE(x) ((x) & 0xf) /* Completion Timeout Value */
+#define PCI_EXP_DEV2_TIMEOUT_DIS 0x0010 /* Completion Timeout Disable Supported */
+#define PCI_EXP_DEV2_ATOMICOP_REQUESTER_EN 0x0040 /* AtomicOp RequesterEnable */
+#define PCI_EXP_DEV2_ATOMICOP_EGRESS_BLOCK 0x0080 /* AtomicOp Egress Blocking */
+#define PCI_EXP_DEV2_ARI 0x0020 /* ARI Forwarding */
+#define PCI_EXP_DEVCAP2_ATOMICOP_ROUTING 0x0040 /* AtomicOp Routing Supported */
+#define PCI_EXP_DEVCAP2_32BIT_ATOMICOP_COMP 0x0080 /* 32bit AtomicOp Completer Supported */
+#define PCI_EXP_DEVCAP2_64BIT_ATOMICOP_COMP 0x0100 /* 64bit AtomicOp Completer Supported */
+#define PCI_EXP_DEVCAP2_128BIT_CAS_COMP 0x0200 /* 128bit CAS Completer Supported */
+#define PCI_EXP_DEV2_LTR 0x0400 /* LTR enabled */
+#define PCI_EXP_DEV2_OBFF(x) (((x) >> 13) & 3) /* OBFF enabled */
+#define PCI_EXP_DEVSTA2 0x2a /* Device Status */
+#define PCI_EXP_LNKCAP2 0x2c /* Link Capabilities */
+#define PCI_EXP_LNKCAP2_SPEED(x) (((x) >> 1) & 0x7f)
+#define PCI_EXP_LNKCAP2_CROSSLINK 0x00000100 /* Crosslink Supported */
+#define PCI_EXP_LNKCAP2_RETIMER 0x00800000 /* Retimer Supported */
+#define PCI_EXP_LNKCAP2_2RETIMERS 0x01000000 /* 2 Retimers Supported */
+#define PCI_EXP_LNKCAP2_DRS 0x80000000 /* Device Readiness Status */
+#define PCI_EXP_LNKCTL2 0x30 /* Link Control */
+#define PCI_EXP_LNKCTL2_SPEED(x) ((x) & 0xf) /* Target Link Speed */
+#define PCI_EXP_LNKCTL2_CMPLNC 0x0010 /* Enter Compliance */
+#define PCI_EXP_LNKCTL2_SPEED_DIS 0x0020 /* Hardware Autonomous Speed Disable */
+#define PCI_EXP_LNKCTL2_DEEMPHASIS(x) (((x) >> 6) & 1) /* Selectable De-emphasis */
+#define PCI_EXP_LNKCTL2_MARGIN(x) (((x) >> 7) & 7) /* Transmit Margin */
+#define PCI_EXP_LNKCTL2_MOD_CMPLNC 0x0400 /* Enter Modified Compliance */
+#define PCI_EXP_LNKCTL2_CMPLNC_SOS 0x0800 /* Compliance SOS */
+#define PCI_EXP_LNKCTL2_COM_DEEMPHASIS(x) (((x) >> 12) & 0xf) /* Compliance De-emphasis */
+#define PCI_EXP_LNKSTA2 0x32 /* Link Status */
+#define PCI_EXP_LINKSTA2_DEEMPHASIS(x) ((x) & 1) /* Current De-emphasis Level */
+#define PCI_EXP_LINKSTA2_EQU_COMP 0x02 /* Equalization Complete */
+#define PCI_EXP_LINKSTA2_EQU_PHASE1 0x04 /* Equalization Phase 1 Successful */
+#define PCI_EXP_LINKSTA2_EQU_PHASE2 0x08 /* Equalization Phase 2 Successful */
+#define PCI_EXP_LINKSTA2_EQU_PHASE3 0x10 /* Equalization Phase 3 Successful */
+#define PCI_EXP_LINKSTA2_EQU_REQ 0x20 /* Link Equalization Request */
+#define PCI_EXP_LINKSTA2_RETIMER 0x0040 /* Retimer Detected */
+#define PCI_EXP_LINKSTA2_2RETIMERS 0x0080 /* 2 Retimers Detected */
+#define PCI_EXP_LINKSTA2_CROSSLINK(x) (((x) >> 8) & 0x3) /* Crosslink Res */
+#define PCI_EXP_LINKSTA2_COMPONENT(x) (((x) >> 12) & 0x7) /* Presence */
+#define PCI_EXP_LINKSTA2_DRS_RCVD 0x8000 /* DRS Msg Received */
+#define PCI_EXP_SLTCAP2 0x34 /* Slot Capabilities */
+#define PCI_EXP_SLTCTL2 0x38 /* Slot Control */
+#define PCI_EXP_SLTSTA2 0x3a /* Slot Status */
+
+/* MSI-X */
+#define PCI_MSIX_ENABLE 0x8000
+#define PCI_MSIX_MASK 0x4000
+#define PCI_MSIX_TABSIZE 0x07ff
+#define PCI_MSIX_TABLE 4
+#define PCI_MSIX_PBA 8
+#define PCI_MSIX_BIR 0x7
+
+/* Subsystem vendor/device ID for PCI bridges */
+#define PCI_SSVID_VENDOR 4
+#define PCI_SSVID_DEVICE 6
+
+/* PCI Advanced Features */
+#define PCI_AF_CAP 3
+#define PCI_AF_CAP_TP 0x01
+#define PCI_AF_CAP_FLR 0x02
+#define PCI_AF_CTRL 4
+#define PCI_AF_CTRL_FLR 0x01
+#define PCI_AF_STATUS 5
+#define PCI_AF_STATUS_TP 0x01
+
+/* SATA Host Bus Adapter */
+#define PCI_SATA_HBA_BARS 4
+#define PCI_SATA_HBA_REG0 8
+
+/* Enhanced Allocation (EA) */
+#define PCI_EA_CAP_TYPE1_SECONDARY 4
+#define PCI_EA_CAP_TYPE1_SUBORDINATE 5
+/* EA Entry header */
+#define PCI_EA_CAP_ENT_WRITABLE 0x40000000 /* Writable: 1 = RW, 0 = HwInit */
+#define PCI_EA_CAP_ENT_ENABLE 0x80000000 /* Enable for this entry */
+
+/*** Definitions of extended capabilities ***/
+
+/* Advanced Error Reporting */
+#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */
+#define PCI_ERR_UNC_TRAIN 0x00000001 /* Undefined in PCIe rev1.1 & 2.0 spec */
+#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */
+#define PCI_ERR_UNC_SDES 0x00000020 /* Surprise Down Error */
+#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */
+#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */
+#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */
+#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */
+#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */
+#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */
+#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */
+#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */
+#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */
+#define PCI_ERR_UNC_ACS_VIOL 0x00200000 /* ACS Violation */
+#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */
+ /* Same bits as above */
+#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */
+ /* Same bits as above */
+#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */
+#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */
+#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */
+#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */
+#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */
+#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */
+#define PCI_ERR_COR_REP_ANFE 0x00002000 /* Advisory Non-Fatal Error */
+#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */
+ /* Same bits as above */
+#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */
+#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */
+#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */
+#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */
+#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */
+#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */
+#define PCI_ERR_CAP_MULT_HDRC 0x00000200 /* Multiple Header Capable */
+#define PCI_ERR_CAP_MULT_HDRE 0x00000400 /* Multiple Header Enable */
+#define PCI_ERR_CAP_TLP_PFX 0x00000800 /* TLP Prefix Log Present */
+#define PCI_ERR_CAP_HDR_LOG 0x00001000 /* Completion Timeout Prefix/Header Log Capable */
+#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */
+#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */
+#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 /* Correctable Error Reporting Enable */
+#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 /* Non-Fatal Error Reporting Enable*/
+#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 /* Fatal Error Reporting Enable */
+#define PCI_ERR_ROOT_STATUS 48 /* Root Error Status */
+#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */
+#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 /* Multiple ERR_COR Received */
+#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 /* ERR_FATAL/NONFATAL Received */
+#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 /* Multiple ERR_FATAL/NONFATAL Received */
+#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Uncorrectable Fatal */
+#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Error Messages Received */
+#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Error Messages Received */
+#define PCI_ERR_MSG_NUM(x) (((x) >> 27) & 0x1f) /* MSI/MSI-X vector */
+#define PCI_ERR_ROOT_COR_SRC 52
+#define PCI_ERR_ROOT_SRC 54
+
+/* Virtual Channel */
+#define PCI_VC_PORT_REG1 4
+#define PCI_VC_PORT_REG2 8
+#define PCI_VC_PORT_CTRL 12
+#define PCI_VC_PORT_STATUS 14
+#define PCI_VC_RES_CAP 16
+#define PCI_VC_RES_CTRL 20
+#define PCI_VC_RES_STATUS 26
+
+/* Power Budgeting */
+#define PCI_PWR_DSR 4 /* Data Select Register */
+#define PCI_PWR_DATA 8 /* Data Register */
+#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */
+#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */
+#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */
+#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */
+#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */
+#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */
+#define PCI_PWR_CAP 12 /* Capability */
+#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */
+
+/* Root Complex Link */
+#define PCI_RCLINK_ESD 4 /* Element Self Description */
+#define PCI_RCLINK_LINK1 16 /* First Link Entry */
+#define PCI_RCLINK_LINK_DESC 0 /* Link Entry: Description */
+#define PCI_RCLINK_LINK_ADDR 8 /* Link Entry: Address (64-bit) */
+#define PCI_RCLINK_LINK_SIZE 16 /* Link Entry: sizeof */
+
+/* PCIe Vendor-Specific Capability */
+#define PCI_EVNDR_HEADER 4 /* Vendor-Specific Header */
+#define PCI_EVNDR_REGISTERS 8 /* Vendor-Specific Registers */
+
+/* PCIe Designated Vendor-Specific Capability */
+#define PCI_DVSEC_HEADER1 4 /* Designated Vendor-Specific Header 1 */
+#define PCI_DVSEC_HEADER2 8 /* Designated Vendor-Specific Header 2 */
+#define PCI_DVSEC_VENDOR_ID_CXL 0x1e98 /* Designated Vendor-Specific Vendor ID for CXL */
+#define PCI_DVSEC_ID_CXL 0 /* Designated Vendor-Specific ID for Intel CXL */
+
+/* PCIe CXL Designated Vendor-Specific Capabilities, Control, Status */
+#define PCI_CXL_CAP 0x0a /* CXL Capability Register */
+#define PCI_CXL_CAP_CACHE 0x0001 /* CXL.cache Protocol Support */
+#define PCI_CXL_CAP_IO 0x0002 /* CXL.io Protocol Support */
+#define PCI_CXL_CAP_MEM 0x0004 /* CXL.mem Protocol Support */
+#define PCI_CXL_CAP_MEM_HWINIT 0x0008 /* CXL.mem Initalizes with HW/FW Support */
+#define PCI_CXL_CAP_HDM_CNT(x) (((x) & (3 << 4)) >> 4) /* CXL Number of HDM ranges */
+#define PCI_CXL_CAP_VIRAL 0x4000 /* CXL Viral Handling Support */
+#define PCI_CXL_CTRL 0x0c /* CXL Control Register */
+#define PCI_CXL_CTRL_CACHE 0x0001 /* CXL.cache Protocol Enable */
+#define PCI_CXL_CTRL_IO 0x0002 /* CXL.io Protocol Enable */
+#define PCI_CXL_CTRL_MEM 0x0004 /* CXL.mem Protocol Enable */
+#define PCI_CXL_CTRL_CACHE_SF_COV(x) (((x) & (0x1f << 3)) >> 3) /* Snoop Filter Coverage */
+#define PCI_CXL_CTRL_CACHE_SF_GRAN(x) (((x) & (0x7 << 8)) >> 8) /* Snoop Filter Granularity */
+#define PCI_CXL_CTRL_CACHE_CLN 0x0800 /* CXL.cache Performance Hint on Clean Evictions */
+#define PCI_CXL_CTRL_VIRAL 0x4000 /* CXL Viral Handling Enable */
+#define PCI_CXL_STATUS 0x0e /* CXL Status Register */
+#define PCI_CXL_STATUS_VIRAL 0x4000 /* CXL Viral Handling Status */
+
+/* Access Control Services */
+#define PCI_ACS_CAP 0x04 /* ACS Capability Register */
+#define PCI_ACS_CAP_VALID 0x0001 /* ACS Source Validation */
+#define PCI_ACS_CAP_BLOCK 0x0002 /* ACS Translation Blocking */
+#define PCI_ACS_CAP_REQ_RED 0x0004 /* ACS P2P Request Redirect */
+#define PCI_ACS_CAP_CMPLT_RED 0x0008 /* ACS P2P Completion Redirect */
+#define PCI_ACS_CAP_FORWARD 0x0010 /* ACS Upstream Forwarding */
+#define PCI_ACS_CAP_EGRESS 0x0020 /* ACS P2P Egress Control */
+#define PCI_ACS_CAP_TRANS 0x0040 /* ACS Direct Translated P2P */
+#define PCI_ACS_CAP_VECTOR(x) (((x) >> 8) & 0xff) /* Egress Control Vector Size */
+#define PCI_ACS_CTRL 0x06 /* ACS Control Register */
+#define PCI_ACS_CTRL_VALID 0x0001 /* ACS Source Validation Enable */
+#define PCI_ACS_CTRL_BLOCK 0x0002 /* ACS Translation Blocking Enable */
+#define PCI_ACS_CTRL_REQ_RED 0x0004 /* ACS P2P Request Redirect Enable */
+#define PCI_ACS_CTRL_CMPLT_RED 0x0008 /* ACS P2P Completion Redirect Enable */
+#define PCI_ACS_CTRL_FORWARD 0x0010 /* ACS Upstream Forwarding Enable */
+#define PCI_ACS_CTRL_EGRESS 0x0020 /* ACS P2P Egress Control Enable */
+#define PCI_ACS_CTRL_TRANS 0x0040 /* ACS Direct Translated P2P Enable */
+#define PCI_ACS_EGRESS_CTRL 0x08 /* Egress Control Vector */
+
+/* Alternative Routing-ID Interpretation */
+#define PCI_ARI_CAP 0x04 /* ARI Capability Register */
+#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */
+#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */
+#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */
+#define PCI_ARI_CTRL 0x06 /* ARI Control Register */
+#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */
+#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */
+#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */
+
+/* Address Translation Service */
+#define PCI_ATS_CAP 0x04 /* ATS Capability Register */
+#define PCI_ATS_CAP_IQD(x) ((x) & 0x1f) /* Invalidate Queue Depth */
+#define PCI_ATS_CTRL 0x06 /* ATS Control Register */
+#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */
+#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */
+
+/* Single Root I/O Virtualization */
+#define PCI_IOV_CAP 0x04 /* SR-IOV Capability Register */
+#define PCI_IOV_CAP_VFM 0x00000001 /* VF Migration Capable */
+#define PCI_IOV_CAP_IMN(x) ((x) >> 21) /* VF Migration Interrupt Message Number */
+#define PCI_IOV_CTRL 0x08 /* SR-IOV Control Register */
+#define PCI_IOV_CTRL_VFE 0x0001 /* VF Enable */
+#define PCI_IOV_CTRL_VFME 0x0002 /* VF Migration Enable */
+#define PCI_IOV_CTRL_VFMIE 0x0004 /* VF Migration Interrupt Enable */
+#define PCI_IOV_CTRL_MSE 0x0008 /* VF MSE */
+#define PCI_IOV_CTRL_ARI 0x0010 /* ARI Capable Hierarchy */
+#define PCI_IOV_STATUS 0x0a /* SR-IOV Status Register */
+#define PCI_IOV_STATUS_MS 0x0001 /* VF Migration Status */
+#define PCI_IOV_INITIALVF 0x0c /* Number of VFs that are initially associated */
+#define PCI_IOV_TOTALVF 0x0e /* Maximum number of VFs that could be associated */
+#define PCI_IOV_NUMVF 0x10 /* Number of VFs that are available */
+#define PCI_IOV_FDL 0x12 /* Function Dependency Link */
+#define PCI_IOV_OFFSET 0x14 /* First VF Offset */
+#define PCI_IOV_STRIDE 0x16 /* Routing ID offset from one VF to the next one */
+#define PCI_IOV_DID 0x1a /* VF Device ID */
+#define PCI_IOV_SUPPS 0x1c /* Supported Page Sizes */
+#define PCI_IOV_SYSPS 0x20 /* System Page Size */
+#define PCI_IOV_BAR_BASE 0x24 /* VF BAR0, VF BAR1, ... VF BAR5 */
+#define PCI_IOV_NUM_BAR 6 /* Number of VF BARs */
+#define PCI_IOV_MSAO 0x3c /* VF Migration State Array Offset */
+#define PCI_IOV_MSA_BIR(x) ((x) & 7) /* VF Migration State BIR */
+#define PCI_IOV_MSA_OFFSET(x) ((x) & 0xfffffff8) /* VF Migration State Offset */
+
+/* Multicast */
+#define PCI_MCAST_CAP 0x04 /* Multicast Capability */
+#define PCI_MCAST_CAP_MAX_GROUP(x) ((x) & 0x3f)
+#define PCI_MCAST_CAP_WIN_SIZE(x) (((x) >> 8) & 0x3f)
+#define PCI_MCAST_CAP_ECRC 0x8000 /* ECRC Regeneration Supported */
+#define PCI_MCAST_CTRL 0x06 /* Multicast Control */
+#define PCI_MCAST_CTRL_NUM_GROUP(x) ((x) & 0x3f)
+#define PCI_MCAST_CTRL_ENABLE 0x8000 /* MC Enabled */
+#define PCI_MCAST_BAR 0x08 /* Base Address */
+#define PCI_MCAST_BAR_INDEX_POS(x) ((u32) ((x) & 0x3f))
+#define PCI_MCAST_BAR_MASK (~0xfffUL)
+#define PCI_MCAST_RCV 0x10 /* Receive */
+#define PCI_MCAST_BLOCK 0x18 /* Block All */
+#define PCI_MCAST_BLOCK_UNTRANS 0x20 /* Block Untranslated */
+#define PCI_MCAST_OVL_BAR 0x28 /* Overlay BAR */
+#define PCI_MCAST_OVL_SIZE(x) ((u32) ((x) & 0x3f))
+#define PCI_MCAST_OVL_MASK (~0x3fUL)
+
+/* Page Request Interface */
+#define PCI_PRI_CTRL 0x04 /* PRI Control Register */
+#define PCI_PRI_CTRL_ENABLE 0x01 /* Enable */
+#define PCI_PRI_CTRL_RESET 0x02 /* Reset */
+#define PCI_PRI_STATUS 0x06 /* PRI status register */
+#define PCI_PRI_STATUS_RF 0x001 /* Response Failure */
+#define PCI_PRI_STATUS_UPRGI 0x002 /* Unexpected PRG index */
+#define PCI_PRI_STATUS_STOPPED 0x100 /* PRI Stopped */
+#define PCI_PRI_MAX_REQ 0x08 /* PRI max reqs supported */
+#define PCI_PRI_ALLOC_REQ 0x0c /* PRI max reqs allowed */
+
+/* Transaction Processing Hints */
+#define PCI_TPH_CAPABILITIES 4
+#define PCI_TPH_INTVEC_SUP (1<<1) /* Supports interrupt vector mode */
+#define PCI_TPH_DEV_SUP (1<<2) /* Device specific mode supported */
+#define PCI_TPH_EXT_REQ_SUP (1<<8) /* Supports extended requests */
+#define PCI_TPH_ST_LOC_MASK (3<<9) /* Steering table location bits */
+#define PCI_TPH_ST_NONE (0<<9) /* No steering table */
+#define PCI_TPH_ST_CAP (1<<9) /* Steering table in TPH cap */
+#define PCI_TPH_ST_MSIX (2<<9) /* Steering table in MSI-X table */
+#define PCI_TPH_ST_SIZE_SHIFT (16) /* Encoded as size - 1 */
+
+/* Latency Tolerance Reporting */
+#define PCI_LTR_MAX_SNOOP 4 /* 16 bit value */
+#define PCI_LTR_VALUE_MASK (0x3ff)
+#define PCI_LTR_SCALE_SHIFT (10)
+#define PCI_LTR_SCALE_MASK (7)
+#define PCI_LTR_MAX_NOSNOOP 6 /* 16 bit value */
+
+/* Secondary PCI Express Extended Capability */
+#define PCI_SEC_LNKCTL3 4 /* Link Control 3 register */
+#define PCI_SEC_LNKCTL3_PERFORM_LINK_EQU 0x01
+#define PCI_SEC_LNKCTL3_LNK_EQU_REQ_INTR_EN 0x02
+#define PCI_SEC_LNKCTL3_ENBL_LOWER_SKP_OS_GEN_VEC(x) ((x >> 8) & 0x7F)
+#define PCI_SEC_LANE_ERR 8 /* Lane Error status register */
+#define PCI_SEC_LANE_EQU_CTRL 12 /* Lane Equalization control register */
+
+/* Process Address Space ID */
+#define PCI_PASID_CAP 0x04 /* PASID feature register */
+#define PCI_PASID_CAP_EXEC 0x02 /* Exec permissions Supported */
+#define PCI_PASID_CAP_PRIV 0x04 /* Privilege Mode Supported */
+#define PCI_PASID_CAP_WIDTH(x) (((x) >> 8) & 0x1f) /* Max PASID Width */
+#define PCI_PASID_CTRL 0x06 /* PASID control register */
+#define PCI_PASID_CTRL_ENABLE 0x01 /* Enable bit */
+#define PCI_PASID_CTRL_EXEC 0x02 /* Exec permissions Enable */
+#define PCI_PASID_CTRL_PRIV 0x04 /* Privilege Mode Enable */
+
+#define PCI_DPC_CAP 4 /* DPC Capability */
+#define PCI_DPC_CAP_INT_MSG(x) ((x) & 0x1f) /* DPC Interrupt Message Number */
+#define PCI_DPC_CAP_RP_EXT 0x20 /* DPC Root Port Extentions */
+#define PCI_DPC_CAP_TLP_BLOCK 0x40 /* DPC Poisoned TLP Egress Blocking */
+#define PCI_DPC_CAP_SW_TRIGGER 0x80 /* DPC Software Trigger */
+#define PCI_DPC_CAP_RP_LOG(x) (((x) >> 8) & 0xf) /* DPC RP PIO Log Size */
+#define PCI_DPC_CAP_DL_ACT_ERR 0x1000 /* DPC DL_Active ERR_COR Signal */
+#define PCI_DPC_CTL 6 /* DPC Control */
+#define PCI_DPC_CTL_TRIGGER(x) ((x) & 0x3) /* DPC Trigger Enable */
+#define PCI_DPC_CTL_CMPL 0x4 /* DPC Completion Control */
+#define PCI_DPC_CTL_INT 0x8 /* DPC Interrupt Enabled */
+#define PCI_DPC_CTL_ERR_COR 0x10 /* DPC ERR_COR Enabled */
+#define PCI_DPC_CTL_TLP 0x20 /* DPC Poisoned TLP Egress Blocking Enabled */
+#define PCI_DPC_CTL_SW_TRIGGER 0x40 /* DPC Software Trigger */
+#define PCI_DPC_CTL_DL_ACTIVE 0x80 /* DPC DL_Active ERR_COR Enable */
+#define PCI_DPC_STATUS 8 /* DPC STATUS */
+#define PCI_DPC_STS_TRIGGER 0x01 /* DPC Trigger Status */
+#define PCI_DPC_STS_REASON(x) (((x) >> 1) & 0x3) /* DPC Trigger Reason */
+#define PCI_DPC_STS_INT 0x08 /* DPC Interrupt Status */
+#define PCI_DPC_STS_RP_BUSY 0x10 /* DPC Root Port Busy */
+#define PCI_DPC_STS_TRIGGER_EXT(x) (((x) >> 5) & 0x3) /* Trigger Reason Extention */
+#define PCI_DPC_STS_PIO_FEP(x) (((x) >> 8) & 0x1f) /* DPC PIO First Error Pointer */
+#define PCI_DPC_SOURCE 10 /* DPC Source ID */
+
+/* L1 PM Substates Extended Capability */
+#define PCI_L1PM_SUBSTAT_CAP 0x4 /* L1 PM Substate Capability */
+#define PCI_L1PM_SUBSTAT_CAP_PM_L12 0x1 /* PCI-PM L1.2 Supported */
+#define PCI_L1PM_SUBSTAT_CAP_PM_L11 0x2 /* PCI-PM L1.1 Supported */
+#define PCI_L1PM_SUBSTAT_CAP_ASPM_L12 0x4 /* ASPM L1.2 Supported */
+#define PCI_L1PM_SUBSTAT_CAP_ASPM_L11 0x8 /* ASPM L1.1 Supported */
+#define PCI_L1PM_SUBSTAT_CAP_L1PM_SUPP 0x16 /* L1 PM Substates supported */
+#define PCI_L1PM_SUBSTAT_CTL1 0x8 /* L1 PM Substate Control 1 */
+#define PCI_L1PM_SUBSTAT_CTL1_PM_L12 0x1 /* PCI-PM L1.2 Enable */
+#define PCI_L1PM_SUBSTAT_CTL1_PM_L11 0x2 /* PCI-PM L1.1 Enable */
+#define PCI_L1PM_SUBSTAT_CTL1_ASPM_L12 0x4 /* ASPM L1.2 Enable */
+#define PCI_L1PM_SUBSTAT_CTL1_ASPM_L11 0x8 /* ASPM L1.1 Enable */
+#define PCI_L1PM_SUBSTAT_CTL2 0xC /* L1 PM Substate Control 2 */
+
+/*
+ * The PCI interface treats multi-function devices as independent
+ * devices. The slot/function address of each device is encoded
+ * in a single byte as follows:
+ *
+ * 7:3 = slot
+ * 2:0 = function
+ */
+#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn) ((devfn) & 0x07)
+
+/* Device classes and subclasses */
+
+#define PCI_CLASS_NOT_DEFINED 0x0000
+#define PCI_CLASS_NOT_DEFINED_VGA 0x0001
+
+#define PCI_BASE_CLASS_STORAGE 0x01
+#define PCI_CLASS_STORAGE_SCSI 0x0100
+#define PCI_CLASS_STORAGE_IDE 0x0101
+#define PCI_CLASS_STORAGE_FLOPPY 0x0102
+#define PCI_CLASS_STORAGE_IPI 0x0103
+#define PCI_CLASS_STORAGE_RAID 0x0104
+#define PCI_CLASS_STORAGE_ATA 0x0105
+#define PCI_CLASS_STORAGE_SATA 0x0106
+#define PCI_CLASS_STORAGE_SAS 0x0107
+#define PCI_CLASS_STORAGE_OTHER 0x0180
+
+#define PCI_BASE_CLASS_NETWORK 0x02
+#define PCI_CLASS_NETWORK_ETHERNET 0x0200
+#define PCI_CLASS_NETWORK_TOKEN_RING 0x0201
+#define PCI_CLASS_NETWORK_FDDI 0x0202
+#define PCI_CLASS_NETWORK_ATM 0x0203
+#define PCI_CLASS_NETWORK_ISDN 0x0204
+#define PCI_CLASS_NETWORK_OTHER 0x0280
+
+#define PCI_BASE_CLASS_DISPLAY 0x03
+#define PCI_CLASS_DISPLAY_VGA 0x0300
+#define PCI_CLASS_DISPLAY_XGA 0x0301
+#define PCI_CLASS_DISPLAY_3D 0x0302
+#define PCI_CLASS_DISPLAY_OTHER 0x0380
+
+#define PCI_BASE_CLASS_MULTIMEDIA 0x04
+#define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400
+#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
+#define PCI_CLASS_MULTIMEDIA_PHONE 0x0402
+#define PCI_CLASS_MULTIMEDIA_AUDIO_DEV 0x0403
+#define PCI_CLASS_MULTIMEDIA_OTHER 0x0480
+
+#define PCI_BASE_CLASS_MEMORY 0x05
+#define PCI_CLASS_MEMORY_RAM 0x0500
+#define PCI_CLASS_MEMORY_FLASH 0x0501
+#define PCI_CLASS_MEMORY_OTHER 0x0580
+
+#define PCI_BASE_CLASS_BRIDGE 0x06
+#define PCI_CLASS_BRIDGE_HOST 0x0600
+#define PCI_CLASS_BRIDGE_ISA 0x0601
+#define PCI_CLASS_BRIDGE_EISA 0x0602
+#define PCI_CLASS_BRIDGE_MC 0x0603
+#define PCI_CLASS_BRIDGE_PCI 0x0604
+#define PCI_CLASS_BRIDGE_PCMCIA 0x0605
+#define PCI_CLASS_BRIDGE_NUBUS 0x0606
+#define PCI_CLASS_BRIDGE_CARDBUS 0x0607
+#define PCI_CLASS_BRIDGE_RACEWAY 0x0608
+#define PCI_CLASS_BRIDGE_PCI_SEMI 0x0609
+#define PCI_CLASS_BRIDGE_IB_TO_PCI 0x060a
+#define PCI_CLASS_BRIDGE_OTHER 0x0680
+
+#define PCI_BASE_CLASS_COMMUNICATION 0x07
+#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700
+#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
+#define PCI_CLASS_COMMUNICATION_MSERIAL 0x0702
+#define PCI_CLASS_COMMUNICATION_MODEM 0x0703
+#define PCI_CLASS_COMMUNICATION_OTHER 0x0780
+
+#define PCI_BASE_CLASS_SYSTEM 0x08
+#define PCI_CLASS_SYSTEM_PIC 0x0800
+#define PCI_CLASS_SYSTEM_DMA 0x0801
+#define PCI_CLASS_SYSTEM_TIMER 0x0802
+#define PCI_CLASS_SYSTEM_RTC 0x0803
+#define PCI_CLASS_SYSTEM_PCI_HOTPLUG 0x0804
+#define PCI_CLASS_SYSTEM_OTHER 0x0880
+
+#define PCI_BASE_CLASS_INPUT 0x09
+#define PCI_CLASS_INPUT_KEYBOARD 0x0900
+#define PCI_CLASS_INPUT_PEN 0x0901
+#define PCI_CLASS_INPUT_MOUSE 0x0902
+#define PCI_CLASS_INPUT_SCANNER 0x0903
+#define PCI_CLASS_INPUT_GAMEPORT 0x0904
+#define PCI_CLASS_INPUT_OTHER 0x0980
+
+#define PCI_BASE_CLASS_DOCKING 0x0a
+#define PCI_CLASS_DOCKING_GENERIC 0x0a00
+#define PCI_CLASS_DOCKING_OTHER 0x0a80
+
+#define PCI_BASE_CLASS_PROCESSOR 0x0b
+#define PCI_CLASS_PROCESSOR_386 0x0b00
+#define PCI_CLASS_PROCESSOR_486 0x0b01
+#define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02
+#define PCI_CLASS_PROCESSOR_ALPHA 0x0b10
+#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20
+#define PCI_CLASS_PROCESSOR_MIPS 0x0b30
+#define PCI_CLASS_PROCESSOR_CO 0x0b40
+
+#define PCI_BASE_CLASS_SERIAL 0x0c
+#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00
+#define PCI_CLASS_SERIAL_ACCESS 0x0c01
+#define PCI_CLASS_SERIAL_SSA 0x0c02
+#define PCI_CLASS_SERIAL_USB 0x0c03
+#define PCI_CLASS_SERIAL_FIBER 0x0c04
+#define PCI_CLASS_SERIAL_SMBUS 0x0c05
+#define PCI_CLASS_SERIAL_INFINIBAND 0x0c06
+
+#define PCI_BASE_CLASS_WIRELESS 0x0d
+#define PCI_CLASS_WIRELESS_IRDA 0x0d00
+#define PCI_CLASS_WIRELESS_CONSUMER_IR 0x0d01
+#define PCI_CLASS_WIRELESS_RF 0x0d10
+#define PCI_CLASS_WIRELESS_OTHER 0x0d80
+
+#define PCI_BASE_CLASS_INTELLIGENT 0x0e
+#define PCI_CLASS_INTELLIGENT_I2O 0x0e00
+
+#define PCI_BASE_CLASS_SATELLITE 0x0f
+#define PCI_CLASS_SATELLITE_TV 0x0f00
+#define PCI_CLASS_SATELLITE_AUDIO 0x0f01
+#define PCI_CLASS_SATELLITE_VOICE 0x0f03
+#define PCI_CLASS_SATELLITE_DATA 0x0f04
+
+#define PCI_BASE_CLASS_CRYPT 0x10
+#define PCI_CLASS_CRYPT_NETWORK 0x1000
+#define PCI_CLASS_CRYPT_ENTERTAINMENT 0x1010
+#define PCI_CLASS_CRYPT_OTHER 0x1080
+
+#define PCI_BASE_CLASS_SIGNAL 0x11
+#define PCI_CLASS_SIGNAL_DPIO 0x1100
+#define PCI_CLASS_SIGNAL_PERF_CTR 0x1101
+#define PCI_CLASS_SIGNAL_SYNCHRONIZER 0x1110
+#define PCI_CLASS_SIGNAL_OTHER 0x1180
+
+#define PCI_CLASS_OTHERS 0xff
+
+/* Several ID's we need in the library */
+
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_VENDOR_ID_COMPAQ 0x0e11
+
+/* I/O resource flags, compatible with <include/linux/ioport.h> */
+
+#define PCI_IORESOURCE_PCI_EA_BEI (1<<5)
diff --git a/lib/hurd.c b/lib/hurd.c
new file mode 100644
index 0000000..7b3b2ae
--- /dev/null
+++ b/lib/hurd.c
@@ -0,0 +1,380 @@
+/*
+ * The PCI Library -- Hurd access via RPCs
+ *
+ * Copyright (c) 2017 Joan Lledó <jlledom@member.fsf.org>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#define _GNU_SOURCE
+
+#include "internal.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <string.h>
+#include <hurd.h>
+#include <hurd/pci.h>
+#include <hurd/paths.h>
+
+/* Server path */
+#define _SERVERS_BUS_PCI _SERVERS_BUS "/pci"
+
+/* File names */
+#define FILE_CONFIG_NAME "config"
+#define FILE_ROM_NAME "rom"
+
+/* Level in the fs tree */
+typedef enum
+{
+ LEVEL_NONE,
+ LEVEL_DOMAIN,
+ LEVEL_BUS,
+ LEVEL_DEV,
+ LEVEL_FUNC
+} tree_level;
+
+/* Check whether there's a pci server */
+static int
+hurd_detect(struct pci_access *a)
+{
+ int err;
+ struct stat st;
+
+ err = stat(_SERVERS_BUS_PCI, &st);
+ if (err)
+ {
+ a->error("Could not open file `%s'", _SERVERS_BUS_PCI);
+ return 0;
+ }
+
+ /* The node must be a directory and a translator */
+ return S_ISDIR(st.st_mode) && ((st.st_mode & S_ITRANS) == S_IROOT);
+}
+
+/* Empty callbacks, we don't need any special init or cleanup */
+static void
+hurd_init(struct pci_access *a UNUSED)
+{
+}
+
+static void
+hurd_cleanup(struct pci_access *a UNUSED)
+{
+}
+
+/* Each device has its own server path. Allocate space for the port. */
+static void
+hurd_init_dev(struct pci_dev *d)
+{
+ d->aux = pci_malloc(d->access, sizeof(mach_port_t));
+}
+
+/* Deallocate the port and free its space */
+static void
+hurd_cleanup_dev(struct pci_dev *d)
+{
+ mach_port_t device_port;
+
+ device_port = *((mach_port_t *) d->aux);
+ mach_port_deallocate(mach_task_self(), device_port);
+
+ pci_mfree(d->aux);
+}
+
+/* Walk through the FS tree to see what is allowed for us */
+static void
+enum_devices(const char *parent, struct pci_access *a, int domain, int bus,
+ int dev, int func, tree_level lev)
+{
+ int ret;
+ DIR *dir;
+ struct dirent *entry;
+ char path[NAME_MAX];
+ char server[NAME_MAX];
+ uint32_t vd;
+ uint8_t ht;
+ mach_port_t device_port;
+ struct pci_dev *d;
+
+ dir = opendir(parent);
+ if (!dir)
+ {
+ if (errno == EPERM || errno == EACCES)
+ /* The client lacks the permissions to access this function, skip */
+ return;
+ else
+ a->error("Cannot open directory: %s (%s)", parent, strerror(errno));
+ }
+
+ while ((entry = readdir(dir)) != 0)
+ {
+ snprintf(path, NAME_MAX, "%s/%s", parent, entry->d_name);
+ if (entry->d_type == DT_DIR)
+ {
+ if (!strncmp(entry->d_name, ".", NAME_MAX)
+ || !strncmp(entry->d_name, "..", NAME_MAX))
+ continue;
+
+ errno = 0;
+ ret = strtol(entry->d_name, 0, 16);
+ if (errno)
+ {
+ if (closedir(dir) < 0)
+ a->warning("Cannot close directory: %s (%s)", parent,
+ strerror(errno));
+ a->error("Wrong directory name: %s (number expected) probably \
+ not connected to an arbiter", entry->d_name);
+ }
+
+ /*
+ * We found a valid directory.
+ * Update the address and switch to the next level.
+ */
+ switch (lev)
+ {
+ case LEVEL_DOMAIN:
+ domain = ret;
+ break;
+ case LEVEL_BUS:
+ bus = ret;
+ break;
+ case LEVEL_DEV:
+ dev = ret;
+ break;
+ case LEVEL_FUNC:
+ func = ret;
+ break;
+ default:
+ if (closedir(dir) < 0)
+ a->warning("Cannot close directory: %s (%s)", parent,
+ strerror(errno));
+ a->error("Wrong directory tree, probably not connected \
+ to an arbiter");
+ }
+
+ enum_devices(path, a, domain, bus, dev, func, lev + 1);
+ }
+ else
+ {
+ if (strncmp(entry->d_name, FILE_CONFIG_NAME, NAME_MAX))
+ /* We are looking for the config file */
+ continue;
+
+ /* We found an available virtual device, add it to our list */
+ snprintf(server, NAME_MAX, "%s/%04x/%02x/%02x/%01u/%s",
+ _SERVERS_BUS_PCI, domain, bus, dev, func, entry->d_name);
+ device_port = file_name_lookup(server, 0, 0);
+ if (device_port == MACH_PORT_NULL)
+ {
+ if (closedir(dir) < 0)
+ a->warning("Cannot close directory: %s (%s)", parent,
+ strerror(errno));
+ a->error("Cannot open %s", server);
+ }
+
+ d = pci_alloc_dev(a);
+ *((mach_port_t *) d->aux) = device_port;
+ d->bus = bus;
+ d->dev = dev;
+ d->func = func;
+ pci_link_dev(a, d);
+
+ vd = pci_read_long(d, PCI_VENDOR_ID);
+ ht = pci_read_byte(d, PCI_HEADER_TYPE);
+
+ d->vendor_id = vd & 0xffff;
+ d->device_id = vd >> 16U;
+ d->known_fields = PCI_FILL_IDENT;
+ d->hdrtype = ht;
+ }
+ }
+
+ if (closedir(dir) < 0)
+ a->error("Cannot close directory: %s (%s)", parent, strerror(errno));
+}
+
+/* Enumerate devices */
+static void
+hurd_scan(struct pci_access *a)
+{
+ enum_devices(_SERVERS_BUS_PCI, a, -1, -1, -1, -1, LEVEL_DOMAIN);
+}
+
+/*
+ * Read `len' bytes to `buf'.
+ *
+ * Returns error when the number of read bytes does not match `len'.
+ */
+static int
+hurd_read(struct pci_dev *d, int pos, byte * buf, int len)
+{
+ int err;
+ size_t nread;
+ char *data;
+ mach_port_t device_port;
+
+ nread = len;
+ device_port = *((mach_port_t *) d->aux);
+ if (len > 4)
+ err = !pci_generic_block_read(d, pos, buf, nread);
+ else
+ {
+ data = (char *) buf;
+ err = pci_conf_read(device_port, pos, &data, &nread, len);
+
+ if (data != (char *) buf)
+ {
+ if (nread > (size_t) len) /* Sanity check for bogus server. */
+ {
+ vm_deallocate(mach_task_self(), (vm_address_t) data, nread);
+ return 0;
+ }
+
+ memcpy(buf, data, nread);
+ vm_deallocate(mach_task_self(), (vm_address_t) data, nread);
+ }
+ }
+ if (err)
+ return 0;
+
+ return nread == (size_t) len;
+}
+
+/*
+ * Write `len' bytes from `buf'.
+ *
+ * Returns error when the number of written bytes does not match `len'.
+ */
+static int
+hurd_write(struct pci_dev *d, int pos, byte * buf, int len)
+{
+ int err;
+ size_t nwrote;
+ mach_port_t device_port;
+
+ nwrote = len;
+ device_port = *((mach_port_t *) d->aux);
+ if (len > 4)
+ err = !pci_generic_block_write(d, pos, buf, len);
+ else
+ err = pci_conf_write(device_port, pos, (char *) buf, len, &nwrote);
+ if (err)
+ return 0;
+
+ return nwrote == (size_t) len;
+}
+
+/* Get requested info from the server */
+
+static void
+hurd_fill_regions(struct pci_dev *d)
+{
+ mach_port_t device_port = *((mach_port_t *) d->aux);
+ struct pci_bar regions[6];
+ char *buf = (char *) &regions;
+ size_t size = sizeof(regions);
+
+ int err = pci_get_dev_regions(device_port, &buf, &size);
+ if (err)
+ return;
+
+ if ((char *) &regions != buf)
+ {
+ /* Sanity check for bogus server. */
+ if (size > sizeof(regions))
+ {
+ vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
+ return;
+ }
+
+ memcpy(&regions, buf, size);
+ vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
+ }
+
+ for (int i = 0; i < 6; i++)
+ {
+ if (regions[i].size == 0)
+ continue;
+
+ d->base_addr[i] = regions[i].base_addr;
+ d->base_addr[i] |= regions[i].is_IO;
+ d->base_addr[i] |= regions[i].is_64 << 2;
+ d->base_addr[i] |= regions[i].is_prefetchable << 3;
+
+ if (flags & PCI_FILL_SIZES)
+ d->size[i] = regions[i].size;
+ }
+}
+
+static void
+hurd_fill_rom(struct pci_dev *d)
+{
+ struct pci_xrom_bar rom;
+ mach_port_t device_port = *((mach_port_t *) d->aux);
+ char *buf = (char *) &rom;
+ size_t size = sizeof(rom);
+
+ int err = pci_get_dev_rom(device_port, &buf, &size);
+ if (err)
+ return;
+
+ if ((char *) &rom != buf)
+ {
+ /* Sanity check for bogus server. */
+ if (size > sizeof(rom))
+ {
+ vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
+ return;
+ }
+
+ memcpy(&rom, buf, size);
+ vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
+ }
+
+ d->rom_base_addr = rom.base_addr;
+ d->rom_size = rom.size;
+}
+
+static unsigned int
+hurd_fill_info(struct pci_dev *d, unsigned int flags)
+{
+ unsigned int done = 0;
+
+ if (!d->access->buscentric)
+ {
+ if (flags & (PCI_FILL_BASES | PCI_FILL_SIZES))
+ {
+ hurd_fill_regions(d);
+ done |= PCI_FILL_BASES | PCI_FILL_SIZES;
+ }
+ if (flags & PCI_FILL_ROM_BASE)
+ {
+ hurd_fill_rom(d);
+ done |= PCI_FILL_ROM_BASE;
+ }
+ }
+
+ return done | pci_generic_fill_info(d, flags & ~done);
+}
+
+struct pci_methods pm_hurd = {
+ "hurd",
+ "Hurd access using RPCs",
+ NULL, /* config */
+ hurd_detect,
+ hurd_init,
+ hurd_cleanup,
+ hurd_scan,
+ hurd_fill_info,
+ hurd_read,
+ hurd_write,
+ NULL, /* read_vpd */
+ hurd_init_dev,
+ hurd_cleanup_dev
+};
diff --git a/lib/i386-io-beos.h b/lib/i386-io-beos.h
new file mode 100644
index 0000000..a0ee6c9
--- /dev/null
+++ b/lib/i386-io-beos.h
@@ -0,0 +1,67 @@
+/*
+ * The PCI Library -- Access to i386 I/O ports on BeOS
+ *
+ * Copyright (c) 2009 Francois Revol <revol@free.fr>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+/* those are private syscalls */
+extern int read_isa_io(int pci_bus, void *addr, int size);
+extern int write_isa_io(int pci_bus, void *addr, int size, u32 value);
+
+static int
+intel_setup_io(struct pci_access *a UNUSED)
+{
+ return 1;
+}
+
+static inline int
+intel_cleanup_io(struct pci_access *a UNUSED)
+{
+ return 1;
+}
+
+static inline u8
+inb (u16 port)
+{
+ return (u8)read_isa_io(0, (void *)(u32)port, sizeof(u8));
+}
+
+static inline u16
+inw (u16 port)
+{
+ return (u16)read_isa_io(0, (void *)(u32)port, sizeof(u16));
+}
+
+static inline u32
+inl (u16 port)
+{
+ return (u32)read_isa_io(0, (void *)(u32)port, sizeof(u32));
+}
+
+static inline void
+outb (u8 value, u16 port)
+{
+ write_isa_io(0, (void *)(u32)port, sizeof(value), value);
+}
+
+static inline void
+outw (u16 value, u16 port)
+{
+ write_isa_io(0, (void *)(u32)port, sizeof(value), value);
+}
+
+static inline void
+outl (u32 value, u16 port)
+{
+ write_isa_io(0, (void *)(u32)port, sizeof(value), value);
+}
+
+static inline void intel_io_lock(void)
+{
+}
+
+static inline void intel_io_unlock(void)
+{
+}
diff --git a/lib/i386-io-cygwin.h b/lib/i386-io-cygwin.h
new file mode 100644
index 0000000..1602248
--- /dev/null
+++ b/lib/i386-io-cygwin.h
@@ -0,0 +1,30 @@
+/*
+ * The PCI Library -- Access to i386 I/O ports under Windows with CYGWIN
+ *
+ * Copyright (c) 1997--2006 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <sys/io.h>
+
+static int
+intel_setup_io(struct pci_access *a UNUSED)
+{
+ return (iopl(3) < 0) ? 0 : 1;
+}
+
+static inline int
+intel_cleanup_io(struct pci_access *a UNUSED)
+{
+ iopl(3);
+ return -1;
+}
+
+static inline void intel_io_lock(void)
+{
+}
+
+static inline void intel_io_unlock(void)
+{
+}
diff --git a/lib/i386-io-djgpp.h b/lib/i386-io-djgpp.h
new file mode 100644
index 0000000..41885db
--- /dev/null
+++ b/lib/i386-io-djgpp.h
@@ -0,0 +1,45 @@
+/*
+ * The PCI Library -- Access to i386 I/O ports on DJGPP
+ *
+ * Copyright (c) 2010, 2017 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <pc.h>
+#include <dos.h>
+#define outb(x,y) outportb(y, x)
+#define outw(x,y) outportw(y, x)
+#define outl(x,y) outportl(y, x)
+
+#define inb inportb
+#define inw inportw
+#define inl inportl
+
+static int irq_enabled;
+
+static int
+intel_setup_io(struct pci_access *a UNUSED)
+{
+ return 1;
+}
+
+static inline int
+intel_cleanup_io(struct pci_access *a UNUSED)
+{
+ return 1;
+}
+
+static inline void intel_io_lock(void)
+{
+ asm volatile("" : : : "memory");
+ irq_enabled = disable();
+}
+
+static inline void intel_io_unlock(void)
+{
+ asm volatile("" : : : "memory");
+ if (irq_enabled) {
+ enable();
+ }
+}
diff --git a/lib/i386-io-haiku.h b/lib/i386-io-haiku.h
new file mode 100644
index 0000000..2bbe592
--- /dev/null
+++ b/lib/i386-io-haiku.h
@@ -0,0 +1,132 @@
+/*
+ * The PCI Library -- Access to i386 I/O ports on Haiku
+ *
+ * Copyright (c) 2009 Francois Revol <revol@free.fr>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <Drivers.h>
+#include <ISA.h>
+#include <PCI.h>
+
+/* from haiku/trunk/headers/private/drivers/poke.h */
+
+#define POKE_DEVICE_NAME "poke"
+#define POKE_DEVICE_FULLNAME "/dev/misc/poke"
+#define POKE_SIGNATURE 'wltp' // "We Like To Poke"
+
+enum {
+ POKE_PORT_READ = B_DEVICE_OP_CODES_END + 1,
+ POKE_PORT_WRITE,
+ POKE_PORT_INDEXED_READ,
+ POKE_PORT_INDEXED_WRITE,
+ POKE_PCI_READ_CONFIG,
+ POKE_PCI_WRITE_CONFIG,
+ POKE_GET_NTH_PCI_INFO,
+ POKE_GET_PHYSICAL_ADDRESS,
+ POKE_MAP_MEMORY,
+ POKE_UNMAP_MEMORY
+};
+
+
+typedef struct {
+ uint32 signature;
+ uint8 index;
+ pci_info* info;
+ status_t status;
+} pci_info_args;
+
+
+typedef struct {
+ uint32 signature;
+ uint16 port;
+ uint8 size; // == index for POKE_PORT_INDEXED_*
+ uint32 value;
+} port_io_args;
+
+
+typedef struct {
+ uint32 signature;
+ uint8 bus;
+ uint8 device;
+ uint8 function;
+ uint8 size;
+ uint8 offset;
+ uint32 value;
+} pci_io_args;
+
+
+/* en poke.h*/
+
+static int poke_driver_fd;
+
+static int
+intel_setup_io(struct pci_access *a UNUSED)
+{
+ poke_driver_fd = open(POKE_DEVICE_FULLNAME, O_RDWR);
+ return (poke_driver_fd < 0) ? 0 : 1;
+}
+
+static inline int
+intel_cleanup_io(struct pci_access *a UNUSED)
+{
+ close(poke_driver_fd);
+ return 1;
+}
+
+static inline u8
+inb (u16 port)
+{
+ port_io_args args = { POKE_SIGNATURE, port, sizeof(u8), 0 };
+ if (ioctl(poke_driver_fd, POKE_PORT_READ, &args, sizeof(args)) < 0)
+ return 0;
+ return (u8)args.value;
+}
+
+static inline u16
+inw (u16 port)
+{
+ port_io_args args = { POKE_SIGNATURE, port, sizeof(u16), 0 };
+ if (ioctl(poke_driver_fd, POKE_PORT_READ, &args, sizeof(args)) < 0)
+ return 0;
+ return (u16)args.value;
+}
+
+static inline u32
+inl (u16 port)
+{
+ port_io_args args = { POKE_SIGNATURE, port, sizeof(u32), 0 };
+ if (ioctl(poke_driver_fd, POKE_PORT_READ, &args, sizeof(args)) < 0)
+ return 0;
+ return (u32)args.value;
+}
+
+static inline void
+outb (u8 value, u16 port)
+{
+ port_io_args args = { POKE_SIGNATURE, port, sizeof(u8), value };
+ ioctl(poke_driver_fd, POKE_PORT_WRITE, &args, sizeof(args));
+}
+
+static inline void
+outw (u16 value, u16 port)
+{
+ port_io_args args = { POKE_SIGNATURE, port, sizeof(u16), value };
+ ioctl(poke_driver_fd, POKE_PORT_WRITE, &args, sizeof(args));
+}
+
+static inline void
+outl (u32 value, u16 port)
+{
+ port_io_args args = { POKE_SIGNATURE, port, sizeof(u32), value };
+ ioctl(poke_driver_fd, POKE_PORT_WRITE, &args, sizeof(args));
+}
+
+static inline void intel_io_lock(void)
+{
+}
+
+static inline void intel_io_unlock(void)
+{
+}
diff --git a/lib/i386-io-hurd.h b/lib/i386-io-hurd.h
new file mode 100644
index 0000000..d6df909
--- /dev/null
+++ b/lib/i386-io-hurd.h
@@ -0,0 +1,35 @@
+/*
+ * The PCI Library -- Access to i386 I/O ports on GNU Hurd
+ *
+ * Copyright (c) 2003 Marco Gerards <metgerards@student.han.nl>
+ * Copyright (c) 2003 Martin Mares <mj@ucw.cz>
+ * Copyright (c) 2006 Samuel Thibault <samuel.thibault@ens-lyon.org> and
+ * Thomas Schwinge <tschwinge@gnu.org>
+ * Copyright (c) 2007 Thomas Schwinge <tschwinge@gnu.org>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <sys/io.h>
+
+static inline int
+intel_setup_io(struct pci_access *a UNUSED)
+{
+ return (ioperm (0, 65535, 1) == -1) ? 0 : 1;
+}
+
+static inline int
+intel_cleanup_io(struct pci_access *a UNUSED)
+{
+ ioperm (0, 65535, 0);
+
+ return -1;
+}
+
+static inline void intel_io_lock(void)
+{
+}
+
+static inline void intel_io_unlock(void)
+{
+}
diff --git a/lib/i386-io-linux.h b/lib/i386-io-linux.h
new file mode 100644
index 0000000..b39b4eb
--- /dev/null
+++ b/lib/i386-io-linux.h
@@ -0,0 +1,30 @@
+/*
+ * The PCI Library -- Access to i386 I/O ports on Linux
+ *
+ * Copyright (c) 1997--2006 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <sys/io.h>
+
+static int
+intel_setup_io(struct pci_access *a UNUSED)
+{
+ return (iopl(3) < 0) ? 0 : 1;
+}
+
+static inline int
+intel_cleanup_io(struct pci_access *a UNUSED)
+{
+ iopl(3);
+ return -1;
+}
+
+static inline void intel_io_lock(void)
+{
+}
+
+static inline void intel_io_unlock(void)
+{
+}
diff --git a/lib/i386-io-sunos.h b/lib/i386-io-sunos.h
new file mode 100644
index 0000000..6221d13
--- /dev/null
+++ b/lib/i386-io-sunos.h
@@ -0,0 +1,74 @@
+/*
+ * The PCI Library -- Access to i386 I/O ports on Solaris
+ *
+ * Copyright (c) 2003 Bill Moore <billm@eng.sun.com>
+ * Copyright (c) 2003--2006 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <sys/sysi86.h>
+#include <sys/psw.h>
+
+static int
+intel_setup_io(struct pci_access *a UNUSED)
+{
+ return (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) < 0) ? 0 : 1;
+}
+
+static inline int
+intel_cleanup_io(struct pci_access *a UNUSED)
+{
+ /* FIXME: How to switch off I/O port access? */
+ return 1;
+}
+
+static inline u8
+inb (u16 port)
+{
+ u8 v;
+ __asm__ __volatile__ ("inb (%w1)":"=a" (v):"Nd" (port));
+ return v;
+}
+
+static inline u16
+inw (u16 port)
+{
+ u16 v;
+ __asm__ __volatile__ ("inw (%w1)":"=a" (v):"Nd" (port));
+ return v;
+}
+
+static inline u32
+inl (u16 port)
+{
+ u32 v;
+ __asm__ __volatile__ ("inl (%w1)":"=a" (v):"Nd" (port));
+ return v;
+}
+
+static inline void
+outb (u8 value, u16 port)
+{
+ __asm__ __volatile__ ("outb (%w1)": :"a" (value), "Nd" (port));
+}
+
+static inline void
+outw (u16 value, u16 port)
+{
+ __asm__ __volatile__ ("outw (%w1)": :"a" (value), "Nd" (port));
+}
+
+static inline void
+outl (u32 value, u16 port)
+{
+ __asm__ __volatile__ ("outl (%w1)": :"a" (value), "Nd" (port));
+}
+
+static inline void intel_io_lock(void)
+{
+}
+
+static inline void intel_io_unlock(void)
+{
+}
diff --git a/lib/i386-io-windows.h b/lib/i386-io-windows.h
new file mode 100644
index 0000000..d5823ee
--- /dev/null
+++ b/lib/i386-io-windows.h
@@ -0,0 +1,77 @@
+/*
+ * The PCI Library -- Access to i386 I/O ports on Windows
+ *
+ * Copyright (c) 2004 Alexander Stock <stock.alexander@gmx.de>
+ * Copyright (c) 2006 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <io.h>
+#include <windows.h>
+
+#ifndef __GNUC__
+#include <conio.h>
+#else
+int _outp(unsigned short port, int databyte);
+unsigned short _outpw(unsigned short port, unsigned short dataword);
+unsigned long _outpd(unsigned short port, unsigned long dataword);
+int _inp(unsigned short port);
+unsigned short _inpw(unsigned short port);
+unsigned long _inpd(unsigned short port);
+#endif
+
+#define outb(x,y) _outp(y,x)
+#define outw(x,y) _outpw(y,x)
+#define outl(x,y) _outpd(y,x)
+
+#define inb(x) _inp(x)
+#define inw(x) _inpw(x)
+#define inl(x) _inpd(x)
+
+static int
+intel_setup_io(struct pci_access *a)
+{
+ typedef int (*MYPROC)(void);
+ MYPROC InitializeWinIo;
+ HMODULE lib;
+
+ lib = LoadLibrary("WinIo.dll");
+ if (!lib)
+ {
+ a->warning("i386-io-windows: Couldn't load WinIo.dll.");
+ return 0;
+ }
+ /* XXX: Is this really needed? --mj */
+ GetProcAddress(lib, "InitializeWinIo");
+
+ InitializeWinIo = (MYPROC) GetProcAddress(lib, "InitializeWinIo");
+ if (!InitializeWinIo)
+ {
+ a->warning("i386-io-windows: Couldn't find InitializeWinIo function.");
+ return 0;
+ }
+
+ if (!InitializeWinIo())
+ {
+ a->warning("i386-io-windows: InitializeWinIo() failed.");
+ return 0;
+ }
+
+ return 1;
+}
+
+static inline int
+intel_cleanup_io(struct pci_access *a UNUSED)
+{
+ //TODO: DeInitializeWinIo!
+ return 1;
+}
+
+static inline void intel_io_lock(void)
+{
+}
+
+static inline void intel_io_unlock(void)
+{
+}
diff --git a/lib/i386-ports.c b/lib/i386-ports.c
new file mode 100644
index 0000000..b3b752c
--- /dev/null
+++ b/lib/i386-ports.c
@@ -0,0 +1,315 @@
+/*
+ * The PCI Library -- Direct Configuration access via i386 Ports
+ *
+ * Copyright (c) 1997--2006 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#define _GNU_SOURCE
+
+#include "internal.h"
+
+#include <unistd.h>
+
+#if defined(PCI_OS_LINUX)
+#include "i386-io-linux.h"
+#elif defined(PCI_OS_GNU)
+#include "i386-io-hurd.h"
+#elif defined(PCI_OS_SUNOS)
+#include "i386-io-sunos.h"
+#elif defined(PCI_OS_WINDOWS)
+#include "i386-io-windows.h"
+#elif defined(PCI_OS_CYGWIN)
+#include "i386-io-cygwin.h"
+#elif defined(PCI_OS_HAIKU)
+#include "i386-io-haiku.h"
+#elif defined(PCI_OS_BEOS)
+#include "i386-io-beos.h"
+#elif defined(PCI_OS_DJGPP)
+#include "i386-io-djgpp.h"
+#else
+#error Do not know how to access I/O ports on this OS.
+#endif
+
+static int conf12_io_enabled = -1; /* -1=haven't tried, 0=failed, 1=succeeded */
+
+static int
+conf12_setup_io(struct pci_access *a)
+{
+ if (conf12_io_enabled < 0)
+ conf12_io_enabled = intel_setup_io(a);
+ return conf12_io_enabled;
+}
+
+static void
+conf12_init(struct pci_access *a)
+{
+ if (!conf12_setup_io(a))
+ a->error("No permission to access I/O ports (you probably have to be root).");
+}
+
+static void
+conf12_cleanup(struct pci_access *a UNUSED)
+{
+ if (conf12_io_enabled > 0)
+ conf12_io_enabled = intel_cleanup_io(a);
+}
+
+/*
+ * Before we decide to use direct hardware access mechanisms, we try to do some
+ * trivial checks to ensure it at least _seems_ to be working -- we just test
+ * whether bus 00 contains a host bridge (this is similar to checking
+ * techniques used in XFree86, but ours should be more reliable since we
+ * attempt to make use of direct access hints provided by the PCI BIOS).
+ *
+ * This should be close to trivial, but it isn't, because there are buggy
+ * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
+ */
+
+static int
+intel_sanity_check(struct pci_access *a, struct pci_methods *m)
+{
+ struct pci_dev d;
+
+ a->debug("...sanity check");
+ d.bus = 0;
+ d.func = 0;
+ for (d.dev = 0; d.dev < 32; d.dev++)
+ {
+ u16 class, vendor;
+ if (m->read(&d, PCI_CLASS_DEVICE, (byte *) &class, sizeof(class)) &&
+ (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST) || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA)) ||
+ m->read(&d, PCI_VENDOR_ID, (byte *) &vendor, sizeof(vendor)) &&
+ (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL) || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ)))
+ {
+ a->debug("...outside the Asylum at 0/%02x/0", d.dev);
+ return 1;
+ }
+ }
+ a->debug("...insane");
+ return 0;
+}
+
+/*
+ * Configuration type 1
+ */
+
+#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
+
+static int
+conf1_detect(struct pci_access *a)
+{
+ unsigned int tmp;
+ int res = 0;
+
+ if (!conf12_setup_io(a))
+ {
+ a->debug("...no I/O permission");
+ return 0;
+ }
+
+ intel_io_lock();
+ outb (0x01, 0xCFB);
+ tmp = inl (0xCF8);
+ outl (0x80000000, 0xCF8);
+ if (inl (0xCF8) == 0x80000000)
+ res = 1;
+ outl (tmp, 0xCF8);
+ intel_io_unlock();
+
+ if (res)
+ res = intel_sanity_check(a, &pm_intel_conf1);
+ return res;
+}
+
+static int
+conf1_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int addr = 0xcfc + (pos&3);
+ int res = 1;
+
+ if (d->domain || pos >= 256)
+ return 0;
+
+ intel_io_lock();
+ outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
+
+ switch (len)
+ {
+ case 1:
+ buf[0] = inb(addr);
+ break;
+ case 2:
+ ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
+ break;
+ case 4:
+ ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
+ break;
+ default:
+ res = pci_generic_block_read(d, pos, buf, len);
+ }
+
+ intel_io_unlock();
+ return res;
+}
+
+static int
+conf1_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int addr = 0xcfc + (pos&3);
+ int res = 1;
+
+ if (d->domain || pos >= 256)
+ return 0;
+
+ intel_io_lock();
+ outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
+
+ switch (len)
+ {
+ case 1:
+ outb(buf[0], addr);
+ break;
+ case 2:
+ outw(le16_to_cpu(((u16 *) buf)[0]), addr);
+ break;
+ case 4:
+ outl(le32_to_cpu(((u32 *) buf)[0]), addr);
+ break;
+ default:
+ res = pci_generic_block_write(d, pos, buf, len);
+ }
+ intel_io_unlock();
+ return res;
+}
+
+/*
+ * Configuration type 2. Obsolete and brain-damaged, but existing.
+ */
+
+static int
+conf2_detect(struct pci_access *a)
+{
+ int res = 0;
+
+ if (!conf12_setup_io(a))
+ {
+ a->debug("...no I/O permission");
+ return 0;
+ }
+
+ /* This is ugly and tends to produce false positives. Beware. */
+
+ intel_io_lock();
+ outb(0x00, 0xCFB);
+ outb(0x00, 0xCF8);
+ outb(0x00, 0xCFA);
+ if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00)
+ res = intel_sanity_check(a, &pm_intel_conf2);
+ intel_io_unlock();
+ return res;
+}
+
+static int
+conf2_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int res = 1;
+ int addr = 0xc000 | (d->dev << 8) | pos;
+
+ if (d->domain || pos >= 256)
+ return 0;
+
+ if (d->dev >= 16)
+ /* conf2 supports only 16 devices per bus */
+ return 0;
+
+ intel_io_lock();
+ outb((d->func << 1) | 0xf0, 0xcf8);
+ outb(d->bus, 0xcfa);
+ switch (len)
+ {
+ case 1:
+ buf[0] = inb(addr);
+ break;
+ case 2:
+ ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
+ break;
+ case 4:
+ ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
+ break;
+ default:
+ res = pci_generic_block_read(d, pos, buf, len);
+ }
+ outb(0, 0xcf8);
+ intel_io_unlock();
+ return res;
+}
+
+static int
+conf2_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int res = 1;
+ int addr = 0xc000 | (d->dev << 8) | pos;
+
+ if (d->domain || pos >= 256)
+ return 0;
+
+ if (d->dev >= 16)
+ /* conf2 supports only 16 devices per bus */
+ return 0;
+
+ intel_io_lock();
+ outb((d->func << 1) | 0xf0, 0xcf8);
+ outb(d->bus, 0xcfa);
+ switch (len)
+ {
+ case 1:
+ outb(buf[0], addr);
+ break;
+ case 2:
+ outw(le16_to_cpu(* (u16 *) buf), addr);
+ break;
+ case 4:
+ outl(le32_to_cpu(* (u32 *) buf), addr);
+ break;
+ default:
+ res = pci_generic_block_write(d, pos, buf, len);
+ }
+
+ outb(0, 0xcf8);
+ intel_io_unlock();
+ return res;
+}
+
+struct pci_methods pm_intel_conf1 = {
+ "intel-conf1",
+ "Raw I/O port access using Intel conf1 interface",
+ NULL, /* config */
+ conf1_detect,
+ conf12_init,
+ conf12_cleanup,
+ pci_generic_scan,
+ pci_generic_fill_info,
+ conf1_read,
+ conf1_write,
+ NULL, /* read_vpd */
+ NULL, /* init_dev */
+ NULL /* cleanup_dev */
+};
+
+struct pci_methods pm_intel_conf2 = {
+ "intel-conf2",
+ "Raw I/O port access using Intel conf2 interface",
+ NULL, /* config */
+ conf2_detect,
+ conf12_init,
+ conf12_cleanup,
+ pci_generic_scan,
+ pci_generic_fill_info,
+ conf2_read,
+ conf2_write,
+ NULL, /* read_vpd */
+ NULL, /* init_dev */
+ NULL /* cleanup_dev */
+};
diff --git a/lib/init.c b/lib/init.c
new file mode 100644
index 0000000..e6295fc
--- /dev/null
+++ b/lib/init.c
@@ -0,0 +1,269 @@
+/*
+ * The PCI Library -- Initialization and related things
+ *
+ * Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "internal.h"
+
+static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = {
+ NULL,
+#ifdef PCI_HAVE_PM_LINUX_SYSFS
+ &pm_linux_sysfs,
+#else
+ NULL,
+#endif
+#ifdef PCI_HAVE_PM_LINUX_PROC
+ &pm_linux_proc,
+#else
+ NULL,
+#endif
+#ifdef PCI_HAVE_PM_INTEL_CONF
+ &pm_intel_conf1,
+ &pm_intel_conf2,
+#else
+ NULL,
+ NULL,
+#endif
+#ifdef PCI_HAVE_PM_FBSD_DEVICE
+ &pm_fbsd_device,
+#else
+ NULL,
+#endif
+#ifdef PCI_HAVE_PM_AIX_DEVICE
+ &pm_aix_device,
+#else
+ NULL,
+#endif
+#ifdef PCI_HAVE_PM_NBSD_LIBPCI
+ &pm_nbsd_libpci,
+#else
+ NULL,
+#endif
+#ifdef PCI_HAVE_PM_OBSD_DEVICE
+ &pm_obsd_device,
+#else
+ NULL,
+#endif
+#ifdef PCI_HAVE_PM_DUMP
+ &pm_dump,
+#else
+ NULL,
+#endif
+#ifdef PCI_HAVE_PM_DARWIN_DEVICE
+ &pm_darwin,
+#else
+ NULL,
+#endif
+#ifdef PCI_HAVE_PM_SYLIXOS_DEVICE
+ &pm_sylixos_device,
+#else
+ NULL,
+#endif
+#ifdef PCI_HAVE_PM_HURD_CONF
+ &pm_hurd,
+#else
+ NULL,
+#endif
+};
+
+// If PCI_ACCESS_AUTO is selected, we probe the access methods in this order
+static int probe_sequence[] = {
+ // System-specific methods
+ PCI_ACCESS_SYS_BUS_PCI,
+ PCI_ACCESS_PROC_BUS_PCI,
+ PCI_ACCESS_FBSD_DEVICE,
+ PCI_ACCESS_AIX_DEVICE,
+ PCI_ACCESS_NBSD_LIBPCI,
+ PCI_ACCESS_OBSD_DEVICE,
+ PCI_ACCESS_DARWIN,
+ PCI_ACCESS_SYLIXOS_DEVICE,
+ PCI_ACCESS_HURD,
+ // Low-level methods poking the hardware directly
+ PCI_ACCESS_I386_TYPE1,
+ PCI_ACCESS_I386_TYPE2,
+ -1,
+};
+
+void *
+pci_malloc(struct pci_access *a, int size)
+{
+ void *x = malloc(size);
+
+ if (!x)
+ a->error("Out of memory (allocation of %d bytes failed)", size);
+ return x;
+}
+
+void
+pci_mfree(void *x)
+{
+ if (x)
+ free(x);
+}
+
+char *
+pci_strdup(struct pci_access *a, const char *s)
+{
+ int len = strlen(s) + 1;
+ char *t = pci_malloc(a, len);
+ memcpy(t, s, len);
+ return t;
+}
+
+static void
+pci_generic_error(char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ fputs("pcilib: ", stderr);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fputc('\n', stderr);
+ exit(1);
+}
+
+static void
+pci_generic_warn(char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ fputs("pcilib: ", stderr);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+ fputc('\n', stderr);
+}
+
+static void
+pci_generic_debug(char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ vfprintf(stdout, msg, args);
+ va_end(args);
+}
+
+static void
+pci_null_debug(char *msg UNUSED, ...)
+{
+}
+
+int
+pci_lookup_method(char *name)
+{
+ int i;
+
+ for (i=0; i<PCI_ACCESS_MAX; i++)
+ if (pci_methods[i] && !strcmp(pci_methods[i]->name, name))
+ return i;
+ return -1;
+}
+
+char *
+pci_get_method_name(int index)
+{
+ if (index < 0 || index >= PCI_ACCESS_MAX)
+ return NULL;
+ else if (!pci_methods[index])
+ return "";
+ else
+ return pci_methods[index]->name;
+}
+
+struct pci_access *
+pci_alloc(void)
+{
+ struct pci_access *a = malloc(sizeof(struct pci_access));
+ int i;
+
+ memset(a, 0, sizeof(*a));
+ pci_set_name_list_path(a, PCI_PATH_IDS_DIR "/" PCI_IDS, 0);
+#ifdef PCI_USE_DNS
+ pci_define_param(a, "net.domain", PCI_ID_DOMAIN, "DNS domain used for resolving of ID's");
+ pci_define_param(a, "net.cache_name", "~/.pciids-cache", "Name of the ID cache file");
+ a->id_lookup_mode = PCI_LOOKUP_CACHE;
+#endif
+#ifdef PCI_HAVE_HWDB
+ pci_define_param(a, "hwdb.disable", "0", "Do not look up names in UDEV's HWDB if non-zero");
+#endif
+ for (i=0; i<PCI_ACCESS_MAX; i++)
+ if (pci_methods[i] && pci_methods[i]->config)
+ pci_methods[i]->config(a);
+ return a;
+}
+
+void
+pci_init_v35(struct pci_access *a)
+{
+ if (!a->error)
+ a->error = pci_generic_error;
+ if (!a->warning)
+ a->warning = pci_generic_warn;
+ if (!a->debug)
+ a->debug = pci_generic_debug;
+ if (!a->debugging)
+ a->debug = pci_null_debug;
+
+ if (a->method)
+ {
+ if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method])
+ a->error("This access method is not supported.");
+ a->methods = pci_methods[a->method];
+ }
+ else
+ {
+ unsigned int i;
+ for (i=0; probe_sequence[i] >= 0; i++)
+ {
+ struct pci_methods *m = pci_methods[probe_sequence[i]];
+ if (!m)
+ continue;
+ a->debug("Trying method %s...", m->name);
+ if (m->detect(a))
+ {
+ a->debug("...OK\n");
+ a->methods = m;
+ a->method = probe_sequence[i];
+ break;
+ }
+ a->debug("...No.\n");
+ }
+ if (!a->methods)
+ a->error("Cannot find any working access method.");
+ }
+ a->debug("Decided to use %s\n", a->methods->name);
+ a->methods->init(a);
+}
+
+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);
+SYMBOL_VERSION(pci_init_v35, pci_init@@LIBPCI_3.5);
+
+void
+pci_cleanup(struct pci_access *a)
+{
+ struct pci_dev *d, *e;
+
+ for (d=a->devices; d; d=e)
+ {
+ e = d->next;
+ pci_free_dev(d);
+ }
+ if (a->methods)
+ a->methods->cleanup(a);
+ pci_free_name_list(a);
+ pci_free_params(a);
+ pci_set_name_list_path(a, NULL, 0);
+ pci_mfree(a);
+}
diff --git a/lib/internal.h b/lib/internal.h
new file mode 100644
index 0000000..17c27e1
--- /dev/null
+++ b/lib/internal.h
@@ -0,0 +1,97 @@
+/*
+ * The PCI Library -- Internal Stuff
+ *
+ * Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "config.h"
+
+#ifdef PCI_SHARED_LIB
+#define PCI_ABI __attribute__((visibility("default")))
+// Functions, which are bound to externally visible symbols by the versioning
+// mechanism, have to be declared as VERSIONED. Otherwise, GCC with global
+// optimizations is happy to optimize them away, leading to linker failures.
+#define VERSIONED_ABI __attribute__((used)) PCI_ABI
+#ifdef __APPLE__
+#define STATIC_ALIAS(_decl, _for) _decl PCI_ABI { return _for; }
+#define DEFINE_ALIAS(_decl, _for)
+#define SYMBOL_VERSION(_int, _ext)
+#else
+#define STATIC_ALIAS(_decl, _for)
+#define DEFINE_ALIAS(_decl, _for) extern _decl __attribute__((alias(#_for)))
+#define SYMBOL_VERSION(_int, _ext) asm(".symver " #_int "," #_ext)
+#endif
+#else
+#define VERSIONED_ABI
+#define STATIC_ALIAS(_decl, _for) _decl { return _for; }
+#define DEFINE_ALIAS(_decl, _for)
+#define SYMBOL_VERSION(_int, _ext)
+#endif
+
+#include "pci.h"
+#include "sysdep.h"
+
+struct pci_methods {
+ char *name;
+ char *help;
+ void (*config)(struct pci_access *);
+ int (*detect)(struct pci_access *);
+ void (*init)(struct pci_access *);
+ void (*cleanup)(struct pci_access *);
+ void (*scan)(struct pci_access *);
+ unsigned int (*fill_info)(struct pci_dev *, unsigned int flags);
+ int (*read)(struct pci_dev *, int pos, byte *buf, int len);
+ int (*write)(struct pci_dev *, int pos, byte *buf, int len);
+ int (*read_vpd)(struct pci_dev *, int pos, byte *buf, int len);
+ void (*init_dev)(struct pci_dev *);
+ void (*cleanup_dev)(struct pci_dev *);
+};
+
+/* generic.c */
+void pci_generic_scan_bus(struct pci_access *, byte *busmap, int bus);
+void pci_generic_scan(struct pci_access *);
+unsigned int pci_generic_fill_info(struct pci_dev *, unsigned int flags);
+int pci_generic_block_read(struct pci_dev *, int pos, byte *buf, int len);
+int pci_generic_block_write(struct pci_dev *, int pos, byte *buf, int len);
+
+/* init.c */
+void *pci_malloc(struct pci_access *, int);
+void pci_mfree(void *);
+char *pci_strdup(struct pci_access *a, const char *s);
+
+void pci_init_v30(struct pci_access *a) VERSIONED_ABI;
+void pci_init_v35(struct pci_access *a) VERSIONED_ABI;
+
+/* access.c */
+struct pci_dev *pci_alloc_dev(struct pci_access *);
+int pci_link_dev(struct pci_access *, struct pci_dev *);
+
+int pci_fill_info_v30(struct pci_dev *, int flags) VERSIONED_ABI;
+int pci_fill_info_v31(struct pci_dev *, int flags) VERSIONED_ABI;
+int pci_fill_info_v32(struct pci_dev *, int flags) VERSIONED_ABI;
+int pci_fill_info_v33(struct pci_dev *, int flags) VERSIONED_ABI;
+int pci_fill_info_v34(struct pci_dev *, int flags) VERSIONED_ABI;
+int pci_fill_info_v35(struct pci_dev *, int flags) VERSIONED_ABI;
+
+struct pci_property {
+ struct pci_property *next;
+ u32 key;
+ char value[1];
+};
+
+char *pci_set_property(struct pci_dev *d, u32 key, char *value);
+
+/* params.c */
+void pci_define_param(struct pci_access *acc, char *param, char *val, char *help);
+int pci_set_param_internal(struct pci_access *acc, char *param, char *val, int copy);
+void pci_free_params(struct pci_access *acc);
+
+/* caps.c */
+unsigned int pci_scan_caps(struct pci_dev *, unsigned int want_fields);
+void pci_free_caps(struct pci_dev *);
+
+extern struct pci_methods pm_intel_conf1, pm_intel_conf2, pm_linux_proc,
+ pm_fbsd_device, pm_aix_device, pm_nbsd_libpci, pm_obsd_device,
+ pm_dump, pm_linux_sysfs, pm_darwin, pm_sylixos_device, pm_hurd;
diff --git a/lib/libpci.pc.in b/lib/libpci.pc.in
new file mode 100644
index 0000000..9d7e8a0
--- /dev/null
+++ b/lib/libpci.pc.in
@@ -0,0 +1,11 @@
+prefix=@PREFIX@
+includedir=@INCDIR@
+libdir=@LIBDIR@
+idsdir=@IDSDIR@
+
+Name: libpci
+Description: libpci
+Version: @VERSION@
+Libs: -L${libdir} -lpci
+Libs.private: @LDLIBS@
+Cflags: -I${includedir}
diff --git a/lib/libpci.ver b/lib/libpci.ver
new file mode 100644
index 0000000..e20c3f5
--- /dev/null
+++ b/lib/libpci.ver
@@ -0,0 +1,84 @@
+/* Version script for the libpci */
+
+/*
+ * Visibility declarations in the source take precedence over this script,
+ * so we can boldly declare pci_* as public and still keep the internal
+ * functions properly hidden.
+ */
+
+LIBPCI_3.0 {
+ global:
+ pci_alloc;
+ pci_cleanup;
+ pci_fill_info;
+ pci_filter_init;
+ pci_filter_match;
+ pci_filter_parse_id;
+ pci_filter_parse_slot;
+ pci_free_dev;
+ pci_free_name_list;
+ pci_get_dev;
+ pci_get_method_name;
+ pci_get_param;
+ pci_id_cache_flush;
+ pci_init;
+ pci_load_name_list;
+ pci_lookup_method;
+ pci_lookup_name;
+ pci_read_block;
+ pci_read_byte;
+ pci_read_long;
+ pci_read_word;
+ pci_scan_bus;
+ pci_set_name_list_path;
+ pci_set_param;
+ pci_setup_cache;
+ pci_walk_params;
+ pci_write_block;
+ pci_write_byte;
+ pci_write_long;
+ pci_write_word;
+ local: *;
+};
+
+LIBPCI_3.1 {
+ global:
+ pci_fill_info;
+ pci_find_cap;
+ pci_read_vpd;
+};
+
+LIBPCI_3.2 {
+ global:
+ pci_fill_info;
+};
+
+LIBPCI_3.3 {
+ global:
+ pci_fill_info;
+ pci_filter_init;
+ pci_filter_match;
+ pci_filter_parse_id;
+ pci_filter_parse_slot;
+};
+
+LIBPCI_3.4 {
+ global:
+ pci_fill_info;
+};
+
+LIBPCI_3.5 {
+ global:
+ pci_init;
+ pci_fill_info;
+};
+
+LIBPCI_3.6 {
+ global:
+ pci_get_string_property;
+};
+
+LIBPCI_3.7 {
+ global:
+ pci_find_cap_nr;
+};
diff --git a/lib/names-cache.c b/lib/names-cache.c
new file mode 100644
index 0000000..ba5de6d
--- /dev/null
+++ b/lib/names-cache.c
@@ -0,0 +1,204 @@
+/*
+ * The PCI Library -- ID to Name Cache
+ *
+ * Copyright (c) 2008--2009 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "internal.h"
+#include "names.h"
+
+#ifdef PCI_USE_DNS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
+
+static const char cache_version[] = "#PCI-CACHE-1.0";
+
+static char *get_cache_name(struct pci_access *a)
+{
+ char *name, *buf;
+
+ name = pci_get_param(a, "net.cache_name");
+ if (!name || !name[0])
+ return NULL;
+ if (strncmp(name, "~/", 2))
+ return name;
+
+ uid_t uid = getuid();
+ struct passwd *pw = getpwuid(uid);
+ if (!pw)
+ return name;
+
+ buf = pci_malloc(a, strlen(pw->pw_dir) + strlen(name+1) + 1);
+ sprintf(buf, "%s%s", pw->pw_dir, name+1);
+ pci_set_param_internal(a, "net.cache_name", buf, 1);
+ pci_mfree(buf);
+ return pci_get_param(a, "net.cache_name");
+}
+
+int
+pci_id_cache_load(struct pci_access *a, int flags)
+{
+ char *name;
+ char line[MAX_LINE];
+ FILE *f;
+ int lino;
+
+ a->id_cache_status = 1;
+ name = get_cache_name(a);
+ if (!name)
+ return 0;
+ a->debug("Using cache %s\n", name);
+ if (flags & PCI_LOOKUP_REFRESH_CACHE)
+ {
+ a->debug("Not loading cache, will refresh everything\n");
+ a->id_cache_status = 2;
+ return 0;
+ }
+
+ f = fopen(name, "rb");
+ if (!f)
+ {
+ a->debug("Cache file does not exist\n");
+ return 0;
+ }
+ /* FIXME: Compare timestamp with the pci.ids file? */
+
+ lino = 0;
+ while (fgets(line, sizeof(line), f))
+ {
+ char *p = strchr(line, '\n');
+ lino++;
+ if (p)
+ {
+ *p = 0;
+ if (lino == 1)
+ {
+ if (strcmp(line, cache_version))
+ {
+ a->debug("Unrecognized cache version %s, ignoring\n", line);
+ break;
+ }
+ continue;
+ }
+ else
+ {
+ int cat, id1, id2, id3, id4, cnt;
+ if (sscanf(line, "%d%x%x%x%x%n", &cat, &id1, &id2, &id3, &id4, &cnt) >= 5)
+ {
+ p = line + cnt;
+ while (*p && *p == ' ')
+ p++;
+ pci_id_insert(a, cat, id1, id2, id3, id4, p, SRC_CACHE);
+ continue;
+ }
+ }
+ }
+ a->warning("Malformed cache file %s (line %d), ignoring", name, lino);
+ break;
+ }
+
+ if (ferror(f))
+ a->warning("Error while reading %s", name);
+ fclose(f);
+ return 1;
+}
+
+void
+pci_id_cache_flush(struct pci_access *a)
+{
+ int orig_status = a->id_cache_status;
+ FILE *f;
+ unsigned int h;
+ struct id_entry *e, *e2;
+ char hostname[256], *tmpname, *name;
+ int this_pid;
+
+ a->id_cache_status = 0;
+ if (orig_status < 2)
+ return;
+ name = get_cache_name(a);
+ if (!name)
+ return;
+
+ this_pid = getpid();
+ if (gethostname(hostname, sizeof(hostname)) < 0)
+ hostname[0] = 0;
+ else
+ hostname[sizeof(hostname)-1] = 0;
+ tmpname = pci_malloc(a, strlen(name) + strlen(hostname) + 64);
+ sprintf(tmpname, "%s.tmp-%s-%d", name, hostname, this_pid);
+
+ f = fopen(tmpname, "wb");
+ if (!f)
+ {
+ a->warning("Cannot write to %s: %s", name, strerror(errno));
+ pci_mfree(tmpname);
+ return;
+ }
+ a->debug("Writing cache to %s\n", name);
+ fprintf(f, "%s\n", cache_version);
+
+ for (h=0; h<HASH_SIZE; h++)
+ for (e=a->id_hash[h]; e; e=e->next)
+ if (e->src == SRC_CACHE || e->src == SRC_NET)
+ {
+ /* Negative entries are not written */
+ if (!e->name[0])
+ continue;
+
+ /* Verify that every entry is written at most once */
+ for (e2=a->id_hash[h]; e2 != e; e2=e2->next)
+ if ((e2->src == SRC_CACHE || e2->src == SRC_NET) &&
+ e2->cat == e->cat &&
+ e2->id12 == e->id12 && e2->id34 == e->id34)
+ break;
+ if (e2 == e)
+ fprintf(f, "%d %x %x %x %x %s\n",
+ e->cat,
+ pair_first(e->id12), pair_second(e->id12),
+ pair_first(e->id34), pair_second(e->id34),
+ e->name);
+ }
+
+ fflush(f);
+ if (ferror(f))
+ a->warning("Error writing %s", name);
+ fclose(f);
+
+ if (rename(tmpname, name) < 0)
+ {
+ a->warning("Cannot rename %s to %s: %s", tmpname, name, strerror(errno));
+ unlink(tmpname);
+ }
+ pci_mfree(tmpname);
+}
+
+#else
+
+int pci_id_cache_load(struct pci_access *a UNUSED, int flags UNUSED)
+{
+ a->id_cache_status = 1;
+ return 0;
+}
+
+void pci_id_cache_flush(struct pci_access *a)
+{
+ a->id_cache_status = 0;
+}
+
+#endif
+
+void
+pci_id_cache_dirty(struct pci_access *a)
+{
+ if (a->id_cache_status >= 1)
+ a->id_cache_status = 2;
+}
diff --git a/lib/names-hash.c b/lib/names-hash.c
new file mode 100644
index 0000000..2f5bc3c
--- /dev/null
+++ b/lib/names-hash.c
@@ -0,0 +1,128 @@
+/*
+ * The PCI Library -- ID to Name Hash
+ *
+ * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <string.h>
+
+#include "internal.h"
+#include "names.h"
+
+struct id_bucket {
+ struct id_bucket *next;
+ unsigned int full;
+};
+
+#ifdef __GNUC__
+#define BUCKET_ALIGNMENT __alignof__(struct id_bucket)
+#else
+union id_align {
+ struct id_bucket *next;
+ unsigned int full;
+};
+#define BUCKET_ALIGNMENT sizeof(union id_align)
+#endif
+#define BUCKET_ALIGN(n) ((n)+BUCKET_ALIGNMENT-(n)%BUCKET_ALIGNMENT)
+
+static void *id_alloc(struct pci_access *a, unsigned int size)
+{
+ struct id_bucket *buck = a->current_id_bucket;
+ unsigned int pos;
+
+ if (!a->id_hash)
+ {
+ a->id_hash = pci_malloc(a, sizeof(struct id_entry *) * HASH_SIZE);
+ memset(a->id_hash, 0, sizeof(struct id_entry *) * HASH_SIZE);
+ }
+
+ if (!buck || buck->full + size > BUCKET_SIZE)
+ {
+ buck = pci_malloc(a, BUCKET_SIZE);
+ buck->next = a->current_id_bucket;
+ a->current_id_bucket = buck;
+ buck->full = BUCKET_ALIGN(sizeof(struct id_bucket));
+ }
+ pos = buck->full;
+ buck->full = BUCKET_ALIGN(buck->full + size);
+ return (byte *)buck + pos;
+}
+
+static inline unsigned int id_hash(int cat, u32 id12, u32 id34)
+{
+ unsigned int h;
+
+ h = id12 ^ (id34 << 3) ^ (cat << 5);
+ return h % HASH_SIZE;
+}
+
+int
+pci_id_insert(struct pci_access *a, int cat, int id1, int id2, int id3, int id4, char *text, enum id_entry_src src)
+{
+ u32 id12 = id_pair(id1, id2);
+ u32 id34 = id_pair(id3, id4);
+ unsigned int h = id_hash(cat, id12, id34);
+ struct id_entry *n = a->id_hash ? a->id_hash[h] : NULL;
+ int len = strlen(text);
+
+ while (n && (n->id12 != id12 || n->id34 != id34 || n->cat != cat))
+ n = n->next;
+ if (n)
+ return 1;
+ n = id_alloc(a, sizeof(struct id_entry) + len);
+ n->id12 = id12;
+ n->id34 = id34;
+ n->cat = cat;
+ n->src = src;
+ memcpy(n->name, text, len+1);
+ n->next = a->id_hash[h];
+ a->id_hash[h] = n;
+ return 0;
+}
+
+char
+*pci_id_lookup(struct pci_access *a, int flags, int cat, int id1, int id2, int id3, int id4)
+{
+ struct id_entry *n, *best;
+ u32 id12 = id_pair(id1, id2);
+ u32 id34 = id_pair(id3, id4);
+
+ if (a->id_hash)
+ {
+ n = a->id_hash[id_hash(cat, id12, id34)];
+ best = NULL;
+ for (; n; n=n->next)
+ {
+ if (n->id12 != id12 || n->id34 != id34 || n->cat != cat)
+ continue;
+ if (n->src == SRC_LOCAL && (flags & PCI_LOOKUP_SKIP_LOCAL))
+ continue;
+ if (n->src == SRC_NET && !(flags & PCI_LOOKUP_NETWORK))
+ continue;
+ if (n->src == SRC_CACHE && !(flags & PCI_LOOKUP_CACHE))
+ continue;
+ if (n->src == SRC_HWDB && (flags & (PCI_LOOKUP_SKIP_LOCAL | PCI_LOOKUP_NO_HWDB)))
+ continue;
+ if (!best || best->src < n->src)
+ best = n;
+ }
+ if (best)
+ return best->name;
+ }
+ return NULL;
+}
+
+void
+pci_id_hash_free(struct pci_access *a)
+{
+ pci_mfree(a->id_hash);
+ a->id_hash = NULL;
+ while (a->current_id_bucket)
+ {
+ struct id_bucket *buck = a->current_id_bucket;
+ a->current_id_bucket = buck->next;
+ pci_mfree(buck);
+ }
+}
diff --git a/lib/names-hwdb.c b/lib/names-hwdb.c
new file mode 100644
index 0000000..07b3499
--- /dev/null
+++ b/lib/names-hwdb.c
@@ -0,0 +1,109 @@
+/*
+ * The PCI Library -- Looking up Names via UDEV and HWDB
+ *
+ * Copyright (c) 2013--2014 Tom Gundersen <teg@jklm.no>
+ * Copyright (c) 2014 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <string.h>
+
+#include "internal.h"
+#include "names.h"
+
+#ifdef PCI_HAVE_HWDB
+
+#include <libudev.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+char *
+pci_id_hwdb_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4)
+{
+ char modalias[64];
+ const char *key = NULL;
+
+ const char *disabled = pci_get_param(a, "hwdb.disable");
+ if (disabled && atoi(disabled))
+ return NULL;
+
+ switch (cat)
+ {
+ case ID_VENDOR:
+ sprintf(modalias, "pci:v%08X*", id1);
+ key = "ID_VENDOR_FROM_DATABASE";
+ break;
+ case ID_DEVICE:
+ sprintf(modalias, "pci:v%08Xd%08X*", id1, id2);
+ key = "ID_MODEL_FROM_DATABASE";
+ break;
+ case ID_SUBSYSTEM:
+ sprintf(modalias, "pci:v%08Xd%08Xsv%08Xsd%08X*", id1, id2, id3, id4);
+ key = "ID_MODEL_FROM_DATABASE";
+ break;
+ case ID_GEN_SUBSYSTEM:
+ sprintf(modalias, "pci:v*d*sv%08Xsd%08X*", id1, id2);
+ key = "ID_MODEL_FROM_DATABASE";
+ break;
+ case ID_CLASS:
+ sprintf(modalias, "pci:v*d*sv*sd*bc%02X*", id1);
+ key = "ID_PCI_CLASS_FROM_DATABASE";
+ break;
+ case ID_SUBCLASS:
+ sprintf(modalias, "pci:v*d*sv*sd*bc%02Xsc%02X*", id1, id2);
+ key = "ID_PCI_SUBCLASS_FROM_DATABASE";
+ break;
+ case ID_PROGIF:
+ sprintf(modalias, "pci:v*d*sv*sd*bc%02Xsc%02Xi%02X*", id1, id2, id3);
+ key = "ID_PCI_INTERFACE_FROM_DATABASE";
+ break;
+ }
+
+ if (key)
+ {
+ if (!a->id_udev_hwdb)
+ {
+ a->debug("Initializing UDEV HWDB\n");
+ a->id_udev = udev_new();
+ a->id_udev_hwdb = udev_hwdb_new(a->id_udev);
+ }
+
+ struct udev_list_entry *entry;
+ udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(a->id_udev_hwdb, modalias, 0))
+ if (strcmp(udev_list_entry_get_name(entry), key) == 0)
+ return pci_strdup(a, udev_list_entry_get_value(entry));
+ }
+
+ return NULL;
+}
+
+void
+pci_id_hwdb_free(struct pci_access *a)
+{
+ if (a->id_udev_hwdb)
+ {
+ udev_hwdb_unref(a->id_udev_hwdb);
+ a->id_udev_hwdb = NULL;
+ }
+ if (a->id_udev)
+ {
+ udev_unref(a->id_udev);
+ a->id_udev = NULL;
+ }
+}
+
+#else
+
+char *
+pci_id_hwdb_lookup(struct pci_access *a UNUSED, int cat UNUSED, int id1 UNUSED, int id2 UNUSED, int id3 UNUSED, int id4 UNUSED)
+{
+ return NULL;
+}
+
+void
+pci_id_hwdb_free(struct pci_access *a UNUSED)
+{
+}
+
+#endif
diff --git a/lib/names-net.c b/lib/names-net.c
new file mode 100644
index 0000000..95a6fd2
--- /dev/null
+++ b/lib/names-net.c
@@ -0,0 +1,250 @@
+/*
+ * The PCI Library -- Resolving ID's via DNS
+ *
+ * Copyright (c) 2007--2008 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "internal.h"
+#include "names.h"
+
+#ifdef PCI_USE_DNS
+
+/*
+ * Our definition of BYTE_ORDER confuses arpa/nameser_compat.h on
+ * Solaris so we must undef it before including arpa/nameser.h.
+ */
+#ifdef PCI_OS_SUNOS
+#undef BYTE_ORDER
+#endif
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+
+/*
+ * Unfortunately, there are no portable functions for DNS RR parsing,
+ * so we will do the bit shuffling with our own bare hands.
+ */
+
+#define GET16(x) do { if (p+2 > end) goto err; x = (p[0] << 8) | p[1]; p += 2; } while (0)
+#define GET32(x) do { if (p+4 > end) goto err; x = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; p += 4; } while (0)
+
+enum dns_section {
+ DNS_SEC_QUESTION,
+ DNS_SEC_ANSWER,
+ DNS_SEC_AUTHORITY,
+ DNS_SEC_ADDITIONAL,
+ DNS_NUM_SECTIONS
+};
+
+struct dns_state {
+ u16 counts[DNS_NUM_SECTIONS];
+ byte *sections[DNS_NUM_SECTIONS+1];
+ byte *sec_ptr, *sec_end;
+
+ /* Result of dns_parse_rr(): */
+ u16 rr_type;
+ u16 rr_class;
+ u32 rr_ttl;
+ u16 rr_len;
+ byte *rr_data;
+};
+
+static byte *
+dns_skip_name(byte *p, byte *end)
+{
+ while (p < end)
+ {
+ unsigned int x = *p++;
+ if (!x)
+ return p;
+ switch (x & 0xc0)
+ {
+ case 0: /* Uncompressed: x = length */
+ p += x;
+ break;
+ case 0xc0: /* Indirection: 1 byte more for offset */
+ p++;
+ return (p < end) ? p : NULL;
+ default: /* RFU */
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+static int
+dns_parse_packet(struct dns_state *s, byte *p, unsigned int plen)
+{
+ byte *end = p + plen;
+ unsigned int i, j, len;
+ unsigned int UNUSED x;
+
+#if 0
+ /* Dump the packet */
+ for (i=0; i<plen; i++)
+ {
+ if (!(i%16)) printf("%04x:", i);
+ printf(" %02x", p[i]);
+ if ((i%16)==15 || i==plen-1) putchar('\n');
+ }
+#endif
+
+ GET32(x); /* ID and flags are ignored */
+ for (i=0; i<DNS_NUM_SECTIONS; i++)
+ GET16(s->counts[i]);
+ for (i=0; i<DNS_NUM_SECTIONS; i++)
+ {
+ s->sections[i] = p;
+ for (j=0; j < s->counts[i]; j++)
+ {
+ p = dns_skip_name(p, end); /* Name */
+ if (!p)
+ goto err;
+ GET32(x); /* Type and class */
+ if (i != DNS_SEC_QUESTION)
+ {
+ GET32(x); /* TTL */
+ GET16(len); /* Length of data */
+ p += len;
+ if (p > end)
+ goto err;
+ }
+ }
+ }
+ s->sections[i] = p;
+ return 0;
+
+err:
+ return -1;
+}
+
+static void
+dns_init_section(struct dns_state *s, int i)
+{
+ s->sec_ptr = s->sections[i];
+ s->sec_end = s->sections[i+1];
+}
+
+static int
+dns_parse_rr(struct dns_state *s)
+{
+ byte *p = s->sec_ptr;
+ byte *end = s->sec_end;
+
+ if (p == end)
+ return 0;
+ p = dns_skip_name(p, end);
+ if (!p)
+ goto err;
+ GET16(s->rr_type);
+ GET16(s->rr_class);
+ GET32(s->rr_ttl);
+ GET16(s->rr_len);
+ s->rr_data = p;
+ s->sec_ptr = p + s->rr_len;
+ return 1;
+
+err:
+ return -1;
+}
+
+char
+*pci_id_net_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4)
+{
+ static int resolver_inited;
+ char name[256], dnsname[256], txt[256], *domain;
+ byte answer[4096];
+ const byte *data;
+ int res, j, dlen;
+ struct dns_state ds;
+
+ domain = pci_get_param(a, "net.domain");
+ if (!domain || !domain[0])
+ return NULL;
+
+ switch (cat)
+ {
+ case ID_VENDOR:
+ sprintf(name, "%04x", id1);
+ break;
+ case ID_DEVICE:
+ sprintf(name, "%04x.%04x", id2, id1);
+ break;
+ case ID_SUBSYSTEM:
+ sprintf(name, "%04x.%04x.%04x.%04x", id4, id3, id2, id1);
+ break;
+ case ID_GEN_SUBSYSTEM:
+ sprintf(name, "%04x.%04x.s", id2, id1);
+ break;
+ case ID_CLASS:
+ sprintf(name, "%02x.c", id1);
+ break;
+ case ID_SUBCLASS:
+ sprintf(name, "%02x.%02x.c", id2, id1);
+ break;
+ case ID_PROGIF:
+ sprintf(name, "%02x.%02x.%02x.c", id3, id2, id1);
+ break;
+ default:
+ return NULL;
+ }
+ sprintf(dnsname, "%.100s.%.100s", name, domain);
+
+ a->debug("Resolving %s\n", dnsname);
+ if (!resolver_inited)
+ {
+ resolver_inited = 1;
+ res_init();
+ }
+ res = res_query(dnsname, ns_c_in, ns_t_txt, answer, sizeof(answer));
+ if (res < 0)
+ {
+ a->debug("\tfailed, h_errno=%d\n", h_errno);
+ return NULL;
+ }
+ if (dns_parse_packet(&ds, answer, res) < 0)
+ {
+ a->debug("\tMalformed DNS packet received\n");
+ return NULL;
+ }
+ dns_init_section(&ds, DNS_SEC_ANSWER);
+ while (dns_parse_rr(&ds) > 0)
+ {
+ if (ds.rr_class != ns_c_in || ds.rr_type != ns_t_txt)
+ {
+ a->debug("\tUnexpected RR in answer: class %d, type %d\n", ds.rr_class, ds.rr_type);
+ continue;
+ }
+ data = ds.rr_data;
+ dlen = ds.rr_len;
+ j = 0;
+ while (j < dlen && j+1+data[j] <= dlen)
+ {
+ memcpy(txt, &data[j+1], data[j]);
+ txt[data[j]] = 0;
+ j += 1+data[j];
+ a->debug("\t\"%s\"\n", txt);
+ if (txt[0] == 'i' && txt[1] == '=')
+ return strdup(txt+2);
+ }
+ }
+
+ return NULL;
+}
+
+#else
+
+char *pci_id_net_lookup(struct pci_access *a UNUSED, int cat UNUSED, int id1 UNUSED, int id2 UNUSED, int id3 UNUSED, int id4 UNUSED)
+{
+ return NULL;
+}
+
+#endif
diff --git a/lib/names-parse.c b/lib/names-parse.c
new file mode 100644
index 0000000..f3b7da9
--- /dev/null
+++ b/lib/names-parse.c
@@ -0,0 +1,252 @@
+/*
+ * The PCI Library -- Parsing of the ID list
+ *
+ * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "internal.h"
+#include "names.h"
+
+#ifdef PCI_COMPRESSED_IDS
+#include <zlib.h>
+typedef gzFile pci_file;
+#define pci_gets(f, l, s) gzgets(f, l, s)
+#define pci_eof(f) gzeof(f)
+
+static pci_file pci_open(struct pci_access *a)
+{
+ pci_file result;
+ size_t len;
+ char *new_name;
+
+ result = gzopen(a->id_file_name, "rb");
+ if (result)
+ return result;
+ len = strlen(a->id_file_name);
+ if (len < 3 || memcmp(a->id_file_name + len - 3, ".gz", 3) != 0)
+ return result;
+ new_name = malloc(len - 2);
+ memcpy(new_name, a->id_file_name, len - 3);
+ new_name[len - 3] = 0;
+ pci_set_name_list_path(a, new_name, 1);
+ return gzopen(a->id_file_name, "rb");
+}
+
+#define pci_close(f) gzclose(f)
+#define PCI_ERROR(f, err) \
+ if (!err) { \
+ int errnum; \
+ gzerror(f, &errnum); \
+ if (errnum >= 0) err = NULL; \
+ else if (errnum == Z_ERRNO) err = "I/O error"; \
+ else err = zError(errnum); \
+ }
+#else
+typedef FILE * pci_file;
+#define pci_gets(f, l, s) fgets(l, s, f)
+#define pci_eof(f) feof(f)
+#define pci_open(a) fopen(a->id_file_name, "r")
+#define pci_close(f) fclose(f)
+#define PCI_ERROR(f, err) if (!err && ferror(f)) err = "I/O error";
+#endif
+
+static int id_hex(char *p, int cnt)
+{
+ int x = 0;
+ while (cnt--)
+ {
+ x <<= 4;
+ if (*p >= '0' && *p <= '9')
+ x += (*p - '0');
+ else if (*p >= 'a' && *p <= 'f')
+ x += (*p - 'a' + 10);
+ else if (*p >= 'A' && *p <= 'F')
+ x += (*p - 'A' + 10);
+ else
+ return -1;
+ p++;
+ }
+ return x;
+}
+
+static inline int id_white_p(int c)
+{
+ return (c == ' ') || (c == '\t');
+}
+
+
+static const char *id_parse_list(struct pci_access *a, pci_file f, int *lino)
+{
+ char line[MAX_LINE];
+ char *p;
+ int id1=0, id2=0, id3=0, id4=0;
+ int cat = -1;
+ int nest;
+ static const char parse_error[] = "Parse error";
+
+ *lino = 0;
+ while (pci_gets(f, line, sizeof(line)))
+ {
+ (*lino)++;
+ p = line;
+ while (*p && *p != '\n' && *p != '\r')
+ p++;
+ if (!*p && !pci_eof(f))
+ return "Line too long";
+ *p = 0;
+ if (p > line && (p[-1] == ' ' || p[-1] == '\t'))
+ *--p = 0;
+
+ p = line;
+ while (id_white_p(*p))
+ p++;
+ if (!*p || *p == '#')
+ continue;
+
+ p = line;
+ while (*p == '\t')
+ p++;
+ nest = p - line;
+
+ if (!nest) /* Top-level entries */
+ {
+ if (p[0] == 'C' && p[1] == ' ') /* Class block */
+ {
+ if ((id1 = id_hex(p+2, 2)) < 0 || !id_white_p(p[4]))
+ return parse_error;
+ cat = ID_CLASS;
+ p += 5;
+ }
+ else if (p[0] == 'S' && p[1] == ' ')
+ { /* Generic subsystem block */
+ if ((id1 = id_hex(p+2, 4)) < 0 || p[6])
+ return parse_error;
+ if (!pci_id_lookup(a, 0, ID_VENDOR, id1, 0, 0, 0))
+ return "Vendor does not exist";
+ cat = ID_GEN_SUBSYSTEM;
+ continue;
+ }
+ else if (p[0] >= 'A' && p[0] <= 'Z' && p[1] == ' ')
+ { /* Unrecognized block (RFU) */
+ cat = ID_UNKNOWN;
+ continue;
+ }
+ else /* Vendor ID */
+ {
+ if ((id1 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
+ return parse_error;
+ cat = ID_VENDOR;
+ p += 5;
+ }
+ id2 = id3 = id4 = 0;
+ }
+ else if (cat == ID_UNKNOWN) /* Nested entries in RFU blocks are skipped */
+ continue;
+ else if (nest == 1) /* Nesting level 1 */
+ switch (cat)
+ {
+ case ID_VENDOR:
+ case ID_DEVICE:
+ case ID_SUBSYSTEM:
+ if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
+ return parse_error;
+ p += 5;
+ cat = ID_DEVICE;
+ id3 = id4 = 0;
+ break;
+ case ID_GEN_SUBSYSTEM:
+ if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
+ return parse_error;
+ p += 5;
+ id3 = id4 = 0;
+ break;
+ case ID_CLASS:
+ case ID_SUBCLASS:
+ case ID_PROGIF:
+ if ((id2 = id_hex(p, 2)) < 0 || !id_white_p(p[2]))
+ return parse_error;
+ p += 3;
+ cat = ID_SUBCLASS;
+ id3 = id4 = 0;
+ break;
+ default:
+ return parse_error;
+ }
+ else if (nest == 2) /* Nesting level 2 */
+ switch (cat)
+ {
+ case ID_DEVICE:
+ case ID_SUBSYSTEM:
+ if ((id3 = id_hex(p, 4)) < 0 || !id_white_p(p[4]) || (id4 = id_hex(p+5, 4)) < 0 || !id_white_p(p[9]))
+ return parse_error;
+ p += 10;
+ cat = ID_SUBSYSTEM;
+ break;
+ case ID_CLASS:
+ case ID_SUBCLASS:
+ case ID_PROGIF:
+ if ((id3 = id_hex(p, 2)) < 0 || !id_white_p(p[2]))
+ return parse_error;
+ p += 3;
+ cat = ID_PROGIF;
+ id4 = 0;
+ break;
+ default:
+ return parse_error;
+ }
+ else /* Nesting level 3 or more */
+ return parse_error;
+ while (id_white_p(*p))
+ p++;
+ if (!*p)
+ return parse_error;
+ if (pci_id_insert(a, cat, id1, id2, id3, id4, p, SRC_LOCAL))
+ return "Duplicate entry";
+ }
+ return NULL;
+}
+
+int
+pci_load_name_list(struct pci_access *a)
+{
+ pci_file f;
+ int lino;
+ const char *err;
+
+ pci_free_name_list(a);
+ a->id_load_failed = 1;
+ if (!(f = pci_open(a)))
+ return 0;
+ err = id_parse_list(a, f, &lino);
+ PCI_ERROR(f, err);
+ pci_close(f);
+ if (err)
+ a->error("%s at %s, line %d\n", err, a->id_file_name, lino);
+ a->id_load_failed = 0;
+ return 1;
+}
+
+void
+pci_free_name_list(struct pci_access *a)
+{
+ pci_id_cache_flush(a);
+ pci_id_hash_free(a);
+ pci_id_hwdb_free(a);
+ a->id_load_failed = 0;
+}
+
+void
+pci_set_name_list_path(struct pci_access *a, char *name, int to_be_freed)
+{
+ if (a->free_id_name)
+ free(a->id_file_name);
+ a->id_file_name = name;
+ a->free_id_name = to_be_freed;
+}
diff --git a/lib/names.c b/lib/names.c
new file mode 100644
index 0000000..df04495
--- /dev/null
+++ b/lib/names.c
@@ -0,0 +1,226 @@
+/*
+ * The PCI Library -- ID to Name Translation
+ *
+ * Copyright (c) 1997--2014 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "internal.h"
+#include "names.h"
+
+static char *id_lookup(struct pci_access *a, int flags, int cat, int id1, int id2, int id3, int id4)
+{
+ char *name;
+ int tried_hwdb = 0;
+
+ while (!(name = pci_id_lookup(a, flags, cat, id1, id2, id3, id4)))
+ {
+ if ((flags & PCI_LOOKUP_CACHE) && !a->id_cache_status)
+ {
+ if (pci_id_cache_load(a, flags))
+ continue;
+ }
+ if (!tried_hwdb && !(flags & (PCI_LOOKUP_SKIP_LOCAL | PCI_LOOKUP_NO_HWDB)))
+ {
+ tried_hwdb = 1;
+ if (name = pci_id_hwdb_lookup(a, cat, id1, id2, id3, id4))
+ {
+ pci_id_insert(a, cat, id1, id2, id3, id4, name, SRC_HWDB);
+ continue;
+ }
+ }
+ if (flags & PCI_LOOKUP_NETWORK)
+ {
+ if (name = pci_id_net_lookup(a, cat, id1, id2, id3, id4))
+ {
+ pci_id_insert(a, cat, id1, id2, id3, id4, name, SRC_NET);
+ pci_mfree(name);
+ pci_id_cache_dirty(a);
+ }
+ else
+ pci_id_insert(a, cat, id1, id2, id3, id4, "", SRC_NET);
+ /* We want to iterate the lookup to get the allocated ID entry from the hash */
+ continue;
+ }
+ return NULL;
+ }
+ return (name[0] ? name : NULL);
+}
+
+static char *
+id_lookup_subsys(struct pci_access *a, int flags, int iv, int id, int isv, int isd)
+{
+ char *d = NULL;
+ if (iv > 0 && id > 0) /* Per-device lookup */
+ d = id_lookup(a, flags, ID_SUBSYSTEM, iv, id, isv, isd);
+ if (!d) /* Generic lookup */
+ d = id_lookup(a, flags, ID_GEN_SUBSYSTEM, isv, isd, 0, 0);
+ if (!d && iv == isv && id == isd) /* Check for subsystem == device */
+ d = id_lookup(a, flags, ID_DEVICE, iv, id, 0, 0);
+ return d;
+}
+
+static char *
+format_name(char *buf, int size, int flags, char *name, char *num, char *unknown)
+{
+ int res;
+ if ((flags & PCI_LOOKUP_NO_NUMBERS) && !name)
+ return NULL;
+ else if (flags & PCI_LOOKUP_NUMERIC)
+ res = snprintf(buf, size, "%s", num);
+ else if (!name)
+ res = snprintf(buf, size, ((flags & PCI_LOOKUP_MIXED) ? "%s [%s]" : "%s %s"), unknown, num);
+ else if (!(flags & PCI_LOOKUP_MIXED))
+ res = snprintf(buf, size, "%s", name);
+ else
+ res = snprintf(buf, size, "%s [%s]", name, num);
+ if (res >= size && size >= 4)
+ buf[size-2] = buf[size-3] = buf[size-4] = '.';
+ else if (res < 0 || res >= size)
+ return "<pci_lookup_name: buffer too small>";
+ return buf;
+}
+
+static char *
+format_name_pair(char *buf, int size, int flags, char *v, char *d, char *num)
+{
+ int res;
+ if ((flags & PCI_LOOKUP_NO_NUMBERS) && (!v || !d))
+ return NULL;
+ if (flags & PCI_LOOKUP_NUMERIC)
+ res = snprintf(buf, size, "%s", num);
+ else if (flags & PCI_LOOKUP_MIXED)
+ {
+ if (v && d)
+ res = snprintf(buf, size, "%s %s [%s]", v, d, num);
+ else if (!v)
+ res = snprintf(buf, size, "Device [%s]", num);
+ else /* v && !d */
+ res = snprintf(buf, size, "%s Device [%s]", v, num);
+ }
+ else
+ {
+ if (v && d)
+ res = snprintf(buf, size, "%s %s", v, d);
+ else if (!v)
+ res = snprintf(buf, size, "Device %s", num);
+ else /* v && !d */
+ res = snprintf(buf, size, "%s Device %s", v, num+5);
+ }
+ if (res >= size && size >= 4)
+ buf[size-2] = buf[size-3] = buf[size-4] = '.';
+ else if (res < 0 || res >= size)
+ return "<pci_lookup_name: buffer too small>";
+ return buf;
+}
+
+char *
+pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, ...)
+{
+ va_list args;
+ char *v, *d, *cls, *pif;
+ int iv, id, isv, isd, icls, ipif;
+ char numbuf[16], pifbuf[32];
+
+ va_start(args, flags);
+
+ flags |= a->id_lookup_mode;
+ if (!(flags & PCI_LOOKUP_NO_NUMBERS))
+ {
+ if (a->numeric_ids > 1)
+ flags |= PCI_LOOKUP_MIXED;
+ else if (a->numeric_ids)
+ flags |= PCI_LOOKUP_NUMERIC;
+ }
+ if (flags & PCI_LOOKUP_MIXED)
+ flags &= ~PCI_LOOKUP_NUMERIC;
+
+ if (!a->id_hash && !(flags & (PCI_LOOKUP_NUMERIC | PCI_LOOKUP_SKIP_LOCAL)) && !a->id_load_failed)
+ pci_load_name_list(a);
+
+ switch (flags & 0xffff)
+ {
+ case PCI_LOOKUP_VENDOR:
+ iv = va_arg(args, int);
+ sprintf(numbuf, "%04x", iv);
+ va_end(args);
+ return format_name(buf, size, flags, id_lookup(a, flags, ID_VENDOR, iv, 0, 0, 0), numbuf, "Vendor");
+ case PCI_LOOKUP_DEVICE:
+ iv = va_arg(args, int);
+ id = va_arg(args, int);
+ sprintf(numbuf, "%04x", id);
+ va_end(args);
+ return format_name(buf, size, flags, id_lookup(a, flags, ID_DEVICE, iv, id, 0, 0), numbuf, "Device");
+ case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE:
+ iv = va_arg(args, int);
+ id = va_arg(args, int);
+ sprintf(numbuf, "%04x:%04x", iv, id);
+ v = id_lookup(a, flags, ID_VENDOR, iv, 0, 0, 0);
+ d = id_lookup(a, flags, ID_DEVICE, iv, id, 0, 0);
+ va_end(args);
+ return format_name_pair(buf, size, flags, v, d, numbuf);
+ case PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR:
+ isv = va_arg(args, int);
+ sprintf(numbuf, "%04x", isv);
+ v = id_lookup(a, flags, ID_VENDOR, isv, 0, 0, 0);
+ va_end(args);
+ return format_name(buf, size, flags, v, numbuf, "Unknown vendor");
+ case PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE:
+ iv = va_arg(args, int);
+ id = va_arg(args, int);
+ isv = va_arg(args, int);
+ isd = va_arg(args, int);
+ sprintf(numbuf, "%04x", isd);
+ va_end(args);
+ return format_name(buf, size, flags, id_lookup_subsys(a, flags, iv, id, isv, isd), numbuf, "Device");
+ case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
+ iv = va_arg(args, int);
+ id = va_arg(args, int);
+ isv = va_arg(args, int);
+ isd = va_arg(args, int);
+ v = id_lookup(a, flags, ID_VENDOR, isv, 0, 0, 0);
+ d = id_lookup_subsys(a, flags, iv, id, isv, isd);
+ sprintf(numbuf, "%04x:%04x", isv, isd);
+ va_end(args);
+ return format_name_pair(buf, size, flags, v, d, numbuf);
+ case PCI_LOOKUP_CLASS:
+ icls = va_arg(args, int);
+ sprintf(numbuf, "%04x", icls);
+ cls = id_lookup(a, flags, ID_SUBCLASS, icls >> 8, icls & 0xff, 0, 0);
+ if (!cls && (cls = id_lookup(a, flags, ID_CLASS, icls >> 8, 0, 0, 0)))
+ {
+ if (!(flags & PCI_LOOKUP_NUMERIC)) /* Include full class number */
+ flags |= PCI_LOOKUP_MIXED;
+ }
+ va_end(args);
+ return format_name(buf, size, flags, cls, numbuf, "Class");
+ case PCI_LOOKUP_PROGIF:
+ icls = va_arg(args, int);
+ ipif = va_arg(args, int);
+ sprintf(numbuf, "%02x", ipif);
+ pif = id_lookup(a, flags, ID_PROGIF, icls >> 8, icls & 0xff, ipif, 0);
+ if (!pif && icls == 0x0101 && !(ipif & 0x70))
+ {
+ /* IDE controllers have complex prog-if semantics */
+ sprintf(pifbuf, "%s%s%s%s%s",
+ (ipif & 0x80) ? " Master" : "",
+ (ipif & 0x08) ? " SecP" : "",
+ (ipif & 0x04) ? " SecO" : "",
+ (ipif & 0x02) ? " PriP" : "",
+ (ipif & 0x01) ? " PriO" : "");
+ pif = pifbuf;
+ if (*pif)
+ pif++;
+ }
+ va_end(args);
+ return format_name(buf, size, flags, pif, numbuf, "ProgIf");
+ default:
+ va_end(args);
+ return "<pci_lookup_name: invalid request>";
+ }
+}
diff --git a/lib/names.h b/lib/names.h
new file mode 100644
index 0000000..d7e71ff
--- /dev/null
+++ b/lib/names.h
@@ -0,0 +1,75 @@
+/*
+ * The PCI Library -- ID to Name Translation
+ *
+ * Copyright (c) 1997--2014 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#define MAX_LINE 1024
+
+/* names-hash.c */
+
+struct id_entry {
+ struct id_entry *next;
+ u32 id12, id34;
+ byte cat;
+ byte src;
+ char name[1];
+};
+
+enum id_entry_type {
+ ID_UNKNOWN,
+ ID_VENDOR,
+ ID_DEVICE,
+ ID_SUBSYSTEM,
+ ID_GEN_SUBSYSTEM,
+ ID_CLASS,
+ ID_SUBCLASS,
+ ID_PROGIF
+};
+
+enum id_entry_src {
+ SRC_UNKNOWN,
+ SRC_CACHE,
+ SRC_NET,
+ SRC_HWDB,
+ SRC_LOCAL,
+};
+
+#define BUCKET_SIZE 8192
+#define HASH_SIZE 4099
+
+static inline u32 id_pair(unsigned int x, unsigned int y)
+{
+ return ((x << 16) | y);
+}
+
+static inline unsigned int pair_first(unsigned int x)
+{
+ return (x >> 16) & 0xffff;
+}
+
+static inline unsigned int pair_second(unsigned int x)
+{
+ return x & 0xffff;
+}
+
+int pci_id_insert(struct pci_access *a, int cat, int id1, int id2, int id3, int id4, char *text, enum id_entry_src src);
+char *pci_id_lookup(struct pci_access *a, int flags, int cat, int id1, int id2, int id3, int id4);
+
+/* names-cache.c */
+
+int pci_id_cache_load(struct pci_access *a, int flags);
+void pci_id_cache_dirty(struct pci_access *a);
+void pci_id_cache_flush(struct pci_access *a);
+void pci_id_hash_free(struct pci_access *a);
+
+/* names-dns.c */
+
+char *pci_id_net_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4);
+
+/* names-hwdb.c */
+
+char *pci_id_hwdb_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4);
+void pci_id_hwdb_free(struct pci_access *a);
diff --git a/lib/nbsd-libpci.c b/lib/nbsd-libpci.c
new file mode 100644
index 0000000..2b2ca41
--- /dev/null
+++ b/lib/nbsd-libpci.c
@@ -0,0 +1,157 @@
+/*
+ * The PCI Library -- NetBSD libpci access
+ * (based on FreeBSD /dev/pci access)
+ *
+ * Copyright (c) 1999 Jari Kirma <kirma@cs.hut.fi>
+ * Copyright (c) 2002 Quentin Garnier <cube@cubidou.net>
+ * Copyright (c) 2002 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+/*
+ * Read functionality of this driver is briefly tested, and seems
+ * to supply basic information correctly, but I promise no more.
+ */
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <pci.h>
+
+#include "internal.h"
+
+static void
+nbsd_config(struct pci_access *a)
+{
+ pci_define_param(a, "nbsd.path", PCI_PATH_NBSD_DEVICE, "Path to the NetBSD PCI device");
+}
+
+static int
+nbsd_detect(struct pci_access *a)
+{
+ char *name = pci_get_param(a, "nbsd.path");
+
+ if (access(name, R_OK))
+ {
+ a->warning("Cannot open %s", name);
+ return 0;
+ }
+
+ if (!access(name, W_OK))
+ a->writeable = O_RDWR;
+ a->debug("...using %s", name);
+ return 1;
+}
+
+static void
+nbsd_init(struct pci_access *a)
+{
+ char *name = pci_get_param(a, "nbsd.path");
+ int mode = a->writeable ? O_RDWR : O_RDONLY;
+
+ a->fd = open(name, mode, 0);
+ if (a->fd < 0)
+ a->error("nbsd_init: %s open failed", name);
+}
+
+static void
+nbsd_cleanup(struct pci_access *a)
+{
+ close(a->fd);
+}
+
+static int
+nbsd_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ pcireg_t val;
+ int shift;
+
+ if (!(len == 1 || len == 2 || len == 4))
+ return pci_generic_block_read(d, pos, buf, len);
+
+ if (d->domain || pos >= 4096)
+ return 0;
+
+ shift = 8*(pos % 4);
+ pos &= ~3;
+
+ if (pcibus_conf_read(d->access->fd, d->bus, d->dev, d->func, pos, &val) < 0)
+ d->access->error("nbsd_read: pci_bus_conf_read() failed");
+
+ switch (len)
+ {
+ case 1:
+ *buf = val >> shift;
+ break;
+ case 2:
+ *(u16*)buf = cpu_to_le16(val >> shift);
+ break;
+ case 4:
+ *(u32*)buf = cpu_to_le32(val);
+ break;
+ }
+ return 1;
+}
+
+static int
+nbsd_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ pcireg_t val = 0;
+ int shift;
+
+ if (!(len == 1 || len == 2 || len == 4))
+ return pci_generic_block_write(d, pos, buf, len);
+
+ if (d->domain || pos >= 256)
+ return 0;
+
+ /*
+ * BEWARE: NetBSD seems to support only 32-bit access, so we have
+ * to emulate byte and word writes by read-modify-write, possibly
+ * causing troubles.
+ */
+
+ shift = 8*(pos % 4);
+ pos &= ~3;
+ if (len != 4)
+ {
+ if (pcibus_conf_read(d->access->fd, d->bus, d->dev, d->func, pos, &val) < 0)
+ d->access->error("nbsd_write: pci_bus_conf_read() failed");
+ }
+
+ switch (len)
+ {
+ case 1:
+ val = (val & ~(0xff << shift)) | (buf[0] << shift);
+ break;
+ case 2:
+ val = (val & ~(0xffff << shift)) | (le16_to_cpu(*(u16*)buf) << shift);
+ break;
+ case 4:
+ val = le32_to_cpu(*(u32*)buf);
+ break;
+ }
+
+ if (pcibus_conf_write(d->access->fd, d->bus, d->dev, d->func, pos, val) < 0)
+ d->access->error("nbsd_write: pci_bus_conf_write() failed");
+
+ return 1;
+}
+
+struct pci_methods pm_nbsd_libpci = {
+ "nbsd-libpci",
+ "NetBSD libpci",
+ nbsd_config,
+ nbsd_detect,
+ nbsd_init,
+ nbsd_cleanup,
+ pci_generic_scan,
+ pci_generic_fill_info,
+ nbsd_read,
+ nbsd_write,
+ NULL, /* read_vpd */
+ NULL, /* dev_init */
+ NULL /* dev_cleanup */
+};
diff --git a/lib/obsd-device.c b/lib/obsd-device.c
new file mode 100644
index 0000000..71cde5e
--- /dev/null
+++ b/lib/obsd-device.c
@@ -0,0 +1,152 @@
+/*
+ * The PCI Library -- OpenBSD /dev/pci access
+ *
+ * Adapted from fbsd-device.c by Matthieu Herrb <matthieu.herrb@laas.fr>, 2006
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/endian.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/pciio.h>
+#include "internal.h"
+
+static void
+obsd_config(struct pci_access *a)
+{
+ pci_define_param(a, "obsd.path", PCI_PATH_OBSD_DEVICE, "Path to the OpenBSD PCI device");
+}
+
+static int
+obsd_detect(struct pci_access *a)
+{
+ char *name = pci_get_param(a, "obsd.path");
+
+ if (access(name, R_OK))
+ {
+ a->warning("Cannot open %s", name);
+ return 0;
+ }
+ a->debug("...using %s", name);
+ return 1;
+}
+
+static void
+obsd_init(struct pci_access *a)
+{
+ char *name = pci_get_param(a, "obsd.path");
+
+ a->fd = open(name, O_RDWR, 0);
+ if (a->fd < 0)
+ a->error("obsd_init: %s open failed", name);
+}
+
+static void
+obsd_cleanup(struct pci_access *a)
+{
+ close(a->fd);
+}
+
+static int
+obsd_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ struct pci_io pi;
+ union {
+ u_int32_t u32;
+ u_int16_t u16[2];
+ u_int8_t u8[4];
+ } u;
+
+ if (!(len == 1 || len == 2 || len == 4))
+ return pci_generic_block_read(d, pos, buf, len);
+
+ if (d->domain || pos >= 256)
+ return 0;
+
+ pi.pi_sel.pc_bus = d->bus;
+ pi.pi_sel.pc_dev = d->dev;
+ pi.pi_sel.pc_func = d->func;
+
+ pi.pi_reg = pos - (pos % 4);
+ pi.pi_width = 4;
+
+ if (ioctl(d->access->fd, PCIOCREAD, &pi) < 0) {
+ if (errno == ENXIO)
+ pi.pi_data = 0xffffffff;
+ else
+ d->access->error("obsd_read: ioctl(PCIOCREAD) failed");
+ }
+ u.u32 = pi.pi_data;
+
+ switch (len)
+ {
+ case 1:
+ buf[0] = (u8) u.u8[pos % 4];
+ break;
+ case 2:
+ ((u16 *) buf)[0] = letoh16(u.u16[(pos % 4) / 2]);
+ break;
+ case 4:
+ ((u32 *) buf)[0] = (u32) letoh32(pi.pi_data);
+ break;
+ }
+ return 1;
+}
+
+static int
+obsd_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ struct pci_io pi;
+
+ if (!(len == 1 || len == 2 || len == 4))
+ return pci_generic_block_write(d, pos, buf, len);
+
+ if (d->domain || pos >= 256)
+ return 0;
+
+ pi.pi_sel.pc_bus = d->bus;
+ pi.pi_sel.pc_dev = d->dev;
+ pi.pi_sel.pc_func = d->func;
+
+ pi.pi_reg = pos;
+ pi.pi_width = len;
+
+ switch (len)
+ {
+ case 1:
+ pi.pi_data = buf[0];
+ break;
+ case 2:
+ pi.pi_data = ((u16 *) buf)[0];
+ break;
+ case 4:
+ pi.pi_data = ((u32 *) buf)[0];
+ break;
+ }
+
+ if (ioctl(d->access->fd, PCIOCWRITE, &pi) < 0)
+ d->access->error("obsd_write: ioctl(PCIOCWRITE) failed");
+
+ return 1;
+}
+
+struct pci_methods pm_obsd_device = {
+ "obsd-device",
+ "/dev/pci on OpenBSD",
+ obsd_config,
+ obsd_detect,
+ obsd_init,
+ obsd_cleanup,
+ pci_generic_scan,
+ pci_generic_fill_info,
+ obsd_read,
+ obsd_write,
+ NULL, /* read_vpd */
+ NULL, /* dev_init */
+ NULL /* dev_cleanup */
+};
diff --git a/lib/params.c b/lib/params.c
new file mode 100644
index 0000000..4d48cab
--- /dev/null
+++ b/lib/params.c
@@ -0,0 +1,87 @@
+/*
+ * The PCI Library -- Parameters
+ *
+ * Copyright (c) 2008 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "internal.h"
+
+char *
+pci_get_param(struct pci_access *acc, char *param)
+{
+ struct pci_param *p;
+
+ for (p=acc->params; p; p=p->next)
+ if (!strcmp(p->param, param))
+ return p->value;
+ return NULL;
+}
+
+void
+pci_define_param(struct pci_access *acc, char *param, char *value, char *help)
+{
+ struct pci_param *p = pci_malloc(acc, sizeof(*p));
+
+ p->next = acc->params;
+ acc->params = p;
+ p->param = param;
+ p->value = value;
+ p->value_malloced = 0;
+ p->help = help;
+}
+
+int
+pci_set_param_internal(struct pci_access *acc, char *param, char *value, int copy)
+{
+ struct pci_param *p;
+
+ for (p=acc->params; p; p=p->next)
+ if (!strcmp(p->param, param))
+ {
+ if (p->value_malloced)
+ pci_mfree(p->value);
+ p->value_malloced = copy;
+ if (copy)
+ p->value = pci_strdup(acc, value);
+ else
+ p->value = value;
+ return 0;
+ }
+ return -1;
+}
+
+int
+pci_set_param(struct pci_access *acc, char *param, char *value)
+{
+ return pci_set_param_internal(acc, param, value, 1);
+}
+
+void
+pci_free_params(struct pci_access *acc)
+{
+ struct pci_param *p;
+
+ while (p = acc->params)
+ {
+ acc->params = p->next;
+ if (p->value_malloced)
+ pci_mfree(p->value);
+ pci_mfree(p);
+ }
+}
+
+struct pci_param *
+pci_walk_params(struct pci_access *acc, struct pci_param *prev)
+{
+ /* So far, the params form a simple linked list, but this can change in the future */
+ if (!prev)
+ return acc->params;
+ else
+ return prev->next;
+}
diff --git a/lib/pci.h b/lib/pci.h
new file mode 100644
index 0000000..8142476
--- /dev/null
+++ b/lib/pci.h
@@ -0,0 +1,284 @@
+/*
+ * The PCI Library
+ *
+ * Copyright (c) 1997--2020 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _PCI_LIB_H
+#define _PCI_LIB_H
+
+#ifndef PCI_CONFIG_H
+#include "config.h"
+#endif
+
+#include "header.h"
+#include "types.h"
+
+#define PCI_LIB_VERSION 0x030700
+
+#ifndef PCI_ABI
+#define PCI_ABI
+#endif
+
+/*
+ * PCI Access Structure
+ */
+
+struct pci_methods;
+
+enum pci_access_type {
+ /* Known access methods, remember to update init.c as well */
+ PCI_ACCESS_AUTO, /* Autodetection */
+ PCI_ACCESS_SYS_BUS_PCI, /* Linux /sys/bus/pci */
+ PCI_ACCESS_PROC_BUS_PCI, /* Linux /proc/bus/pci */
+ PCI_ACCESS_I386_TYPE1, /* i386 ports, type 1 */
+ PCI_ACCESS_I386_TYPE2, /* i386 ports, type 2 */
+ PCI_ACCESS_FBSD_DEVICE, /* FreeBSD /dev/pci */
+ PCI_ACCESS_AIX_DEVICE, /* /dev/pci0, /dev/bus0, etc. */
+ PCI_ACCESS_NBSD_LIBPCI, /* NetBSD libpci */
+ PCI_ACCESS_OBSD_DEVICE, /* OpenBSD /dev/pci */
+ PCI_ACCESS_DUMP, /* Dump file */
+ PCI_ACCESS_DARWIN, /* Darwin */
+ PCI_ACCESS_SYLIXOS_DEVICE, /* SylixOS pci */
+ PCI_ACCESS_HURD, /* GNU/Hurd */
+ PCI_ACCESS_MAX
+};
+
+struct pci_access {
+ /* Options you can change: */
+ unsigned int method; /* Access method */
+ int writeable; /* Open in read/write mode */
+ int buscentric; /* Bus-centric view of the world */
+
+ char *id_file_name; /* Name of ID list file (use pci_set_name_list_path()) */
+ int free_id_name; /* Set if id_file_name is malloced */
+ int numeric_ids; /* Enforce PCI_LOOKUP_NUMERIC (>1 => PCI_LOOKUP_MIXED) */
+
+ unsigned int id_lookup_mode; /* pci_lookup_mode flags which are set automatically */
+ /* Default: PCI_LOOKUP_CACHE */
+
+ int debugging; /* Turn on debugging messages */
+
+ /* Functions you can override: */
+ void (*error)(char *msg, ...) PCI_PRINTF(1,2); /* Write error message and quit */
+ void (*warning)(char *msg, ...) PCI_PRINTF(1,2); /* Write a warning message */
+ void (*debug)(char *msg, ...) PCI_PRINTF(1,2); /* Write a debugging message */
+
+ struct pci_dev *devices; /* Devices found on this bus */
+
+ /* Fields used internally: */
+ struct pci_methods *methods;
+ struct pci_param *params;
+ struct id_entry **id_hash; /* names.c */
+ struct id_bucket *current_id_bucket;
+ int id_load_failed;
+ int id_cache_status; /* 0=not read, 1=read, 2=dirty */
+ struct udev *id_udev; /* names-hwdb.c */
+ struct udev_hwdb *id_udev_hwdb;
+ int fd; /* proc/sys: fd for config space */
+ int fd_rw; /* proc/sys: fd opened read-write */
+ int fd_pos; /* proc/sys: current position */
+ int fd_vpd; /* sys: fd for VPD */
+ struct pci_dev *cached_dev; /* proc/sys: device the fds are for */
+};
+
+/* Initialize PCI access */
+struct pci_access *pci_alloc(void) PCI_ABI;
+void pci_init(struct pci_access *) PCI_ABI;
+void pci_cleanup(struct pci_access *) PCI_ABI;
+
+/* Scanning of devices */
+void pci_scan_bus(struct pci_access *acc) PCI_ABI;
+struct pci_dev *pci_get_dev(struct pci_access *acc, int domain, int bus, int dev, int func) PCI_ABI; /* Raw access to specified device */
+void pci_free_dev(struct pci_dev *) PCI_ABI;
+
+/* Names of access methods */
+int pci_lookup_method(char *name) PCI_ABI; /* Returns -1 if not found */
+char *pci_get_method_name(int index) PCI_ABI; /* Returns "" if unavailable, NULL if index out of range */
+
+/*
+ * Named parameters
+ */
+
+struct pci_param {
+ struct pci_param *next; /* Please use pci_walk_params() for traversing the list */
+ char *param; /* Name of the parameter */
+ char *value; /* Value of the parameter */
+ int value_malloced; /* used internally */
+ char *help; /* Explanation of the parameter */
+};
+
+char *pci_get_param(struct pci_access *acc, char *param) PCI_ABI;
+int pci_set_param(struct pci_access *acc, char *param, char *value) PCI_ABI; /* 0 on success, -1 if no such parameter */
+/* To traverse the list, call pci_walk_params repeatedly, first with prev=NULL, and do not modify the parameters during traversal. */
+struct pci_param *pci_walk_params(struct pci_access *acc, struct pci_param *prev) PCI_ABI;
+
+/*
+ * Devices
+ */
+
+struct pci_dev {
+ struct pci_dev *next; /* Next device in the chain */
+ u16 domain_16; /* 16-bit version of the PCI domain for backward compatibility */
+ /* 0xffff if the real domain doesn't fit in 16 bits */
+ u8 bus, dev, func; /* Bus inside domain, device and function */
+
+ /* These fields are set by pci_fill_info() */
+ unsigned int known_fields; /* Set of info fields already known (see pci_fill_info()) */
+ u16 vendor_id, device_id; /* Identity of the device */
+ u16 device_class; /* PCI device class */
+ int irq; /* IRQ number */
+ pciaddr_t base_addr[6]; /* Base addresses including flags in lower bits */
+ pciaddr_t size[6]; /* Region sizes */
+ pciaddr_t rom_base_addr; /* Expansion ROM base address */
+ pciaddr_t rom_size; /* Expansion ROM size */
+ struct pci_cap *first_cap; /* List of capabilities */
+ char *phy_slot; /* Physical slot */
+ char *module_alias; /* Linux kernel module alias */
+ char *label; /* Device name as exported by BIOS */
+ int numa_node; /* NUMA node */
+ pciaddr_t flags[6]; /* PCI_IORESOURCE_* flags for regions */
+ pciaddr_t rom_flags; /* PCI_IORESOURCE_* flags for expansion ROM */
+ int domain; /* PCI domain (host bridge) */
+
+ /* Fields used internally */
+ struct pci_access *access;
+ struct pci_methods *methods;
+ u8 *cache; /* Cached config registers */
+ int cache_len;
+ int hdrtype; /* Cached low 7 bits of header type, -1 if unknown */
+ void *aux; /* Auxiliary data for use by the back-end */
+ struct pci_property *properties; /* A linked list of extra properties */
+ struct pci_cap *last_cap; /* Last capability in the list */
+};
+
+#define PCI_ADDR_IO_MASK (~(pciaddr_t) 0x3)
+#define PCI_ADDR_MEM_MASK (~(pciaddr_t) 0xf)
+#define PCI_ADDR_FLAG_MASK 0xf
+
+u8 pci_read_byte(struct pci_dev *, int pos) PCI_ABI; /* Access to configuration space */
+u16 pci_read_word(struct pci_dev *, int pos) PCI_ABI;
+u32 pci_read_long(struct pci_dev *, int pos) PCI_ABI;
+int pci_read_block(struct pci_dev *, int pos, u8 *buf, int len) PCI_ABI;
+int pci_read_vpd(struct pci_dev *d, int pos, u8 *buf, int len) PCI_ABI;
+int pci_write_byte(struct pci_dev *, int pos, u8 data) PCI_ABI;
+int pci_write_word(struct pci_dev *, int pos, u16 data) PCI_ABI;
+int pci_write_long(struct pci_dev *, int pos, u32 data) PCI_ABI;
+int pci_write_block(struct pci_dev *, int pos, u8 *buf, int len) PCI_ABI;
+
+/*
+ * Most device properties take some effort to obtain, so libpci does not
+ * initialize them during default bus scan. Instead, you have to call
+ * pci_fill_info() with the proper PCI_FILL_xxx constants OR'ed together.
+ *
+ * Some properties are stored directly in the pci_dev structure.
+ * The remaining ones can be accessed through pci_get_string_property().
+ *
+ * pci_fill_info() returns the current value of pci_dev->known_fields.
+ * This is a bit mask of all fields, which were already obtained during
+ * the lifetime of the device. This includes fields which are not supported
+ * by the particular device -- in that case, the field is left at its default
+ * value, which is 0 for integer fields and NULL for pointers. On the other
+ * hand, we never consider known fields unsupported by the current back-end;
+ * such fields always contain the default value.
+ *
+ * XXX: flags and the result should be unsigned, but we do not want to break the ABI.
+ */
+
+int pci_fill_info(struct pci_dev *, int flags) PCI_ABI;
+char *pci_get_string_property(struct pci_dev *d, u32 prop) PCI_ABI;
+
+#define PCI_FILL_IDENT 0x0001
+#define PCI_FILL_IRQ 0x0002
+#define PCI_FILL_BASES 0x0004
+#define PCI_FILL_ROM_BASE 0x0008
+#define PCI_FILL_SIZES 0x0010
+#define PCI_FILL_CLASS 0x0020
+#define PCI_FILL_CAPS 0x0040
+#define PCI_FILL_EXT_CAPS 0x0080
+#define PCI_FILL_PHYS_SLOT 0x0100
+#define PCI_FILL_MODULE_ALIAS 0x0200
+#define PCI_FILL_LABEL 0x0400
+#define PCI_FILL_NUMA_NODE 0x0800
+#define PCI_FILL_IO_FLAGS 0x1000
+#define PCI_FILL_DT_NODE 0x2000 /* Device tree node */
+#define PCI_FILL_IOMMU_GROUP 0x4000
+#define PCI_FILL_RESCAN 0x00010000
+
+void pci_setup_cache(struct pci_dev *, u8 *cache, int len) PCI_ABI;
+
+/*
+ * Capabilities
+ */
+
+struct pci_cap {
+ struct pci_cap *next;
+ u16 id; /* PCI_CAP_ID_xxx */
+ u16 type; /* PCI_CAP_xxx */
+ unsigned int addr; /* Position in the config space */
+};
+
+#define PCI_CAP_NORMAL 1 /* Traditional PCI capabilities */
+#define PCI_CAP_EXTENDED 2 /* PCIe extended capabilities */
+
+struct pci_cap *pci_find_cap(struct pci_dev *, unsigned int id, unsigned int type) PCI_ABI;
+struct pci_cap *pci_find_cap_nr(struct pci_dev *, unsigned int id, unsigned int type,
+ unsigned int *cap_number) PCI_ABI;
+
+/*
+ * Filters
+ */
+
+struct pci_filter {
+ int domain, bus, slot, func; /* -1 = ANY */
+ int vendor, device, device_class;
+ int rfu[3];
+};
+
+void pci_filter_init(struct pci_access *, struct pci_filter *) PCI_ABI;
+char *pci_filter_parse_slot(struct pci_filter *, char *) PCI_ABI;
+char *pci_filter_parse_id(struct pci_filter *, char *) PCI_ABI;
+int pci_filter_match(struct pci_filter *, struct pci_dev *) PCI_ABI;
+
+/*
+ * Conversion of PCI ID's to names (according to the pci.ids file)
+ *
+ * Call pci_lookup_name() to identify different types of ID's:
+ *
+ * VENDOR (vendorID) -> vendor
+ * DEVICE (vendorID, deviceID) -> device
+ * VENDOR | DEVICE (vendorID, deviceID) -> combined vendor and device
+ * SUBSYSTEM | VENDOR (subvendorID) -> subsystem vendor
+ * SUBSYSTEM | DEVICE (vendorID, deviceID, subvendorID, subdevID) -> subsystem device
+ * SUBSYSTEM | VENDOR | DEVICE (vendorID, deviceID, subvendorID, subdevID) -> combined subsystem v+d
+ * SUBSYSTEM | ... (-1, -1, subvendorID, subdevID) -> generic subsystem
+ * CLASS (classID) -> class
+ * PROGIF (classID, progif) -> programming interface
+ */
+
+char *pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, ...) PCI_ABI;
+
+int pci_load_name_list(struct pci_access *a) PCI_ABI; /* Called automatically by pci_lookup_*() when needed; returns success */
+void pci_free_name_list(struct pci_access *a) PCI_ABI; /* Called automatically by pci_cleanup() */
+void pci_set_name_list_path(struct pci_access *a, char *name, int to_be_freed) PCI_ABI;
+void pci_id_cache_flush(struct pci_access *a) PCI_ABI;
+
+enum pci_lookup_mode {
+ PCI_LOOKUP_VENDOR = 1, /* Vendor name (args: vendorID) */
+ PCI_LOOKUP_DEVICE = 2, /* Device name (args: vendorID, deviceID) */
+ PCI_LOOKUP_CLASS = 4, /* Device class (args: classID) */
+ PCI_LOOKUP_SUBSYSTEM = 8,
+ PCI_LOOKUP_PROGIF = 16, /* Programming interface (args: classID, prog_if) */
+ PCI_LOOKUP_NUMERIC = 0x10000, /* Want only formatted numbers; default if access->numeric_ids is set */
+ PCI_LOOKUP_NO_NUMBERS = 0x20000, /* Return NULL if not found in the database; default is to print numerically */
+ PCI_LOOKUP_MIXED = 0x40000, /* Include both numbers and names */
+ PCI_LOOKUP_NETWORK = 0x80000, /* Try to resolve unknown ID's by DNS */
+ PCI_LOOKUP_SKIP_LOCAL = 0x100000, /* Do not consult local database */
+ PCI_LOOKUP_CACHE = 0x200000, /* Consult the local cache before using DNS */
+ PCI_LOOKUP_REFRESH_CACHE = 0x400000, /* Forget all previously cached entries, but still allow updating the cache */
+ PCI_LOOKUP_NO_HWDB = 0x800000, /* Do not ask udev's hwdb */
+};
+
+#endif
diff --git a/lib/pread.h b/lib/pread.h
new file mode 100644
index 0000000..3db90e3
--- /dev/null
+++ b/lib/pread.h
@@ -0,0 +1,57 @@
+/*
+ * The PCI Library -- Portable interface to pread() and pwrite()
+ *
+ * Copyright (c) 1997--2003 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+/*
+ * We'd like to use pread/pwrite for configuration space accesses, but
+ * unfortunately it isn't simple at all since all libc's until glibc 2.1
+ * don't define it.
+ */
+
+#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0
+/* glibc 2.1 or newer -> pread/pwrite supported automatically */
+
+#elif defined(i386) && defined(__GLIBC__)
+/* glibc 2.0 on i386 -> call syscalls directly */
+#include <asm/unistd.h>
+#include <syscall-list.h>
+#ifndef SYS_pread
+#define SYS_pread 180
+#endif
+static int pread(unsigned int fd, void *buf, size_t size, loff_t where)
+{ return syscall(SYS_pread, fd, buf, size, where); }
+#ifndef SYS_pwrite
+#define SYS_pwrite 181
+#endif
+static int pwrite(unsigned int fd, void *buf, size_t size, loff_t where)
+{ return syscall(SYS_pwrite, fd, buf, size, where); }
+
+#else
+/* In all other cases we use lseek/read/write instead to be safe */
+#define make_rw_glue(op) \
+ static int do_##op(struct pci_dev *d, int fd, void *buf, size_t size, int where) \
+ { \
+ struct pci_access *a = d->access; \
+ int r; \
+ if (a->fd_pos != where && lseek(fd, where, SEEK_SET) < 0) \
+ return -1; \
+ r = op(fd, buf, size); \
+ if (r < 0) \
+ a->fd_pos = -1; \
+ else \
+ a->fd_pos = where + r; \
+ return r; \
+ }
+make_rw_glue(read)
+make_rw_glue(write)
+#define PCI_HAVE_DO_READ
+#endif
+
+#ifndef PCI_HAVE_DO_READ
+#define do_read(d,f,b,l,p) pread(f,b,l,p)
+#define do_write(d,f,b,l,p) pwrite(f,b,l,p)
+#endif
diff --git a/lib/proc.c b/lib/proc.c
new file mode 100644
index 0000000..cb9d08d
--- /dev/null
+++ b/lib/proc.c
@@ -0,0 +1,212 @@
+/*
+ * The PCI Library -- Configuration Access via /proc/bus/pci
+ *
+ * Copyright (c) 1997--2003 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include "internal.h"
+#include "pread.h"
+
+static void
+proc_config(struct pci_access *a)
+{
+ pci_define_param(a, "proc.path", PCI_PATH_PROC_BUS_PCI, "Path to the procfs bus tree");
+}
+
+static int
+proc_detect(struct pci_access *a)
+{
+ char *name = pci_get_param(a, "proc.path");
+
+ if (access(name, R_OK))
+ {
+ a->warning("Cannot open %s", name);
+ return 0;
+ }
+ a->debug("...using %s", name);
+ return 1;
+}
+
+static void
+proc_init(struct pci_access *a)
+{
+ a->fd = -1;
+}
+
+static void
+proc_cleanup(struct pci_access *a)
+{
+ if (a->fd >= 0)
+ {
+ close(a->fd);
+ a->fd = -1;
+ }
+}
+
+static void
+proc_scan(struct pci_access *a)
+{
+ FILE *f;
+ char buf[512];
+
+ if (snprintf(buf, sizeof(buf), "%s/devices", pci_get_param(a, "proc.path")) == sizeof(buf))
+ a->error("File name too long");
+ f = fopen(buf, "r");
+ if (!f)
+ a->error("Cannot open %s", buf);
+ while (fgets(buf, sizeof(buf)-1, f))
+ {
+ struct pci_dev *d = pci_alloc_dev(a);
+ unsigned int dfn, vend, cnt, known;
+
+#define F " " PCIADDR_T_FMT
+ cnt = sscanf(buf, "%x %x %x" F F F F F F F F F F F F F F,
+ &dfn,
+ &vend,
+ &d->irq,
+ &d->base_addr[0],
+ &d->base_addr[1],
+ &d->base_addr[2],
+ &d->base_addr[3],
+ &d->base_addr[4],
+ &d->base_addr[5],
+ &d->rom_base_addr,
+ &d->size[0],
+ &d->size[1],
+ &d->size[2],
+ &d->size[3],
+ &d->size[4],
+ &d->size[5],
+ &d->rom_size);
+#undef F
+ if (cnt != 9 && cnt != 10 && cnt != 17)
+ a->error("proc: parse error (read only %d items)", cnt);
+ d->bus = dfn >> 8U;
+ d->dev = PCI_SLOT(dfn & 0xff);
+ d->func = PCI_FUNC(dfn & 0xff);
+ d->vendor_id = vend >> 16U;
+ d->device_id = vend & 0xffff;
+ known = 0;
+ if (!a->buscentric)
+ {
+ known |= PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES;
+ if (cnt >= 10)
+ known |= PCI_FILL_ROM_BASE;
+ if (cnt >= 17)
+ known |= PCI_FILL_SIZES;
+ }
+ d->known_fields = known;
+ pci_link_dev(a, d);
+ }
+ fclose(f);
+}
+
+static int
+proc_setup(struct pci_dev *d, int rw)
+{
+ struct pci_access *a = d->access;
+
+ if (a->cached_dev != d || a->fd_rw < rw)
+ {
+ char buf[1024];
+ int e;
+ if (a->fd >= 0)
+ close(a->fd);
+ e = snprintf(buf, sizeof(buf), "%s/%02x/%02x.%d",
+ pci_get_param(a, "proc.path"),
+ d->bus, d->dev, d->func);
+ if (e < 0 || e >= (int) sizeof(buf))
+ a->error("File name too long");
+ a->fd_rw = a->writeable || rw;
+ a->fd = open(buf, a->fd_rw ? O_RDWR : O_RDONLY);
+ if (a->fd < 0)
+ {
+ e = snprintf(buf, sizeof(buf), "%s/%04x:%02x/%02x.%d",
+ pci_get_param(a, "proc.path"),
+ d->domain, d->bus, d->dev, d->func);
+ if (e < 0 || e >= (int) sizeof(buf))
+ a->error("File name too long");
+ a->fd = open(buf, a->fd_rw ? O_RDWR : O_RDONLY);
+ }
+ if (a->fd < 0)
+ a->warning("Cannot open %s", buf);
+ a->cached_dev = d;
+ a->fd_pos = 0;
+ }
+ return a->fd;
+}
+
+static int
+proc_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int fd = proc_setup(d, 0);
+ int res;
+
+ if (fd < 0)
+ return 0;
+ res = do_read(d, fd, buf, len, pos);
+ if (res < 0)
+ {
+ d->access->warning("proc_read: read failed: %s", strerror(errno));
+ return 0;
+ }
+ else if (res != len)
+ return 0;
+ return 1;
+}
+
+static int
+proc_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int fd = proc_setup(d, 1);
+ int res;
+
+ if (fd < 0)
+ return 0;
+ res = do_write(d, fd, buf, len, pos);
+ if (res < 0)
+ {
+ d->access->warning("proc_write: write failed: %s", strerror(errno));
+ return 0;
+ }
+ else if (res != len)
+ {
+ d->access->warning("proc_write: tried to write %d bytes at %d, but only %d succeeded", len, pos, res);
+ return 0;
+ }
+ return 1;
+}
+
+static void
+proc_cleanup_dev(struct pci_dev *d)
+{
+ if (d->access->cached_dev == d)
+ d->access->cached_dev = NULL;
+}
+
+struct pci_methods pm_linux_proc = {
+ "linux-proc",
+ "The proc file system on Linux",
+ proc_config,
+ proc_detect,
+ proc_init,
+ proc_cleanup,
+ proc_scan,
+ pci_generic_fill_info,
+ proc_read,
+ proc_write,
+ NULL, /* read_vpd */
+ NULL, /* init_dev */
+ proc_cleanup_dev
+};
diff --git a/lib/sylixos-device.c b/lib/sylixos-device.c
new file mode 100644
index 0000000..a23438e
--- /dev/null
+++ b/lib/sylixos-device.c
@@ -0,0 +1,158 @@
+/*
+ * The PCI Library -- Direct Configuration access via SylixOS Ports
+ *
+ * Copyright (c) 2018 YuJian.Gong <gongyujian@acoinfo.com>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#define _GNU_SOURCE
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_PCI_DRV
+#include <SylixOS.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "internal.h"
+
+static void
+sylixos_scan(struct pci_access *a)
+{
+ u8 busmap[256];
+ int bus;
+
+ memset(busmap, 0, sizeof(busmap));
+
+ for (bus = 0; bus < PCI_MAX_BUS; bus++)
+ if (!busmap[bus])
+ pci_generic_scan_bus(a, busmap, bus);
+}
+
+static void
+sylixos_config(struct pci_access *a)
+{
+ pci_define_param(a, "sylixos.path", PCI_PATH_SYLIXOS_DEVICE, "Path to the SylixOS PCI device");
+}
+
+static int
+sylixos_detect(struct pci_access *a)
+{
+ char *name = pci_get_param(a, "sylixos.path");
+
+ if (access(name, R_OK))
+ {
+ a->warning("Cannot open %s", name);
+ return 0;
+ }
+
+ a->debug("...using %s", name);
+ return 1;
+}
+
+static void
+sylixos_init(struct pci_access *a UNUSED)
+{
+}
+
+static void
+sylixos_cleanup(struct pci_access *a UNUSED)
+{
+}
+
+static int
+sylixos_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int ret = -1;
+ u8 data_byte = -1;
+ u16 data_word = -1;
+ u32 data_dword = -1;
+
+ if (!(len == 1 || len == 2 || len == 4))
+ return pci_generic_block_read(d, pos, buf, len);
+
+ if (pos >= 256)
+ return 0;
+
+ switch (len)
+ {
+ case 1:
+ ret = pciConfigInByte(d->bus, d->dev, d->func, pos, &data_byte);
+ if (ret != ERROR_NONE)
+ return 0;
+ buf[0] = (u8)data_byte;
+ break;
+
+ case 2:
+ ret = pciConfigInWord(d->bus, d->dev, d->func, pos, &data_word);
+ if (ret != ERROR_NONE)
+ return 0;
+ ((u16 *) buf)[0] = cpu_to_le16(data_word);
+ break;
+
+ case 4:
+ ret = pciConfigInDword(d->bus, d->dev, d->func, pos, &data_dword);
+ if (ret != ERROR_NONE)
+ return 0;
+ ((u32 *) buf)[0] = cpu_to_le32(data_dword);
+ break;
+ }
+
+ return 1;
+}
+
+static int
+sylixos_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int ret = PX_ERROR;
+ u8 data_byte;
+ u16 data_word;
+ u32 data_dword;
+
+ if (!(len == 1 || len == 2 || len == 4))
+ return pci_generic_block_write(d, pos, buf, len);
+
+ if (pos >= 256)
+ return 0;
+
+ switch (len)
+ {
+ case 1:
+ data_byte = buf[0];
+ ret = pciConfigOutByte(d->bus, d->dev, d->func, pos, data_byte);
+ if (ret != ERROR_NONE)
+ return 0;
+ break;
+
+ case 2:
+ data_word = le16_to_cpu(((u16 *) buf)[0]);
+ ret = pciConfigOutWord(d->bus, d->dev, d->func, pos, data_word);
+ if (ret != ERROR_NONE)
+ return 0;
+ break;
+
+ case 4:
+ data_dword = le32_to_cpu(((u32 *) buf)[0]);
+ ret = pciConfigOutDword(d->bus, d->dev, d->func, pos, data_dword);
+ if (ret != ERROR_NONE)
+ return 0;
+ break;
+ }
+
+ return 1;
+}
+
+struct pci_methods pm_sylixos_device = {
+ "sylixos-device",
+ "SylixOS /proc/pci device",
+ sylixos_config,
+ sylixos_detect,
+ sylixos_init,
+ sylixos_cleanup,
+ sylixos_scan,
+ pci_generic_fill_info,
+ sylixos_read,
+ sylixos_write,
+ NULL, // no read_vpd
+ NULL, // no init_dev
+ NULL, // no cleanup_dev
+};
diff --git a/lib/sysdep.h b/lib/sysdep.h
new file mode 100644
index 0000000..1a5cb16
--- /dev/null
+++ b/lib/sysdep.h
@@ -0,0 +1,112 @@
+/*
+ * The PCI Library -- System-Dependent Stuff
+ *
+ * Copyright (c) 1997--2020 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#define NONRET __attribute__((noreturn))
+#define FORMAT_CHECK(x,y,z) __attribute__((format(x,y,z)))
+#else
+#define UNUSED
+#define NONRET
+#define FORMAT_CHECK(x,y,z)
+#define inline
+#endif
+
+typedef u8 byte;
+typedef u16 word;
+
+#ifdef PCI_OS_WINDOWS
+#define strcasecmp strcmpi
+#endif
+
+#ifdef PCI_HAVE_LINUX_BYTEORDER_H
+
+#include <asm/byteorder.h>
+#define cpu_to_le16 __cpu_to_le16
+#define cpu_to_le32 __cpu_to_le32
+#define le16_to_cpu __le16_to_cpu
+#define le32_to_cpu __le32_to_cpu
+
+#else
+
+#ifdef PCI_OS_LINUX
+#include <endian.h>
+#define BYTE_ORDER __BYTE_ORDER
+#define BIG_ENDIAN __BIG_ENDIAN
+#endif
+
+#ifdef PCI_OS_SUNOS
+#include <sys/byteorder.h>
+#if defined(__i386) && defined(LITTLE_ENDIAN)
+# define BYTE_ORDER LITTLE_ENDIAN
+#elif defined(__sparc) && defined(BIG_ENDIAN)
+# define BYTE_ORDER BIG_ENDIAN
+#else
+#define BIG_ENDIAN 4321
+#endif
+#ifndef BYTE_ORDER
+#ifdef _LITTLE_ENDIAN
+#define BYTE_ORDER 1234
+#else
+#define BYTE_ORDER 4321
+#endif
+#endif /* BYTE_ORDER */
+#endif /* PCI_OS_SUNOS */
+
+#ifdef PCI_OS_WINDOWS
+#ifdef __MINGW32__
+ #include <sys/param.h>
+#else
+ #include <io.h>
+ #define BIG_ENDIAN 4321
+ #define LITTLE_ENDIAN 1234
+ #define BYTE_ORDER LITTLE_ENDIAN
+ #define snprintf _snprintf
+#endif
+#endif
+
+#ifdef PCI_OS_SYLIXOS
+#include <endian.h>
+#endif
+
+#ifdef PCI_OS_DJGPP
+ #define BIG_ENDIAN 4321
+ #define LITTLE_ENDIAN 1234
+ #define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+#if !defined(BYTE_ORDER)
+#error "BYTE_ORDER not defined for your platform"
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define cpu_to_le16 swab16
+#define cpu_to_le32 swab32
+#define le16_to_cpu swab16
+#define le32_to_cpu swab32
+
+static inline word swab16(word w)
+{
+ return (w << 8) | ((w >> 8) & 0xff);
+}
+
+static inline u32 swab32(u32 w)
+{
+ return ((w & 0xff000000) >> 24) |
+ ((w & 0x00ff0000) >> 8) |
+ ((w & 0x0000ff00) << 8) |
+ ((w & 0x000000ff) << 24);
+}
+#else
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define le16_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#endif
+
+#endif
diff --git a/lib/sysfs.c b/lib/sysfs.c
new file mode 100644
index 0000000..fb64241
--- /dev/null
+++ b/lib/sysfs.c
@@ -0,0 +1,517 @@
+/*
+ * The PCI Library -- Configuration Access via /sys/bus/pci
+ *
+ * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
+ * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include "internal.h"
+#include "pread.h"
+
+static void
+sysfs_config(struct pci_access *a)
+{
+ pci_define_param(a, "sysfs.path", PCI_PATH_SYS_BUS_PCI, "Path to the sysfs device tree");
+}
+
+static inline char *
+sysfs_name(struct pci_access *a)
+{
+ return pci_get_param(a, "sysfs.path");
+}
+
+static int
+sysfs_detect(struct pci_access *a)
+{
+ if (access(sysfs_name(a), R_OK))
+ {
+ a->debug("...cannot open %s", sysfs_name(a));
+ return 0;
+ }
+ a->debug("...using %s", sysfs_name(a));
+ return 1;
+}
+
+static void
+sysfs_init(struct pci_access *a)
+{
+ a->fd = -1;
+ a->fd_vpd = -1;
+}
+
+static void
+sysfs_flush_cache(struct pci_access *a)
+{
+ if (a->fd >= 0)
+ {
+ close(a->fd);
+ a->fd = -1;
+ }
+ if (a->fd_vpd >= 0)
+ {
+ close(a->fd_vpd);
+ a->fd_vpd = -1;
+ }
+ a->cached_dev = NULL;
+}
+
+static void
+sysfs_cleanup(struct pci_access *a)
+{
+ sysfs_flush_cache(a);
+}
+
+#define OBJNAMELEN 1024
+static void
+sysfs_obj_name(struct pci_dev *d, char *object, char *buf)
+{
+ int n = snprintf(buf, OBJNAMELEN, "%s/devices/%04x:%02x:%02x.%d/%s",
+ sysfs_name(d->access), d->domain, d->bus, d->dev, d->func, object);
+ if (n < 0 || n >= OBJNAMELEN)
+ d->access->error("File name too long");
+}
+
+#define OBJBUFSIZE 1024
+
+static int
+sysfs_get_string(struct pci_dev *d, char *object, char *buf, int mandatory)
+{
+ struct pci_access *a = d->access;
+ int fd, n;
+ char namebuf[OBJNAMELEN];
+ void (*warn)(char *msg, ...) = (mandatory ? a->error : a->warning);
+
+ sysfs_obj_name(d, object, namebuf);
+ fd = open(namebuf, O_RDONLY);
+ if (fd < 0)
+ {
+ if (mandatory || errno != ENOENT)
+ warn("Cannot open %s: %s", namebuf, strerror(errno));
+ return 0;
+ }
+ n = read(fd, buf, OBJBUFSIZE);
+ close(fd);
+ if (n < 0)
+ {
+ warn("Error reading %s: %s", namebuf, strerror(errno));
+ return 0;
+ }
+ if (n >= OBJBUFSIZE)
+ {
+ warn("Value in %s too long", namebuf);
+ return 0;
+ }
+ buf[n] = 0;
+ return 1;
+}
+
+static char *
+sysfs_deref_link(struct pci_dev *d, char *link_name)
+{
+ char path[2*OBJNAMELEN], rel_path[OBJNAMELEN];
+
+ sysfs_obj_name(d, link_name, path);
+ memset(rel_path, 0, sizeof(rel_path));
+
+ if (readlink(path, rel_path, sizeof(rel_path)) < 0)
+ return NULL;
+
+ sysfs_obj_name(d, "", path);
+ strcat(path, rel_path);
+
+ // Returns a pointer to malloc'ed memory
+ return realpath(path, NULL);
+}
+
+static int
+sysfs_get_value(struct pci_dev *d, char *object, int mandatory)
+{
+ char buf[OBJBUFSIZE];
+
+ if (sysfs_get_string(d, object, buf, mandatory))
+ return strtol(buf, NULL, 0);
+ else
+ return -1;
+}
+
+static void
+sysfs_get_resources(struct pci_dev *d)
+{
+ struct pci_access *a = d->access;
+ char namebuf[OBJNAMELEN], buf[256];
+ FILE *file;
+ int i;
+
+ sysfs_obj_name(d, "resource", namebuf);
+ file = fopen(namebuf, "r");
+ if (!file)
+ a->error("Cannot open %s: %s", namebuf, strerror(errno));
+ for (i = 0; i < 7; i++)
+ {
+ unsigned long long start, end, size, flags;
+ if (!fgets(buf, sizeof(buf), file))
+ break;
+ if (sscanf(buf, "%llx %llx %llx", &start, &end, &flags) != 3)
+ a->error("Syntax error in %s", namebuf);
+ if (end > start)
+ size = end - start + 1;
+ else
+ size = 0;
+ if (i < 6)
+ {
+ d->flags[i] = flags;
+ flags &= PCI_ADDR_FLAG_MASK;
+ d->base_addr[i] = start | flags;
+ d->size[i] = size;
+ }
+ else
+ {
+ d->rom_flags = flags;
+ flags &= PCI_ADDR_FLAG_MASK;
+ d->rom_base_addr = start | flags;
+ d->rom_size = size;
+ }
+ }
+ fclose(file);
+}
+
+static void sysfs_scan(struct pci_access *a)
+{
+ char dirname[1024];
+ DIR *dir;
+ struct dirent *entry;
+ int n;
+
+ n = snprintf(dirname, sizeof(dirname), "%s/devices", sysfs_name(a));
+ if (n < 0 || n >= (int) sizeof(dirname))
+ a->error("Directory name too long");
+ dir = opendir(dirname);
+ if (!dir)
+ a->error("Cannot open %s", dirname);
+ while ((entry = readdir(dir)))
+ {
+ struct pci_dev *d;
+ unsigned int dom, bus, dev, func;
+
+ /* ".", ".." or a special non-device perhaps */
+ if (entry->d_name[0] == '.')
+ continue;
+
+ d = pci_alloc_dev(a);
+ if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4)
+ a->error("sysfs_scan: Couldn't parse entry name %s", entry->d_name);
+
+ /* Ensure kernel provided domain that fits in a signed integer */
+ if (dom > 0x7fffffff)
+ a->error("sysfs_scan: Invalid domain %x", dom);
+
+ d->domain = dom;
+ d->bus = bus;
+ d->dev = dev;
+ d->func = func;
+ pci_link_dev(a, d);
+ }
+ closedir(dir);
+}
+
+static void
+sysfs_fill_slots(struct pci_access *a)
+{
+ char dirname[1024];
+ DIR *dir;
+ struct dirent *entry;
+ int n;
+
+ n = snprintf(dirname, sizeof(dirname), "%s/slots", sysfs_name(a));
+ if (n < 0 || n >= (int) sizeof(dirname))
+ a->error("Directory name too long");
+ dir = opendir(dirname);
+ if (!dir)
+ return;
+
+ while (entry = readdir(dir))
+ {
+ char namebuf[OBJNAMELEN], buf[16];
+ FILE *file;
+ unsigned int dom, bus, dev;
+ int res = 0;
+ struct pci_dev *d;
+
+ /* ".", ".." or a special non-device perhaps */
+ if (entry->d_name[0] == '.')
+ continue;
+
+ n = snprintf(namebuf, OBJNAMELEN, "%s/%s/%s", dirname, entry->d_name, "address");
+ if (n < 0 || n >= OBJNAMELEN)
+ a->error("File name too long");
+ file = fopen(namebuf, "r");
+ /*
+ * Old versions of Linux had a fakephp which didn't have an 'address'
+ * file. There's no useful information to be gleaned from these
+ * devices, pretend they're not there.
+ */
+ if (!file)
+ continue;
+
+ if (!fgets(buf, sizeof(buf), file) || (res = sscanf(buf, "%x:%x:%x", &dom, &bus, &dev)) < 3)
+ {
+ /*
+ * In some cases, the slot is not tied to a specific device before
+ * a card gets inserted. This happens for example on IBM pSeries
+ * and we need not warn about it.
+ */
+ if (res != 2)
+ a->warning("sysfs_fill_slots: Couldn't parse entry address %s", buf);
+ }
+ else
+ {
+ for (d = a->devices; d; d = d->next)
+ if (dom == (unsigned)d->domain && bus == d->bus && dev == d->dev && !d->phy_slot)
+ d->phy_slot = pci_set_property(d, PCI_FILL_PHYS_SLOT, entry->d_name);
+ }
+ fclose(file);
+ }
+ closedir(dir);
+}
+
+static unsigned int
+sysfs_fill_info(struct pci_dev *d, unsigned int flags)
+{
+ unsigned int done = 0;
+
+ if (!d->access->buscentric)
+ {
+ /*
+ * These fields can be read from the config registers, but we want to show
+ * the kernel's view, which has regions and IRQs remapped and other fields
+ * (most importantly classes) possibly fixed if the device is known broken.
+ */
+ if (flags & PCI_FILL_IDENT)
+ {
+ d->vendor_id = sysfs_get_value(d, "vendor", 1);
+ d->device_id = sysfs_get_value(d, "device", 1);
+ done |= PCI_FILL_IDENT;
+ }
+ if (flags & PCI_FILL_CLASS)
+ {
+ d->device_class = sysfs_get_value(d, "class", 1) >> 8;
+ done |= PCI_FILL_CLASS;
+ }
+ if (flags & PCI_FILL_IRQ)
+ {
+ d->irq = sysfs_get_value(d, "irq", 1);
+ done |= PCI_FILL_IRQ;
+ }
+ if (flags & (PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS))
+ {
+ sysfs_get_resources(d);
+ done |= PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS;
+ }
+ }
+
+ if (flags & PCI_FILL_PHYS_SLOT)
+ {
+ struct pci_dev *pd;
+ sysfs_fill_slots(d->access);
+ for (pd = d->access->devices; pd; pd = pd->next)
+ pd->known_fields |= PCI_FILL_PHYS_SLOT;
+ done |= PCI_FILL_PHYS_SLOT;
+ }
+
+ if (flags & PCI_FILL_MODULE_ALIAS)
+ {
+ char buf[OBJBUFSIZE];
+ if (sysfs_get_string(d, "modalias", buf, 0))
+ d->module_alias = pci_set_property(d, PCI_FILL_MODULE_ALIAS, buf);
+ done |= PCI_FILL_MODULE_ALIAS;
+ }
+
+ if (flags & PCI_FILL_LABEL)
+ {
+ char buf[OBJBUFSIZE];
+ if (sysfs_get_string(d, "label", buf, 0))
+ d->label = pci_set_property(d, PCI_FILL_LABEL, buf);
+ done |= PCI_FILL_LABEL;
+ }
+
+ if (flags & PCI_FILL_NUMA_NODE)
+ {
+ d->numa_node = sysfs_get_value(d, "numa_node", 0);
+ done |= PCI_FILL_NUMA_NODE;
+ }
+
+ if (flags & PCI_FILL_IOMMU_GROUP)
+ {
+ char *group_link = sysfs_deref_link(d, "iommu_group");
+ if (group_link)
+ {
+ pci_set_property(d, PCI_FILL_IOMMU_GROUP, basename(group_link));
+ free(group_link);
+ }
+ done |= PCI_FILL_IOMMU_GROUP;
+ }
+
+ if (flags & PCI_FILL_DT_NODE)
+ {
+ char *node = sysfs_deref_link(d, "of_node");
+ if (node)
+ {
+ pci_set_property(d, PCI_FILL_DT_NODE, node);
+ free(node);
+ }
+ done |= PCI_FILL_DT_NODE;
+ }
+
+ return done | pci_generic_fill_info(d, flags & ~done);
+}
+
+/* Intent of the sysfs_setup() caller */
+enum
+ {
+ SETUP_READ_CONFIG = 0,
+ SETUP_WRITE_CONFIG = 1,
+ SETUP_READ_VPD = 2
+ };
+
+static int
+sysfs_setup(struct pci_dev *d, int intent)
+{
+ struct pci_access *a = d->access;
+ char namebuf[OBJNAMELEN];
+
+ if (a->cached_dev != d || (intent == SETUP_WRITE_CONFIG && !a->fd_rw))
+ {
+ sysfs_flush_cache(a);
+ a->cached_dev = d;
+ }
+
+ if (intent == SETUP_READ_VPD)
+ {
+ if (a->fd_vpd < 0)
+ {
+ sysfs_obj_name(d, "vpd", namebuf);
+ a->fd_vpd = open(namebuf, O_RDONLY);
+ /* No warning on error; vpd may be absent or accessible only to root */
+ }
+ return a->fd_vpd;
+ }
+
+ if (a->fd < 0)
+ {
+ sysfs_obj_name(d, "config", namebuf);
+ a->fd_rw = a->writeable || intent == SETUP_WRITE_CONFIG;
+ a->fd = open(namebuf, a->fd_rw ? O_RDWR : O_RDONLY);
+ if (a->fd < 0)
+ a->warning("Cannot open %s", namebuf);
+ a->fd_pos = 0;
+ }
+ return a->fd;
+}
+
+static int sysfs_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int fd = sysfs_setup(d, SETUP_READ_CONFIG);
+ int res;
+
+ if (fd < 0)
+ return 0;
+ res = do_read(d, fd, buf, len, pos);
+ if (res < 0)
+ {
+ d->access->warning("sysfs_read: read failed: %s", strerror(errno));
+ return 0;
+ }
+ else if (res != len)
+ return 0;
+ return 1;
+}
+
+static int sysfs_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int fd = sysfs_setup(d, SETUP_WRITE_CONFIG);
+ int res;
+
+ if (fd < 0)
+ return 0;
+ res = do_write(d, fd, buf, len, pos);
+ if (res < 0)
+ {
+ d->access->warning("sysfs_write: write failed: %s", strerror(errno));
+ return 0;
+ }
+ else if (res != len)
+ {
+ d->access->warning("sysfs_write: tried to write %d bytes at %d, but only %d succeeded", len, pos, res);
+ return 0;
+ }
+ return 1;
+}
+
+#ifdef PCI_HAVE_DO_READ
+
+/* pread() is not available and do_read() only works for a single fd, so we
+ * cannot implement read_vpd properly. */
+static int sysfs_read_vpd(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ return 0;
+}
+
+#else /* !PCI_HAVE_DO_READ */
+
+static int sysfs_read_vpd(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ int fd = sysfs_setup(d, SETUP_READ_VPD);
+ int res;
+
+ if (fd < 0)
+ return 0;
+ res = pread(fd, buf, len, pos);
+ if (res < 0)
+ {
+ d->access->warning("sysfs_read_vpd: read failed: %s", strerror(errno));
+ return 0;
+ }
+ else if (res != len)
+ return 0;
+ return 1;
+}
+
+#endif /* PCI_HAVE_DO_READ */
+
+static void sysfs_cleanup_dev(struct pci_dev *d)
+{
+ struct pci_access *a = d->access;
+
+ if (a->cached_dev == d)
+ sysfs_flush_cache(a);
+}
+
+struct pci_methods pm_linux_sysfs = {
+ "linux-sysfs",
+ "The sys filesystem on Linux",
+ sysfs_config,
+ sysfs_detect,
+ sysfs_init,
+ sysfs_cleanup,
+ sysfs_scan,
+ sysfs_fill_info,
+ sysfs_read,
+ sysfs_write,
+ sysfs_read_vpd,
+ NULL, /* init_dev */
+ sysfs_cleanup_dev
+};
diff --git a/lib/types.h b/lib/types.h
new file mode 100644
index 0000000..7011252
--- /dev/null
+++ b/lib/types.h
@@ -0,0 +1,75 @@
+/*
+ * The PCI Library -- Types and Format Strings
+ *
+ * Copyright (c) 1997--2017 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <sys/types.h>
+
+#ifndef PCI_HAVE_Uxx_TYPES
+
+#ifdef PCI_OS_WINDOWS
+/* On Windows compilers, use <windef.h> */
+#include <windef.h>
+typedef BYTE u8;
+typedef WORD u16;
+typedef DWORD u32;
+typedef unsigned __int64 u64;
+#define PCI_U64_FMT_X "I64x"
+
+#elif defined(PCI_HAVE_STDINT_H) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
+/* Use standard types in C99 and newer */
+#include <stdint.h>
+#include <inttypes.h>
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+#define PCI_U64_FMT_X PRIx64
+
+#else
+/* Hope for POSIX types from <sys/types.h> */
+typedef u_int8_t u8;
+typedef u_int16_t u16;
+typedef u_int32_t u32;
+
+/* u64 will be unsigned (long) long */
+#include <limits.h>
+#if ULONG_MAX > 0xffffffff
+typedef unsigned long u64;
+#define PCI_U64_FMT_X "lx"
+#else
+typedef unsigned long long u64;
+#define PCI_U64_FMT_X "llx"
+#endif
+
+#endif
+
+#endif /* PCI_HAVE_Uxx_TYPES */
+
+#ifdef PCI_HAVE_64BIT_ADDRESS
+typedef u64 pciaddr_t;
+#define PCIADDR_T_FMT "%08" PCI_U64_FMT_X
+#define PCIADDR_PORT_FMT "%04" PCI_U64_FMT_X
+#else
+typedef u32 pciaddr_t;
+#define PCIADDR_T_FMT "%08x"
+#define PCIADDR_PORT_FMT "%04x"
+#endif
+
+#ifdef PCI_ARCH_SPARC64
+/* On sparc64 Linux the kernel reports remapped port addresses and IRQ numbers */
+#undef PCIADDR_PORT_FMT
+#define PCIADDR_PORT_FMT PCIADDR_T_FMT
+#define PCIIRQ_FMT "%08x"
+#else
+#define PCIIRQ_FMT "%d"
+#endif
+
+#if defined(__GNUC__) && __GNUC__ > 2
+#define PCI_PRINTF(x,y) __attribute__((format(printf, x, y)))
+#else
+#define PCI_PRINTF(x,y)
+#endif
diff --git a/ls-caps-vendor.c b/ls-caps-vendor.c
new file mode 100644
index 0000000..dc24f90
--- /dev/null
+++ b/ls-caps-vendor.c
@@ -0,0 +1,82 @@
+/*
+ * The PCI Utilities -- Show Vendor-specific Capabilities
+ *
+ * Copyright (c) 2014 Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lspci.h"
+
+static int
+show_vendor_caps_virtio(struct device *d, int where, int cap)
+{
+ int length = BITS(cap, 0, 8);
+ int type = BITS(cap, 8, 8);
+ char *tname;
+
+ if (length < 16)
+ return 0;
+ if (!config_fetch(d, where, length))
+ return 0;
+
+ switch (type)
+ {
+ case 1:
+ tname = "CommonCfg";
+ break;
+ case 2:
+ tname = "Notify";
+ break;
+ case 3:
+ tname = "ISR";
+ break;
+ case 4:
+ tname = "DeviceCfg";
+ break;
+ default:
+ tname = "<unknown>";
+ break;
+ }
+
+ printf("VirtIO: %s\n", tname);
+
+ if (verbose < 2)
+ return 1;
+
+ printf("\t\tBAR=%d offset=%08x size=%08x",
+ get_conf_byte(d, where + 4),
+ get_conf_long(d, where + 8),
+ get_conf_long(d, where + 12));
+
+ if (type == 2 && length >= 20)
+ printf(" multiplier=%08x", get_conf_long(d, where+16));
+
+ printf("\n");
+ return 1;
+}
+
+static int
+do_show_vendor_caps(struct device *d, int where, int cap)
+{
+ switch (get_conf_word(d, PCI_VENDOR_ID))
+ {
+ case 0x1af4: /* Red Hat */
+ if (get_conf_word(d, PCI_DEVICE_ID) >= 0x1000 &&
+ get_conf_word(d, PCI_DEVICE_ID) <= 0x107f)
+ return show_vendor_caps_virtio(d, where, cap);
+ break;
+ }
+ return 0;
+}
+
+void
+show_vendor_caps(struct device *d, int where, int cap)
+{
+ printf("Vendor Specific Information: ");
+ if (!do_show_vendor_caps(d, where, cap))
+ printf("Len=%02x <?>\n", BITS(cap, 0, 8));
+}
diff --git a/ls-caps.c b/ls-caps.c
new file mode 100644
index 0000000..a09b0cf
--- /dev/null
+++ b/ls-caps.c
@@ -0,0 +1,1778 @@
+/*
+ * The PCI Utilities -- Show Capabilities
+ *
+ * Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lspci.h"
+
+static void
+cap_pm(struct device *d, int where, int cap)
+{
+ int t, b;
+ static int pm_aux_current[8] = { 0, 55, 100, 160, 220, 270, 320, 375 };
+
+ printf("Power Management version %d\n", cap & PCI_PM_CAP_VER_MASK);
+ if (verbose < 2)
+ return;
+ printf("\t\tFlags: PMEClk%c DSI%c D1%c D2%c AuxCurrent=%dmA PME(D0%c,D1%c,D2%c,D3hot%c,D3cold%c)\n",
+ FLAG(cap, PCI_PM_CAP_PME_CLOCK),
+ FLAG(cap, PCI_PM_CAP_DSI),
+ FLAG(cap, PCI_PM_CAP_D1),
+ FLAG(cap, PCI_PM_CAP_D2),
+ pm_aux_current[(cap & PCI_PM_CAP_AUX_C_MASK) >> 6],
+ FLAG(cap, PCI_PM_CAP_PME_D0),
+ FLAG(cap, PCI_PM_CAP_PME_D1),
+ FLAG(cap, PCI_PM_CAP_PME_D2),
+ FLAG(cap, PCI_PM_CAP_PME_D3_HOT),
+ FLAG(cap, PCI_PM_CAP_PME_D3_COLD));
+ if (!config_fetch(d, where + PCI_PM_CTRL, PCI_PM_SIZEOF - PCI_PM_CTRL))
+ return;
+ t = get_conf_word(d, where + PCI_PM_CTRL);
+ printf("\t\tStatus: D%d NoSoftRst%c PME-Enable%c DSel=%d DScale=%d PME%c\n",
+ t & PCI_PM_CTRL_STATE_MASK,
+ FLAG(t, PCI_PM_CTRL_NO_SOFT_RST),
+ FLAG(t, PCI_PM_CTRL_PME_ENABLE),
+ (t & PCI_PM_CTRL_DATA_SEL_MASK) >> 9,
+ (t & PCI_PM_CTRL_DATA_SCALE_MASK) >> 13,
+ FLAG(t, PCI_PM_CTRL_PME_STATUS));
+ b = get_conf_byte(d, where + PCI_PM_PPB_EXTENSIONS);
+ if (b)
+ printf("\t\tBridge: PM%c B3%c\n",
+ FLAG(t, PCI_PM_BPCC_ENABLE),
+ FLAG(~t, PCI_PM_PPB_B2_B3));
+}
+
+static void
+format_agp_rate(int rate, char *buf, int agp3)
+{
+ char *c = buf;
+ int i;
+
+ for (i=0; i<=2; i++)
+ if (rate & (1 << i))
+ {
+ if (c != buf)
+ *c++ = ',';
+ c += sprintf(c, "x%d", 1 << (i + 2*agp3));
+ }
+ if (c != buf)
+ *c = 0;
+ else
+ strcpy(buf, "<none>");
+}
+
+static void
+cap_agp(struct device *d, int where, int cap)
+{
+ u32 t;
+ char rate[16];
+ int ver, rev;
+ int agp3 = 0;
+
+ ver = (cap >> 4) & 0x0f;
+ rev = cap & 0x0f;
+ printf("AGP version %x.%x\n", ver, rev);
+ if (verbose < 2)
+ return;
+ if (!config_fetch(d, where + PCI_AGP_STATUS, PCI_AGP_SIZEOF - PCI_AGP_STATUS))
+ return;
+ t = get_conf_long(d, where + PCI_AGP_STATUS);
+ if (ver >= 3 && (t & PCI_AGP_STATUS_AGP3))
+ agp3 = 1;
+ format_agp_rate(t & 7, rate, agp3);
+ printf("\t\tStatus: RQ=%d Iso%c ArqSz=%d Cal=%d SBA%c ITACoh%c GART64%c HTrans%c 64bit%c FW%c AGP3%c Rate=%s\n",
+ ((t & PCI_AGP_STATUS_RQ_MASK) >> 24U) + 1,
+ FLAG(t, PCI_AGP_STATUS_ISOCH),
+ ((t & PCI_AGP_STATUS_ARQSZ_MASK) >> 13),
+ ((t & PCI_AGP_STATUS_CAL_MASK) >> 10),
+ FLAG(t, PCI_AGP_STATUS_SBA),
+ FLAG(t, PCI_AGP_STATUS_ITA_COH),
+ FLAG(t, PCI_AGP_STATUS_GART64),
+ FLAG(t, PCI_AGP_STATUS_HTRANS),
+ FLAG(t, PCI_AGP_STATUS_64BIT),
+ FLAG(t, PCI_AGP_STATUS_FW),
+ FLAG(t, PCI_AGP_STATUS_AGP3),
+ rate);
+ t = get_conf_long(d, where + PCI_AGP_COMMAND);
+ format_agp_rate(t & 7, rate, agp3);
+ printf("\t\tCommand: RQ=%d ArqSz=%d Cal=%d SBA%c AGP%c GART64%c 64bit%c FW%c Rate=%s\n",
+ ((t & PCI_AGP_COMMAND_RQ_MASK) >> 24U) + 1,
+ ((t & PCI_AGP_COMMAND_ARQSZ_MASK) >> 13),
+ ((t & PCI_AGP_COMMAND_CAL_MASK) >> 10),
+ FLAG(t, PCI_AGP_COMMAND_SBA),
+ FLAG(t, PCI_AGP_COMMAND_AGP),
+ FLAG(t, PCI_AGP_COMMAND_GART64),
+ FLAG(t, PCI_AGP_COMMAND_64BIT),
+ FLAG(t, PCI_AGP_COMMAND_FW),
+ rate);
+}
+
+static void
+cap_pcix_nobridge(struct device *d, int where)
+{
+ u16 command;
+ u32 status;
+ static const byte max_outstanding[8] = { 1, 2, 3, 4, 8, 12, 16, 32 };
+
+ printf("PCI-X non-bridge device\n");
+
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_PCIX_STATUS, 4))
+ return;
+
+ command = get_conf_word(d, where + PCI_PCIX_COMMAND);
+ status = get_conf_long(d, where + PCI_PCIX_STATUS);
+ printf("\t\tCommand: DPERE%c ERO%c RBC=%d OST=%d\n",
+ FLAG(command, PCI_PCIX_COMMAND_DPERE),
+ FLAG(command, PCI_PCIX_COMMAND_ERO),
+ 1 << (9 + ((command & PCI_PCIX_COMMAND_MAX_MEM_READ_BYTE_COUNT) >> 2U)),
+ max_outstanding[(command & PCI_PCIX_COMMAND_MAX_OUTSTANDING_SPLIT_TRANS) >> 4U]);
+ printf("\t\tStatus: Dev=%02x:%02x.%d 64bit%c 133MHz%c SCD%c USC%c DC=%s DMMRBC=%u DMOST=%u DMCRS=%u RSCEM%c 266MHz%c 533MHz%c\n",
+ (status & PCI_PCIX_STATUS_BUS) >> 8,
+ (status & PCI_PCIX_STATUS_DEVICE) >> 3,
+ (status & PCI_PCIX_STATUS_FUNCTION),
+ FLAG(status, PCI_PCIX_STATUS_64BIT),
+ FLAG(status, PCI_PCIX_STATUS_133MHZ),
+ FLAG(status, PCI_PCIX_STATUS_SC_DISCARDED),
+ FLAG(status, PCI_PCIX_STATUS_UNEXPECTED_SC),
+ ((status & PCI_PCIX_STATUS_DEVICE_COMPLEXITY) ? "bridge" : "simple"),
+ 1 << (9 + ((status & PCI_PCIX_STATUS_DESIGNED_MAX_MEM_READ_BYTE_COUNT) >> 21)),
+ max_outstanding[(status & PCI_PCIX_STATUS_DESIGNED_MAX_OUTSTANDING_SPLIT_TRANS) >> 23],
+ 1 << (3 + ((status & PCI_PCIX_STATUS_DESIGNED_MAX_CUMULATIVE_READ_SIZE) >> 26)),
+ FLAG(status, PCI_PCIX_STATUS_RCVD_SC_ERR_MESS),
+ FLAG(status, PCI_PCIX_STATUS_266MHZ),
+ FLAG(status, PCI_PCIX_STATUS_533MHZ));
+}
+
+static void
+cap_pcix_bridge(struct device *d, int where)
+{
+ static const char * const sec_clock_freq[8] = { "conv", "66MHz", "100MHz", "133MHz", "?4", "?5", "?6", "?7" };
+ u16 secstatus;
+ u32 status, upstcr, downstcr;
+
+ printf("PCI-X bridge device\n");
+
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_PCIX_BRIDGE_STATUS, 12))
+ return;
+
+ secstatus = get_conf_word(d, where + PCI_PCIX_BRIDGE_SEC_STATUS);
+ printf("\t\tSecondary Status: 64bit%c 133MHz%c SCD%c USC%c SCO%c SRD%c Freq=%s\n",
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_64BIT),
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_133MHZ),
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_SC_DISCARDED),
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_UNEXPECTED_SC),
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_SC_OVERRUN),
+ FLAG(secstatus, PCI_PCIX_BRIDGE_SEC_STATUS_SPLIT_REQUEST_DELAYED),
+ sec_clock_freq[(secstatus & PCI_PCIX_BRIDGE_SEC_STATUS_CLOCK_FREQ) >> 6]);
+ status = get_conf_long(d, where + PCI_PCIX_BRIDGE_STATUS);
+ printf("\t\tStatus: Dev=%02x:%02x.%d 64bit%c 133MHz%c SCD%c USC%c SCO%c SRD%c\n",
+ (status & PCI_PCIX_BRIDGE_STATUS_BUS) >> 8,
+ (status & PCI_PCIX_BRIDGE_STATUS_DEVICE) >> 3,
+ (status & PCI_PCIX_BRIDGE_STATUS_FUNCTION),
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_64BIT),
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_133MHZ),
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_SC_DISCARDED),
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_UNEXPECTED_SC),
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_SC_OVERRUN),
+ FLAG(status, PCI_PCIX_BRIDGE_STATUS_SPLIT_REQUEST_DELAYED));
+ upstcr = get_conf_long(d, where + PCI_PCIX_BRIDGE_UPSTREAM_SPLIT_TRANS_CTRL);
+ printf("\t\tUpstream: Capacity=%u CommitmentLimit=%u\n",
+ (upstcr & PCI_PCIX_BRIDGE_STR_CAPACITY),
+ (upstcr >> 16) & 0xffff);
+ downstcr = get_conf_long(d, where + PCI_PCIX_BRIDGE_DOWNSTREAM_SPLIT_TRANS_CTRL);
+ printf("\t\tDownstream: Capacity=%u CommitmentLimit=%u\n",
+ (downstcr & PCI_PCIX_BRIDGE_STR_CAPACITY),
+ (downstcr >> 16) & 0xffff);
+}
+
+static void
+cap_pcix(struct device *d, int where)
+{
+ switch (get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ cap_pcix_nobridge(d, where);
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ cap_pcix_bridge(d, where);
+ break;
+ }
+}
+
+static inline char *
+ht_link_width(unsigned width)
+{
+ static char * const widths[8] = { "8bit", "16bit", "[2]", "32bit", "2bit", "4bit", "[6]", "N/C" };
+ return widths[width];
+}
+
+static inline char *
+ht_link_freq(unsigned freq)
+{
+ static char * const freqs[16] = { "200MHz", "300MHz", "400MHz", "500MHz", "600MHz", "800MHz", "1.0GHz", "1.2GHz",
+ "1.4GHz", "1.6GHz", "[a]", "[b]", "[c]", "[d]", "[e]", "Vend" };
+ return freqs[freq];
+}
+
+static void
+cap_ht_pri(struct device *d, int where, int cmd)
+{
+ u16 lctr0, lcnf0, lctr1, lcnf1, eh;
+ u8 rid, lfrer0, lfcap0, ftr, lfrer1, lfcap1, mbu, mlu, bn;
+
+ printf("HyperTransport: Slave or Primary Interface\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_HT_PRI_LCTR0, PCI_HT_PRI_SIZEOF - PCI_HT_PRI_LCTR0))
+ return;
+ rid = get_conf_byte(d, where + PCI_HT_PRI_RID);
+ if (rid < 0x22 && rid > 0x11)
+ printf("\t\t!!! Possibly incomplete decoding\n");
+
+ printf("\t\tCommand: BaseUnitID=%u UnitCnt=%u MastHost%c DefDir%c",
+ (cmd & PCI_HT_PRI_CMD_BUID),
+ (cmd & PCI_HT_PRI_CMD_UC) >> 5,
+ FLAG(cmd, PCI_HT_PRI_CMD_MH),
+ FLAG(cmd, PCI_HT_PRI_CMD_DD));
+ if (rid >= 0x22)
+ printf(" DUL%c", FLAG(cmd, PCI_HT_PRI_CMD_DUL));
+ printf("\n");
+
+ lctr0 = get_conf_word(d, where + PCI_HT_PRI_LCTR0);
+ printf("\t\tLink Control 0: CFlE%c CST%c CFE%c <LkFail%c Init%c EOC%c TXO%c <CRCErr=%x",
+ FLAG(lctr0, PCI_HT_LCTR_CFLE),
+ FLAG(lctr0, PCI_HT_LCTR_CST),
+ FLAG(lctr0, PCI_HT_LCTR_CFE),
+ FLAG(lctr0, PCI_HT_LCTR_LKFAIL),
+ FLAG(lctr0, PCI_HT_LCTR_INIT),
+ FLAG(lctr0, PCI_HT_LCTR_EOC),
+ FLAG(lctr0, PCI_HT_LCTR_TXO),
+ (lctr0 & PCI_HT_LCTR_CRCERR) >> 8);
+ if (rid >= 0x22)
+ printf(" IsocEn%c LSEn%c ExtCTL%c 64b%c",
+ FLAG(lctr0, PCI_HT_LCTR_ISOCEN),
+ FLAG(lctr0, PCI_HT_LCTR_LSEN),
+ FLAG(lctr0, PCI_HT_LCTR_EXTCTL),
+ FLAG(lctr0, PCI_HT_LCTR_64B));
+ printf("\n");
+
+ lcnf0 = get_conf_word(d, where + PCI_HT_PRI_LCNF0);
+ if (rid < 0x22)
+ printf("\t\tLink Config 0: MLWI=%s MLWO=%s LWI=%s LWO=%s\n",
+ ht_link_width(lcnf0 & PCI_HT_LCNF_MLWI),
+ ht_link_width((lcnf0 & PCI_HT_LCNF_MLWO) >> 4),
+ ht_link_width((lcnf0 & PCI_HT_LCNF_LWI) >> 8),
+ ht_link_width((lcnf0 & PCI_HT_LCNF_LWO) >> 12));
+ else
+ printf("\t\tLink Config 0: MLWI=%s DwFcIn%c MLWO=%s DwFcOut%c LWI=%s DwFcInEn%c LWO=%s DwFcOutEn%c\n",
+ ht_link_width(lcnf0 & PCI_HT_LCNF_MLWI),
+ FLAG(lcnf0, PCI_HT_LCNF_DFI),
+ ht_link_width((lcnf0 & PCI_HT_LCNF_MLWO) >> 4),
+ FLAG(lcnf0, PCI_HT_LCNF_DFO),
+ ht_link_width((lcnf0 & PCI_HT_LCNF_LWI) >> 8),
+ FLAG(lcnf0, PCI_HT_LCNF_DFIE),
+ ht_link_width((lcnf0 & PCI_HT_LCNF_LWO) >> 12),
+ FLAG(lcnf0, PCI_HT_LCNF_DFOE));
+
+ lctr1 = get_conf_word(d, where + PCI_HT_PRI_LCTR1);
+ printf("\t\tLink Control 1: CFlE%c CST%c CFE%c <LkFail%c Init%c EOC%c TXO%c <CRCErr=%x",
+ FLAG(lctr1, PCI_HT_LCTR_CFLE),
+ FLAG(lctr1, PCI_HT_LCTR_CST),
+ FLAG(lctr1, PCI_HT_LCTR_CFE),
+ FLAG(lctr1, PCI_HT_LCTR_LKFAIL),
+ FLAG(lctr1, PCI_HT_LCTR_INIT),
+ FLAG(lctr1, PCI_HT_LCTR_EOC),
+ FLAG(lctr1, PCI_HT_LCTR_TXO),
+ (lctr1 & PCI_HT_LCTR_CRCERR) >> 8);
+ if (rid >= 0x22)
+ printf(" IsocEn%c LSEn%c ExtCTL%c 64b%c",
+ FLAG(lctr1, PCI_HT_LCTR_ISOCEN),
+ FLAG(lctr1, PCI_HT_LCTR_LSEN),
+ FLAG(lctr1, PCI_HT_LCTR_EXTCTL),
+ FLAG(lctr1, PCI_HT_LCTR_64B));
+ printf("\n");
+
+ lcnf1 = get_conf_word(d, where + PCI_HT_PRI_LCNF1);
+ if (rid < 0x22)
+ printf("\t\tLink Config 1: MLWI=%s MLWO=%s LWI=%s LWO=%s\n",
+ ht_link_width(lcnf1 & PCI_HT_LCNF_MLWI),
+ ht_link_width((lcnf1 & PCI_HT_LCNF_MLWO) >> 4),
+ ht_link_width((lcnf1 & PCI_HT_LCNF_LWI) >> 8),
+ ht_link_width((lcnf1 & PCI_HT_LCNF_LWO) >> 12));
+ else
+ printf("\t\tLink Config 1: MLWI=%s DwFcIn%c MLWO=%s DwFcOut%c LWI=%s DwFcInEn%c LWO=%s DwFcOutEn%c\n",
+ ht_link_width(lcnf1 & PCI_HT_LCNF_MLWI),
+ FLAG(lcnf1, PCI_HT_LCNF_DFI),
+ ht_link_width((lcnf1 & PCI_HT_LCNF_MLWO) >> 4),
+ FLAG(lcnf1, PCI_HT_LCNF_DFO),
+ ht_link_width((lcnf1 & PCI_HT_LCNF_LWI) >> 8),
+ FLAG(lcnf1, PCI_HT_LCNF_DFIE),
+ ht_link_width((lcnf1 & PCI_HT_LCNF_LWO) >> 12),
+ FLAG(lcnf1, PCI_HT_LCNF_DFOE));
+
+ printf("\t\tRevision ID: %u.%02u\n",
+ (rid & PCI_HT_RID_MAJ) >> 5, (rid & PCI_HT_RID_MIN));
+ if (rid < 0x22)
+ return;
+
+ lfrer0 = get_conf_byte(d, where + PCI_HT_PRI_LFRER0);
+ printf("\t\tLink Frequency 0: %s\n", ht_link_freq(lfrer0 & PCI_HT_LFRER_FREQ));
+ printf("\t\tLink Error 0: <Prot%c <Ovfl%c <EOC%c CTLTm%c\n",
+ FLAG(lfrer0, PCI_HT_LFRER_PROT),
+ FLAG(lfrer0, PCI_HT_LFRER_OV),
+ FLAG(lfrer0, PCI_HT_LFRER_EOC),
+ FLAG(lfrer0, PCI_HT_LFRER_CTLT));
+
+ lfcap0 = get_conf_byte(d, where + PCI_HT_PRI_LFCAP0);
+ printf("\t\tLink Frequency Capability 0: 200MHz%c 300MHz%c 400MHz%c 500MHz%c 600MHz%c 800MHz%c 1.0GHz%c 1.2GHz%c 1.4GHz%c 1.6GHz%c Vend%c\n",
+ FLAG(lfcap0, PCI_HT_LFCAP_200),
+ FLAG(lfcap0, PCI_HT_LFCAP_300),
+ FLAG(lfcap0, PCI_HT_LFCAP_400),
+ FLAG(lfcap0, PCI_HT_LFCAP_500),
+ FLAG(lfcap0, PCI_HT_LFCAP_600),
+ FLAG(lfcap0, PCI_HT_LFCAP_800),
+ FLAG(lfcap0, PCI_HT_LFCAP_1000),
+ FLAG(lfcap0, PCI_HT_LFCAP_1200),
+ FLAG(lfcap0, PCI_HT_LFCAP_1400),
+ FLAG(lfcap0, PCI_HT_LFCAP_1600),
+ FLAG(lfcap0, PCI_HT_LFCAP_VEND));
+
+ ftr = get_conf_byte(d, where + PCI_HT_PRI_FTR);
+ printf("\t\tFeature Capability: IsocFC%c LDTSTOP%c CRCTM%c ECTLT%c 64bA%c UIDRD%c\n",
+ FLAG(ftr, PCI_HT_FTR_ISOCFC),
+ FLAG(ftr, PCI_HT_FTR_LDTSTOP),
+ FLAG(ftr, PCI_HT_FTR_CRCTM),
+ FLAG(ftr, PCI_HT_FTR_ECTLT),
+ FLAG(ftr, PCI_HT_FTR_64BA),
+ FLAG(ftr, PCI_HT_FTR_UIDRD));
+
+ lfrer1 = get_conf_byte(d, where + PCI_HT_PRI_LFRER1);
+ printf("\t\tLink Frequency 1: %s\n", ht_link_freq(lfrer1 & PCI_HT_LFRER_FREQ));
+ printf("\t\tLink Error 1: <Prot%c <Ovfl%c <EOC%c CTLTm%c\n",
+ FLAG(lfrer1, PCI_HT_LFRER_PROT),
+ FLAG(lfrer1, PCI_HT_LFRER_OV),
+ FLAG(lfrer1, PCI_HT_LFRER_EOC),
+ FLAG(lfrer1, PCI_HT_LFRER_CTLT));
+
+ lfcap1 = get_conf_byte(d, where + PCI_HT_PRI_LFCAP1);
+ printf("\t\tLink Frequency Capability 1: 200MHz%c 300MHz%c 400MHz%c 500MHz%c 600MHz%c 800MHz%c 1.0GHz%c 1.2GHz%c 1.4GHz%c 1.6GHz%c Vend%c\n",
+ FLAG(lfcap1, PCI_HT_LFCAP_200),
+ FLAG(lfcap1, PCI_HT_LFCAP_300),
+ FLAG(lfcap1, PCI_HT_LFCAP_400),
+ FLAG(lfcap1, PCI_HT_LFCAP_500),
+ FLAG(lfcap1, PCI_HT_LFCAP_600),
+ FLAG(lfcap1, PCI_HT_LFCAP_800),
+ FLAG(lfcap1, PCI_HT_LFCAP_1000),
+ FLAG(lfcap1, PCI_HT_LFCAP_1200),
+ FLAG(lfcap1, PCI_HT_LFCAP_1400),
+ FLAG(lfcap1, PCI_HT_LFCAP_1600),
+ FLAG(lfcap1, PCI_HT_LFCAP_VEND));
+
+ eh = get_conf_word(d, where + PCI_HT_PRI_EH);
+ printf("\t\tError Handling: PFlE%c OFlE%c PFE%c OFE%c EOCFE%c RFE%c CRCFE%c SERRFE%c CF%c RE%c PNFE%c ONFE%c EOCNFE%c RNFE%c CRCNFE%c SERRNFE%c\n",
+ FLAG(eh, PCI_HT_EH_PFLE),
+ FLAG(eh, PCI_HT_EH_OFLE),
+ FLAG(eh, PCI_HT_EH_PFE),
+ FLAG(eh, PCI_HT_EH_OFE),
+ FLAG(eh, PCI_HT_EH_EOCFE),
+ FLAG(eh, PCI_HT_EH_RFE),
+ FLAG(eh, PCI_HT_EH_CRCFE),
+ FLAG(eh, PCI_HT_EH_SERRFE),
+ FLAG(eh, PCI_HT_EH_CF),
+ FLAG(eh, PCI_HT_EH_RE),
+ FLAG(eh, PCI_HT_EH_PNFE),
+ FLAG(eh, PCI_HT_EH_ONFE),
+ FLAG(eh, PCI_HT_EH_EOCNFE),
+ FLAG(eh, PCI_HT_EH_RNFE),
+ FLAG(eh, PCI_HT_EH_CRCNFE),
+ FLAG(eh, PCI_HT_EH_SERRNFE));
+
+ mbu = get_conf_byte(d, where + PCI_HT_PRI_MBU);
+ mlu = get_conf_byte(d, where + PCI_HT_PRI_MLU);
+ printf("\t\tPrefetchable memory behind bridge Upper: %02x-%02x\n", mbu, mlu);
+
+ bn = get_conf_byte(d, where + PCI_HT_PRI_BN);
+ printf("\t\tBus Number: %02x\n", bn);
+}
+
+static void
+cap_ht_sec(struct device *d, int where, int cmd)
+{
+ u16 lctr, lcnf, ftr, eh;
+ u8 rid, lfrer, lfcap, mbu, mlu;
+ char *fmt;
+
+ printf("HyperTransport: Host or Secondary Interface\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_HT_SEC_LCTR, PCI_HT_SEC_SIZEOF - PCI_HT_SEC_LCTR))
+ return;
+ rid = get_conf_byte(d, where + PCI_HT_SEC_RID);
+ if (rid < 0x22 && rid > 0x11)
+ printf("\t\t!!! Possibly incomplete decoding\n");
+
+ if (rid >= 0x22)
+ fmt = "\t\tCommand: WarmRst%c DblEnd%c DevNum=%u ChainSide%c HostHide%c Slave%c <EOCErr%c DUL%c\n";
+ else
+ fmt = "\t\tCommand: WarmRst%c DblEnd%c\n";
+ printf(fmt,
+ FLAG(cmd, PCI_HT_SEC_CMD_WR),
+ FLAG(cmd, PCI_HT_SEC_CMD_DE),
+ (cmd & PCI_HT_SEC_CMD_DN) >> 2,
+ FLAG(cmd, PCI_HT_SEC_CMD_CS),
+ FLAG(cmd, PCI_HT_SEC_CMD_HH),
+ FLAG(cmd, PCI_HT_SEC_CMD_AS),
+ FLAG(cmd, PCI_HT_SEC_CMD_HIECE),
+ FLAG(cmd, PCI_HT_SEC_CMD_DUL));
+ lctr = get_conf_word(d, where + PCI_HT_SEC_LCTR);
+ if (rid >= 0x22)
+ fmt = "\t\tLink Control: CFlE%c CST%c CFE%c <LkFail%c Init%c EOC%c TXO%c <CRCErr=%x IsocEn%c LSEn%c ExtCTL%c 64b%c\n";
+ else
+ fmt = "\t\tLink Control: CFlE%c CST%c CFE%c <LkFail%c Init%c EOC%c TXO%c <CRCErr=%x\n";
+ printf(fmt,
+ FLAG(lctr, PCI_HT_LCTR_CFLE),
+ FLAG(lctr, PCI_HT_LCTR_CST),
+ FLAG(lctr, PCI_HT_LCTR_CFE),
+ FLAG(lctr, PCI_HT_LCTR_LKFAIL),
+ FLAG(lctr, PCI_HT_LCTR_INIT),
+ FLAG(lctr, PCI_HT_LCTR_EOC),
+ FLAG(lctr, PCI_HT_LCTR_TXO),
+ (lctr & PCI_HT_LCTR_CRCERR) >> 8,
+ FLAG(lctr, PCI_HT_LCTR_ISOCEN),
+ FLAG(lctr, PCI_HT_LCTR_LSEN),
+ FLAG(lctr, PCI_HT_LCTR_EXTCTL),
+ FLAG(lctr, PCI_HT_LCTR_64B));
+ lcnf = get_conf_word(d, where + PCI_HT_SEC_LCNF);
+ if (rid >= 0x22)
+ fmt = "\t\tLink Config: MLWI=%1$s DwFcIn%5$c MLWO=%2$s DwFcOut%6$c LWI=%3$s DwFcInEn%7$c LWO=%4$s DwFcOutEn%8$c\n";
+ else
+ fmt = "\t\tLink Config: MLWI=%s MLWO=%s LWI=%s LWO=%s\n";
+ printf(fmt,
+ ht_link_width(lcnf & PCI_HT_LCNF_MLWI),
+ ht_link_width((lcnf & PCI_HT_LCNF_MLWO) >> 4),
+ ht_link_width((lcnf & PCI_HT_LCNF_LWI) >> 8),
+ ht_link_width((lcnf & PCI_HT_LCNF_LWO) >> 12),
+ FLAG(lcnf, PCI_HT_LCNF_DFI),
+ FLAG(lcnf, PCI_HT_LCNF_DFO),
+ FLAG(lcnf, PCI_HT_LCNF_DFIE),
+ FLAG(lcnf, PCI_HT_LCNF_DFOE));
+ printf("\t\tRevision ID: %u.%02u\n",
+ (rid & PCI_HT_RID_MAJ) >> 5, (rid & PCI_HT_RID_MIN));
+ if (rid < 0x22)
+ return;
+ lfrer = get_conf_byte(d, where + PCI_HT_SEC_LFRER);
+ printf("\t\tLink Frequency: %s\n", ht_link_freq(lfrer & PCI_HT_LFRER_FREQ));
+ printf("\t\tLink Error: <Prot%c <Ovfl%c <EOC%c CTLTm%c\n",
+ FLAG(lfrer, PCI_HT_LFRER_PROT),
+ FLAG(lfrer, PCI_HT_LFRER_OV),
+ FLAG(lfrer, PCI_HT_LFRER_EOC),
+ FLAG(lfrer, PCI_HT_LFRER_CTLT));
+ lfcap = get_conf_byte(d, where + PCI_HT_SEC_LFCAP);
+ printf("\t\tLink Frequency Capability: 200MHz%c 300MHz%c 400MHz%c 500MHz%c 600MHz%c 800MHz%c 1.0GHz%c 1.2GHz%c 1.4GHz%c 1.6GHz%c Vend%c\n",
+ FLAG(lfcap, PCI_HT_LFCAP_200),
+ FLAG(lfcap, PCI_HT_LFCAP_300),
+ FLAG(lfcap, PCI_HT_LFCAP_400),
+ FLAG(lfcap, PCI_HT_LFCAP_500),
+ FLAG(lfcap, PCI_HT_LFCAP_600),
+ FLAG(lfcap, PCI_HT_LFCAP_800),
+ FLAG(lfcap, PCI_HT_LFCAP_1000),
+ FLAG(lfcap, PCI_HT_LFCAP_1200),
+ FLAG(lfcap, PCI_HT_LFCAP_1400),
+ FLAG(lfcap, PCI_HT_LFCAP_1600),
+ FLAG(lfcap, PCI_HT_LFCAP_VEND));
+ ftr = get_conf_word(d, where + PCI_HT_SEC_FTR);
+ printf("\t\tFeature Capability: IsocFC%c LDTSTOP%c CRCTM%c ECTLT%c 64bA%c UIDRD%c ExtRS%c UCnfE%c\n",
+ FLAG(ftr, PCI_HT_FTR_ISOCFC),
+ FLAG(ftr, PCI_HT_FTR_LDTSTOP),
+ FLAG(ftr, PCI_HT_FTR_CRCTM),
+ FLAG(ftr, PCI_HT_FTR_ECTLT),
+ FLAG(ftr, PCI_HT_FTR_64BA),
+ FLAG(ftr, PCI_HT_FTR_UIDRD),
+ FLAG(ftr, PCI_HT_SEC_FTR_EXTRS),
+ FLAG(ftr, PCI_HT_SEC_FTR_UCNFE));
+ if (ftr & PCI_HT_SEC_FTR_EXTRS)
+ {
+ eh = get_conf_word(d, where + PCI_HT_SEC_EH);
+ printf("\t\tError Handling: PFlE%c OFlE%c PFE%c OFE%c EOCFE%c RFE%c CRCFE%c SERRFE%c CF%c RE%c PNFE%c ONFE%c EOCNFE%c RNFE%c CRCNFE%c SERRNFE%c\n",
+ FLAG(eh, PCI_HT_EH_PFLE),
+ FLAG(eh, PCI_HT_EH_OFLE),
+ FLAG(eh, PCI_HT_EH_PFE),
+ FLAG(eh, PCI_HT_EH_OFE),
+ FLAG(eh, PCI_HT_EH_EOCFE),
+ FLAG(eh, PCI_HT_EH_RFE),
+ FLAG(eh, PCI_HT_EH_CRCFE),
+ FLAG(eh, PCI_HT_EH_SERRFE),
+ FLAG(eh, PCI_HT_EH_CF),
+ FLAG(eh, PCI_HT_EH_RE),
+ FLAG(eh, PCI_HT_EH_PNFE),
+ FLAG(eh, PCI_HT_EH_ONFE),
+ FLAG(eh, PCI_HT_EH_EOCNFE),
+ FLAG(eh, PCI_HT_EH_RNFE),
+ FLAG(eh, PCI_HT_EH_CRCNFE),
+ FLAG(eh, PCI_HT_EH_SERRNFE));
+ mbu = get_conf_byte(d, where + PCI_HT_SEC_MBU);
+ mlu = get_conf_byte(d, where + PCI_HT_SEC_MLU);
+ printf("\t\tPrefetchable memory behind bridge Upper: %02x-%02x\n", mbu, mlu);
+ }
+}
+
+static void
+cap_ht(struct device *d, int where, int cmd)
+{
+ int type;
+
+ switch (cmd & PCI_HT_CMD_TYP_HI)
+ {
+ case PCI_HT_CMD_TYP_HI_PRI:
+ cap_ht_pri(d, where, cmd);
+ return;
+ case PCI_HT_CMD_TYP_HI_SEC:
+ cap_ht_sec(d, where, cmd);
+ return;
+ }
+
+ type = cmd & PCI_HT_CMD_TYP;
+ switch (type)
+ {
+ case PCI_HT_CMD_TYP_SW:
+ printf("HyperTransport: Switch\n");
+ break;
+ case PCI_HT_CMD_TYP_IDC:
+ printf("HyperTransport: Interrupt Discovery and Configuration\n");
+ break;
+ case PCI_HT_CMD_TYP_RID:
+ printf("HyperTransport: Revision ID: %u.%02u\n",
+ (cmd & PCI_HT_RID_MAJ) >> 5, (cmd & PCI_HT_RID_MIN));
+ break;
+ case PCI_HT_CMD_TYP_UIDC:
+ printf("HyperTransport: UnitID Clumping\n");
+ break;
+ case PCI_HT_CMD_TYP_ECSA:
+ printf("HyperTransport: Extended Configuration Space Access\n");
+ break;
+ case PCI_HT_CMD_TYP_AM:
+ printf("HyperTransport: Address Mapping\n");
+ break;
+ case PCI_HT_CMD_TYP_MSIM:
+ printf("HyperTransport: MSI Mapping Enable%c Fixed%c\n",
+ FLAG(cmd, PCI_HT_MSIM_CMD_EN),
+ FLAG(cmd, PCI_HT_MSIM_CMD_FIXD));
+ if (verbose >= 2 && !(cmd & PCI_HT_MSIM_CMD_FIXD))
+ {
+ u32 offl, offh;
+ if (!config_fetch(d, where + PCI_HT_MSIM_ADDR_LO, 8))
+ break;
+ offl = get_conf_long(d, where + PCI_HT_MSIM_ADDR_LO);
+ offh = get_conf_long(d, where + PCI_HT_MSIM_ADDR_HI);
+ printf("\t\tMapping Address Base: %016llx\n", ((unsigned long long)offh << 32) | (offl & ~0xfffff));
+ }
+ break;
+ case PCI_HT_CMD_TYP_DR:
+ printf("HyperTransport: DirectRoute\n");
+ break;
+ case PCI_HT_CMD_TYP_VCS:
+ printf("HyperTransport: VCSet\n");
+ break;
+ case PCI_HT_CMD_TYP_RM:
+ printf("HyperTransport: Retry Mode\n");
+ break;
+ case PCI_HT_CMD_TYP_X86:
+ printf("HyperTransport: X86 (reserved)\n");
+ break;
+ default:
+ printf("HyperTransport: #%02x\n", type >> 11);
+ }
+}
+
+static void
+cap_msi(struct device *d, int where, int cap)
+{
+ int is64;
+ u32 t;
+ u16 w;
+
+ printf("MSI: Enable%c Count=%d/%d Maskable%c 64bit%c\n",
+ FLAG(cap, PCI_MSI_FLAGS_ENABLE),
+ 1 << ((cap & PCI_MSI_FLAGS_QSIZE) >> 4),
+ 1 << ((cap & PCI_MSI_FLAGS_QMASK) >> 1),
+ FLAG(cap, PCI_MSI_FLAGS_MASK_BIT),
+ FLAG(cap, PCI_MSI_FLAGS_64BIT));
+ if (verbose < 2)
+ return;
+ is64 = cap & PCI_MSI_FLAGS_64BIT;
+ if (!config_fetch(d, where + PCI_MSI_ADDRESS_LO, (is64 ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32) + 2 - PCI_MSI_ADDRESS_LO))
+ return;
+ printf("\t\tAddress: ");
+ if (is64)
+ {
+ t = get_conf_long(d, where + PCI_MSI_ADDRESS_HI);
+ w = get_conf_word(d, where + PCI_MSI_DATA_64);
+ printf("%08x", t);
+ }
+ else
+ w = get_conf_word(d, where + PCI_MSI_DATA_32);
+ t = get_conf_long(d, where + PCI_MSI_ADDRESS_LO);
+ printf("%08x Data: %04x\n", t, w);
+ if (cap & PCI_MSI_FLAGS_MASK_BIT)
+ {
+ u32 mask, pending;
+
+ if (is64)
+ {
+ if (!config_fetch(d, where + PCI_MSI_MASK_BIT_64, 8))
+ return;
+ mask = get_conf_long(d, where + PCI_MSI_MASK_BIT_64);
+ pending = get_conf_long(d, where + PCI_MSI_PENDING_64);
+ }
+ else
+ {
+ if (!config_fetch(d, where + PCI_MSI_MASK_BIT_32, 8))
+ return;
+ mask = get_conf_long(d, where + PCI_MSI_MASK_BIT_32);
+ pending = get_conf_long(d, where + PCI_MSI_PENDING_32);
+ }
+ printf("\t\tMasking: %08x Pending: %08x\n", mask, pending);
+ }
+}
+
+static int exp_downstream_port(int type)
+{
+ return type == PCI_EXP_TYPE_ROOT_PORT ||
+ type == PCI_EXP_TYPE_DOWNSTREAM ||
+ type == PCI_EXP_TYPE_PCIE_BRIDGE; /* PCI/PCI-X to PCIe Bridge */
+}
+
+static float power_limit(int value, int scale)
+{
+ static const float scales[4] = { 1.0, 0.1, 0.01, 0.001 };
+ return value * scales[scale];
+}
+
+static const char *latency_l0s(int value)
+{
+ static const char *latencies[] = { "<64ns", "<128ns", "<256ns", "<512ns", "<1us", "<2us", "<4us", "unlimited" };
+ return latencies[value];
+}
+
+static const char *latency_l1(int value)
+{
+ static const char *latencies[] = { "<1us", "<2us", "<4us", "<8us", "<16us", "<32us", "<64us", "unlimited" };
+ return latencies[value];
+}
+
+static void cap_express_dev(struct device *d, int where, int type)
+{
+ u32 t;
+ u16 w;
+
+ t = get_conf_long(d, where + PCI_EXP_DEVCAP);
+ printf("\t\tDevCap:\tMaxPayload %d bytes, PhantFunc %d",
+ 128 << (t & PCI_EXP_DEVCAP_PAYLOAD),
+ (1 << ((t & PCI_EXP_DEVCAP_PHANTOM) >> 3)) - 1);
+ if ((type == PCI_EXP_TYPE_ENDPOINT) || (type == PCI_EXP_TYPE_LEG_END))
+ printf(", Latency L0s %s, L1 %s",
+ latency_l0s((t & PCI_EXP_DEVCAP_L0S) >> 6),
+ latency_l1((t & PCI_EXP_DEVCAP_L1) >> 9));
+ printf("\n");
+ printf("\t\t\tExtTag%c", FLAG(t, PCI_EXP_DEVCAP_EXT_TAG));
+ if ((type == PCI_EXP_TYPE_ENDPOINT) || (type == PCI_EXP_TYPE_LEG_END) ||
+ (type == PCI_EXP_TYPE_UPSTREAM) || (type == PCI_EXP_TYPE_PCI_BRIDGE))
+ printf(" AttnBtn%c AttnInd%c PwrInd%c",
+ FLAG(t, PCI_EXP_DEVCAP_ATN_BUT),
+ FLAG(t, PCI_EXP_DEVCAP_ATN_IND), FLAG(t, PCI_EXP_DEVCAP_PWR_IND));
+ printf(" RBE%c",
+ FLAG(t, PCI_EXP_DEVCAP_RBE));
+ if ((type == PCI_EXP_TYPE_ENDPOINT) || (type == PCI_EXP_TYPE_LEG_END) || (type == PCI_EXP_TYPE_ROOT_INT_EP))
+ printf(" FLReset%c",
+ FLAG(t, PCI_EXP_DEVCAP_FLRESET));
+ if ((type == PCI_EXP_TYPE_ENDPOINT) || (type == PCI_EXP_TYPE_UPSTREAM) ||
+ (type == PCI_EXP_TYPE_PCI_BRIDGE))
+ printf(" SlotPowerLimit %.3fW",
+ power_limit((t & PCI_EXP_DEVCAP_PWR_VAL) >> 18,
+ (t & PCI_EXP_DEVCAP_PWR_SCL) >> 26));
+ printf("\n");
+
+ w = get_conf_word(d, where + PCI_EXP_DEVCTL);
+ printf("\t\tDevCtl:\tCorrErr%c NonFatalErr%c FatalErr%c UnsupReq%c\n",
+ FLAG(w, PCI_EXP_DEVCTL_CERE),
+ FLAG(w, PCI_EXP_DEVCTL_NFERE),
+ FLAG(w, PCI_EXP_DEVCTL_FERE),
+ FLAG(w, PCI_EXP_DEVCTL_URRE));
+ printf("\t\t\tRlxdOrd%c ExtTag%c PhantFunc%c AuxPwr%c NoSnoop%c",
+ FLAG(w, PCI_EXP_DEVCTL_RELAXED),
+ FLAG(w, PCI_EXP_DEVCTL_EXT_TAG),
+ FLAG(w, PCI_EXP_DEVCTL_PHANTOM),
+ FLAG(w, PCI_EXP_DEVCTL_AUX_PME),
+ FLAG(w, PCI_EXP_DEVCTL_NOSNOOP));
+ if (type == PCI_EXP_TYPE_PCI_BRIDGE)
+ printf(" BrConfRtry%c", FLAG(w, PCI_EXP_DEVCTL_BCRE));
+ if (((type == PCI_EXP_TYPE_ENDPOINT) || (type == PCI_EXP_TYPE_LEG_END) || (type == PCI_EXP_TYPE_ROOT_INT_EP)) &&
+ (t & PCI_EXP_DEVCAP_FLRESET))
+ printf(" FLReset%c", FLAG(w, PCI_EXP_DEVCTL_FLRESET));
+ printf("\n\t\t\tMaxPayload %d bytes, MaxReadReq %d bytes\n",
+ 128 << ((w & PCI_EXP_DEVCTL_PAYLOAD) >> 5),
+ 128 << ((w & PCI_EXP_DEVCTL_READRQ) >> 12));
+
+ w = get_conf_word(d, where + PCI_EXP_DEVSTA);
+ printf("\t\tDevSta:\tCorrErr%c NonFatalErr%c FatalErr%c UnsupReq%c AuxPwr%c TransPend%c\n",
+ FLAG(w, PCI_EXP_DEVSTA_CED),
+ FLAG(w, PCI_EXP_DEVSTA_NFED),
+ FLAG(w, PCI_EXP_DEVSTA_FED),
+ FLAG(w, PCI_EXP_DEVSTA_URD),
+ FLAG(w, PCI_EXP_DEVSTA_AUXPD),
+ FLAG(w, PCI_EXP_DEVSTA_TRPND));
+}
+
+static char *link_speed(int speed)
+{
+ switch (speed)
+ {
+ case 1:
+ return "2.5GT/s";
+ case 2:
+ return "5GT/s";
+ case 3:
+ return "8GT/s";
+ case 4:
+ return "16GT/s";
+ case 5:
+ return "32GT/s";
+ default:
+ return "unknown";
+ }
+}
+
+static char *link_compare(int sta, int cap)
+{
+ if (sta < cap)
+ return "downgraded";
+ if (sta > cap)
+ return "strange";
+ return "ok";
+}
+
+static char *aspm_support(int code)
+{
+ switch (code)
+ {
+ case 0:
+ return "not supported";
+ case 1:
+ return "L0s";
+ case 2:
+ return "L1";
+ case 3:
+ return "L0s L1";
+ default:
+ return "unknown";
+ }
+}
+
+static const char *aspm_enabled(int code)
+{
+ static const char *desc[] = { "Disabled", "L0s Enabled", "L1 Enabled", "L0s L1 Enabled" };
+ return desc[code];
+}
+
+static void cap_express_link(struct device *d, int where, int type)
+{
+ u32 t, aspm, cap_speed, cap_width, sta_speed, sta_width;
+ u16 w;
+
+ t = get_conf_long(d, where + PCI_EXP_LNKCAP);
+ aspm = (t & PCI_EXP_LNKCAP_ASPM) >> 10;
+ cap_speed = t & PCI_EXP_LNKCAP_SPEED;
+ cap_width = (t & PCI_EXP_LNKCAP_WIDTH) >> 4;
+ printf("\t\tLnkCap:\tPort #%d, Speed %s, Width x%d, ASPM %s",
+ t >> 24,
+ link_speed(cap_speed), cap_width,
+ aspm_support(aspm));
+ if (aspm)
+ {
+ printf(", Exit Latency ");
+ if (aspm & 1)
+ printf("L0s %s", latency_l0s((t & PCI_EXP_LNKCAP_L0S) >> 12));
+ if (aspm & 2)
+ printf("%sL1 %s", (aspm & 1) ? ", " : "",
+ latency_l1((t & PCI_EXP_LNKCAP_L1) >> 15));
+ }
+ printf("\n");
+ printf("\t\t\tClockPM%c Surprise%c LLActRep%c BwNot%c ASPMOptComp%c\n",
+ FLAG(t, PCI_EXP_LNKCAP_CLOCKPM),
+ FLAG(t, PCI_EXP_LNKCAP_SURPRISE),
+ FLAG(t, PCI_EXP_LNKCAP_DLLA),
+ FLAG(t, PCI_EXP_LNKCAP_LBNC),
+ FLAG(t, PCI_EXP_LNKCAP_AOC));
+
+ w = get_conf_word(d, where + PCI_EXP_LNKCTL);
+ printf("\t\tLnkCtl:\tASPM %s;", aspm_enabled(w & PCI_EXP_LNKCTL_ASPM));
+ if ((type == PCI_EXP_TYPE_ROOT_PORT) || (type == PCI_EXP_TYPE_ENDPOINT) ||
+ (type == PCI_EXP_TYPE_LEG_END) || (type == PCI_EXP_TYPE_PCI_BRIDGE))
+ printf(" RCB %d bytes,", w & PCI_EXP_LNKCTL_RCB ? 128 : 64);
+ printf(" Disabled%c CommClk%c\n\t\t\tExtSynch%c ClockPM%c AutWidDis%c BWInt%c AutBWInt%c\n",
+ FLAG(w, PCI_EXP_LNKCTL_DISABLE),
+ FLAG(w, PCI_EXP_LNKCTL_CLOCK),
+ FLAG(w, PCI_EXP_LNKCTL_XSYNCH),
+ FLAG(w, PCI_EXP_LNKCTL_CLOCKPM),
+ FLAG(w, PCI_EXP_LNKCTL_HWAUTWD),
+ FLAG(w, PCI_EXP_LNKCTL_BWMIE),
+ FLAG(w, PCI_EXP_LNKCTL_AUTBWIE));
+
+ w = get_conf_word(d, where + PCI_EXP_LNKSTA);
+ sta_speed = w & PCI_EXP_LNKSTA_SPEED;
+ sta_width = (w & PCI_EXP_LNKSTA_WIDTH) >> 4;
+ printf("\t\tLnkSta:\tSpeed %s (%s), Width x%d (%s)\n",
+ link_speed(sta_speed),
+ link_compare(sta_speed, cap_speed),
+ sta_width,
+ link_compare(sta_width, cap_width));
+ printf("\t\t\tTrErr%c Train%c SlotClk%c DLActive%c BWMgmt%c ABWMgmt%c\n",
+ FLAG(w, PCI_EXP_LNKSTA_TR_ERR),
+ FLAG(w, PCI_EXP_LNKSTA_TRAIN),
+ FLAG(w, PCI_EXP_LNKSTA_SL_CLK),
+ FLAG(w, PCI_EXP_LNKSTA_DL_ACT),
+ FLAG(w, PCI_EXP_LNKSTA_BWMGMT),
+ FLAG(w, PCI_EXP_LNKSTA_AUTBW));
+}
+
+static const char *indicator(int code)
+{
+ static const char *names[] = { "Unknown", "On", "Blink", "Off" };
+ return names[code];
+}
+
+static void cap_express_slot(struct device *d, int where)
+{
+ u32 t;
+ u16 w;
+
+ t = get_conf_long(d, where + PCI_EXP_SLTCAP);
+ printf("\t\tSltCap:\tAttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c\n",
+ FLAG(t, PCI_EXP_SLTCAP_ATNB),
+ FLAG(t, PCI_EXP_SLTCAP_PWRC),
+ FLAG(t, PCI_EXP_SLTCAP_MRL),
+ FLAG(t, PCI_EXP_SLTCAP_ATNI),
+ FLAG(t, PCI_EXP_SLTCAP_PWRI),
+ FLAG(t, PCI_EXP_SLTCAP_HPC),
+ FLAG(t, PCI_EXP_SLTCAP_HPS));
+ printf("\t\t\tSlot #%d, PowerLimit %.3fW; Interlock%c NoCompl%c\n",
+ (t & PCI_EXP_SLTCAP_PSN) >> 19,
+ power_limit((t & PCI_EXP_SLTCAP_PWR_VAL) >> 7, (t & PCI_EXP_SLTCAP_PWR_SCL) >> 15),
+ FLAG(t, PCI_EXP_SLTCAP_INTERLOCK),
+ FLAG(t, PCI_EXP_SLTCAP_NOCMDCOMP));
+
+ w = get_conf_word(d, where + PCI_EXP_SLTCTL);
+ printf("\t\tSltCtl:\tEnable: AttnBtn%c PwrFlt%c MRL%c PresDet%c CmdCplt%c HPIrq%c LinkChg%c\n",
+ FLAG(w, PCI_EXP_SLTCTL_ATNB),
+ FLAG(w, PCI_EXP_SLTCTL_PWRF),
+ FLAG(w, PCI_EXP_SLTCTL_MRLS),
+ FLAG(w, PCI_EXP_SLTCTL_PRSD),
+ FLAG(w, PCI_EXP_SLTCTL_CMDC),
+ FLAG(w, PCI_EXP_SLTCTL_HPIE),
+ FLAG(w, PCI_EXP_SLTCTL_LLCHG));
+ printf("\t\t\tControl: AttnInd %s, PwrInd %s, Power%c Interlock%c\n",
+ indicator((w & PCI_EXP_SLTCTL_ATNI) >> 6),
+ indicator((w & PCI_EXP_SLTCTL_PWRI) >> 8),
+ FLAG(w, PCI_EXP_SLTCTL_PWRC),
+ FLAG(w, PCI_EXP_SLTCTL_INTERLOCK));
+
+ w = get_conf_word(d, where + PCI_EXP_SLTSTA);
+ printf("\t\tSltSta:\tStatus: AttnBtn%c PowerFlt%c MRL%c CmdCplt%c PresDet%c Interlock%c\n",
+ FLAG(w, PCI_EXP_SLTSTA_ATNB),
+ FLAG(w, PCI_EXP_SLTSTA_PWRF),
+ FLAG(w, PCI_EXP_SLTSTA_MRL_ST),
+ FLAG(w, PCI_EXP_SLTSTA_CMDC),
+ FLAG(w, PCI_EXP_SLTSTA_PRES),
+ FLAG(w, PCI_EXP_SLTSTA_INTERLOCK));
+ printf("\t\t\tChanged: MRL%c PresDet%c LinkState%c\n",
+ FLAG(w, PCI_EXP_SLTSTA_MRLS),
+ FLAG(w, PCI_EXP_SLTSTA_PRSD),
+ FLAG(w, PCI_EXP_SLTSTA_LLCHG));
+}
+
+static void cap_express_root(struct device *d, int where)
+{
+ u32 w;
+
+ w = get_conf_word(d, where + PCI_EXP_RTCAP);
+ printf("\t\tRootCap: CRSVisible%c\n",
+ FLAG(w, PCI_EXP_RTCAP_CRSVIS));
+
+ w = get_conf_word(d, where + PCI_EXP_RTCTL);
+ printf("\t\tRootCtl: ErrCorrectable%c ErrNon-Fatal%c ErrFatal%c PMEIntEna%c CRSVisible%c\n",
+ FLAG(w, PCI_EXP_RTCTL_SECEE),
+ FLAG(w, PCI_EXP_RTCTL_SENFEE),
+ FLAG(w, PCI_EXP_RTCTL_SEFEE),
+ FLAG(w, PCI_EXP_RTCTL_PMEIE),
+ FLAG(w, PCI_EXP_RTCTL_CRSVIS));
+
+ w = get_conf_long(d, where + PCI_EXP_RTSTA);
+ printf("\t\tRootSta: PME ReqID %04x, PMEStatus%c PMEPending%c\n",
+ w & PCI_EXP_RTSTA_PME_REQID,
+ FLAG(w, PCI_EXP_RTSTA_PME_STATUS),
+ FLAG(w, PCI_EXP_RTSTA_PME_PENDING));
+}
+
+static const char *cap_express_dev2_timeout_range(int type)
+{
+ /* Decode Completion Timeout Ranges. */
+ switch (type)
+ {
+ case 0:
+ return "Not Supported";
+ case 1:
+ return "Range A";
+ case 2:
+ return "Range B";
+ case 3:
+ return "Range AB";
+ case 6:
+ return "Range BC";
+ case 7:
+ return "Range ABC";
+ case 14:
+ return "Range BCD";
+ case 15:
+ return "Range ABCD";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *cap_express_dev2_timeout_value(int type)
+{
+ /* Decode Completion Timeout Value. */
+ switch (type)
+ {
+ case 0:
+ return "50us to 50ms";
+ case 1:
+ return "50us to 100us";
+ case 2:
+ return "1ms to 10ms";
+ case 5:
+ return "16ms to 55ms";
+ case 6:
+ return "65ms to 210ms";
+ case 9:
+ return "260ms to 900ms";
+ case 10:
+ return "1s to 3.5s";
+ case 13:
+ return "4s to 13s";
+ case 14:
+ return "17s to 64s";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *cap_express_devcap2_obff(int obff)
+{
+ switch (obff)
+ {
+ case 1:
+ return "Via message";
+ case 2:
+ return "Via WAKE#";
+ case 3:
+ return "Via message/WAKE#";
+ default:
+ return "Not Supported";
+ }
+}
+
+static const char *cap_express_devcap2_epr(int epr)
+{
+ switch (epr)
+ {
+ case 1:
+ return "Dev Specific";
+ case 2:
+ return "Form Factor Dev Specific";
+ case 3:
+ return "Reserved";
+ default:
+ return "Not Supported";
+ }
+}
+
+static const char *cap_express_devcap2_lncls(int lncls)
+{
+ switch (lncls)
+ {
+ case 1:
+ return "64byte cachelines";
+ case 2:
+ return "128byte cachelines";
+ case 3:
+ return "Reserved";
+ default:
+ return "Not Supported";
+ }
+}
+
+static const char *cap_express_devcap2_tphcomp(int tph)
+{
+ switch (tph)
+ {
+ case 1:
+ return "TPHComp+ ExtTPHComp-";
+ case 2:
+ /* Reserved; intentionally left blank */
+ return "";
+ case 3:
+ return "TPHComp+ ExtTPHComp+";
+ default:
+ return "TPHComp- ExtTPHComp-";
+ }
+}
+
+static const char *cap_express_devctl2_obff(int obff)
+{
+ switch (obff)
+ {
+ case 0:
+ return "Disabled";
+ case 1:
+ return "Via message A";
+ case 2:
+ return "Via message B";
+ case 3:
+ return "Via WAKE#";
+ default:
+ return "Unknown";
+ }
+}
+
+static int
+device_has_memory_space_bar(struct device *d)
+{
+ struct pci_dev *p = d->dev;
+ int i, found = 0;
+
+ for (i=0; i<6; i++)
+ if (p->base_addr[i] && p->size[i])
+ {
+ if (!(p->base_addr[i] & PCI_BASE_ADDRESS_SPACE_IO))
+ {
+ found = 1;
+ break;
+ }
+ }
+ return found;
+}
+
+static void cap_express_dev2(struct device *d, int where, int type)
+{
+ u32 l;
+ u16 w;
+ int has_mem_bar = device_has_memory_space_bar(d);
+
+ l = get_conf_long(d, where + PCI_EXP_DEVCAP2);
+ printf("\t\tDevCap2: Completion Timeout: %s, TimeoutDis%c NROPrPrP%c LTR%c",
+ cap_express_dev2_timeout_range(PCI_EXP_DEV2_TIMEOUT_RANGE(l)),
+ FLAG(l, PCI_EXP_DEV2_TIMEOUT_DIS),
+ FLAG(l, PCI_EXP_DEVCAP2_NROPRPRP),
+ FLAG(l, PCI_EXP_DEVCAP2_LTR));
+ printf("\n\t\t\t 10BitTagComp%c 10BitTagReq%c OBFF %s, ExtFmt%c EETLPPrefix%c",
+ FLAG(l, PCI_EXP_DEVCAP2_10BIT_TAG_COMP),
+ FLAG(l, PCI_EXP_DEVCAP2_10BIT_TAG_REQ),
+ cap_express_devcap2_obff(PCI_EXP_DEVCAP2_OBFF(l)),
+ FLAG(l, PCI_EXP_DEVCAP2_EXTFMT),
+ FLAG(l, PCI_EXP_DEVCAP2_EE_TLP));
+
+ if (PCI_EXP_DEVCAP2_EE_TLP == (l & PCI_EXP_DEVCAP2_EE_TLP))
+ {
+ printf(", MaxEETLPPrefixes %d",
+ PCI_EXP_DEVCAP2_MEE_TLP(l) ? PCI_EXP_DEVCAP2_MEE_TLP(l) : 4);
+ }
+
+ printf("\n\t\t\t EmergencyPowerReduction %s, EmergencyPowerReductionInit%c",
+ cap_express_devcap2_epr(PCI_EXP_DEVCAP2_EPR(l)),
+ FLAG(l, PCI_EXP_DEVCAP2_EPR_INIT));
+ printf("\n\t\t\t FRS%c", FLAG(l, PCI_EXP_DEVCAP2_FRS));
+
+ if (type == PCI_EXP_TYPE_ROOT_PORT)
+ printf(" LN System CLS %s,",
+ cap_express_devcap2_lncls(PCI_EXP_DEVCAP2_LN_CLS(l)));
+
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_ENDPOINT)
+ printf(" %s", cap_express_devcap2_tphcomp(PCI_EXP_DEVCAP2_TPH_COMP(l)));
+
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_DOWNSTREAM)
+ printf(" ARIFwd%c\n", FLAG(l, PCI_EXP_DEV2_ARI));
+ else
+ printf("\n");
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_UPSTREAM ||
+ type == PCI_EXP_TYPE_DOWNSTREAM || has_mem_bar)
+ {
+ printf("\t\t\t AtomicOpsCap:");
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_UPSTREAM ||
+ type == PCI_EXP_TYPE_DOWNSTREAM)
+ printf(" Routing%c", FLAG(l, PCI_EXP_DEVCAP2_ATOMICOP_ROUTING));
+ if (type == PCI_EXP_TYPE_ROOT_PORT || has_mem_bar)
+ printf(" 32bit%c 64bit%c 128bitCAS%c",
+ FLAG(l, PCI_EXP_DEVCAP2_32BIT_ATOMICOP_COMP),
+ FLAG(l, PCI_EXP_DEVCAP2_64BIT_ATOMICOP_COMP),
+ FLAG(l, PCI_EXP_DEVCAP2_128BIT_CAS_COMP));
+ printf("\n");
+ }
+
+ w = get_conf_word(d, where + PCI_EXP_DEVCTL2);
+ printf("\t\tDevCtl2: Completion Timeout: %s, TimeoutDis%c LTR%c OBFF %s,",
+ cap_express_dev2_timeout_value(PCI_EXP_DEV2_TIMEOUT_VALUE(w)),
+ FLAG(w, PCI_EXP_DEV2_TIMEOUT_DIS),
+ FLAG(w, PCI_EXP_DEV2_LTR),
+ cap_express_devctl2_obff(PCI_EXP_DEV2_OBFF(w)));
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_DOWNSTREAM)
+ printf(" ARIFwd%c\n", FLAG(w, PCI_EXP_DEV2_ARI));
+ else
+ printf("\n");
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_UPSTREAM ||
+ type == PCI_EXP_TYPE_DOWNSTREAM || type == PCI_EXP_TYPE_ENDPOINT ||
+ type == PCI_EXP_TYPE_ROOT_INT_EP || type == PCI_EXP_TYPE_LEG_END)
+ {
+ printf("\t\t\t AtomicOpsCtl:");
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_ENDPOINT ||
+ type == PCI_EXP_TYPE_ROOT_INT_EP || type == PCI_EXP_TYPE_LEG_END)
+ printf(" ReqEn%c", FLAG(w, PCI_EXP_DEV2_ATOMICOP_REQUESTER_EN));
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_UPSTREAM ||
+ type == PCI_EXP_TYPE_DOWNSTREAM)
+ printf(" EgressBlck%c", FLAG(w, PCI_EXP_DEV2_ATOMICOP_EGRESS_BLOCK));
+ printf("\n");
+ }
+}
+
+static const char *cap_express_link2_speed_cap(int vector)
+{
+ /*
+ * Per PCIe r5.0, sec 8.2.1, a device must support 2.5GT/s and is not
+ * permitted to skip support for any data rates between 2.5GT/s and the
+ * highest supported rate.
+ */
+ if (vector & 0x60)
+ return "RsvdP";
+ if (vector & 0x10)
+ return "2.5-32GT/s";
+ if (vector & 0x08)
+ return "2.5-16GT/s";
+ if (vector & 0x04)
+ return "2.5-8GT/s";
+ if (vector & 0x02)
+ return "2.5-5GT/s";
+ if (vector & 0x01)
+ return "2.5GT/s";
+
+ return "Unknown";
+}
+
+static const char *cap_express_link2_speed(int type)
+{
+ switch (type)
+ {
+ case 0: /* hardwire to 0 means only the 2.5GT/s is supported */
+ case 1:
+ return "2.5GT/s";
+ case 2:
+ return "5GT/s";
+ case 3:
+ return "8GT/s";
+ case 4:
+ return "16GT/s";
+ case 5:
+ return "32GT/s";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *cap_express_link2_deemphasis(int type)
+{
+ switch (type)
+ {
+ case 0:
+ return "-6dB";
+ case 1:
+ return "-3.5dB";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *cap_express_link2_transmargin(int type)
+{
+ switch (type)
+ {
+ case 0:
+ return "Normal Operating Range";
+ case 1:
+ return "800-1200mV(full-swing)/400-700mV(half-swing)";
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ return "200-400mV(full-swing)/100-200mV(half-swing)";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *cap_express_link2_crosslink_res(int crosslink)
+{
+ switch (crosslink)
+ {
+ case 0:
+ return "unsupported";
+ case 1:
+ return "Upstream Port";
+ case 2:
+ return "Downstream Port";
+ default:
+ return "incomplete";
+ }
+}
+
+static const char *cap_express_link2_component(int presence)
+{
+ switch (presence)
+ {
+ case 0:
+ return "Link Down - Not Determined";
+ case 1:
+ return "Link Down - Not Present";
+ case 2:
+ return "Link Down - Present";
+ case 4:
+ return "Link Up - Present";
+ case 5:
+ return "Link Up - Present and DRS Received";
+ default:
+ return "Reserved";
+ }
+}
+
+static void cap_express_link2(struct device *d, int where, int type)
+{
+ u32 l = 0;
+ u16 w;
+
+ if (!((type == PCI_EXP_TYPE_ENDPOINT || type == PCI_EXP_TYPE_LEG_END) &&
+ (d->dev->dev != 0 || d->dev->func != 0))) {
+ /* Link Capabilities 2 was reserved before PCIe r3.0 */
+ l = get_conf_long(d, where + PCI_EXP_LNKCAP2);
+ if (l) {
+ printf("\t\tLnkCap2: Supported Link Speeds: %s, Crosslink%c "
+ "Retimer%c 2Retimers%c DRS%c\n",
+ cap_express_link2_speed_cap(PCI_EXP_LNKCAP2_SPEED(l)),
+ FLAG(l, PCI_EXP_LNKCAP2_CROSSLINK),
+ FLAG(l, PCI_EXP_LNKCAP2_RETIMER),
+ FLAG(l, PCI_EXP_LNKCAP2_2RETIMERS),
+ FLAG(l, PCI_EXP_LNKCAP2_DRS));
+ }
+
+ w = get_conf_word(d, where + PCI_EXP_LNKCTL2);
+ printf("\t\tLnkCtl2: Target Link Speed: %s, EnterCompliance%c SpeedDis%c",
+ cap_express_link2_speed(PCI_EXP_LNKCTL2_SPEED(w)),
+ FLAG(w, PCI_EXP_LNKCTL2_CMPLNC),
+ FLAG(w, PCI_EXP_LNKCTL2_SPEED_DIS));
+ if (type == PCI_EXP_TYPE_DOWNSTREAM)
+ printf(", Selectable De-emphasis: %s",
+ cap_express_link2_deemphasis(PCI_EXP_LNKCTL2_DEEMPHASIS(w)));
+ printf("\n"
+ "\t\t\t Transmit Margin: %s, EnterModifiedCompliance%c ComplianceSOS%c\n"
+ "\t\t\t Compliance De-emphasis: %s\n",
+ cap_express_link2_transmargin(PCI_EXP_LNKCTL2_MARGIN(w)),
+ FLAG(w, PCI_EXP_LNKCTL2_MOD_CMPLNC),
+ FLAG(w, PCI_EXP_LNKCTL2_CMPLNC_SOS),
+ cap_express_link2_deemphasis(PCI_EXP_LNKCTL2_COM_DEEMPHASIS(w)));
+ }
+
+ w = get_conf_word(d, where + PCI_EXP_LNKSTA2);
+ printf("\t\tLnkSta2: Current De-emphasis Level: %s, EqualizationComplete%c EqualizationPhase1%c\n"
+ "\t\t\t EqualizationPhase2%c EqualizationPhase3%c LinkEqualizationRequest%c\n"
+ "\t\t\t Retimer%c 2Retimers%c CrosslinkRes: %s",
+ cap_express_link2_deemphasis(PCI_EXP_LINKSTA2_DEEMPHASIS(w)),
+ FLAG(w, PCI_EXP_LINKSTA2_EQU_COMP),
+ FLAG(w, PCI_EXP_LINKSTA2_EQU_PHASE1),
+ FLAG(w, PCI_EXP_LINKSTA2_EQU_PHASE2),
+ FLAG(w, PCI_EXP_LINKSTA2_EQU_PHASE3),
+ FLAG(w, PCI_EXP_LINKSTA2_EQU_REQ),
+ FLAG(w, PCI_EXP_LINKSTA2_RETIMER),
+ FLAG(w, PCI_EXP_LINKSTA2_2RETIMERS),
+ cap_express_link2_crosslink_res(PCI_EXP_LINKSTA2_CROSSLINK(w)));
+
+ if (exp_downstream_port(type) && (l & PCI_EXP_LNKCAP2_DRS)) {
+ printf(", DRS%c\n"
+ "\t\t\t DownstreamComp: %s\n",
+ FLAG(w, PCI_EXP_LINKSTA2_DRS_RCVD),
+ cap_express_link2_component(PCI_EXP_LINKSTA2_COMPONENT(w)));
+ } else
+ printf("\n");
+}
+
+static void cap_express_slot2(struct device *d UNUSED, int where UNUSED)
+{
+ /* No capabilities that require this field in PCIe rev2.0 spec. */
+}
+
+static int
+cap_express(struct device *d, int where, int cap)
+{
+ int type = (cap & PCI_EXP_FLAGS_TYPE) >> 4;
+ int size;
+ int slot = 0;
+ int link = 1;
+
+ printf("Express ");
+ if (verbose >= 2)
+ printf("(v%d) ", cap & PCI_EXP_FLAGS_VERS);
+ switch (type)
+ {
+ case PCI_EXP_TYPE_ENDPOINT:
+ printf("Endpoint");
+ break;
+ case PCI_EXP_TYPE_LEG_END:
+ printf("Legacy Endpoint");
+ break;
+ case PCI_EXP_TYPE_ROOT_PORT:
+ slot = cap & PCI_EXP_FLAGS_SLOT;
+ printf("Root Port (Slot%c)", FLAG(cap, PCI_EXP_FLAGS_SLOT));
+ break;
+ case PCI_EXP_TYPE_UPSTREAM:
+ printf("Upstream Port");
+ break;
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ slot = cap & PCI_EXP_FLAGS_SLOT;
+ printf("Downstream Port (Slot%c)", FLAG(cap, PCI_EXP_FLAGS_SLOT));
+ break;
+ case PCI_EXP_TYPE_PCI_BRIDGE:
+ printf("PCI-Express to PCI/PCI-X Bridge");
+ break;
+ case PCI_EXP_TYPE_PCIE_BRIDGE:
+ slot = cap & PCI_EXP_FLAGS_SLOT;
+ printf("PCI/PCI-X to PCI-Express Bridge (Slot%c)",
+ FLAG(cap, PCI_EXP_FLAGS_SLOT));
+ break;
+ case PCI_EXP_TYPE_ROOT_INT_EP:
+ link = 0;
+ printf("Root Complex Integrated Endpoint");
+ break;
+ case PCI_EXP_TYPE_ROOT_EC:
+ link = 0;
+ printf("Root Complex Event Collector");
+ break;
+ default:
+ printf("Unknown type %d", type);
+ }
+ printf(", MSI %02x\n", (cap & PCI_EXP_FLAGS_IRQ) >> 9);
+ if (verbose < 2)
+ return type;
+
+ size = 16;
+ if (slot)
+ size = 24;
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_ROOT_EC)
+ size = 32;
+ if (!config_fetch(d, where + PCI_EXP_DEVCAP, size))
+ return type;
+
+ cap_express_dev(d, where, type);
+ if (link)
+ cap_express_link(d, where, type);
+ if (slot)
+ cap_express_slot(d, where);
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_ROOT_EC)
+ cap_express_root(d, where);
+
+ if ((cap & PCI_EXP_FLAGS_VERS) < 2)
+ return type;
+
+ size = 16;
+ if (slot)
+ size = 24;
+ if (!config_fetch(d, where + PCI_EXP_DEVCAP2, size))
+ return type;
+
+ cap_express_dev2(d, where, type);
+ if (link)
+ cap_express_link2(d, where, type);
+ if (slot)
+ cap_express_slot2(d, where);
+ return type;
+}
+
+static void
+cap_msix(struct device *d, int where, int cap)
+{
+ u32 off;
+
+ printf("MSI-X: Enable%c Count=%d Masked%c\n",
+ FLAG(cap, PCI_MSIX_ENABLE),
+ (cap & PCI_MSIX_TABSIZE) + 1,
+ FLAG(cap, PCI_MSIX_MASK));
+ if (verbose < 2 || !config_fetch(d, where + PCI_MSIX_TABLE, 8))
+ return;
+
+ off = get_conf_long(d, where + PCI_MSIX_TABLE);
+ printf("\t\tVector table: BAR=%d offset=%08x\n",
+ off & PCI_MSIX_BIR, off & ~PCI_MSIX_BIR);
+ off = get_conf_long(d, where + PCI_MSIX_PBA);
+ printf("\t\tPBA: BAR=%d offset=%08x\n",
+ off & PCI_MSIX_BIR, off & ~PCI_MSIX_BIR);
+}
+
+static void
+cap_slotid(int cap)
+{
+ int esr = cap & 0xff;
+ int chs = cap >> 8;
+
+ printf("Slot ID: %d slots, First%c, chassis %02x\n",
+ esr & PCI_SID_ESR_NSLOTS,
+ FLAG(esr, PCI_SID_ESR_FIC),
+ chs);
+}
+
+static void
+cap_ssvid(struct device *d, int where)
+{
+ u16 subsys_v, subsys_d;
+ char ssnamebuf[256];
+
+ if (!config_fetch(d, where, 8))
+ return;
+ subsys_v = get_conf_word(d, where + PCI_SSVID_VENDOR);
+ subsys_d = get_conf_word(d, where + PCI_SSVID_DEVICE);
+ printf("Subsystem: %s\n",
+ pci_lookup_name(pacc, ssnamebuf, sizeof(ssnamebuf),
+ PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
+ d->dev->vendor_id, d->dev->device_id, subsys_v, subsys_d));
+}
+
+static void
+cap_debug_port(int cap)
+{
+ int bar = cap >> 13;
+ int pos = cap & 0x1fff;
+ printf("Debug port: BAR=%d offset=%04x\n", bar, pos);
+}
+
+static void
+cap_af(struct device *d, int where)
+{
+ u8 reg;
+
+ printf("PCI Advanced Features\n");
+ if (verbose < 2 || !config_fetch(d, where + PCI_AF_CAP, 3))
+ return;
+
+ reg = get_conf_byte(d, where + PCI_AF_CAP);
+ printf("\t\tAFCap: TP%c FLR%c\n", FLAG(reg, PCI_AF_CAP_TP),
+ FLAG(reg, PCI_AF_CAP_FLR));
+ reg = get_conf_byte(d, where + PCI_AF_CTRL);
+ printf("\t\tAFCtrl: FLR%c\n", FLAG(reg, PCI_AF_CTRL_FLR));
+ reg = get_conf_byte(d, where + PCI_AF_STATUS);
+ printf("\t\tAFStatus: TP%c\n", FLAG(reg, PCI_AF_STATUS_TP));
+}
+
+static void
+cap_sata_hba(struct device *d, int where, int cap)
+{
+ u32 bars;
+ int bar;
+
+ printf("SATA HBA v%d.%d", BITS(cap, 4, 4), BITS(cap, 0, 4));
+ if (verbose < 2 || !config_fetch(d, where + PCI_SATA_HBA_BARS, 4))
+ {
+ printf("\n");
+ return;
+ }
+
+ bars = get_conf_long(d, where + PCI_SATA_HBA_BARS);
+ bar = BITS(bars, 0, 4);
+ if (bar >= 4 && bar <= 9)
+ printf(" BAR%d Offset=%08x\n", bar - 4, BITS(bars, 4, 20));
+ else if (bar == 15)
+ printf(" InCfgSpace\n");
+ else
+ printf(" BAR??%d\n", bar);
+}
+
+static const char *cap_ea_property(int p, int is_secondary)
+{
+ switch (p) {
+ case 0x00:
+ return "memory space, non-prefetchable";
+ case 0x01:
+ return "memory space, prefetchable";
+ case 0x02:
+ return "I/O space";
+ case 0x03:
+ return "VF memory space, prefetchable";
+ case 0x04:
+ return "VF memory space, non-prefetchable";
+ case 0x05:
+ return "allocation behind bridge, non-prefetchable memory";
+ case 0x06:
+ return "allocation behind bridge, prefetchable memory";
+ case 0x07:
+ return "allocation behind bridge, I/O space";
+ case 0xfd:
+ return "memory space resource unavailable for use";
+ case 0xfe:
+ return "I/O space resource unavailable for use";
+ case 0xff:
+ if (is_secondary)
+ return "entry unavailable for use, PrimaryProperties should be used";
+ else
+ return "entry unavailable for use";
+ default:
+ return NULL;
+ }
+}
+
+static void cap_ea(struct device *d, int where, int cap)
+{
+ int entry;
+ int entry_base = where + 4;
+ int num_entries = BITS(cap, 0, 6);
+ u8 htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
+
+ printf("Enhanced Allocation (EA): NumEntries=%u", num_entries);
+ if (htype == PCI_HEADER_TYPE_BRIDGE) {
+ byte fixed_sub, fixed_sec;
+
+ entry_base += 4;
+ if (!config_fetch(d, where + 4, 2)) {
+ printf("\n");
+ return;
+ }
+ fixed_sec = get_conf_byte(d, where + PCI_EA_CAP_TYPE1_SECONDARY);
+ fixed_sub = get_conf_byte(d, where + PCI_EA_CAP_TYPE1_SUBORDINATE);
+ printf(", secondary=%d, subordinate=%d", fixed_sec, fixed_sub);
+ }
+ printf("\n");
+ if (verbose < 2)
+ return;
+
+ for (entry = 0; entry < num_entries; entry++) {
+ int max_offset_high_pos, has_base_high, has_max_offset_high;
+ u32 entry_header;
+ u32 base, max_offset;
+ int es, bei, pp, sp;
+ const char *prop_text;
+
+ if (!config_fetch(d, entry_base, 4))
+ return;
+ entry_header = get_conf_long(d, entry_base);
+ es = BITS(entry_header, 0, 3);
+ bei = BITS(entry_header, 4, 4);
+ pp = BITS(entry_header, 8, 8);
+ sp = BITS(entry_header, 16, 8);
+ if (!config_fetch(d, entry_base + 4, es * 4))
+ return;
+ printf("\t\tEntry %u: Enable%c Writable%c EntrySize=%u\n", entry,
+ FLAG(entry_header, PCI_EA_CAP_ENT_ENABLE),
+ FLAG(entry_header, PCI_EA_CAP_ENT_WRITABLE), es);
+ printf("\t\t\t BAR Equivalent Indicator: ");
+ switch (bei) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ printf("BAR %u", bei);
+ break;
+ case 6:
+ printf("resource behind function");
+ break;
+ case 7:
+ printf("not indicated");
+ break;
+ case 8:
+ printf("expansion ROM");
+ break;
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ printf("VF-BAR %u", bei - 9);
+ break;
+ default:
+ printf("reserved");
+ break;
+ }
+ printf("\n");
+
+ prop_text = cap_ea_property(pp, 0);
+ printf("\t\t\t PrimaryProperties: ");
+ if (prop_text)
+ printf("%s\n", prop_text);
+ else
+ printf("[%02x]\n", pp);
+
+ prop_text = cap_ea_property(sp, 1);
+ printf("\t\t\t SecondaryProperties: ");
+ if (prop_text)
+ printf("%s\n", prop_text);
+ else
+ printf("[%02x]\n", sp);
+
+ base = get_conf_long(d, entry_base + 4);
+ has_base_high = ((base & 2) != 0);
+ base &= ~3;
+
+ max_offset = get_conf_long(d, entry_base + 8);
+ has_max_offset_high = ((max_offset & 2) != 0);
+ max_offset |= 3;
+ max_offset_high_pos = entry_base + 12;
+
+ printf("\t\t\t Base: ");
+ if (has_base_high) {
+ u32 base_high = get_conf_long(d, entry_base + 12);
+
+ printf("%x", base_high);
+ max_offset_high_pos += 4;
+ }
+ printf("%08x\n", base);
+
+ printf("\t\t\t MaxOffset: ");
+ if (has_max_offset_high) {
+ u32 max_offset_high = get_conf_long(d, max_offset_high_pos);
+
+ printf("%x", max_offset_high);
+ }
+ printf("%08x\n", max_offset);
+
+ entry_base += 4 + 4 * es;
+ }
+}
+
+void
+show_caps(struct device *d, int where)
+{
+ int can_have_ext_caps = 0;
+ int type = -1;
+
+ if (get_conf_word(d, PCI_STATUS) & PCI_STATUS_CAP_LIST)
+ {
+ byte been_there[256];
+ where = get_conf_byte(d, where) & ~3;
+ memset(been_there, 0, 256);
+ while (where)
+ {
+ int id, next, cap;
+ printf("\tCapabilities: ");
+ if (!config_fetch(d, where, 4))
+ {
+ puts("<access denied>");
+ break;
+ }
+ id = get_conf_byte(d, where + PCI_CAP_LIST_ID);
+ next = get_conf_byte(d, where + PCI_CAP_LIST_NEXT) & ~3;
+ cap = get_conf_word(d, where + PCI_CAP_FLAGS);
+ printf("[%02x] ", where);
+ if (been_there[where]++)
+ {
+ printf("<chain looped>\n");
+ break;
+ }
+ if (id == 0xff)
+ {
+ printf("<chain broken>\n");
+ break;
+ }
+ switch (id)
+ {
+ case PCI_CAP_ID_NULL:
+ printf("Null\n");
+ break;
+ case PCI_CAP_ID_PM:
+ cap_pm(d, where, cap);
+ break;
+ case PCI_CAP_ID_AGP:
+ cap_agp(d, where, cap);
+ break;
+ case PCI_CAP_ID_VPD:
+ cap_vpd(d);
+ break;
+ case PCI_CAP_ID_SLOTID:
+ cap_slotid(cap);
+ break;
+ case PCI_CAP_ID_MSI:
+ cap_msi(d, where, cap);
+ break;
+ case PCI_CAP_ID_CHSWP:
+ printf("CompactPCI hot-swap <?>\n");
+ break;
+ case PCI_CAP_ID_PCIX:
+ cap_pcix(d, where);
+ can_have_ext_caps = 1;
+ break;
+ case PCI_CAP_ID_HT:
+ cap_ht(d, where, cap);
+ break;
+ case PCI_CAP_ID_VNDR:
+ show_vendor_caps(d, where, cap);
+ break;
+ case PCI_CAP_ID_DBG:
+ cap_debug_port(cap);
+ break;
+ case PCI_CAP_ID_CCRC:
+ printf("CompactPCI central resource control <?>\n");
+ break;
+ case PCI_CAP_ID_HOTPLUG:
+ printf("Hot-plug capable\n");
+ break;
+ case PCI_CAP_ID_SSVID:
+ cap_ssvid(d, where);
+ break;
+ case PCI_CAP_ID_AGP3:
+ printf("AGP3 <?>\n");
+ break;
+ case PCI_CAP_ID_SECURE:
+ printf("Secure device <?>\n");
+ break;
+ case PCI_CAP_ID_EXP:
+ type = cap_express(d, where, cap);
+ can_have_ext_caps = 1;
+ break;
+ case PCI_CAP_ID_MSIX:
+ cap_msix(d, where, cap);
+ break;
+ case PCI_CAP_ID_SATA:
+ cap_sata_hba(d, where, cap);
+ break;
+ case PCI_CAP_ID_AF:
+ cap_af(d, where);
+ break;
+ case PCI_CAP_ID_EA:
+ cap_ea(d, where, cap);
+ break;
+ default:
+ printf("Capability ID %#02x [%04x]\n", id, cap);
+ }
+ where = next;
+ }
+ }
+ if (can_have_ext_caps)
+ show_ext_caps(d, type);
+}
diff --git a/ls-ecaps.c b/ls-ecaps.c
new file mode 100644
index 0000000..e71209e
--- /dev/null
+++ b/ls-ecaps.c
@@ -0,0 +1,1093 @@
+/*
+ * The PCI Utilities -- Show Extended Capabilities
+ *
+ * Copyright (c) 1997--2020 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lspci.h"
+
+static void
+cap_tph(struct device *d, int where)
+{
+ u32 tph_cap;
+ printf("Transaction Processing Hints\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_TPH_CAPABILITIES, 4))
+ return;
+
+ tph_cap = get_conf_long(d, where + PCI_TPH_CAPABILITIES);
+
+ if (tph_cap & PCI_TPH_INTVEC_SUP)
+ printf("\t\tInterrupt vector mode supported\n");
+ if (tph_cap & PCI_TPH_DEV_SUP)
+ printf("\t\tDevice specific mode supported\n");
+ if (tph_cap & PCI_TPH_EXT_REQ_SUP)
+ printf("\t\tExtended requester support\n");
+
+ switch (tph_cap & PCI_TPH_ST_LOC_MASK) {
+ case PCI_TPH_ST_NONE:
+ printf("\t\tNo steering table available\n");
+ break;
+ case PCI_TPH_ST_CAP:
+ printf("\t\tSteering table in TPH capability structure\n");
+ break;
+ case PCI_TPH_ST_MSIX:
+ printf("\t\tSteering table in MSI-X table\n");
+ break;
+ default:
+ printf("\t\tReserved steering table location\n");
+ break;
+ }
+}
+
+static u32
+cap_ltr_scale(u8 scale)
+{
+ return 1 << (scale * 5);
+}
+
+static void
+cap_ltr(struct device *d, int where)
+{
+ u32 scale;
+ u16 snoop, nosnoop;
+ printf("Latency Tolerance Reporting\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_LTR_MAX_SNOOP, 4))
+ return;
+
+ snoop = get_conf_word(d, where + PCI_LTR_MAX_SNOOP);
+ scale = cap_ltr_scale((snoop >> PCI_LTR_SCALE_SHIFT) & PCI_LTR_SCALE_MASK);
+ printf("\t\tMax snoop latency: %lldns\n",
+ ((unsigned long long)snoop & PCI_LTR_VALUE_MASK) * scale);
+
+ nosnoop = get_conf_word(d, where + PCI_LTR_MAX_NOSNOOP);
+ scale = cap_ltr_scale((nosnoop >> PCI_LTR_SCALE_SHIFT) & PCI_LTR_SCALE_MASK);
+ printf("\t\tMax no snoop latency: %lldns\n",
+ ((unsigned long long)nosnoop & PCI_LTR_VALUE_MASK) * scale);
+}
+
+static void
+cap_sec(struct device *d, int where)
+{
+ u32 ctrl3, lane_err_stat;
+ u8 lane;
+ printf("Secondary PCI Express\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_SEC_LNKCTL3, 12))
+ return;
+
+ ctrl3 = get_conf_word(d, where + PCI_SEC_LNKCTL3);
+ printf("\t\tLnkCtl3: LnkEquIntrruptEn%c PerformEqu%c\n",
+ FLAG(ctrl3, PCI_SEC_LNKCTL3_LNK_EQU_REQ_INTR_EN),
+ FLAG(ctrl3, PCI_SEC_LNKCTL3_PERFORM_LINK_EQU));
+
+ lane_err_stat = get_conf_word(d, where + PCI_SEC_LANE_ERR);
+ printf("\t\tLaneErrStat: ");
+ if (lane_err_stat)
+ {
+ printf("LaneErr at lane:");
+ for (lane = 0; lane_err_stat; lane_err_stat >>= 1, lane += 1)
+ if (BITS(lane_err_stat, 0, 1))
+ printf(" %u", lane);
+ }
+ else
+ printf("0");
+ printf("\n");
+}
+
+static void
+cap_dsn(struct device *d, int where)
+{
+ u32 t1, t2;
+ if (!config_fetch(d, where + 4, 8))
+ return;
+ t1 = get_conf_long(d, where + 4);
+ t2 = get_conf_long(d, where + 8);
+ printf("Device Serial Number %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n",
+ t2 >> 24, (t2 >> 16) & 0xff, (t2 >> 8) & 0xff, t2 & 0xff,
+ t1 >> 24, (t1 >> 16) & 0xff, (t1 >> 8) & 0xff, t1 & 0xff);
+}
+
+static void
+cap_aer(struct device *d, int where, int type)
+{
+ u32 l, l0, l1, l2, l3;
+ u16 w;
+
+ printf("Advanced Error Reporting\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_ERR_UNCOR_STATUS, 40))
+ return;
+
+ l = get_conf_long(d, where + PCI_ERR_UNCOR_STATUS);
+ printf("\t\tUESta:\tDLP%c SDES%c TLP%c FCP%c CmpltTO%c CmpltAbrt%c UnxCmplt%c RxOF%c "
+ "MalfTLP%c ECRC%c UnsupReq%c ACSViol%c\n",
+ FLAG(l, PCI_ERR_UNC_DLP), FLAG(l, PCI_ERR_UNC_SDES), FLAG(l, PCI_ERR_UNC_POISON_TLP),
+ FLAG(l, PCI_ERR_UNC_FCP), FLAG(l, PCI_ERR_UNC_COMP_TIME), FLAG(l, PCI_ERR_UNC_COMP_ABORT),
+ FLAG(l, PCI_ERR_UNC_UNX_COMP), FLAG(l, PCI_ERR_UNC_RX_OVER), FLAG(l, PCI_ERR_UNC_MALF_TLP),
+ FLAG(l, PCI_ERR_UNC_ECRC), FLAG(l, PCI_ERR_UNC_UNSUP), FLAG(l, PCI_ERR_UNC_ACS_VIOL));
+ l = get_conf_long(d, where + PCI_ERR_UNCOR_MASK);
+ printf("\t\tUEMsk:\tDLP%c SDES%c TLP%c FCP%c CmpltTO%c CmpltAbrt%c UnxCmplt%c RxOF%c "
+ "MalfTLP%c ECRC%c UnsupReq%c ACSViol%c\n",
+ FLAG(l, PCI_ERR_UNC_DLP), FLAG(l, PCI_ERR_UNC_SDES), FLAG(l, PCI_ERR_UNC_POISON_TLP),
+ FLAG(l, PCI_ERR_UNC_FCP), FLAG(l, PCI_ERR_UNC_COMP_TIME), FLAG(l, PCI_ERR_UNC_COMP_ABORT),
+ FLAG(l, PCI_ERR_UNC_UNX_COMP), FLAG(l, PCI_ERR_UNC_RX_OVER), FLAG(l, PCI_ERR_UNC_MALF_TLP),
+ FLAG(l, PCI_ERR_UNC_ECRC), FLAG(l, PCI_ERR_UNC_UNSUP), FLAG(l, PCI_ERR_UNC_ACS_VIOL));
+ l = get_conf_long(d, where + PCI_ERR_UNCOR_SEVER);
+ printf("\t\tUESvrt:\tDLP%c SDES%c TLP%c FCP%c CmpltTO%c CmpltAbrt%c UnxCmplt%c RxOF%c "
+ "MalfTLP%c ECRC%c UnsupReq%c ACSViol%c\n",
+ FLAG(l, PCI_ERR_UNC_DLP), FLAG(l, PCI_ERR_UNC_SDES), FLAG(l, PCI_ERR_UNC_POISON_TLP),
+ FLAG(l, PCI_ERR_UNC_FCP), FLAG(l, PCI_ERR_UNC_COMP_TIME), FLAG(l, PCI_ERR_UNC_COMP_ABORT),
+ FLAG(l, PCI_ERR_UNC_UNX_COMP), FLAG(l, PCI_ERR_UNC_RX_OVER), FLAG(l, PCI_ERR_UNC_MALF_TLP),
+ FLAG(l, PCI_ERR_UNC_ECRC), FLAG(l, PCI_ERR_UNC_UNSUP), FLAG(l, PCI_ERR_UNC_ACS_VIOL));
+ l = get_conf_long(d, where + PCI_ERR_COR_STATUS);
+ printf("\t\tCESta:\tRxErr%c BadTLP%c BadDLLP%c Rollover%c Timeout%c AdvNonFatalErr%c\n",
+ FLAG(l, PCI_ERR_COR_RCVR), FLAG(l, PCI_ERR_COR_BAD_TLP), FLAG(l, PCI_ERR_COR_BAD_DLLP),
+ FLAG(l, PCI_ERR_COR_REP_ROLL), FLAG(l, PCI_ERR_COR_REP_TIMER), FLAG(l, PCI_ERR_COR_REP_ANFE));
+ l = get_conf_long(d, where + PCI_ERR_COR_MASK);
+ printf("\t\tCEMsk:\tRxErr%c BadTLP%c BadDLLP%c Rollover%c Timeout%c AdvNonFatalErr%c\n",
+ FLAG(l, PCI_ERR_COR_RCVR), FLAG(l, PCI_ERR_COR_BAD_TLP), FLAG(l, PCI_ERR_COR_BAD_DLLP),
+ FLAG(l, PCI_ERR_COR_REP_ROLL), FLAG(l, PCI_ERR_COR_REP_TIMER), FLAG(l, PCI_ERR_COR_REP_ANFE));
+ l = get_conf_long(d, where + PCI_ERR_CAP);
+ printf("\t\tAERCap:\tFirst Error Pointer: %02x, ECRCGenCap%c ECRCGenEn%c ECRCChkCap%c ECRCChkEn%c\n"
+ "\t\t\tMultHdrRecCap%c MultHdrRecEn%c TLPPfxPres%c HdrLogCap%c\n",
+ PCI_ERR_CAP_FEP(l), FLAG(l, PCI_ERR_CAP_ECRC_GENC), FLAG(l, PCI_ERR_CAP_ECRC_GENE),
+ FLAG(l, PCI_ERR_CAP_ECRC_CHKC), FLAG(l, PCI_ERR_CAP_ECRC_CHKE),
+ FLAG(l, PCI_ERR_CAP_MULT_HDRC), FLAG(l, PCI_ERR_CAP_MULT_HDRE),
+ FLAG(l, PCI_ERR_CAP_TLP_PFX), FLAG(l, PCI_ERR_CAP_HDR_LOG));
+
+ l0 = get_conf_long(d, where + PCI_ERR_HEADER_LOG);
+ l1 = get_conf_long(d, where + PCI_ERR_HEADER_LOG + 4);
+ l2 = get_conf_long(d, where + PCI_ERR_HEADER_LOG + 8);
+ l3 = get_conf_long(d, where + PCI_ERR_HEADER_LOG + 12);
+ printf("\t\tHeaderLog: %08x %08x %08x %08x\n", l0, l1, l2, l3);
+
+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_ROOT_EC)
+ {
+ if (!config_fetch(d, where + PCI_ERR_ROOT_COMMAND, 12))
+ return;
+
+ l = get_conf_long(d, where + PCI_ERR_ROOT_COMMAND);
+ printf("\t\tRootCmd: CERptEn%c NFERptEn%c FERptEn%c\n",
+ FLAG(l, PCI_ERR_ROOT_CMD_COR_EN),
+ FLAG(l, PCI_ERR_ROOT_CMD_NONFATAL_EN),
+ FLAG(l, PCI_ERR_ROOT_CMD_FATAL_EN));
+
+ l = get_conf_long(d, where + PCI_ERR_ROOT_STATUS);
+ printf("\t\tRootSta: CERcvd%c MultCERcvd%c UERcvd%c MultUERcvd%c\n"
+ "\t\t\t FirstFatal%c NonFatalMsg%c FatalMsg%c IntMsg %d\n",
+ FLAG(l, PCI_ERR_ROOT_COR_RCV),
+ FLAG(l, PCI_ERR_ROOT_MULTI_COR_RCV),
+ FLAG(l, PCI_ERR_ROOT_UNCOR_RCV),
+ FLAG(l, PCI_ERR_ROOT_MULTI_UNCOR_RCV),
+ FLAG(l, PCI_ERR_ROOT_FIRST_FATAL),
+ FLAG(l, PCI_ERR_ROOT_NONFATAL_RCV),
+ FLAG(l, PCI_ERR_ROOT_FATAL_RCV),
+ PCI_ERR_MSG_NUM(l));
+
+ w = get_conf_word(d, where + PCI_ERR_ROOT_COR_SRC);
+ printf("\t\tErrorSrc: ERR_COR: %04x ", w);
+
+ w = get_conf_word(d, where + PCI_ERR_ROOT_SRC);
+ printf("ERR_FATAL/NONFATAL: %04x\n", w);
+ }
+}
+
+static void cap_dpc(struct device *d, int where)
+{
+ u16 l;
+
+ printf("Downstream Port Containment\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_DPC_CAP, 8))
+ return;
+
+ l = get_conf_word(d, where + PCI_DPC_CAP);
+ printf("\t\tDpcCap:\tINT Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n",
+ PCI_DPC_CAP_INT_MSG(l), FLAG(l, PCI_DPC_CAP_RP_EXT), FLAG(l, PCI_DPC_CAP_TLP_BLOCK),
+ FLAG(l, PCI_DPC_CAP_SW_TRIGGER), PCI_DPC_CAP_RP_LOG(l), FLAG(l, PCI_DPC_CAP_DL_ACT_ERR));
+
+ l = get_conf_word(d, where + PCI_DPC_CTL);
+ printf("\t\tDpcCtl:\tTrigger:%x Cmpl%c INT%c ErrCor%c PoisonedTLP%c SwTrigger%c DL_ActiveErr%c\n",
+ PCI_DPC_CTL_TRIGGER(l), FLAG(l, PCI_DPC_CTL_CMPL), FLAG(l, PCI_DPC_CTL_INT),
+ FLAG(l, PCI_DPC_CTL_ERR_COR), FLAG(l, PCI_DPC_CTL_TLP), FLAG(l, PCI_DPC_CTL_SW_TRIGGER),
+ FLAG(l, PCI_DPC_CTL_DL_ACTIVE));
+
+ l = get_conf_word(d, where + PCI_DPC_STATUS);
+ printf("\t\tDpcSta:\tTrigger%c Reason:%02x INT%c RPBusy%c TriggerExt:%02x RP PIO ErrPtr:%02x\n",
+ FLAG(l, PCI_DPC_STS_TRIGGER), PCI_DPC_STS_REASON(l), FLAG(l, PCI_DPC_STS_INT),
+ FLAG(l, PCI_DPC_STS_RP_BUSY), PCI_DPC_STS_TRIGGER_EXT(l), PCI_DPC_STS_PIO_FEP(l));
+
+ l = get_conf_word(d, where + PCI_DPC_SOURCE);
+ printf("\t\tSource:\t%04x\n", l);
+}
+
+static void
+cap_acs(struct device *d, int where)
+{
+ u16 w;
+
+ printf("Access Control Services\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_ACS_CAP, 4))
+ return;
+
+ w = get_conf_word(d, where + PCI_ACS_CAP);
+ printf("\t\tACSCap:\tSrcValid%c TransBlk%c ReqRedir%c CmpltRedir%c UpstreamFwd%c EgressCtrl%c "
+ "DirectTrans%c\n",
+ FLAG(w, PCI_ACS_CAP_VALID), FLAG(w, PCI_ACS_CAP_BLOCK), FLAG(w, PCI_ACS_CAP_REQ_RED),
+ FLAG(w, PCI_ACS_CAP_CMPLT_RED), FLAG(w, PCI_ACS_CAP_FORWARD), FLAG(w, PCI_ACS_CAP_EGRESS),
+ FLAG(w, PCI_ACS_CAP_TRANS));
+ w = get_conf_word(d, where + PCI_ACS_CTRL);
+ printf("\t\tACSCtl:\tSrcValid%c TransBlk%c ReqRedir%c CmpltRedir%c UpstreamFwd%c EgressCtrl%c "
+ "DirectTrans%c\n",
+ FLAG(w, PCI_ACS_CTRL_VALID), FLAG(w, PCI_ACS_CTRL_BLOCK), FLAG(w, PCI_ACS_CTRL_REQ_RED),
+ FLAG(w, PCI_ACS_CTRL_CMPLT_RED), FLAG(w, PCI_ACS_CTRL_FORWARD), FLAG(w, PCI_ACS_CTRL_EGRESS),
+ FLAG(w, PCI_ACS_CTRL_TRANS));
+}
+
+static void
+cap_ari(struct device *d, int where)
+{
+ u16 w;
+
+ printf("Alternative Routing-ID Interpretation (ARI)\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_ARI_CAP, 4))
+ return;
+
+ w = get_conf_word(d, where + PCI_ARI_CAP);
+ printf("\t\tARICap:\tMFVC%c ACS%c, Next Function: %d\n",
+ FLAG(w, PCI_ARI_CAP_MFVC), FLAG(w, PCI_ARI_CAP_ACS),
+ PCI_ARI_CAP_NFN(w));
+ w = get_conf_word(d, where + PCI_ARI_CTRL);
+ printf("\t\tARICtl:\tMFVC%c ACS%c, Function Group: %d\n",
+ FLAG(w, PCI_ARI_CTRL_MFVC), FLAG(w, PCI_ARI_CTRL_ACS),
+ PCI_ARI_CTRL_FG(w));
+}
+
+static void
+cap_ats(struct device *d, int where)
+{
+ u16 w;
+
+ printf("Address Translation Service (ATS)\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_ATS_CAP, 4))
+ return;
+
+ w = get_conf_word(d, where + PCI_ATS_CAP);
+ printf("\t\tATSCap:\tInvalidate Queue Depth: %02x\n", PCI_ATS_CAP_IQD(w));
+ w = get_conf_word(d, where + PCI_ATS_CTRL);
+ printf("\t\tATSCtl:\tEnable%c, Smallest Translation Unit: %02x\n",
+ FLAG(w, PCI_ATS_CTRL_ENABLE), PCI_ATS_CTRL_STU(w));
+}
+
+static void
+cap_pri(struct device *d, int where)
+{
+ u16 w;
+ u32 l;
+
+ printf("Page Request Interface (PRI)\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_PRI_CTRL, 0xc))
+ return;
+
+ w = get_conf_word(d, where + PCI_PRI_CTRL);
+ printf("\t\tPRICtl: Enable%c Reset%c\n",
+ FLAG(w, PCI_PRI_CTRL_ENABLE), FLAG(w, PCI_PRI_CTRL_RESET));
+ w = get_conf_word(d, where + PCI_PRI_STATUS);
+ printf("\t\tPRISta: RF%c UPRGI%c Stopped%c\n",
+ FLAG(w, PCI_PRI_STATUS_RF), FLAG(w, PCI_PRI_STATUS_UPRGI),
+ FLAG(w, PCI_PRI_STATUS_STOPPED));
+ l = get_conf_long(d, where + PCI_PRI_MAX_REQ);
+ printf("\t\tPage Request Capacity: %08x, ", l);
+ l = get_conf_long(d, where + PCI_PRI_ALLOC_REQ);
+ printf("Page Request Allocation: %08x\n", l);
+}
+
+static void
+cap_pasid(struct device *d, int where)
+{
+ u16 w;
+
+ printf("Process Address Space ID (PASID)\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_PASID_CAP, 4))
+ return;
+
+ w = get_conf_word(d, where + PCI_PASID_CAP);
+ printf("\t\tPASIDCap: Exec%c Priv%c, Max PASID Width: %02x\n",
+ FLAG(w, PCI_PASID_CAP_EXEC), FLAG(w, PCI_PASID_CAP_PRIV),
+ PCI_PASID_CAP_WIDTH(w));
+ w = get_conf_word(d, where + PCI_PASID_CTRL);
+ printf("\t\tPASIDCtl: Enable%c Exec%c Priv%c\n",
+ FLAG(w, PCI_PASID_CTRL_ENABLE), FLAG(w, PCI_PASID_CTRL_EXEC),
+ FLAG(w, PCI_PASID_CTRL_PRIV));
+}
+
+static void
+cap_sriov(struct device *d, int where)
+{
+ u16 b;
+ u16 w;
+ u32 l;
+ int i;
+
+ printf("Single Root I/O Virtualization (SR-IOV)\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_IOV_CAP, 0x3c))
+ return;
+
+ l = get_conf_long(d, where + PCI_IOV_CAP);
+ printf("\t\tIOVCap:\tMigration%c, Interrupt Message Number: %03x\n",
+ FLAG(l, PCI_IOV_CAP_VFM), PCI_IOV_CAP_IMN(l));
+ w = get_conf_word(d, where + PCI_IOV_CTRL);
+ printf("\t\tIOVCtl:\tEnable%c Migration%c Interrupt%c MSE%c ARIHierarchy%c\n",
+ FLAG(w, PCI_IOV_CTRL_VFE), FLAG(w, PCI_IOV_CTRL_VFME),
+ FLAG(w, PCI_IOV_CTRL_VFMIE), FLAG(w, PCI_IOV_CTRL_MSE),
+ FLAG(w, PCI_IOV_CTRL_ARI));
+ w = get_conf_word(d, where + PCI_IOV_STATUS);
+ printf("\t\tIOVSta:\tMigration%c\n", FLAG(w, PCI_IOV_STATUS_MS));
+ w = get_conf_word(d, where + PCI_IOV_INITIALVF);
+ printf("\t\tInitial VFs: %d, ", w);
+ w = get_conf_word(d, where + PCI_IOV_TOTALVF);
+ printf("Total VFs: %d, ", w);
+ w = get_conf_word(d, where + PCI_IOV_NUMVF);
+ printf("Number of VFs: %d, ", w);
+ b = get_conf_byte(d, where + PCI_IOV_FDL);
+ printf("Function Dependency Link: %02x\n", b);
+ w = get_conf_word(d, where + PCI_IOV_OFFSET);
+ printf("\t\tVF offset: %d, ", w);
+ w = get_conf_word(d, where + PCI_IOV_STRIDE);
+ printf("stride: %d, ", w);
+ w = get_conf_word(d, where + PCI_IOV_DID);
+ printf("Device ID: %04x\n", w);
+ l = get_conf_long(d, where + PCI_IOV_SUPPS);
+ printf("\t\tSupported Page Size: %08x, ", l);
+ l = get_conf_long(d, where + PCI_IOV_SYSPS);
+ printf("System Page Size: %08x\n", l);
+
+ for (i=0; i < PCI_IOV_NUM_BAR; i++)
+ {
+ u32 addr;
+ int type;
+ u32 h;
+ l = get_conf_long(d, where + PCI_IOV_BAR_BASE + 4*i);
+ if (l == 0xffffffff)
+ l = 0;
+ if (!l)
+ continue;
+ printf("\t\tRegion %d: Memory at ", i);
+ addr = l & PCI_ADDR_MEM_MASK;
+ type = l & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+ if (type == PCI_BASE_ADDRESS_MEM_TYPE_64)
+ {
+ i++;
+ h = get_conf_long(d, where + PCI_IOV_BAR_BASE + (i*4));
+ printf("%08x", h);
+ }
+ printf("%08x (%s-bit, %sprefetchable)\n",
+ addr,
+ (type == PCI_BASE_ADDRESS_MEM_TYPE_32) ? "32" : "64",
+ (l & PCI_BASE_ADDRESS_MEM_PREFETCH) ? "" : "non-");
+ }
+
+ l = get_conf_long(d, where + PCI_IOV_MSAO);
+ printf("\t\tVF Migration: offset: %08x, BIR: %x\n", PCI_IOV_MSA_OFFSET(l),
+ PCI_IOV_MSA_BIR(l));
+}
+
+static void
+cap_multicast(struct device *d, int where, int type)
+{
+ u16 w;
+ u32 l;
+ u64 bar, rcv, block;
+
+ printf("Multicast\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_MCAST_CAP, 0x30))
+ return;
+
+ w = get_conf_word(d, where + PCI_MCAST_CAP);
+ printf("\t\tMcastCap: MaxGroups %d", PCI_MCAST_CAP_MAX_GROUP(w) + 1);
+ if (type == PCI_EXP_TYPE_ENDPOINT || type == PCI_EXP_TYPE_ROOT_INT_EP)
+ printf(", WindowSz %d (%d bytes)",
+ PCI_MCAST_CAP_WIN_SIZE(w), 1 << PCI_MCAST_CAP_WIN_SIZE(w));
+ if (type == PCI_EXP_TYPE_ROOT_PORT ||
+ type == PCI_EXP_TYPE_UPSTREAM || type == PCI_EXP_TYPE_DOWNSTREAM)
+ printf(", ECRCRegen%c\n", FLAG(w, PCI_MCAST_CAP_ECRC));
+ w = get_conf_word(d, where + PCI_MCAST_CTRL);
+ printf("\t\tMcastCtl: NumGroups %d, Enable%c\n",
+ PCI_MCAST_CTRL_NUM_GROUP(w) + 1, FLAG(w, PCI_MCAST_CTRL_ENABLE));
+ bar = get_conf_long(d, where + PCI_MCAST_BAR);
+ l = get_conf_long(d, where + PCI_MCAST_BAR + 4);
+ bar |= (u64) l << 32;
+ printf("\t\tMcastBAR: IndexPos %d, BaseAddr %016" PCI_U64_FMT_X "\n",
+ PCI_MCAST_BAR_INDEX_POS(bar), bar & PCI_MCAST_BAR_MASK);
+ rcv = get_conf_long(d, where + PCI_MCAST_RCV);
+ l = get_conf_long(d, where + PCI_MCAST_RCV + 4);
+ rcv |= (u64) l << 32;
+ printf("\t\tMcastReceiveVec: %016" PCI_U64_FMT_X "\n", rcv);
+ block = get_conf_long(d, where + PCI_MCAST_BLOCK);
+ l = get_conf_long(d, where + PCI_MCAST_BLOCK + 4);
+ block |= (u64) l << 32;
+ printf("\t\tMcastBlockAllVec: %016" PCI_U64_FMT_X "\n", block);
+ block = get_conf_long(d, where + PCI_MCAST_BLOCK_UNTRANS);
+ l = get_conf_long(d, where + PCI_MCAST_BLOCK_UNTRANS + 4);
+ block |= (u64) l << 32;
+ printf("\t\tMcastBlockUntransVec: %016" PCI_U64_FMT_X "\n", block);
+
+ if (type == PCI_EXP_TYPE_ENDPOINT || type == PCI_EXP_TYPE_ROOT_INT_EP)
+ return;
+ bar = get_conf_long(d, where + PCI_MCAST_OVL_BAR);
+ l = get_conf_long(d, where + PCI_MCAST_OVL_BAR + 4);
+ bar |= (u64) l << 32;
+ printf("\t\tMcastOverlayBAR: OverlaySize %d ", PCI_MCAST_OVL_SIZE(bar));
+ if (PCI_MCAST_OVL_SIZE(bar) >= 6)
+ printf("(%d bytes)", 1 << PCI_MCAST_OVL_SIZE(bar));
+ else
+ printf("(disabled)");
+ printf(", BaseAddr %016" PCI_U64_FMT_X "\n", bar & PCI_MCAST_OVL_MASK);
+}
+
+static void
+cap_vc(struct device *d, int where)
+{
+ u32 cr1, cr2;
+ u16 ctrl, status;
+ int evc_cnt;
+ int arb_table_pos;
+ int i, j;
+ static const char ref_clocks[][6] = { "100ns" };
+ static const char arb_selects[8][7] = { "Fixed", "WRR32", "WRR64", "WRR128", "??4", "??5", "??6", "??7" };
+ static const char vc_arb_selects[8][8] = { "Fixed", "WRR32", "WRR64", "WRR128", "TWRR128", "WRR256", "??6", "??7" };
+ char buf[8];
+
+ printf("Virtual Channel\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + 4, 0x1c - 4))
+ return;
+
+ cr1 = get_conf_long(d, where + PCI_VC_PORT_REG1);
+ cr2 = get_conf_long(d, where + PCI_VC_PORT_REG2);
+ ctrl = get_conf_word(d, where + PCI_VC_PORT_CTRL);
+ status = get_conf_word(d, where + PCI_VC_PORT_STATUS);
+
+ evc_cnt = BITS(cr1, 0, 3);
+ printf("\t\tCaps:\tLPEVC=%d RefClk=%s PATEntryBits=%d\n",
+ BITS(cr1, 4, 3),
+ TABLE(ref_clocks, BITS(cr1, 8, 2), buf),
+ 1 << BITS(cr1, 10, 2));
+
+ printf("\t\tArb:");
+ for (i=0; i<8; i++)
+ if (arb_selects[i][0] != '?' || cr2 & (1 << i))
+ printf("%c%s%c", (i ? ' ' : '\t'), arb_selects[i], FLAG(cr2, 1 << i));
+ arb_table_pos = BITS(cr2, 24, 8);
+
+ printf("\n\t\tCtrl:\tArbSelect=%s\n", TABLE(arb_selects, BITS(ctrl, 1, 3), buf));
+ printf("\t\tStatus:\tInProgress%c\n", FLAG(status, 1));
+
+ if (arb_table_pos)
+ {
+ arb_table_pos = where + 16*arb_table_pos;
+ printf("\t\tPort Arbitration Table [%x] <?>\n", arb_table_pos);
+ }
+
+ for (i=0; i<=evc_cnt; i++)
+ {
+ int pos = where + PCI_VC_RES_CAP + 12*i;
+ u32 rcap, rctrl;
+ u16 rstatus;
+ int pat_pos;
+
+ printf("\t\tVC%d:\t", i);
+ if (!config_fetch(d, pos, 12))
+ {
+ printf("<unreadable>\n");
+ continue;
+ }
+ rcap = get_conf_long(d, pos);
+ rctrl = get_conf_long(d, pos+4);
+ rstatus = get_conf_word(d, pos+10);
+
+ pat_pos = BITS(rcap, 24, 8);
+ printf("Caps:\tPATOffset=%02x MaxTimeSlots=%d RejSnoopTrans%c\n",
+ pat_pos,
+ BITS(rcap, 16, 6) + 1,
+ FLAG(rcap, 1 << 15));
+
+ printf("\t\t\tArb:");
+ for (j=0; j<8; j++)
+ if (vc_arb_selects[j][0] != '?' || rcap & (1 << j))
+ printf("%c%s%c", (j ? ' ' : '\t'), vc_arb_selects[j], FLAG(rcap, 1 << j));
+
+ printf("\n\t\t\tCtrl:\tEnable%c ID=%d ArbSelect=%s TC/VC=%02x\n",
+ FLAG(rctrl, 1 << 31),
+ BITS(rctrl, 24, 3),
+ TABLE(vc_arb_selects, BITS(rctrl, 17, 3), buf),
+ BITS(rctrl, 0, 8));
+
+ printf("\t\t\tStatus:\tNegoPending%c InProgress%c\n",
+ FLAG(rstatus, 2),
+ FLAG(rstatus, 1));
+
+ if (pat_pos)
+ printf("\t\t\tPort Arbitration Table <?>\n");
+ }
+}
+
+static void
+cap_rclink(struct device *d, int where)
+{
+ u32 esd;
+ int num_links;
+ int i;
+ static const char elt_types[][9] = { "Config", "Egress", "Internal" };
+ char buf[8];
+
+ printf("Root Complex Link\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + 4, PCI_RCLINK_LINK1 - 4))
+ return;
+
+ esd = get_conf_long(d, where + PCI_RCLINK_ESD);
+ num_links = BITS(esd, 8, 8);
+ printf("\t\tDesc:\tPortNumber=%02x ComponentID=%02x EltType=%s\n",
+ BITS(esd, 24, 8),
+ BITS(esd, 16, 8),
+ TABLE(elt_types, BITS(esd, 0, 8), buf));
+
+ for (i=0; i<num_links; i++)
+ {
+ int pos = where + PCI_RCLINK_LINK1 + i*PCI_RCLINK_LINK_SIZE;
+ u32 desc;
+ u32 addr_lo, addr_hi;
+
+ printf("\t\tLink%d:\t", i);
+ if (!config_fetch(d, pos, PCI_RCLINK_LINK_SIZE))
+ {
+ printf("<unreadable>\n");
+ return;
+ }
+ desc = get_conf_long(d, pos + PCI_RCLINK_LINK_DESC);
+ addr_lo = get_conf_long(d, pos + PCI_RCLINK_LINK_ADDR);
+ addr_hi = get_conf_long(d, pos + PCI_RCLINK_LINK_ADDR + 4);
+
+ printf("Desc:\tTargetPort=%02x TargetComponent=%02x AssocRCRB%c LinkType=%s LinkValid%c\n",
+ BITS(desc, 24, 8),
+ BITS(desc, 16, 8),
+ FLAG(desc, 4),
+ ((desc & 2) ? "Config" : "MemMapped"),
+ FLAG(desc, 1));
+
+ if (desc & 2)
+ {
+ int n = addr_lo & 7;
+ if (!n)
+ n = 8;
+ printf("\t\t\tAddr:\t%02x:%02x.%d CfgSpace=%08x%08x\n",
+ BITS(addr_lo, 20, n),
+ BITS(addr_lo, 15, 5),
+ BITS(addr_lo, 12, 3),
+ addr_hi, addr_lo);
+ }
+ else
+ printf("\t\t\tAddr:\t%08x%08x\n", addr_hi, addr_lo);
+ }
+}
+
+static void
+cap_dvsec_cxl(struct device *d, int where)
+{
+ u16 l;
+
+ printf(": CXL\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_CXL_CAP, 12))
+ return;
+
+ l = get_conf_word(d, where + PCI_CXL_CAP);
+ printf("\t\tCXLCap:\tCache%c IO%c Mem%c Mem HW Init%c HDMCount %d Viral%c\n",
+ FLAG(l, PCI_CXL_CAP_CACHE), FLAG(l, PCI_CXL_CAP_IO), FLAG(l, PCI_CXL_CAP_MEM),
+ FLAG(l, PCI_CXL_CAP_MEM_HWINIT), PCI_CXL_CAP_HDM_CNT(l), FLAG(l, PCI_CXL_CAP_VIRAL));
+
+ l = get_conf_word(d, where + PCI_CXL_CTRL);
+ printf("\t\tCXLCtl:\tCache%c IO%c Mem%c Cache SF Cov %d Cache SF Gran %d Cache Clean%c Viral%c\n",
+ FLAG(l, PCI_CXL_CTRL_CACHE), FLAG(l, PCI_CXL_CTRL_IO), FLAG(l, PCI_CXL_CTRL_MEM),
+ PCI_CXL_CTRL_CACHE_SF_COV(l), PCI_CXL_CTRL_CACHE_SF_GRAN(l), FLAG(l, PCI_CXL_CTRL_CACHE_CLN),
+ FLAG(l, PCI_CXL_CTRL_VIRAL));
+
+ l = get_conf_word(d, where + PCI_CXL_STATUS);
+ printf("\t\tCXLSta:\tViral%c\n", FLAG(l, PCI_CXL_STATUS_VIRAL));
+}
+
+static void
+cap_dvsec(struct device *d, int where)
+{
+ printf("Designated Vendor-Specific: ");
+ if (!config_fetch(d, where + PCI_DVSEC_HEADER1, 8))
+ {
+ printf("<unreadable>\n");
+ return;
+ }
+
+ u32 hdr = get_conf_long(d, where + PCI_DVSEC_HEADER1);
+ u16 vendor = BITS(hdr, 0, 16);
+ byte rev = BITS(hdr, 16, 4);
+ u16 len = BITS(hdr, 20, 12);
+
+ u16 id = get_conf_long(d, where + PCI_DVSEC_HEADER2);
+
+ printf("Vendor=%04x ID=%04x Rev=%d Len=%d", vendor, id, rev, len);
+ if (vendor == PCI_DVSEC_VENDOR_ID_CXL && id == PCI_DVSEC_ID_CXL && len >= 16)
+ cap_dvsec_cxl(d, where);
+ else
+ printf(" <?>\n");
+}
+
+static void
+cap_evendor(struct device *d, int where)
+{
+ u32 hdr;
+
+ printf("Vendor Specific Information: ");
+ if (!config_fetch(d, where + PCI_EVNDR_HEADER, 4))
+ {
+ printf("<unreadable>\n");
+ return;
+ }
+
+ hdr = get_conf_long(d, where + PCI_EVNDR_HEADER);
+ printf("ID=%04x Rev=%d Len=%03x <?>\n",
+ BITS(hdr, 0, 16),
+ BITS(hdr, 16, 4),
+ BITS(hdr, 20, 12));
+}
+
+static int l1pm_calc_pwron(int scale, int value)
+{
+ switch (scale)
+ {
+ case 0:
+ return 2 * value;
+ case 1:
+ return 10 * value;
+ case 2:
+ return 100 * value;
+ }
+ return -1;
+}
+
+static void
+cap_l1pm(struct device *d, int where)
+{
+ u32 l1_cap, val, scale;
+ int time;
+
+ printf("L1 PM Substates\n");
+
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + PCI_L1PM_SUBSTAT_CAP, 12))
+ {
+ printf("\t\t<unreadable>\n");
+ return;
+ }
+
+ l1_cap = get_conf_long(d, where + PCI_L1PM_SUBSTAT_CAP);
+ printf("\t\tL1SubCap: ");
+ printf("PCI-PM_L1.2%c PCI-PM_L1.1%c ASPM_L1.2%c ASPM_L1.1%c L1_PM_Substates%c\n",
+ FLAG(l1_cap, PCI_L1PM_SUBSTAT_CAP_PM_L12),
+ FLAG(l1_cap, PCI_L1PM_SUBSTAT_CAP_PM_L11),
+ FLAG(l1_cap, PCI_L1PM_SUBSTAT_CAP_ASPM_L12),
+ FLAG(l1_cap, PCI_L1PM_SUBSTAT_CAP_ASPM_L11),
+ FLAG(l1_cap, PCI_L1PM_SUBSTAT_CAP_L1PM_SUPP));
+
+ if (l1_cap & PCI_L1PM_SUBSTAT_CAP_PM_L12 || l1_cap & PCI_L1PM_SUBSTAT_CAP_ASPM_L12)
+ {
+ printf("\t\t\t PortCommonModeRestoreTime=%dus ", BITS(l1_cap, 8, 8));
+ time = l1pm_calc_pwron(BITS(l1_cap, 16, 2), BITS(l1_cap, 19, 5));
+ if (time != -1)
+ printf("PortTPowerOnTime=%dus\n", time);
+ else
+ printf("PortTPowerOnTime=<error>\n");
+ }
+
+ val = get_conf_long(d, where + PCI_L1PM_SUBSTAT_CTL1);
+ printf("\t\tL1SubCtl1: PCI-PM_L1.2%c PCI-PM_L1.1%c ASPM_L1.2%c ASPM_L1.1%c\n",
+ FLAG(val, PCI_L1PM_SUBSTAT_CTL1_PM_L12),
+ FLAG(val, PCI_L1PM_SUBSTAT_CTL1_PM_L11),
+ FLAG(val, PCI_L1PM_SUBSTAT_CTL1_ASPM_L12),
+ FLAG(val, PCI_L1PM_SUBSTAT_CTL1_ASPM_L11));
+
+ if (l1_cap & PCI_L1PM_SUBSTAT_CAP_PM_L12 || l1_cap & PCI_L1PM_SUBSTAT_CAP_ASPM_L12)
+ {
+ printf("\t\t\t T_CommonMode=%dus", BITS(val, 8, 8));
+
+ if (l1_cap & PCI_L1PM_SUBSTAT_CAP_ASPM_L12)
+ {
+ scale = BITS(val, 29, 3);
+ if (scale > 5)
+ printf(" LTR1.2_Threshold=<error>");
+ else
+ printf(" LTR1.2_Threshold=%lldns", BITS(val, 16, 10) * (unsigned long long) cap_ltr_scale(scale));
+ }
+ printf("\n");
+ }
+
+ val = get_conf_long(d, where + PCI_L1PM_SUBSTAT_CTL2);
+ printf("\t\tL1SubCtl2:");
+ if (l1_cap & PCI_L1PM_SUBSTAT_CAP_PM_L12 || l1_cap & PCI_L1PM_SUBSTAT_CAP_ASPM_L12)
+ {
+ time = l1pm_calc_pwron(BITS(val, 0, 2), BITS(val, 3, 5));
+ if (time != -1)
+ printf(" T_PwrOn=%dus", time);
+ else
+ printf(" T_PwrOn=<error>");
+ }
+ printf("\n");
+}
+
+static void
+cap_ptm(struct device *d, int where)
+{
+ u32 buff;
+ u16 clock;
+
+ printf("Precision Time Measurement\n");
+
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where + 4, 8))
+ {
+ printf("\t\t<unreadable>\n");
+ return;
+ }
+
+ buff = get_conf_long(d, where + 4);
+ printf("\t\tPTMCap: ");
+ printf("Requester:%c Responder:%c Root:%c\n",
+ FLAG(buff, 0x1),
+ FLAG(buff, 0x2),
+ FLAG(buff, 0x4));
+
+ clock = BITS(buff, 8, 8);
+ printf("\t\tPTMClockGranularity: ");
+ switch (clock)
+ {
+ case 0x00:
+ printf("Unimplemented\n");
+ break;
+ case 0xff:
+ printf("Greater than 254ns\n");
+ break;
+ default:
+ printf("%huns\n", clock);
+ }
+
+ buff = get_conf_long(d, where + 8);
+ printf("\t\tPTMControl: ");
+ printf("Enabled:%c RootSelected:%c\n",
+ FLAG(buff, 0x1),
+ FLAG(buff, 0x2));
+
+ clock = BITS(buff, 8, 8);
+ printf("\t\tPTMEffectiveGranularity: ");
+ switch (clock)
+ {
+ case 0x00:
+ printf("Unknown\n");
+ break;
+ case 0xff:
+ printf("Greater than 254ns\n");
+ break;
+ default:
+ printf("%huns\n", clock);
+ }
+}
+
+static void
+print_rebar_range_size(int ld2_size)
+{
+ // This function prints the input as a power-of-2 size value
+ // It is biased with 1MB = 0, ...
+ // Maximum resizable BAR value supported is 2^63 bytes = 43
+ // for the extended resizable BAR capability definition
+ // (otherwise it would stop at 2^28)
+
+ if (ld2_size >= 0 && ld2_size < 10)
+ printf(" %dMB", (1 << ld2_size));
+ else if (ld2_size >= 10 && ld2_size < 20)
+ printf(" %dGB", (1 << (ld2_size-10)));
+ else if (ld2_size >= 20 && ld2_size < 30)
+ printf(" %dTB", (1 << (ld2_size-20)));
+ else if (ld2_size >= 30 && ld2_size < 40)
+ printf(" %dPB", (1 << (ld2_size-30)));
+ else if (ld2_size >= 40 && ld2_size < 44)
+ printf(" %dEB", (1 << (ld2_size-40)));
+ else
+ printf(" <unknown>");
+}
+
+static void
+cap_rebar(struct device *d, int where, int virtual)
+{
+ u32 sizes_buffer, control_buffer, ext_sizes, current_size;
+ u16 bar_index, barcount, i;
+ // If the structure exists, at least one bar is defined
+ u16 num_bars = 1;
+
+ printf("%s Resizable BAR\n", (virtual) ? "Virtual" : "Physical");
+
+ if (verbose < 2)
+ return;
+
+ // Go through all defined BAR definitions of the caps, at minimum 1
+ // (loop also terminates if num_bars read from caps is > 6)
+ for (barcount = 0; barcount < num_bars; barcount++)
+ {
+ where += 4;
+
+ // Get the next BAR configuration
+ if (!config_fetch(d, where, 8))
+ {
+ printf("\t\t<unreadable>\n");
+ return;
+ }
+
+ sizes_buffer = get_conf_long(d, where) >> 4;
+ where += 4;
+ control_buffer = get_conf_long(d, where);
+
+ bar_index = BITS(control_buffer, 0, 3);
+ current_size = BITS(control_buffer, 8, 6);
+ ext_sizes = BITS(control_buffer, 16, 16);
+
+ if (barcount == 0)
+ {
+ // Only index 0 controlreg has the num_bar count definition
+ num_bars = BITS(control_buffer, 5, 3);
+ if (num_bars < 1 || num_bars > 6)
+ {
+ printf("\t\t<error in resizable BAR: num_bars=%d is out of specification>\n", num_bars);
+ break;
+ }
+ }
+
+ // Resizable BAR list entry have an arbitrary index and current size
+ printf("\t\tBAR %d: current size:", bar_index);
+ print_rebar_range_size(current_size);
+
+ if (sizes_buffer || ext_sizes)
+ {
+ printf(", supported:");
+
+ for (i=0; i<28; i++)
+ if (sizes_buffer & (1U << i))
+ print_rebar_range_size(i);
+
+ for (i=0; i<16; i++)
+ if (ext_sizes & (1U << i))
+ print_rebar_range_size(i + 28);
+ }
+
+ printf("\n");
+ }
+}
+
+void
+show_ext_caps(struct device *d, int type)
+{
+ int where = 0x100;
+ char been_there[0x1000];
+ memset(been_there, 0, 0x1000);
+ do
+ {
+ u32 header;
+ int id, version;
+
+ if (!config_fetch(d, where, 4))
+ break;
+ header = get_conf_long(d, where);
+ if (!header)
+ break;
+ id = header & 0xffff;
+ version = (header >> 16) & 0xf;
+ printf("\tCapabilities: [%03x", where);
+ if (verbose > 1)
+ printf(" v%d", version);
+ printf("] ");
+ if (been_there[where]++)
+ {
+ printf("<chain looped>\n");
+ break;
+ }
+ switch (id)
+ {
+ case PCI_EXT_CAP_ID_NULL:
+ printf("Null\n");
+ break;
+ case PCI_EXT_CAP_ID_AER:
+ cap_aer(d, where, type);
+ break;
+ case PCI_EXT_CAP_ID_DPC:
+ cap_dpc(d, where);
+ break;
+ case PCI_EXT_CAP_ID_VC:
+ case PCI_EXT_CAP_ID_VC2:
+ cap_vc(d, where);
+ break;
+ case PCI_EXT_CAP_ID_DSN:
+ cap_dsn(d, where);
+ break;
+ case PCI_EXT_CAP_ID_PB:
+ printf("Power Budgeting <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_RCLINK:
+ cap_rclink(d, where);
+ break;
+ case PCI_EXT_CAP_ID_RCILINK:
+ printf("Root Complex Internal Link <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_RCECOLL:
+ printf("Root Complex Event Collector <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_MFVC:
+ printf("Multi-Function Virtual Channel <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_RCRB:
+ printf("Root Complex Register Block <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_VNDR:
+ cap_evendor(d, where);
+ break;
+ case PCI_EXT_CAP_ID_ACS:
+ cap_acs(d, where);
+ break;
+ case PCI_EXT_CAP_ID_ARI:
+ cap_ari(d, where);
+ break;
+ case PCI_EXT_CAP_ID_ATS:
+ cap_ats(d, where);
+ break;
+ case PCI_EXT_CAP_ID_SRIOV:
+ cap_sriov(d, where);
+ break;
+ case PCI_EXT_CAP_ID_MRIOV:
+ printf("Multi-Root I/O Virtualization <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_MCAST:
+ cap_multicast(d, where, type);
+ break;
+ case PCI_EXT_CAP_ID_PRI:
+ cap_pri(d, where);
+ break;
+ case PCI_EXT_CAP_ID_REBAR:
+ cap_rebar(d, where, 0);
+ break;
+ case PCI_EXT_CAP_ID_DPA:
+ printf("Dynamic Power Allocation <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_TPH:
+ cap_tph(d, where);
+ break;
+ case PCI_EXT_CAP_ID_LTR:
+ cap_ltr(d, where);
+ break;
+ case PCI_EXT_CAP_ID_SECPCI:
+ cap_sec(d, where);
+ break;
+ case PCI_EXT_CAP_ID_PMUX:
+ printf("Protocol Multiplexing <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_PASID:
+ cap_pasid(d, where);
+ break;
+ case PCI_EXT_CAP_ID_LNR:
+ printf("LN Requester <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_L1PM:
+ cap_l1pm(d, where);
+ break;
+ case PCI_EXT_CAP_ID_PTM:
+ cap_ptm(d, where);
+ break;
+ case PCI_EXT_CAP_ID_M_PCIE:
+ printf("PCI Express over M_PHY <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_FRS:
+ printf("FRS Queueing <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_RTR:
+ printf("Readiness Time Reporting <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_DVSEC:
+ cap_dvsec(d, where);
+ break;
+ case PCI_EXT_CAP_ID_VF_REBAR:
+ cap_rebar(d, where, 1);
+ break;
+ case PCI_EXT_CAP_ID_DLNK:
+ printf("Data Link Feature <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_16GT:
+ printf("Physical Layer 16.0 GT/s <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_LMR:
+ printf("Lane Margining at the Receiver <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_HIER_ID:
+ printf("Hierarchy ID <?>\n");
+ break;
+ case PCI_EXT_CAP_ID_NPEM:
+ printf("Native PCIe Enclosure Management <?>\n");
+ break;
+ default:
+ printf("Extended Capability ID %#02x\n", id);
+ break;
+ }
+ where = (header >> 20) & ~3;
+ } while (where);
+}
diff --git a/ls-kernel.c b/ls-kernel.c
new file mode 100644
index 0000000..ecacd0e
--- /dev/null
+++ b/ls-kernel.c
@@ -0,0 +1,323 @@
+/*
+ * The PCI Utilities -- Show Kernel Drivers
+ *
+ * Copyright (c) 1997--2013 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "lspci.h"
+
+#ifdef PCI_OS_LINUX
+
+#include <sys/utsname.h>
+
+#ifdef PCI_USE_LIBKMOD
+
+#include <libkmod.h>
+
+static struct kmod_ctx *kmod_ctx;
+
+static int
+show_kernel_init(void)
+{
+ static int show_kernel_inited = -1;
+ if (show_kernel_inited >= 0)
+ return show_kernel_inited;
+
+ kmod_ctx = kmod_new(NULL, NULL);
+ if (!kmod_ctx)
+ {
+ fprintf(stderr, "lspci: Unable to initialize libkmod context\n");
+ goto failed;
+ }
+
+ int err;
+ if ((err = kmod_load_resources(kmod_ctx)) < 0)
+ {
+ fprintf(stderr, "lspci: Unable to load libkmod resources: error %d\n", err);
+ goto failed;
+ }
+
+ show_kernel_inited = 1;
+ return 1;
+
+failed:
+ show_kernel_inited = 0;
+ return 0;
+}
+
+void
+show_kernel_cleanup(void)
+{
+ if (kmod_ctx)
+ kmod_unref(kmod_ctx);
+}
+
+static const char *next_module(struct device *d)
+{
+ static struct kmod_list *klist, *kcurrent;
+ static struct kmod_module *kmodule;
+
+ if (kmodule)
+ {
+ kmod_module_unref(kmodule);
+ kmodule = NULL;
+ }
+
+ if (!klist)
+ {
+ pci_fill_info(d->dev, PCI_FILL_MODULE_ALIAS);
+ if (!d->dev->module_alias)
+ return NULL;
+ int err = kmod_module_new_from_lookup(kmod_ctx, d->dev->module_alias, &klist);
+ if (err < 0)
+ {
+ fprintf(stderr, "lspci: libkmod lookup failed: error %d\n", err);
+ return NULL;
+ }
+ kcurrent = klist;
+ }
+ else
+ kcurrent = kmod_list_next(klist, kcurrent);
+
+ if (kcurrent)
+ {
+ kmodule = kmod_module_get_module(kcurrent);
+ return kmod_module_get_name(kmodule);
+ }
+
+ kmod_module_unref_list(klist);
+ klist = NULL;
+ return NULL;
+}
+
+#else
+
+struct pcimap_entry {
+ struct pcimap_entry *next;
+ unsigned int vendor, device;
+ unsigned int subvendor, subdevice;
+ unsigned int class, class_mask;
+ char module[1];
+};
+
+static struct pcimap_entry *pcimap_head;
+
+static int
+show_kernel_init(void)
+{
+ static int tried_pcimap;
+ struct utsname uts;
+ char *name, line[1024];
+ FILE *f;
+
+ if (tried_pcimap)
+ return 1;
+ tried_pcimap = 1;
+
+ if (name = opt_pcimap)
+ {
+ f = fopen(name, "r");
+ if (!f)
+ die("Cannot open pcimap file %s: %m", name);
+ }
+ else
+ {
+ if (uname(&uts) < 0)
+ die("uname() failed: %m");
+ name = alloca(64 + strlen(uts.release));
+ sprintf(name, "/lib/modules/%s/modules.pcimap", uts.release);
+ f = fopen(name, "r");
+ if (!f)
+ return 1;
+ }
+
+ while (fgets(line, sizeof(line), f))
+ {
+ char *c = strchr(line, '\n');
+ struct pcimap_entry *e;
+
+ if (!c)
+ die("Unterminated or too long line in %s", name);
+ *c = 0;
+ if (!line[0] || line[0] == '#')
+ continue;
+
+ c = line;
+ while (*c && *c != ' ' && *c != '\t')
+ c++;
+ if (!*c)
+ continue; /* FIXME: Emit warnings! */
+ *c++ = 0;
+
+ e = xmalloc(sizeof(*e) + strlen(line));
+ if (sscanf(c, "%i%i%i%i%i%i",
+ &e->vendor, &e->device,
+ &e->subvendor, &e->subdevice,
+ &e->class, &e->class_mask) != 6)
+ continue;
+ e->next = pcimap_head;
+ pcimap_head = e;
+ strcpy(e->module, line);
+ }
+ fclose(f);
+
+ return 1;
+}
+
+static int
+match_pcimap(struct device *d, struct pcimap_entry *e)
+{
+ struct pci_dev *dev = d->dev;
+ unsigned int class = get_conf_long(d, PCI_REVISION_ID) >> 8;
+ word subv, subd;
+
+#define MATCH(x, y) ((y) > 0xffff || (x) == (y))
+ get_subid(d, &subv, &subd);
+ return
+ MATCH(dev->vendor_id, e->vendor) &&
+ MATCH(dev->device_id, e->device) &&
+ MATCH(subv, e->subvendor) &&
+ MATCH(subd, e->subdevice) &&
+ (class & e->class_mask) == e->class;
+#undef MATCH
+}
+
+static const char *next_module(struct device *d)
+{
+ static struct pcimap_entry *current;
+
+ if (!current)
+ current = pcimap_head;
+ else
+ current = current->next;
+
+ while (current)
+ {
+ if (match_pcimap(d, current))
+ return current->module;
+ current = current->next;
+ }
+
+ return NULL;
+}
+
+void
+show_kernel_cleanup(void)
+{
+}
+
+#endif
+
+#define DRIVER_BUF_SIZE 1024
+
+static char *
+find_driver(struct device *d, char *buf)
+{
+ struct pci_dev *dev = d->dev;
+ char name[1024], *drv, *base;
+ int n;
+
+ if (dev->access->method != PCI_ACCESS_SYS_BUS_PCI)
+ return NULL;
+
+ base = pci_get_param(dev->access, "sysfs.path");
+ if (!base || !base[0])
+ return NULL;
+
+ n = snprintf(name, sizeof(name), "%s/devices/%04x:%02x:%02x.%d/driver",
+ base, dev->domain, dev->bus, dev->dev, dev->func);
+ if (n < 0 || n >= (int)sizeof(name))
+ die("show_driver: sysfs device name too long, why?");
+
+ n = readlink(name, buf, DRIVER_BUF_SIZE);
+ if (n < 0)
+ return NULL;
+ if (n >= DRIVER_BUF_SIZE)
+ return "<name-too-long>";
+ buf[n] = 0;
+
+ if (drv = strrchr(buf, '/'))
+ return drv+1;
+ else
+ return buf;
+}
+
+static const char *
+next_module_filtered(struct device *d)
+{
+ static char prev_module[256];
+ const char *module;
+
+ while (module = next_module(d))
+ {
+ if (strcmp(module, prev_module))
+ {
+ strncpy(prev_module, module, sizeof(prev_module));
+ prev_module[sizeof(prev_module) - 1] = 0;
+ return module;
+ }
+ }
+ prev_module[0] = 0;
+ return NULL;
+}
+
+void
+show_kernel(struct device *d)
+{
+ char buf[DRIVER_BUF_SIZE];
+ const char *driver, *module;
+
+ if (driver = find_driver(d, buf))
+ printf("\tKernel driver in use: %s\n", driver);
+
+ if (!show_kernel_init())
+ return;
+
+ int cnt = 0;
+ while (module = next_module_filtered(d))
+ printf("%s %s", (cnt++ ? "," : "\tKernel modules:"), module);
+ if (cnt)
+ putchar('\n');
+}
+
+void
+show_kernel_machine(struct device *d)
+{
+ char buf[DRIVER_BUF_SIZE];
+ const char *driver, *module;
+
+ if (driver = find_driver(d, buf))
+ printf("Driver:\t%s\n", driver);
+
+ if (!show_kernel_init())
+ return;
+
+ while (module = next_module_filtered(d))
+ printf("Module:\t%s\n", module);
+}
+
+#else
+
+void
+show_kernel(struct device *d UNUSED)
+{
+}
+
+void
+show_kernel_machine(struct device *d UNUSED)
+{
+}
+
+void
+show_kernel_cleanup(void)
+{
+}
+
+#endif
+
diff --git a/ls-map.c b/ls-map.c
new file mode 100644
index 0000000..c3ef54b
--- /dev/null
+++ b/ls-map.c
@@ -0,0 +1,181 @@
+/*
+ * The PCI Utilities -- Bus Mapping Mode
+ *
+ * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "lspci.h"
+
+struct bus_bridge {
+ struct bus_bridge *next;
+ byte this, dev, func, first, last, bug;
+};
+
+struct bus_info {
+ byte exists;
+ byte guestbook;
+ struct bus_bridge *bridges, *via;
+};
+
+static struct bus_info *bus_info;
+
+static void
+map_bridge(struct bus_info *bi, struct device *d, int np, int ns, int nl)
+{
+ struct bus_bridge *b = xmalloc(sizeof(struct bus_bridge));
+ struct pci_dev *p = d->dev;
+
+ b->next = bi->bridges;
+ bi->bridges = b;
+ b->this = get_conf_byte(d, np);
+ b->dev = p->dev;
+ b->func = p->func;
+ b->first = get_conf_byte(d, ns);
+ b->last = get_conf_byte(d, nl);
+ printf("## %02x:%02x.%d is a bridge from %02x to %02x-%02x\n",
+ p->bus, p->dev, p->func, b->this, b->first, b->last);
+ if (b->this != p->bus)
+ printf("!!! Bridge points to invalid primary bus.\n");
+ if (b->first > b->last)
+ {
+ printf("!!! Bridge points to invalid bus range.\n");
+ b->last = b->first;
+ }
+}
+
+static void
+do_map_bus(int bus)
+{
+ int dev, func;
+ int verbose = pacc->debugging;
+ struct bus_info *bi = bus_info + bus;
+ struct device *d;
+
+ if (verbose)
+ printf("Mapping bus %02x\n", bus);
+ for (dev = 0; dev < 32; dev++)
+ if (filter.slot < 0 || filter.slot == dev)
+ {
+ int func_limit = 1;
+ for (func = 0; func < func_limit; func++)
+ if (filter.func < 0 || filter.func == func)
+ {
+ /* XXX: Bus mapping supports only domain 0 */
+ struct pci_dev *p = pci_get_dev(pacc, 0, bus, dev, func);
+ u16 vendor = pci_read_word(p, PCI_VENDOR_ID);
+ if (vendor && vendor != 0xffff)
+ {
+ if (!func && (pci_read_byte(p, PCI_HEADER_TYPE) & 0x80))
+ func_limit = 8;
+ if (verbose)
+ printf("Discovered device %02x:%02x.%d\n", bus, dev, func);
+ bi->exists = 1;
+ if (d = scan_device(p))
+ {
+ show_device(d);
+ switch (get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f)
+ {
+ case PCI_HEADER_TYPE_BRIDGE:
+ map_bridge(bi, d, PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS);
+ break;
+ case PCI_HEADER_TYPE_CARDBUS:
+ map_bridge(bi, d, PCI_CB_PRIMARY_BUS, PCI_CB_CARD_BUS, PCI_CB_SUBORDINATE_BUS);
+ break;
+ }
+ free(d);
+ }
+ else if (verbose)
+ printf("But it was filtered out.\n");
+ }
+ pci_free_dev(p);
+ }
+ }
+}
+
+static void
+do_map_bridges(int bus, int min, int max)
+{
+ struct bus_info *bi = bus_info + bus;
+ struct bus_bridge *b;
+
+ bi->guestbook = 1;
+ for (b=bi->bridges; b; b=b->next)
+ {
+ if (bus_info[b->first].guestbook)
+ b->bug = 1;
+ else if (b->first < min || b->last > max)
+ b->bug = 2;
+ else
+ {
+ bus_info[b->first].via = b;
+ do_map_bridges(b->first, b->first, b->last);
+ }
+ }
+}
+
+static void
+map_bridges(void)
+{
+ int i;
+
+ printf("\nSummary of buses:\n\n");
+ for (i=0; i<256; i++)
+ if (bus_info[i].exists && !bus_info[i].guestbook)
+ do_map_bridges(i, 0, 255);
+ for (i=0; i<256; i++)
+ {
+ struct bus_info *bi = bus_info + i;
+ struct bus_bridge *b = bi->via;
+
+ if (bi->exists)
+ {
+ printf("%02x: ", i);
+ if (b)
+ printf("Entered via %02x:%02x.%d\n", b->this, b->dev, b->func);
+ else if (!i)
+ printf("Primary host bus\n");
+ else
+ printf("Secondary host bus (?)\n");
+ }
+ for (b=bi->bridges; b; b=b->next)
+ {
+ printf("\t%02x.%d Bridge to %02x-%02x", b->dev, b->func, b->first, b->last);
+ switch (b->bug)
+ {
+ case 1:
+ printf(" <overlap bug>");
+ break;
+ case 2:
+ printf(" <crossing bug>");
+ break;
+ }
+ putchar('\n');
+ }
+ }
+}
+
+void
+map_the_bus(void)
+{
+ if (pacc->method == PCI_ACCESS_PROC_BUS_PCI ||
+ pacc->method == PCI_ACCESS_SYS_BUS_PCI ||
+ pacc->method == PCI_ACCESS_DUMP)
+ printf("WARNING: Bus mapping can be reliable only with direct hardware access enabled.\n\n");
+ bus_info = xmalloc(sizeof(struct bus_info) * 256);
+ memset(bus_info, 0, sizeof(struct bus_info) * 256);
+ if (filter.bus >= 0)
+ do_map_bus(filter.bus);
+ else
+ {
+ int bus;
+ for (bus=0; bus<256; bus++)
+ do_map_bus(bus);
+ }
+ map_bridges();
+}
diff --git a/ls-tree.c b/ls-tree.c
new file mode 100644
index 0000000..aeb4087
--- /dev/null
+++ b/ls-tree.c
@@ -0,0 +1,279 @@
+/*
+ * The PCI Utilities -- Show Bus Tree
+ *
+ * Copyright (c) 1997--2020 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "lspci.h"
+
+struct bridge host_bridge = { NULL, NULL, NULL, NULL, 0, ~0, 0, ~0, NULL };
+
+static struct bus *
+find_bus(struct bridge *b, unsigned int domain, unsigned int n)
+{
+ struct bus *bus;
+
+ for (bus=b->first_bus; bus; bus=bus->sibling)
+ if (bus->domain == domain && bus->number == n)
+ break;
+ return bus;
+}
+
+static struct bus *
+new_bus(struct bridge *b, unsigned int domain, unsigned int n)
+{
+ struct bus *bus = xmalloc(sizeof(struct bus));
+ bus->domain = domain;
+ bus->number = n;
+ bus->sibling = b->first_bus;
+ bus->first_dev = NULL;
+ bus->last_dev = &bus->first_dev;
+ bus->parent_bridge = b;
+ b->first_bus = bus;
+ return bus;
+}
+
+static void
+insert_dev(struct device *d, struct bridge *b)
+{
+ struct pci_dev *p = d->dev;
+ struct bus *bus;
+
+ if (! (bus = find_bus(b, p->domain, p->bus)))
+ {
+ struct bridge *c;
+ for (c=b->child; c; c=c->next)
+ if (c->domain == (unsigned)p->domain && c->secondary <= p->bus && p->bus <= c->subordinate)
+ {
+ insert_dev(d, c);
+ return;
+ }
+ bus = new_bus(b, p->domain, p->bus);
+ }
+ /* Simple insertion at the end _does_ guarantee the correct order as the
+ * original device list was sorted by (domain, bus, devfn) lexicographically
+ * and all devices on the new list have the same bus number.
+ */
+ *bus->last_dev = d;
+ bus->last_dev = &d->bus_next;
+ d->bus_next = NULL;
+ d->parent_bus = bus;
+}
+
+void
+grow_tree(void)
+{
+ struct device *d;
+ struct bridge **last_br, *b;
+
+ /* Build list of bridges */
+
+ last_br = &host_bridge.chain;
+ for (d=first_dev; d; d=d->next)
+ {
+ struct pci_dev *dd = d->dev;
+ word class = dd->device_class;
+ byte ht = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
+ if ((class >> 8) == PCI_BASE_CLASS_BRIDGE &&
+ (ht == PCI_HEADER_TYPE_BRIDGE || ht == PCI_HEADER_TYPE_CARDBUS))
+ {
+ b = xmalloc(sizeof(struct bridge));
+ b->domain = dd->domain;
+ if (ht == PCI_HEADER_TYPE_BRIDGE)
+ {
+ b->primary = get_conf_byte(d, PCI_PRIMARY_BUS);
+ b->secondary = get_conf_byte(d, PCI_SECONDARY_BUS);
+ b->subordinate = get_conf_byte(d, PCI_SUBORDINATE_BUS);
+ }
+ else
+ {
+ b->primary = get_conf_byte(d, PCI_CB_PRIMARY_BUS);
+ b->secondary = get_conf_byte(d, PCI_CB_CARD_BUS);
+ b->subordinate = get_conf_byte(d, PCI_CB_SUBORDINATE_BUS);
+ }
+ *last_br = b;
+ last_br = &b->chain;
+ b->next = b->child = NULL;
+ b->first_bus = NULL;
+ b->br_dev = d;
+ d->bridge = b;
+ pacc->debug("Tree: bridge %04x:%02x:%02x.%d: %02x -> %02x-%02x\n",
+ dd->domain, dd->bus, dd->dev, dd->func,
+ b->primary, b->secondary, b->subordinate);
+ }
+ }
+ *last_br = NULL;
+
+ /* Create a bridge tree */
+
+ for (b=&host_bridge; b; b=b->chain)
+ {
+ struct bridge *c, *best;
+ best = NULL;
+ for (c=&host_bridge; c; c=c->chain)
+ if (c != b && (c == &host_bridge || b->domain == c->domain) &&
+ b->primary >= c->secondary && b->primary <= c->subordinate &&
+ (!best || best->subordinate - best->primary > c->subordinate - c->primary))
+ best = c;
+ if (best)
+ {
+ b->next = best->child;
+ best->child = b;
+ }
+ }
+
+ /* Insert secondary bus for each bridge */
+
+ for (b=&host_bridge; b; b=b->chain)
+ if (!find_bus(b, b->domain, b->secondary))
+ new_bus(b, b->domain, b->secondary);
+
+ /* Create bus structs and link devices */
+
+ for (d=first_dev; d; d=d->next)
+ insert_dev(d, &host_bridge);
+}
+
+static void
+print_it(char *line, char *p)
+{
+ *p++ = '\n';
+ *p = 0;
+ fputs(line, stdout);
+ for (p=line; *p; p++)
+ if (*p == '+' || *p == '|')
+ *p = '|';
+ else
+ *p = ' ';
+}
+
+static void show_tree_bridge(struct bridge *, char *, char *);
+
+#define LINE_BUF_SIZE 1024
+
+static char * FORMAT_CHECK(printf, 3, 4)
+tree_printf(char *line, char *p, char *fmt, ...)
+{
+ va_list args;
+ char *end = line + LINE_BUF_SIZE - 2;
+
+ if (p >= end)
+ return p;
+
+ va_start(args, fmt);
+ int res = vsnprintf(p, end - p, fmt, args);
+ if (res < 0)
+ {
+ /* Ancient C libraries return -1 on overflow */
+ p += strlen(p);
+ }
+ else
+ p += res;
+
+ va_end(args);
+ return p;
+}
+
+static void
+show_tree_dev(struct device *d, char *line, char *p)
+{
+ struct pci_dev *q = d->dev;
+ struct bridge *b;
+ char namebuf[256];
+
+ p = tree_printf(line, p, "%02x.%x", q->dev, q->func);
+ for (b=&host_bridge; b; b=b->chain)
+ if (b->br_dev == d)
+ {
+ if (b->secondary == b->subordinate)
+ p = tree_printf(line, p, "-[%02x]-", b->secondary);
+ else
+ p = tree_printf(line, p, "-[%02x-%02x]-", b->secondary, b->subordinate);
+ show_tree_bridge(b, line, p);
+ return;
+ }
+ if (verbose)
+ p = tree_printf(line, p, " %s",
+ pci_lookup_name(pacc, namebuf, sizeof(namebuf),
+ PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
+ q->vendor_id, q->device_id));
+ print_it(line, p);
+}
+
+static void
+show_tree_bus(struct bus *b, char *line, char *p)
+{
+ if (!b->first_dev)
+ print_it(line, p);
+ else if (!b->first_dev->bus_next)
+ {
+ p = tree_printf(line, p, "--");
+ show_tree_dev(b->first_dev, line, p);
+ }
+ else
+ {
+ struct device *d = b->first_dev;
+ while (d->bus_next)
+ {
+ char *p2 = tree_printf(line, p, "+-");
+ show_tree_dev(d, line, p2);
+ d = d->bus_next;
+ }
+ p = tree_printf(line, p, "\\-");
+ show_tree_dev(d, line, p);
+ }
+}
+
+static void
+show_tree_bridge(struct bridge *b, char *line, char *p)
+{
+ *p++ = '-';
+ if (!b->first_bus->sibling)
+ {
+ if (b == &host_bridge)
+ p = tree_printf(line, p, "[%04x:%02x]-", b->domain, b->first_bus->number);
+ show_tree_bus(b->first_bus, line, p);
+ }
+ else
+ {
+ struct bus *u = b->first_bus;
+ char *k;
+
+ while (u->sibling)
+ {
+ k = tree_printf(line, p, "+-[%04x:%02x]-", u->domain, u->number);
+ show_tree_bus(u, line, k);
+ u = u->sibling;
+ }
+ k = tree_printf(line, p, "\\-[%04x:%02x]-", u->domain, u->number);
+ show_tree_bus(u, line, k);
+ }
+}
+
+void
+show_forest(struct pci_filter *filter)
+{
+ char line[LINE_BUF_SIZE];
+ if (filter == NULL)
+ show_tree_bridge(&host_bridge, line, line);
+ else
+ {
+ struct bridge *b;
+ for (b=&host_bridge; b; b=b->chain)
+ {
+ if (b->br_dev && pci_filter_match(filter, b->br_dev->dev))
+ {
+ struct pci_dev *d = b->br_dev->dev;
+ char *p = line;
+ p = tree_printf(line, p, "%04x:%02x:", d->domain_16, d->bus);
+ show_tree_dev(b->br_dev, line, p);
+ }
+ }
+ }
+}
diff --git a/ls-vpd.c b/ls-vpd.c
new file mode 100644
index 0000000..92627e4
--- /dev/null
+++ b/ls-vpd.c
@@ -0,0 +1,222 @@
+/*
+ * The PCI Utilities -- Show Vital Product Data
+ *
+ * Copyright (c) 2008 Solarflare Communications
+ *
+ * Written by Ben Hutchings <bhutchings@solarflare.com>
+ * Improved by Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lspci.h"
+
+/*
+ * The list of all known VPD items and their formats.
+ * Technically, this belongs to the pci.ids file, but the VPD does not seem
+ * to be developed any longer, so we have chosen the easier way.
+ */
+
+enum vpd_format {
+ F_BINARY,
+ F_TEXT,
+ F_RESVD,
+ F_RDWR,
+};
+
+static const struct vpd_item {
+ byte id1, id2;
+ byte format;
+ const char *name;
+} vpd_items[] = {
+ { 'C','P', F_BINARY, "Extended capability" },
+ { 'E','C', F_TEXT, "Engineering changes" },
+ { 'M','N', F_TEXT, "Manufacture ID" },
+ { 'P','N', F_TEXT, "Part number" },
+ { 'R','V', F_RESVD, "Reserved" },
+ { 'R','W', F_RDWR, "Read-write area" },
+ { 'S','N', F_TEXT, "Serial number" },
+ { 'Y','A', F_TEXT, "Asset tag" },
+ { 'V', 0 , F_TEXT, "Vendor specific" },
+ { 'Y', 0 , F_TEXT, "System specific" },
+ /* Non-standard extensions */
+ { 'C','C', F_TEXT, "CCIN" },
+ { 'F','C', F_TEXT, "Feature code" },
+ { 'F','N', F_TEXT, "FRU" },
+ { 'N','A', F_TEXT, "Network address" },
+ { 'R','M', F_TEXT, "Firmware version" },
+ { 'Z', 0 , F_TEXT, "Product specific" },
+ { 0, 0 , F_BINARY, "Unknown" }
+};
+
+static void
+print_vpd_string(const byte *buf, word len)
+{
+ while (len--)
+ {
+ byte ch = *buf++;
+ if (ch == '\\')
+ printf("\\\\");
+ else if (!ch && !len)
+ ; /* Cards with null-terminated strings have been observed */
+ else if (ch < 32 || ch == 127)
+ printf("\\x%02x", ch);
+ else
+ putchar(ch);
+ }
+}
+
+static void
+print_vpd_binary(const byte *buf, word len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ {
+ if (i)
+ putchar(' ');
+ printf("%02x", buf[i]);
+ }
+}
+
+static int
+read_vpd(struct device *d, int pos, byte *buf, int len, byte *csum)
+{
+ if (!pci_read_vpd(d->dev, pos, buf, len))
+ return 0;
+ while (len--)
+ *csum += *buf++;
+ return 1;
+}
+
+void
+cap_vpd(struct device *d)
+{
+ word res_addr = 0, res_len, part_pos, part_len;
+ byte buf[256];
+ byte tag;
+ byte csum = 0;
+
+ printf("Vital Product Data\n");
+ if (verbose < 2)
+ return;
+
+ while (res_addr <= PCI_VPD_ADDR_MASK)
+ {
+ if (!read_vpd(d, res_addr, &tag, 1, &csum))
+ break;
+ if (tag & 0x80)
+ {
+ if (res_addr > PCI_VPD_ADDR_MASK + 1 - 3)
+ break;
+ if (!read_vpd(d, res_addr + 1, buf, 2, &csum))
+ break;
+ res_len = buf[0] + (buf[1] << 8);
+ res_addr += 3;
+ }
+ else
+ {
+ res_len = tag & 7;
+ tag >>= 3;
+ res_addr += 1;
+ }
+ if (res_len > PCI_VPD_ADDR_MASK + 1 - res_addr)
+ break;
+
+ part_pos = 0;
+
+ switch (tag)
+ {
+ case 0x0f:
+ printf("\t\tEnd\n");
+ return;
+
+ case 0x82:
+ printf("\t\tProduct Name: ");
+ while (part_pos < res_len)
+ {
+ part_len = res_len - part_pos;
+ if (part_len > sizeof(buf))
+ part_len = sizeof(buf);
+ if (!read_vpd(d, res_addr + part_pos, buf, part_len, &csum))
+ break;
+ print_vpd_string(buf, part_len);
+ part_pos += part_len;
+ }
+ printf("\n");
+ break;
+
+ case 0x90:
+ case 0x91:
+ printf("\t\t%s fields:\n",
+ (tag == 0x90) ? "Read-only" : "Read/write");
+
+ while (part_pos + 3 <= res_len)
+ {
+ word read_len;
+ const struct vpd_item *item;
+ byte id[2], id1, id2;
+
+ if (!read_vpd(d, res_addr + part_pos, buf, 3, &csum))
+ break;
+ part_pos += 3;
+ memcpy(id, buf, 2);
+ id1 = id[0];
+ id2 = id[1];
+ part_len = buf[2];
+ if (part_len > res_len - part_pos)
+ break;
+
+ /* Is this item known? */
+ for (item=vpd_items; item->id1 && item->id1 != id1 ||
+ item->id2 && item->id2 != id2; item++)
+ ;
+
+ /* Only read the first byte of the RV field because the
+ * remaining bytes are not included in the checksum. */
+ read_len = (item->format == F_RESVD) ? 1 : part_len;
+ if (!read_vpd(d, res_addr + part_pos, buf, read_len, &csum))
+ break;
+
+ printf("\t\t\t[");
+ print_vpd_string(id, 2);
+ printf("] %s: ", item->name);
+
+ switch (item->format)
+ {
+ case F_TEXT:
+ print_vpd_string(buf, part_len);
+ printf("\n");
+ break;
+ case F_BINARY:
+ print_vpd_binary(buf, part_len);
+ printf("\n");
+ break;
+ case F_RESVD:
+ printf("checksum %s, %d byte(s) reserved\n", csum ? "bad" : "good", part_len - 1);
+ break;
+ case F_RDWR:
+ printf("%d byte(s) free\n", part_len);
+ break;
+ }
+
+ part_pos += part_len;
+ }
+ break;
+
+ default:
+ printf("\t\tUnknown %s resource type %02x, will not decode more.\n",
+ (tag & 0x80) ? "large" : "small", tag & ~0x80);
+ return;
+ }
+
+ res_addr += res_len;
+ }
+
+ if (res_addr == 0)
+ printf("\t\tNot readable\n");
+ else
+ printf("\t\tNo end tag found\n");
+}
diff --git a/lspci.c b/lspci.c
new file mode 100644
index 0000000..aba2745
--- /dev/null
+++ b/lspci.c
@@ -0,0 +1,1132 @@
+/*
+ * The PCI Utilities -- List All PCI Devices
+ *
+ * Copyright (c) 1997--2020 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "lspci.h"
+
+/* Options */
+
+int verbose; /* Show detailed information */
+static int opt_hex; /* Show contents of config space as hexadecimal numbers */
+struct pci_filter filter; /* Device filter */
+static int opt_filter; /* Any filter was given */
+static int opt_tree; /* Show bus tree */
+static int opt_path; /* Show bridge path */
+static int opt_machine; /* Generate machine-readable output */
+static int opt_map_mode; /* Bus mapping mode enabled */
+static int opt_domains; /* Show domain numbers (0=disabled, 1=auto-detected, 2=requested) */
+static int opt_kernel; /* Show kernel drivers */
+static int opt_query_dns; /* Query the DNS (0=disabled, 1=enabled, 2=refresh cache) */
+static int opt_query_all; /* Query the DNS for all entries */
+char *opt_pcimap; /* Override path to Linux modules.pcimap */
+
+const char program_name[] = "lspci";
+
+static char options[] = "nvbxs:d:tPi:mgp:qkMDQ" GENERIC_OPTIONS ;
+
+static char help_msg[] =
+"Usage: lspci [<switches>]\n"
+"\n"
+"Basic display modes:\n"
+"-mm\t\tProduce machine-readable output (single -m for an obsolete format)\n"
+"-t\t\tShow bus tree\n"
+"\n"
+"Display options:\n"
+"-v\t\tBe verbose (-vv or -vvv for higher verbosity)\n"
+#ifdef PCI_OS_LINUX
+"-k\t\tShow kernel drivers handling each device\n"
+#endif
+"-x\t\tShow hex-dump of the standard part of the config space\n"
+"-xxx\t\tShow hex-dump of the whole config space (dangerous; root only)\n"
+"-xxxx\t\tShow hex-dump of the 4096-byte extended config space (root only)\n"
+"-b\t\tBus-centric view (addresses and IRQ's as seen by the bus)\n"
+"-D\t\tAlways show domain numbers\n"
+"-P\t\tDisplay bridge path in addition to bus and device number\n"
+"-PP\t\tDisplay bus path in addition to bus and device number\n"
+"\n"
+"Resolving of device ID's to names:\n"
+"-n\t\tShow numeric ID's\n"
+"-nn\t\tShow both textual and numeric ID's (names & numbers)\n"
+#ifdef PCI_USE_DNS
+"-q\t\tQuery the PCI ID database for unknown ID's via DNS\n"
+"-qq\t\tAs above, but re-query locally cached entries\n"
+"-Q\t\tQuery the PCI ID database for all ID's via DNS\n"
+#endif
+"\n"
+"Selection of devices:\n"
+"-s [[[[<domain>]:]<bus>]:][<slot>][.[<func>]]\tShow only devices in selected slots\n"
+"-d [<vendor>]:[<device>][:<class>]\t\tShow only devices with specified ID's\n"
+"\n"
+"Other options:\n"
+"-i <file>\tUse specified ID database instead of %s\n"
+#ifdef PCI_OS_LINUX
+"-p <file>\tLook up kernel modules in a given file instead of default modules.pcimap\n"
+#endif
+"-M\t\tEnable `bus mapping' mode (dangerous; root only)\n"
+"\n"
+"PCI access options:\n"
+GENERIC_HELP
+;
+
+/*** Our view of the PCI bus ***/
+
+struct pci_access *pacc;
+struct device *first_dev;
+static int seen_errors;
+static int need_topology;
+
+int
+config_fetch(struct device *d, unsigned int pos, unsigned int len)
+{
+ unsigned int end = pos+len;
+ int result;
+
+ while (pos < d->config_bufsize && len && d->present[pos])
+ pos++, len--;
+ while (pos+len <= d->config_bufsize && len && d->present[pos+len-1])
+ len--;
+ if (!len)
+ return 1;
+
+ if (end > d->config_bufsize)
+ {
+ int orig_size = d->config_bufsize;
+ while (end > d->config_bufsize)
+ d->config_bufsize *= 2;
+ d->config = xrealloc(d->config, d->config_bufsize);
+ d->present = xrealloc(d->present, d->config_bufsize);
+ memset(d->present + orig_size, 0, d->config_bufsize - orig_size);
+ }
+ result = pci_read_block(d->dev, pos, d->config + pos, len);
+ if (result)
+ memset(d->present + pos, 1, len);
+ return result;
+}
+
+struct device *
+scan_device(struct pci_dev *p)
+{
+ struct device *d;
+
+ if (p->domain && !opt_domains)
+ opt_domains = 1;
+ if (!pci_filter_match(&filter, p) && !need_topology)
+ return NULL;
+ d = xmalloc(sizeof(struct device));
+ memset(d, 0, sizeof(*d));
+ d->dev = p;
+ d->config_cached = d->config_bufsize = 64;
+ d->config = xmalloc(64);
+ d->present = xmalloc(64);
+ memset(d->present, 1, 64);
+ if (!pci_read_block(p, 0, d->config, 64))
+ {
+ fprintf(stderr, "lspci: Unable to read the standard configuration space header of device %04x:%02x:%02x.%d\n",
+ p->domain, p->bus, p->dev, p->func);
+ seen_errors++;
+ return NULL;
+ }
+ if ((d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
+ {
+ /* For cardbus bridges, we need to fetch 64 bytes more to get the
+ * full standard header... */
+ if (config_fetch(d, 64, 64))
+ d->config_cached += 64;
+ }
+ pci_setup_cache(p, d->config, d->config_cached);
+ pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_CLASS);
+ return d;
+}
+
+static void
+scan_devices(void)
+{
+ struct device *d;
+ struct pci_dev *p;
+
+ pci_scan_bus(pacc);
+ for (p=pacc->devices; p; p=p->next)
+ if (d = scan_device(p))
+ {
+ d->next = first_dev;
+ first_dev = d;
+ }
+}
+
+/*** Config space accesses ***/
+
+static void
+check_conf_range(struct device *d, unsigned int pos, unsigned int len)
+{
+ while (len)
+ if (!d->present[pos])
+ die("Internal bug: Accessing non-read configuration byte at position %x", pos);
+ else
+ pos++, len--;
+}
+
+byte
+get_conf_byte(struct device *d, unsigned int pos)
+{
+ check_conf_range(d, pos, 1);
+ return d->config[pos];
+}
+
+word
+get_conf_word(struct device *d, unsigned int pos)
+{
+ check_conf_range(d, pos, 2);
+ return d->config[pos] | (d->config[pos+1] << 8);
+}
+
+u32
+get_conf_long(struct device *d, unsigned int pos)
+{
+ check_conf_range(d, pos, 4);
+ return d->config[pos] |
+ (d->config[pos+1] << 8) |
+ (d->config[pos+2] << 16) |
+ (d->config[pos+3] << 24);
+}
+
+/*** Sorting ***/
+
+static int
+compare_them(const void *A, const void *B)
+{
+ const struct pci_dev *a = (*(const struct device **)A)->dev;
+ const struct pci_dev *b = (*(const struct device **)B)->dev;
+
+ if (a->domain < b->domain)
+ return -1;
+ if (a->domain > b->domain)
+ return 1;
+ if (a->bus < b->bus)
+ return -1;
+ if (a->bus > b->bus)
+ return 1;
+ if (a->dev < b->dev)
+ return -1;
+ if (a->dev > b->dev)
+ return 1;
+ if (a->func < b->func)
+ return -1;
+ if (a->func > b->func)
+ return 1;
+ return 0;
+}
+
+static void
+sort_them(void)
+{
+ struct device **index, **h, **last_dev;
+ int cnt;
+ struct device *d;
+
+ cnt = 0;
+ for (d=first_dev; d; d=d->next)
+ cnt++;
+ h = index = alloca(sizeof(struct device *) * cnt);
+ for (d=first_dev; d; d=d->next)
+ *h++ = d;
+ qsort(index, cnt, sizeof(struct device *), compare_them);
+ last_dev = &first_dev;
+ h = index;
+ while (cnt--)
+ {
+ *last_dev = *h;
+ last_dev = &(*h)->next;
+ h++;
+ }
+ *last_dev = NULL;
+}
+
+/*** Normal output ***/
+
+static void
+show_slot_path(struct device *d)
+{
+ struct pci_dev *p = d->dev;
+
+ if (opt_path)
+ {
+ struct bus *bus = d->parent_bus;
+ struct bridge *br = bus->parent_bridge;
+
+ if (br && br->br_dev)
+ {
+ show_slot_path(br->br_dev);
+ if (opt_path > 1)
+ printf("/%02x:%02x.%d", p->bus, p->dev, p->func);
+ else
+ printf("/%02x.%d", p->dev, p->func);
+ return;
+ }
+ }
+ printf("%02x:%02x.%d", p->bus, p->dev, p->func);
+}
+
+static void
+show_slot_name(struct device *d)
+{
+ struct pci_dev *p = d->dev;
+
+ if (!opt_machine ? opt_domains : (p->domain || opt_domains >= 2))
+ printf("%04x:", p->domain);
+ show_slot_path(d);
+}
+
+void
+get_subid(struct device *d, word *subvp, word *subdp)
+{
+ byte htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
+
+ if (htype == PCI_HEADER_TYPE_NORMAL)
+ {
+ *subvp = get_conf_word(d, PCI_SUBSYSTEM_VENDOR_ID);
+ *subdp = get_conf_word(d, PCI_SUBSYSTEM_ID);
+ }
+ else if (htype == PCI_HEADER_TYPE_CARDBUS && d->config_cached >= 128)
+ {
+ *subvp = get_conf_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID);
+ *subdp = get_conf_word(d, PCI_CB_SUBSYSTEM_ID);
+ }
+ else
+ *subvp = *subdp = 0xffff;
+}
+
+static void
+show_terse(struct device *d)
+{
+ int c;
+ struct pci_dev *p = d->dev;
+ char classbuf[128], devbuf[128];
+
+ show_slot_name(d);
+ printf(" %s: %s",
+ pci_lookup_name(pacc, classbuf, sizeof(classbuf),
+ PCI_LOOKUP_CLASS,
+ p->device_class),
+ pci_lookup_name(pacc, devbuf, sizeof(devbuf),
+ PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
+ p->vendor_id, p->device_id));
+ if (c = get_conf_byte(d, PCI_REVISION_ID))
+ printf(" (rev %02x)", c);
+ if (verbose)
+ {
+ char *x;
+ c = get_conf_byte(d, PCI_CLASS_PROG);
+ x = pci_lookup_name(pacc, devbuf, sizeof(devbuf),
+ PCI_LOOKUP_PROGIF | PCI_LOOKUP_NO_NUMBERS,
+ p->device_class, c);
+ if (c || x)
+ {
+ printf(" (prog-if %02x", c);
+ if (x)
+ printf(" [%s]", x);
+ putchar(')');
+ }
+ }
+ putchar('\n');
+
+ if (verbose || opt_kernel)
+ {
+ word subsys_v, subsys_d;
+ char ssnamebuf[256];
+
+ pci_fill_info(p, PCI_FILL_LABEL);
+
+ if (p->label)
+ printf("\tDeviceName: %s", p->label);
+ get_subid(d, &subsys_v, &subsys_d);
+ if (subsys_v && subsys_v != 0xffff)
+ printf("\tSubsystem: %s\n",
+ pci_lookup_name(pacc, ssnamebuf, sizeof(ssnamebuf),
+ PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
+ p->vendor_id, p->device_id, subsys_v, subsys_d));
+ }
+}
+
+/*** Verbose output ***/
+
+static void
+show_size(u64 x)
+{
+ static const char suffix[][2] = { "", "K", "M", "G", "T" };
+ unsigned i;
+ if (!x)
+ return;
+ for (i = 0; i < (sizeof(suffix) / sizeof(*suffix) - 1); i++) {
+ if (x % 1024)
+ break;
+ x /= 1024;
+ }
+ printf(" [size=%u%s]", (unsigned)x, suffix[i]);
+}
+
+static void
+show_range(char *prefix, u64 base, u64 limit, int is_64bit)
+{
+ printf("%s:", prefix);
+ if (base <= limit || verbose > 2)
+ {
+ if (is_64bit)
+ printf(" %016" PCI_U64_FMT_X "-%016" PCI_U64_FMT_X, base, limit);
+ else
+ printf(" %08x-%08x", (unsigned) base, (unsigned) limit);
+ }
+ if (base <= limit)
+ show_size(limit - base + 1);
+ else
+ printf(" [disabled]");
+ putchar('\n');
+}
+
+static void
+show_bases(struct device *d, int cnt)
+{
+ struct pci_dev *p = d->dev;
+ word cmd = get_conf_word(d, PCI_COMMAND);
+ int i;
+ int virtual = 0;
+
+ for (i=0; i<cnt; i++)
+ {
+ pciaddr_t pos = p->base_addr[i];
+ pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->size[i] : 0;
+ pciaddr_t ioflg = (p->known_fields & PCI_FILL_IO_FLAGS) ? p->flags[i] : 0;
+ u32 flg = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
+ u32 hw_lower;
+ u32 hw_upper = 0;
+ int broken = 0;
+
+ if (flg == 0xffffffff)
+ flg = 0;
+ if (!pos && !flg && !len)
+ continue;
+
+ if (verbose > 1)
+ printf("\tRegion %d: ", i);
+ else
+ putchar('\t');
+
+ /* Read address as seen by the hardware */
+ if (flg & PCI_BASE_ADDRESS_SPACE_IO)
+ hw_lower = flg & PCI_BASE_ADDRESS_IO_MASK;
+ else
+ {
+ hw_lower = flg & PCI_BASE_ADDRESS_MEM_MASK;
+ if ((flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
+ {
+ if (i >= cnt - 1)
+ broken = 1;
+ else
+ {
+ i++;
+ hw_upper = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
+ }
+ }
+ }
+
+ /* Detect virtual regions, which are reported by the OS, but unassigned in the device */
+ if (pos && !hw_lower && !hw_upper && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
+ {
+ flg = pos;
+ virtual = 1;
+ }
+
+ /* Print base address */
+ if (flg & PCI_BASE_ADDRESS_SPACE_IO)
+ {
+ pciaddr_t a = pos & PCI_BASE_ADDRESS_IO_MASK;
+ printf("I/O ports at ");
+ if (a || (cmd & PCI_COMMAND_IO))
+ printf(PCIADDR_PORT_FMT, a);
+ else if (hw_lower)
+ printf("<ignored>");
+ else
+ printf("<unassigned>");
+ if (virtual)
+ printf(" [virtual]");
+ else if (!(cmd & PCI_COMMAND_IO))
+ printf(" [disabled]");
+ }
+ else
+ {
+ int t = flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+ pciaddr_t a = pos & PCI_ADDR_MEM_MASK;
+
+ printf("Memory at ");
+ if (broken)
+ printf("<broken-64-bit-slot>");
+ else if (a)
+ printf(PCIADDR_T_FMT, a);
+ else if (hw_lower || hw_upper)
+ printf("<ignored>");
+ else
+ printf("<unassigned>");
+ printf(" (%s, %sprefetchable)",
+ (t == PCI_BASE_ADDRESS_MEM_TYPE_32) ? "32-bit" :
+ (t == PCI_BASE_ADDRESS_MEM_TYPE_64) ? "64-bit" :
+ (t == PCI_BASE_ADDRESS_MEM_TYPE_1M) ? "low-1M" : "type 3",
+ (flg & PCI_BASE_ADDRESS_MEM_PREFETCH) ? "" : "non-");
+ if (virtual)
+ printf(" [virtual]");
+ else if (!(cmd & PCI_COMMAND_MEMORY))
+ printf(" [disabled]");
+ }
+
+ if (ioflg & PCI_IORESOURCE_PCI_EA_BEI)
+ printf(" [enhanced]");
+
+ show_size(len);
+ putchar('\n');
+ }
+}
+
+static void
+show_rom(struct device *d, int reg)
+{
+ struct pci_dev *p = d->dev;
+ pciaddr_t rom = p->rom_base_addr;
+ pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->rom_size : 0;
+ pciaddr_t ioflg = (p->known_fields & PCI_FILL_IO_FLAGS) ? p->rom_flags : 0;
+ u32 flg = get_conf_long(d, reg);
+ word cmd = get_conf_word(d, PCI_COMMAND);
+ int virtual = 0;
+
+ if (!rom && !flg && !len)
+ return;
+
+ if ((rom & PCI_ROM_ADDRESS_MASK) && !(flg & PCI_ROM_ADDRESS_MASK) && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
+ {
+ flg = rom;
+ virtual = 1;
+ }
+
+ printf("\tExpansion ROM at ");
+ if (rom & PCI_ROM_ADDRESS_MASK)
+ printf(PCIADDR_T_FMT, rom & PCI_ROM_ADDRESS_MASK);
+ else if (flg & PCI_ROM_ADDRESS_MASK)
+ printf("<ignored>");
+ else
+ printf("<unassigned>");
+
+ if (virtual)
+ printf(" [virtual]");
+
+ if (!(flg & PCI_ROM_ADDRESS_ENABLE))
+ printf(" [disabled]");
+ else if (!virtual && !(cmd & PCI_COMMAND_MEMORY))
+ printf(" [disabled by cmd]");
+
+ if (ioflg & PCI_IORESOURCE_PCI_EA_BEI)
+ printf(" [enhanced]");
+
+ show_size(len);
+ putchar('\n');
+}
+
+static void
+show_htype0(struct device *d)
+{
+ show_bases(d, 6);
+ show_rom(d, PCI_ROM_ADDRESS);
+ show_caps(d, PCI_CAPABILITY_LIST);
+}
+
+static void
+show_htype1(struct device *d)
+{
+ u32 io_base = get_conf_byte(d, PCI_IO_BASE);
+ u32 io_limit = get_conf_byte(d, PCI_IO_LIMIT);
+ u32 io_type = io_base & PCI_IO_RANGE_TYPE_MASK;
+ u32 mem_base = get_conf_word(d, PCI_MEMORY_BASE);
+ u32 mem_limit = get_conf_word(d, PCI_MEMORY_LIMIT);
+ u32 mem_type = mem_base & PCI_MEMORY_RANGE_TYPE_MASK;
+ u32 pref_base = get_conf_word(d, PCI_PREF_MEMORY_BASE);
+ u32 pref_limit = get_conf_word(d, PCI_PREF_MEMORY_LIMIT);
+ u32 pref_type = pref_base & PCI_PREF_RANGE_TYPE_MASK;
+ word sec_stat = get_conf_word(d, PCI_SEC_STATUS);
+ word brc = get_conf_word(d, PCI_BRIDGE_CONTROL);
+
+ show_bases(d, 2);
+ printf("\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%d\n",
+ get_conf_byte(d, PCI_PRIMARY_BUS),
+ get_conf_byte(d, PCI_SECONDARY_BUS),
+ get_conf_byte(d, PCI_SUBORDINATE_BUS),
+ get_conf_byte(d, PCI_SEC_LATENCY_TIMER));
+
+ if (io_type != (io_limit & PCI_IO_RANGE_TYPE_MASK) ||
+ (io_type != PCI_IO_RANGE_TYPE_16 && io_type != PCI_IO_RANGE_TYPE_32))
+ printf("\t!!! Unknown I/O range types %x/%x\n", io_base, io_limit);
+ else
+ {
+ io_base = (io_base & PCI_IO_RANGE_MASK) << 8;
+ io_limit = (io_limit & PCI_IO_RANGE_MASK) << 8;
+ if (io_type == PCI_IO_RANGE_TYPE_32)
+ {
+ io_base |= (get_conf_word(d, PCI_IO_BASE_UPPER16) << 16);
+ io_limit |= (get_conf_word(d, PCI_IO_LIMIT_UPPER16) << 16);
+ }
+ show_range("\tI/O behind bridge", io_base, io_limit+0xfff, 0);
+ }
+
+ if (mem_type != (mem_limit & PCI_MEMORY_RANGE_TYPE_MASK) ||
+ mem_type)
+ printf("\t!!! Unknown memory range types %x/%x\n", mem_base, mem_limit);
+ else
+ {
+ mem_base = (mem_base & PCI_MEMORY_RANGE_MASK) << 16;
+ mem_limit = (mem_limit & PCI_MEMORY_RANGE_MASK) << 16;
+ show_range("\tMemory behind bridge", mem_base, mem_limit + 0xfffff, 0);
+ }
+
+ if (pref_type != (pref_limit & PCI_PREF_RANGE_TYPE_MASK) ||
+ (pref_type != PCI_PREF_RANGE_TYPE_32 && pref_type != PCI_PREF_RANGE_TYPE_64))
+ printf("\t!!! Unknown prefetchable memory range types %x/%x\n", pref_base, pref_limit);
+ else
+ {
+ u64 pref_base_64 = (pref_base & PCI_PREF_RANGE_MASK) << 16;
+ u64 pref_limit_64 = (pref_limit & PCI_PREF_RANGE_MASK) << 16;
+ if (pref_type == PCI_PREF_RANGE_TYPE_64)
+ {
+ pref_base_64 |= (u64) get_conf_long(d, PCI_PREF_BASE_UPPER32) << 32;
+ pref_limit_64 |= (u64) get_conf_long(d, PCI_PREF_LIMIT_UPPER32) << 32;
+ }
+ show_range("\tPrefetchable memory behind bridge", pref_base_64, pref_limit_64 + 0xfffff, (pref_type == PCI_PREF_RANGE_TYPE_64));
+ }
+
+ if (verbose > 1)
+ printf("\tSecondary status: 66MHz%c FastB2B%c ParErr%c DEVSEL=%s >TAbort%c <TAbort%c <MAbort%c <SERR%c <PERR%c\n",
+ FLAG(sec_stat, PCI_STATUS_66MHZ),
+ FLAG(sec_stat, PCI_STATUS_FAST_BACK),
+ FLAG(sec_stat, PCI_STATUS_PARITY),
+ ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
+ ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
+ ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??",
+ FLAG(sec_stat, PCI_STATUS_SIG_TARGET_ABORT),
+ FLAG(sec_stat, PCI_STATUS_REC_TARGET_ABORT),
+ FLAG(sec_stat, PCI_STATUS_REC_MASTER_ABORT),
+ FLAG(sec_stat, PCI_STATUS_SIG_SYSTEM_ERROR),
+ FLAG(sec_stat, PCI_STATUS_DETECTED_PARITY));
+
+ show_rom(d, PCI_ROM_ADDRESS1);
+
+ if (verbose > 1)
+ {
+ printf("\tBridgeCtl: Parity%c SERR%c NoISA%c VGA%c VGA16%c MAbort%c >Reset%c FastB2B%c\n",
+ FLAG(brc, PCI_BRIDGE_CTL_PARITY),
+ FLAG(brc, PCI_BRIDGE_CTL_SERR),
+ FLAG(brc, PCI_BRIDGE_CTL_NO_ISA),
+ FLAG(brc, PCI_BRIDGE_CTL_VGA),
+ FLAG(brc, PCI_BRIDGE_CTL_VGA_16BIT),
+ FLAG(brc, PCI_BRIDGE_CTL_MASTER_ABORT),
+ FLAG(brc, PCI_BRIDGE_CTL_BUS_RESET),
+ FLAG(brc, PCI_BRIDGE_CTL_FAST_BACK));
+ printf("\t\tPriDiscTmr%c SecDiscTmr%c DiscTmrStat%c DiscTmrSERREn%c\n",
+ FLAG(brc, PCI_BRIDGE_CTL_PRI_DISCARD_TIMER),
+ FLAG(brc, PCI_BRIDGE_CTL_SEC_DISCARD_TIMER),
+ FLAG(brc, PCI_BRIDGE_CTL_DISCARD_TIMER_STATUS),
+ FLAG(brc, PCI_BRIDGE_CTL_DISCARD_TIMER_SERR_EN));
+ }
+
+ show_caps(d, PCI_CAPABILITY_LIST);
+}
+
+static void
+show_htype2(struct device *d)
+{
+ int i;
+ word cmd = get_conf_word(d, PCI_COMMAND);
+ word brc = get_conf_word(d, PCI_CB_BRIDGE_CONTROL);
+ word exca;
+ int verb = verbose > 2;
+
+ show_bases(d, 1);
+ printf("\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%d\n",
+ get_conf_byte(d, PCI_CB_PRIMARY_BUS),
+ get_conf_byte(d, PCI_CB_CARD_BUS),
+ get_conf_byte(d, PCI_CB_SUBORDINATE_BUS),
+ get_conf_byte(d, PCI_CB_LATENCY_TIMER));
+ for (i=0; i<2; i++)
+ {
+ int p = 8*i;
+ u32 base = get_conf_long(d, PCI_CB_MEMORY_BASE_0 + p);
+ u32 limit = get_conf_long(d, PCI_CB_MEMORY_LIMIT_0 + p);
+ limit = limit + 0xfff;
+ if (base <= limit || verb)
+ printf("\tMemory window %d: %08x-%08x%s%s\n", i, base, limit,
+ (cmd & PCI_COMMAND_MEMORY) ? "" : " [disabled]",
+ (brc & (PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 << i)) ? " (prefetchable)" : "");
+ }
+ for (i=0; i<2; i++)
+ {
+ int p = 8*i;
+ u32 base = get_conf_long(d, PCI_CB_IO_BASE_0 + p);
+ u32 limit = get_conf_long(d, PCI_CB_IO_LIMIT_0 + p);
+ if (!(base & PCI_IO_RANGE_TYPE_32))
+ {
+ base &= 0xffff;
+ limit &= 0xffff;
+ }
+ base &= PCI_CB_IO_RANGE_MASK;
+ limit = (limit & PCI_CB_IO_RANGE_MASK) + 3;
+ if (base <= limit || verb)
+ printf("\tI/O window %d: %08x-%08x%s\n", i, base, limit,
+ (cmd & PCI_COMMAND_IO) ? "" : " [disabled]");
+ }
+
+ if (get_conf_word(d, PCI_CB_SEC_STATUS) & PCI_STATUS_SIG_SYSTEM_ERROR)
+ printf("\tSecondary status: SERR\n");
+ if (verbose > 1)
+ printf("\tBridgeCtl: Parity%c SERR%c ISA%c VGA%c MAbort%c >Reset%c 16bInt%c PostWrite%c\n",
+ FLAG(brc, PCI_CB_BRIDGE_CTL_PARITY),
+ FLAG(brc, PCI_CB_BRIDGE_CTL_SERR),
+ FLAG(brc, PCI_CB_BRIDGE_CTL_ISA),
+ FLAG(brc, PCI_CB_BRIDGE_CTL_VGA),
+ FLAG(brc, PCI_CB_BRIDGE_CTL_MASTER_ABORT),
+ FLAG(brc, PCI_CB_BRIDGE_CTL_CB_RESET),
+ FLAG(brc, PCI_CB_BRIDGE_CTL_16BIT_INT),
+ FLAG(brc, PCI_CB_BRIDGE_CTL_POST_WRITES));
+
+ if (d->config_cached < 128)
+ {
+ printf("\t<access denied to the rest>\n");
+ return;
+ }
+
+ exca = get_conf_word(d, PCI_CB_LEGACY_MODE_BASE);
+ if (exca)
+ printf("\t16-bit legacy interface ports at %04x\n", exca);
+ show_caps(d, PCI_CB_CAPABILITY_LIST);
+}
+
+static void
+show_verbose(struct device *d)
+{
+ struct pci_dev *p = d->dev;
+ word status = get_conf_word(d, PCI_STATUS);
+ word cmd = get_conf_word(d, PCI_COMMAND);
+ word class = p->device_class;
+ byte bist = get_conf_byte(d, PCI_BIST);
+ byte htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
+ byte latency = get_conf_byte(d, PCI_LATENCY_TIMER);
+ byte cache_line = get_conf_byte(d, PCI_CACHE_LINE_SIZE);
+ byte max_lat, min_gnt;
+ byte int_pin = get_conf_byte(d, PCI_INTERRUPT_PIN);
+ unsigned int irq;
+ char *dt_node, *iommu_group;
+
+ show_terse(d);
+
+ pci_fill_info(p, PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES |
+ PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE | PCI_FILL_IOMMU_GROUP);
+ irq = p->irq;
+
+ switch (htype)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ if (class == PCI_CLASS_BRIDGE_PCI)
+ printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
+ max_lat = get_conf_byte(d, PCI_MAX_LAT);
+ min_gnt = get_conf_byte(d, PCI_MIN_GNT);
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
+ printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
+ min_gnt = max_lat = 0;
+ break;
+ case PCI_HEADER_TYPE_CARDBUS:
+ if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
+ printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
+ min_gnt = max_lat = 0;
+ break;
+ default:
+ printf("\t!!! Unknown header type %02x\n", htype);
+ return;
+ }
+
+ if (p->phy_slot)
+ printf("\tPhysical Slot: %s\n", p->phy_slot);
+
+ if (dt_node = pci_get_string_property(p, PCI_FILL_DT_NODE))
+ printf("\tDevice tree node: %s\n", dt_node);
+
+ if (verbose > 1)
+ {
+ printf("\tControl: I/O%c Mem%c BusMaster%c SpecCycle%c MemWINV%c VGASnoop%c ParErr%c Stepping%c SERR%c FastB2B%c DisINTx%c\n",
+ FLAG(cmd, PCI_COMMAND_IO),
+ FLAG(cmd, PCI_COMMAND_MEMORY),
+ FLAG(cmd, PCI_COMMAND_MASTER),
+ FLAG(cmd, PCI_COMMAND_SPECIAL),
+ FLAG(cmd, PCI_COMMAND_INVALIDATE),
+ FLAG(cmd, PCI_COMMAND_VGA_PALETTE),
+ FLAG(cmd, PCI_COMMAND_PARITY),
+ FLAG(cmd, PCI_COMMAND_WAIT),
+ FLAG(cmd, PCI_COMMAND_SERR),
+ FLAG(cmd, PCI_COMMAND_FAST_BACK),
+ FLAG(cmd, PCI_COMMAND_DISABLE_INTx));
+ printf("\tStatus: Cap%c 66MHz%c UDF%c FastB2B%c ParErr%c DEVSEL=%s >TAbort%c <TAbort%c <MAbort%c >SERR%c <PERR%c INTx%c\n",
+ FLAG(status, PCI_STATUS_CAP_LIST),
+ FLAG(status, PCI_STATUS_66MHZ),
+ FLAG(status, PCI_STATUS_UDF),
+ FLAG(status, PCI_STATUS_FAST_BACK),
+ FLAG(status, PCI_STATUS_PARITY),
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??",
+ FLAG(status, PCI_STATUS_SIG_TARGET_ABORT),
+ FLAG(status, PCI_STATUS_REC_TARGET_ABORT),
+ FLAG(status, PCI_STATUS_REC_MASTER_ABORT),
+ FLAG(status, PCI_STATUS_SIG_SYSTEM_ERROR),
+ FLAG(status, PCI_STATUS_DETECTED_PARITY),
+ FLAG(status, PCI_STATUS_INTx));
+ if (cmd & PCI_COMMAND_MASTER)
+ {
+ printf("\tLatency: %d", latency);
+ if (min_gnt || max_lat)
+ {
+ printf(" (");
+ if (min_gnt)
+ printf("%dns min", min_gnt*250);
+ if (min_gnt && max_lat)
+ printf(", ");
+ if (max_lat)
+ printf("%dns max", max_lat*250);
+ putchar(')');
+ }
+ if (cache_line)
+ printf(", Cache Line Size: %d bytes", cache_line * 4);
+ putchar('\n');
+ }
+ if (int_pin || irq)
+ printf("\tInterrupt: pin %c routed to IRQ " PCIIRQ_FMT "\n",
+ (int_pin ? 'A' + int_pin - 1 : '?'), irq);
+ if (p->numa_node != -1)
+ printf("\tNUMA node: %d\n", p->numa_node);
+ if (iommu_group = pci_get_string_property(p, PCI_FILL_IOMMU_GROUP))
+ printf("\tIOMMU group: %s\n", iommu_group);
+ }
+ else
+ {
+ printf("\tFlags: ");
+ if (cmd & PCI_COMMAND_MASTER)
+ printf("bus master, ");
+ if (cmd & PCI_COMMAND_VGA_PALETTE)
+ printf("VGA palette snoop, ");
+ if (cmd & PCI_COMMAND_WAIT)
+ printf("stepping, ");
+ if (cmd & PCI_COMMAND_FAST_BACK)
+ printf("fast Back2Back, ");
+ if (status & PCI_STATUS_66MHZ)
+ printf("66MHz, ");
+ if (status & PCI_STATUS_UDF)
+ printf("user-definable features, ");
+ printf("%s devsel",
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
+ ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??");
+ if (cmd & PCI_COMMAND_MASTER)
+ printf(", latency %d", latency);
+ if (irq)
+ printf(", IRQ " PCIIRQ_FMT, irq);
+ if (p->numa_node != -1)
+ printf(", NUMA node %d", p->numa_node);
+ if (iommu_group = pci_get_string_property(p, PCI_FILL_IOMMU_GROUP))
+ printf(", IOMMU group %s", iommu_group);
+ putchar('\n');
+ }
+
+ if (bist & PCI_BIST_CAPABLE)
+ {
+ if (bist & PCI_BIST_START)
+ printf("\tBIST is running\n");
+ else
+ printf("\tBIST result: %02x\n", bist & PCI_BIST_CODE_MASK);
+ }
+
+ switch (htype)
+ {
+ case PCI_HEADER_TYPE_NORMAL:
+ show_htype0(d);
+ break;
+ case PCI_HEADER_TYPE_BRIDGE:
+ show_htype1(d);
+ break;
+ case PCI_HEADER_TYPE_CARDBUS:
+ show_htype2(d);
+ break;
+ }
+}
+
+/*** Machine-readable dumps ***/
+
+static void
+show_hex_dump(struct device *d)
+{
+ unsigned int i, cnt;
+
+ cnt = d->config_cached;
+ if (opt_hex >= 3 && config_fetch(d, cnt, 256-cnt))
+ {
+ cnt = 256;
+ if (opt_hex >= 4 && config_fetch(d, 256, 4096-256))
+ cnt = 4096;
+ }
+
+ for (i=0; i<cnt; i++)
+ {
+ if (! (i & 15))
+ printf("%02x:", i);
+ printf(" %02x", get_conf_byte(d, i));
+ if ((i & 15) == 15)
+ putchar('\n');
+ }
+}
+
+static void
+print_shell_escaped(char *c)
+{
+ printf(" \"");
+ while (*c)
+ {
+ if (*c == '"' || *c == '\\')
+ putchar('\\');
+ putchar(*c++);
+ }
+ putchar('"');
+}
+
+static void
+show_machine(struct device *d)
+{
+ struct pci_dev *p = d->dev;
+ int c;
+ word sv_id, sd_id;
+ char classbuf[128], vendbuf[128], devbuf[128], svbuf[128], sdbuf[128];
+ char *dt_node, *iommu_group;
+
+ get_subid(d, &sv_id, &sd_id);
+
+ if (verbose)
+ {
+ pci_fill_info(p, PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE | PCI_FILL_IOMMU_GROUP);
+ printf((opt_machine >= 2) ? "Slot:\t" : "Device:\t");
+ show_slot_name(d);
+ putchar('\n');
+ printf("Class:\t%s\n",
+ pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, p->device_class));
+ printf("Vendor:\t%s\n",
+ pci_lookup_name(pacc, vendbuf, sizeof(vendbuf), PCI_LOOKUP_VENDOR, p->vendor_id, p->device_id));
+ printf("Device:\t%s\n",
+ pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id));
+ if (sv_id && sv_id != 0xffff)
+ {
+ printf("SVendor:\t%s\n",
+ pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, sv_id));
+ printf("SDevice:\t%s\n",
+ pci_lookup_name(pacc, sdbuf, sizeof(sdbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id, sv_id, sd_id));
+ }
+ if (p->phy_slot)
+ printf("PhySlot:\t%s\n", p->phy_slot);
+ if (c = get_conf_byte(d, PCI_REVISION_ID))
+ printf("Rev:\t%02x\n", c);
+ if (c = get_conf_byte(d, PCI_CLASS_PROG))
+ printf("ProgIf:\t%02x\n", c);
+ if (opt_kernel)
+ show_kernel_machine(d);
+ if (p->numa_node != -1)
+ printf("NUMANode:\t%d\n", p->numa_node);
+ if (dt_node = pci_get_string_property(p, PCI_FILL_DT_NODE))
+ printf("DTNode:\t%s\n", dt_node);
+ if (iommu_group = pci_get_string_property(p, PCI_FILL_IOMMU_GROUP))
+ printf("IOMMUGroup:\t%s\n", iommu_group);
+ }
+ else
+ {
+ show_slot_name(d);
+ print_shell_escaped(pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, p->device_class));
+ print_shell_escaped(pci_lookup_name(pacc, vendbuf, sizeof(vendbuf), PCI_LOOKUP_VENDOR, p->vendor_id, p->device_id));
+ print_shell_escaped(pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id));
+ if (c = get_conf_byte(d, PCI_REVISION_ID))
+ printf(" -r%02x", c);
+ if (c = get_conf_byte(d, PCI_CLASS_PROG))
+ printf(" -p%02x", c);
+ if (sv_id && sv_id != 0xffff)
+ {
+ print_shell_escaped(pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, sv_id));
+ print_shell_escaped(pci_lookup_name(pacc, sdbuf, sizeof(sdbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id, sv_id, sd_id));
+ }
+ else
+ printf(" \"\" \"\"");
+ putchar('\n');
+ }
+}
+
+/*** Main show function ***/
+
+void
+show_device(struct device *d)
+{
+ if (opt_machine)
+ show_machine(d);
+ else
+ {
+ if (verbose)
+ show_verbose(d);
+ else
+ show_terse(d);
+ if (opt_kernel || verbose)
+ show_kernel(d);
+ }
+ if (opt_hex)
+ show_hex_dump(d);
+ if (verbose || opt_hex)
+ putchar('\n');
+}
+
+static void
+show(void)
+{
+ struct device *d;
+
+ for (d=first_dev; d; d=d->next)
+ if (pci_filter_match(&filter, d->dev))
+ show_device(d);
+}
+
+/* Main */
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ char *msg;
+
+ if (argc == 2 && !strcmp(argv[1], "--version"))
+ {
+ puts("lspci version " PCIUTILS_VERSION);
+ return 0;
+ }
+
+ pacc = pci_alloc();
+ pacc->error = die;
+ pci_filter_init(pacc, &filter);
+
+ while ((i = getopt(argc, argv, options)) != -1)
+ switch (i)
+ {
+ case 'n':
+ pacc->numeric_ids++;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'b':
+ pacc->buscentric = 1;
+ break;
+ case 's':
+ if (msg = pci_filter_parse_slot(&filter, optarg))
+ die("-s: %s", msg);
+ opt_filter = 1;
+ break;
+ case 'd':
+ if (msg = pci_filter_parse_id(&filter, optarg))
+ die("-d: %s", msg);
+ opt_filter = 1;
+ break;
+ case 'x':
+ opt_hex++;
+ break;
+ case 'P':
+ opt_path++;
+ need_topology = 1;
+ break;
+ case 't':
+ opt_tree++;
+ need_topology = 1;
+ break;
+ case 'i':
+ pci_set_name_list_path(pacc, optarg, 0);
+ break;
+ case 'm':
+ opt_machine++;
+ break;
+ case 'p':
+ opt_pcimap = optarg;
+ break;
+#ifdef PCI_OS_LINUX
+ case 'k':
+ opt_kernel++;
+ break;
+#endif
+ case 'M':
+ opt_map_mode++;
+ break;
+ case 'D':
+ opt_domains = 2;
+ break;
+#ifdef PCI_USE_DNS
+ case 'q':
+ opt_query_dns++;
+ break;
+ case 'Q':
+ opt_query_all = 1;
+ break;
+#else
+ case 'q':
+ case 'Q':
+ die("DNS queries are not available in this version");
+#endif
+ default:
+ if (parse_generic_option(i, pacc, optarg))
+ break;
+ bad:
+ fprintf(stderr, help_msg, pacc->id_file_name);
+ return 1;
+ }
+ if (optind < argc)
+ goto bad;
+
+ if (opt_query_dns)
+ {
+ pacc->id_lookup_mode |= PCI_LOOKUP_NETWORK;
+ if (opt_query_dns > 1)
+ pacc->id_lookup_mode |= PCI_LOOKUP_REFRESH_CACHE;
+ }
+ if (opt_query_all)
+ pacc->id_lookup_mode |= PCI_LOOKUP_NETWORK | PCI_LOOKUP_SKIP_LOCAL;
+
+ pci_init(pacc);
+ if (opt_map_mode)
+ {
+ if (need_topology)
+ die("Bus mapping mode does not recognize bus topology");
+ map_the_bus();
+ }
+ else
+ {
+ scan_devices();
+ sort_them();
+ if (need_topology)
+ grow_tree();
+ if (opt_tree)
+ show_forest(opt_filter ? &filter : NULL);
+ else
+ show();
+ }
+ show_kernel_cleanup();
+ pci_cleanup(pacc);
+
+ return (seen_errors ? 2 : 0);
+}
diff --git a/lspci.h b/lspci.h
new file mode 100644
index 0000000..fefee52
--- /dev/null
+++ b/lspci.h
@@ -0,0 +1,114 @@
+/*
+ * The PCI Utilities -- List All PCI Devices
+ *
+ * Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#define PCIUTILS_LSPCI
+#include "pciutils.h"
+
+/*
+ * If we aren't being compiled by GCC, use xmalloc() instead of alloca().
+ * This increases our memory footprint, but only slightly since we don't
+ * use alloca() much.
+ */
+#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__DragonFly__) || defined (__DJGPP__)
+/* alloca() is defined in stdlib.h */
+#elif defined(__GNUC__) && !defined(PCI_OS_WINDOWS)
+#include <alloca.h>
+#else
+#undef alloca
+#define alloca xmalloc
+#endif
+
+/*** Options ***/
+
+extern int verbose;
+extern struct pci_filter filter;
+extern char *opt_pcimap;
+
+/*** PCI devices and access to their config space ***/
+
+struct device {
+ struct device *next;
+ struct pci_dev *dev;
+ /* Bus topology calculated by grow_tree() */
+ struct device *bus_next;
+ struct bus *parent_bus;
+ struct bridge *bridge;
+ /* Cache */
+ unsigned int config_cached, config_bufsize;
+ byte *config; /* Cached configuration space data */
+ byte *present; /* Maps which configuration bytes are present */
+};
+
+extern struct device *first_dev;
+extern struct pci_access *pacc;
+
+struct device *scan_device(struct pci_dev *p);
+void show_device(struct device *d);
+
+int config_fetch(struct device *d, unsigned int pos, unsigned int len);
+u32 get_conf_long(struct device *d, unsigned int pos);
+word get_conf_word(struct device *d, unsigned int pos);
+byte get_conf_byte(struct device *d, unsigned int pos);
+
+void get_subid(struct device *d, word *subvp, word *subdp);
+
+/* Useful macros for decoding of bits and bit fields */
+
+#define FLAG(x,y) ((x & y) ? '+' : '-')
+#define BITS(x,at,width) (((x) >> (at)) & ((1 << (width)) - 1))
+#define TABLE(tab,x,buf) ((x) < sizeof(tab)/sizeof((tab)[0]) ? (tab)[x] : (sprintf((buf), "??%d", (x)), (buf)))
+
+/* ls-vpd.c */
+
+void cap_vpd(struct device *d);
+
+/* ls-caps.c */
+
+void show_caps(struct device *d, int where);
+
+/* ls-ecaps.c */
+
+void show_ext_caps(struct device *d, int type);
+
+/* ls-caps-vendor.c */
+
+void show_vendor_caps(struct device *d, int where, int cap);
+
+/* ls-kernel.c */
+
+void show_kernel_machine(struct device *d UNUSED);
+void show_kernel(struct device *d UNUSED);
+void show_kernel_cleanup(void);
+
+/* ls-tree.c */
+
+struct bridge {
+ struct bridge *chain; /* Single-linked list of bridges */
+ struct bridge *next, *child; /* Tree of bridges */
+ struct bus *first_bus; /* List of buses connected to this bridge */
+ unsigned int domain;
+ unsigned int primary, secondary, subordinate; /* Bus numbers */
+ struct device *br_dev;
+};
+
+struct bus {
+ unsigned int domain;
+ unsigned int number;
+ struct bus *sibling;
+ struct bridge *parent_bridge;
+ struct device *first_dev, **last_dev;
+};
+
+extern struct bridge host_bridge;
+
+void grow_tree(void);
+void show_forest(struct pci_filter *filter);
+
+/* ls-map.c */
+
+void map_the_bus(void);
diff --git a/lspci.man b/lspci.man
new file mode 100644
index 0000000..255a13a
--- /dev/null
+++ b/lspci.man
@@ -0,0 +1,369 @@
+.TH lspci 8 "@TODAY@" "@VERSION@" "The PCI Utilities"
+.SH NAME
+lspci \- list all PCI devices
+.SH SYNOPSIS
+.B lspci
+.RB [ options ]
+.SH DESCRIPTION
+.B lspci
+is a utility for displaying information about PCI buses in the system and
+devices connected to them.
+
+By default, it shows a brief list of devices. Use the options described
+below to request either a more verbose output or output intended for
+parsing by other programs.
+
+If you are going to report bugs in PCI device drivers or in
+.I lspci
+itself, please include output of "lspci -vvx" or even better "lspci -vvxxx"
+(however, see below for possible caveats).
+
+Some parts of the output, especially in the highly verbose modes, are probably
+intelligible only to experienced PCI hackers. For exact definitions of
+the fields, please consult either the PCI specifications or the
+.B header.h
+and
+.B /usr/include/linux/pci.h
+include files.
+
+Access to some parts of the PCI configuration space is restricted to root
+on many operating systems, so the features of
+.I lspci
+available to normal users are limited. However,
+.I lspci
+tries its best to display as much as available and mark all other
+information with
+.I <access denied>
+text.
+
+.SH OPTIONS
+
+.SS Basic display modes
+.TP
+.B -m
+Dump PCI device data in a backward-compatible machine readable form.
+See below for details.
+.TP
+.B -mm
+Dump PCI device data in a machine readable form for easy parsing by scripts.
+See below for details.
+.TP
+.B -t
+Show a tree-like diagram containing all buses, bridges, devices and connections
+between them.
+
+.SS Display options
+.TP
+.B -v
+Be verbose and display detailed information about all devices.
+.TP
+.B -vv
+Be very verbose and display more details. This level includes everything deemed
+useful.
+.TP
+.B -vvv
+Be even more verbose and display everything we are able to parse,
+even if it doesn't look interesting at all (e.g., undefined memory regions).
+.TP
+.B -k
+Show kernel drivers handling each device and also kernel modules capable of handling it.
+Turned on by default when
+.B -v
+is given in the normal mode of output.
+(Currently works only on Linux with kernel 2.6 or newer.)
+.TP
+.B -x
+Show hexadecimal dump of the standard part of the configuration space (the first
+64 bytes or 128 bytes for CardBus bridges).
+.TP
+.B -xxx
+Show hexadecimal dump of the whole PCI configuration space. It is available only to root
+as several PCI devices
+.B crash
+when you try to read some parts of the config space (this behavior probably
+doesn't violate the PCI standard, but it's at least very stupid). However, such
+devices are rare, so you needn't worry much.
+.TP
+.B -xxxx
+Show hexadecimal dump of the extended (4096-byte) PCI configuration space available
+on PCI-X 2.0 and PCI Express buses.
+.TP
+.B -b
+Bus-centric view. Show all IRQ numbers and addresses as seen by the cards on the
+PCI bus instead of as seen by the kernel.
+.TP
+.B -D
+Always show PCI domain numbers. By default, lspci suppresses them on machines which
+have only domain 0.
+.TP
+.B -P
+Identify PCI devices by path through each bridge, instead of by bus number.
+.TP
+.B -PP
+Identify PCI devices by path through each bridge, showing the bus number as
+well as the device number.
+
+.SS Options to control resolving ID's to names
+.TP
+.B -n
+Show PCI vendor and device codes as numbers instead of looking them up in the
+PCI ID list.
+.TP
+.B -nn
+Show PCI vendor and device codes as both numbers and names.
+.TP
+.B -q
+Use DNS to query the central PCI ID database if a device is not found in the local
+.B pci.ids
+file. If the DNS query succeeds, the result is cached in
+.B ~/.pciids-cache
+and it is recognized in subsequent runs even if
+.B -q
+is not given any more. Please use this switch inside automated scripts only
+with caution to avoid overloading the database servers.
+.TP
+.B -qq
+Same as
+.BR -q ,
+but the local cache is reset.
+.TP
+.B -Q
+Query the central database even for entries which are recognized locally.
+Use this if you suspect that the displayed entry is wrong.
+
+.SS Options for selection of devices
+.TP
+.B -s [[[[<domain>]:]<bus>]:][<device>][.[<func>]]
+Show only devices in the specified domain (in case your machine has several host bridges,
+they can either share a common bus number space or each of them can address a PCI domain
+of its own; domains are numbered from 0 to ffff), bus (0 to ff), device (0 to 1f) and function (0 to 7).
+Each component of the device address can be omitted or set to "*", both meaning "any value". All numbers are
+hexadecimal. E.g., "0:" means all devices on bus 0, "0" means all functions of device 0
+on any bus, "0.3" selects third function of device 0 on all buses and ".4" shows only
+the fourth function of each device.
+.TP
+.B -d [<vendor>]:[<device>][:<class>]
+Show only devices with specified vendor, device and class ID. The ID's are
+given in hexadecimal and may be omitted or given as "*", both meaning
+"any value".
+
+.SS Other options
+.TP
+.B -i <file>
+Use
+.B
+<file>
+as the PCI ID list instead of @IDSDIR@/pci.ids.
+.TP
+.B -p <file>
+Use
+.B
+<file>
+as the map of PCI ID's handled by kernel modules. By default, lspci uses
+.RI /lib/modules/ kernel_version /modules.pcimap.
+Applies only to Linux systems with recent enough module tools.
+.TP
+.B -M
+Invoke bus mapping mode which performs a thorough scan of all PCI devices, including
+those behind misconfigured bridges, etc. This option gives meaningful results only
+with a direct hardware access mode, which usually requires root privileges.
+Please note that the bus mapper only scans PCI domain 0.
+.TP
+.B --version
+Shows
+.I lspci
+version. This option should be used stand-alone.
+
+.SS PCI access options
+.PP
+The PCI utilities use the PCI library to talk to PCI devices (see
+\fBpcilib\fP(7) for details). You can use the following options to
+influence its behavior:
+.TP
+.B -A <method>
+The library supports a variety of methods to access the PCI hardware.
+By default, it uses the first access method available, but you can use
+this option to override this decision. See \fB-A help\fP for a list of
+available methods and their descriptions.
+.TP
+.B -O <param>=<value>
+The behavior of the library is controlled by several named parameters.
+This option allows to set the value of any of the parameters. Use \fB-O help\fP
+for a list of known parameters and their default values.
+.TP
+.B -H1
+Use direct hardware access via Intel configuration mechanism 1.
+(This is a shorthand for \fB-A intel-conf1\fP.)
+.TP
+.B -H2
+Use direct hardware access via Intel configuration mechanism 2.
+(This is a shorthand for \fB-A intel-conf2\fP.)
+.TP
+.B -F <file>
+Instead of accessing real hardware, read the list of devices and values of their
+configuration registers from the given file produced by an earlier run of lspci -x.
+This is very useful for analysis of user-supplied bug reports, because you can display
+the hardware configuration in any way you want without disturbing the user with
+requests for more dumps.
+.TP
+.B -G
+Increase debug level of the library.
+
+.SH MACHINE READABLE OUTPUT
+If you intend to process the output of lspci automatically, please use one of the
+machine-readable output formats
+.RB ( -m ,
+.BR -vm ,
+.BR -vmm )
+described in this section. All other formats are likely to change
+between versions of lspci.
+
+.P
+All numbers are always printed in hexadecimal. If you want to process numeric ID's instead of
+names, please add the
+.B -n
+switch.
+
+.SS Simple format (-m)
+
+In the simple format, each device is described on a single line, which is
+formatted as parameters suitable for passing to a shell script, i.e., values
+separated by whitespaces, quoted and escaped if necessary.
+Some of the arguments are positional: slot, class, vendor name, device name,
+subsystem vendor name and subsystem name (the last two are empty if
+the device has no subsystem); the remaining arguments are option-like:
+
+.TP
+.BI -r rev
+Revision number.
+
+.TP
+.BI -p progif
+Programming interface.
+
+.P
+The relative order of positional arguments and options is undefined.
+New options can be added in future versions, but they will always
+have a single argument not separated from the option by any spaces,
+so they can be easily ignored if not recognized.
+
+.SS Verbose format (-vmm)
+
+The verbose output is a sequence of records separated by blank lines.
+Each record describes a single device by a sequence of lines, each line
+containing a single
+.RI ` tag :
+.IR value '
+pair. The
+.I tag
+and the
+.I value
+are separated by a single tab character.
+Neither the records nor the lines within a record are in any particular order.
+Tags are case-sensitive.
+
+.P
+The following tags are defined:
+
+.TP
+.B Slot
+The name of the slot where the device resides
+.RI ([ domain :] bus : device . function ).
+This tag is always the first in a record.
+
+.TP
+.B Class
+Name of the class.
+
+.TP
+.B Vendor
+Name of the vendor.
+
+.TP
+.B Device
+Name of the device.
+
+.TP
+.B SVendor
+Name of the subsystem vendor (optional).
+
+.TP
+.B SDevice
+Name of the subsystem (optional).
+
+.TP
+.B PhySlot
+The physical slot where the device resides (optional, Linux only).
+
+.TP
+.B Rev
+Revision number (optional).
+
+.TP
+.B ProgIf
+Programming interface (optional).
+
+.TP
+.B Driver
+Kernel driver currently handling the device (optional, Linux only).
+
+.TP
+.B Module
+Kernel module reporting that it is capable of handling the device
+(optional, Linux only). Multiple lines with this tag can occur.
+
+.TP
+.B NUMANode
+NUMA node this device is connected to (optional, Linux only).
+
+.TP
+.B IOMMUGroup
+IOMMU group that this device is part of (optional, Linux only).
+
+.P
+New tags can be added in future versions, so you should silently ignore any tags you don't recognize.
+
+.SS Backward-compatible verbose format (-vm)
+
+In this mode, lspci tries to be perfectly compatible with its old versions.
+It's almost the same as the regular verbose format, but the
+.B
+Device
+tag is used for both the slot and the device name, so it occurs twice
+in a single record. Please avoid using this format in any new code.
+
+.SH FILES
+.TP
+.B @IDSDIR@/pci.ids
+A list of all known PCI ID's (vendors, devices, classes and subclasses). Maintained
+at https://pci-ids.ucw.cz/, use the
+.B update-pciids
+utility to download the most recent version.
+.TP
+.B @IDSDIR@/pci.ids.gz
+If lspci is compiled with support for compression, this file is tried before pci.ids.
+.TP
+.B ~/.pciids-cache
+All ID's found in the DNS query mode are cached in this file.
+
+.SH BUGS
+
+Sometimes, lspci is not able to decode the configuration registers completely.
+This usually happens when not enough documentation was available to the authors.
+In such cases, it at least prints the
+.B <?>
+mark to signal that there is potentially something more to say. If you know
+the details, patches will be of course welcome.
+
+Access to the extended configuration space is currently supported only by the
+.B linux_sysfs
+back-end.
+
+.SH SEE ALSO
+.BR setpci (8),
+.BR pci.ids (5),
+.BR update-pciids (8),
+.BR pcilib (7)
+
+.SH AUTHOR
+The PCI Utilities are maintained by Martin Mares <mj@ucw.cz>.
diff --git a/maint/RELEASE b/maint/RELEASE
new file mode 100644
index 0000000..b1ab665
--- /dev/null
+++ b/maint/RELEASE
@@ -0,0 +1,18 @@
+How to release pciutils
+~~~~~~~~~~~~~~~~~~~~~~~
+(a couple of hints for the forgetful maintainer)
+
+Update pci.ids.
+
+Check version numbers in Makefile and lib/pci.h.
+
+ssh-add ~/.ssh/id_korg
+
+maint/tag-release vX.Y.Z
+git push --tags
+
+maint/release
+
+Update progs/pciutils at Jabberwock.
+
+Check that everything was pushed to both kernel.org and github.com.
diff --git a/maint/gen-zone b/maint/gen-zone
new file mode 100755
index 0000000..b3591f8
--- /dev/null
+++ b/maint/gen-zone
@@ -0,0 +1,52 @@
+#!/usr/bin/perl -w
+# Create a DNS zone with PCI ID records
+
+use strict;
+
+my %ids = ();
+my %comments = ();
+foreach our $file (@ARGV) {
+ my $fn = ($file =~ /\.gz$/) ? "zcat $file |" : ($file =~ /\.bz2$/) ? "bzcat $file |" : $file;
+ open F, $fn or die "Unable to open $file: $!";
+ my @id = ();
+ my $comm = "";
+ sub err($) {
+ print STDERR "Error in $file, line $.: @_\n";
+ exit 1;
+ }
+ while (<F>) {
+ if (/^(#.*)/) {
+ $comm .= $_;
+ next;
+ }
+ chomp;
+ if (my ($indent, $id, $ignored, $name) = /^(\t*)(([0-9a-fA-Z]+ ?)*)(( |\t|$)\s*(.*))$/) {
+ my $depth = length $indent;
+ $depth <= @id or err "Mismatched indentation";
+ @id = (@id[0..$depth-1], $id);
+ my $i = join(":", @id);
+ if ($i ne "") {
+ !exists $ids{$i} or die "ID $i defined twice";
+ $ids{$i} = $name;
+ $comments{$i} = $comm if $comm;
+ }
+ } elsif (!/^$/) {
+ err "Parse error";
+ }
+ $comm = "";
+ }
+ close F;
+}
+
+sub esc($) {
+ my ($x) = @_;
+ $x =~ s/^\s+//;
+ $x =~ s/"/\\"/g;
+ return $x;
+}
+
+foreach my $i (keys %ids) {
+ my $j = join(".", reverse split(/[: ]/, $i));
+ print "$j.pci\tTXT \"i=", esc($ids{$i}), "\"\n";
+ # print "$j.pci\tTXT \"c=", esc($comments{$i}), "\"\n"
+}
diff --git a/maint/release b/maint/release
new file mode 100755
index 0000000..9c2521b
--- /dev/null
+++ b/maint/release
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+# A simple script for making releases of the pciutils
+# (c) 2003--2012 Martin Mares <mj@ucw.cz>
+
+use strict;
+use warnings;
+require "./maint/release.pm";
+
+# Check API version
+my $apiver = "???";
+open X, "lib/pci.h" or die;
+while (<X>) {
+ /^#define PCI_LIB_VERSION 0x(.{6})$/ and $apiver = $1;
+}
+print "API version is $apiver ... <confirm> "; <STDIN>;
+
+#print "Updating public GIT tree\n";
+#`git push --tags public`; die if $?;
+
+my $r = new UCW::Release("pciutils");
+my $ver = $r->GetVersionFromFile("Makefile", "VERSION=(.*)");
+$r->GetVersionsFromChangelog("ChangeLog", "Released as (.*)\.");
+push @{$r->{"rules"}}, '^win32/config.h' => 's';
+if ($ver =~ /-/) {
+ $r->{"ALPHADIR"} = "alpha/";
+ $r->{"conditions"}->{"ALPHA_VERSION"} = 1;
+} else {
+ $r->{"ALPHADIR"} = "";
+ $r->{"conditions"}->{"ALPHA_VERSION"} = -1;
+}
+push @{$r->{"uploads"}}, {
+ "url" => "scp://jabberwock.ucw.cz/home/ftp/pub/mj/linux/pci/" . $r->{"ALPHADIR"}
+## },{
+## "url" => "scp://master.kernel.org/pub/software/utils/pciutils/" . $r->{"ALPHADIR"}
+ };
+$r->ParseOptions;
+$r->InitDist("maint/dist");
+my $reldir = $r->GenPackage;
+$r->GenFile("README");
+$r->GenFile("pciutils.lsm");
+$r->Dispatch;
+if ($r->{"do_upload"}) {
+ print "Uploading pci.ids to Jabberwock\n";
+ `scp -C pci.ids pciids\@jabberwock.ucw.cz:05-pciutils.new`; die if $?;
+ `ssh pciids\@jabberwock.ucw.cz mv 05-pciutils.new origs/05-pciutils`; die if $?;
+}
+
+# Hacks for kernel.org
+print "Preparing kernel.org package\n";
+my $dd = $r->{"DISTDIR"};
+my $pkg = $r->{"PKG"};
+`gzip -d <$dd/$pkg.tar.gz >$dd/$pkg.tar`; die if $?;
+system "gpg", "--armor", "--detach-sig", "-o", "$dd/$pkg.tar.sig", "$dd/$pkg.tar"; die if $?;
+if ($r->{"do_upload"}) {
+ print "Uploading to kernel.org\n";
+ print "<confirm> "; <STDIN>;
+ system '/home/mj/tree/kup/kup', 'put', "$dd/$pkg.tar", "$dd/$pkg.tar.sig", "/pub/software/utils/pciutils/$pkg.tar.gz"; die if $?;
+}
diff --git a/maint/release.pm b/maint/release.pm
new file mode 100644
index 0000000..33f64d7
--- /dev/null
+++ b/maint/release.pm
@@ -0,0 +1,328 @@
+#!/usr/bin/perl
+# A simple system for making software releases
+# (c) 2003--2011 Martin Mares <mj@ucw.cz>
+
+package UCW::Release;
+use strict;
+use warnings;
+use Getopt::Long;
+
+our $verbose = 0;
+
+sub new($$) {
+ my ($class,$basename) = @_;
+ my $s = {
+ "PACKAGE" => $basename,
+ "rules" => [
+ # p=preprocess, s=subst, -=discard
+ '(^|/)(CVS|\.arch-ids|{arch}|\.git|tmp)/' => '-',
+ '\.sw[a-z]$' => '-',
+ '\.(lsm|spec)$' => 'ps',
+ '(^|/)README$' => 's'
+ ],
+ "directories" => [
+ ],
+ "conditions" => {
+ },
+ "DATE" => `date '+%Y-%m-%d' | tr -d '\n'`,
+ "LSMDATE" => `date '+%y%m%d' | tr -d '\n'`,
+ "distfiles" => [
+ ],
+ "archivedir" => $ENV{HOME} . "/archives/sw/$basename",
+ "uploads" => [
+ ],
+ # Options
+ "do_test" => 1,
+ "do_patch" => 1,
+ "diff_against" => "",
+ "do_upload" => 1,
+ "do_sign" => 1,
+ };
+ bless $s;
+ return $s;
+}
+
+sub GetVersionFromFile($) {
+ my ($s,$file,$rx) = @_;
+ open F, $file or die "Unable to open $file for version autodetection";
+ while (<F>) {
+ chomp;
+ if (/$rx/) {
+ $s->{"VERSION"} = $1;
+ print "Detected version $1 from $file\n" if $verbose;
+ last;
+ }
+ }
+ close F;
+ if (!defined $s->{"VERSION"}) { die "Failed to auto-detect version"; }
+ return $s->{"VERSION"};
+}
+
+sub GetVersionsFromChangelog($) {
+ my ($s,$file,$rx) = @_;
+ open F, $file or die "Unable to open $file for version autodetection";
+ while (<F>) {
+ chomp;
+ if (/$rx/) {
+ if (!defined $s->{"VERSION"}) {
+ $s->{"VERSION"} = $1;
+ print "Detected version $1 from $file\n" if $verbose;
+ } elsif ($s->{"VERSION"} eq $1) {
+ # do nothing
+ } else {
+ $s->{"OLDVERSION"} = $1;
+ print "Detected previous version $1 from $file\n" if $verbose;
+ last;
+ }
+ }
+ }
+ close F;
+ if (!defined $s->{"VERSION"}) { die "Failed to auto-detect version"; }
+ return $s->{"VERSION"};
+}
+
+sub InitDist($) {
+ my ($s,$dd) = @_;
+ $s->{"DISTDIR"} = $dd;
+ print "Initializing dist directory $dd\n" if $verbose;
+ `rm -rf $dd`; die if $?;
+ `mkdir -p $dd`; die if $?;
+}
+
+sub ExpandVar($$) {
+ my ($s,$v) = @_;
+ if (defined $s->{$v}) {
+ return $s->{$v};
+ } else {
+ die "Reference to unknown variable $v";
+ }
+}
+
+sub CopyFile($$$$) {
+ my ($s,$f,$dir,$action) = @_;
+
+ (my $d = $f) =~ s@(^|/)[^/]*$@@;
+ $d = "$dir/$d";
+ -d $d || `mkdir -p $d`; die if $?;
+
+ my $preprocess = ($action =~ /p/);
+ my $subst = ($action =~ /s/);
+ if ($preprocess || $subst) {
+ open I, "$f" or die "open($f): $?";
+ open O, ">$dir/$f" or die "open($dir/$f): $!";
+ my @ifs = (); # stack of conditions, 1=satisfied
+ my $empty = 0; # last line was empty
+ my $is_makefile = ($f =~ /(Makefile|.mk)$/);
+ while (<I>) {
+ if ($subst) {
+ s/@([0-9A-Za-z_]+)@/$s->ExpandVar($1)/ge;
+ }
+ if ($preprocess) {
+ if (/^#/ || $is_makefile) {
+ if (/^#?ifdef\s+(\w+)/) {
+ if (defined ${$s->{"conditions"}}{$1}) {
+ push @ifs, ${$s->{"conditions"}}{$1};
+ next;
+ }
+ push @ifs, 0;
+ } elsif (/^#ifndef\s+(\w+)/) {
+ if (defined ${$s->{"conditions"}}{$1}) {
+ push @ifs, -${$s->{"conditions"}}{$1};
+ next;
+ }
+ push @ifs, 0;
+ } elsif (/^#if\s+/) {
+ push @ifs, 0;
+ } elsif (/^#?endif/) {
+ my $x = pop @ifs;
+ defined $x or die "Improper nesting of conditionals";
+ $x && next;
+ } elsif (/^#?else/) {
+ my $x = pop @ifs;
+ defined $x or die "Improper nesting of conditionals";
+ push @ifs, -$x;
+ $x && next;
+ }
+ }
+ @ifs && $ifs[$#ifs] < 0 && next;
+ if (/^$/) {
+ $empty && next;
+ $empty = 1;
+ } else { $empty = 0; }
+ }
+ print O;
+ }
+ close O;
+ close I;
+ ! -x $f or chmod(0755, "$dir/$f") or die "chmod($dir/$f): $!";
+ } else {
+ `cp -a "$f" "$dir/$f"`; die if $?;
+ }
+}
+
+sub GenPackage($) {
+ my ($s) = @_;
+ $s->{"PKG"} = $s->{"PACKAGE"} . "-" . $s->{"VERSION"};
+ my $dd = $s->{"DISTDIR"};
+ my $pkg = $s->{"PKG"};
+ my $dir = "$dd/$pkg";
+ print "Generating $dir\n";
+
+ FILES: foreach my $f (`find . -type f`) {
+ chomp $f;
+ $f =~ s/^\.\///;
+ my $action = "";
+ my @rules = @{$s->{"rules"}};
+ while (@rules) {
+ my $rule = shift @rules;
+ my $act = shift @rules;
+ if ($f =~ $rule) {
+ $action = $act;
+ last;
+ }
+ }
+ ($action =~ /-/) && next FILES;
+ print "$f ($action)\n" if $verbose;
+ $s->CopyFile($f, $dir, $action);
+ }
+
+ foreach my $d (@{$s->{"directories"}}) {
+ `mkdir -p $dir/$d`; die if $?;
+ }
+
+ if (-f "$dir/Makefile") {
+ print "Cleaning up\n";
+ `cd $dir && make distclean >&2`; die if $?;
+ }
+
+ print "Creating $dd/$pkg.tar.gz\n";
+ my $tarvv = $verbose ? "vv" : "";
+ `cd $dd && tar cz${tarvv}f $pkg.tar.gz $pkg >&2`; die if $?;
+ push @{$s->{"distfiles"}}, "$dd/$pkg.tar.gz";
+
+ if ($s->{'do_sign'}) {
+ print "Signing package\n";
+ system "gpg", "--armor", "--detach-sig", "$dd/$pkg.tar.gz";
+ die if $?;
+ rename "$dd/$pkg.tar.gz.asc", "$dd/$pkg.tar.gz.sign" or die "No signature produced!?\n";
+ push @{$s->{"distfiles"}}, "$dd/$pkg.tar.gz.sign";
+ }
+
+ my $adir = $s->{"archivedir"};
+ my $afile = "$adir/$pkg.tar.gz";
+ print "Archiving to $afile\n";
+ -d $adir or `mkdir -p $adir`;
+ `cp $dd/$pkg.tar.gz $afile`; die if $?;
+
+ return $dir;
+}
+
+sub GenFile($$) {
+ my ($s,$f) = @_;
+ my $sf = $s->{"DISTDIR"} . "/" . $s->{"PKG"} . "/$f";
+ my $df = $s->{"DISTDIR"} . "/$f";
+ print "Generating $df\n";
+ `cp $sf $df`; die if $?;
+ push @{$s->{"distfiles"}}, $df;
+}
+
+sub ParseOptions($) {
+ my ($s) = @_;
+ GetOptions(
+ "verbose!" => \$verbose,
+ "test!" => \$s->{"do_test"},
+ "patch!" => \$s->{"do_patch"},
+ "diff-against=s" => \$s->{"diff_against"},
+ "upload!" => \$s->{"do_upload"},
+ "sign!" => \$s->{"do_sign"},
+ ) || die "Syntax: release [--verbose] [--test] [--nopatch] [--diff-against=<version>] [--noupload] [--nosign]";
+}
+
+sub Test($) {
+ my ($s) = @_;
+ my $dd = $s->{"DISTDIR"};
+ my $pkg = $s->{"PKG"};
+ my $log = "$dd/$pkg.log";
+ print "Doing a test compilation\n";
+ `( cd $dd/$pkg && make ) >$log 2>&1`;
+ die "There were errors. Please inspect $log" if $?;
+ `grep -q [Ww]arning $log`;
+ $? or print "There were warnings! Please inspect $log.\n";
+ print "Cleaning up\n";
+ `cd $dd/$pkg && make distclean`; die if $?;
+}
+
+sub MakePatch($) {
+ my ($s) = @_;
+ my $dd = $s->{"DISTDIR"};
+ my $pkg1 = $s->{"PKG"};
+ my $oldver;
+ if ($s->{"diff_against"} ne "") {
+ $oldver = $s->{"diff_against"};
+ } elsif (defined $s->{"OLDVERSION"}) {
+ $oldver = $s->{"OLDVERSION"};