pciconf.c revision 41103
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. 1519102Sse * 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[] = 3241103Sken "$Id: pciconf.c,v 1.6 1998/09/15 08:21:13 gibbs Exp $"; 3330172Scharnier#endif /* not lint */ 3430172Scharnier 3519102Sse#include <sys/types.h> 3619102Sse#include <sys/fcntl.h> 3719102Sse 3819102Sse#include <err.h> 3919102Sse#include <stdlib.h> 4019102Sse#include <stdio.h> 4119102Sse#include <string.h> 4219102Sse#include <unistd.h> 4319102Sse 4419102Sse#include <pci/pcivar.h> 4519102Sse#include <pci/pci_ioctl.h> 4619102Sse 4719102Sse#include "pathnames.h" 4819102Sse 4919102Ssestatic void list_devs(void); 5019102Ssestatic void readit(const char *, const char *, int); 5119102Ssestatic void writeit(const char *, const char *, const char *, int); 5221935Ssestatic void chkattached(const char *, int); 5319102Sse 5421935Ssestatic exitstatus = 0; 5519102Sse 5619102Ssestatic void 5730172Scharnierusage() 5830172Scharnier{ 5930172Scharnier fprintf(stderr, "%s\n%s\n%s\n%s\n", 6030172Scharnier "usage: pciconf -l", 6130172Scharnier " pciconf -a sel", 6230172Scharnier " pciconf -r [-b | -h] sel addr", 6330172Scharnier " pciconf -w [-b | -h] sel addr [value]"); 6419817Sse exit (1); 6519102Sse} 6619102Sse 6719102Sseint 6819102Ssemain(int argc, char **argv) 6919102Sse{ 7019102Sse int c; 7121935Sse int listmode, readmode, writemode, attachedmode; 7219102Sse int byte, isshort; 7319102Sse 7421935Sse listmode = readmode = writemode = attachedmode = byte = isshort = 0; 7519102Sse 7624428Simp while ((c = getopt(argc, argv, "alrwbh")) != -1) { 7719102Sse switch(c) { 7821935Sse case 'a': 7921935Sse attachedmode = 1; 8021935Sse break; 8121935Sse 8219102Sse case 'l': 8319102Sse listmode = 1; 8419102Sse break; 8519102Sse 8619102Sse case 'r': 8719102Sse readmode = 1; 8819102Sse break; 8919102Sse 9019102Sse case 'w': 9119102Sse writemode = 1; 9219102Sse break; 9319102Sse 9419102Sse case 'b': 9519102Sse byte = 1; 9619102Sse break; 9719102Sse 9819102Sse case 'h': 9919102Sse isshort = 1; 10019102Sse break; 10119102Sse 10219102Sse default: 10330172Scharnier usage(); 10419102Sse } 10519102Sse } 10619102Sse 10719102Sse if ((listmode && optind != argc) 10819102Sse || (writemode && optind + 3 != argc) 10921935Sse || (readmode && optind + 2 != argc) 11021935Sse || (attachedmode && optind + 1 != argc)) 11130172Scharnier usage(); 11219102Sse 11319102Sse if (listmode) { 11419102Sse list_devs(); 11521935Sse } else if(attachedmode) { 11621935Sse chkattached(argv[optind], 11721935Sse byte ? 1 : isshort ? 2 : 4); 11819102Sse } else if(readmode) { 11919102Sse readit(argv[optind], argv[optind + 1], 12019102Sse byte ? 1 : isshort ? 2 : 4); 12119102Sse } else if(writemode) { 12219102Sse writeit(argv[optind], argv[optind + 1], argv[optind + 2], 12319102Sse byte ? 1 : isshort ? 2 : 4); 12419102Sse } else { 12530172Scharnier usage(); 12619102Sse } 12719102Sse 12821935Sse return exitstatus; 12919102Sse} 13019102Sse 13119102Ssestatic void 13219102Sselist_devs(void) 13319102Sse{ 13419102Sse int fd; 13519102Sse struct pci_conf_io pc; 13619102Sse struct pci_conf conf[255], *p; 13741103Sken int none_count = 0; 13819102Sse 13939231Sgibbs fd = open(_PATH_DEVPCI, O_RDWR, 0); 14019102Sse if (fd < 0) 14119102Sse err(1, "%s", _PATH_DEVPCI); 14219102Sse 14339231Sgibbs bzero(&pc, sizeof(struct pci_conf_io)); 14439231Sgibbs pc.match_buf_len = sizeof(conf); 14539231Sgibbs pc.matches = conf; 14619102Sse 14739231Sgibbs do { 14839231Sgibbs if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 14939231Sgibbs err(1, "ioctl(PCIOCGETCONF)"); 15019102Sse 15139231Sgibbs /* 15239231Sgibbs * 255 entries should be more than enough for most people, 15339231Sgibbs * but if someone has more devices, and then changes things 15439231Sgibbs * around between ioctls, we'll do the cheezy thing and 15539231Sgibbs * just bail. The alternative would be to go back to the 15639231Sgibbs * beginning of the list, and print things twice, which may 15739231Sgibbs * not be desireable. 15839231Sgibbs */ 15939231Sgibbs if (pc.status == PCI_GETCONF_LIST_CHANGED) { 16039231Sgibbs warnx("PCI device list changed, please try again"); 16139231Sgibbs exitstatus = 1; 16239231Sgibbs close(fd); 16339231Sgibbs return; 16439231Sgibbs } else if (pc.status == PCI_GETCONF_ERROR) { 16539231Sgibbs warnx("Error returned from PCIOCGETCONF ioctl"); 16639231Sgibbs exitstatus = 1; 16739231Sgibbs close(fd); 16839231Sgibbs return; 16939231Sgibbs } 17039231Sgibbs for (p = conf; p < &conf[pc.num_matches]; p++) { 17139231Sgibbs 17239231Sgibbs printf("%s%d@pci%d:%d:%d:\tclass=0x%06x card=0x%08lx " 17339231Sgibbs "chip=0x%08lx rev=0x%02x hdr=0x%02x\n", 17441103Sken (p->pd_name && *p->pd_name) ? p->pd_name : 17541103Sken "none", 17641103Sken (p->pd_name && *p->pd_name) ? p->pd_unit : 17741103Sken none_count++, 17839231Sgibbs p->pc_sel.pc_bus, p->pc_sel.pc_dev, 17939231Sgibbs p->pc_sel.pc_func, (p->pc_class << 16) | 18039231Sgibbs (p->pc_subclass << 8) | p->pc_progif, 18139231Sgibbs (p->pc_subdevice << 16) | p->pc_subvendor, 18239231Sgibbs (p->pc_device << 16) | p->pc_vendor, 18339231Sgibbs p->pc_revid, p->pc_hdr); 18439231Sgibbs } 18539231Sgibbs } while (pc.status == PCI_GETCONF_MORE_DEVS); 18639231Sgibbs 18719102Sse close(fd); 18819102Sse} 18919102Sse 19019102Ssestatic struct pcisel 19119102Ssegetsel(const char *str) 19219102Sse{ 19319102Sse char *ep = (char*) str; 19419102Sse struct pcisel sel; 19519102Sse 19619102Sse if (strncmp(ep, "pci", 3) == 0) { 19719102Sse ep += 3; 19819102Sse sel.pc_bus = strtoul(ep, &ep, 0); 19919102Sse if (!ep || *ep++ != ':') 20019102Sse errx(1, "cannot parse selector %s", str); 20119102Sse sel.pc_dev = strtoul(ep, &ep, 0); 20219102Sse if (!ep || *ep != ':') { 20319102Sse sel.pc_func = 0; 20419102Sse } else { 20519102Sse ep++; 20619102Sse sel.pc_func = strtoul(ep, &ep, 0); 20719102Sse } 20819102Sse } 20919102Sse if (*ep == ':') 21019102Sse ep++; 21119102Sse if (*ep || ep == str) 21219102Sse errx(1, "cannot parse selector %s", str); 21319102Sse return sel; 21419102Sse} 21519102Sse 21619102Ssestatic void 21719102Ssereadit(const char *name, const char *reg, int width) 21819102Sse{ 21919102Sse int fd; 22019102Sse struct pci_io pi; 22119102Sse 22219102Sse pi.pi_sel = getsel(name); 22319102Sse pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 22419102Sse pi.pi_width = width; 22519102Sse 22619102Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 22719102Sse if (fd < 0) 22819102Sse err(1, "%s", _PATH_DEVPCI); 22919102Sse 23019102Sse if (ioctl(fd, PCIOCREAD, &pi) < 0) 23119102Sse err(1, "ioctl(PCIOCREAD)"); 23219102Sse 23319102Sse printf("0x%08x\n", pi.pi_data); 23419102Sse} 23519102Sse 23619102Ssestatic void 23719102Ssewriteit(const char *name, const char *reg, const char *data, int width) 23819102Sse{ 23919102Sse int fd; 24019102Sse struct pci_io pi; 24119102Sse 24219102Sse pi.pi_sel = getsel(name); 24319102Sse pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 24419102Sse pi.pi_width = width; 24519102Sse pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */ 24619102Sse 24719102Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 24819102Sse if (fd < 0) 24919102Sse err(1, "%s", _PATH_DEVPCI); 25019102Sse 25119102Sse if (ioctl(fd, PCIOCWRITE, &pi) < 0) 25219102Sse err(1, "ioctl(PCIOCWRITE)"); 25319102Sse} 25421935Sse 25521935Ssestatic void 25621935Ssechkattached (const char *name, int width) 25721935Sse{ 25821935Sse int fd; 25921935Sse struct pci_io pi; 26021935Sse 26121935Sse pi.pi_sel = getsel(name); 26221935Sse pi.pi_reg = 0; 26321935Sse pi.pi_width = width; 26421935Sse pi.pi_data = 0; 26521935Sse 26621935Sse fd = open(_PATH_DEVPCI, O_RDWR, 0); 26721935Sse if (fd < 0) 26821935Sse err(1, "%s", _PATH_DEVPCI); 26921935Sse 27021935Sse if (ioctl(fd, PCIOCATTACHED, &pi) < 0) 27121935Sse err(1, "ioctl(PCIOCATTACHED)"); 27221935Sse 27321935Sse exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ 27421935Sse printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached"); 27521935Sse} 276