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