ALSA声卡08_从零编写之框架_学习笔记
1、整體框架
(1)圖示((DAI(全稱Digital Audio Interface)接口))
?在嵌入式系統(tǒng)里面,聲卡驅(qū)動是ASOC,是在ALSA驅(qū)動上封裝的一層,包括以下三大塊
(2)程序框架
machine:s3c2440_uda1341.c
codec: UDA1341,WM8976
platform:IIS ,DMA
2、s3c2440_uda1341.c(參考s3c24xx_uda134x.c)
(1)分配一個(gè)平臺為soc-audio的平臺設(shè)備,
在這平臺設(shè)備里面有一個(gè)核心結(jié)構(gòu)體snd_soc_s3c24xx_uda134x設(shè)置到私有數(shù)據(jù)里面
snd_soc_s3c24xx_uda134x結(jié)構(gòu)體是snd_soc_card類型的,里面有dai_link(我們需要重點(diǎn)關(guān)注的),dai_link確定了聲卡各部分所對應(yīng)的驅(qū)動程序
(2)名為soc-audio的平臺設(shè)備,注冊后會跟內(nèi)核里面soc-core.c文件注冊的同名driver匹配,最后調(diào)用probe,進(jìn)行一系列的聲卡注冊。
3、s3c2440_uda1341.c編寫
/* 參考sound\soc\samsung\s3c24xx_uda134x.c
?*/
/*
?* 1. 分配注冊一個(gè)名為soc-audio的平臺設(shè)備
?* 2. 這個(gè)平臺設(shè)備有一個(gè)私有數(shù)據(jù) snd_soc_card(結(jié)構(gòu)體)
?* ? ?snd_soc_card里有一項(xiàng)snd_soc_dai_link(結(jié)構(gòu)體)
?* ? ?snd_soc_dai_link被用來決定ASOC各部分的驅(qū)動
?*/
static struct snd_soc_ops s3c2440_uda1341_ops = {
//.hw_params = s3c24xx_uda134x_hw_params,//設(shè)置參數(shù)
};
static struct?snd_soc_dai_link?s3c2440_uda1341_dai_link = {
.name = "100ask_UDA1341",//結(jié)構(gòu)體的名字
.stream_name = "100ask_UDA1341",//
.codec_name = "uda1341-codec",//使用哪一個(gè)編解碼芯片
.codec_dai_name = "uda1341-iis",//編解碼芯片里面哪一個(gè)DAI
.cpu_dai_name = "s3c2440-iis",//2440的DAI(平臺部分的)
.ops = &s3c2440_uda1341_ops,//操作函數(shù)
.platform_name= "s3c2440-dma",?//平臺的名字
};
static struct?snd_soc_card?myalsa_card = {
.name = "S3C2440_UDA1341",//結(jié)構(gòu)體的名字
.owner = THIS_MODULE,
.dai_link = &s3c2440_uda1341_dai_link,
.num_links = 1,
};
static void asoc_release(struct device * dev)
{
}
//定義一個(gè)名為soc-audio的平臺設(shè)備
static struct?platform_device?asoc_dev = {
? ? .name ? ? ? ? = "soc-audio",
? ? .id ? ? ? = -1,
? ? .dev = {?
? ??.release = asoc_release,?//release函數(shù)必須要寫,否則有警告信息
},
};
//入口函數(shù)
static int s3c2440_uda1341_init(void)
{
platform_set_drvdata(&asoc_dev, &myalsa_card);//把snd_soc_card結(jié)構(gòu)體當(dāng)做平臺設(shè)備的私有數(shù)據(jù)
? ? platform_device_register(&asoc_dev); ???//注冊平臺設(shè)備
? ? return 0;
}
//出口函數(shù)
static void s3c2440_uda1341_exit(void)
{
? ? platform_device_unregister(&asoc_dev);//卸載平臺設(shè)備
}
4、uda1341.c(codec)
小技巧:本來想在初始化的函數(shù)里調(diào)用snd_soc_register_codec函數(shù),但是這個(gè)函數(shù)里有device參數(shù)。所以要自己構(gòu)建一個(gè)平臺設(shè)備和平臺驅(qū)動。
int snd_soc_register_codec(struct device *dev,
? const struct snd_soc_codec_driver *codec_drv,
? struct snd_soc_dai_driver *dai_drv,
? int num_dai)
通過注冊平臺設(shè)備、平臺驅(qū)動來實(shí)現(xiàn)對snd_soc_register_codec的調(diào)用(通過平臺設(shè)備和平臺驅(qū)動匹配后調(diào)用probe函數(shù))
兩個(gè)核心結(jié)構(gòu)體
/* 參考 sound\soc\codecs\uda134x.c
?*/
/*
* 1. 構(gòu)造一個(gè)snd_soc_dai_driver(結(jié)構(gòu)體)
?* 2. 構(gòu)造一個(gè)snd_soc_codec_driver(結(jié)構(gòu)體)
?* 3. 注冊它們
?*/
static struct?snd_soc_codec_driver?soc_codec_dev_uda1341?= {
? ? .probe = uda1341_soc_probe,
};
static const struct snd_soc_dai_ops?uda1341_dai_ops?= {
.hw_params?= uda1341_hw_params,
};
static struct?snd_soc_dai_driver?uda1341_dai?= {
.name = "uda1341-iis",//這個(gè)名字取的是machine部分的s3c2440_uda1341.c文件的?snd_soc_dai_link結(jié)構(gòu)體,編解碼芯片里面哪一個(gè)DAI
根據(jù)編解碼芯片的數(shù)據(jù)手冊確定的
/* playback capabilities */播放相關(guān)的屬性
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = UDA134X_RATES,//編解碼芯片支持的聲音采樣率
.formats = UDA134X_FORMATS,//編解碼芯片支持哪種格式
},
/* capture capabilities */捕抓屬性
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = UDA134X_RATES,
.formats = UDA134X_FORMATS,
},
/* pcm operations */含操作相關(guān)函數(shù)的結(jié)構(gòu)體
.ops = &uda1341_dai_ops,
};
/* 通過注冊平臺設(shè)備、平臺驅(qū)動來實(shí)現(xiàn)對snd_soc_register_codec的調(diào)用(通過平臺設(shè)備和平臺驅(qū)動匹配后調(diào)用probe函數(shù))
?*
?*/
static void?uda1341_dev_release(struct device * dev)
{
}
//probe函數(shù)
static int uda1341_probe(struct platform_device *pdev)
{
return snd_soc_register_codec(&pdev->dev, ??//注冊結(jié)構(gòu)體snd_soc_dai_driver?和snd_soc_codec_driver,用哪一個(gè)codec,哪一個(gè)DAI
&soc_codec_dev_uda1341, &uda1341_dai, 1);
}
//remove函數(shù)
static int uda1341_remove(struct platform_device *pdev)
{
? ? snd_soc_unregister_codec(&pdev->dev);
? ? return 0;
}
//平臺設(shè)備
static struct?platform_device?uda1341_dev = {
? ? .name ? ? ? ? = "uda1341-codec",//這個(gè)名字取的是machine部分的s3c2440_uda1341.c文件的?snd_soc_dai_link結(jié)構(gòu)體
? ? .id ? ? ? = -1,
? ? .dev = {?
? ??.release =?uda1341_dev_release,?
},
};
//平臺驅(qū)動
struct?platform_driveruda1341_drv = {
.probe= uda1341_probe,//probe函數(shù)
.remove= uda1341_remove,
.driver= {
.name= "uda1341-codec",
}
};
static int uda1341_init(void)
{
? ??
? ? platform_device_register(&uda1341_dev);//注冊平臺設(shè)備
? ? platform_driver_register(&uda1341_drv);//注冊平臺驅(qū)動
? ? return 0;
}
static void uda1341_exit(void)
{
? ? platform_device_unregister(&uda1341_dev);//卸載平臺設(shè)備
? ? platform_driver_unregister(&uda1341_drv);//卸載平臺驅(qū)動
}
5、s3c2440_iis.c(Platform)
/* 參考sound\soc\samsung\s3c24xx-i2s.c
?*/
//操作函數(shù)相關(guān)的結(jié)構(gòu)體
static const struct snd_soc_dai_ops s3c2440_i2s_dai_ops = {
.hw_params?= s3c2440_i2s_hw_params,//設(shè)置參數(shù)
.trigger?= s3c2440_i2s_trigger,//觸發(fā)傳輸
};
//我們的dai_driver沒有名字,而我們的machine怎么知道使用哪一個(gè)CPU DAI,沒有名字,名字在注冊的時(shí)候從平臺設(shè)備哦繼承而來snd_soc_register_dai(&pdev->dev, &s3c2440_i2s_dai);
表示能夠支持的屬性
static struct?snd_soc_dai_driver?s3c2440_i2s_dai = {
.playback = {
.channels_min = 2,
.channels_max = 2,
.rates = S3C24XX_I2S_RATES,//支持的采樣率
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},//支持的格式
.capture = {
.channels_min = 2,
.channels_max = 2,
.rates = S3C24XX_I2S_RATES,
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
.ops = &s3c2440_i2s_dai_ops,//操作函數(shù)相關(guān)的結(jié)構(gòu)體
};
//probe函數(shù)(注冊)
static int s3c2440_iis_probe(struct platform_device *pdev)
{
return snd_soc_register_dai(&pdev->dev, &s3c2440_i2s_dai);//注冊cpu dai
}
remove函數(shù)(卸載)
static int s3c2440_iis_remove(struct platform_device *pdev)
{
snd_soc_unregister_dai(&pdev->dev);
? ? return 0;
}
static void s3c2440_iis_release(struct device * dev)
{
}
//注冊平臺設(shè)備
static struct?platform_device?s3c2440_iis_dev = {
? ? .name ? ? ? ? = "s3c2440-iis",//這個(gè)名字取的是machine部分的s3c2440_uda1341.c文件的?snd_soc_dai_link結(jié)構(gòu)體
? ? .id ? ? ? = -1,
? ? .dev = {?
? ??.release = s3c2440_iis_release,?
},
};
//注冊平臺驅(qū)動
struct?platform_driver?s3c2440_iis_drv = {
.probe= s3c2440_iis_probe,
.remove= s3c2440_iis_remove,
.driver= {
.name= "s3c2440-iis",//這個(gè)名字取的是machine部分的s3c2440_uda1341.c文件的?snd_soc_dai_link結(jié)構(gòu)體
}
};
//入口函數(shù)
static int s3c2440_iis_init(void)
{
??
? ? platform_device_register(&s3c2440_iis_dev);//注冊平臺設(shè)備
? ? platform_driver_register(&s3c2440_iis_drv);//注冊平臺驅(qū)動
? ? return 0;
}
//出口函數(shù)
static void s3c2440_iis_exit(void)
{
? ??
? ? platform_device_unregister(&s3c2440_iis_dev);//卸載平臺設(shè)備
? ? platform_driver_unregister(&s3c2440_iis_drv);//卸載平臺驅(qū)動
? ?
? ??
}
6、s3c2440_dma.c(Platform)
/* 參考 sound\soc\samsung\dma.c
?*/
/* 1. 分配DMA BUFFER
?* 2. 從BUFFER取出period
?* 3. 啟動DMA傳輸
?* 4. 傳輸完畢,更新狀態(tài)(hw_ptr)
?* ? ?2,3,4這部分主要有: request_irq, 觸發(fā)DMA傳輸, 中斷處理
?*/
//操作函數(shù)相關(guān)的結(jié)構(gòu)體
static struct?snd_pcm_ops?s3c2440_dma_ops = {
.open= s3c2440_dma_open,
.close?= s3c2440_dma_close,
.ioctl?= snd_pcm_lib_ioctl,
.hw_params?= s3c2440_dma_hw_params,
.prepare ? ?= s3c2440_dma_prepare,
.trigger?= s3c2440_dma_trigger,
.pointer?= s3c2440_dma_pointer,
};
static struct?snd_soc_platform_driver?s3c2440_dma_platform = {
.ops= &s3c2440_dma_ops,//操作函數(shù)相關(guān)的結(jié)構(gòu)體
.pcm_new?= s3c2440_dma_new,
.pcm_free?= s3c2440_dma_free,
};
//probe 函數(shù)
static int s3c2440_dma_probe(struct platform_device *pdev)
{
return snd_soc_register_platform(&pdev->dev, &s3c2440_dma_platform);//注冊平臺結(jié)構(gòu)體,//我們的s3c2440_dma_platform沒有名字,而我們的machine怎么知道使用哪一個(gè)CPU DAI,沒有名字,名字在注冊的時(shí)候從平臺設(shè)備哦繼承而來snd_soc_register_platform(&pdev->dev, &s3c2440_dma_platform);
}
static int s3c2440_dma_remove(struct platform_device *pdev)
{
snd_soc_unregister_platform(&pdev->dev);
? ? return 0;
}
static void s3c2440_dma_release(struct device * dev)
{
}
//平臺設(shè)備
static struct?platform_device?s3c2440_dma_dev = {
? ? .name ? ? ? ? = "s3c2440-dma",
? ? .id ? ? ? = -1,
? ? .dev = {?
? ??.release = s3c2440_dma_release,?
},
};
//平臺驅(qū)動
struct?platform_drivers3c2440_dma_drv = {
.probe= s3c2440_dma_probe,//probe函數(shù)
.remove= s3c2440_dma_remove,
.driver= {
.name= "s3c2440-dma",
}
};
static int s3c2440_dma_init(void)
{
? ? platform_device_register(&s3c2440_dma_dev);/注冊平臺設(shè)備
? ? platform_driver_register(&s3c2440_dma_drv);//注冊平臺驅(qū)動
? ? return 0;
}
static void s3c2440_dma_exit(void)
{
? ? platform_device_unregister(&s3c2440_dma_dev);
? ? platform_driver_unregister(&s3c2440_dma_drv);
? ? iounmap(dma_regs);
}
7、總結(jié)
總結(jié)
以上是生活随笔為你收集整理的ALSA声卡08_从零编写之框架_学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Python】把excel文件中的数据
- 下一篇: 初识结构体