再说声卡驱动操作实质

 

说说内核的ASoc架构的分层思想:

1、
对于内核而言,声卡Asoc架构是基于alsa架构的。在该架构里,操作声卡是最终会通过调用核心层的snd_pcm_ops函数来实现的:

原因:首先无论uda1314还是wm9714,都得调用函数snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1),在这个函数里会设置pcm。其中会通过snd_pcm_new_stream来创建播放和录音流snd_pcm_substream(pcm的成员),然后通过snd_pcm_set_ops(pcm,***, &soc_pcm_op)来实现substream->ops操作函数。

最终注册pcm是通过snd_pcm_dev_register函数来注册,在这个函数会指定pcm的操作函数:

err = snd_register_device_for_dev(devtype, pcm->card,pcm->device,&snd_pcm_f_ops[cidx], pcm, str, dev);

但是无论是打开还是播放等,最终都是会调用到核心层的snd_pcm_ops函数:

例如播放打开函数:

snd_pcm_playback_open

                snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);

snd_pcm_open函数就是核心层的snd_pcm_ops函数成员。

再例如播放函数:

snd_pcm_write

        snd_pcm_lib_write

              snd_pcm_lib_write1

                      snd_pcm_start

                             snd_pcm_action

                                   snd_pcm_do_start

                                              substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);

 

substream->ops->trigger就是核心层的soc_pcm_trigger函数了。

 

2、核心层的作用就是使得芯片和dma能合作一起来按我们的目的进行工作。所以在核心层调用的函数来说,以wm9714,内核主要分为了三部分:

dma函数部分,通过snd_soc_platform结构体来实现(wm9714芯片的对应于s3c24xx_soc_platform);

接口函数部分:通过snd_soc_dai结构体来实现(如ac97接口对应于s3c_ac97_dai);

芯片函数部分:通过snd_soc_dai_ops结构体来实现(如wm9714的芯片对应于wm9713_dai);

 

对于ac97接口,有个ac97接口操作函数结构体s3c_ac97_info。芯片层和接口层都是对芯片进行操作,都是通过这个函数来实现的。接口层的实现函数适合所有支持该接口的芯片,而芯片层则针对响应的开发板。

再者,对于dma层,一方面就是负责dma分配和释放,另一方面就是负责dma启动和停止。还有很重要的一点,就是dma如何和wm9714芯片实现“合作”。毕竟我们是声卡使用DMA来传输的,至少来告诉声卡我们使用的DMA地址在哪里,这样才能然声卡依靠DMA来正确传输数据。ac97在snd_soc_dai_ops的hw_params里把设置好的s3c_ac97_pcm_out\s3c_ac97_pcm_in赋给了cpu_dai->playback.dma_data(cpu_dai就是snd_soc_dai结构体)。

 

3、现在看看核心层让dma和wm9714工作的:

如果我们播放声音的时候,那么通过核心层的函数,来调用dma函数\接口函数\芯片函数,来使得wm9714处于播放状态(主要接口来实现),dma处于传输状态(dma函数来实现),原因就这么简单:

例如:打开函数---soc_pcm_open:

/*\接口函数部分*/

 if (cpu_dai->ops->startup) {
  ret = cpu_dai->ops->startup(substream, cpu_dai);
  if (ret < 0) {
   printk(KERN_ERR "asoc: can't open interface %s\n",
    cpu_dai->name);
   goto out;
  }
 }
/*DMA函数部分*/
 if (platform->pcm_ops->open) {
  ret = platform->pcm_ops->open(substream);
  if (ret < 0) {
   printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
   goto platform_err;
  }
 }

/*芯片函数*/

 if (codec_dai->ops->startup) {
  ret = codec_dai->ops->startup(substream, codec_dai);
  if (ret < 0) {
   printk(KERN_ERR "asoc: can't open codec %s\n",
    codec_dai->name);
   goto codec_dai_err;
  }
 }

 

再例如播放,在上面说过会调用soc_pcm_trigger函数:

/*对应于芯片部分,但是该函数对于WM9714不用实现*/
 if (codec_dai->ops->trigger) {
  ret = codec_dai->ops->trigger(substream, cmd, codec_dai);
  if (ret < 0)
   return ret;
 }
//s3c_dma_trigger-----对应DMA函数部分,控制DMA启动和停止
 if (platform->pcm_ops->trigger) {
  ret = platform->pcm_ops->trigger(substream, cmd);
  if (ret < 0)
   return ret;
 }
//s3c_ac97_trigger----对应wm9713硬件----------对应于ac97接口函数部分,操作WM9714硬件
 if (cpu_dai->ops->trigger) {
  ret = cpu_dai->ops->trigger(substream, cmd, cpu_dai);
  if (ret < 0)
   return ret;
 }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值