1 | /* $NetBSD: acpi.c,v 1.262 2016/06/21 11:33:33 nonaka Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2003, 2007 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Charles M. Hannum of By Noon Software, Inc. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Copyright (c) 2003 Wasabi Systems, Inc. |
34 | * All rights reserved. |
35 | * |
36 | * Written by Frank van der Linden for Wasabi Systems, Inc. |
37 | * |
38 | * Redistribution and use in source and binary forms, with or without |
39 | * modification, are permitted provided that the following conditions |
40 | * are met: |
41 | * 1. Redistributions of source code must retain the above copyright |
42 | * notice, this list of conditions and the following disclaimer. |
43 | * 2. Redistributions in binary form must reproduce the above copyright |
44 | * notice, this list of conditions and the following disclaimer in the |
45 | * documentation and/or other materials provided with the distribution. |
46 | * 3. All advertising materials mentioning features or use of this software |
47 | * must display the following acknowledgement: |
48 | * This product includes software developed for the NetBSD Project by |
49 | * Wasabi Systems, Inc. |
50 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
51 | * or promote products derived from this software without specific prior |
52 | * written permission. |
53 | * |
54 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
55 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
56 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
57 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
58 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
59 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
60 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
61 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
62 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
63 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
64 | * POSSIBILITY OF SUCH DAMAGE. |
65 | */ |
66 | |
67 | /* |
68 | * Copyright 2001, 2003 Wasabi Systems, Inc. |
69 | * All rights reserved. |
70 | * |
71 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
72 | * |
73 | * Redistribution and use in source and binary forms, with or without |
74 | * modification, are permitted provided that the following conditions |
75 | * are met: |
76 | * 1. Redistributions of source code must retain the above copyright |
77 | * notice, this list of conditions and the following disclaimer. |
78 | * 2. Redistributions in binary form must reproduce the above copyright |
79 | * notice, this list of conditions and the following disclaimer in the |
80 | * documentation and/or other materials provided with the distribution. |
81 | * 3. All advertising materials mentioning features or use of this software |
82 | * must display the following acknowledgement: |
83 | * This product includes software developed for the NetBSD Project by |
84 | * Wasabi Systems, Inc. |
85 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
86 | * or promote products derived from this software without specific prior |
87 | * written permission. |
88 | * |
89 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
90 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
91 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
92 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
93 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
94 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
95 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
96 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
97 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
98 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
99 | * POSSIBILITY OF SUCH DAMAGE. |
100 | */ |
101 | |
102 | #include <sys/cdefs.h> |
103 | __KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.262 2016/06/21 11:33:33 nonaka Exp $" ); |
104 | |
105 | #include "opt_acpi.h" |
106 | #include "opt_pcifixup.h" |
107 | |
108 | #include <sys/param.h> |
109 | #include <sys/device.h> |
110 | #include <sys/kernel.h> |
111 | #include <sys/kmem.h> |
112 | #include <sys/malloc.h> |
113 | #include <sys/module.h> |
114 | #include <sys/mutex.h> |
115 | #include <sys/sysctl.h> |
116 | #include <sys/systm.h> |
117 | #include <sys/timetc.h> |
118 | |
119 | #include <dev/acpi/acpireg.h> |
120 | #include <dev/acpi/acpivar.h> |
121 | #include <dev/acpi/acpi_mcfg.h> |
122 | #include <dev/acpi/acpi_osd.h> |
123 | #include <dev/acpi/acpi_pci.h> |
124 | #include <dev/acpi/acpi_power.h> |
125 | #include <dev/acpi/acpi_timer.h> |
126 | #include <dev/acpi/acpi_wakedev.h> |
127 | |
128 | #include <machine/acpi_machdep.h> |
129 | |
130 | #define _COMPONENT ACPI_BUS_COMPONENT |
131 | ACPI_MODULE_NAME ("acpi" ) |
132 | |
133 | /* |
134 | * The acpi_active variable is set when the ACPI subsystem is active. |
135 | * Machine-dependent code may wish to skip other steps (such as attaching |
136 | * subsystems that ACPI supercedes) when ACPI is active. |
137 | */ |
138 | int acpi_active = 0; |
139 | int acpi_suspended = 0; |
140 | int acpi_force_load = 0; |
141 | int acpi_verbose_loaded = 0; |
142 | |
143 | struct acpi_softc *acpi_softc = NULL; |
144 | static uint64_t acpi_root_pointer; |
145 | extern kmutex_t acpi_interrupt_list_mtx; |
146 | extern struct cfdriver acpi_cd; |
147 | static ACPI_HANDLE acpi_scopes[4]; |
148 | ACPI_TABLE_HEADER *; |
149 | |
150 | /* |
151 | * This structure provides a context for the ACPI |
152 | * namespace walk performed in acpi_build_tree(). |
153 | */ |
154 | struct acpi_walkcontext { |
155 | struct acpi_softc *aw_sc; |
156 | struct acpi_devnode *aw_parent; |
157 | }; |
158 | |
159 | /* |
160 | * Ignored HIDs. |
161 | */ |
162 | static const char * const acpi_ignored_ids[] = { |
163 | #if defined(i386) || defined(x86_64) |
164 | "ACPI0007" , /* ACPI CPUs do not attach to acpi(4) */ |
165 | "PNP0000" , /* AT interrupt controller is handled internally */ |
166 | "PNP0200" , /* AT DMA controller is handled internally */ |
167 | "PNP0A??" , /* PCI Busses are handled internally */ |
168 | "PNP0B00" , /* AT RTC is handled internally */ |
169 | "PNP0C0F" , /* ACPI PCI link devices are handled internally */ |
170 | #endif |
171 | #if defined(x86_64) |
172 | "PNP0C04" , /* FPU is handled internally */ |
173 | #endif |
174 | NULL |
175 | }; |
176 | |
177 | /* |
178 | * Devices that should be attached early. |
179 | */ |
180 | static const char * const acpi_early_ids[] = { |
181 | "PNP0C09" , /* acpiec(4) */ |
182 | NULL |
183 | }; |
184 | |
185 | static int acpi_match(device_t, cfdata_t, void *); |
186 | static int acpi_submatch(device_t, cfdata_t, const int *, void *); |
187 | static void acpi_attach(device_t, device_t, void *); |
188 | static int acpi_detach(device_t, int); |
189 | static void acpi_childdet(device_t, device_t); |
190 | static bool acpi_suspend(device_t, const pmf_qual_t *); |
191 | static bool acpi_resume(device_t, const pmf_qual_t *); |
192 | |
193 | static void acpi_build_tree(struct acpi_softc *); |
194 | static void acpi_config_tree(struct acpi_softc *); |
195 | static ACPI_STATUS acpi_make_devnode(ACPI_HANDLE, uint32_t, |
196 | void *, void **); |
197 | static ACPI_STATUS acpi_make_devnode_post(ACPI_HANDLE, uint32_t, |
198 | void *, void **); |
199 | static void acpi_make_name(struct acpi_devnode *, uint32_t); |
200 | |
201 | static int acpi_rescan(device_t, const char *, const int *); |
202 | static void acpi_rescan_early(struct acpi_softc *); |
203 | static void acpi_rescan_nodes(struct acpi_softc *); |
204 | static void acpi_rescan_capabilities(device_t); |
205 | static int acpi_print(void *aux, const char *); |
206 | |
207 | static void acpi_notify_handler(ACPI_HANDLE, uint32_t, void *); |
208 | |
209 | static void acpi_register_fixed_button(struct acpi_softc *, int); |
210 | static void acpi_deregister_fixed_button(struct acpi_softc *, int); |
211 | static uint32_t acpi_fixed_button_handler(void *); |
212 | static void acpi_fixed_button_pressed(void *); |
213 | |
214 | static void acpi_sleep_init(struct acpi_softc *); |
215 | |
216 | static int sysctl_hw_acpi_fixedstats(SYSCTLFN_PROTO); |
217 | static int sysctl_hw_acpi_sleepstate(SYSCTLFN_PROTO); |
218 | static int sysctl_hw_acpi_sleepstates(SYSCTLFN_PROTO); |
219 | |
220 | static bool acpi_is_scope(struct acpi_devnode *); |
221 | static ACPI_TABLE_HEADER *acpi_map_rsdt(void); |
222 | static void acpi_unmap_rsdt(ACPI_TABLE_HEADER *); |
223 | |
224 | void acpi_print_verbose_stub(struct acpi_softc *); |
225 | void acpi_print_dev_stub(const char *); |
226 | |
227 | static void acpi_activate_device(ACPI_HANDLE, ACPI_DEVICE_INFO **); |
228 | ACPI_STATUS acpi_allocate_resources(ACPI_HANDLE); |
229 | |
230 | void (*acpi_print_verbose)(struct acpi_softc *) = acpi_print_verbose_stub; |
231 | void (*acpi_print_dev)(const char *) = acpi_print_dev_stub; |
232 | |
233 | CFATTACH_DECL2_NEW(acpi, sizeof(struct acpi_softc), |
234 | acpi_match, acpi_attach, acpi_detach, NULL, acpi_rescan, acpi_childdet); |
235 | |
236 | /* |
237 | * Probe for ACPI support. |
238 | * |
239 | * This is called by the machine-dependent ACPI front-end. |
240 | * Note: this is not an autoconfiguration interface function. |
241 | */ |
242 | int |
243 | acpi_probe(void) |
244 | { |
245 | ACPI_TABLE_HEADER *rsdt; |
246 | ACPI_STATUS rv; |
247 | int quirks; |
248 | |
249 | if (acpi_softc != NULL) |
250 | panic("%s: already probed" , __func__); |
251 | |
252 | mutex_init(&acpi_interrupt_list_mtx, MUTEX_DEFAULT, IPL_NONE); |
253 | |
254 | /* |
255 | * Start up ACPICA. |
256 | */ |
257 | AcpiGbl_EnableInterpreterSlack = true; |
258 | |
259 | rv = AcpiInitializeSubsystem(); |
260 | |
261 | if (ACPI_FAILURE(rv)) { |
262 | aprint_error("%s: failed to initialize subsystem\n" , __func__); |
263 | return 0; |
264 | } |
265 | |
266 | /* |
267 | * Allocate space for RSDT/XSDT and DSDT, |
268 | * but allow resizing if more tables exist. |
269 | */ |
270 | rv = AcpiInitializeTables(NULL, 2, true); |
271 | |
272 | if (ACPI_FAILURE(rv)) { |
273 | aprint_error("%s: failed to initialize tables\n" , __func__); |
274 | goto fail; |
275 | } |
276 | |
277 | rv = AcpiLoadTables(); |
278 | |
279 | if (ACPI_FAILURE(rv)) { |
280 | aprint_error("%s: failed to load tables\n" , __func__); |
281 | goto fail; |
282 | } |
283 | |
284 | rsdt = acpi_map_rsdt(); |
285 | |
286 | if (rsdt == NULL) { |
287 | aprint_error("%s: failed to map RSDT\n" , __func__); |
288 | goto fail; |
289 | } |
290 | |
291 | quirks = acpi_find_quirks(); |
292 | |
293 | if (acpi_force_load == 0 && (quirks & ACPI_QUIRK_BROKEN) != 0) { |
294 | |
295 | aprint_normal("ACPI: BIOS is listed as broken:\n" ); |
296 | aprint_normal("ACPI: X/RSDT: OemId <%6.6s,%8.8s,%08x>, " |
297 | "AslId <%4.4s,%08x>\n" , rsdt->OemId, rsdt->OemTableId, |
298 | rsdt->OemRevision, rsdt->AslCompilerId, |
299 | rsdt->AslCompilerRevision); |
300 | aprint_normal("ACPI: Not used. Set acpi_force_load to use.\n" ); |
301 | |
302 | acpi_unmap_rsdt(rsdt); |
303 | goto fail; |
304 | } |
305 | |
306 | if (acpi_force_load == 0 && (quirks & ACPI_QUIRK_OLDBIOS) != 0) { |
307 | |
308 | aprint_normal("ACPI: BIOS is too old (%s). " |
309 | "Set acpi_force_load to use.\n" , |
310 | pmf_get_platform("bios-date" )); |
311 | |
312 | acpi_unmap_rsdt(rsdt); |
313 | goto fail; |
314 | } |
315 | |
316 | acpi_unmap_rsdt(rsdt); |
317 | |
318 | rv = AcpiEnableSubsystem(~(ACPI_NO_HARDWARE_INIT|ACPI_NO_ACPI_ENABLE)); |
319 | |
320 | if (ACPI_FAILURE(rv)) { |
321 | aprint_error("%s: failed to enable subsystem\n" , __func__); |
322 | goto fail; |
323 | } |
324 | |
325 | return 1; |
326 | |
327 | fail: |
328 | (void)AcpiTerminate(); |
329 | |
330 | return 0; |
331 | } |
332 | |
333 | void |
334 | acpi_disable(void) |
335 | { |
336 | |
337 | if (acpi_softc == NULL) |
338 | return; |
339 | |
340 | KASSERT(acpi_active != 0); |
341 | |
342 | if (AcpiGbl_FADT.SmiCommand != 0) |
343 | AcpiDisable(); |
344 | } |
345 | |
346 | int |
347 | acpi_check(device_t parent, const char *ifattr) |
348 | { |
349 | return (config_search_ia(acpi_submatch, parent, ifattr, NULL) != NULL); |
350 | } |
351 | |
352 | int |
353 | acpi_reset(void) |
354 | { |
355 | struct acpi_softc *sc = acpi_softc; |
356 | ACPI_GENERIC_ADDRESS *ResetReg; |
357 | ACPI_PCI_ID PciId; |
358 | ACPI_STATUS status; |
359 | |
360 | if (sc == NULL) |
361 | return ENXIO; |
362 | |
363 | ResetReg = &AcpiGbl_FADT.ResetRegister; |
364 | |
365 | /* Check if the reset register is supported */ |
366 | if (!(AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER) || |
367 | !ResetReg->Address) { |
368 | return ENOENT; |
369 | } |
370 | |
371 | switch (ResetReg->SpaceId) { |
372 | case ACPI_ADR_SPACE_PCI_CONFIG: |
373 | PciId.Segment = PciId.Bus = 0; |
374 | PciId.Device = ACPI_GAS_PCI_DEV(ResetReg->Address); |
375 | PciId.Function = ACPI_GAS_PCI_FUNC(ResetReg->Address); |
376 | status = AcpiOsWritePciConfiguration(&PciId, |
377 | ACPI_GAS_PCI_REGOFF(ResetReg->Address), |
378 | AcpiGbl_FADT.ResetValue, ResetReg->BitWidth); |
379 | break; |
380 | case ACPI_ADR_SPACE_SYSTEM_IO: |
381 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: |
382 | status = AcpiReset(); |
383 | break; |
384 | default: |
385 | status = AE_TYPE; |
386 | break; |
387 | } |
388 | |
389 | return ACPI_FAILURE(status) ? EIO : 0; |
390 | } |
391 | |
392 | /* |
393 | * Autoconfiguration. |
394 | */ |
395 | static int |
396 | acpi_match(device_t parent, cfdata_t match, void *aux) |
397 | { |
398 | /* |
399 | * XXX: Nada; MD code has called acpi_probe(). |
400 | */ |
401 | return 1; |
402 | } |
403 | |
404 | static int |
405 | acpi_submatch(device_t parent, cfdata_t cf, const int *locs, void *aux) |
406 | { |
407 | struct cfattach *ca; |
408 | |
409 | ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname); |
410 | |
411 | return (ca == &acpi_ca); |
412 | } |
413 | |
414 | static void |
415 | acpi_attach(device_t parent, device_t self, void *aux) |
416 | { |
417 | struct acpi_softc *sc = device_private(self); |
418 | struct acpibus_attach_args *aa = aux; |
419 | ACPI_TABLE_HEADER *rsdt; |
420 | ACPI_STATUS rv; |
421 | |
422 | aprint_naive("\n" ); |
423 | aprint_normal(": Intel ACPICA %08x\n" , ACPI_CA_VERSION); |
424 | |
425 | if (acpi_softc != NULL) |
426 | panic("%s: already attached" , __func__); |
427 | |
428 | rsdt = acpi_map_rsdt(); |
429 | |
430 | if (rsdt == NULL) |
431 | aprint_error_dev(self, "X/RSDT: Not found\n" ); |
432 | else { |
433 | aprint_verbose_dev(self, |
434 | "X/RSDT: OemId <%6.6s,%8.8s,%08x>, AslId <%4.4s,%08x>\n" , |
435 | rsdt->OemId, rsdt->OemTableId, |
436 | rsdt->OemRevision, |
437 | rsdt->AslCompilerId, rsdt->AslCompilerRevision); |
438 | } |
439 | |
440 | acpi_unmap_rsdt(rsdt); |
441 | |
442 | sc->sc_dev = self; |
443 | sc->sc_root = NULL; |
444 | |
445 | sc->sc_sleepstate = ACPI_STATE_S0; |
446 | sc->sc_quirks = acpi_find_quirks(); |
447 | |
448 | sysmon_power_settype("acpi" ); |
449 | |
450 | sc->sc_iot = aa->aa_iot; |
451 | sc->sc_memt = aa->aa_memt; |
452 | sc->sc_pc = aa->aa_pc; |
453 | sc->sc_pciflags = aa->aa_pciflags; |
454 | sc->sc_ic = aa->aa_ic; |
455 | sc->sc_dmat = aa->aa_dmat; |
456 | sc->sc_dmat64 = aa->aa_dmat64; |
457 | |
458 | SIMPLEQ_INIT(&sc->ad_head); |
459 | |
460 | acpi_softc = sc; |
461 | |
462 | if (pmf_device_register(self, acpi_suspend, acpi_resume) != true) |
463 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
464 | |
465 | /* |
466 | * Bring ACPICA on-line. |
467 | */ |
468 | |
469 | rv = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION); |
470 | |
471 | if (ACPI_FAILURE(rv)) |
472 | goto fail; |
473 | |
474 | /* |
475 | * Early initialization of acpiec(4) via ECDT. |
476 | */ |
477 | (void)config_found_ia(self, "acpiecdtbus" , aa, NULL); |
478 | |
479 | rv = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION); |
480 | |
481 | if (ACPI_FAILURE(rv)) |
482 | goto fail; |
483 | |
484 | /* |
485 | * Scan the namespace and build our device tree. |
486 | */ |
487 | acpi_build_tree(sc); |
488 | |
489 | /* |
490 | * Probe MCFG table |
491 | */ |
492 | acpimcfg_probe(sc); |
493 | |
494 | acpi_md_callback(sc); |
495 | |
496 | /* |
497 | * Early initialization of the _PDC control method |
498 | * that may load additional SSDT tables dynamically. |
499 | */ |
500 | (void)acpi_md_pdc(); |
501 | |
502 | /* |
503 | * Install global notify handlers. |
504 | */ |
505 | rv = AcpiInstallNotifyHandler(ACPI_ROOT_OBJECT, |
506 | ACPI_SYSTEM_NOTIFY, acpi_notify_handler, NULL); |
507 | |
508 | if (ACPI_FAILURE(rv)) |
509 | goto fail; |
510 | |
511 | rv = AcpiInstallNotifyHandler(ACPI_ROOT_OBJECT, |
512 | ACPI_DEVICE_NOTIFY, acpi_notify_handler, NULL); |
513 | |
514 | if (ACPI_FAILURE(rv)) |
515 | goto fail; |
516 | |
517 | acpi_active = 1; |
518 | |
519 | /* Show SCI interrupt. */ |
520 | aprint_verbose_dev(self, "SCI interrupting at int %u\n" , |
521 | AcpiGbl_FADT.SciInterrupt); |
522 | |
523 | /* |
524 | * Install fixed-event handlers. |
525 | */ |
526 | acpi_register_fixed_button(sc, ACPI_EVENT_POWER_BUTTON); |
527 | acpi_register_fixed_button(sc, ACPI_EVENT_SLEEP_BUTTON); |
528 | |
529 | acpitimer_init(sc); |
530 | acpi_config_tree(sc); |
531 | acpi_sleep_init(sc); |
532 | |
533 | #ifdef ACPI_DEBUG |
534 | acpi_debug_init(); |
535 | #endif |
536 | |
537 | /* |
538 | * Print debug information. |
539 | */ |
540 | acpi_print_verbose(sc); |
541 | |
542 | return; |
543 | |
544 | fail: |
545 | aprint_error("%s: failed to initialize ACPI: %s\n" , |
546 | __func__, AcpiFormatException(rv)); |
547 | } |
548 | |
549 | /* |
550 | * XXX: This is incomplete. |
551 | */ |
552 | static int |
553 | acpi_detach(device_t self, int flags) |
554 | { |
555 | struct acpi_softc *sc = device_private(self); |
556 | ACPI_STATUS rv; |
557 | int rc; |
558 | |
559 | rv = AcpiRemoveNotifyHandler(ACPI_ROOT_OBJECT, |
560 | ACPI_SYSTEM_NOTIFY, acpi_notify_handler); |
561 | |
562 | if (ACPI_FAILURE(rv)) |
563 | return EBUSY; |
564 | |
565 | rv = AcpiRemoveNotifyHandler(ACPI_ROOT_OBJECT, |
566 | ACPI_DEVICE_NOTIFY, acpi_notify_handler); |
567 | |
568 | if (ACPI_FAILURE(rv)) |
569 | return EBUSY; |
570 | |
571 | if ((rc = config_detach_children(self, flags)) != 0) |
572 | return rc; |
573 | |
574 | if ((rc = acpitimer_detach()) != 0) |
575 | return rc; |
576 | |
577 | acpi_deregister_fixed_button(sc, ACPI_EVENT_POWER_BUTTON); |
578 | acpi_deregister_fixed_button(sc, ACPI_EVENT_SLEEP_BUTTON); |
579 | |
580 | pmf_device_deregister(self); |
581 | |
582 | acpi_softc = NULL; |
583 | |
584 | return 0; |
585 | } |
586 | |
587 | static void |
588 | acpi_childdet(device_t self, device_t child) |
589 | { |
590 | struct acpi_softc *sc = device_private(self); |
591 | struct acpi_devnode *ad; |
592 | |
593 | if (sc->sc_apmbus == child) |
594 | sc->sc_apmbus = NULL; |
595 | |
596 | if (sc->sc_hpet == child) |
597 | sc->sc_hpet = NULL; |
598 | |
599 | if (sc->sc_wdrt == child) |
600 | sc->sc_wdrt = NULL; |
601 | |
602 | SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) { |
603 | |
604 | if (ad->ad_device == child) |
605 | ad->ad_device = NULL; |
606 | } |
607 | } |
608 | |
609 | static bool |
610 | acpi_suspend(device_t dv, const pmf_qual_t *qual) |
611 | { |
612 | |
613 | acpi_suspended = 1; |
614 | |
615 | return true; |
616 | } |
617 | |
618 | static bool |
619 | acpi_resume(device_t dv, const pmf_qual_t *qual) |
620 | { |
621 | |
622 | acpi_suspended = 0; |
623 | |
624 | return true; |
625 | } |
626 | |
627 | /* |
628 | * Namespace scan. |
629 | */ |
630 | static void |
631 | acpi_build_tree(struct acpi_softc *sc) |
632 | { |
633 | struct acpi_walkcontext awc; |
634 | |
635 | /* |
636 | * Get the root scope handles. |
637 | */ |
638 | KASSERT(__arraycount(acpi_scopes) == 4); |
639 | |
640 | (void)AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_PR_" , &acpi_scopes[0]); |
641 | (void)AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_" , &acpi_scopes[1]); |
642 | (void)AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SI_" , &acpi_scopes[2]); |
643 | (void)AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_TZ_" , &acpi_scopes[3]); |
644 | |
645 | /* |
646 | * Make the root node. |
647 | */ |
648 | awc.aw_sc = sc; |
649 | awc.aw_parent = NULL; |
650 | |
651 | (void)acpi_make_devnode(ACPI_ROOT_OBJECT, 0, &awc, NULL); |
652 | |
653 | KASSERT(sc->sc_root == NULL); |
654 | KASSERT(awc.aw_parent != NULL); |
655 | |
656 | sc->sc_root = awc.aw_parent; |
657 | |
658 | /* |
659 | * Build the internal namespace. |
660 | */ |
661 | (void)AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, UINT32_MAX, |
662 | acpi_make_devnode, acpi_make_devnode_post, &awc, NULL); |
663 | |
664 | /* |
665 | * Scan the internal namespace. |
666 | */ |
667 | (void)acpi_pcidev_scan(sc->sc_root); |
668 | } |
669 | |
670 | static void |
671 | acpi_config_tree(struct acpi_softc *sc) |
672 | { |
673 | |
674 | /* |
675 | * Configure all everything found "at acpi?". |
676 | */ |
677 | (void)acpi_rescan(sc->sc_dev, NULL, NULL); |
678 | |
679 | /* |
680 | * Update GPE information. |
681 | * |
682 | * Note that this must be called after |
683 | * all GPE handlers have been installed. |
684 | */ |
685 | (void)AcpiUpdateAllGpes(); |
686 | |
687 | /* |
688 | * Defer rest of the configuration. |
689 | */ |
690 | (void)config_defer(sc->sc_dev, acpi_rescan_capabilities); |
691 | } |
692 | |
693 | static ACPI_STATUS |
694 | acpi_make_devnode(ACPI_HANDLE handle, uint32_t level, |
695 | void *context, void **status) |
696 | { |
697 | struct acpi_walkcontext *awc = context; |
698 | struct acpi_softc *sc = awc->aw_sc; |
699 | struct acpi_devnode *ad; |
700 | ACPI_DEVICE_INFO *devinfo; |
701 | ACPI_OBJECT_TYPE type; |
702 | ACPI_STATUS rv; |
703 | |
704 | rv = AcpiGetObjectInfo(handle, &devinfo); |
705 | |
706 | if (ACPI_FAILURE(rv)) |
707 | return AE_OK; /* Do not terminate the walk. */ |
708 | |
709 | type = devinfo->Type; |
710 | |
711 | switch (type) { |
712 | |
713 | case ACPI_TYPE_DEVICE: |
714 | acpi_activate_device(handle, &devinfo); |
715 | case ACPI_TYPE_PROCESSOR: |
716 | case ACPI_TYPE_THERMAL: |
717 | case ACPI_TYPE_POWER: |
718 | |
719 | ad = kmem_zalloc(sizeof(*ad), KM_SLEEP); |
720 | |
721 | if (ad == NULL) |
722 | return AE_NO_MEMORY; |
723 | |
724 | ad->ad_device = NULL; |
725 | ad->ad_notify = NULL; |
726 | ad->ad_pciinfo = NULL; |
727 | ad->ad_wakedev = NULL; |
728 | |
729 | ad->ad_type = type; |
730 | ad->ad_handle = handle; |
731 | ad->ad_devinfo = devinfo; |
732 | |
733 | ad->ad_root = sc->sc_dev; |
734 | ad->ad_parent = awc->aw_parent; |
735 | |
736 | acpi_match_node_init(ad); |
737 | acpi_make_name(ad, devinfo->Name); |
738 | |
739 | /* |
740 | * Identify wake GPEs from the _PRW. Note that |
741 | * AcpiUpdateAllGpes() must be called afterwards. |
742 | */ |
743 | if (ad->ad_devinfo->Type == ACPI_TYPE_DEVICE) |
744 | acpi_wakedev_init(ad); |
745 | |
746 | SIMPLEQ_INIT(&ad->ad_child_head); |
747 | SIMPLEQ_INSERT_TAIL(&sc->ad_head, ad, ad_list); |
748 | |
749 | if (ad->ad_parent != NULL) { |
750 | |
751 | SIMPLEQ_INSERT_TAIL(&ad->ad_parent->ad_child_head, |
752 | ad, ad_child_list); |
753 | } |
754 | |
755 | awc->aw_parent = ad; |
756 | } |
757 | |
758 | return AE_OK; |
759 | } |
760 | |
761 | static ACPI_STATUS |
762 | acpi_make_devnode_post(ACPI_HANDLE handle, uint32_t level, |
763 | void *context, void **status) |
764 | { |
765 | struct acpi_walkcontext *awc = context; |
766 | |
767 | KASSERT(awc != NULL); |
768 | KASSERT(awc->aw_parent != NULL); |
769 | |
770 | if (handle == awc->aw_parent->ad_handle) |
771 | awc->aw_parent = awc->aw_parent->ad_parent; |
772 | |
773 | return AE_OK; |
774 | } |
775 | |
776 | static void |
777 | acpi_make_name(struct acpi_devnode *ad, uint32_t name) |
778 | { |
779 | ACPI_NAME_UNION *anu; |
780 | int clear, i; |
781 | |
782 | anu = (ACPI_NAME_UNION *)&name; |
783 | ad->ad_name[4] = '\0'; |
784 | |
785 | for (i = 3, clear = 0; i >= 0; i--) { |
786 | |
787 | if (clear == 0 && anu->Ascii[i] == '_') |
788 | ad->ad_name[i] = '\0'; |
789 | else { |
790 | ad->ad_name[i] = anu->Ascii[i]; |
791 | clear = 1; |
792 | } |
793 | } |
794 | |
795 | if (ad->ad_name[0] == '\0') |
796 | ad->ad_name[0] = '_'; |
797 | } |
798 | |
799 | /* |
800 | * Device attachment. |
801 | */ |
802 | static int |
803 | acpi_rescan(device_t self, const char *ifattr, const int *locators) |
804 | { |
805 | struct acpi_softc *sc = device_private(self); |
806 | struct acpi_attach_args aa; |
807 | |
808 | /* |
809 | * Try to attach hpet(4) first via a specific table. |
810 | */ |
811 | aa.aa_memt = sc->sc_memt; |
812 | |
813 | if (ifattr_match(ifattr, "acpihpetbus" ) && sc->sc_hpet == NULL) |
814 | sc->sc_hpet = config_found_ia(sc->sc_dev, |
815 | "acpihpetbus" , &aa, NULL); |
816 | |
817 | /* |
818 | * A two-pass scan for acpinodebus. |
819 | */ |
820 | if (ifattr_match(ifattr, "acpinodebus" )) { |
821 | acpi_rescan_early(sc); |
822 | acpi_rescan_nodes(sc); |
823 | } |
824 | |
825 | /* |
826 | * Attach APM emulation and acpiwdrt(4). |
827 | */ |
828 | if (ifattr_match(ifattr, "acpiapmbus" ) && sc->sc_apmbus == NULL) |
829 | sc->sc_apmbus = config_found_ia(sc->sc_dev, |
830 | "acpiapmbus" , NULL, NULL); |
831 | |
832 | if (ifattr_match(ifattr, "acpiwdrtbus" ) && sc->sc_wdrt == NULL) |
833 | sc->sc_wdrt = config_found_ia(sc->sc_dev, |
834 | "acpiwdrtbus" , NULL, NULL); |
835 | |
836 | return 0; |
837 | } |
838 | |
839 | static void |
840 | acpi_rescan_early(struct acpi_softc *sc) |
841 | { |
842 | struct acpi_attach_args aa; |
843 | struct acpi_devnode *ad; |
844 | |
845 | /* |
846 | * First scan for devices such as acpiec(4) that |
847 | * should be always attached before anything else. |
848 | * We want these devices to attach regardless of |
849 | * the device status and other restrictions. |
850 | */ |
851 | SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) { |
852 | |
853 | if (ad->ad_device != NULL) |
854 | continue; |
855 | |
856 | if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) |
857 | continue; |
858 | |
859 | if (acpi_match_hid(ad->ad_devinfo, acpi_early_ids) == 0) |
860 | continue; |
861 | |
862 | aa.aa_node = ad; |
863 | aa.aa_iot = sc->sc_iot; |
864 | aa.aa_memt = sc->sc_memt; |
865 | aa.aa_pc = sc->sc_pc; |
866 | aa.aa_pciflags = sc->sc_pciflags; |
867 | aa.aa_ic = sc->sc_ic; |
868 | aa.aa_dmat = sc->sc_dmat; |
869 | aa.aa_dmat64 = sc->sc_dmat64; |
870 | |
871 | ad->ad_device = config_found_ia(sc->sc_dev, |
872 | "acpinodebus" , &aa, acpi_print); |
873 | } |
874 | } |
875 | |
876 | static void |
877 | acpi_rescan_nodes(struct acpi_softc *sc) |
878 | { |
879 | const char * const hpet_ids[] = { "PNP0103" , NULL }; |
880 | struct acpi_attach_args aa; |
881 | struct acpi_devnode *ad; |
882 | ACPI_DEVICE_INFO *di; |
883 | |
884 | SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) { |
885 | |
886 | if (ad->ad_device != NULL) |
887 | continue; |
888 | |
889 | /* |
890 | * There is a bug in ACPICA: it defines the type |
891 | * of the scopes incorrectly for its own reasons. |
892 | */ |
893 | if (acpi_is_scope(ad) != false) |
894 | continue; |
895 | |
896 | di = ad->ad_devinfo; |
897 | |
898 | /* |
899 | * We only attach devices which are present, enabled, and |
900 | * functioning properly. However, if a device is enabled, |
901 | * it is decoding resources and we should claim these, |
902 | * if possible. This requires changes to bus_space(9). |
903 | * Note: there is a possible race condition, because _STA |
904 | * may have changed since di->CurrentStatus was set. |
905 | */ |
906 | if (di->Type == ACPI_TYPE_DEVICE) { |
907 | |
908 | if ((di->Valid & ACPI_VALID_STA) != 0 && |
909 | (di->CurrentStatus & ACPI_STA_OK) != ACPI_STA_OK) |
910 | continue; |
911 | } |
912 | |
913 | if (di->Type == ACPI_TYPE_POWER) |
914 | continue; |
915 | |
916 | if (di->Type == ACPI_TYPE_PROCESSOR) |
917 | continue; |
918 | |
919 | if (acpi_match_hid(di, acpi_early_ids) != 0) |
920 | continue; |
921 | |
922 | if (acpi_match_hid(di, acpi_ignored_ids) != 0) |
923 | continue; |
924 | |
925 | if (acpi_match_hid(di, hpet_ids) != 0 && sc->sc_hpet != NULL) |
926 | continue; |
927 | |
928 | aa.aa_node = ad; |
929 | aa.aa_iot = sc->sc_iot; |
930 | aa.aa_memt = sc->sc_memt; |
931 | aa.aa_pc = sc->sc_pc; |
932 | aa.aa_pciflags = sc->sc_pciflags; |
933 | aa.aa_ic = sc->sc_ic; |
934 | aa.aa_dmat = sc->sc_dmat; |
935 | aa.aa_dmat64 = sc->sc_dmat64; |
936 | |
937 | ad->ad_device = config_found_ia(sc->sc_dev, |
938 | "acpinodebus" , &aa, acpi_print); |
939 | } |
940 | } |
941 | |
942 | static void |
943 | acpi_rescan_capabilities(device_t self) |
944 | { |
945 | struct acpi_softc *sc = device_private(self); |
946 | struct acpi_devnode *ad; |
947 | ACPI_HANDLE tmp; |
948 | ACPI_STATUS rv; |
949 | |
950 | SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) { |
951 | |
952 | if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE) |
953 | continue; |
954 | |
955 | /* |
956 | * Scan power resource capabilities. |
957 | * |
958 | * If any power states are supported, |
959 | * at least _PR0 and _PR3 must be present. |
960 | */ |
961 | rv = AcpiGetHandle(ad->ad_handle, "_PR0" , &tmp); |
962 | |
963 | if (ACPI_SUCCESS(rv)) { |
964 | ad->ad_flags |= ACPI_DEVICE_POWER; |
965 | acpi_power_add(ad); |
966 | } |
967 | |
968 | /* |
969 | * Scan wake-up capabilities. |
970 | */ |
971 | if (ad->ad_wakedev != NULL) { |
972 | ad->ad_flags |= ACPI_DEVICE_WAKEUP; |
973 | acpi_wakedev_add(ad); |
974 | } |
975 | |
976 | /* |
977 | * Scan docking stations. |
978 | */ |
979 | rv = AcpiGetHandle(ad->ad_handle, "_DCK" , &tmp); |
980 | |
981 | if (ACPI_SUCCESS(rv)) |
982 | ad->ad_flags |= ACPI_DEVICE_DOCK; |
983 | |
984 | /* |
985 | * Scan devices that are ejectable. |
986 | */ |
987 | rv = AcpiGetHandle(ad->ad_handle, "_EJ0" , &tmp); |
988 | |
989 | if (ACPI_SUCCESS(rv)) |
990 | ad->ad_flags |= ACPI_DEVICE_EJECT; |
991 | } |
992 | } |
993 | |
994 | static int |
995 | acpi_print(void *aux, const char *pnp) |
996 | { |
997 | struct acpi_attach_args *aa = aux; |
998 | struct acpi_devnode *ad; |
999 | const char *hid, *uid; |
1000 | ACPI_DEVICE_INFO *di; |
1001 | |
1002 | ad = aa->aa_node; |
1003 | di = ad->ad_devinfo; |
1004 | |
1005 | hid = di->HardwareId.String; |
1006 | uid = di->UniqueId.String; |
1007 | |
1008 | if (pnp != NULL) { |
1009 | |
1010 | if (di->Type != ACPI_TYPE_DEVICE) { |
1011 | |
1012 | aprint_normal("%s (ACPI Object Type '%s') at %s" , |
1013 | ad->ad_name, AcpiUtGetTypeName(ad->ad_type), pnp); |
1014 | |
1015 | return UNCONF; |
1016 | } |
1017 | |
1018 | if ((di->Valid & ACPI_VALID_HID) == 0 || hid == NULL) |
1019 | return 0; |
1020 | |
1021 | aprint_normal("%s (%s) " , ad->ad_name, hid); |
1022 | acpi_print_dev(hid); |
1023 | aprint_normal("at %s" , pnp); |
1024 | |
1025 | return UNCONF; |
1026 | } |
1027 | |
1028 | aprint_normal(" (%s" , ad->ad_name); |
1029 | |
1030 | if ((di->Valid & ACPI_VALID_HID) != 0 && hid != NULL) { |
1031 | |
1032 | aprint_normal(", %s" , hid); |
1033 | |
1034 | if ((di->Valid & ACPI_VALID_UID) != 0 && uid != NULL) { |
1035 | |
1036 | if (uid[0] == '\0') |
1037 | uid = "<null>" ; |
1038 | |
1039 | aprint_normal("-%s" , uid); |
1040 | } |
1041 | } |
1042 | |
1043 | aprint_normal(")" ); |
1044 | |
1045 | return UNCONF; |
1046 | } |
1047 | |
1048 | /* |
1049 | * Notify. |
1050 | */ |
1051 | static void |
1052 | acpi_notify_handler(ACPI_HANDLE handle, uint32_t event, void *aux) |
1053 | { |
1054 | struct acpi_softc *sc = acpi_softc; |
1055 | struct acpi_devnode *ad; |
1056 | |
1057 | KASSERT(sc != NULL); |
1058 | KASSERT(aux == NULL); |
1059 | KASSERT(acpi_active != 0); |
1060 | |
1061 | if (acpi_suspended != 0) |
1062 | return; |
1063 | |
1064 | /* |
1065 | * System: 0x00 - 0x7F. |
1066 | * Device: 0x80 - 0xFF. |
1067 | */ |
1068 | switch (event) { |
1069 | |
1070 | case ACPI_NOTIFY_BUS_CHECK: |
1071 | case ACPI_NOTIFY_DEVICE_CHECK: |
1072 | case ACPI_NOTIFY_DEVICE_WAKE: |
1073 | case ACPI_NOTIFY_EJECT_REQUEST: |
1074 | case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: |
1075 | case ACPI_NOTIFY_FREQUENCY_MISMATCH: |
1076 | case ACPI_NOTIFY_BUS_MODE_MISMATCH: |
1077 | case ACPI_NOTIFY_POWER_FAULT: |
1078 | case ACPI_NOTIFY_CAPABILITIES_CHECK: |
1079 | case ACPI_NOTIFY_DEVICE_PLD_CHECK: |
1080 | case ACPI_NOTIFY_RESERVED: |
1081 | case ACPI_NOTIFY_LOCALITY_UPDATE: |
1082 | break; |
1083 | } |
1084 | |
1085 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "notification 0x%02X for " |
1086 | "%s (%p)\n" , event, acpi_name(handle), handle)); |
1087 | |
1088 | /* |
1089 | * We deliver notifications only to drivers |
1090 | * that have been successfully attached and |
1091 | * that have registered a handler with us. |
1092 | * The opaque pointer is always the device_t. |
1093 | */ |
1094 | SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) { |
1095 | |
1096 | if (ad->ad_device == NULL) |
1097 | continue; |
1098 | |
1099 | if (ad->ad_notify == NULL) |
1100 | continue; |
1101 | |
1102 | if (ad->ad_handle != handle) |
1103 | continue; |
1104 | |
1105 | (*ad->ad_notify)(ad->ad_handle, event, ad->ad_device); |
1106 | |
1107 | return; |
1108 | } |
1109 | |
1110 | aprint_debug_dev(sc->sc_dev, "unhandled notify 0x%02X " |
1111 | "for %s (%p)\n" , event, acpi_name(handle), handle); |
1112 | } |
1113 | |
1114 | bool |
1115 | acpi_register_notify(struct acpi_devnode *ad, ACPI_NOTIFY_HANDLER notify) |
1116 | { |
1117 | struct acpi_softc *sc = acpi_softc; |
1118 | |
1119 | KASSERT(sc != NULL); |
1120 | KASSERT(acpi_active != 0); |
1121 | |
1122 | if (acpi_suspended != 0) |
1123 | goto fail; |
1124 | |
1125 | if (ad == NULL || notify == NULL) |
1126 | goto fail; |
1127 | |
1128 | ad->ad_notify = notify; |
1129 | |
1130 | return true; |
1131 | |
1132 | fail: |
1133 | aprint_error_dev(sc->sc_dev, "failed to register notify " |
1134 | "handler for %s (%p)\n" , ad->ad_name, ad->ad_handle); |
1135 | |
1136 | return false; |
1137 | } |
1138 | |
1139 | void |
1140 | acpi_deregister_notify(struct acpi_devnode *ad) |
1141 | { |
1142 | |
1143 | ad->ad_notify = NULL; |
1144 | } |
1145 | |
1146 | /* |
1147 | * Fixed buttons. |
1148 | */ |
1149 | static void |
1150 | acpi_register_fixed_button(struct acpi_softc *sc, int event) |
1151 | { |
1152 | struct sysmon_pswitch *smpsw; |
1153 | ACPI_STATUS rv; |
1154 | int type; |
1155 | |
1156 | switch (event) { |
1157 | |
1158 | case ACPI_EVENT_POWER_BUTTON: |
1159 | |
1160 | if ((AcpiGbl_FADT.Flags & ACPI_FADT_POWER_BUTTON) != 0) |
1161 | return; |
1162 | |
1163 | type = PSWITCH_TYPE_POWER; |
1164 | smpsw = &sc->sc_smpsw_power; |
1165 | break; |
1166 | |
1167 | case ACPI_EVENT_SLEEP_BUTTON: |
1168 | |
1169 | if ((AcpiGbl_FADT.Flags & ACPI_FADT_SLEEP_BUTTON) != 0) |
1170 | return; |
1171 | |
1172 | type = PSWITCH_TYPE_SLEEP; |
1173 | smpsw = &sc->sc_smpsw_sleep; |
1174 | break; |
1175 | |
1176 | default: |
1177 | rv = AE_TYPE; |
1178 | goto fail; |
1179 | } |
1180 | |
1181 | smpsw->smpsw_type = type; |
1182 | smpsw->smpsw_name = device_xname(sc->sc_dev); |
1183 | |
1184 | if (sysmon_pswitch_register(smpsw) != 0) { |
1185 | rv = AE_ERROR; |
1186 | goto fail; |
1187 | } |
1188 | |
1189 | AcpiClearEvent(event); |
1190 | |
1191 | rv = AcpiInstallFixedEventHandler(event, |
1192 | acpi_fixed_button_handler, smpsw); |
1193 | |
1194 | if (ACPI_FAILURE(rv)) { |
1195 | sysmon_pswitch_unregister(smpsw); |
1196 | goto fail; |
1197 | } |
1198 | |
1199 | aprint_debug_dev(sc->sc_dev, "fixed %s button present\n" , |
1200 | (type != ACPI_EVENT_SLEEP_BUTTON) ? "power" : "sleep" ); |
1201 | |
1202 | return; |
1203 | |
1204 | fail: |
1205 | aprint_error_dev(sc->sc_dev, "failed to register " |
1206 | "fixed event %d: %s\n" , event, AcpiFormatException(rv)); |
1207 | } |
1208 | |
1209 | static void |
1210 | acpi_deregister_fixed_button(struct acpi_softc *sc, int event) |
1211 | { |
1212 | struct sysmon_pswitch *smpsw; |
1213 | ACPI_STATUS rv; |
1214 | |
1215 | switch (event) { |
1216 | |
1217 | case ACPI_EVENT_POWER_BUTTON: |
1218 | smpsw = &sc->sc_smpsw_power; |
1219 | |
1220 | if ((AcpiGbl_FADT.Flags & ACPI_FADT_POWER_BUTTON) != 0) { |
1221 | KASSERT(smpsw->smpsw_type != PSWITCH_TYPE_POWER); |
1222 | return; |
1223 | } |
1224 | |
1225 | break; |
1226 | |
1227 | case ACPI_EVENT_SLEEP_BUTTON: |
1228 | smpsw = &sc->sc_smpsw_sleep; |
1229 | |
1230 | if ((AcpiGbl_FADT.Flags & ACPI_FADT_SLEEP_BUTTON) != 0) { |
1231 | KASSERT(smpsw->smpsw_type != PSWITCH_TYPE_SLEEP); |
1232 | return; |
1233 | } |
1234 | |
1235 | break; |
1236 | |
1237 | default: |
1238 | rv = AE_TYPE; |
1239 | goto fail; |
1240 | } |
1241 | |
1242 | rv = AcpiRemoveFixedEventHandler(event, acpi_fixed_button_handler); |
1243 | |
1244 | if (ACPI_SUCCESS(rv)) { |
1245 | sysmon_pswitch_unregister(smpsw); |
1246 | return; |
1247 | } |
1248 | |
1249 | fail: |
1250 | aprint_error_dev(sc->sc_dev, "failed to deregister " |
1251 | "fixed event: %s\n" , AcpiFormatException(rv)); |
1252 | } |
1253 | |
1254 | static uint32_t |
1255 | acpi_fixed_button_handler(void *context) |
1256 | { |
1257 | static const int handler = OSL_NOTIFY_HANDLER; |
1258 | struct sysmon_pswitch *smpsw = context; |
1259 | |
1260 | (void)AcpiOsExecute(handler, acpi_fixed_button_pressed, smpsw); |
1261 | |
1262 | return ACPI_INTERRUPT_HANDLED; |
1263 | } |
1264 | |
1265 | static void |
1266 | acpi_fixed_button_pressed(void *context) |
1267 | { |
1268 | struct sysmon_pswitch *smpsw = context; |
1269 | |
1270 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s fixed button pressed\n" , |
1271 | (smpsw->smpsw_type != ACPI_EVENT_SLEEP_BUTTON) ? |
1272 | "power" : "sleep" )); |
1273 | |
1274 | sysmon_pswitch_event(smpsw, PSWITCH_EVENT_PRESSED); |
1275 | } |
1276 | |
1277 | /* |
1278 | * Sleep. |
1279 | */ |
1280 | static void |
1281 | acpi_sleep_init(struct acpi_softc *sc) |
1282 | { |
1283 | uint8_t a, b, i; |
1284 | ACPI_STATUS rv; |
1285 | |
1286 | CTASSERT(ACPI_STATE_S0 == 0 && ACPI_STATE_S1 == 1); |
1287 | CTASSERT(ACPI_STATE_S2 == 2 && ACPI_STATE_S3 == 3); |
1288 | CTASSERT(ACPI_STATE_S4 == 4 && ACPI_STATE_S5 == 5); |
1289 | |
1290 | /* |
1291 | * Evaluate supported sleep states. |
1292 | */ |
1293 | for (i = ACPI_STATE_S0; i <= ACPI_STATE_S5; i++) { |
1294 | |
1295 | rv = AcpiGetSleepTypeData(i, &a, &b); |
1296 | |
1297 | if (ACPI_SUCCESS(rv)) |
1298 | sc->sc_sleepstates |= __BIT(i); |
1299 | } |
1300 | } |
1301 | |
1302 | /* |
1303 | * Must be called with interrupts enabled. |
1304 | */ |
1305 | void |
1306 | acpi_enter_sleep_state(int state) |
1307 | { |
1308 | struct acpi_softc *sc = acpi_softc; |
1309 | ACPI_STATUS rv; |
1310 | |
1311 | if (acpi_softc == NULL) |
1312 | return; |
1313 | |
1314 | if (state == sc->sc_sleepstate) |
1315 | return; |
1316 | |
1317 | if (state < ACPI_STATE_S0 || state > ACPI_STATE_S5) |
1318 | return; |
1319 | |
1320 | aprint_normal_dev(sc->sc_dev, "entering state S%d\n" , state); |
1321 | |
1322 | switch (state) { |
1323 | |
1324 | case ACPI_STATE_S0: |
1325 | sc->sc_sleepstate = ACPI_STATE_S0; |
1326 | return; |
1327 | |
1328 | case ACPI_STATE_S1: |
1329 | case ACPI_STATE_S2: |
1330 | case ACPI_STATE_S3: |
1331 | case ACPI_STATE_S4: |
1332 | |
1333 | if ((sc->sc_sleepstates & __BIT(state)) == 0) { |
1334 | aprint_error_dev(sc->sc_dev, "sleep state " |
1335 | "S%d is not available\n" , state); |
1336 | return; |
1337 | } |
1338 | |
1339 | /* |
1340 | * Evaluate the _TTS method. This should be done before |
1341 | * pmf_system_suspend(9) and the evaluation of _PTS. |
1342 | * We should also re-evaluate this once we return to |
1343 | * S0 or if we abort the sleep state transition in the |
1344 | * middle (see ACPI 3.0, section 7.3.6). In reality, |
1345 | * however, the _TTS method is seldom seen in the field. |
1346 | */ |
1347 | rv = acpi_eval_set_integer(NULL, "\\_TTS" , state); |
1348 | |
1349 | if (ACPI_SUCCESS(rv)) |
1350 | aprint_debug_dev(sc->sc_dev, "evaluated _TTS\n" ); |
1351 | |
1352 | if (state != ACPI_STATE_S1 && |
1353 | pmf_system_suspend(PMF_Q_NONE) != true) { |
1354 | aprint_error_dev(sc->sc_dev, "aborting suspend\n" ); |
1355 | break; |
1356 | } |
1357 | |
1358 | /* |
1359 | * This will evaluate the _PTS and _SST methods, |
1360 | * but unlike the documentation claims, not _GTS, |
1361 | * which is evaluated in AcpiEnterSleepState(). |
1362 | * This must be called with interrupts enabled. |
1363 | */ |
1364 | rv = AcpiEnterSleepStatePrep(state); |
1365 | |
1366 | if (ACPI_FAILURE(rv)) { |
1367 | aprint_error_dev(sc->sc_dev, "failed to prepare " |
1368 | "S%d: %s\n" , state, AcpiFormatException(rv)); |
1369 | break; |
1370 | } |
1371 | |
1372 | /* |
1373 | * After the _PTS method has been evaluated, we can |
1374 | * enable wake and evaluate _PSW (ACPI 4.0, p. 284). |
1375 | */ |
1376 | acpi_wakedev_commit(sc, state); |
1377 | |
1378 | sc->sc_sleepstate = state; |
1379 | |
1380 | if (state == ACPI_STATE_S1) { |
1381 | |
1382 | /* |
1383 | * Before the transition to S1, CPU caches |
1384 | * must be flushed (see ACPI 4.0, 7.3.4.2). |
1385 | * |
1386 | * Note that interrupts must be off before |
1387 | * calling AcpiEnterSleepState(). Conversely, |
1388 | * AcpiLeaveSleepState() should always be |
1389 | * called with interrupts enabled. |
1390 | */ |
1391 | acpi_md_OsDisableInterrupt(); |
1392 | |
1393 | ACPI_FLUSH_CPU_CACHE(); |
1394 | rv = AcpiEnterSleepState(state); |
1395 | |
1396 | if (ACPI_FAILURE(rv)) |
1397 | aprint_error_dev(sc->sc_dev, "failed to " |
1398 | "enter S1: %s\n" , AcpiFormatException(rv)); |
1399 | |
1400 | /* |
1401 | * Clear fixed events and disable all GPEs before |
1402 | * interrupts are enabled. |
1403 | */ |
1404 | AcpiClearEvent(ACPI_EVENT_PMTIMER); |
1405 | AcpiClearEvent(ACPI_EVENT_GLOBAL); |
1406 | AcpiClearEvent(ACPI_EVENT_POWER_BUTTON); |
1407 | AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON); |
1408 | AcpiClearEvent(ACPI_EVENT_RTC); |
1409 | AcpiHwDisableAllGpes(); |
1410 | |
1411 | acpi_md_OsEnableInterrupt(); |
1412 | rv = AcpiLeaveSleepState(state); |
1413 | |
1414 | } else { |
1415 | |
1416 | (void)acpi_md_sleep(state); |
1417 | |
1418 | if (state == ACPI_STATE_S4) |
1419 | AcpiEnable(); |
1420 | |
1421 | (void)pmf_system_bus_resume(PMF_Q_NONE); |
1422 | (void)AcpiLeaveSleepState(state); |
1423 | (void)AcpiSetFirmwareWakingVector(0, 0); |
1424 | (void)pmf_system_resume(PMF_Q_NONE); |
1425 | } |
1426 | |
1427 | /* |
1428 | * No wake GPEs should be enabled at runtime. |
1429 | */ |
1430 | acpi_wakedev_commit(sc, ACPI_STATE_S0); |
1431 | break; |
1432 | |
1433 | case ACPI_STATE_S5: |
1434 | |
1435 | (void)acpi_eval_set_integer(NULL, "\\_TTS" , ACPI_STATE_S5); |
1436 | |
1437 | rv = AcpiEnterSleepStatePrep(ACPI_STATE_S5); |
1438 | |
1439 | if (ACPI_FAILURE(rv)) { |
1440 | aprint_error_dev(sc->sc_dev, "failed to prepare " |
1441 | "S%d: %s\n" , state, AcpiFormatException(rv)); |
1442 | break; |
1443 | } |
1444 | |
1445 | (void)AcpiDisableAllGpes(); |
1446 | |
1447 | DELAY(1000000); |
1448 | |
1449 | sc->sc_sleepstate = state; |
1450 | acpi_md_OsDisableInterrupt(); |
1451 | |
1452 | (void)AcpiEnterSleepState(ACPI_STATE_S5); |
1453 | |
1454 | aprint_error_dev(sc->sc_dev, "WARNING: powerdown failed!\n" ); |
1455 | |
1456 | break; |
1457 | } |
1458 | |
1459 | sc->sc_sleepstate = ACPI_STATE_S0; |
1460 | |
1461 | (void)acpi_eval_set_integer(NULL, "\\_TTS" , ACPI_STATE_S0); |
1462 | } |
1463 | |
1464 | /* |
1465 | * Sysctl. |
1466 | */ |
1467 | SYSCTL_SETUP(sysctl_acpi_setup, "sysctl hw.acpi subtree setup" ) |
1468 | { |
1469 | const struct sysctlnode *rnode, *snode; |
1470 | int err; |
1471 | |
1472 | err = sysctl_createv(clog, 0, NULL, &rnode, |
1473 | CTLFLAG_PERMANENT, CTLTYPE_NODE, |
1474 | "acpi" , SYSCTL_DESCR("ACPI subsystem parameters" ), |
1475 | NULL, 0, NULL, 0, |
1476 | CTL_HW, CTL_CREATE, CTL_EOL); |
1477 | |
1478 | if (err != 0) |
1479 | return; |
1480 | |
1481 | (void)sysctl_createv(NULL, 0, &rnode, NULL, |
1482 | CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_QUAD, |
1483 | "root" , SYSCTL_DESCR("ACPI root pointer" ), |
1484 | NULL, 0, &acpi_root_pointer, sizeof(acpi_root_pointer), |
1485 | CTL_CREATE, CTL_EOL); |
1486 | |
1487 | err = sysctl_createv(clog, 0, &rnode, &snode, |
1488 | CTLFLAG_PERMANENT, CTLTYPE_NODE, |
1489 | "sleep" , SYSCTL_DESCR("ACPI sleep" ), |
1490 | NULL, 0, NULL, 0, |
1491 | CTL_CREATE, CTL_EOL); |
1492 | |
1493 | if (err != 0) |
1494 | return; |
1495 | |
1496 | (void)sysctl_createv(NULL, 0, &snode, NULL, |
1497 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, |
1498 | "state" , SYSCTL_DESCR("System sleep state" ), |
1499 | sysctl_hw_acpi_sleepstate, 0, NULL, 0, |
1500 | CTL_CREATE, CTL_EOL); |
1501 | |
1502 | (void)sysctl_createv(NULL, 0, &snode, NULL, |
1503 | CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_STRING, |
1504 | "states" , SYSCTL_DESCR("Supported sleep states" ), |
1505 | sysctl_hw_acpi_sleepstates, 0, NULL, 0, |
1506 | CTL_CREATE, CTL_EOL); |
1507 | |
1508 | err = sysctl_createv(clog, 0, &rnode, &rnode, |
1509 | CTLFLAG_PERMANENT, CTLTYPE_NODE, |
1510 | "stat" , SYSCTL_DESCR("ACPI statistics" ), |
1511 | NULL, 0, NULL, 0, |
1512 | CTL_CREATE, CTL_EOL); |
1513 | |
1514 | if (err != 0) |
1515 | return; |
1516 | |
1517 | (void)sysctl_createv(clog, 0, &rnode, NULL, |
1518 | CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_QUAD, |
1519 | "gpe" , SYSCTL_DESCR("Number of dispatched GPEs" ), |
1520 | NULL, 0, &AcpiGpeCount, sizeof(AcpiGpeCount), |
1521 | CTL_CREATE, CTL_EOL); |
1522 | |
1523 | (void)sysctl_createv(clog, 0, &rnode, NULL, |
1524 | CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_QUAD, |
1525 | "sci" , SYSCTL_DESCR("Number of SCI interrupts" ), |
1526 | NULL, 0, &AcpiSciCount, sizeof(AcpiSciCount), |
1527 | CTL_CREATE, CTL_EOL); |
1528 | |
1529 | (void)sysctl_createv(clog, 0, &rnode, NULL, |
1530 | CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_QUAD, |
1531 | "fixed" , SYSCTL_DESCR("Number of fixed events" ), |
1532 | sysctl_hw_acpi_fixedstats, 0, NULL, 0, |
1533 | CTL_CREATE, CTL_EOL); |
1534 | |
1535 | (void)sysctl_createv(clog, 0, &rnode, NULL, |
1536 | CTLFLAG_PERMANENT | CTLFLAG_READONLY, CTLTYPE_QUAD, |
1537 | "method" , SYSCTL_DESCR("Number of methods executed" ), |
1538 | NULL, 0, &AcpiMethodCount, sizeof(AcpiMethodCount), |
1539 | CTL_CREATE, CTL_EOL); |
1540 | |
1541 | CTASSERT(sizeof(AcpiGpeCount) == sizeof(uint64_t)); |
1542 | CTASSERT(sizeof(AcpiSciCount) == sizeof(uint64_t)); |
1543 | } |
1544 | |
1545 | static int |
1546 | sysctl_hw_acpi_fixedstats(SYSCTLFN_ARGS) |
1547 | { |
1548 | struct sysctlnode node; |
1549 | uint64_t t; |
1550 | int err, i; |
1551 | |
1552 | for (i = t = 0; i < __arraycount(AcpiFixedEventCount); i++) |
1553 | t += AcpiFixedEventCount[i]; |
1554 | |
1555 | node = *rnode; |
1556 | node.sysctl_data = &t; |
1557 | |
1558 | err = sysctl_lookup(SYSCTLFN_CALL(&node)); |
1559 | |
1560 | if (err || newp == NULL) |
1561 | return err; |
1562 | |
1563 | return 0; |
1564 | } |
1565 | |
1566 | static int |
1567 | sysctl_hw_acpi_sleepstate(SYSCTLFN_ARGS) |
1568 | { |
1569 | struct acpi_softc *sc = acpi_softc; |
1570 | struct sysctlnode node; |
1571 | int err, t; |
1572 | |
1573 | if (acpi_softc == NULL) |
1574 | return ENOSYS; |
1575 | |
1576 | node = *rnode; |
1577 | t = sc->sc_sleepstate; |
1578 | node.sysctl_data = &t; |
1579 | |
1580 | err = sysctl_lookup(SYSCTLFN_CALL(&node)); |
1581 | |
1582 | if (err || newp == NULL) |
1583 | return err; |
1584 | |
1585 | if (t < ACPI_STATE_S0 || t > ACPI_STATE_S5) |
1586 | return EINVAL; |
1587 | |
1588 | acpi_enter_sleep_state(t); |
1589 | |
1590 | return 0; |
1591 | } |
1592 | |
1593 | static int |
1594 | sysctl_hw_acpi_sleepstates(SYSCTLFN_ARGS) |
1595 | { |
1596 | struct acpi_softc *sc = acpi_softc; |
1597 | struct sysctlnode node; |
1598 | char t[3 * 6 + 1]; |
1599 | int err; |
1600 | |
1601 | if (acpi_softc == NULL) |
1602 | return ENOSYS; |
1603 | |
1604 | (void)memset(t, '\0', sizeof(t)); |
1605 | |
1606 | (void)snprintf(t, sizeof(t), "%s%s%s%s%s%s" , |
1607 | ((sc->sc_sleepstates & __BIT(0)) != 0) ? "S0 " : "" , |
1608 | ((sc->sc_sleepstates & __BIT(1)) != 0) ? "S1 " : "" , |
1609 | ((sc->sc_sleepstates & __BIT(2)) != 0) ? "S2 " : "" , |
1610 | ((sc->sc_sleepstates & __BIT(3)) != 0) ? "S3 " : "" , |
1611 | ((sc->sc_sleepstates & __BIT(4)) != 0) ? "S4 " : "" , |
1612 | ((sc->sc_sleepstates & __BIT(5)) != 0) ? "S5 " : "" ); |
1613 | |
1614 | node = *rnode; |
1615 | node.sysctl_data = &t; |
1616 | |
1617 | err = sysctl_lookup(SYSCTLFN_CALL(&node)); |
1618 | |
1619 | if (err || newp == NULL) |
1620 | return err; |
1621 | |
1622 | return 0; |
1623 | } |
1624 | |
1625 | /* |
1626 | * Tables. |
1627 | */ |
1628 | ACPI_PHYSICAL_ADDRESS |
1629 | acpi_OsGetRootPointer(void) |
1630 | { |
1631 | ACPI_PHYSICAL_ADDRESS PhysicalAddress; |
1632 | |
1633 | /* |
1634 | * We let MD code handle this since there are multiple ways to do it: |
1635 | * |
1636 | * IA-32: Use AcpiFindRootPointer() to locate the RSDP. |
1637 | * |
1638 | * IA-64: Use the EFI. |
1639 | */ |
1640 | PhysicalAddress = acpi_md_OsGetRootPointer(); |
1641 | |
1642 | if (acpi_root_pointer == 0) |
1643 | acpi_root_pointer = PhysicalAddress; |
1644 | |
1645 | return PhysicalAddress; |
1646 | } |
1647 | |
1648 | static ACPI_TABLE_HEADER * |
1649 | acpi_map_rsdt(void) |
1650 | { |
1651 | ACPI_PHYSICAL_ADDRESS paddr; |
1652 | ACPI_TABLE_RSDP *rsdp; |
1653 | |
1654 | paddr = AcpiOsGetRootPointer(); |
1655 | |
1656 | if (paddr == 0) |
1657 | return NULL; |
1658 | |
1659 | rsdp = AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_RSDP)); |
1660 | |
1661 | if (rsdp == NULL) |
1662 | return NULL; |
1663 | |
1664 | if (rsdp->Revision > 1 && rsdp->XsdtPhysicalAddress) |
1665 | paddr = rsdp->XsdtPhysicalAddress; |
1666 | else |
1667 | paddr = rsdp->RsdtPhysicalAddress; |
1668 | |
1669 | AcpiOsUnmapMemory(rsdp, sizeof(ACPI_TABLE_RSDP)); |
1670 | |
1671 | return AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_HEADER)); |
1672 | } |
1673 | |
1674 | /* |
1675 | * XXX: Refactor to be a generic function that unmaps tables. |
1676 | */ |
1677 | static void |
1678 | acpi_unmap_rsdt(ACPI_TABLE_HEADER *rsdt) |
1679 | { |
1680 | |
1681 | if (rsdt == NULL) |
1682 | return; |
1683 | |
1684 | AcpiOsUnmapMemory(rsdt, sizeof(ACPI_TABLE_HEADER)); |
1685 | } |
1686 | |
1687 | /* |
1688 | * XXX: Refactor to be a generic function that maps tables. |
1689 | */ |
1690 | ACPI_STATUS |
1691 | acpi_madt_map(void) |
1692 | { |
1693 | ACPI_STATUS rv; |
1694 | |
1695 | if (madt_header != NULL) |
1696 | return AE_ALREADY_EXISTS; |
1697 | |
1698 | rv = AcpiGetTable(ACPI_SIG_MADT, 1, &madt_header); |
1699 | |
1700 | if (ACPI_FAILURE(rv)) |
1701 | return rv; |
1702 | |
1703 | return AE_OK; |
1704 | } |
1705 | |
1706 | void |
1707 | acpi_madt_unmap(void) |
1708 | { |
1709 | madt_header = NULL; |
1710 | } |
1711 | |
1712 | /* |
1713 | * XXX: Refactor to be a generic function that walks tables. |
1714 | */ |
1715 | void |
1716 | acpi_madt_walk(ACPI_STATUS (*func)(ACPI_SUBTABLE_HEADER *, void *), void *aux) |
1717 | { |
1718 | ACPI_SUBTABLE_HEADER *hdrp; |
1719 | char *madtend, *where; |
1720 | |
1721 | madtend = (char *)madt_header + madt_header->Length; |
1722 | where = (char *)madt_header + sizeof (ACPI_TABLE_MADT); |
1723 | |
1724 | while (where < madtend) { |
1725 | |
1726 | hdrp = (ACPI_SUBTABLE_HEADER *)where; |
1727 | |
1728 | if (ACPI_FAILURE(func(hdrp, aux))) |
1729 | break; |
1730 | |
1731 | where += hdrp->Length; |
1732 | } |
1733 | } |
1734 | |
1735 | /* |
1736 | * Miscellaneous. |
1737 | */ |
1738 | static bool |
1739 | acpi_is_scope(struct acpi_devnode *ad) |
1740 | { |
1741 | int i; |
1742 | |
1743 | /* |
1744 | * Return true if the node is a root scope. |
1745 | */ |
1746 | if (ad->ad_parent == NULL) |
1747 | return false; |
1748 | |
1749 | if (ad->ad_parent->ad_handle != ACPI_ROOT_OBJECT) |
1750 | return false; |
1751 | |
1752 | for (i = 0; i < __arraycount(acpi_scopes); i++) { |
1753 | |
1754 | if (acpi_scopes[i] == NULL) |
1755 | continue; |
1756 | |
1757 | if (ad->ad_handle == acpi_scopes[i]) |
1758 | return true; |
1759 | } |
1760 | |
1761 | return false; |
1762 | } |
1763 | |
1764 | /* |
1765 | * ACPIVERBOSE. |
1766 | */ |
1767 | void |
1768 | acpi_load_verbose(void) |
1769 | { |
1770 | |
1771 | if (acpi_verbose_loaded == 0) |
1772 | module_autoload("acpiverbose" , MODULE_CLASS_MISC); |
1773 | } |
1774 | |
1775 | void |
1776 | acpi_print_verbose_stub(struct acpi_softc *sc) |
1777 | { |
1778 | |
1779 | acpi_load_verbose(); |
1780 | |
1781 | if (acpi_verbose_loaded != 0) |
1782 | acpi_print_verbose(sc); |
1783 | } |
1784 | |
1785 | void |
1786 | acpi_print_dev_stub(const char *pnpstr) |
1787 | { |
1788 | |
1789 | acpi_load_verbose(); |
1790 | |
1791 | if (acpi_verbose_loaded != 0) |
1792 | acpi_print_dev(pnpstr); |
1793 | } |
1794 | |
1795 | MALLOC_DECLARE(M_ACPI); /* XXX: ACPI_ACTIVATE_DEV should use kmem(9). */ |
1796 | |
1797 | /* |
1798 | * ACPI_ACTIVATE_DEV. |
1799 | */ |
1800 | static void |
1801 | acpi_activate_device(ACPI_HANDLE handle, ACPI_DEVICE_INFO **di) |
1802 | { |
1803 | |
1804 | #ifndef ACPI_ACTIVATE_DEV |
1805 | return; |
1806 | } |
1807 | #else |
1808 | static const int valid = ACPI_VALID_STA | ACPI_VALID_HID; |
1809 | ACPI_DEVICE_INFO *newdi; |
1810 | ACPI_STATUS rv; |
1811 | uint32_t old; |
1812 | |
1813 | /* |
1814 | * If the device is valid and present, |
1815 | * but not enabled, try to activate it. |
1816 | */ |
1817 | if (((*di)->Valid & valid) != valid) |
1818 | return; |
1819 | |
1820 | old = (*di)->CurrentStatus; |
1821 | |
1822 | if ((old & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED)) != |
1823 | ACPI_STA_DEVICE_PRESENT) |
1824 | return; |
1825 | |
1826 | rv = acpi_allocate_resources(handle); |
1827 | |
1828 | if (ACPI_FAILURE(rv)) |
1829 | goto fail; |
1830 | |
1831 | rv = AcpiGetObjectInfo(handle, &newdi); |
1832 | |
1833 | if (ACPI_FAILURE(rv)) |
1834 | goto fail; |
1835 | |
1836 | ACPI_FREE(*di); |
1837 | *di = newdi; |
1838 | |
1839 | aprint_verbose_dev(acpi_softc->sc_dev, |
1840 | "%s activated, STA 0x%08X -> STA 0x%08X\n" , |
1841 | (*di)->HardwareId.String, old, (*di)->CurrentStatus); |
1842 | |
1843 | return; |
1844 | |
1845 | fail: |
1846 | aprint_error_dev(acpi_softc->sc_dev, "failed to " |
1847 | "activate %s\n" , (*di)->HardwareId.String); |
1848 | } |
1849 | |
1850 | /* |
1851 | * XXX: This very incomplete. |
1852 | */ |
1853 | ACPI_STATUS |
1854 | acpi_allocate_resources(ACPI_HANDLE handle) |
1855 | { |
1856 | ACPI_BUFFER bufp, bufc, bufn; |
1857 | ACPI_RESOURCE *resp, *resc, *resn; |
1858 | ACPI_RESOURCE_IRQ *irq; |
1859 | #if 0 |
1860 | ACPI_RESOURCE_EXTENDED_IRQ *xirq; |
1861 | #endif |
1862 | ACPI_STATUS rv; |
1863 | uint delta; |
1864 | |
1865 | rv = acpi_get(handle, &bufp, AcpiGetPossibleResources); |
1866 | if (ACPI_FAILURE(rv)) |
1867 | goto out; |
1868 | rv = acpi_get(handle, &bufc, AcpiGetCurrentResources); |
1869 | if (ACPI_FAILURE(rv)) { |
1870 | goto out1; |
1871 | } |
1872 | |
1873 | bufn.Length = 1000; |
1874 | bufn.Pointer = resn = malloc(bufn.Length, M_ACPI, M_WAITOK); |
1875 | resp = bufp.Pointer; |
1876 | resc = bufc.Pointer; |
1877 | while (resc->Type != ACPI_RESOURCE_TYPE_END_TAG && |
1878 | resp->Type != ACPI_RESOURCE_TYPE_END_TAG) { |
1879 | while (resc->Type != resp->Type && resp->Type != ACPI_RESOURCE_TYPE_END_TAG) |
1880 | resp = ACPI_NEXT_RESOURCE(resp); |
1881 | if (resp->Type == ACPI_RESOURCE_TYPE_END_TAG) |
1882 | break; |
1883 | /* Found identical Id */ |
1884 | resn->Type = resc->Type; |
1885 | switch (resc->Type) { |
1886 | case ACPI_RESOURCE_TYPE_IRQ: |
1887 | memcpy(&resn->Data, &resp->Data, |
1888 | sizeof(ACPI_RESOURCE_IRQ)); |
1889 | irq = (ACPI_RESOURCE_IRQ *)&resn->Data; |
1890 | irq->Interrupts[0] = |
1891 | ((ACPI_RESOURCE_IRQ *)&resp->Data)-> |
1892 | Interrupts[irq->InterruptCount-1]; |
1893 | irq->InterruptCount = 1; |
1894 | resn->Length = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ); |
1895 | break; |
1896 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
1897 | memcpy(&resn->Data, &resp->Data, |
1898 | sizeof(ACPI_RESOURCE_EXTENDED_IRQ)); |
1899 | #if 0 |
1900 | xirq = (ACPI_RESOURCE_EXTENDED_IRQ *)&resn->Data; |
1901 | /* |
1902 | * XXX: Not duplicating the interrupt logic above |
1903 | * because its not clear what it accomplishes. |
1904 | */ |
1905 | xirq->Interrupts[0] = |
1906 | ((ACPI_RESOURCE_EXT_IRQ *)&resp->Data)-> |
1907 | Interrupts[irq->NumberOfInterrupts-1]; |
1908 | xirq->NumberOfInterrupts = 1; |
1909 | #endif |
1910 | resn->Length = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ); |
1911 | break; |
1912 | case ACPI_RESOURCE_TYPE_IO: |
1913 | memcpy(&resn->Data, &resp->Data, |
1914 | sizeof(ACPI_RESOURCE_IO)); |
1915 | resn->Length = resp->Length; |
1916 | break; |
1917 | default: |
1918 | aprint_error_dev(acpi_softc->sc_dev, |
1919 | "%s: invalid type %u\n" , __func__, resc->Type); |
1920 | rv = AE_BAD_DATA; |
1921 | goto out2; |
1922 | } |
1923 | resc = ACPI_NEXT_RESOURCE(resc); |
1924 | resn = ACPI_NEXT_RESOURCE(resn); |
1925 | resp = ACPI_NEXT_RESOURCE(resp); |
1926 | delta = (uint8_t *)resn - (uint8_t *)bufn.Pointer; |
1927 | if (delta >= |
1928 | bufn.Length-ACPI_RS_SIZE(ACPI_RESOURCE_DATA)) { |
1929 | bufn.Length *= 2; |
1930 | bufn.Pointer = realloc(bufn.Pointer, bufn.Length, |
1931 | M_ACPI, M_WAITOK); |
1932 | resn = (ACPI_RESOURCE *)((uint8_t *)bufn.Pointer + |
1933 | delta); |
1934 | } |
1935 | } |
1936 | |
1937 | if (resc->Type != ACPI_RESOURCE_TYPE_END_TAG) { |
1938 | aprint_error_dev(acpi_softc->sc_dev, |
1939 | "%s: resc not exhausted\n" , __func__); |
1940 | rv = AE_BAD_DATA; |
1941 | goto out3; |
1942 | } |
1943 | |
1944 | resn->Type = ACPI_RESOURCE_TYPE_END_TAG; |
1945 | rv = AcpiSetCurrentResources(handle, &bufn); |
1946 | |
1947 | if (ACPI_FAILURE(rv)) |
1948 | aprint_error_dev(acpi_softc->sc_dev, "%s: failed to set " |
1949 | "resources: %s\n" , __func__, AcpiFormatException(rv)); |
1950 | |
1951 | out3: |
1952 | free(bufn.Pointer, M_ACPI); |
1953 | out2: |
1954 | ACPI_FREE(bufc.Pointer); |
1955 | out1: |
1956 | ACPI_FREE(bufp.Pointer); |
1957 | out: |
1958 | return rv; |
1959 | } |
1960 | |
1961 | #endif /* ACPI_ACTIVATE_DEV */ |
1962 | |