summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-02-23 23:57:10 +0000
committerkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-02-23 23:57:10 +0000
commitdf1e7f7b0470bd759c9687eeffdcbeee02778008 (patch)
treefbd777063821d50d81aeb1ed0999f4eb6cfd1671
parente30d85766ea8d6b623f0964cbf8129c6c7700462 (diff)
partial update to support all the stuff that went into Zaptel 1.2 recently... this definitely still broken for 2.4 kernels, and maybe for 2.6 as well :-)
includes: Makefile split and reorganize TE120P driver TC400B driver HPEC support (not yet complete) git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@2215 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rw-r--r--Makefile369
-rw-r--r--Makefile.kernel2615
-rw-r--r--datamods/Makefile4
-rw-r--r--firmware/firmware.xml9
-rw-r--r--hpec/hpec.h47
-rw-r--r--hpec/hpec_user.h40
-rw-r--r--hpec/hpec_zaptel.h137
-rw-r--r--wct4xxp/Makefile2
-rw-r--r--wct4xxp/Makefile.kernel26 (renamed from wct4xxp/Kbuild)0
-rw-r--r--wctc4xxp/Makefile13
-rw-r--r--wctc4xxp/Makefile.kernel2615
-rw-r--r--wctc4xxp/base.c1813
-rw-r--r--wctc4xxp/codec_test.c332
-rw-r--r--wctc4xxp/tc400m-firmware.binbin0 -> 1400630 bytes
-rw-r--r--wcte12xp.c2046
-rw-r--r--zaptel-base.c (renamed from zaptel.c)0
-rw-r--r--zaptel.h48
-rw-r--r--zaptel.xml20
-rw-r--r--zttranscode.c36
19 files changed, 4711 insertions, 235 deletions
diff --git a/Makefile b/Makefile
index 5fa0388..f3b0add 100644
--- a/Makefile
+++ b/Makefile
@@ -1,21 +1,22 @@
#
# Makefile for Zaptel driver modules and utilities
#
-# Copyright (C) 2001-2006 Digium, Inc.
+# Copyright (C) 2001-2007 Digium, Inc.
#
#
-.EXPORT_ALL_VARIABLES:
-
-.PHONY: menuselect distclean dist-clean clean version.h all _all install b410p devices programs modules linux24 linux26 xpp tests devel data stackcheck install-udev config update install-programs install-modules install-linux24 install-linux26 firmware install-include install-libs xpp-install xpp-utils
+CFLAGS+=-DSTANDALONE_ZAPATA -DBUILDING_TONEZONE
-PWD=$(shell pwd)
+ifeq ($(MAKELEVEL),0)
+PWD:=$(shell pwd)
+endif
ifeq ($(DEB_HOST_GNU_TYPE),)
UNAME_M:=$(shell uname -m)
else
UNAME_M:=$(DEB_HOST_GNU_TYPE)
endif
+
# If you want to build for a kernel other than the current kernel, set KVERS
ifndef KVERS
KVERS:=$(shell uname -r)
@@ -31,6 +32,85 @@ endif
KVERS_MAJ:=$(shell echo $(KVERS) | cut -d. -f1-2)
KINCLUDES:=$(KSRC)/include
+ifeq ($(KVERS_MAJ),2.4)
+ BUILDVER:=linux24
+else
+ BUILDVER:=linux26
+endif
+
+# Set HOTPLUG_FIRMWARE=no to override automatic building with hotplug support
+# if it is enabled in the kernel.
+ifeq ($(BUILDVER),linux26)
+ ifneq (,$(wildcard $(INSTALL_PREFIX)/etc/udev/rules.d))
+ DYNFS=yes
+ UDEVRULES=yes
+ endif
+ HOTPLUG_FIRMWARE:=$(shell if grep CONFIG_FW_LOADER $(KINCLUDES)/linux/autoconf.h | grep -q undef; then echo "no"; else echo "yes"; fi)
+endif
+
+ifeq ($(HOTPLUG_FIRMWARE),yes)
+ CFLAGS+=-DHOTPLUG_FIRMWARE
+endif
+
+ifeq ($(ARCH),i386)
+ifneq ($(wildcard $(PWD)/hpec/hpec_x86_32.o_shipped),)
+HPEC_PRESENT=yes
+endif
+endif
+
+ifeq ($(ARCH),x86_64)
+ifneq ($(wildcard $(PWD)/hpec/hpec_x86_64.o_shipped),)
+HPEC_PRESENT=yes
+endif
+endif
+
+ifeq ($(BUILDVER),linux24)
+MENUSELECT_MODULES+=xpp wctc4xxp zttranscode
+endif
+
+ifeq ($(findstring xpp,$(MENUSELECT_MODULES)),)
+ BUILD_XPP:=yes
+endif
+
+TOPDIR_MODULES:=pciradio tor2 torisa wcfxo wct1xxp wctdm wctdm24xxp wcte11xp wcusb zaptel ztd-eth ztd-loc ztdummy ztdynamic zttranscode wcte12xp
+SUBDIR_MODULES:=wct4xxp wctc4xxp xpp
+BUILD_TOPDIR_MODULES:=$(filter-out $(MENUSELECT_MODULES),$(TOPDIR_MODULES))
+BUILD_SUBDIR_MODULES:=$(filter-out $(MENUSELECT_MODULES),$(SUBDIR_MODULES))
+BUILD_MODULES:=$(BUILD_TOPDIR_MODULES) $(BUILD_SUBDIR_MODULES)
+
+MOD_DESTDIR:=zaptel
+
+#NOTE NOTE NOTE
+#
+# all variables set before the include of Makefile.kernel26 are needed by the 2.6 kernel module build process
+
+ifneq ($(KBUILD_EXTMOD),)
+
+obj-m:=$(BUILD_TOPDIR_MODULES:%=%.o)
+obj-m+=$(BUILD_SUBDIR_MODULES:%=%/)
+
+include $(src)/Makefile.kernel26
+
+else
+
+ifeq ($(BUILDVER),linux24)
+ INSTALL_MODULES:=$(BUILD_TOPDIR_MODULES:%=%.o)
+ INSTALL_MODULES+=$(BUILD_SUBDIR_MODULES:%=%/%.o)
+ ALL_MODULES:=$(TOPDIR_MODULES:%=%.o)
+ ALL_MODULES+=$(SUBDIR_MODULES:%=%/%.o)
+else
+ INSTALL_MODULES:=$(BUILD_TOPDIR_MODULES:%=%.ko)
+ INSTALL_MODULES+=$(foreach mod,$(filter-out xpp,$(BUILD_SUBDIR_MODULES)),$(mod)/$(mod).ko)
+ ifneq ($(filter xpp,$(BUILD_SUBDIR_MODULES)),)
+ INSTALL_MODULES+=$(patsubst %,xpp/%.ko,xpp_usb xpd_fxo xpd_fxs xpp)
+ endif
+
+ ALL_MODULES:=$(TOPDIR_MODULES:%=%.ko)
+ ALL_MODULES+=$(foreach mod,$(filter-out xpp,$(SUBDIR_MODULES)),$(mod)/$(mod).ko)
+ ALL_MODULES+=$(patsubst %,xpp/%.ko,xpp_usb xpd_fxo xpd_fxs xpp)
+ endif
+endif
+
CFLAGS+=-I. -O4 -g -Wall -DBUILDING_TONEZONE #-DTONEZONE_DRIVER
ifneq (,$(findstring ppc,$(UNAME_M)))
CFLAGS_PPC:=-fsigned-char
@@ -81,6 +161,8 @@ endif
# Features are now configured in zconfig.h
#
+MODULE_ALIASES=wcfxs wctdm8xxp wct2xxp
+
KFLAGS+=-DSTANDALONE_ZAPATA
CFLAGS+=-DSTANDALONE_ZAPATA
KMAKE = $(MAKE) -C $(KSRC) SUBDIRS=$(PWD)
@@ -93,23 +175,6 @@ INSTALL_PREFIX=$(DESTDIR)
CONFIG_FILE=$(INSTALL_PREFIX)/etc/zaptel.conf
CFLAGS+=-DZAPTEL_CONFIG=\"$(CONFIG_FILE)\"
-ifeq ($(KVERS_MAJ),2.4)
- BUILDVER:=linux24
-else
- BUILDVER:=linux26
-endif
-
-# This is not related to the version that we build. Rather, to the
-# version that we runs. If we build for 2.4 using 2.4 headers on a 2.6
-# system with udev mounted on /dev , no point in installing files to /dev
-# because they'll be wiped at next reboot.
-DYNFS:=$(shell ps ax | grep -v grep | grep -qw 'devfsd\|udevd' && echo "yes")
-
-# Check for udev rules directories
-ifneq (,$(wildcard $(ROOT_PREFIX)/etc/udev/rules.d))
- UDEVRULES=yes
-endif
-
CHKCONFIG:=$(shell sh -c 'type -p chkconfig' 2> /dev/null)
ifndef CHKCONFIG
CHKCONFIG:=:
@@ -130,56 +195,11 @@ LTZ_SO_OBJS:=zonedata.lo tonezone.lo
LTZ_SO_MAJOR_VER:=1
LTZ_SO_MINOR_VER:=0
-ifeq ($(findstring xpp_usb,$(MENUSELECT_MODULES)),)
- BUILD_XPP:=yes
-endif
-MODULES:=pciradio tor2 torisa wcfxo wct1xxp wctdm wctdm24xxp wcte11xp wcusb zaptel ztd-eth ztd-loc ztdummy ztdynamic zttranscode
-MODULES:=$(filter-out $(MENUSELECT_MODULES),$(MODULES))
-MODULE_ALIASES=wcfxs wctdm8xxp wct2xxp
-
-MODULESO:=$(MODULES:%=%.o)
-MODULESKO:=$(MODULES:%=%.ko)
-ifeq ($(BUILDVER),linux26)
-MODULES_BUILD:=$(MODULESKO)
-HOTPLUG_FIRMWARE:=$(shell if grep CONFIG_FW_LOADER $(KINCLUDES)/linux/autoconf.h | grep -q undef; then echo "no"; else echo "yes"; fi)
-else
-MODULES_BUILD:=$(MODULESO)
-endif
-
BIN_DIR:=$(INSTALL_PREFIX)/sbin
LIB_DIR:=$(INSTALL_PREFIX)/usr/lib
INC_DIR:=$(INSTALL_PREFIX)/usr/include
MOD_DIR:=$(INSTALL_PREFIX)/lib/modules/$(KVERS)/misc
-MOD_DESTDIR:=zaptel
-
-obj-m:=$(MODULESO)
-ifeq ($(findstring wct4xxp,$(MENUSELECT_MODULES)),)
-obj-m+=wct4xxp/
-MODULES+=wct4xxp
-endif
-
-# Set this to override hotplug firmware loading and revert to classic header
-#HOTPLUG_FIRMWARE=no
-ifeq ($(HOTPLUG_FIRMWARE),yes)
-CFLAGS+=-DHOTPLUG_FIRMWARE
-endif
-
-# Also build xpp in the subdirectory xpp/ . But only for >=2.6.8 and only
-# for i386 or x86_64. On other platforms it has still not been tested well
-# enough.
-# This does not affect kernel 2.4, because obj-m is only used for kernel
-# 2.6's build. Note that it is only actually tested by the kernel 2.6 build
-# system and not by the main makefile.
-ifneq (,$(shell [ 0$(SUBLEVEL) -ge 8 ] && echo 1))
-ifeq ($(ARCH),i386)
-obj-m+=xpp/
-endif
-ifeq ($(ARCH),x86_64)
-obj-m+=xpp/
-endif
-endif
-
BINS:=fxotune fxstest sethdlc-new ztcfg ztdiag ztmonitor ztspeed zttest zttool
UTILS:=$(filter-out zttool fxstest ztcfg,$(BINS))
UTILSO:=$(UTILS:%=%.o)
@@ -188,7 +208,7 @@ BINS:=$(filter-out $(MENUSELECT_UTILS),$(BINS))
all: menuselect.makeopts
@$(MAKE) _all
-_all: $(if $(MODULES),modules) programs $(LTZ_SO) $(LTZ_A)
+_all: $(if $(BUILD_MODULES),modules) programs $(LTZ_SO) $(LTZ_A)
xpp-utils:
ifeq (yes,$(BUILD_XPP))
@@ -197,15 +217,13 @@ endif
programs: $(BINS) xpp-utils
-modules: $(BUILDVER)
-
-linux24: prereq $(MODULESO) wct4xxp/wct4xxp.o
-
-linux26: prereq
+modules: prereq
@if [ -z "$(KSRC)" -o ! -d "$(KSRC)" ]; then echo "You do not appear to have the sources for the $(KVERS) kernel installed."; exit 1 ; fi
- $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) HOTPLUG_FIRMWARE=$(HOTPLUG_FIRMWARE) modules
-
-xpp: linux26
+ifeq ($(BUILDVER),linux26)
+ $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) modules
+else
+modules: $(BUILD_MODULES)
+endif
version.h:
@ZAPTELVERSION="${ZAPTELVERSION}" build_tools/make_version_h > $@.tmp
@@ -214,32 +232,8 @@ version.h:
fi
@rm -f $@.tmp
-wct4xxp/wct4xxp.o:
- $(MAKE) -C wct4xxp KFLAGS="$(KFLAGS) -I.." CFLAGS="$(CFLAGS) -I.."
-
-devel: tor2ee
-
tests: patgen pattest patlooptest hdlcstress hdlctest hdlcgen hdlcverify timertest
-tor2.o: tor2-hw.h tor2fw.h
-
-zaptel.o: digits.h arith.h sec.h mec.h sec-2.h mec2.h mec3.h zconfig.h
-
-wcusb.o: wcusb.h
-
-wcfxsusb.o: wcfxsusb.h
-
-wctdm.o: wctdm.h
-
-wctdm24xxp.o: wctdm.h
-
-pciradio.o: radfw.h
-
-ztdummy.o: ztdummy.h
-
-$(MODULESO): %.o: %.c zaptel.h
- $(CC) $(KFLAGS) -o $@ -c $<
-
tor2ee.o: tor2-hw.h
tor2ee: LDLIBS+=-lpci
@@ -268,8 +262,6 @@ makefw: makefw.c
gendigits: LDLIBS+=-lm
gendigits: CFLAGS=
-zaptel.c: tones.h
-
prereq: config.status tones.h tor2fw.h radfw.h version.h
zttool.o: zttool.c zaptel.h
@@ -317,6 +309,34 @@ fxstest: LDLIBS+=-lm
fxotune: LDLIBS+=-lm
fxsdump: LDLIBS+=-lm
+devel: tor2ee
+
+ifeq ($(BUILDVER),linux24)
+wct4xxp/wct4xxp.o:
+ $(MAKE) -C wct4xxp KFLAGS="$(KFLAGS) -I.." CFLAGS="$(CFLAGS) -I.."
+
+tor2.o: tor2-hw.h tor2fw.h
+
+zaptel.o: digits.h arith.h sec.h mec.h sec-2.h mec2.h mec3.h zconfig.h
+
+wcusb.o: wcusb.h
+
+wcfxsusb.o: wcfxsusb.h
+
+wctdm.o: wctdm.h
+
+wctdm24xxp.o: wctdm.h
+
+pciradio.o: radfw.h
+
+ztdummy.o: ztdummy.h
+
+$(BUILD_MODULES): %.o: %.c zaptel.h
+ $(CC) $(KFLAGS) -o $@ -c $<
+
+zaptel.c: tones.h
+endif
+
stackcheck: checkstack $(BUILDVER)
./checkstack *.o
@@ -346,51 +366,15 @@ $(UTILS): %: %.o
$(UTILSO): %.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
-devices:
-ifndef DYNFS
- mkdir -p $(INSTALL_PREFIX)/dev/zap
- rm -f $(INSTALL_PREFIX)/dev/zap/ctl
- rm -f $(INSTALL_PREFIX)/dev/zap/channel
- rm -f $(INSTALL_PREFIX)/dev/zap/pseudo
- rm -f $(INSTALL_PREFIX)/dev/zap/timer
- rm -f $(INSTALL_PREFIX)/dev/zap/transcode
- rm -f $(INSTALL_PREFIX)/dev/zap/253
- rm -f $(INSTALL_PREFIX)/dev/zap/252
- rm -f $(INSTALL_PREFIX)/dev/zap/251
- rm -f $(INSTALL_PREFIX)/dev/zap/250
- mknod $(INSTALL_PREFIX)/dev/zap/ctl c 196 0
- mknod $(INSTALL_PREFIX)/dev/zap/transcode c 196 250
- mknod $(INSTALL_PREFIX)/dev/zap/timer c 196 253
- mknod $(INSTALL_PREFIX)/dev/zap/channel c 196 254
- mknod $(INSTALL_PREFIX)/dev/zap/pseudo c 196 255
- N=1; \
- while [ $$N -lt 250 ]; do \
- rm -f $(INSTALL_PREFIX)/dev/zap/$$N; \
- mknod $(INSTALL_PREFIX)/dev/zap/$$N c 196 $$N; \
- N=$$[$$N+1]; \
- done
-else # DYNFS
- ifdef UDEVRULES
- build_tools/genudevrules > $(INSTALL_PREFIX)/etc/udev/rules.d/zaptel.rules
- else # !UDEVRULES
- @echo "**** Dynamic filesystem detected -- not creating device nodes"
- endif
-endif
-
hotplug-uninstall:
$(MAKE) -C firmware hotplug-uninstall
-xpp-install:
-ifeq (yes,$(BUILD_XPP))
- @$(MAKE) -C xpp/utils install
-endif
-
-install: all devices firmware install-libs install-include xpp-install
+install: all devices install-modules install-libs install-include install-xpp
ifeq ($(HOTPLUG_FIRMWARE),yes)
$(MAKE) -C firmware hotplug-install
endif
if [ -f ztcfg ]; then \
- $(INSTALL) -D -m 755 ztcfg $(INSTALL_PREFIX)/sbin/ztcfg; \
+ $(INSTALL -D -m 755 ztcfg $(INSTALL_PREFIX)/sbin/ztcfg; \
fi
if [ -f sethdlc-new ]; then \
$(INSTALL) -D -m 755 sethdlc-new $(INSTALL_PREFIX)/sbin/sethdlc; \
@@ -400,30 +384,11 @@ endif
if [ -f zttool ]; then \
$(INSTALL) -D -m 755 zttool $(INSTALL_PREFIX)/sbin/zttool; \
fi
-ifeq ($(BUILDVER),linux26)
- for x in $(MODULESKO); do \
- rm -f $(INSTALL_PREFIX)/lib/modules/$(KVERS)/extra/$$x ; \
- done; \
- $(KMAKE_INST); \
- if [ -f datamods/syncppp.ko ]; then \
- $(MAKE) -C datamods install; \
- else \
- rm -f $(INSTALL_PREFIX)/lib/modules/$(KVERS)/misc/{hdlc_*,syncppp}.ko; \
- fi
-else
- for x in $(MODULESO) wct4xxp/wct4xxp.o; do \
- $(INSTALL) -D -m 644 $$x $(INSTALL_PREFIX)/lib/modules/$(KVERS)/misc/$$x ; \
- done
-endif
- if ! [ -f wcfxsusb.o ]; then \
- rm -f $(INSTALL_PREFIX)/lib/modules/$(KVERS)/misc/wcfxsusb.o; \
- fi; \
- rm -f $(INSTALL_PREFIX)/lib/modules/$(KVERS)/misc/wcfxs.o
$(INSTALL) -m 644 doc/ztcfg.8 $(INSTALL_PREFIX)/usr/share/man/man8
$(INSTALL) -m 644 doc/zttool.8 $(INSTALL_PREFIX)/usr/share/man/man8
[ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || :
[ -f $(CONFIG_FILE) ] || $(INSTALL) -D -m 644 zaptel.conf.sample $(CONFIG_FILE)
- build_tools/genmodconf $(BUILDVER) "$(ROOT_PREFIX)" "$(filter-out zaptel,$(MODULES)) $(MODULE_ALIASES)"
+ build_tools/genmodconf $(BUILDVER) "$(ROOT_PREFIX)" "$(filter-out zaptel xpp zttranscode ztdynamic,$(BUILD_MODULES)) $(MODULE_ALIASES)"
@if [ -d /etc/modutils ]; then \
/sbin/update-modules ; \
fi
@@ -441,6 +406,11 @@ install-libs: $(LTZ_SO) $(LTZ_A)
$(LIB_DIR)/$(LTZ_SO)
if [ -z "$(INSTALL_PREFIX)" ] && [ -x /usr/sbin/sestatus ] && (/usr/sbin/sestatus | grep "SELinux status:" | grep -q "enabled") ; then /sbin/restorecon -v $(LIB_DIR)/$(LTZ_SO); fi
+install-xpp:
+ifeq (yes,$(BUILD_XPP))
+ @$(MAKE) -C xpp/utils install
+endif
+
install-include:
$(INSTALL) -D -m 644 zaptel.h $(INSTALL_PREFIX)/usr/include/zaptel/zaptel.h
$(INSTALL) -D -m 644 tonezone.h $(INSTALL_PREFIX)/usr/include/zaptel/tonezone.h
@@ -450,8 +420,65 @@ install-include:
rm -f $(INSTALL_PREFIX)/usr/include/torisa.h
rm -f $(INSTALL_PREFIX)/usr/include/tonezone.h
+devices:
+ifndef DYNFS
+ mkdir -p $(INSTALL_PREFIX)/dev/zap
+ rm -f $(INSTALL_PREFIX)/dev/zap/ctl
+ rm -f $(INSTALL_PREFIX)/dev/zap/channel
+ rm -f $(INSTALL_PREFIX)/dev/zap/pseudo
+ rm -f $(INSTALL_PREFIX)/dev/zap/timer
+ rm -f $(INSTALL_PREFIX)/dev/zap/transcode
+ rm -f $(INSTALL_PREFIX)/dev/zap/253
+ rm -f $(INSTALL_PREFIX)/dev/zap/252
+ rm -f $(INSTALL_PREFIX)/dev/zap/251
+ rm -f $(INSTALL_PREFIX)/dev/zap/250
+ mknod $(INSTALL_PREFIX)/dev/zap/ctl c 196 0
+ mknod $(INSTALL_PREFIX)/dev/zap/transcode c 196 250
+ mknod $(INSTALL_PREFIX)/dev/zap/timer c 196 253
+ mknod $(INSTALL_PREFIX)/dev/zap/channel c 196 254
+ mknod $(INSTALL_PREFIX)/dev/zap/pseudo c 196 255
+ N=1; \
+ while [ $$N -lt 250 ]; do \
+ rm -f $(INSTALL_PREFIX)/dev/zap/$$N; \
+ mknod $(INSTALL_PREFIX)/dev/zap/$$N c 196 $$N; \
+ N=$$[$$N+1]; \
+ done
+else # DYNFS
+ ifdef UDEVRULES
+ build_tools/genudevrules > $(INSTALL_PREFIX)/etc/udev/rules.d/zaptel.rules
+ else # !UDEVRULES
+ @echo "**** Dynamic filesystem detected -- not creating device nodes"
+ endif
+endif
+
install-udev: devices
+# make should *fail* and not silently succeed if a program did not build
+install-programs: $(BINS)
+ $(INSTALL) -d $(BIN_DIR)
+ $(INSTALL) $(BINS) $(BIN_DIR)
+
+uninstall-modules:
+ifeq ($(BUILDVER),linux24)
+else
+ for x in $(ALL_MODULES); do \
+ rm -f $(INSTALL_PREFIX)/lib/modules/$(KVERS)/extra/$$x ; \
+ rm -f $(INSTALL_PREFIX)/lib/modules/$(KVERS)/misc/$$x ; \
+ rm -f $(INSTALL_PREFIX)/lib/modules/$(KVERS)/zaptel/$$x ; \
+ done; \
+endif
+
+install-modules: $(INSTALL_MODULES) uninstall-modules
+ifeq ($(BUILDVER),linux24)
+ $(INSTALL) -d $(MOD_DIR)
+ $(INSTALL) -m 644 $(INSTALL_MODULES) $(MOD_DIR)
+else
+ $(KMAKE_INST)
+ if [ -f datamods/syncppp.ko ]; then \
+ $(MAKE) -C datamods install; \
+ fi
+endif
+
config:
if [ -d $(INSTALL_PREFIX)/etc/rc.d/init.d ]; then \
$(INSTALL) -D -m 755 zaptel.init $(INSTALL_PREFIX)/etc/rc.d/init.d/zaptel; \
@@ -488,19 +515,6 @@ update:
echo "Not under version control"; \
fi
-# make should *fail* and not silently succeed if a program did not build
-install-programs: $(BINS) install-libs install-include
- $(INSTALL) -d $(BIN_DIR)
- $(INSTALL) $(BINS) $(BIN_DIR)
-
-install-modules: install-$(BUILDVER)
-install-linux24: $(MODULES_BUILD)
- $(INSTALL) -d $(MOD_DIR)
- $(INSTALL) -m 644 $(MODULES_BUILD) $(MOD_DIR)
-
-install-linux26: $(MODULESKO)
- $(KMAKE_INST)
-
clean:
-@$(MAKE) -C menuselect clean
rm -f torisatool makefw tor2fw.h radfw.h
@@ -509,13 +523,11 @@ clean:
rm -f $(LTZ_SO) $(LTZ_A) *.lo
ifeq ($(BUILDVER),linux26)
$(MAKE) -C $(KSRC) SUBDIRS=$(PWD) clean
+ $(MAKE) -C xpp/utils clean
else
$(MAKE) -C wct4xxp clean
endif
$(MAKE) -C firmware clean
- -@$(MAKE) -C xpp/utils clean
- rm -f xpp/*.ko xpp/*.mod.c xpp/.*o.cmd
- rm -f xpp/*.o xpp/*.mod.o
rm -rf .tmp_versions
rm -f gendigits tones.h
rm -f libtonezone*
@@ -556,3 +568,8 @@ menuselect/menuselect: menuselect/menuselect.c menuselect/menuselect_curses.c me
menuselect-tree: zaptel.xml firmware/firmware.xml
@echo "Generating input for menuselect ..."
@build_tools/make_tree > $@
+
+.EXPORT_ALL_VARIABLES:
+
+.PHONY: menuselect distclean dist-clean clean version.h all _all install b410p devices programs modules tests devel data stackcheck install-udev config update install-programs install-modules install-include install-libs install-xpp xpp-utils uninstall-modules
+endif
diff --git a/Makefile.kernel26 b/Makefile.kernel26
new file mode 100644
index 0000000..97a4e59
--- /dev/null
+++ b/Makefile.kernel26
@@ -0,0 +1,15 @@
+EXTRA_CFLAGS := -I$(src)
+
+zaptel-objs := zaptel-base.o
+
+ifeq ($(HPEC_PRESENT),yes)
+ifeq ($(ARCH),i386)
+zaptel-objs += hpec/hpec_x86_32.o
+endif
+
+ifeq ($(ARCH),x86_64)
+zaptel-objs += hpec/hpec_x86_64.o
+endif
+
+EXTRA_CFLAGS += -DECHO_CAN_HPEC -I$(src)/hpec
+endif
diff --git a/datamods/Makefile b/datamods/Makefile
index c84dc32..310073e 100644
--- a/datamods/Makefile
+++ b/datamods/Makefile
@@ -2,7 +2,7 @@
MODULES= \
hdlc_cisco hdlc_generic hdlc_raw syncppp \
hdlc_fr hdlc_ppp hdlc_raw_eth
-
+
PWD=$(shell pwd)
@@ -24,7 +24,7 @@ clean:
install: $(MODULESKO)
$(KMAKE_INST)
-
+
datamods:
@echo "To build: $(obj-m)"
@echo $(KSRC)
diff --git a/firmware/firmware.xml b/firmware/firmware.xml
index f7baa46..272f9ee 100644
--- a/firmware/firmware.xml
+++ b/firmware/firmware.xml
@@ -1,11 +1,14 @@
<category name="MENUSELECT_FIRMWARE" displayname="Binary Firmware Packages" positive_output="yes">
- <member name="FIRMWARE-OCT6114-064" displayname="Oct6114 064 Echo Cancellation Firmware" >
+ <member name="FIRMWARE-OCT6114-064" displayname="Digium VPMOCT064M" >
<defaultenabled>yes</defaultenabled>
+ <depend>wct4xxp</depend>
</member>
- <member name="FIRMWARE-OCT6114-128" displayname="Oct6114 128 Echo Cancellation Firmware" >
+ <member name="FIRMWARE-OCT6114-128" displayname="Digium VPMOCT128M/VPM450M">
<defaultenabled>yes</defaultenabled>
+ <depend>wct4xxp</depend>
</member>
- <member name="FIRMWARE-TC400M" displayname="TC400M Module Firmware" >
+ <member name="FIRMWARE-TC400M" displayname="Digium TC400M" >
<defaultenabled>yes</defaultenabled>
+ <depend>wctc4xxp</depend>
</member>
</category>
diff --git a/hpec/hpec.h b/hpec/hpec.h
new file mode 100644
index 0000000..7e90f12
--- /dev/null
+++ b/hpec/hpec.h
@@ -0,0 +1,47 @@
+/*
+ * Zapata Telephony Interface to Digium High-Performance Echo Canceller
+ *
+ * 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.
+ */
+
+#if !defined(_HPEC_H)
+#define _HPEC_H
+
+struct echo_can_state;
+
+void __attribute__((regparm(0))) hpec_init(int __attribute__((regparm(0))) __attribute__((format (printf, 1, 2))) (*logger)(const char *format, ...),
+ unsigned int debug,
+ unsigned int chunk_size,
+ void * (*memalloc)(size_t len),
+ void (*memfree)(void *ptr));
+
+void __attribute__((regparm(0))) hpec_shutdown(void);
+
+int __attribute__((regparm(0))) hpec_license_challenge(struct hpec_challenge *challenge);
+
+int __attribute__((regparm(0))) hpec_license_check(struct hpec_license *license);
+
+struct echo_can_state __attribute__((regparm(0))) *hpec_channel_alloc(unsigned int len);
+
+void __attribute__((regparm(0))) hpec_channel_free(struct echo_can_state *channel);
+
+void __attribute__((regparm(0))) hpec_channel_update(struct echo_can_state *channel, short *iref, short *isig);
+
+#endif /* !defined(_HPEC_H) */
+
diff --git a/hpec/hpec_user.h b/hpec/hpec_user.h
new file mode 100644
index 0000000..bf006eb
--- /dev/null
+++ b/hpec/hpec_user.h
@@ -0,0 +1,40 @@
+/*
+ * Zapata Telephony Interface to Digium High-Performance Echo Canceller
+ *
+ * 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.
+ */
+
+#if !defined(_HPEC_USER_H)
+#define _HPEC_USER_H
+
+struct hpec_challenge {
+ __u8 challenge[16];
+};
+
+struct hpec_license {
+ __u32 numchannels;
+ __u8 userinfo[256];
+ __u8 response[16];
+};
+
+#define ZT_EC_LICENSE_CHALLENGE _IOR(ZT_CODE, 60, struct hpec_challenge)
+#define ZT_EC_LICENSE_RESPONSE _IOW(ZT_CODE, 61, struct hpec_license)
+
+#endif /* !defined(_HPEC_USER_H) */
+
diff --git a/hpec/hpec_zaptel.h b/hpec/hpec_zaptel.h
new file mode 100644
index 0000000..b03bfe6
--- /dev/null
+++ b/hpec/hpec_zaptel.h
@@ -0,0 +1,137 @@
+/*
+ * Zapata Telephony Interface to Digium High-Performance Echo Canceller
+ *
+ * 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.
+ */
+
+#if !defined(_HPEC_ZAPTEL_H)
+#define _HPEC_ZAPTEL_H
+
+#define ZT_EC_ARRAY_UPDATE
+
+#include "hpec_user.h"
+#include "hpec.h"
+
+static int __attribute__((regparm(0))) __attribute__((format (printf, 1, 2))) logger(const char *format, ...)
+{
+ int res;
+ va_list args;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ va_start(args, format);
+ res = vprintk(format, args);
+ va_end(args);
+#else
+ char buf[256];
+
+ va_start(args, format);
+ res = vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
+ printk(buf);
+#endif
+
+ return res;
+}
+
+static void *memalloc(size_t len)
+{
+ return kmalloc(len, GFP_KERNEL);
+}
+
+static void memfree(void *ptr)
+{
+ kfree(ptr);
+}
+
+static void echo_can_init(void)
+{
+ printk("Zaptel Echo Canceller: Digium High-Performance Echo Canceller\n");
+ hpec_init(logger, debug, ZT_CHUNKSIZE, memalloc, memfree);
+}
+
+static void echo_can_shutdown(void)
+{
+ hpec_shutdown();
+}
+
+static inline void echo_can_free(struct echo_can_state *ec)
+{
+ hpec_channel_free(ec);
+}
+
+static inline void echo_can_array_update(struct echo_can_state *ec, short *iref, short *isig)
+{
+ hpec_channel_update(ec, iref, isig);
+}
+
+DECLARE_MUTEX(alloc_lock);
+
+static inline struct echo_can_state *echo_can_create(int len, int adaption_mode)
+{
+ struct echo_can_state *result = NULL;
+
+ if (down_interruptible(&alloc_lock))
+ return NULL;
+
+ result = hpec_channel_alloc(len);
+
+ up(&alloc_lock);
+
+ return result;
+}
+
+static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+ return 0;
+}
+
+DECLARE_MUTEX(license_lock);
+
+static int hpec_license_ioctl(unsigned int cmd, unsigned long data)
+{
+ struct hpec_challenge challenge;
+ struct hpec_license license;
+ int result = 0;
+
+ switch (cmd) {
+ case ZT_EC_LICENSE_CHALLENGE:
+ if (down_interruptible(&license_lock))
+ return -EINTR;
+ memset(&challenge, 0, sizeof(challenge));
+ if (hpec_license_challenge(&challenge))
+ result = -ENODEV;
+ if (!result && copy_to_user((unsigned char *) data, &challenge, sizeof(challenge)))
+ result = -EFAULT;
+ up(&license_lock);
+ return result;
+ case ZT_EC_LICENSE_RESPONSE:
+ if (down_interruptible(&license_lock))
+ return -EINTR;
+ if (copy_from_user(&license, (unsigned char *) data, sizeof(license)))
+ result = -EFAULT;
+ if (!result && hpec_license_check(&license))
+ result = -EACCES;
+ up(&license_lock);
+ return result;
+ default:
+ return -ENOSYS;
+ }
+}
+
+#endif /* !defined(_HPEC_ZAPTEL_H) */
diff --git a/wct4xxp/Makefile b/wct4xxp/Makefile
index 2fd4ee3..37f69c4 100644
--- a/wct4xxp/Makefile
+++ b/wct4xxp/Makefile
@@ -1,6 +1,6 @@
ifneq ($(KBUILD_EXTMOD),)
-include $(obj)/Kbuild
+include $(obj)/Makefile.kernel26
else
diff --git a/wct4xxp/Kbuild b/wct4xxp/Makefile.kernel26
index 105ca73..105ca73 100644
--- a/wct4xxp/Kbuild
+++ b/wct4xxp/Makefile.kernel26
diff --git a/wctc4xxp/Makefile b/wctc4xxp/Makefile
new file mode 100644
index 0000000..cad6216
--- /dev/null
+++ b/wctc4xxp/Makefile
@@ -0,0 +1,13 @@
+ifneq ($(KBUILD_EXTMOD),)
+
+include $(obj)/Makefile.kernel26
+
+endif
+
+tests: codec_test
+
+codec_test: codec_test.c ../zaptel.h
+ $(CC) -o $@ $< $(CFLAGS)
+
+clean:
+ rm -rf codec_test
diff --git a/wctc4xxp/Makefile.kernel26 b/wctc4xxp/Makefile.kernel26
new file mode 100644
index 0000000..b034819
--- /dev/null
+++ b/wctc4xxp/Makefile.kernel26
@@ -0,0 +1,15 @@
+obj-m += wctc4xxp.o
+
+EXTRA_CFLAGS := -I$(src)/.. -Wno-undef
+
+wctc4xxp-objs := base.o
+
+ifneq ($(HOTPLUG_FIRMWARE),yes)
+wctc4xxp-objs += firmware_tc400m.o
+endif
+
+$(obj)/base.o: $(src)/../zaptel.h
+
+$(obj)/firmware_tc400m.o: $(src)/tc400m-firmware.bin $(obj)/base.o
+ @echo Making firmware object file for $(notdir $<)
+ @cd $(src) && ../build_tools/make_firmware_object $(notdir $<) $@ $(obj)/base.o
diff --git a/wctc4xxp/base.c b/wctc4xxp/base.c
new file mode 100644
index 0000000..b7138e3
--- /dev/null
+++ b/wctc4xxp/base.c
@@ -0,0 +1,1813 @@
+/*
+ * 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
+
+#ifdef HOTPLUG_FIRMWARE
+static const char *dte_firmware = "tc400m-firmware.bin";
+#else
+extern u8 _binary_tc400m_firmware_bin_start[];
+extern void _binary_tc400m_firmware_bin_size;
+#endif
+
+
+/* #define USE_TEST_HW */
+#define USE_TDM_CONFIG
+
+#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 97
+
+#define DTE_FORMAT_ULAW 0x00
+#define DTE_FORMAT_G723_1 0x04
+#define DTE_FORMAT_ALAW 0x08
+#define DTE_FORMAT_G729A 0x12
+#define DTE_FORMAT_UNDEF 0xFF
+
+#define G729_LENGTH 20
+#define G723_LENGTH 30
+
+#define G729_SAMPLES 160 /* g.729 */
+#define G723_SAMPLES 240 /* g.723 */
+
+#define G729_BYTES 20 /* g.729 */
+#define G723_BYTES 20 /* g.723 */
+
+
+
+#define ACK_SPACE 20
+
+#define MAX_COMMANDS (NUM_CHANNELS + ACK_SPACE)
+#define MAX_RCV_COMMANDS 16
+
+/* 1432 for boot, 274 for 30msec ulaw, 194 for 20mec ulaw */
+#define BOOT_CMD_LEN 1500
+#define 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_TRANS_CONNECT_LEN 38
+#define CMD_MSG_TRANS_CONNECT(s,e,c1,c2,f1,f2) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x12, 0x00, 0x00,0x06,0x22,0x93, 0x00,0x00, \
+ e,0x00, (c1&0x00FF),((c1&0xFF00)>>8), f1,0x00, (c2&0x00FF),((c2&0xFF00)>>8), f2,0x00 }
+#define CMD_MSG_DESTROY_CHANNEL_LEN 32
+#define CMD_MSG_DESTROY_CHANNEL(s,t) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x11,0x00, 0x00,0x00, \
+ (t&0x00FF),((t&0xFF00)>>8), 0x00, 0x00 }
+
+/* Individual channel config commands */
+#define CMD_MSG_SET_IP_HDR_CHANNEL_LEN 58
+#define CMD_MSG_SET_IP_HDR_CHANNEL(s,c,t2,t1) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00) >> 8),(c&0x00FF), 0x26, 0x00, 0x00,0x02,0x00,0x90, 0x00,0x00, \
+ 0x00,0x00, 0x45,0x00, 0x00,0x00, 0x00,0x00, 0x40,0x00, 0x80,0x11, 0x00,0x00, \
+ 0xC0,0xA8,0x09,0x03, 0xC0,0xA8,0x09,0x03, \
+ ((t2&0xFF00)>>8)+0x50,(t2&0x00FF), ((t1&0xFF00)>>8)+0x50,(t1&0x00FF), 0x00,0x00, 0x00,0x00 }
+#define CMD_MSG_VOIP_VCEOPT_LEN 40
+#define CMD_MSG_VOIP_VCEOPT(s,c,l,w) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x12, 0x00, 0x00,0x02,0x01,0x80, 0x00,0x00, \
+ 0x21,l, 0x00,0x1C, 0x04,0x00, 0x00,0x00, w,0x00, 0x80,0x11 }
+#define CMD_MSG_VOIP_VOPENA_LEN 44
+#define CMD_MSG_VOIP_VOPENA(s,c,f) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x16, 0x00, 0x00,0x02,0x00,0x80, 0x00,0x00, \
+ 0x01,0x00, 0x80,f, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x12,0x34, 0x56,0x78, 0x00,0x00 }
+#define CMD_MSG_VOIP_VOPENA_CLOSE_LEN 32
+#define CMD_MSG_VOIP_VOPENA_CLOSE(s,c) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x00,0x80, 0x00,0x00, \
+ 0x00,0x00, 0x00,0x00 }
+#define CMD_MSG_VOIP_INDCTRL_LEN 32
+#define CMD_MSG_VOIP_INDCTRL(s,c) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x84,0x80, 0x00,0x00, \
+ 0x07,0x00, 0x00,0x00 }
+
+/* CPU ACK command */
+#define CMD_MSG_ACK_LEN 20
+#define CMD_MSG_ACK(s,c) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s, 0xE0, (c&0x00FF), ((c>>8)&0x00FF) }
+
+/* Wrapper for RTP packets */
+#define CMD_MSG_IP_UDP_RTP_LEN 54
+#define CMD_MSG_IP_UDP_RTP(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x08,0x00, \
+ 0x45,0x00, p1,p2, 0x00,p3, 0x40,0x00, 0x80,0x11, p4,p5, \
+ 0xC0,0xA8,0x09,0x03, 0xC0,0xA8,0x09,0x03, p6,p7, p8,p9, p10,p11, p12,p13, \
+ 0x80,p14, p15,p16, p17,p18,p19,p20, 0x12,0x34,0x56,0x78}
+
+
+#define zt_send_cmd(wc, command, length, hex) \
+ ({ \
+ int ret = 0; \
+ do { \
+ if (ret == 2) \
+ { \
+ wc->ztsnd_rtx++; \
+ if (hex == 0x0010) \
+ wc->ztsnd_0010_rtx++; \
+ } \
+ down(&wc->cmdqsem); \
+ wc->last_command_sent = hex; \
+ if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) \
+ printk("wcdte error: cmdq is full.\n"); \
+ else { \
+ unsigned char fifo[OTHER_CMD_LEN] = command; \
+ int i; \
+ wc->cmdq[wc->cmdq_wndx].cmdlen = length; \
+ for (i = 0; i < length; i++) \
+ wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i]; \
+ wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; \
+ } \
+ __transmit_demand(wc); \
+ up(&wc->cmdqsem); \
+ ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 0); \
+ if (ret == 1) \
+ return(1); \
+ } while (ret == 2); \
+ })
+
+
+struct cmdq {
+ unsigned int cmdlen;
+ unsigned int cmd[MAX_COMMAND_LEN];
+};
+
+struct 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_command_sent;
+ unsigned int last_rcommand;
+ unsigned int last_rparm2;
+ unsigned int seq_num;
+ long timeout;
+
+ unsigned int ztsnd_rtx;
+ unsigned int ztsnd_0010_rtx;
+
+ unsigned 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 wcdte = { "Wildcard TC400P+TC400M", 0 };
+
+static struct wcdte *ifaces[WC_MAX_IFACES];
+
+
+
+/*
+ * The following is the definition of the state structure
+ * used by the G.721/G.723 encoder and decoder to preserve their internal
+ * state between successive calls. The meanings of the majority
+ * of the state structure fields are explained in detail in the
+ * CCITT Recommendation G.721. The field names are essentially indentical
+ * to variable names in the bit level description of the coding algorithm
+ * included in this Recommendation.
+ */
+struct dte_state {
+ int encoder; /* If we're an encoder */
+ struct wcdte *wc;
+
+ unsigned int timestamp;
+ unsigned int seqno;
+
+ unsigned int timeslot_in_num; /* DTE chennel on which results we be received from */
+ unsigned int timeslot_out_num; /* DTE channel to send data to */
+
+ unsigned int chan_in_num; /* DTE chennel on which results we be received from */
+ unsigned int chan_out_num; /* DTE channel to send data to */
+
+ unsigned int packets_sent;
+ unsigned int packets_received;
+
+ unsigned int last_dte_seqno;
+ unsigned int dte_seqno_rcv;
+};
+
+
+static struct zt_transcoder *uencode;
+static struct zt_transcoder *udecode;
+static struct dte_state *encoders;
+static struct dte_state *decoders;
+static int debug = 0;
+static char *mode;
+int debug_packets = 0;
+
+
+static int wcdte_create_channel(struct wcdte *wc, int simple, int complicated, int part1_id, int part2_id, unsigned int *dte_chan1, unsigned int *dte_chan2);
+static int wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2);
+
+/* 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->packets_sent = 0;
+ state_ptr->packets_received = 0;
+ state_ptr->last_dte_seqno = 0;
+ state_ptr->dte_seqno_rcv = 0;
+
+ state_ptr->chan_in_num = 999;
+ state_ptr->chan_out_num = 999;
+
+ if (encoder == 1)
+ {
+ 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_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)
+ {
+ inbytes = G723_BYTES;
+ 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);
+
+ 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_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] & 0xC0) == 0)
+ {
+ rcommand = readchunk[24] | (readchunk[25] << 8);
+ rchannel = readchunk[18] | (readchunk[19] << 8);
+ rseq = readchunk[16];
+
+ down(&wc->cmdqsem);
+ if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug )
+ printk("wcdte error: cmdq is full (rndx = %d, wndx = %d).\n", wc->cmdq_rndx, wc->cmdq_wndx);
+ else
+ {
+ unsigned char fifo[OTHER_CMD_LEN] = CMD_MSG_ACK(rseq++, rchannel);
+
+ wc->cmdq[wc->cmdq_wndx].cmdlen = CMD_MSG_ACK_LEN;
+ for (i = 0; i < wc->cmdq[wc->cmdq_wndx].cmdlen; i++)
+ wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i];
+ wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS;
+ }
+
+ __transmit_demand(wc);
+
+
+ wc->rcvflags = RCV_CSMENCAPS;
+ wc->last_rcommand = rcommand;
+ wc->last_rparm2 = readchunk[30] | (readchunk[31] << 8);
+ wake_up_interruptible(&wc->regq);
+ up(&wc->cmdqsem);
+ }
+ else
+ {
+ wc->rcvflags = RCV_CSMENCAPS_ACK;
+ wake_up_interruptible(&wc->regq);
+ }
+ }
+
+ /* 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!\n");
+ rcodec = DTE_FORMAT_UNDEF;
+ } else {
+ chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen);
+ st->packets_received++;
+ }
+
+ }
+
+ if ((rcodec == 0x04) || (rcodec == 0x12)) /* g.723 or g.729 (encoders) */
+ {
+ ztc = &(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!\n");
+ rcodec = DTE_FORMAT_UNDEF;
+ } else {
+ chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen);
+ st->packets_received++;
+ }
+
+ }
+
+ if (st->dte_seqno_rcv == 0)
+ {
+ st->dte_seqno_rcv = 1;
+ st->last_dte_seqno = rtp_rseq;
+ } else {
+ rtp_eseq = (st->last_dte_seqno + 1) & 0xFFFF;
+ if ( (rtp_rseq != rtp_eseq) && debug )
+ printk("wcdte error: Bad seqno from DTE! [%d][%d][%d]\n", rchannel, rtp_rseq, st->last_dte_seqno);
+
+ st->last_dte_seqno = rtp_rseq;
+ }
+
+ if (rcodec == 0x00) /* ulaw */
+ {
+ if (zt_tc_sanitycheck(zth, rlen) && ((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_BYTES))
+ {
+ for (i = 0; i < rlen; i++)
+ chars[i] = readchunk[i+54];
+
+ zth->dstlen += rlen;
+ zth->dstsamples = zth->dstlen * 12;
+
+ } 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;
+
+ if (wc->wqueints & 0x00000040) {
+ /* Loop descriptors is available */
+ do {
+ res = wcdte_check_descriptor(wc);
+ } while(res);
+ }
+
+ /* Handle TX interrupts */
+ if (wc->wqueints & 0x00000001)
+ {
+ wc->txints++;
+ transmit_demand(wc);
+ wc->intcount++;
+ }
+}
+
+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));
+
+
+ /* 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 use_mask)
+{
+ int ret;
+
+
+ if (use_mask)
+ ret = wait_event_interruptible_timeout(wc->regq, (wc->rcvflags == mask), wc->timeout);
+ else
+ ret = wait_event_interruptible_timeout(wc->regq, (wc->last_rcommand == wc->last_command_sent), wc->timeout);
+ wc->rcvflags = 0;
+ wc->last_rcommand = 0;
+ wc->last_command_sent = 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)\n", ret);
+ return(2);
+ }
+ 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 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(1000);
+
+ /* Clear reset */
+ wcdte_setctl(wc, 0x00A0, 0x04080000);
+
+ /* Waitfor ethernet link */
+ delay_count = 0;
+ do
+ {
+ reg = wcdte_getctl(wc, 0x00fc);
+ mdelay(100);
+ delay_count++;
+
+ if (delay_count >= 100)
+ {
+ printk("wcdte error: Failed to link to DTE processor!\n");
+ return(1);
+ }
+ } while ((reg & 0xE0000000) != 0xE0000000);
+
+
+ /* Turn off booted LED */
+ wcdte_setctl(wc, 0x00A0, 0x04084000);
+
+
+#endif
+
+ reg = wcdte_getctl(wc, 0x00fc);
+ if (debug)
+ printk("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;
+ }
+
+ __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++;
+
+ } while (byteloc < firmware->size-20);
+ wc->timeout = 10 * HZ;
+ 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;
+ 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);
+ chan1 = wc->last_rparm2;
+
+ /* Create simple channel */
+ zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010);
+ chan2 = wc->last_rparm2;
+
+ /* Configure complex channel */
+ zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(wc->seq_num++, chan1, part2_id, part1_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(wc->seq_num++, chan1, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001);
+
+ /* Configure simple channel */
+ zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(wc->seq_num++, chan2, part1_id, part2_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(wc->seq_num++, chan2, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001);
+
+ 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_INDCTRL(wc->seq_num++, chan1), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084);
+ zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(wc->seq_num++, chan2), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(wc->seq_num++, chan1, complicated), CMD_MSG_VOIP_VOPENA_LEN, 0x8000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(wc->seq_num++, chan2, simple), CMD_MSG_VOIP_VOPENA_LEN, 0x8000);
+
+ *dte_chan1 = chan1;
+ *dte_chan2 = chan2;
+
+ return 1;
+}
+
+static int wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2)
+{
+
+ /* Turn off both channels */
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(wc->seq_num++, chan1), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(wc->seq_num++, 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)
+{
+#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/100 + 1; /* 10msec */
+
+ 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;
+ unsigned int complexfmts;
+ struct firmware embedded_firmware = {
+#if !defined(HOTPLUG_FIRMWARE)
+ /* Yes... this is weird. objcopy gives us a symbol containing
+ the size of the firmware, not a pointer to a variable containing
+ the size. The only way we can get the value of the symbol
+ is to take its address, so we define it as a pointer and
+ then cast that value to the proper type.
+ */
+ .size = (size_t) &_binary_tc400m_firmware_bin_size,
+ .data = _binary_tc400m_firmware_bin_start,
+#endif
+ };
+ const struct firmware *firmware = &embedded_firmware;
+
+ 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_command_sent = 0;
+ wc->last_rcommand = 0;
+ wc->last_rparm2 = 0;
+ wc->cmdq_wndx = 0;
+ wc->cmdq_rndx = 0;
+ wc->seq_num = 6;
+ wc->timeout = 1 * HZ; /* 1 sec */
+ 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_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
+
+#ifdef HOTPLUG_FIRMWARE
+ if ((request_firmware(&firmware, dte_firmware, &wc->dev->dev) != 0) || !firmware) {
+ printk("TC400B: firmware %s not available from userspace\n", dte_firmware);
+ return -1;
+ }
+#endif
+ dte_firmware_ver = firmware->data[0];
+ 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 5.3kbps");
+ complexfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1;
+ wc->numchannels = min_numchannels;
+ }
+ else if (mode[3] == '9') /* "g729" */
+ {
+ sprintf(wc->complexname, "g.729a");
+ complexfmts = ZT_FORMAT_G729A;
+ wc->numchannels = g729_numchannels;
+ }
+ else if (mode[3] == '3') /* "g723" */
+ {
+ sprintf(wc->complexname, "g.723.1 5.3kbps");
+ complexfmts = ZT_FORMAT_G723_1;
+ wc->numchannels = g723_numchannels;
+ }
+ else
+ {
+ sprintf(wc->complexname, "g.729a / g.723.1 5.3kbps");
+ 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)\n", wc->complexname, dte_firmware_ver);
+
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, wc);
+
+ if (request_irq(pdev->irq, wcdte_interrupt, SA_SHIRQ, "tc400b", wc)) {
+ printk("wcdte error: Unable to request IRQ %d\n", pdev->irq);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ vfree(wc);
+ return -EIO;
+ }
+
+
+ if (wcdte_hardware_init(wc)) {
+ /* Set Reset Low */
+ wcdte_stop_dma(wc);
+ /* Free Resources */
+ free_irq(pdev->irq, wc);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ vfree(wc);
+ return -EIO;
+
+ }
+
+ /* Enable interrupts */
+ wcdte_enable_interrupts(wc);
+
+ /* Start DMA */
+ wcdte_start_dma(wc);
+ if (wcdte_boot_processor(wc,firmware)) {
+ 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 (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);
+ 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) &wcdte }, /* Digium board */
+#else
+ { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcdte }, /* reference board */
+#endif
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, wcdte_pci_tbl);
+
+static struct pci_driver wcdte_driver = {
+ name: "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 = pci_module_init(&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(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/wctc4xxp/codec_test.c b/wctc4xxp/codec_test.c
new file mode 100644
index 0000000..287979d
--- /dev/null
+++ b/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;
+}
diff --git a/wctc4xxp/tc400m-firmware.bin b/wctc4xxp/tc400m-firmware.bin
new file mode 100644
index 0000000..2e6c743
--- /dev/null
+++ b/wctc4xxp/tc400m-firmware.bin
Binary files differ
diff --git a/wcte12xp.c b/wcte12xp.c
new file mode 100644
index 0000000..52d9122
--- /dev/null
+++ b/wcte12xp.c
@@ -0,0 +1,2046 @@
+/*
+ * Digium, Inc. Wildcard TE12xP T1/PRI card Driver
+ *
+ * Written by Michael Spiceland <mspiceland@digium.com>
+ *
+ * Adapted from the wctdm24xxp and wcte11xp drivers originally
+ * written by Mark Spencer <markster@digium.com>
+ * Matthew Fredrickson <creslin@digium.com>
+ * William Meadows <wmeadows@digium.com>
+ *
+ * Copyright (C) 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 <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/proc_fs.h>
+
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+#include "wct4xxp/wct4xxp.h" /* For certain definitions */
+
+#define WC_MAX_IFACES 8
+
+#define SDI_CLK (0x00010000)
+#define SDI_DOUT (0x00020000)
+#define SDI_DREAD (0x00040000)
+#define SDI_DIN (0x00080000)
+
+#define EFRAME_SIZE 108
+#define ERING_SIZE 16 /* Maximum ring size */
+#define EFRAME_GAP 20
+#define SFRAME_SIZE ((EFRAME_SIZE * ZT_CHUNKSIZE) + (EFRAME_GAP * (ZT_CHUNKSIZE - 1)))
+
+#define PCI_WINDOW_SIZE ((2 * 2 * 2 * SFRAME_SIZE) + (2 * ERING_SIZE * 4))
+
+#define MAX_COMMANDS 7*7*2 /* 42 bytes /3 (cntl,addr,data) /2 (cs) */
+
+#define ISR_COMMANDS 2
+
+#define __CMD_ISR (1 << 17) /* flag for ISR reads */
+#define __CMD_PINS (1 << 18) /* CPLD pin read */
+#define __CMD_LEDS (1 << 19) /* LED Operation */
+#define __CMD_RD (1 << 20) /* Read Operation */
+#define __CMD_WR (1 << 21) /* Write Operation */
+#define __CMD_FIN (1 << 22) /* Has finished receive */
+#define __CMD_TX (1 << 23) /* Has been transmitted */
+
+#define __LED_ORANGE (1<<3)
+#define __LED_GREEN (1<<2)
+#define __LED_RED (1<<1)
+
+#define SET_LED_ORANGE(a) a | __LED_ORANGE
+#define SET_LED_RED(a) (a | __LED_RED) & ~__LED_GREEN
+#define SET_LED_GREEN(a) (a | __LED_GREEN) & ~__LED_RED
+
+#define UNSET_LED_ORANGE(a) a & ~__LED_ORANGE
+#define UNSET_LED_REDGREEN(a) a | __LED_RED | __LED_GREEN
+
+#define CMD_WR(a,b) (((a) << 8) | (b) | __CMD_WR)
+#define CMD_RD(a) (((a) << 8) | __CMD_RD)
+#define CMD_LEDS(a) (((a) << 8) | __CMD_LEDS)
+#define CMD_BYTE(slot, a) (slot*6)+(a*2) /* only even slots */
+
+#define TYPE_T1 1
+#define TYPE_E1 2
+
+static struct pci_driver te12xp_driver;
+#define module_printk(fmt, args...) printk("%s: " fmt, te12xp_driver.name, ## args)
+#define debug_printk(level, fmt, args...) if (debug >= level) printk("%s (%s): " fmt, te12xp_driver.name, __FUNCTION__, ## args)
+
+static int chanmap_t1[] =
+{ 2,1,0,
+ 6,5,4,
+ 10,9,8,
+ 14,13,12,
+ 18,17,16,
+ 22,21,20,
+ 26,25,24,
+ 30,29,28 };
+
+static int chanmap_e1[] =
+{ 2,1,0,
+ 7,6,5,4,
+ 11,10,9,8,
+ 15,14,13,12,
+ 19,18,17,16,
+ 23,22,21,20,
+ 27,26,25,24,
+ 31,30,29,28 };
+
+static int chanmap_e1uc[] =
+{ 3,2,1,0,
+ 7,6,5,4,
+ 11,10,9,8,
+ 15,14,13,12,
+ 19,18,17,16,
+ 23,22,21,20,
+ 27,26,25,24,
+ 31,30,29,28 };
+
+struct command {
+ unsigned char address;
+ unsigned char data;
+ unsigned char ident;
+ unsigned int flags;
+ unsigned char cs_slot;
+};
+
+struct cmdq {
+ struct command cmds[MAX_COMMANDS];
+ unsigned char isrshadow[ISR_COMMANDS];
+};
+
+struct t1 {
+ struct pci_dev *dev;
+ spinlock_t reglock;
+ unsigned char txident;
+ unsigned char rxident;
+ int spantype;
+ struct {
+ unsigned int nmf:1;
+ unsigned int sendingyellow:1;
+ } flags;
+ unsigned char txsigs[16]; /* Copy of tx sig registers */
+ int num;
+ int alarmcount; /* How much red alarm we've seen */
+ int alarmdebounce;
+ char *variety;
+ unsigned int intcount;
+ int sync;
+ int dead;
+ int blinktimer;
+ int alarmtimer;
+ int yellowtimer;
+ int ledlastvalue;
+ int alarms_read;
+ int checktiming; /* Set >0 to cause the timing source to be checked */
+ int loopupcnt;
+ int loopdowncnt;
+ int initialized;
+ int *chanmap;
+ unsigned char ledtestreg;
+ unsigned long iobase;
+ unsigned char ec_chunk1[32][ZT_CHUNKSIZE];
+ unsigned char ec_chunk2[32][ZT_CHUNKSIZE];
+ struct zt_span span; /* Span */
+ struct zt_chan chans[32]; /* Channels */
+ int freeregion;
+ unsigned int intmask;
+ wait_queue_head_t regq;
+ struct cmdq cmdq;
+ struct command dummy; /* preallocate for dummy noop command */
+ unsigned char ctlreg;
+ int rdbl;
+ int tdbl;
+ unsigned int rxints;
+ unsigned int txints;
+ unsigned int sdi;
+ int usecount;
+ dma_addr_t readdma;
+ dma_addr_t writedma;
+ dma_addr_t descripdma;
+ volatile unsigned int *writechunk;
+ volatile unsigned int *readchunk;
+ volatile unsigned int *descripchunk;
+ unsigned int isrreaderrors;
+};
+
+static int debug = 0;
+static int j1mode = 0;
+static int alarmdebounce = 0;
+static int loopback = 0;
+static int t1e1override = -1;
+static int unchannelized = 0;
+
+static struct t1 *ifaces[WC_MAX_IFACES];
+
+struct t1_desc {
+ char *name;
+ int flags;
+};
+
+static struct t1_desc te12xp = { "Wildcard TE12xP", 0 };
+
+static int schluffen(wait_queue_head_t *q)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ add_wait_queue(q, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+ if (!signal_pending(current)) schedule();
+ current->state = TASK_RUNNING;
+ remove_wait_queue(q, &wait);
+ if (signal_pending(current)) return -ERESTARTSYS;
+ return(0);
+}
+
+static inline int empty_slot(struct t1 *wc)
+{
+ unsigned int x;
+
+ for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+ if (!wc->cmdq.cmds[x].flags && !wc->cmdq.cmds[x].address)
+ return x;
+ }
+ return -1;
+}
+
+static inline void __t1_setctl(struct t1 *wc, unsigned int addr, unsigned int val)
+{
+ outl(val, wc->iobase + addr);
+}
+
+static inline void t1_setctl(struct t1 *wc, unsigned int addr, unsigned int val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t1_setctl(wc, addr, val);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline unsigned int __t1_getctl(struct t1 *wc, unsigned int addr)
+{
+ return inl(wc->iobase + addr);
+}
+
+static inline unsigned int t1_getctl(struct t1 *wc, unsigned int addr)
+{
+ unsigned long flags;
+ unsigned int val;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ val = __t1_getctl(wc, addr);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ return val;
+}
+
+static void t1_init_descriptors(struct t1 *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] = 0x80000000;
+ descrip[1] = 0xe5800000 | (SFRAME_SIZE);
+ if (x % 2)
+ descrip[2] = writedma + SFRAME_SIZE;
+ else
+ descrip[2] = writedma;
+ descrip[3] = descripdma;
+
+ /* Receive descriptor */
+ descrip[0 + ERING_SIZE * 4] = 0x80000000;
+ descrip[1 + ERING_SIZE * 4] = 0x01000000 | (SFRAME_SIZE);
+ if (x % 2)
+ descrip[2 + ERING_SIZE * 4] = readdma + SFRAME_SIZE;
+ else
+ descrip[2 + ERING_SIZE * 4] = readdma;
+ descrip[3 + ERING_SIZE * 4] = descripdma + ERING_SIZE * 16;
+
+ /* Advance descriptor */
+ descrip += 4;
+ }
+}
+
+static inline void t1_reinit_descriptor(struct t1 *wc, int tx, int dbl, char *s)
+{
+ int o2 = dbl * 4;
+
+ if (!tx)
+ o2 += ERING_SIZE * 4;
+
+ wc->descripchunk[o2] = 0x80000000;
+}
+
+static inline void cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int eframe, int slot)
+{
+ unsigned long flags;
+ struct command *curcmd=NULL;
+ unsigned int x;
+
+ /* Skip audio */
+ writechunk += 66;
+ spin_lock_irqsave(&wc->reglock, flags);
+ /* Search for something waiting to transmit */
+ if ((slot < 6) && (eframe) && (eframe < ZT_CHUNKSIZE - 1)) {
+ /* only 6 useable cs slots per */
+ for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+ if ((wc->cmdq.cmds[x].flags & (__CMD_RD | __CMD_WR | __CMD_LEDS | __CMD_PINS)) &&
+ !(wc->cmdq.cmds[x].flags & (__CMD_TX | __CMD_FIN))) {
+ curcmd = &wc->cmdq.cmds[x];
+#if 0
+ printk("Transmitting command addr='%02x' data='%02x' flags='%08x' in txident=%d slot=%d CMD_BYTE=%d jiffies=%d\n", wc->cmdq.cmds[x].address, wc->cmdq.cmds[x].data, wc->cmdq.cmds[x].flags, wc->txident, slot, CMD_BYTE(slot,2), jiffies);
+#endif
+ wc->cmdq.cmds[x].flags |= __CMD_TX;
+ wc->cmdq.cmds[x].ident = wc->txident;
+ break;
+ }
+ }
+ if (!curcmd) {
+ curcmd = &wc->dummy;
+ /* If nothing else, use filler */
+ curcmd->address = 0x4a;
+ curcmd->data = 0x00;
+ curcmd->flags = __CMD_RD;
+ }
+ curcmd->cs_slot = slot;
+ if (curcmd->flags & __CMD_WR)
+ writechunk[CMD_BYTE(slot, 0)] = 0x0c; /* 0c write command */
+ else if (curcmd->flags & __CMD_LEDS)
+ writechunk[CMD_BYTE(slot, 0)] = 0x10 | ((curcmd->address) & 0x0E); /* led set command */
+ else if (curcmd->flags & __CMD_PINS)
+ writechunk[CMD_BYTE(slot, 0)] = 0x30; /* CPLD2 pin state */
+ else
+ writechunk[CMD_BYTE(slot, 0)] = 0x0a; /* read command */
+ writechunk[CMD_BYTE(slot, 1)] = curcmd->address;
+ writechunk[CMD_BYTE(slot, 2)] = curcmd->data;
+ }
+
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline void cmd_decipher(struct t1 *wc, volatile unsigned char *readchunk)
+{
+ unsigned long flags;
+ unsigned char ident, cs_slot;
+ unsigned int x;
+
+ /* Skip audio */
+ readchunk += 66;
+ spin_lock_irqsave(&wc->reglock, flags);
+ /* Search for any pending results */
+ for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+ if ((wc->cmdq.cmds[x].flags & (__CMD_RD | __CMD_WR | __CMD_LEDS | __CMD_PINS)) &&
+ (wc->cmdq.cmds[x].flags & (__CMD_TX)) &&
+ !(wc->cmdq.cmds[x].flags & (__CMD_FIN))) {
+ ident = wc->cmdq.cmds[x].ident;
+ cs_slot = wc->cmdq.cmds[x].cs_slot;
+
+ if (ident == wc->rxident) {
+ /* Store result */
+ wc->cmdq.cmds[x].data |= readchunk[CMD_BYTE(cs_slot, 2)];
+ /*printk("answer in rxident=%d cs_slot=%d is %d CMD_BYTE=%d jiffies=%d\n", ident, cs_slot, last_read_command, CMD_BYTE(cs_slot, 2), jiffies); */
+ wc->cmdq.cmds[x].flags |= __CMD_FIN;
+ if (wc->cmdq.cmds[x].flags & (__CMD_WR | __CMD_LEDS))
+ /* clear out writes (and leds) since they need no ack */
+ memset(&wc->cmdq.cmds[x], 0, sizeof(wc->cmdq.cmds[x]));
+ }
+ }
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline unsigned int __t1_sdi_clk(struct t1 *wc)
+{
+ unsigned int ret;
+
+ wc->sdi &= ~SDI_CLK;
+ __t1_setctl(wc, 0x0048, wc->sdi);
+ ret = __t1_getctl(wc, 0x0048);
+ wc->sdi |= SDI_CLK;
+ __t1_setctl(wc, 0x0048, wc->sdi);
+ return ret & SDI_DIN;
+}
+
+static inline void __t1_sdi_sendbits(struct t1 *wc, unsigned int bits, int count)
+{
+ wc->sdi &= ~SDI_DREAD;
+ __t1_setctl(wc, 0x0048, wc->sdi);
+ while (count--) {
+ if (bits & (1 << count))
+ wc->sdi |= SDI_DOUT;
+ else
+ wc->sdi &= ~SDI_DOUT;
+ __t1_sdi_clk(wc);
+ }
+}
+
+static inline unsigned int __t1_sdi_recvbits(struct t1 *wc, int count)
+{
+ unsigned int bits=0;
+
+ wc->sdi |= SDI_DREAD;
+ __t1_setctl(wc, 0x0048, wc->sdi);
+ while (count--) {
+ bits <<= 1;
+ if (__t1_sdi_clk(wc))
+ bits |= 1;
+ else
+ bits &= ~1;
+ }
+ return bits;
+}
+
+static inline unsigned short __t1_getsdi(struct t1 *wc, unsigned char addr)
+{
+ unsigned int bits;
+
+ /* Send preamble */
+ bits = 0xffffffff;
+ __t1_sdi_sendbits(wc, bits, 32);
+ bits = (0x6 << 10) | (1 << 5) | (addr);
+ __t1_sdi_sendbits(wc, bits, 14);
+
+ return __t1_sdi_recvbits(wc, 18);
+}
+
+static inline unsigned short t1_getsdi(struct t1 *wc, unsigned char addr)
+{
+ unsigned long flags;
+ unsigned short val;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ val = __t1_getsdi(wc, addr);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ return val;
+}
+
+static inline void __t1_setsdi(struct t1 *wc, unsigned char addr, unsigned short value)
+{
+ unsigned int bits;
+
+ /* Send preamble */
+ bits = 0xffffffff;
+ __t1_sdi_sendbits(wc, bits, 32);
+ bits = (0x5 << 12) | (1 << 7) | (addr << 2) | 0x2;
+ __t1_sdi_sendbits(wc, bits, 16);
+ __t1_sdi_sendbits(wc, value, 16);
+}
+
+static inline void t1_setsdi(struct t1 *wc, unsigned char addr, unsigned short value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t1_setsdi(wc, addr, value);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline int t1_setreg_full(struct t1 *wc, int addr, int val, int inisr)
+{
+ unsigned long flags;
+ int hit;
+ int ret;
+
+ do {
+ spin_lock_irqsave(&wc->reglock, flags);
+ hit = empty_slot(wc);
+ if (hit > -1) {
+ wc->cmdq.cmds[hit].address = addr;
+ wc->cmdq.cmds[hit].data = val;
+ wc->cmdq.cmds[hit].flags |= __CMD_WR;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (inisr)
+ break;
+ if (hit < 0) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ } while (hit < 0);
+
+ return (hit > -1) ? 0 : -1;
+}
+
+static inline int t1_setreg(struct t1 *wc, int addr, int val)
+{
+ return t1_setreg_full(wc, addr, val, 0);
+}
+
+/***************************************************************************
+ * clean_leftovers()
+ *
+ * Check for unconsumed isr register reads and clean them up.
+ **************************************************************************/
+static inline void clean_leftovers(struct t1 *wc)
+{
+ unsigned long flags;
+ unsigned int x;
+ int count = 0;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ /* find our requested command */
+ for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+ if ((wc->cmdq.cmds[x].flags & __CMD_RD) &&
+ (wc->cmdq.cmds[x].flags & __CMD_ISR) &&
+ !(wc->cmdq.cmds[x].flags & __CMD_FIN)) {
+ debug_printk(1,"leftover isr read! %d", count);
+ memset(&wc->cmdq.cmds[x], 0, sizeof(wc->cmdq.cmds[x]));
+ }
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+/********************************************************************
+ * t1_getreg_isr()
+ *
+ * Called in interrupt context to retrieve a value already requested
+ * by the normal t1_getreg().
+ *******************************************************************/
+static inline int t1_getreg_isr(struct t1 *wc, int addr)
+{
+ unsigned long flags;
+ int hit=-1;
+ int ret;
+ unsigned int x;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ /* find our requested command */
+ for (x = 0;x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+ if ((wc->cmdq.cmds[x].flags & __CMD_RD) &&
+ (wc->cmdq.cmds[x].flags & __CMD_FIN) &&
+ (wc->cmdq.cmds[x].address==addr)) {
+ hit = x;
+ break;
+ }
+ }
+
+ if (hit < 0) {
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ debug_printk(2, "t1_getreg_isr() no addr=%02x\n", addr);
+ return -1; /* oops, couldn't find it */
+ }
+
+ ret = wc->cmdq.cmds[hit].data;
+ memset(&wc->cmdq.cmds[hit], 0, sizeof(struct command));
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ return ret;
+}
+
+static inline int t1_getreg(struct t1 *wc, int addr, int inisr)
+{
+ unsigned long flags;
+ int hit;
+ int ret = 0;
+
+ do {
+ spin_lock_irqsave(&wc->reglock, flags);
+ hit = empty_slot(wc);
+ if (hit > -1) {
+ wc->cmdq.cmds[hit].address = addr;
+ wc->cmdq.cmds[hit].data = 0x00;
+ wc->cmdq.cmds[hit].flags |= __CMD_RD;
+ if (inisr)
+ wc->cmdq.cmds[hit].flags |= __CMD_ISR;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (inisr) /* must be requested in t1_getreg_isr() */
+ return (hit > -1) ? 0 : -1;
+ if (hit < 0) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ } while (hit < 0);
+
+ do {
+ spin_lock_irqsave(&wc->reglock, flags);
+ if (wc->cmdq.cmds[hit].flags & __CMD_FIN) {
+ ret = wc->cmdq.cmds[hit].data;
+ memset(&wc->cmdq.cmds[hit], 0, sizeof(wc->cmdq.cmds[hit]));
+ hit = -1;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (hit > -1) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ } while (hit > -1);
+
+ return ret;
+}
+
+static inline int t1_setleds(struct t1 *wc, int leds, int inisr)
+{
+ unsigned long flags;
+ int hit;
+ int ret = 0;
+
+ leds = ~leds & 0x0E; /* invert the LED bits (3 downto 1)*/
+
+ do {
+ spin_lock_irqsave(&wc->reglock, flags);
+ hit = empty_slot(wc);
+ if (hit > -1) {
+ wc->cmdq.cmds[hit].flags |= __CMD_LEDS;
+ wc->cmdq.cmds[hit].address = leds;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (inisr)
+ break;
+ if (hit < 0) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ } while (hit < 0);
+
+ return (hit > -1) ? 0 : -1;
+}
+
+static inline int t1_getpins(struct t1 *wc, int inisr)
+{
+ unsigned long flags;
+ int hit;
+ int ret = 0;
+
+ do {
+ spin_lock_irqsave(&wc->reglock, flags);
+ hit = empty_slot(wc);
+ if (hit > -1) {
+ wc->cmdq.cmds[hit].address = 0x00;
+ wc->cmdq.cmds[hit].data = 0x00;
+ wc->cmdq.cmds[hit].flags |= __CMD_PINS;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (inisr)
+ return (hit > -1) ? 0 : -1;
+ if (hit < 0) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ } while (hit < 0);
+
+ do {
+ spin_lock_irqsave(&wc->reglock, flags);
+ if (wc->cmdq.cmds[hit].flags & __CMD_FIN) {
+ ret = wc->cmdq.cmds[hit].data;
+ memset(&wc->cmdq.cmds[hit], 0, sizeof(wc->cmdq.cmds[hit]));
+ hit = -1;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (hit > -1) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ } while (hit > -1);
+
+ return ret;
+}
+
+static void t1_setintmask(struct t1 *wc, unsigned int intmask)
+{
+ wc->intmask = intmask;
+ t1_setctl(wc, 0x0038, intmask);
+}
+
+static void t1_enable_interrupts(struct t1 *wc)
+{
+ /* Enable interrupts */
+ t1_setintmask(wc, 0x00010041); /* only RX */
+}
+
+static void t1_disable_interrupts(struct t1 *wc)
+{
+ /* Disable interrupts */
+ t1_setintmask(wc, 0x00000000);
+ t1_setctl(wc, 0x0084, 0x00000000);
+}
+
+static void t1_start_dma(struct t1 *wc)
+{
+ unsigned int reg;
+ int x;
+
+ wmb();
+ t1_setctl(wc, 0x0020, wc->descripdma);
+ t1_setctl(wc, 0x0018, wc->descripdma + (16 * ERING_SIZE));
+ /* Start receiver/transmitter */
+ reg = t1_getctl(wc, 0x0030);
+ t1_setctl(wc, 0x0030, reg | 0x00002002);
+ t1_setctl(wc, 0x0008, 0x00000000);
+ t1_setctl(wc, 0x0010, 0x00000000);
+ reg = t1_getctl(wc, 0x0028);
+ t1_setctl(wc, 0x0028, reg);
+
+ /* Set Reset - now with MAGIC TIPS */
+ t1_setctl(wc, 0x0048, 0x00000000);
+ for (x = 0; x < 10; x++)
+ schluffen(&wc->regq);
+ /* Clear reset */
+ t1_setctl(wc, 0x0048, 0x00010000);
+ for (x = 0; x < 10; x++)
+ schluffen(&wc->regq);
+ /* Switch to caring only about receive interrupts */
+ t1_setintmask(wc, 0x00010040);
+}
+
+static void t1_stop_dma(struct t1 *wc)
+{
+ /* Disable interrupts and reset */
+ unsigned int reg;
+
+ /* Disable interrupts */
+ t1_setintmask(wc, 0x00000000);
+ t1_setctl(wc, 0x0084, 0x00000000);
+ t1_setctl(wc, 0x0048, 0x00000000);
+ /* Reset the part to be on the safe side */
+ reg = t1_getctl(wc, 0x0000);
+ reg |= 0x00000001;
+ t1_setctl(wc, 0x0000, reg);
+}
+
+static void __t1xxp_set_clear(struct t1 *wc, int channo)
+{
+ int i,j;
+ int ret;
+ unsigned short val=0;
+
+ for (i = 0; i < 24; i++) {
+ j = (i / 8);
+ if (wc->span.chans[i].flags & ZT_FLAG_CLEAR)
+ val |= 1 << (7 - (i % 8));
+ if (((i % 8)==7) && /* write byte every 8 channels */
+ ((channo < 0) || /* channo=-1 means all channels */
+ (j == (channo-1)/8) )) { /* only the register for this channo */
+ ret = t1_setreg_full(wc, 0x2f + j, val, 1);
+ if (ret < 0)
+ module_printk("set_clear failed for chan %d!\n",i);
+ val = 0;
+ }
+ }
+}
+
+static void t1_release(struct t1 *wc)
+{
+ zt_unregister(&wc->span);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ kfree(wc);
+ printk("Freed a Wildcard TE12xP\n");
+}
+
+static void t4_serial_setup(struct t1 *wc)
+{
+ module_printk("Setting up global serial parameters for %s\n",
+ wc->spantype == TYPE_E1 ? (unchannelized ? "Unchannelized E1" : "E1") : "T1");
+
+ t1_setreg(wc, 0x85, 0xe0); /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */
+ t1_setreg(wc, 0x08, 0x05); /* IPC: Interrupt push/pull active low */
+
+ /* Global clocks (8.192 Mhz CLK) */
+ t1_setreg(wc, 0x92, 0x00);
+ t1_setreg(wc, 0x93, 0x18);
+ t1_setreg(wc, 0x94, 0xfb);
+ t1_setreg(wc, 0x95, 0x0b);
+ t1_setreg(wc, 0x96, 0x00);
+ t1_setreg(wc, 0x97, 0x0b);
+ t1_setreg(wc, 0x98, 0xdb);
+ t1_setreg(wc, 0x99, 0xdf);
+
+ /* Configure interrupts */
+ t1_setreg(wc, 0x46, 0xc0); /* GCR: Interrupt on Activation/Deactivation of AIX, LOS */
+
+ /* Configure system interface */
+ t1_setreg(wc, 0x3e, 0x0a /* 0x02 */); /* SIC1: 4.096 Mhz clock/bus, double buffer receive / transmit, byte interleaved */
+ t1_setreg(wc, 0x3f, 0x00); /* SIC2: No FFS, no center receive eliastic buffer, phase 0 */
+ t1_setreg(wc, 0x40, 0x04); /* SIC3: Edges for capture */
+ t1_setreg(wc, 0x44, 0x30); /* CMR1: RCLK is at 8.192 Mhz dejittered */
+ t1_setreg(wc, 0x45, 0x00); /* CMR2: We provide sync and clock for tx and rx. */
+ t1_setreg(wc, 0x22, 0x00); /* XC0: Normal operation of Sa-bits */
+ t1_setreg(wc, 0x23, 0x04); /* XC1: 0 offset */
+ t1_setreg(wc, 0x24, 0x00); /* RC0: Just shy of 255 */
+ t1_setreg(wc, 0x25, 0x05); /* RC1: The rest of RC0 */
+
+ /* Configure ports */
+ t1_setreg(wc, 0x80, 0x00); /* PC1: SPYR/SPYX input on RPA/XPA */
+ t1_setreg(wc, 0x81, 0x22); /* PC2: RMFB/XSIG output/input on RPB/XPB */
+ t1_setreg(wc, 0x82, 0x65); /* PC3: Some unused stuff */
+ t1_setreg(wc, 0x83, 0x35); /* PC4: Some more unused stuff */
+ t1_setreg(wc, 0x84, 0x31); /* PC5: XMFS active low, SCLKR is input, RCLK is output */
+ t1_setreg(wc, 0x86, 0x03); /* PC6: CLK1 is Tx Clock output, CLK2 is 8.192 Mhz from DCO-R */
+ t1_setreg(wc, 0x3b, 0x00); /* Clear LCR1 */
+}
+
+static void t1_configure_t1(struct t1 *wc, int lineconfig, int txlevel)
+{
+ unsigned int fmr4, fmr2, fmr1, fmr0, lim2;
+ char *framing, *line;
+ int mytxlevel;
+
+ if ((txlevel > 7) || (txlevel < 4))
+ mytxlevel = 0;
+ else
+ mytxlevel = txlevel - 4;
+ fmr1 = 0x9e; /* FMR1: Mode 0, T1 mode, CRC on for ESF, 2.048 Mhz system data rate, no XAIS */
+ fmr2 = 0x22; /* FMR2: no payload loopback, auto send yellow alarm */
+ if (loopback)
+ fmr2 |= 0x4;
+
+ if (j1mode)
+ fmr4 = 0x1c;
+ else
+ fmr4 = 0x0c; /* FMR4: Lose sync on 2 out of 5 framing bits, auto resync */
+
+ lim2 = 0x21; /* LIM2: 50% peak is a "1", Advanced Loss recovery */
+ lim2 |= (mytxlevel << 6); /* LIM2: Add line buildout */
+ t1_setreg(wc, 0x1d, fmr1);
+ t1_setreg(wc, 0x1e, fmr2);
+
+ /* Configure line interface */
+ if (lineconfig & ZT_CONFIG_AMI) {
+ line = "AMI";
+ fmr0 = 0xa0;
+ } else {
+ line = "B8ZS";
+ fmr0 = 0xf0;
+ }
+ if (lineconfig & ZT_CONFIG_D4) {
+ framing = "D4";
+ } else {
+ framing = "ESF";
+ fmr4 |= 0x2;
+ fmr2 |= 0xc0;
+ }
+ t1_setreg(wc, 0x1c, fmr0);
+
+ t1_setreg(wc, 0x20, fmr4);
+ t1_setreg(wc, 0x21, 0x40); /* FMR5: Enable RBS mode */
+
+ t1_setreg(wc, 0x37, 0xf8); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */
+ t1_setreg(wc, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */
+
+ t1_setreg(wc, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */
+ t1_setreg(wc, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */
+
+ t1_setreg(wc, 0x3a, lim2); /* LIM2: 50% peak amplitude is a "1" */
+ t1_setreg(wc, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */
+ t1_setreg(wc, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */
+
+ if (j1mode)
+ t1_setreg(wc, 0x24, 0x80); /* J1 overide */
+
+ /* Generate pulse mask for T1 */
+ switch (mytxlevel) {
+ case 3:
+ t1_setreg(wc, 0x26, 0x07); /* XPM0 */
+ t1_setreg(wc, 0x27, 0x01); /* XPM1 */
+ t1_setreg(wc, 0x28, 0x00); /* XPM2 */
+ break;
+ case 2:
+ t1_setreg(wc, 0x26, 0x8c); /* XPM0 */
+ t1_setreg(wc, 0x27, 0x11); /* XPM1 */
+ t1_setreg(wc, 0x28, 0x01); /* XPM2 */
+ break;
+ case 1:
+ t1_setreg(wc, 0x26, 0x8c); /* XPM0 */
+ t1_setreg(wc, 0x27, 0x01); /* XPM1 */
+ t1_setreg(wc, 0x28, 0x00); /* XPM2 */
+ break;
+ case 0:
+ default:
+ t1_setreg(wc, 0x26, 0xd7); /* XPM0 */
+ t1_setreg(wc, 0x27, 0x22); /* XPM1 */
+ t1_setreg(wc, 0x28, 0x01); /* XPM2 */
+ break;
+ }
+
+ module_printk("Span configured for %s/%s\n", framing, line);
+}
+
+static void t1_configure_e1(struct t1 *wc, int lineconfig)
+{
+ unsigned int fmr2, fmr1, fmr0;
+ unsigned int cas = 0;
+ char *crc4 = "";
+ char *framing, *line;
+
+ fmr1 = 0x46; /* FMR1: E1 mode, Automatic force resync, PCM30 mode, 8.192 Mhz backplane, no XAIS */
+ fmr2 = 0x03; /* FMR2: Auto transmit remote alarm, auto loss of multiframe recovery, no payload loopback */
+ if (unchannelized)
+ fmr2 |= 0x30;
+ if (loopback)
+ fmr2 |= 0x4;
+ if (lineconfig & ZT_CONFIG_CRC4) {
+ fmr1 |= 0x08; /* CRC4 transmit */
+ fmr2 |= 0xc0; /* CRC4 receive */
+ crc4 = "/CRC4";
+ }
+ t1_setreg(wc, 0x1d, fmr1);
+ t1_setreg(wc, 0x1e, fmr2);
+
+ /* Configure line interface */
+ if (lineconfig & ZT_CONFIG_AMI) {
+ line = "AMI";
+ fmr0 = 0xa0;
+ } else {
+ line = "HDB3";
+ fmr0 = 0xf0;
+ }
+ if (lineconfig & ZT_CONFIG_CCS) {
+ framing = "CCS";
+ } else {
+ framing = "CAS";
+ cas = 0x40;
+ }
+ t1_setreg(wc, 0x1c, fmr0);
+
+ if (unchannelized)
+ t1_setreg(wc, 0x1f, 0x40);
+
+ t1_setreg(wc, 0x37, 0xf0 /*| 0x6 */ ); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */
+ t1_setreg(wc, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */
+
+ t1_setreg(wc, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */
+ t1_setreg(wc, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */
+
+ /* Condition receive line interface for E1 after reset */
+ t1_setreg(wc, 0xbb, 0x17);
+ t1_setreg(wc, 0xbc, 0x55);
+ t1_setreg(wc, 0xbb, 0x97);
+ t1_setreg(wc, 0xbb, 0x11);
+ t1_setreg(wc, 0xbc, 0xaa);
+ t1_setreg(wc, 0xbb, 0x91);
+ t1_setreg(wc, 0xbb, 0x12);
+ t1_setreg(wc, 0xbc, 0x55);
+ t1_setreg(wc, 0xbb, 0x92);
+ t1_setreg(wc, 0xbb, 0x0c);
+ t1_setreg(wc, 0xbb, 0x00);
+ t1_setreg(wc, 0xbb, 0x8c);
+
+ t1_setreg(wc, 0x3a, 0x20); /* LIM2: 50% peak amplitude is a "1" */
+ t1_setreg(wc, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */
+ t1_setreg(wc, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */
+
+ t1_setreg(wc, 0x20, 0x9f); /* XSW: Spare bits all to 1 */
+ if (unchannelized)
+ t1_setreg(wc, 0x21, 0x3c);
+ else
+ t1_setreg(wc, 0x21, 0x1c|cas); /* XSP: E-bit set when async. AXS auto, XSIF to 1 */
+
+
+ /* Generate pulse mask for E1 */
+ t1_setreg(wc, 0x26, 0x54); /* XPM0 */
+ t1_setreg(wc, 0x27, 0x02); /* XPM1 */
+ t1_setreg(wc, 0x28, 0x00); /* XPM2 */
+ module_printk("Span configured for %s/%s%s\n", framing, line, crc4);
+}
+
+static void t1xxp_framer_start(struct t1 *wc, struct zt_span *span)
+{
+ int alreadyrunning = wc->span.flags & ZT_FLAG_RUNNING;
+ unsigned long flags;
+
+ if (wc->spantype == TYPE_E1) { /* if this is an E1 card */
+ t1_configure_e1(wc, span->lineconfig);
+ } else { /* is a T1 card */
+ t1_configure_t1(wc, span->lineconfig, span->txlevel);
+ __t1xxp_set_clear(wc, -1);
+ }
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ if (!alreadyrunning)
+ wc->span.flags |= ZT_FLAG_RUNNING;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static int t1xxp_startup(struct zt_span *span)
+{
+ struct t1 *wc = span->pvt;
+ int i;
+
+ /* initialize the start value for the entire chunk of last ec buffer */
+ for (i = 0; i < span->channels; i++) {
+ memset(wc->ec_chunk1[i], ZT_LIN2X(0, &span->chans[i]), ZT_CHUNKSIZE);
+ memset(wc->ec_chunk2[i], ZT_LIN2X(0, &span->chans[i]), ZT_CHUNKSIZE);
+ }
+
+ /* Reset framer with proper parameters and start */
+ t1xxp_framer_start(wc, span);
+ debug_printk(1, "Calling startup (flags is %d)\n", span->flags);
+
+ return 0;
+}
+
+static int t1xxp_shutdown(struct zt_span *span)
+{
+ struct t1 *wc = span->pvt;
+ unsigned long flags;
+
+ t1_setreg(wc, 0x46, 0x41); /* GCR: Interrupt on Activation/Deactivation of AIX, LOS */
+ spin_lock_irqsave(&wc->reglock, flags);
+ span->flags &= ~ZT_FLAG_RUNNING;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return 0;
+}
+
+static int t1xxp_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ struct t1 *wc = chan->pvt;
+ int alreadyrunning = chan->span->flags & ZT_FLAG_RUNNING;
+
+ if (alreadyrunning && (wc->spantype != TYPE_E1))
+ __t1xxp_set_clear(wc, chan->channo);
+
+ return 0;
+}
+
+static int t1xxp_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+ struct t1 *wc = span->pvt;
+
+ span->lineconfig = lc->lineconfig;
+ span->txlevel = lc->lbo;
+ span->rxlevel = 0;
+ /* Do we want to SYNC on receive or not */
+ wc->sync = lc->sync;
+ if (wc->sync)
+ wc->ctlreg |= 0x80;
+ else
+ wc->ctlreg &= ~0x80;
+
+ /* If already running, apply changes immediately */
+ if (span->flags & ZT_FLAG_RUNNING)
+ return t1xxp_startup(span);
+
+ return 0;
+}
+
+static int t1xxp_rbsbits(struct zt_chan *chan, int bits)
+{
+ u_char m,c;
+ int n,b;
+ struct t1 *wc = chan->pvt;
+ unsigned long flags;
+
+ debug_printk(2, "Setting bits to %d on channel %s\n", bits, chan->name);
+ if (wc->spantype == TYPE_E1) { /* do it E1 way */
+ if (chan->chanpos == 16)
+ return 0;
+
+ n = chan->chanpos - 1;
+ if (chan->chanpos > 15) n--;
+ b = (n % 15);
+ spin_lock_irqsave(&wc->reglock, flags);
+ c = wc->txsigs[b];
+ m = (n / 15) << 2; /* nibble selector */
+ c &= (0xf << m); /* keep the other nibble */
+ c |= (bits & 0xf) << (4 - m); /* put our new nibble here */
+ wc->txsigs[b] = c;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ /* output them to the chip */
+ t1_setreg_full(wc,0x71 + b,c,1);
+ } else if (wc->span.lineconfig & ZT_CONFIG_D4) {
+ n = chan->chanpos - 1;
+ b = (n / 4);
+ spin_lock_irqsave(&wc->reglock, flags);
+ c = wc->txsigs[b];
+ m = ((3 - (n % 4)) << 1); /* nibble selector */
+ c &= ~(0x3 << m); /* keep the other nibble */
+ c |= ((bits >> 2) & 0x3) << m; /* put our new nibble here */
+ wc->txsigs[b] = c;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ /* output them to the chip */
+ t1_setreg_full(wc,0x70 + b,c,1);
+ t1_setreg_full(wc,0x70 + b + 6,c,1);
+ } else if (wc->span.lineconfig & ZT_CONFIG_ESF) {
+ n = chan->chanpos - 1;
+ b = (n / 2);
+ spin_lock_irqsave(&wc->reglock, flags);
+ c = wc->txsigs[b];
+ m = ((n % 2) << 2); /* nibble selector */
+ c &= (0xf << m); /* keep the other nibble */
+ c |= (bits & 0xf) << (4 - m); /* put our new nibble here */
+ wc->txsigs[b] = c;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ /* output them to the chip */
+ t1_setreg_full(wc,0x70 + b,c,1);
+ }
+ debug_printk(2,"Finished setting RBS bits\n");
+
+ return 0;
+}
+
+static inline void __t1_check_sigbits_reads(struct t1 *wc)
+{
+ int i;
+
+ if (!(wc->span.flags & ZT_FLAG_RUNNING))
+ return;
+ if (wc->spantype == TYPE_E1) {
+ for (i = 0; i < 15; i++) {
+ if (t1_getreg(wc, 0x71 + i, 1))
+ wc->isrreaderrors++;
+ }
+ } else if (wc->span.lineconfig & ZT_CONFIG_D4) {
+ for (i = 0; i < 24; i+=4) {
+ if (t1_getreg(wc, 0x70 + (i >> 2), 1))
+ wc->isrreaderrors++;
+ }
+ } else {
+ for (i = 0; i < 24; i+=2) {
+ if (t1_getreg(wc, 0x70 + (i >> 1), 1))
+ wc->isrreaderrors++;
+ }
+ }
+}
+
+static inline void __t1_check_sigbits(struct t1 *wc)
+{
+ int a,i,rxs;
+
+ if (!(wc->span.flags & ZT_FLAG_RUNNING))
+ return;
+ if (wc->spantype == TYPE_E1) {
+ for (i = 0; i < 15; i++) {
+ a = t1_getreg_isr(wc, 0x71 + i);
+ if (a > -1) {
+ /* Get high channel in low bits */
+ rxs = (a & 0xf);
+ if (!(wc->span.chans[i+16].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i+16].rxsig != rxs)
+ zt_rbsbits(&wc->span.chans[i+16], rxs);
+ }
+ rxs = (a >> 4) & 0xf;
+ if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i].rxsig != rxs)
+ zt_rbsbits(&wc->span.chans[i], rxs);
+ }
+ } else {
+ debug_printk(1, "no space to request register in isr\n");
+ }
+ }
+ } else if (wc->span.lineconfig & ZT_CONFIG_D4) {
+ for (i = 0; i < 24; i+=4) {
+ a = t1_getreg_isr(wc, 0x70 + (i>>2));
+ if (a > -1) {
+ /* Get high channel in low bits */
+ rxs = (a & 0x3) << 2;
+ if (!(wc->span.chans[i+3].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i+3].rxsig != rxs)
+ zt_rbsbits(&wc->span.chans[i+3], rxs);
+ }
+ rxs = (a & 0xc);
+ if (!(wc->span.chans[i+2].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i+2].rxsig != rxs)
+ zt_rbsbits(&wc->span.chans[i+2], rxs);
+ }
+ rxs = (a >> 2) & 0xc;
+ if (!(wc->span.chans[i+1].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i+1].rxsig != rxs)
+ zt_rbsbits(&wc->span.chans[i+1], rxs);
+ }
+ rxs = (a >> 4) & 0xc;
+ if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i].rxsig != rxs)
+ zt_rbsbits(&wc->span.chans[i], rxs);
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < 24; i+=2) {
+ a = t1_getreg_isr(wc, 0x70 + (i>>1));
+ if (a > -1) {
+ /* Get high channel in low bits */
+ rxs = (a & 0xf);
+ if (!(wc->span.chans[i+1].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i+1].rxsig != rxs)
+ zt_rbsbits(&wc->span.chans[i+1], rxs);
+ }
+ rxs = (a >> 4) & 0xf;
+ if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i].rxsig != rxs)
+ zt_rbsbits(&wc->span.chans[i], rxs);
+ }
+ }
+ }
+ }
+}
+
+static int t1xxp_maint(struct zt_span *span, int cmd)
+{
+ struct t1 *wc = span->pvt;
+
+ if (wc->spantype == TYPE_E1) {
+ switch (cmd) {
+ case ZT_MAINT_NONE:
+ module_printk("XXX Turn off local and remote loops E1 XXX\n");
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ module_printk("XXX Turn on local loopback E1 XXX\n");
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ module_printk("XXX Turn on remote loopback E1 XXX\n");
+ break;
+ case ZT_MAINT_LOOPUP:
+ module_printk("XXX Send loopup code E1 XXX\n");
+ break;
+ case ZT_MAINT_LOOPDOWN:
+ module_printk("XXX Send loopdown code E1 XXX\n");
+ break;
+ case ZT_MAINT_LOOPSTOP:
+ module_printk("XXX Stop sending loop codes E1 XXX\n");
+ break;
+ default:
+ module_printk("Unknown E1 maint command: %d\n", cmd);
+ break;
+ }
+ } else {
+ switch (cmd) {
+ case ZT_MAINT_NONE:
+ module_printk("XXX Turn off local and remote loops T1 XXX\n");
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ module_printk("XXX Turn on local loop and no remote loop XXX\n");
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ module_printk("XXX Turn on remote loopup XXX\n");
+ break;
+ case ZT_MAINT_LOOPUP:
+ t1_setreg(wc, 0x21, 0x50); /* FMR5: Nothing but RBS mode */
+ break;
+ case ZT_MAINT_LOOPDOWN:
+ t1_setreg(wc, 0x21, 0x60); /* FMR5: Nothing but RBS mode */
+ break;
+ case ZT_MAINT_LOOPSTOP:
+ t1_setreg(wc, 0x21, 0x40); /* FMR5: Nothing but RBS mode */
+ break;
+ default:
+ module_printk("Unknown T1 maint command: %d\n", cmd);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int t1xxp_open(struct zt_chan *chan)
+{
+ struct t1 *wc = chan->pvt;
+
+ if (wc->dead)
+ return -ENODEV;
+ wc->usecount++;
+
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#else
+ try_module_get(THIS_MODULE);
+#endif
+
+ return 0;
+}
+
+static int t1xxp_close(struct zt_chan *chan)
+{
+ struct t1 *wc = chan->pvt;
+
+ wc->usecount--;
+
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#else
+ module_put(THIS_MODULE);
+#endif
+
+ /* If we're dead, release us now */
+ if (!wc->usecount && wc->dead)
+ t1_release(wc);
+
+ return 0;
+}
+
+static int t1xxp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
+{
+ struct t4_regs regs;
+ unsigned int x;
+ struct t1 *wc;
+
+ switch (cmd) {
+ case WCT4_GET_REGS:
+ wc = chan->pvt;
+ for (x = 0; x < sizeof(regs.pci) / sizeof(regs.pci[0]); x++)
+#if 1
+ regs.pci[x] = (inb(wc->iobase + (x << 2))) |
+ (inb(wc->iobase + (x << 2) + 1) << 8) |
+ (inb(wc->iobase + (x << 2) + 2) << 16) |
+ (inb(wc->iobase + (x << 2) + 3) << 24);
+#else
+ regs.pci[x] = (inb(wc->iobase + x));
+#endif
+
+ for (x = 0; x < sizeof(regs.regs) / sizeof(regs.regs[0]); x++)
+ regs.regs[x] = t1_getreg(wc, x, 0);
+
+ if (copy_to_user((struct t4_regs *) data, &regs, sizeof(regs)))
+ return -EFAULT;
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int t1_software_init(struct t1 *wc)
+{
+ int x;
+
+ /* Find position */
+ for (x = 0; x < sizeof(ifaces) / sizeof(ifaces[0]); x++) {
+ if (ifaces[x] == wc) {
+ debug_printk(1, "software init for card %d\n",x);
+ break;
+ }
+ }
+
+ if (x == sizeof(ifaces) / sizeof(ifaces[0]))
+ return -1;
+
+ t4_serial_setup(wc);
+
+ wc->num = x;
+ sprintf(wc->span.name, "WCT1/%d", wc->num);
+ sprintf(wc->span.desc, "%s Card %d", wc->variety, wc->num);
+
+ wc->span.spanconfig = t1xxp_spanconfig;
+ wc->span.chanconfig = t1xxp_chanconfig;
+ wc->span.startup = t1xxp_startup;
+ wc->span.shutdown = t1xxp_shutdown;
+ wc->span.rbsbits = t1xxp_rbsbits;
+ wc->span.maint = t1xxp_maint;
+ wc->span.open = t1xxp_open;
+ wc->span.close = t1xxp_close;
+ wc->span.ioctl = t1xxp_ioctl;
+
+ if (wc->spantype == TYPE_E1) {
+ if (unchannelized)
+ wc->span.channels = 32;
+ else
+ wc->span.channels = 31;
+ } else
+ wc->span.channels = 24;
+ wc->span.chans = wc->chans;
+ wc->span.flags = ZT_FLAG_RBS;
+ wc->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
+ wc->span.pvt = wc;
+ if (wc->spantype == TYPE_E1)
+ wc->span.deflaw = ZT_LAW_ALAW;
+ else
+ wc->span.deflaw = ZT_LAW_MULAW;
+ init_waitqueue_head(&wc->span.maintq);
+ for (x = 0; x < wc->span.channels; x++) {
+ sprintf(wc->chans[x].name, "WCT1/%d/%d", wc->num, x + 1);
+ wc->chans[x].sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_EM_E1 |
+ ZT_SIG_FXSLS | ZT_SIG_FXSGS |
+ ZT_SIG_FXSKS | ZT_SIG_FXOLS | ZT_SIG_DACS_RBS |
+ ZT_SIG_FXOGS | ZT_SIG_FXOKS | ZT_SIG_CAS | ZT_SIG_SF;
+ wc->chans[x].pvt = wc;
+ wc->chans[x].chanpos = x + 1;
+ }
+ if (zt_register(&wc->span, 0)) {
+ module_printk("Unable to register span with Zaptel\n");
+ return -1;
+ }
+ wc->initialized = 1;
+
+ return 0;
+}
+
+static int t1_hardware_post_init(struct t1 *wc)
+{
+ unsigned int reg;
+ int x;
+
+ /* T1 or E1 */
+ if (t1e1override > -1) {
+ if (t1e1override)
+ wc->spantype = TYPE_E1;
+ else
+ wc->spantype = TYPE_T1;
+ } else {
+ if (t1_getpins(wc,0) & 0x01) /* returns 1 for T1 mode */
+ wc->spantype = TYPE_T1;
+ else
+ wc->spantype = TYPE_E1;
+ }
+ debug_printk(1, "spantype: %s\n", wc->spantype==1 ? "T1" : "E1");
+
+ if (wc->spantype == TYPE_E1) {
+ if (unchannelized)
+ wc->chanmap = chanmap_e1uc;
+ else
+ wc->chanmap = chanmap_e1;
+ } else
+ wc->chanmap = chanmap_t1;
+ /* what version of the FALC are we using? */
+ reg = t1_setreg(wc, 0x4a, 0xaa);
+ reg = t1_getreg(wc, 0x4a, 0);
+ debug_printk(1, "FALC version: %08x\n", reg);
+
+ /* make sure reads and writes work */
+ for (x = 0; x < 256; x++) {
+ t1_setreg(wc, 0x14, x);
+ if ((reg = t1_getreg(wc, 0x14, 0)) != x)
+ module_printk("Wrote '%x' but read '%x'\n", x, reg);
+ }
+
+ /* all LED's blank */
+ wc->ledtestreg = UNSET_LED_ORANGE(wc->ledtestreg);
+ wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg);
+ t1_setleds(wc, wc->ledtestreg, 0);
+
+ return 0;
+}
+
+static inline void __t1_check_alarms_reads(struct t1 *wc)
+{
+ if (!(wc->span.flags & ZT_FLAG_RUNNING))
+ return;
+
+ if (t1_getreg(wc, 0x4c, 1))
+ wc->isrreaderrors++;
+ if (t1_getreg(wc, 0x20, 1))
+ wc->isrreaderrors++;
+ if (t1_getreg(wc, 0x4d, 1))
+ wc->isrreaderrors++;
+}
+
+static inline void __t1_check_alarms(struct t1 *wc)
+{
+ unsigned char c,d;
+ int alarms;
+ int x,j;
+ unsigned char fmr4; /* must read this always */
+
+ if (!(wc->span.flags & ZT_FLAG_RUNNING))
+ return;
+
+ c = t1_getreg_isr(wc, 0x4c);
+ fmr4 = t1_getreg_isr(wc, 0x20); /* must read this even if we don't use it */
+ d = t1_getreg_isr(wc, 0x4d);
+
+ /* Assume no alarms */
+ alarms = 0;
+
+ /* And consider only carrier alarms */
+ wc->span.alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN);
+
+ if (wc->spantype == TYPE_E1) {
+ if (c & 0x04) {
+ /* No multiframe found, force RAI high after 400ms only if
+ we haven't found a multiframe since last loss
+ of frame */
+ if (!wc->flags.nmf) {
+ t1_setreg_full(wc, 0x20, 0x9f | 0x20, 1); /* LIM0: Force RAI High */
+ wc->flags.nmf = 1;
+ module_printk("NMF workaround on!\n");
+ }
+ t1_setreg_full(wc, 0x1e, 0xc3, 1); /* Reset to CRC4 mode */
+ t1_setreg_full(wc, 0x1c, 0xf2, 1); /* Force Resync */
+ t1_setreg_full(wc, 0x1c, 0xf0, 1); /* Force Resync */
+ } else if (!(c & 0x02)) {
+ if (wc->flags.nmf) {
+ t1_setreg_full(wc, 0x20, 0x9f, 1); /* LIM0: Clear forced RAI */
+ wc->flags.nmf = 0;
+ module_printk("NMF workaround off!\n");
+ }
+ }
+ } else {
+ /* Detect loopup code if we're not sending one */
+ if ((!wc->span.mainttimer) && (d & 0x08)) {
+ /* Loop-up code detected */
+ if ((wc->loopupcnt++ > 80) && (wc->span.maintstat != ZT_MAINT_REMOTELOOP)) {
+ t1_setreg_full(wc, 0x36, 0x08, 1); /* LIM0: Disable any local loop */
+ t1_setreg_full(wc, 0x37, 0xf6, 1); /* LIM1: Enable remote loop */
+ wc->span.maintstat = ZT_MAINT_REMOTELOOP;
+ }
+ } else
+ wc->loopupcnt = 0;
+ /* Same for loopdown code */
+ if ((!wc->span.mainttimer) && (d & 0x10)) {
+ /* Loop-down code detected */
+ if ((wc->loopdowncnt++ > 80) && (wc->span.maintstat == ZT_MAINT_REMOTELOOP)) {
+ t1_setreg_full(wc, 0x36, 0x08, 1); /* LIM0: Disable any local loop */
+ t1_setreg_full(wc, 0x37, 0xf0, 1); /* LIM1: Disable remote loop */
+ wc->span.maintstat = ZT_MAINT_NONE;
+ }
+ } else
+ wc->loopdowncnt = 0;
+ }
+
+ if (wc->span.lineconfig & ZT_CONFIG_NOTOPEN) {
+ for (x=0,j=0;x < wc->span.channels;x++)
+ if ((wc->span.chans[x].flags & ZT_FLAG_OPEN) ||
+ (wc->span.chans[x].flags & ZT_FLAG_NETDEV))
+ j++;
+ if (!j)
+ alarms |= ZT_ALARM_NOTOPEN;
+ }
+
+ if (c & 0xa0) {
+ if (wc->alarmcount >= alarmdebounce) {
+ if (!unchannelized)
+ alarms |= ZT_ALARM_RED;
+ } else
+ wc->alarmcount++;
+ } else
+ wc->alarmcount = 0;
+ if (c & 0x4)
+ alarms |= ZT_ALARM_BLUE;
+
+ /* Keep track of recovering */
+ if ((!alarms) && wc->span.alarms)
+ wc->alarmtimer = ZT_ALARMSETTLE_TIME;
+ if (wc->alarmtimer)
+ alarms |= ZT_ALARM_RECOVER;
+
+ /* If receiving alarms, go into Yellow alarm state */
+ if (alarms && !wc->flags.sendingyellow) {
+ module_printk("Setting yellow alarm\n");
+
+ /* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */
+ t1_setreg_full(wc, 0x20, fmr4 | 0x20, 1);
+ wc->flags.sendingyellow = 1;
+ } else if (!alarms && wc->flags.sendingyellow) {
+ module_printk("Clearing yellow alarm\n");
+ /* We manually do yellow alarm to handle RECOVER */
+ t1_setreg_full(wc, 0x20, fmr4 & ~0x20, 1);
+ wc->flags.sendingyellow = 0;
+ }
+
+ if ((c & 0x10) && !unchannelized)
+ alarms |= ZT_ALARM_YELLOW;
+ if (wc->span.mainttimer || wc->span.maintstat)
+ alarms |= ZT_ALARM_LOOPBACK;
+ wc->span.alarms = alarms;
+ zt_alarm_notify(&wc->span);
+}
+
+static inline void __handle_leds(struct t1 *wc)
+{
+ if (wc->span.alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE)) {
+ wc->blinktimer++;
+ if (wc->blinktimer == 160)
+ wc->ledtestreg = SET_LED_RED(wc->ledtestreg);
+ if (wc->blinktimer == 480) {
+ wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg);
+ wc->blinktimer = 0;
+ }
+ } else if (wc->span.alarms & ZT_ALARM_YELLOW) {
+ wc->yellowtimer++;
+ if (!(wc->yellowtimer % 2))
+ wc->ledtestreg = SET_LED_RED(wc->ledtestreg);
+ else
+ wc->ledtestreg = SET_LED_GREEN(wc->ledtestreg);
+ } else {
+ if (wc->span.maintstat != ZT_MAINT_NONE)
+ wc->ledtestreg = SET_LED_ORANGE(wc->ledtestreg);
+ else
+ wc->ledtestreg = UNSET_LED_ORANGE(wc->ledtestreg);
+ if (wc->span.flags & ZT_FLAG_RUNNING)
+ wc->ledtestreg = SET_LED_GREEN(wc->ledtestreg);
+ else
+ wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg);
+ }
+
+ if (wc->ledtestreg != wc->ledlastvalue) {
+ t1_setleds(wc, wc->ledtestreg, 1);
+ wc->ledlastvalue = wc->ledtestreg;
+ }
+}
+
+
+static void __t1_do_counters(struct t1 *wc)
+{
+ if (wc->alarmtimer) {
+ if (!--wc->alarmtimer) {
+ wc->span.alarms &= ~(ZT_ALARM_RECOVER);
+ zt_alarm_notify(&wc->span);
+ }
+ }
+}
+
+static inline void t1_isr_misc(struct t1 *wc)
+{
+ unsigned int x;
+
+ if (unlikely(!wc->initialized)) return;
+
+ __handle_leds(wc);
+
+ __t1_do_counters(wc);
+
+ x = wc->intcount & 0xF;
+ switch (x) {
+ case 0:
+ __t1_check_sigbits_reads(wc);
+ break;
+ case 1:
+ if (!(wc->intcount & 0x30)) {
+ __t1_check_alarms_reads(wc);
+ wc->alarms_read=1;
+ }
+ break;
+ case 2:
+ break;
+ case 4:
+ break;
+ case 5:
+ break;
+ case 7:
+ __t1_check_sigbits(wc);
+ break;
+ case 8:
+ if (wc->alarms_read) {
+ __t1_check_alarms(wc);
+ wc->alarms_read=0;
+ }
+ break;
+ case 9:
+ clean_leftovers(wc);
+ break;
+ }
+}
+
+static inline void t1_transmitprep(struct t1 *wc, int dbl)
+{
+ volatile unsigned char *writechunk;
+ int x;
+ int y;
+ int chan;
+
+ dbl = dbl % 2;
+
+ writechunk = (volatile unsigned char *)(wc->writechunk);
+ if (dbl)
+ /* Write is at interrupt address. Start writing from normal offset */
+ writechunk += SFRAME_SIZE;
+
+ /* Calculate Transmission */
+ if (likely(wc->initialized))
+ zt_transmit(&wc->span);
+
+ for (x = 0; x < ZT_CHUNKSIZE; x++) {
+ if (likely(wc->initialized)) {
+ for (chan = 0; chan < wc->span.channels; chan++)
+ writechunk[(chan+1)*2] = wc->chans[chan].writechunk[x];
+ }
+
+ /* process the command queue */
+ for (y = 0; y < 7; y++) {
+ cmd_dequeue(wc, writechunk, x, y);
+ }
+
+ if (x < ZT_CHUNKSIZE - 1) {
+ writechunk[EFRAME_SIZE] = wc->ctlreg;
+ writechunk[EFRAME_SIZE + 1] = wc->txident++;
+ }
+ writechunk += (EFRAME_SIZE + EFRAME_GAP);
+ }
+}
+
+static inline void cmd_retransmit(struct t1 *wc)
+{
+ unsigned int x;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+ if (!(wc->cmdq.cmds[x].flags & __CMD_FIN)) {
+ wc->cmdq.cmds[x].flags &= ~(__CMD_TX) ; /* clear __CMD_TX */
+ wc->cmdq.cmds[x].ident = 0;
+ }
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline void t1_receiveprep(struct t1 *wc, int dbl)
+{
+ volatile unsigned char *readchunk;
+ int x,chan;
+ unsigned char expected;
+
+ dbl = dbl % 2;
+
+ readchunk = (volatile unsigned char *)wc->readchunk;
+ if (dbl)
+ readchunk += SFRAME_SIZE;
+ for (x = 0; x < ZT_CHUNKSIZE; x++) {
+ if (likely(wc->initialized)) {
+ for (chan = 0; chan < wc->span.channels; chan++) {
+ wc->chans[chan].readchunk[x]= readchunk[(chan+1)*2];
+ }
+ }
+ if (x < ZT_CHUNKSIZE - 1) {
+ expected = wc->rxident+1;
+ wc->rxident = readchunk[EFRAME_SIZE + 1];
+ if (wc->rxident != expected) {
+ wc->span.irqmisses++;
+ cmd_retransmit(wc);
+ if (unlikely(debug && wc->initialized))
+ module_printk("oops: rxident=%d expected=%d\n", wc->rxident, expected);
+ }
+ }
+ cmd_decipher(wc, readchunk);
+ readchunk += (EFRAME_SIZE + EFRAME_GAP);
+ }
+
+ /* echo cancel */
+
+ if (likely(wc->initialized)) {
+ for (x = 0; x < wc->span.channels; x++) {
+ zt_ec_chunk(&wc->chans[x], wc->chans[x].readchunk, wc->ec_chunk2[x]);
+ memcpy(wc->ec_chunk2[x],wc->ec_chunk1[x],ZT_CHUNKSIZE);
+ memcpy(wc->ec_chunk1[x],wc->chans[x].writechunk,ZT_CHUNKSIZE);
+ }
+ zt_receive(&wc->span);
+ }
+
+ /* Wake up anyone sleeping to read/write a new register */
+ wake_up_interruptible(&wc->regq);
+}
+
+static inline int t1_check_descriptor(struct t1 *wc, int tx)
+{
+ int o2 = 0;
+
+ if (!tx) {
+ o2 += ERING_SIZE * 4;
+ o2 += wc->rdbl * 4;
+ } else {
+ o2 += wc->tdbl * 4;
+ }
+
+ if (!(wc->descripchunk[o2] & 0x80000000)) {
+ if (tx) {
+ wc->txints++;
+ t1_transmitprep(wc, wc->tdbl);
+ t1_reinit_descriptor(wc, tx, wc->tdbl, "txchk");
+ wc->tdbl = (wc->tdbl + 1) % ERING_SIZE;
+ wc->intcount++;
+ t1_isr_misc(wc);
+ } else {
+ wc->rxints++;
+ t1_receiveprep(wc, wc->rdbl);
+ t1_reinit_descriptor(wc, tx, wc->rdbl, "rxchk");
+ wc->rdbl = (wc->rdbl + 1) % ERING_SIZE;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int t1_hardware_init(struct t1 *wc)
+{
+ /* Hardware stuff */
+ unsigned int reg;
+ unsigned long newjiffies;
+
+ /* Initialize descriptors */
+ t1_init_descriptors(wc);
+
+ /* Enable I/O Access */
+ pci_read_config_dword(wc->dev, PCI_COMMAND, &reg);
+ reg |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_dword(wc->dev, PCI_COMMAND, reg);
+ debug_printk(1, "PCI Config reg is %08x\n", reg);
+
+ t1_setctl(wc, 0x0000, 0xfff88001);
+
+ newjiffies = jiffies + HZ/10;
+ while(((reg = t1_getctl(wc,0x0000)) & 0x00000001) && ( time_after(newjiffies,jiffies) ));
+ debug_printk(1, "ctlreg 0x0000 now=%08x!\n", reg);
+
+ /* Configure watchdogs, access, etc */
+ t1_setctl(wc, 0x0030, 0x00280048);
+ t1_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */);
+
+ reg = t1_getctl(wc, 0x00fc);
+ t1_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7); /* normal mode */
+ t1_setsdi(wc, 0x00, 0x0100);
+ t1_setsdi(wc, 0x16, 0x2100);
+ debug_printk(1, "Detected SDI REG0: %08x\n", t1_getsdi(wc, 0x00));
+ debug_printk(1, "Detected SDI REG1: %08x\n", t1_getsdi(wc, 0x01));
+ debug_printk(1, "Detected SDI REG2: %08x\n", t1_getsdi(wc, 0x02));
+
+ reg = t1_getctl(wc, 0x00fc);
+ debug_printk(1, "(pre) Reg fc is %08x\n", reg);
+
+ t1_setctl(wc, 0x00fc, (reg & ~0x7) | 0x4); /* mac only */
+ t1_setsdi(wc, 0x00, 0x0100); /* full duplex */
+ t1_setsdi(wc, 0x16, 0x2100);
+ reg = t1_getctl(wc, 0x00fc);
+ debug_printk(1, "(post) ctlreg 0xfc=%08x\n", reg);
+ debug_printk(1, "Detected SDI REG2: %08x\n", t1_getsdi(wc, 0x02));
+ debug_printk(1, "ctlreg 0x0088=%08x\n", t1_getctl(wc, 0x0088));
+
+ return 0;
+}
+
+
+ZAP_IRQ_HANDLER(te12xp_interrupt)
+{
+ struct t1 *wc = dev_id;
+ unsigned int ints;
+ int res;
+
+ /* Read interrupts */
+ ints = t1_getctl(wc, 0x0028);
+
+ if (!ints)
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+
+ /* clear interrupts interrupts (we only get here if interrupt is for us) */
+ t1_setctl(wc, 0x0028, ints);
+ ints &= wc->intmask;
+
+ if (ints & 0x00000041) {
+ do {
+ res = t1_check_descriptor(wc, 0);
+ res |= t1_check_descriptor(wc, 1);
+ } while(res);
+ }
+
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+}
+
+static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct t1 *wc;
+ struct t1_desc *d = (struct t1_desc *) ent->driver_data;
+ unsigned int x;
+
+ for (x = 0; x < sizeof(ifaces) / sizeof(ifaces[0]); x++)
+ if (!ifaces[x]) break;
+
+ if (x >= sizeof(ifaces) / sizeof(ifaces[0])) {
+ module_printk("Too many interfaces\n");
+ return -EIO;
+ }
+
+ if (pci_enable_device(pdev))
+ return -EIO;
+
+ wc = kmalloc(sizeof(*wc), GFP_KERNEL);
+ if (!wc)
+ return -ENOMEM;
+
+ ifaces[x] = wc;
+ memset(wc, 0, sizeof(*wc));
+ spin_lock_init(&wc->reglock);
+ wc->iobase = pci_resource_start(pdev, 0);
+ wc->dev = pdev;
+ wc->variety = d->name;
+ /* Keep track of whether we need to free the region */
+ if (request_region(wc->iobase, 0xff, te12xp_driver.name))
+ wc->freeregion = 1;
+
+ /* Allocate enough memory for two zt chunks, receive and transmit.
+ * Each sample uses 32 bits. Allocate an extra set just for
+ * control too */
+ wc->writechunk = (int *) pci_alloc_consistent(pdev, PCI_WINDOW_SIZE, &wc->writedma);
+ if (!wc->writechunk) {
+ module_printk("Unable to allocate DMA-able memory\n");
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ kfree(wc);
+ return -ENOMEM;
+ }
+
+ wc->readchunk = wc->writechunk + SFRAME_SIZE / 2; /* in doublewords */
+ wc->readdma = wc->writedma + SFRAME_SIZE * 2; /* in bytes */
+
+ wc->descripchunk = wc->readchunk + SFRAME_SIZE / 2; /* in doublewords */
+ wc->descripdma = wc->readdma + SFRAME_SIZE * 2; /* 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);
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, wc);
+
+ if (request_irq(pdev->irq, te12xp_interrupt, SA_SHIRQ, te12xp_driver.name, wc)) {
+ module_printk("Unable to request IRQ %d\n", pdev->irq);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *) wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ kfree(wc);
+ return -EIO;
+ }
+
+ if (t1_hardware_init(wc)) {
+ /* Set Reset Low */
+ t1_stop_dma(wc);
+ /* Free Resources */
+ free_irq(pdev->irq, wc);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *) wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+
+ kfree(wc);
+ return -EIO;
+
+ }
+
+ t1_enable_interrupts(wc);
+ t1_start_dma(wc);
+ t1_hardware_post_init(wc);
+ t1_software_init(wc);
+ module_printk("Found a %s\n", wc->variety);
+
+ return 0;
+}
+
+static void __devexit te12xp_remove_one(struct pci_dev *pdev)
+{
+ struct t1 *wc = pci_get_drvdata(pdev);
+
+ if (!wc)
+ return;
+
+ /* Stop any DMA */
+ t1_stop_dma(wc);
+
+ /* In case hardware is still there */
+ t1_disable_interrupts(wc);
+
+ if (debug && wc->isrreaderrors)
+ debug_printk(1, "isrreaderrors=%d\n", wc->isrreaderrors);
+
+ /* Immediately free resources */
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ free_irq(pdev->irq, wc);
+
+ /* Release span, possibly delayed */
+ if (!wc->usecount)
+ t1_release(wc);
+ else
+ wc->dead = 1;
+}
+
+static struct pci_device_id te12xp_pci_tbl[] = {
+ { 0xd161, 0x0120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &te12xp},
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, te12xp_pci_tbl);
+
+static struct pci_driver te12xp_driver = {
+ name: "wcte12xp",
+ probe: te12xp_init_one,
+#ifdef LINUX26
+ remove: __devexit_p(te12xp_remove_one),
+#else
+ remove: te12xp_remove_one,
+#endif
+ suspend: NULL,
+ resume: NULL,
+ id_table: te12xp_pci_tbl,
+};
+
+static int __init te12xp_init(void)
+{
+ int res;
+
+ res = pci_module_init(&te12xp_driver);
+
+ return res ? -ENODEV : 0;
+}
+
+
+static void __exit te12xp_cleanup(void)
+{
+ pci_unregister_driver(&te12xp_driver);
+}
+
+#ifdef LINUX26
+module_param(debug, int, S_IRUGO | S_IWUSR);
+module_param(loopback, int, S_IRUGO | S_IWUSR);
+module_param(t1e1override, int, S_IRUGO | S_IWUSR);
+module_param(j1mode, int, S_IRUGO | S_IWUSR);
+module_param(alarmdebounce, int, S_IRUGO | S_IWUSR);
+#else
+MODULE_PARM(debug, "i");
+MODULE_PARM(loopback, "i");
+MODULE_PARM(t1e1override, "i");
+MODULE_PARM(j1mode, "i");
+MODULE_PARM(alarmdebounce, "i");
+#endif
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(te12xp_init);
+module_exit(te12xp_cleanup);
diff --git a/zaptel.c b/zaptel-base.c
index c519310..c519310 100644
--- a/zaptel.c
+++ b/zaptel-base.c
diff --git a/zaptel.h b/zaptel.h
index b7850c4..2f4f8bd 100644
--- a/zaptel.h
+++ b/zaptel.h
@@ -720,29 +720,31 @@ enum {
#define ZT_TRANSCODE_MAGIC 0x74a9c0de
/* Operations */
-#define ZT_TCOP_RESET 1 /* Reset the channel state / codec selection */
+#define ZT_TCOP_ALLOCATE 1 /* Allocate/reset DTE channel */
#define ZT_TCOP_TRANSCODE 2 /* Begin transcoding a block */
#define ZT_TCOP_GETINFO 3 /* Get information (use zt_transcode_info) */
-
+#define ZT_TCOP_RELEASE 4 /* Release DTE channel */
+#define ZT_TCOP_TEST 5 /* test DTE device */
typedef struct zt_transcode_info {
unsigned int op;
unsigned int tcnum;
char name[80];
+ int numchannels;
unsigned int srcfmts;
unsigned int dstfmts;
} ZT_TRANSCODE_INFO;
-#define ZT_TCCONF_USETS (1 << 0) /* Use/update timestamp field */
-#define ZT_TCCONF_USESEQ (1 << 1) /* Use/update seqno field */
+#define ZT_TCCONF_USETS (1 << 0) /* Use/update timestamp field */
+#define ZT_TCCONF_USESEQ (1 << 1) /* Use/update seqno field */
-#define ZT_TCSTAT_DSTRDY (1 << 0) /* Destination data is ready */
-#define ZT_TCSTAT_DSTBUSY (1 << 1) /* Destination data is outstanding */
+#define ZT_TCSTAT_DSTRDY (1 << 0) /* Destination data is ready */
+#define ZT_TCSTAT_DSTBUSY (1 << 1) /* Destination data is outstanding */
-#define __ZT_TRANSCODE_BUFSIZ 16384
-#define ZT_TRANSCODE_HDRLEN 256
-#define ZT_TRANSCODE_BUFSIZ ((__ZT_TRANSCODE_BUFSIZ) - (ZT_TRANSCODE_HDRLEN))
-#define ZT_TRANSCODE_DSTOFFSET (((ZT_TRANSCODE_BUFSIZ) / 2) + ZT_TRANSCODE_HDRLEN)
-#define ZT_TRANSCODE_SRCOFFSET (((ZT_TRANSCODE_BUFSIZ) / 2) + ZT_TRANSCODE_HDRLEN)
+#define __ZT_TRANSCODE_BUFSIZ 16384
+#define ZT_TRANSCODE_HDRLEN 256
+#define ZT_TRANSCODE_BUFSIZ ((__ZT_TRANSCODE_BUFSIZ) - (ZT_TRANSCODE_HDRLEN))
+#define ZT_TRANSCODE_DSTOFFSET (((ZT_TRANSCODE_BUFSIZ) / 2) + ZT_TRANSCODE_HDRLEN)
+#define ZT_TRANSCODE_SRCOFFSET (((ZT_TRANSCODE_BUFSIZ) / 2) + ZT_TRANSCODE_HDRLEN)
typedef struct zt_transcode_header {
unsigned int srcfmt; /* See formats.h -- use TCOP_RESET when you change */
@@ -761,8 +763,6 @@ typedef struct zt_transcode_header {
unsigned int magic; /* Magic value -- ZT_TRANSCODE_MAGIC, read by user */
unsigned int config; /* Read/write by user */
unsigned int status; /* Read/write by user */
-
- /* XXX: fix this to automatically calculate somehow */
unsigned char userhdr[ZT_TRANSCODE_HDRLEN - (sizeof(unsigned int) * 14)]; /* Storage for user parameters */
unsigned char srcdata[ZT_TRANSCODE_BUFSIZ / 2]; /* Storage of source data */
unsigned char dstdata[ZT_TRANSCODE_BUFSIZ / 2]; /* Storage of destination data */
@@ -1438,6 +1438,8 @@ struct zt_transcoder_channel {
wait_queue_head_t ready;
int errorstatus;
int offset;
+ unsigned int chan_built;
+ unsigned int built_fmts;
unsigned int flags;
unsigned int srcfmt;
unsigned int dstfmt;
@@ -1539,26 +1541,6 @@ int zt_transcoder_unregister(struct zt_transcoder *tc);
/* Alert a transcoder */
int zt_transcoder_alert(struct zt_transcoder_channel *ztc);
-/* 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;
-}
-
/* Unregister a span */
int zt_unregister(struct zt_span *span);
diff --git a/zaptel.xml b/zaptel.xml
index c7e4312..b1db337 100644
--- a/zaptel.xml
+++ b/zaptel.xml
@@ -5,24 +5,26 @@
</member>
<member name="torisa" displayname="Tormenta ISA" remove_on_change="torisa.o torisa.ko">
</member>
- <member name="wcfxo" displayname="Wildcard X100P" remove_on_change="wcfxo.o wcfxo.ko">
+ <member name="wcfxo" displayname="Digium Wildcard X100P" remove_on_change="wcfxo.o wcfxo.ko">
</member>
- <member name="wct1xxp" displayname="Wildcard T100P / E100P" remove_on_change="wct1xxp.o wct1xxp.ko">
+ <member name="wct1xxp" displayname="Digium Wildcard T100P / E100P" remove_on_change="wct1xxp.o wct1xxp.ko">
</member>
- <member name="wct4xxp" displayname="Wildcard TE4XXP / TE2XXP" remove_on_change="wct4xxp/wct4xxp.o wct4xxp/wct4xxp.ko">
+ <member name="wct4xxp" displayname="Digium Wildcard TE4XXP / TE2XXP" remove_on_change="wct4xxp/wct4xxp.o wct4xxp/wct4xxp.ko">
</member>
- <member name="wctc4xxp" displayname="Wildcard TC400B" remove_on_change="wctc4xxp/wctc4xxp.o wctc4xxp/wctc4xxp.ko">
+ <member name="wctc4xxp" displayname="Digium Wildcard TC400B" remove_on_change="wctc4xxp/wctc4xxp.o wctc4xxp/wctc4xxp.ko">
<depend>zttranscode</depend>
</member>
- <member name="wctdm" displayname="Wildcard TDM400P" remove_on_change="wctdm.o wctdm.ko">
+ <member name="wctdm" displayname="Digium Wildcard TDM400P" remove_on_change="wctdm.o wctdm.ko">
</member>
- <member name="wctdm24xxp" displayname="Wildcard TDM2400P / TDM800P" remove_on_change="wctdm24xxp.o wctdm24xxp.ko">
+ <member name="wctdm24xxp" displayname="Digium Wildcard TDM2400P / TDM800P" remove_on_change="wctdm24xxp.o wctdm24xxp.ko">
</member>
- <member name="wcte11xp" displayname="Wildcard TE110P" remove_on_change="wcte11xp.o wcte11xp.ko">
+ <member name="wcte11xp" displayname="Digium Wildcard TE110P" remove_on_change="wcte11xp.o wcte11xp.ko">
</member>
- <member name="wcusb" displayname="Wildcard S100U" remove_on_change="wcusb.o wcusb.ko">
+ <member name="wcte12xp" displayname="Digium Wildcard TE120P" remove_on_change="wcte12xp.o wcte12xp.ko">
</member>
- <member name="xpp_usb" displayname="Xorcom Astribank">
+ <member name="wcusb" displayname="Digium S100U" remove_on_change="wcusb.o wcusb.ko">
+ </member>
+ <member name="xpp" displayname="Xorcom Astribank">
</member>
<member name="ztd-eth" displayname="TDM-over-Ethernet Virtual Span" remove_on_change="ztd-eth.o ztd-eth.ko">
<depend>ztdynamic</depend>
diff --git a/zttranscode.c b/zttranscode.c
index 7e3d287..cf99b8a 100644
--- a/zttranscode.c
+++ b/zttranscode.c
@@ -3,7 +3,7 @@
*
* Written by Mark Spencer <markster@digium.com>
*
- * Copyright (C) 2006, Digium, Inc.
+ * Copyright (C) 2006-2007, Digium, Inc.
*
* All rights reserved.
*
@@ -42,7 +42,7 @@
#ifdef STANDALONE_ZAPATA
#include "zaptel.h"
#else
-#include <zaptel/zaptel.h>
+#include <linux/zaptel.h>
#endif
#ifdef LINUX26
#include <linux/moduleparam.h>
@@ -74,6 +74,8 @@ struct zt_transcoder *zt_transcoder_alloc(int numchans)
init_waitqueue_head(&ztc->channels[x].ready);
ztc->channels[x].parent = ztc;
ztc->channels[x].offset = x;
+ ztc->channels[x].chan_built = 0;
+ ztc->channels[x].built_fmts = 0;
}
return ztc;
@@ -207,15 +209,18 @@ static void ztc_release(struct zt_transcoder_channel *ztc)
if (!ztc)
return;
- for (page = virt_to_page(zth);
- page < virt_to_page((unsigned long) zth + sizeof(*zth));
- page++)
- ClearPageReserved(page);
-
ztc->flags &= ~(ZT_TC_FLAG_BUSY);
- if (ztc->tch)
+
+ if(ztc->tch) {
+ for (page = virt_to_page(zth);
+ page < virt_to_page((unsigned long) zth + sizeof(*zth));
+ page++)
+ ClearPageReserved(page);
kfree(ztc->tch);
+ }
+
ztc->tch = NULL;
+ /* Actually reset the transcoder channel */
if (ztc->flags & ZT_TC_FLAG_TRANSIENT)
kfree(ztc);
if (debug)
@@ -252,6 +257,8 @@ static int do_reset(struct zt_transcoder_channel **ztc)
for (x = 0; x < tc->numchannels; x++) {
if (tc->channels[x].flags & ZT_TC_FLAG_BUSY)
continue;
+ if ((tc->channels[x].chan_built) && ((zth->srcfmt | zth->dstfmt) != tc->channels[x].built_fmts))
+ continue;
newztc = &tc->channels[x];
newztc->flags = ZT_TC_FLAG_BUSY;
@@ -274,7 +281,7 @@ static int do_reset(struct zt_transcoder_channel **ztc)
/* Actually reset the transcoder channel */
if ((*ztc)->parent && ((*ztc)->parent->operation))
- return (*ztc)->parent->operation((*ztc), ZT_TCOP_RESET);
+ return (*ztc)->parent->operation((*ztc), ZT_TCOP_ALLOCATE);
return -EINVAL;
}
@@ -308,6 +315,7 @@ static int zt_tc_getinfo(unsigned long data)
return -ENOSYS;
strncpy(info.name, tc->name, sizeof(info.name) - 1);
+ info.numchannels = tc->numchannels;
info.srcfmts = tc->srcfmts;
info.dstfmts = tc->dstfmts;
@@ -333,11 +341,17 @@ static int zt_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case ZT_TCOP_GETINFO:
ret = zt_tc_getinfo(data);
break;
- case ZT_TCOP_RESET:
+ case ZT_TCOP_ALLOCATE:
/* Reset transcoder, possibly changing who we point to */
ret = do_reset(&ztc);
file->private_data = ztc;
break;
+ case ZT_TCOP_RELEASE:
+ ret = ztc->parent->operation(ztc, ZT_TCOP_RELEASE);
+ break;
+ case ZT_TCOP_TEST:
+ ret = ztc->parent->operation(ztc, ZT_TCOP_TEST);
+ break;
case ZT_TCOP_TRANSCODE:
if (!ztc->parent->operation)
return -EINVAL;
@@ -449,7 +463,7 @@ void zttranscode_cleanup(void)
}
#ifdef LINUX26
-module_param(debug, int, 0600);
+module_param(debug, int, S_IRUGO | S_IWUSR);
#else
MODULE_PARM(debug, "i");
#endif