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$"; 3330172Scharnier#endif /* not lint */ 3430172Scharnier 3519102Sse#include <sys/types.h> 3619102Sse#include <sys/fcntl.h> 3719102Sse 38166435Sjhb#include <ctype.h> 3919102Sse#include <err.h> 40188018Sjhb#include <inttypes.h> 4119102Sse#include <stdlib.h> 4219102Sse#include <stdio.h> 4319102Sse#include <string.h> 4419102Sse#include <unistd.h> 4554322Sken#include <sys/pciio.h> 4669700Smsmith#include <sys/queue.h> 4719102Sse 4869785Smsmith#include <dev/pci/pcireg.h> 4969700Smsmith 5019102Sse#include "pathnames.h" 51166435Sjhb#include "pciconf.h" 5219102Sse 53149223Sdesstruct pci_device_info 5469700Smsmith{ 5569700Smsmith TAILQ_ENTRY(pci_device_info) link; 5669700Smsmith int id; 5769700Smsmith char *desc; 5869700Smsmith}; 5969700Smsmith 6069700Smsmithstruct pci_vendor_info 6169700Smsmith{ 6269700Smsmith TAILQ_ENTRY(pci_vendor_info) link; 6369700Smsmith TAILQ_HEAD(,pci_device_info) devs; 6469700Smsmith int id; 6569700Smsmith char *desc; 6669700Smsmith}; 6769700Smsmith 6869700SmsmithTAILQ_HEAD(,pci_vendor_info) pci_vendors; 6969700Smsmith 70188018Sjhbstatic void list_bars(int fd, struct pci_conf *p); 71236415Sjhbstatic void list_devs(int verbose, int bars, int caps, int errors); 7269700Smsmithstatic void list_verbose(struct pci_conf *p); 73166435Sjhbstatic const char *guess_class(struct pci_conf *p); 74166435Sjhbstatic const char *guess_subclass(struct pci_conf *p); 7569700Smsmithstatic int load_vendors(void); 7619102Ssestatic void readit(const char *, const char *, int); 7719102Ssestatic void writeit(const char *, const char *, const char *, int); 78212329Sjhbstatic void chkattached(const char *); 7919102Sse 8050225Speterstatic int exitstatus = 0; 8119102Sse 8219102Ssestatic void 83166435Sjhbusage(void) 8430172Scharnier{ 8530172Scharnier fprintf(stderr, "%s\n%s\n%s\n%s\n", 86236415Sjhb "usage: pciconf -l [-bcev]", 87103499Sjdp " pciconf -a selector", 88103499Sjdp " pciconf -r [-b | -h] selector addr[:addr2]", 89103499Sjdp " pciconf -w [-b | -h] selector addr value"); 9019817Sse exit (1); 9119102Sse} 9219102Sse 9319102Sseint 9419102Ssemain(int argc, char **argv) 9519102Sse{ 9619102Sse int c; 97236415Sjhb int listmode, readmode, writemode, attachedmode; 98236415Sjhb int bars, caps, errors, verbose; 9919102Sse int byte, isshort; 10019102Sse 101236415Sjhb listmode = readmode = writemode = attachedmode = 0; 102236415Sjhb bars = caps = errors = verbose = byte = isshort = 0; 10319102Sse 104236415Sjhb while ((c = getopt(argc, argv, "abcehlrwv")) != -1) { 10519102Sse switch(c) { 10621935Sse case 'a': 10721935Sse attachedmode = 1; 10821935Sse break; 10921935Sse 110182707Simp case 'b': 111188018Sjhb bars = 1; 112182707Simp byte = 1; 113182707Simp break; 114182707Simp 115166435Sjhb case 'c': 116166435Sjhb caps = 1; 117166435Sjhb break; 118166435Sjhb 119236415Sjhb case 'e': 120236415Sjhb errors = 1; 121236415Sjhb break; 122236415Sjhb 123182707Simp case 'h': 124182707Simp isshort = 1; 125182707Simp break; 126182707Simp 12719102Sse case 'l': 12819102Sse listmode = 1; 12919102Sse break; 13019102Sse 13119102Sse case 'r': 13219102Sse readmode = 1; 13319102Sse break; 134149223Sdes 13519102Sse case 'w': 13619102Sse writemode = 1; 13719102Sse break; 13819102Sse 13968677Smsmith case 'v': 14069700Smsmith verbose = 1; 14168677Smsmith break; 14268677Smsmith 14319102Sse default: 14430172Scharnier usage(); 14519102Sse } 14619102Sse } 14719102Sse 14819102Sse if ((listmode && optind != argc) 14919102Sse || (writemode && optind + 3 != argc) 15021935Sse || (readmode && optind + 2 != argc) 151133271Simp || (attachedmode && optind + 1 != argc)) 15230172Scharnier usage(); 15319102Sse 15419102Sse if (listmode) { 155236415Sjhb list_devs(verbose, bars, caps, errors); 15677513Simp } else if (attachedmode) { 157212329Sjhb chkattached(argv[optind]); 15877513Simp } else if (readmode) { 159149223Sdes readit(argv[optind], argv[optind + 1], 160182708Simp byte ? 1 : isshort ? 2 : 4); 16177513Simp } else if (writemode) { 16219102Sse writeit(argv[optind], argv[optind + 1], argv[optind + 2], 163182708Simp byte ? 1 : isshort ? 2 : 4); 16419102Sse } else { 165149223Sdes usage(); 16619102Sse } 16719102Sse 16821935Sse return exitstatus; 16919102Sse} 17019102Sse 17119102Ssestatic void 172236415Sjhblist_devs(int verbose, int bars, int caps, int errors) 17319102Sse{ 17419102Sse int fd; 17519102Sse struct pci_conf_io pc; 17619102Sse struct pci_conf conf[255], *p; 17741103Sken int none_count = 0; 17819102Sse 17969700Smsmith if (verbose) 18069700Smsmith load_vendors(); 18169700Smsmith 182236415Sjhb fd = open(_PATH_DEVPCI, (caps || errors) ? O_RDWR : O_RDONLY, 0); 18319102Sse if (fd < 0) 18419102Sse err(1, "%s", _PATH_DEVPCI); 18519102Sse 18639231Sgibbs bzero(&pc, sizeof(struct pci_conf_io)); 18739231Sgibbs pc.match_buf_len = sizeof(conf); 18839231Sgibbs pc.matches = conf; 18919102Sse 19039231Sgibbs do { 19139231Sgibbs if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 19239231Sgibbs err(1, "ioctl(PCIOCGETCONF)"); 19319102Sse 19439231Sgibbs /* 19539231Sgibbs * 255 entries should be more than enough for most people, 19639231Sgibbs * but if someone has more devices, and then changes things 197228990Suqs * around between ioctls, we'll do the cheesy thing and 19839231Sgibbs * just bail. The alternative would be to go back to the 19939231Sgibbs * beginning of the list, and print things twice, which may 200228990Suqs * not be desirable. 20139231Sgibbs */ 20239231Sgibbs if (pc.status == PCI_GETCONF_LIST_CHANGED) { 20339231Sgibbs warnx("PCI device list changed, please try again"); 20439231Sgibbs exitstatus = 1; 20539231Sgibbs close(fd); 20639231Sgibbs return; 20739231Sgibbs } else if (pc.status == PCI_GETCONF_ERROR) { 20853761Scharnier warnx("error returned from PCIOCGETCONF ioctl"); 20939231Sgibbs exitstatus = 1; 21039231Sgibbs close(fd); 21139231Sgibbs return; 21239231Sgibbs } 21339231Sgibbs for (p = conf; p < &conf[pc.num_matches]; p++) { 214172394Smarius printf("%s%d@pci%d:%d:%d:%d:\tclass=0x%06x card=0x%08x " 215182708Simp "chip=0x%08x rev=0x%02x hdr=0x%02x\n", 216182708Simp (p->pd_name && *p->pd_name) ? p->pd_name : 217182708Simp "none", 218182708Simp (p->pd_name && *p->pd_name) ? (int)p->pd_unit : 219182708Simp none_count++, p->pc_sel.pc_domain, 220182708Simp p->pc_sel.pc_bus, p->pc_sel.pc_dev, 221182708Simp p->pc_sel.pc_func, (p->pc_class << 16) | 222182708Simp (p->pc_subclass << 8) | p->pc_progif, 223182708Simp (p->pc_subdevice << 16) | p->pc_subvendor, 224182708Simp (p->pc_device << 16) | p->pc_vendor, 225182708Simp p->pc_revid, p->pc_hdr); 22669700Smsmith if (verbose) 22769700Smsmith list_verbose(p); 228188018Sjhb if (bars) 229188018Sjhb list_bars(fd, p); 230166435Sjhb if (caps) 231166435Sjhb list_caps(fd, p); 232236415Sjhb if (errors) 233236415Sjhb list_errors(fd, p); 23439231Sgibbs } 23539231Sgibbs } while (pc.status == PCI_GETCONF_MORE_DEVS); 23639231Sgibbs 23719102Sse close(fd); 23819102Sse} 23919102Sse 24068677Smsmithstatic void 241188018Sjhblist_bars(int fd, struct pci_conf *p) 242188018Sjhb{ 243188018Sjhb struct pci_bar_io bar; 244188018Sjhb uint64_t base; 245188018Sjhb const char *type; 246188018Sjhb int i, range, max; 247188018Sjhb 248188018Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 249188018Sjhb case PCIM_HDRTYPE_NORMAL: 250188018Sjhb max = PCIR_MAX_BAR_0; 251188018Sjhb break; 252188018Sjhb case PCIM_HDRTYPE_BRIDGE: 253188018Sjhb max = PCIR_MAX_BAR_1; 254188018Sjhb break; 255188018Sjhb case PCIM_HDRTYPE_CARDBUS: 256188018Sjhb max = PCIR_MAX_BAR_2; 257188018Sjhb break; 258188018Sjhb default: 259188018Sjhb return; 260188018Sjhb } 261188018Sjhb 262188018Sjhb for (i = 0; i <= max; i++) { 263188018Sjhb bar.pbi_sel = p->pc_sel; 264188018Sjhb bar.pbi_reg = PCIR_BAR(i); 265188018Sjhb if (ioctl(fd, PCIOCGETBAR, &bar) < 0) 266188018Sjhb continue; 267188018Sjhb if (PCI_BAR_IO(bar.pbi_base)) { 268188018Sjhb type = "I/O Port"; 269188018Sjhb range = 32; 270188018Sjhb base = bar.pbi_base & PCIM_BAR_IO_BASE; 271188018Sjhb } else { 272188018Sjhb if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH) 273188018Sjhb type = "Prefetchable Memory"; 274188018Sjhb else 275188018Sjhb type = "Memory"; 276188018Sjhb switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) { 277188018Sjhb case PCIM_BAR_MEM_32: 278188018Sjhb range = 32; 279188018Sjhb break; 280188018Sjhb case PCIM_BAR_MEM_1MB: 281188018Sjhb range = 20; 282188018Sjhb break; 283188018Sjhb case PCIM_BAR_MEM_64: 284188018Sjhb range = 64; 285188018Sjhb break; 286188018Sjhb default: 287188018Sjhb range = -1; 288188018Sjhb } 289188018Sjhb base = bar.pbi_base & ~((uint64_t)0xf); 290188018Sjhb } 291188018Sjhb printf(" bar [%02x] = type %s, range %2d, base %#jx, ", 292188018Sjhb PCIR_BAR(i), type, range, (uintmax_t)base); 293246632Sneel printf("size %ju, %s\n", (uintmax_t)bar.pbi_length, 294188018Sjhb bar.pbi_enabled ? "enabled" : "disabled"); 295188018Sjhb } 296188018Sjhb} 297188018Sjhb 298188018Sjhbstatic void 29969700Smsmithlist_verbose(struct pci_conf *p) 30068677Smsmith{ 30169700Smsmith struct pci_vendor_info *vi; 30269700Smsmith struct pci_device_info *di; 303166435Sjhb const char *dp; 304149223Sdes 30569700Smsmith TAILQ_FOREACH(vi, &pci_vendors, link) { 30669700Smsmith if (vi->id == p->pc_vendor) { 307166435Sjhb printf(" vendor = '%s'\n", vi->desc); 30868677Smsmith break; 30969700Smsmith } 31069700Smsmith } 31169700Smsmith if (vi == NULL) { 31269700Smsmith di = NULL; 31368677Smsmith } else { 31469700Smsmith TAILQ_FOREACH(di, &vi->devs, link) { 31569700Smsmith if (di->id == p->pc_device) { 316166435Sjhb printf(" device = '%s'\n", di->desc); 31769700Smsmith break; 31869700Smsmith } 31969700Smsmith } 32068677Smsmith } 32169700Smsmith if ((dp = guess_class(p)) != NULL) 322166435Sjhb printf(" class = %s\n", dp); 32369700Smsmith if ((dp = guess_subclass(p)) != NULL) 324166435Sjhb printf(" subclass = %s\n", dp); 32569700Smsmith} 32669700Smsmith 32769700Smsmith/* 32869700Smsmith * This is a direct cut-and-paste from the table in sys/dev/pci/pci.c. 32969700Smsmith */ 33069700Smsmithstatic struct 33169700Smsmith{ 33269700Smsmith int class; 33369700Smsmith int subclass; 334166435Sjhb const char *desc; 33569700Smsmith} pci_nomatch_tab[] = { 33669700Smsmith {PCIC_OLD, -1, "old"}, 33769700Smsmith {PCIC_OLD, PCIS_OLD_NONVGA, "non-VGA display device"}, 33869700Smsmith {PCIC_OLD, PCIS_OLD_VGA, "VGA-compatible display device"}, 33969700Smsmith {PCIC_STORAGE, -1, "mass storage"}, 34069700Smsmith {PCIC_STORAGE, PCIS_STORAGE_SCSI, "SCSI"}, 34169700Smsmith {PCIC_STORAGE, PCIS_STORAGE_IDE, "ATA"}, 34269700Smsmith {PCIC_STORAGE, PCIS_STORAGE_FLOPPY, "floppy disk"}, 34369700Smsmith {PCIC_STORAGE, PCIS_STORAGE_IPI, "IPI"}, 34469700Smsmith {PCIC_STORAGE, PCIS_STORAGE_RAID, "RAID"}, 345184936Smav {PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, "ATA (ADMA)"}, 346184936Smav {PCIC_STORAGE, PCIS_STORAGE_SATA, "SATA"}, 347184936Smav {PCIC_STORAGE, PCIS_STORAGE_SAS, "SAS"}, 348240739Sgavin {PCIC_STORAGE, PCIS_STORAGE_NVM, "NVM"}, 34969700Smsmith {PCIC_NETWORK, -1, "network"}, 35069700Smsmith {PCIC_NETWORK, PCIS_NETWORK_ETHERNET, "ethernet"}, 35169700Smsmith {PCIC_NETWORK, PCIS_NETWORK_TOKENRING, "token ring"}, 35269700Smsmith {PCIC_NETWORK, PCIS_NETWORK_FDDI, "fddi"}, 35369700Smsmith {PCIC_NETWORK, PCIS_NETWORK_ATM, "ATM"}, 354144156Sjmg {PCIC_NETWORK, PCIS_NETWORK_ISDN, "ISDN"}, 35569700Smsmith {PCIC_DISPLAY, -1, "display"}, 35669700Smsmith {PCIC_DISPLAY, PCIS_DISPLAY_VGA, "VGA"}, 35769700Smsmith {PCIC_DISPLAY, PCIS_DISPLAY_XGA, "XGA"}, 358144156Sjmg {PCIC_DISPLAY, PCIS_DISPLAY_3D, "3D"}, 35969700Smsmith {PCIC_MULTIMEDIA, -1, "multimedia"}, 36069700Smsmith {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_VIDEO, "video"}, 36169700Smsmith {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_AUDIO, "audio"}, 362144156Sjmg {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_TELE, "telephony"}, 363184142Smav {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_HDA, "HDA"}, 36469700Smsmith {PCIC_MEMORY, -1, "memory"}, 36569700Smsmith {PCIC_MEMORY, PCIS_MEMORY_RAM, "RAM"}, 36669700Smsmith {PCIC_MEMORY, PCIS_MEMORY_FLASH, "flash"}, 36769700Smsmith {PCIC_BRIDGE, -1, "bridge"}, 36869700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_HOST, "HOST-PCI"}, 36969700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_ISA, "PCI-ISA"}, 37069700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_EISA, "PCI-EISA"}, 37169700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_MCA, "PCI-MCA"}, 37269700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_PCI, "PCI-PCI"}, 37369700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_PCMCIA, "PCI-PCMCIA"}, 37469700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_NUBUS, "PCI-NuBus"}, 37569700Smsmith {PCIC_BRIDGE, PCIS_BRIDGE_CARDBUS, "PCI-CardBus"}, 376144156Sjmg {PCIC_BRIDGE, PCIS_BRIDGE_RACEWAY, "PCI-RACEway"}, 37769700Smsmith {PCIC_SIMPLECOMM, -1, "simple comms"}, 37869700Smsmith {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_UART, "UART"}, /* could detect 16550 */ 37969700Smsmith {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_PAR, "parallel port"}, 380144156Sjmg {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MULSER, "multiport serial"}, 381144156Sjmg {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MODEM, "generic modem"}, 38269700Smsmith {PCIC_BASEPERIPH, -1, "base peripheral"}, 38369700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PIC, "interrupt controller"}, 38469700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_DMA, "DMA controller"}, 38569700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_TIMER, "timer"}, 38669700Smsmith {PCIC_BASEPERIPH, PCIS_BASEPERIPH_RTC, "realtime clock"}, 387144156Sjmg {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PCIHOT, "PCI hot-plug controller"}, 388184140Smav {PCIC_BASEPERIPH, PCIS_BASEPERIPH_SDHC, "SD host controller"}, 38969700Smsmith {PCIC_INPUTDEV, -1, "input device"}, 39069700Smsmith {PCIC_INPUTDEV, PCIS_INPUTDEV_KEYBOARD, "keyboard"}, 39169700Smsmith {PCIC_INPUTDEV, PCIS_INPUTDEV_DIGITIZER,"digitizer"}, 39269700Smsmith {PCIC_INPUTDEV, PCIS_INPUTDEV_MOUSE, "mouse"}, 393144156Sjmg {PCIC_INPUTDEV, PCIS_INPUTDEV_SCANNER, "scanner"}, 394144156Sjmg {PCIC_INPUTDEV, PCIS_INPUTDEV_GAMEPORT, "gameport"}, 39569700Smsmith {PCIC_DOCKING, -1, "docking station"}, 39669700Smsmith {PCIC_PROCESSOR, -1, "processor"}, 39769700Smsmith {PCIC_SERIALBUS, -1, "serial bus"}, 39869700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_FW, "FireWire"}, 399149223Sdes {PCIC_SERIALBUS, PCIS_SERIALBUS_ACCESS, "AccessBus"}, 40069700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_SSA, "SSA"}, 40169700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_USB, "USB"}, 40269700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_FC, "Fibre Channel"}, 40369700Smsmith {PCIC_SERIALBUS, PCIS_SERIALBUS_SMBUS, "SMBus"}, 404144156Sjmg {PCIC_WIRELESS, -1, "wireless controller"}, 405144156Sjmg {PCIC_WIRELESS, PCIS_WIRELESS_IRDA, "iRDA"}, 406144156Sjmg {PCIC_WIRELESS, PCIS_WIRELESS_IR, "IR"}, 407144156Sjmg {PCIC_WIRELESS, PCIS_WIRELESS_RF, "RF"}, 408144156Sjmg {PCIC_INTELLIIO, -1, "intelligent I/O controller"}, 409144156Sjmg {PCIC_INTELLIIO, PCIS_INTELLIIO_I2O, "I2O"}, 410144156Sjmg {PCIC_SATCOM, -1, "satellite communication"}, 411144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_TV, "sat TV"}, 412144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_AUDIO, "sat audio"}, 413144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_VOICE, "sat voice"}, 414144156Sjmg {PCIC_SATCOM, PCIS_SATCOM_DATA, "sat data"}, 415144156Sjmg {PCIC_CRYPTO, -1, "encrypt/decrypt"}, 416144156Sjmg {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "network/computer crypto"}, 417144156Sjmg {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "entertainment crypto"}, 418144156Sjmg {PCIC_DASP, -1, "dasp"}, 419144156Sjmg {PCIC_DASP, PCIS_DASP_DPIO, "DPIO module"}, 42069700Smsmith {0, 0, NULL} 42169700Smsmith}; 42269700Smsmith 423166435Sjhbstatic const char * 42469700Smsmithguess_class(struct pci_conf *p) 42569700Smsmith{ 42669700Smsmith int i; 42769700Smsmith 42869700Smsmith for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { 42969700Smsmith if (pci_nomatch_tab[i].class == p->pc_class) 43069700Smsmith return(pci_nomatch_tab[i].desc); 43169700Smsmith } 43269700Smsmith return(NULL); 43369700Smsmith} 43469700Smsmith 435166435Sjhbstatic const char * 43669700Smsmithguess_subclass(struct pci_conf *p) 43769700Smsmith{ 43869700Smsmith int i; 43969700Smsmith 44069700Smsmith for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { 44169700Smsmith if ((pci_nomatch_tab[i].class == p->pc_class) && 44269700Smsmith (pci_nomatch_tab[i].subclass == p->pc_subclass)) 44369700Smsmith return(pci_nomatch_tab[i].desc); 44469700Smsmith } 44569700Smsmith return(NULL); 44669700Smsmith} 44769700Smsmith 44869700Smsmithstatic int 44969700Smsmithload_vendors(void) 45069700Smsmith{ 451166435Sjhb const char *dbf; 45269700Smsmith FILE *db; 45369700Smsmith struct pci_vendor_info *cv; 45469700Smsmith struct pci_device_info *cd; 455149225Sdes char buf[1024], str[1024]; 456149225Sdes char *ch; 45769700Smsmith int id, error; 45869700Smsmith 45969700Smsmith /* 46069700Smsmith * Locate the database and initialise. 46169700Smsmith */ 46269700Smsmith TAILQ_INIT(&pci_vendors); 46369700Smsmith if ((dbf = getenv("PCICONF_VENDOR_DATABASE")) == NULL) 46469700Smsmith dbf = _PATH_PCIVDB; 46569700Smsmith if ((db = fopen(dbf, "r")) == NULL) 46669700Smsmith return(1); 46769700Smsmith cv = NULL; 46869700Smsmith cd = NULL; 46969700Smsmith error = 0; 47069700Smsmith 47169700Smsmith /* 47269700Smsmith * Scan input lines from the database 47369700Smsmith */ 47469700Smsmith for (;;) { 47569700Smsmith if (fgets(buf, sizeof(buf), db) == NULL) 47668677Smsmith break; 47769700Smsmith 478149225Sdes if ((ch = strchr(buf, '#')) != NULL) 479149225Sdes *ch = '\0'; 480149225Sdes ch = strchr(buf, '\0') - 1; 481149225Sdes while (ch > buf && isspace(*ch)) 482149225Sdes *ch-- = '\0'; 483149225Sdes if (ch <= buf) 484149225Sdes continue; 485149225Sdes 486149225Sdes /* Can't handle subvendor / subdevice entries yet */ 487149225Sdes if (buf[0] == '\t' && buf[1] == '\t') 488149225Sdes continue; 489149225Sdes 49069700Smsmith /* Check for vendor entry */ 491149225Sdes if (buf[0] != '\t' && sscanf(buf, "%04x %[^\n]", &id, str) == 2) { 49269700Smsmith if ((id == 0) || (strlen(str) < 1)) 49369700Smsmith continue; 49469700Smsmith if ((cv = malloc(sizeof(struct pci_vendor_info))) == NULL) { 49569700Smsmith warn("allocating vendor entry"); 49669700Smsmith error = 1; 49769700Smsmith break; 49869700Smsmith } 49969700Smsmith if ((cv->desc = strdup(str)) == NULL) { 50069700Smsmith free(cv); 50169700Smsmith warn("allocating vendor description"); 50269700Smsmith error = 1; 50369700Smsmith break; 50469700Smsmith } 50569700Smsmith cv->id = id; 50669700Smsmith TAILQ_INIT(&cv->devs); 50769700Smsmith TAILQ_INSERT_TAIL(&pci_vendors, cv, link); 50869700Smsmith continue; 50969700Smsmith } 510149223Sdes 51169700Smsmith /* Check for device entry */ 512149225Sdes if (buf[0] == '\t' && sscanf(buf + 1, "%04x %[^\n]", &id, str) == 2) { 51369700Smsmith if ((id == 0) || (strlen(str) < 1)) 51469700Smsmith continue; 51569700Smsmith if (cv == NULL) { 51669700Smsmith warnx("device entry with no vendor!"); 51769700Smsmith continue; 51869700Smsmith } 51969700Smsmith if ((cd = malloc(sizeof(struct pci_device_info))) == NULL) { 52069700Smsmith warn("allocating device entry"); 52169700Smsmith error = 1; 52269700Smsmith break; 52369700Smsmith } 52469700Smsmith if ((cd->desc = strdup(str)) == NULL) { 52569700Smsmith free(cd); 52669700Smsmith warn("allocating device description"); 52769700Smsmith error = 1; 52869700Smsmith break; 52969700Smsmith } 53069700Smsmith cd->id = id; 53169700Smsmith TAILQ_INSERT_TAIL(&cv->devs, cd, link); 53269700Smsmith continue; 53369700Smsmith } 53469700Smsmith 53569700Smsmith /* It's a comment or junk, ignore it */ 53668677Smsmith } 53769700Smsmith if (ferror(db)) 53869700Smsmith error = 1; 53969700Smsmith fclose(db); 540149223Sdes 54169700Smsmith return(error); 54268677Smsmith} 54368677Smsmith 544166435Sjhbuint32_t 545166435Sjhbread_config(int fd, struct pcisel *sel, long reg, int width) 546166435Sjhb{ 547166435Sjhb struct pci_io pi; 54869700Smsmith 549166435Sjhb pi.pi_sel = *sel; 550166435Sjhb pi.pi_reg = reg; 551166435Sjhb pi.pi_width = width; 552166435Sjhb 553166435Sjhb if (ioctl(fd, PCIOCREAD, &pi) < 0) 554166435Sjhb err(1, "ioctl(PCIOCREAD)"); 555166435Sjhb 556166435Sjhb return (pi.pi_data); 557166435Sjhb} 558166435Sjhb 55919102Ssestatic struct pcisel 56019102Ssegetsel(const char *str) 56119102Sse{ 562116640Sjmg char *ep = strchr(str, '@'); 563116640Sjmg char *epbase; 56419102Sse struct pcisel sel; 565172447Sse unsigned long selarr[4]; 566172447Sse int i; 567116640Sjmg 568116640Sjmg if (ep == NULL) 569116640Sjmg ep = (char *)str; 570116640Sjmg else 571116640Sjmg ep++; 572116640Sjmg 573116640Sjmg epbase = ep; 574116640Sjmg 57519102Sse if (strncmp(ep, "pci", 3) == 0) { 57619102Sse ep += 3; 577172447Sse i = 0; 578172447Sse do { 579172447Sse selarr[i++] = strtoul(ep, &ep, 10); 580172448Sse } while ((*ep == ':' || *ep == '.') && *++ep != '\0' && i < 4); 581172447Sse 582172447Sse if (i > 2) 583172447Sse sel.pc_func = selarr[--i]; 584172447Sse else 58519102Sse sel.pc_func = 0; 586172447Sse sel.pc_dev = selarr[--i]; 587172447Sse sel.pc_bus = selarr[--i]; 588172447Sse if (i > 0) 589172447Sse sel.pc_domain = selarr[--i]; 590172447Sse else 591172447Sse sel.pc_domain = 0; 59219102Sse } 593116640Sjmg if (*ep != '\x0' || ep == epbase) 59419102Sse errx(1, "cannot parse selector %s", str); 59519102Sse return sel; 59619102Sse} 59719102Sse 59819102Ssestatic void 59977533Simpreadone(int fd, struct pcisel *sel, long reg, int width) 60019102Sse{ 60119102Sse 602166435Sjhb printf("%0*x", width*2, read_config(fd, sel, reg, width)); 60377533Simp} 60477533Simp 60577533Simpstatic void 60677533Simpreadit(const char *name, const char *reg, int width) 60777533Simp{ 60877533Simp long rstart; 60977533Simp long rend; 61077533Simp long r; 61177533Simp char *end; 61277533Simp int i; 61377533Simp int fd; 61477533Simp struct pcisel sel; 61577533Simp 61619102Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 61719102Sse if (fd < 0) 61819102Sse err(1, "%s", _PATH_DEVPCI); 61919102Sse 62077533Simp rend = rstart = strtol(reg, &end, 0); 62177533Simp if (end && *end == ':') { 62277533Simp end++; 62377533Simp rend = strtol(end, (char **) 0, 0); 62477533Simp } 62577533Simp sel = getsel(name); 626149223Sdes for (i = 1, r = rstart; r <= rend; i++, r += width) { 62777533Simp readone(fd, &sel, r, width); 628182708Simp if (i && !(i % 8)) 629182708Simp putchar(' '); 63091299Ssos putchar(i % (16/width) ? ' ' : '\n'); 63177533Simp } 63291299Ssos if (i % (16/width) != 1) 63377533Simp putchar('\n'); 63477533Simp close(fd); 63519102Sse} 63619102Sse 63719102Ssestatic void 63819102Ssewriteit(const char *name, const char *reg, const char *data, int width) 63919102Sse{ 64019102Sse int fd; 64119102Sse struct pci_io pi; 64219102Sse 64319102Sse pi.pi_sel = getsel(name); 64419102Sse pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 64519102Sse pi.pi_width = width; 64619102Sse pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */ 64719102Sse 64819102Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 64919102Sse if (fd < 0) 65019102Sse err(1, "%s", _PATH_DEVPCI); 65119102Sse 65219102Sse if (ioctl(fd, PCIOCWRITE, &pi) < 0) 65319102Sse err(1, "ioctl(PCIOCWRITE)"); 65419102Sse} 65521935Sse 65621935Ssestatic void 657212329Sjhbchkattached(const char *name) 65821935Sse{ 65921935Sse int fd; 66021935Sse struct pci_io pi; 66121935Sse 66221935Sse pi.pi_sel = getsel(name); 66321935Sse 66421935Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 66521935Sse if (fd < 0) 66621935Sse err(1, "%s", _PATH_DEVPCI); 66721935Sse 66821935Sse if (ioctl(fd, PCIOCATTACHED, &pi) < 0) 66921935Sse err(1, "ioctl(PCIOCATTACHED)"); 67021935Sse 67121935Sse exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ 67221935Sse printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached"); 67321935Sse} 674