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