📄 ixj.c
字号:
/* * ixj.c * * Device Driver for the Internet PhoneJACK and * Internet LineJACK Telephony Cards. * * (c) Copyright 1999 Quicknet Technologies, Inc. * * 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. * * Author: Ed Okerson, <eokerson@quicknet.net> * * Contributors: Greg Herlein, <gherlein@quicknet.net> * David W. Erhart, <derhart@quicknet.net> * John Sellers, <jsellers@quicknet.net> * Mike Preston, <mpreston@quicknet.net> * * Fixes: * * More information about the hardware related to this driver can be found * at our website: http://www.quicknet.net * * IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET * TECHNOLOGIES, INC.HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND QUICKNET TECHNOLOGIES, INC. HAS NO OBLIGATION * TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */#ifndef __KERNEL__#define __KERNEL__#endif#ifndef MODULE#define MODULE#endifstatic char ixj_c_rcsid[] = "$Id: ixj.c,v 1.1 2000/01/07 22:49:59 ctam Exp $";//#define PERFMON_STATS#define IXJDEBUG 1#define MAXRINGS 5#include <linux/module.h>#include <linux/sched.h>#include <linux/kernel.h> /* printk() */#include <linux/fs.h> /* everything... */#include <linux/errno.h> /* error codes */#include <linux/malloc.h>#include <linux/mm.h>#include <linux/ioport.h>#include <linux/interrupt.h>#include <linux/tqueue.h>#include <linux/proc_fs.h>#include <linux/poll.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/pci.h>#include <asm/io.h>#include <asm/segment.h>#include <asm/uaccess.h>#ifdef CONFIG_ISAPNP#include "isapnp/pnpio.h"#include "isapnp/isapnp.h"#endif#include "ixj.h"#define TYPE(dev) (MINOR(dev) >> 4)#define NUM(dev) (MINOR(dev) & 0xf)static int ixjdebug = 0;static int hertz = HZ;static int samplerate = 100;MODULE_PARM(ixjdebug, "i");//static int ixj_major = 159;//static struct wait_queue *ixj_queue;static IXJ ixj[IXJMAX];static struct timer_list ixj_timer;int ixj_convert_loaded = 0;/************************************************************************** These are function definitions to allow external modules to register* enhanced functionality call backs.*************************************************************************/static int Stub(IXJ * J, unsigned long arg){ return 0;}static IXJ_REGFUNC ixj_DownloadG729 = &Stub;static IXJ_REGFUNC ixj_DownloadTS85 = &Stub;static IXJ_REGFUNC ixj_PreRead = &Stub;static IXJ_REGFUNC ixj_PostRead = &Stub;static IXJ_REGFUNC ixj_PreWrite = &Stub;static IXJ_REGFUNC ixj_PostWrite = &Stub;static IXJ_REGFUNC ixj_PreIoctl = &Stub;static IXJ_REGFUNC ixj_PostIoctl = &Stub;static void ixj_read_frame(int board);static void ixj_write_frame(int board);static void ixj_init_timer(void);static void ixj_timeout(unsigned long ptr);static int read_filters(int board);static int LineMonitor(int board);static int ixj_fasync(int fd, struct file *, int mode);static int ixj_hookstate(int board);static int ixj_record_start(int board);static void ixj_record_stop(int board);static int ixj_play_start(int board);static void ixj_play_stop(int board);static int ixj_set_tone_on(unsigned short arg, int board);static int ixj_set_tone_off(unsigned short, int board);static int ixj_play_tone(int board, char tone);static int idle(int board);static void ixj_ring_on(int board);static void ixj_ring_off(int board);static void aec_stop(int board);static void ixj_ringback(int board);static void ixj_busytone(int board);static void ixj_dialtone(int board);static void ixj_cpt_stop(int board);static char daa_int_read(int board);static int daa_set_mode(int board, int mode);static int ixj_linetest(int board);static int ixj_daa_cid_read(int board);static void DAA_Coeff_US(int board);static void DAA_Coeff_UK(int board);static void DAA_Coeff_France(int board);static void DAA_Coeff_Germany(int board);static void DAA_Coeff_Australia(int board);static void DAA_Coeff_Japan(int board);static int ixj_init_filter(int board, IXJ_FILTER * jf);static int ixj_init_tone(int board, IXJ_TONE * ti);static int ixj_build_cadence(int board, IXJ_CADENCE * cp);// Serial Control Interface funtionsstatic int SCI_Control(int board, int control);static int SCI_Prepare(int board);static int SCI_WaitHighSCI(int board);static int SCI_WaitLowSCI(int board);static DWORD PCIEE_GetSerialNumber(WORD wAddress);/************************************************************************CT8020/CT8021 Host Programmers ModelHost address Function AccessDSPbase +0-1 Aux Software Status Register (reserved) Read Only2-3 Software Status Register Read Only4-5 Aux Software Control Register (reserved) Read Write6-7 Software Control Register Read Write8-9 Hardware Status Register Read OnlyA-B Hardware Control Register Read WriteC-D Host Transmit (Write) Data Buffer Access Port (buffer input)Write OnlyE-F Host Recieve (Read) Data Buffer Access Port (buffer input) Read Only************************************************************************/extern __inline__ void ixj_read_HSR(board){ ixj[board].hsr.bytes.low = inb_p(ixj[board].DSPbase + 8); ixj[board].hsr.bytes.high = inb_p(ixj[board].DSPbase + 9);}extern __inline__ int IsControlReady(int board){ ixj_read_HSR(board); return ixj[board].hsr.bits.controlrdy ? 1 : 0;}extern __inline__ int IsStatusReady(int board){ ixj_read_HSR(board); return ixj[board].hsr.bits.statusrdy ? 1 : 0;}extern __inline__ int IsRxReady(int board){ ixj_read_HSR(board); return ixj[board].hsr.bits.rxrdy ? 1 : 0;}extern __inline__ int IsTxReady(int board){ ixj_read_HSR(board); return ixj[board].hsr.bits.txrdy ? 1 : 0;}extern __inline__ BYTE SLIC_GetState(int board){ IXJ *j = &ixj[board]; j->pld_slicr.byte = inb_p(j->XILINXbase + 0x01); return j->pld_slicr.bits.state;}static BOOL SLIC_SetState(BYTE byState, int board){ BOOL fRetVal = FALSE; IXJ *j = &ixj[board]; // Set the C1, C2, C3 & B2EN signals. switch (byState) { case PLD_SLIC_STATE_OC: j->pld_slicw.bits.c1 = 0; j->pld_slicw.bits.c2 = 0; j->pld_slicw.bits.c3 = 0; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); fRetVal = TRUE; break; case PLD_SLIC_STATE_RINGING: j->pld_slicw.bits.c1 = 1; j->pld_slicw.bits.c2 = 0; j->pld_slicw.bits.c3 = 0; j->pld_slicw.bits.b2en = 1; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); fRetVal = TRUE; break; case PLD_SLIC_STATE_ACTIVE: j->pld_slicw.bits.c1 = 0; j->pld_slicw.bits.c2 = 1; j->pld_slicw.bits.c3 = 0; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); fRetVal = TRUE; break; case PLD_SLIC_STATE_OHT: // On-hook transmit j->pld_slicw.bits.c1 = 1; j->pld_slicw.bits.c2 = 1; j->pld_slicw.bits.c3 = 0; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); fRetVal = TRUE; break; case PLD_SLIC_STATE_TIPOPEN: j->pld_slicw.bits.c1 = 0; j->pld_slicw.bits.c2 = 0; j->pld_slicw.bits.c3 = 1; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); fRetVal = TRUE; break; case PLD_SLIC_STATE_STANDBY: j->pld_slicw.bits.c1 = 1; j->pld_slicw.bits.c2 = 0; j->pld_slicw.bits.c3 = 1; j->pld_slicw.bits.b2en = 1; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); fRetVal = TRUE; break; case PLD_SLIC_STATE_APR: // Active polarity reversal j->pld_slicw.bits.c1 = 0; j->pld_slicw.bits.c2 = 1; j->pld_slicw.bits.c3 = 1; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); fRetVal = TRUE; break; case PLD_SLIC_STATE_OHTPR: // OHT polarity reversal j->pld_slicw.bits.c1 = 1; j->pld_slicw.bits.c2 = 1; j->pld_slicw.bits.c3 = 1; j->pld_slicw.bits.b2en = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); fRetVal = TRUE; break; default: fRetVal = FALSE; break; } return fRetVal;}int ixj_register(int index, IXJ_REGFUNC regfunc){ int cnt; int retval = 0; switch (index) { case G729LOADER: ixj_DownloadG729 = regfunc; for (cnt = 0; cnt < IXJMAX; cnt++) ixj_DownloadG729(&ixj[cnt], 0L); break; case TS85LOADER: ixj_DownloadTS85 = regfunc; for (cnt = 0; cnt < IXJMAX; cnt++) ixj_DownloadTS85(&ixj[cnt], 0L); break; case PRE_READ: ixj_PreRead = regfunc; break; case POST_READ: ixj_PostRead = regfunc; break; case PRE_WRITE: ixj_PreWrite = regfunc; break; case POST_WRITE: ixj_PostWrite = regfunc; break; case PRE_IOCTL: ixj_PreIoctl = regfunc; break; case POST_IOCTL: ixj_PostIoctl = regfunc; break; default: retval = 1; } return retval;}int ixj_unregister(int index){ int retval = 0; switch (index) { case G729LOADER: ixj_DownloadG729 = &Stub; break; case TS85LOADER: ixj_DownloadTS85 = &Stub; break; case PRE_READ: ixj_PreRead = &Stub; break; case POST_READ: ixj_PostRead = &Stub; break; case PRE_WRITE: ixj_PreWrite = &Stub; break; case POST_WRITE: ixj_PostWrite = &Stub; break; case PRE_IOCTL: ixj_PreIoctl = &Stub; break; case POST_IOCTL: ixj_PostIoctl = &Stub; break; default: retval = 1; } return retval;}void ixj_init_timer(void){ init_timer(&ixj_timer); ixj_timer.function = ixj_timeout; ixj_timer.data = (int) NULL; ixj_timer.expires = jiffies + (hertz / samplerate); add_timer(&ixj_timer);}static void ixj_timeout(unsigned long ptr){ int board; unsigned long jifon; IXJ *j; IXJ_TONE ti; static int mutex = 0; /* What is this trying to do ?? */ /* This is a safeguard in case the loop does not complete before the next timer tick. Since all the work is done during this timer loop, we do not want the next iteration of the loop to start before the last one finished. */ if (!mutex) { mutex++; for (board = 0; board < IXJMAX; board++) { j = &ixj[board]; if (j->DSPbase) {#ifdef PERFMON_STATS j->timerchecks++;#endif if (j->tone_state) { if (!ixj_hookstate(board)) { ixj_cpt_stop(board); if (j->m_hook) { j->m_hook = 0; j->ex.bits.hookstate = 1; if (j->async_queue) kill_fasync(j->async_queue, SIGIO); // Send apps notice of change } goto timer_end; } if (j->tone_state == 1) jifon = (hertz * j->tone_on_time * 25 / 100000); else jifon = (hertz * j->tone_on_time * 25 / 100000) + (hertz * j->tone_off_time * 25 / 100000); if (jiffies < j->tone_start_jif + jifon) { if (j->tone_state == 1) { ixj_play_tone(board, j->tone_index); if (j->dsp.low == 0x20) { goto timer_end; } } else { ixj_play_tone(board, 0); if (j->dsp.low == 0x20) { goto timer_end; } } } else { j->tone_state++; if (j->tone_state == 3) { j->tone_state = 0; if (j->cadence_t) { j->tone_cadence_state++; if (j->tone_cadence_state == j->cadence_t->elements_used) { switch (j->cadence_t->termination) { case PLAY_ONCE: ixj_cpt_stop(board); break; case REPEAT_LAST_ELEMENT: j->tone_cadence_state--; ixj_play_tone(board, j->cadence_t->ce[j->tone_cadence_state].index); break; case REPEAT_ALL: j->tone_cadence_state = 0; if (j->cadence_t->ce[j->tone_cadence_state].freq0) { ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index; ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0; ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0; ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1; ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1; ixj_init_tone(board, &ti); } ixj_set_tone_on(j->cadence_t->ce[0].tone_on_time, board); ixj_set_tone_off(j->cadence_t->ce[0].tone_off_time, board); ixj_play_tone(board, j->cadence_t->ce[0].index); break; } } else { if (j->cadence_t->ce[j->tone_cadence_state].gain0) { ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index; ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0; ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0; ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1; ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1; ixj_init_tone(board, &ti); } ixj_set_tone_on(j->cadence_t->ce[j->tone_cadence_state].tone_on_time, board); ixj_set_tone_off(j->cadence_t->ce[j->tone_cadence_state].tone_off_time, board); ixj_play_tone(board, j->cadence_t->ce[j->tone_cadence_state].index); } } } if (j->flags.dialtone) { ixj_dialtone(board); } if (j->flags.busytone) { ixj_busytone(board); if (j->dsp.low == 0x20) { goto timer_end; } } if (j->flags.ringback) { ixj_ringback(board); if (j->dsp.low == 0x20) { goto timer_end; } } if (!j->tone_state) { if (j->dsp.low == 0x20 || (j->play_mode == -1 && j->rec_mode == -1)) idle(board); if (j->dsp.low == 0x20 && j->play_mode != -1) ixj_play_start(board); if (j->dsp.low == 0x20 && j->rec_mode != -1) ixj_record_start(board); } } } if (!j->tone_state || j->dsp.low != 0x20) { if (IsRxReady(board)) { ixj_read_frame(board); } if (IsTxReady(board)) { ixj_write_frame(board); } } if (j->flags.cringing) { if (ixj_hookstate(board) & 1) { j->flags.cringing = 0; ixj_ring_off(board); } else { if (jiffies - j->ring_cadence_jif >= (.5 * hertz)) { j->ring_cadence_t--; if (j->ring_cadence_t == -1) j->ring_cadence_t = 15; j->ring_cadence_jif = jiffies; } if (j->ring_cadence & 1 << j->ring_cadence_t) { ixj_ring_on(board); } else { ixj_ring_off(board); } goto timer_end; } } if (!j->flags.ringing) { if (ixj_hookstate(board)) { if (j->dsp.low == 0x21 && j->pld_slicr.bits.state != PLD_SLIC_STATE_ACTIVE) // Internet LineJACK { SLIC_SetState(PLD_SLIC_STATE_ACTIVE, board); } LineMonitor(board); read_filters(board); ixj_WriteDSPCommand(0x511B, board); j->proc_load = j->ssr.high << 8 | j->ssr.low; if (!j->m_hook) { j->m_hook = j->ex.bits.hookstate = 1; if (j->async_queue) kill_fasync(j->async_queue, SIGIO); // Send apps notice of change } } else { if (j->dsp.low == 0x21 && j->pld_slicr.bits.state == PLD_SLIC_STATE_ACTIVE) // Internet LineJACK { SLIC_SetState(PLD_SLIC_STATE_STANDBY, board); } if (j->ex.bits.dtmf_ready) { j->dtmf_wp = j->dtmf_rp = j->ex.bits.dtmf_ready = 0; } if (j->m_hook) { j->m_hook = 0; j->ex.bits.hookstate = 1; if (j->async_queue) kill_fasync(j->async_queue, SIGIO); // Send apps notice of change } } } if (j->cardtype == 300) { if (j->flags.pstn_present) { j->pld_scrr.byte = inb_p(j->XILINXbase); if (jiffies >= j->pstn_sleeptil && j->pld_scrr.bits.daaflag) { daa_int_read(board); if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.RING) { if (!j->flags.pstn_ringing) { j->flags.pstn_ringing = 1; if (j->daa_mode != SOP_PU_RINGING) daa_set_mode(board, SOP_PU_RINGING); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -