acpi_ec.c revision 78992
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 78992 2001-06-29 20:31:37Z msmith $
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	ACPI_EC
156MODULE_NAME("EC")
157
158struct acpi_ec_softc {
159    device_t		ec_dev;
160    ACPI_HANDLE		ec_handle;
161    UINT32		ec_gpebit;
162
163    int			ec_data_rid;
164    struct resource	*ec_data_res;
165    bus_space_tag_t	ec_data_tag;
166    bus_space_handle_t	ec_data_handle;
167
168    int			ec_csr_rid;
169    struct resource	*ec_csr_res;
170    bus_space_tag_t	ec_csr_tag;
171    bus_space_handle_t	ec_csr_handle;
172
173    int			ec_locked;
174    int			ec_pendquery;
175    int			ec_csrvalue;
176};
177
178#define EC_LOCK_TIMEOUT	1000	/* 1ms */
179
180static __inline ACPI_STATUS
181EcLock(struct acpi_ec_softc *sc)
182{
183    ACPI_STATUS	status;
184
185    status = AcpiAcquireGlobalLock();
186    (sc)->ec_locked = 1;
187    return(status);
188}
189
190static __inline void
191EcUnlock(struct acpi_ec_softc *sc)
192{
193    (sc)->ec_locked = 0;
194    AcpiReleaseGlobalLock();
195}
196
197static __inline int
198EcIsLocked(struct acpi_ec_softc *sc)
199{
200    return((sc)->ec_locked != 0);
201}
202
203typedef struct
204{
205    EC_COMMAND              Command;
206    UINT8                   Address;
207    UINT8                   Data;
208} EC_REQUEST;
209
210static void		EcGpeHandler(void *Context);
211static ACPI_STATUS	EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function,
212					   void *Context, void **return_Context);
213static ACPI_STATUS	EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
214				      void *Context, void *RegionContext);
215
216static ACPI_STATUS	EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event);
217static ACPI_STATUS	EcQuery(struct acpi_ec_softc *sc, UINT8 *Data);
218static ACPI_STATUS	EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest);
219static ACPI_STATUS	EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
220static ACPI_STATUS	EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
221
222static void		acpi_ec_identify(driver_t driver, device_t bus);
223static int		acpi_ec_probe(device_t dev);
224static int		acpi_ec_attach(device_t dev);
225
226static device_method_t acpi_ec_methods[] = {
227    /* Device interface */
228    DEVMETHOD(device_identify,	acpi_ec_identify),
229    DEVMETHOD(device_probe,	acpi_ec_probe),
230    DEVMETHOD(device_attach,	acpi_ec_attach),
231
232    {0, 0}
233};
234
235static driver_t acpi_ec_driver = {
236    "acpi_ec",
237    acpi_ec_methods,
238    sizeof(struct acpi_ec_softc),
239};
240
241devclass_t acpi_ec_devclass;
242DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
243
244/*
245 * Look for an ECDT table and if we find one, set up a default EC
246 * space handler to catch possible attempts to access EC space before
247 * we have a real driver instance in place.
248 * We're not really an identify routine, but because we get called
249 * before most other things, this works out OK.
250 */
251static void
252acpi_ec_identify(driver_t driver, device_t bus)
253{
254    FUNCTION_TRACE(__func__);
255
256    /* XXX implement - need an ACPI 2.0 system to test this */
257
258    return_VOID;
259}
260
261/*
262 * We could setup resources in the probe routine in order to have them printed
263 * when the device is attached.
264 */
265static int
266acpi_ec_probe(device_t dev)
267{
268
269    if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
270	!acpi_disabled("ec") &&
271	acpi_MatchHid(dev, "PNP0C09")) {
272
273	/*
274	 * Set device description
275	 */
276	device_set_desc(dev, "embedded controller");
277
278	return(0);
279    }
280    return(ENXIO);
281}
282
283static int
284acpi_ec_attach(device_t dev)
285{
286    struct acpi_ec_softc	*sc;
287    ACPI_STATUS			Status;
288
289    FUNCTION_TRACE(__func__);
290
291    /*
292     * Fetch/initialise softc
293     */
294    sc = device_get_softc(dev);
295    bzero(sc, sizeof(*sc));
296    sc->ec_dev = dev;
297    sc->ec_handle = acpi_get_handle(dev);
298
299    /*
300     * Evaluate resources
301     */
302    DEBUG_PRINT(TRACE_RESOURCES, ("parsing EC resources\n"));
303    acpi_parse_resources(sc->ec_dev, sc->ec_handle, &acpi_res_parse_set);
304
305    /*
306     * Attach bus resources
307     */
308    sc->ec_data_rid = 0;
309    if ((sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_data_rid,
310					      0, ~0, 1, RF_ACTIVE)) == NULL) {
311	device_printf(dev, "can't allocate data port\n");
312	return_VALUE(ENXIO);
313    }
314    sc->ec_data_tag = rman_get_bustag(sc->ec_data_res);
315    sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res);
316
317    sc->ec_csr_rid = 1;
318    if ((sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_csr_rid,
319					     0, ~0, 1, RF_ACTIVE)) == NULL) {
320	device_printf(dev, "can't allocate command/status port\n");
321	return_VALUE(ENXIO);
322    }
323    sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res);
324    sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res);
325
326    /*
327     * Install GPE handler
328     *
329     * Evaluate the _GPE method to find the GPE bit used by the EC to signal
330     * status (SCI).
331     */
332    DEBUG_PRINT(TRACE_RESOURCES, ("attaching GPE\n"));
333    if ((Status = acpi_EvaluateInteger(sc->ec_handle, "_GPE", &sc->ec_gpebit)) != AE_OK) {
334	device_printf(dev, "can't evaluate _GPE - %s\n", acpi_strerror(Status));
335	return_VALUE(ENXIO);
336    }
337
338    /*
339     * Install a handler for this EC's GPE bit.  Note that EC SCIs are
340     * treated as both edge- and level-triggered interrupts; in other words
341     * we clear the status bit immediately after getting an EC-SCI, then
342     * again after we're done processing the event.  This guarantees that
343     * events we cause while performing a transaction (e.g. IBE/OBF) get
344     * cleared before re-enabling the GPE.
345     */
346    if ((Status = AcpiInstallGpeHandler(sc->ec_gpebit, ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED,
347					EcGpeHandler, sc)) != AE_OK) {
348	device_printf(dev, "can't install GPE handler - %s\n", acpi_strerror(Status));
349	return_VALUE(ENXIO);
350    }
351
352    /*
353     * Install address space handler
354     */
355    DEBUG_PRINT(TRACE_RESOURCES, ("attaching address space handler\n"));
356    if ((Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ACPI_ADR_SPACE_EC,
357						 EcSpaceHandler, EcSpaceSetup, sc)) != AE_OK) {
358	device_printf(dev, "can't install address space handler - %s\n", acpi_strerror(Status));
359	return_VALUE(ENXIO);
360    }
361    DEBUG_PRINT(TRACE_RESOURCES, ("attach complete\n"));
362
363    return_VALUE(0);
364}
365
366static void
367EcGpeQueryHandler(void *Context)
368{
369    struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
370    UINT8			Data;
371    ACPI_STATUS			Status;
372    char			qxx[5];
373
374    FUNCTION_TRACE(__func__);
375
376    for (;;) {
377
378	/*
379	 * Check EC_SCI.
380	 *
381	 * Bail out if the EC_SCI bit of the status register is not set.
382	 * Note that this function should only be called when
383	 * this bit is set (polling is used to detect IBE/OBF events).
384	 *
385	 * It is safe to do this without locking the controller, as it's
386	 * OK to call EcQuery when there's no data ready; in the worst
387	 * case we should just find nothing waiting for us and bail.
388	 */
389	if (!(EC_GET_CSR(sc) & EC_EVENT_SCI))
390	    break;
391
392	/*
393	 * Find out why the EC is signalling us
394	 */
395	Status = EcQuery(sc, &Data);
396
397	/*
398	 * If we failed to get anything from the EC, give up
399	 */
400	if (Status != AE_OK) {
401	    device_printf(sc->ec_dev, "GPE query failed - %s\n", acpi_strerror(Status));
402	    break;
403	}
404
405	/*
406	 * Evaluate _Qxx to respond to the controller.
407	 */
408	sprintf(qxx, "_Q%02x", Data);
409	strupr(qxx);
410	Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL);
411	/*
412	 * Ignore spurious query requests.
413	 */
414	if (Status != AE_OK && (Data != 0 || Status != AE_NOT_FOUND)) {
415	    device_printf(sc->ec_dev, "evaluation of GPE query method %s failed - %s\n",
416			  qxx, acpi_strerror(Status));
417	}
418    }
419        /* I know I request Level trigger cleanup */
420    if(AcpiClearEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
421	    printf("EcGpeQueryHandler:ClearEvent Failed\n");
422    if(AcpiEnableEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
423	    printf("EcGpeQueryHandler:EnableEvent Failed\n");
424    return_VOID;
425}
426
427/*
428 * Handle a GPE sent to us.
429 */
430static void
431EcGpeHandler(void *Context)
432{
433    struct acpi_ec_softc *sc = Context;
434    int csrvalue;
435
436    /*
437     * If EC is locked, the intr must process EcRead/Write wait only.
438     * Query request must be pending.
439     */
440    if (EcIsLocked(sc)){
441	csrvalue = EC_GET_CSR(sc);
442	if (csrvalue & EC_EVENT_SCI)
443	    sc->ec_pendquery = 1;
444	if ((csrvalue & EC_FLAG_OUTPUT_BUFFER)
445	    || !(csrvalue & EC_FLAG_INPUT_BUFFER)) {
446	    sc->ec_csrvalue = csrvalue;
447	    wakeup((void *)&sc->ec_csrvalue);
448	}
449    }else{
450	/* Queue GpeQuery Handler */
451	if (AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
452				    EcGpeQueryHandler,Context) != AE_OK){
453	    printf("QueryHandler Queuing Failed\n");
454	}
455    }
456    return;
457}
458
459static ACPI_STATUS
460EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, void **RegionContext)
461{
462
463    FUNCTION_TRACE(__func__);
464
465    /*
466     * Just pass the context through, there's nothing to do here.
467     */
468    *RegionContext = Context;
469
470    return_ACPI_STATUS(AE_OK);
471}
472
473static ACPI_STATUS
474EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
475	       void *Context, void *RegionContext)
476{
477    struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
478    ACPI_STATUS			Status = AE_OK;
479    EC_REQUEST			EcRequest;
480    int				i;
481
482    FUNCTION_TRACE_U32(__func__, (UINT32)Address);
483
484    if ((Address > 0xFF) || (width % 8 != 0) || (Value == NULL) || (Context == NULL))
485        return_ACPI_STATUS(AE_BAD_PARAMETER);
486
487    switch (Function) {
488    case ACPI_READ_ADR_SPACE:
489        EcRequest.Command = EC_COMMAND_READ;
490        EcRequest.Address = Address;
491	(*Value) = 0;
492        break;
493
494    case ACPI_WRITE_ADR_SPACE:
495        EcRequest.Command = EC_COMMAND_WRITE;
496        EcRequest.Address = Address;
497        break;
498
499    default:
500	device_printf(sc->ec_dev, "invalid Address Space function %d\n", Function);
501        return_ACPI_STATUS(AE_BAD_PARAMETER);
502    }
503
504    /*
505     * Perform the transaction.
506     */
507    for (i = 0; i < width; i += 8) {
508	if (Function == ACPI_READ_ADR_SPACE)
509	    EcRequest.Data = 0;
510	else
511	    EcRequest.Data = (UINT8)((*Value) >> i);
512	if ((Status = EcTransaction(sc, &EcRequest)) != AE_OK)
513	    break;
514        (*Value) |= (UINT32)EcRequest.Data << i;
515	if (++EcRequest.Address == 0)
516            return_ACPI_STATUS(AE_BAD_PARAMETER);
517    }
518    return_ACPI_STATUS(Status);
519}
520
521/*
522 * Wait for an event interrupt for a specific condition.
523 */
524static ACPI_STATUS
525EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event)
526{
527    EC_STATUS	EcStatus;
528    int		i;
529
530    FUNCTION_TRACE_U32(__func__, (UINT32)Event);
531
532    /* XXX this should test whether interrupts are available some other way */
533    if(cold)
534	return_ACPI_STATUS(EcWaitEvent(sc, Event));
535
536    if (!EcIsLocked(sc))
537	device_printf(sc->ec_dev, "EcWaitEventIntr called without EC lock!\n");
538
539    EcStatus = EC_GET_CSR(sc);
540
541    /* XXX waiting too long? */
542    for(i = 0; i < 10; i++){
543	/*
544	 * Check EC status against the desired event.
545	 */
546    	if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
547	    (EcStatus & EC_FLAG_OUTPUT_BUFFER))
548	    return_ACPI_STATUS(AE_OK);
549
550	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
551	    !(EcStatus & EC_FLAG_INPUT_BUFFER))
552	    return_ACPI_STATUS(AE_OK);
553
554	sc->ec_csrvalue = 0;
555	if (ACPI_MSLEEP(&sc->ec_csrvalue, &acpi_mutex, PZERO, "EcWait", 1) != EWOULDBLOCK){
556	    EcStatus = sc->ec_csrvalue;
557	}else{
558	    EcStatus = EC_GET_CSR(sc);
559	}
560    }
561    return_ACPI_STATUS(AE_ERROR);
562}
563
564static ACPI_STATUS
565EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
566{
567    EC_STATUS	EcStatus;
568    UINT32	i = 0;
569
570    if (!EcIsLocked(sc))
571	device_printf(sc->ec_dev, "EcWaitEvent called without EC lock!\n");
572
573    /*
574     * Stall 1us:
575     * ----------
576     * Stall for 1 microsecond before reading the status register
577     * for the first time.  This allows the EC to set the IBF/OBF
578     * bit to its proper state.
579     *
580     * XXX it is not clear why we read the CSR twice.
581     */
582    AcpiOsSleepUsec(1);
583    EcStatus = EC_GET_CSR(sc);
584
585    /*
586     * Wait For Event:
587     * ---------------
588     * Poll the EC status register to detect completion of the last
589     * command.  Wait up to 10ms (in 10us chunks) for this to occur.
590     */
591    for (i = 0; i < 1000; i++) {
592	EcStatus = EC_GET_CSR(sc);
593
594        if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
595            (EcStatus & EC_FLAG_OUTPUT_BUFFER))
596	    return(AE_OK);
597
598	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
599            !(EcStatus & EC_FLAG_INPUT_BUFFER))
600	    return(AE_OK);
601
602	AcpiOsSleepUsec(10);
603    }
604
605    return(AE_ERROR);
606}
607
608static ACPI_STATUS
609EcQuery(struct acpi_ec_softc *sc, UINT8 *Data)
610{
611    ACPI_STATUS	Status;
612
613    if ((Status = EcLock(sc)) != AE_OK)
614	return(Status);
615
616    EC_SET_CSR(sc, EC_COMMAND_QUERY);
617    Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL);
618    if (Status == AE_OK)
619	*Data = EC_GET_DATA(sc);
620
621    EcUnlock(sc);
622
623    if (Status != AE_OK)
624	device_printf(sc->ec_dev, "timeout waiting for EC to respond to EC_COMMAND_QUERY\n");
625    return(Status);
626}
627
628static ACPI_STATUS
629EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
630{
631    ACPI_STATUS	Status;
632
633    /*
634     * Lock the EC
635     */
636    if ((Status = EcLock(sc)) != AE_OK)
637	return(Status);
638
639    /*
640     * Perform the transaction.
641     */
642    switch (EcRequest->Command) {
643    case EC_COMMAND_READ:
644	Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data));
645	break;
646
647    case EC_COMMAND_WRITE:
648	Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data));
649	break;
650
651    default:
652	Status = AE_SUPPORT;
653	break;
654    }
655
656    /*
657     * Unlock the EC
658     */
659    EcUnlock(sc);
660
661    /*
662     * Clear & Re-Enable the EC GPE:
663     * -----------------------------
664     * 'Consume' any EC GPE events that we generated while performing
665     * the transaction (e.g. IBF/OBF).	Clearing the GPE here shouldn't
666     * have an adverse affect on outstanding EC-SCI's, as the source
667     * (EC-SCI) will still be high and thus should trigger the GPE
668     * immediately after we re-enabling it.
669     */
670    if (sc->ec_pendquery){
671	    if(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
672		EcGpeQueryHandler, sc) != AE_OK)
673		    printf("Pend Query Queuing Failed\n");
674	    sc->ec_pendquery = 0;
675    }
676
677    if (AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
678	device_printf(sc->ec_dev, "EcRequest: Unable to clear the EC GPE.\n");
679    if (AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
680	device_printf(sc->ec_dev, "EcRequest: Unable to re-enable the EC GPE.\n");
681
682    return(Status);
683}
684
685
686static ACPI_STATUS
687EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
688{
689    ACPI_STATUS	Status;
690
691    if (!EcIsLocked(sc))
692	device_printf(sc->ec_dev, "EcRead called without EC lock!\n");
693
694    /*EcBurstEnable(EmbeddedController);*/
695
696    EC_SET_CSR(sc, EC_COMMAND_READ);
697    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
698	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process read command.\n");
699	return(Status);
700    }
701
702    EC_SET_DATA(sc, Address);
703    if ((Status = EcWaitEventIntr(sc, EC_EVENT_OUTPUT_BUFFER_FULL)) != AE_OK) {
704	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to send data.\n");
705	return(Status);
706    }
707
708    (*Data) = EC_GET_DATA(sc);
709
710    /*EcBurstDisable(EmbeddedController);*/
711
712    return(AE_OK);
713}
714
715static ACPI_STATUS
716EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
717{
718    ACPI_STATUS	Status;
719
720    if (!EcIsLocked(sc))
721	device_printf(sc->ec_dev, "EcWrite called without EC lock!\n");
722
723    /*EcBurstEnable(EmbeddedController);*/
724
725    EC_SET_CSR(sc, EC_COMMAND_WRITE);
726    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
727	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process write command.\n");
728	return(Status);
729    }
730
731    EC_SET_DATA(sc, Address);
732    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
733	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process address.\n");
734	return(Status);
735    }
736
737    EC_SET_DATA(sc, *Data);
738    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
739	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process data.\n");
740	return(Status);
741    }
742
743    /*EcBurstDisable(EmbeddedController);*/
744
745    return(AE_OK);
746}
747