diff options
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 343 |
1 files changed, 153 insertions, 190 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7aa600794ae4..4a909bfb805c 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -45,35 +45,34 @@ ACPI_MODULE_NAME("acpi_ec") | |||
45 | #define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" | 45 | #define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" |
46 | #define ACPI_EC_DEVICE_NAME "Embedded Controller" | 46 | #define ACPI_EC_DEVICE_NAME "Embedded Controller" |
47 | #define ACPI_EC_FILE_INFO "info" | 47 | #define ACPI_EC_FILE_INFO "info" |
48 | 48 | #undef PREFIX | |
49 | #define PREFIX "ACPI: EC: " | ||
49 | /* EC status register */ | 50 | /* EC status register */ |
50 | #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ | 51 | #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ |
51 | #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ | 52 | #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ |
52 | #define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ | 53 | #define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ |
53 | #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ | 54 | #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ |
54 | |||
55 | /* EC commands */ | 55 | /* EC commands */ |
56 | #define ACPI_EC_COMMAND_READ 0x80 | 56 | enum ec_command { |
57 | #define ACPI_EC_COMMAND_WRITE 0x81 | 57 | ACPI_EC_COMMAND_READ = 0x80, |
58 | #define ACPI_EC_BURST_ENABLE 0x82 | 58 | ACPI_EC_COMMAND_WRITE = 0x81, |
59 | #define ACPI_EC_BURST_DISABLE 0x83 | 59 | ACPI_EC_BURST_ENABLE = 0x82, |
60 | #define ACPI_EC_COMMAND_QUERY 0x84 | 60 | ACPI_EC_BURST_DISABLE = 0x83, |
61 | 61 | ACPI_EC_COMMAND_QUERY = 0x84, | |
62 | }; | ||
62 | /* EC events */ | 63 | /* EC events */ |
63 | enum { | 64 | enum ec_event { |
64 | ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ | 65 | ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ |
65 | ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ | 66 | ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ |
66 | }; | 67 | }; |
67 | 68 | ||
68 | #define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */ | 69 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ |
69 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ | 70 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ |
70 | #define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ | ||
71 | #define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ | ||
72 | 71 | ||
73 | enum { | 72 | static enum ec_mode { |
74 | EC_INTR = 1, /* Output buffer full */ | 73 | EC_INTR = 1, /* Output buffer full */ |
75 | EC_POLL, /* Input buffer empty */ | 74 | EC_POLL, /* Input buffer empty */ |
76 | }; | 75 | } acpi_ec_mode = EC_INTR; |
77 | 76 | ||
78 | static int acpi_ec_remove(struct acpi_device *device, int type); | 77 | static int acpi_ec_remove(struct acpi_device *device, int type); |
79 | static int acpi_ec_start(struct acpi_device *device); | 78 | static int acpi_ec_start(struct acpi_device *device); |
@@ -96,19 +95,18 @@ static struct acpi_driver acpi_ec_driver = { | |||
96 | struct acpi_ec { | 95 | struct acpi_ec { |
97 | acpi_handle handle; | 96 | acpi_handle handle; |
98 | unsigned long uid; | 97 | unsigned long uid; |
99 | unsigned long gpe_bit; | 98 | unsigned long gpe; |
100 | unsigned long command_addr; | 99 | unsigned long command_addr; |
101 | unsigned long data_addr; | 100 | unsigned long data_addr; |
102 | unsigned long global_lock; | 101 | unsigned long global_lock; |
103 | struct semaphore sem; | 102 | struct mutex lock; |
104 | unsigned int expect_event; | 103 | atomic_t query_pending; |
105 | atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ | 104 | atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */ |
106 | wait_queue_head_t wait; | 105 | wait_queue_head_t wait; |
107 | } *ec_ecdt; | 106 | } *ec_ecdt; |
108 | 107 | ||
109 | /* External interfaces use first EC only, so remember */ | 108 | /* External interfaces use first EC only, so remember */ |
110 | static struct acpi_device *first_ec; | 109 | static struct acpi_device *first_ec; |
111 | static int acpi_ec_mode = EC_INTR; | ||
112 | 110 | ||
113 | /* -------------------------------------------------------------------------- | 111 | /* -------------------------------------------------------------------------- |
114 | Transaction Management | 112 | Transaction Management |
@@ -134,54 +132,41 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) | |||
134 | outb(data, ec->data_addr); | 132 | outb(data, ec->data_addr); |
135 | } | 133 | } |
136 | 134 | ||
137 | static int acpi_ec_check_status(u8 status, u8 event) | 135 | static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) |
138 | { | 136 | { |
139 | switch (event) { | 137 | u8 status = acpi_ec_read_status(ec); |
140 | case ACPI_EC_EVENT_OBF_1: | 138 | |
139 | if (event == ACPI_EC_EVENT_OBF_1) { | ||
141 | if (status & ACPI_EC_FLAG_OBF) | 140 | if (status & ACPI_EC_FLAG_OBF) |
142 | return 1; | 141 | return 1; |
143 | break; | 142 | } else if (event == ACPI_EC_EVENT_IBF_0) { |
144 | case ACPI_EC_EVENT_IBF_0: | ||
145 | if (!(status & ACPI_EC_FLAG_IBF)) | 143 | if (!(status & ACPI_EC_FLAG_IBF)) |
146 | return 1; | 144 | return 1; |
147 | break; | ||
148 | default: | ||
149 | break; | ||
150 | } | 145 | } |
151 | 146 | ||
152 | return 0; | 147 | return 0; |
153 | } | 148 | } |
154 | 149 | ||
155 | static int acpi_ec_wait(struct acpi_ec *ec, u8 event) | 150 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event) |
156 | { | 151 | { |
157 | int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0; | 152 | if (acpi_ec_mode == EC_POLL) { |
158 | long time_left; | 153 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); |
159 | 154 | while (time_before(jiffies, delay)) { | |
160 | ec->expect_event = event; | 155 | if (acpi_ec_check_status(ec, event)) |
161 | if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { | ||
162 | ec->expect_event = 0; | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | do { | ||
167 | if (acpi_ec_mode == EC_POLL) { | ||
168 | udelay(ACPI_EC_UDELAY); | ||
169 | } else { | ||
170 | time_left = wait_event_timeout(ec->wait, | ||
171 | !ec->expect_event, | ||
172 | msecs_to_jiffies(ACPI_EC_DELAY)); | ||
173 | if (time_left > 0) { | ||
174 | ec->expect_event = 0; | ||
175 | return 0; | 156 | return 0; |
176 | } | ||
177 | } | 157 | } |
178 | if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) { | 158 | } else { |
179 | ec->expect_event = 0; | 159 | if (wait_event_timeout(ec->wait, |
160 | acpi_ec_check_status(ec, event), | ||
161 | msecs_to_jiffies(ACPI_EC_DELAY)) || | ||
162 | acpi_ec_check_status(ec, event)) { | ||
180 | return 0; | 163 | return 0; |
164 | } else { | ||
165 | printk(KERN_ERR PREFIX "acpi_ec_wait timeout," | ||
166 | " status = %d, expect_event = %d\n", | ||
167 | acpi_ec_read_status(ec), event); | ||
181 | } | 168 | } |
182 | } while (--i > 0); | 169 | } |
183 | |||
184 | ec->expect_event = 0; | ||
185 | 170 | ||
186 | return -ETIME; | 171 | return -ETIME; |
187 | } | 172 | } |
@@ -196,7 +181,6 @@ int acpi_ec_enter_burst_mode(struct acpi_ec *ec) | |||
196 | u8 tmp = 0; | 181 | u8 tmp = 0; |
197 | u8 status = 0; | 182 | u8 status = 0; |
198 | 183 | ||
199 | |||
200 | status = acpi_ec_read_status(ec); | 184 | status = acpi_ec_read_status(ec); |
201 | if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) { | 185 | if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) { |
202 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); | 186 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); |
@@ -212,7 +196,7 @@ int acpi_ec_enter_burst_mode(struct acpi_ec *ec) | |||
212 | 196 | ||
213 | atomic_set(&ec->leaving_burst, 0); | 197 | atomic_set(&ec->leaving_burst, 0); |
214 | return 0; | 198 | return 0; |
215 | end: | 199 | end: |
216 | ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode")); | 200 | ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode")); |
217 | return -1; | 201 | return -1; |
218 | } | 202 | } |
@@ -221,58 +205,68 @@ int acpi_ec_leave_burst_mode(struct acpi_ec *ec) | |||
221 | { | 205 | { |
222 | u8 status = 0; | 206 | u8 status = 0; |
223 | 207 | ||
224 | |||
225 | status = acpi_ec_read_status(ec); | 208 | status = acpi_ec_read_status(ec); |
226 | if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){ | 209 | if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) { |
227 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); | 210 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); |
228 | if(status) | 211 | if (status) |
229 | goto end; | 212 | goto end; |
230 | acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE); | 213 | acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE); |
231 | acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); | 214 | acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); |
232 | } | 215 | } |
233 | atomic_set(&ec->leaving_burst, 1); | 216 | atomic_set(&ec->leaving_burst, 1); |
234 | return 0; | 217 | return 0; |
235 | end: | 218 | end: |
236 | ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode")); | 219 | ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode")); |
237 | return -1; | 220 | return -1; |
238 | } | 221 | } |
239 | #endif /* ACPI_FUTURE_USAGE */ | 222 | #endif /* ACPI_FUTURE_USAGE */ |
240 | 223 | ||
241 | static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, | 224 | static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, |
242 | const u8 *wdata, unsigned wdata_len, | 225 | const u8 * wdata, unsigned wdata_len, |
243 | u8 *rdata, unsigned rdata_len) | 226 | u8 * rdata, unsigned rdata_len) |
244 | { | 227 | { |
245 | int result; | 228 | int result = 0; |
246 | 229 | ||
247 | acpi_ec_write_cmd(ec, command); | 230 | acpi_ec_write_cmd(ec, command); |
248 | 231 | ||
249 | for (; wdata_len > 0; wdata_len --) { | 232 | for (; wdata_len > 0; --wdata_len) { |
250 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); | 233 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); |
251 | if (result) | 234 | if (result) { |
252 | return result; | 235 | printk(KERN_ERR PREFIX |
236 | "write_cmd timeout, command = %d\n", command); | ||
237 | goto end; | ||
238 | } | ||
253 | acpi_ec_write_data(ec, *(wdata++)); | 239 | acpi_ec_write_data(ec, *(wdata++)); |
254 | } | 240 | } |
255 | 241 | ||
256 | if (command == ACPI_EC_COMMAND_WRITE) { | 242 | if (!rdata_len) { |
257 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); | 243 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); |
258 | if (result) | 244 | if (result) { |
259 | return result; | 245 | printk(KERN_ERR PREFIX |
246 | "finish-write timeout, command = %d\n", command); | ||
247 | goto end; | ||
248 | } | ||
249 | } else if (command == ACPI_EC_COMMAND_QUERY) { | ||
250 | atomic_set(&ec->query_pending, 0); | ||
260 | } | 251 | } |
261 | 252 | ||
262 | for (; rdata_len > 0; rdata_len --) { | 253 | for (; rdata_len > 0; --rdata_len) { |
263 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1); | 254 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1); |
264 | if (result) | 255 | if (result) { |
265 | return result; | 256 | printk(KERN_ERR PREFIX "read timeout, command = %d\n", |
257 | command); | ||
258 | goto end; | ||
259 | } | ||
266 | 260 | ||
267 | *(rdata++) = acpi_ec_read_data(ec); | 261 | *(rdata++) = acpi_ec_read_data(ec); |
268 | } | 262 | } |
269 | 263 | end: | |
270 | return 0; | 264 | return result; |
271 | } | 265 | } |
272 | 266 | ||
273 | static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, | 267 | static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, |
274 | const u8 *wdata, unsigned wdata_len, | 268 | const u8 * wdata, unsigned wdata_len, |
275 | u8 *rdata, unsigned rdata_len) | 269 | u8 * rdata, unsigned rdata_len) |
276 | { | 270 | { |
277 | int status; | 271 | int status; |
278 | u32 glk; | 272 | u32 glk; |
@@ -280,36 +274,40 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, | |||
280 | if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) | 274 | if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata)) |
281 | return -EINVAL; | 275 | return -EINVAL; |
282 | 276 | ||
283 | if (rdata) | 277 | if (rdata) |
284 | memset(rdata, 0, rdata_len); | 278 | memset(rdata, 0, rdata_len); |
285 | 279 | ||
280 | mutex_lock(&ec->lock); | ||
286 | if (ec->global_lock) { | 281 | if (ec->global_lock) { |
287 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); | 282 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); |
288 | if (ACPI_FAILURE(status)) | 283 | if (ACPI_FAILURE(status)) |
289 | return -ENODEV; | 284 | return -ENODEV; |
290 | } | 285 | } |
291 | down(&ec->sem); | 286 | |
287 | /* Make sure GPE is enabled before doing transaction */ | ||
288 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | ||
292 | 289 | ||
293 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); | 290 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0); |
294 | if (status) { | 291 | if (status) { |
295 | printk(KERN_DEBUG PREFIX "read EC, IB not empty\n"); | 292 | printk(KERN_DEBUG PREFIX |
293 | "input buffer is not empty, aborting transaction\n"); | ||
296 | goto end; | 294 | goto end; |
297 | } | 295 | } |
298 | 296 | ||
299 | status = acpi_ec_transaction_unlocked(ec, command, | 297 | status = acpi_ec_transaction_unlocked(ec, command, |
300 | wdata, wdata_len, | 298 | wdata, wdata_len, |
301 | rdata, rdata_len); | 299 | rdata, rdata_len); |
302 | 300 | ||
303 | end: | 301 | end: |
304 | up(&ec->sem); | ||
305 | 302 | ||
306 | if (ec->global_lock) | 303 | if (ec->global_lock) |
307 | acpi_release_global_lock(glk); | 304 | acpi_release_global_lock(glk); |
305 | mutex_unlock(&ec->lock); | ||
308 | 306 | ||
309 | return status; | 307 | return status; |
310 | } | 308 | } |
311 | 309 | ||
312 | static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) | 310 | static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) |
313 | { | 311 | { |
314 | int result; | 312 | int result; |
315 | u8 d; | 313 | u8 d; |
@@ -322,15 +320,15 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) | |||
322 | 320 | ||
323 | static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) | 321 | static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data) |
324 | { | 322 | { |
325 | u8 wdata[2] = { address, data }; | 323 | u8 wdata[2] = { address, data }; |
326 | return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, | 324 | return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, |
327 | wdata, 2, NULL, 0); | 325 | wdata, 2, NULL, 0); |
328 | } | 326 | } |
329 | 327 | ||
330 | /* | 328 | /* |
331 | * Externally callable EC access functions. For now, assume 1 EC only | 329 | * Externally callable EC access functions. For now, assume 1 EC only |
332 | */ | 330 | */ |
333 | int ec_read(u8 addr, u8 *val) | 331 | int ec_read(u8 addr, u8 * val) |
334 | { | 332 | { |
335 | struct acpi_ec *ec; | 333 | struct acpi_ec *ec; |
336 | int err; | 334 | int err; |
@@ -370,8 +368,8 @@ int ec_write(u8 addr, u8 val) | |||
370 | EXPORT_SYMBOL(ec_write); | 368 | EXPORT_SYMBOL(ec_write); |
371 | 369 | ||
372 | int ec_transaction(u8 command, | 370 | int ec_transaction(u8 command, |
373 | const u8 *wdata, unsigned wdata_len, | 371 | const u8 * wdata, unsigned wdata_len, |
374 | u8 *rdata, unsigned rdata_len) | 372 | u8 * rdata, unsigned rdata_len) |
375 | { | 373 | { |
376 | struct acpi_ec *ec; | 374 | struct acpi_ec *ec; |
377 | 375 | ||
@@ -386,65 +384,49 @@ int ec_transaction(u8 command, | |||
386 | 384 | ||
387 | EXPORT_SYMBOL(ec_transaction); | 385 | EXPORT_SYMBOL(ec_transaction); |
388 | 386 | ||
389 | static int acpi_ec_query(struct acpi_ec *ec, u8 *data) | 387 | static int acpi_ec_query(struct acpi_ec *ec, u8 * data) |
390 | { | 388 | { |
391 | int result; | 389 | int result; |
392 | u8 d; | 390 | u8 d; |
393 | 391 | ||
394 | if (!ec || !data) | 392 | if (!ec || !data) |
395 | return -EINVAL; | 393 | return -EINVAL; |
396 | 394 | ||
397 | /* | 395 | /* |
398 | * Query the EC to find out which _Qxx method we need to evaluate. | 396 | * Query the EC to find out which _Qxx method we need to evaluate. |
399 | * Note that successful completion of the query causes the ACPI_EC_SCI | 397 | * Note that successful completion of the query causes the ACPI_EC_SCI |
400 | * bit to be cleared (and thus clearing the interrupt source). | 398 | * bit to be cleared (and thus clearing the interrupt source). |
401 | */ | 399 | */ |
402 | 400 | ||
403 | result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1); | 401 | result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1); |
404 | if (result) | 402 | if (result) |
405 | return result; | 403 | return result; |
406 | 404 | ||
407 | if (!d) | 405 | if (!d) |
408 | return -ENODATA; | 406 | return -ENODATA; |
409 | 407 | ||
410 | *data = d; | 408 | *data = d; |
411 | return 0; | 409 | return 0; |
412 | } | 410 | } |
413 | 411 | ||
414 | /* -------------------------------------------------------------------------- | 412 | /* -------------------------------------------------------------------------- |
415 | Event Management | 413 | Event Management |
416 | -------------------------------------------------------------------------- */ | 414 | -------------------------------------------------------------------------- */ |
417 | 415 | ||
418 | struct acpi_ec_query_data { | ||
419 | acpi_handle handle; | ||
420 | u8 data; | ||
421 | }; | ||
422 | |||
423 | static void acpi_ec_gpe_query(void *ec_cxt) | 416 | static void acpi_ec_gpe_query(void *ec_cxt) |
424 | { | 417 | { |
425 | struct acpi_ec *ec = (struct acpi_ec *)ec_cxt; | 418 | struct acpi_ec *ec = (struct acpi_ec *)ec_cxt; |
426 | u8 value = 0; | 419 | u8 value = 0; |
427 | static char object_name[8]; | 420 | char object_name[8]; |
428 | 421 | ||
429 | if (!ec) | 422 | if (!ec || acpi_ec_query(ec, &value)) |
430 | goto end; | 423 | return; |
431 | |||
432 | value = acpi_ec_read_status(ec); | ||
433 | |||
434 | if (!(value & ACPI_EC_FLAG_SCI)) | ||
435 | goto end; | ||
436 | |||
437 | if (acpi_ec_query(ec, &value)) | ||
438 | goto end; | ||
439 | 424 | ||
440 | snprintf(object_name, 8, "_Q%2.2X", value); | 425 | snprintf(object_name, 8, "_Q%2.2X", value); |
441 | 426 | ||
442 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name)); | 427 | printk(KERN_INFO PREFIX "evaluating %s\n", object_name); |
443 | 428 | ||
444 | acpi_evaluate_object(ec->handle, object_name, NULL, NULL); | 429 | acpi_evaluate_object(ec->handle, object_name, NULL, NULL); |
445 | |||
446 | end: | ||
447 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | ||
448 | } | 430 | } |
449 | 431 | ||
450 | static u32 acpi_ec_gpe_handler(void *data) | 432 | static u32 acpi_ec_gpe_handler(void *data) |
@@ -453,22 +435,18 @@ static u32 acpi_ec_gpe_handler(void *data) | |||
453 | u8 value; | 435 | u8 value; |
454 | struct acpi_ec *ec = (struct acpi_ec *)data; | 436 | struct acpi_ec *ec = (struct acpi_ec *)data; |
455 | 437 | ||
456 | acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR); | ||
457 | value = acpi_ec_read_status(ec); | ||
458 | |||
459 | if (acpi_ec_mode == EC_INTR) { | 438 | if (acpi_ec_mode == EC_INTR) { |
460 | if (acpi_ec_check_status(value, ec->expect_event)) { | 439 | wake_up(&ec->wait); |
461 | ec->expect_event = 0; | ||
462 | wake_up(&ec->wait); | ||
463 | } | ||
464 | } | 440 | } |
465 | 441 | ||
466 | if (value & ACPI_EC_FLAG_SCI) { | 442 | value = acpi_ec_read_status(ec); |
467 | status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); | 443 | if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) { |
468 | return status == AE_OK ? | 444 | atomic_set(&ec->query_pending, 1); |
469 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; | 445 | status = |
446 | acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, | ||
447 | ec); | ||
470 | } | 448 | } |
471 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR); | 449 | |
472 | return status == AE_OK ? | 450 | return status == AE_OK ? |
473 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; | 451 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; |
474 | } | 452 | } |
@@ -504,7 +482,6 @@ acpi_ec_space_handler(u32 function, | |||
504 | acpi_integer f_v = 0; | 482 | acpi_integer f_v = 0; |
505 | int i = 0; | 483 | int i = 0; |
506 | 484 | ||
507 | |||
508 | if ((address > 0xFF) || !value || !handler_context) | 485 | if ((address > 0xFF) || !value || !handler_context) |
509 | return AE_BAD_PARAMETER; | 486 | return AE_BAD_PARAMETER; |
510 | 487 | ||
@@ -518,7 +495,7 @@ acpi_ec_space_handler(u32 function, | |||
518 | switch (function) { | 495 | switch (function) { |
519 | case ACPI_READ: | 496 | case ACPI_READ: |
520 | temp = 0; | 497 | temp = 0; |
521 | result = acpi_ec_read(ec, (u8) address, (u8 *) &temp); | 498 | result = acpi_ec_read(ec, (u8) address, (u8 *) & temp); |
522 | break; | 499 | break; |
523 | case ACPI_WRITE: | 500 | case ACPI_WRITE: |
524 | result = acpi_ec_write(ec, (u8) address, (u8) temp); | 501 | result = acpi_ec_write(ec, (u8) address, (u8) temp); |
@@ -571,18 +548,15 @@ static int acpi_ec_read_info(struct seq_file *seq, void *offset) | |||
571 | { | 548 | { |
572 | struct acpi_ec *ec = (struct acpi_ec *)seq->private; | 549 | struct acpi_ec *ec = (struct acpi_ec *)seq->private; |
573 | 550 | ||
574 | |||
575 | if (!ec) | 551 | if (!ec) |
576 | goto end; | 552 | goto end; |
577 | 553 | ||
578 | seq_printf(seq, "gpe bit: 0x%02x\n", | 554 | seq_printf(seq, "gpe: 0x%02x\n", (u32) ec->gpe); |
579 | (u32) ec->gpe_bit); | ||
580 | seq_printf(seq, "ports: 0x%02x, 0x%02x\n", | 555 | seq_printf(seq, "ports: 0x%02x, 0x%02x\n", |
581 | (u32) ec->command_addr, | 556 | (u32) ec->command_addr, (u32) ec->data_addr); |
582 | (u32) ec->data_addr); | ||
583 | seq_printf(seq, "use global lock: %s\n", | 557 | seq_printf(seq, "use global lock: %s\n", |
584 | ec->global_lock ? "yes" : "no"); | 558 | ec->global_lock ? "yes" : "no"); |
585 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | 559 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
586 | 560 | ||
587 | end: | 561 | end: |
588 | return 0; | 562 | return 0; |
@@ -605,7 +579,6 @@ static int acpi_ec_add_fs(struct acpi_device *device) | |||
605 | { | 579 | { |
606 | struct proc_dir_entry *entry = NULL; | 580 | struct proc_dir_entry *entry = NULL; |
607 | 581 | ||
608 | |||
609 | if (!acpi_device_dir(device)) { | 582 | if (!acpi_device_dir(device)) { |
610 | acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), | 583 | acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), |
611 | acpi_ec_dir); | 584 | acpi_ec_dir); |
@@ -648,7 +621,6 @@ static int acpi_ec_add(struct acpi_device *device) | |||
648 | acpi_status status = AE_OK; | 621 | acpi_status status = AE_OK; |
649 | struct acpi_ec *ec = NULL; | 622 | struct acpi_ec *ec = NULL; |
650 | 623 | ||
651 | |||
652 | if (!device) | 624 | if (!device) |
653 | return -EINVAL; | 625 | return -EINVAL; |
654 | 626 | ||
@@ -659,7 +631,8 @@ static int acpi_ec_add(struct acpi_device *device) | |||
659 | 631 | ||
660 | ec->handle = device->handle; | 632 | ec->handle = device->handle; |
661 | ec->uid = -1; | 633 | ec->uid = -1; |
662 | init_MUTEX(&ec->sem); | 634 | mutex_init(&ec->lock); |
635 | atomic_set(&ec->query_pending, 0); | ||
663 | if (acpi_ec_mode == EC_INTR) { | 636 | if (acpi_ec_mode == EC_INTR) { |
664 | atomic_set(&ec->leaving_burst, 1); | 637 | atomic_set(&ec->leaving_burst, 1); |
665 | init_waitqueue_head(&ec->wait); | 638 | init_waitqueue_head(&ec->wait); |
@@ -669,8 +642,7 @@ static int acpi_ec_add(struct acpi_device *device) | |||
669 | acpi_driver_data(device) = ec; | 642 | acpi_driver_data(device) = ec; |
670 | 643 | ||
671 | /* Use the global lock for all EC transactions? */ | 644 | /* Use the global lock for all EC transactions? */ |
672 | acpi_evaluate_integer(ec->handle, "_GLK", NULL, | 645 | acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock); |
673 | &ec->global_lock); | ||
674 | 646 | ||
675 | /* XXX we don't test uids, because on some boxes ecdt uid = 0, see: | 647 | /* XXX we don't test uids, because on some boxes ecdt uid = 0, see: |
676 | http://bugzilla.kernel.org/show_bug.cgi?id=6111 */ | 648 | http://bugzilla.kernel.org/show_bug.cgi?id=6111 */ |
@@ -679,7 +651,7 @@ static int acpi_ec_add(struct acpi_device *device) | |||
679 | ACPI_ADR_SPACE_EC, | 651 | ACPI_ADR_SPACE_EC, |
680 | &acpi_ec_space_handler); | 652 | &acpi_ec_space_handler); |
681 | 653 | ||
682 | acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, | 654 | acpi_remove_gpe_handler(NULL, ec_ecdt->gpe, |
683 | &acpi_ec_gpe_handler); | 655 | &acpi_ec_gpe_handler); |
684 | 656 | ||
685 | kfree(ec_ecdt); | 657 | kfree(ec_ecdt); |
@@ -687,11 +659,10 @@ static int acpi_ec_add(struct acpi_device *device) | |||
687 | 659 | ||
688 | /* Get GPE bit assignment (EC events). */ | 660 | /* Get GPE bit assignment (EC events). */ |
689 | /* TODO: Add support for _GPE returning a package */ | 661 | /* TODO: Add support for _GPE returning a package */ |
690 | status = | 662 | status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe); |
691 | acpi_evaluate_integer(ec->handle, "_GPE", NULL, | ||
692 | &ec->gpe_bit); | ||
693 | if (ACPI_FAILURE(status)) { | 663 | if (ACPI_FAILURE(status)) { |
694 | ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit assignment")); | 664 | ACPI_EXCEPTION((AE_INFO, status, |
665 | "Obtaining GPE bit assignment")); | ||
695 | result = -ENODEV; | 666 | result = -ENODEV; |
696 | goto end; | 667 | goto end; |
697 | } | 668 | } |
@@ -701,13 +672,13 @@ static int acpi_ec_add(struct acpi_device *device) | |||
701 | goto end; | 672 | goto end; |
702 | 673 | ||
703 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.", | 674 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.", |
704 | acpi_device_name(device), acpi_device_bid(device), | 675 | acpi_device_name(device), acpi_device_bid(device), |
705 | (u32) ec->gpe_bit)); | 676 | (u32) ec->gpe)); |
706 | 677 | ||
707 | if (!first_ec) | 678 | if (!first_ec) |
708 | first_ec = device; | 679 | first_ec = device; |
709 | 680 | ||
710 | end: | 681 | end: |
711 | if (result) | 682 | if (result) |
712 | kfree(ec); | 683 | kfree(ec); |
713 | 684 | ||
@@ -718,7 +689,6 @@ static int acpi_ec_remove(struct acpi_device *device, int type) | |||
718 | { | 689 | { |
719 | struct acpi_ec *ec = NULL; | 690 | struct acpi_ec *ec = NULL; |
720 | 691 | ||
721 | |||
722 | if (!device) | 692 | if (!device) |
723 | return -EINVAL; | 693 | return -EINVAL; |
724 | 694 | ||
@@ -761,7 +731,6 @@ static int acpi_ec_start(struct acpi_device *device) | |||
761 | acpi_status status = AE_OK; | 731 | acpi_status status = AE_OK; |
762 | struct acpi_ec *ec = NULL; | 732 | struct acpi_ec *ec = NULL; |
763 | 733 | ||
764 | |||
765 | if (!device) | 734 | if (!device) |
766 | return -EINVAL; | 735 | return -EINVAL; |
767 | 736 | ||
@@ -782,27 +751,26 @@ static int acpi_ec_start(struct acpi_device *device) | |||
782 | } | 751 | } |
783 | 752 | ||
784 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx", | 753 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx", |
785 | ec->gpe_bit, ec->command_addr, ec->data_addr)); | 754 | ec->gpe, ec->command_addr, ec->data_addr)); |
786 | 755 | ||
787 | /* | 756 | /* |
788 | * Install GPE handler | 757 | * Install GPE handler |
789 | */ | 758 | */ |
790 | status = acpi_install_gpe_handler(NULL, ec->gpe_bit, | 759 | status = acpi_install_gpe_handler(NULL, ec->gpe, |
791 | ACPI_GPE_EDGE_TRIGGERED, | 760 | ACPI_GPE_EDGE_TRIGGERED, |
792 | &acpi_ec_gpe_handler, ec); | 761 | &acpi_ec_gpe_handler, ec); |
793 | if (ACPI_FAILURE(status)) { | 762 | if (ACPI_FAILURE(status)) { |
794 | return -ENODEV; | 763 | return -ENODEV; |
795 | } | 764 | } |
796 | acpi_set_gpe_type(NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME); | 765 | acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); |
797 | acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); | 766 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); |
798 | 767 | ||
799 | status = acpi_install_address_space_handler(ec->handle, | 768 | status = acpi_install_address_space_handler(ec->handle, |
800 | ACPI_ADR_SPACE_EC, | 769 | ACPI_ADR_SPACE_EC, |
801 | &acpi_ec_space_handler, | 770 | &acpi_ec_space_handler, |
802 | &acpi_ec_space_setup, ec); | 771 | &acpi_ec_space_setup, ec); |
803 | if (ACPI_FAILURE(status)) { | 772 | if (ACPI_FAILURE(status)) { |
804 | acpi_remove_gpe_handler(NULL, ec->gpe_bit, | 773 | acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); |
805 | &acpi_ec_gpe_handler); | ||
806 | return -ENODEV; | 774 | return -ENODEV; |
807 | } | 775 | } |
808 | 776 | ||
@@ -814,7 +782,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type) | |||
814 | acpi_status status = AE_OK; | 782 | acpi_status status = AE_OK; |
815 | struct acpi_ec *ec = NULL; | 783 | struct acpi_ec *ec = NULL; |
816 | 784 | ||
817 | |||
818 | if (!device) | 785 | if (!device) |
819 | return -EINVAL; | 786 | return -EINVAL; |
820 | 787 | ||
@@ -826,9 +793,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type) | |||
826 | if (ACPI_FAILURE(status)) | 793 | if (ACPI_FAILURE(status)) |
827 | return -ENODEV; | 794 | return -ENODEV; |
828 | 795 | ||
829 | status = | 796 | status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); |
830 | acpi_remove_gpe_handler(NULL, ec->gpe_bit, | ||
831 | &acpi_ec_gpe_handler); | ||
832 | if (ACPI_FAILURE(status)) | 797 | if (ACPI_FAILURE(status)) |
833 | return -ENODEV; | 798 | return -ENODEV; |
834 | 799 | ||
@@ -841,7 +806,7 @@ acpi_fake_ecdt_callback(acpi_handle handle, | |||
841 | { | 806 | { |
842 | acpi_status status; | 807 | acpi_status status; |
843 | 808 | ||
844 | init_MUTEX(&ec_ecdt->sem); | 809 | mutex_init(&ec_ecdt->lock); |
845 | if (acpi_ec_mode == EC_INTR) { | 810 | if (acpi_ec_mode == EC_INTR) { |
846 | init_waitqueue_head(&ec_ecdt->wait); | 811 | init_waitqueue_head(&ec_ecdt->wait); |
847 | } | 812 | } |
@@ -853,16 +818,15 @@ acpi_fake_ecdt_callback(acpi_handle handle, | |||
853 | ec_ecdt->uid = -1; | 818 | ec_ecdt->uid = -1; |
854 | acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid); | 819 | acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid); |
855 | 820 | ||
856 | status = | 821 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe); |
857 | acpi_evaluate_integer(handle, "_GPE", NULL, | ||
858 | &ec_ecdt->gpe_bit); | ||
859 | if (ACPI_FAILURE(status)) | 822 | if (ACPI_FAILURE(status)) |
860 | return status; | 823 | return status; |
861 | ec_ecdt->global_lock = TRUE; | 824 | ec_ecdt->global_lock = TRUE; |
862 | ec_ecdt->handle = handle; | 825 | ec_ecdt->handle = handle; |
863 | 826 | ||
864 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx", | 827 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx", |
865 | ec_ecdt->gpe_bit, ec_ecdt->command_addr, ec_ecdt->data_addr)); | 828 | ec_ecdt->gpe, ec_ecdt->command_addr, |
829 | ec_ecdt->data_addr)); | ||
866 | 830 | ||
867 | return AE_CTRL_TERMINATE; | 831 | return AE_CTRL_TERMINATE; |
868 | } | 832 | } |
@@ -901,7 +865,7 @@ static int __init acpi_ec_fake_ecdt(void) | |||
901 | goto error; | 865 | goto error; |
902 | } | 866 | } |
903 | return 0; | 867 | return 0; |
904 | error: | 868 | error: |
905 | return ret; | 869 | return ret; |
906 | } | 870 | } |
907 | 871 | ||
@@ -926,25 +890,24 @@ static int __init acpi_ec_get_real_ecdt(void) | |||
926 | return -ENOMEM; | 890 | return -ENOMEM; |
927 | memset(ec_ecdt, 0, sizeof(struct acpi_ec)); | 891 | memset(ec_ecdt, 0, sizeof(struct acpi_ec)); |
928 | 892 | ||
929 | init_MUTEX(&ec_ecdt->sem); | 893 | mutex_init(&ec_ecdt->lock); |
930 | if (acpi_ec_mode == EC_INTR) { | 894 | if (acpi_ec_mode == EC_INTR) { |
931 | init_waitqueue_head(&ec_ecdt->wait); | 895 | init_waitqueue_head(&ec_ecdt->wait); |
932 | } | 896 | } |
933 | ec_ecdt->command_addr = ecdt_ptr->ec_control.address; | 897 | ec_ecdt->command_addr = ecdt_ptr->ec_control.address; |
934 | ec_ecdt->data_addr = ecdt_ptr->ec_data.address; | 898 | ec_ecdt->data_addr = ecdt_ptr->ec_data.address; |
935 | ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit; | 899 | ec_ecdt->gpe = ecdt_ptr->gpe_bit; |
936 | /* use the GL just to be safe */ | 900 | /* use the GL just to be safe */ |
937 | ec_ecdt->global_lock = TRUE; | 901 | ec_ecdt->global_lock = TRUE; |
938 | ec_ecdt->uid = ecdt_ptr->uid; | 902 | ec_ecdt->uid = ecdt_ptr->uid; |
939 | 903 | ||
940 | status = | 904 | status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle); |
941 | acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle); | ||
942 | if (ACPI_FAILURE(status)) { | 905 | if (ACPI_FAILURE(status)) { |
943 | goto error; | 906 | goto error; |
944 | } | 907 | } |
945 | 908 | ||
946 | return 0; | 909 | return 0; |
947 | error: | 910 | error: |
948 | ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT")); | 911 | ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT")); |
949 | kfree(ec_ecdt); | 912 | kfree(ec_ecdt); |
950 | ec_ecdt = NULL; | 913 | ec_ecdt = NULL; |
@@ -970,14 +933,14 @@ int __init acpi_ec_ecdt_probe(void) | |||
970 | /* | 933 | /* |
971 | * Install GPE handler | 934 | * Install GPE handler |
972 | */ | 935 | */ |
973 | status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit, | 936 | status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe, |
974 | ACPI_GPE_EDGE_TRIGGERED, | 937 | ACPI_GPE_EDGE_TRIGGERED, |
975 | &acpi_ec_gpe_handler, ec_ecdt); | 938 | &acpi_ec_gpe_handler, ec_ecdt); |
976 | if (ACPI_FAILURE(status)) { | 939 | if (ACPI_FAILURE(status)) { |
977 | goto error; | 940 | goto error; |
978 | } | 941 | } |
979 | acpi_set_gpe_type(NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME); | 942 | acpi_set_gpe_type(NULL, ec_ecdt->gpe, ACPI_GPE_TYPE_RUNTIME); |
980 | acpi_enable_gpe(NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR); | 943 | acpi_enable_gpe(NULL, ec_ecdt->gpe, ACPI_NOT_ISR); |
981 | 944 | ||
982 | status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, | 945 | status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, |
983 | ACPI_ADR_SPACE_EC, | 946 | ACPI_ADR_SPACE_EC, |
@@ -985,7 +948,7 @@ int __init acpi_ec_ecdt_probe(void) | |||
985 | &acpi_ec_space_setup, | 948 | &acpi_ec_space_setup, |
986 | ec_ecdt); | 949 | ec_ecdt); |
987 | if (ACPI_FAILURE(status)) { | 950 | if (ACPI_FAILURE(status)) { |
988 | acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, | 951 | acpi_remove_gpe_handler(NULL, ec_ecdt->gpe, |
989 | &acpi_ec_gpe_handler); | 952 | &acpi_ec_gpe_handler); |
990 | goto error; | 953 | goto error; |
991 | } | 954 | } |
@@ -1004,7 +967,6 @@ static int __init acpi_ec_init(void) | |||
1004 | { | 967 | { |
1005 | int result = 0; | 968 | int result = 0; |
1006 | 969 | ||
1007 | |||
1008 | if (acpi_disabled) | 970 | if (acpi_disabled) |
1009 | return 0; | 971 | return 0; |
1010 | 972 | ||
@@ -1057,7 +1019,8 @@ static int __init acpi_ec_set_intr_mode(char *str) | |||
1057 | acpi_ec_mode = EC_POLL; | 1019 | acpi_ec_mode = EC_POLL; |
1058 | } | 1020 | } |
1059 | acpi_ec_driver.ops.add = acpi_ec_add; | 1021 | acpi_ec_driver.ops.add = acpi_ec_add; |
1060 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", intr ? "interrupt" : "polling")); | 1022 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", |
1023 | intr ? "interrupt" : "polling")); | ||
1061 | 1024 | ||
1062 | return 1; | 1025 | return 1; |
1063 | } | 1026 | } |