root/sound/pci/au88x0/au88x0_pcm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vortex_notify_pcm_vol_change
  2. snd_vortex_pcm_open
  3. snd_vortex_pcm_close
  4. snd_vortex_pcm_hw_params
  5. snd_vortex_pcm_hw_free
  6. snd_vortex_pcm_prepare
  7. snd_vortex_pcm_trigger
  8. snd_vortex_pcm_pointer
  9. snd_vortex_spdif_info
  10. snd_vortex_spdif_mask_get
  11. snd_vortex_spdif_get
  12. snd_vortex_spdif_put
  13. snd_vortex_pcm_vol_info
  14. snd_vortex_pcm_vol_get
  15. snd_vortex_pcm_vol_put
  16. snd_vortex_new_pcm

   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 }

/* [<][>][^][v][top][bottom][index][help] */