The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/i386/bios.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 7a040f9cd2d557b59c7a43cb298187d6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.