|
@@ -145,57 +145,154 @@ static const u16 bios_to_linux_keycode[256] __initconst = {
|
|
|
|
|
|
static struct input_dev *dell_wmi_input_dev;
|
|
|
|
|
|
+static void dell_wmi_process_key(int reported_key)
|
|
|
+{
|
|
|
+ const struct key_entry *key;
|
|
|
+
|
|
|
+ key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
|
|
|
+ reported_key);
|
|
|
+ if (!key) {
|
|
|
+ pr_info("Unknown key %x pressed\n", reported_key);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ pr_debug("Key %x pressed\n", reported_key);
|
|
|
+
|
|
|
+ /* Don't report brightness notifications that will also come via ACPI */
|
|
|
+ if ((key->keycode == KEY_BRIGHTNESSUP ||
|
|
|
+ key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video)
|
|
|
+ return;
|
|
|
+
|
|
|
+ sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true);
|
|
|
+}
|
|
|
+
|
|
|
static void dell_wmi_notify(u32 value, void *context)
|
|
|
{
|
|
|
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
|
union acpi_object *obj;
|
|
|
acpi_status status;
|
|
|
+ acpi_size buffer_size;
|
|
|
+ u16 *buffer_entry, *buffer_end;
|
|
|
+ int len, i;
|
|
|
|
|
|
status = wmi_get_event_data(value, &response);
|
|
|
if (status != AE_OK) {
|
|
|
- pr_info("bad event status 0x%x\n", status);
|
|
|
+ pr_warn("bad event status 0x%x\n", status);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
obj = (union acpi_object *)response.pointer;
|
|
|
+ if (!obj) {
|
|
|
+ pr_warn("no response\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (obj && obj->type == ACPI_TYPE_BUFFER) {
|
|
|
- const struct key_entry *key;
|
|
|
- int reported_key;
|
|
|
- u16 *buffer_entry = (u16 *)obj->buffer.pointer;
|
|
|
- int buffer_size = obj->buffer.length/2;
|
|
|
-
|
|
|
- if (buffer_size >= 2 && dell_new_hk_type && buffer_entry[1] != 0x10) {
|
|
|
- pr_info("Received unknown WMI event (0x%x)\n",
|
|
|
- buffer_entry[1]);
|
|
|
- kfree(obj);
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (obj->type != ACPI_TYPE_BUFFER) {
|
|
|
+ pr_warn("bad response type %x\n", obj->type);
|
|
|
+ kfree(obj);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ pr_debug("Received WMI event (%*ph)\n",
|
|
|
+ obj->buffer.length, obj->buffer.pointer);
|
|
|
|
|
|
- if (buffer_size >= 3 && (dell_new_hk_type || buffer_entry[1] == 0x0))
|
|
|
- reported_key = (int)buffer_entry[2];
|
|
|
+ buffer_entry = (u16 *)obj->buffer.pointer;
|
|
|
+ buffer_size = obj->buffer.length/2;
|
|
|
+
|
|
|
+ if (!dell_new_hk_type) {
|
|
|
+ if (buffer_size >= 3 && buffer_entry[1] == 0x0)
|
|
|
+ dell_wmi_process_key(buffer_entry[2]);
|
|
|
else if (buffer_size >= 2)
|
|
|
- reported_key = (int)buffer_entry[1] & 0xffff;
|
|
|
- else {
|
|
|
+ dell_wmi_process_key(buffer_entry[1]);
|
|
|
+ else
|
|
|
pr_info("Received unknown WMI event\n");
|
|
|
- kfree(obj);
|
|
|
- return;
|
|
|
+ kfree(obj);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ buffer_end = buffer_entry + buffer_size;
|
|
|
+
|
|
|
+ while (buffer_entry < buffer_end) {
|
|
|
+
|
|
|
+ len = buffer_entry[0];
|
|
|
+ if (len == 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ len++;
|
|
|
+
|
|
|
+ if (buffer_entry + len > buffer_end) {
|
|
|
+ pr_warn("Invalid length of WMI event\n");
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
- key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
|
|
|
- reported_key);
|
|
|
- if (!key) {
|
|
|
- pr_info("Unknown key %x pressed\n", reported_key);
|
|
|
- } else if ((key->keycode == KEY_BRIGHTNESSUP ||
|
|
|
- key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) {
|
|
|
- /* Don't report brightness notifications that will also
|
|
|
- * come via ACPI */
|
|
|
- ;
|
|
|
- } else {
|
|
|
- sparse_keymap_report_entry(dell_wmi_input_dev, key,
|
|
|
- 1, true);
|
|
|
+ pr_debug("Process buffer (%*ph)\n", len*2, buffer_entry);
|
|
|
+
|
|
|
+ switch (buffer_entry[1]) {
|
|
|
+ case 0x00:
|
|
|
+ for (i = 2; i < len; ++i) {
|
|
|
+ switch (buffer_entry[i]) {
|
|
|
+ case 0xe043:
|
|
|
+ /* NIC Link is Up */
|
|
|
+ pr_debug("NIC Link is Up\n");
|
|
|
+ break;
|
|
|
+ case 0xe044:
|
|
|
+ /* NIC Link is Down */
|
|
|
+ pr_debug("NIC Link is Down\n");
|
|
|
+ break;
|
|
|
+ case 0xe045:
|
|
|
+ /* Unknown event but defined in DSDT */
|
|
|
+ default:
|
|
|
+ /* Unknown event */
|
|
|
+ pr_info("Unknown WMI event type 0x00: "
|
|
|
+ "0x%x\n", (int)buffer_entry[i]);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 0x10:
|
|
|
+ /* Keys pressed */
|
|
|
+ for (i = 2; i < len; ++i)
|
|
|
+ dell_wmi_process_key(buffer_entry[i]);
|
|
|
+ break;
|
|
|
+ case 0x11:
|
|
|
+ for (i = 2; i < len; ++i) {
|
|
|
+ switch (buffer_entry[i]) {
|
|
|
+ case 0xfff0:
|
|
|
+ /* Battery unplugged */
|
|
|
+ pr_debug("Battery unplugged\n");
|
|
|
+ break;
|
|
|
+ case 0xfff1:
|
|
|
+ /* Battery inserted */
|
|
|
+ pr_debug("Battery inserted\n");
|
|
|
+ break;
|
|
|
+ case 0x01e1:
|
|
|
+ case 0x02ea:
|
|
|
+ case 0x02eb:
|
|
|
+ case 0x02ec:
|
|
|
+ case 0x02f6:
|
|
|
+ /* Keyboard backlight level changed */
|
|
|
+ pr_debug("Keyboard backlight level "
|
|
|
+ "changed\n");
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ /* Unknown event */
|
|
|
+ pr_info("Unknown WMI event type 0x11: "
|
|
|
+ "0x%x\n", (int)buffer_entry[i]);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ /* Unknown event */
|
|
|
+ pr_info("Unknown WMI event type 0x%x\n",
|
|
|
+ (int)buffer_entry[1]);
|
|
|
+ break;
|
|
|
}
|
|
|
+
|
|
|
+ buffer_entry += len;
|
|
|
+
|
|
|
}
|
|
|
+
|
|
|
kfree(obj);
|
|
|
}
|
|
|
|