1. route种类
route分为三种:
-
常规route
{“sink”,NULL,“source”}
path->connect=1 -
sink widget是mixer:
{“mixer”,name1,“source1”}
{“mixer”,name2,“source2”}
对应的下面的图 :
name1和name2是kcontrol,这两个kcontrol包含在mixer widget中。
这样mixer widget中包括如下:
1)mixer本身信息
2)几个snd_kcontrol_new中包括name1和name2。
3)kcontrol_new的名,可以通过操作某个kcontrol来打开某条path。 -
sink widget是mux
2. route怎么变成path
构造函数snd_soc_dapm_add_route
1656 static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
1657 const struct snd_soc_dapm_route *route)
1658 {
1659 struct snd_soc_dapm_path *path;
1660 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
1661 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
1662 const char *sink;
1663 const char *control = route->control;
1664 const char *source;
1665 char prefixed_sink[80];
1666 char prefixed_source[80];
1667 int ret = 0;
1668
1669 if (dapm->codec && dapm->codec->name_prefix) {
1670 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
1671 dapm->codec->name_prefix, route->sink);
1672 sink = prefixed_sink;
1673 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
1674 dapm->codec->name_prefix, route->source);
1675 source = prefixed_source;
1676 } else {
1677 sink = route->sink;
1678 source = route->source;
1679 }
1680
1681 /*
1682 * find src and dest widgets over all widgets but favor a widget from
1683 * current DAPM context
1684 */
1685 list_for_each_entry(w, &dapm->card->widgets, list) {
1686 if (!wsink && !(strcmp(w->name, sink))) {
1687 wtsink = w;
1688 if (w->dapm == dapm)
1689 wsink = w;
1690 continue;
1691 }
1692 if (!wsource && !(strcmp(w->name, source))) {
1693 wtsource = w;
1694 if (w->dapm == dapm)
1695 wsource = w;
1696 }
1697 }
1698 /* use widget from another DAPM context if not found from this */
1699 if (!wsink)
1700 wsink = wtsink;
1701 if (!wsource)
1702 wsource = wtsource;
1703
1704 if (wsource == NULL || wsink == NULL)
1705 return -ENODEV;
1706
1707 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
1708 if (!path)
1709 return -ENOMEM;
1710
1711 path->source = wsource;
1712 path->sink = wsink;
1713 path->connected = route->connected;
1714 INIT_LIST_HEAD(&path->list);
1715 INIT_LIST_HEAD(&path->list_source);
1716 INIT_LIST_HEAD(&path->list_sink);
1717
1718 /* check for external widgets */
1719 if (wsink->id == snd_soc_dapm_input) {
1720 if (wsource->id == snd_soc_dapm_micbias ||
1721 wsource->id == snd_soc_dapm_mic ||
1722 wsource->id == snd_soc_dapm_line ||
1723 wsource->id == snd_soc_dapm_output)
1724 wsink->ext = 1;
1725 }
1726 if (wsource->id == snd_soc_dapm_output) {
1727 if (wsink->id == snd_soc_dapm_spk ||
1728 wsink->id == snd_soc_dapm_hp ||
1729 wsink->id == snd_soc_dapm_line ||
1730 wsink->id == snd_soc_dapm_input)
1731 wsource->ext = 1;
1732 }
1733
1734 /* connect static paths */
1735 if (control == NULL) {
1736 list_add(&path->list, &dapm->card->paths);
1737 list_add(&path->list_sink, &wsink->sources);
1738 list_add(&path->list_source, &wsource->sinks);
1739 path->connect = 1;
1740 return 0;
1741 }
1742
1743 /* connect dynamic paths */
1744 switch (wsink->id) {
1745 case snd_soc_dapm_adc:
1746 case snd_soc_dapm_dac:
1747 case snd_soc_dapm_pga:
1748 case snd_soc_dapm_out_drv:
1749 case snd_soc_dapm_input:
1750 case snd_soc_dapm_output:
1751 case snd_soc_dapm_micbias:
1752 case snd_soc_dapm_vmid:
1753 case snd_soc_dapm_pre:
1754 case snd_soc_dapm_post:
1755 case snd_soc_dapm_supply:
1756 case snd_soc_dapm_aif_in:
1757 case snd_soc_dapm_aif_out:
1758 list_add(&path->list, &dapm->card->paths);
1759 list_add(&path->list_sink, &wsink->sources);
1760 list_add(&path->list_source, &wsource->sinks);
1761 path->connect = 1;
1762 return 0;
1763 case snd_soc_dapm_mux:
1764 case snd_soc_dapm_virt_mux:
1765 case snd_soc_dapm_value_mux:
1766 ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
1767 &wsink->kcontrol_news[0]);
1768 if (ret != 0)
1769 goto err;
1770 break;
1771 case snd_soc_dapm_switch:
1772 case snd_soc_dapm_mixer:
1773 case snd_soc_dapm_mixer_named_ctl:
1774 ret = dapm_connect_mixer(dapm, wsource, wsink, path, control);
1775 if (ret != 0)
1776 goto err;
1777 break;
1778 case snd_soc_dapm_hp:
1779 case snd_soc_dapm_mic:
1780 case snd_soc_dapm_line:
1781 case snd_soc_dapm_spk:
1782 list_add(&path->list, &dapm->card->paths);
1783 list_add(&path->list_sink, &wsink->sources);
1784 list_add(&path->list_source, &wsource->sinks);
1785 path->connect = 0;
1786 return 0;
1787 }
1788 return 0;
1789
1790 err:
1791 dev_warn(dapm->dev, "asoc: no dapm match for %s --> %s --> %s\n",
1792 source, control, sink);
1793 kfree(path);
1794 return ret;
1795 }
说明:
- 找到source,sink widget
- 构造path
path–>source 指向source widget
path–>sink 指向sink widget
path–>kcontrol = NULL - 设置path->connect
(1734-1741行) a. kcontrol != NULL : 静态路径path->connect=1 (1734-1741行)
(1744-1761行) b.1 sink widget为ADC,DAC等的path,从芯片手册上看,该path一般直连(无开关),所以path->connect=1
(1765-1777行)sink widget是mixer/mux的path,path->connect=根据寄存器的值来确定,在dapm_set_path_status的204-208行可以看出。
(1778-1787)是动态插拔的耳机,喇叭,麦克,先设置path->connect=0,根据实际情况后续改变。
4. 把path放入链表
1758 list_add(&path->list, &dapm->card->paths);
//如果想找出所有path,则从dpam->card找出所有path
1759 list_add(&path->list_sink, &wsink->sources);
//对于某个widget,想知道谁给我提供数据的话,则从这个wdiget的sources链表,找到这些path.
1760 list_add(&path->list_source, &wsource->sinks);
//对于某个widget,想知道我提供数据给谁的话,则从这个wdiget的sinks链表,找到这些path.
根据链表,可知任一个widget
a. 原始数据从哪一个widget发出
b. 数据最终发给谁
也就是complete path。
- path->kcontrol的设置
snd_soc_dapm_add_routes
创建path,但path->kcontrol未设置。
在snd_soc_dapm_new_widgets函数中,他会导致mux/mixer中snd_kcontrol_new被构造为snd_kcontrol,
进而设置path->kcontrol。
dapm_set_path_status函数
dapm_connect_mixer或者dapm_connect_mux调用dapm_set_path_status函数
188 static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
189 struct snd_soc_dapm_path *p, int i)
190 {
191 switch (w->id) {
192 case snd_soc_dapm_switch:
193 case snd_soc_dapm_mixer:
194 case snd_soc_dapm_mixer_named_ctl: {
195 int val;
196 struct soc_mixer_control *mc = (struct soc_mixer_control *)
197 w->kcontrol_news[i].private_value;
198 unsigned int reg = mc->reg;
199 unsigned int shift = mc->shift;
200 int max = mc->max;
201 unsigned int mask = (1 << fls(max)) - 1;
202 unsigned int invert = mc->invert;
203
204 val = snd_soc_read(w->codec, reg);
205 val = (val >> shift) & mask;
206
207 if ((invert && !val) || (!invert && val))
208 p->connect = 1;
209 else
210 p->connect = 0;
211 }
212 break;
213 case snd_soc_dapm_mux: {
214 struct soc_enum *e = (struct soc_enum *)
215 w->kcontrol_news[i].private_value;
216 int val, item, bitmask;
217
218 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
219 ;
220 val = snd_soc_read(w->codec, e->reg);
221 item = (val >> e->shift_l) & (bitmask - 1);
222
223 p->connect = 0;
224 for (i = 0; i < e->max; i++) {
225 if (!(strcmp(p->name, e->texts[i])) && item == i)
226 p->connect = 1;
}