summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpica/acpi_ec.c
diff options
context:
space:
mode:
authortakawata <takawata@FreeBSD.org>2000-12-14 12:43:22 +0000
committertakawata <takawata@FreeBSD.org>2000-12-14 12:43:22 +0000
commit41330c955038e5321980e599462c931a0505b773 (patch)
tree34eeadeb3027cb68635d92796360ac431b1a7ac0 /sys/dev/acpica/acpi_ec.c
parent51b13b77a86b00df06fcb85475474e4a7b388084 (diff)
downloadFreeBSD-src-41330c955038e5321980e599462c931a0505b773.zip
FreeBSD-src-41330c955038e5321980e599462c931a0505b773.tar.gz
Make Embedded Controller driver interrupt driven.
Diffstat (limited to 'sys/dev/acpica/acpi_ec.c')
-rw-r--r--sys/dev/acpica/acpi_ec.c96
1 files changed, 77 insertions, 19 deletions
diff --git a/sys/dev/acpica/acpi_ec.c b/sys/dev/acpica/acpi_ec.c
index aa90c87..6f44add 100644
--- a/sys/dev/acpica/acpi_ec.c
+++ b/sys/dev/acpica/acpi_ec.c
@@ -172,6 +172,8 @@ struct acpi_ec_softc {
bus_space_handle_t ec_csr_handle;
int ec_locked;
+ int ec_pendquery;
+ int ec_csrvalue;
};
#define EC_LOCK_TIMEOUT 1000 /* 1ms */
@@ -296,6 +298,7 @@ acpi_ec_attach(device_t dev)
* Fetch/initialise softc
*/
sc = device_get_softc(dev);
+ bzero(sc, sizeof(*sc));
sc->ec_dev = dev;
sc->ec_handle = acpi_get_handle(dev);
@@ -400,7 +403,7 @@ acpi_ec_attach(device_t dev)
}
static void
-EcGpeHandler(void *Context)
+EcGpeQueryHandler(void *Context)
{
struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context;
UINT8 Data;
@@ -443,11 +446,42 @@ EcGpeHandler(void *Context)
*/
sprintf(qxx, "_Q%02x", Data);
strupr(qxx);
- if ((Status - AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL)) != AE_OK) {
+ if ((Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL)) != AE_OK) {
device_printf(sc->ec_dev, "evaluation of GPE query method %s failed - %s\n",
qxx, acpi_strerror(Status));
}
}
+ /* I know I request Level trigger cleanup */
+ if(AcpiClearEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
+ printf("EcGpeQueryHandler:ClearEvent Failed\n");
+ if(AcpiEnableEvent(sc->ec_gpebit,ACPI_EVENT_GPE) != AE_OK)
+ printf("EcGpeQueryHandler:EnableEvent Failed\n");
+ return;
+}
+static void EcGpeHandler(void *Context)
+{
+ struct acpi_ec_softc *sc = Context;
+ int csrvalue;
+ /*
+ * If EC is locked, the intr must process EcRead/Write wait only.
+ * Query request must be pending.
+ */
+ if(EcIsLocked(sc)){
+ csrvalue = EC_GET_CSR(sc);
+ if(csrvalue & EC_EVENT_SCI)
+ sc->ec_pendquery = 1;
+ if((csrvalue & EC_FLAG_OUTPUT_BUFFER)
+ || !(csrvalue & EC_FLAG_INPUT_BUFFER)){
+ sc->ec_csrvalue=csrvalue;
+ wakeup((void *)&sc->ec_csrvalue);
+ }
+ }else{
+ /*Queue GpeQuery Handler*/
+ if(AcpiOsQueueForExecution(OSD_PRIORITY_GPE,
+ EcGpeQueryHandler,Context) != AE_OK){
+ printf("QueryHandler Queuing Failed\n");
+ }
+ }
return_VOID;
}
@@ -501,6 +535,34 @@ EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UIN
return_ACPI_STATUS(Status);
}
+static ACPI_STATUS
+EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event)
+{
+ EC_STATUS EcStatus;
+ int i;
+ if(cold)
+ return EcWaitEvent(sc, Event);
+ if (!EcIsLocked(sc))
+ device_printf(sc->ec_dev, "EcWaitEventIntr called without EC lock!\n");
+ EcStatus = EC_GET_CSR(sc);
+ /*Too long?*/
+ for(i=0;i<10;i++){
+ if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) &&
+ (EcStatus & EC_FLAG_OUTPUT_BUFFER))
+ return(AE_OK);
+
+ if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) &&
+ !(EcStatus & EC_FLAG_INPUT_BUFFER))
+ return(AE_OK);
+ sc->ec_csrvalue = 0;
+ if(tsleep(&sc->ec_csrvalue, 0,"ECTRANS",1) != EWOULDBLOCK){
+ EcStatus = sc->ec_csrvalue;
+ }else{
+ EcStatus=EC_GET_CSR(sc);
+ }
+ }
+ return AE_ERROR;
+}
static ACPI_STATUS
EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
@@ -579,17 +641,6 @@ EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
return(Status);
/*
- * Disable EC GPE:
- * ---------------
- * Disable EC interrupts (GPEs) from occuring during this transaction.
- * This is done here as EcTransaction() is also called by the EC GPE
- * handler -- where disabling/re-enabling the EC GPE is automatically
- * handled by the ACPI Core Subsystem.
- */
- if (AcpiDisableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
- device_printf(sc->ec_dev, "EcRequest: Unable to disable the EC GPE.\n");
-
- /*
* Perform the transaction.
*/
switch (EcRequest->Command) {
@@ -615,6 +666,13 @@ EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest)
* (EC-SCI) will still be high and thus should trigger the GPE
* immediately after we re-enabling it.
*/
+ if (sc->ec_pendquery){
+ if(AcpiOsQueueForExecution(OSD_PRIORITY_GPE,
+ EcGpeQueryHandler, sc) != AE_OK)
+ printf("Pend Query Queuing Failed\n");
+ sc->ec_pendquery = 0;
+ }
+
if (AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
device_printf(sc->ec_dev, "EcRequest: Unable to clear the EC GPE.\n");
if (AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK)
@@ -640,13 +698,13 @@ EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
/*EcBurstEnable(EmbeddedController);*/
EC_SET_CSR(sc, EC_COMMAND_READ);
- if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
+ if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process read command.\n");
return(Status);
}
EC_SET_DATA(sc, Address);
- if ((Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL)) != AE_OK) {
+ if ((Status = EcWaitEventIntr(sc, EC_EVENT_OUTPUT_BUFFER_FULL)) != AE_OK) {
device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to send data.\n");
return(Status);
}
@@ -669,19 +727,19 @@ EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
/*EcBurstEnable(EmbeddedController);*/
EC_SET_CSR(sc, EC_COMMAND_WRITE);
- if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
+ if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process write command.\n");
return(Status);
}
EC_SET_DATA(sc, Address);
- if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
+ if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process address.\n");
return(Status);
}
EC_SET_DATA(sc, *Data);
- if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
+ if ((Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) {
device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process data.\n");
return(Status);
}
@@ -689,4 +747,4 @@ EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data)
/*EcBurstDisable(EmbeddedController);*/
return(AE_OK);
-}
+}
OpenPOWER on IntegriCloud