📄 ev44b0_sound.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 + -