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