ARM-Linux驅(qū)動--DMA驅(qū)動分析(一)
內(nèi)核版本:2.6.35
本文引用地址:http://m.butianyuan.cn/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中
- /*定義系統(tǒng)設(shè)備類*/
- structsysdev_classs3c2440_sysclass={
- .name="s3c2440-core",
- .suspend=s3c244x_suspend,
- .resume=s3c244x_resume
- };
- staticint__inits3c2440_core_init(void)
- {
- returnsysdev_class_register(&s3c2440_sysclass);
- }
下面就是系統(tǒng)設(shè)備類的注冊函數(shù),在./drivers/base/sys.c中
- intsysdev_class_register(structsysdev_class*cls)
- {
- intretval;
- pr_debug("Registeringsysdevclass%sn",cls->name);
- INIT_LIST_HEAD(&cls->drivers);
- memset(&cls->kset.kobj,0x00,sizeof(structkobject));
- cls->kset.kobj.parent=&system_kset->kobj;
- cls->kset.kobj.ktype=&ktype_sysdev_class;
- cls->kset.kobj.kset=system_kset;
- retval=kobject_set_name(&cls->kset.kobj,"%s",cls->name);
- if(retval)
- returnretval;
- retval=kset_register(&cls->kset);
- if(!retval&&cls->attrs)
- retval=sysfs_create_files(&cls->kset.kobj,
- (conststructattribute**)cls->attrs);
- returnretval;
- }
- /*定義DMA系統(tǒng)設(shè)備驅(qū)動*/
- staticstructsysdev_drivers3c2440_dma_driver={
- .add=s3c2440_dma_add,/*添加add函數(shù)*/
- };
- staticint__inits3c2440_dma_add(structsys_device*sysdev)
- {
- s3c2410_dma_init();
- s3c24xx_dma_order_set(&s3c2440_dma_order);
- returns3c24xx_dma_init_map(&s3c2440_dma_sel);
- }
- staticint__inits3c2440_dma_init(void)
- {
- returnsysdev_driver_register(&s3c2440_sysclass,&s3c2440_dma_driver);
- }
- /**
- *sysdev_driver_register-Registerauxillarydriver
- *@cls:Deviceclassdriverbelongsto.
- *@drv:Driver.
- *
- *@drvisinsertedinto@cls->driverstobe
- *calledoneachoperationondevicesofthatclass.Therefcount
- *of@clsisincremented.
- */
- intsysdev_driver_register(structsysdev_class*cls,structsysdev_driver*drv)
- {
- interr=0;
- if(!cls){
- WARN(1,KERN_WARNING"sysdev:invalidclasspassedto"
- "sysdev_driver_register!n");
- return-EINVAL;
- }
- /*Checkwhetherthisdriverhasalreadybeenaddedtoaclass.*/
- if(drv->entry.next&&!list_empty(&drv->entry))
- WARN(1,KERN_WARNING"sysdev:class%s:driver(%p)hasalready"
- "beenregisteredtoaclass,somethingiswrong,but"
- "willforgeon!n",cls->name,drv);
- mutex_lock(&sysdev_drivers_lock);
- if(cls&&kset_get(&cls->kset)){
- list_add_tail(&drv->entry,&cls->drivers);/*將設(shè)備驅(qū)動添加到系統(tǒng)設(shè)備類的鏈表中*/
- /*Ifdevicesofthisclassalreadyexist,tellthedriver*/
- if(drv->add){
- structsys_device*dev;
- list_for_each_entry(dev,&cls->kset.list,kobj.entry)
- drv->add(dev);
- }
- }else{
- err=-EINVAL;
- WARN(1,KERN_ERR"%s:invaliddeviceclassn",__func__);
- }
- mutex_unlock(&sysdev_drivers_lock);
- returnerr;
- }
- staticstructsys_devices3c2440_sysdev={
- .cls=&s3c2440_sysclass,/*定義系統(tǒng)設(shè)備的所屬系統(tǒng)設(shè)備類,用于系統(tǒng)設(shè)備注冊到指定設(shè)備類*/
- };
- /*S3C2440初始化*/
- int__inits3c2440_init(void)
- {
- printk("S3C2440:Initialisingarchitecturen");
- s3c24xx_gpiocfg_default.set_pull=s3c_gpio_setpull_1up;
- s3c24xx_gpiocfg_default.get_pull=s3c_gpio_getpull_1up;
- /*changeirqforwatchdog*/
- s3c_device_wdt.resource[1].start=IRQ_S3C2440_WDT;
- s3c_device_wdt.resource[1].end=IRQ_S3C2440_WDT;
- /*registeroursystemdeviceforeverythingelse*/
- returnsysdev_register(&s3c2440_sysdev);/*注冊s3c2440的系統(tǒng)設(shè)備*/
- }
- /**
- *sysdev_register-addasystemdevicetothetree
- *@sysdev:deviceinquestion
- *
- */
- /*系統(tǒng)設(shè)備的注冊*/
- intsysdev_register(structsys_device*sysdev)
- {
- interror;
- structsysdev_class*cls=sysdev->cls;/*所屬的系統(tǒng)設(shè)備類*/
- if(!cls)
- return-EINVAL;
- pr_debug("Registeringsysdeviceofclass%sn",
- kobject_name(&cls->kset.kobj));
- /*initializethekobjectto0,incaseithadpreviouslybeenused*/
- memset(&sysdev->kobj,0x00,sizeof(structkobject));
- /*Makesuretheksetisset*/
- sysdev->kobj.kset=&cls->kset;
- /*Registertheobject*/
- error=kobject_init_and_add(&sysdev->kobj,&ktype_sysdev,NULL,
- "%s%d",kobject_name(&cls->kset.kobj),
- sysdev->id);
- if(!error){
- structsysdev_driver*drv;
- pr_debug("Registeringsysdevice%sn",
- kobject_name(&sysdev->kobj));
- mutex_lock(&sysdev_drivers_lock);
- /*Genericnotificationisimplicit,becauseitsthat
- *codethatshouldhavecalledus.
- */
- /*Notifyclassauxillarydrivers*/
- list_for_each_entry(drv,&cls->drivers,entry){
- if(drv->add)
- drv->add(sysdev);/*遍歷該設(shè)備所屬同一個設(shè)備類的所有設(shè)備,并執(zhí)行相應的add函數(shù)*/
- }
- mutex_unlock(&sysdev_drivers_lock);
- kobject_uevent(&sysdev->kobj,KOBJ_ADD);
- }
- returnerror;
- }
(1)首先看第一個函數(shù)int __init s3c2410_dma_init(void),在./arch/arm/plat-s3c24xx/dma.c
- int__inits3c2410_dma_init(void)
- {
- returns3c24xx_dma_init(4,IRQ_DMA0,0x40);
- }
下面是該函數(shù)的實現(xiàn)
- int__inits3c24xx_dma_init(unsignedintchannels,unsignedintirq,
- unsignedintstride)/*參數(shù)分別為通道個數(shù)、中斷號、寄存器的覆蓋范圍*/
- {
- structs3c2410_dma_chan*cp;/*通道的結(jié)構(gòu)體表示*/
- intchannel;
- intret;
- printk("S3C24XXDMADriver,Copyright2003-2006SimtecElectronicsn");
- dma_channels=channels;
- dma_base=ioremap(S3C24XX_PA_DMA,stride*channels);
- if(dma_base==NULL){
- printk(KERN_ERR"dmafailedtoremapregisterblockn");
- return-ENOMEM;
- }
- /*分配DMA告訴緩沖區(qū)*/
- dma_kmem=kmem_cache_create("dma_desc",
- sizeof(structs3c2410_dma_buf),0,
- SLAB_HWCACHE_ALIGN,
- s3c2410_dma_cache_ctor);
- if(dma_kmem==NULL){
- printk(KERN_ERR"dmafailedtomakekmemcachen");
- ret=-ENOMEM;
- gotoerr;
- }
- for(channel=0;channel
- cp=&s3c2410_chans[channel];
- memset(cp,0,sizeof(structs3c2410_dma_chan));
- /*dmachannelirqsareinorder..*/
- cp->number=channel;
- cp->irq=channel+irq;
- cp->regs=dma_base+(channel*stride);
- /*pointcurrentstatssomewhere*/
- cp->stats=&cp->stats_store;
- cp->stats_store.timeout_shortest=LONG_MAX;
- /*basicchannelconfiguration*/
- cp->load_timeout=1<<18;
- printk("DMAchannel%dat%p,irq%dn",
- cp->number,cp->regs,cp->irq);
- }
- return0;
- /*異常處理*/
- err:
- kmem_cache_destroy(dma_kmem);
- iounmap(dma_base);
- dma_base=NULL;
- returnret;
- }
(2)然后是函數(shù)s3c24xx_dma_order_set(&s3c2440_dma_order);
- int__inits3c24xx_dma_order_set(structs3c24xx_dma_order*ord)
- {
- structs3c24xx_dma_order*nord=dma_order;
- if(nord==NULL)
- nord=kmalloc(sizeof(structs3c24xx_dma_order),GFP_KERNEL);
- if(nord==NULL){
- printk(KERN_ERR"nomemorytostoredmachannelordern");
- return-ENOMEM;
- }
- dma_order=nord;
- memcpy(nord,ord,sizeof(structs3c24xx_dma_order));
- return0;
- }
(3)最后一個函數(shù)s3c24xx_dma_init_map(&s3c2440_dma_sel)
該函數(shù)功能是建立DMA源與硬件通道的映射圖
- int__inits3c24xx_dma_init_map(structs3c24xx_dma_selection*sel)
- {
- structs3c24xx_dma_map*nmap;
- size_tmap_sz=sizeof(*nmap)*sel->map_size;
- intptr;
- nmap=kmalloc(map_sz,GFP_KERNEL);
- if(nmap==NULL)
- return-ENOMEM;
- memcpy(nmap,sel->map,map_sz);
- memcpy(&dma_sel,sel,sizeof(*sel));
- dma_sel.map=nmap;
- for(ptr=0;ptr
map_size;ptr++) - s3c24xx_dma_check_entry(nmap+ptr,ptr);
- return0;
- }
注:由于內(nèi)核實在是太深了,這里只是表面上按流程大體了解了子同設(shè)備的注冊和系統(tǒng)設(shè)備驅(qū)動的注冊以及DMA設(shè)備的注冊和初始化,函數(shù)中有很多細節(jié)有待進一步研究。
評論