博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
s3c2410的dma操作的一般步骤
阅读量:4051 次
发布时间:2019-05-25

本文共 6913 字,大约阅读时间需要 23 分钟。

2009-04-10 17:33 345人阅读 (0)  
 
一般的,在s3c2440中,要想进行dma传输,需要一下七个步骤:

一:

int s3c2410_dma_request(unsigned int channel,
            struct s3c2410_dma_client *client,
            void *dev)

s3c2410_dma_client的定义为:
struct s3c2410_dma_client {
 
 
 
 
 
 
 
char 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
*name;
};
以uda1314的驱动为例,驱动中定义了两个s3c2410_dma_client
static struct s3c2410_dma_client s3c2410iis_dma_out= {
 
 
 
.name = "I2SSDO",
};
static struct s3c2410_dma_client s3c2410iis_dma_in = {
 
 
 
.name = "I2SSDI",
};

二:

s3c2410_dma_config(dmach_t channel,int xferunit,int dcon)

s3c2410_dma_config(dmach_t channel,int xferunit,int dcon)
根据xferunit以及dcon设置通道的控制寄存器DCONx
xferunit为每次传输的数据大小:0:byte 1:half word 2:word

三:

int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)

设置相应的dma通道完成一次dma传输后的回调函数,也即是s3c2410_dma_enqueue完成后会调用的函数
回调函数应具有一下格式:
typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
void *buf, int size,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
enum s3c2410_dma_buffresult result);
buf可以传递一些有用的数据,在uda1314的驱动中,传递的是audio_buf_t结构体

四:

int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)

在1314驱动中,
flags = S3C2410_DMAF_AUTOSTART; 
 
 
 
 
 
 
s3c2410_dma_setflags(channel, flags);

五:

int s3c2410_dma_devconfig(int channel,

             enum s3c2410_dmasrc source,
             int hwcfg,
             unsigned long devaddr)

参数意义:
 
* source: 
 
 
S3C2410_DMASRC_HW: source is hardware
 
 
 
 
 
 
 
 
 
 
 
S3C2410_DMASRC_MEM: source is memory
 
*
 
* hwcfg: 
 
 
 
the value for xxxSTCn register,
 
 
 
 
 
 
 
 
 
 
 
bit 0: 0=increment pointer, 1=leave pointer
 
 
 
 
 
 
 
 
 
 
 
bit 1: 0=soucre is AHB, 1=soucre is APB
 
*
 
* devaddr: 
 
physical address of the source
如果source为S3C2410_DMASRC_HW(外设), 配置它的S3C2410_DMA_DISRCC,S3C2410_DMA_DISRC,S3C2410_DMA_DIDSTC
如果source为S3C2410_DMASRC_MEM(内存),配置它的S3C2410_DMA_DISRCC,S3C2410_DMA_DIDST,S3C2410_DMA_DIDSTC
由此可见,地址方面,只配置涉及外设的地址
以uda1341的驱动为例,这几个值为
 
 
 
 
 
 
source = S3C2410_DMASRC_MEM;
 
 
 
 
 
 
hwcfg = 3;
 
 
 
 
 
 
devaddr = 0x55000010;

六:

void *dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *dma_handle,intflag)

利用此函数,申请dmabuf,建立一致性映射
以uda1314的驱动为例,调应的实例为:
dmabuf = dma_alloc_coherent(NULL, dmasize, &dmaphys, GFP_KERNEL);(在audio_setup_buf函数中)
dmabuf为虚拟地址,dmaphys是总线地址,虚拟地址用来让驱动写buf用,dmaphys用来传给dma。
dma关心的是总线地址。
关于总线地址与物理地址的区别,这里有很好的说明http://hi.baidu.com/zengzhaonong/blog/item/eeb8003083276e9ba9018ee3
.html,感谢儒雅,现摘录如下:
1) 物理地址是与CPU相关的。在CPU的地址信号线上产生的就是物理地址。在程序指令中的虚拟地址经过段映射和页面映射后,就生成了物理地址,这个物理地址被放到CPU的地址线上。
2) 总线地址,顾名思义,是与总线相关的,就是总线的地址线或在地址周期上产生的信号。外设使用的是总线地址。
3) 物理地址与总线地址之间的关系由系统的设计决定的。在x86平台上,物理地址与PCI总线地址是相同的。在其他平台上,也许会有某种转换,通常是线性的转换。
比如:CPU需要访问物理地址是0xfa000的单元,那么在x86平台上,会产生一个PCI总线上对0xfa000地址的访问。这个单元或者是内存中,或者是某个卡上的存储单元,甚至可能这个地址上没有对应的存储器。而在另外一个平台上,或许在PCI总线上产生的访问是针对地址为0x1fa000的单元。
上述函数是建立一致性映射。使用dma_map_single函数可以建立一致性映射:
2.当只有一个缓冲区要被传输的时候,使用dma_map_single函数来映射它
dma_addr_t dma_map_single(struct device *dev,void *buffer,size_t size, enum dma_data_direction direction)
3.为page结构指针指向的缓冲区建立映射,单页流式映射:
dma_addr_t dma_map_page(struct device *dev,struct page *page ,unsigned long offset ,size_t size,enum dma_data_direction direction);
4.分散/聚集映射
int dma_map_sg(struct device *dev,struct scatterlist *sg,int nents,enum dma_alloc_coherent direction);
还不知道哪种情况下用流式映射,哪种用一致映射。对于s3c2440,其mmc驱动中用到了分散聚集(流式)映射,声卡驱动中又用到了一致映射。

七:

int s3c2410_dma_enqueue(unsigned int channel, void *id,
            dma_addr_t data, int size)

发起一次dma传输
 
参数意义:
 
* id 
 
 
 
 
 
 
 
the device driver's id information for this buffer
 
* data 
 
 
 
 
 
the physical address of the buffer data
 
* size 
 
 
 
 
 
the size of the buffer in bytes
将dma_alloc_coherent中得到的dmaphys传递给s3c2410_dma_enqueue. s3c2410_dma_enqueue提交一次dma请求,当dma通道可用的时候通过s3c2410_dma_loadbuffer开始一次传输,传输完成后会产生irq中断。其dma的中断服务函数中会继续启动dma请求队列中的请求,传输剩下的数据。
 
============================================
一些相关函数的说明。供自己日后参考。
--------------------------------------------------------------------------------------
int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
初始化全局变量dma_sel结构,在此函数中大家可能疑惑的是
 
 
 
nmap = kmalloc(map_sz, GFP_KERNEL);
 
 
 
if (nmap == NULL)
 
 
 
 
 
 
return -ENOMEM;
 
 
 
memcpy(nmap, sel->map, map_sz);
 
 
 
memcpy(&dma_sel, sel, sizeof(*sel));
 
 
 
dma_sel.map = nmap;
这几条语句,为什么用memcpy初始化为了dma_sel,而又要用再分配的nmap结构去给dma_sel赋值。其答案是为了保险,因为dma_sel 中的map成员是个指针。对指针的操作是要很小心的。这里在此函数中重新定义一个指针变量,并指向它,就是为了防止别处定义的指针被撤消而造成越界 。其实我认为这没有必要的。
dma_sel的定义为struct s3c24xx_dma_selection dma_sel;
而struct s3c24xx_dma_selection的定义为
struct s3c24xx_dma_selection {
 
 
 
struct s3c24xx_dma_map 
 
 
*map;
 
 
 
unsigned long 
 
 
 
 
 
map_size;
 
 
 
unsigned long 
 
 
 
 
 
dcon_mask;
 
 
 
void 
 
 
(*select)(struct s3c2410_dma_chan *chan,
 
 
 
 
 
 
 
 
 
 
struct s3c24xx_dma_map *map);
};
--------------------------------------------------------------------------------------------------------
struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
此函数 是: turn the virtual channel number into a real, and un-used hardware channel.完成 通道的虚实映射
在s3c2440_dma_mappings数组中查找相应channel对应的通道(0--4,有效未使用),并将映射关系记入dma_chan_map[channel]数组中。
---------------------------------------------------------------------------------------------------------
static int __init s3c2410_init_dma(void)
用于初始化s3c2410_dma_chan结构,并完成 映射。
-----------------------------------------------------------------------------------------------------------
static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
DMA通道虚实转换
-----------------------------------------------------------------------------------------------------------
int s3c2410_dma_request(unsigned int channel,
 
 
 
 
 
 
 
 
 
struct s3c2410_dma_client *client,
 
 
 
 
 
 
 
 
 
void *dev)
通过s3c2410_dma_map_channel函数找到channel对应的通道,并 相应的通道状态,申请中断
-----------------------------------------------------------------------------------------------------------
int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
 
 
 
-----------------------------------------------------------------------------------------------------------
int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
--------------------------------------------------------------------------------------------------------------
static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
 
* stop the channel, and remove all current and pending transfers
--------------------------------------------------------------------------------------------------------------
int s3c2410_dma_config(dmach_t channel,
 
 
 
 
 
 
 
 
 
 
 
 
int xferunit,
 
 
 
 
 
 
 
 
 
 
 
 
int dcon)
根据xferunit设置通道的控制寄存器
--------------------------------------------------------------------------------------------------------------
int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
根据flags设置通道的flags
--------------------------------------------------------------------------------------------------------------
int s3c2410_dma_devconfig(int channel,
 
 
 
 
 
 
 
 
 
 
enum s3c2410_dmasrc source,
 
 
 
 
 
 
 
 
 
 
int hwcfg,
 
 
 
 
 
 
 
 
 
 
unsigned long devaddr)
参数意义:
 
* source: 
 
 
S3C2410_DMASRC_HW: source is hardware
 
 
 
 
 
 
 
 
 
 
 
S3C2410_DMASRC_MEM: source is memory
 
*
 
* hwcfg: 
 
 
 
the value for xxxSTCn register,
 
 
 
 
 
 
 
 
 
 
 
bit 0: 0=increment pointer, 1=leave pointer
 
 
 
 
 
 
 
 
 
 
 
bit 1: 0=soucre is AHB, 1=soucre is APB
 
*
 
* devaddr: 
 
physical address of the source
如果source为S3C2410_DMASRC_HW(外设), 配置它的S3C2410_DMA_DISRCC,S3C2410_DMA_DISRC,S3C2410_DMA_DIDSTC
如果source为S3C2410_DMASRC_MEM(内存),配置它的S3C2410_DMA_DISRCC,S3C2410_DMA_DIDST,S3C2410_DMA_DIDSTC
由此可见,地址方面,只配置涉及外设的地址
你可能感兴趣的文章
jxbrowser 监听所有网络请求 jxbrowser 系列教程2
查看>>
jxbrowser 实现java 和 js互相调用(破解版请联系作者)
查看>>
jxbrowser java代码直接调用js代码 (破解版请联系作者)免license
查看>>
jxbrowser 实现自定义右键菜单 jxbrowser破解版请联系作者
查看>>
快速开发框架设计
查看>>
需要统计的数据
查看>>
eclipse js jsp 卡怎么办,解决办法
查看>>
高性能J2EE接口平台设计
查看>>
spring mvc tomcat 线程池的坑
查看>>
JAVA 生成不重复订单号 优化版本 订单号格式为yyyymmdd后面自增
查看>>
mybatis-jpa插件使用教程
查看>>
cas 4.2.7 和 Nginx 整合遇到的问题 登录一会可以一会不可以
查看>>
CAS 单点登出 loginout 解决方案 -- 最靠谱的方案,不是抄的--还是不靠谱大家不要抄了
查看>>
springboot 支持jsp 直接访问jsp办法无需通过controller转发
查看>>
后续框架可以优化的点
查看>>
SpringBoot Logback 配置参数迁移到配置中心 Apollo
查看>>
springboot 自定义webroot的目录
查看>>
springboot springmvc j2ee 做伪静态化 .html 转发到 .jsp
查看>>
我入行以来java框架的几个阶段&论什么是真正的组件开发&项目中部分源码干货分享
查看>>
java-真正面向配置+组件的开发
查看>>