xref: /freebsd/sys/dev/acpica/acpi_ec.c (revision dbd0058a4e14d3d945a03ea2a74f03d7276e3258)
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
155dbd0058aSMike Smith ACPI_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;
242dbd0058aSMike Smith     int			ec_lockhandle;
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 
254dbd0058aSMike Smith     /* XXX WAIT_FOREVER is probably a bad idea, what is a better time? */
255dbd0058aSMike Smith     if (ACPI_SUCCESS(status = AcpiAcquireGlobalLock(WAIT_FOREVER, &sc->ec_lockhandle)))
25615e32d5dSMike Smith 	(sc)->ec_locked = 1;
257c573e654SMitsuru IWASAKI 
25815e32d5dSMike Smith     return(status);
25915e32d5dSMike Smith }
26015e32d5dSMike Smith 
26115e32d5dSMike Smith static __inline void
26215e32d5dSMike Smith EcUnlock(struct acpi_ec_softc *sc)
26315e32d5dSMike Smith {
26415e32d5dSMike Smith     (sc)->ec_locked = 0;
265dbd0058aSMike Smith     AcpiReleaseGlobalLock(sc->ec_lockhandle);
26615e32d5dSMike Smith }
26715e32d5dSMike Smith 
26815e32d5dSMike Smith static __inline int
26915e32d5dSMike Smith EcIsLocked(struct acpi_ec_softc *sc)
27015e32d5dSMike Smith {
27115e32d5dSMike Smith     return((sc)->ec_locked != 0);
27215e32d5dSMike Smith }
27315e32d5dSMike Smith 
27415e32d5dSMike Smith typedef struct
27515e32d5dSMike Smith {
27615e32d5dSMike Smith     EC_COMMAND              Command;
27715e32d5dSMike Smith     UINT8                   Address;
27815e32d5dSMike Smith     UINT8                   Data;
27915e32d5dSMike Smith } EC_REQUEST;
28015e32d5dSMike Smith 
28115e32d5dSMike Smith static void		EcGpeHandler(void *Context);
28215e32d5dSMike Smith static ACPI_STATUS	EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function,
28315e32d5dSMike Smith 					   void *Context, void **return_Context);
28476f2b644SMike Smith static ACPI_STATUS	EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, ACPI_INTEGER *Value,
28515e32d5dSMike Smith 				      void *Context, void *RegionContext);
28615e32d5dSMike Smith 
28715e32d5dSMike Smith static ACPI_STATUS	EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event);
28815e32d5dSMike Smith static ACPI_STATUS	EcQuery(struct acpi_ec_softc *sc, UINT8 *Data);
28915e32d5dSMike Smith static ACPI_STATUS	EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest);
29015e32d5dSMike Smith static ACPI_STATUS	EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
29115e32d5dSMike Smith static ACPI_STATUS	EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
29215e32d5dSMike Smith 
29315e32d5dSMike Smith static void		acpi_ec_identify(driver_t driver, device_t bus);
29415e32d5dSMike Smith static int		acpi_ec_probe(device_t dev);
29515e32d5dSMike Smith static int		acpi_ec_attach(device_t dev);
29615e32d5dSMike Smith 
29715e32d5dSMike Smith static device_method_t acpi_ec_methods[] = {
29815e32d5dSMike Smith     /* Device interface */
29915e32d5dSMike Smith     DEVMETHOD(device_identify,	acpi_ec_identify),
30015e32d5dSMike Smith     DEVMETHOD(device_probe,	acpi_ec_probe),
30115e32d5dSMike Smith     DEVMETHOD(device_attach,	acpi_ec_attach),
30215e32d5dSMike Smith 
30315e32d5dSMike Smith     {0, 0}
30415e32d5dSMike Smith };
30515e32d5dSMike Smith 
30615e32d5dSMike Smith static driver_t acpi_ec_driver = {
30715e32d5dSMike Smith     "acpi_ec",
30815e32d5dSMike Smith     acpi_ec_methods,
30915e32d5dSMike Smith     sizeof(struct acpi_ec_softc),
31015e32d5dSMike Smith };
31115e32d5dSMike Smith 
3123273b005SMike Smith static devclass_t acpi_ec_devclass;
31315e32d5dSMike Smith DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
31415e32d5dSMike Smith 
31515e32d5dSMike Smith /*
31615e32d5dSMike Smith  * Look for an ECDT table and if we find one, set up a default EC
31715e32d5dSMike Smith  * space handler to catch possible attempts to access EC space before
31815e32d5dSMike Smith  * we have a real driver instance in place.
31915e32d5dSMike Smith  * We're not really an identify routine, but because we get called
32015e32d5dSMike Smith  * before most other things, this works out OK.
32115e32d5dSMike Smith  */
32215e32d5dSMike Smith static void
32315e32d5dSMike Smith acpi_ec_identify(driver_t driver, device_t bus)
32415e32d5dSMike Smith {
325dbd0058aSMike Smith     ACPI_FUNCTION_TRACE(__func__);
32615e32d5dSMike Smith 
32715e32d5dSMike Smith     /* XXX implement - need an ACPI 2.0 system to test this */
3280ae55423SMike Smith 
3290ae55423SMike Smith     return_VOID;
33015e32d5dSMike Smith }
33115e32d5dSMike Smith 
33215e32d5dSMike Smith /*
33315e32d5dSMike Smith  * We could setup resources in the probe routine in order to have them printed
33415e32d5dSMike Smith  * when the device is attached.
33515e32d5dSMike Smith  */
33615e32d5dSMike Smith static int
33715e32d5dSMike Smith acpi_ec_probe(device_t dev)
33815e32d5dSMike Smith {
3390ae55423SMike Smith 
34015e32d5dSMike Smith     if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
3410ae55423SMike Smith 	!acpi_disabled("ec") &&
34215e32d5dSMike Smith 	acpi_MatchHid(dev, "PNP0C09")) {
34315e32d5dSMike Smith 
34415e32d5dSMike Smith 	/*
34515e32d5dSMike Smith 	 * Set device description
34615e32d5dSMike Smith 	 */
34715e32d5dSMike Smith 	device_set_desc(dev, "embedded controller");
34815e32d5dSMike Smith 
34915e32d5dSMike Smith 	return(0);
35015e32d5dSMike Smith     }
35115e32d5dSMike Smith     return(ENXIO);
35215e32d5dSMike Smith }
35315e32d5dSMike Smith 
35415e32d5dSMike Smith static int
35515e32d5dSMike Smith acpi_ec_attach(device_t dev)
35615e32d5dSMike Smith {
35715e32d5dSMike Smith     struct acpi_ec_softc	*sc;
35815e32d5dSMike Smith     ACPI_STATUS			Status;
359f8372adeSTakanori Watanabe     int errval = 0;
360dbd0058aSMike Smith 
361dbd0058aSMike Smith     ACPI_FUNCTION_TRACE(__func__);
3620ae55423SMike Smith 
36315e32d5dSMike Smith     /*
36415e32d5dSMike Smith      * Fetch/initialise softc
36515e32d5dSMike Smith      */
36615e32d5dSMike Smith     sc = device_get_softc(dev);
367c07572e7STakanori Watanabe     bzero(sc, sizeof(*sc));
36815e32d5dSMike Smith     sc->ec_dev = dev;
36915e32d5dSMike Smith     sc->ec_handle = acpi_get_handle(dev);
37015e32d5dSMike Smith 
37115e32d5dSMike Smith     /*
37215e32d5dSMike Smith      * Attach bus resources
37315e32d5dSMike Smith      */
37415e32d5dSMike Smith     sc->ec_data_rid = 0;
37515e32d5dSMike Smith     if ((sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_data_rid,
37615e32d5dSMike Smith 					      0, ~0, 1, RF_ACTIVE)) == NULL) {
37715e32d5dSMike Smith 	device_printf(dev, "can't allocate data port\n");
378f8372adeSTakanori Watanabe 	errval = ENXIO;
379f8372adeSTakanori Watanabe 	goto out;
38015e32d5dSMike Smith     }
38115e32d5dSMike Smith     sc->ec_data_tag = rman_get_bustag(sc->ec_data_res);
38215e32d5dSMike Smith     sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res);
38315e32d5dSMike Smith 
38415e32d5dSMike Smith     sc->ec_csr_rid = 1;
38515e32d5dSMike Smith     if ((sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_csr_rid,
38615e32d5dSMike Smith 					     0, ~0, 1, RF_ACTIVE)) == NULL) {
38715e32d5dSMike Smith 	device_printf(dev, "can't allocate command/status port\n");
388f8372adeSTakanori Watanabe 	errval = ENXIO;
389f8372adeSTakanori Watanabe 	goto out;
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      */
4004c1cdee6SMike Smith     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attaching GPE\n"));
401dbd0058aSMike Smith     if (ACPI_FAILURE(Status = acpi_EvaluateInteger(sc->ec_handle, "_GPE", &sc->ec_gpebit))) {
402bfae45aaSMike Smith 	device_printf(dev, "can't evaluate _GPE - %s\n", AcpiFormatException(Status));
403f8372adeSTakanori Watanabe 	errval =ENXIO;
404f8372adeSTakanori Watanabe 	goto out;
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      */
415dbd0058aSMike Smith     if (ACPI_FAILURE(Status = AcpiInstallGpeHandler(sc->ec_gpebit,
416dbd0058aSMike Smith 						    ACPI_EVENT_LEVEL_TRIGGERED |
417dbd0058aSMike Smith 						    ACPI_EVENT_EDGE_TRIGGERED,
418dbd0058aSMike Smith 						    EcGpeHandler, sc))) {
41976d1dff4SMike Smith 	device_printf(dev, "can't install GPE handler for %s - %s\n",
420bfae45aaSMike Smith 		      acpi_name(sc->ec_handle), AcpiFormatException(Status));
421f8372adeSTakanori Watanabe 	errval = ENXIO;
422f8372adeSTakanori Watanabe 	goto out;
42315e32d5dSMike Smith     }
42415e32d5dSMike Smith 
42515e32d5dSMike Smith     /*
42615e32d5dSMike Smith      * Install address space handler
42715e32d5dSMike Smith      */
4284c1cdee6SMike Smith     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attaching address space handler\n"));
429dbd0058aSMike Smith     if (ACPI_FAILURE(Status = AcpiInstallAddressSpaceHandler(sc->ec_handle,
430dbd0058aSMike Smith 							     ACPI_ADR_SPACE_EC,
431dbd0058aSMike Smith 							     EcSpaceHandler,
432dbd0058aSMike Smith 							     EcSpaceSetup,
433dbd0058aSMike Smith 							     sc))) {
43476d1dff4SMike Smith 	device_printf(dev, "can't install address space handler for %s - %s\n",
435bfae45aaSMike Smith 		      acpi_name(sc->ec_handle), AcpiFormatException(Status));
43676d1dff4SMike Smith 	panic("very suck");
437f8372adeSTakanori Watanabe 	errval = ENXIO;
438f8372adeSTakanori Watanabe 	goto out;
43915e32d5dSMike Smith     }
4404c1cdee6SMike Smith     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attach complete\n"));
4410ae55423SMike Smith     return_VALUE(0);
442f8372adeSTakanori Watanabe  out:
443f8372adeSTakanori Watanabe     if(sc->ec_csr_res)
444f8372adeSTakanori Watanabe 	bus_release_resource(sc->ec_dev, SYS_RES_IOPORT, sc->ec_csr_rid,
445f8372adeSTakanori Watanabe 			     sc->ec_csr_res);
446f8372adeSTakanori Watanabe     if(sc->ec_data_res)
447f8372adeSTakanori Watanabe         bus_release_resource(sc->ec_dev, SYS_RES_IOPORT, sc->ec_data_rid,
448f8372adeSTakanori Watanabe 			     sc->ec_data_res);
449f8372adeSTakanori Watanabe     return_VALUE(errval);
45015e32d5dSMike Smith }
45115e32d5dSMike Smith 
45215e32d5dSMike Smith static void
453c07572e7STakanori Watanabe EcGpeQueryHandler(void *Context)
45415e32d5dSMike Smith {
45515e32d5dSMike Smith     struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
45615e32d5dSMike Smith     UINT8			Data;
45715e32d5dSMike Smith     ACPI_STATUS			Status;
45815e32d5dSMike Smith     char			qxx[5];
45915e32d5dSMike Smith 
460dbd0058aSMike Smith     ACPI_FUNCTION_TRACE(__func__);
4610ae55423SMike Smith 
46215e32d5dSMike Smith     for (;;) {
46315e32d5dSMike Smith 
46415e32d5dSMike Smith 	/*
46515e32d5dSMike Smith 	 * Check EC_SCI.
46615e32d5dSMike Smith 	 *
46715e32d5dSMike Smith 	 * Bail out if the EC_SCI bit of the status register is not set.
46815e32d5dSMike Smith 	 * Note that this function should only be called when
46915e32d5dSMike Smith 	 * this bit is set (polling is used to detect IBE/OBF events).
47015e32d5dSMike Smith 	 *
47115e32d5dSMike Smith 	 * It is safe to do this without locking the controller, as it's
47215e32d5dSMike Smith 	 * OK to call EcQuery when there's no data ready; in the worst
47315e32d5dSMike Smith 	 * case we should just find nothing waiting for us and bail.
47415e32d5dSMike Smith 	 */
47515e32d5dSMike Smith 	if (!(EC_GET_CSR(sc) & EC_EVENT_SCI))
47615e32d5dSMike Smith 	    break;
47715e32d5dSMike Smith 
47815e32d5dSMike Smith 	/*
47915e32d5dSMike Smith 	 * Find out why the EC is signalling us
48015e32d5dSMike Smith 	 */
48115e32d5dSMike Smith 	Status = EcQuery(sc, &Data);
48215e32d5dSMike Smith 
48315e32d5dSMike Smith 	/*
48415e32d5dSMike Smith 	 * If we failed to get anything from the EC, give up
48515e32d5dSMike Smith 	 */
486dbd0058aSMike Smith 	if (ACPI_FAILURE(Status)) {
4876971b3c7SMitsuru IWASAKI 	    ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
4886971b3c7SMitsuru IWASAKI 		"GPE query failed - %s\n", AcpiFormatException(Status));
48915e32d5dSMike Smith 	    break;
49015e32d5dSMike Smith 	}
49115e32d5dSMike Smith 
49215e32d5dSMike Smith 	/*
49315e32d5dSMike Smith 	 * Evaluate _Qxx to respond to the controller.
49415e32d5dSMike Smith 	 */
49515e32d5dSMike Smith 	sprintf(qxx, "_Q%02x", Data);
49615e32d5dSMike Smith 	strupr(qxx);
497ee785aa9SJohn Baldwin 	Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL);
498ee785aa9SJohn Baldwin 	/*
499ee785aa9SJohn Baldwin 	 * Ignore spurious query requests.
500ee785aa9SJohn Baldwin 	 */
501dbd0058aSMike Smith 	if (ACPI_FAILURE(Status) && (Data != 0 || Status != AE_NOT_FOUND)) {
5026971b3c7SMitsuru IWASAKI 	    ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
5036971b3c7SMitsuru IWASAKI 	    	"evaluation of GPE query method %s failed - %s\n",
504bfae45aaSMike Smith 			qxx, AcpiFormatException(Status));
50515e32d5dSMike Smith 	}
50615e32d5dSMike Smith     }
507c07572e7STakanori Watanabe         /* I know I request Level trigger cleanup */
508dbd0058aSMike Smith     if (ACPI_FAILURE(AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE)))
509c07572e7STakanori Watanabe 	    printf("EcGpeQueryHandler:ClearEvent Failed\n");
510dbd0058aSMike Smith     if (ACPI_FAILURE(AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE, 0)))
511c07572e7STakanori Watanabe 	    printf("EcGpeQueryHandler:EnableEvent Failed\n");
512874d21b4STakanori Watanabe     return_VOID;
513c07572e7STakanori Watanabe }
51442f6d122SMike Smith 
515a9cf0dffSMike Smith /*
516a9cf0dffSMike Smith  * Handle a GPE sent to us.
517a9cf0dffSMike Smith  */
518a9cf0dffSMike Smith static void
519a9cf0dffSMike Smith EcGpeHandler(void *Context)
520c07572e7STakanori Watanabe {
521c07572e7STakanori Watanabe     struct acpi_ec_softc *sc = Context;
522c07572e7STakanori Watanabe     int csrvalue;
523a9cf0dffSMike Smith 
524c07572e7STakanori Watanabe     /*
525c07572e7STakanori Watanabe      * If EC is locked, the intr must process EcRead/Write wait only.
526c07572e7STakanori Watanabe      * Query request must be pending.
527c07572e7STakanori Watanabe      */
528c07572e7STakanori Watanabe     if (EcIsLocked(sc)){
529c07572e7STakanori Watanabe 	csrvalue = EC_GET_CSR(sc);
530c07572e7STakanori Watanabe 	if (csrvalue & EC_EVENT_SCI)
531c07572e7STakanori Watanabe 	    sc->ec_pendquery = 1;
532c07572e7STakanori Watanabe 	if ((csrvalue & EC_FLAG_OUTPUT_BUFFER)
533c07572e7STakanori Watanabe 	    || !(csrvalue & EC_FLAG_INPUT_BUFFER)) {
534c07572e7STakanori Watanabe 	    sc->ec_csrvalue = csrvalue;
535c07572e7STakanori Watanabe 	    wakeup((void *)&sc->ec_csrvalue);
536c07572e7STakanori Watanabe 	}
537c07572e7STakanori Watanabe     }else{
538c07572e7STakanori Watanabe 	/* Queue GpeQuery Handler */
539dbd0058aSMike Smith 	if (ACPI_FAILURE(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
540dbd0058aSMike Smith 				    EcGpeQueryHandler,Context))) {
541c07572e7STakanori Watanabe 	    printf("QueryHandler Queuing Failed\n");
542c07572e7STakanori Watanabe 	}
543c07572e7STakanori Watanabe     }
544874d21b4STakanori Watanabe     return;
54515e32d5dSMike Smith }
54615e32d5dSMike Smith 
54715e32d5dSMike Smith static ACPI_STATUS
54815e32d5dSMike Smith EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, void **RegionContext)
54915e32d5dSMike Smith {
55042f6d122SMike Smith 
551dbd0058aSMike Smith     ACPI_FUNCTION_TRACE(__func__);
55242f6d122SMike Smith 
55315e32d5dSMike Smith     /*
55415e32d5dSMike Smith      * Just pass the context through, there's nothing to do here.
55515e32d5dSMike Smith      */
55615e32d5dSMike Smith     *RegionContext = Context;
55715e32d5dSMike Smith 
55842f6d122SMike Smith     return_ACPI_STATUS(AE_OK);
55915e32d5dSMike Smith }
56015e32d5dSMike Smith 
56115e32d5dSMike Smith static ACPI_STATUS
56276f2b644SMike Smith EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, ACPI_INTEGER *Value,
563042283a6SMike Smith 	       void *Context, void *RegionContext)
56415e32d5dSMike Smith {
56515e32d5dSMike Smith     struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
56615e32d5dSMike Smith     ACPI_STATUS			Status = AE_OK;
56715e32d5dSMike Smith     EC_REQUEST			EcRequest;
568ee785aa9SJohn Baldwin     int				i;
56915e32d5dSMike Smith 
570dbd0058aSMike Smith     ACPI_FUNCTION_TRACE_U32(__func__, (UINT32)Address);
5710ae55423SMike Smith 
572ee785aa9SJohn Baldwin     if ((Address > 0xFF) || (width % 8 != 0) || (Value == NULL) || (Context == NULL))
5730ae55423SMike Smith         return_ACPI_STATUS(AE_BAD_PARAMETER);
57415e32d5dSMike Smith 
57515e32d5dSMike Smith     switch (Function) {
57676f2b644SMike Smith     case ACPI_READ:
57715e32d5dSMike Smith         EcRequest.Command = EC_COMMAND_READ;
57815e32d5dSMike Smith         EcRequest.Address = Address;
5792a4ac806SMike Smith 	(*Value) = 0;
58015e32d5dSMike Smith         break;
58115e32d5dSMike Smith 
58276f2b644SMike Smith     case ACPI_WRITE:
58315e32d5dSMike Smith         EcRequest.Command = EC_COMMAND_WRITE;
58415e32d5dSMike Smith         EcRequest.Address = Address;
58515e32d5dSMike Smith         break;
58615e32d5dSMike Smith 
58715e32d5dSMike Smith     default:
58815e32d5dSMike Smith 	device_printf(sc->ec_dev, "invalid Address Space function %d\n", Function);
5890ae55423SMike Smith         return_ACPI_STATUS(AE_BAD_PARAMETER);
59015e32d5dSMike Smith     }
59115e32d5dSMike Smith 
59215e32d5dSMike Smith     /*
59315e32d5dSMike Smith      * Perform the transaction.
59415e32d5dSMike Smith      */
595ee785aa9SJohn Baldwin     for (i = 0; i < width; i += 8) {
59676f2b644SMike Smith 	if (Function == ACPI_READ)
597ee785aa9SJohn Baldwin 	    EcRequest.Data = 0;
598ee785aa9SJohn Baldwin 	else
599ee785aa9SJohn Baldwin 	    EcRequest.Data = (UINT8)((*Value) >> i);
600dbd0058aSMike Smith 	if (ACPI_FAILURE(Status = EcTransaction(sc, &EcRequest)))
601ee785aa9SJohn Baldwin 	    break;
60276f2b644SMike Smith         (*Value) |= (ACPI_INTEGER)EcRequest.Data << i;
603ee785aa9SJohn Baldwin 	if (++EcRequest.Address == 0)
604ee785aa9SJohn Baldwin             return_ACPI_STATUS(AE_BAD_PARAMETER);
605ee785aa9SJohn Baldwin     }
6060ae55423SMike Smith     return_ACPI_STATUS(Status);
60715e32d5dSMike Smith }
6082a4ac806SMike Smith 
609a9cf0dffSMike Smith /*
610a9cf0dffSMike Smith  * Wait for an event interrupt for a specific condition.
611a9cf0dffSMike Smith  */
612c07572e7STakanori Watanabe static ACPI_STATUS
613c07572e7STakanori Watanabe EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event)
614c07572e7STakanori Watanabe {
615c07572e7STakanori Watanabe     EC_STATUS	EcStatus;
616c07572e7STakanori Watanabe     int		i;
617a9cf0dffSMike Smith 
618dbd0058aSMike Smith     ACPI_FUNCTION_TRACE_U32(__func__, (UINT32)Event);
619a9cf0dffSMike Smith 
620a9cf0dffSMike Smith     /* XXX this should test whether interrupts are available some other way */
621c07572e7STakanori Watanabe     if(cold)
622a9cf0dffSMike Smith 	return_ACPI_STATUS(EcWaitEvent(sc, Event));
623a9cf0dffSMike Smith 
624c07572e7STakanori Watanabe     if (!EcIsLocked(sc))
6256971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
6266971b3c7SMitsuru IWASAKI 	    "EcWaitEventIntr called without EC lock!\n");
627a9cf0dffSMike Smith 
628c07572e7STakanori Watanabe     EcStatus = EC_GET_CSR(sc);
629a9cf0dffSMike Smith 
630a9cf0dffSMike Smith     /* XXX waiting too long? */
631c07572e7STakanori Watanabe     for(i = 0; i < 10; i++){
632a9cf0dffSMike Smith 	/*
633a9cf0dffSMike Smith 	 * Check EC status against the desired event.
634a9cf0dffSMike Smith 	 */
635c07572e7STakanori Watanabe     	if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
636c07572e7STakanori Watanabe 	    (EcStatus & EC_FLAG_OUTPUT_BUFFER))
637a9cf0dffSMike Smith 	    return_ACPI_STATUS(AE_OK);
638c07572e7STakanori Watanabe 
639c07572e7STakanori Watanabe 	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
640c07572e7STakanori Watanabe 	    !(EcStatus & EC_FLAG_INPUT_BUFFER))
641a9cf0dffSMike Smith 	    return_ACPI_STATUS(AE_OK);
642a9cf0dffSMike Smith 
643c07572e7STakanori Watanabe 	sc->ec_csrvalue = 0;
644a9cf0dffSMike Smith 	if (ACPI_MSLEEP(&sc->ec_csrvalue, &acpi_mutex, PZERO, "EcWait", 1) != EWOULDBLOCK){
645c07572e7STakanori Watanabe 	    EcStatus = sc->ec_csrvalue;
646c07572e7STakanori Watanabe 	}else{
647c07572e7STakanori Watanabe 	    EcStatus = EC_GET_CSR(sc);
648c07572e7STakanori Watanabe 	}
649c07572e7STakanori Watanabe     }
650a9cf0dffSMike Smith     return_ACPI_STATUS(AE_ERROR);
651c07572e7STakanori Watanabe }
65215e32d5dSMike Smith 
65315e32d5dSMike Smith static ACPI_STATUS
65415e32d5dSMike Smith EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
65515e32d5dSMike Smith {
65615e32d5dSMike Smith     EC_STATUS	EcStatus;
65715e32d5dSMike Smith     UINT32	i = 0;
65815e32d5dSMike Smith 
65915e32d5dSMike Smith     if (!EcIsLocked(sc))
6606971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
6616971b3c7SMitsuru IWASAKI 	    "EcWaitEvent called without EC lock!\n");
66215e32d5dSMike Smith 
66315e32d5dSMike Smith     /*
66415e32d5dSMike Smith      * Stall 1us:
66515e32d5dSMike Smith      * ----------
66615e32d5dSMike Smith      * Stall for 1 microsecond before reading the status register
66715e32d5dSMike Smith      * for the first time.  This allows the EC to set the IBF/OBF
66815e32d5dSMike Smith      * bit to its proper state.
66915e32d5dSMike Smith      *
67015e32d5dSMike Smith      * XXX it is not clear why we read the CSR twice.
67115e32d5dSMike Smith      */
672da3b867eSMike Smith     AcpiOsStall(1);
67315e32d5dSMike Smith     EcStatus = EC_GET_CSR(sc);
67415e32d5dSMike Smith 
67515e32d5dSMike Smith     /*
67615e32d5dSMike Smith      * Wait For Event:
67715e32d5dSMike Smith      * ---------------
67815e32d5dSMike Smith      * Poll the EC status register to detect completion of the last
6792a4ac806SMike Smith      * command.  Wait up to 10ms (in 10us chunks) for this to occur.
68015e32d5dSMike Smith      */
6812a4ac806SMike Smith     for (i = 0; i < 1000; i++) {
68215e32d5dSMike Smith 	EcStatus = EC_GET_CSR(sc);
68315e32d5dSMike Smith 
68415e32d5dSMike Smith         if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
68515e32d5dSMike Smith             (EcStatus & EC_FLAG_OUTPUT_BUFFER))
68615e32d5dSMike Smith 	    return(AE_OK);
68715e32d5dSMike Smith 
68815e32d5dSMike Smith 	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
68915e32d5dSMike Smith             !(EcStatus & EC_FLAG_INPUT_BUFFER))
69015e32d5dSMike Smith 	    return(AE_OK);
69115e32d5dSMike Smith 
692da3b867eSMike Smith 	AcpiOsStall(10);
69315e32d5dSMike Smith     }
69415e32d5dSMike Smith 
69515e32d5dSMike Smith     return(AE_ERROR);
69615e32d5dSMike Smith }
69715e32d5dSMike Smith 
69815e32d5dSMike Smith static ACPI_STATUS
69915e32d5dSMike Smith EcQuery(struct acpi_ec_softc *sc, UINT8 *Data)
70015e32d5dSMike Smith {
70115e32d5dSMike Smith     ACPI_STATUS	Status;
70215e32d5dSMike Smith 
703dbd0058aSMike Smith     if (ACPI_FAILURE(Status = EcLock(sc)))
70415e32d5dSMike Smith 	return(Status);
70515e32d5dSMike Smith 
70615e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_QUERY);
707dbd0058aSMike Smith     if (ACPI_SUCCESS(Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL)))
70815e32d5dSMike Smith 	*Data = EC_GET_DATA(sc);
70915e32d5dSMike Smith 
71015e32d5dSMike Smith     EcUnlock(sc);
71115e32d5dSMike Smith 
712dbd0058aSMike Smith     if (ACPI_FAILURE(Status))
7136971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
7146971b3c7SMitsuru IWASAKI 	    "timeout waiting for EC to respond to EC_COMMAND_QUERY\n");
71515e32d5dSMike Smith     return(Status);
71615e32d5dSMike Smith }
71715e32d5dSMike Smith 
71815e32d5dSMike Smith static ACPI_STATUS
71915e32d5dSMike Smith EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
72015e32d5dSMike Smith {
72115e32d5dSMike Smith     ACPI_STATUS	Status;
72215e32d5dSMike Smith 
72315e32d5dSMike Smith     /*
72415e32d5dSMike Smith      * Lock the EC
72515e32d5dSMike Smith      */
726dbd0058aSMike Smith     if (ACPI_FAILURE(Status = EcLock(sc)))
72715e32d5dSMike Smith 	return(Status);
72815e32d5dSMike Smith 
72915e32d5dSMike Smith     /*
73015e32d5dSMike Smith      * Perform the transaction.
73115e32d5dSMike Smith      */
73215e32d5dSMike Smith     switch (EcRequest->Command) {
73315e32d5dSMike Smith     case EC_COMMAND_READ:
73415e32d5dSMike Smith 	Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data));
73515e32d5dSMike Smith 	break;
73615e32d5dSMike Smith 
73715e32d5dSMike Smith     case EC_COMMAND_WRITE:
73815e32d5dSMike Smith 	Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data));
73915e32d5dSMike Smith 	break;
74015e32d5dSMike Smith 
74115e32d5dSMike Smith     default:
74215e32d5dSMike Smith 	Status = AE_SUPPORT;
74315e32d5dSMike Smith 	break;
74415e32d5dSMike Smith     }
74515e32d5dSMike Smith 
74615e32d5dSMike Smith     /*
7472a4ac806SMike Smith      * Unlock the EC
7482a4ac806SMike Smith      */
7492a4ac806SMike Smith     EcUnlock(sc);
7502a4ac806SMike Smith 
7512a4ac806SMike Smith     /*
75215e32d5dSMike Smith      * Clear & Re-Enable the EC GPE:
75315e32d5dSMike Smith      * -----------------------------
75415e32d5dSMike Smith      * 'Consume' any EC GPE events that we generated while performing
75515e32d5dSMike Smith      * the transaction (e.g. IBF/OBF).	Clearing the GPE here shouldn't
75615e32d5dSMike Smith      * have an adverse affect on outstanding EC-SCI's, as the source
75715e32d5dSMike Smith      * (EC-SCI) will still be high and thus should trigger the GPE
75815e32d5dSMike Smith      * immediately after we re-enabling it.
75915e32d5dSMike Smith      */
760c07572e7STakanori Watanabe     if (sc->ec_pendquery){
761dbd0058aSMike Smith 	if (ACPI_FAILURE(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
762dbd0058aSMike Smith 						 EcGpeQueryHandler, sc)))
763c07572e7STakanori Watanabe 	    printf("Pend Query Queuing Failed\n");
764c07572e7STakanori Watanabe 	sc->ec_pendquery = 0;
765c07572e7STakanori Watanabe     }
766c07572e7STakanori Watanabe 
767dbd0058aSMike Smith     if (ACPI_FAILURE(AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE)))
7686971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
7696971b3c7SMitsuru IWASAKI 	    "EcRequest: Unable to clear the EC GPE.\n");
770dbd0058aSMike Smith     if (ACPI_FAILURE(AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE, 0)))
7716971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
7726971b3c7SMitsuru IWASAKI 	    "EcRequest: Unable to re-enable the EC GPE.\n");
77315e32d5dSMike Smith 
77415e32d5dSMike Smith     return(Status);
77515e32d5dSMike Smith }
77615e32d5dSMike Smith 
77715e32d5dSMike Smith 
77815e32d5dSMike Smith static ACPI_STATUS
77915e32d5dSMike Smith EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
78015e32d5dSMike Smith {
78115e32d5dSMike Smith     ACPI_STATUS	Status;
78215e32d5dSMike Smith 
78315e32d5dSMike Smith     if (!EcIsLocked(sc))
7846971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
7856971b3c7SMitsuru IWASAKI 	    "EcRead called without EC lock!\n");
78615e32d5dSMike Smith 
78715e32d5dSMike Smith     /*EcBurstEnable(EmbeddedController);*/
78815e32d5dSMike Smith 
78915e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_READ);
790dbd0058aSMike Smith     if (ACPI_FAILURE(Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY))) {
7916971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
7926971b3c7SMitsuru IWASAKI 	    "EcRead: Failed waiting for EC to process read command.\n");
79315e32d5dSMike Smith 	return(Status);
79415e32d5dSMike Smith     }
79515e32d5dSMike Smith 
79615e32d5dSMike Smith     EC_SET_DATA(sc, Address);
797dbd0058aSMike Smith     if (ACPI_FAILURE(Status = EcWaitEventIntr(sc, EC_EVENT_OUTPUT_BUFFER_FULL))) {
7986971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
7996971b3c7SMitsuru IWASAKI 	    "EcRead: Failed waiting for EC to send data.\n");
80015e32d5dSMike Smith 	return(Status);
80115e32d5dSMike Smith     }
80215e32d5dSMike Smith 
80315e32d5dSMike Smith     (*Data) = EC_GET_DATA(sc);
80415e32d5dSMike Smith 
80515e32d5dSMike Smith     /*EcBurstDisable(EmbeddedController);*/
80615e32d5dSMike Smith 
80715e32d5dSMike Smith     return(AE_OK);
80815e32d5dSMike Smith }
80915e32d5dSMike Smith 
81015e32d5dSMike Smith static ACPI_STATUS
81115e32d5dSMike Smith EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
81215e32d5dSMike Smith {
81315e32d5dSMike Smith     ACPI_STATUS	Status;
81415e32d5dSMike Smith 
81515e32d5dSMike Smith     if (!EcIsLocked(sc))
8166971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
8176971b3c7SMitsuru IWASAKI 	    "EcWrite called without EC lock!\n");
81815e32d5dSMike Smith 
81915e32d5dSMike Smith     /*EcBurstEnable(EmbeddedController);*/
82015e32d5dSMike Smith 
82115e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_WRITE);
822dbd0058aSMike Smith     if (ACPI_FAILURE(Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY))) {
8236971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
8246971b3c7SMitsuru IWASAKI 	    "EcWrite: Failed waiting for EC to process write command.\n");
82515e32d5dSMike Smith 	return(Status);
82615e32d5dSMike Smith     }
82715e32d5dSMike Smith 
82815e32d5dSMike Smith     EC_SET_DATA(sc, Address);
829dbd0058aSMike Smith     if (ACPI_FAILURE(Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY))) {
8306971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
8316971b3c7SMitsuru IWASAKI 	    "EcRead: Failed waiting for EC to process address.\n");
83215e32d5dSMike Smith 	return(Status);
83315e32d5dSMike Smith     }
83415e32d5dSMike Smith 
83515e32d5dSMike Smith     EC_SET_DATA(sc, *Data);
836dbd0058aSMike Smith     if (ACPI_FAILURE(Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY))) {
8376971b3c7SMitsuru IWASAKI 	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
8386971b3c7SMitsuru IWASAKI 	    "EcWrite: Failed waiting for EC to process data.\n");
83915e32d5dSMike Smith 	return(Status);
84015e32d5dSMike Smith     }
84115e32d5dSMike Smith 
84215e32d5dSMike Smith     /*EcBurstDisable(EmbeddedController);*/
84315e32d5dSMike Smith 
84415e32d5dSMike Smith     return(AE_OK);
84515e32d5dSMike Smith }
846