xref: /freebsd/sys/dev/acpica/acpi_ec.c (revision c07572e7ad2a1765d62ff4b8822e3993b4a9a36f)
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  */
1550ae55423SMike Smith #define _COMPONENT	EMBEDDED_CONTROLLER
1560ae55423SMike Smith MODULE_NAME("EC")
1570ae55423SMike Smith 
15815e32d5dSMike Smith struct acpi_ec_softc {
15915e32d5dSMike Smith     device_t		ec_dev;
16015e32d5dSMike Smith     ACPI_HANDLE		ec_handle;
16115e32d5dSMike Smith     ACPI_HANDLE		ec_semaphore;
16215e32d5dSMike Smith     UINT32		ec_gpebit;
16315e32d5dSMike Smith 
16415e32d5dSMike Smith     int			ec_data_rid;
16515e32d5dSMike Smith     struct resource	*ec_data_res;
16615e32d5dSMike Smith     bus_space_tag_t	ec_data_tag;
16715e32d5dSMike Smith     bus_space_handle_t	ec_data_handle;
16815e32d5dSMike Smith 
16915e32d5dSMike Smith     int			ec_csr_rid;
17015e32d5dSMike Smith     struct resource	*ec_csr_res;
17115e32d5dSMike Smith     bus_space_tag_t	ec_csr_tag;
17215e32d5dSMike Smith     bus_space_handle_t	ec_csr_handle;
17315e32d5dSMike Smith 
17415e32d5dSMike Smith     int			ec_locked;
175c07572e7STakanori Watanabe     int			ec_pendquery;
176c07572e7STakanori Watanabe     int			ec_csrvalue;
17715e32d5dSMike Smith };
17815e32d5dSMike Smith 
17915e32d5dSMike Smith #define EC_LOCK_TIMEOUT	1000	/* 1ms */
18015e32d5dSMike Smith 
18115e32d5dSMike Smith static __inline ACPI_STATUS
18215e32d5dSMike Smith EcLock(struct acpi_ec_softc *sc)
18315e32d5dSMike Smith {
18415e32d5dSMike Smith     ACPI_STATUS	status;
18515e32d5dSMike Smith 
18615e32d5dSMike Smith     status = AcpiOsWaitSemaphore((sc)->ec_semaphore, 1, EC_LOCK_TIMEOUT);
18715e32d5dSMike Smith     (sc)->ec_locked = 1;
18815e32d5dSMike Smith     return(status);
18915e32d5dSMike Smith }
19015e32d5dSMike Smith 
19115e32d5dSMike Smith static __inline void
19215e32d5dSMike Smith EcUnlock(struct acpi_ec_softc *sc)
19315e32d5dSMike Smith {
19415e32d5dSMike Smith     (sc)->ec_locked = 0;
19515e32d5dSMike Smith     AcpiOsSignalSemaphore((sc)->ec_semaphore, 1);
19615e32d5dSMike Smith }
19715e32d5dSMike Smith 
19815e32d5dSMike Smith static __inline int
19915e32d5dSMike Smith EcIsLocked(struct acpi_ec_softc *sc)
20015e32d5dSMike Smith {
20115e32d5dSMike Smith     return((sc)->ec_locked != 0);
20215e32d5dSMike Smith }
20315e32d5dSMike Smith 
20415e32d5dSMike Smith typedef struct
20515e32d5dSMike Smith {
20615e32d5dSMike Smith     EC_COMMAND              Command;
20715e32d5dSMike Smith     UINT8                   Address;
20815e32d5dSMike Smith     UINT8                   Data;
20915e32d5dSMike Smith } EC_REQUEST;
21015e32d5dSMike Smith 
21115e32d5dSMike Smith static struct acpi_ec_softc	acpi_ec_default;	/* for the default EC handler */
21215e32d5dSMike Smith 
21315e32d5dSMike Smith static void		EcGpeHandler(void *Context);
21415e32d5dSMike Smith static ACPI_STATUS	EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function,
21515e32d5dSMike Smith 					   void *Context, void **return_Context);
216042283a6SMike Smith static ACPI_STATUS	EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
21715e32d5dSMike Smith 				      void *Context, void *RegionContext);
21815e32d5dSMike Smith 
21915e32d5dSMike Smith static ACPI_STATUS	EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event);
22015e32d5dSMike Smith static ACPI_STATUS	EcQuery(struct acpi_ec_softc *sc, UINT8 *Data);
22115e32d5dSMike Smith static ACPI_STATUS	EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest);
22215e32d5dSMike Smith static ACPI_STATUS	EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
22315e32d5dSMike Smith static ACPI_STATUS	EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data);
22415e32d5dSMike Smith 
22515e32d5dSMike Smith static void		acpi_ec_identify(driver_t driver, device_t bus);
22615e32d5dSMike Smith static int		acpi_ec_probe(device_t dev);
22715e32d5dSMike Smith static int		acpi_ec_attach(device_t dev);
22815e32d5dSMike Smith 
22915e32d5dSMike Smith static device_method_t acpi_ec_methods[] = {
23015e32d5dSMike Smith     /* Device interface */
23115e32d5dSMike Smith     DEVMETHOD(device_identify,	acpi_ec_identify),
23215e32d5dSMike Smith     DEVMETHOD(device_probe,	acpi_ec_probe),
23315e32d5dSMike Smith     DEVMETHOD(device_attach,	acpi_ec_attach),
23415e32d5dSMike Smith 
23515e32d5dSMike Smith     {0, 0}
23615e32d5dSMike Smith };
23715e32d5dSMike Smith 
23815e32d5dSMike Smith static driver_t acpi_ec_driver = {
23915e32d5dSMike Smith     "acpi_ec",
24015e32d5dSMike Smith     acpi_ec_methods,
24115e32d5dSMike Smith     sizeof(struct acpi_ec_softc),
24215e32d5dSMike Smith };
24315e32d5dSMike Smith 
24415e32d5dSMike Smith devclass_t acpi_ec_devclass;
24515e32d5dSMike Smith DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
24615e32d5dSMike Smith 
24715e32d5dSMike Smith /*
24815e32d5dSMike Smith  * Look for an ECDT table and if we find one, set up a default EC
24915e32d5dSMike Smith  * space handler to catch possible attempts to access EC space before
25015e32d5dSMike Smith  * we have a real driver instance in place.
25115e32d5dSMike Smith  * We're not really an identify routine, but because we get called
25215e32d5dSMike Smith  * before most other things, this works out OK.
25315e32d5dSMike Smith  */
25415e32d5dSMike Smith static void
25515e32d5dSMike Smith acpi_ec_identify(driver_t driver, device_t bus)
25615e32d5dSMike Smith {
2570ae55423SMike Smith     FUNCTION_TRACE(__FUNCTION__);
25815e32d5dSMike Smith 
25915e32d5dSMike Smith     /* XXX implement - need an ACPI 2.0 system to test this */
2600ae55423SMike Smith 
2610ae55423SMike Smith     return_VOID;
26215e32d5dSMike Smith }
26315e32d5dSMike Smith 
26415e32d5dSMike Smith /*
26515e32d5dSMike Smith  * We could setup resources in the probe routine in order to have them printed
26615e32d5dSMike Smith  * when the device is attached.
26715e32d5dSMike Smith  */
26815e32d5dSMike Smith static int
26915e32d5dSMike Smith acpi_ec_probe(device_t dev)
27015e32d5dSMike Smith {
2710ae55423SMike Smith 
27215e32d5dSMike Smith     if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
2730ae55423SMike Smith 	!acpi_disabled("ec") &&
27415e32d5dSMike Smith 	acpi_MatchHid(dev, "PNP0C09")) {
27515e32d5dSMike Smith 
27615e32d5dSMike Smith 	/*
27715e32d5dSMike Smith 	 * Set device description
27815e32d5dSMike Smith 	 */
27915e32d5dSMike Smith 	device_set_desc(dev, "embedded controller");
28015e32d5dSMike Smith 
28115e32d5dSMike Smith 	return(0);
28215e32d5dSMike Smith     }
28315e32d5dSMike Smith     return(ENXIO);
28415e32d5dSMike Smith }
28515e32d5dSMike Smith 
28615e32d5dSMike Smith static int
28715e32d5dSMike Smith acpi_ec_attach(device_t dev)
28815e32d5dSMike Smith {
28915e32d5dSMike Smith     struct acpi_ec_softc	*sc;
29015e32d5dSMike Smith     ACPI_BUFFER			*bufp;
29115e32d5dSMike Smith     UINT32			*param;
29215e32d5dSMike Smith     ACPI_STATUS			Status;
29315e32d5dSMike Smith     struct acpi_object_list	*args;
29415e32d5dSMike Smith 
2950ae55423SMike Smith     FUNCTION_TRACE(__FUNCTION__);
2960ae55423SMike Smith 
29715e32d5dSMike Smith     /*
29815e32d5dSMike Smith      * Fetch/initialise softc
29915e32d5dSMike Smith      */
30015e32d5dSMike Smith     sc = device_get_softc(dev);
301c07572e7STakanori Watanabe     bzero(sc, sizeof(*sc));
30215e32d5dSMike Smith     sc->ec_dev = dev;
30315e32d5dSMike Smith     sc->ec_handle = acpi_get_handle(dev);
30415e32d5dSMike Smith 
30515e32d5dSMike Smith     /*
30615e32d5dSMike Smith      * Evaluate resources
30715e32d5dSMike Smith      */
30815e32d5dSMike Smith     acpi_parse_resources(sc->ec_dev, sc->ec_handle, &acpi_res_parse_set);
30915e32d5dSMike Smith 
31015e32d5dSMike Smith     /*
31115e32d5dSMike Smith      * Attach bus resources
31215e32d5dSMike Smith      */
31315e32d5dSMike Smith     sc->ec_data_rid = 0;
31415e32d5dSMike Smith     if ((sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_data_rid,
31515e32d5dSMike Smith 					      0, ~0, 1, RF_ACTIVE)) == NULL) {
31615e32d5dSMike Smith 	device_printf(dev, "can't allocate data port\n");
3170ae55423SMike Smith 	return_VALUE(ENXIO);
31815e32d5dSMike Smith     }
31915e32d5dSMike Smith     sc->ec_data_tag = rman_get_bustag(sc->ec_data_res);
32015e32d5dSMike Smith     sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res);
32115e32d5dSMike Smith 
32215e32d5dSMike Smith     sc->ec_csr_rid = 1;
32315e32d5dSMike Smith     if ((sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_csr_rid,
32415e32d5dSMike Smith 					     0, ~0, 1, RF_ACTIVE)) == NULL) {
32515e32d5dSMike Smith 	device_printf(dev, "can't allocate command/status port\n");
3260ae55423SMike Smith 	return_VALUE(ENXIO);
32715e32d5dSMike Smith     }
32815e32d5dSMike Smith     sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res);
32915e32d5dSMike Smith     sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res);
33015e32d5dSMike Smith 
33115e32d5dSMike Smith     /*
33215e32d5dSMike Smith      * Create serialisation semaphore
33315e32d5dSMike Smith      */
33415e32d5dSMike Smith     if ((Status = AcpiOsCreateSemaphore(1, 1, &sc->ec_semaphore)) != AE_OK) {
33515e32d5dSMike Smith 	device_printf(dev, "can't create semaphore - %s\n", acpi_strerror(Status));
3360ae55423SMike Smith 	return_VALUE(ENXIO);
33715e32d5dSMike Smith     }
33815e32d5dSMike Smith 
33915e32d5dSMike Smith     /*
34015e32d5dSMike Smith      * Install GPE handler
34115e32d5dSMike Smith      *
34215e32d5dSMike Smith      * Evaluate the _GPE method to find the GPE bit used by the EC to signal
34315e32d5dSMike Smith      * status (SCI).
34415e32d5dSMike Smith      */
34515e32d5dSMike Smith     if ((bufp = acpi_AllocBuffer(16)) == NULL)
3460ae55423SMike Smith 	return_VALUE(ENOMEM);
34715e32d5dSMike Smith     if ((Status = AcpiEvaluateObject(sc->ec_handle, "_GPE", NULL, bufp)) != AE_OK) {
34815e32d5dSMike Smith 	device_printf(dev, "can't evaluate _GPE method - %s\n", acpi_strerror(Status));
3490ae55423SMike Smith 	return_VALUE(ENXIO);
35015e32d5dSMike Smith     }
35115e32d5dSMike Smith     param = (UINT32 *)bufp->Pointer;
35215e32d5dSMike Smith     if (param[0] != ACPI_TYPE_NUMBER) {
35315e32d5dSMike Smith 	device_printf(dev, "_GPE method returned bad result\n");
3540ae55423SMike Smith 	return_VALUE(ENXIO);
35515e32d5dSMike Smith     }
35615e32d5dSMike Smith     sc->ec_gpebit = param[1];
35715e32d5dSMike Smith     AcpiOsFree(bufp);
35815e32d5dSMike Smith 
35915e32d5dSMike Smith     /*
36015e32d5dSMike Smith      * Install a handler for this EC's GPE bit.  Note that EC SCIs are
36115e32d5dSMike Smith      * treated as both edge- and level-triggered interrupts; in other words
36215e32d5dSMike Smith      * we clear the status bit immediately after getting an EC-SCI, then
36315e32d5dSMike Smith      * again after we're done processing the event.  This guarantees that
36415e32d5dSMike Smith      * events we cause while performing a transaction (e.g. IBE/OBF) get
36515e32d5dSMike Smith      * cleared before re-enabling the GPE.
36615e32d5dSMike Smith      */
36715e32d5dSMike Smith     if ((Status = AcpiInstallGpeHandler(sc->ec_gpebit, ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED,
36815e32d5dSMike Smith 					EcGpeHandler, sc)) != AE_OK) {
36915e32d5dSMike Smith 	device_printf(dev, "can't install GPE handler - %s\n", acpi_strerror(Status));
3700ae55423SMike Smith 	return_VALUE(ENXIO);
37115e32d5dSMike Smith     }
37215e32d5dSMike Smith 
37315e32d5dSMike Smith     /*
37415e32d5dSMike Smith      * Install address space handler
37515e32d5dSMike Smith      */
37615e32d5dSMike Smith     if ((Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ADDRESS_SPACE_EC,
37715e32d5dSMike Smith 						 &EcSpaceHandler, &EcSpaceSetup, sc)) != AE_OK) {
37815e32d5dSMike Smith 	device_printf(dev, "can't install address space handler - %s\n", acpi_strerror(Status));
3790ae55423SMike Smith 	return_VALUE(ENXIO);
38015e32d5dSMike Smith     }
38115e32d5dSMike Smith 
38215e32d5dSMike Smith     /*
38315e32d5dSMike Smith      * Evaluate _REG to indicate that the region is now available.
38415e32d5dSMike Smith      */
38515e32d5dSMike Smith     if ((args = acpi_AllocObjectList(2)) == NULL)
3860ae55423SMike Smith 	return_VALUE(ENOMEM);
38715e32d5dSMike Smith     args->object[0].Type = ACPI_TYPE_NUMBER;
38815e32d5dSMike Smith     args->object[0].Number.Value = ADDRESS_SPACE_EC;
38915e32d5dSMike Smith     args->object[1].Type = ACPI_TYPE_NUMBER;
39015e32d5dSMike Smith     args->object[1].Number.Value = 1;
39115e32d5dSMike Smith     Status = AcpiEvaluateObject(sc->ec_handle, "_REG", (ACPI_OBJECT_LIST *)args, NULL);
39215e32d5dSMike Smith     AcpiOsFree(args);
39315e32d5dSMike Smith     /*
39415e32d5dSMike Smith      * If evaluation failed for some reason other than that the method didn't
39515e32d5dSMike Smith      * exist, that's bad and we should not attach.
39615e32d5dSMike Smith      */
39715e32d5dSMike Smith     if ((Status != AE_OK) && (Status != AE_NOT_FOUND)) {
39815e32d5dSMike Smith 	device_printf(dev, "can't evaluate _REG method - %s\n", acpi_strerror(Status));
3990ae55423SMike Smith 	return_VALUE(ENXIO);
40015e32d5dSMike Smith     }
40115e32d5dSMike Smith 
4020ae55423SMike Smith     return_VALUE(0);
40315e32d5dSMike Smith }
40415e32d5dSMike Smith 
40515e32d5dSMike Smith static void
406c07572e7STakanori Watanabe EcGpeQueryHandler(void *Context)
40715e32d5dSMike Smith {
40815e32d5dSMike Smith     struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
40915e32d5dSMike Smith     UINT8			Data;
41015e32d5dSMike Smith     ACPI_STATUS			Status;
41115e32d5dSMike Smith     char			qxx[5];
41215e32d5dSMike Smith 
4130ae55423SMike Smith     FUNCTION_TRACE(__FUNCTION__);
4140ae55423SMike Smith 
41515e32d5dSMike Smith     for (;;) {
41615e32d5dSMike Smith 
41715e32d5dSMike Smith 	/*
41815e32d5dSMike Smith 	 * Check EC_SCI.
41915e32d5dSMike Smith 	 *
42015e32d5dSMike Smith 	 * Bail out if the EC_SCI bit of the status register is not set.
42115e32d5dSMike Smith 	 * Note that this function should only be called when
42215e32d5dSMike Smith 	 * this bit is set (polling is used to detect IBE/OBF events).
42315e32d5dSMike Smith 	 *
42415e32d5dSMike Smith 	 * It is safe to do this without locking the controller, as it's
42515e32d5dSMike Smith 	 * OK to call EcQuery when there's no data ready; in the worst
42615e32d5dSMike Smith 	 * case we should just find nothing waiting for us and bail.
42715e32d5dSMike Smith 	 */
42815e32d5dSMike Smith 	if (!(EC_GET_CSR(sc) & EC_EVENT_SCI))
42915e32d5dSMike Smith 	    break;
43015e32d5dSMike Smith 
43115e32d5dSMike Smith 	/*
43215e32d5dSMike Smith 	 * Find out why the EC is signalling us
43315e32d5dSMike Smith 	 */
43415e32d5dSMike Smith 	Status = EcQuery(sc, &Data);
43515e32d5dSMike Smith 
43615e32d5dSMike Smith 	/*
43715e32d5dSMike Smith 	 * If we failed to get anything from the EC, give up
43815e32d5dSMike Smith 	 */
43915e32d5dSMike Smith 	if (Status != AE_OK) {
44015e32d5dSMike Smith 	    device_printf(sc->ec_dev, "GPE query failed - %s\n", acpi_strerror(Status));
44115e32d5dSMike Smith 	    break;
44215e32d5dSMike Smith 	}
44315e32d5dSMike Smith 
44415e32d5dSMike Smith 	/*
44515e32d5dSMike Smith 	 * Evaluate _Qxx to respond to the controller.
44615e32d5dSMike Smith 	 */
44715e32d5dSMike Smith 	sprintf(qxx, "_Q%02x", Data);
44815e32d5dSMike Smith 	strupr(qxx);
449c07572e7STakanori Watanabe 	if ((Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL)) != AE_OK) {
45015e32d5dSMike Smith 	    device_printf(sc->ec_dev, "evaluation of GPE query method %s failed - %s\n",
45115e32d5dSMike Smith 			  qxx, acpi_strerror(Status));
45215e32d5dSMike Smith 	}
45315e32d5dSMike Smith     }
454c07572e7STakanori Watanabe         /* I know I request Level trigger cleanup */
455c07572e7STakanori Watanabe     if(AcpiClearEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
456c07572e7STakanori Watanabe 	    printf("EcGpeQueryHandler:ClearEvent Failed\n");
457c07572e7STakanori Watanabe     if(AcpiEnableEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
458c07572e7STakanori Watanabe 	    printf("EcGpeQueryHandler:EnableEvent Failed\n");
459c07572e7STakanori Watanabe     return;
460c07572e7STakanori Watanabe }
461c07572e7STakanori Watanabe static void EcGpeHandler(void *Context)
462c07572e7STakanori Watanabe {
463c07572e7STakanori Watanabe 	struct acpi_ec_softc *sc = Context;
464c07572e7STakanori Watanabe 	int csrvalue;
465c07572e7STakanori Watanabe 	/*
466c07572e7STakanori Watanabe 	 * If EC is locked, the intr must process EcRead/Write wait only.
467c07572e7STakanori Watanabe 	 * Query request must be pending.
468c07572e7STakanori Watanabe 	 */
469c07572e7STakanori Watanabe 	if(EcIsLocked(sc)){
470c07572e7STakanori Watanabe 		csrvalue = EC_GET_CSR(sc);
471c07572e7STakanori Watanabe 		if(csrvalue & EC_EVENT_SCI)
472c07572e7STakanori Watanabe 			sc->ec_pendquery = 1;
473c07572e7STakanori Watanabe 		if((csrvalue & EC_FLAG_OUTPUT_BUFFER)
474c07572e7STakanori Watanabe 		   || !(csrvalue & EC_FLAG_INPUT_BUFFER)){
475c07572e7STakanori Watanabe 			sc->ec_csrvalue=csrvalue;
476c07572e7STakanori Watanabe 			wakeup((void *)&sc->ec_csrvalue);
477c07572e7STakanori Watanabe 		}
478c07572e7STakanori Watanabe 	}else{
479c07572e7STakanori Watanabe 		/*Queue GpeQuery Handler*/
480c07572e7STakanori Watanabe 		if(AcpiOsQueueForExecution(OSD_PRIORITY_GPE,
481c07572e7STakanori Watanabe 		    EcGpeQueryHandler,Context) != AE_OK){
482c07572e7STakanori Watanabe 			printf("QueryHandler Queuing Failed\n");
483c07572e7STakanori Watanabe 		}
484c07572e7STakanori Watanabe 	}
4850ae55423SMike Smith     return_VOID;
48615e32d5dSMike Smith }
48715e32d5dSMike Smith 
48815e32d5dSMike Smith static ACPI_STATUS
48915e32d5dSMike Smith EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, void **RegionContext)
49015e32d5dSMike Smith {
49115e32d5dSMike Smith     /*
49215e32d5dSMike Smith      * Just pass the context through, there's nothing to do here.
49315e32d5dSMike Smith      */
49415e32d5dSMike Smith     *RegionContext = Context;
49515e32d5dSMike Smith 
49615e32d5dSMike Smith     return(AE_OK);
49715e32d5dSMike Smith }
49815e32d5dSMike Smith 
49915e32d5dSMike Smith static ACPI_STATUS
500042283a6SMike Smith EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value,
501042283a6SMike Smith 	       void *Context, void *RegionContext)
50215e32d5dSMike Smith {
50315e32d5dSMike Smith     struct acpi_ec_softc	*sc = (struct acpi_ec_softc *)Context;
50415e32d5dSMike Smith     ACPI_STATUS			Status = AE_OK;
50515e32d5dSMike Smith     EC_REQUEST			EcRequest;
50615e32d5dSMike Smith 
5070ae55423SMike Smith     FUNCTION_TRACE_U32(__FUNCTION__, Address);
5080ae55423SMike Smith 
50915e32d5dSMike Smith     if ((Address > 0xFF) || (width != 8) || (Value == NULL) || (Context == NULL))
5100ae55423SMike Smith         return_ACPI_STATUS(AE_BAD_PARAMETER);
51115e32d5dSMike Smith 
51215e32d5dSMike Smith     switch (Function) {
51315e32d5dSMike Smith     case ADDRESS_SPACE_READ:
51415e32d5dSMike Smith         EcRequest.Command = EC_COMMAND_READ;
51515e32d5dSMike Smith         EcRequest.Address = Address;
51615e32d5dSMike Smith         EcRequest.Data = 0;
51715e32d5dSMike Smith         break;
51815e32d5dSMike Smith 
51915e32d5dSMike Smith     case ADDRESS_SPACE_WRITE:
52015e32d5dSMike Smith         EcRequest.Command = EC_COMMAND_WRITE;
52115e32d5dSMike Smith         EcRequest.Address = Address;
52215e32d5dSMike Smith         EcRequest.Data = (UINT8)(*Value);
52315e32d5dSMike Smith         break;
52415e32d5dSMike Smith 
52515e32d5dSMike Smith     default:
52615e32d5dSMike Smith 	device_printf(sc->ec_dev, "invalid Address Space function %d\n", Function);
5270ae55423SMike Smith         return_ACPI_STATUS(AE_BAD_PARAMETER);
52815e32d5dSMike Smith     }
52915e32d5dSMike Smith 
53015e32d5dSMike Smith     /*
53115e32d5dSMike Smith      * Perform the transaction.
53215e32d5dSMike Smith      */
53315e32d5dSMike Smith     if ((Status = EcTransaction(sc, &EcRequest)) == AE_OK)
53415e32d5dSMike Smith         (*Value) = (UINT32)EcRequest.Data;
53515e32d5dSMike Smith 
5360ae55423SMike Smith     return_ACPI_STATUS(Status);
53715e32d5dSMike Smith }
538c07572e7STakanori Watanabe static ACPI_STATUS
539c07572e7STakanori Watanabe EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event)
540c07572e7STakanori Watanabe {
541c07572e7STakanori Watanabe     EC_STATUS	EcStatus;
542c07572e7STakanori Watanabe     int i;
543c07572e7STakanori Watanabe     if(cold)
544c07572e7STakanori Watanabe 	    return EcWaitEvent(sc, Event);
545c07572e7STakanori Watanabe     if (!EcIsLocked(sc))
546c07572e7STakanori Watanabe 	    device_printf(sc->ec_dev, "EcWaitEventIntr called without EC lock!\n");
547c07572e7STakanori Watanabe     EcStatus = EC_GET_CSR(sc);
548c07572e7STakanori Watanabe     /*Too long?*/
549c07572e7STakanori Watanabe     for(i=0;i<10;i++){
550c07572e7STakanori Watanabe     	if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
551c07572e7STakanori Watanabe 		(EcStatus & EC_FLAG_OUTPUT_BUFFER))
552c07572e7STakanori Watanabe 		return(AE_OK);
553c07572e7STakanori Watanabe 
554c07572e7STakanori Watanabe 	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
555c07572e7STakanori Watanabe 		!(EcStatus & EC_FLAG_INPUT_BUFFER))
556c07572e7STakanori Watanabe 		return(AE_OK);
557c07572e7STakanori Watanabe 	sc->ec_csrvalue = 0;
558c07572e7STakanori Watanabe 	if(tsleep(&sc->ec_csrvalue, 0,"ECTRANS",1) != EWOULDBLOCK){
559c07572e7STakanori Watanabe 		EcStatus = sc->ec_csrvalue;
560c07572e7STakanori Watanabe 	}else{
561c07572e7STakanori Watanabe 		EcStatus=EC_GET_CSR(sc);
562c07572e7STakanori Watanabe 	}
563c07572e7STakanori Watanabe     }
564c07572e7STakanori Watanabe     return AE_ERROR;
565c07572e7STakanori Watanabe }
56615e32d5dSMike Smith 
56715e32d5dSMike Smith static ACPI_STATUS
56815e32d5dSMike Smith EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
56915e32d5dSMike Smith {
57015e32d5dSMike Smith     EC_STATUS	EcStatus;
57115e32d5dSMike Smith     UINT32	i = 0;
57215e32d5dSMike Smith 
57315e32d5dSMike Smith     if (!EcIsLocked(sc))
57415e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWaitEvent called without EC lock!\n");
57515e32d5dSMike Smith 
57615e32d5dSMike Smith     /*
57715e32d5dSMike Smith      * Stall 1us:
57815e32d5dSMike Smith      * ----------
57915e32d5dSMike Smith      * Stall for 1 microsecond before reading the status register
58015e32d5dSMike Smith      * for the first time.  This allows the EC to set the IBF/OBF
58115e32d5dSMike Smith      * bit to its proper state.
58215e32d5dSMike Smith      *
58315e32d5dSMike Smith      * XXX it is not clear why we read the CSR twice.
58415e32d5dSMike Smith      */
58515e32d5dSMike Smith     AcpiOsSleepUsec(1);
58615e32d5dSMike Smith     EcStatus = EC_GET_CSR(sc);
58715e32d5dSMike Smith 
58815e32d5dSMike Smith     /*
58915e32d5dSMike Smith      * Wait For Event:
59015e32d5dSMike Smith      * ---------------
59115e32d5dSMike Smith      * Poll the EC status register to detect completion of the last
59215e32d5dSMike Smith      * command.  Wait up to 10ms (in 100us chunks) for this to occur.
59315e32d5dSMike Smith      */
59415e32d5dSMike Smith     for (i = 0; i < 100; i++) {
59515e32d5dSMike Smith 	EcStatus = EC_GET_CSR(sc);
59615e32d5dSMike Smith 
59715e32d5dSMike Smith         if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
59815e32d5dSMike Smith             (EcStatus & EC_FLAG_OUTPUT_BUFFER))
59915e32d5dSMike Smith 	    return(AE_OK);
60015e32d5dSMike Smith 
60115e32d5dSMike Smith 	if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
60215e32d5dSMike Smith             !(EcStatus & EC_FLAG_INPUT_BUFFER))
60315e32d5dSMike Smith 	    return(AE_OK);
60415e32d5dSMike Smith 
60515e32d5dSMike Smith 	AcpiOsSleepUsec(100);
60615e32d5dSMike Smith     }
60715e32d5dSMike Smith 
60815e32d5dSMike Smith     return(AE_ERROR);
60915e32d5dSMike Smith }
61015e32d5dSMike Smith 
61115e32d5dSMike Smith static ACPI_STATUS
61215e32d5dSMike Smith EcQuery(struct acpi_ec_softc *sc, UINT8 *Data)
61315e32d5dSMike Smith {
61415e32d5dSMike Smith     ACPI_STATUS	Status;
61515e32d5dSMike Smith 
61615e32d5dSMike Smith     if ((Status = EcLock(sc)) != AE_OK)
61715e32d5dSMike Smith 	return(Status);
61815e32d5dSMike Smith 
61915e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_QUERY);
62015e32d5dSMike Smith     Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL);
62115e32d5dSMike Smith     if (Status == AE_OK)
62215e32d5dSMike Smith 	*Data = EC_GET_DATA(sc);
62315e32d5dSMike Smith 
62415e32d5dSMike Smith     EcUnlock(sc);
62515e32d5dSMike Smith 
62615e32d5dSMike Smith     if (Status != AE_OK)
62715e32d5dSMike Smith 	device_printf(sc->ec_dev, "timeout waiting for EC to respond to EC_COMMAND_QUERY\n");
62815e32d5dSMike Smith     return(Status);
62915e32d5dSMike Smith }
63015e32d5dSMike Smith 
63115e32d5dSMike Smith 
63215e32d5dSMike Smith static ACPI_STATUS
63315e32d5dSMike Smith EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
63415e32d5dSMike Smith {
63515e32d5dSMike Smith     ACPI_STATUS	Status;
63615e32d5dSMike Smith 
63715e32d5dSMike Smith     /*
63815e32d5dSMike Smith      * Lock the EC
63915e32d5dSMike Smith      */
64015e32d5dSMike Smith     if ((Status = EcLock(sc)) != AE_OK)
64115e32d5dSMike Smith 	return(Status);
64215e32d5dSMike Smith 
64315e32d5dSMike Smith     /*
64415e32d5dSMike Smith      * Perform the transaction.
64515e32d5dSMike Smith      */
64615e32d5dSMike Smith     switch (EcRequest->Command) {
64715e32d5dSMike Smith     case EC_COMMAND_READ:
64815e32d5dSMike Smith 	Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data));
64915e32d5dSMike Smith 	break;
65015e32d5dSMike Smith 
65115e32d5dSMike Smith     case EC_COMMAND_WRITE:
65215e32d5dSMike Smith 	Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data));
65315e32d5dSMike Smith 	break;
65415e32d5dSMike Smith 
65515e32d5dSMike Smith     default:
65615e32d5dSMike Smith 	Status = AE_SUPPORT;
65715e32d5dSMike Smith 	break;
65815e32d5dSMike Smith     }
65915e32d5dSMike Smith 
66015e32d5dSMike Smith     /*
66115e32d5dSMike Smith      * Clear & Re-Enable the EC GPE:
66215e32d5dSMike Smith      * -----------------------------
66315e32d5dSMike Smith      * 'Consume' any EC GPE events that we generated while performing
66415e32d5dSMike Smith      * the transaction (e.g. IBF/OBF).	Clearing the GPE here shouldn't
66515e32d5dSMike Smith      * have an adverse affect on outstanding EC-SCI's, as the source
66615e32d5dSMike Smith      * (EC-SCI) will still be high and thus should trigger the GPE
66715e32d5dSMike Smith      * immediately after we re-enabling it.
66815e32d5dSMike Smith      */
669c07572e7STakanori Watanabe     if (sc->ec_pendquery){
670c07572e7STakanori Watanabe 	    if(AcpiOsQueueForExecution(OSD_PRIORITY_GPE,
671c07572e7STakanori Watanabe 		EcGpeQueryHandler, sc) != AE_OK)
672c07572e7STakanori Watanabe 		    printf("Pend Query Queuing Failed\n");
673c07572e7STakanori Watanabe 	    sc->ec_pendquery = 0;
674c07572e7STakanori Watanabe     }
675c07572e7STakanori Watanabe 
67615e32d5dSMike Smith     if (AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
67715e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRequest: Unable to clear the EC GPE.\n");
67815e32d5dSMike Smith     if (AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
67915e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRequest: Unable to re-enable the EC GPE.\n");
68015e32d5dSMike Smith 
68115e32d5dSMike Smith     /*
68215e32d5dSMike Smith      * Unlock the EC
68315e32d5dSMike Smith      */
68415e32d5dSMike Smith     EcUnlock(sc);
68515e32d5dSMike Smith 
68615e32d5dSMike Smith     return(Status);
68715e32d5dSMike Smith }
68815e32d5dSMike Smith 
68915e32d5dSMike Smith 
69015e32d5dSMike Smith static ACPI_STATUS
69115e32d5dSMike Smith EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
69215e32d5dSMike Smith {
69315e32d5dSMike Smith     ACPI_STATUS	Status;
69415e32d5dSMike Smith 
69515e32d5dSMike Smith     if (!EcIsLocked(sc))
69615e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead called without EC lock!\n");
69715e32d5dSMike Smith 
69815e32d5dSMike Smith     /*EcBurstEnable(EmbeddedController);*/
69915e32d5dSMike Smith 
70015e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_READ);
701c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
70215e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process read command.\n");
70315e32d5dSMike Smith 	return(Status);
70415e32d5dSMike Smith     }
70515e32d5dSMike Smith 
70615e32d5dSMike Smith     EC_SET_DATA(sc, Address);
707c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_OUTPUT_BUFFER_FULL)) != AE_OK) {
70815e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to send data.\n");
70915e32d5dSMike Smith 	return(Status);
71015e32d5dSMike Smith     }
71115e32d5dSMike Smith 
71215e32d5dSMike Smith     (*Data) = EC_GET_DATA(sc);
71315e32d5dSMike Smith 
71415e32d5dSMike Smith     /*EcBurstDisable(EmbeddedController);*/
71515e32d5dSMike Smith 
71615e32d5dSMike Smith     return(AE_OK);
71715e32d5dSMike Smith }
71815e32d5dSMike Smith 
71915e32d5dSMike Smith static ACPI_STATUS
72015e32d5dSMike Smith EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
72115e32d5dSMike Smith {
72215e32d5dSMike Smith     ACPI_STATUS	Status;
72315e32d5dSMike Smith 
72415e32d5dSMike Smith     if (!EcIsLocked(sc))
72515e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWrite called without EC lock!\n");
72615e32d5dSMike Smith 
72715e32d5dSMike Smith     /*EcBurstEnable(EmbeddedController);*/
72815e32d5dSMike Smith 
72915e32d5dSMike Smith     EC_SET_CSR(sc, EC_COMMAND_WRITE);
730c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
73115e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process write command.\n");
73215e32d5dSMike Smith 	return(Status);
73315e32d5dSMike Smith     }
73415e32d5dSMike Smith 
73515e32d5dSMike Smith     EC_SET_DATA(sc, Address);
736c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
73715e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process address.\n");
73815e32d5dSMike Smith 	return(Status);
73915e32d5dSMike Smith     }
74015e32d5dSMike Smith 
74115e32d5dSMike Smith     EC_SET_DATA(sc, *Data);
742c07572e7STakanori Watanabe     if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
74315e32d5dSMike Smith 	device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process data.\n");
74415e32d5dSMike Smith 	return(Status);
74515e32d5dSMike Smith     }
74615e32d5dSMike Smith 
74715e32d5dSMike Smith     /*EcBurstDisable(EmbeddedController);*/
74815e32d5dSMike Smith 
74915e32d5dSMike Smith     return(AE_OK);
75015e32d5dSMike Smith }
751