| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: acpi_ec.c,v 1.55 2009/05/12 09:29:46 cegger Exp $ */ | | 1 | /* $NetBSD: acpi_ec.c,v 1.56 2009/07/06 00:54:00 alc Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>. | | 4 | * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * | | 10 | * |
11 | * 1. Redistributions of source code must retain the above copyright | | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in | | 14 | * notice, this list of conditions and the following disclaimer in |
| @@ -49,27 +49,27 @@ | | | @@ -49,27 +49,27 @@ |
49 | * working and the handlers just busy loop. | | 49 | * working and the handlers just busy loop. |
50 | * | | 50 | * |
51 | * A callout is scheduled to compensate for missing interrupts on some | | 51 | * A callout is scheduled to compensate for missing interrupts on some |
52 | * hardware. If the EC doesn't process a request for 5s, it is most likely | | 52 | * hardware. If the EC doesn't process a request for 5s, it is most likely |
53 | * in a wedged state. No method to reset the EC is currently known. | | 53 | * in a wedged state. No method to reset the EC is currently known. |
54 | * | | 54 | * |
55 | * Special care has to be taken to not poll the EC in a busy loop without | | 55 | * Special care has to be taken to not poll the EC in a busy loop without |
56 | * delay. This can prevent processing of Power Button events. At least some | | 56 | * delay. This can prevent processing of Power Button events. At least some |
57 | * Lenovo Thinkpads seem to be implement the Power Button Override in the EC | | 57 | * Lenovo Thinkpads seem to be implement the Power Button Override in the EC |
58 | * and the only option to recover on those models is to cut off all power. | | 58 | * and the only option to recover on those models is to cut off all power. |
59 | */ | | 59 | */ |
60 | | | 60 | |
61 | #include <sys/cdefs.h> | | 61 | #include <sys/cdefs.h> |
62 | __KERNEL_RCSID(0, "$NetBSD: acpi_ec.c,v 1.55 2009/05/12 09:29:46 cegger Exp $"); | | 62 | __KERNEL_RCSID(0, "$NetBSD: acpi_ec.c,v 1.56 2009/07/06 00:54:00 alc Exp $"); |
63 | | | 63 | |
64 | #include <sys/param.h> | | 64 | #include <sys/param.h> |
65 | #include <sys/systm.h> | | 65 | #include <sys/systm.h> |
66 | #include <sys/condvar.h> | | 66 | #include <sys/condvar.h> |
67 | #include <sys/device.h> | | 67 | #include <sys/device.h> |
68 | #include <sys/kernel.h> | | 68 | #include <sys/kernel.h> |
69 | #include <sys/kthread.h> | | 69 | #include <sys/kthread.h> |
70 | #include <sys/mutex.h> | | 70 | #include <sys/mutex.h> |
71 | | | 71 | |
72 | #include <sys/bus.h> | | 72 | #include <sys/bus.h> |
73 | | | 73 | |
74 | #include <dev/acpi/acpivar.h> | | 74 | #include <dev/acpi/acpivar.h> |
75 | #include <dev/acpi/acpi_ecvar.h> | | 75 | #include <dev/acpi/acpi_ecvar.h> |
| @@ -138,28 +138,29 @@ struct acpiec_softc { | | | @@ -138,28 +138,29 @@ struct acpiec_softc { |
138 | | | 138 | |
139 | uint8_t sc_cur_addr, sc_cur_val; | | 139 | uint8_t sc_cur_addr, sc_cur_val; |
140 | }; | | 140 | }; |
141 | | | 141 | |
142 | static int acpiecdt_match(device_t, cfdata_t, void *); | | 142 | static int acpiecdt_match(device_t, cfdata_t, void *); |
143 | static void acpiecdt_attach(device_t, device_t, void *); | | 143 | static void acpiecdt_attach(device_t, device_t, void *); |
144 | | | 144 | |
145 | static int acpiec_match(device_t, cfdata_t, void *); | | 145 | static int acpiec_match(device_t, cfdata_t, void *); |
146 | static void acpiec_attach(device_t, device_t, void *); | | 146 | static void acpiec_attach(device_t, device_t, void *); |
147 | | | 147 | |
148 | static void acpiec_common_attach(device_t, device_t, ACPI_HANDLE, | | 148 | static void acpiec_common_attach(device_t, device_t, ACPI_HANDLE, |
149 | bus_addr_t, bus_addr_t, ACPI_HANDLE, uint8_t); | | 149 | bus_addr_t, bus_addr_t, ACPI_HANDLE, uint8_t); |
150 | | | 150 | |
151 | static bool acpiec_resume(device_t PMF_FN_PROTO); | | | |
152 | static bool acpiec_suspend(device_t PMF_FN_PROTO); | | 151 | static bool acpiec_suspend(device_t PMF_FN_PROTO); |
| | | 152 | static bool acpiec_resume(device_t PMF_FN_PROTO); |
| | | 153 | static bool acpiec_shutdown(device_t, int); |
153 | | | 154 | |
154 | static bool acpiec_parse_gpe_package(device_t, ACPI_HANDLE, | | 155 | static bool acpiec_parse_gpe_package(device_t, ACPI_HANDLE, |
155 | ACPI_HANDLE *, uint8_t *); | | 156 | ACPI_HANDLE *, uint8_t *); |
156 | | | 157 | |
157 | static void acpiec_callout(void *); | | 158 | static void acpiec_callout(void *); |
158 | static void acpiec_gpe_query(void *); | | 159 | static void acpiec_gpe_query(void *); |
159 | static UINT32 acpiec_gpe_handler(void *); | | 160 | static UINT32 acpiec_gpe_handler(void *); |
160 | static ACPI_STATUS acpiec_space_setup(ACPI_HANDLE, UINT32, void *, void **); | | 161 | static ACPI_STATUS acpiec_space_setup(ACPI_HANDLE, UINT32, void *, void **); |
161 | static ACPI_STATUS acpiec_space_handler(UINT32, ACPI_PHYSICAL_ADDRESS, | | 162 | static ACPI_STATUS acpiec_space_handler(UINT32, ACPI_PHYSICAL_ADDRESS, |
162 | UINT32, ACPI_INTEGER *, void *, void *); | | 163 | UINT32, ACPI_INTEGER *, void *, void *); |
163 | | | 164 | |
164 | static void acpiec_gpe_state_machine(device_t); | | 165 | static void acpiec_gpe_state_machine(device_t); |
165 | | | 166 | |
| @@ -367,27 +368,28 @@ acpiec_common_attach(device_t parent, de | | | @@ -367,27 +368,28 @@ acpiec_common_attach(device_t parent, de |
367 | aprint_error_dev(self, "unable to enable GPE: %s\n", | | 368 | aprint_error_dev(self, "unable to enable GPE: %s\n", |
368 | AcpiFormatException(rv)); | | 369 | AcpiFormatException(rv)); |
369 | goto post_csr_map; | | 370 | goto post_csr_map; |
370 | } | | 371 | } |
371 | | | 372 | |
372 | if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, acpiec_gpe_query, | | 373 | if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, acpiec_gpe_query, |
373 | self, NULL, "acpiec sci thread")) { | | 374 | self, NULL, "acpiec sci thread")) { |
374 | aprint_error_dev(self, "unable to create query kthread\n"); | | 375 | aprint_error_dev(self, "unable to create query kthread\n"); |
375 | goto post_csr_map; | | 376 | goto post_csr_map; |
376 | } | | 377 | } |
377 | | | 378 | |
378 | ec_singleton = self; | | 379 | ec_singleton = self; |
379 | | | 380 | |
380 | if (!pmf_device_register(self, acpiec_suspend, acpiec_resume)) | | 381 | if (!pmf_device_register1(self, acpiec_suspend, acpiec_resume, |
| | | 382 | acpiec_shutdown)) |
381 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 383 | aprint_error_dev(self, "couldn't establish power handler\n"); |
382 | | | 384 | |
383 | return; | | 385 | return; |
384 | | | 386 | |
385 | post_csr_map: | | 387 | post_csr_map: |
386 | (void)AcpiRemoveGpeHandler(sc->sc_gpeh, sc->sc_gpebit, | | 388 | (void)AcpiRemoveGpeHandler(sc->sc_gpeh, sc->sc_gpebit, |
387 | acpiec_gpe_handler); | | 389 | acpiec_gpe_handler); |
388 | (void)AcpiRemoveAddressSpaceHandler(sc->sc_ech, | | 390 | (void)AcpiRemoveAddressSpaceHandler(sc->sc_ech, |
389 | ACPI_ADR_SPACE_EC, acpiec_space_handler); | | 391 | ACPI_ADR_SPACE_EC, acpiec_space_handler); |
390 | bus_space_unmap(sc->sc_csr_st, sc->sc_csr_sh, 1); | | 392 | bus_space_unmap(sc->sc_csr_st, sc->sc_csr_sh, 1); |
391 | post_data_map: | | 393 | post_data_map: |
392 | bus_space_unmap(sc->sc_data_st, sc->sc_data_sh, 1); | | 394 | bus_space_unmap(sc->sc_data_st, sc->sc_data_sh, 1); |
393 | } | | 395 | } |
| @@ -399,26 +401,34 @@ acpiec_suspend(device_t dv PMF_FN_ARGS) | | | @@ -399,26 +401,34 @@ acpiec_suspend(device_t dv PMF_FN_ARGS) |
399 | | | 401 | |
400 | return true; | | 402 | return true; |
401 | } | | 403 | } |
402 | | | 404 | |
403 | static bool | | 405 | static bool |
404 | acpiec_resume(device_t dv PMF_FN_ARGS) | | 406 | acpiec_resume(device_t dv PMF_FN_ARGS) |
405 | { | | 407 | { |
406 | acpiec_cold = false; | | 408 | acpiec_cold = false; |
407 | | | 409 | |
408 | return true; | | 410 | return true; |
409 | } | | 411 | } |
410 | | | 412 | |
411 | static bool | | 413 | static bool |
| | | 414 | acpiec_shutdown(device_t dv, int how) |
| | | 415 | { |
| | | 416 | |
| | | 417 | acpiec_cold = true; |
| | | 418 | return true; |
| | | 419 | } |
| | | 420 | |
| | | 421 | static bool |
412 | acpiec_parse_gpe_package(device_t self, ACPI_HANDLE ec_handle, | | 422 | acpiec_parse_gpe_package(device_t self, ACPI_HANDLE ec_handle, |
413 | ACPI_HANDLE *gpe_handle, uint8_t *gpebit) | | 423 | ACPI_HANDLE *gpe_handle, uint8_t *gpebit) |
414 | { | | 424 | { |
415 | ACPI_BUFFER buf; | | 425 | ACPI_BUFFER buf; |
416 | ACPI_OBJECT *p, *c; | | 426 | ACPI_OBJECT *p, *c; |
417 | ACPI_STATUS rv; | | 427 | ACPI_STATUS rv; |
418 | | | 428 | |
419 | rv = acpi_eval_struct(ec_handle, "_GPE", &buf); | | 429 | rv = acpi_eval_struct(ec_handle, "_GPE", &buf); |
420 | if (rv != AE_OK) { | | 430 | if (rv != AE_OK) { |
421 | aprint_error_dev(self, "unable to evaluate _GPE: %s\n", | | 431 | aprint_error_dev(self, "unable to evaluate _GPE: %s\n", |
422 | AcpiFormatException(rv)); | | 432 | AcpiFormatException(rv)); |
423 | return false; | | 433 | return false; |
424 | } | | 434 | } |