| @@ -1,877 +1,877 @@ | | | @@ -1,877 +1,877 @@ |
1 | /* $NetBSD: acpi_ec.c,v 1.67 2010/06/06 18:56:10 jruoho Exp $ */ | | 1 | /* $NetBSD: acpi_ec.c,v 1.68 2011/01/07 14:08:29 cegger 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 |
15 | * the documentation and/or other materials provided with the | | 15 | * the documentation and/or other materials provided with the |
16 | * distribution. | | 16 | * distribution. |
17 | * | | 17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | | 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | | 19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | | 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
21 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | | 21 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
22 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | | 22 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
23 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | | 23 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, |
24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | | 24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
26 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 26 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | | 27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
28 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 28 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. | | 29 | * SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * The ACPI Embedded Controller (EC) driver serves two different purposes: | | 33 | * The ACPI Embedded Controller (EC) driver serves two different purposes: |
34 | * - read and write access from ASL, e.g. to read battery state | | 34 | * - read and write access from ASL, e.g. to read battery state |
35 | * - notification of ASL of System Control Interrupts. | | 35 | * - notification of ASL of System Control Interrupts. |
36 | * | | 36 | * |
37 | * Access to the EC is serialised by sc_access_mtx and optionally the | | 37 | * Access to the EC is serialised by sc_access_mtx and optionally the |
38 | * ACPI global mutex. Both locks are held until the request is fulfilled. | | 38 | * ACPI global mutex. Both locks are held until the request is fulfilled. |
39 | * All access to the softc has to hold sc_mtx to serialise against the GPE | | 39 | * All access to the softc has to hold sc_mtx to serialise against the GPE |
40 | * handler and the callout. sc_mtx is also used for wakeup conditions. | | 40 | * handler and the callout. sc_mtx is also used for wakeup conditions. |
41 | * | | 41 | * |
42 | * SCIs are processed in a kernel thread. Handling gets a bit complicated | | 42 | * SCIs are processed in a kernel thread. Handling gets a bit complicated |
43 | * by the lock order (sc_mtx must be acquired after sc_access_mtx and the | | 43 | * by the lock order (sc_mtx must be acquired after sc_access_mtx and the |
44 | * ACPI global mutex). | | 44 | * ACPI global mutex). |
45 | * | | 45 | * |
46 | * Read and write requests spin around for a short time as many requests | | 46 | * Read and write requests spin around for a short time as many requests |
47 | * can be handled instantly by the EC. During normal processing interrupt | | 47 | * can be handled instantly by the EC. During normal processing interrupt |
48 | * mode is used exclusively. At boot and resume time interrupts are not | | 48 | * mode is used exclusively. At boot and resume time interrupts are not |
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.67 2010/06/06 18:56:10 jruoho Exp $"); | | 62 | __KERNEL_RCSID(0, "$NetBSD: acpi_ec.c,v 1.68 2011/01/07 14:08:29 cegger Exp $"); |
63 | | | 63 | |
64 | #include <sys/param.h> | | 64 | #include <sys/param.h> |
65 | #include <sys/callout.h> | | 65 | #include <sys/callout.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 | #include <sys/systm.h> | | 71 | #include <sys/systm.h> |
72 | | | 72 | |
73 | #include <dev/acpi/acpireg.h> | | 73 | #include <dev/acpi/acpireg.h> |
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> |
76 | | | 76 | |
77 | #define _COMPONENT ACPI_EC_COMPONENT | | 77 | #define _COMPONENT ACPI_EC_COMPONENT |
78 | ACPI_MODULE_NAME ("acpi_ec") | | 78 | ACPI_MODULE_NAME ("acpi_ec") |
79 | | | 79 | |
80 | /* Maximum time to wait for global ACPI lock in ms */ | | 80 | /* Maximum time to wait for global ACPI lock in ms */ |
81 | #define EC_LOCK_TIMEOUT 5 | | 81 | #define EC_LOCK_TIMEOUT 5 |
82 | | | 82 | |
83 | /* Maximum time to poll for completion of a command in ms */ | | 83 | /* Maximum time to poll for completion of a command in ms */ |
84 | #define EC_POLL_TIMEOUT 5 | | 84 | #define EC_POLL_TIMEOUT 5 |
85 | | | 85 | |
86 | /* Maximum time to give a single EC command in s */ | | 86 | /* Maximum time to give a single EC command in s */ |
87 | #define EC_CMD_TIMEOUT 10 | | 87 | #define EC_CMD_TIMEOUT 10 |
88 | | | 88 | |
89 | /* From ACPI 3.0b, chapter 12.3 */ | | 89 | /* From ACPI 3.0b, chapter 12.3 */ |
90 | #define EC_COMMAND_READ 0x80 | | 90 | #define EC_COMMAND_READ 0x80 |
91 | #define EC_COMMAND_WRITE 0x81 | | 91 | #define EC_COMMAND_WRITE 0x81 |
92 | #define EC_COMMAND_BURST_EN 0x82 | | 92 | #define EC_COMMAND_BURST_EN 0x82 |
93 | #define EC_COMMAND_BURST_DIS 0x83 | | 93 | #define EC_COMMAND_BURST_DIS 0x83 |
94 | #define EC_COMMAND_QUERY 0x84 | | 94 | #define EC_COMMAND_QUERY 0x84 |
95 | | | 95 | |
96 | /* From ACPI 3.0b, chapter 12.2.1 */ | | 96 | /* From ACPI 3.0b, chapter 12.2.1 */ |
97 | #define EC_STATUS_OBF 0x01 | | 97 | #define EC_STATUS_OBF 0x01 |
98 | #define EC_STATUS_IBF 0x02 | | 98 | #define EC_STATUS_IBF 0x02 |
99 | #define EC_STATUS_CMD 0x08 | | 99 | #define EC_STATUS_CMD 0x08 |
100 | #define EC_STATUS_BURST 0x10 | | 100 | #define EC_STATUS_BURST 0x10 |
101 | #define EC_STATUS_SCI 0x20 | | 101 | #define EC_STATUS_SCI 0x20 |
102 | #define EC_STATUS_SMI 0x40 | | 102 | #define EC_STATUS_SMI 0x40 |
103 | | | 103 | |
104 | static const char *ec_hid[] = { | | 104 | static const char *ec_hid[] = { |
105 | "PNP0C09", | | 105 | "PNP0C09", |
106 | NULL, | | 106 | NULL, |
107 | }; | | 107 | }; |
108 | | | 108 | |
109 | enum ec_state_t { | | 109 | enum ec_state_t { |
110 | EC_STATE_QUERY, | | 110 | EC_STATE_QUERY, |
111 | EC_STATE_QUERY_VAL, | | 111 | EC_STATE_QUERY_VAL, |
112 | EC_STATE_READ, | | 112 | EC_STATE_READ, |
113 | EC_STATE_READ_ADDR, | | 113 | EC_STATE_READ_ADDR, |
114 | EC_STATE_READ_VAL, | | 114 | EC_STATE_READ_VAL, |
115 | EC_STATE_WRITE, | | 115 | EC_STATE_WRITE, |
116 | EC_STATE_WRITE_ADDR, | | 116 | EC_STATE_WRITE_ADDR, |
117 | EC_STATE_WRITE_VAL, | | 117 | EC_STATE_WRITE_VAL, |
118 | EC_STATE_FREE | | 118 | EC_STATE_FREE |
119 | }; | | 119 | }; |
120 | | | 120 | |
121 | struct acpiec_softc { | | 121 | struct acpiec_softc { |
122 | ACPI_HANDLE sc_ech; | | 122 | ACPI_HANDLE sc_ech; |
123 | | | 123 | |
124 | ACPI_HANDLE sc_gpeh; | | 124 | ACPI_HANDLE sc_gpeh; |
125 | uint8_t sc_gpebit; | | 125 | uint8_t sc_gpebit; |
126 | | | 126 | |
127 | bus_space_tag_t sc_data_st; | | 127 | bus_space_tag_t sc_data_st; |
128 | bus_space_handle_t sc_data_sh; | | 128 | bus_space_handle_t sc_data_sh; |
129 | | | 129 | |
130 | bus_space_tag_t sc_csr_st; | | 130 | bus_space_tag_t sc_csr_st; |
131 | bus_space_handle_t sc_csr_sh; | | 131 | bus_space_handle_t sc_csr_sh; |
132 | | | 132 | |
133 | bool sc_need_global_lock; | | 133 | bool sc_need_global_lock; |
134 | uint32_t sc_global_lock; | | 134 | uint32_t sc_global_lock; |
135 | | | 135 | |
136 | kmutex_t sc_mtx, sc_access_mtx; | | 136 | kmutex_t sc_mtx, sc_access_mtx; |
137 | kcondvar_t sc_cv, sc_cv_sci; | | 137 | kcondvar_t sc_cv, sc_cv_sci; |
138 | enum ec_state_t sc_state; | | 138 | enum ec_state_t sc_state; |
139 | bool sc_got_sci; | | 139 | bool sc_got_sci; |
140 | callout_t sc_pseudo_intr; | | 140 | callout_t sc_pseudo_intr; |
141 | | | 141 | |
142 | uint8_t sc_cur_addr, sc_cur_val; | | 142 | uint8_t sc_cur_addr, sc_cur_val; |
143 | }; | | 143 | }; |
144 | | | 144 | |
145 | static int acpiecdt_match(device_t, cfdata_t, void *); | | 145 | static int acpiecdt_match(device_t, cfdata_t, void *); |
146 | static void acpiecdt_attach(device_t, device_t, void *); | | 146 | static void acpiecdt_attach(device_t, device_t, void *); |
147 | | | 147 | |
148 | static int acpiec_match(device_t, cfdata_t, void *); | | 148 | static int acpiec_match(device_t, cfdata_t, void *); |
149 | static void acpiec_attach(device_t, device_t, void *); | | 149 | static void acpiec_attach(device_t, device_t, void *); |
150 | | | 150 | |
151 | static void acpiec_common_attach(device_t, device_t, ACPI_HANDLE, | | 151 | static void acpiec_common_attach(device_t, device_t, ACPI_HANDLE, |
152 | bus_space_tag_t, bus_addr_t, bus_space_tag_t, bus_addr_t, | | 152 | bus_space_tag_t, bus_addr_t, bus_space_tag_t, bus_addr_t, |
153 | ACPI_HANDLE, uint8_t); | | 153 | ACPI_HANDLE, uint8_t); |
154 | | | 154 | |
155 | static bool acpiec_suspend(device_t, const pmf_qual_t *); | | 155 | static bool acpiec_suspend(device_t, const pmf_qual_t *); |
156 | static bool acpiec_resume(device_t, const pmf_qual_t *); | | 156 | static bool acpiec_resume(device_t, const pmf_qual_t *); |
157 | static bool acpiec_shutdown(device_t, int); | | 157 | static bool acpiec_shutdown(device_t, int); |
158 | | | 158 | |
159 | static bool acpiec_parse_gpe_package(device_t, ACPI_HANDLE, | | 159 | static bool acpiec_parse_gpe_package(device_t, ACPI_HANDLE, |
160 | ACPI_HANDLE *, uint8_t *); | | 160 | ACPI_HANDLE *, uint8_t *); |
161 | | | 161 | |
162 | static void acpiec_callout(void *); | | 162 | static void acpiec_callout(void *); |
163 | static void acpiec_gpe_query(void *); | | 163 | static void acpiec_gpe_query(void *); |
164 | static uint32_t acpiec_gpe_handler(void *); | | 164 | static uint32_t acpiec_gpe_handler(void *); |
165 | static ACPI_STATUS acpiec_space_setup(ACPI_HANDLE, uint32_t, void *, void **); | | 165 | static ACPI_STATUS acpiec_space_setup(ACPI_HANDLE, uint32_t, void *, void **); |
166 | static ACPI_STATUS acpiec_space_handler(uint32_t, ACPI_PHYSICAL_ADDRESS, | | 166 | static ACPI_STATUS acpiec_space_handler(uint32_t, ACPI_PHYSICAL_ADDRESS, |
167 | uint32_t, ACPI_INTEGER *, void *, void *); | | 167 | uint32_t, ACPI_INTEGER *, void *, void *); |
168 | | | 168 | |
169 | static void acpiec_gpe_state_machine(device_t); | | 169 | static void acpiec_gpe_state_machine(device_t); |
170 | | | 170 | |
171 | CFATTACH_DECL_NEW(acpiec, sizeof(struct acpiec_softc), | | 171 | CFATTACH_DECL_NEW(acpiec, sizeof(struct acpiec_softc), |
172 | acpiec_match, acpiec_attach, NULL, NULL); | | 172 | acpiec_match, acpiec_attach, NULL, NULL); |
173 | | | 173 | |
174 | CFATTACH_DECL_NEW(acpiecdt, sizeof(struct acpiec_softc), | | 174 | CFATTACH_DECL_NEW(acpiecdt, sizeof(struct acpiec_softc), |
175 | acpiecdt_match, acpiecdt_attach, NULL, NULL); | | 175 | acpiecdt_match, acpiecdt_attach, NULL, NULL); |
176 | | | 176 | |
177 | static device_t ec_singleton = NULL; | | 177 | static device_t ec_singleton = NULL; |
178 | static bool acpiec_cold = false; | | 178 | static bool acpiec_cold = false; |
179 | | | 179 | |
180 | static bool | | 180 | static bool |
181 | acpiecdt_find(device_t parent, ACPI_HANDLE *ec_handle, | | 181 | acpiecdt_find(device_t parent, ACPI_HANDLE *ec_handle, |
182 | bus_addr_t *cmd_reg, bus_addr_t *data_reg, uint8_t *gpebit) | | 182 | bus_addr_t *cmd_reg, bus_addr_t *data_reg, uint8_t *gpebit) |
183 | { | | 183 | { |
184 | ACPI_TABLE_ECDT *ecdt; | | 184 | ACPI_TABLE_ECDT *ecdt; |
185 | ACPI_STATUS rv; | | 185 | ACPI_STATUS rv; |
186 | | | 186 | |
187 | rv = AcpiGetTable(ACPI_SIG_ECDT, 1, (ACPI_TABLE_HEADER **)&ecdt); | | 187 | rv = AcpiGetTable(ACPI_SIG_ECDT, 1, (ACPI_TABLE_HEADER **)&ecdt); |
188 | if (ACPI_FAILURE(rv)) | | 188 | if (ACPI_FAILURE(rv)) |
189 | return false; | | 189 | return false; |
190 | | | 190 | |
191 | if (ecdt->Control.BitWidth != 8 || ecdt->Data.BitWidth != 8) { | | 191 | if (ecdt->Control.BitWidth != 8 || ecdt->Data.BitWidth != 8) { |
192 | aprint_error_dev(parent, | | 192 | aprint_error_dev(parent, |
193 | "ECDT register width invalid (%u/%u)\n", | | 193 | "ECDT register width invalid (%u/%u)\n", |
194 | ecdt->Control.BitWidth, ecdt->Data.BitWidth); | | 194 | ecdt->Control.BitWidth, ecdt->Data.BitWidth); |
195 | return false; | | 195 | return false; |
196 | } | | 196 | } |
197 | | | 197 | |
198 | rv = AcpiGetHandle(ACPI_ROOT_OBJECT, ecdt->Id, ec_handle); | | 198 | rv = AcpiGetHandle(ACPI_ROOT_OBJECT, ecdt->Id, ec_handle); |
199 | if (ACPI_FAILURE(rv)) { | | 199 | if (ACPI_FAILURE(rv)) { |
200 | aprint_error_dev(parent, | | 200 | aprint_error_dev(parent, |
201 | "failed to look up EC object %s: %s\n", | | 201 | "failed to look up EC object %s: %s\n", |
202 | ecdt->Id, AcpiFormatException(rv)); | | 202 | ecdt->Id, AcpiFormatException(rv)); |
203 | return false; | | 203 | return false; |
204 | } | | 204 | } |
205 | | | 205 | |
206 | *cmd_reg = ecdt->Control.Address; | | 206 | *cmd_reg = ecdt->Control.Address; |
207 | *data_reg = ecdt->Data.Address; | | 207 | *data_reg = ecdt->Data.Address; |
208 | *gpebit = ecdt->Gpe; | | 208 | *gpebit = ecdt->Gpe; |
209 | | | 209 | |
210 | return true; | | 210 | return true; |
211 | } | | 211 | } |
212 | | | 212 | |
213 | static int | | 213 | static int |
214 | acpiecdt_match(device_t parent, cfdata_t match, void *aux) | | 214 | acpiecdt_match(device_t parent, cfdata_t match, void *aux) |
215 | { | | 215 | { |
216 | ACPI_HANDLE ec_handle; | | 216 | ACPI_HANDLE ec_handle; |
217 | bus_addr_t cmd_reg, data_reg; | | 217 | bus_addr_t cmd_reg, data_reg; |
218 | uint8_t gpebit; | | 218 | uint8_t gpebit; |
219 | | | 219 | |
220 | if (acpiecdt_find(parent, &ec_handle, &cmd_reg, &data_reg, &gpebit)) | | 220 | if (acpiecdt_find(parent, &ec_handle, &cmd_reg, &data_reg, &gpebit)) |
221 | return 1; | | 221 | return 1; |
222 | else | | 222 | else |
223 | return 0; | | 223 | return 0; |
224 | } | | 224 | } |
225 | | | 225 | |
226 | static void | | 226 | static void |
227 | acpiecdt_attach(device_t parent, device_t self, void *aux) | | 227 | acpiecdt_attach(device_t parent, device_t self, void *aux) |
228 | { | | 228 | { |
229 | struct acpibus_attach_args *aa = aux; | | 229 | struct acpibus_attach_args *aa = aux; |
230 | ACPI_HANDLE ec_handle; | | 230 | ACPI_HANDLE ec_handle; |
231 | bus_addr_t cmd_reg, data_reg; | | 231 | bus_addr_t cmd_reg, data_reg; |
232 | uint8_t gpebit; | | 232 | uint8_t gpebit; |
233 | | | 233 | |
234 | if (!acpiecdt_find(parent, &ec_handle, &cmd_reg, &data_reg, &gpebit)) | | 234 | if (!acpiecdt_find(parent, &ec_handle, &cmd_reg, &data_reg, &gpebit)) |
235 | panic("ECDT disappeared"); | | 235 | panic("ECDT disappeared"); |
236 | | | 236 | |
237 | aprint_naive("\n"); | | 237 | aprint_naive("\n"); |
238 | aprint_normal(": ACPI Embedded Controller via ECDT\n"); | | 238 | aprint_normal(": ACPI Embedded Controller via ECDT\n"); |
239 | | | 239 | |
240 | acpiec_common_attach(parent, self, ec_handle, aa->aa_iot, cmd_reg, | | 240 | acpiec_common_attach(parent, self, ec_handle, aa->aa_iot, cmd_reg, |
241 | aa->aa_iot, data_reg, NULL, gpebit); | | 241 | aa->aa_iot, data_reg, NULL, gpebit); |
242 | } | | 242 | } |
243 | | | 243 | |
244 | static int | | 244 | static int |
245 | acpiec_match(device_t parent, cfdata_t match, void *aux) | | 245 | acpiec_match(device_t parent, cfdata_t match, void *aux) |
246 | { | | 246 | { |
247 | struct acpi_attach_args *aa = aux; | | 247 | struct acpi_attach_args *aa = aux; |
248 | | | 248 | |
249 | if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) | | 249 | if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) |
250 | return 0; | | 250 | return 0; |
251 | | | 251 | |
252 | return acpi_match_hid(aa->aa_node->ad_devinfo, ec_hid); | | 252 | return acpi_match_hid(aa->aa_node->ad_devinfo, ec_hid); |
253 | } | | 253 | } |
254 | | | 254 | |
255 | static void | | 255 | static void |
256 | acpiec_attach(device_t parent, device_t self, void *aux) | | 256 | acpiec_attach(device_t parent, device_t self, void *aux) |
257 | { | | 257 | { |
258 | struct acpi_attach_args *aa = aux; | | 258 | struct acpi_attach_args *aa = aux; |
259 | struct acpi_resources ec_res; | | 259 | struct acpi_resources ec_res; |
260 | struct acpi_io *io0, *io1; | | 260 | struct acpi_io *io0, *io1; |
261 | ACPI_HANDLE gpe_handle; | | 261 | ACPI_HANDLE gpe_handle; |
262 | uint8_t gpebit; | | 262 | uint8_t gpebit; |
263 | ACPI_STATUS rv; | | 263 | ACPI_STATUS rv; |
264 | | | 264 | |
265 | if (ec_singleton != NULL) { | | 265 | if (ec_singleton != NULL) { |
266 | aprint_naive(": using %s\n", device_xname(ec_singleton)); | | 266 | aprint_naive(": using %s\n", device_xname(ec_singleton)); |
267 | aprint_normal(": using %s\n", device_xname(ec_singleton)); | | 267 | aprint_normal(": using %s\n", device_xname(ec_singleton)); |
268 | if (!pmf_device_register(self, NULL, NULL)) | | 268 | if (!pmf_device_register(self, NULL, NULL)) |
269 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 269 | aprint_error_dev(self, "couldn't establish power handler\n"); |
270 | return; | | 270 | return; |
271 | } | | 271 | } |
272 | | | 272 | |
273 | if (!acpiec_parse_gpe_package(self, aa->aa_node->ad_handle, | | 273 | if (!acpiec_parse_gpe_package(self, aa->aa_node->ad_handle, |
274 | &gpe_handle, &gpebit)) | | 274 | &gpe_handle, &gpebit)) |
275 | return; | | 275 | return; |
276 | | | 276 | |
277 | rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", | | 277 | rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", |
278 | &ec_res, &acpi_resource_parse_ops_default); | | 278 | &ec_res, &acpi_resource_parse_ops_default); |
279 | if (rv != AE_OK) { | | 279 | if (rv != AE_OK) { |
280 | aprint_error_dev(self, "resource parsing failed: %s\n", | | 280 | aprint_error_dev(self, "resource parsing failed: %s\n", |
281 | AcpiFormatException(rv)); | | 281 | AcpiFormatException(rv)); |
282 | return; | | 282 | return; |
283 | } | | 283 | } |
284 | | | 284 | |
285 | if ((io0 = acpi_res_io(&ec_res, 0)) == NULL) { | | 285 | if ((io0 = acpi_res_io(&ec_res, 0)) == NULL) { |
286 | aprint_error_dev(self, "no data register resource\n"); | | 286 | aprint_error_dev(self, "no data register resource\n"); |
287 | goto free_res; | | 287 | goto free_res; |
288 | } | | 288 | } |
289 | if ((io1 = acpi_res_io(&ec_res, 1)) == NULL) { | | 289 | if ((io1 = acpi_res_io(&ec_res, 1)) == NULL) { |
290 | aprint_error_dev(self, "no CSR register resource\n"); | | 290 | aprint_error_dev(self, "no CSR register resource\n"); |
291 | goto free_res; | | 291 | goto free_res; |
292 | } | | 292 | } |
293 | | | 293 | |
294 | acpiec_common_attach(parent, self, aa->aa_node->ad_handle, | | 294 | acpiec_common_attach(parent, self, aa->aa_node->ad_handle, |
295 | aa->aa_iot, io1->ar_base, aa->aa_iot, io0->ar_base, | | 295 | aa->aa_iot, io1->ar_base, aa->aa_iot, io0->ar_base, |
296 | gpe_handle, gpebit); | | 296 | gpe_handle, gpebit); |
297 | | | 297 | |
298 | free_res: | | 298 | free_res: |
299 | acpi_resource_cleanup(&ec_res); | | 299 | acpi_resource_cleanup(&ec_res); |
300 | } | | 300 | } |
301 | | | 301 | |
302 | static void | | 302 | static void |
303 | acpiec_common_attach(device_t parent, device_t self, | | 303 | acpiec_common_attach(device_t parent, device_t self, |
304 | ACPI_HANDLE ec_handle, bus_space_tag_t cmdt, bus_addr_t cmd_reg, | | 304 | ACPI_HANDLE ec_handle, bus_space_tag_t cmdt, bus_addr_t cmd_reg, |
305 | bus_space_tag_t datat, bus_addr_t data_reg, | | 305 | bus_space_tag_t datat, bus_addr_t data_reg, |
306 | ACPI_HANDLE gpe_handle, uint8_t gpebit) | | 306 | ACPI_HANDLE gpe_handle, uint8_t gpebit) |
307 | { | | 307 | { |
308 | struct acpiec_softc *sc = device_private(self); | | 308 | struct acpiec_softc *sc = device_private(self); |
309 | ACPI_STATUS rv; | | 309 | ACPI_STATUS rv; |
310 | ACPI_INTEGER val; | | 310 | ACPI_INTEGER val; |
311 | | | 311 | |
312 | sc->sc_csr_st = cmdt; | | 312 | sc->sc_csr_st = cmdt; |
313 | sc->sc_data_st = datat; | | 313 | sc->sc_data_st = datat; |
314 | | | 314 | |
315 | sc->sc_ech = ec_handle; | | 315 | sc->sc_ech = ec_handle; |
316 | sc->sc_gpeh = gpe_handle; | | 316 | sc->sc_gpeh = gpe_handle; |
317 | sc->sc_gpebit = gpebit; | | 317 | sc->sc_gpebit = gpebit; |
318 | | | 318 | |
319 | sc->sc_state = EC_STATE_FREE; | | 319 | sc->sc_state = EC_STATE_FREE; |
320 | mutex_init(&sc->sc_mtx, MUTEX_DRIVER, IPL_TTY); | | 320 | mutex_init(&sc->sc_mtx, MUTEX_DRIVER, IPL_TTY); |
321 | mutex_init(&sc->sc_access_mtx, MUTEX_DEFAULT, IPL_NONE); | | 321 | mutex_init(&sc->sc_access_mtx, MUTEX_DEFAULT, IPL_NONE); |
322 | cv_init(&sc->sc_cv, "eccv"); | | 322 | cv_init(&sc->sc_cv, "eccv"); |
323 | cv_init(&sc->sc_cv_sci, "ecsci"); | | 323 | cv_init(&sc->sc_cv_sci, "ecsci"); |
324 | | | 324 | |
325 | if (bus_space_map(sc->sc_data_st, data_reg, 1, 0, | | 325 | if (bus_space_map(sc->sc_data_st, data_reg, 1, 0, |
326 | &sc->sc_data_sh) != 0) { | | 326 | &sc->sc_data_sh) != 0) { |
327 | aprint_error_dev(self, "unable to map data register\n"); | | 327 | aprint_error_dev(self, "unable to map data register\n"); |
328 | return; | | 328 | return; |
329 | } | | 329 | } |
330 | | | 330 | |
331 | if (bus_space_map(sc->sc_csr_st, cmd_reg, 1, 0, &sc->sc_csr_sh) != 0) { | | 331 | if (bus_space_map(sc->sc_csr_st, cmd_reg, 1, 0, &sc->sc_csr_sh) != 0) { |
332 | aprint_error_dev(self, "unable to map CSR register\n"); | | 332 | aprint_error_dev(self, "unable to map CSR register\n"); |
333 | goto post_data_map; | | 333 | goto post_data_map; |
334 | } | | 334 | } |
335 | | | 335 | |
336 | rv = acpi_eval_integer(sc->sc_ech, "_GLK", &val); | | 336 | rv = acpi_eval_integer(sc->sc_ech, "_GLK", &val); |
337 | if (rv == AE_OK) { | | 337 | if (rv == AE_OK) { |
338 | sc->sc_need_global_lock = val != 0; | | 338 | sc->sc_need_global_lock = val != 0; |
339 | } else if (rv != AE_NOT_FOUND) { | | 339 | } else if (rv != AE_NOT_FOUND) { |
340 | aprint_error_dev(self, "unable to evaluate _GLK: %s\n", | | 340 | aprint_error_dev(self, "unable to evaluate _GLK: %s\n", |
341 | AcpiFormatException(rv)); | | 341 | AcpiFormatException(rv)); |
342 | goto post_csr_map; | | 342 | goto post_csr_map; |
343 | } else { | | 343 | } else { |
344 | sc->sc_need_global_lock = false; | | 344 | sc->sc_need_global_lock = false; |
345 | } | | 345 | } |
346 | if (sc->sc_need_global_lock) | | 346 | if (sc->sc_need_global_lock) |
347 | aprint_normal_dev(self, "using global ACPI lock\n"); | | 347 | aprint_normal_dev(self, "using global ACPI lock\n"); |
348 | | | 348 | |
349 | callout_init(&sc->sc_pseudo_intr, CALLOUT_MPSAFE); | | 349 | callout_init(&sc->sc_pseudo_intr, CALLOUT_MPSAFE); |
350 | callout_setfunc(&sc->sc_pseudo_intr, acpiec_callout, self); | | 350 | callout_setfunc(&sc->sc_pseudo_intr, acpiec_callout, self); |
351 | | | 351 | |
352 | rv = AcpiInstallAddressSpaceHandler(sc->sc_ech, ACPI_ADR_SPACE_EC, | | 352 | rv = AcpiInstallAddressSpaceHandler(sc->sc_ech, ACPI_ADR_SPACE_EC, |
353 | acpiec_space_handler, acpiec_space_setup, self); | | 353 | acpiec_space_handler, acpiec_space_setup, self); |
354 | if (rv != AE_OK) { | | 354 | if (rv != AE_OK) { |
355 | aprint_error_dev(self, | | 355 | aprint_error_dev(self, |
356 | "unable to install address space handler: %s\n", | | 356 | "unable to install address space handler: %s\n", |
357 | AcpiFormatException(rv)); | | 357 | AcpiFormatException(rv)); |
358 | goto post_csr_map; | | 358 | goto post_csr_map; |
359 | } | | 359 | } |
360 | | | 360 | |
361 | rv = AcpiInstallGpeHandler(sc->sc_gpeh, sc->sc_gpebit, | | 361 | rv = AcpiInstallGpeHandler(sc->sc_gpeh, sc->sc_gpebit, |
362 | ACPI_GPE_EDGE_TRIGGERED, acpiec_gpe_handler, self); | | 362 | ACPI_GPE_EDGE_TRIGGERED, acpiec_gpe_handler, self); |
363 | if (rv != AE_OK) { | | 363 | if (rv != AE_OK) { |
364 | aprint_error_dev(self, "unable to install GPE handler: %s\n", | | 364 | aprint_error_dev(self, "unable to install GPE handler: %s\n", |
365 | AcpiFormatException(rv)); | | 365 | AcpiFormatException(rv)); |
366 | goto post_csr_map; | | 366 | goto post_csr_map; |
367 | } | | 367 | } |
368 | | | 368 | |
369 | rv = AcpiEnableGpe(sc->sc_gpeh, sc->sc_gpebit, ACPI_GPE_TYPE_RUNTIME); | | 369 | rv = AcpiEnableGpe(sc->sc_gpeh, sc->sc_gpebit, ACPI_GPE_TYPE_RUNTIME); |
370 | if (rv != AE_OK) { | | 370 | if (rv != AE_OK) { |
371 | aprint_error_dev(self, "unable to enable GPE: %s\n", | | 371 | aprint_error_dev(self, "unable to enable GPE: %s\n", |
372 | AcpiFormatException(rv)); | | 372 | AcpiFormatException(rv)); |
373 | goto post_csr_map; | | 373 | goto post_csr_map; |
374 | } | | 374 | } |
375 | | | 375 | |
376 | if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, acpiec_gpe_query, | | 376 | if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, acpiec_gpe_query, |
377 | self, NULL, "acpiec sci thread")) { | | 377 | self, NULL, "acpiec sci thread")) { |
378 | aprint_error_dev(self, "unable to create query kthread\n"); | | 378 | aprint_error_dev(self, "unable to create query kthread\n"); |
379 | goto post_csr_map; | | 379 | goto post_csr_map; |
380 | } | | 380 | } |
381 | | | 381 | |
382 | ec_singleton = self; | | 382 | ec_singleton = self; |
383 | | | 383 | |
384 | if (!pmf_device_register1(self, acpiec_suspend, acpiec_resume, | | 384 | if (!pmf_device_register1(self, acpiec_suspend, acpiec_resume, |
385 | acpiec_shutdown)) | | 385 | acpiec_shutdown)) |
386 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 386 | aprint_error_dev(self, "couldn't establish power handler\n"); |
387 | | | 387 | |
388 | return; | | 388 | return; |
389 | | | 389 | |
390 | post_csr_map: | | 390 | post_csr_map: |
391 | (void)AcpiRemoveGpeHandler(sc->sc_gpeh, sc->sc_gpebit, | | 391 | (void)AcpiRemoveGpeHandler(sc->sc_gpeh, sc->sc_gpebit, |
392 | acpiec_gpe_handler); | | 392 | acpiec_gpe_handler); |
393 | (void)AcpiRemoveAddressSpaceHandler(sc->sc_ech, | | 393 | (void)AcpiRemoveAddressSpaceHandler(sc->sc_ech, |
394 | ACPI_ADR_SPACE_EC, acpiec_space_handler); | | 394 | ACPI_ADR_SPACE_EC, acpiec_space_handler); |
395 | bus_space_unmap(sc->sc_csr_st, sc->sc_csr_sh, 1); | | 395 | bus_space_unmap(sc->sc_csr_st, sc->sc_csr_sh, 1); |
396 | post_data_map: | | 396 | post_data_map: |
397 | bus_space_unmap(sc->sc_data_st, sc->sc_data_sh, 1); | | 397 | bus_space_unmap(sc->sc_data_st, sc->sc_data_sh, 1); |
398 | } | | 398 | } |
399 | | | 399 | |
400 | static bool | | 400 | static bool |
401 | acpiec_suspend(device_t dv, const pmf_qual_t *qual) | | 401 | acpiec_suspend(device_t dv, const pmf_qual_t *qual) |
402 | { | | 402 | { |
403 | acpiec_cold = true; | | 403 | acpiec_cold = true; |
404 | | | 404 | |
405 | return true; | | 405 | return true; |
406 | } | | 406 | } |
407 | | | 407 | |
408 | static bool | | 408 | static bool |
409 | acpiec_resume(device_t dv, const pmf_qual_t *qual) | | 409 | acpiec_resume(device_t dv, const pmf_qual_t *qual) |
410 | { | | 410 | { |
411 | acpiec_cold = false; | | 411 | acpiec_cold = false; |
412 | | | 412 | |
413 | return true; | | 413 | return true; |
414 | } | | 414 | } |
415 | | | 415 | |
416 | static bool | | 416 | static bool |
417 | acpiec_shutdown(device_t dv, int how) | | 417 | acpiec_shutdown(device_t dv, int how) |
418 | { | | 418 | { |
419 | | | 419 | |
420 | acpiec_cold = true; | | 420 | acpiec_cold = true; |
421 | return true; | | 421 | return true; |
422 | } | | 422 | } |
423 | | | 423 | |
424 | static bool | | 424 | static bool |
425 | acpiec_parse_gpe_package(device_t self, ACPI_HANDLE ec_handle, | | 425 | acpiec_parse_gpe_package(device_t self, ACPI_HANDLE ec_handle, |
426 | ACPI_HANDLE *gpe_handle, uint8_t *gpebit) | | 426 | ACPI_HANDLE *gpe_handle, uint8_t *gpebit) |
427 | { | | 427 | { |
428 | ACPI_BUFFER buf; | | 428 | ACPI_BUFFER buf; |
429 | ACPI_OBJECT *p, *c; | | 429 | ACPI_OBJECT *p, *c; |
430 | ACPI_STATUS rv; | | 430 | ACPI_STATUS rv; |
431 | | | 431 | |
432 | rv = acpi_eval_struct(ec_handle, "_GPE", &buf); | | 432 | rv = acpi_eval_struct(ec_handle, "_GPE", &buf); |
433 | if (rv != AE_OK) { | | 433 | if (rv != AE_OK) { |
434 | aprint_error_dev(self, "unable to evaluate _GPE: %s\n", | | 434 | aprint_error_dev(self, "unable to evaluate _GPE: %s\n", |
435 | AcpiFormatException(rv)); | | 435 | AcpiFormatException(rv)); |
436 | return false; | | 436 | return false; |
437 | } | | 437 | } |
438 | | | 438 | |
439 | p = buf.Pointer; | | 439 | p = buf.Pointer; |
440 | | | 440 | |
441 | if (p->Type == ACPI_TYPE_INTEGER) { | | 441 | if (p->Type == ACPI_TYPE_INTEGER) { |
442 | *gpe_handle = NULL; | | 442 | *gpe_handle = NULL; |
443 | *gpebit = p->Integer.Value; | | 443 | *gpebit = p->Integer.Value; |
444 | ACPI_FREE(p); | | 444 | ACPI_FREE(p); |
445 | return true; | | 445 | return true; |
446 | } | | 446 | } |
447 | | | 447 | |
448 | if (p->Type != ACPI_TYPE_PACKAGE) { | | 448 | if (p->Type != ACPI_TYPE_PACKAGE) { |
449 | aprint_error_dev(self, "_GPE is neither integer nor package\n"); | | 449 | aprint_error_dev(self, "_GPE is neither integer nor package\n"); |
450 | ACPI_FREE(p); | | 450 | ACPI_FREE(p); |
451 | return false; | | 451 | return false; |
452 | } | | 452 | } |
453 | | | 453 | |
454 | if (p->Package.Count != 2) { | | 454 | if (p->Package.Count != 2) { |
455 | aprint_error_dev(self, "_GPE package does not contain 2 elements\n"); | | 455 | aprint_error_dev(self, "_GPE package does not contain 2 elements\n"); |
456 | ACPI_FREE(p); | | 456 | ACPI_FREE(p); |
457 | return false; | | 457 | return false; |
458 | } | | 458 | } |
459 | | | 459 | |
460 | c = &p->Package.Elements[0]; | | 460 | c = &p->Package.Elements[0]; |
461 | rv = acpi_eval_reference_handle(c, gpe_handle); | | 461 | rv = acpi_eval_reference_handle(c, gpe_handle); |
462 | | | 462 | |
463 | if (ACPI_FAILURE(rv)) { | | 463 | if (ACPI_FAILURE(rv)) { |
464 | aprint_error_dev(self, "failed to evaluate _GPE handle\n"); | | 464 | aprint_error_dev(self, "failed to evaluate _GPE handle\n"); |
465 | ACPI_FREE(p); | | 465 | ACPI_FREE(p); |
466 | return false; | | 466 | return false; |
467 | } | | 467 | } |
468 | | | 468 | |
469 | c = &p->Package.Elements[1]; | | 469 | c = &p->Package.Elements[1]; |
470 | | | 470 | |
471 | if (c->Type != ACPI_TYPE_INTEGER) { | | 471 | if (c->Type != ACPI_TYPE_INTEGER) { |
472 | aprint_error_dev(self, | | 472 | aprint_error_dev(self, |
473 | "_GPE package needs integer as 2nd field\n"); | | 473 | "_GPE package needs integer as 2nd field\n"); |
474 | ACPI_FREE(p); | | 474 | ACPI_FREE(p); |
475 | return false; | | 475 | return false; |
476 | } | | 476 | } |
477 | *gpebit = c->Integer.Value; | | 477 | *gpebit = c->Integer.Value; |
478 | ACPI_FREE(p); | | 478 | ACPI_FREE(p); |
479 | return true; | | 479 | return true; |
480 | } | | 480 | } |
481 | | | 481 | |
482 | static uint8_t | | 482 | static uint8_t |
483 | acpiec_read_data(struct acpiec_softc *sc) | | 483 | acpiec_read_data(struct acpiec_softc *sc) |
484 | { | | 484 | { |
485 | return bus_space_read_1(sc->sc_data_st, sc->sc_data_sh, 0); | | 485 | return bus_space_read_1(sc->sc_data_st, sc->sc_data_sh, 0); |
486 | } | | 486 | } |
487 | | | 487 | |
488 | static void | | 488 | static void |
489 | acpiec_write_data(struct acpiec_softc *sc, uint8_t val) | | 489 | acpiec_write_data(struct acpiec_softc *sc, uint8_t val) |
490 | { | | 490 | { |
491 | bus_space_write_1(sc->sc_data_st, sc->sc_data_sh, 0, val); | | 491 | bus_space_write_1(sc->sc_data_st, sc->sc_data_sh, 0, val); |
492 | } | | 492 | } |
493 | | | 493 | |
494 | static uint8_t | | 494 | static uint8_t |
495 | acpiec_read_status(struct acpiec_softc *sc) | | 495 | acpiec_read_status(struct acpiec_softc *sc) |
496 | { | | 496 | { |
497 | return bus_space_read_1(sc->sc_csr_st, sc->sc_csr_sh, 0); | | 497 | return bus_space_read_1(sc->sc_csr_st, sc->sc_csr_sh, 0); |
498 | } | | 498 | } |
499 | | | 499 | |
500 | static void | | 500 | static void |
501 | acpiec_write_command(struct acpiec_softc *sc, uint8_t cmd) | | 501 | acpiec_write_command(struct acpiec_softc *sc, uint8_t cmd) |
502 | { | | 502 | { |
503 | bus_space_write_1(sc->sc_csr_st, sc->sc_csr_sh, 0, cmd); | | 503 | bus_space_write_1(sc->sc_csr_st, sc->sc_csr_sh, 0, cmd); |
504 | } | | 504 | } |
505 | | | 505 | |
506 | static ACPI_STATUS | | 506 | static ACPI_STATUS |
507 | acpiec_space_setup(ACPI_HANDLE region, uint32_t func, void *arg, | | 507 | acpiec_space_setup(ACPI_HANDLE region, uint32_t func, void *arg, |
508 | void **region_arg) | | 508 | void **region_arg) |
509 | { | | 509 | { |
510 | if (func == ACPI_REGION_DEACTIVATE) | | 510 | if (func == ACPI_REGION_DEACTIVATE) |
511 | *region_arg = NULL; | | 511 | *region_arg = NULL; |
512 | else | | 512 | else |
513 | *region_arg = arg; | | 513 | *region_arg = arg; |
514 | | | 514 | |
515 | return AE_OK; | | 515 | return AE_OK; |
516 | } | | 516 | } |
517 | | | 517 | |
518 | static void | | 518 | static void |
519 | acpiec_lock(device_t dv) | | 519 | acpiec_lock(device_t dv) |
520 | { | | 520 | { |
521 | struct acpiec_softc *sc = device_private(dv); | | 521 | struct acpiec_softc *sc = device_private(dv); |
522 | ACPI_STATUS rv; | | 522 | ACPI_STATUS rv; |
523 | | | 523 | |
524 | mutex_enter(&sc->sc_access_mtx); | | 524 | mutex_enter(&sc->sc_access_mtx); |
525 | | | 525 | |
526 | if (sc->sc_need_global_lock) { | | 526 | if (sc->sc_need_global_lock) { |
527 | rv = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT, &sc->sc_global_lock); | | 527 | rv = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT, &sc->sc_global_lock); |
528 | if (rv != AE_OK) { | | 528 | if (rv != AE_OK) { |
529 | aprint_error_dev(dv, "failed to acquire global lock: %s\n", | | 529 | aprint_error_dev(dv, "failed to acquire global lock: %s\n", |
530 | AcpiFormatException(rv)); | | 530 | AcpiFormatException(rv)); |
531 | return; | | 531 | return; |
532 | } | | 532 | } |
533 | } | | 533 | } |
534 | } | | 534 | } |
535 | | | 535 | |
536 | static void | | 536 | static void |
537 | acpiec_unlock(device_t dv) | | 537 | acpiec_unlock(device_t dv) |
538 | { | | 538 | { |
539 | struct acpiec_softc *sc = device_private(dv); | | 539 | struct acpiec_softc *sc = device_private(dv); |
540 | ACPI_STATUS rv; | | 540 | ACPI_STATUS rv; |
541 | | | 541 | |
542 | if (sc->sc_need_global_lock) { | | 542 | if (sc->sc_need_global_lock) { |
543 | rv = AcpiReleaseGlobalLock(sc->sc_global_lock); | | 543 | rv = AcpiReleaseGlobalLock(sc->sc_global_lock); |
544 | if (rv != AE_OK) { | | 544 | if (rv != AE_OK) { |
545 | aprint_error_dev(dv, "failed to release global lock: %s\n", | | 545 | aprint_error_dev(dv, "failed to release global lock: %s\n", |
546 | AcpiFormatException(rv)); | | 546 | AcpiFormatException(rv)); |
547 | } | | 547 | } |
548 | } | | 548 | } |
549 | mutex_exit(&sc->sc_access_mtx); | | 549 | mutex_exit(&sc->sc_access_mtx); |
550 | } | | 550 | } |
551 | | | 551 | |
552 | static ACPI_STATUS | | 552 | static ACPI_STATUS |
553 | acpiec_read(device_t dv, uint8_t addr, uint8_t *val) | | 553 | acpiec_read(device_t dv, uint8_t addr, uint8_t *val) |
554 | { | | 554 | { |
555 | struct acpiec_softc *sc = device_private(dv); | | 555 | struct acpiec_softc *sc = device_private(dv); |
556 | int i, timeo = 1000 * EC_CMD_TIMEOUT; | | 556 | int i, timeo = 1000 * EC_CMD_TIMEOUT; |
557 | | | 557 | |
558 | acpiec_lock(dv); | | 558 | acpiec_lock(dv); |
559 | mutex_enter(&sc->sc_mtx); | | 559 | mutex_enter(&sc->sc_mtx); |
560 | | | 560 | |
561 | sc->sc_cur_addr = addr; | | 561 | sc->sc_cur_addr = addr; |
562 | sc->sc_state = EC_STATE_READ; | | 562 | sc->sc_state = EC_STATE_READ; |
563 | | | 563 | |
564 | for (i = 0; i < EC_POLL_TIMEOUT; ++i) { | | 564 | for (i = 0; i < EC_POLL_TIMEOUT; ++i) { |
565 | acpiec_gpe_state_machine(dv); | | 565 | acpiec_gpe_state_machine(dv); |
566 | if (sc->sc_state == EC_STATE_FREE) | | 566 | if (sc->sc_state == EC_STATE_FREE) |
567 | goto done; | | 567 | goto done; |
568 | delay(1); | | 568 | delay(1); |
569 | } | | 569 | } |
570 | | | 570 | |
571 | if (cold || acpiec_cold) { | | 571 | if (cold || acpiec_cold) { |
572 | while (sc->sc_state != EC_STATE_FREE && timeo-- > 0) { | | 572 | while (sc->sc_state != EC_STATE_FREE && timeo-- > 0) { |
573 | delay(1000); | | 573 | delay(1000); |
574 | acpiec_gpe_state_machine(dv); | | 574 | acpiec_gpe_state_machine(dv); |
575 | } | | 575 | } |
576 | if (sc->sc_state != EC_STATE_FREE) { | | 576 | if (sc->sc_state != EC_STATE_FREE) { |
577 | mutex_exit(&sc->sc_mtx); | | 577 | mutex_exit(&sc->sc_mtx); |
578 | acpiec_unlock(dv); | | 578 | acpiec_unlock(dv); |
579 | aprint_error_dev(dv, "command timed out, state %d\n", | | 579 | aprint_error_dev(dv, "command timed out, state %d\n", |
580 | sc->sc_state); | | 580 | sc->sc_state); |
581 | return AE_ERROR; | | 581 | return AE_ERROR; |
582 | } | | 582 | } |
583 | } else if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, EC_CMD_TIMEOUT * hz)) { | | 583 | } else if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, EC_CMD_TIMEOUT * hz)) { |
584 | mutex_exit(&sc->sc_mtx); | | 584 | mutex_exit(&sc->sc_mtx); |
585 | acpiec_unlock(dv); | | 585 | acpiec_unlock(dv); |
586 | aprint_error_dev(dv, "command takes over %d sec...\n", EC_CMD_TIMEOUT); | | 586 | aprint_error_dev(dv, "command takes over %d sec...\n", EC_CMD_TIMEOUT); |
587 | return AE_ERROR; | | 587 | return AE_ERROR; |
588 | } | | 588 | } |
589 | | | 589 | |
590 | done: | | 590 | done: |
591 | *val = sc->sc_cur_val; | | 591 | *val = sc->sc_cur_val; |
592 | | | 592 | |
593 | mutex_exit(&sc->sc_mtx); | | 593 | mutex_exit(&sc->sc_mtx); |
594 | acpiec_unlock(dv); | | 594 | acpiec_unlock(dv); |
595 | return AE_OK; | | 595 | return AE_OK; |
596 | } | | 596 | } |
597 | | | 597 | |
598 | static ACPI_STATUS | | 598 | static ACPI_STATUS |
599 | acpiec_write(device_t dv, uint8_t addr, uint8_t val) | | 599 | acpiec_write(device_t dv, uint8_t addr, uint8_t val) |
600 | { | | 600 | { |
601 | struct acpiec_softc *sc = device_private(dv); | | 601 | struct acpiec_softc *sc = device_private(dv); |
602 | int i, timeo = 1000 * EC_CMD_TIMEOUT; | | 602 | int i, timeo = 1000 * EC_CMD_TIMEOUT; |
603 | | | 603 | |
604 | acpiec_lock(dv); | | 604 | acpiec_lock(dv); |
605 | mutex_enter(&sc->sc_mtx); | | 605 | mutex_enter(&sc->sc_mtx); |
606 | | | 606 | |
607 | sc->sc_cur_addr = addr; | | 607 | sc->sc_cur_addr = addr; |
608 | sc->sc_cur_val = val; | | 608 | sc->sc_cur_val = val; |
609 | sc->sc_state = EC_STATE_WRITE; | | 609 | sc->sc_state = EC_STATE_WRITE; |
610 | | | 610 | |
611 | for (i = 0; i < EC_POLL_TIMEOUT; ++i) { | | 611 | for (i = 0; i < EC_POLL_TIMEOUT; ++i) { |
612 | acpiec_gpe_state_machine(dv); | | 612 | acpiec_gpe_state_machine(dv); |
613 | if (sc->sc_state == EC_STATE_FREE) | | 613 | if (sc->sc_state == EC_STATE_FREE) |
614 | goto done; | | 614 | goto done; |
615 | delay(1); | | 615 | delay(1); |
616 | } | | 616 | } |
617 | | | 617 | |
618 | if (cold || acpiec_cold) { | | 618 | if (cold || acpiec_cold) { |
619 | while (sc->sc_state != EC_STATE_FREE && timeo-- > 0) { | | 619 | while (sc->sc_state != EC_STATE_FREE && timeo-- > 0) { |
620 | delay(1000); | | 620 | delay(1000); |
621 | acpiec_gpe_state_machine(dv); | | 621 | acpiec_gpe_state_machine(dv); |
622 | } | | 622 | } |
623 | if (sc->sc_state != EC_STATE_FREE) { | | 623 | if (sc->sc_state != EC_STATE_FREE) { |
624 | mutex_exit(&sc->sc_mtx); | | 624 | mutex_exit(&sc->sc_mtx); |
625 | acpiec_unlock(dv); | | 625 | acpiec_unlock(dv); |
626 | aprint_error_dev(dv, "command timed out, state %d\n", | | 626 | aprint_error_dev(dv, "command timed out, state %d\n", |
627 | sc->sc_state); | | 627 | sc->sc_state); |
628 | return AE_ERROR; | | 628 | return AE_ERROR; |
629 | } | | 629 | } |
630 | } else if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, EC_CMD_TIMEOUT * hz)) { | | 630 | } else if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, EC_CMD_TIMEOUT * hz)) { |
631 | mutex_exit(&sc->sc_mtx); | | 631 | mutex_exit(&sc->sc_mtx); |
632 | acpiec_unlock(dv); | | 632 | acpiec_unlock(dv); |
633 | aprint_error_dev(dv, "command takes over %d sec...\n", EC_CMD_TIMEOUT); | | 633 | aprint_error_dev(dv, "command takes over %d sec...\n", EC_CMD_TIMEOUT); |
634 | return AE_ERROR; | | 634 | return AE_ERROR; |
635 | } | | 635 | } |
636 | | | 636 | |
637 | done: | | 637 | done: |
638 | mutex_exit(&sc->sc_mtx); | | 638 | mutex_exit(&sc->sc_mtx); |
639 | acpiec_unlock(dv); | | 639 | acpiec_unlock(dv); |
640 | return AE_OK; | | 640 | return AE_OK; |
641 | } | | 641 | } |
642 | | | 642 | |
643 | static ACPI_STATUS | | 643 | static ACPI_STATUS |
644 | acpiec_space_handler(uint32_t func, ACPI_PHYSICAL_ADDRESS paddr, | | 644 | acpiec_space_handler(uint32_t func, ACPI_PHYSICAL_ADDRESS paddr, |
645 | uint32_t width, ACPI_INTEGER *value, void *arg, void *region_arg) | | 645 | uint32_t width, ACPI_INTEGER *value, void *arg, void *region_arg) |
646 | { | | 646 | { |
647 | device_t dv; | | 647 | device_t dv; |
648 | struct acpiec_softc *sc; | | 648 | struct acpiec_softc *sc; |
649 | ACPI_STATUS rv; | | 649 | ACPI_STATUS rv; |
650 | uint8_t addr, reg; | | 650 | uint8_t addr, reg; |
651 | unsigned int i; | | 651 | unsigned int i; |
652 | | | 652 | |
653 | if (paddr > 0xff || width % 8 != 0 || value == NULL || arg == NULL || | | 653 | if (paddr > 0xff || width % 8 != 0 || value == NULL || arg == NULL || |
654 | paddr + width / 8 > 0xff) | | 654 | paddr + width / 8 > 0xff) |
655 | return AE_BAD_PARAMETER; | | 655 | return AE_BAD_PARAMETER; |
656 | | | 656 | |
657 | addr = paddr; | | 657 | addr = paddr; |
658 | dv = arg; | | 658 | dv = arg; |
659 | sc = device_private(dv); | | 659 | sc = device_private(dv); |
660 | | | 660 | |
661 | rv = AE_OK; | | 661 | rv = AE_OK; |
662 | | | 662 | |
663 | switch (func) { | | 663 | switch (func) { |
664 | case ACPI_READ: | | 664 | case ACPI_READ: |
665 | *value = 0; | | 665 | *value = 0; |
666 | for (i = 0; i < width; i += 8, ++addr) { | | 666 | for (i = 0; i < width; i += 8, ++addr) { |
667 | rv = acpiec_read(dv, addr, ®); | | 667 | rv = acpiec_read(dv, addr, ®); |
668 | if (rv != AE_OK) | | 668 | if (rv != AE_OK) |
669 | break; | | 669 | break; |
670 | *value |= (ACPI_INTEGER)reg << i; | | 670 | *value |= (ACPI_INTEGER)reg << i; |
671 | } | | 671 | } |
672 | break; | | 672 | break; |
673 | case ACPI_WRITE: | | 673 | case ACPI_WRITE: |
674 | for (i = 0; i < width; i += 8, ++addr) { | | 674 | for (i = 0; i < width; i += 8, ++addr) { |
675 | reg = (*value >>i) & 0xff; | | 675 | reg = (*value >>i) & 0xff; |
676 | rv = acpiec_write(dv, addr, reg); | | 676 | rv = acpiec_write(dv, addr, reg); |
677 | if (rv != AE_OK) | | 677 | if (rv != AE_OK) |
678 | break; | | 678 | break; |
679 | } | | 679 | } |
680 | break; | | 680 | break; |
681 | default: | | 681 | default: |
682 | aprint_error("%s: invalid Address Space function called: %x\n", | | 682 | aprint_error("%s: invalid Address Space function called: %x\n", |
683 | device_xname(dv), (unsigned int)func); | | 683 | device_xname(dv), (unsigned int)func); |
684 | return AE_BAD_PARAMETER; | | 684 | return AE_BAD_PARAMETER; |
685 | } | | 685 | } |
686 | | | 686 | |
687 | return rv; | | 687 | return rv; |
688 | } | | 688 | } |
689 | | | 689 | |
690 | static void | | 690 | static void |
691 | acpiec_gpe_query(void *arg) | | 691 | acpiec_gpe_query(void *arg) |
692 | { | | 692 | { |
693 | device_t dv = arg; | | 693 | device_t dv = arg; |
694 | struct acpiec_softc *sc = device_private(dv); | | 694 | struct acpiec_softc *sc = device_private(dv); |
695 | uint8_t reg; | | 695 | uint8_t reg; |
696 | char qxx[5]; | | 696 | char qxx[5]; |
697 | ACPI_STATUS rv; | | 697 | ACPI_STATUS rv; |
698 | int i; | | 698 | int i; |
699 | | | 699 | |
700 | loop: | | 700 | loop: |
701 | mutex_enter(&sc->sc_mtx); | | 701 | mutex_enter(&sc->sc_mtx); |
702 | | | 702 | |
703 | if (sc->sc_got_sci == false) | | 703 | if (sc->sc_got_sci == false) |
704 | cv_wait(&sc->sc_cv_sci, &sc->sc_mtx); | | 704 | cv_wait(&sc->sc_cv_sci, &sc->sc_mtx); |
705 | mutex_exit(&sc->sc_mtx); | | 705 | mutex_exit(&sc->sc_mtx); |
706 | | | 706 | |
707 | acpiec_lock(dv); | | 707 | acpiec_lock(dv); |
708 | mutex_enter(&sc->sc_mtx); | | 708 | mutex_enter(&sc->sc_mtx); |
709 | | | 709 | |
710 | /* The Query command can always be issued, so be defensive here. */ | | 710 | /* The Query command can always be issued, so be defensive here. */ |
711 | sc->sc_got_sci = false; | | 711 | sc->sc_got_sci = false; |
712 | sc->sc_state = EC_STATE_QUERY; | | 712 | sc->sc_state = EC_STATE_QUERY; |
713 | | | 713 | |
714 | for (i = 0; i < EC_POLL_TIMEOUT; ++i) { | | 714 | for (i = 0; i < EC_POLL_TIMEOUT; ++i) { |
715 | acpiec_gpe_state_machine(dv); | | 715 | acpiec_gpe_state_machine(dv); |
716 | if (sc->sc_state == EC_STATE_FREE) | | 716 | if (sc->sc_state == EC_STATE_FREE) |
717 | goto done; | | 717 | goto done; |
718 | delay(1); | | 718 | delay(1); |
719 | } | | 719 | } |
720 | | | 720 | |
721 | cv_wait(&sc->sc_cv, &sc->sc_mtx); | | 721 | cv_wait(&sc->sc_cv, &sc->sc_mtx); |
722 | | | 722 | |
723 | done: | | 723 | done: |
724 | reg = sc->sc_cur_val; | | 724 | reg = sc->sc_cur_val; |
725 | | | 725 | |
726 | mutex_exit(&sc->sc_mtx); | | 726 | mutex_exit(&sc->sc_mtx); |
727 | acpiec_unlock(dv); | | 727 | acpiec_unlock(dv); |
728 | | | 728 | |
729 | if (reg == 0) | | 729 | if (reg == 0) |
730 | goto loop; /* Spurious query result */ | | 730 | goto loop; /* Spurious query result */ |
731 | | | 731 | |
732 | /* | | 732 | /* |
733 | * Evaluate _Qxx to respond to the controller. | | 733 | * Evaluate _Qxx to respond to the controller. |
734 | */ | | 734 | */ |
735 | snprintf(qxx, sizeof(qxx), "_Q%02X", (unsigned int)reg); | | 735 | snprintf(qxx, sizeof(qxx), "_Q%02X", (unsigned int)reg); |
736 | rv = AcpiEvaluateObject(sc->sc_ech, qxx, NULL, NULL); | | 736 | rv = AcpiEvaluateObject(sc->sc_ech, qxx, NULL, NULL); |
737 | if (rv != AE_OK && rv != AE_NOT_FOUND) { | | 737 | if (rv != AE_OK && rv != AE_NOT_FOUND) { |
738 | aprint_error("%s: GPE query method %s failed: %s", | | 738 | aprint_error_dev(dv, "GPE query method %s failed: %s", |
739 | device_xname(dv), qxx, AcpiFormatException(rv)); | | 739 | qxx, AcpiFormatException(rv)); |
740 | } | | 740 | } |
741 | | | 741 | |
742 | goto loop; | | 742 | goto loop; |
743 | } | | 743 | } |
744 | | | 744 | |
745 | static void | | 745 | static void |
746 | acpiec_gpe_state_machine(device_t dv) | | 746 | acpiec_gpe_state_machine(device_t dv) |
747 | { | | 747 | { |
748 | struct acpiec_softc *sc = device_private(dv); | | 748 | struct acpiec_softc *sc = device_private(dv); |
749 | uint8_t reg; | | 749 | uint8_t reg; |
750 | | | 750 | |
751 | reg = acpiec_read_status(sc); | | 751 | reg = acpiec_read_status(sc); |
752 | | | 752 | |
753 | if (reg & EC_STATUS_SCI) | | 753 | if (reg & EC_STATUS_SCI) |
754 | sc->sc_got_sci = true; | | 754 | sc->sc_got_sci = true; |
755 | | | 755 | |
756 | switch (sc->sc_state) { | | 756 | switch (sc->sc_state) { |
757 | case EC_STATE_QUERY: | | 757 | case EC_STATE_QUERY: |
758 | if ((reg & EC_STATUS_IBF) != 0) | | 758 | if ((reg & EC_STATUS_IBF) != 0) |
759 | break; /* Nothing of interest here. */ | | 759 | break; /* Nothing of interest here. */ |
760 | acpiec_write_command(sc, EC_COMMAND_QUERY); | | 760 | acpiec_write_command(sc, EC_COMMAND_QUERY); |
761 | sc->sc_state = EC_STATE_QUERY_VAL; | | 761 | sc->sc_state = EC_STATE_QUERY_VAL; |
762 | break; | | 762 | break; |
763 | | | 763 | |
764 | case EC_STATE_QUERY_VAL: | | 764 | case EC_STATE_QUERY_VAL: |
765 | if ((reg & EC_STATUS_OBF) == 0) | | 765 | if ((reg & EC_STATUS_OBF) == 0) |
766 | break; /* Nothing of interest here. */ | | 766 | break; /* Nothing of interest here. */ |
767 | | | 767 | |
768 | sc->sc_cur_val = acpiec_read_data(sc); | | 768 | sc->sc_cur_val = acpiec_read_data(sc); |
769 | sc->sc_state = EC_STATE_FREE; | | 769 | sc->sc_state = EC_STATE_FREE; |
770 | | | 770 | |
771 | cv_signal(&sc->sc_cv); | | 771 | cv_signal(&sc->sc_cv); |
772 | break; | | 772 | break; |
773 | | | 773 | |
774 | case EC_STATE_READ: | | 774 | case EC_STATE_READ: |
775 | if ((reg & EC_STATUS_IBF) != 0) | | 775 | if ((reg & EC_STATUS_IBF) != 0) |
776 | break; /* Nothing of interest here. */ | | 776 | break; /* Nothing of interest here. */ |
777 | | | 777 | |
778 | acpiec_write_command(sc, EC_COMMAND_READ); | | 778 | acpiec_write_command(sc, EC_COMMAND_READ); |
779 | sc->sc_state = EC_STATE_READ_ADDR; | | 779 | sc->sc_state = EC_STATE_READ_ADDR; |
780 | break; | | 780 | break; |
781 | | | 781 | |
782 | case EC_STATE_READ_ADDR: | | 782 | case EC_STATE_READ_ADDR: |
783 | if ((reg & EC_STATUS_IBF) != 0) | | 783 | if ((reg & EC_STATUS_IBF) != 0) |
784 | break; /* Nothing of interest here. */ | | 784 | break; /* Nothing of interest here. */ |
785 | | | 785 | |
786 | acpiec_write_data(sc, sc->sc_cur_addr); | | 786 | acpiec_write_data(sc, sc->sc_cur_addr); |
787 | sc->sc_state = EC_STATE_READ_VAL; | | 787 | sc->sc_state = EC_STATE_READ_VAL; |
788 | break; | | 788 | break; |
789 | | | 789 | |
790 | case EC_STATE_READ_VAL: | | 790 | case EC_STATE_READ_VAL: |
791 | if ((reg & EC_STATUS_OBF) == 0) | | 791 | if ((reg & EC_STATUS_OBF) == 0) |
792 | break; /* Nothing of interest here. */ | | 792 | break; /* Nothing of interest here. */ |
793 | sc->sc_cur_val = acpiec_read_data(sc); | | 793 | sc->sc_cur_val = acpiec_read_data(sc); |
794 | sc->sc_state = EC_STATE_FREE; | | 794 | sc->sc_state = EC_STATE_FREE; |
795 | | | 795 | |
796 | cv_signal(&sc->sc_cv); | | 796 | cv_signal(&sc->sc_cv); |
797 | break; | | 797 | break; |
798 | | | 798 | |
799 | case EC_STATE_WRITE: | | 799 | case EC_STATE_WRITE: |
800 | if ((reg & EC_STATUS_IBF) != 0) | | 800 | if ((reg & EC_STATUS_IBF) != 0) |
801 | break; /* Nothing of interest here. */ | | 801 | break; /* Nothing of interest here. */ |
802 | | | 802 | |
803 | acpiec_write_command(sc, EC_COMMAND_WRITE); | | 803 | acpiec_write_command(sc, EC_COMMAND_WRITE); |
804 | sc->sc_state = EC_STATE_WRITE_ADDR; | | 804 | sc->sc_state = EC_STATE_WRITE_ADDR; |
805 | break; | | 805 | break; |
806 | | | 806 | |
807 | case EC_STATE_WRITE_ADDR: | | 807 | case EC_STATE_WRITE_ADDR: |
808 | if ((reg & EC_STATUS_IBF) != 0) | | 808 | if ((reg & EC_STATUS_IBF) != 0) |
809 | break; /* Nothing of interest here. */ | | 809 | break; /* Nothing of interest here. */ |
810 | acpiec_write_data(sc, sc->sc_cur_addr); | | 810 | acpiec_write_data(sc, sc->sc_cur_addr); |
811 | sc->sc_state = EC_STATE_WRITE_VAL; | | 811 | sc->sc_state = EC_STATE_WRITE_VAL; |
812 | break; | | 812 | break; |
813 | | | 813 | |
814 | case EC_STATE_WRITE_VAL: | | 814 | case EC_STATE_WRITE_VAL: |
815 | if ((reg & EC_STATUS_IBF) != 0) | | 815 | if ((reg & EC_STATUS_IBF) != 0) |
816 | break; /* Nothing of interest here. */ | | 816 | break; /* Nothing of interest here. */ |
817 | sc->sc_state = EC_STATE_FREE; | | 817 | sc->sc_state = EC_STATE_FREE; |
818 | cv_signal(&sc->sc_cv); | | 818 | cv_signal(&sc->sc_cv); |
819 | | | 819 | |
820 | acpiec_write_data(sc, sc->sc_cur_val); | | 820 | acpiec_write_data(sc, sc->sc_cur_val); |
821 | break; | | 821 | break; |
822 | | | 822 | |
823 | case EC_STATE_FREE: | | 823 | case EC_STATE_FREE: |
824 | if (sc->sc_got_sci) | | 824 | if (sc->sc_got_sci) |
825 | cv_signal(&sc->sc_cv_sci); | | 825 | cv_signal(&sc->sc_cv_sci); |
826 | break; | | 826 | break; |
827 | default: | | 827 | default: |
828 | panic("invalid state"); | | 828 | panic("invalid state"); |
829 | } | | 829 | } |
830 | | | 830 | |
831 | if (sc->sc_state != EC_STATE_FREE) | | 831 | if (sc->sc_state != EC_STATE_FREE) |
832 | callout_schedule(&sc->sc_pseudo_intr, 1); | | 832 | callout_schedule(&sc->sc_pseudo_intr, 1); |
833 | } | | 833 | } |
834 | | | 834 | |
835 | static void | | 835 | static void |
836 | acpiec_callout(void *arg) | | 836 | acpiec_callout(void *arg) |
837 | { | | 837 | { |
838 | device_t dv = arg; | | 838 | device_t dv = arg; |
839 | struct acpiec_softc *sc = device_private(dv); | | 839 | struct acpiec_softc *sc = device_private(dv); |
840 | | | 840 | |
841 | mutex_enter(&sc->sc_mtx); | | 841 | mutex_enter(&sc->sc_mtx); |
842 | acpiec_gpe_state_machine(dv); | | 842 | acpiec_gpe_state_machine(dv); |
843 | mutex_exit(&sc->sc_mtx); | | 843 | mutex_exit(&sc->sc_mtx); |
844 | } | | 844 | } |
845 | | | 845 | |
846 | static uint32_t | | 846 | static uint32_t |
847 | acpiec_gpe_handler(void *arg) | | 847 | acpiec_gpe_handler(void *arg) |
848 | { | | 848 | { |
849 | device_t dv = arg; | | 849 | device_t dv = arg; |
850 | struct acpiec_softc *sc = device_private(dv); | | 850 | struct acpiec_softc *sc = device_private(dv); |
851 | | | 851 | |
852 | mutex_enter(&sc->sc_mtx); | | 852 | mutex_enter(&sc->sc_mtx); |
853 | acpiec_gpe_state_machine(dv); | | 853 | acpiec_gpe_state_machine(dv); |
854 | mutex_exit(&sc->sc_mtx); | | 854 | mutex_exit(&sc->sc_mtx); |
855 | | | 855 | |
856 | return 0; | | 856 | return 0; |
857 | } | | 857 | } |
858 | | | 858 | |
859 | ACPI_STATUS | | 859 | ACPI_STATUS |
860 | acpiec_bus_read(device_t dv, u_int addr, ACPI_INTEGER *val, int width) | | 860 | acpiec_bus_read(device_t dv, u_int addr, ACPI_INTEGER *val, int width) |
861 | { | | 861 | { |
862 | return acpiec_space_handler(ACPI_READ, addr, width * 8, val, dv, NULL); | | 862 | return acpiec_space_handler(ACPI_READ, addr, width * 8, val, dv, NULL); |
863 | } | | 863 | } |
864 | | | 864 | |
865 | ACPI_STATUS | | 865 | ACPI_STATUS |
866 | acpiec_bus_write(device_t dv, u_int addr, ACPI_INTEGER val, int width) | | 866 | acpiec_bus_write(device_t dv, u_int addr, ACPI_INTEGER val, int width) |
867 | { | | 867 | { |
868 | return acpiec_space_handler(ACPI_WRITE, addr, width * 8, &val, dv, NULL); | | 868 | return acpiec_space_handler(ACPI_WRITE, addr, width * 8, &val, dv, NULL); |
869 | } | | 869 | } |
870 | | | 870 | |
871 | ACPI_HANDLE | | 871 | ACPI_HANDLE |
872 | acpiec_get_handle(device_t dv) | | 872 | acpiec_get_handle(device_t dv) |
873 | { | | 873 | { |
874 | struct acpiec_softc *sc = device_private(dv); | | 874 | struct acpiec_softc *sc = device_private(dv); |
875 | | | 875 | |
876 | return sc->sc_ech; | | 876 | return sc->sc_ech; |
877 | } | | 877 | } |