Commit 20133d4c authored by Hans de Goede's avatar Hans de Goede Committed by Takashi Iwai

ALSA: snd-meastro3: Document hardware volume control a bit

While working on a fix for the volume being muted on the allegro in my
Compaq EVO N600C after suspend, I've learned a few things about the hardware
volume control worth documenting. The actual fix for the suspend / resume
issue is in the next patch in this set.
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 6458a544
...@@ -1598,6 +1598,10 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s) ...@@ -1598,6 +1598,10 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s)
} }
} }
/* The m3's hardware volume works by incrementing / decrementing 2 counters
(without wrap around) in response to volume button presses and then
generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7
of a byte wide register. The meaning of bits 0 and 4 is unknown. */
static void snd_m3_update_hw_volume(unsigned long private_data) static void snd_m3_update_hw_volume(unsigned long private_data)
{ {
struct snd_m3 *chip = (struct snd_m3 *) private_data; struct snd_m3 *chip = (struct snd_m3 *) private_data;
...@@ -1609,7 +1613,15 @@ static void snd_m3_update_hw_volume(unsigned long private_data) ...@@ -1609,7 +1613,15 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
values. */ values. */
x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee; x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee;
/* Reset the volume control registers. */ /* Reset the volume counters to 4. Tests on the allegro integrated
into a Compaq N600C laptop, have revealed that:
1) Writing any value will result in the 2 counters being reset to
4 so writing 0x88 is not strictly necessary
2) Writing to any of the 4 involved registers will reset all 4
of them (and reading them always returns the same value for all
of them)
It could be that a maestro deviates from this, so leave the code
as is. */
outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE); outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE);
outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE); outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE);
outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER);
...@@ -1629,7 +1641,9 @@ static void snd_m3_update_hw_volume(unsigned long private_data) ...@@ -1629,7 +1641,9 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
val = chip->ac97->regs[AC97_MASTER_VOL]; val = chip->ac97->regs[AC97_MASTER_VOL];
switch (x) { switch (x) {
case 0x88: case 0x88:
/* mute */ /* The counters have not changed, yet we've received a HV
interrupt. According to tests run by various people this
happens when pressing the mute button. */
val ^= 0x8000; val ^= 0x8000;
chip->ac97->regs[AC97_MASTER_VOL] = val; chip->ac97->regs[AC97_MASTER_VOL] = val;
outw(val, chip->iobase + CODEC_DATA); outw(val, chip->iobase + CODEC_DATA);
...@@ -1638,7 +1652,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data) ...@@ -1638,7 +1652,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
&chip->master_switch->id); &chip->master_switch->id);
break; break;
case 0xaa: case 0xaa:
/* volume up */ /* counters increased by 1 -> volume up */
if ((val & 0x7f) > 0) if ((val & 0x7f) > 0)
val--; val--;
if ((val & 0x7f00) > 0) if ((val & 0x7f00) > 0)
...@@ -1650,7 +1664,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data) ...@@ -1650,7 +1664,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
&chip->master_volume->id); &chip->master_volume->id);
break; break;
case 0x66: case 0x66:
/* volume down */ /* counters decreased by 1 -> volume down */
if ((val & 0x7f) < 0x1f) if ((val & 0x7f) < 0x1f)
val++; val++;
if ((val & 0x7f00) < 0x1f00) if ((val & 0x7f00) < 0x1f00)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment