aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/au88x0
diff options
context:
space:
mode:
authorRaymond Yau <superquad.vortex2@gmail.com>2012-01-16 22:32:17 -0500
committerTakashi Iwai <tiwai@suse.de>2012-01-24 09:25:08 -0500
commitbb92b7c4ed4f7d5102bb1623cc8a1a9960ddfc08 (patch)
treed92a7641af16f2b7952a4c091756e067650c11b2 /sound/pci/au88x0
parentdcd6c92267155e70a94b3927bce681ce74b80d1f (diff)
ALSA: Au88x0 - Implement subdevice volume controls
- add "PCM Playback Volume" controls for 16 playback subdevices This allow application to change the volume of each subdevice by using hardware mixer of au88x0 and default is zero gain/attenunation. Signed-off-by: Raymond Yau <superquad.vortex2@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/au88x0')
-rw-r--r--sound/pci/au88x0/au88x0.h13
-rw-r--r--sound/pci/au88x0/au88x0_core.c18
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c127
3 files changed, 145 insertions, 13 deletions
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index bb938153a964..466a5c8e8354 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -26,7 +26,7 @@
26#include <sound/mpu401.h> 26#include <sound/mpu401.h>
27#include <sound/hwdep.h> 27#include <sound/hwdep.h>
28#include <sound/ac97_codec.h> 28#include <sound/ac97_codec.h>
29 29#include <sound/tlv.h>
30#endif 30#endif
31 31
32#ifndef CHIP_AU8820 32#ifndef CHIP_AU8820
@@ -107,6 +107,14 @@
107#define NR_WTPB 0x20 /* WT channels per each bank. */ 107#define NR_WTPB 0x20 /* WT channels per each bank. */
108#define NR_PCM 0x10 108#define NR_PCM 0x10
109 109
110struct pcm_vol {
111 struct snd_kcontrol *kctl;
112 int active;
113 int dma;
114 int mixin[4];
115 int vol[4];
116};
117
110/* Structs */ 118/* Structs */
111typedef struct { 119typedef struct {
112 //int this_08; /* Still unknown */ 120 //int this_08; /* Still unknown */
@@ -168,6 +176,7 @@ struct snd_vortex {
168 /* Xtalk canceler */ 176 /* Xtalk canceler */
169 int xt_mode; /* 1: speakers, 0:headphones. */ 177 int xt_mode; /* 1: speakers, 0:headphones. */
170#endif 178#endif
179 struct pcm_vol pcm_vol[NR_PCM];
171 180
172 int isquad; /* cache of extended ID codec flag. */ 181 int isquad; /* cache of extended ID codec flag. */
173 182
@@ -239,7 +248,7 @@ static int vortex_alsafmt_aspfmt(int alsafmt);
239/* Connection stuff. */ 248/* Connection stuff. */
240static void vortex_connect_default(vortex_t * vortex, int en); 249static void vortex_connect_default(vortex_t * vortex, int en);
241static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, 250static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch,
242 int dir, int type); 251 int dir, int type, int subdev);
243static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, 252static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out,
244 int restype); 253 int restype);
245#ifndef CHIP_AU8810 254#ifndef CHIP_AU8810
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 6933a27a5d76..1181c5ec2d4f 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -2050,8 +2050,6 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
2050} 2050}
2051 2051
2052/* Default Connections */ 2052/* Default Connections */
2053static int
2054vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type);
2055 2053
2056static void vortex_connect_default(vortex_t * vortex, int en) 2054static void vortex_connect_default(vortex_t * vortex, int en)
2057{ 2055{
@@ -2111,15 +2109,13 @@ static void vortex_connect_default(vortex_t * vortex, int en)
2111 Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0. 2109 Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0.
2112*/ 2110*/
2113static int 2111static int
2114vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type) 2112vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir,
2113 int type, int subdev)
2115{ 2114{
2116 stream_t *stream; 2115 stream_t *stream;
2117 int i, en; 2116 int i, en;
2117 struct pcm_vol *p;
2118 2118
2119 if ((nr_ch == 3)
2120 || ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2)))
2121 return -EBUSY;
2122
2123 if (dma >= 0) { 2119 if (dma >= 0) {
2124 en = 0; 2120 en = 0;
2125 vortex_adb_checkinout(vortex, 2121 vortex_adb_checkinout(vortex,
@@ -2250,6 +2246,14 @@ vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type)
2250 MIX_DEFIGAIN); 2246 MIX_DEFIGAIN);
2251#endif 2247#endif
2252 } 2248 }
2249 if (stream->type == VORTEX_PCM_ADB && en) {
2250 p = &vortex->pcm_vol[subdev];
2251 p->dma = dma;
2252 for (i = 0; i < nr_ch; i++)
2253 p->mixin[i] = mix[i];
2254 for (i = 0; i < ch_top; i++)
2255 p->vol[i] = 0;
2256 }
2253 } 2257 }
2254#ifndef CHIP_AU8820 2258#ifndef CHIP_AU8820
2255 else { 2259 else {
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
126static 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 */
126static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) 138static 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
538static 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
549static 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
562static 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
599static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400);
600
601static 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 */
510static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) 614static 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}