acer-wmi: add ACER_WMID_v2 interface flag to represent new notebooks
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>
This commit is contained in:
parent
6a0d89c264
commit
72e71de15f
|
@ -190,6 +190,7 @@ enum interface_flags {
|
|||
ACER_AMW0,
|
||||
ACER_AMW0_V2,
|
||||
ACER_WMID,
|
||||
ACER_WMID_v2,
|
||||
};
|
||||
|
||||
#define ACER_DEFAULT_WIRELESS 0
|
||||
|
@ -877,6 +878,177 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
|
|||
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;
|
||||
|
@ -922,17 +1094,11 @@ static acpi_status WMID_set_capabilities(void)
|
|||
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;
|
||||
|
@ -945,6 +1111,10 @@ static struct wmi_interface wmid_interface = {
|
|||
.type = ACER_WMID,
|
||||
};
|
||||
|
||||
static struct wmi_interface wmid_v2_interface = {
|
||||
.type = ACER_WMID_v2,
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic Device (interface-independent)
|
||||
*/
|
||||
|
@ -965,6 +1135,14 @@ static acpi_status get_u32(u32 *value, u32 cap)
|
|||
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;
|
||||
|
@ -998,6 +1176,13 @@ static acpi_status set_u32(u32 value, u32 cap)
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
@ -1104,186 +1289,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
|
||||
*/
|
||||
|
@ -1311,8 +1316,7 @@ static void acer_rfkill_update(struct work_struct *ignored)
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -1326,7 +1330,7 @@ static int acer_rfkill_set(void *data, bool blocked)
|
|||
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;
|
||||
}
|
||||
|
@ -1353,7 +1357,7 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
|
|||
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 device *dev,
|
|||
|
||||
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 device *dev, struct device_attribute *attr,
|
|||
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");
|
||||
|
|
Loading…
Reference in New Issue