Rockchip RK3399 - ASoC Machine驱动基础

----------------------------------------------------------------------------------------------------------------------------

开发板 :NanoPC-T4开发板eMMC :16GBLPDDR3 :4GB显示屏 :15.6英寸HDMI接口显示屏u-boot :2023.04linux    :6.3----------------------------------------------------------------------------------------------------------------------------

Rockchip RK3399 - ALSA子系统我们介绍了ALSA子系统的软件架构,同时介绍了ALSA CORE核心数据结构和相关API。本节我们将会介绍ASoC软件体系中音频三大驱动模块(Codec、Platform 和Machine)中的Machine。

Machine driver描述了如何控制platform、codec、cpu dai(Digital Audio Interface,数字音频接口)和codec dai,使得互相配合在一起工作。单独的Platform和Codec驱动是不能工作的,它必须由Machine驱动把它们结合在一起才能完成整个设备的音频处理工作。

一、核心数据结构

ASoC的一切都从Machine驱动开始,包括声卡的注册,绑定Platform和Codec驱动等等,描述Machine 的最主要的几个数据结构分别是:snd_soc_card,snd_soc_dai,snd_soc_dai_driver、snd_soc_dai_link;当然了此外还有一些操作集相关的数据结构,比如snd_soc_ops、snd_soc_dai_ops;

  • snd_soc_card:ASoC中的核心数据结构,和ASLA CORE中的snd_card地位一样;用于对ASocC中的声卡设备进行统一抽象;可以认为snd_soc_card是整个 ASoc 数据结构的根本,由它开始,引出一系列的数据结构用于表述音频的各个特性和功能;snd_soc_card数据结构中引出了snd_soc_dai_link结构;
  • snd_soc_dai和snd_soc_dai_driver:用于描述dai以及dai驱动,根据codec端和soc端,分为codec_dai 和cpu_dai,在ASoC的Platform驱动和Codec驱动中也会使用到;所以这个我们单独拎出来说;
  • snd_soc_dai_link:用来描述音频数据链路以及板级操作函数,在snd_soc_dai_link中,指定了platform、codec、codec_dai、cpu_dai的名字;
1.1 struct snd_soc_card

ASoC中使用struct snd_soc_card数据结构来描述SoC声卡的所有信息,需要将该数据结构与我们上一节介绍的ALSA CORE中的struct snd_card区分开来;struct snd_soc_card定义在include/sound/soc.h;

/* SoC card */
struct snd_soc_card {
        const char *name;
        const char *long_name;
        const char *driver_name;
        const char *components;
#ifdef CONFIG_DMI
        char dmi_longname[80];
#endif /* CONFIG_DMI */
        char topology_shortname[32];

        struct device *dev;
        struct snd_card *snd_card;
        struct module *owner;

        struct mutex mutex;
        struct mutex dapm_mutex;

        /* Mutex for PCM operations */
        struct mutex pcm_mutex;
        enum snd_soc_pcm_subclass pcm_subclass;

        int (*probe)(struct snd_soc_card *card);
        int (*late_probe)(struct snd_soc_card *card);
        void (*fixup_controls)(struct snd_soc_card *card);
        int (*remove)(struct snd_soc_card *card);

        /* the pre and post PM functions are used to do any PM work before and
         * after the codec and DAI's do any PM work. */
        int (*suspend_pre)(struct snd_soc_card *card);
        int (*suspend_post)(struct snd_soc_card *card);
        int (*resume_pre)(struct snd_soc_card *card);
        int (*resume_post)(struct snd_soc_card *card);

        /* callbacks */
        int (*set_bias_level)(struct snd_soc_card *,
                              struct snd_soc_dapm_context *dapm,
                              enum snd_soc_bias_level level);
        int (*set_bias_level_post)(struct snd_soc_card *,
                                   struct snd_soc_dapm_context *dapm,
                                   enum snd_soc_bias_level level);

        int (*add_dai_link)(struct snd_soc_card *,
                            struct snd_soc_dai_link *link);
        void (*remove_dai_link)(struct snd_soc_card *,
                            struct snd_soc_dai_link *link);

        long pmdown_time;
        /* CPU <--> Codec DAI links  */
        struct snd_soc_dai_link *dai_link;  /* predefined links only */
        int num_links;  /* predefined links only */

        struct list_head rtd_list;
        int num_rtd;

        /* optional codec specific configuration */
        struct snd_soc_codec_conf *codec_conf;
        int num_configs;

        /*
         * optional auxiliary devices such as amplifiers or codecs with DAI
         * link unused
         */
        struct snd_soc_aux_dev *aux_dev;
        int num_aux_devs;
        struct list_head aux_comp_list;

        const struct snd_kcontrol_new *controls;
        int num_controls;

        /*
         * Card-specific routes and widgets.
         * Note: of_dapm_xxx for Device Tree; Otherwise for driver build-in.
         */
        const struct snd_soc_dapm_widget *dapm_widgets;
        int num_dapm_widgets;
        const struct snd_soc_dapm_route *dapm_routes;
        int num_dapm_routes;
        const struct snd_soc_dapm_widget *of_dapm_widgets;
        int num_of_dapm_widgets;
        const struct snd_soc_dapm_route *of_dapm_routes;
        int num_of_dapm_routes;

        /* lists of probed devices belonging to this card */
        struct list_head component_dev_list;
        struct list_head list;

        struct list_head widgets;
        struct list_head paths;
        struct list_head dapm_list;
        struct list_head dapm_dirty;

        /* attached dynamic objects */
        struct list_head dobj_list;

        /* Generic DAPM context for the card */
        struct snd_soc_dapm_context dapm;
        struct snd_soc_dapm_stats dapm_stats;
        struct snd_soc_dapm_update *update;
#ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_card_root;
#endif
#ifdef CONFIG_PM_SLEEP
        struct work_struct deferred_resume_work;
#endif
        u32 pop_time;

        /* bit field */
        unsigned int instantiated:1;
        unsigned int topology_shortname_created:1;
        unsigned int fully_routed:1;
        unsigned int disable_route_checks:1;
        unsigned int probed:1;
        unsigned int component_chaining:1;

        void *drvdata;
};

这个数据结构的内容比较多,我们只挑一些重点说一下:

  • name:声卡的名称;如果使用设备树,保存解析设备节点label或者simple-audio-card,name得到的信息;
  • long_name:更详细的名称;
  • driver_name:驱动程序的名称;
  • components:component标识符;
  • dev:分配给此声卡的设备;一般设置为平台设备的device;
  • snd_card:ALSA CORE中的声卡设备;
  • owner:指向驱动程序拥有者模块的指针;
  • pcm_subclass:PCM子类的枚举类型;
  • probe:probe是可选的函数,注册当前声卡设备时会回调该函数;
  • late_probe:late_probe是可选的函数,注册当前声卡设备时会回调该函数;
  • remove:remove是可选的函数,用于在设备被移除时执行特定的操作;
  • add_dai_link:snd_soc_add_pcm_runtime函数执行时会回调该函数;
  • remove_dai_link:
  • dai_link:指向动态分配得到的数组,每个元素都一个struct snd_soc_dai_link,即每一元素描述了一条音频数据链路(如果使用设备树,保存解析设备节点simple-audio-card,cpu、simple-audio-card,codec得到的dai_link);
  • num_links:dai_link指向数组的长度;
  • rtd_list:保存pcm runtime的链表;链表中存储的是struct snd_soc_pcm_runtime;
  • codec_conf:指向动态分配得到的数组,每个元素都是一个struct snd_soc_codec_conf,即每个元素描述一个codec_conf;
  • num_configs:codec_conf指向数组的长度;
  • aux_dev:指向动态分配得到的数组,每个元素都是一个struct snd_soc_aux_dev;如果使用设备树,保存解析设备节点simple-audio-card,aux-devs得到的aux_dev;
  • num_aux_devs:aux_dev指向的数组的长度;
  • controls:指向动态分配得到的数组,每个元素都是一个struct snd_kcontrol;如果使用设备树,保存解析设备节点simple-audio-card,pin-switches得到的kcontrol信息;
  • num_controls:controls指向的数组的长度;
  • dapm_widgets:指向动态分配得到的数组,每个元素都是一个struct snd_soc_dapm_widget ,即每个元素描述了一个widget控件;
  • num_dapm_widgets:dapm_widgets指向的数组的长度;
  • dapm_routes:指向动态分配得到的数组,每个元素都是一个struct snd_soc_dapm_route;
  • num_dapm_routes:dapm_routes指向的数组的长度;
  • of_dapm_widgets:指向动态分配得到的数组,每个元素都是一个struct snd_soc_dapm_widget ;如果使用设备树,保存解析设备节点simple-audio-card,widgets得到的音频控件信息;
  • num_of_dapm_widgets:of_dapm_widgets指向的数组的长度;
  • of_dapm_routes:指向动态分配得到的数组,每个元素都是一个struct snd_soc_dapm_route;如果使用设备树,保存解析设备节点simple-audio-card,routing得到的音频路由信息;
  • num_of_dapm_routes:of_dapm_routes指向的数组的长度;
  • component_dev_list:保存component的链表;链表中存放的数据类型为struct snd_soc_component;
  • widgets:保存widget的链表;链表中存放的数据类型为struct snd_soc_dapm_widget;
  • paths:保存path的链表;链表中存放的数据类型为struct snd_soc_dapm_path;
  • dapm_list:保存dapm域的链表;链表中存放的数据类型为struct snd_soc_dapm_context;
  • dapm_dirty:保存状态(包括电源状态、连接状态)发生改变的widget;链表中存放的数据类型为struct snd_soc_dapm_widget;
  • dapm:dapm上下文,struct snd_soc_dapm_context类型;
  • deferred_resume_work:用于在系统挂起(suspend)后执行延迟的恢复操作,func函数被设置为soc_resume_deferred;
  • drvdata:驱动程序的私有数据结构;
1.2 struct snd_soc_dai_link

ASoC使用struct snd_soc_dai_link数据结构来描述音频数据链路以及板级操作函数,在snd_soc_dai_link中,指定了platform、codec、codec_dai、cpu_dai的名字,Machine驱动将会利用这些名字去匹配已经在系统中注册的platform,codec,dai,这些注册的部件都是在另外相应的Platform驱动和Codec驱动的代码文件中定义的。

struct snd_soc_dai_link定义在include/sound/soc.h:

struct snd_soc_dai_link {
        /* config - must be set by machine driver */
        const char *name;                       /* Codec name */
        const char *stream_name;                /* Stream name */

        /*
         * You MAY specify the link's CPU-side device, either by device name,
         * or by DT/OF node, but not both. If this information is omitted,
         * the CPU-side DAI is matched using .cpu_dai_name only, which hence
         * must be globally unique. These fields are currently typically used
         * only for codec to codec links, or systems using device tree.
         */
        /*
         * You MAY specify the DAI name of the CPU DAI. If this information is
         * omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node
         * only, which only works well when that device exposes a single DAI.
         */
        struct snd_soc_dai_link_component *cpus;
        unsigned int num_cpus;

        /*
         * You MUST specify the link's codec, either by device name, or by
         * DT/OF node, but not both.
         */
        /* You MUST specify the DAI name within the codec */
        struct snd_soc_dai_link_component *codecs;
        unsigned int num_codecs;

        /*
         * You MAY specify the link's platform/PCM/DMA driver, either by
         * device name, or by DT/OF node, but not both. Some forms of link
         * do not need a platform. In such case, platforms are not mandatory.
         */
        struct snd_soc_dai_link_component *platforms;
        unsigned int num_platforms;

        int id; /* optional ID for machine driver link identification */

        const struct snd_soc_pcm_stream *params;
        unsigned int num_params;

        unsigned int dai_fmt;           /* format to set on init */

        enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */

        /* codec/machine specific init - e.g. add machine controls */
        int (*init)(struct snd_soc_pcm_runtime *rtd);

        /* codec/machine specific exit - dual of init() */
        void (*exit)(struct snd_soc_pcm_runtime *rtd);

        /* optional hw_params re-writing for BE and FE sync */
        int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
                        struct snd_pcm_hw_params *params);

        /* machine stream operations */
        const struct snd_soc_ops *ops;
        const struct snd_soc_compr_ops *compr_ops;

        /* Mark this pcm with non atomic ops */
        unsigned int nonatomic:1;

        /* For unidirectional dai links */
        unsigned int playback_only:1;
        unsigned int capture_only:1;

        /* Keep DAI active over suspend */
        unsigned int ignore_suspend:1;

        /* Symmetry requirements */
        unsigned int symmetric_rate:1;
        unsigned int symmetric_channels:1;
        unsigned int symmetric_sample_bits:1;

        /* Do not create a PCM for this DAI link (Backend link) */
        unsigned int no_pcm:1;

        /* This DAI link can route to other DAI links at runtime (Frontend)*/
        unsigned int dynamic:1;

        /* DPCM capture and Playback support */
        unsigned int dpcm_capture:1;
        unsigned int dpcm_playback:1;

        /* DPCM used FE & BE merged format */
        unsigned int dpcm_merged_format:1;
        /* DPCM used FE & BE merged channel */
        unsigned int dpcm_merged_chan:1;
        /* DPCM used FE & BE merged rate */
        unsigned int dpcm_merged_rate:1;

        /* pmdown_time is ignored at stop */
        unsigned int ignore_pmdown_time:1;

        /* Do not create a PCM for this DAI link (Backend link) */
        unsigned int ignore:1;

        /* This flag will reorder stop sequence. By enabling this flag
         * DMA controller stop sequence will be invoked first followed by
         * CPU DAI driver stop sequence
         */
        unsigned int stop_dma_first:1;

#ifdef CONFIG_SND_SOC_TOPOLOGY
        struct snd_soc_dobj dobj; /* For topology */
#endif
};

这个数据结构的内容比较多,我们只挑一些重点说一下:

  • name:指定名称,必须配置;
  • stream_name:指定Stream名称,必须配置;
  • cpus:指向动态分配得到的数组,每个元素都是一个struct snd_soc_dai_link_component(名称/设备树节点(二选一)以及dai的名称),即保存当前音频数据链路上的所有cpu设备;
  • num_cpus:cpus指向的数组长度,一般来说1条音频数据链路只有1个CPU、1个Codec;
  • codecs:指向动态分配得到的数组,每个元素都是一个struct snd_soc_dai_link_component(名称/设备树节点(二选一)以及dai名称),即保存当前音频数据链路上的所有codec设备;
  • num_codecs:codec指向的数组长度,一般来说1条音频数据链路只有1个CPU、1个Codec;
  • platforms:指向动态分配得到的数组,每个元素都是一个struct snd_soc_dai_link_component(通过名称/设备树节点字段指定cpu测的platform驱动名称,通常都是DMA驱动,用于音频数据传输);
  • num_platforms:platforms指向的数组长度;
  • id:可选的链接 ID,用于识别Machine driver link;
  • params:指定PCM流参数;
  • num_params:PCM流参数数量;
  • dai_fmt:数字音频接口格式;
  • trigger:DPCM(Direct Pulse Code Modulation)触发类型;
  • init:初始化函数,例如添加Machine controls;
  • exit:退出函数;
  • be_hw_params_fixup:可选的硬件参数重写函数;
  • ops:音频相关的操作集;重点留意 hw_params回调,一般来说这个回调是要实现的,用于配置 codec、codec_dai、cpu_dai 的数据格式和系统时钟;
  • compr_ops:数据压缩操作函数;
  • nonatomic:标记 PCM 是否使用非原子操作;
  • playback_only:标记 PCM 流是否只支持播放;
  • capture_only:标记 PCM 流是否只支持捕获;
  • ignore_suspend:标记 PCM 是否在挂起时保持 DAI 活动状态;
  • symmetric_rate:标记 PCM 采样率是否对称;
  • symmetric_channels:标记 PCM 通道数是否对称;
  • symmetric_sample_bits:标记 PCM 采样位数是否对称;
  • no_pcm:标记 PCM 流是否需要创建;
  • dynamic:标记该 dai link是否可以在运行时路由到其他 dai link,具体可以参考DPCM相关内容;
  • dpcm_capture:标记是否支持 DPCM 捕获;
  • dpcm_playback:标记是否支持 DPCM 播放;
  • dpcm_merged_format:标记是否使用合并格式的 DPCM;
  • dpcm_merged_chan:标记是否使用合并通道的 DPCM;
  • dpcm_merged_rate:标记是否使用合并采样率的 DPCM;
  • ignore_pmdown_time:标记是否忽略 pmdown_time 停止时间;pmdown_time 是一种 PCM 的停止时间戳,用于控制 PCM 流在空闲一段时间后自动停止以降低功耗;
  • ignore:标记该dai link是否需要创建 PCM;
  • stop_dma_first:标记是否对停止序列进行排序;
1.3.1 snd_soc_dai_link_component 

ASoC使用struct snd_soc_dai_link_component来描述音频数据链路中的component,主要目的就是为了定位到snd_soc_component、snd_soc_dai,定义在include/sound/soc.h;

struct snd_soc_dai_link_component {
        const char *name;
        struct device_node *of_node;
        const char *dai_name;
};

其中:

  • name:名称,在非设备树场景使用;如果指定了这个,音频数据链路可以通过这个字段到全局链表component_list中查找与之匹配的component;
  • of_node:设备树节点,在设备树场景使用;如果指定了这个,音频数据链路可以通过这个字段到全局链表component_list中查找与之匹配的component;
  • dai_name:dai的名称,音频数据链路就是通过这个字段到匹配的component的dai_list链表中查找与之匹配的dai;
1.3.2 struct snd_soc_ops

ASoC使用struct snd_soc_ops来描述ALSA PCM操作集,定义在include/sound/soc.h;

/* SoC audio ops */
struct snd_soc_ops {
        int (*startup)(struct snd_pcm_substream *);
        void (*shutdown)(struct snd_pcm_substream *);
        int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
        int (*hw_free)(struct snd_pcm_substream *);
        int (*prepare)(struct snd_pcm_substream *);
        int (*trigger)(struct snd_pcm_substream *, int);
}

其中:

  • startup:在 PCM子流上启动音频传输期间调用;
  • shutdown:在PCM子流上关闭音频传输期间调用;
  • hw_params:更改PCM子流硬件参数期间调用;
  • hw_free:释放PCM子流资源期间调用;
  • prepare:准备PCM子流传输期间调用;
  • trigger:在PCM子流上触发执行操作期间调用;
1.3 DAI

DAI全称数字音频接口,根据codec端和soc端,分为codec_dai、cpu_dai,实际上dai也是一种widget。

描述dai的最主要的几个数据结构分别是:snd_soc_dai、snd_soc_dai_driver、snd_soc_dai_ops;

以cpu dai driver为例,每个cpu dai driver必须提供以下功能:

  • DAI描述信息;
  • DAI配置信息;
  • PCM描述信息;
  • 系统时钟(SYSCLK)配置;
  • 挂起和恢复(可选);

以codec dai driver为例,每个codec dai driver必须提供以下功能:

  • Codec DAI和PCM的配置信息;
  • Codec的控制接口,如I2C/SPI;
  • Mixer和其它音频控件;
  • Codec的音频操作;
1.3.1 struct snd_soc_dai

ALSA中使用struct snd_soc_dai数据结构来描述dai,定义在include/sound/soc-dai.h:

/*
 * Digital Audio Interface runtime data.
 *
 * Holds runtime data for a DAI.
 */
struct snd_soc_dai {
        const char *name;
        int id;
        struct device *dev;

        /* driver ops */
        struct snd_soc_dai_driver *driver;

        /* DAI runtime info */
        struct snd_soc_dai_stream stream[SNDRV_PCM_STREAM_LAST + 1];

        /* Symmetry data - only valid if symmetry is being enforced */
        unsigned int rate;
        unsigned int channels;
        unsigned int sample_bits;

        /* parent platform/codec */
        struct snd_soc_component *component;

        struct list_head list;

        /* function mark */
        struct snd_pcm_substream *mark_startup;
        struct snd_pcm_substream *mark_hw_params;
        struct snd_pcm_substream *mark_trigger;
        struct snd_compr_stream  *mark_compr_startup;

        /* bit field */
        unsigned int probed:1;
};
 

该数据结构包含以下字段:

  • name:dai的名称,音频数据链路在component的dai_list链表中查找dai时,就是通过该字段匹配来完成的;snd_soc_dai一般是在注册component时动态创建的,name字段值取自与之关联的snd_soc_dai_driver的name;
  • id:dai的标识符;
  • dev:指向包含该dai的设备的指针;
  • driver:指向dai驱动结构的指针;
  • stream:录音流和播放流的数组,其中包含有关流的信息;
  • rate:如果强制对称,则为采样率;
  • channels:如果强制对称,则为通道数;
  • sample_bits:如果强制对称,则为采样位数;
  • component:指向component(通常是 platform或codec)的指针;
  • list:用于构建链表节点,用于将该dai添加到到component的dai_list链表中;
  • mark_startup:用于标记PCM启动事件的指针;
  • mark_hw_params:用于标记PCM硬件参数变化事件的指针;
  • mark_trigger:用于标记PCM触发事件的指针;
  • mark_compr_startup:用于标记压缩流启动事件的指针;
  • probed:标记dai是否已经探测完成;
1.3.2  struct snd_soc_dai_stream 

ALSA中使用struct snd_soc_dai_stream数据结构来表示音频数据流,定义在include/sound/soc-dai.h:

/* for Playback/Capture */
struct snd_soc_dai_stream {
        struct snd_soc_dapm_widget *widget;

        unsigned int active;    /* usage count */
        unsigned int tdm_mask;  /* CODEC TDM slot masks and params (for fixup) */

        void *dma_data;         /* DAI DMA data */
};

数据结构中有一个widget指针,可以用来代表播放流/录音流。

1.3.3 struct snd_soc_dai_driver

ALSA中使用struct snd_soc_dai_driver数据结构来描述DAI驱动,包括DAI和PCM的能力和操作,定义在include/sound/soc-dai.h:

/*
 * Digital Audio Interface Driver.
 *
 * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
 * operations and capabilities. Codec and platform drivers will register this
 * structure for every DAI they have.
 *
 * This structure covers the clocking, formating and ALSA operations for each
 * interface.
 */
struct snd_soc_dai_driver {
        /* DAI description */
        const char *name;
        unsigned int id;
        unsigned int base;
        struct snd_soc_dobj dobj;

        /* DAI driver callbacks */
        int (*probe)(struct snd_soc_dai *dai);
        int (*remove)(struct snd_soc_dai *dai);
        /* compress dai */
        int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
        /* Optional Callback used at pcm creation*/
        int (*pcm_new)(struct snd_soc_pcm_runtime *rtd,
                       struct snd_soc_dai *dai);

        /* ops */
        const struct snd_soc_dai_ops *ops;
        const struct snd_soc_cdai_ops *cops;

        /* DAI capabilities */
        struct snd_soc_pcm_stream capture;
        struct snd_soc_pcm_stream playback;
        unsigned int symmetric_rate:1;
        unsigned int symmetric_channels:1;
        unsigned int symmetric_sample_bits:1;

        /* probe ordering - for components with runtime dependencies */
        int probe_order;
        int remove_order;
};

该数据结构包含了以下字段:

  • name:指定dai的名称;
  • id:可选的dai标识符,用于在注册期间区分多个dai;
  • base:可选的dai寄存器基地址;
  • dobj:dai对象,包含dai及其父组件的句柄;
  • probe:可选的dai探测回调函数;注册声卡时回调;
  • remove:可选的dai卸载回调函数;
  • compress_new:可选的压缩dai创建回调函数;
  • pcm_new:可选的 PCM 创建回调函数;
  • ops:指向本dai的snd_soc_dai_ops结构,即dai的操作集,这个操作集非常重要,用于dai的时钟配置、格式配置、硬件参数配置;
  • cops:dai压缩操作函数指针表;
  • capture:描述capture的能力;如回放设备所支持的声道数、采样率、音频格式;非常重要的字段;
  • playbackk:描述playback的能力;如录制设备所支持声道数、采样率、音频格式;非常重要的字段;
  • symmetric_rate:标记dai采样率是否对称;
  • symmetric_channels:标记dai通道数是否对称;
  • symmetric_sample_bits:标记dai采样位数是否对称;
  • probe_order:probe函数执行顺序;
  • remove_order:remove函数执行顺序;
1.3.4 struct snd_soc_dai_ops
ASoC使用struct snd_soc_dai_ops数据结构描述dai的控制和参数配置,这些函数包括对dai时钟配置、对 dai格式配置、对 TDM(时分复用)通道配置以及对 ALSA PCM音频操作的配置等。定义在include/sound/soc-dai.h:
struct snd_soc_dai_ops {
        /*
         * DAI clocking configuration, all optional.
         * Called by soc_card drivers, normally in their hw_params.
         */
        int (*set_sysclk)(struct snd_soc_dai *dai,
                int clk_id, unsigned int freq, int dir);
        int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source,
                unsigned int freq_in, unsigned int freq_out);
        int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
        int (*set_bclk_ratio)(struct snd_soc_dai *dai, unsigned int ratio);

        /*
         * DAI format configuration
         * Called by soc_card drivers, normally in their hw_params.
         */
        int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
        int (*xlate_tdm_slot_mask)(unsigned int slots,
                unsigned int *tx_mask, unsigned int *rx_mask);
        int (*set_tdm_slot)(struct snd_soc_dai *dai,
                unsigned int tx_mask, unsigned int rx_mask,
                int slots, int slot_width);
        int (*set_channel_map)(struct snd_soc_dai *dai,
                unsigned int tx_num, unsigned int *tx_slot,
                unsigned int rx_num, unsigned int *rx_slot);
        int (*get_channel_map)(struct snd_soc_dai *dai,
                        unsigned int *tx_num, unsigned int *tx_slot,
                        unsigned int *rx_num, unsigned int *rx_slot);
        int (*set_tristate)(struct snd_soc_dai *dai, int tristate);

        int (*set_stream)(struct snd_soc_dai *dai,
                          void *stream, int direction);
        void *(*get_stream)(struct snd_soc_dai *dai, int direction);

        /*
         * DAI digital mute - optional.
         * Called by soc-core to minimise any pops.
         */
        int (*mute_stream)(struct snd_soc_dai *dai, int mute, int stream);

        /*
         * ALSA PCM audio operations - all optional.
         * Called by soc-core during audio PCM operations.
         */
       
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Graceful_scenery

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值