?? tjusb.c
字號:
/* * TigerJet Network USB Device Driver * * Written by Ping Liu <pliu@tjnet.com> * * Copyright (C) 2003 TigerJet Network 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. * * http://www.gnu.org/licenses/gpl.txt */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/fcntl.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/list.h>#include <linux/smp_lock.h>#include <linux/usb.h>#include <linux/devfs_fs_kernel.h>#include "tjusb.h"#include "proslic.h"/* Version Information */#define DRIVER_VERSION "v0.2"#define DRIVER_AUTHOR "Ping Liu, pliu@tjnet.com"#define DRIVER_DESC "Tigerjet USB Driver"#define USB_TJ_VENDOR_ID 0x06e6static int debug = 0;/* the global usb devfs handle */extern devfs_handle_t usb_devfs_handle;/* table of devices that work with this driver */static struct usb_device_id tjusb_table[] = { { match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_VENDOR), bInterfaceClass: USB_CLASS_VENDOR_SPEC, bInterfaceSubClass: 0xff, idVendor: 0x06e6, }, { } /* Terminating Entry */};MODULE_DEVICE_TABLE (usb, tjusb_table);/* Device types. */typedef enum { TJ_KEYPAD, /* The tigerjet phone with the keypad. */ TJ_PROSLIC, /* For various devices with a proslic */} dev_type_t;/* Structure to hold all of our device specific stuff */struct usb_tj { struct usb_device * udev; /* save off the usb device pointer */ struct usb_interface * interface; /* the interface for this device */ devfs_handle_t devfs; /* devfs device node */ unsigned char minor; /* the starting minor number for this device */ unsigned char num_ports; /* the number of ports this device has */ char num_interrupt_in; /* number of interrupt in endpoints we have */ char num_bulk_in; /* number of bulk in endpoints we have */ char num_bulk_out; /* number of bulk out endpoints we have */ unsigned char * bulk_in_buffer; /* the buffer to receive data */ int bulk_in_size; /* the size of the receive buffer */ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ unsigned char * bulk_out_buffer; /* the buffer to send data */ int bulk_out_size; /* the size of the send buffer */ struct urb * write_urb; /* the urb used to send data */ __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ struct tq_struct tqueue; /* task queue for line discipline waking up */ int open_count; /* number of times this port has been opened */ struct semaphore sem; /* locks this structure */ dev_type_t devclass;};// ProSlic Function prototypesstatic int readProSlicDirectReg(struct usb_device *dev, unsigned char address, unsigned char* data);static int writeProSlicDirectReg(struct usb_device *dev, unsigned char address, unsigned char 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 int initializeIndirectRegisters(struct usb_device *dev);static int verifyIndirectRegisters(struct usb_device *dev);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},};/* driver system interface function prototypes */static ssize_t tjusb_read (struct file *file, char *buffer, size_t count, loff_t *ppos);static ssize_t tjusb_write (struct file *file, const char *buffer, size_t count, loff_t *ppos);static int tjusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int tjusb_open (struct inode *inode, struct file *file);static int tjusb_release (struct inode *inode, struct file *file); static void * tjusb_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);static void tjusb_disconnect (struct usb_device *dev, void *ptr);static void tjusb_write_bulk_callback (struct urb *urb);/* array of pointers to our devices that are currently connected */static struct usb_tj *minor_table[MAX_DEVICES];/* lock to protect the minor_table structure */static DECLARE_MUTEX (minor_table_mutex);/* * File operations needed when we register this driver. * This assumes that this driver NEEDS file operations, * of course, which means that the driver is expected * to have a node in the /dev directory. If the USB * device were for a network interface then the driver * would use "struct net_driver" instead, and a serial * device would use "struct tty_driver". */static struct file_operations tjusb_fops = { owner: THIS_MODULE, read: tjusb_read, write: tjusb_write, ioctl: tjusb_ioctl, open: tjusb_open, release: tjusb_release,}; /* usb specific object needed to register this driver with the usb subsystem */static struct usb_driver tjusb_driver = { name: "tjusb", probe: tjusb_probe, disconnect: tjusb_disconnect, fops: &tjusb_fops, minor: USB_TJ_MINOR_BASE, id_table: tjusb_table,};static int Tjusb_WriteTjRegs(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("tjusb: timeout on vendor write\n"); return -1; } else if (res < 0) { printk("tjusb: Error executing control: status=%d\n",le32_to_cpu(res)); return -1; } return 0;} static int Tjusb_ReadTjRegs(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("tjusb: timeout on vendor read\n"); return -1; } else if (res < 0) { printk("tjusb: Error executing control: status=%d\n", le32_to_cpu(res)); return -1; } else { if(debug) printk("tjusb: Executed read, (add = %x) (data = %x)\n", index, (unsigned char) *data); } return 0;} /*** Write register to Tj560*/static int tjoutp(struct usb_device *dev, unsigned char address, unsigned char data){ if (!Tjusb_WriteTjRegs(dev, address, &data, 1)) return 0; return -1;}/*** read register from Tj560*/static int tjinp(struct usb_device *dev, unsigned char address, unsigned char* data ){ if (!Tjusb_ReadTjRegs(dev, address, data, 1)) return 0; return -1;}/* Don't call from an interrupt context */static int set_aux_ctrl(struct usb_tj *p, char uauxpins, int on){ char udata12 = 0; char udata13 = 0; tjinp(p->udev, 0x12, &udata12); tjinp(p->udev, 0x13, &udata13); tjoutp(p->udev, 0x12, on ? (uauxpins | udata12) : (~uauxpins & udata12)); tjoutp(p->udev, 0x13, uauxpins | udata13); return 0;}/*-------------------------------------------------- * ProSlic Functions *--------------------------------------------------*/ static int waitForProSlicIndirectRegAccess(struct usb_device *dev){ unsigned char count, data; count = 0; while (count++ < 3) { data = 0; readProSlicDirectReg(dev, I_STATUS, &data); if (!data) return 0; } if(count > 2) printk(" ##### Loop error #####\n"); return -1;}static int writeProSlicInDirectReg(struct usb_device *dev, unsigned char address, unsigned short data){ if(!waitForProSlicIndirectRegAccess(dev)) { if (!writeProSlicDirectReg(dev, IDA_LO,(unsigned char)(data & 0xFF))) { if(!writeProSlicDirectReg(dev, IDA_HI,(unsigned char)((data & 0xFF00)>>8))) { if(!writeProSlicDirectReg(dev, IAA,address)) return 0; } } } return -1;}/*** Read register from ProSlic*/int readProSlicDirectReg(struct usb_device *dev, unsigned char address, unsigned char* dataRead){ unsigned char data[4]; data[0] = address | 0x80; data[1] = 0; data[2] = 0; data[3] = 0x67; // write to TJ register 0x26 Tjusb_WriteTjRegs(dev, TJ_SPORT0, data, 4); Tjusb_ReadTjRegs(dev, TJ_SPORT1, data, 1); *dataRead = data[0]; return 0;}/*** Write register to ProSlic*/int writeProSlicDirectReg(struct usb_device *dev, unsigned char address, unsigned char RegValue){ unsigned char data[4]; data[0] = address & 0x7f; data[1] = RegValue; data[2] = 0; data[3] = 0x27; // write to TJ register 0x26 return Tjusb_WriteTjRegs(dev, TJ_SPORT0, data, 4);}static int readProSlicInDirectReg(struct usb_device *dev, unsigned char address, unsigned short *data){ if (!waitForProSlicIndirectRegAccess(dev)) { if (!writeProSlicDirectReg(dev,IAA,address)) { if(!waitForProSlicIndirectRegAccess(dev)) { unsigned char data1, data2; if (!readProSlicDirectReg(dev,IDA_LO, &data1) && !readProSlicDirectReg (dev, IDA_HI, &data2)) { *data = data1 | (data2 << 8); return 0; } else printk("Failed to read direct reg\n"); } else printk("Failed to wait inside\n"); } else printk("failed write direct IAA\n"); } else printk("failed to wait\n"); return -1;}static int initializeIndirectRegisters(struct usb_device *dev){ unsigned char i; for (i=0; i<43; i++) { if(writeProSlicInDirectReg(dev, i,indirect_regs[i].initial)) return -1; } return 0;}static int verifyIndirectRegisters(struct usb_device *dev){ int passed = 1; unsigned short i,j, initial; for (i=0; i<43; i++) { if(readProSlicInDirectReg(dev, (unsigned char) i, &j)) { printk("Failed to read indirect register %d\n", i); return -1; } initial= indirect_regs[i].initial; if ( j != initial ) { printk("!!!!!!! %s iREG %X = %X should be %X\n", indirect_regs[i].name,i,j,initial ); passed = 0; } } if (passed) { if (debug) printk("Init Indirect Registers completed successfully.\n"); } else { printk(" !!!!! Init Indirect Registers UNSUCCESSFULLY.\n"); } return 0;}static int calibrateAndActivateProSlic(struct usb_device *dev){ unsigned char x; if(writeProSlicDirectReg(dev, 92, 0xc8)) return -1; if(writeProSlicDirectReg(dev, 97, 0)) return -1; if(writeProSlicDirectReg(dev, 93, 0x19)) return -1; if(writeProSlicDirectReg(dev, 14, 0)) return -1; if(writeProSlicDirectReg(dev, 93, 0x99)) return -1; if(!readProSlicDirectReg (dev, 93, &x)) { if (debug) printk("DC Cal x=%x\n",x); if (!writeProSlicDirectReg(dev, 97, 0)) { if(!writeProSlicDirectReg(dev, CALIBR1, CALIBRATE_LINE)) { unsigned char data; if(!readProSlicDirectReg(dev, CALIBR1, &data)) return writeProSlicDirectReg(dev, LINE_STATE,ACTIVATE_LINE); } } } return -1;}static int InitProSlic(struct usb_device *dev){ if (writeProSlicDirectReg(dev, 67, 0x0e)) /* Disable Auto Power Alarm Detect and other "features" */ return -1; if (initializeIndirectRegisters(dev)) { printk(KERN_INFO "Indirect Registers failed to initialize.\n"); return -1; } if (verifyIndirectRegisters(dev)) { printk(KERN_INFO "Indirect Registers failed verification.\n"); return -1; } if (calibrateAndActivateProSlic(dev)) { printk(KERN_INFO "ProSlic Died on Activation.\n"); return -1; } if (writeProSlicInDirectReg(dev, 97, 0x0)) { // Stanley: for the bad recording fix printk(KERN_INFO "ProSlic IndirectReg Died.\n"); return -1; } if (writeProSlicDirectReg(dev, 1, 0x2a)) { // U-Law GCI 8-bit interface printk(KERN_INFO "ProSlic DirectReg Died.\n"); return -1; } if (writeProSlicDirectReg(dev, 2, 0)) // Tx Start count low byte 0 return -1; if (writeProSlicDirectReg(dev, 3, 0)) // Tx Start count high byte 0 return -1; if (writeProSlicDirectReg(dev, 4, 0)) // Rx Start count low byte 0 return -1; if (writeProSlicDirectReg(dev, 5, 0)) // Rx Start count high byte 0 return -1; if (writeProSlicDirectReg(dev, 8, 0x0)) // disable loopback return -1; if (writeProSlicDirectReg(dev, 18, 0xff)) // clear all interrupt return -1; if (writeProSlicDirectReg(dev, 19, 0xff)) return -1; if (writeProSlicDirectReg(dev, 20, 0xff)) return -1; if (writeProSlicDirectReg(dev, 21, 0x00)) // enable interrupt return -1; if (writeProSlicDirectReg(dev, 22, 0x02)) // Loop detection interrupt return -1; if (writeProSlicDirectReg(dev, 23, 0x01)) // DTMF detection interrupt return -1;// if (writeProSlicDirectReg(dev, 72, 0x20))// return -1;#ifdef BOOST_RINGER /* Beef up Ringing voltage to 89V */// if (writeProSlicInDirectReg(dev, 23, 0x1d1))// return -1;#endif return 0;}static int init_hardware(struct usb_tj *p){ struct usb_device *dev = p->udev; switch (p->devclass) { case TJ_PROSLIC: if (tjoutp(dev, 0x12, 0x00)) /* AUX6 as output, set to low */ return -1; if (tjoutp(dev, 0x13, 0x40)) /* AUX6 is output */ return -1; if (tjoutp(dev, 0, 0x50)) /* extrst, AUX2 is suspend */ return -1; if (tjoutp(dev, 0x29, 0x20)) /* enable SerialUP AUX pin definition */ return -1; if (tjoutp(dev, 0, 0x51)) /* no extrst, AUX2 is suspend */ return -1; /* Make sure there is no gain */ /* if (tjoutp(dev, 0x22, 0x00)) return -1; if (tjoutp(dev, 0x23, 0xf2)) return -1; if (tjoutp(dev, 0x24, 0x00))
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -