xref: /haiku/src/add-ons/kernel/bus_managers/acpi/EmbeddedController.cpp (revision 204dee708a999d5a71d0cb9497650ee7cef85d0a)
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 
57 uint8
58 bus_space_read_1(int address)
59 {
60 	return gPCIManager->read_io_8(address);
61 }
62 
63 
64 void
65 bus_space_write_1(int address, uint8 value)
66 {
67 	gPCIManager->write_io_8(address, value);
68 }
69 
70 
71 status_t
72 acpi_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 
93 acpi_handle
94 acpi_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 
121 status_t
122 acpi_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 
133 status_t
134 acpi_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 
149 static status_t
150 embedded_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 
160 static status_t
161 embedded_controller_close(void* cookie)
162 {
163 	return B_OK;
164 }
165 
166 
167 static status_t
168 embedded_controller_read(void* _cookie, off_t position, void* buffer,
169 	size_t* numBytes)
170 {
171 	return B_IO_ERROR;
172 }
173 
174 
175 static status_t
176 embedded_controller_write(void* cookie, off_t position, const void* buffer,
177 	size_t* numBytes)
178 {
179 	return B_IO_ERROR;
180 }
181 
182 
183 status_t
184 embedded_controller_control(void* _cookie, uint32 op, void* arg, size_t len)
185 {
186 	return B_ERROR;
187 }
188 
189 
190 static status_t
191 embedded_controller_free(void* cookie)
192 {
193 	return B_OK;
194 }
195 
196 
197 //	#pragma mark - driver module API
198 
199 
200 static int32
201 acpi_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 
219 static float
220 embedded_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 
249 static status_t
250 embedded_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 
263 static status_t
264 embedded_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 
385 error:
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 
397 static void
398 embedded_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 
407 static status_t
408 embedded_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 
425 static status_t
426 embedded_controller_init_device(void* driverCookie, void** cookie)
427 {
428 	return B_ERROR;
429 }
430 
431 
432 static void
433 embedded_controller_uninit_device(void* _cookie)
434 {
435 	acpi_ec_cookie* device = (acpi_ec_cookie*)_cookie;
436 	free(device);
437 }
438 
439 
440 driver_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 
457 struct 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 
484 static acpi_status
485 EcCheckStatus(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 
502 static void
503 EcGpeQueryHandler(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 */
572 static uint32
573 EcGpeHandler(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 
603 static acpi_status
604 EcSpaceSetup(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 
618 static acpi_status
619 EcSpaceHandler(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 
687 static acpi_status
688 EcWaitEvent(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 
772 static acpi_status
773 EcCommand(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 
821 static acpi_status
822 EcRead(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 
851 static acpi_status
852 EcWrite(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