ALSA子系统(七)------simple_card添加虚拟声卡
你好!這里是風箏的博客,
歡迎和我一起交流。
我們知道,asoc框架里面主要包含machine codec platform 這三大部分,
(1)machine:單板相關內容,表明聲卡中所用的主芯片(Platform是指Soc)、編解碼芯片(codec)是哪一個。
主芯片里的接口(DAI(全稱Digital Audio Interface)接口)接到哪里去.CPU DAI是哪一個,codec DAI是哪一個,DMA是哪個。
(2)platform:用于實現平臺相關內容,如IIS(DAI)(設置接口)和DMA(傳輸數據)。
(3)codec:用于實現平臺無關的功能,即編解碼芯片驅動, DAI和控制接口(控制音量)。
音頻子系統(ASOC框架)之Machine
音頻子系統(ASOC框架)之Codec
但是有些場合,我們是不需要一個“真實”的codec做處理的,例如藍牙通話,這時候只要一個虛擬聲卡即可。這里提供一個虛擬聲卡的驅動:
/** Driver for generic Bluetooth SCO link* Copyright 2011 Lars-Peter Clausen <lars@metafoo.de>** This program is free software; you can redistribute it and/or modify it* under the terms of the GNU General Public License as published by the* Free Software Foundation; either version 2 of the License, or (at your* option) any later version.**/ #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> #include <sound/soc.h>static const struct snd_soc_dapm_widget bt_sco_widgets[] = {SND_SOC_DAPM_INPUT("RX"),SND_SOC_DAPM_OUTPUT("TX"), };static const struct snd_soc_dapm_route bt_sco_routes[] = {{ "Capture", NULL, "RX" },{ "TX", NULL, "Playback" }, };static int btsco_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir){pr_debug("%s: clk_id=%d, freq=%d.\n", __func__, clk_id, freq);return 0; }static int btsco_set_pll(struct snd_soc_dai *dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out){pr_debug("%s: pll_id=%d, freq_in=%d, freq_out=%d.\n", __func__, pll_id, freq_in, freq_out);return 0; }static int btsco_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div){pr_debug("%s: div_id=%d, div=%d.\n", __func__, div_id, div);return 0; }static int btsco_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai){pr_debug("%s .\n", __func__);return 0; }static int btsco_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai){pr_debug("%s .\n", __func__);return 0; }static int btsco_set_fmt(struct snd_soc_dai *dai, unsigned int fmt){pr_debug("%s: fmt=%d.\n", __func__, fmt);return 0; }static const struct snd_soc_dai_ops btsco_dai_ops = {.set_sysclk = btsco_set_sysclk,.set_pll = btsco_set_pll,.set_clkdiv = btsco_set_clkdiv,.hw_params = btsco_hw_params,.hw_free = btsco_hw_free,.set_fmt = btsco_set_fmt, };static struct snd_soc_dai_driver bt_sco_dai[] = {{.name = "bt-sco-pcm",.capture = {.stream_name = "Capture",.channels_min = 1,.channels_max = 2,.rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,.formats = SNDRV_PCM_FMTBIT_S16_LE|SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,},.ops = &btsco_dai_ops,}, };static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {.component_driver = {.dapm_widgets = bt_sco_widgets,.num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets),.dapm_routes = bt_sco_routes,.num_dapm_routes = ARRAY_SIZE(bt_sco_routes),}, };static int bt_sco_probe(struct platform_device *pdev) {pr_debug("bt_sco_probe.\n");return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_bt_sco,&bt_sco_dai[0], 1); }static int bt_sco_remove(struct platform_device *pdev) {snd_soc_unregister_codec(&pdev->dev);return 0; }static const struct platform_device_id bt_sco_driver_ids[] = {{.name = "dfbmcs320",},{.name = "bt-sco",},{}, }; MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);#if defined(CONFIG_OF) static const struct of_device_id bt_sco_codec_of_match[] = {{ .compatible = "delta,dfbmcs320", },{ .compatible = "linux,bt-sco", },{}, }; MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match); #endifstatic struct platform_driver bt_sco_driver = {.driver = {.name = "bt-sco",.of_match_table = of_match_ptr(bt_sco_codec_of_match),},.probe = bt_sco_probe,.remove = bt_sco_remove,.id_table = bt_sco_driver_ids, };module_platform_driver(bt_sco_driver);MODULE_DESCRIPTION("ASoC generic bluetooth sco link driver"); MODULE_LICENSE("GPL");這個虛擬到聲卡驅動是通用的,就一個虛擬codec,里面啥都沒做,就規定了一些參數:最大兩通道,采樣率在8k~48k,支持16、20、24、32bit位寬。
既然codec是通用的,那么machine是否也有通用的例子的?
還真有!!!就是simple card framework
Simple card顧名思義,簡單通用的machine driver,代碼實現路徑如下:sound/soc/generic/simple-card.c
需要在內核開啟如下配置才能使用:
同時,我們還需要在設備樹中進行相應到配置:
sound {compatible = "simple-audio-card";simple-audio-card,name = "Dummy-Audio-Card";simple-audio-card,format = "dsp_a";simple-audio-card,bitclock-master = <&dailink0_master>;simple-audio-card,frame-master = <&dailink0_master>;simple-audio-card,mclk-fs = <512>; //codec做主,主控供給編解碼芯片用的時鐘 512FSsimple-audio-card,cpu {sound-dai = <&i2s>;};dailink0_master: simple-audio-card,codec {sound-dai = <&bt_sco>;};}; &i2s {#sound-dai-cells = <0>;status = "okay"; };&bt_sco {#sound-dai-cells = <0>;compatible = "linux,bt-sco";status = "okay"; };這里設備數配置到時:選擇藍牙做主設備,pcm格式。
關于simple-card里的描述,差不多可以歸納為:
- simple-audio-card,name:用戶指定的音頻聲卡名稱。
- simple-audio-card,widgets:指定音頻編解碼器DAPM小部件(widgets),
每個條目都是一對字符串:“template-wname”,“user-supplied-wname”。
“ template-wname”是模板小部件名稱,可選為:“Microphone”, “Line”, “Headphone”, “Speaker”.
“user-supplied-wname”是用戶指定的窗口小部件名稱。 - simple-audio-card,routing:音頻組件之間的連接列表。
每個條目都是一對字符串,第一個是目的(sink),第二個是源(source)。 - simple-audio-card,pin-switches:包含以下組件的窗口小部件名稱的字符串列表必須創建哪個引腳開關。
- simple-audio-card,dai-link:用于dai-link里指定CPU和CODEC子節點。
- simple-audio-card,format:CPU / CODEC通用音頻格式。
可選格式為:
“ i2s”,“ right_j”,“ left_j”,“ dsp_a”
“ dsp_b”,“ ac97”,“ pdm”,“ msb”,“ lsb”。 - frame-master:指向CPU或者CODEC,表示dai-link fram 主機。
- bitclock-master:指向CPU或者CODEC,表示dai-link的位時鐘主控。
- bitclock-inversion:布爾屬性,如果添加則表明dai-link使用位時鐘反轉。
- frame-inversion:布爾屬性。 如果添加則表明dai-link使用幀時鐘反轉。
舉幾個具體到例子:
simple-audio-card,pin-switches = "Headphone","HpSpeaker","LINEOUT"; 等價于驅動里 static const struct snd_kcontrol_new sunxi_card_controls[] = {SOC_DAPM_PIN_SWITCH("Headphone"),SOC_DAPM_PIN_SWITCH("HpSpeaker"),SOC_DAPM_PIN_SWITCH("LINEOUT"), }; snd_soc_add_card_controls(card, sunxi_card_controls,ARRAY_SIZE(sunxi_card_controls)); simple-audio-card,widgets = "Microphone", "HeadphoneMic","Microphone", "Main Mic"; 等價于驅動里 static const struct snd_soc_dapm_widget sunxi_card_dapm_widgets[] = {SND_SOC_DAPM_MIC("HeadphoneMic", NULL),SND_SOC_DAPM_MIC("Main Mic", NULL), }; snd_soc_dapm_new_controls(dapm, sunxi_card_dapm_widgets,ARRAY_SIZE(sunxi_card_dapm_widgets)); simple-audio-card,routing = "MainMic Bias", "Main Mic","MIC1", "MainMic Bias","MIC2", "HeadphoneMic"; 等價于驅動里 static const struct snd_soc_dapm_route sunxi_card_routes[] = {{"MainMic Bias", NULL, "Main Mic"},{"MIC1", NULL, "MainMic Bias"},{"MIC2", NULL, "HeadphoneMic"}, }; snd_soc_dapm_add_routes(dapm, sunxi_card_routes,ARRAY_SIZE(sunxi_card_routes));最后,更多實現詳情可以參考內核文檔:Documentation/devicetree/bindings/sound/simple-card.txt
或者網上也可以瀏覽在線文件:https://www.kernel.org/doc/Documentation/devicetree/bindings/sound/simple-card.txt
總結
以上是生活随笔為你收集整理的ALSA子系统(七)------simple_card添加虚拟声卡的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WinInet + MFC 写vc驿站助
- 下一篇: Windows CMD命令大全(值得收藏