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