aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2010-05-16 18:45:28 -0400
committerHenrique de Moraes Holschuh <hmh@hmh.eng.br>2010-05-16 18:45:28 -0400
commit5d756db99a7382d5cd173e912d527e9ee73d0596 (patch)
tree0f80aa83538e5869223e82b9d53ae8baa12484e1 /drivers/platform
parenta318930d06a7a93bd50000c7112f995b459adda7 (diff)
thinkpad-acpi: fix volume/mute hotkey poll handling
The hotkey polling code is supposed to generate hotkey messages as close to the way the IBM event-based volume hotkey firmware does as possible, i.e: * Pressing MUTE issues a mute hotkey event, even if already mute; * Pressing Volume up/down issues a volume up/down hotkey event, even if already at maximum or minumum volume; * The act of unmuting issues a volume up/down event, depending on which hotkey was used to unmute. Fix the code to do just that (mute handling was incorrect), and handle multiple hotkey presses between two polling cycles. The new code uses the volume_toggle bit in NVRAM only to detect repeated presses of the mute key and multiple presses of the volume keys trying to go past the end of the volume scale. This will work around a bug in recent Lenovo firmware (e.g. T400), which causes the firmware to not update the volume_toggle bit in certain situations. Reported-by: Yang Zhe <yangzhe1990@gmail.com> Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c71
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 */
126enum {
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