概念
8月底了试用期第二个月了,内心依旧有着大大的疑惑呢!
在之前的DAPM浅析(一)中,了解到widget route path 三个基本的概念。
widget:弥补了kcontrol的缺陷,实现了对kcontrols和电源管理信息的封装以及widget 链表
route: 描述连接关系
path :则作为widget之间的连接器
见图
为便于大家对照图去理解,特附上 struct snd_soc_dapm_widget,snd_soc_dapm_route 以及snd_soc_dapm_path 源码
/* dapm widget */
504 struct snd_soc_dapm_widget {
505 enum snd_soc_dapm_type id;
506 const char *name; /* widget name */
507 const char *sname; /* stream name */
508 struct snd_soc_codec *codec;
509 struct snd_soc_platform *platform;
// sound card widget list 部件互联
510 struct list_head list;
511 struct snd_soc_dapm_context *dapm;
512
513 void *priv; /* widget specific data */
514 struct regulator *regulator; /* attached regulator */
515 const struct snd_soc_pcm_stream *params; /* params for dai links */
516
517 /* dapm control */
518 int reg; /* negative reg = no direct dapm */
519 unsigned char shift; /* bits to shift */
520 unsigned int value; /* widget current value */
521 unsigned int mask; /* non-shifted mask */
522 unsigned int on_val; /* on state value */
523 unsigned int off_val; /* off state value */
524 unsigned char power:1; /* block power status */
525 unsigned char invert:1; /* invert the power bit */
526 unsigned char active:1; /* active stream on DAC, ADC's */
527 unsigned char connected:1; /* connected codec pin */
528 unsigned char new:1; /* cnew complete */
529 unsigned char ext:1; /* has external widgets */
530 unsigned char force:1; /* force state */
531 unsigned char ignore_suspend:1; /* kept enabled over suspend */
532 unsigned char new_power:1; /* power from this run */
533 unsigned char power_checked:1; /* power checked this run */
534 int subseq; /* sort within widget type */
535
536 int (*power_check)(struct snd_soc_dapm_widget *w);
537
538 /* external events */
539 unsigned short event_flags; /* flags to specify event types */
540 int (*event)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int);
541
542 /* kcontrols that relate to this widget */
// 可操作
543 int num_kcontrols;
544 const struct snd_kcontrol_new *kcontrol_news;
545 struct snd_kcontrol **kcontrols;
546
547 /* widget input and outputs */
// 与 snd_soc_dapm_path 中的 sink source 对应
548 struct list_head sources;
549 struct list_head sinks;
550
551 /* used during DAPM updates */
// connect to other widget power_list 见 dapm_seq_insert 源码
552 struct list_head power_list;
553 struct list_head dirty;
554 int inputs;
555 int outputs;
556
557 struct clk *clk;
558 };
/*
464 * DAPM audio route definition.
465 *
466 * Defines an audio route originating at source via control and finishing
467 * at sink.
468 */
469 struct snd_soc_dapm_route {
470 const char *sink;
471 const char *control;
472 const char *source;
473
474 /* Note: currently only supported for links where source is a supply */
475 int (*connected)(struct snd_soc_dapm_widget *source,
476 struct snd_soc_dapm_widget *sink);
477 };
/* dapm audio path between two widgets */
480 struct snd_soc_dapm_path {
//标识
481 const char *name;
482 const char *long_name;
483
484 /* source (input) and sink (output) widgets */
//path 作为连接器 source and sink 分别指向 源端和槽端 widget
485 struct snd_soc_dapm_widget *source;
486 struct snd_soc_dapm_widget *sink;
487 struct snd_kcontrol *kcontrol;
488
489 /* status */
490 u32 connect:1; /* source and sink widgets are connected */
491 u32 walked:1; /* path has been walked */
492 u32 walking:1; /* path is in the process of being walked */
493 u32 weak:1; /* path ignored for power management */
494 // 函数指针
495 int (*connected)(struct snd_soc_dapm_widget *source,
496 struct snd_soc_dapm_widget *sink);
497 //一个widget 对应多个path
// path 的 source 连接 source widget 的槽段
498 struct list_head list_source;
//path 的 sink 连接作为 sink widget 的源端 ,见上图
499 struct list_head list_sink;
500 struct list_head list;
501 };
不同域widget
1.codec域
这类域内的widget操作通常是在 codec驱动的probe/remove阶段或者是suspend和resume阶段。
实体操作:上下电,系统休眠唤醒(linux标准的电源管理,以及Android的PM具体见下回分解)
2.machine域
通常是物理上的接入输入,输出等用户指定操作,machine检测,则配置自然也在
machine中。其次machine 驱动区别于codec中的widget
(1)无寄存器比特位关联,无对应寄存器位控制,依赖于event 机制,即widget中的成员event_flags and event
(2)一个machine widget 对应一个 音频子部件 可以独立上电驱动,如下
扬声器
麦克风
插口jack (machine常常会通过插口jack来检测耳机的插拔)
3.path域
随混音器mixer以及mux多路选择器配置而自动配置,
路径域小部件能够控制或影响音频信号(PGA)或音频子系统中的音频路径
tinyalsa 工具的使用见 link
4.stream域
顾名思义 音频链路中有音频流时
对应card中的ADC DAC 以及AIF IN and AIF out
SND_SOC_DAPM_DAC(“HiFi DAC”, “HiFi Playback”, REG, 3, 1),
SND_SOC_DAPM_ADC(“HiFi ADC”, “HiFi Capture”, REG, 2, 1),
SND_SOC_DAPM_AIF_IN(“AIF1RX”, “AIF1 Playback”, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT(“AIF1TX”, “AIF1 Capture”, 0, SND_SOC_NOPM, 0, 0),
实体操作:playback/capture时
5.virtual widget
个人理解:实体部件存在codec 和 machine 音频表中,抽象出一个virtual widget 如
mixer(混音器)来对实际的widge 进行操作。
Sometimes widgets exist in the codec or machine audio map that don’t
have any corresponding soft power control. In this case it is
necessary to create a virtual widget - a widget with no control bits
e.g.SND_SOC_DAPM_MIXER(“AC97 Mixer”, SND_SOC_DAPM_NOPM, 0, 0, NULL, 0),
This can be used to merge to signal paths together in software.
After all the widgets have been defined, they can then be added to the
DAPM subsystem individually with a call to snd_soc_dapm_new_control().
After all the widgets have been defined, they can then be added to the
DAPM subsystem individually with a call to snd_soc_dapm_new_control().
event widgets
event widgets 可以向 DAPM core 注册一些感兴趣的widgets events
e.g. A Speaker with an amplifier registers a widget so the amplifier can be powered only when the spk is in use.
/* turn speaker amplifier on/off depending on use */
static int corgi_amp_event(struct snd_soc_dapm_widget w, int event)
{
gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event));
return 0;
}
/ corgi machine dapm widgets */
static const struct snd_soc_dapm_widget wm8731_dapm_widgets =
SND_SOC_DAPM_SPK(“Ext Spk”, corgi_amp_event);
带有功放的扬声器可以注册一个widget 以便可以检测指定情况,并进行对应的寄存器功能操作。
SND_SOC_DAPM_SPK辅助宏源码
#define SND_SOC_DAPM_SPK(wname, wevent) \
{ .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
event type
如下为event widget 支持的event type 以及使用场景
/* dapm event types /
#define SND_SOC_DAPM_PRE_PMU 0x1 / before widget power up /
#define SND_SOC_DAPM_POST_PMU 0x2 / after widget power up /
#define SND_SOC_DAPM_PRE_PMD 0x4 / before widget power down /
#define SND_SOC_DAPM_POST_PMD 0x8 / after widget power down /
#define SND_SOC_DAPM_PRE_REG 0x10 / before audio path setup /
#define SND_SOC_DAPM_POST_REG 0x20 / after audio path setup */