xref: /freebsd/sys/dev/acpica/acpi_ec.c (revision bfae45aa43bd0201341d5ffbbfb983d19f35a0e8)
115e32d5dSMike Smith /*-
215e32d5dSMike Smith  * Copyright (c) 2000 Michael Smith
315e32d5dSMike Smith  * Copyright (c) 2000 BSDi
415e32d5dSMike Smith  * All rights reserved.
515e32d5dSMike Smith  *
615e32d5dSMike Smith  * Redistribution and use in source and binary forms, with or without
715e32d5dSMike Smith  * modification, are permitted provided that the following conditions
815e32d5dSMike Smith  * are met:
915e32d5dSMike Smith  * 1. Redistributions of source code must retain the above copyright
1015e32d5dSMike Smith  *    notice, this list of conditions and the following disclaimer.
1115e32d5dSMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
1215e32d5dSMike Smith  *    notice, this list of conditions and the following disclaimer in the
1315e32d5dSMike Smith  *    documentation and/or other materials provided with the distribution.
1415e32d5dSMike Smith  *
1515e32d5dSMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1615e32d5dSMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1715e32d5dSMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1815e32d5dSMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1915e32d5dSMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2015e32d5dSMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2115e32d5dSMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2215e32d5dSMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2315e32d5dSMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2415e32d5dSMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2515e32d5dSMike Smith  * SUCH DAMAGE.
2615e32d5dSMike Smith  *
2715e32d5dSMike Smith  *	$FreeBSD$
2815e32d5dSMike Smith  */
2915e32d5dSMike Smith /******************************************************************************
3015e32d5dSMike Smith  *
3115e32d5dSMike Smith  * 1. Copyright Notice
3215e32d5dSMike Smith  *
3315e32d5dSMike Smith  * Some or all of this work - Copyright (c) 1999, Intel Corp.  All rights
3415e32d5dSMike Smith  * reserved.
3515e32d5dSMike Smith  *
3615e32d5dSMike Smith  * 2. License
3715e32d5dSMike Smith  *
3815e32d5dSMike Smith  * 2.1. This is your license from Intel Corp. under its intellectual property
3915e32d5dSMike Smith  * rights.  You may have additional license terms from the party that provided
4015e32d5dSMike Smith  * you this software, covering your right to use that party's intellectual
4115e32d5dSMike Smith  * property rights.
4215e32d5dSMike Smith  *
4315e32d5dSMike Smith  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
4415e32d5dSMike Smith  * copy of the source code appearing in this file ("Covered Code") an
4515e32d5dSMike Smith  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
4615e32d5dSMike Smith  * base code distributed originally by Intel ("Original Intel Code") to copy,
4715e32d5dSMike Smith  * make derivatives, distribute, use and display any portion of the Covered
4815e32d5dSMike Smith  * Code in any form, with the right to sublicense such rights; and
4915e32d5dSMike Smith  *
5015e32d5dSMike Smith  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
5115e32d5dSMike Smith  * license (with the right to sublicense), under only those claims of Intel
5215e32d5dSMike Smith  * patents that are infringed by the Original Intel Code, to make, use, sell,
5315e32d5dSMike Smith  * offer to sell, and import the Covered Code and derivative works thereof
5415e32d5dSMike Smith  * solely to the minimum extent necessary to exercise the above copyright
5515e32d5dSMike Smith  * license, and in no event shall the patent license extend to any additions
5615e32d5dSMike Smith  * to or modifications of the Original Intel Code.  No other license or right
5715e32d5dSMike Smith  * is granted directly or by implication, estoppel or otherwise;
5815e32d5dSMike Smith  *
5915e32d5dSMike Smith  * The above copyright and patent license is granted only if the following
6015e32d5dSMike Smith  * conditions are met:
6115e32d5dSMike Smith  *
6215e32d5dSMike Smith  * 3. Conditions
6315e32d5dSMike Smith  *
6415e32d5dSMike Smith  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
6515e32d5dSMike Smith  * Redistribution of source code of any substantial portion of the Covered
6615e32d5dSMike Smith  * Code or modification with rights to further distribute source must include
6715e32d5dSMike Smith  * the above Copyright Notice, the above License, this list of Conditions,
6815e32d5dSMike Smith  * and the following Disclaimer and Export Compliance provision.  In addition,
6915e32d5dSMike Smith  * Licensee must cause all Covered Code to which Licensee contributes to
7015e32d5dSMike Smith  * contain a file documenting the changes Licensee made to create that Covered
7115e32d5dSMike Smith  * Code and the date of any change.  Licensee must include in that file the
7215e32d5dSMike Smith  * documentation of any changes made by any predecessor Licensee.  Licensee
7315e32d5dSMike Smith  * must include a prominent statement that the modification is derived,
7415e32d5dSMike Smith  * directly or indirectly, from Original Intel Code.
7515e32d5dSMike Smith  *
7615e32d5dSMike Smith  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
7715e32d5dSMike Smith  * Redistribution of source code of any substantial portion of the Covered
7815e32d5dSMike Smith  * Code or modification without rights to further distribute source must
7915e32d5dSMike Smith  * include the following Disclaimer and Export Compliance provision in the
8015e32d5dSMike Smith  * documentation and/or other materials provided with distribution.  In
8115e32d5dSMike Smith  * addition, Licensee may not authorize further sublicense of source of any
8215e32d5dSMike Smith  * portion of the Covered Code, and must include terms to the effect that the
8315e32d5dSMike Smith  * license from Licensee to its licensee is limited to the intellectual
8415e32d5dSMike Smith  * property embodied in the software Licensee provides to its licensee, and
8515e32d5dSMike Smith  * not to intellectual property embodied in modifications its licensee may
8615e32d5dSMike Smith  * make.
8715e32d5dSMike Smith  *
8815e32d5dSMike Smith  * 3.3. Redistribution of Executable. Redistribution in executable form of any
8915e32d5dSMike Smith  * substantial portion of the Covered Code or modification must reproduce the
9015e32d5dSMike Smith  * above Copyright Notice, and the following Disclaimer and Export Compliance
9115e32d5dSMike Smith  * provision in the documentation and/or other materials provided with the
9215e32d5dSMike Smith  * distribution.
9315e32d5dSMike Smith  *
9415e32d5dSMike Smith  * 3.4. Intel retains all right, title, and interest in and to the Original
9515e32d5dSMike Smith  * Intel Code.
9615e32d5dSMike Smith  *
9715e32d5dSMike Smith  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
9815e32d5dSMike Smith  * Intel shall be used in advertising or otherwise to promote the sale, use or
9915e32d5dSMike Smith  * other dealings in products derived from or relating to the Covered Code
10015e32d5dSMike Smith  * without prior written authorization from Intel.
10115e32d5dSMike Smith  *
10215e32d5dSMike Smith  * 4. Disclaimer and Export Compliance
10315e32d5dSMike Smith  *
10415e32d5dSMike Smith  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
10515e32d5dSMike Smith  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
10615e32d5dSMike Smith  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
10715e32d5dSMike Smith  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
10815e32d5dSMike Smith  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
10915e32d5dSMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
11015e32d5dSMike Smith  * PARTICULAR PURPOSE.
11115e32d5dSMike Smith  *
11215e32d5dSMike Smith  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
11315e32d5dSMike Smith  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
11415e32d5dSMike Smith  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
11515e32d5dSMike Smith  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
11615e32d5dSMike Smith  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
11715e32d5dSMike Smith  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
11815e32d5dSMike Smith  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
11915e32d5dSMike Smith  * LIMITED REMEDY.
12015e32d5dSMike Smith  *
12115e32d5dSMike Smith  * 4.3. Licensee shall not export, either directly or indirectly, any of this
12215e32d5dSMike Smith  * software or system incorporating such software without first obtaining any
12315e32d5dSMike Smith  * required license or other approval from the U. S. Department of Commerce or
12415e32d5dSMike Smith  * any other agency or department of the United States Government.  In the
12515e32d5dSMike Smith  * event Licensee exports any such software from the United States or
12615e32d5dSMike Smith  * re-exports any such software from a foreign destination, Licensee shall
12715e32d5dSMike Smith  * ensure that the distribution and export/re-export of the software is in
12815e32d5dSMike Smith  * compliance with all laws, regulations, orders, or other restrictions of the
12915e32d5dSMike Smith  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
13015e32d5dSMike Smith  * any of its subsidiaries will export/re-export any technical data, process,
13115e32d5dSMike Smith  * software, or service, directly or indirectly, to any country for which the
13215e32d5dSMike Smith  * United States government or any agency thereof requires an export license,
13315e32d5dSMike Smith  * other governmental approval, or letter of assurance, without first obtaining
13415e32d5dSMike Smith  * such license, approval or letter.
13515e32d5dSMike Smith  *
13615e32d5dSMike Smith  *****************************************************************************/
13715e32d5dSMike Smith 
13815e32d5dSMike Smith #include "opt_acpi.h"
13915e32d5dSMike Smith #include <sys/param.h>
14015e32d5dSMike Smith #include <sys/kernel.h>
14115e32d5dSMike Smith #include <sys/bus.h>
14215e32d5dSMike Smith 
14315e32d5dSMike Smith #include <machine/bus.h>
14415e32d5dSMike Smith #include <machine/resource.h>
14515e32d5dSMike Smith #include <sys/rman.h>
14615e32d5dSMike Smith 
14715e32d5dSMike Smith #include "acpi.h"
14815e32d5dSMike Smith 
14915e32d5dSMike Smith #include <dev/acpica/acpivar.h>
15015e32d5dSMike Smith 
1510ae55423SMike Smith /*
1520ae55423SMike Smith  * Hooks for the ACPI CA debugging infrastructure
1530ae55423SMike Smith  */
154a9cf0dffSMike Smith #define _COMPONENT	ACPI_EC
1550ae55423SMike Smith MODULE_NAME("EC")
1560ae55423SMike Smith 
157da3b867eSMike Smith /*
158da3b867eSMike Smith  * EC_COMMAND:
159da3b867eSMike Smith  * -----------
160da3b867eSMike Smith  */
161da3b867eSMike Smith typedef UINT8				EC_COMMAND;
162da3b867eSMike Smith 
163da3b867eSMike Smith #define EC_COMMAND_UNKNOWN		((EC_COMMAND) 0x00)
164da3b867eSMike Smith #define EC_COMMAND_READ			((EC_COMMAND) 0x80)
165da3b867eSMike Smith #define EC_COMMAND_WRITE		((EC_COMMAND) 0x81)
166da3b867eSMike Smith #define EC_COMMAND_BURST_ENABLE		((EC_COMMAND) 0x82)
167da3b867eSMike Smith #define EC_COMMAND_BURST_DISABLE	((EC_COMMAND) 0x83)
168da3b867eSMike Smith #define EC_COMMAND_QUERY		((EC_COMMAND) 0x84)
169da3b867eSMike Smith 
170da3b867eSMike Smith /*
171da3b867eSMike Smith  * EC_STATUS:
172da3b867eSMike Smith  * ----------
173da3b867eSMike Smith  * The encoding of the EC status register is illustrated below.
174da3b867eSMike Smith  * Note that a set bit (1) indicates the property is TRUE
175da3b867eSMike Smith  * (e.g. if bit 0 is set then the output buffer is full).
176da3b867eSMike Smith  * +-+-+-+-+-+-+-+-+
177da3b867eSMike Smith  * |7|6|5|4|3|2|1|0|
178da3b867eSMike Smith  * +-+-+-+-+-+-+-+-+
179da3b867eSMike Smith  *  | | | | | | | |
180da3b867eSMike Smith  *  | | | | | | | +- Output Buffer Full?
181da3b867eSMike Smith  *  | | | | | | +--- Input Buffer Full?
182da3b867eSMike Smith  *  | | | | | +----- <reserved>
183da3b867eSMike Smith  *  | | | | +------- Data Register is Command Byte?
184da3b867eSMike Smith  *  | | | +--------- Burst Mode Enabled?
185da3b867eSMike Smith  *  | | +----------- SCI Event?
186da3b867eSMike Smith  *  | +------------- SMI Event?
187da3b867eSMike Smith  *  +--------------- <Reserved>
188da3b867eSMike Smith  *
189da3b867eSMike Smith  */
190da3b867eSMike Smith typedef UINT8				EC_STATUS;
191da3b867eSMike Smith 
192da3b867eSMike Smith #define EC_FLAG_OUTPUT_BUFFER		((EC_STATUS) 0x01)
193da3b867eSMike Smith #define EC_FLAG_INPUT_BUFFER		((EC_STATUS) 0x02)
194da3b867eSMike Smith #define EC_FLAG_BURST_MODE		((EC_STATUS) 0x10)
195da3b867eSMike Smith #define EC_FLAG_SCI			((EC_STATUS) 0x20)
196da3b867eSMike Smith 
197da3b867eSMike Smith /*
198da3b867eSMike Smith  * EC_EVENT:
199da3b867eSMike Smith  * ---------
200da3b867eSMike Smith  */
201da3b867eSMike Smith typedef UINT8				EC_EVENT;
202da3b867eSMike Smith 
203da3b867eSMike Smith #define EC_EVENT_UNKNOWN		((EC_EVENT) 0x00)
204da3b867eSMike Smith #define EC_EVENT_OUTPUT_BUFFER_FULL	((EC_EVENT) 0x01)
205da3b867eSMike Smith #define EC_EVENT_INPUT_BUFFER_EMPTY	((EC_EVENT) 0x02)
206da3b867eSMike Smith #define EC_EVENT_SCI			((EC_EVENT) 0x20)
207da3b867eSMike Smith 
208da3b867eSMike Smith /*
209da3b867eSMike Smith  * Register access primitives
210da3b867eSMike Smith  */
211da3b867eSMike Smith #define EC_GET_DATA(sc)							\
212da3b867eSMike Smith 	bus_space_read_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0)
213da3b867eSMike Smith 
214da3b867eSMike Smith #define EC_SET_DATA(sc, v)						\
215da3b867eSMike Smith 	bus_space_write_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0, (v))
216da3b867eSMike Smith 
217da3b867eSMike Smith #define EC_GET_CSR(sc)							\
218da3b867eSMike Smith 	bus_space_read_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0)
219da3b867eSMike Smith 
220da3b867eSMike Smith #define EC_SET_CSR(sc, v)						\
221da3b867eSMike Smith 	bus_space_write_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0, (v))
222da3b867eSMike Smith 
223da3b867eSMike Smith /*
224da3b867eSMike Smith  * Driver softc.
225da3b867eSMike Smith  */
22615e32d5dSMike Smith struct acpi_ec_softc {
22715e32d5dSMike Smith     device_t		ec_dev;
22815e32d5dSMike Smith     ACPI_HANDLE		ec_handle;
22915e32d5dSMike Smith     UINT32		ec_gpebit;
23015e32d5dSMike Smith 
23115e32d5dSMike Smith     int			ec_data_rid;
23215e32d5dSMike Smith     struct resource	*ec_data_res;
23315e32d5dSMike Smith     bus_space_tag_t	ec_data_tag;
23415e32d5dSMike Smith     bus_space_handle_t	ec_data_handle;
23515e32d5dSMike Smith 
23615e32d5dSMike Smith     int			ec_csr_rid;
23715e32d5dSMike Smith     struct resource	*ec_csr_res;
23815e32d5dSMike Smith     bus_space_tag_t	ec_csr_tag;
23915e32d5dSMike Smith     bus_space_handle_t	ec_csr_handle;
24015e32d5dSMike Smith 
24115e32d5dSMike Smith     int			ec_locked;
242c07572e7STakanori Watanabe     int			ec_pendquery;
243c07572e7STakanori Watanabe     int			ec_csrvalue;
24415e32d5dSMike Smith };
24515e32d5dSMike Smith 
24615e32d5dSMike Smith #define EC_LOCK_TIMEOUT	1000	/* 1ms */
24715e32d5dSMike Smith 
24815e32d5dSMike Smith static __inline ACPI_STATUS
24915e32d5dSMike Smith EcLock(struct acpi_ec_softc *sc)
25015e32d5dSMike Smith {
25115e32d5dSMike Smith     ACPI_STATUS	status;
25215e32d5dSMike Smith 
2537a1d55dfSTakanori Watanabe     status = AcpiAcquireGlobalLock();
25415e32d5dSMike Smith     (sc)->ec_locked = 1;
25515e32d5dSMike Smith     return(status);
25615e32d5dSMike Smith }
25715e32d5dSMike Smith 
25815e32d5dSMike Smith static __inline void
25915e32d5dSMike Smith EcUnlock(struct acpi_ec_softc *sc)
26015e32d5dSMike Smith {
26115e32d5dSMike Smith     (sc)->ec_locked = 0;
2627a1d55dfSTakanori Watanabe     AcpiReleaseGlobalLock();
26315e32d5dSMike Smith }
26415e32d5dSMike Smith 
26515e32d5dSMike Smith static __inline int
26615e32d5dSMike Smith EcIsLocked(struct acpi_ec_softc *sc)
26715e32d5dSMike Smith {
26815e32d5dSMike Smith     return((sc)->ec_locked != 0);
26915e32d5dSMike Smith }
27015e32d5dSMike Smith 
27115e32d5dSMike Smith typedef struct
27215e32d5dSMike Smith {
27315e32d5dSMike Smith     EC_COMMAND              Command;
27415e32d5dSMike Smith     UINT8                   Address;
27515e32d5dSMike Smith     UINT8                   Data;
27615e32d5dSMike Smith } EC_REQUEST;
27715e32d5dSMike Smith 
27815e32d5dSMike Smith static void		EcGpeHandler(void *Context);
27915e32d5dSMike Smith static ACPI_STATUS	EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function,
28015e32d5dSMike Smith 					   void *Context, void **return_Context);
281042283a6SMike Smith static ACPI_STATUS	EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
28215e32d5dSMike Smith 				      void *Context, void *RegionContext);
28315e32d5dSMike Smith 
28415e32d5dSMike Smith static ACPI_STATUS	EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event);
28515e32d5dSMike Smith static ACPI_STATUS	EcQuery(struct acpi_ec_softc *sc, UINT8 *Data);
28615e32d5dSMike Smith static ACPI_STATUS	EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest);
28715e32d5dSMike Smith static ACPI_STATUS	EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
28815e32d5dSMike Smith static ACPI_STATUS	EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
28915e32d5dSMike Smith 
29015e32d5dSMike Smith static void		acpi_ec_identify(driver_t driver, device_t bus);
29115e32d5dSMike Smith static int		acpi_ec_probe(device_t dev);
29215e32d5dSMike Smith static int		acpi_ec_attach(device_t dev);
29315e32d5dSMike Smith 
29415e32d5dSMike Smith static device_method_t acpi_ec_methods[] = {
29515e32d5dSMike Smith     /* Device interface */
29615e32d5dSMike Smith     DEVMETHOD(device_identify,	acpi_ec_identify),
29715e32d5dSMike Smith     DEVMETHOD(device_probe,	acpi_ec_probe),
29815e32d5dSMike Smith     DEVMETHOD(device_attach,	acpi_ec_attach),
29915e32d5dSMike Smith 
30015e32d5dSMike Smith     {0, 0}
30115e32d5dSMike Smith };
30215e32d5dSMike Smith 
30315e32d5dSMike Smith static driver_t acpi_ec_driver = {
30415e32d5dSMike Smith     "acpi_ec",
30515e32d5dSMike Smith     acpi_ec_methods,
30615e32d5dSMike Smith     sizeof(struct acpi_ec_softc),
30715e32d5dSMike Smith };
30815e32d5dSMike Smith 
30915e32d5dSMike Smith devclass_t acpi_ec_devclass;
31015e32d5dSMike Smith DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
31115e32d5dSMike Smith 
31215e32d5dSMike Smith /*
31315e32d5dSMike Smith  * Look for an ECDT table and if we find one, set up a default EC
31415e32d5dSMike Smith  * space handler to catch possible attempts to access EC space before
31515e32d5dSMike Smith  * we have a real driver instance in place.
31615e32d5dSMike Smith  * We're not really an identify routine, but because we get called
31715e32d5dSMike Smith  * before most other things, this works out OK.
31815e32d5dSMike Smith  */
31915e32d5dSMike Smith static void
32015e32d5dSMike Smith acpi_ec_identify(driver_t driver, device_t bus)
32115e32d5dSMike Smith {
3222a4ac806SMike Smith     FUNCTION_TRACE(__func__);
32315e32d5dSMike Smith 
32415e32d5dSMike Smith     /* XXX implement - need an ACPI 2.0 system to test this */
3250ae55423SMike Smith 
3260ae55423SMike Smith     return_VOID;
32715e32d5dSMike Smith }
32815e32d5dSMike Smith 
32915e32d5dSMike Smith /*
33015e32d5dSMike Smith  * We could setup resources in the probe routine in order to have them printed
33115e32d5dSMike Smith  * when the device is attached.
33215e32d5dSMike Smith  */
33315e32d5dSMike Smith static int
33415e32d5dSMike Smith acpi_ec_probe(device_t dev)
33515e32d5dSMike Smith {
3360ae55423SMike Smith 
33715e32d5dSMike Smith     if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
3380ae55423SMike Smith 	!acpi_disabled("ec") &&
33915e32d5dSMike Smith 	acpi_MatchHid(dev, "PNP0C09")) {
34015e32d5dSMike Smith 
34115e32d5dSMike Smith 	/*
34215e32d5dSMike Smith 	 * Set device description
34315e32d5dSMike Smith 	 */
34415e32d5dSMike Smith 	device_set_desc(dev, "embedded controller");
34515e32d5dSMike Smith 
34615e32d5dSMike Smith 	return(0);
34715e32d5dSMike Smith     }
34815e32d5dSMike Smith     return(ENXIO);
34915e32d5dSMike Smith }
35015e32d5dSMike Smith 
35115e32d5dSMike Smith static int
35215e32d5dSMike Smith acpi_ec_attach(device_t dev)
35315e32d5dSMike Smith {
35415e32d5dSMike Smith     struct acpi_ec_softc	*sc;
35515e32d5dSMike Smith     ACPI_STATUS			Status;
35615e32d5dSMike Smith 
3572a4ac806SMike Smith     FUNCTION_TRACE(__func__);
3580ae55423SMike Smith 
35915e32d5dSMike Smith     /*
36015e32d5dSMike Smith      * Fetch/initialise softc
36115e32d5dSMike Smith      */
36215e32d5dSMike Smith     sc = device_get_softc(dev);
363c07572e7STakanori Watanabe     bzero(sc, sizeof(*sc));
36415e32d5dSMike Smith     sc->ec_dev = dev;
36515e32d5dSMike Smith     sc->ec_handle = acpi_get_handle(dev);
36615e32d5dSMike Smith 
36715e32d5dSMike Smith     /*
36815e32d5dSMike Smith      * Evaluate resources
36915e32d5dSMike Smith      */
37042f6d122SMike Smith     DEBUG_PRINT(TRACE_RESOURCES, ("parsing EC resources\n"));
37115e32d5dSMike Smith     acpi_parse_resources(sc->ec_dev, sc->ec_handle, &acpi_res_parse_set);
37215e32d5dSMike Smith 
37315e32d5dSMike Smith     /*
37415e32d5dSMike Smith      * Attach bus resources
37515e32d5dSMike Smith      */
37615e32d5dSMike Smith     sc->ec_data_rid = 0;
37715e32d5dSMike Smith     if ((sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_data_rid,
37815e32d5dSMike Smith 					      0, ~0, 1, RF_ACTIVE)) == NULL) {
37915e32d5dSMike Smith 	device_printf(dev, "can't allocate data port\n");
3800ae55423SMike Smith 	return_VALUE(ENXIO);
38115e32d5dSMike Smith     }
38215e32d5dSMike Smith     sc->ec_data_tag = rman_get_bustag(sc->ec_data_res);
38315e32d5dSMike Smith     sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res);
38415e32d5dSMike Smith 
38515e32d5dSMike Smith     sc->ec_csr_rid = 1;
38615e32d5dSMike Smith     if ((sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_csr_rid,
38715e32d5dSMike Smith 					     0, ~0, 1, RF_ACTIVE)) == NULL) {
38815e32d5dSMike Smith 	device_printf(dev, "can't allocate command/status port\n");
3890ae55423SMike Smith 	return_VALUE(ENXIO);
39015e32d5dSMike Smith     }
39115e32d5dSMike Smith     sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res);
39215e32d5dSMike Smith     sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res);
39315e32d5dSMike Smith 
39415e32d5dSMike Smith     /*
39515e32d5dSMike Smith      * Install GPE handler
39615e32d5dSMike Smith      *
39715e32d5dSMike Smith      * Evaluate the _GPE method to find the GPE bit used by the EC to signal
39815e32d5dSMike Smith      * status (SCI).
39915e32d5dSMike Smith      */
40042f6d122SMike Smith     DEBUG_PRINT(TRACE_RESOURCES, ("attaching GPE\n"));
40142f6d122SMike Smith     if ((Status = acpi_EvaluateInteger(sc->ec_handle, "_GPE", &sc->ec_gpebit)) != AE_OK) {
402bfae45aaSMike Smith 	device_printf(dev, "can't evaluate _GPE - %s\n", AcpiFormatException(Status));
4030ae55423SMike Smith 	return_VALUE(ENXIO);
40415e32d5dSMike Smith     }
40515e32d5dSMike Smith 
40615e32d5dSMike Smith     /*
40715e32d5dSMike Smith      * Install a handler for this EC's GPE bit.  Note that EC SCIs are
40815e32d5dSMike Smith      * treated as both edge- and level-triggered interrupts; in other words
40915e32d5dSMike Smith      * we clear the status bit immediately after getting an EC-SCI, then
41015e32d5dSMike Smith      * again after we're done processing the event.  This guarantees that
41115e32d5dSMike Smith      * events we cause while performing a transaction (e.g. IBE/OBF) get
41215e32d5dSMike Smith      * cleared before re-enabling the GPE.
41315e32d5dSMike Smith      */
41415e32d5dSMike Smith     if ((Status = AcpiInstallGpeHandler(sc->ec_gpebit, ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED,
41515e32d5dSMike Smith 					EcGpeHandler, sc)) != AE_OK) {
41676d1dff4SMike Smith 	device_printf(dev, "can't install GPE handler for %s - %s\n",
417bfae45aaSMike Smith 		      acpi_name(sc->ec_handle), AcpiFormatException(Status));
4180ae55423SMike Smith 	return_VALUE(ENXIO);
41915e32d5dSMike Smith     }
42015e32d5dSMike Smith 
42115e32d5dSMike Smith     /*
42215e32d5dSMike Smith      * Install address space handler
42315e32d5dSMike Smith      */
42442f6d122SMike Smith     DEBUG_PRINT(TRACE_RESOURCES, ("attaching address space handler\n"));
4252a4ac806SMike Smith     if ((Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ACPI_ADR_SPACE_EC,
42642f6d122SMike Smith 						 EcSpaceHandler, EcSpaceSetup, sc)) != AE_OK) {
42776d1dff4SMike Smith 	device_printf(dev, "can't install address space handler for %s - %s\n",
428bfae45aaSMike Smith 		      acpi_name(sc->ec_handle), AcpiFormatException(Status));
42976d1dff4SMike Smith 	panic("very suck");
4300ae55423SMike Smith 	return_VALUE(ENXIO);
43115e32d5dSMike Smith     }
43242f6d122SMike Smith     DEBUG_PRINT(TRACE_RESOURCES, ("attach complete\n"));
43315e32d5dSMike Smith 
4340ae55423SMike Smith     return_VALUE(0);
43515e32d5dSMike Smith }
43615e32d5dSMike Smith 
43715e32d5dSMike Smith static void
438c07572e7STakanori Watanabe EcGpeQueryHandler(void *Context)
43915e32d5dSMike Smith {
44015e32d5dSMike Smith     struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
44115e32d5dSMike Smith     UINT8			Data;
44215e32d5dSMike Smith     ACPI_STATUS			Status;
44315e32d5dSMike Smith     char			qxx[5];
44415e32d5dSMike Smith 
4452a4ac806SMike Smith     FUNCTION_TRACE(__func__);
4460ae55423SMike Smith 
44715e32d5dSMike Smith     for (;;) {
44815e32d5dSMike Smith 
44915e32d5dSMike Smith 	/*
45015e32d5dSMike Smith 	 * Check EC_SCI.
45115e32d5dSMike Smith 	 *
45215e32d5dSMike Smith 	 * Bail out if the EC_SCI bit of the status register is not set.
45315e32d5dSMike Smith 	 * Note that this function should only be called when
45415e32d5dSMike Smith 	 * this bit is set (polling is used to detect IBE/OBF events).
45515e32d5dSMike Smith 	 *
45615e32d5dSMike Smith 	 * It is safe to do this without locking the controller, as it's
45715e32d5dSMike Smith 	 * OK to call EcQuery when there's no data ready; in the worst
45815e32d5dSMike Smith 	 * case we should just find nothing waiting for us and bail.
45915e32d5dSMike Smith 	 */
46015e32d5dSMike Smith 	if (!(EC_GET_CSR(sc) & EC_EVENT_SCI))
46115e32d5dSMike Smith 	    break;
46215e32d5dSMike Smith 
46315e32d5dSMike Smith 	/*
46415e32d5dSMike Smith 	 * Find out why the EC is signalling us
46515e32d5dSMike Smith 	 */
46615e32d5dSMike Smith 	Status = EcQuery(sc, &Data);
46715e32d5dSMike Smith 
46815e32d5dSMike Smith 	/*
46915e32d5dSMike Smith 	 * If we failed to get anything from the EC, give up
47015e32d5dSMike Smith 	 */
47115e32d5dSMike Smith 	if (Status != AE_OK) {
472bfae45aaSMike Smith 	    device_printf(sc->ec_dev, "GPE query failed - %s\n", AcpiFormatException(Status));
47315e32d5dSMike Smith 	    break;
47415e32d5dSMike Smith 	}
47515e32d5dSMike Smith 
47615e32d5dSMike Smith 	/*
47715e32d5dSMike Smith 	 * Evaluate _Qxx to respond to the controller.
47815e32d5dSMike Smith 	 */
47915e32d5dSMike Smith 	sprintf(qxx, "_Q%02x", Data);
48015e32d5dSMike Smith 	strupr(qxx);
481ee785aa9SJohn Baldwin 	Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL);
482ee785aa9SJohn Baldwin 	/*
483ee785aa9SJohn Baldwin 	 * Ignore spurious query requests.
484ee785aa9SJohn Baldwin 	 */
485ee785aa9SJohn Baldwin 	if (Status != AE_OK && (Data != 0 || Status != AE_NOT_FOUND)) {
48615e32d5dSMike Smith 	    device_printf(sc->ec_dev, "evaluation of GPE query method %s failed - %s\n",
487bfae45aaSMike Smith 			  qxx, AcpiFormatException(Status));
48815e32d5dSMike Smith 	}
48915e32d5dSMike Smith     }
490c07572e7STakanori Watanabe         /* I know I request Level trigger cleanup */
491c07572e7STakanori Watanabe     if(AcpiClearEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
492c07572e7STakanori Watanabe 	    printf("EcGpeQueryHandler:ClearEvent Failed\n");
493c07572e7STakanori Watanabe     if(AcpiEnableEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
494c07572e7STakanori Watanabe 	    printf("EcGpeQueryHandler:EnableEvent Failed\n");
495874d21b4STakanori Watanabe     return_VOID;
496c07572e7STakanori Watanabe }
49742f6d122SMike Smith 
498a9cf0dffSMike Smith /*
499a9cf0dffSMike Smith  * Handle a GPE sent to us.
500a9cf0dffSMike Smith  */
501a9cf0dffSMike Smith static void
502a9cf0dffSMike Smith EcGpeHandler(void *Context)
503c07572e7STakanori Watanabe {
504c07572e7STakanori Watanabe     struct acpi_ec_softc *sc = Context;
505c07572e7STakanori Watanabe     int csrvalue;
506a9cf0dffSMike Smith 
507c07572e7STakanori Watanabe     /*
508c07572e7STakanori Watanabe      * If EC is locked, the intr must process EcRead/Write wait only.
509c07572e7STakanori Watanabe      * Query request must be pending.
510c07572e7STakanori Watanabe      */
511c07572e7STakanori Watanabe     if (EcIsLocked(sc)){
512c07572e7STakanori Watanabe 	csrvalue = EC_GET_CSR(sc);
513c07572e7STakanori Watanabe 	if (csrvalue & EC_EVENT_SCI)
514c07572e7STakanori Watanabe 	    sc->ec_pendquery = 1;
515c07572e7STakanori Watanabe 	if ((csrvalue & EC_FLAG_OUTPUT_BUFFER)
516c07572e7STakanori Watanabe 	    || !(csrvalue & EC_FLAG_INPUT_BUFFER)) {
517c07572e7STakanori Watanabe 	    sc->ec_csrvalue = csrvalue;
518c07572e7STakanori Watanabe 	    wakeup((void *)&sc->ec_csrvalue);
519c07572e7STakanori Watanabe 	}
520c07572e7STakanori Watanabe     }else{
521c07572e7STakanori Watanabe 	/* Queue GpeQuery Handler */
522b37c9b90STakanori Watanabe 	if (AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
523c07572e7STakanori Watanabe 				    EcGpeQueryHandler,Context) != AE_OK){
524c07572e7STakanori Watanabe 	    printf("QueryHandler Queuing Failed\n");
525c07572e7STakanori Watanabe 	}
526c07572e7STakanori Watanabe     }
527874d21b4STakanori Watanabe     return;
52815e32d5dSMike Smith }
52915e32d5dSMike Smith 
53015e32d5dSMike Smith static ACPI_STATUS
53115e32d5dSMike Smith EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, void **RegionContext)
53215e32d5dSMike Smith {
53342f6d122SMike Smith 
5342a4ac806SMike Smith     FUNCTION_TRACE(__func__);
53542f6d122SMike Smith 
53615e32d5dSMike Smith     /*
53715e32d5dSMike Smith      * Just pass the context through, there's nothing to do here.
53815e32d5dSMike Smith      */
53915e32d5dSMike Smith     *RegionContext = Context;
54015e32d5dSMike Smith 
54142f6d122SMike Smith     return_ACPI_STATUS(AE_OK);
54215e32d5dSMike Smith }
54315e32d5dSMike Smith 
54415e32d5dSMike Smith static ACPI_STATUS
545042283a6SMike Smith EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
546042283a6SMike Smith 	       void *Context, void *RegionContext)
54715e32d5dSMike Smith {
54815e32d5dSMike Smith     struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
54915e32d5dSMike Smith     ACPI_STATUS			Status = AE_OK;
55015e32d5dSMike Smith     EC_REQUEST			EcRequest;
551ee785aa9SJohn Baldwin     int				i;
55215e32d5dSMike Smith 
5532a4ac806SMike Smith     FUNCTION_TRACE_U32(__func__, (UINT32)Address);
5540ae55423SMike Smith 
555ee785aa9SJohn Baldwin     if ((Address > 0xFF) || (width % 8 != 0) || (Value == NULL) || (Context == NULL))
5560ae55423SMike Smith         return_ACPI_STATUS(AE_BAD_PARAMETER);
55715e32d5dSMike Smith 
55815e32d5dSMike Smith     switch (Function) {
5592a4ac806SMike Smith     case ACPI_READ_ADR_SPACE:
56015e32d5dSMike Smith         EcRequest.Command = EC_COMMAND_READ;
56115e32d5dSMike Smith         EcRequest.Address = Address;
5622a4ac806SMike Smith 	(*Value) = 0;
56315e32d5dSMike Smith         break;
56415e32d5dSMike Smith 
5652a4ac806SMike Smith     case ACPI_WRITE_ADR_SPACE:
56615e32d5dSMike Smith         EcRequest.Command = EC_COMMAND_WRITE;
56715e32d5dSMike Smith         EcRequest.Address = Address;
56815e32d5dSMike Smith         break;
56915e32d5dSMike Smith 
57015e32d5dSMike Smith     default:
57115e32d5dSMike Smith 	device_printf(sc->ec_dev, "invalid Address Space function %d\n", Function);
5720ae55423SMike Smith         return_ACPI_STATUS(AE_BAD_PARAMETER);
57315e32d5dSMike Smith     }
57415e32d5dSMike Smith 
57515e32d5dSMike Smith     /*
57615e32d5dSMike Smith      * Perform the transaction.
57715e32d5dSMike Smith      */
578ee785aa9SJohn Baldwin     for (i = 0; i < width; i += 8) {
5792a4ac806SMike Smith 	if (Function == ACPI_READ_ADR_SPACE)
580ee785aa9SJohn Baldwin 	    EcRequest.Data = 0;
581ee785aa9SJohn Baldwin 	else
582ee785aa9SJohn Baldwin 	    EcRequest.Data = (UINT8)((*Value) >> i);
583ee785aa9SJohn Baldwin 	if ((Status = EcTransaction(sc, &EcRequest)) != AE_OK)
584ee785aa9SJohn Baldwin 	    break;
585ee785aa9SJohn Baldwin         (*Value) |= (UINT32)EcRequest.Data << i;
586ee785aa9SJohn Baldwin 	if (++EcRequest.Address == 0)
587ee785aa9SJohn Baldwin             return_ACPI_STATUS(AE_BAD_PARAMETER);
588ee785aa9SJohn Baldwin     }
5890ae55423SMike Smith     return_ACPI_STATUS(Status);
59015e32d5dSMike Smith }
5912a4ac806SMike Smith 
592a9cf0dffSMike Smith /*
593a9cf0dffSMike Smith  * Wait for an event interrupt for a specific condition.
594a9cf0dffSMike Smith  */
595c07572e7STakanori Watanabe static ACPI_STATUS
596c07572e7STakanori Watanabe EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event)
597c07572e7STakanori Watanabe {
598c07572e7STakanori Watanabe     EC_STATUS	EcStatus;
599c07572e7STakanori Watanabe     int		i;
600a9cf0dffSMike Smith 
601a9cf0dffSMike Smith     FUNCTION_TRACE_U32(__func__, (UINT32)Event);
602a9cf0dffSMike Smith 
603a9cf0dffSMike Smith     /* XXX this should test whether interrupts are available some other way */
604c07572e7STakanori Watanabe     if(cold)
605a9cf0dffSMike Smith 	return_ACPI_STATUS(EcWaitEvent(sc, Event));
606a9cf0dffSMike Smith 
607c07572e7STakanori Watanabe     if (!EcIsLocked(sc))
608c07572e7STakanori Watanabe 	device_printf(sc->ec_dev, "EcWaitEventIntr called without EC lock!\n");
609a9cf0dffSMike Smith 
610c07572e7STakanori Watanabe     EcStatus = EC_GET_CSR(sc);
611a9cf0dffSMike Smith 
612a9cf0dffSMike Smith     /* XXX waiting too long? */
613c07572e7STakanori Watanabe     for(i = 0; i < 10; i++){
614a9cf0dffSMike Smith 	/*
615a9cf0dffSMike Smith 	 * Check EC status against the desired event.
616a9cf0dffSMike Smith 	 */
617c07572e7STakanori Watanabe     	if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
618c07572e7STakanori Watanabe 	    (EcStatus & EC_FLAG_OUTPUT_BUFFER))
619a9cf0dffSMike Smith 	    return_ACPI_STATUS(AE_OK);
620c07572e7STakanori Watanabe 
621c07572e7STakanori Watanabe 	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
622c07572e7STakanori Watanabe 	    !(EcStatus & EC_FLAG_INPUT_BUFFER))
623a9cf0dffSMike Smith 	    return_ACPI_STATUS(AE_OK);
624a9cf0dffSMike Smith 
625c07572e7STakanori Watanabe 	sc->ec_csrvalue = 0;
626a9cf0dffSMike Smith 	if (ACPI_MSLEEP(&sc->ec_csrvalue, &acpi_mutex, PZERO, "EcWait", 1) != EWOULDBLOCK){
627c07572e7STakanori Watanabe 	    EcStatus = sc->ec_csrvalue;
628c07572e7STakanori Watanabe 	}else{
629c07572e7STakanori Watanabe 	    EcStatus = EC_GET_CSR(sc);
630c07572e7STakanori Watanabe 	}
631c07572e7STakanori Watanabe     }
632a9cf0dffSMike Smith     return_ACPI_STATUS(AE_ERROR);
633c07572e7STakanori Watanabe }
63415e32d5dSMike Smith 
63515e32d5dSMike Smith static ACPI_STATUS
63615e32d5dSMike Smith EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
63715e32d5dSMike Smith {
63815e32d5dSMike Smith     EC_STATUS	EcStatus;
63915e32d5dSMike Smith     UINT32	i = 0;
64015e32d5dSMike Smith 
64115e32d5dSMike Smith     if (!EcIsLocked(sc))
64215e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWaitEvent called without EC lock!\n");
64315e32d5dSMike Smith 
64415e32d5dSMike Smith     /*
64515e32d5dSMike Smith      * Stall 1us:
64615e32d5dSMike Smith      * ----------
64715e32d5dSMike Smith      * Stall for 1 microsecond before reading the status register
64815e32d5dSMike Smith      * for the first time.  This allows the EC to set the IBF/OBF
64915e32d5dSMike Smith      * bit to its proper state.
65015e32d5dSMike Smith      *
65115e32d5dSMike Smith      * XXX it is not clear why we read the CSR twice.
65215e32d5dSMike Smith      */
653da3b867eSMike Smith     AcpiOsStall(1);
65415e32d5dSMike Smith     EcStatus = EC_GET_CSR(sc);
65515e32d5dSMike Smith 
65615e32d5dSMike Smith     /*
65715e32d5dSMike Smith      * Wait For Event:
65815e32d5dSMike Smith      * ---------------
65915e32d5dSMike Smith      * Poll the EC status register to detect completion of the last
6602a4ac806SMike Smith      * command.  Wait up to 10ms (in 10us chunks) for this to occur.
66115e32d5dSMike Smith      */
6622a4ac806SMike Smith     for (i = 0; i < 1000; i++) {
66315e32d5dSMike Smith 	EcStatus = EC_GET_CSR(sc);
66415e32d5dSMike Smith 
66515e32d5dSMike Smith         if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
66615e32d5dSMike Smith             (EcStatus & EC_FLAG_OUTPUT_BUFFER))
66715e32d5dSMike Smith 	    return(AE_OK);
66815e32d5dSMike Smith 
66915e32d5dSMike Smith 	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
67015e32d5dSMike Smith             !(EcStatus & EC_FLAG_INPUT_BUFFER))
67115e32d5dSMike Smith 	    return(AE_OK);
67215e32d5dSMike Smith 
673da3b867eSMike Smith 	AcpiOsStall(10);
67415e32d5dSMike Smith     }
67515e32d5dSMike Smith 
67615e32d5dSMike Smith     return(AE_ERROR);
67715e32d5dSMike Smith }
67815e32d5dSMike Smith 
67915e32d5dSMike Smith static ACPI_STATUS
68015e32d5dSMike Smith EcQuery(struct acpi_ec_softc *sc, UINT8 *Data)
68115e32d5dSMike Smith {
68215e32d5dSMike Smith     ACPI_STATUS	Status;
68315e32d5dSMike Smith 
68415e32d5dSMike Smith     if ((Status = EcLock(sc)) != AE_OK)
68515e32d5dSMike Smith 	return(Status);
68615e32d5dSMike Smith 
68715e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_QUERY);
68815e32d5dSMike Smith     Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL);
68915e32d5dSMike Smith     if (Status == AE_OK)
69015e32d5dSMike Smith 	*Data = EC_GET_DATA(sc);
69115e32d5dSMike Smith 
69215e32d5dSMike Smith     EcUnlock(sc);
69315e32d5dSMike Smith 
69415e32d5dSMike Smith     if (Status != AE_OK)
69515e32d5dSMike Smith 	device_printf(sc->ec_dev, "timeout waiting for EC to respond to EC_COMMAND_QUERY\n");
69615e32d5dSMike Smith     return(Status);
69715e32d5dSMike Smith }
69815e32d5dSMike Smith 
69915e32d5dSMike Smith static ACPI_STATUS
70015e32d5dSMike Smith EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
70115e32d5dSMike Smith {
70215e32d5dSMike Smith     ACPI_STATUS	Status;
70315e32d5dSMike Smith 
70415e32d5dSMike Smith     /*
70515e32d5dSMike Smith      * Lock the EC
70615e32d5dSMike Smith      */
70715e32d5dSMike Smith     if ((Status = EcLock(sc)) != AE_OK)
70815e32d5dSMike Smith 	return(Status);
70915e32d5dSMike Smith 
71015e32d5dSMike Smith     /*
71115e32d5dSMike Smith      * Perform the transaction.
71215e32d5dSMike Smith      */
71315e32d5dSMike Smith     switch (EcRequest->Command) {
71415e32d5dSMike Smith     case EC_COMMAND_READ:
71515e32d5dSMike Smith 	Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data));
71615e32d5dSMike Smith 	break;
71715e32d5dSMike Smith 
71815e32d5dSMike Smith     case EC_COMMAND_WRITE:
71915e32d5dSMike Smith 	Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data));
72015e32d5dSMike Smith 	break;
72115e32d5dSMike Smith 
72215e32d5dSMike Smith     default:
72315e32d5dSMike Smith 	Status = AE_SUPPORT;
72415e32d5dSMike Smith 	break;
72515e32d5dSMike Smith     }
72615e32d5dSMike Smith 
72715e32d5dSMike Smith     /*
7282a4ac806SMike Smith      * Unlock the EC
7292a4ac806SMike Smith      */
7302a4ac806SMike Smith     EcUnlock(sc);
7312a4ac806SMike Smith 
7322a4ac806SMike Smith     /*
73315e32d5dSMike Smith      * Clear & Re-Enable the EC GPE:
73415e32d5dSMike Smith      * -----------------------------
73515e32d5dSMike Smith      * 'Consume' any EC GPE events that we generated while performing
73615e32d5dSMike Smith      * the transaction (e.g. IBF/OBF).	Clearing the GPE here shouldn't
73715e32d5dSMike Smith      * have an adverse affect on outstanding EC-SCI's, as the source
73815e32d5dSMike Smith      * (EC-SCI) will still be high and thus should trigger the GPE
73915e32d5dSMike Smith      * immediately after we re-enabling it.
74015e32d5dSMike Smith      */
741c07572e7STakanori Watanabe     if (sc->ec_pendquery){
742b37c9b90STakanori Watanabe 	    if(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
743c07572e7STakanori Watanabe 		EcGpeQueryHandler, sc) != AE_OK)
744c07572e7STakanori Watanabe 		    printf("Pend Query Queuing Failed\n");
745c07572e7STakanori Watanabe 	    sc->ec_pendquery = 0;
746c07572e7STakanori Watanabe     }
747c07572e7STakanori Watanabe 
74815e32d5dSMike Smith     if (AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
74915e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRequest: Unable to clear the EC GPE.\n");
75015e32d5dSMike Smith     if (AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
75115e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRequest: Unable to re-enable the EC GPE.\n");
75215e32d5dSMike Smith 
75315e32d5dSMike Smith     return(Status);
75415e32d5dSMike Smith }
75515e32d5dSMike Smith 
75615e32d5dSMike Smith 
75715e32d5dSMike Smith static ACPI_STATUS
75815e32d5dSMike Smith EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
75915e32d5dSMike Smith {
76015e32d5dSMike Smith     ACPI_STATUS	Status;
76115e32d5dSMike Smith 
76215e32d5dSMike Smith     if (!EcIsLocked(sc))
76315e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead called without EC lock!\n");
76415e32d5dSMike Smith 
76515e32d5dSMike Smith     /*EcBurstEnable(EmbeddedController);*/
76615e32d5dSMike Smith 
76715e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_READ);
768c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
76915e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process read command.\n");
77015e32d5dSMike Smith 	return(Status);
77115e32d5dSMike Smith     }
77215e32d5dSMike Smith 
77315e32d5dSMike Smith     EC_SET_DATA(sc, Address);
774c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_OUTPUT_BUFFER_FULL)) != AE_OK) {
77515e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to send data.\n");
77615e32d5dSMike Smith 	return(Status);
77715e32d5dSMike Smith     }
77815e32d5dSMike Smith 
77915e32d5dSMike Smith     (*Data) = EC_GET_DATA(sc);
78015e32d5dSMike Smith 
78115e32d5dSMike Smith     /*EcBurstDisable(EmbeddedController);*/
78215e32d5dSMike Smith 
78315e32d5dSMike Smith     return(AE_OK);
78415e32d5dSMike Smith }
78515e32d5dSMike Smith 
78615e32d5dSMike Smith static ACPI_STATUS
78715e32d5dSMike Smith EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
78815e32d5dSMike Smith {
78915e32d5dSMike Smith     ACPI_STATUS	Status;
79015e32d5dSMike Smith 
79115e32d5dSMike Smith     if (!EcIsLocked(sc))
79215e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWrite called without EC lock!\n");
79315e32d5dSMike Smith 
79415e32d5dSMike Smith     /*EcBurstEnable(EmbeddedController);*/
79515e32d5dSMike Smith 
79615e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_WRITE);
797c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
79815e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process write command.\n");
79915e32d5dSMike Smith 	return(Status);
80015e32d5dSMike Smith     }
80115e32d5dSMike Smith 
80215e32d5dSMike Smith     EC_SET_DATA(sc, Address);
803c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
80415e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process address.\n");
80515e32d5dSMike Smith 	return(Status);
80615e32d5dSMike Smith     }
80715e32d5dSMike Smith 
80815e32d5dSMike Smith     EC_SET_DATA(sc, *Data);
809c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
81015e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process data.\n");
81115e32d5dSMike Smith 	return(Status);
81215e32d5dSMike Smith     }
81315e32d5dSMike Smith 
81415e32d5dSMike Smith     /*EcBurstDisable(EmbeddedController);*/
81515e32d5dSMike Smith 
81615e32d5dSMike Smith     return(AE_OK);
81715e32d5dSMike Smith }
818