澳门新葡8455最新网站
澳门新葡8455最新网站[www.8455.com]
取消
N物理农业
您所在的位置是:澳门新葡8455最新网站 > 物理农业 >
N物理农业
您所在的位置是:澳门新葡8455最新网站 > 物理农业 >

分配释放DMA缓冲区,大医院当然好

发布时间:2019-12-26 16:05    浏览次数 :

     

  自微信普及以来,我们很幸运,能够通过微信学习群学习最新最前沿的医学知识,它们来自于国外,来自于国内一流医院的主任,教授,专家们。

DMA(Direct Memory Access)

图片 1

  这样的学习与培训,对于每一位医务工作者,尤其是县级,或者县级以下的乡镇卫生院每一位医生,都是相当宝贵的学习机会。

即直接存储器访问, DMA 传输方式无需 CPU 直接控制传输,通过硬件为 RAM 、I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。

        丁酉仲春,时和气清。衡水湖畔,植四泽之芳草,汇八隅之佳木,亭榭绕以绿蕙,廊台缀以青蓠。园林之盛景,铺排锦绣;博苑之蓝图,气势恢宏。余感园林博览之盛事,抒乡梓康裕之胸臆,怀古颂今,遂作此赋。其词曰:

  经常会听到患者,或者医生本人埋怨哪个医院如何不好,用一个难堪的词语“很垃圾”,须不知,逞口舌之快容易。可是你究竟知不知道,中国是个人口大国,也是农业大国,15亿人口,超过8亿是农民。


      古郡千载,沐衡漳①之福泽;湖城日新,呈平野之膏腴。禹建冀州,雄踞九州之冠首;秦封钜鹿,势成兵家之锁钥。齐赐乐毅之食邑,赵筑简子之池城,汉尊董子之儒术,世颂毛苌之诗经,可谓云衢通天,风水衡存,文脉厚重,物阜民丰。

    诚然,我们国家有大医院,也有小医院,尤其是贫穷落后的山区至今缺医少药。大医院当然好,有一流的设备,一流的人才,一流的技术与服务。

 

图片 2

可是大医院的医疗资源毕竟是有限的。不是每个患者都能有此幸运,有机会,有足够的经济能力,能够进大医院,更可悲的,多少生命等不及去大医院排队,就死在等待的路上。

学了这么多驱动,不难推出DMA的编写套路:

董子园

  你最看不起的“垃圾”小乡镇,或者县级医院,关键时候却能救你的命。每个医院,每个人的起点不一样,能力有大小之分,可是你要看到,小医院也在逐渐发展,水平在逐渐提高,我们也在不断提升与进步。

  • 1)注册DMA中断,分配缓冲区
  • 2)注册字符设备,并提供文件操作集合fops
  •   -> 2.1)file_operations里设置DMA硬件相关操作,来启动DMA

      善哉衡水!钟灵毓秀,名贤辈出,立功立德,名垂不朽。美人钩弋,养育一代君主;窦氏漪房,辅佐三朝帝王;博陵崔姓②,开创儒家文林;蓨县高门,尽出社稷栋梁。三张④才高,文材郁茂,庭生芝草,门楣光耀;崔家天幸,才俊辈出,蟾宫折桂,雁塔名标。辑柳写经,孙敬⑤系发悬梁;关山戎马,高适诗意铿锵。更有煌煌巨著,经史典籍,彰人性之崇德,显文心之尚义,弘圣贤之达道,扬醒世之臻理。若夫《四民月令》⑥,集农技之大成;《五经正义》⑦,平儒学之纷争;《太平御览》⑧,竟成类书之冠;《中山狼传》⑨,激扬刺贪之风。

  医院再小,医生的能力不能与大医院的专家教授相提并论,可是我们同样有一颗仁心,同样有作为一名医者基本的情怀,我们也在进步,在努力,希望日后为您解除更多病痛,提供更优质规范的服务。

由于我们是用字符设备的测试方法测试的,而本例子只是用两个地址之间的拷贝来演示DMA的作用,所以采用字符设备方式编写

图片 3

  医学是人文学科,不可以和商业性质的职业相提并论。这并不是一个付出与收入能够成正比的职业。如果你想要更多的钱,不要学医,因为它不可能直接提供你更多的钱。假如同样多的精力你用来投资生意,或许早已是家财万贯。然而,医学却是不能以此来论的,因为患者的生命本身就是无价的。因此,我觉得医学是高尚的,作为一名医者也是骄傲与光荣的。

 

衡水中学

  作为一名县级医院的医者,我知道我自己非常不足,可是我们也在努力,我知道自己解决不了你的问题,可是我希望自己至少能告诉你,你该去哪里,哪里能救得了你,我不能提供你直接的帮助与服务,可是请相信我,至少我不会害你。

1.驱动编写之前,先来讲如何分配释放缓冲区、DMA相关寄存器介绍、使用DMA中断

京南之地,首善之区,蔚兴英杰之豪气,长传道德之薪火。李洛能⑩,武林之泰斗,形随意动,开门立派;荀慧生,梨园之奇葩,玉质冰心,几度梅开。英雄仲韬⑪,点燃台城星火;平原枪声,奏响抗日战歌;上校村官,赤心长系乡梓;好人秀贞,大爱感动中国。呜呼,碧血昭于苍穹,丹心泽于子孙,节义兮承传,守正兮出新!

1.1在linux中,分配释放DMA缓冲区,只能使用以下几个函数

图片 4

1) 

衡水湖

/*该函数只禁止cache缓冲,保持写缓冲区,也就是对注册的物理区写入数据,也会更新到对应的虚拟缓存区上*/
void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp); 
//分配DMA缓存区
//返回值为:申请到的DMA缓冲区的虚拟地址,若为NULL,表示分配失败,需要释放,避免内存泄漏
//参数如下:
  //*dev:指针,这里填0,表示这个申请的缓冲区里没有内容
  //size:分配的地址大小(字节单位)
  //*handle:申请到的物理起始地址
  //gfp:分配出来的内存参数,标志定义在<linux/gfp.h>,常用标志如下:
        //GFP_ATOMIC    用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.
        //GFP_KERNEL    内核内存的正常分配. 可能睡眠.
      //GFP_USER      用来为用户空间页来分配内存; 它可能睡眠. 

图片 5

 

衡水湖晚景

2)

        美哉衡水! 滨湖宜居,生态湖城,文化旅游,异军突起。窦氏青山,高峻崔巍,耸佳人之孝,千载不朽;圣姑高台⑫,庙宇俨然,表先贤之义,百代犹存;宝云古寺,香火鼎盛,撞祈福之钟,声震天地;安济老桥,虹跨滏阳,引清源之水,激荡古今。三塔三墓⑬,列为国保,后世瞻仰,古柏风涛。一河一湖,同做市标,今人游览,水色妖娆。若夫一枝吐艳,百里芳菲,桃之夭夭,香馥遍野;一湖凝碧,千顷潋滟,鱼跃鸟飞,生机盎然。观夫年画色巧,广贴千门;烟壶玲珑,内蕴乾坤;黑陶朴拙,塑成大器;管弦清越,合奏金音。更有侯店毛笔,紫竹狼毫,书写寒来暑往;宫廷金鱼,凤尾龙睛,见证河清海晏;白干老酒,百年佳酿,香飘十八酒坊。呜呼,紫气起于冀南,虹霓跨于滨湖,清风兮拂面,诗画兮舒展!

/*该函数禁止cache缓存以及禁止写入缓冲区*/
void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);         
//分配DMA缓存区,返回值和参数和上面的函数一直

图片 6

 

景州塔

 3)

      壮哉衡水! 欣逢盛世,喜看今朝,桃城宝地,旧颜新貌。交通便利,产业云集,乘风破浪,负重崛起。京九石德,巨龙交错,铸就黄金十字;大广高速,银蛇逶迤,纵贯大江南北;银鹰筑巢⑭,凤鸟振翼,夔蛟摆尾⑮,白鹿奋蹄,百灵兮倏至,万民兮聚力;炼乳为胶,成就行业品牌;集腋成裘,皮衣远销海外;五金结网,广络天下财富;镔铁垒塔,屹立华夏风采。更有沃野广袤,黍稷沉穗,棉麦丰裕;名牌教育,广育英才,九州扬誉。呜呼,云气荫于湿地,霞光耀于平原,嘉宾兮咸聚,光华兮灿然!

dma_free_writecombine(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle);   //释放DMA缓存,与dma_alloc_writecombine()对应
//size:释放长度
//cpu_addr:虚拟地址,
//handle:物理地址

图片 7

 

衡水文化艺术中心

 4)

        乱⑯曰:横漳之福地兮,崇德尚义;滨湖之百业兮,日新月异;衡水之俊彦兮,同心戮力;生态之崛起兮,歌以献礼。

dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)    //释放DMA缓存,与dma_alloc_coherent ()对应
//size:释放长度
//cpu_addr:虚拟地址,
//handle:物理地址

注释:

 

①衡漳--北魏文成帝拓跋浚《南巡碑》中首提“衡水之滨”。“衡水”是河流的名字,也就是当时穿越漳河后一段的别称,又名“衡漳”或“横漳”。

 (PS: dma_free_writecombine()其实就是dma_free_conherent(),只不过是用了#define重命名而已。)

②博陵崔氏--东汉跻身名门,北齐北周时期全面上升,成为一流士族。在隋唐时曾尊为五姓七望之一的名门望族。在唐朝,博陵崔氏一共诞生了15位宰相。东汉时期,崔骃及子崔瑗、孙崔寔皆有文名,合称“三崔”。《后汉书·崔骃列传》“崔氏世有美才,兼以沉沦典籍,遂为儒家文林”

而我们之前用的内存分配kmalloc()函数,是不能用在DMA上,因为分配出来的内存可能在物理地址上是不连续的.

③蓨县高门--北齐高祖高欢,原籍渤海蓨县(今河北景县),东魏权臣,北齐王朝奠基人,史称齐神武帝。其子高洋公元550年登上帝位,改国号为“齐”,建都邺城(今河北省临漳县),史称北齐。北齐高氏皇族有尚武传统。史料记载“北齐皇族高氏是人尽为将,人人都是将军,人人都能带兵交兵。”。

 

④三张--西晋文学家张载和弟弟张协、张亢都以文学著名,时称“三张”,三人皆为武邑人。

1.2 那么2440开发板如何来启动DMA,先来看2440的DMA寄存器

⑤孙敬--汉朝信都(今冀州市)人,东汉著名政治家,纵横家,成语“悬梁刺股”中“悬梁”的主人公。东汉·班固《汉书》:“孙敬字文宝,好学,晨夕不休。及至眠睡疲寝,以绳系头,悬屋梁。后为当世大儒。”

(PS:实际这些DMA相关的寄存器,在linux内核中三星已封装好了,可以直接调用,不过非常麻烦,还不如直接设置寄存器,可以参考: http://blog.csdn.net/mirkerson/article/details/6632273)

⑥《四民月令》--东汉政论家崔寔模仿古时月令所著的农业著作,是东汉后期叙述一年例行农事活动的专书,描述古代中国社会地主阶层的农业运作,书中提及的经济运作,亦为中国经济史研究提供第一手资料。

1.2.1 2440支持4个通道的DMA控制器

⑦《五经正义》--唐太宗时,冀州衡水籍著名经学家、教育家孔颖达奉旨召集当时一些著名儒士共同撰修《五经正义》,贞观十六年(642)编成。汉末以来,长期变乱,儒家典籍散佚,文理乖错,且师说多门,章句杂乱,为适应科举取士和维护全国政治统一的需要,《五经正义》应时而出,以求结束儒学内部宗派的纷争,为古代经学发展史的重要环节。《五经正义》现存《十三经注疏》中,流传版本以影印阮刻《十三经注疏》本为佳。

其中4个通道的DMA外设请求源,如下图所示(通过DCONn寄存器的[26:24]来设置)

⑧《太平御览》--中国百科全书性质的类书,北宋四大部书之一。翰林学世李昉(饶阳籍)奉诏主纂,全书1000卷,分55部,引用古今图书及各种体裁文章共2579种,与同时编纂的史学类书《册府元龟》,文学类书《文苑英华》和小说类书《太平广记》合称为“宋四大书”。四部书中,《太平御览》编得最早。它是一部综合性类书,门类繁多,征引赅博,在类书中堪称“空前”,被视为“类书之冠”。

(PS:如果请求源是系统总线上的,就只需要设置DCONn寄存器的[23]=0即可)

⑨《中山狼传》--《中山狼传》是明代马中锡的一篇寓言故事,出自马中锡的《东田集》。马中锡,字天禄,明代故城(属河北省)人。1475年(成化十一年)进士。明武宗朱厚照在位时(1506—1521),曾任兵部侍郎,因为对太监刘瑾作斗争,被逮捕下狱。

图片 8

⑩李洛能--李洛能,著名武术家,近代形意拳宗师,生于河北省深县,名飞羽,字能然,当年世称老能先生。由于武艺高强,又有神拳李之威名,著有《形意拳谱》。李洛能在咸丰、同治年间,与八卦拳之董海川,太极拳之杨露禅,鼎足而三,为心意拳、八卦拳、太极拳武术之领袖,威震武林。

 

⑪英雄仲韬--河北省安平县人,1916年考入北京法政大学,1919年参加五四运动。1923年4月由李大钊介绍加入中国共产党,并受李大钊派遣回原籍传播马列主义,1923年8月发起成立了“中共安平县台城特别支部”(简称“台城特支”),直接受中共北京区委领导,这是中国共产党第一个农村党支部。

1.2.2 且每个通道都可以处理以下4种情况:

⑫圣姑高台--圣姑庙相传是汉光武帝修建,是方圆百里最大的庙宇建筑。元代大德十年(公元1306年)在原庙东侧筑高台重建,明、清两代多次扩建而成。据史料记载,“燕赵齐鲁之民,虽千百里之远,致香火者如织”。1945年5月,该庙在抗日战火中遭到毁坏。2012年重新修复,相传圣姑,字女君,为周代末的安平县会沃村人氏,以其智救汉光武帝刘秀和侍奉父母终生不嫁被传颂为忠孝双全的女圣人。

1) 源和目标都在系统总线上(比如:两个物理内存地址)
2) 当目标在外设总线上时,源在系统总线上(外设指:串口,定时器,I2C,I2S等)
3) 当目标在系统总线上时,源在外设总线上
4) 源和目标都在外设总线上

⑬三塔三墓--衡水境内的6处全国重点文物保护单位。“三塔”指的是宝云寺宝云塔、开福寺舍利塔、庆林寺塔;“三墓”指的是北齐高氏墓群、北魏至隋封氏墓群、逯家庄汉代壁画墓。

 

⑭银鹰筑巢--衡水机场位于河北省衡水市故城县里老乡,现为北京军区军用机场,曾担任过多次国家级军事任务,但由于其独特的地理位置,一直是河北省衡水市与山东省德州市重点民航建设的项目之一。2017年规划建设冀州、安平、景县、枣强通用机场。

1.2.3 DMA有两种工作模式(通过DCONn寄存器的[28]来设置)

⑮夔蛟摆尾--京九高铁衡水段规划建设,于2017年开工。

查询模式:

  ⑯乱曰--《康熙字典》解释:”乐之卒章曰乱“,“古赋末皆有乱,总一赋之终,发其要指也”。也就是说,“乱曰”是乐章的结尾部分,是对这篇赋辞的总体概括。       

当DMA请求XnXDREQ为低电平时,则DMA会一直传输数据,直到DMA请求拉高,才停止

握手模式:

当DMA请求XnXDREQ有下降沿触发时,则DMA会传输一次数据

 图片 9

 

1.2.4 DMA有两种传输模式(通过DCONn寄存器的[31]来设置)

单元传输:

指传输过程中,每执行一次,则读1次,写1次.(如上图所示)

突发4传输:

指传输过程中,每执行一次,则读4次,然后写4次(如下图所示)

 图片 10

 

1.2.5 2440中的DMA寄存器如下图所示:

 图片 11

 

共有4个通道的寄存器,且每个通道的寄存器内容都一致,所以我们以DMA通道0为例:

1)**DISRC0初始源寄存器 **

[30:0] : 存放DMA源的基地址

2)**DISRCC0初始源控制寄存器**

[1] : 源位置选择,0:源在系统总线上,                       1:源在外设总线上

[0] : 源地址选择,0:传输时源地址自动增加,            1:源地址固定

3)DIDST0初始目标寄存器

[30:0] : 设置DMA目的的基地址

 

4)DIDSTC0初始目标控制寄存器

[2]  : 中断时间选择,       0:当DMA传输计数=0,立即发生中断       1:执行完自动加载后再发送中断(也就是计数为0,然后重新加载计数值)

[1] : 目的位置选择,         0:目的在系统总线上,                         1:目的在外设总线上

[0] : 目的地址选择,         0:传输时目的地址自动增加,            1:目的地址固定

 

5)DCON0控制寄存器

[31] : 工作模式选择,   0:查询模式                  1:握手模式      (当源处于外设时,尽量选择握手模式)

[30] : 中断请求(DREQ)/中断回应(DACK)的同步时钟选择,        0:PCLK同步     1:HCLK同步

(PS:如果有设备在HCLK上,该位应当设为1,比如:(SDRAM)内存数组, 反之当这些设备在PCLK上,应当设为0,比如:ADC,IIS,I2C,UART)

[29] : DMA传输计数中断使能/禁止      0:禁止中断                                1:当传输完成后,产生中断

[28] : 传输模式选择,         0:单元传输                            1:突发4传输

[27] : 传输服务模式  

0:单服务模式,比如:有2个DMA请求,它们会被顺序执行一次(单元传输/突发4传输)后停止,然后直到有下一次DMA请求,再重新开始另一次循环。

1:全服务模式,指该DMA若有请求,则会占用DMA总线,一直传输,期间若有其它DMA请求,只有等待传输计数TC为0,才会执行其它DMA请求

[26:24] : DMA外设请求源选择

[23]     : 软件/硬件请求源选择      0:软件请求            1:硬件请求(还需要设置[26:24]来选择外设源)

[22]     : 重新加载开关选项             为0即可

[21:20] : 传输数据大小    为00(8位)即可

[19:0]   : 设置DMA传输的计数TC               

6)DSTAT0状态寄存器

[21:20] :      DMA状态             00:空闲           01:忙

[19:0]   : 传输计数当前值CURR_TC            为0表示传输结束

7)DCSRC0当前源寄存器

[30:0]  : 存放DMA当前的源基地址

 

8)DCDST0当前目标寄存器

[30:0]  : 存放DMA当前的目的基地址

 

9)DMASKTRIG0触发屏蔽寄存器

[2]   : 停止STOP            该位写1,立刻停止DMA当前的传输

[1]   : DMA通道使能        0:关闭DMA的通道0(禁止DMA请求)            1:开启DMA的通道0(开启DMA请求)

[0]   : 软件请求触发      1:表示启动一次软件请求DMA,只有DCONn[23]=0和DMASKTRIGn[1]=1才有效,DMA传输时,该位自动清0

1.3接下来就开始讲linux注册DMA中断

首先,DMA的每个通道只能有一个源- >目的,所以输入命令 cat /proc/interrupts ,找到DMA3中断未被使用

所以在linux中使用:

request_irq(IRQ_DMA3, s3c_dma_irq, NULL, "s3c_dma", 1);// s3c_dma_irq:中断服务函数,这里注册DMA3中断服务函数
//NULL:中断产生类型, 不需要,所以填NULL
//1:表示中断时,传入中断函数的参数,本节不需要所以填1,切记不能填0,否则注册失败

 

 

2.接下来,我们便来写一个DMA的字符设备驱动

步骤如下:

  • 1) 注册DMA中断,分配两个DMA缓冲区(源、目的)
  • 2) 注册字符设备,并提供文件操作集合fops
  • -> 2.1) 通过ioctl的cmd来判断是使用DMA启动两个地址之间的拷贝,还是直接两个地址之间的拷贝
  • -> 2.2)若是DMA启动,则设置DMA的相关硬件,并启动DMA传输

2.1 所以,驱动代码如下所示:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>   
#include <asm/irq.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/dma-mapping.h>

#define  S3C_DMA_SIZE   512*1024          //DMA传输长度   512KB

#define NORMAL_COPY     0                 //两个地址之间的正常拷贝
#define DMA_COPY        1                 //两个地址之间的DMA拷贝

/*函数声明*/
static DECLARE_WAIT_QUEUE_HEAD(s3c_dma_queue);          //声明等待队列
static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long flags);

  /*
   * 定义中断事件标志
   * 0:进入等待队列        1:退出等待队列
   */
     static int s3c_dma_even=0;


static unsigned char   *source_virt;            //源虚拟地址
static unsigned int     source_phys;            //源物理地址

static unsigned char *dest_virt;              //目的虚拟地址
static unsigned int   dest_phys;              //目的虚拟地址


/*DMA3寄存器*/
struct  S3c_dma3_regs{
    unsigned int disrc3    ;          //0x4b0000c0
    unsigned int disrcc3   ;                    
    unsigned int didst3    ;                    
    unsigned int didstc3   ;               
    unsigned int dcon3     ;                
    unsigned int dstat3    ; 
    unsigned int dcsrc3    ; 
    unsigned int dcdst3    ;        
    unsigned int dmasktrig3;        //0x4b0000e0
};


 static volatile struct S3c_dma3_regs   *s3c_dma3_regs;

/*字符设备操作*/
static struct file_operations  s3c_dma_fops={
        .owner  = THIS_MODULE,
        .ioctl     = s3c_dma_ioctl,
};

/*中断服务函数*/
static irqreturn_t  s3c_dma_irq (int irq, void *dev_id)   
{
    s3c_dma_even=1;                             //退出等待队列
    wake_up_interruptible(&s3c_dma_queue);      //唤醒 中断
    return IRQ_HANDLED;
}

/*ioctl函数*/
static int s3c_dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long flags)
{
    int i;
    memset(source_virt, 0xAA, S3C_DMA_SIZE);          
    memset(dest_virt, 0x55, S3C_DMA_SIZE);   

    switch(cmd)
    {
    case NORMAL_COPY:                           //正常拷贝

             for(i=0;i<S3C_DMA_SIZE;i++)
                 dest_virt[i] =  source_virt[i];

             if(memcmp(dest_virt, source_virt, S3C_DMA_SIZE)==0)
           {
         printk("NORMAL_COPY OKn");
                return 0;
         }
         else
        {
         printk("NORMAL_COPY ERRORn");
               return -EAGAIN;
        }             

    case DMA_COPY:                               //DMA拷贝

        s3c_dma_even=0;     //进入等待队列

        /*设置DMA寄存器,启动一次DMA传输 */
        /* 源的物理地址 */
        s3c_dma3_regs->disrc3      = source_phys;      
        /* 源位于AHB总线, 源地址递增 */  
        s3c_dma3_regs->disrcc3     = (0<<1) | (0<<0);
        /* 目的的物理地址 */
        s3c_dma3_regs->didst3      = dest_phys;      
        /* 目的位于AHB总线, 目的地址递增 */
        s3c_dma3_regs->didstc3     = (0<<2) | (0<<1) | (0<<0);     
        /* 使能中断,单个传输,软件触发, */
        s3c_dma3_regs->dcon3=(1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(S3C_DMA_SIZE<<0);  
        //启动一次DMA传输
        s3c_dma3_regs->dmasktrig3  = (1<<1) | (1<<0);     

        wait_event_interruptible(s3c_dma_queue, s3c_dma_even);    //进入睡眠,等待DMA传输中断到来才退出

        if(memcmp(dest_virt, source_virt, S3C_DMA_SIZE)==0)
        {
         printk("DMA_COPY OKn");
                return 0;
         }
        else
        {
       printk("DMA_COPY ERRORn");
             return -EAGAIN;
           }  

            break;
    }
    return 0;
}


static unsigned int major;
static struct class *cls;
static int s3c_dma_init(void)
{
    /*1.1 注册DMA3 中断  */
    if(request_irq(IRQ_DMA3, s3c_dma_irq,NULL, "s3c_dma",1)) 
    {
        printk("Can't    request_irq   "IRQ_DMA3"!!!n ");
        return -EBUSY;
    }

    /*1.2 分配两个DMA缓冲区(源、目的)*/
    source_virt=dma_alloc_writecombine(NULL,S3C_DMA_SIZE, &source_phys, GFP_KERNEL);
    if(source_virt==NULL)       
   {
        printk("Can't  dma_alloc   n ");
        return -ENOMEM;
   }

    dest_virt=dma_alloc_writecombine(NULL,S3C_DMA_SIZE, &dest_phys, GFP_KERNEL);
    if(dest_virt==NULL)       
   {
        printk("Can't  dma_alloc   n ");
        return -ENOMEM;
   }


    /*2.注册字符设备,并提供文件操作集合fops*/
    major=register_chrdev(0, "s3c_dma",&s3c_dma_fops);
    cls= class_create(THIS_MODULE, "s3c_dma");
    class_device_create(cls, NULL,MKDEV(major,0), NULL, "s3c_dma");

    s3c_dma3_regs=ioremap(0x4b0000c0, sizeof(struct S3c_dma3_regs));

    return 0;  
}

static void s3c_dma_exit(void)
{
    iounmap(s3c_dma3_regs);

    class_device_destroy(cls, MKDEV(major,0));
    class_destroy(cls);

    dma_free_writecombine(NULL, S3C_DMA_SIZE, dest_virt, dest_phys);
    dma_free_writecombine(NULL, S3C_DMA_SIZE, source_virt, source_phys);   

    free_irq(IRQ_DMA3, 1);

}
module_init(s3c_dma_init);
module_exit(s3c_dma_exit);
MODULE_LICENSE("GPL");

2.2 应用测试程序如下所示:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>

/* ./dma_test NORMAL
 * ./dma_test DMA
 */
#define NORMAL_COPY     0               //两个地址之间的正常拷贝
#define DMA_COPY        1              //两个地址之间的DMA拷贝

void print_usage(char *name)
{
    printf("Usage:n");
    printf("%s <NORMAL | DMA>n", name);
}

int main(int argc, char **argv)
{
    int fd,i=30;

     if (argc != 2)
    {
        print_usage(argv[0]);
        return -1;
    }

    fd = open("/dev/s3c_dma", O_RDWR);
    if (fd < 0)
    {
        printf("can't open /dev/s3c_dman");
        return -1;
    }

    if (strcmp(argv[1], "NORMAL") == 0)
    {
        while (i--)                //调用驱动的ioctl(),30次
        {
            ioctl(fd, NORMAL_COPY);
        }
    }
    else if (strcmp(argv[1], "DMA") == 0)
    {
        while (i--)                //调用驱动的ioctl(),30次        
        {
            ioctl(fd, DMA_COPY);
        }
    }
    else
    {
        print_usage(argv[0]);
        return -1;
    }
    return 0;     
}

3.测试运行

输入 ./dma_test NORMAL & ,使用CPU正常拷贝,可以发现占用了大部分资源,输入 ls 无反应:

 图片 12

 

输入./dma_test DMA & ,使用DMA拷贝,输入 ls 立马有反应,从而释放了CPU的压力:

 图片 13

 

 

 

 

上一篇:没有了 下一篇:没有了
友情链接