acpi_ec.c revision 70232
1/*-
2 * Copyright (c) 2000 Michael Smith
3 * Copyright (c) 2000 BSDi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *	$FreeBSD: head/sys/dev/acpica/acpi_ec.c 70232 2000-12-20 17:00:33Z takawata $
28 */
29/******************************************************************************
30 *
31 * 1. Copyright Notice
32 *
33 * Some or all of this work - Copyright (c) 1999, Intel Corp.  All rights
34 * reserved.
35 *
36 * 2. License
37 *
38 * 2.1. This is your license from Intel Corp. under its intellectual property
39 * rights.  You may have additional license terms from the party that provided
40 * you this software, covering your right to use that party's intellectual
41 * property rights.
42 *
43 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
44 * copy of the source code appearing in this file ("Covered Code") an
45 * irrevocable, perpetual, worldwide license under Intel's copyrights in the
46 * base code distributed originally by Intel ("Original Intel Code") to copy,
47 * make derivatives, distribute, use and display any portion of the Covered
48 * Code in any form, with the right to sublicense such rights; and
49 *
50 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
51 * license (with the right to sublicense), under only those claims of Intel
52 * patents that are infringed by the Original Intel Code, to make, use, sell,
53 * offer to sell, and import the Covered Code and derivative works thereof
54 * solely to the minimum extent necessary to exercise the above copyright
55 * license, and in no event shall the patent license extend to any additions
56 * to or modifications of the Original Intel Code.  No other license or right
57 * is granted directly or by implication, estoppel or otherwise;
58 *
59 * The above copyright and patent license is granted only if the following
60 * conditions are met:
61 *
62 * 3. Conditions
63 *
64 * 3.1. Redistribution of Source with Rights to Further Distribute Source.
65 * Redistribution of source code of any substantial portion of the Covered
66 * Code or modification with rights to further distribute source must include
67 * the above Copyright Notice, the above License, this list of Conditions,
68 * and the following Disclaimer and Export Compliance provision.  In addition,
69 * Licensee must cause all Covered Code to which Licensee contributes to
70 * contain a file documenting the changes Licensee made to create that Covered
71 * Code and the date of any change.  Licensee must include in that file the
72 * documentation of any changes made by any predecessor Licensee.  Licensee
73 * must include a prominent statement that the modification is derived,
74 * directly or indirectly, from Original Intel Code.
75 *
76 * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
77 * Redistribution of source code of any substantial portion of the Covered
78 * Code or modification without rights to further distribute source must
79 * include the following Disclaimer and Export Compliance provision in the
80 * documentation and/or other materials provided with distribution.  In
81 * addition, Licensee may not authorize further sublicense of source of any
82 * portion of the Covered Code, and must include terms to the effect that the
83 * license from Licensee to its licensee is limited to the intellectual
84 * property embodied in the software Licensee provides to its licensee, and
85 * not to intellectual property embodied in modifications its licensee may
86 * make.
87 *
88 * 3.3. Redistribution of Executable. Redistribution in executable form of any
89 * substantial portion of the Covered Code or modification must reproduce the
90 * above Copyright Notice, and the following Disclaimer and Export Compliance
91 * provision in the documentation and/or other materials provided with the
92 * distribution.
93 *
94 * 3.4. Intel retains all right, title, and interest in and to the Original
95 * Intel Code.
96 *
97 * 3.5. Neither the name Intel nor any other trademark owned or controlled by
98 * Intel shall be used in advertising or otherwise to promote the sale, use or
99 * other dealings in products derived from or relating to the Covered Code
100 * without prior written authorization from Intel.
101 *
102 * 4. Disclaimer and Export Compliance
103 *
104 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
105 * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
106 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
107 * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
108 * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
109 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
110 * PARTICULAR PURPOSE.
111 *
112 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
113 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
114 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
115 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
116 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
117 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
118 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
119 * LIMITED REMEDY.
120 *
121 * 4.3. Licensee shall not export, either directly or indirectly, any of this
122 * software or system incorporating such software without first obtaining any
123 * required license or other approval from the U. S. Department of Commerce or
124 * any other agency or department of the United States Government.  In the
125 * event Licensee exports any such software from the United States or
126 * re-exports any such software from a foreign destination, Licensee shall
127 * ensure that the distribution and export/re-export of the software is in
128 * compliance with all laws, regulations, orders, or other restrictions of the
129 * U.S. Export Administration Regulations. Licensee agrees that neither it nor
130 * any of its subsidiaries will export/re-export any technical data, process,
131 * software, or service, directly or indirectly, to any country for which the
132 * United States government or any agency thereof requires an export license,
133 * other governmental approval, or letter of assurance, without first obtaining
134 * such license, approval or letter.
135 *
136 *****************************************************************************/
137
138#include "opt_acpi.h"
139#include <sys/param.h>
140#include <sys/kernel.h>
141#include <sys/bus.h>
142
143#include <machine/bus.h>
144#include <machine/resource.h>
145#include <sys/rman.h>
146
147#include "acpi.h"
148
149#include <dev/acpica/acpivar.h>
150#include <dev/acpica/acpi_ecreg.h>
151
152/*
153 * Hooks for the ACPI CA debugging infrastructure
154 */
155#define _COMPONENT	EMBEDDED_CONTROLLER
156MODULE_NAME("EC")
157
158struct acpi_ec_softc {
159    device_t		ec_dev;
160    ACPI_HANDLE		ec_handle;
161    ACPI_HANDLE		ec_semaphore;
162    UINT32		ec_gpebit;
163
164    int			ec_data_rid;
165    struct resource	*ec_data_res;
166    bus_space_tag_t	ec_data_tag;
167    bus_space_handle_t	ec_data_handle;
168
169    int			ec_csr_rid;
170    struct resource	*ec_csr_res;
171    bus_space_tag_t	ec_csr_tag;
172    bus_space_handle_t	ec_csr_handle;
173
174    int			ec_locked;
175    int			ec_pendquery;
176    int			ec_csrvalue;
177};
178
179#define EC_LOCK_TIMEOUT	1000	/* 1ms */
180
181static __inline ACPI_STATUS
182EcLock(struct acpi_ec_softc *sc)
183{
184    ACPI_STATUS	status;
185
186    status = AcpiOsWaitSemaphore((sc)->ec_semaphore, 1, EC_LOCK_TIMEOUT);
187    (sc)->ec_locked = 1;
188    return(status);
189}
190
191static __inline void
192EcUnlock(struct acpi_ec_softc *sc)
193{
194    (sc)->ec_locked = 0;
195    AcpiOsSignalSemaphore((sc)->ec_semaphore, 1);
196}
197
198static __inline int
199EcIsLocked(struct acpi_ec_softc *sc)
200{
201    return((sc)->ec_locked != 0);
202}
203
204typedef struct
205{
206    EC_COMMAND              Command;
207    UINT8                   Address;
208    UINT8                   Data;
209} EC_REQUEST;
210
211static struct acpi_ec_softc	acpi_ec_default;	/* for the default EC handler */
212
213static void		EcGpeHandler(void *Context);
214static ACPI_STATUS	EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function,
215					   void *Context, void **return_Context);
216static ACPI_STATUS	EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
217				      void *Context, void *RegionContext);
218
219static ACPI_STATUS	EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event);
220static ACPI_STATUS	EcQuery(struct acpi_ec_softc *sc, UINT8 *Data);
221static ACPI_STATUS	EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest);
222static ACPI_STATUS	EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
223static ACPI_STATUS	EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
224
225static void		acpi_ec_identify(driver_t driver, device_t bus);
226static int		acpi_ec_probe(device_t dev);
227static int		acpi_ec_attach(device_t dev);
228
229static device_method_t acpi_ec_methods[] = {
230    /* Device interface */
231    DEVMETHOD(device_identify,	acpi_ec_identify),
232    DEVMETHOD(device_probe,	acpi_ec_probe),
233    DEVMETHOD(device_attach,	acpi_ec_attach),
234
235    {0, 0}
236};
237
238static driver_t acpi_ec_driver = {
239    "acpi_ec",
240    acpi_ec_methods,
241    sizeof(struct acpi_ec_softc),
242};
243
244devclass_t acpi_ec_devclass;
245DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
246
247/*
248 * Look for an ECDT table and if we find one, set up a default EC
249 * space handler to catch possible attempts to access EC space before
250 * we have a real driver instance in place.
251 * We're not really an identify routine, but because we get called
252 * before most other things, this works out OK.
253 */
254static void
255acpi_ec_identify(driver_t driver, device_t bus)
256{
257    FUNCTION_TRACE(__FUNCTION__);
258
259    /* XXX implement - need an ACPI 2.0 system to test this */
260
261    return_VOID;
262}
263
264/*
265 * We could setup resources in the probe routine in order to have them printed
266 * when the device is attached.
267 */
268static int
269acpi_ec_probe(device_t dev)
270{
271
272    if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
273	!acpi_disabled("ec") &&
274	acpi_MatchHid(dev, "PNP0C09")) {
275
276	/*
277	 * Set device description
278	 */
279	device_set_desc(dev, "embedded controller");
280
281	return(0);
282    }
283    return(ENXIO);
284}
285
286static int
287acpi_ec_attach(device_t dev)
288{
289    struct acpi_ec_softc	*sc;
290    ACPI_BUFFER			*bufp;
291    UINT32			*param;
292    ACPI_STATUS			Status;
293    struct acpi_object_list	*args;
294
295    FUNCTION_TRACE(__FUNCTION__);
296
297    /*
298     * Fetch/initialise softc
299     */
300    sc = device_get_softc(dev);
301    bzero(sc, sizeof(*sc));
302    sc->ec_dev = dev;
303    sc->ec_handle = acpi_get_handle(dev);
304
305    /*
306     * Evaluate resources
307     */
308    acpi_parse_resources(sc->ec_dev, sc->ec_handle, &acpi_res_parse_set);
309
310    /*
311     * Attach bus resources
312     */
313    sc->ec_data_rid = 0;
314    if ((sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_data_rid,
315					      0, ~0, 1, RF_ACTIVE)) == NULL) {
316	device_printf(dev, "can't allocate data port\n");
317	return_VALUE(ENXIO);
318    }
319    sc->ec_data_tag = rman_get_bustag(sc->ec_data_res);
320    sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res);
321
322    sc->ec_csr_rid = 1;
323    if ((sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_csr_rid,
324					     0, ~0, 1, RF_ACTIVE)) == NULL) {
325	device_printf(dev, "can't allocate command/status port\n");
326	return_VALUE(ENXIO);
327    }
328    sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res);
329    sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res);
330
331    /*
332     * Create serialisation semaphore
333     */
334    if ((Status = AcpiOsCreateSemaphore(1, 1, &sc->ec_semaphore)) != AE_OK) {
335	device_printf(dev, "can't create semaphore - %s\n", acpi_strerror(Status));
336	return_VALUE(ENXIO);
337    }
338
339    /*
340     * Install GPE handler
341     *
342     * Evaluate the _GPE method to find the GPE bit used by the EC to signal
343     * status (SCI).
344     */
345    if ((bufp = acpi_AllocBuffer(16)) == NULL)
346	return_VALUE(ENOMEM);
347    if ((Status = AcpiEvaluateObject(sc->ec_handle, "_GPE", NULL, bufp)) != AE_OK) {
348	device_printf(dev, "can't evaluate _GPE method - %s\n", acpi_strerror(Status));
349	return_VALUE(ENXIO);
350    }
351    param = (UINT32 *)bufp->Pointer;
352    if (param[0] != ACPI_TYPE_NUMBER) {
353	device_printf(dev, "_GPE method returned bad result\n");
354	return_VALUE(ENXIO);
355    }
356    sc->ec_gpebit = param[1];
357    AcpiOsFree(bufp);
358
359    /*
360     * Install a handler for this EC's GPE bit.  Note that EC SCIs are
361     * treated as both edge- and level-triggered interrupts; in other words
362     * we clear the status bit immediately after getting an EC-SCI, then
363     * again after we're done processing the event.  This guarantees that
364     * events we cause while performing a transaction (e.g. IBE/OBF) get
365     * cleared before re-enabling the GPE.
366     */
367    if ((Status = AcpiInstallGpeHandler(sc->ec_gpebit, ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED,
368					EcGpeHandler, sc)) != AE_OK) {
369	device_printf(dev, "can't install GPE handler - %s\n", acpi_strerror(Status));
370	return_VALUE(ENXIO);
371    }
372
373    /*
374     * Install address space handler
375     */
376    if ((Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ADDRESS_SPACE_EC,
377						 &EcSpaceHandler, &EcSpaceSetup, sc)) != AE_OK) {
378	device_printf(dev, "can't install address space handler - %s\n", acpi_strerror(Status));
379	return_VALUE(ENXIO);
380    }
381
382    /*
383     * Evaluate _REG to indicate that the region is now available.
384     */
385    if ((args = acpi_AllocObjectList(2)) == NULL)
386	return_VALUE(ENOMEM);
387    args->object[0].Type = ACPI_TYPE_NUMBER;
388    args->object[0].Number.Value = ADDRESS_SPACE_EC;
389    args->object[1].Type = ACPI_TYPE_NUMBER;
390    args->object[1].Number.Value = 1;
391    Status = AcpiEvaluateObject(sc->ec_handle, "_REG", (ACPI_OBJECT_LIST *)args, NULL);
392    AcpiOsFree(args);
393    /*
394     * If evaluation failed for some reason other than that the method didn't
395     * exist, that's bad and we should not attach.
396     */
397    if ((Status != AE_OK) && (Status != AE_NOT_FOUND)) {
398	device_printf(dev, "can't evaluate _REG method - %s\n", acpi_strerror(Status));
399	return_VALUE(ENXIO);
400    }
401
402    return_VALUE(0);
403}
404
405static void
406EcGpeQueryHandler(void *Context)
407{
408    struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
409    UINT8			Data;
410    ACPI_STATUS			Status;
411    char			qxx[5];
412
413    FUNCTION_TRACE(__FUNCTION__);
414
415    for (;;) {
416
417	/*
418	 * Check EC_SCI.
419	 *
420	 * Bail out if the EC_SCI bit of the status register is not set.
421	 * Note that this function should only be called when
422	 * this bit is set (polling is used to detect IBE/OBF events).
423	 *
424	 * It is safe to do this without locking the controller, as it's
425	 * OK to call EcQuery when there's no data ready; in the worst
426	 * case we should just find nothing waiting for us and bail.
427	 */
428	if (!(EC_GET_CSR(sc) & EC_EVENT_SCI))
429	    break;
430
431	/*
432	 * Find out why the EC is signalling us
433	 */
434	Status = EcQuery(sc, &Data);
435
436	/*
437	 * If we failed to get anything from the EC, give up
438	 */
439	if (Status != AE_OK) {
440	    device_printf(sc->ec_dev, "GPE query failed - %s\n", acpi_strerror(Status));
441	    break;
442	}
443
444	/*
445	 * Evaluate _Qxx to respond to the controller.
446	 */
447	sprintf(qxx, "_Q%02x", Data);
448	strupr(qxx);
449	if ((Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL)) != AE_OK) {
450	    device_printf(sc->ec_dev, "evaluation of GPE query method %s failed - %s\n",
451			  qxx, acpi_strerror(Status));
452	}
453    }
454        /* I know I request Level trigger cleanup */
455    if(AcpiClearEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
456	    printf("EcGpeQueryHandler:ClearEvent Failed\n");
457    if(AcpiEnableEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
458	    printf("EcGpeQueryHandler:EnableEvent Failed\n");
459    return_VOID;
460}
461static void EcGpeHandler(void *Context)
462{
463	struct acpi_ec_softc *sc = Context;
464	int csrvalue;
465	/*
466	 * If EC is locked, the intr must process EcRead/Write wait only.
467	 * Query request must be pending.
468	 */
469	if(EcIsLocked(sc)){
470		csrvalue = EC_GET_CSR(sc);
471		if(csrvalue & EC_EVENT_SCI)
472			sc->ec_pendquery = 1;
473		if((csrvalue & EC_FLAG_OUTPUT_BUFFER)
474		   || !(csrvalue & EC_FLAG_INPUT_BUFFER)){
475			sc->ec_csrvalue=csrvalue;
476			wakeup((void *)&sc->ec_csrvalue);
477		}
478	}else{
479		/*Queue GpeQuery Handler*/
480		if(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
481		    EcGpeQueryHandler,Context) != AE_OK){
482			printf("QueryHandler Queuing Failed\n");
483		}
484	}
485    return;
486}
487
488static ACPI_STATUS
489EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, void **RegionContext)
490{
491    /*
492     * Just pass the context through, there's nothing to do here.
493     */
494    *RegionContext = Context;
495
496    return(AE_OK);
497}
498
499static ACPI_STATUS
500EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
501	       void *Context, void *RegionContext)
502{
503    struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
504    ACPI_STATUS			Status = AE_OK;
505    EC_REQUEST			EcRequest;
506
507    FUNCTION_TRACE_U32(__FUNCTION__, Address);
508
509    if ((Address > 0xFF) || (width != 8) || (Value == NULL) || (Context == NULL))
510        return_ACPI_STATUS(AE_BAD_PARAMETER);
511
512    switch (Function) {
513    case ADDRESS_SPACE_READ:
514        EcRequest.Command = EC_COMMAND_READ;
515        EcRequest.Address = Address;
516        EcRequest.Data = 0;
517        break;
518
519    case ADDRESS_SPACE_WRITE:
520        EcRequest.Command = EC_COMMAND_WRITE;
521        EcRequest.Address = Address;
522        EcRequest.Data = (UINT8)(*Value);
523        break;
524
525    default:
526	device_printf(sc->ec_dev, "invalid Address Space function %d\n", Function);
527        return_ACPI_STATUS(AE_BAD_PARAMETER);
528    }
529
530    /*
531     * Perform the transaction.
532     */
533    if ((Status = EcTransaction(sc, &EcRequest)) == AE_OK)
534        (*Value) = (UINT32)EcRequest.Data;
535
536    return_ACPI_STATUS(Status);
537}
538static ACPI_STATUS
539EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event)
540{
541    EC_STATUS	EcStatus;
542    int i;
543    if(cold)
544	    return EcWaitEvent(sc, Event);
545    if (!EcIsLocked(sc))
546	    device_printf(sc->ec_dev, "EcWaitEventIntr called without EC lock!\n");
547    EcStatus = EC_GET_CSR(sc);
548    /*Too long?*/
549    for(i=0;i<10;i++){
550    	if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
551		(EcStatus & EC_FLAG_OUTPUT_BUFFER))
552		return(AE_OK);
553
554	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
555		!(EcStatus & EC_FLAG_INPUT_BUFFER))
556		return(AE_OK);
557	sc->ec_csrvalue = 0;
558	if(tsleep(&sc->ec_csrvalue, 0,"ECTRANS",1) != EWOULDBLOCK){
559		EcStatus = sc->ec_csrvalue;
560	}else{
561		EcStatus=EC_GET_CSR(sc);
562	}
563    }
564    return AE_ERROR;
565}
566
567static ACPI_STATUS
568EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
569{
570    EC_STATUS	EcStatus;
571    UINT32	i = 0;
572
573    if (!EcIsLocked(sc))
574	device_printf(sc->ec_dev, "EcWaitEvent called without EC lock!\n");
575
576    /*
577     * Stall 1us:
578     * ----------
579     * Stall for 1 microsecond before reading the status register
580     * for the first time.  This allows the EC to set the IBF/OBF
581     * bit to its proper state.
582     *
583     * XXX it is not clear why we read the CSR twice.
584     */
585    AcpiOsSleepUsec(1);
586    EcStatus = EC_GET_CSR(sc);
587
588    /*
589     * Wait For Event:
590     * ---------------
591     * Poll the EC status register to detect completion of the last
592     * command.  Wait up to 10ms (in 100us chunks) for this to occur.
593     */
594    for (i = 0; i < 100; i++) {
595	EcStatus = EC_GET_CSR(sc);
596
597        if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
598            (EcStatus & EC_FLAG_OUTPUT_BUFFER))
599	    return(AE_OK);
600
601	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
602            !(EcStatus & EC_FLAG_INPUT_BUFFER))
603	    return(AE_OK);
604
605	AcpiOsSleepUsec(100);
606    }
607
608    return(AE_ERROR);
609}
610
611static ACPI_STATUS
612EcQuery(struct acpi_ec_softc *sc, UINT8 *Data)
613{
614    ACPI_STATUS	Status;
615
616    if ((Status = EcLock(sc)) != AE_OK)
617	return(Status);
618
619    EC_SET_CSR(sc, EC_COMMAND_QUERY);
620    Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL);
621    if (Status == AE_OK)
622	*Data = EC_GET_DATA(sc);
623
624    EcUnlock(sc);
625
626    if (Status != AE_OK)
627	device_printf(sc->ec_dev, "timeout waiting for EC to respond to EC_COMMAND_QUERY\n");
628    return(Status);
629}
630
631
632static ACPI_STATUS
633EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
634{
635    ACPI_STATUS	Status;
636
637    /*
638     * Lock the EC
639     */
640    if ((Status = EcLock(sc)) != AE_OK)
641	return(Status);
642
643    /*
644     * Perform the transaction.
645     */
646    switch (EcRequest->Command) {
647    case EC_COMMAND_READ:
648	Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data));
649	break;
650
651    case EC_COMMAND_WRITE:
652	Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data));
653	break;
654
655    default:
656	Status = AE_SUPPORT;
657	break;
658    }
659
660    /*
661     * Clear & Re-Enable the EC GPE:
662     * -----------------------------
663     * 'Consume' any EC GPE events that we generated while performing
664     * the transaction (e.g. IBF/OBF).	Clearing the GPE here shouldn't
665     * have an adverse affect on outstanding EC-SCI's, as the source
666     * (EC-SCI) will still be high and thus should trigger the GPE
667     * immediately after we re-enabling it.
668     */
669    if (sc->ec_pendquery){
670	    if(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
671		EcGpeQueryHandler, sc) != AE_OK)
672		    printf("Pend Query Queuing Failed\n");
673	    sc->ec_pendquery = 0;
674    }
675
676    if (AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
677	device_printf(sc->ec_dev, "EcRequest: Unable to clear the EC GPE.\n");
678    if (AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
679	device_printf(sc->ec_dev, "EcRequest: Unable to re-enable the EC GPE.\n");
680
681    /*
682     * Unlock the EC
683     */
684    EcUnlock(sc);
685
686    return(Status);
687}
688
689
690static ACPI_STATUS
691EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
692{
693    ACPI_STATUS	Status;
694
695    if (!EcIsLocked(sc))
696	device_printf(sc->ec_dev, "EcRead called without EC lock!\n");
697
698    /*EcBurstEnable(EmbeddedController);*/
699
700    EC_SET_CSR(sc, EC_COMMAND_READ);
701    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
702	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process read command.\n");
703	return(Status);
704    }
705
706    EC_SET_DATA(sc, Address);
707    if ((Status = EcWaitEventIntr(sc, EC_EVENT_OUTPUT_BUFFER_FULL)) != AE_OK) {
708	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to send data.\n");
709	return(Status);
710    }
711
712    (*Data) = EC_GET_DATA(sc);
713
714    /*EcBurstDisable(EmbeddedController);*/
715
716    return(AE_OK);
717}
718
719static ACPI_STATUS
720EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
721{
722    ACPI_STATUS	Status;
723
724    if (!EcIsLocked(sc))
725	device_printf(sc->ec_dev, "EcWrite called without EC lock!\n");
726
727    /*EcBurstEnable(EmbeddedController);*/
728
729    EC_SET_CSR(sc, EC_COMMAND_WRITE);
730    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
731	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process write command.\n");
732	return(Status);
733    }
734
735    EC_SET_DATA(sc, Address);
736    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
737	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process address.\n");
738	return(Status);
739    }
740
741    EC_SET_DATA(sc, *Data);
742    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
743	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process data.\n");
744	return(Status);
745    }
746
747    /*EcBurstDisable(EmbeddedController);*/
748
749    return(AE_OK);
750}
751