[ALSA] oxygen: add monitor controls
authorClemens Ladisch <clemens@ladisch.de>
Wed, 19 Mar 2008 07:17:33 +0000 (08:17 +0100)
committerTakashi Iwai <tiwai@suse.de>
Thu, 24 Apr 2008 10:00:27 +0000 (12:00 +0200)
Add controls to enable monitoring of the analog and digital inputs.

To allow monitoring after loading the driver when nothing has been
played back or recorded yet, the I2S input and outputs are initialized
to a valid configuration.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/oxygen_mixer.c

index 78c21155218ecb761a4055fbed2b1756a297d1a3..a1abb50eedb55d6fd8aceb5b944b9aa53aded146 100644 (file)
@@ -267,20 +267,20 @@ static void oxygen_init(struct oxygen *chip)
                      (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT));
        oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2);
        oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT,
-                      OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
-                      OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
+                      OXYGEN_RATE_48000 | chip->model->dac_i2s_format |
+                      OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
                       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
        oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
-                      OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
-                      OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
+                      OXYGEN_RATE_48000 | chip->model->adc_i2s_format |
+                      OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
                       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
        oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
-                      OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
-                      OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
+                      OXYGEN_RATE_48000 | chip->model->adc_i2s_format |
+                      OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
                       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
        oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
-                      OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
-                      OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
+                      OXYGEN_RATE_48000 | chip->model->adc_i2s_format |
+                      OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
                       OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
        oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL,
                              OXYGEN_SPDIF_SENSE_MASK |
index a8e4623415d9a2e34f8e4539f849c14e30108caa..4e77b79b3b6e4bc43baf4593f638c13c390e3942 100644 (file)
@@ -446,6 +446,50 @@ static int spdif_loopback_put(struct snd_kcontrol *ctl,
        return changed;
 }
 
+static int monitor_volume_info(struct snd_kcontrol *ctl,
+                              struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 1;
+       info->value.integer.min = 0;
+       info->value.integer.max = 1;
+       return 0;
+}
+
+static int monitor_get(struct snd_kcontrol *ctl,
+                      struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u8 bit = ctl->private_value;
+       int invert = ctl->private_value & (1 << 8);
+
+       value->value.integer.value[0] =
+               !!invert ^ !!(oxygen_read8(chip, OXYGEN_ADC_MONITOR) & bit);
+       return 0;
+}
+
+static int monitor_put(struct snd_kcontrol *ctl,
+                      struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u8 bit = ctl->private_value;
+       int invert = ctl->private_value & (1 << 8);
+       u8 oldreg, newreg;
+       int changed;
+
+       spin_lock_irq(&chip->reg_lock);
+       oldreg = oxygen_read8(chip, OXYGEN_ADC_MONITOR);
+       if ((!!value->value.integer.value[0] ^ !!invert) != 0)
+               newreg = oldreg | bit;
+       else
+               newreg = oldreg & ~bit;
+       changed = newreg != oldreg;
+       if (changed)
+               oxygen_write8(chip, OXYGEN_ADC_MONITOR, newreg);
+       spin_unlock_irq(&chip->reg_lock);
+       return changed;
+}
+
 static int ac97_switch_get(struct snd_kcontrol *ctl,
                           struct snd_ctl_elem_value *value)
 {
@@ -608,6 +652,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
                .private_value = ((codec) << 24) | (index), \
        }
 
+static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0);
 static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0);
 static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0);
 
@@ -692,6 +737,93 @@ static const struct snd_kcontrol_new controls[] = {
        },
 };
 
+static const struct snd_kcontrol_new monitor_a_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Input Monitor Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = monitor_get,
+               .put = monitor_put,
+               .private_value = OXYGEN_ADC_MONITOR_A,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Input Monitor Volume",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .info = monitor_volume_info,
+               .get = monitor_get,
+               .put = monitor_put,
+               .private_value = OXYGEN_ADC_MONITOR_A_HALF_VOL | (1 << 8),
+               .tlv = { .p = monitor_db_scale, },
+       },
+};
+static const struct snd_kcontrol_new monitor_b_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Input Monitor Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = monitor_get,
+               .put = monitor_put,
+               .private_value = OXYGEN_ADC_MONITOR_B,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Input Monitor Volume",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .info = monitor_volume_info,
+               .get = monitor_get,
+               .put = monitor_put,
+               .private_value = OXYGEN_ADC_MONITOR_B_HALF_VOL | (1 << 8),
+               .tlv = { .p = monitor_db_scale, },
+       },
+};
+static const struct snd_kcontrol_new monitor_2nd_b_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Input Monitor Switch",
+               .index = 1,
+               .info = snd_ctl_boolean_mono_info,
+               .get = monitor_get,
+               .put = monitor_put,
+               .private_value = OXYGEN_ADC_MONITOR_B,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Input Monitor Volume",
+               .index = 1,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .info = monitor_volume_info,
+               .get = monitor_get,
+               .put = monitor_put,
+               .private_value = OXYGEN_ADC_MONITOR_B_HALF_VOL | (1 << 8),
+               .tlv = { .p = monitor_db_scale, },
+       },
+};
+static const struct snd_kcontrol_new monitor_c_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Digital Input Monitor Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = monitor_get,
+               .put = monitor_put,
+               .private_value = OXYGEN_ADC_MONITOR_C,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Digital Input Monitor Volume",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .info = monitor_volume_info,
+               .get = monitor_get,
+               .put = monitor_put,
+               .private_value = OXYGEN_ADC_MONITOR_C_HALF_VOL | (1 << 8),
+               .tlv = { .p = monitor_db_scale, },
+       },
+};
+
 static const struct snd_kcontrol_new ac97_controls[] = {
        AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC),
        AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1),
@@ -778,6 +910,30 @@ int oxygen_mixer_init(struct oxygen *chip)
        err = add_controls(chip, controls, ARRAY_SIZE(controls));
        if (err < 0)
                return err;
+       if (chip->model->used_channels & OXYGEN_CHANNEL_A) {
+               err = add_controls(chip, monitor_a_controls,
+                                  ARRAY_SIZE(monitor_a_controls));
+               if (err < 0)
+                       return err;
+       } else if (chip->model->used_channels & OXYGEN_CHANNEL_B) {
+               err = add_controls(chip, monitor_b_controls,
+                                  ARRAY_SIZE(monitor_b_controls));
+               if (err < 0)
+                       return err;
+       }
+       if ((chip->model->used_channels & (OXYGEN_CHANNEL_A | OXYGEN_CHANNEL_B))
+           == (OXYGEN_CHANNEL_A | OXYGEN_CHANNEL_B)) {
+               err = add_controls(chip, monitor_2nd_b_controls,
+                                  ARRAY_SIZE(monitor_2nd_b_controls));
+               if (err < 0)
+                       return err;
+       }
+       if (chip->model->used_channels & OXYGEN_CHANNEL_C) {
+               err = add_controls(chip, monitor_c_controls,
+                                  ARRAY_SIZE(monitor_c_controls));
+               if (err < 0)
+                       return err;
+       }
        if (chip->has_ac97_0) {
                err = add_controls(chip, ac97_controls,
                                   ARRAY_SIZE(ac97_controls));