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

📄 audio.c

📁 9200下的音频驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
                a9200_rxend = bufcnt;
        }
        else
        {
                slen = (bufcnt - LBUFSIZE) > LBUFSIZE ? LBUFSIZE : (bufcnt - LBUFSIZE);
                a9200_rxend = slen;
        }
        // SSC_CR 
//        DPRINTK(" pdc_ptsr is: %d!\n", pdc_regs->PDC_PTSR);
//        DPRINTK(" ssc_sr is: %d!\n", ssc_regs->SSC_SR);
       ssc_regs->SSC_CR |= AT91C_SSC_RXEN;
//      pdc_regs->PDC_PTCR |= AT91C_PDC_RXTEN;
//	DPRINTK(" pdc_ptsr is: %d!\n", pdc_regs->PDC_PTSR);
//        DPRINTK(" ssc_sr is: %d!\n", ssc_regs->SSC_SR);  
//DPRINTK("pdc_ptsr = %p \n",pdc_regs->PDC_PTSR);

        // rx with irq 
        if(a9200_rxbusy == 0)
        {
                a9200_rxbusy = 1;
                ssc_regs->SSC_IER = AT91C_SSC_RXRDY;// enable RXRDY interrupt 
                tmp = ssc_regs->SSC_RHR;
        }

        DPRINTK("waiting the recording to finish ... \n");

        while(a9200_rxbusy == 1)
        {
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(1);
        }
        DPRINTK("Copy from buflp : %p to appbuflp : %p ,length : %p \n",appbuflp,buflp,4 * slen);
        for(i = 0;i < slen;i++)
        {
                *appbuflp++ = buflp[i];
        }

	// rx with dma
//	a9200_rx_dmabuf();
        bufcnt -= slen;
        if(bufcnt > 0)
                goto tryagain;
                                                                                
        return (count);
}
/**********************************************************
放音函数
***********************************************************/

 static ssize_t at91_audio_write(struct file * file, const char * buf, size_t count,loff_t *ppos)
{
        unsigned long *dp,*buflp;
        unsigned short *bufwp;
        unsigned char *bufbp;
        unsigned int slen,bufcnt,i,s,e;

        
        if(count <= 0)
                return (0);
//待输入的数据缓存的指针
        buflp = (unsigned long *) buf;
        bufwp = (unsigned short *) buf;
        bufbp = (unsigned char *) buf;
                                                                                
        bufcnt = count & ~0x3;   //以4 为单位
        //非立体声或8bits,缓存字节数乘以2
        if(a9200_stereo == 0)
                bufcnt <<= 1;
        if(a9200_bits == 8)
                bufcnt <<= 1;
                                                                                
tryagain:
        s = a9200_dmastart;
        e = a9200_append;
        dp = (unsigned long *) & a9200_buf[e];//dp指向缓存的末尾
        //计算剩余DMA缓存的大小,即每次写操作能处理的数据长度                                                                        
        slen = ((s > e) ? (s - e) : (BUFSIZE - (e - s))) - 4;
	//如果缓存大于需写入的数量,全部写入	
        if(slen > bufcnt)
                slen = bufcnt;
	//如果剩余的缓存跨越头尾,本次操作先写到尾部,下次再重头开始
        if((BUFSIZE - e) < slen)
                slen = BUFSIZE - e;
        //如果没有空闲的DMA缓存,则睡眠等待                                                                      
        if(slen == 0)
        {         //有未决信号
                if(signal_pending(current))
                        return (-ERESTARTSYS);
		    //设置为可中断方式
                set_current_state(TASK_INTERRUPTIBLE);
		   //切换到其他进程,并进入睡眠状态	
                schedule_timeout(1);
		   //定时轮询,直到有空闲的DMA缓存
                goto tryagain;
        }
                                                                                
        if(a9200_stereo)
        {
                if(a9200_bits == 16)
                {
                        for(i = 0;i < slen;i += 4)
                                *dp++ = *buflp++;
                }
                else
                {
                        for(i = 0;i < slen;i += 4)
                        {       //将第一字节复制高16位,将第二个字节复制到低16位
                                *dp++ = (((unsigned long) *bufbp++) << 24) | (((unsigned long) *bufbp++) << 8);
                        }
                }
        }
        else
        {
                if(a9200_bits == 16)
                {
                        for(i = 0;i < slen;i += 4)
                        {
                                *dp++ = (((unsigned long) *bufwp) << 16) | *bufwp;
                                bufwp++;
                        }
                }
                else
                {
                        for(i = 0;i < slen;i += 4)
                        {
                                *dp++ = (((unsigned long) *bufbp) << 24) | (((unsigned long) *bufbp) << 8);
                                bufbp++;
                        }
                }
        }
        //更新尾部指针                                                                        
        e += slen; 
        if(e >= BUFSIZE)
	//回绕
                e = 0;
        a9200_append = e;
		
#if 0
        // SSC Control Register 
	pdc_regs->PDC_PTCR = AT91C_PDC_TXTEN;
        ssc_regs->SSC_CR = AT91C_SSC_TXEN;

        // tx with irq
        if(a9200_txbusy == 0)
        {
                a9200_txbusy++;
                ssc_regs->SSC_IER = AT91C_SSC_TXRDY ;// enable TXRDY interrupt
                ssc_regs->SSC_THR = 0;
        }

#endif

#if 1
	// tx with dma
	a9200_tx_dmabuf();
#endif
      //更新剩余字节数,每次写出slen字节
        bufcnt -= slen;
        if(bufcnt > 0)
                goto tryagain;
        return (count);
}                                                                          

/*
 static ssize_t at91_audio_llseek(struct file * file, const char * buf, size_t cmd,loff_t *ppos)
{
      int val, ret = 0;
        U32 tmpdata;
        U8 lsb, msb;

	switch (cmd) 
	{       
                case REC:
			codec_init(uda1380_rx_init);
                       break;
		 case SOUND:
		 	codec_init(uda1380_tx_init);
                       break;
		 default :
			ret = -EINVAL;
			break;
		
	        
	}

	return ret;
}

*/

/******************************************************
本函数用于启动DMA传输,将数据从用户缓
冲区拷贝到内核缓冲区
*******************************************************/
void __inline__ a9200_tx_dmarun(void)
{
       		
	unsigned long *bp;
	U32 dma_tx_addr;

	
	a9200_dmaing = 1;
	a9200_txbusy = 1;

		
	bp = (unsigned long *) & a9200_buf[a9200_dmastart];
	dma_tx_addr = virt_to_phys((void *)bp);
	AT91F_PDC_SetTx(pdc_regs,(char *)dma_tx_addr,a9200_dmacount/2);
//    AT91F_PDC_SetNextTx(pdc_regs,(char *)dma_tx_addr,a9200_dmacount/2);

        //pdc_regs->PDC_PTCR = AT91C_PDC_TXTDIS;
	pdc_regs->PDC_PTCR = AT91C_PDC_TXTEN;
	ssc_regs->SSC_CR = AT91C_SSC_TXEN;

			
	ssc_regs->SSC_IER =  AT91C_SSC_ENDTX; // endtx interrupt

}

/***************************************************
计算本次DMA传输长度,调整当前DMA缓
存首地址,最后调用DMARUN启动DMA传输
****************************************************/
void a9200_tx_dmabuf(void)
{
         
	// 如果已经启动DMA,则直接返回
	if(a9200_dmaing)
		return;

	// 计算DMA传输数据长度
	a9200_dmacount = (a9200_append >= a9200_appstart) ? (a9200_append - a9200_appstart) : (BUFSIZE - a9200_appstart);
	if(a9200_dmacount > DMASIZE)
		a9200_dmacount = DMASIZE;

	// 调整首地址指针和计数
	a9200_appstart += a9200_dmacount;
	if(a9200_appstart >= BUFSIZE)
		a9200_appstart = 0;
	if(a9200_dmacount > 0)
		a9200_tx_dmarun();
	else
		a9200_txbusy = 0;
	
	
}

void a9200_tx_dmaisr(int irq,void *dev_id,struct pt_regs *regs)
{
       
	 //DPRINTK("I'm in  transfor!...\n");	
	// clear dma interrupt
//        aic_regs->AIC_ICCR = 0x1 << AT91C_ID_SSC1; // clear interrupt
//	ssc_regs->SSC_IDR = AT91C_SSC_ENDTX; // disbale endtx interrupt
//       pdc_regs->PDC_PTCR = AT91C_PDC_TXTDIS;

	a9200_dmaing = 0;

	// update data pointers and counts
	a9200_dmastart += a9200_dmacount;
	if(a9200_dmastart >= BUFSIZE)
		a9200_dmastart = 0;
	       a9200_dmacount = 0;
	// start new dma buffer if we can
	a9200_tx_dmabuf();
	
}


void a9200_txdrain(void)
{
        a9200_txbusy = 0;
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(1);
        return;
                                                                                
        while(!signal_pending(current)) {
                if(a9200_txbusy == 0)
                        break;
        }
}
                                                                                

void unload_tx_ssi()
{
	unregister_sound_dsp(audio_dev_dsp);
}

/*
void unload_rx_ssi()
{
	unregister_sound_mixer(audio_dev_mixer);
}
 */
 
struct file_operations at91_audio_fops = {
      open:at91_audio_open,     /* open */
      release:at91_audio_close,/* release */
      read:at91_audio_read,     /*read*/
      write:at91_audio_write,   /* write */
      ioctl:at91_audio_ioctl,   /* ioctl */
//      llseek:at91_audio_llseek,

};

//struct file_operations at91_mixer_fops = {
//      open:at91_mixer_open,     /* open */
//      release:at91_mixer_close,/* release */
 //     ioctl:at91_mixer_ioctl,   /* ioctl */
//};
                                                                                
static int __init init_ssi(void)
{
	int m;
        SINT32 ok = 0;
                                                                                
        printk("AT91RM9200 audio driver version 0.1, build time:" __TIME__ "\n");

	audio_dev_dsp = register_sound_dsp(&at91_audio_fops, -1);
//	audio_dev_mixer = register_sound_mixer(&at91_mixer_fops, -1);

	//为设备分配内存
        a9200_buf = (unsigned char *) __get_free_pages(GFP_KERNEL,7);
        if(a9200_buf == NULL)
        	{
        	     printk("a9200:failed to allocate DMA buffer\n");
        	}
	//申请中断	
        if( request_irq(AT91C_ID_SSC1,at91_audio_interrupt, SA_INTERRUPT, "SSC", NULL) < 0 )
//       if( request_irq(AT91C_ID_SYS, ssc_interrupt_handler,  SA_SHIRQ, "SSC", NULL) < 0 )			
                printk("SSC interrupt handler request failed!\n");
		
	else
		DPRINTK("request irq succeed...\n");
	
        AT91_PIO_SSC_Set();
        SSC_init();
        port_init_I2C();
		
        /*Configure the CODEC to Default status */
 //	codec_init(uda1380_tx_init);
	printk("I'm ready now,9200!... \n");

	 return ok;
}



static void __exit cleanup_ssi(void)
{
        
        codec_init(uda1380_init);
        if (a9200_buf)
                free_pages((void *) a9200_buf, 7); // 512K
	free_irq(AT91C_ID_SSC1,NULL);
//	free_irq(AT91C_ID_SYS,NULL);

	unload_tx_ssi();
//	unload_rx_ssi();
       codec_init(uda1380_init);
       printk("Good bye,9200,I'll be back!...\n");

}

																			   
MODULE_AUTHOR("WELL");
MODULE_DESCRIPTION("SSI-Low Level Audio Device Driver");
                                                                              
module_init(init_ssi);
module_exit(cleanup_ssi);

                                                                                


⌨️ 快捷键说明

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