linux-2.6.24.4中s3c2410和dma有关的函数的分析

发布者:电子设计艺术家最新更新时间:2022-05-25 来源: eefocus关键字:linux  s3c2410  dma 手机看文章 扫描二维码
随时随地手机看文章

首先介绍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 DMA MASK寄存器。

 

 

下面是linux-2.6.24.4中和dma有关的函数的分析:

 

首先定义了几个变量:
static int dma_channels ;//被设定为4
static struct s3c24xx_dma_selection dma_sel ;
struct s3c2410_dma_chan s3c2410_chans [S3C2410_DMA_CHANNELS];
static struct s3c24xx_dma_order * dma_order ;


有关的结构体定义如下:

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 s3c24xx_dma_map {

 const char * name;

 struct s3c24xx_dma_addr hw_addr;

 unsigned long channels[ S3C2410_DMA_CHANNELS] ;

} ;


struct s3c2410_dma_chan {

 /* channel state flags and information * /

 unsigned char number; /* number of this dma channel * /

 unsigned char in_use; /* channel allocated * /

 unsigned char irq_claimed; /* irq claimed for channel * /

 unsigned char irq_enabled; /* irq enabled for channel * /

 unsigned char xfer_unit; /* size of an transfer * /

 /* channel state * /

 enum s3c2410_dma_state state;

 enum s3c2410_dma_loadst load_state;

 struct s3c2410_dma_client * client;

 /* channel configuration * /

 enum s3c2410_dmasrc source;

 unsigned long dev_addr;

 unsigned long load_timeout;

 unsigned int flags; /* channel flags * /

 struct s3c24xx_dma_map * map; /* channel hw maps * /

 /* channel


struct s3c24xx_dma_order {

 struct s3c24xx_dma_order_ch channels[ DMACH_MAX] ;

} ;


struct s3c24xx_dma_order_ch {

 unsigned int list [ S3C2410_DMA_CHANNELS] ; /* list of channels */

 unsigned int flags; /* flags */

} ;


 


然后分析各个函数。


int s3c2410_dma_request( unsigned int channel,

   struct s3c2410_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) ;

   return err;

  }

  chan- > irq_enabled = 1; //使能中断


 }

 local_irq_restore( flags) ;

 /* need to setup */

 pr_debug( "%s: channel initialised, %p/n" , __FUNCTION__ , chan) ;

 return 0;

}


 

可见,该函数向内核申请了资源,即dma通道,然后就可以对申请的通道进行设置了。下面继续。

 

int s3c2410_dma_config( dmach_t channel, //通道号,和申请时使用的通道号要一致


         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=%08x/n" ,

   __FUNCTION__ , channel, xferunit, dcon) ;

 if ( chan = = NULL )

  return - EINVAL;

 pr_debug( "%s: Initial dcon is %08x/n" , __FUNCTION__ , dcon) ;

 dcon | = chan- > dcon & dma_sel. dcon_mask; //这步的作用是清除dcon寄存器中除了24~26的其他位,从datasheet中知道这三位


      //决定dma的中断源


 pr_debug( "%s: New dcon is %08x/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 %08x/n" , __FUNCTION__ , dcon) ;

 chan- > dcon = dcon;

 chan- > xfer_unit = xferunit;

 return 0;

}


由以上分析可以知道,该函数完成的主要功能就是设置对应通道的dcon寄存器。关于更细节的东西,可以查看datasheet。


int s3c2410_dma_devconfig( int channel,

     enum s3c2410_dmasrc source, //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=%08x, devaddr=%08lx/n" ,

   __FUNCTION__ , ( int ) source, hwcfg, devaddr) ;

 chan- > source = source;

 chan- > dev_addr = devaddr;

 switch ( source) {

 case S3C2410_DMASRC_HW: //dma传送源是外围硬件


  /* source is hardware */

  pr_debug( "%s: hw source, devaddr=%08lx, 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) ; //得到传送目的地址寄存器的地址


  return 0;

 case S3C2410_DMASRC_MEM: //dma传送源是内存


  /* source is memory */

  pr_debug( "%s: mem source, devaddr=%08lx, 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通道的映射:

return s3c24xx_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通道。


关键字:linux  s3c2410  dma 引用地址:linux-2.6.24.4中s3c2410和dma有关的函数的分析

上一篇:s3c2410_i2c总线驱动及at24c02设备驱动实例
下一篇:linux 2.6.24.4在S3C2410上的移植(CS8900网卡驱动)(基于GEC2410)

推荐阅读最新更新时间:2024-11-16 21:01

嵌入式Linux启动过程中的问题积累
1.Bad Magic Number ## Booting image at 33000000 ... Bad Magic Number OMAP5912 OSK # (tftp下载好kernel的uImage后就停止在这,不能启动kernel) 问题原因:启动参数设置错误,0x30000000处不可以执行。 有的开发板sdram不是在0x33000000,所以不能把kernel uImage下载到0x33000000中运行。如我之前的bootcmd参数为:setenv bootcmd tftpboot 33000000 uImage/; bootm 33000000。但板子Omap5912的sdram地址在0x10
[单片机]
嵌入式Linux 工业控制网络 TCP/IP
随着Internet的飞速发展,网络应用越来越广泛,对各种工业控制设备的网络功能要求也越来越高。当前的要求是希望工业控制设备能够支持TCP/IP以及其它Internet协议,从而能够通过用户熟悉的浏览器查看设备状态、设置设备参数,或者将设备采集到的数据通过网络传送到Windows或Unix/Linux服务器上的数据库中。 这就要求工控系统必须具备两方面的功能: 一是要在现场完成复杂的测控任务,因为通常一些任务都具有一定的实时性要求; 二是要求测控系统能够与某一类型的控制网相连,以实现远程监控。在目前应用的大多数测控系统中,嵌入式系统的硬件采用的是8/16位单片机;软件多采用汇编语言编程,由于这些程序仅包含一些简单的循环处理控制
[单片机]
AT91RM9200Linux移植笔记(二)-移植u-boot-1.1.6
u-boot的下载地址为http://sourceforge.net/project/showfiles.php?group_id=65938 ,最新的为u-boot-1.1.6,这个版本已经可以很好的支持AT91RM9200 添加PATH环境变量或者修改u-boot的Makefile将之前编译好的工具链路径添加进来 因为我们的开发板配置和at91rm9200dk很类似,因而可以直接使用at91rm9200dk_config的配置,如果相差比较大的话可以添加自己的开发板配置,还要修改诸如flash等的驱动,具体方法可参考u-boot的文档,一种简便的做法是在u-boot已经支持的开发板中参考选择一种较接近板的进行修改。 $ tar
[单片机]
ARM筆記:Linux内核移植到JZ2440
一、准备工作: 1、Linux内核:Linux2.6.22.6,可从 www.kernel.org 上下载; 2、交叉工具编译链:arm-linux-gcc-3.4.5-glibc-2.3.6; 3、yaffs2文件代码; 4、ubuntu9.10; 5、JZ2440; 二、内核移植: 1、修改Makefile: 修改内核源码根目录下的Makefile文件 #ARCH ?= arm #CROSS_COMPILE ?=arm-linux- 2、修改晶振 修改arch/arm/mach-s3c2440/mach-smdk2440.c static void __init smdk2440_map_io(void) {
[单片机]
MPEG-4编码器在Intel PXA27X平台上的实现
  0 引 言   随着人们对消费类电子产品(如PDA,MP4,HDTV等)需求不断增加,特别是对高质量高清晰多媒体的要求越来越高,因此视频质量已经成为广大消费者关注的焦点之一。在视频的格式方面,一些国际组织和大公司分别提出了自己的标准,如ISO组织的MPEG一2,MPEG一4,微软的WMV等。   针对Intel公司的PXA27X处理器(这是一个包含Intel Wireless MMX技术基于Intel Xscale的处理器),以XVID MPEG一4为基础,针对MPEG一4在Linux操作系统中实现视频的编码要求。在此首先介绍MPEG一4视频标准,紧接着阐述MPEG-4视频标准的关键技术和MPEG一4视频编码软件部分,
[嵌入式]
嵌入式智能家庭网关的设计
0 概述 家庭网络接入 Internet 目前主要通过PC机接入Internet和采用嵌入式产品通过 以太网 控制器接入Internet两种方式。前者优点是明显的,如灵活性、大量现有的可用的软件环境和高级的用户接口及软件工具。但是对于智能家庭网络来说,网络的使用者希望能方便快捷地获得服务,所需熟悉的操作要尽可能地少,并且在任何地方都能对家中设备进行监控;而PC不能随意移动,对设备的控制就会受到局限。因此,目前在智能家庭网络中,网关产品的设计主要采用嵌入式系统。 一个智能家庭网关可以看成是一个信息处理系统,组成系统的各单元就是连接在网络各节点的设备。控制平台一方面辅助不具备信息化条件的设备实现信息化,即提供信息处理的
[单片机]
嵌入式智能家庭网关的设计
选择实时操作系统(RTOS)前必须了解的几个要点
对许多嵌入式项目来说,系统设计师都倾向于选择实时操作系统(RTOS)。但RTOS总是必要的吗?答案是取决于具体的应用,因此了解我们要达到什么目标是决定RTOS是必要的还是花瓶的关键。 一般来说,在采用非实时操作系统(non-RTOS)的任何场合,也都可采用RTOS。但是,要找到一款具有完全相同应用编程接口(API)的匹配RTOS就相当困难了。因此,许多传统的操作系统(OS)在其内嵌入了一个RTOS。例如,Lynux-Works LynxOS和Bluecat Linux共享一个Linux API。LynxOS是一款硬RTOS,而Bluecat是Linux的一个衍生产品。 Linux继续在努力改善其实时性能,但其最长中断时延仍无法
[嵌入式]
风河提升On-Chip Debugging能力,强化Linux及多内核支持
全球领先的设备软件优化(DSO)厂商风河系统公司日前宣布推出增强型Wind River Workbench 2.6.1 On-Chip Debugging Edition(OCD,片上调试版)。作为风河旗下的设备软件开发综合工具套件,该产品将有效地解决越来越复杂化的片上调试工作。升级后的Wind River Workbench OCD Edition内置了专用开发工具集,不需要额外的内核测试装置,即可实现Linux内核和用户应用的调试,同时为多内核设备开发人员提供了一个基于标准且具有更全面支持能力的开发环境。 风河公司片上调试产品副总裁兼总经理Sandy Orlando表示:“风河公司充分理解设备开发人员在开发项目中进行32位或6
[新品]

推荐帖子

MC1413的应用
【不懂就问】MC1413芯片的DATASHEET的等效电路如下图,但是不知道输出口和PIN9脚怎么外接datasheet说7路输入7路输出,PIN9是公共端,看起来是个集电极开路电路看到一种接法,如下图,可以这样接吗?如果上图是正确的,那么输出的电压,是依靠上拉电阻拉倒Vcc的吗?在DATASHEET中规定的输出最大不超过50V,是指这个vcc吗?此外PIN9接一个电源,这里是3.3V,是怎么起保护作用的?它只是能让输出钳位在3.3+0.7V处把这是找的一个应用图,右边的两个
shaorc 模拟电子
数据存储技术与实践
分享一本华为的新书《数据存储技术与实践》pdf第一篇企业存储概述第1章存储工业演进历史31.1高端存储系统的演进41.2中端存储兴起61.3SAN外置存储阵列71.4NAS外置存储阵列91.5块、文件统一存储系统101.6全Flash外置存储阵列101.7ServerSAN融合存储11第2章存储产品架构演进趋势132.1高端存储架构演进142.2中端存储架构演进15第3章企业存储
白丁 FPGA/CPLD
储存搬运对静电敏感的元器件有什么方法?
 静电敏感元件在储存和运输过程中会暴露于有静电的区域中,用静电屏蔽的方法可削弱外界静电对电子元件的影响。最通常的方法是用静电屏蔽袋和防静电周转箱作为防护用。另外防静电衣对人体的静电具有一定的屏蔽作用。  所以我们要求在周转搬运过程中,工人必须佩带无绳静电环和手套,穿防静电服装和防静电鞋等,同时应使用防静电料箱、PCB防静电料架、不锈钢周转车等专业设备,尽量避免人体直接接触周转。  要说明的是:由于防静电服,是用特殊合成纤维织成布料,一般情况下揉搓磨擦不会产生静
ESD技术咨询 安防电子
暴力拆解特斯拉电池组,探究美帝黑科技!(惊呆了!)
时尚的外形、百公里加速3.2秒、续航440公里,这些都是特斯拉ModelS作为一款纯电动汽车所展示给人们的数据。ModelS之所以能够拥有不逊于传统燃油车的性能表现,除了电动机技术之外,还要得益于特斯拉先进的电池技术。那么,特斯拉到底在电动车最核心技术之一的电池组研发方面有何独特建树呢?据介绍,ModelS的电池板总重高达900公斤,被放置在驾驶舱正下方的底盘当中,在为电动机提供能量的同时,也起到了稳定车辆重心的作用。
木犯001号 电源技术
好东东共享,Cadence SPB15.7 视频教程第1-7讲(于博士版)
可在线观看,也可以下载。文件太大,传不上来。给个地址,自己去下载吧。http://www.sig007.com/videoclass/107.htmlhttp://www.sig007.com/videoclass/108.htmlhttp://www.sig007.com/videoclass/109.htmlhttp://www.sig007.com/videoclass/110.htmlhttp://www.sig007.com/videoclass/111.htm
cheeta PCB设计
做了一个电容屏的IIC接口转USB
实现的功能:电容屏的触控芯片一般对外接口为IIC接口,无法在windows/linux等电脑主机上直接使用,通过增加一颗转接芯片实现IIC接口转免驱USB接口,可以直接在通用电脑上免驱使用触控屏。实现框图如下:目前转接方案已支持汇顶(如GT911/GT9110/GT928等)、墩泰(如FT5406/FT5446等)、集创北方(如ICNT88X6)等主流触控IC的IIC接口转USB接口。有需求或技术探讨的可直接联系球球1258305301.应用场景:1、中
明天会更好124 51单片机
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved