/* * Wildcard TC400B Interface Driver for Zapata Telephony interface * * Written by John Sloan * and Kevin P. Fleming * * Copyright (C) 2006-2007, 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 #include #include #include #include #include #ifdef STANDALONE_ZAPATA #include "zaptel.h" #else #include #endif #if defined(HOTPLUG_FIRMWARE) static const char *tc400m_firmware = "tc400m-firmware.bin"; #else extern u8 _binary_tc400m_firmware_bin_start[]; extern void _binary_tc400m_firmware_bin_size; #endif static struct pci_driver driver; #define module_printk(fmt, args...) printk("%s: " fmt, driver.name, ## args) #define debug_printk(test, fmt, args...) if (debug && (test)) printk("%s (%s): " fmt, driver.name, __FUNCTION__, ## args) /* #define USE_TEST_HW */ #define USE_TDM_CONFIG #define WC_MAX_IFACES 8 /* NUM_CHANNELS must be checked if new firmware (dte_firm.h) is used */ #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 G729_LENGTH 20 #define G723_LENGTH 30 #define G729_SAMPLES 160 #define G723_SAMPLES 240 #define G729_BYTES 20 #define G723_BYTES 20 /* 274 for 30ms ulaw, 194 for 20ms ulaw */ #define OTHER_CMD_LEN 300 #define MAX_COMMAND_LEN 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 MDIO_SHIFT_CLK 0x10000 #define MDIO_DATA_WRITE0 0x00000 #define MDIO_DATA_WRITE1 0x20000 #define MDIO_ENB 0x00000 #define MDIO_ENB_IN 0x40000 #define MDIO_DATA_READ 0x80000 #define RCV_CSMENCAPS 1 #define RCV_RTP 2 #define RCV_CSMENCAPS_ACK 3 #define RCV_OTHER 99 /* TDM Commands */ #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&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x01, 0x00,0x06,0x17,0x04, 0xFF,0xFF, \ 0x04,0x00 } #define CMD_MSG_TDM_ENABLE_BUS(s) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x02, 0x00,0x06,0x05,0x04, 0xFF,0xFF, \ 0x04,0x00 } #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&0x0F, 0x01, 0xFF,0xFF, 0x10, p1, 0x00,0x06,0x07,0x04, 0xFF,0xFF, \ p2,0x83, 0x00,0x0C, 0x00,0x00, p3,0x00 } #define CMD_MSG_TDM_OPT(s) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x35,0x04, 0xFF,0xFF, \ 0x00,0x00 } #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&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x1B,0x04, 0xFF,0xFF, \ 0x00,0x00 } /* CPU Commands */ #define CMD_MSG_SET_ARM_CLK(s) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x11,0x04, 0x00,0x00, \ 0x2C,0x01, 0x00,0x00 } #define CMD_MSG_SET_SPU_CLK(s) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x12,0x04, 0x00,0x00, \ 0x2C,0x01, 0x00,0x00 } #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&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x13,0x00, 0xFF,0xFF, \ p1,0x00 } #define CMD_MSG_DEVICE_STATUS_CONFIG(s) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x0F,0x04, 0xFF,0xFF, \ 0x05,0x00 } /* General IP/RTP Commands */ #define CMD_MSG_SET_ETH_HEADER(s) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 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(s) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x02,0x03, 0xFF,0xFF, \ 0x00,0x02 } #define CMD_MSG_ARP_SERVICE_CONFIG(s) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x05,0x01, 0xFF,0xFF, \ 0x01,0x00 } #define CMD_MSG_ICMP_SERVICE_CONFIG(s) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x04,0x03, 0xFF,0xFF, \ 0x01,0xFF } #define CMD_MSG_IP_OPTIONS(s) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x06,0x03, 0xFF,0xFF, \ 0x02,0x00 } /* Supervisor channel commands */ #define CMD_MSG_CREATE_CHANNEL(s,t) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x10,0x00, 0x00,0x00, \ 0x02,0x00, (t&0x00FF), ((t&0xFF00) >> 8) } #define CMD_MSG_TRANS_CONNECT(s,e,c1,c2,f1,f2) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x12, 0x00, 0x00,0x06,0x22,0x93, 0x00,0x00, \ e,0x00, (c1&0x00FF),((c1&0xFF00)>>8), f1,0x00, (c2&0x00FF),((c2&0xFF00)>>8), f2,0x00 } #define CMD_MSG_DESTROY_CHANNEL(s,t) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x11,0x00, 0x00,0x00, \ (t&0x00FF),((t&0xFF00)>>8), 0x00, 0x00 } /* Individual channel config commands */ #define CMD_MSG_SET_IP_HDR_CHANNEL(s,c,t2,t1) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00) >> 8),(c&0x00FF), 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, \ ((t2&0xFF00)>>8)+0x50,(t2&0x00FF), ((t1&0xFF00)>>8)+0x50,(t1&0x00FF), 0x00,0x00, 0x00,0x00 } #define CMD_MSG_VOIP_VCEOPT(s,c,l,w) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x12, 0x00, 0x00,0x02,0x01,0x80, 0x00,0x00, \ 0x21,l, 0x00,0x1C, 0x04,0x00, 0x00,0x00, w,0x00, 0x80,0x11 } #define CMD_MSG_VOIP_VOPENA(s,c,f) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 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(s,c) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x00,0x80, 0x00,0x00, \ 0x00,0x00, 0x00,0x00 } #define CMD_MSG_VOIP_INDCTRL(s,c) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x84,0x80, 0x00,0x00, \ 0x07,0x00, 0x00,0x00 } /* CPU ACK command */ #define CMD_MSG_ACK(s,c) { \ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \ 0x00,0x01, s, 0xE0, (c&0x00FF), ((c>>8)&0x00FF) } /* Wrapper for RTP packets */ #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} struct cmdq { struct list_head list; size_t cmdspace; size_t cmdlen; u8 cmd[0]; }; #define MAX_PACKET_SIZE 1500 #define MAX_TOTAL_CMDQ 40 struct wcdte { struct pci_dev *dev; const char *variety; unsigned int intcount; unsigned int rxints; unsigned int txints; unsigned int intmask; int pos; int freeregion; int rdbl; int tdbl; spinlock_t reglock; wait_queue_head_t regq; int rcvflags; struct semaphore chansem; struct semaphore cmdqsem; struct list_head pending_cmdq; struct list_head free_cmdq; u32 total_cmdq; /* total of all cmdq entries, both pending and free */ unsigned int last_command_sent; unsigned int last_rcommand; unsigned int last_rparm2; unsigned int seq_num; long timeout; unsigned int ztsnd_rtx; unsigned int ztsnd_0010_rtx; unsigned int numchannels; unsigned char complexname[40]; unsigned long iobase; dma_addr_t readdma; dma_addr_t writedma; dma_addr_t descripdma; volatile u8 *writechunk; /* write buffers */ volatile u8 *readchunk; /* read buffers */ volatile u32 *descripchunk; /* descriptors */ int wqueints; struct workqueue_struct *dte_wq; struct work_struct dte_work; struct zt_transcoder *uencode; struct zt_transcoder *udecode; }; struct wcdte_desc { const char *name; int flags; }; static const struct wcdte_desc wcdte = { "Wildcard TC400P+TC400M", 0 }; static struct wcdte *ifaces[WC_MAX_IFACES]; struct dte_state { int encoder; struct wcdte *wc; unsigned int timestamp; unsigned int seqno; unsigned int timeslot_in_num; unsigned int timeslot_out_num; unsigned int chan_in_num; unsigned int chan_out_num; unsigned int packets_sent; unsigned int packets_received; unsigned int last_dte_seqno; unsigned int dte_seqno_rcv; }; static int debug = 0; static char *mode[2] = { "g729", "g723" }; static int mode_count = 2; u32 debug_packets = 0; u32 debug_cmd_packets = 0; static int create_channel(struct wcdte *wc, int simple, int complicated, int part1_id, int part2_id, unsigned int *dte_chan1, unsigned int *dte_chan2); static int destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2); /* Sanity check values */ static inline int sanitycheck(struct zt_transcode_header *zth, unsigned int outbytes) { if (zth->dstoffset >= sizeof(zth->dstdata)) return 0; if (zth->dstlen >= sizeof(zth->dstdata)) return 0; if (outbytes >= sizeof(zth->dstdata)) return 0; if ((zth->dstoffset + zth->dstlen + outbytes) >= sizeof(zth->dstdata)) return 0; if (zth->srcoffset >= sizeof(zth->srcdata)) return 0; if (zth->srclen >= sizeof(zth->srcdata)) return 0; if ((zth->srcoffset + zth->srclen) > sizeof(zth->srcdata)) return 0; return 1; } static void dump_cmdq(struct wcdte *wc) { struct cmdq *cmdq; debug_printk(1, "pending_cmdq: "); list_for_each_entry(cmdq, &wc->pending_cmdq, list) printk("%p(%zd) ", cmdq, cmdq->cmdspace); printk("\n"); debug_printk(1, "free_cmdq: "); list_for_each_entry(cmdq, &wc->free_cmdq, list) printk("%p(%zd) ", cmdq, cmdq->cmdspace); printk("\n"); } static struct cmdq *get_free_cmdq(struct wcdte *wc, size_t size_needed) { struct cmdq *winner = NULL; struct cmdq *candidate = NULL; size_t candidate_size = MAX_PACKET_SIZE; struct cmdq *smallest_seen = NULL; size_t smallest_seen_size = MAX_PACKET_SIZE; struct cmdq *entry; size_needed = ((size_needed / 16) + 1) * 16; if (size_needed > MAX_PACKET_SIZE) return NULL; list_for_each_entry(entry, &wc->free_cmdq, list) { if (entry->cmdspace == size_needed) { winner = entry; break; } else if ((entry->cmdspace > size_needed) && (entry->cmdspace < candidate_size)) { candidate = entry; candidate_size = entry->cmdspace; } else if (entry->cmdspace < smallest_seen_size) { smallest_seen = entry; smallest_seen_size = entry->cmdspace; } } /* at this point, we either have a winner, a candidate, a potentially freeable too-small entry, or nothing... deal with the results */ if (winner) { list_del_init(&winner->list); return winner; } else if (candidate) { list_del_init(&candidate->list); return candidate; } else if (wc->total_cmdq < MAX_TOTAL_CMDQ) { /* we can make a new entry */ if (debug) dump_cmdq(wc); if ((winner = kmalloc(sizeof(*winner) + size_needed, GFP_KERNEL))) { debug_printk(1, "created a '%zd' byte cmdq entry at '%p'\n", size_needed, winner); winner->cmdspace = size_needed; INIT_LIST_HEAD(&winner->list); } return winner; } else if (smallest_seen) { /* we can't allocate new entries, but we have a too-small entry we can free and replace */ if (debug) dump_cmdq(wc); list_del(&smallest_seen->list); kfree(smallest_seen); if ((winner = kmalloc(sizeof(*winner) + size_needed, GFP_KERNEL))) { debug_printk(1, "replaced a '%zd' byte cmdq entry at '%p' with a '%zd' byte one at '%p'\n", smallest_seen_size, smallest_seen, size_needed, winner); winner->cmdspace = size_needed; INIT_LIST_HEAD(&winner->list); } return winner; } else { /* we failed */ debug_printk(1, "no cmdq entries available\n"); return NULL; } } static int queue_cmd(struct wcdte *wc, u8 *data, size_t length) { struct cmdq *cmdq = get_free_cmdq(wc, length); if (!cmdq) return -1; cmdq->cmdlen = length; memcpy(cmdq->cmd, data, length); list_add_tail(&cmdq->list, &wc->pending_cmdq); return 0; } #define send_cmd(wc, command, length, hex) \ ({ \ int ret = 0; \ u8 fifo[] = command; \ do { \ if (ret == 2) { \ wc->ztsnd_rtx++; \ if (hex == 0x0010) \ wc->ztsnd_0010_rtx++; \ } \ down(&wc->cmdqsem); \ queue_cmd(wc, fifo, sizeof(fifo)); \ wc->last_command_sent = hex; \ __transmit_demand(wc); \ up(&wc->cmdqsem); \ ret = waitfor_csmencaps(wc, RCV_CSMENCAPS, 0); \ if (ret == 1) \ return 1; \ } while (ret == 2); \ }) static void dte_init_state(struct dte_state *state_ptr, int encoder, unsigned int channel, struct wcdte *wc) { memset(state_ptr, 0, sizeof(*state_ptr)); state_ptr->encoder = encoder; state_ptr->wc = wc; state_ptr->chan_in_num = 999; state_ptr->chan_out_num = 999; if (encoder) { state_ptr->timeslot_in_num = channel * 2; state_ptr->timeslot_out_num = channel * 2 + 1; } else { state_ptr->timeslot_in_num = channel * 2 + 1; state_ptr->timeslot_out_num = channel * 2; } } static inline unsigned int zapfmt_to_dtefmt(unsigned int fmt) { switch (fmt) { case ZT_FORMAT_G723_1: return DTE_FORMAT_G723_1; case ZT_FORMAT_ULAW: return DTE_FORMAT_ULAW; case ZT_FORMAT_ALAW: return DTE_FORMAT_ALAW; case ZT_FORMAT_G729A: return DTE_FORMAT_G729A; default: return DTE_FORMAT_UNDEF; } } static inline void __setctl(struct wcdte *wc, unsigned int addr, unsigned int val) { outl(val, wc->iobase + addr); } static inline unsigned int __getctl(struct wcdte *wc, unsigned int addr) { return inl(wc->iobase + addr); } static inline void setctl(struct wcdte *wc, unsigned int addr, unsigned int val) { unsigned long flags; spin_lock_irqsave(&wc->reglock, flags); __setctl(wc, addr, val); spin_unlock_irqrestore(&wc->reglock, flags); } static inline unsigned int getctl(struct wcdte *wc, unsigned int addr) { unsigned long flags; unsigned int val; spin_lock_irqsave(&wc->reglock, flags); val = __getctl(wc, addr); spin_unlock_irqrestore(&wc->reglock, flags); return val; } static inline void reinit_descriptor(struct wcdte *wc, int tx, int dbl, char *s) { unsigned int o2; o2 = dbl * 4; if (!tx) o2 += ERING_SIZE * 4; wc->descripchunk[o2] = cpu_to_le32(0x80000000); setctl(wc, 0x0008, 0x00000000); } static inline void __transmit_one(struct wcdte *wc, u8 *data, size_t length) { u32 o2 = wc->tdbl * 4; volatile u8 *writechunk = (volatile u8 *) wc->writechunk + (wc->tdbl * SFRAME_SIZE); size_t xmt_length; /* Yes... this is a busy loop, that is not interruptible. However, it is highly unlikely (and testing proves) that the wait for a descriptor to become available will ever be long enough for this to be an issue. */ do {} while ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000)); xmt_length = max(length, (size_t) 64); wc->descripchunk[o2 + 1] = cpu_to_le32((le32_to_cpu(wc->descripchunk[o2 + 1]) & 0xFBFFF800) | xmt_length); memcpy((void *) writechunk, data, length); if (length < xmt_length) memset((void *) writechunk + length, 0, xmt_length - length); wc->descripchunk[o2] = cpu_to_le32(0x80000000); setctl(wc, 0x0008, 0x00000000); /* Transmit Poll Demand */ wc->tdbl = (wc->tdbl + 1) % ERING_SIZE; } static inline int __transmit_demand(struct wcdte *wc) { int i; unsigned int reg; struct cmdq *cmdq; reg = getctl(wc, 0x0028) & 0x00700000; /* Nothing to transmit */ if (list_empty(&wc->pending_cmdq)) return 1; /* pop the first entry off the list */ cmdq = list_entry(wc->pending_cmdq.next, struct cmdq, list); list_del_init(&cmdq->list); debug_printk(1, "transmitting command at '%p' of '%zd' bytes\n", cmdq, cmdq->cmdlen); __transmit_one(wc, cmdq->cmd, cmdq->cmdlen); if (debug_packets) { debug_printk(1, "TX: "); for (i = 0; i < min((size_t) debug_packets, cmdq->cmdlen); i++) printk("%02X ", cmdq->cmd[i]); printk("\n"); } if (debug_cmd_packets && (cmdq->cmd[12] == 0x88) && (cmdq->cmd[13] == 0x9B)) { debug_printk(1, "TX: "); for (i = 0; i < min((size_t) debug_cmd_packets, cmdq->cmdlen); i++) printk("%02X ", cmdq->cmd[i]); printk("\n"); } list_add_tail(&cmdq->list, &wc->free_cmdq); return 0; } static inline int transmit_demand(struct wcdte *wc) { int val; down(&wc->cmdqsem); val = __transmit_demand(wc); up(&wc->cmdqsem); return val; } static int dte_operation(struct zt_transcoder_channel *ztc, int op) { struct zt_transcoder_channel *compl_ztc; struct dte_state *st = ztc->pvt, *compl_st; 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 res = 0; u32 ipchksum; switch (op) { case ZT_TCOP_ALLOCATE: if (ztc->chan_built) break; down(&wc->chansem); if (st->encoder) create_channel(wc, zapfmt_to_dtefmt(zth->srcfmt), zapfmt_to_dtefmt(zth->dstfmt), st->timeslot_in_num, st->timeslot_out_num, &(st->chan_in_num), &(st->chan_out_num)); else create_channel(wc, zapfmt_to_dtefmt(zth->dstfmt), zapfmt_to_dtefmt(zth->srcfmt), st->timeslot_out_num, st->timeslot_in_num, &(st->chan_out_num), &(st->chan_in_num)); /* Mark this channel as built */ ztc->chan_built = 1; ztc->built_fmts = zth->dstfmt | zth->srcfmt; /* Mark the channel complement (other half of encoder/decoder pair) as built */ if (st->encoder) compl_ztc = &(wc->udecode->channels[st->timeslot_in_num >> 1]); else compl_ztc = &(wc->uencode->channels[st->timeslot_in_num >> 1]); compl_ztc->chan_built = 1; compl_ztc->built_fmts = zth->dstfmt | zth->srcfmt; compl_st = compl_ztc->pvt; compl_st->chan_in_num = st->chan_out_num; compl_st->chan_out_num = st->chan_in_num; up(&wc->chansem); break; case ZT_TCOP_RELEASE: down(&wc->chansem); if (st->encoder) compl_ztc = &(wc->udecode->channels[st->timeslot_in_num >> 1]); else compl_ztc = &(wc->uencode->channels[st->timeslot_in_num >> 1]); /* If the channel complement (other half of the encoder/decoder pair) is not being used... */ if (!compl_ztc->busy) { if (st->encoder) destroy_channel(wc, st->chan_in_num, st->chan_out_num); else destroy_channel(wc, st->chan_out_num, st->chan_in_num); /* Mark this channel as not built */ ztc->chan_built = 0; ztc->built_fmts = 0; st->chan_in_num = 999; st->chan_out_num = 999; /* Mark the channel complement as not built */ compl_ztc->chan_built = 0; compl_ztc->built_fmts = 0; compl_st = compl_ztc->pvt; compl_st->chan_in_num = 999; compl_st->chan_out_num = 999; } st->dte_seqno_rcv = 0; up(&wc->chansem); break; case ZT_TCOP_TRANSCODE: if ((((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) && ((zth->dstfmt == ZT_FORMAT_G729A && zth->srclen >= G729_SAMPLES) || (zth->dstfmt == ZT_FORMAT_G723_1 && zth->srclen >= G723_SAMPLES))) || ((zth->srcfmt == ZT_FORMAT_G729A) && (zth->srclen >= G729_BYTES)) || ((zth->srcfmt == ZT_FORMAT_G723_1) && (zth->srclen >= G723_BYTES))) { struct cmdq *cmdq; do { chars = (u8 *)(zth->srcdata + zth->srcoffset); switch (zth->srcfmt) { case ZT_FORMAT_ULAW: case ZT_FORMAT_ALAW: switch (zth->dstfmt) { case ZT_FORMAT_G729A: inbytes = G729_SAMPLES; timestamp_inc = G729_SAMPLES; break; case ZT_FORMAT_G723_1: inbytes = G723_SAMPLES; timestamp_inc = G723_SAMPLES; break; } break; case ZT_FORMAT_G729A: inbytes = G729_BYTES; timestamp_inc = G729_SAMPLES; break; case ZT_FORMAT_G723_1: inbytes = G723_BYTES; timestamp_inc = G723_SAMPLES; break; } zth->srclen -= inbytes; { u8 fifo[] = CMD_MSG_IP_UDP_RTP( ((inbytes+40) >> 8) & 0xFF, (inbytes+40) & 0xFF, st->seqno & 0xFF, 0x00, 0x00, (((st->timeslot_out_num) >> 8)+0x50) & 0xFF, (st->timeslot_out_num) & 0xFF, (((st->timeslot_in_num) >> 8)+0x50) & 0xFF, (st->timeslot_in_num) & 0xFF, ((inbytes+20) >> 8) & 0xFF, (inbytes+20) & 0xFF, 0x00, 0x00, zapfmt_to_dtefmt(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; down(&wc->cmdqsem); if (!(cmdq = get_free_cmdq(wc, sizeof(fifo) + inbytes))) { up(&wc->cmdqsem); res = -EIO; break; } memcpy(cmdq->cmd, fifo, sizeof(fifo)); memcpy(cmdq->cmd + sizeof(fifo), chars, inbytes); cmdq->cmdlen = sizeof(fifo) + inbytes; list_add_tail(&cmdq->list, &wc->pending_cmdq); __transmit_demand(wc); up(&wc->cmdqsem); st->packets_sent++; zth->srcoffset += inbytes; } } while ((((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) && ((zth->dstfmt == ZT_FORMAT_G729A && zth->srclen >= G729_SAMPLES) || (zth->dstfmt == ZT_FORMAT_G723_1 && zth->srclen >= G723_SAMPLES))) || ((zth->srcfmt == ZT_FORMAT_G729A) && (zth->srclen >= G729_BYTES)) || ((zth->srcfmt == ZT_FORMAT_G723_1) && (zth->srclen >= G723_BYTES))); } else { zt_transcoder_alert(ztc); res = -EINVAL; } break; } return res; } static void stop_dma(struct wcdte *wc); static inline void receiveprep(struct wcdte *wc, int dbl) { volatile u8 *readchunk = wc->readchunk + (dbl * SFRAME_SIZE); 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 rcommand, rchannel, rlen, rtp_rseq, rtp_eseq; u8 *chars = NULL; unsigned int ztc_ndx; o2 = dbl * 4; o2 += ERING_SIZE * 4; if (debug_packets) { debug_printk(1, "RX: "); for (i = 0; i < debug_packets; i++) printk("%02X ", readchunk[i]); printk("\n"); } if ((readchunk[12] == 0x88) && (readchunk[13] == 0x9B)) { /* Control in packet */ if (debug_cmd_packets) { debug_printk(1, "RX: "); for (i = 0; i < debug_cmd_packets; i++) printk("%02X ", readchunk[i]); printk("\n"); } /* See if message must be ACK'd */ if ((readchunk[17] & 0xC0) == 0) { rcommand = readchunk[24] | (readchunk[25] << 8); rchannel = readchunk[18] | (readchunk[19] << 8); rseq = readchunk[16]; { u8 fifo[] = CMD_MSG_ACK(rseq++, rchannel); down(&wc->cmdqsem); queue_cmd(wc, fifo, sizeof(fifo)); __transmit_demand(wc); wc->rcvflags = RCV_CSMENCAPS; wc->last_rcommand = rcommand; wc->last_rparm2 = readchunk[30] | (readchunk[31] << 8); wake_up_interruptible(&wc->regq); up(&wc->cmdqsem); } } else { wc->rcvflags = RCV_CSMENCAPS_ACK; wake_up_interruptible(&wc->regq); } } else if ((readchunk[12] == 0x08) && (readchunk[13] == 0x00) && (readchunk[50] == 0x12) && (readchunk[51] == 0x34) && (readchunk[52] = 0x56) && (readchunk[53] == 0x78)) { /* IP/UDP in packet */ 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 >> 1; if (ztc_ndx >= wc->numchannels) { debug_printk(1, "Invalid channel number received (ztc_ndx = %d) (numchannels = %d)\n", ztc_ndx, wc->numchannels); rcodec = DTE_FORMAT_UNDEF; } switch (rcodec) { case 0x00: /* ulaw */ case 0x08: /* alaw */ ztc = &(wc->udecode->channels[ztc_ndx]); break; case 0x04: /* g.723.1 */ case 0x12: /* g.729 */ ztc = &(wc->uencode->channels[ztc_ndx]); break; } zth = ztc->tch; st = ztc->pvt; if (!zth) { debug_printk(1, "Tried to put data into a freed zth header\n"); rcodec = DTE_FORMAT_UNDEF; } else { chars = (u8 *)(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; debug_printk(rtp_rseq != rtp_eseq, "Bad seqno from module [%d][%d][%d]\n", rchannel, rtp_rseq, st->last_dte_seqno); st->last_dte_seqno = rtp_rseq; } switch (rcodec) { case 0x00: /* ulaw */ case 0x08: /* alaw */ if (sanitycheck(zth, rlen) && ((zth->srcfmt == ZT_FORMAT_G729A && rlen == G729_SAMPLES) || (zth->srcfmt == ZT_FORMAT_G723_1 && rlen == G723_SAMPLES))) { memcpy(chars, (void *) readchunk + 54, rlen); zth->dstlen += rlen; zth->dstsamples = zth->dstlen; } else { ztc->errorstatus = -EOVERFLOW; } zt_transcoder_alert(ztc); break; case 0x04: /* g.723.1 */ if (sanitycheck(zth, rlen) && (rlen == G723_BYTES)) { memcpy(chars, (void *) readchunk + 54, rlen); zth->dstlen += rlen; zth->dstsamples = zth->dstlen * 12; } else { ztc->errorstatus = -EOVERFLOW; } if ((zth->dstsamples % G723_SAMPLES) == 0) zt_transcoder_alert(ztc); break; case 0x12: /* g.729 */ if (sanitycheck(zth, rlen) && (rlen == G729_BYTES)) { memcpy(chars, (void *) readchunk + 54, rlen); zth->dstlen += rlen; zth->dstsamples = zth->dstlen * 8; } else { ztc->errorstatus = -EOVERFLOW; } if ((zth->dstsamples % G729_SAMPLES) == 0) zt_transcoder_alert(ztc); } } } static int check_descriptor(struct wcdte *wc) { int o2 = (ERING_SIZE * 4) + (wc->rdbl * 4); if (!(le32_to_cpu(wc->descripchunk[o2]) & 0x80000000)) { wc->rxints++; receiveprep(wc, wc->rdbl); reinit_descriptor(wc, 0, wc->rdbl, "rxchk"); wc->rdbl = (wc->rdbl + 1) % ERING_SIZE; return 1; } return 0; } static void init_descriptors(struct wcdte *wc) { volatile u32 *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; x < ERING_SIZE; x++) { if (x < ERING_SIZE - 1) descripdma += 16; else descripdma = wc->descripdma; /* 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; } } static void dte_wque_run(struct wcdte *wc) { int res; if (wc->wqueints & 0x00000040) { /* Loop descriptors is available */ do {} while ((res = check_descriptor(wc))); } /* Handle TX interrupts */ if (wc->wqueints & 0x00000001) { wc->txints++; transmit_demand(wc); wc->intcount++; } } ZAP_IRQ_HANDLER(interrupt_handler) { struct wcdte *wc = dev_id; unsigned int ints; if (!(ints = getctl(wc, 0x0028))) return IRQ_NONE; setctl(wc, 0x0028, ints); ints &= wc->intmask; if (ints & 0x00000041) { wc->wqueints = ints; queue_work(wc->dte_wq, &wc->dte_work); } if (!debug) return IRQ_RETVAL(1); debug_printk(ints & 0x00008000, "Abnormal Interrupt\n"); debug_printk(ints & 0x00002000, "Fatal Bus Error\n"); debug_printk(ints & 0x00000100, "Receive Stopped\n"); debug_printk(ints & 0x00000080, "Receive Desciptor Unavailable\n"); debug_printk(ints & 0x00000020, "Transmit Under-flow\n"); debug_printk(ints & 0x00000008, "Jabber Timer Time-out\n"); debug_printk(ints & 0x00000004, "Transmit Descriptor Unavailable\n"); debug_printk(ints & 0x00000002, "Transmit Processor Stopped\n"); return IRQ_RETVAL(1); } static int hardware_init(struct wcdte *wc) { /* Hardware stuff */ unsigned int reg; unsigned long newjiffies; /* Initialize descriptors */ init_descriptors(wc); /* Enable I/O Access */ pci_read_config_dword(wc->dev, 0x0004, ®); reg |= 0x00000007; pci_write_config_dword(wc->dev, 0x0004, reg); setctl(wc, 0x0000, 0xFFF88001); newjiffies = jiffies + HZ/10; while (((reg = getctl(wc, 0x0000)) & 0x00000001) && (newjiffies > jiffies)); /* Configure watchdogs, access, etc */ setctl(wc, 0x0030, 0x00280048); setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */); reg = getctl(wc, 0x00fc); setctl(wc, 0x00fc, (reg & ~0x7) | 0x7); reg = getctl(wc, 0x00fc); return 0; } static inline void setintmask(struct wcdte *wc, unsigned int intmask) { wc->intmask = intmask; setctl(wc, 0x0038, intmask); } static inline void enable_interrupts(struct wcdte *wc) { setintmask(wc, !debug ? 0x00010041 : 0x0001A1EB); } static void start_dma(struct wcdte *wc) { unsigned int reg; wmb(); setctl(wc, 0x0020, wc->descripdma); setctl(wc, 0x0018, wc->descripdma + (16 * ERING_SIZE)); /* Start receiver/transmitter */ reg = getctl(wc, 0x0030); setctl(wc, 0x0030, reg | 0x00002002); /* Start XMT and RCD */ setctl(wc, 0x0010, 0x00000000); /* Receive Poll Demand */ reg = getctl(wc, 0x0028); setctl(wc, 0x0028, reg); } static void disable_interrupts(struct wcdte *wc) { setintmask(wc, 0x00000000); setctl(wc, 0x0084, 0x00000000); } static void stop_dma(struct wcdte *wc) { unsigned int reg; disable_interrupts(wc); setctl(wc, 0x0048, 0x00000000); /* Reset the part to be on the safe side */ reg = getctl(wc, 0x0000); reg |= 0x00000001; setctl(wc, 0x0000, reg); } static int waitfor_csmencaps(struct wcdte *wc, unsigned int mask, int use_mask) { int ret; ret = wait_event_interruptible_timeout(wc->regq, use_mask ? (wc->rcvflags == mask) : (wc->last_rcommand == wc->last_command_sent), wc->timeout); wc->rcvflags = 0; wc->last_rcommand = 0; wc->last_command_sent = 0; if (ret < 0) { debug_printk(1, "Wait interrupted, need to stop boot (ret = %d)\n", ret); return 1; } if (!ret) { debug_printk(1, "Waitfor CSMENCAPS response timed out (ret = %d)\n", ret); return 2; } return 0; } static int read_phy(struct wcdte *wc, int location) { int i; long mdio_addr = 0x0048; int read_cmd = (0xf6 << 10) | (1 << 5) | location; int retval = 0; /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1); getctl(wc, mdio_addr); setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); getctl(wc, mdio_addr); } /* Shift the read command bits out. */ for (i = 17; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; setctl(wc, mdio_addr, MDIO_ENB | dataval); getctl(wc, mdio_addr); setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK); getctl(wc, mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { setctl(wc, mdio_addr, MDIO_ENB_IN); getctl(wc, mdio_addr); retval = (retval << 1) | ((getctl(wc, mdio_addr) & MDIO_DATA_READ) ? 1 : 0); setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK); getctl(wc, mdio_addr); } retval = (retval >> 1) & 0xffff; return retval; } void write_phy(struct wcdte *wc, int location, int value) { int i; int cmd = (0x5002 << 16) | (1 << 23) | (location<<18) | value; long mdio_addr = 0x0048; /* Establish sync by sending 32 logic ones. */ for (i = 32; i >= 0; i--) { setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1); getctl(wc, mdio_addr); setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); getctl(wc, mdio_addr); } /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; setctl(wc, mdio_addr, MDIO_ENB | dataval); getctl(wc, mdio_addr); setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK); getctl(wc, mdio_addr); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { setctl(wc, mdio_addr, MDIO_ENB_IN); getctl(wc, mdio_addr); setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK); getctl(wc, mdio_addr); } return; } static int boot_processor(struct wcdte *wc, const struct firmware *firmware) { int byteloc, last_byteloc, length, delay_count; unsigned int reg, ret; #if !defined(USE_TEST_HW) /* Turn off auto negotiation */ write_phy(wc, 0, 0x2100); debug_printk(1, "PHY register 0 = %X", read_phy(wc, 0)); /* Set reset */ setctl(wc, 0x00A0, 0x04000000); /* Wait 1000ms to ensure processor reset */ mdelay(1000); /* Clear reset */ setctl(wc, 0x00A0, 0x04080000); /* Wait for Ethernet link */ for (delay_count = 0; ((getctl(wc, 0x00fc) & 0xE0000000) != 0xE0000000) && delay_count < 100; mdelay(100), delay_count++); if (delay_count == 100) { module_printk("Failed to link to DTE processor!\n"); return 1; } /* Turn off booted LED */ setctl(wc, 0x00A0, 0x04084000); #endif /* !defined(USE_TEST_HW) */ if (debug) { reg = getctl(wc, 0x00fc); debug_printk(1, "LINK STATUS: reg(0xfc) = %X\n", reg); } for (ret = 0, last_byteloc = byteloc = 17; byteloc < (firmware->size - 20); last_byteloc = byteloc) { length = (firmware->data[byteloc] << 8) | firmware->data[byteloc + 1]; byteloc += 2; __transmit_one(wc, firmware->data + byteloc, length); byteloc += length; ret = waitfor_csmencaps(wc, RCV_CSMENCAPS_ACK, 1); if (ret == 1) return 1; else if (ret == 2) /* Retransmit if processor times out */ byteloc = last_byteloc; } wc->timeout = 10 * HZ; if (waitfor_csmencaps(wc, RCV_CSMENCAPS, 1)) return 1; /* Turn on booted LED */ setctl(wc, 0x00A0, 0x04080000); debug_printk(1, "Successfully booted DTE processor.\n"); return 0; } static int create_channel(struct wcdte *wc, int simple, int complicated, int part1_id, int part2_id, unsigned int *dte_chan1, unsigned int *dte_chan2) { int length = 0; unsigned char chan1, chan2; if (complicated == DTE_FORMAT_G729A) length = G729_LENGTH; else if (complicated == DTE_FORMAT_G723_1) length = G723_LENGTH; /* Create complex channel */ send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part1_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010); chan1 = wc->last_rparm2; /* Create simple channel */ send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010); chan2 = wc->last_rparm2; /* Configure complex channel */ send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(wc->seq_num++, chan1, part2_id, part1_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000); send_cmd(wc, CMD_MSG_VOIP_VCEOPT(wc->seq_num++, chan1, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001); /* Configure simple channel */ send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(wc->seq_num++, chan2, part1_id, part2_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000); send_cmd(wc, CMD_MSG_VOIP_VCEOPT(wc->seq_num++, chan2, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001); send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 1, chan1, chan2, complicated, simple), CMD_MSG_TRANS_CONNECT_LEN, 0x9322); send_cmd(wc, CMD_MSG_VOIP_INDCTRL(wc->seq_num++, chan1), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084); send_cmd(wc, CMD_MSG_VOIP_INDCTRL(wc->seq_num++, chan2), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084); send_cmd(wc, CMD_MSG_VOIP_VOPENA(wc->seq_num++, chan1, complicated), CMD_MSG_VOIP_VOPENA_LEN, 0x8000); send_cmd(wc, CMD_MSG_VOIP_VOPENA(wc->seq_num++, chan2, simple), CMD_MSG_VOIP_VOPENA_LEN, 0x8000); *dte_chan1 = chan1; *dte_chan2 = chan2; return 1; } static int destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2) { /* Turn off both channels */ send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(wc->seq_num++, chan1), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000); send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(wc->seq_num++, chan2), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000); /* Disconnect the channels */ send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 0, chan1, chan2, 0, 0), CMD_MSG_TRANS_CONNECT_LEN, 0x9322); /* Remove the channels */ send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan1), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011); send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan2), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011); return 1; } static int setup_channels(struct wcdte *wc) { #ifndef USE_TEST_HW send_cmd(wc, CMD_MSG_SET_ARM_CLK(wc->seq_num++), CMD_MSG_SET_ARM_CLK_LEN, 0x0411); send_cmd(wc, CMD_MSG_SET_SPU_CLK(wc->seq_num++), CMD_MSG_SET_SPU_CLK_LEN, 0x0412); #endif #ifdef USE_TDM_CONFIG send_cmd(wc, CMD_MSG_TDM_SELECT_BUS_MODE(wc->seq_num++), CMD_MSG_TDM_SELECT_BUS_MODE_LEN, 0x0417); send_cmd(wc, CMD_MSG_TDM_ENABLE_BUS(wc->seq_num++), CMD_MSG_TDM_ENABLE_BUS_LEN, 0x0405); send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x03, 0x20, 0x00), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x04, 0x80, 0x04), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x05, 0x20, 0x08), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x06, 0x80, 0x0C), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407); #endif send_cmd(wc, CMD_MSG_SET_ETH_HEADER(wc->seq_num++), CMD_MSG_SET_ETH_HEADER_LEN, 0x0100); send_cmd(wc, CMD_MSG_IP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_IP_SERVICE_CONFIG_LEN, 0x0302); send_cmd(wc, CMD_MSG_ARP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_ARP_SERVICE_CONFIG_LEN, 0x0105); send_cmd(wc, CMD_MSG_ICMP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_ICMP_SERVICE_CONFIG_LEN, 0x0304); #ifdef USE_TDM_CONFIG send_cmd(wc, CMD_MSG_DEVICE_SET_COUNTRY_CODE(wc->seq_num++), CMD_MSG_DEVICE_SET_COUNTRY_CODE_LEN, 0x041B); #endif send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x02), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013); send_cmd(wc, CMD_MSG_IP_OPTIONS(wc->seq_num++), CMD_MSG_IP_OPTIONS_LEN, 0x0306); send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x04), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013); #ifdef USE_TDM_CONFIG send_cmd(wc, CMD_MSG_TDM_OPT(wc->seq_num++), CMD_MSG_TDM_OPT_LEN, 0x0435); #endif wc->timeout = HZ/100 + 1; return 0; } static int __devinit init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int res = 0, reg; struct wcdte *wc; struct wcdte_desc *d = (struct wcdte_desc *) ent->driver_data; int x; unsigned int g729_numchannels, g723_numchannels; u8 firmware_ver; unsigned int complexfmts = 0; struct firmware embedded_firmware; const struct firmware *firmware = &embedded_firmware; struct dte_state *encoders; struct dte_state *decoders; for (x = 0; x < (sizeof(ifaces) / sizeof(ifaces[0])); x++) if (!ifaces[x]) break; if (x == (sizeof(ifaces) / sizeof(ifaces[0]))) { module_printk("Too many interfaces\n"); return -EIO; } if (pci_enable_device(pdev)) return -EIO; if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) return -ENOMEM; memset(wc, 0, sizeof(*wc)); ifaces[x] = wc; spin_lock_init(&wc->reglock); sema_init(&wc->chansem, 1); sema_init(&wc->cmdqsem, 1); wc->iobase = pci_resource_start(pdev, 0); wc->dev = pdev; wc->pos = x; wc->variety = d->name; wc->seq_num = 6; wc->timeout = HZ; INIT_LIST_HEAD(&wc->pending_cmdq); INIT_LIST_HEAD(&wc->free_cmdq); /* Keep track of whether we need to free the region */ if (request_region(wc->iobase, 0xff, "wctc4xxp")) wc->freeregion = 1; /* Allocate enough memory for all TX buffers, RX buffers, and descriptors */ wc->writechunk = pci_alloc_consistent(pdev, PCI_WINDOW_SIZE, &wc->writedma); if (!wc->writechunk) { module_printk("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); wc->readdma = wc->writedma + (SFRAME_SIZE * ERING_SIZE); wc->descripchunk = (u32 *) (wc->readchunk + (SFRAME_SIZE * ERING_SIZE)); wc->descripdma = wc->readdma + (SFRAME_SIZE * ERING_SIZE); init_waitqueue_head(&wc->regq); /* Initialize the work queue */ wc->dte_wq = create_workqueue("wctc4xxp"); INIT_WORK(&wc->dte_work, (void (*)(void *)) dte_wque_run, wc); #ifdef HOTPLUG_FIRMWARE if ((request_firmware(&firmware, tc400m_firmware, &wc->dev->dev) != 0) || !firmware) { module_printk("Firmware %s not available from userspace\n", tc400m_firmware); return -1; } #else embedded_firmware.data = _binary_tc400m_firmware_bin_start; /* Yes... this is weird. objcopy gives us a symbol containing the size of the firmware, not a pointer a variable containing the size. The only way we can get the value of the symbol is to take its address, so we do that and then cast that value to the proper type. */ embedded_firmware.size = (size_t) &_binary_tc400m_firmware_bin_size; #endif firmware_ver = firmware->data[0]; g729_numchannels = firmware->data[1]; g723_numchannels = firmware->data[2]; wc->numchannels = 2048; /* someday... */ for (x = 0; x < mode_count; x++) { if (!strcmp(mode[x], "g729") || !strcmp(mode[x], "G729")) { if (!g729_numchannels) { module_printk("Format '%s' not supported by the firmware for this module; ignored.\n", mode[x]); continue; } strcat(wc->complexname, "G.729A / "); complexfmts |= ZT_FORMAT_G729A; wc->numchannels = min(wc->numchannels, g729_numchannels); } else if (!strcmp(mode[x], "g723") || !strcmp(mode[x], "G723")) { if (!g723_numchannels) { module_printk("Format '%s' not supported by the firmware for this module; ignored.\n", mode[x]); continue; } strcat(wc->complexname, "G.723.1 5.3Kbps / "); complexfmts |= ZT_FORMAT_G723_1; wc->numchannels = min(wc->numchannels, g723_numchannels); } else { module_printk("Invalid transcoder format specified: %s\n", mode[x]); } } if (!complexfmts) { module_printk("No valid transcoder formats specified; module will not be enabled.\n"); return -1; } wc->complexname[strlen(wc->complexname) - 3] = '\0'; wc->uencode = zt_transcoder_alloc(wc->numchannels); wc->udecode = zt_transcoder_alloc(wc->numchannels); encoders = kmalloc(sizeof(*encoders) * wc->numchannels, GFP_KERNEL); decoders = kmalloc(sizeof(*decoders) * wc->numchannels, GFP_KERNEL); if (!wc->uencode || !wc->udecode || !encoders || !decoders) { if (wc->uencode) zt_transcoder_free(wc->uencode); if (wc->udecode) zt_transcoder_free(wc->udecode); if (encoders) kfree(encoders); if (decoders) kfree(decoders); return -ENOMEM; } strcpy(wc->udecode->name, wc->variety); strcpy(wc->uencode->name, wc->variety); wc->udecode->srcfmts = wc->uencode->dstfmts = complexfmts; wc->udecode->dstfmts = wc->uencode->srcfmts = ZT_FORMAT_ULAW | ZT_FORMAT_ALAW; wc->udecode->operation = wc->uencode->operation = dte_operation; for (x = 0;x < wc->numchannels; x++) { dte_init_state(&encoders[x], 1, x, wc); dte_init_state(&decoders[x], 0, x, wc); wc->uencode->channels[x].pvt = &encoders[x]; wc->udecode->channels[x].pvt = &decoders[x]; } zt_transcoder_register(wc->uencode, THIS_MODULE); zt_transcoder_register(wc->udecode, THIS_MODULE); /* Enable bus mastering */ pci_set_master(pdev); /* Keep track of which device we are */ pci_set_drvdata(pdev, wc); if (request_irq(pdev->irq, interrupt_handler, SA_SHIRQ, driver.name, wc)) { module_printk("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); kfree(wc); /* TODO: what about all the encoders and decoders (do this earlier)? */ return -EIO; } if (hardware_init(wc)) { /* Set Reset Low */ 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); kfree(wc); return -EIO; } /* Enable interrupts */ enable_interrupts(wc); /* Start DMA */ start_dma(wc); if (boot_processor(wc, firmware)) { /* Set Reset Low */ 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); kfree(wc); return -EIO; } if (setup_channels(wc)) { /* Set Reset Low */ 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); kfree(wc); return -EIO; } if (debug) { reg = getctl(wc, 0x00fc); debug_printk(1, "(post-boot) Reg fc is %08x\n", reg); } module_printk("%s supporting '%s' with firmware version '%d'\n", wc->variety, wc->complexname, firmware_ver); res = 0; return res; } static void release(struct wcdte *wc) { struct cmdq *cmdq, *next; if (wc->freeregion) release_region(wc->iobase, 0xff); list_for_each_entry_safe(cmdq, next, &wc->pending_cmdq, list) { debug_printk(1, "freeing cmdq entry at '%p'\n", cmdq); list_del(&cmdq->list); kfree(cmdq); } list_for_each_entry_safe(cmdq, next, &wc->free_cmdq, list) { debug_printk(1, "freeing cmdq entry at '%p'\n", cmdq); list_del(&cmdq->list); kfree(cmdq); } kfree(wc); } static void __devexit remove_one(struct pci_dev *pdev) { int i; struct wcdte *wc = pci_get_drvdata(pdev); struct zt_transcoder_channel *ztc_en, *ztc_de; struct dte_state *st_en, *st_de; if (!wc) return; zt_transcoder_unregister(wc->udecode); zt_transcoder_unregister(wc->uencode); if (debug) { debug_printk(1, "wc->ztsnd_rtx = %d\n", wc->ztsnd_rtx); debug_printk(1, "wc->ztsnd_0010_rtx = %d\n", wc->ztsnd_0010_rtx); for (i = 0; i < wc->numchannels; i++) { ztc_en = &(wc->uencode->channels[i]); st_en = ztc_en->pvt; ztc_de = &(wc->udecode->channels[i]); st_de = ztc_de->pvt; debug_printk(1, "en[%d] snt = %d, rcv = %d [%d]\n", i, st_en->packets_sent, st_en->packets_received, st_en->packets_sent - st_en->packets_received); debug_printk(1, "de[%d] snt = %d, rcv = %d [%d]\n", i, st_de->packets_sent, st_de->packets_received, st_de->packets_sent - st_de->packets_received); } } /* Stop any DMA */ stop_dma(wc); /* In case hardware is still there */ disable_interrupts(wc); /* Kill workqueue */ destroy_workqueue(wc->dte_wq); /* Immediately free resources */ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *) wc->writechunk, wc->writedma); free_irq(pdev->irq, wc); kfree(wc->uencode->channels[0].pvt); kfree(wc->udecode->channels[0].pvt); zt_transcoder_free(wc->uencode); zt_transcoder_free(wc->udecode); /* Release span, possibly delayed */ release(wc); } static struct pci_device_id 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, pci_tbl); static struct pci_driver driver = { name: "wctc4xxp", probe: init_one, remove: __devexit_p(remove_one), suspend: NULL, resume: NULL, id_table: pci_tbl, }; static int init(void) { return pci_module_init(&driver) ? -ENODEV : 0; } static void cleanup(void) { pci_unregister_driver(&driver); } module_param(debug, int, S_IRUGO | S_IWUSR); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) module_param_array(mode, charp, &mode_count, S_IRUGO | S_IWUSR); #else module_param_array(mode, charp, mode_count, S_IRUGO | S_IWUSR); #endif module_param(debug_packets, uint, S_IRUGO | S_IWUSR); module_param(debug_cmd_packets, uint, S_IRUGO | S_IWUSR); MODULE_DESCRIPTION("Wildcard TC400P+TC400M Transcoder"); MODULE_AUTHOR("John Sloan "); MODULE_LICENSE("GPL"); module_init(init); module_exit(cleanup);