linux-2.6.24.4中和dma有关的函数…

来源:互联网 发布:淘宝中老年女秋装 编辑:程序博客网 时间:2024/05/17 02:27
s3c2410与DMA相关的寄存器
s3c2410共有4通道的dma,每通道9个寄存器,共36个。 
1、DISRCn 该寄存器保存待传送数据的源地址。
2、DISRCCn 源控制寄存器。位1表示数据源的总线类型,位0表示地址是否自动增减。
3、DIDSTn 该寄存器保存待传送数据的目的地址。
4、DIDSTCn 目的控制寄存器。位1表示目的地址的总线类型,位0表示地址是否自动增减。
5、DCON  DMA控制寄存器。
6、DSTATn DMA状态寄存器。
7、DCSRCn 当前源地址寄存器。
8、DCDSTn 当前目的地址寄存器。
9、DMASKTRIGn DMAMASK寄存器。 
下面是linux-2.6.24.4中和dma有关的函数的分析: 
首先定义了三个变量:
static int dma_channels;//被设定为4
static struct s3c24xx_dma_selection dma_sel;
struct s3c2410_dma_chans3c2410_chans[S3C2410_DMA_CHANNELS];
static struct s3c24xx_dma_order *dma_order;
有关的结构体定义如下:
struct s3c24xx_dma_selection {
 structs3c24xx_dma_map *map;
 unsigned long  map_size;
 unsigned long  dcon_mask; 
 void (*select)(structs3c2410_dma_chan *chan,
    struct s3c24xx_dma_map *map);
}; 
struct s3c24xx_dma_map {
 constchar  *name;
 struct s3c24xx_dma_addr hw_addr; 
 unsigned long  channels[S3C2410_DMA_CHANNELS];
}; 

struct s3c2410_dma_chan {
 
 unsigned char  number;     
 unsigned char  in_use;     
 unsigned char  irq_claimed;
 unsigned char  irq_enabled;
 unsigned char  xfer_unit;   
  
 enum s3c2410_dma_state state;
 enum s3c2410_dma_loadst load_state;
 struct s3c2410_dma_client*client; 
 
 enum s3c2410_dmasrc source;
 unsigned long  dev_addr;
 unsigned long  load_timeout;
 unsigned int  flags;   
 structs3c24xx_dma_map *map;   
 
 void__iomem  *regs;  
 void__iomem  *addr_reg; 
 unsigned int  irq;  
 unsigned long  dcon;   
 
 s3c2410_dma_cbfn_t callback_fn; 
 s3c2410_dma_opfn_t op_fn;   
 
 struct s3c2410_dma_stats *stats;
 struct s3c2410_dma_stats stats_store; 
 
 structs3c2410_dma_buf *curr;  
 structs3c2410_dma_buf *next;  
 structs3c2410_dma_buf *end;   
 
 struct sys_device dev;
}; 
struct s3c24xx_dma_order {
 structs3c24xx_dma_order_ch channels[DMACH_MAX];
}; 
struct s3c24xx_dma_order_ch {
 unsignedint list[S3C2410_DMA_CHANNELS]; 
 unsignedint flags;    
}; 

然后分析各个函数。 
int s3c2410_dma_request(unsigned int channel,
   structs3c2410_dma_client *client,
   void*dev)
{
 struct s3c2410_dma_chan *chan;
 unsigned long flags;
 int err; 
 pr_debug("dma%d: s3c2410_request_dma: client=%s,dev=%p\n",
   channel,client->name, dev); 
 local_irq_save(flags); 
 chan =s3c2410_dma_map_channel(channel);//获得dma通道
 if (chan == NULL) {
  local_irq_restore(flags);
  return -EBUSY;
 
 dbg_showchan(chan); 
 chan->client = client;
 chan->in_use =1;//占用该dma通道 
 if (!chan->irq_claimed){
  pr_debug("dma%d: %s :requesting irq %d\n",
    channel,__FUNCTION__,chan->irq); 
  chan->irq_claimed= 1;
  local_irq_restore(flags); 
  err =request_irq(chan->irq, s3c2410_dma_irq,IRQF_DISABLED,//申请中断
     client->name, (void*)chan); 
  local_irq_save(flags); 
  if (err) {//中断申请失败
   chan->in_use= 0;//释放申请的通道和其他资源
   chan->irq_claimed= 0;
   local_irq_restore(flags); 
   printk(KERN_ERR"%s: cannot get IRQ %d for DMA %d\n",
         client->name, chan->irq,chan->number);
   returnerr;
  
  chan->irq_enabled= 1;//使能中断
 
 local_irq_restore(flags); 
  
 pr_debug("%s: channel initialised, %p\n",__FUNCTION__, chan); 
 return 0;
}
可见,该函数向内核申请了资源,即dma通道,然后就可以对申请的通道进行设置了。下面继续。 
int s3c2410_dma_config(dmach_tchannel,//通道号,和申请时使用的通道号要一致
        int xferunit,//发送时位的设置,可以是1、2、或者4,分别对应8、16和32位方式
        int dcon)//特别重要,就是dcon寄存器的值
{
 struct s3c2410_dma_chan *chan =lookup_dma_channel(channel);//得到申请的dma通道 
 pr_debug("%s: chan=%d, xfer_unit=%d,dcon=x\n",
   __FUNCTION__, channel,xferunit, dcon); 
 if (chan == NULL)
  return-EINVAL; 
 pr_debug("%s: Initial dcon is x\n", __FUNCTION__,dcon); 
 dcon |= chan->dcon&dma_sel.dcon_mask;//这步的作用是清除dcon寄存器中除了24~26的其他位,从datasheet中知道这三位
      //决定dma的中断源
 pr_debug("%s: New dcon is x\n", __FUNCTION__,dcon); 
 switch (xferunit) {//设置字节传送的方式
 case 1:
  dcon |=S3C2410_DCON_BYTE;
  break; 
 case 2:
  dcon |=S3C2410_DCON_HALFWORD;
  break; 
 case 4:
  dcon |=S3C2410_DCON_WORD;
  break; 
 default:
  pr_debug("%s: bad transfer size%d\n", __FUNCTION__, xferunit);
  return -EINVAL;
 
 dcon |=S3C2410_DCON_HWTRIG;//使24~26位的选择有效
 dcon |=S3C2410_DCON_INTREQ;//使传送完成的时候产生中断 
 pr_debug("%s: dcon now x\n", __FUNCTION__,dcon); 
 chan->dcon = dcon;
 chan->xfer_unit =xferunit; 
 return 0;

由以上分析可以知道,该函数完成的主要功能就是设置对应通道的dcon寄存器。关于更细节的东西,可以查看datasheet。 
int s3c2410_dma_devconfig(int channel,
    enum s3c2410_dmasrcsource,//dma传送源的类型,可以是S3C2410_DMASRC_HW和S3C2410_DMASRC_MEM
    int hwcfg,
    unsigned long devaddr)//传送的目的地址
{
 struct s3c2410_dma_chan *chan =lookup_dma_channel(channel); 
 if (chan == NULL)
  return-EINVAL; 
 pr_debug("%s: source=%d, hwcfg=x,devaddr=lx\n",
   __FUNCTION__, (int)source,hwcfg, devaddr); 
 chan->source = source;
 chan->dev_addr =devaddr; 
 switch (source) {
 case S3C2410_DMASRC_HW://dma传送源是外围硬件
  
  pr_debug("%s: hw source,devaddr=lx, hwcfg=%d\n",
   __FUNCTION__, devaddr, hwcfg);
  dma_wrreg(chan,S3C2410_DMA_DISRCC, hwcfg & 3);//设置源控制寄存器
  dma_wrreg(chan,S3C2410_DMA_DISRC,  devaddr);//设置传送源的地址
  dma_wrreg(chan,S3C2410_DMA_DIDSTC, (0<<1) |(0<<0));//目的地址一般是内存 
  chan->addr_reg =dma_regaddr(chan, S3C2410_DMA_DIDST);//得到传送目的地址寄存器的地址
  return0; 
 case S3C2410_DMASRC_MEM://dma传送源是内存
  
  pr_debug( "%s: mem source,devaddr=lx, hwcfg=%d\n",
    __FUNCTION__, devaddr, hwcfg);
  dma_wrreg(chan,S3C2410_DMA_DISRCC, (0<<1) |(0<<0));//传送源控制器
  dma_wrreg(chan,S3C2410_DMA_DIDST,  devaddr);//传送的目的地址
  dma_wrreg(chan,S3C2410_DMA_DIDSTC, hwcfg &3);//目的地址控制器 
  chan->addr_reg =dma_regaddr(chan, S3C2410_DMA_DISRC);//得到传送源地址寄存器的地址
  return 0;
 
 printk(KERN_ERR "dma%d: invalid source type(%d)\n", channel, source);
 return -EINVAL;

整个系统中dma的建立过程如下:
首先调用了s3c2410_dma_init(),该函数只有一句:
return s3c24xx_dma_init(4, IRQ_DMA0, 0x40);
其中第一个参数就是通道号,第二个参数为dma的中断号的基数,第三个参数表示各个通道占用的空间的大小。
在函数s3c24xx_dma_init中,主要做了以下几件事情:
1、调用ioremap,将dma控制器的地址做一个映射。
2、为dma分配内核空间。
3、将上面提到的s3c2410_chans数组的内容全部清零。
4、初始化4个s3c2410_dma_chan结构的变量,对其中的一部分成员赋值。
成功结束时,该函数返回0。 
第二步,系统调用s3c24xx_dma_order_set函数,如下:
s3c24xx_dma_order_set(&s3c2410_dma_order);
s3c2410_dma_order定义于arch/arm/mach-s3c2410/dma.c文件中,是一个s3c24xx_dma_order类型的结构体。
该函数主要为该结构体分配空间,然后将s3c2410_dma_order的内容copy到dma_order中。 
第三步,系统调用s3c24xx_dma_init_map,完成dma通道的映射:
returns3c24xx_dma_init_map(&s3c2410_dma_sel);
下面重点分析一下该函数。 
传给该函数的参数定义如下:
static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel ={
 .select  =s3c2410_dma_select,
 .dcon_mask = 7<< 24,
 .map  =s3c2410_dma_mappings,
 .map_size =ARRAY_SIZE(s3c2410_dma_mappings),
}; 
该函数首先为各个通道分配内存空间,分配的总的大小为sizeof(struct s3c24xx_dma_map ) *s3c2410_dma_sel.map_size。
然后,函数把s3c2410_dma_sel的所有内容全部赋给上面提到的dma_sel结构体,该结构体就包含了所有的dma可以申请的通道。
用户申请dma通道的时候,内核就可以在dma_sel的map表中查找,并决定是否可以使用该dma通道。
如果图片或页面不能正常显示请点击这里
0 0