static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var, unsigned int val, int dir) { int changed; if (hw_is_mask(var)) { struct snd_mask *m = hw_param_mask(params, var); if (val == 0 && dir < 0) { changed = -EINVAL; snd_mask_none(m); } else { if (dir > 0) val++; else if (dir < 0) val--; changed = snd_mask_refine_set( hw_param_mask(params, var), val); } } else if (hw_is_interval(var)) { struct snd_interval *i = hw_param_interval(params, var); if (val == 0 && dir < 0) { changed = -EINVAL; snd_interval_none(i); } else if (dir == 0) changed = snd_interval_refine_set(i, val); else { struct snd_interval t; t.openmin = 1; t.openmax = 1; t.empty = 0; t.integer = 0; if (dir < 0) { t.min = val - 1; t.max = val; } else { t.min = val; t.max = val+1; } changed = snd_interval_refine(i, &t); } } else { return -EINVAL; } if (changed) { params->cmask |= 1 << var; params->rmask |= 1 << var; } return changed; }
static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_interval *rate; struct snd_mask *mask; rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); rate->max = rate->min = priv->asrc_rate; mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); snd_mask_none(mask); snd_mask_set(mask, priv->asrc_format); return 0; }
static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct imx_priv *priv = &card_priv; hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min = priv->fe_output_rate; hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max = priv->fe_output_rate; snd_mask_none(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT)); if (priv->fe_output_width == 16) snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), SNDRV_PCM_FORMAT_S16_LE); else snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), SNDRV_PCM_FORMAT_S24_LE); return 0; }
static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct imx_priv *priv = &card_priv; struct snd_interval *rate; struct snd_mask *mask; if (!priv->asrc_pdev) return -EINVAL; rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); rate->max = rate->min = priv->asrc_rate; mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); snd_mask_none(mask); snd_mask_set(mask, priv->asrc_format); return 0; }
static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var, unsigned int val, int dir) { int changed; int open = 0; if (dir) { if (dir < 0) { open = 1; } else if (dir > 0) { open = 1; val++; } } if (hw_is_mask(var)) { if (val == 0 && open) { snd_mask_none(hw_param_mask(params, var)); changed = -EINVAL; } else changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!open); } else if (hw_is_interval(var)) changed = snd_interval_refine_max(hw_param_interval(params, var), val, open); else return -EINVAL; if (changed) { params->cmask |= 1 << var; params->rmask |= 1 << var; } return changed; }
/* * here goes a really tricky part; hw_refine falls back to ACCESS_RW_* type * when ACCESS_MMAP_* isn't supported by the hardware. */ static int snd_pcm_mmap_emul_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { mmap_emul_t *map = pcm->private_data; int err = 0; snd_pcm_access_mask_t oldmask = *snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS); snd_pcm_access_mask_t mask; const snd_mask_t *pmask; snd_mask_none(&mask); err = snd_pcm_hw_refine(map->gen.slave, params); if (err < 0) { snd_pcm_hw_params_t new = *params; /* try to use RW_* */ if (snd_pcm_access_mask_test(&oldmask, SND_PCM_ACCESS_MMAP_INTERLEAVED) && !snd_pcm_access_mask_test(&oldmask, SND_PCM_ACCESS_RW_INTERLEAVED)) snd_pcm_access_mask_set(&mask, SND_PCM_ACCESS_RW_INTERLEAVED); if (snd_pcm_access_mask_test(&oldmask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED) && !snd_pcm_access_mask_test(&oldmask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) snd_pcm_access_mask_set(&mask, SND_PCM_ACCESS_RW_NONINTERLEAVED); if (snd_pcm_access_mask_empty(&mask)) return err; pmask = snd_pcm_hw_param_get_mask(&new, SND_PCM_HW_PARAM_ACCESS); *(snd_mask_t *)pmask = mask; err = snd_pcm_hw_refine(map->gen.slave, &new); if (err < 0) return err; *params = new; }
int ksnd_pcm_set_params(ksnd_pcm_t *pcm, int nrchannels, int sampledepth, int samplerate, int periodsize, int buffersize) { snd_pcm_substream_t *substream = pcm->substream; snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_hw_params_t *hw_params = NULL; snd_pcm_sw_params_t *sw_params = NULL; int err; int format; snd_mask_t mask; int i; void *hwbuf; err = ksnd_pcm_hw_params_malloc(&hw_params); if (0 != err) goto failure; sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL); if (!sw_params) { err = -ENOMEM; goto failure; } switch (sampledepth) { case 16: format = SNDRV_PCM_FORMAT_S16_LE; break; case 24: sampledepth = 32; /*FALLTHRU*/ case 32: format = SNDRV_PCM_FORMAT_S32_LE; break; default: snd_printd("%s Unsupported sampledepth %d\n", __FUNCTION__, sampledepth); err = -EINVAL; goto failure; } err = ksnd_pcm_hw_params_any(pcm, hw_params); if (snd_BUG_ON(err < 0)) goto failure; _snd_pcm_hw_param_setinteger(hw_params, SNDRV_PCM_HW_PARAM_PERIODS); _snd_pcm_hw_param_min(hw_params, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0); snd_mask_none(&mask); snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED); err = snd_pcm_hw_param_mask(substream, hw_params, SNDRV_PCM_HW_PARAM_ACCESS, &mask); if (err < 0) { err = -EINVAL; goto failure; } err = snd_pcm_hw_param_set(substream, hw_params, SNDRV_PCM_HW_PARAM_RATE, samplerate, 0); if (snd_BUG_ON(err < 0)) goto failure; err = snd_pcm_hw_param_near(substream, hw_params, SNDRV_PCM_HW_PARAM_CHANNELS, nrchannels, NULL); if (snd_BUG_ON(err < 0)) goto failure; err = snd_pcm_hw_param_near(substream, hw_params, SNDRV_PCM_HW_PARAM_FORMAT, format, 0); if (snd_BUG_ON(err < 0)) goto failure; err = snd_pcm_hw_param_near(substream, hw_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, periodsize, NULL); if (snd_BUG_ON(err < 0)) goto failure; err = snd_pcm_hw_param_near(substream, hw_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, buffersize, NULL); if (snd_BUG_ON(err < 0)) goto failure; _ksnd_pcm_drop(substream); /*now we re-use the 61937 control to enable the HW sync mechanism */ if (0 != (err = ksnd_pcm_hw_params(pcm, hw_params) < 0)) { snd_printd("HW_PARAMS failed: for %d:%d code is %i\n", substream->pcm->card->number, substream->pcm->device, err); goto failure; } memset(sw_params, 0, sizeof(*sw_params)); sw_params->start_threshold = (runtime->buffer_size - (runtime->period_size * 2)); sw_params->stop_threshold = runtime->buffer_size; sw_params->period_step = 1; sw_params->sleep_min = 0; sw_params->avail_min = runtime->period_size; sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; sw_params->silence_threshold = runtime->period_size; sw_params->silence_size = runtime->period_size; if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) { snd_printd("SW_PARAMS failed: for %d:%d code is %i\n", substream->pcm->card->number, substream->pcm->device, err); goto failure; } if ((err = ksnd_pcm_prepare(pcm)) < 0) goto failure; if (pcm->hwareas[0].addr) iounmap(pcm->hwareas[0].addr); hwbuf = ioremap_nocache(runtime->dma_addr, runtime->dma_bytes); for (i = 0; i < nrchannels; i++) { pcm->hwareas[i].addr = hwbuf; pcm->hwareas[i].first = i * sampledepth; pcm->hwareas[i].step = nrchannels * sampledepth; } nrchannels = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_CHANNELS, 0); samplerate = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_RATE, 0); periodsize = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 0); buffersize = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0); printk(KERN_DEBUG "ksound: Set parameters for hw:%d,%d to %d x %dhz with period %d (of %d)\n", substream->pcm->card->number, substream->pcm->device, nrchannels, samplerate, periodsize, buffersize); err = 0; failure: if (hw_params) ksnd_pcm_hw_params_free(hw_params); if (sw_params) kfree(sw_params); return err; }