ALSA: snd-meastro3: Document hardware volume control a bit
Hans de Goede [Wed, 21 Apr 2010 15:04:07 +0000 (11:04 -0400)]
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: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

sound/pci/maestro3.c

index b56e336..53d2a5d 100644 (file)
@@ -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)
 {
        struct snd_m3 *chip = (struct snd_m3 *) private_data;
@@ -1609,7 +1613,15 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
           values. */
        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 + HW_VOL_COUNTER_VOICE);
        outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER);
@@ -1629,7 +1641,9 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
        val = chip->ac97->regs[AC97_MASTER_VOL];
        switch (x) {
        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;
                chip->ac97->regs[AC97_MASTER_VOL] = val;
                outw(val, chip->iobase + CODEC_DATA);
@@ -1638,7 +1652,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
                               &chip->master_switch->id);
                break;
        case 0xaa:
-               /* volume up */
+               /* counters increased by 1 -> volume up */
                if ((val & 0x7f) > 0)
                        val--;
                if ((val & 0x7f00) > 0)
@@ -1650,7 +1664,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
                               &chip->master_volume->id);
                break;
        case 0x66:
-               /* volume down */
+               /* counters decreased by 1 -> volume down */
                if ((val & 0x7f) < 0x1f)
                        val++;
                if ((val & 0x7f00) < 0x1f00)