[opensuse-kernel] [PATCH 3/3] acer-wmi: Detect communication hot key number
Git-commit: 34b6cfabd760d3a2784f0ae649eb5e390e0e53cc Patch-mainline: v3.4-rc1 References: bnc#745236 Release-target: openSUSE 12.1 Currently we set a fixed hot key number to 0x01 for communction button, but, actually, the key number is different on each acer laptop and it was reported by SMBIOS. So, add this patch to get the communication hot key number from Acer OEM-specific SMBIOS Type AA. Tested on Acer TravelMate 4750 Cc: Carlos Corbacho <carlos@strangeworlds.co.uk> Cc: Matthew Garrett <mjg@redhat.com> Cc: Dmitry Torokhov <dtor@mail.ru> Cc: Corentin Chary <corentincj@iksaif.net> Cc: Thomas Renninger <trenn@suse.de> Signed-off-by: Lee, Chun-Yi <jlee@suse.com> Signed-off-by: Matthew Garrett <mjg@redhat.com> --- drivers/platform/x86/acer-wmi.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -171,6 +171,11 @@ struct hotkey_function_type_aa { u8 length; u16 handle; u16 commun_func_bitmap; + u16 application_func_bitmap; + u16 media_func_bitmap; + u16 display_func_bitmap; + u16 others_func_bitmap; + u8 commun_fn_key_number; } __attribute__((packed)); /* @@ -207,6 +212,7 @@ static int force_series; static bool ec_raw_mode; static bool has_type_aa; static u16 commun_func_bitmap; +static u8 commun_fn_key_number; module_param(mailled, int, 0444); module_param(brightness, int, 0444); @@ -906,7 +912,7 @@ static acpi_status wmid3_get_device_stat union acpi_object *obj; struct wmid3_gds_input_param params = { .function_num = 0x1, - .hotkey_number = 0x01, + .hotkey_number = commun_fn_key_number, .devices = device, }; struct acpi_buffer input = { @@ -975,7 +981,7 @@ static acpi_status wmid3_set_device_stat u16 devices; struct wmid3_gds_input_param params = { .function_num = 0x1, - .hotkey_number = 0x01, + .hotkey_number = commun_fn_key_number, .devices = commun_func_bitmap, }; struct acpi_buffer input = { @@ -1015,7 +1021,7 @@ static acpi_status wmid3_set_device_stat devices = return_value.devices; params.function_num = 0x2; - params.hotkey_number = 0x01; + params.hotkey_number = commun_fn_key_number; params.devices = (value) ? (devices | device) : (devices & ~device); status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2); @@ -1088,6 +1094,8 @@ static void type_aa_dmi_decode(const str interface->capability |= ACER_CAP_THREEG; if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH) interface->capability |= ACER_CAP_BLUETOOTH; + + commun_fn_key_number = type_aa->commun_fn_key_number; } static acpi_status WMID_set_capabilities(void) -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
From: Lee, Chun-Yi <joeyli.kernel@gmail.com> Git-commit: 72e71de15fceb0fd7cdfd8bb35f4f8aa8b0e20b5 Patch-mainline: v3.2 References: bnc#745236 Release-target: openSUSE 12.1 There have new acer notebooks' BIOS provide new WMID_GUID3 and ACERWMID_EVENT_GUID methods. Some of machines still keep the old WMID_GUID1 method but more and more machines were already removed old wmi methods from DSDT. So, this patch add a new ACER_WMID_v2 interface flag to represent new acer notebooks, the following is definition: + ACER_WMID: It means this machine only provides WMID_GUID1/2 methods. + ACER_WMID_v2: It means this machine provide new WMID_GUID3 and WMID_EVENT_GUID methods. Some ACER_WMID_v2 machines also provide old WMID_GUID1/2 methods, but we still query/set communication device's state by new WMID_GUID3 method. Tested on Acer Travelmate 8572 Tested on Acer Aspire 4739Z Tested-by: AceLan Kao <acelan.kao@canonical.com> Cc: Carlos Corbacho <carlos@strangeworlds.co.uk> Cc: Matthew Garrett <mjg@redhat.com> Cc: Dmitry Torokhov <dtor@mail.ru> Cc: Corentin Chary <corentincj@iksaif.net> Cc: Thomas Renninger <trenn@suse.de> Signed-off-by: Lee, Chun-Yi <jlee@suse.com> Signed-off-by: Matthew Garrett <mjg@redhat.com> --- drivers/platform/x86/acer-wmi.c | 416 ++++++++++++++++++++-------------------- 1 file changed, 213 insertions(+), 203 deletions(-) --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -190,6 +190,7 @@ enum interface_flags { ACER_AMW0, ACER_AMW0_V2, ACER_WMID, + ACER_WMID_v2, }; #define ACER_DEFAULT_WIRELESS 0 @@ -897,6 +898,177 @@ static acpi_status WMID_set_u32(u32 valu return WMI_execute_u32(method_id, (u32)value, NULL); } +static acpi_status wmid3_get_device_status(u32 *value, u16 device) +{ + struct wmid3_gds_return_value return_value; + acpi_status status; + union acpi_object *obj; + struct wmid3_gds_input_param params = { + .function_num = 0x1, + .hotkey_number = 0x01, + .devices = device, + }; + struct acpi_buffer input = { + sizeof(struct wmid3_gds_input_param), + ¶ms + }; + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + + status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); + if (ACPI_FAILURE(status)) + return status; + + obj = output.pointer; + + if (!obj) + return AE_ERROR; + else if (obj->type != ACPI_TYPE_BUFFER) { + kfree(obj); + return AE_ERROR; + } + if (obj->buffer.length != 8) { + pr_warn("Unknown buffer length %d\n", obj->buffer.length); + kfree(obj); + return AE_ERROR; + } + + return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); + kfree(obj); + + if (return_value.error_code || return_value.ec_return_value) + pr_warn("Get 0x%x Device Status failed: 0x%x - 0x%x\n", + device, + return_value.error_code, + return_value.ec_return_value); + else + *value = !!(return_value.devices & device); + + return status; +} + +static acpi_status wmid_v2_get_u32(u32 *value, u32 cap) +{ + u16 device; + + switch (cap) { + case ACER_CAP_WIRELESS: + device = ACER_WMID3_GDS_WIRELESS; + break; + case ACER_CAP_BLUETOOTH: + device = ACER_WMID3_GDS_BLUETOOTH; + break; + case ACER_CAP_THREEG: + device = ACER_WMID3_GDS_THREEG; + break; + default: + return AE_ERROR; + } + return wmid3_get_device_status(value, device); +} + +static acpi_status wmid3_set_device_status(u32 value, u16 device) +{ + struct wmid3_gds_return_value return_value; + acpi_status status; + union acpi_object *obj; + u16 devices; + struct wmid3_gds_input_param params = { + .function_num = 0x1, + .hotkey_number = 0x01, + .devices = ACER_WMID3_GDS_WIRELESS | + ACER_WMID3_GDS_THREEG | + ACER_WMID3_GDS_WIMAX | + ACER_WMID3_GDS_BLUETOOTH, + }; + struct acpi_buffer input = { + sizeof(struct wmid3_gds_input_param), + ¶ms + }; + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL }; + + status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); + if (ACPI_FAILURE(status)) + return status; + + obj = output.pointer; + + if (!obj) + return AE_ERROR; + else if (obj->type != ACPI_TYPE_BUFFER) { + kfree(obj); + return AE_ERROR; + } + if (obj->buffer.length != 8) { + pr_warning("Unknown buffer length %d\n", obj->buffer.length); + kfree(obj); + return AE_ERROR; + } + + return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); + kfree(obj); + + if (return_value.error_code || return_value.ec_return_value) { + pr_warning("Get Current Device Status failed: " + "0x%x - 0x%x\n", return_value.error_code, + return_value.ec_return_value); + return status; + } + + devices = return_value.devices; + params.function_num = 0x2; + params.hotkey_number = 0x01; + params.devices = (value) ? (devices | device) : (devices & ~device); + + status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2); + if (ACPI_FAILURE(status)) + return status; + + obj = output2.pointer; + + if (!obj) + return AE_ERROR; + else if (obj->type != ACPI_TYPE_BUFFER) { + kfree(obj); + return AE_ERROR; + } + if (obj->buffer.length != 4) { + pr_warning("Unknown buffer length %d\n", obj->buffer.length); + kfree(obj); + return AE_ERROR; + } + + return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); + kfree(obj); + + if (return_value.error_code || return_value.ec_return_value) + pr_warning("Set Device Status failed: " + "0x%x - 0x%x\n", return_value.error_code, + return_value.ec_return_value); + + return status; +} + +static acpi_status wmid_v2_set_u32(u32 value, u32 cap) +{ + u16 device; + + switch (cap) { + case ACER_CAP_WIRELESS: + device = ACER_WMID3_GDS_WIRELESS; + break; + case ACER_CAP_BLUETOOTH: + device = ACER_WMID3_GDS_BLUETOOTH; + break; + case ACER_CAP_THREEG: + device = ACER_WMID3_GDS_THREEG; + break; + default: + return AE_ERROR; + } + return wmid3_set_device_status(value, device); +} + static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy) { struct hotkey_function_type_aa *type_aa; @@ -942,17 +1114,11 @@ static acpi_status WMID_set_capabilities return AE_ERROR; } - dmi_walk(type_aa_dmi_decode, NULL); - if (!has_type_aa) { - interface->capability |= ACER_CAP_WIRELESS; - if (devices & 0x40) - interface->capability |= ACER_CAP_THREEG; - if (devices & 0x10) - interface->capability |= ACER_CAP_BLUETOOTH; - } - - /* WMID always provides brightness methods */ - interface->capability |= ACER_CAP_BRIGHTNESS; + interface->capability |= ACER_CAP_WIRELESS; + if (devices & 0x40) + interface->capability |= ACER_CAP_THREEG; + if (devices & 0x10) + interface->capability |= ACER_CAP_BLUETOOTH; if (!(devices & 0x20)) max_brightness = 0x9; @@ -965,6 +1131,10 @@ static struct wmi_interface wmid_interfa .type = ACER_WMID, }; +static struct wmi_interface wmid_v2_interface = { + .type = ACER_WMID_v2, +}; + /* * Generic Device (interface-independent) */ @@ -985,6 +1155,14 @@ static acpi_status get_u32(u32 *value, u case ACER_WMID: status = WMID_get_u32(value, cap, interface); break; + case ACER_WMID_v2: + if (cap & (ACER_CAP_WIRELESS | + ACER_CAP_BLUETOOTH | + ACER_CAP_THREEG)) + status = wmid_v2_get_u32(value, cap); + else if (wmi_has_guid(WMID_GUID2)) + status = WMID_get_u32(value, cap, interface); + break; } return status; @@ -1018,6 +1196,13 @@ static acpi_status set_u32(u32 value, u3 } case ACER_WMID: return WMID_set_u32(value, cap, interface); + case ACER_WMID_v2: + if (cap & (ACER_CAP_WIRELESS | + ACER_CAP_BLUETOOTH | + ACER_CAP_THREEG)) + return wmid_v2_set_u32(value, cap); + else if (wmi_has_guid(WMID_GUID2)) + return WMID_set_u32(value, cap, interface); default: return AE_BAD_PARAMETER; } @@ -1124,186 +1309,6 @@ static void acer_backlight_exit(void) backlight_device_unregister(acer_backlight_device); } -static acpi_status wmid3_get_device_status(u32 *value, u16 device) -{ - struct wmid3_gds_return_value return_value; - acpi_status status; - union acpi_object *obj; - struct wmid3_gds_input_param params = { - .function_num = 0x1, - .hotkey_number = 0x01, - .devices = device, - }; - struct acpi_buffer input = { - sizeof(struct wmid3_gds_input_param), - ¶ms - }; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - - status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); - if (ACPI_FAILURE(status)) - return status; - - obj = output.pointer; - - if (!obj) - return AE_ERROR; - else if (obj->type != ACPI_TYPE_BUFFER) { - kfree(obj); - return AE_ERROR; - } - if (obj->buffer.length != 8) { - pr_warn("Unknown buffer length %d\n", obj->buffer.length); - kfree(obj); - return AE_ERROR; - } - - return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); - kfree(obj); - - if (return_value.error_code || return_value.ec_return_value) - pr_warn("Get Device Status failed: 0x%x - 0x%x\n", - return_value.error_code, - return_value.ec_return_value); - else - *value = !!(return_value.devices & device); - - return status; -} - -static acpi_status get_device_status(u32 *value, u32 cap) -{ - if (wmi_has_guid(WMID_GUID3)) { - u16 device; - - switch (cap) { - case ACER_CAP_WIRELESS: - device = ACER_WMID3_GDS_WIRELESS; - break; - case ACER_CAP_BLUETOOTH: - device = ACER_WMID3_GDS_BLUETOOTH; - break; - case ACER_CAP_THREEG: - device = ACER_WMID3_GDS_THREEG; - break; - default: - return AE_ERROR; - } - return wmid3_get_device_status(value, device); - - } else { - return get_u32(value, cap); - } -} - -static acpi_status wmid3_set_device_status(u32 value, u16 device) -{ - struct wmid3_gds_return_value return_value; - acpi_status status; - union acpi_object *obj; - u16 devices; - struct wmid3_gds_input_param params = { - .function_num = 0x1, - .hotkey_number = 0x01, - .devices = ACER_WMID3_GDS_WIRELESS | - ACER_WMID3_GDS_THREEG | - ACER_WMID3_GDS_WIMAX | - ACER_WMID3_GDS_BLUETOOTH, - }; - struct acpi_buffer input = { - sizeof(struct wmid3_gds_input_param), - ¶ms - }; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL }; - - status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); - if (ACPI_FAILURE(status)) - return status; - - obj = output.pointer; - - if (!obj) - return AE_ERROR; - else if (obj->type != ACPI_TYPE_BUFFER) { - kfree(obj); - return AE_ERROR; - } - if (obj->buffer.length != 8) { - pr_warning("Unknown buffer length %d\n", obj->buffer.length); - kfree(obj); - return AE_ERROR; - } - - return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); - kfree(obj); - - if (return_value.error_code || return_value.ec_return_value) { - pr_warning("Get Current Device Status failed: " - "0x%x - 0x%x\n", return_value.error_code, - return_value.ec_return_value); - return status; - } - - devices = return_value.devices; - params.function_num = 0x2; - params.hotkey_number = 0x01; - params.devices = (value) ? (devices | device) : (devices & ~device); - - status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2); - if (ACPI_FAILURE(status)) - return status; - - obj = output2.pointer; - - if (!obj) - return AE_ERROR; - else if (obj->type != ACPI_TYPE_BUFFER) { - kfree(obj); - return AE_ERROR; - } - if (obj->buffer.length != 4) { - pr_warning("Unknown buffer length %d\n", obj->buffer.length); - kfree(obj); - return AE_ERROR; - } - - return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); - kfree(obj); - - if (return_value.error_code || return_value.ec_return_value) - pr_warning("Set Device Status failed: " - "0x%x - 0x%x\n", return_value.error_code, - return_value.ec_return_value); - - return status; -} - -static acpi_status set_device_status(u32 value, u32 cap) -{ - if (wmi_has_guid(WMID_GUID3)) { - u16 device; - - switch (cap) { - case ACER_CAP_WIRELESS: - device = ACER_WMID3_GDS_WIRELESS; - break; - case ACER_CAP_BLUETOOTH: - device = ACER_WMID3_GDS_BLUETOOTH; - break; - case ACER_CAP_THREEG: - device = ACER_WMID3_GDS_THREEG; - break; - default: - return AE_ERROR; - } - return wmid3_set_device_status(value, device); - - } else { - return set_u32(value, cap); - } -} - /* * Rfkill devices */ @@ -1330,8 +1335,7 @@ static void acer_rfkill_update(struct wo } if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) { - status = wmid3_get_device_status(&state, - ACER_WMID3_GDS_THREEG); + status = get_u32(&state, ACER_WMID3_GDS_THREEG); if (ACPI_SUCCESS(status)) rfkill_set_sw_state(threeg_rfkill, !state); } @@ -1345,7 +1349,7 @@ static int acer_rfkill_set(void *data, b u32 cap = (unsigned long)data; if (rfkill_inited) { - status = set_device_status(!blocked, cap); + status = set_u32(!blocked, cap); if (ACPI_FAILURE(status)) return -ENODEV; } @@ -1372,7 +1376,7 @@ static struct rfkill *acer_rfkill_regist if (!rfkill_dev) return ERR_PTR(-ENOMEM); - status = get_device_status(&state, cap); + status = get_u32(&state, cap); err = rfkill_register(rfkill_dev); if (err) { @@ -1457,11 +1461,7 @@ static ssize_t show_bool_threeg(struct d pr_info("This threeg sysfs will be removed in 2012" " - used by: %s\n", current->comm); - if (wmi_has_guid(WMID_GUID3)) - status = wmid3_get_device_status(&result, - ACER_WMID3_GDS_THREEG); - else - status = get_u32(&result, ACER_CAP_THREEG); + status = get_u32(&result, ACER_CAP_THREEG); if (ACPI_SUCCESS(status)) return sprintf(buf, "%u\n", result); return sprintf(buf, "Read error\n"); @@ -1493,6 +1493,8 @@ static ssize_t show_interface(struct dev return sprintf(buf, "AMW0 v2\n"); case ACER_WMID: return sprintf(buf, "WMID\n"); + case ACER_WMID_v2: + return sprintf(buf, "WMID v2\n"); default: return sprintf(buf, "Error!\n"); } @@ -1912,12 +1914,20 @@ static int __init acer_wmi_init(void) if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) interface = &wmid_interface; + if (wmi_has_guid(WMID_GUID3)) + interface = &wmid_v2_interface; + + if (interface) + dmi_walk(type_aa_dmi_decode, NULL); + if (wmi_has_guid(WMID_GUID2) && interface) { - if (ACPI_FAILURE(WMID_set_capabilities())) { + if (!has_type_aa && ACPI_FAILURE(WMID_set_capabilities())) { pr_err("Unable to detect available WMID devices\n"); return -ENODEV; } - } else if (!wmi_has_guid(WMID_GUID2) && interface) { + /* WMID always provides brightness methods */ + interface->capability |= ACER_CAP_BRIGHTNESS; + } else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa) { pr_err("No WMID device detection method found\n"); return -ENODEV; } @@ -1941,7 +1951,7 @@ static int __init acer_wmi_init(void) set_quirks(); - if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { + if (acpi_video_backlight_support()) { interface->capability &= ~ACER_CAP_BRIGHTNESS; pr_info("Brightness must be controlled by " "generic video driver\n"); -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
From: Lee, Chun-Yi <joeyli.kernel@gmail.com> Git-commit: 1d1fc8a75fec3a2b29cc5864d45c5d03048f62e0 Patch-mainline: v3.2 References: bnc#745236 Release-target: openSUSE 12.1 Before set communication devices state, we need query out all devices state to set the states bitmap. That will be better use the devices bitmap in SMBIOS type Aah instead of hardcode in driver. Tested on Acer Travelmate 8572. Cc: Carlos Corbacho <carlos@strangeworlds.co.uk> Cc: Matthew Garrett <mjg@redhat.com> Cc: Dmitry Torokhov <dtor@mail.ru> Cc: Corentin Chary <corentincj@iksaif.net> Cc: Thomas Renninger <trenn@suse.de> Signed-off-by: Lee, Chun-Yi <jlee@suse.com> Signed-off-by: Matthew Garrett <mjg@redhat.com> --- drivers/platform/x86/acer-wmi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -206,6 +206,7 @@ static int threeg = -1; static int force_series; static bool ec_raw_mode; static bool has_type_aa; +static u16 commun_func_bitmap; module_param(mailled, int, 0444); module_param(brightness, int, 0444); @@ -975,10 +976,7 @@ static acpi_status wmid3_set_device_stat struct wmid3_gds_input_param params = { .function_num = 0x1, .hotkey_number = 0x01, - .devices = ACER_WMID3_GDS_WIRELESS | - ACER_WMID3_GDS_THREEG | - ACER_WMID3_GDS_WIMAX | - ACER_WMID3_GDS_BLUETOOTH, + .devices = commun_func_bitmap, }; struct acpi_buffer input = { sizeof(struct wmid3_gds_input_param), @@ -1082,6 +1080,7 @@ static void type_aa_dmi_decode(const str pr_info("Function bitmap for Communication Button: 0x%x\n", type_aa->commun_func_bitmap); + commun_func_bitmap = type_aa->commun_func_bitmap; if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS) interface->capability |= ACER_CAP_WIRELESS; -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
participants (1)
-
Lee, Chun-Yi