Subject: [PATCH] [acpi ec] Fill out GPE handling - Schedule gpe_query() to run in process context - Query the device to determine what happened - Determine the _Qxx method to run and evaluate it Signed-off-by: Patrick Mochel --- drivers/acpi/drivers/ec/gpe.c | 77 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 77 insertions(+), 0 deletions(-) applies-to: 7625fb2e853bd096862d9850105d135154902a7c 29978ef25c364d72ed70cf4d0d369dc479dac193 diff --git a/drivers/acpi/drivers/ec/gpe.c b/drivers/acpi/drivers/ec/gpe.c index 4fb07b6..14f0dc1 100644 --- a/drivers/acpi/drivers/ec/gpe.c +++ b/drivers/acpi/drivers/ec/gpe.c @@ -14,11 +14,88 @@ #include "ec.h" +static int ec_query(struct acpi_ec * ec, u32 * data) +{ + acpi_status status; + u32 glk; + int ret; + + if (ec->e_global_lock) { + status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); + if (ACPI_FAILURE(status)) + return -ENODEV; + } + + down(&ec->e_sem); + + ret = ec->e_wait(ec, ACPI_EC_EVENT_IBE); + if (ret) { + dbg("EC queried, IB not empty"); + goto Done; + } + + /* + * Query the EC to find out which _Qxx method we need to evaluate. + * Note that successful completion of the query causes the ACPI_EC_SCI + * bit to be cleared (and thus clearing the interrupt source). + */ + acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->e_command); + ret = ec->e_wait(ec, ACPI_EC_EVENT_OBF); + if (ret) { + dbg("EC queried, OB not full"); + goto Done; + } + + acpi_hw_low_level_read(8, data, &ec->e_data); + if (!*data) + ret = -ENODATA; + + Done: + up(&ec->e_sem); + if (ec->e_global_lock) + acpi_release_global_lock(glk); + return ret; +} + + +static void gpe_query(void * context) +{ + struct acpi_ec * ec = context; + static char obj[5] = "_Q--"; + const char hex[] = "01234567890abcdef"; + u32 value; + int ret; + + ret = ec_query(ec, &value); + if (!ret) { + obj[2] = hex[(value >> 4) & 0x0f]; + obj[3] = hex[value & 0x0f]; + dbg("Evaluating %s", obj); + acpi_evaluate_object(ec->e_handle, obj, NULL, NULL); + } +} + static u32 gpe_callback(void * data) { struct acpi_ec * ec = data; + u32 ec_status; acpi_disable_gpe(NULL, ec->e_gpe_bit, ACPI_ISR); + ec_status = ec_read_status(ec); + + /* + * NOTE: All we care about are EC-SCI's. Other EC events are + * handled via polling (yuck!). This is because some systems + * treat EC-SCIs as level (versus EDGE!) triggered, preventing + * a purely interrupt-driven approach (grumble, grumble). + */ + if (ec_status & ACPI_EC_FLAG_SCI) { + acpi_status status; + status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, + gpe_query, ec); + return ACPI_SUCCESS(status) ? ACPI_INTERRUPT_HANDLED : + ACPI_INTERRUPT_NOT_HANDLED; + } return ACPI_INTERRUPT_HANDLED; } --- 0.99.9.GIT