acpi.c revision 1.54 1 /* $NetBSD: acpi.c,v 1.54 2003/11/03 06:03:47 kochi 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.54 2003/11/03 06:03:47 kochi 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 ACPI_BUFFER buf;
482
483 buf.Pointer = NULL;
484 buf.Length = ACPI_ALLOCATE_BUFFER;
485
486 #ifdef ACPI_DEBUG
487 printf("acpi_activate_device: %s, old status=%x\n",
488 (*di)->HardwareId.Value, (*di)->CurrentStatus);
489 #endif
490
491 rv = acpi_allocate_resources(handle);
492 if (ACPI_FAILURE(rv)) {
493 printf("acpi: activate failed for %s\n",
494 (*di)->HardwareId.Value);
495 } else {
496 printf("acpi: activated %s\n", (*di)->HardwareId.Value);
497 }
498
499 (void)AcpiGetObjectInfo(handle, &buf);
500 AcpiOsFree(*di);
501 *di = buf.Pointer;
502
503 #ifdef ACPI_DEBUG
504 printf("acpi_activate_device: %s, new status=%x\n",
505 (*di)->HardwareId.Value, (*di)->CurrentStatus);
506 #endif
507 }
508 #endif /* ACPI_ACTIVATE_DEV */
509
510 /*
511 * acpi_make_devnode:
512 *
513 * Make an ACPI devnode.
514 */
515 ACPI_STATUS
516 acpi_make_devnode(ACPI_HANDLE handle, UINT32 level, void *context,
517 void **status)
518 {
519 struct acpi_make_devnode_state *state = context;
520 #if defined(ACPI_DEBUG) || defined(ACPI_EXTRA_DEBUG)
521 struct acpi_softc *sc = state->softc;
522 #endif
523 struct acpi_scope *as = state->scope;
524 struct acpi_devnode *ad;
525 ACPI_OBJECT_TYPE type;
526 ACPI_BUFFER buf;
527 ACPI_DEVICE_INFO *devinfo;
528 ACPI_STATUS rv;
529
530 if (AcpiGetType(handle, &type) == AE_OK) {
531 buf.Pointer = NULL;
532 buf.Length = ACPI_ALLOCATE_BUFFER;
533 rv = AcpiGetObjectInfo(handle, &buf);
534 if (rv != AE_OK) {
535 #ifdef ACPI_DEBUG
536 printf("%s: AcpiGetObjectInfo failed\n",
537 sc->sc_dev.dv_xname);
538 #endif
539 goto out; /* XXX why return OK */
540 }
541
542 devinfo = buf.Pointer;
543
544 switch (type) {
545 case ACPI_TYPE_DEVICE:
546 #ifdef ACPI_ACTIVATE_DEV
547 if ((devinfo->Valid & (ACPI_VALID_STA|ACPI_VALID_HID)) ==
548 (ACPI_VALID_STA|ACPI_VALID_HID) &&
549 (devinfo->CurrentStatus &
550 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED)) ==
551 ACPI_STA_DEV_PRESENT)
552 acpi_activate_device(handle, &devinfo);
553
554 /* FALLTHROUGH */
555 #endif
556
557 case ACPI_TYPE_PROCESSOR:
558 case ACPI_TYPE_THERMAL:
559 case ACPI_TYPE_POWER:
560 ad = malloc(sizeof(*ad), M_ACPI, M_NOWAIT|M_ZERO);
561 if (ad == NULL)
562 return (AE_NO_MEMORY);
563
564 ad->ad_devinfo = devinfo;
565 ad->ad_handle = handle;
566 ad->ad_level = level;
567 ad->ad_scope = as;
568 ad->ad_type = type;
569
570 TAILQ_INSERT_TAIL(&as->as_devnodes, ad, ad_list);
571
572 if ((ad->ad_devinfo->Valid & ACPI_VALID_HID) == 0)
573 goto out;
574
575 #ifdef ACPI_EXTRA_DEBUG
576 printf("%s: HID %s found in scope %s level %d\n",
577 sc->sc_dev.dv_xname,
578 ad->ad_devinfo->HardwareId.Value,
579 as->as_name, ad->ad_level);
580 if (ad->ad_devinfo->Valid & ACPI_VALID_UID)
581 printf(" UID %s\n",
582 ad->ad_devinfo->UniqueId.Value);
583 if (ad->ad_devinfo->Valid & ACPI_VALID_ADR)
584 printf(" ADR 0x%016qx\n",
585 ad->ad_devinfo->Address);
586 if (ad->ad_devinfo->Valid & ACPI_VALID_STA)
587 printf(" STA 0x%08x\n",
588 ad->ad_devinfo->CurrentStatus);
589 #endif
590 }
591 }
592 out:
593 return (AE_OK);
594 }
595
596 /*
597 * acpi_print:
598 *
599 * Autoconfiguration print routine.
600 */
601 int
602 acpi_print(void *aux, const char *pnp)
603 {
604 struct acpi_attach_args *aa = aux;
605
606 if (pnp) {
607 if (aa->aa_node->ad_devinfo->Valid & ACPI_VALID_HID) {
608 char *pnpstr =
609 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_match_hid
868 *
869 * Match given ids against _HID and _CIDs
870 */
871 int
872 acpi_match_hid(ACPI_DEVICE_INFO *ad, const char * const *ids)
873 {
874 int i;
875
876 while (*ids) {
877 if ((ad->Valid & ACPI_VALID_HID) &&
878 strcmp(ad->HardwareId.Value, *ids) == 0)
879 return (1);
880
881 if (ad->Valid & ACPI_VALID_CID) {
882 for (i = 0; i < ad->CompatibilityId.Count; i++) {
883 if (strcmp(ad->CompatibilityId.Id[i].Value, *ids) == 0)
884 return (1);
885 }
886 }
887 ids++;
888 }
889
890 return (0);
891 }
892
893
894 /*****************************************************************************
895 * ACPI sleep support.
896 *****************************************************************************/
897
898 static int
899 is_available_state(struct acpi_softc *sc, int state)
900 {
901 UINT8 type_a, type_b;
902
903 return (ACPI_SUCCESS(AcpiGetSleepTypeData((UINT8)state,
904 &type_a, &type_b)));
905 }
906
907 /*
908 * acpi_enter_sleep_state:
909 *
910 * enter to the specified sleep state.
911 */
912
913 ACPI_STATUS
914 acpi_enter_sleep_state(struct acpi_softc *sc, int state)
915 {
916 int s;
917 ACPI_STATUS ret = AE_OK;
918
919 switch (state) {
920 case ACPI_STATE_S0:
921 break;
922 case ACPI_STATE_S1:
923 case ACPI_STATE_S2:
924 case ACPI_STATE_S3:
925 case ACPI_STATE_S4:
926 if (!is_available_state(sc, state)) {
927 printf("acpi: cannot enter the sleep state (%d).\n",
928 state);
929 break;
930 }
931 ret = AcpiEnterSleepStatePrep(state);
932 if (ACPI_FAILURE(ret)) {
933 printf("acpi: failed preparing to sleep (%s)\n",
934 AcpiFormatException(ret));
935 break;
936 }
937 if (state==ACPI_STATE_S1) {
938 /* just enter the state */
939 acpi_md_OsDisableInterrupt();
940 AcpiEnterSleepState((UINT8)state);
941 AcpiUtReleaseMutex(ACPI_MTX_HARDWARE);
942 } else {
943 /* XXX: powerhooks(9) framework is too poor to
944 * support ACPI sleep state...
945 */
946 dopowerhooks(PWR_SOFTSUSPEND);
947 s = splhigh();
948 dopowerhooks(PWR_SUSPEND);
949 acpi_md_sleep(state);
950 dopowerhooks(PWR_RESUME);
951 splx(s);
952 dopowerhooks(PWR_SOFTRESUME);
953 if (state==ACPI_STATE_S4)
954 AcpiEnable();
955 }
956 AcpiLeaveSleepState((UINT8)state);
957 break;
958 case ACPI_STATE_S5:
959 ret = AcpiEnterSleepStatePrep(ACPI_STATE_S5);
960 if (ACPI_FAILURE(ret)) {
961 printf("acpi: failed preparing to sleep (%s)\n",
962 AcpiFormatException(ret));
963 break;
964 }
965 acpi_md_OsDisableInterrupt();
966 AcpiEnterSleepState(ACPI_STATE_S5);
967 printf("WARNING: powerdown failed!\n");
968 break;
969 }
970
971 return (ret);
972 }
973
974 #ifdef ACPI_PCI_FIXUP
975 ACPI_STATUS acpi_pci_fixup_bus(ACPI_HANDLE, UINT32, void *, void **);
976 /*
977 * acpi_pci_fixup:
978 *
979 * Set up PCI devices that BIOS didn't handle right.
980 * Iterate through all devices and try to get the _PTR
981 * (PCI Routing Table). If it exists then make sure all
982 * interrupt links that it uses are working.
983 */
984 void
985 acpi_pci_fixup(struct acpi_softc *sc)
986 {
987 ACPI_HANDLE parent;
988
989 #ifdef ACPI_DEBUG
990 printf("acpi_pci_fixup starts:\n");
991 #endif
992 if (AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent) != AE_OK)
993 return;
994 sc->sc_pci_bus = 0;
995 AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100,
996 acpi_pci_fixup_bus, sc, NULL);
997 }
998
999 static ACPI_HANDLE
1000 acpi_get_node(char *name)
1001 {
1002 ACPI_NAMESPACE_NODE *ObjDesc;
1003 ACPI_STATUS Status;
1004
1005 Status = AcpiNsGetNodeByPath(name, NULL, 0, &ObjDesc);
1006 if (ACPI_FAILURE (Status)) {
1007 printf("acpi_get_node: could not find: %s\n",
1008 AcpiFormatException (Status));
1009 return NULL;
1010 }
1011 return ObjDesc;
1012 }
1013
1014 static uint
1015 acpi_get_intr(ACPI_HANDLE handle)
1016 {
1017 ACPI_BUFFER ret;
1018 ACPI_STATUS rv;
1019 ACPI_RESOURCE *res;
1020 ACPI_RESOURCE_IRQ *irq;
1021 uint intr;
1022
1023 intr = -1;
1024 rv = acpi_get(handle, &ret, AcpiGetCurrentResources);
1025 if (ACPI_FAILURE(rv))
1026 return (intr);
1027 for (res = ret.Pointer; res->Id != ACPI_RSTYPE_END_TAG;
1028 res = ACPI_NEXT_RESOURCE(res)) {
1029 if (res->Id == ACPI_RSTYPE_IRQ) {
1030 irq = (ACPI_RESOURCE_IRQ *)&res->Data;
1031 if (irq->NumberOfInterrupts == 1)
1032 intr = irq->Interrupts[0];
1033 break;
1034 }
1035 }
1036 AcpiOsFree(ret.Pointer);
1037 return (intr);
1038 }
1039
1040 static void
1041 acpi_pci_set_line(int bus, int dev, int pin, int line)
1042 {
1043 ACPI_STATUS err;
1044 ACPI_PCI_ID pid;
1045 UINT32 intr, id, bhlc;
1046 int func, nfunc;
1047
1048 pid.Bus = bus;
1049 pid.Device = dev;
1050 pid.Function = 0;
1051
1052 err = AcpiOsReadPciConfiguration(&pid, PCI_BHLC_REG, &bhlc, 32);
1053 if (err)
1054 return;
1055 if (PCI_HDRTYPE_MULTIFN(bhlc))
1056 nfunc = 8;
1057 else
1058 nfunc = 1;
1059
1060 for (func = 0; func < nfunc; func++) {
1061 pid.Function = func;
1062
1063 err = AcpiOsReadPciConfiguration(&pid, PCI_ID_REG, &id, 32);
1064 if (err || PCI_VENDOR(id) == PCI_VENDOR_INVALID ||
1065 PCI_VENDOR(id) == 0)
1066 continue;
1067
1068 err = AcpiOsReadPciConfiguration(&pid, PCI_INTERRUPT_REG,
1069 &intr, 32);
1070 if (err) {
1071 printf("AcpiOsReadPciConfiguration failed %d\n", err);
1072 return;
1073 }
1074 if (pin == PCI_INTERRUPT_PIN(intr) &&
1075 line != PCI_INTERRUPT_LINE(intr)) {
1076 #ifdef ACPI_DEBUG
1077 printf("acpi fixup pci intr: %d:%d:%d %c: %d -> %d\n",
1078 bus, dev, func,
1079 pin + '@', PCI_INTERRUPT_LINE(intr),
1080 line);
1081 #endif
1082 intr &= ~(PCI_INTERRUPT_LINE_MASK <<
1083 PCI_INTERRUPT_LINE_SHIFT);
1084 intr |= line << PCI_INTERRUPT_LINE_SHIFT;
1085 err = AcpiOsWritePciConfiguration(&pid,
1086 PCI_INTERRUPT_REG, intr, 32);
1087 if (err) {
1088 printf("AcpiOsWritePciConfiguration failed"
1089 " %d\n", err);
1090 return;
1091 }
1092 }
1093 }
1094 }
1095
1096 ACPI_STATUS
1097 acpi_pci_fixup_bus(ACPI_HANDLE handle, UINT32 level, void *context,
1098 void **status)
1099 {
1100 struct acpi_softc *sc = context;
1101 ACPI_STATUS rv;
1102 ACPI_BUFFER buf;
1103 UINT8 *Buffer;
1104 ACPI_PCI_ROUTING_TABLE *PrtElement;
1105 ACPI_HANDLE link;
1106 uint line;
1107 ACPI_NAMESPACE_NODE *node;
1108 ACPI_INTEGER val;
1109
1110 rv = acpi_get(handle, &buf, AcpiGetIrqRoutingTable);
1111 if (ACPI_FAILURE(rv))
1112 return (AE_OK);
1113
1114 /*
1115 * If at level 1, this is a PCI root bus. Try the _BBN method
1116 * to get the right PCI bus numbering for the following
1117 * busses (this is a depth-first walk). It may fail,
1118 * for example if there's only one root bus, but that
1119 * case should be ok, so we'll ignore that.
1120 */
1121 if (level == 1) {
1122 node = AcpiNsMapHandleToNode(handle);
1123 rv = AcpiUtEvaluateNumericObject(METHOD_NAME__BBN, node, &val);
1124 if (!ACPI_FAILURE(rv)) {
1125 #ifdef ACPI_DEBUG
1126 printf("%s: fixup: _BBN success, bus # was %d now %d\n",
1127 sc->sc_dev.dv_xname, sc->sc_pci_bus,
1128 ACPI_LOWORD(val));
1129 #endif
1130 sc->sc_pci_bus = ACPI_LOWORD(val);
1131 }
1132 }
1133
1134
1135 #ifdef ACPI_DEBUG
1136 printf("%s: fixing up PCI bus %d at level %u\n", sc->sc_dev.dv_xname,
1137 sc->sc_pci_bus, level);
1138 #endif
1139
1140 for (Buffer = buf.Pointer; ; Buffer += PrtElement->Length) {
1141 PrtElement = (ACPI_PCI_ROUTING_TABLE *)Buffer;
1142 if (PrtElement->Length == 0)
1143 break;
1144 if (PrtElement->Source[0] == 0)
1145 continue;
1146
1147 link = acpi_get_node(PrtElement->Source);
1148 if (link == NULL)
1149 continue;
1150 line = acpi_get_intr(link);
1151 if (line == -1) {
1152 #ifdef ACPI_DEBUG
1153 printf("%s: fixing up intr link %s\n",
1154 sc->sc_dev.dv_xname, PrtElement->Source);
1155 #endif
1156 rv = acpi_allocate_resources(link);
1157 if (ACPI_FAILURE(rv)) {
1158 printf("%s: interrupt allocation failed %s\n",
1159 sc->sc_dev.dv_xname, PrtElement->Source);
1160 continue;
1161 }
1162 line = acpi_get_intr(link);
1163 if (line == -1) {
1164 printf("%s: get intr failed %s\n",
1165 sc->sc_dev.dv_xname, PrtElement->Source);
1166 continue;
1167 }
1168 }
1169
1170 acpi_pci_set_line(sc->sc_pci_bus, PrtElement->Address >> 16,
1171 PrtElement->Pin + 1, line);
1172 }
1173
1174 sc->sc_pci_bus++;
1175
1176 AcpiOsFree(buf.Pointer);
1177 return (AE_OK);
1178 }
1179 #endif /* ACPI_PCI_FIXUP */
1180
1181 #if defined(ACPI_PCI_FIXUP) || defined(ACPI_ACTIVATE_DEV)
1182 /* XXX This very incomplete */
1183 ACPI_STATUS
1184 acpi_allocate_resources(ACPI_HANDLE handle)
1185 {
1186 ACPI_BUFFER bufp, bufc, bufn;
1187 ACPI_RESOURCE *resp, *resc, *resn;
1188 ACPI_RESOURCE_IRQ *irq;
1189 ACPI_STATUS rv;
1190 uint delta;
1191
1192 rv = acpi_get(handle, &bufp, AcpiGetPossibleResources);
1193 if (ACPI_FAILURE(rv))
1194 goto out;
1195 rv = acpi_get(handle, &bufc, AcpiGetCurrentResources);
1196 if (ACPI_FAILURE(rv)) {
1197 goto out1;
1198 }
1199
1200 bufn.Length = 1000;
1201 bufn.Pointer = resn = malloc(bufn.Length, M_ACPI, M_WAITOK);
1202 resp = bufp.Pointer;
1203 resc = bufc.Pointer;
1204 while (resc->Id != ACPI_RSTYPE_END_TAG &&
1205 resp->Id != ACPI_RSTYPE_END_TAG) {
1206 while (resc->Id != resp->Id && resp->Id != ACPI_RSTYPE_END_TAG)
1207 resp = ACPI_NEXT_RESOURCE(resp);
1208 if (resp->Id == ACPI_RSTYPE_END_TAG)
1209 break;
1210 /* Found identical Id */
1211 resn->Id = resc->Id;
1212 switch (resc->Id) {
1213 case ACPI_RSTYPE_IRQ:
1214 memcpy(&resn->Data, &resp->Data,
1215 sizeof(ACPI_RESOURCE_IRQ));
1216 irq = (ACPI_RESOURCE_IRQ *)&resn->Data;
1217 irq->Interrupts[0] =
1218 ((ACPI_RESOURCE_IRQ *)&resp->Data)->
1219 Interrupts[irq->NumberOfInterrupts-1];
1220 irq->NumberOfInterrupts = 1;
1221 resn->Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
1222 break;
1223 case ACPI_RSTYPE_IO:
1224 memcpy(&resn->Data, &resp->Data,
1225 sizeof(ACPI_RESOURCE_IO));
1226 resn->Length = resp->Length;
1227 break;
1228 default:
1229 printf("acpi_allocate_resources: res=%d\n", resc->Id);
1230 rv = AE_BAD_DATA;
1231 goto out2;
1232 }
1233 resc = ACPI_NEXT_RESOURCE(resc);
1234 resn = ACPI_NEXT_RESOURCE(resn);
1235 delta = (UINT8 *)resn - (UINT8 *)bufn.Pointer;
1236 if (delta >=
1237 bufn.Length-ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_DATA)) {
1238 bufn.Length *= 2;
1239 bufn.Pointer = realloc(bufn.Pointer, bufn.Length,
1240 M_ACPI, M_WAITOK);
1241 resn = (ACPI_RESOURCE *)((UINT8 *)bufn.Pointer + delta);
1242 }
1243 }
1244 if (resc->Id != ACPI_RSTYPE_END_TAG) {
1245 printf("acpi_allocate_resources: resc not exhausted\n");
1246 rv = AE_BAD_DATA;
1247 goto out3;
1248 }
1249
1250 resn->Id = ACPI_RSTYPE_END_TAG;
1251 rv = AcpiSetCurrentResources(handle, &bufn);
1252 if (ACPI_FAILURE(rv)) {
1253 printf("acpi_allocate_resources: AcpiSetCurrentResources %s\n",
1254 AcpiFormatException(rv));
1255 }
1256
1257 out3:
1258 free(bufn.Pointer, M_ACPI);
1259 out2:
1260 AcpiOsFree(bufc.Pointer);
1261 out1:
1262 AcpiOsFree(bufp.Pointer);
1263 out:
1264 return rv;
1265 }
1266 #endif /* ACPI_PCI_FIXUP || ACPI_ACTIVATE_DEV */
1267