1/* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 *
| 1/* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 *
|
90}; 91 92static int 93pci_open(dev_t dev, int oflags, int devtype, struct thread *td) 94{ 95 int error; 96 97 if (oflags & FWRITE) { 98 error = securelevel_gt(td->td_ucred, 0); 99 if (error) 100 return (error); 101 } 102 103 return (0); 104} 105 106static int 107pci_close(dev_t dev, int flag, int devtype, struct thread *td) 108{ 109 return 0; 110} 111 112/* 113 * Match a single pci_conf structure against an array of pci_match_conf 114 * structures. The first argument, 'matches', is an array of num_matches 115 * pci_match_conf structures. match_buf is a pointer to the pci_conf 116 * structure that will be compared to every entry in the matches array. 117 * This function returns 1 on failure, 0 on success. 118 */ 119static int 120pci_conf_match(struct pci_match_conf *matches, int num_matches, 121 struct pci_conf *match_buf) 122{ 123 int i; 124 125 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 126 return(1); 127 128 for (i = 0; i < num_matches; i++) { 129 /* 130 * I'm not sure why someone would do this...but... 131 */ 132 if (matches[i].flags == PCI_GETCONF_NO_MATCH) 133 continue; 134 135 /* 136 * Look at each of the match flags. If it's set, do the 137 * comparison. If the comparison fails, we don't have a 138 * match, go on to the next item if there is one. 139 */ 140 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) 141 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 142 continue; 143 144 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) 145 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 146 continue; 147 148 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) 149 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 150 continue; 151 152 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 153 && (match_buf->pc_vendor != matches[i].pc_vendor)) 154 continue; 155 156 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) 157 && (match_buf->pc_device != matches[i].pc_device)) 158 continue; 159 160 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) 161 && (match_buf->pc_class != matches[i].pc_class)) 162 continue; 163 164 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) 165 && (match_buf->pd_unit != matches[i].pd_unit)) 166 continue; 167 168 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) 169 && (strncmp(matches[i].pd_name, match_buf->pd_name, 170 sizeof(match_buf->pd_name)) != 0)) 171 continue; 172 173 return(0); 174 } 175 176 return(1); 177} 178 179static int 180pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 181{ 182 device_t pci, pcib; 183 struct pci_io *io; 184 const char *name; 185 int error; 186 187 if (!(flag & FWRITE)) 188 return EPERM; 189 190 191 switch(cmd) { 192 case PCIOCGETCONF: 193 { 194 struct pci_devinfo *dinfo; 195 struct pci_conf_io *cio; 196 struct devlist *devlist_head; 197 struct pci_match_conf *pattern_buf; 198 int num_patterns; 199 size_t iolen; 200 int ionum, i; 201 202 cio = (struct pci_conf_io *)data; 203 204 num_patterns = 0; 205 dinfo = NULL; 206 207 /* 208 * Hopefully the user won't pass in a null pointer, but it 209 * can't hurt to check. 210 */ 211 if (cio == NULL) { 212 error = EINVAL; 213 break; 214 } 215 216 /* 217 * If the user specified an offset into the device list, 218 * but the list has changed since they last called this 219 * ioctl, tell them that the list has changed. They will 220 * have to get the list from the beginning. 221 */ 222 if ((cio->offset != 0) 223 && (cio->generation != pci_generation)){ 224 cio->num_matches = 0; 225 cio->status = PCI_GETCONF_LIST_CHANGED; 226 error = 0; 227 break; 228 } 229 230 /* 231 * Check to see whether the user has asked for an offset 232 * past the end of our list. 233 */ 234 if (cio->offset >= pci_numdevs) { 235 cio->num_matches = 0; 236 cio->status = PCI_GETCONF_LAST_DEVICE; 237 error = 0; 238 break; 239 } 240 241 /* get the head of the device queue */ 242 devlist_head = &pci_devq; 243 244 /* 245 * Determine how much room we have for pci_conf structures. 246 * Round the user's buffer size down to the nearest 247 * multiple of sizeof(struct pci_conf) in case the user 248 * didn't specify a multiple of that size. 249 */ 250 iolen = min(cio->match_buf_len - 251 (cio->match_buf_len % sizeof(struct pci_conf)), 252 pci_numdevs * sizeof(struct pci_conf)); 253 254 /* 255 * Since we know that iolen is a multiple of the size of 256 * the pciconf union, it's okay to do this. 257 */ 258 ionum = iolen / sizeof(struct pci_conf); 259 260 /* 261 * If this test is true, the user wants the pci_conf 262 * structures returned to match the supplied entries. 263 */ 264 if ((cio->num_patterns > 0) 265 && (cio->pat_buf_len > 0)) { 266 /* 267 * pat_buf_len needs to be: 268 * num_patterns * sizeof(struct pci_match_conf) 269 * While it is certainly possible the user just 270 * allocated a large buffer, but set the number of 271 * matches correctly, it is far more likely that 272 * their kernel doesn't match the userland utility 273 * they're using. It's also possible that the user 274 * forgot to initialize some variables. Yes, this 275 * may be overly picky, but I hazard to guess that 276 * it's far more likely to just catch folks that 277 * updated their kernel but not their userland. 278 */ 279 if ((cio->num_patterns * 280 sizeof(struct pci_match_conf)) != cio->pat_buf_len){ 281 /* The user made a mistake, return an error*/ 282 cio->status = PCI_GETCONF_ERROR; 283 printf("pci_ioctl: pat_buf_len %d != " 284 "num_patterns (%d) * sizeof(struct " 285 "pci_match_conf) (%d)\npci_ioctl: " 286 "pat_buf_len should be = %d\n", 287 cio->pat_buf_len, cio->num_patterns, 288 (int)sizeof(struct pci_match_conf), 289 (int)sizeof(struct pci_match_conf) * 290 cio->num_patterns); 291 printf("pci_ioctl: do your headers match your " 292 "kernel?\n"); 293 cio->num_matches = 0; 294 error = EINVAL; 295 break; 296 } 297 298 /* 299 * Check the user's buffer to make sure it's readable. 300 */ 301 if (!useracc((caddr_t)cio->patterns, 302 cio->pat_buf_len, VM_PROT_READ)) { 303 printf("pci_ioctl: pattern buffer %p, " 304 "length %u isn't user accessible for" 305 " READ\n", cio->patterns, 306 cio->pat_buf_len); 307 error = EACCES; 308 break; 309 } 310 /* 311 * Allocate a buffer to hold the patterns. 312 */ 313 pattern_buf = malloc(cio->pat_buf_len, M_TEMP, 314 M_WAITOK); 315 error = copyin(cio->patterns, pattern_buf, 316 cio->pat_buf_len); 317 if (error != 0) 318 break; 319 num_patterns = cio->num_patterns; 320 321 } else if ((cio->num_patterns > 0) 322 || (cio->pat_buf_len > 0)) { 323 /* 324 * The user made a mistake, spit out an error. 325 */ 326 cio->status = PCI_GETCONF_ERROR; 327 cio->num_matches = 0; 328 printf("pci_ioctl: invalid GETCONF arguments\n"); 329 error = EINVAL; 330 break; 331 } else 332 pattern_buf = NULL; 333 334 /* 335 * Make sure we can write to the match buffer. 336 */ 337 if (!useracc((caddr_t)cio->matches, 338 cio->match_buf_len, VM_PROT_WRITE)) { 339 printf("pci_ioctl: match buffer %p, length %u " 340 "isn't user accessible for WRITE\n", 341 cio->matches, cio->match_buf_len); 342 error = EACCES; 343 break; 344 } 345 346 /* 347 * Go through the list of devices and copy out the devices 348 * that match the user's criteria. 349 */ 350 for (cio->num_matches = 0, error = 0, i = 0, 351 dinfo = STAILQ_FIRST(devlist_head); 352 (dinfo != NULL) && (cio->num_matches < ionum) 353 && (error == 0) && (i < pci_numdevs); 354 dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 355 356 if (i < cio->offset) 357 continue; 358 359 /* Populate pd_name and pd_unit */ 360 name = NULL; 361 if (dinfo->cfg.dev && dinfo->conf.pd_name[0] == '\0') 362 name = device_get_name(dinfo->cfg.dev); 363 if (name) { 364 strncpy(dinfo->conf.pd_name, name, 365 sizeof(dinfo->conf.pd_name)); 366 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0; 367 dinfo->conf.pd_unit = 368 device_get_unit(dinfo->cfg.dev); 369 } 370 371 if ((pattern_buf == NULL) || 372 (pci_conf_match(pattern_buf, num_patterns, 373 &dinfo->conf) == 0)) { 374 375 /* 376 * If we've filled up the user's buffer, 377 * break out at this point. Since we've 378 * got a match here, we'll pick right back 379 * up at the matching entry. We can also 380 * tell the user that there are more matches 381 * left. 382 */ 383 if (cio->num_matches >= ionum) 384 break; 385 386 error = copyout(&dinfo->conf, 387 &cio->matches[cio->num_matches], 388 sizeof(struct pci_conf)); 389 cio->num_matches++; 390 } 391 } 392 393 /* 394 * Set the pointer into the list, so if the user is getting 395 * n records at a time, where n < pci_numdevs, 396 */ 397 cio->offset = i; 398 399 /* 400 * Set the generation, the user will need this if they make 401 * another ioctl call with offset != 0. 402 */ 403 cio->generation = pci_generation; 404 405 /* 406 * If this is the last device, inform the user so he won't 407 * bother asking for more devices. If dinfo isn't NULL, we 408 * know that there are more matches in the list because of 409 * the way the traversal is done. 410 */ 411 if (dinfo == NULL) 412 cio->status = PCI_GETCONF_LAST_DEVICE; 413 else 414 cio->status = PCI_GETCONF_MORE_DEVS; 415 416 if (pattern_buf != NULL) 417 free(pattern_buf, M_TEMP); 418 419 break; 420 } 421 case PCIOCREAD: 422 io = (struct pci_io *)data; 423 switch(io->pi_width) { 424 case 4: 425 case 2: 426 case 1: 427 /* 428 * Assume that the user-level bus number is 429 * actually the pciN instance number. We map 430 * from that to the real pcib+bus combination. 431 */ 432 pci = devclass_get_device(devclass_find("pci"), 433 io->pi_sel.pc_bus); 434 if (pci) { 435 int b = pcib_get_bus(pci); 436 pcib = device_get_parent(pci); 437 io->pi_data = 438 PCIB_READ_CONFIG(pcib, 439 b, 440 io->pi_sel.pc_dev, 441 io->pi_sel.pc_func, 442 io->pi_reg, 443 io->pi_width); 444 error = 0; 445 } else { 446 error = ENODEV; 447 } 448 break; 449 default: 450 error = ENODEV; 451 break; 452 } 453 break; 454 455 case PCIOCWRITE: 456 io = (struct pci_io *)data; 457 switch(io->pi_width) { 458 case 4: 459 case 2: 460 case 1: 461 /* 462 * Assume that the user-level bus number is 463 * actually the pciN instance number. We map 464 * from that to the real pcib+bus combination. 465 */ 466 pci = devclass_get_device(devclass_find("pci"), 467 io->pi_sel.pc_bus); 468 if (pci) { 469 int b = pcib_get_bus(pci); 470 pcib = device_get_parent(pci); 471 PCIB_WRITE_CONFIG(pcib, 472 b, 473 io->pi_sel.pc_dev, 474 io->pi_sel.pc_func, 475 io->pi_reg, 476 io->pi_data, 477 io->pi_width); 478 error = 0; 479 } else { 480 error = ENODEV; 481 } 482 break; 483 default: 484 error = ENODEV; 485 break; 486 } 487 break; 488 489 default: 490 error = ENOTTY; 491 break; 492 } 493 494 return (error); 495} 496
| 82}; 83 84static int 85pci_open(dev_t dev, int oflags, int devtype, struct thread *td) 86{ 87 int error; 88 89 if (oflags & FWRITE) { 90 error = securelevel_gt(td->td_ucred, 0); 91 if (error) 92 return (error); 93 } 94 95 return (0); 96} 97 98static int 99pci_close(dev_t dev, int flag, int devtype, struct thread *td) 100{ 101 return 0; 102} 103 104/* 105 * Match a single pci_conf structure against an array of pci_match_conf 106 * structures. The first argument, 'matches', is an array of num_matches 107 * pci_match_conf structures. match_buf is a pointer to the pci_conf 108 * structure that will be compared to every entry in the matches array. 109 * This function returns 1 on failure, 0 on success. 110 */ 111static int 112pci_conf_match(struct pci_match_conf *matches, int num_matches, 113 struct pci_conf *match_buf) 114{ 115 int i; 116 117 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) 118 return(1); 119 120 for (i = 0; i < num_matches; i++) { 121 /* 122 * I'm not sure why someone would do this...but... 123 */ 124 if (matches[i].flags == PCI_GETCONF_NO_MATCH) 125 continue; 126 127 /* 128 * Look at each of the match flags. If it's set, do the 129 * comparison. If the comparison fails, we don't have a 130 * match, go on to the next item if there is one. 131 */ 132 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) 133 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) 134 continue; 135 136 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) 137 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) 138 continue; 139 140 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) 141 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) 142 continue; 143 144 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 145 && (match_buf->pc_vendor != matches[i].pc_vendor)) 146 continue; 147 148 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) 149 && (match_buf->pc_device != matches[i].pc_device)) 150 continue; 151 152 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) 153 && (match_buf->pc_class != matches[i].pc_class)) 154 continue; 155 156 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) 157 && (match_buf->pd_unit != matches[i].pd_unit)) 158 continue; 159 160 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) 161 && (strncmp(matches[i].pd_name, match_buf->pd_name, 162 sizeof(match_buf->pd_name)) != 0)) 163 continue; 164 165 return(0); 166 } 167 168 return(1); 169} 170 171static int 172pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 173{ 174 device_t pci, pcib; 175 struct pci_io *io; 176 const char *name; 177 int error; 178 179 if (!(flag & FWRITE)) 180 return EPERM; 181 182 183 switch(cmd) { 184 case PCIOCGETCONF: 185 { 186 struct pci_devinfo *dinfo; 187 struct pci_conf_io *cio; 188 struct devlist *devlist_head; 189 struct pci_match_conf *pattern_buf; 190 int num_patterns; 191 size_t iolen; 192 int ionum, i; 193 194 cio = (struct pci_conf_io *)data; 195 196 num_patterns = 0; 197 dinfo = NULL; 198 199 /* 200 * Hopefully the user won't pass in a null pointer, but it 201 * can't hurt to check. 202 */ 203 if (cio == NULL) { 204 error = EINVAL; 205 break; 206 } 207 208 /* 209 * If the user specified an offset into the device list, 210 * but the list has changed since they last called this 211 * ioctl, tell them that the list has changed. They will 212 * have to get the list from the beginning. 213 */ 214 if ((cio->offset != 0) 215 && (cio->generation != pci_generation)){ 216 cio->num_matches = 0; 217 cio->status = PCI_GETCONF_LIST_CHANGED; 218 error = 0; 219 break; 220 } 221 222 /* 223 * Check to see whether the user has asked for an offset 224 * past the end of our list. 225 */ 226 if (cio->offset >= pci_numdevs) { 227 cio->num_matches = 0; 228 cio->status = PCI_GETCONF_LAST_DEVICE; 229 error = 0; 230 break; 231 } 232 233 /* get the head of the device queue */ 234 devlist_head = &pci_devq; 235 236 /* 237 * Determine how much room we have for pci_conf structures. 238 * Round the user's buffer size down to the nearest 239 * multiple of sizeof(struct pci_conf) in case the user 240 * didn't specify a multiple of that size. 241 */ 242 iolen = min(cio->match_buf_len - 243 (cio->match_buf_len % sizeof(struct pci_conf)), 244 pci_numdevs * sizeof(struct pci_conf)); 245 246 /* 247 * Since we know that iolen is a multiple of the size of 248 * the pciconf union, it's okay to do this. 249 */ 250 ionum = iolen / sizeof(struct pci_conf); 251 252 /* 253 * If this test is true, the user wants the pci_conf 254 * structures returned to match the supplied entries. 255 */ 256 if ((cio->num_patterns > 0) 257 && (cio->pat_buf_len > 0)) { 258 /* 259 * pat_buf_len needs to be: 260 * num_patterns * sizeof(struct pci_match_conf) 261 * While it is certainly possible the user just 262 * allocated a large buffer, but set the number of 263 * matches correctly, it is far more likely that 264 * their kernel doesn't match the userland utility 265 * they're using. It's also possible that the user 266 * forgot to initialize some variables. Yes, this 267 * may be overly picky, but I hazard to guess that 268 * it's far more likely to just catch folks that 269 * updated their kernel but not their userland. 270 */ 271 if ((cio->num_patterns * 272 sizeof(struct pci_match_conf)) != cio->pat_buf_len){ 273 /* The user made a mistake, return an error*/ 274 cio->status = PCI_GETCONF_ERROR; 275 printf("pci_ioctl: pat_buf_len %d != " 276 "num_patterns (%d) * sizeof(struct " 277 "pci_match_conf) (%d)\npci_ioctl: " 278 "pat_buf_len should be = %d\n", 279 cio->pat_buf_len, cio->num_patterns, 280 (int)sizeof(struct pci_match_conf), 281 (int)sizeof(struct pci_match_conf) * 282 cio->num_patterns); 283 printf("pci_ioctl: do your headers match your " 284 "kernel?\n"); 285 cio->num_matches = 0; 286 error = EINVAL; 287 break; 288 } 289 290 /* 291 * Check the user's buffer to make sure it's readable. 292 */ 293 if (!useracc((caddr_t)cio->patterns, 294 cio->pat_buf_len, VM_PROT_READ)) { 295 printf("pci_ioctl: pattern buffer %p, " 296 "length %u isn't user accessible for" 297 " READ\n", cio->patterns, 298 cio->pat_buf_len); 299 error = EACCES; 300 break; 301 } 302 /* 303 * Allocate a buffer to hold the patterns. 304 */ 305 pattern_buf = malloc(cio->pat_buf_len, M_TEMP, 306 M_WAITOK); 307 error = copyin(cio->patterns, pattern_buf, 308 cio->pat_buf_len); 309 if (error != 0) 310 break; 311 num_patterns = cio->num_patterns; 312 313 } else if ((cio->num_patterns > 0) 314 || (cio->pat_buf_len > 0)) { 315 /* 316 * The user made a mistake, spit out an error. 317 */ 318 cio->status = PCI_GETCONF_ERROR; 319 cio->num_matches = 0; 320 printf("pci_ioctl: invalid GETCONF arguments\n"); 321 error = EINVAL; 322 break; 323 } else 324 pattern_buf = NULL; 325 326 /* 327 * Make sure we can write to the match buffer. 328 */ 329 if (!useracc((caddr_t)cio->matches, 330 cio->match_buf_len, VM_PROT_WRITE)) { 331 printf("pci_ioctl: match buffer %p, length %u " 332 "isn't user accessible for WRITE\n", 333 cio->matches, cio->match_buf_len); 334 error = EACCES; 335 break; 336 } 337 338 /* 339 * Go through the list of devices and copy out the devices 340 * that match the user's criteria. 341 */ 342 for (cio->num_matches = 0, error = 0, i = 0, 343 dinfo = STAILQ_FIRST(devlist_head); 344 (dinfo != NULL) && (cio->num_matches < ionum) 345 && (error == 0) && (i < pci_numdevs); 346 dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 347 348 if (i < cio->offset) 349 continue; 350 351 /* Populate pd_name and pd_unit */ 352 name = NULL; 353 if (dinfo->cfg.dev && dinfo->conf.pd_name[0] == '\0') 354 name = device_get_name(dinfo->cfg.dev); 355 if (name) { 356 strncpy(dinfo->conf.pd_name, name, 357 sizeof(dinfo->conf.pd_name)); 358 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0; 359 dinfo->conf.pd_unit = 360 device_get_unit(dinfo->cfg.dev); 361 } 362 363 if ((pattern_buf == NULL) || 364 (pci_conf_match(pattern_buf, num_patterns, 365 &dinfo->conf) == 0)) { 366 367 /* 368 * If we've filled up the user's buffer, 369 * break out at this point. Since we've 370 * got a match here, we'll pick right back 371 * up at the matching entry. We can also 372 * tell the user that there are more matches 373 * left. 374 */ 375 if (cio->num_matches >= ionum) 376 break; 377 378 error = copyout(&dinfo->conf, 379 &cio->matches[cio->num_matches], 380 sizeof(struct pci_conf)); 381 cio->num_matches++; 382 } 383 } 384 385 /* 386 * Set the pointer into the list, so if the user is getting 387 * n records at a time, where n < pci_numdevs, 388 */ 389 cio->offset = i; 390 391 /* 392 * Set the generation, the user will need this if they make 393 * another ioctl call with offset != 0. 394 */ 395 cio->generation = pci_generation; 396 397 /* 398 * If this is the last device, inform the user so he won't 399 * bother asking for more devices. If dinfo isn't NULL, we 400 * know that there are more matches in the list because of 401 * the way the traversal is done. 402 */ 403 if (dinfo == NULL) 404 cio->status = PCI_GETCONF_LAST_DEVICE; 405 else 406 cio->status = PCI_GETCONF_MORE_DEVS; 407 408 if (pattern_buf != NULL) 409 free(pattern_buf, M_TEMP); 410 411 break; 412 } 413 case PCIOCREAD: 414 io = (struct pci_io *)data; 415 switch(io->pi_width) { 416 case 4: 417 case 2: 418 case 1: 419 /* 420 * Assume that the user-level bus number is 421 * actually the pciN instance number. We map 422 * from that to the real pcib+bus combination. 423 */ 424 pci = devclass_get_device(devclass_find("pci"), 425 io->pi_sel.pc_bus); 426 if (pci) { 427 int b = pcib_get_bus(pci); 428 pcib = device_get_parent(pci); 429 io->pi_data = 430 PCIB_READ_CONFIG(pcib, 431 b, 432 io->pi_sel.pc_dev, 433 io->pi_sel.pc_func, 434 io->pi_reg, 435 io->pi_width); 436 error = 0; 437 } else { 438 error = ENODEV; 439 } 440 break; 441 default: 442 error = ENODEV; 443 break; 444 } 445 break; 446 447 case PCIOCWRITE: 448 io = (struct pci_io *)data; 449 switch(io->pi_width) { 450 case 4: 451 case 2: 452 case 1: 453 /* 454 * Assume that the user-level bus number is 455 * actually the pciN instance number. We map 456 * from that to the real pcib+bus combination. 457 */ 458 pci = devclass_get_device(devclass_find("pci"), 459 io->pi_sel.pc_bus); 460 if (pci) { 461 int b = pcib_get_bus(pci); 462 pcib = device_get_parent(pci); 463 PCIB_WRITE_CONFIG(pcib, 464 b, 465 io->pi_sel.pc_dev, 466 io->pi_sel.pc_func, 467 io->pi_reg, 468 io->pi_data, 469 io->pi_width); 470 error = 0; 471 } else { 472 error = ENODEV; 473 } 474 break; 475 default: 476 error = ENODEV; 477 break; 478 } 479 break; 480 481 default: 482 error = ENOTTY; 483 break; 484 } 485 486 return (error); 487} 488
|