pciconf.c revision 39231
1/* 2 * Copyright 1996 Massachusetts Institute of Technology 3 * 4 * Permission to use, copy, modify, and distribute this software and 5 * its documentation for any purpose and without fee is hereby 6 * granted, provided that both the above copyright notice and this 7 * permission notice appear in all copies, that both the above 8 * copyright notice and this permission notice appear in all 9 * supporting documentation, and that the name of M.I.T. not be used 10 * in advertising or publicity pertaining to distribution of the 11 * software without specific, written prior permission. M.I.T. makes 12 * no representations about the suitability of this software for any 13 * purpose. It is provided "as is" without express or implied 14 * warranty. 15 * 16 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 17 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 20 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#ifndef lint 31static const char rcsid[] = 32 "$Id: pciconf.c,v 1.5 1997/10/06 11:38:30 charnier Exp $"; 33#endif /* not lint */ 34 35#include <sys/types.h> 36#include <sys/fcntl.h> 37 38#include <err.h> 39#include <stdlib.h> 40#include <stdio.h> 41#include <string.h> 42#include <unistd.h> 43 44#include <pci/pcivar.h> 45#include <pci/pci_ioctl.h> 46 47#include "pathnames.h" 48 49static void list_devs(void); 50static void readit(const char *, const char *, int); 51static void writeit(const char *, const char *, const char *, int); 52static void chkattached(const char *, int); 53 54static exitstatus = 0; 55 56static void 57usage() 58{ 59 fprintf(stderr, "%s\n%s\n%s\n%s\n", 60 "usage: pciconf -l", 61 " pciconf -a sel", 62 " pciconf -r [-b | -h] sel addr", 63 " pciconf -w [-b | -h] sel addr [value]"); 64 exit (1); 65} 66 67int 68main(int argc, char **argv) 69{ 70 int c; 71 int listmode, readmode, writemode, attachedmode; 72 int byte, isshort; 73 74 listmode = readmode = writemode = attachedmode = byte = isshort = 0; 75 76 while ((c = getopt(argc, argv, "alrwbh")) != -1) { 77 switch(c) { 78 case 'a': 79 attachedmode = 1; 80 break; 81 82 case 'l': 83 listmode = 1; 84 break; 85 86 case 'r': 87 readmode = 1; 88 break; 89 90 case 'w': 91 writemode = 1; 92 break; 93 94 case 'b': 95 byte = 1; 96 break; 97 98 case 'h': 99 isshort = 1; 100 break; 101 102 default: 103 usage(); 104 } 105 } 106 107 if ((listmode && optind != argc) 108 || (writemode && optind + 3 != argc) 109 || (readmode && optind + 2 != argc) 110 || (attachedmode && optind + 1 != argc)) 111 usage(); 112 113 if (listmode) { 114 list_devs(); 115 } else if(attachedmode) { 116 chkattached(argv[optind], 117 byte ? 1 : isshort ? 2 : 4); 118 } else if(readmode) { 119 readit(argv[optind], argv[optind + 1], 120 byte ? 1 : isshort ? 2 : 4); 121 } else if(writemode) { 122 writeit(argv[optind], argv[optind + 1], argv[optind + 2], 123 byte ? 1 : isshort ? 2 : 4); 124 } else { 125 usage(); 126 } 127 128 return exitstatus; 129} 130 131static void 132list_devs(void) 133{ 134 int fd; 135 struct pci_conf_io pc; 136 struct pci_conf conf[255], *p; 137 138 fd = open(_PATH_DEVPCI, O_RDWR, 0); 139 if (fd < 0) 140 err(1, "%s", _PATH_DEVPCI); 141 142 bzero(&pc, sizeof(struct pci_conf_io)); 143 pc.match_buf_len = sizeof(conf); 144 pc.matches = conf; 145 146 do { 147 if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 148 err(1, "ioctl(PCIOCGETCONF)"); 149 150 /* 151 * 255 entries should be more than enough for most people, 152 * but if someone has more devices, and then changes things 153 * around between ioctls, we'll do the cheezy thing and 154 * just bail. The alternative would be to go back to the 155 * beginning of the list, and print things twice, which may 156 * not be desireable. 157 */ 158 if (pc.status == PCI_GETCONF_LIST_CHANGED) { 159 warnx("PCI device list changed, please try again"); 160 exitstatus = 1; 161 close(fd); 162 return; 163 } else if (pc.status == PCI_GETCONF_ERROR) { 164 warnx("Error returned from PCIOCGETCONF ioctl"); 165 exitstatus = 1; 166 close(fd); 167 return; 168 } 169 for (p = conf; p < &conf[pc.num_matches]; p++) { 170 if ((p->pd_name == NULL) || (*p->pd_name == '\0')) 171 continue; 172 173 printf("%s%d@pci%d:%d:%d:\tclass=0x%06x card=0x%08lx " 174 "chip=0x%08lx rev=0x%02x hdr=0x%02x\n", 175 p->pd_name, p->pd_unit, 176 p->pc_sel.pc_bus, p->pc_sel.pc_dev, 177 p->pc_sel.pc_func, (p->pc_class << 16) | 178 (p->pc_subclass << 8) | p->pc_progif, 179 (p->pc_subdevice << 16) | p->pc_subvendor, 180 (p->pc_device << 16) | p->pc_vendor, 181 p->pc_revid, p->pc_hdr); 182 } 183 } while (pc.status == PCI_GETCONF_MORE_DEVS); 184 185 close(fd); 186} 187 188static struct pcisel 189getsel(const char *str) 190{ 191 char *ep = (char*) str; 192 struct pcisel sel; 193 194 if (strncmp(ep, "pci", 3) == 0) { 195 ep += 3; 196 sel.pc_bus = strtoul(ep, &ep, 0); 197 if (!ep || *ep++ != ':') 198 errx(1, "cannot parse selector %s", str); 199 sel.pc_dev = strtoul(ep, &ep, 0); 200 if (!ep || *ep != ':') { 201 sel.pc_func = 0; 202 } else { 203 ep++; 204 sel.pc_func = strtoul(ep, &ep, 0); 205 } 206 } 207 if (*ep == ':') 208 ep++; 209 if (*ep || ep == str) 210 errx(1, "cannot parse selector %s", str); 211 return sel; 212} 213 214static void 215readit(const char *name, const char *reg, int width) 216{ 217 int fd; 218 struct pci_io pi; 219 220 pi.pi_sel = getsel(name); 221 pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 222 pi.pi_width = width; 223 224 fd = open(_PATH_DEVPCI, O_RDWR, 0); 225 if (fd < 0) 226 err(1, "%s", _PATH_DEVPCI); 227 228 if (ioctl(fd, PCIOCREAD, &pi) < 0) 229 err(1, "ioctl(PCIOCREAD)"); 230 231 printf("0x%08x\n", pi.pi_data); 232} 233 234static void 235writeit(const char *name, const char *reg, const char *data, int width) 236{ 237 int fd; 238 struct pci_io pi; 239 240 pi.pi_sel = getsel(name); 241 pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 242 pi.pi_width = width; 243 pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */ 244 245 fd = open(_PATH_DEVPCI, O_RDWR, 0); 246 if (fd < 0) 247 err(1, "%s", _PATH_DEVPCI); 248 249 if (ioctl(fd, PCIOCWRITE, &pi) < 0) 250 err(1, "ioctl(PCIOCWRITE)"); 251} 252 253static void 254chkattached (const char *name, int width) 255{ 256 int fd; 257 struct pci_io pi; 258 259 pi.pi_sel = getsel(name); 260 pi.pi_reg = 0; 261 pi.pi_width = width; 262 pi.pi_data = 0; 263 264 fd = open(_PATH_DEVPCI, O_RDWR, 0); 265 if (fd < 0) 266 err(1, "%s", _PATH_DEVPCI); 267 268 if (ioctl(fd, PCIOCATTACHED, &pi) < 0) 269 err(1, "ioctl(PCIOCATTACHED)"); 270 271 exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ 272 printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached"); 273} 274