Linux DMA驱动构架分析_第1页
Linux DMA驱动构架分析_第2页
Linux DMA驱动构架分析_第3页
Linux DMA驱动构架分析_第4页
Linux DMA驱动构架分析_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Linux DMA驱动构架分析以linux2.6.32中的S3C2440驱动为例进行分析,DMA驱动所对应的源码为 linux-2.6.32.2archarmmach-s3c2440dma.c,代码入口为: arch_initcall(s3c2440_dma_init);static int _init s3c2440_dma_init(void)return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_dma_driver);DMA驱动作为系统驱动由sysdev_driver_register来向内核注册,这里只关注 s3c2440_

2、dma_driver相关的内容,即调用drive中的add方法,其他的kobject对 象略过。static struct sysdev_driver s3c2440_dma_driver = .add= s3c2440_dma_add, TOC o 1-5 h z ;s3c2440_dma_add做了一系列的初始化工作,相应的代码如下:static int _init s3c2440_dma_add(struct sys_device *sysdev)s3c2410_dma_init();s3c24xx_dma_order_set(&s3c2440_dma_order);return s3c

3、24xx_dma_init_map(&s3c2440_dma_sel);下面就其中出的三个函数一一进行分析。A.s3c2410_dma_init首先 s3c2410_dma_init()调用 了 plat-s3c24xx 平台公共的函数 s3c24xx_dma_init(4, IRQ_DMA0, 0 x40);int _init s3c24xx_dma_init(unsigned int channels, unsigned int irq,unsigned int stride)struct s3c2410_dma_chan *cp;int channel;int ret;13121313p

4、rintk(S3C24XXDMA Driver, (c) 2003-2004,2006SimtecElectronicsn);13141315dma_channels = channels;1316dma_base = ioremap(S3C24XX_PA_DMA, stride * channels);if (dma_base = NULL) printk(KERN_ERR dma failed to remap register blockn);return -ENOMEM;1322dma_kmem = kmem_cache_create(dma_desc”,sizeof(struct s

5、3c2410_dma_buf), 0,SLAB_HWCACHE_ALIGN,s3c2410_dma_cache_ctor);1327if (dma_kmem = NULL) printk(KERN_ERRdmafailedtomakekmemcachen);ret = -ENOMEM;goto err;1333for (channel = 0; channel number = channel;cp-irq = channel + irq;cp-regs = dma_base + (channel* stride);1343/* point current stats somewhere */

6、cp-stats = &cp-stats_store;cp-stats_store.timeout_shortest = LONG_MAX;13471348/* basic channel configuration */13491350cp-load_timeout = 1number, cp-regs, cp-irq);13551356return 0;1357err:kmem_cache_destroy(dma_kmem);iounmap(dma_base);dma_base = NULL;return ret;1364首先来关注一下函数传递的参数:unsigned int channe

7、ls: s3c2440 平台对应的 DMA 通道总数,为 4unsigned int irq:起始DMA中断的中断号unsigned int stride:每通道DMA所占寄存器资源数1309行struct s3c2410_dma_chan记录dma通道信息,内容如下:151 struct s3c2410_dma_chan 152/* channel state flags and information */153unsigned charnumber;/dma 通道号,154unsigned charin_use;当前通道是否已经使用155unsigned charirq_claimed;

8、 / 有无 dma 中断156unsigned charirq_enabled; /是否使能了 dma中断157unsigned charxfer_unit;传输块大小158159/* channel state */160161enum s3c2410_dma_state state;162enum s3c2410_dma_loadst load_state;163struct s3c2410_dma_client *client;164165/* channel configuration */166enum s3c2410_dmasrc source;167enum dma_chreq_

9、ch;168unsigned longdev_addr;169unsigned longload_timeout;170 unsigned int flags; /* channel flags */171 172 struct s3c24xx_dma_map *map; /* channel hw maps */173174/* channels hardware position and configuration */175void _iomem*regs;/* channels registers */176void _iomem*addr_reg; /* data address r

10、egister */177unsigned intirq;中断号178unsigned longdcon;/默认控制寄存器的值179/* driver handles */s3c2410_dma_cbfn_t callback_fn;传输完成回调函数s3c2410_dma_opfn_t op_fn; 操作完成回调函数*/183/* stats gathering */struct s3c2410_dma_stats*stats;struct s3c2410_dma_statsstats_store;187/* buffer list and information */structs3c241

11、0_dma_buf*curr;structs3c2410_dma_buf*next;structs3c2410_dma_buf*end;192/* system device */structsys_device dev;/* current dma buffer */* next buffer to load */* end of queue */dma 缓冲区链表1315行dma_channels是全局变量记录了当前系统dma通道总数 1317-1321行映射dma控制寄存器 1323-1332 行 为 struct s3c2410_dma_buf 分 配 cache,并利 用函数 s3c

12、2410_dma_cache_ctor 初始化为 0。1334-1354 行的循环就是初始化全局数组 struct s3c2410_dma_chan s3c2410_chansS3C_DMA_CHANNELS;,其中包括通道编号、中断号以及寄存 器基地址等信息。这个数组是针对实际的硬件信息建立的,每个硬件的dma通 道唯一对应一个struct s3c2410_dma_chan的数据结构。与之对应的还有一个虚拟 的dma通道,其实质是将不同dma请求源区分开来,然后用一个虚拟的通道号 与之一一对应,然后与实际的dma通道通过一张map表关联起来。关于map的 相关内容后面将会分析。首先这个函数的

13、意义是预定一些目标板要用的dma通道,使用的是上文提到的 虚拟的dma通道号。int _init s3c24xx_dma_order_set(struct s3c24xx_dma_order *ord)struct s3c24xx_dma_order *nord = dma_order;1478if (nord = NULL)nord = kmalloc(sizeof(struct s3c24xx_dma_order), GFP_KERNEL);1481if (nord = NULL) printk(KERN_ERR no memory to store dma channel ordern)

14、;return -ENOMEM;1486dma_order = nord;memcpy(nord, ord, sizeof(struct s3c24xx_dma_order);return 0;1477行dma_order是个全局变量,其作用是记录下目标板的dma预定信息。这里使用的是s3c2440_dma_order为其赋值,数据如下:51static struct s3c24xx_dma_order_initdata s3c244052.channels = 53DMACH_SDI = 54.list = 550 = 3 | DMA_CH_VALID,561 = 2 | DMA_CH_VA

15、LID,572 = 1 | DMA_CH_VALID,583 = 0 | DMA_CH_VALID,59,60,61DMACH_I2S_IN = 62.list = 630 = 1 | DMA_CH_VALID,641 = 2 | DMA_CH_VALID,65,66,67DMACH_I2S_OUT=68.list = 690 = 2 | DMA_CH_VALID,701 = 1 | DMA_CH_VALID,71,72,_dma_order = 7374757677787980818283848586878889909192DMACH_PCM_IN = .list = 0 = 2 | DMA

16、_CH_VALID,1 = 1 | DMA_CH_VALID,DMACH_PCM_OUT = .list = 0 = 1 | DMA_CH_VALID,1 = 3 | DMA_CH_VALID, DMACH_MIC_IN = .list = 0 = 3 | DMA_CH_VALID,1 = 2 | DMA_CH_VALID,;DMACH_SDI、DMACH_I2S_IN等是系统为dma所分配的虚拟dma通道号, 犹如中断子系统为中断分配的中断号一样,与具体硬件的中断向量号是不一致 的。后面我们在系统中使用的dma通道号,都将是内核虚拟出来的, s3c2410_dma_request函数将为用户

17、找到硬件对应的 dma通道号。提取上面 DMACH_SDI虚拟通道来分析一下:DMACH_SDI = .list = 0=3 | DMA_CH_VALID,1=2 | DMA_CH_VALID,2=1 | DMA_CH_VALID,3=0 | DMA_CH_VALID,List这个结构列出的是实际dma通道的可用信息,这里表面对于sdi所能够使用 的dma通道包含通道3,2,1,0 一共四个通道,为什么从大到小排列是因为某些dma 请求只能使用dma0,dma1等较小的通道号,比如外部总线dma只能使用dma0, 为了避免sdi占用,这里就采用了这种排列。三、 s3c24xx_dma_init

18、_map上面提到过一个map,这里就是为这个map的初始化函数了。他实际是根据硬 件情况为一个全局变量赋值。与前面的初始化一样,这里主要是为了统一管理 plat24xx这个平台下的dma资源,所以不同的芯片必须将自己硬件有关的dma 信息初始化到相应的全局变量中。再说函数之前先来关注一下struct s3c24xx_dma_map这个数据结构,他提供了 dma虚拟通道与实际的dma通道直 接的关联:struct s3c24xx_dma_map const char*name;/虚拟 dma 通道名称struct s3c24xx_dma_addr hw_addr;unsigned longcha

19、nnelsS3C_DMA_CHANNELS;/实际 dma 通道信息unsigned longchannels_rxS3C_DMA_CHANNELS;上面的结构只提供了单个虚拟通道的dma视图,整个芯片的虚拟dma通道的分 配情况是靠struct s3c24xx_dma_map数组完成的。在这里由struct s3c24XX_dma_selection 来统一管理。struct s3c24xx_dma_selection struct s3c24xx_dma_map *map;/记录了 struct s3c24xx_dma_map 数组的首地 址unsigned longmap_size;/

20、struct s3c24xx_dma_map 数组的成员个数unsigned longdcon_mask;/dma 控制器掩码void (*select)(struct s3c2410_dma_chan *chan,struct s3c24xx_dma_map *map);/ 虚拟通道选择函数void (*direction)(struct s3c2410_dma_chan *chan,struct s3c24xx_dma_map *map, enum s3c2410_dmasrc dir);/dma 方向;有了上面的背景以后下面函数就是简单的数据拷贝了,函数比较简单不在展开说 明。int _

21、init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)struct s3c24xx_dma_map *nmap;size_t map_sz = sizeof(*nmap) * sel-map_size;int ptr;1459nmap = kmalloc(map_sz, GFP_KERNEL);if (nmap = NULL)return -ENOMEM;14631464memcpy(nmap, sel-map, map_sz);memcpy(&dma_sel, sel, sizeof(*sel);dma_sel.map = n

22、map;for (ptr = 0; ptr map_size; ptr+) s3c24xx_dma_check_entry(nmap+ptr, ptr);return 0;146514661467146814691470147114721473初始化的任务比较简单,就是建立硬件dma通道信息即:struct s3c2410_dma_chan s3c2410_chansS3C_DMA_CHANNELS;建立目标板虚拟dma通道与硬件的dma通道的关联:static struct s3c24xx_dma_order *dma_order;建立芯片本身的虚拟dma通道与硬件dma通道的视图:stat

23、ic struct s3c24xx_dma_selection dma_sel;完成上述工作以后,基本的dma框架就已经建立起来了。接下分析dma使用过程中相关的函数:(一)s3c2410_dma_requestint s3c2410_dma_request(unsigned int channel,struct s3c2410_dma_client *client,void *dev)struct s3c2410_dma_chan *chan;unsigned long flags;int err;722pr_debug(dma%d: s3c2410_request_dma: client=

24、%s, dev=%pn”,channel, client-name, dev);725726local_irq_save(flags);727chan = s3c2410_dma_map_channel(channel);if (chan = NULL) local_irq_restore(flags);return -EBUSY;733734dbg_showchan(chan);735chan-client = client;chan-in_use = 1;738if (!chan-irq_claimed) pr_debug(dma%d: %s : requesting irq %dn”,c

25、hannel, _func_, chan-irq);742chan-irq_claimed = 1;local_irq_restore(flags);745err = request_irq(chan-irq,s3c2410_dma_irq, IRQF_DISABLED,client-name, (void *)chan);748749local_irq_save(flags);750if (err) chan-in_use = 0;chan-irq_claimed = 0;local_irq_restore(flags);755printk(KERN_ERR %s: cannot get I

26、RQ %d for DMA %dn,client-name, chan-irq, chan-number);return err;760chan-irq_enabled = 1;763764local_irq_restore(flags);765766/* need to setup */767768 pr_debug(%s: channel initialised, %pn, _func, chan);769return chan-number I DMACH_LOW_LEVEL;728行s3c2410_dma_map_channel为虚拟的dma通道可用的硬件dma资源,相应 的代码如下:

27、static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)struct s3c24xx_dma_order_ch *ord = NULL;struct s3c24xx_dma_map *ch_map;struct s3c2410_dma_chan *dmach;int ch;1394if (dma_sel.map = NULL II channel dma_sel.map_size)return NULL;13971398 ch_map = dma_sel.map + channel;13991400/* first, try the board mapping */1401if (dma_order) ord = &dma_order-channelschannel;1404for (ch = 0; ch listch)continue;1408if (s3c2410_chansord-listch.in_use = 0) ch = ord-listch& DMA_CH_VALID;

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论