有关Alsa 代码的编写,推荐看看《wirte an alsa driver》,
等有时间,我也会针对它来写一些中文版的博客文章,敬请期待。
Codec 的作用:
音频芯片的控制,比如静音,打开/关闭 ADC/DAC,设置ADC/DAC的增益,耳机模式的检测等操作。
I2S:数字音频接口,用于CPU 和 Codec 之间的数字音频流 raw data 的传输。每当有 playback 或 record 操作时, snd_soc_dai_ops.prepare() 会被调用,启动 I2S 总线。
音频数据流向:
| copy_from_user | | DMA | | I2S/PCM/AC97 |
RAM--------------->dma buffer--------> I2S tx FIFO -----------------> CODEC -> SPK/Headset
codec 驱动代码位于 @\kernel\msm-3.18\sound\soc\codecs 目录下。
在学习Codec 前,我们先来学习下它的结构体,看懂了它的结构体,代码就差不多了。
snd_soc_dai 类似一个中枢结构体,它主要的功能有两个:
snd_soc_dai 结构体是 codec 最大的结构体,其中有几个很重要的成员:
@\kernel\msm-3.18\include\sound\soc-dai.h
/*
* Digital Audio Interface runtime data.
* Holds runtime data for a DAI.
*/
struct snd_soc_dai {
const char *name; // Codec DAI 的名字
int id; // Codec DAI 的 ID
struct device *dev;
void *ac97_pdata; /* codec 平台私有数据 platform_data for the ac97 codec */
/* driver ops */
struct snd_soc_dai_driver *driver; // Codec 驱动的核心结构体
/* DAI runtime info */
unsigned int capture_active:1; /* 是否允许Capture,默认为1, stream is in use */
unsigned int playback_active:1; /* 是否允许playback,默认为1, stream is in use */
unsigned int symmetric_rates:1;
unsigned int symmetric_channels:1;
unsigned int symmetric_samplebits:1;
unsigned int active;
unsigned char probed:1; // 是否已经 probe 过
struct snd_soc_dapm_widget *playback_widget; //播放的kcontrol
struct snd_soc_dapm_widget *capture_widget; //录音的kcontrol
/* DAI DMA data */
void *playback_dma_data; //播放时的dma buffer 地址
void *capture_dma_data; //录音时的dma buffer 地址
/* 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_platform *platform; // 所属的 平台驱动
struct snd_soc_codec *codec; // 所属的 codec
struct snd_soc_component *component; // 所属的 控件
/* CODEC TDM slot masks and params (for fixup) */
unsigned int tx_mask;
unsigned int rx_mask;
struct snd_soc_card *card; // 对应的声卡结构体
struct list_head list;
};
重要成员如下:
DAI driver callbacks
包含probe、remove、suspend、resume 等函数
当 snd_soc_codec_drive 和 codec device匹配后 Codec DAI 的回调函数
struct snd_soc_dai_ops:用于配置 codec 相关的硬件参数(后续分析)
struct snd_soc_pcm_stream capture/playback :Capture 和 playback 对应的详细参数
probe_order:probe 的顺序
@\kernel\msm-3.18\include\sound\soc-dai.h
struct snd_soc_dai_driver {
/* DAI description */
const char *name; // Codec DAI 的名字
unsigned int id; // Codec DAI 的 ID
int ac97_control; // codec 平台私有数据
unsigned int base;
/* DAI driver callbacks */
// 当 snd_soc_codec_drive 和 codec device匹配后 Codec DAI 的回调函数
int (*probe)(struct snd_soc_dai *dai);
int (*remove)(struct snd_soc_dai *dai);
int (*suspend)(struct snd_soc_dai *dai);
int (*resume)(struct snd_soc_dai *dai);
/* compress dai */
bool compress_dai;
/* ops */
const struct snd_soc_dai_ops *ops; // codec 字符设备结构体,用于配置 Codec 相关的参数
/* DAI capabilities */
struct snd_soc_pcm_stream capture;
struct snd_soc_pcm_stream playback;
unsigned int symmetric_rates:1;
unsigned int symmetric_channels:1;
unsigned int symmetric_samplebits:1;
/* probe ordering - for components with runtime dependencies */
int probe_order; // probe 的顺序
int remove_order; // remove 的顺序
};
重要成员如下:
设置 Codec DAI 时钟相关参数
set_sysclk(设置系统时钟)、set_clkdiv(设置时钟分频)等
设置 Codec DAI 的信号格式配置
set_fmt:配置数据格式
设置 Codec DAI 的静音操作函数
digital_mute:数字信号静音函数
mute_stream : 数据流静音函数
设置PCM 相关控制的操作方法,包手中 硬件参数设定
hw_params:硬件参数设定
@\kernel\msm-3.18\include\sound\soc.h
struct snd_soc_dai_ops {
/* 设置 Codec DAI 时钟相关参数
* 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);
/* 设置 Codec DAI 的信号格式配置
* 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 (*set_tristate)(struct snd_soc_dai *dai, int tristate);
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);
/* 设置 Codec DAI 的静音操作函数
* DAI digital mute - optional.
* Called by soc-core to minimise any pops.
*/
int (*digital_mute)(struct snd_soc_dai *dai, int mute);
int (*mute_stream)(struct snd_soc_dai *dai, int mute, int stream);
/* 设置PCM 相关控制的操作方法,包手中 硬件参数设定
* ALSA PCM audio operations - all optional.
* Called by soc-core during audio PCM operations.
*/
int (*startup)(struct snd_pcm_substream *,struct snd_soc_dai *);
void (*shutdown)(struct snd_pcm_substream *,struct snd_soc_dai *);
int (*hw_params)(struct snd_pcm_substream *,struct snd_pcm_hw_params *, struct snd_soc_dai *);
int (*hw_free)(struct snd_pcm_substream *,struct snd_soc_dai *);
int (*prepare)(struct snd_pcm_substream *,struct snd_soc_dai *);
/*
* NOTE: Commands passed to the trigger function are not necessarily compatible with the current state of the dai.
* For example this sequence of commands is possible: START STOP STOP.
* So do not unconditionally use refcounting functions in the trigger function, e.g. clk_enable/disable.
*/
int (*trigger)(struct snd_pcm_substream *, int, struct snd_soc_dai *);
int (*bespoke_trigger)(struct snd_pcm_substream *, int, struct snd_soc_dai *);
/*
* For hardware based FIFO caused delay reporting.
* Optional.
*/
snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,struct snd_soc_dai *);
};
配置具体的软件参数,如 传输速率,通道数,格式等。
@\kernel\msm-3.18\include\sound\soc.h
/* SoC PCM stream information */
struct snd_soc_pcm_stream {
const char *stream_name;
u64 formats; /* SNDRV_PCM_FMTBIT_* */
unsigned int rates; /* SNDRV_PCM_RATE_* */
unsigned int rate_min; /* min rate */
unsigned int rate_max; /* max rate */
unsigned int channels_min; /* min channels */
unsigned int channels_max; /* max channels */
unsigned int sig_bits; /* number of bits of content */
const char *aif_name; /* DAPM AIF widget name */
};
Audio 的 Codec device 结构体,重要成员如下:
struct snd_soc_codec_driver
绑定对应的codec driver 结构体
定义的 Codec 硬件寄存器读写操作方法
volatile_register(),readable_register() , writable_register()
codec IO
codec 控制数据指针 control_data
@\kernel\msm-3.18\include\sound\soc.h
/* SoC Audio Codec device */
struct snd_soc_codec {
struct device *dev;
const struct snd_soc_codec_driver *driver; // 对应的codec driver 结构体
struct mutex mutex;
struct list_head list;
struct list_head card_list;
// Codec 寄存器读写操作方法
int (*volatile_register)(struct snd_soc_codec *, unsigned int);
int (*readable_register)(struct snd_soc_codec *, unsigned int);
int (*writable_register)(struct snd_soc_codec *, unsigned int);
/* runtime */
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
unsigned int cache_bypass:1; /* Suppress access to the cache */
unsigned int suspended:1; /* Codec is in suspend PM state */
unsigned int ac97_registered:1; /* Codec has been AC97 registered */
unsigned int ac97_created:1; /* Codec has been created by SoC */
unsigned int cache_init:1; /* codec cache has been initialized */
u32 cache_sync; /* Cache needs to be synced to hardware */
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
hw_write_t hw_write;
void *reg_cache;
struct mutex cache_rw_mutex;
/* component */
struct snd_soc_component component;
/* dapm */
struct snd_soc_dapm_context dapm;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_reg;
#endif
};
最大的声卡结构体
@\kernel\msm-3.18\include\sound\soc.h
/* SoC card */
struct snd_soc_card {
const char *name; // 声卡 名字
const char *long_name;
const char *driver_name; // 声卡驱动 名字
struct device *dev;
struct snd_card *snd_card; // 绑定 snd_card 声卡结构体
struct module *owner; // 驱动模块
struct mutex mutex;
struct mutex dapm_mutex;
struct mutex dapm_power_mutex;
bool instantiated;
int (*probe)(struct snd_soc_card *card); // Card probe 函数
int (*late_probe)(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);
long pmdown_time;
// 绑定的 snd_soc_dai_link 结构休
/* CPU <--> Codec DAI links */
struct snd_soc_dai_link *dai_link;
int num_links;
struct snd_soc_pcm_runtime *rtd;
int num_rtd;
// Codec 配置结构体 struct snd_soc_codec_conf
/* 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 snd_soc_pcm_runtime *rtd_aux;
int num_aux_rtd;
// codec 的 snd_kcontrol_new 结构体
const struct snd_kcontrol_new *controls;
int num_controls;
/*
* Card-specific routes and widgets.
*/
// codec dapm 控件结构体 struct snd_soc_dapm_widget
const struct snd_soc_dapm_widget *dapm_widgets;
int num_dapm_widgets;
// codec dapm 回路结构体 struct snd_soc_dapm_route
const struct snd_soc_dapm_route *dapm_routes;
int num_dapm_routes;
bool fully_routed;
struct work_struct deferred_resume_work;
/* lists of probed devices belonging to this card */
struct list_head codec_dev_list;
struct list_head widgets;
struct list_head paths;
struct list_head dapm_list;
struct list_head dapm_dirty;
/* Generic DAPM context for the card */
// 声卡的 DAPM 信息 struct snd_soc_dapm_context
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;
struct dentry *debugfs_pop_time;
#endif
u32 pop_time;
void *drvdata;
};
@ \kernel\msm-3.18\include\sound\soc.h
struct snd_soc_codec_conf {
/*
* specify device either by device name, or by
* DT/OF node, but not both.
*/
const char *dev_name;
const struct device_node *of_node;
/*
* optional map of kcontrol, widget and path name prefixes that are
* associated per device
*/
const char *name_prefix;
};
kcontrol 结构体
@ \kernel\msm-3.18\include\sound\control.h
struct snd_kcontrol_new {
snd_ctl_elem_iface_t iface; /* interface identifier */
unsigned int device; /* device/client number */
unsigned int subdevice; /* subdevice (substream) number */
const unsigned char *name; /* ASCII name of item */
unsigned int index; /* index of item */
unsigned int access; /* access rights */
unsigned int count; /* count of same elements */
snd_kcontrol_info_t *info;
snd_kcontrol_get_t *get;
snd_kcontrol_put_t *put;
union {
snd_kcontrol_tlv_rw_t *c;
const unsigned int *p;
} tlv;
unsigned long private_value;
};
@ \kernel\msm-3.18\include\sound\soc-dapm.h
/* dapm widget */
struct snd_soc_dapm_widget {
enum snd_soc_dapm_type id;
const char *name; /* widget name */
const char *sname; /* stream name */
struct snd_soc_codec *codec;
struct list_head list;
struct snd_soc_dapm_context *dapm;
void *priv; /* widget specific data */
struct regulator *regulator; /* attached regulator */
const struct snd_soc_pcm_stream *params; /* params for dai links */
/* dapm control */
int reg; /* negative reg = no direct dapm */
unsigned char shift; /* bits to shift */
unsigned int mask; /* non-shifted mask */
unsigned int on_val; /* on state value */
unsigned int off_val; /* off state value */
unsigned char power:1; /* block power status */
unsigned char active:1; /* active stream on DAC, ADC's */
unsigned char connected:1; /* connected codec pin */
unsigned char new:1; /* cnew complete */
unsigned char ext:1; /* has external widgets */
unsigned char force:1; /* force state */
unsigned char ignore_suspend:1; /* kept enabled over suspend */
unsigned char new_power:1; /* power from this run */
unsigned char power_checked:1; /* power checked this run */
int subseq; /* sort within widget type */
int (*power_check)(struct snd_soc_dapm_widget *w);
/* external events */
unsigned short event_flags; /* flags to specify event types */
int (*event)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int);
/* kcontrols that relate to this widget */
int num_kcontrols;
const struct snd_kcontrol_new *kcontrol_news;
struct snd_kcontrol **kcontrols;
/* widget input and outputs */
struct list_head sources;
struct list_head sinks;
/* used during DAPM updates */
struct list_head power_list;
struct list_head dirty;
int inputs;
int outputs;
struct clk *clk;
};
@ \kernel\msm-3.18\include\sound\soc-dapm.h
struct snd_soc_dapm_route {
const char *sink;
const char *control;
const char *source;
/* Note: currently only supported for links where source is a supply */
int (*connected)(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink);
};
dapm 上下文环境变量
@ \kernel\msm-3.18\include\sound\soc-dapm.h
/* DAPM context */
struct snd_soc_dapm_context {
enum snd_soc_bias_level bias_level;
enum snd_soc_bias_level suspend_bias_level;
struct delayed_work delayed_work;
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
/* Go to BIAS_OFF in suspend if the DAPM context is idle */
unsigned int suspend_bias_off:1;
void (*seq_notifier)(struct snd_soc_dapm_context *,
enum snd_soc_dapm_type, int);
struct device *dev; /* from parent - for debug */
struct snd_soc_component *component; /* parent component */
struct snd_soc_card *card; /* parent card */
/* used during DAPM updates */
enum snd_soc_bias_level target_bias_level;
struct list_head list;
int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
int (*set_bias_level)(struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level);
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_dapm;
#endif
};
snd_pcm_runtime是pcm运行时的信息。当打开一个pcm子流时,pcm运行时实例就会分配给这个子流。它拥有很多多种信息:hw_params和sw_params配置拷贝,缓冲区指针,mmap记录,自旋锁等。snd_pcm_runtime对于驱动程序操作集函数是只读的,仅pcm中间层可以改变或更新这些信息。
@ \src\kernel\msm-3.18\include\sound\soc.h
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
struct snd_soc_pcm_runtime {
struct device *dev;
struct snd_soc_card *card; // 声卡结构体
struct snd_soc_dai_link *dai_link; // snd_soc_dai_link 结构体
struct mutex pcm_mutex;
enum snd_soc_pcm_subclass pcm_subclass;
struct snd_pcm_ops ops; // snd_pcm_ops pcm文件的操作方法,包括 打开,读,写等方法
unsigned int dev_registered:1;
/* Dynamic PCM BE runtime data */
struct snd_soc_dpcm_runtime dpcm[2];
int fe_compr;
long pmdown_time;
unsigned char pop_wait:1;
/* err in case of ops failed */
int err_ops;
/* runtime devices */
struct snd_pcm *pcm; // snd_pcm
struct snd_compr *compr;
struct snd_soc_codec *codec;
struct snd_soc_platform *platform;
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai;
struct snd_soc_component *component; /* Only valid for AUX dev rtds */
struct snd_soc_dai **codec_dais;
unsigned int num_codecs;
struct delayed_work delayed_work;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_dpcm_root;
struct dentry *debugfs_dpcm_state;
#endif
};
PCM 的字符设备文件操作方法结构体
@ \kernel\msm-3.18\include\sound\pcm.h
struct snd_pcm_ops {
int (*open)(struct snd_pcm_substream *substream);
int (*close)(struct snd_pcm_substream *substream);
int (*ioctl)(struct snd_pcm_substream * substream,
unsigned int cmd, void *arg);
int (*compat_ioctl)(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg);
int (*hw_params)(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params);
int (*hw_free)(struct snd_pcm_substream *substream);
int (*prepare)(struct snd_pcm_substream *substream);
int (*trigger)(struct snd_pcm_substream *substream, int cmd);
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
int (*delay_blk)(struct snd_pcm_substream *substream);
int (*wall_clock)(struct snd_pcm_substream *substream,
struct timespec *audio_ts);
int (*copy)(struct snd_pcm_substream *substream, int channel,
snd_pcm_uframes_t pos,
void __user *buf, snd_pcm_uframes_t count);
int (*silence)(struct snd_pcm_substream *substream, int channel,
snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
struct page *(*page)(struct snd_pcm_substream *substream,
unsigned long offset);
int (*mmap)(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
int (*ack)(struct snd_pcm_substream *substream);
int (*restart)(struct snd_pcm_substream *substream);
};
@ \kernel\msm-3.18\include\sound\soc-dpcm.h
/*
* Dynamic PCM runtime data.
*/
struct snd_soc_dpcm_runtime {
struct list_head be_clients;
struct list_head fe_clients;
int users;
struct snd_pcm_runtime *runtime;
struct snd_pcm_hw_params hw_params;
/* state and update */
enum snd_soc_dpcm_update runtime_update;
enum snd_soc_dpcm_state state;
int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
};
@ \kernel\msm-3.18\include\sound\pcm.h
struct snd_pcm {
struct snd_card *card;
struct list_head list;
int device; /* device number */
unsigned int info_flags;
unsigned short dev_class;
unsigned short dev_subclass;
char id[64];
char name[80];
struct snd_pcm_str streams[2];
struct mutex open_mutex;
wait_queue_head_t open_wait;
void *private_data;
void (*private_free) (struct snd_pcm *pcm);
struct device *dev; /* actual hw device this belongs to */
bool internal; /* pcm is for internal use only */
bool nonatomic; /* whole PCM operations are in non-atomic context */
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
struct snd_pcm_oss oss;
#endif
};
dsp 描述结构体
@ \kernel\msm-3.18\include\sound\compress_driver.h
/**
* struct snd_compr: Compressed device
* @name: DSP device name
* @dev: Device pointer
* @ops: pointer to DSP callbacks
* @private_data: pointer to DSP pvt data
* @card: sound card pointer
* @direction: Playback or capture direction
* @lock: device lock
* @device: device id
*/
struct snd_compr {
const char *name;
struct device *dev;
struct snd_compr_ops *ops;
void *private_data;
struct snd_card *card;
unsigned int direction;
struct mutex lock;
int device;
};
@ \kernel\msm-3.18\include\sound\soc.h
struct snd_soc_platform {
struct device *dev;
const struct snd_soc_platform_driver *driver;
unsigned int suspended:1; /* platform is suspended */
struct list_head list;
struct snd_soc_component component;
};
@ \kernel\msm-3.18\include\sound\soc.h
struct snd_soc_component {
const char *name;
int id;
const char *name_prefix;
struct device *dev;
struct snd_soc_card *card;
unsigned int active;
unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
unsigned int registered_as_component:1;
unsigned int probed:1;
struct list_head list;
struct snd_soc_dai_driver *dai_drv;
int num_dai;
const struct snd_soc_component_driver *driver;
struct list_head dai_list;
int (*read)(struct snd_soc_component *, unsigned int, unsigned int *);
int (*write)(struct snd_soc_component *, unsigned int, unsigned int);
struct regmap *regmap;
int val_bytes;
struct mutex io_mutex;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
#endif
/*
* DO NOT use any of the fields below in drivers, they are temporary and
* are going to be removed again soon. If you use them in driver code the
* driver will be marked as BROKEN when these fields are removed.
*/
/* Don't use these, use snd_soc_component_get_dapm() */
struct snd_soc_dapm_context dapm;
struct snd_soc_dapm_context *dapm_ptr;
const struct snd_kcontrol_new *controls;
unsigned int num_controls;
const struct snd_soc_dapm_widget *dapm_widgets;
unsigned int num_dapm_widgets;
const struct snd_soc_dapm_route *dapm_routes;
unsigned int num_dapm_routes;
struct snd_soc_codec *codec;
int (*probe)(struct snd_soc_component *);
void (*remove)(struct snd_soc_component *);
#ifdef CONFIG_DEBUG_FS
void (*init_debugfs)(struct snd_soc_component *component);
const char *debugfs_prefix;
#endif
};
在 snd_soc_dai_link 中没有实际的操作 方法,其充当的角色更多的是一个媒介的作用,
通过它,就能够找到对应的platform ,codec dai ,codec,CPU, cpu dai等。
在其结构体中,比较重要的
@\kernel\msm-3.18\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.
*/
const char *cpu_name; // CPU 的名字
struct device_node *cpu_of_node; // cpu 的dts 节点
/*
* 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.
*/
const char *cpu_dai_name; // Cpu dai 的名字
/*
* You MUST specify the link's codec, either by device name, or by
* DT/OF node, but not both.
*/
const char *codec_name; // codec 名字
struct device_node *codec_of_node; // codec 节点
/* You MUST specify the DAI name within the codec */
const char *codec_dai_name; // codec dai 的名字
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.
*/
const char *platform_name; // platform 的名字
struct device_node *platform_of_node; // platform 的dts 节点
int be_id; /* optional ID for machine driver BE identification */
const struct snd_soc_pcm_stream *params; // playbakc 和 capture 的参数
unsigned int dai_fmt; /* format to set on init */
enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
/* Keep DAI active over suspend */
unsigned int ignore_suspend:1; // 永不休眠
/* Symmetry requirements */
unsigned int symmetric_rates:1;
unsigned int symmetric_channels:1;
unsigned int symmetric_samplebits: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;
/* This DAI can support no host IO (no pcm data is copied to from host) */
unsigned int no_host_mode:2;
/* DPCM capture and Playback support */
unsigned int dpcm_capture:1;
unsigned int dpcm_playback:1;
/* pmdown_time is ignored at stop */
unsigned int ignore_pmdown_time:1;
/* codec/machine specific init - e.g. add machine controls */
int (*init)(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;
/* For unidirectional dai links */
bool playback_only;
bool capture_only;
/* this value determines what all ops can be started asynchronously */
enum snd_soc_async_ops async_ops;
};
struct snd_soc_dai_link_component {
const char *name;
const struct device_node *of_node;
const char *dai_name;
};
本来想详细整理学习下Audio 的结构体,
但写到后面发现,发现功力远远还不够,以致于在 6.1 中,后面挺多结构体都写不明白。
这里给未来的自已留个作业,等后面真的对Audio 有更深入的了解后,
再重新回来,查询梳理 Audio 各大结构体之间的关系。
Date:2019/09/22 - 14:21
参考博文:
https://blog.csdn.net/azloong/article/details/6146378
谢谢