return 0;
 }
 
-static int set_ac97_em202_input(struct em28xx *dev)
+struct em28xx_input_table {
+       enum em28xx_amux amux;
+       u8               reg;
+};
+
+static struct em28xx_input_table inputs[] = {
+       { EM28XX_AMUX_VIDEO,    AC97_VIDEO_VOL   },
+       { EM28XX_AMUX_LINE_IN,  AC97_LINEIN_VOL  },
+       { EM28XX_AMUX_PHONE,    AC97_PHONE_VOL   },
+       { EM28XX_AMUX_MIC,      AC97_MIC_VOL     },
+       { EM28XX_AMUX_CD,       AC97_CD_VOL      },
+       { EM28XX_AMUX_AUX,      AC97_AUX_VOL     },
+       { EM28XX_AMUX_PCM_OUT,  AC97_PCM_OUT_VOL },
+};
+
+static int set_ac97_input(struct em28xx *dev)
 {
-       int ret;
-       u16 enable  = 0x0808;           /* 12 dB attenuation Left/Right */
-       u16 disable = 0x8808;           /* bit 15 - mute volumme */
-       u16 video, line;
-
-       if (dev->ctl_ainput == EM28XX_AMUX_VIDEO) {
-               video = enable;
-               line = disable;
-       } else {
-               video = disable;
-               line  = enable;
-       }
+       int ret, i;
+       enum em28xx_amux amux = dev->ctl_ainput;
 
-       /* Sets em202 AC97 mixer registers */
-       ret = em28xx_write_ac97(dev, AC97_VIDEO_VOL, video);
-       if (ret < 0)
-               return ret;
+       /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that
+          em28xx should point to LINE IN, while AC97 should use VIDEO
+        */
+       if (amux == EM28XX_AMUX_VIDEO2)
+               amux = dev->ctl_ainput;
 
-       ret = em28xx_write_ac97(dev, AC97_LINEIN_VOL, line);
+       /* Mute all entres but the one that were selected */
+       for (i = 0; i < ARRAY_SIZE(inputs); i++) {
+               if (amux == inputs[i].amux)
+                       ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808);
+               else
+                       ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000);
 
-       return ret;
+               if (ret < 0)
+                       em28xx_warn("couldn't setup AC97 register %d\n",
+                                    inputs[i].reg);
+       }
+       return 0;
 }
 
 static int em28xx_set_audio_source(struct em28xx *dev)
        u8 input;
 
        if (dev->is_em2800) {
-               if (dev->ctl_ainput)
-                       input = EM2800_AUDIO_SRC_LINE;
-               else
+               if (dev->ctl_ainput == EM28XX_AMUX_VIDEO)
                        input = EM2800_AUDIO_SRC_TUNER;
+               else
+                       input = EM2800_AUDIO_SRC_LINE;
 
                ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
                if (ret < 0)
        switch (dev->audio_mode.ac97) {
        case EM28XX_NO_AC97:
                break;
-       case EM28XX_AC97_OTHER:
-               /* We don't know how to handle this chip.
-                  Let's hope it is close enough to em202 to work
-                */
-       case EM28XX_AC97_EM202:
-               ret = set_ac97_em202_input(dev);
-               break;
+       default:
+               ret = set_ac97_input(dev);
        }
 
-       return 0;
+       return ret;
 }
 
 int em28xx_audio_analog_set(struct em28xx *dev)
        if (!dev->audio_mode.has_audio)
                return 0;
 
+       /* It is assumed that all devices use master volume for output.
+          It would be possible to use also line output.
+        */
        if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
                /* Mute */
                ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, 0x8000);
 
 
 /* Standard AC97 registers */
 #define AC97_RESET               0x00
+
+       /* Output volumes */
 #define AC97_MASTER_VOL          0x02
-#define AC97_LINE_LEVEL_VOL      0x04
+#define AC97_LINE_LEVEL_VOL      0x04  /* Some devices use for headphones */
 #define AC97_MASTER_MONO_VOL     0x06
 
+       /* Input volumes */
 #define AC97_PC_BEEP_VOL         0x0a
 #define AC97_PHONE_VOL           0x0c
 #define AC97_MIC_VOL             0x0e
 #define AC97_VIDEO_VOL           0x14
 #define AC97_AUX_VOL             0x16
 #define AC97_PCM_OUT_VOL         0x18
+
+       /* capture registers */
 #define AC97_RECORD_SELECT       0x1a
 #define AC97_RECORD_GAIN         0x1c
+
+       /* control registers */
 #define AC97_GENERAL_PURPOSE     0x20
 #define AC97_3D_CTRL             0x22
 #define AC97_AUD_INT_AND_PAG     0x24
 #define AC97_PCM_OUT_SURR_SRATE  0x2e
 #define AC97_PCM_OUT_LFE_SRATE   0x30
 #define AC97_PCM_IN_SRATE        0x32
+
+       /* For devices with more than 2 channels, extra output volumes */
 #define AC97_LFE_MASTER_VOL      0x36
 #define AC97_SURR_MASTER_VOL     0x38
+
+       /* Digital SPDIF output control */
 #define AC97_SPDIF_OUT_CTRL      0x3a
 
+       /* Vendor ID identifier */
 #define AC97_VENDOR_ID1          0x7c
 #define AC97_VENDOR_ID2          0x7e
 
 
        unsigned int i2s_5rates:1;
 };
 
+/* em28xx has two audio inputs: tuner and line in.
+   However, on most devices, an auxiliary AC97 codec device is used.
+   The AC97 device may have several different inputs and outputs,
+   depending on their model. So, it is possible to use AC97 mixer to
+   address more than two different entries.
+ */
 enum em28xx_amux {
-       EM28XX_AMUX_VIDEO,
-       EM28XX_AMUX_LINE_IN,
+       /* This is the only entry for em28xx tuner input */
+       EM28XX_AMUX_VIDEO,      /* em28xx tuner, AC97 mixer Video */
+
+       EM28XX_AMUX_LINE_IN,    /* AC97 mixer Line In */
+
+       /* Some less-common mixer setups */
+       EM28XX_AMUX_VIDEO2,     /* em28xx Line in, AC97 mixer Video */
+       EM28XX_AMUX_PHONE,
+       EM28XX_AMUX_MIC,
+       EM28XX_AMUX_CD,
+       EM28XX_AMUX_AUX,
+       EM28XX_AMUX_PCM_OUT,
 };
 
 struct em28xx_input {