diff options
Diffstat (limited to 'drivers/platform/x86/thinkpad_acpi.c')
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 227 |
1 files changed, 186 insertions, 41 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 94bb6157c957..15e61c16736e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -2321,53 +2321,55 @@ static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m) | |||
2321 | } | 2321 | } |
2322 | } | 2322 | } |
2323 | 2323 | ||
2324 | static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | ||
2325 | struct tp_nvram_state *newn, | ||
2326 | const u32 event_mask) | ||
2327 | { | ||
2328 | |||
2329 | #define TPACPI_COMPARE_KEY(__scancode, __member) \ | 2324 | #define TPACPI_COMPARE_KEY(__scancode, __member) \ |
2330 | do { \ | 2325 | do { \ |
2331 | if ((event_mask & (1 << __scancode)) && \ | 2326 | if ((event_mask & (1 << __scancode)) && \ |
2332 | oldn->__member != newn->__member) \ | 2327 | oldn->__member != newn->__member) \ |
2333 | tpacpi_hotkey_send_key(__scancode); \ | 2328 | tpacpi_hotkey_send_key(__scancode); \ |
2334 | } while (0) | 2329 | } while (0) |
2335 | 2330 | ||
2336 | #define TPACPI_MAY_SEND_KEY(__scancode) \ | 2331 | #define TPACPI_MAY_SEND_KEY(__scancode) \ |
2337 | do { \ | 2332 | do { \ |
2338 | if (event_mask & (1 << __scancode)) \ | 2333 | if (event_mask & (1 << __scancode)) \ |
2339 | tpacpi_hotkey_send_key(__scancode); \ | 2334 | tpacpi_hotkey_send_key(__scancode); \ |
2340 | } while (0) | 2335 | } while (0) |
2341 | 2336 | ||
2342 | void issue_volchange(const unsigned int oldvol, | 2337 | static void issue_volchange(const unsigned int oldvol, |
2343 | const unsigned int newvol) | 2338 | const unsigned int newvol, |
2344 | { | 2339 | const u32 event_mask) |
2345 | unsigned int i = oldvol; | 2340 | { |
2341 | unsigned int i = oldvol; | ||
2346 | 2342 | ||
2347 | while (i > newvol) { | 2343 | while (i > newvol) { |
2348 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); | 2344 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); |
2349 | i--; | 2345 | i--; |
2350 | } | 2346 | } |
2351 | while (i < newvol) { | 2347 | while (i < newvol) { |
2352 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | 2348 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); |
2353 | i++; | 2349 | i++; |
2354 | } | ||
2355 | } | 2350 | } |
2351 | } | ||
2356 | 2352 | ||
2357 | void issue_brightnesschange(const unsigned int oldbrt, | 2353 | static void issue_brightnesschange(const unsigned int oldbrt, |
2358 | const unsigned int newbrt) | 2354 | const unsigned int newbrt, |
2359 | { | 2355 | const u32 event_mask) |
2360 | unsigned int i = oldbrt; | 2356 | { |
2357 | unsigned int i = oldbrt; | ||
2361 | 2358 | ||
2362 | while (i > newbrt) { | 2359 | while (i > newbrt) { |
2363 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); | 2360 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND); |
2364 | i--; | 2361 | i--; |
2365 | } | ||
2366 | while (i < newbrt) { | ||
2367 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); | ||
2368 | i++; | ||
2369 | } | ||
2370 | } | 2362 | } |
2363 | while (i < newbrt) { | ||
2364 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME); | ||
2365 | i++; | ||
2366 | } | ||
2367 | } | ||
2368 | |||
2369 | static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | ||
2370 | struct tp_nvram_state *newn, | ||
2371 | const u32 event_mask) | ||
2372 | { | ||
2371 | 2373 | ||
2372 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); | 2374 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); |
2373 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); | 2375 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); |
@@ -2402,7 +2404,8 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | |||
2402 | oldn->volume_level != newn->volume_level) { | 2404 | oldn->volume_level != newn->volume_level) { |
2403 | /* recently muted, or repeated mute keypress, or | 2405 | /* recently muted, or repeated mute keypress, or |
2404 | * multiple presses ending in mute */ | 2406 | * multiple presses ending in mute */ |
2405 | issue_volchange(oldn->volume_level, newn->volume_level); | 2407 | issue_volchange(oldn->volume_level, newn->volume_level, |
2408 | event_mask); | ||
2406 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); | 2409 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); |
2407 | } | 2410 | } |
2408 | } else { | 2411 | } else { |
@@ -2412,7 +2415,8 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | |||
2412 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | 2415 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); |
2413 | } | 2416 | } |
2414 | if (oldn->volume_level != newn->volume_level) { | 2417 | if (oldn->volume_level != newn->volume_level) { |
2415 | issue_volchange(oldn->volume_level, newn->volume_level); | 2418 | issue_volchange(oldn->volume_level, newn->volume_level, |
2419 | event_mask); | ||
2416 | } else if (oldn->volume_toggle != newn->volume_toggle) { | 2420 | } else if (oldn->volume_toggle != newn->volume_toggle) { |
2417 | /* repeated vol up/down keypress at end of scale ? */ | 2421 | /* repeated vol up/down keypress at end of scale ? */ |
2418 | if (newn->volume_level == 0) | 2422 | if (newn->volume_level == 0) |
@@ -2425,7 +2429,7 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | |||
2425 | /* handle brightness */ | 2429 | /* handle brightness */ |
2426 | if (oldn->brightness_level != newn->brightness_level) { | 2430 | if (oldn->brightness_level != newn->brightness_level) { |
2427 | issue_brightnesschange(oldn->brightness_level, | 2431 | issue_brightnesschange(oldn->brightness_level, |
2428 | newn->brightness_level); | 2432 | newn->brightness_level, event_mask); |
2429 | } else if (oldn->brightness_toggle != newn->brightness_toggle) { | 2433 | } else if (oldn->brightness_toggle != newn->brightness_toggle) { |
2430 | /* repeated key presses that didn't change state */ | 2434 | /* repeated key presses that didn't change state */ |
2431 | if (newn->brightness_level == 0) | 2435 | if (newn->brightness_level == 0) |
@@ -3437,6 +3441,106 @@ err_exit: | |||
3437 | return (res < 0)? res : 1; | 3441 | return (res < 0)? res : 1; |
3438 | } | 3442 | } |
3439 | 3443 | ||
3444 | /* Thinkpad X1 Carbon support 5 modes including Home mode, Web browser | ||
3445 | * mode, Web conference mode, Function mode and Lay-flat mode. | ||
3446 | * We support Home mode and Function mode currently. | ||
3447 | * | ||
3448 | * Will consider support rest of modes in future. | ||
3449 | * | ||
3450 | */ | ||
3451 | enum ADAPTIVE_KEY_MODE { | ||
3452 | HOME_MODE, | ||
3453 | WEB_BROWSER_MODE, | ||
3454 | WEB_CONFERENCE_MODE, | ||
3455 | FUNCTION_MODE, | ||
3456 | LAYFLAT_MODE | ||
3457 | }; | ||
3458 | |||
3459 | const int adaptive_keyboard_modes[] = { | ||
3460 | HOME_MODE, | ||
3461 | /* WEB_BROWSER_MODE = 2, | ||
3462 | WEB_CONFERENCE_MODE = 3, */ | ||
3463 | FUNCTION_MODE | ||
3464 | }; | ||
3465 | |||
3466 | #define DFR_CHANGE_ROW 0x101 | ||
3467 | #define DFR_SHOW_QUICKVIEW_ROW 0x102 | ||
3468 | |||
3469 | /* press Fn key a while second, it will switch to Function Mode. Then | ||
3470 | * release Fn key, previous mode be restored. | ||
3471 | */ | ||
3472 | static bool adaptive_keyboard_mode_is_saved; | ||
3473 | static int adaptive_keyboard_prev_mode; | ||
3474 | |||
3475 | static int adaptive_keyboard_get_next_mode(int mode) | ||
3476 | { | ||
3477 | size_t i; | ||
3478 | size_t max_mode = ARRAY_SIZE(adaptive_keyboard_modes) - 1; | ||
3479 | |||
3480 | for (i = 0; i <= max_mode; i++) { | ||
3481 | if (adaptive_keyboard_modes[i] == mode) | ||
3482 | break; | ||
3483 | } | ||
3484 | |||
3485 | if (i >= max_mode) | ||
3486 | i = 0; | ||
3487 | else | ||
3488 | i++; | ||
3489 | |||
3490 | return adaptive_keyboard_modes[i]; | ||
3491 | } | ||
3492 | |||
3493 | static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode) | ||
3494 | { | ||
3495 | u32 current_mode = 0; | ||
3496 | int new_mode = 0; | ||
3497 | |||
3498 | switch (scancode) { | ||
3499 | case DFR_CHANGE_ROW: | ||
3500 | if (adaptive_keyboard_mode_is_saved) { | ||
3501 | new_mode = adaptive_keyboard_prev_mode; | ||
3502 | adaptive_keyboard_mode_is_saved = false; | ||
3503 | } else { | ||
3504 | if (!acpi_evalf( | ||
3505 | hkey_handle, ¤t_mode, | ||
3506 | "GTRW", "dd", 0)) { | ||
3507 | pr_err("Cannot read adaptive keyboard mode\n"); | ||
3508 | return false; | ||
3509 | } else { | ||
3510 | new_mode = adaptive_keyboard_get_next_mode( | ||
3511 | current_mode); | ||
3512 | } | ||
3513 | } | ||
3514 | |||
3515 | if (!acpi_evalf(hkey_handle, NULL, "STRW", "vd", new_mode)) { | ||
3516 | pr_err("Cannot set adaptive keyboard mode\n"); | ||
3517 | return false; | ||
3518 | } | ||
3519 | |||
3520 | return true; | ||
3521 | |||
3522 | case DFR_SHOW_QUICKVIEW_ROW: | ||
3523 | if (!acpi_evalf(hkey_handle, | ||
3524 | &adaptive_keyboard_prev_mode, | ||
3525 | "GTRW", "dd", 0)) { | ||
3526 | pr_err("Cannot read adaptive keyboard mode\n"); | ||
3527 | return false; | ||
3528 | } else { | ||
3529 | adaptive_keyboard_mode_is_saved = true; | ||
3530 | |||
3531 | if (!acpi_evalf(hkey_handle, | ||
3532 | NULL, "STRW", "vd", FUNCTION_MODE)) { | ||
3533 | pr_err("Cannot set adaptive keyboard mode\n"); | ||
3534 | return false; | ||
3535 | } | ||
3536 | } | ||
3537 | return true; | ||
3538 | |||
3539 | default: | ||
3540 | return false; | ||
3541 | } | ||
3542 | } | ||
3543 | |||
3440 | static bool hotkey_notify_hotkey(const u32 hkey, | 3544 | static bool hotkey_notify_hotkey(const u32 hkey, |
3441 | bool *send_acpi_ev, | 3545 | bool *send_acpi_ev, |
3442 | bool *ignore_acpi_ev) | 3546 | bool *ignore_acpi_ev) |
@@ -3456,6 +3560,8 @@ static bool hotkey_notify_hotkey(const u32 hkey, | |||
3456 | *ignore_acpi_ev = true; | 3560 | *ignore_acpi_ev = true; |
3457 | } | 3561 | } |
3458 | return true; | 3562 | return true; |
3563 | } else { | ||
3564 | return adaptive_keyboard_hotkey_notify_hotkey(scancode); | ||
3459 | } | 3565 | } |
3460 | return false; | 3566 | return false; |
3461 | } | 3567 | } |
@@ -3728,13 +3834,28 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) | |||
3728 | 3834 | ||
3729 | static void hotkey_suspend(void) | 3835 | static void hotkey_suspend(void) |
3730 | { | 3836 | { |
3837 | int hkeyv; | ||
3838 | |||
3731 | /* Do these on suspend, we get the events on early resume! */ | 3839 | /* Do these on suspend, we get the events on early resume! */ |
3732 | hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE; | 3840 | hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE; |
3733 | hotkey_autosleep_ack = 0; | 3841 | hotkey_autosleep_ack = 0; |
3842 | |||
3843 | /* save previous mode of adaptive keyboard of X1 Carbon */ | ||
3844 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { | ||
3845 | if ((hkeyv >> 8) == 2) { | ||
3846 | if (!acpi_evalf(hkey_handle, | ||
3847 | &adaptive_keyboard_prev_mode, | ||
3848 | "GTRW", "dd", 0)) { | ||
3849 | pr_err("Cannot read adaptive keyboard mode.\n"); | ||
3850 | } | ||
3851 | } | ||
3852 | } | ||
3734 | } | 3853 | } |
3735 | 3854 | ||
3736 | static void hotkey_resume(void) | 3855 | static void hotkey_resume(void) |
3737 | { | 3856 | { |
3857 | int hkeyv; | ||
3858 | |||
3738 | tpacpi_disable_brightness_delay(); | 3859 | tpacpi_disable_brightness_delay(); |
3739 | 3860 | ||
3740 | if (hotkey_status_set(true) < 0 || | 3861 | if (hotkey_status_set(true) < 0 || |
@@ -3747,6 +3868,18 @@ static void hotkey_resume(void) | |||
3747 | hotkey_wakeup_reason_notify_change(); | 3868 | hotkey_wakeup_reason_notify_change(); |
3748 | hotkey_wakeup_hotunplug_complete_notify_change(); | 3869 | hotkey_wakeup_hotunplug_complete_notify_change(); |
3749 | hotkey_poll_setup_safe(false); | 3870 | hotkey_poll_setup_safe(false); |
3871 | |||
3872 | /* restore previous mode of adapive keyboard of X1 Carbon */ | ||
3873 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { | ||
3874 | if ((hkeyv >> 8) == 2) { | ||
3875 | if (!acpi_evalf(hkey_handle, | ||
3876 | NULL, | ||
3877 | "STRW", "vd", | ||
3878 | adaptive_keyboard_prev_mode)) { | ||
3879 | pr_err("Cannot set adaptive keyboard mode.\n"); | ||
3880 | } | ||
3881 | } | ||
3882 | } | ||
3750 | } | 3883 | } |
3751 | 3884 | ||
3752 | /* procfs -------------------------------------------------------------- */ | 3885 | /* procfs -------------------------------------------------------------- */ |
@@ -8447,9 +8580,21 @@ static void mute_led_exit(void) | |||
8447 | tpacpi_led_set(i, false); | 8580 | tpacpi_led_set(i, false); |
8448 | } | 8581 | } |
8449 | 8582 | ||
8583 | static void mute_led_resume(void) | ||
8584 | { | ||
8585 | int i; | ||
8586 | |||
8587 | for (i = 0; i < TPACPI_LED_MAX; i++) { | ||
8588 | struct tp_led_table *t = &led_tables[i]; | ||
8589 | if (t->state >= 0) | ||
8590 | mute_led_on_off(t, t->state); | ||
8591 | } | ||
8592 | } | ||
8593 | |||
8450 | static struct ibm_struct mute_led_driver_data = { | 8594 | static struct ibm_struct mute_led_driver_data = { |
8451 | .name = "mute_led", | 8595 | .name = "mute_led", |
8452 | .exit = mute_led_exit, | 8596 | .exit = mute_led_exit, |
8597 | .resume = mute_led_resume, | ||
8453 | }; | 8598 | }; |
8454 | 8599 | ||
8455 | /**************************************************************************** | 8600 | /**************************************************************************** |