📄 wcfxsusb.c
字号:
/* * Wildcard S100U USB FXS Interface Zapata Telephony Driver * * Written by Mark Spencer <markster@linux-support.net> * Matthew Fredrickson <creslin@linux-support.net> * * Copyright (C) 2001, Linux Support Services, Inc. * * All rights reserved. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * *//* Save power at the expense of not always being able to transmit on hook. If this is set, we only transit on hook for some time after a ring (POWERSAVE_TIMEOUT) */#define PROSLIC_POWERSAVE#define POWERSAVE_TIME 4000#include <linux/kernel.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/usb.h>#include <linux/errno.h>#include <linux/version.h>#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,19)#define USB2420#endif#ifdef STANDALONE_ZAPATA#include "zaptel.h"#else#include <linux/zaptel.h>#endif /* STANDALONE_ZAPATA */#include "wcfxsusb.h"#include "proslic.h"#ifdef DEBUG_WILDCARD#define DPRINTK(x) printk x#else#define DPRINTK(x)#endif// Function prototypesstatic int readProSlicDirectReg(struct usb_device *dev, unsigned char address, unsigned char* data);static int initializeIndirectRegisters(struct usb_device *dev);static int verifyIndirectRegisters(struct usb_device *dev);static int writeProSlicDirectReg(struct usb_device *dev, unsigned char address, unsigned char data);static int writeProSlicInDirectReg(struct usb_device *dev, unsigned char address, unsigned short data);static int readProSlicInDirectReg(struct usb_device *dev, unsigned char address, unsigned short *data);static int writeProSlicInDirectReg(struct usb_device *dev, unsigned char address, unsigned short data);static alpha indirect_regs[] ={{0,"DTMF_ROW_0_PEAK",0x55C2},{1,"DTMF_ROW_1_PEAK",0x51E6},{2,"DTMF_ROW2_PEAK",0x4B85},{3,"DTMF_ROW3_PEAK",0x4937},{4,"DTMF_COL1_PEAK",0x3333},{5,"DTMF_FWD_TWIST",0x0202},{6,"DTMF_RVS_TWIST",0x0202},{7,"DTMF_ROW_RATIO_TRES",0x0198},{8,"DTMF_COL_RATIO_TRES",0x0198},{9,"DTMF_ROW_2ND_ARM",0x0611},{10,"DTMF_COL_2ND_ARM",0x0202},{11,"DTMF_PWR_MIN_TRES",0x00E5},{12,"DTMF_OT_LIM_TRES",0x0A1C},{13,"OSC1_COEF",0x6D40},{14,"OSC1X",0x0470},{15,"OSC1Y",0x0000},{16,"OSC2_COEF",0x4A80},{17,"OSC2X",0x0830},{18,"OSC2Y",0x0000},{19,"RING_V_OFF",0x0000},{20,"RING_OSC",0x7EF0},{21,"RING_X",0x0160},{22,"RING_Y",0x0000},{23,"PULSE_ENVEL",0x2000},{24,"PULSE_X",0x2000},{25,"PULSE_Y",0x0000},//{26,"RECV_DIGITAL_GAIN",0x4000}, // playback volume set lower{26,"RECV_DIGITAL_GAIN",0x2000}, // playback volume set lower{27,"XMIT_DIGITAL_GAIN",0xc000 /* was 0x4000 */ },{28,"LOOP_CLOSE_TRES",0x1000},{29,"RING_TRIP_TRES",0x3600},{30,"COMMON_MIN_TRES",0x1000},{31,"COMMON_MAX_TRES",0x0200},{32,"PWR_ALARM_Q1Q2",0x0550},{33,"PWR_ALARM_Q3Q4",0x2600},{34,"PWR_ALARM_Q5Q6",0x1B80},{35,"LOOP_CLOSURE_FILTER",0x8000},{36,"RING_TRIP_FILTER",0x0320},{37,"TERM_LP_POLE_Q1Q2",0x0100},{38,"TERM_LP_POLE_Q3Q4",0x0100},{39,"TERM_LP_POLE_Q5Q6",0x0010},{40,"CM_BIAS_RINGING",0x0C00},{41,"DCDC_MIN_V",0x0C00},{42,"DCDC_XTRA",0x1000},};#define WCUSB_SPORT0 0x26#define WCUSB_SPORT1 0x27#define WCUSB_SPORT2 0x28#define WCUSB_SPORT_CTRL 0x29#define WC_AUX0 0x1#define WC_AUX1 0x2#define WC_AUX2 0x4#define WC_AUX3 0x8#define CONTROL_TIMEOUT_MS (500) /* msec */#define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ) / 1000)#define REQUEST_NORMAL 4#define FLAG_RUNNING (1 << 0)static int debug = 0;struct stinky_urb {#ifdef USB2420 struct urb urb; struct iso_packet_descriptor isoframe[1];#else urb_t urb; iso_packet_descriptor_t isoframe[1];#endif};typedef enum { STREAM_NORMAL, STREAM_DTMF,} stream_t;typedef enum { STATE_WCREAD_WRITEREG, STATE_WCREAD_READRES, STATE_WCWRITE_WRITEREG, STATE_WCWRITE_WRITERES,} control_state_t;typedef enum { WC_KEYPAD, WC_PROSLIC,} dev_type_t;typedef enum { STATE_FOR_LOOP_1_OUT, STATE_FOR_LOOP_2_IN, STATE_FOR_LOOP_PROC_DATA, STATE_FOR_LOOP_CLEAR_DIGIT,} keypad_state_t;struct wc_keypad_data { /* Keypad state monitoring variables */ keypad_state_t state;#ifdef USB2420 struct urb urb;#else urb_t urb;#endif int running; char data; char data12; char tmp; int scanned_event; int i; int count; /* DTMF tone generation stuff for zaptel */ struct zt_tone_state ts; struct zt_tone *tone;};#define WC_IO_READ (1 << 0)#define WC_IO_WRITE (1 << 1)#define IO_READY(x) (((x) & (WC_IO_READ | WC_IO_WRITE)) == \ (WC_IO_READ | WC_IO_WRITE))struct wc_usb_pvt { struct usb_device *dev; dev_type_t devclass; unsigned int readpipe; unsigned int writepipe; int usecount; int dead; int hardwareflags; struct zt_span span; struct zt_chan chan; struct stinky_urb dataread[2]; struct stinky_urb datawrite[2]; int iostate; /* Whether reads/writes are complete */#ifdef USB2420 struct urb *pendingurb; /* Pending URB for transmission */ struct urb control; struct usb_ctrlrequest dr;#else urb_t *pendingurb; /* Pending URB for transmission */ urb_t control; devrequest dr;#endif control_state_t controlstate; int urbcount; int flags; int timer; int lowpowertimer; int idletxhookstate; int hookstate; __u8 newtxhook; __u8 txhook; int pos; unsigned char auxstatus; unsigned char wcregindex; unsigned char wcregbuf[4]; unsigned char wcregval; short readchunk[ZT_MAX_CHUNKSIZE * 2]; short writechunk[ZT_MAX_CHUNKSIZE * 2]; stream_t sample; void *pvt_data;};struct wc_usb_desc { char *name; int flags;};#define FLAG_FLIP_RELAYS (1 << 0)static struct wc_usb_desc wcusb = { "Wildcard S100U USB FXS Interface" };static struct wc_usb_desc wcusb2 = { "Wildcard S110U USB FXS Interface", FLAG_FLIP_RELAYS };static struct wc_usb_desc wc_usb_phone = { "Wildcard Phone Test driver" };static struct wc_usb_pvt *ifaces[WC_MAX_IFACES];static void wcusb_check_keypad(struct wc_usb_pvt *p);static int set_aux_ctrl(struct wc_usb_pvt *p, char auxpins, int on);static int Wcusb_WriteWcRegs(struct usb_device *dev, unsigned char index, unsigned char *data, int len){ unsigned int pipe = usb_sndctrlpipe(dev, 0); int requesttype; int res; requesttype = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; res = usb_control_msg(dev, pipe, REQUEST_NORMAL, requesttype, 0, index, data, len, CONTROL_TIMEOUT_JIFFIES); if (res == -ETIMEDOUT) { printk("wcusb: timeout on vendor write\n"); return -1; } else if (res < 0) { printk("wcusb: Error executing control: status=%d\n", le32_to_cpu(res)); return -1; } return 0;} static int Wcusb_ReadWcRegs(struct usb_device *dev, unsigned char index, unsigned char *data, int len){ unsigned int pipe = usb_rcvctrlpipe(dev, 0); int requesttype; int res; requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; res = usb_control_msg(dev, pipe, REQUEST_NORMAL, requesttype, 0, index, data, len, CONTROL_TIMEOUT_JIFFIES); if (res == -ETIMEDOUT) { printk("wcusb: timeout on vendor write\n"); return -1; } else if (res < 0) { printk("wcusb: Error executing control: status=%d\n", le32_to_cpu(res)); return -1; } else { DPRINTK(("wcusb: Executed read, result = %d (data = %04x)\n", le32_to_cpu(res), (int) *data)); } return 0;} #ifdef USB2420static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb));static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb));static void wcusb_async_control(struct urb *urb);#elsestatic int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(urb_t *urb));static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(urb_t *urb));static void wcusb_async_control(urb_t *urb);#endifstatic void proslic_read_direct_async(struct wc_usb_pvt *p, unsigned char address){ p->wcregindex = address; p->wcregbuf[0] = address | 0x80; p->wcregbuf[1] = 0; p->wcregbuf[2] = 0; p->wcregbuf[3] = 0x67; wcusb_async_write(p, WCUSB_SPORT0, p->wcregbuf, 4, STATE_WCREAD_WRITEREG, wcusb_async_control);}static void proslic_write_direct_async(struct wc_usb_pvt *p, unsigned char address, unsigned char val){ p->wcregindex = address; p->wcregbuf[0] = address & 0x7f; p->wcregbuf[1] = val; p->wcregbuf[2] = 0; p->wcregbuf[3] = 0x27; wcusb_async_write(p, WCUSB_SPORT0, p->wcregbuf, 4, STATE_WCWRITE_WRITERES, wcusb_async_control);}#ifdef USB2420static void wcusb_async_control(struct urb *urb)#elsestatic void wcusb_async_control(urb_t *urb)#endif{ struct wc_usb_pvt *p = urb->context; p->urbcount--; if (urb->status) { printk("Error in transfer...\n"); p->timer = 50; return; } if (!(p->flags & FLAG_RUNNING)) { return; } switch (p->controlstate) { case STATE_WCREAD_WRITEREG: /* We've written the register to sport0, now read form sport 1 */ wcusb_async_read(p, WCUSB_SPORT1, &p->wcregval, 1, STATE_WCREAD_READRES, wcusb_async_control); return; case STATE_WCREAD_READRES: switch(p->wcregindex) { case 68: if (!p->hookstate && (p->wcregval & 1)) { p->hookstate = 1; if (debug) printk("Going off hook...\n"); zt_hooksig(&p->chan, ZT_RXSIG_OFFHOOK); } else if (p->hookstate && !(p->wcregval & 1)) { p->hookstate = 0; if (debug) printk("Going on hook...\n"); zt_hooksig(&p->chan, ZT_RXSIG_ONHOOK); } /* Set outgoing hook state if necessary */ if (p->txhook != p->newtxhook) { if (debug) printk("Really setting hook state to %d\n", p->newtxhook); p->txhook = p->newtxhook; proslic_write_direct_async(p, 64, p->newtxhook); } else p->timer = 50; break; case 64: if (debug) printk("Read hook state as %02x\n", p->wcregval); p->timer = 50; break; default: printk("dunno what to do with read/regindex %d\n", p->wcregindex); p->wcregindex = 0; } return; case STATE_WCWRITE_WRITERES: switch(p->wcregindex) { case 64: if (debug) { printk("Hook transition complete to %d\n", ((char *)(urb->transfer_buffer))[1]);#ifdef BOOST_RINGER } if (p->txhook == 4) { /* Ringing -- boost battery to 96V */ proslic_write_direct_async(p, 74, 0x3f); } else { /* Leave battery at default 75V */ proslic_write_direct_async(p, 74, 0x32); } break; case 74: if (debug) { printk("Battery set to -%dV\n", ((char *)(urb->transfer_buffer))[1] * 3 / 2);#endif proslic_read_direct_async(p, 64); } else p->timer = 50; break; default: printk("dunno what to do with write/regindex %d\n", p->wcregindex); p->wcregindex = 0; } return; default: printk("async control in unknown state %d\n", p->controlstate); }}#ifdef USB2420static void keypad_check_done(struct urb *urb)#elsestatic void keypad_check_done(urb_t *urb)#endif{ struct wc_usb_pvt *p = urb->context; struct wc_keypad_data *d = p->pvt_data; static char aux_pattern[] = {0x1e, 0x1d, 0x17, 0xf}; char digit = 'z'; p->urbcount--; if (!d->running) { printk("Stopping stream (check_done)\n"); return; } if (urb->status) { printk("status %d\n", urb->status); } if (debug) printk("i is %d\n", d->i); switch (d->state) {loop_start: case STATE_FOR_LOOP_1_OUT: if (debug) printk("data12 is %x\n", d->data12); if(d->i < sizeof(aux_pattern) / sizeof(char)) { d->tmp = aux_pattern[d->i] | (d->data12 & 0xe0); d->state = STATE_FOR_LOOP_2_IN; if (debug) printk("tmp is %x\n", d->tmp); wcusb_async_write(p, 0x12, &d->tmp, 1, 0, keypad_check_done); return; } else { goto func_end; } case STATE_FOR_LOOP_2_IN: d->state = STATE_FOR_LOOP_PROC_DATA; wcusb_async_read(p, 0xc0, &d->data, 1, 0, keypad_check_done); return; case STATE_FOR_LOOP_PROC_DATA: d->state = STATE_FOR_LOOP_CLEAR_DIGIT; if(debug) printk("data is %x\n", d->data); if ((d->data & 0x1f) != 0x1f) { if(d->data == 0xe && aux_pattern[d->i] == 0x1e) { digit = '1';} else if(d->data == 0xd && aux_pattern[d->i] == 0x1e) { digit = '2';} else if(d->data == 0xb && aux_pattern[d->i] == 0x1e) { digit = '3';} else if(d->data == 0x7 && aux_pattern[d->i] == 0x1e) { p->hookstate = 0; /* On||Off */ zt_hooksig(&p->chan, ZT_RXSIG_ONHOOK); } else if(d->data == 0xe && aux_pattern[d->i] == 0x1d) { digit = '4';} else if(d->data == 0xd && aux_pattern[d->i] == 0x1d) { digit = '5';} else if(d->data == 0xb && aux_pattern[d->i] == 0x1d) { digit = '6';} else if(d->data == 0x7 && aux_pattern[d->i] == 0x1d) { p->hookstate = 1;/* Dial */ zt_hooksig(&p->chan, ZT_RXSIG_OFFHOOK); } else if(d->data == 0xe && aux_pattern[d->i] == 0x17) { digit = '7';} else if(d->data == 0xd && aux_pattern[d->i] == 0x17) { digit = '8';} else if(d->data == 0xb && aux_pattern[d->i] == 0x17) { digit = '9';} else if(d->data == 0x7 && aux_pattern[d->i] == 0x17) d->scanned_event = 15; /* ReDial */ else if(d->data == 0xe && aux_pattern[d->i] == 0xf) { digit = '*';}/* '*' */ else if(d->data == 0xd && aux_pattern[d->i] == 0xf) { digit = '0';} else if(d->data == 0xb && aux_pattern[d->i] == 0xf) { digit = '#';} /* '#' */ else if(d->data == 0x7 && aux_pattern[d->i] == 0xf) d->scanned_event = 16; /* Volume? */ else { (d->i)++; if (debug) printk("Scanned event %d; data = %x\n", d->scanned_event, d->data); goto loop_start; } } else { if(debug) printk("Hit new if\n"); goto func_end; } if (debug) printk("wcusb: got digit %d\n", d->scanned_event); if (digit != 'z') { d->tone = zt_dtmf_tone(digit, 0); if (!d->tone) { printk("wcusb: Didn't get a tone structure\n"); goto func_end; } zt_init_tone_state(&d->ts, d->tone); p->sample = STREAM_DTMF; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -