pnpbios.c revision 1.13 1 /* $NetBSD: pnpbios.c,v 1.13 2000/04/22 06:38:24 thorpej Exp $ */
2 /*
3 * Copyright (c) 2000 Christian E. Hopps. All rights reserved.
4 * Copyright (c) 1999
5 * Matthias Drochner. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * PnP BIOS documentation is available at the following locations.
31 *
32 * http://www.microsoft.com/hwdev/download/respec/pnpbios.zip
33 * http://www.microsoft.com/hwdev/download/respec/biosclar.zip
34 * http://www.microsoft.com/hwdev/download/respec/devids.txt
35 *
36 * PNPBIOSEVENTS is unfinished. After coding what I did I discovered
37 * I had no platforms to test on so someone else will need to finish
38 * it. I didn't want to toss the code though
39 */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/device.h>
44 #include <sys/malloc.h>
45 #include <sys/kernel.h>
46 #include <sys/kthread.h>
47
48 #include <vm/vm.h>
49 #include <vm/vm_kern.h>
50
51 #include <machine/isa_machdep.h>
52 #include <machine/segments.h>
53
54 #include <dev/isa/isareg.h>
55 #include <dev/isapnp/isapnpreg.h>
56
57 #include <arch/i386/pnpbios/pnpbiosvar.h>
58 #include <arch/i386/pnpbios/pnpbiosreg.h>
59
60 #include "opt_pnpbiosverbose.h"
61 #include "isadma.h"
62 #include "locators.h"
63
64 #ifdef PNPBIOSDEBUG
65 #define DPRINTF(x) printf x
66 #else
67 #define DPRINTF(x)
68 #endif
69
70 struct pnpbios_softc {
71 struct device sc_dev;
72 isa_chipset_tag_t sc_ic;
73 struct proc *sc_evthread;
74
75 u_int8_t *sc_evaddr;
76 int sc_version;
77 int sc_control;
78 int sc_threadrun;
79 };
80
81 #define PNPGET4(p) ((p)[0] + ((p)[1] << 8) + \
82 ((p)[2] << 16) + ((p)[3] << 24))
83
84 /* bios calls */
85 int pnpbios_getapmtable __P((u_char *, size_t *));
86 int pnpbios_getdockinfo __P((struct pnpdockinfo *));
87 int pnpbios_getnode __P((int, int *, u_int8_t *, size_t));
88 int pnpbios_getnumnodes __P((int *, size_t *));
89 int pnpbios_getevent __P((u_int16_t *event));
90 int pnpbios_sendmessage __P((int));
91 int pnpbios_setnode __P((int, int, const u_int8_t *, size_t));
92
93 void pnpbios_create_event_thread __P((void *));
94 void pnpbios_event_thread __P((void *));
95
96 /* configuration stuff */
97 caddr_t pnpbios_mapit __P((u_long, u_long, int));
98 caddr_t pnpbios_find __P((void));
99 int pnpbios_match __P((struct device *, struct cfdata *, void *));
100 void pnpbios_attach __P((struct device *, struct device *, void *));
101 void pnpbios_printres __P((struct pnpresources *));
102 int pnpbios_print __P((void *, const char *));
103 void pnpbios_id_to_string __P((u_int32_t, char *));
104 void pnpbios_attachnode __P((struct pnpbios_softc *, int, const u_int8_t *,
105 size_t));
106 int pnp_scan __P((const u_int8_t **, size_t,struct pnpresources *, int));
107 int pnpbios_submatch __P((struct device *, struct cfdata *, void *));
108 extern int pnpbioscall __P((int));
109
110 /* scanning functions */
111 int pnp_compatid __P((struct pnpresources *, const void *, size_t));
112 int pnp_newirq __P((struct pnpresources *, const void *, size_t));
113 int pnp_newdma __P((struct pnpresources *, const void *, size_t));
114 int pnp_newioport __P((struct pnpresources *, const void *, size_t));
115 int pnp_newfixedioport __P((struct pnpresources *, const void *, size_t));
116 #ifdef PNPBIOSDEBUG
117 int pnp_debugdump __P((struct pnpresources *, const void *, size_t));
118 #endif
119
120 /*
121 * small ressource types (beginning with 1)
122 */
123 static struct{
124 int (*handler) __P((struct pnpresources *, const void *, size_t));
125 int minlen, maxlen;
126 } smallrescs[] = {
127 {0, 2, 2}, /* PnP version number */
128 {0, 5, 6}, /* logical device id */
129 {pnp_compatid, 4, 4}, /* compatible device id */
130 {pnp_newirq, 2, 3}, /* irq descriptor */
131 {pnp_newdma, 2, 2}, /* dma descriptor */
132 {0, 0, 1}, /* start dep */
133 {0, 0, 0}, /* end dep */
134 {pnp_newioport, 7, 7}, /* io descriptor */
135 {pnp_newfixedioport, 3, 3}, /* fixed io descriptor */
136 {0, -1, -1}, /* reserved */
137 {0, -1, -1},
138 {0, -1, -1},
139 {0, -1, -1},
140 {0, 1, 7}, /* vendor defined */
141 {0, 1, 1} /* end */
142 };
143
144
145 struct cfattach pnpbios_ca = {
146 sizeof(struct pnpbios_softc), pnpbios_match, pnpbios_attach
147 };
148
149 /*
150 * Private stack and return value buffer. Spec (1.0a, ch. 4.3) says that
151 * 1024 bytes must be available to the BIOS function.
152 */
153 #define PNPBIOS_BUFSIZE 4096
154
155 int pnpbios_enabled = 1;
156 size_t pnpbios_entry;
157 caddr_t pnpbios_scratchbuf;
158
159 /*
160 * There can be only one of these, and the i386 ISA code needs to
161 * reference this.
162 */
163 struct pnpbios_softc *pnpbios_softc;
164
165 #define PNPBIOS_SIGNATURE ('$' | ('P' << 8) | ('n' << 16) | ('P' << 24))
166
167 caddr_t
168 pnpbios_find()
169 {
170 caddr_t p, c;
171 u_int8_t cksum;
172 size_t structlen;
173
174 for (p = (caddr_t)ISA_HOLE_VADDR(0xf0000);
175 p <= (caddr_t)ISA_HOLE_VADDR(0xffff0);
176 p += 16) {
177 if (*(int *)p != PNPBIOS_SIGNATURE)
178 continue;
179 structlen = *(u_int8_t *)(p + 5);
180 if ((structlen < 0x21) ||
181 ((p + structlen - 1) > (caddr_t)ISA_HOLE_VADDR(0xfffff)))
182 continue;
183
184 cksum = 0;
185 for (c = p; c < p + structlen; c++)
186 cksum += *(u_int8_t *)c;
187 if (cksum != 0)
188 continue;
189
190 if (*(char *)(p + 4) != 0x10) {
191 printf("unknown version %x\n", *(char *)(p + 4));
192 continue;
193 }
194
195 return (p);
196 }
197
198 return (0);
199 }
200
201 int
202 pnpbios_probe()
203 {
204
205 return (pnpbios_find() != 0);
206 }
207
208 int
209 pnpbios_match(parent, match, aux)
210 struct device *parent;
211 struct cfdata *match;
212 void *aux;
213 {
214 struct pnpbios_attach_args *paa = aux;
215
216 /* These are not the droids you're looking for. */
217 if (strcmp(paa->paa_busname, "pnpbios") != 0)
218 return (0);
219
220 /* There can be only one! */
221 if (pnpbios_softc != NULL)
222 return (0);
223
224 return (pnpbios_enabled);
225 }
226
227 caddr_t
228 pnpbios_mapit(addr, len, prot)
229 u_long addr, len;
230 int prot;
231 {
232 u_long startpa, pa, endpa;
233 vaddr_t startva, va;
234
235 pa = startpa = i386_trunc_page(addr);
236 endpa = i386_round_page(addr + len);
237
238 va = startva = uvm_km_valloc(kernel_map, endpa - startpa);
239 if (!startva)
240 return (0);
241 for (; pa < endpa; pa += NBPG, va += NBPG)
242 pmap_kenter_pa(va, pa, prot);
243
244 return ((caddr_t)(startva + (addr - startpa)));
245 }
246
247 void
248 pnpbios_attach(parent, self, aux)
249 struct device *parent, *self;
250 void *aux;
251 {
252 struct pnpbios_softc *sc = (struct pnpbios_softc *)self;
253 struct pnpbios_attach_args *paa = aux;
254 struct pnpdevnode *dn;
255 caddr_t p;
256 unsigned int codepbase, datapbase, evaddrp;
257 caddr_t codeva, datava;
258 extern char pnpbiostramp[], epnpbiostramp[];
259 int res, num, i, size, idx;
260 #ifdef PNPBIOSVERBOSE
261 struct pnpdockinfo di;
262 #endif
263 #ifdef PNPBIOSEVENTS
264 int evtype;
265 #endif
266 u_int8_t *buf;
267
268 pnpbios_softc = sc;
269 sc->sc_ic = paa->paa_ic;
270
271 #if NISADMA > 0
272 isa_dmainit(sc->sc_ic, I386_BUS_SPACE_IO, &isa_bus_dma_tag, self);
273 #endif
274
275 p = pnpbios_find();
276 if (!p)
277 panic("pnpbios_attach: disappeared");
278
279 sc->sc_version = *(u_int8_t *)(p + 0x04);
280 sc->sc_control = *(u_int8_t *)(p + 0x06);
281 evaddrp = *(u_int32_t *)(p + 0x09);
282 codepbase = *(u_int32_t *)(p + 0x13);
283 datapbase = *(u_int32_t *)(p + 0x1d);
284 pnpbios_entry = *(u_int16_t *)(p + 0x11);
285
286 #ifdef PNPBIOSEVENTS
287 /* if we have an event mechnism queue a thread to deal with them */
288 evtype = (sc->sc_control & PNP_IC_CONTORL_EVENT_MASK);
289 if (evtype == PNP_IC_CONTROL_EVENT_POLL) {
290 sc->sc_evaddr = pnpbios_mapit(evaddrp, NBPG,
291 VM_PROT_READ | VM_PROT_WRITE);
292 if (!sc->sc_evaddr)
293 printf("pnpbios: couldn't map event flag 0x%08x\n",
294 evaddrp);
295 DPRINTF(("pnpbios: event flag vaddr 0x%08x\n",
296 (int)sc->sc_evaddr));
297 }
298 #endif
299 #ifdef PNPBIOSVERBOSE
300 printf(": code %x, data %x, entry %x, control %x eventp %x\n%s",
301 codepbase, datapbase, pnpbios_entry, sc->sc_control,
302 (int)evaddrp, self->dv_xname);
303 #endif
304
305 codeva = pnpbios_mapit(codepbase, 0x10000,
306 VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
307 datava = pnpbios_mapit(datapbase, 0x10000,
308 VM_PROT_READ | VM_PROT_WRITE);
309 if (codeva == 0 || datava == 0) {
310 printf("no vm for mapping\n");
311 return;
312 }
313 pnpbios_scratchbuf = malloc(PNPBIOS_BUFSIZE, M_DEVBUF, M_NOWAIT);
314
315 setsegment(&gdt[GPNPBIOSCODE_SEL].sd, codeva, 0xffff,
316 SDT_MEMERA, SEL_KPL, 0, 0);
317 setsegment(&gdt[GPNPBIOSDATA_SEL].sd, datava, 0xffff,
318 SDT_MEMRWA, SEL_KPL, 0, 0);
319 setsegment(&gdt[GPNPBIOSSCRATCH_SEL].sd,
320 pnpbios_scratchbuf, PNPBIOS_BUFSIZE - 1,
321 SDT_MEMRWA, SEL_KPL, 0, 0);
322 setsegment(&gdt[GPNPBIOSTRAMP_SEL].sd,
323 pnpbiostramp, epnpbiostramp - pnpbiostramp - 1,
324 SDT_MEMERA, SEL_KPL, 1, 0);
325
326 res = pnpbios_getnumnodes(&num, &size);
327 if (res) {
328 printf("pnpbios_getnumnodes: error %d\n", res);
329 return;
330 }
331
332 printf(": nodes %d, max len %d\n", num, size);
333 buf = malloc(size, M_DEVBUF, M_NOWAIT);
334
335 idx = 0;
336 for (i = 0; i < num && idx != 0xff; i++) {
337 int node = idx;
338 res = pnpbios_getnode(1, &idx, buf, size);
339 if (res) {
340 printf("pnpbios_getnode: error %d\n", res);
341 continue;
342 }
343 dn = (struct pnpdevnode *)buf;
344 if (dn->dn_handle != node)
345 printf("node idx: called %d, got %d\n", node,
346 dn->dn_handle);
347 pnpbios_attachnode(sc, node, buf, dn->dn_size);
348 }
349 if (i != num)
350 printf("got only %d nodes\n", i);
351 if (idx != 0xff)
352 printf("last idx=%x\n", idx);
353
354 free(buf, M_DEVBUF);
355
356 #ifdef PNPBIOSVERBOSE
357 res = pnpbios_getdockinfo(&di);
358 if (res == PNP_RC_SYSTEM_NOT_DOCKED)
359 printf("%s: not docked\n", sc->sc_dev.dv_xname);
360 else if (res)
361 DPRINTF(("pnpbios: dockinfo fails 0x%02x\n", res));
362 else {
363 char idstr[8];
364 pnpbios_id_to_string(di.di_id, idstr);
365 printf("%s: dock id %s serial number %d capabilities 0x%04x\n",
366 sc->sc_dev.dv_xname, idstr, di.di_serial, di.di_cap);
367 }
368 #endif
369 #ifdef PNPBIOSEVENTS
370 /* if we have an event mechnism queue a thread to deal with them */
371 /* XXX need to update with irq if we do that */
372 if (evtype != PNP_IC_CONTROL_EVENT_NONE) {
373 if (evtype != PNP_IC_CONTROL_EVENT_POLL || sc->sc_evaddr) {
374 sc->sc_threadrun = 1;
375 config_pending_incr();
376 kthread_create(pnpbios_create_event_thread, sc);
377 }
378 }
379 #endif
380 }
381
382 int
383 pnpbios_getnumnodes(nump, sizep)
384 int *nump;
385 size_t *sizep;
386 {
387 int res;
388 short *help = (short *)(pnpbios_scratchbuf + PNPBIOS_BUFSIZE);
389
390 *--help = GSEL(GPNPBIOSDATA_SEL, SEL_KPL);
391 *--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
392 *--help = 2; /* buffer offset for node size */
393 *--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
394 *--help = 0; /* buffer offset for numnodes */
395 *--help = PNP_FC_GET_NUM_NODES;
396
397 res = pnpbioscall(((caddr_t)help) - pnpbios_scratchbuf);
398 if (res)
399 return (res);
400
401 *nump = *(short *)(pnpbios_scratchbuf + 0);
402 *sizep = *(short *)(pnpbios_scratchbuf + 2);
403 return (0);
404 }
405
406 int
407 pnpbios_getnode(flags, idxp, buf, len)
408 int flags;
409 int *idxp;
410 u_int8_t *buf;
411 size_t len;
412 {
413 int res;
414 short *help = (short *)(pnpbios_scratchbuf + PNPBIOS_BUFSIZE);
415
416 *--help = GSEL(GPNPBIOSDATA_SEL, SEL_KPL);
417 *--help = flags;
418 *--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
419 *--help = 2; /* buffer offset for node data */
420 *--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
421 *--help = 0; /* buffer offset for index in/out */
422 *--help = PNP_FC_GET_DEVICE_NODE;
423
424 *(short *)(pnpbios_scratchbuf + 0) = *idxp;
425
426 res = pnpbioscall(((caddr_t)help) - pnpbios_scratchbuf);
427 if (res)
428 return (res);
429
430 *idxp = *(short *)(pnpbios_scratchbuf + 0);
431 bcopy(pnpbios_scratchbuf + 2, buf, len);
432 return (0);
433 }
434
435 int
436 pnpbios_setnode(flags, idx, buf, len)
437 int flags, idx;
438 const u_int8_t *buf;
439 size_t len;
440 {
441 short *help = (short *)(pnpbios_scratchbuf + PNPBIOS_BUFSIZE);
442
443 *--help = GSEL(GPNPBIOSDATA_SEL, SEL_KPL);
444 *--help = flags;
445 *--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
446 *--help = 0; /* buffer offset for node data */
447 *--help = idx;
448 *--help = PNP_FC_SET_DEVICE_NODE;
449
450 memcpy(pnpbios_scratchbuf, buf, len);
451
452 return (pnpbioscall(((caddr_t)help) - pnpbios_scratchbuf));
453 }
454
455 int
456 pnpbios_getevent(event)
457 u_int16_t *event;
458 {
459 int res;
460 short *help = (short *)(pnpbios_scratchbuf + PNPBIOS_BUFSIZE);
461
462 *--help = GSEL(GPNPBIOSDATA_SEL, SEL_KPL);
463 *--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
464 *--help = 0; /* buffer offset for message data */
465 *--help = PNP_FC_GET_EVENT;
466
467 res = pnpbioscall(((caddr_t)help) - pnpbios_scratchbuf);
468 *event = pnpbios_scratchbuf[0] + (pnpbios_scratchbuf[1] << 8);
469 return (res);
470 }
471
472 int
473 pnpbios_sendmessage(msg)
474 int msg;
475 {
476 short *help = (short *)(pnpbios_scratchbuf + PNPBIOS_BUFSIZE);
477
478 *--help = GSEL(GPNPBIOSDATA_SEL, SEL_KPL);
479 *--help = msg;
480 *--help = PNP_FC_SEND_MESSAGE;
481
482 return (pnpbioscall(((caddr_t)help) - pnpbios_scratchbuf));
483 }
484
485 int
486 pnpbios_getdockinfo(di)
487 struct pnpdockinfo *di;
488 {
489 int res;
490 short *help = (short *)(pnpbios_scratchbuf + PNPBIOS_BUFSIZE);
491
492 *--help = GSEL(GPNPBIOSDATA_SEL, SEL_KPL);
493 *--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
494 *--help = 0; /* buffer offset for dock info */
495 *--help = PNP_FC_GET_DOCK_INFO;
496
497 res = pnpbioscall(((caddr_t)help) - pnpbios_scratchbuf);
498 memcpy(di, pnpbios_scratchbuf, sizeof(*di));
499 return (res);
500 }
501
502 /* XXX we don't support more than PNPBIOS_BUFSIZE - (stacklen + 2) */
503 int
504 pnpbios_getapmtable(tab, len)
505 u_int8_t *tab;
506 size_t *len;
507 {
508 short *help = (short *)(pnpbios_scratchbuf + PNPBIOS_BUFSIZE);
509 size_t origlen, stacklen;
510 int res;
511
512 *--help = GSEL(GPNPBIOSDATA_SEL, SEL_KPL);
513 *--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
514 *--help = 2; /* buffer offset for table */
515 *--help = GSEL(GPNPBIOSSCRATCH_SEL, SEL_KPL);
516 *--help = 0; /* buffer offset for length */
517 *--help = PNP_FC_GET_APM_TABLE;
518
519 origlen = *len;
520 stacklen = (caddr_t)help - pnpbios_scratchbuf;
521 if (origlen > PNPBIOS_BUFSIZE - stacklen - 2)
522 origlen = PNPBIOS_BUFSIZE - stacklen - 2;
523 *(u_int16_t *)(pnpbios_scratchbuf) = origlen;
524
525 res = pnpbioscall(((caddr_t)help) - pnpbios_scratchbuf);
526 *len = *(u_int16_t *)pnpbios_scratchbuf;
527 if (res)
528 return (res);
529 if (origlen && *len > origlen) {
530 printf("pnpbios: returned apm table exceed requested size\n");
531 return (PNP_RC_BUFFER_TOO_SMALL);
532 }
533 memcpy(tab, pnpbios_scratchbuf + 2, *len);
534 return (0);
535 }
536
537 void
538 pnpbios_id_to_string(pnpid, s)
539 u_int32_t pnpid;
540 char *s;
541 {
542 static char hex[] = "0123456789ABCDEF";
543 u_int8_t *id;
544
545 id = (u_int8_t *)&pnpid;
546 *s++ = 'A' + (id[0] >> 2) - 1;
547 *s++ = 'A' + ((id[0] & 3) << 3) + (id[1] >> 5) - 1;
548 *s++ = 'A' + (id[1] & 0x1f) - 1;
549 *s++ = hex[id[2] >> 4];
550 *s++ = hex[id[2] & 0x0f];
551 *s++ = hex[id[3] >> 4];
552 *s++ = hex[id[3] & 0x0f];
553 *s = '\0';
554 }
555
556 void
557 pnpbios_printres(r)
558 struct pnpresources *r;
559 {
560 struct pnp_mem *mem;
561 struct pnp_io *io;
562 struct pnp_irq *irq;
563 struct pnp_dma *dma;
564 int p = 0;
565
566 mem = SIMPLEQ_FIRST(&r->mem);
567 if (mem) {
568 printf("mem");
569 do {
570 printf(" %x", mem->minbase);
571 if (mem->len > 1)
572 printf("-%x", mem->minbase + mem->len - 1);
573 } while ((mem = SIMPLEQ_NEXT(mem, next)));
574 p++;
575 }
576 io = SIMPLEQ_FIRST(&r->io);
577 if (io) {
578 if (p++)
579 printf(", ");
580 printf("io");
581 do {
582 printf(" %x", io->minbase);
583 if (io->len > 1)
584 printf("-%x", io->minbase + io->len - 1);
585 } while ((io = SIMPLEQ_NEXT(io, next)));
586 }
587 irq = SIMPLEQ_FIRST(&r->irq);
588 if (irq) {
589 if (p++)
590 printf(", ");
591 printf("irq");
592 do {
593 printf(" %d", ffs(irq->mask) - 1);
594 } while ((irq = SIMPLEQ_NEXT(irq, next)));
595 }
596 dma = SIMPLEQ_FIRST(&r->dma);
597 if (dma) {
598 if (p)
599 printf(", ");
600 printf("dma");
601 do {
602 printf(" %d", ffs(dma->mask) - 1);
603 } while ((dma = SIMPLEQ_NEXT(dma, next)));
604 }
605 }
606
607 int
608 pnpbios_print(aux, pnp)
609 void *aux;
610 const char *pnp;
611 {
612 struct pnpbiosdev_attach_args *aa = aux;
613
614 if (pnp)
615 return (QUIET);
616
617 printf(" index %d (%s", aa->idx, aa->primid);
618 if (aa->resc->longname)
619 printf(", %s", aa->resc->longname);
620 if (aa->idstr != aa->primid)
621 printf(", attached as %s", aa->idstr);
622 printf(")");
623
624 return (0);
625 }
626
627 void
628 pnpbios_print_devres(dev, aa)
629 struct device *dev;
630 struct pnpbiosdev_attach_args *aa;
631 {
632
633 printf("%s: ", dev->dv_xname);
634 pnpbios_printres(aa->resc);
635 printf("\n");
636 }
637
638 int
639 pnpbios_submatch(parent, match, aux)
640 struct device *parent;
641 struct cfdata *match;
642 void *aux;
643 {
644 struct pnpbiosdev_attach_args *aa = aux;
645
646 if (match->cf_loc[PNPBIOSCF_INDEX] != PNPBIOSCF_INDEX_DEFAULT &&
647 match->cf_loc[PNPBIOSCF_INDEX] != aa->idx)
648 return (0);
649
650 return ((*match->cf_attach->ca_match)(parent, match, aux));
651 }
652
653 void
654 pnpbios_attachnode(sc, idx, buf, len)
655 struct pnpbios_softc *sc;
656 int idx;
657 const u_int8_t *buf;
658 size_t len;
659 {
660 struct pnpdevnode *dn;
661 const u_int8_t *p;
662 char idstr[8];
663 struct pnpresources r, s;
664 struct pnpbiosdev_attach_args aa;
665 struct pnp_compatid *compatid;
666 int res, i;
667
668 dn = (struct pnpdevnode *)buf;
669 pnpbios_id_to_string(dn->dn_product, idstr);
670 p = (u_char *)(dn + 1);
671
672 DPRINTF(("%s: type 0x%02x subtype 0x%02x dpi 0x%02x attr 0x%04x:\n",
673 idstr, dn->dn_type, dn->dn_subtype, dn->dn_dpi, dn->dn_attr));
674 DPRINTF(("%s: allocated config scan:\n", idstr));
675 res = pnp_scan(&p, len - 12, &r, 0);
676 if (res < 0) {
677 printf("error in config data\n");
678 goto dump;
679 }
680
681 /*
682 * the following is consistency check only for now
683 */
684 DPRINTF(("\tpossible config scan:\n"));
685 res = pnp_scan(&p, len - (p - buf), &s, 0);
686 if (res < 0) {
687 printf("error in possible configuration\n");
688 goto dump;
689 }
690
691 DPRINTF(("\tcompat id scan:\n"));
692 res = pnp_scan(&p, len - (p - buf), &s, 0);
693 if (res < 0) {
694 printf("error in compatible ID\n");
695 goto dump;
696 }
697
698 if (p != buf + len) {
699 printf("%s: length mismatch in node %d: used %d of %d Bytes\n",
700 sc->sc_dev.dv_xname, idx, p - buf, len);
701 if (p > buf + len) {
702 /* XXX shouldn't happen - pnp_scan should catch it */
703 goto dump;
704 }
705 /* Crappy BIOS: Buffer is not fully used. Be generous. */
706 }
707
708 if (r.nummem + r.numio + r.numirq + r.numdma == 0) {
709 #ifdef PNPBIOSVERBOSE
710 printf("%s", idstr);
711 if (r.longname)
712 printf(", %s", r.longname);
713 compatid = s.compatids;
714 while (compatid) {
715 printf(", %s", compatid->idstr);
716 compatid = compatid->next;
717 }
718 printf(" at %s index %d disabled\n", sc->sc_dev.dv_xname, idx);
719 #endif
720 return;
721 }
722
723 aa.pbt = 0; /* XXX placeholder */
724 aa.idx = idx;
725 aa.resc = &r;
726 aa.ic = sc->sc_ic;
727 aa.primid = idstr;
728
729 /* first try the specific device ID */
730 aa.idstr = idstr;
731 if (config_found_sm((struct device *)sc, &aa, pnpbios_print,
732 pnpbios_submatch))
733 return;
734
735 /* if no driver was found, try compatible IDs */
736 compatid = s.compatids;
737 while (compatid) {
738 aa.idstr = compatid->idstr;
739 if (config_found_sm((struct device *)sc, &aa, pnpbios_print,
740 pnpbios_submatch))
741 return;
742 compatid = compatid->next;
743 }
744
745 #ifdef PNPBIOSVERBOSE
746 printf("%s", idstr);
747 if (r.longname)
748 printf(", %s", r.longname);
749 compatid = s.compatids;
750 while (compatid) {
751 printf(", %s", compatid->idstr);
752 compatid = compatid->next;
753 }
754 printf(" (");
755 pnpbios_printres(&r);
756 printf(") at %s index %d ignored\n", sc->sc_dev.dv_xname, idx);
757 #endif
758
759 return;
760
761 /* XXX should free ressource lists */
762
763 dump:
764 i = 0;
765 #ifdef PNPBIOSDEBUG
766 /* print some useful info */
767 if (len >= sizeof(*dn)) {
768 printf("%s idx %d size %d type 0x%x:0x%x:0x%x attr 0x%x\n",
769 idstr, dn->dn_handle, dn->dn_size, dn->dn_type,
770 dn->dn_subtype, dn->dn_dpi, dn->dn_attr);
771 i += sizeof(*dn);
772 }
773 #endif
774 for (; i < len; i++)
775 printf(" %02x", buf[i]);
776 printf("\n");
777 }
778
779 int
780 pnp_scan(bufp, maxlen, r, in_depends)
781 const u_int8_t **bufp;
782 size_t maxlen;
783 struct pnpresources *r;
784 int in_depends;
785 {
786 const void *start;
787 const u_int8_t *p;
788 struct pnp_mem *mem;
789 int tag, type, len;
790 char *idstr;
791 int i;
792
793 p = *bufp;
794
795 bzero(r, sizeof(*r));
796 SIMPLEQ_INIT(&r->mem);
797 SIMPLEQ_INIT(&r->io);
798 SIMPLEQ_INIT(&r->irq);
799 SIMPLEQ_INIT(&r->dma);
800
801 for (;;) {
802 if (p >= *bufp + maxlen) {
803 printf("pnp_scanresources: end of buffer\n");
804 return (-1);
805 }
806 start = p;
807 tag = *p;
808 if (tag & ISAPNP_LARGE_TAG) {
809 len = *(u_int16_t *)(p + 1);
810 p += sizeof(struct pnplargeres) + len;
811
812 switch (tag) {
813 case ISAPNP_TAG_MEM_RANGE_DESC: {
814 const struct pnpmem16rangeres *res = start;
815 if (len != sizeof(*res) - 3) {
816 printf("pnp_scan: bad mem desc\n");
817 return (-1);
818 }
819
820 mem = malloc(sizeof(struct pnp_mem),
821 M_DEVBUF, M_WAITOK);
822 mem->flags = res->r_flags;
823 mem->minbase = res->r_minbase << 8;
824 mem->maxbase = res->r_maxbase << 8;
825 mem->align = res->r_align;
826 if (mem->align == 0)
827 mem->align = 0x10000;
828 mem->len = res->r_len << 8;
829 DPRINTF(("\ttag memrange "));
830 goto gotmem;
831 }
832 case ISAPNP_TAG_ANSI_IDENT_STRING: {
833 const struct pnpansiidentres *res = start;
834 if (in_depends)
835 printf("ID in dep?\n");
836 idstr = malloc(len + 1, M_DEVBUF, M_NOWAIT);
837 for (i = 0; i < len; i++)
838 idstr[i] = res->r_id[i];
839 idstr[len] = '\0';
840
841 DPRINTF(("\ttag ansiident %s\n", idstr));
842
843 if (idstr[0] == '\0') {
844 /* disabled device */
845 free(idstr, M_DEVBUF);
846 break;
847 }
848 r->longname = idstr;
849 break;
850 }
851 case ISAPNP_TAG_MEM32_RANGE_DESC: {
852 const struct pnpmem32rangeres *res = start;
853 if (len != sizeof(*res) - 3) {
854 printf("pnp_scan: bad mem32 desc\n");
855 return (-1);
856 }
857
858 mem = malloc(sizeof(struct pnp_mem),
859 M_DEVBUF, M_WAITOK);
860 mem->flags = res->r_flags;
861 mem->minbase = res->r_minbase;
862 mem->maxbase = res->r_maxbase;
863 mem->align = res->r_align;
864 mem->len = res->r_len;
865 DPRINTF(("\ttag mem32range "));
866 goto gotmem;
867 }
868 case ISAPNP_TAG_FIXED_MEM32_RANGE_DESC: {
869 const struct pnpfixedmem32rangeres *res = start;
870 if (len != sizeof(*res) - 3) {
871 printf("pnp_scan: bad mem32 desc\n");
872 return (-1);
873 }
874
875 mem = malloc(sizeof(struct pnp_mem),
876 M_DEVBUF, M_WAITOK);
877 mem->flags = res->r_flags;
878 mem->minbase = res->r_base;
879 mem->maxbase = mem->minbase;
880 mem->align = 0;
881 mem->len = res->r_len;
882 DPRINTF(("\ttag fixedmem32range "));
883 gotmem:
884 if (mem->len == 0) { /* disabled */
885 DPRINTF(("zeroed\n"));
886 free(mem, M_DEVBUF);
887 break;
888 }
889 SIMPLEQ_INSERT_TAIL(&r->mem, mem, next);
890 r->nummem++;
891
892 DPRINTF(("flags %02x min %08x max %08x "
893 "align %08x len %08x\n", mem->flags,
894 mem->minbase, mem->maxbase, mem->align,
895 mem->len));
896
897 break;
898 }
899 case ISAPNP_TAG_UNICODE_IDENT_STRING:
900 case ISAPNP_TAG_VENDOR_DEFINED:
901 default:
902 #ifdef PNPBIOSDEBUG
903 pnp_debugdump(r, start, len);
904 #endif
905 break;
906 }
907 } else {
908 type = (tag >> 3) & 0x0f;
909 len = tag & 0x07;
910 p += 1 + len;
911
912 if (type == 0 ||
913 len < smallrescs[type - 1].minlen ||
914 len > smallrescs[type - 1].maxlen) {
915 printf("pnp_scan: bad small resource\n");
916 return (-1);
917 }
918 if (type == ISAPNP_TAG_END) {
919 #ifdef PNPBIOSDEBUG
920 const struct pnpendres *res = start;
921 #endif
922 if (in_depends) {
923 /*
924 * this seems to occur and is
925 * an optimization to not require
926 * the end dep in a depend
927 * that ends the section
928 */
929 p -= 1 + len;
930 }
931 DPRINTF(("\ttag end cksum %02x\n",
932 res->r_cksum));
933 break;
934 }
935 if (type == ISAPNP_TAG_DEP_START) {
936 #ifdef PNPBIOSDEBUG
937 const struct pnpdepstartres *res = start;
938 #endif
939 struct pnpresources *new, *last;
940 int rv;
941
942 DPRINTF(("\ttag startdep flags %02x\n",
943 len ? res->r_pri : ISAPNP_DEP_ACCEPTABLE));
944
945 if (r->dependant_link) {
946 printf("second dep?\n");
947 return (-1);
948 }
949 /* XXX not sure about this */
950 if (in_depends) {
951 *bufp = p;
952 return (1);
953 }
954 last = r;
955 do {
956 new = malloc(sizeof(*new),
957 M_DEVBUF, M_NOWAIT);
958
959 rv = pnp_scan(&p, maxlen - (p - *bufp),
960 new, 1);
961 if (rv < 0) {
962 printf("error in dependant "
963 "function\n");
964 free(new, M_DEVBUF);
965 return (-1);
966 }
967 last->dependant_link = new;
968 last = new;
969 } while (rv > 0);
970 continue;
971 }
972 if (type == ISAPNP_TAG_DEP_END) {
973 DPRINTF(("\ttag enddep\n"));
974 if (!in_depends) {
975 printf("tag %d end dep?\n", tag);
976 return (-1);
977 }
978 break;
979 }
980 if (!smallrescs[type - 1].handler) {
981 #ifdef PNPBIOSDEBUG
982 pnp_debugdump(r, start, len);
983 #endif
984 } else if (
985 (*smallrescs[type - 1].handler)(r, start, len))
986 return (-1);
987 }
988 }
989 *bufp = p;
990 return (0);
991 }
992
993 int
994 pnp_newirq(r, vres, len)
995 struct pnpresources *r;
996 const void *vres;
997 size_t len;
998 {
999 const struct pnpirqres *res;
1000 struct pnp_irq *irq;
1001
1002 res = vres;
1003 if (res->r_mask == 0) { /* disabled */
1004 DPRINTF(("\ttag irq zeroed\n"));
1005 return (0);
1006 }
1007 irq = malloc(sizeof(struct pnp_irq), M_DEVBUF, M_NOWAIT);
1008 irq->mask = res->r_mask;
1009 if (len > 2)
1010 irq->flags = res->r_info;
1011 else
1012 irq->flags = 0x01;
1013 SIMPLEQ_INSERT_TAIL(&r->irq, irq, next);
1014 r->numirq++;
1015
1016 DPRINTF(("\ttag irq flags %02x mask %04x\n", irq->flags,irq->mask));
1017
1018 return (0);
1019 }
1020
1021 int
1022 pnp_newdma(r, vres, len)
1023 struct pnpresources *r;
1024 const void *vres;
1025 size_t len;
1026 {
1027 const struct pnpdmares *res;
1028 struct pnp_dma *dma;
1029
1030 res = vres;
1031 if (res->r_mask == 0) { /* disabled */
1032 DPRINTF(("\ttag dma zeroed\n"));
1033 return (0);
1034 }
1035 dma = malloc(sizeof(struct pnp_dma), M_DEVBUF, M_NOWAIT);
1036 dma->mask = res->r_mask;
1037 dma->flags = res->r_flags;
1038 SIMPLEQ_INSERT_TAIL(&r->dma, dma, next);
1039 r->numdma++;
1040
1041 DPRINTF(("\ttag dma flags %02x mask %02x\n", dma->flags,dma->mask));
1042
1043 return (0);
1044 }
1045
1046 int
1047 pnp_newioport(r, vres, len)
1048 struct pnpresources *r;
1049 const void *vres;
1050 size_t len;
1051 {
1052 const struct pnpportres *res;
1053 struct pnp_io *io;
1054
1055 res = vres;
1056 if (res->r_len == 0) { /* disabled */
1057 DPRINTF(("\ttag io zeroed\n"));
1058 return (0);
1059 }
1060 io = malloc(sizeof(struct pnp_io), M_DEVBUF, M_NOWAIT);
1061 io->flags = res->r_flags;
1062 io->minbase = res->r_minbase;
1063 io->maxbase = res->r_maxbase;
1064 io->align = res->r_align;
1065 io->len = res->r_len;
1066 SIMPLEQ_INSERT_TAIL(&r->io, io, next);
1067 r->numio++;
1068
1069 DPRINTF(("\ttag io flags %02x min %04x max %04x align "
1070 "0x%02x len 0x%02x\n", io->flags, io->minbase, io->maxbase,
1071 io->align, io->len));
1072
1073 return (0);
1074 }
1075
1076 int
1077 pnp_newfixedioport(r, vres, len)
1078 struct pnpresources *r;
1079 const void *vres;
1080 size_t len;
1081 {
1082 const struct pnpfixedportres *res;
1083 struct pnp_io *io;
1084
1085 res = vres;
1086 if (res->r_len == 0) { /* disabled */
1087 DPRINTF(("\ttag fixedio zeroed\n"));
1088 return (0);
1089 }
1090 io = malloc(sizeof(struct pnp_io), M_DEVBUF, M_NOWAIT);
1091 io->flags = 1; /* 10 bit decoding */
1092 io->minbase = io->maxbase = res->r_base;
1093 io->align = 1;
1094 io->len = res->r_len;
1095 SIMPLEQ_INSERT_TAIL(&r->io, io, next);
1096 r->numio++;
1097
1098 DPRINTF(("\ttag fixedio flags %02x base %04x align %02x len %02x\n",
1099 io->flags, io->minbase, io->align, io->len));
1100
1101 return (0);
1102 }
1103
1104 int
1105 pnp_compatid(r, vres, len)
1106 struct pnpresources *r;
1107 const void *vres;
1108 size_t len;
1109 {
1110 const struct pnpcompatres *res;
1111 struct pnp_compatid *id;
1112
1113 res = vres;
1114 id = malloc(sizeof(*id), M_DEVBUF, M_NOWAIT);
1115 pnpbios_id_to_string(res->r_id, id->idstr);
1116 id->next = r->compatids;
1117 r->compatids = id;
1118
1119 DPRINTF(("\ttag compatid %s\n", id->idstr));
1120
1121 return (0);
1122 }
1123
1124 #ifdef PNPBIOSDEBUG
1125 int
1126 pnp_debugdump(r, vres, len)
1127 struct pnpresources *r;
1128 const void *vres;
1129 size_t len;
1130 {
1131 const u_int8_t *res;
1132 int type, i;
1133
1134 if (res[0] & ISAPNP_LARGE_TAG) {
1135 type = res[0] & 0x7f;
1136 printf("\tTAG %02x len %04x %s", type, len, len ? "data" : "");
1137 i = 3;
1138 } else {
1139 type = (res[0] >> 3) & 0x0f;
1140 printf("\tTAG %02x len %02x %s", type, len, len ? "data" : "");
1141 i = 1;
1142 }
1143 for (; i < len; i++)
1144 printf(" %02x", res[i]);
1145 printf("\n");
1146
1147 return (0);
1148 }
1149 #endif
1150
1151 int
1152 pnpbios_io_map(pbt, resc, idx, tagp, hdlp)
1153 pnpbios_tag_t pbt;
1154 struct pnpresources *resc;
1155 int idx;
1156 bus_space_tag_t *tagp;
1157 bus_space_handle_t *hdlp;
1158 {
1159 struct pnp_io *io;
1160
1161 if (idx >= resc->numio)
1162 return (EINVAL);
1163
1164 io = SIMPLEQ_FIRST(&resc->io);
1165 while (idx--)
1166 io = SIMPLEQ_NEXT(io, next);
1167
1168 *tagp = I386_BUS_SPACE_IO;
1169 return (i386_memio_map(I386_BUS_SPACE_IO, io->minbase, io->len,
1170 0, hdlp));
1171 }
1172
1173 void
1174 pnpbios_io_unmap(pbt, resc, idx, tag, hdl)
1175 pnpbios_tag_t pbt;
1176 struct pnpresources *resc;
1177 int idx;
1178 bus_space_tag_t tag;
1179 bus_space_handle_t hdl;
1180 {
1181 struct pnp_io *io;
1182
1183 if (idx >= resc->numio)
1184 return;
1185
1186 io = SIMPLEQ_FIRST(&resc->io);
1187 while (idx--)
1188 io = SIMPLEQ_NEXT(io, next);
1189
1190 i386_memio_unmap(tag, hdl, io->len);
1191 }
1192
1193 int
1194 pnpbios_getiobase(pbt, resc, idx, tagp, basep)
1195 pnpbios_tag_t pbt;
1196 struct pnpresources *resc;
1197 int idx;
1198 bus_space_tag_t *tagp;
1199 int *basep;
1200 {
1201 struct pnp_io *io;
1202
1203 if (idx >= resc->numio)
1204 return (EINVAL);
1205
1206 io = SIMPLEQ_FIRST(&resc->io);
1207 while (idx--)
1208 io = SIMPLEQ_NEXT(io, next);
1209
1210 if (tagp)
1211 *tagp = I386_BUS_SPACE_IO;
1212 if (basep)
1213 *basep = io->minbase;
1214 return (0);
1215 }
1216
1217 void *
1218 pnpbios_intr_establish(pbt, resc, idx, level, fcn, arg)
1219 pnpbios_tag_t pbt;
1220 struct pnpresources *resc;
1221 int idx, level;
1222 int (*fcn) __P((void *));
1223 void *arg;
1224 {
1225 struct pnp_irq *irq;
1226 int irqnum, type;
1227
1228 if (idx >= resc->numirq)
1229 return (0);
1230
1231 irq = SIMPLEQ_FIRST(&resc->irq);
1232 while (idx--)
1233 irq = SIMPLEQ_NEXT(irq, next);
1234
1235 irqnum = ffs(irq->mask) - 1;
1236 type = (irq->flags & 0x0c) ? IST_LEVEL : IST_EDGE;
1237
1238 return (isa_intr_establish(0, irqnum, type, level, fcn, arg));
1239 }
1240
1241 int
1242 pnpbios_getirqnum(pbt, resc, idx, irqp, istp)
1243 pnpbios_tag_t pbt;
1244 struct pnpresources *resc;
1245 int idx;
1246 int *irqp;
1247 int *istp;
1248 {
1249 struct pnp_irq *irq;
1250
1251 if (idx >= resc->numirq)
1252 return (EINVAL);
1253
1254 irq = SIMPLEQ_FIRST(&resc->irq);
1255 while (idx--)
1256 irq = SIMPLEQ_NEXT(irq, next);
1257
1258 if (irqp != NULL)
1259 *irqp = ffs(irq->mask) - 1;
1260 if (istp != NULL)
1261 *istp = (irq->flags & 0x0c) ? IST_LEVEL : IST_EDGE;
1262 return (0);
1263 }
1264
1265 int
1266 pnpbios_getdmachan(pbt, resc, idx, chanp)
1267 pnpbios_tag_t pbt;
1268 struct pnpresources *resc;
1269 int idx;
1270 int *chanp;
1271 {
1272 struct pnp_dma *dma;
1273
1274 if (idx >= resc->numdma)
1275 return (EINVAL);
1276
1277 dma = SIMPLEQ_FIRST(&resc->dma);
1278 while (idx--)
1279 dma = SIMPLEQ_NEXT(dma, next);
1280
1281 *chanp = ffs(dma->mask) - 1;
1282 return (0);
1283 }
1284
1285 #ifdef PNPBIOSEVENTS
1286 void
1287 pnpbios_create_event_thread(arg)
1288 void *arg;
1289 {
1290 struct pnpbios_softc *sc;
1291
1292 sc = arg;
1293 if (kthread_create1(pnpbios_event_thread, sc, &sc->sc_evthread,
1294 "%s", sc->sc_dev.dv_xname))
1295 panic("pnpbios_create_event_thread");
1296 }
1297
1298 void
1299 pnpbios_event_thread(arg)
1300 void *arg;
1301 {
1302 struct pnpbios_softc *sc;
1303 u_int16_t event;
1304 u_int evflag;
1305 int rv, poll;
1306
1307 sc = arg;
1308 if ((sc->sc_control & PNP_IC_CONTORL_EVENT_MASK)
1309 != PNP_IC_CONTROL_EVENT_POLL)
1310 poll = 0;
1311 else {
1312 poll = hz;
1313 rv = pnpbios_sendmessage(PNP_CM_PNP_OS_ACTIVE);
1314 DPRINTF(("pnpbios: os active returns 0x%02x\n", rv));
1315 }
1316
1317 config_pending_decr();
1318
1319 goto start;
1320 while (sc->sc_threadrun) {
1321 /* maybe we have an event */
1322 if (!poll)
1323 (void)tsleep(pnpbios_event_thread, PWAIT,
1324 "pnpbiosevent", 0);
1325 else if (((evflag = *sc->sc_evaddr) & 0x01) == 0) {
1326 if (evflag)
1327 DPRINTF(("pnpbios: evflags 0x%02x\n", evflag));
1328 (void)tsleep(pnpbios_event_thread, PWAIT,
1329 "pnpbiosevent", poll);
1330 continue;
1331 } else {
1332 DPRINTF(("pnpbios: evflags 0x%02x\n", evflag));
1333 }
1334 start:
1335 if ((rv = pnpbios_getevent(&event))) {
1336 DPRINTF(("pnpbios: getevent rc: 0x%02x\n", rv));
1337 #ifdef DIAGNOSTIC
1338 if (rv != PNP_RC_EVENTS_NOT_PENDING)
1339 printf("pnpbios: getevent failed: %d\n", rv);
1340 #endif
1341 continue;
1342 }
1343 switch (event) {
1344 case PNP_EID_ABOUT_TO_CHANGE_CONFIG:
1345 DPRINTF(("pnpbios: about to change event\n"));
1346 break;
1347 case PNP_EID_DOCK_CHANGED:
1348 DPRINTF(("pnpbios: dock changed event\n"));
1349 break;
1350 case PNP_EID_SYSTEM_DEVICE_CHANGED:
1351 DPRINTF(("pnpbios: system device changed event\n"));
1352 break;
1353 case PNP_EID_CONFIG_CHANGE_FAILED:
1354 DPRINTF(("pnpbios: config changed event\n"));
1355 break;
1356 case PNP_EID_UNKNOWN_SYSTEM_EVENT:
1357 #ifdef DIAGNOSTIC
1358 printf("pnpbios: \"unknown system event\"\n");
1359 #endif
1360 break;
1361 default:
1362 #ifdef DIAGNOSTIC
1363 #ifdef PNPBIOSVERBOSE
1364 if (event & PNP_EID_OEM_DEFINED_BIT)
1365 printf("pnpbios: vendor defined event 0x%04x\n",
1366 event);
1367 else
1368 #endif
1369 printf("pnpbios: unkown event 0x%04x\n",
1370 event);
1371 #endif
1372 break;
1373 }
1374 }
1375
1376 pnpbios_sendmessage(PNP_CM_PNP_OS_INACTIVE);
1377 kthread_exit(0);
1378 }
1379 #endif /* PNPBIOSEVENTS */
1380
1381