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