📄 em8xxx_voip_new.c
字号:
/***************************************** Copyright @ 2005, 2006, 2007 Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//** @file em8xxx_voip_new.c @brief New linux kernel telephony driver of the em8xxx boards @author Yoann Walther @date 2006-11-07*//* to enable or disable the debug messages of this source file, put 1 or 0 below */#if 1#define LOCALDBG ENABLE#else#define LOCALDBG DISABLE#endif#include "em8xxxvoip_new.h"MODULE_DESCRIPTION("EM8XXX New Linux Telephony Driver");MODULE_AUTHOR("Yoann Walther <yoann_walther@sdesigns.eu>");#ifdef MODULE_LICENSEMODULE_LICENSE("Proprietary");#endifextern struct em8xxxprivate Etable[MAXLLAD];static RMuint32 em8xxx_voip_event_callback(void *pE,RMuint32 ModuleID,RMuint32 mask);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 int rm_free_ptr(struct em8xxxprivate *pE,RMuint32 ptr);static int gpio_set_dir(struct em8xxxprivate *pE,int gpio_number,int dir);static int read_gpio(struct em8xxxprivate *pE,int gpio_number);static int write_gpio(struct em8xxxprivate *pE,int gpio_number, int val);static int init_gpio(struct em8xxxprivate *pE);static int SlicSetState(struct voipprivate *pV,enum SLIC_STATES State);static void em8xxx_voip_check_hookstate(struct voipprivate *pV);static void em8xxx_voip_init_timer(struct voipprivate *pV);static void em8xxx_voip_add_timer(struct voipprivate *pV);static void em8xxx_voip_timeout(unsigned long private);static int em8xxx_voip_init(struct em8xxxprivate *pE);static int em8xxx_voip_cleanup(struct em8xxxprivate *pE);static int em8xxx_voip_open(struct phone_device *p, struct file *file_p);static ssize_t em8xxx_voip_read(struct file * file_p, char *buf, size_t length,loff_t * ppos);static ssize_t em8xxx_voip_write(struct file * file_p, const char *buf, size_t count, loff_t * ppos);static unsigned int em8xxx_voip_poll(struct file *file_p, poll_table * wait);static int em8xxx_voip_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd, unsigned long arg);static int em8xxx_voip_release(struct inode *inode, struct file *file_p);static int em8xxx_voip_fasync(int fd, struct file *file_p, int mode);struct file_operations em8xxx_voip_fops ={#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) NULL, /* lseek */ em8xxx_voip_read, em8xxx_voip_write, NULL, /* readdir */ em8xxx_voip_poll, em8xxx_voip_ioctl, NULL, /* mmap */ NULL, /* open */ NULL, /* flush */ em8xxx_voip_release, NULL, /* fsync */ em8xxx_voip_fasync, /* fasync */ NULL, /* media change */ NULL, /* revalidate */ NULL /* lock */#else#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) owner: THIS_MODULE, read: em8xxx_voip_read, write: em8xxx_voip_write, poll: em8xxx_voip_poll, ioctl: em8xxx_voip_ioctl, release: em8xxx_voip_release, fasync: em8xxx_voip_fasync#else .owner = THIS_MODULE, .read = em8xxx_voip_read, .write = em8xxx_voip_write, .poll = em8xxx_voip_poll, .ioctl = em8xxx_voip_ioctl, .release = em8xxx_voip_release, .fasync = em8xxx_voip_fasync#endif#endif};static int rm_free_ptr(struct em8xxxprivate *pE,RMuint32 ptr){ RMuint32 dramIndex=0xffffffff; RMstatus err; if ((MEM_BASE_dram_controller_0<=ptr)&&(ptr<MEM_BASE_dram_controller_1)) dramIndex=0; if ((MEM_BASE_dram_controller_1<=ptr)&&(ptr<MEM_BASE_dram_controller_1+(512*1024*1024))) dramIndex=1; if (dramIndex<=1) { EM8XXXVOIPSP(pE, EMHWLIB_MODULE(MM,dramIndex), RMMMPropertyID_Free, (void *)(&ptr),sizeof(void *)); if(err!=RM_OK) RMDBGLOG((ENABLE,"rm_ptr_free: pointer 0x%08lx cannot be freed\n",ptr)); } else RMDBGLOG((ENABLE,"rm_ptr_free: pointer %p not in a dram controller\n",ptr)); return 0;}static void em8xxx_voip_clear_event_mask(unsigned long private_data){ struct voipprivate *pV = (struct voipprivate *) private_data; struct em8xxxprivate *pE = Etable + (pV-VOIPtable); RMuint32 status = 0; RMuint32 mask; kc_spin_lock(pE->lock); mask = pV->event_mask; kc_spin_unlock(pE->lock); if (mask & SOFT_IRQ_EVENT_COMMANDCOMPLETION) { kc_wake_up_interruptible(pV->command_q); status |= SOFT_IRQ_EVENT_COMMANDCOMPLETION; } if (mask & SOFT_IRQ_EVENT_VOIP_DTMF_READY) { pV->exc.bits.dtmf_ready = 1; kc_wake_up_interruptible(pV->poll_q); status |= SOFT_IRQ_EVENT_VOIP_DTMF_READY; } if (mask & SOFT_IRQ_EVENT_VOIP_FRAME_ENCODED) { kc_wake_up_interruptible(pV->read_q); status |= SOFT_IRQ_EVENT_VOIP_FRAME_ENCODED; } if (mask & SOFT_IRQ_EVENT_VOIP_FRAME_DECODED) { kc_wake_up_interruptible(pV->write_q); status |= SOFT_IRQ_EVENT_VOIP_FRAME_DECODED; } kc_spin_lock(pE->lock); EMhwlibSetProperty(pE->pemhwlib,VoipCodec,RMGenericPropertyID_ClearEventMask,&status,sizeof(status)); pV->event_mask = 0; kc_spin_unlock(pE->lock);}static RMuint32 em8xxx_voip_event_callback(void *pE,RMuint32 ModuleID,RMuint32 mask){ struct em8xxxprivate *real_pE = (struct em8xxxprivate *) pE; struct voipprivate *pV = VOIPtable + (real_pE - Etable); kc_spin_lock(real_pE->lock); pV->event_mask |= mask; kc_spin_unlock(real_pE->lock); tasklet_hi_schedule(&pV->event_tq); return mask;}static int gpio_set_dir(struct em8xxxprivate *pE,int gpio_number,int dir){ RMuint32 gpio_dir; RMuint32 gpio_dir_addr; int nb; if(gpio_number > 16){ gpio_dir_addr = ETH_GPIO_DIR; nb = gpio_number - 16; } else { gpio_dir_addr = SYS_GPIO_DATA; nb = gpio_number; } gpio_dir = gbus_read_uint32(pE->pgbus,gpio_dir_addr); RMsetConsecutiveBitsVar(&gpio_dir,nb+16,nb+16,1); RMsetConsecutiveBitsVar(&gpio_dir,nb,nb,dir); gbus_write_uint32(pE->pgbus,gpio_dir_addr,gpio_dir); gpio_dir = gbus_read_uint32(pE->pgbus,gpio_dir_addr); if (dir == ((gpio_dir >> nb) & 1)) return 0; else return -1; }static int read_gpio(struct em8xxxprivate *pE,int gpio_number){ RMuint32 gpio_data; RMuint32 gpio_data_addr; int val; int nb; if(gpio_number > 16){ gpio_data_addr = ETH_GPIO_DATA; nb = gpio_number - 16; } else { gpio_data_addr = SYS_GPIO_DATA; nb = gpio_number; } gpio_data = gbus_read_uint32(pE->pgbus,gpio_data_addr); val = (gpio_data >> nb) & 1; return val; }static int write_gpio(struct em8xxxprivate *pE,int gpio_number, int val){ RMuint32 gpio_data; RMuint32 gpio_data_addr; int nb; if(gpio_number > 16){ gpio_data_addr = ETH_GPIO_DATA; nb = gpio_number - 16; } else{ gpio_data_addr = SYS_GPIO_DATA; nb = gpio_number; } gpio_data = gbus_read_uint32(pE->pgbus,gpio_data_addr); RMsetConsecutiveBitsVar(&gpio_data,nb+16,nb+16,1); RMsetConsecutiveBitsVar(&gpio_data,nb,nb,val); gbus_write_uint32(pE->pgbus,gpio_data_addr,gpio_data); gpio_data = gbus_read_uint32(pE->pgbus,gpio_data_addr); if (val == ((gpio_data >> nb) & 1)) return 0; else return -1;}static int init_gpio(struct em8xxxprivate *pE){ gpio_set_dir(pE,GPIO_SLIC_COMP,GPIO_DIR_OUTPUT); gpio_set_dir(pE,GPIO_SLIC_CTL1,GPIO_DIR_OUTPUT); gpio_set_dir(pE,GPIO_SLIC_CTL2,GPIO_DIR_OUTPUT); gpio_set_dir(pE,GPIO_SLIC_MUTE,GPIO_DIR_OUTPUT); gpio_set_dir(pE,GPIO_HDS_MUTE,GPIO_DIR_OUTPUT); gpio_set_dir(pE,GPIO_LOOP_DETECT,GPIO_DIR_INPUT); gpio_set_dir(pE,GPIO_FAULT_DETECT,GPIO_DIR_INPUT); return 0;}static int SlicSetState(struct voipprivate *pV,enum SLIC_STATES State){ struct em8xxxprivate *pE = Etable + (pV - VOIPtable); switch(State){ case LOW_POWER_STANDBY: write_gpio(pE,GPIO_SLIC_COMP,0); write_gpio(pE,GPIO_SLIC_CTL1,0); write_gpio(pE,GPIO_SLIC_CTL2,0); break; case REVERSE_POLARITY: write_gpio(pE,GPIO_SLIC_COMP,0); write_gpio(pE,GPIO_SLIC_CTL1,1); write_gpio(pE,GPIO_SLIC_CTL2,0); break; case NORMAL_ACTIVE: write_gpio(pE,GPIO_SLIC_COMP,0); write_gpio(pE,GPIO_SLIC_CTL1,0); write_gpio(pE,GPIO_SLIC_CTL2,1); break; case RINGING: write_gpio(pE,GPIO_SLIC_COMP,0); write_gpio(pE,GPIO_SLIC_CTL1,1); write_gpio(pE,GPIO_SLIC_CTL2,1); break; case DISCONNECT: write_gpio(pE,GPIO_SLIC_COMP,1); write_gpio(pE,GPIO_SLIC_CTL1,0); write_gpio(pE,GPIO_SLIC_CTL2,0); break; } return 0;}static void em8xxx_voip_check_hookstate(struct voipprivate *pV){ struct em8xxxprivate *pE = Etable + (pV - VOIPtable); pV->hookstate = !read_gpio(pE,GPIO_LOOP_DETECT); if(pV->hookstate != pV->last_hookstate){ pV->hook_cnt ++; if(pV->hook_cnt>=10){ pV->hook_cnt = 0; RMDBGLOG((LOCALDBG,"detecting hook state change pV->hook_cnt = %d ! \n",pV->hook_cnt)); pV->last_hookstate = pV->hookstate; pV->exc.bits.hookstate = 1; kc_wake_up_interruptible(pV->poll_q); RMDBGLOG((LOCALDBG,"exc.bytes = %d \n",pV->exc.bytes)); } }}static void em8xxx_voip_timeout(unsigned long private){ struct voipprivate *pV = (struct voipprivate *) private; struct em8xxxprivate *pE = Etable + (pV - VOIPtable); struct XferFIFOInfo_type xfer_info; em8xxx_voip_check_hookstate(pV); kc_spin_lock(pE->lock); EMhwlibGetProperty(pE->pemhwlib,EMHWLIB_TARGET_MODULE(VoipCodec,0,0),RMGenericPropertyID_XferFIFOInfo,&xfer_info,sizeof(xfer_info)); kc_spin_unlock(pE->lock); if (xfer_info.Erasable > 0) { kc_wake_up_interruptible(pV->poll_q); } kc_spin_lock(pE->lock); EMhwlibGetProperty(pE->pemhwlib,EMHWLIB_TARGET_MODULE(VoipCodec,0,1),RMGenericPropertyID_XferFIFOInfo,&xfer_info,sizeof(xfer_info)); kc_spin_unlock(pE->lock); if (xfer_info.Writable > 0) { kc_wake_up_interruptible(pV->poll_q); } if(pV->voip_open_count) em8xxx_voip_add_timer(pV); return;}static void em8xxx_voip_init_timer(struct voipprivate *pV){ init_timer(&pV->timer); pV->timer.function = em8xxx_voip_timeout; pV->timer.data = (unsigned long)pV;}static void em8xxx_voip_add_timer(struct voipprivate *pV){ pV->timer.expires = jiffies + pV->check_interval; add_timer(&pV->timer);}static RMstatus init_voip(struct voipprivate *pV){ struct em8xxxprivate *pE = Etable + (pV-VOIPtable); struct MM_Malloc_in_type in; struct MM_Malloc_out_type out; enum AudioEngine_SpdifOut_type spdif_out; struct AudioEngine_I2SConfig_type i2s; enum AudioEngine_SerialOut_type serialOutStatus; struct VoipCodec_DRAMSize_in_type dram_in; struct VoipCodec_DRAMSize_out_type dram_out; struct VoipCodec_Open_type profile; enum VoipCodec_Command_type command; RMuint32 volume; RMstatus err; int rc;#ifndef WITH_XLOADED_UCODE enum ProcessorState run; struct AudioEngine_MicrocodeDRAMSize_in_type size_in; struct AudioEngine_MicrocodeDRAMSize_out_type size_out; struct AudioEngine_Microcode_type ucode; run = CPU_RESET; EM8XXXVOIPSP(pE,EMHWLIB_MODULE(AudioEngine,1),RMAudioEnginePropertyID_State,&run,sizeof(run)); if (RMFAILED(err)) { RMDBGLOG((ENABLE,"Error while resetting Audio RISC\n")); return err; } run = CPU_STOPPED; EM8XXXVOIPSP(pE,EMHWLIB_MODULE(AudioEngine,1),RMAudioEnginePropertyID_State,&run,sizeof(run)); if (RMFAILED(err)) { RMDBGLOG((ENABLE,"Error while stopping Audio RISC\n")); return err; } size_in.MicrocodeVersion = 2; EM8XXXVOIPEXP(pE,EMHWLIB_MODULE(AudioEngine,1),RMAudioEnginePropertyID_MicrocodeDRAMSize, &size_in, sizeof(size_in), &size_out, sizeof(size_out)); if (RMFAILED(err)) { RMDBGLOG((ENABLE,"Error while getting memory needed for audio microcode!\n")); return err; } if (size_out.Size == 0) { RMDBGLOG((LOCALDBG,"Voip microcode does not need DRAM\n")); ucode.Address = 0; } else { in.dramtype=RUA_DRAM_CACHED; in.Size=size_out.Size; EM8XXXVOIPEXP(pE,EMHWLIB_MODULE(MM,0),RMMMPropertyID_Malloc,&in,sizeof(in),&out,sizeof(out)); if (err == RM_OK){ ucode.Address = (RMuint32) out.Address; RMDBGLOG((LOCALDBG,"Voip ucode cached addr : 0x%08lx, size 0x%08lx, end: 0x%08lx\n",ucode.Address,size_out.Size,ucode.Address+size_out.Size)); pV->VoipUCodeAddr = ucode.Address;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -