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