* Add this nice filesystem testing tool that I've recently
[dragonfly.git] / sys / dev / acpica / acpi_ec.c
1 /*-
2  * Copyright (c) 2000 Michael Smith
3  * Copyright (c) 2000 BSDi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *      $FreeBSD: src/sys/dev/acpica/acpi_ec.c,v 1.38.2.1 2003/08/22 20:49:20 jhb Exp $
28  *      $DragonFly: src/sys/dev/acpica/Attic/acpi_ec.c,v 1.1 2003/09/24 03:32:16 drhodus Exp $ 
29  */
30 /******************************************************************************
31  *
32  * 1. Copyright Notice
33  *
34  * Some or all of this work - Copyright (c) 1999, Intel Corp.  All rights
35  * reserved.
36  *
37  * 2. License
38  *
39  * 2.1. This is your license from Intel Corp. under its intellectual property
40  * rights.  You may have additional license terms from the party that provided
41  * you this software, covering your right to use that party's intellectual
42  * property rights.
43  *
44  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
45  * copy of the source code appearing in this file ("Covered Code") an
46  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
47  * base code distributed originally by Intel ("Original Intel Code") to copy,
48  * make derivatives, distribute, use and display any portion of the Covered
49  * Code in any form, with the right to sublicense such rights; and
50  *
51  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
52  * license (with the right to sublicense), under only those claims of Intel
53  * patents that are infringed by the Original Intel Code, to make, use, sell,
54  * offer to sell, and import the Covered Code and derivative works thereof
55  * solely to the minimum extent necessary to exercise the above copyright
56  * license, and in no event shall the patent license extend to any additions
57  * to or modifications of the Original Intel Code.  No other license or right
58  * is granted directly or by implication, estoppel or otherwise;
59  *
60  * The above copyright and patent license is granted only if the following
61  * conditions are met:
62  *
63  * 3. Conditions 
64  *
65  * 3.1. Redistribution of Source with Rights to Further Distribute Source.  
66  * Redistribution of source code of any substantial portion of the Covered
67  * Code or modification with rights to further distribute source must include
68  * the above Copyright Notice, the above License, this list of Conditions,
69  * and the following Disclaimer and Export Compliance provision.  In addition,
70  * Licensee must cause all Covered Code to which Licensee contributes to
71  * contain a file documenting the changes Licensee made to create that Covered
72  * Code and the date of any change.  Licensee must include in that file the
73  * documentation of any changes made by any predecessor Licensee.  Licensee 
74  * must include a prominent statement that the modification is derived,
75  * directly or indirectly, from Original Intel Code.
76  *
77  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.  
78  * Redistribution of source code of any substantial portion of the Covered
79  * Code or modification without rights to further distribute source must
80  * include the following Disclaimer and Export Compliance provision in the
81  * documentation and/or other materials provided with distribution.  In
82  * addition, Licensee may not authorize further sublicense of source of any
83  * portion of the Covered Code, and must include terms to the effect that the
84  * license from Licensee to its licensee is limited to the intellectual
85  * property embodied in the software Licensee provides to its licensee, and
86  * not to intellectual property embodied in modifications its licensee may
87  * make.
88  *
89  * 3.3. Redistribution of Executable. Redistribution in executable form of any
90  * substantial portion of the Covered Code or modification must reproduce the
91  * above Copyright Notice, and the following Disclaimer and Export Compliance
92  * provision in the documentation and/or other materials provided with the
93  * distribution.
94  *
95  * 3.4. Intel retains all right, title, and interest in and to the Original
96  * Intel Code.
97  *
98  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
99  * Intel shall be used in advertising or otherwise to promote the sale, use or
100  * other dealings in products derived from or relating to the Covered Code
101  * without prior written authorization from Intel.
102  *
103  * 4. Disclaimer and Export Compliance
104  *
105  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
106  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
107  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
108  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
109  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
110  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
111  * PARTICULAR PURPOSE. 
112  *
113  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
114  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
115  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
116  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
117  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
118  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
119  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
120  * LIMITED REMEDY.
121  *
122  * 4.3. Licensee shall not export, either directly or indirectly, any of this
123  * software or system incorporating such software without first obtaining any
124  * required license or other approval from the U. S. Department of Commerce or
125  * any other agency or department of the United States Government.  In the
126  * event Licensee exports any such software from the United States or
127  * re-exports any such software from a foreign destination, Licensee shall
128  * ensure that the distribution and export/re-export of the software is in
129  * compliance with all laws, regulations, orders, or other restrictions of the
130  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
131  * any of its subsidiaries will export/re-export any technical data, process,
132  * software, or service, directly or indirectly, to any country for which the
133  * United States government or any agency thereof requires an export license,
134  * other governmental approval, or letter of assurance, without first obtaining
135  * such license, approval or letter.
136  *
137  *****************************************************************************/
138
139 #include "opt_acpi.h"
140 #include <sys/param.h>
141 #include <sys/kernel.h>
142 #include <sys/bus.h>
143
144 #include <machine/bus.h>
145 #include <machine/resource.h>
146 #include <sys/rman.h>
147
148 #include "acpi.h"
149
150 #include <dev/acpica/acpivar.h>
151
152 /*
153  * Hooks for the ACPI CA debugging infrastructure
154  */
155 #define _COMPONENT      ACPI_EC
156 ACPI_MODULE_NAME("EC")
157
158 /*
159  * EC_COMMAND:
160  * -----------
161  */
162 typedef UINT8                           EC_COMMAND;
163
164 #define EC_COMMAND_UNKNOWN              ((EC_COMMAND) 0x00)
165 #define EC_COMMAND_READ                 ((EC_COMMAND) 0x80)
166 #define EC_COMMAND_WRITE                ((EC_COMMAND) 0x81)
167 #define EC_COMMAND_BURST_ENABLE         ((EC_COMMAND) 0x82)
168 #define EC_COMMAND_BURST_DISABLE        ((EC_COMMAND) 0x83)
169 #define EC_COMMAND_QUERY                ((EC_COMMAND) 0x84)
170
171 /* 
172  * EC_STATUS:
173  * ----------
174  * The encoding of the EC status register is illustrated below.
175  * Note that a set bit (1) indicates the property is TRUE
176  * (e.g. if bit 0 is set then the output buffer is full).
177  * +-+-+-+-+-+-+-+-+
178  * |7|6|5|4|3|2|1|0|    
179  * +-+-+-+-+-+-+-+-+
180  *  | | | | | | | |
181  *  | | | | | | | +- Output Buffer Full?
182  *  | | | | | | +--- Input Buffer Full?
183  *  | | | | | +----- <reserved>
184  *  | | | | +------- Data Register is Command Byte?
185  *  | | | +--------- Burst Mode Enabled?
186  *  | | +----------- SCI Event?
187  *  | +------------- SMI Event?
188  *  +--------------- <Reserved>
189  *
190  */
191 typedef UINT8                           EC_STATUS;
192
193 #define EC_FLAG_OUTPUT_BUFFER           ((EC_STATUS) 0x01)
194 #define EC_FLAG_INPUT_BUFFER            ((EC_STATUS) 0x02)
195 #define EC_FLAG_BURST_MODE              ((EC_STATUS) 0x10)
196 #define EC_FLAG_SCI                     ((EC_STATUS) 0x20)
197
198 /*
199  * EC_EVENT:
200  * ---------
201  */
202 typedef UINT8                           EC_EVENT;
203
204 #define EC_EVENT_UNKNOWN                ((EC_EVENT) 0x00)
205 #define EC_EVENT_OUTPUT_BUFFER_FULL     ((EC_EVENT) 0x01)
206 #define EC_EVENT_INPUT_BUFFER_EMPTY     ((EC_EVENT) 0x02)
207 #define EC_EVENT_SCI                    ((EC_EVENT) 0x20)
208
209 /*
210  * Register access primitives
211  */
212 #define EC_GET_DATA(sc)                                                 \
213         bus_space_read_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0)
214
215 #define EC_SET_DATA(sc, v)                                              \
216         bus_space_write_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0, (v))
217
218 #define EC_GET_CSR(sc)                                                  \
219         bus_space_read_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0)
220
221 #define EC_SET_CSR(sc, v)                                               \
222         bus_space_write_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0, (v))
223
224 /*
225  * Driver softc.
226  */
227 struct acpi_ec_softc {
228     device_t            ec_dev;
229     ACPI_HANDLE         ec_handle;
230     UINT32              ec_gpebit;
231     
232     int                 ec_data_rid;
233     struct resource     *ec_data_res;
234     bus_space_tag_t     ec_data_tag;
235     bus_space_handle_t  ec_data_handle;
236
237     int                 ec_csr_rid;
238     struct resource     *ec_csr_res;
239     bus_space_tag_t     ec_csr_tag;
240     bus_space_handle_t  ec_csr_handle;
241
242     int                 ec_locked;
243     int                 ec_lockhandle;
244     int                 ec_pendquery;
245     int                 ec_csrvalue;
246 };
247
248 static int              acpi_ec_event_driven = 0;
249 TUNABLE_INT("hw.acpi.ec.event_driven", &acpi_ec_event_driven);
250
251 #define EC_LOCK_TIMEOUT 1000    /* 1ms */
252
253 static __inline ACPI_STATUS
254 EcLock(struct acpi_ec_softc *sc)
255 {
256     ACPI_STATUS status;
257
258     /* XXX ACPI_WAIT_FOREVER is probably a bad idea, what is a better time? */
259     status = AcpiAcquireGlobalLock(ACPI_WAIT_FOREVER, &sc->ec_lockhandle);
260     if (ACPI_SUCCESS(status))
261         sc->ec_locked = 1;
262
263     return (status);
264 }
265
266 static __inline void
267 EcUnlock(struct acpi_ec_softc *sc)
268 {
269     sc->ec_locked = 0; 
270     AcpiReleaseGlobalLock(sc->ec_lockhandle);
271 }
272
273 static __inline int
274 EcIsLocked(struct acpi_ec_softc *sc)
275 {
276     return (sc->ec_locked != 0);
277 }
278
279 typedef struct
280 {
281     EC_COMMAND          Command;
282     UINT8               Address;
283     UINT8               Data;
284 } EC_REQUEST;
285
286 static void             EcGpeHandler(void *Context);
287 static ACPI_STATUS      EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, 
288                                 void *Context, void **return_Context);
289 static ACPI_STATUS      EcSpaceHandler(UINT32 Function,
290                                 ACPI_PHYSICAL_ADDRESS Address,
291                                 UINT32 width, ACPI_INTEGER *Value,
292                                 void *Context, void *RegionContext);
293 static ACPI_STATUS      EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event);
294 static ACPI_STATUS      EcQuery(struct acpi_ec_softc *sc, UINT8 *Data);
295 static ACPI_STATUS      EcTransaction(struct acpi_ec_softc *sc,
296                                 EC_REQUEST *EcRequest);
297 static ACPI_STATUS      EcRead(struct acpi_ec_softc *sc, UINT8 Address,
298                                 UINT8 *Data);
299 static ACPI_STATUS      EcWrite(struct acpi_ec_softc *sc, UINT8 Address,
300                                 UINT8 *Data);
301 static void             acpi_ec_identify(driver_t driver, device_t bus);
302 static int              acpi_ec_probe(device_t dev);
303 static int              acpi_ec_attach(device_t dev);
304
305 static device_method_t acpi_ec_methods[] = {
306     /* Device interface */
307     DEVMETHOD(device_identify,  acpi_ec_identify),
308     DEVMETHOD(device_probe,     acpi_ec_probe),
309     DEVMETHOD(device_attach,    acpi_ec_attach),
310
311     {0, 0}
312 };
313
314 static driver_t acpi_ec_driver = {
315     "acpi_ec",
316     acpi_ec_methods,
317     sizeof(struct acpi_ec_softc),
318 };
319
320 static devclass_t acpi_ec_devclass;
321 DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0);
322
323 /*
324  * Look for an ECDT table and if we find one, set up a default EC 
325  * space handler to catch possible attempts to access EC space before
326  * we have a real driver instance in place.
327  * We're not really an identify routine, but because we get called 
328  * before most other things, this works out OK.
329  */
330 static void
331 acpi_ec_identify(driver_t driver, device_t bus)
332 {
333     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
334
335     /* XXX implement - need an ACPI 2.0 system to test this */
336 }
337
338 /*
339  * We could setup resources in the probe routine in order to have them printed 
340  * when the device is attached.
341  */
342 static int
343 acpi_ec_probe(device_t dev)
344 {
345
346     if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("ec") &&
347         acpi_MatchHid(dev, "PNP0C09")) {
348
349         /*
350          * Set device description 
351          */
352         device_set_desc(dev, "embedded controller");
353         return (0);
354     }
355     return (ENXIO);
356 }
357
358 static int
359 acpi_ec_attach(device_t dev)
360 {
361     struct acpi_ec_softc        *sc;
362     ACPI_STATUS                 Status;
363     int                         errval = 0;
364
365     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
366
367     /*
368      * Fetch/initialise softc
369      */
370     sc = device_get_softc(dev);
371     bzero(sc, sizeof(*sc));
372     sc->ec_dev = dev;
373     sc->ec_handle = acpi_get_handle(dev);
374
375     /* 
376      * Attach bus resources
377      */
378     sc->ec_data_rid = 0;
379     sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT,
380                         &sc->ec_data_rid, 0, ~0, 1, RF_ACTIVE);
381     if (sc->ec_data_res == NULL) {
382         device_printf(dev, "can't allocate data port\n");
383         errval = ENXIO;
384         goto out;
385     }
386     sc->ec_data_tag = rman_get_bustag(sc->ec_data_res);
387     sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res);
388
389     sc->ec_csr_rid = 1;
390     sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT,
391                         &sc->ec_csr_rid, 0, ~0, 1, RF_ACTIVE);
392     if (sc->ec_csr_res == NULL) {
393         device_printf(dev, "can't allocate command/status port\n");
394         errval = ENXIO;
395         goto out;
396     }
397     sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res);
398     sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res);
399
400     /*
401      * Install GPE handler
402      *
403      * Evaluate the _GPE method to find the GPE bit used by the EC to signal
404      * status (SCI).
405      */
406     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attaching GPE\n"));
407     Status = acpi_EvaluateInteger(sc->ec_handle, "_GPE", &sc->ec_gpebit);
408     if (ACPI_FAILURE(Status)) {
409         device_printf(dev, "can't evaluate _GPE - %s\n",
410                       AcpiFormatException(Status));
411         errval = ENXIO;
412         goto out;
413     }
414
415     /*
416      * Install a handler for this EC's GPE bit.  Note that EC SCIs are 
417      * treated as both edge- and level-triggered interrupts; in other words
418      * we clear the status bit immediately after getting an EC-SCI, then
419      * again after we're done processing the event.  This guarantees that
420      * events we cause while performing a transaction (e.g. IBE/OBF) get 
421      * cleared before re-enabling the GPE.
422      */
423     Status = AcpiInstallGpeHandler(sc->ec_gpebit,
424                 ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED, 
425                 EcGpeHandler, sc);
426     if (ACPI_FAILURE(Status)) {
427         device_printf(dev, "can't install GPE handler for %s - %s\n",
428                       acpi_name(sc->ec_handle), AcpiFormatException(Status));
429         errval = ENXIO;
430         goto out;
431     }
432
433     /* 
434      * Install address space handler
435      */
436     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attaching address space handler\n"));
437     Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ACPI_ADR_SPACE_EC,
438                 EcSpaceHandler, EcSpaceSetup, sc);
439     if (ACPI_FAILURE(Status)) {
440         device_printf(dev, "can't install address space handler for %s - %s\n",
441                       acpi_name(sc->ec_handle), AcpiFormatException(Status));
442         panic("very suck");
443         errval = ENXIO;
444         goto out;
445     }
446     ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attach complete\n"));
447     return_VALUE (0);
448
449  out:
450     if (sc->ec_csr_res)
451         bus_release_resource(sc->ec_dev, SYS_RES_IOPORT, sc->ec_csr_rid, 
452                              sc->ec_csr_res);
453     if (sc->ec_data_res)
454         bus_release_resource(sc->ec_dev, SYS_RES_IOPORT, sc->ec_data_rid,
455                              sc->ec_data_res);
456     return_VALUE (errval);
457 }
458
459 static void
460 EcGpeQueryHandler(void *Context)
461 {
462     struct acpi_ec_softc        *sc = (struct acpi_ec_softc *)Context;
463     UINT8                       Data;
464     ACPI_STATUS                 Status;
465     char                        qxx[5];
466
467     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
468
469     for (;;) {
470
471         /*
472          * Check EC_SCI.
473          * 
474          * Bail out if the EC_SCI bit of the status register is not set.
475          * Note that this function should only be called when
476          * this bit is set (polling is used to detect IBE/OBF events).
477          *
478          * It is safe to do this without locking the controller, as it's
479          * OK to call EcQuery when there's no data ready; in the worst
480          * case we should just find nothing waiting for us and bail.
481          */
482         if ((EC_GET_CSR(sc) & EC_EVENT_SCI) == 0)
483             break;
484
485         /*
486          * Find out why the EC is signalling us
487          */
488         Status = EcQuery(sc, &Data);
489             
490         /*
491          * If we failed to get anything from the EC, give up
492          */
493         if (ACPI_FAILURE(Status)) {
494             ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
495                 "GPE query failed - %s\n", AcpiFormatException(Status));
496             break;
497         }
498
499         /*
500          * Evaluate _Qxx to respond to the controller.
501          */
502         sprintf(qxx, "_Q%02x", Data);
503         strupr(qxx);
504         Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL);
505         /*
506          * Ignore spurious query requests.
507          */
508         if (ACPI_FAILURE(Status) && (Data != 0 || Status != AE_NOT_FOUND)) {
509             ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
510                 "evaluation of GPE query method %s failed - %s\n", 
511                 qxx, AcpiFormatException(Status));
512         }
513     }
514         /* I know I request Level trigger cleanup */
515     if (ACPI_FAILURE(AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE)))
516         printf("EcGpeQueryHandler:ClearEvent Failed\n");
517     if (ACPI_FAILURE(AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE, 0)))
518         printf("EcGpeQueryHandler:EnableEvent Failed\n");
519 }
520
521 /*
522  * Handle a GPE sent to us.
523  */
524 static void
525 EcGpeHandler(void *Context)
526 {
527     struct acpi_ec_softc *sc = Context;
528     int csrvalue;
529
530     /* 
531      * If EC is locked, the intr must process EcRead/Write wait only.
532      * Query request must be pending.
533      */
534     if (EcIsLocked(sc)) {
535         csrvalue = EC_GET_CSR(sc);
536         if (csrvalue & EC_EVENT_SCI)
537             sc->ec_pendquery = 1;
538         if ((csrvalue & EC_FLAG_OUTPUT_BUFFER) != 0 ||
539             (csrvalue & EC_FLAG_INPUT_BUFFER) == 0) {
540             sc->ec_csrvalue = csrvalue;
541             wakeup(&sc->ec_csrvalue);
542         }
543     } else {
544         /* Queue GpeQuery Handler */
545         if (ACPI_FAILURE(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
546                                     EcGpeQueryHandler,Context))) {
547             printf("QueryHandler Queuing Failed\n");
548         }
549     }
550 }
551
552 static ACPI_STATUS
553 EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context,
554              void **RegionContext)
555 {
556
557     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
558
559     /*
560      * Just pass the context through, there's nothing to do here.
561      */
562     *RegionContext = Context;
563
564     return_ACPI_STATUS (AE_OK);
565 }
566
567 static ACPI_STATUS
568 EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width,
569                ACPI_INTEGER *Value, void *Context, void *RegionContext)
570 {
571     struct acpi_ec_softc        *sc = (struct acpi_ec_softc *)Context;
572     ACPI_STATUS                 Status = AE_OK;
573     EC_REQUEST                  EcRequest;
574     int                         i;
575
576     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, (UINT32)Address);
577
578     if (Address > 0xFF || width % 8 != 0 || Value == NULL || Context == NULL)
579         return_ACPI_STATUS (AE_BAD_PARAMETER);
580
581     switch (Function) {
582     case ACPI_READ:
583         EcRequest.Command = EC_COMMAND_READ;
584         EcRequest.Address = Address;
585         (*Value) = 0;
586         break;
587     case ACPI_WRITE:
588         EcRequest.Command = EC_COMMAND_WRITE;
589         EcRequest.Address = Address;
590         break;
591     default:
592         device_printf(sc->ec_dev, "invalid Address Space function %d\n",
593                       Function);
594         return_ACPI_STATUS (AE_BAD_PARAMETER);
595     }
596
597     /*
598      * Perform the transaction.
599      */
600     for (i = 0; i < width; i += 8) {
601         if (Function == ACPI_READ)
602             EcRequest.Data = 0;
603         else
604             EcRequest.Data = (UINT8)((*Value) >> i);
605         Status = EcTransaction(sc, &EcRequest);
606         if (ACPI_FAILURE(Status))
607             break;
608         *Value |= (ACPI_INTEGER)EcRequest.Data << i;
609         if (++EcRequest.Address == 0)
610             return_ACPI_STATUS (AE_BAD_PARAMETER);
611     }
612     return_ACPI_STATUS (Status);
613 }
614
615 /*
616  * Wait for an event interrupt for a specific condition.
617  */
618 static ACPI_STATUS
619 EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event)
620 {
621     EC_STATUS   EcStatus;
622     int         i;
623
624     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, (UINT32)Event);
625
626     /* XXX this should test whether interrupts are available some other way */
627     if (cold || acpi_ec_event_driven)
628         return_ACPI_STATUS (EcWaitEvent(sc, Event));
629
630     if (!EcIsLocked(sc)) {
631         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
632             "EcWaitEventIntr called without EC lock!\n");
633     }
634
635     EcStatus = EC_GET_CSR(sc);
636
637     /* XXX waiting too long? */
638     for (i = 0; i < 10; i++) {
639         /*
640          * Check EC status against the desired event.
641          */
642         if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
643             (EcStatus & EC_FLAG_OUTPUT_BUFFER) != 0)
644             return_ACPI_STATUS (AE_OK);
645       
646         if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) && 
647             (EcStatus & EC_FLAG_INPUT_BUFFER) == 0)
648             return_ACPI_STATUS (AE_OK);
649         
650         sc->ec_csrvalue = 0;
651         /* XXX sleeping with Acpi Global Lock held */
652         if (tsleep(&sc->ec_csrvalue, 0, "EcWait", 1) != EWOULDBLOCK) {
653             EcStatus = sc->ec_csrvalue;
654         } else {
655             EcStatus = EC_GET_CSR(sc);
656         }
657     }
658     return_ACPI_STATUS (AE_ERROR);
659 }
660
661 static ACPI_STATUS
662 EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
663 {
664     EC_STATUS   EcStatus;
665     UINT32      i = 0;
666
667     if (!EcIsLocked(sc)) {
668         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
669             "EcWaitEvent called without EC lock!\n");
670     }
671
672     /*
673      * Stall 1us:
674      * ----------
675      * Stall for 1 microsecond before reading the status register
676      * for the first time.  This allows the EC to set the IBF/OBF
677      * bit to its proper state.
678      *
679      * XXX it is not clear why we read the CSR twice.
680      */
681     AcpiOsStall(1);
682     EcStatus = EC_GET_CSR(sc);
683
684     /*
685      * Wait For Event:
686      * ---------------
687      * Poll the EC status register to detect completion of the last
688      * command.  Wait up to 10ms (in 10us chunks) for this to occur.
689      */
690     for (i = 0; i < 1000; i++) {
691         EcStatus = EC_GET_CSR(sc);
692
693         if (Event == EC_EVENT_OUTPUT_BUFFER_FULL &&
694             (EcStatus & EC_FLAG_OUTPUT_BUFFER) != 0)
695             return (AE_OK);
696
697         if (Event == EC_EVENT_INPUT_BUFFER_EMPTY && 
698             (EcStatus & EC_FLAG_INPUT_BUFFER) == 0)
699             return(AE_OK);
700         
701         AcpiOsStall(10);
702     }
703
704     return (AE_ERROR);
705 }    
706
707 static ACPI_STATUS
708 EcQuery(struct acpi_ec_softc *sc, UINT8 *Data)
709 {
710     ACPI_STATUS Status;
711
712     Status = EcLock(sc);
713     if (ACPI_FAILURE(Status))
714         return (Status);
715
716     EC_SET_CSR(sc, EC_COMMAND_QUERY);
717     Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL);
718     if (ACPI_SUCCESS(Status))
719         *Data = EC_GET_DATA(sc);
720
721     EcUnlock(sc);
722
723     if (ACPI_FAILURE(Status)) {
724         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
725             "timeout waiting for EC to respond to EC_COMMAND_QUERY\n");
726     }
727     return (Status);
728 }    
729
730 static ACPI_STATUS
731 EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
732 {
733     ACPI_STATUS Status;
734
735     Status = EcLock(sc);
736     if (ACPI_FAILURE(Status))
737         return (Status);
738
739     /*
740      * Perform the transaction.
741      */
742     switch (EcRequest->Command) {
743     case EC_COMMAND_READ:
744         Status = EcRead(sc, EcRequest->Address, &EcRequest->Data);
745         break;
746     case EC_COMMAND_WRITE:
747         Status = EcWrite(sc, EcRequest->Address, &EcRequest->Data);
748         break;
749     default:
750         Status = AE_SUPPORT;
751         break;
752     }
753
754     EcUnlock(sc);
755     
756     /*
757      * Clear & Re-Enable the EC GPE:
758      * -----------------------------
759      * 'Consume' any EC GPE events that we generated while performing
760      * the transaction (e.g. IBF/OBF).  Clearing the GPE here shouldn't
761      * have an adverse affect on outstanding EC-SCI's, as the source
762      * (EC-SCI) will still be high and thus should trigger the GPE
763      * immediately after we re-enabling it.
764      */
765     if (sc->ec_pendquery) {
766         if (ACPI_FAILURE(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
767                                                  EcGpeQueryHandler, sc)))
768             printf("Pend Query Queuing Failed\n");
769         sc->ec_pendquery = 0;
770     }
771
772     if (ACPI_FAILURE(AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE))) {
773         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
774             "EcRequest: Unable to clear the EC GPE.\n");
775     }
776     if (ACPI_FAILURE(AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE, 0))) {
777         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
778             "EcRequest: Unable to re-enable the EC GPE.\n");
779     }
780
781     return (Status);
782 }
783
784
785 static ACPI_STATUS
786 EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
787 {
788     ACPI_STATUS Status;
789
790     if (!EcIsLocked(sc)) {
791         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
792             "EcRead called without EC lock!\n");
793     }
794
795     /*EcBurstEnable(EmbeddedController);*/
796
797     EC_SET_CSR(sc, EC_COMMAND_READ);
798     Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY);
799     if (ACPI_FAILURE(Status)) {
800         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
801             "EcRead: Failed waiting for EC to process read command.\n");
802         return (Status);
803     }
804
805     EC_SET_DATA(sc, Address);
806     Status = EcWaitEventIntr(sc, EC_EVENT_OUTPUT_BUFFER_FULL);
807     if (ACPI_FAILURE(Status)) {
808         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
809             "EcRead: Failed waiting for EC to send data.\n");
810         return (Status);
811     }
812
813     *Data = EC_GET_DATA(sc);
814
815     /*EcBurstDisable(EmbeddedController);*/
816
817     return (AE_OK);
818 }    
819
820 static ACPI_STATUS
821 EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
822 {
823     ACPI_STATUS Status;
824
825     if (!EcIsLocked(sc)) {
826         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
827             "EcWrite called without EC lock!\n");
828     }
829
830     /*EcBurstEnable(EmbeddedController);*/
831
832     EC_SET_CSR(sc, EC_COMMAND_WRITE);
833     Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY);
834     if (ACPI_FAILURE(Status)) {
835         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
836             "EcWrite: Failed waiting for EC to process write command.\n");
837         return (Status);
838     }
839
840     EC_SET_DATA(sc, Address);
841     Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY);
842     if (ACPI_FAILURE(Status)) {
843         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
844             "EcRead: Failed waiting for EC to process address.\n");
845         return (Status);
846     }
847
848     EC_SET_DATA(sc, *Data);
849     Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY);
850     if (ACPI_FAILURE(Status)) {
851         ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
852             "EcWrite: Failed waiting for EC to process data.\n");
853         return (Status);
854     }
855
856     /*EcBurstDisable(EmbeddedController);*/
857
858     return (AE_OK);
859 }