Linux 内核音频子系统调试

debugfs 文件系统

debugfs 可以为 Linux 内核各个模块的分析调试,提供许多信息,如音频子系统的 ASoC,以及 tracing 等。debugfs 文件系统可以通过命令行工具挂载,如下所示:

root@apollo:~# ls /sys/kernel/debug/root@apollo:~# mount -t debugfs nodev /sys/kernel/debugroot@apollo:~# ls /sys/kernel/debug/asoc                device_component    fault_around_bytes  mtd                 regulator           virtio-portsbdi                 devices_deferred    gpio                opp                 remoteproc          wakeup_sourcesblock               dma_buf             hid                 pinctrl             sleep_timeclear_warn_once     dma_pools           iio                 pm_genpd            split_huge_pagesclk                 dmaengine           interconnect        pwm                 suspend_statsdebug_enabled       energy_model        irq                 ras                 swiotlbdevfreq             extfrag             memblock            regmap              usb

debugfs 文件系统也可以在系统启动时自动挂载,这需要修改 /etc/fstab 文件,需要在这个文件中添加如下行:

debugfs  /sys/kernel/debug  debugfs  defaults  0  0

挂载了 debugfs 文件系统之后,可以在 /sys/kernel/debug/asoc/ 目录下看到注册的所有 DAI、component 和 sound card,如:

root@apollo:~# ls /sys/kernel/debug/asoc/components        dais              rt5651codec_card

在 sound card 对应的目录下,可以看到其更详细的组成,如:

root@apollo:~# ls /sys/kernel/debug/asoc/rt5651codec_card/725000.i2s     dapm           dapm_pop_time  rt5651.0-001a

这里的 sound card 主要由位于 0x725000 的 I2S 设备,也就是 CPU DAI,几个 DAPM 小部件,及 Audio Codec ALC5651,也就是 Codec DAI 组成。在 sound card 的 dapm 目录下,可以看到关于它的 DAPM 小部件的更详细的信息,如:

root@apollo:~# ls /sys/kernel/debug/asoc/rt5651codec_card/dapmHDMIIN       Headphones   Headset Mic  Int Mic      Lineout      bias_level

查看 sound card 的 dapm 目录下各个文件的内容,可以了解对应 DAPM 小部件的状态,如:

root@apollo:~# cat /sys/kernel/debug/asoc/rt5651codec_card/dapm/'Headset Mic'Headset Mic: Off  in 1 out 0

这些小部件可能需要用户专门通过工具来开关,也可能播放和录制应用软件会自动地开关。如 Headphones 小部件,它不需要用户专门通过工具来开关。在不播放音频文件时,它的状态为 Off,如:

root@apollo:~# cat /sys/kernel/debug/asoc/rt5651codec_card/dapm/HeadphonesHeadphones: Off  in 0 out 1 in  "static" "HPOR" in  "static" "HPOL"

当启动 tinyplay 播放 WAV 音频文件时,它的状态变为 On,如:

root@apollo:~# cat /sys/kernel/debug/asoc/rt5651codec_card/dapm/HeadphonesHeadphones: On  in 16 out 1 in  "static" "HPOR" in  "static" "HPOL"

在 sound card 的 rt5651.0-001a 目录下,可以看到关于它的 Audio Codec ALC5651 的更详细的信息,如:

root@apollo:~# ls /sys/kernel/debug/asoc/rt5651codec_card/rt5651.0-001a/dapm

ALC5651 的 Linux 内核驱动程序,主要提供了众多 DAPM 小部件,来对其内部各部分进行控制,如音量,静音,DAC,ADC,Mixer,耳机输出,有线输出等。

ALC5651 的 DAPM 小部件有如下这些:

root@apollo:~# ls /sys/kernel/debug/asoc/rt5651codec_card/rt5651.0-001a/dapm/ADC ASRC                            HPO R Playback                      LOUT R PlaybackADC L                               HPO R Playback Switch Autodisable   LOUT R Playback Switch AutodisableADC L Power                         HPOL                                LOUTLADC R                               HPOL MIX                            LOUTRADC R Power                         HPOR                                MIC1AIF1 Capture                        HPOR MIX                            MIC2AIF1 Playback                       HPOVOL L                            MIC3AIF1RX                              HPOVOL R                            OUT MIXLAIF1TX                              I2S1                                OUT MIXRAIF2 Capture                        I2S1 ASRC                           OUTVOL LAIF2 Playback                       I2S2                                OUTVOL RAIF2RX                              I2S2 ASRC                           PDM L MuxAIF2TX                              IF1 ADC1                            PDM R MuxAmp Power                           IF1 ADC2                            PDMLAudio DSP                           IF1 DAC                             PDMRBST1                                IF1 DAC1 L                          RECMIXLBST2                                IF1 DAC1 R                          RECMIXRBST3                                IF1 DAC2 L                          STO1 DAC ASRCDAC L1                              IF1 DAC2 R                          STO2 DAC ASRCDAC L1 Power                        IF2 ADC                             Stereo DAC MIXLDAC L2 Mux                          IF2 DAC                             Stereo DAC MIXRDAC L2 Volume                       IF2 DAC L                           Stereo1 ADC L1 MuxDAC MIXL                            IF2 DAC R                           Stereo1 ADC L2 MuxDAC MIXR                            IN1P                                Stereo1 ADC MIXLDAC R1                              IN2N                                Stereo1 ADC MIXRDAC R1 Power                        IN2P                                Stereo1 ADC R1 MuxDAC R2 Mux                          IN3P                                Stereo1 ADC R2 MuxDAC R2 Volume                       INL1                                Stereo1 FilterDD MIXL                             INL1 VOL                            Stereo2 ADC L1 MuxDD MIXR                             INL2                                Stereo2 ADC L2 MuxDMIC CLK                            INL2 VOL                            Stereo2 ADC MIXLDMIC L1                             INR1                                Stereo2 ADC MIXRDMIC R1                             INR1 VOL                            Stereo2 ADC R1 MuxHP Amp                              INR2                                Stereo2 ADC R2 MuxHP L Amp                            INR2 VOL                            Stereo2 FilterHP Post                             LDO                                 Stero1 DAC PowerHP R Amp                            LOUT L Playback                     Stero2 DAC PowerHPO L Playback                      LOUT L Playback Switch Autodisable  bias_levelHPO L Playback Switch Autodisable   LOUT MIX                            micbias1

同样,查看这些文件的内容,可以了解它们的状态。其中的许多,由播放和录制应用自动控制。如其中的耳机输出开关 HPOVOL L,在播放音频文件之前状态如下:

root@apollo:~# cat /sys/kernel/debug/asoc/rt5651codec_card/rt5651.0-001a/dapm/'HPOVOL L'HPOVOL L: Off  in 0 out 2 - R102(0x66) mask 0x800 out  "HPO MIX HPVOL Switch" "HPOL MIX" in  "Switch" "OUT MIXL"

在播放音频文件之后,其状态则为:

root@apollo:~# cat /sys/kernel/debug/asoc/rt5651codec_card/rt5651.0-001a/dapm/'HPOVOL L'HPOVOL L: On  in 2 out 2 - R102(0x66) mask 0x800 out  "HPO MIX HPVOL Switch" "HPOL MIX" in  "Switch" "OUT MIXL"

这里还会显示各个 DAPM 小部件的音频路由,即其输入和输出分别是其它哪个小部件。

在 debugfs 文件系统中看到的 DAPM 小部件,由驱动程序中类似下面的代码定义:

static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = {	/* ASRC */	SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5651_PLL_MODE_2,			      15, 0, NULL, 0),	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5651_PLL_MODE_2,			      14, 0, NULL, 0),	SND_SOC_DAPM_SUPPLY_S("STO1 DAC ASRC", 1, RT5651_PLL_MODE_2,			      13, 0, NULL, 0),	SND_SOC_DAPM_SUPPLY_S("STO2 DAC ASRC", 1, RT5651_PLL_MODE_2,			      12, 0, NULL, 0),	SND_SOC_DAPM_SUPPLY_S("ADC ASRC", 1, RT5651_PLL_MODE_2,			      11, 0, NULL, 0), . . . . . . 	/* Output Lines */	SND_SOC_DAPM_OUTPUT("HPOL"),	SND_SOC_DAPM_OUTPUT("HPOR"),	SND_SOC_DAPM_OUTPUT("LOUTL"),	SND_SOC_DAPM_OUTPUT("LOUTR"),	SND_SOC_DAPM_OUTPUT("PDML"),	SND_SOC_DAPM_OUTPUT("PDMR"),};

Linux 内核音频设备驱动程序可以向用户空间导出控制接口,用户可以通过这些控制接口控制音量大小,音量开关等,也可以通过这些控制接口控制两个 DAPM 小部件等。这些控制接口在 Linux 内核音频设备驱动程序中,由 struct snd_kcontrol_new 描述。ALC5651 Linux 内核设备驱动程序中定义的控制接口有如下这些:

static const struct snd_kcontrol_new rt5651_snd_controls[] = {	/* Headphone Output Volume */	SOC_DOUBLE_TLV("HP Playback Volume", RT5651_HP_VOL,		RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv),	/* OUTPUT Control */	SOC_DOUBLE_TLV("OUT Playback Volume", RT5651_LOUT_CTRL1,		RT5651_L_VOL_SFT, RT5651_R_VOL_SFT, 39, 1, out_vol_tlv), 	/* DAC Digital Volume */	SOC_DOUBLE("DAC2 Playback Switch", RT5651_DAC2_CTRL,		RT5651_M_DAC_L2_VOL_SFT, RT5651_M_DAC_R2_VOL_SFT, 1, 1),	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5651_DAC1_DIG_VOL,			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,			175, 0, dac_vol_tlv),	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5651_DAC2_DIG_VOL,			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,			175, 0, dac_vol_tlv),	/* IN1/IN2/IN3 Control */	SOC_SINGLE_TLV("IN1 Boost", RT5651_IN1_IN2,		RT5651_BST_SFT1, 8, 0, bst_tlv),	SOC_SINGLE_TLV("IN2 Boost", RT5651_IN1_IN2,		RT5651_BST_SFT2, 8, 0, bst_tlv),	SOC_SINGLE_TLV("IN3 Boost", RT5651_IN3,		RT5651_BST_SFT1, 8, 0, bst_tlv),	/* INL/INR Volume Control */	SOC_DOUBLE_TLV("IN Capture Volume", RT5651_INL1_INR1_VOL,			RT5651_INL_VOL_SFT, RT5651_INR_VOL_SFT,			31, 1, in_vol_tlv),	/* ADC Digital Volume Control */	SOC_DOUBLE("ADC Capture Switch", RT5651_ADC_DIG_VOL,		RT5651_L_MUTE_SFT, RT5651_R_MUTE_SFT, 1, 1),	SOC_DOUBLE_TLV("ADC Capture Volume", RT5651_ADC_DIG_VOL,			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,			127, 0, adc_vol_tlv),	SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5651_ADC_DATA,			RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,			127, 0, adc_vol_tlv),	/* ADC Boost Volume Control */	SOC_DOUBLE_TLV("ADC Boost Gain", RT5651_ADC_BST_VOL,			RT5651_ADC_L_BST_SFT, RT5651_ADC_R_BST_SFT,			3, 0, adc_bst_tlv), 	/* ASRC */	SOC_SINGLE("IF1 ASRC Switch", RT5651_PLL_MODE_1,		RT5651_STO1_T_SFT, 1, 0),	SOC_SINGLE("IF2 ASRC Switch", RT5651_PLL_MODE_1,		RT5651_STO2_T_SFT, 1, 0),	SOC_SINGLE("DMIC ASRC Switch", RT5651_PLL_MODE_1,		RT5651_DMIC_1_M_SFT, 1, 0), 	SOC_ENUM("ADC IF2 Data Switch", rt5651_if2_adc_enum),	SOC_ENUM("DAC IF2 Data Switch", rt5651_if2_dac_enum),}; . . . . . ./* Digital Mixer */static const struct snd_kcontrol_new rt5651_sto1_adc_l_mix[] = {	SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER,			RT5651_M_STO1_ADC_L1_SFT, 1, 1),	SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER,			RT5651_M_STO1_ADC_L2_SFT, 1, 1),}; static const struct snd_kcontrol_new rt5651_sto1_adc_r_mix[] = {	SOC_DAPM_SINGLE("ADC1 Switch", RT5651_STO1_ADC_MIXER,			RT5651_M_STO1_ADC_R1_SFT, 1, 1),	SOC_DAPM_SINGLE("ADC2 Switch", RT5651_STO1_ADC_MIXER,			RT5651_M_STO1_ADC_R2_SFT, 1, 1),}; . . . . . .

DAPM 小部件可以绑定控制操作或事件处理程序,这种控制操作在 Linux 内核驱动程序中也用控制接口来描述。上面的 DAPM 小部件,引用的部分 struct snd_kcontrol_new 定义如下:

static const struct snd_kcontrol_new rt5651_dd_dac_l_mix[] = {	SOC_DAPM_SINGLE("DAC L1 Switch", RT5651_DD_MIXER,			RT5651_M_STO_DD_L1_SFT, 1, 1),	SOC_DAPM_SINGLE("DAC L2 Switch", RT5651_DD_MIXER,			RT5651_M_STO_DD_L2_SFT, 1, 1),	SOC_DAPM_SINGLE("DAC R2 Switch", RT5651_DD_MIXER,			RT5651_M_STO_DD_R2_L_SFT, 1, 1),};

音频路由描述不同的 DAPM 小部件之间的连接。上面看到的音频路由,在 Linux 内核驱动程序中,由 struct snd_soc_dapm_route 描述。一些控制接口用于控制两个 DAPM 小部件之间的连接,对于需要这种控制接口的音频路由,在音频路由表中,会引用控制接口。ALC5651 Linux 内核驱动程序中定义的音频路由主要有如下这些:

static const struct snd_soc_dapm_route rt5651_dapm_routes[] = {	{"Stero1 DAC Power", NULL, "STO1 DAC ASRC"},	{"Stero2 DAC Power", NULL, "STO2 DAC ASRC"},	{"I2S1", NULL, "I2S1 ASRC"},	{"I2S2", NULL, "I2S2 ASRC"}, . . . . . .	{"RECMIXL", "INL1 Switch", "INL1 VOL"},	{"RECMIXL", "BST3 Switch", "BST3"},	{"RECMIXL", "BST2 Switch", "BST2"},	{"RECMIXL", "BST1 Switch", "BST1"}, 	{"RECMIXR", "INR1 Switch", "INR1 VOL"},	{"RECMIXR", "BST3 Switch", "BST3"},	{"RECMIXR", "BST2 Switch", "BST2"},	{"RECMIXR", "BST1 Switch", "BST1"}, . . . . . .	{"PDML", NULL, "PDM L Mux"},	{"PDMR", NULL, "PDM R Mux"},};

上面的这些 DAPM 小部件,和音频路由,作为 Codec DAI 驱动程序的一部分在注册 Codec DAI 驱动程序时注册进 ALSA 框架,如:

static const struct snd_soc_component_driver soc_component_dev_rt5651 = {	.probe			= rt5651_probe,	.suspend		= rt5651_suspend,	.resume			= rt5651_resume,	.set_bias_level		= rt5651_set_bias_level,	.set_jack		= rt5651_set_jack,	.controls		= rt5651_snd_controls,	.num_controls		= ARRAY_SIZE(rt5651_snd_controls),	.dapm_widgets		= rt5651_dapm_widgets,	.num_dapm_widgets	= ARRAY_SIZE(rt5651_dapm_widgets),	.dapm_routes		= rt5651_dapm_routes,	.num_dapm_routes	= ARRAY_SIZE(rt5651_dapm_routes),	.use_pmdown_time	= 1,	.endianness		= 1,	.non_legacy_dai_naming	= 1,};

通过 debugfs 文件系统了解音频子系统的状态比较方便,但控制各个 DAPM 小部件的开关则需要其它工具,如 tinymix 等。

ALSA 项目的用户空间程序包括可以帮助用户空间应用程序访问 ALSA 的 alsa-lib 库,及众多实用的工具,如 alsa-utils 中的 alsactlamixeraplayamidi等,这些工具可用于配置和测试 ALSA 的各项功能。如 aplay 调用 alsa-lib 库来播放音频文件,arecord 调用 alsa-lib 库来录制音频文件,amixer 可用于配置各个控制接口的状态等。更多详细信息可以参考 alsa-project 的 github

tinyalsa 可以看作是 ALSA 项目的用户空间程序的简化版本,它包含一个简化版的库,及一些实用的小工具。这些工具包括 tinyplaytinycaptinymix 等,这几个工具的作用大体与 aplayarecordamixer 等价。相对于 ALSA 项目的用户空间程序,tinyalsa 的代码更简洁,因而移植和调试分析也就更简单。本文中所做的测试和调试用 tinyalsa 的工具。

tinymix

tinymix 可用来获取或设置各个控制接口的状态,这个工具用法如下:

root@apollo:~# tinymix --helpusage: tinymix [options] <command>options:        -h, --help               : prints this help message and exits        -v, --version            : prints this version of tinymix and exits        -D, --card NUMBER        : specifies the card number of the mixer commands:        get NAME|ID              : prints the values of a control        set NAME|ID VALUE(S) ... : sets the value of a control                VALUE(S): integers, percents, and relative values                        Integers: 0, 100, -100 ...                        Percents: 0%, 100% ...                        Relative values: 1+, 1-, 1%+, 2%+ ...        controls                 : lists controls of the mixer        contents                 : lists controls of the mixer and their contents

tinymix controls 命令可以列出系统中所有的控制接口,如:

root@apollo:~# tinymix controlsNumber of controls: 91ctl     type    num     name0       INT     2       HP Playback Volume1       INT     2       OUT Playback Volume2       BOOL    2       DAC2 Playback Switch3       INT     2       DAC1 Playback Volume4       INT     2       Mono DAC Playback Volume5       INT     1       IN1 Boost6       INT     1       IN2 Boost7       INT     1       IN3 Boost8       INT     2       IN Capture Volume9       BOOL    2       ADC Capture Switch10      INT     2       ADC Capture Volume11      INT     2       Mono ADC Capture Volume12      INT     2       ADC Boost Gain13      BOOL    1       IF1 ASRC Switch14      BOOL    1       IF2 ASRC Switch15      BOOL    1       DMIC ASRC Switch16      ENUM    1       ADC IF2 Data Switch17      ENUM    1       DAC IF2 Data Switch18      BOOL    1       Headphones Switch19      BOOL    1       Lineout Switch20      BOOL    1       Headset Mic Switch21      BOOL    1       Int Mic Switch22      BOOL    1       RECMIXL INL1 Switch23      BOOL    1       RECMIXL BST3 Switch24      BOOL    1       RECMIXL BST2 Switch25      BOOL    1       RECMIXL BST1 Switch26      BOOL    1       RECMIXR INR1 Switch27      BOOL    1       RECMIXR BST3 Switch28      BOOL    1       RECMIXR BST2 Switch29      BOOL    1       RECMIXR BST1 Switch30      ENUM    1       Stereo1 ADC L2 Mux31      ENUM    1       Stereo1 ADC R2 Mux32      ENUM    1       Stereo1 ADC L1 Mux33      ENUM    1       Stereo1 ADC R1 Mux34      ENUM    1       Stereo2 ADC L2 Mux35      ENUM    1       Stereo2 ADC L1 Mux36      ENUM    1       Stereo2 ADC R1 Mux37      ENUM    1       Stereo2 ADC R2 Mux38      BOOL    1       Stereo1 ADC MIXL ADC1 Switch39      BOOL    1       Stereo1 ADC MIXL ADC2 Switch40      BOOL    1       Stereo1 ADC MIXR ADC1 Switch41      BOOL    1       Stereo1 ADC MIXR ADC2 Switch42      BOOL    1       Stereo2 ADC MIXL ADC1 Switch43      BOOL    1       Stereo2 ADC MIXL ADC2 Switch44      BOOL    1       Stereo2 ADC MIXR ADC1 Switch45      BOOL    1       Stereo2 ADC MIXR ADC2 Switch46      ENUM    1       IF2 ADC47      ENUM    1       PDM L Mux48      ENUM    1       PDM R Mux49      BOOL    1       DAC MIXL Stereo ADC Switch50      BOOL    1       DAC MIXL INF1 Switch51      BOOL    1       DAC MIXR Stereo ADC Switch52      BOOL    1       DAC MIXR INF1 Switch53      ENUM    1       DAC L2 Mux54      ENUM    1       DAC R2 Mux55      BOOL    1       Stereo DAC MIXL DAC L1 Switch56      BOOL    1       Stereo DAC MIXL DAC L2 Switch57      BOOL    1       Stereo DAC MIXL DAC R1 Switch58      BOOL    1       Stereo DAC MIXR DAC R1 Switch59      BOOL    1       Stereo DAC MIXR DAC R2 Switch60      BOOL    1       Stereo DAC MIXR DAC L1 Switch61      BOOL    1       DD MIXL DAC L1 Switch62      BOOL    1       DD MIXL DAC L2 Switch63      BOOL    1       DD MIXL DAC R2 Switch64      BOOL    1       DD MIXR DAC R1 Switch65      BOOL    1       DD MIXR DAC R2 Switch66      BOOL    1       DD MIXR DAC L2 Switch67      BOOL    1       OUT MIXL BST1 Switch68      BOOL    1       OUT MIXL BST2 Switch69      BOOL    1       OUT MIXL INL1 Switch70      BOOL    1       OUT MIXL REC MIXL Switch71      BOOL    1       OUT MIXL DAC L1 Switch72      BOOL    1       OUT MIXR BST2 Switch73      BOOL    1       OUT MIXR BST1 Switch74      BOOL    1       OUT MIXR INR1 Switch75      BOOL    1       OUT MIXR REC MIXR Switch76      BOOL    1       OUT MIXR DAC R1 Switch77      BOOL    1       OUTVOL L Switch78      BOOL    1       OUTVOL R Switch79      BOOL    1       HPOVOL L Switch80      BOOL    1       HPOVOL R Switch81      BOOL    1       HPO MIX DAC1 Switch82      BOOL    1       HPO MIX HPVOL Switch83      BOOL    1       LOUT MIX DAC L1 Switch84      BOOL    1       LOUT MIX DAC R1 Switch85      BOOL    1       LOUT MIX OUTVOL L Switch86      BOOL    1       LOUT MIX OUTVOL R Switch87      BOOL    1       HPO L Playback Switch88      BOOL    1       HPO R Playback Switch89      BOOL    1       LOUT L Playback Switch90      BOOL    1       LOUT R Playback Switch

tinymix controls 命令每行列出一个控制接口,其中包含控制 ID,可以用于其它命令,值的类型,及控制接口的名称等。tinymix contents 命令在列出 tinymix controls 命令列出的内容之外,还会列出各个控制接口的状态,如:

root@apollo:~# tinymix contentsNumber of controls: 91ctl     type    num     name                                    value0       INT     2       HP Playback Volume                      31, 31 (range 0->39)1       INT     2       OUT Playback Volume                     31, 31 (range 0->39)2       BOOL    2       DAC2 Playback Switch                    On, On3       INT     2       DAC1 Playback Volume                    175, 175 (range 0->175)4       INT     2       Mono DAC Playback Volume                175, 175 (range 0->175)5       INT     1       IN1 Boost                               0 (range 0->8)6       INT     1       IN2 Boost                               0 (range 0->8)7       INT     1       IN3 Boost                               0 (range 0->8)8       INT     2       IN Capture Volume                       23, 23 (range 0->31)9       BOOL    2       ADC Capture Switch                      On, On10      INT     2       ADC Capture Volume                      47, 47 (range 0->127)11      INT     2       Mono ADC Capture Volume                 47, 47 (range 0->127)12      INT     2       ADC Boost Gain                          0, 0 (range 0->3)13      BOOL    1       IF1 ASRC Switch                         Off14      BOOL    1       IF2 ASRC Switch                         Off15      BOOL    1       DMIC ASRC Switch                        Off16      ENUM    1       ADC IF2 Data Switch                     > Normal, Swap, left copy to right, right copy to left,17      ENUM    1       DAC IF2 Data Switch                     > Normal, Swap, left copy to right, right copy to left,18      BOOL    1       Headphones Switch                       On19      BOOL    1       Lineout Switch                          On20      BOOL    1       Headset Mic Switch                      On21      BOOL    1       Int Mic Switch                          On22      BOOL    1       RECMIXL INL1 Switch                     Off23      BOOL    1       RECMIXL BST3 Switch                     Off24      BOOL    1       RECMIXL BST2 Switch                     Off25      BOOL    1       RECMIXL BST1 Switch                     Off26      BOOL    1       RECMIXR INR1 Switch                     Off27      BOOL    1       RECMIXR BST3 Switch                     Off28      BOOL    1       RECMIXR BST2 Switch                     Off29      BOOL    1       RECMIXR BST1 Switch                     Off30      ENUM    1       Stereo1 ADC L2 Mux                      DMIC, > DD MIX,31      ENUM    1       Stereo1 ADC R2 Mux                      DMIC, > DD MIX,32      ENUM    1       Stereo1 ADC L1 Mux                      DD MIX, > ADC,33      ENUM    1       Stereo1 ADC R1 Mux                      DD MIX, > ADC,34      ENUM    1       Stereo2 ADC L2 Mux                      DMIC L, > DD MIXL,35      ENUM    1       Stereo2 ADC L1 Mux                      DD MIXL, > ADCL,36      ENUM    1       Stereo2 ADC R1 Mux                      > DD MIXR, ADCR,37      ENUM    1       Stereo2 ADC R2 Mux                      > DMIC R, DD MIXR,38      BOOL    1       Stereo1 ADC MIXL ADC1 Switch            Off39      BOOL    1       Stereo1 ADC MIXL ADC2 Switch            Off40      BOOL    1       Stereo1 ADC MIXR ADC1 Switch            Off41      BOOL    1       Stereo1 ADC MIXR ADC2 Switch            Off42      BOOL    1       Stereo2 ADC MIXL ADC1 Switch            Off43      BOOL    1       Stereo2 ADC MIXL ADC2 Switch            Off44      BOOL    1       Stereo2 ADC MIXR ADC1 Switch            Off45      BOOL    1       Stereo2 ADC MIXR ADC2 Switch            Off46      ENUM    1       IF2 ADC                                 > IF1 ADC1, IF1 ADC2,47      ENUM    1       PDM L Mux                               > DD MIX, Stereo DAC MIX,48      ENUM    1       PDM R Mux                               > DD MIX, Stereo DAC MIX,49      BOOL    1       DAC MIXL Stereo ADC Switch              Off50      BOOL    1       DAC MIXL INF1 Switch                    On51      BOOL    1       DAC MIXR Stereo ADC Switch              Off52      BOOL    1       DAC MIXR INF1 Switch                    On53      ENUM    1       DAC L2 Mux                              IF1, > IF2,54      ENUM    1       DAC R2 Mux                              IF1, > IF2,55      BOOL    1       Stereo DAC MIXL DAC L1 Switch           On56      BOOL    1       Stereo DAC MIXL DAC L2 Switch           Off57      BOOL    1       Stereo DAC MIXL DAC R1 Switch           Off58      BOOL    1       Stereo DAC MIXR DAC R1 Switch           On59      BOOL    1       Stereo DAC MIXR DAC R2 Switch           Off60      BOOL    1       Stereo DAC MIXR DAC L1 Switch           Off61      BOOL    1       DD MIXL DAC L1 Switch                   Off62      BOOL    1       DD MIXL DAC L2 Switch                   Off63      BOOL    1       DD MIXL DAC R2 Switch                   Off64      BOOL    1       DD MIXR DAC R1 Switch                   Off65      BOOL    1       DD MIXR DAC R2 Switch                   Off66      BOOL    1       DD MIXR DAC L2 Switch                   Off67      BOOL    1       OUT MIXL BST1 Switch                    Off68      BOOL    1       OUT MIXL BST2 Switch                    Off69      BOOL    1       OUT MIXL INL1 Switch                    Off70      BOOL    1       OUT MIXL REC MIXL Switch                Off71      BOOL    1       OUT MIXL DAC L1 Switch                  On72      BOOL    1       OUT MIXR BST2 Switch                    Off73      BOOL    1       OUT MIXR BST1 Switch                    Off74      BOOL    1       OUT MIXR INR1 Switch                    Off75      BOOL    1       OUT MIXR REC MIXR Switch                Off76      BOOL    1       OUT MIXR DAC R1 Switch                  On77      BOOL    1       OUTVOL L Switch                         Off78      BOOL    1       OUTVOL R Switch                         Off79      BOOL    1       HPOVOL L Switch                         On80      BOOL    1       HPOVOL R Switch                         On81      BOOL    1       HPO MIX DAC1 Switch                     On82      BOOL    1       HPO MIX HPVOL Switch                    On83      BOOL    1       LOUT MIX DAC L1 Switch                  Off84      BOOL    1       LOUT MIX DAC R1 Switch                  Off85      BOOL    1       LOUT MIX OUTVOL L Switch                Off86      BOOL    1       LOUT MIX OUTVOL R Switch                Off87      BOOL    1       HPO L Playback Switch                   On88      BOOL    1       HPO R Playback Switch                   On89      BOOL    1       LOUT L Playback Switch                  Off90      BOOL    1       LOUT R Playback Switch                  Off

如前面看到的,tinymix controlstinymix contents 命令列出的所有控制接口,在 Linux 内核设备驱动程序中,由 struct snd_kcontrol_new 结构体描述。

对于相同的 Audio Codec,由于 sound card 注册的控制接口不同,而使其各个控制接口,在不同设备中的控制 ID 可能不同,但名称都是相同的。

要使播放或录制正常运转,通常需要开启 sound card 及 Audio Codec 中相关各个控制接口的开关。如要播放音频,对于 ALC5651,大概有如下这样的音频路由:

image

需要开启如下这些控制接口:

18      BOOL    1       Headphones Switch                       On50      BOOL    1       DAC MIXL INF1 Switch                    On52      BOOL    1       DAC MIXR INF1 Switch                    On55      BOOL    1       Stereo DAC MIXL DAC L1 Switch           On58      BOOL    1       Stereo DAC MIXR DAC R1 Switch           On71      BOOL    1       OUT MIXL DAC L1 Switch                  On76      BOOL    1       OUT MIXR DAC R1 Switch                  On79      BOOL    1       HPOVOL L Switch                         On80      BOOL    1       HPOVOL R Switch                         On81      BOOL    1       HPO MIX DAC1 Switch                     On82      BOOL    1       HPO MIX HPVOL Switch                    On87      BOOL    1       HPO L Playback Switch                   On88      BOOL    1       HPO R Playback Switch                   On

tinymix get 命令可以用于获取具体某个控制接口的状态,其参数为上面看到的控制 ID,如:

root@apollo:~# tinymix get 18On

tinymix set 命令可以用于设置具体某个控制接口的状态,其参数为上面看到的控制 ID 和要设置的值,如:

root@apollo:~# tinymix get 18Onroot@apollo:~# tinymix set 18 0root@apollo:~# tinymix get 18Offroot@apollo:~# tinymix set 18 1root@apollo:~# tinymix get 18On

对于 ALC5651,如要播放音频,需要像下面这样打开相关控制接口的开关:

root@apollo:~# tinymix set 18 1root@apollo:~# tinymix set 50 1root@apollo:~# tinymix set 52 1root@apollo:~# tinymix set 55 1root@apollo:~# tinymix set 58 1root@apollo:~# tinymix set 71 1root@apollo:~# tinymix set 76 1root@apollo:~# tinymix set 79 1root@apollo:~# tinymix set 80 1root@apollo:~# tinymix set 81 1root@apollo:~# tinymix set 82 1root@apollo:~# tinymix set 87 1root@apollo:~# tinymix set 88 1

在播放音频数据的过程中,可以看到 Audio Codec 的 DAPM 小部件 AIF1 Playback 的状态由 inactive 变为 active, sound card 的 DAPM 小部件 Headphones 的状态由 Off 变为 On,如:

root@apollo:~# cat /sys/kernel/debug/asoc/rt5651codec_card/rt5651.0-001a/dapm/'AIF1 Playback'AIF1 Playback: Off  in 0 out 18 stream AIF1 Playback inactive out  "static" "AIF1RX" in  "static" "Playback"root@apollo:~# cat /sys/kernel/debug/asoc/rt5651codec_card/rt5651.0-001a/dapm/'AIF1 Playback'AIF1 Playback: On  in 1 out 18 stream AIF1 Playback active out  "static" "AIF1RX" in  "static" "Playback"root@apollo:~# cat /sys/kernel/debug/asoc/rt5651codec_card/dapm/HeadphonesHeadphones: On  in 16 out 1 in  "static" "HPOR" in  "static" "HPOL"

如果要用 ALC5651 录音,有如下的音频路由:

image

则需要打开如下这些控制接口的开关:

24      BOOL    1       RECMIXL BST2 Switch                     Off28      BOOL    1       RECMIXR BST2 Switch                     Off32      ENUM    1       Stereo1 ADC L1 Mux                      DD MIX, > ADC,33      ENUM    1       Stereo1 ADC R1 Mux                      DD MIX, > ADC,38      BOOL    1       Stereo1 ADC MIXL ADC1 Switch            Off40      BOOL    1       Stereo1 ADC MIXR ADC1 Switch            Off

这需要执行如下这些命令:

root@apollo:~# tinymix set 24 1root@apollo:~# tinymix set 28 1root@apollo:~# tinymix set 38 1root@apollo:~# tinymix set 40 1

i2cget/i2cset

调试 Linux 内核音频子系统时,如果怀疑音频设备的寄存器设置不正确,则可以根据不同设备的特性,采取不同的方法来确认。在 SoC 上,许多设备的寄存器被映射到物理内存地址空间,访问设备的寄存器就像访问物理内存一样,如 I2S 总线。还有一些设备的寄存器,需要通过 I2C 等其它总线访问,如 Audio Codec ALC5651。在 Linux 内核驱动程序的实现中,这些设备的寄存器都可以用 regmap 机制来访问。

debugfs 文件系统的 /sys/kernel/debug/regmap 目录中,可以看到使用了 regmap 机制的设备,如:

root@apollo:~# ls /sys/kernel/debug/regmap/0-001a/                725000.i2s/            dummy-crg_vid@2c0000/

在上面各个具体设备的目录中,可以看到关于该设备的 regmap 的更详细信息,如 Audio Codec ALC5651 的 0-001a 目录包含如下内容:

root@apollo:~# ls /sys/kernel/debug/regmap/0-001a/PR            cache_bypass  cache_only    range         registersaccess        cache_dirty   name          rbtree

查看目录中 registers 文件的内容,可以看到设备的所有寄存器当前的值,如:

root@apollo:~# cat /sys/kernel/debug/regmap/0-001a/registers000: 0000002: 8888003: c8c8005: 000000d: 000000e: 000000f: 0808010: 0808019: afaf01a: afaf . . . . . .0fc: 00000fd: 00020fe: 10ec0ff: 6281100: aaaa101: 4000102: a280 . . . . . .1ad: 01f41ae: 1c101af: 01f41b0: 20001b1: 00001b2: 20001b3: 08001b4: 0800

播放音频时查看 ALC5651 电源控制寄存器 1 的值:

root@apollo:~# cat /sys/kernel/debug/regmap/0-001a/registers  | grep 061061: 0000

可以用同样的方法查看 I2S 这种把设备寄存器映射到物理内存地址空间的设备的寄存器,如:

root@apollo:~# cat /sys/kernel/debug/regmap/725000.i2s/registers000: 00000000004: 00000000008: 00000000 . . . . . .

对于把设备寄存器映射到物理内存地址空间的设备,devmem 族是更好用的分析调试工具。devmemdevmset 分别可以查看和设置特定物理内存地址处的值,因而也可以读取和设置设备寄存器的值,如:

root@apollo:~# devmem 0x9f41000000x00000000root@apollo:~# devmset 0x9f4100000 0x1234 1root@apollo:~# devmem 0x9f41000000x00001234

对于需要通过 I2C 来访问内部寄存器的设备,i2cget/i2cset 族是更好用的工具。i2cdetect 命令可以检测 I2C 总线的状态,这个命令的用法如下:

root@apollo:~# i2cdetect --helpBusyBox v1.35.0 () multi-call binary. Usage: i2cdetect -l | -F I2CBUS | [-ya] [-q|-r] I2CBUS [FIRST LAST]

i2cdetect -l 命令列出所有的 I2C 设备:

root@apollo:~# i2cdetect -li2c-0   i2c            I2C adapter

i2cdetect -F [I2CBUS] 命令列出特定 I2C 总线支持的特性,如:

root@apollo:~# i2cdetect -F 0Functionalities implemented by bus #0I2C                              yesSMBus quick command              yesSMBus send byte                  yesSMBus receive byte               yesSMBus write byte                 yesSMBus read byte                  yesSMBus write word                 yesSMBus read word                  yesSMBus process call               noSMBus block write                yesSMBus block read                 yesSMBus block process call         noSMBus PEC                        noI2C block write                  yesI2C block read                   yes

i2cdetect [I2CBUS] 命令检测特定 I2C 总线上,哪个从地址上有设备。如下面的命令列出了 I2C 0 总线的情况:

root@apollo:~# i2cdetect -y 0     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f00:          -- -- -- -- -- -- -- -- -- -- -- -- --10: -- -- -- -- -- -- -- -- -- -- UU -- -- -- -- --20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --70: -- -- -- -- -- -- -- --

在上面这个 I2C总线上,只有从地址 0x1A 上有设备,也就是 ALC5651。

i2cdump 命令可以显示特定 I2C 从设备所有寄存器的值,如下面的命令列出了 ALC5651 的所有寄存器的值:

root@apollo:~# i2cdump -fy 0 0x1a w     0,8  1,9  2,a  3,b  4,c  5,d  6,e  7,f00: 0000 0000 8888 c8c8 0000 0000 0000 000008: 0000 0000 0000 0000 0000 0000 0000 080810: 0808 0000 0000 0000 0000 0000 0000 000018: 0000 afaf afaf 000c 2f2f 2f2f 0000 000020: 0000 0000 0000 0000 0000 0000 0000 001828: 1010 8080 1212 0000 0000 0000 0000 000030: 0050 0000 0000 0000 0000 0000 0000 000038: 0000 0000 0000 0000 4100 0000 4100 000040: 0000 0000 0000 0000 0000 0000 0000 000048: 0000 0000 0000 0000 0000 0000 0000 780250: 0000 0000 7802 00f0 0000 0000 0000 000058: 0000 0000 0000 0000 0000 0000 0000 000060: 0000 0000 0000 0200 0002 0000 0000 000068: 0000 0000 b400 0000 0008 0000 0000 000070: 0080 0080 0000 0411 000c 8014 0000 000c78: 0040 2301 0000 0000 0000 0000 0000 000080: 0040 0102 0008 0008 0000 0800 0000 000088: 0000 0000 0000 0006 0000 0000 0500 401190: 3707 000e 0000 0020 0002 0000 0000 000098: 0000 0000 0000 0000 0000 0000 0000 0000a0: 0000 0000 0000 0000 0000 0000 0000 0000a8: 0000 0000 0000 0000 0000 0000 0000 0000b0: 8020 0000 0000 0000 0622 001f 0000 0000b8: 0000 0000 0000 0000 0000 0000 0000 0000c0: 0000 0000 0000 0000 0000 0000 0000 0000c8: 0000 0000 0000 0000 0000 0000 0000 1300d0: 8006 171c 0000 20b3 0000 0000 0004 0000d8: 0000 0908 0000 0000 0000 0000 0000 0000e0: 0000 0000 0000 0000 0000 0000 0000 0000e8: 0000 0000 0000 0000 0000 0000 0000 0000f0: 0000 0000 0000 0000 0000 0000 0000 0000f8: 0000 0000 1000 0000 0000 0200 ec10 8162

i2cgeti2cset分别用于读取和写入特定 I2C 从设备的寄存器。如:

root@apollo:~# i2cget -fy 0 0x1a 0xff w0x8162

i2c* 默认不能访问已经被某个驱动程序占用的 I2C 从设备,上面看到的 -f 标记表示强制访问,-y 标记表示以 Y 来回答工具给出的提示。这些工具是按大尾端来读取和设置值的。如上面看到的,0xFF 地址处的 0x8162,其实际值为 0x6281。向 I2C 从设备的寄存器写入特定值的方法如下:

root@apollo:~# i2cset -fy 0 0x1a 0xff 0x8162 w

Done.

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYmu4bPY' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片