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 31 static const char rcsid[] = 32 "$FreeBSD$"; 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 #include <sys/pciio.h> 44 45 #include "pathnames.h" 46 #include "vendors.h" 47 48 static void list_devs(int vendors); 49 static void list_vendor(int vendor, int device); 50 static void readit(const char *, const char *, int); 51 static void writeit(const char *, const char *, const char *, int); 52 static void chkattached(const char *, int); 53 54 static int exitstatus = 0; 55 56 static void 57 usage() 58 { 59 fprintf(stderr, "%s\n%s\n%s\n%s\n", 60 "usage: pciconf -l [-v]", 61 " pciconf -a sel", 62 " pciconf -r [-b | -h] sel addr", 63 " pciconf -w [-b | -h] sel addr [value]"); 64 exit (1); 65 } 66 67 int 68 main(int argc, char **argv) 69 { 70 int c; 71 int listmode, readmode, writemode, attachedmode, vendors; 72 int byte, isshort; 73 74 listmode = readmode = writemode = attachedmode = vendors = byte = isshort = 0; 75 76 while ((c = getopt(argc, argv, "alrwbhv")) != -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 case 'v': 103 vendors = 1; 104 break; 105 106 default: 107 usage(); 108 } 109 } 110 111 if ((listmode && optind != argc) 112 || (writemode && optind + 3 != argc) 113 || (readmode && optind + 2 != argc) 114 || (attachedmode && optind + 1 != argc)) 115 usage(); 116 117 if (listmode) { 118 list_devs(vendors); 119 } else if(attachedmode) { 120 chkattached(argv[optind], 121 byte ? 1 : isshort ? 2 : 4); 122 } else if(readmode) { 123 readit(argv[optind], argv[optind + 1], 124 byte ? 1 : isshort ? 2 : 4); 125 } else if(writemode) { 126 writeit(argv[optind], argv[optind + 1], argv[optind + 2], 127 byte ? 1 : isshort ? 2 : 4); 128 } else { 129 usage(); 130 } 131 132 return exitstatus; 133 } 134 135 static void 136 list_devs(int vendors) 137 { 138 int fd; 139 struct pci_conf_io pc; 140 struct pci_conf conf[255], *p; 141 int none_count = 0; 142 143 fd = open(_PATH_DEVPCI, O_RDWR, 0); 144 if (fd < 0) 145 err(1, "%s", _PATH_DEVPCI); 146 147 bzero(&pc, sizeof(struct pci_conf_io)); 148 pc.match_buf_len = sizeof(conf); 149 pc.matches = conf; 150 151 do { 152 if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 153 err(1, "ioctl(PCIOCGETCONF)"); 154 155 /* 156 * 255 entries should be more than enough for most people, 157 * but if someone has more devices, and then changes things 158 * around between ioctls, we'll do the cheezy thing and 159 * just bail. The alternative would be to go back to the 160 * beginning of the list, and print things twice, which may 161 * not be desireable. 162 */ 163 if (pc.status == PCI_GETCONF_LIST_CHANGED) { 164 warnx("PCI device list changed, please try again"); 165 exitstatus = 1; 166 close(fd); 167 return; 168 } else if (pc.status == PCI_GETCONF_ERROR) { 169 warnx("error returned from PCIOCGETCONF ioctl"); 170 exitstatus = 1; 171 close(fd); 172 return; 173 } 174 for (p = conf; p < &conf[pc.num_matches]; p++) { 175 176 printf("%s%d@pci%d:%d:%d:\tclass=0x%06x card=0x%08x " 177 "chip=0x%08x rev=0x%02x hdr=0x%02x\n", 178 (p->pd_name && *p->pd_name) ? p->pd_name : 179 "none", 180 (p->pd_name && *p->pd_name) ? (int)p->pd_unit : 181 none_count++, 182 p->pc_sel.pc_bus, p->pc_sel.pc_dev, 183 p->pc_sel.pc_func, (p->pc_class << 16) | 184 (p->pc_subclass << 8) | p->pc_progif, 185 (p->pc_subdevice << 16) | p->pc_subvendor, 186 (p->pc_device << 16) | p->pc_vendor, 187 p->pc_revid, p->pc_hdr); 188 if (vendors) 189 list_vendor(p->pc_vendor, p->pc_device); 190 } 191 } while (pc.status == PCI_GETCONF_MORE_DEVS); 192 193 close(fd); 194 } 195 196 static void 197 list_vendor(int vendor, int device) 198 { 199 struct pci_vendor_information *pv; 200 struct pci_device_information *pd; 201 202 for (pv = pci_vendor_information; pv->desc != NULL; pv++) 203 if (pv->id == vendor) 204 break; 205 if (pv->desc != NULL) { 206 printf(" <%s>,", pv->desc); 207 } else { 208 printf(" <unknown vendor 0x%04x>,", vendor); 209 } 210 for (pd = pv->devices; (pd != NULL) && (pd->desc != NULL); pd++) 211 if (pd->id == device) 212 break; 213 if ((pd != NULL) && (pd->desc != NULL)) { 214 printf("<%s>\n", pd->desc); 215 } else { 216 printf("<unknown device 0x%04x>\n", device); 217 } 218 } 219 220 static struct pcisel 221 getsel(const char *str) 222 { 223 char *ep = (char*) str; 224 struct pcisel sel; 225 226 if (strncmp(ep, "pci", 3) == 0) { 227 ep += 3; 228 sel.pc_bus = strtoul(ep, &ep, 0); 229 if (!ep || *ep++ != ':') 230 errx(1, "cannot parse selector %s", str); 231 sel.pc_dev = strtoul(ep, &ep, 0); 232 if (!ep || *ep != ':') { 233 sel.pc_func = 0; 234 } else { 235 ep++; 236 sel.pc_func = strtoul(ep, &ep, 0); 237 } 238 } 239 if (*ep == ':') 240 ep++; 241 if (*ep || ep == str) 242 errx(1, "cannot parse selector %s", str); 243 return sel; 244 } 245 246 static void 247 readit(const char *name, const char *reg, int width) 248 { 249 int fd; 250 struct pci_io pi; 251 252 pi.pi_sel = getsel(name); 253 pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 254 pi.pi_width = width; 255 256 fd = open(_PATH_DEVPCI, O_RDWR, 0); 257 if (fd < 0) 258 err(1, "%s", _PATH_DEVPCI); 259 260 if (ioctl(fd, PCIOCREAD, &pi) < 0) 261 err(1, "ioctl(PCIOCREAD)"); 262 263 printf("0x%08x\n", pi.pi_data); 264 } 265 266 static void 267 writeit(const char *name, const char *reg, const char *data, int width) 268 { 269 int fd; 270 struct pci_io pi; 271 272 pi.pi_sel = getsel(name); 273 pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 274 pi.pi_width = width; 275 pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */ 276 277 fd = open(_PATH_DEVPCI, O_RDWR, 0); 278 if (fd < 0) 279 err(1, "%s", _PATH_DEVPCI); 280 281 if (ioctl(fd, PCIOCWRITE, &pi) < 0) 282 err(1, "ioctl(PCIOCWRITE)"); 283 } 284 285 static void 286 chkattached (const char *name, int width) 287 { 288 int fd; 289 struct pci_io pi; 290 291 pi.pi_sel = getsel(name); 292 pi.pi_reg = 0; 293 pi.pi_width = width; 294 pi.pi_data = 0; 295 296 fd = open(_PATH_DEVPCI, O_RDWR, 0); 297 if (fd < 0) 298 err(1, "%s", _PATH_DEVPCI); 299 300 if (ioctl(fd, PCIOCATTACHED, &pi) < 0) 301 err(1, "ioctl(PCIOCATTACHED)"); 302 303 exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ 304 printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached"); 305 } 306