DMA驱动框架

Posted zsy12138

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DMA驱动框架相关的知识,希望对你有一定的参考价值。

框架入口源文件:dma.c

(可根据入口源文件,再按着框架到内核走一遍)

内核版本:linux_2.6.22.6    硬件平台:JZ2440


以下是驱动框架:


以下是驱动代码  dma.c :

#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/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/poll.h>
#include <linux/dma-mapping.h>

//源地址
static unsigned char *src;
static unsigned int src_phy;

//目的地址
static unsigned char* dest;
static unsigned int dest_phy;

//空间大小
#define  DMA_SIZE (1204*512)

//驱动类
static struct class *dma_class;

//主设备号
static int major ;

#define USE_DMA 1
#define NO_DMA 0

//DMA寄存器
static struct s3c_dma_reg 
{
     unsigned long disrc;
     unsigned long disrcc;
     unsigned long didst;
     unsigned long didstc;
     unsigned long dcon;
     unsigned long dstat;
     unsigned long dcsrc;
     unsigned long dcdst;    
     unsigned long dmaskting;
}*s3c_dma_regs;

//DMA地址
static unsigned long dma_addr0 = 0x4b000000;
static unsigned long dma_addr1 = 0x4b000040;
static unsigned long dma_addr2 = 0x4b000080;
static unsigned long dma_addr3 = 0x4b0000c0;

//为这个进程创建等待队列
static DECLARE_WAIT_QUEUE_HEAD(dma_wait_queue);

//进程队列标志位
static volatile int dma_wait_queue_condition=0;


static int s3c_dma_iotcl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long args)
{
   int i=0;
       memset(src, 0xAA, DMA_SIZE);
    memset(dest, 0x55, DMA_SIZE);

    
    switch(cmd)
   {
      case NO_DMA :
          {
          for(i=0;i<DMA_SIZE;i++) dest[i] = src[i];
          if(memcmp(src,dest,DMA_SIZE) == 0) printk("copy without DMA successfuly !
");
          else printk("copy without DMA fialed !
");
          break;
      }
      case USE_DMA :
          {
         // 设置DMA寄存器
          s3c_dma_regs->disrc = src_phy;
          s3c_dma_regs->disrcc = (0<<0)|(0<<0);
          s3c_dma_regs->didst = dest_phy;
          s3c_dma_regs->didstc =(0<<3)|(0<<1)|(0<<0);
          s3c_dma_regs->dcon = (1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(0<<20)|(DMA_SIZE<<0);
          s3c_dma_regs->dmaskting = (1<<1)|(1<<0);

         //休眠进程
          dma_wait_queue_condition = 0;      //状态标志位为假         休眠dma.c进程      。 进程可被信号中断休眠,返回非0值表示休眠被信号中断
          wait_event_interruptible(dma_wait_queue, dma_wait_queue_condition);  

          if(memcmp(src,dest,DMA_SIZE) == 0) printk(" copy with DMA successfuly !
");
          else printk("copy with DMA failed !
");
          break;
      }
     }
  return 0;

}

//字符设备操作函数
static struct file_operations dma_fops = 
{
     .owner = THIS_MODULE,
     .ioctl = s3c_dma_iotcl,
};


//中断处理函数
static     int s3c_dma_irq(int irq, void *devid)
{
    dma_wait_queue_condition = 1;            //状态为真     唤醒dma.c进程
    wake_up_interruptible(&dma_wait_queue);
    return IRQ_HANDLED;
}


static int dma_init(void)
{
    //申请中断
    request_irq(IRQ_DMA3, s3c_dma_irq,0, "s3c_dma", 1);
    
    //申请源地址空间
     src = dma_alloc_writecombine(NULL,DMA_SIZE, &src_phy,GFP_KERNEL);
     //申请目的地址空间
     dest= dma_alloc_writecombine(NULL,DMA_SIZE, &dest_phy,GFP_KERNEL);

    //dma_reg映射
     s3c_dma_regs = ioremap(dma_addr3,sizeof(struct s3c_dma_reg));

    //注册字符设备
    major = register_chrdev(0, "s3c_dma",&dma_fops);

    //注册类 设备节点

    dma_class = class_create(THIS_MODULE,"s3c_dma_class");                //     /sys/class/s3c_dma_class
    class_device_create(dma_class,NULL,MKDEV(major,0),NULL, "s3c_dma");   //     /dev/s3c_dma
                                                                          
    return 0;
}

static void dma_exit(void)

{
   free_irq(IRQ_DMA3,1);
   dma_free_writecombine(NULL,DMA_SIZE, src,GFP_KERNEL);
   dma_free_writecombine(NULL,DMA_SIZE, dest,GFP_KERNEL);
   iounmap(s3c_dma_regs);
   unregister_chrdev(major, "s3c_dma");
   class_destroy(dma_class);
   class_device_destroy( dma_class,MKDEV(major,0)); 
}


module_init(dma_init);
module_exit(dma_exit);

MODULE_LICENSE("GPL");

 

以下是驱动测试文件:

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


#define USE_DMA 1
#define NO_DMA 0

int main(int argc ,char **argv)
{
    int fd=0;
    fd = open("/dev/s3c_dma", O_RDWR);
    if(fd<0)   printf("can‘t open 
");
    if(argc !=2) printf("please using like this : ./dma_test  <dma|no_dma>
"); 
    
    if(argc ==2)
        {
         if(strcmp(argv[1],"dma")==0) while(1) ioctl(fd,USE_DMA);
         if(strcmp(argv[1],"no_dma")==0)while(1)  ioctl(fd,NO_DMA);
        }
    
  return 0;
}

 


以下是编译驱动的Makefile:

KERN_DIR = /work/systems/kernel/linux-2/linux-2.6.22.6

all:
    make -C $(KERN_DIR) M=`pwd` modules 

clean:
    make -C $(KERN_DIR) M=`pwd` modules clean
    rm -rf modules.order

obj-m    +=dma.o

 




以上是关于DMA驱动框架的主要内容,如果未能解决你的问题,请参考以下文章

DMA驱动框架流程编写

DMA设计

高效的串行数据驱动框架

高效的串行数据驱动框架

小熊派 FreeRTOS+SPI+DMA 驱动 TFT-LCD

小熊派 FreeRTOS+SPI+DMA 驱动 TFT-LCD