summaryrefslogtreecommitdiff
path: root/kernel/wctc4xxp
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-02-04 23:00:48 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-02-04 23:00:48 +0000
commit7e068801fbf82413ac0a5e63e586c268bd457434 (patch)
tree9b61e9a4e07167e0b7d347e4336245724befa29c /kernel/wctc4xxp
parent29daeebad888269fa0ee2ca7e54e238c8498ca2d (diff)
Move kernel stuff to under kernel/
(merged branch /zaptel/team/tzafrir/move ) Closes issue #7117. git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@3793 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'kernel/wctc4xxp')
-rw-r--r--kernel/wctc4xxp/Kbuild20
-rw-r--r--kernel/wctc4xxp/Makefile16
-rw-r--r--kernel/wctc4xxp/base.c2027
-rw-r--r--kernel/wctc4xxp/codec_test.c332
4 files changed, 2395 insertions, 0 deletions
diff --git a/kernel/wctc4xxp/Kbuild b/kernel/wctc4xxp/Kbuild
new file mode 100644
index 0000000..214aae1
--- /dev/null
+++ b/kernel/wctc4xxp/Kbuild
@@ -0,0 +1,20 @@
+obj-m += wctc4xxp.o
+
+FIRM_DIR := ../../firmware
+
+EXTRA_CFLAGS := -I$(src)/.. -Wno-undef -DSTANDALONE_ZAPATA
+
+ifeq ($(HOTPLUG_FIRMWARE),yes)
+ EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
+endif
+
+wctc4xxp-objs := base.o
+
+ifneq ($(HOTPLUG_FIRMWARE),yes)
+wctc4xxp-objs += $(FIRM_DIR)/zaptel-fw-tc400m.o
+endif
+
+$(obj)/base.o: $(src)/../zaptel.h
+
+$(obj)/$(FIRM_DIR)/zaptel-fw-tc400m.o: $(obj)/base.o
+ $(MAKE) -C $(obj)/$(FIRM_DIR) zaptel-fw-tc400m.o
diff --git a/kernel/wctc4xxp/Makefile b/kernel/wctc4xxp/Makefile
new file mode 100644
index 0000000..725abc4
--- /dev/null
+++ b/kernel/wctc4xxp/Makefile
@@ -0,0 +1,16 @@
+ifneq ($(KBUILD_EXTMOD),)
+# We only get here on kernels 2.6.0-2.6.9 .
+# 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
diff --git a/kernel/wctc4xxp/base.c b/kernel/wctc4xxp/base.c
new file mode 100644
index 0000000..3dcb1f4
--- /dev/null
+++ b/kernel/wctc4xxp/base.c
@@ -0,0 +1,2027 @@
+/*
+ * Wildcard TC400B Driver
+ *
+ * Written by John Sloan <jsloan@digium.com>
+ *
+ * Copyright (C) 2006, Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#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>
+#endif
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <linux/zaptel.h>
+#endif
+
+/* #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 */
+#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_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, \
+ 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 }
+#define CMD_MSG_VOIP_DTMFOPT_LEN 32
+#define CMD_MSG_VOIP_DTMFOPT(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,0x02,0x80, 0x00,0x00, \
+ 0x08,0x00, 0x00,0x00 }
+
+#define CMD_MSG_VOIP_TONECTL_LEN 32
+#define CMD_MSG_VOIP_TONECTL(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,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];
+};
+
+struct wcdte {
+ struct pci_dev *dev;
+ char *variety;
+ unsigned int intcount;
+ unsigned int rxints;
+ unsigned int txints;
+ unsigned int intmask;
+ int pos;
+ int freeregion;
+ int rdbl;
+ int tdbl;
+ int cards;
+ spinlock_t reglock;
+ wait_queue_head_t regq;
+ int rcvflags;
+
+ struct 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;
+ 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 */
+
+ int wqueints;
+ struct workqueue_struct *dte_wq;
+ struct work_struct dte_work;
+
+ struct zt_transcoder *uencode;
+ struct zt_transcoder *udecode;
+};
+
+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 */
+
+ 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)
+ {
+ case ZT_FORMAT_G723_1:
+ pt = DTE_FORMAT_G723_1;
+ break;
+ case ZT_FORMAT_ULAW:
+ pt = DTE_FORMAT_ULAW;
+ break;
+ case ZT_FORMAT_ALAW:
+ pt = DTE_FORMAT_ALAW;
+ break;
+ case ZT_FORMAT_G729A:
+ pt = DTE_FORMAT_G729A;
+ break;
+ default:
+ pt = DTE_FORMAT_UNDEF;
+ }
+
+ return(pt);
+}
+
+static inline void __wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
+{
+ outl(val, wc->iobase + addr);
+}
+
+static inline unsigned int __wcdte_getctl(struct wcdte *wc, unsigned int addr)
+{
+ return inl(wc->iobase + addr);
+}
+
+static inline void wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __wcdte_setctl(wc, addr, val);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline void wcdte_reinit_descriptor(struct wcdte *wc, int tx, int dbl, char *s)
+{
+ int o2 = 0;
+ o2 += dbl * 4;
+
+ if (!tx)
+ o2 += ERING_SIZE * 4;
+ wc->descripchunk[o2] = cpu_to_le32(0x80000000);
+
+ wcdte_setctl(wc, 0x0008, 0x00000000);
+}
+
+static inline unsigned int wcdte_getctl(struct wcdte *wc, unsigned int addr)
+{
+ unsigned long flags;
+ unsigned int val;
+ spin_lock_irqsave(&wc->reglock, flags);
+ val = __wcdte_getctl(wc, addr);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return val;
+}
+
+static inline int __transmit_demand(struct wcdte *wc)
+{
+ volatile unsigned char *writechunk;
+ int o2,i,j;
+ unsigned int reg, xmt_length;
+
+ reg = wcdte_getctl(wc, 0x0028) & 0x00700000;
+
+ /* Already transmiting, no need to demand another */
+ if (!((reg == 0) || (reg = 6)))
+ return(1);
+
+ /* Nothing to transmit */
+ if (wc->cmdq_rndx == wc->cmdq_wndx)
+ return(1);
+
+ /* Nothing to transmit */
+ if (wc->cmdq[wc->cmdq_rndx].cmdlen == 0 )
+ return(1);
+
+ writechunk = (volatile unsigned char *)(wc->writechunk);
+
+ writechunk += wc->tdbl * SFRAME_SIZE;
+
+ o2 = wc->tdbl * 4;
+
+ do
+ {
+ } while ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000));
+
+ xmt_length = wc->cmdq[wc->cmdq_rndx].cmdlen;
+ if (xmt_length < 64)
+ xmt_length = 64;
+
+ wc->descripchunk[o2+1] = cpu_to_le32((le32_to_cpu(wc->descripchunk[o2+1]) & 0xFBFFF800) | xmt_length);
+
+ for(i = 0; i < wc->cmdq[wc->cmdq_rndx].cmdlen; i++)
+ writechunk[i] = wc->cmdq[wc->cmdq_rndx].cmd[i];
+ for (j = i; j < xmt_length; j++)
+ writechunk[j] = 0;
+
+ 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:
+ 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;
+ }
+ 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;
+ }
+ 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_SID_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;
+ }
+ } else if (zth->srcfmt == ZT_FORMAT_G729A) {
+ inbytes = G729_BYTES;
+ timestamp_inc = G729_SAMPLES;
+ } else if (zth->srcfmt == ZT_FORMAT_G723_1) {
+ /* determine the size of the frame */
+ switch (chars[0] & 0x03) {
+ case 0x00:
+ inbytes = G723_6K_BYTES;
+ break;
+ case 0x01:
+ inbytes = G723_5K_BYTES;
+ break;
+ case 0x02:
+ inbytes = G723_SID_BYTES;
+ break;
+ case 0x03:
+ /* this is a 'reserved' value in the G.723.1
+ spec and should never occur in real media streams */
+ inbytes = G723_SID_BYTES;
+ break;
+ }
+ timestamp_inc = G723_SAMPLES;
+ }
+
+ zth->srclen -= inbytes;
+
+ {
+ unsigned char fifo[OTHER_CMD_LEN] = CMD_MSG_IP_UDP_RTP(
+ ((inbytes+40) >> 8) & 0xFF,
+ (inbytes+40) & 0xFF,
+ st->seqno & 0xFF,
+ 0x00,
+ 0x00,
+ (((st->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,
+ 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,
+ (st->ssrc) & 0xFF);
+
+ ipchksum = 0x9869 + (fifo[16] << 8) + fifo[17]
+ + (fifo[18] << 8) + fifo[19];
+ while (ipchksum >> 16)
+ ipchksum = (ipchksum & 0xFFFF) + (ipchksum >> 16);
+ ipchksum = (~ipchksum) & 0xFFFF;
+
+ fifo[24] = ipchksum >> 8;
+ fifo[25] = ipchksum & 0xFF;
+
+ st->seqno += 1;
+ st->timestamp += timestamp_inc;
+
+ for (i = 0; i < inbytes; i++)
+ fifo[i+CMD_MSG_IP_UDP_RTP_LEN]= chars[i];
+
+ down(&wc->cmdqsem);
+
+ 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;
+ }
+
+ __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_SID_BYTES)) );
+
+ } else {
+ zt_transcoder_alert(ztc);
+ }
+
+ res = 0;
+ break;
+ }
+ return res;
+}
+
+static void wcdte_stop_dma(struct wcdte *wc);
+
+static inline void wcdte_receiveprep(struct wcdte *wc, int dbl)
+{
+ volatile unsigned char *readchunk;
+ struct zt_transcoder_channel *ztc = NULL;
+ struct zt_transcode_header *zth = NULL;
+ struct dte_state *st = NULL;
+ int o2,i;
+ unsigned char rseq, rcodec;
+ unsigned int rcommand, rchannel, rlen, rtp_rseq, rtp_eseq;
+ unsigned char *chars = NULL;
+ unsigned int ztc_ndx;
+
+ readchunk = (volatile unsigned char *)wc->readchunk;
+ readchunk += dbl * SFRAME_SIZE;
+
+ o2 = dbl * 4;
+ o2 += ERING_SIZE * 4;
+
+ /* Control in packet */
+ if ((readchunk[12] == 0x88) && (readchunk[13] == 0x9B))
+ {
+ if (debug_packets)
+ {
+ printk("wcdte debug: RX: ");
+ for (i=0; i<debug_packets; i++)
+ printk("%02X ", readchunk[i]);
+ printk("\n");
+ }
+ /* See if message must be ACK'd */
+ if ((readchunk[17] & 0x80) == 0)
+ {
+ rcommand = readchunk[24] | (readchunk[25] << 8);
+ rchannel = readchunk[18] | (readchunk[19] << 8);
+ rseq = readchunk[16];
+
+ down(&wc->cmdqsem);
+ if ((readchunk[17] & 0x40) == 0) {
+ 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;
+ }
+
+ __transmit_demand(wc);
+ }
+
+ wc->rcvflags = RCV_CSMENCAPS;
+ if (rcommand == wc->last_command_sent) {
+ wc->last_rcommand = rcommand;
+ wc->last_rparm1 = readchunk[28] | (readchunk[29] << 8);
+ wake_up(&wc->regq);
+ } else {
+ if (debug)
+ printk("wcdte error: unexpected command response received (sent: %04X, received: %04X)\n", wc->last_command_sent, rcommand);
+ }
+ up(&wc->cmdqsem);
+ }
+ else
+ {
+ wc->last_rseqno = readchunk[16];
+ wc->rcvflags = RCV_CSMENCAPS_ACK;
+ if (!wc->dumping)
+ wake_up_interruptible(&wc->regq);
+ else
+ wake_up(&wc->regq);
+ }
+
+ if ((readchunk[22] == 0x75) && (readchunk[23] = 0xC1))
+ {
+ if (debug)
+ printk("wcdte error: received alert (0x%02X%02X) from dsp\n", readchunk[29], readchunk[28]);
+ if (debug_des) {
+ down(&wc->cmdqsem);
+ __dump_descriptors(wc);
+ up(&wc->cmdqsem);
+ }
+ }
+
+ if (wc->dumping && (readchunk[22] == 0x04) && (readchunk[23] = 0x14)) {
+ for (i = 27; i < 227; i++)
+ printk("%02X ", readchunk[i]);
+ printk("\n");
+ }
+ }
+
+ /* IP/UDP in packet */
+ else if ((readchunk[12] == 0x08) && (readchunk[13] == 0x00)
+ && (readchunk[50] == 0x12) && (readchunk[51] == 0x34) && (readchunk[52] = 0x56) && (readchunk[53] == 0x78))
+ {
+ 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);
+ rcodec = DTE_FORMAT_UNDEF;
+ }
+
+ if ((rcodec == 0x00) || (rcodec == 0x08)) /* ulaw or alaw (decoders) */
+ {
+ 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! (ztc_ndx = %d, ztc->chan_built = %d)\n", ztc_ndx, ztc->chan_built);
+ if (debug_des) {
+ down(&wc->cmdqsem);
+ __dump_descriptors(wc);
+ up(&wc->cmdqsem);
+ }
+ rcodec = DTE_FORMAT_UNDEF;
+ } else {
+ chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen);
+ st->packets_received++;
+ }
+
+ }
+
+ if ((rcodec == 0x04) || (rcodec == 0x12)) /* g.723 or g.729 (encoders) */
+ {
+ ztc = &(wc->uencode->channels[ztc_ndx]);
+ zth = ztc->tch;
+ st = ztc->pvt;
+
+ if (zth == NULL)
+ {
+ if (debug)
+ printk("wcdte error: Tried to put DTE data into a freed zth header! (ztc_ndx = %d, ztc->chan_built = %d)\n", ztc_ndx, ztc->chan_built);
+ if (debug_des) {
+ down(&wc->cmdqsem);
+ __dump_descriptors(wc);
+ up(&wc->cmdqsem);
+ }
+ rcodec = DTE_FORMAT_UNDEF;
+ } else {
+ chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen);
+ st->packets_received++;
+ }
+
+ }
+
+ if (st->dte_seqno_rcv == 0)
+ {
+ st->dte_seqno_rcv = 1;
+ st->last_dte_seqno = rtp_rseq;
+ } else {
+ rtp_eseq = (st->last_dte_seqno + 1) & 0xFFFF;
+ if ( (rtp_rseq != rtp_eseq) && debug )
+ printk("wcdte error: Bad seqno from DTE! [%04X][%d][%d][%d]\n", (readchunk[37] | (readchunk[36] << 8)), rchannel, rtp_rseq, st->last_dte_seqno);
+
+ st->last_dte_seqno = rtp_rseq;
+ }
+
+ if (rcodec == 0x00) /* ulaw */
+ {
+ if (zt_tc_sanitycheck(zth, rlen) && ((zth->srcfmt == ZT_FORMAT_G729A && rlen == G729_SAMPLES) || (zth->srcfmt == ZT_FORMAT_G723_1 && rlen == G723_SAMPLES))) {
+ for (i = 0; i < rlen; i++)
+ chars[i] = readchunk[i+54];
+
+ zth->dstlen += rlen;
+ zth->dstsamples = zth->dstlen;
+
+ } else {
+ ztc->errorstatus = -EOVERFLOW;
+ }
+ zt_transcoder_alert(ztc);
+ }
+ else if (rcodec == 0x08) /* alaw */
+ {
+ if (zt_tc_sanitycheck(zth, rlen) && ((zth->srcfmt == ZT_FORMAT_G729A && rlen == G729_SAMPLES) || (zth->srcfmt == ZT_FORMAT_G723_1 && rlen == G723_SAMPLES))) {
+
+ for (i = 0; i < rlen; i++)
+ chars[i] = readchunk[i+54];
+
+ zth->dstlen += rlen;
+ zth->dstsamples = zth->dstlen;
+
+ } else {
+ ztc->errorstatus = -EOVERFLOW;
+ }
+ zt_transcoder_alert(ztc);
+ }
+ else if (rcodec == 0x04) /* G.723.1 */
+ {
+ if (zt_tc_sanitycheck(zth, rlen) &&
+ ((rlen == G723_6K_BYTES) || (rlen == G723_5K_BYTES) || (rlen == G723_SID_BYTES)))
+ {
+ for (i = 0; i < rlen; i++)
+ chars[i] = readchunk[i+54];
+
+ zth->dstlen += rlen;
+ zth->dstsamples += G723_SAMPLES;
+
+ } else {
+ ztc->errorstatus = -EOVERFLOW;
+ }
+
+ if (!(zth->dstsamples % G723_SAMPLES))
+ {
+ zt_transcoder_alert(ztc);
+ }
+ }
+ else if (rcodec == 0x12) /* G.729a */
+ {
+ if (zt_tc_sanitycheck(zth, rlen) && (rlen == G729_BYTES))
+ {
+ for (i = 0; i < rlen; i++)
+ chars[i] = readchunk[i+54];
+
+ zth->dstlen += rlen;
+ zth->dstsamples = zth->dstlen * 8;
+
+ } else {
+ ztc->errorstatus = -EOVERFLOW;
+ }
+
+ if (!(zth->dstsamples % G729_SAMPLES))
+ {
+ zt_transcoder_alert(ztc);
+ }
+ }
+ }
+}
+
+
+
+
+
+/* static inline int wcdte_check_descriptor(struct wcdte *wc) */
+static int wcdte_check_descriptor(struct wcdte *wc)
+{
+ int o2 = 0;
+
+ o2 += ERING_SIZE * 4;
+ o2 += wc->rdbl * 4;
+
+ if (!(le32_to_cpu(wc->descripchunk[o2]) & 0x80000000)) {
+ wc->rxints++;
+ wcdte_receiveprep(wc, wc->rdbl);
+ wcdte_reinit_descriptor(wc, 0, wc->rdbl, "rxchk");
+ wc->rdbl = (wc->rdbl + 1) % ERING_SIZE;
+
+ return 1;
+ }
+ return 0;
+}
+
+static void wcdte_init_descriptors(struct wcdte *wc)
+{
+ volatile unsigned int *descrip;
+ dma_addr_t descripdma;
+ dma_addr_t writedma;
+ dma_addr_t readdma;
+ int x;
+
+ descrip = wc->descripchunk;
+ descripdma = wc->descripdma;
+ writedma = wc->writedma;
+ readdma = wc->readdma;
+
+ for (x=0;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;
+ }
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+static void dte_wque_run(struct work_struct *work)
+{
+ struct wcdte *wc = container_of(work, struct wcdte, dte_work);
+#else
+static void dte_wque_run(void *work_data)
+{
+ struct wcdte *wc = work_data;
+#endif
+ int res;
+
+ do {
+ res = wcdte_check_descriptor(wc);
+ } while(res);
+
+ transmit_demand(wc);
+}
+
+ZAP_IRQ_HANDLER(wcdte_interrupt)
+{
+ struct wcdte *wc = dev_id;
+ unsigned int ints;
+
+ /* Read and clear interrupts */
+ ints = wcdte_getctl(wc, 0x0028);
+ wcdte_setctl(wc, 0x0028, ints);
+
+ if (!ints)
+ return IRQ_NONE;
+ ints &= wc->intmask;
+
+ if (ints & 0x00000041) {
+ wc->wqueints = ints;
+ queue_work(wc->dte_wq, &wc->dte_work);
+ }
+
+ if ((ints & 0x00008000) && debug)
+ printk("wcdte: Abnormal Interrupt: ");
+
+ if ((ints & 0x00002000) && debug)
+ printk("wcdte: Fatal Bus Error INT\n");
+
+ if ((ints & 0x00000100) && debug)
+ printk("wcdte: Receive Stopped INT\n");
+
+ if ((ints & 0x00000080) && debug)
+ printk("wcdte: Receive Desciptor Unavailable INT\n");
+
+ if ((ints & 0x00000020) && debug)
+ printk("wcdte: Transmit Under-flow INT\n");
+
+ if ((ints & 0x00000008) && debug)
+ printk("wcdte: Jabber Timer Time-out INT\n");
+
+ if ((ints & 0x00000004) && debug)
+ printk("wcdte: Transmit Descriptor Unavailable INT\n");
+
+ if ((ints & 0x00000002) && debug)
+ printk("wcdte: Transmit Processor Stopped INT\n");
+
+ return IRQ_RETVAL(1);
+
+}
+
+static int wcdte_hardware_init(struct wcdte *wc)
+{
+ /* Hardware stuff */
+ unsigned int reg;
+ unsigned long newjiffies;
+
+ /* Initialize descriptors */
+ wcdte_init_descriptors(wc);
+
+ /* Enable I/O Access */
+ pci_read_config_dword(wc->dev, 0x0004, &reg);
+ reg |= 0x00000007;
+ pci_write_config_dword(wc->dev, 0x0004, reg);
+
+ wcdte_setctl(wc, 0x0000, 0xFFF88001);
+
+ newjiffies = jiffies + HZ/10;
+ while(((reg = wcdte_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies));
+
+ wcdte_setctl(wc, 0x0000, 0xFFFA0000);
+
+ /* Configure watchdogs, access, etc */
+ wcdte_setctl(wc, 0x0030, 0x00280048);
+ wcdte_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */);
+
+ reg = wcdte_getctl(wc, 0x00fc);
+ wcdte_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7);
+
+ reg = wcdte_getctl(wc, 0x00fc);
+
+ return 0;
+}
+
+static void wcdte_setintmask(struct wcdte *wc, unsigned int intmask)
+{
+ wc->intmask = intmask;
+ wcdte_setctl(wc, 0x0038, intmask);
+}
+
+static void wcdte_enable_interrupts(struct wcdte *wc)
+{
+ /* Enable interrupts */
+ if (!debug)
+ wcdte_setintmask(wc, 0x00010041);
+ else
+ wcdte_setintmask(wc, 0x0001A1EB);
+}
+
+static void wcdte_start_dma(struct wcdte *wc)
+{
+ unsigned int reg;
+ wmb();
+ wcdte_setctl(wc, 0x0020, wc->descripdma);
+ wcdte_setctl(wc, 0x0018, wc->descripdma + (16 * ERING_SIZE));
+ /* Start receiver/transmitter */
+ reg = wcdte_getctl(wc, 0x0030);
+ wcdte_setctl(wc, 0x0030, reg | 0x00002002); /* Start XMT and RCD */
+ wcdte_setctl(wc, 0x0010, 0x00000000); /* Receive Poll Demand */
+ reg = wcdte_getctl(wc, 0x0028);
+ wcdte_setctl(wc, 0x0028, reg);
+
+}
+
+static void wcdte_stop_dma(struct wcdte *wc)
+{
+ /* Disable interrupts and reset */
+ unsigned int reg;
+ /* Disable interrupts */
+ wcdte_setintmask(wc, 0x00000000);
+ wcdte_setctl(wc, 0x0084, 0x00000000);
+ wcdte_setctl(wc, 0x0048, 0x00000000);
+ /* Reset the part to be on the safe side */
+ reg = wcdte_getctl(wc, 0x0000);
+ reg |= 0x00000001;
+ wcdte_setctl(wc, 0x0000, reg);
+}
+
+static void wcdte_disable_interrupts(struct wcdte *wc)
+{
+ /* Disable interrupts */
+ wcdte_setintmask(wc, 0x00000000);
+ wcdte_setctl(wc, 0x0084, 0x00000000);
+}
+
+static int wcdte_waitfor_csmencaps(struct wcdte *wc, unsigned int mask, int wait_mode)
+{
+ int ret;
+
+
+ if (wait_mode == 1)
+ ret = wait_event_interruptible_timeout(wc->regq, (wc->rcvflags == mask), wc->timeout);
+ else if (wait_mode == 2)
+ ret = wait_event_timeout(wc->regq, (wc->rcvflags == mask), wc->timeout);
+ else {
+ if (!debug_notimeout) {
+ ret = wait_event_timeout(wc->regq, ((wc->last_rcommand == wc->last_command_sent) && (wc->last_seqno == wc->last_rseqno) && (wc->rcvflags == mask)), wc->timeout);
+ }
+ else {
+ ret = wait_event_interruptible(wc->regq, ((wc->last_rcommand == wc->last_command_sent) && (wc->last_seqno == wc->last_rseqno) && (wc->rcvflags == mask)));
+ if (ret == 0)
+ ret = 1;
+ }
+ }
+ wc->rcvflags = 0;
+ wc->last_rcommand = 0;
+ wc->last_seqno = 0;
+
+ if (ret < 0)
+ {
+ if (debug)
+ printk("wcdte error: Wait interrupted, need to stop boot (ret = %d)\n", ret);
+ return(1);
+ }
+ if (ret == 0)
+ {
+ if (debug)
+ printk("wcdte error: Waitfor CSMENCAPS response timed out (ret = %d) (cmd_snt = %04X)\n", ret, wc->last_command_sent);
+ if (debug_des) {
+ down(&wc->cmdqsem);
+ __dump_descriptors(wc);
+ up(&wc->cmdqsem);
+ }
+ return(2);
+ }
+ if (wait_mode == 0)
+ wc->last_command_sent = 999;
+ wc->last_rseqno = 999;
+ return(0);
+}
+
+
+static int wcdte_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--) {
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1);
+ wcdte_getctl(wc, mdio_addr);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
+ wcdte_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;
+
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval);
+ wcdte_getctl(wc, mdio_addr);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK);
+ wcdte_getctl(wc, mdio_addr);
+ }
+
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN);
+ wcdte_getctl(wc, mdio_addr);
+ retval = (retval << 1) | ((wcdte_getctl(wc, mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
+ wcdte_getctl(wc, mdio_addr);
+ }
+ retval = (retval>>1) & 0xffff;
+ return retval;
+}
+
+void wcdte_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--) {
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1);
+ wcdte_getctl(wc, mdio_addr);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
+ wcdte_getctl(wc, mdio_addr);
+ }
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval);
+ wcdte_getctl(wc, mdio_addr);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK);
+ wcdte_getctl(wc, mdio_addr);
+ }
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN);
+ wcdte_getctl(wc, mdio_addr);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
+ wcdte_getctl(wc, mdio_addr);
+ }
+ return;
+}
+
+static int wcdte_boot_processor(struct wcdte *wc, const struct firmware *firmware, int full)
+{
+ int i, j, byteloc, last_byteloc, length, delay_count;
+ unsigned int reg, ret;
+
+#ifndef USE_TEST_HW
+ /* Turn off auto negotiation */
+ wcdte_write_phy(wc, 0, 0x2100);
+ if (debug)
+ printk("wcdte: PHY register 0 = %X", wcdte_read_phy(wc, 0));
+
+ /* Set reset */
+ wcdte_setctl(wc, 0x00A0, 0x04000000);
+
+ /* Wait 1000msec to ensure processor reset */
+ mdelay(4);
+
+ /* Clear reset */
+ wcdte_setctl(wc, 0x00A0, 0x04080000);
+
+ /* Waitfor ethernet link */
+ delay_count = 0;
+ do
+ {
+ reg = wcdte_getctl(wc, 0x00fc);
+ mdelay(2);
+ delay_count++;
+
+ if (delay_count >= 5000)
+ {
+ printk("wcdte error: Failed to link to DTE processor!\n");
+ return(1);
+ }
+ } while ((reg & 0xE0000000) != 0xE0000000);
+
+
+ /* Turn off booted LED */
+ wcdte_setctl(wc, 0x00A0, 0x04084000);
+
+
+#endif
+
+ reg = wcdte_getctl(wc, 0x00fc);
+ if (debug)
+ printk("wcdte: LINK STATUS: reg(0xfc) = %X\n", reg);
+
+ reg = wcdte_getctl(wc, 0x00A0);
+
+ byteloc = 17;
+ j = 0;
+ do
+ {
+ last_byteloc = byteloc;
+
+ length = (firmware->data[byteloc] << 8) |firmware->data[byteloc+1];
+ byteloc += 2;
+
+ down(&wc->cmdqsem);
+ if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug )
+ printk("wcdte error: cmdq is full.\n");
+ else
+ {
+ wc->cmdq[wc->cmdq_wndx].cmdlen = length;
+ for (i = 0; i < length; i++)
+ wc->cmdq[wc->cmdq_wndx].cmd[i] = firmware->data[byteloc++];
+ wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS;
+ }
+
+ ret = __transmit_demand(wc);
+ up(&wc->cmdqsem);
+
+ ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS_ACK, 1);
+ if (ret == 1)
+ return(1);
+ else if (ret == 2) /* Retransmit if dte processor times out */
+ byteloc = last_byteloc;
+ j++;
+
+ if (!full && (byteloc > 189)) { /* Quit if not fully booting */
+ wcdte_setctl(wc, 0x00A0, 0x04080000);
+ return 0;
+ }
+
+
+ } while (byteloc < firmware->size-20);
+ wc->timeout = 10 * HZ;
+ wc->last_command_sent = 0;
+ if (wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 1))
+ return(1);
+
+ /* Turn on booted LED */
+ wcdte_setctl(wc, 0x00A0, 0x04080000);
+ if(debug)
+ printk("wcdte: Successfully booted DTE processor.\n");
+
+ return(0);
+}
+
+static int wcdte_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;
+ struct zt_transcoder_channel *ztc1, *ztc2;
+ struct dte_state *st1, *st2;
+ if(complicated == DTE_FORMAT_G729A)
+ length = G729_LENGTH;
+ else if (complicated == DTE_FORMAT_G723_1)
+ length = G723_LENGTH;
+
+ /* Create complex channel */
+ zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part1_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010);
+ zt_send_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part1_id), CMD_MSG_QUERY_CHANNEL_LEN, 0x0010);
+ chan1 = wc->last_rparm1;
+
+ /* Create simple channel */
+ zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010);
+ zt_send_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_QUERY_CHANNEL_LEN, 0x0010);
+ chan2 = wc->last_rparm1;
+
+ ztc1 = &(wc->uencode->channels[part1_id/2]);
+ ztc2 = &(wc->udecode->channels[part2_id/2]);
+ st1 = ztc1->pvt;
+ st2 = ztc2->pvt;
+
+ /* Configure complex channel */
+ zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(st1->cmd_seqno++, chan1, part2_id, part1_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st1->cmd_seqno++, chan1, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001);
+
+ /* Configure simple channel */
+ zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(st2->cmd_seqno++, chan2, part1_id, part2_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st2->cmd_seqno++, chan2, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001);
+
+#ifdef QUIET_DSP
+ zt_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_TONECTL_LEN, 0x805B);
+ zt_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002);
+ zt_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_TONECTL_LEN, 0x805B);
+ zt_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002);
+ zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084);
+ zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084);
+#endif
+
+ zt_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 1, chan1, chan2, complicated, simple), CMD_MSG_TRANS_CONNECT_LEN, 0x9322);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(st1->cmd_seqno++, chan1, complicated), CMD_MSG_VOIP_VOPENA_LEN, 0x8000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(st2->cmd_seqno++, chan2, simple), CMD_MSG_VOIP_VOPENA_LEN, 0x8000);
+
+ *dte_chan1 = chan1;
+ *dte_chan2 = chan2;
+
+ return 1;
+}
+
+static int wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2)
+{
+ struct zt_transcoder_channel *ztc1, *ztc2;
+ struct dte_state *st1, *st2;
+
+ ztc1 = &(wc->uencode->channels[chan1/2]);
+ ztc2 = &(wc->udecode->channels[chan2/2]);
+ st1 = ztc1->pvt;
+ st2 = ztc2->pvt;
+
+ /* Turn off both channels */
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000);
+
+ /* Disconnect the channels */
+ zt_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 0, chan1, chan2, 0, 0), CMD_MSG_TRANS_CONNECT_LEN, 0x9322);
+
+ /* Remove the channels */
+ zt_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan1), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011);
+ zt_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan2), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011);
+
+ return 1;
+}
+
+
+static int __wcdte_setup_channels(struct wcdte *wc)
+{
+ wc->seq_num = 6;
+
+#ifndef USE_TEST_HW
+ zt_send_cmd(wc, CMD_MSG_SET_ARM_CLK(wc->seq_num++), CMD_MSG_SET_ARM_CLK_LEN, 0x0411);
+ zt_send_cmd(wc, CMD_MSG_SET_SPU_CLK(wc->seq_num++), CMD_MSG_SET_SPU_CLK_LEN, 0x0412);
+#endif
+
+#ifdef USE_TDM_CONFIG
+ zt_send_cmd(wc, CMD_MSG_TDM_SELECT_BUS_MODE(wc->seq_num++), CMD_MSG_TDM_SELECT_BUS_MODE_LEN, 0x0417);
+ zt_send_cmd(wc, CMD_MSG_TDM_ENABLE_BUS(wc->seq_num++), CMD_MSG_TDM_ENABLE_BUS_LEN, 0x0405);
+ zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x03, 0x20, 0x00), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
+ zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x04, 0x80, 0x04), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
+ zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x05, 0x20, 0x08), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
+ zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x06, 0x80, 0x0C), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
+#endif
+
+ zt_send_cmd(wc, CMD_MSG_SET_ETH_HEADER(wc->seq_num++), CMD_MSG_SET_ETH_HEADER_LEN, 0x0100);
+ zt_send_cmd(wc, CMD_MSG_IP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_IP_SERVICE_CONFIG_LEN, 0x0302);
+ zt_send_cmd(wc, CMD_MSG_ARP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_ARP_SERVICE_CONFIG_LEN, 0x0105);
+ zt_send_cmd(wc, CMD_MSG_ICMP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_ICMP_SERVICE_CONFIG_LEN, 0x0304);
+
+#ifdef USE_TDM_CONFIG
+ zt_send_cmd(wc, CMD_MSG_DEVICE_SET_COUNTRY_CODE(wc->seq_num++), CMD_MSG_DEVICE_SET_COUNTRY_CODE_LEN, 0x041B);
+#endif
+
+ zt_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x02), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013);
+ zt_send_cmd(wc, CMD_MSG_IP_OPTIONS(wc->seq_num++), CMD_MSG_IP_OPTIONS_LEN, 0x0306);
+ zt_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x04), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013);
+
+#ifdef USE_TDM_CONFIG
+ zt_send_cmd(wc, CMD_MSG_TDM_OPT(wc->seq_num++), CMD_MSG_TDM_OPT_LEN, 0x0435);
+#endif
+
+ wc->timeout = HZ/10 + 1; /* 100msec */
+
+ return(0);
+}
+
+static int wcdte_setup_channels(struct wcdte *wc)
+{
+ down(&wc->chansem);
+ __wcdte_setup_channels(wc);
+ up(&wc->chansem);
+
+ return 0;
+}
+
+static int __devinit wcdte_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int res, reg;
+ struct wcdte *wc;
+ struct wcdte_desc *d = (struct wcdte_desc *)ent->driver_data;
+ int x;
+ static int initd_ifaces=0;
+ unsigned char g729_numchannels, g723_numchannels, min_numchannels, dte_firmware_ver, dte_firmware_ver_minor;
+ unsigned int complexfmts;
+
+ struct firmware embedded_firmware;
+ const struct firmware *firmware = &embedded_firmware;
+#if !defined(HOTPLUG_FIRMWARE)
+ extern void _binary_zaptel_fw_tc400m_bin_size;
+ extern u8 _binary_zaptel_fw_tc400m_bin_start[];
+#else
+ static const char tc400m_firmware[] = "zaptel-fw-tc400m.bin";
+#endif
+
+ if (!initd_ifaces) {
+ memset((void *)ifaces,0,(sizeof(struct wcdte *))*WC_MAX_IFACES);
+ initd_ifaces=1;
+ }
+ for (x=0;x<WC_MAX_IFACES;x++)
+ if (!ifaces[x]) break;
+ if (x >= WC_MAX_IFACES) {
+ printk("wcdte: Too many interfaces\n");
+ return -EIO;
+ }
+
+ if (pci_enable_device(pdev)) {
+ res = -EIO;
+ } else {
+
+ wc = vmalloc(sizeof(struct wcdte));
+ if (wc) {
+ ifaces[x] = wc;
+ memset(wc, 0, sizeof(struct wcdte));
+ spin_lock_init(&wc->reglock);
+ sema_init(&wc->chansem, 1);
+ sema_init(&wc->cmdqsem, 1);
+ wc->cards = NUM_CARDS;
+ wc->iobase = pci_resource_start(pdev, 0);
+ wc->dev = pdev;
+ wc->pos = x;
+ wc->variety = d->name;
+
+ wc->tdbl = 0;
+ wc->rdbl = 0;
+ wc->rcvflags = 0;
+ wc->last_seqno = 999;
+ wc->last_command_sent = 0;
+ wc->last_rcommand = 0;
+ wc->last_rparm1 = 0;
+ wc->cmdq_wndx = 0;
+ wc->cmdq_rndx = 0;
+ wc->seq_num = 6;
+ wc->timeout = 1 * HZ; /* 1 sec */
+ wc->dsp_crashed = 0;
+ wc->dumping = 0;
+ wc->ztsnd_rtx = 0;
+ wc->ztsnd_0010_rtx = 0;
+
+ /* Keep track of whether we need to free the region */
+ if (request_region(wc->iobase, 0xff, "wcdte"))
+ wc->freeregion = 1;
+
+ /* Allocate enought memory for all TX buffers, RX buffers, and descriptors */
+ wc->writechunk = (int *)pci_alloc_consistent(pdev, PCI_WINDOW_SIZE, &wc->writedma);
+ if (!wc->writechunk) {
+ printk("wcdte error: Unable to allocate DMA-able memory\n");
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ return -ENOMEM;
+ }
+
+ wc->readchunk = wc->writechunk + (SFRAME_SIZE * ERING_SIZE) / 4; /* in doublewords */
+ wc->readdma = wc->writedma + (SFRAME_SIZE * ERING_SIZE); /* in bytes */
+
+ wc->descripchunk = wc->readchunk + (SFRAME_SIZE * ERING_SIZE) / 4; /* in doublewords */
+ wc->descripdma = wc->readdma + (SFRAME_SIZE * ERING_SIZE); /* in bytes */
+
+ /* Initialize Write/Buffers to all blank data */
+ memset((void *)wc->writechunk,0x00, SFRAME_SIZE * 2);
+ memset((void *)wc->readchunk, 0x00, SFRAME_SIZE * 2);
+
+ init_waitqueue_head(&wc->regq);
+
+ /* Initialize the work queue */
+ wc->dte_wq = create_singlethread_workqueue("tc400b");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+ INIT_WORK(&wc->dte_work, dte_wque_run);
+#else
+ INIT_WORK(&wc->dte_work, dte_wque_run, wc);
+#endif
+
+#if defined(HOTPLUG_FIRMWARE)
+ if ((request_firmware(&firmware, tc400m_firmware, &wc->dev->dev) != 0) ||
+ !firmware) {
+ printk("TC400M: firmware %s not available from userspace\n", tc400m_firmware);
+ return -EIO;
+ }
+#else
+ embedded_firmware.data = _binary_zaptel_fw_tc400m_bin_start;
+ embedded_firmware.size = (size_t) &_binary_zaptel_fw_tc400m_bin_size;
+#endif
+
+ dte_firmware_ver = firmware->data[0];
+ dte_firmware_ver_minor = firmware->data[16];
+ g729_numchannels = firmware->data[1];
+ g723_numchannels = firmware->data[2];
+
+ if (g723_numchannels < g729_numchannels)
+ min_numchannels = g723_numchannels;
+ else
+ min_numchannels = g729_numchannels;
+
+ /* Setup Encoders and Decoders */
+
+ if (!mode || strlen(mode) < 4) {
+ sprintf(wc->complexname, "G.729a / G.723.1");
+ complexfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1;
+ wc->numchannels = min_numchannels;
+ } else if (mode[3] == '9') { /* "G.729" */
+ sprintf(wc->complexname, "G.729a");
+ complexfmts = ZT_FORMAT_G729A;
+ wc->numchannels = g729_numchannels;
+ } else if (mode[3] == '3') { /* "G.723.1" */
+ sprintf(wc->complexname, "G.723.1");
+ complexfmts = ZT_FORMAT_G723_1;
+ wc->numchannels = g723_numchannels;
+ } else {
+ sprintf(wc->complexname, "G.729a / G.723.1");
+ complexfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1;
+ wc->numchannels = min_numchannels;
+ }
+
+ uencode = zt_transcoder_alloc(wc->numchannels);
+ udecode = zt_transcoder_alloc(wc->numchannels);
+ encoders = vmalloc(sizeof(struct dte_state) * wc->numchannels);
+ decoders = vmalloc(sizeof(struct dte_state) * wc->numchannels);
+ memset(encoders, 0, sizeof(struct dte_state) * wc->numchannels);
+ memset(decoders, 0, sizeof(struct dte_state) * wc->numchannels);
+ if (!uencode || !udecode || !encoders || !decoders) {
+ if (uencode)
+ zt_transcoder_free(uencode);
+ if (udecode)
+ zt_transcoder_free(udecode);
+ if (encoders)
+ vfree(encoders);
+ if (decoders)
+ vfree(decoders);
+ return -ENOMEM;
+ }
+ sprintf(udecode->name, "DTE Decoder");
+ sprintf(uencode->name, "DTE Encoder");
+
+ udecode->srcfmts = uencode->dstfmts = complexfmts;
+ udecode->dstfmts = uencode->srcfmts = ZT_FORMAT_ULAW | ZT_FORMAT_ALAW;
+
+ udecode->operation = uencode->operation = dte_operation;
+
+ for (x=0;x<wc->numchannels;x++) {
+ dte_init_state(encoders + x, 1, x, wc);
+ encoders[x].encoder = 1;
+ decoders[x].encoder = 0;
+ dte_init_state(decoders + x, 0, x, wc);
+ uencode->channels[x].pvt = encoders + x;
+ udecode->channels[x].pvt = decoders + x;
+ }
+
+ wc->uencode = uencode;
+ wc->udecode = udecode;
+
+ zt_transcoder_register(uencode);
+ zt_transcoder_register(udecode);
+
+ printk("Zaptel DTE (%s) Transcoder support LOADED (firm ver = %d.%d)\n", wc->complexname, dte_firmware_ver, dte_firmware_ver_minor);
+
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, wc);
+
+ if (request_irq(pdev->irq, wcdte_interrupt, ZAP_IRQ_SHARED, "tc400b", wc)) {
+ printk("wcdte error: Unable to request IRQ %d\n", pdev->irq);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ vfree(wc);
+ return -EIO;
+ }
+
+
+ if (wcdte_hardware_init(wc)) {
+ /* Set Reset Low */
+ wcdte_stop_dma(wc);
+ /* Free Resources */
+ free_irq(pdev->irq, wc);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ vfree(wc);
+ return -EIO;
+
+ }
+
+ /* Enable interrupts */
+ wcdte_enable_interrupts(wc);
+
+ /* Start DMA */
+ wcdte_start_dma(wc);
+
+ if (wcdte_boot_processor(wc,firmware,1)) {
+ if (firmware != &embedded_firmware)
+ release_firmware(firmware);
+
+ /* Set Reset Low */
+ wcdte_stop_dma(wc);
+ /* Free Resources */
+ free_irq(pdev->irq, wc);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ vfree(wc);
+ return -EIO;
+ }
+ if (firmware != &embedded_firmware)
+ release_firmware(firmware);
+
+ if (wcdte_setup_channels(wc)) {
+ /* Set Reset Low */
+ wcdte_stop_dma(wc);
+ /* Free Resources */
+ free_irq(pdev->irq, wc);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ vfree(wc);
+ return -EIO;
+ }
+
+ reg = wcdte_getctl(wc, 0x00fc);
+ if (debug)
+ printk("wcdte debug: (post-boot) Reg fc is %08x\n", reg);
+
+ printk("Found and successfully installed a Wildcard TC: %s \n", wc->variety);
+ if (debug) {
+ printk("TC400B operating in DEBUG mode\n");
+ printk("debug_des = %d, debug_des_cnt = %d, force_alert = %d,\n debug_notimeout = %d, debug_packets = %d\n",
+ debug_des, debug_des_cnt, force_alert, debug_notimeout, debug_packets);
+ }
+ res = 0;
+ } else
+ res = -ENOMEM;
+ }
+ return res;
+}
+
+static void wcdte_release(struct wcdte *wc)
+{
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ vfree(wc);
+}
+
+static void __devexit wcdte_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) {
+ if (debug)
+ {
+ printk("wcdte debug: wc->ztsnd_rtx = %d\n", wc->ztsnd_rtx);
+ printk("wcdte debug: 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;
+
+ printk("wcdte debug: 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);
+ printk("wcdte debug: 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);
+ }
+ }
+
+ zt_transcoder_unregister(wc->udecode);
+ zt_transcoder_unregister(wc->uencode);
+ zt_transcoder_free(wc->uencode);
+ zt_transcoder_free(wc->udecode);
+ vfree(wc->uencode->channels[0].pvt);
+ vfree(wc->udecode->channels[0].pvt);
+
+ /* Stop any DMA */
+ wcdte_stop_dma(wc);
+
+ /* In case hardware is still there */
+ wcdte_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);
+
+ /* Release span, possibly delayed */
+ wcdte_release(wc);
+ }
+}
+
+static struct pci_device_id wcdte_pci_tbl[] = {
+#ifndef USE_TEST_HW
+ { 0xd161, 0x3400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctc400p }, /* Digium board */
+ { 0xd161, 0x8004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctce400 }, /* Digium board */
+#else
+ { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctc400p }, /* reference board */
+#endif
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, wcdte_pci_tbl);
+
+static struct pci_driver wcdte_driver = {
+ name: "wctc4xxp",
+ probe: wcdte_init_one,
+ remove: __devexit_p(wcdte_remove_one),
+ suspend: NULL,
+ resume: NULL,
+ id_table: wcdte_pci_tbl,
+};
+
+int ztdte_init(void)
+{
+ int res;
+
+ res = zap_pci_module(&wcdte_driver);
+ if (res)
+ return -ENODEV;
+ return 0;
+}
+
+void ztdte_cleanup(void)
+{
+ pci_unregister_driver(&wcdte_driver);
+}
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+module_param(debug_des, int, S_IRUGO | S_IWUSR);
+module_param(debug_des_cnt, int, S_IRUGO | S_IWUSR);
+module_param(debug_notimeout, int, S_IRUGO | S_IWUSR);
+module_param(force_alert, int, S_IRUGO | S_IWUSR);
+module_param(mode, charp, S_IRUGO | S_IWUSR);
+MODULE_DESCRIPTION("Wildcard TC400P+TC400M Driver");
+MODULE_AUTHOR("John Sloan <jsloan@digium.com>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(ztdte_init);
+module_exit(ztdte_cleanup);
diff --git a/kernel/wctc4xxp/codec_test.c b/kernel/wctc4xxp/codec_test.c
new file mode 100644
index 0000000..287979d
--- /dev/null
+++ b/kernel/wctc4xxp/codec_test.c
@@ -0,0 +1,332 @@
+/*
+ * Wilcard TC400B Digium Transcoder Engine Interface Driver for Zapata Telephony interface test tool.
+ *
+ * Written by Matt O'Gorman <mogorman@digium.com>
+ *
+ * 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 <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <linux/zaptel.h>
+#endif
+
+#define MAX_CARDS_TO_TEST 6
+#define MAX_CHANNELS_PER_CARD 96
+
+#define AST_FORMAT_ULAW (1 << 2)
+#define AST_FORMAT_G729A (1 << 8)
+
+#define AST_FRIENDLY_OFFSET 64
+
+static int debug = 0;
+
+static unsigned char ulaw_slin_ex[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static unsigned char g729a_expected[] = {
+ 0xE9, 0x88, 0x4C, 0xA0, 0x00, 0xFA, 0xDD, 0xA2, 0x06, 0x2D,
+ 0x69, 0x88, 0x00, 0x60, 0x68, 0xD5, 0x9E, 0x20, 0x80, 0x50
+};
+
+
+struct format_map {
+ unsigned int map[32][32];
+};
+
+
+struct tcpvt {
+ int fd;
+ int fake;
+ int inuse;
+ struct zt_transcode_header *hdr;
+// struct ast_frame f;
+};
+
+struct tctest_info {
+ int numcards;
+ int numchans[MAX_CARDS_TO_TEST];
+ int total_chans;
+ int errors;
+ int overcnt_error; /* Too many cards found */
+ int undercnt_error; /* Too few cards found */
+ int timeout_error[MAX_CARDS_TO_TEST];
+ int data_error[MAX_CARDS_TO_TEST];
+ int numcards_werrors;
+};
+
+
+static int find_transcoders(struct tctest_info *tctest_info)
+{
+ struct zt_transcode_info info = { 0, };
+ int fd, res;
+
+ if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) {
+ printf("Warning: No Zaptel transcoder support!\n");
+ return 0;
+ }
+
+ tctest_info->total_chans = 0;
+ info.op = ZT_TCOP_GETINFO;
+ for (info.tcnum = 0; !(res = ioctl(fd, ZT_TRANSCODE_OP, &info)); info.tcnum++) {
+ if (debug)
+ printf("Found transcoder %d, '%s' with %d channels.\n", info.tcnum, info.name, info.numchannels);
+ if ((info.tcnum % 2) == 0)
+ {
+ tctest_info->numchans[info.tcnum/2] = info.numchannels;
+ tctest_info->total_chans += info.numchannels;
+ }
+ }
+ tctest_info->numcards = info.tcnum / 2;
+
+ close(fd);
+ if (!info.tcnum)
+ printf("No hardware transcoders found.\n");
+ return 0;
+}
+
+
+static int open_transcoder(struct tcpvt *ztp, int dest, int source)
+{
+ int fd;
+ unsigned int x = ZT_TCOP_ALLOCATE;
+ struct zt_transcode_header *hdr;
+ int flags;
+
+ if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0)
+ return -1;
+ flags = fcntl(fd, F_GETFL);
+ if (flags > - 1) {
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
+ printf("Could not set non-block mode!\n");
+ }
+
+ if ((hdr = mmap(NULL, sizeof(*hdr), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+ printf("Memory Map failed for transcoding (%s)\n", strerror(errno));
+ close(fd);
+
+ return -1;
+ }
+
+ if (hdr->magic != ZT_TRANSCODE_MAGIC) {
+ printf("Transcoder header (%08x) wasn't magic. Abandoning\n", hdr->magic);
+ munmap(hdr, sizeof(*hdr));
+ close(fd);
+
+ return -1;
+ }
+
+ hdr->srcfmt = source;
+ hdr->dstfmt = dest;
+
+ if (ioctl(fd, ZT_TRANSCODE_OP, &x)) {
+ printf("Unable to attach transcoder: %s\n", strerror(errno));
+ munmap(hdr, sizeof(*hdr));
+ close(fd);
+
+ return -1;
+ }
+
+ ztp->fd = fd;
+ ztp->hdr = hdr;
+
+ return 0;
+}
+
+
+static void close_transcoder(struct tcpvt *ztp)
+{
+ unsigned int x;
+
+ x = ZT_TCOP_RELEASE;
+ if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x))
+ printf("Failed to release transcoder channel: %s\n", strerror(errno));
+
+ munmap(ztp->hdr, sizeof(*ztp->hdr));
+ close(ztp->fd);
+}
+
+
+static int encode_packet(struct tcpvt *ztp, unsigned char *packet_in, unsigned char *packet_out)
+{
+ struct zt_transcode_header *hdr = ztp->hdr;
+ unsigned int x;
+
+ hdr->srcoffset = 0;
+
+ memcpy(hdr->srcdata + hdr->srcoffset + hdr->srclen, packet_in, 160);
+ hdr->srclen += 160;
+
+
+ hdr->dstoffset = AST_FRIENDLY_OFFSET;
+ x = ZT_TCOP_TRANSCODE;
+ if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x))
+ printf("Failed to transcode: %s\n", strerror(errno));
+
+ usleep(20000);
+ if (hdr->dstlen)
+ {
+ memcpy(packet_out, hdr->dstdata + hdr->dstoffset, hdr->dstlen);
+ return 0;
+ }
+ else
+ return -1;
+}
+
+
+static void print_failed()
+{
+ printf("______ ___ _____ _ _____ ______\n");
+ printf("| ___| / _ \\ |_ _| | | | ___| | _ \\\n");
+ printf("| |_ / /_\\ \\ | | | | | |__ | | | |\n");
+ printf("| _| | _ | | | | | | __| | | | |\n");
+ printf("| | | | | | _| |_ | |____ | |___ | |/ /\n");
+ printf("\\_| \\_| |_/ \\___/ \\_____/ \\____/ |___/ \n");
+}
+
+
+int main(int argc, char *argv[])
+{
+ int arg1, arg2, i, j, card_testing, chan_testing;
+ struct tcpvt ztp[MAX_CHANNELS_PER_CARD * MAX_CARDS_TO_TEST];
+ unsigned char packet_out[200];
+ struct tctest_info tctest_info;
+
+ memset(&tctest_info, 0, sizeof(tctest_info));
+
+ if ((argc < 2) || (argc > 3))
+ {
+ printf("codec_test requires one argument.\n");
+ printf(" arg1 = number of cards to test\n");
+ return -1;
+ }
+
+ if (argc == 2)
+ sscanf(argv[1], "%d", &arg1);
+ else if (argc == 3)
+ {
+ sscanf(argv[1], "%d %d", &arg1, &arg2);
+ debug = arg2;
+ }
+
+ printf("Beginning test of %d TC400B cards\n", arg1);
+
+
+ /* Search for TC400Bs */
+ find_transcoders(&tctest_info);
+
+ if (tctest_info.numcards > arg1)
+ {
+ tctest_info.errors++;
+ tctest_info.overcnt_error = 1;
+ }
+ if (tctest_info.numcards < arg1)
+ {
+ tctest_info.errors++;
+ tctest_info.undercnt_error = 1;
+ }
+
+ if (tctest_info.errors == 0)
+ {
+ /* Begin testing transcoder channels */
+ for (card_testing = 0; card_testing < tctest_info.numcards; card_testing++)
+ {
+ tctest_info.data_error[card_testing] = 0;
+ tctest_info.timeout_error[card_testing] = 0;
+ for (chan_testing = 0; chan_testing < tctest_info.numchans[card_testing]; chan_testing++)
+ {
+ i = chan_testing;
+ for(j = 0; j < card_testing; j++)
+ i += tctest_info.numchans[j];
+
+ open_transcoder(&ztp[i], AST_FORMAT_G729A, AST_FORMAT_ULAW);
+
+ if ((tctest_info.timeout_error[card_testing] = encode_packet(&ztp[i], ulaw_slin_ex, packet_out) == -1))
+ tctest_info.errors++;
+
+ if (memcmp(g729a_expected, packet_out, 20) != 0)
+ {
+ tctest_info.errors++;
+ tctest_info.data_error[card_testing] += 1;
+ }
+ }
+ if ( (tctest_info.data_error[card_testing]) || (tctest_info.timeout_error[card_testing]) )
+ tctest_info.numcards_werrors++;
+ }
+
+ for (i = 0; i < tctest_info.total_chans; i++)
+ close_transcoder(&ztp[i]);
+ }
+
+ if (debug)
+ {
+ printf("\n\n");
+ printf("tctest_info.errors = %d\n", tctest_info.errors);
+ printf("tctest_info.overcnt_error = %d\n", tctest_info.overcnt_error);
+ printf("tctest_info.undercnt_error = %d\n", tctest_info.undercnt_error);
+ printf("tctest_info.numcards_werrors = %d\n", tctest_info.numcards_werrors);
+
+ for (i = 0; i < tctest_info.numcards; i++)
+ {
+ printf("tctest_info.data_error[%d] = %d\n", i, tctest_info.data_error[i]);
+ printf("tctest_info.timeout_error[%d] = %d\n", i, tctest_info.timeout_error[i]);
+ }
+ }
+
+ if (tctest_info.errors)
+ {
+ printf("\n\n\n");
+ if (tctest_info.numcards_werrors)
+ printf("%d of %d cards\n", tctest_info.numcards_werrors, tctest_info.numcards);
+ print_failed();
+ if (tctest_info.overcnt_error)
+ printf("\n%d cards found, %d expected\n", tctest_info.numcards, arg1);
+ if (tctest_info.undercnt_error)
+ printf("\n%d cards found, %d expected\n", tctest_info.numcards, arg1);
+ printf("\n\n\n");
+ }
+ else
+ printf("%d of %d cards PASSED\n", tctest_info.numcards - tctest_info.numcards_werrors, tctest_info.numcards);
+
+ return 0;
+}