From 7873bfb866c89f9e6eab28b14d0c2007b361150c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 7 May 2012 09:24:37 +0200 Subject: [PATCH] hw/ac97: Mask out unused bits of volume controls The Linux ac97 drivers does a number of register read/write tests to see how much resolution a volume control actually has. This patch takes this into account by masking out any bits written to a volume control reg which should not be there according to the spec. After this the Linux ac97 driver correctly uses a range of 0 - 0x1f for the PCM out volume, as stated in the spec, and we can fix the FIXME in update_combined_volume_out(). This patch was also tested with a Windows XP guest without any issues. Signed-off-by: Hans de Goede Signed-off-by: malc --- hw/ac97.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index d175870798..b009257434 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -458,8 +458,7 @@ static void update_combined_volume_out (AC97LinkState *s) get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, &mute, &lvol, &rvol); - /* FIXME: should be 1f according to spec */ - get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1, + get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x1f, 1, &pmute, &plvol, &prvol); mute = mute | pmute; @@ -482,11 +481,22 @@ static void update_volume_in (AC97LinkState *s) static void set_volume (AC97LinkState *s, int index, uint32_t val) { - mixer_store (s, index, val); - if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) { + switch (index) { + case AC97_Master_Volume_Mute: + val &= 0xbf3f; + mixer_store (s, index, val); update_combined_volume_out (s); - } else if (index == AC97_Record_Gain_Mute) { + break; + case AC97_PCM_Out_Volume_Mute: + val &= 0x9f1f; + mixer_store (s, index, val); + update_combined_volume_out (s); + break; + case AC97_Record_Gain_Mute: + val &= 0x8f0f; + mixer_store (s, index, val); update_volume_in (s); + break; } }