From dbeec8173da3e8a3a71e20a640ce3678f7cc2045 Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Sun, 5 Jul 2009 19:16:05 +0200
Subject: [PATCH 2/4] pciconf(8): Sync with FreeBSD's RELENG_7_2.

---
 usr.sbin/pciconf/Makefile  |    5 +-
 usr.sbin/pciconf/cap.c     |  483 ++++++++++++++++++++++++++++++++++++++++++++
 usr.sbin/pciconf/pciconf.8 |  101 +++++++---
 usr.sbin/pciconf/pciconf.c |  288 ++++++++++++++++++---------
 usr.sbin/pciconf/pciconf.h |   39 ++++
 5 files changed, 795 insertions(+), 121 deletions(-)
 create mode 100644 usr.sbin/pciconf/cap.c
 create mode 100644 usr.sbin/pciconf/pciconf.h

diff --git a/usr.sbin/pciconf/Makefile b/usr.sbin/pciconf/Makefile
index 5ddb8bc..8794e5b 100644
--- a/usr.sbin/pciconf/Makefile
+++ b/usr.sbin/pciconf/Makefile
@@ -1,6 +1,7 @@
 #	$ANA: Makefile,v 1.1.1.1 1996/09/25 21:12:57 wollman Exp $
-# $FreeBSD: src/usr.sbin/pciconf/Makefile,v 1.6.6.1 2001/04/25 12:10:26 ru Exp $
+# $FreeBSD: src/usr.sbin/pciconf/Makefile,v 1.10.8.1 2009/04/15 03:14:26 kensmith Exp $
 # $DragonFly: src/usr.sbin/pciconf/Makefile,v 1.4 2008/11/03 00:25:45 pavalos Exp $
 
 PROG=	pciconf
+SRCS=	pciconf.c cap.c
 MAN=	pciconf.8

 CFLAGS+= -I${.CURDIR}/../../sys
 
 .include <bsd.prog.mk>
diff --git a/usr.sbin/pciconf/cap.c b/usr.sbin/pciconf/cap.c
new file mode 100644
index 0000000..be08708
--- /dev/null
+++ b/usr.sbin/pciconf/cap.c
@@ -0,0 +1,483 @@
+/*-
+ * Copyright (c) 2007 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.sbin/pciconf/cap.c,v 1.2.2.2.6.1 2009/04/15 03:14:26 kensmith Exp $
+ */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <sys/agpio.h>
+#include <sys/pciio.h>
+
+#include <dev/agp/agpreg.h>
+#include <bus/pci/pcireg.h>
+
+#include "pciconf.h"
+
+static void
+cap_power(int fd, struct pci_conf *p, uint8_t ptr)
+{
+	uint16_t cap, status;
+
+	cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2);
+	status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2);
+	printf("powerspec %d  supports D0%s%s D3  current D%d",
+	    cap & PCIM_PCAP_SPEC,
+	    cap & PCIM_PCAP_D1SUPP ? " D1" : "",
+	    cap & PCIM_PCAP_D2SUPP ? " D2" : "",
+	    status & PCIM_PSTAT_DMASK);
+}
+
+static void
+cap_agp(int fd, struct pci_conf *p, uint8_t ptr)
+{
+	uint32_t status, command;
+
+	status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4);
+	command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4);
+	printf("AGP ");
+	if (AGP_MODE_GET_MODE_3(status)) {
+		printf("v3 ");
+		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x)
+			printf("8x ");
+		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x)
+			printf("4x ");
+	} else {
+		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x)
+			printf("4x ");
+		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x)
+			printf("2x ");
+		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x)
+			printf("1x ");
+	}
+	if (AGP_MODE_GET_SBA(status))
+		printf("SBA ");
+	if (AGP_MODE_GET_AGP(command)) {
+		printf("enabled at ");
+		if (AGP_MODE_GET_MODE_3(command)) {
+			printf("v3 ");
+			switch (AGP_MODE_GET_RATE(command)) {
+			case AGP_MODE_V3_RATE_8x:
+				printf("8x ");
+				break;
+			case AGP_MODE_V3_RATE_4x:
+				printf("4x ");
+				break;
+			}
+		} else
+			switch (AGP_MODE_GET_RATE(command)) {
+			case AGP_MODE_V2_RATE_4x:
+				printf("4x ");
+				break;
+			case AGP_MODE_V2_RATE_2x:
+				printf("2x ");
+				break;
+			case AGP_MODE_V2_RATE_1x:
+				printf("1x ");
+				break;
+			}
+		if (AGP_MODE_GET_SBA(command))
+			printf("SBA ");
+	} else
+		printf("disabled");
+}
+
+static void
+cap_vpd(int fd, struct pci_conf *p, uint8_t ptr)
+{
+
+	printf("VPD");
+}
+
+static void
+cap_msi(int fd, struct pci_conf *p, uint8_t ptr)
+{
+	uint16_t ctrl;
+	int msgnum;
+
+	ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2);
+	msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1);
+	printf("MSI supports %d message%s%s%s ", msgnum,
+	    (msgnum == 1) ? "" : "s",
+	    (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "",
+	    (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : "");
+	if (ctrl & PCIM_MSICTRL_MSI_ENABLE) {
+		msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4);
+		printf("enabled with %d message%s", msgnum,
+		    (msgnum == 1) ? "" : "s");
+	}
+}
+
+static void
+cap_pcix(int fd, struct pci_conf *p, uint8_t ptr)
+{
+	uint32_t status;
+	int comma, max_splits, max_burst_read;
+
+	status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4);
+	printf("PCI-X ");
+	if (status & PCIXM_STATUS_64BIT)
+		printf("64-bit ");
+	if ((p->pc_hdr & PCIM_HDRTYPE) == 1)
+		printf("bridge ");
+	printf("supports");
+	comma = 0;
+	if (status & PCIXM_STATUS_133CAP) {
+		printf("%s 133MHz", comma ? "," : "");
+		comma = 1;
+	}
+	if (status & PCIXM_STATUS_266CAP) {
+		printf("%s 266MHz", comma ? "," : "");
+		comma = 1;
+	}
+	if (status & PCIXM_STATUS_533CAP) {
+		printf("%s 533MHz", comma ? "," : "");
+		comma = 1;
+	}
+	if ((p->pc_hdr & PCIM_HDRTYPE) == 1)
+		return;
+	switch (status & PCIXM_STATUS_MAX_READ) {
+	case PCIXM_STATUS_MAX_READ_512:
+		max_burst_read = 512;
+		break;
+	case PCIXM_STATUS_MAX_READ_1024:
+		max_burst_read = 1024;
+		break;
+	case PCIXM_STATUS_MAX_READ_2048:
+		max_burst_read = 2048;
+		break;
+	case PCIXM_STATUS_MAX_READ_4096:
+		max_burst_read = 4096;
+		break;
+	}
+	switch (status & PCIXM_STATUS_MAX_SPLITS) {
+	case PCIXM_STATUS_MAX_SPLITS_1:
+		max_splits = 1;
+		break;
+	case PCIXM_STATUS_MAX_SPLITS_2:
+		max_splits = 2;
+		break;
+	case PCIXM_STATUS_MAX_SPLITS_3:
+		max_splits = 3;
+		break;
+	case PCIXM_STATUS_MAX_SPLITS_4:
+		max_splits = 4;
+		break;
+	case PCIXM_STATUS_MAX_SPLITS_8:
+		max_splits = 8;
+		break;
+	case PCIXM_STATUS_MAX_SPLITS_12:
+		max_splits = 12;
+		break;
+	case PCIXM_STATUS_MAX_SPLITS_16:
+		max_splits = 16;
+		break;
+	case PCIXM_STATUS_MAX_SPLITS_32:
+		max_splits = 32;
+		break;
+	}
+	printf("%s %d burst read, %d split transaction%s", comma ? "," : "",
+	    max_burst_read, max_splits, max_splits == 1 ? "" : "s");
+}
+
+static void
+cap_ht(int fd, struct pci_conf *p, uint8_t ptr)
+{
+	uint32_t reg;
+	uint16_t command;
+
+	command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2);
+	printf("HT ");
+	if ((command & 0xe000) == PCIM_HTCAP_SLAVE)
+		printf("slave");
+	else if ((command & 0xe000) == PCIM_HTCAP_HOST)
+		printf("host");
+	else
+		switch (command & PCIM_HTCMD_CAP_MASK) {
+		case PCIM_HTCAP_SWITCH:
+			printf("switch");
+			break;
+		case PCIM_HTCAP_INTERRUPT:
+			printf("interrupt");
+			break;
+		case PCIM_HTCAP_REVISION_ID:
+			printf("revision ID");
+			break;
+		case PCIM_HTCAP_UNITID_CLUMPING:
+			printf("unit ID clumping");
+			break;
+		case PCIM_HTCAP_EXT_CONFIG_SPACE:
+			printf("extended config space");
+			break;
+		case PCIM_HTCAP_ADDRESS_MAPPING:
+			printf("address mapping");
+			break;
+		case PCIM_HTCAP_MSI_MAPPING:
+			printf("MSI %saddress window %s at 0x",
+			    command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "",
+			    command & PCIM_HTCMD_MSI_ENABLE ? "enabled" :
+			    "disabled");
+			if (command & PCIM_HTCMD_MSI_FIXED)
+				printf("fee00000");
+			else {
+				reg = read_config(fd, &p->pc_sel,
+				    ptr + PCIR_HTMSI_ADDRESS_HI, 4);
+				if (reg != 0)
+					printf("%08x", reg);
+				reg = read_config(fd, &p->pc_sel,
+				    ptr + PCIR_HTMSI_ADDRESS_LO, 4);
+				printf("%08x", reg);
+			}
+			break;
+		case PCIM_HTCAP_DIRECT_ROUTE:
+			printf("direct route");
+			break;
+		case PCIM_HTCAP_VCSET:
+			printf("VC set");
+			break;
+		case PCIM_HTCAP_RETRY_MODE:
+			printf("retry mode");
+			break;
+		case PCIM_HTCAP_X86_ENCODING:
+			printf("X86 encoding");
+			break;
+		default:
+			printf("unknown %02x", command);
+			break;
+		}
+}
+
+static void
+cap_vendor(int fd, struct pci_conf *p, uint8_t ptr)
+{
+	uint8_t length;
+
+	length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1);
+	printf("vendor (length %d)", length);
+	if (p->pc_vendor == 0x8086) {
+		/* Intel */
+		uint8_t version;
+
+		version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA,
+		    1);
+		printf(" Intel cap %d version %d", version >> 4, version & 0xf);
+		if (version >> 4 == 1 && length == 12) {
+			/* Feature Detection */
+			uint32_t fvec;
+			int comma;
+
+			comma = 0;
+			fvec = read_config(fd, &p->pc_sel, ptr +
+			    PCIR_VENDOR_DATA + 5, 4);
+			printf("\n\t\t features:");
+			if (fvec & (1 << 0)) {
+				printf(" AMT");
+				comma = 1;
+			}
+			fvec = read_config(fd, &p->pc_sel, ptr +
+			    PCIR_VENDOR_DATA + 1, 4);
+			if (fvec & (1 << 21)) {
+				printf("%s Quick Resume", comma ? "," : "");
+				comma = 1;
+			}
+			if (fvec & (1 << 18)) {
+				printf("%s SATA RAID-5", comma ? "," : "");
+				comma = 1;
+			}
+			if (fvec & (1 << 9)) {
+				printf("%s Mobile", comma ? "," : "");
+				comma = 1;
+			}
+			if (fvec & (1 << 7)) {
+				printf("%s 6 PCI-e x1 slots", comma ? "," : "");
+				comma = 1;
+			} else {
+				printf("%s 4 PCI-e x1 slots", comma ? "," : "");
+				comma = 1;
+			}
+			if (fvec & (1 << 5)) {
+				printf("%s SATA RAID-0/1/10", comma ? "," : "");
+				comma = 1;
+			}
+			if (fvec & (1 << 3)) {
+				printf("%s SATA AHCI", comma ? "," : "");
+				comma = 1;
+			}
+		}
+	}
+}
+
+static void
+cap_debug(int fd, struct pci_conf *p, uint8_t ptr)
+{
+	uint16_t debug_port;
+
+	debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2);
+	printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port &
+	    PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13));
+}
+
+static void
+cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr)
+{
+	uint32_t id;
+
+	id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4);
+	printf("PCI Bridge card=0x%08x", id);
+}
+
+static void
+cap_express(int fd, struct pci_conf *p, uint8_t ptr)
+{
+	uint16_t flags;
+
+	flags = read_config(fd, &p->pc_sel, ptr + PCIER_CAPABILITY, 2);
+	printf("PCI-Express %d ", flags & PCIEM_CAP_VER_MASK);
+	switch (flags & PCIEM_CAP_PORT_TYPE) {
+	case PCIE_END_POINT:
+		printf("endpoint");
+		break;
+	case PCIE_LEG_END_POINT:
+		printf("legacy endpoint");
+		break;
+	case PCIE_ROOT_PORT:
+		printf("root port");
+		break;
+	case PCIE_UP_STREAM_PORT:
+		printf("upstream port");
+		break;
+	case PCIE_DOWN_STREAM_PORT:
+		printf("downstream port");
+		break;
+	case PCIE_PCIE2PCI_BRIDGE:
+		printf("PCI bridge");
+		break;
+	default:
+		printf("type %d", (flags & PCIEM_CAP_PORT_TYPE) >> 8);
+		break;
+	}
+	if (flags & PCIEM_CAP_IRQ)
+		printf(" IRQ %d", (flags & PCIEM_CAP_IRQ) >> 17);
+}
+
+static void
+cap_msix(int fd, struct pci_conf *p, uint8_t ptr)
+{
+	uint32_t val;
+	uint16_t ctrl;
+	int msgnum, table_bar, pba_bar;
+
+	ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2);
+	msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1;
+	val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4);
+	table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
+	val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4);
+	pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
+	printf("MSI-X supports %d message%s ", msgnum,
+	    (msgnum == 1) ? "" : "s");
+	if (table_bar == pba_bar)
+		printf("in map 0x%x", table_bar);
+	else
+		printf("in maps 0x%x and 0x%x", table_bar, pba_bar);
+	if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE)
+		printf(" enabled");
+}
+
+void
+list_caps(int fd, struct pci_conf *p)
+{
+	uint16_t cmd;
+	uint8_t ptr, cap;
+
+	/* Are capabilities present for this device? */
+	cmd = read_config(fd, &p->pc_sel, PCIR_STATUS, 2);
+	if (!(cmd & PCIM_STATUS_CAPPRESENT))
+		return;
+
+	switch (p->pc_hdr & PCIM_HDRTYPE) {
+	case 0:
+	case 1:
+		ptr = PCIR_CAP_PTR;
+		break;
+	case 2:
+		ptr = PCIR_CAP_PTR_2;
+		break;
+	default:
+		errx(1, "list_caps: bad header type");
+	}
+
+	/* Walk the capability list. */
+	ptr = read_config(fd, &p->pc_sel, ptr, 1);
+	while (ptr != 0 && ptr != 0xff) {
+		cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1);
+		printf("    cap %02x[%02x] = ", cap, ptr);
+		switch (cap) {
+		case PCIY_PMG:
+			cap_power(fd, p, ptr);
+			break;
+		case PCIY_AGP:
+			cap_agp(fd, p, ptr);
+			break;
+		case PCIY_VPD:
+			cap_vpd(fd, p, ptr);
+			break;
+		case PCIY_MSI:
+			cap_msi(fd, p, ptr);
+			break;
+		case PCIY_PCIX:
+			cap_pcix(fd, p, ptr);
+			break;
+		case PCIY_HT:
+			cap_ht(fd, p, ptr);
+			break;
+		case PCIY_VENDOR:
+			cap_vendor(fd, p, ptr);
+			break;
+		case PCIY_DEBUG:
+			cap_debug(fd, p, ptr);
+			break;
+		case PCIY_SUBVENDOR:
+			cap_subvendor(fd, p, ptr);
+			break;
+		case PCIY_EXPRESS:
+			cap_express(fd, p, ptr);
+			break;
+		case PCIY_MSIX:
+			cap_msix(fd, p, ptr);
+			break;
+		default:
+			printf("unknown");
+			break;
+		}
+		printf("\n");
+		ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1);
+	}
+}
diff --git a/usr.sbin/pciconf/pciconf.8 b/usr.sbin/pciconf/pciconf.8
index ad4e1e4..2198eec 100644
--- a/usr.sbin/pciconf/pciconf.8
+++ b/usr.sbin/pciconf/pciconf.8
@@ -1,4 +1,4 @@
-.\" $FreeBSD: src/usr.sbin/pciconf/pciconf.8,v 1.8.2.9 2003/03/11 22:31:30 trhodes Exp $
+.\" $FreeBSD: src/usr.sbin/pciconf/pciconf.8,v 1.30.2.2.2.1 2009/04/15 03:14:26 kensmith Exp $
 .\" $DragonFly: src/usr.sbin/pciconf/pciconf.8,v 1.4 2008/09/30 12:20:29 hasso Exp $
 .\" Copyright (c) 1997
 .\"	Stefan Esser <se@FreeBSD.org>. All rights reserved.
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd February 7, 1997
+.Dd July 5, 2009
 .Dt PCICONF 8
 .Os
 .Sh NAME
@@ -33,7 +33,7 @@
 .Nd diagnostic utility for the PCI bus
 .Sh SYNOPSIS
 .Nm
-.Fl l Op Fl v
+.Fl l Op Fl bcv
 .Nm
 .Fl a Ar selector
 .Nm
@@ -47,7 +47,8 @@ utility provides a command line interface to functionality provided by the
 .Xr pci 4
 .Xr ioctl 2
 interface.
-As such, it is only available to users with write access to
+As such, some of the functions are only available to users with write
+access to
 .Pa /dev/pci ,
 normally only the super-user.
 .Pp
@@ -55,18 +56,14 @@ With the
 .Fl l
 option, it lists all devices found by the boot probe in the following format:
 .Bd -literal
-foo0@pci0:4:0: class=0x010000 card=0x00000000 chip=0x000f1000 rev=0x01 hdr=0x00
-bar0@pci0:5:0: class=0x000100 card=0x00000000 chip=0x88c15333 rev=0x00 hdr=0x00
-none0@pci0:6:0: class=0x020000 card=0x00000000 chip=0x802910ec rev=0x00 hdr=0x00
+foo0@pci0:0:4:0: class=0x010000 card=0x00000000 chip=0x000f1000 rev=0x01 \
+hdr=0x00
+bar0@pci0:0:5:0: class=0x000100 card=0x00000000 chip=0x88c15333 rev=0x00 \
+hdr=0x00
+none0@pci0:0:6:0: class=0x020000 card=0x00000000 chip=0x802910ec rev=0x00 \
+hdr=0x00
 .Ed
 .Pp
-If the
-.Fl v
-option is supplied,
-.Nm
-will attempt to load the vendor/device information database, and print
-vendor, device, class and subclass identification strings for each device.
-.Pp
 The first column gives the
 device name, unit number, and
 .Ar selector .
@@ -85,12 +82,7 @@ The third column gives the contents of the subvendorid register, introduced
 in revision 2.1 of the
 .Tn PCI
 standard.
-It is 0 for most current (2.0)
-.Tn PCI
-cards, but is supposed to be loaded with a unique card identification code
-in newly developed
-.Tn PCI
-cards.
+Note that it will be 0 for older cards.
 The field consists of the card ID in the upper
 half and the card vendor ID in the lower half of the value.
 .Pp
@@ -100,11 +92,16 @@ It consists of two fields, identifying the chip and
 its vendor, as above.
 The fifth column prints the chip's revision.
 The sixth column describes the header type.
-Currently assigned header types are 0 for all devices except
+Currently assigned header types include 0 for most devices,
+1 for
 .Tn PCI
 to
 .Tn PCI
-bridges, and 1 for such bridge chips.
+bridges, and 2 for
+.Tn PCI
+to
+.Tn CardBus
+bridges.
 If the most significant bit
 of the header type register is set for
 function 0 of a
@@ -114,6 +111,56 @@ device, it is a
 device, which contains several (similar or independent) functions on
 one chip.
 .Pp
+If the
+.Fl b
+option is supplied,
+.Nm
+will list any base address registers
+.Pq BARs
+that are assigned resources for each device.
+Each BAR will be enumerated via a line in the following format:
+.Bd -literal
+    bar   [10] = type Memory, range 32, base 0xda060000, size 131072, enabled
+.Ed
+.Pp
+The first value after the
+.Dq Li bar
+prefix in the square brackets is the offset of the BAR in config space in
+hexadecimal.
+The type of a BAR is one of
+.Dq Memory ,
+.Dq Prefetchable Memory ,
+or
+.Dq I/O Port .
+The range indicates the maximum address the BAR decodes.
+The base and size indicate the start and length of the BAR's address window,
+respectively.
+Finally, the last flag indicates if the BAR is enabled or disabled.
+.Pp
+If the
+.Fl c
+option is supplied,
+.Nm
+will list any capabilities supported by each device.
+Each capability will be enumerated via a line in the following format:
+.Bd -literal
+    cap 10[40] = PCI-Express 1 root port
+.Ed
+.Pp
+The first value after the
+.Dq Li cap
+prefix is the capability ID in hexadecimal.
+The second value in the square brackets is the offset of the capability
+in config space in hexadecimal.
+The format of the text after the equals sign is capability-specific.
+.Pp
+If the
+.Fl v
+option is supplied,
+.Nm
+will attempt to load the vendor/device information database, and print
+vendor, device, class and subclass identification strings for each device.
+.Pp
 All invocations of
 .Nm
 except for
@@ -121,10 +168,12 @@ except for
 require a
 .Ar selector
 of the form
-.Li pci Ns Va bus Ns \&: Ns Va device
-(optionally followed by
-.Li \&: Ns Va function ) .
-A final colon may be appended and
+.Li pci Ns Va domain Ns \&: Ns Va bus Ns \&: Ns Va device Ns \&: \
+Ns Va function Ns ,
+.Li pci Ns Va bus Ns \&: Ns Va device Ns \&: Ns Va function Ns , or
+.Li pci Ns Va bus Ns \&: Ns Va device Ns .
+In case of an abrigded form, omitted selector components are assumed to be 0.
+An optional leading device name followed by @ and an optional final colon
 will be ignored; this is so that the first column in the output of
 .Nm
 .Fl l
diff --git a/usr.sbin/pciconf/pciconf.c b/usr.sbin/pciconf/pciconf.c
index a903ea1..72674cd 100644
--- a/usr.sbin/pciconf/pciconf.c
+++ b/usr.sbin/pciconf/pciconf.c
@@ -12,7 +12,7 @@
  * no representations about the suitability of this software for any
  * purpose.  It is provided "as is" without express or implied
  * warranty.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
@@ -26,13 +26,14 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.sbin/pciconf/pciconf.c,v 1.11.2.3 2002/09/17 22:09:15 jdp Exp $
+ * $FreeBSD: src/usr.sbin/pciconf/pciconf.c,v 1.30.2.3.2.1 2009/04/15 03:14:26 kensmith Exp $
  * $DragonFly: src/usr.sbin/pciconf/pciconf.c,v 1.6 2005/01/01 22:06:25 cpressey Exp $
  */
 
 #include <sys/types.h>
 #include <sys/fcntl.h>
 
+#include <ctype.h>
 #include <err.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -44,8 +45,9 @@
 #include <bus/pci/pcireg.h>
 
 #include "pathnames.h"
+#include "pciconf.h"
 
-struct pci_device_info 
+struct pci_device_info
 {
     TAILQ_ENTRY(pci_device_info)	link;
     int					id;
@@ -62,7 +64,8 @@ struct pci_vendor_info
 
 TAILQ_HEAD(,pci_vendor_info)	pci_vendors;
 
-static void list_devs(int vendors);
+static void list_bars(int fd, struct pci_conf *p);
+static void list_devs(int verbose, int bars, int caps);
 static void list_verbose(struct pci_conf *p);
 static const char *guess_class(struct pci_conf *p);
 static const char *guess_subclass(struct pci_conf *p);
@@ -77,7 +80,7 @@ static void
 usage(void)
 {
 	fprintf(stderr, "%s\n%s\n%s\n%s\n",
-		"usage: pciconf -l [-v]",
+		"usage: pciconf -l [-bcv]",
 		"       pciconf -a selector",
 		"       pciconf -r [-b | -h] selector addr[:addr2]",
 		"       pciconf -w [-b | -h] selector addr value");
@@ -88,17 +91,30 @@ int
 main(int argc, char **argv)
 {
 	int c;
-	int listmode, readmode, writemode, attachedmode, verbose;
+	int listmode, readmode, writemode, attachedmode, bars, caps, verbose;
 	int byte, isshort;
 
-	listmode = readmode = writemode = attachedmode = verbose = byte = isshort = 0;
+	listmode = readmode = writemode = attachedmode = bars = caps = verbose = byte = isshort = 0;
 
-	while ((c = getopt(argc, argv, "alrwbhv")) != -1) {
+	while ((c = getopt(argc, argv, "abchlrwv")) != -1) {
 		switch(c) {
 		case 'a':
 			attachedmode = 1;
 			break;
 
+		case 'b':
+			bars = 1;
+			byte = 1;
+			break;
+
+		case 'c':
+			caps = 1;
+			break;
+
+		case 'h':
+			isshort = 1;
+			break;
+
 		case 'l':
 			listmode = 1;
 			break;
@@ -106,19 +122,11 @@ main(int argc, char **argv)
 		case 'r':
 			readmode = 1;
 			break;
-			
+
 		case 'w':
 			writemode = 1;
 			break;
 
-		case 'b':
-			byte = 1;
-			break;
-
-		case 'h':
-			isshort = 1;
-			break;
-
 		case 'v':
 			verbose = 1;
 			break;
@@ -135,25 +143,25 @@ main(int argc, char **argv)
 		usage();
 
 	if (listmode) {
-		list_devs(verbose);
-	} else if(attachedmode) {
-		chkattached(argv[optind], 
+		list_devs(verbose, bars, caps);
+	} else if (attachedmode) {
+		chkattached(argv[optind],
 		       byte ? 1 : isshort ? 2 : 4);
-	} else if(readmode) {
-		readit(argv[optind], argv[optind + 1], 
+	} else if (readmode) {
+		readit(argv[optind], argv[optind + 1],
 		       byte ? 1 : isshort ? 2 : 4);
-	} else if(writemode) {
+	} else if (writemode) {
 		writeit(argv[optind], argv[optind + 1], argv[optind + 2],
 		       byte ? 1 : isshort ? 2 : 4);
 	} else {
- 		usage();
+		usage();
 	}
 
 	return exitstatus;
 }
 
 static void
-list_devs(int verbose)
+list_devs(int verbose, int bars, int caps)
 {
 	int fd;
 	struct pci_conf_io pc;
@@ -163,7 +171,7 @@ list_devs(int verbose)
 	if (verbose)
 		load_vendors();
 
-	fd = open(_PATH_DEVPCI, O_RDWR, 0);
+	fd = open(_PATH_DEVPCI, caps ? O_RDWR : O_RDONLY, 0);
 	if (fd < 0)
 		err(1, "%s", _PATH_DEVPCI);
 
@@ -195,14 +203,13 @@ list_devs(int verbose)
 			return;
 		}
 		for (p = conf; p < &conf[pc.num_matches]; p++) {
-
-			printf("%s%d@pci%d:%d:%d:\tclass=0x%06x card=0x%08x "
-			       "chip=0x%08x rev=0x%02x hdr=0x%02x\n", 
+			printf("%s%d@pci%d:%d:%d:%d:\tclass=0x%06x card=0x%08x "
+			       "chip=0x%08x rev=0x%02x hdr=0x%02x\n",
 			       (p->pd_name && *p->pd_name) ? p->pd_name :
 			       "none",
 			       (p->pd_name && *p->pd_name) ? (int)p->pd_unit :
-			       none_count++,
-			       p->pc_sel.pc_bus, p->pc_sel.pc_dev, 
+			       none_count++, p->pc_sel.pc_domain,
+			       p->pc_sel.pc_bus, p->pc_sel.pc_dev,
 			       p->pc_sel.pc_func, (p->pc_class << 16) |
 			       (p->pc_subclass << 8) | p->pc_progif,
 			       (p->pc_subdevice << 16) | p->pc_subvendor,
@@ -210,6 +217,10 @@ list_devs(int verbose)
 			       p->pc_revid, p->pc_hdr);
 			if (verbose)
 				list_verbose(p);
+			if (bars)
+				list_bars(fd, p);
+			if (caps)
+				list_caps(fd, p);
 		}
 	} while (pc.status == PCI_GETCONF_MORE_DEVS);
 
@@ -217,15 +228,73 @@ list_devs(int verbose)
 }
 
 static void
+list_bars(int fd, struct pci_conf *p)
+{
+	struct pci_bar_io bar;
+	uint64_t base;
+	const char *type;
+	int i, range, max;
+
+	switch (p->pc_hdr & PCIM_HDRTYPE) {
+	case PCIM_HDRTYPE_NORMAL:
+		max = PCIR_MAX_BAR_0;
+		break;
+	case PCIM_HDRTYPE_BRIDGE:
+		max = PCIR_MAX_BAR_1;
+		break;
+	case PCIM_HDRTYPE_CARDBUS:
+		max = PCIR_MAX_BAR_2;
+		break;
+	default:
+		return;
+	}
+
+	for (i = 0; i <= max; i++) {
+		bar.pbi_sel = p->pc_sel;
+		bar.pbi_reg = PCIR_BAR(i);
+		if (ioctl(fd, PCIOCGETBAR, &bar) < 0)
+			continue;
+		if (PCI_BAR_IO(bar.pbi_base)) {
+			type = "I/O Port";
+			range = 32;
+			base = bar.pbi_base & PCIM_BAR_IO_BASE;
+		} else {
+			if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH)
+				type = "Prefetchable Memory";
+			else
+				type = "Memory";
+			switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) {
+			case PCIM_BAR_MEM_32:
+				range = 32;
+				break;
+			case PCIM_BAR_MEM_1MB:
+				range = 20;
+				break;
+			case PCIM_BAR_MEM_64:
+				range = 64;
+				break;
+			default:
+				range = -1;
+			}
+			base = bar.pbi_base & ~((uint64_t)0xf);
+		}
+		printf("    bar   [%02x] = type %s, range %2d, base %#jx, ",
+		    PCIR_BAR(i), type, range, (uintmax_t)base);
+		printf("size %2d, %s\n", (int)bar.pbi_length,
+		    bar.pbi_enabled ? "enabled" : "disabled");
+	}
+}
+
+static void
 list_verbose(struct pci_conf *p)
 {
 	struct pci_vendor_info	*vi;
 	struct pci_device_info	*di;
 	const char *dp;
-	
+
 	TAILQ_FOREACH(vi, &pci_vendors, link) {
 		if (vi->id == p->pc_vendor) {
-			printf("    vendor   = '%s'\n", vi->desc);
+			printf("    vendor     = '%s'\n", vi->desc);
 			break;
 		}
 	}
@@ -234,15 +303,15 @@ list_verbose(struct pci_conf *p)
 	} else {
 		TAILQ_FOREACH(di, &vi->devs, link) {
 			if (di->id == p->pc_device) {
-				printf("    device   = '%s'\n", di->desc);
+				printf("    device     = '%s'\n", di->desc);
 				break;
 			}
 		}
 	}
 	if ((dp = guess_class(p)) != NULL)
-		printf("    class    = %s\n", dp);
+		printf("    class      = %s\n", dp);
 	if ((dp = guess_subclass(p)) != NULL)
-		printf("    subclass = %s\n", dp);
+		printf("    subclass   = %s\n", dp);
 }
 
 /*
@@ -263,8 +332,9 @@ static struct
 	{PCIC_STORAGE,		PCIS_STORAGE_FLOPPY,	"floppy disk"},
 	{PCIC_STORAGE,		PCIS_STORAGE_IPI,	"IPI"},
 	{PCIC_STORAGE,		PCIS_STORAGE_RAID,	"RAID"},
-	{PCIC_STORAGE,		PCIS_STORAGE_ATA_ADMA,	"ATA"},
+	{PCIC_STORAGE,		PCIS_STORAGE_ATA_ADMA,	"ATA (ADMA)"},
 	{PCIC_STORAGE,		PCIS_STORAGE_SATA,	"SATA"},
+	{PCIC_STORAGE,		PCIS_STORAGE_SAS,	"SAS"},
 	{PCIC_NETWORK,		-1,			"network"},
 	{PCIC_NETWORK,		PCIS_NETWORK_ETHERNET,	"ethernet"},
 	{PCIC_NETWORK,		PCIS_NETWORK_TOKENRING,	"token ring"},
@@ -279,6 +349,7 @@ static struct
 	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_VIDEO,	"video"},
 	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_AUDIO,	"audio"},
 	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_TELE,	"telephony"},
+	{PCIC_MULTIMEDIA,	PCIS_MULTIMEDIA_HDA,	"HDA"},
 	{PCIC_MEMORY,		-1,			"memory"},
 	{PCIC_MEMORY,		PCIS_MEMORY_RAM,	"RAM"},
 	{PCIC_MEMORY,		PCIS_MEMORY_FLASH,	"flash"},
@@ -291,20 +362,19 @@ static struct
 	{PCIC_BRIDGE,		PCIS_BRIDGE_PCMCIA,	"PCI-PCMCIA"},
 	{PCIC_BRIDGE,		PCIS_BRIDGE_NUBUS,	"PCI-NuBus"},
 	{PCIC_BRIDGE,		PCIS_BRIDGE_CARDBUS,	"PCI-CardBus"},
-	{PCIC_BRIDGE,		PCIS_BRIDGE_INFINIBAND,	"PCI-InfiniBand"},
-	{PCIC_BRIDGE,		PCIS_BRIDGE_OTHER,	"PCI-unknown"},
+	{PCIC_BRIDGE,		PCIS_BRIDGE_RACEWAY,	"PCI-RACEway"},
 	{PCIC_SIMPLECOMM,	-1,			"simple comms"},
 	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_UART,	"UART"},	/* could detect 16550 */
 	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_PAR,	"parallel port"},
 	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_MULSER,	"multiport serial"},
 	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_MODEM,	"generic modem"},
-	{PCIC_SIMPLECOMM,	PCIS_SIMPLECOMM_SMART_CARD,"smartcard"},
 	{PCIC_BASEPERIPH,	-1,			"base peripheral"},
 	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_PIC,	"interrupt controller"},
 	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_DMA,	"DMA controller"},
 	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_TIMER,	"timer"},
 	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_RTC,	"realtime clock"},
-	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_PCIHOT,	"PCI Hotplug"},
+	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_PCIHOT,	"PCI hot-plug controller"},
+	{PCIC_BASEPERIPH,	PCIS_BASEPERIPH_SDHC,	"SD host controller"},
 	{PCIC_INPUTDEV,		-1,			"input device"},
 	{PCIC_INPUTDEV,		PCIS_INPUTDEV_KEYBOARD,	"keyboard"},
 	{PCIC_INPUTDEV,		PCIS_INPUTDEV_DIGITIZER,"digitizer"},
@@ -315,25 +385,27 @@ static struct
 	{PCIC_PROCESSOR,	-1,			"processor"},
 	{PCIC_SERIALBUS,	-1,			"serial bus"},
 	{PCIC_SERIALBUS,	PCIS_SERIALBUS_FW,	"FireWire"},
-	{PCIC_SERIALBUS,	PCIS_SERIALBUS_ACCESS,	"AccessBus"},	 
+	{PCIC_SERIALBUS,	PCIS_SERIALBUS_ACCESS,	"AccessBus"},
 	{PCIC_SERIALBUS,	PCIS_SERIALBUS_SSA,	"SSA"},
 	{PCIC_SERIALBUS,	PCIS_SERIALBUS_USB,	"USB"},
 	{PCIC_SERIALBUS,	PCIS_SERIALBUS_FC,	"Fibre Channel"},
 	{PCIC_SERIALBUS,	PCIS_SERIALBUS_SMBUS,	"SMBus"},
-	{PCIC_SERIALBUS,	PCIS_SERIALBUS_INFINIBAND,"InfiniBand"},
-	{PCIC_WIRELESS,		-1,			"wireless"},
+	{PCIC_WIRELESS,		-1,			"wireless controller"},
 	{PCIC_WIRELESS,		PCIS_WIRELESS_IRDA,	"iRDA"},
-	{PCIC_WIRELESS,		PCIS_WIRELESS_IR,	"consumer IR"},
-	{PCIC_WIRELESS,		PCIS_WIRELESS_RF,	"RF controller"},
-	{PCIC_WIRELESS,		PCIS_WIRELESS_BLUETOOTH,"Bluetooth"},
-	{PCIC_WIRELESS,		PCIS_WIRELESS_BROADBAND,"broadband"},
-	{PCIC_WIRELESS,		PCIS_WIRELESS_80211A,	"Ethernet (802.11a)"},
-	{PCIC_WIRELESS,		PCIS_WIRELESS_80211B,	"Ethernet (802.11b)"},
-	{PCIC_INTELLIIO,	-1,			"I2O"},
-	{PCIC_INTELLIIO,	PCIS_INTELLIIO_I2O,	"I2O 1.0"},
-	{PCIC_SATCOM,		-1,			"satellite"},
-	{PCIC_CRYPTO,		-1,			"crypto controller"},
-	{PCIC_DASP,		-1,			"signal processing"},
+	{PCIC_WIRELESS,		PCIS_WIRELESS_IR,	"IR"},
+	{PCIC_WIRELESS,		PCIS_WIRELESS_RF,	"RF"},
+	{PCIC_INTELLIIO,	-1,			"intelligent I/O controller"},
+	{PCIC_INTELLIIO,	PCIS_INTELLIIO_I2O,	"I2O"},
+	{PCIC_SATCOM,		-1,			"satellite communication"},
+	{PCIC_SATCOM,		PCIS_SATCOM_TV,		"sat TV"},
+	{PCIC_SATCOM,		PCIS_SATCOM_AUDIO,	"sat audio"},
+	{PCIC_SATCOM,		PCIS_SATCOM_VOICE,	"sat voice"},
+	{PCIC_SATCOM,		PCIS_SATCOM_DATA,	"sat data"},
+	{PCIC_CRYPTO,		-1,			"encrypt/decrypt"},
+	{PCIC_CRYPTO,		PCIS_CRYPTO_NETCOMP,	"network/computer crypto"},
+	{PCIC_CRYPTO,		PCIS_CRYPTO_NETCOMP,	"entertainment crypto"},
+	{PCIC_DASP,		-1,			"dasp"},
+	{PCIC_DASP,		PCIS_DASP_DPIO,		"DPIO module"},
 	{0, 0,		NULL}
 };
 
@@ -369,7 +441,8 @@ load_vendors(void)
 	FILE *db;
 	struct pci_vendor_info *cv;
 	struct pci_device_info *cd;
-	char buf[100], str[100];
+	char buf[1024], str[1024];
+	char *ch;
 	int id, error;
 
 	/*
@@ -391,8 +464,20 @@ load_vendors(void)
 		if (fgets(buf, sizeof(buf), db) == NULL)
 			break;
 
+		if ((ch = strchr(buf, '#')) != NULL)
+			*ch = '\0';
+		ch = strchr(buf, '\0') - 1;
+		while (ch > buf && isspace(*ch))
+			*ch-- = '\0';
+		if (ch <= buf)
+			continue;
+
+		/* Can't handle subvendor / subdevice entries yet */
+		if (buf[0] == '\t' && buf[1] == '\t')
+			continue;
+
 		/* Check for vendor entry */
-		if ((buf[0] != '\t') && (sscanf(buf, "%04x\t%[^\n]", &id, str) == 2)) {
+		if (buf[0] != '\t' && sscanf(buf, "%04x %[^\n]", &id, str) == 2) {
 			if ((id == 0) || (strlen(str) < 1))
 				continue;
 			if ((cv = malloc(sizeof(struct pci_vendor_info))) == NULL) {
@@ -411,9 +496,9 @@ load_vendors(void)
 			TAILQ_INSERT_TAIL(&pci_vendors, cv, link);
 			continue;
 		}
-		
+
 		/* Check for device entry */
-		if ((buf[0] == '\t') && (sscanf(buf + 1, "%04x\t%[^\n]", &id, str) == 2)) {
+		if (buf[0] == '\t' && sscanf(buf + 1, "%04x %[^\n]", &id, str) == 2) {
 			if ((id == 0) || (strlen(str) < 1))
 				continue;
 			if (cv == NULL) {
@@ -441,55 +526,69 @@ load_vendors(void)
 	if (ferror(db))
 		error = 1;
 	fclose(db);
-	
+
 	return(error);
 }
 
+uint32_t
+read_config(int fd, struct pcisel *sel, long reg, int width)
+{
+	struct pci_io pi;
+
+	pi.pi_sel = *sel;
+	pi.pi_reg = reg;
+	pi.pi_width = width;
+
+	if (ioctl(fd, PCIOCREAD, &pi) < 0)
+		err(1, "ioctl(PCIOCREAD)");
+
+	return (pi.pi_data);
+}
 
 static struct pcisel
 getsel(const char *str)
 {
-	char *parse_buf, *ep;
-	struct pcisel sel = { .pc_func = 0};
+	char *ep = strchr(str, '@');
+	char *epbase;
+	struct pcisel sel;
+	unsigned long selarr[4];
+	int i;
+
+	if (ep == NULL)
+		ep = (char *)str;
+	else
+		ep++;
 
-	parse_buf = strdup(str);
-	ep = parse_buf;
+	epbase = ep;
 
 	if (strncmp(ep, "pci", 3) == 0) {
 		ep += 3;
-		sel.pc_bus = strtoul(ep, &ep, 0);
-		if (!ep || *ep++ != ':')
-			errx(1, "cannot parse selector %s", str);
-		sel.pc_dev = strtoul(ep, &ep, 0);
-		if (!ep || *ep != ':') {
+		i = 0;
+		do {
+			selarr[i++] = strtoul(ep, &ep, 10);
+		} while ((*ep == ':' || *ep == '.') && *++ep != '\0' && i < 4);
+
+		if (i > 2)
+			sel.pc_func = selarr[--i];
+		else
 			sel.pc_func = 0;
-		} else {
-			ep++;
-			sel.pc_func = strtoul(ep, &ep, 0);
-		}
+		sel.pc_dev = selarr[--i];
+		sel.pc_bus = selarr[--i];
+		if (i > 0)
+			sel.pc_domain = selarr[--i];
+		else
+			sel.pc_domain = 0;
 	}
-	if (*ep == ':')
-		ep++;
-	if (*ep || ep == parse_buf)
+	if (*ep != '\x0' || ep == epbase)
 		errx(1, "cannot parse selector %s", str);
-	free(parse_buf);
-
 	return sel;
 }
 
 static void
 readone(int fd, struct pcisel *sel, long reg, int width)
 {
-	struct pci_io pi;
-
-	pi.pi_sel = *sel;
-	pi.pi_reg = reg;
-	pi.pi_width = width;
-
-	if (ioctl(fd, PCIOCREAD, &pi) < 0)
-		err(1, "ioctl(PCIOCREAD)");
 
-	printf("0x%08x", pi.pi_data);
+	printf("%0*x", width*2, read_config(fd, sel, reg, width));
 }
 
 static void
@@ -510,14 +609,15 @@ readit(const char *name, const char *reg, int width)
 	rend = rstart = strtol(reg, &end, 0);
 	if (end && *end == ':') {
 		end++;
-		rend = strtol(end, NULL, 0);
+		rend = strtol(end, (char **) 0, 0);
 	}
 	sel = getsel(name);
-	for (i = 1, r = rstart; r <= rend; i++, r += width) {	
+	for (i = 1, r = rstart; r <= rend; i++, r += width) {
 		readone(fd, &sel, r, width);
-		putchar(i % 4 ? ' ' : '\n');
+		if (i && !(i % 8)) putchar(' ');
+		putchar(i % (16/width) ? ' ' : '\n');
 	}
-	if (i % 4 != 1)
+	if (i % (16/width) != 1)
 		putchar('\n');
 	close(fd);
 }
@@ -529,9 +629,9 @@ writeit(const char *name, const char *reg, const char *data, int width)
 	struct pci_io pi;
 
 	pi.pi_sel = getsel(name);
-	pi.pi_reg = strtoul(reg, NULL, 0); /* XXX error check */
+	pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */
 	pi.pi_width = width;
-	pi.pi_data = strtoul(data, NULL, 0); /* XXX error check */
+	pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */
 
 	fd = open(_PATH_DEVPCI, O_RDWR, 0);
 	if (fd < 0)
@@ -542,7 +642,7 @@ writeit(const char *name, const char *reg, const char *data, int width)
 }
 
 static void
-chkattached (const char *name, int width)
+chkattached(const char *name, int width)
 {
 	int fd;
 	struct pci_io pi;
diff --git a/usr.sbin/pciconf/pciconf.h b/usr.sbin/pciconf/pciconf.h
new file mode 100644
index 0000000..d01de5f
--- /dev/null
+++ b/usr.sbin/pciconf/pciconf.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2007 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.sbin/pciconf/pciconf.h,v 1.1.4.1.6.1 2009/04/15 03:14:26 kensmith Exp $
+ */
+
+#ifndef __PCICONF_H__
+#define	__PCICONF_H__
+
+void	list_caps(int fd, struct pci_conf *p);
+uint32_t read_config(int fd, struct pcisel *sel, long reg, int width);
+
+#endif
-- 
1.6.2.5

