static ACPI_STATUS EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 Data) { ACPI_STATUS status; u_int gen_count; ACPI_SERIAL_ASSERT(ec); status = EcCommand(sc, EC_COMMAND_WRITE); if (ACPI_FAILURE(status)) return (status); gen_count = sc->ec_gencount; EC_SET_DATA(sc, Address); status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count); if (ACPI_FAILURE(status)) { device_printf(sc->ec_dev, "EcWrite: failed waiting for sent address\n"); return (status); } gen_count = sc->ec_gencount; EC_SET_DATA(sc, Data); status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count); if (ACPI_FAILURE(status)) { device_printf(sc->ec_dev, "EcWrite: failed waiting for sent data\n"); return (status); } return (AE_OK); }
static ACPI_STATUS EcCommand(struct acpi_ec_softc *sc, EC_COMMAND cmd) { ACPI_STATUS status; EC_EVENT event; EC_STATUS ec_status; u_int gen_count; ACPI_SERIAL_ASSERT(ec); /* Don't use burst mode if user disabled it. */ if (!ec_burst_mode && cmd == EC_COMMAND_BURST_ENABLE) return (AE_ERROR); /* Decide what to wait for based on command type. */ switch (cmd) { case EC_COMMAND_READ: case EC_COMMAND_WRITE: case EC_COMMAND_BURST_DISABLE: event = EC_EVENT_INPUT_BUFFER_EMPTY; break; case EC_COMMAND_QUERY: case EC_COMMAND_BURST_ENABLE: event = EC_EVENT_OUTPUT_BUFFER_FULL; break; default: device_printf(sc->ec_dev, "EcCommand: invalid command %#x\n", cmd); return (AE_BAD_PARAMETER); } /* * Ensure empty input buffer before issuing command. * Use generation count of zero to force a quick check. */ status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, 0); if (ACPI_FAILURE(status)) return (status); /* Run the command and wait for the chosen event. */ CTR1(KTR_ACPI, "ec running command %#x", cmd); gen_count = sc->ec_gencount; EC_SET_CSR(sc, cmd); status = EcWaitEvent(sc, event, gen_count); if (ACPI_SUCCESS(status)) { /* If we succeeded, burst flag should now be present. */ if (cmd == EC_COMMAND_BURST_ENABLE) { ec_status = EC_GET_CSR(sc); if ((ec_status & EC_FLAG_BURST_MODE) == 0) status = AE_ERROR; } } else device_printf(sc->ec_dev, "EcCommand: no response to %#x\n", cmd); return (status); }
static ACPI_STATUS EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 Data) { ACPI_STATUS status; UINT8 data; u_int gen_count; ACPI_SERIAL_ASSERT(ec); CTR2(KTR_ACPI, "ec write to %#x, data %#x", Address, Data); /* If we can't start burst mode, continue anyway. */ status = EcCommand(sc, EC_COMMAND_BURST_ENABLE); if (status == AE_OK) { data = EC_GET_DATA(sc); if (data == EC_BURST_ACK) { CTR0(KTR_ACPI, "ec burst enabled"); sc->ec_burstactive = TRUE; } } status = EcCommand(sc, EC_COMMAND_WRITE); if (ACPI_FAILURE(status)) return (status); gen_count = sc->ec_gencount; EC_SET_DATA(sc, Address); status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count); if (ACPI_FAILURE(status)) { device_printf(sc->ec_dev, "EcRead: failed waiting for sent address\n"); return (status); } gen_count = sc->ec_gencount; EC_SET_DATA(sc, Data); status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count); if (ACPI_FAILURE(status)) { device_printf(sc->ec_dev, "EcWrite: failed waiting for sent data\n"); return (status); } if (sc->ec_burstactive) { sc->ec_burstactive = FALSE; status = EcCommand(sc, EC_COMMAND_BURST_DISABLE); if (ACPI_FAILURE(status)) return (status); CTR0(KTR_ACPI, "ec disabled burst ok"); } return (AE_OK); }
static ACPI_STATUS EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data) { ACPI_STATUS status; u_int gen_count; int retry; ACPI_SERIAL_ASSERT(ec); for (retry = 0; retry < 2; retry++) { status = EcCommand(sc, EC_COMMAND_READ); if (ACPI_FAILURE(status)) return (status); gen_count = sc->ec_gencount; EC_SET_DATA(sc, Address); status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL, gen_count); if (ACPI_FAILURE(status)) { if (EcCheckStatus(sc, "retr_check", EC_EVENT_INPUT_BUFFER_EMPTY) == AE_OK) continue; else break; } *Data = EC_GET_DATA(sc); return (AE_OK); } device_printf(sc->ec_dev, "EcRead: failed waiting to get data\n"); 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); }
/* * Wait for an event interrupt for a specific condition. */ static ACPI_STATUS EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event) { EC_STATUS EcStatus; int i; ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, (UINT32)Event); /* XXX this should test whether interrupts are available some other way */ if (cold || acpi_ec_event_driven) return_ACPI_STATUS(EcWaitEvent(sc, Event)); if (!EcIsLocked(sc)) ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), "EcWaitEventIntr called without EC lock!\n"); EcStatus = EC_GET_CSR(sc); /* XXX waiting too long? */ for(i = 0; i < 10; i++){ /* * Check EC status against the desired event. */ if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) && (EcStatus & EC_FLAG_OUTPUT_BUFFER)) return_ACPI_STATUS(AE_OK); if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) && !(EcStatus & EC_FLAG_INPUT_BUFFER)) return_ACPI_STATUS(AE_OK); sc->ec_csrvalue = 0; if (ACPI_MSLEEP(&sc->ec_csrvalue, &acpi_mutex, PZERO, "EcWait", 1) != EWOULDBLOCK){ EcStatus = sc->ec_csrvalue; }else{ EcStatus = EC_GET_CSR(sc); } } return_ACPI_STATUS(AE_ERROR); }
static ACPI_STATUS EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event) { EC_STATUS EcStatus; int i; FUNCTION_TRACE_U32(__FUNCTION__, (UINT32)Event); /* XXX Need better test for "yes, you have interrupts". */ if (cold) return_ACPI_STATUS(EcWaitEvent(sc, Event)); if (EcIsLocked(sc) == 0) printf("%s: EcWaitEventIntr called without EC lock!\n", sc->sc_dev.dv_xname); EcStatus = EC_CSR_READ(sc); /* Too long? */ for (i = 0; i < 10; i++) { /* Check EC status against the desired event. */ if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) && (EcStatus & EC_FLAG_OUTPUT_BUFFER) != 0) return_ACPI_STATUS(AE_OK); if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) && (EcStatus & EC_FLAG_INPUT_BUFFER) == 0) return_ACPI_STATUS(AE_OK); sc->sc_csrvalue = 0; /* XXXJRT Sleeping with a lock held? */ if (tsleep(&sc->sc_csrvalue, 0, "EcWait", 1) != EWOULDBLOCK) EcStatus = sc->sc_csrvalue; else EcStatus = EC_CSR_READ(sc); } return_ACPI_STATUS(AE_ERROR); }