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 "$Id: pciconf.c,v 1.7 1998/11/12 00:22:30 ken 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 49 static void list_devs(void); 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", 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; 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 131 static void 132 list_devs(void) 133 { 134 int fd; 135 struct pci_conf_io pc; 136 struct pci_conf conf[255], *p; 137 int none_count = 0; 138 139 fd = open(_PATH_DEVPCI, O_RDWR, 0); 140 if (fd < 0) 141 err(1, "%s", _PATH_DEVPCI); 142 143 bzero(&pc, sizeof(struct pci_conf_io)); 144 pc.match_buf_len = sizeof(conf); 145 pc.matches = conf; 146 147 do { 148 if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 149 err(1, "ioctl(PCIOCGETCONF)"); 150 151 /* 152 * 255 entries should be more than enough for most people, 153 * but if someone has more devices, and then changes things 154 * around between ioctls, we'll do the cheezy thing and 155 * just bail. The alternative would be to go back to the 156 * beginning of the list, and print things twice, which may 157 * not be desireable. 158 */ 159 if (pc.status == PCI_GETCONF_LIST_CHANGED) { 160 warnx("PCI device list changed, please try again"); 161 exitstatus = 1; 162 close(fd); 163 return; 164 } else if (pc.status == PCI_GETCONF_ERROR) { 165 warnx("Error returned from PCIOCGETCONF ioctl"); 166 exitstatus = 1; 167 close(fd); 168 return; 169 } 170 for (p = conf; p < &conf[pc.num_matches]; p++) { 171 172 printf("%s%d@pci%d:%d:%d:\tclass=0x%06x card=0x%08x " 173 "chip=0x%08x rev=0x%02x hdr=0x%02x\n", 174 (p->pd_name && *p->pd_name) ? p->pd_name : 175 "none", 176 (p->pd_name && *p->pd_name) ? (int)p->pd_unit : 177 none_count++, 178 p->pc_sel.pc_bus, p->pc_sel.pc_dev, 179 p->pc_sel.pc_func, (p->pc_class << 16) | 180 (p->pc_subclass << 8) | p->pc_progif, 181 (p->pc_subdevice << 16) | p->pc_subvendor, 182 (p->pc_device << 16) | p->pc_vendor, 183 p->pc_revid, p->pc_hdr); 184 } 185 } while (pc.status == PCI_GETCONF_MORE_DEVS); 186 187 close(fd); 188 } 189 190 static struct pcisel 191 getsel(const char *str) 192 { 193 char *ep = (char*) str; 194 struct pcisel sel; 195 196 if (strncmp(ep, "pci", 3) == 0) { 197 ep += 3; 198 sel.pc_bus = strtoul(ep, &ep, 0); 199 if (!ep || *ep++ != ':') 200 errx(1, "cannot parse selector %s", str); 201 sel.pc_dev = strtoul(ep, &ep, 0); 202 if (!ep || *ep != ':') { 203 sel.pc_func = 0; 204 } else { 205 ep++; 206 sel.pc_func = strtoul(ep, &ep, 0); 207 } 208 } 209 if (*ep == ':') 210 ep++; 211 if (*ep || ep == str) 212 errx(1, "cannot parse selector %s", str); 213 return sel; 214 } 215 216 static void 217 readit(const char *name, const char *reg, int width) 218 { 219 int fd; 220 struct pci_io pi; 221 222 pi.pi_sel = getsel(name); 223 pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 224 pi.pi_width = width; 225 226 fd = open(_PATH_DEVPCI, O_RDWR, 0); 227 if (fd < 0) 228 err(1, "%s", _PATH_DEVPCI); 229 230 if (ioctl(fd, PCIOCREAD, &pi) < 0) 231 err(1, "ioctl(PCIOCREAD)"); 232 233 printf("0x%08x\n", pi.pi_data); 234 } 235 236 static void 237 writeit(const char *name, const char *reg, const char *data, int width) 238 { 239 int fd; 240 struct pci_io pi; 241 242 pi.pi_sel = getsel(name); 243 pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 244 pi.pi_width = width; 245 pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */ 246 247 fd = open(_PATH_DEVPCI, O_RDWR, 0); 248 if (fd < 0) 249 err(1, "%s", _PATH_DEVPCI); 250 251 if (ioctl(fd, PCIOCWRITE, &pi) < 0) 252 err(1, "ioctl(PCIOCWRITE)"); 253 } 254 255 static void 256 chkattached (const char *name, int width) 257 { 258 int fd; 259 struct pci_io pi; 260 261 pi.pi_sel = getsel(name); 262 pi.pi_reg = 0; 263 pi.pi_width = width; 264 pi.pi_data = 0; 265 266 fd = open(_PATH_DEVPCI, O_RDWR, 0); 267 if (fd < 0) 268 err(1, "%s", _PATH_DEVPCI); 269 270 if (ioctl(fd, PCIOCATTACHED, &pi) < 0) 271 err(1, "ioctl(PCIOCATTACHED)"); 272 273 exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ 274 printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached"); 275 } 276