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: stable/10/usr.sbin/pciconf/pciconf.c 308063 2016-10-28 19:46:08Z mav $"; 3330172Scharnier#endif /* not lint */ 3430172Scharnier 3519102Sse#include <sys/types.h> 3619102Sse#include <sys/fcntl.h> 3719102Sse 38261250Sjhb#include <assert.h> 39166435Sjhb#include <ctype.h> 4019102Sse#include <err.h> 41188018Sjhb#include <inttypes.h> 42294289Sjhb#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 7069700SmsmithTAILQ_HEAD(,pci_vendor_info) pci_vendors; 7169700Smsmith 72261250Sjhbstatic struct pcisel getsel(const char *str); 73294289Sjhbstatic void list_bridge(int fd, struct pci_conf *p); 74188018Sjhbstatic void list_bars(int fd, struct pci_conf *p); 75294289Sjhbstatic void list_devs(const char *name, int verbose, int bars, int bridge, 76294289Sjhb int caps, int errors, int vpd); 7769700Smsmithstatic void list_verbose(struct pci_conf *p); 78262134Sjhbstatic 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", 92294289Sjhb "usage: pciconf -l [-BbcevV] [device]", 93261250Sjhb " pciconf -a device", 94261250Sjhb " pciconf -r [-b | -h] device addr[:addr2]", 95261250Sjhb " 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; 104294289Sjhb int bars, bridge, caps, errors, verbose, vpd; 10519102Sse int byte, isshort; 10619102Sse 107236415Sjhb listmode = readmode = writemode = attachedmode = 0; 108294289Sjhb bars = bridge = caps = errors = verbose = vpd = byte = isshort = 0; 10919102Sse 110294289Sjhb while ((c = getopt(argc, argv, "aBbcehlrwVv")) != -1) { 11119102Sse switch(c) { 11221935Sse case 'a': 11321935Sse attachedmode = 1; 11421935Sse break; 11521935Sse 116294289Sjhb case 'B': 117294289Sjhb bridge = 1; 118294289Sjhb break; 119294289Sjhb 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 153262134Sjhb case 'V': 154262134Sjhb vpd = 1; 155262134Sjhb break; 156262134Sjhb 15719102Sse default: 15830172Scharnier usage(); 15919102Sse } 16019102Sse } 16119102Sse 162261250Sjhb 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) { 169261250Sjhb list_devs(optind + 1 == argc ? argv[optind] : NULL, verbose, 170294289Sjhb 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 187294289Sjhblist_devs(const char *name, int verbose, int bars, int bridge, int caps, 188294289Sjhb int errors, int vpd) 18919102Sse{ 19019102Sse int fd; 19119102Sse struct pci_conf_io pc; 19219102Sse struct pci_conf conf[255], *p; 193261250Sjhb struct pci_match_conf patterns[1]; 19441103Sken int none_count = 0; 19519102Sse 19669700Smsmith if (verbose) 19769700Smsmith load_vendors(); 19869700Smsmith 199294289Sjhb fd = open(_PATH_DEVPCI, (bridge || caps || errors) ? O_RDWR : O_RDONLY, 200294289Sjhb 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; 207261250Sjhb if (name != NULL) { 208261250Sjhb bzero(&patterns, sizeof(patterns)); 209261250Sjhb patterns[0].pc_sel = getsel(name); 210261250Sjhb patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | 211261250Sjhb PCI_GETCONF_MATCH_BUS | PCI_GETCONF_MATCH_DEV | 212261250Sjhb PCI_GETCONF_MATCH_FUNC; 213261250Sjhb pc.num_patterns = 1; 214261250Sjhb pc.pat_buf_len = sizeof(patterns); 215261250Sjhb pc.patterns = patterns; 216261250Sjhb } 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", 244182708Simp (p->pd_name && *p->pd_name) ? p->pd_name : 245182708Simp "none", 246182708Simp (p->pd_name && *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); 258294289Sjhb if (bridge) 259294289Sjhb list_bridge(fd, p); 260166435Sjhb if (caps) 261166435Sjhb list_caps(fd, p); 262236415Sjhb if (errors) 263236415Sjhb list_errors(fd, p); 264262134Sjhb if (vpd) 265262134Sjhb list_vpd(fd, p); 26639231Sgibbs } 26739231Sgibbs } while (pc.status == PCI_GETCONF_MORE_DEVS); 26839231Sgibbs 26919102Sse close(fd); 27019102Sse} 27119102Sse 27268677Smsmithstatic void 273294289Sjhbprint_bus_range(int fd, struct pci_conf *p, int secreg, int subreg) 274294289Sjhb{ 275294289Sjhb uint8_t secbus, subbus; 276294289Sjhb 277294289Sjhb secbus = read_config(fd, &p->pc_sel, secreg, 1); 278294289Sjhb subbus = read_config(fd, &p->pc_sel, subreg, 1); 279294289Sjhb printf(" bus range = %u-%u\n", secbus, subbus); 280294289Sjhb} 281294289Sjhb 282294289Sjhbstatic void 283294289Sjhbprint_window(int reg, const char *type, int range, uint64_t base, 284294289Sjhb uint64_t limit) 285294289Sjhb{ 286294289Sjhb 287294289Sjhb printf(" window[%02x] = type %s, range %2d, addr %#jx-%#jx, %s\n", 288294289Sjhb reg, type, range, (uintmax_t)base, (uintmax_t)limit, 289294289Sjhb base < limit ? "enabled" : "disabled"); 290294289Sjhb} 291294289Sjhb 292294289Sjhbstatic void 293294289Sjhbprint_special_decode(bool isa, bool vga, bool subtractive) 294294289Sjhb{ 295294289Sjhb bool comma; 296294289Sjhb 297294289Sjhb if (isa || vga || subtractive) { 298294289Sjhb comma = false; 299294289Sjhb printf(" decode = "); 300294289Sjhb if (isa) { 301294289Sjhb printf("ISA"); 302294289Sjhb comma = true; 303294289Sjhb } 304294289Sjhb if (vga) { 305294289Sjhb printf("%sVGA", comma ? ", " : ""); 306294289Sjhb comma = true; 307294289Sjhb } 308294289Sjhb if (subtractive) 309294289Sjhb printf("%ssubtractive", comma ? ", " : ""); 310294289Sjhb printf("\n"); 311294289Sjhb } 312294289Sjhb} 313294289Sjhb 314294289Sjhbstatic void 315294289Sjhbprint_bridge_windows(int fd, struct pci_conf *p) 316294289Sjhb{ 317294289Sjhb uint64_t base, limit; 318294289Sjhb uint32_t val; 319294289Sjhb uint16_t bctl; 320294289Sjhb bool subtractive; 321294289Sjhb int range; 322294289Sjhb 323294289Sjhb /* 324294289Sjhb * XXX: This assumes that a window with a base and limit of 0 325294289Sjhb * is not implemented. In theory a window might be programmed 326294289Sjhb * at the smallest size with a base of 0, but those do not seem 327294289Sjhb * common in practice. 328294289Sjhb */ 329294289Sjhb val = read_config(fd, &p->pc_sel, PCIR_IOBASEL_1, 1); 330294289Sjhb if (val != 0 || read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1) != 0) { 331294289Sjhb if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 332294289Sjhb base = PCI_PPBIOBASE( 333294289Sjhb read_config(fd, &p->pc_sel, PCIR_IOBASEH_1, 2), 334294289Sjhb val); 335294289Sjhb limit = PCI_PPBIOLIMIT( 336294289Sjhb read_config(fd, &p->pc_sel, PCIR_IOLIMITH_1, 2), 337294289Sjhb read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1)); 338294289Sjhb range = 32; 339294289Sjhb } else { 340294289Sjhb base = PCI_PPBIOBASE(0, val); 341294289Sjhb limit = PCI_PPBIOLIMIT(0, 342294289Sjhb read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1)); 343294289Sjhb range = 16; 344294289Sjhb } 345294289Sjhb print_window(PCIR_IOBASEL_1, "I/O Port", range, base, limit); 346294289Sjhb } 347294289Sjhb 348294289Sjhb base = PCI_PPBMEMBASE(0, 349294289Sjhb read_config(fd, &p->pc_sel, PCIR_MEMBASE_1, 2)); 350294289Sjhb limit = PCI_PPBMEMLIMIT(0, 351294289Sjhb read_config(fd, &p->pc_sel, PCIR_MEMLIMIT_1, 2)); 352294289Sjhb print_window(PCIR_MEMBASE_1, "Memory", 32, base, limit); 353294289Sjhb 354294289Sjhb val = read_config(fd, &p->pc_sel, PCIR_PMBASEL_1, 2); 355294289Sjhb if (val != 0 || read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2) != 0) { 356294289Sjhb if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { 357294289Sjhb base = PCI_PPBMEMBASE( 358294289Sjhb read_config(fd, &p->pc_sel, PCIR_PMBASEH_1, 4), 359294289Sjhb val); 360294289Sjhb limit = PCI_PPBMEMLIMIT( 361294289Sjhb read_config(fd, &p->pc_sel, PCIR_PMLIMITH_1, 4), 362294289Sjhb read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2)); 363294289Sjhb range = 64; 364294289Sjhb } else { 365294289Sjhb base = PCI_PPBMEMBASE(0, val); 366294289Sjhb limit = PCI_PPBMEMLIMIT(0, 367294289Sjhb read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2)); 368294289Sjhb range = 32; 369294289Sjhb } 370294289Sjhb print_window(PCIR_PMBASEL_1, "Prefetchable Memory", range, base, 371294289Sjhb limit); 372294289Sjhb } 373294289Sjhb 374294289Sjhb /* 375294289Sjhb * XXX: This list of bridges that are subtractive but do not set 376294289Sjhb * progif to indicate it is copied from pci_pci.c. 377294289Sjhb */ 378294289Sjhb subtractive = p->pc_progif == PCIP_BRIDGE_PCI_SUBTRACTIVE; 379294289Sjhb switch (p->pc_device << 16 | p->pc_vendor) { 380294289Sjhb case 0xa002177d: /* Cavium ThunderX */ 381294289Sjhb case 0x124b8086: /* Intel 82380FB Mobile */ 382294289Sjhb case 0x060513d7: /* Toshiba ???? */ 383294289Sjhb subtractive = true; 384294289Sjhb } 385294289Sjhb if (p->pc_vendor == 0x8086 && (p->pc_device & 0xff00) == 0x2400) 386294289Sjhb subtractive = true; 387294289Sjhb 388294289Sjhb bctl = read_config(fd, &p->pc_sel, PCIR_BRIDGECTL_1, 2); 389294289Sjhb print_special_decode(bctl & PCIB_BCR_ISA_ENABLE, 390294289Sjhb bctl & PCIB_BCR_VGA_ENABLE, subtractive); 391294289Sjhb} 392294289Sjhb 393294289Sjhbstatic void 394294289Sjhbprint_cardbus_mem_window(int fd, struct pci_conf *p, int basereg, int limitreg, 395294289Sjhb bool prefetch) 396294289Sjhb{ 397294289Sjhb 398294289Sjhb print_window(basereg, prefetch ? "Prefetchable Memory" : "Memory", 32, 399294289Sjhb PCI_CBBMEMBASE(read_config(fd, &p->pc_sel, basereg, 4)), 400294289Sjhb PCI_CBBMEMLIMIT(read_config(fd, &p->pc_sel, limitreg, 4))); 401294289Sjhb} 402294289Sjhb 403294289Sjhbstatic void 404294289Sjhbprint_cardbus_io_window(int fd, struct pci_conf *p, int basereg, int limitreg) 405294289Sjhb{ 406294289Sjhb uint32_t base, limit; 407294289Sjhb uint32_t val; 408294289Sjhb int range; 409294289Sjhb 410294289Sjhb val = read_config(fd, &p->pc_sel, basereg, 2); 411294289Sjhb if ((val & PCIM_CBBIO_MASK) == PCIM_CBBIO_32) { 412294289Sjhb base = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, basereg, 4)); 413294289Sjhb limit = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, limitreg, 4)); 414294289Sjhb range = 32; 415294289Sjhb } else { 416294289Sjhb base = PCI_CBBIOBASE(val); 417294289Sjhb limit = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, limitreg, 2)); 418294289Sjhb range = 16; 419294289Sjhb } 420294289Sjhb print_window(basereg, "I/O Port", range, base, limit); 421294289Sjhb} 422294289Sjhb 423294289Sjhbstatic void 424294289Sjhbprint_cardbus_windows(int fd, struct pci_conf *p) 425294289Sjhb{ 426294289Sjhb uint16_t bctl; 427294289Sjhb 428294289Sjhb bctl = read_config(fd, &p->pc_sel, PCIR_BRIDGECTL_2, 2); 429294289Sjhb print_cardbus_mem_window(fd, p, PCIR_MEMBASE0_2, PCIR_MEMLIMIT0_2, 430294289Sjhb bctl & CBB_BCR_PREFETCH_0_ENABLE); 431294289Sjhb print_cardbus_mem_window(fd, p, PCIR_MEMBASE1_2, PCIR_MEMLIMIT1_2, 432294289Sjhb bctl & CBB_BCR_PREFETCH_1_ENABLE); 433294289Sjhb print_cardbus_io_window(fd, p, PCIR_IOBASE0_2, PCIR_IOLIMIT0_2); 434294289Sjhb print_cardbus_io_window(fd, p, PCIR_IOBASE1_2, PCIR_IOLIMIT1_2); 435294289Sjhb print_special_decode(bctl & CBB_BCR_ISA_ENABLE, 436294289Sjhb bctl & CBB_BCR_VGA_ENABLE, false); 437294289Sjhb} 438294289Sjhb 439294289Sjhbstatic void 440294289Sjhblist_bridge(int fd, struct pci_conf *p) 441294289Sjhb{ 442294289Sjhb 443294289Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 444294289Sjhb case PCIM_HDRTYPE_BRIDGE: 445294289Sjhb print_bus_range(fd, p, PCIR_SECBUS_1, PCIR_SUBBUS_1); 446294289Sjhb print_bridge_windows(fd, p); 447294289Sjhb break; 448294289Sjhb case PCIM_HDRTYPE_CARDBUS: 449294289Sjhb print_bus_range(fd, p, PCIR_SECBUS_2, PCIR_SUBBUS_2); 450294289Sjhb print_cardbus_windows(fd, p); 451294289Sjhb break; 452294289Sjhb } 453294289Sjhb} 454294289Sjhb 455294289Sjhbstatic void 456188018Sjhblist_bars(int fd, struct pci_conf *p) 457188018Sjhb{ 458188018Sjhb struct pci_bar_io bar; 459188018Sjhb uint64_t base; 460188018Sjhb const char *type; 461188018Sjhb int i, range, max; 462188018Sjhb 463188018Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 464188018Sjhb case PCIM_HDRTYPE_NORMAL: 465188018Sjhb max = PCIR_MAX_BAR_0; 466188018Sjhb break; 467188018Sjhb case PCIM_HDRTYPE_BRIDGE: 468188018Sjhb max = PCIR_MAX_BAR_1; 469188018Sjhb break; 470188018Sjhb case PCIM_HDRTYPE_CARDBUS: 471188018Sjhb max = PCIR_MAX_BAR_2; 472188018Sjhb break; 473188018Sjhb default: 474188018Sjhb return; 475188018Sjhb } 476188018Sjhb 477188018Sjhb for (i = 0; i <= max; i++) { 478188018Sjhb bar.pbi_sel = p->pc_sel; 479188018Sjhb bar.pbi_reg = PCIR_BAR(i); 480188018Sjhb if (ioctl(fd, PCIOCGETBAR, &bar) < 0) 481188018Sjhb continue; 482188018Sjhb if (PCI_BAR_IO(bar.pbi_base)) { 483188018Sjhb type = "I/O Port"; 484188018Sjhb range = 32; 485188018Sjhb base = bar.pbi_base & PCIM_BAR_IO_BASE; 486188018Sjhb } else { 487188018Sjhb if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH) 488188018Sjhb type = "Prefetchable Memory"; 489188018Sjhb else 490188018Sjhb type = "Memory"; 491188018Sjhb switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) { 492188018Sjhb case PCIM_BAR_MEM_32: 493188018Sjhb range = 32; 494188018Sjhb break; 495188018Sjhb case PCIM_BAR_MEM_1MB: 496188018Sjhb range = 20; 497188018Sjhb break; 498188018Sjhb case PCIM_BAR_MEM_64: 499188018Sjhb range = 64; 500188018Sjhb break; 501188018Sjhb default: 502188018Sjhb range = -1; 503188018Sjhb } 504188018Sjhb base = bar.pbi_base & ~((uint64_t)0xf); 505188018Sjhb } 506188018Sjhb printf(" bar [%02x] = type %s, range %2d, base %#jx, ", 507188018Sjhb PCIR_BAR(i), type, range, (uintmax_t)base); 508246632Sneel printf("size %ju, %s\n", (uintmax_t)bar.pbi_length, 509188018Sjhb bar.pbi_enabled ? "enabled" : "disabled"); 510188018Sjhb } 511188018Sjhb} 512188018Sjhb 513188018Sjhbstatic void 51469700Smsmithlist_verbose(struct pci_conf *p) 51568677Smsmith{ 51669700Smsmith struct pci_vendor_info *vi; 51769700Smsmith struct pci_device_info *di; 518166435Sjhb const char *dp; 519149223Sdes 52069700Smsmith TAILQ_FOREACH(vi, &pci_vendors, link) { 52169700Smsmith if (vi->id == p->pc_vendor) { 522166435Sjhb printf(" vendor = '%s'\n", vi->desc); 52368677Smsmith break; 52469700Smsmith } 52569700Smsmith } 52669700Smsmith if (vi == NULL) { 52769700Smsmith di = NULL; 52868677Smsmith } else { 52969700Smsmith TAILQ_FOREACH(di, &vi->devs, link) { 53069700Smsmith if (di->id == p->pc_device) { 531166435Sjhb printf(" device = '%s'\n", di->desc); 53269700Smsmith break; 53369700Smsmith } 53469700Smsmith } 53568677Smsmith } 53669700Smsmith if ((dp = guess_class(p)) != NULL) 537166435Sjhb printf(" class = %s\n", dp); 53869700Smsmith if ((dp = guess_subclass(p)) != NULL) 539166435Sjhb printf(" subclass = %s\n", dp); 54069700Smsmith} 54169700Smsmith 542262134Sjhbstatic void 543262134Sjhblist_vpd(int fd, struct pci_conf *p) 544262134Sjhb{ 545262134Sjhb struct pci_list_vpd_io list; 546262134Sjhb struct pci_vpd_element *vpd, *end; 547262134Sjhb 548262134Sjhb list.plvi_sel = p->pc_sel; 549262134Sjhb list.plvi_len = 0; 550262134Sjhb list.plvi_data = NULL; 551262134Sjhb if (ioctl(fd, PCIOCLISTVPD, &list) < 0 || list.plvi_len == 0) 552262134Sjhb return; 553262134Sjhb 554262134Sjhb list.plvi_data = malloc(list.plvi_len); 555262134Sjhb if (ioctl(fd, PCIOCLISTVPD, &list) < 0) { 556262134Sjhb free(list.plvi_data); 557262134Sjhb return; 558262134Sjhb } 559262134Sjhb 560262134Sjhb vpd = list.plvi_data; 561262134Sjhb end = (struct pci_vpd_element *)((char *)vpd + list.plvi_len); 562262134Sjhb for (; vpd < end; vpd = PVE_NEXT(vpd)) { 563262134Sjhb if (vpd->pve_flags == PVE_FLAG_IDENT) { 564262134Sjhb printf(" VPD ident = '%.*s'\n", 565262134Sjhb (int)vpd->pve_datalen, vpd->pve_data); 566262134Sjhb continue; 567262134Sjhb } 568262134Sjhb 569262134Sjhb /* Ignore the checksum keyword. */ 570262134Sjhb if (!(vpd->pve_flags & PVE_FLAG_RW) && 571262134Sjhb memcmp(vpd->pve_keyword, "RV", 2) == 0) 572262134Sjhb continue; 573262134Sjhb 574262134Sjhb /* Ignore remaining read-write space. */ 575262134Sjhb if (vpd->pve_flags & PVE_FLAG_RW && 576262134Sjhb memcmp(vpd->pve_keyword, "RW", 2) == 0) 577262134Sjhb continue; 578262134Sjhb 579262134Sjhb /* Handle extended capability keyword. */ 580262134Sjhb if (!(vpd->pve_flags & PVE_FLAG_RW) && 581262134Sjhb memcmp(vpd->pve_keyword, "CP", 2) == 0) { 582262134Sjhb printf(" VPD ro CP = ID %02x in map 0x%x[0x%x]\n", 583262134Sjhb (unsigned int)vpd->pve_data[0], 584262134Sjhb PCIR_BAR((unsigned int)vpd->pve_data[1]), 585262134Sjhb (unsigned int)vpd->pve_data[3] << 8 | 586262134Sjhb (unsigned int)vpd->pve_data[2]); 587262134Sjhb continue; 588262134Sjhb } 589262134Sjhb 590262134Sjhb /* Remaining keywords should all have ASCII values. */ 591262134Sjhb printf(" VPD %s %c%c = '%.*s'\n", 592262134Sjhb vpd->pve_flags & PVE_FLAG_RW ? "rw" : "ro", 593262134Sjhb vpd->pve_keyword[0], vpd->pve_keyword[1], 594262134Sjhb (int)vpd->pve_datalen, vpd->pve_data); 595262134Sjhb } 596262134Sjhb free(list.plvi_data); 597262134Sjhb} 598262134Sjhb 59969700Smsmith/* 60069700Smsmith * This is a direct cut-and-paste from the table in sys/dev/pci/pci.c. 60169700Smsmith */ 60269700Smsmithstatic struct 60369700Smsmith{ 60469700Smsmith int class; 60569700Smsmith int subclass; 606166435Sjhb const char *desc; 60769700Smsmith} pci_nomatch_tab[] = { 60869700Smsmith {PCIC_OLD, -1, "old"}, 60969700Smsmith {PCIC_OLD, PCIS_OLD_NONVGA, "non-VGA display device"}, 61069700Smsmith {PCIC_OLD, PCIS_OLD_VGA, "VGA-compatible display device"}, 61169700Smsmith {PCIC_STORAGE, -1, "mass storage"}, 61269700Smsmith {PCIC_STORAGE, PCIS_STORAGE_SCSI, "SCSI"}, 61369700Smsmith {PCIC_STORAGE, PCIS_STORAGE_IDE, "ATA"}, 61469700Smsmith {PCIC_STORAGE, PCIS_STORAGE_FLOPPY, "floppy disk"}, 61569700Smsmith {PCIC_STORAGE, PCIS_STORAGE_IPI, "IPI"}, 61669700Smsmith {PCIC_STORAGE, PCIS_STORAGE_RAID, "RAID"}, 617184936Smav {PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, "ATA (ADMA)"}, 618184936Smav {PCIC_STORAGE, PCIS_STORAGE_SATA, "SATA"}, 619184936Smav {PCIC_STORAGE, PCIS_STORAGE_SAS, "SAS"}, 620240739Sgavin {PCIC_STORAGE, PCIS_STORAGE_NVM, "NVM"}, 62169700Smsmith {PCIC_NETWORK, -1, "network"}, 62269700Smsmith {PCIC_NETWORK, PCIS_NETWORK_ETHERNET, "ethernet"}, 62369700Smsmith {PCIC_NETWORK, PCIS_NETWORK_TOKENRING, "token ring"}, 62469700Smsmith {PCIC_NETWORK, PCIS_NETWORK_FDDI, "fddi"}, 62569700Smsmith {PCIC_NETWORK, PCIS_NETWORK_ATM, "ATM"}, 626144156Sjmg {PCIC_NETWORK, PCIS_NETWORK_ISDN, "ISDN"}, 62769700Smsmith {PCIC_DISPLAY, -1, "display"}, 62869700Smsmith {PCIC_DISPLAY, PCIS_DISPLAY_VGA, "VGA"}, 62969700Smsmith {PCIC_DISPLAY, PCIS_DISPLAY_XGA, "XGA"}, 630144156Sjmg {PCIC_DISPLAY, PCIS_DISPLAY_3D, "3D"}, 63169700Smsmith {PCIC_MULTIMEDIA, -1, "multimedia"}, 63269700Smsmith {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_VIDEO, "video"}, 63369700Smsmith {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_AUDIO, "audio"}, 634144156Sjmg {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_TELE, "telephony"}, 635184142Smav {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_HDA, "HDA"}, 63669700Smsmith {PCIC_MEMORY, -1, "memory"}, 63769700Smsmith {PCIC_MEMORY, PCIS_MEMORY_RAM, "RAM"}, 63869700Smsmith {PCIC_MEMORY, PCIS_MEMORY_FLASH, "flash"}, 63969700Smsmith {PCIC_BRIDGE, -1, "bridge"}, 64069700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_HOST, "HOST-PCI"}, 64169700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_ISA, "PCI-ISA"}, 64269700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_EISA, "PCI-EISA"}, 64369700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_MCA, "PCI-MCA"}, 64469700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_PCI, "PCI-PCI"}, 64569700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_PCMCIA, "PCI-PCMCIA"}, 64669700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_NUBUS, "PCI-NuBus"}, 64769700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_CARDBUS, "PCI-CardBus"}, 648144156Sjmg {PCIC_BRIDGE, PCIS_BRIDGE_RACEWAY, "PCI-RACEway"}, 64969700Smsmith {PCIC_SIMPLECOMM, -1, "simple comms"}, 65069700Smsmith {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_UART, "UART"}, /* could detect 16550 */ 65169700Smsmith {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_PAR, "parallel port"}, 652144156Sjmg {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MULSER, "multiport serial"}, 653144156Sjmg {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MODEM, "generic modem"}, 65469700Smsmith {PCIC_BASEPERIPH, -1, "base peripheral"}, 65569700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PIC, "interrupt controller"}, 65669700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_DMA, "DMA controller"}, 65769700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_TIMER, "timer"}, 65869700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_RTC, "realtime clock"}, 659144156Sjmg {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PCIHOT, "PCI hot-plug controller"}, 660184140Smav {PCIC_BASEPERIPH, PCIS_BASEPERIPH_SDHC, "SD host controller"}, 661267002Smav {PCIC_BASEPERIPH, PCIS_BASEPERIPH_IOMMU, "IOMMU"}, 66269700Smsmith {PCIC_INPUTDEV, -1, "input device"}, 66369700Smsmith {PCIC_INPUTDEV, PCIS_INPUTDEV_KEYBOARD, "keyboard"}, 66469700Smsmith {PCIC_INPUTDEV, PCIS_INPUTDEV_DIGITIZER,"digitizer"}, 66569700Smsmith {PCIC_INPUTDEV, PCIS_INPUTDEV_MOUSE, "mouse"}, 666144156Sjmg {PCIC_INPUTDEV, PCIS_INPUTDEV_SCANNER, "scanner"}, 667144156Sjmg {PCIC_INPUTDEV, PCIS_INPUTDEV_GAMEPORT, "gameport"}, 66869700Smsmith {PCIC_DOCKING, -1, "docking station"}, 66969700Smsmith {PCIC_PROCESSOR, -1, "processor"}, 67069700Smsmith {PCIC_SERIALBUS, -1, "serial bus"}, 67169700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_FW, "FireWire"}, 672149223Sdes {PCIC_SERIALBUS, PCIS_SERIALBUS_ACCESS, "AccessBus"}, 67369700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_SSA, "SSA"}, 67469700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_USB, "USB"}, 67569700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_FC, "Fibre Channel"}, 67669700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_SMBUS, "SMBus"}, 677144156Sjmg {PCIC_WIRELESS, -1, "wireless controller"}, 678144156Sjmg {PCIC_WIRELESS, PCIS_WIRELESS_IRDA, "iRDA"}, 679144156Sjmg {PCIC_WIRELESS, PCIS_WIRELESS_IR, "IR"}, 680144156Sjmg {PCIC_WIRELESS, PCIS_WIRELESS_RF, "RF"}, 681144156Sjmg {PCIC_INTELLIIO, -1, "intelligent I/O controller"}, 682144156Sjmg {PCIC_INTELLIIO, PCIS_INTELLIIO_I2O, "I2O"}, 683144156Sjmg {PCIC_SATCOM, -1, "satellite communication"}, 684144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_TV, "sat TV"}, 685144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_AUDIO, "sat audio"}, 686144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_VOICE, "sat voice"}, 687144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_DATA, "sat data"}, 688144156Sjmg {PCIC_CRYPTO, -1, "encrypt/decrypt"}, 689144156Sjmg {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "network/computer crypto"}, 690144156Sjmg {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "entertainment crypto"}, 691144156Sjmg {PCIC_DASP, -1, "dasp"}, 692144156Sjmg {PCIC_DASP, PCIS_DASP_DPIO, "DPIO module"}, 693308063Smav {PCIC_DASP, PCIS_DASP_PERFCNTRS, "performance counters"}, 694308063Smav {PCIC_DASP, PCIS_DASP_COMM_SYNC, "communication synchronizer"}, 695308063Smav {PCIC_DASP, PCIS_DASP_MGMT_CARD, "signal processing management"}, 69669700Smsmith {0, 0, NULL} 69769700Smsmith}; 69869700Smsmith 699166435Sjhbstatic const char * 70069700Smsmithguess_class(struct pci_conf *p) 70169700Smsmith{ 70269700Smsmith int i; 70369700Smsmith 70469700Smsmith for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { 70569700Smsmith if (pci_nomatch_tab[i].class == p->pc_class) 70669700Smsmith return(pci_nomatch_tab[i].desc); 70769700Smsmith } 70869700Smsmith return(NULL); 70969700Smsmith} 71069700Smsmith 711166435Sjhbstatic const char * 71269700Smsmithguess_subclass(struct pci_conf *p) 71369700Smsmith{ 71469700Smsmith int i; 71569700Smsmith 71669700Smsmith for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { 71769700Smsmith if ((pci_nomatch_tab[i].class == p->pc_class) && 71869700Smsmith (pci_nomatch_tab[i].subclass == p->pc_subclass)) 71969700Smsmith return(pci_nomatch_tab[i].desc); 72069700Smsmith } 72169700Smsmith return(NULL); 72269700Smsmith} 72369700Smsmith 72469700Smsmithstatic int 72569700Smsmithload_vendors(void) 72669700Smsmith{ 727166435Sjhb const char *dbf; 72869700Smsmith FILE *db; 72969700Smsmith struct pci_vendor_info *cv; 73069700Smsmith struct pci_device_info *cd; 731149225Sdes char buf[1024], str[1024]; 732149225Sdes char *ch; 73369700Smsmith int id, error; 73469700Smsmith 73569700Smsmith /* 73669700Smsmith * Locate the database and initialise. 73769700Smsmith */ 73869700Smsmith TAILQ_INIT(&pci_vendors); 73969700Smsmith if ((dbf = getenv("PCICONF_VENDOR_DATABASE")) == NULL) 740287746Sbapt dbf = _PATH_LPCIVDB; 741287746Sbapt if ((db = fopen(dbf, "r")) == NULL) { 74269700Smsmith dbf = _PATH_PCIVDB; 743287746Sbapt if ((db = fopen(dbf, "r")) == NULL) 744287746Sbapt return(1); 745287746Sbapt } 74669700Smsmith cv = NULL; 74769700Smsmith cd = NULL; 74869700Smsmith error = 0; 74969700Smsmith 75069700Smsmith /* 75169700Smsmith * Scan input lines from the database 75269700Smsmith */ 75369700Smsmith for (;;) { 75469700Smsmith if (fgets(buf, sizeof(buf), db) == NULL) 75568677Smsmith break; 75669700Smsmith 757149225Sdes if ((ch = strchr(buf, '#')) != NULL) 758149225Sdes *ch = '\0'; 759149225Sdes ch = strchr(buf, '\0') - 1; 760149225Sdes while (ch > buf && isspace(*ch)) 761149225Sdes *ch-- = '\0'; 762149225Sdes if (ch <= buf) 763149225Sdes continue; 764149225Sdes 765149225Sdes /* Can't handle subvendor / subdevice entries yet */ 766149225Sdes if (buf[0] == '\t' && buf[1] == '\t') 767149225Sdes continue; 768149225Sdes 76969700Smsmith /* Check for vendor entry */ 770149225Sdes if (buf[0] != '\t' && sscanf(buf, "%04x %[^\n]", &id, str) == 2) { 77169700Smsmith if ((id == 0) || (strlen(str) < 1)) 77269700Smsmith continue; 77369700Smsmith if ((cv = malloc(sizeof(struct pci_vendor_info))) == NULL) { 77469700Smsmith warn("allocating vendor entry"); 77569700Smsmith error = 1; 77669700Smsmith break; 77769700Smsmith } 77869700Smsmith if ((cv->desc = strdup(str)) == NULL) { 77969700Smsmith free(cv); 78069700Smsmith warn("allocating vendor description"); 78169700Smsmith error = 1; 78269700Smsmith break; 78369700Smsmith } 78469700Smsmith cv->id = id; 78569700Smsmith TAILQ_INIT(&cv->devs); 78669700Smsmith TAILQ_INSERT_TAIL(&pci_vendors, cv, link); 78769700Smsmith continue; 78869700Smsmith } 789149223Sdes 79069700Smsmith /* Check for device entry */ 791149225Sdes if (buf[0] == '\t' && sscanf(buf + 1, "%04x %[^\n]", &id, str) == 2) { 79269700Smsmith if ((id == 0) || (strlen(str) < 1)) 79369700Smsmith continue; 79469700Smsmith if (cv == NULL) { 79569700Smsmith warnx("device entry with no vendor!"); 79669700Smsmith continue; 79769700Smsmith } 79869700Smsmith if ((cd = malloc(sizeof(struct pci_device_info))) == NULL) { 79969700Smsmith warn("allocating device entry"); 80069700Smsmith error = 1; 80169700Smsmith break; 80269700Smsmith } 80369700Smsmith if ((cd->desc = strdup(str)) == NULL) { 80469700Smsmith free(cd); 80569700Smsmith warn("allocating device description"); 80669700Smsmith error = 1; 80769700Smsmith break; 80869700Smsmith } 80969700Smsmith cd->id = id; 81069700Smsmith TAILQ_INSERT_TAIL(&cv->devs, cd, link); 81169700Smsmith continue; 81269700Smsmith } 81369700Smsmith 81469700Smsmith /* It's a comment or junk, ignore it */ 81568677Smsmith } 81669700Smsmith if (ferror(db)) 81769700Smsmith error = 1; 81869700Smsmith fclose(db); 819149223Sdes 82069700Smsmith return(error); 82168677Smsmith} 82268677Smsmith 823166435Sjhbuint32_t 824166435Sjhbread_config(int fd, struct pcisel *sel, long reg, int width) 825166435Sjhb{ 826166435Sjhb struct pci_io pi; 82769700Smsmith 828166435Sjhb pi.pi_sel = *sel; 829166435Sjhb pi.pi_reg = reg; 830166435Sjhb pi.pi_width = width; 831166435Sjhb 832166435Sjhb if (ioctl(fd, PCIOCREAD, &pi) < 0) 833166435Sjhb err(1, "ioctl(PCIOCREAD)"); 834166435Sjhb 835166435Sjhb return (pi.pi_data); 836166435Sjhb} 837166435Sjhb 83819102Ssestatic struct pcisel 839261250Sjhbgetdevice(const char *name) 84019102Sse{ 841261250Sjhb struct pci_conf_io pc; 842261250Sjhb struct pci_conf conf[1]; 843261250Sjhb struct pci_match_conf patterns[1]; 844261250Sjhb char *cp; 845261250Sjhb int fd; 846261250Sjhb 847261250Sjhb fd = open(_PATH_DEVPCI, O_RDONLY, 0); 848261250Sjhb if (fd < 0) 849261250Sjhb err(1, "%s", _PATH_DEVPCI); 850261250Sjhb 851261250Sjhb bzero(&pc, sizeof(struct pci_conf_io)); 852261250Sjhb pc.match_buf_len = sizeof(conf); 853261250Sjhb pc.matches = conf; 854261250Sjhb 855261250Sjhb bzero(&patterns, sizeof(patterns)); 856261250Sjhb 857261250Sjhb /* 858261250Sjhb * The pattern structure requires the unit to be split out from 859261250Sjhb * the driver name. Walk backwards from the end of the name to 860261250Sjhb * find the start of the unit. 861261250Sjhb */ 862261250Sjhb if (name[0] == '\0') 863275465Smarkj errx(1, "Empty device name"); 864261250Sjhb cp = strchr(name, '\0'); 865261250Sjhb assert(cp != NULL && cp != name); 866261250Sjhb cp--; 867261250Sjhb while (cp != name && isdigit(cp[-1])) 868261250Sjhb cp--; 869275465Smarkj if (cp == name || !isdigit(*cp)) 870261250Sjhb errx(1, "Invalid device name"); 871261250Sjhb if ((size_t)(cp - name) + 1 > sizeof(patterns[0].pd_name)) 872275465Smarkj errx(1, "Device name is too long"); 873261250Sjhb memcpy(patterns[0].pd_name, name, cp - name); 874261250Sjhb patterns[0].pd_unit = strtol(cp, &cp, 10); 875261250Sjhb assert(*cp == '\0'); 876261250Sjhb patterns[0].flags = PCI_GETCONF_MATCH_NAME | PCI_GETCONF_MATCH_UNIT; 877261250Sjhb pc.num_patterns = 1; 878261250Sjhb pc.pat_buf_len = sizeof(patterns); 879261250Sjhb pc.patterns = patterns; 880261250Sjhb 881261250Sjhb if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 882261250Sjhb err(1, "ioctl(PCIOCGETCONF)"); 883261250Sjhb if (pc.status != PCI_GETCONF_LAST_DEVICE && 884261250Sjhb pc.status != PCI_GETCONF_MORE_DEVS) 885261250Sjhb errx(1, "error returned from PCIOCGETCONF ioctl"); 886261250Sjhb close(fd); 887261250Sjhb if (pc.num_matches == 0) 888261250Sjhb errx(1, "Device not found"); 889261250Sjhb return (conf[0].pc_sel); 890261250Sjhb} 891261250Sjhb 892261250Sjhbstatic struct pcisel 893261250Sjhbparsesel(const char *str) 894261250Sjhb{ 895116640Sjmg char *ep = strchr(str, '@'); 896116640Sjmg char *epbase; 89719102Sse struct pcisel sel; 898172447Sse unsigned long selarr[4]; 899172447Sse int i; 900116640Sjmg 901116640Sjmg if (ep == NULL) 902116640Sjmg ep = (char *)str; 903116640Sjmg else 904116640Sjmg ep++; 905116640Sjmg 906116640Sjmg epbase = ep; 907116640Sjmg 90819102Sse if (strncmp(ep, "pci", 3) == 0) { 90919102Sse ep += 3; 910172447Sse i = 0; 911172447Sse do { 912172447Sse selarr[i++] = strtoul(ep, &ep, 10); 913172448Sse } while ((*ep == ':' || *ep == '.') && *++ep != '\0' && i < 4); 914172447Sse 915172447Sse if (i > 2) 916172447Sse sel.pc_func = selarr[--i]; 917172447Sse else 91819102Sse sel.pc_func = 0; 919172447Sse sel.pc_dev = selarr[--i]; 920172447Sse sel.pc_bus = selarr[--i]; 921172447Sse if (i > 0) 922172447Sse sel.pc_domain = selarr[--i]; 923172447Sse else 924172447Sse sel.pc_domain = 0; 92519102Sse } 926116640Sjmg if (*ep != '\x0' || ep == epbase) 92719102Sse errx(1, "cannot parse selector %s", str); 92819102Sse return sel; 92919102Sse} 93019102Sse 931261250Sjhbstatic struct pcisel 932261250Sjhbgetsel(const char *str) 933261250Sjhb{ 934261250Sjhb 935261250Sjhb /* 936261250Sjhb * No device names contain colons and selectors always contain 937261250Sjhb * at least one colon. 938261250Sjhb */ 939261250Sjhb if (strchr(str, ':') == NULL) 940261250Sjhb return (getdevice(str)); 941261250Sjhb else 942261250Sjhb return (parsesel(str)); 943261250Sjhb} 944261250Sjhb 94519102Ssestatic void 94677533Simpreadone(int fd, struct pcisel *sel, long reg, int width) 94719102Sse{ 94819102Sse 949166435Sjhb printf("%0*x", width*2, read_config(fd, sel, reg, width)); 95077533Simp} 95177533Simp 95277533Simpstatic void 95377533Simpreadit(const char *name, const char *reg, int width) 95477533Simp{ 95577533Simp long rstart; 95677533Simp long rend; 95777533Simp long r; 95877533Simp char *end; 95977533Simp int i; 96077533Simp int fd; 96177533Simp struct pcisel sel; 96277533Simp 96319102Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 96419102Sse if (fd < 0) 96519102Sse err(1, "%s", _PATH_DEVPCI); 96619102Sse 96777533Simp rend = rstart = strtol(reg, &end, 0); 96877533Simp if (end && *end == ':') { 96977533Simp end++; 97077533Simp rend = strtol(end, (char **) 0, 0); 97177533Simp } 97277533Simp sel = getsel(name); 973149223Sdes for (i = 1, r = rstart; r <= rend; i++, r += width) { 97477533Simp readone(fd, &sel, r, width); 975182708Simp if (i && !(i % 8)) 976182708Simp putchar(' '); 97791299Ssos putchar(i % (16/width) ? ' ' : '\n'); 97877533Simp } 97991299Ssos if (i % (16/width) != 1) 98077533Simp putchar('\n'); 98177533Simp close(fd); 98219102Sse} 98319102Sse 98419102Ssestatic void 98519102Ssewriteit(const char *name, const char *reg, const char *data, int width) 98619102Sse{ 98719102Sse int fd; 98819102Sse struct pci_io pi; 98919102Sse 99019102Sse pi.pi_sel = getsel(name); 99119102Sse pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 99219102Sse pi.pi_width = width; 99319102Sse pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */ 99419102Sse 99519102Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 99619102Sse if (fd < 0) 99719102Sse err(1, "%s", _PATH_DEVPCI); 99819102Sse 99919102Sse if (ioctl(fd, PCIOCWRITE, &pi) < 0) 100019102Sse err(1, "ioctl(PCIOCWRITE)"); 100119102Sse} 100221935Sse 100321935Ssestatic void 1004212329Sjhbchkattached(const char *name) 100521935Sse{ 100621935Sse int fd; 100721935Sse struct pci_io pi; 100821935Sse 100921935Sse pi.pi_sel = getsel(name); 101021935Sse 101121935Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 101221935Sse if (fd < 0) 101321935Sse err(1, "%s", _PATH_DEVPCI); 101421935Sse 101521935Sse if (ioctl(fd, PCIOCATTACHED, &pi) < 0) 101621935Sse err(1, "ioctl(PCIOCATTACHED)"); 101721935Sse 101821935Sse exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ 101921935Sse printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached"); 102021935Sse} 1021