在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > ARM-Linux驅(qū)動(dòng)--DMA驅(qū)動(dòng)分析(一)

            ARM-Linux驅(qū)動(dòng)--DMA驅(qū)動(dòng)分析(一)

            作者: 時(shí)間:2016-11-20 來(lái)源:網(wǎng)絡(luò) 收藏
            硬件平臺(tái):FL2440 (s3c2440

            內(nèi)核版本:2.6.35

            本文引用地址:http://www.biyoush.com/article/201611/319010.htm

            主機(jī)平臺(tái):Ubuntu 11.04

            內(nèi)核版本:2.6.39

            1、DMA的功能和工作原理這里就不多說(shuō)了,可以查看s3c2440的手冊(cè)

            2、在正式分析DMA驅(qū)動(dòng)之前,我們先來(lái)看一下DMA的注冊(cè)和初始化過(guò)程

            系統(tǒng)設(shè)備:(翻譯自源碼注釋)

            系統(tǒng)設(shè)備和系統(tǒng)模型有點(diǎn)不同,它不需要?jiǎng)討B(tài)綁定驅(qū)動(dòng),不能被探測(cè)(probe),不歸結(jié)為任何的系統(tǒng)總線,所以要區(qū)分對(duì)待。對(duì)待系統(tǒng)設(shè)備我們?nèi)匀灰性O(shè)備驅(qū)動(dòng)的觀念,因?yàn)槲覀冃枰獙?duì)設(shè)備進(jìn)行基本的操作。

            定義系統(tǒng)設(shè)備,在./arch/arm/mach-s3c2440/s3c244x.c中


            1. /*定義系統(tǒng)設(shè)備類*/
            2. structsysdev_classs3c2440_sysclass={
            3. .name="s3c2440-core",
            4. .suspend=s3c244x_suspend,
            5. .resume=s3c244x_resume
            6. };
            注冊(cè)系統(tǒng)設(shè)備類,在真正注冊(cè)設(shè)備之前,確保已經(jīng)注冊(cè)了初始化了的系統(tǒng)設(shè)備類


            1. staticint__inits3c2440_core_init(void)
            2. {
            3. returnsysdev_class_register(&s3c2440_sysclass);
            4. }

            下面就是系統(tǒng)設(shè)備類的注冊(cè)函數(shù),在./drivers/base/sys.c中

            1. intsysdev_class_register(structsysdev_class*cls)
            2. {
            3. intretval;
            4. pr_debug("Registeringsysdevclass%sn",cls->name);
            5. INIT_LIST_HEAD(&cls->drivers);
            6. memset(&cls->kset.kobj,0x00,sizeof(structkobject));
            7. cls->kset.kobj.parent=&system_kset->kobj;
            8. cls->kset.kobj.ktype=&ktype_sysdev_class;
            9. cls->kset.kobj.kset=system_kset;
            10. retval=kobject_set_name(&cls->kset.kobj,"%s",cls->name);
            11. if(retval)
            12. returnretval;
            13. retval=kset_register(&cls->kset);
            14. if(!retval&&cls->attrs)
            15. retval=sysfs_create_files(&cls->kset.kobj,
            16. (conststructattribute**)cls->attrs);
            17. returnretval;
            18. }

            1. /*定義DMA系統(tǒng)設(shè)備驅(qū)動(dòng)*/
            2. staticstructsysdev_drivers3c2440_dma_driver={
            3. .add=s3c2440_dma_add,/*添加add函數(shù)*/
            4. };
            下面是add函數(shù),就是調(diào)用三個(gè)函數(shù)

            1. staticint__inits3c2440_dma_add(structsys_device*sysdev)
            2. {
            3. s3c2410_dma_init();
            4. s3c24xx_dma_order_set(&s3c2440_dma_order);
            5. returns3c24xx_dma_init_map(&s3c2440_dma_sel);
            6. }
            注冊(cè)DMA驅(qū)動(dòng)到系統(tǒng)設(shè)備

            1. staticint__inits3c2440_dma_init(void)
            2. {
            3. returnsysdev_driver_register(&s3c2440_sysclass,&s3c2440_dma_driver);
            4. }
            下面就是系統(tǒng)設(shè)備驅(qū)動(dòng)的注冊(cè)函數(shù)

            1. /**
            2. *sysdev_driver_register-Registerauxillarydriver
            3. *@cls:Deviceclassdriverbelongsto.
            4. *@drv:Driver.
            5. *
            6. *@drvisinsertedinto@cls->driverstobe
            7. *calledoneachoperationondevicesofthatclass.Therefcount
            8. *of@clsisincremented.
            9. */
            10. intsysdev_driver_register(structsysdev_class*cls,structsysdev_driver*drv)
            11. {
            12. interr=0;
            13. if(!cls){
            14. WARN(1,KERN_WARNING"sysdev:invalidclasspassedto"
            15. "sysdev_driver_register!n");
            16. return-EINVAL;
            17. }
            18. /*Checkwhetherthisdriverhasalreadybeenaddedtoaclass.*/
            19. if(drv->entry.next&&!list_empty(&drv->entry))
            20. WARN(1,KERN_WARNING"sysdev:class%s:driver(%p)hasalready"
            21. "beenregisteredtoaclass,somethingiswrong,but"
            22. "willforgeon!n",cls->name,drv);
            23. mutex_lock(&sysdev_drivers_lock);
            24. if(cls&&kset_get(&cls->kset)){
            25. list_add_tail(&drv->entry,&cls->drivers);/*將設(shè)備驅(qū)動(dòng)添加到系統(tǒng)設(shè)備類的鏈表中*/
            26. /*Ifdevicesofthisclassalreadyexist,tellthedriver*/
            27. if(drv->add){
            28. structsys_device*dev;
            29. list_for_each_entry(dev,&cls->kset.list,kobj.entry)
            30. drv->add(dev);
            31. }
            32. }else{
            33. err=-EINVAL;
            34. WARN(1,KERN_ERR"%s:invaliddeviceclassn",__func__);
            35. }
            36. mutex_unlock(&sysdev_drivers_lock);
            37. returnerr;
            38. }
            在./arch/arm/mach-s3c2440/s3c2440.c中定義s3c2440的系統(tǒng)設(shè)備和注冊(cè)

            1. staticstructsys_devices3c2440_sysdev={
            2. .cls=&s3c2440_sysclass,/*定義系統(tǒng)設(shè)備的所屬系統(tǒng)設(shè)備類,用于系統(tǒng)設(shè)備注冊(cè)到指定設(shè)備類*/
            3. };
            4. /*S3C2440初始化*/
            5. int__inits3c2440_init(void)
            6. {
            7. printk("S3C2440:Initialisingarchitecturen");
            8. s3c24xx_gpiocfg_default.set_pull=s3c_gpio_setpull_1up;
            9. s3c24xx_gpiocfg_default.get_pull=s3c_gpio_getpull_1up;
            10. /*changeirqforwatchdog*/
            11. s3c_device_wdt.resource[1].start=IRQ_S3C2440_WDT;
            12. s3c_device_wdt.resource[1].end=IRQ_S3C2440_WDT;
            13. /*registeroursystemdeviceforeverythingelse*/
            14. returnsysdev_register(&s3c2440_sysdev);/*注冊(cè)s3c2440的系統(tǒng)設(shè)備*/
            15. }
            接下來(lái)是系統(tǒng)設(shè)備的注冊(cè)函數(shù)


            1. /**
            2. *sysdev_register-addasystemdevicetothetree
            3. *@sysdev:deviceinquestion
            4. *
            5. */
            6. /*系統(tǒng)設(shè)備的注冊(cè)*/
            7. intsysdev_register(structsys_device*sysdev)
            8. {
            9. interror;
            10. structsysdev_class*cls=sysdev->cls;/*所屬的系統(tǒng)設(shè)備類*/
            11. if(!cls)
            12. return-EINVAL;
            13. pr_debug("Registeringsysdeviceofclass%sn",
            14. kobject_name(&cls->kset.kobj));
            15. /*initializethekobjectto0,incaseithadpreviouslybeenused*/
            16. memset(&sysdev->kobj,0x00,sizeof(structkobject));
            17. /*Makesuretheksetisset*/
            18. sysdev->kobj.kset=&cls->kset;
            19. /*Registertheobject*/
            20. error=kobject_init_and_add(&sysdev->kobj,&ktype_sysdev,NULL,
            21. "%s%d",kobject_name(&cls->kset.kobj),
            22. sysdev->id);
            23. if(!error){
            24. structsysdev_driver*drv;
            25. pr_debug("Registeringsysdevice%sn",
            26. kobject_name(&sysdev->kobj));
            27. mutex_lock(&sysdev_drivers_lock);
            28. /*Genericnotificationisimplicit,becauseitsthat
            29. *codethatshouldhavecalledus.
            30. */
            31. /*Notifyclassauxillarydrivers*/
            32. list_for_each_entry(drv,&cls->drivers,entry){
            33. if(drv->add)
            34. drv->add(sysdev);/*遍歷該設(shè)備所屬同一個(gè)設(shè)備類的所有設(shè)備,并執(zhí)行相應(yīng)的add函數(shù)*/
            35. }
            36. mutex_unlock(&sysdev_drivers_lock);
            37. kobject_uevent(&sysdev->kobj,KOBJ_ADD);
            38. }
            39. returnerror;
            40. }
            那DMA系統(tǒng)設(shè)備驅(qū)動(dòng)中的add函數(shù)中到底是什么呢?

            (1)首先看第一個(gè)函數(shù)int __init s3c2410_dma_init(void),在./arch/arm/plat-s3c24xx/dma.c

            [cpp]view plaincopy
            1. int__inits3c2410_dma_init(void)
            2. {
            3. returns3c24xx_dma_init(4,IRQ_DMA0,0x40);
            4. }
            實(shí)際上就是初始化DMA為4通道,設(shè)置中斷號(hào),設(shè)置寄存器的覆蓋范圍

            下面是該函數(shù)的實(shí)現(xiàn)

            1. int__inits3c24xx_dma_init(unsignedintchannels,unsignedintirq,
            2. unsignedintstride)/*參數(shù)分別為通道個(gè)數(shù)、中斷號(hào)、寄存器的覆蓋范圍*/
            3. {
            4. structs3c2410_dma_chan*cp;/*通道的結(jié)構(gòu)體表示*/
            5. intchannel;
            6. intret;
            7. printk("S3C24XXDMADriver,Copyright2003-2006SimtecElectronicsn");
            8. dma_channels=channels;
            9. dma_base=ioremap(S3C24XX_PA_DMA,stride*channels);
            10. if(dma_base==NULL){
            11. printk(KERN_ERR"dmafailedtoremapregisterblockn");
            12. return-ENOMEM;
            13. }
            14. /*分配DMA告訴緩沖區(qū)*/
            15. dma_kmem=kmem_cache_create("dma_desc",
            16. sizeof(structs3c2410_dma_buf),0,
            17. SLAB_HWCACHE_ALIGN,
            18. s3c2410_dma_cache_ctor);
            19. if(dma_kmem==NULL){
            20. printk(KERN_ERR"dmafailedtomakekmemcachen");
            21. ret=-ENOMEM;
            22. gotoerr;
            23. }
            24. for(channel=0;channel
            25. cp=&s3c2410_chans[channel];
            26. memset(cp,0,sizeof(structs3c2410_dma_chan));
            27. /*dmachannelirqsareinorder..*/
            28. cp->number=channel;
            29. cp->irq=channel+irq;
            30. cp->regs=dma_base+(channel*stride);
            31. /*pointcurrentstatssomewhere*/
            32. cp->stats=&cp->stats_store;
            33. cp->stats_store.timeout_shortest=LONG_MAX;
            34. /*basicchannelconfiguration*/
            35. cp->load_timeout=1<<18;
            36. printk("DMAchannel%dat%p,irq%dn",
            37. cp->number,cp->regs,cp->irq);
            38. }
            39. return0;
            40. /*異常處理*/
            41. err:
            42. kmem_cache_destroy(dma_kmem);
            43. iounmap(dma_base);
            44. dma_base=NULL;
            45. returnret;
            46. }

            (2)然后是函數(shù)s3c24xx_dma_order_set(&s3c2440_dma_order);

            1. int__inits3c24xx_dma_order_set(structs3c24xx_dma_order*ord)
            2. {
            3. structs3c24xx_dma_order*nord=dma_order;
            4. if(nord==NULL)
            5. nord=kmalloc(sizeof(structs3c24xx_dma_order),GFP_KERNEL);
            6. if(nord==NULL){
            7. printk(KERN_ERR"nomemorytostoredmachannelordern");
            8. return-ENOMEM;
            9. }
            10. dma_order=nord;
            11. memcpy(nord,ord,sizeof(structs3c24xx_dma_order));
            12. return0;
            13. }
            我們注意到函數(shù)中使用了kmalloc給結(jié)構(gòu)體重新分配了內(nèi)存,這是由于__initdata修飾的變量表示初始化用的變量,初始化完畢后空間自動(dòng)釋放,所以需要將其存儲(chǔ)起來(lái)。

            (3)最后一個(gè)函數(shù)s3c24xx_dma_init_map(&s3c2440_dma_sel)

            該函數(shù)功能是建立DMA源與硬件通道的映射圖

            1. int__inits3c24xx_dma_init_map(structs3c24xx_dma_selection*sel)
            2. {
            3. structs3c24xx_dma_map*nmap;
            4. size_tmap_sz=sizeof(*nmap)*sel->map_size;
            5. intptr;
            6. nmap=kmalloc(map_sz,GFP_KERNEL);
            7. if(nmap==NULL)
            8. return-ENOMEM;
            9. memcpy(nmap,sel->map,map_sz);
            10. memcpy(&dma_sel,sel,sizeof(*sel));
            11. dma_sel.map=nmap;
            12. for(ptr=0;ptrmap_size;ptr++)
            13. s3c24xx_dma_check_entry(nmap+ptr,ptr);
            14. return0;
            15. }
            這里的kmalloc函數(shù)的作用同上面的作用一樣。

            注:由于內(nèi)核實(shí)在是太深了,這里只是表面上按流程大體了解了子同設(shè)備的注冊(cè)和系統(tǒng)設(shè)備驅(qū)動(dòng)的注冊(cè)以及DMA設(shè)備的注冊(cè)和初始化,函數(shù)中有很多細(xì)節(jié)有待進(jìn)一步研究。



            評(píng)論


            相關(guān)推薦

            技術(shù)專區(qū)

            關(guān)閉