[zaptel-commits] kpfleming: branch group/transcoder-rework r2126 - in /team/group/transcoder-r...

zaptel-commits at lists.digium.com zaptel-commits at lists.digium.com
Thu Feb 8 09:46:55 MST 2007


Author: kpfleming
Date: Thu Feb  8 10:46:54 2007
New Revision: 2126

URL: http://svn.digium.com/view/zaptel?view=rev&rev=2126
Log:
bring back the not-quite-working-but-otherwise-much-improved driver :-)

Modified:
    team/group/transcoder-rework/wctc4xxp/base.c
    team/group/transcoder-rework/zaptel.h
    team/group/transcoder-rework/zttranscode.c

Modified: team/group/transcoder-rework/wctc4xxp/base.c
URL: http://svn.digium.com/view/zaptel/team/group/transcoder-rework/wctc4xxp/base.c?view=diff&rev=2126&r1=2125&r2=2126
==============================================================================
--- team/group/transcoder-rework/wctc4xxp/base.c (original)
+++ team/group/transcoder-rework/wctc4xxp/base.c Thu Feb  8 10:46:54 2007
@@ -1,9 +1,10 @@
 /*
- * Wildcard TC400B Driver
+ * Wildcard TC400B Interface Driver for Zapata Telephony interface
  *
  * Written by John Sloan <jsloan at digium.com>
+ *        and Kevin P. Fleming <kpfleming at digium.com>
  *
- * Copyright (C) 2006, Digium, Inc.
+ * Copyright (C) 2006-2007, Digium, Inc.
  *
  * All rights reserved.
  *
@@ -23,7 +24,6 @@
  *
  */
 
-
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/module.h>
@@ -34,7 +34,6 @@
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
-#include <linux/vmalloc.h>
 #include <linux/mman.h>
 #include <linux/delay.h>
 #include <asm/io.h>
@@ -43,30 +42,30 @@
 #include <linux/workqueue.h>
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
-#endif
+#include <linux/list.h>
+
 #ifdef STANDALONE_ZAPATA
 #include "zaptel.h"
 #else
 #include <linux/zaptel.h>
 #endif
 
-#ifdef HOTPLUG_FIRMWARE
-static const char *dte_firmware = "tc400m-firmware.bin";
+#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 128
-
-#define NUM_CARDS 24
-#define NUM_EC	  4
+#define WC_MAX_IFACES 8
 
 /* NUM_CHANNELS must be checked if new firmware (dte_firm.h) is used */
 #define NUM_CHANNELS 97
@@ -80,30 +79,22 @@
 #define G729_LENGTH 20
 #define G723_LENGTH 30
 
-#define G729_SAMPLES 160	/* g.729 */
-#define G723_SAMPLES 240 	/* g.723 */
-
-#define G729_BYTES 20	/* g.729 */
-#define G723_BYTES 20 	/* g.723 */
-
-
-
-#define ACK_SPACE 20
-
-#define MAX_COMMANDS (NUM_CHANNELS + ACK_SPACE)
-#define MAX_RCV_COMMANDS 16
-
-/* 1432 for boot, 274 for 30msec ulaw, 194 for 20mec ulaw */
-#define BOOT_CMD_LEN 1500
+#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 BOOT_CMD_LEN	/* Must be the larger of BOOT_CMD_LEN or OTHER_CMD_LEN */
+#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 PCI_WINDOW_SIZE ((2 *  2 * ERING_SIZE * SFRAME_SIZE) + (2 * ERING_SIZE * 4))
 
 #define MDIO_SHIFT_CLK		0x10000
 #define MDIO_DATA_WRITE0 	0x00000
@@ -117,182 +108,130 @@
 #define RCV_CSMENCAPS_ACK 3
 #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&0x0F, 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&0x0F, 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&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_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&0x0F, 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&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x1B,0x04, 0xFF,0xFF, \
 	0x00,0x00 }
 
 /* CPU Commands */
-#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&0x0F, 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&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x12,0x04, 0x00,0x00, \
 	0x2C,0x01, 0x00,0x00 }
-#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&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x13,0x00, 0xFF,0xFF, \
 	p1,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&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x0F,0x04, 0xFF,0xFF, \
 	0x05,0x00 }
 
 /* General IP/RTP Commands */
-#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&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_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&0x0F, 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&0x0F, 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&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x04,0x03, 0xFF,0xFF, \
 	0x01,0xFF }
-#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&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x06,0x03, 0xFF,0xFF, \
 	0x02,0x00 }
 
 /* Supervisor channel commands */
-#define CMD_MSG_CREATE_CHANNEL_LEN 32
 #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_LEN 38
 #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_LEN 32
 #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_LEN 58
 #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_LEN 40
 #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_LEN 44
 #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_LEN 32
 #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_LEN 32
 #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_LEN 20
 #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_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) \
-	({ \
-		int ret = 0; \
-		do { \
-	 		if (ret == 2) \
-	 		{ \
-				wc->ztsnd_rtx++; \
-	 			if (hex == 0x0010) \
-					wc->ztsnd_0010_rtx++; \
-			} \
-			down(&wc->cmdqsem); \
-	 		wc->last_command_sent = hex; \
-			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; \
-				int i; \
-				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); \
-			up(&wc->cmdqsem); \
-			ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 0); \
-			if (ret == 1) \
-				return(1); \
-		} while (ret == 2); \
-	})
-
-
 struct cmdq {
-	unsigned int cmdlen;
-	unsigned int cmd[MAX_COMMAND_LEN];
+	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;
-	char *variety;
+	const char *variety;
 	unsigned int intcount;
 	unsigned int rxints;
 	unsigned int txints;
@@ -301,16 +240,15 @@
 	int freeregion;
 	int rdbl;
 	int tdbl;
-	int cards;
 	spinlock_t reglock;
 	wait_queue_head_t regq;
 	int rcvflags;
 	
 	struct semaphore chansem;
 	struct semaphore cmdqsem;
-	struct cmdq cmdq[MAX_COMMANDS];
-	unsigned int cmdq_wndx;
-	unsigned int cmdq_rndx;
+	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;
@@ -321,16 +259,16 @@
 	unsigned int ztsnd_rtx;
 	unsigned int ztsnd_0010_rtx;
 
-	unsigned char numchannels;
+	unsigned int numchannels;
 	unsigned char complexname[40];
 
 	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 */
+	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;
@@ -341,37 +279,26 @@
 };
 
 struct wcdte_desc {
-	char *name;
+	const char *name;
 	int flags;
 };
 
-static struct wcdte_desc wcdte = { "Wildcard TC400P+TC400M", 0 };
+static const struct wcdte_desc wcdte = { "Wildcard TC400P+TC400M", 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 */
+	int encoder;
 	struct wcdte *wc;
 
 	unsigned int timestamp;
 	unsigned int seqno;
 
-	unsigned int timeslot_in_num;		/* DTE chennel on which results we be received from */
-	unsigned int timeslot_out_num;		/* DTE channel to send data to */
-
-	unsigned int chan_in_num;		/* DTE chennel on which results we be received from */
-	unsigned int chan_out_num;		/* DTE channel to send data to */
+	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;
@@ -380,21 +307,17 @@
 	unsigned int dte_seqno_rcv;
 };
 
-
-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 char *mode;
-int debug_packets = 0;
-
-
-static int wcdte_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 wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2);
+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 zt_tc_sanitycheck(struct zt_transcode_header *zth, unsigned int outbytes)
+static inline int sanitycheck(struct zt_transcode_header *zth, unsigned int outbytes)
 {
 	if (zth->dstoffset >= sizeof(zth->dstdata))
 		return 0;
@@ -413,23 +336,136 @@
 	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 */
+		module_printk("no cmdq entries available; limit of %d reached\n", MAX_TOTAL_CMDQ);
+		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->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;
 
 	state_ptr->chan_in_num = 999;
 	state_ptr->chan_out_num = 999;
 	
-	if (encoder == 1)
-	{
+	if (encoder) {
 		state_ptr->timeslot_in_num = channel * 2;
 		state_ptr->timeslot_out_num = channel * 2 + 1;
 	} else {
@@ -438,138 +474,141 @@
 	}
 }
 
-static unsigned int wcdte_zapfmt_to_dtefmt(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)
+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 __wcdte_getctl(struct wcdte *wc, unsigned int addr)
+static inline unsigned int __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)
+static inline void setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
 {
 	unsigned long flags;
+
 	spin_lock_irqsave(&wc->reglock, flags);
-	__wcdte_setctl(wc, addr, val);
+	__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;
+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);
 
-	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;
+	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)
 {
-	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);
-
+	int i;
+	unsigned int reg;
+	struct cmdq *cmdq;
+
+	reg = getctl(wc, 0x0028) & 0x00700000;
+	
 	/* 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;
-
-	if (debug_packets && (writechunk[12] == 0x88) && (writechunk[13] == 0x9B))
-	{
-		printk("wcdte debug: TX: ");
-		for (i=0; i<debug_packets; i++)
-			printk("%02X ", writechunk[i]);
+	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");
 	}
 
-	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);
+	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;
 }
 
@@ -582,63 +621,61 @@
 	unsigned char *chars;
 	unsigned int inbytes = 0;
 	unsigned int timestamp_inc = 0;
-	int i = 0;
 	int res = 0;
-	unsigned int ipchksum, ndx;
-	switch(op) {
+	u32 ipchksum;
+
+	switch (op) {
 	case ZT_TCOP_ALLOCATE:
+		if (ztc->flags.chan_built)
+			break;
 		down(&wc->chansem);
-		if (ztc->chan_built == 0)
-		{
-			if (st->encoder == 1)
-				wcdte_create_channel(wc, wcdte_zapfmt_to_dtefmt(zth->srcfmt), wcdte_zapfmt_to_dtefmt(zth->dstfmt),
-						st->timeslot_in_num, st->timeslot_out_num, &(st->chan_in_num), &(st->chan_out_num));
-			else
-				wcdte_create_channel(wc, wcdte_zapfmt_to_dtefmt(zth->dstfmt), wcdte_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 */
-			ndx = st->timeslot_in_num/2;
-			if (st->encoder == 1)
-				compl_ztc = &(wc->udecode->channels[ndx]);
-			else
-				compl_ztc = &(wc->uencode->channels[ndx]);
-			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;
-		}
+		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->flags.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->flags.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);
-		ndx = st->timeslot_in_num/2;
 			
-		if (st->encoder == 1)
-			compl_ztc = &(wc->udecode->channels[ndx]);
+		if (st->encoder)
+			compl_ztc = &(wc->udecode->channels[st->timeslot_in_num >> 1]);
 		else
-			compl_ztc = &(wc->uencode->channels[ndx]);
+			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->flags & ZT_TC_FLAG_BUSY) == 0)
-		{
-			if (st->encoder == 1)
-				wcdte_destroy_channel(wc, st->chan_in_num, st->chan_out_num);
+		if (!compl_ztc->flags.busy) {
+			if (st->encoder)
+				destroy_channel(wc, st->chan_in_num, st->chan_out_num);
 			else
-				wcdte_destroy_channel(wc, st->chan_out_num, st->chan_in_num);
+				destroy_channel(wc, st->chan_out_num, st->chan_in_num);
 
 			/* Mark this channel as not built */
-			ztc->chan_built = 0;
+			ztc->flags.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->flags.chan_built = 0;
 			compl_ztc->built_fmts = 0;
 			compl_st = compl_ztc->pvt;
 			compl_st->chan_in_num = 999;
@@ -648,61 +685,66 @@
 		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)) )
-		{
-			do
-			{
-				chars = (unsigned char *)(zth->srcdata + zth->srcoffset);
-					
-				if ((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW))
-				{
-					if (zth->dstfmt == ZT_FORMAT_G729A) {
-						inbytes = G729_SAMPLES; 
-						timestamp_inc = G729_SAMPLES; 
-					} else if (zth->dstfmt == ZT_FORMAT_G723_1) {
-						inbytes = G723_SAMPLES; 
-						timestamp_inc = G723_SAMPLES; 
+		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;
 					}
-
-				} else if (zth->srcfmt == ZT_FORMAT_G729A)
-				{
+					break;
+				case ZT_FORMAT_G729A:
 					inbytes = G729_BYTES;
 					timestamp_inc = G729_SAMPLES;
-				} else if (zth->srcfmt == ZT_FORMAT_G723_1)
-				{
+					break;
+				case ZT_FORMAT_G723_1:
 					inbytes = G723_BYTES;
 					timestamp_inc = G723_SAMPLES;
+					break;
 				}
 
 				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,
+					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_out_num)             & 0xFF,
 						(((st->timeslot_in_num) >> 8)+0x50)  & 0xFF,
-						  (st->timeslot_in_num)              & 0xFF,
-						 ((inbytes+20) >> 8)                 & 0xFF,
-						  (inbytes+20)                       & 0xFF,
-						   0x00,
-						   0x00,
-						   wcdte_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];
+						(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;
@@ -713,273 +755,198 @@
 					st->seqno += 1;
 					st->timestamp += timestamp_inc;
 
-					for (i = 0; i < inbytes; i++)
-						fifo[i+CMD_MSG_IP_UDP_RTP_LEN]= chars[i];
-
 					down(&wc->cmdqsem);
+
+					if (!(cmdq = get_free_cmdq(wc, sizeof(fifo) + inbytes))) {
+						up(&wc->cmdqsem);
+						res = -EIO;
+						break;
+					}
 		
-					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;
-					}
-					
+					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;
 				}
-				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)) );
-
+			} 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;
 		}
 
-		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;
+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;
+	int o2, i;
 	unsigned char rseq, rcodec;
 	unsigned int rcommand, rchannel, rlen, rtp_rseq, rtp_eseq;
-	unsigned char *chars = NULL;
+	u8 *chars = NULL;
 	unsigned int ztc_ndx;
-
-	readchunk = (volatile unsigned char *)wc->readchunk;
-	readchunk += dbl * SFRAME_SIZE;
 
 	o2 = dbl * 4;
 	o2 += ERING_SIZE * 4;
 	
-	/* Control in packet */
-	if ((readchunk[12] == 0x88) && (readchunk[13] == 0x9B))
-	{
-		if (debug_packets)
-		{
-			printk("wcdte debug: RX: ");
-			for (i=0; i<debug_packets; i++)
+	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)
-		{
+		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);
-			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++, rchannel);
-
-				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;
+				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);
 			}
-				
-			__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
-		{
+		} else {
 			wc->rcvflags = RCV_CSMENCAPS_ACK;
 			wake_up_interruptible(&wc->regq);
 		}
-	}
-
-	/* IP/UDP in packet */
-	else if ((readchunk[12] == 0x08) && (readchunk[13] == 0x00)
-		&& (readchunk[50] == 0x12) && (readchunk[51] == 0x34) && (readchunk[52] = 0x56) && (readchunk[53] == 0x78))
-	{
+	} 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/2;
-
-		if (ztc_ndx >= wc->numchannels)
-		{
-			if (debug)
-				printk("wcdte error: Invalid channel number received (ztc_ndx = %d) (numchannels = %d)\n", ztc_ndx, wc->numchannels);
+		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;
 		}
 
-		if ((rcodec == 0x00) || (rcodec == 0x08))	/* ulaw or alaw (decoders) */
-		{
+		switch (rcodec) {
+		case 0x00:		/* ulaw */
+		case 0x08:		/* alaw */
 			ztc = &(wc->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++;
-			}
-
+			break;
+		case 0x04:		/* g.723.1 */
+		case 0x12:		/* g.729 */

[... 1826 lines stripped ...]


More information about the zaptel-commits mailing list