[zaptel-commits] kpfleming: branch 1.4 r4483 - in /branches/1.4/kernel: ./ wctc4xxp/

SVN commits to the Zaptel project zaptel-commits at lists.digium.com
Wed Aug 13 20:57:02 CDT 2008


Author: kpfleming
Date: Wed Aug 13 20:57:01 2008
New Revision: 4483

URL: http://svn.digium.com/view/zaptel?view=rev&rev=4483
Log:
backport new transcoder interface and driver from DAHDI


Removed:
    branches/1.4/kernel/wctc4xxp/codec_test.c
Modified:
    branches/1.4/kernel/wctc4xxp/Kbuild
    branches/1.4/kernel/wctc4xxp/Makefile
    branches/1.4/kernel/wctc4xxp/base.c
    branches/1.4/kernel/zaptel-base.c
    branches/1.4/kernel/zaptel.h
    branches/1.4/kernel/zttranscode.c

Modified: branches/1.4/kernel/wctc4xxp/Kbuild
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/wctc4xxp/Kbuild?view=diff&rev=4483&r1=4482&r2=4483
==============================================================================
--- branches/1.4/kernel/wctc4xxp/Kbuild (original)
+++ branches/1.4/kernel/wctc4xxp/Kbuild Wed Aug 13 20:57:01 2008
@@ -8,7 +8,7 @@
   EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
 endif
 
-wctc4xxp-objs := base.o 
+wctc4xxp-objs := base.o
 
 ifneq ($(HOTPLUG_FIRMWARE),yes)
 wctc4xxp-objs += $(FIRM_DIR)/zaptel-fw-tc400m.o

Modified: branches/1.4/kernel/wctc4xxp/Makefile
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/wctc4xxp/Makefile?view=diff&rev=4483&r1=4482&r2=4483
==============================================================================
--- branches/1.4/kernel/wctc4xxp/Makefile (original)
+++ branches/1.4/kernel/wctc4xxp/Makefile Wed Aug 13 20:57:01 2008
@@ -3,14 +3,4 @@
 # For newer kernels, Kbuild will be included directly by the kernel
 # build system.
 include $(src)/Kbuild
-
-else
-
-tests: codec_test
-
-codec_test: codec_test.c ../zaptel.h
-	$(CC) -o $@ $< $(CFLAGS)
-
-clean:
-	rm -rf codec_test
 endif

Modified: branches/1.4/kernel/wctc4xxp/base.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/wctc4xxp/base.c?view=diff&rev=4483&r1=4482&r2=4483
==============================================================================
--- branches/1.4/kernel/wctc4xxp/base.c (original)
+++ branches/1.4/kernel/wctc4xxp/base.c Wed Aug 13 20:57:01 2008
@@ -1,9 +1,7 @@
 /*
  * Wildcard TC400B Driver
  *
- * Written by John Sloan <jsloan at digium.com>
- *
- * Copyright (C) 2006, Digium, Inc.
+ * Copyright (C) 2006-2008, Digium, Inc.
  *
  * All rights reserved.
  *
@@ -26,86 +24,154 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
 #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>
-#include <asm/semaphore.h>
 #include <linux/jiffies.h>
-#include <linux/workqueue.h>
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/etherdevice.h>
+#include <linux/timer.h>
+
+#include "zaptel.h"
+
+/* COMPILE TIME OPTIONS =================================================== */
+
+#define INTERRUPT 0
+#define WORKQUEUE 1
+#define TASKLET   2
+
+#ifndef DEFERRED_PROCESSING 
+#	define DEFERRED_PROCESSING WORKQUEUE
 #endif
-#include "zaptel.h"
-
-/* #define USE_TEST_HW */
-#define USE_TDM_CONFIG
-#define QUIET_DSP
-
-#define WC_MAX_IFACES 128
-
-#define NUM_CARDS 24
-#define NUM_EC	  4
-
-/* NUM_CHANNELS must be checked if new firmware (dte_firm.h) is used */
-#define NUM_CHANNELS 120
-
-#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	/* G.729 */
-#define G723_SAMPLES 240 	/* G.723.1 */
-
-#define G729_BYTES 20		/* G.729 */
-#define G723_6K_BYTES 24 	/* G.723.1 at 6.3kb/s */
-#define G723_5K_BYTES 20	/* G.723.1 at 5.3kb/s */
-#define G723_SID_BYTES 4	/* G.723.1 SID frame */
-
-#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 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 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 */
+
+#if DEFERRED_PROCESSING == INTERRUPT
+#	define ALLOC_FLAGS GFP_ATOMIC
+#elif DEFERRED_PROCESSING == TASKLET
+#	define ALLOC_FLAGS GFP_ATOMIC
+#else
+#	define ALLOC_FLAGS GFP_KERNEL
+#endif
+
+#define WARN() WARN_ON(1)
+
+#define DTE_PRINTK(_lvl, _fmt, _args...) \
+	   printk(KERN_##_lvl "%s: %s: " _fmt, THIS_MODULE->name, \
+	          (wc)->board_name, ## _args)
+
+#define DTE_DEBUG(_dbgmask, _fmt, _args...)                                 \
+	if ((debug & _dbgmask) == (_dbgmask)) {                             \
+		printk(KERN_DEBUG "%s: %s: " _fmt, THIS_MODULE->name,       \
+		       (wc)->board_name, ## _args);                         \
+	}                                                                   \
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#define WARN_ON_ONCE(__condition) do {         \
+	static int __once = 1;                 \
+	if (unlikely(__condition)) {           \
+		if (__once) {                  \
+			__once = 0;            \
+			WARN_ON(0);            \
+		}                              \
+	}                                      \
+} while(0) 
+#endif
+
+#define INVALID 999 /* Used to mark invalid channels, commands, etc.. */
+#define MAX_CHANNEL_PACKETS  5 /* Never let more than 5 outstanding packets exist for any channel. */
+
+#define G729_LENGTH	20
+#define G723_LENGTH	30
+
+#define G729_SAMPLES	160	/* G.729 */
+#define G723_SAMPLES	240 	/* G.723.1 */
+
+#define G729_BYTES	20	/* G.729 */
+#define G723_6K_BYTES	24 	/* G.723.1 at 6.3kb/s */
+#define G723_5K_BYTES	20	/* G.723.1 at 5.3kb/s */
+#define G723_SID_BYTES	4	/* G.723.1 SID frame */
+
+#define MAX_CAPTURED_PACKETS 5000
+
+/* The following bit fields are used to set the various debug levels. */
+#define DTE_DEBUG_GENERAL          (1 << 0) /* 1  */
+#define DTE_DEBUG_CHANNEL_SETUP    (1 << 1) /* 2  */
+#define DTE_DEBUG_RTP_TX           (1 << 2) /* 4  */
+#define DTE_DEBUG_RTP_RX           (1 << 3) /* 8  */
+#define DTE_DEBUG_RX_TIMEOUT	   (1 << 4) /* 16 */
+#define DTE_DEBUG_NETWORK_IF       (1 << 5) /* 32 */
+#define DTE_DEBUG_NETWORK_EARLY    (1 << 6) /* 64 */
+
+int debug;
+char *mode;
+
+static spinlock_t wctc4xxp_list_lock;
+static struct list_head wctc4xxp_list;
+
+#define ETH_P_CSM_ENCAPS 0x889B
+
+struct rtphdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8    csrc_count:4;
+	__u8    extension:1;
+	__u8    padding:1;
+	__u8    ver:2;
+	__u8    type:7;
+	__u8 	marker:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	__u8    ver:2;
+	__u8    padding:1;
+	__u8    extension:1;
+	__u8    csrc_count:4;
+	__u8 	marker:1;
+	__u8    type:7;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	__be16	seqno;
+	__be32  timestamp;
+	__be32  ssrc;
+} __attribute__((packed));
+
+struct rtp_packet {
+	struct ethhdr ethhdr;
+	struct iphdr  iphdr;
+	struct udphdr udphdr;
+	struct rtphdr rtphdr;
+	__u8   payload[0];
+}__attribute__((packed));
+
+/* Ethernet packet type for communication control information to the DTE. */
+struct csm_encaps_hdr {
+	struct ethhdr ethhdr;
+	/* CSM_ENCAPS HEADER */
+	__be16 op_code;
+	__u8   seq_num;
+	__u8   control;
+	__be16 channel;
+	/* COMMON PART OF PAYLOAD HEADER */
+	__u8   length;
+	__u8   index;
+	__u8   type;
+	__u8   class;
+	__le16 function;
+	__le16 reserved;
+	__le16 params[0];
+} __attribute__((packed));
+
+struct csm_create_channel_cmd {
+	struct csm_encaps_hdr hdr;
+	__le16 channel_type;
+	__le16 timeslot;
+} __attribute__((packed));
+
 #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, \
@@ -181,17 +247,26 @@
 	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 CONTROL_PACKET_OPCODE  0x0001
+/* Control bits */
+#define LITTLE_ENDIAN   0x01
+#define SUPPRESS_ACK    0x40
+#define MESSAGE_PACKET  0x80
+
+#define SUPERVISOR_CHANNEL 0xffff
+
+/* Supervisor function codes */
+#define SUPVSR_CREATE_CHANNEL  0x0010
+
+#define CONFIG_CHANGE_TYPE        0x00 
+#define CONFIG_DEVICE_CLASS       0x06
+
 #define CMD_MSG_QUERY_CHANNEL_LEN 30
 #define CMD_MSG_QUERY_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, 0x01,0x06,0x10,0x00, 0x00,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, \
@@ -242,303 +317,227 @@
 	0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x5B,0x80, 0x00,0x00, \
 	0x00,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,s) { \
-	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,(s&0xFF)}
-
-#define CMD_MSG_DW_WRITE_LEN 38
-#define CMD_MSG_DW_WRITE(s,a,d) { \
-	0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
-	0x00,0x01,s&0x0F,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x00,0x00, \
-	((a>>24)&0x00FF),((a>>16)&0x00FF), ((a>>8)&0x00FF),(a&0x00FF), \
-	((d>>24)&0x00FF),((d>>16)&0x00FF), ((d>>8)&0x00FF),(d&0x00FF) }
-
-#define CMD_MSG_FORCE_ALERT_LEN 32
-#define CMD_MSG_FORCE_ALERT(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,0x09,0x04, 0x00,0x00, \
-	0x24,0x00, 0x00,0x00 }
-
-#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->last_seqno = fifo[16]; \
-				wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; \
-			} \
-			__transmit_demand(wc); \
-			up(&wc->cmdqsem); \
-			if (hex == 0x0000) \
-				ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS_ACK, 2); \
-			else { \
-				ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 0); \
-				if (wc->dsp_crashed) \
-					return 1; \
-			} \
-			if (ret == 1) \
-				return(1); \
-		} while (ret == 2); \
-	})
-
-
-struct cmdq {
-	unsigned int cmdlen;
-	unsigned char cmd[MAX_COMMAND_LEN];
+#define SFRAME_SIZE 320 
+
+/* Transcoder buffer (tcb) */
+struct tcb {
+	/* First field so that is aligned by default. */
+	u8 cmd[SFRAME_SIZE];
+	struct list_head node;
+	unsigned long timeout;
+	unsigned long retries;
+	/* NOTE:  these flags aren't bit fields because some of the flags are
+	 * combinations of the other ones. */
+#define DO_NOT_AUTO_FREE        (1 << 0)
+#define TX_COMPLETE             (1 << 1)
+#define DO_NOT_CAPTURE          (1 << 2)
+#define __WAIT_FOR_ACK          (1 << 3)
+#define __WAIT_FOR_RESPONSE     (1 << 4) 
+#define DTE_CMD_TIMEOUT         (1 << 5)
+#define WAIT_FOR_ACK (__WAIT_FOR_ACK | DO_NOT_AUTO_FREE)
+#define WAIT_FOR_RESPONSE (__WAIT_FOR_RESPONSE | DO_NOT_AUTO_FREE)
+	unsigned long flags;
+	struct tcb *response;
+	struct completion complete;
+	struct timer_list timer;
+	void *data;
+	/* The number of bytes available in data. */
+	int data_len; 
 };
 
+static inline void *hdr_from_cmd(struct tcb *cmd) {
+	return cmd->data;
+}
+
+static inline void 
+initialize_cmd(struct tcb *cmd, unsigned long cmd_flags) 
+{
+	memset(cmd, 0, sizeof(*cmd));
+	INIT_LIST_HEAD(&cmd->node);
+	init_completion(&cmd->complete);
+	cmd->flags = cmd_flags;
+	cmd->data = &cmd->cmd[0];
+	cmd->data_len = SFRAME_SIZE;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+/*! Used to allocate commands to submit to the dte. */
+kmem_cache_t *cmd_cache;
+#else
+/*! Used to allocate commands to submit to the dte. */
+struct kmem_cache *cmd_cache;
+#endif
+
+static inline struct tcb *
+__alloc_cmd(unsigned alloc_flags, unsigned long cmd_flags)
+{
+	struct tcb *cmd;
+
+	cmd = kmem_cache_alloc(cmd_cache, alloc_flags);
+	if (likely(cmd)) {
+		initialize_cmd(cmd, cmd_flags);
+	}
+	return cmd;
+}
+
+static struct tcb *
+alloc_cmd(void)
+{
+	return __alloc_cmd(GFP_KERNEL, 0);
+}
+
+static void 
+__free_cmd(struct tcb *cmd)
+{
+	if (cmd->data != &cmd->cmd[0]) {
+		kfree(cmd->data);
+	}
+	kmem_cache_free(cmd_cache, cmd);
+	return;
+}
+
+static void 
+free_cmd(struct tcb *cmd)
+{
+	if (cmd->response) {
+		__free_cmd(cmd->response);
+	}
+	__free_cmd(cmd);
+}
+
+typedef enum { DECODER=0, ENCODER, } encode_t;
+
+struct channel_stats {
+	atomic_t packets_sent;
+	atomic_t packets_received;
+};
+
+struct channel_pvt {
+	spinlock_t lock;		/* Lock for this structure */
+	encode_t encoder;		/* If we're an encoder */
+	struct wcdte *wc;
+
+	unsigned int timestamp;
+	unsigned int seqno;
+
+	unsigned int cmd_seqno;
+
+	unsigned int timeslot_in_num;	/* DTE channel on which results will be received from */
+	unsigned int timeslot_out_num;	/* DTE channel to send data to */
+
+	unsigned int chan_in_num;	/* DTE channel on which results will be received from */
+	unsigned int chan_out_num;	/* DTE channel to send data to */
+	
+	struct channel_stats stats;
+
+	u16 last_dte_seqno;
+	unsigned int wctc4xxp_seqno_rcv;
+
+	unsigned char ssrc;
+	struct list_head rx_queue;	/* Transcoded packets for this channel. */
+};
+
 struct wcdte {
-	struct pci_dev *dev;
-	char *variety;
-	unsigned int intcount;
-	unsigned int rxints;
-	unsigned int txints;
-	unsigned int intmask;
+	char board_name[40];
+	const char *variety;
 	int pos;
-	int freeregion;
-	int rdbl;
-	int tdbl;
 	int cards;
+	struct list_head node;
 	spinlock_t reglock;
-	wait_queue_head_t regq;
-	int rcvflags;
-	
+	wait_queue_head_t waitq;
 	struct semaphore chansem;
-	struct semaphore cmdqsem;
-	struct cmdq cmdq[MAX_COMMANDS];
-	unsigned int cmdq_wndx;
-	unsigned int cmdq_rndx;
-
-	unsigned int last_seqno;
-	unsigned int last_rseqno;
-	unsigned int last_command_sent;
-	unsigned int last_rcommand;
-	unsigned int last_rparm1;
+#define DTE_READY	1
+#define DTE_SHUTDOWN	2 
+	unsigned long flags;
+
+	spinlock_t cmd_list_lock;
+	/* This is a device-global list of commands that are waiting to be
+	 * transmited (and did not fit on the transmit descriptor ring) */
+	struct list_head cmd_list;
+	struct list_head waiting_for_response_list;
+
 	unsigned int seq_num;
-	long timeout;
-
-	unsigned int dsp_crashed;
-	unsigned int dumping;
-
-	unsigned int ztsnd_rtx;
-	unsigned int ztsnd_0010_rtx;
-
 	unsigned char 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 */
+	/* This section contains the members necessary to communicate with the
+	 * physical interface to the transcoding engine.  */
+	struct pci_dev *pdev;
+	unsigned int   intmask;
+	unsigned long  iobase;
+	struct wctc4xxp_descriptor_ring *txd;
+	struct wctc4xxp_descriptor_ring *rxd;
 	
-	int wqueints;
-	struct workqueue_struct *dte_wq;
-	struct work_struct dte_work;
-
 	struct zt_transcoder *uencode;
 	struct zt_transcoder *udecode;
+	struct channel_pvt *encoders;
+	struct channel_pvt *decoders;
+
+#if DEFERRED_PROCESSING == WORKQUEUE
+	struct work_struct deferred_work;
+#endif
+
+	/*
+	 * This section contains the members necessary for exporting the
+	 * network interface to the host system.  This is only used for
+	 * debugging purposes.
+	 *
+	 */
+	struct sk_buff_head captured_packets;
+	struct net_device *netdev;
+	struct net_device_stats net_stats;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+	struct napi_struct napi;
+#endif
+	struct timer_list watchdog;
+
 };
 
-struct wcdte_desc {
-	char *name;
-	int flags;
-};
-
-static struct wcdte_desc wctc400p = { "Wildcard TC400P+TC400M", 0 };
-static struct wcdte_desc wctce400 = { "Wildcard TCE400+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 */
-	struct wcdte *wc;
-
-	unsigned int timestamp;
-	unsigned int seqno;
-
-	unsigned int cmd_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 */
+static inline void wctc4xxp_set_ready(struct wcdte *wc) {
+	set_bit(DTE_READY, &wc->flags);
+}
+static inline int wctc4xxp_is_ready(struct wcdte *wc) {
+	return test_bit(DTE_READY, &wc->flags);
+}
+
+#if 1
+ /* \todo This macro is a candidate for removal.  It's still here because of
+ * how the commands are passed to this zt_send_cmd */
+#define wctc4xxp_send_cmd(wc, command) ({                                         \
+	int __res;                                                           \
+	u8 _cmd[] = command;                                                 \
+	struct tcb *cmd;                                                 \
+	if (!(cmd=__alloc_cmd(GFP_KERNEL, WAIT_FOR_RESPONSE)))               \
+		return -ENOMEM;                                              \
+	BUG_ON(sizeof(_cmd) > SFRAME_SIZE);                                  \
+	memcpy(cmd->data, _cmd, sizeof(_cmd));                               \
+	cmd->data_len = sizeof(_cmd);                                        \
+	__res = __wctc4xxp_send_cmd(wc, cmd);                                     \
+	__res;                                                               \
+})
+#define wctc4xxp_create_cmd(wc, command) ({                                       \
+	u8 _command[] = command;                                             \
+	struct tcb *_cmd;                                                \
+	if (!(_cmd=__alloc_cmd(GFP_KERNEL, WAIT_FOR_RESPONSE)))              \
+		return -ENOMEM;                                              \
+	BUG_ON(sizeof(_command) > SFRAME_SIZE);                              \
+	memcpy(_cmd->data, _command, sizeof(_command));                      \
+	_cmd->data_len = sizeof(_command);                                   \
+	_cmd;                                                                \
+})
+#endif
+
+#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
+
+static inline u8 wctc4xxp_zapfmt_to_dtefmt(unsigned int fmt)
+{
+	u8 pt;
 	
-	unsigned int packets_sent;
-	unsigned int packets_received;
-
-	unsigned int last_dte_seqno;
-	unsigned int dte_seqno_rcv;
-
-	unsigned char ssrc;
-};
-
-
-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 int debug_des = 0;			/* Set the number of descriptor packet bytes to output on errors, 0 disables output */
-static int debug_des_cnt = 0;			/* Set the number of times descriptor packets are displayed before the output is disabled */
-static int force_alert = 0;
-static int debug_notimeout = 0;
-static char *mode;
-static 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 int __wcdte_setup_channels(struct wcdte *wc);
-
-static int __dump_descriptors(struct wcdte *wc)
-{
-	volatile unsigned char *writechunk, *readchunk;
-	int o2, i, j;
-
-	if (debug_des_cnt == 0)
-		return 1;
-
-	printk("Transmit Descriptors (wc->tdbl = %d)\n", wc->tdbl);
-	for (i = 0; i < ERING_SIZE; i++)
-	{
-		writechunk = (volatile unsigned char *)(wc->writechunk);
-		writechunk += i * SFRAME_SIZE;
-		o2 = i * 4;
-
-		if (i == wc->tdbl)
-			printk("->");
-		else
-			printk("  ");
-		if ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000))
-			printk("AN983 owns : ");
-		else
-			printk("Driver owns: ");
-
-		for (j = 0; j < debug_des; j++)
-			printk("%02X ", writechunk[j]);
-		printk("\n");
-	}
-
-	printk("Receive Descriptors (wc->rdbl = %d)\n", wc->rdbl);
-	for (i = 0; i < ERING_SIZE; i++)
-	{
-		readchunk = (volatile unsigned char *)wc->readchunk;
-		readchunk += i * SFRAME_SIZE;
-		o2 = i * 4;
-		o2 += ERING_SIZE * 4;
-
-		if (i == wc->rdbl)
-			printk("->");
-		else
-			printk("  ");
-		if ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000))
-			printk("AN983 owns : ");
-		else
-			printk("Driver owns: ");
-
-		for (j = 0; j < debug_des; j++)
-			printk("%02X ", readchunk[j]);
-		printk("\n");
-	}
-	if (debug_des_cnt > 0)
-		debug_des_cnt--;
-	return 0;
-}
-
-/* Sanity check values */
-static inline int zt_tc_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 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->cmd_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;
-
-	state_ptr->ssrc = 0x78;
-	
-	if (encoder == 1)
-	{
-		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 unsigned int wcdte_zapfmt_to_dtefmt(unsigned int fmt)
-{
-	unsigned int pt;
-	
-	switch(fmt)
-	{
+	switch(fmt) {
 		case ZT_FORMAT_G723_1:
 			pt = DTE_FORMAT_G723_1;
 			break;
@@ -553,808 +552,1700 @@
 			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;
-
-	if (debug_packets && (writechunk[12] == 0x88) && (writechunk[13] == 0x9B))
-	{
-		printk("wcdte debug: TX: ");
-		for (i=0; i<debug_packets; i++)
-			printk("%02X ", writechunk[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);
-}
-
-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 i = 0;
-	int res = 0;
-	unsigned int ipchksum, ndx;
-	switch(op) {
-	case ZT_TCOP_ALLOCATE:
+			break;
+	}
+
+	return pt;
+}
+
+
+static struct sk_buff * 
+tcb_to_skb(struct net_device *netdev, const struct tcb *cmd)
+{
+	struct sk_buff *skb;
+	skb = alloc_skb(cmd->data_len, in_atomic() ? GFP_ATOMIC : GFP_KERNEL);
+	if (skb) {
+		skb->dev = netdev;
+		skb_put(skb, cmd->data_len);
+		memcpy(skb->data, cmd->data, cmd->data_len);
+		skb->protocol = eth_type_trans(skb,netdev);
+	}
+	return skb;
+}
+
+/** 
+ * wctc4xxp_skb_to_cmd - Convert a socket buffer (skb) to a tcb
+ * @wc: The transcoder that we're going to send this command to.
+ * @skb: socket buffer to convert.
+ *
+ */
+static struct tcb *
+wctc4xxp_skb_to_cmd(struct wcdte *wc, const struct sk_buff *skb)
+{
+	const unsigned long alloc_flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+	struct tcb *cmd;
+	/* const static char dev_mac[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; */
+	if ((cmd = __alloc_cmd(alloc_flags, 0))) {
+		int res;
+		cmd->data_len = skb->len;
+		if ((res = skb_copy_bits(skb, 0, cmd->data, cmd->data_len))) {
+			DTE_PRINTK(WARNING, 
+			   "Failed call to skb_copy_bits.\n");
+			free_cmd(cmd);
+			cmd = NULL;
+		}
+		/* When we set up our interface we indicated that we do not
+		 * support ARP.  Therefore, the destination MAC on packets
+		 * arriving from the kernel networking components are not
+		 * going to be correct. Let's fix that here.
+		 */
+		/* \todo let us just use whatever was in the packet already... */
+		/* memcpy(&cmd->cmd[6], dev_mac, sizeof(dev_mac)); */
+	}
+	return cmd;
+}
+
+static void 
+wctc4xxp_net_set_multi(struct net_device *netdev)
+{
+	struct wcdte *wc = netdev->priv;
+	DTE_DEBUG(DTE_DEBUG_GENERAL, "%s promiscuity:%d\n", 
+	   __FUNCTION__, netdev->promiscuity);
+}
+
+static int 
+wctc4xxp_net_up(struct net_device *netdev)
+{
+	struct wcdte *wc = netdev->priv;
+	DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __FUNCTION__);
+#if 1
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+	netif_poll_enable(netdev);
+#else
+	napi_enable(&wc->napi);
+#endif
+#endif
+	return 0;
+}
+
+static int 
+wctc4xxp_net_down(struct net_device *netdev)
+{
+	struct wcdte *wc = netdev->priv;
+	DTE_DEBUG(DTE_DEBUG_GENERAL, "%s\n", __FUNCTION__);
+#if 1
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+	netif_poll_disable(netdev);
+#else
+	napi_disable(&wc->napi);
+#endif
+#endif
+	return 0;
+}
+
+static void wctc4xxp_transmit_cmd(struct wcdte *, struct tcb *);
+
+static int 
+wctc4xxp_net_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct wcdte *wc = netdev->priv;
+	struct tcb *cmd;
+
+	/* We set DO_NOT_CAPTURE because this packet was already captured by
+	 * in code higher up in the networking stack.  We don't want to
+	 * capture it twice. 
+	 */
+	if ((cmd = wctc4xxp_skb_to_cmd(wc, skb))) {
+		cmd->flags |= DO_NOT_CAPTURE; 
+		wctc4xxp_transmit_cmd(wc, cmd);
+	}
+
+	dev_kfree_skb_any(skb);
+	return NETDEV_TX_OK;
+}
+
+static int 
+wctc4xxp_net_receive(struct wcdte *wc, int max)
+{
+	int count = 0;
+	struct sk_buff *skb;
+	WARN_ON(0 == max);
+	while ((skb = skb_dequeue(&wc->captured_packets))) {
+		netif_receive_skb(skb);
+		if (++count >= max) {
+			break;
+		}
+	}
+	return count;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+static int 
+wctc4xxp_poll(struct net_device *netdev, int *budget)
+{
+	struct wcdte *wc = netdev->priv;
+	int count = 0;
+	int quota = min(netdev->quota, *budget);
+
+	count = wctc4xxp_net_receive(wc, quota);
+
+	*budget -=       count;
+	netdev->quota -= count;
+
+	if (!skb_queue_len(&wc->captured_packets)) {
+		netif_rx_complete(netdev);
+		return 0;
+	} else {
+		return -1;
+	}
+}
+#else
+static int 
+wctc4xxp_poll(struct napi_struct *napi, int budget)
+{
+	struct wcdte *wc = container_of(napi, struct wcdte, napi);
+	int count;
+
+	count = wctc4xxp_net_receive(wc, budget);
+
+	if (!skb_queue_len(&wc->captured_packets)) {
+		netif_rx_complete(wc->netdev, &wc->napi);
+	}
+	return count;
+}
+#endif
+
+static struct net_device_stats *
+wctc4xxp_net_get_stats(struct net_device *netdev)
+{
+	struct wcdte *wc = netdev->priv;
+	return &wc->net_stats;
+}
+
+/* Wait until this device is put into promiscuous mode, or we timeout. */
+static void 
+wctc4xxp_net_waitfor_promiscuous(struct wcdte *wc)
+{
+	unsigned int seconds = 15;
+	unsigned long start = jiffies;
+	struct net_device *netdev = wc->netdev;
+
+	DTE_PRINTK(INFO, 
+	   "Waiting %d seconds for adapter to be placed in " \
+	   "promiscuous mode for early trace.\n", seconds);
+
+	while (!netdev->promiscuity) {
+		if (signal_pending(current)) {
+			DTE_PRINTK(INFO, 
+			   "Aborting wait due to signal.\n");
+			break;
+		}
+		msleep(100);
+		if (time_after(jiffies, start + (seconds * HZ))) {
+			DTE_PRINTK(INFO,
+			   "Aborting wait due to timeout.\n");
+			break;
+		}
+	}
+}
+
+static int  wctc4xxp_turn_off_booted_led(struct wcdte *wc);
+static void wctc4xxp_turn_on_booted_led(struct wcdte *wc);
+
+static int 
+wctc4xxp_net_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct wcdte *wc = netdev->priv;
+	switch(cmd) {
+	case 0x89f0:
 		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;
-		}
+		wctc4xxp_turn_off_booted_led(wc);
+		break;
+	case 0x89f1:
+		wctc4xxp_turn_on_booted_led(wc);
 		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]);
-		else
-			compl_ztc = &(wc->uencode->channels[ndx]);
-
-		/* 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);
-			else
-				wcdte_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;
+	default:
+		return -EOPNOTSUPP;
+	};
+	return 0;
+}
+
+/** 
+ * wctc4xxp_net_register - Register a new network interface.
+ * @wc: transcoder card to register the interface for.
+ *
+ * The network interface is primarily used for debugging in order to watch the
+ * traffic between the transcoder and the host.
+ * 
+ */
+static int 
+wctc4xxp_net_register(struct wcdte *wc)
+{
+	int res;
+	struct net_device *netdev;
+	const char our_mac[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
+
+	if (!(netdev = alloc_netdev(0, wc->board_name, ether_setup))) {
+		return -ENOMEM;
+	}
+
+	memcpy(netdev->dev_addr, our_mac, sizeof(our_mac));
+	netdev->priv = wc;
+	netdev->set_multicast_list = &wctc4xxp_net_set_multi;
+	netdev->open = &wctc4xxp_net_up;
+	netdev->stop = &wctc4xxp_net_down;
+	netdev->hard_start_xmit = &wctc4xxp_net_hard_start_xmit;
+	netdev->get_stats = &wctc4xxp_net_get_stats;
+	netdev->do_ioctl = &wctc4xxp_net_ioctl;
+	netdev->promiscuity = 0;
+	netdev->flags |= IFF_NOARP;
+#	if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+	netdev->poll = &wctc4xxp_poll;
+	netdev->weight = 64;
+#	else
+	netif_napi_add(netdev, &wc->napi, &wctc4xxp_poll, 64);
+#	endif
+
+	if ((res = register_netdev(netdev))) {
+		DTE_PRINTK(WARNING, 
+		   "Failed to register network device %s.\n",
+		   wc->board_name);
+		goto error_sw;
+	}
+
+	wc->netdev = netdev;
+	skb_queue_head_init(&wc->captured_packets);
+
+	if (debug & DTE_DEBUG_NETWORK_EARLY) {
+		wctc4xxp_net_waitfor_promiscuous(wc);
+	}
+
+	DTE_PRINTK(DEBUG, 
+	   "Created network device %s for debug.\n", wc->board_name);
+	return 0;
+
+error_sw:
+	if (netdev) free_netdev(netdev);
+	return res;
+}
+
+static void 
+wctc4xxp_net_unregister(struct wcdte *wc)
+{
+	struct sk_buff *skb;
+	if (!wc->netdev) {
+		return;
+	}
+
+	unregister_netdev(wc->netdev);
+
+	while ((skb = skb_dequeue(&wc->captured_packets))) {
+		kfree_skb(skb);
+	}
+	
+	free_netdev(wc->netdev);
+	wc->netdev = NULL;
+}
+
+
+/**
+ * wctc4xxp_net_capture_cmd - Send a tcb to the network stack.
+ * @wc: transcoder that received the command.
+ * @cmd: command to send to network stack.
+ *
+ */
+static void 
+wctc4xxp_net_capture_cmd(struct wcdte *wc, const struct tcb *cmd)
+{
+	struct sk_buff *skb;
+	struct net_device *netdev = wc->netdev;
+
+	if (!netdev) {
+		return;
+	}
+
+	/* No need to capture if there isn't anyone listening. */
+	if (!(netdev->flags & IFF_UP)) {
+		return;
+	}
+	
+	if (skb_queue_len(&wc->captured_packets) > MAX_CAPTURED_PACKETS) {
+		WARN_ON_ONCE(1);
+		return;
+	}
+
+	if (!(skb = tcb_to_skb(netdev, cmd))) {
+		return;
+	}
+
+	skb_queue_tail(&wc->captured_packets, skb);
+#	if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+	netif_rx_schedule(netdev);
+#	else
+	netif_rx_schedule(netdev, &wc->napi);
+#	endif
+	return;
+}
+
+
+/*! In-memory structure shared by the host and the adapter. */
+struct wctc4xxp_descriptor {
+	__le32 des0;
+	__le32 des1;
+	__le32 buffer1;
+	__le32 container; /* Unused */
+} __attribute__((packed));
+
+#define DRING_SIZE (1 << 3) /* Must be a power of two */
+#define DRING_MASK (DRING_SIZE-1)
+#define MIN_PACKET_LEN  64
+
+struct wctc4xxp_descriptor_ring {
+	/* Pointer to an array of descriptors to give to hardware. */
+	struct wctc4xxp_descriptor* desc;
+	/* Read completed buffers from the head. */
+	unsigned int 	head;
+	/* Write ready buffers to the tail. */
+	unsigned int 	tail;
+	/* Array to save the kernel virtual address of pending commands. */
+	struct tcb *pending[DRING_SIZE];
+	/* PCI Bus address of the descriptor list. */
+	dma_addr_t	desc_dma;
+	/*! either DMA_FROM_DEVICE or DMA_TO_DEVICE */
+	unsigned int 	direction;
+	/*! The number of buffers currently submitted to the hardware. */
+	unsigned int    count;
+	/*! The number of bytes to pad each descriptor for cache alignment. */
+	unsigned int	padding;
+	/*! Protects this structure from concurrent access. */
+	spinlock_t      lock;
+	/*! PCI device for the card associated with this ring. */
+	struct pci_dev  *pdev;
+};
+
+/**
+ * wctc4xxp_descriptor - Returns the desriptor at index.
+ * @dr: The descriptor ring we're using.
+ * @index: index of the descriptor we want.
+ * 
+ * We need this function because we do not know what the padding on the
+ * descriptors will be.  Otherwise, we would just use an array.
+ */
+static inline struct wctc4xxp_descriptor *
+wctc4xxp_descriptor(struct wctc4xxp_descriptor_ring *dr, int index)
+{
+	return (struct wctc4xxp_descriptor *)((u8*)dr->desc + 
+		((sizeof(*dr->desc) + dr->padding) * index));
+}
+
+static int
+wctc4xxp_initialize_descriptor_ring(struct pci_dev *pdev, struct wctc4xxp_descriptor_ring *dr, 
+	u32 des1, unsigned int direction)
+{
+	int i; 
+	const u32 END_OF_RING = 0x02000000;
+	u8 cache_line_size = 0;
+	struct wctc4xxp_descriptor *d;
+
+	BUG_ON(!pdev);
+	BUG_ON(!dr);
+
+	if (pci_read_config_byte(pdev, 0x0c, &cache_line_size)) {
+		/* \todo Print an error message... */
+		return -EIO;
+	}
+
+	memset(dr, 0, sizeof(*dr));
+
+	/*
+	 * Add some padding to each descriptor to ensure that they are
+	 * aligned on host system cache-line boundaries, but only for the 
+	 * cache-line sizes that we support.

[... 4538 lines stripped ...]



More information about the zaptel-commits mailing list