static ACPI_STATUS EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest) { ACPI_STATUS Status; /* * Lock the EC */ if (ACPI_FAILURE(Status = EcLock(sc))) return(Status); /* * Perform the transaction. */ switch (EcRequest->Command) { case EC_COMMAND_READ: Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data)); break; case EC_COMMAND_WRITE: Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data)); break; default: Status = AE_SUPPORT; break; } /* * Unlock the EC */ EcUnlock(sc); /* * Clear & Re-Enable the EC GPE: * ----------------------------- * 'Consume' any EC GPE events that we generated while performing * the transaction (e.g. IBF/OBF). Clearing the GPE here shouldn't * have an adverse affect on outstanding EC-SCI's, as the source * (EC-SCI) will still be high and thus should trigger the GPE * immediately after we re-enabling it. */ if (sc->ec_pendquery){ if (ACPI_FAILURE(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, EcGpeQueryHandler, sc))) printf("Pend Query Queuing Failed\n"); sc->ec_pendquery = 0; } if (ACPI_FAILURE(AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE))) ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), "EcRequest: Unable to clear the EC GPE.\n"); if (ACPI_FAILURE(AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE, 0))) ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), "EcRequest: Unable to re-enable the EC GPE.\n"); return(Status); }
static void EcGpeQueryHandler(void *Context) { struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; UINT8 Data; ACPI_STATUS Status; char qxx[5]; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); KASSERT(Context != NULL, ("EcGpeQueryHandler called with NULL")); /* Serialize user access with EcSpaceHandler(). */ Status = EcLock(sc); if (ACPI_FAILURE(Status)) { device_printf(sc->ec_dev, "GpeQuery lock error: %s\n", AcpiFormatException(Status)); return; } /* * Send a query command to the EC to find out which _Qxx call it * wants to make. This command clears the SCI bit and also the * interrupt source since we are edge-triggered. To prevent the GPE * that may arise from running the query from causing another query * to be queued, we clear the pending flag only after running it. */ Status = EcCommand(sc, EC_COMMAND_QUERY); sc->ec_sci_pend = FALSE; if (ACPI_FAILURE(Status)) { EcUnlock(sc); device_printf(sc->ec_dev, "GPE query failed: %s\n", AcpiFormatException(Status)); return; } Data = EC_GET_DATA(sc); /* * We have to unlock before running the _Qxx method below since that * method may attempt to read/write from EC address space, causing * recursive acquisition of the lock. */ EcUnlock(sc); /* Ignore the value for "no outstanding event". (13.3.5) */ CTR2(KTR_ACPI, "ec query ok,%s running _Q%02X", Data ? "" : " not", Data); if (Data == 0) return; /* Evaluate _Qxx to respond to the controller. */ snprintf(qxx, sizeof(qxx), "_Q%02X", Data); AcpiUtStrupr(qxx); Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL); if (ACPI_FAILURE(Status) && Status != AE_NOT_FOUND) { device_printf(sc->ec_dev, "evaluation of query method %s failed: %s\n", qxx, AcpiFormatException(Status)); } }
static ACPI_STATUS EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest) { ACPI_STATUS Status; if ((Status = EcLock(sc)) != AE_OK) return (Status); /* * Perform the transaction. */ switch (EcRequest->Command) { case EC_COMMAND_READ: Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data)); break; case EC_COMMAND_WRITE: Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data)); break; default: Status = AE_SUPPORT; break; } /* * Clear & Re-Enable the EC GPE: * ----------------------------- * 'Consume' any EC GPE events that we generated while performing * the transaction (e.g. IBF/OBF). Clearing the GPE here shouldn't * have an adverse affect on outstanding EC-SCI's, as the source * (EC-SCI) will still be high and thus should trigger the GPE * immediately after we re-enabling it. */ if (sc->sc_flags & EC_F_PENDQUERY) { if (AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, EcGpeQueryHandler, sc) != AE_OK) printf("%s: unable to queue pending query\n", sc->sc_dev.dv_xname); sc->sc_flags &= ~EC_F_PENDQUERY; } if (AcpiClearEvent(sc->sc_gpebit, ACPI_EVENT_GPE) != AE_OK) printf("%s: EcRequest: unable to clear EC GPE\n", sc->sc_dev.dv_xname); if (AcpiEnableEvent(sc->sc_gpebit, ACPI_EVENT_GPE) != AE_OK) printf("%s: EcRequest: unable to reenable EC GPE\n", sc->sc_dev.dv_xname); EcUnlock(sc); return(Status); }
static ACPI_STATUS EcQuery(struct acpi_ec_softc *sc, UINT8 *Data) { ACPI_STATUS Status; if (ACPI_FAILURE(Status = EcLock(sc))) return(Status); EC_SET_CSR(sc, EC_COMMAND_QUERY); if (ACPI_SUCCESS(Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL))) *Data = EC_GET_DATA(sc); EcUnlock(sc); if (ACPI_FAILURE(Status)) ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), "timeout waiting for EC to respond to EC_COMMAND_QUERY\n"); return(Status); }
static ACPI_STATUS EcQuery(struct acpi_ec_softc *sc, UINT8 *Data) { ACPI_STATUS Status; if ((Status = EcLock(sc)) != AE_OK) return (Status); EC_CSR_WRITE(sc, EC_COMMAND_QUERY); Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL); if (Status == AE_OK) *Data = EC_DATA_READ(sc); EcUnlock(sc); if (Status != AE_OK) printf("%s: timed out waiting for EC to respond to " "EC_COMMAND_QUERY\n", sc->sc_dev.dv_xname); return (Status); }
static ACPI_STATUS EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 Width, UINT64 *Value, void *Context, void *RegionContext) { struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; ACPI_PHYSICAL_ADDRESS EcAddr; UINT8 *EcData; ACPI_STATUS Status; ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, (UINT32)Address); if (Function != ACPI_READ && Function != ACPI_WRITE) return_ACPI_STATUS (AE_BAD_PARAMETER); if (Width % 8 != 0 || Value == NULL || Context == NULL) return_ACPI_STATUS (AE_BAD_PARAMETER); if (Address + Width / 8 > 256) return_ACPI_STATUS (AE_BAD_ADDRESS); /* * If booting, check if we need to run the query handler. If so, we * we call it directly here since our thread taskq is not active yet. */ if (cold || rebooting || sc->ec_suspending) { if ((EC_GET_CSR(sc) & EC_EVENT_SCI)) { EcGpeQueryHandler(sc); } } /* Serialize with EcGpeQueryHandler() at transaction granularity. */ Status = EcLock(sc); if (ACPI_FAILURE(Status)) return_ACPI_STATUS (Status); /* If we can't start burst mode, continue anyway. */ Status = EcCommand(sc, EC_COMMAND_BURST_ENABLE); if (ACPI_SUCCESS(Status)) { if (EC_GET_DATA(sc) == EC_BURST_ACK) { sc->ec_burstactive = TRUE; } } /* Perform the transaction(s), based on Width. */ EcAddr = Address; EcData = (UINT8 *)Value; if (Function == ACPI_READ) *Value = 0; do { switch (Function) { case ACPI_READ: Status = EcRead(sc, EcAddr, EcData); break; case ACPI_WRITE: Status = EcWrite(sc, EcAddr, *EcData); break; } if (ACPI_FAILURE(Status)) break; EcAddr++; EcData++; } while (EcAddr < Address + Width / 8); if (sc->ec_burstactive) { sc->ec_burstactive = FALSE; if (ACPI_SUCCESS(EcCommand(sc, EC_COMMAND_BURST_DISABLE))) { } } EcUnlock(sc); return_ACPI_STATUS (Status); }
static void EcGpeQueryHandler(void *Context) { struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; UINT8 Data; ACPI_STATUS Status; int retry, sci_enqueued; char qxx[5]; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); KASSERT(Context != NULL, ("EcGpeQueryHandler called with NULL")); /* Serialize user access with EcSpaceHandler(). */ Status = EcLock(sc); if (ACPI_FAILURE(Status)) { device_printf(sc->ec_dev, "GpeQuery lock error: %s\n", AcpiFormatException(Status)); return; } /* * Send a query command to the EC to find out which _Qxx call it * wants to make. This command clears the SCI bit and also the * interrupt source since we are edge-triggered. To prevent the GPE * that may arise from running the query from causing another query * to be queued, we clear the pending flag only after running it. */ sci_enqueued = sc->ec_sci_pend; for (retry = 0; retry < 2; retry++) { Status = EcCommand(sc, EC_COMMAND_QUERY); if (ACPI_SUCCESS(Status)) break; if (EcCheckStatus(sc, "retr_check", EC_EVENT_INPUT_BUFFER_EMPTY) == AE_OK) continue; else break; } sc->ec_sci_pend = FALSE; if (ACPI_FAILURE(Status)) { EcUnlock(sc); device_printf(sc->ec_dev, "GPE query failed: %s\n", AcpiFormatException(Status)); return; } Data = EC_GET_DATA(sc); /* * We have to unlock before running the _Qxx method below since that * method may attempt to read/write from EC address space, causing * recursive acquisition of the lock. */ EcUnlock(sc); /* Ignore the value for "no outstanding event". (13.3.5) */ if (Data == 0) return; /* Evaluate _Qxx to respond to the controller. */ ksnprintf(qxx, sizeof(qxx), "_Q%02X", Data); AcpiUtStrupr(qxx); Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL); if (ACPI_FAILURE(Status) && Status != AE_NOT_FOUND) { device_printf(sc->ec_dev, "evaluation of query method %s failed: %s\n", qxx, AcpiFormatException(Status)); } /* Reenable runtime GPE if its execution was deferred. */ if (sci_enqueued) { Status = AcpiFinishGpe(sc->ec_gpehandle, sc->ec_gpebit); if (ACPI_FAILURE(Status)) device_printf(sc->ec_dev, "reenabling runtime GPE failed: %s\n", AcpiFormatException(Status)); } }
static ACPI_STATUS EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 Width, UINT64 *Value, void *Context, void *RegionContext) { struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; ACPI_STATUS Status; UINT8 *EcData; UINT8 EcAddr; int bytes, i; ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, (UINT32)Address); if (Width % 8 != 0 || Value == NULL || Context == NULL) return_ACPI_STATUS (AE_BAD_PARAMETER); bytes = Width / 8; if (Address + bytes - 1 > 0xFF) return_ACPI_STATUS (AE_BAD_ADDRESS); if (Function == ACPI_READ) *Value = 0; EcAddr = Address; EcData = (UINT8 *)Value; /* * If booting, check if we need to run the query handler. If so, we * we call it directly here since our thread taskq is not active yet. */ if (cold || rebooting || sc->ec_suspending) { if ((EC_GET_CSR(sc) & EC_EVENT_SCI)) { CTR0(KTR_ACPI, "ec running gpe handler directly"); EcGpeQueryHandler(sc); } } /* Serialize with EcGpeQueryHandler() at transaction granularity. */ Status = EcLock(sc); if (ACPI_FAILURE(Status)) return_ACPI_STATUS (Status); /* Perform the transaction(s), based on Width. */ for (i = 0; i < bytes; i++, EcAddr++, EcData++) { switch (Function) { case ACPI_READ: Status = EcRead(sc, EcAddr, EcData); break; case ACPI_WRITE: Status = EcWrite(sc, EcAddr, *EcData); break; default: device_printf(sc->ec_dev, "invalid EcSpaceHandler function %d\n", Function); Status = AE_BAD_PARAMETER; break; } if (ACPI_FAILURE(Status)) break; } EcUnlock(sc); return_ACPI_STATUS (Status); }