📄 au88x0_pcm.c
字号:
}/* prepare callback */static int snd_vortex_pcm_prepare(snd_pcm_substream_t * substream){ vortex_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; stream_t *stream = (stream_t *) substream->runtime->private_data; int dma = stream->dma, fmt, dir; // set up the hardware with the current configuration. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) dir = 1; else dir = 0; fmt = vortex_alsafmt_aspfmt(runtime->format); spin_lock_irq(&chip->lock); if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { vortex_adbdma_setmode(chip, dma, 1, dir, fmt, 0 /*? */ , 0); vortex_adbdma_setstartbuffer(chip, dma, 0); if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF) vortex_adb_setsrc(chip, dma, runtime->rate, dir); }#ifndef CHIP_AU8810 else { vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0); // FIXME: Set rate (i guess using vortex_wt_writereg() somehow). vortex_wtdma_setstartbuffer(chip, dma, 0); }#endif spin_unlock_irq(&chip->lock); return 0;}/* trigger callback */static int snd_vortex_pcm_trigger(snd_pcm_substream_t * substream, int cmd){ vortex_t *chip = snd_pcm_substream_chip(substream); stream_t *stream = (stream_t *) substream->runtime->private_data; int dma = stream->dma; spin_lock(&chip->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: // do something to start the PCM engine //printk(KERN_INFO "vortex: start %d\n", dma); stream->fifo_enabled = 1; if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { vortex_adbdma_resetup(chip, dma); vortex_adbdma_startfifo(chip, dma); }#ifndef CHIP_AU8810 else { printk(KERN_INFO "vortex: wt start %d\n", dma); vortex_wtdma_startfifo(chip, dma); }#endif break; case SNDRV_PCM_TRIGGER_STOP: // do something to stop the PCM engine //printk(KERN_INFO "vortex: stop %d\n", dma); stream->fifo_enabled = 0; if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) vortex_adbdma_pausefifo(chip, dma); //vortex_adbdma_stopfifo(chip, dma);#ifndef CHIP_AU8810 else { printk(KERN_INFO "vortex: wt stop %d\n", dma); vortex_wtdma_stopfifo(chip, dma); }#endif break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: //printk(KERN_INFO "vortex: pause %d\n", dma); if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) vortex_adbdma_pausefifo(chip, dma);#ifndef CHIP_AU8810 else vortex_wtdma_pausefifo(chip, dma);#endif break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: //printk(KERN_INFO "vortex: resume %d\n", dma); if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) vortex_adbdma_resumefifo(chip, dma);#ifndef CHIP_AU8810 else vortex_wtdma_resumefifo(chip, dma);#endif break; default: spin_unlock(&chip->lock); return -EINVAL; } spin_unlock(&chip->lock); return 0;}/* pointer callback */static snd_pcm_uframes_t snd_vortex_pcm_pointer(snd_pcm_substream_t * substream){ vortex_t *chip = snd_pcm_substream_chip(substream); stream_t *stream = (stream_t *) substream->runtime->private_data; int dma = stream->dma; snd_pcm_uframes_t current_ptr = 0; spin_lock(&chip->lock); if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) current_ptr = vortex_adbdma_getlinearpos(chip, dma);#ifndef CHIP_AU8810 else current_ptr = vortex_wtdma_getlinearpos(chip, dma);#endif //printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr); spin_unlock(&chip->lock); return (bytes_to_frames(substream->runtime, current_ptr));}/* Page callback. *//*static struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset) { }*//* operators */static snd_pcm_ops_t snd_vortex_playback_ops = { .open = snd_vortex_pcm_open, .close = snd_vortex_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_vortex_pcm_hw_params, .hw_free = snd_vortex_pcm_hw_free, .prepare = snd_vortex_pcm_prepare, .trigger = snd_vortex_pcm_trigger, .pointer = snd_vortex_pcm_pointer, .page = snd_pcm_sgbuf_ops_page,};/** definitions of capture are omitted here...*/static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = { "AU88x0 ADB", "AU88x0 SPDIF", "AU88x0 A3D", "AU88x0 WT", "AU88x0 I2S",};static char *vortex_pcm_name[VORTEX_PCM_LAST] = { "adb", "spdif", "a3d", "wt", "i2s",};/* SPDIF kcontrol */static int snd_vortex_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; return 0;}static int snd_vortex_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ucontrol->value.iec958.status[0] = 0xff; ucontrol->value.iec958.status[1] = 0xff; ucontrol->value.iec958.status[2] = 0xff; ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS; return 0;}static int snd_vortex_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ vortex_t *vortex = snd_kcontrol_chip(kcontrol); ucontrol->value.iec958.status[0] = 0x00; ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL|IEC958_AES1_CON_DIGDIGCONV_ID; ucontrol->value.iec958.status[2] = 0x00; switch (vortex->spdif_sr) { case 32000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_32000; break; case 44100: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_44100; break; case 48000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; break; } return 0;}static int snd_vortex_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ vortex_t *vortex = snd_kcontrol_chip(kcontrol); int spdif_sr = 48000; switch (ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) { case IEC958_AES3_CON_FS_32000: spdif_sr = 32000; break; case IEC958_AES3_CON_FS_44100: spdif_sr = 44100; break; case IEC958_AES3_CON_FS_48000: spdif_sr = 48000; break; } if (spdif_sr == vortex->spdif_sr) return 0; vortex->spdif_sr = spdif_sr; vortex_spdif_init(vortex, vortex->spdif_sr, 1); return 1;}/* spdif controls */static snd_kcontrol_new_t snd_vortex_mixer_spdif[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), .info = snd_vortex_spdif_info, .get = snd_vortex_spdif_get, .put = snd_vortex_spdif_put, }, { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), .info = snd_vortex_spdif_info, .get = snd_vortex_spdif_mask_get },};/* create a pcm device */static int __devinit snd_vortex_new_pcm(vortex_t * chip, int idx, int nr){ snd_pcm_t *pcm; snd_kcontrol_t *kctl; int i; int err, nr_capt; if ((chip == 0) || (idx < 0) || (idx > VORTEX_PCM_LAST)) return -ENODEV; /* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the * same dma engine. WT uses it own separate dma engine whcih cant capture. */ if (idx == VORTEX_PCM_ADB) nr_capt = nr; else nr_capt = 0; if ((err = snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr, nr_capt, &pcm)) < 0) return err; strcpy(pcm->name, vortex_pcm_name[idx]); chip->pcm[idx] = pcm; // This is an evil hack, but it saves a lot of duplicated code. VORTEX_PCM_TYPE(pcm) = idx; pcm->private_data = chip; /* set operators */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_vortex_playback_ops); if (idx == VORTEX_PCM_ADB) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_vortex_playback_ops); /* pre-allocation of Scatter-Gather buffers */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci_dev), 0x10000, 0x10000); if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) { for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) { kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip); if (!kctl) return -ENOMEM; if ((err = snd_ctl_add(chip->card, kctl)) < 0) return err; } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -