acpi_ec.c revision 80069
169626Sru/*-
269626Sru * Copyright (c) 2000 Michael Smith
369626Sru * Copyright (c) 2000 BSDi
469626Sru * All rights reserved.
569626Sru *
669626Sru * Redistribution and use in source and binary forms, with or without
769626Sru * modification, are permitted provided that the following conditions
869626Sru * are met:
969626Sru * 1. Redistributions of source code must retain the above copyright
1069626Sru *    notice, this list of conditions and the following disclaimer.
1169626Sru * 2. Redistributions in binary form must reproduce the above copyright
1269626Sru *    notice, this list of conditions and the following disclaimer in the
1369626Sru *    documentation and/or other materials provided with the distribution.
1469626Sru *
1569626Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1669626Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1769626Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1869626Sru * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1969626Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2069626Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2169626Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2269626Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2369626Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2469626Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2569626Sru * SUCH DAMAGE.
2669626Sru *
2769626Sru *	$FreeBSD: head/sys/dev/acpica/acpi_ec.c 80069 2001-07-21 04:06:44Z msmith $
2869626Sru */
2969626Sru/******************************************************************************
3069626Sru *
3169626Sru * 1. Copyright Notice
3269626Sru *
3369626Sru * Some or all of this work - Copyright (c) 1999, Intel Corp.  All rights
3469626Sru * reserved.
3569626Sru *
3669626Sru * 2. License
3769626Sru *
3869626Sru * 2.1. This is your license from Intel Corp. under its intellectual property
3969626Sru * rights.  You may have additional license terms from the party that provided
4069626Sru * you this software, covering your right to use that party's intellectual
4169626Sru * property rights.
4269626Sru *
4369626Sru * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
4469626Sru * copy of the source code appearing in this file ("Covered Code") an
4569626Sru * irrevocable, perpetual, worldwide license under Intel's copyrights in the
4669626Sru * base code distributed originally by Intel ("Original Intel Code") to copy,
4769626Sru * make derivatives, distribute, use and display any portion of the Covered
4869626Sru * Code in any form, with the right to sublicense such rights; and
4969626Sru *
5069626Sru * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
5169626Sru * license (with the right to sublicense), under only those claims of Intel
5269626Sru * patents that are infringed by the Original Intel Code, to make, use, sell,
5369626Sru * offer to sell, and import the Covered Code and derivative works thereof
5469626Sru * solely to the minimum extent necessary to exercise the above copyright
5569626Sru * license, and in no event shall the patent license extend to any additions
5669626Sru * to or modifications of the Original Intel Code.  No other license or right
5769626Sru * is granted directly or by implication, estoppel or otherwise;
5869626Sru *
5969626Sru * The above copyright and patent license is granted only if the following
6069626Sru * conditions are met:
6169626Sru *
6269626Sru * 3. Conditions
6369626Sru *
6469626Sru * 3.1. Redistribution of Source with Rights to Further Distribute Source.
6569626Sru * Redistribution of source code of any substantial portion of the Covered
6669626Sru * Code or modification with rights to further distribute source must include
6769626Sru * the above Copyright Notice, the above License, this list of Conditions,
6869626Sru * and the following Disclaimer and Export Compliance provision.  In addition,
6969626Sru * Licensee must cause all Covered Code to which Licensee contributes to
7069626Sru * contain a file documenting the changes Licensee made to create that Covered
7169626Sru * Code and the date of any change.  Licensee must include in that file the
7269626Sru * documentation of any changes made by any predecessor Licensee.  Licensee
7369626Sru * must include a prominent statement that the modification is derived,
7469626Sru * directly or indirectly, from Original Intel Code.
7569626Sru *
7669626Sru * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
7769626Sru * Redistribution of source code of any substantial portion of the Covered
7869626Sru * Code or modification without rights to further distribute source must
7969626Sru * include the following Disclaimer and Export Compliance provision in the
8069626Sru * documentation and/or other materials provided with distribution.  In
8169626Sru * addition, Licensee may not authorize further sublicense of source of any
8269626Sru * portion of the Covered Code, and must include terms to the effect that the
8369626Sru * license from Licensee to its licensee is limited to the intellectual
8469626Sru * property embodied in the software Licensee provides to its licensee, and
8569626Sru * not to intellectual property embodied in modifications its licensee may
8669626Sru * 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
158/*
159 * EC_COMMAND:
160 * -----------
161 */
162typedef UINT8				EC_COMMAND;
163
164#define EC_COMMAND_UNKNOWN		((EC_COMMAND) 0x00)
165#define EC_COMMAND_READ			((EC_COMMAND) 0x80)
166#define EC_COMMAND_WRITE		((EC_COMMAND) 0x81)
167#define EC_COMMAND_BURST_ENABLE		((EC_COMMAND) 0x82)
168#define EC_COMMAND_BURST_DISABLE	((EC_COMMAND) 0x83)
169#define EC_COMMAND_QUERY		((EC_COMMAND) 0x84)
170
171/*
172 * EC_STATUS:
173 * ----------
174 * The encoding of the EC status register is illustrated below.
175 * Note that a set bit (1) indicates the property is TRUE
176 * (e.g. if bit 0 is set then the output buffer is full).
177 * +-+-+-+-+-+-+-+-+
178 * |7|6|5|4|3|2|1|0|
179 * +-+-+-+-+-+-+-+-+
180 *  | | | | | | | |
181 *  | | | | | | | +- Output Buffer Full?
182 *  | | | | | | +--- Input Buffer Full?
183 *  | | | | | +----- <reserved>
184 *  | | | | +------- Data Register is Command Byte?
185 *  | | | +--------- Burst Mode Enabled?
186 *  | | +----------- SCI Event?
187 *  | +------------- SMI Event?
188 *  +--------------- <Reserved>
189 *
190 */
191typedef UINT8				EC_STATUS;
192
193#define EC_FLAG_OUTPUT_BUFFER		((EC_STATUS) 0x01)
194#define EC_FLAG_INPUT_BUFFER		((EC_STATUS) 0x02)
195#define EC_FLAG_BURST_MODE		((EC_STATUS) 0x10)
196#define EC_FLAG_SCI			((EC_STATUS) 0x20)
197
198/*
199 * EC_EVENT:
200 * ---------
201 */
202typedef UINT8				EC_EVENT;
203
204#define EC_EVENT_UNKNOWN		((EC_EVENT) 0x00)
205#define EC_EVENT_OUTPUT_BUFFER_FULL	((EC_EVENT) 0x01)
206#define EC_EVENT_INPUT_BUFFER_EMPTY	((EC_EVENT) 0x02)
207#define EC_EVENT_SCI			((EC_EVENT) 0x20)
208
209/*
210 * Register access primitives
211 */
212#define EC_GET_DATA(sc)							\
213	bus_space_read_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0)
214
215#define EC_SET_DATA(sc, v)						\
216	bus_space_write_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0, (v))
217
218#define EC_GET_CSR(sc)							\
219	bus_space_read_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0)
220
221#define EC_SET_CSR(sc, v)						\
222	bus_space_write_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0, (v))
223
224/*
225 * Driver softc.
226 */
227struct acpi_ec_softc {
228    device_t		ec_dev;
229    ACPI_HANDLE		ec_handle;
230    UINT32		ec_gpebit;
231
232    int			ec_data_rid;
233    struct resource	*ec_data_res;
234    bus_space_tag_t	ec_data_tag;
235    bus_space_handle_t	ec_data_handle;
236
237    int			ec_csr_rid;
238    struct resource	*ec_csr_res;
239    bus_space_tag_t	ec_csr_tag;
240    bus_space_handle_t	ec_csr_handle;
241
242    int			ec_locked;
243    int			ec_pendquery;
244    int			ec_csrvalue;
245};
246
247#define EC_LOCK_TIMEOUT	1000	/* 1ms */
248
249static __inline ACPI_STATUS
250EcLock(struct acpi_ec_softc *sc)
251{
252    ACPI_STATUS	status;
253
254    status = AcpiAcquireGlobalLock();
255    (sc)->ec_locked = 1;
256    return(status);
257}
258
259static __inline void
260EcUnlock(struct acpi_ec_softc *sc)
261{
262    (sc)->ec_locked = 0;
263    AcpiReleaseGlobalLock();
264}
265
266static __inline int
267EcIsLocked(struct acpi_ec_softc *sc)
268{
269    return((sc)->ec_locked != 0);
270}
271
272typedef struct
273{
274    EC_COMMAND              Command;
275    UINT8                   Address;
276    UINT8                   Data;
277} EC_REQUEST;
278
279static void		EcGpeHandler(void *Context);
280static ACPI_STATUS	EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function,
281					   void *Context, void **return_Context);
282static ACPI_STATUS	EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
283				      void *Context, void *RegionContext);
284
285static ACPI_STATUS	EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event);
286static ACPI_STATUS	EcQuery(struct acpi_ec_softc *sc, UINT8 *Data);
287static ACPI_STATUS	EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest);
288static ACPI_STATUS	EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
289static ACPI_STATUS	EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
290
291static void		acpi_ec_identify(driver_t driver, device_t bus);
292static int		acpi_ec_probe(device_t dev);
293static int		acpi_ec_attach(device_t dev);
294
295static device_method_t acpi_ec_methods[] = {
296    /* Device interface */
297    DEVMETHOD(device_identify,	acpi_ec_identify),
298    DEVMETHOD(device_probe,	acpi_ec_probe),
299    DEVMETHOD(device_attach,	acpi_ec_attach),
300
301    {0, 0}
302};
303
304static driver_t acpi_ec_driver = {
305    "acpi_ec",
306    acpi_ec_methods,
307    sizeof(struct acpi_ec_softc),
308};
309
310devclass_t acpi_ec_devclass;
311DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
312
313/*
314 * Look for an ECDT table and if we find one, set up a default EC
315 * space handler to catch possible attempts to access EC space before
316 * we have a real driver instance in place.
317 * We're not really an identify routine, but because we get called
318 * before most other things, this works out OK.
319 */
320static void
321acpi_ec_identify(driver_t driver, device_t bus)
322{
323    FUNCTION_TRACE(__func__);
324
325    /* XXX implement - need an ACPI 2.0 system to test this */
326
327    return_VOID;
328}
329
330/*
331 * We could setup resources in the probe routine in order to have them printed
332 * when the device is attached.
333 */
334static int
335acpi_ec_probe(device_t dev)
336{
337
338    if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
339	!acpi_disabled("ec") &&
340	acpi_MatchHid(dev, "PNP0C09")) {
341
342	/*
343	 * Set device description
344	 */
345	device_set_desc(dev, "embedded controller");
346
347	return(0);
348    }
349    return(ENXIO);
350}
351
352static int
353acpi_ec_attach(device_t dev)
354{
355    struct acpi_ec_softc	*sc;
356    ACPI_STATUS			Status;
357
358    FUNCTION_TRACE(__func__);
359
360    /*
361     * Fetch/initialise softc
362     */
363    sc = device_get_softc(dev);
364    bzero(sc, sizeof(*sc));
365    sc->ec_dev = dev;
366    sc->ec_handle = acpi_get_handle(dev);
367
368    /*
369     * Evaluate resources
370     */
371    DEBUG_PRINT(TRACE_RESOURCES, ("parsing EC resources\n"));
372    acpi_parse_resources(sc->ec_dev, sc->ec_handle, &acpi_res_parse_set);
373
374    /*
375     * Attach bus resources
376     */
377    sc->ec_data_rid = 0;
378    if ((sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_data_rid,
379					      0, ~0, 1, RF_ACTIVE)) == NULL) {
380	device_printf(dev, "can't allocate data port\n");
381	return_VALUE(ENXIO);
382    }
383    sc->ec_data_tag = rman_get_bustag(sc->ec_data_res);
384    sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res);
385
386    sc->ec_csr_rid = 1;
387    if ((sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_csr_rid,
388					     0, ~0, 1, RF_ACTIVE)) == NULL) {
389	device_printf(dev, "can't allocate command/status port\n");
390	return_VALUE(ENXIO);
391    }
392    sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res);
393    sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res);
394
395    /*
396     * Install GPE handler
397     *
398     * Evaluate the _GPE method to find the GPE bit used by the EC to signal
399     * status (SCI).
400     */
401    DEBUG_PRINT(TRACE_RESOURCES, ("attaching GPE\n"));
402    if ((Status = acpi_EvaluateInteger(sc->ec_handle, "_GPE", &sc->ec_gpebit)) != AE_OK) {
403	device_printf(dev, "can't evaluate _GPE - %s\n", acpi_strerror(Status));
404	return_VALUE(ENXIO);
405    }
406
407    /*
408     * Install a handler for this EC's GPE bit.  Note that EC SCIs are
409     * treated as both edge- and level-triggered interrupts; in other words
410     * we clear the status bit immediately after getting an EC-SCI, then
411     * again after we're done processing the event.  This guarantees that
412     * events we cause while performing a transaction (e.g. IBE/OBF) get
413     * cleared before re-enabling the GPE.
414     */
415    if ((Status = AcpiInstallGpeHandler(sc->ec_gpebit, ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED,
416					EcGpeHandler, sc)) != AE_OK) {
417	device_printf(dev, "can't install GPE handler for %s - %s\n",
418		      acpi_name(sc->ec_handle), acpi_strerror(Status));
419	return_VALUE(ENXIO);
420    }
421
422    /*
423     * Install address space handler
424     */
425    DEBUG_PRINT(TRACE_RESOURCES, ("attaching address space handler\n"));
426    if ((Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ACPI_ADR_SPACE_EC,
427						 EcSpaceHandler, EcSpaceSetup, sc)) != AE_OK) {
428	device_printf(dev, "can't install address space handler for %s - %s\n",
429		      acpi_name(sc->ec_handle), acpi_strerror(Status));
430	panic("very suck");
431	return_VALUE(ENXIO);
432    }
433    DEBUG_PRINT(TRACE_RESOURCES, ("attach complete\n"));
434
435    return_VALUE(0);
436}
437
438static void
439EcGpeQueryHandler(void *Context)
440{
441    struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
442    UINT8			Data;
443    ACPI_STATUS			Status;
444    char			qxx[5];
445
446    FUNCTION_TRACE(__func__);
447
448    for (;;) {
449
450	/*
451	 * Check EC_SCI.
452	 *
453	 * Bail out if the EC_SCI bit of the status register is not set.
454	 * Note that this function should only be called when
455	 * this bit is set (polling is used to detect IBE/OBF events).
456	 *
457	 * It is safe to do this without locking the controller, as it's
458	 * OK to call EcQuery when there's no data ready; in the worst
459	 * case we should just find nothing waiting for us and bail.
460	 */
461	if (!(EC_GET_CSR(sc) & EC_EVENT_SCI))
462	    break;
463
464	/*
465	 * Find out why the EC is signalling us
466	 */
467	Status = EcQuery(sc, &Data);
468
469	/*
470	 * If we failed to get anything from the EC, give up
471	 */
472	if (Status != AE_OK) {
473	    device_printf(sc->ec_dev, "GPE query failed - %s\n", acpi_strerror(Status));
474	    break;
475	}
476
477	/*
478	 * Evaluate _Qxx to respond to the controller.
479	 */
480	sprintf(qxx, "_Q%02x", Data);
481	strupr(qxx);
482	Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL);
483	/*
484	 * Ignore spurious query requests.
485	 */
486	if (Status != AE_OK && (Data != 0 || Status != AE_NOT_FOUND)) {
487	    device_printf(sc->ec_dev, "evaluation of GPE query method %s failed - %s\n",
488			  qxx, acpi_strerror(Status));
489	}
490    }
491        /* I know I request Level trigger cleanup */
492    if(AcpiClearEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
493	    printf("EcGpeQueryHandler:ClearEvent Failed\n");
494    if(AcpiEnableEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
495	    printf("EcGpeQueryHandler:EnableEvent Failed\n");
496    return_VOID;
497}
498
499/*
500 * Handle a GPE sent to us.
501 */
502static void
503EcGpeHandler(void *Context)
504{
505    struct acpi_ec_softc *sc = Context;
506    int csrvalue;
507
508    /*
509     * If EC is locked, the intr must process EcRead/Write wait only.
510     * Query request must be pending.
511     */
512    if (EcIsLocked(sc)){
513	csrvalue = EC_GET_CSR(sc);
514	if (csrvalue & EC_EVENT_SCI)
515	    sc->ec_pendquery = 1;
516	if ((csrvalue & EC_FLAG_OUTPUT_BUFFER)
517	    || !(csrvalue & EC_FLAG_INPUT_BUFFER)) {
518	    sc->ec_csrvalue = csrvalue;
519	    wakeup((void *)&sc->ec_csrvalue);
520	}
521    }else{
522	/* Queue GpeQuery Handler */
523	if (AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
524				    EcGpeQueryHandler,Context) != AE_OK){
525	    printf("QueryHandler Queuing Failed\n");
526	}
527    }
528    return;
529}
530
531static ACPI_STATUS
532EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, void **RegionContext)
533{
534
535    FUNCTION_TRACE(__func__);
536
537    /*
538     * Just pass the context through, there's nothing to do here.
539     */
540    *RegionContext = Context;
541
542    return_ACPI_STATUS(AE_OK);
543}
544
545static ACPI_STATUS
546EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
547	       void *Context, void *RegionContext)
548{
549    struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
550    ACPI_STATUS			Status = AE_OK;
551    EC_REQUEST			EcRequest;
552    int				i;
553
554    FUNCTION_TRACE_U32(__func__, (UINT32)Address);
555
556    if ((Address > 0xFF) || (width % 8 != 0) || (Value == NULL) || (Context == NULL))
557        return_ACPI_STATUS(AE_BAD_PARAMETER);
558
559    switch (Function) {
560    case ACPI_READ_ADR_SPACE:
561        EcRequest.Command = EC_COMMAND_READ;
562        EcRequest.Address = Address;
563	(*Value) = 0;
564        break;
565
566    case ACPI_WRITE_ADR_SPACE:
567        EcRequest.Command = EC_COMMAND_WRITE;
568        EcRequest.Address = Address;
569        break;
570
571    default:
572	device_printf(sc->ec_dev, "invalid Address Space function %d\n", Function);
573        return_ACPI_STATUS(AE_BAD_PARAMETER);
574    }
575
576    /*
577     * Perform the transaction.
578     */
579    for (i = 0; i < width; i += 8) {
580	if (Function == ACPI_READ_ADR_SPACE)
581	    EcRequest.Data = 0;
582	else
583	    EcRequest.Data = (UINT8)((*Value) >> i);
584	if ((Status = EcTransaction(sc, &EcRequest)) != AE_OK)
585	    break;
586        (*Value) |= (UINT32)EcRequest.Data << i;
587	if (++EcRequest.Address == 0)
588            return_ACPI_STATUS(AE_BAD_PARAMETER);
589    }
590    return_ACPI_STATUS(Status);
591}
592
593/*
594 * Wait for an event interrupt for a specific condition.
595 */
596static ACPI_STATUS
597EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event)
598{
599    EC_STATUS	EcStatus;
600    int		i;
601
602    FUNCTION_TRACE_U32(__func__, (UINT32)Event);
603
604    /* XXX this should test whether interrupts are available some other way */
605    if(cold)
606	return_ACPI_STATUS(EcWaitEvent(sc, Event));
607
608    if (!EcIsLocked(sc))
609	device_printf(sc->ec_dev, "EcWaitEventIntr called without EC lock!\n");
610
611    EcStatus = EC_GET_CSR(sc);
612
613    /* XXX waiting too long? */
614    for(i = 0; i < 10; i++){
615	/*
616	 * Check EC status against the desired event.
617	 */
618    	if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
619	    (EcStatus & EC_FLAG_OUTPUT_BUFFER))
620	    return_ACPI_STATUS(AE_OK);
621
622	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
623	    !(EcStatus & EC_FLAG_INPUT_BUFFER))
624	    return_ACPI_STATUS(AE_OK);
625
626	sc->ec_csrvalue = 0;
627	if (ACPI_MSLEEP(&sc->ec_csrvalue, &acpi_mutex, PZERO, "EcWait", 1) != EWOULDBLOCK){
628	    EcStatus = sc->ec_csrvalue;
629	}else{
630	    EcStatus = EC_GET_CSR(sc);
631	}
632    }
633    return_ACPI_STATUS(AE_ERROR);
634}
635
636static ACPI_STATUS
637EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
638{
639    EC_STATUS	EcStatus;
640    UINT32	i = 0;
641
642    if (!EcIsLocked(sc))
643	device_printf(sc->ec_dev, "EcWaitEvent called without EC lock!\n");
644
645    /*
646     * Stall 1us:
647     * ----------
648     * Stall for 1 microsecond before reading the status register
649     * for the first time.  This allows the EC to set the IBF/OBF
650     * bit to its proper state.
651     *
652     * XXX it is not clear why we read the CSR twice.
653     */
654    AcpiOsStall(1);
655    EcStatus = EC_GET_CSR(sc);
656
657    /*
658     * Wait For Event:
659     * ---------------
660     * Poll the EC status register to detect completion of the last
661     * command.  Wait up to 10ms (in 10us chunks) for this to occur.
662     */
663    for (i = 0; i < 1000; i++) {
664	EcStatus = EC_GET_CSR(sc);
665
666        if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
667            (EcStatus & EC_FLAG_OUTPUT_BUFFER))
668	    return(AE_OK);
669
670	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
671            !(EcStatus & EC_FLAG_INPUT_BUFFER))
672	    return(AE_OK);
673
674	AcpiOsStall(10);
675    }
676
677    return(AE_ERROR);
678}
679
680static ACPI_STATUS
681EcQuery(struct acpi_ec_softc *sc, UINT8 *Data)
682{
683    ACPI_STATUS	Status;
684
685    if ((Status = EcLock(sc)) != AE_OK)
686	return(Status);
687
688    EC_SET_CSR(sc, EC_COMMAND_QUERY);
689    Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL);
690    if (Status == AE_OK)
691	*Data = EC_GET_DATA(sc);
692
693    EcUnlock(sc);
694
695    if (Status != AE_OK)
696	device_printf(sc->ec_dev, "timeout waiting for EC to respond to EC_COMMAND_QUERY\n");
697    return(Status);
698}
699
700static ACPI_STATUS
701EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
702{
703    ACPI_STATUS	Status;
704
705    /*
706     * Lock the EC
707     */
708    if ((Status = EcLock(sc)) != AE_OK)
709	return(Status);
710
711    /*
712     * Perform the transaction.
713     */
714    switch (EcRequest->Command) {
715    case EC_COMMAND_READ:
716	Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data));
717	break;
718
719    case EC_COMMAND_WRITE:
720	Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data));
721	break;
722
723    default:
724	Status = AE_SUPPORT;
725	break;
726    }
727
728    /*
729     * Unlock the EC
730     */
731    EcUnlock(sc);
732
733    /*
734     * Clear & Re-Enable the EC GPE:
735     * -----------------------------
736     * 'Consume' any EC GPE events that we generated while performing
737     * the transaction (e.g. IBF/OBF).	Clearing the GPE here shouldn't
738     * have an adverse affect on outstanding EC-SCI's, as the source
739     * (EC-SCI) will still be high and thus should trigger the GPE
740     * immediately after we re-enabling it.
741     */
742    if (sc->ec_pendquery){
743	    if(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
744		EcGpeQueryHandler, sc) != AE_OK)
745		    printf("Pend Query Queuing Failed\n");
746	    sc->ec_pendquery = 0;
747    }
748
749    if (AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
750	device_printf(sc->ec_dev, "EcRequest: Unable to clear the EC GPE.\n");
751    if (AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
752	device_printf(sc->ec_dev, "EcRequest: Unable to re-enable the EC GPE.\n");
753
754    return(Status);
755}
756
757
758static ACPI_STATUS
759EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
760{
761    ACPI_STATUS	Status;
762
763    if (!EcIsLocked(sc))
764	device_printf(sc->ec_dev, "EcRead called without EC lock!\n");
765
766    /*EcBurstEnable(EmbeddedController);*/
767
768    EC_SET_CSR(sc, EC_COMMAND_READ);
769    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
770	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process read command.\n");
771	return(Status);
772    }
773
774    EC_SET_DATA(sc, Address);
775    if ((Status = EcWaitEventIntr(sc, EC_EVENT_OUTPUT_BUFFER_FULL)) != AE_OK) {
776	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to send data.\n");
777	return(Status);
778    }
779
780    (*Data) = EC_GET_DATA(sc);
781
782    /*EcBurstDisable(EmbeddedController);*/
783
784    return(AE_OK);
785}
786
787static ACPI_STATUS
788EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
789{
790    ACPI_STATUS	Status;
791
792    if (!EcIsLocked(sc))
793	device_printf(sc->ec_dev, "EcWrite called without EC lock!\n");
794
795    /*EcBurstEnable(EmbeddedController);*/
796
797    EC_SET_CSR(sc, EC_COMMAND_WRITE);
798    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
799	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process write command.\n");
800	return(Status);
801    }
802
803    EC_SET_DATA(sc, Address);
804    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
805	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process address.\n");
806	return(Status);
807    }
808
809    EC_SET_DATA(sc, *Data);
810    if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
811	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process data.\n");
812	return(Status);
813    }
814
815    /*EcBurstDisable(EmbeddedController);*/
816
817    return(AE_OK);
818}
819