首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

对DMA 通道的操作分析之一(2)

对DMA 通道的操作分析之一(2)

下面我们再来看一些与DMA操作有关的函数

DMA控制器是一个系统级的资源,所以我们要向对它进行任何的操作,都必须在内核的
协助下来完成。我们的内核开发人员为我们做好了很多的接口:
  内核使用DMA注册表为DMA通道提供了请求/释放机制,并且为我们提供了一组
DMA控制器配置通道信息的函数。

获取和释放DMA

DMA控制器使用request_dma和free_dma来获取和释放DMA通道的所有权。注意在请求
DMA通道之前应先请求中断线,同样必须在释放dma通道后在释放中断线。所以每个
使用DMA的设备同时也必须使用中断信号线,否则在数据传输完成时是无法发送“数据
传完成”通知的。下面我们来看看这两个函数,这两个函数都位于kernel/dma.c中
   
    /**
     * request_dma - request and reserve a system DMA channel
     * @dmanr: DMA channel number
     * @device_id: reserving device ID string, used in /proc/dma
     */
    int request_dma(unsigned int dmanr, const char * device_id)
    {
     if (dmanr >= MAX_DMA_CHANNELS)
      return -EINVAL;
   
     if (xchg(&dma_chan_busy[dmanr].lock, 1) != 0)
      return -EBUSY;
   
     dma_chan_busy[dmanr].device_id = device_id;
   
     /* old flag was 0, now contains 1 to indicate busy */
     return 0;
    } /* request_dma */
   
    /**
     * free_dma - free a reserved system DMA channel
     * @dmanr: DMA channel number
     */
    void free_dma(unsigned int dmanr)
    {
     if (dmanr >= MAX_DMA_CHANNELS) {
      printk(KERN_WARNING "Trying to free DMA%d\n", dmanr);
      return;
     }
   
     if (xchg(&dma_chan_busy[dmanr].lock, 0) == 0) {
      printk(KERN_WARNING "Trying to free free DMA%d\n", dmanr);
      return;
     }
   
    } /* free_dma */
DMA控制器是被dam_spin_lock的自旋锁所保护的!必要的时候我们需要获得和释放
这个自旋锁,内核为我们提供了两个函数来分别完成这个工作:

   extern spinlock_t  dma_spin_lock;
   
   static inline unsigned long claim_dma_lock(void)
   {
    unsigned long flags;
    spin_lock_irqsave(&dma_spin_lock, flags);
    return flags;
   }
该函数用于获取自旋锁,可以看到该函数的调用会阻塞本地处理器上的中断,并将
当前处理器的状态标志值返回。在后面的release_dma_lock中可以看到,在重新打开
中断时必须使用claim_dma_lock返回的标志,重新恢复中断  
   static inline void release_dma_lock(unsigned long flags)
   {
    spin_unlock_irqrestore(&dma_spin_lock, flags);
   }
该函数用于释放DMA 自旋锁,并且恢复处理器以前的中断状态
   
这两个函数位于asm/dma.h之中,在这要必要提一下,我在这使用的内核版本是linux2.6.30.4

接下来我们看一下对DMA控制器的设置。DMA控制器的控制设置信息由RAM地址、传输的数据(
以字节或字为单位)、传输的方向三部分。对这三部分设置就是我们下面将要做的!

linux内核为我们提供了一下几个函数来设置DMA 的控制信息,需要注意的是在使用
这些函数来操作设置DMA控制器时,应该持有自旋锁,但是在驱动程序做I/O操作时,
不能持有自旋锁。

    /* Set the DMA address for this channel
    *
    * This should not be called if a DMA channel is enabled,
    * especially since some DMA architectures don't update the
    * DMA address immediately, but defer it to the enable_dma().
    */
   extern void __set_dma_addr(unsigned int chan, void *addr);
   #define set_dma_addr(chan, addr)    \
    __set_dma_addr(chan, bus_to_virt(addr))
   
   该函数给DMA缓冲区的地址赋值。将总线地址addr的最低24位存储到控制器中。
继承事业,薪火相传
返回列表