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

📄 ev44b0_sound.c

📁 s3c44b0下uclinux下
💻 C
字号:
/*------------------------------------------------------------------------ . ev44b0_sound.c . . This is a sound driver for Philips's UDA1341 device. . . (C) Copyright 2003 . MICETEK International Inc., Shanghai China . Qin Wei <king@micetek.com.cn> . . . This program is free software; you can redistribute it and/or modify . it under the terms of the GNU General Public License as published by . the Free Software Foundation; either version 2 of the License, or . (at your option) any later version. . . This program is distributed in the hope that it will be useful, . but WITHOUT ANY WARRANTY; without even the implied warranty of . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the . GNU General Public License for more details. . . You should have received a copy of the GNU General Public License . along with this program; if not, write to the Free Software . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA . . . author: .  Qin Wei                     ( king@micetek.com.cn ) . History: .  01/22/03  Qin Wei ----------------------------------------------------------------------------*/#include <linux/module.h>#include <linux/types.h>#include <linux/wait.h>#include <linux/fs.h>#include <linux/sched.h>#include <linux/poll.h>#include <linux/miscdevice.h>#include <linux/init.h>#include <linux/compiler.h>#include <linux/interrupt.h>#include <linux/sound.h>#include <linux/soundcard.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/hardware.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/pm.h>#include <linux/errno.h>#include <asm/dma.h>#include "ev44b0_sound.h"#define EV44B0II_SOUND_MODULE_NAME    "audio"static const char sound_driver_version[] =	"EV44B0II Sound driver v1.0 (2003-01-22) Qinwei, MICETEK Shanghai";static char *bmda0_id = "BDMA0 (audio)"; static volatile unsigned int DMA_Done = 1;extern int Init1341(char mode );void l3_ev44b0_send_byte(unsigned char , unsigned char );void l3_ev44b0_send_ext_byte(unsigned char , unsigned char ,unsigned char );static int sound_cpu_init(void){    return 0;  }/* * Interrupt sevices */static void irq_sound(int irq, void *dev_id, struct pt_regs *regs){    DMA_Done = 1;}static audio_mix_t audio_mix = {    OGS       : 1,    IGS       : 1,    volume    : 0,    BassBoost : 0,    Treble    : 0,    mute      : 0,    mode      : 0,    EXTADDR   : 0,    EXTDATA   : 0,};static audio_state_t audio_state = {	mix        : &audio_mix,    used       : 0,	write_count: 0,	read_count : 0,	status     : 0,};#define AUDIO_READ  1#define AUDIO_WRITE 0/* * File operation */static int ev44b0ii_sound_open(struct inode *inode, struct file *filp){    int err = -EBUSY;        filp->private_data = (void *)&audio_state;    if (audio_state.used)        return err;        err =0;	MOD_INC_USE_COUNT;	DMA_Done = 1; // set start status.	if ((filp->f_mode & FMODE_WRITE)) 	{	    audio_state.used = 1;	    audio_state.status = AUDIO_WRITE;	    Init1341(0);	    return err;	}		if ((filp->f_mode & FMODE_READ)) 	{	    audio_state.used = 1;	    audio_state.status = AUDIO_READ;	    Init1341(1);    	    return err;	}	return err;}/* It is playback to external world*/static ssize_tev44b0ii_sound_write(struct file *filp, const char *buf, size_t count, loff_t *ppos){    unsigned int dma_addr;    struct audio_state_s *dev = (struct audio_state_s *)filp->private_data;        if ( !(filp->f_mode & FMODE_WRITE))        return -EINVAL;        while ( DMA_Done == 0 ) // must wait last voice ok.    {        if ( filp->f_flags & O_NONBLOCK )		    return -EAGAIN;              }        /* Aligment to half word*/    count &= 0xfffffffe;    dma_addr = (unsigned int) buf;    dma_addr = (dma_addr + 1) & 0xfffffffe;//    Init1341(0);    //    rBDISRC0=(1<<30)+(1<<28)+ dma_addr;	//Half word,inc,Buf    CSR_WRITE(rBDISRC0,(1<<30)+(1<<28)+ dma_addr );    
//    rBDIDES0=(1<<30)+(3<<28)+ (unsigned int)(rIISFIF);	//M2IO,fix,IISFIF
    CSR_WRITE(rBDIDES0,(1<<30)+(3<<28)+ (unsigned int)(rIISFIF) );    //    rBDICNT0=(1<<30)+(1<<26)+(3<<22)+(1<<21)+(1<<20)+count;// IIS,INT when count, Auto load&start,Enable, 
    CSR_WRITE(rBDICNT0,(1<<30)+(1<<26)+(3<<22)+(0<<21)+(1<<20)+count ); // IIS,INT when count, no Auto load&start,Enable, //    rBDCON0 = 0x0<<2; // Enable DMA
    CSR_WRITE(rBDCON0,0x0<<2 );    
        /****** IIS Initialize ******/
#if (AUDIO_CODEC_CLOCK == 256)          //    rIISMOD=0x89;	//Master,Tx,L-ch=low,iis,16bit ch.,codeclk=256fs,lrck=32fs    CSR_WRITE(rIISMOD ,0x89 );#else//    rIISMOD=0x8D;	//Master,Tx,L-ch=low,iis,16bit ch.,codeclk=384fs,lrck=32fs    CSR_WRITE(rIISMOD ,0x8D );#endif
//    rIISPSR=0x33;	//Prescaler_A/B enable, value=3, already set in init and open function
//    rIISFCON=0xa00;	//Tx/Rx DMA,Tx/Rx FIFO --> start piling....    CSR_WRITE(rIISFCON , 0xa00);
    DMA_Done = 0;//    rIISCON=0x22;	//Tx DMA enable,Rx idle,prescaler enable//    rIISCON |=0x1; // start    CSR_WRITE(rIISCON ,0x23 );
        dev->write_count += count;    return count;}/* It is Rec from external world*/static ssize_t ev44b0ii_sound_read(struct file *filp, char *buf, size_t count, loff_t *l){    struct audio_state_s *dev = (struct audio_state_s *)filp->private_data;    unsigned int dma_addr;        if ( !(filp->f_mode & FMODE_READ))        return -EINVAL;   //    Init1341(1);    /* Aligment to half word*/    count &= 0xfffffffe;    dma_addr = (unsigned int) buf;    dma_addr = (dma_addr + 1) & 0xfffffffe;    
    /****** BDMA0 Initialize ******/

//    rBDISRC0=(1<<30)+(3<<28)+(unsigned int)rIISFIF;	//Half word,fix,IISFIF    CSR_WRITE(rBDISRC0,(1<<30)+(3<<28)+(unsigned int)rIISFIF);
//    rBDIDES0=(2<<30)+(1<<28)+ dma_addr;	//IO2M,inc , Buf
    CSR_WRITE(rBDIDES0,(2<<30)+(1<<28)+ dma_addr);//    rBDICNT0=(1<<30)+(1<<26)+(3<<22)+(1<<21)+(1<<20)+count; // IIS,INT when count, Auto load&start,Enable,     CSR_WRITE(rBDICNT0,(1<<30)+(1<<26)+(3<<22)+(0<<21)+(1<<20)+count); // IIS,INT when count, no Auto load&start,Enable, 
//    rBDCON0 = 0x0<<2; // Enable DMA    CSR_WRITE(rBDCON0,0x0<<2);
  
    /****** IIS Initialize ******/
#if (AUDIO_CODEC_CLOCK == 256)          //   rIISMOD =0x49;	//Master,Tx,L-ch=low,iis,16bit ch.,codeclk=256fs,lrck=32fs    CSR_WRITE(rIISMOD,0x49);#else//    rIISMOD =0x4D;	//Master,Tx,L-ch=low,iis,16bit ch.,codeclk=384fs,lrck=32fs    CSR_WRITE(rIISMOD,0x4D);#endif
//    rIISPSR =0x33;	//Prescaler_A/B enable, value=3 , and already set on init and open function
//    rIISFCON=0x500;	//Tx/Rx DMA,Tx/Rx FIFO --> start piling....    CSR_WRITE(rIISFCON,0x500);        DMA_Done = 0;    
    //--- Rx start
//    rIISCON =0x1a;	//Rx DMA enable,Rx idle,prescaler enable//    rIISCON |=0x1;    CSR_WRITE(rIISCON,0x1B);
    while ( DMA_Done == 0 ) // must wait last voice ok.    {        if ( filp->f_flags & O_NONBLOCK )		        return -EAGAIN;              }    dev->read_count += count;    return count;}static int ev44b0ii_sound_release(struct inode *inode, struct file *filp){    struct audio_state_s *dev = (struct audio_state_s *)filp->private_data;    	if ((filp->f_mode & FMODE_WRITE)) 	{	    dev->used = 0;	    dev->status = 2;	}	if ((filp->f_mode & FMODE_READ)) 	{	    dev->used = 0;	    dev->status = 2;	}	MOD_DEC_USE_COUNT;		/*cancel the DMA*/	CSR_WRITE(rBDCON0,0x3 | 1<<2 ); 	/*Disable IIS*/    CSR_WRITE(rIISCON,0xC);    DMA_Done = 0;	return 0;}static intmixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg){    struct audio_mix *setmix;    struct audio_state_s *dev = (struct audio_state_s *)file->private_data;    unsigned char mode =0,bt= 0;	/*	 * We only accept mixer (type 'M') ioctls.	 */	if (_IOC_TYPE(cmd) != 'M')		return -EINVAL;    setmix  = (struct audio_mix *)arg;    if ((setmix->EXTADDR != 0) && (setmix->EXTDATA != 0))    {        setmix->EXTDATA = (setmix->EXTDATA & 0x1f) + 0xe0;        setmix->EXTADDR = (setmix->EXTADDR & 0x07) + 0xc0;        l3_ev44b0_send_ext_byte(0x14+0,setmix->EXTADDR,setmix->EXTDATA);    }    if (setmix->mode != dev->mix->mode)    {        setmix->mode  &= 0x3;        dev->mix->mode = setmix->mode;        mode = mode | setmix->mode | 0xA0;    }    if (setmix->mute != dev->mix->mute)    {        setmix->mute &= 0x1;        dev->mix->mute = setmix->mute;        mode = mode | (setmix->mute << 2) | 0xA0;    }    if (mode)        l3_ev44b0_send_byte(0x14+0,mode);        if (setmix->volume != dev->mix->volume)    {        setmix->volume &= 0x3f;        dev->mix->volume = setmix->volume;        l3_ev44b0_send_byte(0x14+0,setmix->volume);    }    if (setmix->BassBoost != dev->mix->BassBoost)    {        setmix->BassBoost &= 0xf;        dev->mix->BassBoost = setmix->BassBoost;        bt = bt | (setmix->BassBoost << 2) | 0x40;    }    if (setmix->Treble != dev->mix->Treble)    {        setmix->Treble &= 0x3;        dev->mix->Treble = setmix->Treble;        bt = bt | (setmix->Treble << 0) | 0x40;    }    if (bt)        l3_ev44b0_send_byte(0x14+0,bt);	return 0;}static int ev44b0ii_sound_ioctl(struct inode *inode, struct file *filp,		unsigned int cmd, unsigned long arg){	long val = 0;	int ret = 0;	switch (cmd) {	case SNDCTL_DSP_STEREO:		ret = get_user(val, (int *) arg);		if (ret)			return ret;		/* the UDA1341 is stereo only */		ret = (val == 0) ? -EINVAL : 1;		return put_user(ret, (int *) arg);	case SNDCTL_DSP_CHANNELS:	case SOUND_PCM_READ_CHANNELS:		/* the UDA1341 is stereo only */		return put_user(2, (long *) arg);	case SNDCTL_DSP_SPEED:		ret = get_user(val, (long *) arg);		if (ret) break;		if (val < 8000) val = 8000;		if (val > 44100) val = 44100;/* For example * my wav file 8.0 khz sampling rate. * codeclk is 384fs = 8.0*384 = 3.0720Mhz * IISPSR : *        Prescaler control A  :  PCLK / ( N +1) = 3.072 Mhz   *                                N = 60/3.072 = 19.5 *        Prescaler control B  : A=B could be  *   */		switch(val) {		case 8000:#if (AUDIO_CODEC_CLOCK == 256)        	        CSR_WRITE(rIISPSR,(6<<4)+6); /*System clock too high, so set a vaule on hand*/#else	        CSR_WRITE(rIISPSR,(6<<4)+6); /*System clock too high, so set a vaule on hand*/#endif			break;		case 11025:#if (AUDIO_CODEC_CLOCK == 256)        	        CSR_WRITE(rIISPSR,(6<<4)+6);  /*System clock too high, so set a vaule on hand*/#else	        CSR_WRITE(rIISPSR,(6<<4)+6); /*Should be 14, and register vaule is 6*/#endif			break;		case 22050:#if (AUDIO_CODEC_CLOCK == 256)        		    CSR_WRITE(rIISPSR,(4<<4)+4);      /*Should be 10.6 , the register is 4*/#else 			CSR_WRITE(rIISPSR,(0xe<<4)+0xe);	 /*Should be 7, and the register vaule is 0xe*/#endif			break;		case 44100:#if (AUDIO_CODEC_CLOCK == 256)        		    CSR_WRITE(rIISPSR,(0xc<<4)+0xc);	/*Should be 5.31, the register is 0xc*/#else			CSR_WRITE(rIISPSR,(1<<4)+1);   /*Should be 3.5, and the register vaule is 0x1*/#endif                			break;		default:#if (AUDIO_CODEC_CLOCK == 256)        		    CSR_WRITE(rIISPSR,(4<<4)+4);#else			CSR_WRITE(rIISPSR,(6<<4)+6);#endif                			break;		} 	case SOUND_PCM_READ_RATE: /* I am n't sure what it is  */		return put_user(val , (long *) arg);	case SNDCTL_DSP_SETFMT:	case SNDCTL_DSP_GETFMTS:	        /*printk("%s[%d] %s : DSP_SAMPLESIZE  \n", __FILE__,__LINE__,__FUNCTION__); */		/* we can do 16-bit only */		return put_user(AFMT_S16_LE, (long *) arg);	default:		/* Maybe this is meant for the mixer (as per OSS Docs) */		return mixer_ioctl(inode, filp, cmd, arg);	}	return ret;}static unsigned int ev44b0ii_sound_poll(struct file *filp, poll_table *wait){//  struct audio_state_s *dev = (struct audio_state_s *)file->private_data;	return (POLLIN | POLLRDNORM);}static loff_t  ev44b0ii_sound_llseek(struct file *file, loff_t offset, int origin){	return -ESPIPE;}static struct file_operations ev44b0ii_sound_fops = {	owner:		THIS_MODULE,	read:		ev44b0ii_sound_read,	write:      ev44b0ii_sound_write,	poll:		ev44b0ii_sound_poll,	ioctl:		ev44b0ii_sound_ioctl,	open:		ev44b0ii_sound_open,	release:	ev44b0ii_sound_release,	llseek:     ev44b0ii_sound_llseek,};/* * Module install */int __init ev44b0ii_sound_init_module(void){    sound_cpu_init();#if 1    #if (AUDIO_CODEC_CLOCK == 256)            		    CSR_WRITE(rIISPSR,(4<<4)+4);      /*Should be 10.6 , the register is 4*/    #else     			CSR_WRITE(rIISPSR,(0xe<<4)+0xe);	 /*Should be 7, and the register vaule is 0xe*/    #endif#else    #if (AUDIO_CODEC_CLOCK == 256)                CSR_WRITE(rIISPSR,(0xc<<4)+0xc);	/*Should be 5.31, the register is 0xc*/    #else    	CSR_WRITE(rIISPSR,(1<<4)+1);        /*Should be 3.5, and the register vaule is 0x1*/    #endif                #endif    if ( 0 != devfs_register_chrdev(SOUND_MAJOR, EV44B0II_SOUND_MODULE_NAME, &ev44b0ii_sound_fops))    {        printk(__FUNCTION__ ": can't get major number\n");        return -1;	}   	if ( 0 != request_irq(INT_BDMA0, irq_sound ,SA_INTERRUPT,bmda0_id, NULL))    	{		printk(KERN_WARNING "ev44b0ii_sound: failed to get IRQ\n");		return 1;	}    printk("%s\n",sound_driver_version);    	return 0;}void __exit ev44b0ii_sound_cleanup_module(void){	printk(__FUNCTION__ ": EV44B0II Sound Exit.\n");    free_irq(INT_BDMA0,bmda0_id);	devfs_unregister_chrdev(SOUND_MAJOR, EV44B0II_SOUND_MODULE_NAME);}module_init(ev44b0ii_sound_init_module);module_exit(ev44b0ii_sound_cleanup_module);MODULE_DESCRIPTION("EV44B0-II Sound(UDA1341) driver");MODULE_AUTHOR("Qin Wei <king@micetek.com.cn>");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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