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