V4L/DVB (12586): Update ALSA capture controls according to selected source.
authorOldřich Jedlička <oldium.pro@seznam.cz>
Sat, 22 Aug 2009 18:13:51 +0000 (15:13 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Sat, 12 Sep 2009 15:19:41 +0000 (12:19 -0300)
The patch introduces new snd_saa7134_capsrc_set (code taken from
snd_saa7134_capsrc_put) that updates also the ALSA capture controls during
snd_card_saa7134_capture_prepare and snd_saa7134_capsrc_put.

There can be much more work done in order to unify the control of the card
(now the card's capture source is tuned/switched in saa7134-video.c too), but
I don't have enough time. This work could be a starting point, but it can be
applied as-is too (it doesn't need any further work to make it working).

Signed-off-by: Oldřich Jedlička <oldium.pro@seznam.cz>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/saa7134/saa7134-alsa.c

index 7c0a3a3d61a6fad64ace851d7061f57574a05b99..d48c450ed77c948a0d278f7f26c6543fcc7d62b7 100644 (file)
@@ -40,6 +40,7 @@ MODULE_PARM_DESC(debug,"enable debug messages [alsa]");
  */
 
 /* defaults */
+#define MIXER_ADDR_UNSELECTED  -1
 #define MIXER_ADDR_TVTUNER     0
 #define MIXER_ADDR_LINE1       1
 #define MIXER_ADDR_LINE2       2
@@ -68,7 +69,9 @@ typedef struct snd_card_saa7134 {
        struct snd_card *card;
        spinlock_t mixer_lock;
        int mixer_volume[MIXER_ADDR_LAST+1][2];
-       int capture_source[MIXER_ADDR_LAST+1][2];
+       int capture_source_addr;
+       int capture_source[2];
+       struct snd_kcontrol *capture_ctl[MIXER_ADDR_LAST+1];
        struct pci_dev *pci;
        struct saa7134_dev *dev;
 
@@ -314,6 +317,115 @@ static int dsp_buffer_free(struct saa7134_dev *dev)
        return 0;
 }
 
+/*
+ * Setting the capture source and updating the ALSA controls
+ */
+static int snd_saa7134_capsrc_set(struct snd_kcontrol *kcontrol,
+                                 int left, int right, bool force_notify)
+{
+       snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+       int change = 0, addr = kcontrol->private_value;
+       int active, old_addr;
+       u32 anabar, xbarin;
+       int analog_io, rate;
+       struct saa7134_dev *dev;
+
+       dev = chip->dev;
+
+       spin_lock_irq(&chip->mixer_lock);
+
+       active = left != 0 || right != 0;
+       old_addr = chip->capture_source_addr;
+
+       /* The active capture source cannot be deactivated */
+       if (active) {
+               change = old_addr != addr ||
+                        chip->capture_source[0] != left ||
+                        chip->capture_source[1] != right;
+
+               chip->capture_source[0] = left;
+               chip->capture_source[1] = right;
+               chip->capture_source_addr = addr;
+               dev->dmasound.input = addr;
+       }
+       spin_unlock_irq(&chip->mixer_lock);
+
+       if (change) {
+               switch (dev->pci->device) {
+
+               case PCI_DEVICE_ID_PHILIPS_SAA7134:
+                       switch (addr) {
+                       case MIXER_ADDR_TVTUNER:
+                               saa_andorb(SAA7134_AUDIO_FORMAT_CTRL,
+                                          0xc0, 0xc0);
+                               saa_andorb(SAA7134_SIF_SAMPLE_FREQ,
+                                          0x03, 0x00);
+                               break;
+                       case MIXER_ADDR_LINE1:
+                       case MIXER_ADDR_LINE2:
+                               analog_io = (MIXER_ADDR_LINE1 == addr) ?
+                                            0x00 : 0x08;
+                               rate = (32000 == dev->dmasound.rate) ?
+                                       0x01 : 0x03;
+                               saa_andorb(SAA7134_ANALOG_IO_SELECT,
+                                          0x08, analog_io);
+                               saa_andorb(SAA7134_AUDIO_FORMAT_CTRL,
+                                          0xc0, 0x80);
+                               saa_andorb(SAA7134_SIF_SAMPLE_FREQ,
+                                          0x03, rate);
+                               break;
+                       }
+
+                       break;
+               case PCI_DEVICE_ID_PHILIPS_SAA7133:
+               case PCI_DEVICE_ID_PHILIPS_SAA7135:
+                       xbarin = 0x03; /* adc */
+                       anabar = 0;
+                       switch (addr) {
+                       case MIXER_ADDR_TVTUNER:
+                               xbarin = 0; /* Demodulator */
+                               anabar = 2; /* DACs */
+                               break;
+                       case MIXER_ADDR_LINE1:
+                               anabar = 0;  /* aux1, aux1 */
+                               break;
+                       case MIXER_ADDR_LINE2:
+                               anabar = 9;  /* aux2, aux2 */
+                               break;
+                       }
+
+                       /* output xbar always main channel */
+                       saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1,
+                                      0xbbbb10);
+
+                       if (left || right) {
+                               /* We've got data, turn the input on */
+                               saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1,
+                                              xbarin);
+                               saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
+                       } else {
+                               saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1,
+                                              0);
+                               saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
+                       }
+                       break;
+               }
+       }
+
+       if (change) {
+               if (force_notify)
+                       snd_ctl_notify(chip->card,
+                                      SNDRV_CTL_EVENT_MASK_VALUE,
+                                      &chip->capture_ctl[addr]->id);
+
+               if (old_addr != MIXER_ADDR_UNSELECTED && old_addr != addr)
+                       snd_ctl_notify(chip->card,
+                                      SNDRV_CTL_EVENT_MASK_VALUE,
+                                      &chip->capture_ctl[old_addr]->id);
+       }
+
+       return change;
+}
 
 /*
  * ALSA PCM preparation
@@ -401,6 +513,10 @@ static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream
 
        dev->dmasound.rate = runtime->rate;
 
+       /* Setup and update the card/ALSA controls */
+       snd_saa7134_capsrc_set(saa7134->capture_ctl[dev->dmasound.input], 1, 1,
+                              true);
+
        return 0;
 
 }
@@ -846,8 +962,13 @@ static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
        int addr = kcontrol->private_value;
 
        spin_lock_irq(&chip->mixer_lock);
-       ucontrol->value.integer.value[0] = chip->capture_source[addr][0];
-       ucontrol->value.integer.value[1] = chip->capture_source[addr][1];
+       if (chip->capture_source_addr == addr) {
+               ucontrol->value.integer.value[0] = chip->capture_source[0];
+               ucontrol->value.integer.value[1] = chip->capture_source[1];
+       } else {
+               ucontrol->value.integer.value[0] = 0;
+               ucontrol->value.integer.value[1] = 0;
+       }
        spin_unlock_irq(&chip->mixer_lock);
 
        return 0;
@@ -856,87 +977,22 @@ static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
 static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol,
                                  struct snd_ctl_elem_value * ucontrol)
 {
-       snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
-       int change, addr = kcontrol->private_value;
        int left, right;
-       u32 anabar, xbarin;
-       int analog_io, rate;
-       struct saa7134_dev *dev;
-
-       dev = chip->dev;
-
        left = ucontrol->value.integer.value[0] & 1;
        right = ucontrol->value.integer.value[1] & 1;
-       spin_lock_irq(&chip->mixer_lock);
 
-       change = chip->capture_source[addr][0] != left ||
-                chip->capture_source[addr][1] != right;
-       chip->capture_source[addr][0] = left;
-       chip->capture_source[addr][1] = right;
-       dev->dmasound.input=addr;
-       spin_unlock_irq(&chip->mixer_lock);
-
-
-       if (change) {
-         switch (dev->pci->device) {
-
-          case PCI_DEVICE_ID_PHILIPS_SAA7134:
-               switch (addr) {
-                       case MIXER_ADDR_TVTUNER:
-                               saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
-                               saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
-                               break;
-                       case MIXER_ADDR_LINE1:
-                       case MIXER_ADDR_LINE2:
-                               analog_io = (MIXER_ADDR_LINE1 == addr) ? 0x00 : 0x08;
-                               rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
-                               saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x08, analog_io);
-                               saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
-                               saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, rate);
-                               break;
-               }
-
-               break;
-          case PCI_DEVICE_ID_PHILIPS_SAA7133:
-          case PCI_DEVICE_ID_PHILIPS_SAA7135:
-               xbarin = 0x03; // adc
-               anabar = 0;
-               switch (addr) {
-                       case MIXER_ADDR_TVTUNER:
-                               xbarin = 0; // Demodulator
-                               anabar = 2; // DACs
-                               break;
-                       case MIXER_ADDR_LINE1:
-                               anabar = 0;  // aux1, aux1
-                               break;
-                       case MIXER_ADDR_LINE2:
-                               anabar = 9;  // aux2, aux2
-                               break;
-               }
-
-               /* output xbar always main channel */
-               saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, 0xbbbb10);
-
-               if (left || right) { // We've got data, turn the input on
-                 saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, xbarin);
-                 saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
-               } else {
-                 saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, 0);
-                 saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
-               }
-               break;
-         }
-       }
-
-       return change;
+       return snd_saa7134_capsrc_set(kcontrol, left, right, false);
 }
 
-static struct snd_kcontrol_new snd_saa7134_controls[] = {
+static struct snd_kcontrol_new snd_saa7134_volume_controls[] = {
 SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER),
-SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
 SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1),
-SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
 SAA713x_VOLUME("Line Volume", 2, MIXER_ADDR_LINE2),
+};
+
+static struct snd_kcontrol_new snd_saa7134_capture_controls[] = {
+SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
+SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
 SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
 };
 
@@ -951,17 +1007,33 @@ SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
 static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
 {
        struct snd_card *card = chip->card;
+       struct snd_kcontrol *kcontrol;
        unsigned int idx;
-       int err;
+       int err, addr;
 
        if (snd_BUG_ON(!chip))
                return -EINVAL;
        strcpy(card->mixername, "SAA7134 Mixer");
 
-       for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_controls); idx++) {
-               if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_saa7134_controls[idx], chip))) < 0)
+       for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_volume_controls); idx++) {
+               kcontrol = snd_ctl_new1(&snd_saa7134_volume_controls[idx],
+                                       chip);
+               err = snd_ctl_add(card, kcontrol);
+               if (err < 0)
                        return err;
        }
+
+       for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_capture_controls); idx++) {
+               kcontrol = snd_ctl_new1(&snd_saa7134_capture_controls[idx],
+                                       chip);
+               addr = snd_saa7134_capture_controls[idx].private_value;
+               chip->capture_ctl[addr] = kcontrol;
+               err = snd_ctl_add(card, kcontrol);
+               if (err < 0)
+                       return err;
+       }
+
+       chip->capture_source_addr = MIXER_ADDR_UNSELECTED;
        return 0;
 }