From 63a78bb1051b240417daad3a3fa9c1bb10646dca Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 20 Jun 2012 11:47:35 +0800 Subject: asus-wmi: use ASUS_WMI_METHODID_DSTS2 as default DSTS ID. According to responses from the BIOS team, ASUS_WMI_METHODID_DSTS2 (0x53545344) will be used as future DSTS ID. In addition, calling asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL) returns ASUS_WMI_UNSUPPORTED_METHOD in new ASUS laptop PCs. This patch fixes no DSTS ID will be assigned in this case. Signed-off-by: Alex Hung Signed-off-by: Matthew Garrett Cc: stable@kernel.org --- drivers/platform/x86/asus-wmi.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 77aadde5281c..556cbb455ed2 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1467,14 +1467,9 @@ static int asus_wmi_platform_init(struct asus_wmi *asus) */ if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL)) asus->dsts_id = ASUS_WMI_METHODID_DSTS; - else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL)) + else asus->dsts_id = ASUS_WMI_METHODID_DSTS2; - if (!asus->dsts_id) { - pr_err("Can't find DSTS"); - return -ENODEV; - } - /* CWAP allow to define the behavior of the Fn+F2 key, * this method doesn't seems to be present on Eee PCs */ if (asus->driver->quirks->wapf >= 0) -- cgit v1.2.3 From 1eb3fe1d3b6b9bf6045eb12f0c3ac12569169870 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 1 Jun 2012 19:11:22 +0200 Subject: ACER: Add support for accelerometer sensor This device is present on Iconia Tab W500. Signed-off-by: Marek Vasut Cc: joeyli Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 138 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c8f40c9c0428..175809dd5587 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -95,6 +95,7 @@ MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); enum acer_wmi_event_ids { WMID_HOTKEY_EVENT = 0x1, + WMID_ACCEL_EVENT = 0x5, }; static const struct key_entry acer_wmi_keymap[] = { @@ -130,6 +131,7 @@ static const struct key_entry acer_wmi_keymap[] = { }; static struct input_dev *acer_wmi_input_dev; +static struct input_dev *acer_wmi_accel_dev; struct event_return_value { u8 function; @@ -200,6 +202,7 @@ struct hotkey_function_type_aa { #define ACER_CAP_BLUETOOTH (1<<2) #define ACER_CAP_BRIGHTNESS (1<<3) #define ACER_CAP_THREEG (1<<4) +#define ACER_CAP_ACCEL (1<<5) #define ACER_CAP_ANY (0xFFFFFFFF) /* @@ -1398,6 +1401,60 @@ static void acer_backlight_exit(void) backlight_device_unregister(acer_backlight_device); } +/* + * Accelerometer device + */ +static acpi_handle gsensor_handle; + +static int acer_gsensor_init(void) +{ + acpi_status status; + struct acpi_buffer output; + union acpi_object out_obj; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + status = acpi_evaluate_object(gsensor_handle, "_INI", NULL, &output); + if (ACPI_FAILURE(status)) + return -1; + + return 0; +} + +static int acer_gsensor_open(struct input_dev *input) +{ + return acer_gsensor_init(); +} + +static int acer_gsensor_event(void) +{ + acpi_status status; + struct acpi_buffer output; + union acpi_object out_obj[5]; + + if (!has_cap(ACER_CAP_ACCEL)) + return -1; + + output.length = sizeof(out_obj); + output.pointer = out_obj; + + status = acpi_evaluate_object(gsensor_handle, "RDVL", NULL, &output); + if (ACPI_FAILURE(status)) + return -1; + + if (out_obj->package.count != 4) + return -1; + + input_report_abs(acer_wmi_accel_dev, ABS_X, + (s16)out_obj->package.elements[0].integer.value); + input_report_abs(acer_wmi_accel_dev, ABS_Y, + (s16)out_obj->package.elements[1].integer.value); + input_report_abs(acer_wmi_accel_dev, ABS_Z, + (s16)out_obj->package.elements[2].integer.value); + input_sync(acer_wmi_accel_dev); + return 0; +} + /* * Rfkill devices */ @@ -1673,6 +1730,9 @@ static void acer_wmi_notify(u32 value, void *context) 1, true); } break; + case WMID_ACCEL_EVENT: + acer_gsensor_event(); + break; default: pr_warn("Unknown function number - %d - %d\n", return_value.function, return_value.key_num); @@ -1758,6 +1818,74 @@ static int acer_wmi_enable_lm(void) return status; } +static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level, + void *ctx, void **retval) +{ + *(acpi_handle *)retval = ah; + return AE_OK; +} + +static int __init acer_wmi_get_handle(const char *name, const char *prop, + acpi_handle *ah) +{ + acpi_status status; + acpi_handle handle; + + BUG_ON(!name || !ah); + + handle = 0; + status = acpi_get_devices(prop, acer_wmi_get_handle_cb, + (void *)name, &handle); + + if (ACPI_SUCCESS(status)) { + *ah = handle; + return 0; + } else { + return -ENODEV; + } +} + +static int __init acer_wmi_accel_setup(void) +{ + int err; + + err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle); + if (err) + return err; + + interface->capability |= ACER_CAP_ACCEL; + + acer_wmi_accel_dev = input_allocate_device(); + if (!acer_wmi_accel_dev) + return -ENOMEM; + + acer_wmi_accel_dev->open = acer_gsensor_open; + + acer_wmi_accel_dev->name = "Acer BMA150 accelerometer"; + acer_wmi_accel_dev->phys = "wmi/input1"; + acer_wmi_accel_dev->id.bustype = BUS_HOST; + acer_wmi_accel_dev->evbit[0] = BIT_MASK(EV_ABS); + input_set_abs_params(acer_wmi_accel_dev, ABS_X, -16384, 16384, 0, 0); + input_set_abs_params(acer_wmi_accel_dev, ABS_Y, -16384, 16384, 0, 0); + input_set_abs_params(acer_wmi_accel_dev, ABS_Z, -16384, 16384, 0, 0); + + err = input_register_device(acer_wmi_accel_dev); + if (err) + goto err_free_dev; + + return 0; + +err_free_dev: + input_free_device(acer_wmi_accel_dev); + return err; +} + +static void acer_wmi_accel_destroy(void) +{ + input_unregister_device(acer_wmi_accel_dev); + input_free_device(acer_wmi_accel_dev); +} + static int __init acer_wmi_input_setup(void) { acpi_status status; @@ -1912,6 +2040,9 @@ static int acer_resume(struct device *dev) if (has_cap(ACER_CAP_BRIGHTNESS)) set_u32(data->brightness, ACER_CAP_BRIGHTNESS); + if (has_cap(ACER_CAP_ACCEL)) + acer_gsensor_init(); + return 0; } @@ -2090,6 +2221,8 @@ static int __init acer_wmi_init(void) return err; } + acer_wmi_accel_setup(); + err = platform_driver_register(&acer_platform_driver); if (err) { pr_err("Unable to register platform driver\n"); @@ -2133,6 +2266,8 @@ error_device_alloc: error_platform_register: if (wmi_has_guid(ACERWMID_EVENT_GUID)) acer_wmi_input_destroy(); + if (has_cap(ACER_CAP_ACCEL)) + acer_wmi_accel_destroy(); return err; } @@ -2142,6 +2277,9 @@ static void __exit acer_wmi_exit(void) if (wmi_has_guid(ACERWMID_EVENT_GUID)) acer_wmi_input_destroy(); + if (has_cap(ACER_CAP_ACCEL)) + acer_wmi_accel_destroy(); + remove_sysfs(acer_platform_device); remove_debugfs(); platform_device_unregister(acer_platform_device); -- cgit v1.2.3 From f838eb5bd257e8a666aa8c451058fa198df7e299 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 13 Jun 2012 09:32:01 +0200 Subject: acpi: add a way to promote/demote vendor backlight drivers Instead of adding a big blacklist in video_detect.c to set ACPI_VIDEO_BACKLIGHT_DMI_VENDOR correctly, let external modules promote or demote themselves when they know the generic video module won't work. Currently drivers where using acpi_video_unregister() directly but: - That didn't respect any acpi_backlight=[video|vendor] parameter provided by the user. - Any later call to acpi_video_register() would still re-load the generic video module (and some gpu drivers are doing that). This patch fix those two issues. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/acpi/video_detect.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 45d8097ef4cf..942fa2a998f7 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -182,8 +182,7 @@ long acpi_video_get_capabilities(acpi_handle graphics_handle) } EXPORT_SYMBOL(acpi_video_get_capabilities); -/* Returns true if video.ko can do backlight switching */ -int acpi_video_backlight_support(void) +static void acpi_video_caps_check(void) { /* * We must check whether the ACPI graphics device is physically plugged @@ -191,6 +190,34 @@ int acpi_video_backlight_support(void) */ if (!acpi_video_caps_checked) acpi_video_get_capabilities(NULL); +} + +/* Promote the vendor interface instead of the generic video module. + * This function allow DMI blacklists to be implemented by externals + * platform drivers instead of putting a big blacklist in video_detect.c + * After calling this function you will probably want to call + * acpi_video_unregister() to make sure the video module is not loaded + */ +void acpi_video_dmi_promote_vendor(void) +{ + acpi_video_caps_check(); + acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; +} +EXPORT_SYMBOL(acpi_video_dmi_promote_vendor); + +/* To be called when a driver who previously promoted the vendor + * interface */ +void acpi_video_dmi_demote_vendor(void) +{ + acpi_video_caps_check(); + acpi_video_support &= ~ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; +} +EXPORT_SYMBOL(acpi_video_dmi_demote_vendor); + +/* Returns true if video.ko can do backlight switching */ +int acpi_video_backlight_support(void) +{ + acpi_video_caps_check(); /* First check for boot param -> highest prio */ if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR) -- cgit v1.2.3 From a60b21763cce01c64cc537869662b41429c62e5f Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 13 Jun 2012 09:32:02 +0200 Subject: drivers-platform-x86: use acpi_video_dmi_promote_vendor() Instead of using directly acpi_video_unregister(), use acpi_video_dmi_promote_vendor() (and make it call acpi_video_unregister() if needed) Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 16 +++++++++------- drivers/platform/x86/apple-gmux.c | 6 ++++++ drivers/platform/x86/samsung-laptop.c | 22 ++++++++++++---------- 3 files changed, 27 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 175809dd5587..377d92d8d9b1 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -2191,14 +2191,16 @@ static int __init acer_wmi_init(void) set_quirks(); + if (dmi_check_system(video_vendor_dmi_table)) + acpi_video_dmi_promote_vendor(); if (acpi_video_backlight_support()) { - if (dmi_check_system(video_vendor_dmi_table)) { - acpi_video_unregister(); - } else { - interface->capability &= ~ACER_CAP_BRIGHTNESS; - pr_info("Brightness must be controlled by " - "acpi video driver\n"); - } + interface->capability &= ~ACER_CAP_BRIGHTNESS; + pr_info("Brightness must be controlled by acpi video driver\n"); + } else { +#ifdef CONFIG_ACPI_VIDEO + pr_info("Disabling ACPI video driver\n"); + acpi_video_unregister(); +#endif } if (wmi_has_guid(WMID_GUID3)) { diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index 694a15a56230..905fa01ac8df 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -193,7 +193,10 @@ static int __devinit gmux_probe(struct pnp_dev *pnp, * backlight control and supports more levels than other options. * Disable the other backlight choices. */ + acpi_video_dmi_promote_vendor(); +#ifdef CONFIG_ACPI_VIDEO acpi_video_unregister(); +#endif apple_bl_unregister(); return 0; @@ -213,7 +216,10 @@ static void __devexit gmux_remove(struct pnp_dev *pnp) release_region(gmux_data->iostart, gmux_data->iolen); kfree(gmux_data); + acpi_video_dmi_demote_vendor(); +#ifdef CONFIG_ACPI_VIDEO acpi_video_register(); +#endif apple_bl_register(); } diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index e2a34b42ddc1..2cbccc1b4b68 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -26,7 +26,7 @@ #include #include #include -#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE) +#ifdef CONFIG_ACPI_VIDEO #include #endif @@ -1530,15 +1530,18 @@ static int __init samsung_init(void) samsung->quirks = quirks; -#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE) +#ifdef CONFIG_ACPI + if (samsung->quirks->broken_acpi_video) + acpi_video_dmi_promote_vendor(); + /* Don't handle backlight here if the acpi video already handle it */ if (acpi_video_backlight_support()) { - if (samsung->quirks->broken_acpi_video) { - pr_info("Disabling ACPI video driver\n"); - acpi_video_unregister(); - } else { - samsung->handle_backlight = false; - } + samsung->handle_backlight = false; + } else if (samsung->quirks->broken_acpi_video) { + pr_info("Disabling ACPI video driver\n"); +#ifdef CONFIG_ACPI_VIDEO + acpi_video_unregister(); +#endif } #endif @@ -1552,8 +1555,7 @@ static int __init samsung_init(void) #ifdef CONFIG_ACPI /* Only log that if we are really on a sabi platform */ - if (acpi_video_backlight_support() && - !samsung->quirks->broken_acpi_video) + if (acpi_video_backlight_support()) pr_info("Backlight controlled by ACPI video driver\n"); #endif -- cgit v1.2.3 From 09d5677cf18f1b9f0e092eb83e9ba6a771c15c5c Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 13 Jun 2012 09:32:03 +0200 Subject: samsung-laptop: X360 ACPI backlight device is broken Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 2cbccc1b4b68..98f07588ac86 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -1506,6 +1506,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { }, .driver_data = &samsung_broken_acpi_video, }, + { + .callback = samsung_dmi_matched, + .ident = "X360", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "X360"), + DMI_MATCH(DMI_BOARD_NAME, "X360"), + }, + .driver_data = &samsung_broken_acpi_video, + }, { }, }; MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); -- cgit v1.2.3 From 084940d5b101e9ca91a689eb5048151b14076839 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 13 Jun 2012 09:32:04 +0200 Subject: acpi/video_detect: blacklist samsung x360 On Samsung X360, the BIOS will set a flag (VDRV) if the generic ACPI backlight device is used. This flag will definitively break the backlight interface (even the vendor interface) untill next reboot. It's why we should prevent video.ko from being used here and we can't rely on a later call to acpi_video_unregister(). Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/acpi/video_detect.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 942fa2a998f7..b728880ef10e 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -132,6 +132,33 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; } +/* Force to use vendor driver when the ACPI device is known to be + * buggy */ +static int video_detect_force_vendor(const struct dmi_system_id *d) +{ + acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; + return 0; +} + +static struct dmi_system_id video_detect_dmi_table[] = { + /* On Samsung X360, the BIOS will set a flag (VDRV) if generic + * ACPI backlight device is used. This flag will definitively break + * the backlight interface (even the vendor interface) untill next + * reboot. It's why we should prevent video.ko from being used here + * and we can't rely on a later call to acpi_video_unregister(). + */ + { + .callback = video_detect_force_vendor, + .ident = "X360", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "X360"), + DMI_MATCH(DMI_BOARD_NAME, "X360"), + }, + }, + { }, +}; + /* * Returns the video capabilities of a specific ACPI graphics device * @@ -164,6 +191,8 @@ long acpi_video_get_capabilities(acpi_handle graphics_handle) * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR; *} */ + + dmi_check_system(video_detect_dmi_table); } else { status = acpi_bus_get_device(graphics_handle, &tmp_dev); if (ACPI_FAILURE(status)) { -- cgit v1.2.3 From e052067df00592b1b62d1d438191b931f2009cbb Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 13 Jun 2012 09:32:05 +0200 Subject: samsung-laptop: support R40/R41 > Chassis Information > Manufacturer: SAMSUNG ELECTRONICS CO., LTD. > Type: Other Type should be "Notebook", "Laptop", .. not "Other". Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 98f07588ac86..c1ca7bcebb66 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -1465,6 +1465,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */ }, }, + /* DMI ids for laptops with bad Chassis Type */ + { + .ident = "R40/R41", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "R40/R41"), + DMI_MATCH(DMI_BOARD_NAME, "R40/R41"), + }, + }, /* Specific DMI ids for laptop with quirks */ { .callback = samsung_dmi_matched, -- cgit v1.2.3 From 272c77d55672ef92eda9d5e24a5a7ac62df9c431 Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Wed, 13 Jun 2012 09:32:06 +0200 Subject: asus-wmi: control backlight power through WMI, not ACPI BugLink: https://bugs.launchpad.net/bugs/1000146 Some h/w that can adjust screen brightness through ACPI functions, but can't turn on/off the backlight power correctly. So, we list those h/w in quirks and try to turn on/off the backlight power through WMI. Signed-off-by: AceLan Kao Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 9 +++++++++ drivers/platform/x86/asus-wmi.h | 1 + drivers/platform/x86/eeepc-wmi.c | 25 ++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 556cbb455ed2..486f836b79df 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -47,6 +47,9 @@ #include #include #include +#ifdef CONFIG_ACPI_VIDEO +#include +#endif #include "asus-wmi.h" @@ -1676,7 +1679,13 @@ static int asus_wmi_add(struct platform_device *pdev) if (err) goto fail_rfkill; + if (asus->driver->quirks->wmi_backlight_power) + acpi_video_dmi_promote_vendor(); if (!acpi_video_backlight_support()) { +#ifdef CONFIG_ACPI_VIDEO + pr_info("Disabling ACPI video driver\n"); + acpi_video_unregister(); +#endif err = asus_wmi_backlight_init(asus); if (err && err != -ENODEV) goto fail_backlight; diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index d43b66742004..9c1da8b81bea 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -39,6 +39,7 @@ struct quirk_entry { bool hotplug_wireless; bool scalar_panel_brightness; bool store_backlight_power; + bool wmi_backlight_power; int wapf; }; diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 656761380342..5838332ea5bd 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -79,7 +79,7 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ { KE_KEY, HOME_PRESS, { KEY_CONFIG } }, /* Home/Express gate key */ { KE_KEY, 0xe8, { KEY_SCREENLOCK } }, - { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, + { KE_KEY, 0xe9, { KEY_DISPLAYTOGGLE } }, { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, { KE_KEY, 0xec, { KEY_CAMERA_UP } }, { KE_KEY, 0xed, { KEY_CAMERA_DOWN } }, @@ -107,6 +107,11 @@ static struct quirk_entry quirk_asus_et2012_type3 = { .store_backlight_power = true, }; +static struct quirk_entry quirk_asus_x101ch = { + /* We need this when ACPI function doesn't do this well */ + .wmi_backlight_power = true, +}; + static struct quirk_entry *quirks; static void et2012_quirks(void) @@ -157,6 +162,24 @@ static struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_unknown, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK Computer INC. X101CH", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"), + }, + .driver_data = &quirk_asus_x101ch, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK Computer INC. 1015CX", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"), + }, + .driver_data = &quirk_asus_x101ch, + }, {}, }; -- cgit v1.2.3 From c0b91b6d5226247fa4fe894eb592bcc56bc7e9fd Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Wed, 13 Jun 2012 09:32:07 +0200 Subject: asus-wmi: enable resume on lid open According to the ASUS WMI spec., to enable resume on lid open should use the device ID(0x00120032), but it doesn't work indeed. After discussing with ASUS' BIOS engineer, they say wake on lid open doesn't have a uniq device ID(0x00120032) in the BIOS. It shares the same device ID with deep S3(0x00120031), and the deep S3(resume on lid open) is disable by default. Adding this option in asus wmi sysfs /sys/devices/platform//lid_resume so that userspace apps can enable/disable this feature by themselves. Signed-off-by: AceLan Kao Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 486f836b79df..c7a36f6b0580 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -139,6 +139,9 @@ MODULE_LICENSE("GPL"); /* Power */ #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012 +/* Deep S3 / Resume on LID open */ +#define ASUS_WMI_DEVID_LID_RESUME 0x00120031 + /* DSTS masks */ #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002 @@ -1368,6 +1371,7 @@ static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf) ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD); ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA); ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER); +ASUS_WMI_CREATE_DEVICE_ATTR(lid_resume, 0644, ASUS_WMI_DEVID_LID_RESUME); static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1393,6 +1397,7 @@ static struct attribute *platform_attributes[] = { &dev_attr_camera.attr, &dev_attr_cardr.attr, &dev_attr_touchpad.attr, + &dev_attr_lid_resume.attr, NULL }; @@ -1411,6 +1416,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, devid = ASUS_WMI_DEVID_CARDREADER; else if (attr == &dev_attr_touchpad.attr) devid = ASUS_WMI_DEVID_TOUCHPAD; + else if (attr == &dev_attr_lid_resume.attr) + devid = ASUS_WMI_DEVID_LID_RESUME; if (devid != -1) ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); -- cgit v1.2.3 From 7125587df4e87224dbd3b90ddf6f23e83044ae30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20G=C3=B3mez?= Date: Fri, 29 Jun 2012 15:39:48 +0200 Subject: classmate-laptop: Add support for Classmate V4 accelerometer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Classmate V4 laptop includes a new accelerometer that can't be handled by previous driver. This patch adds a new driver to handle it. [mjg: Fixed up the driver pm stuff] Signed-off-by: Miguel Gómez Signed-off-by: Matthew Garrett --- drivers/platform/x86/classmate-laptop.c | 403 +++++++++++++++++++++++++++++++- 1 file changed, 401 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index e2230a2b2f8e..33f4d2c72c03 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -31,12 +31,18 @@ MODULE_LICENSE("GPL"); struct cmpc_accel { int sensitivity; + int g_select; + int inputdev_state; }; -#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5 +#define CMPC_ACCEL_DEV_STATE_CLOSED 0 +#define CMPC_ACCEL_DEV_STATE_OPEN 1 +#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5 +#define CMPC_ACCEL_G_SELECT_DEFAULT 0 #define CMPC_ACCEL_HID "ACCE0000" +#define CMPC_ACCEL_HID_V4 "ACCE0001" #define CMPC_TABLET_HID "TBLT0000" #define CMPC_IPML_HID "IPML200" #define CMPC_KEYS_HID "FnBT0000" @@ -76,7 +82,391 @@ static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi) } /* - * Accelerometer code. + * Accelerometer code for Classmate V4 + */ +static acpi_status cmpc_start_accel_v4(acpi_handle handle) +{ + union acpi_object param[4]; + struct acpi_object_list input; + acpi_status status; + + param[0].type = ACPI_TYPE_INTEGER; + param[0].integer.value = 0x3; + param[1].type = ACPI_TYPE_INTEGER; + param[1].integer.value = 0; + param[2].type = ACPI_TYPE_INTEGER; + param[2].integer.value = 0; + param[3].type = ACPI_TYPE_INTEGER; + param[3].integer.value = 0; + input.count = 4; + input.pointer = param; + status = acpi_evaluate_object(handle, "ACMD", &input, NULL); + return status; +} + +static acpi_status cmpc_stop_accel_v4(acpi_handle handle) +{ + union acpi_object param[4]; + struct acpi_object_list input; + acpi_status status; + + param[0].type = ACPI_TYPE_INTEGER; + param[0].integer.value = 0x4; + param[1].type = ACPI_TYPE_INTEGER; + param[1].integer.value = 0; + param[2].type = ACPI_TYPE_INTEGER; + param[2].integer.value = 0; + param[3].type = ACPI_TYPE_INTEGER; + param[3].integer.value = 0; + input.count = 4; + input.pointer = param; + status = acpi_evaluate_object(handle, "ACMD", &input, NULL); + return status; +} + +static acpi_status cmpc_accel_set_sensitivity_v4(acpi_handle handle, int val) +{ + union acpi_object param[4]; + struct acpi_object_list input; + + param[0].type = ACPI_TYPE_INTEGER; + param[0].integer.value = 0x02; + param[1].type = ACPI_TYPE_INTEGER; + param[1].integer.value = val; + param[2].type = ACPI_TYPE_INTEGER; + param[2].integer.value = 0; + param[3].type = ACPI_TYPE_INTEGER; + param[3].integer.value = 0; + input.count = 4; + input.pointer = param; + return acpi_evaluate_object(handle, "ACMD", &input, NULL); +} + +static acpi_status cmpc_accel_set_g_select_v4(acpi_handle handle, int val) +{ + union acpi_object param[4]; + struct acpi_object_list input; + + param[0].type = ACPI_TYPE_INTEGER; + param[0].integer.value = 0x05; + param[1].type = ACPI_TYPE_INTEGER; + param[1].integer.value = val; + param[2].type = ACPI_TYPE_INTEGER; + param[2].integer.value = 0; + param[3].type = ACPI_TYPE_INTEGER; + param[3].integer.value = 0; + input.count = 4; + input.pointer = param; + return acpi_evaluate_object(handle, "ACMD", &input, NULL); +} + +static acpi_status cmpc_get_accel_v4(acpi_handle handle, + int16_t *x, + int16_t *y, + int16_t *z) +{ + union acpi_object param[4]; + struct acpi_object_list input; + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + int16_t *locs; + acpi_status status; + + param[0].type = ACPI_TYPE_INTEGER; + param[0].integer.value = 0x01; + param[1].type = ACPI_TYPE_INTEGER; + param[1].integer.value = 0; + param[2].type = ACPI_TYPE_INTEGER; + param[2].integer.value = 0; + param[3].type = ACPI_TYPE_INTEGER; + param[3].integer.value = 0; + input.count = 4; + input.pointer = param; + status = acpi_evaluate_object(handle, "ACMD", &input, &output); + if (ACPI_SUCCESS(status)) { + union acpi_object *obj; + obj = output.pointer; + locs = (int16_t *) obj->buffer.pointer; + *x = locs[0]; + *y = locs[1]; + *z = locs[2]; + kfree(output.pointer); + } + return status; +} + +static void cmpc_accel_handler_v4(struct acpi_device *dev, u32 event) +{ + if (event == 0x81) { + int16_t x, y, z; + acpi_status status; + + status = cmpc_get_accel_v4(dev->handle, &x, &y, &z); + if (ACPI_SUCCESS(status)) { + struct input_dev *inputdev = dev_get_drvdata(&dev->dev); + + input_report_abs(inputdev, ABS_X, x); + input_report_abs(inputdev, ABS_Y, y); + input_report_abs(inputdev, ABS_Z, z); + input_sync(inputdev); + } + } +} + +static ssize_t cmpc_accel_sensitivity_show_v4(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi; + struct input_dev *inputdev; + struct cmpc_accel *accel; + + acpi = to_acpi_device(dev); + inputdev = dev_get_drvdata(&acpi->dev); + accel = dev_get_drvdata(&inputdev->dev); + + return sprintf(buf, "%d\n", accel->sensitivity); +} + +static ssize_t cmpc_accel_sensitivity_store_v4(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_device *acpi; + struct input_dev *inputdev; + struct cmpc_accel *accel; + unsigned long sensitivity; + int r; + + acpi = to_acpi_device(dev); + inputdev = dev_get_drvdata(&acpi->dev); + accel = dev_get_drvdata(&inputdev->dev); + + r = kstrtoul(buf, 0, &sensitivity); + if (r) + return r; + + /* sensitivity must be between 1 and 127 */ + if (sensitivity < 1 || sensitivity > 127) + return -EINVAL; + + accel->sensitivity = sensitivity; + cmpc_accel_set_sensitivity_v4(acpi->handle, sensitivity); + + return strnlen(buf, count); +} + +static struct device_attribute cmpc_accel_sensitivity_attr_v4 = { + .attr = { .name = "sensitivity", .mode = 0660 }, + .show = cmpc_accel_sensitivity_show_v4, + .store = cmpc_accel_sensitivity_store_v4 +}; + +static ssize_t cmpc_accel_g_select_show_v4(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi; + struct input_dev *inputdev; + struct cmpc_accel *accel; + + acpi = to_acpi_device(dev); + inputdev = dev_get_drvdata(&acpi->dev); + accel = dev_get_drvdata(&inputdev->dev); + + return sprintf(buf, "%d\n", accel->g_select); +} + +static ssize_t cmpc_accel_g_select_store_v4(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_device *acpi; + struct input_dev *inputdev; + struct cmpc_accel *accel; + unsigned long g_select; + int r; + + acpi = to_acpi_device(dev); + inputdev = dev_get_drvdata(&acpi->dev); + accel = dev_get_drvdata(&inputdev->dev); + + r = kstrtoul(buf, 0, &g_select); + if (r) + return r; + + /* 0 means 1.5g, 1 means 6g, everything else is wrong */ + if (g_select != 0 && g_select != 1) + return -EINVAL; + + accel->g_select = g_select; + cmpc_accel_set_g_select_v4(acpi->handle, g_select); + + return strnlen(buf, count); +} + +static struct device_attribute cmpc_accel_g_select_attr_v4 = { + .attr = { .name = "g_select", .mode = 0660 }, + .show = cmpc_accel_g_select_show_v4, + .store = cmpc_accel_g_select_store_v4 +}; + +static int cmpc_accel_open_v4(struct input_dev *input) +{ + struct acpi_device *acpi; + struct cmpc_accel *accel; + + acpi = to_acpi_device(input->dev.parent); + accel = dev_get_drvdata(&input->dev); + + cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity); + cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select); + + if (ACPI_SUCCESS(cmpc_start_accel_v4(acpi->handle))) { + accel->inputdev_state = CMPC_ACCEL_DEV_STATE_OPEN; + return 0; + } + return -EIO; +} + +static void cmpc_accel_close_v4(struct input_dev *input) +{ + struct acpi_device *acpi; + struct cmpc_accel *accel; + + acpi = to_acpi_device(input->dev.parent); + accel = dev_get_drvdata(&input->dev); + + cmpc_stop_accel_v4(acpi->handle); + accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED; +} + +static void cmpc_accel_idev_init_v4(struct input_dev *inputdev) +{ + set_bit(EV_ABS, inputdev->evbit); + input_set_abs_params(inputdev, ABS_X, -255, 255, 16, 0); + input_set_abs_params(inputdev, ABS_Y, -255, 255, 16, 0); + input_set_abs_params(inputdev, ABS_Z, -255, 255, 16, 0); + inputdev->open = cmpc_accel_open_v4; + inputdev->close = cmpc_accel_close_v4; +} + +static int cmpc_accel_suspend_v4(struct device *dev) +{ + struct input_dev *inputdev; + struct cmpc_accel *accel; + + inputdev = dev_get_drvdata(dev); + accel = dev_get_drvdata(&inputdev->dev); + + if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) + return cmpc_stop_accel_v4(to_acpi_device(dev)->handle); + + return 0; +} + +static int cmpc_accel_resume_v4(struct device *dev) +{ + struct input_dev *inputdev; + struct cmpc_accel *accel; + + inputdev = dev_get_drvdata(dev); + accel = dev_get_drvdata(&inputdev->dev); + + if (accel->inputdev_state == CMPC_ACCEL_DEV_STATE_OPEN) { + cmpc_accel_set_sensitivity_v4(to_acpi_device(dev)->handle, + accel->sensitivity); + cmpc_accel_set_g_select_v4(to_acpi_device(dev)->handle, + accel->g_select); + + if (ACPI_FAILURE(cmpc_start_accel_v4(to_acpi_device(dev)->handle))) + return -EIO; + } + + return 0; +} + +static int cmpc_accel_add_v4(struct acpi_device *acpi) +{ + int error; + struct input_dev *inputdev; + struct cmpc_accel *accel; + + accel = kmalloc(sizeof(*accel), GFP_KERNEL); + if (!accel) + return -ENOMEM; + + accel->inputdev_state = CMPC_ACCEL_DEV_STATE_CLOSED; + + accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT; + cmpc_accel_set_sensitivity_v4(acpi->handle, accel->sensitivity); + + error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4); + if (error) + goto failed_sensitivity; + + accel->g_select = CMPC_ACCEL_G_SELECT_DEFAULT; + cmpc_accel_set_g_select_v4(acpi->handle, accel->g_select); + + error = device_create_file(&acpi->dev, &cmpc_accel_g_select_attr_v4); + if (error) + goto failed_g_select; + + error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel_v4", + cmpc_accel_idev_init_v4); + if (error) + goto failed_input; + + inputdev = dev_get_drvdata(&acpi->dev); + dev_set_drvdata(&inputdev->dev, accel); + + return 0; + +failed_input: + device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4); +failed_g_select: + device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4); +failed_sensitivity: + kfree(accel); + return error; +} + +static int cmpc_accel_remove_v4(struct acpi_device *acpi, int type) +{ + struct input_dev *inputdev; + struct cmpc_accel *accel; + + inputdev = dev_get_drvdata(&acpi->dev); + accel = dev_get_drvdata(&inputdev->dev); + + device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr_v4); + device_remove_file(&acpi->dev, &cmpc_accel_g_select_attr_v4); + return cmpc_remove_acpi_notify_device(acpi); +} + +static SIMPLE_DEV_PM_OPS(cmpc_accel_pm, cmpc_accel_suspend_v4, + cmpc_accel_resume_v4); + +static const struct acpi_device_id cmpc_accel_device_ids_v4[] = { + {CMPC_ACCEL_HID_V4, 0}, + {"", 0} +}; + +static struct acpi_driver cmpc_accel_acpi_driver_v4 = { + .owner = THIS_MODULE, + .name = "cmpc_accel_v4", + .class = "cmpc_accel_v4", + .ids = cmpc_accel_device_ids_v4, + .ops = { + .add = cmpc_accel_add_v4, + .remove = cmpc_accel_remove_v4, + .notify = cmpc_accel_handler_v4, + }, + .drv.pm = &cmpc_accel_pm, +}; + + +/* + * Accelerometer code for Classmate versions prior to V4 */ static acpi_status cmpc_start_accel(acpi_handle handle) { @@ -726,8 +1116,15 @@ static int cmpc_init(void) if (r) goto failed_accel; + r = acpi_bus_register_driver(&cmpc_accel_acpi_driver_v4); + if (r) + goto failed_accel_v4; + return r; +failed_accel_v4: + acpi_bus_unregister_driver(&cmpc_accel_acpi_driver); + failed_accel: acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver); @@ -743,6 +1140,7 @@ failed_keys: static void cmpc_exit(void) { + acpi_bus_unregister_driver(&cmpc_accel_acpi_driver_v4); acpi_bus_unregister_driver(&cmpc_accel_acpi_driver); acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver); acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver); @@ -754,6 +1152,7 @@ module_exit(cmpc_exit); static const struct acpi_device_id cmpc_device_ids[] = { {CMPC_ACCEL_HID, 0}, + {CMPC_ACCEL_HID_V4, 0}, {CMPC_TABLET_HID, 0}, {CMPC_IPML_HID, 0}, {CMPC_KEYS_HID, 0}, -- cgit v1.2.3 From 0ece8d515c264078a144bc597d0ffc40645ce378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20G=C3=B3mez?= Date: Tue, 24 Jul 2012 15:05:25 +0200 Subject: classmate-laptop: Fix extra keys hardware id. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since ACPI devices ids were changed to use always upper-case letters, the ACPI id of the extra keys (FNBT0000) was not maching the one defined in the driver (FnBT0000), causing the extra keys not to work. The patch replaces the driver id with the one reported by ACPI, fixing the problem. Signed-off-by: Miguel Gómez Signed-off-by: Matthew Garrett --- drivers/platform/x86/classmate-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index 33f4d2c72c03..2ca7dd1ab3e4 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -45,7 +45,7 @@ struct cmpc_accel { #define CMPC_ACCEL_HID_V4 "ACCE0001" #define CMPC_TABLET_HID "TBLT0000" #define CMPC_IPML_HID "IPML200" -#define CMPC_KEYS_HID "FnBT0000" +#define CMPC_KEYS_HID "FNBT0000" /* * Generic input device code. -- cgit v1.2.3 From d2044c5a3aafac552d28c1add16930821c24cbd0 Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Wed, 4 Jul 2012 11:19:08 +0800 Subject: asus-nb-wmi: add wapf quirk for ASUS machines The BIOS of these machines will try to enable/disable wifi/bt in their own sqeuence. It won't read the enable/disable parameter in WMI command, but just iterates the wifi/bt's status described below 1st. enable wifi, enable bt 2nd. disable wifi, enable bt 3rd. enable wifi, disable bt 4th. disable wifi, disable bt That will totally mess up the rfkill status, since we will try to read wifi and bt's status and reset it again while booting up. To avoid this, these machines should set the wapf value to 4, that will let software totally control the wifi/bt's status and BIOS will do nothing instead of sending out the 0x88(KEY_RFKILL) event instead of 0x5e(wifi enable), 0x5f(wifi diable), 0x7d(bt enable), and 0x7e(bt disable) through WMI. With this patch[1], it will handle the KEY_RFKILL event correctly and will block/unblock wifi and bt together. 1. https://lkml.org/lkml/2012/5/21/75 Signed-off-by: AceLan Kao Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-nb-wmi.c | 104 +++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 99a30b513137..57712ff1a1de 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "asus-wmi.h" @@ -48,18 +49,115 @@ MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); * 1 | Hardware | Software * 4 | Software | Software */ -static uint wapf; +static int wapf = -1; module_param(wapf, uint, 0444); MODULE_PARM_DESC(wapf, "WAPF value"); +static struct quirk_entry *quirks; + static struct quirk_entry quirk_asus_unknown = { + .wapf = 0, +}; + +static struct quirk_entry quirk_asus_x401u = { + .wapf = 4, +}; + +static int dmi_matched(const struct dmi_system_id *dmi) +{ + quirks = dmi->driver_data; + return 1; +} + +static struct dmi_system_id asus_quirks[] = { + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X401U", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X401U"), + }, + .driver_data = &quirk_asus_x401u, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X401A1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X401A1"), + }, + .driver_data = &quirk_asus_x401u, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X501U", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X501U"), + }, + .driver_data = &quirk_asus_x401u, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X501A1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X501A1"), + }, + .driver_data = &quirk_asus_x401u, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X55A", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X55A"), + }, + .driver_data = &quirk_asus_x401u, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X55C", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X55C"), + }, + .driver_data = &quirk_asus_x401u, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X55U", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X55U"), + }, + .driver_data = &quirk_asus_x401u, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X55VD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X55VD"), + }, + .driver_data = &quirk_asus_x401u, + }, + {}, }; static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) { - driver->quirks = &quirk_asus_unknown; - driver->quirks->wapf = wapf; + quirks = &quirk_asus_unknown; + dmi_check_system(asus_quirks); + + driver->quirks = quirks; driver->panel_power = FB_BLANK_UNBLANK; + + /* overwrite the wapf setting if the wapf paramater is specified */ + if (wapf != -1) + quirks->wapf = wapf; + else + wapf = quirks->wapf; } static const struct key_entry asus_nb_wmi_keymap[] = { -- cgit v1.2.3 From 3766054fff4af1b58a1440a284907887f4d2e8be Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Wed, 4 Jul 2012 15:20:14 +0800 Subject: asus-nb-wmi: add some video toggle keys There are some new video switch keys that used by newer machines. 0xA0 - SDSP HDMI only 0xA1 - SDSP LCD + HDMI 0xA2 - SDSP CRT + HDMI 0xA3 - SDSP TV + HDMI But in Linux, there is no suitable userspace application to handle this, so, mapping them all to KEY_SWITCHVIDEOMODE. Signed-off-by: AceLan Kao Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-nb-wmi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 57712ff1a1de..6b0ebdeae916 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -192,6 +192,10 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x8A, { KEY_PROG1 } }, { KE_KEY, 0x95, { KEY_MEDIA } }, { KE_KEY, 0x99, { KEY_PHONE } }, + { KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */ + { KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */ + { KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */ + { KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */ { KE_KEY, 0xb5, { KEY_CALC } }, { KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, -- cgit v1.2.3 From 24237c43aade30758aacabbf0e462fca19c48231 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 5 Jul 2012 01:30:09 +0200 Subject: ACER: Fix up sparse warning drivers/platform/x86/acer-wmi.c:1836:18: sparse: Using plain integer as NULL pointer drivers/platform/x86/acer-wmi.c:1836: 1833 1834 BUG_ON(!name || !ah); 1835 > 1836 handle = 0; 1837 status = acpi_get_devices(prop, acer_wmi_get_handle_cb, 1838 (void *)name, &handle); 1839 Reported-by: Fengguang Wu Signed-off-by: Marek Vasut Cc: Matthew Garrett Cc: Fengguang Wu Cc: joeyli Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 377d92d8d9b1..cdee5ecf4bf6 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1833,7 +1833,7 @@ static int __init acer_wmi_get_handle(const char *name, const char *prop, BUG_ON(!name || !ah); - handle = 0; + handle = NULL; status = acpi_get_devices(prop, acer_wmi_get_handle_cb, (void *)name, &handle); -- cgit v1.2.3 From 1bfaf1d5bcfb2ae0b7b90c5aed86909ee4f3f099 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 5 Jul 2012 01:30:10 +0200 Subject: ACER: Fix Smatch double-free issue The patch 6ae3a0876185: "ACER: Add support for accelerometer sensor" from Jun 1, 2012, leads to the following Smatch warning: drivers/platform/x86/acer-wmi.c:1886 acer_wmi_accel_destroy() error: don't call input_free_device() after input_unregister_device() drivers/platform/x86/acer-wmi.c 1883 static void acer_wmi_accel_destroy(void) 1884 { 1885 input_unregister_device(acer_wmi_accel_dev); 1886 input_free_device(acer_wmi_accel_dev); 1887 } Reported-by: Dan Carpenter Signed-off-by: Marek Vasut Cc: Matthew Garrett Cc: Fengguang Wu Cc: joeyli Cc: Dan Carpenter Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index cdee5ecf4bf6..3782e1cd3697 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1883,7 +1883,6 @@ err_free_dev: static void acer_wmi_accel_destroy(void) { input_unregister_device(acer_wmi_accel_dev); - input_free_device(acer_wmi_accel_dev); } static int __init acer_wmi_input_setup(void) -- cgit v1.2.3 From 5f1e88f4974c82fc0eccf0a12f9eeb038af383fa Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Fri, 13 Jul 2012 16:39:57 +0800 Subject: dell-laptop: Add 6 machines to touchpad led quirk Add the following machines into quirk, Isnpiron 5420, Isnpiron 5520, Isnpiron 5720, Isnpiron 7420, Isnpiron 7520, Isnpiron 7720 Signed-off-by: AceLan Kao Signed-off-by: Matthew Garrett --- drivers/platform/x86/dell-laptop.c | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 5f78aac9b163..4e96e8c0b60f 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -206,6 +206,60 @@ static struct dmi_system_id __devinitdata dell_quirks[] = { }, .driver_data = &quirk_dell_vostro_v130, }, + { + .callback = dmi_matched, + .ident = "Dell Inspiron 5420", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5420"), + }, + .driver_data = &quirk_dell_vostro_v130, + }, + { + .callback = dmi_matched, + .ident = "Dell Inspiron 5520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5520"), + }, + .driver_data = &quirk_dell_vostro_v130, + }, + { + .callback = dmi_matched, + .ident = "Dell Inspiron 5720", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 5720"), + }, + .driver_data = &quirk_dell_vostro_v130, + }, + { + .callback = dmi_matched, + .ident = "Dell Inspiron 7420", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7420"), + }, + .driver_data = &quirk_dell_vostro_v130, + }, + { + .callback = dmi_matched, + .ident = "Dell Inspiron 7520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7520"), + }, + .driver_data = &quirk_dell_vostro_v130, + }, + { + .callback = dmi_matched, + .ident = "Dell Inspiron 7720", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Isnpiron 7720"), + }, + .driver_data = &quirk_dell_vostro_v130, + }, { } }; -- cgit v1.2.3 From e03e389da50dd967f20470e58827abe7a532c5a5 Mon Sep 17 00:00:00 2001 From: Li Dongyang Date: Wed, 25 Jul 2012 10:45:07 +1000 Subject: thinkpad_acpi: Flush the workqueue before freeing tpacpi_leds We init work_struct within tpacpi_leds, and we should free tpacpi_leds after the workqueue is empty, in case of the work_struct is referenced after free. This script could trigger the OOPS: #!/bin/sh while true do modprobe -r thinkpad_acpi modprobe thinkpad_acpi done And the OOPS looks like this: [ 73.863557] BUG: unable to handle kernel paging request at 45440000 [ 73.863925] IP: [] process_one_work+0x25/0x3b0 [ 73.864749] *pde = 00000000 [ 73.865571] Oops: 0000 [#1] PREEMPT SMP [ 73.866443] Modules linked in: thinkpad_acpi(-) nvram netconsole configfs aes_i586 cryptd aes_generic joydev btusb bluetooth arc4 snd_hda_codec_analog iwl4965 uhci_hcd pcmcia microcode iwlegacy mac80211 cfg80211 firewire_ohci firewire_core kvm_intel kvm snd_hda_intel acpi_cpufreq mperf ehci_hcd yenta_socket pcmcia_rsrc crc_itu_t sr_mod snd_hda_codec processor pcmcia_core i2c_i801 usbcore lpc_ich cdrom serio_raw psmouse coretemp rfkill e1000e snd_pcm snd_page_alloc snd_hwdep snd_timer snd pcspkr evdev ac battery thermal soundcore usb_common intel_agp intel_gtt tp_smapi(O) thinkpad_ec(O) ext4 crc16 jbd2 mbcache sd_mod ata_piix ahci libahci libata scsi_mod nouveau button video mxm_wmi wmi i2c_algo_bit drm_kms_helper ttm drm agpgart i2c_core [last unloaded: nvram] [ 73.866676] [ 73.866676] Pid: 62, comm: kworker/u:4 Tainted: G O 3.5.0-1-ARCH #1 LENOVO 7662CTO/7662CTO [ 73.866676] EIP: 0060:[] EFLAGS: 00010002 CPU: 1 [ 73.866676] EIP is at process_one_work+0x25/0x3b0 [ 73.866676] EAX: 45440065 EBX: f5545090 ECX: 00000088 EDX: 45440000 [ 73.866676] ESI: f568ff40 EDI: c164dd40 EBP: f5705f98 ESP: f5705f68 [ 73.866676] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 [ 73.866676] CR0: 8005003b CR2: 45440000 CR3: 357ed000 CR4: 000007d0 [ 73.866676] DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 [ 73.866676] DR6: ffff0ff0 DR7: 00000400 [ 73.866676] Process kworker/u:4 (pid: 62, ti=f5704000 task=f5700540 task.ti=f5704000) [ 73.866676] Stack: [ 73.866676] f56fbf24 00000001 f5705f78 c10683e0 c1294950 00000000 00000000 f568ff40 [ 73.866676] 00000000 f568ff40 f568ff50 c164dd40 f5705fb8 c1052589 c1060c7e c15b9300 [ 73.866676] c164dd40 00000000 f568ff40 c1052490 f5705fe4 c10570b2 00000000 f568ff40 [ 73.866676] Call Trace: [ 73.866676] [] ? default_wake_function+0x10/0x20 [ 73.866676] [] ? dev_get_drvdata+0x20/0x20 [ 73.866676] [] worker_thread+0xf9/0x280 [ 73.866676] [] ? complete+0x4e/0x60 [ 73.866676] [] ? manage_workers.isra.24+0x1c0/0x1c0 [ 73.866676] [] kthread+0x72/0x80 [ 73.866676] [] ? kthread_freezable_should_stop+0x50/0x50 [ 73.866676] [] kernel_thread_helper+0x6/0x10 [ 73.866676] Code: bc 27 00 00 00 00 55 89 e5 57 56 53 83 ec 24 3e 8d 74 26 00 89 c6 8b 02 89 d3 c7 45 f0 00 00 00 00 89 c2 30 d2 a8 04 0f 44 55 f0 <8b> 02 89 55 f0 89 da c1 ea 0a 89 45 ec 89 d8 8b 4d ec c1 e8 04 [ 73.866676] EIP: [] process_one_work+0x25/0x3b0 SS:ESP 0068:f5705f68 [ 73.866676] CR2: 0000000045440000 [ 73.866676] ---[ end trace 4d8a1887edca08c5 ]--- [ 73.866676] note: kworker/u:4[62] exited with preempt_count 1 Signed-off-by: Li Dongyang Signed-off-by: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d5fd4a1193f8..c85b66602ee1 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -5217,6 +5217,7 @@ static void led_exit(void) led_classdev_unregister(&tpacpi_leds[i].led_classdev); } + flush_workqueue(tpacpi_wq); kfree(tpacpi_leds); } -- cgit v1.2.3 From d2be15bdda45b184d483754e434c9a1c8ed80a8e Mon Sep 17 00:00:00 2001 From: Li Dongyang Date: Wed, 25 Jul 2012 10:45:08 +1000 Subject: thinkpad_acpi: Fix a memory leak during module exit We should free the thinkpad_id.nummodel_str during exit as it's allocated in get_thinkpad_module_data(). Signed-off-by: Li Dongyang Signed-off-by: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index c85b66602ee1..ae203558ac90 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -8970,6 +8970,7 @@ static void thinkpad_acpi_module_exit(void) kfree(thinkpad_id.bios_version_str); kfree(thinkpad_id.ec_version_str); kfree(thinkpad_id.model_str); + kfree(thinkpad_id.nummodel_str); } -- cgit v1.2.3 From 00d39597e825a2b09ec88d4dd429ff72fe60d9d4 Mon Sep 17 00:00:00 2001 From: Li Dongyang Date: Wed, 25 Jul 2012 10:45:09 +1000 Subject: thinkpad_acpi: Free hotkey_keycode_map after unregistering tpacpi_inputdev We should free hotkey_keycode_map after unregistering tpacpi_inputdev, to aviod use after free like this: [ 99.408388] ============================================================================= [ 99.408393] BUG kmalloc-64 (Not tainted): Poison overwritten [ 99.408394] ----------------------------------------------------------------------------- [ 99.408394] [ 99.408398] INFO: 0xf2751962-0xf2751995. First byte 0x98 instead of 0x6b [ 99.408402] INFO: Allocated in 0xfdc88c28 age=79 cpu=0 pid=1329 [ 99.408407] __slab_alloc.isra.50.constprop.56+0x49f/0x533 [ 99.408410] kmem_cache_alloc_trace+0x10d/0x140 [ 99.408412] 0xfdc88c28 [ 99.408414] 0xfdc898cc [ 99.408417] do_one_initcall+0x112/0x160 [ 99.408420] sys_init_module+0xe6d/0x1bc0 [ 99.408422] sysenter_do_call+0x12/0x28 [ 99.408427] INFO: Freed in hotkey_exit+0x50/0xb0 [thinkpad_acpi] age=14 cpu=1 pid=1333 [ 99.408429] __slab_free+0x3d/0x30b [ 99.408431] kfree+0x129/0x140 [ 99.408435] hotkey_exit+0x50/0xb0 [thinkpad_acpi] [ 99.408438] ibm_exit+0xe3/0x1a0 [thinkpad_acpi] [ 99.408441] thinkpad_acpi_module_exit+0x35/0x208 [thinkpad_acpi] [ 99.408443] sys_delete_module+0x11f/0x280 [ 99.408445] sysenter_do_call+0x12/0x28 [ 99.408447] INFO: Slab 0xf4d5ea20 objects=17 used=17 fp=0x (null) flags=0x40000080 [ 99.408449] INFO: Object 0xf2751960 @offset=2400 fp=0xf2751780 [ 99.408449] [ 99.408452] Bytes b4 f2751950: 64 02 00 00 ae ce fe ff 5a 5a 5a 5a 5a 5a 5a 5a d.......ZZZZZZZZ [ 99.408454] Object f2751960: 6b 6b 98 00 ec 00 8e 00 ee 00 6b 6b e3 00 bf 00 kk........kk.... [ 99.408456] Object f2751970: c2 00 6b 6b 6b 6b cd 00 6b 6b 6b 6b 6b 6b e1 00 ..kkkk..kkkkkk.. [ 99.408458] Object f2751980: e0 00 e4 00 6b 6b 74 01 73 00 72 00 71 00 94 00 ....kkt.s.r.q... [ 99.408460] Object f2751990: 6b 6b 6b 6b f8 00 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkk..kkkkkkkkk. [ 99.408462] Redzone f27519a0: bb bb bb bb .... Signed-off-by: Li Dongyang Signed-off-by: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index ae203558ac90..e7f73287636c 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3015,8 +3015,6 @@ static void hotkey_exit(void) if (hotkey_dev_attributes) delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); - kfree(hotkey_keycode_map); - dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, "restoring original HKEY status and mask\n"); /* yes, there is a bitwise or below, we want the @@ -8937,6 +8935,7 @@ static void thinkpad_acpi_module_exit(void) input_unregister_device(tpacpi_inputdev); else input_free_device(tpacpi_inputdev); + kfree(hotkey_keycode_map); } if (tpacpi_hwmon) -- cgit v1.2.3