1 /************************************************************************** 2 ** 3 ** $Id: pci.c,v 1.9 1994/11/02 23:47:13 se Exp $ 4 ** 5 ** General subroutines for the PCI bus on 80*86 systems. 6 ** pci_configure () 7 ** 8 ** 386bsd / FreeBSD 9 ** 10 **------------------------------------------------------------------------- 11 ** 12 ** Copyright (c) 1994 Wolfgang Stanglmeier. All rights reserved. 13 ** 14 ** Redistribution and use in source and binary forms, with or without 15 ** modification, are permitted provided that the following conditions 16 ** are met: 17 ** 1. Redistributions of source code must retain the above copyright 18 ** notice, this list of conditions and the following disclaimer. 19 ** 2. Redistributions in binary form must reproduce the above copyright 20 ** notice, this list of conditions and the following disclaimer in the 21 ** documentation and/or other materials provided with the distribution. 22 ** 3. The name of the author may not be used to endorse or promote products 23 ** derived from this software without specific prior written permission. 24 ** 25 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 ** 36 *************************************************************************** 37 */ 38 39 #include <pci.h> 40 #if NPCI > 0 41 42 #ifndef __FreeBSD2__ 43 #if __FreeBSD__ >= 2 44 #define __FreeBSD2__ 45 #endif 46 #endif 47 48 /*======================================================== 49 ** 50 ** #includes and declarations 51 ** 52 **======================================================== 53 */ 54 55 #include <sys/param.h> 56 #include <sys/systm.h> 57 #include <sys/malloc.h> 58 #include <sys/errno.h> 59 #include <sys/kernel.h> 60 61 #include <vm/vm.h> 62 #include <vm/vm_param.h> 63 64 #include <pci/pcivar.h> 65 #include <pci/pcireg.h> 66 #include <pci/pcibus.h> 67 68 #include <machine/pmap.h> 69 #ifdef __FreeBSD2__ 70 #include <sys/devconf.h> 71 72 struct pci_devconf { 73 struct kern_devconf pdc_kdc; 74 struct pci_info pdc_pi; 75 }; 76 77 static int 78 pci_externalize (struct proc *, struct kern_devconf *, void *, size_t); 79 80 static int 81 pci_internalize (struct proc *, struct kern_devconf *, void *, size_t); 82 #else /* __FreeBSD2__ */ 83 84 /* 85 ** Function prototypes missing in system headers 86 */ 87 88 extern pmap_t pmap_kernel(void); 89 static vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize); 90 #endif /* __FreeBSD2__ */ 91 92 93 /*======================================================== 94 ** 95 ** Autoconfiguration of pci devices. 96 ** 97 ** This is reverse to the isa configuration. 98 ** (1) find a pci device. 99 ** (2) look for a driver. 100 ** 101 **======================================================== 102 */ 103 104 /*-------------------------------------------------------- 105 ** 106 ** The pci devices can be mapped to any address. 107 ** As default we start at the last gigabyte. 108 ** 109 **-------------------------------------------------------- 110 */ 111 112 #ifndef PCI_PMEM_START 113 #define PCI_PMEM_START 0xc0000000 114 #endif 115 116 static vm_offset_t pci_paddr = PCI_PMEM_START; 117 118 /*-------------------------------------------------------- 119 ** 120 ** The pci ports can be mapped to any address. 121 ** As default we start at 0x400 122 ** 123 **-------------------------------------------------------- 124 */ 125 126 #ifndef PCI_PORT_START 127 #define PCI_PORT_START 0xbc00 128 #endif 129 130 static u_short pci_ioaddr = PCI_PORT_START; 131 132 /*-------------------------------------------------------- 133 ** 134 ** The pci device interrupt lines should have been 135 ** assigned by the bios. But if the bios failed to 136 ** to it, we set it. 137 ** 138 **-------------------------------------------------------- 139 */ 140 141 #ifndef PCI_IRQ 142 #define PCI_IRQ 0 143 #endif 144 145 static u_long pci_irq = PCI_IRQ; 146 147 /*--------------------------------------------------------- 148 ** 149 ** pci_configure () 150 ** 151 ** Probe all devices on pci bus and attach them. 152 ** 153 ** May be called more than once. 154 ** Any device is attached only once. 155 ** (Attached devices are remembered in pci_seen.) 156 ** 157 **--------------------------------------------------------- 158 */ 159 160 static void not_supported (pcici_t tag, u_long type); 161 162 static unsigned long pci_seen[NPCI]; 163 164 static int pci_conf_count; 165 166 void pci_configure() 167 { 168 u_char device,last_device; 169 u_short bus; 170 pcici_t tag; 171 pcidi_t type; 172 u_long data; 173 int unit; 174 int pci_mechanism; 175 int pciint; 176 int irq; 177 char* name=0; 178 vm_offset_t old_addr=pci_paddr; 179 u_short old_ioaddr=pci_ioaddr; 180 181 int dvi; 182 struct pci_device *dvp=0; 183 184 #ifdef __FreeBSD2__ 185 struct pci_devconf *pdcp; 186 #endif 187 188 /* 189 ** first check pci bus driver available 190 */ 191 192 if (pcibus_set.ls_length <= 0) 193 return; 194 195 #define pcibus (*((struct pcibus*) pcibus_set.ls_items[0])) 196 /* 197 ** check pci bus present 198 */ 199 200 pci_mechanism = pcibus.pb_mode (); 201 if (!pci_mechanism) return; 202 last_device = pci_mechanism==1 ? 31 : 15; 203 204 /* 205 ** hello world .. 206 */ 207 208 209 for (bus=0;bus<NPCI;bus++) { 210 #ifndef PCI_QUIET 211 printf ("%s%d: scanning device 0..%d, mechanism=%d.\n", 212 pcibus.pb_name, bus, last_device, pci_mechanism); 213 #endif 214 for (device=0; device<=last_device; device ++) { 215 216 if (pci_seen[bus] & (1ul << device)) 217 continue; 218 219 tag = pcibus.pb_tag (bus, device, 0); 220 type = pcibus.pb_read (tag, PCI_ID_REG); 221 222 if ((!type) || (type==0xfffffffful)) continue; 223 224 /* 225 ** lookup device in ioconfiguration: 226 */ 227 228 for (dvi=0; dvi<pcidevice_set.ls_length; dvi++) { 229 dvp = (struct pci_device*) pcidevice_set.ls_items[dvi]; 230 if ((name=(*dvp->pd_probe)(tag, type))) 231 break; 232 dvp = NULL; 233 }; 234 235 if (dvp==NULL) { 236 #ifndef PCI_QUIET 237 if (pci_conf_count) 238 continue; 239 printf("%s%d:%d: ", pcibus.pb_name, bus, device); 240 not_supported (tag, type); 241 #endif 242 continue; 243 }; 244 245 pci_seen[bus] |= (1ul << device); 246 /* 247 ** Get and increment the unit. 248 */ 249 250 unit = (*dvp->pd_count)++; 251 252 /* 253 ** ignore device ? 254 */ 255 256 if (!*name) continue; 257 258 /* 259 ** Announce this device 260 */ 261 262 printf ("%s%d <%s>", dvp->pd_name, unit, name); 263 264 /* 265 ** Get the int pin number (pci interrupt number a-d) 266 ** from the pci configuration space. 267 */ 268 269 data = pcibus.pb_read (tag, PCI_INTERRUPT_REG); 270 pciint = PCI_INTERRUPT_PIN_EXTRACT(data); 271 272 if (pciint) { 273 274 printf (" int %c", 0x60+pciint); 275 276 /* 277 ** If the interrupt line register is not set, 278 ** set it now from PCI_IRQ. 279 */ 280 281 if (!(PCI_INTERRUPT_LINE_EXTRACT(data))) { 282 283 irq = pci_irq & 0x0f; 284 pci_irq >>= 4; 285 286 data = PCI_INTERRUPT_LINE_INSERT(data, irq); 287 printf (" (config)"); 288 pcibus.pb_write (tag, PCI_INTERRUPT_REG, data); 289 }; 290 291 irq = PCI_INTERRUPT_LINE_EXTRACT(data); 292 293 /* 294 ** If it's zero, the isa irq number is unknown, 295 ** and we cannot bind the pci interrupt to isa. 296 */ 297 298 if (irq) 299 printf (" irq %d", irq); 300 else 301 printf (" not bound"); 302 }; 303 304 /* 305 ** enable memory access 306 */ 307 308 data = (pcibus.pb_read (tag, PCI_COMMAND_STATUS_REG) 309 & 0xffff) | PCI_COMMAND_MEM_ENABLE; 310 311 pcibus.pb_write (tag, (u_char) PCI_COMMAND_STATUS_REG, data); 312 313 /* 314 ** show pci slot. 315 */ 316 317 printf (" on pci%d:%d\n", bus, device); 318 319 #ifdef __FreeBSD2__ 320 321 /* 322 ** Allocate a devconf structure 323 */ 324 325 pdcp = (struct pci_devconf *) 326 malloc (sizeof (struct pci_devconf),M_DEVBUF,M_WAITOK); 327 328 /* 329 ** Fill in. 330 ** 331 ** Sorry, this is not yet complete. 332 ** We should, and eventually will, set the 333 ** parent pointer to a pci bus devconf structure, 334 ** and arrange to set the state field dynamically. 335 ** 336 ** But I'll go to vacation today, and after all, 337 ** wasn't there a new feature freeze on Oct 1.? 338 */ 339 340 pdcp -> pdc_pi.pi_bus = bus; 341 pdcp -> pdc_pi.pi_device = device; 342 343 pdcp -> pdc_kdc.kdc_name = dvp->pd_name; 344 pdcp -> pdc_kdc.kdc_unit = unit; 345 346 pdcp -> pdc_kdc.kdc_md.mddc_devtype = MDDT_PCI; 347 348 pdcp -> pdc_kdc.kdc_externalize = pci_externalize; 349 pdcp -> pdc_kdc.kdc_internalize = pci_internalize; 350 351 pdcp -> pdc_kdc.kdc_datalen = PCI_EXTERNAL_LEN; 352 pdcp -> pdc_kdc.kdc_parentdata = &pdcp->pdc_pi; 353 pdcp -> pdc_kdc.kdc_state = DC_UNKNOWN; 354 pdcp -> pdc_kdc.kdc_description = name; 355 356 /* 357 ** And register this device 358 */ 359 360 dev_attach (&pdcp->pdc_kdc); 361 362 #endif /* __FreeBSD2__ */ 363 364 365 /* 366 ** attach device 367 ** may produce additional log messages, 368 ** i.e. when installing subdevices. 369 */ 370 371 (*dvp->pd_attach) (tag, unit); 372 }; 373 }; 374 375 #ifndef PCI_QUIET 376 if (pci_paddr != old_addr) 377 printf ("pci uses physical addresses from 0x%lx to 0x%lx\n", 378 (u_long)PCI_PMEM_START, (u_long)pci_paddr); 379 if (pci_ioaddr != old_ioaddr) 380 printf ("pci devices use ioports from 0x%x to 0x%x\n", 381 (unsigned)PCI_PORT_START, (unsigned)pci_ioaddr); 382 #endif 383 pci_conf_count++; 384 } 385 386 /*----------------------------------------------------------------- 387 ** 388 ** The following functions are provided for the device driver 389 ** to read/write the configuration space. 390 ** 391 ** pci_conf_read(): 392 ** Read a long word from the pci configuration space. 393 ** Requires a tag (from pcitag) and the register 394 ** number (should be a long word alligned one). 395 ** 396 ** pci_conf_write(): 397 ** Writes a long word to the pci configuration space. 398 ** Requires a tag (from pcitag), the register number 399 ** (should be a long word alligned one), and a value. 400 ** 401 **----------------------------------------------------------------- 402 */ 403 404 u_long 405 pci_conf_read (pcici_t tag, u_long reg) 406 { 407 return (pcibus.pb_read (tag, reg)); 408 } 409 410 void 411 pci_conf_write (pcici_t tag, u_long reg, u_long data) 412 { 413 pcibus.pb_write (tag, reg, data); 414 } 415 416 /*----------------------------------------------------------------------- 417 ** 418 ** Map device into port space. 419 ** 420 ** PCI-Specification: 6.2.5.1: address maps 421 ** 422 **----------------------------------------------------------------------- 423 */ 424 425 int pci_map_port (pcici_t tag, u_long reg, u_short* pa) 426 { 427 u_long data; 428 u_short size; 429 430 /* 431 ** sanity check 432 */ 433 434 if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) { 435 printf ("pci_map_port failed: bad register=0x%x\n", 436 (unsigned)reg); 437 return (0); 438 }; 439 440 /* 441 ** get size and type of port 442 ** 443 ** type is in the lowest two bits. 444 ** If device requires 2^n bytes, the next 445 ** n-2 bits are hardwired as 0. 446 */ 447 448 pcibus.pb_write (tag, reg, 0xfffffffful); 449 data = pcibus.pb_read (tag, reg); 450 451 switch (data & 0x03) { 452 453 case PCI_MAP_IO: 454 break; 455 456 default: /* unknown */ 457 printf ("pci_map_port failed: bad port type=0x%x\n", 458 (unsigned) data); 459 return (0); 460 }; 461 462 /* 463 ** get the size 464 */ 465 466 size = -(data & PCI_MAP_IO_ADDRESS_MASK); 467 468 if (!size) return (0); 469 470 /* 471 ** align physical address to virtual size 472 */ 473 474 if ((data = pci_ioaddr % size)) 475 pci_ioaddr += size - data; 476 477 #ifndef PCI_QUIET 478 /* 479 ** display values. 480 */ 481 482 printf ("\treg%d: ioaddr=0x%x size=0x%x\n", 483 (unsigned) reg, (unsigned) pci_ioaddr, (unsigned) size); 484 #endif 485 486 /* 487 ** set device address 488 */ 489 490 pcibus.pb_write (tag, reg, (u_long) pci_ioaddr); 491 492 /* 493 ** return them to the driver 494 */ 495 496 *pa = pci_ioaddr; 497 498 /* 499 ** and don't forget to increment pci_ioaddr 500 */ 501 502 pci_ioaddr += size; 503 504 return (1); 505 } 506 507 /*----------------------------------------------------------------------- 508 ** 509 ** Map device into virtual and physical space 510 ** 511 ** PCI-Specification: 6.2.5.1: address maps 512 ** 513 **----------------------------------------------------------------------- 514 */ 515 516 int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa) 517 { 518 u_long data; 519 vm_size_t vsize; 520 vm_offset_t vaddr; 521 int i; 522 523 /* 524 ** sanity check 525 */ 526 527 if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) { 528 printf ("pci_map_mem failed: bad register=0x%x\n", 529 (unsigned)reg); 530 return (0); 531 }; 532 533 /* 534 ** get size and type of memory 535 ** 536 ** type is in the lowest four bits. 537 ** If device requires 2^n bytes, the next 538 ** n-4 bits are read as 0. 539 */ 540 541 pcibus.pb_write (tag, reg, 0xfffffffful); 542 data = pcibus.pb_read (tag, reg); 543 544 switch (data & 0x0f) { 545 546 case PCI_MAP_MEMORY_TYPE_32BIT: /* 32 bit non cachable */ 547 break; 548 549 default: /* unknown */ 550 printf ("pci_map_mem failed: bad memory type=0x%x\n", 551 (unsigned) data); 552 return (0); 553 }; 554 555 /* 556 ** mask out the type, 557 ** and round up to a page size 558 */ 559 560 vsize = round_page (-(data & PCI_MAP_MEMORY_ADDRESS_MASK)); 561 562 if (!vsize) return (0); 563 564 /* 565 ** align physical address to virtual size 566 */ 567 568 if ((data = pci_paddr % vsize)) 569 pci_paddr += vsize - data; 570 571 vaddr = (vm_offset_t) pmap_mapdev (pci_paddr, vsize); 572 573 574 if (!vaddr) return (0); 575 576 #ifndef PCI_QUIET 577 /* 578 ** display values. 579 */ 580 581 printf ("\treg%d: virtual=0x%lx physical=0x%lx\n", 582 (unsigned) reg, (u_long)vaddr, (u_long)pci_paddr); 583 #endif 584 585 /* 586 ** probe for already mapped device. 587 */ 588 589 for (i=0; i<vsize; i+=4) { 590 u_long* addr = (u_long*) (vaddr+i); 591 data = *addr; 592 if (data != 0xffffffff) { 593 printf ("WARNING: possible address conflict " 594 "at 0x%08x (read: 0x%08x).\n", 595 (unsigned) pci_paddr+i, (unsigned) data); 596 break; 597 }; 598 }; 599 600 /* 601 ** return them to the driver 602 */ 603 604 *va = vaddr; 605 *pa = pci_paddr; 606 607 /* 608 ** set device address 609 */ 610 611 pcibus.pb_write (tag, reg, pci_paddr); 612 613 /* 614 ** and don't forget to increment pci_paddr 615 */ 616 617 pci_paddr += vsize; 618 619 return (1); 620 } 621 622 /*------------------------------------------------------------ 623 ** 624 ** Interface functions for the devconf module. 625 ** 626 **------------------------------------------------------------ 627 */ 628 629 static int 630 pci_externalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t l) 631 { 632 struct pci_externalize_buffer buffer; 633 struct pci_info * pip = kdcp->kdc_parentdata; 634 pcici_t tag; 635 int i; 636 637 if (l < sizeof buffer) { 638 return ENOMEM; 639 }; 640 641 tag = pcibus.pb_tag (pip->pi_bus, pip->pi_device, 0); 642 643 buffer.peb_pci_info = *pip; 644 645 for (i=0; i<PCI_EXT_CONF_LEN; i++) { 646 buffer.peb_config[i] = pcibus.pb_read (tag, i*4); 647 }; 648 649 return copyout(&buffer, u, sizeof buffer); 650 } 651 652 653 static int 654 pci_internalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t s) 655 { 656 return EOPNOTSUPP; 657 } 658 659 /*----------------------------------------------------------------------- 660 ** 661 ** Map pci interrupts to isa interrupts. 662 ** 663 **----------------------------------------------------------------------- 664 */ 665 666 int pci_map_int (pcici_t tag, int(*func)(), void* arg, unsigned* maskptr) 667 { 668 int irq, result; 669 670 irq = PCI_INTERRUPT_LINE_EXTRACT( 671 pcibus.pb_read (tag, PCI_INTERRUPT_REG)); 672 673 if (irq >= 16 || irq <= 0) { 674 printf ("pci_map_int failed: no int line set.\n"); 675 return (0); 676 } 677 678 result = pcibus.pb_regint (tag, func, arg, maskptr); 679 680 if (!result) { 681 printf ("pci_map_int failed.\n"); 682 return (0); 683 }; 684 685 return (1); 686 } 687 688 /*----------------------------------------------------------- 689 ** 690 ** Display of unknown devices. 691 ** 692 **----------------------------------------------------------- 693 */ 694 struct vt { 695 u_short ident; 696 char* name; 697 }; 698 699 static struct vt VendorTable[] = { 700 {0x1002, "ATI TECHNOLOGIES INC"}, 701 {0x1011, "DIGITAL EQUIPMENT CORPORATION"}, 702 {0x101A, "NCR"}, 703 {0x102B, "MATROX"}, 704 {0x1045, "OPTI"}, 705 {0x5333, "S3 INC."}, 706 {0x8086, "INTEL CORPORATION"}, 707 {0,0} 708 }; 709 710 static const char *const majclasses[] = { 711 "old", "storage", "network", "display", 712 "multimedia", "memory", "bridge" 713 }; 714 715 void not_supported (pcici_t tag, u_long type) 716 { 717 u_char reg; 718 u_long data; 719 struct vt * vp; 720 721 /* 722 ** lookup the names. 723 */ 724 725 for (vp=VendorTable; vp->ident; vp++) 726 if (vp->ident == (type & 0xffff)) 727 break; 728 729 /* 730 ** and display them. 731 */ 732 733 if (vp->ident) printf (vp->name); 734 else printf ("vendor=0x%lx", type & 0xffff); 735 736 printf (", device=0x%lx", type >> 16); 737 738 data = (pcibus.pb_read(tag, PCI_CLASS_REG) >> 24) & 0xff; 739 if (data < sizeof(majclasses) / sizeof(majclasses[0])) 740 printf(", class=%s", majclasses[data]); 741 742 printf (" [not supported]\n"); 743 744 for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) { 745 data = pcibus.pb_read (tag, reg); 746 if (!data) continue; 747 switch (data&7) { 748 749 case 1: 750 case 5: 751 printf (" map(%x): io(%lx)\n", 752 reg, data & ~3); 753 break; 754 case 0: 755 printf (" map(%x): mem32(%lx)\n", 756 reg, data & ~7); 757 break; 758 case 2: 759 printf (" map(%x): mem20(%lx)\n", 760 reg, data & ~7); 761 break; 762 case 4: 763 printf (" map(%x): mem64(%lx)\n", 764 reg, data & ~7); 765 break; 766 } 767 } 768 } 769 770 #ifndef __FreeBSD2__ 771 /*----------------------------------------------------------- 772 ** 773 ** Mapping of physical to virtual memory 774 ** 775 **----------------------------------------------------------- 776 */ 777 778 extern vm_map_t kernel_map; 779 780 static vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize) 781 { 782 vm_offset_t vaddr,value; 783 u_long result; 784 785 vaddr = vm_map_min (kernel_map); 786 787 result = vm_map_find (kernel_map, (void*)0, (vm_offset_t) 0, 788 &vaddr, vsize, TRUE); 789 790 if (result != KERN_SUCCESS) { 791 printf (" vm_map_find failed(%d)\n", result); 792 return (0); 793 }; 794 795 /* 796 ** map physical 797 */ 798 799 value = vaddr; 800 while (vsize >= NBPG) { 801 pmap_enter (pmap_kernel(), vaddr, paddr, 802 VM_PROT_READ|VM_PROT_WRITE, TRUE); 803 vaddr += NBPG; 804 paddr += NBPG; 805 vsize -= NBPG; 806 }; 807 return (value); 808 } 809 810 /*------------------------------------------------------------ 811 ** 812 ** Emulate the register_intr() function of FreeBSD 2.0 813 ** 814 ** requires a patch: 815 ** FreeBSD 2.0: "/sys/i386/isa/vector.s" 816 ** 386bsd0.1: "/sys/i386/isa/icu.s" 817 ** 386bsd1.0: Please ask Jesus Monroy Jr. 818 ** 819 **------------------------------------------------------------ 820 */ 821 822 #include <machine/segments.h> 823 824 int pci_int_unit [16]; 825 inthand2_t* (pci_int_hdlr [16]); 826 unsigned int * pci_int_mptr [16]; 827 unsigned int pci_int_count[16]; 828 829 extern void 830 Vpci3(), Vpci4(), Vpci5(), Vpci6(), Vpci7(), Vpci8(), Vpci9(), 831 Vpci10(), Vpci11(), Vpci12(), Vpci13(), Vpci14(), Vpci15(); 832 833 static inthand_t* pci_int_glue[16] = { 834 0, 0, 0, Vpci3, Vpci4, Vpci5, Vpci6, Vpci7, Vpci8, 835 Vpci9, Vpci10, Vpci11, Vpci12, Vpci13, Vpci14, Vpci15 }; 836 837 static int 838 register_intr __P((int intr, int device_id, unsigned int flags, 839 inthand2_t *handler, unsigned int* mptr, int unit)) 840 { 841 if (intr >= 16 || intr <= 2) 842 return (EINVAL); 843 if (pci_int_hdlr [intr]) 844 return (EBUSY); 845 846 pci_int_hdlr [intr] = handler; 847 pci_int_unit [intr] = unit; 848 pci_int_mptr [intr] = mptr; 849 850 setidt(NRSVIDT + intr, pci_int_glue[intr], SDT_SYS386IGT, SEL_KPL); 851 return (0); 852 } 853 #endif /* __FreeBSD2__ */ 854 #endif /* NPCI */ 855