Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8dda6b04 authored by Thomas Renninger's avatar Thomas Renninger Committed by Matthew Garrett
Browse files

x86 platform drivers: hp-wmi fix buffer size depending on ACPI version



Depending on ACPI version (1.0 -> 32 bit) an integer could be
32 or 64 bit long. _WED internal concatenates two integers and
the return value will be 8 byte (2* 32 bit) or 16 byte (2* 64 bit)
long, depending on the ACPI version.

Also the data send with the WMI event is defined to be splitted into:
  - Event ID -> 4 bytes
  - Event Data -> 4 bytes

This gets messed up with new ACPI versions.
But it's a HP BIOS bug that may get fixed in the future
-> Support both, 16 and 8 byte _WED buffers.

Also the wrong assumption that from the event data sent, only the
first byte is relevant got cleaned up that it fits event_id/event_data
as described above.

Signed-off-by: default avatarThomas Renninger <trenn@suse.de>
CC: robert.moore@intel.com
Signed-off-by: default avatarMatthew Garrett <mjg@redhat.com>
CC: platform-driver-x86@vger.kernel.org
CC: linux-acpi@vger.kernel.org
parent 1bbdfd59
Loading
Loading
Loading
Loading
+27 −7
Original line number Diff line number Diff line
@@ -352,7 +352,9 @@ static void hp_wmi_notify(u32 value, void *context)
	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
	static struct key_entry *key;
	union acpi_object *obj;
	int eventcode, key_code;
	u32 event_id, event_data;
	int key_code;
	u32 *location;
	acpi_status status;

	status = wmi_get_event_data(value, &response);
@@ -363,15 +365,33 @@ static void hp_wmi_notify(u32 value, void *context)

	obj = (union acpi_object *)response.pointer;

	if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
		printk(KERN_INFO PREFIX "Unknown response received\n");
	if (obj || obj->type != ACPI_TYPE_BUFFER) {
		printk(KERN_INFO "hp-wmi: Unknown response received %d\n",
		       obj->type);
		kfree(obj);
		return;
	}

	eventcode = *((u8 *) obj->buffer.pointer);
	/*
	 * Depending on ACPI version the concatenation of id and event data
	 * inside _WED function will result in a 8 or 16 byte buffer.
	 */
	location = (u32 *)obj->buffer.pointer;
	if (obj->buffer.length == 8) {
		event_id = *location;
		event_data = *(location + 1);
	} else if (obj->buffer.length == 16) {
		event_id = *location;
		event_data = *(location + 2);
	} else {
		printk(KERN_INFO "hp-wmi: Unknown buffer length %d\n",
		       obj->buffer.length);
		kfree(obj);
		return;
	}
	kfree(obj);
	switch (eventcode) {

	switch (event_id) {
	case HPWMI_DOCK_EVENT:
		input_report_switch(hp_wmi_input_dev, SW_DOCK,
				    hp_wmi_dock_state());
@@ -423,8 +443,8 @@ static void hp_wmi_notify(u32 value, void *context)
	case HPWMI_LOCK_SWITCH:
		break;
	default:
		printk(KERN_INFO PREFIX "Unknown eventcode - %d\n",
		       eventcode);
		printk(KERN_INFO PREFIX "Unknown event_id - %d - 0x%x\n",
		       event_id, event_data);
		break;
	}
}