alsa声卡驱动一:声卡的创建

Linux ALSA声卡驱动之二:Platform 1.Platform驱动在ASoC中的作用 ASoC被分为Machine,Platform和Codec三大部件,Platform驱动的主要作用是完成音频数据的管理,最终通过CPU的数字音频接口(DAI)把音频数据传送给Codec进行处理,最终由Codec输出驱动耳机或者是喇叭的音信信号。在具体实现上,ASoC有把Platform驱动分为两个部分:snd_soc_platform_drive... 阅读详情

对于Alsa的介绍跟大概框架我这里就不做纤细的总结了,需要了解可以去看
http://blog.youkuaiyun.com/droidphone/article/details/6271122
这个博客的文章,写得很好,我也是在对他文章的阅读跟源代码的阅读做出属于自己的总结。

声卡的创建流程

这里写图片描述
图片是一个声卡的简单的创建流程,最主要要关心的是snd_card跟PCM的创建跟注册。
由PCM的创建,我们可以看出PCM是挂在声卡snd_card下的,用下图来看一下snd_card的框架。
这里写图片描述
由图片我们可以很清楚看出来,一个声卡驱动主要需要实现的,就做snd_card、pcm、挂在pcm下的plaback跟capture。
接下来以ASOC的框架来了解一下声卡创建的过程。

ASOC

ASoC–ALSA System on Chip ,是建立在标准ALSA驱动层上,为了更好地支持嵌入式处理器和移动设备中的音频Codec的一套软件体系。在ASoc出现之前,内核对于SoC中的音频已经有部分的支持,不过会有一些局限性:
1、Codec驱动与SoC CPU的底层耦合过于紧密,这种不理想会导致代码的重复,例如,仅是wm8731的驱动,当时Linux中有分别针对4个平台的驱动代码。
2、音频事件没有标准的方法来通知用户,例如耳机、麦克风的插拔和检测,这些事件在移动设备中是非常普通的,而且通常都需要特定于机器的代码进行重新对音频路劲进行配置。
3、当进行播放或录音时,驱动会让整个codec处于上电状态,这对于PC没问题,但对于移动设备来说,这意味着浪费大量的电量。同时也不支持通过改变过取样频率和偏置电流来达到省电的目的。
ASoC正是为了解决上述种种问题而提出的,目前已经被整合至内核的代码树中:sound/soc。ASoC不能单独存在,他只是建立在标准ALSA驱动上的一个它必须和标准的ALSA驱动框架相结合才能工作。(来至http://blog.youkuaiyun.com/droidphone/article/details/7165482)

硬件架构

音频系统可以被划分为三个部分:1.板载硬件(Machine),2.Soc(Platform),3Codec;
1.Machine:指具体的某款开发板或者开发板,未platform以及code提供载体。
2.platform:指具体的某个Soc平台,主要跟音频驱动中,需要用的Soc的硬件资源有关,比如DMA,I2S,时钟等。将platform抽象出来的好处是,这样可以在不同的machine中使用而不需要改动。
3.codec:根据字面不难理解就是一个解码器,包含了I2S接口,A/D,D/A转化等。codec跟platform一样都是重用的部件,可以在不同的machine中使用不用改动。
这里写图片描述
图片为machine、platform、codec之间的关系。
我们以omapl138开发板为例,解码芯片tlv320aic3x。
我们先从裸机驱动方向思考:
soc(omapl138):需要做的工作EDMA、MCASP、时钟这方面的初始化,这部分工作在ASOC相当于platform,platform主要工作也是做这方面的初始化跟一些操作,其中还包含一个cpu_dai结构跟codec进行数据交互。
codec(tlv320aic3x):主要工作是通过i2c对芯片进行初始化跟配置,这部分工作也是相当于ASOC中codec的工作,对解码芯片进行初始化配置以及一些相对于的操作,以及包含一个codec_dai跟soc进行数据交互。
现在我们来思考这两部分是怎么关联起来的,其实这部分是在Machine完成的了。以我用的开发板为例子,machine在文件/sound/soc/davinci的davinci-evm.c中。

static int __init evm_init(void)
{
    struct snd_soc_card *evm_snd_dev_data;
    int index;
    int ret;

    if (machine_is_davinci_evm()) {
        evm_snd_dev_data = &dm6446_snd_soc_card_evm;
        index = 0;
    } else if (machine_is_davinci_dm355_evm()) {
        evm_snd_dev_data = &dm355_snd_soc_card_evm;
        index = 1;
    } else if (machine_is_davinci_dm365_evm()) {
        evm_snd_dev_data = &dm365_snd_soc_card_evm;
        index = 0;
    } else if (machine_is_davinci_dm6467_evm()) {
        evm_snd_dev_data = &dm6467_snd_soc_card_evm;
        index = 0;
    } else if (machine_is_davinci_da830_evm()) {
        evm_snd_dev_data = &da830_snd_soc_card;
        index = 1;
    } else if (machine_is_davinci_da850_evm()) {
        evm_snd_dev_data = &da850_snd_soc_card;
        index = 0;
    } else if (machine_is_davinci_da850_sdi()) {
#ifdef CONFIG_MACH_DAVINCI_DA850_SDI
        evm_snd_dev_data = &da850_sdi_snd_soc_card;
        index = 0;
#endif
    } else if (machine_is_omapl138_lcdkboard()) {
        evm_snd_dev_data = &da850_snd_soc_card;
        index = 0;
    } else
        return -EINVAL;

    evm_snd_device = platform_device_alloc("soc-audio", index);
    if (!evm_snd_device)
        return -ENOMEM;

    platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
    ret = platform_device_add(evm_snd_device);
    if (ret)
        platform_device_put(evm_snd_device);

    return ret;
}

static void __exit evm_exit(void)
{
    platform_device_unregister(evm_snd_device);
}

module_init(evm_init);
module_exit(evm_exit);

ret = platform_device_add(evm_snd_device);添加了一个platform_device,就一定会有platform_driver的存在,对应的platform_driver在/sound/soc/soc_core.c中。
platform_set_drvdata(evm_snd_device, evm_snd_dev_data);给evm_snd_device添加 了一个专用数据evm_snd_dev_data,用的开发板是davinci_da850,进入看,存在这样一个数据结构:

static struct snd_soc_card da850_snd_soc_card = {
    .name = "DA850/OMAP-L138 EVM",
    .owner = THIS_MODULE,
    .dai_link = &da850_evm_dai,
    .num_links = 1,
};

其中.dai_link = &da850_evm_dai就是我们machine跟据名字将platform跟codec联系起来的,进入&da850_evm_dai中

static struct snd_soc_dai_link da850_evm_dai = {
    .name = "TLV320AIC3X",
    .stream_name = "AIC3X",
    .cpu_dai_name= "davinci-mcasp.0",
    .codec_dai_name = "tlv320aic3x-hifi",
    .codec_name = "tlv320aic3x-codec.1-0018",
    .platform_name = "davinci-pcm-audio",
    .init = evm_aic3x_init,
    .ops = &evm_ops,
};

由结构体成员我们可以看到,我们上面提到的几个部分,codec、codec_dai、platform、cpu_dai的名字都在上面,就是通过名字的方式将这四个部分整合到machine中的。
接下来我们去看一下machine文件的platform_device对应的platform_driver,

static struct platform_driver soc_driver = {
    .driver     = {
        .name       = "soc-audio",
        .owner      = THIS_MODULE,
        .pm     = &snd_soc_pm_ops,
    },
    .probe      = soc_probe,
    .remove     = soc_remove,
};

进入.probe = soc_probe回调函数,

static int soc_probe(struct platform_device *pdev)
{
    struct snd_soc_card *card = platform_get_drvdata(pdev);
    int ret = 0;

    /*
     * no card, so machine driver should be registering card
     * we should not be here in that case so ret error
     */
    if (!card)
        return -EINVAL;

    /* Bodge while we unpick instantiation */
    card->dev = &pdev->dev;

    ret = snd_soc_register_card(card);
    if (ret != 0) {
        dev_err(&pdev->dev, "Failed to register card\n");
        return ret;
    }

    return 0;
}

card->dev = &pdev->dev;将card->dev 指向platf_device的私有数据,即上面提到的struct snd_soc_dai_link da850_evm_dai这个结构体,后面的声卡创建跟PCM创建跟这个结构体有这密切关系。
我们进入声卡的注册函数snd_soc_register_card(card);但其他的部分我们先不进行了解直接进入snd_soc_instantiate_cards()再进入snd_soc_instantiate_card(card)中:
这个函数的第一步是通过函数soc_bind_dai_link对card_link进行名字的关联

    struct snd_soc_dai_link *dai_link = &card->dai_link[num];
    struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
    struct snd_soc_codec *codec;
    struct snd_soc_platform *platform;
    struct snd_soc_dai *codec_dai, *cpu_dai;
    const char *platform_name;

    if (rtd->complete)
        return 1;
    dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);

    /* do we already have the CPU DAI for this link ? */
    if (rtd->cpu_dai) {
        goto find_codec;
    }
    /* no, then find CPU DAI from registered DAIs*/
    list_for_each_entry(cpu_dai, &dai_list, list) {
        if (dai_link->cpu_dai_of_node) {
            if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
                continue;
        } else {
            if (strcmp(cpu_dai->name, dai_link->cpu_dai_name))
                continue;
        }

        rtd->cpu_dai = cpu_dai;
        goto find_codec;
    }

从list_for_each_entry(cpu_dai, &dai_list, list)取出cpu_dai,再跟card_link的cpu_dai_name进行匹配,如果匹配上将cpu_dai放入rtd->cpu_dai,既将匹配到的cpu_dai赋值给card的成员snd_soc_pcm_runtime的cpu_dai。后面的codec、codec_dai、platform是通过一样的方式进行匹配的。经过这个过程,card的成员snd_soc_pcm_runtime:(card->rtd)中保存了本Machine中使用的Codec,DAI和Platform驱动的信息。
返回snd_soc_instantiate_card中
第二步、通过

ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
            card->owner, 0, &card->snd_card);

进行声卡的创建,对这个函数是不是很熟悉,就是最前面提到的声卡创建步骤的第一步;
第三步:调用各个子结构的probe函数,对soc跟cedec进行相对应的初始化

for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
            order++) {
        for (i = 0; i < card->num_links; i++) {
            ret = soc_probe_dai_link(card, i, order);
            if (ret < 0) {
                pr_err("asoc: failed to instantiate card %s: %d\n",
                   card->name, ret);
                goto probe_dai_err;
            }
        }
    }

soc_probe_dai_link()函数中做了比较多的事情,把他展开继续讨论:

static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
{
    struct snd_soc_dai_link *dai_link = &card->dai_link[num];
    struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
    struct snd_soc_codec *codec = rtd->codec;
    struct snd_soc_platform *platform = rtd->platform;
    struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
    int ret;

    dev_dbg(card->dev, "probe %s dai link %d late %d\n",
            card->name, num, order);

    /* config components */
    codec_dai->codec = codec;
    cpu_dai->platform = platform;
    codec_dai->card = card;
    cpu_dai->card = card;

    /* set default power off timeout */
    rtd->pmdown_time = pmdown_time;

    /* probe the cpu_dai */
    if (!cpu_dai->probed &&
            cpu_dai->driver->probe_order == order) {
        if (!try_module_get(cpu_dai->dev->driver->owner))
            return -ENODEV;

        if (cpu_dai->driver->probe) {
            ret = cpu_dai->driver->probe(cpu_dai);
            if (ret < 0) {
                printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n",
                        cpu_dai->name);
                module_put(cpu_dai->dev->driver->owner);
                return ret;
            }
        }
        cpu_dai->probed = 1;
        /* mark cpu_dai as probed and add to card dai list */
        list_add(&cpu_dai->card_list, &card->dai_dev_list);
    }

    /* probe the CODEC */
    if (!codec->probed &&
            codec->driver->probe_order == order) {
        ret = soc_probe_codec(card, codec);
        if (ret < 0)
            return ret;
    }

    /* probe the platform */
    if (!platform->probed &&
            platform->driver->probe_order == order) {
        ret = soc_probe_platform(card, platform);
        if (ret < 0)
            return ret;
    }

    /* probe the CODEC DAI */
    if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
        if (codec_dai->driver->probe) {
            ret = codec_dai->driver->probe(codec_dai);
            if (ret < 0) {
                printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n",
                        codec_dai->name);
                return ret;
            }
        }

        /* mark codec_dai as probed and add to card dai list */
        codec_dai->probed = 1;
        list_add(&codec_dai->card_list, &card->dai_dev_list);
    }

    /* complete DAI probe during last probe */
    if (order != SND_SOC_COMP_ORDER_LAST)
        return 0;

    ret = soc_post_component_init(card, codec, num, 0);
    if (ret)
        return ret;

    ret = device_create_file(rtd->dev, &dev_attr_pmdown_time);
    if (ret < 0)
        printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");

    /* create the pcm */
    ret = soc_new_pcm(rtd, num);
    if (ret < 0) {
        printk(KERN_ERR "asoc: can't create pcm %s\n", dai_link->stream_name);
        return ret;
    }

    /* add platform data for AC97 devices */
    if (rtd->codec_dai->driver->ac97_control)
        snd_ac97_dev_add_pdata(codec->ac97, rtd->cpu_dai->ac97_pdata);

    return 0;
}

分别调用cpu_dai、codec、platform、codec_dai的probe函数,这些函数主要工作也是进行相对于的初始化,这里不作探讨,留到后面章节的总结再说。函数最后ret = soc_new_pcm(rtd, num),进行PCM设备的创建,进入函数

int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
{
    struct snd_soc_codec *codec = rtd->codec;
    struct snd_soc_platform *platform = rtd->platform;
    struct snd_soc_dai *codec_dai = rtd->codec_dai;
    struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
    struct snd_pcm_ops *soc_pcm_ops = &rtd->ops;
    struct snd_pcm *pcm;
    char new_name[64];
    int ret = 0, playback = 0, capture = 0;

    soc_pcm_ops->open   = soc_pcm_open;
    soc_pcm_ops->close  = soc_pcm_close;
    soc_pcm_ops->hw_params  = soc_pcm_hw_params;
    soc_pcm_ops->hw_free    = soc_pcm_hw_free;
    soc_pcm_ops->prepare    = soc_pcm_prepare;
    soc_pcm_ops->trigger    = soc_pcm_trigger;
    soc_pcm_ops->pointer    = soc_pcm_pointer;

    /* check client and interface hw capabilities */
    snprintf(new_name, sizeof(new_name), "%s %s-%d",
            rtd->dai_link->stream_name, codec_dai->name, num);

    if (codec_dai->driver->playback.channels_min)
        playback = 1;
    if (codec_dai->driver->capture.channels_min)
        capture = 1;

    dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
    ret = snd_pcm_new(rtd->card->snd_card, new_name,
            num, playback, capture, &pcm);
    if (ret < 0) {
        printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
        return ret;
    }

    /* DAPM dai link stream work */
    INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);

    rtd->pcm = pcm;
    pcm->private_data = rtd;
    if (platform->driver->ops) {
        soc_pcm_ops->mmap = platform->driver->ops->mmap;
        soc_pcm_ops->pointer = platform->driver->ops->pointer;
        soc_pcm_ops->ioctl = platform->driver->ops->ioctl;
        soc_pcm_ops->copy = platform->driver->ops->copy;
        soc_pcm_ops->silence = platform->driver->ops->silence;
        soc_pcm_ops->ack = platform->driver->ops->ack;
        soc_pcm_ops->page = platform->driver->ops->page;
    }

    if (playback)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, soc_pcm_ops);

    if (capture)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, soc_pcm_ops);

    if (platform->driver->pcm_new) {
        ret = platform->driver->pcm_new(rtd);
        if (ret < 0) {
            pr_err("asoc: platform pcm constructor failed\n");
            return ret;
        }
    }

    pcm->private_free = platform->driver->pcm_free;
    printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
        cpu_dai->name);
    return ret;
}

主要工作实行soc_pcm_ops成员函数

    soc_pcm_ops->open   = soc_pcm_open;
    soc_pcm_ops->close  = soc_pcm_close;
    soc_pcm_ops->hw_params  = soc_pcm_hw_params;
    soc_pcm_ops->hw_free    = soc_pcm_hw_free;
    soc_pcm_ops->prepare    = soc_pcm_prepare;
    soc_pcm_ops->trigger    = soc_pcm_trigger;
    soc_pcm_ops->pointer    = soc_pcm_pointer;

创建一个PCM:

ret = snd_pcm_new(rtd->card->snd_card, new_name,
            num, playback, capture, &pcm);

这一步就是最早说的声卡驱动创建步骤的第四步。
回到snd_soc_init_codec_cache中
第四步:对声卡进行注册

ret = snd_card_register(card->snd_card);

到此我们队ASOC框架下的声卡创建过程也大概探讨完了,这对我们对于我们做一个声卡驱动需要做的工作内容理解有很大帮助。下面是Asoc数据结构的静态关系图。
这里写图片描述
来自于:http://blog.youkuaiyun.com/droidphone/article/details/7165482
根据上面所说,我们可以大概知道,一个声卡的驱动主要工作是:
1.实现codec实例
2.实现codec_dai实例
3.实现platform实例
4.实现cpu_dai实例
5.machine通过名字对各个部分进行关联。
后面内容对这几个部分再进行了解。

有任何错误的地方,还望指出。

安装ALSA声卡驱动程序 1.下载下面4个软件包alsa-driver-1.0.22.tar.bz2alsa-lib-1.0.22.tar.bz2alsa-utils-1.0.22.tar.bz2alsaconf-0.4.3b.tar.gz   其中,前三个可以到http://www.alsa-project.org/main/index.php/Main_Page下载,alsaconf则到http:/ 阅读详情

相关推荐

安卓声卡驱动:1.ALSA简介

一 概述 安卓内核采用的是Linux内核,所以安卓也沿用了Linux内核内置的音频子系统。 Linux内核的音频子系统全称是Advanced Linux Sound Architecture,简称ALSA。 ALSA官网为https://www.alsa-project.org/wiki/Main_Page,在官网上有一些编程手册以及API介绍,也可以直接到Linux内核源码的 Documentation/sound 目录下去查阅编程信息 ALSA的版本是随同L

baidu_26866585的博客 2765

IMX6ul下tlv320aic3x音频驱动调试

原理图: tlv320aic3x音频芯片 功率放大器 移植分为三步: 1.codec 驱动 sound/soc/codecs/tlv320aic3x.c 2.平台驱动 sound/soc/imx/imx-tlv320aic3x.c 3.添加板文件   arch/arm/mach-mx6/board-mx6q_sabres

zhuwei852159448的博客 5274

基于imx6ul下调试tlv320aic3x声卡

因为这次声卡芯片是tlv320aic3101,从网上搜相关的资料可谓是少之又少,基本上都是有linux2.6版本的,基本上都是没有用到设备树DTB去适配,看了一下内核源码linux4.1.15只有sound/soc/codecs有tlv320aic3x.c和tlv320aic3x.h这两个文件,而sound/soc/fsl/就没有驱动tlv320aic3x的驱动文件。需要自己从网上去下载或者参照imx-sgtl5000.c去重新写一个。内核版本:linux4.1.15。核心板:imx6ul。

qq_45147279的博客 1331

Linux 内核 ASoC DMA 引擎驱动程序

Linux 内核 ASoC 框架,在概念上将嵌入式音频系统拆分为多个可复用的组件驱动程序,包括 Codec 类驱动程序、平台类驱动程序和机器类驱动程序。在实现上,机器类驱动程序用和结构描述,属于平台类驱动程序的 DMA 引擎驱动程序由结构描述,codec 类驱动程序和 I2S 等驱动程序,由和等结构描述。除平台类驱动程序外的各种驱动程序都通过 component 抽象组织在一起,即这些驱动程序都作为注册给 Linux 内核 ASoC 框架,Linux 内核 ASoC 框架为它们各自创建结构对象,并保存在。

tq08g2z的专栏 1470

Linux ALSA驱动框架(一)--ALSA架构简介--声卡的创建

(1)ALSA简介(1)Native ALSA Application:tinyplay/tinycap/tinymix,这些用户程序直接调用 alsa 用户库接口来实现放音、录音、控制ALSA Library API:alsa 用户库接口,常见有 tinyalsa、alsa-libALSA CORE:alsa 核心层,向上提供逻辑设备(PCM/CTL/MIDI/TIMER/…)系统调用,向下驱动...

sinat_37817094的博客 4万+

Appsflyer S2S事件上报实战:从参数获取到避坑指南(附Firebase对比)

本文详细解析了Appsflyer S2S事件上报的实战技巧,包括核心参数获取、测试环境搭建、生产环境最佳实践以及高级场景处理。通过对比Firebase的事件上报机制,帮助开发者高效避坑并优化数据上报流程,提升应用分析与营销效果。

egg99的博客 885

IMX6Q下tlv320aic3x音频驱动移植

imx6q下tlv320aic3x音频驱动移植

一梦十年 5805

Unity3D 集成 SQLite 数据库实战:从零搭建到数据可视化

本文详细介绍了在Unity3D项目中集成SQLite数据库的完整实战流程。从SQLite的轻量、稳定、易用特性讲起,逐步指导开发者完成环境配置、驱动集成、C#脚本编写(涵盖连接、建表、增删改查),并进阶演示了数据模型封装与在Unity UI中实现数据可视化的方法。最后提供了多线程访问、路径差异、性能优化等关键避坑指南,帮助开发者构建可靠高效的本地数据管理方案。

weixin_29291069的博客 91

Linux ALSA声卡驱动之六:ASoC架构中的Machine

前面一节的内容我们提到,ASoC被分为Machine、Platform和Codec三大部分,其中的Machine驱动负责Platform和Codec之间的耦合以及部分和设备或板子特定的代码,再次引用上一节的内容:Machine驱动负责处理机器特有的一些控件和音频事件(例如,当播放音频时,需要先行打开一个放大器);单独的Platform和Codec驱动是不能工作的,它必须由Machine驱动把它们结

DroidPhone的专栏 7万+

保姆级教程:用Ansys Workbench找出BGA焊点最容易坏的位置(附热循环+振动分析)

本文提供了一份详细的Ansys Workbench教程,指导如何通过热循环和振动分析找出BGA焊点最容易失效的位置。从模型搭建、材料定义到网格划分和载荷设置,全面解析了BGA焊点可靠性分析的全流程,帮助工程师提前预防焊点开裂问题,提升电子封装设计的可靠性。

weixin_30983965的博客 420

Avalonia v11实战:手把手教你从零创建第一个跨平台桌面App(含设计器不显示的解决方案)

本文详细介绍了如何使用Avalonia v11从零开始创建跨平台桌面应用,包括环境准备、项目创建、界面设计及常见问题解决方案。特别针对设计器不显示等常见问题提供了实用解决方法,帮助.NET开发者快速掌握这一强大的UI框架,实现Windows、macOS和Linux多平台应用开发。

weixin_30417487的博客 164

alsa架构下的声卡驱动开发一:声卡的创建与注册

我们直入主题,想要在alsa结构上完成驱动开发,其实就是依赖三板斧,首先这第一板斧就是需要先创建声卡,这里直接调用现成的函数就行,这里以一个platform driver的probe函数为例。int err;return err;

st13772178063的博客 1014

Keil中搭建自动化单元测试框架Unity

前言:   虽然一些C++的自动化单元测试框架也能用来C语言单元测试,但那样我们编写C语言程序时需要符合C++的标准,这样有一些C的特性是无法使用的,限制C的特性使用不太好,于是找了一个全部用C实现的自动化测试框架。Unity是一个简单且直接的自动化单元测试框架,它由很少的几个文件构成。 搭建环境:   1.从github上下载最新版本的Unity源码,下载链接:https://github...

程序员的自我修炼 3900

Linux ALSA声卡驱动之二:声卡的创建

声明:本博内容均由http://blog.youkuaiyun.com/droidphone原创,转载请注明出处,谢谢! 1. struct snd_card   1.1. snd_card是什么 snd_card可以说是整个ALSA音频驱动最顶层的一个结构,整个声卡的软件逻辑结构开始于该结构,几乎所有与声音相关的逻辑设备都是在snd_card的管理之下,声卡驱动的第一个动作通常就是创建一个snd_c

DroidPhone的专栏 9万+

2025数学建模美赛C题完整建模思路——奥运会奖牌榜的模型

2025数学建模美赛C题完整建模思路——奥运会奖牌榜的模型

Yilu264的博客 1万+

Ubuntu 22.04 搭建 PX4 飞控系统完全指南:从仿真到硬件试飞

定义消息文件protobufuint64 timestamp # 时间戳float32 temperature # 温度float32 humidity # 湿度生成代码:bashPX4 在 Ubuntu 22.04 的搭建涉及环境配置、编译仿真、硬件连接等多环节,核心是理解 PX4 1.14 的新特性(uXRCE-DDS、动态控制分配)。通过本文指南,开发者可快速构建稳定的 PX4 开发环境,为无人机应用开发奠定基础。

zqmgx13291的博客 3041

Linux ALSA声卡驱动之一:ALSA架构简介

声明:本博内容均由http://blog.youkuaiyun.com/droidphone原创,转载请注明出处,谢谢! 一.  概述     ALSA是Advanced Linux Sound Architecture 的缩写,目前已经成为了linux的主流音频体系结构,想了解更多的关于ALSA的这一开源项目的信息和知识,请查看以下网址:http://www.alsa-project.org/。

DroidPhone的专栏 15万+

Web渗/透/攻/击实战(1)—成功渗/透台湾某净化设备公司官网

写在前面 作为一个防御型白帽黑客​ 你一定要知道黑客的进攻套路 才能有相应的防御措施 声明:只做测试,发现对方的漏洞,并不进行破坏性操作 1、 网站分析 地址:http://www.xxx.com.tw/ 这是一家中国台湾地区的网站,看着满屏的繁体字,就不是很舒服 网站首页包括:关于我们、资料下载、联络方式等等。 这些对我们进行sql注入用处并不大 我们需要的是可以进行参数传入的页面,这样我们就可以在参数里做文章 找一下 有没有新闻列表相关的页面 页...

信息安全领域优质创作者|操作系统领域专家 1807

Linux ALSA声卡驱动之五:Machine 以及ALSA声卡的注册

一、Machine 简介 Machine是指某一款机器,可以是某款设备,某款开发板,又或者是某款智能手机,由此可以看出Machine几乎是不可重用的,每个Machine上的硬件实现可能都不一样,CPU不一样,Codec不一样,音频的输入、输出设备也不一样,Machine为CPU、Codec、输入输出设备提供了一个载体,用于描述一块电路板,它指明此块电路板上用的是哪个Platform和哪...

肖岩 5809

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Linux ALSA 之二:ALSA 声卡与设备

ALSA 声卡与设备

年少生而为人 7592

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

ALSA声卡驱动(二)声卡创建

文章目录 ALSA声卡驱动(一)初识alsa 目录文章目录1、声卡实例1.1、struct snd_card1.2、struct snd_devide2、声卡的创建流程2.1、创建一个声卡实例2.2、创建声卡芯片的专用数据2.3、设置Driver和ID和名字2.4、创建声卡的功能部件(逻辑设备)2.5、注册声卡3、snd_card_create()和snd_card_new()4、snd_card_register()总结 1、声卡实例 1.1、struct snd_card   snd_card可以说是整

Mr_zhangsq的博客 1555
上一篇: i2c子系统学习总结
下一篇: alsa声卡驱动二:ASoC框架中的Codec
BERLIN23
博客等级 码龄14年 7粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值