acpi.c revision 1.3 1 /* $NetBSD: acpi.c,v 1.3 2001/09/29 05:39:14 thorpej 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 struct acpi_softc *sc = state->softc;
418 struct acpi_scope *as = state->scope;
419 struct acpi_devnode *ad;
420 ACPI_OBJECT_TYPE type;
421 ACPI_STATUS rv;
422
423 if (AcpiGetType(handle, &type) == AE_OK) {
424 switch (type) {
425 case ACPI_TYPE_DEVICE:
426 case ACPI_TYPE_PROCESSOR:
427 case ACPI_TYPE_THERMAL:
428 case ACPI_TYPE_POWER:
429 ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT);
430 if (ad == NULL)
431 return (AE_NO_MEMORY);
432 memset(ad, 0, sizeof(*ad));
433
434 ad->ad_handle = handle;
435 ad->ad_level = level;
436 ad->ad_scope = as;
437 ad->ad_type = type;
438
439 TAILQ_INSERT_TAIL(&as->as_devnodes, ad, ad_list);
440
441 rv = AcpiGetObjectInfo(handle, &ad->ad_devinfo);
442 if (rv != AE_OK)
443 goto out;
444
445 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0)
446 goto out;
447
448 #ifdef ACPI_DEBUG
449 printf("%s: HID %s found in scope %s level %d\n",
450 sc->sc_dev.dv_xname, ad->ad_devinfo.HardwareId,
451 as->as_name, ad->ad_level);
452 if (ad->ad_devinfo.Valid & ACPI_VALID_UID)
453 printf(" UID %s\n",
454 ad->ad_devinfo.UniqueId);
455 if (ad->ad_devinfo.Valid & ACPI_VALID_ADR)
456 printf(" ADR 0x%016qx\n",
457 ad->ad_devinfo.Address);
458 if (ad->ad_devinfo.Valid & ACPI_VALID_STA)
459 printf(" STA 0x%08x\n",
460 ad->ad_devinfo.CurrentStatus);
461 #endif
462 }
463 }
464 out:
465 return (AE_OK);
466 }
467
468 /*
469 * acpi_print:
470 *
471 * Autoconfiguration print routine.
472 */
473 int
474 acpi_print(void *aux, const char *pnp)
475 {
476 struct acpi_attach_args *aa = aux;
477
478 if (pnp)
479 printf("%s at %s", aa->aa_node->ad_devinfo.HardwareId, pnp);
480
481 return (UNCONF);
482 }
483
484 /*****************************************************************************
485 * ACPI fixed-hardware feature handlers
486 *****************************************************************************/
487
488 UINT32 acpi_fixed_power_button_handler(void *);
489 UINT32 acpi_fixed_sleep_button_handler(void *);
490
491 /*
492 * acpi_enable_fixed_events:
493 *
494 * Enable any fixed-hardware feature handlers.
495 */
496 void
497 acpi_enable_fixed_events(struct acpi_softc *sc)
498 {
499 static int beenhere;
500 ACPI_STATUS rv;
501
502 /*
503 * Check for fixed-hardware buttons.
504 */
505
506 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) {
507 if (beenhere == 0)
508 printf("%s: fixed-feature power button present\n",
509 sc->sc_dev.dv_xname);
510 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
511 acpi_fixed_power_button_handler, sc);
512 if (rv != AE_OK)
513 printf("%s: unable to install handler for fixed "
514 "power button: %d\n", sc->sc_dev.dv_xname, rv);
515 }
516
517 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) {
518 if (beenhere == 0)
519 printf("%s: fixed-feature sleep button present\n",
520 sc->sc_dev.dv_xname);
521 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON,
522 acpi_fixed_sleep_button_handler, sc);
523 if (rv != AE_OK)
524 printf("%s: unable to install handler for fixed "
525 "power button: %d\n", sc->sc_dev.dv_xname, rv);
526 }
527
528 beenhere = 1;
529 }
530
531 /*
532 * acpi_fixed_power_button_handler:
533 *
534 * Fixed event handler for the power button.
535 */
536 UINT32
537 acpi_fixed_power_button_handler(void *context)
538 {
539 struct acpi_softc *sc = context;
540
541 /* XXX XXX XXX */
542
543 printf("%s: fixed power button pressed\n", sc->sc_dev.dv_xname);
544
545 return (INTERRUPT_HANDLED);
546 }
547
548 /*
549 * acpi_fixed_sleep_button_handler:
550 *
551 * Fixed event handler for the sleep button.
552 */
553 UINT32
554 acpi_fixed_sleep_button_handler(void *context)
555 {
556 struct acpi_softc *sc = context;
557
558 /* XXX XXX XXX */
559
560 printf("%s: fixed sleep button pressed\n", sc->sc_dev.dv_xname);
561
562 return (INTERRUPT_HANDLED);
563 }
564
565 /*****************************************************************************
566 * ACPI utility routines.
567 *****************************************************************************/
568
569 /*
570 * acpi_eval_integer:
571 *
572 * Evaluate an integer object.
573 */
574 ACPI_STATUS
575 acpi_eval_integer(ACPI_HANDLE handle, char *path, int *valp)
576 {
577 ACPI_STATUS rv;
578 ACPI_BUFFER buf;
579 ACPI_OBJECT param;
580
581 if (handle == NULL)
582 handle = ACPI_ROOT_OBJECT;
583
584 buf.Pointer = ¶m;
585 buf.Length = sizeof(param);
586
587 rv = AcpiEvaluateObject(handle, path, NULL, &buf);
588 if (rv == AE_OK) {
589 if (param.Type == ACPI_TYPE_INTEGER)
590 *valp = param.Integer.Value;
591 else
592 rv = AE_TYPE;
593 }
594
595 return (rv);
596 }
597
598 /*
599 * acpi_get:
600 *
601 * Fetch data info the specified (empty) ACPI buffer.
602 */
603 ACPI_STATUS
604 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf,
605 ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *))
606 {
607 ACPI_STATUS rv;
608
609 buf->Pointer = NULL;
610 buf->Length = 0;
611
612 rv = (*getit)(handle, buf);
613 if (rv != AE_BUFFER_OVERFLOW)
614 return (rv);
615
616 buf->Pointer = AcpiOsCallocate(buf->Length);
617 if (buf->Pointer == NULL)
618 return (AE_NO_MEMORY);
619
620 return ((*getit)(handle, buf));
621 }
622