diff options
Diffstat (limited to 'sound/pci/au88x0/au88x0_pcm.c')
-rw-r--r-- | sound/pci/au88x0/au88x0_pcm.c | 127 |
1 files changed, 123 insertions, 4 deletions
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 0ef2f9712208..e59f120742a4 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c | |||
@@ -122,6 +122,18 @@ static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { | |||
122 | .mask = 0, | 122 | .mask = 0, |
123 | }; | 123 | }; |
124 | #endif | 124 | #endif |
125 | |||
126 | static void vortex_notify_pcm_vol_change(struct snd_card *card, | ||
127 | struct snd_kcontrol *kctl, int activate) | ||
128 | { | ||
129 | if (activate) | ||
130 | kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
131 | else | ||
132 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
133 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE | | ||
134 | SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id)); | ||
135 | } | ||
136 | |||
125 | /* open callback */ | 137 | /* open callback */ |
126 | static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) | 138 | static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) |
127 | { | 139 | { |
@@ -230,12 +242,14 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, | |||
230 | if (stream != NULL) | 242 | if (stream != NULL) |
231 | vortex_adb_allocroute(chip, stream->dma, | 243 | vortex_adb_allocroute(chip, stream->dma, |
232 | stream->nr_ch, stream->dir, | 244 | stream->nr_ch, stream->dir, |
233 | stream->type); | 245 | stream->type, |
246 | substream->number); | ||
234 | /* Alloc routes. */ | 247 | /* Alloc routes. */ |
235 | dma = | 248 | dma = |
236 | vortex_adb_allocroute(chip, -1, | 249 | vortex_adb_allocroute(chip, -1, |
237 | params_channels(hw_params), | 250 | params_channels(hw_params), |
238 | substream->stream, type); | 251 | substream->stream, type, |
252 | substream->number); | ||
239 | if (dma < 0) { | 253 | if (dma < 0) { |
240 | spin_unlock_irq(&chip->lock); | 254 | spin_unlock_irq(&chip->lock); |
241 | return dma; | 255 | return dma; |
@@ -246,6 +260,11 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, | |||
246 | vortex_adbdma_setbuffers(chip, dma, | 260 | vortex_adbdma_setbuffers(chip, dma, |
247 | params_period_bytes(hw_params), | 261 | params_period_bytes(hw_params), |
248 | params_periods(hw_params)); | 262 | params_periods(hw_params)); |
263 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { | ||
264 | chip->pcm_vol[substream->number].active = 1; | ||
265 | vortex_notify_pcm_vol_change(chip->card, | ||
266 | chip->pcm_vol[substream->number].kctl, 1); | ||
267 | } | ||
249 | } | 268 | } |
250 | #ifndef CHIP_AU8810 | 269 | #ifndef CHIP_AU8810 |
251 | else { | 270 | else { |
@@ -275,10 +294,18 @@ static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream) | |||
275 | spin_lock_irq(&chip->lock); | 294 | spin_lock_irq(&chip->lock); |
276 | // Delete audio routes. | 295 | // Delete audio routes. |
277 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | 296 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { |
278 | if (stream != NULL) | 297 | if (stream != NULL) { |
298 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { | ||
299 | chip->pcm_vol[substream->number].active = 0; | ||
300 | vortex_notify_pcm_vol_change(chip->card, | ||
301 | chip->pcm_vol[substream->number].kctl, | ||
302 | 0); | ||
303 | } | ||
279 | vortex_adb_allocroute(chip, stream->dma, | 304 | vortex_adb_allocroute(chip, stream->dma, |
280 | stream->nr_ch, stream->dir, | 305 | stream->nr_ch, stream->dir, |
281 | stream->type); | 306 | stream->type, |
307 | substream->number); | ||
308 | } | ||
282 | } | 309 | } |
283 | #ifndef CHIP_AU8810 | 310 | #ifndef CHIP_AU8810 |
284 | else { | 311 | else { |
@@ -506,6 +533,83 @@ static struct snd_kcontrol_new snd_vortex_mixer_spdif[] __devinitdata = { | |||
506 | }, | 533 | }, |
507 | }; | 534 | }; |
508 | 535 | ||
536 | /* subdevice PCM Volume control */ | ||
537 | |||
538 | static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol, | ||
539 | struct snd_ctl_elem_info *uinfo) | ||
540 | { | ||
541 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | ||
542 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
543 | uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2); | ||
544 | uinfo->value.integer.min = -128; | ||
545 | uinfo->value.integer.max = 32; | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol, | ||
550 | struct snd_ctl_elem_value *ucontrol) | ||
551 | { | ||
552 | int i; | ||
553 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | ||
554 | int subdev = kcontrol->id.subdevice; | ||
555 | struct pcm_vol *p = &vortex->pcm_vol[subdev]; | ||
556 | int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); | ||
557 | for (i = 0; i < max_chn; i++) | ||
558 | ucontrol->value.integer.value[i] = p->vol[i]; | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol, | ||
563 | struct snd_ctl_elem_value *ucontrol) | ||
564 | { | ||
565 | int i; | ||
566 | int changed = 0; | ||
567 | int mixin; | ||
568 | unsigned char vol; | ||
569 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | ||
570 | int subdev = kcontrol->id.subdevice; | ||
571 | struct pcm_vol *p = &vortex->pcm_vol[subdev]; | ||
572 | int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); | ||
573 | for (i = 0; i < max_chn; i++) { | ||
574 | if (p->vol[i] != ucontrol->value.integer.value[i]) { | ||
575 | p->vol[i] = ucontrol->value.integer.value[i]; | ||
576 | if (p->active) { | ||
577 | switch (vortex->dma_adb[p->dma].nr_ch) { | ||
578 | case 1: | ||
579 | mixin = p->mixin[0]; | ||
580 | break; | ||
581 | case 2: | ||
582 | default: | ||
583 | mixin = p->mixin[(i < 2) ? i : (i - 2)]; | ||
584 | break; | ||
585 | case 4: | ||
586 | mixin = p->mixin[i]; | ||
587 | break; | ||
588 | }; | ||
589 | vol = p->vol[i]; | ||
590 | vortex_mix_setinputvolumebyte(vortex, | ||
591 | vortex->mixplayb[i], mixin, vol); | ||
592 | } | ||
593 | changed = 1; | ||
594 | } | ||
595 | } | ||
596 | return changed; | ||
597 | } | ||
598 | |||
599 | static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400); | ||
600 | |||
601 | static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = { | ||
602 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
603 | .name = "PCM Playback Volume", | ||
604 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
605 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | ||
606 | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | ||
607 | .info = snd_vortex_pcm_vol_info, | ||
608 | .get = snd_vortex_pcm_vol_get, | ||
609 | .put = snd_vortex_pcm_vol_put, | ||
610 | .tlv = { .p = vortex_pcm_vol_db_scale }, | ||
611 | }; | ||
612 | |||
509 | /* create a pcm device */ | 613 | /* create a pcm device */ |
510 | static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) | 614 | static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) |
511 | { | 615 | { |
@@ -555,5 +659,20 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) | |||
555 | return err; | 659 | return err; |
556 | } | 660 | } |
557 | } | 661 | } |
662 | if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) { | ||
663 | for (i = 0; i < NR_PCM; i++) { | ||
664 | chip->pcm_vol[i].active = 0; | ||
665 | chip->pcm_vol[i].dma = -1; | ||
666 | kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip); | ||
667 | if (!kctl) | ||
668 | return -ENOMEM; | ||
669 | chip->pcm_vol[i].kctl = kctl; | ||
670 | kctl->id.device = 0; | ||
671 | kctl->id.subdevice = i; | ||
672 | err = snd_ctl_add(chip->card, kctl); | ||
673 | if (err < 0) | ||
674 | return err; | ||
675 | } | ||
676 | } | ||
558 | return 0; | 677 | return 0; |
559 | } | 678 | } |