diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2010-02-27 16:45:29 -0500 |
---|---|---|
committer | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2010-02-27 16:45:29 -0500 |
commit | 88cc83772a3c7756b9f2b4ba835545ad90a08409 (patch) | |
tree | 317dd539082f7fe26227b1dcf3860433f2e7acfe | |
parent | b525c06cdbd8a3963f0173ccd23f9147d4c384b5 (diff) |
thinkpad-acpi: fix ALSA callback return status
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>
Cc: stable@kernel.org
-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 5d02cc06d1a7..e7b0c3bcef89 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -6541,7 +6541,8 @@ static int volume_set_status(const u8 status) | |||
6541 | return volume_set_status_ec(status); | 6541 | return volume_set_status_ec(status); |
6542 | } | 6542 | } |
6543 | 6543 | ||
6544 | static int volume_set_mute_ec(const bool mute) | 6544 | /* returns < 0 on error, 0 on no change, 1 on change */ |
6545 | static int __volume_set_mute_ec(const bool mute) | ||
6545 | { | 6546 | { |
6546 | int rc; | 6547 | int rc; |
6547 | u8 s, n; | 6548 | u8 s, n; |
@@ -6556,22 +6557,37 @@ static int volume_set_mute_ec(const bool mute) | |||
6556 | n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK : | 6557 | n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK : |
6557 | s & ~TP_EC_AUDIO_MUTESW_MSK; | 6558 | s & ~TP_EC_AUDIO_MUTESW_MSK; |
6558 | 6559 | ||
6559 | if (n != s) | 6560 | if (n != s) { |
6560 | rc = volume_set_status_ec(n); | 6561 | rc = volume_set_status_ec(n); |
6562 | if (!rc) | ||
6563 | rc = 1; | ||
6564 | } | ||
6561 | 6565 | ||
6562 | unlock: | 6566 | unlock: |
6563 | mutex_unlock(&volume_mutex); | 6567 | mutex_unlock(&volume_mutex); |
6564 | return rc; | 6568 | return rc; |
6565 | } | 6569 | } |
6566 | 6570 | ||
6571 | static int volume_alsa_set_mute(const bool mute) | ||
6572 | { | ||
6573 | dbg_printk(TPACPI_DBG_MIXER, "ALSA: trying to %smute\n", | ||
6574 | (mute) ? "" : "un"); | ||
6575 | return __volume_set_mute_ec(mute); | ||
6576 | } | ||
6577 | |||
6567 | static int volume_set_mute(const bool mute) | 6578 | static int volume_set_mute(const bool mute) |
6568 | { | 6579 | { |
6580 | int rc; | ||
6581 | |||
6569 | dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n", | 6582 | dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n", |
6570 | (mute) ? "" : "un"); | 6583 | (mute) ? "" : "un"); |
6571 | return volume_set_mute_ec(mute); | 6584 | |
6585 | rc = __volume_set_mute_ec(mute); | ||
6586 | return (rc < 0) ? rc : 0; | ||
6572 | } | 6587 | } |
6573 | 6588 | ||
6574 | static int volume_set_volume_ec(const u8 vol) | 6589 | /* returns < 0 on error, 0 on no change, 1 on change */ |
6590 | static int __volume_set_volume_ec(const u8 vol) | ||
6575 | { | 6591 | { |
6576 | int rc; | 6592 | int rc; |
6577 | u8 s, n; | 6593 | u8 s, n; |
@@ -6588,19 +6604,22 @@ static int volume_set_volume_ec(const u8 vol) | |||
6588 | 6604 | ||
6589 | n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol; | 6605 | n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol; |
6590 | 6606 | ||
6591 | if (n != s) | 6607 | if (n != s) { |
6592 | rc = volume_set_status_ec(n); | 6608 | rc = volume_set_status_ec(n); |
6609 | if (!rc) | ||
6610 | rc = 1; | ||
6611 | } | ||
6593 | 6612 | ||
6594 | unlock: | 6613 | unlock: |
6595 | mutex_unlock(&volume_mutex); | 6614 | mutex_unlock(&volume_mutex); |
6596 | return rc; | 6615 | return rc; |
6597 | } | 6616 | } |
6598 | 6617 | ||
6599 | static int volume_set_volume(const u8 vol) | 6618 | static int volume_alsa_set_volume(const u8 vol) |
6600 | { | 6619 | { |
6601 | dbg_printk(TPACPI_DBG_MIXER, | 6620 | dbg_printk(TPACPI_DBG_MIXER, |
6602 | "trying to set volume level to %hu\n", vol); | 6621 | "ALSA: trying to set volume level to %hu\n", vol); |
6603 | return volume_set_volume_ec(vol); | 6622 | return __volume_set_volume_ec(vol); |
6604 | } | 6623 | } |
6605 | 6624 | ||
6606 | static void volume_alsa_notify_change(void) | 6625 | static void volume_alsa_notify_change(void) |
@@ -6647,7 +6666,7 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol, | |||
6647 | static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, | 6666 | static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, |
6648 | struct snd_ctl_elem_value *ucontrol) | 6667 | struct snd_ctl_elem_value *ucontrol) |
6649 | { | 6668 | { |
6650 | return volume_set_volume(ucontrol->value.integer.value[0]); | 6669 | return volume_alsa_set_volume(ucontrol->value.integer.value[0]); |
6651 | } | 6670 | } |
6652 | 6671 | ||
6653 | #define volume_alsa_mute_info snd_ctl_boolean_mono_info | 6672 | #define volume_alsa_mute_info snd_ctl_boolean_mono_info |
@@ -6670,7 +6689,7 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol, | |||
6670 | static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, | 6689 | static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, |
6671 | struct snd_ctl_elem_value *ucontrol) | 6690 | struct snd_ctl_elem_value *ucontrol) |
6672 | { | 6691 | { |
6673 | return volume_set_mute(!ucontrol->value.integer.value[0]); | 6692 | return volume_alsa_set_mute(!ucontrol->value.integer.value[0]); |
6674 | } | 6693 | } |
6675 | 6694 | ||
6676 | static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = { | 6695 | static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = { |