From 8866f04eb1a3da57402c11225be3e2a2bfb48552 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Fri, 2 Feb 2007 19:54:17 +0000 Subject: [PATCH] - 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 --- usr.sbin/pciconf/Makefile | 1 + usr.sbin/pciconf/cap.c | 477 +++++++++++++++++++++++++++++++++++++ usr.sbin/pciconf/pciconf.8 | 49 ++-- usr.sbin/pciconf/pciconf.c | 74 +++--- usr.sbin/pciconf/pciconf.h | 38 +++ 5 files changed, 593 insertions(+), 46 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 d892a1282197..e57e736fe2c1 100644 --- a/usr.sbin/pciconf/Makefile +++ b/usr.sbin/pciconf/Makefile @@ -2,6 +2,7 @@ # $FreeBSD$ PROG= pciconf +SRCS= pciconf.c cap.c MAN= pciconf.8 CFLAGS+= -I${.CURDIR}/../../sys diff --git a/usr.sbin/pciconf/cap.c b/usr.sbin/pciconf/cap.c new file mode 100644 index 000000000000..b0ec40ff09c7 --- /dev/null +++ b/usr.sbin/pciconf/cap.c @@ -0,0 +1,477 @@ +/*- + * Copyright (c) 2007 John Baldwin + * 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 + +#include +#include +#include +#include + +#include +#include + +#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); + } +} diff --git a/usr.sbin/pciconf/pciconf.8 b/usr.sbin/pciconf/pciconf.8 index ea41bbad46b9..524cf1e4db9b 100644 --- a/usr.sbin/pciconf/pciconf.8 +++ b/usr.sbin/pciconf/pciconf.8 @@ -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 diff --git a/usr.sbin/pciconf/pciconf.c b/usr.sbin/pciconf/pciconf.c index 8fc3146d1fd0..a42435c5a70b 100644 --- a/usr.sbin/pciconf/pciconf.c +++ b/usr.sbin/pciconf/pciconf.c @@ -35,6 +35,7 @@ static const char rcsid[] = #include #include +#include #include #include #include @@ -46,6 +47,7 @@ static const char rcsid[] = #include #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; diff --git a/usr.sbin/pciconf/pciconf.h b/usr.sbin/pciconf/pciconf.h new file mode 100644 index 000000000000..81d94f548955 --- /dev/null +++ b/usr.sbin/pciconf/pciconf.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2007 John Baldwin + * 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