1 /*- 2 * Copyright (c) 1997 Michael Smith 3 * Copyright (c) 1998 Jonathan Lemon 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following 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 AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 /* 32 * Code for dealing with the BIOS in x86 PC systems. 33 */ 34 35 #include "opt_isa.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 #include <sys/bus.h> 42 #include <sys/pcpu.h> 43 #include <vm/vm.h> 44 #include <vm/pmap.h> 45 #include <machine/md_var.h> 46 #include <machine/segments.h> 47 #include <machine/stdarg.h> 48 #include <machine/vmparam.h> 49 #include <machine/pc/bios.h> 50 #ifdef DEV_ISA 51 #include <isa/isavar.h> 52 #include <isa/pnpreg.h> 53 #include <isa/pnpvar.h> 54 #endif 55 56 #define BIOS_START 0xe0000 57 #define BIOS_SIZE 0x20000 58 59 /* exported lookup results */ 60 struct bios32_SDentry PCIbios; 61 struct PnPBIOS_table *PnPBIOStable; 62 63 static u_int bios32_SDCI; 64 65 /* start fairly early */ 66 static void bios32_init(void *junk); 67 SYSINIT(bios32, SI_SUB_CPU, SI_ORDER_ANY, bios32_init, NULL); 68 69 /* 70 * bios32_init 71 * 72 * Locate various bios32 entities. 73 */ 74 static void 75 bios32_init(void *junk) 76 { 77 u_long sigaddr; 78 struct bios32_SDheader *sdh; 79 struct PnPBIOS_table *pt; 80 u_int8_t ck, *cv; 81 int i; 82 char *p; 83 84 /* 85 * BIOS32 Service Directory, PCI BIOS 86 */ 87 88 /* look for the signature */ 89 if ((sigaddr = bios_sigsearch(0, "_32_", 4, 16, 0)) != 0) { 90 91 /* get a virtual pointer to the structure */ 92 sdh = (struct bios32_SDheader *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr); 93 for (cv = (u_int8_t *)sdh, ck = 0, i = 0; i < (sdh->len * 16); i++) { 94 ck += cv[i]; 95 } 96 /* If checksum is OK, enable use of the entrypoint */ 97 if ((ck == 0) && (BIOS_START <= sdh->entry ) && 98 (sdh->entry < (BIOS_START + BIOS_SIZE))) { 99 bios32_SDCI = BIOS_PADDRTOVADDR(sdh->entry); 100 if (bootverbose) { 101 printf("bios32: Found BIOS32 Service Directory header at %p\n", sdh); 102 printf("bios32: Entry = 0x%x (%x) Rev = %d Len = %d\n", 103 sdh->entry, bios32_SDCI, sdh->revision, sdh->len); 104 } 105 106 /* Allow user override of PCI BIOS search */ 107 if (((p = getenv("machdep.bios.pci")) == NULL) || strcmp(p, "disable")) { 108 109 /* See if there's a PCI BIOS entrypoint here */ 110 PCIbios.ident.id = 0x49435024; /* PCI systems should have this */ 111 if (!bios32_SDlookup(&PCIbios) && bootverbose) 112 printf("pcibios: PCI BIOS entry at 0x%x+0x%x\n", PCIbios.base, PCIbios.entry); 113 } 114 if (p != NULL) 115 freeenv(p); 116 } else { 117 printf("bios32: Bad BIOS32 Service Directory\n"); 118 } 119 } 120 121 /* 122 * PnP BIOS 123 * 124 * Allow user override of PnP BIOS search 125 */ 126 if ((((p = getenv("machdep.bios.pnp")) == NULL) || strcmp(p, "disable")) && 127 ((sigaddr = bios_sigsearch(0, "$PnP", 4, 16, 0)) != 0)) { 128 129 /* get a virtual pointer to the structure */ 130 pt = (struct PnPBIOS_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr); 131 for (cv = (u_int8_t *)pt, ck = 0, i = 0; i < pt->len; i++) { 132 ck += cv[i]; 133 } 134 /* If checksum is OK, enable use of the entrypoint */ 135 if (ck == 0) { 136 PnPBIOStable = pt; 137 if (bootverbose) { 138 printf("pnpbios: Found PnP BIOS data at %p\n", pt); 139 printf("pnpbios: Entry = %x:%x Rev = %d.%d\n", 140 pt->pmentrybase, pt->pmentryoffset, pt->version >> 4, pt->version & 0xf); 141 if ((pt->control & 0x3) == 0x01) 142 printf("pnpbios: Event flag at %x\n", pt->evflagaddr); 143 if (pt->oemdevid != 0) 144 printf("pnpbios: OEM ID %x\n", pt->oemdevid); 145 146 } 147 } else { 148 printf("pnpbios: Bad PnP BIOS data checksum\n"); 149 } 150 } 151 if (p != NULL) 152 freeenv(p); 153 if (bootverbose) { 154 /* look for other know signatures */ 155 printf("Other BIOS signatures found:\n"); 156 } 157 } 158 159 /* 160 * bios32_SDlookup 161 * 162 * Query the BIOS32 Service Directory for the service named in (ent), 163 * returns nonzero if the lookup fails. The caller must fill in 164 * (ent->ident), the remainder are populated on a successful lookup. 165 */ 166 int 167 bios32_SDlookup(struct bios32_SDentry *ent) 168 { 169 struct bios_regs args; 170 171 if (bios32_SDCI == 0) 172 return (1); 173 174 args.eax = ent->ident.id; /* set up arguments */ 175 args.ebx = args.ecx = args.edx = 0; 176 bios32(&args, bios32_SDCI, GSEL(GCODE_SEL, SEL_KPL)); 177 if ((args.eax & 0xff) == 0) { /* success? */ 178 ent->base = args.ebx; 179 ent->len = args.ecx; 180 ent->entry = args.edx; 181 ent->ventry = BIOS_PADDRTOVADDR(ent->base + ent->entry); 182 return (0); /* all OK */ 183 } 184 return (1); /* failed */ 185 } 186 187 188 /* 189 * bios_sigsearch 190 * 191 * Search some or all of the BIOS region for a signature string. 192 * 193 * (start) Optional offset returned from this function 194 * (for searching for multiple matches), or NULL 195 * to start the search from the base of the BIOS. 196 * Note that this will be a _physical_ address in 197 * the range 0xe0000 - 0xfffff. 198 * (sig) is a pointer to the byte(s) of the signature. 199 * (siglen) number of bytes in the signature. 200 * (paralen) signature paragraph (alignment) size. 201 * (sigofs) offset of the signature within the paragraph. 202 * 203 * Returns the _physical_ address of the found signature, 0 if the 204 * signature was not found. 205 */ 206 207 u_int32_t 208 bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs) 209 { 210 u_char *sp, *end; 211 212 /* compute the starting address */ 213 if ((start >= BIOS_START) && (start <= (BIOS_START + BIOS_SIZE))) { 214 sp = (char *)BIOS_PADDRTOVADDR(start); 215 } else if (start == 0) { 216 sp = (char *)BIOS_PADDRTOVADDR(BIOS_START); 217 } else { 218 return 0; /* bogus start address */ 219 } 220 221 /* compute the end address */ 222 end = (u_char *)BIOS_PADDRTOVADDR(BIOS_START + BIOS_SIZE); 223 224 /* loop searching */ 225 while ((sp + sigofs + siglen) < end) { 226 227 /* compare here */ 228 if (!bcmp(sp + sigofs, sig, siglen)) { 229 /* convert back to physical address */ 230 return((u_int32_t)BIOS_VADDRTOPADDR(sp)); 231 } 232 sp += paralen; 233 } 234 return(0); 235 } 236 237 /* 238 * do not staticize, used by bioscall.s 239 */ 240 union { 241 struct { 242 u_short offset; 243 u_short segment; 244 } vec16; 245 struct { 246 u_int offset; 247 u_short segment; 248 } vec32; 249 } bioscall_vector; /* bios jump vector */ 250 251 void 252 set_bios_selectors(struct bios_segments *seg, int flags) 253 { 254 struct soft_segment_descriptor ssd = { 255 0, /* segment base address (overwritten) */ 256 0, /* length (overwritten) */ 257 SDT_MEMERA, /* segment type (overwritten) */ 258 0, /* priority level */ 259 1, /* descriptor present */ 260 0, 0, 261 1, /* descriptor size (overwritten) */ 262 0 /* granularity == byte units */ 263 }; 264 union descriptor *p_gdt; 265 266 #ifdef SMP 267 p_gdt = &gdt[PCPU_GET(cpuid) * NGDT]; 268 #else 269 p_gdt = gdt; 270 #endif 271 272 ssd.ssd_base = seg->code32.base; 273 ssd.ssd_limit = seg->code32.limit; 274 ssdtosd(&ssd, &p_gdt[GBIOSCODE32_SEL].sd); 275 276 ssd.ssd_def32 = 0; 277 if (flags & BIOSCODE_FLAG) { 278 ssd.ssd_base = seg->code16.base; 279 ssd.ssd_limit = seg->code16.limit; 280 ssdtosd(&ssd, &p_gdt[GBIOSCODE16_SEL].sd); 281 } 282 283 ssd.ssd_type = SDT_MEMRWA; 284 if (flags & BIOSDATA_FLAG) { 285 ssd.ssd_base = seg->data.base; 286 ssd.ssd_limit = seg->data.limit; 287 ssdtosd(&ssd, &p_gdt[GBIOSDATA_SEL].sd); 288 } 289 290 if (flags & BIOSUTIL_FLAG) { 291 ssd.ssd_base = seg->util.base; 292 ssd.ssd_limit = seg->util.limit; 293 ssdtosd(&ssd, &p_gdt[GBIOSUTIL_SEL].sd); 294 } 295 296 if (flags & BIOSARGS_FLAG) { 297 ssd.ssd_base = seg->args.base; 298 ssd.ssd_limit = seg->args.limit; 299 ssdtosd(&ssd, &p_gdt[GBIOSARGS_SEL].sd); 300 } 301 } 302 303 extern int vm86pa; 304 extern void bios16_jmp(void); 305 306 /* 307 * this routine is really greedy with selectors, and uses 5: 308 * 309 * 32-bit code selector: to return to kernel 310 * 16-bit code selector: for running code 311 * data selector: for 16-bit data 312 * util selector: extra utility selector 313 * args selector: to handle pointers 314 * 315 * the util selector is set from the util16 entry in bios16_args, if a 316 * "U" specifier is seen. 317 * 318 * See <machine/pc/bios.h> for description of format specifiers 319 */ 320 int 321 bios16(struct bios_args *args, char *fmt, ...) 322 { 323 char *p, *stack, *stack_top; 324 va_list ap; 325 int flags = BIOSCODE_FLAG | BIOSDATA_FLAG; 326 u_int i, arg_start, arg_end; 327 pt_entry_t *pte; 328 pd_entry_t *ptd; 329 330 arg_start = 0xffffffff; 331 arg_end = 0; 332 333 /* 334 * Some BIOS entrypoints attempt to copy the largest-case 335 * argument frame (in order to generalise handling for 336 * different entry types). If our argument frame is 337 * smaller than this, the BIOS will reach off the top of 338 * our constructed stack segment. Pad the top of the stack 339 * with some garbage to avoid this. 340 */ 341 stack = (caddr_t)PAGE_SIZE - 32; 342 343 va_start(ap, fmt); 344 for (p = fmt; p && *p; p++) { 345 switch (*p) { 346 case 'p': /* 32-bit pointer */ 347 i = va_arg(ap, u_int); 348 arg_start = min(arg_start, i); 349 arg_end = max(arg_end, i); 350 flags |= BIOSARGS_FLAG; 351 stack -= 4; 352 break; 353 354 case 'i': /* 32-bit integer */ 355 i = va_arg(ap, u_int); 356 stack -= 4; 357 break; 358 359 case 'U': /* 16-bit selector */ 360 flags |= BIOSUTIL_FLAG; 361 /* FALLTHROUGH */ 362 case 'D': /* 16-bit selector */ 363 case 'C': /* 16-bit selector */ 364 stack -= 2; 365 break; 366 367 case 's': /* 16-bit integer passed as an int */ 368 i = va_arg(ap, int); 369 stack -= 2; 370 break; 371 372 default: 373 return (EINVAL); 374 } 375 } 376 377 if (flags & BIOSARGS_FLAG) { 378 if (arg_end - arg_start > ctob(16)) 379 return (EACCES); 380 args->seg.args.base = arg_start; 381 args->seg.args.limit = 0xffff; 382 } 383 384 args->seg.code32.base = (u_int)&bios16_jmp & PG_FRAME; 385 args->seg.code32.limit = 0xffff; 386 387 ptd = (pd_entry_t *)rcr3(); 388 #ifdef PAE 389 if (ptd == IdlePDPT) 390 #else 391 if (ptd == IdlePTD) 392 #endif 393 { 394 /* 395 * no page table, so create one and install it. 396 */ 397 pte = (pt_entry_t *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 398 ptd = (pd_entry_t *)((u_int)IdlePTD + KERNBASE); 399 *ptd = vtophys(pte) | PG_RW | PG_V; 400 } else { 401 /* 402 * this is a user-level page table 403 */ 404 pte = PTmap; 405 } 406 /* 407 * install pointer to page 0. we don't need to flush the tlb, 408 * since there should not be a previous mapping for page 0. 409 */ 410 *pte = (vm86pa - PAGE_SIZE) | PG_RW | PG_V; 411 412 stack_top = stack; 413 va_start(ap, fmt); 414 for (p = fmt; p && *p; p++) { 415 switch (*p) { 416 case 'p': /* 32-bit pointer */ 417 i = va_arg(ap, u_int); 418 *(u_int *)stack = (i - arg_start) | 419 (GSEL(GBIOSARGS_SEL, SEL_KPL) << 16); 420 stack += 4; 421 break; 422 423 case 'i': /* 32-bit integer */ 424 i = va_arg(ap, u_int); 425 *(u_int *)stack = i; 426 stack += 4; 427 break; 428 429 case 'U': /* 16-bit selector */ 430 *(u_short *)stack = GSEL(GBIOSUTIL_SEL, SEL_KPL); 431 stack += 2; 432 break; 433 434 case 'D': /* 16-bit selector */ 435 *(u_short *)stack = GSEL(GBIOSDATA_SEL, SEL_KPL); 436 stack += 2; 437 break; 438 439 case 'C': /* 16-bit selector */ 440 *(u_short *)stack = GSEL(GBIOSCODE16_SEL, SEL_KPL); 441 stack += 2; 442 break; 443 444 case 's': /* 16-bit integer passed as an int */ 445 i = va_arg(ap, int); 446 *(u_short *)stack = i; 447 stack += 2; 448 break; 449 450 default: 451 return (EINVAL); 452 } 453 } 454 455 set_bios_selectors(&args->seg, flags); 456 bioscall_vector.vec16.offset = (u_short)args->entry; 457 bioscall_vector.vec16.segment = GSEL(GBIOSCODE16_SEL, SEL_KPL); 458 459 i = bios16_call(&args->r, stack_top); 460 461 if (pte == PTmap) { 462 *pte = 0; /* remove entry */ 463 } else { 464 *ptd = 0; /* remove page table */ 465 free(pte, M_TEMP); /* ... and free it */ 466 } 467 468 /* 469 * XXX only needs to be invlpg(0) but that doesn't work on the 386 470 */ 471 pmap_invalidate_all(kernel_pmap); 472 473 return (i); 474 } 475 476 #ifdef DEV_ISA 477 /* 478 * PnP BIOS interface; enumerate devices only known to the system 479 * BIOS and save information about them for later use. 480 */ 481 482 struct pnp_sysdev 483 { 484 u_int16_t size; 485 u_int8_t handle; 486 u_int32_t devid; 487 u_int8_t type[3]; 488 u_int16_t attrib; 489 #define PNPATTR_NODISABLE (1<<0) /* can't be disabled */ 490 #define PNPATTR_NOCONFIG (1<<1) /* can't be configured */ 491 #define PNPATTR_OUTPUT (1<<2) /* can be primary output */ 492 #define PNPATTR_INPUT (1<<3) /* can be primary input */ 493 #define PNPATTR_BOOTABLE (1<<4) /* can be booted from */ 494 #define PNPATTR_DOCK (1<<5) /* is a docking station */ 495 #define PNPATTR_REMOVEABLE (1<<6) /* device is removeable */ 496 #define PNPATTR_CONFIG_STATIC (0) 497 #define PNPATTR_CONFIG_DYNAMIC (1) 498 #define PNPATTR_CONFIG_DYNONLY (3) 499 #define PNPATTR_CONFIG(a) (((a) >> 7) & 0x3) 500 /* device-specific data comes here */ 501 u_int8_t devdata[0]; 502 } __packed; 503 504 /* We have to cluster arguments within a 64k range for the bios16 call */ 505 struct pnp_sysdevargs 506 { 507 u_int16_t next; 508 struct pnp_sysdev node; 509 }; 510 511 /* 512 * This function is called after the bus has assigned resource 513 * locations for a logical device. 514 */ 515 static void 516 pnpbios_set_config(void *arg, struct isa_config *config, int enable) 517 { 518 } 519 520 /* 521 * Quiz the PnP BIOS, build a list of PNP IDs and resource data. 522 */ 523 static void 524 pnpbios_identify(driver_t *driver, device_t parent) 525 { 526 struct PnPBIOS_table *pt = PnPBIOStable; 527 struct bios_args args; 528 struct pnp_sysdev *pd; 529 struct pnp_sysdevargs *pda; 530 u_int16_t ndevs, bigdev; 531 int error, currdev; 532 u_int8_t *devnodebuf, tag; 533 u_int32_t *devid, *compid; 534 int idx, left; 535 device_t dev; 536 537 /* no PnP BIOS information */ 538 if (pt == NULL) 539 return; 540 541 /* ACPI already active */ 542 if (devclass_get_softc(devclass_find("ACPI"), 0) != NULL) 543 return; 544 545 /* get count of PnP devices */ 546 bzero(&args, sizeof(args)); 547 args.seg.code16.base = BIOS_PADDRTOVADDR(pt->pmentrybase); 548 args.seg.code16.limit = 0xffff; /* XXX ? */ 549 args.seg.data.base = BIOS_PADDRTOVADDR(pt->pmdataseg); 550 args.seg.data.limit = 0xffff; 551 args.entry = pt->pmentryoffset; 552 553 if ((error = bios16(&args, PNP_COUNT_DEVNODES, &ndevs, &bigdev)) || (args.r.eax & 0xff)) 554 printf("pnpbios: error %d/%x getting device count/size limit\n", error, args.r.eax); 555 ndevs &= 0xff; /* clear high byte garbage */ 556 if (bootverbose) 557 printf("pnpbios: %d devices, largest %d bytes\n", ndevs, bigdev); 558 559 devnodebuf = malloc(bigdev + (sizeof(struct pnp_sysdevargs) - sizeof(struct pnp_sysdev)), 560 M_DEVBUF, M_NOWAIT); 561 pda = (struct pnp_sysdevargs *)devnodebuf; 562 pd = &pda->node; 563 564 for (currdev = 0, left = ndevs; (currdev != 0xff) && (left > 0); left--) { 565 566 bzero(pd, bigdev); 567 pda->next = currdev; 568 /* get current configuration */ 569 if ((error = bios16(&args, PNP_GET_DEVNODE, &pda->next, &pda->node, 1))) { 570 printf("pnpbios: error %d making BIOS16 call\n", error); 571 break; 572 } 573 if ((error = (args.r.eax & 0xff))) { 574 if (bootverbose) 575 printf("pnpbios: %s 0x%x fetching node %d\n", error & 0x80 ? "error" : "warning", error, currdev); 576 if (error & 0x80) 577 break; 578 } 579 currdev = pda->next; 580 if (pd->size < sizeof(struct pnp_sysdev)) { 581 printf("pnpbios: bogus system node data, aborting scan\n"); 582 break; 583 } 584 585 /* 586 * If we are in APIC_IO mode, we should ignore the ISA PIC if it 587 * shows up. Likewise, in !APIC_IO mode, we should ignore the 588 * APIC (less important). 589 * This is significant because the ISA PIC will claim IRQ 2 (which 590 * it uses for chaining), while in APIC mode this is a valid IRQ 591 * available for general use. 592 */ 593 #ifdef APIC_IO 594 if (!strcmp(pnp_eisaformat(pd->devid), "PNP0000")) /* ISA PIC */ 595 continue; 596 #else 597 if (!strcmp(pnp_eisaformat(pd->devid), "PNP0003")) /* APIC */ 598 continue; 599 #endif 600 601 /* Add the device and parse its resources */ 602 dev = BUS_ADD_CHILD(parent, ISA_ORDER_PNP, NULL, -1); 603 isa_set_vendorid(dev, pd->devid); 604 isa_set_logicalid(dev, pd->devid); 605 /* 606 * It appears that some PnP BIOS doesn't allow us to re-enable 607 * the embedded system device once it is disabled. We shall 608 * mark all system device nodes as "cannot be disabled", regardless 609 * of actual settings in the device attribute byte. 610 * XXX 611 isa_set_configattr(dev, 612 ((pd->attrib & PNPATTR_NODISABLE) ? 0 : ISACFGATTR_CANDISABLE) | 613 ((!(pd->attrib & PNPATTR_NOCONFIG) && 614 PNPATTR_CONFIG(pd->attrib) != PNPATTR_CONFIG_STATIC) 615 ? ISACFGATTR_DYNAMIC : 0)); 616 */ 617 isa_set_configattr(dev, 618 (!(pd->attrib & PNPATTR_NOCONFIG) && 619 PNPATTR_CONFIG(pd->attrib) != PNPATTR_CONFIG_STATIC) 620 ? ISACFGATTR_DYNAMIC : 0); 621 ISA_SET_CONFIG_CALLBACK(parent, dev, pnpbios_set_config, 0); 622 pnp_parse_resources(dev, &pd->devdata[0], 623 pd->size - sizeof(struct pnp_sysdev), 0); 624 if (!device_get_desc(dev)) 625 device_set_desc_copy(dev, pnp_eisaformat(pd->devid)); 626 627 /* Find device IDs */ 628 devid = &pd->devid; 629 compid = NULL; 630 631 /* look for a compatible device ID too */ 632 left = pd->size - sizeof(struct pnp_sysdev); 633 idx = 0; 634 while (idx < left) { 635 tag = pd->devdata[idx++]; 636 if (PNP_RES_TYPE(tag) == 0) { 637 /* Small resource */ 638 switch (PNP_SRES_NUM(tag)) { 639 case PNP_TAG_COMPAT_DEVICE: 640 compid = (u_int32_t *)(pd->devdata + idx); 641 if (bootverbose) 642 printf("pnpbios: node %d compat ID 0x%08x\n", pd->handle, *compid); 643 /* FALLTHROUGH */ 644 case PNP_TAG_END: 645 idx = left; 646 break; 647 default: 648 idx += PNP_SRES_LEN(tag); 649 break; 650 } 651 } else 652 /* Large resource, skip it */ 653 idx += *(u_int16_t *)(pd->devdata + idx) + 2; 654 } 655 if (bootverbose) { 656 printf("pnpbios: handle %d device ID %s (%08x)", 657 pd->handle, pnp_eisaformat(*devid), *devid); 658 if (compid != NULL) 659 printf(" compat ID %s (%08x)", 660 pnp_eisaformat(*compid), *compid); 661 printf("\n"); 662 } 663 } 664 } 665 666 static device_method_t pnpbios_methods[] = { 667 /* Device interface */ 668 DEVMETHOD(device_identify, pnpbios_identify), 669 670 { 0, 0 } 671 }; 672 673 static driver_t pnpbios_driver = { 674 "pnpbios", 675 pnpbios_methods, 676 1, /* no softc */ 677 }; 678 679 static devclass_t pnpbios_devclass; 680 681 DRIVER_MODULE(pnpbios, isa, pnpbios_driver, pnpbios_devclass, 0, 0); 682 #endif /* DEV_ISA */ 683