|
@@ -156,6 +156,7 @@ struct snd_es18xx {
|
|
#define ES18XX_I2S 0x0200 /* I2S mixer control */
|
|
#define ES18XX_I2S 0x0200 /* I2S mixer control */
|
|
#define ES18XX_MUTEREC 0x0400 /* Record source can be muted */
|
|
#define ES18XX_MUTEREC 0x0400 /* Record source can be muted */
|
|
#define ES18XX_CONTROL 0x0800 /* Has control ports */
|
|
#define ES18XX_CONTROL 0x0800 /* Has control ports */
|
|
|
|
+#define ES18XX_GPO_2BIT 0x1000 /* GPO0,1 controlled by PM port */
|
|
|
|
|
|
/* Power Management */
|
|
/* Power Management */
|
|
#define ES18XX_PM 0x07
|
|
#define ES18XX_PM 0x07
|
|
@@ -1120,11 +1121,14 @@ static int snd_es18xx_reg_read(struct snd_es18xx *chip, unsigned char reg)
|
|
return snd_es18xx_read(chip, 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, \
|
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
|
|
.info = snd_es18xx_info_single, \
|
|
.info = snd_es18xx_info_single, \
|
|
.get = snd_es18xx_get_single, .put = snd_es18xx_put_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)
|
|
static int snd_es18xx_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
|
|
{
|
|
{
|
|
@@ -1143,10 +1147,14 @@ static int snd_es18xx_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
|
int reg = kcontrol->private_value & 0xff;
|
|
int reg = kcontrol->private_value & 0xff;
|
|
int shift = (kcontrol->private_value >> 8) & 0xff;
|
|
int shift = (kcontrol->private_value >> 8) & 0xff;
|
|
int mask = (kcontrol->private_value >> 16) & 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;
|
|
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;
|
|
ucontrol->value.integer.value[0] = (val >> shift) & mask;
|
|
if (invert)
|
|
if (invert)
|
|
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
|
|
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
|
|
@@ -1159,7 +1167,8 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
|
int reg = kcontrol->private_value & 0xff;
|
|
int reg = kcontrol->private_value & 0xff;
|
|
int shift = (kcontrol->private_value >> 8) & 0xff;
|
|
int shift = (kcontrol->private_value >> 8) & 0xff;
|
|
int mask = (kcontrol->private_value >> 16) & 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;
|
|
unsigned char val;
|
|
|
|
|
|
val = (ucontrol->value.integer.value[0] & mask);
|
|
val = (ucontrol->value.integer.value[0] & mask);
|
|
@@ -1167,6 +1176,15 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
|
|
val = mask - val;
|
|
val = mask - val;
|
|
mask <<= shift;
|
|
mask <<= shift;
|
|
val <<= 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;
|
|
return snd_es18xx_reg_bits(chip, reg, mask, val) != val;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1288,7 +1306,7 @@ static struct snd_kcontrol_new snd_es18xx_opt_speaker =
|
|
ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0);
|
|
ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0);
|
|
|
|
|
|
static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
|
|
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_SINGLE("Video Playback Switch", 0, 0x7f, 0, 1, 0),
|
|
ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 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)
|
|
ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
|
|
@@ -1347,6 +1365,11 @@ static struct snd_kcontrol_new snd_es18xx_hw_volume_controls[] = {
|
|
ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
|
|
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)
|
|
static int snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
|
|
{
|
|
{
|
|
int data;
|
|
int data;
|
|
@@ -1613,10 +1636,10 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
|
|
|
|
|
|
switch (chip->version) {
|
|
switch (chip->version) {
|
|
case 0x1868:
|
|
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;
|
|
break;
|
|
case 0x1869:
|
|
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;
|
|
break;
|
|
case 0x1878:
|
|
case 0x1878:
|
|
chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL;
|
|
chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL;
|
|
@@ -1626,7 +1649,7 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
|
|
break;
|
|
break;
|
|
case 0x1887:
|
|
case 0x1887:
|
|
case 0x1888:
|
|
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;
|
|
break;
|
|
default:
|
|
default:
|
|
snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n",
|
|
snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n",
|
|
@@ -1928,6 +1951,15 @@ static int snd_es18xx_mixer(struct snd_card *card)
|
|
return err;
|
|
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;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|