~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/pci/au88x0/au88x0_pcm.c

Version: ~ [ linux-5.7-rc7 ] ~ [ linux-5.6.14 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.42 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.124 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.181 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.224 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.224 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.84 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  */
  4  
  5 /*
  6  * Vortex PCM ALSA driver.
  7  *
  8  * Supports ADB and WT DMA. Unfortunately, WT channels do not run yet.
  9  * It remains stuck,and DMA transfers do not happen. 
 10  */
 11 #include <sound/asoundef.h>
 12 #include <linux/time.h>
 13 #include <sound/core.h>
 14 #include <sound/pcm.h>
 15 #include <sound/pcm_params.h>
 16 #include "au88x0.h"
 17 
 18 #define VORTEX_PCM_TYPE(x) (x->name[40])
 19 
 20 /* hardware definition */
 21 static const struct snd_pcm_hardware snd_vortex_playback_hw_adb = {
 22         .info =
 23             (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
 24              SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
 25              SNDRV_PCM_INFO_MMAP_VALID),
 26         .formats =
 27             SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
 28             SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
 29         .rates = SNDRV_PCM_RATE_CONTINUOUS,
 30         .rate_min = 5000,
 31         .rate_max = 48000,
 32         .channels_min = 1,
 33         .channels_max = 2,
 34         .buffer_bytes_max = 0x10000,
 35         .period_bytes_min = 0x20,
 36         .period_bytes_max = 0x1000,
 37         .periods_min = 2,
 38         .periods_max = 1024,
 39 };
 40 
 41 #ifndef CHIP_AU8820
 42 static const struct snd_pcm_hardware snd_vortex_playback_hw_a3d = {
 43         .info =
 44             (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
 45              SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
 46              SNDRV_PCM_INFO_MMAP_VALID),
 47         .formats =
 48             SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
 49             SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
 50         .rates = SNDRV_PCM_RATE_CONTINUOUS,
 51         .rate_min = 5000,
 52         .rate_max = 48000,
 53         .channels_min = 1,
 54         .channels_max = 1,
 55         .buffer_bytes_max = 0x10000,
 56         .period_bytes_min = 0x100,
 57         .period_bytes_max = 0x1000,
 58         .periods_min = 2,
 59         .periods_max = 64,
 60 };
 61 #endif
 62 static const struct snd_pcm_hardware snd_vortex_playback_hw_spdif = {
 63         .info =
 64             (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
 65              SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
 66              SNDRV_PCM_INFO_MMAP_VALID),
 67         .formats =
 68             SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
 69             SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | SNDRV_PCM_FMTBIT_MU_LAW |
 70             SNDRV_PCM_FMTBIT_A_LAW,
 71         .rates =
 72             SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
 73         .rate_min = 32000,
 74         .rate_max = 48000,
 75         .channels_min = 1,
 76         .channels_max = 2,
 77         .buffer_bytes_max = 0x10000,
 78         .period_bytes_min = 0x100,
 79         .period_bytes_max = 0x1000,
 80         .periods_min = 2,
 81         .periods_max = 64,
 82 };
 83 
 84 #ifndef CHIP_AU8810
 85 static const struct snd_pcm_hardware snd_vortex_playback_hw_wt = {
 86         .info = (SNDRV_PCM_INFO_MMAP |
 87                  SNDRV_PCM_INFO_INTERLEAVED |
 88                  SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
 89         .formats = SNDRV_PCM_FMTBIT_S16_LE,
 90         .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, // SNDRV_PCM_RATE_48000,
 91         .rate_min = 8000,
 92         .rate_max = 48000,
 93         .channels_min = 1,
 94         .channels_max = 2,
 95         .buffer_bytes_max = 0x10000,
 96         .period_bytes_min = 0x0400,
 97         .period_bytes_max = 0x1000,
 98         .periods_min = 2,
 99         .periods_max = 64,
100 };
101 #endif
102 #ifdef CHIP_AU8830
103 static const unsigned int au8830_channels[3] = {
104         1, 2, 4,
105 };
106 
107 static const struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = {
108         .count = ARRAY_SIZE(au8830_channels),
109         .list = au8830_channels,
110         .mask = 0,
111 };
112 #endif
113 
114 static void vortex_notify_pcm_vol_change(struct snd_card *card,
115                         struct snd_kcontrol *kctl, int activate)
116 {
117         if (activate)
118                 kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
119         else
120                 kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
121         snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE |
122                                 SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id));
123 }
124 
125 /* open callback */
126 static int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
127 {
128         vortex_t *vortex = snd_pcm_substream_chip(substream);
129         struct snd_pcm_runtime *runtime = substream->runtime;
130         int err;
131         
132         /* Force equal size periods */
133         if ((err =
134              snd_pcm_hw_constraint_integer(runtime,
135                                            SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
136                 return err;
137         /* Avoid PAGE_SIZE boundary to fall inside of a period. */
138         if ((err =
139              snd_pcm_hw_constraint_pow2(runtime, 0,
140                                         SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
141                 return err;
142 
143         snd_pcm_hw_constraint_step(runtime, 0,
144                                         SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 64);
145 
146         if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
147 #ifndef CHIP_AU8820
148                 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) {
149                         runtime->hw = snd_vortex_playback_hw_a3d;
150                 }
151 #endif
152                 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) {
153                         runtime->hw = snd_vortex_playback_hw_spdif;
154                         switch (vortex->spdif_sr) {
155                         case 32000:
156                                 runtime->hw.rates = SNDRV_PCM_RATE_32000;
157                                 break;
158                         case 44100:
159                                 runtime->hw.rates = SNDRV_PCM_RATE_44100;
160                                 break;
161                         case 48000:
162                                 runtime->hw.rates = SNDRV_PCM_RATE_48000;
163                                 break;
164                         }
165                 }
166                 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB
167                     || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S)
168                         runtime->hw = snd_vortex_playback_hw_adb;
169 #ifdef CHIP_AU8830
170                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
171                         VORTEX_IS_QUAD(vortex) &&
172                         VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
173                         runtime->hw.channels_max = 4;
174                         snd_pcm_hw_constraint_list(runtime, 0,
175                                 SNDRV_PCM_HW_PARAM_CHANNELS,
176                                 &hw_constraints_au8830_channels);
177                 }
178 #endif
179                 substream->runtime->private_data = NULL;
180         }
181 #ifndef CHIP_AU8810
182         else {
183                 runtime->hw = snd_vortex_playback_hw_wt;
184                 substream->runtime->private_data = NULL;
185         }
186 #endif
187         return 0;
188 }
189 
190 /* close callback */
191 static int snd_vortex_pcm_close(struct snd_pcm_substream *substream)
192 {
193         //vortex_t *chip = snd_pcm_substream_chip(substream);
194         stream_t *stream = (stream_t *) substream->runtime->private_data;
195 
196         // the hardware-specific codes will be here
197         if (stream != NULL) {
198                 stream->substream = NULL;
199                 stream->nr_ch = 0;
200         }
201         substream->runtime->private_data = NULL;
202         return 0;
203 }
204 
205 /* hw_params callback */
206 static int
207 snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
208                          struct snd_pcm_hw_params *hw_params)
209 {
210         vortex_t *chip = snd_pcm_substream_chip(substream);
211         stream_t *stream = (stream_t *) (substream->runtime->private_data);
212         int err;
213 
214         // Alloc buffer memory.
215         err =
216             snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
217         if (err < 0) {
218                 dev_err(chip->card->dev, "Vortex: pcm page alloc failed!\n");
219                 return err;
220         }
221         /*
222            pr_info( "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
223            params_period_bytes(hw_params), params_channels(hw_params));
224          */
225         spin_lock_irq(&chip->lock);
226         // Make audio routes and config buffer DMA.
227         if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
228                 int dma, type = VORTEX_PCM_TYPE(substream->pcm);
229                 /* Dealloc any routes. */
230                 if (stream != NULL)
231                         vortex_adb_allocroute(chip, stream->dma,
232                                               stream->nr_ch, stream->dir,
233                                               stream->type,
234                                               substream->number);
235                 /* Alloc routes. */
236                 dma =
237                     vortex_adb_allocroute(chip, -1,
238                                           params_channels(hw_params),
239                                           substream->stream, type,
240                                           substream->number);
241                 if (dma < 0) {
242                         spin_unlock_irq(&chip->lock);
243                         return dma;
244                 }
245                 stream = substream->runtime->private_data = &chip->dma_adb[dma];
246                 stream->substream = substream;
247                 /* Setup Buffers. */
248                 vortex_adbdma_setbuffers(chip, dma,
249                                          params_period_bytes(hw_params),
250                                          params_periods(hw_params));
251                 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
252                         chip->pcm_vol[substream->number].active = 1;
253                         vortex_notify_pcm_vol_change(chip->card,
254                                 chip->pcm_vol[substream->number].kctl, 1);
255                 }
256         }
257 #ifndef CHIP_AU8810
258         else {
259                 /* if (stream != NULL)
260                    vortex_wt_allocroute(chip, substream->number, 0); */
261                 vortex_wt_allocroute(chip, substream->number,
262                                      params_channels(hw_params));
263                 stream = substream->runtime->private_data =
264                     &chip->dma_wt[substream->number];
265                 stream->dma = substream->number;
266                 stream->substream = substream;
267                 vortex_wtdma_setbuffers(chip, substream->number,
268                                         params_period_bytes(hw_params),
269                                         params_periods(hw_params));
270         }
271 #endif
272         spin_unlock_irq(&chip->lock);
273         return 0;
274 }
275 
276 /* hw_free callback */
277 static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream)
278 {
279         vortex_t *chip = snd_pcm_substream_chip(substream);
280         stream_t *stream = (stream_t *) (substream->runtime->private_data);
281 
282         spin_lock_irq(&chip->lock);
283         // Delete audio routes.
284         if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
285                 if (stream != NULL) {
286                         if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
287                                 chip->pcm_vol[substream->number].active = 0;
288                                 vortex_notify_pcm_vol_change(chip->card,
289                                         chip->pcm_vol[substream->number].kctl,
290                                         0);
291                         }
292                         vortex_adb_allocroute(chip, stream->dma,
293                                               stream->nr_ch, stream->dir,
294                                               stream->type,
295                                               substream->number);
296                 }
297         }
298 #ifndef CHIP_AU8810
299         else {
300                 if (stream != NULL)
301                         vortex_wt_allocroute(chip, stream->dma, 0);
302         }
303 #endif
304         substream->runtime->private_data = NULL;
305         spin_unlock_irq(&chip->lock);
306 
307         return snd_pcm_lib_free_pages(substream);
308 }
309 
310 /* prepare callback */
311 static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream)
312 {
313         vortex_t *chip = snd_pcm_substream_chip(substream);
314         struct snd_pcm_runtime *runtime = substream->runtime;
315         stream_t *stream = (stream_t *) substream->runtime->private_data;
316         int dma = stream->dma, fmt, dir;
317 
318         // set up the hardware with the current configuration.
319         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
320                 dir = 1;
321         else
322                 dir = 0;
323         fmt = vortex_alsafmt_aspfmt(runtime->format, chip);
324         spin_lock_irq(&chip->lock);
325         if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
326                 vortex_adbdma_setmode(chip, dma, 1, dir, fmt,
327                                 runtime->channels == 1 ? 0 : 1, 0);
328                 vortex_adbdma_setstartbuffer(chip, dma, 0);
329                 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF)
330                         vortex_adb_setsrc(chip, dma, runtime->rate, dir);
331         }
332 #ifndef CHIP_AU8810
333         else {
334                 vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0);
335                 // FIXME: Set rate (i guess using vortex_wt_writereg() somehow).
336                 vortex_wtdma_setstartbuffer(chip, dma, 0);
337         }
338 #endif
339         spin_unlock_irq(&chip->lock);
340         return 0;
341 }
342 
343 /* trigger callback */
344 static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
345 {
346         vortex_t *chip = snd_pcm_substream_chip(substream);
347         stream_t *stream = (stream_t *) substream->runtime->private_data;
348         int dma = stream->dma;
349 
350         spin_lock(&chip->lock);
351         switch (cmd) {
352         case SNDRV_PCM_TRIGGER_START:
353                 // do something to start the PCM engine
354                 //printk(KERN_INFO "vortex: start %d\n", dma);
355                 stream->fifo_enabled = 1;
356                 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
357                         vortex_adbdma_resetup(chip, dma);
358                         vortex_adbdma_startfifo(chip, dma);
359                 }
360 #ifndef CHIP_AU8810
361                 else {
362                         dev_info(chip->card->dev, "wt start %d\n", dma);
363                         vortex_wtdma_startfifo(chip, dma);
364                 }
365 #endif
366                 break;
367         case SNDRV_PCM_TRIGGER_STOP:
368                 // do something to stop the PCM engine
369                 //printk(KERN_INFO "vortex: stop %d\n", dma);
370                 stream->fifo_enabled = 0;
371                 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
372                         vortex_adbdma_stopfifo(chip, dma);
373 #ifndef CHIP_AU8810
374                 else {
375                         dev_info(chip->card->dev, "wt stop %d\n", dma);
376                         vortex_wtdma_stopfifo(chip, dma);
377                 }
378 #endif
379                 break;
380         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
381                 //printk(KERN_INFO "vortex: pause %d\n", dma);
382                 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
383                         vortex_adbdma_pausefifo(chip, dma);
384 #ifndef CHIP_AU8810
385                 else
386                         vortex_wtdma_pausefifo(chip, dma);
387 #endif
388                 break;
389         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
390                 //printk(KERN_INFO "vortex: resume %d\n", dma);
391                 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
392                         vortex_adbdma_resumefifo(chip, dma);
393 #ifndef CHIP_AU8810
394                 else
395                         vortex_wtdma_resumefifo(chip, dma);
396 #endif
397                 break;
398         default:
399                 spin_unlock(&chip->lock);
400                 return -EINVAL;
401         }
402         spin_unlock(&chip->lock);
403         return 0;
404 }
405 
406 /* pointer callback */
407 static snd_pcm_uframes_t snd_vortex_pcm_pointer(struct snd_pcm_substream *substream)
408 {
409         vortex_t *chip = snd_pcm_substream_chip(substream);
410         stream_t *stream = (stream_t *) substream->runtime->private_data;
411         int dma = stream->dma;
412         snd_pcm_uframes_t current_ptr = 0;
413 
414         spin_lock(&chip->lock);
415         if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
416                 current_ptr = vortex_adbdma_getlinearpos(chip, dma);
417 #ifndef CHIP_AU8810
418         else
419                 current_ptr = vortex_wtdma_getlinearpos(chip, dma);
420 #endif
421         //printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr);
422         spin_unlock(&chip->lock);
423         current_ptr = bytes_to_frames(substream->runtime, current_ptr);
424         if (current_ptr >= substream->runtime->buffer_size)
425                 current_ptr = 0;
426         return current_ptr;
427 }
428 
429 /* operators */
430 static const struct snd_pcm_ops snd_vortex_playback_ops = {
431         .open = snd_vortex_pcm_open,
432         .close = snd_vortex_pcm_close,
433         .ioctl = snd_pcm_lib_ioctl,
434         .hw_params = snd_vortex_pcm_hw_params,
435         .hw_free = snd_vortex_pcm_hw_free,
436         .prepare = snd_vortex_pcm_prepare,
437         .trigger = snd_vortex_pcm_trigger,
438         .pointer = snd_vortex_pcm_pointer,
439         .page = snd_pcm_sgbuf_ops_page,
440 };
441 
442 /*
443 *  definitions of capture are omitted here...
444 */
445 
446 static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = {
447         CARD_NAME " ADB",
448         CARD_NAME " SPDIF",
449         CARD_NAME " A3D",
450         CARD_NAME " WT",
451         CARD_NAME " I2S",
452 };
453 static char *vortex_pcm_name[VORTEX_PCM_LAST] = {
454         "adb",
455         "spdif",
456         "a3d",
457         "wt",
458         "i2s",
459 };
460 
461 /* SPDIF kcontrol */
462 
463 static int snd_vortex_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
464 {
465         uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
466         uinfo->count = 1;
467         return 0;
468 }
469 
470 static int snd_vortex_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
471 {
472         ucontrol->value.iec958.status[0] = 0xff;
473         ucontrol->value.iec958.status[1] = 0xff;
474         ucontrol->value.iec958.status[2] = 0xff;
475         ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;
476         return 0;
477 }
478 
479 static int snd_vortex_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
480 {
481         vortex_t *vortex = snd_kcontrol_chip(kcontrol);
482         ucontrol->value.iec958.status[0] = 0x00;
483         ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL|IEC958_AES1_CON_DIGDIGCONV_ID;
484         ucontrol->value.iec958.status[2] = 0x00;
485         switch (vortex->spdif_sr) {
486         case 32000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_32000; break;
487         case 44100: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_44100; break;
488         case 48000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; break;
489         }
490         return 0;
491 }
492 
493 static int snd_vortex_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
494 {
495         vortex_t *vortex = snd_kcontrol_chip(kcontrol);
496         int spdif_sr = 48000;
497         switch (ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) {
498         case IEC958_AES3_CON_FS_32000: spdif_sr = 32000; break;
499         case IEC958_AES3_CON_FS_44100: spdif_sr = 44100; break;
500         case IEC958_AES3_CON_FS_48000: spdif_sr = 48000; break;
501         }
502         if (spdif_sr == vortex->spdif_sr)
503                 return 0;
504         vortex->spdif_sr = spdif_sr;
505         vortex_spdif_init(vortex, vortex->spdif_sr, 1);
506         return 1;
507 }
508 
509 /* spdif controls */
510 static struct snd_kcontrol_new snd_vortex_mixer_spdif[] = {
511         {
512                 .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
513                 .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
514                 .info =         snd_vortex_spdif_info,
515                 .get =          snd_vortex_spdif_get,
516                 .put =          snd_vortex_spdif_put,
517         },
518         {
519                 .access =       SNDRV_CTL_ELEM_ACCESS_READ,
520                 .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
521                 .name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
522                 .info =         snd_vortex_spdif_info,
523                 .get =          snd_vortex_spdif_mask_get
524         },
525 };
526 
527 /* subdevice PCM Volume control */
528 
529 static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol,
530                                 struct snd_ctl_elem_info *uinfo)
531 {
532         vortex_t *vortex = snd_kcontrol_chip(kcontrol);
533         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
534         uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
535         uinfo->value.integer.min = -128;
536         uinfo->value.integer.max = 32;
537         return 0;
538 }
539 
540 static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol,
541                                 struct snd_ctl_elem_value *ucontrol)
542 {
543         int i;
544         vortex_t *vortex = snd_kcontrol_chip(kcontrol);
545         int subdev = kcontrol->id.subdevice;
546         struct pcm_vol *p = &vortex->pcm_vol[subdev];
547         int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
548         for (i = 0; i < max_chn; i++)
549                 ucontrol->value.integer.value[i] = p->vol[i];
550         return 0;
551 }
552 
553 static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol,
554                                 struct snd_ctl_elem_value *ucontrol)
555 {
556         int i;
557         int changed = 0;
558         int mixin;
559         unsigned char vol;
560         vortex_t *vortex = snd_kcontrol_chip(kcontrol);
561         int subdev = kcontrol->id.subdevice;
562         struct pcm_vol *p = &vortex->pcm_vol[subdev];
563         int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
564         for (i = 0; i < max_chn; i++) {
565                 if (p->vol[i] != ucontrol->value.integer.value[i]) {
566                         p->vol[i] = ucontrol->value.integer.value[i];
567                         if (p->active) {
568                                 switch (vortex->dma_adb[p->dma].nr_ch) {
569                                 case 1:
570                                         mixin = p->mixin[0];
571                                         break;
572                                 case 2:
573                                 default:
574                                         mixin = p->mixin[(i < 2) ? i : (i - 2)];
575                                         break;
576                                 case 4:
577                                         mixin = p->mixin[i];
578                                         break;
579                                 }
580                                 vol = p->vol[i];
581                                 vortex_mix_setinputvolumebyte(vortex,
582                                         vortex->mixplayb[i], mixin, vol);
583                         }
584                         changed = 1;
585                 }
586         }
587         return changed;
588 }
589 
590 static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400);
591 
592 static const struct snd_kcontrol_new snd_vortex_pcm_vol = {
593         .iface = SNDRV_CTL_ELEM_IFACE_PCM,
594         .name = "PCM Playback Volume",
595         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
596                 SNDRV_CTL_ELEM_ACCESS_TLV_READ |
597                 SNDRV_CTL_ELEM_ACCESS_INACTIVE,
598         .info = snd_vortex_pcm_vol_info,
599         .get = snd_vortex_pcm_vol_get,
600         .put = snd_vortex_pcm_vol_put,
601         .tlv = { .p = vortex_pcm_vol_db_scale },
602 };
603 
604 /* create a pcm device */
605 static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
606 {
607         struct snd_pcm *pcm;
608         struct snd_kcontrol *kctl;
609         int i;
610         int err, nr_capt;
611 
612         if (!chip || idx < 0 || idx >= VORTEX_PCM_LAST)
613                 return -ENODEV;
614 
615         /* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the 
616          * same dma engine. WT uses it own separate dma engine which can't capture. */
617         if (idx == VORTEX_PCM_ADB)
618                 nr_capt = nr;
619         else
620                 nr_capt = 0;
621         err = snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr,
622                           nr_capt, &pcm);
623         if (err < 0)
624                 return err;
625         snprintf(pcm->name, sizeof(pcm->name),
626                 "%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]);
627         chip->pcm[idx] = pcm;
628         // This is an evil hack, but it saves a lot of duplicated code.
629         VORTEX_PCM_TYPE(pcm) = idx;
630         pcm->private_data = chip;
631         /* set operators */
632         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
633                         &snd_vortex_playback_ops);
634         if (idx == VORTEX_PCM_ADB)
635                 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
636                                 &snd_vortex_playback_ops);
637         
638         /* pre-allocation of Scatter-Gather buffers */
639         
640         snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
641                                               snd_dma_pci_data(chip->pci_dev),
642                                               0x10000, 0x10000);
643 
644         switch (VORTEX_PCM_TYPE(pcm)) {
645         case VORTEX_PCM_ADB:
646                 err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
647                                              snd_pcm_std_chmaps,
648                                              VORTEX_IS_QUAD(chip) ? 4 : 2,
649                                              0, NULL);
650                 if (err < 0)
651                         return err;
652                 err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
653                                              snd_pcm_std_chmaps, 2, 0, NULL);
654                 if (err < 0)
655                         return err;
656                 break;
657 #ifdef CHIP_AU8830
658         case VORTEX_PCM_A3D:
659                 err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
660                                              snd_pcm_std_chmaps, 1, 0, NULL);
661                 if (err < 0)
662                         return err;
663                 break;
664 #endif
665         }
666 
667         if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
668                 for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) {
669                         kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip);
670                         if (!kctl)
671                                 return -ENOMEM;
672                         if ((err = snd_ctl_add(chip->card, kctl)) < 0)
673                                 return err;
674                 }
675         }
676         if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) {
677                 for (i = 0; i < NR_PCM; i++) {
678                         chip->pcm_vol[i].active = 0;
679                         chip->pcm_vol[i].dma = -1;
680                         kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip);
681                         if (!kctl)
682                                 return -ENOMEM;
683                         chip->pcm_vol[i].kctl = kctl;
684                         kctl->id.device = 0;
685                         kctl->id.subdevice = i;
686                         err = snd_ctl_add(chip->card, kctl);
687                         if (err < 0)
688                                 return err;
689                 }
690         }
691         return 0;
692 }
693 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp