xref: /netbsd-src/sys/dev/acpi/acpi.c (revision 37b34d511dea595d3ba03a661cf3b775038ea5f8)
1 /*	$NetBSD: acpi.c,v 1.18 2002/10/02 16:33:35 thorpej Exp $	*/
2 
3 /*
4  * Copyright 2001 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
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  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed for the NetBSD Project by
20  *	Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * Autoconfiguration support for the Intel ACPI Component Architecture
40  * ACPI reference implementation.
41  */
42 
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.18 2002/10/02 16:33:35 thorpej Exp $");
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49 #include <sys/malloc.h>
50 
51 #include <dev/acpi/acpica.h>
52 #include <dev/acpi/acpireg.h>
53 #include <dev/acpi/acpivar.h>
54 #include <dev/acpi/acpi_osd.h>
55 
56 #ifndef ACPI_PCI_FIXUP
57 #define ACPI_PCI_FIXUP 1
58 #endif
59 
60 #ifndef ACPI_ACTIVATE_DEV
61 #define ACPI_ACTIVATE_DEV 0
62 #endif
63 
64 #if ACPI_PCI_FIXUP
65 #include <dev/acpi/acpica/Subsystem/acnamesp.h> /* AcpiNsGetNodeByPath() */
66 #include <dev/pci/pcidevs.h>
67 #endif
68 
69 #include <machine/acpi_machdep.h>
70 
71 #ifdef ENABLE_DEBUGGER
72 #define	ACPI_DBGR_INIT		0x01
73 #define	ACPI_DBGR_TABLES	0x02
74 #define	ACPI_DBGR_ENABLE	0x04
75 #define	ACPI_DBGR_PROBE		0x08
76 #define	ACPI_DBGR_RUNNING	0x10
77 
78 int	acpi_dbgr = 0x00;
79 #endif
80 
81 int	acpi_match(struct device *, struct cfdata *, void *);
82 void	acpi_attach(struct device *, struct device *, void *);
83 
84 int	acpi_print(void *aux, const char *);
85 
86 extern struct cfdriver acpi_cd;
87 
88 CFATTACH_DECL(acpi, sizeof(struct acpi_softc),
89     acpi_match, acpi_attach, NULL, NULL);
90 
91 /*
92  * This is a flag we set when the ACPI subsystem is active.  Machine
93  * dependent code may wish to skip other steps (such as attaching
94  * subsystems that ACPI supercedes) when ACPI is active.
95  */
96 int	acpi_active;
97 
98 /*
99  * Pointer to the ACPI subsystem's state.  There can be only
100  * one ACPI instance.
101  */
102 struct acpi_softc *acpi_softc;
103 
104 void		acpi_shutdown(void *);
105 ACPI_STATUS	acpi_disable(struct acpi_softc *sc);
106 void		acpi_build_tree(struct acpi_softc *);
107 ACPI_STATUS	acpi_make_devnode(ACPI_HANDLE, UINT32, void *, void **);
108 
109 void		acpi_enable_fixed_events(struct acpi_softc *);
110 #if ACPI_PCI_FIXUP
111 void		acpi_pci_fixup(struct acpi_softc *);
112 #endif
113 #if ACPI_PCI_FIXUP || ACPI_ACTIVATE_DEV
114 ACPI_STATUS	acpi_allocate_resources(ACPI_HANDLE handle);
115 #endif
116 
117 /*
118  * acpi_probe:
119  *
120  *	Probe for ACPI support.  This is called by the
121  *	machine-dependent ACPI front-end.  All of the
122  *	actual work is done by ACPICA.
123  *
124  *	NOTE: This is not an autoconfiguration interface function.
125  */
126 int
127 acpi_probe(void)
128 {
129 	static int beenhere;
130 	ACPI_STATUS rv;
131 
132 	if (beenhere != 0)
133 		panic("acpi_probe: ACPI has already been probed");
134 	beenhere = 1;
135 
136 	/*
137 	 * Start up ACPICA.
138 	 */
139 #ifdef ENABLE_DEBUGGER
140 	if (acpi_dbgr & ACPI_DBGR_INIT)
141 		acpi_osd_debugger();
142 #endif
143 
144 	rv = AcpiInitializeSubsystem();
145 	if (rv != AE_OK) {
146 		printf("ACPI: unable to initialize ACPICA: %d\n", rv);
147 		return (0);
148 	}
149 
150 #ifdef ENABLE_DEBUGGER
151 	if (acpi_dbgr & ACPI_DBGR_TABLES)
152 		acpi_osd_debugger();
153 #endif
154 
155 	rv = AcpiLoadTables();
156 	if (rv != AE_OK) {
157 		printf("ACPI: unable to load tables: %d\n", rv);
158 		return (0);
159 	}
160 
161 	/*
162 	 * Looks like we have ACPI!
163 	 */
164 
165 	return (1);
166 }
167 
168 /*
169  * acpi_match:
170  *
171  *	Autoconfiguration `match' routine.
172  */
173 int
174 acpi_match(struct device *parent, struct cfdata *match, void *aux)
175 {
176 	struct acpibus_attach_args *aa = aux;
177 
178 	if (strcmp(aa->aa_busname, acpi_cd.cd_name) != 0)
179 		return (0);
180 
181 	/*
182 	 * XXX Check other locators?  Hard to know -- machine
183 	 * dependent code has already checked for the presence
184 	 * of ACPI by calling acpi_probe(), so I suppose we
185 	 * don't really have to do anything else.
186 	 */
187 	return (1);
188 }
189 
190 /*
191  * acpi_attach:
192  *
193  *	Autoconfiguration `attach' routine.  Finish initializing
194  *	ACPICA (some initialization was done in acpi_probe(),
195  *	which was required to check for the presence of ACPI),
196  *	and enable the ACPI subsystem.
197  */
198 void
199 acpi_attach(struct device *parent, struct device *self, void *aux)
200 {
201 	struct acpi_softc *sc = (void *) self;
202 	struct acpibus_attach_args *aa = aux;
203 	ACPI_STATUS rv;
204 
205 	printf("\n");
206 
207 	if (acpi_softc != NULL)
208 		panic("acpi_attach: ACPI has already been attached");
209 
210 	sc->sc_iot = aa->aa_iot;
211 	sc->sc_memt = aa->aa_memt;
212 	sc->sc_pc = aa->aa_pc;
213 	sc->sc_pciflags = aa->aa_pciflags;
214 
215 	acpi_softc = sc;
216 
217 	/*
218 	 * Install the default address space handlers.
219 	 */
220 
221 	rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
222 	    ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL);
223 	if (rv != AE_OK) {
224 		printf("%s: unable to install SYSTEM MEMORY handler: %d\n",
225 		    sc->sc_dev.dv_xname, rv);
226 		return;
227 	}
228 
229 	rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
230 	    ACPI_ADR_SPACE_SYSTEM_IO, ACPI_DEFAULT_HANDLER, NULL, NULL);
231 	if (rv != AE_OK) {
232 		printf("%s: unable to install SYSTEM IO handler: %d\n",
233 		    sc->sc_dev.dv_xname, rv);
234 		return;
235 	}
236 
237 	rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
238 	    ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
239 	if (rv != AE_OK) {
240 		printf("%s: unable to install PCI CONFIG handler: %d\n",
241 		    sc->sc_dev.dv_xname, rv);
242 		return;
243 	}
244 
245 	/*
246 	 * Bring ACPI on-line.
247 	 *
248 	 * Note that we request that _STA (device init) and _INI (object init)
249 	 * methods not be run.
250 	 *
251 	 * XXX We need to arrange for the object init pass after we have
252 	 * XXX attached all of our children.
253 	 */
254 #ifdef ENABLE_DEBUGGER
255 	if (acpi_dbgr & ACPI_DBGR_ENABLE)
256 		acpi_osd_debugger();
257 #endif
258 	rv = AcpiEnableSubsystem(ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT);
259 	if (rv != AE_OK) {
260 		printf("%s: unable to enable ACPI: %d\n",
261 		    sc->sc_dev.dv_xname, rv);
262 		return;
263 	}
264 	acpi_active = 1;
265 
266 	/*
267 	 * Set up the default sleep state to enter when various
268 	 * switches are activated.
269 	 */
270 	sc->sc_switch_sleep[ACPI_SWITCH_POWERBUTTON] = ACPI_STATE_S5;
271 	sc->sc_switch_sleep[ACPI_SWITCH_SLEEPBUTTON] = ACPI_STATE_S1;
272 	sc->sc_switch_sleep[ACPI_SWITCH_LID]	     = ACPI_STATE_S1;
273 
274 	/* Our current state is "awake". */
275 	sc->sc_sleepstate = ACPI_STATE_S0;
276 
277 	/* Show SCI interrupt. */
278 	if (AcpiGbl_FADT != NULL)
279 		printf("%s: SCI interrupting at irq %d\n",
280 			sc->sc_dev.dv_xname, AcpiGbl_FADT->SciInt);
281 	/*
282 	 * Check for fixed-hardware features.
283 	 */
284 	acpi_enable_fixed_events(sc);
285 
286 	/*
287 	 * Fix up PCI devices.
288 	 */
289 #if ACPI_PCI_FIXUP
290 	acpi_pci_fixup(sc);
291 #endif
292 
293 	/*
294 	 * Scan the namespace and build our device tree.
295 	 */
296 #ifdef ENABLE_DEBUGGER
297 	if (acpi_dbgr & ACPI_DBGR_PROBE)
298 		acpi_osd_debugger();
299 #endif
300 	acpi_build_tree(sc);
301 
302 	/*
303 	 * Register a shutdown hook that disables certain ACPI
304 	 * events that might happen and confuse us while we're
305 	 * trying to shut down.
306 	 */
307 	sc->sc_sdhook = shutdownhook_establish(acpi_shutdown, sc);
308 	if (sc->sc_sdhook == NULL)
309 		printf("%s: WARNING: unable to register shutdown hook\n",
310 		    sc->sc_dev.dv_xname);
311 
312 #ifdef ENABLE_DEBUGGER
313 	if (acpi_dbgr & ACPI_DBGR_RUNNING)
314 		acpi_osd_debugger();
315 #endif
316 }
317 
318 /*
319  * acpi_shutdown:
320  *
321  *	Shutdown hook for ACPI -- disable some events that
322  *	might confuse us.
323  */
324 void
325 acpi_shutdown(void *arg)
326 {
327 	struct acpi_softc *sc = arg;
328 
329 	if (acpi_disable(sc) != AE_OK)
330 		printf("%s: WARNING: unable to disable ACPI\n",
331 		    sc->sc_dev.dv_xname);
332 }
333 
334 /*
335  * acpi_disable:
336  *
337  *	Disable ACPI.
338  */
339 ACPI_STATUS
340 acpi_disable(struct acpi_softc *sc)
341 {
342 	ACPI_STATUS rv = AE_OK;
343 
344 	if (acpi_active) {
345 		rv = AcpiDisable();
346 		if (rv == AE_OK)
347 			acpi_active = 0;
348 	}
349 	return (rv);
350 }
351 
352 struct acpi_make_devnode_state {
353 	struct acpi_softc *softc;
354 	struct acpi_scope *scope;
355 };
356 
357 /*
358  * acpi_build_tree:
359  *
360  *	Scan relevant portions of the ACPI namespace and attach
361  *	child devices.
362  */
363 void
364 acpi_build_tree(struct acpi_softc *sc)
365 {
366 	static const char *scopes[] = {
367 		"\\_PR_",	/* ACPI 1.0 processor namespace */
368 		"\\_SB_",	/* system bus namespace */
369 		"\\_SI_",	/* system idicator namespace */
370 		"\\_TZ_",	/* ACPI 1.0 thermal zone namespace */
371 		NULL,
372 	};
373 	struct acpi_attach_args aa;
374 	struct acpi_make_devnode_state state;
375 	struct acpi_scope *as;
376 	struct acpi_devnode *ad;
377 	ACPI_HANDLE parent;
378 	int i;
379 
380 	TAILQ_INIT(&sc->sc_scopes);
381 
382 	state.softc = sc;
383 
384 	/*
385 	 * Scan the namespace and build our tree.
386 	 */
387 	for (i = 0; scopes[i] != NULL; i++) {
388 		as = malloc(sizeof(*as), M_DEVBUF, M_WAITOK);
389 		as->as_name = scopes[i];
390 		TAILQ_INIT(&as->as_devnodes);
391 
392 		TAILQ_INSERT_TAIL(&sc->sc_scopes, as, as_list);
393 
394 		state.scope = as;
395 
396 		if (AcpiGetHandle(ACPI_ROOT_OBJECT, (char *) scopes[i],
397 		    &parent) == AE_OK) {
398 			AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100,
399 			    acpi_make_devnode, &state, NULL);
400 		}
401 
402 		/* Now, for this namespace, try and attach the devices. */
403 		TAILQ_FOREACH(ad, &as->as_devnodes, ad_list) {
404 			aa.aa_node = ad;
405 			aa.aa_iot = sc->sc_iot;
406 			aa.aa_memt = sc->sc_memt;
407 			aa.aa_pc = sc->sc_pc;
408 			aa.aa_pciflags = sc->sc_pciflags;
409 
410 			/*
411 			 * XXX We only attach devices which are:
412 			 *
413 			 *	- present
414 			 *	- enabled
415 			 *	- functioning properly
416 			 *
417 			 * However, if enabled, it's decoding resources,
418 			 * so we should claim them, if possible.  Requires
419 			 * changes to bus_space(9).
420 			 */
421 			if ((ad->ad_devinfo.CurrentStatus &
422 			     (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED|
423 			      ACPI_STA_DEV_OK)) !=
424 			    (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED|
425 			     ACPI_STA_DEV_OK))
426 				continue;
427 
428 			/*
429 			 * XXX Same problem as above...
430 			 */
431 			if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0)
432 				continue;
433 
434 			ad->ad_device = config_found(&sc->sc_dev,
435 			    &aa, acpi_print);
436 		}
437 	}
438 }
439 
440 #if ACPI_ACTIVATE_DEV
441 static void
442 acpi_activate_device(ACPI_HANDLE handle, ACPI_DEVICE_INFO *di)
443 {
444 	ACPI_STATUS rv;
445 
446 #ifdef ACPI_DEBUG
447 	printf("acpi_activate_device: %s, old status=%x\n",
448 	       di->HardwareId, di->CurrentStatus);
449 #endif
450 
451 	rv = acpi_allocate_resources(handle);
452 	if (ACPI_FAILURE(rv)) {
453 		printf("acpi: activate failed for %s\n", di->HardwareId);
454 	}
455 
456 	(void)AcpiGetObjectInfo(handle, di);
457 #ifdef ACPI_DEBUG
458 	printf("acpi_activate_device: %s, new status=%x\n",
459 	       di->HardwareId, di->CurrentStatus);
460 #endif
461 }
462 #endif /* ACPI_ACTIVATE_DEV */
463 
464 /*
465  * acpi_make_devnode:
466  *
467  *	Make an ACPI devnode.
468  */
469 ACPI_STATUS
470 acpi_make_devnode(ACPI_HANDLE handle, UINT32 level, void *context,
471     void **status)
472 {
473 	struct acpi_make_devnode_state *state = context;
474 #ifdef ACPI_DEBUG
475 	struct acpi_softc *sc = state->softc;
476 #endif
477 	struct acpi_scope *as = state->scope;
478 	struct acpi_devnode *ad;
479 	ACPI_DEVICE_INFO devinfo;
480 	ACPI_OBJECT_TYPE type;
481 	ACPI_STATUS rv;
482 
483 	if (AcpiGetType(handle, &type) == AE_OK) {
484 		rv = AcpiGetObjectInfo(handle, &devinfo);
485 		if (rv != AE_OK) {
486 #ifdef ACPI_DEBUG
487 			printf("%s: AcpiGetObjectInfo failed\n",
488 			    sc->sc_dev.dv_xname);
489 #endif
490 			goto out; /* XXX why return OK */
491 		}
492 
493 		switch (type) {
494 		case ACPI_TYPE_DEVICE:
495 #if ACPI_ACTIVATE_DEV
496 			if ((devinfo.Valid & ACPI_VALID_STA) &&
497 			    (devinfo.CurrentStatus &
498 			     (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED)) ==
499 			    ACPI_STA_DEV_PRESENT)
500 				acpi_activate_device(handle, &devinfo);
501 			/* FALLTHROUGH */
502 #endif
503 
504 		case ACPI_TYPE_PROCESSOR:
505 		case ACPI_TYPE_THERMAL:
506 		case ACPI_TYPE_POWER:
507 			ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT|M_ZERO);
508 			if (ad == NULL)
509 				return (AE_NO_MEMORY);
510 
511 			ad->ad_handle = handle;
512 			ad->ad_level = level;
513 			ad->ad_scope = as;
514 			ad->ad_type = type;
515 
516 			TAILQ_INSERT_TAIL(&as->as_devnodes, ad, ad_list);
517 
518 			rv = AcpiGetObjectInfo(handle, &ad->ad_devinfo);
519 			if (rv != AE_OK)
520 				goto out;
521 
522 			if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0)
523 				goto out;
524 
525 #ifdef ACPI_EXTRA_DEBUG
526 			printf("%s: HID %s found in scope %s level %d\n",
527 			    sc->sc_dev.dv_xname, ad->ad_devinfo.HardwareId,
528 			    as->as_name, ad->ad_level);
529 			if (ad->ad_devinfo.Valid & ACPI_VALID_UID)
530 				printf("       UID %s\n",
531 				    ad->ad_devinfo.UniqueId);
532 			if (ad->ad_devinfo.Valid & ACPI_VALID_ADR)
533 				printf("       ADR 0x%016qx\n",
534 				    ad->ad_devinfo.Address);
535 			if (ad->ad_devinfo.Valid & ACPI_VALID_STA)
536 				printf("       STA 0x%08x\n",
537 				    ad->ad_devinfo.CurrentStatus);
538 #endif
539 		}
540 	}
541  out:
542 	return (AE_OK);
543 }
544 
545 /*
546  * acpi_print:
547  *
548  *	Autoconfiguration print routine.
549  */
550 int
551 acpi_print(void *aux, const char *pnp)
552 {
553 	struct acpi_attach_args *aa = aux;
554 #if 0
555 	char *str;
556 #endif
557 
558 	if (pnp) {
559 		printf("%s ", aa->aa_node->ad_devinfo.HardwareId);
560 #if 0 /* Not until we fix acpi_eval_string */
561 		if (acpi_eval_string(aa->aa_node->ad_handle,
562 		    "_STR", &str) == AE_OK) {
563 			printf("[%s] ", str);
564 			AcpiOsFree(str);
565 		}
566 #endif
567 		printf("at %s", pnp);
568 	}
569 
570 	return (UNCONF);
571 }
572 
573 /*****************************************************************************
574  * ACPI fixed-hardware feature handlers
575  *****************************************************************************/
576 
577 UINT32		acpi_fixed_power_button_handler(void *);
578 UINT32		acpi_fixed_sleep_button_handler(void *);
579 
580 /*
581  * acpi_enable_fixed_events:
582  *
583  *	Enable any fixed-hardware feature handlers.
584  */
585 void
586 acpi_enable_fixed_events(struct acpi_softc *sc)
587 {
588 	static int beenhere;
589 	ACPI_STATUS rv;
590 
591 	/*
592 	 * Check for fixed-hardware buttons.
593 	 */
594 
595 	if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) {
596 		if (beenhere == 0)
597 			printf("%s: fixed-feature power button present\n",
598 			    sc->sc_dev.dv_xname);
599 		rv = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
600 		    acpi_fixed_power_button_handler, sc);
601 		if (rv != AE_OK)
602 			printf("%s: unable to install handler for fixed "
603 			    "power button: %d\n", sc->sc_dev.dv_xname, rv);
604 	}
605 
606 	if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) {
607 		if (beenhere == 0)
608 			printf("%s: fixed-feature sleep button present\n",
609 			    sc->sc_dev.dv_xname);
610 		rv = AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON,
611 		    acpi_fixed_sleep_button_handler, sc);
612 		if (rv != AE_OK)
613 			printf("%s: unable to install handler for fixed "
614 			    "power button: %d\n", sc->sc_dev.dv_xname, rv);
615 	}
616 
617 	beenhere = 1;
618 }
619 
620 /*
621  * acpi_fixed_power_button_handler:
622  *
623  *	Fixed event handler for the power button.
624  */
625 UINT32
626 acpi_fixed_power_button_handler(void *context)
627 {
628 	struct acpi_softc *sc = context;
629 
630 	/* XXX XXX XXX */
631 
632 	printf("%s: fixed power button pressed\n", sc->sc_dev.dv_xname);
633 
634 	return (ACPI_INTERRUPT_HANDLED);
635 }
636 
637 /*
638  * acpi_fixed_sleep_button_handler:
639  *
640  *	Fixed event handler for the sleep button.
641  */
642 UINT32
643 acpi_fixed_sleep_button_handler(void *context)
644 {
645 	struct acpi_softc *sc = context;
646 
647 	/* XXX XXX XXX */
648 
649 	printf("%s: fixed sleep button pressed\n", sc->sc_dev.dv_xname);
650 
651 	return (ACPI_INTERRUPT_HANDLED);
652 }
653 
654 /*****************************************************************************
655  * ACPI utility routines.
656  *****************************************************************************/
657 
658 /*
659  * acpi_eval_integer:
660  *
661  *	Evaluate an integer object.
662  */
663 ACPI_STATUS
664 acpi_eval_integer(ACPI_HANDLE handle, char *path, int *valp)
665 {
666 	ACPI_STATUS rv;
667 	ACPI_BUFFER buf;
668 	ACPI_OBJECT param;
669 
670 	if (handle == NULL)
671 		handle = ACPI_ROOT_OBJECT;
672 
673 	buf.Pointer = &param;
674 	buf.Length = sizeof(param);
675 
676 	rv = AcpiEvaluateObject(handle, path, NULL, &buf);
677 	if (rv == AE_OK) {
678 		if (param.Type == ACPI_TYPE_INTEGER)
679 			*valp = param.Integer.Value;
680 		else
681 			rv = AE_TYPE;
682 	}
683 
684 	return (rv);
685 }
686 
687 #if 0
688 /*
689  * acpi_eval_string:
690  *
691  *	Evaluate a (Unicode) string object.
692  * XXX current API may leak memory, so don't use this.
693  */
694 ACPI_STATUS
695 acpi_eval_string(ACPI_HANDLE handle, char *path, char **stringp)
696 {
697 	ACPI_STATUS rv;
698 	ACPI_BUFFER buf;
699 	ACPI_OBJECT *param;
700 
701 	if (handle == NULL)
702 		handle = ACPI_ROOT_OBJECT;
703 
704 	buf.Pointer = NULL;
705 	buf.Length = 0;
706 
707 	rv = AcpiEvaluateObject(handle, path, NULL, &buf);
708 	if (rv != AE_BUFFER_OVERFLOW)
709 		return (rv);
710 
711 	buf.Pointer = AcpiOsAllocate(buf.Length);
712 	if (buf.Pointer == NULL)
713 		return (AE_NO_MEMORY);
714 
715 	rv = AcpiEvaluateObject(handle, path, NULL, &buf);
716 	param = (ACPI_OBJECT *)buf.Pointer;
717 	if (rv == AE_OK) {
718 		if (param->Type == ACPI_TYPE_STRING) {
719 			/* XXX may leak buf.Pointer!! */
720 			*stringp = param->String.Pointer;
721 			return (AE_OK);
722 		}
723 		rv = AE_TYPE;
724 	}
725 
726 	AcpiOsFree(buf.Pointer);
727 	return (rv);
728 }
729 #endif
730 
731 
732 /*
733  * acpi_eval_struct:
734  *
735  *	Evaluate a more complex structure.  Caller must free buf.Pointer.
736  */
737 ACPI_STATUS
738 acpi_eval_struct(ACPI_HANDLE handle, char *path, ACPI_BUFFER *bufp)
739 {
740 	ACPI_STATUS rv;
741 
742 	if (handle == NULL)
743 		handle = ACPI_ROOT_OBJECT;
744 
745 	bufp->Pointer = NULL;
746 	bufp->Length = 0;
747 
748 	rv = AcpiEvaluateObject(handle, path, NULL, bufp);
749 	if (rv != AE_BUFFER_OVERFLOW)
750 		return (rv);
751 
752 	bufp->Pointer = AcpiOsAllocate(bufp->Length);
753 	if (bufp->Pointer == NULL)
754 		return (AE_NO_MEMORY);
755 
756 	rv = AcpiEvaluateObject(handle, path, NULL, bufp);
757 
758 	return (rv);
759 }
760 
761 /*
762  * acpi_get:
763  *
764  *	Fetch data info the specified (empty) ACPI buffer.
765  */
766 ACPI_STATUS
767 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf,
768     ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *))
769 {
770 	ACPI_STATUS rv;
771 
772 	buf->Pointer = NULL;
773 	buf->Length = 0;
774 
775 	rv = (*getit)(handle, buf);
776 	if (rv != AE_BUFFER_OVERFLOW)
777 		return (rv);
778 
779 	buf->Pointer = AcpiOsAllocate(buf->Length);
780 	if (buf->Pointer == NULL)
781 		return (AE_NO_MEMORY);
782 	memset(buf->Pointer, 0, buf->Length);
783 
784 	return ((*getit)(handle, buf));
785 }
786 
787 
788 /*****************************************************************************
789  * ACPI sleep support.
790  *****************************************************************************/
791 
792 static int
793 is_available_state(struct acpi_softc *sc, int state)
794 {
795 	UINT8 type_a, type_b;
796 
797 	return (ACPI_SUCCESS(AcpiGetSleepTypeData((UINT8)state,
798 						  &type_a, &type_b)));
799 }
800 
801 /*
802  * acpi_enter_sleep_state:
803  *
804  *	enter to the specified sleep state.
805  */
806 
807 ACPI_STATUS
808 acpi_enter_sleep_state(struct acpi_softc *sc, int state)
809 {
810 	int s;
811 	ACPI_STATUS ret = AE_OK;
812 
813 	switch (state) {
814 	case ACPI_STATE_S0:
815 		break;
816 	case ACPI_STATE_S1:
817 	case ACPI_STATE_S2:
818 	case ACPI_STATE_S3:
819 	case ACPI_STATE_S4:
820 		if (!is_available_state(sc, state)) {
821 			printf("acpi: cannot enter the sleep state (%d).\n",
822 			       state);
823 			break;
824 		}
825 		ret = AcpiEnterSleepStatePrep(state);
826 		if (ACPI_FAILURE(ret)) {
827 			printf("acpi: failed preparing to sleep (%s)\n",
828 			       AcpiFormatException(ret));
829 			break;
830 		}
831 		if (state==ACPI_STATE_S1) {
832 			/* just enter the state */
833 			acpi_md_OsDisableInterrupt();
834 			AcpiEnterSleepState((UINT8)state);
835 			AcpiUtReleaseMutex(ACPI_MTX_HARDWARE);
836 		} else {
837 			/* XXX: powerhooks(9) framework is too poor to
838 			 * support ACPI sleep state...
839 			 */
840 			dopowerhooks(PWR_SOFTSUSPEND);
841 			s = splhigh();
842 			dopowerhooks(PWR_SUSPEND);
843 			acpi_md_sleep(state);
844 			dopowerhooks(PWR_RESUME);
845 			splx(s);
846 			dopowerhooks(PWR_SOFTRESUME);
847 			if (state==ACPI_STATE_S4)
848 				AcpiEnable();
849 		}
850 		AcpiLeaveSleepState((UINT8)state);
851 		break;
852 	case ACPI_STATE_S5:
853 		AcpiEnterSleepStatePrep(ACPI_STATE_S5);
854 		acpi_md_OsDisableInterrupt();
855 		AcpiEnterSleepState(ACPI_STATE_S5);
856 		printf("WARNING: powerdown failed!\n");
857 		break;
858 	}
859 
860 	return (ret);
861 }
862 
863 #if ACPI_PCI_FIXUP
864 ACPI_STATUS acpi_pci_fixup_bus(ACPI_HANDLE, UINT32, void *, void **);
865 /*
866  * acpi_pci_fixup:
867  *
868  *	Set up PCI devices that BIOS didn't handle right.
869  *	Iterate through all devices and try to get the _PTR
870  *	(PCI Routing Table).  If it exists then make sure all
871  *	interrupt links that it uses are working.
872  */
873 void
874 acpi_pci_fixup(struct acpi_softc *sc)
875 {
876 	ACPI_HANDLE parent;
877 
878 #ifdef ACPI_DEBUG
879 	printf("acpi_pci_fixup starts:\n");
880 #endif
881 	if (AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent) != AE_OK)
882 		return;
883 	sc->sc_pci_bus = 0;
884 	AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100,
885 	    acpi_pci_fixup_bus, sc, NULL);
886 }
887 
888 static ACPI_HANDLE
889 acpi_get_node(char *name)
890 {
891 	ACPI_NAMESPACE_NODE *ObjDesc;
892 	ACPI_STATUS Status;
893 
894 	Status = AcpiNsGetNodeByPath(name, NULL, 0, &ObjDesc);
895 	if (ACPI_FAILURE (Status)) {
896 		printf("acpi_get_node: could not find: %s\n",
897 		       AcpiFormatException (Status));
898 		return NULL;
899 	}
900 	return ObjDesc;
901 }
902 
903 static uint
904 acpi_get_intr(ACPI_HANDLE handle)
905 {
906 	ACPI_BUFFER ret;
907 	ACPI_STATUS rv;
908 	ACPI_RESOURCE *res;
909 	ACPI_RESOURCE_IRQ *irq;
910 	uint intr;
911 
912 	intr = -1;
913 	rv = acpi_get(handle, &ret, AcpiGetCurrentResources);
914 	if (ACPI_FAILURE(rv))
915 		return (intr);
916 	for (res = ret.Pointer; res->Id != ACPI_RSTYPE_END_TAG;
917 	     res = ACPI_NEXT_RESOURCE(res)) {
918 		if (res->Id == ACPI_RSTYPE_IRQ) {
919 			irq = (ACPI_RESOURCE_IRQ *)&res->Data;
920 			if (irq->NumberOfInterrupts == 1)
921 				intr = irq->Interrupts[0];
922 			break;
923 		}
924 	}
925 	free(ret.Pointer, M_DEVBUF);
926 	return (intr);
927 }
928 
929 static void
930 acpi_pci_set_line(int bus, int dev, int pin, int line)
931 {
932 	ACPI_STATUS err;
933 	ACPI_PCI_ID pid;
934 	UINT32 intr, id, bhlc;
935 	int func, nfunc;
936 
937 	pid.Bus = bus;
938 	pid.Device = dev;
939 	pid.Function = 0;
940 
941 	err = AcpiOsReadPciConfiguration(&pid, PCI_BHLC_REG, &bhlc, 32);
942 	if (err)
943 		return;
944 	if (PCI_HDRTYPE_MULTIFN(bhlc))
945 		nfunc = 8;
946 	else
947 		nfunc = 1;
948 
949 	for (func = 0; func < nfunc; func++) {
950 		pid.Function = func;
951 
952 		err = AcpiOsReadPciConfiguration(&pid, PCI_ID_REG, &id, 32);
953 		if (err || PCI_VENDOR(id) == PCI_VENDOR_INVALID ||
954 		    PCI_VENDOR(id) == 0)
955 			continue;
956 
957 		err = AcpiOsReadPciConfiguration(&pid, PCI_INTERRUPT_REG,
958 			  &intr, 32);
959 		if (err) {
960 			printf("AcpiOsReadPciConfiguration failed %d\n", err);
961 			return;
962 		}
963 		if (pin == PCI_INTERRUPT_PIN(intr) &&
964 		    line != PCI_INTERRUPT_LINE(intr)) {
965 #ifdef ACPI_DEBUG
966 			printf("acpi fixup pci intr: %d:%d:%d %c: %d -> %d\n",
967 			       bus, dev, func,
968 			       pin + '@', PCI_INTERRUPT_LINE(intr),
969 			       line);
970 #endif
971 			intr &= ~(PCI_INTERRUPT_LINE_MASK <<
972 				  PCI_INTERRUPT_LINE_SHIFT);
973 			intr |= line << PCI_INTERRUPT_LINE_SHIFT;
974 			err = AcpiOsWritePciConfiguration(&pid,
975 				  PCI_INTERRUPT_REG, intr, 32);
976 			if (err) {
977 				printf("AcpiOsWritePciConfiguration failed"
978 				       " %d\n", err);
979 				return;
980 			}
981 		}
982 	}
983 }
984 
985 ACPI_STATUS
986 acpi_pci_fixup_bus(ACPI_HANDLE handle, UINT32 level, void *context,
987 		   void **status)
988 {
989 	struct acpi_softc *sc = context;
990 	ACPI_STATUS rv;
991 	ACPI_BUFFER buf;
992 	UINT8 *Buffer;
993 	ACPI_PCI_ROUTING_TABLE *PrtElement;
994 	ACPI_HANDLE link;
995 	uint line;
996 
997 	rv = acpi_get(handle, &buf, AcpiGetIrqRoutingTable);
998 	if (ACPI_FAILURE(rv))
999 		return (AE_OK);
1000 
1001 #ifdef ACPI_DEBUG
1002 	printf("%s: fixing up PCI\n", sc->sc_dev.dv_xname);
1003 #endif
1004 
1005         for (Buffer = buf.Pointer; ; Buffer += PrtElement->Length) {
1006 		PrtElement = (ACPI_PCI_ROUTING_TABLE *)Buffer;
1007 		if (PrtElement->Length == 0)
1008 			break;
1009 		if (PrtElement->Source == NULL)
1010 			continue;
1011 
1012 		link = acpi_get_node(PrtElement->Source);
1013 		if (link == NULL)
1014 			continue;
1015 		line = acpi_get_intr(link);
1016 		if (line == -1) {
1017 #ifdef ACPI_DEBUG
1018 			printf("%s: fixing up link %s\n", sc->sc_dev.dv_xname,
1019 			    PrtElement->Source);
1020 #endif
1021 			rv = acpi_allocate_resources(link);
1022 			if (ACPI_FAILURE(rv)) {
1023 				printf("%s: interrupt allocation failed %s\n",
1024 				    sc->sc_dev.dv_xname, PrtElement->Source);
1025 				continue;
1026 			}
1027 			line = acpi_get_intr(link);
1028 			if (line == -1) {
1029 				printf("%s: get intr failed %s\n",
1030 				    sc->sc_dev.dv_xname, PrtElement->Source);
1031 				continue;
1032 			}
1033 		}
1034 
1035 		acpi_pci_set_line(sc->sc_pci_bus, PrtElement->Address >> 16,
1036 		    PrtElement->Pin + 1, line);
1037 	}
1038 
1039 	sc->sc_pci_bus++;
1040 
1041 	free(buf.Pointer, M_DEVBUF);
1042 	return (AE_OK);
1043 }
1044 #endif /* ACPI_PCI_FIXUP */
1045 
1046 #if ACPI_PCI_FIXUP || ACPI_ACTIVATE_DEV
1047 /* XXX This very incomplete */
1048 ACPI_STATUS
1049 acpi_allocate_resources(ACPI_HANDLE handle)
1050 {
1051 	ACPI_BUFFER bufp, bufc, bufn;
1052 	ACPI_RESOURCE *resp, *resc, *resn;
1053 	ACPI_RESOURCE_IRQ *irq;
1054 	ACPI_STATUS rv;
1055 	uint delta;
1056 
1057 	rv = acpi_get(handle, &bufp, AcpiGetPossibleResources);
1058 	if (ACPI_FAILURE(rv))
1059 		goto out;
1060 	rv = acpi_get(handle, &bufc, AcpiGetCurrentResources);
1061 	if (ACPI_FAILURE(rv)) {
1062 		goto out1;
1063 	}
1064 
1065 	bufn.Length = 1000;
1066 	bufn.Pointer = resn = malloc(bufn.Length, M_DEVBUF, M_WAITOK);
1067 	resp = bufp.Pointer;
1068 	resc = bufc.Pointer;
1069 	while (resc->Id != ACPI_RSTYPE_END_TAG &&
1070 	       resp->Id != ACPI_RSTYPE_END_TAG) {
1071 		while (resc->Id != resp->Id && resp->Id != ACPI_RSTYPE_END_TAG)
1072 			resp = ACPI_NEXT_RESOURCE(resp);
1073 		if (resp->Id == ACPI_RSTYPE_END_TAG)
1074 			break;
1075 		/* Found identical Id */
1076 		resn->Id = resc->Id;
1077 		switch (resc->Id) {
1078 		case ACPI_RSTYPE_IRQ:
1079 			memcpy(&resn->Data, &resp->Data,
1080 			       sizeof(ACPI_RESOURCE_IRQ));
1081 			irq = (ACPI_RESOURCE_IRQ *)&resn->Data;
1082 			irq->Interrupts[0] =
1083 			    ((ACPI_RESOURCE_IRQ *)&resp->Data)->
1084 			        Interrupts[irq->NumberOfInterrupts-1];
1085 			irq->NumberOfInterrupts = 1;
1086 			resn->Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
1087 			break;
1088 		case ACPI_RSTYPE_IO:
1089 			memcpy(&resn->Data, &resp->Data,
1090 			       sizeof(ACPI_RESOURCE_IO));
1091 			resn->Length = resp->Length;
1092 			break;
1093 		default:
1094 			printf("acpi_allocate_resources: res=%d\n", resc->Id);
1095 			rv = AE_BAD_DATA;
1096 			goto out2;
1097 		}
1098 		resc = ACPI_NEXT_RESOURCE(resc);
1099 		resn = ACPI_NEXT_RESOURCE(resn);
1100 		delta = (UINT8 *)resn - (UINT8 *)bufn.Pointer;
1101 		if (delta >= bufn.Length-ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_DATA)) {
1102 			bufn.Length *= 2;
1103 			bufn.Pointer = realloc(bufn.Pointer, bufn.Length,
1104 					       M_DEVBUF, M_WAITOK);
1105 			resn = (ACPI_RESOURCE *)((UINT8 *)bufn.Pointer + delta);
1106 		}
1107 	}
1108 	if (resc->Id != ACPI_RSTYPE_END_TAG) {
1109 		printf("acpi_allocate_resources: resc not exhausted\n");
1110 		rv = AE_BAD_DATA;
1111 		goto out3;
1112 	}
1113 
1114 	resn->Id = ACPI_RSTYPE_END_TAG;
1115 	rv = AcpiSetCurrentResources(handle, &bufn);
1116 	if (ACPI_FAILURE(rv)) {
1117 		printf("acpi_allocate_resources: AcpiSetCurrentResources %s\n",
1118 		       AcpiFormatException(rv));
1119 	}
1120 
1121 out3:
1122 	free(bufn.Pointer, M_DEVBUF);
1123 out2:
1124 	free(bufc.Pointer, M_DEVBUF);
1125 out1:
1126 	free(bufp.Pointer, M_DEVBUF);
1127 out:
1128 	return rv;
1129 }
1130 #endif /* ACPI_PCI_FIXUP || ACPI_ACTIVATE_DEV */
1131