pciconf.c revision 50479
1238405Sjkim/* 2238405Sjkim * Copyright 1996 Massachusetts Institute of Technology 3238405Sjkim * 4238405Sjkim * Permission to use, copy, modify, and distribute this software and 5238405Sjkim * its documentation for any purpose and without fee is hereby 6238405Sjkim * granted, provided that both the above copyright notice and this 7238405Sjkim * permission notice appear in all copies, that both the above 8238405Sjkim * copyright notice and this permission notice appear in all 9238405Sjkim * supporting documentation, and that the name of M.I.T. not be used 10238405Sjkim * in advertising or publicity pertaining to distribution of the 11238405Sjkim * software without specific, written prior permission. M.I.T. makes 12238405Sjkim * no representations about the suitability of this software for any 13238405Sjkim * purpose. It is provided "as is" without express or implied 14238405Sjkim * warranty. 15238405Sjkim * 16238405Sjkim * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 17238405Sjkim * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 18238405Sjkim * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19238405Sjkim * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 20238405Sjkim * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21238405Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22238405Sjkim * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23238405Sjkim * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24238405Sjkim * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25238405Sjkim * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26238405Sjkim * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27238405Sjkim * SUCH DAMAGE. 28238405Sjkim */ 29238405Sjkim 30238405Sjkim#ifndef lint 31238405Sjkimstatic const char rcsid[] = 32238405Sjkim "$FreeBSD: head/usr.sbin/pciconf/pciconf.c 50479 1999-08-28 01:35:59Z peter $"; 33238405Sjkim#endif /* not lint */ 34238405Sjkim 35238405Sjkim#include <sys/types.h> 36238405Sjkim#include <sys/fcntl.h> 37238405Sjkim 38238405Sjkim#include <err.h> 39238405Sjkim#include <stdlib.h> 40238405Sjkim#include <stdio.h> 41238405Sjkim#include <string.h> 42238405Sjkim#include <unistd.h> 43238405Sjkim 44238405Sjkim#include <pci/pcivar.h> 45238405Sjkim#include <pci/pci_ioctl.h> 46238405Sjkim 47238405Sjkim#include "pathnames.h" 48238405Sjkim 49238405Sjkimstatic void list_devs(void); 50238405Sjkimstatic void readit(const char *, const char *, int); 51238405Sjkimstatic void writeit(const char *, const char *, const char *, int); 52238405Sjkimstatic void chkattached(const char *, int); 53238405Sjkim 54238405Sjkimstatic int exitstatus = 0; 55238405Sjkim 56238405Sjkimstatic void 57238405Sjkimusage() 58238405Sjkim{ 59238405Sjkim fprintf(stderr, "%s\n%s\n%s\n%s\n", 60238405Sjkim "usage: pciconf -l", 61238405Sjkim " pciconf -a sel", 62238405Sjkim " pciconf -r [-b | -h] sel addr", 63238405Sjkim " pciconf -w [-b | -h] sel addr [value]"); 64238405Sjkim exit (1); 65238405Sjkim} 66238405Sjkim 67238405Sjkimint 68238405Sjkimmain(int argc, char **argv) 69238405Sjkim{ 70238405Sjkim int c; 71238405Sjkim int listmode, readmode, writemode, attachedmode; 72238405Sjkim int byte, isshort; 73238405Sjkim 74238405Sjkim listmode = readmode = writemode = attachedmode = byte = isshort = 0; 75238405Sjkim 76238405Sjkim while ((c = getopt(argc, argv, "alrwbh")) != -1) { 77238405Sjkim switch(c) { 78238405Sjkim case 'a': 79238405Sjkim attachedmode = 1; 80238405Sjkim break; 81238405Sjkim 82238405Sjkim case 'l': 83238405Sjkim listmode = 1; 84238405Sjkim break; 85238405Sjkim 86238405Sjkim case 'r': 87238405Sjkim readmode = 1; 88238405Sjkim break; 89238405Sjkim 90238405Sjkim case 'w': 91238405Sjkim writemode = 1; 92238405Sjkim break; 93238405Sjkim 94238405Sjkim case 'b': 95238405Sjkim byte = 1; 96238405Sjkim break; 97238405Sjkim 98238405Sjkim case 'h': 99238405Sjkim isshort = 1; 100238405Sjkim break; 101238405Sjkim 102238405Sjkim default: 103238405Sjkim usage(); 104238405Sjkim } 105238405Sjkim } 106238405Sjkim 107238405Sjkim if ((listmode && optind != argc) 108238405Sjkim || (writemode && optind + 3 != argc) 109238405Sjkim || (readmode && optind + 2 != argc) 110238405Sjkim || (attachedmode && optind + 1 != argc)) 111238405Sjkim usage(); 112238405Sjkim 113238405Sjkim if (listmode) { 114238405Sjkim list_devs(); 115238405Sjkim } else if(attachedmode) { 116238405Sjkim chkattached(argv[optind], 117238405Sjkim byte ? 1 : isshort ? 2 : 4); 118238405Sjkim } else if(readmode) { 119238405Sjkim readit(argv[optind], argv[optind + 1], 120238405Sjkim byte ? 1 : isshort ? 2 : 4); 121238405Sjkim } else if(writemode) { 122238405Sjkim writeit(argv[optind], argv[optind + 1], argv[optind + 2], 123238405Sjkim byte ? 1 : isshort ? 2 : 4); 124238405Sjkim } else { 125238405Sjkim usage(); 126238405Sjkim } 127238405Sjkim 128238405Sjkim return exitstatus; 129238405Sjkim} 130238405Sjkim 131238405Sjkimstatic void 132238405Sjkimlist_devs(void) 133238405Sjkim{ 134238405Sjkim int fd; 135238405Sjkim struct pci_conf_io pc; 136238405Sjkim struct pci_conf conf[255], *p; 137238405Sjkim int none_count = 0; 138238405Sjkim 139238405Sjkim fd = open(_PATH_DEVPCI, O_RDWR, 0); 140238405Sjkim if (fd < 0) 141238405Sjkim err(1, "%s", _PATH_DEVPCI); 142238405Sjkim 143238405Sjkim bzero(&pc, sizeof(struct pci_conf_io)); 144238405Sjkim pc.match_buf_len = sizeof(conf); 145238405Sjkim pc.matches = conf; 146238405Sjkim 147238405Sjkim do { 148238405Sjkim if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 149238405Sjkim err(1, "ioctl(PCIOCGETCONF)"); 150238405Sjkim 151238405Sjkim /* 152238405Sjkim * 255 entries should be more than enough for most people, 153238405Sjkim * but if someone has more devices, and then changes things 154238405Sjkim * around between ioctls, we'll do the cheezy thing and 155238405Sjkim * just bail. The alternative would be to go back to the 156238405Sjkim * beginning of the list, and print things twice, which may 157238405Sjkim * not be desireable. 158238405Sjkim */ 159238405Sjkim if (pc.status == PCI_GETCONF_LIST_CHANGED) { 160238405Sjkim warnx("PCI device list changed, please try again"); 161238405Sjkim exitstatus = 1; 162238405Sjkim close(fd); 163238405Sjkim return; 164238405Sjkim } else if (pc.status == PCI_GETCONF_ERROR) { 165238405Sjkim warnx("Error returned from PCIOCGETCONF ioctl"); 166238405Sjkim exitstatus = 1; 167238405Sjkim close(fd); 168238405Sjkim return; 169238405Sjkim } 170238405Sjkim for (p = conf; p < &conf[pc.num_matches]; p++) { 171238405Sjkim 172238405Sjkim printf("%s%d@pci%d:%d:%d:\tclass=0x%06x card=0x%08x " 173238405Sjkim "chip=0x%08x rev=0x%02x hdr=0x%02x\n", 174238405Sjkim (p->pd_name && *p->pd_name) ? p->pd_name : 175238405Sjkim "none", 176238405Sjkim (p->pd_name && *p->pd_name) ? (int)p->pd_unit : 177238405Sjkim none_count++, 178238405Sjkim p->pc_sel.pc_bus, p->pc_sel.pc_dev, 179238405Sjkim p->pc_sel.pc_func, (p->pc_class << 16) | 180238405Sjkim (p->pc_subclass << 8) | p->pc_progif, 181238405Sjkim (p->pc_subdevice << 16) | p->pc_subvendor, 182238405Sjkim (p->pc_device << 16) | p->pc_vendor, 183238405Sjkim p->pc_revid, p->pc_hdr); 184238405Sjkim } 185238405Sjkim } while (pc.status == PCI_GETCONF_MORE_DEVS); 186238405Sjkim 187238405Sjkim close(fd); 188238405Sjkim} 189238405Sjkim 190238405Sjkimstatic struct pcisel 191238405Sjkimgetsel(const char *str) 192238405Sjkim{ 193238405Sjkim char *ep = (char*) str; 194238405Sjkim struct pcisel sel; 195238405Sjkim 196238405Sjkim if (strncmp(ep, "pci", 3) == 0) { 197238405Sjkim ep += 3; 198238405Sjkim sel.pc_bus = strtoul(ep, &ep, 0); 199238405Sjkim if (!ep || *ep++ != ':') 200238405Sjkim errx(1, "cannot parse selector %s", str); 201238405Sjkim sel.pc_dev = strtoul(ep, &ep, 0); 202238405Sjkim if (!ep || *ep != ':') { 203238405Sjkim sel.pc_func = 0; 204238405Sjkim } else { 205238405Sjkim ep++; 206238405Sjkim sel.pc_func = strtoul(ep, &ep, 0); 207238405Sjkim } 208238405Sjkim } 209238405Sjkim if (*ep == ':') 210238405Sjkim ep++; 211238405Sjkim if (*ep || ep == str) 212238405Sjkim errx(1, "cannot parse selector %s", str); 213238405Sjkim return sel; 214238405Sjkim} 215238405Sjkim 216238405Sjkimstatic void 217238405Sjkimreadit(const char *name, const char *reg, int width) 218238405Sjkim{ 219238405Sjkim int fd; 220238405Sjkim struct pci_io pi; 221238405Sjkim 222238405Sjkim pi.pi_sel = getsel(name); 223238405Sjkim pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 224238405Sjkim pi.pi_width = width; 225238405Sjkim 226238405Sjkim fd = open(_PATH_DEVPCI, O_RDWR, 0); 227238405Sjkim if (fd < 0) 228238405Sjkim err(1, "%s", _PATH_DEVPCI); 229238405Sjkim 230238405Sjkim if (ioctl(fd, PCIOCREAD, &pi) < 0) 231238405Sjkim err(1, "ioctl(PCIOCREAD)"); 232238405Sjkim 233238405Sjkim printf("0x%08x\n", pi.pi_data); 234238405Sjkim} 235238405Sjkim 236238405Sjkimstatic void 237238405Sjkimwriteit(const char *name, const char *reg, const char *data, int width) 238238405Sjkim{ 239238405Sjkim int fd; 240238405Sjkim struct pci_io pi; 241238405Sjkim 242238405Sjkim pi.pi_sel = getsel(name); 243238405Sjkim pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 244238405Sjkim pi.pi_width = width; 245238405Sjkim pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */ 246238405Sjkim 247238405Sjkim fd = open(_PATH_DEVPCI, O_RDWR, 0); 248238405Sjkim if (fd < 0) 249238405Sjkim err(1, "%s", _PATH_DEVPCI); 250238405Sjkim 251238405Sjkim if (ioctl(fd, PCIOCWRITE, &pi) < 0) 252238405Sjkim err(1, "ioctl(PCIOCWRITE)"); 253238405Sjkim} 254238405Sjkim 255238405Sjkimstatic void 256238405Sjkimchkattached (const char *name, int width) 257238405Sjkim{ 258238405Sjkim int fd; 259238405Sjkim struct pci_io pi; 260238405Sjkim 261238405Sjkim pi.pi_sel = getsel(name); 262238405Sjkim pi.pi_reg = 0; 263238405Sjkim pi.pi_width = width; 264238405Sjkim pi.pi_data = 0; 265238405Sjkim 266238405Sjkim fd = open(_PATH_DEVPCI, O_RDWR, 0); 267238405Sjkim if (fd < 0) 268238405Sjkim err(1, "%s", _PATH_DEVPCI); 269238405Sjkim 270238405Sjkim if (ioctl(fd, PCIOCATTACHED, &pi) < 0) 271238405Sjkim err(1, "ioctl(PCIOCATTACHED)"); 272238405Sjkim 273238405Sjkim exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ 274238405Sjkim printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached"); 275238405Sjkim} 276238405Sjkim