Home | History | Annotate | Line # | Download | only in pnpbios
pnpbios.c revision 1.10
      1 /* $NetBSD: pnpbios.c,v 1.10 2000/02/20 21:42:26 soren Exp $ */
      2 /*
      3  * Copyright (c) 1999
      4  * 	Matthias Drochner.  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 /*
     29  * PnP BIOS documentation is available at the following locations.
     30  *
     31  * http://www.microsoft.com/hwdev/download/respec/pnpbios.zip
     32  * http://www.microsoft.com/hwdev/download/respec/biosclar.zip
     33  * http://www.microsoft.com/hwdev/download/respec/devids.txt
     34  */
     35 
     36 #include <sys/param.h>
     37 #include <sys/systm.h>
     38 #include <sys/device.h>
     39 #include <sys/malloc.h>
     40 #include <dev/isa/isareg.h>
     41 #include <machine/isa_machdep.h>
     42 #include <machine/segments.h>
     43 #include <vm/vm.h>
     44 #include <vm/vm_kern.h>
     45 
     46 #include <arch/i386/pnpbios/pnpbiosvar.h>
     47 
     48 #include "opt_pnpbiosverbose.h"
     49 #include "isadma.h"
     50 #include "locators.h"
     51 
     52 struct pnpbios_softc {
     53 	struct device sc_dev;
     54 	isa_chipset_tag_t sc_ic;
     55 };
     56 
     57 static caddr_t pnpbios_find __P((void));
     58 static int pnpbios_match __P((struct device *, struct cfdata *, void *));
     59 static void pnpbios_attach __P((struct device *, struct device *, void *));
     60 static void pnpbios_printres __P((struct pnpresources *));
     61 static int pnpbios_print __P((void *, const char *));
     62 static int pnpbios_getnumnodes __P((int *, size_t *));
     63 static int pnpbios_getnode __P((int, int *, unsigned char *, size_t));
     64 static void eisaid_to_string __P((unsigned char *, char *));
     65 static void pnpbios_attachnode __P((struct pnpbios_softc *, int,
     66 				    unsigned char *, size_t));
     67 static int pnp_scan __P((unsigned char **, size_t, struct pnpresources *, int));
     68 
     69 static int pnpbios_submatch __P((struct device *, struct cfdata *, void *));
     70 
     71 extern int pnpbioscall __P((int));
     72 
     73 struct cfattach pnpbios_ca = {
     74 	sizeof(struct pnpbios_softc), pnpbios_match, pnpbios_attach
     75 };
     76 
     77 /*
     78  * Private stack and return value buffer. Spec (1.0a, ch. 4.3) says that
     79  * 1024 bytes must be available to the BIOS function.
     80  */
     81 #define PNPBIOS_BUFSIZE 4096
     82 
     83 int pnpbios_enabled = 1;
     84 size_t pnpbios_entry;
     85 caddr_t pnpbios_scratchbuf;
     86 
     87 /*
     88  * There can be only one of these, and the i386 ISA code needs to
     89  * reference this.
     90  */
     91 struct pnpbios_softc *pnpbios_softc;
     92 
     93 #define PNPBIOS_SIGNATURE ('$' | ('P' << 8) | ('n' << 16) | ('P' << 24))
     94 
     95 static caddr_t
     96 pnpbios_find()
     97 {
     98 	caddr_t p, c;
     99 	unsigned char cksum;
    100 	size_t structlen;
    101 
    102 	for (p = (caddr_t)ISA_HOLE_VADDR(0xf0000);
    103 	     p <= (caddr_t)ISA_HOLE_VADDR(0xffff0);
    104 	     p += 16) {
    105 		if (*(int *)p != PNPBIOS_SIGNATURE)
    106 			continue;
    107 		structlen = *(unsigned char *)(p + 5);
    108 		if ((structlen < 0x21) ||
    109 		    ((p + structlen - 1) > (caddr_t)ISA_HOLE_VADDR(0xfffff)))
    110 			continue;
    111 
    112 		cksum = 0;
    113 		for (c = p; c < p + structlen; c++)
    114 			cksum += *(unsigned char *)c;
    115 		if (cksum != 0)
    116 			continue;
    117 
    118 		if (*(char *)(p + 4) != 0x10) {
    119 			printf("unknown version %x\n", *(char *)(p + 4));
    120 			continue;
    121 		}
    122 
    123 		return (p);
    124 	}
    125 
    126 	return (0);
    127 }
    128 
    129 int
    130 pnpbios_probe()
    131 {
    132 
    133 	return (pnpbios_find() != 0);
    134 }
    135 
    136 static int
    137 pnpbios_match(parent, match, aux)
    138 	struct device *parent;
    139 	struct cfdata *match;
    140 	void *aux;
    141 {
    142 	struct pnpbios_attach_args *paa = aux;
    143 
    144 	/* These are not the droids you're looking for. */
    145 	if (strcmp(paa->paa_busname, "pnpbios") != 0)
    146 		return (0);
    147 
    148 	/* There can be only one! */
    149 	if (pnpbios_softc != NULL)
    150 		return (0);
    151 
    152 	return (pnpbios_enabled);
    153 }
    154 
    155 static caddr_t mapit __P((u_long, u_long, int));
    156 
    157 static caddr_t
    158 mapit(addr, len, prot)
    159 	u_long addr, len;
    160 	int prot;
    161 {
    162 	u_long startpa, pa, endpa;
    163 	vaddr_t startva, va;
    164 
    165 	pa = startpa = i386_trunc_page(addr);
    166 	endpa = i386_round_page(addr + len);
    167 
    168 	va = startva = uvm_km_valloc(kernel_map, endpa - startpa);
    169 	if (!startva)
    170 		return (0);
    171 	for (; pa < endpa; pa += NBPG, va += NBPG)
    172 		pmap_kenter_pa(va, pa, prot);
    173 
    174 	return ((caddr_t)(startva + (addr - startpa)));
    175 }
    176 
    177 static void
    178 pnpbios_attach(parent, self, aux)
    179 	struct device *parent, *self;
    180 	void *aux;
    181 {
    182 	struct pnpbios_softc *sc = (struct pnpbios_softc *)self;
    183 	struct pnpbios_attach_args *paa = aux;
    184 	caddr_t p;
    185 	unsigned int codepbase, datapbase;
    186 	caddr_t codeva, datava;
    187 	extern char pnpbiostramp[], epnpbiostramp[];
    188 	int res, num, i, size, idx;
    189 	unsigned char *buf;
    190 
    191 	pnpbios_softc = sc;
    192 	sc->sc_ic = paa->paa_ic;
    193 
    194 #if NISADMA > 0
    195 	isa_dmainit(sc->sc_ic, I386_BUS_SPACE_IO, &isa_bus_dma_tag, self);
    196 #endif
    197 
    198 	p = pnpbios_find();
    199 	if (!p)
    200 		panic("pnpbios_attach: disappeared");
    201 
    202 	codepbase = *(unsigned int *)(p + 0x13);
    203 	datapbase = *(unsigned int *)(p + 0x1d);
    204 	pnpbios_entry = *(unsigned short *)(p + 0x11);
    205 
    206 #ifdef PNPBIOSVERBOSE
    207 	printf(": code %x, data %x, entry %x\n%s",
    208 		codepbase, datapbase, pnpbios_entry, self->dv_xname);
    209 #endif
    210 
    211 	codeva = mapit(codepbase, 0x10000,
    212 		VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
    213 	datava = mapit(datapbase, 0x10000,
    214 		VM_PROT_READ | VM_PROT_WRITE);
    215 	if (codeva == 0 || datava == 0) {
    216 		printf("no vm for mapping\n");
    217 		return;
    218 	}
    219 	pnpbios_scratchbuf = malloc(PNPBIOS_BUFSIZE, M_DEVBUF, M_NOWAIT);
    220 
    221 	setsegment(&gdt[GPNPBIOSCODE_SEL].sd, codeva, 0xffff,
    222 		   SDT_MEMERA, SEL_KPL, 0, 0);
    223 	setsegment(&gdt[GPNPBIOSDATA_SEL].sd, datava, 0xffff,
    224 		   SDT_MEMRWA, SEL_KPL, 0, 0);
    225 	setsegment(&gdt[GPNPBIOSSCRATCH_SEL].sd,
    226 		   pnpbios_scratchbuf, PNPBIOS_BUFSIZE - 1,
    227 		   SDT_MEMRWA, SEL_KPL, 0, 0);
    228 	setsegment(&gdt[GPNPBIOSTRAMP_SEL].sd,
    229 		   pnpbiostramp, epnpbiostramp - pnpbiostramp - 1,
    230 		   SDT_MEMERA, SEL_KPL, 1, 0);
    231 
    232 	res = pnpbios_getnumnodes(&num, &size);
    233 	if (res) {
    234 		printf("pnpbios_getnumnodes: error %d\n", res);
    235 		return;
    236 	}
    237 
    238 	printf(": %d nodes, max len %d\n", num, size);
    239 	buf = malloc(size, M_DEVBUF, M_NOWAIT);
    240 
    241 	idx = 0;
    242 	for (i = 0; i < num && idx != 0xff; i++) {
    243 		int node = idx;
    244 		res = pnpbios_getnode(1, &idx, buf, size);
    245 		if (res) {
    246 			printf("pnpbios_getnode: error %d\n", res);
    247 			continue;
    248 		}
    249 		if (buf[2] != node)
    250 			printf("node idx: called %d, got %d\n", node, buf[2]);
    251 		pnpbios_attachnode(sc, node, buf, buf[0] + (buf[1] << 8));
    252 	}
    253 	if (i != num)
    254 		printf("got only %d nodes\n", i);
    255 	if (idx != 0xff)
    256 		printf("last idx=%x\n", idx);
    257 
    258 	free(buf, M_DEVBUF);
    259 }
    260 
    261 static int
    262 pnpbios_getnumnodes(nump, sizep)
    263 	int *nump;
    264 	size_t *sizep;
    265 {
    266 	int res;
    267 	short *help = (short *)(pnpbios_scratchbuf + PNPBIOS_BUFSIZE);
    268 
    269 	*--help = GSEL(GPNPBIOSDATA_SEL, SEL_KPL);
    270 	*--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
    271 	*--help = 2; /* buffer offset for node size */
    272 	*--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
    273 	*--help = 0; /* buffer offset for numnodes */
    274 	*--help = 0; /* GET_NUM_NODES */
    275 
    276 	res = pnpbioscall(((caddr_t)help) - pnpbios_scratchbuf);
    277 	if (res)
    278 		return (res);
    279 
    280 	*nump = *(short *)(pnpbios_scratchbuf + 0);
    281 	*sizep = *(short *)(pnpbios_scratchbuf + 2);
    282 	return (0);
    283 }
    284 
    285 static int
    286 pnpbios_getnode(flags, idxp, buf, len)
    287 	int flags;
    288 	int *idxp;
    289 	unsigned char *buf;
    290 	size_t len;
    291 {
    292 	int res;
    293 	short *help = (short *)(pnpbios_scratchbuf + PNPBIOS_BUFSIZE);
    294 
    295 	*--help = GSEL(GPNPBIOSDATA_SEL, SEL_KPL);
    296 	*--help = flags;
    297 	*--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
    298 	*--help = 2; /* buffer offset for node data */
    299 	*--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
    300 	*--help = 0; /* buffer offset for index in/out */
    301 	*--help = 1; /* GET_DEVICE_NODE */
    302 
    303 	*(short *)(pnpbios_scratchbuf + 0) = *idxp;
    304 
    305 	res = pnpbioscall(((caddr_t)help) - pnpbios_scratchbuf);
    306 	if (res)
    307 		return (res);
    308 
    309 	*idxp = *(short *)(pnpbios_scratchbuf + 0);
    310 	bcopy(pnpbios_scratchbuf + 2, buf, len);
    311 	return (0);
    312 }
    313 
    314 static void
    315 eisaid_to_string(id, s)
    316 	unsigned char *id;
    317 	char *s;
    318 {
    319 	static char hex[] = "0123456789ABCDEF";
    320 
    321 	*s++ = 'A' + (id[0] >> 2) - 1;
    322 	*s++ = 'A' + ((id[0] & 3) << 3) + (id[1] >> 5) - 1;
    323 	*s++ = 'A' + (id[1] & 0x1f) - 1;
    324 	*s++ = hex[id[2] >> 4];
    325 	*s++ = hex[id[2] & 0x0f];
    326 	*s++ = hex[id[3] >> 4];
    327 	*s++ = hex[id[3] & 0x0f];
    328 	*s = '\0';
    329 }
    330 
    331 static void
    332 pnpbios_printres(r)
    333 	struct pnpresources *r;
    334 {
    335 	struct pnp_mem *mem;
    336 	struct pnp_io *io;
    337 	struct pnp_irq *irq;
    338 	struct pnp_dma *dma;
    339 	int p = 0;
    340 
    341 	mem = SIMPLEQ_FIRST(&r->mem);
    342 	if (mem) {
    343 		printf("mem");
    344 		do {
    345 			printf(" %x", mem->minbase);
    346 			if (mem->len > 1)
    347 				printf("-%x", mem->minbase + mem->len - 1);
    348 		} while ((mem = SIMPLEQ_NEXT(mem, next)));
    349 		p++;
    350 	}
    351 	io = SIMPLEQ_FIRST(&r->io);
    352 	if (io) {
    353 		if (p++)
    354 			printf(", ");
    355 		printf("io");
    356 		do {
    357 			printf(" %x", io->minbase);
    358 			if (io->len > 1)
    359 				printf("-%x", io->minbase + io->len - 1);
    360 		} while ((io = SIMPLEQ_NEXT(io, next)));
    361 	}
    362 	irq = SIMPLEQ_FIRST(&r->irq);
    363 	if (irq) {
    364 		if (p++)
    365 			printf(", ");
    366 		printf("irq");
    367 		do {
    368 			printf(" %d", ffs(irq->mask) - 1);
    369 		} while ((irq = SIMPLEQ_NEXT(irq, next)));
    370 	}
    371 	dma = SIMPLEQ_FIRST(&r->dma);
    372 	if (dma) {
    373 		if (p)
    374 			printf(", ");
    375 		printf("dma");
    376 		do {
    377 			printf(" %d", ffs(dma->mask) - 1);
    378 		} while ((dma = SIMPLEQ_NEXT(dma, next)));
    379 	}
    380 }
    381 
    382 static int
    383 pnpbios_print(aux, pnp)
    384 	void *aux;
    385 	const char *pnp;
    386 {
    387 	struct pnpbiosdev_attach_args *aa = aux;
    388 
    389 	if (pnp)
    390 		return (QUIET);
    391 
    392 	printf(" index %d (%s", aa->idx, aa->primid);
    393 	if (aa->resc->longname)
    394 		printf(", %s", aa->resc->longname);
    395 	if (aa->idstr != aa->primid)
    396 		printf(", attached as %s", aa->idstr);
    397 	printf(")");
    398 
    399 	return (0);
    400 }
    401 
    402 void
    403 pnpbios_print_devres(dev, aa)
    404 	struct device *dev;
    405 	struct pnpbiosdev_attach_args *aa;
    406 {
    407 
    408 	printf("%s: ", dev->dv_xname);
    409 	pnpbios_printres(aa->resc);
    410 	printf("\n");
    411 }
    412 
    413 static int
    414 pnpbios_submatch(parent, match, aux)
    415 	struct device *parent;
    416 	struct cfdata *match;
    417 	void *aux;
    418 {
    419 	struct pnpbiosdev_attach_args *aa = aux;
    420 
    421 	if (match->cf_loc[PNPBIOSCF_INDEX] != PNPBIOSCF_INDEX_DEFAULT &&
    422 	    match->cf_loc[PNPBIOSCF_INDEX] != aa->idx)
    423 		return (0);
    424 
    425 	return ((*match->cf_attach->ca_match)(parent, match, aux));
    426 }
    427 
    428 static void
    429 pnpbios_attachnode(sc, idx, buf, len)
    430 	struct pnpbios_softc *sc;
    431 	int idx;
    432 	unsigned char *buf;
    433 	size_t len;
    434 {
    435 	char idstr[8];
    436 	unsigned char *p;
    437 	int res;
    438 	struct pnpresources r, s;
    439 	int i;
    440 	struct pnpbiosdev_attach_args aa;
    441 	struct pnp_compatid *compatid;
    442 
    443 	eisaid_to_string(buf + 3, idstr);
    444 	p = buf + 12;
    445 
    446 	res = pnp_scan(&p, len - 12, &r, 0);
    447 	if (res < 0) {
    448 		printf("error in config data\n");
    449 		goto dump;
    450 	}
    451 
    452 	/*
    453 	 * the following is consistency check only for now
    454 	 */
    455 	res = pnp_scan(&p, len - (p - buf), &s, 0);
    456 	if (res < 0) {
    457 		printf("error in possible configuration\n");
    458 		goto dump;
    459 	}
    460 
    461 	res = pnp_scan(&p, len - (p - buf), &s, 0);
    462 	if (res < 0) {
    463 		printf("error in compatible ID\n");
    464 		goto dump;
    465 	}
    466 
    467 	if (p != buf + len) {
    468 		printf("%s: length mismatch in node %d: used %d of %d Bytes\n",
    469 		       sc->sc_dev.dv_xname, idx, p - buf, len);
    470 		if (p > buf + len) {
    471 			/* XXX shouldn't happen - pnp_scan should catch it */
    472 			goto dump;
    473 		}
    474 		/* Crappy BIOS: Buffer is not fully used. Be generous. */
    475 	}
    476 
    477 	if (r.nummem + r.numio + r.numirq + r.numdma == 0) {
    478 #ifdef PNPBIOSVERBOSE
    479 		printf("%s", idstr);
    480 		if (r.longname)
    481 			printf(", %s", r.longname);
    482 		compatid = s.compatids;
    483 		while (compatid) {
    484 			printf(", %s", compatid->idstr);
    485 			compatid = compatid->next;
    486 		}
    487 		printf(" at %s index %d disabled\n", sc->sc_dev.dv_xname, idx);
    488 #endif
    489 		return;
    490 	}
    491 
    492 	aa.pbt = 0; /* XXX placeholder */
    493 	aa.idx = idx;
    494 	aa.resc = &r;
    495 	aa.ic = sc->sc_ic;
    496 	aa.primid = idstr;
    497 
    498 	/* first try the specific device ID */
    499 	aa.idstr = idstr;
    500 	if (config_found_sm((struct device *)sc, &aa, pnpbios_print,
    501 	    pnpbios_submatch))
    502 		return;
    503 
    504 	/* if no driver was found, try compatible IDs */
    505 	compatid = s.compatids;
    506 	while (compatid) {
    507 		aa.idstr = compatid->idstr;
    508 		if (config_found_sm((struct device *)sc, &aa, pnpbios_print,
    509 		    pnpbios_submatch))
    510 			return;
    511 		compatid = compatid->next;
    512 	}
    513 
    514 #ifdef PNPBIOSVERBOSE
    515 	printf("%s", idstr);
    516 	if (r.longname)
    517 		printf(", %s", r.longname);
    518 	compatid = s.compatids;
    519 	while (compatid) {
    520 		printf(", %s", compatid->idstr);
    521 		compatid = compatid->next;
    522 	}
    523 	printf(" (");
    524 	pnpbios_printres(&r);
    525 	printf(") at %s index %d ignored\n", sc->sc_dev.dv_xname, idx);
    526 #endif
    527 
    528 	return;
    529 
    530 	/* XXX should free ressource lists */
    531 
    532 dump:
    533 	for (i = 0; i < len; i++)
    534 		printf(" %02x", buf[i]);
    535 	printf("\n");
    536 }
    537 
    538 static int pnp_compatid __P((struct pnpresources *, unsigned char *, size_t));
    539 static int pnp_newirq __P((struct pnpresources *, unsigned char *, size_t));
    540 static int pnp_newdma __P((struct pnpresources *, unsigned char *, size_t));
    541 static int pnp_newioport __P((struct pnpresources *, unsigned char *, size_t));
    542 static int pnp_newfixedioport __P((struct pnpresources *, unsigned char *, size_t));
    543 
    544 /*
    545  * small ressource types (beginning with 1)
    546  */
    547 static struct{
    548 	int (*handler) __P((struct pnpresources *, unsigned char *, size_t));
    549 	int minlen, maxlen;
    550 } smallrescs[] = {
    551 	{0, 2, 2}, /* PnP version number */
    552 	{0, 5, 6}, /* logical device id */
    553 	{pnp_compatid, 4, 4}, /* compatible device id */
    554 	{pnp_newirq, 2, 3}, /* irq  descriptor */
    555 	{pnp_newdma, 2, 2}, /* dma  descriptor */
    556 	{0, 0, 1}, /* start dep */
    557 	{0, 0, 0}, /* end dep */
    558 	{pnp_newioport, 7, 7}, /* io descriptor */
    559 	{pnp_newfixedioport, 3, 3}, /* fixed io descriptor */
    560 	{0, -1, -1}, /* reserved */
    561 	{0, -1, -1},
    562 	{0, -1, -1},
    563 	{0, -1, -1},
    564 	{0, 1, 7}, /* vendor defined */
    565 	{0, 1, 1} /* end */
    566 };
    567 
    568 #define NEXTBYTE(p) (*(p)++)
    569 
    570 static int
    571 pnp_scan(bufp, maxlen, r, in_depends)
    572 	unsigned char **bufp;
    573 	size_t maxlen;
    574 	struct pnpresources *r;
    575 	int in_depends;
    576 {
    577 	unsigned char *p = *bufp;
    578 	int tag, type, len;
    579 	char *idstr;
    580 	int i;
    581 	struct pnp_mem *mem;
    582 
    583 	bzero(r, sizeof(*r));
    584 	SIMPLEQ_INIT(&r->mem);
    585 	SIMPLEQ_INIT(&r->io);
    586 	SIMPLEQ_INIT(&r->irq);
    587 	SIMPLEQ_INIT(&r->dma);
    588 
    589 	for (;;) {
    590 		if (p >= *bufp + maxlen) {
    591 			printf("pnp_scanresources: end of buffer\n");
    592 			return (-1);
    593 		}
    594 		tag = NEXTBYTE(p);
    595 
    596 		if (tag & 0x80) { /* long tag */
    597 			type = tag & 0x7f;
    598 			len = NEXTBYTE(p);
    599 			len |= NEXTBYTE(p) << 8;
    600 
    601 			switch (type) {
    602 			case 0x01: /* memory descriptor */
    603 				if (len != 9) {
    604 					printf("pnp_scan: bad mem desc\n");
    605 					return (-1);
    606 				}
    607 
    608 				mem = malloc(sizeof(struct pnp_mem),
    609 					     M_DEVBUF, M_WAITOK);
    610 				mem->flags = NEXTBYTE(p);
    611 				mem->minbase = NEXTBYTE(p) << 8;
    612 				mem->minbase |= NEXTBYTE(p) << 16;
    613 				mem->maxbase = NEXTBYTE(p) << 8;
    614 				mem->maxbase |= NEXTBYTE(p) << 16;
    615 				mem->align = NEXTBYTE(p);
    616 				mem->align |= NEXTBYTE(p) << 8;
    617 				if (mem->align == 0)
    618 					mem->align = 0x10000;
    619 				mem->len = NEXTBYTE(p) << 8;
    620 				mem->len |= NEXTBYTE(p) << 16;
    621 				goto gotmem;
    622 			case 0x02:
    623 				if (in_depends)
    624 					printf("ID in dep?\n");
    625 				idstr = malloc(len + 1, M_DEVBUF, M_NOWAIT);
    626 				for (i = 0; i < len; i++)
    627 					idstr[i] = NEXTBYTE(p);
    628 				idstr[len] = '\0';
    629 				if (idstr[0] == '\0') {
    630 					/* disabled device */
    631 					free(idstr, M_DEVBUF);
    632 					break;
    633 				}
    634 				r->longname = idstr;
    635 				break;
    636 			case 0x05:  /* 32bit memory descriptor */
    637 				if (len != 17) {
    638 					printf("pnp_scan: bad mem32 desc\n");
    639 					return (-1);
    640 				}
    641 
    642 				mem = malloc(sizeof(struct pnp_mem),
    643 					     M_DEVBUF, M_WAITOK);
    644 				mem->flags = NEXTBYTE(p);
    645 				mem->minbase = NEXTBYTE(p);
    646 				mem->minbase |= NEXTBYTE(p) << 8;
    647 				mem->minbase |= NEXTBYTE(p) << 16;
    648 				mem->minbase |= NEXTBYTE(p) << 24;
    649 				mem->maxbase = NEXTBYTE(p);
    650 				mem->maxbase |= NEXTBYTE(p) << 8;
    651 				mem->maxbase |= NEXTBYTE(p) << 16;
    652 				mem->maxbase |= NEXTBYTE(p) << 24;
    653 				mem->align = NEXTBYTE(p);
    654 				mem->align |= NEXTBYTE(p) << 8;
    655 				mem->align |= NEXTBYTE(p) << 16;
    656 				mem->align |= NEXTBYTE(p) << 24;
    657 				mem->len = NEXTBYTE(p);
    658 				mem->len |= NEXTBYTE(p) << 8;
    659 				mem->len |= NEXTBYTE(p) << 16;
    660 				mem->len |= NEXTBYTE(p) << 24;
    661 				goto gotmem;
    662 			case 0x06: /* 32bit fixed memory descriptor */
    663 				if (len != 9) {
    664 					printf("pnp_scan: bad mem32 desc\n");
    665 					return (-1);
    666 				}
    667 
    668 				mem = malloc(sizeof(struct pnp_mem),
    669 					     M_DEVBUF, M_WAITOK);
    670 				mem->flags = NEXTBYTE(p);
    671 				mem->minbase = NEXTBYTE(p);
    672 				mem->minbase |= NEXTBYTE(p) << 8;
    673 				mem->minbase |= NEXTBYTE(p) << 16;
    674 				mem->minbase |= NEXTBYTE(p) << 24;
    675 				mem->maxbase = mem->minbase;
    676 				mem->align = 0;
    677 				mem->len = NEXTBYTE(p);
    678 				mem->len |= NEXTBYTE(p) << 8;
    679 				mem->len |= NEXTBYTE(p) << 16;
    680 				mem->len |= NEXTBYTE(p) << 24;
    681 gotmem:
    682 				if (mem->len == 0) { /* disabled */
    683 #ifdef PNPBIOSDEBUG
    684 					printf("ZERO mem descriptor\n");
    685 #endif
    686 					free(mem, M_DEVBUF);
    687 					break;
    688 				}
    689 				SIMPLEQ_INSERT_TAIL(&r->mem, mem, next);
    690 				r->nummem++;
    691 				break;
    692 			default:
    693 				printf("ignoring long tag %x\n", type);
    694 				while (len--)
    695 					(void) NEXTBYTE(p);
    696 			}
    697 		} else {
    698 			unsigned char tmpbuf[7];
    699 			int i;
    700 
    701 			type = (tag >> 3) & 0x0f;
    702 			len = tag & 0x07;
    703 
    704 			if (type == 0 ||
    705 			    len < smallrescs[type - 1].minlen ||
    706 			    len > smallrescs[type - 1].maxlen) {
    707 				printf("pnp_scan: bad small resource\n");
    708 				return (-1);
    709 			}
    710 			for (i = 0; i < len; i++)
    711 				tmpbuf[i] = NEXTBYTE(p);
    712 
    713 			if (type == 0x0f) { /* end mark */
    714 				if (in_depends) {
    715 					printf("end in dep?\n");
    716 					return (-1);
    717 				}
    718 				break;
    719 			}
    720 			if (type == 0x06) { /* start dep */
    721 				struct pnpresources *new, *last;
    722 				int res;
    723 
    724 				if (r->dependant_link) {
    725 					printf("second dep?\n");
    726 					return (-1);
    727 				}
    728 
    729 				if (in_depends) {
    730 					*bufp = p;
    731 					return (1);
    732 				}
    733 
    734 				last = r;
    735 				do {
    736 					new = malloc(sizeof(*new),
    737 						     M_DEVBUF, M_NOWAIT);
    738 
    739 					res = pnp_scan(&p, maxlen - (p - *bufp),
    740 						       new, 1);
    741 					if (res < 0) {
    742 				printf("error in dependant function\n");
    743 						free(new, M_DEVBUF);
    744 						return (-1);
    745 					}
    746 
    747 					last->dependant_link = new;
    748 					last = new;
    749 				} while (res > 0);
    750 				continue;
    751 			}
    752 			if (type == 0x07) { /* end dep */
    753 				if (!in_depends) {
    754 					printf("end dep?\n");
    755 					return (-1);
    756 				}
    757 				break;
    758 			}
    759 
    760 			if (!smallrescs[type - 1].handler)
    761 				printf("ignoring short tag %x\n", type);
    762 			else
    763 				if ((*smallrescs[type - 1].handler)(r, tmpbuf,
    764 								    len))
    765 					return (-1);
    766 		}
    767 	}
    768 	*bufp = p;
    769 	return (0);
    770 }
    771 
    772 static int
    773 pnp_newirq(r, buf, len)
    774 	struct pnpresources *r;
    775 	unsigned char *buf;
    776 	size_t len;
    777 {
    778 	struct pnp_irq *irq;
    779 
    780 	if (buf[0] == 0 && buf[1] == 0) { /* disabled */
    781 #ifdef PNPBIOSDEBUG
    782 		printf("ZERO irq descriptor\n");
    783 #endif
    784 		return (0);
    785 	}
    786 	irq = malloc(sizeof(struct pnp_irq), M_DEVBUF, M_NOWAIT);
    787 	irq->mask = buf[0] | (buf[1] << 8);
    788 	if (len > 2)
    789 		irq->flags = buf[2];
    790 	else
    791 		irq->flags = 0x01;
    792 	SIMPLEQ_INSERT_TAIL(&r->irq, irq, next);
    793 	r->numirq++;
    794 	return (0);
    795 }
    796 
    797 static int
    798 pnp_newdma(r, buf, len)
    799 	struct pnpresources *r;
    800 	unsigned char *buf;
    801 	size_t len;
    802 {
    803 	struct pnp_dma *dma;
    804 
    805 	if (buf[0] == 0) { /* disabled */
    806 #ifdef PNPBIOSDEBUG
    807 		printf("ZERO dma descriptor\n");
    808 #endif
    809 		return (0);
    810 	}
    811 	dma = malloc(sizeof(struct pnp_dma), M_DEVBUF, M_NOWAIT);
    812 	dma->mask = buf[0];
    813 	dma->flags = buf[1];
    814 	SIMPLEQ_INSERT_TAIL(&r->dma, dma, next);
    815 	r->numdma++;
    816 	return (0);
    817 }
    818 
    819 static int
    820 pnp_newioport(r, buf, len)
    821 	struct pnpresources *r;
    822 	unsigned char *buf;
    823 	size_t len;
    824 {
    825 	struct pnp_io *io;
    826 
    827 	if (buf[6] == 0) { /* disabled */
    828 #ifdef PNPBIOSDEBUG
    829 		printf("ZERO io descriptor\n");
    830 #endif
    831 		return (0);
    832 	}
    833 	io = malloc(sizeof(struct pnp_io), M_DEVBUF, M_NOWAIT);
    834 	io->flags = buf[0];
    835 	io->minbase = buf[1] | (buf[2] << 8);
    836 	io->maxbase = buf[3] | (buf[4] << 8);
    837 	io->align = buf[5];
    838 	io->len = buf[6];
    839 	SIMPLEQ_INSERT_TAIL(&r->io, io, next);
    840 	r->numio++;
    841 	return (0);
    842 }
    843 
    844 static int
    845 pnp_newfixedioport(r, buf, len)
    846 	struct pnpresources *r;
    847 	unsigned char *buf;
    848 	size_t len;
    849 {
    850 	struct pnp_io *io;
    851 
    852 	if (buf[2] == 0) { /* disabled */
    853 #ifdef PNPBIOSDEBUG
    854 		printf("ZERO fixed io descriptor\n");
    855 #endif
    856 		return (0);
    857 	}
    858 	io = malloc(sizeof(struct pnp_io), M_DEVBUF, M_NOWAIT);
    859 	io->flags = 1; /* 10 bit decoding */
    860 	io->minbase = io->maxbase = buf[0] | (buf[1] << 8);
    861 	io->align = 1;
    862 	io->len = buf[2];
    863 	SIMPLEQ_INSERT_TAIL(&r->io, io, next);
    864 	r->numio++;
    865 	return (0);
    866 }
    867 
    868 static int
    869 pnp_compatid(r, buf, len)
    870 	struct pnpresources *r;
    871 	unsigned char *buf;
    872 	size_t len;
    873 {
    874 	struct pnp_compatid *id;
    875 
    876 	id = malloc(sizeof(*id), M_DEVBUF, M_NOWAIT);
    877 	eisaid_to_string(buf, id->idstr);
    878 	id->next = r->compatids;
    879 	r->compatids = id;
    880 	return (0);
    881 }
    882 
    883 int
    884 pnpbios_io_map(pbt, resc, idx, tagp, hdlp)
    885 	pnpbios_tag_t pbt;
    886 	struct pnpresources *resc;
    887 	int idx;
    888 	bus_space_tag_t *tagp;
    889 	bus_space_handle_t *hdlp;
    890 {
    891 	struct pnp_io *io;
    892 
    893 	if (idx >= resc->numio)
    894 		return (EINVAL);
    895 
    896 	io = SIMPLEQ_FIRST(&resc->io);
    897 	while (idx--)
    898 		io = SIMPLEQ_NEXT(io, next);
    899 
    900 	*tagp = I386_BUS_SPACE_IO;
    901 	return (i386_memio_map(I386_BUS_SPACE_IO, io->minbase, io->len,
    902 			       0, hdlp));
    903 }
    904 
    905 int
    906 pnpbios_getiobase(pbt, resc, idx, tagp, basep)
    907 	pnpbios_tag_t pbt;
    908 	struct pnpresources *resc;
    909 	int idx;
    910 	bus_space_tag_t *tagp;
    911 	int *basep;
    912 {
    913 	struct pnp_io *io;
    914 
    915 	if (idx >= resc->numio)
    916 		return (EINVAL);
    917 
    918 	io = SIMPLEQ_FIRST(&resc->io);
    919 	while (idx--)
    920 		io = SIMPLEQ_NEXT(io, next);
    921 
    922 	if (tagp)
    923 		*tagp = I386_BUS_SPACE_IO;
    924 	if (basep)
    925 		*basep = io->minbase;
    926 	return (0);
    927 }
    928 
    929 void *
    930 pnpbios_intr_establish(pbt, resc, idx, level, fcn, arg)
    931 	pnpbios_tag_t pbt;
    932 	struct pnpresources *resc;
    933 	int idx, level;
    934 	int (*fcn) __P((void *));
    935 	void *arg;
    936 {
    937 	struct pnp_irq *irq;
    938 	int irqnum, type;
    939 
    940 	if (idx >= resc->numirq)
    941 		return (0);
    942 
    943 	irq = SIMPLEQ_FIRST(&resc->irq);
    944 	while (idx--)
    945 		irq = SIMPLEQ_NEXT(irq, next);
    946 
    947 	irqnum = ffs(irq->mask) - 1;
    948 	type = (irq->flags & 0x0c) ? IST_LEVEL : IST_EDGE;
    949 
    950 	return (isa_intr_establish(0, irqnum, type, level, fcn, arg));
    951 }
    952 
    953 int
    954 pnpbios_getirqnum(pbt, resc, idx, irqp)
    955 	pnpbios_tag_t pbt;
    956 	struct pnpresources *resc;
    957 	int idx;
    958 	int *irqp;
    959 {
    960 	struct pnp_irq *irq;
    961 
    962 	if (idx >= resc->numirq)
    963 		return (EINVAL);
    964 
    965 	irq = SIMPLEQ_FIRST(&resc->irq);
    966 	while (idx--)
    967 		irq = SIMPLEQ_NEXT(irq, next);
    968 
    969 	*irqp = ffs(irq->mask) - 1;
    970 	return (0);
    971 }
    972 
    973 int
    974 pnpbios_getdmachan(pbt, resc, idx, chanp)
    975 	pnpbios_tag_t pbt;
    976 	struct pnpresources *resc;
    977 	int idx;
    978 	int *chanp;
    979 {
    980 	struct pnp_dma *dma;
    981 
    982 	if (idx >= resc->numdma)
    983 		return (EINVAL);
    984 
    985 	dma = SIMPLEQ_FIRST(&resc->dma);
    986 	while (idx--)
    987 		dma = SIMPLEQ_NEXT(dma, next);
    988 
    989 	*chanp = ffs(dma->mask) - 1;
    990 	return (0);
    991 }
    992