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