static void vortex_wt_connect(vortex_t * vortex, int en) { int i, ii, mix; #define NR_WTROUTES 6 #ifdef CHIP_AU8830 #define NR_WTBLOCKS 2 #else #define NR_WTBLOCKS 1 #endif for (i = 0; i < NR_WTBLOCKS; i++) { for (ii = 0; ii < NR_WTROUTES; ii++) { mix = vortex_adb_checkinout(vortex, vortex->fixed_res, en, VORTEX_RESOURCE_MIXIN); vortex->mixwt[(i * NR_WTROUTES) + ii] = mix; vortex_route(vortex, en, 0x11, ADB_WTOUT(i, ii + 0x20), ADB_MIXIN(mix)); vortex_connection_mixin_mix(vortex, en, mix, vortex->mixplayb[ii % 2], 0); if (VORTEX_IS_QUAD(vortex)) vortex_connection_mixin_mix(vortex, en, mix, vortex->mixplayb[2 + (ii % 2)], 0); } } for (i = 0; i < NR_WT; i++) { hwwrite(vortex->mmio, WT_RUN(i), 1); } }
static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { vortex_t *vortex = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2); uinfo->value.integer.min = -128; uinfo->value.integer.max = 32; return 0; }
static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int i; vortex_t *vortex = snd_kcontrol_chip(kcontrol); int subdev = kcontrol->id.subdevice; struct pcm_vol *p = &vortex->pcm_vol[subdev]; int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); for (i = 0; i < max_chn; i++) ucontrol->value.integer.value[i] = p->vol[i]; return 0; }
static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int i; int changed = 0; int mixin; unsigned char vol; vortex_t *vortex = snd_kcontrol_chip(kcontrol); int subdev = kcontrol->id.subdevice; struct pcm_vol *p = &vortex->pcm_vol[subdev]; int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); for (i = 0; i < max_chn; i++) { if (p->vol[i] != ucontrol->value.integer.value[i]) { p->vol[i] = ucontrol->value.integer.value[i]; if (p->active) { switch (vortex->dma_adb[p->dma].nr_ch) { case 1: mixin = p->mixin[0]; break; case 2: default: mixin = p->mixin[(i < 2) ? i : (i - 2)]; break; case 4: mixin = p->mixin[i]; break; } vol = p->vol[i]; vortex_mix_setinputvolumebyte(vortex, vortex->mixplayb[i], mixin, vol); } changed = 1; } } return changed; }
/* create a pcm device */ static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) { struct snd_pcm *pcm; struct snd_kcontrol *kctl; int i; int err, nr_capt; if (!chip || 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 which can't capture. */ if (idx == VORTEX_PCM_ADB) nr_capt = nr; else nr_capt = 0; err = snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr, nr_capt, &pcm); if (err < 0) return err; snprintf(pcm->name, sizeof(pcm->name), "%s %s", CARD_NAME_SHORT, 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); switch (VORTEX_PCM_TYPE(pcm)) { case VORTEX_PCM_ADB: err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_std_chmaps, VORTEX_IS_QUAD(chip) ? 4 : 2, 0, NULL); if (err < 0) return err; err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE, snd_pcm_std_chmaps, 2, 0, NULL); if (err < 0) return err; break; #ifdef CHIP_AU8830 case VORTEX_PCM_A3D: err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_std_chmaps, 1, 0, NULL); if (err < 0) return err; break; #endif } 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; } } if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) { for (i = 0; i < NR_PCM; i++) { chip->pcm_vol[i].active = 0; chip->pcm_vol[i].dma = -1; kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip); if (!kctl) return -ENOMEM; chip->pcm_vol[i].kctl = kctl; kctl->id.device = 0; kctl->id.subdevice = i; err = snd_ctl_add(chip->card, kctl); if (err < 0) return err; } } return 0; }
/* open callback */ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) { vortex_t *vortex = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; /* Force equal size periods */ if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; /* Avoid PAGE_SIZE boundary to fall inside of a period. */ if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0) return err; snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 64); if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { #ifndef CHIP_AU8820 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) { runtime->hw = snd_vortex_playback_hw_a3d; } #endif if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) { runtime->hw = snd_vortex_playback_hw_spdif; switch (vortex->spdif_sr) { case 32000: runtime->hw.rates = SNDRV_PCM_RATE_32000; break; case 44100: runtime->hw.rates = SNDRV_PCM_RATE_44100; break; case 48000: runtime->hw.rates = SNDRV_PCM_RATE_48000; break; } } if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S) runtime->hw = snd_vortex_playback_hw_adb; #ifdef CHIP_AU8830 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && VORTEX_IS_QUAD(vortex) && VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { runtime->hw.channels_max = 4; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_au8830_channels); } #endif substream->runtime->private_data = NULL; } #ifndef CHIP_AU8810 else { runtime->hw = snd_vortex_playback_hw_wt; substream->runtime->private_data = NULL; } #endif return 0; }