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