Fix #8729.
[haiku.git] / src / add-ons / kernel / bus_managers / acpi / acpi_embedded_controller.cpp
blob9cbfbc7f088c20b3db771228c5f6cfa34dc73ed0
1 /*
2 * Copyright (c) 2009 Clemens Zeidler
3 * Copyright (c) 2003-2007 Nate Lawson
4 * Copyright (c) 2000 Michael Smith
5 * Copyright (c) 2000 BSDi
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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 the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
31 #include "acpi_embedded_controller.h"
33 #include <kernel.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
38 #include <condition_variable.h>
39 #include <Errors.h>
40 #include <KernelExport.h>
41 #include <drivers/PCI.h>
43 #include "SmallResourceData.h"
46 #define ACPI_EC_DRIVER_NAME "drivers/power/acpi_embedded_controller/driver_v1"
48 #define ACPI_EC_DEVICE_NAME "drivers/power/acpi_embedded_controller/device_v1"
50 /* Base Namespace devices are published to */
51 #define ACPI_EC_BASENAME "power/embedded_controller/%d"
53 // name of pnp generator of path ids
54 #define ACPI_EC_PATHID_GENERATOR "embedded_controller/path_id"
57 uint8
58 bus_space_read_1(int address)
60 return gPCIManager->read_io_8(address);
64 void
65 bus_space_write_1(int address, uint8 value)
67 gPCIManager->write_io_8(address, value);
71 status_t
72 acpi_GetInteger(acpi_device_module_info* acpi, acpi_device& acpiCookie,
73 const char* path, int* number)
75 acpi_data buf;
76 acpi_object_type object;
77 buf.pointer = &object;
78 buf.length = sizeof(acpi_object_type);
80 // Assume that what we've been pointed at is an Integer object, or
81 // a method that will return an Integer.
82 status_t status = acpi->evaluate_method(acpiCookie, path, NULL, &buf);
83 if (status == B_OK) {
84 if (object.object_type == ACPI_TYPE_INTEGER)
85 *number = object.data.integer;
86 else
87 status = B_BAD_VALUE;
89 return status;
93 acpi_handle
94 acpi_GetReference(acpi_module_info* acpi, acpi_handle scope,
95 acpi_object_type* obj)
97 if (obj == NULL)
98 return NULL;
100 switch (obj->object_type) {
101 case ACPI_TYPE_LOCAL_REFERENCE:
102 case ACPI_TYPE_ANY:
103 return obj->data.reference.handle;
105 case ACPI_TYPE_STRING:
107 // The String object usually contains a fully-qualified path, so
108 // scope can be NULL.
109 // TODO: This may not always be the case.
110 acpi_handle handle;
111 if (acpi->get_handle(scope, obj->data.string.string, &handle)
112 == B_OK)
113 return handle;
117 return NULL;
121 status_t
122 acpi_PkgInt(acpi_object_type* res, int idx, int* dst)
124 acpi_object_type* obj = &res->data.package.objects[idx];
125 if (obj == NULL || obj->object_type != ACPI_TYPE_INTEGER)
126 return B_BAD_VALUE;
127 *dst = obj->data.integer;
129 return B_OK;
133 status_t
134 acpi_PkgInt32(acpi_object_type* res, int idx, uint32* dst)
136 int tmp;
138 status_t status = acpi_PkgInt(res, idx, &tmp);
139 if (status == B_OK)
140 *dst = (uint32) tmp;
142 return status;
146 // #pragma mark -
149 static status_t
150 embedded_controller_open(void* initCookie, const char* path, int flags,
151 void** cookie)
153 acpi_ec_cookie* device = (acpi_ec_cookie*) initCookie;
154 *cookie = device;
156 return B_OK;
160 static status_t
161 embedded_controller_close(void* cookie)
163 return B_OK;
167 static status_t
168 embedded_controller_read(void* _cookie, off_t position, void* buffer,
169 size_t* numBytes)
171 return B_IO_ERROR;
175 static status_t
176 embedded_controller_write(void* cookie, off_t position, const void* buffer,
177 size_t* numBytes)
179 return B_IO_ERROR;
183 status_t
184 embedded_controller_control(void* _cookie, uint32 op, void* arg, size_t len)
186 return B_ERROR;
190 static status_t
191 embedded_controller_free(void* cookie)
193 return B_OK;
197 // #pragma mark - driver module API
200 static int32
201 acpi_get_type(device_node* dev)
203 const char *bus;
204 if (gDeviceManager->get_attr_string(dev, B_DEVICE_BUS, &bus, false))
205 return -1;
207 if (strcmp(bus, "acpi"))
208 return -1;
210 uint32 deviceType;
211 if (gDeviceManager->get_attr_uint32(dev, ACPI_DEVICE_TYPE_ITEM,
212 &deviceType, false) != B_OK)
213 return -1;
215 return deviceType;
219 static float
220 embedded_controller_support(device_node* dev)
222 TRACE("embedded_controller_support()\n");
224 // Check that this is a device
225 if (acpi_get_type(dev) != ACPI_TYPE_DEVICE)
226 return 0.0;
228 const char* name;
229 if (gDeviceManager->get_attr_string(dev, ACPI_DEVICE_HID_ITEM, &name, false)
230 != B_OK)
231 return 0.0;
233 // Test all known IDs
235 static const char* kEmbeddedControllerIDs[] = { "PNP0C09" };
237 for (size_t i = 0; i < sizeof(kEmbeddedControllerIDs)
238 / sizeof(kEmbeddedControllerIDs[0]); i++) {
239 if (!strcmp(name, kEmbeddedControllerIDs[i])) {
240 TRACE("supported device found %s\n", name);
241 return 0.6;
245 return 0.0;
249 static status_t
250 embedded_controller_register_device(device_node* node)
252 device_attr attrs[] = {
253 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
254 { string: "ACPI embedded controller" }},
255 { NULL }
258 return gDeviceManager->register_node(node, ACPI_EC_DRIVER_NAME, attrs,
259 NULL, NULL);
263 static status_t
264 embedded_controller_init_driver(device_node* dev, void** _driverCookie)
266 TRACE("init driver\n");
268 acpi_ec_cookie* sc;
269 sc = (acpi_ec_cookie*)malloc(sizeof(acpi_ec_cookie));
270 if (sc == NULL)
271 return B_NO_MEMORY;
273 memset(sc, 0, sizeof(acpi_ec_cookie));
275 *_driverCookie = sc;
276 sc->ec_dev = dev;
278 sc->ec_condition_var.Init(NULL, "ec condition variable");
279 mutex_init(&sc->ec_lock, "ec lock");
280 device_node* parent = gDeviceManager->get_parent_node(dev);
281 gDeviceManager->get_driver(parent, (driver_module_info**)&sc->ec_acpi,
282 (void**)&sc->ec_handle);
283 gDeviceManager->put_node(parent);
285 SmallResourceData resourceData(sc->ec_acpi, sc->ec_handle, "_CRS");
286 if (resourceData.InitCheck() != B_OK) {
287 TRACE("failed to read _CRS resource\n") ;
288 return B_ERROR;
290 io_port portData;
292 if (get_module(B_ACPI_MODULE_NAME, (module_info**)&sc->ec_acpi_module)
293 != B_OK)
294 return B_ERROR;
296 acpi_data buf;
297 buf.pointer = NULL;
298 buf.length = ACPI_ALLOCATE_BUFFER;
300 // Read the unit ID to check for duplicate attach and the
301 // global lock value to see if we should acquire it when
302 // accessing the EC.
303 status_t status = acpi_GetInteger(sc->ec_acpi, sc->ec_handle, "_UID",
304 &sc->ec_uid);
305 if (status != B_OK)
306 sc->ec_uid = 0;
307 status = acpi_GetInteger(sc->ec_acpi, sc->ec_handle, "_GLK", &sc->ec_glk);
308 if (status != B_OK)
309 sc->ec_glk = 0;
311 // Evaluate the _GPE method to find the GPE bit used by the EC to
312 // signal status (SCI). If it's a package, it contains a reference
313 // and GPE bit, similar to _PRW.
314 status = sc->ec_acpi->evaluate_method(sc->ec_handle, "_GPE", NULL, &buf);
315 if (status != B_OK) {
316 TRACE("can't evaluate _GPE\n");
317 goto error;
320 acpi_object_type* obj;
321 obj = (acpi_object_type*)buf.pointer;
322 if (obj == NULL)
323 goto error;
325 switch (obj->object_type) {
326 case ACPI_TYPE_INTEGER:
327 sc->ec_gpehandle = NULL;
328 sc->ec_gpebit = obj->data.integer;
329 break;
330 case ACPI_TYPE_PACKAGE:
331 if (!ACPI_PKG_VALID(obj, 2))
332 goto error;
333 sc->ec_gpehandle = acpi_GetReference(sc->ec_acpi_module, NULL,
334 &obj->data.package.objects[0]);
335 if (sc->ec_gpehandle == NULL
336 || acpi_PkgInt32(obj, 1, (uint32*)&sc->ec_gpebit) != B_OK)
337 goto error;
338 break;
339 default:
340 TRACE("_GPE has invalid type %i\n", int(obj->object_type));
341 goto error;
344 sc->ec_suspending = FALSE;
346 // Attach bus resources for data and command/status ports.
347 if (resourceData.ReadIOPort(&portData) != B_OK)
348 goto error;
350 sc->ec_data_pci_address = portData.minimumBase;
352 if (resourceData.ReadIOPort(&portData) != B_OK)
353 goto error;
355 sc->ec_csr_pci_address = portData.minimumBase;
357 // Install a handler for this EC's GPE bit. We want edge-triggered
358 // behavior.
359 TRACE("attaching GPE handler\n");
360 status = sc->ec_acpi_module->install_gpe_handler(sc->ec_gpehandle,
361 sc->ec_gpebit, ACPI_GPE_EDGE_TRIGGERED, &EcGpeHandler, sc);
362 if (status != B_OK) {
363 TRACE("can't install ec GPE handler\n");
364 goto error;
367 // Install address space handler
368 TRACE("attaching address space handler\n");
369 status = sc->ec_acpi->install_address_space_handler(sc->ec_handle,
370 ACPI_ADR_SPACE_EC, &EcSpaceHandler, &EcSpaceSetup, sc);
371 if (status != B_OK) {
372 TRACE("can't install address space handler\n");
373 goto error;
376 // Enable runtime GPEs for the handler.
377 status = sc->ec_acpi_module->enable_gpe(sc->ec_gpehandle, sc->ec_gpebit);
378 if (status != B_OK) {
379 TRACE("AcpiEnableGpe failed.\n");
380 goto error;
383 return 0;
385 error:
386 free(buf.pointer);
388 sc->ec_acpi_module->remove_gpe_handler(sc->ec_gpehandle, sc->ec_gpebit,
389 &EcGpeHandler);
390 sc->ec_acpi->remove_address_space_handler(sc->ec_handle, ACPI_ADR_SPACE_EC,
391 EcSpaceHandler);
393 return ENXIO;
397 static void
398 embedded_controller_uninit_driver(void* driverCookie)
400 acpi_ec_cookie* sc = (struct acpi_ec_cookie*)driverCookie;
401 mutex_destroy(&sc->ec_lock);
402 free(sc);
403 put_module(B_ACPI_MODULE_NAME);
407 static status_t
408 embedded_controller_register_child_devices(void* _cookie)
410 device_node* node = ((acpi_ec_cookie*)_cookie)->ec_dev;
412 int pathID = gDeviceManager->create_id(ACPI_EC_PATHID_GENERATOR);
413 if (pathID < 0) {
414 TRACE("register_child_device couldn't create a path_id\n");
415 return B_ERROR;
418 char name[128];
419 snprintf(name, sizeof(name), ACPI_EC_BASENAME, pathID);
421 return gDeviceManager->publish_device(node, name, ACPI_EC_DEVICE_NAME);
425 static status_t
426 embedded_controller_init_device(void* driverCookie, void** cookie)
428 return B_ERROR;
432 static void
433 embedded_controller_uninit_device(void* _cookie)
435 acpi_ec_cookie* device = (acpi_ec_cookie*)_cookie;
436 free(device);
440 driver_module_info embedded_controller_driver_module = {
442 ACPI_EC_DRIVER_NAME,
444 NULL
447 embedded_controller_support,
448 embedded_controller_register_device,
449 embedded_controller_init_driver,
450 embedded_controller_uninit_driver,
451 embedded_controller_register_child_devices,
452 NULL, // rescan
453 NULL, // removed
457 struct device_module_info embedded_controller_device_module = {
459 ACPI_EC_DEVICE_NAME,
461 NULL
464 embedded_controller_init_device,
465 embedded_controller_uninit_device,
466 NULL,
468 embedded_controller_open,
469 embedded_controller_close,
470 embedded_controller_free,
471 embedded_controller_read,
472 embedded_controller_write,
473 NULL,
474 embedded_controller_control,
476 NULL,
477 NULL
481 // #pragma mark -
484 static acpi_status
485 EcCheckStatus(struct acpi_ec_cookie* sc, const char* msg, EC_EVENT event)
487 acpi_status status = AE_NO_HARDWARE_RESPONSE;
488 EC_STATUS ec_status = EC_GET_CSR(sc);
490 if (sc->ec_burstactive && !(ec_status & EC_FLAG_BURST_MODE)) {
491 TRACE("burst disabled in waitevent (%s)\n", msg);
492 sc->ec_burstactive = false;
494 if (EVENT_READY(event, ec_status)) {
495 TRACE("%s wait ready, status %#x\n", msg, ec_status);
496 status = AE_OK;
498 return status;
502 static void
503 EcGpeQueryHandler(void* context)
505 struct acpi_ec_cookie* sc = (struct acpi_ec_cookie*)context;
507 ASSERT(context != NULL);
509 // Serialize user access with EcSpaceHandler().
510 status_t status = EcLock(sc);
511 if (status != B_OK) {
512 TRACE("GpeQuery lock error.\n");
513 return;
516 // Send a query command to the EC to find out which _Qxx call it
517 // wants to make. This command clears the SCI bit and also the
518 // interrupt source since we are edge-triggered. To prevent the GPE
519 // that may arise from running the query from causing another query
520 // to be queued, we clear the pending flag only after running it.
521 int sci_enqueued = sc->ec_sci_pending;
522 acpi_status acpi_status;
523 for (uint8 retry = 0; retry < 2; retry++) {
524 acpi_status = EcCommand(sc, EC_COMMAND_QUERY);
525 if (acpi_status == AE_OK)
526 break;
527 if (EcCheckStatus(sc, "retr_check",
528 EC_EVENT_INPUT_BUFFER_EMPTY) != AE_OK)
529 break;
532 sc->ec_sci_pending = FALSE;
533 if (acpi_status != AE_OK) {
534 EcUnlock(sc);
535 TRACE("GPE query failed.\n");
536 return;
538 uint8 data = EC_GET_DATA(sc);
540 // We have to unlock before running the _Qxx method below since that
541 // method may attempt to read/write from EC address space, causing
542 // recursive acquisition of the lock.
543 EcUnlock(sc);
545 // Ignore the value for "no outstanding event". (13.3.5)
546 TRACE("query ok,%s running _Q%02X\n", data ? "" : " not", data);
547 if (data == 0)
548 return;
550 // Evaluate _Qxx to respond to the controller.
551 char qxx[5];
552 snprintf(qxx, sizeof(qxx), "_Q%02X", data);
553 AcpiUtStrupr(qxx);
554 status = sc->ec_acpi->evaluate_method(sc->ec_handle, qxx, NULL, NULL);
555 if (status != B_OK) {
556 TRACE("evaluation of query method %s failed\n", qxx);
559 // Reenable runtime GPE if its execution was deferred.
560 if (sci_enqueued) {
561 status = sc->ec_acpi_module->finish_gpe(sc->ec_gpehandle, sc->ec_gpebit);
562 if (status != B_OK)
563 ERROR("reenabling runtime GPE failed.\n");
569 /*! The GPE handler is called when IBE/OBF or SCI events occur. We are
570 called from an unknown lock context.
572 static uint32
573 EcGpeHandler(acpi_handle gpeDevice, uint32 gpeNumber, void* context)
575 struct acpi_ec_cookie* sc = (acpi_ec_cookie*)context;
577 ASSERT(context != NULL);//, ("EcGpeHandler called with NULL"));
578 TRACE("gpe handler start\n");
580 // Notify EcWaitEvent() that the status register is now fresh. If we
581 // didn't do this, it wouldn't be possible to distinguish an old IBE
582 // from a new one, for example when doing a write transaction (writing
583 // address and then data values.)
584 atomic_add(&sc->ec_gencount, 1);
585 sc->ec_condition_var.NotifyAll();
587 // If the EC_SCI bit of the status register is set, queue a query handler.
588 // It will run the query and _Qxx method later, under the lock.
589 EC_STATUS ecStatus = EC_GET_CSR(sc);
590 if ((ecStatus & EC_EVENT_SCI) && !sc->ec_sci_pending) {
591 TRACE("gpe queueing query handler\n");
592 acpi_status status = AcpiOsExecute(OSL_GPE_HANDLER, EcGpeQueryHandler,
593 context);
594 if (status == AE_OK)
595 sc->ec_sci_pending = TRUE;
596 else
597 dprintf("EcGpeHandler: queuing GPE query handler failed\n");
599 return B_INVOKE_SCHEDULER;
603 static acpi_status
604 EcSpaceSetup(acpi_handle region, uint32 function, void* context,
605 void** regionContext)
607 // If deactivating a region, always set the output to NULL. Otherwise,
608 // just pass the context through.
609 if (function == ACPI_REGION_DEACTIVATE)
610 *regionContext = NULL;
611 else
612 *regionContext = context;
614 return AE_OK;
618 static acpi_status
619 EcSpaceHandler(uint32 function, acpi_physical_address address, uint32 width,
620 int* value, void* context, void* regionContext)
622 TRACE("enter EcSpaceHandler\n");
623 struct acpi_ec_cookie* sc = (struct acpi_ec_cookie*)context;
625 if (function != ACPI_READ && function != ACPI_WRITE) return AE_BAD_PARAMETER;
626 if (width % 8 != 0 || value == NULL || context == NULL)
627 return AE_BAD_PARAMETER;
628 if (address + width / 8 > 256)
629 return AE_BAD_ADDRESS;
631 // If booting, check if we need to run the query handler. If so, we
632 // we call it directly here as scheduling and dpc might not be up yet.
633 // (Not sure if it's needed)
635 if (gKernelStartup || gKernelShutdown || sc->ec_suspending) {
636 if ((EC_GET_CSR(sc) & EC_EVENT_SCI)) {
637 //CTR0(KTR_ACPI, "ec running gpe handler directly");
638 EcGpeQueryHandler(sc);
642 // Serialize with EcGpeQueryHandler() at transaction granularity.
643 acpi_status status = EcLock(sc);
644 if (status != B_OK)
645 return AE_NOT_ACQUIRED;
647 // If we can't start burst mode, continue anyway.
648 status = EcCommand(sc, EC_COMMAND_BURST_ENABLE);
649 if (status == B_OK) {
650 if (EC_GET_DATA(sc) == EC_BURST_ACK) {
651 TRACE("burst enabled.\n");
652 sc->ec_burstactive = TRUE;
656 // Perform the transaction(s), based on width.
657 acpi_physical_address ecAddr = address;
658 uint8* ecData = (uint8 *) value;
659 if (function == ACPI_READ)
660 *value = 0;
661 do {
662 switch (function) {
663 case ACPI_READ:
664 status = EcRead(sc, ecAddr, ecData);
665 break;
666 case ACPI_WRITE:
667 status = EcWrite(sc, ecAddr, *ecData);
668 break;
670 if (status != AE_OK)
671 break;
672 ecAddr++;
673 ecData++;
674 } while (ecAddr < address + width / 8);
676 if (sc->ec_burstactive) {
677 sc->ec_burstactive = FALSE;
678 if (EcCommand(sc, EC_COMMAND_BURST_DISABLE) == AE_OK)
679 TRACE("disabled burst ok.");
682 EcUnlock(sc);
683 return status;
687 static acpi_status
688 EcWaitEvent(struct acpi_ec_cookie* sc, EC_EVENT event, int32 generationCount)
690 acpi_status status = AE_NO_HARDWARE_RESPONSE;
691 int32 count, i;
693 // int need_poll = cold || rebooting || ec_polled_mode || sc->ec_suspending;
694 int needPoll = ec_polled_mode || sc->ec_suspending || gKernelStartup || gKernelShutdown;
696 // Wait for event by polling or GPE (interrupt).
697 // be "not ready" when we start waiting. But if the main CPU is really
698 // slow, it's possible we see the current "ready" response. Since that
699 // can't be distinguished from the previous response in polled mode,
700 // this is a potential issue. We really should have interrupts enabled
701 // during boot so there is no ambiguity in polled mode.
703 // If this occurs, we add an additional delay before actually entering
704 // the status checking loop, hopefully to allow the EC to go to work
705 // and produce a non-stale status.
706 if (needPoll) {
707 static int once;
709 if (EcCheckStatus(sc, "pre-check", event) == B_OK) {
710 if (!once) {
711 TRACE("warning: EC done before starting event wait\n");
712 once = 1;
714 spin(10);
718 // Wait for event by polling or GPE (interrupt).
719 if (needPoll) {
720 count = (ec_timeout * 1000) / EC_POLL_DELAY;
721 if (count == 0)
722 count = 1;
723 for (i = 0; i < count; i++) {
724 status = EcCheckStatus(sc, "poll", event);
725 if (status == AE_OK)
726 break;
727 spin(EC_POLL_DELAY);
729 } else {
730 bigtime_t sleepInterval = system_time() + ec_timeout * 1000;
732 // Wait for the GPE to signal the status changed, checking the
733 // status register each time we get one. It's possible to get a
734 // GPE for an event we're not interested in here (i.e., SCI for
735 // EC query).
736 status_t waitStatus = B_NO_ERROR;
737 while (waitStatus != B_TIMED_OUT) {
738 if (generationCount != sc->ec_gencount) {
739 // Record new generation count. It's possible the GPE was
740 // just to notify us that a query is needed and we need to
741 // wait for a second GPE to signal the completion of the
742 // event we are actually waiting for.
743 generationCount = sc->ec_gencount;
744 status = EcCheckStatus(sc, "sleep", event);
745 if (status == AE_OK)
746 break;
748 waitStatus = sc->ec_condition_var.Wait(B_ABSOLUTE_TIMEOUT,
749 sleepInterval);
752 // We finished waiting for the GPE and it never arrived. Try to
753 // read the register once and trust whatever value we got. This is
754 // the best we can do at this point.
755 // since this system doesn't appear to generate GPEs.
756 if (status != AE_OK) {
757 status = EcCheckStatus(sc, "sleep_end", event);
758 TRACE("wait timed out (%sresponse), forcing polled mode\n",
759 status == AE_OK ? "" : "no ");
760 ec_polled_mode = TRUE;
765 if (status != AE_OK)
766 TRACE("error: ec wait timed out\n");
768 return status;
772 static acpi_status
773 EcCommand(struct acpi_ec_cookie* sc, EC_COMMAND cmd)
775 // Don't use burst mode if user disabled it.
776 if (!ec_burst_mode && cmd == EC_COMMAND_BURST_ENABLE)
777 return AE_ERROR;
779 // Decide what to wait for based on command type.
780 EC_EVENT event;
781 switch (cmd) {
782 case EC_COMMAND_READ:
783 case EC_COMMAND_WRITE:
784 case EC_COMMAND_BURST_DISABLE:
785 event = EC_EVENT_INPUT_BUFFER_EMPTY;
786 break;
787 case EC_COMMAND_QUERY:
788 case EC_COMMAND_BURST_ENABLE:
789 event = EC_EVENT_OUTPUT_BUFFER_FULL;
790 break;
791 default:
792 TRACE("EcCommand: invalid command %#x\n", cmd);
793 return AE_BAD_PARAMETER;
796 // Ensure empty input buffer before issuing command.
797 // Use generation count of zero to force a quick check.
798 acpi_status status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, 0);
799 if (status != AE_OK)
800 return status;
802 // Run the command and wait for the chosen event.
803 TRACE("running command %#x\n", cmd);
804 int32 generationCount = sc->ec_gencount;
805 EC_SET_CSR(sc, cmd);
806 status = EcWaitEvent(sc, event, generationCount);
807 if (status == AE_OK) {
808 // If we succeeded, burst flag should now be present.
809 if (cmd == EC_COMMAND_BURST_ENABLE) {
810 EC_STATUS ec_status = EC_GET_CSR(sc);
811 if ((ec_status & EC_FLAG_BURST_MODE) == 0)
812 status = AE_ERROR;
814 } else
815 TRACE("EcCommand: no response to %#x\n", cmd);
817 return status;
821 static acpi_status
822 EcRead(struct acpi_ec_cookie* sc, uint8 address, uint8* readData)
824 TRACE("read from %#x\n", address);
826 acpi_status status;
827 for (uint8 retry = 0; retry < 2; retry++) {
828 status = EcCommand(sc, EC_COMMAND_READ);
829 if (status != AE_OK)
830 return status;
832 int32 generationCount = sc->ec_gencount;
833 EC_SET_DATA(sc, address);
834 status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL, generationCount);
835 if (status != AE_OK) {
836 if (EcCheckStatus(sc, "retr_check",
837 EC_EVENT_INPUT_BUFFER_EMPTY) == AE_OK)
838 continue;
839 else
840 break;
842 *readData = EC_GET_DATA(sc);
843 return AE_OK;
846 TRACE("EcRead: failed waiting to get data\n");
847 return status;
851 static acpi_status
852 EcWrite(struct acpi_ec_cookie* sc, uint8 address, uint8 writeData)
854 acpi_status status = EcCommand(sc, EC_COMMAND_WRITE);
855 if (status != AE_OK)
856 return status;
858 int32 generationCount = sc->ec_gencount;
859 EC_SET_DATA(sc, address);
860 status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, generationCount);
861 if (status != AE_OK) {
862 TRACE("EcWrite: failed waiting for sent address\n");
863 return status;
866 generationCount = sc->ec_gencount;
867 EC_SET_DATA(sc, writeData);
868 status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, generationCount);
869 if (status != AE_OK) {
870 TRACE("EcWrite: failed waiting for sent data\n");
871 return status;
874 return AE_OK;