<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

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

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

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

          內(nèi)核版本:2.6.35

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

          主機平臺:Ubuntu 11.04

          內(nèi)核版本:2.6.39

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

          2、在正式分析DMA驅(qū)動之前,我們先來看一下DMA的注冊和初始化過程

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

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

          定義系統(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. };
          注冊系統(tǒng)設(shè)備類,在真正注冊設(shè)備之前,確保已經(jīng)注冊了初始化了的系統(tǒng)設(shè)備類


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

          下面就是系統(tǒng)設(shè)備類的注冊函數(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ū)動*/
          2. staticstructsysdev_drivers3c2440_dma_driver={
          3. .add=s3c2440_dma_add,/*添加add函數(shù)*/
          4. };
          下面是add函數(shù),就是調(diào)用三個函數(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. }
          注冊DMA驅(qū)動到系統(tǒng)設(shè)備

          1. staticint__inits3c2440_dma_init(void)
          2. {
          3. returnsysdev_driver_register(&s3c2440_sysclass,&s3c2440_dma_driver);
          4. }
          下面就是系統(tǒng)設(shè)備驅(qū)動的注冊函數(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ū)動添加到系統(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è)備和注冊

          1. staticstructsys_devices3c2440_sysdev={
          2. .cls=&s3c2440_sysclass,/*定義系統(tǒng)設(shè)備的所屬系統(tǒng)設(shè)備類,用于系統(tǒng)設(shè)備注冊到指定設(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);/*注冊s3c2440的系統(tǒng)設(shè)備*/
          15. }
          接下來是系統(tǒng)設(shè)備的注冊函數(shù)


          1. /**
          2. *sysdev_register-addasystemdevicetothetree
          3. *@sysdev:deviceinquestion
          4. *
          5. */
          6. /*系統(tǒng)設(shè)備的注冊*/
          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è)備所屬同一個設(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ū)動中的add函數(shù)中到底是什么呢?

          (1)首先看第一個函數(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. }
          實際上就是初始化DMA為4通道,設(shè)置中斷號,設(shè)置寄存器的覆蓋范圍

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

          1. int__inits3c24xx_dma_init(unsignedintchannels,unsignedintirq,
          2. unsignedintstride)/*參數(shù)分別為通道個數(shù)、中斷號、寄存器的覆蓋范圍*/
          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修飾的變量表示初始化用的變量,初始化完畢后空間自動釋放,所以需要將其存儲起來。

          (3)最后一個函數(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è)備的注冊和系統(tǒng)設(shè)備驅(qū)動的注冊以及DMA設(shè)備的注冊和初始化,函數(shù)中有很多細節(jié)有待進一步研究。



          評論


          相關(guān)推薦

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

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();