6. 播放音频(第四部分)

本文详细解析了音频播放过程中的azx_pcm_prepare函数,包括snd_hdac_stream_reset、snd_hdac_stream_set_params、snd_hdac_stream_setup等步骤。介绍了BDLE(Buffer Descriptor List Entry)和BDL(Buffer Descriptor List)的概念,以及如何设置它们。同时,讨论了相关寄存器的设置,如SD_CTL、SD_CBL、SD_FORMAT等,以确保音频数据的正确传输和处理。
摘要由CSDN通过智能技术生成

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的用法如下。

  1. 将该bit位写1,将导致stream中除了该位以外的内容都被重置。
  2. 当reset完成后,硬件才会将该bit位置1。软件必须从该bit位读取到1后,才能确认reset已经完成。
  3. 软件需要写0,通知硬件退出reset模式。
  4. 退出reset模式后,硬件会将该bit位置0。软件必须从该bit位读取到0后,才能访问其它的寄存器。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值