日期:2014-05-16 浏览次数:20982 次
和以前一样,我不说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