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