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