1335cp=&s3c2410_chans[channel];
1336
1337memset(cp,0,sizeof(structs3c2410_dma_chan));
1338
1339/*dmachannelirqsareinorder..*/
1340cp->number=channel;
1341cp->irq=channel+irq;
1342cp->regs=dma_base+(channel*stride);
1343
1344/*pointcurrentstatssomewhere*/
1345cp->stats=&cp->stats_store;
1346cp->stats_store.timeout_shortest=LONG_MAX;
1347
1348/*basicchannelconfiguration*/
1349
1350cp->load_timeout=1<<18;
1351
1352printk("DMAchannel%dat%p,irq%d\n",
1353cp->number,cp->regs,cp->irq);
1354}
1355
1356return0;
1357
1358err:
1359kmem_cache_destroy(dma_kmem);
1360iounmap(dma_base);
1361dma_base=NULL;
1362returnret;
1363}
1364
首先来关注一下函数传递的参数:
unsignedintchannels:
s3c2440平台对应的DMA通道总数,为4
unsignedintirq:
起始DMA中断的中断号
unsignedintstride:
每通道DMA所占寄存器资源数
1309行structs3c2410_dma_chan记录dma通道信息,内容如下:
151structs3c2410_dma_chan{
152/*channelstateflagsandinformation*/
153unsignedcharnumber;//dma通道号,
154unsignedcharin_use;//当前通道是否已经使用
155unsignedcharirq_claimed;//有无dma中断
156unsignedcharirq_enabled;//是否使能了dma中断
157unsignedcharxfer_unit;//传输块大小
158
159/*channelstate*/
160
161enums3c2410_dma_statestate;
162enums3c2410_dma_loadstload_state;
163structs3c2410_dma_client*client;
164
165/*channelconfiguration*/
166enums3c2410_dmasrcsource;
167enumdma_chreq_ch;
168unsignedlongdev_addr;
169unsignedlongload_timeout;
170unsignedintflags;/*channelflags*/
171
172structs3c24xx_dma_map*map;/*channelhwmaps*/
173
174/*channel'shardwarepositionandconfiguration*/
175void__iomem*regs;/*channelsregisters*/
176void__iomem*addr_reg;/*dataaddressregister*/
177unsignedintirq;中断号
178unsignedlongdcon;/默认控制寄存器的值
179
180/*driverhandles*/
181s3c2410_dma_cbfn_tcallback_fn;传输完成回调函数
182s3c2410_dma_opfn_top_fn;操作完成回调函数*/
183
184/*statsgathering*/
185structs3c2410_dma_stats*stats;
186structs3c2410_dma_statsstats_store;
187
188/*bufferlistandinformation*/
189structs3c2410_dma_buf*curr;/*currentdmabuffer*/
190structs3c2410_dma_buf*next;/*nextbuffertoload*/
191structs3c2410_dma_buf*end;/*endofqueue*/dma缓冲区链表
192
193/*systemdevice*/
194structsys_devicedev;
195};
1315行dma_channels是全局变量记录了当前系统dma通道总数
1317-1321行映射dma控制寄存器
1323-1332行为structs3c2410_dma_buf分配cache,并利用函数s3c2410_dma_cache_ctor初始化为0。
1334-1354行的循环就是初始化全局数组structs3c2410_dma_chans3c2410_chans[S3C_DMA_CHANNELS];,其中包括通道编号、中断号以及寄存器基地址等信息。
这个数组是针对实际的硬件信息建立的,每个硬件的dma通道唯一对应一个structs3c2410_dma_chan的数据结构。
与之对应的还有一个虚拟的dma通道,其实质是将不同dma请求源区分开来,然后用一个虚拟的通道号与之一一对应,然后与实际的dma通道通过一张map表关联起来。
关于map的相关内容后面将会分析。
二、
s3c24xx_dma_order_set
首先这个函数的意义是预定一些目标板要用的dma通道,使用的是上文提到的虚拟的dma通道号。
1475int__inits3c24xx_dma_order_set(structs3c24xx_dma_order*ord)
1476{
1477structs3c24xx_dma_order*nord=dma_order;
1478
1479if(nord==NULL)
1480nord=kmalloc(sizeof(structs3c24xx_dma_order),GFP_KERNEL);
1481
1482if(nord==NULL){
1483printk(KERN_ERR"nomemorytostoredmachannelorder\n");
1484return-ENOMEM;
1485}
1486
1487dma_order=nord;
1488memcpy(nord,ord,sizeof(structs3c24xx_dma_order));
1489return0;
1490}
1477行dma_order是个全局变量,其作用是记录下目标板的dma预定信息。
这里使用的是s3c2440_dma_order为其赋值,数据如下:
51staticstructs3c24xx_dma_order__initdatas3c2440_dma_order={
52.channels={
53[DMACH_SDI]={
54.list={
55[0]=3|DMA_CH_VALID,
56[1]=2|DMA_CH_VALID,
57[2]=1|DMA_CH_VALID,
58[3]=0|DMA_CH_VALID,
59},
60},
61[DMACH_I2S_IN]={
62.list={
63[0]=1|DMA_CH_VALID,
64[1]=2|DMA_CH_VALID,
65},
66},
67[DMACH_I2S_OUT]={
68.list={
69[0]=2|DMA_CH_VALID,
70[1]=1|DMA_CH_VALID,
71},
72},
73[DMACH_PCM_IN]={
74.list={
75[0]=2|DMA_CH_VALID,
76[1]=1|DMA_CH_VALID,
77},
78},
79[DMACH_PCM_OUT]={
80.list={
81[0]=1|DMA_CH_VALID,
82[1]=3|DMA_CH_VALID,
83},
84},
85[DMACH_MIC_IN]={
86.list={
87[0]=3|DMA_CH_VALID,
88[1]=2|DMA_CH_VALID,
89},
90},
91},
92};
[DMACH_SDI]、[DMACH_I2S_IN]等是系统为dma所分配的虚拟dma通道号,犹如中断子系统为中断分配的中断号一样,与具体硬件的中断向量号是不一致的。
后面我们在系统中使用的dma通道号,都将是内核虚拟出来的,s3c2410_dma_request函数将为用户找到硬件对应的dma通道号。
提取上面[DMACH_SDI]虚拟通道来分析一下:
[DMACH_SDI]={
54.list={
55[0]=3|DMA_CH_VALID,
56[1]=2|DMA_CH_VALID,
57[2]=1|DMA_CH_VALID,
58[3]=0|DMA_CH_VALID,
59},
60},
List这个结构列出的是实际dma通道的可用信息,这里表面对于sdi所能够使用的dma通道包含通道3,2,1,0一共四个通道,为什么从大到小排列是因为某些dma请求只能使用dma0,dma1等较小的通道号,比如外部总线dma只能使用dma0,为了避免sdi占用,这里就采用了这种排列。
三、
s3c24xx_dma_init_map
上面提到过一个map,这里就是为这个map的初始化函数了。
他实际是根据硬件情况为一个全局变量赋值。
与前面的初始化一样,这里主要是为了统一管理plat24xx这个平台下的dma资源,所以不同的芯片必须将自己硬件有关的dma信息初始化到相应的全局变量中。
再说函数之前先来关注一下structs3c24xx_dma_map这个数据结构,他提供了dma虚拟通道与实际的dma通道直接的关联:
structs3c24xx_dma_map{
constchar*name;//虚拟dma通道名称
structs3c24xx_dma_addrhw_addr;
unsignedlongchannels[S3C_DMA_CHANNELS];//实际dma通道信息
unsignedlongchannels_rx[S3C_DMA_CHANNELS];
};
上面的结构只提供了单个虚拟通道的dma视图,整个芯片的虚拟dma通道的分配情况是靠structs3c24xx_dma_map数组完成的。
在这里由structs3c24XX_dma_selection来统一管理。
structs3c24xx_dma_selection{
structs3c24xx_dma_map*map;//记录了structs3c24xx_dma_map数组的首地址
unsignedlongmap_size;//structs3c24xx_dma_map数组的成员个数
unsignedlongdcon_mask;//dma控制器掩码
void(*select)(structs3c2410_dma_chan*chan,
structs3c24xx_dma_map*map);//虚拟通道选择函数
void(*direction)(structs3c2410_dma_chan*chan,
structs3c24xx_dma_map*map,
enums3c2410_dmasrcdir);//dma方向
};
有了上面的背景以后下面函数就是简单的数据拷贝了,函数比较简单不在展开说明。
1454int__inits3c24xx_dma_init_map(structs3c24xx_dma_selection*sel)
1455{
1456structs3c24xx_dma_map*nmap;
1457size_tmap_sz=sizeof(*nmap)*sel->map_size;
1458intptr;
1459
1460nmap=kmalloc(map_sz,GFP_KERNEL);
1461if(nmap==NULL)
1462return-ENOMEM;
1463
1464memcpy(nmap,sel->map,map_sz);
1465memcpy(&dma_sel,sel,sizeof(*sel));
1466
1467dma_sel.map=nmap;
1468
1469for(ptr=0;ptrmap_size;ptr++)
1470s3c24xx_dma_check_entry(nmap+ptr,ptr);
1471
1472return0;
1473}
初始化的任务比较简单,就是
(1)建立硬件dma通道信息即:
structs3c2410_dma_chans3c2410_chans[S3C_DMA_CHANNELS];
(2)建立目标板虚拟dma通道与硬件的dma通道的关联:
staticstructs3c24xx_dma_order*dma_order;
(3)建立芯片本身的虚拟dma通道与硬件dma通道的视图:
staticstructs3c24xx_dma_selectiondma_sel;
完成上述工作以后,基本的dma框架就已经建立起来了。
接下分析dma使用过程中相关的函数:
(一)s3c2410_dma_request
715ints3c2410_dma_request(unsignedintchannel,
716structs3c2410_dma_client*client,
717void*dev)
718{
719structs3c2410_dma_chan*chan;
720unsignedlongflags;
721interr;
722
723pr_debug("dma%d:
s3c2410_request_dma:
client=%s,dev=%p\n",
724channel,client->name,dev);
725
726local_irq_save(flags);
727
728chan=s3c2410_dma_map_channel(channel);
729if(chan==NULL){
730local_irq_restore(flags);
731return-EBUSY;
732}
733
734dbg_showchan(chan);
735
736chan->client=client;
737chan->in_use=1;
738
739if(!
chan->irq_claimed){
740pr_debug("dma%d:
%s:
requestingirq%d\n",
741channel,__func__,chan->irq);
742
743chan->irq_claimed=1;
744local_irq_restore(flags);
745
746err=request_irq(chan->irq,s3c2410_dma_irq,IRQF_DISABLED,
747client->name,(void*)chan);
748
749local_irq_save(flags);
750
751if(err){
752chan->in_use=0;
75