/* * Wilcard TC400B Digium Transcoder Engine Interface Driver for Zapata Telephony interface * * Written by John Sloan * * Copyright (C) 2006, Digium, 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_DEVFS_FS #include #endif #ifdef STANDALONE_ZAPATA #include "zaptel.h" #else #include #endif #ifdef LINUX26 #include #endif #include "dte_firm.h" /* #define USE_TEST_HW */ #define USE_TDM_CONFIG #define WC_MAX_IFACES 128 #define NUM_CARDS 24 #define NUM_EC 4 #define NUM_CHANNELS 97 #define DTE_FORMAT_ULAW 0x00 #define DTE_FORMAT_G723_1 0x04 #define DTE_FORMAT_ALAW 0x08 #define DTE_FORMAT_G729A 0x12 #define DTE_FORMAT_UNDEF 0xFF /* #define COMPLEX_CODEC DTE_FORMAT_G723_1 */ #define COMPLEX_CODEC DTE_FORMAT_G729A #define SIMPLE_CODEC DTE_FORMAT_ULAW #define SAMPLE_LENGTH 20 #define PACKET_OUT_SIZE 160 /* g.729 */ /* #define PACKET_OUT_SIZE 240 */ /* g.723 */ #define ACK_SPACE 20 #define MAX_COMMANDS (NUM_CHANNELS + ACK_SPACE) /* 1432 for boot, 274 for 30msec ulaw, 194 for 20mec ulaw */ #define BOOT_CMD_LEN 1500 #define OTHER_CMD_LEN 300 #define MAX_COMMAND_LEN BOOT_CMD_LEN /* Must be the larger of BOOT_CMD_LEN or OTHER_CMD_LEN */ #define ERING_SIZE (NUM_CHANNELS * 2) /* Maximum ring size */ #define SFRAME_SIZE MAX_COMMAND_LEN #define PCI_WINDOW_SIZE ((2* 2 * ERING_SIZE * SFRAME_SIZE) + (2 * ERING_SIZE * 4)) #define RCV_CSMENCAPS 1 #define RCV_RTP 2 #define RCV_OTHER 99 /* TDM Commands */ #define CMD_MSG_TDM_SELECT_BUS_MODE_LEN 30 #define CMD_MSG_TDM_SELECT_BUS_MODE(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0A, 0x01, 0x00,0x06,0x17,0x04, 0xFF,0xFF, 0x04,0x00} #define CMD_MSG_TDM_ENABLE_BUS_LEN 30 #define CMD_MSG_TDM_ENABLE_BUS(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0A, 0x02, 0x00,0x06,0x05,0x04, 0xFF,0xFF, 0x04,0x00} #define CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN 34 #define CMD_MSG_SUPVSR_SETUP_TDM_PARMS(s,p1,p2,p3) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x10, p1, 0x00,0x06,0x07,0x04, 0xFF,0xFF, p2,0x83, 0x00,0x0C, 0x00,0x00, p3,0x00} #define CMD_MSG_TDM_OPT_LEN 30 #define CMD_MSG_TDM_OPT(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x35,0x04, 0xFF,0xFF, 0x00,0x00} #define CMD_MSG_DEVICE_SET_COUNTRY_CODE_LEN 30 #define CMD_MSG_DEVICE_SET_COUNTRY_CODE(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x1B,0x04, 0xFF,0xFF, 0x00,0x00} #define CMD_MSG_SET_ARM_CLK_LEN 32 #define CMD_MSG_SET_ARM_CLK(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x11,0x04, 0x00,0x00, 0x2C,0x01, 0x00,0x00} #define CMD_MSG_SET_SPU_CLK_LEN 32 #define CMD_MSG_SET_SPU_CLK(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x12,0x04, 0x00,0x00, 0x2C,0x01, 0x00,0x00} #define CMD_MSG_ACK_LEN 20 #define CMD_MSG_ACK(s,c1,c2) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0xE0, c1, c2} #define CMD_MSG_SET_ETH_HEADER_LEN 44 #define CMD_MSG_SET_ETH_HEADER(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x18, 0x00, 0x00,0x06,0x00,0x01, 0xFF,0xFF, 0x01,0x00, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x00,0x11,0x22,0x33,0x44,0x55, 0x08,0x00}; #define CMD_MSG_IP_SERVICE_CONFIG_LEN 30 #define CMD_MSG_IP_SERVICE_CONFIG(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x02,0x03, 0xFF,0xFF, 0x00,0x02} #define CMD_MSG_ARP_SERVICE_CONFIG_LEN 30 #define CMD_MSG_ARP_SERVICE_CONFIG(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x05,0x01, 0xFF,0xFF, 0x01,0x00} #define CMD_MSG_ICMP_SERVICE_CONFIG_LEN 30 #define CMD_MSG_ICMP_SERVICE_CONFIG(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x04,0x03, 0xFF,0xFF, 0x01,0xFF} #define CMD_MSG_SPU_FEATURES_CONTROL_LEN 30 #define CMD_MSG_SPU_FEATURES_CONTROL(s,p1) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x13,0x00, 0xFF,0xFF, p1,0x00} #define CMD_MSG_IP_OPTIONS_LEN 30 #define CMD_MSG_IP_OPTIONS(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x06,0x03, 0xFF,0xFF, 0x02,0x00} #define CMD_MSG_CREATE_CHANNEL_LEN 32 #define CMD_MSG_CREATE_CHANNEL(s,t1,t2) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x10,0x00, 0x00,0x00, 0x02,0x00, t1, t2} #define CMD_MSG_SET_IP_HDR_CHANNEL_LEN 58 #define CMD_MSG_SET_IP_HDR_CHANNEL(s,c1,c2,s1,s2,s3,s4) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, c1,c2, 0x26, 0x00, 0x00,0x02,0x00,0x90, 0x00,0x00, 0x00,0x00, 0x45,0x00, 0x00,0x00, 0x00,0x00, 0x40,0x00, 0x80,0x11, 0x00,0x00, 0xC0,0xA8,0x09,0x03, 0xC0,0xA8,0x09,0x03, s1,s2, s3,s4, 0x00,0x00, 0x00,0x00} #define CMD_MSG_VOIP_VCEOPT_LEN 40 #define CMD_MSG_VOIP_VCEOPT(s,c1,c2,t,w) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, c1,c2, 0x12, 0x00, 0x00,0x02,0x01,0x80, 0x00,0x00, 0x31,t, 0x00,0x1C, 0x04,0x00, 0x00,0x00, w,0x00, 0x80,0x11} #define CMD_MSG_TRANS_CONNECT_LEN 38 #define CMD_MSG_TRANS_CONNECT(s,e,c1,c2,c3,c4) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x12, 0x00, 0x00,0x06,0x22,0x93, 0x00,0x00, e,0x00, c1,c2, COMPLEX_CODEC,0x00, c3,c4, 0x00,0x00} #define CMD_MSG_VOIP_VOPENA_LEN 44 #define CMD_MSG_VOIP_VOPENA(s,c1,c2,f) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, c1,c2, 0x16, 0x00, 0x00,0x02,0x00,0x80, 0x00,0x00, 0x01,0x00, 0x80,f, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x12,0x34, 0x56,0x78, 0x00,0x00} #define CMD_MSG_VOIP_VOPENA_CLOSE_LEN 32 #define CMD_MSG_VOIP_VOPENA_CLOSE(s,c1,c2,f) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, c1,c2, 0x0A, 0x00, 0x00,0x02,0x00,0x80, 0x00,0x00, 0x00,0x00, 0x00,0x00} #define CMD_MSG_DEVICE_STATUS_CONFIG_LEN 30 #define CMD_MSG_DEVICE_STATUS_CONFIG(s) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, 0x00,0x01, s, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x0F,0x04, 0xFF,0xFF, 0x05,0x00} #define CMD_MSG_IP_UDP_RTP_LEN 54 #define CMD_MSG_IP_UDP_RTP(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x08,0x00, 0x45,0x00, p1,p2, 0x00,p3, 0x40,0x00, 0x80,0x11, p4,p5, 0xC0,0xA8,0x09,0x03, 0xC0,0xA8,0x09,0x03, p6,p7, p8,p9, p10,p11, p12,p13, 0x80,p14, p15,p16, p17,p18,p19,p20, 0x12,0x34,0x56,0x78} #define zt_send_cmd(wc, command, length, hex) \ ({ \ do { \ if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) \ printk("wcdte error: cmdq is full.\n"); \ else { \ unsigned char fifo[OTHER_CMD_LEN] = command; \ wc->cmdq[wc->cmdq_wndx].cmdlen = length; \ for (i = 0; i < length; i++) \ wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i]; \ wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; \ } \ transmit_demand(wc); \ do { \ ret = wcdte_waitfor_csmencaps(wc); \ if (ret == 1) \ return(1); \ } while ((wc->last_rcommand != hex) && (ret != 2)); \ } while (ret == 2); \ }) /* define NOT_BLI to use a faster but not bit-level identical version */ /* #define NOT_BLI */ #if defined(NOT_BLI) # if defined(_MSC_VER) typedef __int64 sint64; # elif defined(__GNUC__) typedef long long sint64; # else # error 64-bit integer type is not defined for your compiler/platform # endif #endif struct cmdq { unsigned int cmdlen; unsigned int cmd[MAX_COMMAND_LEN]; }; struct wcdte { struct pci_dev *dev; char *variety; unsigned int intcount; unsigned int rxints; unsigned int txints; unsigned int intmask; int pos; int freeregion; int rdbl; int tdbl; int cards; spinlock_t reglock; wait_queue_head_t regq; int rcvflags; struct cmdq cmdq[MAX_COMMANDS]; unsigned int cmdq_wndx; unsigned int cmdq_rndx; unsigned int last_rcommand; unsigned int seq_num; unsigned long iobase; dma_addr_t readdma; dma_addr_t writedma; dma_addr_t descripdma; volatile unsigned int *writechunk; /* Double-word aligned write memory */ volatile unsigned int *readchunk; /* Double-word aligned read memory */ volatile unsigned int *descripchunk; /* Descriptors */ }; struct wcdte_desc { char *name; int flags; }; static struct wcdte_desc wcdte = { "Wildcard TC400B", 0 }; static struct wcdte *ifaces[WC_MAX_IFACES]; /* * The following is the definition of the state structure * used by the G.721/G.723 encoder and decoder to preserve their internal * state between successive calls. The meanings of the majority * of the state structure fields are explained in detail in the * CCITT Recommendation G.721. The field names are essentially indentical * to variable names in the bit level description of the coding algorithm * included in this Recommendation. */ struct dte_state { int encoder; /* If we're an encoder */ struct wcdte *wc; unsigned int timestamp; unsigned int seqno; unsigned int phys_in_chan; /* DTE chennel on which results we be received from */ unsigned int phys_out_chan; /* DTE channel to send data to */ unsigned int packets_sent; unsigned int packets_received; unsigned int last_dte_seqno; unsigned int dte_seqno_rcv; }; static int numchannels = NUM_CHANNELS - 1; static struct zt_transcoder *uencode; static struct zt_transcoder *udecode; static struct dte_state *encoders; static struct dte_state *decoders; static int debug = 0; static void dte_init_state(struct dte_state *state_ptr, int encoder, unsigned int channel, struct wcdte *wc) { state_ptr->encoder = encoder; state_ptr->wc = wc; state_ptr->timestamp = 0; state_ptr->seqno = 0; state_ptr->packets_sent = 0; state_ptr->packets_received = 0; state_ptr->last_dte_seqno = 0; state_ptr->dte_seqno_rcv = 0; if (encoder == 1) { state_ptr->phys_in_chan = channel * 2; state_ptr->phys_out_chan = channel * 2 + 1; } else { state_ptr->phys_in_chan = channel * 2 + 1; state_ptr->phys_out_chan = channel * 2; } } static unsigned int dte_fmt_to_pt(unsigned int fmt) { unsigned int pt; switch(fmt) { case ZT_FORMAT_G723_1: pt = DTE_FORMAT_G723_1; break; case ZT_FORMAT_ULAW: pt = DTE_FORMAT_ULAW; break; case ZT_FORMAT_ALAW: pt = DTE_FORMAT_ALAW; break; case ZT_FORMAT_G729A: pt = DTE_FORMAT_G729A; break; default: pt = DTE_FORMAT_UNDEF; } return(pt); } static inline void __wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val) { outl(val, wc->iobase + addr); } static inline unsigned int __wcdte_getctl(struct wcdte *wc, unsigned int addr) { return inl(wc->iobase + addr); } static inline void wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val) { unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); __wcdte_setctl(wc, addr, val); spin_unlock_irqrestore(&wc->reglock, flags); } static inline void wcdte_reinit_descriptor(struct wcdte *wc, int tx, int dbl, char *s) { int o2 = 0; o2 += dbl * 4; if (!tx) o2 += ERING_SIZE * 4; wc->descripchunk[o2] = cpu_to_le32(0x80000000); wcdte_setctl(wc, 0x0008, 0x00000000); } static inline unsigned int wcdte_getctl(struct wcdte *wc, unsigned int addr) { unsigned long flags; unsigned int val; spin_lock_irqsave(&wc->reglock, flags); val = __wcdte_getctl(wc, addr); spin_unlock_irqrestore(&wc->reglock, flags); return val; } static inline int __transmit_demand(struct wcdte *wc) { volatile unsigned char *writechunk; int o2,i,j; unsigned int reg, xmt_length; reg = __wcdte_getctl(wc, 0x0028) & 0x00700000; /* Already transmiting, no need to demand another */ if (!((reg == 0) || (reg = 6))) return(1); /* Nothing to transmit */ if (wc->cmdq_rndx == wc->cmdq_wndx) return(1); /* Nothing to transmit */ if (wc->cmdq[wc->cmdq_rndx].cmdlen == 0 ) return(1); writechunk = (volatile unsigned char *)(wc->writechunk); writechunk += wc->tdbl * SFRAME_SIZE; o2 = wc->tdbl * 4; do { } while ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000)); xmt_length = wc->cmdq[wc->cmdq_rndx].cmdlen; if (xmt_length < 64) xmt_length = 64; wc->descripchunk[o2+1] = cpu_to_le32((le32_to_cpu(wc->descripchunk[o2+1]) & 0xFBFFF800) | xmt_length); for(i = 0; i < wc->cmdq[wc->cmdq_rndx].cmdlen; i++) writechunk[i] = wc->cmdq[wc->cmdq_rndx].cmd[i]; for (j = i; j < xmt_length; j++) writechunk[j] = 0; wc->cmdq[wc->cmdq_rndx].cmdlen = 0; wc->descripchunk[o2] = cpu_to_le32(0x80000000); __wcdte_setctl(wc, 0x0008, 0x00000000); /* Transmit Poll Demand */ wc->tdbl = (wc->tdbl + 1) % ERING_SIZE; wc->cmdq_rndx = (wc->cmdq_rndx + 1) % MAX_COMMANDS; return(0); } static inline int transmit_demand(struct wcdte *wc) { unsigned long flags; int val; spin_lock_irqsave(&wc->reglock, flags); val = __transmit_demand(wc); spin_unlock_irqrestore(&wc->reglock, flags); return val; } static int dte_operation(struct zt_transcoder_channel *ztc, int op) { struct dte_state *st = ztc->pvt; struct zt_transcode_header *zth = ztc->tch; struct wcdte *wc = st->wc; unsigned char *chars; unsigned int inbytes = 0; unsigned int timestamp_inc = 0; int i = 0; int res = 0; unsigned long flags; unsigned int ipchksum; switch(op) { case ZT_TCOP_RESET: break; case ZT_TCOP_TRANSCODE: spin_lock_irqsave(&wc->reglock, flags); if ( (((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) && (zth->srclen >= 160)) || ((zth->srcfmt == ZT_FORMAT_G729A) && (zth->srclen >= 20)) || ((zth->srcfmt == ZT_FORMAT_G723_1) && (zth->srclen >= 24)) ) { do { chars = (unsigned char *)(zth->srcdata + zth->srcoffset); if ((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) { inbytes = 160; /* 80; */ timestamp_inc = 160; /* 80; */ } else if (zth->srcfmt == ZT_FORMAT_G729A) { inbytes = 20; /* 10; */ timestamp_inc = 160; /* 80; */ } else if (zth->srcfmt == ZT_FORMAT_G723_1) { inbytes = 24; timestamp_inc = 240; } zth->srclen -= inbytes; { unsigned char fifo[OTHER_CMD_LEN] = CMD_MSG_IP_UDP_RTP( ((inbytes+40) >> 8) & 0xFF, (inbytes+40) & 0xFF, st->seqno & 0xFF, 0x00, 0x00, (((st->phys_out_chan) >> 8)+0x50) & 0xFF, (st->phys_out_chan) & 0xFF, (((st->phys_in_chan) >> 8)+0x50) & 0xFF, (st->phys_in_chan) & 0xFF, ((inbytes+20) >> 8) & 0xFF, (inbytes+20) & 0xFF, 0x00, 0x00, dte_fmt_to_pt(zth->srcfmt), ((st->seqno) >> 8) & 0xFF, (st->seqno) & 0xFF, ((st->timestamp) >> 24) & 0xFF, ((st->timestamp) >> 16) & 0xFF, ((st->timestamp) >> 8) & 0xFF, (st->timestamp) & 0xFF); ipchksum = 0x9869 + (fifo[16] << 8) + fifo[17] + (fifo[18] << 8) + fifo[19]; while (ipchksum >> 16) ipchksum = (ipchksum & 0xFFFF) + (ipchksum >> 16); ipchksum = (~ipchksum) & 0xFFFF; fifo[24] = ipchksum >> 8; fifo[25] = ipchksum & 0xFF; st->seqno += 1; st->timestamp += timestamp_inc; for (i = 0; i < inbytes; i++) fifo[i+CMD_MSG_IP_UDP_RTP_LEN]= chars[i]; if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) printk("wcdte error: cmdq is full.\n"); else { wc->cmdq[wc->cmdq_wndx].cmdlen = CMD_MSG_IP_UDP_RTP_LEN+inbytes; for (i = 0; i < CMD_MSG_IP_UDP_RTP_LEN+inbytes; i++) wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i]; wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; } } st->packets_sent++; __transmit_demand(wc); zth->srcoffset += inbytes; } while ( (((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) && (zth->srclen >= 160)) || ((zth->srcfmt == ZT_FORMAT_G729A) && (zth->srclen >= 20)) || ((zth->srcfmt == ZT_FORMAT_G723_1) && (zth->srclen >= 24)) ); } else { zt_transcoder_alert(ztc); } spin_unlock_irqrestore(&wc->reglock, flags); res = 0; break; } return res; } static void wcdte_stop_dma(struct wcdte *wc); static inline void wcdte_receiveprep(struct wcdte *wc, int dbl) { volatile unsigned char *readchunk; struct zt_transcoder_channel *ztc = NULL; struct zt_transcode_header *zth = NULL; struct dte_state *st = NULL; int o2,i; unsigned char rseq, rcodec; unsigned int reg, rchannel, rlen, rtp_rseq, rtp_eseq; unsigned char *chars = NULL; unsigned int ztc_ndx; readchunk = (volatile unsigned char *)wc->readchunk; readchunk += dbl * SFRAME_SIZE; o2 = dbl * 4; o2 += ERING_SIZE * 4; reg = wcdte_getctl(wc, 0x0001); /* Control in packet */ if ((readchunk[12] == 0x88) && (readchunk[13] == 0x9B)) { wc->rcvflags = RCV_CSMENCAPS; wc->last_rcommand = readchunk[24] | (readchunk[25] << 8); /* See if message must be ACK'd */ if ((readchunk[17] & 0xC0) == 0) { rchannel = readchunk[18] | (readchunk[19] << 8); rseq = readchunk[16]; if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) printk("wcdte error: cmdq is full (rndx = %d, wndx = %d).\n", wc->cmdq_rndx, wc->cmdq_wndx); else { unsigned char fifo[OTHER_CMD_LEN] = CMD_MSG_ACK((rseq++)&0x0F, rchannel&0x00FF, (rchannel>>8)&0x00FF); wc->cmdq[wc->cmdq_wndx].cmdlen = CMD_MSG_ACK_LEN; for (i = 0; i < wc->cmdq[wc->cmdq_wndx].cmdlen; i++) wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i]; wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; } transmit_demand(wc); } } /* IP/UDP in packet */ else if ((readchunk[12] == 0x08) && (readchunk[13] == 0x00) && (readchunk[50] == 0x12) && (readchunk[51] == 0x34) && (readchunk[52] = 0x56) && (readchunk[53] == 0x78)) { wc->rcvflags = RCV_RTP; rchannel = (readchunk[37] | (readchunk[36] << 8)) - 0x5000; rlen = (readchunk[39] | (readchunk[38] << 8)) - 20; rtp_rseq = (readchunk[45] | (readchunk[44] << 8)); rcodec = readchunk[43]; ztc_ndx = rchannel/2; if (ztc_ndx >= numchannels) { if (debug) printk("wcdte error: Invalid channel number received (ztc_ndx = %d) (numchannels = %d)\n", ztc_ndx, numchannels); rcodec = DTE_FORMAT_UNDEF; } if ((rcodec == 0x00) || (rcodec == 0x08)) /* ulaw or alaw (decoders) */ { ztc = &(udecode->channels[ztc_ndx]); zth = ztc->tch; st = ztc->pvt; if (zth == NULL) { if (debug) printk("wcdte error: Tried to put DTE data into a freed zth header!\n"); rcodec = DTE_FORMAT_UNDEF; } else { chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen); st->packets_received++; } } if ((rcodec == 0x04) || (rcodec == 0x12)) /* g.723 or g.729 (encoders) */ { ztc = &(uencode->channels[ztc_ndx]); zth = ztc->tch; st = ztc->pvt; if (zth == NULL) { if (debug) printk("wcdte error: Tried to put DTE data into a freed zth header!\n"); rcodec = DTE_FORMAT_UNDEF; } else { chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen); st->packets_received++; } } if (st->dte_seqno_rcv == 0) { st->dte_seqno_rcv = 1; st->last_dte_seqno = rtp_rseq; } else { rtp_eseq = (st->last_dte_seqno + 1) & 0xFFFF; if ( (rtp_rseq != rtp_eseq) && debug ) printk("wcdte error: Bad seqno from DTE! [%d][%d][%d]\n", rchannel, rtp_rseq, st->last_dte_seqno); st->last_dte_seqno = rtp_rseq; } if (rcodec == 0x00) /* ulaw */ { if (zt_tc_sanitycheck(zth, rlen) && (rlen == 160)) { for (i = 0; i < rlen; i++) chars[i] = readchunk[i+54]; zth->dstlen += rlen; zth->dstsamples = zth->dstlen; } else { ztc->errorstatus = -EOVERFLOW; } if (!(zth->dstsamples % PACKET_OUT_SIZE)) { zt_transcoder_alert(ztc); } } else if (rcodec == 0x08) /* alaw */ { if (zt_tc_sanitycheck(zth, rlen) && (rlen == 160)) { for (i = 0; i < rlen; i++) chars[i] = readchunk[i+54]; zth->dstlen += rlen; zth->dstsamples = zth->dstlen; } else { ztc->errorstatus = -EOVERFLOW; } zt_transcoder_alert(ztc); } else if (rcodec == 0x04) /* g.723.1 */ { if (zt_tc_sanitycheck(zth, rlen) && (rlen == 24)) { for (i = 0; i < rlen; i++) chars[i] = readchunk[i+54]; zth->dstlen += rlen; zth->dstsamples = zth->dstlen * 10; } else { ztc->errorstatus = -EOVERFLOW; } if (!(zth->dstsamples % PACKET_OUT_SIZE)) { zt_transcoder_alert(ztc); } } else if (rcodec == 0x12) /* g.729a */ { if (zt_tc_sanitycheck(zth, rlen) && (rlen == 20)) { for (i = 0; i < rlen; i++) chars[i] = readchunk[i+54]; zth->dstlen += rlen; zth->dstsamples = zth->dstlen * 8; } else { ztc->errorstatus = -EOVERFLOW; } if (!(zth->dstsamples % PACKET_OUT_SIZE)) { zt_transcoder_alert(ztc); } } } else wc->rcvflags = RCV_OTHER; wake_up_interruptible(&wc->regq); } /* static inline int wcdte_check_descriptor(struct wcdte *wc) */ static int wcdte_check_descriptor(struct wcdte *wc) { int o2 = 0; o2 += ERING_SIZE * 4; o2 += wc->rdbl * 4; if (!(le32_to_cpu(wc->descripchunk[o2]) & 0x80000000)) { wc->rxints++; wcdte_receiveprep(wc, wc->rdbl); wcdte_reinit_descriptor(wc, 0, wc->rdbl, "rxchk"); wc->rdbl = (wc->rdbl + 1) % ERING_SIZE; return 1; } return 0; } static void wcdte_init_descriptors(struct wcdte *wc) { volatile unsigned int *descrip; dma_addr_t descripdma; dma_addr_t writedma; dma_addr_t readdma; int x; descrip = wc->descripchunk; descripdma = wc->descripdma; writedma = wc->writedma; readdma = wc->readdma; for (x=0;xdescripdma; /* Transmit descriptor */ descrip[0 ] = cpu_to_le32(0x00000000); descrip[1 ] = cpu_to_le32(0xe5800000 | (SFRAME_SIZE)); descrip[2 ] = cpu_to_le32(writedma + x*SFRAME_SIZE); descrip[3 ] = cpu_to_le32(descripdma); /* Receive descriptor */ descrip[0 + ERING_SIZE * 4] = cpu_to_le32(0x80000000); descrip[1 + ERING_SIZE * 4] = cpu_to_le32(0x01000000 | (SFRAME_SIZE)); descrip[2 + ERING_SIZE * 4] = cpu_to_le32(readdma + x*SFRAME_SIZE); descrip[3 + ERING_SIZE * 4] = cpu_to_le32(descripdma + ERING_SIZE * 16); /* Advance descriptor */ descrip += 4; } } #ifdef LINUX26 static irqreturn_t wcdte_interrupt(int irq, void *dev_id, struct pt_regs *regs) #else static void wcdte_interrupt(int irq, void *dev_id, struct pt_regs *regs) #endif { struct wcdte *wc = dev_id; unsigned int ints; int res; /* Read and clear interrupts */ ints = wcdte_getctl(wc, 0x0028); wcdte_setctl(wc, 0x0028, ints); if (!ints) #ifdef LINUX26 return IRQ_NONE; #else return; #endif ints &= wc->intmask; /* Handle RX interrupts */ if (ints & 0x00000040) { /* Loop descriptors is available */ do { res = wcdte_check_descriptor(wc); } while(res); } /* Handle TX interrupts */ if (ints & 0x00000001) { wc->txints++; transmit_demand(wc); wc->intcount++; } if ((ints & 0x00008000) && debug) printk("wcdte: Abormal Interrupt: "); if ((ints & 0x00002000) && debug) printk("wcdte: Fatal Bus Error INT\n"); if ((ints & 0x00000100) && debug) printk("wcdte: Receive Stopped INT\n"); if ((ints & 0x00000080) && debug) printk("wcdte: Receive Desciptor Unavailable INT\n"); if ((ints & 0x00000020) && debug) printk("wcdte: Transmit Under-flow INT\n"); if ((ints & 0x00000008) && debug) printk("wcdte: Jabber Timer Time-out INT\n"); if ((ints & 0x00000004) && debug) printk("wcdte: Transmit Descriptor Unavailable INT\n"); if ((ints & 0x00000002) && debug) printk("wcdte: Transmit Processor Stopped INT\n"); #ifdef LINUX26 return IRQ_RETVAL(1); #endif } static int wcdte_hardware_init(struct wcdte *wc) { /* Hardware stuff */ unsigned int reg; unsigned long newjiffies; /* Initialize descriptors */ wcdte_init_descriptors(wc); /* Enable I/O Access */ pci_read_config_dword(wc->dev, 0x0004, ®); reg |= 0x00000007; pci_write_config_dword(wc->dev, 0x0004, reg); wcdte_setctl(wc, 0x0000, 0xFFF88001); newjiffies = jiffies + HZ/10; while(((reg = wcdte_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies)); /* Configure watchdogs, access, etc */ wcdte_setctl(wc, 0x0030, 0x00280048); wcdte_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */); reg = wcdte_getctl(wc, 0x00fc); wcdte_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7); reg = wcdte_getctl(wc, 0x00fc); return 0; } static void wcdte_setintmask(struct wcdte *wc, unsigned int intmask) { wc->intmask = intmask; wcdte_setctl(wc, 0x0038, intmask); } static void wcdte_enable_interrupts(struct wcdte *wc) { /* Enable interrupts */ if (!debug) wcdte_setintmask(wc, 0x00010041); else wcdte_setintmask(wc, 0x0001A1EB); } static void wcdte_start_dma(struct wcdte *wc) { unsigned int reg; wmb(); wcdte_setctl(wc, 0x0020, wc->descripdma); wcdte_setctl(wc, 0x0018, wc->descripdma + (16 * ERING_SIZE)); /* Start receiver/transmitter */ reg = wcdte_getctl(wc, 0x0030); wcdte_setctl(wc, 0x0030, reg | 0x00002002); /* Start XMT and RCD */ wcdte_setctl(wc, 0x0010, 0x00000000); /* Receive Poll Demand */ reg = wcdte_getctl(wc, 0x0028); wcdte_setctl(wc, 0x0028, reg); } static void wcdte_stop_dma(struct wcdte *wc) { /* Disable interrupts and reset */ unsigned int reg; /* Disable interrupts */ wcdte_setintmask(wc, 0x00000000); wcdte_setctl(wc, 0x0084, 0x00000000); wcdte_setctl(wc, 0x0048, 0x00000000); /* Reset the part to be on the safe side */ reg = wcdte_getctl(wc, 0x0000); reg |= 0x00000001; wcdte_setctl(wc, 0x0000, reg); } static void wcdte_disable_interrupts(struct wcdte *wc) { /* Disable interrupts */ wcdte_setintmask(wc, 0x00000000); wcdte_setctl(wc, 0x0084, 0x00000000); } static int wcdte_waitfor_csmencaps(struct wcdte *wc) { int ret; #ifdef LINUX26 ret = wait_event_interruptible_timeout(wc->regq, wc->rcvflags != 0, (1*HZ)); #else /* Since timeout versions of wait_event... don't exist, */ /* make a success ret look like ir didn't timeout */ /* It may be good to look for a 2.4 compatible timeout mechanism */ ret = wait_event_interruptible(wc->regq, wc->rcvflags != 0); if (ret == 0) ret = 1; #endif if (ret < 0) { if (debug) printk("wcdte error: Wait interrupted, need to stop boot (ret = %d)\n", ret); return(1); } if (ret == 0) { if (debug) printk("wcdte error: Waitfor CSMENCAPS ACK timed out (ret = %d)\n", ret); return(2); } if (wc->rcvflags != RCV_CSMENCAPS) { printk("wcdte error: DTE processor failed to respond\n"); return(1); } wc->rcvflags = 0; return(0); } static int wcdte_boot_processor(struct wcdte *wc) { int i, j, byteloc, last_byteloc, length, delay_count; unsigned int reg, ret; #ifndef USE_TEST_HW /* Set reset */ wcdte_setctl(wc, 0x00A0, 0x04000000); /* Wait 300msec to ensure processor reset */ mdelay(300); /* Clear reset */ wcdte_setctl(wc, 0x00A0, 0x04080000); /* Waitfor ethernet link */ delay_count = 0; do { reg = wcdte_getctl(wc, 0x00fc); mdelay(100); delay_count++; if (delay_count >= 100) { printk("wcdte error: Failed to link to DTE processor!\n"); return(1); } } while ((reg & 0xE0000000) != 0xE0000000); /* Turn off booted LED */ wcdte_setctl(wc, 0x00A0, 0x04084000); #endif reg = wcdte_getctl(wc, 0x00fc); if (debug) printk("LINK STATUS: reg(0xfc) = %X\n", reg); reg = wcdte_getctl(wc, 0x00A0); byteloc = 0; j = 0; do { last_byteloc = byteloc; length = (wcdte_firmware[byteloc] << 8) | wcdte_firmware[byteloc+1]; byteloc += 2; if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) printk("wcdte error: cmdq is full.\n"); else { wc->cmdq[wc->cmdq_wndx].cmdlen = length; for (i = 0; i < length; i++) wc->cmdq[wc->cmdq_wndx].cmd[i] = wcdte_firmware[byteloc++]; wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; } transmit_demand(wc); ret = wcdte_waitfor_csmencaps(wc); if (ret == 1) return(1); else if (ret == 2) /* Retransmit if dte processor times out */ byteloc = last_byteloc; j++; } while (byteloc < sizeof(wcdte_firmware)-20); /* Waitfor code to start */ if (wcdte_waitfor_csmencaps(wc)) return(1); /* Turn on booted LED */ wcdte_setctl(wc, 0x00A0, 0x04080000); if (debug) printk("wcdte: Successfully booted DTE processor.\n"); return(0); } static int wcdte_setup_channels(struct wcdte *wc) { int i, j, ret; unsigned int part1_id, part2_id; #ifndef USE_TEST_HW zt_send_cmd(wc, CMD_MSG_SET_ARM_CLK((wc->seq_num++)&0x0F), CMD_MSG_SET_ARM_CLK_LEN, 0x0411); zt_send_cmd(wc, CMD_MSG_SET_SPU_CLK((wc->seq_num++)&0x0F), CMD_MSG_SET_SPU_CLK_LEN, 0x0412); #endif #ifdef USE_TDM_CONFIG zt_send_cmd(wc, CMD_MSG_TDM_SELECT_BUS_MODE((wc->seq_num++)&0x0F), CMD_MSG_TDM_SELECT_BUS_MODE_LEN, 0x0417); zt_send_cmd(wc, CMD_MSG_TDM_ENABLE_BUS((wc->seq_num++)&0x0F), CMD_MSG_TDM_ENABLE_BUS_LEN, 0x0405); zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS((wc->seq_num++)&0x0F, 0x03, 0x20, 0x00), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS((wc->seq_num++)&0x0F, 0x04, 0x80, 0x04), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS((wc->seq_num++)&0x0F, 0x05, 0x20, 0x08), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS((wc->seq_num++)&0x0F, 0x06, 0x80, 0x0C), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); #endif zt_send_cmd(wc, CMD_MSG_SET_ETH_HEADER((wc->seq_num++)&0x0F), CMD_MSG_SET_ETH_HEADER_LEN, 0x0100); zt_send_cmd(wc, CMD_MSG_IP_SERVICE_CONFIG((wc->seq_num++)&0x0F), CMD_MSG_IP_SERVICE_CONFIG_LEN, 0x0302); zt_send_cmd(wc, CMD_MSG_ARP_SERVICE_CONFIG((wc->seq_num++)&0x0F), CMD_MSG_ARP_SERVICE_CONFIG_LEN, 0x0105); zt_send_cmd(wc, CMD_MSG_ICMP_SERVICE_CONFIG((wc->seq_num++)&0x0F), CMD_MSG_ICMP_SERVICE_CONFIG_LEN, 0x0304); #ifdef USE_TDM_CONFIG zt_send_cmd(wc, CMD_MSG_DEVICE_SET_COUNTRY_CODE((wc->seq_num++)&0x0F), CMD_MSG_DEVICE_SET_COUNTRY_CODE_LEN, 0x041B); #endif zt_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL((wc->seq_num++)&0x0F, 0x02), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013); zt_send_cmd(wc, CMD_MSG_IP_OPTIONS((wc->seq_num++)&0x0F), CMD_MSG_IP_OPTIONS_LEN, 0x0306); zt_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL((wc->seq_num++)&0x0F, 0x04), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013); #ifdef USE_TDM_CONFIG zt_send_cmd(wc, CMD_MSG_TDM_OPT((wc->seq_num++)&0x0F), CMD_MSG_TDM_OPT_LEN, 0x0435); #endif part1_id = 0; part2_id = 1; for(j = 0; j < NUM_CHANNELS; j++) { /* Create complex channel */ zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL((wc->seq_num++)&0x0F, (part1_id&0x00FF), (part1_id&0xFF00) >> 8), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010); zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL((wc->seq_num++)&0x0F, (part1_id&0xFF00) >> 8, (part1_id&0x00FF),((part2_id&0xFF00) >> 8) + 0x50, (part2_id&0x00FF), ((part1_id&0xFF00) >> 8) + 0x50, (part1_id&0x00FF)), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000); zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT((wc->seq_num++)&0x0F, (part1_id&0xFF00) >> 8, (part1_id&0x00FF), SAMPLE_LENGTH, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001); /* Create simple channel */ zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL((wc->seq_num++)&0x0F, (part2_id&0x00FF), (part2_id&0xFF00) >> 8), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010); zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL((wc->seq_num++)&0x0F, (part2_id&0xFF00) >> 8, (part2_id&0x00FF),((part1_id&0xFF00) >> 8) + 0x50, (part1_id&0x00FF), ((part2_id&0xFF00) >> 8) + 0x50, (part2_id&0x00FF)), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000); zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT((wc->seq_num++)&0x0F, (part2_id&0xFF00) >> 8, (part2_id&0x00FF), SAMPLE_LENGTH, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001); zt_send_cmd(wc, CMD_MSG_TRANS_CONNECT((wc->seq_num++)&0x0F, 1, (part1_id&0x00FF), (part1_id&0xFF00) >> 8, (part2_id&0x00FF), (part2_id&0xFF00) >> 8), CMD_MSG_TRANS_CONNECT_LEN, 0x9322); zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA((wc->seq_num++)&0x0F, (part1_id&0xFF00) >> 8, (part1_id&0x00FF), COMPLEX_CODEC), CMD_MSG_VOIP_VOPENA_LEN, 0x8000); zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA((wc->seq_num++)&0x0F, (part2_id&0xFF00) >> 8, (part2_id&0x00FF), SIMPLE_CODEC), CMD_MSG_VOIP_VOPENA_LEN, 0x8000); part1_id += 2; part2_id += 2; } if (debug) zt_send_cmd(wc, CMD_MSG_DEVICE_STATUS_CONFIG((wc->seq_num++)&0x0F), CMD_MSG_DEVICE_STATUS_CONFIG_LEN, 0x040F); return(0); } static int __devinit wcdte_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int res, reg; struct wcdte *wc; struct wcdte_desc *d = (struct wcdte_desc *)ent->driver_data; int x; static int initd_ifaces=0; if(initd_ifaces){ memset((void *)ifaces,0,(sizeof(struct wcdte *))*WC_MAX_IFACES); initd_ifaces=1; } for (x=0;x= WC_MAX_IFACES) { printk("Too many interfaces\n"); return -EIO; } if (pci_enable_device(pdev)) { res = -EIO; } else { wc = vmalloc(sizeof(struct wcdte)); if (wc) { ifaces[x] = wc; memset(wc, 0, sizeof(struct wcdte)); spin_lock_init(&wc->reglock); wc->cards = NUM_CARDS; wc->iobase = pci_resource_start(pdev, 0); wc->dev = pdev; wc->pos = x; wc->variety = d->name; wc->tdbl = 0; wc->rdbl = 0; wc->rcvflags = 0; wc->last_rcommand = 0; wc->cmdq_wndx = 0; wc->cmdq_rndx = 0; wc->seq_num = 6; /* Keep track of whether we need to free the region */ if (request_region(wc->iobase, 0xff, "wcdte")) wc->freeregion = 1; /* Allocate enought memory for all TX buffers, RX buffers, and descriptors */ wc->writechunk = (int *)pci_alloc_consistent(pdev, PCI_WINDOW_SIZE, &wc->writedma); if (!wc->writechunk) { printk("wcdte error: Unable to allocate DMA-able memory\n"); if (wc->freeregion) release_region(wc->iobase, 0xff); return -ENOMEM; } wc->readchunk = wc->writechunk + (SFRAME_SIZE * ERING_SIZE) / 4; /* in doublewords */ wc->readdma = wc->writedma + (SFRAME_SIZE * ERING_SIZE); /* in bytes */ wc->descripchunk = wc->readchunk + (SFRAME_SIZE * ERING_SIZE) / 4; /* in doublewords */ wc->descripdma = wc->readdma + (SFRAME_SIZE * ERING_SIZE); /* in bytes */ /* Initialize Write/Buffers to all blank data */ memset((void *)wc->writechunk,0x00, SFRAME_SIZE * 2); memset((void *)wc->readchunk, 0x00, SFRAME_SIZE * 2); init_waitqueue_head(&wc->regq); /* Setup Encoders nad Decoders */ uencode = zt_transcoder_alloc(numchannels); udecode = zt_transcoder_alloc(numchannels); encoders = vmalloc(sizeof(struct dte_state) * numchannels); decoders = vmalloc(sizeof(struct dte_state) * numchannels); memset(encoders, 0, sizeof(struct dte_state) * numchannels); memset(decoders, 0, sizeof(struct dte_state) * numchannels); if (!uencode || !udecode || !encoders || !decoders) { if (uencode) zt_transcoder_free(uencode); if (udecode) zt_transcoder_free(udecode); if (encoders) vfree(encoders); if (decoders) vfree(decoders); return -ENOMEM; } sprintf(udecode->name, "DTE Decoder"); sprintf(uencode->name, "DTE Encoder"); /* udecode->srcfmts = uencode->dstfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1; */ /* udecode->dstfmts = uencode->srcfmts = ZT_FORMAT_ULAW | ZT_FORMAT_ALAW; */ udecode->srcfmts = uencode->dstfmts = ZT_FORMAT_G729A; udecode->dstfmts = uencode->srcfmts = ZT_FORMAT_ULAW; udecode->operation = uencode->operation = dte_operation; for (x=0;xchannels[x].pvt = encoders + x; udecode->channels[x].pvt = decoders + x; } zt_transcoder_register(uencode); zt_transcoder_register(udecode); printk("Zaptel DTE (G.729/G.723) Transcoder support LOADED\n"); /* Enable bus mastering */ pci_set_master(pdev); /* Keep track of which device we are */ pci_set_drvdata(pdev, wc); if (request_irq(pdev->irq, wcdte_interrupt, SA_SHIRQ, "tc400b", wc)) { printk("wcdte error: Unable to request IRQ %d\n", pdev->irq); if (wc->freeregion) release_region(wc->iobase, 0xff); pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma); pci_set_drvdata(pdev, NULL); vfree(wc); return -EIO; } if (wcdte_hardware_init(wc)) { /* Set Reset Low */ wcdte_stop_dma(wc); /* Free Resources */ free_irq(pdev->irq, wc); if (wc->freeregion) release_region(wc->iobase, 0xff); pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma); pci_set_drvdata(pdev, NULL); vfree(wc); return -EIO; } /* Enable interrupts */ wcdte_enable_interrupts(wc); /* Start DMA */ wcdte_start_dma(wc); if (wcdte_boot_processor(wc)) { /* Set Reset Low */ wcdte_stop_dma(wc); /* Free Resources */ free_irq(pdev->irq, wc); if (wc->freeregion) release_region(wc->iobase, 0xff); pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma); pci_set_drvdata(pdev, NULL); vfree(wc); return -EIO; } if (wcdte_setup_channels(wc)) { /* Set Reset Low */ wcdte_stop_dma(wc); /* Free Resources */ free_irq(pdev->irq, wc); if (wc->freeregion) release_region(wc->iobase, 0xff); pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma); pci_set_drvdata(pdev, NULL); vfree(wc); return -EIO; } reg = wcdte_getctl(wc, 0x00fc); if (debug) printk("(post-boot) Reg fc is %08x\n", reg); printk("Found a Wildcard TC: %s \n", wc->variety); res = 0; } else res = -ENOMEM; } return res; } static void wcdte_release(struct wcdte *wc) { if (wc->freeregion) release_region(wc->iobase, 0xff); vfree(wc); printk("Freed a Wildcard\n"); } static void __devexit wcdte_remove_one(struct pci_dev *pdev) { struct wcdte *wc = pci_get_drvdata(pdev); if (wc) { /* Stop any DMA */ wcdte_stop_dma(wc); /* In case hardware is still there */ wcdte_disable_interrupts(wc); /* Immediately free resources */ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma); free_irq(pdev->irq, wc); /* Release span, possibly delayed */ wcdte_release(wc); } } static struct pci_device_id wcdte_pci_tbl[] = { #ifndef USE_TEST_HW { 0xd161, 0x3400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcdte }, /* digium board */ #else { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcdte }, /*reference board */ #endif { 0 } }; MODULE_DEVICE_TABLE(pci, wcdte_pci_tbl); static struct pci_driver wcdte_driver = { name: "ztcodec_dte", probe: wcdte_init_one, #ifdef LINUX26 remove: __devexit_p(wcdte_remove_one), #else remove: wcdte_remove_one, #endif suspend: NULL, resume: NULL, id_table: wcdte_pci_tbl, }; int ztdte_init(void) { int res; res = pci_module_init(&wcdte_driver); if (res) return -ENODEV; return 0; } void ztdte_cleanup(void) { int i; if (debug) { for(i = 0; i < NUM_CHANNELS; i++) { printk("encoder[%d] packets_sent = %d, packets_received = %d [%d]\n", i, encoders[i].packets_sent, encoders[i].packets_received, encoders[i].packets_sent - encoders[i].packets_received); printk("decoder[%d] packets_sent = %d, packets_received = %d [%d]\n", i, decoders[i].packets_sent, decoders[i].packets_received, decoders[i].packets_sent - decoders[i].packets_received); } } pci_unregister_driver(&wcdte_driver); zt_transcoder_unregister(udecode); zt_transcoder_unregister(uencode); zt_transcoder_free(uencode); zt_transcoder_free(udecode); vfree(encoders); vfree(decoders); printk("Zaptel DTE (G.729/G.723) Transcoder support unloaded.\n"); } #ifdef LINUX26 module_param(debug, int, 0600); module_param(numchannels, int, 0600); #else MODULE_PARM(debug, "i"); MODULE_PARM(numchannels, "i"); #endif MODULE_DESCRIPTION("Zaptel DTE (G.729/G.723) Transcoder Support"); MODULE_AUTHOR("John Sloan "); #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); #endif module_init(ztdte_init); module_exit(ztdte_cleanup);