1/*
2 * Copyright 2013, J��r��me Duval, korli@users.berlios.de.
3 * Copyright (c) 2009 Clemens Zeidler
4 * Copyright (c) 2003-2007 Nate Lawson
5 * Copyright (c) 2000 Michael Smith
6 * Copyright (c) 2000 BSDi
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31
32#include "EmbeddedController.h"
33
34#include <kernel.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
39#include <condition_variable.h>
40#include <Errors.h>
41#include <KernelExport.h>
42#include <drivers/PCI.h>
43
44
45#define ACPI_EC_DRIVER_NAME "drivers/power/acpi_embedded_controller/driver_v1"
46
47#define ACPI_EC_DEVICE_NAME "drivers/power/acpi_embedded_controller/device_v1"
48
49/* Base Namespace devices are published to */
50#define ACPI_EC_BASENAME "power/embedded_controller/%d"
51
52// name of pnp generator of path ids
53#define ACPI_EC_PATHID_GENERATOR "embedded_controller/path_id"
54
55
56uint8
57bus_space_read_1(int address)
58{
59	return gPCIManager->read_io_8(address);
60}
61
62
63void
64bus_space_write_1(int address, uint8 value)
65{
66	gPCIManager->write_io_8(address, value);
67}
68
69
70status_t
71acpi_GetInteger(acpi_device_module_info* acpi, acpi_device& acpiCookie,
72	const char* path, int* number)
73{
74	acpi_data buf;
75	acpi_object_type object;
76	buf.pointer = &object;
77	buf.length = sizeof(acpi_object_type);
78
79	// Assume that what we've been pointed at is an Integer object, or
80	// a method that will return an Integer.
81	status_t status = acpi->evaluate_method(acpiCookie, path, NULL, &buf);
82	if (status == B_OK) {
83		if (object.object_type == ACPI_TYPE_INTEGER)
84			*number = object.integer.integer;
85		else
86			status = B_BAD_VALUE;
87	}
88	return status;
89}
90
91
92acpi_handle
93acpi_GetReference(acpi_module_info* acpi, acpi_handle scope,
94	acpi_object_type* obj)
95{
96	if (obj == NULL)
97		return NULL;
98
99	switch (obj->object_type) {
100		case ACPI_TYPE_LOCAL_REFERENCE:
101		case ACPI_TYPE_ANY:
102			return obj->reference.handle;
103
104		case ACPI_TYPE_STRING:
105		{
106			// The String object usually contains a fully-qualified path, so
107			// scope can be NULL.
108			// TODO: This may not always be the case.
109			acpi_handle handle;
110			if (acpi->get_handle(scope, obj->string.string, &handle)
111					== B_OK)
112				return handle;
113		}
114	}
115
116	return NULL;
117}
118
119
120status_t
121acpi_PkgInt(acpi_object_type* res, int idx, int* dst)
122{
123	acpi_object_type* obj = &res->package.objects[idx];
124	if (obj == NULL || obj->object_type != ACPI_TYPE_INTEGER)
125		return B_BAD_VALUE;
126	*dst = obj->integer.integer;
127
128	return B_OK;
129}
130
131
132status_t
133acpi_PkgInt32(acpi_object_type* res, int idx, uint32* dst)
134{
135	int tmp;
136
137	status_t status = acpi_PkgInt(res, idx, &tmp);
138	if (status == B_OK)
139		*dst = (uint32) tmp;
140
141	return status;
142}
143
144
145acpi_status
146embedded_controller_io_ports_parse_callback(ACPI_RESOURCE* resource,
147	void* _context)
148{
149	acpi_ec_cookie* sc = (acpi_ec_cookie*)_context;
150	if (resource->Type != ACPI_RESOURCE_TYPE_IO)
151		return AE_OK;
152	if (sc->ec_data_pci_address == 0) {
153		sc->ec_data_pci_address = resource->Data.Io.Minimum;
154	} else if (sc->ec_csr_pci_address == 0) {
155		sc->ec_csr_pci_address = resource->Data.Io.Minimum;
156	} else {
157		return AE_CTRL_TERMINATE;
158	}
159
160	return AE_OK;
161}
162
163
164// #pragma mark -
165
166
167static status_t
168embedded_controller_open(void* initCookie, const char* path, int flags,
169	void** cookie)
170{
171	acpi_ec_cookie* device = (acpi_ec_cookie*) initCookie;
172	*cookie = device;
173
174	return B_OK;
175}
176
177
178static status_t
179embedded_controller_close(void* cookie)
180{
181	return B_OK;
182}
183
184
185static status_t
186embedded_controller_read(void* _cookie, off_t position, void* buffer,
187	size_t* numBytes)
188{
189	return B_IO_ERROR;
190}
191
192
193static status_t
194embedded_controller_write(void* cookie, off_t position, const void* buffer,
195	size_t* numBytes)
196{
197	return B_IO_ERROR;
198}
199
200
201status_t
202embedded_controller_control(void* _cookie, uint32 op, void* arg, size_t len)
203{
204	return B_ERROR;
205}
206
207
208static status_t
209embedded_controller_free(void* cookie)
210{
211	return B_OK;
212}
213
214
215//	#pragma mark - driver module API
216
217
218static int32
219acpi_get_type(device_node* dev)
220{
221	const char *bus;
222	if (gDeviceManager->get_attr_string(dev, B_DEVICE_BUS, &bus, false))
223		return -1;
224
225	if (strcmp(bus, "acpi"))
226		return -1;
227
228	uint32 deviceType;
229	if (gDeviceManager->get_attr_uint32(dev, ACPI_DEVICE_TYPE_ITEM,
230			&deviceType, false) != B_OK)
231		return -1;
232
233	return deviceType;
234}
235
236
237static float
238embedded_controller_support(device_node* dev)
239{
240	TRACE("embedded_controller_support()\n");
241
242	// Check that this is a device
243	if (acpi_get_type(dev) != ACPI_TYPE_DEVICE)
244		return 0.0;
245
246	const char* name;
247	if (gDeviceManager->get_attr_string(dev, ACPI_DEVICE_HID_ITEM, &name, false)
248			!= B_OK)
249		return 0.0;
250
251	// Test all known IDs
252
253	static const char* kEmbeddedControllerIDs[] = { "PNP0C09" };
254
255	for (size_t i = 0; i < sizeof(kEmbeddedControllerIDs)
256			/ sizeof(kEmbeddedControllerIDs[0]); i++) {
257		if (!strcmp(name, kEmbeddedControllerIDs[i])) {
258			TRACE("supported device found %s\n", name);
259			return 0.6;
260		}
261	}
262
263	return 0.0;
264}
265
266
267static status_t
268embedded_controller_register_device(device_node* node)
269{
270	device_attr attrs[] = {
271		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
272			{ .string = "ACPI embedded controller" }},
273		{ NULL }
274	};
275
276	return gDeviceManager->register_node(node, ACPI_EC_DRIVER_NAME, attrs,
277		NULL, NULL);
278}
279
280
281static status_t
282embedded_controller_init_driver(device_node* dev, void** _driverCookie)
283{
284	TRACE("init driver\n");
285
286	acpi_ec_cookie* sc;
287	sc = (acpi_ec_cookie*)malloc(sizeof(acpi_ec_cookie));
288	if (sc == NULL)
289		return B_NO_MEMORY;
290
291	memset(sc, 0, sizeof(acpi_ec_cookie));
292
293	*_driverCookie = sc;
294	sc->ec_dev = dev;
295
296	sc->ec_condition_var.Init(NULL, "ec condition variable");
297	mutex_init(&sc->ec_lock, "ec lock");
298	device_node* parent = gDeviceManager->get_parent_node(dev);
299	gDeviceManager->get_driver(parent, (driver_module_info**)&sc->ec_acpi,
300		(void**)&sc->ec_handle);
301	gDeviceManager->put_node(parent);
302
303	if (get_module(B_ACPI_MODULE_NAME, (module_info**)&sc->ec_acpi_module)
304			!= B_OK)
305		return B_ERROR;
306
307	acpi_data buf;
308	buf.pointer = NULL;
309	buf.length = ACPI_ALLOCATE_BUFFER;
310
311	// Read the unit ID to check for duplicate attach and the
312	// global lock value to see if we should acquire it when
313	// accessing the EC.
314	status_t status = acpi_GetInteger(sc->ec_acpi, sc->ec_handle, "_UID",
315		&sc->ec_uid);
316	if (status != B_OK)
317		sc->ec_uid = 0;
318	status = acpi_GetInteger(sc->ec_acpi, sc->ec_handle, "_GLK", &sc->ec_glk);
319	if (status != B_OK)
320		sc->ec_glk = 0;
321
322	// Evaluate the _GPE method to find the GPE bit used by the EC to
323	// signal status (SCI).  If it's a package, it contains a reference
324	// and GPE bit, similar to _PRW.
325	status = sc->ec_acpi->evaluate_method(sc->ec_handle, "_GPE", NULL, &buf);
326	if (status != B_OK) {
327		ERROR("can't evaluate _GPE %s\n", strerror(status));
328		goto error2;
329	}
330
331	acpi_object_type* obj;
332	obj = (acpi_object_type*)buf.pointer;
333	if (obj == NULL)
334		goto error2;
335
336	switch (obj->object_type) {
337		case ACPI_TYPE_INTEGER:
338			sc->ec_gpehandle = NULL;
339			sc->ec_gpebit = obj->integer.integer;
340			break;
341		case ACPI_TYPE_PACKAGE:
342			if (!ACPI_PKG_VALID(obj, 2))
343				goto error2;
344			sc->ec_gpehandle = acpi_GetReference(sc->ec_acpi_module, NULL,
345				&obj->package.objects[0]);
346			if (sc->ec_gpehandle == NULL
347				|| acpi_PkgInt32(obj, 1, (uint32*)&sc->ec_gpebit) != B_OK)
348				goto error2;
349			break;
350		default:
351			ERROR("_GPE has invalid type %i\n", int(obj->object_type));
352			goto error2;
353	}
354
355	sc->ec_suspending = FALSE;
356
357	// Attach bus resources for data and command/status ports.
358	status = sc->ec_acpi->walk_resources(sc->ec_handle, (ACPI_STRING)"_CRS",
359		embedded_controller_io_ports_parse_callback, sc);
360	if (status != B_OK) {
361		ERROR("Error while getting IO ports addresses\n");
362		goto error2;
363	}
364
365	// Install a handler for this EC's GPE bit.  We want edge-triggered
366	// behavior.
367	TRACE("attaching GPE handler\n");
368	status = sc->ec_acpi_module->install_gpe_handler(sc->ec_gpehandle,
369		sc->ec_gpebit, ACPI_GPE_EDGE_TRIGGERED, &EcGpeHandler, sc);
370	if (status != B_OK) {
371		TRACE("can't install ec GPE handler\n");
372		goto error1;
373	}
374
375	// Install address space handler
376	TRACE("attaching address space handler\n");
377	status = sc->ec_acpi->install_address_space_handler(sc->ec_handle,
378		ACPI_ADR_SPACE_EC, &EcSpaceHandler, &EcSpaceSetup, sc);
379	if (status != B_OK) {
380		ERROR("can't install address space handler\n");
381		goto error1;
382	}
383
384	// Enable runtime GPEs for the handler.
385	status = sc->ec_acpi_module->enable_gpe(sc->ec_gpehandle, sc->ec_gpebit);
386	if (status != B_OK) {
387		ERROR("AcpiEnableGpe failed.\n");
388		goto error1;
389	}
390
391	return 0;
392
393error1:
394	sc->ec_acpi_module->remove_gpe_handler(sc->ec_gpehandle, sc->ec_gpebit,
395		&EcGpeHandler);
396	sc->ec_acpi->remove_address_space_handler(sc->ec_handle, ACPI_ADR_SPACE_EC,
397		EcSpaceHandler);
398
399error2:
400	free(buf.pointer);
401
402	// remove child nodes
403	device_node *child = NULL;
404	const device_attr attrs[] = { { NULL } };
405	while (gDeviceManager->get_next_child_node(dev, attrs, &child) == B_OK)
406		gDeviceManager->unregister_node(child);
407
408	return ENXIO;
409}
410
411
412static void
413embedded_controller_uninit_driver(void* driverCookie)
414{
415	acpi_ec_cookie* sc = (struct acpi_ec_cookie*)driverCookie;
416	mutex_destroy(&sc->ec_lock);
417	free(sc);
418	put_module(B_ACPI_MODULE_NAME);
419}
420
421
422static status_t
423embedded_controller_register_child_devices(void* _cookie)
424{
425	device_node* node = ((acpi_ec_cookie*)_cookie)->ec_dev;
426
427	int pathID = gDeviceManager->create_id(ACPI_EC_PATHID_GENERATOR);
428	if (pathID < 0) {
429		TRACE("register_child_device couldn't create a path_id\n");
430		return B_ERROR;
431	}
432
433	char name[128];
434	snprintf(name, sizeof(name), ACPI_EC_BASENAME, pathID);
435
436	return gDeviceManager->publish_device(node, name, ACPI_EC_DEVICE_NAME);
437}
438
439
440static status_t
441embedded_controller_init_device(void* driverCookie, void** cookie)
442{
443	*cookie = driverCookie;
444	return B_OK;
445}
446
447
448static void
449embedded_controller_uninit_device(void* _cookie)
450{
451}
452
453
454driver_module_info embedded_controller_driver_module = {
455	{
456		ACPI_EC_DRIVER_NAME,
457		0,
458		NULL
459	},
460
461	embedded_controller_support,
462	embedded_controller_register_device,
463	embedded_controller_init_driver,
464	embedded_controller_uninit_driver,
465	embedded_controller_register_child_devices,
466	NULL,	// rescan
467	NULL,	// removed
468};
469
470
471struct device_module_info embedded_controller_device_module = {
472	{
473		ACPI_EC_DEVICE_NAME,
474		0,
475		NULL
476	},
477
478	embedded_controller_init_device,
479	embedded_controller_uninit_device,
480	NULL,
481
482	embedded_controller_open,
483	embedded_controller_close,
484	embedded_controller_free,
485	embedded_controller_read,
486	embedded_controller_write,
487	NULL,
488	embedded_controller_control,
489
490	NULL,
491	NULL
492};
493
494
495// #pragma mark -
496
497
498static acpi_status
499EcCheckStatus(struct acpi_ec_cookie* sc, const char* msg, EC_EVENT event)
500{
501	acpi_status status = AE_NO_HARDWARE_RESPONSE;
502	EC_STATUS ec_status = EC_GET_CSR(sc);
503
504	if (sc->ec_burstactive && !(ec_status & EC_FLAG_BURST_MODE)) {
505		TRACE("burst disabled in waitevent (%s)\n", msg);
506		sc->ec_burstactive = false;
507	}
508	if (EVENT_READY(event, ec_status)) {
509		TRACE("%s wait ready, status %#x\n", msg, ec_status);
510		status = AE_OK;
511	}
512	return status;
513}
514
515
516static void
517EcGpeQueryHandlerSub(struct acpi_ec_cookie *sc)
518{
519	// Serialize user access with EcSpaceHandler().
520	status_t status = EcLock(sc);
521	if (status != B_OK) {
522		TRACE("GpeQuery lock error.\n");
523		return;
524	}
525
526	// Send a query command to the EC to find out which _Qxx call it
527	// wants to make.  This command clears the SCI bit and also the
528	// interrupt source since we are edge-triggered.  To prevent the GPE
529	// that may arise from running the query from causing another query
530	// to be queued, we clear the pending flag only after running it.
531	acpi_status acpi_status = AE_ERROR;
532	for (uint8 retry = 0; retry < 2; retry++) {
533		acpi_status = EcCommand(sc, EC_COMMAND_QUERY);
534		if (acpi_status == AE_OK)
535			break;
536		if (EcCheckStatus(sc, "retr_check",
537			EC_EVENT_INPUT_BUFFER_EMPTY) != AE_OK)
538			break;
539	}
540
541	if (acpi_status != AE_OK) {
542		EcUnlock(sc);
543		TRACE("GPE query failed.\n");
544		return;
545	}
546	uint8 data = EC_GET_DATA(sc);
547
548	// We have to unlock before running the _Qxx method below since that
549	// method may attempt to read/write from EC address space, causing
550	// recursive acquisition of the lock.
551	EcUnlock(sc);
552
553	// Ignore the value for "no outstanding event". (13.3.5)
554	TRACE("query ok,%s running _Q%02X\n", data ? "" : " not", data);
555	if (data == 0)
556		return;
557
558	// Evaluate _Qxx to respond to the controller.
559	char qxx[5];
560	snprintf(qxx, sizeof(qxx), "_Q%02X", data);
561	AcpiUtStrupr(qxx);
562	status = sc->ec_acpi->evaluate_method(sc->ec_handle, qxx, NULL, NULL);
563	if (status != B_OK) {
564		TRACE("evaluation of query method %s failed\n", qxx);
565	}
566}
567
568
569static void
570EcGpeQueryHandler(void* context)
571{
572	struct acpi_ec_cookie* sc = (struct acpi_ec_cookie*)context;
573	int32 pending;
574
575	ASSERT(context != NULL);
576
577	do {
578		// Read the current pending count
579		pending = atomic_get(&sc->ec_sci_pending);
580
581		// Call GPE handler function
582		EcGpeQueryHandlerSub(sc);
583
584		// Try to reset the pending count to zero. If this fails we
585		// know another GPE event has occurred while handling the
586		// current GPE event and need to loop.
587	} while (atomic_test_and_set(&sc->ec_sci_pending, 0, pending));
588}
589
590
591/*!	The GPE handler is called when IBE/OBF or SCI events occur.  We are
592	called from an unknown lock context.
593*/
594static uint32
595EcGpeHandler(acpi_handle gpeDevice, uint32 gpeNumber, void* context)
596{
597	struct acpi_ec_cookie* sc = (acpi_ec_cookie*)context;
598
599	ASSERT(context != NULL);//, ("EcGpeHandler called with NULL"));
600	TRACE("gpe handler start\n");
601
602	// Notify EcWaitEvent() that the status register is now fresh.  If we
603	// didn't do this, it wouldn't be possible to distinguish an old IBE
604	// from a new one, for example when doing a write transaction (writing
605	// address and then data values.)
606	atomic_add(&sc->ec_gencount, 1);
607	sc->ec_condition_var.NotifyAll();
608
609	// If the EC_SCI bit of the status register is set, queue a query handler.
610	// It will run the query and _Qxx method later, under the lock.
611	EC_STATUS ecStatus = EC_GET_CSR(sc);
612	if ((ecStatus & EC_EVENT_SCI) && atomic_add(&sc->ec_sci_pending, 1) == 0) {
613		TRACE("gpe queueing query handler\n");
614		acpi_status status = AcpiOsExecute(OSL_GPE_HANDLER, EcGpeQueryHandler,
615			context);
616		if (status != AE_OK) {
617			dprintf("EcGpeHandler: queuing GPE query handler failed\n");
618			atomic_add(&sc->ec_sci_pending, -1);
619		}
620	}
621	return ACPI_REENABLE_GPE;
622}
623
624
625static acpi_status
626EcSpaceSetup(acpi_handle region, uint32 function, void* context,
627	void** regionContext)
628{
629	// If deactivating a region, always set the output to NULL.  Otherwise,
630	// just pass the context through.
631	if (function == ACPI_REGION_DEACTIVATE)
632		*regionContext = NULL;
633	else
634		*regionContext = context;
635
636	return AE_OK;
637}
638
639
640static acpi_status
641EcSpaceHandler(uint32 function, acpi_physical_address address, uint32 width,
642	int* value, void* context, void* regionContext)
643{
644	TRACE("enter EcSpaceHandler\n");
645	struct acpi_ec_cookie* sc = (struct acpi_ec_cookie*)context;
646
647	if (function != ACPI_READ && function != ACPI_WRITE)
648		return AE_BAD_PARAMETER;
649	if (width % 8 != 0 || value == NULL || context == NULL)
650		return AE_BAD_PARAMETER;
651	if (address + width / 8 > 256)
652		return AE_BAD_ADDRESS;
653
654	// If booting, check if we need to run the query handler.  If so, we
655	// we call it directly here as scheduling and dpc might not be up yet.
656	// (Not sure if it's needed)
657
658	if (gKernelStartup || gKernelShutdown || sc->ec_suspending) {
659		if ((EC_GET_CSR(sc) & EC_EVENT_SCI) &&
660			atomic_add(&sc->ec_sci_pending, 1) == 0) {
661			//CTR0(KTR_ACPI, "ec running gpe handler directly");
662			EcGpeQueryHandler(sc);
663		}
664	}
665
666	// Serialize with EcGpeQueryHandler() at transaction granularity.
667	acpi_status status = EcLock(sc);
668	if (status != B_OK)
669		return AE_NOT_ACQUIRED;
670
671	// If we can't start burst mode, continue anyway.
672	status = EcCommand(sc, EC_COMMAND_BURST_ENABLE);
673	if (status == B_OK) {
674		if (EC_GET_DATA(sc) == EC_BURST_ACK) {
675			TRACE("burst enabled.\n");
676			sc->ec_burstactive = TRUE;
677		}
678	}
679
680	// Perform the transaction(s), based on width.
681	ACPI_PHYSICAL_ADDRESS ecAddr = address;
682	uint8* ecData = (uint8 *) value;
683	if (function == ACPI_READ)
684		*value = 0;
685	do {
686		switch (function) {
687			case ACPI_READ:
688				status = EcRead(sc, ecAddr, ecData);
689				break;
690			case ACPI_WRITE:
691				status = EcWrite(sc, ecAddr, *ecData);
692				break;
693		}
694		if (status != AE_OK)
695			break;
696		ecAddr++;
697		ecData++;
698	} while (ecAddr < address + width / 8);
699
700	if (sc->ec_burstactive) {
701		sc->ec_burstactive = FALSE;
702		if (EcCommand(sc, EC_COMMAND_BURST_DISABLE) == AE_OK)
703			TRACE("disabled burst ok.");
704	}
705
706	EcUnlock(sc);
707	return status;
708}
709
710
711static acpi_status
712EcWaitEvent(struct acpi_ec_cookie* sc, EC_EVENT event, int32 generationCount)
713{
714	static int32 noIntr = 0;
715	acpi_status status = AE_NO_HARDWARE_RESPONSE;
716	int32 count, i;
717
718	int needPoll = ec_polled_mode || sc->ec_suspending
719		|| gKernelStartup || gKernelShutdown;
720
721	// Wait for event by polling or GPE (interrupt).
722	if (needPoll) {
723		count = (ec_timeout * 1000) / EC_POLL_DELAY;
724		if (count == 0)
725			count = 1;
726		spin(10);
727		for (i = 0; i < count; i++) {
728			status = EcCheckStatus(sc, "poll", event);
729			if (status == AE_OK)
730				break;
731			spin(EC_POLL_DELAY);
732		}
733	} else {
734		// Wait for the GPE to signal the status changed, checking the
735		// status register each time we get one.  It's possible to get a
736		// GPE for an event we're not interested in here (i.e., SCI for
737		// EC query).
738		for (i = 0; i < ec_timeout; i++) {
739			if (generationCount == sc->ec_gencount) {
740				sc->ec_condition_var.Wait(B_RELATIVE_TIMEOUT, 1000);
741			}
742			/*
743			 * Record new generation count.  It's possible the GPE was
744			 * just to notify us that a query is needed and we need to
745			 * wait for a second GPE to signal the completion of the
746			 * event we are actually waiting for.
747			 */
748			status = EcCheckStatus(sc, "sleep", event);
749			if (status == AE_OK) {
750				if (generationCount == sc->ec_gencount)
751					noIntr++;
752				else
753					noIntr = 0;
754				break;
755			}
756			generationCount = sc->ec_gencount;
757		}
758
759		/*
760		 * We finished waiting for the GPE and it never arrived.  Try to
761		 * read the register once and trust whatever value we got.  This is
762		 * the best we can do at this point.
763		 */
764		if (status != AE_OK)
765			status = EcCheckStatus(sc, "sleep_end", event);
766	}
767	if (!needPoll && noIntr > 10) {
768		TRACE("not getting interrupts, switched to polled mode\n");
769		ec_polled_mode = true;
770	}
771
772	if (status != AE_OK)
773		TRACE("error: ec wait timed out\n");
774
775	return status;
776}
777
778
779static acpi_status
780EcCommand(struct acpi_ec_cookie* sc, EC_COMMAND cmd)
781{
782	// Don't use burst mode if user disabled it.
783	if (!ec_burst_mode && cmd == EC_COMMAND_BURST_ENABLE)
784		return AE_ERROR;
785
786	// Decide what to wait for based on command type.
787	EC_EVENT event;
788	switch (cmd) {
789		case EC_COMMAND_READ:
790		case EC_COMMAND_WRITE:
791		case EC_COMMAND_BURST_DISABLE:
792			event = EC_EVENT_INPUT_BUFFER_EMPTY;
793			break;
794		case EC_COMMAND_QUERY:
795		case EC_COMMAND_BURST_ENABLE:
796			event = EC_EVENT_OUTPUT_BUFFER_FULL;
797			break;
798		default:
799			TRACE("EcCommand: invalid command %#x\n", cmd);
800			return AE_BAD_PARAMETER;
801	}
802
803	// Ensure empty input buffer before issuing command.
804	// Use generation count of zero to force a quick check.
805	acpi_status status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, 0);
806	if (status != AE_OK)
807		return status;
808
809	// Run the command and wait for the chosen event.
810	TRACE("running command %#x\n", cmd);
811	int32 generationCount = sc->ec_gencount;
812	EC_SET_CSR(sc, cmd);
813	status = EcWaitEvent(sc, event, generationCount);
814	if (status == AE_OK) {
815		// If we succeeded, burst flag should now be present.
816		if (cmd == EC_COMMAND_BURST_ENABLE) {
817			EC_STATUS ec_status = EC_GET_CSR(sc);
818			if ((ec_status & EC_FLAG_BURST_MODE) == 0)
819				status = AE_ERROR;
820		}
821	} else
822		TRACE("EcCommand: no response to %#x\n", cmd);
823
824	return status;
825}
826
827
828static acpi_status
829EcRead(struct acpi_ec_cookie* sc, uint8 address, uint8* readData)
830{
831	TRACE("read from %#x\n", address);
832
833	acpi_status status;
834	for (uint8 retry = 0; retry < 2; retry++) {
835		status = EcCommand(sc, EC_COMMAND_READ);
836		if (status != AE_OK)
837			return status;
838
839		int32 generationCount = sc->ec_gencount;
840		EC_SET_DATA(sc, address);
841		status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL, generationCount);
842		if (status == AE_OK) {
843			*readData = EC_GET_DATA(sc);
844			return AE_OK;
845		}
846		if (EcCheckStatus(sc, "retr_check", EC_EVENT_INPUT_BUFFER_EMPTY)
847				!= AE_OK) {
848			break;
849		}
850	}
851
852	TRACE("EcRead: failed waiting to get data\n");
853	return status;
854}
855
856
857static acpi_status
858EcWrite(struct acpi_ec_cookie* sc, uint8 address, uint8 writeData)
859{
860	acpi_status status = EcCommand(sc, EC_COMMAND_WRITE);
861	if (status != AE_OK)
862		return status;
863
864	int32 generationCount = sc->ec_gencount;
865	EC_SET_DATA(sc, address);
866	status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, generationCount);
867	if (status != AE_OK) {
868		TRACE("EcWrite: failed waiting for sent address\n");
869		return status;
870	}
871
872	generationCount = sc->ec_gencount;
873	EC_SET_DATA(sc, writeData);
874	status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, generationCount);
875	if (status != AE_OK) {
876		TRACE("EcWrite: failed waiting for sent data\n");
877		return status;
878	}
879
880	return AE_OK;
881}
882