Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
[cascardo/linux.git] / sound / isa / es18xx.c
index 6faaac6..b481bb8 100644 (file)
@@ -156,6 +156,7 @@ struct snd_es18xx {
 #define ES18XX_I2S     0x0200  /* I2S mixer control */
 #define ES18XX_MUTEREC 0x0400  /* Record source can be muted */
 #define ES18XX_CONTROL 0x0800  /* Has control ports */
+#define ES18XX_GPO_2BIT        0x1000  /* GPO0,1 controlled by PM port */
 
 /* Power Management */
 #define ES18XX_PM      0x07
@@ -964,44 +965,28 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream)
 
 static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts5Source[5] = {
+       static const char * const texts5Source[5] = {
                "Mic", "CD", "Line", "Master", "Mix"
        };
-       static char *texts8Source[8] = {
+       static const char * const texts8Source[8] = {
                "Mic", "Mic Master", "CD", "AOUT",
                "Mic1", "Mix", "Line", "Master"
        };
        struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
 
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
        switch (chip->version) {
        case 0x1868:
        case 0x1878:
-               uinfo->value.enumerated.items = 4;
-               if (uinfo->value.enumerated.item > 3)
-                       uinfo->value.enumerated.item = 3;
-               strcpy(uinfo->value.enumerated.name,
-                       texts5Source[uinfo->value.enumerated.item]);
-               break;
+               return snd_ctl_enum_info(uinfo, 1, 4, texts5Source);
        case 0x1887:
        case 0x1888:
-               uinfo->value.enumerated.items = 5;
-               if (uinfo->value.enumerated.item > 4)
-                       uinfo->value.enumerated.item = 4;
-               strcpy(uinfo->value.enumerated.name, texts5Source[uinfo->value.enumerated.item]);
-               break;
+               return snd_ctl_enum_info(uinfo, 1, 5, texts5Source);
        case 0x1869: /* DS somewhat contradictory for 1869: could be be 5 or 8 */
        case 0x1879:
-               uinfo->value.enumerated.items = 8;
-               if (uinfo->value.enumerated.item > 7)
-                       uinfo->value.enumerated.item = 7;
-               strcpy(uinfo->value.enumerated.name, texts8Source[uinfo->value.enumerated.item]);
-               break;
+               return snd_ctl_enum_info(uinfo, 1, 8, texts8Source);
        default:
                return -EINVAL;
        }
-       return 0;
 }
 
 static int snd_es18xx_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1136,11 +1121,14 @@ static int snd_es18xx_reg_read(struct snd_es18xx *chip, unsigned char reg)
                return snd_es18xx_read(chip, reg);
 }
 
-#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, invert) \
+#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, flags) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_es18xx_info_single, \
   .get = snd_es18xx_get_single, .put = snd_es18xx_put_single, \
-  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
+  .private_value = reg | (shift << 8) | (mask << 16) | (flags << 24) }
+
+#define ES18XX_FL_INVERT       (1 << 0)
+#define ES18XX_FL_PMPORT       (1 << 1)
 
 static int snd_es18xx_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
@@ -1159,10 +1147,14 @@ static int snd_es18xx_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        int reg = kcontrol->private_value & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0xff;
        int mask = (kcontrol->private_value >> 16) & 0xff;
-       int invert = (kcontrol->private_value >> 24) & 0xff;
+       int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT;
+       int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT;
        int val;
-       
-       val = snd_es18xx_reg_read(chip, reg);
+
+       if (pm_port)
+               val = inb(chip->port + ES18XX_PM);
+       else
+               val = snd_es18xx_reg_read(chip, reg);
        ucontrol->value.integer.value[0] = (val >> shift) & mask;
        if (invert)
                ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
@@ -1175,7 +1167,8 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        int reg = kcontrol->private_value & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0xff;
        int mask = (kcontrol->private_value >> 16) & 0xff;
-       int invert = (kcontrol->private_value >> 24) & 0xff;
+       int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT;
+       int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT;
        unsigned char val;
        
        val = (ucontrol->value.integer.value[0] & mask);
@@ -1183,6 +1176,15 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
                val = mask - val;
        mask <<= shift;
        val <<= shift;
+       if (pm_port) {
+               unsigned char cur = inb(chip->port + ES18XX_PM);
+
+               if ((cur & mask) == val)
+                       return 0;
+               outb((cur & ~mask) | val, chip->port + ES18XX_PM);
+               return 1;
+       }
+
        return snd_es18xx_reg_bits(chip, reg, mask, val) != val;
 }
 
@@ -1304,7 +1306,7 @@ static struct snd_kcontrol_new snd_es18xx_opt_speaker =
        ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0);
 
 static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
-ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
+ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, ES18XX_FL_INVERT),
 ES18XX_SINGLE("Video Playback Switch", 0, 0x7f, 0, 1, 0),
 ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
 ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
@@ -1363,6 +1365,11 @@ static struct snd_kcontrol_new snd_es18xx_hw_volume_controls[] = {
 ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
 };
 
+static struct snd_kcontrol_new snd_es18xx_opt_gpo_2bit[] = {
+ES18XX_SINGLE("GPO0 Switch", 0, ES18XX_PM, 0, 1, ES18XX_FL_PMPORT),
+ES18XX_SINGLE("GPO1 Switch", 0, ES18XX_PM, 1, 1, ES18XX_FL_PMPORT),
+};
+
 static int snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
 {
        int data;
@@ -1629,10 +1636,10 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
 
        switch (chip->version) {
        case 0x1868:
-               chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL;
+               chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL | ES18XX_GPO_2BIT;
                break;
        case 0x1869:
-               chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV;
+               chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV | ES18XX_GPO_2BIT;
                break;
        case 0x1878:
                chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL;
@@ -1642,7 +1649,7 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
                break;
        case 0x1887:
        case 0x1888:
-               chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
+               chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_GPO_2BIT;
                break;
        default:
                snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n",
@@ -1944,6 +1951,15 @@ static int snd_es18xx_mixer(struct snd_card *card)
                                return err;
                }
        }
+       if (chip->caps & ES18XX_GPO_2BIT) {
+               for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_gpo_2bit); idx++) {
+                       err = snd_ctl_add(card,
+                                         snd_ctl_new1(&snd_es18xx_opt_gpo_2bit[idx],
+                                                      chip));
+                       if (err < 0)
+                               return err;
+               }
+       }
        return 0;
 }