In the last section, we explained three concepts of DAPM: widget, route and path, and guessed the process of using DAPM to them. In the following sections, we explained the process of calling DAPM according to the code.
a, dapm's kcontrol registration process
b, tinymix, tinyplay, tinycap all call the dapm_power_widgets function
c, the core of dapm, comlete path
In this section, we first explain the kcontrol registration process of dapm.
Section review
Let's review the previous knowledge, before introducing DAPM:
Insert a picture description here
To achieve the recording function, we need to set the registers corresponding to each of the above kcontrol. As shown above, there are six registers. If each register is exposed to the application, let the application set it up. After introducing DAPM, we only need to open the red arrow in the picture, then the whole line will be opened.
For ordinary kcontrol, there is first a snd_kcontrol_new structure, which contains info, put, get, private data (generally including registers, registers bits, etc.). It will be used to construct a snd_kcontrol, and then added to the sound card through snd_ctl_add. The following is the process after the analysis of the previous section:
static const struct snd_kcontrol_new rt5651_snd_controls[] = {} static struct snd_soc_codec_driver soc_codec_dev_rt5651 = { .controls = rt5651_snd_controls, .num_controls = ARRAY_SIZE(rt5651_snd_controls), } snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651,rt5651_dai, ARRAY_SIZE(rt5651_dai)); ret = snd_soc_register_card(card); /*Within this function, a lot of work will be done, such as binding dai, and so on.*/ ret = snd_soc_instantiate_card(card); snd_soc_add_card_controls(card, card->controls, card->num_controls); snd_soc_add_controls(card, soc_card->dev, controls, num_controls,NULL, soc_card); const struct snd_kcontrol_new *control = &controls[i]; snd_ctl_add(card, snd_soc_cnew(control, data,control->name, prefix)); /*Add to & Card - > controls*/ list_add_tail(&kcontrol->list, &card->controls);
As you can see, the so-called addition to the sound card is actually added to the card - > controls list, which is the traditional kcontrol registration process. So how does the kcontrol of DAPM register?
kcontrol of DAPM
As we said in the last section,
A widget includes mixer s and three pairs of kcontrol s (above), if our ALC 5651:
There are four kcontrol s. Let's look at the source code below.
static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = { { ...... ...... } static struct snd_soc_codec_driver soc_codec_dev_rt5651 = { .dapm_widgets = rt5651_dapm_widgets, } ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5651,rt5651_dai, ARRAY_SIZE(rt5651_dai)); /*snd_soc_register_codec After registration, machine will eventually cause the function to be called*/ ret = snd_soc_instantiate_card(card); if (card->dapm_widgets)//Through platform snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,card->num_dapm_widgets); if (card->of_dapm_widgets)//Through the Device Tree snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,card->num_of_dapm_widgets); snd_soc_dapm_new_control_unlocked(dapm, widget); /*Add to Sound Card - > Widgets Link List*/ list_add_tail(&w->list, &dapm->card->widgets);
You can see that it will eventually be added to the card - > Widgets list.
There must be a question that ordinary kcontrols and DAPM kcontrols give the same access interface to applications, so it is clear that the kcontrol of DAPM (kcontrol in widgets) will eventually be placed in the card->controls (ordinary kcontrol) list.
However, the above analysis does not deal with the kcontrol in widgets and puts it into the card - > controls list, so there must be other operations:
static int snd_soc_instantiate_card(struct snd_soc_card *card) static int soc_probe_link_components(struct snd_soc_card *card, int num,int order) static int soc_probe_component(struct snd_soc_card *card,struct snd_soc_component *component) int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, snd_soc_dapm_new_control_unlocked(dapm, &template); w->power_check = dapm_generic_check_power; snd_soc_dapm_new_widgets(card);
1. The soc_probe_link_components function sets its power_check = dapm_generic_check_power for each widget, which is used to determine whether power is needed (power condition: 1. on complete path). 2. APP is using sound card.
2. For each mixer:
You can see that through three switches, each switch will enter the mixer as long as it is connected. Let's imagine when we will use the kcontrol corresponding to the three switches. If his kcontrol_new is on a path, we use kcontrol_new to construct the son_kcontrol and put it into the card - > controls list.
Following the previous analysis:
snd_soc_dapm_new_widgets(card); case snd_soc_dapm_mixer://If it is a mixer dapm_new_mixer(w); /*See if the kcontrol in the widget exists in a path*/ snd_soc_dapm_widget_for_each_source_path(w, path) { /* mixer/mux paths name must match control name */ if (path->name != (char *)w->kcontrol_news[i].name) continue if (!w->kcontrols[i]) { ret = dapm_create_or_share_kcontrol(w, i); ret = snd_ctl_add(card, kcontrol); list_add_tail(&kcontrol->list, &card->controls);
As you can see, it is finally added to the card - > controls list of the sound card. Note: Their names are mixer names plus kcontrol names, which can be viewed on the development board using the tinymix command.
We know that an audio encoder has multiple inputs, which is multi-choice for mixer (multi-choice one way), but for mux, which is different, it is single-choice (multi-choice one way). Open the rt5651.c file:
static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = { ...... SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,&rt5651_sto1_adc_l2_mux), SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0&rt5651_sto1_adc_r2_mux), SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,&rt5651_sto1_adc_l1_mux), ...... } static const struct snd_soc_dapm_route rt5651_dapm_routes[] = { ...... {"Stereo1 ADC L1 Mux", "ADC", "ADC L"}, {"Stereo1 ADC L1 Mux", "DD MIX", "DD MIXL"}, ...... }
Here is a simple image:
In this case, we only need several bits of a register to represent it. It can be seen that the selection is opposite to the previous mixer, which is a pair of pairs and a mixer of many pairs of 1. In this case, only one kcontrol is needed, and mux connections are determined by values, such as the value of registers. The mixer value passes through a string (name). A mux widget contains a mux itself and a snd_kcontrol_new. Snd_kcontrol_new has multiple values, such as lift. right et al.
As shown above, two green lines represent two paths, path1 and path1, so the kcontrol of them is the same kcontrol.
Let's guess what to do with mux widgets:
1.snd_kcontrol_new will be converted to snd_kcontrol and put into the list. Finally, it will be put into the card - > control list of the sound card.
2. For path1, they point to the same kcontrol, and their sink (destination) is the same.
As follows, let's look at any of them:
static const struct snd_kcontrol_new rt5651_inl1_mux = SOC_DAPM_ENUM("INL1 source", rt5651_inl_enum); SND_SOC_DAPM_MUX("INL1 Mux", SND_SOC_NOPM, 0, 0, &rt5651_inl1_mux),
Back to the previous one
snd_soc_dapm_new_widgets(card); case snd_soc_dapm_mux: dapm_new_mux(w); ret = dapm_create_or_share_kcontrol(w, 0); ret = snd_ctl_add(card, kcontrol); list_add_tail(&kcontrol->list, &card->controls);
It can be seen that the analysis is similar to the previous one. The following is a summary: the kcontrol registration process of DAPM.
The kcontrol registration process of DAPM For ordin a ry snd_kcontrol: Snd_soc_add_controls: snd_kcontrol_new constructs snd_kcontrol and puts it in card-> controls list b. For snd_kcontrol of DAPM, there are two steps: b.1 snd_soc_dapm_new_controls// Put widget s in the card - > Widgets list b.2 When registering machine drivers, the following calls are made: soc_probe_dai_link > soc_post_component_init > snd_soc_dapm_new_widgets snd_soc_dapm_new_widgets: For each widget, set its power_check function (to determine whether the widget should be powered on) For mixer widget, snd_kcontrol_new is constructed from snd_kcontrol_new and put into card - > controls list. For mux widget, it has only one snd_kcontrol_new, constructs snd_kcontrol, and puts it in the card - > controls list.