📄 wcusb.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 "wcusb.h"#include "proslic.h"#ifndef FILL_CONTROL_URB#define FILL_CONTROL_URB usb_fill_control_urb#endif#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",0x8000},{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},};static int debug = 0;#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 USB2420#ifdef LINUX26static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb, struct pt_regs *regs));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, struct pt_regs *regs));static void wcusb_async_control(struct urb *urb, struct pt_regs *regs);#elsestatic 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);#endif /* LINUX26 */#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 USB2420#ifdef LINUX26static void wcusb_async_control(struct urb *urb, struct pt_regs *regs)#elsestatic void wcusb_async_control(struct urb *urb)#endif#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"); /* return is the "right thing", but don't... */ 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 USB2420#ifdef LINUX26static void keypad_check_done(struct urb *urb, struct pt_regs *regs)#elsestatic void keypad_check_done(struct urb *urb)#endif#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; } d->count = 0; case STATE_FOR_LOOP_CLEAR_DIGIT: if (((d->data & 0xf) != 0xf) && d->count < 200) { wcusb_async_read(p, 0xc0, &d->data, 1, 0, keypad_check_done); return; } (d->i)++; p->sample = STREAM_NORMAL; goto loop_start; }func_end: p->timer = 100; return;}static void wcusb_check_interrupt(struct wc_usb_pvt *p){ /* Start checking for interrupts */ if (p->devclass == WC_KEYPAD) { wcusb_check_keypad(p); } else { proslic_read_direct_async(p, 68); } return;}#ifdef USB2420#ifdef LINUX26static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb, struct pt_regs *regs))#elsestatic int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb))#endif /* LINUX26 */#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))#endif{ __u16 size = len; __u16 ind = index;#ifdef USB2420 struct urb *urb = &p->control; memset(urb, 0, sizeof(struct urb)); p->dr.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; p->dr.bRequest = REQUEST_NORMAL; p->dr.wValue = 0; p->dr.wIndex = cpu_to_le16(ind); p->dr.wLength = cpu_to_le16(size);#else urb_t *urb = &p->control; memset(urb, 0, sizeof(urb_t)); p->dr.requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; p->dr.request = REQUEST_NORMAL; p->dr.value = 0; p->dr.index = cpu_to_le16(ind); p->dr.length = cpu_to_le16(size);#endif FILL_CONTROL_URB(urb, p->dev, usb_rcvctrlpipe(p->dev, 0), (unsigned char *)&p->dr, data, len, complete, p);#ifdef LINUX26 if (usb_submit_urb(urb, GFP_KERNEL)) #else if (usb_submit_urb(urb)) #endif { printk("wcusb_async_read: control URB died\n"); p->timer = 50; return -1; } p->controlstate = state; p->urbcount++; return 0;}#ifdef USB2420#ifdef LINUX26static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb, struct pt_regs *regs))#elsestatic int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb))#endif /* LINUX26 */#elsestatic int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(urb_t *urb))#endif{ __u16 size = len; __u16 ind = index;#ifdef USB2420 struct urb *urb = &p->control; memset(urb, 0, sizeof(struct urb)); p->dr.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; p->dr.bRequest = REQUEST_NORMAL; p->dr.wValue = 0; p->dr.wIndex = cpu_to_le16(ind);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -