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