diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2010-02-27 16:45:29 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-15 12:06:21 -0400 |
commit | d707522d421d10bb56c5054812eb1f53a39a5c08 (patch) | |
tree | ba7197c1602bffd9136fc93d3a3e2c60d7fc72e3 | |
parent | f4d574122bc35f8c90effac2e3a2af2889e9ba81 (diff) |
thinkpad-acpi: fix ALSA callback return status
commit 88cc83772a3c7756b9f2b4ba835545ad90a08409 upstream.
Clemens Ladisch reports that thinkpad-acpi improperly implements the
ALSA API, and always returns 0 for success for the "put" callbacks
while the API requires it to return "1" when the control value has
been changed in the hardware/firmware.
Rework the volume subdriver to be able to properly implement the ALSA
API. Based on a patch by Clemens Ladisch <clemens@ladisch.de>.
This fix is also needed on 2.6.33.
Reported-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index eb603f1d55ca..159a1f877d91 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -6522,7 +6522,8 @@ static int volume_set_status(const u8 status) | |||
6522 | return volume_set_status_ec(status); | 6522 | return volume_set_status_ec(status); |
6523 | } | 6523 | } |
6524 | 6524 | ||
6525 | static int volume_set_mute_ec(const bool mute) | 6525 | /* returns < 0 on error, 0 on no change, 1 on change */ |
6526 | static int __volume_set_mute_ec(const bool mute) | ||
6526 | { | 6527 | { |
6527 | int rc; | 6528 | int rc; |
6528 | u8 s, n; | 6529 | u8 s, n; |
@@ -6537,22 +6538,37 @@ static int volume_set_mute_ec(const bool mute) | |||
6537 | n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK : | 6538 | n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK : |
6538 | s & ~TP_EC_AUDIO_MUTESW_MSK; | 6539 | s & ~TP_EC_AUDIO_MUTESW_MSK; |
6539 | 6540 | ||
6540 | if (n != s) | 6541 | if (n != s) { |
6541 | rc = volume_set_status_ec(n); | 6542 | rc = volume_set_status_ec(n); |
6543 | if (!rc) | ||
6544 | rc = 1; | ||
6545 | } | ||
6542 | 6546 | ||
6543 | unlock: | 6547 | unlock: |
6544 | mutex_unlock(&volume_mutex); | 6548 | mutex_unlock(&volume_mutex); |
6545 | return rc; | 6549 | return rc; |
6546 | } | 6550 | } |
6547 | 6551 | ||
6552 | static int volume_alsa_set_mute(const bool mute) | ||
6553 | { | ||
6554 | dbg_printk(TPACPI_DBG_MIXER, "ALSA: trying to %smute\n", | ||
6555 | (mute) ? "" : "un"); | ||
6556 | return __volume_set_mute_ec(mute); | ||
6557 | } | ||
6558 | |||
6548 | static int volume_set_mute(const bool mute) | 6559 | static int volume_set_mute(const bool mute) |
6549 | { | 6560 | { |
6561 | int rc; | ||
6562 | |||
6550 | dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n", | 6563 | dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n", |
6551 | (mute) ? "" : "un"); | 6564 | (mute) ? "" : "un"); |
6552 | return volume_set_mute_ec(mute); | 6565 | |
6566 | rc = __volume_set_mute_ec(mute); | ||
6567 | return (rc < 0) ? rc : 0; | ||
6553 | } | 6568 | } |
6554 | 6569 | ||
6555 | static int volume_set_volume_ec(const u8 vol) | 6570 | /* returns < 0 on error, 0 on no change, 1 on change */ |
6571 | static int __volume_set_volume_ec(const u8 vol) | ||
6556 | { | 6572 | { |
6557 | int rc; | 6573 | int rc; |
6558 | u8 s, n; | 6574 | u8 s, n; |
@@ -6569,19 +6585,22 @@ static int volume_set_volume_ec(const u8 vol) | |||
6569 | 6585 | ||
6570 | n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol; | 6586 | n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol; |
6571 | 6587 | ||
6572 | if (n != s) | 6588 | if (n != s) { |
6573 | rc = volume_set_status_ec(n); | 6589 | rc = volume_set_status_ec(n); |
6590 | if (!rc) | ||
6591 | rc = 1; | ||
6592 | } | ||
6574 | 6593 | ||
6575 | unlock: | 6594 | unlock: |
6576 | mutex_unlock(&volume_mutex); | 6595 | mutex_unlock(&volume_mutex); |
6577 | return rc; | 6596 | return rc; |
6578 | } | 6597 | } |
6579 | 6598 | ||
6580 | static int volume_set_volume(const u8 vol) | 6599 | static int volume_alsa_set_volume(const u8 vol) |
6581 | { | 6600 | { |
6582 | dbg_printk(TPACPI_DBG_MIXER, | 6601 | dbg_printk(TPACPI_DBG_MIXER, |
6583 | "trying to set volume level to %hu\n", vol); | 6602 | "ALSA: trying to set volume level to %hu\n", vol); |
6584 | return volume_set_volume_ec(vol); | 6603 | return __volume_set_volume_ec(vol); |
6585 | } | 6604 | } |
6586 | 6605 | ||
6587 | static void volume_alsa_notify_change(void) | 6606 | static void volume_alsa_notify_change(void) |
@@ -6628,7 +6647,7 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol, | |||
6628 | static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, | 6647 | static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, |
6629 | struct snd_ctl_elem_value *ucontrol) | 6648 | struct snd_ctl_elem_value *ucontrol) |
6630 | { | 6649 | { |
6631 | return volume_set_volume(ucontrol->value.integer.value[0]); | 6650 | return volume_alsa_set_volume(ucontrol->value.integer.value[0]); |
6632 | } | 6651 | } |
6633 | 6652 | ||
6634 | #define volume_alsa_mute_info snd_ctl_boolean_mono_info | 6653 | #define volume_alsa_mute_info snd_ctl_boolean_mono_info |
@@ -6651,7 +6670,7 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol, | |||
6651 | static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, | 6670 | static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, |
6652 | struct snd_ctl_elem_value *ucontrol) | 6671 | struct snd_ctl_elem_value *ucontrol) |
6653 | { | 6672 | { |
6654 | return volume_set_mute(!ucontrol->value.integer.value[0]); | 6673 | return volume_alsa_set_mute(!ucontrol->value.integer.value[0]); |
6655 | } | 6674 | } |
6656 | 6675 | ||
6657 | static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = { | 6676 | static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = { |