683 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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 */21static 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_AU882042static 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#endif62static 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_AU881085static 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#endif102#ifdef CHIP_AU8830103static const unsigned int au8830_channels[3] = {104 1, 2, 4,105};106 107static 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#endif113 114static 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 else120 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 */126static 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 err = snd_pcm_hw_constraint_integer(runtime,134 SNDRV_PCM_HW_PARAM_PERIODS);135 if (err < 0)136 return err;137 /* Avoid PAGE_SIZE boundary to fall inside of a period. */138 err = snd_pcm_hw_constraint_pow2(runtime, 0,139 SNDRV_PCM_HW_PARAM_PERIOD_BYTES);140 if (err < 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_AU8820148 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) {149 runtime->hw = snd_vortex_playback_hw_a3d;150 }151#endif152 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_ADB167 || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S)168 runtime->hw = snd_vortex_playback_hw_adb;169#ifdef CHIP_AU8830170 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#endif179 substream->runtime->private_data = NULL;180 }181#ifndef CHIP_AU8810182 else {183 runtime->hw = snd_vortex_playback_hw_wt;184 substream->runtime->private_data = NULL;185 }186#endif187 return 0;188}189 190/* close callback */191static 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 here197 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 */206static int207snd_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 213 /*214 pr_info( "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),215 params_period_bytes(hw_params), params_channels(hw_params));216 */217 spin_lock_irq(&chip->lock);218 // Make audio routes and config buffer DMA.219 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {220 int dma, type = VORTEX_PCM_TYPE(substream->pcm);221 /* Dealloc any routes. */222 if (stream != NULL)223 vortex_adb_allocroute(chip, stream->dma,224 stream->nr_ch, stream->dir,225 stream->type,226 substream->number);227 /* Alloc routes. */228 dma =229 vortex_adb_allocroute(chip, -1,230 params_channels(hw_params),231 substream->stream, type,232 substream->number);233 if (dma < 0) {234 spin_unlock_irq(&chip->lock);235 return dma;236 }237 stream = substream->runtime->private_data = &chip->dma_adb[dma];238 stream->substream = substream;239 /* Setup Buffers. */240 vortex_adbdma_setbuffers(chip, dma,241 params_period_bytes(hw_params),242 params_periods(hw_params));243 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {244 chip->pcm_vol[substream->number].active = 1;245 vortex_notify_pcm_vol_change(chip->card,246 chip->pcm_vol[substream->number].kctl, 1);247 }248 }249#ifndef CHIP_AU8810250 else {251 /* if (stream != NULL)252 vortex_wt_allocroute(chip, substream->number, 0); */253 vortex_wt_allocroute(chip, substream->number,254 params_channels(hw_params));255 stream = substream->runtime->private_data =256 &chip->dma_wt[substream->number];257 stream->dma = substream->number;258 stream->substream = substream;259 vortex_wtdma_setbuffers(chip, substream->number,260 params_period_bytes(hw_params),261 params_periods(hw_params));262 }263#endif264 spin_unlock_irq(&chip->lock);265 return 0;266}267 268/* hw_free callback */269static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream)270{271 vortex_t *chip = snd_pcm_substream_chip(substream);272 stream_t *stream = (stream_t *) (substream->runtime->private_data);273 274 spin_lock_irq(&chip->lock);275 // Delete audio routes.276 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {277 if (stream != NULL) {278 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {279 chip->pcm_vol[substream->number].active = 0;280 vortex_notify_pcm_vol_change(chip->card,281 chip->pcm_vol[substream->number].kctl,282 0);283 }284 vortex_adb_allocroute(chip, stream->dma,285 stream->nr_ch, stream->dir,286 stream->type,287 substream->number);288 }289 }290#ifndef CHIP_AU8810291 else {292 if (stream != NULL)293 vortex_wt_allocroute(chip, stream->dma, 0);294 }295#endif296 substream->runtime->private_data = NULL;297 spin_unlock_irq(&chip->lock);298 299 return 0;300}301 302/* prepare callback */303static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream)304{305 vortex_t *chip = snd_pcm_substream_chip(substream);306 struct snd_pcm_runtime *runtime = substream->runtime;307 stream_t *stream = (stream_t *) substream->runtime->private_data;308 int dma = stream->dma, fmt, dir;309 310 // set up the hardware with the current configuration.311 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)312 dir = 1;313 else314 dir = 0;315 fmt = vortex_alsafmt_aspfmt(runtime->format, chip);316 spin_lock_irq(&chip->lock);317 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {318 vortex_adbdma_setmode(chip, dma, 1, dir, fmt,319 runtime->channels == 1 ? 0 : 1, 0);320 vortex_adbdma_setstartbuffer(chip, dma, 0);321 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF)322 vortex_adb_setsrc(chip, dma, runtime->rate, dir);323 }324#ifndef CHIP_AU8810325 else {326 vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0);327 // FIXME: Set rate (i guess using vortex_wt_writereg() somehow).328 vortex_wtdma_setstartbuffer(chip, dma, 0);329 }330#endif331 spin_unlock_irq(&chip->lock);332 return 0;333}334 335/* trigger callback */336static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)337{338 vortex_t *chip = snd_pcm_substream_chip(substream);339 stream_t *stream = (stream_t *) substream->runtime->private_data;340 int dma = stream->dma;341 342 spin_lock(&chip->lock);343 switch (cmd) {344 case SNDRV_PCM_TRIGGER_START:345 // do something to start the PCM engine346 //printk(KERN_INFO "vortex: start %d\n", dma);347 stream->fifo_enabled = 1;348 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {349 vortex_adbdma_resetup(chip, dma);350 vortex_adbdma_startfifo(chip, dma);351 }352#ifndef CHIP_AU8810353 else {354 dev_info(chip->card->dev, "wt start %d\n", dma);355 vortex_wtdma_startfifo(chip, dma);356 }357#endif358 break;359 case SNDRV_PCM_TRIGGER_STOP:360 // do something to stop the PCM engine361 //printk(KERN_INFO "vortex: stop %d\n", dma);362 stream->fifo_enabled = 0;363 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)364 vortex_adbdma_stopfifo(chip, dma);365#ifndef CHIP_AU8810366 else {367 dev_info(chip->card->dev, "wt stop %d\n", dma);368 vortex_wtdma_stopfifo(chip, dma);369 }370#endif371 break;372 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:373 //printk(KERN_INFO "vortex: pause %d\n", dma);374 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)375 vortex_adbdma_pausefifo(chip, dma);376#ifndef CHIP_AU8810377 else378 vortex_wtdma_pausefifo(chip, dma);379#endif380 break;381 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:382 //printk(KERN_INFO "vortex: resume %d\n", dma);383 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)384 vortex_adbdma_resumefifo(chip, dma);385#ifndef CHIP_AU8810386 else387 vortex_wtdma_resumefifo(chip, dma);388#endif389 break;390 default:391 spin_unlock(&chip->lock);392 return -EINVAL;393 }394 spin_unlock(&chip->lock);395 return 0;396}397 398/* pointer callback */399static snd_pcm_uframes_t snd_vortex_pcm_pointer(struct snd_pcm_substream *substream)400{401 vortex_t *chip = snd_pcm_substream_chip(substream);402 stream_t *stream = (stream_t *) substream->runtime->private_data;403 int dma = stream->dma;404 snd_pcm_uframes_t current_ptr = 0;405 406 spin_lock(&chip->lock);407 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)408 current_ptr = vortex_adbdma_getlinearpos(chip, dma);409#ifndef CHIP_AU8810410 else411 current_ptr = vortex_wtdma_getlinearpos(chip, dma);412#endif413 //printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr);414 spin_unlock(&chip->lock);415 current_ptr = bytes_to_frames(substream->runtime, current_ptr);416 if (current_ptr >= substream->runtime->buffer_size)417 current_ptr = 0;418 return current_ptr;419}420 421/* operators */422static const struct snd_pcm_ops snd_vortex_playback_ops = {423 .open = snd_vortex_pcm_open,424 .close = snd_vortex_pcm_close,425 .hw_params = snd_vortex_pcm_hw_params,426 .hw_free = snd_vortex_pcm_hw_free,427 .prepare = snd_vortex_pcm_prepare,428 .trigger = snd_vortex_pcm_trigger,429 .pointer = snd_vortex_pcm_pointer,430};431 432/*433* definitions of capture are omitted here...434*/435 436static const char * const vortex_pcm_prettyname[VORTEX_PCM_LAST] = {437 CARD_NAME " ADB",438 CARD_NAME " SPDIF",439 CARD_NAME " A3D",440 CARD_NAME " WT",441 CARD_NAME " I2S",442};443static const char * const vortex_pcm_name[VORTEX_PCM_LAST] = {444 "adb",445 "spdif",446 "a3d",447 "wt",448 "i2s",449};450 451/* SPDIF kcontrol */452 453static int snd_vortex_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)454{455 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;456 uinfo->count = 1;457 return 0;458}459 460static int snd_vortex_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)461{462 ucontrol->value.iec958.status[0] = 0xff;463 ucontrol->value.iec958.status[1] = 0xff;464 ucontrol->value.iec958.status[2] = 0xff;465 ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;466 return 0;467}468 469static int snd_vortex_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)470{471 vortex_t *vortex = snd_kcontrol_chip(kcontrol);472 ucontrol->value.iec958.status[0] = 0x00;473 ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL|IEC958_AES1_CON_DIGDIGCONV_ID;474 ucontrol->value.iec958.status[2] = 0x00;475 switch (vortex->spdif_sr) {476 case 32000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_32000; break;477 case 44100: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_44100; break;478 case 48000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; break;479 }480 return 0;481}482 483static int snd_vortex_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)484{485 vortex_t *vortex = snd_kcontrol_chip(kcontrol);486 int spdif_sr = 48000;487 switch (ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) {488 case IEC958_AES3_CON_FS_32000: spdif_sr = 32000; break;489 case IEC958_AES3_CON_FS_44100: spdif_sr = 44100; break;490 case IEC958_AES3_CON_FS_48000: spdif_sr = 48000; break;491 }492 if (spdif_sr == vortex->spdif_sr)493 return 0;494 vortex->spdif_sr = spdif_sr;495 vortex_spdif_init(vortex, vortex->spdif_sr, 1);496 return 1;497}498 499/* spdif controls */500static const struct snd_kcontrol_new snd_vortex_mixer_spdif[] = {501 {502 .iface = SNDRV_CTL_ELEM_IFACE_PCM,503 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),504 .info = snd_vortex_spdif_info,505 .get = snd_vortex_spdif_get,506 .put = snd_vortex_spdif_put,507 },508 {509 .access = SNDRV_CTL_ELEM_ACCESS_READ,510 .iface = SNDRV_CTL_ELEM_IFACE_PCM,511 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),512 .info = snd_vortex_spdif_info,513 .get = snd_vortex_spdif_mask_get514 },515};516 517/* subdevice PCM Volume control */518 519static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol,520 struct snd_ctl_elem_info *uinfo)521{522 vortex_t *vortex = snd_kcontrol_chip(kcontrol);523 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;524 uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2);525 uinfo->value.integer.min = -128;526 uinfo->value.integer.max = 32;527 return 0;528}529 530static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol,531 struct snd_ctl_elem_value *ucontrol)532{533 int i;534 vortex_t *vortex = snd_kcontrol_chip(kcontrol);535 int subdev = kcontrol->id.subdevice;536 struct pcm_vol *p = &vortex->pcm_vol[subdev];537 int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);538 for (i = 0; i < max_chn; i++)539 ucontrol->value.integer.value[i] = p->vol[i];540 return 0;541}542 543static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol,544 struct snd_ctl_elem_value *ucontrol)545{546 int i;547 int changed = 0;548 int mixin;549 unsigned char vol;550 vortex_t *vortex = snd_kcontrol_chip(kcontrol);551 int subdev = kcontrol->id.subdevice;552 struct pcm_vol *p = &vortex->pcm_vol[subdev];553 int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);554 for (i = 0; i < max_chn; i++) {555 if (p->vol[i] != ucontrol->value.integer.value[i]) {556 p->vol[i] = ucontrol->value.integer.value[i];557 if (p->active) {558 switch (vortex->dma_adb[p->dma].nr_ch) {559 case 1:560 mixin = p->mixin[0];561 break;562 case 2:563 default:564 mixin = p->mixin[(i < 2) ? i : (i - 2)];565 break;566 case 4:567 mixin = p->mixin[i];568 break;569 }570 vol = p->vol[i];571 vortex_mix_setinputvolumebyte(vortex,572 vortex->mixplayb[i], mixin, vol);573 }574 changed = 1;575 }576 }577 return changed;578}579 580static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400);581 582static const struct snd_kcontrol_new snd_vortex_pcm_vol = {583 .iface = SNDRV_CTL_ELEM_IFACE_PCM,584 .name = "PCM Playback Volume",585 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |586 SNDRV_CTL_ELEM_ACCESS_TLV_READ |587 SNDRV_CTL_ELEM_ACCESS_INACTIVE,588 .info = snd_vortex_pcm_vol_info,589 .get = snd_vortex_pcm_vol_get,590 .put = snd_vortex_pcm_vol_put,591 .tlv = { .p = vortex_pcm_vol_db_scale },592};593 594/* create a pcm device */595static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)596{597 struct snd_pcm *pcm;598 struct snd_kcontrol *kctl;599 int i;600 int err, nr_capt;601 602 if (!chip || idx < 0 || idx >= VORTEX_PCM_LAST)603 return -ENODEV;604 605 /* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the 606 * same dma engine. WT uses it own separate dma engine which can't capture. */607 if (idx == VORTEX_PCM_ADB)608 nr_capt = nr;609 else610 nr_capt = 0;611 err = snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr,612 nr_capt, &pcm);613 if (err < 0)614 return err;615 snprintf(pcm->name, sizeof(pcm->name),616 "%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]);617 chip->pcm[idx] = pcm;618 // This is an evil hack, but it saves a lot of duplicated code.619 VORTEX_PCM_TYPE(pcm) = idx;620 pcm->private_data = chip;621 /* set operators */622 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,623 &snd_vortex_playback_ops);624 if (idx == VORTEX_PCM_ADB)625 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,626 &snd_vortex_playback_ops);627 628 /* pre-allocation of Scatter-Gather buffers */629 630 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG,631 &chip->pci_dev->dev, 0x10000, 0x10000);632 633 switch (VORTEX_PCM_TYPE(pcm)) {634 case VORTEX_PCM_ADB:635 err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,636 snd_pcm_std_chmaps,637 VORTEX_IS_QUAD(chip) ? 4 : 2,638 0, NULL);639 if (err < 0)640 return err;641 err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,642 snd_pcm_std_chmaps, 2, 0, NULL);643 if (err < 0)644 return err;645 break;646#ifdef CHIP_AU8830647 case VORTEX_PCM_A3D:648 err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,649 snd_pcm_std_chmaps, 1, 0, NULL);650 if (err < 0)651 return err;652 break;653#endif654 }655 656 if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {657 for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) {658 kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip);659 if (!kctl)660 return -ENOMEM;661 err = snd_ctl_add(chip->card, kctl);662 if (err < 0)663 return err;664 }665 }666 if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) {667 for (i = 0; i < NR_PCM; i++) {668 chip->pcm_vol[i].active = 0;669 chip->pcm_vol[i].dma = -1;670 kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip);671 if (!kctl)672 return -ENOMEM;673 chip->pcm_vol[i].kctl = kctl;674 kctl->id.device = 0;675 kctl->id.subdevice = i;676 err = snd_ctl_add(chip->card, kctl);677 if (err < 0)678 return err;679 }680 }681 return 0;682}683