Chinaunix首页 | 论坛 | 博客
  • 博客访问: 122666
  • 博文数量: 34
  • 博客积分: 69
  • 博客等级: 民兵
  • 技术积分: 233
  • 用 户 组: 普通用户
  • 注册时间: 2013-01-08 21:56
文章分类

全部博文(34)

文章存档

2014年(9)

2013年(25)

分类: Android平台

2014-09-02 09:46:16

Asoc : ALSA system on chip 即嵌入式设备中的 ALSA
分为三个部分:
以展讯 Sc882x 平台为例分析
注: 代码相关的描述,只写出我们关心的部分
1. Machine : 与具体的单板相关

kernel\sound\soc\sprd\Sc882x.c
sc882x_modinit
{
    //构造名为 soc-audio 的平台设备,根据 Linux 设备驱动模型,必定有一个名为 soc-audio 的平台驱动
    platform_device_alloc("soc-audio", -1);
    platform_set_drvdata(sc882x_snd_device, &sc882x_card);
    platform_device_add(sc882x_snd_device);
}

声卡结构:
static struct snd_soc_card sc882x_card =
{
.name = "sprdphone",
.dai_link = sc882x_dai,
}

// 这个结构体指定了 Codec、Codec Dai 和 Cpu、Cpu Dai 的名称
static struct snd_soc_dai_link sc882x_dai[] =
{
    .name = "sc882x-vbc",
    .stream_name = "vbc-dac",
    .codec_name = "sprd-codec",
    .platform_name = "sprd-pcm-audio",
    .cpu_dai_name = "vbc",
    .codec_dai_name = "sprd-codec-i2s",
}

kernel\sound\soc\soc-core.c

static struct platform_driver soc_driver = {
        .driver = {
        .name = "soc-audio",
        .owner = THIS_MODULE,
        .pm = &snd_soc_pm_ops,
    },
    .probe = soc_probe,
    .remove = soc_remove,
};
snd_soc_init
{
    platform_driver_register(&soc_driver);
}
根据总线设备驱动模型的原理,当发现有一个名为 soc-audio 的平台设备,则调用 soc_probe 函数
soc_probe
{
    // 注册声卡
    snd_soc_register_card
}
如何注册?
snd_soc_register_card
{
    //先分配一个 struct snd_soc_pcm_runtime *rtd 结构
    // 再把 struct snd_soc_card sc882x_card -> struct snd_soc_dai_link sc882x_dai 的数据copy到
    // struct snd_soc_pcm_runtime *rtd->dai_link
    card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) *
                   (card->num_links + card->num_aux_devs),GFP_KERNEL);
      for (i = 0; i < card->num_links; i++)
    card->rtd[i].dai_link = &card->dai_link[i];
    //实例化一个声卡结构
    snd_soc_instantiate_cards();
        snd_soc_instantiate_card

}

如何实例化?
snd_soc_instantiate_card
{
根据 snd_soc_card 中的 dai_link 中的 platform、cpu_dai、codec_dai、codec 的名字在各自链绑定对应的结构
soc_bind_dai_link(card, i);
//声卡从设备的绑定完成后,开始创建声卡
ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
card->owner, 0, &card->snd_card);
//探测 platform、cpu_dai、codec_dai、codec 并执行各自 probe函数,最后创建PCM数据流
soc_probe_dai_link
{
    .....
    soc_new_pcm(rtd, num);//创建 PCM 设备
    {
        snd_pcm_new
        static struct snd_device_ops ops = {
        .dev_free = snd_pcm_dev_free,
        .dev_register = snd_pcm_dev_register, //用来注册PCM设备
        .dev_disconnect = snd_pcm_dev_disconnect,
         };
    //创建 播放 和 录音 数据流
    snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)
    snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)
    创建一个声卡的 PCM 从设备 PCM 逻辑设备,指定对应的 struct snd_device_ops ops,在稍后的注册声卡设备时会调用snd_pcm_dev_register完成PCM设备的注册
    snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)
    {
    ...
    dev->ops = ops;
    }
//指定播放和录音流的 PCM ops,间接调用到ALSA驱动的各个函数
static struct snd_pcm_ops soc_pcm_ops = {
    .open = soc_pcm_open,
    .close = soc_codec_close,
    .hw_params = soc_pcm_hw_params,
    .hw_free = soc_pcm_hw_free,
    .prepare = soc_pcm_prepare,
    .trigger = soc_pcm_trigger,
    .pointer = soc_pcm_pointer,
    };
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
//调用 kernel\sound\soc\sprd\sprd_pcm.c 中的 .pcm_new = sprd_pcm_new,
platform->driver->pcm_new
}

}
// 注册声卡
snd_card_register
snd_device_register_all
// 会调用刚刚 pcm 设备的 snd_pcm_dev_register,来注册声卡上从设备,也包括其他的 Control.c、Hwdep.c、Rawmidi.c 等文件描述的声卡从设备
dev->ops->dev_register(dev)
snd_pcm_dev_register
{
     case SNDRV_PCM_STREAM_PLAYBACK:
    sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);
    devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
    break;
    case SNDRV_PCM_STREAM_CAPTURE:
    sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);
    devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
    break;
    // 注册声卡的从设备 PCM,最后会调用 device_create 创建 pcm 设备文件
    snd_register_device_for_dev(devtype, pcm->card, pcm->device,&snd_pcm_f_ops[cidx],pcm, str, dev)

}
// PCM 设备文件的 file_operation 结构
const struct file_operations snd_pcm_f_ops[2] = {
{
.owner = THIS_MODULE,
.write = snd_pcm_write,
.aio_write = snd_pcm_aio_write,
.open = snd_pcm_playback_open,
.release = snd_pcm_release,
.llseek = no_llseek,
.poll = snd_pcm_playback_poll,
.unlocked_ioctl = snd_pcm_playback_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
.get_unmapped_area = snd_pcm_get_unmapped_area,
},
{
.owner = THIS_MODULE,
.read = snd_pcm_read,
.aio_read = snd_pcm_aio_read,
.open = snd_pcm_capture_open,
.release = snd_pcm_release,
.llseek = no_llseek,
.poll = snd_pcm_capture_poll,
.unlocked_ioctl = snd_pcm_capture_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
.get_unmapped_area = snd_pcm_get_unmapped_area,
}

}














































阅读(3233) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~