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 47 static void list_devs(void); 48 static void readit(const char *, const char *, int); 49 static void writeit(const char *, const char *, const char *, int); 50 static void chkattached(const char *, int); 51 52 static int exitstatus = 0; 53 54 static void 55 usage() 56 { 57 fprintf(stderr, "%s\n%s\n%s\n%s\n", 58 "usage: pciconf -l", 59 " pciconf -a sel", 60 " pciconf -r [-b | -h] sel addr", 61 " pciconf -w [-b | -h] sel addr [value]"); 62 exit (1); 63 } 64 65 int 66 main(int argc, char **argv) 67 { 68 int c; 69 int listmode, readmode, writemode, attachedmode; 70 int byte, isshort; 71 72 listmode = readmode = writemode = attachedmode = byte = isshort = 0; 73 74 while ((c = getopt(argc, argv, "alrwbh")) != -1) { 75 switch(c) { 76 case 'a': 77 attachedmode = 1; 78 break; 79 80 case 'l': 81 listmode = 1; 82 break; 83 84 case 'r': 85 readmode = 1; 86 break; 87 88 case 'w': 89 writemode = 1; 90 break; 91 92 case 'b': 93 byte = 1; 94 break; 95 96 case 'h': 97 isshort = 1; 98 break; 99 100 default: 101 usage(); 102 } 103 } 104 105 if ((listmode && optind != argc) 106 || (writemode && optind + 3 != argc) 107 || (readmode && optind + 2 != argc) 108 || (attachedmode && optind + 1 != argc)) 109 usage(); 110 111 if (listmode) { 112 list_devs(); 113 } else if(attachedmode) { 114 chkattached(argv[optind], 115 byte ? 1 : isshort ? 2 : 4); 116 } else if(readmode) { 117 readit(argv[optind], argv[optind + 1], 118 byte ? 1 : isshort ? 2 : 4); 119 } else if(writemode) { 120 writeit(argv[optind], argv[optind + 1], argv[optind + 2], 121 byte ? 1 : isshort ? 2 : 4); 122 } else { 123 usage(); 124 } 125 126 return exitstatus; 127 } 128 129 static void 130 list_devs(void) 131 { 132 int fd; 133 struct pci_conf_io pc; 134 struct pci_conf conf[255], *p; 135 int none_count = 0; 136 137 fd = open(_PATH_DEVPCI, O_RDWR, 0); 138 if (fd < 0) 139 err(1, "%s", _PATH_DEVPCI); 140 141 bzero(&pc, sizeof(struct pci_conf_io)); 142 pc.match_buf_len = sizeof(conf); 143 pc.matches = conf; 144 145 do { 146 if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 147 err(1, "ioctl(PCIOCGETCONF)"); 148 149 /* 150 * 255 entries should be more than enough for most people, 151 * but if someone has more devices, and then changes things 152 * around between ioctls, we'll do the cheezy thing and 153 * just bail. The alternative would be to go back to the 154 * beginning of the list, and print things twice, which may 155 * not be desireable. 156 */ 157 if (pc.status == PCI_GETCONF_LIST_CHANGED) { 158 warnx("PCI device list changed, please try again"); 159 exitstatus = 1; 160 close(fd); 161 return; 162 } else if (pc.status == PCI_GETCONF_ERROR) { 163 warnx("error returned from PCIOCGETCONF ioctl"); 164 exitstatus = 1; 165 close(fd); 166 return; 167 } 168 for (p = conf; p < &conf[pc.num_matches]; p++) { 169 170 printf("%s%d@pci%d:%d:%d:\tclass=0x%06x card=0x%08x " 171 "chip=0x%08x rev=0x%02x hdr=0x%02x\n", 172 (p->pd_name && *p->pd_name) ? p->pd_name : 173 "none", 174 (p->pd_name && *p->pd_name) ? (int)p->pd_unit : 175 none_count++, 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 188 static struct pcisel 189 getsel(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 214 static void 215 readit(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 234 static void 235 writeit(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 253 static void 254 chkattached (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