acpi.c revision 1.4.4.2 1 /* $NetBSD: acpi.c,v 1.4.4.2 2001/10/08 21:18:05 nathanw 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/param.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46 #include <sys/malloc.h>
47
48 #include <dev/acpi/acpica.h>
49 #include <dev/acpi/acpireg.h>
50 #include <dev/acpi/acpivar.h>
51 #include <dev/acpi/acpi_osd.h>
52
53 #ifdef ENABLE_DEBUGGER
54 #define ACPI_DBGR_INIT 0x01
55 #define ACPI_DBGR_TABLES 0x02
56 #define ACPI_DBGR_ENABLE 0x04
57 #define ACPI_DBGR_PROBE 0x08
58 #define ACPI_DBGR_RUNNING 0x10
59
60 int acpi_dbgr = 0x00;
61 #endif
62
63 int acpi_match(struct device *, struct cfdata *, void *);
64 void acpi_attach(struct device *, struct device *, void *);
65
66 int acpi_print(void *aux, const char *);
67
68 extern struct cfdriver acpi_cd;
69
70 struct cfattach acpi_ca = {
71 sizeof(struct acpi_softc), acpi_match, acpi_attach,
72 };
73
74 /*
75 * This is a flag we set when the ACPI subsystem is active. Machine
76 * dependent code may wish to skip other steps (such as attaching
77 * subsystems that ACPI supercedes) when ACPI is active.
78 */
79 int acpi_active;
80
81 /*
82 * Pointer to the ACPI subsystem's state. There can be only
83 * one ACPI instance.
84 */
85 struct acpi_softc *acpi_softc;
86
87 void acpi_shutdown(void *);
88 ACPI_STATUS acpi_disable(struct acpi_softc *sc);
89 void acpi_build_tree(struct acpi_softc *);
90 ACPI_STATUS acpi_make_devnode(ACPI_HANDLE, UINT32, void *, void **);
91
92 void acpi_enable_fixed_events(struct acpi_softc *);
93
94 /*
95 * acpi_probe:
96 *
97 * Probe for ACPI support. This is called by the
98 * machine-dependent ACPI front-end. All of the
99 * actual work is done by ACPICA.
100 *
101 * NOTE: This is not an autoconfiguration interface function.
102 */
103 int
104 acpi_probe(void)
105 {
106 static int beenhere;
107 ACPI_STATUS rv;
108
109 if (beenhere != 0)
110 panic("acpi_probe: ACPI has already been probed");
111 beenhere = 1;
112
113 /*
114 * Start up ACPICA.
115 */
116 #ifdef ENABLE_DEBUGGER
117 if (acpi_dbgr & ACPI_DBGR_INIT)
118 acpi_osd_debugger();
119 #endif
120
121 rv = AcpiInitializeSubsystem();
122 if (rv != AE_OK) {
123 printf("ACPI: unable to initialize ACPICA: %d\n", rv);
124 return (0);
125 }
126
127 #ifdef ENABLE_DEBUGGER
128 if (acpi_dbgr & ACPI_DBGR_TABLES)
129 acpi_osd_debugger();
130 #endif
131
132 rv = AcpiLoadTables();
133 if (rv != AE_OK) {
134 printf("ACPI: unable to load tables: %d\n", rv);
135 return (0);
136 }
137
138 /*
139 * Looks like we have ACPI!
140 */
141
142 return (1);
143 }
144
145 /*
146 * acpi_match:
147 *
148 * Autoconfiguration `match' routine.
149 */
150 int
151 acpi_match(struct device *parent, struct cfdata *match, void *aux)
152 {
153 struct acpibus_attach_args *aa = aux;
154
155 if (strcmp(aa->aa_busname, acpi_cd.cd_name) != 0)
156 return (0);
157
158 /*
159 * XXX Check other locators? Hard to know -- machine
160 * dependent code has already checked for the presence
161 * of ACPI by calling acpi_probe(), so I suppose we
162 * don't really have to do anything else.
163 */
164 return (1);
165 }
166
167 /*
168 * acpi_attach:
169 *
170 * Autoconfiguration `attach' routine. Finish initializing
171 * ACPICA (some initialization was done in acpi_probe(),
172 * which was required to check for the presence of ACPI),
173 * and enable the ACPI subsystem.
174 */
175 void
176 acpi_attach(struct device *parent, struct device *self, void *aux)
177 {
178 struct acpi_softc *sc = (void *) self;
179 struct acpibus_attach_args *aa = aux;
180 ACPI_STATUS rv;
181
182 printf("\n");
183
184 if (acpi_softc != NULL)
185 panic("acpi_attach: ACPI has already been attached");
186
187 sc->sc_iot = aa->aa_iot;
188 sc->sc_memt = aa->aa_memt;
189 sc->sc_pc = aa->aa_pc;
190 sc->sc_pciflags = aa->aa_pciflags;
191
192 acpi_softc = sc;
193
194 /*
195 * Install the default address space handlers.
196 */
197
198 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
199 ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL);
200 if (rv != AE_OK) {
201 printf("%s: unable to install SYSTEM MEMORY handler: %d\n",
202 sc->sc_dev.dv_xname, rv);
203 return;
204 }
205
206 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
207 ACPI_ADR_SPACE_SYSTEM_IO, ACPI_DEFAULT_HANDLER, NULL, NULL);
208 if (rv != AE_OK) {
209 printf("%s: unable to install SYSTEM IO handler: %d\n",
210 sc->sc_dev.dv_xname, rv);
211 return;
212 }
213
214 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
215 ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
216 if (rv != AE_OK) {
217 printf("%s: unable to install PCI CONFIG handler: %d\n",
218 sc->sc_dev.dv_xname, rv);
219 return;
220 }
221
222 /*
223 * Bring ACPI on-line.
224 *
225 * Note that we request that _STA (device init) and _INI (object init)
226 * methods not be run.
227 *
228 * XXX We need to arrange for the object init pass after we have
229 * XXX attached all of our children.
230 */
231 #ifdef ENABLE_DEBUGGER
232 if (acpi_dbgr & ACPI_DBGR_ENABLE)
233 acpi_osd_debugger();
234 #endif
235 rv = AcpiEnableSubsystem(ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT);
236 if (rv != AE_OK) {
237 printf("%s: unable to enable ACPI: %d\n",
238 sc->sc_dev.dv_xname, rv);
239 return;
240 }
241 acpi_active = 1;
242
243 /*
244 * Set up the default sleep state to enter when various
245 * switches are activated.
246 */
247 sc->sc_switch_sleep[ACPI_SWITCH_POWERBUTTON] = ACPI_STATE_S5;
248 sc->sc_switch_sleep[ACPI_SWITCH_SLEEPBUTTON] = ACPI_STATE_S1;
249 sc->sc_switch_sleep[ACPI_SWITCH_LID] = ACPI_STATE_S1;
250
251 /* Our current state is "awake". */
252 sc->sc_sleepstate = ACPI_STATE_S0;
253
254 /*
255 * Check for fixed-hardware features.
256 */
257 acpi_enable_fixed_events(sc);
258
259 /*
260 * Scan the namespace and build our device tree.
261 */
262 #ifdef ENABLE_DEBUGGER
263 if (acpi_dbgr & ACPI_DBGR_PROBE)
264 acpi_osd_debugger();
265 #endif
266 acpi_build_tree(sc);
267
268 /*
269 * Register a shutdown hook that disables certain ACPI
270 * events that might happen and confuse us while we're
271 * trying to shut down.
272 */
273 sc->sc_sdhook = shutdownhook_establish(acpi_shutdown, sc);
274 if (sc->sc_sdhook == NULL)
275 printf("%s: WARNING: unable to register shutdown hook\n",
276 sc->sc_dev.dv_xname);
277
278 #ifdef ENABLE_DEBUGGER
279 if (acpi_dbgr & ACPI_DBGR_RUNNING)
280 acpi_osd_debugger();
281 #endif
282 }
283
284 /*
285 * acpi_shutdown:
286 *
287 * Shutdown hook for ACPI -- disable some events that
288 * might confuse us.
289 */
290 void
291 acpi_shutdown(void *arg)
292 {
293 struct acpi_softc *sc = arg;
294
295 if (acpi_disable(sc) != AE_OK)
296 printf("%s: WARNING: unable to disable ACPI\n",
297 sc->sc_dev.dv_xname);
298 }
299
300 /*
301 * acpi_disable:
302 *
303 * Disable ACPI.
304 */
305 ACPI_STATUS
306 acpi_disable(struct acpi_softc *sc)
307 {
308 ACPI_STATUS rv = AE_OK;
309
310 if (acpi_active) {
311 rv = AcpiDisable();
312 if (rv == AE_OK)
313 acpi_active = 0;
314 }
315 return (rv);
316 }
317
318 struct acpi_make_devnode_state {
319 struct acpi_softc *softc;
320 struct acpi_scope *scope;
321 };
322
323 /*
324 * acpi_build_tree:
325 *
326 * Scan relevant portions of the ACPI namespace and attach
327 * child devices.
328 */
329 void
330 acpi_build_tree(struct acpi_softc *sc)
331 {
332 static const char *scopes[] = {
333 "\\_PR_", /* ACPI 1.0 processor namespace */
334 "\\_SB_", /* system bus namespace */
335 "\\_SI_", /* system idicator namespace */
336 "\\_TZ_", /* ACPI 1.0 thermal zone namespace */
337 NULL,
338 };
339 struct acpi_attach_args aa;
340 struct acpi_make_devnode_state state;
341 struct acpi_scope *as;
342 struct acpi_devnode *ad;
343 ACPI_HANDLE parent;
344 int i;
345
346 TAILQ_INIT(&sc->sc_scopes);
347
348 state.softc = sc;
349
350 /*
351 * Scan the namespace and build our tree.
352 */
353 for (i = 0; scopes[i] != NULL; i++) {
354 as = malloc(sizeof(*as), M_DEVBUF, M_WAITOK);
355 as->as_name = scopes[i];
356 TAILQ_INIT(&as->as_devnodes);
357
358 TAILQ_INSERT_TAIL(&sc->sc_scopes, as, as_list);
359
360 state.scope = as;
361
362 if (AcpiGetHandle(ACPI_ROOT_OBJECT, (char *) scopes[i],
363 &parent) == AE_OK) {
364 AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100,
365 acpi_make_devnode, &state, NULL);
366 }
367
368 /* Now, for this namespace, try and attach the devices. */
369 TAILQ_FOREACH(ad, &as->as_devnodes, ad_list) {
370 aa.aa_node = ad;
371 aa.aa_iot = sc->sc_iot;
372 aa.aa_memt = sc->sc_memt;
373 aa.aa_pc = sc->sc_pc;
374 aa.aa_pciflags = sc->sc_pciflags;
375
376 /*
377 * XXX We only attach devices which are:
378 *
379 * - present
380 * - enabled
381 * - to be shown
382 * - functioning properly
383 *
384 * However, if enabled, it's decoding resources,
385 * so we should claim them, if possible. Requires
386 * changes to bus_space(9).
387 */
388 if ((ad->ad_devinfo.CurrentStatus &
389 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED|
390 ACPI_STA_DEV_SHOW|ACPI_STA_DEV_OK)) !=
391 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED|
392 ACPI_STA_DEV_SHOW|ACPI_STA_DEV_OK))
393 continue;
394
395 /*
396 * XXX Same problem as above...
397 */
398 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0)
399 continue;
400
401 ad->ad_device = config_found(&sc->sc_dev,
402 &aa, acpi_print);
403 }
404 }
405 }
406
407 /*
408 * acpi_make_devnode:
409 *
410 * Make an ACPI devnode.
411 */
412 ACPI_STATUS
413 acpi_make_devnode(ACPI_HANDLE handle, UINT32 level, void *context,
414 void **status)
415 {
416 struct acpi_make_devnode_state *state = context;
417 #ifdef ACPI_DEBUG
418 struct acpi_softc *sc = state->softc;
419 #endif
420 struct acpi_scope *as = state->scope;
421 struct acpi_devnode *ad;
422 ACPI_OBJECT_TYPE type;
423 ACPI_STATUS rv;
424
425 if (AcpiGetType(handle, &type) == AE_OK) {
426 switch (type) {
427 case ACPI_TYPE_DEVICE:
428 case ACPI_TYPE_PROCESSOR:
429 case ACPI_TYPE_THERMAL:
430 case ACPI_TYPE_POWER:
431 ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT);
432 if (ad == NULL)
433 return (AE_NO_MEMORY);
434 memset(ad, 0, sizeof(*ad));
435
436 ad->ad_handle = handle;
437 ad->ad_level = level;
438 ad->ad_scope = as;
439 ad->ad_type = type;
440
441 TAILQ_INSERT_TAIL(&as->as_devnodes, ad, ad_list);
442
443 rv = AcpiGetObjectInfo(handle, &ad->ad_devinfo);
444 if (rv != AE_OK)
445 goto out;
446
447 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0)
448 goto out;
449
450 #ifdef ACPI_DEBUG
451 printf("%s: HID %s found in scope %s level %d\n",
452 sc->sc_dev.dv_xname, ad->ad_devinfo.HardwareId,
453 as->as_name, ad->ad_level);
454 if (ad->ad_devinfo.Valid & ACPI_VALID_UID)
455 printf(" UID %s\n",
456 ad->ad_devinfo.UniqueId);
457 if (ad->ad_devinfo.Valid & ACPI_VALID_ADR)
458 printf(" ADR 0x%016qx\n",
459 ad->ad_devinfo.Address);
460 if (ad->ad_devinfo.Valid & ACPI_VALID_STA)
461 printf(" STA 0x%08x\n",
462 ad->ad_devinfo.CurrentStatus);
463 #endif
464 }
465 }
466 out:
467 return (AE_OK);
468 }
469
470 /*
471 * acpi_print:
472 *
473 * Autoconfiguration print routine.
474 */
475 int
476 acpi_print(void *aux, const char *pnp)
477 {
478 struct acpi_attach_args *aa = aux;
479 char *str;
480
481 if (pnp) {
482 printf("%s ", aa->aa_node->ad_devinfo.HardwareId);
483 if (acpi_eval_string(aa->aa_node->ad_handle,
484 "_STR", &str) == AE_OK) {
485 printf("[%s] ", str);
486 AcpiOsFree(str);
487 }
488 printf("at %s", pnp);
489 }
490
491 return (UNCONF);
492 }
493
494 /*****************************************************************************
495 * ACPI fixed-hardware feature handlers
496 *****************************************************************************/
497
498 UINT32 acpi_fixed_power_button_handler(void *);
499 UINT32 acpi_fixed_sleep_button_handler(void *);
500
501 /*
502 * acpi_enable_fixed_events:
503 *
504 * Enable any fixed-hardware feature handlers.
505 */
506 void
507 acpi_enable_fixed_events(struct acpi_softc *sc)
508 {
509 static int beenhere;
510 ACPI_STATUS rv;
511
512 /*
513 * Check for fixed-hardware buttons.
514 */
515
516 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) {
517 if (beenhere == 0)
518 printf("%s: fixed-feature power button present\n",
519 sc->sc_dev.dv_xname);
520 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
521 acpi_fixed_power_button_handler, sc);
522 if (rv != AE_OK)
523 printf("%s: unable to install handler for fixed "
524 "power button: %d\n", sc->sc_dev.dv_xname, rv);
525 }
526
527 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) {
528 if (beenhere == 0)
529 printf("%s: fixed-feature sleep button present\n",
530 sc->sc_dev.dv_xname);
531 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON,
532 acpi_fixed_sleep_button_handler, sc);
533 if (rv != AE_OK)
534 printf("%s: unable to install handler for fixed "
535 "power button: %d\n", sc->sc_dev.dv_xname, rv);
536 }
537
538 beenhere = 1;
539 }
540
541 /*
542 * acpi_fixed_power_button_handler:
543 *
544 * Fixed event handler for the power button.
545 */
546 UINT32
547 acpi_fixed_power_button_handler(void *context)
548 {
549 struct acpi_softc *sc = context;
550
551 /* XXX XXX XXX */
552
553 printf("%s: fixed power button pressed\n", sc->sc_dev.dv_xname);
554
555 return (INTERRUPT_HANDLED);
556 }
557
558 /*
559 * acpi_fixed_sleep_button_handler:
560 *
561 * Fixed event handler for the sleep button.
562 */
563 UINT32
564 acpi_fixed_sleep_button_handler(void *context)
565 {
566 struct acpi_softc *sc = context;
567
568 /* XXX XXX XXX */
569
570 printf("%s: fixed sleep button pressed\n", sc->sc_dev.dv_xname);
571
572 return (INTERRUPT_HANDLED);
573 }
574
575 /*****************************************************************************
576 * ACPI utility routines.
577 *****************************************************************************/
578
579 /*
580 * acpi_eval_integer:
581 *
582 * Evaluate an integer object.
583 */
584 ACPI_STATUS
585 acpi_eval_integer(ACPI_HANDLE handle, char *path, int *valp)
586 {
587 ACPI_STATUS rv;
588 ACPI_BUFFER buf;
589 ACPI_OBJECT param;
590
591 if (handle == NULL)
592 handle = ACPI_ROOT_OBJECT;
593
594 buf.Pointer = ¶m;
595 buf.Length = sizeof(param);
596
597 rv = AcpiEvaluateObject(handle, path, NULL, &buf);
598 if (rv == AE_OK) {
599 if (param.Type == ACPI_TYPE_INTEGER)
600 *valp = param.Integer.Value;
601 else
602 rv = AE_TYPE;
603 }
604
605 return (rv);
606 }
607
608 /*
609 * acpi_eval_string:
610 *
611 * Evaluage a (Unicode) string object.
612 */
613 ACPI_STATUS
614 acpi_eval_string(ACPI_HANDLE handle, char *path, char **stringp)
615 {
616 ACPI_STATUS rv;
617 ACPI_BUFFER buf;
618 ACPI_OBJECT param;
619
620 if (handle == NULL)
621 handle = ACPI_ROOT_OBJECT;
622
623 buf.Pointer = NULL;
624 buf.Length = 0;
625
626 rv = AcpiEvaluateObject(handle, path, NULL, &buf);
627 if (rv != AE_BUFFER_OVERFLOW)
628 return (rv);
629
630 buf.Pointer = AcpiOsAllocate(buf.Length);
631 if (buf.Pointer == NULL)
632 return (AE_NO_MEMORY);
633
634 rv = AcpiEvaluateObject(handle, path, NULL, &buf);
635 if (rv == AE_OK) {
636 if (param.Type == ACPI_TYPE_STRING) {
637 *stringp = buf.Pointer;
638 return (AE_OK);
639 }
640 rv = AE_TYPE;
641 }
642
643 AcpiOsFree(buf.Pointer);
644 return (rv);
645 }
646
647 /*
648 * acpi_get:
649 *
650 * Fetch data info the specified (empty) ACPI buffer.
651 */
652 ACPI_STATUS
653 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf,
654 ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *))
655 {
656 ACPI_STATUS rv;
657
658 buf->Pointer = NULL;
659 buf->Length = 0;
660
661 rv = (*getit)(handle, buf);
662 if (rv != AE_BUFFER_OVERFLOW)
663 return (rv);
664
665 buf->Pointer = AcpiOsCallocate(buf->Length);
666 if (buf->Pointer == NULL)
667 return (AE_NO_MEMORY);
668
669 return ((*getit)(handle, buf));
670 }
671