|
@@ -122,6 +122,18 @@ static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = {
|
|
|
.mask = 0,
|
|
|
};
|
|
|
#endif
|
|
|
+
|
|
|
+static void vortex_notify_pcm_vol_change(struct snd_card *card,
|
|
|
+ struct snd_kcontrol *kctl, int activate)
|
|
|
+{
|
|
|
+ if (activate)
|
|
|
+ kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
|
|
+ else
|
|
|
+ kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
|
|
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE |
|
|
|
+ SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id));
|
|
|
+}
|
|
|
+
|
|
|
/* open callback */
|
|
|
static int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
|
|
|
{
|
|
@@ -230,12 +242,14 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
|
|
|
if (stream != NULL)
|
|
|
vortex_adb_allocroute(chip, stream->dma,
|
|
|
stream->nr_ch, stream->dir,
|
|
|
- stream->type);
|
|
|
+ stream->type,
|
|
|
+ substream->number);
|
|
|
/* Alloc routes. */
|
|
|
dma =
|
|
|
vortex_adb_allocroute(chip, -1,
|
|
|
params_channels(hw_params),
|
|
|
- substream->stream, type);
|
|
|
+ substream->stream, type,
|
|
|
+ substream->number);
|
|
|
if (dma < 0) {
|
|
|
spin_unlock_irq(&chip->lock);
|
|
|
return dma;
|
|
@@ -246,6 +260,11 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
|
|
|
vortex_adbdma_setbuffers(chip, dma,
|
|
|
params_period_bytes(hw_params),
|
|
|
params_periods(hw_params));
|
|
|
+ if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
|
|
|
+ chip->pcm_vol[substream->number].active = 1;
|
|
|
+ vortex_notify_pcm_vol_change(chip->card,
|
|
|
+ chip->pcm_vol[substream->number].kctl, 1);
|
|
|
+ }
|
|
|
}
|
|
|
#ifndef CHIP_AU8810
|
|
|
else {
|
|
@@ -275,10 +294,18 @@ static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream)
|
|
|
spin_lock_irq(&chip->lock);
|
|
|
// Delete audio routes.
|
|
|
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
|
|
|
- if (stream != NULL)
|
|
|
+ if (stream != NULL) {
|
|
|
+ if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
|
|
|
+ chip->pcm_vol[substream->number].active = 0;
|
|
|
+ vortex_notify_pcm_vol_change(chip->card,
|
|
|
+ chip->pcm_vol[substream->number].kctl,
|
|
|
+ 0);
|
|
|
+ }
|
|
|
vortex_adb_allocroute(chip, stream->dma,
|
|
|
stream->nr_ch, stream->dir,
|
|
|
- stream->type);
|
|
|
+ stream->type,
|
|
|
+ substream->number);
|
|
|
+ }
|
|
|
}
|
|
|
#ifndef CHIP_AU8810
|
|
|
else {
|
|
@@ -506,6 +533,83 @@ static struct snd_kcontrol_new snd_vortex_mixer_spdif[] __devinitdata = {
|
|
|
},
|
|
|
};
|
|
|
|
|
|
+/* subdevice PCM Volume control */
|
|
|
+
|
|
|
+static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_info *uinfo)
|
|
|
+{
|
|
|
+ vortex_t *vortex = snd_kcontrol_chip(kcontrol);
|
|
|
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
|
|
+ uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
|
|
|
+ uinfo->value.integer.min = -128;
|
|
|
+ uinfo->value.integer.max = 32;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_value *ucontrol)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ vortex_t *vortex = snd_kcontrol_chip(kcontrol);
|
|
|
+ int subdev = kcontrol->id.subdevice;
|
|
|
+ struct pcm_vol *p = &vortex->pcm_vol[subdev];
|
|
|
+ int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
|
|
|
+ for (i = 0; i < max_chn; i++)
|
|
|
+ ucontrol->value.integer.value[i] = p->vol[i];
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_ctl_elem_value *ucontrol)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int changed = 0;
|
|
|
+ int mixin;
|
|
|
+ unsigned char vol;
|
|
|
+ vortex_t *vortex = snd_kcontrol_chip(kcontrol);
|
|
|
+ int subdev = kcontrol->id.subdevice;
|
|
|
+ struct pcm_vol *p = &vortex->pcm_vol[subdev];
|
|
|
+ int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
|
|
|
+ for (i = 0; i < max_chn; i++) {
|
|
|
+ if (p->vol[i] != ucontrol->value.integer.value[i]) {
|
|
|
+ p->vol[i] = ucontrol->value.integer.value[i];
|
|
|
+ if (p->active) {
|
|
|
+ switch (vortex->dma_adb[p->dma].nr_ch) {
|
|
|
+ case 1:
|
|
|
+ mixin = p->mixin[0];
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ default:
|
|
|
+ mixin = p->mixin[(i < 2) ? i : (i - 2)];
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ mixin = p->mixin[i];
|
|
|
+ break;
|
|
|
+ };
|
|
|
+ vol = p->vol[i];
|
|
|
+ vortex_mix_setinputvolumebyte(vortex,
|
|
|
+ vortex->mixplayb[i], mixin, vol);
|
|
|
+ }
|
|
|
+ changed = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return changed;
|
|
|
+}
|
|
|
+
|
|
|
+static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400);
|
|
|
+
|
|
|
+static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = {
|
|
|
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
|
|
+ .name = "PCM Playback Volume",
|
|
|
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
|
|
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
|
|
|
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE,
|
|
|
+ .info = snd_vortex_pcm_vol_info,
|
|
|
+ .get = snd_vortex_pcm_vol_get,
|
|
|
+ .put = snd_vortex_pcm_vol_put,
|
|
|
+ .tlv = { .p = vortex_pcm_vol_db_scale },
|
|
|
+};
|
|
|
+
|
|
|
/* create a pcm device */
|
|
|
static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
|
|
|
{
|
|
@@ -555,5 +659,20 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
|
|
|
return err;
|
|
|
}
|
|
|
}
|
|
|
+ if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) {
|
|
|
+ for (i = 0; i < NR_PCM; i++) {
|
|
|
+ chip->pcm_vol[i].active = 0;
|
|
|
+ chip->pcm_vol[i].dma = -1;
|
|
|
+ kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip);
|
|
|
+ if (!kctl)
|
|
|
+ return -ENOMEM;
|
|
|
+ chip->pcm_vol[i].kctl = kctl;
|
|
|
+ kctl->id.device = 0;
|
|
|
+ kctl->id.subdevice = i;
|
|
|
+ err = snd_ctl_add(chip->card, kctl);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|