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