119102Sse/* 219102Sse * Copyright 1996 Massachusetts Institute of Technology 319102Sse * 419102Sse * Permission to use, copy, modify, and distribute this software and 519102Sse * its documentation for any purpose and without fee is hereby 619102Sse * granted, provided that both the above copyright notice and this 719102Sse * permission notice appear in all copies, that both the above 819102Sse * copyright notice and this permission notice appear in all 919102Sse * supporting documentation, and that the name of M.I.T. not be used 1019102Sse * in advertising or publicity pertaining to distribution of the 1119102Sse * software without specific, written prior permission. M.I.T. makes 1219102Sse * no representations about the suitability of this software for any 1319102Sse * purpose. It is provided "as is" without express or implied 1419102Sse * warranty. 15149223Sdes * 1619102Sse * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 1719102Sse * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 1819102Sse * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1919102Sse * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 2019102Sse * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2119102Sse * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2219102Sse * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 2319102Sse * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2419102Sse * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2519102Sse * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 2619102Sse * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2719102Sse * SUCH DAMAGE. 2819102Sse */ 2919102Sse 3030172Scharnier#ifndef lint 3130172Scharnierstatic const char rcsid[] = 3250479Speter "$FreeBSD: releng/11.0/usr.sbin/pciconf/pciconf.c 295806 2016-02-19 14:01:35Z se $"; 3330172Scharnier#endif /* not lint */ 3430172Scharnier 3519102Sse#include <sys/types.h> 3619102Sse#include <sys/fcntl.h> 3719102Sse 38260910Sjhb#include <assert.h> 39166435Sjhb#include <ctype.h> 4019102Sse#include <err.h> 41188018Sjhb#include <inttypes.h> 42291225Sjhb#include <stdbool.h> 4319102Sse#include <stdlib.h> 4419102Sse#include <stdio.h> 4519102Sse#include <string.h> 4619102Sse#include <unistd.h> 4754322Sken#include <sys/pciio.h> 4869700Smsmith#include <sys/queue.h> 4919102Sse 5069785Smsmith#include <dev/pci/pcireg.h> 5169700Smsmith 5219102Sse#include "pathnames.h" 53166435Sjhb#include "pciconf.h" 5419102Sse 55149223Sdesstruct pci_device_info 5669700Smsmith{ 5769700Smsmith TAILQ_ENTRY(pci_device_info) link; 5869700Smsmith int id; 5969700Smsmith char *desc; 6069700Smsmith}; 6169700Smsmith 6269700Smsmithstruct pci_vendor_info 6369700Smsmith{ 6469700Smsmith TAILQ_ENTRY(pci_vendor_info) link; 6569700Smsmith TAILQ_HEAD(,pci_device_info) devs; 6669700Smsmith int id; 6769700Smsmith char *desc; 6869700Smsmith}; 6969700Smsmith 70295760Ssestatic TAILQ_HEAD(,pci_vendor_info) pci_vendors; 7169700Smsmith 72260910Sjhbstatic struct pcisel getsel(const char *str); 73291225Sjhbstatic void list_bridge(int fd, struct pci_conf *p); 74188018Sjhbstatic void list_bars(int fd, struct pci_conf *p); 75291225Sjhbstatic void list_devs(const char *name, int verbose, int bars, int bridge, 76291225Sjhb int caps, int errors, int vpd); 7769700Smsmithstatic void list_verbose(struct pci_conf *p); 78260926Sjhbstatic void list_vpd(int fd, struct pci_conf *p); 79166435Sjhbstatic const char *guess_class(struct pci_conf *p); 80166435Sjhbstatic const char *guess_subclass(struct pci_conf *p); 8169700Smsmithstatic int load_vendors(void); 8219102Ssestatic void readit(const char *, const char *, int); 8319102Ssestatic void writeit(const char *, const char *, const char *, int); 84212329Sjhbstatic void chkattached(const char *); 8519102Sse 8650225Speterstatic int exitstatus = 0; 8719102Sse 8819102Ssestatic void 89166435Sjhbusage(void) 9030172Scharnier{ 9130172Scharnier fprintf(stderr, "%s\n%s\n%s\n%s\n", 92291225Sjhb "usage: pciconf -l [-BbcevV] [device]", 93260910Sjhb " pciconf -a device", 94260910Sjhb " pciconf -r [-b | -h] device addr[:addr2]", 95260910Sjhb " pciconf -w [-b | -h] device addr value"); 9619817Sse exit (1); 9719102Sse} 9819102Sse 9919102Sseint 10019102Ssemain(int argc, char **argv) 10119102Sse{ 10219102Sse int c; 103236415Sjhb int listmode, readmode, writemode, attachedmode; 104291225Sjhb int bars, bridge, caps, errors, verbose, vpd; 10519102Sse int byte, isshort; 10619102Sse 107236415Sjhb listmode = readmode = writemode = attachedmode = 0; 108291225Sjhb bars = bridge = caps = errors = verbose = vpd = byte = isshort = 0; 10919102Sse 110291225Sjhb while ((c = getopt(argc, argv, "aBbcehlrwVv")) != -1) { 11119102Sse switch(c) { 11221935Sse case 'a': 11321935Sse attachedmode = 1; 11421935Sse break; 11521935Sse 116291225Sjhb case 'B': 117291225Sjhb bridge = 1; 118291225Sjhb break; 119291225Sjhb 120182707Simp case 'b': 121188018Sjhb bars = 1; 122182707Simp byte = 1; 123182707Simp break; 124182707Simp 125166435Sjhb case 'c': 126166435Sjhb caps = 1; 127166435Sjhb break; 128166435Sjhb 129236415Sjhb case 'e': 130236415Sjhb errors = 1; 131236415Sjhb break; 132236415Sjhb 133182707Simp case 'h': 134182707Simp isshort = 1; 135182707Simp break; 136182707Simp 13719102Sse case 'l': 13819102Sse listmode = 1; 13919102Sse break; 14019102Sse 14119102Sse case 'r': 14219102Sse readmode = 1; 14319102Sse break; 144149223Sdes 14519102Sse case 'w': 14619102Sse writemode = 1; 14719102Sse break; 14819102Sse 14968677Smsmith case 'v': 15069700Smsmith verbose = 1; 15168677Smsmith break; 15268677Smsmith 153260926Sjhb case 'V': 154260926Sjhb vpd = 1; 155260926Sjhb break; 156260926Sjhb 15719102Sse default: 15830172Scharnier usage(); 15919102Sse } 16019102Sse } 16119102Sse 162260910Sjhb if ((listmode && optind >= argc + 1) 16319102Sse || (writemode && optind + 3 != argc) 16421935Sse || (readmode && optind + 2 != argc) 165133271Simp || (attachedmode && optind + 1 != argc)) 16630172Scharnier usage(); 16719102Sse 16819102Sse if (listmode) { 169260910Sjhb list_devs(optind + 1 == argc ? argv[optind] : NULL, verbose, 170291225Sjhb bars, bridge, caps, errors, vpd); 17177513Simp } else if (attachedmode) { 172212329Sjhb chkattached(argv[optind]); 17377513Simp } else if (readmode) { 174149223Sdes readit(argv[optind], argv[optind + 1], 175182708Simp byte ? 1 : isshort ? 2 : 4); 17677513Simp } else if (writemode) { 17719102Sse writeit(argv[optind], argv[optind + 1], argv[optind + 2], 178182708Simp byte ? 1 : isshort ? 2 : 4); 17919102Sse } else { 180149223Sdes usage(); 18119102Sse } 18219102Sse 18321935Sse return exitstatus; 18419102Sse} 18519102Sse 18619102Ssestatic void 187291225Sjhblist_devs(const char *name, int verbose, int bars, int bridge, int caps, 188291225Sjhb int errors, int vpd) 18919102Sse{ 19019102Sse int fd; 19119102Sse struct pci_conf_io pc; 19219102Sse struct pci_conf conf[255], *p; 193260910Sjhb struct pci_match_conf patterns[1]; 19441103Sken int none_count = 0; 19519102Sse 19669700Smsmith if (verbose) 19769700Smsmith load_vendors(); 19869700Smsmith 199291225Sjhb fd = open(_PATH_DEVPCI, (bridge || caps || errors) ? O_RDWR : O_RDONLY, 200291225Sjhb 0); 20119102Sse if (fd < 0) 20219102Sse err(1, "%s", _PATH_DEVPCI); 20319102Sse 20439231Sgibbs bzero(&pc, sizeof(struct pci_conf_io)); 20539231Sgibbs pc.match_buf_len = sizeof(conf); 20639231Sgibbs pc.matches = conf; 207260910Sjhb if (name != NULL) { 208260910Sjhb bzero(&patterns, sizeof(patterns)); 209260910Sjhb patterns[0].pc_sel = getsel(name); 210260910Sjhb patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | 211260910Sjhb PCI_GETCONF_MATCH_BUS | PCI_GETCONF_MATCH_DEV | 212260910Sjhb PCI_GETCONF_MATCH_FUNC; 213260910Sjhb pc.num_patterns = 1; 214260910Sjhb pc.pat_buf_len = sizeof(patterns); 215260910Sjhb pc.patterns = patterns; 216260910Sjhb } 21719102Sse 21839231Sgibbs do { 21939231Sgibbs if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 22039231Sgibbs err(1, "ioctl(PCIOCGETCONF)"); 22119102Sse 22239231Sgibbs /* 22339231Sgibbs * 255 entries should be more than enough for most people, 22439231Sgibbs * but if someone has more devices, and then changes things 225228990Suqs * around between ioctls, we'll do the cheesy thing and 22639231Sgibbs * just bail. The alternative would be to go back to the 22739231Sgibbs * beginning of the list, and print things twice, which may 228228990Suqs * not be desirable. 22939231Sgibbs */ 23039231Sgibbs if (pc.status == PCI_GETCONF_LIST_CHANGED) { 23139231Sgibbs warnx("PCI device list changed, please try again"); 23239231Sgibbs exitstatus = 1; 23339231Sgibbs close(fd); 23439231Sgibbs return; 23539231Sgibbs } else if (pc.status == PCI_GETCONF_ERROR) { 23653761Scharnier warnx("error returned from PCIOCGETCONF ioctl"); 23739231Sgibbs exitstatus = 1; 23839231Sgibbs close(fd); 23939231Sgibbs return; 24039231Sgibbs } 24139231Sgibbs for (p = conf; p < &conf[pc.num_matches]; p++) { 242172394Smarius printf("%s%d@pci%d:%d:%d:%d:\tclass=0x%06x card=0x%08x " 243182708Simp "chip=0x%08x rev=0x%02x hdr=0x%02x\n", 244277856Sdim *p->pd_name ? p->pd_name : 245182708Simp "none", 246277856Sdim *p->pd_name ? (int)p->pd_unit : 247182708Simp none_count++, p->pc_sel.pc_domain, 248182708Simp p->pc_sel.pc_bus, p->pc_sel.pc_dev, 249182708Simp p->pc_sel.pc_func, (p->pc_class << 16) | 250182708Simp (p->pc_subclass << 8) | p->pc_progif, 251182708Simp (p->pc_subdevice << 16) | p->pc_subvendor, 252182708Simp (p->pc_device << 16) | p->pc_vendor, 253182708Simp p->pc_revid, p->pc_hdr); 25469700Smsmith if (verbose) 25569700Smsmith list_verbose(p); 256188018Sjhb if (bars) 257188018Sjhb list_bars(fd, p); 258291225Sjhb if (bridge) 259291225Sjhb list_bridge(fd, p); 260166435Sjhb if (caps) 261166435Sjhb list_caps(fd, p); 262236415Sjhb if (errors) 263236415Sjhb list_errors(fd, p); 264260926Sjhb if (vpd) 265260926Sjhb list_vpd(fd, p); 26639231Sgibbs } 26739231Sgibbs } while (pc.status == PCI_GETCONF_MORE_DEVS); 26839231Sgibbs 26919102Sse close(fd); 27019102Sse} 27119102Sse 27268677Smsmithstatic void 273291225Sjhbprint_bus_range(int fd, struct pci_conf *p, int secreg, int subreg) 274291225Sjhb{ 275291225Sjhb uint8_t secbus, subbus; 276291225Sjhb 277291225Sjhb secbus = read_config(fd, &p->pc_sel, secreg, 1); 278291225Sjhb subbus = read_config(fd, &p->pc_sel, subreg, 1); 279291225Sjhb printf(" bus range = %u-%u\n", secbus, subbus); 280291225Sjhb} 281291225Sjhb 282291225Sjhbstatic void 283291225Sjhbprint_window(int reg, const char *type, int range, uint64_t base, 284291225Sjhb uint64_t limit) 285291225Sjhb{ 286291225Sjhb 287291225Sjhb printf(" window[%02x] = type %s, range %2d, addr %#jx-%#jx, %s\n", 288291225Sjhb reg, type, range, (uintmax_t)base, (uintmax_t)limit, 289291225Sjhb base < limit ? "enabled" : "disabled"); 290291225Sjhb} 291291225Sjhb 292291225Sjhbstatic void 293291225Sjhbprint_special_decode(bool isa, bool vga, bool subtractive) 294291225Sjhb{ 295291225Sjhb bool comma; 296291225Sjhb 297291225Sjhb if (isa || vga || subtractive) { 298291225Sjhb comma = false; 299291225Sjhb printf(" decode = "); 300291225Sjhb if (isa) { 301291225Sjhb printf("ISA"); 302291225Sjhb comma = true; 303291225Sjhb } 304291225Sjhb if (vga) { 305291225Sjhb printf("%sVGA", comma ? ", " : ""); 306291225Sjhb comma = true; 307291225Sjhb } 308291225Sjhb if (subtractive) 309291225Sjhb printf("%ssubtractive", comma ? ", " : ""); 310291225Sjhb printf("\n"); 311291225Sjhb } 312291225Sjhb} 313291225Sjhb 314291225Sjhbstatic void 315291225Sjhbprint_bridge_windows(int fd, struct pci_conf *p) 316291225Sjhb{ 317291225Sjhb uint64_t base, limit; 318291225Sjhb uint32_t val; 319291225Sjhb uint16_t bctl; 320291225Sjhb bool subtractive; 321291225Sjhb int range; 322291225Sjhb 323291225Sjhb /* 324291225Sjhb * XXX: This assumes that a window with a base and limit of 0 325291225Sjhb * is not implemented. In theory a window might be programmed 326291225Sjhb * at the smallest size with a base of 0, but those do not seem 327291225Sjhb * common in practice. 328291225Sjhb */ 329291225Sjhb val = read_config(fd, &p->pc_sel, PCIR_IOBASEL_1, 1); 330291225Sjhb if (val != 0 || read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1) != 0) { 331291225Sjhb if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 332291225Sjhb base = PCI_PPBIOBASE( 333291225Sjhb read_config(fd, &p->pc_sel, PCIR_IOBASEH_1, 2), 334291225Sjhb val); 335291225Sjhb limit = PCI_PPBIOLIMIT( 336291225Sjhb read_config(fd, &p->pc_sel, PCIR_IOLIMITH_1, 2), 337291225Sjhb read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1)); 338291225Sjhb range = 32; 339291225Sjhb } else { 340291225Sjhb base = PCI_PPBIOBASE(0, val); 341291225Sjhb limit = PCI_PPBIOLIMIT(0, 342291225Sjhb read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1)); 343291225Sjhb range = 16; 344291225Sjhb } 345291225Sjhb print_window(PCIR_IOBASEL_1, "I/O Port", range, base, limit); 346291225Sjhb } 347291225Sjhb 348291225Sjhb base = PCI_PPBMEMBASE(0, 349291225Sjhb read_config(fd, &p->pc_sel, PCIR_MEMBASE_1, 2)); 350291225Sjhb limit = PCI_PPBMEMLIMIT(0, 351291225Sjhb read_config(fd, &p->pc_sel, PCIR_MEMLIMIT_1, 2)); 352291225Sjhb print_window(PCIR_MEMBASE_1, "Memory", 32, base, limit); 353291225Sjhb 354291225Sjhb val = read_config(fd, &p->pc_sel, PCIR_PMBASEL_1, 2); 355291225Sjhb if (val != 0 || read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2) != 0) { 356291225Sjhb if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { 357291225Sjhb base = PCI_PPBMEMBASE( 358291225Sjhb read_config(fd, &p->pc_sel, PCIR_PMBASEH_1, 4), 359291225Sjhb val); 360291225Sjhb limit = PCI_PPBMEMLIMIT( 361291225Sjhb read_config(fd, &p->pc_sel, PCIR_PMLIMITH_1, 4), 362291225Sjhb read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2)); 363291225Sjhb range = 64; 364291225Sjhb } else { 365291225Sjhb base = PCI_PPBMEMBASE(0, val); 366291225Sjhb limit = PCI_PPBMEMLIMIT(0, 367291225Sjhb read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2)); 368291225Sjhb range = 32; 369291225Sjhb } 370291225Sjhb print_window(PCIR_PMBASEL_1, "Prefetchable Memory", range, base, 371291225Sjhb limit); 372291225Sjhb } 373291225Sjhb 374291225Sjhb /* 375291225Sjhb * XXX: This list of bridges that are subtractive but do not set 376291225Sjhb * progif to indicate it is copied from pci_pci.c. 377291225Sjhb */ 378291225Sjhb subtractive = p->pc_progif == PCIP_BRIDGE_PCI_SUBTRACTIVE; 379291225Sjhb switch (p->pc_device << 16 | p->pc_vendor) { 380291225Sjhb case 0xa002177d: /* Cavium ThunderX */ 381291225Sjhb case 0x124b8086: /* Intel 82380FB Mobile */ 382291225Sjhb case 0x060513d7: /* Toshiba ???? */ 383291225Sjhb subtractive = true; 384291225Sjhb } 385291225Sjhb if (p->pc_vendor == 0x8086 && (p->pc_device & 0xff00) == 0x2400) 386291225Sjhb subtractive = true; 387291225Sjhb 388291225Sjhb bctl = read_config(fd, &p->pc_sel, PCIR_BRIDGECTL_1, 2); 389291225Sjhb print_special_decode(bctl & PCIB_BCR_ISA_ENABLE, 390291225Sjhb bctl & PCIB_BCR_VGA_ENABLE, subtractive); 391291225Sjhb} 392291225Sjhb 393291225Sjhbstatic void 394291225Sjhbprint_cardbus_mem_window(int fd, struct pci_conf *p, int basereg, int limitreg, 395291225Sjhb bool prefetch) 396291225Sjhb{ 397291225Sjhb 398291225Sjhb print_window(basereg, prefetch ? "Prefetchable Memory" : "Memory", 32, 399291225Sjhb PCI_CBBMEMBASE(read_config(fd, &p->pc_sel, basereg, 4)), 400291225Sjhb PCI_CBBMEMLIMIT(read_config(fd, &p->pc_sel, limitreg, 4))); 401291225Sjhb} 402291225Sjhb 403291225Sjhbstatic void 404291225Sjhbprint_cardbus_io_window(int fd, struct pci_conf *p, int basereg, int limitreg) 405291225Sjhb{ 406291225Sjhb uint32_t base, limit; 407291225Sjhb uint32_t val; 408291225Sjhb int range; 409291225Sjhb 410291225Sjhb val = read_config(fd, &p->pc_sel, basereg, 2); 411291225Sjhb if ((val & PCIM_CBBIO_MASK) == PCIM_CBBIO_32) { 412291225Sjhb base = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, basereg, 4)); 413291225Sjhb limit = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, limitreg, 4)); 414291225Sjhb range = 32; 415291225Sjhb } else { 416291225Sjhb base = PCI_CBBIOBASE(val); 417291225Sjhb limit = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, limitreg, 2)); 418291225Sjhb range = 16; 419291225Sjhb } 420291225Sjhb print_window(basereg, "I/O Port", range, base, limit); 421291225Sjhb} 422291225Sjhb 423291225Sjhbstatic void 424291225Sjhbprint_cardbus_windows(int fd, struct pci_conf *p) 425291225Sjhb{ 426291225Sjhb uint16_t bctl; 427291225Sjhb 428291225Sjhb bctl = read_config(fd, &p->pc_sel, PCIR_BRIDGECTL_2, 2); 429291225Sjhb print_cardbus_mem_window(fd, p, PCIR_MEMBASE0_2, PCIR_MEMLIMIT0_2, 430291225Sjhb bctl & CBB_BCR_PREFETCH_0_ENABLE); 431291225Sjhb print_cardbus_mem_window(fd, p, PCIR_MEMBASE1_2, PCIR_MEMLIMIT1_2, 432291225Sjhb bctl & CBB_BCR_PREFETCH_1_ENABLE); 433291225Sjhb print_cardbus_io_window(fd, p, PCIR_IOBASE0_2, PCIR_IOLIMIT0_2); 434291225Sjhb print_cardbus_io_window(fd, p, PCIR_IOBASE1_2, PCIR_IOLIMIT1_2); 435291225Sjhb print_special_decode(bctl & CBB_BCR_ISA_ENABLE, 436291225Sjhb bctl & CBB_BCR_VGA_ENABLE, false); 437291225Sjhb} 438291225Sjhb 439291225Sjhbstatic void 440291225Sjhblist_bridge(int fd, struct pci_conf *p) 441291225Sjhb{ 442291225Sjhb 443291225Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 444291225Sjhb case PCIM_HDRTYPE_BRIDGE: 445291225Sjhb print_bus_range(fd, p, PCIR_SECBUS_1, PCIR_SUBBUS_1); 446291225Sjhb print_bridge_windows(fd, p); 447291225Sjhb break; 448291225Sjhb case PCIM_HDRTYPE_CARDBUS: 449291225Sjhb print_bus_range(fd, p, PCIR_SECBUS_2, PCIR_SUBBUS_2); 450291225Sjhb print_cardbus_windows(fd, p); 451291225Sjhb break; 452291225Sjhb } 453291225Sjhb} 454291225Sjhb 455291225Sjhbstatic void 456188018Sjhblist_bars(int fd, struct pci_conf *p) 457188018Sjhb{ 458279466Srstone int i, max; 459188018Sjhb 460188018Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 461188018Sjhb case PCIM_HDRTYPE_NORMAL: 462188018Sjhb max = PCIR_MAX_BAR_0; 463188018Sjhb break; 464188018Sjhb case PCIM_HDRTYPE_BRIDGE: 465188018Sjhb max = PCIR_MAX_BAR_1; 466188018Sjhb break; 467188018Sjhb case PCIM_HDRTYPE_CARDBUS: 468188018Sjhb max = PCIR_MAX_BAR_2; 469188018Sjhb break; 470188018Sjhb default: 471188018Sjhb return; 472188018Sjhb } 473188018Sjhb 474279466Srstone for (i = 0; i <= max; i++) 475279466Srstone print_bar(fd, p, "bar ", PCIR_BAR(i)); 476279466Srstone} 477279466Srstone 478279466Srstonevoid 479279466Srstoneprint_bar(int fd, struct pci_conf *p, const char *label, uint16_t bar_offset) 480279466Srstone{ 481279466Srstone uint64_t base; 482279466Srstone const char *type; 483279466Srstone struct pci_bar_io bar; 484279466Srstone int range; 485279466Srstone 486279466Srstone bar.pbi_sel = p->pc_sel; 487279466Srstone bar.pbi_reg = bar_offset; 488279466Srstone if (ioctl(fd, PCIOCGETBAR, &bar) < 0) 489279466Srstone return; 490279466Srstone if (PCI_BAR_IO(bar.pbi_base)) { 491279466Srstone type = "I/O Port"; 492279466Srstone range = 32; 493279466Srstone base = bar.pbi_base & PCIM_BAR_IO_BASE; 494279466Srstone } else { 495279466Srstone if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH) 496279466Srstone type = "Prefetchable Memory"; 497279466Srstone else 498279466Srstone type = "Memory"; 499279466Srstone switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) { 500279466Srstone case PCIM_BAR_MEM_32: 501188018Sjhb range = 32; 502279466Srstone break; 503279466Srstone case PCIM_BAR_MEM_1MB: 504279466Srstone range = 20; 505279466Srstone break; 506279466Srstone case PCIM_BAR_MEM_64: 507279466Srstone range = 64; 508279466Srstone break; 509279466Srstone default: 510279466Srstone range = -1; 511188018Sjhb } 512279466Srstone base = bar.pbi_base & ~((uint64_t)0xf); 513188018Sjhb } 514279466Srstone printf(" %s[%02x] = type %s, range %2d, base %#jx, ", 515279466Srstone label, bar_offset, type, range, (uintmax_t)base); 516279466Srstone printf("size %ju, %s\n", (uintmax_t)bar.pbi_length, 517279466Srstone bar.pbi_enabled ? "enabled" : "disabled"); 518188018Sjhb} 519188018Sjhb 520188018Sjhbstatic void 52169700Smsmithlist_verbose(struct pci_conf *p) 52268677Smsmith{ 52369700Smsmith struct pci_vendor_info *vi; 52469700Smsmith struct pci_device_info *di; 525166435Sjhb const char *dp; 526149223Sdes 52769700Smsmith TAILQ_FOREACH(vi, &pci_vendors, link) { 52869700Smsmith if (vi->id == p->pc_vendor) { 529166435Sjhb printf(" vendor = '%s'\n", vi->desc); 53068677Smsmith break; 53169700Smsmith } 53269700Smsmith } 53369700Smsmith if (vi == NULL) { 53469700Smsmith di = NULL; 53568677Smsmith } else { 53669700Smsmith TAILQ_FOREACH(di, &vi->devs, link) { 53769700Smsmith if (di->id == p->pc_device) { 538166435Sjhb printf(" device = '%s'\n", di->desc); 53969700Smsmith break; 54069700Smsmith } 54169700Smsmith } 54268677Smsmith } 54369700Smsmith if ((dp = guess_class(p)) != NULL) 544166435Sjhb printf(" class = %s\n", dp); 54569700Smsmith if ((dp = guess_subclass(p)) != NULL) 546166435Sjhb printf(" subclass = %s\n", dp); 54769700Smsmith} 54869700Smsmith 549260926Sjhbstatic void 550260926Sjhblist_vpd(int fd, struct pci_conf *p) 551260926Sjhb{ 552260926Sjhb struct pci_list_vpd_io list; 553260926Sjhb struct pci_vpd_element *vpd, *end; 554260926Sjhb 555260926Sjhb list.plvi_sel = p->pc_sel; 556260926Sjhb list.plvi_len = 0; 557260926Sjhb list.plvi_data = NULL; 558260926Sjhb if (ioctl(fd, PCIOCLISTVPD, &list) < 0 || list.plvi_len == 0) 559260926Sjhb return; 560260926Sjhb 561260926Sjhb list.plvi_data = malloc(list.plvi_len); 562260926Sjhb if (ioctl(fd, PCIOCLISTVPD, &list) < 0) { 563260926Sjhb free(list.plvi_data); 564260926Sjhb return; 565260926Sjhb } 566260926Sjhb 567260926Sjhb vpd = list.plvi_data; 568260926Sjhb end = (struct pci_vpd_element *)((char *)vpd + list.plvi_len); 569260926Sjhb for (; vpd < end; vpd = PVE_NEXT(vpd)) { 570260926Sjhb if (vpd->pve_flags == PVE_FLAG_IDENT) { 571260926Sjhb printf(" VPD ident = '%.*s'\n", 572260926Sjhb (int)vpd->pve_datalen, vpd->pve_data); 573260926Sjhb continue; 574260926Sjhb } 575260926Sjhb 576260926Sjhb /* Ignore the checksum keyword. */ 577260926Sjhb if (!(vpd->pve_flags & PVE_FLAG_RW) && 578260926Sjhb memcmp(vpd->pve_keyword, "RV", 2) == 0) 579260926Sjhb continue; 580260926Sjhb 581260926Sjhb /* Ignore remaining read-write space. */ 582260926Sjhb if (vpd->pve_flags & PVE_FLAG_RW && 583260926Sjhb memcmp(vpd->pve_keyword, "RW", 2) == 0) 584260926Sjhb continue; 585260926Sjhb 586260926Sjhb /* Handle extended capability keyword. */ 587260926Sjhb if (!(vpd->pve_flags & PVE_FLAG_RW) && 588260926Sjhb memcmp(vpd->pve_keyword, "CP", 2) == 0) { 589260926Sjhb printf(" VPD ro CP = ID %02x in map 0x%x[0x%x]\n", 590260926Sjhb (unsigned int)vpd->pve_data[0], 591260926Sjhb PCIR_BAR((unsigned int)vpd->pve_data[1]), 592260926Sjhb (unsigned int)vpd->pve_data[3] << 8 | 593260926Sjhb (unsigned int)vpd->pve_data[2]); 594260926Sjhb continue; 595260926Sjhb } 596260926Sjhb 597260926Sjhb /* Remaining keywords should all have ASCII values. */ 598260926Sjhb printf(" VPD %s %c%c = '%.*s'\n", 599260926Sjhb vpd->pve_flags & PVE_FLAG_RW ? "rw" : "ro", 600260926Sjhb vpd->pve_keyword[0], vpd->pve_keyword[1], 601260926Sjhb (int)vpd->pve_datalen, vpd->pve_data); 602260926Sjhb } 603260926Sjhb free(list.plvi_data); 604260926Sjhb} 605260926Sjhb 60669700Smsmith/* 60769700Smsmith * This is a direct cut-and-paste from the table in sys/dev/pci/pci.c. 60869700Smsmith */ 60969700Smsmithstatic struct 61069700Smsmith{ 61169700Smsmith int class; 61269700Smsmith int subclass; 613166435Sjhb const char *desc; 61469700Smsmith} pci_nomatch_tab[] = { 61569700Smsmith {PCIC_OLD, -1, "old"}, 61669700Smsmith {PCIC_OLD, PCIS_OLD_NONVGA, "non-VGA display device"}, 61769700Smsmith {PCIC_OLD, PCIS_OLD_VGA, "VGA-compatible display device"}, 61869700Smsmith {PCIC_STORAGE, -1, "mass storage"}, 61969700Smsmith {PCIC_STORAGE, PCIS_STORAGE_SCSI, "SCSI"}, 62069700Smsmith {PCIC_STORAGE, PCIS_STORAGE_IDE, "ATA"}, 62169700Smsmith {PCIC_STORAGE, PCIS_STORAGE_FLOPPY, "floppy disk"}, 62269700Smsmith {PCIC_STORAGE, PCIS_STORAGE_IPI, "IPI"}, 62369700Smsmith {PCIC_STORAGE, PCIS_STORAGE_RAID, "RAID"}, 624184936Smav {PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, "ATA (ADMA)"}, 625184936Smav {PCIC_STORAGE, PCIS_STORAGE_SATA, "SATA"}, 626184936Smav {PCIC_STORAGE, PCIS_STORAGE_SAS, "SAS"}, 627240739Sgavin {PCIC_STORAGE, PCIS_STORAGE_NVM, "NVM"}, 62869700Smsmith {PCIC_NETWORK, -1, "network"}, 62969700Smsmith {PCIC_NETWORK, PCIS_NETWORK_ETHERNET, "ethernet"}, 63069700Smsmith {PCIC_NETWORK, PCIS_NETWORK_TOKENRING, "token ring"}, 63169700Smsmith {PCIC_NETWORK, PCIS_NETWORK_FDDI, "fddi"}, 63269700Smsmith {PCIC_NETWORK, PCIS_NETWORK_ATM, "ATM"}, 633144156Sjmg {PCIC_NETWORK, PCIS_NETWORK_ISDN, "ISDN"}, 63469700Smsmith {PCIC_DISPLAY, -1, "display"}, 63569700Smsmith {PCIC_DISPLAY, PCIS_DISPLAY_VGA, "VGA"}, 63669700Smsmith {PCIC_DISPLAY, PCIS_DISPLAY_XGA, "XGA"}, 637144156Sjmg {PCIC_DISPLAY, PCIS_DISPLAY_3D, "3D"}, 63869700Smsmith {PCIC_MULTIMEDIA, -1, "multimedia"}, 63969700Smsmith {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_VIDEO, "video"}, 64069700Smsmith {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_AUDIO, "audio"}, 641144156Sjmg {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_TELE, "telephony"}, 642184142Smav {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_HDA, "HDA"}, 64369700Smsmith {PCIC_MEMORY, -1, "memory"}, 64469700Smsmith {PCIC_MEMORY, PCIS_MEMORY_RAM, "RAM"}, 64569700Smsmith {PCIC_MEMORY, PCIS_MEMORY_FLASH, "flash"}, 64669700Smsmith {PCIC_BRIDGE, -1, "bridge"}, 64769700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_HOST, "HOST-PCI"}, 64869700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_ISA, "PCI-ISA"}, 64969700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_EISA, "PCI-EISA"}, 65069700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_MCA, "PCI-MCA"}, 65169700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_PCI, "PCI-PCI"}, 65269700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_PCMCIA, "PCI-PCMCIA"}, 65369700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_NUBUS, "PCI-NuBus"}, 65469700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_CARDBUS, "PCI-CardBus"}, 655144156Sjmg {PCIC_BRIDGE, PCIS_BRIDGE_RACEWAY, "PCI-RACEway"}, 65669700Smsmith {PCIC_SIMPLECOMM, -1, "simple comms"}, 65769700Smsmith {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_UART, "UART"}, /* could detect 16550 */ 65869700Smsmith {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_PAR, "parallel port"}, 659144156Sjmg {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MULSER, "multiport serial"}, 660144156Sjmg {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MODEM, "generic modem"}, 66169700Smsmith {PCIC_BASEPERIPH, -1, "base peripheral"}, 66269700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PIC, "interrupt controller"}, 66369700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_DMA, "DMA controller"}, 66469700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_TIMER, "timer"}, 66569700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_RTC, "realtime clock"}, 666144156Sjmg {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PCIHOT, "PCI hot-plug controller"}, 667184140Smav {PCIC_BASEPERIPH, PCIS_BASEPERIPH_SDHC, "SD host controller"}, 668266468Smav {PCIC_BASEPERIPH, PCIS_BASEPERIPH_IOMMU, "IOMMU"}, 66969700Smsmith {PCIC_INPUTDEV, -1, "input device"}, 67069700Smsmith {PCIC_INPUTDEV, PCIS_INPUTDEV_KEYBOARD, "keyboard"}, 67169700Smsmith {PCIC_INPUTDEV, PCIS_INPUTDEV_DIGITIZER,"digitizer"}, 67269700Smsmith {PCIC_INPUTDEV, PCIS_INPUTDEV_MOUSE, "mouse"}, 673144156Sjmg {PCIC_INPUTDEV, PCIS_INPUTDEV_SCANNER, "scanner"}, 674144156Sjmg {PCIC_INPUTDEV, PCIS_INPUTDEV_GAMEPORT, "gameport"}, 67569700Smsmith {PCIC_DOCKING, -1, "docking station"}, 67669700Smsmith {PCIC_PROCESSOR, -1, "processor"}, 67769700Smsmith {PCIC_SERIALBUS, -1, "serial bus"}, 67869700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_FW, "FireWire"}, 679149223Sdes {PCIC_SERIALBUS, PCIS_SERIALBUS_ACCESS, "AccessBus"}, 68069700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_SSA, "SSA"}, 68169700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_USB, "USB"}, 68269700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_FC, "Fibre Channel"}, 68369700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_SMBUS, "SMBus"}, 684144156Sjmg {PCIC_WIRELESS, -1, "wireless controller"}, 685144156Sjmg {PCIC_WIRELESS, PCIS_WIRELESS_IRDA, "iRDA"}, 686144156Sjmg {PCIC_WIRELESS, PCIS_WIRELESS_IR, "IR"}, 687144156Sjmg {PCIC_WIRELESS, PCIS_WIRELESS_RF, "RF"}, 688144156Sjmg {PCIC_INTELLIIO, -1, "intelligent I/O controller"}, 689144156Sjmg {PCIC_INTELLIIO, PCIS_INTELLIIO_I2O, "I2O"}, 690144156Sjmg {PCIC_SATCOM, -1, "satellite communication"}, 691144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_TV, "sat TV"}, 692144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_AUDIO, "sat audio"}, 693144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_VOICE, "sat voice"}, 694144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_DATA, "sat data"}, 695144156Sjmg {PCIC_CRYPTO, -1, "encrypt/decrypt"}, 696144156Sjmg {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "network/computer crypto"}, 697144156Sjmg {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "entertainment crypto"}, 698144156Sjmg {PCIC_DASP, -1, "dasp"}, 699144156Sjmg {PCIC_DASP, PCIS_DASP_DPIO, "DPIO module"}, 70069700Smsmith {0, 0, NULL} 70169700Smsmith}; 70269700Smsmith 703166435Sjhbstatic const char * 70469700Smsmithguess_class(struct pci_conf *p) 70569700Smsmith{ 70669700Smsmith int i; 70769700Smsmith 70869700Smsmith for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { 70969700Smsmith if (pci_nomatch_tab[i].class == p->pc_class) 71069700Smsmith return(pci_nomatch_tab[i].desc); 71169700Smsmith } 71269700Smsmith return(NULL); 71369700Smsmith} 71469700Smsmith 715166435Sjhbstatic const char * 71669700Smsmithguess_subclass(struct pci_conf *p) 71769700Smsmith{ 71869700Smsmith int i; 71969700Smsmith 72069700Smsmith for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { 72169700Smsmith if ((pci_nomatch_tab[i].class == p->pc_class) && 72269700Smsmith (pci_nomatch_tab[i].subclass == p->pc_subclass)) 72369700Smsmith return(pci_nomatch_tab[i].desc); 72469700Smsmith } 72569700Smsmith return(NULL); 72669700Smsmith} 72769700Smsmith 72869700Smsmithstatic int 72969700Smsmithload_vendors(void) 73069700Smsmith{ 731166435Sjhb const char *dbf; 73269700Smsmith FILE *db; 73369700Smsmith struct pci_vendor_info *cv; 73469700Smsmith struct pci_device_info *cd; 735149225Sdes char buf[1024], str[1024]; 736149225Sdes char *ch; 73769700Smsmith int id, error; 73869700Smsmith 73969700Smsmith /* 74069700Smsmith * Locate the database and initialise. 74169700Smsmith */ 74269700Smsmith TAILQ_INIT(&pci_vendors); 74369700Smsmith if ((dbf = getenv("PCICONF_VENDOR_DATABASE")) == NULL) 744287522Sbapt dbf = _PATH_LPCIVDB; 745287522Sbapt if ((db = fopen(dbf, "r")) == NULL) { 74669700Smsmith dbf = _PATH_PCIVDB; 747287522Sbapt if ((db = fopen(dbf, "r")) == NULL) 748287522Sbapt return(1); 749287522Sbapt } 75069700Smsmith cv = NULL; 75169700Smsmith cd = NULL; 75269700Smsmith error = 0; 75369700Smsmith 75469700Smsmith /* 75569700Smsmith * Scan input lines from the database 75669700Smsmith */ 75769700Smsmith for (;;) { 75869700Smsmith if (fgets(buf, sizeof(buf), db) == NULL) 75968677Smsmith break; 76069700Smsmith 761149225Sdes if ((ch = strchr(buf, '#')) != NULL) 762149225Sdes *ch = '\0'; 763149225Sdes ch = strchr(buf, '\0') - 1; 764149225Sdes while (ch > buf && isspace(*ch)) 765149225Sdes *ch-- = '\0'; 766149225Sdes if (ch <= buf) 767149225Sdes continue; 768149225Sdes 769149225Sdes /* Can't handle subvendor / subdevice entries yet */ 770149225Sdes if (buf[0] == '\t' && buf[1] == '\t') 771149225Sdes continue; 772149225Sdes 77369700Smsmith /* Check for vendor entry */ 774149225Sdes if (buf[0] != '\t' && sscanf(buf, "%04x %[^\n]", &id, str) == 2) { 77569700Smsmith if ((id == 0) || (strlen(str) < 1)) 77669700Smsmith continue; 77769700Smsmith if ((cv = malloc(sizeof(struct pci_vendor_info))) == NULL) { 77869700Smsmith warn("allocating vendor entry"); 77969700Smsmith error = 1; 78069700Smsmith break; 78169700Smsmith } 78269700Smsmith if ((cv->desc = strdup(str)) == NULL) { 78369700Smsmith free(cv); 78469700Smsmith warn("allocating vendor description"); 78569700Smsmith error = 1; 78669700Smsmith break; 78769700Smsmith } 78869700Smsmith cv->id = id; 78969700Smsmith TAILQ_INIT(&cv->devs); 79069700Smsmith TAILQ_INSERT_TAIL(&pci_vendors, cv, link); 79169700Smsmith continue; 79269700Smsmith } 793149223Sdes 79469700Smsmith /* Check for device entry */ 795149225Sdes if (buf[0] == '\t' && sscanf(buf + 1, "%04x %[^\n]", &id, str) == 2) { 79669700Smsmith if ((id == 0) || (strlen(str) < 1)) 79769700Smsmith continue; 79869700Smsmith if (cv == NULL) { 79969700Smsmith warnx("device entry with no vendor!"); 80069700Smsmith continue; 80169700Smsmith } 80269700Smsmith if ((cd = malloc(sizeof(struct pci_device_info))) == NULL) { 80369700Smsmith warn("allocating device entry"); 80469700Smsmith error = 1; 80569700Smsmith break; 80669700Smsmith } 80769700Smsmith if ((cd->desc = strdup(str)) == NULL) { 80869700Smsmith free(cd); 80969700Smsmith warn("allocating device description"); 81069700Smsmith error = 1; 81169700Smsmith break; 81269700Smsmith } 81369700Smsmith cd->id = id; 81469700Smsmith TAILQ_INSERT_TAIL(&cv->devs, cd, link); 81569700Smsmith continue; 81669700Smsmith } 81769700Smsmith 81869700Smsmith /* It's a comment or junk, ignore it */ 81968677Smsmith } 82069700Smsmith if (ferror(db)) 82169700Smsmith error = 1; 82269700Smsmith fclose(db); 823149223Sdes 82469700Smsmith return(error); 82568677Smsmith} 82668677Smsmith 827166435Sjhbuint32_t 828166435Sjhbread_config(int fd, struct pcisel *sel, long reg, int width) 829166435Sjhb{ 830166435Sjhb struct pci_io pi; 83169700Smsmith 832166435Sjhb pi.pi_sel = *sel; 833166435Sjhb pi.pi_reg = reg; 834166435Sjhb pi.pi_width = width; 835166435Sjhb 836166435Sjhb if (ioctl(fd, PCIOCREAD, &pi) < 0) 837166435Sjhb err(1, "ioctl(PCIOCREAD)"); 838166435Sjhb 839166435Sjhb return (pi.pi_data); 840166435Sjhb} 841166435Sjhb 84219102Ssestatic struct pcisel 843260910Sjhbgetdevice(const char *name) 84419102Sse{ 845260910Sjhb struct pci_conf_io pc; 846260910Sjhb struct pci_conf conf[1]; 847260910Sjhb struct pci_match_conf patterns[1]; 848260910Sjhb char *cp; 849260910Sjhb int fd; 850260910Sjhb 851260910Sjhb fd = open(_PATH_DEVPCI, O_RDONLY, 0); 852260910Sjhb if (fd < 0) 853260910Sjhb err(1, "%s", _PATH_DEVPCI); 854260910Sjhb 855260910Sjhb bzero(&pc, sizeof(struct pci_conf_io)); 856260910Sjhb pc.match_buf_len = sizeof(conf); 857260910Sjhb pc.matches = conf; 858260910Sjhb 859260910Sjhb bzero(&patterns, sizeof(patterns)); 860260910Sjhb 861260910Sjhb /* 862260910Sjhb * The pattern structure requires the unit to be split out from 863260910Sjhb * the driver name. Walk backwards from the end of the name to 864260910Sjhb * find the start of the unit. 865260910Sjhb */ 866260910Sjhb if (name[0] == '\0') 867273488Smarkj errx(1, "Empty device name"); 868260910Sjhb cp = strchr(name, '\0'); 869260910Sjhb assert(cp != NULL && cp != name); 870260910Sjhb cp--; 871260910Sjhb while (cp != name && isdigit(cp[-1])) 872260910Sjhb cp--; 873273488Smarkj if (cp == name || !isdigit(*cp)) 874260910Sjhb errx(1, "Invalid device name"); 875260910Sjhb if ((size_t)(cp - name) + 1 > sizeof(patterns[0].pd_name)) 876273488Smarkj errx(1, "Device name is too long"); 877260910Sjhb memcpy(patterns[0].pd_name, name, cp - name); 878260910Sjhb patterns[0].pd_unit = strtol(cp, &cp, 10); 879260910Sjhb assert(*cp == '\0'); 880260910Sjhb patterns[0].flags = PCI_GETCONF_MATCH_NAME | PCI_GETCONF_MATCH_UNIT; 881260910Sjhb pc.num_patterns = 1; 882260910Sjhb pc.pat_buf_len = sizeof(patterns); 883260910Sjhb pc.patterns = patterns; 884260910Sjhb 885260910Sjhb if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 886260910Sjhb err(1, "ioctl(PCIOCGETCONF)"); 887260910Sjhb if (pc.status != PCI_GETCONF_LAST_DEVICE && 888260910Sjhb pc.status != PCI_GETCONF_MORE_DEVS) 889260910Sjhb errx(1, "error returned from PCIOCGETCONF ioctl"); 890260910Sjhb close(fd); 891260910Sjhb if (pc.num_matches == 0) 892260910Sjhb errx(1, "Device not found"); 893260910Sjhb return (conf[0].pc_sel); 894260910Sjhb} 895260910Sjhb 896260910Sjhbstatic struct pcisel 897260910Sjhbparsesel(const char *str) 898260910Sjhb{ 899295760Sse const char *ep; 900295760Sse char *eppos; 90119102Sse struct pcisel sel; 902172447Sse unsigned long selarr[4]; 903172447Sse int i; 904116640Sjmg 905295760Sse ep = strchr(str, '@'); 906295760Sse if (ep != NULL) 907295760Sse ep++; 908116640Sjmg else 909295760Sse ep = str; 910116640Sjmg 91119102Sse if (strncmp(ep, "pci", 3) == 0) { 91219102Sse ep += 3; 913172447Sse i = 0; 914295806Sse while (isdigit(*ep) && i < 4) { 915295769Sse selarr[i++] = strtoul(ep, &eppos, 10); 916295769Sse ep = eppos; 917295806Sse if (*ep == ':') { 918295806Sse ep++; 919295806Sse if (*ep == '\0') 920295806Sse i = 0; 921295806Sse } 922295806Sse } 923295806Sse if (i > 0 && *ep == '\0') { 924295806Sse sel.pc_func = (i > 2) ? selarr[--i] : 0; 925295806Sse sel.pc_dev = (i > 0) ? selarr[--i] : 0; 926295806Sse sel.pc_bus = (i > 0) ? selarr[--i] : 0; 927295806Sse sel.pc_domain = (i > 0) ? selarr[--i] : 0; 928295806Sse return (sel); 929295806Sse } 93019102Sse } 931295806Sse errx(1, "cannot parse selector %s", str); 93219102Sse} 93319102Sse 934260910Sjhbstatic struct pcisel 935260910Sjhbgetsel(const char *str) 936260910Sjhb{ 937260910Sjhb 938260910Sjhb /* 939260910Sjhb * No device names contain colons and selectors always contain 940260910Sjhb * at least one colon. 941260910Sjhb */ 942260910Sjhb if (strchr(str, ':') == NULL) 943260910Sjhb return (getdevice(str)); 944260910Sjhb else 945260910Sjhb return (parsesel(str)); 946260910Sjhb} 947260910Sjhb 94819102Ssestatic void 94977533Simpreadone(int fd, struct pcisel *sel, long reg, int width) 95019102Sse{ 95119102Sse 952166435Sjhb printf("%0*x", width*2, read_config(fd, sel, reg, width)); 95377533Simp} 95477533Simp 95577533Simpstatic void 95677533Simpreadit(const char *name, const char *reg, int width) 95777533Simp{ 95877533Simp long rstart; 95977533Simp long rend; 96077533Simp long r; 96177533Simp char *end; 96277533Simp int i; 96377533Simp int fd; 96477533Simp struct pcisel sel; 96577533Simp 96619102Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 96719102Sse if (fd < 0) 96819102Sse err(1, "%s", _PATH_DEVPCI); 96919102Sse 97077533Simp rend = rstart = strtol(reg, &end, 0); 97177533Simp if (end && *end == ':') { 97277533Simp end++; 97377533Simp rend = strtol(end, (char **) 0, 0); 97477533Simp } 97577533Simp sel = getsel(name); 976149223Sdes for (i = 1, r = rstart; r <= rend; i++, r += width) { 97777533Simp readone(fd, &sel, r, width); 978182708Simp if (i && !(i % 8)) 979182708Simp putchar(' '); 98091299Ssos putchar(i % (16/width) ? ' ' : '\n'); 98177533Simp } 98291299Ssos if (i % (16/width) != 1) 98377533Simp putchar('\n'); 98477533Simp close(fd); 98519102Sse} 98619102Sse 98719102Ssestatic void 98819102Ssewriteit(const char *name, const char *reg, const char *data, int width) 98919102Sse{ 99019102Sse int fd; 99119102Sse struct pci_io pi; 99219102Sse 99319102Sse pi.pi_sel = getsel(name); 99419102Sse pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 99519102Sse pi.pi_width = width; 99619102Sse pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */ 99719102Sse 99819102Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 99919102Sse if (fd < 0) 100019102Sse err(1, "%s", _PATH_DEVPCI); 100119102Sse 100219102Sse if (ioctl(fd, PCIOCWRITE, &pi) < 0) 100319102Sse err(1, "ioctl(PCIOCWRITE)"); 100419102Sse} 100521935Sse 100621935Ssestatic void 1007212329Sjhbchkattached(const char *name) 100821935Sse{ 100921935Sse int fd; 101021935Sse struct pci_io pi; 101121935Sse 101221935Sse pi.pi_sel = getsel(name); 101321935Sse 101421935Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 101521935Sse if (fd < 0) 101621935Sse err(1, "%s", _PATH_DEVPCI); 101721935Sse 101821935Sse if (ioctl(fd, PCIOCATTACHED, &pi) < 0) 101921935Sse err(1, "ioctl(PCIOCATTACHED)"); 102021935Sse 102121935Sse exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ 102221935Sse printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached"); 102321935Sse} 1024