ASoc音频框架
嵌入式系统使用的音频框架是Asoc,在alsa的基础上又封装了一套代码,针对嵌入式系统。
Asoc产生
x86是通过PCI,如下图:
嵌入式式下面接口,产生了ASoc。
1)分为三个部分,platform,codec和machine
platform:提供主控芯片驱动
codec :提供音频芯片驱动
machine类似于单板,它选择哪个platform,哪一个codec;并且决定了platform和codec怎么连接。
2)播放与录音
播放:soc通过i2s把数字信号给音频芯片,音频转换成模拟播放起来。
录音:音频芯片把模拟信号转换成数字信号通过i2s接口传递给soc端
codec侧驱动
codec侧有I2S和I2C分别对应着结构体snd_soc_dai_driver和snd_soc_codec_driver。
1.1 snd_soc_dai_driver结构
384 static struct snd_soc_dai_driver uda1341_dai = {
385 .name = "uda1341-iis",
386 /* playback capabilities */
387 .playback = {
388 .stream_name = "Playback",
389 .channels_min = 1,
390 .channels_max = 2,
391 .rates = UDA134X_RATES,
392 .formats = UDA134X_FORMATS,
393 },
394 /* capture capabilities */
395 .capture = {
396 .stream_name = "Capture",
397 .channels_min = 1,
398 .channels_max = 2,
399 .rates = UDA134X_RATES,
400 .formats = UDA134X_FORMATS,
401 },
402 /* pcm operations */
403 .ops = &uda1341_dai_ops,
404 };
说明:
- 名字
- 参数(速率,格式)
- 函数(设置参数的接口)
1.2snd_soc_codec_driver
334 static struct snd_soc_codec_driver soc_codec_dev_uda1341 = {
335 .probe = uda1341_soc_probe,
336
337 /* UDA1341的寄存器不支持读操作
338 * 要知道某个寄存器的当前值,
339 * 只能在写入时保存起来
340 */
341 .reg_cache_size = sizeof(uda1341_reg),
342 .reg_word_size = sizeof(u8),
343 .reg_cache_default = uda1341_reg,
344 .reg_cache_step = 1,
345 .read = uda1341_read_reg_cache,
346 .write = uda1341_write_reg, /* 写寄存器 */
347 };
说明:
读写寄存器
platform端
snd_soc_dai_driver
142 static struct snd_soc_dai_driver s3c2440_i2s_dai = {
143 .playback = {
144 .channels_min = 2,
145 .channels_max = 2,
146 .rates = S3C24XX_I2S_RATES,
147 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
148 .capture = {
149 .channels_min = 2,
150 .channels_max = 2,
151 .rates = S3C24XX_I2S_RATES,
152 .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
153 .ops = &s3c2440_i2s_dai_ops,
154 }; 132 static const struct snd_soc_dai_ops s3c2440_i2s_dai_ops = {
133 .hw_params = s3c2440_i2s_hw_params,
134 .trigger = s3c2440_i2s_trigger,
135 };
说明:
1)name
2)参数
3)函数(设置参数函数,启动数据传输)
snd_soc_platform_driver
数据结构,负责数据传输。
283 static struct snd_soc_platform_driver s3c2440_dma_platform = {
284 .ops = &s3c2440_dma_ops,
285 .pcm_new = s3c2440_dma_new,
286 .pcm_free = s3c2440_dma_free,
287 };
288 230 static struct snd_pcm_ops s3c2440_dma_ops = {
231 .open = s3c2440_dma_open,
232 .close = s3c2440_dma_close,
233 .ioctl = snd_pcm_lib_ioctl,
234 .hw_params = s3c2440_dma_hw_params,
235 .prepare = s3c2440_dma_prepare,
236 .trigger = s3c2440_dma_trigger,
237 .pointer = s3c2440_dma_pointer,
238 };
内核相关链表
dai_list、codec_list和platform_list三个链表
1)dai_list
snd_soc_dai_driver
2)codec_list
snd_soc_codec_driver
3)platform_list
snd_soc_platform_driver
machine
22 static struct snd_soc_dai_link s3c2440_uda1341_dai_link = { 23 .name = "100ask_UDA1341", 24 .stream_name = "100ask_UDA1341", 25 .codec_name = "wm8976-codec", 26 .codec_dai_name = "wm8976-iis", 27 .cpu_dai_name = "s3c2440-iis", 28 .ops = &s3c2440_uda1341_ops, 29 .platform_name = "s3c2440-dma", 30 }; 31 32 33 static struct snd_soc_card myalsa_card = { 34 .name = "S3C2440_UDA1341", 35 .owner = THIS_MODULE, 36 .dai_link = &s3c2440_uda1341_dai_link, 37 .num_links = 1, 38 };
Asoc的流程
33 static struct snd_soc_card myalsa_card = { 34 .name = "S3C2440_UDA1341", 35 .owner = THIS_MODULE, 36 .dai_link = &s3c2440_uda1341_dai_link, 37 .num_links = 1, 38 };44 static struct platform_device asoc_dev = { 45 .name = "soc-audio", 46 .id = -1, 47 .dev = { 48 .release = asoc_release, 49 }, 50 }; 51 52 static int s3c2440_uda1341_init(void) 53 { 54 platform_set_drvdata(&asoc_dev, &myalsa_card); 55 platform_device_register(&asoc_dev);
myalsa_card作为私有数据(主要dai_link结构体),放入到platform_device,
通过platform_device_register把设备soc-audio加入到虚拟platform框架中,会导致soc-audio同名的driver被调用。
soc
执行sound/soc/soc-core.c
2013 static int soc_probe(struct platform_device *pdev)
2014 {
2015 struct snd_soc_card *card = platform_get_drvdata(pdev);
2016 int ret = 0;
2017
2018 /*
2019 * no card, so machine driver should be registering card
2020 * we should not be here in that case so ret error
2021 */
2022 if (!card)
2023 return -EINVAL;
2024
2025 /* Bodge while we unpick instantiation */
2026 card->dev = &pdev->dev;
2027
2028 ret = snd_soc_register_card(card);
2029 if (ret != 0) {
2030 dev_err(&pdev->dev, "Failed to register card\n");
2031 return ret;
2032 }
2033
2034 return 0;
2035 }
platform_get_drvdata提取传递过来的私有数据,重新构造card。
3387 int snd_soc_register_card(struct snd_soc_card *card)
3388 {
3389 int i;
3390
3391 if (!card->name || !card->dev)
3392 return -EINVAL;
3393
3394 dev_set_drvdata(card->dev, card);
3395
3396 snd_soc_initialize_card_lists(card);
3397
3398 soc_init_card_debugfs(card);
3399
3400 card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) *
3401 (card->num_links + card->num_aux_devs),
3402 GFP_KERNEL);
3403 if (card->rtd == NULL)
3404 return -ENOMEM;
3405 card->rtd_aux = &card->rtd[card->num_links];
3406
3407 for (i = 0; i < card->num_links; i++)
3408 card->rtd[i].dai_link = &card->dai_link[i];
3409
3410 INIT_LIST_HEAD(&card->list);
3411 card->instantiated = 0;
3412 mutex_init(&card->mutex);
3413
3414 mutex_lock(&client_mutex);
3415 list_add(&card->list, &card_list);
3416 snd_soc_instantiate_cards();
3417 mutex_unlock(&client_mutex);
3418
3419 dev_dbg(card->dev, "Registered card '%s'\n", card->name);
3420
3421 return 0;
3422 }
进入3416行
2005 static void snd_soc_instantiate_cards(void)
2006 {
2007 struct snd_soc_card *card;
2008 list_for_each_entry(card, &card_list, list)
2009 snd_soc_instantiate_card(card);
2010 }
进入2009那个函数
1821 static void snd_soc_instantiate_card(struct snd_soc_card *card)
1822 {
1823 struct snd_soc_codec *codec;
1824 struct snd_soc_codec_conf *codec_conf;
1825 enum snd_soc_compress_type compress_type;
1826 int ret, i;
1827
1828 mutex_lock(&card->mutex);
1829
1830 if (card->instantiated) {
1831 mutex_unlock(&card->mutex);
1832 return;
1833 }
1834
1835 /* bind DAIs */
1836 for (i = 0; i < card->num_links; i++)
1837 soc_bind_dai_link(card, i);
1838
1839 /* bind completed ? */
1840 if (card->num_rtd != card->num_links) {
1841 mutex_unlock(&card->mutex);
1842 return;
1843 }
1844
1845 /* initialize the register cache for each available codec */
1846 list_for_each_entry(codec, &codec_list, list) {
1847 if (codec->cache_init)
1848 continue;
1849 /* by default we don't override the compress_type */
1850 compress_type = 0;
1851 /* check to see if we need to override the compress_type */
1852 for (i = 0; i < card->num_configs; ++i) {
1853 codec_conf = &card->codec_conf[i];
1854 if (!strcmp(codec->name, codec_conf->dev_name)) {
1855 compress_type = codec_conf->compress_type;
1856 if (compress_type && compress_type
1857 != codec->compress_type)
1858 break;
1859 }
1860 }
1861 ret = snd_soc_init_codec_cache(codec, compress_type);
1862 if (ret < 0) {
1863 mutex_unlock(&card->mutex);
1864 return;
1865 }
1866 }
1867
1868 /* card bind complete so register a sound card */
1869 ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
1870 card->owner, 0, &card->snd_card);
1871 if (ret < 0) {
1872 printk(KERN_ERR "asoc: can't create sound card for card %s\n",
1873 card->name);
1874 mutex_unlock(&card->mutex);
1875 return;
1876 }
1877 card->snd_card->dev = card->dev;
1878
1879 card->dapm.bias_level = SND_SOC_BIAS_OFF;
1880 card->dapm.dev = card->dev;
1881 card->dapm.card = card;
1882 list_add(&card->dapm.list, &card->dapm_list);
1883
1884 #ifdef CONFIG_DEBUG_FS
1885 snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
1886 #endif
1887
1888 #ifdef CONFIG_PM_SLEEP
1889 /* deferred resume work */
1890 INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
1891 #endif
1892
1893 if (card->dapm_widgets)
1894 snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
1895 card->num_dapm_widgets);
1896
1897 /* initialise the sound card only once */
1898 if (card->probe) {
1899 ret = card->probe(card);
1900 if (ret < 0)
1901 goto card_probe_error;
1902 }
1903
1904 for (i = 0; i < card->num_links; i++) {
1905 ret = soc_probe_dai_link(card, i);
1906 if (ret < 0) {
1907 pr_err("asoc: failed to instantiate card %s: %d\n",
1908 card->name, ret);
1909 goto probe_dai_err;
1910 }
1911 }
1912
1913 for (i = 0; i < card->num_aux_devs; i++) {
1914 ret = soc_probe_aux_dev(card, i);
1915 if (ret < 0) {
1916 pr_err("asoc: failed to add auxiliary devices %s: %d\n",
1917 card->name, ret);
1918 goto probe_aux_dev_err;
1919 }
1920 }
1921
1922 /* We should have a non-codec control add function but we don't */
1923 if (card->controls)
1924 snd_soc_add_controls(list_first_entry(&card->codec_dev_list, 1925 struct snd_soc_codec,
1926 card_list),
1927 card->controls,
1928 card->num_controls);
1929
1930 if (card->dapm_routes)
1931 snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
1932 card->num_dapm_routes);
1933
1934 snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
1935 "%s", card->name);
1936 snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
1937 "%s", card->long_name ? card->long_name : card->name);
1938 snprintf(card->snd_card->driver, sizeof(card->snd_card->driver),
1939 "%s", card->driver_name ? card->driver_name : card->name);
1940 for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) {
1941 switch (card->snd_card->driver[i]) {
1942 case '_':
1943 case '-':
1944 case '\0':
1945 break;
1946 default:
1947 if (!isalnum(card->snd_card->driver[i]))
1948 card->snd_card->driver[i] = '_';
1949 break;
1950 }
1951 } 1953 if (card->late_probe) {
1954 ret = card->late_probe(card);
1955 if (ret < 0) {
1956 dev_err(card->dev, "%s late_probe() failed: %d\n",
1957 card->name, ret);
1958 goto probe_aux_dev_err;
1959 }
1960 }
1961
1962 ret = snd_card_register(card->snd_card);
1963 if (ret < 0) {
1964 printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
1965 goto probe_aux_dev_err;
1966 }
1967
1968 #ifdef CONFIG_SND_SOC_AC97_BUS
1969 /* register any AC97 codecs */
1970 for (i = 0; i < card->num_rtd; i++) {
1971 ret = soc_register_ac97_dai_link(&card->rtd[i]);
1972 if (ret < 0) {
1973 printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
1974 while (--i >= 0)
1975 soc_unregister_ac97_dai_link(card->rtd[i].codec);
1976 goto probe_aux_dev_err;
1977 }
1978 }
1979 #endif
在1836行绑定指定dai,在1869行创建,在1962行注册。
概括:分配/设置/注册snd_card。进入alsa那一套。