Example #1
0
/*
 * Handle a GPE sent to us.
 */
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 (ACPI_FAILURE(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH,
				    EcGpeQueryHandler,Context))) {
	    printf("QueryHandler Queuing Failed\n");
	}
    }
    return;
}
Example #2
0
/*
 * The GPE handler is called when IBE/OBF or SCI events occur.  We are
 * called from an unknown lock context.
 */
static uint32_t
EcGpeHandler(ACPI_HANDLE GpeDevice, UINT32 GpeNumber, void *Context)
{
    struct acpi_ec_softc *sc = Context;
    ACPI_STATUS		       Status;
    EC_STATUS		       EcStatus;

    KASSERT(Context != NULL, ("EcGpeHandler called with NULL"));
    /*
     * Notify EcWaitEvent() that the status register is now fresh.  If we
     * didn't do this, it wouldn't be possible to distinguish an old IBE
     * from a new one, for example when doing a write transaction (writing
     * address and then data values.)
     */
    atomic_add_int(&sc->ec_gencount, 1);
    wakeup(sc);

    /*
     * If the EC_SCI bit of the status register is set, queue a query handler.
     * It will run the query and _Qxx method later, under the lock.
     */
    EcStatus = EC_GET_CSR(sc);
    if ((EcStatus & EC_EVENT_SCI) && !sc->ec_sci_pend) {
	Status = AcpiOsExecute(OSL_GPE_HANDLER, EcGpeQueryHandler, Context);
	if (ACPI_SUCCESS(Status)) {
	    sc->ec_sci_pend = TRUE;
	    return (0);
	} else {
	    kprintf("EcGpeHandler: queuing GPE query handler failed\n");
    	}
    }
    return (ACPI_REENABLE_GPE);
}
Example #3
0
static ACPI_STATUS
EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event)
{
    EC_STATUS	EcStatus;
    UINT32	i = 0;

    if (!EcIsLocked(sc))
	ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
	    "EcWaitEvent called without EC lock!\n");

    /*
     * Stall 1us:
     * ----------
     * Stall for 1 microsecond before reading the status register
     * for the first time.  This allows the EC to set the IBF/OBF
     * bit to its proper state.
     *
     * XXX it is not clear why we read the CSR twice.
     */
    AcpiOsStall(1);
    EcStatus = EC_GET_CSR(sc);

    /*
     * Wait For Event:
     * ---------------
     * Poll the EC status register to detect completion of the last
     * command.  Wait up to 10ms (in 10us chunks) for this to occur.
     */
    for (i = 0; i < 1000; i++) {
	EcStatus = EC_GET_CSR(sc);

        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);
	
	AcpiOsStall(10);
    }

    return(AE_ERROR);
}    
Example #4
0
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);
}
Example #5
0
/*
 * 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);
}
Example #6
0
static ACPI_STATUS
EcCheckStatus(struct acpi_ec_softc *sc, const char *msg, EC_EVENT event)
{
    ACPI_STATUS status;
    EC_STATUS ec_status;

    status = AE_NO_HARDWARE_RESPONSE;
    ec_status = EC_GET_CSR(sc);
    if (sc->ec_burstactive && !(ec_status & EC_FLAG_BURST_MODE)) {
	sc->ec_burstactive = FALSE;
    }
    if (EVENT_READY(event, ec_status)) {
	status = AE_OK;
    }
    return (status);
}
Example #7
0
static ACPI_STATUS
EcCheckStatus(struct acpi_ec_softc *sc, const char *msg, EC_EVENT event)
{
    ACPI_STATUS status;
    EC_STATUS ec_status;

    status = AE_NO_HARDWARE_RESPONSE;
    ec_status = EC_GET_CSR(sc);
    if (sc->ec_burstactive && !(ec_status & EC_FLAG_BURST_MODE)) {
	CTR1(KTR_ACPI, "ec burst disabled in waitevent (%s)", msg);
	sc->ec_burstactive = FALSE;
    }
    if (EVENT_READY(event, ec_status)) {
	CTR2(KTR_ACPI, "ec %s wait ready, status %#x", msg, ec_status);
	status = AE_OK;
    }
    return (status);
}
Example #8
0
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);
}
Example #9
0
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);
}
Example #10
0
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__);

    for (;;) {

	/*
	 * Check EC_SCI.
	 * 
	 * Bail out if the EC_SCI bit of the status register is not set.
	 * Note that this function should only be called when
	 * this bit is set (polling is used to detect IBE/OBF events).
	 *
	 * It is safe to do this without locking the controller, as it's
	 * OK to call EcQuery when there's no data ready; in the worst
	 * case we should just find nothing waiting for us and bail.
	 */
	if (!(EC_GET_CSR(sc) & EC_EVENT_SCI))
	    break;

	/*
	 * Find out why the EC is signalling us
	 */
	Status = EcQuery(sc, &Data);
	    
	/*
	 * If we failed to get anything from the EC, give up
	 */
	if (ACPI_FAILURE(Status)) {
	    ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
		"GPE query failed - %s\n", AcpiFormatException(Status));
	    break;
	}

	/*
	 * Evaluate _Qxx to respond to the controller.
	 */
	sprintf(qxx, "_Q%02x", Data);
	strupr(qxx);
	Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL);
	/*
	 * Ignore spurious query requests.
	 */
	if (ACPI_FAILURE(Status) && (Data != 0 || Status != AE_NOT_FOUND)) {
	    ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev),
	    	"evaluation of GPE query method %s failed - %s\n", 
			qxx, AcpiFormatException(Status));
	}
    }
        /* I know I request Level trigger cleanup */
    if (ACPI_FAILURE(AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE)))
	    printf("EcGpeQueryHandler:ClearEvent Failed\n");
    if (ACPI_FAILURE(AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE, 0)))
	    printf("EcGpeQueryHandler:EnableEvent Failed\n");
    return_VOID;
}