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.
7 *
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.
16 *
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.
28 */
29
30
31#include "EmbeddedController.h"
32
33#include <kernel.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38#include <condition_variable.h>
39#include <Errors.h>
40#include <KernelExport.h>
41#include <drivers/PCI.h>
42
43#include "SmallResourceData.h"
44
45
46#define ACPI_EC_DRIVER_NAME "drivers/power/acpi_embedded_controller/driver_v1"
47
48#define ACPI_EC_DEVICE_NAME "drivers/power/acpi_embedded_controller/device_v1"
49
50/* Base Namespace devices are published to */
51#define ACPI_EC_BASENAME "power/embedded_controller/%d"
52
53// name of pnp generator of path ids
54#define ACPI_EC_PATHID_GENERATOR "embedded_controller/path_id"
55
56
57uint8
58bus_space_read_1(int address)
59{
60	return gPCIManager->read_io_8(address);
61}
62
63
64void
65bus_space_write_1(int address, uint8 value)
66{
67	gPCIManager->write_io_8(address, value);
68}
69
70
71status_t
72acpi_GetInteger(acpi_device_module_info* acpi, acpi_device& acpiCookie,
73	const char* path, int* number)
74{
75	acpi_data buf;
76	acpi_object_type object;
77	buf.pointer = &object;
78	buf.length = sizeof(acpi_object_type);
79
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;
88	}
89	return status;
90}
91
92
93acpi_handle
94acpi_GetReference(acpi_module_info* acpi, acpi_handle scope,
95	acpi_object_type* obj)
96{
97	if (obj == NULL)
98		return NULL;
99
100	switch (obj->object_type) {
101		case ACPI_TYPE_LOCAL_REFERENCE:
102		case ACPI_TYPE_ANY:
103			return obj->data.reference.handle;
104
105		case ACPI_TYPE_STRING:
106		{
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;
114		}
115	}
116
117	return NULL;
118}
119
120
121status_t
122acpi_PkgInt(acpi_object_type* res, int idx, int* dst)
123{
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;
128
129	return B_OK;
130}
131
132
133status_t
134acpi_PkgInt32(acpi_object_type* res, int idx, uint32* dst)
135{
136	int tmp;
137
138	status_t status = acpi_PkgInt(res, idx, &tmp);
139	if (status == B_OK)
140		*dst = (uint32) tmp;
141
142	return status;
143}
144
145
146// #pragma mark -
147
148
149static status_t
150embedded_controller_open(void* initCookie, const char* path, int flags,
151	void** cookie)
152{
153	acpi_ec_cookie* device = (acpi_ec_cookie*) initCookie;
154	*cookie = device;
155
156	return B_OK;
157}
158
159
160static status_t
161embedded_controller_close(void* cookie)
162{
163	return B_OK;
164}
165
166
167static status_t
168embedded_controller_read(void* _cookie, off_t position, void* buffer,
169	size_t* numBytes)
170{
171	return B_IO_ERROR;
172}
173
174
175static status_t
176embedded_controller_write(void* cookie, off_t position, const void* buffer,
177	size_t* numBytes)
178{
179	return B_IO_ERROR;
180}
181
182
183status_t
184embedded_controller_control(void* _cookie, uint32 op, void* arg, size_t len)
185{
186	return B_ERROR;
187}
188
189
190static status_t
191embedded_controller_free(void* cookie)
192{
193	return B_OK;
194}
195
196
197//	#pragma mark - driver module API
198
199
200static int32
201acpi_get_type(device_node* dev)
202{
203	const char *bus;
204	if (gDeviceManager->get_attr_string(dev, B_DEVICE_BUS, &bus, false))
205		return -1;
206
207	if (strcmp(bus, "acpi"))
208		return -1;
209
210	uint32 deviceType;
211	if (gDeviceManager->get_attr_uint32(dev, ACPI_DEVICE_TYPE_ITEM,
212			&deviceType, false) != B_OK)
213		return -1;
214
215	return deviceType;
216}
217
218
219static float
220embedded_controller_support(device_node* dev)
221{
222	TRACE("embedded_controller_support()\n");
223
224	// Check that this is a device
225	if (acpi_get_type(dev) != ACPI_TYPE_DEVICE)
226		return 0.0;
227
228	const char* name;
229	if (gDeviceManager->get_attr_string(dev, ACPI_DEVICE_HID_ITEM, &name, false)
230			!= B_OK)
231		return 0.0;
232
233	// Test all known IDs
234
235	static const char* kEmbeddedControllerIDs[] = { "PNP0C09" };
236
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;
242		}
243	}
244
245	return 0.0;
246}
247
248
249static status_t
250embedded_controller_register_device(device_node* node)
251{
252	device_attr attrs[] = {
253		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
254			{ string: "ACPI embedded controller" }},
255		{ NULL }
256	};
257
258	return gDeviceManager->register_node(node, ACPI_EC_DRIVER_NAME, attrs,
259		NULL, NULL);
260}
261
262
263static status_t
264embedded_controller_init_driver(device_node* dev, void** _driverCookie)
265{
266	TRACE("init driver\n");
267
268	acpi_ec_cookie* sc;
269	sc = (acpi_ec_cookie*)malloc(sizeof(acpi_ec_cookie));
270	if (sc == NULL)
271		return B_NO_MEMORY;
272
273	memset(sc, 0, sizeof(acpi_ec_cookie));
274
275	*_driverCookie = sc;
276	sc->ec_dev = dev;
277
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);
284
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;
289	}
290	io_port portData;
291
292	if (get_module(B_ACPI_MODULE_NAME, (module_info**)&sc->ec_acpi_module)
293			!= B_OK)
294		return B_ERROR;
295
296	acpi_data buf;
297	buf.pointer = NULL;
298	buf.length = ACPI_ALLOCATE_BUFFER;
299
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;
310
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;
318	}
319
320	acpi_object_type* obj;
321	obj = (acpi_object_type*)buf.pointer;
322	if (obj == NULL)
323		goto error;
324
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;
342	}
343
344	sc->ec_suspending = FALSE;
345
346	// Attach bus resources for data and command/status ports.
347	if (resourceData.ReadIOPort(&portData) != B_OK)
348		goto error;
349
350	sc->ec_data_pci_address = portData.minimumBase;
351
352	if (resourceData.ReadIOPort(&portData) != B_OK)
353		goto error;
354
355	sc->ec_csr_pci_address = portData.minimumBase;
356
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;
365	}
366
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;
374	}
375
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;
381	}
382
383	return 0;
384
385error:
386	free(buf.pointer);
387
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);
392
393	return ENXIO;
394}
395
396
397static void
398embedded_controller_uninit_driver(void* driverCookie)
399{
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);
404}
405
406
407static status_t
408embedded_controller_register_child_devices(void* _cookie)
409{
410	device_node* node = ((acpi_ec_cookie*)_cookie)->ec_dev;
411
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;
416	}
417
418	char name[128];
419	snprintf(name, sizeof(name), ACPI_EC_BASENAME, pathID);
420
421	return gDeviceManager->publish_device(node, name, ACPI_EC_DEVICE_NAME);
422}
423
424
425static status_t
426embedded_controller_init_device(void* driverCookie, void** cookie)
427{
428	return B_ERROR;
429}
430
431
432static void
433embedded_controller_uninit_device(void* _cookie)
434{
435	acpi_ec_cookie* device = (acpi_ec_cookie*)_cookie;
436	free(device);
437}
438
439
440driver_module_info embedded_controller_driver_module = {
441	{
442		ACPI_EC_DRIVER_NAME,
443		0,
444		NULL
445	},
446
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
454};
455
456
457struct device_module_info embedded_controller_device_module = {
458	{
459		ACPI_EC_DEVICE_NAME,
460		0,
461		NULL
462	},
463
464	embedded_controller_init_device,
465	embedded_controller_uninit_device,
466	NULL,
467
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,
475
476	NULL,
477	NULL
478};
479
480
481// #pragma mark -
482
483
484static acpi_status
485EcCheckStatus(struct acpi_ec_cookie* sc, const char* msg, EC_EVENT event)
486{
487	acpi_status status = AE_NO_HARDWARE_RESPONSE;
488	EC_STATUS ec_status = EC_GET_CSR(sc);
489
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;
493	}
494	if (EVENT_READY(event, ec_status)) {
495		TRACE("%s wait ready, status %#x\n", msg, ec_status);
496		status = AE_OK;
497	}
498	return status;
499}
500
501
502static void
503EcGpeQueryHandler(void* context)
504{
505	struct acpi_ec_cookie* sc = (struct acpi_ec_cookie*)context;
506
507	ASSERT(context != NULL);
508
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;
514	}
515
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;
530	}
531
532	sc->ec_sci_pending = FALSE;
533	if (acpi_status != AE_OK) {
534		EcUnlock(sc);
535		TRACE("GPE query failed.\n");
536		return;
537	}
538	uint8 data = EC_GET_DATA(sc);
539
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);
544
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;
549
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);
557	}
558
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");
564	}
565
566}
567
568
569/*!	The GPE handler is called when IBE/OBF or SCI events occur.  We are
570	called from an unknown lock context.
571*/
572static uint32
573EcGpeHandler(acpi_handle gpeDevice, uint32 gpeNumber, void* context)
574{
575	struct acpi_ec_cookie* sc = (acpi_ec_cookie*)context;
576
577	ASSERT(context != NULL);//, ("EcGpeHandler called with NULL"));
578	TRACE("gpe handler start\n");
579
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();
586
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");
598	}
599	return B_INVOKE_SCHEDULER;
600}
601
602
603static acpi_status
604EcSpaceSetup(acpi_handle region, uint32 function, void* context,
605	void** regionContext)
606{
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;
613
614	return AE_OK;
615}
616
617
618static acpi_status
619EcSpaceHandler(uint32 function, acpi_physical_address address, uint32 width,
620	int* value, void* context, void* regionContext)
621{
622	TRACE("enter EcSpaceHandler\n");
623	struct acpi_ec_cookie* sc = (struct acpi_ec_cookie*)context;
624
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;
630
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)
634
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);
639		}
640	}
641
642	// Serialize with EcGpeQueryHandler() at transaction granularity.
643	acpi_status status = EcLock(sc);
644	if (status != B_OK)
645		return AE_NOT_ACQUIRED;
646
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;
653		}
654	}
655
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;
669		}
670		if (status != AE_OK)
671			break;
672		ecAddr++;
673		ecData++;
674	} while (ecAddr < address + width / 8);
675
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.");
680	}
681
682	EcUnlock(sc);
683	return status;
684}
685
686
687static acpi_status
688EcWaitEvent(struct acpi_ec_cookie* sc, EC_EVENT event, int32 generationCount)
689{
690	acpi_status status = AE_NO_HARDWARE_RESPONSE;
691	int32 count, i;
692
693	// int need_poll = cold || rebooting || ec_polled_mode || sc->ec_suspending;
694	int needPoll = ec_polled_mode || sc->ec_suspending || gKernelStartup || gKernelShutdown;
695
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.
702	//
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;
708
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;
713			}
714			spin(10);
715		}
716	}
717
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);
728		}
729	} else {
730		bigtime_t sleepInterval = system_time() + ec_timeout * 1000;
731
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;
747			}
748			waitStatus = sc->ec_condition_var.Wait(B_ABSOLUTE_TIMEOUT,
749				sleepInterval);
750		}
751
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;
761		}
762	}
763
764
765	if (status != AE_OK)
766		TRACE("error: ec wait timed out\n");
767
768	return status;
769}
770
771
772static acpi_status
773EcCommand(struct acpi_ec_cookie* sc, EC_COMMAND cmd)
774{
775	// Don't use burst mode if user disabled it.
776	if (!ec_burst_mode && cmd == EC_COMMAND_BURST_ENABLE)
777		return AE_ERROR;
778
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;
794	}
795
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;
801
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;
813		}
814	} else
815		TRACE("EcCommand: no response to %#x\n", cmd);
816
817	return status;
818}
819
820
821static acpi_status
822EcRead(struct acpi_ec_cookie* sc, uint8 address, uint8* readData)
823{
824	TRACE("read from %#x\n", address);
825
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;
831
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;
841		}
842		*readData = EC_GET_DATA(sc);
843		return AE_OK;
844	}
845
846	TRACE("EcRead: failed waiting to get data\n");
847	return status;
848}
849
850
851static acpi_status
852EcWrite(struct acpi_ec_cookie* sc, uint8 address, uint8 writeData)
853{
854	acpi_status status = EcCommand(sc, EC_COMMAND_WRITE);
855	if (status != AE_OK)
856		return status;
857
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;
864	}
865
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;
872	}
873
874	return AE_OK;
875}
876