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