📄 em8xxx_oss.c
字号:
/***************************************** Copyright 2004-2005 Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//** @file em8xxx_oss.c @brief OSS sound driver for em8xxx series. @author Yoann Walther @date 2005-07-12*/#include "em8xxxoss.h"static u_long audio_capture_index; static u_long audio_decoder_index=1;static u_long audio_engine_index;static u_long audio_mmID = 0;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)module_param(audio_decoder_index, ulong,0);module_param(audio_mmID, ulong,0);#elseMODULE_PARM(audio_decoder_index, "l");MODULE_PARM(audio_mmID, "l");#endifMODULE_PARM_DESC(audio_decoder_index, "Audio Decoder in use\n");MODULE_PARM_DESC(audio_mmID, "Audio Memory Manager in use\n");MODULE_DESCRIPTION("EM8XXX Sound OSS Driver");MODULE_AUTHOR("Yoann Walther <yoann_walther@sdesigns.eu>");#ifdef MODULE_LICENSEMODULE_LICENSE("Proprietary");#endifextern struct em8xxxprivate Etable[MAXLLAD];RMstatus krua_register_event_callback(void *pE,RMuint32 ModuleID,RMuint32 mask, Event_callback callback);RMstatus krua_unregister_event_callback(void *pE,RMuint32 ModuleID,Event_callback callback);static RMstatus prepare_data(struct sndprivate *pS);static RMuint32 bytes_to_samples(struct sndprivate *pS,RMuint32 count);static RMstatus start_capture(struct em8xxxprivate *pE);static RMstatus start_playback(struct em8xxxprivate *pE);/* mixer file operations */static int rm_open_mixer(struct inode *inode, struct file *file);static int rm_release_mixer(struct inode *inode, struct file *file);static int rm_ioctl_mixer(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int process_ioctl_mixer(struct em8xxxprivate *pE, unsigned int cmd, unsigned long arg);static struct file_operations rm_mixer_fops = { owner: THIS_MODULE, ioctl: rm_ioctl_mixer, open: rm_open_mixer, release: rm_release_mixer,};/* dsp file operations */static ssize_t rm_read_dsp(struct file *file, char *buffer, size_t count, loff_t *ppos);static ssize_t rm_write_dsp(struct file *file, const char *buffer, size_t count, loff_t *ppos);static unsigned int rm_poll_dsp(struct file *file, struct poll_table_struct *wait);static int rm_mmap_dsp(struct file *file, struct vm_area_struct *vma);static int rm_ioctl_dsp(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int rm_open_dsp(struct inode *inode, struct file *file);static int rm_release_dsp(struct inode *inode, struct file *file);static int process_ioctl_dsp(struct sndprivate *pS, unsigned int cmd, unsigned long arg);//static RMstatus set_audio_parameters(struct em8xxxprivate *pE, int format, int sampleRate, int channelCount);static RMstatus init_audio(struct sndprivate *pS);static RMstatus cleanup_audio(struct sndprivate *pS);static int rm_free_ptr(struct em8xxxprivate *pE,RMuint32 ptr);static /*const*/ struct file_operations rm_dsp_fops = { // this replaces MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT pain owner: THIS_MODULE, read: rm_read_dsp, write: rm_write_dsp, poll: rm_poll_dsp, ioctl: rm_ioctl_dsp, mmap: rm_mmap_dsp, open: rm_open_dsp, release: rm_release_dsp,};static int sndprivate_init(struct em8xxxprivate *pE){ struct sndprivate *pS=Stable+(pE-Etable); if (pS->sndprivate_active == 0) { memset(pS,0,sizeof(struct sndprivate)); if ((pS->mixer_dev = register_sound_mixer(&rm_mixer_fops, -1)) < 0) { printk("Cannot register em8xxx sound mixer device\n"); goto error_mixer; } if ((pS->dsp_dev = register_sound_dsp(&rm_dsp_fops, -1)) < 0) { printk("Cannot register em8xxx sound dsp device\n"); goto error_dsp; } } else { printk("em8xxx sound driver (/dev/mixer%d, /dev/dsp%d) already registered\n", pS->mixer_dev, pS->dsp_dev); return -EINVAL; } pS->sndprivate_active = 1; printk("em8xxx sound driver (/dev/mixer%d, /dev/dsp%d) registered.\n", pS->mixer_dev, pS->dsp_dev); return 0; error_dsp: unregister_sound_mixer(pS->mixer_dev); error_mixer: return -EINVAL;}static int sndprivate_cleanup(struct em8xxxprivate *pE){ struct sndprivate *pS=Stable+(pE-Etable); // unregister dsp & mixer if (pS->sndprivate_active == 1) { if ((pS->mixer_open_count == 0) && (pS->dsp_open_count == 0)) { unregister_sound_mixer(pS->mixer_dev); unregister_sound_dsp(pS->dsp_dev); } else { if (pS->mixer_open_count > 0) printk("cannot unregistered (/dev/mixer%d). device is opened %d times\n", pS->mixer_dev, pS->mixer_open_count); if (pS->dsp_open_count > 0) printk("cannot unregistered (/dev/dsp%d). device is opened %d times\n", pS->dsp_dev, pS->dsp_open_count); return -EINVAL; } } else { printk("no em8xxx sound mixer device registered\n"); return -EINVAL; } printk("em8xxx sound mixer (/dev/mixer%d, /dev/dsp%d) unregistered\n", pS->mixer_dev, pS->dsp_dev); pS->sndprivate_active = 0; return 0;}////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MIXER FILE OPERATIONS ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////static int rm_open_mixer(struct inode *inode, struct file *file){ int i; int minor = MINOR(inode->i_rdev); struct em8xxxprivate *pE = (struct em8xxxprivate *) NULL; struct sndprivate *pS = (struct sndprivate *) NULL; for (i=0 ; i<MAXLLAD ; i++) { pE = &Etable[i]; pS = Stable+(pE-Etable); if (pS->sndprivate_active == 1) { if (pS->mixer_dev == minor) break; } } if (i == MAXLLAD) { // can't find corresponding realmagic device printk("Cannot open em8xxx sound mixer device\n"); return -EINVAL; } printk("Opens em8xxx sound mixer (/dev/mixer%d)\n", minor); pS->mixer_open_count ++; file->private_data = pS; return 0;}static int rm_release_mixer(struct inode *inode, struct file *file){ struct sndprivate *pS=(struct sndprivate *)file->private_data; struct em8xxxprivate *pE; pE=Etable+(pS-Stable); printk("closes em8xxx sound mixer (/dev/mixer%d)\n", pS->mixer_dev); if(pS->mixer_open_count) pS->mixer_open_count --; return 0;}static int rm_ioctl_mixer(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct sndprivate *pS=(struct sndprivate *)file->private_data; struct em8xxxprivate *pE=Etable+(pS-Stable); int rc; rc = process_ioctl_mixer(pE, cmd, arg); return rc;}static int process_ioctl_mixer(struct em8xxxprivate *pE, unsigned int cmd, unsigned long arg){ int val, i,volume_index; int r,l; int rc = -EINVAL; struct sndprivate *pS=Stable+(pE-Etable); struct AudioEngine_Volume_type volume; struct AudioDecoder_MixerWeight_type cmdblock; RMstatus err; RMuint32 audio_decoder = EMHWLIB_MODULE(AudioDecoder,audio_decoder_index); if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int)) { return -EINVAL; } if (_SIOC_DIR(cmd) == _SIOC_READ) { switch (_IOC_NR(cmd)) { case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ val = SOUND_MASK_VOLUME | SOUND_MASK_PCM; rc = kc_logging_copy_to_user((int *) arg, &val, sizeof(int)); return rc; case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ val = SOUND_MASK_VOLUME | SOUND_MASK_PCM; rc = kc_logging_copy_to_user((int *) arg, &val, sizeof(int)); return rc; case SOUND_MIXER_RECMASK: case SOUND_MIXER_CAPS: case SOUND_MIXER_RECSRC: val = 0; rc =kc_logging_copy_to_user((int *) arg, &val, sizeof(int)); return rc; default: i = _IOC_NR(cmd); switch(i){ case SOUND_MIXER_PCM: val = pS->weight; rc =kc_logging_copy_to_user((int *) arg, &val, sizeof(int)); return rc; case SOUND_MIXER_VOLUME: val = pS->volume; rc =kc_logging_copy_to_user((int *) arg, &val, sizeof(int)); return rc; default: return -EINVAL; } } } if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) { return -EINVAL; } switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ return 0; default: i = _IOC_NR(cmd); switch(i){ case SOUND_MIXER_PCM: rc =kc_logging_copy_from_user(&val, (int *) arg, sizeof(int)); if (rc != 0) break; // Mixer weight initialization l = val & 0xff; volume_index=l*74/100; volume_index=volume_index % 75; cmdblock.MixerValue_ch0=VolumeTable[volume_index] ; EM8XXXSNDSP( pE, audio_decoder,RMAudioDecoderPropertyID_MixerWeight,&cmdblock,sizeof(cmdblock)); r = (val >> 8) & 0xff; volume_index=r*74/100; volume_index=volume_index % 75; cmdblock.MixerValue_ch2=VolumeTable[volume_index] ; EM8XXXSNDSP( pE, audio_decoder,RMAudioDecoderPropertyID_MixerWeight,&cmdblock,sizeof(cmdblock)); pS->weight = val; rc =kc_logging_copy_to_user((int *) arg, &val, sizeof(int)); return rc; case SOUND_MIXER_VOLUME: rc =kc_logging_copy_from_user(&val, (int *) arg, sizeof(int)); if (rc != 0) break; /* sets the left volume */ l = val & 0xff; volume_index=l*74/100; volume_index=volume_index % 75; volume.Channel=0; volume.Volume=VolumeTable[volume_index]; EM8XXXSNDSP(pE,EMHWLIB_MODULE(AudioEngine,audio_engine_index),RMAudioEnginePropertyID_Volume,&volume,sizeof(volume)); if (RMFAILED(err)){ printk("error while setting volume \n"); } /* sets the right volume */ r = (val >> 8) & 0xff; volume_index=r*74/100; volume_index=volume_index % 75; volume.Channel=2; volume.Volume=VolumeTable[volume_index]; EM8XXXSNDSP(pE,EMHWLIB_MODULE(AudioEngine,audio_engine_index),RMAudioEnginePropertyID_Volume,&volume,sizeof(volume)); if (RMFAILED(err)){ printk("error while setting volume \n"); } pS->volume = val; rc =kc_logging_copy_to_user((int *) arg, &val, sizeof(int)); return rc; default: return -EINVAL; } } return rc;}///////////////////////////////////////////////////////////////////////////////////////////////////////////////// /DEV/DSP FILE OPERATIONS ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////static RMuint32 bytes_to_samples(struct sndprivate *pS,RMuint32 count){ RMuint32 samples; RMuint32 nb_bits_per_sample = pS->nb_bits_per_sample; RMuint32 channel_count = pS->channel_count; samples = (count*8) / (nb_bits_per_sample*channel_count); return samples;}static RMstatus prepare_data(struct sndprivate *pS){ struct em8xxx_data param; struct em8xxxprivate *pE = Etable + (pS-Stable); RMuint8 *buffer=NULL; RMuint32 timeout = 0; RMstatus err=RM_OK; RMuint32 audio_capture = EMHWLIB_MODULE(AudioCapture,audio_capture_index); struct ReadBufferInfo prop; RMuint32 nb_buf = 0; while (1) { timeout=0; buffer=kdmapool_getbuffer(pE->pllad,pS->capture_dmapool_id,&timeout); if (buffer==NULL){ break; } nb_buf ++; param.moduleId = audio_capture; param.poolId = pS->capture_dmapool_id; param.bus_addr = kdmapool_get_bus_address(pE->pllad,pS->capture_dmapool_id,buffer, 0); param.dataSize = (1<<SERIALIN_DMA_BUFFER_SIZE_LOG2); prop.address = param.bus_addr; prop.size = param.dataSize; prop.context = (void *) ((pE-Etable) + param.poolId + 1); EM8XXXSNDSP(pE, param.moduleId, RMGenericPropertyID_AddReadBuffer, &prop, sizeof(prop)); buffer=NULL; } printk("prepared %ld buffers \n",nb_buf); return err; }void em8xxx_snd_clear_event_mask(unsigned long private_data){ struct sndprivate *pS = (struct sndprivate *) private_data; struct em8xxxprivate *pE = Etable + (pS-Stable); RMuint32 status=0; RMuint32 mask; kc_spin_lock(pE->lock); mask = pS->event_mask; kc_spin_unlock(pE->lock); if (mask & SOFT_IRQ_EVENT_XFER_RECEIVE_READY) { kc_wake_up_interruptible(pS->sq); status |= SOFT_IRQ_EVENT_XFER_RECEIVE_READY; } kc_spin_lock(pE->lock); EMhwlibSetProperty(pE->pemhwlib,EMHWLIB_MODULE(AudioCapture,audio_capture_index),RMGenericPropertyID_ClearEventMask,&status,sizeof(status)); pS->event_mask = 0; kc_spin_unlock(pE->lock);}static RMuint32 event_callback(void *pE,RMuint32 ModuleID,RMuint32 mask){ struct em8xxxprivate *real_pE = (struct em8xxxprivate *) pE; struct sndprivate *pS = Stable + (real_pE-Etable); kc_spin_lock(real_pE->lock); pS->event_mask |= mask; kc_spin_unlock(real_pE->lock); tasklet_hi_schedule(&pS->event_tq); return mask;}static int rm_open_dsp(struct inode *inode, struct file *file){ int i; int minor = MINOR(inode->i_rdev); struct em8xxxprivate *pE = (struct em8xxxprivate *) NULL; struct sndprivate *pS = (struct sndprivate *) NULL; for (i=0 ; i<MAXLLAD ; i++) { pE = &Etable[i]; pS=Stable+(pE-Etable); if (pS->sndprivate_active==1) { if (pS->dsp_dev==minor) break; } } if (i == MAXLLAD) { // can't find corresponding realmagic device printk("Cannot open em8xxx sound dsp device\n"); return -EINVAL; } printk("Opens em8xxx sound device (/dev/dsp%d)\n", minor); /*Only one process can used oss device*/ if(pS->dsp_open_count != 0){ RMDBGLOG((ENABLE, "/dev/dsp already opened\n")); return -EMFILE; } pS->dsp_open_count ++; file->private_data = pS; init_waitqueue_head(&pS->sound_queue); kc_init_waitqueue_head(&pS->sq); if(init_audio(pS) != RM_OK) { printk("Audio initialisation error.\n"); cleanup_audio(pS); pS->dsp_open_count --; return -EINVAL; } printk("Open the pools\n"); //open the pools pS->dmapool_id=kdmapool_open(pE->pllad,NULL,AUDIO_DMA_BUFFER_COUNT,AUDIO_DMA_BUFFER_SIZE_LOG2); printk("dmapool id = %ld\n", pS->dmapool_id); { RMuint32 timeout = 0; pS->pBuf=kdmapool_getbuffer(pE->pllad,pS->dmapool_id,&timeout); } pS->capture_dmapool_id=kdmapool_open(pE->pllad,NULL,SERIALIN_DMA_BUFFER_COUNT,SERIALIN_DMA_BUFFER_SIZE_LOG2); printk("capture_dmapool id = %ld\n", pS->capture_dmapool_id); prepare_data(pS); tasklet_init(&pS->event_tq,em8xxx_snd_clear_event_mask,(unsigned long) pS); krua_register_event_callback(pE,EMHWLIB_MODULE(AudioCapture,audio_capture_index),SOFT_IRQ_EVENT_XFER_RECEIVE_READY,event_callback); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -