xref: /freebsd/sys/dev/acpica/acpi_ec.c (revision da3b867e3762899671e392f52292fca70bfa2eb0)
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 #include <dev/acpica/acpi_ecreg.h>
15115e32d5dSMike Smith 
1520ae55423SMike Smith /*
1530ae55423SMike Smith  * Hooks for the ACPI CA debugging infrastructure
1540ae55423SMike Smith  */
155a9cf0dffSMike Smith #define _COMPONENT	ACPI_EC
1560ae55423SMike Smith MODULE_NAME("EC")
1570ae55423SMike Smith 
158da3b867eSMike Smith /*
159da3b867eSMike Smith  * EC_COMMAND:
160da3b867eSMike Smith  * -----------
161da3b867eSMike Smith  */
162da3b867eSMike Smith typedef UINT8				EC_COMMAND;
163da3b867eSMike Smith 
164da3b867eSMike Smith #define EC_COMMAND_UNKNOWN		((EC_COMMAND) 0x00)
165da3b867eSMike Smith #define EC_COMMAND_READ			((EC_COMMAND) 0x80)
166da3b867eSMike Smith #define EC_COMMAND_WRITE		((EC_COMMAND) 0x81)
167da3b867eSMike Smith #define EC_COMMAND_BURST_ENABLE		((EC_COMMAND) 0x82)
168da3b867eSMike Smith #define EC_COMMAND_BURST_DISABLE	((EC_COMMAND) 0x83)
169da3b867eSMike Smith #define EC_COMMAND_QUERY		((EC_COMMAND) 0x84)
170da3b867eSMike Smith 
171da3b867eSMike Smith /*
172da3b867eSMike Smith  * EC_STATUS:
173da3b867eSMike Smith  * ----------
174da3b867eSMike Smith  * The encoding of the EC status register is illustrated below.
175da3b867eSMike Smith  * Note that a set bit (1) indicates the property is TRUE
176da3b867eSMike Smith  * (e.g. if bit 0 is set then the output buffer is full).
177da3b867eSMike Smith  * +-+-+-+-+-+-+-+-+
178da3b867eSMike Smith  * |7|6|5|4|3|2|1|0|
179da3b867eSMike Smith  * +-+-+-+-+-+-+-+-+
180da3b867eSMike Smith  *  | | | | | | | |
181da3b867eSMike Smith  *  | | | | | | | +- Output Buffer Full?
182da3b867eSMike Smith  *  | | | | | | +--- Input Buffer Full?
183da3b867eSMike Smith  *  | | | | | +----- <reserved>
184da3b867eSMike Smith  *  | | | | +------- Data Register is Command Byte?
185da3b867eSMike Smith  *  | | | +--------- Burst Mode Enabled?
186da3b867eSMike Smith  *  | | +----------- SCI Event?
187da3b867eSMike Smith  *  | +------------- SMI Event?
188da3b867eSMike Smith  *  +--------------- <Reserved>
189da3b867eSMike Smith  *
190da3b867eSMike Smith  */
191da3b867eSMike Smith typedef UINT8				EC_STATUS;
192da3b867eSMike Smith 
193da3b867eSMike Smith #define EC_FLAG_OUTPUT_BUFFER		((EC_STATUS) 0x01)
194da3b867eSMike Smith #define EC_FLAG_INPUT_BUFFER		((EC_STATUS) 0x02)
195da3b867eSMike Smith #define EC_FLAG_BURST_MODE		((EC_STATUS) 0x10)
196da3b867eSMike Smith #define EC_FLAG_SCI			((EC_STATUS) 0x20)
197da3b867eSMike Smith 
198da3b867eSMike Smith /*
199da3b867eSMike Smith  * EC_EVENT:
200da3b867eSMike Smith  * ---------
201da3b867eSMike Smith  */
202da3b867eSMike Smith typedef UINT8				EC_EVENT;
203da3b867eSMike Smith 
204da3b867eSMike Smith #define EC_EVENT_UNKNOWN		((EC_EVENT) 0x00)
205da3b867eSMike Smith #define EC_EVENT_OUTPUT_BUFFER_FULL	((EC_EVENT) 0x01)
206da3b867eSMike Smith #define EC_EVENT_INPUT_BUFFER_EMPTY	((EC_EVENT) 0x02)
207da3b867eSMike Smith #define EC_EVENT_SCI			((EC_EVENT) 0x20)
208da3b867eSMike Smith 
209da3b867eSMike Smith /*
210da3b867eSMike Smith  * Register access primitives
211da3b867eSMike Smith  */
212da3b867eSMike Smith #define EC_GET_DATA(sc)							\
213da3b867eSMike Smith 	bus_space_read_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0)
214da3b867eSMike Smith 
215da3b867eSMike Smith #define EC_SET_DATA(sc, v)						\
216da3b867eSMike Smith 	bus_space_write_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0, (v))
217da3b867eSMike Smith 
218da3b867eSMike Smith #define EC_GET_CSR(sc)							\
219da3b867eSMike Smith 	bus_space_read_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0)
220da3b867eSMike Smith 
221da3b867eSMike Smith #define EC_SET_CSR(sc, v)						\
222da3b867eSMike Smith 	bus_space_write_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0, (v))
223da3b867eSMike Smith 
224da3b867eSMike Smith /*
225da3b867eSMike Smith  * Driver softc.
226da3b867eSMike Smith  */
22715e32d5dSMike Smith struct acpi_ec_softc {
22815e32d5dSMike Smith     device_t		ec_dev;
22915e32d5dSMike Smith     ACPI_HANDLE		ec_handle;
23015e32d5dSMike Smith     UINT32		ec_gpebit;
23115e32d5dSMike Smith 
23215e32d5dSMike Smith     int			ec_data_rid;
23315e32d5dSMike Smith     struct resource	*ec_data_res;
23415e32d5dSMike Smith     bus_space_tag_t	ec_data_tag;
23515e32d5dSMike Smith     bus_space_handle_t	ec_data_handle;
23615e32d5dSMike Smith 
23715e32d5dSMike Smith     int			ec_csr_rid;
23815e32d5dSMike Smith     struct resource	*ec_csr_res;
23915e32d5dSMike Smith     bus_space_tag_t	ec_csr_tag;
24015e32d5dSMike Smith     bus_space_handle_t	ec_csr_handle;
24115e32d5dSMike Smith 
24215e32d5dSMike Smith     int			ec_locked;
243c07572e7STakanori Watanabe     int			ec_pendquery;
244c07572e7STakanori Watanabe     int			ec_csrvalue;
24515e32d5dSMike Smith };
24615e32d5dSMike Smith 
24715e32d5dSMike Smith #define EC_LOCK_TIMEOUT	1000	/* 1ms */
24815e32d5dSMike Smith 
24915e32d5dSMike Smith static __inline ACPI_STATUS
25015e32d5dSMike Smith EcLock(struct acpi_ec_softc *sc)
25115e32d5dSMike Smith {
25215e32d5dSMike Smith     ACPI_STATUS	status;
25315e32d5dSMike Smith 
2547a1d55dfSTakanori Watanabe     status = AcpiAcquireGlobalLock();
25515e32d5dSMike Smith     (sc)->ec_locked = 1;
25615e32d5dSMike Smith     return(status);
25715e32d5dSMike Smith }
25815e32d5dSMike Smith 
25915e32d5dSMike Smith static __inline void
26015e32d5dSMike Smith EcUnlock(struct acpi_ec_softc *sc)
26115e32d5dSMike Smith {
26215e32d5dSMike Smith     (sc)->ec_locked = 0;
2637a1d55dfSTakanori Watanabe     AcpiReleaseGlobalLock();
26415e32d5dSMike Smith }
26515e32d5dSMike Smith 
26615e32d5dSMike Smith static __inline int
26715e32d5dSMike Smith EcIsLocked(struct acpi_ec_softc *sc)
26815e32d5dSMike Smith {
26915e32d5dSMike Smith     return((sc)->ec_locked != 0);
27015e32d5dSMike Smith }
27115e32d5dSMike Smith 
27215e32d5dSMike Smith typedef struct
27315e32d5dSMike Smith {
27415e32d5dSMike Smith     EC_COMMAND              Command;
27515e32d5dSMike Smith     UINT8                   Address;
27615e32d5dSMike Smith     UINT8                   Data;
27715e32d5dSMike Smith } EC_REQUEST;
27815e32d5dSMike Smith 
27915e32d5dSMike Smith static void		EcGpeHandler(void *Context);
28015e32d5dSMike Smith static ACPI_STATUS	EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function,
28115e32d5dSMike Smith 					   void *Context, void **return_Context);
282042283a6SMike Smith static ACPI_STATUS	EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
28315e32d5dSMike Smith 				      void *Context, void *RegionContext);
28415e32d5dSMike Smith 
28515e32d5dSMike Smith static ACPI_STATUS	EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event);
28615e32d5dSMike Smith static ACPI_STATUS	EcQuery(struct acpi_ec_softc *sc, UINT8 *Data);
28715e32d5dSMike Smith static ACPI_STATUS	EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest);
28815e32d5dSMike Smith static ACPI_STATUS	EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
28915e32d5dSMike Smith static ACPI_STATUS	EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
29015e32d5dSMike Smith 
29115e32d5dSMike Smith static void		acpi_ec_identify(driver_t driver, device_t bus);
29215e32d5dSMike Smith static int		acpi_ec_probe(device_t dev);
29315e32d5dSMike Smith static int		acpi_ec_attach(device_t dev);
29415e32d5dSMike Smith 
29515e32d5dSMike Smith static device_method_t acpi_ec_methods[] = {
29615e32d5dSMike Smith     /* Device interface */
29715e32d5dSMike Smith     DEVMETHOD(device_identify,	acpi_ec_identify),
29815e32d5dSMike Smith     DEVMETHOD(device_probe,	acpi_ec_probe),
29915e32d5dSMike Smith     DEVMETHOD(device_attach,	acpi_ec_attach),
30015e32d5dSMike Smith 
30115e32d5dSMike Smith     {0, 0}
30215e32d5dSMike Smith };
30315e32d5dSMike Smith 
30415e32d5dSMike Smith static driver_t acpi_ec_driver = {
30515e32d5dSMike Smith     "acpi_ec",
30615e32d5dSMike Smith     acpi_ec_methods,
30715e32d5dSMike Smith     sizeof(struct acpi_ec_softc),
30815e32d5dSMike Smith };
30915e32d5dSMike Smith 
31015e32d5dSMike Smith devclass_t acpi_ec_devclass;
31115e32d5dSMike Smith DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
31215e32d5dSMike Smith 
31315e32d5dSMike Smith /*
31415e32d5dSMike Smith  * Look for an ECDT table and if we find one, set up a default EC
31515e32d5dSMike Smith  * space handler to catch possible attempts to access EC space before
31615e32d5dSMike Smith  * we have a real driver instance in place.
31715e32d5dSMike Smith  * We're not really an identify routine, but because we get called
31815e32d5dSMike Smith  * before most other things, this works out OK.
31915e32d5dSMike Smith  */
32015e32d5dSMike Smith static void
32115e32d5dSMike Smith acpi_ec_identify(driver_t driver, device_t bus)
32215e32d5dSMike Smith {
3232a4ac806SMike Smith     FUNCTION_TRACE(__func__);
32415e32d5dSMike Smith 
32515e32d5dSMike Smith     /* XXX implement - need an ACPI 2.0 system to test this */
3260ae55423SMike Smith 
3270ae55423SMike Smith     return_VOID;
32815e32d5dSMike Smith }
32915e32d5dSMike Smith 
33015e32d5dSMike Smith /*
33115e32d5dSMike Smith  * We could setup resources in the probe routine in order to have them printed
33215e32d5dSMike Smith  * when the device is attached.
33315e32d5dSMike Smith  */
33415e32d5dSMike Smith static int
33515e32d5dSMike Smith acpi_ec_probe(device_t dev)
33615e32d5dSMike Smith {
3370ae55423SMike Smith 
33815e32d5dSMike Smith     if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
3390ae55423SMike Smith 	!acpi_disabled("ec") &&
34015e32d5dSMike Smith 	acpi_MatchHid(dev, "PNP0C09")) {
34115e32d5dSMike Smith 
34215e32d5dSMike Smith 	/*
34315e32d5dSMike Smith 	 * Set device description
34415e32d5dSMike Smith 	 */
34515e32d5dSMike Smith 	device_set_desc(dev, "embedded controller");
34615e32d5dSMike Smith 
34715e32d5dSMike Smith 	return(0);
34815e32d5dSMike Smith     }
34915e32d5dSMike Smith     return(ENXIO);
35015e32d5dSMike Smith }
35115e32d5dSMike Smith 
35215e32d5dSMike Smith static int
35315e32d5dSMike Smith acpi_ec_attach(device_t dev)
35415e32d5dSMike Smith {
35515e32d5dSMike Smith     struct acpi_ec_softc	*sc;
35615e32d5dSMike Smith     ACPI_STATUS			Status;
35715e32d5dSMike Smith 
3582a4ac806SMike Smith     FUNCTION_TRACE(__func__);
3590ae55423SMike Smith 
36015e32d5dSMike Smith     /*
36115e32d5dSMike Smith      * Fetch/initialise softc
36215e32d5dSMike Smith      */
36315e32d5dSMike Smith     sc = device_get_softc(dev);
364c07572e7STakanori Watanabe     bzero(sc, sizeof(*sc));
36515e32d5dSMike Smith     sc->ec_dev = dev;
36615e32d5dSMike Smith     sc->ec_handle = acpi_get_handle(dev);
36715e32d5dSMike Smith 
36815e32d5dSMike Smith     /*
36915e32d5dSMike Smith      * Evaluate resources
37015e32d5dSMike Smith      */
37142f6d122SMike Smith     DEBUG_PRINT(TRACE_RESOURCES, ("parsing EC resources\n"));
37215e32d5dSMike Smith     acpi_parse_resources(sc->ec_dev, sc->ec_handle, &acpi_res_parse_set);
37315e32d5dSMike Smith 
37415e32d5dSMike Smith     /*
37515e32d5dSMike Smith      * Attach bus resources
37615e32d5dSMike Smith      */
37715e32d5dSMike Smith     sc->ec_data_rid = 0;
37815e32d5dSMike Smith     if ((sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_data_rid,
37915e32d5dSMike Smith 					      0, ~0, 1, RF_ACTIVE)) == NULL) {
38015e32d5dSMike Smith 	device_printf(dev, "can't allocate data port\n");
3810ae55423SMike Smith 	return_VALUE(ENXIO);
38215e32d5dSMike Smith     }
38315e32d5dSMike Smith     sc->ec_data_tag = rman_get_bustag(sc->ec_data_res);
38415e32d5dSMike Smith     sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res);
38515e32d5dSMike Smith 
38615e32d5dSMike Smith     sc->ec_csr_rid = 1;
38715e32d5dSMike Smith     if ((sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_csr_rid,
38815e32d5dSMike Smith 					     0, ~0, 1, RF_ACTIVE)) == NULL) {
38915e32d5dSMike Smith 	device_printf(dev, "can't allocate command/status port\n");
3900ae55423SMike Smith 	return_VALUE(ENXIO);
39115e32d5dSMike Smith     }
39215e32d5dSMike Smith     sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res);
39315e32d5dSMike Smith     sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res);
39415e32d5dSMike Smith 
39515e32d5dSMike Smith     /*
39615e32d5dSMike Smith      * Install GPE handler
39715e32d5dSMike Smith      *
39815e32d5dSMike Smith      * Evaluate the _GPE method to find the GPE bit used by the EC to signal
39915e32d5dSMike Smith      * status (SCI).
40015e32d5dSMike Smith      */
40142f6d122SMike Smith     DEBUG_PRINT(TRACE_RESOURCES, ("attaching GPE\n"));
40242f6d122SMike Smith     if ((Status = acpi_EvaluateInteger(sc->ec_handle, "_GPE", &sc->ec_gpebit)) != AE_OK) {
40342f6d122SMike Smith 	device_printf(dev, "can't evaluate _GPE - %s\n", acpi_strerror(Status));
4040ae55423SMike Smith 	return_VALUE(ENXIO);
40515e32d5dSMike Smith     }
40615e32d5dSMike Smith 
40715e32d5dSMike Smith     /*
40815e32d5dSMike Smith      * Install a handler for this EC's GPE bit.  Note that EC SCIs are
40915e32d5dSMike Smith      * treated as both edge- and level-triggered interrupts; in other words
41015e32d5dSMike Smith      * we clear the status bit immediately after getting an EC-SCI, then
41115e32d5dSMike Smith      * again after we're done processing the event.  This guarantees that
41215e32d5dSMike Smith      * events we cause while performing a transaction (e.g. IBE/OBF) get
41315e32d5dSMike Smith      * cleared before re-enabling the GPE.
41415e32d5dSMike Smith      */
41515e32d5dSMike Smith     if ((Status = AcpiInstallGpeHandler(sc->ec_gpebit, ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED,
41615e32d5dSMike Smith 					EcGpeHandler, sc)) != AE_OK) {
41776d1dff4SMike Smith 	device_printf(dev, "can't install GPE handler for %s - %s\n",
41876d1dff4SMike Smith 		      acpi_name(sc->ec_handle), acpi_strerror(Status));
4190ae55423SMike Smith 	return_VALUE(ENXIO);
42015e32d5dSMike Smith     }
42115e32d5dSMike Smith 
42215e32d5dSMike Smith     /*
42315e32d5dSMike Smith      * Install address space handler
42415e32d5dSMike Smith      */
42542f6d122SMike Smith     DEBUG_PRINT(TRACE_RESOURCES, ("attaching address space handler\n"));
4262a4ac806SMike Smith     if ((Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ACPI_ADR_SPACE_EC,
42742f6d122SMike Smith 						 EcSpaceHandler, EcSpaceSetup, sc)) != AE_OK) {
42876d1dff4SMike Smith 	device_printf(dev, "can't install address space handler for %s - %s\n",
42976d1dff4SMike Smith 		      acpi_name(sc->ec_handle), acpi_strerror(Status));
43076d1dff4SMike Smith 	panic("very suck");
4310ae55423SMike Smith 	return_VALUE(ENXIO);
43215e32d5dSMike Smith     }
43342f6d122SMike Smith     DEBUG_PRINT(TRACE_RESOURCES, ("attach complete\n"));
43415e32d5dSMike Smith 
4350ae55423SMike Smith     return_VALUE(0);
43615e32d5dSMike Smith }
43715e32d5dSMike Smith 
43815e32d5dSMike Smith static void
439c07572e7STakanori Watanabe EcGpeQueryHandler(void *Context)
44015e32d5dSMike Smith {
44115e32d5dSMike Smith     struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
44215e32d5dSMike Smith     UINT8			Data;
44315e32d5dSMike Smith     ACPI_STATUS			Status;
44415e32d5dSMike Smith     char			qxx[5];
44515e32d5dSMike Smith 
4462a4ac806SMike Smith     FUNCTION_TRACE(__func__);
4470ae55423SMike Smith 
44815e32d5dSMike Smith     for (;;) {
44915e32d5dSMike Smith 
45015e32d5dSMike Smith 	/*
45115e32d5dSMike Smith 	 * Check EC_SCI.
45215e32d5dSMike Smith 	 *
45315e32d5dSMike Smith 	 * Bail out if the EC_SCI bit of the status register is not set.
45415e32d5dSMike Smith 	 * Note that this function should only be called when
45515e32d5dSMike Smith 	 * this bit is set (polling is used to detect IBE/OBF events).
45615e32d5dSMike Smith 	 *
45715e32d5dSMike Smith 	 * It is safe to do this without locking the controller, as it's
45815e32d5dSMike Smith 	 * OK to call EcQuery when there's no data ready; in the worst
45915e32d5dSMike Smith 	 * case we should just find nothing waiting for us and bail.
46015e32d5dSMike Smith 	 */
46115e32d5dSMike Smith 	if (!(EC_GET_CSR(sc) & EC_EVENT_SCI))
46215e32d5dSMike Smith 	    break;
46315e32d5dSMike Smith 
46415e32d5dSMike Smith 	/*
46515e32d5dSMike Smith 	 * Find out why the EC is signalling us
46615e32d5dSMike Smith 	 */
46715e32d5dSMike Smith 	Status = EcQuery(sc, &Data);
46815e32d5dSMike Smith 
46915e32d5dSMike Smith 	/*
47015e32d5dSMike Smith 	 * If we failed to get anything from the EC, give up
47115e32d5dSMike Smith 	 */
47215e32d5dSMike Smith 	if (Status != AE_OK) {
47315e32d5dSMike Smith 	    device_printf(sc->ec_dev, "GPE query failed - %s\n", acpi_strerror(Status));
47415e32d5dSMike Smith 	    break;
47515e32d5dSMike Smith 	}
47615e32d5dSMike Smith 
47715e32d5dSMike Smith 	/*
47815e32d5dSMike Smith 	 * Evaluate _Qxx to respond to the controller.
47915e32d5dSMike Smith 	 */
48015e32d5dSMike Smith 	sprintf(qxx, "_Q%02x", Data);
48115e32d5dSMike Smith 	strupr(qxx);
482ee785aa9SJohn Baldwin 	Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL);
483ee785aa9SJohn Baldwin 	/*
484ee785aa9SJohn Baldwin 	 * Ignore spurious query requests.
485ee785aa9SJohn Baldwin 	 */
486ee785aa9SJohn Baldwin 	if (Status != AE_OK && (Data != 0 || Status != AE_NOT_FOUND)) {
48715e32d5dSMike Smith 	    device_printf(sc->ec_dev, "evaluation of GPE query method %s failed - %s\n",
48815e32d5dSMike Smith 			  qxx, acpi_strerror(Status));
48915e32d5dSMike Smith 	}
49015e32d5dSMike Smith     }
491c07572e7STakanori Watanabe         /* I know I request Level trigger cleanup */
492c07572e7STakanori Watanabe     if(AcpiClearEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
493c07572e7STakanori Watanabe 	    printf("EcGpeQueryHandler:ClearEvent Failed\n");
494c07572e7STakanori Watanabe     if(AcpiEnableEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
495c07572e7STakanori Watanabe 	    printf("EcGpeQueryHandler:EnableEvent Failed\n");
496874d21b4STakanori Watanabe     return_VOID;
497c07572e7STakanori Watanabe }
49842f6d122SMike Smith 
499a9cf0dffSMike Smith /*
500a9cf0dffSMike Smith  * Handle a GPE sent to us.
501a9cf0dffSMike Smith  */
502a9cf0dffSMike Smith static void
503a9cf0dffSMike Smith EcGpeHandler(void *Context)
504c07572e7STakanori Watanabe {
505c07572e7STakanori Watanabe     struct acpi_ec_softc *sc = Context;
506c07572e7STakanori Watanabe     int csrvalue;
507a9cf0dffSMike Smith 
508c07572e7STakanori Watanabe     /*
509c07572e7STakanori Watanabe      * If EC is locked, the intr must process EcRead/Write wait only.
510c07572e7STakanori Watanabe      * Query request must be pending.
511c07572e7STakanori Watanabe      */
512c07572e7STakanori Watanabe     if (EcIsLocked(sc)){
513c07572e7STakanori Watanabe 	csrvalue = EC_GET_CSR(sc);
514c07572e7STakanori Watanabe 	if (csrvalue & EC_EVENT_SCI)
515c07572e7STakanori Watanabe 	    sc->ec_pendquery = 1;
516c07572e7STakanori Watanabe 	if ((csrvalue & EC_FLAG_OUTPUT_BUFFER)
517c07572e7STakanori Watanabe 	    || !(csrvalue & EC_FLAG_INPUT_BUFFER)) {
518c07572e7STakanori Watanabe 	    sc->ec_csrvalue = csrvalue;
519c07572e7STakanori Watanabe 	    wakeup((void *)&sc->ec_csrvalue);
520c07572e7STakanori Watanabe 	}
521c07572e7STakanori Watanabe     }else{
522c07572e7STakanori Watanabe 	/* Queue GpeQuery Handler */
523b37c9b90STakanori Watanabe 	if (AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
524c07572e7STakanori Watanabe 				    EcGpeQueryHandler,Context) != AE_OK){
525c07572e7STakanori Watanabe 	    printf("QueryHandler Queuing Failed\n");
526c07572e7STakanori Watanabe 	}
527c07572e7STakanori Watanabe     }
528874d21b4STakanori Watanabe     return;
52915e32d5dSMike Smith }
53015e32d5dSMike Smith 
53115e32d5dSMike Smith static ACPI_STATUS
53215e32d5dSMike Smith EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, void **RegionContext)
53315e32d5dSMike Smith {
53442f6d122SMike Smith 
5352a4ac806SMike Smith     FUNCTION_TRACE(__func__);
53642f6d122SMike Smith 
53715e32d5dSMike Smith     /*
53815e32d5dSMike Smith      * Just pass the context through, there's nothing to do here.
53915e32d5dSMike Smith      */
54015e32d5dSMike Smith     *RegionContext = Context;
54115e32d5dSMike Smith 
54242f6d122SMike Smith     return_ACPI_STATUS(AE_OK);
54315e32d5dSMike Smith }
54415e32d5dSMike Smith 
54515e32d5dSMike Smith static ACPI_STATUS
546042283a6SMike Smith EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
547042283a6SMike Smith 	       void *Context, void *RegionContext)
54815e32d5dSMike Smith {
54915e32d5dSMike Smith     struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
55015e32d5dSMike Smith     ACPI_STATUS			Status = AE_OK;
55115e32d5dSMike Smith     EC_REQUEST			EcRequest;
552ee785aa9SJohn Baldwin     int				i;
55315e32d5dSMike Smith 
5542a4ac806SMike Smith     FUNCTION_TRACE_U32(__func__, (UINT32)Address);
5550ae55423SMike Smith 
556ee785aa9SJohn Baldwin     if ((Address > 0xFF) || (width % 8 != 0) || (Value == NULL) || (Context == NULL))
5570ae55423SMike Smith         return_ACPI_STATUS(AE_BAD_PARAMETER);
55815e32d5dSMike Smith 
55915e32d5dSMike Smith     switch (Function) {
5602a4ac806SMike Smith     case ACPI_READ_ADR_SPACE:
56115e32d5dSMike Smith         EcRequest.Command = EC_COMMAND_READ;
56215e32d5dSMike Smith         EcRequest.Address = Address;
5632a4ac806SMike Smith 	(*Value) = 0;
56415e32d5dSMike Smith         break;
56515e32d5dSMike Smith 
5662a4ac806SMike Smith     case ACPI_WRITE_ADR_SPACE:
56715e32d5dSMike Smith         EcRequest.Command = EC_COMMAND_WRITE;
56815e32d5dSMike Smith         EcRequest.Address = Address;
56915e32d5dSMike Smith         break;
57015e32d5dSMike Smith 
57115e32d5dSMike Smith     default:
57215e32d5dSMike Smith 	device_printf(sc->ec_dev, "invalid Address Space function %d\n", Function);
5730ae55423SMike Smith         return_ACPI_STATUS(AE_BAD_PARAMETER);
57415e32d5dSMike Smith     }
57515e32d5dSMike Smith 
57615e32d5dSMike Smith     /*
57715e32d5dSMike Smith      * Perform the transaction.
57815e32d5dSMike Smith      */
579ee785aa9SJohn Baldwin     for (i = 0; i < width; i += 8) {
5802a4ac806SMike Smith 	if (Function == ACPI_READ_ADR_SPACE)
581ee785aa9SJohn Baldwin 	    EcRequest.Data = 0;
582ee785aa9SJohn Baldwin 	else
583ee785aa9SJohn Baldwin 	    EcRequest.Data = (UINT8)((*Value) >> i);
584ee785aa9SJohn Baldwin 	if ((Status = EcTransaction(sc, &EcRequest)) != AE_OK)
585ee785aa9SJohn Baldwin 	    break;
586ee785aa9SJohn Baldwin         (*Value) |= (UINT32)EcRequest.Data << i;
587ee785aa9SJohn Baldwin 	if (++EcRequest.Address == 0)
588ee785aa9SJohn Baldwin             return_ACPI_STATUS(AE_BAD_PARAMETER);
589ee785aa9SJohn Baldwin     }
5900ae55423SMike Smith     return_ACPI_STATUS(Status);
59115e32d5dSMike Smith }
5922a4ac806SMike Smith 
593a9cf0dffSMike Smith /*
594a9cf0dffSMike Smith  * Wait for an event interrupt for a specific condition.
595a9cf0dffSMike Smith  */
596c07572e7STakanori Watanabe static ACPI_STATUS
597c07572e7STakanori Watanabe EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event)
598c07572e7STakanori Watanabe {
599c07572e7STakanori Watanabe     EC_STATUS	EcStatus;
600c07572e7STakanori Watanabe     int		i;
601a9cf0dffSMike Smith 
602a9cf0dffSMike Smith     FUNCTION_TRACE_U32(__func__, (UINT32)Event);
603a9cf0dffSMike Smith 
604a9cf0dffSMike Smith     /* XXX this should test whether interrupts are available some other way */
605c07572e7STakanori Watanabe     if(cold)
606a9cf0dffSMike Smith 	return_ACPI_STATUS(EcWaitEvent(sc, Event));
607a9cf0dffSMike Smith 
608c07572e7STakanori Watanabe     if (!EcIsLocked(sc))
609c07572e7STakanori Watanabe 	device_printf(sc->ec_dev, "EcWaitEventIntr called without EC lock!\n");
610a9cf0dffSMike Smith 
611c07572e7STakanori Watanabe     EcStatus = EC_GET_CSR(sc);
612a9cf0dffSMike Smith 
613a9cf0dffSMike Smith     /* XXX waiting too long? */
614c07572e7STakanori Watanabe     for(i = 0; i < 10; i++){
615a9cf0dffSMike Smith 	/*
616a9cf0dffSMike Smith 	 * Check EC status against the desired event.
617a9cf0dffSMike Smith 	 */
618c07572e7STakanori Watanabe     	if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
619c07572e7STakanori Watanabe 	    (EcStatus & EC_FLAG_OUTPUT_BUFFER))
620a9cf0dffSMike Smith 	    return_ACPI_STATUS(AE_OK);
621c07572e7STakanori Watanabe 
622c07572e7STakanori Watanabe 	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
623c07572e7STakanori Watanabe 	    !(EcStatus & EC_FLAG_INPUT_BUFFER))
624a9cf0dffSMike Smith 	    return_ACPI_STATUS(AE_OK);
625a9cf0dffSMike Smith 
626c07572e7STakanori Watanabe 	sc->ec_csrvalue = 0;
627a9cf0dffSMike Smith 	if (ACPI_MSLEEP(&sc->ec_csrvalue, &acpi_mutex, PZERO, "EcWait", 1) != EWOULDBLOCK){
628c07572e7STakanori Watanabe 	    EcStatus = sc->ec_csrvalue;
629c07572e7STakanori Watanabe 	}else{
630c07572e7STakanori Watanabe 	    EcStatus = EC_GET_CSR(sc);
631c07572e7STakanori Watanabe 	}
632c07572e7STakanori Watanabe     }
633a9cf0dffSMike Smith     return_ACPI_STATUS(AE_ERROR);
634c07572e7STakanori Watanabe }
63515e32d5dSMike Smith 
63615e32d5dSMike Smith static ACPI_STATUS
63715e32d5dSMike Smith EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
63815e32d5dSMike Smith {
63915e32d5dSMike Smith     EC_STATUS	EcStatus;
64015e32d5dSMike Smith     UINT32	i = 0;
64115e32d5dSMike Smith 
64215e32d5dSMike Smith     if (!EcIsLocked(sc))
64315e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWaitEvent called without EC lock!\n");
64415e32d5dSMike Smith 
64515e32d5dSMike Smith     /*
64615e32d5dSMike Smith      * Stall 1us:
64715e32d5dSMike Smith      * ----------
64815e32d5dSMike Smith      * Stall for 1 microsecond before reading the status register
64915e32d5dSMike Smith      * for the first time.  This allows the EC to set the IBF/OBF
65015e32d5dSMike Smith      * bit to its proper state.
65115e32d5dSMike Smith      *
65215e32d5dSMike Smith      * XXX it is not clear why we read the CSR twice.
65315e32d5dSMike Smith      */
654da3b867eSMike Smith     AcpiOsStall(1);
65515e32d5dSMike Smith     EcStatus = EC_GET_CSR(sc);
65615e32d5dSMike Smith 
65715e32d5dSMike Smith     /*
65815e32d5dSMike Smith      * Wait For Event:
65915e32d5dSMike Smith      * ---------------
66015e32d5dSMike Smith      * Poll the EC status register to detect completion of the last
6612a4ac806SMike Smith      * command.  Wait up to 10ms (in 10us chunks) for this to occur.
66215e32d5dSMike Smith      */
6632a4ac806SMike Smith     for (i = 0; i < 1000; i++) {
66415e32d5dSMike Smith 	EcStatus = EC_GET_CSR(sc);
66515e32d5dSMike Smith 
66615e32d5dSMike Smith         if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
66715e32d5dSMike Smith             (EcStatus & EC_FLAG_OUTPUT_BUFFER))
66815e32d5dSMike Smith 	    return(AE_OK);
66915e32d5dSMike Smith 
67015e32d5dSMike Smith 	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
67115e32d5dSMike Smith             !(EcStatus & EC_FLAG_INPUT_BUFFER))
67215e32d5dSMike Smith 	    return(AE_OK);
67315e32d5dSMike Smith 
674da3b867eSMike Smith 	AcpiOsStall(10);
67515e32d5dSMike Smith     }
67615e32d5dSMike Smith 
67715e32d5dSMike Smith     return(AE_ERROR);
67815e32d5dSMike Smith }
67915e32d5dSMike Smith 
68015e32d5dSMike Smith static ACPI_STATUS
68115e32d5dSMike Smith EcQuery(struct acpi_ec_softc *sc, UINT8 *Data)
68215e32d5dSMike Smith {
68315e32d5dSMike Smith     ACPI_STATUS	Status;
68415e32d5dSMike Smith 
68515e32d5dSMike Smith     if ((Status = EcLock(sc)) != AE_OK)
68615e32d5dSMike Smith 	return(Status);
68715e32d5dSMike Smith 
68815e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_QUERY);
68915e32d5dSMike Smith     Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL);
69015e32d5dSMike Smith     if (Status == AE_OK)
69115e32d5dSMike Smith 	*Data = EC_GET_DATA(sc);
69215e32d5dSMike Smith 
69315e32d5dSMike Smith     EcUnlock(sc);
69415e32d5dSMike Smith 
69515e32d5dSMike Smith     if (Status != AE_OK)
69615e32d5dSMike Smith 	device_printf(sc->ec_dev, "timeout waiting for EC to respond to EC_COMMAND_QUERY\n");
69715e32d5dSMike Smith     return(Status);
69815e32d5dSMike Smith }
69915e32d5dSMike Smith 
70015e32d5dSMike Smith static ACPI_STATUS
70115e32d5dSMike Smith EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
70215e32d5dSMike Smith {
70315e32d5dSMike Smith     ACPI_STATUS	Status;
70415e32d5dSMike Smith 
70515e32d5dSMike Smith     /*
70615e32d5dSMike Smith      * Lock the EC
70715e32d5dSMike Smith      */
70815e32d5dSMike Smith     if ((Status = EcLock(sc)) != AE_OK)
70915e32d5dSMike Smith 	return(Status);
71015e32d5dSMike Smith 
71115e32d5dSMike Smith     /*
71215e32d5dSMike Smith      * Perform the transaction.
71315e32d5dSMike Smith      */
71415e32d5dSMike Smith     switch (EcRequest->Command) {
71515e32d5dSMike Smith     case EC_COMMAND_READ:
71615e32d5dSMike Smith 	Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data));
71715e32d5dSMike Smith 	break;
71815e32d5dSMike Smith 
71915e32d5dSMike Smith     case EC_COMMAND_WRITE:
72015e32d5dSMike Smith 	Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data));
72115e32d5dSMike Smith 	break;
72215e32d5dSMike Smith 
72315e32d5dSMike Smith     default:
72415e32d5dSMike Smith 	Status = AE_SUPPORT;
72515e32d5dSMike Smith 	break;
72615e32d5dSMike Smith     }
72715e32d5dSMike Smith 
72815e32d5dSMike Smith     /*
7292a4ac806SMike Smith      * Unlock the EC
7302a4ac806SMike Smith      */
7312a4ac806SMike Smith     EcUnlock(sc);
7322a4ac806SMike Smith 
7332a4ac806SMike Smith     /*
73415e32d5dSMike Smith      * Clear & Re-Enable the EC GPE:
73515e32d5dSMike Smith      * -----------------------------
73615e32d5dSMike Smith      * 'Consume' any EC GPE events that we generated while performing
73715e32d5dSMike Smith      * the transaction (e.g. IBF/OBF).	Clearing the GPE here shouldn't
73815e32d5dSMike Smith      * have an adverse affect on outstanding EC-SCI's, as the source
73915e32d5dSMike Smith      * (EC-SCI) will still be high and thus should trigger the GPE
74015e32d5dSMike Smith      * immediately after we re-enabling it.
74115e32d5dSMike Smith      */
742c07572e7STakanori Watanabe     if (sc->ec_pendquery){
743b37c9b90STakanori Watanabe 	    if(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
744c07572e7STakanori Watanabe 		EcGpeQueryHandler, sc) != AE_OK)
745c07572e7STakanori Watanabe 		    printf("Pend Query Queuing Failed\n");
746c07572e7STakanori Watanabe 	    sc->ec_pendquery = 0;
747c07572e7STakanori Watanabe     }
748c07572e7STakanori Watanabe 
74915e32d5dSMike Smith     if (AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
75015e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRequest: Unable to clear the EC GPE.\n");
75115e32d5dSMike Smith     if (AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
75215e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRequest: Unable to re-enable the EC GPE.\n");
75315e32d5dSMike Smith 
75415e32d5dSMike Smith     return(Status);
75515e32d5dSMike Smith }
75615e32d5dSMike Smith 
75715e32d5dSMike Smith 
75815e32d5dSMike Smith static ACPI_STATUS
75915e32d5dSMike Smith EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
76015e32d5dSMike Smith {
76115e32d5dSMike Smith     ACPI_STATUS	Status;
76215e32d5dSMike Smith 
76315e32d5dSMike Smith     if (!EcIsLocked(sc))
76415e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead called without EC lock!\n");
76515e32d5dSMike Smith 
76615e32d5dSMike Smith     /*EcBurstEnable(EmbeddedController);*/
76715e32d5dSMike Smith 
76815e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_READ);
769c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
77015e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process read command.\n");
77115e32d5dSMike Smith 	return(Status);
77215e32d5dSMike Smith     }
77315e32d5dSMike Smith 
77415e32d5dSMike Smith     EC_SET_DATA(sc, Address);
775c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_OUTPUT_BUFFER_FULL)) != AE_OK) {
77615e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to send data.\n");
77715e32d5dSMike Smith 	return(Status);
77815e32d5dSMike Smith     }
77915e32d5dSMike Smith 
78015e32d5dSMike Smith     (*Data) = EC_GET_DATA(sc);
78115e32d5dSMike Smith 
78215e32d5dSMike Smith     /*EcBurstDisable(EmbeddedController);*/
78315e32d5dSMike Smith 
78415e32d5dSMike Smith     return(AE_OK);
78515e32d5dSMike Smith }
78615e32d5dSMike Smith 
78715e32d5dSMike Smith static ACPI_STATUS
78815e32d5dSMike Smith EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
78915e32d5dSMike Smith {
79015e32d5dSMike Smith     ACPI_STATUS	Status;
79115e32d5dSMike Smith 
79215e32d5dSMike Smith     if (!EcIsLocked(sc))
79315e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWrite called without EC lock!\n");
79415e32d5dSMike Smith 
79515e32d5dSMike Smith     /*EcBurstEnable(EmbeddedController);*/
79615e32d5dSMike Smith 
79715e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_WRITE);
798c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
79915e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process write command.\n");
80015e32d5dSMike Smith 	return(Status);
80115e32d5dSMike Smith     }
80215e32d5dSMike Smith 
80315e32d5dSMike Smith     EC_SET_DATA(sc, Address);
804c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
80515e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process address.\n");
80615e32d5dSMike Smith 	return(Status);
80715e32d5dSMike Smith     }
80815e32d5dSMike Smith 
80915e32d5dSMike Smith     EC_SET_DATA(sc, *Data);
810c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
81115e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process data.\n");
81215e32d5dSMike Smith 	return(Status);
81315e32d5dSMike Smith     }
81415e32d5dSMike Smith 
81515e32d5dSMike Smith     /*EcBurstDisable(EmbeddedController);*/
81615e32d5dSMike Smith 
81715e32d5dSMike Smith     return(AE_OK);
81815e32d5dSMike Smith }
819