static struct acpi_device *first_ec;
static int acpi_ec_poll_mode = EC_INTR;
+static u32 wmi_event_data_index = 0;
+extern u8 in_query_wmi_event_data;
+extern const u8 wmi_ec_max_data_size;
+extern u32 wmi_ec_port_data_size;
+extern u8 wmi_ec_port_data[32];
+
/* --------------------------------------------------------------------------
Transaction Management
-------------------------------------------------------------------------- */
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
*data, address));
+ /* HACK ALERT
+ * Please refer to wmi.c for an explanation on why we added this hack.
+ */
+ if ( in_query_wmi_event_data == TRUE ) {
+ if ( address == 0x2b ) {
+ wmi_event_data_index = 0;
+ memset(wmi_ec_port_data, 0, wmi_ec_max_data_size);
+ wmi_ec_port_data_size = *data;
+ } else if ( (address == 0x2c) && (wmi_event_data_index < wmi_ec_port_data_size)
+ && (wmi_event_data_index < wmi_ec_max_data_size) ) {
+ wmi_ec_port_data[wmi_event_data_index] = *data;
+ wmi_event_data_index++;
+ }
+ }
+
end:
up(&ec->intr.sem);
#include <linux/types.h>
#include <linux/list.h>
#include <linux/acpi.h>
+#include <linux/dmi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
};
static struct wmi_block wmi_blocks;
+static DEFINE_MUTEX(wmi_mutex);
+
+/*
+ * YIKEES! HACK ALERT
+ * Due to buffer dereferencing bugs at firmware layer, some firmware(s)
+ * (Dell in specific) return all 0s for wmi event data when
+ * queried through _WED. To work around this firmware bug and provide
+ * appropriate event data to guest firmware, we will sniff the embedded
+ * controller port access to addresses 0x2b and 0x2c and slap that data
+ * at the beginning of _WED return buffer which would otherwise be all 0s.
+ */
+static u8 enable_wmi_event_data_hack = FALSE;
+u8 in_query_wmi_event_data = FALSE;
+const u8 wmi_ec_max_data_size = 32;
+u32 wmi_ec_port_data_size = 0;
+u8 wmi_ec_port_data[32];
/*
* If the GUID data block is marked as expensive, we must enable and
struct guid_block *gblock;
struct wmi_block *wblock;
struct list_head *p;
+ acpi_status status;
+ uint count;
input.count = 1;
input.pointer = params;
gblock = &wblock->gblock;
if ((gblock->flags & ACPI_WMI_EVENT) &&
- (gblock->notify_id == event))
- return acpi_evaluate_object(wblock->handle, "_WED",
+ (gblock->notify_id == event)) {
+ mutex_lock(&wmi_mutex);
+ if ( enable_wmi_event_data_hack == TRUE ) {
+ wmi_ec_port_data_size = 0;
+ memset(wmi_ec_port_data, 0, 32);
+ in_query_wmi_event_data = TRUE;
+ }
+ status = acpi_evaluate_object(wblock->handle, "_WED",
&input, out);
+ if ( enable_wmi_event_data_hack == TRUE ) {
+ for ( count = 0; count < wmi_ec_port_data_size; count++)
+ ((char *)((union acpi_object *)
+ out->pointer)->buffer.pointer)[count]
+ = wmi_ec_port_data[count];
+ in_query_wmi_event_data = FALSE;
+ }
+ mutex_unlock(&wmi_mutex);
+ return status;
+ }
}
return AE_NOT_FOUND;
static int __init acpi_wmi_init(void)
{
acpi_status result;
+ char *dmi_sys_info;
INIT_LIST_HEAD(&wmi_blocks.list);
printk(KERN_INFO PREFIX "Mapper loaded\n");
}
+ dmi_sys_info = dmi_get_system_info(DMI_SYS_VENDOR);
+ if ( dmi_sys_info == NULL )
+ return result;
+
+ if ( strstr(dmi_sys_info, "Dell") != NULL )
+ enable_wmi_event_data_hack = TRUE;
+
return result;
}