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