acpi_ec.c revision 1.41.6.8 1 /* $NetBSD: acpi_ec.c,v 1.41.6.8 2007/10/04 10:43:47 joerg 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.41.6.8 2007/10/04 10:43:47 joerg 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 <machine/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 pnp_status_t acpiec_power(device_t, pnp_request_t, void *);
118
119 static bool acpiec_parse_gpe_package(device_t, ACPI_HANDLE,
120 ACPI_HANDLE *, uint8_t *);
121
122 static void acpiec_gpe_query(void *);
123 static UINT32 acpiec_gpe_handler(void *);
124 static ACPI_STATUS acpiec_space_setup(ACPI_HANDLE, UINT32, void *, void **);
125 static ACPI_STATUS acpiec_space_handler(UINT32, ACPI_PHYSICAL_ADDRESS,
126 UINT32, ACPI_INTEGER *, void *, void *);
127
128 static void acpiec_gpe_state_maschine(device_t);
129
130 CFATTACH_DECL_NEW(acpiec, sizeof(struct acpiec_softc),
131 acpiec_match, acpiec_attach, NULL, NULL);
132
133 CFATTACH_DECL_NEW(acpiecdt, sizeof(struct acpiec_softc),
134 acpiecdt_match, acpiecdt_attach, NULL, NULL);
135
136 static device_t ec_singleton = NULL;
137 static bool acpiec_cold = false;
138
139 static bool
140 acpiecdt_find(device_t parent, ACPI_HANDLE *ec_handle,
141 bus_addr_t *cmd_reg, bus_addr_t *data_reg, uint8_t *gpebit)
142 {
143 ACPI_TABLE_ECDT *ecdt;
144 ACPI_STATUS rv;
145
146 rv = AcpiGetTable(ACPI_SIG_ECDT, 1, (ACPI_TABLE_HEADER **)&ecdt);
147 if (ACPI_FAILURE(rv))
148 return false;
149
150 if (ecdt->Control.BitWidth != 8 || ecdt->Data.BitWidth != 8) {
151 aprint_error_dev(parent,
152 "ECDT register width invalid (%d/%d)\n",
153 ecdt->Control.BitWidth, ecdt->Data.BitWidth);
154 return false;
155 }
156
157 rv = AcpiGetHandle(ACPI_ROOT_OBJECT, ecdt->Id, ec_handle);
158 if (ACPI_FAILURE(rv)) {
159 aprint_error_dev(parent,
160 "failed to look up EC object %s: %s\n",
161 ecdt->Id, AcpiFormatException(rv));
162 return false;
163 }
164
165 *cmd_reg = ecdt->Control.Address;
166 *data_reg = ecdt->Data.Address;
167 *gpebit = ecdt->Gpe;
168
169 return true;
170 }
171
172 static int
173 acpiecdt_match(device_t parent, struct cfdata *match, void *aux)
174 {
175 ACPI_HANDLE ec_handle;
176 bus_addr_t cmd_reg, data_reg;
177 uint8_t gpebit;
178
179 if (acpiecdt_find(parent, &ec_handle, &cmd_reg, &data_reg, &gpebit))
180 return 1;
181 else
182 return 0;
183 }
184
185 static void
186 acpiecdt_attach(device_t parent, device_t self, void *aux)
187 {
188 ACPI_HANDLE ec_handle;
189 bus_addr_t cmd_reg, data_reg;
190 uint8_t gpebit;
191
192 if (!acpiecdt_find(parent, &ec_handle, &cmd_reg, &data_reg, &gpebit))
193 panic("ECDT disappeared");
194
195 aprint_naive(": ACPI Embedded Controller via ECDT\n");
196 aprint_normal(": ACPI Embedded Controller via ECDT\n");
197
198 acpiec_common_attach(parent, self, ec_handle, cmd_reg, data_reg,
199 NULL, gpebit);
200 }
201
202 static int
203 acpiec_match(device_t parent, struct cfdata *match, void *aux)
204 {
205 struct acpi_attach_args *aa = aux;
206
207 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
208 return 0;
209
210 return acpi_match_hid(aa->aa_node->ad_devinfo, ec_hid);
211 }
212
213 static void
214 acpiec_attach(device_t parent, device_t self, void *aux)
215 {
216 struct acpi_attach_args *aa = aux;
217 struct acpi_resources ec_res;
218 struct acpi_io *io0, *io1;
219 ACPI_HANDLE gpe_handle;
220 uint8_t gpebit;
221 ACPI_STATUS rv;
222
223 if (ec_singleton != NULL) {
224 aprint_naive(": ACPI Embedded Controller (disabled)\n");
225 aprint_normal(": ACPI Embedded Controller (disabled)\n");
226 pnp_register(self, pnp_generic_power);
227 return;
228 }
229
230 aprint_naive(": ACPI Embedded Controller\n");
231 aprint_normal(": ACPI Embedded Controller\n");
232
233 if (!acpiec_parse_gpe_package(self, aa->aa_node->ad_handle,
234 &gpe_handle, &gpebit))
235 return;
236
237 rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
238 &ec_res, &acpi_resource_parse_ops_default);
239 if (rv != AE_OK) {
240 aprint_error_dev(self, "resource parsing failed: %s\n",
241 AcpiFormatException(rv));
242 return;
243 }
244
245 if ((io0 = acpi_res_io(&ec_res, 0)) == NULL) {
246 aprint_error_dev(self, "no data register resource\n");
247 goto free_res;
248 }
249 if ((io1 = acpi_res_io(&ec_res, 1)) == NULL) {
250 aprint_error_dev(self, "no CSR register resource\n");
251 goto free_res;
252 }
253
254 acpiec_common_attach(parent, self, aa->aa_node->ad_handle,
255 io1->ar_base, io0->ar_base, gpe_handle, gpebit);
256
257 free_res:
258 acpi_resource_cleanup(&ec_res);
259 }
260
261 static void
262 acpiec_common_attach(device_t parent, device_t self,
263 ACPI_HANDLE ec_handle, bus_addr_t cmd_reg, bus_addr_t data_reg,
264 ACPI_HANDLE gpe_handle, uint8_t gpebit)
265 {
266 struct acpiec_softc *sc = device_private(self);
267 ACPI_STATUS rv;
268 ACPI_INTEGER val;
269
270 sc->sc_ech = ec_handle;
271 sc->sc_gpeh = gpe_handle;
272 sc->sc_gpebit = gpebit;
273
274 sc->sc_state = EC_STATE_FREE;
275 mutex_init(&sc->sc_mtx, MUTEX_DRIVER, IPL_TTY);
276 mutex_init(&sc->sc_access_mtx, MUTEX_DEFAULT, IPL_NONE);
277 cv_init(&sc->sc_cv, "eccv");
278 cv_init(&sc->sc_cv_sci, "ecsci");
279
280 if (bus_space_map(sc->sc_data_st, data_reg, 1, 0,
281 &sc->sc_data_sh) != 0) {
282 aprint_error_dev(self, "unable to map data register\n");
283 return;
284 }
285
286 if (bus_space_map(sc->sc_csr_st, cmd_reg, 1, 0, &sc->sc_csr_sh) != 0) {
287 aprint_error_dev(self, "unable to map CSR register\n");
288 goto post_data_map;
289 }
290
291 rv = acpi_eval_integer(sc->sc_ech, "_GLK", &val);
292 if (rv == AE_OK) {
293 sc->sc_need_global_lock = val != 0;
294 } else if (rv != AE_NOT_FOUND) {
295 aprint_error_dev(self, "unable to evaluate _GLK: %s\n",
296 AcpiFormatException(rv));
297 goto post_csr_map;
298 } else {
299 sc->sc_need_global_lock = false;
300 }
301 if (sc->sc_need_global_lock)
302 aprint_normal_dev(self, "using global ACPI lock\n");
303
304 rv = AcpiInstallAddressSpaceHandler(sc->sc_ech, ACPI_ADR_SPACE_EC,
305 acpiec_space_handler, acpiec_space_setup, self);
306 if (rv != AE_OK) {
307 aprint_error_dev(self,
308 "unable to install address space handler: %s\n",
309 AcpiFormatException(rv));
310 goto post_csr_map;
311 }
312
313 rv = AcpiInstallGpeHandler(sc->sc_gpeh, sc->sc_gpebit,
314 ACPI_GPE_EDGE_TRIGGERED, acpiec_gpe_handler, self);
315 if (rv != AE_OK) {
316 aprint_error_dev(self, "unable to install GPE handler: %s\n",
317 AcpiFormatException(rv));
318 goto post_csr_map;
319 }
320
321 rv = AcpiSetGpeType(sc->sc_gpeh, sc->sc_gpebit, ACPI_GPE_TYPE_RUNTIME);
322 if (rv != AE_OK) {
323 aprint_error_dev(self, "unable to set GPE type: %s\n",
324 AcpiFormatException(rv));
325 goto post_csr_map;
326 }
327
328 rv = AcpiEnableGpe(sc->sc_gpeh, sc->sc_gpebit, ACPI_ISR);
329 if (rv != AE_OK) {
330 aprint_error_dev(self, "unable to enable GPE: %s\n",
331 AcpiFormatException(rv));
332 goto post_csr_map;
333 }
334
335 if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, acpiec_gpe_query,
336 self, NULL, "acpiec sci thread")) {
337 aprint_error_dev(self, "unable to create query kthread\n");
338 goto post_csr_map;
339 }
340
341 ec_singleton = self;
342
343 pnp_register(self, acpiec_power);
344
345 return;
346
347 post_csr_map:
348 (void)AcpiRemoveGpeHandler(sc->sc_gpeh, sc->sc_gpebit,
349 acpiec_gpe_handler);
350 (void)AcpiRemoveAddressSpaceHandler(sc->sc_ech,
351 ACPI_ADR_SPACE_EC, acpiec_space_handler);
352 bus_space_unmap(sc->sc_csr_st, sc->sc_csr_sh, 1);
353 post_data_map:
354 bus_space_unmap(sc->sc_data_st, sc->sc_data_sh, 1);
355 }
356
357 static pnp_status_t
358 acpiec_power(device_t dv, pnp_request_t req, void *opaque)
359 {
360 pnp_capabilities_t *pcaps;
361 pnp_state_t *pstate;
362
363 switch (req) {
364 case PNP_REQUEST_GET_CAPABILITIES:
365 pcaps = opaque;
366 pcaps->state = PNP_STATE_D0 | PNP_STATE_D3;
367 break;
368 case PNP_REQUEST_GET_STATE:
369 pstate = opaque;
370 if (acpiec_cold)
371 *pstate = PNP_STATE_D0;
372 else
373 *pstate = PNP_STATE_D3;
374 break;
375 case PNP_REQUEST_SET_STATE:
376 pstate = opaque;
377 switch (*pstate) {
378 case PNP_STATE_D0:
379 acpiec_cold = false;
380 break;
381 case PNP_STATE_D3:
382 acpiec_cold = true;
383 break;
384 default:
385 return PNP_STATUS_UNSUPPORTED;
386 }
387 break;
388 default:
389 return PNP_STATUS_UNSUPPORTED;
390 }
391
392 return PNP_STATUS_SUCCESS;
393 }
394
395 static bool
396 acpiec_parse_gpe_package(device_t self, ACPI_HANDLE ec_handle,
397 ACPI_HANDLE *gpe_handle, uint8_t *gpebit)
398 {
399 ACPI_BUFFER buf;
400 ACPI_OBJECT *p, *c;
401 ACPI_STATUS rv;
402
403 rv = acpi_eval_struct(ec_handle, "_GPE", &buf);
404 if (rv != AE_OK) {
405 aprint_error_dev(self, "unable to evaluate _GPE: %s\n",
406 AcpiFormatException(rv));
407 return false;
408 }
409
410 p = buf.Pointer;
411
412 if (p->Type == ACPI_TYPE_INTEGER) {
413 *gpe_handle = NULL;
414 *gpebit = p->Integer.Value;
415 AcpiOsFree(p);
416 return true;
417 }
418
419 if (p->Type != ACPI_TYPE_PACKAGE) {
420 aprint_error_dev(self, "_GPE is neither integer nor package\n");
421 AcpiOsFree(p);
422 return false;
423 }
424
425 if (p->Package.Count != 2) {
426 aprint_error_dev(self, "_GPE package does not contain 2 elements\n");
427 AcpiOsFree(p);
428 return false;
429 }
430
431 c = &p->Package.Elements[0];
432 switch (c->Type) {
433 case ACPI_TYPE_LOCAL_REFERENCE:
434 case ACPI_TYPE_ANY:
435 *gpe_handle = c->Reference.Handle;
436 break;
437 case ACPI_TYPE_STRING:
438 /* XXX should be using real scope here */
439 rv = AcpiGetHandle(NULL, p->String.Pointer, gpe_handle);
440 if (rv != AE_OK) {
441 aprint_error_dev(self,
442 "_GPE device reference unresolvable\n");
443 AcpiOsFree(p);
444 return false;
445 }
446 break;
447 default:
448 aprint_error_dev(self, "_GPE device reference incorrect\n");
449 AcpiOsFree(p);
450 return false;
451 }
452 c = &p->Package.Elements[1];
453 if (c->Type != ACPI_TYPE_INTEGER) {
454 aprint_error_dev(self,
455 "_GPE package needs integer as 2nd field\n");
456 AcpiOsFree(p);
457 return false;
458 }
459 *gpebit = c->Integer.Value;
460 AcpiOsFree(p);
461 return true;
462 }
463
464 static uint8_t
465 acpiec_read_data(struct acpiec_softc *sc)
466 {
467 return bus_space_read_1(sc->sc_data_st, sc->sc_data_sh, 0);
468 }
469
470 static void
471 acpiec_write_data(struct acpiec_softc *sc, uint8_t val)
472 {
473 bus_space_write_1(sc->sc_data_st, sc->sc_data_sh, 0, val);
474 }
475
476 static uint8_t
477 acpiec_read_status(struct acpiec_softc *sc)
478 {
479 return bus_space_read_1(sc->sc_csr_st, sc->sc_csr_sh, 0);
480 }
481
482 static void
483 acpiec_write_command(struct acpiec_softc *sc, uint8_t cmd)
484 {
485 bus_space_write_1(sc->sc_csr_st, sc->sc_csr_sh, 0, cmd);
486 }
487
488 static ACPI_STATUS
489 acpiec_space_setup(ACPI_HANDLE region, UINT32 func, void *arg,
490 void **region_arg)
491 {
492 if (func == ACPI_REGION_DEACTIVATE)
493 *region_arg = NULL;
494 else
495 *region_arg = arg;
496
497 return AE_OK;
498 }
499
500 static void
501 acpiec_lock(device_t dv)
502 {
503 struct acpiec_softc *sc = device_private(dv);
504 ACPI_STATUS rv;
505
506 mutex_enter(&sc->sc_access_mtx);
507
508 if (sc->sc_need_global_lock) {
509 rv = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT, &sc->sc_global_lock);
510 if (rv != AE_OK) {
511 aprint_error("%s: failed to acquire global lock (continuing)\n",
512 device_xname(dv));
513 return;
514 }
515 }
516 }
517
518 static void
519 acpiec_unlock(device_t dv)
520 {
521 struct acpiec_softc *sc = device_private(dv);
522 ACPI_STATUS rv;
523
524 if (sc->sc_need_global_lock) {
525 rv = AcpiReleaseGlobalLock(sc->sc_global_lock);
526 if (rv != AE_OK) {
527 aprint_error("%s: failed to release global lock (continuing)\n",
528 device_xname(dv));
529 }
530 }
531 mutex_exit(&sc->sc_access_mtx);
532 }
533
534 static ACPI_STATUS
535 acpiec_read(device_t dv, uint8_t addr, uint8_t *val)
536 {
537 struct acpiec_softc *sc = device_private(dv);
538 int i, timeouts = 0;
539
540 acpiec_lock(dv);
541 mutex_enter(&sc->sc_mtx);
542
543 retry:
544 sc->sc_cur_addr = addr;
545 sc->sc_state = EC_STATE_READ;
546
547 for (i = 0; i < EC_POLL_TIMEOUT; ++i) {
548 acpiec_gpe_state_maschine(dv);
549 if (sc->sc_state == EC_STATE_FREE)
550 goto done;
551 delay(1);
552 }
553
554 if (cold || acpiec_cold) {
555 while (sc->sc_state != EC_STATE_FREE) {
556 delay(1);
557 acpiec_gpe_state_maschine(dv);
558 }
559 } else while (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, hz)) {
560 mutex_exit(&sc->sc_mtx);
561 AcpiClearGpe(sc->sc_gpeh, sc->sc_gpebit, ACPI_NOT_ISR);
562 mutex_enter(&sc->sc_mtx);
563 if (++timeouts < 5)
564 goto retry;
565 mutex_exit(&sc->sc_mtx);
566 acpiec_unlock(dv);
567 aprint_error_dev(dv, "command takes over 5sec...\n");
568 return AE_ERROR;
569 }
570
571 done:
572 *val = sc->sc_cur_val;
573
574 mutex_exit(&sc->sc_mtx);
575 acpiec_unlock(dv);
576 return AE_OK;
577 }
578
579 static ACPI_STATUS
580 acpiec_write(device_t dv, uint8_t addr, uint8_t val)
581 {
582 struct acpiec_softc *sc = device_private(dv);
583 int i, timeouts = 0;
584
585 acpiec_lock(dv);
586 mutex_enter(&sc->sc_mtx);
587
588 retry:
589 sc->sc_cur_addr = addr;
590 sc->sc_cur_val = val;
591 sc->sc_state = EC_STATE_WRITE;
592
593 for (i = 0; i < EC_POLL_TIMEOUT; ++i) {
594 acpiec_gpe_state_maschine(dv);
595 if (sc->sc_state == EC_STATE_FREE)
596 goto done;
597 delay(1);
598 }
599
600 if (cold || acpiec_cold) {
601 while (sc->sc_state != EC_STATE_FREE) {
602 delay(1);
603 acpiec_gpe_state_maschine(dv);
604 }
605 } else while (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, hz)) {
606 mutex_exit(&sc->sc_mtx);
607 AcpiClearGpe(sc->sc_gpeh, sc->sc_gpebit, ACPI_NOT_ISR);
608 mutex_enter(&sc->sc_mtx);
609 if (++timeouts < 5)
610 goto retry;
611 mutex_exit(&sc->sc_mtx);
612 acpiec_unlock(dv);
613 aprint_error_dev(dv, "command takes over 5sec...\n");
614 return AE_ERROR;
615 }
616
617 done:
618 mutex_exit(&sc->sc_mtx);
619 acpiec_unlock(dv);
620 return AE_OK;
621 }
622
623 static ACPI_STATUS
624 acpiec_space_handler(UINT32 func, ACPI_PHYSICAL_ADDRESS paddr,
625 UINT32 width, ACPI_INTEGER *value, void *arg, void *region_arg)
626 {
627 device_t dv;
628 struct acpiec_softc *sc;
629 ACPI_STATUS rv;
630 uint8_t addr, reg;
631 unsigned int i;
632
633 if (paddr > 0xff || width % 8 != 0 || value == NULL || arg == NULL ||
634 paddr + width / 8 > 0xff)
635 return AE_BAD_PARAMETER;
636
637 addr = paddr;
638 dv = arg;
639 sc = device_private(dv);
640
641 rv = AE_OK;
642
643 switch (func) {
644 case ACPI_READ:
645 *value = 0;
646 for (i = 0; i < width; i += 8, ++addr) {
647 rv = acpiec_read(dv, addr, ®);
648 if (rv != AE_OK)
649 break;
650 *value |= (ACPI_INTEGER)reg << i;
651 }
652 break;
653 case ACPI_WRITE:
654 for (i = 0; i < width; i += 8, ++addr) {
655 reg = (*value >>i) & 0xff;
656 rv = acpiec_write(dv, addr, reg);
657 if (rv != AE_OK)
658 break;
659 }
660 break;
661 default:
662 aprint_error("%s: invalid Address Space function called: %x\n",
663 device_xname(dv), (unsigned int)func);
664 return AE_BAD_PARAMETER;
665 }
666
667 return rv;
668 }
669
670 static void
671 acpiec_gpe_query(void *arg)
672 {
673 device_t dv = arg;
674 struct acpiec_softc *sc = device_private(dv);
675 uint8_t reg;
676 char qxx[5];
677 ACPI_STATUS rv;
678 int i;
679
680 loop:
681 mutex_enter(&sc->sc_mtx);
682
683 if (sc->sc_got_sci == false)
684 cv_wait(&sc->sc_cv_sci, &sc->sc_mtx);
685 mutex_exit(&sc->sc_mtx);
686
687 acpiec_lock(dv);
688 mutex_enter(&sc->sc_mtx);
689
690 /* The Query command can always be issued, so be defensive here. */
691 sc->sc_got_sci = false;
692 sc->sc_state = EC_STATE_QUERY;
693
694 for (i = 0; i < EC_POLL_TIMEOUT; ++i) {
695 acpiec_gpe_state_maschine(dv);
696 if (sc->sc_state == EC_STATE_FREE)
697 goto done;
698 delay(1);
699 }
700
701 cv_wait(&sc->sc_cv, &sc->sc_mtx);
702
703 done:
704 reg = sc->sc_cur_val;
705
706 mutex_exit(&sc->sc_mtx);
707 acpiec_unlock(dv);
708
709 if (reg == 0)
710 goto loop; /* Spurious query result */
711
712 /*
713 * Evaluate _Qxx to respond to the controller.
714 */
715 snprintf(qxx, sizeof(qxx), "_Q%02X", (unsigned int)reg);
716 rv = AcpiEvaluateObject(sc->sc_ech, qxx, NULL, NULL);
717 if (rv != AE_OK && rv != AE_NOT_FOUND) {
718 aprint_error("%s: GPE query method %s failed: %s",
719 device_xname(dv), qxx, AcpiFormatException(rv));
720 }
721
722 goto loop;
723 }
724
725 static void
726 acpiec_gpe_state_maschine(device_t dv)
727 {
728 struct acpiec_softc *sc = device_private(dv);
729 uint8_t reg;
730
731 reg = acpiec_read_status(sc);
732
733 if (reg & EC_STATUS_SCI)
734 sc->sc_got_sci = true;
735
736 switch (sc->sc_state) {
737 case EC_STATE_QUERY:
738 if ((reg & EC_STATUS_IBF) != 0)
739 break; /* Nothing of interest here. */
740 acpiec_write_command(sc, EC_COMMAND_QUERY);
741 sc->sc_state = EC_STATE_QUERY_VAL;
742 break;
743
744 case EC_STATE_QUERY_VAL:
745 if ((reg & EC_STATUS_OBF) == 0)
746 break; /* Nothing of interest here. */
747
748 sc->sc_cur_val = acpiec_read_data(sc);
749 sc->sc_state = EC_STATE_FREE;
750
751 cv_signal(&sc->sc_cv);
752 break;
753
754 case EC_STATE_READ:
755 if ((reg & EC_STATUS_IBF) != 0)
756 break; /* Nothing of interest here. */
757
758 acpiec_write_command(sc, EC_COMMAND_READ);
759 sc->sc_state = EC_STATE_READ_ADDR;
760 break;
761
762 case EC_STATE_READ_ADDR:
763 if ((reg & EC_STATUS_IBF) != 0)
764 break; /* Nothing of interest here. */
765
766 acpiec_write_data(sc, sc->sc_cur_addr);
767 sc->sc_state = EC_STATE_READ_VAL;
768 break;
769
770 case EC_STATE_READ_VAL:
771 if ((reg & EC_STATUS_OBF) == 0)
772 break; /* Nothing of interest here. */
773 sc->sc_cur_val = acpiec_read_data(sc);
774 sc->sc_state = EC_STATE_FREE;
775
776 cv_signal(&sc->sc_cv);
777 break;
778
779 case EC_STATE_WRITE:
780 if ((reg & EC_STATUS_IBF) != 0)
781 break; /* Nothing of interest here. */
782
783 acpiec_write_command(sc, EC_COMMAND_WRITE);
784 sc->sc_state = EC_STATE_WRITE_ADDR;
785 break;
786
787 case EC_STATE_WRITE_ADDR:
788 if ((reg & EC_STATUS_IBF) != 0)
789 break; /* Nothing of interest here. */
790 acpiec_write_data(sc, sc->sc_cur_addr);
791 sc->sc_state = EC_STATE_WRITE_VAL;
792 break;
793
794 case EC_STATE_WRITE_VAL:
795 if ((reg & EC_STATUS_IBF) != 0)
796 break; /* Nothing of interest here. */
797 sc->sc_state = EC_STATE_FREE;
798 cv_signal(&sc->sc_cv);
799
800 acpiec_write_data(sc, sc->sc_cur_val);
801 break;
802
803 case EC_STATE_FREE:
804 if (sc->sc_got_sci)
805 cv_signal(&sc->sc_cv_sci);
806 break;
807 default:
808 panic("invalid state");
809 }
810 }
811
812 static UINT32
813 acpiec_gpe_handler(void *arg)
814 {
815 device_t dv = arg;
816 struct acpiec_softc *sc = device_private(dv);
817
818 AcpiClearGpe(sc->sc_gpeh, sc->sc_gpebit, ACPI_ISR);
819
820 mutex_enter(&sc->sc_mtx);
821 acpiec_gpe_state_maschine(dv);
822 mutex_exit(&sc->sc_mtx);
823
824 return 0;
825 }
826