diff options
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 71 |
1 files changed, 57 insertions, 14 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 7817cef6aae1..1f27b350ae01 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -122,6 +122,11 @@ enum { | |||
122 | TP_NVRAM_POS_LEVEL_VOLUME = 0, | 122 | TP_NVRAM_POS_LEVEL_VOLUME = 0, |
123 | }; | 123 | }; |
124 | 124 | ||
125 | /* Misc NVRAM-related */ | ||
126 | enum { | ||
127 | TP_NVRAM_LEVEL_VOLUME_MAX = 14, | ||
128 | }; | ||
129 | |||
125 | /* ACPI HIDs */ | 130 | /* ACPI HIDs */ |
126 | #define TPACPI_ACPI_HKEY_HID "IBM0068" | 131 | #define TPACPI_ACPI_HKEY_HID "IBM0068" |
127 | 132 | ||
@@ -2418,6 +2423,21 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | |||
2418 | tpacpi_hotkey_send_key(__scancode); \ | 2423 | tpacpi_hotkey_send_key(__scancode); \ |
2419 | } while (0) | 2424 | } while (0) |
2420 | 2425 | ||
2426 | void issue_volchange(const unsigned int oldvol, | ||
2427 | const unsigned int newvol) | ||
2428 | { | ||
2429 | unsigned int i = oldvol; | ||
2430 | |||
2431 | while (i > newvol) { | ||
2432 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); | ||
2433 | i--; | ||
2434 | } | ||
2435 | while (i < newvol) { | ||
2436 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | ||
2437 | i++; | ||
2438 | } | ||
2439 | } | ||
2440 | |||
2421 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); | 2441 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); |
2422 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); | 2442 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); |
2423 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); | 2443 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); |
@@ -2427,24 +2447,47 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | |||
2427 | 2447 | ||
2428 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle); | 2448 | TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle); |
2429 | 2449 | ||
2430 | /* handle volume */ | 2450 | /* |
2431 | if (oldn->volume_toggle != newn->volume_toggle) { | 2451 | * Handle volume |
2432 | if (oldn->mute != newn->mute) { | 2452 | * |
2453 | * This code is supposed to duplicate the IBM firmware behaviour: | ||
2454 | * - Pressing MUTE issues mute hotkey message, even when already mute | ||
2455 | * - Pressing Volume up/down issues volume up/down hotkey messages, | ||
2456 | * even when already at maximum or minumum volume | ||
2457 | * - The act of unmuting issues volume up/down notification, | ||
2458 | * depending which key was used to unmute | ||
2459 | * | ||
2460 | * We are constrained to what the NVRAM can tell us, which is not much | ||
2461 | * and certainly not enough if more than one volume hotkey was pressed | ||
2462 | * since the last poll cycle. | ||
2463 | * | ||
2464 | * Just to make our life interesting, some newer Lenovo ThinkPads have | ||
2465 | * bugs in the BIOS and may fail to update volume_toggle properly. | ||
2466 | */ | ||
2467 | if (newn->mute) { | ||
2468 | /* muted */ | ||
2469 | if (!oldn->mute || | ||
2470 | oldn->volume_toggle != newn->volume_toggle || | ||
2471 | oldn->volume_level != newn->volume_level) { | ||
2472 | /* recently muted, or repeated mute keypress, or | ||
2473 | * multiple presses ending in mute */ | ||
2474 | issue_volchange(oldn->volume_level, newn->volume_level); | ||
2433 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); | 2475 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); |
2434 | } | 2476 | } |
2435 | if (oldn->volume_level > newn->volume_level) { | 2477 | } else { |
2436 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); | 2478 | /* unmute */ |
2437 | } else if (oldn->volume_level < newn->volume_level) { | 2479 | if (oldn->mute) { |
2480 | /* recently unmuted, issue 'unmute' keypress */ | ||
2438 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | 2481 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); |
2439 | } else if (oldn->mute == newn->mute) { | 2482 | } |
2440 | /* repeated key presses that didn't change state */ | 2483 | if (oldn->volume_level != newn->volume_level) { |
2441 | if (newn->mute) { | 2484 | issue_volchange(oldn->volume_level, newn->volume_level); |
2442 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE); | 2485 | } else if (oldn->volume_toggle != newn->volume_toggle) { |
2443 | } else if (newn->volume_level != 0) { | 2486 | /* repeated vol up/down keypress at end of scale ? */ |
2444 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | 2487 | if (newn->volume_level == 0) |
2445 | } else { | ||
2446 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); | 2488 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN); |
2447 | } | 2489 | else if (newn->volume_level >= TP_NVRAM_LEVEL_VOLUME_MAX) |
2490 | TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP); | ||
2448 | } | 2491 | } |
2449 | } | 2492 | } |
2450 | 2493 | ||