6.6 azx_pcm_prepare
static int azx_pcm_prepare(struct snd_pcm_substream *substream)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int format_val, stream_tag;
int err;
struct hda_spdif_out *spdif =
snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
unsigned short ctls = spdif ? spdif->ctls : 0;
trace_azx_pcm_prepare(chip, azx_dev);
dsp_lock(azx_dev);
if (dsp_is_locked(azx_dev)) {
err = -EBUSY;
goto unlock;
}
snd_hdac_stream_reset(azx_stream(azx_dev));
format_val = snd_hdac_calc_stream_format(runtime->rate,
runtime->channels,
runtime->format,
hinfo->maxbps,
ctls);
if (!format_val) {
dev_err(chip->card->dev,
"invalid format_val, rate=%d, ch=%d, format=%d\n",
runtime->rate, runtime->channels, runtime->format);
err = -EINVAL;
goto unlock;
}
err = snd_hdac_stream_set_params(azx_stream(azx_dev), format_val);
if (err < 0)
goto unlock;
snd_hdac_stream_setup(azx_stream(azx_dev));
stream_tag = azx_dev->core.stream_tag;
/* CA-IBG chips need the playback stream starting from 1 */
if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
stream_tag > chip->capture_streams)
stream_tag -= chip->capture_streams;
err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
azx_dev->core.format_val, substream);
unlock:
if (!err)
azx_stream(azx_dev)->prepared = 1;
dsp_unlock(azx_dev);
return err;
}
理解这段代码,理解以下几个函数。
6.6.1 snd_hdac_stream_reset
void snd_hdac_stream_reset(struct hdac_stream *azx_dev)
{
unsigned char val;
int timeout;
int dma_run_state;
// 清除状态位
snd_hdac_stream_clear(azx_dev);
// 读取Run bit位确认当前是否时运行状态
dma_run_state = snd_hdac_stream_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START;
// 将SRST位写1
snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET);
udelay(3);
timeout = 300;
// 等待SRST位为1
do {
val = snd_hdac_stream_readb(azx_dev, SD_CTL) &
SD_CTL_STREAM_RESET;
if (val)
break;
} while (--timeout);
// 如果Run bit位为1,按要求等待一段时间
if (azx_dev->bus->dma_stop_delay && dma_run_state)
udelay(azx_dev->bus->dma_stop_delay);
// 将RSRT位写0
val &= ~SD_CTL_STREAM_RESET;
snd_hdac_stream_writeb(azx_dev, SD_CTL, val);
udelay(3);
// 等待RSRT位为0
timeout = 300;
/* waiting for hardware to report that the stream is out of reset */
do {
val = snd_hdac_stream_readb(azx_dev, SD_CTL) &
SD_CTL_STREAM_RESET;
if (!val)
break;
} while (--timeout);
/* reset first position - may not be synced with hw at this time */
if (azx_dev->posbuf)
*azx_dev->posbuf = 0;
}
这段代码是针对stream 寄存器中控制寄存器的处理。每个stream都有自己对应的寄存器,控制寄存器位于这些寄存器的开始位置。该寄存器暂用3个字节,其中0 bit位表示SRST(Stream Reset)。SRST的用法如下。
- 将该bit位写1,将导致stream中除了该位以外的内容都被重置。
- 当reset完成后,硬件才会将该bit位置1。软件必须从该bit位读取到1后,才能确认reset已经完成。
- 软件需要写0,通知硬件退出reset模式。
- 退出reset模式后,硬件会将该bit位置0。软件必须从该bit位读取到0后,才能访问其它的寄存器。