aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2010-02-27 16:45:29 -0500
committerHenrique de Moraes Holschuh <hmh@hmh.eng.br>2010-02-27 16:45:29 -0500
commit88cc83772a3c7756b9f2b4ba835545ad90a08409 (patch)
tree317dd539082f7fe26227b1dcf3860433f2e7acfe
parentb525c06cdbd8a3963f0173ccd23f9147d4c384b5 (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.c39
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
6544static int volume_set_mute_ec(const bool mute) 6544/* returns < 0 on error, 0 on no change, 1 on change */
6545static 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
6562unlock: 6566unlock:
6563 mutex_unlock(&volume_mutex); 6567 mutex_unlock(&volume_mutex);
6564 return rc; 6568 return rc;
6565} 6569}
6566 6570
6571static 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
6567static int volume_set_mute(const bool mute) 6578static 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
6574static int volume_set_volume_ec(const u8 vol) 6589/* returns < 0 on error, 0 on no change, 1 on change */
6590static 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
6594unlock: 6613unlock:
6595 mutex_unlock(&volume_mutex); 6614 mutex_unlock(&volume_mutex);
6596 return rc; 6615 return rc;
6597} 6616}
6598 6617
6599static int volume_set_volume(const u8 vol) 6618static 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
6606static void volume_alsa_notify_change(void) 6625static void volume_alsa_notify_change(void)
@@ -6647,7 +6666,7 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol,
6647static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, 6666static 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,
6670static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, 6689static 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
6676static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = { 6695static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = {