日期:2014-05-16 浏览次数:20824 次
和以前一样,我不说dma基础知识,你可以看看ldd3
这次我说的是三星平台的dma,不是三星的某款芯片的dma使用。这主要得益于三星公司统一了接口。比如我后有的例子是在s3c2440上做的但是我是参考s3c64xx的spi驱动。
当然内核还是linux-3.2.36,我们看dma-ops.h
/* arch/arm/plat-samsung/include/plat/dma-ops.h * * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Samsung DMA support * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef __SAMSUNG_DMA_OPS_H_ #define __SAMSUNG_DMA_OPS_H_ __FILE__ #include <linux/dmaengine.h> struct samsung_dma_prep_info { enum dma_transaction_type cap;//dma处理类型 enum dma_data_direction direction;//dma传输方向 dma_addr_t buf;//内存地址 unsigned long period;// unsigned long len;//buf长度,sizeof(buf) * width,width在下面struct samsung_dma_info /* .c中调用 int len = (info->cap == DMA_CYCLIC) ? info->period : info->len; ... 我不是太清楚period和len区别 */ void (*fp)(void *data);//dma中断时会调用,一般作为dma传输完成的接口 void *fp_param;//传入上面fp的参数 }; struct samsung_dma_info { enum dma_transaction_type cap;//dma处理类型 /* if (info->cap == DMA_CYCLIC) s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);//chan->flags设置 这个可能和芯片有点关系 我的plat-s3c24xx中,通道请求函数 if (chan->flags & S3C2410_DMAF_AUTOSTART) {//如果设置为自动运行,就调用start函数 s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL, S3C2410_DMAOP_START); } 没有判断S3C2410_DMAF_CIRCULAR标志 */ enum dma_data_direction direction;//dma传输方向 enum dma_slave_buswidth width;//要传输的数据宽度,就是(字节、半字、字) dma_addr_t fifo;//外设地址 struct s3c2410_dma_client *client; /* struct s3c2410_dma_client { char *name; }; 就是一个name,你申请通道时命名就可以了,主要dma中断注册是用、free通道时判断 是不是正确通道 */ }; struct samsung_dma_ops { unsigned (*request)(enum dma_ch ch, struct samsung_dma_info *info);//请求会有些限制 //1.总是认为我们的外围设备是一个固定的地址 //2.总是认为我们的内存地址增加 //3.硬件触发 //4.所有传输完成产生中断 //上面这个从数据手册上看是可以设的,但是三星写的驱动代码没有选的可能 int (*release)(unsigned ch, struct s3c2410_dma_client *client);//释放 int (*prepare)(unsigned ch, struct samsung_dma_prep_info *info);//准备 //准备会把内存数据加入链表中,如果有数据在传输,会打开再加载开关 int (*trigger)(unsigned ch);//触发 int (*started)(unsigned ch);//再次开始,实际就是再次载入数据 int (*flush)(unsigned ch);//清除通道数据 int (*stop)(unsigned ch);//停止 }; extern void *samsung_dmadev_get_ops(void); extern void *s3c_dma_get_ops(void); //去获取一个struct samsung_dma_ops全局变量, //然后调用驱动,这个倒是给我们提供了一种驱动之间调用的方法 static inline void *__samsung_dma_get_ops(void) { if (samsung_dma_is_dmadev()) return samsung_dmadev_get_ops(); else return s3c_dma_get_ops(); } /* * samsung_dma_get_ops * get the set of samsung dma operations */ //在驱动中调用这个 #define samsung_dma_get_ops() __samsung_dma_get_ops() #endif /* __SAMSUNG_DMA_OPS_H_ */
如果你和我一样死脑筋,你可以看看下面的源码分析:主要有三个文件
下面这个文件,看的时候不要纠结,主要是为第二个通道使用的,知道就行。
/* linux/arch/arm/plat-samsung/dma.c * * Copyright (c) 2003-2009 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * http://armlinux.simtec.co.uk/ * * S3C DMA core * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ struct s3c2410_dma_buf; /* struct s3c2410_dma_buf { struct s3c2410_dma_buf *next; int magic; // magic int size; // buffer size in bytes dma_addr_t data; // start of DMA data dma_addr_t ptr; // where the DMA got to [1] void