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 = { |
