當前位置:首頁 > 芯聞號 > 充電吧
[導(dǎo)讀]淺析ASoC-audio驅(qū)動oss框架下/dev/dsp與alsa框架下設(shè)備節(jié)點打開和創(chuàng)建簡易流程對于oss設(shè)備節(jié)點1. soundcore_fops?????? --? 提供主設(shè)備號為14的oss節(jié)

淺析ASoC-audio驅(qū)動oss框架下/dev/dsp與alsa框架下設(shè)備節(jié)點打開和創(chuàng)建簡易流程

對于oss設(shè)備節(jié)點
1. soundcore_fops?????? --? 提供主設(shè)備號為14的oss節(jié)點open("/dev/dsp")操作soundcore_open,最后將調(diào)用snd_pcm_oss_open
2. snd_pcm_oss_f_reg??? --? 提供最終的file->f_op應(yīng)用程序調(diào)用方法集
對于alsa設(shè)備節(jié)點
1. snd_fops???????????? --? 提供主設(shè)備號為116的alsa節(jié)點open("/dev/snd/pcmC0D0c")操作snd_open
2. snd_pcm_f_ops[2]???? --? 提供最終的file->f_op應(yīng)用程序調(diào)用方法集snd_pcm_f_ops[0]用于放音,snd_pcm_f_ops[1]用于錄音.

可能后面的流程都是混雜的,不能區(qū)分很清楚,所以先來看最直觀的oss設(shè)備節(jié)點"/dev/dsp"打開流程[luther.gliethttp].
static const struct file_operations soundcore_fops=
{
?? ?/* We must have an owner or the module locking fails */
?? ?.owner?? ?= THIS_MODULE,
?? ?.open?? ?= soundcore_open,?????????????????????????????????????????? // 類似chrdev_open的實現(xiàn),現(xiàn)在很多集中管理的驅(qū)動都這樣
};????????????????????????????????????????????????????????????????????? // 來界定設(shè)備[luther.gliethttp].

static const struct file_operations snd_pcm_oss_f_reg =
{
?? ?.owner =?? ?THIS_MODULE,
?? ?.read =?? ??? ?snd_pcm_oss_read,
?? ?.write =?? ?snd_pcm_oss_write,
?? ?.open =?? ??? ?snd_pcm_oss_open,
?? ?.release =?? ?snd_pcm_oss_release,
?? ?.poll =?? ??? ?snd_pcm_oss_poll,
?? ?.unlocked_ioctl =?? ?snd_pcm_oss_ioctl,
?? ?.compat_ioctl =?? ?snd_pcm_oss_ioctl_compat,
?? ?.mmap =?? ??? ?snd_pcm_oss_mmap,
};

我們先來看看打開/dev/dsp字符設(shè)備節(jié)點的流程[luther.gliethttp].
luther@gliethttp:~$ ll /dev/dsp
crw-rw----+ 1 root audio 14, 3 2009-08-15 14:59 /dev/dsp

module_init(init_soundcore);??????????????????????????????????????????? // 模塊人口
static int __init init_soundcore(void)
{
??? // #define SOUND_MAJOR????? 14
?? ?if (register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) {?? // 主設(shè)備號為14的所有256個字符設(shè)備節(jié)點都將調(diào)用該方法集
?? ??? ?printk(KERN_ERR "soundcore: sound device already in use.n");?? // 比如打開/dev/dsp設(shè)備,那么將首先執(zhí)行這里的soundcore_open
?? ??? ?return -EBUSY;
?? ?}
?? ?sound_class = class_create(THIS_MODULE, "sound");?????????????????? // 創(chuàng)建/sys/class/sound類目錄[luther.gliethttp]
?? ?if (IS_ERR(sound_class))
?? ??? ?return PTR_ERR(sound_class);

?? ?return 0;
}

int soundcore_open(struct inode *inode, struct file *file)
{
???int unit = iminor(inode);?????????????????????????????????????????? //根據(jù)inode節(jié)點的minor次設(shè)備號鎖定聲卡設(shè)備,對于inode節(jié)點的自動創(chuàng)建在后面我們會慢慢談到[luther.gliethttp].
??? struct sound_unit *s;
??? ......
/*
?*?? ?Allocations
?*
?*?? ?0?? ?*16?? ??? ?Mixers
?*?? ?1?? ?*8?? ??? ?Sequencers
?*?? ?2?? ?*16?? ??? ?Midi
?*?? ?3?? ?*16?? ??? ?DSP
?*?? ?4?? ?*16?? ??? ?SunDSP
?*?? ?5?? ?*16?? ??? ?DSP16
?*?? ?6?? ?--?? ??? ?sndstat (obsolete)
?*?? ?7?? ?*16?? ??? ?unused
?*?? ?8?? ?--?? ??? ?alternate sequencer (see above)
?*?? ?9?? ?*16?? ??? ?raw synthesizer access
?*?? ?10?? ?*16?? ??? ?unused
?*?? ?11?? ?*16?? ??? ?unused
?*?? ?12?? ?*16?? ??? ?unused
?*?? ?13?? ?*16?? ??? ?unused
?*?? ?14?? ?*16?? ??? ?unused
?*?? ?15?? ?*16?? ??? ?unused

static struct sound_unit *chains[SOUND_STEP];
*/
??? chain=unit&0x0F;??????????????????????????????????????????????????? // 當前不超過16個SOUND_STEP
??? s = __look_for_unit(chain, unit);?????????????????????????????????? // 從chains[chain]全局鏈表上尋找索引號為unit的sound_unit.
??? if (s)
???????new_fops = fops_get(s->unit_fops);????????????????????????????? //使用s->unit_fops=snd_pcm_oss_f_reg替換原有的soundcore_fops函數(shù)集
??? file->f_op = new_fops;
??? err = file->f_op->open(inode,file);???????????????????????????????? // 使用snd_pcm_oss_open進一步打開
}

static struct sound_unit *__look_for_unit(int chain, int unit)
{
?? ?struct sound_unit *s;
?? ?
??? s=chains[chain];
??? while(s && s->unit_minor <= unit)
??? {
??? ??? if(s->unit_minor==unit)
??? ??? ??? return s;?????????????????????????????????????????????????? // ok,找到
??? ??? s=s->next;
??? }
??? return NULL;
}

到目前為止我們粗略討論了打開/dev/dsp設(shè)備節(jié)點的流程,下面我們繼續(xù)看看創(chuàng)建/dev/dsp設(shè)備節(jié)點的流程是怎么樣的[luther.gliethttp],

module_init(alsa_pcm_oss_init)還有一個module_init(alsa_mixer_oss_init)和alsa_pcm_oss_init過程差不多.
==>alsa_pcm_oss_init???????????????????????????????????//登記snd_pcm_oss_notify,同時為snd_pcm_devices鏈表上的的pcm設(shè)備執(zhí)行snd_pcm_oss_register_minor函數(shù)
==*>snd_pcm_notify(&snd_pcm_oss_notify, 0)????????????? // 將snd_pcm_oss_notify追加到snd_pcm_notify_list通知鏈表
??? list_add_tail(&notify->list, &snd_pcm_notify_list);
??? list_for_each_entry(pcm, &snd_pcm_devices, list)??? // 同時為snd_pcm_oss_notify遍歷已經(jīng)注冊登記到snd_pcm_devices鏈表上的的pcm設(shè)備
??? ??? ??? notify->n_register(pcm);??????????????????? // 為他們分別執(zhí)行snd_pcm_oss_notify的n_register方法[luther.gliehtttp]

static struct snd_pcm_notify snd_pcm_oss_notify =
{
??? .n_register =??? snd_pcm_oss_register_minor,
??? .n_disconnect = snd_pcm_oss_disconnect_minor,
??? .n_unregister =??? snd_pcm_oss_unregister_minor,
};

snd_pcm_oss_register_minor?????????????????????????????? // 當檢測到新的聲卡設(shè)備時,就會調(diào)用該notifer函數(shù),為其注冊登記生成設(shè)備節(jié)點
==> register_oss_dsp(pcm, 0);和register_oss_dsp(pcm, 1); // index=0或者index=1,即第0個16組或者第1個16組
static void register_oss_dsp(struct snd_pcm *pcm, int index)
{
??? char name[128];
??? sprintf(name, "dsp%i%i", pcm->card->number, pcm->device);
??? if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
??? ??? ??? ??? ??? pcm->card, index, &snd_pcm_oss_f_reg,// 實際完成控制設(shè)備的fops,即:snd_pcm_oss_f_reg
??? ??? ??? ??? ??? pcm, name) < 0) {
??? ??? snd_printk(KERN_ERR "unable to register OSS PCM device %i:%in",
??? ??? ??? ?? pcm->card->number, pcm->device);
??? }
}

snd_register_oss_device(int type, struct snd_card *card, int dev,
??? ??? ??? ??? const struct file_operations *f_ops, void *private_data,
??? ??? ??? ??? const char *name)
==>int minor = snd_oss_kernel_minor(type, card, dev);????????????????? //minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_PCM1 :SNDRV_MINOR_OSS_PCM));
==> preg->device = dev;???????????????????????????????????????????????? // 我這里minor等于3
==> preg->f_ops = f_ops;
==> snd_oss_minors[minor] = preg;?????????????????????????????????????? // 放到oss設(shè)備數(shù)組中,這樣在snd_pcm_oss_open時可以打開
==> register_sound_special_device(f_ops, minor, carddev);?????????????? // minor>=3
/**
?*??? register_sound_special_device - register a special sound node
?*??? @fops: File operations for the driver
?*??? @unit: Unit number to allocate
?*????? @dev: device pointer
?*
?*??? Allocate a special sound device by minor number from the sound
?*??? subsystem. The allocated number is returned on succes. On failure
?*??? a negative error code is returned.
?*/
int register_sound_special_device(const struct file_operations *fops, int unit,
??? ??? ??? ??? ? struct device *dev)
{
??? const int chain = unit % SOUND_STEP;??? // SOUND_STEP為16,分別代表主設(shè)備類型,每個主設(shè)備類型下可以追加n個同類型的音頻設(shè)備.
??? int max_unit = 128 + chain;
??? const char *name;
??? char _name[16];

??? switch (chain) {
??? ??? case 0:
??? ??? name = "mixer";
??? ??? break;
??? ??? case 1:
??? ??? name = "sequencer";
??? ??? if (unit >= SOUND_STEP)
??? ??? ??? goto __unknown;
??? ??? max_unit = unit + 1;
??? ??? break;
??? ??? case 2:
??? ??? name = "midi";
??? ??? break;
??? ??? case 3:
??? ??? name = "dsp";
??? ??? break;
??? ??? case 4:
??? ??? name = "audio";
??? ??? break;
??? ??? case 8:
??? ??? name = "sequencer2";
??? ??? if (unit >= SOUND_STEP)
??? ??? ??? goto __unknown;
??? ??? max_unit = unit + 1;
??? ??? break;
??? ??? case 9:
??? ??? name = "dmmidi";
??? ??? break;
??? ??? case 10:
??? ??? name = "dmfm";
??? ??? break;
??? ??? case 12:
??? ??? name = "adsp";
??? ??? break;
??? ??? case 13:
??? ??? name = "amidi";
??? ??? break;
??? ??? case 14:
??? ??? name = "admmidi";
??? ??? break;
??? ??? default:
??? ??? ??? {
??? ??? ??? __unknown:
??? ??? ??? sprintf(_name, "unknown%d", chain);
??? ??? ??? ??? if (unit >= SOUND_STEP)
??? ??? ??? ??? ??? strcat(_name, "-");
??? ??? ??? ??? name = _name;
??? ??? }
??? ??? break;
??? }
??? return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
??? ??? ??? ??? ?name, S_IRUSR | S_IWUSR, dev);???????????????????????? // 將方法集snd_pcm_oss_f_reg注冊上去
}

staticint sound_insert_unit(struct sound_unit **list, const structfile_operations *fops, int index, int low, int top, const char *name,umode_t mode, struct device *dev)
{
??? struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
??? int r;

??? if (!s)
??? ??? return -ENOMEM;???????????????????????????????????????????????? // index等于-1,表示動態(tài)獲取一個可用的設(shè)備節(jié)點號.
??? ???
??? spin_lock(&sound_loader_lock);????????????????????????????????????? // 每16個設(shè)備為一組,index表示第幾組.
??? r = __sound_insert_unit(s, list, fops, index, low, top);??????????? // 插入到上面提到的chains[3]中,inode節(jié)點的minor設(shè)備號
??? spin_unlock(&sound_loader_lock);??????????????????????????????????? // 從最小值3開始按i*16方式遞增,
??????????????????????????????????????????????????????????????????????? // 即/dev/dsp的節(jié)點號為(14,3),
??????????????????????????????????????????????????????????????????????? // /dev/dsp1的節(jié)點號為(14,19),
??????????????????????????????????????????????????????????????????????? // /dev/dsp2的節(jié)點號為(14,35)依次類推[luther.gliethttp].
??? ??????????????????????????????????????????????????????????????????? // 最后s->unit_minor=動態(tài)獲取的一個空閑id
??????????????????????????????????????????????????????????????????????? // s->unit_fops=snd_pcm_oss_f_reg
??? if (r < 0)
??? ??? goto fail;
??? else if (r < SOUND_STEP)
??? ??? sprintf(s->name, "sound/%s", name);
??? else
??? ??? sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
??????????????????????????????????????????????????????????????????????? // 調(diào)用device_create廣播設(shè)備信息到user space,udev創(chuàng)建
??????????????????????????????????????????????????????????????????????? // 相應(yīng)的字符設(shè)備節(jié)點/dev/dsp等[luther.gliethttp].
??? device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),? // MKDEV(SOUND_MAJOR, s->unit_minor)為/dev/dsp設(shè)備的
??? ??? ????? NULL, s->name+6);???????????????????????????????????????? // 節(jié)點號,主節(jié)點號SOUND_MAJOR等于14,子節(jié)點minor等于s->unit_minor
??? return r;

?fail:
??? kfree(s);
??? return r;
}

上面snd_pcm_oss_notify中的n_register方法即:snd_pcm_oss_register_minor是在snd_pcm_oss_notify注冊時主動執(zhí)行的,
那在設(shè)備注冊的時候又是怎么被動的引用n_register方法的呢?下面我們來看看,
先來看看設(shè)備注冊,
/* audio subsystem */
static struct snd_soc_device TLG_snd_devdata = {
??? .machine = &snd_soc_machine_TLG,
??? .platform = &ep93xx_soc_platform,
??? .codec_dev = &soc_codec_dev_xxxxx,
};

static struct platform_device *TLG_snd_device;
module_init(TLG_init);
static int __init TLG_init(void)??????????????????????????????? // 平臺audio設(shè)備初始化入口
{
??? TLG_snd_device = platform_device_alloc("soc-audio", -1);??? // 他將被名為"soc-audio"的platform總線下的驅(qū)動程序驅(qū)動[luther.gliethttp]
??? platform_set_drvdata(TLG_snd_device, &TLG_snd_devdata);
??? TLG_snd_devdata.dev = &TLG_snd_device->dev;
??? ret = platform_device_add(TLG_snd_device);
}

static struct platform_driver soc_driver = {
??? .driver??? ??? = {
??? ??? .name??? ??? = "soc-audio",
??? },
??? .probe??? ??? = soc_probe,
??? .remove??? ??? = soc_remove,
??? .suspend??? = soc_suspend,
??? .resume??? ??? = soc_resume,
};
/* probes a new socdev */
static int soc_probe(struct platform_device *pdev)
{
// /* TLG audio machine driver */
// static struct snd_soc_machine snd_soc_machine_TLG = {
// ??? .name = "TLG",
// ??? .dai_link = TLG_dai,??????? // /* CPU

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉