⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at91_pdc.h

📁 H9200F(2.6.12)的音频接口驱动。 操作方法: 1、将驱动程序rsound.ko拷贝到系统目录:/lib/modules 2、执行如下命令加载模块: insmod /
💻 H
字号:
/*----------------------------------------------------------
**	linux/drivers/at91/at91_pdc.h(DMA)
**		
**
**	Copyright (C) 2006 Hyesco Technology Co.,Ltd
**
**	Author: casiawu <wujh@hyesco.com>
**
**	History:
**
**	2006.4   casiawu  <wujh@hyesco.com>
**               Original version
**---------------------------------------------------------*/

#ifndef __AT91_PDC_H_
#define __AT91_PDC_H_

#include <linux/types.h>
#include <linux/dma-mapping.h>
#include <asm/semaphore.h>
#include <asm/mach-types.h>

#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/AT91RM9200_PDC.h>
#include <asm/irq.h>

#undef DEBUG 
//#define DEBUG 1 
#ifdef DEBUG
#define DPRINTK( x... )  printk(x)
#else
#define DPRINTK( x... )
#endif


#define dma_regs_t AT91PS_PDC

/* Maximum physical DMA buffer size */
//#define MAX_DMA_SIZE		(16*1024)

/* Typedefs for integer types */
typedef unsigned char U8;	           /* unsigned 8 bit data  */
typedef unsigned short U16;	         /* unsigned 16 bit data */
typedef unsigned long U32;	         /* unsigned 32 bit data */
typedef signed char S8;		           /* signed 8 bit data    */
typedef short S16;		               /* signed 16 bit data   */
typedef long  S32;		               /* signed 32 bit data   */

typedef void (*dma_callback_t)( void *buf_id, int size );
typedef void (*dma_readstat_t)( U8 * size );
typedef void (*dma_irq_t)( U8 size );


/*
 * DMA buffer structure
 */

typedef struct dma_buf_s {
	U32 size;		                        /* buffer size */
	dma_addr_t dma_start;	              /* starting DMA address */
	dma_addr_t dma_ptr;	                /* next DMA pointer to use */
	void *id;		                        /* to identify buffer from outside */
	struct dma_buf_s *next;	            /* next buffer to process */
} dma_buf_t;


/*
 * DMA channel structure.
 */

typedef struct {
	dma_buf_t *head;	                  /* where to insert buffers */
	dma_buf_t *tail;	                  /* where to remove buffers */
	dma_buf_t *curr;	                  /* buffer currently DMA'ed */
	dma_regs_t regs;	                  /* points to appropriate DMA registers */
	dma_irq_t  irq_on_off;              /* ... enable or disable irq */	
	dma_callback_t callback;            /* ... to call when buffers are done */		 
	U8 flag;                            /* 0 : wtite dma channel; 1: read dma channel */	
	U8 type;                            /* dma transmit type,1 : byte; 2: half word 4: word*/	
	U8 dma_channel;	                    /* dma channel,0 : 1 : 2 */
} at91rm9200_dma_t;


/*
 * DMA channel user state stucture
 */
typedef struct {
	U32 in_use;	                        /* Device is allocated */
	const char  * device_id;	          /* Device name */	
	U8 irq;		                          /* IRQ used by the channel */	 
	at91rm9200_dma_t* out_chan;         /* DMA output channel      */
	at91rm9200_dma_t* in_chan;         /* DMA output channel       */
	dma_readstat_t readstatback ;       /* read device status  reg */ 
} at91rm9200_dma_state_t;
	
 
/*-----------------------------------------------------
 * Name :      at91rm9200_start_dma()
 * Function:   Process the dma transmition  
 * Last rework data: 06-04-13   wujh@hyesco.com
 *----------------------------------------------------*/

static int at91rm9200_start_dma(at91rm9200_dma_t * dma, dma_buf_t *buf1, dma_buf_t *buf2, int flag)
{
	 dma_regs_t regs = dma->regs;
	 U8 channel = dma->flag ;
	 int type=0;
	 
	 type = dma->type;
	 
	 DPRINTK("coming into at91rm9200_start_dma\n\r");
	 
	 //rx
	 if(channel)	 
	 {
	 	if(buf2 != NULL)
	 	{
			regs->PDC_RPR  = buf1->dma_ptr;
   	  regs->PDC_RCR  = buf1->size / type;
   	  regs->PDC_RNPR = buf2->dma_ptr;
   	  regs->PDC_RNCR = buf2->size / type;   	  	 		
	  }
	  else
	  {
	  	if(flag == 2)
	  	{
	  		regs->PDC_RPR  = buf1->dma_ptr;
   	  	regs->PDC_RCR  = buf1->size / type;
   	  }
   	  else
   	  {
	  		regs->PDC_RNPR  = buf1->dma_ptr;
   	  	regs->PDC_RNCR  = buf1->size / type;   	  	
   	  }
	  }
	 }
	 //tx
	 else
	 {
	 	if(buf2 != NULL)
	 	{
			regs->PDC_TPR  = buf1->dma_ptr;
   	  regs->PDC_TCR  = buf1->size / type;
   	  regs->PDC_TNPR = buf2->dma_ptr;
   	  regs->PDC_TNCR = buf2->size / type;   	  	 		
	  }
	  else
	  {
	  	if(flag == 2)
	  	{
	  		regs->PDC_TPR  = buf1->dma_ptr;
   	  	regs->PDC_TCR  = buf1->size / type;
   	  }
   	  else
   	  {
	  		regs->PDC_TNPR  = buf1->dma_ptr;
   	  	regs->PDC_TNCR  = buf1->size / type;   	  	
   	  }
	  } 	
	 }
	 wmb();
   if ((dma->irq_on_off) && (flag == 2))
   	dma->irq_on_off(1);  

	 return 0;
}


/*-----------------------------------------------------
 * Name :      process_dma()
 * Function:   Set the callback function for dma 
 * Last rework data: 06-04-13   wujh@hyesco.com
 *----------------------------------------------------*/

/* This must be called with IRQ disabled */
static void process_dma(at91rm9200_dma_t * dma)
{
	 dma_buf_t *buf;
	 int type=0;
	 
	 type = dma->type;

	 DPRINTK("coming into process_dma\n\r");

	for (;;) {
		buf = dma->tail;

		if (buf == NULL )     break;    // exit the cycle

		/*
		 * Let's try to start DMA on the current buffer.
		 * If DMA is busy then we break here.
		*/
		
		switch(dma->dma_channel)
		{
			case 2:
				if(buf->next == NULL)
				{
					at91rm9200_start_dma(dma, buf,NULL,2);
					dma->tail = buf->next;
				}
				else
				{
					at91rm9200_start_dma(dma, buf,buf->next,2);
					dma->tail = buf->next->next;
				}
				dma->dma_channel = 0;
				break;
				
			case 1:
					at91rm9200_start_dma(dma, buf,NULL,1);
					dma->tail = buf->next;
					dma->dma_channel = 0;
				break;
				
			case 0:
			default:
				return;
		}

		if (!dma->curr)
			dma->curr = buf;
	}
	
   DPRINTK("exit process_dma\n\r");
}


/*-----------------------------------------------------
 * Name :      at91rm9200_dma_done()
 * Function:   Do some addition work after the transmit have done 
 * Last rework data: 06-04-13   wujh@hyesco.com
 *----------------------------------------------------*/

void at91rm9200_dma_done(at91rm9200_dma_t *dma)
{
	 dma_buf_t *buf = dma->curr;
	 
	 DPRINTK("coming into at91rm9200_dma_done\n\r");	 
   
	 if ((dma->irq_on_off) &&(dma->dma_channel == 2))
   	dma->irq_on_off(0);  
   
	 if (buf != NULL) 
   {
		 /*
		  * Current buffer is done.
			* Move current reference to the next one and send
			* the processed buffer to the callback function,
			* then discard it.
			*/
			dma->curr = buf->next;
			if (dma->head == buf)
				dma->head = NULL;
			if (dma->callback) 
			{
				dma->callback(buf->id, buf->size);
			}
			kfree(buf);
	}

	wmb();
	process_dma(dma);
}


/*-----------------------------------------------------
 * Name :      at91rm9200_dma_queue_buffer()
 * Function:   Place the buffer to DMA handle queue 
 * Last rework data: 06-04-13   wujh@hyesco.com
 *----------------------------------------------------*/

int at91rm9200_dma_queue_buffer(at91rm9200_dma_t *dma, void *buf_id,
			    dma_addr_t data, int size)
{
	 dma_buf_t *buf;
	 int flags;

	 DPRINTK("at91rm9200_dma_queue_buffer\n\r");

	 buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
	 if (!buf)
		return -ENOMEM;

	 buf->next = NULL;
	 buf->dma_ptr = buf->dma_start = data;
	 buf->size = size;
	 buf->id = buf_id;

	 local_irq_save(flags);
	 
	 if (dma->head)
	 dma->head->next = buf;

	 dma->head = buf;
	 
	 if (!dma->tail)
	 dma->tail = buf;
	 
	 wmb();
	 
	 process_dma(dma);
	 local_irq_restore(flags);

	 return 0;
}


/*-----------------------------------------------------
 * Name :      at91rm9200_dma_flush_all()
 * Function:   flush out at91rm9200_dma_t struct before free it
 * Last rework data: 06-04-13   wujh@hyesco.com
 *----------------------------------------------------*/
 
int at91rm9200_dma_flush_all(at91rm9200_dma_t *dma)
{
    int flags;
    dma_buf_t *buf, *next_buf;
    
	  DPRINTK("at91rm9200_dma_flush_all\n\r");    

	  local_irq_save(flags);
		
	  buf = dma->curr;
	  if (!buf)
		  buf = dma->tail;
	  
	  dma->head = dma->tail = dma->curr = NULL;
	  //process_dma(dma);
	  
	  local_irq_restore(flags);
	
	  while (buf) {
		next_buf = buf->next;
		kfree(buf);
		buf = next_buf;
	 }

	 return 0;
}


/*-----------------------------------------------------
 * Name :      dma_irq_handler()
 * Function:   dma irq servive function
 * Last rework data: 06-04-13   wujh@hyesco.com
 *----------------------------------------------------*/

static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{   
    at91rm9200_dma_state_t *state = (at91rm9200_dma_state_t *) dev_id;
    U8 status = 0;   
    
    DPRINTK("dma_irq_handler\n\r"); 
                      
    if(state->readstatback)
    state->readstatback(&status);  
          
    switch(status)
    {
        case 1:
              state->out_chan -> dma_channel = 1;        	
              at91rm9200_dma_done (state->out_chan);
        break;
        
        case 2:
              state->out_chan -> dma_channel = 2;         	
              at91rm9200_dma_done (state->out_chan);
        break;
     
        case 3:
              state->in_chan -> dma_channel = 1;         	
       		    at91rm9200_dma_done (state->in_chan);    		    
        break;  

        case 4:
              state->in_chan -> dma_channel = 2;         	
       		    at91rm9200_dma_done (state->in_chan);    		    
        break;           		  
          		   
        default:
  	    break;
           	     
    } 
		
  return IRQ_HANDLED;       	   
}


/*-----------------------------------------------------
 * Name :      at91rm9200_dma_init()
 * Function:   Init the at91rm9200_dma_t struct for the device 
 * Last rework data: 06-04-13   wujh@hyesco.com
 *----------------------------------------------------*/
 
int at91rm9200_dma_init(at91rm9200_dma_state_t *state)
{
	  int err = 0;
	  
	  state->in_use = 1;
	  
	  DPRINTK("at91rm9200_dma_init\n\r"); 	  
	  
	  err = request_irq(state->irq, dma_irq_handler, SA_INTERRUPT,
			  state->device_id, (void *) state);
			  
	  if (err) {
		    printk(KERN_ERR
		       "%s: unable to request IRQ %d for DMA channel\n",
		       state->device_id, state->irq);
		    return err;
	  }

	  return 0;	  
}

/*-----------------------------------------------------
 * Name :      at91rm9200_free_dma()
 * Function:   free the dma irq for the device 
 * Last rework data: 06-04-13   wujh@hyesco.com
 *----------------------------------------------------*/

void at91rm9200_free_dma(at91rm9200_dma_state_t *state)
{
	 if (!state->in_use) {
		 //printk(KERN_ERR "Trying to free free DMA%d\n", state->irq);
		 return;
	 }

	 DPRINTK("at91rm9200_free_dma\n\r"); 

	 at91rm9200_dma_flush_all(state->out_chan);
	 at91rm9200_dma_flush_all(state->in_chan);	 
	 
	 free_irq(state->irq, (void *) state);
	
	 state->in_use = 0;

}


#endif // __AT91_PDC_H_

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -