- Teach pciconf(8) to list the PCI capabilities supported by each device

via a new -c flag to be used with -l.  Some simple parsing code is
  present for the following capabilities: Power Management, AGP, VPD,
  MSI, PCI-X, HyperTransport, Vendor-specific, EHCI Debug Port, PCI-PCI
  bridge subvendor ID, PCI-express, and MSI-X.
- Fix a few warnings in pciconf.c.
- Update some cruft in pciconf(8):
  - PCI 2.1 is no longer a revolutionary standard, and subvendor ID's are
    fairly common at this point, so reflect that.
  - Header type 2 is used for PCI-CardBus bridges.
  - Describe the -v option for -l after completing the basic -l description
    instead of disrupting the flow in the middle.

Reviewed by:	imp (partially)
MFC after:	1 week
This commit is contained in:
John Baldwin 2007-02-02 19:54:17 +00:00
parent f50589d755
commit 8866f04eb1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=166435
5 changed files with 593 additions and 46 deletions

View File

@ -2,6 +2,7 @@
# $FreeBSD$
PROG= pciconf
SRCS= pciconf.c cap.c
MAN= pciconf.8
CFLAGS+= -I${.CURDIR}/../../sys

477
usr.sbin/pciconf/cap.c Normal file
View File

@ -0,0 +1,477 @@
/*-
* Copyright (c) 2007 John Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
* 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.
*/
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/types.h>
#include <err.h>
#include <stdio.h>
#include <sys/agpio.h>
#include <sys/pciio.h>
#include <pci/agpreg.h>
#include <dev/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 address window %s at 0x",
command & PCIM_HTCMD_MSI_ENABLE ? "enabled" :
"disabled");
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;
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 + PCIR_EXPRESS_FLAGS, 2);
printf("PCI-Express %d ", flags & PCIM_EXP_FLAGS_VERSION);
switch (flags & PCIM_EXP_FLAGS_TYPE) {
case PCIM_EXP_TYPE_ENDPOINT:
printf("endpoint");
break;
case PCIM_EXP_TYPE_LEGACY_ENDPOINT:
printf("legacy endpoint");
break;
case PCIM_EXP_TYPE_ROOT_PORT:
printf("root port");
break;
case PCIM_EXP_TYPE_UPSTREAM_PORT:
printf("upstream port");
break;
case PCIM_EXP_TYPE_DOWNSTREAM_PORT:
printf("downstream port");
break;
case PCIM_EXP_TYPE_PCI_BRIDGE:
printf("PCI bridge");
break;
default:
printf("type %d", (flags & PCIM_EXP_FLAGS_TYPE) >> 8);
break;
}
if (flags & PCIM_EXP_FLAGS_IRQ)
printf(" IRQ %d", (flags & PCIM_EXP_FLAGS_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);
}
}

View File

@ -33,7 +33,7 @@
.Nd diagnostic utility for the PCI bus
.Sh SYNOPSIS
.Nm
.Fl l Op Fl v
.Fl l Op Fl cv
.Nm
.Fl a Ar selector
.Nm
@ -61,13 +61,6 @@ 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
.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 .
@ -86,12 +79,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
@ -101,11 +89,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
@ -115,6 +108,30 @@ device, it is a
device, which contains several (similar or independent) functions on
one chip.
.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 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

View File

@ -35,6 +35,7 @@ static const char rcsid[] =
#include <sys/types.h>
#include <sys/fcntl.h>
#include <ctype.h>
#include <err.h>
#include <stdlib.h>
#include <stdio.h>
@ -46,6 +47,7 @@ static const char rcsid[] =
#include <dev/pci/pcireg.h>
#include "pathnames.h"
#include "pciconf.h"
struct pci_device_info
{
@ -64,10 +66,10 @@ struct pci_vendor_info
TAILQ_HEAD(,pci_vendor_info) pci_vendors;
static void list_devs(int vendors);
static void list_devs(int verbose, int caps);
static void list_verbose(struct pci_conf *p);
static char *guess_class(struct pci_conf *p);
static char *guess_subclass(struct pci_conf *p);
static const char *guess_class(struct pci_conf *p);
static const char *guess_subclass(struct pci_conf *p);
static int load_vendors(void);
static void readit(const char *, const char *, int);
static void writeit(const char *, const char *, const char *, int);
@ -76,10 +78,10 @@ static void chkattached(const char *, int);
static int exitstatus = 0;
static void
usage()
usage(void)
{
fprintf(stderr, "%s\n%s\n%s\n%s\n",
"usage: pciconf -l [-v]",
"usage: pciconf -l [-cv]",
" pciconf -a selector",
" pciconf -r [-b | -h] selector addr[:addr2]",
" pciconf -w [-b | -h] selector addr value");
@ -90,17 +92,21 @@ int
main(int argc, char **argv)
{
int c;
int listmode, readmode, writemode, attachedmode, verbose;
int listmode, readmode, writemode, attachedmode, caps, verbose;
int byte, isshort;
listmode = readmode = writemode = attachedmode = verbose = byte = isshort = 0;
listmode = readmode = writemode = attachedmode = caps = verbose = byte = isshort = 0;
while ((c = getopt(argc, argv, "alrwbhv")) != -1) {
while ((c = getopt(argc, argv, "aclrwbhv")) != -1) {
switch(c) {
case 'a':
attachedmode = 1;
break;
case 'c':
caps = 1;
break;
case 'l':
listmode = 1;
break;
@ -137,7 +143,7 @@ main(int argc, char **argv)
usage();
if (listmode) {
list_devs(verbose);
list_devs(verbose, caps);
} else if (attachedmode) {
chkattached(argv[optind],
byte ? 1 : isshort ? 2 : 4);
@ -155,7 +161,7 @@ main(int argc, char **argv)
}
static void
list_devs(int verbose)
list_devs(int verbose, int caps)
{
int fd;
struct pci_conf_io pc;
@ -165,7 +171,7 @@ list_devs(int verbose)
if (verbose)
load_vendors();
fd = open(_PATH_DEVPCI, O_RDONLY, 0);
fd = open(_PATH_DEVPCI, caps ? O_RDWR : O_RDONLY, 0);
if (fd < 0)
err(1, "%s", _PATH_DEVPCI);
@ -212,6 +218,8 @@ list_devs(int verbose)
p->pc_revid, p->pc_hdr);
if (verbose)
list_verbose(p);
if (caps)
list_caps(fd, p);
}
} while (pc.status == PCI_GETCONF_MORE_DEVS);
@ -223,11 +231,11 @@ list_verbose(struct pci_conf *p)
{
struct pci_vendor_info *vi;
struct pci_device_info *di;
char *dp;
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;
}
}
@ -236,15 +244,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);
}
/*
@ -254,7 +262,7 @@ static struct
{
int class;
int subclass;
char *desc;
const char *desc;
} pci_nomatch_tab[] = {
{PCIC_OLD, -1, "old"},
{PCIC_OLD, PCIS_OLD_NONVGA, "non-VGA display device"},
@ -337,7 +345,7 @@ static struct
{0, 0, NULL}
};
static char *
static const char *
guess_class(struct pci_conf *p)
{
int i;
@ -349,7 +357,7 @@ guess_class(struct pci_conf *p)
return(NULL);
}
static char *
static const char *
guess_subclass(struct pci_conf *p)
{
int i;
@ -365,7 +373,7 @@ guess_subclass(struct pci_conf *p)
static int
load_vendors(void)
{
char *dbf;
const char *dbf;
FILE *db;
struct pci_vendor_info *cv;
struct pci_device_info *cd;
@ -458,6 +466,20 @@ load_vendors(void)
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)
@ -496,16 +518,8 @@ getsel(const char *str)
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("%0*x", width*2, pi.pi_data);
printf("%0*x", width*2, read_config(fd, sel, reg, width));
}
static void
@ -559,7 +573,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;

View File

@ -0,0 +1,38 @@
/*-
* Copyright (c) 2007 John Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
* 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$
*/
#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