summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin P. Fleming <kpfleming@digium.com>2008-05-21 15:11:48 +0000
committerKevin P. Fleming <kpfleming@digium.com>2008-05-21 15:11:48 +0000
commit802b567e6c7ba7803a950324cbed13f7d57944cb (patch)
tree6b90ca3119aaa2e4073d3b651ac965dea5d3430e
parentec5ce88e015b41c2f46f6c9b783339b945f9502a (diff)
start copying kernel bits
git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@4315 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/GNUmakefile144
-rw-r--r--drivers/dahdi/Kbuild71
-rw-r--r--drivers/dahdi/Makefile6
-rw-r--r--drivers/dahdi/adt_lec.c68
-rw-r--r--drivers/dahdi/adt_lec.h43
-rw-r--r--drivers/dahdi/arith.h364
-rw-r--r--drivers/dahdi/biquad.h73
-rw-r--r--drivers/dahdi/datamods/Makefile32
-rw-r--r--drivers/dahdi/datamods/hdlc_cisco.c335
-rw-r--r--drivers/dahdi/datamods/hdlc_fr.c1273
-rw-r--r--drivers/dahdi/datamods/hdlc_generic.c355
-rw-r--r--drivers/dahdi/datamods/hdlc_ppp.c114
-rw-r--r--drivers/dahdi/datamods/hdlc_raw.c89
-rw-r--r--drivers/dahdi/datamods/hdlc_raw_eth.c107
-rw-r--r--drivers/dahdi/datamods/syncppp.c1485
-rw-r--r--drivers/dahdi/digits.h48
-rw-r--r--drivers/dahdi/ecdis.h118
-rw-r--r--drivers/dahdi/fasthdlc.h462
-rw-r--r--drivers/dahdi/fir.h130
-rw-r--r--drivers/dahdi/fxo_modes.h588
-rw-r--r--drivers/dahdi/hpec/hpec.h47
-rw-r--r--drivers/dahdi/hpec/hpec_user.h40
-rw-r--r--drivers/dahdi/hpec/hpec_zaptel.h146
-rw-r--r--drivers/dahdi/jpah.h104
-rw-r--r--drivers/dahdi/kb1ec.h597
-rw-r--r--drivers/dahdi/kb1ec_const.h72
-rw-r--r--drivers/dahdi/makefw.c88
-rw-r--r--drivers/dahdi/mg2ec.h725
-rw-r--r--drivers/dahdi/mg2ec_const.h88
-rw-r--r--drivers/dahdi/pciradio.c1935
-rw-r--r--drivers/dahdi/pciradio.rbt10531
-rw-r--r--drivers/dahdi/proslic.h190
-rw-r--r--drivers/dahdi/sec-2.h451
-rw-r--r--drivers/dahdi/sec.h310
-rw-r--r--drivers/dahdi/tor2-hw.h187
-rw-r--r--drivers/dahdi/tor2.c1521
-rw-r--r--drivers/dahdi/torisa.c1172
-rw-r--r--drivers/dahdi/tormenta2.rbt17482
-rw-r--r--drivers/dahdi/voicebus.c1492
-rw-r--r--drivers/dahdi/voicebus.h53
-rw-r--r--drivers/dahdi/wcfxo.c1103
-rw-r--r--drivers/dahdi/wct1xxp.c1438
-rw-r--r--drivers/dahdi/wct4xxp/Kbuild27
-rw-r--r--drivers/dahdi/wct4xxp/Makefile36
-rw-r--r--drivers/dahdi/wct4xxp/base.c3892
-rw-r--r--drivers/dahdi/wct4xxp/vpm450m.c577
-rw-r--r--drivers/dahdi/wct4xxp/vpm450m.h44
-rw-r--r--drivers/dahdi/wct4xxp/wct4xxp-diag.c414
-rw-r--r--drivers/dahdi/wct4xxp/wct4xxp.h114
-rw-r--r--drivers/dahdi/wctc4xxp/Kbuild20
-rw-r--r--drivers/dahdi/wctc4xxp/Makefile16
-rw-r--r--drivers/dahdi/wctc4xxp/base.c2023
-rw-r--r--drivers/dahdi/wctc4xxp/codec_test.c332
-rw-r--r--drivers/dahdi/wctdm.c2559
-rw-r--r--drivers/dahdi/wctdm.h69
-rw-r--r--drivers/dahdi/wctdm24xxp/GpakApi.c1627
-rw-r--r--drivers/dahdi/wctdm24xxp/GpakApi.h637
-rw-r--r--drivers/dahdi/wctdm24xxp/GpakCust.c476
-rw-r--r--drivers/dahdi/wctdm24xxp/GpakCust.h181
-rw-r--r--drivers/dahdi/wctdm24xxp/GpakHpi.h80
-rw-r--r--drivers/dahdi/wctdm24xxp/Kbuild25
-rw-r--r--drivers/dahdi/wctdm24xxp/Makefile27
-rw-r--r--drivers/dahdi/wctdm24xxp/base.c4063
-rw-r--r--drivers/dahdi/wctdm24xxp/gpakErrs.h156
-rw-r--r--drivers/dahdi/wctdm24xxp/gpakenum.h192
-rw-r--r--drivers/dahdi/wctdm24xxp/wctdm24xxp.h277
-rw-r--r--drivers/dahdi/wcte11xp.c1644
-rw-r--r--drivers/dahdi/wcte12xp/GpakApi.c1617
-rw-r--r--drivers/dahdi/wcte12xp/GpakApi.h637
-rw-r--r--drivers/dahdi/wcte12xp/GpakErrs.h156
-rw-r--r--drivers/dahdi/wcte12xp/GpakHpi.h80
-rw-r--r--drivers/dahdi/wcte12xp/Kbuild25
-rw-r--r--drivers/dahdi/wcte12xp/Makefile25
-rw-r--r--drivers/dahdi/wcte12xp/base.c1763
-rw-r--r--drivers/dahdi/wcte12xp/gpakenum.h191
-rw-r--r--drivers/dahdi/wcte12xp/vpmadt032.c1307
-rw-r--r--drivers/dahdi/wcte12xp/vpmadt032.h148
-rw-r--r--drivers/dahdi/wcte12xp/wcte12xp.h166
-rw-r--r--drivers/dahdi/wcusb.c1490
-rw-r--r--drivers/dahdi/wcusb.h142
-rw-r--r--drivers/dahdi/xpp/.version1
-rw-r--r--drivers/dahdi/xpp/Changelog_xpp317
-rw-r--r--drivers/dahdi/xpp/Kbuild58
-rw-r--r--drivers/dahdi/xpp/Makefile7
-rw-r--r--drivers/dahdi/xpp/README.Astribank1374
-rwxr-xr-xdrivers/dahdi/xpp/calibrate_slics308
-rw-r--r--drivers/dahdi/xpp/card_bri.c1506
-rw-r--r--drivers/dahdi/xpp/card_bri.h31
-rw-r--r--drivers/dahdi/xpp/card_fxo.c1289
-rw-r--r--drivers/dahdi/xpp/card_fxo.h42
-rw-r--r--drivers/dahdi/xpp/card_fxs.c1488
-rw-r--r--drivers/dahdi/xpp/card_fxs.h42
-rw-r--r--drivers/dahdi/xpp/card_global.c835
-rw-r--r--drivers/dahdi/xpp/card_global.h113
-rw-r--r--drivers/dahdi/xpp/card_pri.c1632
-rw-r--r--drivers/dahdi/xpp/card_pri.h32
-rw-r--r--drivers/dahdi/xpp/firmwares/FPGA_1141.hex651
-rw-r--r--drivers/dahdi/xpp/firmwares/FPGA_1151.hex702
-rw-r--r--drivers/dahdi/xpp/firmwares/FPGA_FXS.hex650
-rw-r--r--drivers/dahdi/xpp/firmwares/LICENSE.firmware37
-rw-r--r--drivers/dahdi/xpp/firmwares/README19
-rw-r--r--drivers/dahdi/xpp/firmwares/USB_FW.hex223
-rwxr-xr-xdrivers/dahdi/xpp/init_card_1_30535
-rwxr-xr-xdrivers/dahdi/xpp/init_card_2_30417
-rwxr-xr-xdrivers/dahdi/xpp/init_card_3_30439
-rwxr-xr-xdrivers/dahdi/xpp/init_card_4_30387
-rwxr-xr-xdrivers/dahdi/xpp/param_doc40
-rw-r--r--drivers/dahdi/xpp/parport_debug.c113
-rw-r--r--drivers/dahdi/xpp/parport_debug.h31
-rw-r--r--drivers/dahdi/xpp/utils/Makefile144
-rwxr-xr-xdrivers/dahdi/xpp/utils/astribank_hook57
-rw-r--r--drivers/dahdi/xpp/utils/example_default_zaptel31
-rw-r--r--drivers/dahdi/xpp/utils/fpga_load.886
-rw-r--r--drivers/dahdi/xpp/utils/fpga_load.c1007
-rwxr-xr-xdrivers/dahdi/xpp/utils/genzaptelconf1198
-rw-r--r--drivers/dahdi/xpp/utils/genzaptelconf.8326
-rw-r--r--drivers/dahdi/xpp/utils/hexfile.c567
-rw-r--r--drivers/dahdi/xpp/utils/hexfile.h123
-rwxr-xr-xdrivers/dahdi/xpp/utils/lszaptel108
-rw-r--r--drivers/dahdi/xpp/utils/print_modes.c33
-rw-r--r--drivers/dahdi/xpp/utils/test_parse.c35
-rw-r--r--drivers/dahdi/xpp/utils/xpp.rules14
-rwxr-xr-xdrivers/dahdi/xpp/utils/xpp_blink168
-rw-r--r--drivers/dahdi/xpp/utils/xpp_fxloader297
-rw-r--r--drivers/dahdi/xpp/utils/xpp_fxloader.usermap10
-rw-r--r--drivers/dahdi/xpp/utils/xpp_modprobe10
-rwxr-xr-xdrivers/dahdi/xpp/utils/xpp_sync226
-rwxr-xr-xdrivers/dahdi/xpp/utils/xpp_timing6
-rwxr-xr-xdrivers/dahdi/xpp/utils/zapconf603
-rw-r--r--drivers/dahdi/xpp/utils/zaptel-helper401
-rwxr-xr-xdrivers/dahdi/xpp/utils/zaptel_drivers9
-rwxr-xr-xdrivers/dahdi/xpp/utils/zaptel_hardware164
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel.pm68
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel/Chans.pm202
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel/Config/Defaults.pm56
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware.pm168
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware/PCI.pm208
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware/USB.pm116
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel/Span.pm300
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel/Utils.pm52
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp.pm199
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Line.pm95
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm118
-rw-r--r--drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm123
-rwxr-xr-xdrivers/dahdi/xpp/utils/zt_registration125
-rw-r--r--drivers/dahdi/xpp/xbus-core.c1708
-rw-r--r--drivers/dahdi/xpp/xbus-core.h305
-rw-r--r--drivers/dahdi/xpp/xbus-pcm.c1303
-rw-r--r--drivers/dahdi/xpp/xbus-pcm.h134
-rw-r--r--drivers/dahdi/xpp/xbus-sysfs.c427
-rw-r--r--drivers/dahdi/xpp/xdefs.h133
-rw-r--r--drivers/dahdi/xpp/xframe_queue.c269
-rw-r--r--drivers/dahdi/xpp/xframe_queue.h34
-rw-r--r--drivers/dahdi/xpp/xpd.h226
-rw-r--r--drivers/dahdi/xpp/xpp_log.h52
-rw-r--r--drivers/dahdi/xpp/xpp_usb.c1107
-rw-r--r--drivers/dahdi/xpp/xpp_zap.c1087
-rw-r--r--drivers/dahdi/xpp/xpp_zap.h53
-rw-r--r--drivers/dahdi/xpp/xproto.c478
-rw-r--r--drivers/dahdi/xpp/xproto.h292
-rw-r--r--drivers/dahdi/xpp/zap_debug.c91
-rw-r--r--drivers/dahdi/xpp/zap_debug.h201
-rw-r--r--drivers/dahdi/zaptel-base.c7801
-rw-r--r--drivers/dahdi/zaptel.h2107
-rw-r--r--drivers/dahdi/zconfig.h197
-rw-r--r--drivers/dahdi/ztd-eth.c451
-rw-r--r--drivers/dahdi/ztd-loc.c282
-rw-r--r--drivers/dahdi/ztdummy.c429
-rw-r--r--drivers/dahdi/ztdummy.h152
-rw-r--r--drivers/dahdi/ztdynamic.c870
-rw-r--r--drivers/dahdi/zttranscode.c491
171 files changed, 114384 insertions, 0 deletions
diff --git a/drivers/dahdi/GNUmakefile b/drivers/dahdi/GNUmakefile
new file mode 100644
index 0000000..6da0928
--- /dev/null
+++ b/drivers/dahdi/GNUmakefile
@@ -0,0 +1,144 @@
+#
+# Zaptel kernel 2.4 makefile
+#
+# Copyright (C) 2008 Digium, Inc.
+#
+
+CFLAGS+=-DSTANDALONE_ZAPATA
+
+ifeq ($(MAKELEVEL),0)
+PWD:=$(shell pwd)
+endif
+
+KINCLUDES:=$(KSRC)/include
+
+BUILDVER:=linux24
+
+HOTPLUG_FIRMWARE:=no
+
+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
+
+BUILD_MODULES:=$(BUILD_TOPDIR_MODULES) $(BUILD_SUBDIR_MODULES)
+ALL_MODULES := $(BUILD_TOPDIR_MODULES:%=%.o) \
+ $(join $(BUILD_SUBDIR_MODULES:%=%/), $(BUILD_SUBDIR_MODULES:%=%.o))
+
+OPTFLAG=-O2
+CFLAGS+=-I. $(OPTFLAGS) -g -fPIC -Wall -DBUILDING_TONEZONE #-DTONEZONE_DRIVER
+ifneq (,$(findstring ppc,$(UNAME_M)))
+CFLAGS_PPC:=-fsigned-char
+endif
+ifneq (,$(findstring x86_64,$(UNAME_M)))
+CFLAGS_x86_64:=-m64
+endif
+CFLAGS+=$(CFLAGS_PPC) $(CFLAGS_x86_64)
+KFLAGS=-I$(KINCLUDES) -O6
+KFLAGS+=-DMODULE -D__KERNEL__ -DEXPORT_SYMTAB -I$(KSRC)/drivers/net \
+ -Wall -I. -Wstrict-prototypes -fomit-frame-pointer -I$(KSRC)/drivers/net/wan -I$(KINCLUDES)/net
+ifneq (,$(wildcard $(KINCLUDES)/linux/modversions.h))
+ KFLAGS+=-DMODVERSIONS -include $(KINCLUDES)/linux/modversions.h
+endif
+ifneq (,$(findstring ppc,$(UNAME_M)))
+KFLAGS_PPC:=-msoft-float -fsigned-char
+endif
+KFLAGS+=$(KFLAGS_PPC)
+ ifneq (,$(findstring x86_64,$(UNAME_M)))
+ KFLAGS+=-mcmodel=kernel
+ endif
+
+#
+# Features are now configured in zconfig.h
+#
+
+MODULE_ALIASES=wcfxs wctdm8xxp wct2xxp
+
+KFLAGS+=-DSTANDALONE_ZAPATA
+
+MOD_DIR:=/lib/modules/$(KVERS)/misc
+
+MAKE_SUBDIR = $(MAKE) CC=$(CC) LD=$(LD) \
+ KFLAGS="$(KFLAGS) -I.." CFLAGS="$(CFLAGS) -I.."
+
+all: modules
+
+ifeq ($(HPEC_PRESENT),yes)
+ifeq ($(ARCH),i386)
+ZAPTEL_HPEC:=hpec/hpec_x86_32.o_shipped
+endif
+
+ifeq ($(ARCH),x86_64)
+ZAPTEL_HPEC:=hpec/hpec_x86_64.o_shipped
+endif
+
+KFLAGS+=-DECHO_CAN_HPEC -I$(PWD)/hpec
+zaptel-base.o: hpec/hpec_zaptel.h hpec/hpec_user.h
+endif
+
+prereq: tor2fw.h radfw.h version.h
+
+tor2fw.h: tormenta2.rbt makefw
+ ./makefw $< tor2fw > $@
+
+radfw.h: pciradio.rbt makefw
+ ./makefw $< radfw > $@
+
+makefw: makefw.c
+ $(HOSTCC) -o $@ $^
+
+
+modules: $(ALL_MODULES)
+
+wct4xxp/wct4xxp.o:
+ $(MAKE_SUBDIR) -C wct4xxp
+
+tor2.o: tor2-hw.h tor2fw.h
+
+zaptel-base.o: digits.h arith.h sec.h sec-2.h kb1ec.h mg2ec.h zconfig.h
+
+wcusb.o: wcusb.h
+
+wctdm.o: wctdm.h
+
+wctdm24xxp/wctdm24xxp.o:
+ $(MAKE_SUBDIR) -C wctdm24xxp
+
+wcte12xp/wcte12xp.o:
+ $(MAKE_SUBDIR) -C wcte12xp
+
+pciradio.o: radfw.h
+
+ztdummy.o: ztdummy.h
+
+zaptel.o: zaptel-base.o $(ZAPTEL_HPEC)
+ $(LD) -r -o $@ $< $(ZAPTEL_HPEC)
+
+$(filter-out zaptel.o,$(BUILD_TOPDIR_MODULES:%=%.o)) zaptel-base.o: %.o: %.c zaptel.h
+ $(CC) $(KFLAGS) -o $@ -c $<
+
+
+clean:
+ rm -f makefw tor2fw.h radfw.h
+ rm -f *.o
+ $(MAKE_SUBDIR) -C wct4xxp clean
+ rm -rf .tmp_versions
+ rm -f core
+
+distclean: dist-clean
+
+dist-clean: clean
+
+.PHONY: distclean dist-clean clean all modules
+
diff --git a/drivers/dahdi/Kbuild b/drivers/dahdi/Kbuild
new file mode 100644
index 0000000..6ad4a28
--- /dev/null
+++ b/drivers/dahdi/Kbuild
@@ -0,0 +1,71 @@
+ifdef ECHO_CAN_NAME
+ ECHO_CAN_CFLAGS := -DECHO_CAN_FROMENV -DECHO_CAN_$(ECHO_CAN_NAME)
+endif
+
+obj-m := $(KBUILD_OBJ_M)
+
+EXTRA_CFLAGS := -I$(src) -DSTANDALONE_ZAPATA
+EXTRA_CFLAGS += $(ECHO_CAN_CFLAGS)
+
+# fix typo present in CentOS and RHEL 2.6.9 kernels
+BAD_KERNELS_VERS := 22 34 34.0.1 34.0.2
+BAD_KERNELS := $(foreach ver,$(BAD_KERNELS_VERS),2.6.9-$(ver).EL 2.6.9-$(ver).ELsmp)
+ifneq (,$(filter $(KVERS),$(BAD_KERNELS)))
+EXTRA_CFLAGS+=-Drw_lock_t=rwlock_t
+endif
+
+zaptel-objs := zaptel-base.o
+
+ifeq ($(ARCH),i386)
+ifneq ($(wildcard $(src)/hpec/hpec_x86_32.o_shipped),)
+HPEC_PRESENT=yes
+zaptel-objs += hpec/hpec_x86_32.o
+endif
+endif
+
+ifeq ($(ARCH),x86_64)
+ifneq ($(wildcard $(src)/hpec/hpec_x86_64.o_shipped),)
+HPEC_PRESENT=yes
+zaptel-objs += hpec/hpec_x86_64.o
+endif
+endif
+
+ifeq ($(HPEC_PRESENT),yes)
+EXTRA_CFLAGS += -DECHO_CAN_HPEC -I$(src)/hpec
+$(obj)/zaptel-base.o: $(src)/hpec/hpec_zaptel.h $(src)/hpec/hpec_user.h
+endif
+
+$(obj)/pciradio.o: $(obj)/radfw.h
+$(obj)/tor2.o: $(obj)/tor2fw.h
+
+hostprogs-y := $(obj)/makefw
+
+$(obj)/tor2fw.h: $(src)/tormenta2.rbt $(obj)/makefw
+ $(obj)/makefw $< tor2fw > $@
+
+$(obj)/radfw.h: $(src)/pciradio.rbt $(obj)/makefw
+ $(obj)/makefw $< radfw > $@
+
+$(obj)/makefw: $(src)/makefw.c
+ $(HOSTCC) -o $@ $^
+
+
+# set CONFIG_ZAPTEL_MMX for a number of CPU types.
+# Right now this part is not enabled, unless you build with
+# ZAPTEL_MMX_AUTO=something .
+ZAPMMX_WHITELIST_i386 = M586MMX M686 MPENTIUMII MPENTIUMIII MPENTIUMM \
+ MPENTIUM4 MVIAC3_2
+
+ZAPMMX_WHITELIST_x86_64 =
+
+# A list of configuration variables to test: CONFIG_M686 , etc.
+ZAPMMX_CONFIG_VARS := $(ZAPMMX_WHITELIST_$(ARCH):%=CONFIG_%)
+
+# expand them:
+ZAPMMX_CONFIG_VALS := $(strip $(foreach var,$(ZAPMMX_CONFIG_VARS),$(var)) )
+ifneq (,$(ZAPTEL_MMX_AUTO))
+ ifneq (,$(ZAPMMX_CONFIG_VALS))
+ # TODO: make that
+ CFLAGS_zaptel-base.o += -DCONFIG_ZAPTEL_MMX
+ endif
+endif
diff --git a/drivers/dahdi/Makefile b/drivers/dahdi/Makefile
new file mode 100644
index 0000000..56453cb
--- /dev/null
+++ b/drivers/dahdi/Makefile
@@ -0,0 +1,6 @@
+ifneq ($(KBUILD_EXTMOD),)
+# We only get here on kernels 2.6.0-2.6.9 .
+# For newer kernels, Kbuild will be included directly by the kernel
+# build system.
+include $(src)/Kbuild
+endif
diff --git a/drivers/dahdi/adt_lec.c b/drivers/dahdi/adt_lec.c
new file mode 100644
index 0000000..d191e2b
--- /dev/null
+++ b/drivers/dahdi/adt_lec.c
@@ -0,0 +1,68 @@
+/*
+ * ADT Line Echo Canceller Parameter Parsing
+ *
+ * Copyright (C) 2008 Digium, Inc.
+ *
+ * Kevin P. Fleming <kpfleming@digium.com>
+ *
+ * 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.
+ */
+
+#ifndef _ADT_LEC_C
+#define _ADT_LEC_C
+
+#include <linux/ctype.h>
+
+static inline void adt_lec_init_defaults(struct adt_lec_params *params, __u32 tap_length)
+{
+ memset(params, 0, sizeof(*params));
+ params->tap_length = tap_length;
+}
+
+static int adt_lec_parse_params(struct adt_lec_params *params, struct zt_echocanparams *ecp, struct zt_echocanparam *p)
+{
+ unsigned int x;
+ char *c;
+
+ for (x = 0; x < ecp->param_count; x++) {
+ for (c = p[x].name; *c; c++)
+ *c = tolower(*c);
+ if (!strcmp(p[x].name, "nlp_type")) {
+ switch (p[x].value) {
+ case ADT_LEC_NLP_OFF:
+ case ADT_LEC_NLP_MUTE:
+ case ADT_LEC_RANDOM_NOISE:
+ case ADT_LEC_HOTH_NOISE:
+ case ADT_LEC_SUPPRESS:
+ params->nlp_type = p[x].value;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (!strcmp(p[x].name, "nlp_thresh")) {
+ params->nlp_threshold = p[x].value;
+ } else if (!strcmp(p[x].name, "nlp_suppress")) {
+ params->nlp_max_suppress = p[x].value;
+ } else {
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+#endif /* _ADT_LEC_C */
diff --git a/drivers/dahdi/adt_lec.h b/drivers/dahdi/adt_lec.h
new file mode 100644
index 0000000..c91020d
--- /dev/null
+++ b/drivers/dahdi/adt_lec.h
@@ -0,0 +1,43 @@
+/*
+ * ADT Line Echo Canceller Parameter Parsing
+ *
+ * Copyright (C) 2008 Digium, Inc.
+ *
+ * Kevin P. Fleming <kpfleming@digium.com>
+ *
+ * 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.
+ */
+
+#ifndef _ADT_LEC_H
+#define _ADT_LEC_H
+
+enum adt_lec_nlp_type {
+ ADT_LEC_NLP_OFF = 0,
+ ADT_LEC_NLP_MUTE,
+ ADT_LEC_RANDOM_NOISE,
+ ADT_LEC_HOTH_NOISE,
+ ADT_LEC_SUPPRESS,
+};
+
+struct adt_lec_params {
+ __u32 tap_length;
+ enum adt_lec_nlp_type nlp_type;
+ __u32 nlp_threshold;
+ __u32 nlp_max_suppress;
+};
+
+#endif /* _ADT_LEC_H */
diff --git a/drivers/dahdi/arith.h b/drivers/dahdi/arith.h
new file mode 100644
index 0000000..3059db5
--- /dev/null
+++ b/drivers/dahdi/arith.h
@@ -0,0 +1,364 @@
+#ifndef _ZAPTEL_ARITH_H
+#define _ZAPTEL_ARITH_H
+/*
+ * Handy add/subtract functions to operate on chunks of shorts.
+ * Feel free to add customizations for additional architectures
+ *
+ */
+
+#ifdef CONFIG_ZAPTEL_MMX
+#ifdef ZT_CHUNKSIZE
+static inline void __ACSS(volatile short *dst, const short *src)
+{
+ __asm__ __volatile__ (
+ "movq 0(%0), %%mm0;\n"
+ "movq 0(%1), %%mm1;\n"
+ "movq 8(%0), %%mm2;\n"
+ "movq 8(%1), %%mm3;\n"
+ "paddsw %%mm1, %%mm0;\n"
+ "paddsw %%mm3, %%mm2;\n"
+ "movq %%mm0, 0(%0);\n"
+ "movq %%mm2, 8(%0);\n"
+ : "=r" (dst)
+ : "r" (src), "0" (dst)
+ : "memory"
+#ifdef CLOBBERMMX
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+#endif
+ );
+
+}
+static inline void __SCSS(volatile short *dst, const short *src)
+{
+ __asm__ __volatile__ (
+ "movq 0(%0), %%mm0;\n"
+ "movq 0(%1), %%mm1;\n"
+ "movq 8(%0), %%mm2;\n"
+ "movq 8(%1), %%mm3;\n"
+ "psubsw %%mm1, %%mm0;\n"
+ "psubsw %%mm3, %%mm2;\n"
+ "movq %%mm0, 0(%0);\n"
+ "movq %%mm2, 8(%0);\n"
+ : "=r" (dst)
+ : "r" (src), "0" (dst)
+ : "memory"
+#ifdef CLOBBERMMX
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+#endif
+ );
+
+}
+
+#if (ZT_CHUNKSIZE == 8)
+#define ACSS(a,b) __ACSS(a,b)
+#define SCSS(a,b) __SCSS(a,b)
+#elif (ZT_CHUNKSIZE > 8)
+static inline void ACSS(volatile short *dst, const short *src)
+{
+ int x;
+ for (x=0;x<ZT_CHUNKSIZE;x+=8)
+ __ACSS(dst + x, src + x);
+}
+static inline void SCSS(volatile short *dst, const short *src)
+{
+ int x;
+ for (x=0;x<ZT_CHUNKSIZE;x+=8)
+ __SCSS(dst + x, src + x);
+}
+#else
+#error No MMX for ZT_CHUNKSIZE < 8
+#endif
+#endif
+static inline int CONVOLVE(const int *coeffs, const short *hist, int len)
+{
+ int sum;
+ /* Divide length by 16 */
+ len >>= 4;
+
+ /* Clear our accumulator, mm4 */
+
+ /*
+
+ For every set of eight...
+
+ Load 16 coefficients into four registers...
+ Shift each word right 16 to make them shorts...
+ Pack the resulting shorts into two registers...
+ With the coefficients now in mm0 and mm2, load the
+ history into mm1 and mm3...
+ Multiply/add mm1 into mm0, and mm3 into mm2...
+ Add mm2 into mm0 (without saturation, alas). Now we have two half-results.
+ Accumulate in mm4 (again, without saturation, alas)
+ */
+ __asm__ (
+ "pxor %%mm4, %%mm4;\n"
+ "mov %1, %%edi;\n"
+ "mov %2, %%esi;\n"
+ "mov %3, %%ecx;\n"
+ "1:"
+ "movq 0(%%edi), %%mm0;\n"
+ "movq 8(%%edi), %%mm1;\n"
+ "movq 16(%%edi), %%mm2;\n"
+ "movq 24(%%edi), %%mm3;\n"
+ /* can't use 4/5 since 4 is the accumulator for us */
+ "movq 32(%%edi), %%mm6;\n"
+ "movq 40(%%edi), %%mm7;\n"
+ "psrad $16, %%mm0;\n"
+ "psrad $16, %%mm1;\n"
+ "psrad $16, %%mm2;\n"
+ "psrad $16, %%mm3;\n"
+ "psrad $16, %%mm6;\n"
+ "psrad $16, %%mm7;\n"
+ "packssdw %%mm1, %%mm0;\n"
+ "packssdw %%mm3, %%mm2;\n"
+ "packssdw %%mm7, %%mm6;\n"
+ "movq 0(%%esi), %%mm1;\n"
+ "movq 8(%%esi), %%mm3;\n"
+ "movq 16(%%esi), %%mm7;\n"
+ "pmaddwd %%mm1, %%mm0;\n"
+ "pmaddwd %%mm3, %%mm2;\n"
+ "pmaddwd %%mm7, %%mm6;\n"
+ "paddd %%mm6, %%mm4;\n"
+ "paddd %%mm2, %%mm4;\n"
+ "paddd %%mm0, %%mm4;\n"
+ /* Come back and do for the last few bytes */
+ "movq 48(%%edi), %%mm6;\n"
+ "movq 56(%%edi), %%mm7;\n"
+ "psrad $16, %%mm6;\n"
+ "psrad $16, %%mm7;\n"
+ "packssdw %%mm7, %%mm6;\n"
+ "movq 24(%%esi), %%mm7;\n"
+ "pmaddwd %%mm7, %%mm6;\n"
+ "paddd %%mm6, %%mm4;\n"
+ "add $64, %%edi;\n"
+ "add $32, %%esi;\n"
+ "dec %%ecx;\n"
+ "jnz 1b;\n"
+ "movq %%mm4, %%mm0;\n"
+ "psrlq $32, %%mm0;\n"
+ "paddd %%mm0, %%mm4;\n"
+ "movd %%mm4, %0;\n"
+ : "=r" (sum)
+ : "r" (coeffs), "r" (hist), "r" (len)
+ : "%ecx", "%edi", "%esi"
+ );
+
+ return sum;
+}
+
+static inline void UPDATE(volatile int *taps, const short *history, const int nsuppr, const int ntaps)
+{
+ int i;
+ int correction;
+ for (i=0;i<ntaps;i++) {
+ correction = history[i] * nsuppr;
+ taps[i] += correction;
+ }
+}
+
+static inline void UPDATE2(volatile int *taps, volatile short *taps_short, const short *history, const int nsuppr, const int ntaps)
+{
+ int i;
+ int correction;
+#if 0
+ ntaps >>= 4;
+ /* First, load up taps, */
+ __asm__ (
+ "pxor %%mm4, %%mm4;\n"
+ "mov %0, %%edi;\n"
+ "mov %1, %%esi;\n"
+ "mov %3, %%ecx;\n"
+ "1:"
+ "jnz 1b;\n"
+ "movq %%mm4, %%mm0;\n"
+ "psrlq $32, %%mm0;\n"
+ "paddd %%mm0, %%mm4;\n"
+ "movd %%mm4, %0;\n"
+ : "=r" (taps), "=r" (taps_short)
+ : "r" (history), "r" (nsuppr), "r" (ntaps), "0" (taps)
+ : "%ecx", "%edi", "%esi"
+ );
+#endif
+#if 1
+ for (i=0;i<ntaps;i++) {
+ correction = history[i] * nsuppr;
+ taps[i] += correction;
+ taps_short[i] = taps[i] >> 16;
+ }
+#endif
+}
+
+static inline int CONVOLVE2(const short *coeffs, const short *hist, int len)
+{
+ int sum;
+ /* Divide length by 16 */
+ len >>= 4;
+
+ /* Clear our accumulator, mm4 */
+
+ /*
+
+ For every set of eight...
+ Load in eight coefficients and eight historic samples, multliply add and
+ accumulate the result
+ */
+ __asm__ (
+ "pxor %%mm4, %%mm4;\n"
+ "mov %1, %%edi;\n"
+ "mov %2, %%esi;\n"
+ "mov %3, %%ecx;\n"
+ "1:"
+ "movq 0(%%edi), %%mm0;\n"
+ "movq 8(%%edi), %%mm2;\n"
+ "movq 0(%%esi), %%mm1;\n"
+ "movq 8(%%esi), %%mm3;\n"
+ "pmaddwd %%mm1, %%mm0;\n"
+ "pmaddwd %%mm3, %%mm2;\n"
+ "paddd %%mm2, %%mm4;\n"
+ "paddd %%mm0, %%mm4;\n"
+ "movq 16(%%edi), %%mm0;\n"
+ "movq 24(%%edi), %%mm2;\n"
+ "movq 16(%%esi), %%mm1;\n"
+ "movq 24(%%esi), %%mm3;\n"
+ "pmaddwd %%mm1, %%mm0;\n"
+ "pmaddwd %%mm3, %%mm2;\n"
+ "paddd %%mm2, %%mm4;\n"
+ "paddd %%mm0, %%mm4;\n"
+ "add $32, %%edi;\n"
+ "add $32, %%esi;\n"
+ "dec %%ecx;\n"
+ "jnz 1b;\n"
+ "movq %%mm4, %%mm0;\n"
+ "psrlq $32, %%mm0;\n"
+ "paddd %%mm0, %%mm4;\n"
+ "movd %%mm4, %0;\n"
+ : "=r" (sum)
+ : "r" (coeffs), "r" (hist), "r" (len)
+ : "%ecx", "%edi", "%esi"
+ );
+
+ return sum;
+}
+static inline short MAX16(const short *y, int len, int *pos)
+{
+ int k;
+ short max = 0;
+ int bestpos = 0;
+ for (k=0;k<len;k++) {
+ if (max < y[k]) {
+ bestpos = k;
+ max = y[k];
+ }
+ }
+ *pos = (len - 1 - bestpos);
+ return max;
+}
+
+
+
+#else
+
+#ifdef ZT_CHUNKSIZE
+static inline void ACSS(short *dst, short *src)
+{
+ int x;
+
+ /* Add src to dst with saturation, storing in dst */
+
+#ifdef BFIN
+ for (x = 0; x < ZT_CHUNKSIZE; x++)
+ dst[x] = __builtin_bfin_add_fr1x16(dst[x], src[x]);
+#else
+ int sum;
+
+ for (x = 0; x < ZT_CHUNKSIZE; x++) {
+ sum = dst[x] + src[x];
+ if (sum > 32767)
+ sum = 32767;
+ else if (sum < -32768)
+ sum = -32768;
+ dst[x] = sum;
+ }
+#endif
+}
+
+static inline void SCSS(short *dst, short *src)
+{
+ int x;
+
+ /* Subtract src from dst with saturation, storing in dst */
+#ifdef BFIN
+ for (x = 0; x < ZT_CHUNKSIZE; x++)
+ dst[x] = __builtin_bfin_sub_fr1x16(dst[x], src[x]);
+#else
+ int sum;
+
+ for (x = 0; x < ZT_CHUNKSIZE; x++) {
+ sum = dst[x] - src[x];
+ if (sum > 32767)
+ sum = 32767;
+ else if (sum < -32768)
+ sum = -32768;
+ dst[x] = sum;
+ }
+#endif
+}
+
+#endif /* ZT_CHUNKSIZE */
+
+static inline int CONVOLVE(const int *coeffs, const short *hist, int len)
+{
+ int x;
+ int sum = 0;
+ for (x=0;x<len;x++)
+ sum += (coeffs[x] >> 16) * hist[x];
+ return sum;
+}
+
+static inline int CONVOLVE2(const short *coeffs, const short *hist, int len)
+{
+ int x;
+ int sum = 0;
+ for (x=0;x<len;x++)
+ sum += coeffs[x] * hist[x];
+ return sum;
+}
+
+static inline void UPDATE(int *taps, const short *history, const int nsuppr, const int ntaps)
+{
+ int i;
+ int correction;
+ for (i=0;i<ntaps;i++) {
+ correction = history[i] * nsuppr;
+ taps[i] += correction;
+ }
+}
+
+static inline void UPDATE2(int *taps, short *taps_short, const short *history, const int nsuppr, const int ntaps)
+{
+ int i;
+ int correction;
+ for (i=0;i<ntaps;i++) {
+ correction = history[i] * nsuppr;
+ taps[i] += correction;
+ taps_short[i] = taps[i] >> 16;
+ }
+}
+
+static inline short MAX16(const short *y, int len, int *pos)
+{
+ int k;
+ short max = 0;
+ int bestpos = 0;
+ for (k=0;k<len;k++) {
+ if (max < y[k]) {
+ bestpos = k;
+ max = y[k];
+ }
+ }
+ *pos = (len - 1 - bestpos);
+ return max;
+}
+
+#endif /* MMX */
+#endif /* _ZAPTEL_ARITH_H */
diff --git a/drivers/dahdi/biquad.h b/drivers/dahdi/biquad.h
new file mode 100644
index 0000000..58458a9
--- /dev/null
+++ b/drivers/dahdi/biquad.h
@@ -0,0 +1,73 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * biquad.h - General telephony bi-quad section routines (currently this just
+ * handles canonic/type 2 form)
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ * 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.
+ *
+ */
+
+typedef struct
+{
+ int32_t gain;
+ int32_t a1;
+ int32_t a2;
+ int32_t b1;
+ int32_t b2;
+
+ int32_t z1;
+ int32_t z2;
+} biquad2_state_t;
+
+static inline void biquad2_init (biquad2_state_t *bq,
+ int32_t gain,
+ int32_t a1,
+ int32_t a2,
+ int32_t b1,
+ int32_t b2)
+{
+ bq->gain = gain;
+ bq->a1 = a1;
+ bq->a2 = a2;
+ bq->b1 = b1;
+ bq->b2 = b2;
+
+ bq->z1 = 0;
+ bq->z2 = 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline int16_t biquad2 (biquad2_state_t *bq, int16_t sample)
+{
+ int32_t y;
+ int32_t z0;
+
+ z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2;
+ y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2;
+
+ bq->z2 = bq->z1;
+ bq->z1 = z0 >> 15;
+ y >>= 15;
+ return y;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
diff --git a/drivers/dahdi/datamods/Makefile b/drivers/dahdi/datamods/Makefile
new file mode 100644
index 0000000..310073e
--- /dev/null
+++ b/drivers/dahdi/datamods/Makefile
@@ -0,0 +1,32 @@
+.EXPORT_ALL_VARIABLES:
+MODULES= \
+ hdlc_cisco hdlc_generic hdlc_raw syncppp \
+ hdlc_fr hdlc_ppp hdlc_raw_eth
+
+
+PWD=$(shell pwd)
+
+MODULESO:=$(MODULES:%=%.o)
+MODULESKO:=$(MODULES:%=%.ko)
+KMAKE = $(MAKE) -C $(KSRC) SUBDIRS=$(PWD)
+KMAKE_INST = $(KMAKE) \
+ INSTALL_MOD_PATH=$(INSTALL_PREFIX) INSTALL_MOD_DIR=misc modules_install
+
+obj-m := $(MODULESO)
+#obj-m:=hdlc_raw.o hdlc_cisco.o
+#obj-m := hdlc_cisco.o hdlc_cisco.mod.o hdlc_fr.o hdlc_generic.o hdlc_ppp.o hdlc_raw.o hdlc_raw_eth.o hdlc_raw.mod.o hdlc_x25.o
+
+all:
+ @echo "You don't want to do make here. Do it from up above"
+
+clean:
+ $(KMAKE) clean
+
+install: $(MODULESKO)
+ $(KMAKE_INST)
+
+datamods:
+ @echo "To build: $(obj-m)"
+ @echo $(KSRC)
+ @if [ -z "$(KSRC)" -o ! -d "$(KSRC)" ]; then echo "You do not appear to have the sources for the $(KVERS) kernel installed."; exit 1 ; fi
+ $(KMAKE) modules
diff --git a/drivers/dahdi/datamods/hdlc_cisco.c b/drivers/dahdi/datamods/hdlc_cisco.c
new file mode 100644
index 0000000..1fd0466
--- /dev/null
+++ b/drivers/dahdi/datamods/hdlc_cisco.c
@@ -0,0 +1,335 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Cisco HDLC support
+ *
+ * Copyright (C) 2000 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+#undef DEBUG_HARD_HEADER
+
+#define CISCO_MULTICAST 0x8F /* Cisco multicast address */
+#define CISCO_UNICAST 0x0F /* Cisco unicast address */
+#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */
+#define CISCO_SYS_INFO 0x2000 /* Cisco interface/system info */
+#define CISCO_ADDR_REQ 0 /* Cisco address request */
+#define CISCO_ADDR_REPLY 1 /* Cisco address reply */
+#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
+
+
+static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
+ u16 type, void *daddr, void *saddr,
+ unsigned int len)
+{
+ hdlc_header *data;
+#ifdef DEBUG_HARD_HEADER
+ printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
+#endif
+
+ skb_push(skb, sizeof(hdlc_header));
+ data = (hdlc_header*)skb->data;
+ if (type == CISCO_KEEPALIVE)
+ data->address = CISCO_MULTICAST;
+ else
+ data->address = CISCO_UNICAST;
+ data->control = 0;
+ data->protocol = htons(type);
+
+ return sizeof(hdlc_header);
+}
+
+
+
+static void cisco_keepalive_send(struct net_device *dev, u32 type,
+ u32 par1, u32 par2)
+{
+ struct sk_buff *skb;
+ cisco_packet *data;
+
+ skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet));
+ if (!skb) {
+ printk(KERN_WARNING
+ "%s: Memory squeeze on cisco_keepalive_send()\n",
+ dev->name);
+ return;
+ }
+ skb_reserve(skb, 4);
+ cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0);
+ data = (cisco_packet*)(skb->data + 4);
+
+ data->type = htonl(type);
+ data->par1 = htonl(par1);
+ data->par2 = htonl(par2);
+ data->rel = 0xFFFF;
+ /* we will need do_div here if 1000 % HZ != 0 */
+ data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ));
+
+ skb_put(skb, sizeof(cisco_packet));
+ skb->priority = TC_PRIO_CONTROL;
+ skb->dev = dev;
+ skb->nh.raw = skb->data;
+
+ dev_queue_xmit(skb);
+}
+
+
+
+static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+ hdlc_header *data = (hdlc_header*)skb->data;
+
+ if (skb->len < sizeof(hdlc_header))
+ return __constant_htons(ETH_P_HDLC);
+
+ if (data->address != CISCO_MULTICAST &&
+ data->address != CISCO_UNICAST)
+ return __constant_htons(ETH_P_HDLC);
+
+ switch(data->protocol) {
+ case __constant_htons(ETH_P_IP):
+ case __constant_htons(ETH_P_IPX):
+ case __constant_htons(ETH_P_IPV6):
+ skb_pull(skb, sizeof(hdlc_header));
+ return data->protocol;
+ default:
+ return __constant_htons(ETH_P_HDLC);
+ }
+}
+
+
+static int cisco_rx(struct sk_buff *skb)
+{
+ struct net_device *dev = skb->dev;
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ hdlc_header *data = (hdlc_header*)skb->data;
+ cisco_packet *cisco_data;
+ struct in_device *in_dev;
+ u32 addr, mask;
+
+ if (skb->len < sizeof(hdlc_header))
+ goto rx_error;
+
+ if (data->address != CISCO_MULTICAST &&
+ data->address != CISCO_UNICAST)
+ goto rx_error;
+
+ switch(ntohs(data->protocol)) {
+ case CISCO_SYS_INFO:
+ /* Packet is not needed, drop it. */
+ dev_kfree_skb_any(skb);
+ return NET_RX_SUCCESS;
+
+ case CISCO_KEEPALIVE:
+ if (skb->len != sizeof(hdlc_header) + CISCO_PACKET_LEN &&
+ skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) {
+ printk(KERN_INFO "%s: Invalid length of Cisco "
+ "control packet (%d bytes)\n",
+ dev->name, skb->len);
+ goto rx_error;
+ }
+
+ cisco_data = (cisco_packet*)(skb->data + sizeof(hdlc_header));
+
+ switch(ntohl (cisco_data->type)) {
+ case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
+ in_dev = dev->ip_ptr;
+ addr = 0;
+ mask = ~0; /* is the mask correct? */
+
+ if (in_dev != NULL) {
+ struct in_ifaddr **ifap = &in_dev->ifa_list;
+
+ while (*ifap != NULL) {
+ if (strcmp(dev->name,
+ (*ifap)->ifa_label) == 0) {
+ addr = (*ifap)->ifa_local;
+ mask = (*ifap)->ifa_mask;
+ break;
+ }
+ ifap = &(*ifap)->ifa_next;
+ }
+
+ cisco_keepalive_send(dev, CISCO_ADDR_REPLY,
+ addr, mask);
+ }
+ dev_kfree_skb_any(skb);
+ return NET_RX_SUCCESS;
+
+ case CISCO_ADDR_REPLY:
+ printk(KERN_INFO "%s: Unexpected Cisco IP address "
+ "reply\n", dev->name);
+ goto rx_error;
+
+ case CISCO_KEEPALIVE_REQ:
+ hdlc->state.cisco.rxseq = ntohl(cisco_data->par1);
+ if (hdlc->state.cisco.request_sent &&
+ ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) {
+ hdlc->state.cisco.last_poll = jiffies;
+ if (!hdlc->state.cisco.up) {
+ u32 sec, min, hrs, days;
+ sec = ntohl(cisco_data->time) / 1000;
+ min = sec / 60; sec -= min * 60;
+ hrs = min / 60; min -= hrs * 60;
+ days = hrs / 24; hrs -= days * 24;
+ printk(KERN_INFO "%s: Link up (peer "
+ "uptime %ud%uh%um%us)\n",
+ dev->name, days, hrs,
+ min, sec);
+#if 0
+ netif_carrier_on(dev);
+#endif
+ hdlc->state.cisco.up = 1;
+ }
+ }
+
+ dev_kfree_skb_any(skb);
+ return NET_RX_SUCCESS;
+ } /* switch(keepalive type) */
+ } /* switch(protocol) */
+
+ printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name,
+ data->protocol);
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+
+ rx_error:
+ hdlc->stats.rx_errors++; /* Mark error */
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+}
+
+
+
+static void cisco_timer(unsigned long arg)
+{
+ struct net_device *dev = (struct net_device *)arg;
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+
+ if (hdlc->state.cisco.up &&
+ time_after(jiffies, hdlc->state.cisco.last_poll +
+ hdlc->state.cisco.settings.timeout * HZ)) {
+ hdlc->state.cisco.up = 0;
+ printk(KERN_INFO "%s: Link down\n", dev->name);
+#if 0
+ netif_carrier_off(dev);
+#endif
+ }
+
+ cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
+ ++hdlc->state.cisco.txseq,
+ hdlc->state.cisco.rxseq);
+ hdlc->state.cisco.request_sent = 1;
+ hdlc->state.cisco.timer.expires = jiffies +
+ hdlc->state.cisco.settings.interval * HZ;
+ hdlc->state.cisco.timer.function = cisco_timer;
+ hdlc->state.cisco.timer.data = arg;
+ add_timer(&hdlc->state.cisco.timer);
+}
+
+
+
+static void cisco_start(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ hdlc->state.cisco.up = 0;
+ hdlc->state.cisco.request_sent = 0;
+ hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0;
+
+ init_timer(&hdlc->state.cisco.timer);
+ hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/
+ hdlc->state.cisco.timer.function = cisco_timer;
+ hdlc->state.cisco.timer.data = (unsigned long)dev;
+ add_timer(&hdlc->state.cisco.timer);
+}
+
+
+
+static void cisco_stop(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ del_timer_sync(&hdlc->state.cisco.timer);
+#if 0
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev);
+#endif
+ hdlc->state.cisco.up = 0;
+ hdlc->state.cisco.request_sent = 0;
+}
+
+
+
+int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+ cisco_proto __user *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco;
+ const size_t size = sizeof(cisco_proto);
+ cisco_proto new_settings;
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ int result;
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_PROTO:
+ ifr->ifr_settings.type = IF_PROTO_CISCO;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+ if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_PROTO_CISCO:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if(dev->flags & IFF_UP)
+ return -EBUSY;
+
+ if (copy_from_user(&new_settings, cisco_s, size))
+ return -EFAULT;
+
+ if (new_settings.interval < 1 ||
+ new_settings.timeout < 2)
+ return -EINVAL;
+
+ result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+
+ if (result)
+ return result;
+
+ hdlc_proto_detach(hdlc);
+ memcpy(&hdlc->state.cisco.settings, &new_settings, size);
+ memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+
+ hdlc->proto.start = cisco_start;
+ hdlc->proto.stop = cisco_stop;
+ hdlc->proto.netif_rx = cisco_rx;
+ hdlc->proto.type_trans = cisco_type_trans;
+ hdlc->proto.id = IF_PROTO_CISCO;
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = cisco_hard_header;
+ dev->hard_header_cache = NULL;
+ dev->type = ARPHRD_CISCO;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ dev->addr_len = 0;
+ return 0;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/dahdi/datamods/hdlc_fr.c b/drivers/dahdi/datamods/hdlc_fr.c
new file mode 100644
index 0000000..523afe1
--- /dev/null
+++ b/drivers/dahdi/datamods/hdlc_fr.c
@@ -0,0 +1,1273 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Frame Relay support
+ *
+ * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+
+ Theory of PVC state
+
+ DCE mode:
+
+ (exist,new) -> 0,0 when "PVC create" or if "link unreliable"
+ 0,x -> 1,1 if "link reliable" when sending FULL STATUS
+ 1,1 -> 1,0 if received FULL STATUS ACK
+
+ (active) -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create"
+ -> 1 when "PVC up" and (exist,new) = 1,0
+
+ DTE mode:
+ (exist,new,active) = FULL STATUS if "link reliable"
+ = 0, 0, 0 if "link unreliable"
+ No LMI:
+ active = open and "link reliable"
+ exist = new = not used
+
+ CCITT LMI: ITU-T Q.933 Annex A
+ ANSI LMI: ANSI T1.617 Annex D
+ CISCO LMI: the original, aka "Gang of Four" LMI
+
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/random.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/etherdevice.h>
+#include <linux/hdlc.h>
+
+#undef DEBUG_PKT
+#undef DEBUG_ECN
+#undef DEBUG_LINK
+
+#define FR_UI 0x03
+#define FR_PAD 0x00
+
+#define NLPID_IP 0xCC
+#define NLPID_IPV6 0x8E
+#define NLPID_SNAP 0x80
+#define NLPID_PAD 0x00
+#define NLPID_CCITT_ANSI_LMI 0x08
+#define NLPID_CISCO_LMI 0x09
+
+
+#define LMI_CCITT_ANSI_DLCI 0 /* LMI DLCI */
+#define LMI_CISCO_DLCI 1023
+
+#define LMI_CALLREF 0x00 /* Call Reference */
+#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI locking shift */
+#define LMI_ANSI_CISCO_REPTYPE 0x01 /* report type */
+#define LMI_CCITT_REPTYPE 0x51
+#define LMI_ANSI_CISCO_ALIVE 0x03 /* keep alive */
+#define LMI_CCITT_ALIVE 0x53
+#define LMI_ANSI_CISCO_PVCSTAT 0x07 /* PVC status */
+#define LMI_CCITT_PVCSTAT 0x57
+
+#define LMI_FULLREP 0x00 /* full report */
+#define LMI_INTEGRITY 0x01 /* link integrity report */
+#define LMI_SINGLE 0x02 /* single PVC report */
+
+#define LMI_STATUS_ENQUIRY 0x75
+#define LMI_STATUS 0x7D /* reply */
+
+#define LMI_REPT_LEN 1 /* report type element length */
+#define LMI_INTEG_LEN 2 /* link integrity element length */
+
+#define LMI_CCITT_CISCO_LENGTH 13 /* LMI frame lengths */
+#define LMI_ANSI_LENGTH 14
+
+
+typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned ea1: 1;
+ unsigned cr: 1;
+ unsigned dlcih: 6;
+
+ unsigned ea2: 1;
+ unsigned de: 1;
+ unsigned becn: 1;
+ unsigned fecn: 1;
+ unsigned dlcil: 4;
+#else
+ unsigned dlcih: 6;
+ unsigned cr: 1;
+ unsigned ea1: 1;
+
+ unsigned dlcil: 4;
+ unsigned fecn: 1;
+ unsigned becn: 1;
+ unsigned de: 1;
+ unsigned ea2: 1;
+#endif
+}__attribute__ ((packed)) fr_hdr;
+
+
+static inline u16 q922_to_dlci(u8 *hdr)
+{
+ return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
+}
+
+
+
+static inline void dlci_to_q922(u8 *hdr, u16 dlci)
+{
+ hdr[0] = (dlci >> 2) & 0xFC;
+ hdr[1] = ((dlci << 4) & 0xF0) | 0x01;
+}
+
+
+
+static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
+{
+ pvc_device *pvc = hdlc->state.fr.first_pvc;
+
+ while (pvc) {
+ if (pvc->dlci == dlci)
+ return pvc;
+ if (pvc->dlci > dlci)
+ return NULL; /* the listed is sorted */
+ pvc = pvc->next;
+ }
+
+ return NULL;
+}
+
+
+static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc;
+
+ while (*pvc_p) {
+ if ((*pvc_p)->dlci == dlci)
+ return *pvc_p;
+ if ((*pvc_p)->dlci > dlci)
+ break; /* the list is sorted */
+ pvc_p = &(*pvc_p)->next;
+ }
+
+ pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC);
+ if (!pvc)
+ return NULL;
+
+ memset(pvc, 0, sizeof(pvc_device));
+ pvc->dlci = dlci;
+ pvc->master = dev;
+ pvc->next = *pvc_p; /* Put it in the chain */
+ *pvc_p = pvc;
+ return pvc;
+}
+
+
+static inline int pvc_is_used(pvc_device *pvc)
+{
+ return pvc->main != NULL || pvc->ether != NULL;
+}
+
+
+static inline void pvc_carrier(int on, pvc_device *pvc)
+{
+ if (on) {
+ if (pvc->main)
+ if (!netif_carrier_ok(pvc->main))
+ netif_carrier_on(pvc->main);
+ if (pvc->ether)
+ if (!netif_carrier_ok(pvc->ether))
+ netif_carrier_on(pvc->ether);
+ } else {
+ if (pvc->main)
+ if (netif_carrier_ok(pvc->main))
+ netif_carrier_off(pvc->main);
+ if (pvc->ether)
+ if (netif_carrier_ok(pvc->ether))
+ netif_carrier_off(pvc->ether);
+ }
+}
+
+
+static inline void delete_unused_pvcs(hdlc_device *hdlc)
+{
+ pvc_device **pvc_p = &hdlc->state.fr.first_pvc;
+
+ while (*pvc_p) {
+ if (!pvc_is_used(*pvc_p)) {
+ pvc_device *pvc = *pvc_p;
+ *pvc_p = pvc->next;
+ kfree(pvc);
+ continue;
+ }
+ pvc_p = &(*pvc_p)->next;
+ }
+}
+
+
+static inline struct net_device** get_dev_p(pvc_device *pvc, int type)
+{
+ if (type == ARPHRD_ETHER)
+ return &pvc->ether;
+ else
+ return &pvc->main;
+}
+
+
+static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
+{
+ u16 head_len;
+ struct sk_buff *skb = *skb_p;
+
+ switch (skb->protocol) {
+ case __constant_ntohs(NLPID_CCITT_ANSI_LMI):
+ head_len = 4;
+ skb_push(skb, head_len);
+ skb->data[3] = NLPID_CCITT_ANSI_LMI;
+ break;
+
+ case __constant_ntohs(NLPID_CISCO_LMI):
+ head_len = 4;
+ skb_push(skb, head_len);
+ skb->data[3] = NLPID_CISCO_LMI;
+ break;
+
+ case __constant_ntohs(ETH_P_IP):
+ head_len = 4;
+ skb_push(skb, head_len);
+ skb->data[3] = NLPID_IP;
+ break;
+
+ case __constant_ntohs(ETH_P_IPV6):
+ head_len = 4;
+ skb_push(skb, head_len);
+ skb->data[3] = NLPID_IPV6;
+ break;
+
+ case __constant_ntohs(ETH_P_802_3):
+ head_len = 10;
+ if (skb_headroom(skb) < head_len) {
+ struct sk_buff *skb2 = skb_realloc_headroom(skb,
+ head_len);
+ if (!skb2)
+ return -ENOBUFS;
+ dev_kfree_skb(skb);
+ skb = *skb_p = skb2;
+ }
+ skb_push(skb, head_len);
+ skb->data[3] = FR_PAD;
+ skb->data[4] = NLPID_SNAP;
+ skb->data[5] = FR_PAD;
+ skb->data[6] = 0x80;
+ skb->data[7] = 0xC2;
+ skb->data[8] = 0x00;
+ skb->data[9] = 0x07; /* bridged Ethernet frame w/out FCS */
+ break;
+
+ default:
+ head_len = 10;
+ skb_push(skb, head_len);
+ skb->data[3] = FR_PAD;
+ skb->data[4] = NLPID_SNAP;
+ skb->data[5] = FR_PAD;
+ skb->data[6] = FR_PAD;
+ skb->data[7] = FR_PAD;
+ *(u16*)(skb->data + 8) = skb->protocol;
+ }
+
+ dlci_to_q922(skb->data, dlci);
+ skb->data[2] = FR_UI;
+ return 0;
+}
+
+
+
+static int pvc_open(struct net_device *dev)
+{
+ pvc_device *pvc = dev_to_pvc(dev);
+
+ if ((pvc->master->flags & IFF_UP) == 0)
+ return -EIO; /* Master must be UP in order to activate PVC */
+
+ if (pvc->open_count++ == 0) {
+ hdlc_device *hdlc = dev_to_hdlc(pvc->master);
+ if (hdlc->state.fr.settings.lmi == LMI_NONE)
+ pvc->state.active = hdlc->carrier;
+
+ pvc_carrier(pvc->state.active, pvc);
+ hdlc->state.fr.dce_changed = 1;
+ }
+ return 0;
+}
+
+
+
+static int pvc_close(struct net_device *dev)
+{
+ pvc_device *pvc = dev_to_pvc(dev);
+
+ if (--pvc->open_count == 0) {
+ hdlc_device *hdlc = dev_to_hdlc(pvc->master);
+ if (hdlc->state.fr.settings.lmi == LMI_NONE)
+ pvc->state.active = 0;
+
+ if (hdlc->state.fr.settings.dce) {
+ hdlc->state.fr.dce_changed = 1;
+ pvc->state.active = 0;
+ }
+ }
+ return 0;
+}
+
+
+
+static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ pvc_device *pvc = dev_to_pvc(dev);
+ fr_proto_pvc_info info;
+
+ if (ifr->ifr_settings.type == IF_GET_PROTO) {
+ if (dev->type == ARPHRD_ETHER)
+ ifr->ifr_settings.type = IF_PROTO_FR_ETH_PVC;
+ else
+ ifr->ifr_settings.type = IF_PROTO_FR_PVC;
+
+ if (ifr->ifr_settings.size < sizeof(info)) {
+ /* data size wanted */
+ ifr->ifr_settings.size = sizeof(info);
+ return -ENOBUFS;
+ }
+
+ info.dlci = pvc->dlci;
+ memcpy(info.master, pvc->master->name, IFNAMSIZ);
+ if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info,
+ &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+
+static inline struct net_device_stats *pvc_get_stats(struct net_device *dev)
+{
+ return netdev_priv(dev);
+}
+
+
+
+static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ pvc_device *pvc = dev_to_pvc(dev);
+ struct net_device_stats *stats = pvc_get_stats(dev);
+
+ if (pvc->state.active) {
+ if (dev->type == ARPHRD_ETHER) {
+ int pad = ETH_ZLEN - skb->len;
+ if (pad > 0) { /* Pad the frame with zeros */
+ int len = skb->len;
+ if (skb_tailroom(skb) < pad)
+ if (pskb_expand_head(skb, 0, pad,
+ GFP_ATOMIC)) {
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ skb_put(skb, pad);
+ memset(skb->data + len, 0, pad);
+ }
+ skb->protocol = __constant_htons(ETH_P_802_3);
+ }
+ if (!fr_hard_header(&skb, pvc->dlci)) {
+ stats->tx_bytes += skb->len;
+ stats->tx_packets++;
+ if (pvc->state.fecn) /* TX Congestion counter */
+ stats->tx_compressed++;
+ skb->dev = pvc->master;
+ dev_queue_xmit(skb);
+ return 0;
+ }
+ }
+
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+
+
+static int pvc_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+
+
+static inline void fr_log_dlci_active(pvc_device *pvc)
+{
+ printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n",
+ pvc->master->name,
+ pvc->dlci,
+ pvc->main ? pvc->main->name : "",
+ pvc->main && pvc->ether ? " " : "",
+ pvc->ether ? pvc->ether->name : "",
+ pvc->state.new ? " new" : "",
+ !pvc->state.exist ? "deleted" :
+ pvc->state.active ? "active" : "inactive");
+}
+
+
+
+static inline u8 fr_lmi_nextseq(u8 x)
+{
+ x++;
+ return x ? x : 1;
+}
+
+
+
+static void fr_lmi_send(struct net_device *dev, int fullrep)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct sk_buff *skb;
+ pvc_device *pvc = hdlc->state.fr.first_pvc;
+ int lmi = hdlc->state.fr.settings.lmi;
+ int dce = hdlc->state.fr.settings.dce;
+ int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH;
+ int stat_len = (lmi == LMI_CISCO) ? 6 : 3;
+ u8 *data;
+ int i = 0;
+
+ if (dce && fullrep) {
+ len += hdlc->state.fr.dce_pvc_count * (2 + stat_len);
+ if (len > HDLC_MAX_MRU) {
+ printk(KERN_WARNING "%s: Too many PVCs while sending "
+ "LMI full report\n", dev->name);
+ return;
+ }
+ }
+
+ skb = dev_alloc_skb(len);
+ if (!skb) {
+ printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n",
+ dev->name);
+ return;
+ }
+ memset(skb->data, 0, len);
+ skb_reserve(skb, 4);
+ if (lmi == LMI_CISCO) {
+ skb->protocol = __constant_htons(NLPID_CISCO_LMI);
+ fr_hard_header(&skb, LMI_CISCO_DLCI);
+ } else {
+ skb->protocol = __constant_htons(NLPID_CCITT_ANSI_LMI);
+ fr_hard_header(&skb, LMI_CCITT_ANSI_DLCI);
+ }
+ data = skb->tail;
+ data[i++] = LMI_CALLREF;
+ data[i++] = dce ? LMI_STATUS : LMI_STATUS_ENQUIRY;
+ if (lmi == LMI_ANSI)
+ data[i++] = LMI_ANSI_LOCKSHIFT;
+ data[i++] = lmi == LMI_CCITT ? LMI_CCITT_REPTYPE :
+ LMI_ANSI_CISCO_REPTYPE;
+ data[i++] = LMI_REPT_LEN;
+ data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
+ data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE;
+ data[i++] = LMI_INTEG_LEN;
+ data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq);
+ data[i++] = hdlc->state.fr.rxseq;
+
+ if (dce && fullrep) {
+ while (pvc) {
+ data[i++] = lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT :
+ LMI_ANSI_CISCO_PVCSTAT;
+ data[i++] = stat_len;
+
+ /* LMI start/restart */
+ if (hdlc->state.fr.reliable && !pvc->state.exist) {
+ pvc->state.exist = pvc->state.new = 1;
+ fr_log_dlci_active(pvc);
+ }
+
+ /* ifconfig PVC up */
+ if (pvc->open_count && !pvc->state.active &&
+ pvc->state.exist && !pvc->state.new) {
+ pvc_carrier(1, pvc);
+ pvc->state.active = 1;
+ fr_log_dlci_active(pvc);
+ }
+
+ if (lmi == LMI_CISCO) {
+ data[i] = pvc->dlci >> 8;
+ data[i + 1] = pvc->dlci & 0xFF;
+ } else {
+ data[i] = (pvc->dlci >> 4) & 0x3F;
+ data[i + 1] = ((pvc->dlci << 3) & 0x78) | 0x80;
+ data[i + 2] = 0x80;
+ }
+
+ if (pvc->state.new)
+ data[i + 2] |= 0x08;
+ else if (pvc->state.active)
+ data[i + 2] |= 0x02;
+
+ i += stat_len;
+ pvc = pvc->next;
+ }
+ }
+
+ skb_put(skb, i);
+ skb->priority = TC_PRIO_CONTROL;
+ skb->dev = dev;
+ skb->nh.raw = skb->data;
+
+ dev_queue_xmit(skb);
+}
+
+
+
+static void fr_set_link_state(int reliable, struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ pvc_device *pvc = hdlc->state.fr.first_pvc;
+
+ hdlc->state.fr.reliable = reliable;
+ if (reliable) {
+#if 0
+ if (!netif_carrier_ok(dev))
+ netif_carrier_on(dev);
+#endif
+
+ hdlc->state.fr.n391cnt = 0; /* Request full status */
+ hdlc->state.fr.dce_changed = 1;
+
+ if (hdlc->state.fr.settings.lmi == LMI_NONE) {
+ while (pvc) { /* Activate all PVCs */
+ pvc_carrier(1, pvc);
+ pvc->state.exist = pvc->state.active = 1;
+ pvc->state.new = 0;
+ pvc = pvc->next;
+ }
+ }
+ } else {
+#if 0
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev);
+#endif
+
+ while (pvc) { /* Deactivate all PVCs */
+ pvc_carrier(0, pvc);
+ pvc->state.exist = pvc->state.active = 0;
+ pvc->state.new = 0;
+ if (!hdlc->state.fr.settings.dce)
+ pvc->state.bandwidth = 0;
+ pvc = pvc->next;
+ }
+ }
+}
+
+
+
+static void fr_timer(unsigned long arg)
+{
+ struct net_device *dev = (struct net_device *)arg;
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ int i, cnt = 0, reliable;
+ u32 list;
+
+ if (hdlc->state.fr.settings.dce) {
+ reliable = hdlc->state.fr.request &&
+ time_before(jiffies, hdlc->state.fr.last_poll +
+ hdlc->state.fr.settings.t392 * HZ);
+ hdlc->state.fr.request = 0;
+ } else {
+ hdlc->state.fr.last_errors <<= 1; /* Shift the list */
+ if (hdlc->state.fr.request) {
+ if (hdlc->state.fr.reliable)
+ printk(KERN_INFO "%s: No LMI status reply "
+ "received\n", dev->name);
+ hdlc->state.fr.last_errors |= 1;
+ }
+
+ list = hdlc->state.fr.last_errors;
+ for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1)
+ cnt += (list & 1); /* errors count */
+
+ reliable = (cnt < hdlc->state.fr.settings.n392);
+ }
+
+ if (hdlc->state.fr.reliable != reliable) {
+ printk(KERN_INFO "%s: Link %sreliable\n", dev->name,
+ reliable ? "" : "un");
+ fr_set_link_state(reliable, dev);
+ }
+
+ if (hdlc->state.fr.settings.dce)
+ hdlc->state.fr.timer.expires = jiffies +
+ hdlc->state.fr.settings.t392 * HZ;
+ else {
+ if (hdlc->state.fr.n391cnt)
+ hdlc->state.fr.n391cnt--;
+
+ fr_lmi_send(dev, hdlc->state.fr.n391cnt == 0);
+
+ hdlc->state.fr.last_poll = jiffies;
+ hdlc->state.fr.request = 1;
+ hdlc->state.fr.timer.expires = jiffies +
+ hdlc->state.fr.settings.t391 * HZ;
+ }
+
+ hdlc->state.fr.timer.function = fr_timer;
+ hdlc->state.fr.timer.data = arg;
+ add_timer(&hdlc->state.fr.timer);
+}
+
+
+
+static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ pvc_device *pvc;
+ u8 rxseq, txseq;
+ int lmi = hdlc->state.fr.settings.lmi;
+ int dce = hdlc->state.fr.settings.dce;
+ int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i;
+
+ if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH :
+ LMI_CCITT_CISCO_LENGTH)) {
+ printk(KERN_INFO "%s: Short LMI frame\n", dev->name);
+ return 1;
+ }
+
+ if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI :
+ NLPID_CCITT_ANSI_LMI)) {
+ printk(KERN_INFO "%s: Received non-LMI frame with LMI"
+ " DLCI\n", dev->name);
+ return 1;
+ }
+
+ if (skb->data[4] != LMI_CALLREF) {
+ printk(KERN_INFO "%s: Invalid LMI Call reference (0x%02X)\n",
+ dev->name, skb->data[4]);
+ return 1;
+ }
+
+ if (skb->data[5] != (dce ? LMI_STATUS_ENQUIRY : LMI_STATUS)) {
+ printk(KERN_INFO "%s: Invalid LMI Message type (0x%02X)\n",
+ dev->name, skb->data[5]);
+ return 1;
+ }
+
+ if (lmi == LMI_ANSI) {
+ if (skb->data[6] != LMI_ANSI_LOCKSHIFT) {
+ printk(KERN_INFO "%s: Not ANSI locking shift in LMI"
+ " message (0x%02X)\n", dev->name, skb->data[6]);
+ return 1;
+ }
+ i = 7;
+ } else
+ i = 6;
+
+ if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_REPTYPE :
+ LMI_ANSI_CISCO_REPTYPE)) {
+ printk(KERN_INFO "%s: Not an LMI Report type IE (0x%02X)\n",
+ dev->name, skb->data[i]);
+ return 1;
+ }
+
+ if (skb->data[++i] != LMI_REPT_LEN) {
+ printk(KERN_INFO "%s: Invalid LMI Report type IE length"
+ " (%u)\n", dev->name, skb->data[i]);
+ return 1;
+ }
+
+ reptype = skb->data[++i];
+ if (reptype != LMI_INTEGRITY && reptype != LMI_FULLREP) {
+ printk(KERN_INFO "%s: Unsupported LMI Report type (0x%02X)\n",
+ dev->name, reptype);
+ return 1;
+ }
+
+ if (skb->data[++i] != (lmi == LMI_CCITT ? LMI_CCITT_ALIVE :
+ LMI_ANSI_CISCO_ALIVE)) {
+ printk(KERN_INFO "%s: Not an LMI Link integrity verification"
+ " IE (0x%02X)\n", dev->name, skb->data[i]);
+ return 1;
+ }
+
+ if (skb->data[++i] != LMI_INTEG_LEN) {
+ printk(KERN_INFO "%s: Invalid LMI Link integrity verification"
+ " IE length (%u)\n", dev->name, skb->data[i]);
+ return 1;
+ }
+ i++;
+
+ hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */
+ rxseq = skb->data[i++]; /* Should confirm our sequence */
+
+ txseq = hdlc->state.fr.txseq;
+
+ if (dce)
+ hdlc->state.fr.last_poll = jiffies;
+
+ error = 0;
+ if (!hdlc->state.fr.reliable)
+ error = 1;
+
+ if (rxseq == 0 || rxseq != txseq) {
+ hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */
+ error = 1;
+ }
+
+ if (dce) {
+ if (hdlc->state.fr.fullrep_sent && !error) {
+/* Stop sending full report - the last one has been confirmed by DTE */
+ hdlc->state.fr.fullrep_sent = 0;
+ pvc = hdlc->state.fr.first_pvc;
+ while (pvc) {
+ if (pvc->state.new) {
+ pvc->state.new = 0;
+
+/* Tell DTE that new PVC is now active */
+ hdlc->state.fr.dce_changed = 1;
+ }
+ pvc = pvc->next;
+ }
+ }
+
+ if (hdlc->state.fr.dce_changed) {
+ reptype = LMI_FULLREP;
+ hdlc->state.fr.fullrep_sent = 1;
+ hdlc->state.fr.dce_changed = 0;
+ }
+
+ hdlc->state.fr.request = 1; /* got request */
+ fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0);
+ return 0;
+ }
+
+ /* DTE */
+
+ hdlc->state.fr.request = 0; /* got response, no request pending */
+
+ if (error)
+ return 0;
+
+ if (reptype != LMI_FULLREP)
+ return 0;
+
+ pvc = hdlc->state.fr.first_pvc;
+
+ while (pvc) {
+ pvc->state.deleted = 1;
+ pvc = pvc->next;
+ }
+
+ no_ram = 0;
+ while (skb->len >= i + 2 + stat_len) {
+ u16 dlci;
+ u32 bw;
+ unsigned int active, new;
+
+ if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT :
+ LMI_ANSI_CISCO_PVCSTAT)) {
+ printk(KERN_INFO "%s: Not an LMI PVC status IE"
+ " (0x%02X)\n", dev->name, skb->data[i]);
+ return 1;
+ }
+
+ if (skb->data[++i] != stat_len) {
+ printk(KERN_INFO "%s: Invalid LMI PVC status IE length"
+ " (%u)\n", dev->name, skb->data[i]);
+ return 1;
+ }
+ i++;
+
+ new = !! (skb->data[i + 2] & 0x08);
+ active = !! (skb->data[i + 2] & 0x02);
+ if (lmi == LMI_CISCO) {
+ dlci = (skb->data[i] << 8) | skb->data[i + 1];
+ bw = (skb->data[i + 3] << 16) |
+ (skb->data[i + 4] << 8) |
+ (skb->data[i + 5]);
+ } else {
+ dlci = ((skb->data[i] & 0x3F) << 4) |
+ ((skb->data[i + 1] & 0x78) >> 3);
+ bw = 0;
+ }
+
+ pvc = add_pvc(dev, dlci);
+
+ if (!pvc && !no_ram) {
+ printk(KERN_WARNING
+ "%s: Memory squeeze on fr_lmi_recv()\n",
+ dev->name);
+ no_ram = 1;
+ }
+
+ if (pvc) {
+ pvc->state.exist = 1;
+ pvc->state.deleted = 0;
+ if (active != pvc->state.active ||
+ new != pvc->state.new ||
+ bw != pvc->state.bandwidth ||
+ !pvc->state.exist) {
+ pvc->state.new = new;
+ pvc->state.active = active;
+ pvc->state.bandwidth = bw;
+ pvc_carrier(active, pvc);
+ fr_log_dlci_active(pvc);
+ }
+ }
+
+ i += stat_len;
+ }
+
+ pvc = hdlc->state.fr.first_pvc;
+
+ while (pvc) {
+ if (pvc->state.deleted && pvc->state.exist) {
+ pvc_carrier(0, pvc);
+ pvc->state.active = pvc->state.new = 0;
+ pvc->state.exist = 0;
+ pvc->state.bandwidth = 0;
+ fr_log_dlci_active(pvc);
+ }
+ pvc = pvc->next;
+ }
+
+ /* Next full report after N391 polls */
+ hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391;
+
+ return 0;
+}
+
+
+
+static int fr_rx(struct sk_buff *skb)
+{
+ struct net_device *ndev = skb->dev;
+ hdlc_device *hdlc = dev_to_hdlc(ndev);
+ fr_hdr *fh = (fr_hdr*)skb->data;
+ u8 *data = skb->data;
+ u16 dlci;
+ pvc_device *pvc;
+ struct net_device *dev = NULL;
+
+ if (skb->len <= 4 || fh->ea1 || data[2] != FR_UI)
+ goto rx_error;
+
+ dlci = q922_to_dlci(skb->data);
+
+ if ((dlci == LMI_CCITT_ANSI_DLCI &&
+ (hdlc->state.fr.settings.lmi == LMI_ANSI ||
+ hdlc->state.fr.settings.lmi == LMI_CCITT)) ||
+ (dlci == LMI_CISCO_DLCI &&
+ hdlc->state.fr.settings.lmi == LMI_CISCO)) {
+ if (fr_lmi_recv(ndev, skb))
+ goto rx_error;
+ dev_kfree_skb_any(skb);
+ return NET_RX_SUCCESS;
+ }
+
+ pvc = find_pvc(hdlc, dlci);
+ if (!pvc) {
+#ifdef DEBUG_PKT
+ printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
+ ndev->name, dlci);
+#endif
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+ }
+
+ if (pvc->state.fecn != fh->fecn) {
+#ifdef DEBUG_ECN
+ printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", ndev->name,
+ dlci, fh->fecn ? "N" : "FF");
+#endif
+ pvc->state.fecn ^= 1;
+ }
+
+ if (pvc->state.becn != fh->becn) {
+#ifdef DEBUG_ECN
+ printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", ndev->name,
+ dlci, fh->becn ? "N" : "FF");
+#endif
+ pvc->state.becn ^= 1;
+ }
+
+
+ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
+ hdlc->stats.rx_dropped++;
+ return NET_RX_DROP;
+ }
+
+ if (data[3] == NLPID_IP) {
+ skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
+ dev = pvc->main;
+ skb->protocol = htons(ETH_P_IP);
+
+ } else if (data[3] == NLPID_IPV6) {
+ skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
+ dev = pvc->main;
+ skb->protocol = htons(ETH_P_IPV6);
+
+ } else if (skb->len > 10 && data[3] == FR_PAD &&
+ data[4] == NLPID_SNAP && data[5] == FR_PAD) {
+ u16 oui = ntohs(*(u16*)(data + 6));
+ u16 pid = ntohs(*(u16*)(data + 8));
+ skb_pull(skb, 10);
+
+ switch ((((u32)oui) << 16) | pid) {
+ case ETH_P_ARP: /* routed frame with SNAP */
+ case ETH_P_IPX:
+ case ETH_P_IP: /* a long variant */
+ case ETH_P_IPV6:
+ dev = pvc->main;
+ skb->protocol = htons(pid);
+ break;
+
+ case 0x80C20007: /* bridged Ethernet frame */
+ if ((dev = pvc->ether) != NULL)
+ skb->protocol = eth_type_trans(skb, dev);
+ break;
+
+ default:
+ printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "
+ "PID=%x\n", ndev->name, oui, pid);
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+ }
+ } else {
+ printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x "
+ "length = %i\n", ndev->name, data[3], skb->len);
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+ }
+
+ if (dev) {
+ struct net_device_stats *stats = pvc_get_stats(dev);
+ stats->rx_packets++; /* PVC traffic */
+ stats->rx_bytes += skb->len;
+ if (pvc->state.becn)
+ stats->rx_compressed++;
+ skb->dev = dev;
+ netif_rx(skb);
+ return NET_RX_SUCCESS;
+ } else {
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+ }
+
+ rx_error:
+ hdlc->stats.rx_errors++; /* Mark error */
+ dev_kfree_skb_any(skb);
+ return NET_RX_DROP;
+}
+
+
+
+static void fr_start(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+#ifdef DEBUG_LINK
+ printk(KERN_DEBUG "fr_start\n");
+#endif
+ if (hdlc->state.fr.settings.lmi != LMI_NONE) {
+ hdlc->state.fr.reliable = 0;
+ hdlc->state.fr.dce_changed = 1;
+ hdlc->state.fr.request = 0;
+ hdlc->state.fr.fullrep_sent = 0;
+ hdlc->state.fr.last_errors = 0xFFFFFFFF;
+ hdlc->state.fr.n391cnt = 0;
+ hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0;
+
+ init_timer(&hdlc->state.fr.timer);
+ /* First poll after 1 s */
+ hdlc->state.fr.timer.expires = jiffies + HZ;
+ hdlc->state.fr.timer.function = fr_timer;
+ hdlc->state.fr.timer.data = (unsigned long)dev;
+ add_timer(&hdlc->state.fr.timer);
+ } else
+ fr_set_link_state(1, dev);
+}
+
+
+
+static void fr_stop(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+#ifdef DEBUG_LINK
+ printk(KERN_DEBUG "fr_stop\n");
+#endif
+ if (hdlc->state.fr.settings.lmi != LMI_NONE)
+ del_timer_sync(&hdlc->state.fr.timer);
+ fr_set_link_state(0, dev);
+}
+
+
+
+static void fr_close(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ pvc_device *pvc = hdlc->state.fr.first_pvc;
+
+ while (pvc) { /* Shutdown all PVCs for this FRAD */
+ if (pvc->main)
+ dev_close(pvc->main);
+ if (pvc->ether)
+ dev_close(pvc->ether);
+ pvc = pvc->next;
+ }
+}
+
+static void dlci_setup(struct net_device *dev)
+{
+ dev->type = ARPHRD_DLCI;
+ dev->flags = IFF_POINTOPOINT;
+ dev->hard_header_len = 10;
+ dev->addr_len = 2;
+}
+
+static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
+{
+ hdlc_device *hdlc = dev_to_hdlc(master);
+ pvc_device *pvc = NULL;
+ struct net_device *dev;
+ int result, used;
+ char * prefix = "pvc%d";
+
+ if (type == ARPHRD_ETHER)
+ prefix = "pvceth%d";
+
+ if ((pvc = add_pvc(master, dlci)) == NULL) {
+ printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n",
+ master->name);
+ return -ENOBUFS;
+ }
+
+ if (*get_dev_p(pvc, type))
+ return -EEXIST;
+
+ used = pvc_is_used(pvc);
+
+ if (type == ARPHRD_ETHER)
+ dev = alloc_netdev(sizeof(struct net_device_stats),
+ "pvceth%d", ether_setup);
+ else
+ dev = alloc_netdev(sizeof(struct net_device_stats),
+ "pvc%d", dlci_setup);
+
+ if (!dev) {
+ printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
+ master->name);
+ delete_unused_pvcs(hdlc);
+ return -ENOBUFS;
+ }
+
+ if (type == ARPHRD_ETHER) {
+ memcpy(dev->dev_addr, "\x00\x01", 2);
+ get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
+ } else {
+ *(u16*)dev->dev_addr = htons(dlci);
+ dlci_to_q922(dev->broadcast, dlci);
+ }
+ dev->hard_start_xmit = pvc_xmit;
+ dev->get_stats = pvc_get_stats;
+ dev->open = pvc_open;
+ dev->stop = pvc_close;
+ dev->do_ioctl = pvc_ioctl;
+ dev->change_mtu = pvc_change_mtu;
+ dev->mtu = HDLC_MAX_MTU;
+ dev->tx_queue_len = 0;
+ dev->priv = pvc;
+
+ result = dev_alloc_name(dev, dev->name);
+ if (result < 0) {
+ free_netdev(dev);
+ delete_unused_pvcs(hdlc);
+ return result;
+ }
+
+ if (register_netdevice(dev) != 0) {
+ free_netdev(dev);
+ delete_unused_pvcs(hdlc);
+ return -EIO;
+ }
+
+ dev->destructor = free_netdev;
+ *get_dev_p(pvc, type) = dev;
+ if (!used) {
+ hdlc->state.fr.dce_changed = 1;
+ hdlc->state.fr.dce_pvc_count++;
+ }
+ return 0;
+}
+
+
+
+static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
+{
+ pvc_device *pvc;
+ struct net_device *dev;
+
+ if ((pvc = find_pvc(hdlc, dlci)) == NULL)
+ return -ENOENT;
+
+ if ((dev = *get_dev_p(pvc, type)) == NULL)
+ return -ENOENT;
+
+ if (dev->flags & IFF_UP)
+ return -EBUSY; /* PVC in use */
+
+ unregister_netdevice(dev); /* the destructor will free_netdev(dev) */
+ *get_dev_p(pvc, type) = NULL;
+
+ if (!pvc_is_used(pvc)) {
+ hdlc->state.fr.dce_pvc_count--;
+ hdlc->state.fr.dce_changed = 1;
+ }
+ delete_unused_pvcs(hdlc);
+ return 0;
+}
+
+
+
+static void fr_destroy(hdlc_device *hdlc)
+{
+ pvc_device *pvc;
+
+ pvc = hdlc->state.fr.first_pvc;
+ hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */
+ hdlc->state.fr.dce_pvc_count = 0;
+ hdlc->state.fr.dce_changed = 1;
+
+ while (pvc) {
+ pvc_device *next = pvc->next;
+ /* destructors will free_netdev() main and ether */
+ if (pvc->main)
+ unregister_netdevice(pvc->main);
+
+ if (pvc->ether)
+ unregister_netdevice(pvc->ether);
+
+ kfree(pvc);
+ pvc = next;
+ }
+}
+
+
+
+int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+ fr_proto __user *fr_s = ifr->ifr_settings.ifs_ifsu.fr;
+ const size_t size = sizeof(fr_proto);
+ fr_proto new_settings;
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ fr_proto_pvc pvc;
+ int result;
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_PROTO:
+ ifr->ifr_settings.type = IF_PROTO_FR;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+ if (copy_to_user(fr_s, &hdlc->state.fr.settings, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_PROTO_FR:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if(dev->flags & IFF_UP)
+ return -EBUSY;
+
+ if (copy_from_user(&new_settings, fr_s, size))
+ return -EFAULT;
+
+ if (new_settings.lmi == LMI_DEFAULT)
+ new_settings.lmi = LMI_ANSI;
+
+ if ((new_settings.lmi != LMI_NONE &&
+ new_settings.lmi != LMI_ANSI &&
+ new_settings.lmi != LMI_CCITT &&
+ new_settings.lmi != LMI_CISCO) ||
+ new_settings.t391 < 1 ||
+ new_settings.t392 < 2 ||
+ new_settings.n391 < 1 ||
+ new_settings.n392 < 1 ||
+ new_settings.n393 < new_settings.n392 ||
+ new_settings.n393 > 32 ||
+ (new_settings.dce != 0 &&
+ new_settings.dce != 1))
+ return -EINVAL;
+
+ result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+ if (result)
+ return result;
+
+ if (hdlc->proto.id != IF_PROTO_FR) {
+ hdlc_proto_detach(hdlc);
+ hdlc->state.fr.first_pvc = NULL;
+ hdlc->state.fr.dce_pvc_count = 0;
+ }
+ memcpy(&hdlc->state.fr.settings, &new_settings, size);
+ memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+
+ hdlc->proto.close = fr_close;
+ hdlc->proto.start = fr_start;
+ hdlc->proto.stop = fr_stop;
+ hdlc->proto.detach = fr_destroy;
+ hdlc->proto.netif_rx = fr_rx;
+ hdlc->proto.id = IF_PROTO_FR;
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = NULL;
+ dev->type = ARPHRD_FRAD;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ dev->addr_len = 0;
+ return 0;
+
+ case IF_PROTO_FR_ADD_PVC:
+ case IF_PROTO_FR_DEL_PVC:
+ case IF_PROTO_FR_ADD_ETH_PVC:
+ case IF_PROTO_FR_DEL_ETH_PVC:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&pvc, ifr->ifr_settings.ifs_ifsu.fr_pvc,
+ sizeof(fr_proto_pvc)))
+ return -EFAULT;
+
+ if (pvc.dlci <= 0 || pvc.dlci >= 1024)
+ return -EINVAL; /* Only 10 bits, DLCI 0 reserved */
+
+ if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC ||
+ ifr->ifr_settings.type == IF_PROTO_FR_DEL_ETH_PVC)
+ result = ARPHRD_ETHER; /* bridged Ethernet device */
+ else
+ result = ARPHRD_DLCI;
+
+ if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_PVC ||
+ ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC)
+ return fr_add_pvc(dev, pvc.dlci, result);
+ else
+ return fr_del_pvc(hdlc, pvc.dlci, result);
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/dahdi/datamods/hdlc_generic.c b/drivers/dahdi/datamods/hdlc_generic.c
new file mode 100644
index 0000000..46cef8f
--- /dev/null
+++ b/drivers/dahdi/datamods/hdlc_generic.c
@@ -0,0 +1,355 @@
+/*
+ * Generic HDLC support routines for Linux
+ *
+ * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * Currently supported:
+ * * raw IP-in-HDLC
+ * * Cisco HDLC
+ * * Frame Relay with ANSI or CCITT LMI (both user and network side)
+ * * PPP
+ * * X.25
+ *
+ * Use sethdlc utility to set line parameters, protocol and PVCs
+ *
+ * How does it work:
+ * - proto.open(), close(), start(), stop() calls are serialized.
+ * The order is: open, [ start, stop ... ] close ...
+ * - proto.start() and stop() are called with spin_lock_irq held.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static const char* version = "HDLC support module revision 1.18";
+
+#undef DEBUG_LINK
+
+
+static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+
+
+static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
+{
+ return hdlc_stats(dev);
+}
+
+
+
+static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *p, struct net_device *orig_dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ if (hdlc->proto.netif_rx)
+ return hdlc->proto.netif_rx(skb);
+
+ hdlc->stats.rx_dropped++; /* Shouldn't happen */
+ dev_kfree_skb(skb);
+ return NET_RX_DROP;
+}
+
+
+
+static void __hdlc_set_carrier_on(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ if (hdlc->proto.start)
+ return hdlc->proto.start(dev);
+#if 0
+#ifdef DEBUG_LINK
+ if (netif_carrier_ok(dev))
+ printk(KERN_ERR "hdlc_set_carrier_on(): already on\n");
+#endif
+ netif_carrier_on(dev);
+#endif
+}
+
+
+
+static void __hdlc_set_carrier_off(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ if (hdlc->proto.stop)
+ return hdlc->proto.stop(dev);
+
+#if 0
+#ifdef DEBUG_LINK
+ if (!netif_carrier_ok(dev))
+ printk(KERN_ERR "hdlc_set_carrier_off(): already off\n");
+#endif
+ netif_carrier_off(dev);
+#endif
+}
+
+
+
+void hdlc_set_carrier(int on, struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ unsigned long flags;
+ on = on ? 1 : 0;
+
+#ifdef DEBUG_LINK
+ printk(KERN_DEBUG "hdlc_set_carrier %i\n", on);
+#endif
+
+ spin_lock_irqsave(&hdlc->state_lock, flags);
+
+ if (hdlc->carrier == on)
+ goto carrier_exit; /* no change in DCD line level */
+
+#ifdef DEBUG_LINK
+ printk(KERN_INFO "%s: carrier %s\n", dev->name, on ? "ON" : "off");
+#endif
+ hdlc->carrier = on;
+
+ if (!hdlc->open)
+ goto carrier_exit;
+
+ if (hdlc->carrier) {
+ printk(KERN_INFO "%s: Carrier detected\n", dev->name);
+ __hdlc_set_carrier_on(dev);
+ } else {
+ printk(KERN_INFO "%s: Carrier lost\n", dev->name);
+ __hdlc_set_carrier_off(dev);
+ }
+
+carrier_exit:
+ spin_unlock_irqrestore(&hdlc->state_lock, flags);
+}
+
+
+
+/* Must be called by hardware driver when HDLC device is being opened */
+int hdlc_open(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+#ifdef DEBUG_LINK
+ printk(KERN_DEBUG "hdlc_open() carrier %i open %i\n",
+ hdlc->carrier, hdlc->open);
+#endif
+
+ if (hdlc->proto.id == -1)
+ return -ENOSYS; /* no protocol attached */
+
+ if (hdlc->proto.open) {
+ int result = hdlc->proto.open(dev);
+ if (result)
+ return result;
+ }
+
+ spin_lock_irq(&hdlc->state_lock);
+
+ if (hdlc->carrier) {
+ printk(KERN_INFO "%s: Carrier detected\n", dev->name);
+ __hdlc_set_carrier_on(dev);
+ } else
+ printk(KERN_INFO "%s: No carrier\n", dev->name);
+
+ hdlc->open = 1;
+
+ spin_unlock_irq(&hdlc->state_lock);
+ return 0;
+}
+
+
+
+/* Must be called by hardware driver when HDLC device is being closed */
+void hdlc_close(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+#ifdef DEBUG_LINK
+ printk(KERN_DEBUG "hdlc_close() carrier %i open %i\n",
+ hdlc->carrier, hdlc->open);
+#endif
+
+ spin_lock_irq(&hdlc->state_lock);
+
+ hdlc->open = 0;
+ if (hdlc->carrier)
+ __hdlc_set_carrier_off(dev);
+
+ spin_unlock_irq(&hdlc->state_lock);
+
+ if (hdlc->proto.close)
+ hdlc->proto.close(dev);
+}
+
+
+
+#ifndef CONFIG_HDLC_RAW
+#define hdlc_raw_ioctl(dev, ifr) -ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_RAW_ETH
+#define hdlc_raw_eth_ioctl(dev, ifr) -ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_PPP
+#define hdlc_ppp_ioctl(dev, ifr) -ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_CISCO
+#define hdlc_cisco_ioctl(dev, ifr) -ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_FR
+#define hdlc_fr_ioctl(dev, ifr) -ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_X25
+#define hdlc_x25_ioctl(dev, ifr) -ENOSYS
+#endif
+
+
+int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ unsigned int proto;
+
+ if (cmd != SIOCWANDEV)
+ return -EINVAL;
+
+ switch(ifr->ifr_settings.type) {
+ case IF_PROTO_HDLC:
+ case IF_PROTO_HDLC_ETH:
+ case IF_PROTO_PPP:
+ case IF_PROTO_CISCO:
+ case IF_PROTO_FR:
+ case IF_PROTO_X25:
+ proto = ifr->ifr_settings.type;
+ break;
+
+ default:
+ proto = hdlc->proto.id;
+ }
+
+ switch(proto) {
+ case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr);
+ case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr);
+ case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr);
+ case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr);
+ case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr);
+ case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr);
+ default: return -EINVAL;
+ }
+}
+
+static void hdlc_setup(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+
+ dev->get_stats = hdlc_get_stats;
+ dev->change_mtu = hdlc_change_mtu;
+ dev->mtu = HDLC_MAX_MTU;
+
+ dev->type = ARPHRD_RAWHDLC;
+ dev->hard_header_len = 16;
+
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+
+ hdlc->proto.id = -1;
+ hdlc->proto.detach = NULL;
+ hdlc->carrier = 1;
+ hdlc->open = 0;
+ spin_lock_init(&hdlc->state_lock);
+}
+
+struct net_device *alloc_hdlcdev(void *priv)
+{
+ struct net_device *dev;
+ dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup);
+ if (dev)
+ dev_to_hdlc(dev)->priv = priv;
+ return dev;
+}
+
+int register_hdlc_device(struct net_device *dev)
+{
+ int result = dev_alloc_name(dev, "hdlc%d");
+ if (result < 0)
+ return result;
+
+ result = register_netdev(dev);
+ if (result != 0)
+ return -EIO;
+
+#if 0
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev); /* no carrier until DCD goes up */
+#endif
+
+ return 0;
+}
+
+
+
+void unregister_hdlc_device(struct net_device *dev)
+{
+ rtnl_lock();
+ hdlc_proto_detach(dev_to_hdlc(dev));
+ unregister_netdevice(dev);
+ rtnl_unlock();
+}
+
+
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("HDLC support module");
+MODULE_LICENSE("GPL v2");
+
+EXPORT_SYMBOL(hdlc_open);
+EXPORT_SYMBOL(hdlc_close);
+EXPORT_SYMBOL(hdlc_set_carrier);
+EXPORT_SYMBOL(hdlc_ioctl);
+EXPORT_SYMBOL(alloc_hdlcdev);
+EXPORT_SYMBOL(register_hdlc_device);
+EXPORT_SYMBOL(unregister_hdlc_device);
+
+static struct packet_type hdlc_packet_type = {
+ .type = __constant_htons(ETH_P_HDLC),
+ .func = hdlc_rcv,
+};
+
+
+static int __init hdlc_module_init(void)
+{
+ printk(KERN_INFO "%s\n", version);
+ dev_add_pack(&hdlc_packet_type);
+ return 0;
+}
+
+
+
+static void __exit hdlc_module_exit(void)
+{
+ dev_remove_pack(&hdlc_packet_type);
+}
+
+
+module_init(hdlc_module_init);
+module_exit(hdlc_module_exit);
diff --git a/drivers/dahdi/datamods/hdlc_ppp.c b/drivers/dahdi/datamods/hdlc_ppp.c
new file mode 100644
index 0000000..b81263e
--- /dev/null
+++ b/drivers/dahdi/datamods/hdlc_ppp.c
@@ -0,0 +1,114 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Point-to-point protocol support
+ *
+ * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static int ppp_open(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ void *old_ioctl;
+ int result;
+
+ dev->priv = &hdlc->state.ppp.syncppp_ptr;
+ hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev;
+ hdlc->state.ppp.pppdev.dev = dev;
+
+ old_ioctl = dev->do_ioctl;
+ hdlc->state.ppp.old_change_mtu = dev->change_mtu;
+ sppp_attach(&hdlc->state.ppp.pppdev);
+ /* sppp_attach nukes them. We don't need syncppp's ioctl */
+ dev->do_ioctl = old_ioctl;
+ hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO;
+ dev->type = ARPHRD_PPP;
+ result = sppp_open(dev);
+ if (result) {
+ sppp_detach(dev);
+ return result;
+ }
+
+ return 0;
+}
+
+
+
+static void ppp_close(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+
+ sppp_close(dev);
+ sppp_detach(dev);
+ dev->rebuild_header = NULL;
+ dev->change_mtu = hdlc->state.ppp.old_change_mtu;
+ dev->mtu = HDLC_MAX_MTU;
+ dev->hard_header_len = 16;
+}
+
+
+
+static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+ return __constant_htons(ETH_P_WAN_PPP);
+}
+
+
+
+int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ int result;
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_PROTO:
+ ifr->ifr_settings.type = IF_PROTO_PPP;
+ return 0; /* return protocol only, no settable parameters */
+
+ case IF_PROTO_PPP:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if(dev->flags & IFF_UP)
+ return -EBUSY;
+
+ /* no settable parameters */
+
+ result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+ if (result)
+ return result;
+
+ hdlc_proto_detach(hdlc);
+ memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+
+ hdlc->proto.open = ppp_open;
+ hdlc->proto.close = ppp_close;
+ hdlc->proto.type_trans = ppp_type_trans;
+ hdlc->proto.id = IF_PROTO_PPP;
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = NULL;
+ dev->type = ARPHRD_PPP;
+ dev->addr_len = 0;
+ return 0;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/dahdi/datamods/hdlc_raw.c b/drivers/dahdi/datamods/hdlc_raw.c
new file mode 100644
index 0000000..9456d31
--- /dev/null
+++ b/drivers/dahdi/datamods/hdlc_raw.c
@@ -0,0 +1,89 @@
+/*
+ * Generic HDLC support routines for Linux
+ * HDLC support
+ *
+ * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+ return __constant_htons(ETH_P_IP);
+}
+
+
+
+int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+ raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
+ const size_t size = sizeof(raw_hdlc_proto);
+ raw_hdlc_proto new_settings;
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ int result;
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_PROTO:
+ ifr->ifr_settings.type = IF_PROTO_HDLC;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+ if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_PROTO_HDLC:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ if (copy_from_user(&new_settings, raw_s, size))
+ return -EFAULT;
+
+ if (new_settings.encoding == ENCODING_DEFAULT)
+ new_settings.encoding = ENCODING_NRZ;
+
+ if (new_settings.parity == PARITY_DEFAULT)
+ new_settings.parity = PARITY_CRC16_PR1_CCITT;
+
+ result = hdlc->attach(dev, new_settings.encoding,
+ new_settings.parity);
+ if (result)
+ return result;
+
+ hdlc_proto_detach(hdlc);
+ memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
+ memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+
+ hdlc->proto.type_trans = raw_type_trans;
+ hdlc->proto.id = IF_PROTO_HDLC;
+ dev->hard_start_xmit = hdlc->xmit;
+ dev->hard_header = NULL;
+ dev->type = ARPHRD_RAWHDLC;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ dev->addr_len = 0;
+ return 0;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/dahdi/datamods/hdlc_raw_eth.c b/drivers/dahdi/datamods/hdlc_raw_eth.c
new file mode 100644
index 0000000..b1285cc
--- /dev/null
+++ b/drivers/dahdi/datamods/hdlc_raw_eth.c
@@ -0,0 +1,107 @@
+/*
+ * Generic HDLC support routines for Linux
+ * HDLC Ethernet emulation support
+ *
+ * Copyright (C) 2002-2003 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/random.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/etherdevice.h>
+#include <linux/hdlc.h>
+
+
+static int eth_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ int pad = ETH_ZLEN - skb->len;
+ if (pad > 0) { /* Pad the frame with zeros */
+ int len = skb->len;
+ if (skb_tailroom(skb) < pad)
+ if (pskb_expand_head(skb, 0, pad, GFP_ATOMIC)) {
+ hdlc_stats(dev)->tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ skb_put(skb, pad);
+ memset(skb->data + len, 0, pad);
+ }
+ return dev_to_hdlc(dev)->xmit(skb, dev);
+}
+
+
+int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+ raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
+ const size_t size = sizeof(raw_hdlc_proto);
+ raw_hdlc_proto new_settings;
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ int result;
+ void *old_ch_mtu;
+ int old_qlen;
+
+ switch (ifr->ifr_settings.type) {
+ case IF_GET_PROTO:
+ ifr->ifr_settings.type = IF_PROTO_HDLC_ETH;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+ if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_PROTO_HDLC_ETH:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ if (copy_from_user(&new_settings, raw_s, size))
+ return -EFAULT;
+
+ if (new_settings.encoding == ENCODING_DEFAULT)
+ new_settings.encoding = ENCODING_NRZ;
+
+ if (new_settings.parity == PARITY_DEFAULT)
+ new_settings.parity = PARITY_CRC16_PR1_CCITT;
+
+ result = hdlc->attach(dev, new_settings.encoding,
+ new_settings.parity);
+ if (result)
+ return result;
+
+ hdlc_proto_detach(hdlc);
+ memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
+ memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+
+ hdlc->proto.type_trans = eth_type_trans;
+ hdlc->proto.id = IF_PROTO_HDLC_ETH;
+ dev->hard_start_xmit = eth_tx;
+ old_ch_mtu = dev->change_mtu;
+ old_qlen = dev->tx_queue_len;
+ ether_setup(dev);
+ dev->change_mtu = old_ch_mtu;
+ dev->tx_queue_len = old_qlen;
+ memcpy(dev->dev_addr, "\x00\x01", 2);
+ get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
+ return 0;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/dahdi/datamods/syncppp.c b/drivers/dahdi/datamods/syncppp.c
new file mode 100644
index 0000000..5ca283a
--- /dev/null
+++ b/drivers/dahdi/datamods/syncppp.c
@@ -0,0 +1,1485 @@
+/*
+ * NET3: A (fairly minimal) implementation of synchronous PPP for Linux
+ * as well as a CISCO HDLC implementation. See the copyright
+ * message below for the original source.
+ *
+ * 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.
+ *
+ * Note however. This code is also used in a different form by FreeBSD.
+ * Therefore when making any non OS specific change please consider
+ * contributing it back to the original author under the terms
+ * below in addition.
+ * -- Alan
+ *
+ * Port for Linux-2.1 by Jan "Yenya" Kasprzak <kas@fi.muni.cz>
+ */
+
+/*
+ * Synchronous PPP/Cisco link level subroutines.
+ * Keepalive protocol implemented in both Cisco and PPP modes.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.9, Wed Oct 4 18:58:15 MSK 1995
+ *
+ * $Id$
+ */
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <linux/route.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/random.h>
+#include <linux/pkt_sched.h>
+#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
+
+#include <net/syncppp.h>
+
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#define MAXALIVECNT 6 /* max. alive packets */
+
+#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
+#define PPP_UI 0x03 /* Unnumbered Information */
+#define PPP_IP 0x0021 /* Internet Protocol */
+#define PPP_ISO 0x0023 /* ISO OSI Protocol */
+#define PPP_XNS 0x0025 /* Xerox NS Protocol */
+#define PPP_IPX 0x002b /* Novell IPX Protocol */
+#define PPP_LCP 0xc021 /* Link Control Protocol */
+#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */
+
+#define LCP_CONF_REQ 1 /* PPP LCP configure request */
+#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */
+#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */
+#define LCP_CONF_REJ 4 /* PPP LCP configure reject */
+#define LCP_TERM_REQ 5 /* PPP LCP terminate request */
+#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */
+#define LCP_CODE_REJ 7 /* PPP LCP code reject */
+#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */
+#define LCP_ECHO_REQ 9 /* PPP LCP echo request */
+#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */
+#define LCP_DISC_REQ 11 /* PPP LCP discard request */
+
+#define LCP_OPT_MRU 1 /* maximum receive unit */
+#define LCP_OPT_ASYNC_MAP 2 /* async control character map */
+#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */
+#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */
+#define LCP_OPT_MAGIC 5 /* magic number */
+#define LCP_OPT_RESERVED 6 /* reserved */
+#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */
+#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */
+
+#define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */
+#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */
+#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */
+#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */
+#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */
+#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */
+#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */
+
+#define CISCO_MULTICAST 0x8f /* Cisco multicast address */
+#define CISCO_UNICAST 0x0f /* Cisco unicast address */
+#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */
+#define CISCO_ADDR_REQ 0 /* Cisco address request */
+#define CISCO_ADDR_REPLY 1 /* Cisco address reply */
+#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
+
+struct ppp_header {
+ u8 address;
+ u8 control;
+ u16 protocol;
+};
+#define PPP_HEADER_LEN sizeof (struct ppp_header)
+
+struct lcp_header {
+ u8 type;
+ u8 ident;
+ u16 len;
+};
+#define LCP_HEADER_LEN sizeof (struct lcp_header)
+
+struct cisco_packet {
+ u32 type;
+ u32 par1;
+ u32 par2;
+ u16 rel;
+ u16 time0;
+ u16 time1;
+};
+#define CISCO_PACKET_LEN 18
+#define CISCO_BIG_PACKET_LEN 20
+
+static struct sppp *spppq;
+static struct timer_list sppp_keepalive_timer;
+static DEFINE_SPINLOCK(spppq_lock);
+
+/* global xmit queue for sending packets while spinlock is held */
+static struct sk_buff_head tx_queue;
+
+static void sppp_keepalive (unsigned long dummy);
+static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,
+ u8 ident, u16 len, void *data);
+static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2);
+static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m);
+static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m);
+static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m);
+static void sppp_lcp_open (struct sppp *sp);
+static void sppp_ipcp_open (struct sppp *sp);
+static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
+ int len, u32 *magic);
+static void sppp_cp_timeout (unsigned long arg);
+static char *sppp_lcp_type_name (u8 type);
+static char *sppp_ipcp_type_name (u8 type);
+static void sppp_print_bytes (u8 *p, u16 len);
+
+static int debug;
+
+/* Flush global outgoing packet queue to dev_queue_xmit().
+ *
+ * dev_queue_xmit() must be called with interrupts enabled
+ * which means it can't be called with spinlocks held.
+ * If a packet needs to be sent while a spinlock is held,
+ * then put the packet into tx_queue, and call sppp_flush_xmit()
+ * after spinlock is released.
+ */
+static void sppp_flush_xmit(void)
+{
+ struct sk_buff *skb;
+ while ((skb = skb_dequeue(&tx_queue)) != NULL)
+ dev_queue_xmit(skb);
+}
+
+/*
+ * Interface down stub
+ */
+
+static void if_down(struct net_device *dev)
+{
+ struct sppp *sp = (struct sppp *)sppp_of(dev);
+
+ sp->pp_link_state=SPPP_LINK_DOWN;
+}
+
+/*
+ * Timeout routine activations.
+ */
+
+static void sppp_set_timeout(struct sppp *p,int s)
+{
+ if (! (p->pp_flags & PP_TIMO))
+ {
+ init_timer(&p->pp_timer);
+ p->pp_timer.function=sppp_cp_timeout;
+ p->pp_timer.expires=jiffies+s*HZ;
+ p->pp_timer.data=(unsigned long)p;
+ p->pp_flags |= PP_TIMO;
+ add_timer(&p->pp_timer);
+ }
+}
+
+static void sppp_clear_timeout(struct sppp *p)
+{
+ if (p->pp_flags & PP_TIMO)
+ {
+ del_timer(&p->pp_timer);
+ p->pp_flags &= ~PP_TIMO;
+ }
+}
+
+/**
+ * sppp_input - receive and process a WAN PPP frame
+ * @skb: The buffer to process
+ * @dev: The device it arrived on
+ *
+ * This can be called directly by cards that do not have
+ * timing constraints but is normally called from the network layer
+ * after interrupt servicing to process frames queued via netif_rx().
+ *
+ * We process the options in the card. If the frame is destined for
+ * the protocol stacks then it requeues the frame for the upper level
+ * protocol. If it is a control from it is processed and discarded
+ * here.
+ */
+
+static void sppp_input (struct net_device *dev, struct sk_buff *skb)
+{
+ struct ppp_header *h;
+ struct sppp *sp = (struct sppp *)sppp_of(dev);
+ unsigned long flags;
+
+ skb->dev=dev;
+ skb->mac.raw=skb->data;
+
+ if (dev->flags & IFF_RUNNING)
+ {
+ /* Count received bytes, add FCS and one flag */
+ sp->ibytes+= skb->len + 3;
+ sp->ipkts++;
+ }
+
+ if (!pskb_may_pull(skb, PPP_HEADER_LEN)) {
+ /* Too small packet, drop it. */
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n",
+ dev->name, skb->len);
+ kfree_skb(skb);
+ return;
+ }
+
+ /* Get PPP header. */
+ h = (struct ppp_header *)skb->data;
+ skb_pull(skb,sizeof(struct ppp_header));
+
+ spin_lock_irqsave(&sp->lock, flags);
+
+ switch (h->address) {
+ default: /* Invalid PPP packet. */
+ goto invalid;
+ case PPP_ALLSTATIONS:
+ if (h->control != PPP_UI)
+ goto invalid;
+ if (sp->pp_flags & PP_CISCO) {
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n",
+ dev->name,
+ h->address, h->control, ntohs (h->protocol));
+ goto drop;
+ }
+ switch (ntohs (h->protocol)) {
+ default:
+ if (sp->lcp.state == LCP_STATE_OPENED)
+ sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ,
+ ++sp->pp_seq, skb->len + 2,
+ &h->protocol);
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n",
+ dev->name,
+ h->address, h->control, ntohs (h->protocol));
+ goto drop;
+ case PPP_LCP:
+ sppp_lcp_input (sp, skb);
+ goto drop;
+ case PPP_IPCP:
+ if (sp->lcp.state == LCP_STATE_OPENED)
+ sppp_ipcp_input (sp, skb);
+ else
+ printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n");
+ goto drop;
+ case PPP_IP:
+ if (sp->ipcp.state == IPCP_STATE_OPENED) {
+ if(sp->pp_flags&PP_DEBUG)
+ printk(KERN_DEBUG "Yow an IP frame.\n");
+ skb->protocol=htons(ETH_P_IP);
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ goto done;
+ }
+ break;
+#ifdef IPX
+ case PPP_IPX:
+ /* IPX IPXCP not implemented yet */
+ if (sp->lcp.state == LCP_STATE_OPENED) {
+ skb->protocol=htons(ETH_P_IPX);
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ goto done;
+ }
+ break;
+#endif
+ }
+ break;
+ case CISCO_MULTICAST:
+ case CISCO_UNICAST:
+ /* Don't check the control field here (RFC 1547). */
+ if (! (sp->pp_flags & PP_CISCO)) {
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n",
+ dev->name,
+ h->address, h->control, ntohs (h->protocol));
+ goto drop;
+ }
+ switch (ntohs (h->protocol)) {
+ default:
+ goto invalid;
+ case CISCO_KEEPALIVE:
+ sppp_cisco_input (sp, skb);
+ goto drop;
+#ifdef CONFIG_INET
+ case ETH_P_IP:
+ skb->protocol=htons(ETH_P_IP);
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ goto done;
+#endif
+#ifdef CONFIG_IPX
+ case ETH_P_IPX:
+ skb->protocol=htons(ETH_P_IPX);
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ goto done;
+#endif
+ }
+ break;
+ }
+ goto drop;
+
+invalid:
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n",
+ dev->name, h->address, h->control, ntohs (h->protocol));
+drop:
+ kfree_skb(skb);
+done:
+ spin_unlock_irqrestore(&sp->lock, flags);
+ sppp_flush_xmit();
+ return;
+}
+
+/*
+ * Handle transmit packets.
+ */
+
+static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type,
+ void *daddr, void *saddr, unsigned int len)
+{
+ struct sppp *sp = (struct sppp *)sppp_of(dev);
+ struct ppp_header *h;
+ skb_push(skb,sizeof(struct ppp_header));
+ h=(struct ppp_header *)skb->data;
+ if(sp->pp_flags&PP_CISCO)
+ {
+ h->address = CISCO_UNICAST;
+ h->control = 0;
+ }
+ else
+ {
+ h->address = PPP_ALLSTATIONS;
+ h->control = PPP_UI;
+ }
+ if(sp->pp_flags & PP_CISCO)
+ {
+ h->protocol = htons(type);
+ }
+ else switch(type)
+ {
+ case ETH_P_IP:
+ h->protocol = htons(PPP_IP);
+ break;
+ case ETH_P_IPX:
+ h->protocol = htons(PPP_IPX);
+ break;
+ }
+ return sizeof(struct ppp_header);
+}
+
+static int sppp_rebuild_header(struct sk_buff *skb)
+{
+ return 0;
+}
+
+/*
+ * Send keepalive packets, every 10 seconds.
+ */
+
+static void sppp_keepalive (unsigned long dummy)
+{
+ struct sppp *sp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&spppq_lock, flags);
+
+ for (sp=spppq; sp; sp=sp->pp_next)
+ {
+ struct net_device *dev = sp->pp_if;
+
+ /* Keepalive mode disabled or channel down? */
+ if (! (sp->pp_flags & PP_KEEPALIVE) ||
+ ! (dev->flags & IFF_UP))
+ continue;
+
+ spin_lock(&sp->lock);
+
+ /* No keepalive in PPP mode if LCP not opened yet. */
+ if (! (sp->pp_flags & PP_CISCO) &&
+ sp->lcp.state != LCP_STATE_OPENED) {
+ spin_unlock(&sp->lock);
+ continue;
+ }
+
+ if (sp->pp_alivecnt == MAXALIVECNT) {
+ /* No keepalive packets got. Stop the interface. */
+ printk (KERN_WARNING "%s: protocol down\n", dev->name);
+ if_down (dev);
+ if (! (sp->pp_flags & PP_CISCO)) {
+ /* Shut down the PPP link. */
+ sp->lcp.magic = jiffies;
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ sppp_clear_timeout (sp);
+ /* Initiate negotiation. */
+ sppp_lcp_open (sp);
+ }
+ }
+ if (sp->pp_alivecnt <= MAXALIVECNT)
+ ++sp->pp_alivecnt;
+ if (sp->pp_flags & PP_CISCO)
+ sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
+ sp->pp_rseq);
+ else if (sp->lcp.state == LCP_STATE_OPENED) {
+ long nmagic = htonl (sp->lcp.magic);
+ sp->lcp.echoid = ++sp->pp_seq;
+ sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ,
+ sp->lcp.echoid, 4, &nmagic);
+ }
+
+ spin_unlock(&sp->lock);
+ }
+ spin_unlock_irqrestore(&spppq_lock, flags);
+ sppp_flush_xmit();
+ sppp_keepalive_timer.expires=jiffies+10*HZ;
+ add_timer(&sppp_keepalive_timer);
+}
+
+/*
+ * Handle incoming PPP Link Control Protocol packets.
+ */
+
+static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb)
+{
+ struct lcp_header *h;
+ struct net_device *dev = sp->pp_if;
+ int len = skb->len;
+ u8 *p, opt[6];
+ u32 rmagic;
+
+ if (!pskb_may_pull(skb, sizeof(struct lcp_header))) {
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n",
+ dev->name, len);
+ return;
+ }
+ h = (struct lcp_header *)skb->data;
+ skb_pull(skb,sizeof(struct lcp_header *));
+
+ if (sp->pp_flags & PP_DEBUG)
+ {
+ char state = '?';
+ switch (sp->lcp.state) {
+ case LCP_STATE_CLOSED: state = 'C'; break;
+ case LCP_STATE_ACK_RCVD: state = 'R'; break;
+ case LCP_STATE_ACK_SENT: state = 'S'; break;
+ case LCP_STATE_OPENED: state = 'O'; break;
+ }
+ printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh",
+ dev->name, state, len,
+ sppp_lcp_type_name (h->type), h->ident, ntohs (h->len));
+ if (len > 4)
+ sppp_print_bytes ((u8*) (h+1), len-4);
+ printk (">\n");
+ }
+ if (len > ntohs (h->len))
+ len = ntohs (h->len);
+ switch (h->type) {
+ default:
+ /* Unknown packet type -- send Code-Reject packet. */
+ sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq,
+ skb->len, h);
+ break;
+ case LCP_CONF_REQ:
+ if (len < 4) {
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n",
+ dev->name, len);
+ break;
+ }
+ if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic))
+ goto badreq;
+ if (rmagic == sp->lcp.magic) {
+ /* Local and remote magics equal -- loopback? */
+ if (sp->pp_loopcnt >= MAXALIVECNT*5) {
+ printk (KERN_WARNING "%s: loopback\n",
+ dev->name);
+ sp->pp_loopcnt = 0;
+ if (dev->flags & IFF_UP) {
+ if_down (dev);
+ }
+ } else if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_DEBUG "%s: conf req: magic glitch\n",
+ dev->name);
+ ++sp->pp_loopcnt;
+
+ /* MUST send Conf-Nack packet. */
+ rmagic = ~sp->lcp.magic;
+ opt[0] = LCP_OPT_MAGIC;
+ opt[1] = sizeof (opt);
+ opt[2] = rmagic >> 24;
+ opt[3] = rmagic >> 16;
+ opt[4] = rmagic >> 8;
+ opt[5] = rmagic;
+ sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK,
+ h->ident, sizeof (opt), &opt);
+badreq:
+ switch (sp->lcp.state) {
+ case LCP_STATE_OPENED:
+ /* Initiate renegotiation. */
+ sppp_lcp_open (sp);
+ /* fall through... */
+ case LCP_STATE_ACK_SENT:
+ /* Go to closed state. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ }
+ break;
+ }
+ /* Send Configure-Ack packet. */
+ sp->pp_loopcnt = 0;
+ if (sp->lcp.state != LCP_STATE_OPENED) {
+ sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
+ h->ident, len-4, h+1);
+ }
+ /* Change the state. */
+ switch (sp->lcp.state) {
+ case LCP_STATE_CLOSED:
+ sp->lcp.state = LCP_STATE_ACK_SENT;
+ break;
+ case LCP_STATE_ACK_RCVD:
+ sp->lcp.state = LCP_STATE_OPENED;
+ sppp_ipcp_open (sp);
+ break;
+ case LCP_STATE_OPENED:
+ /* Remote magic changed -- close session. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ /* Initiate renegotiation. */
+ sppp_lcp_open (sp);
+ /* Send ACK after our REQ in attempt to break loop */
+ sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
+ h->ident, len-4, h+1);
+ sp->lcp.state = LCP_STATE_ACK_SENT;
+ break;
+ }
+ break;
+ case LCP_CONF_ACK:
+ if (h->ident != sp->lcp.confid)
+ break;
+ sppp_clear_timeout (sp);
+ if ((sp->pp_link_state != SPPP_LINK_UP) &&
+ (dev->flags & IFF_UP)) {
+ /* Coming out of loopback mode. */
+ sp->pp_link_state=SPPP_LINK_UP;
+ printk (KERN_INFO "%s: protocol up\n", dev->name);
+ }
+ switch (sp->lcp.state) {
+ case LCP_STATE_CLOSED:
+ sp->lcp.state = LCP_STATE_ACK_RCVD;
+ sppp_set_timeout (sp, 5);
+ break;
+ case LCP_STATE_ACK_SENT:
+ sp->lcp.state = LCP_STATE_OPENED;
+ sppp_ipcp_open (sp);
+ break;
+ }
+ break;
+ case LCP_CONF_NAK:
+ if (h->ident != sp->lcp.confid)
+ break;
+ p = (u8*) (h+1);
+ if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) {
+ rmagic = (u32)p[2] << 24 |
+ (u32)p[3] << 16 | p[4] << 8 | p[5];
+ if (rmagic == ~sp->lcp.magic) {
+ int newmagic;
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_DEBUG "%s: conf nak: magic glitch\n",
+ dev->name);
+ get_random_bytes(&newmagic, sizeof(newmagic));
+ sp->lcp.magic += newmagic;
+ } else
+ sp->lcp.magic = rmagic;
+ }
+ if (sp->lcp.state != LCP_STATE_ACK_SENT) {
+ /* Go to closed state. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ }
+ /* The link will be renegotiated after timeout,
+ * to avoid endless req-nack loop. */
+ sppp_clear_timeout (sp);
+ sppp_set_timeout (sp, 2);
+ break;
+ case LCP_CONF_REJ:
+ if (h->ident != sp->lcp.confid)
+ break;
+ sppp_clear_timeout (sp);
+ /* Initiate renegotiation. */
+ sppp_lcp_open (sp);
+ if (sp->lcp.state != LCP_STATE_ACK_SENT) {
+ /* Go to closed state. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ }
+ break;
+ case LCP_TERM_REQ:
+ sppp_clear_timeout (sp);
+ /* Send Terminate-Ack packet. */
+ sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, NULL);
+ /* Go to closed state. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ /* Initiate renegotiation. */
+ sppp_lcp_open (sp);
+ break;
+ case LCP_TERM_ACK:
+ case LCP_CODE_REJ:
+ case LCP_PROTO_REJ:
+ /* Ignore for now. */
+ break;
+ case LCP_DISC_REQ:
+ /* Discard the packet. */
+ break;
+ case LCP_ECHO_REQ:
+ if (sp->lcp.state != LCP_STATE_OPENED)
+ break;
+ if (len < 8) {
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n",
+ dev->name, len);
+ break;
+ }
+ if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
+ /* Line loopback mode detected. */
+ printk (KERN_WARNING "%s: loopback\n", dev->name);
+ if_down (dev);
+
+ /* Shut down the PPP link. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ sppp_clear_timeout (sp);
+ /* Initiate negotiation. */
+ sppp_lcp_open (sp);
+ break;
+ }
+ *(long*)(h+1) = htonl (sp->lcp.magic);
+ sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1);
+ break;
+ case LCP_ECHO_REPLY:
+ if (h->ident != sp->lcp.echoid)
+ break;
+ if (len < 8) {
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n",
+ dev->name, len);
+ break;
+ }
+ if (ntohl (*(long*)(h+1)) != sp->lcp.magic)
+ sp->pp_alivecnt = 0;
+ break;
+ }
+}
+
+/*
+ * Handle incoming Cisco keepalive protocol packets.
+ */
+
+static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
+{
+ struct cisco_packet *h;
+ struct net_device *dev = sp->pp_if;
+
+ if (!pskb_may_pull(skb, sizeof(struct cisco_packet))
+ || (skb->len != CISCO_PACKET_LEN
+ && skb->len != CISCO_BIG_PACKET_LEN)) {
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n",
+ dev->name, skb->len);
+ return;
+ }
+ h = (struct cisco_packet *)skb->data;
+ skb_pull(skb, sizeof(struct cisco_packet*));
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: cisco input: %d bytes <%xh %xh %xh %xh %xh-%xh>\n",
+ dev->name, skb->len,
+ ntohl (h->type), h->par1, h->par2, h->rel,
+ h->time0, h->time1);
+ switch (ntohl (h->type)) {
+ default:
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: unknown cisco packet type: 0x%x\n",
+ dev->name, ntohl (h->type));
+ break;
+ case CISCO_ADDR_REPLY:
+ /* Reply on address request, ignore */
+ break;
+ case CISCO_KEEPALIVE_REQ:
+ sp->pp_alivecnt = 0;
+ sp->pp_rseq = ntohl (h->par1);
+ if (sp->pp_seq == sp->pp_rseq) {
+ /* Local and remote sequence numbers are equal.
+ * Probably, the line is in loopback mode. */
+ int newseq;
+ if (sp->pp_loopcnt >= MAXALIVECNT) {
+ printk (KERN_WARNING "%s: loopback\n",
+ dev->name);
+ sp->pp_loopcnt = 0;
+ if (dev->flags & IFF_UP) {
+ if_down (dev);
+ }
+ }
+ ++sp->pp_loopcnt;
+
+ /* Generate new local sequence number */
+ get_random_bytes(&newseq, sizeof(newseq));
+ sp->pp_seq ^= newseq;
+ break;
+ }
+ sp->pp_loopcnt = 0;
+ if (sp->pp_link_state==SPPP_LINK_DOWN &&
+ (dev->flags & IFF_UP)) {
+ sp->pp_link_state=SPPP_LINK_UP;
+ printk (KERN_INFO "%s: protocol up\n", dev->name);
+ }
+ break;
+ case CISCO_ADDR_REQ:
+ /* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */
+ {
+ struct in_device *in_dev;
+ struct in_ifaddr *ifa;
+ u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
+#ifdef CONFIG_INET
+ rcu_read_lock();
+ if ((in_dev = __in_dev_get_rcu(dev)) != NULL)
+ {
+ for (ifa=in_dev->ifa_list; ifa != NULL;
+ ifa=ifa->ifa_next) {
+ if (strcmp(dev->name, ifa->ifa_label) == 0)
+ {
+ addr = ifa->ifa_local;
+ mask = ifa->ifa_mask;
+ break;
+ }
+ }
+ }
+ rcu_read_unlock();
+#endif
+ /* I hope both addr and mask are in the net order */
+ sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask);
+ break;
+ }
+ }
+}
+
+
+/*
+ * Send PPP LCP packet.
+ */
+
+static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,
+ u8 ident, u16 len, void *data)
+{
+ struct ppp_header *h;
+ struct lcp_header *lh;
+ struct sk_buff *skb;
+ struct net_device *dev = sp->pp_if;
+
+ skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len,
+ GFP_ATOMIC);
+ if (skb==NULL)
+ return;
+
+ skb_reserve(skb,dev->hard_header_len);
+
+ h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header));
+ h->address = PPP_ALLSTATIONS; /* broadcast address */
+ h->control = PPP_UI; /* Unnumbered Info */
+ h->protocol = htons (proto); /* Link Control Protocol */
+
+ lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header));
+ lh->type = type;
+ lh->ident = ident;
+ lh->len = htons (LCP_HEADER_LEN + len);
+
+ if (len)
+ memcpy(skb_put(skb,len),data, len);
+
+ if (sp->pp_flags & PP_DEBUG) {
+ printk (KERN_WARNING "%s: %s output <%s id=%xh len=%xh",
+ dev->name,
+ proto==PPP_LCP ? "lcp" : "ipcp",
+ proto==PPP_LCP ? sppp_lcp_type_name (lh->type) :
+ sppp_ipcp_type_name (lh->type), lh->ident,
+ ntohs (lh->len));
+ if (len)
+ sppp_print_bytes ((u8*) (lh+1), len);
+ printk (">\n");
+ }
+ sp->obytes += skb->len;
+ /* Control is high priority so it doesn't get queued behind data */
+ skb->priority=TC_PRIO_CONTROL;
+ skb->dev = dev;
+ skb_queue_tail(&tx_queue, skb);
+}
+
+/*
+ * Send Cisco keepalive packet.
+ */
+
+static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2)
+{
+ struct ppp_header *h;
+ struct cisco_packet *ch;
+ struct sk_buff *skb;
+ struct net_device *dev = sp->pp_if;
+ u32 t = jiffies * 1000/HZ;
+
+ skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN,
+ GFP_ATOMIC);
+
+ if(skb==NULL)
+ return;
+
+ skb_reserve(skb, dev->hard_header_len);
+ h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header));
+ h->address = CISCO_MULTICAST;
+ h->control = 0;
+ h->protocol = htons (CISCO_KEEPALIVE);
+
+ ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN);
+ ch->type = htonl (type);
+ ch->par1 = htonl (par1);
+ ch->par2 = htonl (par2);
+ ch->rel = -1;
+ ch->time0 = htons ((u16) (t >> 16));
+ ch->time1 = htons ((u16) t);
+
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: cisco output: <%xh %xh %xh %xh %xh-%xh>\n",
+ dev->name, ntohl (ch->type), ch->par1,
+ ch->par2, ch->rel, ch->time0, ch->time1);
+ sp->obytes += skb->len;
+ skb->priority=TC_PRIO_CONTROL;
+ skb->dev = dev;
+ skb_queue_tail(&tx_queue, skb);
+}
+
+/**
+ * sppp_close - close down a synchronous PPP or Cisco HDLC link
+ * @dev: The network device to drop the link of
+ *
+ * This drops the logical interface to the channel. It is not
+ * done politely as we assume we will also be dropping DTR. Any
+ * timeouts are killed.
+ */
+
+int sppp_close (struct net_device *dev)
+{
+ struct sppp *sp = (struct sppp *)sppp_of(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sp->lock, flags);
+ sp->pp_link_state = SPPP_LINK_DOWN;
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ sppp_clear_timeout (sp);
+ spin_unlock_irqrestore(&sp->lock, flags);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(sppp_close);
+
+/**
+ * sppp_open - open a synchronous PPP or Cisco HDLC link
+ * @dev: Network device to activate
+ *
+ * Close down any existing synchronous session and commence
+ * from scratch. In the PPP case this means negotiating LCP/IPCP
+ * and friends, while for Cisco HDLC we simply need to start sending
+ * keepalives
+ */
+
+int sppp_open (struct net_device *dev)
+{
+ struct sppp *sp = (struct sppp *)sppp_of(dev);
+ unsigned long flags;
+
+ sppp_close(dev);
+
+ spin_lock_irqsave(&sp->lock, flags);
+ if (!(sp->pp_flags & PP_CISCO)) {
+ sppp_lcp_open (sp);
+ }
+ sp->pp_link_state = SPPP_LINK_DOWN;
+ spin_unlock_irqrestore(&sp->lock, flags);
+ sppp_flush_xmit();
+
+ return 0;
+}
+
+EXPORT_SYMBOL(sppp_open);
+
+/**
+ * sppp_reopen - notify of physical link loss
+ * @dev: Device that lost the link
+ *
+ * This function informs the synchronous protocol code that
+ * the underlying link died (for example a carrier drop on X.21)
+ *
+ * We increment the magic numbers to ensure that if the other end
+ * failed to notice we will correctly start a new session. It happens
+ * do to the nature of telco circuits is that you can lose carrier on
+ * one endonly.
+ *
+ * Having done this we go back to negotiating. This function may
+ * be called from an interrupt context.
+ */
+
+int sppp_reopen (struct net_device *dev)
+{
+ struct sppp *sp = (struct sppp *)sppp_of(dev);
+ unsigned long flags;
+
+ sppp_close(dev);
+
+ spin_lock_irqsave(&sp->lock, flags);
+ if (!(sp->pp_flags & PP_CISCO))
+ {
+ sp->lcp.magic = jiffies;
+ ++sp->pp_seq;
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ /* Give it a moment for the line to settle then go */
+ sppp_set_timeout (sp, 1);
+ }
+ sp->pp_link_state=SPPP_LINK_DOWN;
+ spin_unlock_irqrestore(&sp->lock, flags);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(sppp_reopen);
+
+/**
+ * sppp_change_mtu - Change the link MTU
+ * @dev: Device to change MTU on
+ * @new_mtu: New MTU
+ *
+ * Change the MTU on the link. This can only be called with
+ * the link down. It returns an error if the link is up or
+ * the mtu is out of range.
+ */
+
+static int sppp_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP))
+ return -EINVAL;
+ dev->mtu=new_mtu;
+ return 0;
+}
+
+/**
+ * sppp_do_ioctl - Ioctl handler for ppp/hdlc
+ * @dev: Device subject to ioctl
+ * @ifr: Interface request block from the user
+ * @cmd: Command that is being issued
+ *
+ * This function handles the ioctls that may be issued by the user
+ * to control the settings of a PPP/HDLC link. It does both busy
+ * and security checks. This function is intended to be wrapped by
+ * callers who wish to add additional ioctl calls of their own.
+ */
+
+int sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct sppp *sp = (struct sppp *)sppp_of(dev);
+
+ if(dev->flags&IFF_UP)
+ return -EBUSY;
+
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ switch(cmd)
+ {
+ case SPPPIOCCISCO:
+ sp->pp_flags|=PP_CISCO;
+ dev->type = ARPHRD_HDLC;
+ break;
+ case SPPPIOCPPP:
+ sp->pp_flags&=~PP_CISCO;
+ dev->type = ARPHRD_PPP;
+ break;
+ case SPPPIOCDEBUG:
+ sp->pp_flags&=~PP_DEBUG;
+ if(ifr->ifr_flags)
+ sp->pp_flags|=PP_DEBUG;
+ break;
+ case SPPPIOCGFLAGS:
+ if(copy_to_user(ifr->ifr_data, &sp->pp_flags, sizeof(sp->pp_flags)))
+ return -EFAULT;
+ break;
+ case SPPPIOCSFLAGS:
+ if(copy_from_user(&sp->pp_flags, ifr->ifr_data, sizeof(sp->pp_flags)))
+ return -EFAULT;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(sppp_do_ioctl);
+
+/**
+ * sppp_attach - attach synchronous PPP/HDLC to a device
+ * @pd: PPP device to initialise
+ *
+ * This initialises the PPP/HDLC support on an interface. At the
+ * time of calling the dev element must point to the network device
+ * that this interface is attached to. The interface should not yet
+ * be registered.
+ */
+
+void sppp_attach(struct ppp_device *pd)
+{
+ struct net_device *dev = pd->dev;
+ struct sppp *sp = &pd->sppp;
+ unsigned long flags;
+
+ /* Make sure embedding is safe for sppp_of */
+ BUG_ON(sppp_of(dev) != sp);
+
+ spin_lock_irqsave(&spppq_lock, flags);
+ /* Initialize keepalive handler. */
+ if (! spppq)
+ {
+ init_timer(&sppp_keepalive_timer);
+ sppp_keepalive_timer.expires=jiffies+10*HZ;
+ sppp_keepalive_timer.function=sppp_keepalive;
+ add_timer(&sppp_keepalive_timer);
+ }
+ /* Insert new entry into the keepalive list. */
+ sp->pp_next = spppq;
+ spppq = sp;
+ spin_unlock_irqrestore(&spppq_lock, flags);
+
+ sp->pp_loopcnt = 0;
+ sp->pp_alivecnt = 0;
+ sp->pp_seq = 0;
+ sp->pp_rseq = 0;
+ sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/
+ sp->lcp.magic = 0;
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ sp->pp_if = dev;
+ spin_lock_init(&sp->lock);
+
+ /*
+ * Device specific setup. All but interrupt handler and
+ * hard_start_xmit.
+ */
+
+ dev->hard_header = sppp_hard_header;
+ dev->rebuild_header = sppp_rebuild_header;
+ dev->tx_queue_len = 10;
+ dev->type = ARPHRD_HDLC;
+ dev->addr_len = 0;
+ dev->hard_header_len = sizeof(struct ppp_header);
+ dev->mtu = PPP_MTU;
+ /*
+ * These 4 are callers but MUST also call sppp_ functions
+ */
+ dev->do_ioctl = sppp_do_ioctl;
+#if 0
+ dev->get_stats = NULL; /* Let the driver override these */
+ dev->open = sppp_open;
+ dev->stop = sppp_close;
+#endif
+ dev->change_mtu = sppp_change_mtu;
+ dev->hard_header_cache = NULL;
+ dev->header_cache_update = NULL;
+ dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
+}
+
+EXPORT_SYMBOL(sppp_attach);
+
+/**
+ * sppp_detach - release PPP resources from a device
+ * @dev: Network device to release
+ *
+ * Stop and free up any PPP/HDLC resources used by this
+ * interface. This must be called before the device is
+ * freed.
+ */
+
+void sppp_detach (struct net_device *dev)
+{
+ struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&spppq_lock, flags);
+ /* Remove the entry from the keepalive list. */
+ for (q = &spppq; (p = *q); q = &p->pp_next)
+ if (p == sp) {
+ *q = p->pp_next;
+ break;
+ }
+
+ /* Stop keepalive handler. */
+ if (! spppq)
+ del_timer(&sppp_keepalive_timer);
+ sppp_clear_timeout (sp);
+ spin_unlock_irqrestore(&spppq_lock, flags);
+}
+
+EXPORT_SYMBOL(sppp_detach);
+
+/*
+ * Analyze the LCP Configure-Request options list
+ * for the presence of unknown options.
+ * If the request contains unknown options, build and
+ * send Configure-reject packet, containing only unknown options.
+ */
+static int
+sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
+ int len, u32 *magic)
+{
+ u8 *buf, *r, *p;
+ int rlen;
+
+ len -= 4;
+ buf = r = kmalloc (len, GFP_ATOMIC);
+ if (! buf)
+ return (0);
+
+ p = (void*) (h+1);
+ for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+ switch (*p) {
+ case LCP_OPT_MAGIC:
+ /* Magic number -- extract. */
+ if (len >= 6 && p[1] == 6) {
+ *magic = (u32)p[2] << 24 |
+ (u32)p[3] << 16 | p[4] << 8 | p[5];
+ continue;
+ }
+ break;
+ case LCP_OPT_ASYNC_MAP:
+ /* Async control character map -- check to be zero. */
+ if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] &&
+ ! p[4] && ! p[5])
+ continue;
+ break;
+ case LCP_OPT_MRU:
+ /* Maximum receive unit -- always OK. */
+ continue;
+ default:
+ /* Others not supported. */
+ break;
+ }
+ /* Add the option to rejected list. */
+ memcpy(r, p, p[1]);
+ r += p[1];
+ rlen += p[1];
+ }
+ if (rlen)
+ sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf);
+ kfree(buf);
+ return (rlen == 0);
+}
+
+static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb)
+{
+ struct lcp_header *h;
+ struct net_device *dev = sp->pp_if;
+ int len = skb->len;
+
+ if (!pskb_may_pull(skb, sizeof(struct lcp_header))) {
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n",
+ dev->name, len);
+ return;
+ }
+ h = (struct lcp_header *)skb->data;
+ skb_pull(skb,sizeof(struct lcp_header));
+ if (sp->pp_flags & PP_DEBUG) {
+ printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh",
+ dev->name, len,
+ sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len));
+ if (len > 4)
+ sppp_print_bytes ((u8*) (h+1), len-4);
+ printk (">\n");
+ }
+ if (len > ntohs (h->len))
+ len = ntohs (h->len);
+ switch (h->type) {
+ default:
+ /* Unknown packet type -- send Code-Reject packet. */
+ sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h);
+ break;
+ case IPCP_CONF_REQ:
+ if (len < 4) {
+ if (sp->pp_flags & PP_DEBUG)
+ printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n",
+ dev->name, len);
+ return;
+ }
+ if (len > 4) {
+ sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident,
+ len-4, h+1);
+
+ switch (sp->ipcp.state) {
+ case IPCP_STATE_OPENED:
+ /* Initiate renegotiation. */
+ sppp_ipcp_open (sp);
+ /* fall through... */
+ case IPCP_STATE_ACK_SENT:
+ /* Go to closed state. */
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ }
+ } else {
+ /* Send Configure-Ack packet. */
+ sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident,
+ 0, NULL);
+ /* Change the state. */
+ if (sp->ipcp.state == IPCP_STATE_ACK_RCVD)
+ sp->ipcp.state = IPCP_STATE_OPENED;
+ else
+ sp->ipcp.state = IPCP_STATE_ACK_SENT;
+ }
+ break;
+ case IPCP_CONF_ACK:
+ if (h->ident != sp->ipcp.confid)
+ break;
+ sppp_clear_timeout (sp);
+ switch (sp->ipcp.state) {
+ case IPCP_STATE_CLOSED:
+ sp->ipcp.state = IPCP_STATE_ACK_RCVD;
+ sppp_set_timeout (sp, 5);
+ break;
+ case IPCP_STATE_ACK_SENT:
+ sp->ipcp.state = IPCP_STATE_OPENED;
+ break;
+ }
+ break;
+ case IPCP_CONF_NAK:
+ case IPCP_CONF_REJ:
+ if (h->ident != sp->ipcp.confid)
+ break;
+ sppp_clear_timeout (sp);
+ /* Initiate renegotiation. */
+ sppp_ipcp_open (sp);
+ if (sp->ipcp.state != IPCP_STATE_ACK_SENT)
+ /* Go to closed state. */
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ break;
+ case IPCP_TERM_REQ:
+ /* Send Terminate-Ack packet. */
+ sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, NULL);
+ /* Go to closed state. */
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ /* Initiate renegotiation. */
+ sppp_ipcp_open (sp);
+ break;
+ case IPCP_TERM_ACK:
+ /* Ignore for now. */
+ case IPCP_CODE_REJ:
+ /* Ignore for now. */
+ break;
+ }
+}
+
+static void sppp_lcp_open (struct sppp *sp)
+{
+ char opt[6];
+
+ if (! sp->lcp.magic)
+ sp->lcp.magic = jiffies;
+ opt[0] = LCP_OPT_MAGIC;
+ opt[1] = sizeof (opt);
+ opt[2] = sp->lcp.magic >> 24;
+ opt[3] = sp->lcp.magic >> 16;
+ opt[4] = sp->lcp.magic >> 8;
+ opt[5] = sp->lcp.magic;
+ sp->lcp.confid = ++sp->pp_seq;
+ sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid,
+ sizeof (opt), &opt);
+ sppp_set_timeout (sp, 2);
+}
+
+static void sppp_ipcp_open (struct sppp *sp)
+{
+ sp->ipcp.confid = ++sp->pp_seq;
+ sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, NULL);
+ sppp_set_timeout (sp, 2);
+}
+
+/*
+ * Process PPP control protocol timeouts.
+ */
+
+static void sppp_cp_timeout (unsigned long arg)
+{
+ struct sppp *sp = (struct sppp*) arg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sp->lock, flags);
+
+ sp->pp_flags &= ~PP_TIMO;
+ if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) {
+ spin_unlock_irqrestore(&sp->lock, flags);
+ return;
+ }
+ switch (sp->lcp.state) {
+ case LCP_STATE_CLOSED:
+ /* No ACK for Configure-Request, retry. */
+ sppp_lcp_open (sp);
+ break;
+ case LCP_STATE_ACK_RCVD:
+ /* ACK got, but no Configure-Request for peer, retry. */
+ sppp_lcp_open (sp);
+ sp->lcp.state = LCP_STATE_CLOSED;
+ break;
+ case LCP_STATE_ACK_SENT:
+ /* ACK sent but no ACK for Configure-Request, retry. */
+ sppp_lcp_open (sp);
+ break;
+ case LCP_STATE_OPENED:
+ /* LCP is already OK, try IPCP. */
+ switch (sp->ipcp.state) {
+ case IPCP_STATE_CLOSED:
+ /* No ACK for Configure-Request, retry. */
+ sppp_ipcp_open (sp);
+ break;
+ case IPCP_STATE_ACK_RCVD:
+ /* ACK got, but no Configure-Request for peer, retry. */
+ sppp_ipcp_open (sp);
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ break;
+ case IPCP_STATE_ACK_SENT:
+ /* ACK sent but no ACK for Configure-Request, retry. */
+ sppp_ipcp_open (sp);
+ break;
+ case IPCP_STATE_OPENED:
+ /* IPCP is OK. */
+ break;
+ }
+ break;
+ }
+ spin_unlock_irqrestore(&sp->lock, flags);
+ sppp_flush_xmit();
+}
+
+static char *sppp_lcp_type_name (u8 type)
+{
+ static char buf [8];
+ switch (type) {
+ case LCP_CONF_REQ: return ("conf-req");
+ case LCP_CONF_ACK: return ("conf-ack");
+ case LCP_CONF_NAK: return ("conf-nack");
+ case LCP_CONF_REJ: return ("conf-rej");
+ case LCP_TERM_REQ: return ("term-req");
+ case LCP_TERM_ACK: return ("term-ack");
+ case LCP_CODE_REJ: return ("code-rej");
+ case LCP_PROTO_REJ: return ("proto-rej");
+ case LCP_ECHO_REQ: return ("echo-req");
+ case LCP_ECHO_REPLY: return ("echo-reply");
+ case LCP_DISC_REQ: return ("discard-req");
+ }
+ sprintf (buf, "%xh", type);
+ return (buf);
+}
+
+static char *sppp_ipcp_type_name (u8 type)
+{
+ static char buf [8];
+ switch (type) {
+ case IPCP_CONF_REQ: return ("conf-req");
+ case IPCP_CONF_ACK: return ("conf-ack");
+ case IPCP_CONF_NAK: return ("conf-nack");
+ case IPCP_CONF_REJ: return ("conf-rej");
+ case IPCP_TERM_REQ: return ("term-req");
+ case IPCP_TERM_ACK: return ("term-ack");
+ case IPCP_CODE_REJ: return ("code-rej");
+ }
+ sprintf (buf, "%xh", type);
+ return (buf);
+}
+
+static void sppp_print_bytes (u_char *p, u16 len)
+{
+ printk (" %x", *p++);
+ while (--len > 0)
+ printk ("-%x", *p++);
+}
+
+/**
+ * sppp_rcv - receive and process a WAN PPP frame
+ * @skb: The buffer to process
+ * @dev: The device it arrived on
+ * @p: Unused
+ * @orig_dev: Unused
+ *
+ * Protocol glue. This drives the deferred processing mode the poorer
+ * cards use. This can be called directly by cards that do not have
+ * timing constraints but is normally called from the network layer
+ * after interrupt servicing to process frames queued via netif_rx.
+ */
+
+static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev)
+{
+ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
+ return NET_RX_DROP;
+ sppp_input(dev,skb);
+ return 0;
+}
+
+static struct packet_type sppp_packet_type = {
+ .type = __constant_htons(ETH_P_WAN_PPP),
+ .func = sppp_rcv,
+};
+
+static char banner[] __initdata =
+ KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"
+ KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & "
+ "Jan \"Yenya\" Kasprzak.\n";
+
+static int __init sync_ppp_init(void)
+{
+ if(debug)
+ debug=PP_DEBUG;
+ printk(banner);
+ skb_queue_head_init(&tx_queue);
+ dev_add_pack(&sppp_packet_type);
+ return 0;
+}
+
+
+static void __exit sync_ppp_cleanup(void)
+{
+ dev_remove_pack(&sppp_packet_type);
+}
+
+module_init(sync_ppp_init);
+module_exit(sync_ppp_cleanup);
+module_param(debug, int, 0);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/dahdi/digits.h b/drivers/dahdi/digits.h
new file mode 100644
index 0000000..9f4ea9b
--- /dev/null
+++ b/drivers/dahdi/digits.h
@@ -0,0 +1,48 @@
+/*
+ * Zapata Telephony
+ *
+ * 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.
+ *
+ */
+
+#ifndef _DIGITS_H
+#define _DIGITS_H
+
+#define DEFAULT_DTMF_LENGTH 100 * ZT_CHUNKSIZE
+#define DEFAULT_MFR1_LENGTH 68 * ZT_CHUNKSIZE
+#define DEFAULT_MFR2_LENGTH 100 * ZT_CHUNKSIZE
+#define PAUSE_LENGTH 500 * ZT_CHUNKSIZE
+
+/* At the end of silence, the tone stops */
+static struct zt_tone dtmf_silence = {
+ .tonesamples = DEFAULT_DTMF_LENGTH,
+};
+
+/* At the end of silence, the tone stops */
+static struct zt_tone mfr1_silence = {
+ .tonesamples = DEFAULT_MFR1_LENGTH,
+};
+
+/* At the end of silence, the tone stops */
+static struct zt_tone mfr2_silence = {
+ .tonesamples = DEFAULT_MFR2_LENGTH,
+};
+
+/* A pause in the dialing */
+static struct zt_tone tone_pause = {
+ .tonesamples = PAUSE_LENGTH,
+};
+
+#endif
diff --git a/drivers/dahdi/ecdis.h b/drivers/dahdi/ecdis.h
new file mode 100644
index 0000000..4d3801b
--- /dev/null
+++ b/drivers/dahdi/ecdis.h
@@ -0,0 +1,118 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * ec_disable_detector.h - A detector which should eventually meet the
+ * G.164/G.165 requirements for detecting the
+ * 2100Hz echo cancellor disable tone.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ * 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 "biquad.h"
+
+typedef struct
+{
+ biquad2_state_t notch;
+ int notch_level;
+ int channel_level;
+ int tone_present;
+ int tone_cycle_duration;
+ int good_cycles;
+ int hit;
+} echo_can_disable_detector_state_t;
+
+
+#define FALSE 0
+#define TRUE (!FALSE)
+
+static inline void echo_can_disable_detector_init (echo_can_disable_detector_state_t *det)
+{
+ /* Elliptic notch */
+ /* This is actually centred at 2095Hz, but gets the balance we want, due
+ to the asymmetric walls of the notch */
+ biquad2_init (&det->notch,
+ (int32_t) (-0.7600000*32768.0),
+ (int32_t) (-0.1183852*32768.0),
+ (int32_t) (-0.5104039*32768.0),
+ (int32_t) ( 0.1567596*32768.0),
+ (int32_t) ( 1.0000000*32768.0));
+
+ det->channel_level = 0;
+ det->notch_level = 0;
+ det->tone_present = FALSE;
+ det->tone_cycle_duration = 0;
+ det->good_cycles = 0;
+ det->hit = 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline int echo_can_disable_detector_update (echo_can_disable_detector_state_t *det,
+ int16_t amp)
+{
+ int16_t notched;
+
+ notched = biquad2 (&det->notch, amp);
+ /* Estimate the overall energy in the channel, and the energy in
+ the notch (i.e. overall channel energy - tone energy => noise).
+ Use abs instead of multiply for speed (is it really faster?).
+ Damp the overall energy a little more for a stable result.
+ Damp the notch energy a little less, so we don't damp out the
+ blip every time the phase reverses */
+ det->channel_level += ((abs(amp) - det->channel_level) >> 5);
+ det->notch_level += ((abs(notched) - det->notch_level) >> 4);
+ if (det->channel_level > 280)
+ {
+ /* There is adequate energy in the channel. Is it mostly at 2100Hz? */
+ if (det->notch_level*6 < det->channel_level)
+ {
+ /* The notch says yes, so we have the tone. */
+ if (!det->tone_present)
+ {
+ /* Do we get a kick every 450+-25ms? */
+ if (det->tone_cycle_duration >= 425*8
+ &&
+ det->tone_cycle_duration <= 475*8)
+ {
+ det->good_cycles++;
+ if (det->good_cycles > 2)
+ det->hit = TRUE;
+ }
+ det->tone_cycle_duration = 0;
+ }
+ det->tone_present = TRUE;
+ }
+ else
+ {
+ det->tone_present = FALSE;
+ }
+ det->tone_cycle_duration++;
+ }
+ else
+ {
+ det->tone_present = FALSE;
+ det->tone_cycle_duration = 0;
+ det->good_cycles = 0;
+ }
+ return det->hit;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
diff --git a/drivers/dahdi/fasthdlc.h b/drivers/dahdi/fasthdlc.h
new file mode 100644
index 0000000..adb5597
--- /dev/null
+++ b/drivers/dahdi/fasthdlc.h
@@ -0,0 +1,462 @@
+/*
+ * Mark's Mythical Table-based raw HDLC implementation
+ *
+ * This is designed to be a very fast, but memory efficient
+ * implementation of standard HDLC protocol.
+ *
+ * This table based HDLC technology is PATENT PENDING, but will always be
+ * remain freely distributable under the terms of the GPL version 2.0.
+ *
+ * For non-GPL licensing, please contact Mark Spencer at
+ * the below e-mail address.
+ *
+ * Copyright (C) 2001, Linux Support Services, Inc.
+ *
+ * Written by Mark Spencer <markster@linux-support.net>
+ *
+ * Distributed under the terms of the GNU General Public License
+ * Version 2.0.
+ *
+ */
+
+#ifndef _FASTHDLC_H
+#define _FASTHDLC_H
+
+struct fasthdlc_state {
+ int state; /* What state we are in */
+ unsigned int data; /* Our current data queue */
+ int bits; /* Number of bits in our data queue */
+ int ones; /* Number of ones */
+};
+
+#ifdef FAST_HDLC_NEED_TABLES
+#define RETURN_COMPLETE_FLAG (0x1000)
+#define RETURN_DISCARD_FLAG (0x2000)
+#define RETURN_EMPTY_FLAG (0x4000)
+
+/* Unlike most HDLC implementations, we define only two states,
+ when we are in a valid frame, and when we are searching for
+ a frame header */
+
+#define FRAME_SEARCH 0
+#define PROCESS_FRAME 1
+
+/*
+
+ HDLC Search State table -- Look for a frame header. The return value
+ of this table is as follows:
+
+ |---8---|---7---|---6---|---5---|---4---|---3---|---2---|---1---|
+ | Z E R O E S | Next | Bits Consumed |
+ |-------|-------|-------|-------|-------|-------|-------|-------|
+
+ The indexes for this table are the state (0 or 1) and the next 8
+ bits of the stream.
+
+ Note that this table is only used for state 0 and 1.
+
+ The user should discard the top "bits consumed" bits of data before
+ the next call. "Next state" represents the actual next state for
+ decoding.
+
+*/
+static unsigned char hdlc_search[256];
+
+/*
+ HDLC Data Table
+
+ The indexes to this table are the number of one's we've seen so far (0-5) and
+ the next 10 bits of input (which is enough to guarantee us that we
+ will retrieve at least one byte of data (or frame or whatever).
+
+ The format for the return value is:
+
+ Bits 15: Status (1=Valid Data, 0=Control Frame (see bits 7-0 for type))
+ Bits 14-12: Number of ones in a row, so far
+ Bits 11-8: The number of bits consumed (0-10)
+ Bits 7-0: The return data (if appropriate)
+
+ The next state is simply bit #15
+
+*/
+
+#define CONTROL_COMPLETE 1
+#define CONTROL_ABORT 2
+
+#define STATUS_MASK (1 << 15)
+#define STATUS_VALID (1 << 15)
+#define STATUS_CONTROL (0 << 15)
+#define STATE_MASK (1 << 15)
+#define ONES_MASK (7 << 12)
+#define DATA_MASK (0xff)
+
+static unsigned short hdlc_frame[6][1024];
+
+static unsigned int minbits[2] = { 8, 10 };
+
+/*
+ Last, but not least, we have the encoder table. It takes
+ as its indices the number of ones so far and a byte of data
+ and returns an int composed of the following fields:
+
+ Bots 31-22: Actual Data
+ Bits 21-16: Unused
+ Bits 15-8: Number of ones
+ Bits 3-0: Number of bits of output (13-4) to use
+
+ Of course we could optimize by reducing to two tables, but I don't
+ really think it's worth the trouble at this point.
+ */
+
+static unsigned int hdlc_encode[6][256];
+
+static inline char hdlc_search_precalc(unsigned char c)
+{
+ int x, p=0;
+ /* Look for a flag. If this isn't a flag,
+ line us up for the next possible shot at
+ a flag */
+
+ /* If it's a flag, we go to state 1, and have
+ consumed 8 bits */
+ if (c == 0x7e)
+ return 0x10 | 8;
+
+ /* If it's an abort, we stay in the same state
+ and have consumed 8 bits */
+ if (c == 0x7f)
+ return 0x00 | 8;
+
+ /* If it's all 1's, we state in the same state and
+ have consumed 8 bits */
+ if (c == 0xff)
+ return 0x00 | 8;
+
+ /* If we get here, we must have at least one zero in us
+ but we're not the flag. So, start at the end (LSB) and
+ work our way to the top (MSB) looking for a zero. The
+ position of that 0 is most optimistic start of a real
+ frame header */
+ x=1;
+ p=7;
+ while(p && (c & x)) {
+ x <<= 1;
+ p--;
+ }
+ return p;
+}
+
+#ifdef DEBUG_PRECALC
+static inline void hdlc_search_print(char c, char r)
+{
+ int x=0x80;
+ while(x) {
+ printf("%s", c & x ? "1" : "0");
+ x >>= 1;
+ }
+ printf(" => State %d, Consume %d\n", (r & 0x10) >> 4, r & 0xf);
+}
+#endif
+
+#define HFP(status, ones, bits, data) \
+ ((status) | ((ones) << 12) | ((bits) << 8) | (data))
+
+static inline unsigned int hdlc_frame_precalc(unsigned char x, unsigned short c)
+{
+ /* Assume we have seen 'x' one's so far, and have read the
+ bottom 10 bytes of c (MSB first). Now, we HAVE to have
+ a byte of data or a frame or something. We are assumed
+ to be at the beginning of a byte of data or something */
+ unsigned char ones = x;
+ unsigned char data=0;
+ int bits=0;
+ int consumed=0;
+ while(bits < 8) {
+ data >>=1;
+ consumed++;
+ if (ones == 5) {
+ /* We've seen five ones */
+ if (c & 0x0200) {
+ /* Another one -- Some sort of signal frame */
+ if ((!(c & 0x0100)) && (bits == 6)) {
+ /* This is a frame terminator (10) */
+ return HFP(0,
+ 0, 8, CONTROL_COMPLETE);
+ } else {
+ /* Yuck! It's something else...
+ Abort this entire frame, and
+ start looking for a good frame */
+ return HFP(0,
+ 0, consumed+1, CONTROL_ABORT);
+ }
+ } else {
+ /* It's an inserted zero, just skip it */
+ ones = 0;
+ data <<= 1;
+ }
+ } else {
+ /* Add it to our bit list, LSB to
+ MSB */
+ if (c & 0x0200) {
+ data |= 0x80;
+ ones++;
+ } else
+ ones=0;
+ bits++;
+ }
+ c <<= 1;
+ }
+ /* Consume the extra 0 now rather than later. */
+ if (ones == 5) {
+ ones = 0;
+ consumed++;
+ }
+ return HFP(STATUS_VALID, ones, consumed, data);
+}
+
+#ifdef DEBUG_PRECALC
+
+static inline void hdlc_frame_print(unsigned char x, unsigned short c, unsigned int res)
+{
+ int z=0x0200;
+ char *status[] = {
+ "Control",
+ "Valid",
+ };
+ printf("%d one's then ", x);
+ while(z) {
+ printf("%s", c & z ? "1" : "0");
+ z >>= 1;
+ }
+ printf(" => Status %s, ", res & STATUS_MASK ? "1" : "0");
+ printf("Consumed: %d, ", (res & 0x0f00) >> 8);
+ printf("Status: %s, ", status[(res & STATUS_MASK) >> 15]);
+ printf("Ones: %d, ", (res & ONES_MASK) >> 12);
+ printf("Data: %02x\n", res & 0xff);
+
+}
+
+#endif
+
+static inline unsigned int hdlc_encode_precalc(int x, unsigned char y)
+{
+ int bits=0;
+ int ones=x;
+ unsigned short data=0;
+ int z;
+ for (z=0;z<8;z++) {
+ /* Zero-stuff if needed */
+ if (ones == 5) {
+ /* Stuff a zero */
+ data <<= 1;
+ ones=0;
+ bits++;
+ }
+ if (y & 0x01) {
+ /* There's a one */
+ data <<= 1;
+ data |= 0x1;
+ ones++;
+ bits++;
+ } else {
+ data <<= 1;
+ ones = 0;
+ bits++;
+ }
+ y >>= 1;
+ }
+ /* Special case -- Stuff the zero at the end if appropriate */
+ if (ones == 5) {
+ /* Stuff a zero */
+ data <<= 1;
+ ones=0;
+ bits++;
+ }
+ data <<= (10-bits);
+ return (data << 22) | (ones << 8) | (bits);
+}
+
+#ifdef DEBUG_PRECALC
+static inline void hdlc_encode_print(int x, unsigned char y, unsigned int val)
+{
+ unsigned int z;
+ unsigned short c;
+ printf("%d ones, %02x (", x, y);
+ z = 0x80;
+ while(z) {
+ printf("%s", y & z ? "1" : "0");
+ z >>= 1;
+ }
+ printf(") encoded as ");
+ z = 1 << 31;
+ for (x=0;x<(val & 0xf);x++) {
+ printf("%s", val & z ? "1" : "0");
+ z >>= 1;
+ }
+ printf(" with %d ones now, %d bits in len\n", (val & 0xf00) >> 8, val & 0xf);
+
+
+}
+#endif
+
+static inline void fasthdlc_precalc(void)
+{
+ int x;
+ int y;
+ /* First the easy part -- the searching */
+ for (x=0;x<256;x++) {
+ hdlc_search[x] = hdlc_search_precalc(x);
+#ifdef DEBUG_PRECALC
+ hdlc_search_print(x, hdlc_search[x]);
+#endif
+ }
+ /* Now the hard part -- the frame tables */
+ for (x=0;x<6;x++) {
+ /* Given the # of preceeding ones, process the next
+ byte of input (up to 10 actual bits) */
+ for (y=0;y<1024;y++) {
+ hdlc_frame[x][y] = hdlc_frame_precalc(x, y);
+#ifdef DEBUG_PRECALC
+ hdlc_frame_print(x, y, hdlc_frame[x][y]);
+#endif
+ }
+ }
+ /* Now another not-so-hard part, the encoding table */
+ for (x=0;x<6;x++) {
+ for (y=0;y<256;y++) {
+ hdlc_encode[x][y] = hdlc_encode_precalc(x,y);
+#ifdef DEBUG_PRECALC
+ hdlc_encode_print(x,y,hdlc_encode[x][y]);
+#endif
+ }
+ }
+}
+
+
+static inline void fasthdlc_init(struct fasthdlc_state *h)
+{
+ /* Initializes all states appropriately */
+ h->state = 0;
+ h->bits = 0;
+ h->data = 0;
+ h->ones = 0;
+
+}
+
+static inline int fasthdlc_tx_load_nocheck(struct fasthdlc_state *h, unsigned char c)
+{
+ unsigned int res;
+ res = hdlc_encode[h->ones][c];
+ h->ones = (res & 0xf00) >> 8;
+ h->data |= (res & 0xffc00000) >> h->bits;
+ h->bits += (res & 0xf);
+ return 0;
+}
+
+static inline int fasthdlc_tx_load(struct fasthdlc_state *h, unsigned char c)
+{
+ /* Gotta have at least 10 bits left */
+ if (h->bits > 22)
+ return -1;
+ return fasthdlc_tx_load_nocheck(h, c);
+}
+
+static inline int fasthdlc_tx_frame_nocheck(struct fasthdlc_state *h)
+{
+ h->ones = 0;
+ h->data |= ( 0x7e000000 >> h->bits);
+ h->bits += 8;
+ return 0;
+}
+
+static inline int fasthdlc_tx_frame(struct fasthdlc_state *h)
+{
+ if (h->bits > 24)
+ return -1;
+ return fasthdlc_tx_frame_nocheck(h);
+}
+
+static inline int fasthdlc_tx_run_nocheck(struct fasthdlc_state *h)
+{
+ unsigned char b;
+ b = h->data >> 24;
+ h->bits -= 8;
+ h->data <<= 8;
+ return b;
+}
+
+static inline int fasthdlc_tx_run(struct fasthdlc_state *h)
+{
+ if (h->bits < 8)
+ return -1;
+ return fasthdlc_tx_run_nocheck(h);
+}
+
+static inline int fasthdlc_rx_load_nocheck(struct fasthdlc_state *h, unsigned char b)
+{
+ /* Put the new byte in the data stream */
+ h->data |= b << (24-h->bits);
+ h->bits += 8;
+ return 0;
+}
+
+static inline int fasthdlc_rx_load(struct fasthdlc_state *h, unsigned char b)
+{
+ /* Make sure we have enough space */
+ if (h->bits > 24)
+ return -1;
+ return fasthdlc_rx_load_nocheck(h, b);
+}
+
+/*
+ Returns a data character if available, logical OR'd with
+ zero or more of RETURN_COMPLETE_FLAG, RETURN_DISCARD_FLAG,
+ and RETURN_EMPTY_FLAG, signifying a complete frame, a
+ discarded frame, or there is nothing to return.
+ */
+
+static inline int fasthdlc_rx_run(struct fasthdlc_state *h)
+{
+ unsigned short next;
+ int retval=RETURN_EMPTY_FLAG;
+ while ((h->bits >= minbits[h->state]) && (retval == RETURN_EMPTY_FLAG)) {
+ /* Run until we can no longer be assured that we will
+ have enough bits to continue */
+ switch(h->state) {
+ case FRAME_SEARCH:
+ /* Look for an HDLC frame, keying from
+ the top byte. */
+ next = hdlc_search[h->data >> 24];
+ h->bits -= next & 0x0f;
+ h->data <<= next & 0x0f;
+ h->state = next >> 4;
+ h->ones = 0;
+ break;
+ case PROCESS_FRAME:
+ /* Process as much as the next ten bits */
+ next = hdlc_frame[h->ones][h->data >> 22];
+ h->bits -= ((next & 0x0f00) >> 8);
+ h->data <<= ((next & 0x0f00) >> 8);
+ h->state = (next & STATE_MASK) >> 15;
+ h->ones = (next & ONES_MASK) >> 12;
+ switch(next & STATUS_MASK) {
+ case STATUS_CONTROL:
+ if (next & CONTROL_COMPLETE) {
+ /* A complete, valid frame received */
+ retval = (RETURN_COMPLETE_FLAG);
+ /* Stay in this state */
+ h->state = 1;
+ } else {
+ /* An abort (either out of sync of explicit) */
+ retval = (RETURN_DISCARD_FLAG);
+ }
+ break;
+ case STATUS_VALID:
+ retval = (next & DATA_MASK);
+ }
+ }
+ }
+ return retval;
+}
+#endif /* FAST_HDLC_NEED_TABLES */
+#endif
diff --git a/drivers/dahdi/fir.h b/drivers/dahdi/fir.h
new file mode 100644
index 0000000..1722285
--- /dev/null
+++ b/drivers/dahdi/fir.h
@@ -0,0 +1,130 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * fir.h - General telephony FIR routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2002 Steve Underwood
+ *
+ * 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(_FIR_H_)
+#define _FIR_H_
+
+typedef struct
+{
+ int taps;
+ int curr_pos;
+ int16_t *coeffs;
+ int16_t *history;
+} fir16_state_t;
+
+typedef struct
+{
+ int taps;
+ int curr_pos;
+ int32_t *coeffs;
+ int16_t *history;
+} fir32_state_t;
+
+static inline void fir16_create (fir16_state_t *fir,
+ int16_t *coeffs,
+ int taps)
+{
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+ fir->history = MALLOC (taps*sizeof (int16_t));
+ if (fir->history)
+ memset (fir->history, '\0', taps*sizeof (int16_t));
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline void fir16_free (fir16_state_t *fir)
+{
+ FREE (fir->history);
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline int16_t fir16 (fir16_state_t *fir, int16_t sample)
+{
+ int i;
+ int offset1;
+ int offset2;
+ int32_t y;
+
+ fir->history[fir->curr_pos] = sample;
+ offset2 = fir->curr_pos + 1;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i]*fir->history[i - offset1];
+ for ( ; i >= 0; i--)
+ y += fir->coeffs[i]*fir->history[i + offset2];
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return y >> 15;
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline void fir32_create (fir32_state_t *fir,
+ int32_t *coeffs,
+ int taps)
+{
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+ fir->history = MALLOC (taps*sizeof (int16_t));
+ if (fir->history)
+ memset (fir->history, '\0', taps*sizeof (int16_t));
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline void fir32_free (fir32_state_t *fir)
+{
+ FREE (fir->history);
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline int16_t fir32 (fir32_state_t *fir, int16_t sample)
+{
+ int i;
+ int offset1;
+ int offset2;
+ int32_t y;
+
+ fir->history[fir->curr_pos] = sample;
+ offset2 = fir->curr_pos + 1;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i]*fir->history[i - offset1];
+ for ( ; i >= 0; i--)
+ y += fir->coeffs[i]*fir->history[i + offset2];
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return y >> 15;
+}
+/*- End of function --------------------------------------------------------*/
+
+#endif
+/*- End of file ------------------------------------------------------------*/
diff --git a/drivers/dahdi/fxo_modes.h b/drivers/dahdi/fxo_modes.h
new file mode 100644
index 0000000..83172a5
--- /dev/null
+++ b/drivers/dahdi/fxo_modes.h
@@ -0,0 +1,588 @@
+/*
+ * FXO port mode settings for various regions
+ *
+ * Copyright (C) 2008 Digium, Inc.
+ *
+ * extracted from wctdm.c by
+ * Kevin P. Fleming <kpfleming@digium.com>
+ *
+ * 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.
+ */
+
+#ifndef _FXO_MODES_H
+#define _FXO_MODES_H
+
+static struct fxo_mode {
+ char *name;
+ int ohs;
+ int ohs2;
+ int rz;
+ int rt;
+ int ilim;
+ int dcv;
+ int mini;
+ int acim;
+ int ring_osc;
+ int ring_x;
+ unsigned int battdebounce; /* in milliseconds */
+ unsigned int battalarm; /* in milliseconds */
+ unsigned int battthresh; /* unknown units */
+} fxo_modes[] =
+{
+ /* US, Canada */
+ { .name = "FCC",
+ .rt = 1,
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ /* Austria, Belgium, Denmark, Finland, France, Germany,
+ Greece, Iceland, Ireland, Italy, Luxembourg, Netherlands,
+ Norway, Portugal, Spain, Sweden, Switzerland, and UK */
+ { .name = "TBR21",
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .ring_osc = 0x7e6c,
+ .ring_x = 0x023a,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "ARGENTINA",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "AUSTRALIA",
+ .ohs = 1,
+ .mini = 0x3,
+ .acim = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "AUSTRIA",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "BAHRAIN",
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "BELGIUM",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "BRAZIL",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "BULGARIA",
+ .ilim = 1,
+ .dcv = 0x3,
+ .mini = 0x0,
+ .acim = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "CANADA",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "CHILE",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "CHINA",
+ .mini = 0x3,
+ .acim = 0xf,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "COLOMBIA",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "CROATIA",
+ .ilim = 1,
+ .dcv = 0x3,
+ .mini = 0,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "CYPRUS",
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "CZECH",
+ .ilim = 1,
+ .dcv = 0x3,
+ .mini = 0,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "DENMARK",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "ECUADOR",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "EGYPT",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "ELSALVADOR",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "FINLAND",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "FRANCE",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .mini = 0,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "GERMANY",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "GREECE",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "GUAM",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "HONGKONG",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "HUNGARY",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "ICELAND",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "INDIA",
+ .dcv = 0x3,
+ .acim = 0x4,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "INDONESIA",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "IRELAND",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "ISRAEL",
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "ITALY",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "JAPAN",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "JORDAN",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "KAZAKHSTAN",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "KUWAIT",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "LATVIA",
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "LEBANON",
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "LUXEMBOURG",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "MACAO",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ /* Current loop >= 20ma */
+ { .name = "MALAYSIA",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "MALTA",
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "MEXICO",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "MOROCCO",
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "NETHERLANDS",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "NEWZEALAND",
+ .dcv = 0x3,
+ .acim = 0x4,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "NIGERIA",
+ .ilim = 0x1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "NORWAY",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "OMAN",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "PAKISTAN",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "PERU",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "PHILIPPINES",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "POLAND",
+ .rz = 1,
+ .rt = 1,
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "PORTUGAL",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "ROMANIA",
+ .dcv = 3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "RUSSIA",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "SAUDIARABIA",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "SINGAPORE",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "SLOVAKIA",
+ .dcv = 0x3,
+ .acim = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "SLOVENIA",
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "SOUTHAFRICA",
+ .ohs = 1,
+ .rz = 1,
+ .dcv = 0x3,
+ .acim = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "SOUTHKOREA",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "SPAIN",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "SWEDEN",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "SWITZERLAND",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x2,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "SYRIA",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "TAIWAN",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "THAILAND",
+ .mini = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "UAE",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "UK",
+ .ohs2 = 1,
+ .ilim = 1,
+ .dcv = 0x3,
+ .acim = 0x5,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "USA",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+ { .name = "YEMEN",
+ .dcv = 0x3,
+ .battdebounce = 64,
+ .battalarm = 1000,
+ .battthresh = 3,
+ },
+};
+
+#endif /* _FXO_MODES_H */
diff --git a/drivers/dahdi/hpec/hpec.h b/drivers/dahdi/hpec/hpec.h
new file mode 100644
index 0000000..7e90f12
--- /dev/null
+++ b/drivers/dahdi/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/drivers/dahdi/hpec/hpec_user.h b/drivers/dahdi/hpec/hpec_user.h
new file mode 100644
index 0000000..bf006eb
--- /dev/null
+++ b/drivers/dahdi/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/drivers/dahdi/hpec/hpec_zaptel.h b/drivers/dahdi/hpec/hpec_zaptel.h
new file mode 100644
index 0000000..2f90571
--- /dev/null
+++ b/drivers/dahdi/hpec/hpec_zaptel.h
@@ -0,0 +1,146 @@
+/*
+ * 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,9)
+ 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_identify(char *buf, size_t len)
+{
+ zap_copy_string(buf, "HPEC", len);
+}
+
+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 int echo_can_create(struct zt_echocanparams *ecp, struct zt_echocanparam *p,
+ struct echo_can_state **ec)
+{
+ if (ecp->param_count > 0) {
+ printk(KERN_WARNING "HPEC does not support parameters; failing request\n");
+ return -EINVAL;
+ }
+
+ if (down_interruptible(&alloc_lock))
+ return -ENOTTY;
+
+ *ec = hpec_channel_alloc(ecp->tap_length);
+
+ up(&alloc_lock);
+
+ return *ec ? 0 : -ENOTTY;
+}
+
+static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+ return 1;
+}
+
+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/drivers/dahdi/jpah.h b/drivers/dahdi/jpah.h
new file mode 100644
index 0000000..fb661ed
--- /dev/null
+++ b/drivers/dahdi/jpah.h
@@ -0,0 +1,104 @@
+/*
+ * ECHO_CAN_JP1
+ *
+ * by Jason Parker
+ *
+ * Based upon mg2ec.h - sort of.
+ * This "echo can" will completely hose your audio.
+ * Don't use it unless you're absolutely sure you know what you're doing.
+ *
+ * Copyright (C) 2007, Digium, Inc.
+ *
+ * This program is free software and may be used and
+ * distributed according to the terms of the GNU
+ * General Public License, incorporated herein by
+ * reference.
+ *
+ */
+
+#ifndef _JP_ECHO_H
+#define _JP_ECHO_H
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#define MALLOC(a) kmalloc((a), GFP_KERNEL)
+#define FREE(a) kfree(a)
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#define MALLOC(a) malloc(a)
+#define FREE(a) free(a)
+#endif
+
+/* Echo canceller definition */
+struct echo_can_state {
+ /* an arbitrary ID for this echo can - this really should be settable from the calling channel... */
+ int id;
+
+ /* absolute time - aka. sample number index - essentially the number of samples since this can was init'ed */
+ int i_d;
+};
+
+static void echo_can_init(void)
+{
+ printk("Zaptel Audio Hoser: JP1\n");
+}
+
+static void echo_can_identify(char *buf, size_t len)
+{
+ zap_copy_string(buf, "JP1", len);
+}
+
+static void echo_can_shutdown(void)
+{
+}
+
+static inline void init_cc(struct echo_can_state *ec)
+{
+ void *ptr = ec;
+ unsigned long tmp;
+ /* Double-word align past end of state */
+ ptr += sizeof(struct echo_can_state);
+ tmp = (unsigned long)ptr;
+ tmp += 3;
+ tmp &= ~3L;
+ ptr = (void *)tmp;
+}
+
+static inline void echo_can_free(struct echo_can_state *ec)
+{
+ FREE(ec);
+}
+
+static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig)
+{
+ static int blah = 0;
+
+ if (blah < 2) {
+ blah++;
+ return 0;
+ } else {
+ blah = (blah + 1) % 3;
+ return isig;
+ }
+}
+
+static inline struct echo_can_state *echo_can_create(int len, int adaption_mode)
+{
+ struct echo_can_state *ec;
+ ec = (struct echo_can_state *)MALLOC(sizeof(struct echo_can_state) + 4); /* align */
+ if (ec) {
+ memset(ec, 0, sizeof(struct echo_can_state) + 4); /* align */
+ init_cc(ec);
+ }
+ return ec;
+}
+
+static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+ return 0;
+}
+#endif
diff --git a/drivers/dahdi/kb1ec.h b/drivers/dahdi/kb1ec.h
new file mode 100644
index 0000000..cfafdf6
--- /dev/null
+++ b/drivers/dahdi/kb1ec.h
@@ -0,0 +1,597 @@
+/*
+ * ECHO_CAN_KB1
+ *
+ * by Kris Boutilier
+ *
+ * Based upon mech2.h
+ *
+ * Copyright (C) 2002, Digium, Inc.
+ *
+ * This program is free software and may be used and
+ * distributed according to the terms of the GNU
+ * General Public License, incorporated herein by
+ * reference.
+ *
+ * Additional background on the techniques used in this code can be found in:
+ *
+ * Messerschmitt, David; Hedberg, David; Cole, Christopher; Haoui, Amine;
+ * Winship, Peter; "Digital Voice Echo Canceller with a TMS32020,"
+ * in Digital Signal Processing Applications with the TMS320 Family,
+ * pp. 415-437, Texas Instruments, Inc., 1986.
+ *
+ * A pdf of which is available by searching on the document title at http://www.ti.com/
+ *
+ */
+
+#ifndef _MARK2_ECHO_H
+#define _MARK2_ECHO_H
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+
+#define MALLOC(a) kmalloc((a), GFP_KERNEL)
+#define FREE(a) kfree(a)
+
+/* Uncomment to provide summary statistics for overall echo can performance every 4000 samples */
+/* #define MEC2_STATS 4000 */
+
+/* Uncomment to generate per-sample statistics - this will severely degrade system performance and audio quality */
+/* #define MEC2_STATS_DETAILED */
+
+/* Get optimized routines for math */
+#include "arith.h"
+
+/* Bring in definitions for the various constants and thresholds */
+#include "kb1ec_const.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+/* Generic circular buffer definition */
+typedef struct {
+ /* Pointer to the relative 'start' of the buffer */
+ int idx_d;
+ /* The absolute size of the buffer */
+ int size_d;
+ /* The actual sample - twice as large as we need, however we do store values at idx_d and idx_d+size_d */
+ short *buf_d;
+} echo_can_cb_s;
+
+/* Echo canceller definition */
+struct echo_can_state {
+ /* an arbitrary ID for this echo can - this really should be settable from the calling channel... */
+ int id;
+
+ /* absolute time - aka. sample number index - essentially the number of samples since this can was init'ed */
+ int i_d;
+
+ /* Pre-computed constants */
+ /* ---------------------- */
+ /* Number of filter coefficents */
+ int N_d;
+ /* Rate of adaptation of filter */
+ int beta2_i;
+
+ /* Accumulators for power computations */
+ /* ----------------------------------- */
+ /* reference signal power estimate - aka. Average absolute value of y(k) */
+ int Ly_i;
+ /* ... */
+ int Lu_i;
+
+ /* Accumulators for signal detectors */
+ /* --------------------------------- */
+ /* Power estimate of the recent past of the near-end hybrid signal - aka. Short-time average of: 2 x |s(i)| */
+ int s_tilde_i;
+ /* Power estimate of the recent past of the far-end receive signal - aka. Short-time average of: |y(i)| */
+ int y_tilde_i;
+
+ /* Near end speech detection counter - stores Hangover counter time remaining, in samples */
+ int HCNTR_d;
+
+ /* Circular buffers and coefficients */
+ /* --------------------------------- */
+ /* ... */
+ int *a_i;
+ /* ... */
+ short *a_s;
+ /* Reference samples of far-end receive signal */
+ echo_can_cb_s y_s;
+ /* Reference samples of near-end signal */
+ echo_can_cb_s s_s;
+ /* Reference samples of near-end signal minus echo estimate */
+ echo_can_cb_s u_s;
+ /* Reference samples of far-end receive signal used to calculate short-time average */
+ echo_can_cb_s y_tilde_s;
+
+ /* Peak far-end receive signal */
+ /* --------------------------- */
+ /* Highest y_tilde value in the sample buffer */
+ short max_y_tilde;
+ /* Index of the sample containing the max_y_tilde value */
+ int max_y_tilde_pos;
+
+#ifdef MEC2_STATS
+ /* Storage for performance statistics */
+ int cntr_nearend_speech_frames;
+ int cntr_residualcorrected_frames;
+ int cntr_residualcorrected_framesskipped;
+ int cntr_coeff_updates;
+ int cntr_coeff_missedupdates;
+
+ int avg_Lu_i_toolow;
+ int avg_Lu_i_ok;
+#endif
+ unsigned int aggressive:1;
+};
+
+static void echo_can_init(void)
+{
+ printk("Zaptel Echo Canceller: KB1\n");
+}
+
+static void echo_can_identify(char *buf, size_t len)
+{
+ zap_copy_string(buf, "KB1", len);
+}
+
+static void echo_can_shutdown(void)
+{
+}
+
+static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where)
+{
+ cb->buf_d = (short *)where;
+ cb->idx_d = 0;
+ cb->size_d = len;
+}
+
+static inline void add_cc_s(echo_can_cb_s *cb, short newval)
+{
+ /* Can't use modulus because N+M isn't a power of two (generally) */
+ cb->idx_d--;
+ if (cb->idx_d < (int)0)
+ /* Whoops - the pointer to the 'start' wrapped around so reset it to the top of the buffer */
+ cb->idx_d += cb->size_d;
+
+ /* Load two copies into memory */
+ cb->buf_d[cb->idx_d] = newval;
+ cb->buf_d[cb->idx_d + cb->size_d] = newval;
+}
+
+static inline short get_cc_s(echo_can_cb_s *cb, int pos)
+{
+ /* Load two copies into memory */
+ return cb->buf_d[cb->idx_d + pos];
+}
+
+static inline void init_cc(struct echo_can_state *ec, int N, int maxy, int maxu)
+{
+
+ void *ptr = ec;
+ unsigned long tmp;
+ /* Double-word align past end of state */
+ ptr += sizeof(struct echo_can_state);
+ tmp = (unsigned long)ptr;
+ tmp += 3;
+ tmp &= ~3L;
+ ptr = (void *)tmp;
+
+ /* Reset parameters */
+ ec->N_d = N;
+ ec->beta2_i = DEFAULT_BETA1_I;
+
+ /* Allocate coefficient memory */
+ ec->a_i = ptr;
+ ptr += (sizeof(int) * ec->N_d);
+ ec->a_s = ptr;
+ ptr += (sizeof(short) * ec->N_d);
+
+ /* Reset Y circular buffer (short version) */
+ init_cb_s(&ec->y_s, maxy, ptr);
+ ptr += (sizeof(short) * (maxy) * 2);
+
+ /* Reset Sigma circular buffer (short version for FIR filter) */
+ init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr);
+ ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2);
+
+ init_cb_s(&ec->u_s, maxu, ptr);
+ ptr += (sizeof(short) * maxu * 2);
+
+ /* Allocate a buffer for the reference signal power computation */
+ init_cb_s(&ec->y_tilde_s, ec->N_d, ptr);
+
+ /* Reset the absolute time index */
+ ec->i_d = (int)0;
+
+ /* Reset the power computations (for y and u) */
+ ec->Ly_i = DEFAULT_CUTOFF_I;
+ ec->Lu_i = DEFAULT_CUTOFF_I;
+
+#ifdef MEC2_STATS
+ /* set the identity */
+ ec->id = (int)&ptr;
+
+ /* Reset performance stats */
+ ec->cntr_nearend_speech_frames = (int)0;
+ ec->cntr_residualcorrected_frames = (int)0;
+ ec->cntr_residualcorrected_framesskipped = (int)0;
+ ec->cntr_coeff_updates = (int)0;
+ ec->cntr_coeff_missedupdates = (int)0;
+
+ ec->avg_Lu_i_toolow = (int)0;
+ ec->avg_Lu_i_ok = (int)0;
+#endif
+
+ /* Reset the near-end speech detector */
+ ec->s_tilde_i = (int)0;
+ ec->y_tilde_i = (int)0;
+ ec->HCNTR_d = (int)0;
+
+}
+
+static inline void echo_can_free(struct echo_can_state *ec)
+{
+ FREE(ec);
+}
+
+static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig)
+{
+
+ /* Declare local variables that are used more than once */
+ /* ... */
+ int k;
+ /* ... */
+ int rs;
+ /* ... */
+ short u;
+ /* ... */
+ int Py_i;
+ /* ... */
+ int two_beta_i;
+
+ /* flow A on pg. 428 */
+ /* eq. (16): high-pass filter the input to generate the next value;
+ * push the current value into the circular buffer
+ *
+ * sdc_im1_d = sdc_d;
+ * sdc_d = sig;
+ * s_i_d = sdc_d;
+ * s_d = s_i_d;
+ * s_i_d = (float)(1.0 - gamma_d) * s_i_d
+ * + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d);
+ */
+
+ /* Update the Far-end receive signal circular buffers and accumulators */
+ /* ------------------------------------------------------------------- */
+ /* Delete the oldest sample from the power estimate accumulator */
+ ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I;
+ /* Add the new sample to the power estimate accumulator */
+ ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_ST_I;
+ /* Push a copy of the new sample into its circular buffer */
+ add_cc_s(&ec->y_s, iref);
+
+
+ /* eq. (2): compute r in fixed-point */
+ rs = CONVOLVE2(ec->a_s,
+ ec->y_s.buf_d + ec->y_s.idx_d,
+ ec->N_d);
+ rs >>= 15;
+
+ /* eq. (3): compute the output value (see figure 3) and the error
+ * note: the error is the same as the output signal when near-end
+ * speech is not present
+ */
+ u = isig - rs;
+
+ /* Push a copy of the output value sample into its circular buffer */
+ add_cc_s(&ec->u_s, u);
+
+
+ /* Update the Near-end hybrid signal circular buffers and accumulators */
+ /* ------------------------------------------------------------------- */
+ /* Delete the oldest sample from the power estimate accumulator */
+ ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 ));
+ /* Add the new sample to the power estimate accumulator */
+ ec->s_tilde_i += abs(isig);
+ /* Push a copy of the new sample into it's circular buffer */
+ add_cc_s(&ec->s_s, isig);
+
+
+ /* Push a copy of the current short-time average of the far-end receive signal into it's circular buffer */
+ add_cc_s(&ec->y_tilde_s, ec->y_tilde_i);
+
+ /* flow B on pg. 428 */
+
+ /* If the hangover timer isn't running then compute the new convergence factor, otherwise set Py_i to 32768 */
+ if (!ec->HCNTR_d) {
+ Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
+ Py_i >>= 15;
+ } else {
+ Py_i = (1 << 15);
+ }
+
+#if 0
+ /* Vary rate of adaptation depending on position in the file
+ * Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech
+ * has begun of the file to allow the echo cancellor to estimate the
+ * channel accurately
+ * Still needs conversion!
+ */
+
+ if (ec->start_speech_d != 0 ){
+ if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){
+ ec->beta2_d = max_cc_float(MIN_BETA, DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) - DEFAULT_T0 - ec->start_speech_d)));
+ }
+ } else {
+ ec->beta2_d = DEFAULT_BETA1;
+ }
+#endif
+
+ /* Fixed point, inverted */
+ ec->beta2_i = DEFAULT_BETA1_I;
+
+ /* Fixed point version, inverted */
+ two_beta_i = (ec->beta2_i * Py_i) >> 15;
+ if (!two_beta_i)
+ two_beta_i++;
+
+ /* Update the Suppressed signal power estimate accumulator */
+ /* ------------------------------------------------------- */
+ /* Delete the oldest sample from the power estimate accumulator */
+ ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ;
+ /* Add the new sample to the power estimate accumulator */
+ ec->Lu_i += abs(u);
+
+ /* Update the Far-end reference signal power estimate accumulator */
+ /* -------------------------------------------------------------- */
+ /* eq. (10): update power estimate of the reference */
+ /* Delete the oldest sample from the power estimate accumulator */
+ ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ;
+ /* Add the new sample to the power estimate accumulator */
+ ec->Ly_i += abs(iref);
+
+ if (ec->Ly_i < DEFAULT_CUTOFF_I)
+ ec->Ly_i = DEFAULT_CUTOFF_I;
+
+
+ /* Update the Peak far-end receive signal detected */
+ /* ----------------------------------------------- */
+ if (ec->y_tilde_i > ec->max_y_tilde) {
+ /* New highest y_tilde with full life */
+ ec->max_y_tilde = ec->y_tilde_i;
+ ec->max_y_tilde_pos = ec->N_d - 1;
+ } else if (--ec->max_y_tilde_pos < 0) {
+ /* Time to find new max y tilde... */
+ ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos);
+ }
+
+ /* Determine if near end speech was detected in this sample */
+ /* -------------------------------------------------------- */
+ if (((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde)
+ && (ec->max_y_tilde > 0)) {
+ /* Then start the Hangover counter */
+ ec->HCNTR_d = DEFAULT_HANGT;
+#ifdef MEC2_STATS_DETAILED
+ printk(KERN_INFO "Reset near end speech timer with: s_tilde_i %d, stmnt %d, max_y_tilde %d\n", ec->s_tilde_i, (ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)), ec->max_y_tilde);
+#endif
+#ifdef MEC2_STATS
+ ++ec->cntr_nearend_speech_frames;
+#endif
+ } else if (ec->HCNTR_d > (int)0) {
+ /* otherwise, if it's still non-zero, decrement the Hangover counter by one sample */
+#ifdef MEC2_STATS
+ ++ec->cntr_nearend_speech_frames;
+#endif
+ ec->HCNTR_d--;
+ }
+
+ /* Update coefficients if no near-end speech in this sample (ie. HCNTR_d = 0)
+ * and we have enough signal to bother trying to update.
+ * --------------------------------------------------------------------------
+ */
+ if (!ec->HCNTR_d && /* no near-end speech present */
+ !(ec->i_d % DEFAULT_M)) { /* we only update on every DEFAULM_M'th sample from the stream */
+ if (ec->Lu_i > MIN_UPDATE_THRESH_I) { /* there is sufficient energy above the noise floor to contain meaningful data */
+ /* so loop over all the filter coefficients */
+#ifdef MEC2_STATS_DETAILED
+ printk( KERN_INFO "updating coefficients with: ec->Lu_i %9d\n", ec->Lu_i);
+#endif
+#ifdef MEC2_STATS
+ ec->avg_Lu_i_ok = ec->avg_Lu_i_ok + ec->Lu_i;
+ ++ec->cntr_coeff_updates;
+#endif
+ for (k=0; k < ec->N_d; k++) {
+ /* eq. (7): compute an expectation over M_d samples */
+ int grad2;
+ grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d,
+ ec->y_s.buf_d + ec->y_s.idx_d + k,
+ DEFAULT_M);
+ /* eq. (7): update the coefficient */
+ ec->a_i[k] += grad2 / two_beta_i;
+ ec->a_s[k] = ec->a_i[k] >> 16;
+ }
+ } else {
+#ifdef MEC2_STATS_DETAILED
+ printk( KERN_INFO "insufficient signal to update coefficients ec->Lu_i %5d < %5d\n", ec->Lu_i, MIN_UPDATE_THRESH_I);
+#endif
+#ifdef MEC2_STATS
+ ec->avg_Lu_i_toolow = ec->avg_Lu_i_toolow + ec->Lu_i;
+ ++ec->cntr_coeff_missedupdates;
+#endif
+ }
+ }
+
+ /* paragraph below eq. (15): if no near-end speech in the sample and
+ * the reference signal power estimate > cutoff threshold
+ * then perform residual error suppression
+ */
+#ifdef MEC2_STATS_DETAILED
+ if (ec->HCNTR_d == 0)
+ printk( KERN_INFO "possibily correcting frame with ec->Ly_i %9d ec->Lu_i %9d and expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+
+#ifndef NO_ECHO_SUPPRESSOR
+ if (ec->aggressive) {
+ if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) {
+ for (k=0; k < 2; k++) {
+ u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
+ }
+#ifdef MEC2_STATS_DETAILED
+ printk( KERN_INFO "aggresively correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+#ifdef MEC2_STATS
+ ++ec->cntr_residualcorrected_frames;
+#endif
+ }
+ } else {
+ if (ec->HCNTR_d == 0) {
+ if ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I) {
+ for (k=0; k < 1; k++) {
+ u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
+ }
+#ifdef MEC2_STATS_DETAILED
+ printk( KERN_INFO "correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+#ifdef MEC2_STATS
+ ++ec->cntr_residualcorrected_frames;
+#endif
+ }
+#ifdef MEC2_STATS
+ else {
+ ++ec->cntr_residualcorrected_framesskipped;
+ }
+#endif
+ }
+ }
+#endif
+
+#if 0
+ /* This will generate a non-linear supression factor, once converted */
+ if ((ec->HCNTR_d == 0) &&
+ ((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) &&
+ (ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) {
+ suppr_factor = (10 / (float)(SUPPR_FLOOR - SUPPR_CEIL)) * log(ec->Lu_d/ec->Ly_d)
+ - SUPPR_CEIL / (float)(SUPPR_FLOOR - SUPPR_CEIL);
+ u_suppr = pow(10.0, (suppr_factor) * RES_SUPR_FACTOR / 10.0) * u_suppr;
+ }
+#endif
+
+#ifdef MEC2_STATS
+ /* Periodically dump performance stats */
+ if ((ec->i_d % MEC2_STATS) == 0) {
+ /* make sure to avoid div0's! */
+ if (ec->cntr_coeff_missedupdates > 0)
+ ec->avg_Lu_i_toolow = (int)(ec->avg_Lu_i_toolow / ec->cntr_coeff_missedupdates);
+ else
+ ec->avg_Lu_i_toolow = -1;
+
+ if (ec->cntr_coeff_updates > 0)
+ ec->avg_Lu_i_ok = (ec->avg_Lu_i_ok / ec->cntr_coeff_updates);
+ else
+ ec->avg_Lu_i_ok = -1;
+
+ printk( KERN_INFO "%d: Near end speech: %5d Residuals corrected/skipped: %5d/%5d Coefficients updated ok/low sig: %3d/%3d Lu_i avg ok/low sig %6d/%5d\n",
+ ec->id,
+ ec->cntr_nearend_speech_frames,
+ ec->cntr_residualcorrected_frames, ec->cntr_residualcorrected_framesskipped,
+ ec->cntr_coeff_updates, ec->cntr_coeff_missedupdates,
+ ec->avg_Lu_i_ok, ec->avg_Lu_i_toolow);
+
+ ec->cntr_nearend_speech_frames = 0;
+ ec->cntr_residualcorrected_frames = 0;
+ ec->cntr_residualcorrected_framesskipped = 0;
+ ec->cntr_coeff_updates = 0;
+ ec->cntr_coeff_missedupdates = 0;
+ ec->avg_Lu_i_ok = 0;
+ ec->avg_Lu_i_toolow = 0;
+ }
+#endif
+
+ /* Increment the sample index and return the corrected sample */
+ ec->i_d++;
+ return u;
+}
+
+static int echo_can_create(struct zt_echocanparams *ecp, struct zt_echocanparam *p,
+ struct echo_can_state **ec)
+{
+ int maxy;
+ int maxu;
+ size_t size;
+ unsigned int x;
+ char *c;
+
+ maxy = ecp->tap_length + DEFAULT_M;
+ maxu = DEFAULT_M;
+ if (maxy < (1 << DEFAULT_ALPHA_YT_I))
+ maxy = (1 << DEFAULT_ALPHA_YT_I);
+ if (maxy < (1 << DEFAULT_SIGMA_LY_I))
+ maxy = (1 << DEFAULT_SIGMA_LY_I);
+ if (maxu < (1 << DEFAULT_SIGMA_LU_I))
+ maxu = (1 << DEFAULT_SIGMA_LU_I);
+
+ size = sizeof(*ec) +
+ 4 + /* align */
+ sizeof(int) * ecp->tap_length + /* a_i */
+ sizeof(short) * ecp->tap_length + /* a_s */
+ 2 * sizeof(short) * (maxy) + /* y_s */
+ 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
+ 2 * sizeof(short) * (maxu) + /* u_s */
+ 2 * sizeof(short) * ecp->tap_length; /* y_tilde_s */
+
+ if (!(*ec = MALLOC(size)))
+ return -ENOMEM;
+
+ memset(*ec, 0, size);
+
+#ifdef AGGRESSIVE_SUPPRESSOR
+ (*ec)->aggressive = 1;
+#endif
+
+ for (x = 0; x < ecp->param_count; x++) {
+ for (c = p[x].name; *c; c++)
+ *c = tolower(*c);
+ if (!strcmp(p[x].name, "aggressive")) {
+ (*ec)->aggressive = p[x].value ? 1 : 0;
+ } else {
+ printk(KERN_WARNING "Unknown parameter supplied to KB1 echo canceler: '%s'\n", p[x].name);
+ kfree(*ec);
+
+ return -EINVAL;
+ }
+ }
+
+ init_cc(*ec, ecp->tap_length, maxy, maxu);
+
+ return 0;
+}
+
+static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+ /* Set the hangover counter to the length of the can to
+ * avoid adjustments occuring immediately after initial forced training
+ */
+ ec->HCNTR_d = ec->N_d << 1;
+
+ if (pos >= ec->N_d)
+ return 1;
+
+ ec->a_i[pos] = val << 17;
+ ec->a_s[pos] = val << 1;
+
+ if (++pos >= ec->N_d)
+ return 1;
+
+ return 0;
+}
+
+#endif
diff --git a/drivers/dahdi/kb1ec_const.h b/drivers/dahdi/kb1ec_const.h
new file mode 100644
index 0000000..0849b14
--- /dev/null
+++ b/drivers/dahdi/kb1ec_const.h
@@ -0,0 +1,72 @@
+/*
+ Important constants for tuning kb1 echo can
+ */
+#ifndef _MEC2_CONST_H
+#define _MEC2_CONST_H
+
+
+/* Convergence (aka. adaptation) speed -- higher means slower */
+#define DEFAULT_BETA1_I 2048
+
+/* Constants for various power computations */
+#define DEFAULT_SIGMA_LY_I 7
+#define DEFAULT_SIGMA_LU_I 7
+#define DEFAULT_ALPHA_ST_I 5 /* near-end speech detection sensitivity factor */
+#define DEFAULT_ALPHA_YT_I 5
+
+#define DEFAULT_CUTOFF_I 128
+
+/* Define the near-end speech hangover counter: if near-end speech
+ * is declared, hcntr is set equal to hangt (see pg. 432)
+ */
+#define DEFAULT_HANGT 600 /* in samples, so 600 samples = 75ms */
+
+/* define the residual error suppression threshold */
+#define DEFAULT_SUPPR_I 16 /* 16 = -24db */
+
+/* This is the minimum reference signal power estimate level
+ * that will result in filter adaptation.
+ * If this is too low then background noise will cause the filter
+ * coefficients to constantly be updated.
+ */
+#define MIN_UPDATE_THRESH_I 4096
+
+/* The number of samples used to update coefficients using the
+ * the block update method (M). It should be related back to the
+ * length of the echo can.
+ * ie. it only updates coefficients when (sample number MOD default_m) = 0
+ *
+ * Getting this wrong may cause an oops. Consider yourself warned!
+ */
+#define DEFAULT_M 16 /* every 16th sample */
+
+/* If AGGRESSIVE supression is enabled, then we start cancelling residual
+ * echos again even while there is potentially the very end of a near-side
+ * signal present.
+ * This defines how many samples of DEFAULT_HANGT can remain before we
+ * kick back in
+ */
+#define AGGRESSIVE_HCNTR 160 /* in samples, so 160 samples = 20ms */
+
+
+/***************************************************************/
+/* The following knobs are not implemented in the current code */
+
+/* we need a dynamic level of suppression varying with the ratio of the
+ power of the echo to the power of the reference signal this is
+ done so that we have a smoother background.
+ we have a higher suppression when the power ratio is closer to
+ suppr_ceil and reduces logarithmically as we approach suppr_floor.
+ */
+#define SUPPR_FLOOR -64
+#define SUPPR_CEIL -24
+
+/* in a second departure, we calculate the residual error suppression
+ * as a percentage of the reference signal energy level. The threshold
+ * is defined in terms of dB below the reference signal.
+ */
+#define RES_SUPR_FACTOR -20
+
+
+#endif /* _MEC2_CONST_H */
+
diff --git a/drivers/dahdi/makefw.c b/drivers/dahdi/makefw.c
new file mode 100644
index 0000000..6a5b0d9
--- /dev/null
+++ b/drivers/dahdi/makefw.c
@@ -0,0 +1,88 @@
+/* Xilinx firmware convertor program.
+ *
+ *
+ * Written by Jim Dixon <jim@lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001 Linux Support Services, Inc.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under thet erms 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.
+ *
+ * Primary Author: Mark Spencer <markster@digium.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SWATH 12
+
+int main(int argc, char *argv[])
+{
+FILE *fp;
+int i,j,nbytes;
+unsigned char c;
+char buf[300];
+
+ if (argc < 3)
+ {
+ puts("Usage... makefw filename.rbt array_name");
+ exit(1);
+ }
+
+ fp = fopen(argv[1],"r");
+ if (!fp)
+ {
+ perror("bit file open");
+ exit(1);
+ }
+ nbytes = 0;
+ printf("static unsigned char %s[] = {\n",argv[2]);
+ i = 0;
+ while(fgets(buf,sizeof(buf) - 1,fp))
+ {
+ if (!buf[0]) continue;
+ if (buf[strlen(buf) - 1] < ' ') buf[strlen(buf) - 1] = 0;
+ if (!buf[0]) continue;
+ if (buf[strlen(buf) - 1] < ' ') buf[strlen(buf) - 1] = 0;
+ if (!buf[0]) continue;
+ if (strlen(buf) < 32) continue;
+ if ((buf[0] != '0') && (buf[0] != '1')) continue;
+ c = 0;
+ for(j = 0; buf[j]; j++)
+ {
+ if (buf[j] > '0') c |= 1 << (j & 7);
+ if ((j & 7) == 7)
+ {
+ nbytes++;
+ if (i) printf(",");
+ printf("0x%02x",c);
+ if (i++ == SWATH) {
+ printf(",\n");
+ i = 0;
+ }
+ c = 0;
+ }
+ }
+ }
+ printf("\n};\n\n");
+ fprintf(stderr,"Loaded %d bytes from file\n",nbytes);
+ fclose(fp);
+ exit(0);
+}
+
diff --git a/drivers/dahdi/mg2ec.h b/drivers/dahdi/mg2ec.h
new file mode 100644
index 0000000..1d4189b
--- /dev/null
+++ b/drivers/dahdi/mg2ec.h
@@ -0,0 +1,725 @@
+/*
+ * ECHO_CAN_MG2
+ *
+ * by Michael Gernoth
+ *
+ * Based upon kb1ec.h and mec2.h
+ *
+ * Copyright (C) 2002, Digium, Inc.
+ *
+ * This program is free software and may be used and
+ * distributed according to the terms of the GNU
+ * General Public License, incorporated herein by
+ * reference.
+ *
+ * Additional background on the techniques used in this code can be found in:
+ *
+ * Messerschmitt, David; Hedberg, David; Cole, Christopher; Haoui, Amine;
+ * Winship, Peter; "Digital Voice Echo Canceller with a TMS32020,"
+ * in Digital Signal Processing Applications with the TMS320 Family,
+ * pp. 415-437, Texas Instruments, Inc., 1986.
+ *
+ * A pdf of which is available by searching on the document title at http://www.ti.com/
+ *
+ */
+
+#ifndef _MG2_ECHO_H
+#define _MG2_ECHO_H
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+
+#define MALLOC(a) kmalloc((a), GFP_KERNEL)
+#define FREE(a) kfree(a)
+
+#define ABS(a) abs(a!=-32768?a:-32767)
+
+#define RESTORE_COEFFS {\
+ int x;\
+ memcpy(ec->a_i, ec->c_i, ec->N_d*sizeof(int));\
+ for (x=0;x<ec->N_d;x++) {\
+ ec->a_s[x] = ec->a_i[x] >> 16;\
+ }\
+ ec->backup = BACKUP;\
+ }
+
+/* Uncomment to provide summary statistics for overall echo can performance every 4000 samples */
+/* #define MEC2_STATS 4000 */
+
+/* Uncomment to generate per-sample statistics - this will severely degrade system performance and audio quality */
+/* #define MEC2_STATS_DETAILED */
+
+/* Uncomment to generate per-call DC bias offset messages */
+/* #define MEC2_DCBIAS_MESSAGE */
+
+/* Get optimized routines for math */
+#include "arith.h"
+
+/* Bring in definitions for the various constants and thresholds */
+#include "mg2ec_const.h"
+
+#define DC_NORMALIZE
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+/* Generic circular buffer definition */
+typedef struct {
+ /* Pointer to the relative 'start' of the buffer */
+ int idx_d;
+ /* The absolute size of the buffer */
+ int size_d;
+ /* The actual sample - twice as large as we need, however we do store values at idx_d and idx_d+size_d */
+ short *buf_d;
+} echo_can_cb_s;
+
+/* Echo canceller definition */
+struct echo_can_state {
+ /* an arbitrary ID for this echo can - this really should be settable from the calling channel... */
+ int id;
+
+ /* absolute time - aka. sample number index - essentially the number of samples since this can was init'ed */
+ int i_d;
+
+ /* Pre-computed constants */
+ /* ---------------------- */
+ /* Number of filter coefficents */
+ int N_d;
+ /* Rate of adaptation of filter */
+ int beta2_i;
+
+ /* Accumulators for power computations */
+ /* ----------------------------------- */
+ /* reference signal power estimate - aka. Average absolute value of y(k) */
+ int Ly_i;
+ /* ... */
+ int Lu_i;
+
+ /* Accumulators for signal detectors */
+ /* --------------------------------- */
+ /* Power estimate of the recent past of the near-end hybrid signal - aka. Short-time average of: 2 x |s(i)| */
+ int s_tilde_i;
+ /* Power estimate of the recent past of the far-end receive signal - aka. Short-time average of: |y(i)| */
+ int y_tilde_i;
+
+ /* Near end speech detection counter - stores Hangover counter time remaining, in samples */
+ int HCNTR_d;
+
+ /* Circular buffers and coefficients */
+ /* --------------------------------- */
+ /* ... */
+ int *a_i;
+ /* ... */
+ short *a_s;
+ /* Backups */
+ int *b_i;
+ int *c_i;
+ /* Reference samples of far-end receive signal */
+ echo_can_cb_s y_s;
+ /* Reference samples of near-end signal */
+ echo_can_cb_s s_s;
+ /* Reference samples of near-end signal minus echo estimate */
+ echo_can_cb_s u_s;
+ /* Reference samples of far-end receive signal used to calculate short-time average */
+ echo_can_cb_s y_tilde_s;
+
+ /* Peak far-end receive signal */
+ /* --------------------------- */
+ /* Highest y_tilde value in the sample buffer */
+ short max_y_tilde;
+ /* Index of the sample containing the max_y_tilde value */
+ int max_y_tilde_pos;
+
+#ifdef MEC2_STATS
+ /* Storage for performance statistics */
+ int cntr_nearend_speech_frames;
+ int cntr_residualcorrected_frames;
+ int cntr_residualcorrected_framesskipped;
+ int cntr_coeff_updates;
+ int cntr_coeff_missedupdates;
+
+ int avg_Lu_i_toolow;
+ int avg_Lu_i_ok;
+#endif
+ unsigned int aggressive:1;
+ short lastsig;
+ int lastcount;
+ int backup;
+#ifdef DC_NORMALIZE
+ int dc_estimate;
+#endif
+
+};
+
+static void echo_can_init(void)
+{
+ printk("Zaptel Echo Canceller: MG2\n");
+}
+
+static void echo_can_identify(char *buf, size_t len)
+{
+ zap_copy_string(buf, "MG2", len);
+}
+
+static void echo_can_shutdown(void)
+{
+}
+
+static inline void init_cb_s(echo_can_cb_s *cb, int len, void *where)
+{
+ cb->buf_d = (short *)where;
+ cb->idx_d = 0;
+ cb->size_d = len;
+}
+
+static inline void add_cc_s(echo_can_cb_s *cb, short newval)
+{
+ /* Can't use modulus because N+M isn't a power of two (generally) */
+ cb->idx_d--;
+ if (cb->idx_d < (int)0)
+ /* Whoops - the pointer to the 'start' wrapped around so reset it to the top of the buffer */
+ cb->idx_d += cb->size_d;
+
+ /* Load two copies into memory */
+ cb->buf_d[cb->idx_d] = newval;
+ cb->buf_d[cb->idx_d + cb->size_d] = newval;
+}
+
+static inline short get_cc_s(echo_can_cb_s *cb, int pos)
+{
+ /* Load two copies into memory */
+ return cb->buf_d[cb->idx_d + pos];
+}
+
+static inline void init_cc(struct echo_can_state *ec, int N, int maxy, int maxu)
+{
+
+ void *ptr = ec;
+ unsigned long tmp;
+ /* Double-word align past end of state */
+ ptr += sizeof(struct echo_can_state);
+ tmp = (unsigned long)ptr;
+ tmp += 3;
+ tmp &= ~3L;
+ ptr = (void *)tmp;
+
+ /* Reset parameters */
+ ec->N_d = N;
+ ec->beta2_i = DEFAULT_BETA1_I;
+
+ /* Allocate coefficient memory */
+ ec->a_i = ptr;
+ ptr += (sizeof(int) * ec->N_d);
+ ec->a_s = ptr;
+ ptr += (sizeof(short) * ec->N_d);
+
+ /* Allocate backup memory */
+ ec->b_i = ptr;
+ ptr += (sizeof(int) * ec->N_d);
+ ec->c_i = ptr;
+ ptr += (sizeof(int) * ec->N_d);
+
+ /* Reset Y circular buffer (short version) */
+ init_cb_s(&ec->y_s, maxy, ptr);
+ ptr += (sizeof(short) * (maxy) * 2);
+
+ /* Reset Sigma circular buffer (short version for FIR filter) */
+ init_cb_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I), ptr);
+ ptr += (sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) * 2);
+
+ init_cb_s(&ec->u_s, maxu, ptr);
+ ptr += (sizeof(short) * maxu * 2);
+
+ /* Allocate a buffer for the reference signal power computation */
+ init_cb_s(&ec->y_tilde_s, ec->N_d, ptr);
+
+ /* Reset the absolute time index */
+ ec->i_d = (int)0;
+
+ /* Reset the power computations (for y and u) */
+ ec->Ly_i = DEFAULT_CUTOFF_I;
+ ec->Lu_i = DEFAULT_CUTOFF_I;
+
+#ifdef MEC2_STATS
+ /* set the identity */
+ ec->id = (int)&ptr;
+
+ /* Reset performance stats */
+ ec->cntr_nearend_speech_frames = (int)0;
+ ec->cntr_residualcorrected_frames = (int)0;
+ ec->cntr_residualcorrected_framesskipped = (int)0;
+ ec->cntr_coeff_updates = (int)0;
+ ec->cntr_coeff_missedupdates = (int)0;
+
+ ec->avg_Lu_i_toolow = (int)0;
+ ec->avg_Lu_i_ok = (int)0;
+#endif
+
+ /* Reset the near-end speech detector */
+ ec->s_tilde_i = (int)0;
+ ec->y_tilde_i = (int)0;
+ ec->HCNTR_d = (int)0;
+
+}
+
+static inline void echo_can_free(struct echo_can_state *ec)
+{
+#if defined(DC_NORMALIZE) && defined(MEC2_DCBIAS_MESSAGE)
+ printk("EC: DC bias calculated: %d V\n", ec->dc_estimate >> 15);
+#endif
+ FREE(ec);
+}
+
+#ifdef DC_NORMALIZE
+short inline dc_removal(int *dc_estimate, short samp)
+{
+ *dc_estimate += ((((int)samp << 15) - *dc_estimate) >> 9);
+ return samp - (*dc_estimate >> 15);
+}
+#endif
+
+static inline short echo_can_update(struct echo_can_state *ec, short iref, short isig)
+{
+
+ /* Declare local variables that are used more than once */
+ /* ... */
+ int k;
+ /* ... */
+ int rs;
+ /* ... */
+ short u;
+ /* ... */
+ int Py_i;
+ /* ... */
+ int two_beta_i;
+
+#ifdef DC_NORMALIZE
+ isig = dc_removal(&ec->dc_estimate, isig);
+#endif
+
+ /* flow A on pg. 428 */
+ /* eq. (16): high-pass filter the input to generate the next value;
+ * push the current value into the circular buffer
+ *
+ * sdc_im1_d = sdc_d;
+ * sdc_d = sig;
+ * s_i_d = sdc_d;
+ * s_d = s_i_d;
+ * s_i_d = (float)(1.0 - gamma_d) * s_i_d
+ * + (float)(0.5 * (1.0 - gamma_d)) * (sdc_d - sdc_im1_d);
+ */
+
+ /* Update the Far-end receive signal circular buffers and accumulators */
+ /* ------------------------------------------------------------------- */
+ /* Delete the oldest sample from the power estimate accumulator */
+ ec->y_tilde_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_ALPHA_YT_I) - 1 )) >> DEFAULT_ALPHA_YT_I;
+ /* Add the new sample to the power estimate accumulator */
+ ec->y_tilde_i += abs(iref) >> DEFAULT_ALPHA_ST_I;
+ /* Push a copy of the new sample into its circular buffer */
+ add_cc_s(&ec->y_s, iref);
+
+
+ /* eq. (2): compute r in fixed-point */
+ rs = CONVOLVE2(ec->a_s,
+ ec->y_s.buf_d + ec->y_s.idx_d,
+ ec->N_d);
+ rs >>= 15;
+
+ if (ec->lastsig == isig) {
+ ec->lastcount++;
+ } else {
+ ec->lastcount = 0;
+ ec->lastsig = isig;
+ }
+
+ if (isig == 0) {
+ u = 0;
+ } else if (ec->lastcount > 255) {
+ /* We have seen the same input-signal more than 255 times,
+ * we should pass it through uncancelled, as we are likely on hold */
+ u = isig;
+ } else {
+ if (rs < -32768) {
+ rs = -32768;
+ ec->HCNTR_d = DEFAULT_HANGT;
+ RESTORE_COEFFS;
+ } else if (rs > 32767) {
+ rs = 32767;
+ ec->HCNTR_d = DEFAULT_HANGT;
+ RESTORE_COEFFS;
+ }
+
+ if (ABS(ABS(rs)-ABS(isig)) > MAX_SIGN_ERROR)
+ {
+ rs = 0;
+ RESTORE_COEFFS;
+ }
+
+ /* eq. (3): compute the output value (see figure 3) and the error
+ * note: the error is the same as the output signal when near-end
+ * speech is not present
+ */
+ u = isig - rs;
+
+ if (u / isig < 0)
+ u = isig - (rs >> 1);
+ }
+
+ /* Push a copy of the output value sample into its circular buffer */
+ add_cc_s(&ec->u_s, u);
+
+ if (!ec->backup) {
+ /* Backup coefficients periodically */
+ ec->backup = BACKUP;
+ memcpy(ec->c_i,ec->b_i,ec->N_d*sizeof(int));
+ memcpy(ec->b_i,ec->a_i,ec->N_d*sizeof(int));
+ } else
+ ec->backup--;
+
+
+ /* Update the Near-end hybrid signal circular buffers and accumulators */
+ /* ------------------------------------------------------------------- */
+ /* Delete the oldest sample from the power estimate accumulator */
+ ec->s_tilde_i -= abs(get_cc_s(&ec->s_s, (1 << DEFAULT_ALPHA_ST_I) - 1 ));
+ /* Add the new sample to the power estimate accumulator */
+ ec->s_tilde_i += abs(isig);
+ /* Push a copy of the new sample into it's circular buffer */
+ add_cc_s(&ec->s_s, isig);
+
+
+ /* Push a copy of the current short-time average of the far-end receive signal into it's circular buffer */
+ add_cc_s(&ec->y_tilde_s, ec->y_tilde_i);
+
+ /* flow B on pg. 428 */
+
+ /* If the hangover timer isn't running then compute the new convergence factor, otherwise set Py_i to 32768 */
+ if (!ec->HCNTR_d) {
+ Py_i = (ec->Ly_i >> DEFAULT_SIGMA_LY_I) * (ec->Ly_i >> DEFAULT_SIGMA_LY_I);
+ Py_i >>= 15;
+ } else {
+ Py_i = (1 << 15);
+ }
+
+#if 0
+ /* Vary rate of adaptation depending on position in the file
+ * Do not do this for the first (DEFAULT_UPDATE_TIME) secs after speech
+ * has begun of the file to allow the echo cancellor to estimate the
+ * channel accurately
+ * Still needs conversion!
+ */
+
+ if (ec->start_speech_d != 0 ){
+ if ( ec->i_d > (DEFAULT_T0 + ec->start_speech_d)*(SAMPLE_FREQ) ){
+ ec->beta2_d = max_cc_float(MIN_BETA, DEFAULT_BETA1 * exp((-1/DEFAULT_TAU)*((ec->i_d/(float)SAMPLE_FREQ) - DEFAULT_T0 - ec->start_speech_d)));
+ }
+ } else {
+ ec->beta2_d = DEFAULT_BETA1;
+ }
+#endif
+
+ /* Fixed point, inverted */
+ ec->beta2_i = DEFAULT_BETA1_I;
+
+ /* Fixed point version, inverted */
+ two_beta_i = (ec->beta2_i * Py_i) >> 15;
+ if (!two_beta_i)
+ two_beta_i++;
+
+ /* Update the Suppressed signal power estimate accumulator */
+ /* ------------------------------------------------------- */
+ /* Delete the oldest sample from the power estimate accumulator */
+ ec->Lu_i -= abs(get_cc_s(&ec->u_s, (1 << DEFAULT_SIGMA_LU_I) - 1 )) ;
+ /* Add the new sample to the power estimate accumulator */
+ ec->Lu_i += abs(u);
+
+ /* Update the Far-end reference signal power estimate accumulator */
+ /* -------------------------------------------------------------- */
+ /* eq. (10): update power estimate of the reference */
+ /* Delete the oldest sample from the power estimate accumulator */
+ ec->Ly_i -= abs(get_cc_s(&ec->y_s, (1 << DEFAULT_SIGMA_LY_I) - 1)) ;
+ /* Add the new sample to the power estimate accumulator */
+ ec->Ly_i += abs(iref);
+
+ if (ec->Ly_i < DEFAULT_CUTOFF_I)
+ ec->Ly_i = DEFAULT_CUTOFF_I;
+
+
+ /* Update the Peak far-end receive signal detected */
+ /* ----------------------------------------------- */
+ if (ec->y_tilde_i > ec->max_y_tilde) {
+ /* New highest y_tilde with full life */
+ ec->max_y_tilde = ec->y_tilde_i;
+ ec->max_y_tilde_pos = ec->N_d - 1;
+ } else if (--ec->max_y_tilde_pos < 0) {
+ /* Time to find new max y tilde... */
+ ec->max_y_tilde = MAX16(ec->y_tilde_s.buf_d + ec->y_tilde_s.idx_d, ec->N_d, &ec->max_y_tilde_pos);
+ }
+
+ /* Determine if near end speech was detected in this sample */
+ /* -------------------------------------------------------- */
+ if (((ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)) > ec->max_y_tilde)
+ && (ec->max_y_tilde > 0)) {
+ /* Then start the Hangover counter */
+ ec->HCNTR_d = DEFAULT_HANGT;
+ RESTORE_COEFFS;
+#ifdef MEC2_STATS_DETAILED
+ printk(KERN_INFO "Reset near end speech timer with: s_tilde_i %d, stmnt %d, max_y_tilde %d\n", ec->s_tilde_i, (ec->s_tilde_i >> (DEFAULT_ALPHA_ST_I - 1)), ec->max_y_tilde);
+#endif
+#ifdef MEC2_STATS
+ ++ec->cntr_nearend_speech_frames;
+#endif
+ } else if (ec->HCNTR_d > (int)0) {
+ /* otherwise, if it's still non-zero, decrement the Hangover counter by one sample */
+#ifdef MEC2_STATS
+ ++ec->cntr_nearend_speech_frames;
+#endif
+ ec->HCNTR_d--;
+ }
+
+ /* Update coefficients if no near-end speech in this sample (ie. HCNTR_d = 0)
+ * and we have enough signal to bother trying to update.
+ * --------------------------------------------------------------------------
+ */
+ if (!ec->HCNTR_d && /* no near-end speech present */
+ !(ec->i_d % DEFAULT_M)) { /* we only update on every DEFAULM_M'th sample from the stream */
+ if (ec->Lu_i > MIN_UPDATE_THRESH_I) { /* there is sufficient energy above the noise floor to contain meaningful data */
+ /* so loop over all the filter coefficients */
+#ifdef USED_COEFFS
+ int max_coeffs[USED_COEFFS];
+ int *pos;
+
+ if (ec->N_d > USED_COEFFS)
+ memset(max_coeffs, 0, USED_COEFFS*sizeof(int));
+#endif
+#ifdef MEC2_STATS_DETAILED
+ printk(KERN_INFO "updating coefficients with: ec->Lu_i %9d\n", ec->Lu_i);
+#endif
+#ifdef MEC2_STATS
+ ec->avg_Lu_i_ok = ec->avg_Lu_i_ok + ec->Lu_i;
+ ++ec->cntr_coeff_updates;
+#endif
+ for (k=0; k < ec->N_d; k++) {
+ /* eq. (7): compute an expectation over M_d samples */
+ int grad2;
+ grad2 = CONVOLVE2(ec->u_s.buf_d + ec->u_s.idx_d,
+ ec->y_s.buf_d + ec->y_s.idx_d + k,
+ DEFAULT_M);
+ /* eq. (7): update the coefficient */
+ ec->a_i[k] += grad2 / two_beta_i;
+ ec->a_s[k] = ec->a_i[k] >> 16;
+
+#ifdef USED_COEFFS
+ if (ec->N_d > USED_COEFFS) {
+ if (abs(ec->a_i[k]) > max_coeffs[USED_COEFFS-1]) {
+ /* More or less insertion-sort... */
+ pos = max_coeffs;
+ while (*pos > abs(ec->a_i[k]))
+ pos++;
+
+ if (*pos > max_coeffs[USED_COEFFS-1])
+ memmove(pos+1, pos, (USED_COEFFS-(pos-max_coeffs)-1)*sizeof(int));
+
+ *pos = abs(ec->a_i[k]);
+ }
+ }
+#endif
+ }
+
+#ifdef USED_COEFFS
+ /* Filter out irrelevant coefficients */
+ if (ec->N_d > USED_COEFFS)
+ for (k=0; k < ec->N_d; k++)
+ if (abs(ec->a_i[k]) < max_coeffs[USED_COEFFS-1])
+ ec->a_i[k] = ec->a_s[k] = 0;
+#endif
+ } else {
+#ifdef MEC2_STATS_DETAILED
+ printk(KERN_INFO "insufficient signal to update coefficients ec->Lu_i %5d < %5d\n", ec->Lu_i, MIN_UPDATE_THRESH_I);
+#endif
+#ifdef MEC2_STATS
+ ec->avg_Lu_i_toolow = ec->avg_Lu_i_toolow + ec->Lu_i;
+ ++ec->cntr_coeff_missedupdates;
+#endif
+ }
+ }
+
+ /* paragraph below eq. (15): if no near-end speech in the sample and
+ * the reference signal power estimate > cutoff threshold
+ * then perform residual error suppression
+ */
+#ifdef MEC2_STATS_DETAILED
+ if (ec->HCNTR_d == 0)
+ printk(KERN_INFO "possibily correcting frame with ec->Ly_i %9d ec->Lu_i %9d and expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+
+#ifndef NO_ECHO_SUPPRESSOR
+ if (ec->aggressive) {
+ if ((ec->HCNTR_d < AGGRESSIVE_HCNTR) && (ec->Ly_i > (ec->Lu_i << 1))) {
+ for (k=0; k < 2; k++) {
+ u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I)) + 1);
+ }
+#ifdef MEC2_STATS_DETAILED
+ printk(KERN_INFO "aggresively correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+#ifdef MEC2_STATS
+ ++ec->cntr_residualcorrected_frames;
+#endif
+ }
+ } else {
+ if (ec->HCNTR_d == 0) {
+ if ((ec->Ly_i/(ec->Lu_i + 1)) > DEFAULT_SUPPR_I) {
+ for (k=0; k < 1; k++) {
+ u = u * (ec->Lu_i >> DEFAULT_SIGMA_LU_I) / ((ec->Ly_i >> (DEFAULT_SIGMA_LY_I + 2)) + 1);
+ }
+#ifdef MEC2_STATS_DETAILED
+ printk(KERN_INFO "correcting frame with ec->Ly_i %9d ec->Lu_i %9d expression %d\n", ec->Ly_i, ec->Lu_i, (ec->Ly_i/(ec->Lu_i + 1)));
+#endif
+#ifdef MEC2_STATS
+ ++ec->cntr_residualcorrected_frames;
+#endif
+ }
+#ifdef MEC2_STATS
+ else {
+ ++ec->cntr_residualcorrected_framesskipped;
+ }
+#endif
+ }
+ }
+#endif
+
+#if 0
+ /* This will generate a non-linear supression factor, once converted */
+ if ((ec->HCNTR_d == 0) &&
+ ((ec->Lu_d/ec->Ly_d) < DEFAULT_SUPPR) &&
+ (ec->Lu_d/ec->Ly_d > EC_MIN_DB_VALUE)) {
+ suppr_factor = (10 / (float)(SUPPR_FLOOR - SUPPR_CEIL)) * log(ec->Lu_d/ec->Ly_d)
+ - SUPPR_CEIL / (float)(SUPPR_FLOOR - SUPPR_CEIL);
+ u_suppr = pow(10.0, (suppr_factor) * RES_SUPR_FACTOR / 10.0) * u_suppr;
+ }
+#endif
+
+#ifdef MEC2_STATS
+ /* Periodically dump performance stats */
+ if ((ec->i_d % MEC2_STATS) == 0) {
+ /* make sure to avoid div0's! */
+ if (ec->cntr_coeff_missedupdates > 0)
+ ec->avg_Lu_i_toolow = (int)(ec->avg_Lu_i_toolow / ec->cntr_coeff_missedupdates);
+ else
+ ec->avg_Lu_i_toolow = -1;
+
+ if (ec->cntr_coeff_updates > 0)
+ ec->avg_Lu_i_ok = (ec->avg_Lu_i_ok / ec->cntr_coeff_updates);
+ else
+ ec->avg_Lu_i_ok = -1;
+
+ printk(KERN_INFO "%d: Near end speech: %5d Residuals corrected/skipped: %5d/%5d Coefficients updated ok/low sig: %3d/%3d Lu_i avg ok/low sig %6d/%5d\n",
+ ec->id,
+ ec->cntr_nearend_speech_frames,
+ ec->cntr_residualcorrected_frames, ec->cntr_residualcorrected_framesskipped,
+ ec->cntr_coeff_updates, ec->cntr_coeff_missedupdates,
+ ec->avg_Lu_i_ok, ec->avg_Lu_i_toolow);
+
+ ec->cntr_nearend_speech_frames = 0;
+ ec->cntr_residualcorrected_frames = 0;
+ ec->cntr_residualcorrected_framesskipped = 0;
+ ec->cntr_coeff_updates = 0;
+ ec->cntr_coeff_missedupdates = 0;
+ ec->avg_Lu_i_ok = 0;
+ ec->avg_Lu_i_toolow = 0;
+ }
+#endif
+
+ /* Increment the sample index and return the corrected sample */
+ ec->i_d++;
+ return u;
+}
+
+static int echo_can_create(struct zt_echocanparams *ecp, struct zt_echocanparam *p,
+ struct echo_can_state **ec)
+{
+ int maxy;
+ int maxu;
+ size_t size;
+ unsigned int x;
+ char *c;
+
+ maxy = ecp->tap_length + DEFAULT_M;
+ maxu = DEFAULT_M;
+ if (maxy < (1 << DEFAULT_ALPHA_YT_I))
+ maxy = (1 << DEFAULT_ALPHA_YT_I);
+ if (maxy < (1 << DEFAULT_SIGMA_LY_I))
+ maxy = (1 << DEFAULT_SIGMA_LY_I);
+ if (maxu < (1 << DEFAULT_SIGMA_LU_I))
+ maxu = (1 << DEFAULT_SIGMA_LU_I);
+ size = sizeof(**ec) +
+ 4 + /* align */
+ sizeof(int) * ecp->tap_length + /* a_i */
+ sizeof(short) * ecp->tap_length + /* a_s */
+ sizeof(int) * ecp->tap_length + /* b_i */
+ sizeof(int) * ecp->tap_length + /* c_i */
+ 2 * sizeof(short) * (maxy) + /* y_s */
+ 2 * sizeof(short) * (1 << DEFAULT_ALPHA_ST_I) + /* s_s */
+ 2 * sizeof(short) * (maxu) + /* u_s */
+ 2 * sizeof(short) * ecp->tap_length; /* y_tilde_s */
+
+ if (!(*ec = MALLOC(size)))
+ return -ENOMEM;
+
+ memset(*ec, 0, size);
+
+#ifdef AGGRESSIVE_SUPPRESSOR
+ (*ec)->aggressive = 1;
+#endif
+
+ for (x = 0; x < ecp->param_count; x++) {
+ for (c = p[x].name; *c; c++)
+ *c = tolower(*c);
+ if (!strcmp(p[x].name, "aggressive")) {
+ (*ec)->aggressive = p[x].value ? 1 : 0;
+ } else {
+ printk(KERN_WARNING "Unknown parameter supplied to MG2 echo canceler: '%s'\n", p[x].name);
+ kfree(*ec);
+
+ return -EINVAL;
+ }
+ }
+
+ init_cc(*ec, ecp->tap_length, maxy, maxu);
+
+ return 0;
+}
+
+static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+ /* Set the hangover counter to the length of the can to
+ * avoid adjustments occuring immediately after initial forced training
+ */
+ ec->HCNTR_d = ec->N_d << 1;
+
+ if (pos >= ec->N_d) {
+ memcpy(ec->b_i,ec->a_i,ec->N_d*sizeof(int));
+ memcpy(ec->c_i,ec->a_i,ec->N_d*sizeof(int));
+ return 1;
+ }
+
+ ec->a_i[pos] = val << 17;
+ ec->a_s[pos] = val << 1;
+
+ if (++pos >= ec->N_d) {
+ memcpy(ec->b_i,ec->a_i,ec->N_d*sizeof(int));
+ memcpy(ec->c_i,ec->a_i,ec->N_d*sizeof(int));
+ return 1;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/drivers/dahdi/mg2ec_const.h b/drivers/dahdi/mg2ec_const.h
new file mode 100644
index 0000000..08fd897
--- /dev/null
+++ b/drivers/dahdi/mg2ec_const.h
@@ -0,0 +1,88 @@
+/*
+ Important constants for tuning mg2 echo can
+ */
+#ifndef _MG2_CONST_H
+#define _MG2_CONST_H
+
+
+/* Convergence (aka. adaptation) speed -- higher means slower */
+#define DEFAULT_BETA1_I 2048
+
+/* Constants for various power computations */
+#define DEFAULT_SIGMA_LY_I 7
+#define DEFAULT_SIGMA_LU_I 7
+#define DEFAULT_ALPHA_ST_I 5 /* near-end speech detection sensitivity factor */
+#define DEFAULT_ALPHA_YT_I 5
+
+#define DEFAULT_CUTOFF_I 128
+
+/* Define the near-end speech hangover counter: if near-end speech
+ * is declared, hcntr is set equal to hangt (see pg. 432)
+ */
+#define DEFAULT_HANGT 600 /* in samples, so 600 samples = 75ms */
+
+/* define the residual error suppression threshold */
+#define DEFAULT_SUPPR_I 16 /* 16 = -24db */
+
+/* This is the minimum reference signal power estimate level
+ * that will result in filter adaptation.
+ * If this is too low then background noise will cause the filter
+ * coefficients to constantly be updated.
+ */
+#define MIN_UPDATE_THRESH_I 2048
+
+/* The number of samples used to update coefficients using the
+ * the block update method (M). It should be related back to the
+ * length of the echo can.
+ * ie. it only updates coefficients when (sample number MOD default_m) = 0
+ *
+ * Getting this wrong may cause an oops. Consider yourself warned!
+ */
+#define DEFAULT_M 16 /* every 16th sample */
+
+/* If AGGRESSIVE supression is enabled, then we start cancelling residual
+ * echos again even while there is potentially the very end of a near-side
+ * signal present.
+ * This defines how many samples of DEFAULT_HANGT can remain before we
+ * kick back in
+ */
+#define AGGRESSIVE_HCNTR 160 /* in samples, so 160 samples = 20ms */
+
+/* Treat sample as error if it has a different sign as the
+ * input signal and is this number larger in ABS() as
+ * the input-signal */
+#define MAX_SIGN_ERROR 3000
+
+/* Number of coefficients really used for calculating the
+ * simulated echo. The value specifies how many of the
+ * biggest coefficients are used for calculating rs.
+ * This helps on long echo-tails by artificially limiting
+ * the number of coefficients for the calculation and
+ * preventing overflows.
+ * Comment this to deactivate the code */
+#define USED_COEFFS 64
+
+/* Backup coefficients every this number of samples */
+#define BACKUP 256
+
+/***************************************************************/
+/* The following knobs are not implemented in the current code */
+
+/* we need a dynamic level of suppression varying with the ratio of the
+ power of the echo to the power of the reference signal this is
+ done so that we have a smoother background.
+ we have a higher suppression when the power ratio is closer to
+ suppr_ceil and reduces logarithmically as we approach suppr_floor.
+ */
+#define SUPPR_FLOOR -64
+#define SUPPR_CEIL -24
+
+/* in a second departure, we calculate the residual error suppression
+ * as a percentage of the reference signal energy level. The threshold
+ * is defined in terms of dB below the reference signal.
+ */
+#define RES_SUPR_FACTOR -20
+
+
+#endif /* _MG2_CONST_H */
+
diff --git a/drivers/dahdi/pciradio.c b/drivers/dahdi/pciradio.c
new file mode 100644
index 0000000..f342859
--- /dev/null
+++ b/drivers/dahdi/pciradio.c
@@ -0,0 +1,1935 @@
+/*
+ * PCI RADIO Card Zapata Telephony PCI Quad Radio Interface driver
+ *
+ * Written by Jim Dixon <jim@lambdatel.com>
+ * Based on previous work by Mark Spencer <markster@digium.com>
+ * Based on previous works, designs, and archetectures conceived and
+ * written by Jim Dixon <jim@lambdatel.com>.
+ *
+ * Copyright (C) 2001-2007 Jim Dixon / Zapata Telephony.
+ *
+ * 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.
+ *
+ */
+
+/*
+ The PCI Radio Interface card interfaces up to 4 two-way radios (either
+ a base/mobile radio or repeater system) to Zaptel channels. The driver
+ may work either independent of an application, or with it, through
+ the driver;s ioctl() interface. This file gives you access to specify
+ load-time parameters for Radio channels, so that the driver may run
+ by itself, and just act like a generic Zaptel radio interface.
+*/
+
+/* Latency tests:
+
+Without driver: 308496
+With driver: 303826 (1.5 %)
+
+*/
+
+
+#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 <asm/io.h>
+#include <asm/delay.h>
+
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+#define RAD_MAX_IFACES 128
+
+#define NUM_CODES 15
+
+#define SERIAL_BUFLEN 128
+
+#define SRX_TIMEOUT 300
+
+#define RAD_CNTL 0x00
+#define RAD_OPER 0x01
+#define RAD_AUXC 0x02
+#define RAD_AUXD 0x03
+ #define XPGM 4
+ #define XCS 2
+
+#define RAD_MASK0 0x04
+#define RAD_MASK1 0x05
+#define RAD_INTSTAT 0x06
+#define RAD_AUXR 0x07
+ #define XINIT 8
+ #define XDONE 0x10
+
+#define RAD_DMAWS 0x08
+#define RAD_DMAWI 0x0c
+#define RAD_DMAWE 0x10
+#define RAD_DMARS 0x18
+#define RAD_DMARI 0x1c
+#define RAD_DMARE 0x20
+
+#define RAD_AUXFUNC 0x2b
+#define RAD_SERCTL 0x2d
+#define RAD_FSCDELAY 0x2f
+
+#define RAD_REGBASE 0xc0
+
+#define RAD_CTCSSMASK 0xf
+#define RAD_CTCSSOTHER 0xf
+#define RAD_CTCSSVALID 0x10
+
+#define NUM_CHANS 4
+
+#define RAD_GOTRX_DEBOUNCE_TIME 75
+#define RAD_CTCSS_ACQUIRE_TIME 10
+#define RAD_CTCSS_TALKOFF_TIME 1000
+
+#define ZT_RADPAR_CTCSSACQUIRETIME 18 /* DEBUG only, this belongs in zaptel.h */
+#define ZT_RADPAR_CTCSSTALKOFFTIME 19 /* DEBUG only, this belongs in zaptel.h */
+
+/*
+* MX828 Commands
+*/
+
+#define MX828_GEN_RESET 0x01 /* W */
+#define MX828_SAUDIO_CTRL 0x80 /* W */
+#define MX828_SAUDIO_STATUS 0x81 /* R */
+#define MX828_SAUDIO_SETUP 0x82 /* W */
+#define MX828_TX_TONE 0x83 /* W16 */
+#define MX828_RX_TONE 0x84 /* W16 */
+#define MX828_DCS3 0x85 /* W */
+#define MX828_DCS2 0x86 /* W */
+#define MX828_DCS1 0x87 /* W */
+#define MX828_GEN_CTRL 0x88 /* W */
+#define MX828_GPT 0x8B /* W */
+#define MX828_IRQ_MASK 0x8E /* W */
+#define MX828_SELCALL 0x8D /* W16 */
+#define MX828_AUD_CTRL 0x8A /* W16 */
+#define MX828_IRQ_FLAG 0x8F /* R */
+
+
+struct encdec
+{
+ unsigned char state; /* 0 = idle */
+ int chan;
+ unsigned char req[NUM_CHANS];
+ unsigned char dcsrx[NUM_CHANS];
+ unsigned char ctrx[NUM_CHANS];
+ unsigned char dcstx[NUM_CHANS];
+ unsigned char cttx[NUM_CHANS];
+ unsigned char saudio_ctrl[NUM_CHANS];
+ unsigned char saudio_setup[NUM_CHANS];
+ unsigned char txcode[NUM_CHANS];
+ unsigned long lastcmd;
+ int myindex[NUM_CHANS];
+ unsigned long waittime;
+ unsigned char retstate;
+} ;
+
+
+struct pciradio {
+ struct pci_dev *dev;
+ struct zt_span span;
+ unsigned char ios;
+ int usecount;
+ unsigned int intcount;
+ int dead;
+ int pos;
+ int freeregion;
+ int nchans;
+ spinlock_t lock;
+ int remote_locked;
+ unsigned char rxbuf[SERIAL_BUFLEN];
+ unsigned short rxindex;
+ unsigned long srxtimer;
+ unsigned char txbuf[SERIAL_BUFLEN];
+ unsigned short txindex;
+ unsigned short txlen;
+ unsigned char pasave;
+ unsigned char pfsave;
+ volatile unsigned long ioaddr;
+ dma_addr_t readdma;
+ dma_addr_t writedma;
+ volatile unsigned int *writechunk; /* Double-word aligned write memory */
+ volatile unsigned int *readchunk; /* Double-word aligned read memory */
+ unsigned char saudio_status[NUM_CHANS];
+ char gotcor[NUM_CHANS];
+ char gotct[NUM_CHANS];
+ char newctcssstate[NUM_CHANS];
+ char ctcssstate[NUM_CHANS];
+ char gotrx[NUM_CHANS];
+ char gotrx1[NUM_CHANS];
+ char gottx[NUM_CHANS];
+ char lasttx[NUM_CHANS];
+ int gotrxtimer[NUM_CHANS];
+ int ctcsstimer[NUM_CHANS];
+ int debouncetime[NUM_CHANS];
+ int ctcssacquiretime[NUM_CHANS];
+ int ctcsstalkofftime[NUM_CHANS];
+ int bursttime[NUM_CHANS];
+ int bursttimer[NUM_CHANS];
+ unsigned char remmode[NUM_CHANS];
+ unsigned short present_code[NUM_CHANS];
+ unsigned short last_code[NUM_CHANS];
+ unsigned short rxcode[NUM_CHANS][NUM_CODES + 1];
+ unsigned short rxclass[NUM_CHANS][NUM_CODES + 1];
+ unsigned short txcode[NUM_CHANS][NUM_CODES + 1];;
+ unsigned char radmode[NUM_CHANS];
+#define RADMODE_INVERTCOR 1
+#define RADMODE_IGNORECOR 2
+#define RADMODE_EXTTONE 4
+#define RADMODE_EXTINVERT 8
+#define RADMODE_IGNORECT 16
+#define RADMODE_NOENCODE 32
+ unsigned char corthresh[NUM_CHANS];
+ struct zt_chan chans[NUM_CHANS];
+ unsigned char mx828_addr;
+ struct encdec encdec;
+ unsigned long lastremcmd;
+};
+
+
+static struct pciradio *ifaces[RAD_MAX_IFACES];
+
+static void pciradio_release(struct pciradio *rad);
+
+static int debug = 0;
+
+struct tonedef {
+ int code;
+ unsigned char b1;
+ unsigned char b2;
+} ;
+
+#include "radfw.h"
+
+static struct tonedef cttable_tx [] = {
+{0,0,0},
+{670,0xE,0xB1},
+{693,0xE,0x34},
+{719,0xD,0xB1},
+{744,0xD,0x3B},
+{770,0xC,0xC9},
+{797,0xC,0x5A},
+{825,0xB,0xEF},
+{854,0xB,0x87},
+{885,0xB,0x1F},
+{915,0xA,0xC2},
+{948,0xA,0x62},
+{974,0xA,0x1B},
+{1000,0x9,0xD8},
+{1035,0x9,0x83},
+{1072,0x9,0x2F},
+{1109,0x8,0xE0},
+{1148,0x8,0x93},
+{1188,0x8,0x49},
+{1230,0x8,0x1},
+{1273,0x7,0xBC},
+{1318,0x7,0x78},
+{1365,0x7,0x36},
+{1413,0x6,0xF7},
+{1462,0x6,0xBC},
+{1514,0x6,0x80},
+{1567,0x6,0x48},
+{1598,0x6,0x29},
+{1622,0x6,0x12},
+{1679,0x5,0xDD},
+{1738,0x5,0xAA},
+{1799,0x5,0x79},
+{1835,0x5,0x5D},
+{1862,0x5,0x49},
+{1899,0x5,0x2F},
+{1928,0x5,0x1B},
+{1966,0x5,0x2},
+{1995,0x4,0xEF},
+{2035,0x4,0xD6},
+{2065,0x4,0xC4},
+{2107,0x4,0xAC},
+{2181,0x4,0x83},
+{2257,0x4,0x5D},
+{2291,0x4,0x4C},
+{2336,0x4,0x37},
+{2418,0x4,0x12},
+{2503,0x3,0xEF},
+{2541,0x3,0xE0},
+{0,0,0}
+} ;
+
+static struct tonedef cttable_rx [] = {
+{0,0,0},
+{670,0x3,0xD8},
+{693,0x4,0x9},
+{719,0x4,0x1B},
+{744,0x4,0x4E},
+{770,0x4,0x83},
+{797,0x4,0x94},
+{825,0x4,0xCB},
+{854,0x5,0x2},
+{885,0x5,0x14},
+{915,0x5,0x4C},
+{948,0x5,0x87},
+{974,0x5,0x94},
+{1000,0x5,0xCB},
+{1035,0x6,0x7},
+{1072,0x6,0x45},
+{1109,0x6,0x82},
+{1148,0x6,0xC0},
+{1188,0x6,0xD1},
+{1230,0x7,0x10},
+{1273,0x7,0x50},
+{1318,0x7,0xC0},
+{1365,0x8,0x2},
+{1413,0x8,0x44},
+{1462,0x8,0x86},
+{1514,0x8,0xC9},
+{1567,0x9,0xC},
+{1598,0x9,0x48},
+{1622,0x9,0x82},
+{1679,0x9,0xC6},
+{1738,0xA,0xB},
+{1799,0xA,0x84},
+{1835,0xA,0xC2},
+{1862,0xA,0xC9},
+{1899,0xB,0x8},
+{1928,0xB,0x44},
+{1966,0xB,0x83},
+{1995,0xB,0x8A},
+{2035,0xB,0xC9},
+{2065,0xC,0x6},
+{2107,0xC,0x46},
+{2181,0xC,0xC3},
+{2257,0xD,0x41},
+{2291,0xD,0x48},
+{2336,0xD,0x89},
+{2418,0xE,0x8},
+{2503,0xE,0x88},
+{2541,0xE,0xC7},
+{0,0,0}
+};
+
+static struct {
+ int code;
+ char b3;
+ char b2;
+ char b1;
+} dcstable[] = {
+{0,0,0,0},
+{23,0x76,0x38,0x13},
+{25,0x6B,0x78,0x15},
+{26,0x65,0xD8,0x16},
+{31,0x51,0xF8,0x19},
+{32,0x5F,0x58,0x1A},
+{43,0x5B,0x68,0x23},
+{47,0x0F,0xD8,0x27},
+{51,0x7C,0xA8,0x29},
+{54,0x6F,0x48,0x2C},
+{65,0x5D,0x18,0x35},
+{71,0x67,0x98,0x39},
+{72,0x69,0x38,0x3A},
+{73,0x2E,0x68,0x3B},
+{74,0x74,0x78,0x3C},
+{114,0x35,0xE8,0x4C},
+{115,0x72,0xB8,0x4D},
+{116,0x7C,0x18,0x4E},
+{125,0x07,0xB8,0x55},
+{131,0x3D,0x38,0x59},
+{132,0x33,0x98,0x5A},
+{134,0x2E,0xD8,0x5C},
+{143,0x37,0xA8,0x63},
+{152,0x1E,0xC8,0x6A},
+{155,0x44,0xD8,0x6D},
+{156,0x4A,0x78,0x6E},
+{162,0x6B,0xC8,0x72},
+{165,0x31,0xD8,0x75},
+{172,0x05,0xF8,0x7A},
+{174,0x18,0xB8,0x7C},
+{205,0x6E,0x98,0x85},
+{223,0x68,0xE8,0x93},
+{226,0x7B,0x08,0x96},
+{243,0x45,0xB8,0xA3},
+{244,0x1F,0xA8,0xA4},
+{245,0x58,0xF8,0xA5},
+{251,0x62,0x78,0xA9},
+{261,0x17,0x78,0xB1},
+{263,0x5E,0x88,0xB3},
+{265,0x43,0xC8,0xB5},
+{271,0x79,0x48,0xB9},
+{306,0x0C,0xF8,0xC6},
+{311,0x38,0xD8,0xC9},
+{315,0x6C,0x68,0xCD},
+{331,0x23,0xE8,0xD9},
+{343,0x29,0x78,0xE3},
+{346,0x3A,0x98,0xE6},
+{351,0x0E,0xB8,0xE9},
+{364,0x68,0x58,0xF4},
+{365,0x2F,0x08,0xF5},
+{371,0x15,0x88,0xF9},
+{411,0x77,0x69,0x09},
+{412,0x79,0xC9,0x0A},
+{413,0x3E,0x99,0x0B},
+{423,0x4B,0x99,0x13},
+{431,0x6C,0x59,0x19},
+{432,0x62,0xF9,0x1A},
+{445,0x7B,0x89,0x25},
+{464,0x27,0xE9,0x34},
+{465,0x60,0xB9,0x35},
+{466,0x6E,0x19,0x36},
+{503,0x3C,0x69,0x43},
+{506,0x2F,0x89,0x46},
+{516,0x41,0xB9,0x4E},
+{532,0x0E,0x39,0x5A},
+{546,0x19,0xE9,0x66},
+{565,0x0C,0x79,0x75},
+{606,0x5D,0x99,0x86},
+{612,0x67,0x19,0x8A},
+{624,0x0F,0x59,0x94},
+{627,0x01,0xF9,0x97},
+{631,0x72,0x89,0x99},
+{632,0x7C,0x29,0x9A},
+{654,0x4C,0x39,0xAC},
+{662,0x24,0x79,0xB2},
+{664,0x39,0x39,0xB4},
+{703,0x22,0xB9,0xC3},
+{712,0x0B,0xD9,0xCA},
+{723,0x39,0x89,0xD3},
+{731,0x1E,0x49,0xD9},
+{732,0x10,0xE9,0xDA},
+{734,0x0D,0xA9,0xDC},
+{743,0x14,0xD9,0xE3},
+{754,0x20,0xF9,0xEC},
+{0,0,0,0}
+};
+
+static int gettxtone(int code)
+{
+int i;
+
+ if (!code) return(0);
+ for(i = 0; cttable_tx[i].code || (!i); i++)
+ {
+ if (cttable_tx[i].code == code)
+ {
+ return (i);
+ }
+ }
+ return(-1);
+}
+
+static int getrxtone(int code)
+{
+int i;
+
+ if (!code) return(0);
+ for(i = 0; cttable_rx[i].code || (!i); i++)
+ {
+ if (cttable_rx[i].code == code)
+ {
+ return (i);
+ }
+ }
+ return(-1);
+}
+
+
+static int getdcstone(int code)
+{
+int i;
+
+ if (!code) return(0);
+ for(i = 0; dcstable[i].code || (!i); i++)
+ {
+ if (dcstable[i].code == code)
+ {
+ return (i);
+ }
+ }
+ return(-1);
+}
+
+
+void __pciradio_setcreg(struct pciradio *rad, unsigned char reg, unsigned char val)
+{
+ outb(val, rad->ioaddr + RAD_REGBASE + ((reg & 0xf) << 2));
+}
+
+unsigned char __pciradio_getcreg(struct pciradio *rad, unsigned char reg)
+{
+ return inb(rad->ioaddr + RAD_REGBASE + ((reg & 0xf) << 2));
+}
+
+
+void rbi_out(struct pciradio *rad, int n, unsigned char *rbicmd)
+{
+unsigned long flags;
+int x;
+DECLARE_WAIT_QUEUE_HEAD(mywait);
+
+
+ for(;;)
+ {
+ spin_lock_irqsave(&rad->lock,flags);
+ x = rad->remote_locked || (__pciradio_getcreg(rad,0xc) & 2);
+ if (!x) rad->remote_locked = 1;
+ spin_unlock_irqrestore(&rad->lock,flags);
+ if (x) interruptible_sleep_on_timeout(&mywait,2);
+ else break;
+ }
+ spin_lock_irqsave(&rad->lock,flags);
+ /* enable and address RBI serializer */
+ __pciradio_setcreg(rad,0xf,rad->pfsave | (n << 4) | 0x40);
+ /* output commands */
+ for(x = 0; x < 5; x++) __pciradio_setcreg(rad,0xc,rbicmd[x]);
+ /* output it */
+ __pciradio_setcreg(rad,0xb,1);
+ rad->remote_locked = 0;
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return;
+}
+
+
+/*
+* Output a command to the MX828 over the serial bus
+*/
+
+
+void mx828_command(struct pciradio *rad,int channel, unsigned char command, unsigned char *byte1, unsigned char *byte2)
+{
+
+ if(channel > 3)
+ return;
+
+ rad->mx828_addr = channel;
+ __pciradio_setcreg(rad,0,channel);
+ if (byte1) __pciradio_setcreg(rad,1,*byte1);
+ if (byte2) __pciradio_setcreg(rad,2,*byte2);
+ __pciradio_setcreg(rad,3,command);
+
+}
+
+void mx828_command_wait(struct pciradio *rad,int channel, unsigned char command, unsigned char *byte1, unsigned char *byte2)
+{
+DECLARE_WAIT_QUEUE_HEAD(mywait);
+unsigned long flags;
+
+
+ spin_lock_irqsave(&rad->lock,flags);
+ while(rad->encdec.state)
+ {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ interruptible_sleep_on_timeout(&mywait,2);
+ spin_lock_irqsave(&rad->lock,flags);
+ }
+ rad->encdec.lastcmd = jiffies + 1000;
+ spin_unlock_irqrestore(&rad->lock,flags);
+ while(__pciradio_getcreg(rad,0xc) & 1);
+ rad->encdec.lastcmd = jiffies + 1000;
+ spin_lock_irqsave(&rad->lock,flags);
+ rad->encdec.lastcmd = jiffies + 1000;
+ mx828_command(rad,channel,command,byte1,byte2);
+ spin_unlock_irqrestore(&rad->lock,flags);
+ rad->encdec.lastcmd = jiffies + 1000;
+ while(__pciradio_getcreg(rad,0xc) & 1);
+ rad->encdec.lastcmd = jiffies;
+}
+
+static void _do_encdec(struct pciradio *rad)
+{
+int i,n;
+unsigned char byte1 = 0,byte2 = 0;
+
+ /* return doing nothing if busy */
+ if ((rad->encdec.lastcmd + 2) > jiffies) return;
+ if (__pciradio_getcreg(rad,0xc) & 1) return;
+ n = 0;
+ byte2 = 0;
+ switch(rad->encdec.state)
+ {
+ case 0:
+ for(i = 0; i < rad->nchans; i++)
+ {
+ n = (unsigned)(i - rad->intcount) % rad->nchans;
+ if (rad->encdec.req[n]) break;
+ }
+ if (i >= rad->nchans) return;
+ rad->encdec.req[n] = 0;
+ rad->encdec.dcsrx[n] = 0;
+ rad->encdec.ctrx[n] = 0;
+ rad->encdec.dcstx[n] = 0;
+ rad->encdec.cttx[n] = 0;
+ rad->encdec.myindex[n] = 0;
+ rad->encdec.req[n] = 0;
+ rad->encdec.chan = n;
+
+ /* if something in code 0 for rx, is DCS */
+ if (rad->rxcode[n][0]) rad->encdec.dcsrx[n] = 1;
+ else { /* otherwise, if something in other codes, is CT rx */
+ for(i = 1; i <= NUM_CODES; i++)
+ {
+ if (rad->rxcode[n][1]) rad->encdec.ctrx[n] = 1;
+ }
+ }
+ /* get index for tx code. Will be 0 if not receiving a CT */
+ rad->encdec.myindex[n] = 0;
+ if (rad->gotrx[n] && rad->encdec.ctrx[n] && (rad->present_code[n]))
+ rad->encdec.myindex[n] = rad->present_code[n];
+ /* get actual tx code from array */
+ rad->encdec.txcode[n] = rad->txcode[n][rad->encdec.myindex[n]];
+ if (rad->encdec.txcode[n] & 0x8000) rad->encdec.dcstx[n] = 1;
+ else if (rad->encdec.txcode[n]) rad->encdec.cttx[n] = 1;
+ if (rad->radmode[n] & RADMODE_NOENCODE)
+ rad->encdec.dcstx[n] = rad->encdec.cttx[n] = 0;
+ if ((!rad->gottx[n]) || rad->bursttimer[n])
+ rad->encdec.dcstx[n] = rad->encdec.cttx[n] = 0;
+ rad->encdec.saudio_ctrl[n] = 0;
+ rad->encdec.saudio_setup[n] = 0;
+ rad->encdec.state = 1;
+ break;
+ case 1:
+ if (rad->encdec.dcstx[rad->encdec.chan] && (!rad->encdec.dcsrx[rad->encdec.chan])) /* if to transmit DCS */
+ {
+ rad->encdec.saudio_setup[rad->encdec.chan] |= 3;
+ rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x80;
+ byte1 = dcstable[rad->encdec.txcode[rad->encdec.chan] & 0x7fff].b1;
+ mx828_command(rad,rad->encdec.chan, MX828_DCS1, &byte1, &byte2 );
+ rad->encdec.state = 2;
+ break;
+ }
+ rad->encdec.state = 4;
+ break;
+ case 2:
+ byte1 = dcstable[rad->encdec.txcode[rad->encdec.chan] & 0x7fff].b2;
+ mx828_command(rad,rad->encdec.chan, MX828_DCS2, &byte1, &byte2 );
+ rad->encdec.state = 3;
+ break;
+ case 3:
+ byte1 = dcstable[rad->encdec.txcode[rad->encdec.chan] & 0x7fff].b3;
+ mx828_command(rad,rad->encdec.chan, MX828_DCS3, &byte1, &byte2 );
+ rad->encdec.state = 4;
+ break;
+ case 4:
+ if (rad->encdec.cttx[rad->encdec.chan])
+ {
+ rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x80;
+ byte1 = cttable_tx[rad->encdec.txcode[rad->encdec.chan]].b1;
+ byte2 = cttable_tx[rad->encdec.txcode[rad->encdec.chan]].b2;
+ mx828_command(rad,rad->encdec.chan, MX828_TX_TONE, &byte1, &byte2 );
+ }
+ rad->encdec.state = 5;
+ break;
+ case 5:
+ if (rad->encdec.dcsrx[rad->encdec.chan])
+ {
+ rad->encdec.saudio_setup[rad->encdec.chan] |= 1;
+ rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x41;
+ byte1 = dcstable[rad->rxcode[rad->encdec.chan][0]].b1;
+ mx828_command(rad,rad->encdec.chan, MX828_DCS1, &byte1, &byte2 );
+ rad->encdec.state = 6;
+ break;
+ }
+ rad->encdec.state = 8;
+ break;
+ case 6:
+ byte1 = dcstable[rad->rxcode[rad->encdec.chan][0]].b2;
+ mx828_command(rad,rad->encdec.chan, MX828_DCS2, &byte1, &byte2 );
+ rad->encdec.state = 7;
+ break;
+ case 7:
+ byte1 = dcstable[rad->rxcode[rad->encdec.chan][0]].b3;
+ mx828_command(rad,rad->encdec.chan, MX828_DCS3, &byte1, &byte2 );
+ rad->encdec.state = 8;
+ break;
+ case 8:
+ if (rad->encdec.ctrx[rad->encdec.chan])
+ {
+ rad->encdec.saudio_setup[rad->encdec.chan] |= 0x80;
+ rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x60;
+ }
+ byte1 = rad->encdec.saudio_setup[rad->encdec.chan];
+ mx828_command(rad,rad->encdec.chan, MX828_SAUDIO_SETUP, &byte1, &byte2 );
+ rad->encdec.state = 9;
+ break;
+ case 9:
+ byte1 = rad->encdec.saudio_ctrl[rad->encdec.chan];
+ mx828_command(rad,rad->encdec.chan, MX828_SAUDIO_CTRL, &byte1, &byte2 );
+ rad->encdec.state = 10;
+ break;
+ case 10:
+ rad->encdec.chan = 0;
+ rad->encdec.state = 0;
+ break;
+ }
+}
+
+static inline void pciradio_transmitprep(struct pciradio *rad, unsigned char ints)
+{
+ volatile unsigned int *writechunk;
+ int x;
+ if (ints & 0x01)
+ /* Write is at interrupt address. Start writing from normal offset */
+ writechunk = rad->writechunk;
+ else
+ writechunk = rad->writechunk + ZT_CHUNKSIZE;
+
+ /* Calculate Transmission */
+ zt_transmit(&rad->span);
+
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ /* Send a sample, as a 32-bit word */
+ writechunk[x] = 0;
+ writechunk[x] |= (rad->chans[0].writechunk[x] << 24);
+ writechunk[x] |= (rad->chans[1].writechunk[x] << 16);
+ writechunk[x] |= (rad->chans[2].writechunk[x] << 8);
+ writechunk[x] |= (rad->chans[3].writechunk[x]);
+ }
+}
+
+static inline void pciradio_receiveprep(struct pciradio *rad, unsigned char ints)
+{
+ volatile unsigned int *readchunk;
+ int x;
+
+ if (ints & 0x08)
+ readchunk = rad->readchunk + ZT_CHUNKSIZE;
+ else
+ /* Read is at interrupt address. Valid data is available at normal offset */
+ readchunk = rad->readchunk;
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ rad->chans[0].readchunk[x] = (readchunk[x] >> 24) & 0xff;
+ rad->chans[1].readchunk[x] = (readchunk[x] >> 16) & 0xff;
+ rad->chans[2].readchunk[x] = (readchunk[x] >> 8) & 0xff;
+ rad->chans[3].readchunk[x] = (readchunk[x]) & 0xff;
+ }
+ for (x=0;x<rad->nchans;x++) {
+ zt_ec_chunk(&rad->chans[x], rad->chans[x].readchunk, rad->chans[x].writechunk);
+ }
+ zt_receive(&rad->span);
+}
+
+static void pciradio_stop_dma(struct pciradio *rad);
+static void pciradio_reset_serial(struct pciradio *rad);
+static void pciradio_restart_dma(struct pciradio *rad);
+
+#ifdef LEAVE_THIS_COMMENTED_OUT
+#ifdef LINUX26
+static irqreturn_t pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#else
+static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#endif
+#endif
+
+ZAP_IRQ_HANDLER(pciradio_interrupt)
+{
+ struct pciradio *rad = dev_id;
+ unsigned char ints,byte1,byte2,gotcor,gotctcss,gotslowctcss,ctcss;
+ int i,x,gotrx;
+
+ ints = inb(rad->ioaddr + RAD_INTSTAT);
+ outb(ints, rad->ioaddr + RAD_INTSTAT);
+
+ if (!ints)
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+
+ if (ints & 0x10) {
+ /* Stop DMA, wait for watchdog */
+ printk("RADIO PCI Master abort\n");
+ pciradio_stop_dma(rad);
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#else
+ return;
+#endif
+ }
+
+ if (ints & 0x20) {
+ printk("RADIO PCI Target abort\n");
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#else
+ return;
+#endif
+ }
+
+ if (ints & 0x0f) {
+
+ rad->intcount++;
+ x = rad->intcount % rad->nchans;
+ /* freeze */
+ __pciradio_setcreg(rad,0,rad->mx828_addr | 4);
+ /* read SAUDIO_STATUS for the proper channel */
+ byte1 = rad->saudio_status[x] = __pciradio_getcreg(rad,x);
+ /* thaw */
+ __pciradio_setcreg(rad,0,rad->mx828_addr);
+ /* get COR input */
+ byte2 = __pciradio_getcreg(rad,9);
+ /* get bit for this channel */
+ gotcor = byte2 & (1 << x);
+ if (rad->radmode[x] & RADMODE_INVERTCOR) gotcor = !gotcor;
+ rad->gotcor[x] = gotcor;
+ if (rad->radmode[x] & RADMODE_IGNORECOR) gotcor = 1;
+ gotslowctcss = 0;
+ if ((byte1 & RAD_CTCSSVALID) &&
+ ((byte1 & RAD_CTCSSMASK) != RAD_CTCSSOTHER)) gotslowctcss = 1;
+ gotctcss = 1;
+ ctcss = 0;
+ /* set ctcss to 1 if decoding ctcss */
+ if (!rad->rxcode[x][0])
+ {
+ for(i = 1; i <= NUM_CODES; i++)
+ {
+ if (rad->rxcode[x][i])
+ {
+ ctcss = 1;
+ break;
+ }
+ }
+ }
+ if (ctcss)
+ {
+ if ((!(byte1 & 0x40)) ||
+ ((!rad->gotrx[x]) && (!gotslowctcss))) gotctcss = 0;
+ }
+ rad->present_code[x] = 0;
+ if (rad->rxcode[x][0])
+ {
+ if (byte1 & 0x80) gotctcss = gotslowctcss = 1; else gotctcss = 0;
+ } else if (gotslowctcss) rad->present_code[x] = (byte1 & RAD_CTCSSMASK) + 1;
+ if (rad->radmode[x] & RADMODE_EXTTONE)
+ {
+ unsigned mask = 1 << (x + 4); /* they're on the UIOB's */
+ unsigned char byteuio;
+
+ /* set UIOB as input */
+ byteuio = __pciradio_getcreg(rad,0xe);
+ byteuio |= mask;
+ __pciradio_setcreg(rad,0xe,byteuio);
+ /* get UIO input */
+ byteuio = __pciradio_getcreg(rad,8);
+ if (rad->radmode[x] & RADMODE_EXTINVERT)
+ gotctcss = gotslowctcss = ((byteuio & mask) == 0);
+ else
+ gotctcss = gotslowctcss = ((byteuio & mask) != 0);
+ }
+ rad->gotct[x] = gotslowctcss;
+ if ((rad->radmode[x] & RADMODE_IGNORECT) ||
+ ((!(rad->radmode[x] & RADMODE_EXTTONE)) && (!ctcss)))
+ {
+ gotctcss = 1;
+ gotslowctcss = 1;
+ rad->present_code[x] = 0;
+ }
+ if(rad->newctcssstate[x] != gotctcss){
+ rad->newctcssstate[x] = gotctcss;
+ if(rad->newctcssstate[x])
+ rad->ctcsstimer[x]=rad->ctcssacquiretime[x];
+ else
+ rad->ctcsstimer[x]=rad->ctcsstalkofftime[x];
+ }
+ else{
+ if(!rad->ctcsstimer[x])
+ rad->ctcssstate[x] = rad->newctcssstate[x];
+ else
+ rad->ctcsstimer[x]--;
+ }
+ gotrx = gotcor && rad->ctcssstate[x];
+ if (gotrx != rad->gotrx[x])
+ {
+ rad->gotrxtimer[x] = rad->debouncetime[x];
+ }
+ rad->gotrx[x] = gotrx;
+ if (rad->present_code[x] != rad->last_code[x])
+ {
+ rad->encdec.req[x] = 1;
+ rad->last_code[x] = rad->present_code[x];
+ }
+ _do_encdec(rad);
+ for(x = 0; x < rad->nchans; x++)
+ {
+ unsigned char mask = 1 << x;
+
+ if (rad->gottx[x] != rad->lasttx[x])
+ {
+ if (rad->gottx[x])
+ {
+ rad->bursttimer[x] = 0;
+ rad->pasave |= mask;
+ __pciradio_setcreg(rad, 0xa, rad->pasave);
+ }
+ else
+ {
+ if (!rad->bursttime[x])
+ {
+ rad->pasave &= ~mask;
+ __pciradio_setcreg(rad, 0xa, rad->pasave);
+ }
+ else
+ {
+ rad->bursttimer[x] = rad->bursttime[x];
+ }
+ }
+ rad->encdec.req[x] = 1;
+ rad->lasttx[x] = rad->gottx[x];
+ }
+ if (rad->bursttimer[x])
+ {
+ /* if just getting to zero */
+ if (!(--rad->bursttimer[x]))
+ {
+ unsigned char mask = 1 << x;
+
+ rad->pasave &= ~mask;
+ __pciradio_setcreg(rad, 0xa, rad->pasave);
+ }
+ }
+
+ /* if timer active */
+ if (rad->gotrxtimer[x])
+ {
+ /* if just getting to zero */
+ if (!(--rad->gotrxtimer[x]))
+ {
+ unsigned char mask;
+
+ mask = 1 << (x + 4);
+ rad->pasave &= ~mask;
+ if (gotctcss) rad->pasave |= mask;
+ __pciradio_setcreg(rad, 0xa, rad->pasave);
+
+ if (rad->gotrx[x] != rad->gotrx1[x])
+ {
+ if (rad->gotrx[x]) {
+ if (debug)
+ {
+ if (rad->present_code[x])
+ printk("Chan %d got rx (ctcss code %d)\n",x + 1,
+ cttable_rx[rad->rxcode[x][rad->present_code[x]]].code);
+ else
+ printk("Chan %d got rx\n",x + 1);
+ }
+ zt_hooksig(&rad->chans[x],ZT_RXSIG_OFFHOOK);
+ } else {
+ if (debug) printk("Chan %d lost rx\n",x + 1);
+ zt_hooksig(&rad->chans[x],ZT_RXSIG_ONHOOK);
+ }
+ rad->encdec.req[x] = 1;
+ }
+ rad->gotrx1[x] = rad->gotrx[x];
+ }
+ }
+ }
+ /* process serial if any */
+ /* send byte if there is one in buffer to send */
+ if (rad->txlen && (rad->txlen != rad->txindex))
+ {
+ /* if tx not busy */
+ if (!(__pciradio_getcreg(rad,9) & 0x80))
+ {
+ __pciradio_setcreg(rad, 4, rad->txbuf[rad->txindex++]);
+ }
+ }
+ rad->srxtimer++;
+ /* if something in rx to read */
+ while(__pciradio_getcreg(rad,9) & 0x10)
+ {
+ unsigned char c = __pciradio_getcreg(rad,4);
+ rad->srxtimer = 0;
+ if (rad->rxindex < RAD_SERIAL_BUFLEN)
+ {
+ rad->rxbuf[rad->rxindex++] = c;
+ }
+ udelay(1);
+ }
+ pciradio_receiveprep(rad, ints);
+ pciradio_transmitprep(rad, ints);
+ i = 0;
+ for(x = 0; x < 4; x++)
+ {
+ if (rad->gottx[x]) i |= (1 << (x * 2));
+ if (rad->gotrx[x]) i |= (2 << (x * 2));
+ }
+ /* output LED's */
+ __pciradio_setcreg(rad, 9, i);
+ }
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+
+}
+
+static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
+{
+ int i,mycode;
+ unsigned long flags;
+ unsigned char byte1,byte2,mask;
+ union {
+ struct zt_radio_stat s;
+ struct zt_radio_param p;
+ } stack;
+
+ struct pciradio *rad = chan->pvt;
+ DECLARE_WAIT_QUEUE_HEAD(mywait);
+
+ switch (cmd) {
+ case ZT_RADIO_GETPARAM:
+ if (copy_from_user(&stack.p,(struct zt_radio_param *)data,sizeof(struct zt_radio_param))) return -EFAULT;
+ spin_lock_irqsave(&rad->lock,flags);
+ stack.p.data = 0; /* start with 0 value in output */
+ switch(stack.p.radpar) {
+ case ZT_RADPAR_INVERTCOR:
+ if (rad->radmode[chan->chanpos - 1] & RADMODE_INVERTCOR)
+ stack.p.data = 1;
+ break;
+ case ZT_RADPAR_IGNORECOR:
+ if (rad->radmode[chan->chanpos - 1] & RADMODE_IGNORECOR)
+ stack.p.data = 1;
+ break;
+ case ZT_RADPAR_IGNORECT:
+ if (rad->radmode[chan->chanpos - 1] & RADMODE_IGNORECT)
+ stack.p.data = 1;
+ break;
+ case ZT_RADPAR_NOENCODE:
+ if (rad->radmode[chan->chanpos - 1] & RADMODE_NOENCODE)
+ stack.p.data = 1;
+ break;
+ case ZT_RADPAR_CORTHRESH:
+ stack.p.data = rad->corthresh[chan->chanpos - 1] & 7;
+ break;
+ case ZT_RADPAR_EXTRXTONE:
+ if (rad->radmode[chan->chanpos - 1] & RADMODE_EXTTONE)
+ {
+ stack.p.data = 1;
+ if (rad->radmode[chan->chanpos - 1] & RADMODE_EXTINVERT)
+ {
+ stack.p.data = 2;
+ }
+ }
+ break;
+ case ZT_RADPAR_NUMTONES:
+ stack.p.data = NUM_CODES;
+ break;
+ case ZT_RADPAR_RXTONE:
+ if ((stack.p.index < 1) || (stack.p.index > NUM_CODES)) {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ stack.p.data =
+ cttable_rx[rad->rxcode[chan->chanpos - 1][stack.p.index] & 0x7fff].code;
+ break;
+ case ZT_RADPAR_RXTONECLASS:
+ if ((stack.p.index < 1) || (stack.p.index > NUM_CODES)) {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ stack.p.data = rad->rxclass[chan->chanpos - 1][stack.p.index] & 0xffff;
+ break;
+ case ZT_RADPAR_TXTONE:
+ if (stack.p.index > NUM_CODES) {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ stack.p.data = cttable_tx[rad->txcode[chan->chanpos - 1][stack.p.index] & 0x7fff].code;
+ /* if a DCS tone, return as such */
+ if (rad->txcode[chan->chanpos - 1][stack.p.index] & 0x8000)
+ stack.p.data |= 0x8000;
+ break;
+ case ZT_RADPAR_DEBOUNCETIME:
+ stack.p.data = rad->debouncetime[chan->chanpos - 1];
+ break;
+
+ case ZT_RADPAR_CTCSSACQUIRETIME:
+ stack.p.data = rad->ctcssacquiretime[chan->chanpos - 1];
+ break;
+
+ case ZT_RADPAR_CTCSSTALKOFFTIME:
+ stack.p.data = rad->ctcsstalkofftime[chan->chanpos - 1];
+ break;
+
+ case ZT_RADPAR_BURSTTIME:
+ stack.p.data = rad->bursttime[chan->chanpos - 1];
+ break;
+ case ZT_RADPAR_UIODATA:
+ stack.p.data = 0;
+ byte1 = __pciradio_getcreg(rad,8);
+ if (byte1 & (1 << (chan->chanpos - 1))) stack.p.data |= 1;
+ if (byte1 & (1 << (chan->chanpos + 3))) stack.p.data |= 2;
+ break;
+ case ZT_RADPAR_UIOMODE:
+ stack.p.data = 0;
+ byte1 = __pciradio_getcreg(rad,0xe);
+ if (byte1 & (1 << (chan->chanpos - 1))) stack.p.data |= 1;
+ if (byte1 & (1 << (chan->chanpos + 3))) stack.p.data |= 2;
+ break;
+ case ZT_RADPAR_REMMODE:
+ stack.p.data = rad->remmode[chan->chanpos - 1];
+ break;
+ default:
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&rad->lock,flags);
+ if (copy_to_user((struct zt_radio_param *)data,&stack.p,sizeof(struct zt_radio_param))) return -EFAULT;
+ break;
+ case ZT_RADIO_SETPARAM:
+ if (copy_from_user(&stack.p,(struct zt_radio_param *)data,sizeof(struct zt_radio_param))) return -EFAULT;
+ spin_lock_irqsave(&rad->lock,flags);
+ switch(stack.p.radpar) {
+ case ZT_RADPAR_INVERTCOR:
+ if (stack.p.data)
+ rad->radmode[chan->chanpos - 1] |= RADMODE_INVERTCOR;
+ else
+ rad->radmode[chan->chanpos - 1] &= ~RADMODE_INVERTCOR;
+ break;
+ case ZT_RADPAR_IGNORECOR:
+ if (stack.p.data)
+ rad->radmode[chan->chanpos - 1] |= RADMODE_IGNORECOR;
+ else
+ rad->radmode[chan->chanpos - 1] &= ~RADMODE_IGNORECOR;
+ break;
+ case ZT_RADPAR_IGNORECT:
+ if (stack.p.data)
+ rad->radmode[chan->chanpos - 1] |= RADMODE_IGNORECT;
+ else
+ rad->radmode[chan->chanpos - 1] &= ~RADMODE_IGNORECT;
+ break;
+ case ZT_RADPAR_NOENCODE:
+ if (stack.p.data)
+ rad->radmode[chan->chanpos - 1] |= RADMODE_NOENCODE;
+ else
+ rad->radmode[chan->chanpos - 1] &= ~RADMODE_NOENCODE;
+ break;
+ case ZT_RADPAR_CORTHRESH:
+ if ((stack.p.data < 0) || (stack.p.data > 7)) {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ rad->corthresh[chan->chanpos - 1] = stack.p.data;
+ byte1 = 0xc0 | (rad->corthresh[chan->chanpos - 1] << 2);
+ spin_unlock_irqrestore(&rad->lock,flags);
+ mx828_command_wait(rad,chan->chanpos - 1, MX828_GEN_CTRL, &byte1, &byte2);
+ spin_lock_irqsave(&rad->lock,flags);
+ break;
+ case ZT_RADPAR_EXTRXTONE:
+ if (stack.p.data)
+ rad->radmode[chan->chanpos - 1] |= RADMODE_EXTTONE;
+ else
+ rad->radmode[chan->chanpos - 1] &= ~RADMODE_EXTTONE;
+ if (stack.p.data > 1)
+ rad->radmode[chan->chanpos - 1] |= RADMODE_EXTINVERT;
+ else
+ rad->radmode[chan->chanpos - 1] &= ~RADMODE_EXTINVERT;
+ break;
+ case ZT_RADPAR_INITTONE:
+ for(i = 0; i <= NUM_CODES; i++)
+ {
+ rad->rxcode[chan->chanpos - 1][i] = 0;
+ rad->rxclass[chan->chanpos - 1][i] = 0;
+ rad->txcode[chan->chanpos - 1][i] = 0;
+ }
+ spin_unlock_irqrestore(&rad->lock,flags);
+ for(i = 0; i < NUM_CODES; i++)
+ {
+ /* set to no encode/decode */
+ byte1 = 0;
+ mx828_command_wait(rad,chan->chanpos - 1, MX828_SAUDIO_CTRL, &byte1, &byte2 );
+ /* set rx tone to none */
+ byte1 = i << 4;
+ byte2 = 0;
+ mx828_command_wait(rad,chan->chanpos - 1, MX828_RX_TONE, &byte1, &byte2 );
+ }
+ spin_lock_irqsave(&rad->lock,flags);
+ break;
+ case ZT_RADPAR_RXTONE:
+ if (!stack.p.index) /* if RX DCS mode */
+ {
+ if ((stack.p.data < 0) || (stack.p.data > 777)) {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ mycode = getdcstone(stack.p.data);
+ if (mycode < 0) {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ rad->rxcode[chan->chanpos - 1][0] = mycode;
+ rad->encdec.req[chan->chanpos - 1] = 1;
+ break;
+ }
+ if ((stack.p.index < 1) || (stack.p.index > NUM_CODES)) {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ mycode = getrxtone(stack.p.data);
+ if (mycode < 0) {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ rad->rxcode[chan->chanpos - 1][stack.p.index] = mycode;
+ byte1 = cttable_rx[mycode].b1 | ((stack.p.index - 1) << 4);
+ byte2 = cttable_rx[mycode].b2;
+ spin_unlock_irqrestore(&rad->lock,flags);
+ mx828_command_wait(rad,chan->chanpos - 1, MX828_RX_TONE, &byte1, &byte2 );
+ spin_lock_irqsave(&rad->lock,flags);
+ /* zot out DCS one if there */
+ rad->rxcode[chan->chanpos - 1][0] = 0;
+ rad->encdec.req[chan->chanpos - 1] = 1;
+ break;
+ case ZT_RADPAR_RXTONECLASS:
+ if ((stack.p.index < 1) || (stack.p.index > NUM_CODES)) {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ rad->rxclass[chan->chanpos - 1][stack.p.index] = stack.p.data & 0xffff;
+ break;
+ case ZT_RADPAR_TXTONE:
+ if (stack.p.index > NUM_CODES) {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ if (stack.p.data & 0x8000) /* if dcs */
+ mycode = getdcstone(stack.p.data & 0x7fff);
+ else
+ mycode = gettxtone(stack.p.data);
+ if (mycode < 0) {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ if (stack.p.data & 0x8000) mycode |= 0x8000;
+ rad->txcode[chan->chanpos - 1][stack.p.index] = mycode;
+ rad->encdec.req[chan->chanpos - 1] = 1;
+ break;
+ case ZT_RADPAR_DEBOUNCETIME:
+ rad->debouncetime[chan->chanpos - 1] = stack.p.data;
+ break;
+
+ case ZT_RADPAR_CTCSSACQUIRETIME:
+ rad->ctcssacquiretime[chan->chanpos - 1] = stack.p.data;
+ break;
+
+ case ZT_RADPAR_CTCSSTALKOFFTIME:
+ rad->ctcsstalkofftime[chan->chanpos - 1] = stack.p.data;
+ break;
+
+ case ZT_RADPAR_BURSTTIME:
+ rad->bursttime[chan->chanpos - 1] = stack.p.data;
+ break;
+ case ZT_RADPAR_UIODATA:
+ byte1 = __pciradio_getcreg(rad,8);
+ byte1 &= ~(1 << (chan->chanpos - 1));
+ byte1 &= ~(1 << (chan->chanpos + 3));
+ if (stack.p.data & 1) byte1 |= (1 << (chan->chanpos - 1));
+ if (stack.p.data & 2) byte1 |= (1 << (chan->chanpos + 3));
+ __pciradio_setcreg(rad,8,byte1);
+ break;
+ case ZT_RADPAR_UIOMODE:
+ byte1 = __pciradio_getcreg(rad,0xe);
+ byte1 &= ~(1 << (chan->chanpos - 1));
+ byte1 &= ~(1 << (chan->chanpos + 3));
+ if (stack.p.data & 1) byte1 |= (1 << (chan->chanpos - 1));
+ if (stack.p.data & 2) byte1 |= (1 << (chan->chanpos + 3));
+ __pciradio_setcreg(rad,0xe,byte1);
+ break;
+ case ZT_RADPAR_REMMODE:
+ rad->remmode[chan->chanpos - 1] = stack.p.data;
+ break;
+ case ZT_RADPAR_REMCOMMAND:
+ /* if no remote mode, return an error */
+ if (rad->remmode[chan->chanpos - 1] == ZT_RADPAR_REM_NONE)
+ {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ i = 0;
+ if (rad->remmode[chan->chanpos - 1] == ZT_RADPAR_REM_RBI1)
+ {
+ /* set UIOA and UIOB for output */
+ byte1 = __pciradio_getcreg(rad,0xe);
+ mask = (1 << (chan->chanpos - 1)) |
+ (1 << (chan->chanpos + 3));
+ byte2 = byte1 & (~mask);
+ i = (byte2 != byte1);
+ __pciradio_setcreg(rad,0xe,byte2);
+ byte1 = __pciradio_getcreg(rad,8);
+ mask = 1 << (chan->chanpos - 1);
+ byte2 = byte1 | mask;
+ i = (byte2 != byte1);
+ __pciradio_setcreg(rad,8,byte2);
+ spin_unlock_irqrestore(&rad->lock,flags);
+ if (i || (jiffies < rad->lastremcmd + 10))
+ interruptible_sleep_on_timeout(&mywait,10);
+ rad->lastremcmd = jiffies;
+ rbi_out(rad,chan->chanpos - 1,(unsigned char *)&stack.p.data);
+ spin_lock_irqsave(&rad->lock,flags);
+ break;
+ }
+ spin_unlock_irqrestore(&rad->lock,flags);
+ for(;;)
+ {
+ int x;
+
+ spin_lock_irqsave(&rad->lock,flags);
+ x = rad->remote_locked || (__pciradio_getcreg(rad,0xc) & 2);
+ if (!x) rad->remote_locked = 1;
+ spin_unlock_irqrestore(&rad->lock,flags);
+ if (x) interruptible_sleep_on_timeout(&mywait,2);
+ else break;
+ }
+ spin_lock_irqsave(&rad->lock,flags);
+ /* set UIOA for input and UIOB for output */
+ byte1 = __pciradio_getcreg(rad,0xe);
+ mask = 1 << (chan->chanpos + 3); /* B an output */
+ byte2 = byte1 & (~mask);
+ byte2 |= 1 << (chan->chanpos - 1); /* A in input */
+ __pciradio_setcreg(rad,0xe,byte2);
+ byte1 = __pciradio_getcreg(rad,8);
+ byte2 = byte1 | mask;
+ byte2 |= 1 << (chan->chanpos - 1);
+ byte2 |= 1 << (chan->chanpos + 3);
+ __pciradio_setcreg(rad,8,byte2);
+ spin_unlock_irqrestore(&rad->lock,flags);
+ if (byte1 != byte2)
+ interruptible_sleep_on_timeout(&mywait,3);
+ while (jiffies < rad->lastremcmd + 10)
+ interruptible_sleep_on_timeout(&mywait,10);
+ rad->lastremcmd = jiffies;
+ for(;;)
+ {
+ if (!(__pciradio_getcreg(rad,0xc) & 2)) break;
+ interruptible_sleep_on_timeout(&mywait,2);
+ }
+ spin_lock_irqsave(&rad->lock,flags);
+ /* enable and address async serializer */
+ __pciradio_setcreg(rad,0xf,rad->pfsave | ((chan->chanpos - 1) << 4) | 0x80);
+ /* copy tx buffer */
+ memcpy(rad->txbuf,stack.p.buf,stack.p.index);
+ rad->txlen = stack.p.index;
+ rad->txindex = 0;
+ rad->rxindex = 0;
+ rad->srxtimer = 0;
+ memset(stack.p.buf,0,SERIAL_BUFLEN);
+ stack.p.index = 0;
+ if (stack.p.data) for(;;)
+ {
+ rad->rxbuf[rad->rxindex] = 0;
+ if ((rad->rxindex < stack.p.data) &&
+ (rad->srxtimer < SRX_TIMEOUT) &&
+ ((rad->remmode[chan->chanpos - 1] == ZT_RADPAR_REM_SERIAL) ||
+ (!strchr((char *)rad->rxbuf,'\r'))))
+ {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ interruptible_sleep_on_timeout(&mywait,2);
+ spin_lock_irqsave(&rad->lock,flags);
+ continue;
+ }
+ memset(stack.p.buf,0,SERIAL_BUFLEN);
+ if (stack.p.data && (rad->rxindex > stack.p.data))
+ rad->rxindex = stack.p.data;
+ if (rad->rxindex)
+ memcpy(stack.p.buf,rad->rxbuf,rad->rxindex);
+ stack.p.index = rad->rxindex;
+ break;
+ }
+ /* wait for done if in SERIAL_ASCII mode, or if no Rx aftwards */
+ if ((rad->remmode[chan->chanpos - 1] == ZT_RADPAR_REM_SERIAL_ASCII) ||
+ (!stack.p.data))
+ {
+ /* wait for TX to be done if not already */
+ while(rad->txlen && (rad->txindex < rad->txlen))
+ {
+ spin_unlock_irqrestore(&rad->lock,flags);
+ interruptible_sleep_on_timeout(&mywait,2);
+ spin_lock_irqsave(&rad->lock,flags);
+ }
+ /* disable and un-address async serializer */
+ __pciradio_setcreg(rad,0xf,rad->pfsave);
+ }
+ rad->remote_locked = 0;
+ spin_unlock_irqrestore(&rad->lock,flags);
+ if (rad->remmode[chan->chanpos - 1] == ZT_RADPAR_REM_SERIAL_ASCII)
+ interruptible_sleep_on_timeout(&mywait,100);
+ if (copy_to_user((struct zt_radio_stat *)data,&stack.p,sizeof(struct zt_radio_param))) return -EFAULT;
+ return 0;
+ default:
+ spin_unlock_irqrestore(&rad->lock,flags);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&rad->lock,flags);
+ break;
+ case ZT_RADIO_GETSTAT:
+ spin_lock_irqsave(&rad->lock,flags);
+ /* start with clean object */
+ memset(&stack.s,0,sizeof(struct zt_radio_stat));
+ /* if we have rx */
+ if (rad->gotrx[chan->chanpos - 1])
+ {
+ stack.s.radstat |= ZT_RADSTAT_RX;
+ if (rad->rxcode[chan->chanpos - 1][0])
+ stack.s.ctcode_rx =
+ dcstable[rad->rxcode[chan->chanpos - 1][0]].code | 0x8000;
+ else {
+ stack.s.ctcode_rx =
+ cttable_rx[rad->rxcode[chan->chanpos - 1][rad->present_code[chan->chanpos - 1]]].code;
+ stack.s.ctclass =
+ rad->rxclass[chan->chanpos - 1][rad->present_code[chan->chanpos - 1]];
+ }
+ }
+ /* if we have tx */
+ if (rad->gottx[chan->chanpos - 1])
+ {
+ unsigned short x,myindex;
+
+ stack.s.radstat |= ZT_RADSTAT_TX;
+ stack.s.radstat |= ZT_RADSTAT_TX;
+
+ myindex = 0;
+ if ((!rad->rxcode[chan->chanpos - 1][0])
+ && (rad->present_code[chan->chanpos - 1]))
+ myindex = rad->present_code[chan->chanpos - 1];
+ x = rad->txcode[chan->chanpos - 1][myindex];
+ if (x & 0x8000)
+ stack.s.ctcode_tx = dcstable[x & 0x7fff].code | 0x8000;
+ else
+ stack.s.ctcode_tx = cttable_tx[x].code;
+
+ }
+
+ if (rad->radmode[chan->chanpos - 1] & RADMODE_IGNORECOR)
+ stack.s.radstat |= ZT_RADSTAT_IGNCOR;
+ if (rad->radmode[chan->chanpos - 1] & RADMODE_IGNORECT)
+ stack.s.radstat |= ZT_RADSTAT_IGNCT;
+ if (rad->radmode[chan->chanpos - 1] & RADMODE_NOENCODE)
+ stack.s.radstat |= ZT_RADSTAT_NOENCODE;
+ if (rad->gotcor[chan->chanpos - 1])
+ stack.s.radstat |= ZT_RADSTAT_RXCOR;
+ if (rad->gotct[chan->chanpos - 1])
+ stack.s.radstat |= ZT_RADSTAT_RXCT;
+ spin_unlock_irqrestore(&rad->lock,flags);
+ if (copy_to_user((struct zt_radio_stat *)data,&stack.s,sizeof(struct zt_radio_stat))) return -EFAULT;
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+
+}
+
+static int pciradio_open(struct zt_chan *chan)
+{
+ struct pciradio *rad = chan->pvt;
+ if (rad->dead)
+ return -ENODEV;
+ rad->usecount++;
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static int pciradio_watchdog(struct zt_span *span, int event)
+{
+ printk("PCI RADIO: Restarting DMA\n");
+ pciradio_restart_dma(span->pvt);
+ return 0;
+}
+
+static int pciradio_close(struct zt_chan *chan)
+{
+ struct pciradio *rad = chan->pvt;
+ rad->usecount--;
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ /* If we're dead, release us now */
+ if (!rad->usecount && rad->dead)
+ pciradio_release(rad);
+ return 0;
+}
+
+static int pciradio_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
+{
+ struct pciradio *rad = chan->pvt;
+
+ switch(txsig) {
+ case ZT_TXSIG_START:
+ case ZT_TXSIG_OFFHOOK:
+ rad->gottx[chan->chanpos - 1] = 1;
+ break;
+ case ZT_TXSIG_ONHOOK:
+ rad->gottx[chan->chanpos - 1] = 0;
+ break;
+ default:
+ printk("pciradio: Can't set tx state to %d\n", txsig);
+ break;
+ }
+ if (debug)
+ printk("pciradio: Setting Radio hook state to %d on chan %d\n", txsig, chan->chanpos);
+ return 0;
+}
+
+static int pciradio_initialize(struct pciradio *rad)
+{
+ int x;
+
+ /* Zapata stuff */
+ sprintf(rad->span.name, "PCIRADIO/%d", rad->pos);
+ sprintf(rad->span.desc, "Board %d", rad->pos + 1);
+ rad->span.deflaw = ZT_LAW_MULAW;
+ for (x=0;x<rad->nchans;x++) {
+ sprintf(rad->chans[x].name, "PCIRADIO/%d/%d", rad->pos, x);
+ rad->chans[x].sigcap = ZT_SIG_SF | ZT_SIG_EM;
+ rad->chans[x].chanpos = x+1;
+ rad->chans[x].pvt = rad;
+ rad->debouncetime[x] = RAD_GOTRX_DEBOUNCE_TIME;
+ rad->ctcssacquiretime[x] = RAD_CTCSS_ACQUIRE_TIME;
+ rad->ctcsstalkofftime[x] = RAD_CTCSS_TALKOFF_TIME;
+ }
+ rad->span.chans = rad->chans;
+ rad->span.channels = rad->nchans;
+ rad->span.hooksig = pciradio_hooksig;
+ rad->span.open = pciradio_open;
+ rad->span.close = pciradio_close;
+ rad->span.flags = ZT_FLAG_RBS;
+ rad->span.ioctl = pciradio_ioctl;
+ rad->span.watchdog = pciradio_watchdog;
+ init_waitqueue_head(&rad->span.maintq);
+
+ rad->span.pvt = rad;
+ if (zt_register(&rad->span, 0)) {
+ printk("Unable to register span with zaptel\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void wait_just_a_bit(int foo)
+{
+ long newjiffies;
+ newjiffies = jiffies + foo;
+ while(jiffies < newjiffies);
+}
+
+static int pciradio_hardware_init(struct pciradio *rad)
+{
+unsigned char byte1,byte2;
+int x;
+unsigned long endjif;
+
+ /* Signal Reset */
+ outb(0x01, rad->ioaddr + RAD_CNTL);
+
+ /* Reset PCI Interface chip and registers (and serial) */
+ outb(0x06, rad->ioaddr + RAD_CNTL);
+ /* Setup our proper outputs */
+ rad->ios = 0xfe;
+ outb(rad->ios, rad->ioaddr + RAD_AUXD);
+
+ /* Set all to outputs except AUX 3 & 4, which are inputs */
+ outb(0x67, rad->ioaddr + RAD_AUXC);
+
+ /* Select alternate function for AUX0 */
+ outb(0x4, rad->ioaddr + RAD_AUXFUNC);
+
+ /* Wait 1/4 of a sec */
+ wait_just_a_bit(HZ/4);
+
+ /* attempt to load the Xilinx Chip */
+ /* De-assert CS+Write */
+ rad->ios |= XCS;
+ outb(rad->ios, rad->ioaddr + RAD_AUXD);
+ /* Assert PGM */
+ rad->ios &= ~XPGM;
+ outb(rad->ios, rad->ioaddr + RAD_AUXD);
+ /* wait for INIT and DONE to go low */
+ endjif = jiffies + 10;
+ while (inb(rad->ioaddr + RAD_AUXR) & (XINIT | XDONE) && (jiffies <= endjif));
+ if (endjif < jiffies) {
+ printk("Timeout waiting for INIT and DONE to go low\n");
+ return -1;
+ }
+ if (debug) printk("fwload: Init and done gone to low\n");
+ /* De-assert PGM */
+ rad->ios |= XPGM;
+ outb(rad->ios, rad->ioaddr + RAD_AUXD);
+ /* wait for INIT to go high (clearing done */
+ endjif = jiffies + 10;
+ while (!(inb(rad->ioaddr + RAD_AUXR) & XINIT) && (jiffies <= endjif));
+ if (endjif < jiffies) {
+ printk("Timeout waiting for INIT to go high\n");
+ return -1;
+ }
+ if (debug) printk("fwload: Init went high (clearing done)\nNow loading...\n");
+ /* Assert CS+Write */
+ rad->ios &= ~XCS;
+ outb(rad->ios, rad->ioaddr + RAD_AUXD);
+ for (x = 0; x < sizeof(radfw); x++)
+ {
+ /* write the byte */
+ outb(radfw[x],rad->ioaddr + RAD_REGBASE);
+ /* if DONE signal, we're done, exit */
+ if (inb(rad->ioaddr + RAD_AUXR) & XDONE) break;
+ /* if INIT drops, we're screwed, exit */
+ if (!(inb(rad->ioaddr + RAD_AUXR) & XINIT)) break;
+ }
+ if (debug) printk("fwload: Transferred %d bytes into chip\n",x);
+ /* Wait for FIFO to clear */
+ endjif = jiffies + 2;
+ while (jiffies < endjif); /* wait */
+ printk("Transfered %d bytes into chip\n",x);
+ /* De-assert CS+Write */
+ rad->ios |= XCS;
+ outb(rad->ios, rad->ioaddr + RAD_AUXD);
+ if (debug) printk("fwload: Loading done!\n");
+ /* Wait for FIFO to clear */
+ endjif = jiffies + 2;
+ while (jiffies < endjif); /* wait */
+ if (!(inb(rad->ioaddr + RAD_AUXR) & XINIT))
+ {
+ printk("Drove Init low!! CRC Error!!!\n");
+ return -1;
+ }
+ if (!(inb(rad->ioaddr + RAD_AUXR) & XDONE))
+ {
+ printk("Did not get DONE signal. Short file maybe??\n");
+ return -1;
+ }
+ wait_just_a_bit(2);
+ /* get the thingy started */
+ outb(0,rad->ioaddr + RAD_REGBASE);
+ outb(0,rad->ioaddr + RAD_REGBASE);
+ printk("Xilinx Chip successfully loaded, configured and started!!\n");
+
+ wait_just_a_bit(HZ/4);
+
+
+ /* Back to normal, with automatic DMA wrap around */
+ outb(0x30 | 0x01, rad->ioaddr + RAD_CNTL);
+
+ /* Configure serial port for MSB->LSB operation */
+ outb(0xc1, rad->ioaddr + RAD_SERCTL); /* DEBUG set double dlck to 0 SR */
+
+ rad->pasave = 0;
+ __pciradio_setcreg(rad,0xa,rad->pasave);
+
+ __pciradio_setcreg(rad,0xf,rad->pfsave);
+ __pciradio_setcreg(rad,8,0xff);
+ __pciradio_setcreg(rad,0xe,0xff);
+ __pciradio_setcreg(rad,9,0);
+ rad->pfsave = 0;
+
+ /* Delay FSC by 0 so it's properly aligned */
+ outb(/* 1 */ 0, rad->ioaddr + RAD_FSCDELAY);
+
+ /* Setup DMA Addresses */
+ outl(rad->writedma, rad->ioaddr + RAD_DMAWS); /* Write start */
+ outl(rad->writedma + ZT_CHUNKSIZE * 4 - 4, rad->ioaddr + RAD_DMAWI); /* Middle (interrupt) */
+ outl(rad->writedma + ZT_CHUNKSIZE * 8 - 4, rad->ioaddr + RAD_DMAWE); /* End */
+
+ outl(rad->readdma, rad->ioaddr + RAD_DMARS); /* Read start */
+ outl(rad->readdma + ZT_CHUNKSIZE * 4 - 4, rad->ioaddr + RAD_DMARI); /* Middle (interrupt) */
+ outl(rad->readdma + ZT_CHUNKSIZE * 8 - 4, rad->ioaddr + RAD_DMARE); /* End */
+
+ /* Clear interrupts */
+ outb(0xff, rad->ioaddr + RAD_INTSTAT);
+
+ /* Wait 1/4 of a second more */
+ wait_just_a_bit(HZ/4);
+
+ for(x = 0; x < rad->nchans; x++)
+ {
+ mx828_command_wait(rad,x, MX828_GEN_RESET, &byte1, &byte2 );
+ byte1 = 0x3f;
+ byte2 = 0x3f;
+ mx828_command_wait(rad,x, MX828_AUD_CTRL, &byte1, &byte2 );
+ byte1 = 0;
+ mx828_command_wait(rad,x, MX828_SAUDIO_SETUP, &byte1, &byte2 );
+ byte1 = 0;
+ mx828_command_wait(rad,x, MX828_SAUDIO_CTRL, &byte1, &byte2 );
+ byte1 = 0xc8; /* default COR thresh is 2 */
+ mx828_command_wait(rad,x, MX828_GEN_CTRL, &byte1, &byte2);
+ rad->corthresh[x] = 2;
+ }
+ /* Wait 1/4 of a sec */
+ wait_just_a_bit(HZ/4);
+
+ return 0;
+}
+
+static void pciradio_enable_interrupts(struct pciradio *rad)
+{
+ /* Enable interrupts (we care about all of them) */
+ outb(0x3f, rad->ioaddr + RAD_MASK0);
+ /* No external interrupts */
+ outb(0x00, rad->ioaddr + RAD_MASK1);
+}
+
+static void pciradio_restart_dma(struct pciradio *rad)
+{
+ /* Reset Master and serial */
+ outb(0x31, rad->ioaddr + RAD_CNTL);
+ outb(0x01, rad->ioaddr + RAD_OPER);
+}
+
+static void pciradio_start_dma(struct pciradio *rad)
+{
+ /* Reset Master and serial */
+ outb(0x3f, rad->ioaddr + RAD_CNTL);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ outb(0x31, rad->ioaddr + RAD_CNTL);
+ outb(0x01, rad->ioaddr + RAD_OPER);
+}
+
+static void pciradio_stop_dma(struct pciradio *rad)
+{
+ outb(0x00, rad->ioaddr + RAD_OPER);
+}
+
+static void pciradio_reset_serial(struct pciradio *rad)
+{
+ /* Reset serial */
+ outb(0x3f, rad->ioaddr + RAD_CNTL);
+}
+
+static void pciradio_disable_interrupts(struct pciradio *rad)
+{
+ outb(0x00, rad->ioaddr + RAD_MASK0);
+ outb(0x00, rad->ioaddr + RAD_MASK1);
+}
+
+static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int res;
+ struct pciradio *rad;
+ int x;
+ static int initd_ifaces=0;
+
+ if(initd_ifaces){
+ memset((void *)ifaces,0,(sizeof(struct pciradio *))*RAD_MAX_IFACES);
+ initd_ifaces=1;
+ }
+ for (x=0;x<RAD_MAX_IFACES;x++)
+ if (!ifaces[x]) break;
+ if (x >= RAD_MAX_IFACES) {
+ printk("Too many interfaces\n");
+ return -EIO;
+ }
+
+ if (pci_enable_device(pdev)) {
+ res = -EIO;
+ } else {
+ rad = kmalloc(sizeof(struct pciradio), GFP_KERNEL);
+ if (rad) {
+ int i;
+
+ ifaces[x] = rad;
+ memset(rad, 0, sizeof(struct pciradio));
+ spin_lock_init(&rad->lock);
+ rad->nchans = 4;
+ rad->ioaddr = pci_resource_start(pdev, 0);
+ rad->dev = pdev;
+ rad->pos = x;
+ for(i = 0; i < rad->nchans; i++) rad->lasttx[x] = rad->gotrx1[i] = -1;
+ /* Keep track of whether we need to free the region */
+ if (request_region(rad->ioaddr, 0xff, "pciradio"))
+ rad->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 */
+ rad->writechunk = pci_alloc_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, &rad->writedma);
+ if (!rad->writechunk) {
+ printk("pciradio: Unable to allocate DMA-able memory\n");
+ if (rad->freeregion)
+ release_region(rad->ioaddr, 0xff);
+ return -ENOMEM;
+ }
+
+ rad->readchunk = rad->writechunk + ZT_MAX_CHUNKSIZE * 2; /* in doublewords */
+ rad->readdma = rad->writedma + ZT_MAX_CHUNKSIZE * 8; /* in bytes */
+
+ if (pciradio_initialize(rad)) {
+ printk("pciradio: Unable to intialize\n");
+ /* Set Reset Low */
+ x=inb(rad->ioaddr + RAD_CNTL);
+ outb((~0x1)&x, rad->ioaddr + RAD_CNTL);
+ outb(x, rad->ioaddr + RAD_CNTL);
+ __pciradio_setcreg(rad,8,0xff);
+ __pciradio_setcreg(rad,0xe,0xff);
+ /* Free Resources */
+ free_irq(pdev->irq, rad);
+ if (rad->freeregion)
+ release_region(rad->ioaddr, 0xff);
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)rad->writechunk, rad->writedma);
+ kfree(rad);
+ return -EIO;
+ }
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, rad);
+
+ if (pciradio_hardware_init(rad)) {
+ unsigned char x;
+
+ /* Set Reset Low */
+ x=inb(rad->ioaddr + RAD_CNTL);
+ outb((~0x1)&x, rad->ioaddr + RAD_CNTL);
+ outb(x, rad->ioaddr + RAD_CNTL);
+ __pciradio_setcreg(rad,8,0xff);
+ __pciradio_setcreg(rad,0xe,0xff);
+ /* Free Resources */
+ free_irq(pdev->irq, rad);
+ if (rad->freeregion)
+ release_region(rad->ioaddr, 0xff);
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)rad->writechunk, rad->writedma);
+ pci_set_drvdata(pdev, NULL);
+ zt_unregister(&rad->span);
+ kfree(rad);
+ return -EIO;
+
+ }
+
+ if (request_irq(pdev->irq, pciradio_interrupt, ZAP_IRQ_SHARED, "pciradio", rad)) {
+ printk("pciradio: Unable to request IRQ %d\n", pdev->irq);
+ if (rad->freeregion)
+ release_region(rad->ioaddr, 0xff);
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)rad->writechunk, rad->writedma);
+ pci_set_drvdata(pdev, NULL);
+ kfree(rad);
+ return -EIO;
+ }
+
+ /* Enable interrupts */
+ pciradio_enable_interrupts(rad);
+ /* Initialize Write/Buffers to all blank data */
+ memset((void *)rad->writechunk,0,ZT_MAX_CHUNKSIZE * 2 * 2 * 4);
+
+ /* Start DMA */
+ pciradio_start_dma(rad);
+ printk("Found a PCI Radio Card\n");
+ res = 0;
+ } else
+ res = -ENOMEM;
+ }
+ return res;
+}
+
+static void pciradio_release(struct pciradio *rad)
+{
+ zt_unregister(&rad->span);
+ if (rad->freeregion)
+ release_region(rad->ioaddr, 0xff);
+ kfree(rad);
+ printk("Freed a PCI RADIO card\n");
+}
+
+static void __devexit pciradio_remove_one(struct pci_dev *pdev)
+{
+ struct pciradio *rad = pci_get_drvdata(pdev);
+ if (rad) {
+
+ /* Stop any DMA */
+ pciradio_stop_dma(rad);
+ pciradio_reset_serial(rad);
+
+ /* In case hardware is still there */
+ pciradio_disable_interrupts(rad);
+
+ /* Immediately free resources */
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)rad->writechunk, rad->writedma);
+ free_irq(pdev->irq, rad);
+
+ /* Reset PCI chip and registers */
+ outb(0x3e, rad->ioaddr + RAD_CNTL);
+
+ /* Clear Reset Line */
+ outb(0x3f, rad->ioaddr + RAD_CNTL);
+
+ __pciradio_setcreg(rad,8,0xff);
+ __pciradio_setcreg(rad,0xe,0xff);
+
+ /* Release span, possibly delayed */
+ if (!rad->usecount)
+ pciradio_release(rad);
+ else
+ rad->dead = 1;
+ }
+}
+
+static struct pci_device_id pciradio_pci_tbl[] = {
+ { 0xe159, 0x0001, 0xe16b, PCI_ANY_ID, 0, 0, (unsigned long)"PCIRADIO" },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, pciradio_pci_tbl);
+
+static struct pci_driver pciradio_driver = {
+ name: "pciradio",
+ probe: pciradio_init_one,
+#ifdef LINUX26
+ remove: __devexit_p(pciradio_remove_one),
+#else
+ remove: pciradio_remove_one,
+#endif
+ suspend: NULL,
+ resume: NULL,
+ id_table: pciradio_pci_tbl,
+};
+
+static int __init pciradio_init(void)
+{
+ int res;
+
+ res = zap_pci_module(&pciradio_driver);
+ if (res)
+ return -ENODEV;
+ return 0;
+}
+
+static void __exit pciradio_cleanup(void)
+{
+ pci_unregister_driver(&pciradio_driver);
+}
+
+#ifdef LINUX26
+module_param(debug, int, 0600);
+#else
+MODULE_PARM(debug, "i");
+#endif
+
+MODULE_DESCRIPTION("Zapata Telephony PCI Radio Card Zaptel Driver");
+MODULE_AUTHOR("Jim Dixon <jim@lambdatel.com>");
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(pciradio_init);
+module_exit(pciradio_cleanup);
diff --git a/drivers/dahdi/pciradio.rbt b/drivers/dahdi/pciradio.rbt
new file mode 100644
index 0000000..3cd2517
--- /dev/null
+++ b/drivers/dahdi/pciradio.rbt
@@ -0,0 +1,10531 @@
+Xilinx ASCII Bitstream
+Created by Bitstream E.33
+Design name: pciradio_xilinx.ncd
+Architecture: spartan2
+Part: 2s30vq100
+Date: Sat Mar 12 18:19:05 2005
+Bits: 336768
+11111111111111111111111111111111
+10101010100110010101010101100110
+00110000000000001000000000000001
+00000000000000000000000000000111
+00110000000000010110000000000001
+00000000000000000000000000001000
+00110000000000010010000000000001
+00000000100000000011111100101101
+00110000000000001100000000000001
+00000000000000000000000000000000
+00110000000000001000000000000001
+00000000000000000000000000001001
+00110000000000000010000000000001
+00000000000000000000000000000000
+00110000000000001000000000000001
+00000000000000000000000000000001
+00110000000000000100000000000000
+01010000000000000010010001100011
+00000000000100100010000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000001000000000010010000000
+00000000000000000000000000000000
+00000000000100100010000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000010010000000
+00000000000000000000000000000000
+00010000000000100000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000000
+00000000000000000000000000000000
+00000000000000100000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000000
+00000000000000000000000000000000
+00000000000100100000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000010010000000
+00000000000000000000000000000000
+00010000000100100000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000001000000000010010000000
+00000000000000000000000000000000
+00010000000100100000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000010000000000
+00000000000000000000000000000000
+11101111000100100000000000001110
+00000000000000111000000000000001
+11100000000000000111100000000000
+00011110000000000000011110000000
+00000001111000000000000001111000
+00000000000111100000000000000101
+00000000000000010100000000000000
+01010000000111111100010000000000
+00000000000000000000000000000000
+11000000000001011111101000000001
+11101111001110000011011111110000
+00001100111100000101001100111100
+00000000111111011000000000110111
+11000100000011001101000000000011
+00110000010000001100111000000000
+00110011100000000000110101000000
+00000011001100000000000001110000
+00000000000000000000000000000000
+10000000000100001110101000000000
+11101111010000000010001011000000
+01011101111101000000001000111101
+00010000101110011000001000100011
+11010000100010101000000000000010
+00001000000000001000100010000000
+00100010100101000000100010101000
+00000011001000000000010000110000
+00000000000000000000000000000000
+10001000000001011100010000010001
+10100011001000000010011011001000
+00001000001101000000101000001101
+00000000101110010000000000100100
+11011000000010001001000000000010
+00001000000000001000000100000000
+00100010100000000001100100010000
+01000010011000100000000101110000
+00000000000000000000000000000000
+11000000000101011010000000000000
+10101011000000000010001011000100
+00011001101100000000001000101100
+00000000101110011000000000100010
+11000000000010101001000000000010
+00101000001000001000100000001000
+00100010101100000010100010110000
+10000010001100000000010001100000
+00000000000000000000000000000000
+00000000000101011110101110010000
+11101011000000100011010011101000
+00001100101100000000001100101100
+00000000111100110000000000110110
+11000000010011000001100000001011
+00100111000000001100101001000000
+00110010001000000000110110000100
+00000011010000000000010001110000
+00000000000000000000000000000000
+11100000000000011011101100000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111110
+11000000000011111100000100000011
+11111000100000001111101000100000
+00111110110000000010111101000000
+00001011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010010100000000
+11110011000001010011111011010001
+00001101001100100000001111101100
+00000000110010010001010000110110
+11000000000011001001000100000011
+00101101000000001110000101100000
+00111010000100000000110110101100
+00000011000100000000010000100000
+00000000000000000000000000000000
+11001000000001010010000000000100
+10111111000000000010111011000000
+00001000111101000000001011111101
+01000010100010011000010100101111
+11000001000010001001000000001010
+10101000000000001000101001000000
+00100000110101000000100010100000
+00000010101100100000000001000000
+00000000000000000000000000000000
+11100000000001010100100000000000
+10110011000000000010110011000000
+01001000001111010001001001001100
+00000000100000010100100000101110
+11000000100010000011110010000010
+00101000000000001010001001000001
+00101000100000000000100000000000
+00000010101110000000000001010000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10110111100000000010111110100000
+00101000011110000000001011001110
+00000000100001011000000000101101
+11100000010010000010100100000010
+10011110000010001000010110000010
+00100001111000000000100001101000
+00000010100110000000000001000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11110011000000000011110011000000
+00001100001100000000001101001100
+11000000110000110000000000110100
+11000000000011000011000000000011
+00001000000100001110001100000000
+10111000100000000010110000010000
+00000011000100100000001000000000
+00000000000000000000000000000000
+01000000010011011011110000000000
+11111111000000000011110111000000
+01001110111101010000001111111100
+01000000111111110000000000110111
+11000010000011111111000000000011
+11111100010000001111110100010000
+00111111110000000000111011110001
+00000011010100000000011001100000
+00000000000000000000000000000000
+10101000000101011110100100000000
+11111011001000000011110011000000
+00011100101101000000101100101100
+10000001111110110010100000111110
+11000000001011001001000000001011
+00101100000000001100101000000001
+00110010100000000000000010010000
+00000011111010100000000001010000
+00000000000000000000000000000000
+01001000000110011001110100100000
+10110111010010010010110101000000
+00101100001101100000001000011100
+00100101101101110100000000101111
+11001100000010000100000000000010
+00001100000010001000001100000000
+10100001100000000000100000010000
+00000010100100100000010001100000
+00000000000000000000000000000000
+11000000000000001001111010000000
+10110111101000000010111111100000
+00001000011110100001001000011110
+01001000100101111010001000100101
+11101000000010000101100001100010
+00011110000000001000011110000000
+00100001101000000000101001111000
+00000010001100000000000000100000
+00000000000000000000000000000000
+01001000000001001100110000010000
+10110011000000000010111011110000
+00001000001100000000001000001100
+00000000101100110000000000101110
+11000000000010000001100000100010
+00001101001000001000001110010000
+00100010101001000010101000110010
+00000010100100100000010000110000
+00000000000000000000000000000000
+11101000000101011110100000000000
+11111010000000000011111110000000
+00011100101000000000011100101000
+00000000101110100000001000111110
+10000000000011001110101000000011
+00111000000000101100111000000001
+10110011100000000000111011100010
+00101011101110100000010001100000
+00000000000000000000000000000000
+01001000000000011010000000000000
+11111000000000010011111000001100
+01011110100000000000011111000000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11000000000000001111100000000000
+00111110001000000000010110000000
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001010010000000000
+11110001000000000001001001000000
+00000100100100000010001100100101
+00011000110010010010000000111110
+01000000000011001001000000000010
+00100100000000000100100100000000
+00110010010100000000110000010000
+00000011000000100000010000110000
+00000000000000000000000000000000
+10000000000001000110111001000000
+10111001000000000010001001000000
+00001000100100000000001010100101
+00000010100010111100000100101110
+01000001010010000001110110001010
+00100100000001001000000101100000
+10101010011100000000100010010000
+00000010001000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000100000
+10111001000000000010101001000000
+00101000000100000000001000100101
+00000000100010010000011000101110
+01000001100010001001000000000010
+10100100000000001000100100000000
+00100010010000000010100010011000
+00000010000001100000000001000000
+00000000000000000000000000000000
+00001000000101001000010000000001
+10110001001010001010100001000000
+00001000000100101000001010000100
+10101000000000110000000000101100
+01001010000010001001001000000010
+10000100100000101000000100100000
+00101000110010000000100000010010
+00011000000000100000000100000000
+00000000000000000000000000000000
+10111000000011011110000000000000
+11111000001000000011101000000000
+00001100100001110000001100100001
+11000000010010000000000000011110
+00001000000011000000010100010011
+10100000000000001100100000000001
+00110000000101000000110010000000
+00000011001011100000001101010000
+00000000000000000000000000000000
+10011000000101011110010000000000
+11111001001010000011011101001011
+00101111100100000000001111100100
+00000000111110010000000000111110
+01001010001011111101000100000011
+01110100111000001011110100010000
+00011111010001000000111111010001
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000000101011110010000000001
+11111001001010000011111001000100
+00001110110100000000001100110100
+11100000110010110000000000111110
+01010000000011111001010000000011
+00100100000000001100100100000001
+00110011010100000000100011010000
+10000001001001100000000001110000
+00000000000000000000000000000000
+00111000000110000110000000000101
+10110000001000000010111000001000
+00001000100001001001001000100001
+00000010110010000000000000101110
+00101000000010111000000000000010
+10100000101010001000101000000000
+00110110000000000000100010000100
+00000010000011100000010000110000
+00000000000000000000000000000000
+00001000000001010100110000001000
+10110001001011000010111001001000
+00001010000100110000101000000100
+10010010100000010000000000101100
+01010001000010111001010000000010
+00000101000000001000000101000000
+00100000010100000011101000010000
+00000110000000100000000101110000
+00000000000000000000000000000000
+00011000010001011010010010000000
+10111001000000000000111001000000
+00000000100100000000001000100100
+00010000100010010000000000101110
+01000000000010111001010000000010
+10100100100000001000100100000000
+00100100010000000100101010010100
+00000010000001100000010001100000
+00000000000000000000000000000000
+10100000000101011110010100100000
+10111001000000010011110001111000
+01000010100100000011001100100100
+00000000110010010000010000111110
+01000000000011110001000000000011
+00100100000000101100000101000000
+00110010010000000000111010011000
+00001010001010000000010001110000
+00000000000000000000000000000000
+00101000000000001010011000100000
+11111001000001000011111001100100
+00001111000100001000011111000100
+00000000111110011100000000111110
+01000000000011111011000000000011
+11000100000010001111101100010010
+00111110010000000000110110010010
+00000011110010100000000001100000
+00000000000000000000000000000000
+00101000000100001010000100000000
+11111000000001010011101000010000
+00001111100000000000001111100000
+00000000111110000000000000110110
+00000000000011111000000000000011
+11100000000000001111100011000000
+10110010000000000000110010000000
+01000011110010100000010000100000
+00000000000000000000000000000000
+00101000000001000010100100001000
+10111010000000000010001010000000
+00001011111001000001001011111000
+00100000100110100101000000101110
+10000001000010111010100000000010
+11101000000000001011101000000000
+00100011101000000000100001100000
+00000010000010100000000001000000
+00000000000000000000000000000000
+00101000000001010100110100000001
+10110011000000001010000011000000
+00001011001111000000001011001100
+00000000101100110000000000100100
+11000000010010110010000001000010
+11001100000000001011001100000100
+00100000111000000010000100010001
+00000010100010100000000001010000
+00000000000000000000000000000000
+00100000000100010001110000000000
+10110111101000100010000111000000
+10001011011100001000001011011000
+00000000100101110000000000101101
+11000000000010110110010000000010
+11011100110000001011001100000000
+00100000110000100000100101010000
+00000010001010000000000001000000
+00000000000000000000000000000000
+00101000000010000001001001000000
+11110111100000010011000111100000
+00011111011110000000001111011110
+00000000111101001000100000110101
+11100000100011110111100000000011
+11011110101000001111011110010010
+00110001011000000000110100011000
+00000011101010100000001000000000
+00000000000000000000000000000000
+00001000000101011010000110010000
+11111011011010000011011011011010
+00011111101100000001001111101000
+00000001110110100110000000111110
+11000000000011111010010000000011
+11101100100000001111101101000000
+00111110000000000110111010010000
+00000011100000100000011001100000
+00000000000000000000000000000000
+01000000010011011111111000000000
+11001111100010000011011111100110
+00000100110110000000000100111110
+01000000110111111000000000111111
+11100000000011001110110000000011
+00111110000000001100111110000000
+00110011111000000000110011011000
+00000011000100000000000001110000
+00000000000000000000000000000000
+10101000000000011001110001000000
+11011111000000000010000111000000
+01001101010100010000001000111000
+00000000110101100000000001101101
+11000000000010000110010000000010
+00011100000010001010011100000000
+00111111110000000000100001010010
+00000010001010100000010001100000
+00000000000000000000000000000000
+00000000000000001011010000000000
+10000111000000000010010111000001
+00001001010100000000001000011100
+00001000100001010000000000101000
+11000000000010000111000000000010
+00011100000000001001011100000000
+00100001110000100000100001010000
+00000010000001100000000000100000
+00000000000000000000000000000000
+01100000000101001100010000000000
+10010011000000000010010011010100
+00001000100100000000101010001000
+00000000100100100000001000101100
+11000000000010000000010000000010
+00001110100000000011001100100000
+00101100101000000010100000011000
+00000010000110000000010000110000
+00000000000000000000000000000000
+10101000000101011010110100000000
+10001111000001000011011111010000
+00001001101000000000001100100100
+00000001110010110000000000111111
+11000000001011001000000100001011
+00111100100010101101101100100000
+00110010111000000010110010011010
+00000010001011100000010001100000
+00000000000000000000000000000000
+10000000000000001110110000100000
+11111011000000000011101011001000
+00101111101000000000001101100000
+00000000111110010000000000111110
+11000000000011111100010001000011
+11001100000000001110101100000000
+00111110110010000000111110010000
+00000011111000000000000000110000
+00000000000000000000000000000000
+00000001000100001111101000000000
+11111111000000000011111111000000
+00001100101000000000001100111110
+01000000110011001000000001111111
+11000000000011111100001000000011
+00101100000000101100111100000000
+00110011010000000000110001011000
+00000011101000000000010000110000
+00000000000000000000000000000000
+10000001010001000110101000011000
+10111011000001000010110011000000
+00001000101011011000001010101111
+10001000101010001000000000101110
+11000000000010010000110000000010
+00101100000000001000001100000000
+00100010000000000010100010011000
+00100011011000000100000000010000
+00000000000000000000000000000000
+10000000000001010010010010000000
+10111011000000000110111011000000
+00001000101000000000001000000100
+00000000100010110001000000101110
+11000000000010111000000000000010
+00101100000010001000101100000000
+00100000110000000000100010010010
+00000010101000000000000001000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110011000000000110011011000000
+00011010000100000000001010000000
+00000100101000000000000000101100
+11000000000010011000000000001010
+00001100000000011000001110000000
+00100000110000000000100000110000
+00000010010000100000000100000000
+00000000000000000000000000000000
+00000000000001010110010000000000
+11111111000000010011110111000000
+00101100101000000000001100100100
+00000000110010010000010000101110
+11000000000011110000000000000011
+00111100000000001100101100000000
+00110010110000000000110010010000
+00000011101000000000001101010000
+00000000000000000000000000000000
+10100000000101011101010000000000
+10111111000001000011111111000000
+01001101110100000000001111110100
+00000000111111000000000000111111
+11000000000011011100000000000011
+11111100000000001111011000000000
+00111111100000000000111101010000
+00000011101010000000011001110000
+00000000000000000000000000000000
+11000000000001011111010000000100
+10101111001100000011001111010000
+10001101110101000000001111111100
+01000000110011110001000000111111
+01100000000011111111000000000011
+00110110000000001111010010000000
+10110011001000000000111011011001
+00000011111100000000000001110000
+00000000000000000000000000000000
+10000000000100001110011000000000
+10001111000100000010001111010000
+00001000101100000000001011011100
+10000000100011110001010000101110
+01100000000010111111010011000010
+00100110000100001011100010000000
+00100000000010001000111000010000
+00000010111000000000010000110000
+00000000000000000000000000000000
+10001000000001011100010000000000
+10100011001000000010000011001101
+00011001000000100000001011001100
+11000000100000110010000100101100
+11000000000110110011001100000010
+10000100000000001011100000000000
+01100000000000100000101000000010
+00000010111000100000000101110000
+00000000000000000000000000000000
+11000000000101011010010000000011
+10100011000000000010001011000000
+00011000101000001000001011101100
+00000000100010110000000000101110
+11000100000010111011000000000010
+10100110000000001011100000000000
+01100010000001000000101010000001
+00000010111100000000010001100000
+00000000000000000000000000000000
+01000000000101011110011000000000
+11101011000001000011001011000000
+00001101100101000001001111101100
+00000000110010110000000000111110
+01100000000011111011000000001011
+10100100000000001111000001100001
+00110010001010000000111010011000
+00000011110100000000010001110000
+00000000000000000000000000000000
+11100000000000011011011001000100
+11011111000000000011111111000000
+00001111111101000100001111111100
+00000000111111110000000000111111
+01000000000011110111000000000011
+01110100000000001111110000000000
+00111111001000000000111111011000
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010011000001000
+11011011000000000011001011000000
+00001100100101000000001111001100
+00000000110010110000000000111110
+11000100000011111011000000000011
+11101100000001001111100001000100
+00110010001000000010110010000000
+00001011000100000000010000100000
+00000000000000000000000000000000
+11001000010001010000010000010000
+10001111000000000010001111000000
+10001010101100000010001011111100
+00000000100011110000000000101110
+11100001000010111111000000000010
+11101101000001001011100000000000
+00100010001100000100100010001000
+00000010001100100000000001000000
+00000000000000000000000000000000
+11100000000001010100010000000000
+10010011000000000010001011000000
+00001000001000000000001011001100
+00000000100000110000000000101100
+01101000000010110011000000000010
+11001100001000001011000100000000
+00100100110000100100100000111000
+01000010011110000000000001010000
+00000000000000000000000000000000
+00100000000000010001011000000000
+10010011100000000010000011100100
+00001010011010000010001011011110
+00001000100001111000000001101101
+11100001010010110111100000000010
+11011110000000001011110111000000
+10100101111000000000100001111000
+00000010010010000000000001000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11010011000000000011000011000000
+00001100000000000100001111001100
+00000000110000110000000000111100
+01000000000001110011000000000011
+11001100000000001111000100000000
+00110100110000000000110000100000
+10000011010100100000001000000000
+00000000000000000000000000000000
+01000000000111011001110001000000
+11101111010000100011111111010001
+10001110111000010000001111111100
+00000000111111110000100000111111
+11010000100011111111000000100011
+11111101000010001111110100000000
+00111011110000000000111111101000
+00000011100100000000011001100000
+00000000000000000000000000000000
+10101000000001011110111000000000
+11001011111000000011001011000100
+00001100101100000000001100101101
+10001000111110110110000000111110
+01010100000011111011110101000111
+00100101000000001111100100000000
+00110010110000000000111110110000
+00000011111010100000000001110000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10001111011000101010001111000000
+10001000111100000000001000011101
+00100000101101110001000100101101
+11001000000010110111001010010110
+00010100100000001011010100000001
+00100001110000000000101101110000
+00000010110100100000010001100000
+00000000000000000000000000000000
+11000000010000001000111000010000
+10000111100000000010000111101001
+00001000010110000100001000011110
+10000000101101111010000000101101
+01100000000010110111100001001010
+00011110010000001011010110000101
+10100001111000010000101101101000
+00000010111100000000000000100000
+00000000000000000000000000000000
+01001000000101000100110000000000
+10000011000000000010000011000000
+00111000001100000000001000001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+00001110000000001011000100000000
+00100000110000000000101110100000
+00000010110100100000010000110000
+00000000000000000000000000000000
+11101000000101011010101010000010
+11001010000000000011001010000000
+00001100111001000000101100101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+00101000000000001111001000000000
+00110010100000000100111110100000
+00000011111110100000010001100000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000100011111000000000
+00001111100000100000001111100000
+00000000111110000000000100111110
+00000000010011111000000001000011
+11100001010000001111100001000000
+00111110000000000000111111000000
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110011100000000
+11111001000000000011111001000000
+00000000100100000000101100100100
+00000000111100010000000000111010
+01000000000011111001000000000011
+11100110000000001111100110000000
+00110010010000000000111110011000
+00000011000000100000010000110000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000001010010111001000000
+00001000100100000000001000100100
+00000000101110010000000000100010
+11000000000010111001000000000010
+11101100000000001011100100011000
+00100010010100001000101110011100
+00000010001000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010110001000000
+00001010000100000000001000100100
+00000000101110010000000000100010
+01000000000010111001000000000010
+11100100010000001011100100000000
+10100011010000000100101111010010
+00000010000001100000000001000000
+00000000000000000000000000000000
+00001000000001000000010010100000
+10110001001010100010110001001011
+00101010000100100000101000000100
+10100000101100010010100000100000
+01100000000010110001001010000010
+11000100000000001001100100000000
+00100001011000000000101101011000
+00001010000000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000010000000
+11111000001000000011111000001000
+00001110100000000010001100100000
+10000000111110000010000000111010
+00000000100011110000001000000011
+11101000000000001111100000000000
+00110010000101000000111111000101
+00000011001011100000001101010000
+00000000000000000000000000000000
+10011000000111011111010000010000
+11111001001010000011111001001010
+00001101110100111000001111100100
+10100000111110010010100010111110
+01000000000011111001001010000011
+11100100000000001111010100000000
+00111110010000000000111110010000
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000010011011111011000010000
+11111001010010000011001001000100
+00001101100100010100001100100100
+00100000110010010100100000110010
+01000000000011111001010010000011
+00100100000000001100010100000000
+00110011010000000000110011010100
+00000011110001100000000001110000
+00000000000000000000000000000000
+00111000000000001110000100000000
+10111000011000000010000000001000
+00001000100000100000101000100001
+10000000100010000110010000100010
+00000000000010111000010001000010
+00100000000000001000100000000000
+00100010000010000000110110000000
+00000010110011100000010000110000
+00000000000000000000000000000000
+00001000000001010100010100000000
+10110001000000000010000001010000
+00011011000101000000001000000100
+00100000100000010010000000100000
+01000000000010110001001000001010
+00101100000001001000000100000000
+01100000110000100000100100010000
+00000010110000100000000101110000
+00000000000000000000000000000000
+00011000000101011010010000001000
+10111001000000000010000001000000
+10000010100101100000001000100100
+00000000100010010000010010100010
+11001000010010111001000000000010
+00100100100000001000100100000000
+00100010010000000000100010010000
+00000010110001100000010001100000
+00000000000000000000000000000000
+10100000000101011110011000000000
+11111001000000000011001001000000
+00001111100100000000001100100100
+00000000110010010000000000110010
+01000000000011111001000000000011
+00000100000000101100100100000000
+00110010010000000010100110010010
+00000011111010000000010001110000
+00000000000000000000000000000000
+00101000000000011010011100000000
+11110001000000011011111001000000
+00001101000100000000001111000100
+00000010111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+10111110010000001000111110010000
+00000011110010100000000001100000
+00000000000000000000000000000000
+00101000000100001010000000001000
+11101000000000000011111000000000
+00001101100001000000001100100000
+00001100110010000000000000111110
+00000000000011110000000000000011
+00100000001000001111100010000000
+00110010001000000000110010000010
+00000011110010100000010000100000
+00000000000000000000000000000000
+00101000010001010010101000100000
+10001010000000100010111010000000
+00000000101000000000101000101000
+00000000100010100000010000101110
+10000000000010111010000000010010
+00101000000010001011011010001000
+00100011100000000110100011100100
+00000010110010100000000001000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10100011000000000010110011000000
+01000010001100000100001000001100
+00000010100010110000000000101100
+11000100000010110011000000000010
+00001100000000001011001000000000
+00100110110000000100100000110000
+00000010110010100000000001010000
+00000000000000000000000000000000
+10100000000000010000111000000000
+10000111000000000010110111000000
+00001010011100100000001000011100
+10000000100001110010010000101101
+01000000000010110111001000000010
+00011100000010001011111100000000
+10100101110000000000100001110000
+00000010111010000000000001000000
+00000000000000000000000000000000
+10101000000000000001111000000000
+11100111101100100011110111101010
+00101110001110110001001100111110
+10000000110001111000000000111101
+10100000010011111111101100000011
+00011110000000001111011010000000
+00110111111000000000110001111000
+00000011111010100000001000000000
+00000000000000000000000000000000
+00001000000101011010110000000000
+11111011011000000011111011110000
+00001100101100110000001111101101
+11010000111110110011110100111110
+01011000000011111011010000011011
+11101001001000001111101100000000
+00111010110000000000111110110000
+00000011110000100000011001100000
+00000000000000000000000000000000
+00000000000011011111111000000000
+11101111100110000011111111100010
+00101100111110000000001111111111
+00010000111111111000000000110111
+11110100000011001111100010000011
+11111010010000001111111110000000
+00111111111000000000111111111000
+00000011000000000000000001110000
+00000000000000000000000000000000
+10101000000000011001110001000000
+11100111000100000010111111000000
+00001000011100000000001011011100
+01000000101101110001000000100001
+11000100001010000111000000000010
+11011000000000001011011100010000
+00101101110000000000101101110000
+00000010001010100000010001100000
+00000000000000000000000000000000
+00000000000000000001110000000000
+10100111000000000110110111100000
+00001000011100000000001011011100
+00000000101101110000000000100011
+10000010000010010111000000000010
+11010100000000001011011100000000
+00101101110000000000101101110000
+00000010000000000000000000100000
+00000000000000000000000000000000
+00100000000101001100110000000001
+10100011000000100010110011000000
+00011000101110010000001011001100
+00000000101100110000000000100000
+11100000000110010011000000000010
+11000000000000001011001100000000
+00101100100000000000101110110100
+00000010000010000000010000110000
+00000000000000000000000000000000
+10101000000101011010110000000000
+11101111000000000011111111000000
+00001100111100000000001111111100
+00001000111111110000000000110110
+11100000000011011111000000000011
+11100100000000001111000100000000
+00101110110000000000111110110000
+00000011001010100000010001100000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000100011111011000000
+00001111101100000000001111101100
+00000000111100110000000000111110
+00010000000011101011000000000011
+11100100000000001111100101000000
+00111110110000000000111110111100
+00000011111000000000000000110000
+00000000000000000000000000000000
+00000001000100001101011100001000
+11001111000000000011110111000000
+00000100111100000010011100111100
+00000000111111110000000000110011
+10000000000011111111000000000011
+11111110000000001111110010000000
+00111011110000000000110011111000
+10000011000000000100010000110000
+00000000000000000000000000000000
+10000001010000000110111000000010
+10001011000000000010111011000000
+00001010101100000000001101101100
+00000000101110110000010000100010
+00010000000010111011000000000010
+11101010000001001011100111000000
+00111010111001010000100010010010
+00000010001000000100000000010000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10001011000000000010111011000000
+00001010101100000000001000101100
+00000000101110110000000000100010
+01100000000110111011000000000010
+11100000100000001011101100101000
+00101000110000000000100010110010
+00000010001000000000000001000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10000011000000000010110011000000
+00001010001100000100101000001100
+00000100101100110000000100100000
+00000000000010010011000000000010
+11000000000000001011001100000000
+00100000010000010000100000110000
+00000010000000100000000100000000
+00000000000000000000000000000000
+00000000000001010110110000000000
+11001111000000000011111111000000
+00001110111100000000001000111100
+00000000111101110000000000110010
+00000000100011111111000000000011
+11100100000000001111100100000000
+01111010110000010000110000100000
+00000011000000000000001101010000
+00000000000000000000000000000000
+10100000000101011111110000000000
+11111111000000000011111111000001
+01001111111100000000001111111100
+00000000111111110000000000111101
+00000000000011111111000000000011
+11110000000000001111110100000000
+00111011000000000000111111000000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011111110001000000
+11001110100000000011011111100000
+10001100111100100000001101111100
+00000000111111110010000000111111
+11000000000011001111000010000011
+00110000000000001100110110000000
+00110011000000000000111111000000
+00001011001100000000000001110000
+00000000000000000000000000000000
+10000000000100001111110100000000
+10001010100000000010001011001010
+00001000101111000000001000111110
+00000000101111110001000100101111
+11000110000011011111011001000010
+00100000000000001000100000000000
+00100010101000010000101110001100
+00000010001000000000010000110000
+00000000000000000000000000000000
+10001000000001011100110001000000
+10101001000000000010011011000000
+00101000001100010000001001001100
+00000000101100110000000000101100
+11000000000010000011000010001010
+00000100000000001000000000000000
+00100000010000000000101100100100
+00000010001000100000000101110000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10101001001000000010001011000000
+00011000101100000100001000101100
+00000000101110110000000000101110
+11000000000010010011000000000010
+00101000000100001000000010000000
+00100010110000000000101110100000
+00000010001100000000010001100000
+00000000000000000000000000000000
+01000000000100011110110000000000
+11101001100000000011010011000110
+00001100001100000100001101101100
+00000000111110110000000000111110
+11000000000011001011000000000011
+00100101000000101100101011000000
+00110010110000000000111110010000
+00000011000100000000010001110000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11011101000001000011111111000001
+10001111101100000000001111101100
+00010000111110110000000000111111
+11000000000011111111000000000011
+11110000000000101111111000000000
+00111111110000000000111111010010
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001000110000000000
+11101001000100000111101011000000
+00001101101100000000001101101100
+01100010110010110000000000110010
+11000000000011001011000000000011
+11001101100000101100101001000000
+10110010110000000000111101111010
+00000011000100000000010000100000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10000001010100000110001011000000
+00001000111101110100001101111110
+00000000100011110000000000100011
+11000000001010001111000000000011
+10101011100000001000101000000000
+10110010110101000000101110110100
+00000010001100100000000001000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10100010100000000010100011000000
+00001001001110000000001000001101
+00000000100000110000000000100010
+11000000000010000011000000000010
+01000001000000001000000010000000
+00100100000000000000101100000000
+00100010001110000000000001010000
+00000000000000000000000000000000
+00100000000000010001111000001001
+10000110100000000010001111100000
+01001001011110000000001001011110
+00000001100001111000000001100001
+11100100000110000111100100000010
+10000010000000001000010011100000
+00100001101000000000101100001000
+00000010000010000000000001000000
+00000000000000000000000000000000
+01001000000010000010110000000000
+11100001000000100010100011000000
+00001101001100000000001000001100
+00000000110000110000000010110010
+11000000000011000011000000000011
+11000101000000001100100001001000
+00110100010000000000111100100000
+00001011000100100000001000000000
+00000000000000000000000000000000
+01000000000111011011111000100000
+11110101000000000011110111000000
+00001110111100001000001111111100
+00000000111111110000000000111111
+11000000000011111111000011000011
+11111100000000001111110000100000
+00111111110000000000111111100000
+00000011110100000000011001100000
+00000000000000000000000000000000
+10101000000001011110111000000000
+11000011100000000011011010000000
+00101100101100000000001111101100
+10000000111110110100000000110010
+11001010000011001011101000001011
+00100100000000001100100000000000
+00110010110000000010110010010100
+10000011111010100000000001110000
+00000000000000000000000000000000
+01001000000100011011110010001000
+10000111000000001010001111000000
+00001000011100100001001011011100
+11000000101100110000100000110101
+11000000000010000111001010000010
+00010100010000101000011000000000
+00100001110000000000100001110000
+00000010110100100000010001100000
+00000000000000000000000000000000
+11000000000000001001111000001001
+10000101100000000010000111100000
+00001000011110000000001011011110
+11000000101101111001000000100001
+11100100000010010011101000000010
+00011110000000001000011010000000
+00100000111000000000101001011000
+00000010111100000000000000100000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10000001111000000010000001110000
+00011000001100000000001011001100
+00001000101100110000000000100100
+11000000001010010011000000000010
+00001100000000001000001011100000
+10100000110100000000101000110101
+00000010110100100000010000110000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11001110110000000011001110000000
+00001100101000000000001111001000
+00000000111110100000000000110010
+10000000000011011010000000000011
+00101001000000001100111011001000
+00110011101000000000111000101000
+00000011111110100000010001100000
+00000000000000000000000000000000
+01001000000000001110000000000010
+11111000000100000011101000001100
+00001111100000000000001111100001
+00000000111110000000001000111100
+00000000000011101000000000000011
+11100000100000001111100001000000
+00111110000011000000010110000000
+10010011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000100000011111001000000
+00101100000100000000001100100110
+00000000110010010000000000110010
+01000000000011001001000000000011
+11101111000000001110100100000100
+00110000010000000000110010110000
+00000011000000100000010000110000
+00000000000000000000000000000000
+10000000000001000111010000000000
+10111001010000000010111001000000
+00001000100100000000101000100101
+00000000110110010000000000101010
+01000000010010101001000000000010
+11000101000010001000000100100100
+00110110010000000110100010010000
+00000010001000000000000000010000
+00000000000000000000000000000000
+00011000000000010010010000000000
+10111001000010000010110001000000
+00001000100100001000001000100100
+01000000100000010000000000100010
+01000000010010001001000001000010
+11100101000000001010100110000000
+00100010010000000010100010010000
+00000010000001100000000001000000
+00000000000000000000000000000000
+00001000000001000000010010000000
+10110001000000000110110001000000
+01001000000100100000001000000100
+10000100100100010010100000101000
+01001010000110100001001011000010
+11000100100000001000100100000000
+00100100010010000000100000010010
+00010010000000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000101000000
+11111000000000000011111000010100
+00001100100000000000001000101000
+00000000110010000111000100110000
+00001001000011001000001000010011
+11100001010000001110000001010000
+00110010000000000000110010000000
+00001011001011100000001101010000
+00000000000000000000000000000000
+10011000000111011110010100000000
+11111101000000000011111101000000
+00001111100100010000001111100100
+01000000111110010000000000111110
+01001010000011111001001010000011
+11000100010000001111111100000000
+00111111010001000000111110010001
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000000001011110010100100000
+11110101000000000011101001010000
+00001100110100101000001111110100
+00100000111110010000000000110010
+01000010000011001001000000000011
+00001101001000001100010100000000
+00110010010000100000110010010000
+10000011110001100000000001110000
+00000000000000000000000000000000
+00111000000100001110000110000000
+10111000000000000010001000000001
+00101000100001000000001110100001
+00000000101110000101000000100010
+00111010000011011000000000001010
+00100001000000101000100000100000
+00100010000100010010100011000100
+00000010110011100000010000110000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001000000000010101001001000
+00001000000100000000001011000100
+00000000101100010010100010100000
+01000000000010000001011010100110
+00000100000001001000000100001000
+01100001011000000000100001010000
+00000010110000100000000101110000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111011000000000010001001000010
+00001000100100000100001011100100
+00000000101110010000000000100000
+01000000000110011001000000000110
+00000101000000001000000100000101
+00100010010000000010100011010000
+00000010110001100000010001100000
+00000000000000000000000000000000
+10100000000101011110010000001000
+11110001010010000011100001110000
+00001100100100000000001111100100
+00000000111110010000000000110010
+01000000000011001001000000000011
+00100110000000001100100110000000
+00110010010100000000110010010000
+00000011111010000000010001110000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11111001110010000011111001101000
+01001111100100000000001110100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11101100100000101111100111000000
+10111110010000000000111110011010
+10000011110010100000000001100000
+00000000000000000000000000000000
+00101000000100001010000000010000
+11111000010000100011001000010000
+00001101100000000000011111100000
+01010000110010000000010000111110
+00000001010011001000000000010011
+11100001000000001110100010000000
+00110000000000000000110011000000
+01000011000010100000010000100000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111110010000000010001010000001
+00001000111011000100001011111001
+00000000100010100000000000101110
+10000000001010001010000000010010
+11101000000000001000111010100000
+00111010100000010000100010100000
+00000010000010100000000001000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000100000010000011000000
+00001001000111011001001011001101
+00101000101010110000000001101100
+11000000000010011011000000100010
+11001101100000001010001110000000
+00100100111000000000100000100000
+00000010000010100000000001010000
+00000000000000000000000000000000
+10100000000000010001110011000000
+10111111000000000010001111001000
+01101000010100000100001011011110
+00000000101001110010000000101101
+11000100101110010111000000000010
+11010000000000001000111100000000
+00101001100100000000100001101000
+00000010001010000000000001000000
+00000000000000000000000000000000
+10101000000010000001111010000000
+11110111100000001011000111110000
+00001101010010000000001011001110
+00000010111001111110000000111111
+11101000000011010111110010100001
+11011010000000001110011110000000
+00110100111000000010110000101000
+00001011001010100000001000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000100011110011000010
+00001111100000000000001111101100
+00000000110110110100001000111110
+11010000010011101011011000000011
+11101000001000001111101100000000
+00111110100000000000111110100000
+00000011110000100000011001100000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11111111100000000011001111100000
+00001100110110000000001111111110
+00000100111111111100000000111111
+11110000000011101111100100011011
+00111110000000001100110010100000
+00110011011000000000110011111000
+00000011110000000000000001110000
+00000000000000000000000000000000
+10101000000100011001110001000000
+11110111001000000011010111001000
+00001000010100010000001111011100
+00000000111101110000000000111101
+11001000000010000111000000000010
+00010000001000101000011100100000
+00100001000000000000100001110000
+00000010111010100000010001100000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000001000010000111000000
+00001000010100000000001011011100
+01000000101101110000000000101101
+11000000010010000011000000000110
+00011100010000001000011100110100
+00100001010000000000101001111000
+10000010110000000000000000100000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10100011000000000010011011010100
+00000000000100000000001010001000
+00000000101000110000000000101000
+11000000001110000011000000000010
+00001011001000001000101110000000
+00100000000000000000101000111000
+00000010110010000000010000110000
+00000000000000000000000000000000
+10101000000101011011110000000000
+10111010000000000011001111010000
+00101100001100000000001011100100
+00000000101111110000000000101111
+11000000000010001111000000000011
+00101111000000101000101101100000
+00110010111000000100111010001000
+00000011111010100000010001100000
+00000000000000000000000000000000
+10000000000000001110110000010000
+11111011000000000011111011001000
+00001111100001000001001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11100100000001001111101100100000
+00111100101000000100100110000000
+00000001111000000000000000110000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111111100000000011001111000000
+00001100111010100000101100011100
+00000000110011110000000000111101
+11000000000011001111000000000011
+11111000000000101100111100000101
+00010010110000000100110011000000
+00000011110000000100010000110000
+00000000000000000000000000000000
+10000001000001000110110000010000
+10110011000000000010001011000000
+00101000100000100000001000101111
+00000000100010110000000100101110
+11000000000010001011000000010010
+11101001001000001000101100000000
+00100010100000000110100010001001
+00000010111000000100000000010000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000100000010001011000000
+10001000101100000000001000101111
+00000000100010110000000000101110
+11000000000010001011000000000010
+11001100000000001000100010000000
+00101010010000000000100010010000
+00000010111000000000000001000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010000011000001
+00001000001000000000001000001100
+00000000100000110000000000101100
+11000000000010000011000000000010
+11000100000000001000000110000000
+00101000000000000000100000010000
+00000010110000100000000100000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111001000000000011000111000000
+00001100101100000000001100101100
+00000010110011110000000000111101
+11000000000111001111000000000011
+11001100000011011100001000000100
+00111010010000000000110010010000
+00000011110000000000001101010000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11110111000000001011111111000000
+00001111111000000000001111111100
+00000100111111110000000100111111
+11000000000011111111000000000011
+11111100000000011111111100000000
+00110111000000000000111111010000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11101101100000000011111100000100
+00001110111100000000001101110110
+00000100111111110110000000110011
+11001100100011001110000100100011
+10110000010100001100110000000000
+10110011000001000100110011010001
+01000011001100000000000001110000
+00000000000000000000000000000000
+10000000000100001100110000000000
+10001001100001000010110011001000
+00001100101111000000001000100110
+00010000101111110001000000100011
+11001100000010000010000000000111
+10100000100000001000100000000000
+00110010100010000000100010010010
+00000010001000000000010000110000
+00000000000000000000000000000000
+10001000000001011110111000000010
+10100011000000000010110011001001
+00001010001100010000001000000100
+00000000101100110010000000100000
+11000000000010010011001000100010
+10000000100000001000000000000000
+00100100000010010000100000010010
+00000010011000100000000101110000
+00000000000000000000000000000000
+11000000000101011010111000000000
+10101011000000000010111000100000
+00001001101000000000000000100100
+00000000101110110000000000000000
+11000000000010011011000000000010
+10100000000000001000100000000000
+00100010100000000000100010010000
+00000010011100000000010001100000
+00000000000000000000000000000000
+01000000000101011100110000000000
+11101001000000000011111001100000
+00001110100101000000101101101110
+00000000111110110000000010110010
+11000000000011011010000000000011
+10100011000000001100100100010000
+10110110010000000010110010100000
+00001011010100000000010001110000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11011111000010000011110111000000
+00001110111101000100001111111110
+10000000111101110000000100111111
+11000000001011101110000000000011
+11010010010001101111100110000000
+10111111110000000000111101100000
+00000011101110000000000001100000
+00000000000000000000000000000000
+01000000000100001010111000000000
+11101001000000010011111011000000
+01001110001000001000101101101100
+00000000111110110001000010110010
+11000000000011001011000000000011
+00100001000000101100000100001000
+00110000010000000000110010101010
+00000011000100000000010000100000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10001011000000010000111001000000
+00001000101000000000001000101100
+00000000101111110101000000100011
+11000000000010001011000000000010
+00100000000000001000100101100010
+00100010110000010000100010100100
+00000010001100100000000001000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10000001000000000010110011000000
+00001010000110000000001010000111
+10010000101100110000010000101000
+11000000000010000010000000100010
+00001100000000001000001000000000
+10100000000000000000100000010000
+01000010001110000000000001010000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10000101100000000010110111100100
+00001000001010000100101010010110
+00100000101100111000000000101001
+11100000101010000110100000000010
+00001110000000001000011010000000
+00100000101000000010100001011000
+00000010000010000000000001000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11100011000001000011110011010000
+01001110001100101000101110001100
+10000000111100110010000000111010
+11000000010001000011000100000111
+00001101100001001100001000100000
+01110000000000000000110010010010
+00001011000100100000001000000000
+00000000000000000000000000000000
+01000000000111011011110000000000
+11111111000000000011111111000000
+10001111111000000000001100111100
+00000000111111110000000000110111
+11000000000011111111000000000011
+11111100000000001111111000000000
+10111111100000000000111111011000
+00000011110100000000011001100000
+00000000000000000000000000000000
+10101000000001011100010000000000
+11001001011000000011111010000000
+00001101000000100000001101100110
+11100000110010110010100010111010
+11100000000011001010000000000011
+11101100000000001100101100000000
+00110110010000000100110010100000
+01000011001010100000000001110000
+00000000000000000000000000000000
+01001000000100011001110000000000
+11010111001010010010111111000000
+00000101011000010000101000010100
+00000000100011110000000010100000
+11011100000010000110000000000010
+11011100000001001010011100000000
+10100001110000000100100001100000
+00000010000100100000010001100000
+00000000000000000000000000000000
+11000000000000001011101000000000
+10000101110100000010110111100000
+00001001011010000000001001111110
+10000010100001111001000000101001
+11101001100010000111100000000010
+10001110000000001010001110000000
+00100001011000000000100001101000
+00000010001100000000000000100000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10010011000000010010110010000000
+00001001001011000000001000001110
+00000000100010110000001010100000
+11000000001010000011000001100010
+11001100000000001010001100000100
+00100000110000000110100000100111
+00001010000100100000010000110000
+00000000000000000000000000000000
+11101000000101011011100000000000
+11001010000000000011111110010000
+00001101101000011000001101101010
+00000000110010100000000010111010
+10000000000011001010000000100011
+10101000000000101110101001000000
+00110010100100000000110011101100
+00001011001110100000010001100000
+00000000000000000000000000000000
+01001000000000001110001100000000
+11111000000000000011111000000010
+00001111000000000000001111100001
+01010000111110000000000000111110
+00000000000011110000000001000011
+11100000000000001011000000001000
+00111110000000100000111101000000
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110010000000010
+11101001001000000011000001000000
+00001100101100000000001100100100
+00000100111110010000000010110010
+01000000000011111001000000000011
+00100100000000001000100100000100
+00110010010000000010110010010000
+00001011000000100000010000110000
+00000000000000000000000000000000
+10000000000001000110010100100000
+10000011111000000010001001000000
+00001000100100110000001000101100
+00000000101110010000000010100010
+01000000000010111001000000000010
+00100100000000001000100100000000
+00100010010100000000100010010100
+00000010001000000000000000010000
+00000000000000000000000000000000
+00011000000001010000011000000000
+10101001000000000010001001000000
+01101000101100000100101000100100
+00000000101110010100000000100010
+01000000100010111001000000000010
+00010100000000001010110100000000
+00100001010000100100100011010000
+11000010000001100000000001000000
+00000000000000000000000000000000
+00001000000001000000010000000010
+10001001000000000010000001001000
+00001000000100100000001000000100
+00000000101100010010100010100000
+01001011000010110001001000001010
+00010100100000101010010100100000
+00100001010010000000100001010010
+00000010000000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11101000000000000011001000000000
+00001100100000000000001100101000
+00000000111110000111000010110010
+00001000000011111000100000000011
+00100010000000001110100011010000
+00110000001101000000110001001101
+00001011001011100000001101010000
+00000000000000000000000000000000
+10011000000111011111010010100000
+11111001000000001011111101001110
+01001111100100010000001111000100
+00000000111110010000000010011110
+01001010000011111001001110000011
+11100100111000001101100100010000
+10111110010001000100111110010001
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000000000011110110100000000
+11001001000000000011111001010000
+00001110110100000000001110100100
+00000000111111010001001010110010
+01001010100010111001000000000011
+00100101000000101100110101000100
+00110010010000000000110010010010
+00001011000001100000000001110000
+00000000000000000000000000000000
+00111000000100001100001000000100
+10001000000000010010111000010100
+00001000100001000000001000100000
+00000100101110000100000010101010
+00011000000010111000010000000010
+00100001010000001000000001000001
+00100010000100000000100011000110
+10000010000011100000010000110000
+00000000000000000000000000000000
+00001000000001011100010010000000
+10000001000000010010110001001000
+00001010000101000000001010000100
+00000000101100010110000010100000
+01000011000010110001011010000010
+00000100100001001010000101100100
+00100001010110100000100101010001
+00000010000000100000000101110000
+00000000000000000000000000000000
+00011000000101011000010101000010
+10001001000000100010111001001000
+01001000100100001000001000100100
+00000100101100010000000010001010
+01000001010010111001010000001010
+00100100000000001010100100000001
+00100010010000000000100111010000
+00000010000001100000010001100000
+00000000000000000000000000000000
+10100000000101011110011000000000
+11001001000000000011111001101000
+00001110100110000000001110100110
+00000100111110010000000010010010
+01000000000001111001000000000010
+00100100000000001110100100000000
+10110010010000000000100110010000
+00000011001010000000010001110000
+00000000000000000000000000000000
+00101000000000011010111000000000
+11111001100101000011110001100000
+00001111100101000000001111100100
+10010100111110010000000000111110
+01000000000011111001000000000011
+11100100000000101101100100001000
+00111100010000000010111000010000
+00000011110010100000000001100000
+00000000000000000000000000000000
+00101000000100001010000000000010
+11001000100000000011111000000000
+10001100000001001000101110100010
+00000000111110000000000010110010
+00000000000011110000000000000011
+00000000000100001100100000000000
+10110010000000000000110011000000
+00000011000010100000010000100000
+00000000000000000000000000000000
+00101000000001010010100001000000
+10001010101000000010111010000000
+00001000111000000000001000101000
+00100000101111101100000010110110
+10000000000010111010000000001010
+00101000000000000000111001001000
+00100010100000010000100011100000
+00000010100010100000000001000000
+00000000000000000000000000000000
+00101000000001010100100100000010
+10000011100000000010110011000000
+10011000001100010000001010001100
+00000000101100010110000000101000
+11000001000010110011000000000010
+00001100000000101000101110000000
+10100000111000000010100000101000
+00000010000010100000000001010000
+00000000000000000000000000000000
+10100000000000010001100100000000
+10000111000000000010110011000000
+00111000011100000000001000011100
+00000000101101000000100010101101
+11000000000010110111000000000010
+00001100000000001000010100000000
+00100001110100000000100001100100
+00000010001010000000000001000000
+00000000000000000000000000000000
+10101000000010000001111000000010
+11000111100010000011110111100100
+00001100011010000000001110011110
+00000100111111011000000010111001
+11100100010011111111101010000111
+00011110001000001100011110000010
+00110011101000000010110011111000
+00001011001010100000001000000000
+00000000000000000000000000000000
+00001000000111011010110110110000
+11111010010000000011111011100100
+10001011001100000000001111101000
+10100000111110000000000000110110
+11000100000011111011010100100011
+11101101110000001111100100000100
+10111110100000000000111110110000
+00000011110000100000011001100000
+00000000000000000000000000000000
+00000000000001011111001000000000
+11001110100000000011111111100001
+00001111111110000000101110111010
+00000000111111111000000000111011
+11100000000011111111100000000111
+00111110010000001100111010000000
+00110011011000000100110011001000
+01000011000000000000000001110000
+00000000000000000000000000000000
+10101000000100011001000001000010
+10000110000100000010110111000000
+00001011011100101000001000010100
+01000000101101100000000000100001
+11000000010011100111000000000010
+00111100110000001000111100010000
+00100001010001000100100001000001
+10001010001010100000010001100000
+00000000000000000000000000000000
+00000000000000001001010000100010
+10000101000000000010110111100010
+00001011001100000000001011011000
+00000000101101110000000000101101
+11000000000010110011000000001010
+00011100000000001000011000000000
+00100000000000000010100000011000
+00001010000000000000000000100000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10000000000001000010110011110010
+00001011001101000000001001000000
+00000100101100110000001010100100
+11000000000010100011000000000010
+00001100000000011000101100000000
+00100000001001000000100000010100
+00000010000010000000010000110000
+00000000000000000000000000000000
+10101000000101011000110000000000
+11001001000000000011111111100000
+00001111101100000000001111100100
+00000000111110000000000000111111
+11000000010011111111000000100011
+00111100000000001100101100000000
+00110010110000000000110010101101
+00000011001010100000010001100000
+00000000000000000000000000000000
+10000000000000001110110100000000
+11111001100000000011111011000001
+00001111101101000000001110101100
+00010000111110110100000000111010
+11000000000111111011000000000011
+11101100000000001111100000000000
+00111110110000000000111110100000
+00000011111000000000000000110000
+00000000000000000000000000000000
+00000001000100001111111000100000
+11011111010000000011111111000000
+00011111111100011000001101110100
+00000000111111000001000010110001
+11000000000001001111000000100011
+11011100000000001000111100000000
+00110001100000000010110001110000
+00001011000000000100010000110000
+00000000000000000000000000000000
+10000001000001000110111101100000
+10001010100000000010111011000000
+10001011001101000000001000101000
+00000100101110110100000010110110
+11000001000010101011000000000010
+11101100000100001101100011001010
+00100010100000010000101010110000
+00000010001000000100000000010000
+00000000000000000000000000000000
+10000000000001010010100000000000
+10011000000000000010111011000000
+00011011101100001000001001100010
+00001000101100100000100010100010
+11000000010010101011000001000010
+11101100000000001010100000100000
+00100010010000000000100010000000
+00000010001000000000000001000000
+00000000000000000000000000000000
+00001000000001000010100000000000
+10000000000000000010110011000000
+00001011001100000000011000000100
+00000000101100110000000001100100
+11000000000010100011000000000010
+11001100000000001011000000000000
+00000000010000000010100000000000
+00000010000000100000000100000000
+00000000000000000000000000000000
+00000000000011010100100000000000
+11011001000000000011111111000001
+00001011101100000000101101100000
+00000100111100110000000010110011
+11000000000011101111000000000011
+11111100000010001110100000000000
+10110010000000000100110010010000
+00000011000000000000001101010000
+00000000000000000000000000000000
+10100000000110011111100000000000
+11111100000000000011111111000000
+00001111110100000000101111110000
+00000000111111110000000000111111
+11000000000011011111000000000011
+11111100000000001101110000000000
+00111111000000000000111111010000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011111110001000000
+11011111000000000011001111000000
+00011110111100100000001100111100
+00000000110011110010000000110011
+00001010000011111101100000000011
+11110100000000001101111000000010
+00110011110000000000111101101000
+00000011011100000000000001110000
+00000000000000000000000000000000
+10000000000110001110110010000000
+10001011001100000011001111011010
+00001101111101000010001000111101
+11101000100011110110100000100010
+00011011000010111001000000000010
+11110110000000001000100010000100
+00110010111000000000100110110000
+00000010001100000000010000110000
+00000000000000000000000000000000
+10001000010001011000110000000100
+10010011000010000010000011010000
+00001000001100010001001010001100
+00000010100000110001000000100000
+00000000000010110001000000000110
+11001100000000001011000000000000
+00101000111000000000101100010000
+00000010001100100000000101110000
+00000000000000000000000000000000
+11000000000001011100110000000000
+10000011000000000010001011000000
+00001001101100000000001010001100
+00000000100010110000000000100010
+00100000000010111010100000000010
+11100110000000001010100010000001
+00101010100000000000100100011000
+00000010001100000000010001100000
+00000000000000000000000000000000
+01000000000101011110110000000000
+11011011000000011011001011000000
+00001100101100000000101110101100
+00000001110010110000000010010010
+00110000000010111001100000010111
+11100110100000001111101010000000
+00101010110000001000111110111000
+00001011010100000000010001110000
+00000000000000000000000000000000
+11100000000000011010110000000000
+11111011000000000011101011000000
+00001111111100000000001101111100
+00000100111111110000000000111110
+11000000000011111101000000000011
+11110100000000001101101100000000
+00110011110000100000111111110000
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11101011000000010011010011000000
+01001100001100000001001111101100
+00010000110010110000000000110110
+01000000000011011011000010000011
+10001100000000001101100011000000
+00110010110000001000110010010010
+00000011000101010000010000100000
+00000000000000000000000000000000
+11001000000001010011110000001000
+10001111000000000010001111000000
+01001010111101000000001011111100
+00000011101011110000000010100010
+11000000000010001011110011000010
+10101100000000000000000100000000
+00010110111100000010110010010100
+00000010001100100000000001000000
+00000000000000000000000000000000
+11000000000001000100110000000000
+10100011000000000010010011000000
+01001001001110011000000011001100
+00000000100010110000000001101100
+00000000000110010011100000000010
+01001100000000010001001000000001
+01100000111101000000100100000100
+00010010001110000000000001010000
+00000000000000000000000000000000
+00100000000100000101111000000000
+10000111100000000010000111100000
+01001010011110000000001011011110
+01000000101000111001000001101001
+01100100010110000111100000000010
+11010110000000101000010010010000
+00100100111000000000100001011000
+00010110001011000000000001000000
+00000000000000000000000000000000
+01001000000010000100110000000000
+11100011000000000011010011000000
+00001101001100100000001011101100
+00000000100000110000000000111100
+11010000000011011011000000000011
+11001000000000001101001001000000
+00110000110001000000110100010000
+00001011000100100000001000000000
+00000000000000000000000000000000
+01000000000101011011110000000000
+11111111000000000011111111010100
+00001111111100000000001111111101
+00100010111111110000000000110111
+11000000010011111110000000000010
+10010100000000001111110000000100
+00111011110001000000111111010001
+00000011110100000000011001100000
+00000000000000000000000000000000
+00001000000001011110110001000000
+11111011000000000011111011010100
+00001110101111001000001100101101
+00000000110010110111001000111010
+00000000000011101011100000000011
+00101100000000001101101000000000
+10110010110010100000111100111000
+00100011001010100000000001110000
+00000000000000000000000000000000
+01001000000110010001110010000100
+10110111001000000010110111000000
+00000011011101000100001010001100
+10000000110101110011000000100001
+11000000000010001111000000010010
+00011100010000001010011000000000
+00100001110000001000101101110000
+00000010001100100000010001100000
+00000000000000000000000000000000
+00100000000000000001111000000000
+10110111100100000010110111101000
+00001010001110100000001000011110
+00000000100000111000000000101001
+01100000000110100111100000000010
+00001110000000001000001010000000
+01100001111000000000101111011000
+00000010001000000000000000100000
+00000000000000000000000000000000
+01101000000001001100110000000000
+10111011000000000010111011000000
+00001011001100000000001010001100
+00000000100100110000000000101000
+11000000000010000011001100001010
+00001110000000001010001110100000
+00100000110000101000101100010101
+10000010000100100000010000110000
+00000000000000000000000000000000
+11101000000101011110100000000000
+11111010000000000011111010000000
+00001110101000000000101100101000
+00000000110010100000000000111011
+10001000000011101110000000000011
+00111011100000001100111010100000
+00110010100100001000111111101100
+00001011001110100000010001100000
+00000000000000000000000000000000
+01001000000000011010000000000000
+11111000000000000011111000000000
+01001111100000000000001111100000
+00000000111100000000000000010110
+00100000100011111000000000000011
+11100000001000001110100000000001
+00111110000000000100111110000000
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001000010000000010
+11001001000000000001001001000000
+01000110100110000000001111100100
+00000000110010010000000000110100
+01000000000011001001000000000011
+11000100000000001000000100000000
+00100010110000001000111110010000
+00000011110000100000010000110000
+00000000000000000000000000000000
+10000000000001000110010000000100
+10001001000000000010001001000000
+00101000100110010000001011100100
+00000010100010010000000010100010
+01000000000010101001010000000010
+11100100000000001000100100000000
+00100010010000000000101110010100
+00000010111000000000000000010000
+00000000000000000000000000000000
+00111000000001010010010000000000
+10001001000000001010101001000000
+00001000100100000000001011000100
+00000000100010010000000000100110
+01000000000010001001000010000010
+11100100000000001010100100000000
+00101010010000000000101110010100
+00000010110001100000000001000000
+00000000000000000000000000000000
+00101000000101000000010010000000
+10000001001010000010100001001001
+00001000000100100000001011000100
+10110000100000010010100000100000
+01001000010010100001000000000010
+11000100100000011010000110100000
+00101000010010010000101100010000
+00000010110000100000000100000000
+00000000000000000000000000000000
+10111000000011000110000000000000
+11001000011100100011101000010100
+00001100100001010000001111100000
+10000000110010000010000000110100
+00000000100011001000010100000011
+11100000000000101110100000000000
+10111010000000000000111110000101
+00000011111011100000001101010000
+00000000000000000000000000000000
+10011000000001011010010011110000
+01111001000000000011011001000100
+00001101100100010000001111100100
+10110000111110010010100000111111
+01001110000011111101000000000011
+11110100010000001101110100010001
+00110110010001001000111111010000
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000000001011110010100001000
+11111001010000000011111001000000
+00001100110101000000001100100100
+00100000110010011000000000110010
+01001000000011111101010000000011
+00010100000000101100000100000000
+00110010010000101000111100010000
+00100011110001100000000101100000
+00000000000000000000000000000000
+00111000000110001110000100001000
+10111000010000000010111000011110
+00001000100001000000001010000011
+10001000110110001111100000100010
+10011001000010110000001000010011
+01100001000000001000100001000000
+00100011100100000000101110000000
+00000010110011100000010000110000
+00000000000000000000000000000000
+01001000010001011000010110000100
+10110001011001000010110001000000
+00101000000101100000001000000100
+00100000100000010000000000100000
+01010010100010110001000000000110
+00000101000000001000010111000010
+10100001010000000000101100011010
+10000010110100100000000100110000
+00000000000000000000000000000000
+00011000000001001010010000001000
+10111001000000000000110001000000
+00000000100100000000001010100100
+00000000100100010000000000100010
+01000000000010110001011000000110
+01100110001000101000110100000000
+00100111010000000000101110010010
+00000010110001100000010001100000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11111001000000010011111001000000
+01000000100100000001001100100100
+00000000110010010000000010110010
+01010000000011111001010000100011
+00100100000000001100100100000010
+00110010010000000000111110011000
+00000011111010000000010001110000
+00000000000000000000000000000000
+01001000000000010010010000000100
+11111001000000000011111001000000
+00001111100100000010001111000100
+00001000111110010000000100111110
+01100100000011111001000000000011
+11000100000000001111000101000100
+00111010010000010000111110110000
+10000011110110100000000001100000
+00000000000000000000000000000000
+00001000000100001010000000000000
+11101000000001000011001000000000
+00001101000000010000001111100000
+00010000110010000000000000110110
+00010000001011001000000000000011
+00100000000000001100100000000000
+00110011000100000100111110000000
+01000011000010100000010000100000
+00000000000000000000000000000000
+00101000000001010010100000000001
+10001010000000000010001010000000
+00001001111000000000001011101000
+00000010100010100000010010100010
+10000000000011011110000000000010
+10101000000000101000101000000000
+00100010100000000100101110100000
+00000010000010100000000001000000
+00000000000000000000000000000000
+00101000000001010100110000000100
+10100011000000100010100011000000
+00001001001110001000001011001100
+00000000100000110000000010100100
+11000000000010000011000000000010
+01000100000000011000001100000000
+10100000100000000000101100110000
+00000010000010100000000001010000
+00000000000000000000000000000000
+10000000000100010001111000000000
+10000111101000000010100111001000
+00011001011000000000001011011100
+10000000100000110001000000100001
+11100100000010000101000000010010
+11010100000000001000010100000000
+00100001100000010000101111111000
+00100010001010000000000001000000
+00000000000000000000000000000000
+10001000000010001011111001000000
+10101111110000000011100111110001
+00001101011110000000001111011111
+00100000110001111010100000110111
+11101000000010000110100000000011
+01010110000000001100011010000000
+00110001101000000000111101111000
+00000011001010100000001000000000
+00000000000000000000000000000000
+00001000000101011010110000000000
+10111011001000001011011011011000
+00001111101000000000001111101100
+00000100111110110000000000111110
+11010000010011111101000000000011
+10100100000000001111100000000000
+00111110100000000000111110110110
+00001011110000100000011001100000
+00000000000000000000000000000000
+00000000000001001111111000100000
+11111111110000000011001111110000
+00001100110110000000001100111110
+00000010110011111000000010110011
+11110000000011111111100100000011
+11110110000000001110111110000000
+00110101101000000000110011111100
+00000011000000000000000001110000
+00000000000000000000000000000000
+10101000000110001001110000000000
+10110111000000000010000111000100
+00001000010001000000001101111100
+00000000100001110010000000100001
+11000000000010110101001100010010
+11010100010000001000010100000000
+00100001100001000000100001110000
+00000010001010100000010001100000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000000010000111000000
+00001000011100000000001000011100
+00000000100001110000000001100001
+11000000000010110110000000100010
+11010101000000001010011000000000
+00100001101000000000100001110100
+00000010000000000000000000100000
+00000000000000000000000000000000
+00100000000001001100110000001001
+10110011000000000010000011000000
+00001000100000000000001001101100
+00000000100010110000000010100000
+11110100000010110001010100000010
+11000100010000001000000010000000
+10100000100100100000100000110000
+00000010000010000000010000110000
+00000000000000000000000000000000
+10101000000101010011110000000000
+10111111000000001110001111000000
+00101000101100000000001100111100
+00000000110011110000000000110011
+11110000000010111001010000000011
+11100000000000001110101101001000
+00110010010100000000110010110000
+00000011001010100000010001100000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011111011000000
+00001111101000000110001111101100
+00000000111110110000000000111110
+11000000000011111001000000000011
+11000000000000001111100100000000
+00111110010000000000111110110100
+00000011111000000000000000110000
+00000000000000000000000000000000
+00100001000100001111110000000000
+11111111000000000001111111000000
+00001111111100000000001100111100
+00000000110011110000000000110011
+11000010000011111100000010000011
+00100000000000001100101000001000
+00111111010000001000111111110000
+00000010000000000100010000110000
+00000000000000000000000000000000
+10100001000001000110110000000000
+10111011000000000010111011000001
+00001011101000000000001010101100
+00000010100010110000000010100010
+11000000000010110001100000000010
+00100001100000001000100000000000
+00101110011000000000101100110000
+00001010001000000000000000010000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011100100000000001000101100
+00000000100010110000000000100010
+11000000000010111001000100100010
+00100000000010001000101100000010
+00101110010001000000101110110100
+00000010101000000000000001000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010110011000000
+01001001000100000000001010001100
+00000000100000110000000000100000
+11000000000010111001000000000010
+00000000000000001000000100000000
+00101100011000000000101110110000
+00000010100000100000000100000000
+00000000000000000000000000000000
+00000000000011010111110000000000
+11110111000000000011110111000000
+00001111001100000000001100111100
+00000000110001110000000000110011
+11000000000011111000000000001011
+00100000000000001100101000000000
+00111110010000000000111110110000
+00000011100000000000001101010000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+00001111110100000010001111111100
+00000000111111110000001000111111
+11000000000011111101000000000011
+11110000000000101111110000000000
+00111111010000000000111101100000
+00000011011010000000011001110000
+00000000000000000000000000000000
+11000000000001011111100000000000
+11001101100000000011111111001000
+00001111111100110000001000110110
+00000000110011110001000000110011
+00001100001010001101100000000011
+11111100000000001100111110000000
+00110111010000000000110011000000
+00110011111100000000000001110000
+00000000000000000000000000000000
+10000000000100001010010000000100
+10001001100000010010111111001110
+00001011111101100000101000100110
+00000100100000110010000000100010
+00001100100010001011100000000010
+11111101100010001000100110000001
+00100010011000000000110110001000
+00000010111000000000010000110000
+00000000000000000000000000000000
+10001000000001001100000000000001
+10000011000001000010110011000000
+00001011001100110000001010101100
+00000000100000110010000000100000
+10001000000010000001000000000010
+11001100011000001010001100000000
+00101110110000000011100000100000
+00000010111000100000000101110000
+00000000000000000000000000000000
+11000000000101011000010000100011
+10001011001000000010111011000000
+00011011101100000000001010100110
+00000000100010110000000001101010
+00000000000010001011000000010010
+11101100000000001010101111000110
+00101010110000000000100110100000
+10000010111100000000010001100000
+00000000000000000000000000000000
+00000000000101011110000101000000
+11001001000000010011111011000000
+00001111101100000100001110000100
+00000000110010110000000001110010
+01001000000011001001100000000011
+11101100000000000110100110000000
+00111100010100100000110010000100
+00000011110000000000010001110000
+00000000000000000000000000000000
+11100000000000011011011000000000
+11111101000011000011111011000000
+00001111111100000000001101110100
+00010000111101110000000011110111
+00000100010011111111100100000011
+11111100000001101101110100000001
+00110111010001000000111110000100
+00100011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010000100000000
+11101011000000100011111011000000
+00101100001100010000001110101100
+00000000111110110000000000110000
+11000100000011111001000000000011
+11101100000000101110101101001000
+00111110110000100010110010110100
+00001011000100000000010000100000
+00000000000000000000000000000000
+11001000000001010010010111010000
+10001011000000000010111111000000
+00001000111101010000001000100100
+10000000101111110000010000100010
+00100000000010111011100000000010
+11111110000000001000001101100000
+00001110110110000000100010111000
+01000000001100100000000001000000
+00000000000000000000000000000000
+11100000000001010100011100000010
+10100001110000000010110011000000
+00011001001110000000001010000100
+00000100101100110000000000000100
+00011000010010110001100000000010
+11101100010000000010000100000000
+00001100000100010000100100010000
+00000010001110000000000001010000
+00000000000000000000000000000000
+01100000000000010000111000000000
+10010101100010110010110111100000
+11001001011110000000011000011110
+00000000101101111000001000100101
+11100000000010110101100010000010
+11011110000000001010010110000010
+00101100001000010100100101011010
+10010010000110000000000001000000
+00000000000000000000000000000000
+01001000000010000000110010001001
+11100001000001000011110011001000
+10011101101100100000001110001100
+00000000111100110000000010110100
+10001000100011110001000000000011
+11101100000000001110001100110000
+00111100110000000000110100000000
+00001001000100100000001000000000
+00000000000000000000000000000000
+01000000000111011011110100000001
+11101101000000000011111111000000
+00011110111101000001001111111101
+00000000111111110001000000111011
+11000000000011111101000100000011
+11111101001000001101111100010000
+00111111110000000000111011000010
+01000011110100000000011001100000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11001011000000000011111011001001
+00001111101100010000001111100100
+10000000111110110001000000111110
+01000000010011111011001100000011
+11101100100000101100100000000000
+00111100010000000010110010110000
+00010011001010100000000001110000
+00000000000000000000000000000000
+01001000000100010000110000000000
+10000111001100000010110111010010
+00001011011100000101001011011100
+00010000101101110000001000101101
+11000000000010110111000010000010
+11011100000000001000010000000010
+00101101010000000000100001110000
+00000010000100100000010001100000
+00000000000000000000000000000000
+11000000010000000001111000000100
+10000111100101000010110111101000
+00001011011110100000001011011110
+01000001101101111000000000101101
+11100000000010110111101000000010
+11001110100000001011011010001000
+00101101011000000000100000111000
+00000010001100000000000000100000
+00000000000000000000000000000000
+01001000000101001100111000000000
+10000011000000000010110011000000
+00001011001100000000001011001100
+00011000101100110000001000101100
+11000000000010110011000100000010
+11101100000000001011001010000010
+00101100111000010000100000111111
+00000010000100100000010000110000
+00000000000000000000000000000000
+11101000000101011010100000100010
+11001010101000000011111010000000
+10001111101000000100001111101000
+00000000111110100000011001101111
+10010001000011111010100000000011
+11101000000010001111111000000100
+00111111101000000000110011100100
+00001011001110100000010001100000
+00000000000000000000000000000000
+01001000000000001110000000000010
+11111000000000000011111000000000
+00000011100001000000001111100000
+00000000111110000000000001111110
+00000010010011111000000000000011
+11100000000000000000100000100000
+00111100000001000000111100000000
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110110001000010
+11001001000000000001001001000000
+10000011000100000010001100100100
+00000000111110010000001001111100
+01000001100011001001100100000011
+11100100000000001100100110000010
+00111110010001100000110010011000
+00000011000000100000010000110000
+00000000000000000000000000000000
+10000000000001000110010100000000
+00000011000000000010001001000000
+00001011100100000000001000101101
+00000100101110010000000000101110
+01000000000010001011100000000010
+11100110000010001000100111000000
+00101110010110000000101010011000
+01000011001000000000000000010000
+00000000000000000000000000000000
+00011000000001010000010100000000
+10001001010000100010101001000000
+01011011100100000000001000100101
+00000000101110010000000000101110
+01000000000010001001000000000010
+11100100010000101000100100101000
+00101110010000000010100010010001
+00000010000001100000000001000000
+00000000000000000000000000000000
+00001000000001000000010010100010
+10001001000000000010100001001010
+00001011000100101000001000000100
+00000000101100010010001100101100
+01001000100010000001000000000010
+11000100101000011000000100000000
+00101100010010000000101000010010
+00000010000000100000000100000000
+00000000000000000000000000000000
+10111000000011000110000010010000
+11001000000001000011101000001000
+10001111101001110000001100100000
+00000000111110000000000100101110
+00010100001011001010000000000011
+11100001110000001100100000000100
+00111110000000000000110010000000
+00001011001011100000001101010000
+00000000000000000000000000000000
+10011000000111011010010010100010
+11111001000000011011011001001010
+00001111100100000000101111100100
+00000000111110010011100000111111
+01000100100011111001000000000011
+11100100000000001111110100000000
+00111111010001010010111111010001
+00000011101001100000011001110000
+00000000000000000000000000000000
+10011000000001011010011000000000
+11001001000000000011111001000100
+00001111110100100000001111100100
+00010000111110010110000000111111
+01001011000011000001000000000011
+11110101000000101100110100000100
+00111111010010000100110011010000
+00000011001001100000000001110000
+00000000000000000000000000000000
+00111000000100001110001010000010
+10001000000000000010110000010100
+00001011100000100000001011100000
+00000000101110000101000000101100
+00011001000010001000000000000010
+11100001000010001000100000000010
+00101110000100000100110110000100
+00001010000011100000010000110000
+00000000000000000000000000000000
+00001000000001001100010100100001
+10000001000001000010110001001000
+00011011000101001000001011000100
+00010001101100010010000000101100
+01000010000010000001000000000010
+11000101100001001000000100000100
+00101100011001000010100000010100
+01000010100000100000000101110000
+00000000000000000000000000000000
+00011000000101011000110010010000
+10001001000000000010111001000001
+00011011100100000000001011100100
+10000000101110010000000000101110
+01000001000010001001000000000010
+11100100000000001000100100000110
+00101110010000000000100110010100
+01000010100001100000010001100000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11001001000100000011111001000000
+01001011100100000100001111100100
+00001000111110010000000000111110
+01000000001011001001000000000011
+11100100000000001100100100010000
+00111110011100000000110000010000
+00000011101010000000010001110000
+00000000000000000000000000000000
+00101000000000011010110000111000
+11111001100000000011111001000000
+00001111100100001000001111100100
+00000000111110010000000000111110
+01000100000011111001000000000011
+11100100000010001111100110000010
+00111110011001000100111110010010
+00000011010010100000000001100000
+00000000000000000000000000000000
+00101000000100001010000000000100
+11001000000000010011111000000000
+10001101100000000000001110100000
+00000000111110000000000011110010
+00000000000011001000000010000011
+00100000000000001101100010000000
+00111110000010000010110010000000
+00000011000010100000010000100000
+00000000000000000000000000000000
+00101000000001010010101000001010
+10001010000000100010111010000000
+00101000111000000000001000101011
+00000000101110100000000100000011
+10000000000010001010010000100010
+00101000000100001000111000000000
+00101101100100001000101011100000
+00000011100010100000000001000000
+00000000000000000000000000000000
+00101000000001010100111000000000
+10010011000100000010110011000000
+00011000001110000000001010001100
+10000000101100110000000000100010
+11100000000010000011010000000010
+00100100000000001001001100000000
+00101100010000000100100000011000
+00000000010010100000000001010000
+00000000000000000000000000000000
+10100000000000010001110000110000
+10010111000000000010110111101000
+00011000010110001000001000010101
+00000100101101111010001000100001
+11010000000010001111100000000010
+00010100000000011000011100000000
+00101101010000001000101001110100
+00010110101010000000000001000000
+00000000000000000000000000000000
+10101000000010000000101001000000
+11010111100010010011110111101000
+00001100111110000000001110011010
+00000000111111111100001000100001
+11100000001011000111100000001011
+00111110000000001101011110000000
+00111100011000000010110000111000
+00001011011010100000001000000000
+00000000000000000000000000000000
+00001000000011011010100010000000
+11101010001000000011111011000100
+00001110100000000000001111100000
+10000000111110110110100000111110
+11000000000011111001011000010011
+11100100000000001111101100000000
+00111110010000000000111110110000
+00000011110000100000011001100000
+00000000000000000000000000000000
+01000000000001011111011001011000
+11101111100100000011111111110000
+00101100111010000000001111111111
+00000000111111111000000000110011
+01100000010011111111110000000011
+11110110000000001100111110000000
+00110001011001000010110011111000
+01000011000100000000000001110000
+00000000000000000000000000000000
+10101000000100011001010011000000
+10000101000000000010110111000000
+00001000010000000000001011010100
+00000000101101110000000000101001
+11000000000010110111000000000010
+11110100100000101101011100000000
+00111101010011000000100001110010
+00100010001010100000010001100000
+00000000000000000000000000000000
+00010000010000001001110000010000
+10000111000000000110110011000000
+00001000011100000000001011011100
+00000000101101110000000000100001
+01000010000010110110000000000010
+11011100000010001000111100000000
+00100001010000000100100001110000
+00000110100000000000000000100000
+00000000000000000000000000000000
+01100000000101001100000100001001
+10000000000000000010111011000001
+00001000000000000000001011000100
+00000001101100110000000000101000
+11100000000010110000000000010000
+11000100000000001000001100000010
+00101000010000000000100000110000
+01100110100110000000010000110000
+00000000000000000000000000000000
+10111000000101011010100100000010
+11001000000000100011111111000000
+10001100101100000000001111101110
+00000000111111110000000000110010
+11110100000011111000100000000001
+11100100000000001000101100000000
+00100010111000000000110000110000
+00000011101011100000010001100000
+00000000000000000000000000000000
+10000000000000001100101100000000
+11111011000000000011111011000000
+00001111101100000000001111101101
+01000000111110110000000000111110
+00010000000011111010000100010011
+11000100000000001111101100010000
+00111110011000000000111110110000
+00000001011000000000000000110000
+00000000000000000000000000000000
+10000000000100001111110000100000
+11011100100000000011111111000000
+00001100111100100000000110111010
+00010000111100110000010000110011
+11000000000011111101000000000011
+11111100000000001100111100000000
+00111111010000000000110011111010
+00000011001000000000010000110000
+00000000000000000000000000000000
+10000101000001000110110000000000
+10001010110000000010111011000000
+00001000101000000010101000101001
+10000000101110110000000000100010
+00101000000010111001100001000010
+11100100000000001000100110000010
+00101100011000000010100010110000
+00000010001001000100000000010000
+00000000000000000000000000000000
+10000000000001010010010000010010
+10001000011000000010111011000000
+00001000000000000000011000100000
+01000000101110110000000000100010
+01001001000010111000000100000010
+11100100000000001000101110000000
+00101110101000100100100010110000
+00000010001000000000000001000000
+00000000000000000000000000000000
+00001000010001000000010000000000
+10000001000000100010110011000000
+00101000000000000000001010000000
+00000000101100110000010100100000
+00000000000010110010100000000010
+11000100000000001000001110000000
+00101110010000000000100000110000
+00001010000000100000000100000000
+00000000000000000000000000000000
+10000000000011010100110000000000
+11001000000000000011111111000000
+00001100100100000000001100100000
+00000100111111110000001000110010
+01000000000011111000000000000011
+11101100000000101100101100000000
+00111110010000000100110010110000
+01000011001000000000001101010000
+00000000000000000000000000000000
+10100000000111011111000000000000
+11111100000000000011111111000000
+00001101110000000010001101110000
+00000000111111110000000010111111
+00000000000011111100000000000011
+11110100000000001111010000000000
+00111111010000000000111101110000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000000011111011000000000
+11011111000010000011001111000110
+00001101110110010000001111110000
+00000000111111011000001100001111
+01100000100011001100001100100001
+11110110000000001100110000000010
+00110011110000000100110011110000
+00000000001100000000000001110000
+00000000000000000000000000000000
+10000000000100001110010000000000
+10001011100000010011011111011000
+00001101100100100000001011100001
+00100100101110011000000000101110
+01100000000010001000011100000010
+11100100000010001000100010000100
+00101010111000000000100010010111
+00010010001000000000010000110000
+00000000000000000000000000000000
+10001000000001011110110000000000
+10010011000000000010000011000000
+00001000000100100000001011000000
+11000000101100010000010000100100
+01000000000010000000000000000010
+11000100000000001000000000000000
+00100000101000000000100000010000
+10000010001000100000000101110000
+00000000000000000000000000000000
+11000000000101011010111000100000
+10001011000000000010010011000000
+00001001100100000000001011100110
+00010000101110111000000000101110
+10100000001010001011100000000010
+11100100100100000000100100000000
+00101010100000010010100000011000
+00100010001100000000010001100000
+00000000000000000000000000000000
+01000000000101010100011100000000
+11011011000000000001001011000000
+00001100100100000000001111100010
+00000000111110011010000000110110
+01100000000011001000110010000011
+11100111000000000100101001010000
+00110010110000000000100010010000
+00000011000100000000010001110000
+00000000000000000000000000000000
+11100000000000011011010000000000
+11111111000000000011111011000001
+00001111110101000000001111111000
+00101000111111010000000000111111
+01000001000011111101000000000011
+11110100000011001111111000000010
+00111110110100001000111111010000
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11101011000000000011111011000000
+00001101100100000000001111100101
+00000000111110110100000000111110
+11001001010011111000010001000011
+00100100001010001100001101001000
+00110010010000000000110010010000
+00000011000100000000010000100000
+00000000000000000000000000000000
+11001000000000010010110000000000
+10110111101000000010111111000000
+00101100100100000000001011101101
+00011000101110110000000001111100
+11100000000010111011110010000010
+10000100000000001000101111100000
+00100000000111000000100010010111
+00000011001100100000000001000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10100011000000010010110011000001
+00001000000100000000001011000011
+00000000101100111000010000101100
+11010100000010110000100010000010
+00000101000100001010000010000000
+00100000110000000010100000010000
+00000010011110000000000001010000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10110111100001000010110111100000
+00011000011110000000011011010110
+01000000101101101100010000101001
+11100000000010110100100001000010
+10110110000010001010011110000001
+00100001111010000000100001011001
+01000010000010000000000001000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11100011000000000011110011000100
+00001100000100000100001111001001
+00100000111100110001100000101100
+11001000000011111001000000000011
+00000101000001001110001000000000
+10110000110000000000110010010000
+00000001010100100000001000000000
+00000000000000000000000000000000
+01000000000111011011110000000000
+11111111000000100011111111000000
+00001111111100000010001111110100
+00010000111111100000000100111111
+10000000000001111111000000000011
+11010100010010001101011100010000
+00111111110010010000111111010000
+00000011110100000000011001100000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011000000000011111011000110
+01000011100100000000001111100100
+00000000111010110000000000111110
+11100001000011001011000000010011
+00100110000000000000001100000000
+00100010110000000000110010010000
+00010011001010100000000001110000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110111000000000010110111001000
+00001011011100000010000011111100
+00000000100001110000000100111101
+11000000000010000101000001000011
+01010000000000001000011100000001
+00101000110000000000100011010000
+00010010000100100000010001100000
+00000000000000000000000000000000
+11000000010000001001111000010100
+10110111100001000010110111100000
+00011011010110000100001011011111
+00010000101001111100010000101111
+11110000000010010011100000000010
+00011111000000101000011110000100
+00100001111000001010100001011000
+00001010001100000000000000100000
+00000000000000000000000000000000
+01001000000101001100100000000100
+10110011000000000010110011000000
+00011011001100000000001011001110
+00100000100000111000000000101100
+11001000000010011011110000000010
+01000101001000001000001110000000
+00101000010000000000100000010000
+00001010000100100000010000110000
+00000000000000000000000000000000
+11101000000101011011100000000000
+11111010000000000011111010000000
+00001111101000000000001111111001
+00000100111011101000001000111111
+10000000000011011110101100000011
+00111010000000001100111011000000
+10110011100110000010110010100000
+00000011001110100000010001100000
+00000000000000000000000000000000
+01001000000000001110000000100100
+11111000000000000011111000000000
+00001111100000000000001111100001
+00000000111110001000000001111010
+00010000011011101000010000000011
+11100000000000101111000001010000
+00111110000000100000111110000001
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11101001000000000011111001000000
+00001111100100000000011100000100
+00000000110010010000000000111110
+01110000100011111001000100000011
+00100100000001001111100110101000
+00110000011000000000111000010001
+00001011000000100000010000110000
+00000000000000000000000000000000
+10000000000001000100010000000000
+10001001000000000010111001000000
+00001011000100000000001000100100
+00010000101010011000010000101110
+01001000000010111001101000000010
+00100111000000001011100111000010
+10110110010100000000100010011000
+00001010001000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10101001000000000010111001000000
+00011011100100000000101000100100
+10000000100010010010000000101110
+01000000000110111001000000000010
+10100100010000001011101101000000
+00100010010001100000101010010000
+00000010000001100000000001000000
+00000000000000000000000000000000
+00001000000001000010010000000000
+10000001001000000010110001001001
+00011011100100000000001000000100
+10000000101000011000000000101100
+01000000000010110001001000001010
+00001100000000001011000100100100
+00100100010010000010100000010010
+00000010000000100000000100000000
+00000000000000000000000000000000
+10111000000011000110000101000000
+11101000000010000011111000010100
+00001111100000000000001000101001
+01000000110010000000000000111110
+00000000000011111000010100000011
+10000001010000001111100000000000
+00110010000000010000111010000101
+00000011001011100000001101010000
+00000000000000000000000000000000
+10011000000111011011010000000000
+11111001000000000011111001000100
+00001111110100101000001111110100
+01000000111111010000000000111101
+01000000000011111101000100100011
+11110100000000001111110100010000
+00111111010001000000111111010001
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000000001011110010001000000
+11111101100000000011111001010000
+00001111100101000000001111110101
+00000000010001010000000000111111
+01000000000011110101001000000011
+00110101000000001100110100000110
+00110011010000000010110011010110
+00001011010001100000000001110000
+00000000000000000000000000000000
+00111000000100001110000000000100
+10111000010100000010111000011100
+00001011100000100000000011101001
+00000100110110000000000000101110
+10000000000010111000001011000011
+01100000000000101000100001000000
+00101010000100010000100000000110
+00000010000011100000010000110000
+00000000000000000000000000000000
+00001000010001011100010010010000
+10110001000001000110110001001000
+00011011000100100000001011000101
+10000001100000010000000000101100
+01000000000010110001010000000010
+00000100100001101000000101000000
+01100000010100000100100000010011
+00100010010000100000000101110000
+00000000000000000000000000000000
+00011000000101011010010000010000
+10111001000000000010111001000000
+00011011100100000001001011100110
+00000100100110010000000000101110
+01000001000010111011001000010010
+01000101100000001000100100001000
+01101010010010000000100010011000
+00000010000001100000010001100000
+00000000000000000000000000000000
+10100000000101011110010101100000
+11111001000000000011111001000000
+00001111100100000010001111100101
+00000000110010011000000000111110
+01000000000011111001001000000011
+00100101000010001100100111000000
+00110000010010001000100010010000
+00001011011010000000010001110000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11111001000000000011111001000000
+00001111100100000001001111100100
+00000000111110010010000100111110
+01110001000011111001000000000011
+11100110000000001111100100101000
+00111110010000000010111100010000
+10011011110010100000000001100000
+00000000000000000000000000000000
+00101000000100001010000100000000
+11001000000000000011001000000000
+00001111100000000000001100100001
+00000001110010000000100000110110
+00000010000011111000000010000011
+00100011000010001111100001000000
+00110010000101100000111010000000
+00001011000010100000010000100000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10001010000000010010101010000000
+00001011101000000001001000111001
+00000000100011100000010000100011
+10101001000010111110010000010010
+00111000000001001011011000100001
+10100011100000000000100011100100
+00000010000010100000000001000000
+00000000000000000000000000000000
+00101000000001010100110000000010
+10000001000000000010010011000000
+00001011001100000010001000101110
+10000000100000110000000000100100
+11100000000010111011110000100010
+00001100000000011011001010000000
+00100100101000001000101000110000
+00001010000010100000000001010000
+00000000000000000000000000000000
+10100000000000010001111011000000
+10000011100000000010110111000100
+00001011011110100000001000001101
+00001000100101111000000000100001
+11000000000010110111010000000010
+00011100000000001011011000000000
+00100101010000000000100001010000
+00010010001010000000000001000000
+00000000000000000000000000000000
+10101000000010000011111000000000
+11000101100000000011010111100010
+01011111111110101000001100011110
+00000010110001101000000000110101
+11100000000011110111100000001011
+00010110000000001111000010000000
+00110100111000001000111001111000
+00000011001010100000001000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011101011011000
+00001111101101110000101111100100
+00010100111010110000000100111110
+11000000100001111001000000000011
+11100100000110001111100000000001
+00111010010000000000111110110000
+00000011110000100000011001100000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11111101100000000011111111100000
+00001000111110000010001111110110
+00000000111101111000000100111011
+10100100000000111111101100000011
+00111110000000001111111010000000
+00110011111010000000111111111000
+00000011000000000000000001110000
+00000000000000000000000000000000
+10101000000100011001110001000000
+10110111000000000010111111000001
+00001101011100100000001011111100
+01000100110001100010000100100001
+11000000000010110110000101000010
+00011100000001001111010001100100
+00110101010000000000101101000001
+10000010101010100000010001100000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110101000000000010110111000000
+00001000011100000010001011010000
+00000000101001110000001000101001
+11000000000010110101001000000010
+00010000001000001011110000001000
+01100001010110000000101101110000
+00000010000000000000000000100000
+00000000000000000000000000000000
+00100000000101001100110000010000
+10110011000000000010110011000000
+00001001001110000000000011000000
+00000000100000110101100000100000
+11011100000010110000000000000010
+00000011000000001010000010000000
+01100000010000000000101110101000
+00000010100010000000010000110000
+00000000000000000000000000000000
+10101000000101011011110000000000
+11111001000000000011111111000000
+00001100111110001000001111101110
+01000000111010011000000000111010
+11100000000011111001101000001011
+00101100000000001011001011000000
+00100010101100000000111110111000
+00001011001010100000010001100000
+00000000000000000000000000000000
+10000000000000001110110000100000
+11111001000000000011110011000000
+00001111101100000001001111100001
+01000000111110110000000100111110
+01000000000011111001010001000011
+11101001001000001111101000000000
+00111110111000000000111110000000
+00000011111000000000000000110000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111101010000000011111111000000
+00001100111100000000001101011100
+00000000110011110000000000110011
+11000000000011110010000010000010
+00111101000000001000110000001000
+00110011110000000100110010110000
+00000011000000000100010000110000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111001000000010010111011000000
+10101000101100000000001000100011
+00000100101000101100110000100010
+01100000010010111000010000000011
+01001011000000001000100011000100
+00100000111000000000100010100000
+01000010001000000100000000010000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111001000000000010111011000000
+00001000001100000000001001100111
+00000000100010001000000000100010
+10100000000010111001100000000010
+10101100001000001010101010000000
+00100010111000000000100010110000
+10000010001000000000000001000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110001000000000010110011000000
+00001000001100000001001000000000
+00000000101010110000000010100000
+01000000000110110000000000000010
+01101000000000001010001000000001
+00100000110000000000100000010000
+00001010000000100000000100000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111001000000000010111111000000
+10001100111100000000001101100000
+00000000110010110000000000110010
+01000000000011111000000000100011
+10101000000001001110100000000000
+10110010010000000000110010110000
+00000011000000000000001101010000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111101000000000011111111000000
+00001111111100000000001111110000
+00000000111111110000000000111111
+01000000010011111100000000010011
+11111000000000000101010100000000
+00111111010000000000111111110000
+01000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011101111000000000
+11011111100100000011001110100000
+00011111111101101010001100111100
+00000000110011010000000000110011
+00000100000011001111000000000001
+01110100000010001101011100000000
+00110011111000000000110001111000
+00000011111100000000000001110000
+00000000000000000000000000000000
+10000000000100001110111000001000
+10000001001000001010001000100000
+00001011111101000000011000111100
+10100010100010011000001000100010
+00001000000011011011100000000010
+00010100000001001010101111010000
+00110010011000000000100010111000
+00000010111000000000000000110000
+00000000000000000000000000000000
+10001000000001011100100000000000
+10111011000000000010000011100000
+00000011001100100000001000001100
+01000000100000010000000010100000
+00000000000010000000000000100010
+01000100000010001001000100000100
+00100110110000000000100000110000
+01000010101000100000000101110000
+00000000000000000000000000000000
+11000000000101011010110001000000
+10001011100000000010001000000000
+00011011101100000000001000101100
+00000100100010010010000000100010
+11000000000010011001010001000010
+00100100000000001010100100000010
+00100010110000000010100010111000
+00000010111100000000010001100000
+00000000000000000000000000000000
+01000000000101011100110000000000
+11011011100010001011001010000100
+00001011101100000100001000101100
+00000000100010100110000000110010
+00100000000111000010100000000011
+01100110000000001101100100000000
+00110100110000000000110010111010
+00000011110100000000010001110000
+00000000000000000000000000000000
+11100000000000011011110000100000
+11111111000000000011111100000000
+00001111101100000000001111111100
+00000000111111000000000000111111
+01101000001011101110101001000011
+11110110010000001111010100000010
+10111111111001000000111111110000
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010010001000000
+11011011000000000011111011000000
+00001111101100000011001100001100
+00000001111110100100000000010001
+00000000000011101000000000000011
+10100110000010001100100100100000
+00110010110000100100111110010010
+00001011000100000000010000100000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10100011000000010010001000000000
+00001011111100000000001000111101
+11000000101101000000001000100010
+11000001010010001000000000010010
+00100101000000001000100110100000
+00100010110000000000111010111100
+10000010001100100000000001000000
+00000000000000000000000000000000
+11100000000001010100111000000000
+10010011000000001010110000011000
+00001011101100000001001010001100
+00000000101100110000001100100000
+00000001000010100011000000000010
+00100101100000001000001111000000
+00100000111100000000101100110000
+00000010001110000000000001010000
+00000000000000000000000000000000
+00100000000000010011111001001000
+10100111100000000010000101100000
+10001011011110010000001010011110
+00000001101100011000000000100001
+00100000110000000011100100000010
+00010110110000001000011110010000
+00100001111000000000101001111001
+00000010000010000000010001000000
+00000000000000000000000000000000
+01001000000010000000110101000000
+11010011000000000011110011000100
+00001111001100000000001110001100
+00000100101100110000000010110010
+11000000010011100010000000001011
+10001100100000001100000100000000
+01110000110000100000111100110000
+00000011000100100000000000000000
+00000000000000000000000000000000
+01000000000111011011110001000000
+11111111000000000011111111000110
+10001111111100000000001101111100
+00000000111111010000100010111111
+11000000000011111111010001000011
+11111100100000001111110100000000
+10111111110000000000111111110000
+00000011110100000000010001100000
+00000000000000000000000000000000
+10101000010101011100110000001000
+11011010000000010011111000001010
+00001111101111100000001101101101
+00100000111110110000000000111110
+01000000100011110011000000000010
+01101100101000001100100100000000
+00110110110000000100111100110000
+00100011001010100000000001110000
+00000000000000000000000000000000
+01001000000100010001110000000000
+10001111000000000010000101000000
+00001011011100010010001000011100
+10000000101101010010000010100001
+01000100000010110111000000000010
+00001100000000001000010100000000
+00100001110000000000101101110000
+00000010000100100000010001100000
+00000000000000000000000000000000
+11000000000000001001111000100000
+10010111100000000010110111101000
+00001011001110010100001001011110
+01000000101100111100000000100101
+11100000000010110110100000000010
+01011110000001001000010110000000
+00100001111000000000101101111100
+00001010001100000000000000100000
+00000000000000000000000000000000
+01001000000101001100110100000000
+10000011010000000010000011000000
+00001011001100000010001000101100
+00001000101100011100000000100000
+11000000000010110011010000000010
+00001110000010001000000100000100
+00100000111000000000101100101000
+10000010000100100000010000110000
+00000000000000000000000000000000
+11101000000001011001101000000000
+11011110100001000011111010000000
+00001011101000000000001101101000
+00001000111111100000010000110110
+10010000000011111010000000000111
+01101010100000101100101000100000
+00110011101000010000111111101100
+00000011001110100000010001100000
+00000000000000000000000000000000
+01001000000000001110000110000000
+11111000000100000011111000000000
+00001111100000000010001111100000
+00000000111110000010000000011110
+00000010000011110000000000000011
+11100000000000001111100000000000
+10111110000001000000111110000100
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000000001110011000001000
+11101001000010000011011001100000
+10001111100100000000001111100100
+00000000010000011010000000110010
+11000000000011101011000010000011
+00000100000000001100000100000000
+00110010011001000000111010011010
+00000011000000100000010000110000
+00000000000000000000000000000000
+10000000010001000110010001000000
+10000001000000000010001011000001
+00001011100100000010001011100100
+00000000100010011000000000100010
+01000000000010001001000000000010
+00100100000010001000100101010000
+00100000010000000000100000011100
+00000010001000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000000010
+10101001000000000010111001001000
+00001011100100000000001011100101
+00000000101010010000000000100000
+11000000010010101001000000000010
+00100100000000001000100100001000
+10100010010000000100101010010000
+00000010000001100000000001000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10001001000000000010100001000000
+00001011000100101000001011000100
+10110110001000010010001000100000
+01001000000010000001001000001010
+00000110100000101000000100100000
+10100000010000000000100000010000
+00001010000000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11101000000000000011111010000000
+00001111100000100000001111100001
+11000000111010000000000010110010
+00000000010011101000000000001011
+00100001010000101100100000000100
+00110010000000000100111010100000
+00000011001011100000001101010000
+00000000000000000000000000000000
+10011000000111011111010000000000
+11111101001010010011011001000000
+00001011100100101000001111100100
+00000000110111010001000000111110
+01001111000011111001000100000011
+11110100010000001111010100010000
+00111111010000000000111111010000
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000000000011111010000000000
+11110001010000011011101001000000
+00001111100101100000011111110101
+00000000110001010010000000110110
+01001010010011111101001000000011
+00110101000000101100110100101000
+10110010010000000000111111010000
+00000011000001100000000001110000
+00000000000000000000000000000000
+00111000000100001110000000000100
+10111000000000000010001000000000
+00001111100000000000001011100001
+00000000100010000101000000101010
+10011000000010111000000001000010
+00000001000000001000100001000000
+00100010000000001000101110000000
+00000010100011100000010000110000
+00000000000000000000000000000000
+00001000010001011100011000010000
+10110001001000000010100001000000
+00011011000101100000001011001101
+10000000100000010000000010100100
+01000011000010110001010000100010
+00001101100000001000000100000000
+00100000010000000000101110010000
+00000010000000100000000101110000
+00000000000000000000000000000000
+00011000000100011010011000000000
+10111001000010100010001001000010
+00001010100100000001001011000100
+00000000100010010000000010100010
+01000000000010111001000010010010
+00100100000000001000100100000000
+00100010010000000000101110010100
+00000010100001100000010001100000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11111001110000000011101001000000
+00001011100100000000001011100100
+00000010100010010000000010110110
+01110000000011111001010000001011
+00100100000001001100100100000000
+10110010010000000000111100010100
+00000010001010000000010001110000
+00000000000000000000000000000000
+00101000000000011010010000000000
+01111001110000000011111001001000
+00001111100100000000001111100100
+00000000111110010000000100111110
+01001001000111111001100100000011
+11100110010100001111000100100000
+00111110111001000000111110010001
+00000011110010100000000001100000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11011000010000000010001000010000
+00001110100000000000001100100000
+00000000110100000001000000110010
+00010000001011000000011000000011
+00100000000000101110100000010000
+00110110000000000000111110000000
+10000011110010100000010000100000
+00000000000000000000000000000000
+00101000000001010011101100000000
+00001010000000000010001010100100
+00001011101000000000001000111000
+00000000111010100000000000110110
+10000000000010001110110000000011
+01111000000000001000111010000000
+00100010101010000000101111101100
+01000010110010100000000001000000
+00000000000000000000000000000000
+00101000000001010100111110010000
+10011011000000000010000011010000
+10001011001100000000011000001100
+00000001100100110000000001100000
+11000000000010000000100000000010
+00101100000000001010001010000000
+00100100001000000000101100111000
+00000010110010100000000001010000
+00000000000000000000000000000000
+10100000010000010011101000100000
+10001111001000001110000110000010
+00001011011110000000001000010000
+00000000101111110000000000100101
+11101100000010000100000010000010
+01011100000000001000011100000000
+00100001010000000000101101110000
+10000010111010000000000001000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11010111101100000010000111100010
+00001110001110000000101100011110
+00000000110101011000010100110000
+11101010000011000000100000000011
+00011110000000001110011110000000
+00110101001001000000111101111000
+00000011111010100000001000000000
+00000000000000000000000000000000
+00001000000111011000110000000000
+11111011001100000011111010001000
+00001011101101010001001111100100
+00000100111010010000000100111110
+11000000100011111000000000000011
+11101000000000001111001100000000
+00111110110010000000111110110000
+00000011110000100000011001100000
+00000000000000000000000000000000
+00000000010001011101111011000100
+11010111100000000011001101100000
+00001111111111000000001110111110
+01000000110011111001000010110011
+11100000000011111110100000000011
+11111110000000001111111010000000
+00110011001000000000111111111000
+00000011100000000000000001110000
+00000000000000000000000000000000
+10101000000000011001110001000000
+11010111001000000011010101000000
+00001110011100000000001000010001
+00000000100001110011000000100001
+11001000000011110110001000000010
+11010100000001001011011100000000
+10100001010000000000101101110000
+00000010111010100000010001100000
+00000000000000000000000000000000
+00000000010000001001110110010100
+10111111000000000010000101000010
+00001010001100000000001011011100
+00000100100100010000000111100001
+11000000000010110110000000000010
+11011100000000001011011100000000
+00101001100000000000101101110000
+00000010100000000000000000100000
+00000000000000000000000000000000
+00100000000101000100110000000001
+10010011000000000010010001100000
+00001010001100000000001001000100
+00000000100100010000000001100000
+11000000000010110010010000000010
+11000000000000001011001100000000
+00101000111000000000101100100100
+10000010110010000000010000110000
+00000000000000000000000000000000
+10101000000101011000110000000000
+11111111111000001011001011100000
+00001110111100000000001111101100
+00000000110110110000000000110011
+11000000000011111001000000000011
+11101100000000001111101100000000
+00111000001000100000111110111010
+00000011101010100000010001100000
+00000000000000000000000000000000
+10000000000000001110111100000000
+11111011000010000011111011010010
+00001110101100000000001110101000
+00000000111000110001000000111100
+11001100000011100001001000000111
+11100100000000001111100100000000
+00100110010000000000111110110000
+00000011111000000000000000110000
+00000000000000000000000000000000
+00000001000100001111110000010000
+11011111000000000011011100100100
+00000100111100000010000100101011
+00000000111111011100000000110111
+11000000000001001101100000000011
+00111000100010001110001100000000
+00110011100000001000110011110000
+00000011000000000100010000110000
+00000000000000000000000000000000
+10000001010001000110110000000000
+10000011000000010010000000110000
+00001010101100000000001000101001
+00000000101110010000000000110010
+11000000010010001001010010011010
+00100010000000001011101111000010
+00100010111000000000100000011100
+00000010001000000100000000010000
+00000000000000000000000000000000
+10000000000001010010110110010000
+10011011000000100010011011000011
+00011010001100000000001010100100
+00000000101110010000000000100110
+11000000101010101000000100000010
+00101100000001011011101111000000
+00100010000001000000100010111000
+11000010001000000000000001000000
+00000000000000000000000000000000
+00001000010001000010110000000000
+10001011000000000010001011000000
+00011010001100000000001010000000
+00000001101100010000000010100000
+11000000000010100000000000000010
+00000110000000001011001100000000
+10100010010000000000100000110000
+00000010000000100000000100000000
+00000000000000000000000000000000
+00000000000001010110010000000000
+11011111000000000011011000000000
+00011110111100000000101110100000
+00000000111110010000000000110111
+11000000000011101000000000000011
+00101000000001001110101100000000
+10110010100000000000110010110000
+00001011000000000000001101010000
+00000000000000000000000000000000
+10100000000110011111110000001010
+11111111000000000011111100000000
+00001111111100000000001101110000
+00000000111111010000000010111011
+11000000010011011100000000000011
+11110000000000001111111100000000
+00111111110000001010111111110000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011101000001000000
+11001111000110000011111111000000
+00011111110010000000001101110010
+00000000110001011000000000111101
+01100000000011111100001100000011
+00010000000000001100111100010000
+00110011111000000000110011110010
+00000011001100000000000001110000
+00000000000000000000000000000000
+10000000000100001110010110001010
+10001111000000000010111111110100
+00000011100000100000001000100010
+00000000000010111000010100101110
+01100000010010111000001000001010
+00100010000000001010111101010000
+00100010110000000000101000100100
+00010010001000000000010000110000
+00000000000000000000000000000000
+10001000000001011100000100000000
+10100011000000100010110011000000
+00011011001000001100001011000000
+00000000100000110000001000101100
+01000000000110110000000100000010
+10001000000000001000001100000010
+00100000110000000000100100101001
+00000010001000100000000101110000
+00000000000000000000000000000000
+11000000000101011000000000000000
+10101011000000000010111011000000
+00001011101001100000001010101000
+10000000100010110000100000101110
+10100000010010110011100010000010
+10101010001000001010101100000000
+00100010110000000100101110111000
+00000010001100000000010001100000
+00000000000000000000000000000000
+01000000000101011110001000000000
+11101011000000000011111011000000
+00001011100110000000001111100011
+00100000110010111101000000111110
+01100000000011111000100000000010
+10100010000000001100101100000000
+10100010110000000000110110100000
+00000011000100000000010001110000
+00000000000000000000000000000000
+11100000000000011011010010000000
+11011111000000010011111111000000
+00001111110000000000001101110010
+00000000111111111000000000111111
+01000001000011111000000000100011
+01010000000001101111111100000100
+00111111111001000100111011100000
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010000000000000
+11101011000000000011111011000000
+00001111101101000100001111100101
+10000000111110111010000000110010
+11000000000011011001010000010011
+00100001000000101100101110100000
+00111110110010000000110000110000
+00001011000100000000010000100000
+00000000000000000000000000000000
+11001000000000010010000000000000
+10001111000000000010111111000000
+01001110101000000000001011000011
+10000000101110101100000000100010
+11100010000010001011000000000010
+00101000100000101000111100000100
+00101100111100000000110110110000
+00001010001100100000000001000000
+00000000000000000000000000000000
+11100000000001010100000000000000
+00100011000000000010110011100000
+00001011100000000000000011000000
+00000000101100110100000000100000
+11100000000010010000000000100010
+00001001001000001000101101000000
+01101100010101000000100000010000
+00000010001110000000000001010000
+00000000000000000000000000000000
+00100000000000010011011000000000
+10000111100000000010110111100010
+00001010011110000000001011011010
+00000100101101111000000000100001
+11100000000010010101100000100110
+00011110010000001000011110010000
+00101101111000000000100101011101
+00000010000010000000000001000000
+00000000000000000000000000000000
+01001000000010000000000000000000
+11100011000100000011110011000000
+00001111000000000000001111000100
+10000000101100110001000000110000
+11000000010011010000000000000011
+00001000010000001100001100000000
+00111100010000001000110000010000
+00000011000100100000001000000000
+00000000000000000000000000000000
+01000000000111011011000000000000
+11111111010000000011111111000000
+00001111111100010000001111110000
+00000000111111110001011010111111
+10000000000011101111000100000011
+11111100010000101111111101000000
+00111101110000000000111111010000
+00000011110100000000011001100000
+00000000000000000000000000000000
+10101000000001011110000000000000
+11001011010100010011111011001010
+10001111100100000000001111100000
+00000000111110110000000000101110
+11000000100011101011000000000011
+00100000000000001100101111010001
+10110000010000000000110010110000
+01000011001010100000000001110000
+00000000000000000000000000000000
+01001000000100011000010000000000
+10000111000000000010110111010000
+00001011011100000000001011010000
+00000000101101110000000000101101
+11000001000010001101000000010010
+00011000000000001010111100000000
+00100001110000000000111000110000
+00001010000100100000010001100000
+00000000000000000000000000000000
+11000000000000001001001000000010
+10000111101000000010110111100000
+00001011010110000000001011010010
+00000001101101011000000000101111
+11100000000010000111100000000010
+00010010000000001001011110000000
+00100001111000000000100001111000
+00000010001100000000000000100000
+00000000000000000000000000000000
+01001000000101001110100000000000
+10000011000000000010110011000000
+00001011001100000010001011000001
+00000000101100110000000001101100
+11000000000010000011110000001010
+00001100000000001011001100000001
+00100000111000000000101000111000
+00000010000100100000010000110000
+00000000000000000000000000000000
+11101000000101011011100000000000
+10001010000000000011111010000000
+00001011111000000000001111011000
+00000000111111100001100000111111
+10010010000011001110101000000011
+00011000001000101101101000000000
+00110010101000000000110011101010
+00000011001110100000010001100000
+00000000000000000000000000000000
+01001000000000001110000001000000
+11110000000000000011110000000000
+00001111100000000000001111100001
+01000000111110000000000100111110
+00000010001011111000000010000011
+11100010000000001110100000000010
+00111110000001000000111010001000
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11001001000000000011001001010000
+00001100100100001010001111100100
+01100000110010011000001000111110
+01101000000011000001000000010011
+00100100000000101100100111000000
+00101110011000000000111010010000
+00000011000000100000010000110000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10001001000000001010001001100000
+00001010100100000000001011100101
+00100000100010010000000100101100
+01100000001010001001000000100010
+10100101000001001101100110000001
+00101110010000000010100000010000
+00000011011000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000000010
+10001001000000000010001001000000
+00001000100100000000001011100100
+00000010100010010001000000101110
+01000000000010001001000000000010
+00100100010000011000100100000000
+00101100010001010000101010010000
+00000010000001100000000001000000
+00000000000000000000000000000000
+00001000000001000000010010000000
+10000001001000000010000001001000
+01001010000100000000001011100100
+00000000100000010000000001101100
+01000000000010000001001000000010
+10000100100000001001000110100100
+00101100011000000000100010110010
+00000010010000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000101000000
+11001000000000000011001000000000
+00001000100001010100001111100000
+00000000110010000000000000101110
+00000000000011001000010100000011
+00101000000000101100100001010000
+00111110000101000100111010000101
+00000011001011100000001101010000
+00000000000000000000000000000000
+10011000000111011111010001000000
+11111001001110000011111001000100
+01001111110100000111001111110100
+00010000111111010000000000001101
+01000000010011111101000100100010
+11010100010000001111100100010000
+00111111010000000000111111010001
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11101001000000000011001101000010
+00001111100100000000001111110100
+00000000111110010000010000110010
+01000000000011111101001000100011
+00110100000001001100110101100000
+10100011010100000000110011010010
+00000011000001100000000001110000
+00000000000000000000000000000000
+00111000000100001110100111000000
+10001000011010000010001000010000
+00001011100000000000001011100000
+00000000101110000000000010100010
+00000000000010111010010000000011
+01100001000001001000100001000000
+00110110000000001000111110000010
+10000010100011100000010000110000
+00000000000000000000000000000000
+00001000000001011100010000100000
+10100001010000001010000001000000
+00001011000100101001011011000100
+00010000101110010000000000100000
+01000000000010100001001111000010
+00000101000000101000000100010001
+00100010010010010000100000010100
+00001010010000100000000101110000
+00000000000000000000000000000000
+00011000000101011010010000000100
+10001001000000000010001001000000
+00001011100100000010010011100100
+00000000101110110000100000100010
+01000000010110111001000000000010
+01101100000000101000101100000000
+00100110110000000000101110010000
+00000010110001100000010001100000
+00000000000000000000000000000000
+10100000000100011110011101000000
+11101001000000000011001001000000
+00001111100110000000001111100110
+00110000111100011101000000110010
+01000010000011101001100100010011
+00100100100000001100100100000000
+00110000011000000000110010010010
+00001011011010000000010001110000
+00000000000000000000000000000000
+00101000000000011010010000000000
+01110001000000000011111001000000
+00001111100110010000001111100100
+10001000111110111000000000111110
+11110001000011110001100001000011
+11000111000000001111100100000000
+00111110011010000000111110010000
+00000011100010100000000001100000
+00000000000000000000000000000000
+00101000000100001000000100000010
+11001000000000000011001000000001
+01001111100000000000001111100000
+00010000111110000100000000111110
+00010000000011111000010000000011
+00100001000000001100100000000000
+00110010000000100000110010000100
+00000011000010100000010000100000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10001010000000000010001010100000
+00001011101000000000001111111010
+00100000101110100100010000101110
+10001000100010111010000000000010
+00111001000000101101111010000000
+00111011100000000000100011101001
+10000010100010100000000001000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10000011000000000010000011000000
+00001011001100000000001011001111
+10000000101100110010000001101100
+00100000000010110011100000100010
+00001100100000001000101100100000
+00100000111000000000100010110100
+00000010000010100000000001010000
+00000000000000000000000000000000
+10100000000000010001110010010101
+10000111001000000010000111010000
+00001011011100000000001010011100
+00000000101101000000010000101101
+10000000000110110111010000010010
+00010000000000001001001101000000
+00101101010000100000100001110000
+00000010001010000000000001000000
+00000000000000000000000000000000
+10101000000010000000111001000000
+11001111111100000011000111100000
+00001011011110000000001011011010
+00000000111101011001000000111101
+10100100000011111111100000001011
+00010110000000001100010110000000
+00110001111000000010110000111000
+00001011001010100000001000000000
+00000000000000000000000000000000
+00001000000111011010110110000000
+11111011000000001011111011000000
+00001111101100010000001111101100
+00000100111110000100000000111110
+10001000000011111011010000000010
+11000000000001001011100100000000
+00111000010000000000111110100000
+00000011110000100000011001100000
+00000000000000000000000000000000
+00000000000001011111111000100000
+11001111100000000011101111100000
+00001100011110010000001110111110
+01000000111011101001000000111011
+00100000010011001101110000100011
+01111010000000001100111110010000
+00110001101000000000110011111000
+00000011000000000000000001110000
+00000000000000000000000000000000
+10101000000100011001110001000000
+11010111000000000010000111000000
+00001101011100000001001000011100
+01000000100001000001110000100001
+00000001000010000101000000000010
+00010000000000101000010000110000
+00110101000010100000101011110000
+00000010101010100000010001100000
+00000000000000000000000000000000
+00000000000000001000110000000000
+10000111000000000010100101000000
+00001000111100000000011010111100
+00000001101001000000000000101101
+00000000000010000101100010000010
+00010001010000101000001100000001
+00100001010000000000100001110000
+00000010000000000000000000100000
+00000000000000000000000000000000
+00100000000101001100110100100000
+10010011000000000110000001000000
+00001001001101000000001000001110
+00000000100000001100110000100100
+00011000000010000001101000100010
+00000000010000101000100000000000
+00100100000000000000101000100100
+00000010100010000000010000110000
+00000000000000000000000000000000
+10101000000101011011110000000000
+11001111000000000011100011000000
+00001100111100011000001110101101
+00100000111010000100000000111110
+10000000000010001001100000001011
+00000001000000001100101100000000
+00110010110000000000110010110100
+00001011001010100000010001100000
+00000000000000000000000000000000
+10000000000000001100110001000010
+11111011000000000011111001000000
+00001111101100000000001111101100
+10000000111110000000000000111010
+10000100001011111001000000000011
+11100000000000001111101101000000
+00111110010000000000111110110010
+00000011111000000000000000110000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11001111000000000011111011100000
+00001101111100000000001100110000
+00000000011111001000000000111111
+10000000000011001101000100000010
+00110100000000001000110000000010
+00110011011010000010111011110000
+00000011100000000100010000110000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10101011000000000010111001100000
+00001000001100000000001010100110
+00000000101110000100000000101100
+10000000000010001001000000000010
+00100010000000001000100011000000
+10100010010000000100101010101101
+10000010001000000100000000010000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10001011000000000010111011001000
+00001001101100000000001000101110
+00000000101110000001010000101110
+00001000000010100011000000000010
+10100010000000001010100110000100
+00100000110000001000101000000000
+00000010101000000000000001000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10100011000000000010110001000000
+00001000101100000000001010000100
+00010000101100000000000001101100
+00000000000010100011000000001010
+10100000000000001010000000000010
+00100000010000000000100000000000
+00000010000000100000000100000000
+00000000000000000000000000000000
+00000000000011010111110000000000
+11000111000000100011111001000000
+00001101101100000000001100100100
+00000000111110000000000000111110
+00000000000011100111000000100011
+10100000000000001110100000000000
+00010010010000000000111010000000
+00000011100000000000001101010000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111101000000
+00001111111100000100001111010100
+00000000111101000000000000111101
+00000000000011011111000000000001
+01010000000001100101110000000000
+00111111010000001000111111000000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011111101000000000
+11111111001000000011001101000100
+00001100111010000001001111111010
+00000000111111101000000000111111
+11000100000011111100000000000011
+00111000000000001100110000000000
+00110011000000000000110011100000
+00000011001100000000000001110000
+00000000000000000000000000000000
+10000000000100001110101000000000
+10111111110100000010001101000000
+00001000100010000000001011101010
+00000000101110101000000000001111
+11011000000010111010100001000010
+00101110000010001000101010000010
+00100010101000000000100010101000
+00000010101000000000010000110000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110011000000000010000001001000
+00001010001100000000001011000000
+00000000101100100000000000101100
+11000100000010110001000000001010
+00000000000000001000000000000000
+00100000010000000000100000110000
+00000010001000100000000101110000
+00000000000000000000000000000000
+11000000000101011010100000010000
+10111011000000000010001001000000
+00101010100000000000011011100000
+00000000101110100000000000101110
+11000000010010111011000000010010
+00101110001000001000101100000000
+00100010110010000000100010110000
+00000010101100000000010001100000
+00000000000000000000000000000000
+01000000000100011110100000000000
+11111011000000000011001001000000
+00001110100001011000001111101001
+00000100111110110100100000111110
+11000000000011111000000000000011
+00101001000000101100100100000000
+00110010000100100100110010001001
+10000011000100000000010001110000
+00000000000000000000000000000000
+11100000000000011011110001000000
+10111111000000100011111001100100
+00001101110010000000001111111010
+01001000111111111001000000111111
+11000000000011111110000000000011
+11101000000000001111011100000000
+10111101101000000000111100000000
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11110011000000000011111111000000
+00101100100100110000001111100101
+00100000111110110100001000111110
+11000000000011100011010000100011
+10000001000000101100101100000000
+00110010010000000000110010010101
+00000011000100000000010000100000
+00000000000000000000000000000000
+11001000000001010010111001000000
+10111111000001100010111011000000
+00000000100000000000001111101110
+10000000101110110001100000101111
+11000000000010001011000000000010
+00101000000000001000101100000010
+00110110110010001000100010010000
+00010010001100100000000001000000
+00000000000000000000000000000000
+11100000000001010100001100000000
+00110011000000000010111001000000
+00001000001011000000001011000101
+00000000101100101100000000101100
+11000000010010100000000001001010
+01000000000000001000000000000000
+10100000000000000000100000101010
+00000010001110000000000001010000
+00000000000000000000000000000000
+00100000000000010001001000100001
+10110111100000000010110101100000
+00001000010110000000001010010110
+00000000101101111000010000101101
+11100000100010000011101100000010
+01010110000000001000001010000000
+00100100111000000000100001101000
+00000010000010000000000001000000
+00000000000000000000000000000000
+01001000000010000000010000000000
+11110011000000000011110001000000
+00001100001100000000001011001000
+00000000111100100000000000111110
+11000000000011100001011000000011
+11000000100000001100000000000000
+00110000010000000000110000110000
+00001011000100100000001000000000
+00000000000000000000000000000000
+01000000000111011011000000100000
+11111111010000000011111101000000
+10001111110100001001011111111000
+00001000111111110000000000111111
+11010000010011111111001000010011
+10110100000000000111111100000000
+00111111110000000000111111110000
+00000011110100000000011001100000
+00000000000000000000000000000000
+10101000000001011110100100100000
+11011011101100000011001101001000
+00001111101001100000001111100101
+10001000111110000110000000111110
+11001000000011111000000000000011
+00111010000000001110100100000000
+00110010101000000000110010010000
+00000011001010100000000001110000
+00000000000000000000000000000000
+01001000000100011001110010000000
+10110111001000001010000101000100
+00001011011100001000001011010101
+10100000101101010010101000101101
+11010000000010110011000000000010
+00001100000000001000011100000010
+00100001110000000000100001110000
+00000010000100100000010001100000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10010011100000000010000101100000
+00001011011110000000001011011110
+00000000101101001001000000101101
+11100000000010110111100000001110
+00010010000000001010001110000000
+00100000111000000000100000011000
+00000010001100000000000000100000
+00000000000000000000000000000000
+01001000000101001100110101100000
+10110011000000000010000001100000
+01011011001100000000001011001100
+00000000101100010010000000101100
+11000000000010110011000000000010
+00001101000000001000001101110000
+10100000111000000010100000111001
+01001010000100100000010000110000
+00000000000000000000000000000000
+11101000000101011010101000001000
+11011010000000000011001010101000
+00001111101000100000001111101000
+10000000111110100000100000111110
+10000000000011111110100000000011
+00111000110000101110011011000000
+00110011101010000000110011100100
+00000011001110100000010001100000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100001000000001111100010
+00000000111110000000000000111110
+00000000010011110000000100000011
+11100000000000001111100000000000
+00111110000000000000111100000000
+10000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110011010000000
+11111001000000000011111001000000
+00001111100100000000001011100100
+00000000111110011000000000111110
+01000000000011101001000000100011
+00100100000000001111100100000000
+00110010010000000000111110010000
+00000001000000100000010000110000
+00000000000000000000000000000000
+10000000000000000110111000000000
+10111001000000100010111001000000
+00001011101100001000011111101100
+00000000101110111000000000101110
+01000000000010001001100000000010
+00100100000000001011100101000010
+00110010010100000100101110010100
+00000010001000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000000001
+10111001000000000010111001000000
+00001011100100000100001011101100
+00000000101110010010000000101100
+01000000000010101001000100000010
+00100100000011001011100100001100
+00100010010000100000101110010000
+10000010100001100000000001000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001001010010010110001001000
+00001011000100000000001010000100
+00000000101100010000000000101100
+01001010000110000001001000000010
+00000100100000001011000100100000
+00100000010010000000101100010010
+00000010100000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000000000100
+11111000001000100011111000000000
+00001111100000000000001011100000
+00000000111110000000000000111110
+00001000000011101000000000000011
+00100000000000001111100000000000
+10110010000000000000111110000000
+00001011101011100000001101010000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111101001110
+00001111100100000000001111100100
+00000000111110010000000000111110
+01001010010011111101000100001011
+11110100010000001111110100010000
+00111011010001000000111111010001
+00000011011001100000011001110000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11111001000010000011011001000100
+00001111100100000101001111100100
+00000001111110010000001000111110
+01011000000011111001001000000011
+00100100000000001100100100000000
+10110010010010000000110010010010
+00000011110001100000000001110000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000010000000010001000010100
+00001011100000000000001001101000
+00000000101110000000000000101110
+00001000000010111000000000000010
+00100001010000001000100001010000
+00100010000100000000100011000101
+00000010110011100000010000110000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001000000000010010001001000
+00001011000110000000001011000100
+00001000101100010000000000101100
+01011000000010110101110000000110
+00010100000000001000010110000000
+00100001011001000000100001011000
+00000010110000100000000101110000
+00000000000000000000000000000000
+00011000000101011010010000100100
+10111001000000000010001001000000
+00001011100100000000001001100100
+01000000101110010000000000101110
+01000000010010111001000100010010
+00110100000100001000110110000000
+00100011010000010001100011010000
+00000010110001100000010001100000
+00000000000000000000000000000000
+10100000000101011110010100001000
+11110001000000000011011001000100
+00001111100100000000001111100100
+00000000101110010000000000111110
+01000000000011111001110000000011
+00100110000000001100100100000000
+00110010010100000010110010010100
+00000011111010000000010001110000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11111011000010000011111001000000
+00001111100100000000001111100110
+00000000111110010000001000111110
+01000000000011110001000000001011
+11000111000000101111000100000000
+00111110010000000000111110010000
+00000011110010100000000001100000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000111111000000000
+00001111100000000000001111100001
+00000000111110000000000000111110
+00000000000011001000001000001011
+00100010000000101100100000000000
+00110000000000000000111111000000
+00000011000010100000010000100000
+00000000000000000000000000000000
+00101000000001010010100000010000
+10111010100010000110111010000000
+00001011101011100001000011101010
+00100000101110101000000000101110
+10000000100010101010010000010011
+00101000000000001000101000000000
+00100010100000000000101110100000
+00000010000010100000000001000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110001000000000010110011000000
+00001011001101001000001011001100
+00000000101100110100100000101100
+11000000000010000011000000000010
+01001100000100001000001110000000
+00100000110000000000101100101000
+00000010000010100000000001010000
+00000000000000000000000000000000
+10100000000000010001110000000100
+10110101000000000010110111001000
+00001011010100000000001011011100
+00001000101101110000100000101100
+11101100000010100011000000001010
+00011100000000001000011101000000
+00100001010000000000101101101100
+00000010001010000000000001000000
+00000000000000000000000000000000
+10101000000010000001011000100000
+11110101100000000010110111110100
+00001111011110001000001111011110
+01000000111101111000100000111101
+11101010000011000101100000000011
+01001110000000001100001010000000
+10110001101000000000111100111000
+00001011001010100000001000000000
+00000000000000000000000000000000
+00001000000111011010010110000000
+01111001011010000011111011000000
+00001111100101100000001111101101
+10000000111110010000000000111110
+11000000000011111001000000000011
+11101100000000001111101000000000
+00111110000000000000111110110000
+00000011110000100000011001100000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11001110100000000011111111100000
+00001100111110000000001100111110
+00000000110011001000000100110011
+11100001000011001110100000000011
+00111010000000001100110110000000
+00111111111000000000111111001000
+00000011000000000000000001110000
+00000000000000000000000000000000
+10101000000100011001110001010000
+11010110000000000010110111000001
+00001000010000000000001101010100
+00000000110101110000000000110101
+11000000000011010110000100000010
+00011000011010001101010100000010
+00101101010001000000101101000000
+00000010101010100000010001100000
+00000000000000000000000000000000
+00000000000000001011010000000000
+10000110000000000010110111000000
+00001000111100000000001000111100
+00000000100111000000000000100100
+11000000000010000100000000001010
+00011000000000001000010000000000
+00101101100000000000101100011000
+00000010000000000000000000100000
+00000000000000000000000000000000
+00100000000101001100010110000100
+10010010000000000010110011000000
+00001000000011000000001001000110
+00000000100100010100010000100100
+11000000000010010000011000001010
+00001001000000001001000001000000
+00101100000100000000101100010001
+00000010100010000000010000110000
+00000000000000000000000000000000
+10101000000101011010100000000000
+11001001000000000011111111000000
+00001100101000100000001100100010
+00000000110110110000000000110111
+11000000000011001011100000000011
+00000111000000001100101110000000
+00111110111000000000111110100000
+00000011001010100000010001100000
+00000000000000000000000000000000
+10000000000000001110010000000000
+11111001000000000011110011000000
+01001111101000000000001111101100
+01000000111110110010000000111110
+11000000000011111011100000001011
+11100100000000001110101110000001
+00111110011000000000111110100000
+00010011111000000000000000110000
+00000000000000000000000000000000
+00000001000100001111100000000000
+11111101000000000011101111000000
+00001101111100001000001111110001
+00000000111111110000000000111111
+11000000000011110001000000000011
+01110100001000001100111000001000
+00111111100000100000111111110000
+00000011110000000100010000110000
+00000000000000000000000000000000
+10000001000001000110011001100100
+10111001100101000010111011000000
+00001010101100000000001011101110
+00100000101110010000000000101110
+11000000000010111001000000000010
+00100100000100001000101000000000
+00101110000000001000101110110000
+00000010111000000100000000010000
+00000000000000000000000000000000
+10000000000001010010100000000000
+10111000000000000010111011000000
+00001001100100100000001011100000
+00000001101110000000000000101110
+11000000000010111010000000000010
+01100010000000001000100100000000
+00101110110000000001101110000000
+00000010111000000000000001000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110000000000000010110011000000
+00001010000010000000001011000100
+00010000101100110000000000101100
+11000000000010110010000000000010
+00000000000000001000000100000000
+00101100010000000000101100000000
+00000010110000100000000100000000
+00000000000000000000000000000000
+00000000000011010110100000010000
+11111000000000000011100111000000
+00001101100100000000001111100000
+00000000111110000000000000111111
+11000000000011111000000000000011
+01100000000100001100100000000000
+00111110100000000000111110010000
+01000011110000000000001101010000
+00000000000000000000000000000000
+10100000000111011101010000000000
+11111100000000010011111111000001
+00001111010000000000001111010100
+00000000111101010000000000111111
+11000001000011111100000000000011
+11010000000000001011110000000000
+00111111000000000000111111010000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111111110010000011001111011000
+10000100110010000000001100110010
+00000000101111110000000000110011
+00001000000011101100100000000000
+01110000000000001100010010000000
+00111111001000000000111111011000
+00100011001100000000000001110000
+00000000000000000000000000000000
+10000000000000001110110000000000
+10111111010000000010001111000100
+00001010100110000000001000000000
+00001000101111110000000000100010
+10110000000010001000000000010010
+00100000000000001010100010000000
+00101100000000000000101100010010
+00000010001000000000011000110000
+00000000000000000000000000000000
+10001000000001011000110000000000
+10110011001000000010000011001000
+00001010100100000100101000000000
+00000000101100110000000000100000
+10010000100010100000000000000010
+11001000000100001000000100000010
+01101100000000000000101100100000
+10000010001000100000000101110000
+00000000000000000000000000000000
+11000000000101011110110000000000
+10111011000000000010001011000000
+00111010100110000000001000101010
+00100000101110110000000110100010
+10100010010010001000100010000010
+10101010001100001010100100000000
+00001110000000001000101110100000
+00000010001100000000000001100000
+00000000000000000000000000000000
+00000000000001011110110000000001
+11111011000000001011000011000000
+01001100000010100000001100100010
+00000001111110110000000000110000
+10000000000011101000110001000011
+11100000000000001100100000000000
+00111110001000000000101110010000
+00001011000000000000010001110000
+00000000000000000000000000000000
+11100000000100011011110000000000
+11111111000000000011111011000000
+00001101110100000000001111111000
+00000000111101110000010000111111
+10000000000011111100000000000011
+01110000000000001111110000000000
+00111111000100010000111111010000
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+01001100100100011000001110100001
+00000000110010110000001000111110
+10010000010011001000010010001011
+00111000010100001110100100000000
+00111010000000100000111010100010
+00001011000100000000010000100000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111111000001000010111111001000
+10100000100111000000001000101000
+00000000101011110000000000101110
+10100000000010001000110000100011
+01101000000000001000100100000000
+00100010000010010000100010101100
+00000010001100100000000001000000
+00000000000000000000000000000000
+11000000000001000000110000000000
+10111011000000100010110011000000
+10001001001001000000001010001000
+00000000100000110000000000101100
+10001000001010001000110000001010
+00100110100000001010000010010100
+00101100110000000000101010011000
+00000010011100000000000000010000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10110111100000000010110111100100
+10001001111110000001001000011010
+00000001101001111010000000101101
+11100101000010001100100000100010
+01011110000000101000010010010000
+00101101111001000000100001011000
+00000010010110000000010000010000
+00000000000000000000000000000000
+01001000010110000000110000001000
+11110011000000100010110011000100
+00001101001100000000001110001000
+00000000110000110001000000111100
+10000110000011000000001010010011
+00101100100000101110000100000000
+00111100110101000000111000100000
+10000011010100100000001000010000
+00000000000000000000000000000000
+01000000000011011011110000000000
+11111111000000010011111111010100
+00001110011100000000001111111000
+00000000111111110111100000001101
+11000100000011110111000000000011
+11111000000000001111110100000001
+00110011110001000000111111101000
+00000011100100000000010001100000
+00000000000000000000000000000000
+00001000000001011110110000000000
+11111011001000000011111011010000
+00101100001010000000001100101010
+00000000110010110100000010110000
+10011010000010011000000000000011
+01100100000100001100000010000000
+00110110110000000000110010010000
+00001011000000100000000001110000
+00000000000000000000000000000000
+01001000000000011001110000000000
+10110111010010000010110111001000
+00101000010100000000001010111100
+00000000110100110010000000100001
+11000000000010001100000000000010
+00011100000000001000010000000000
+00100011110000000000110001010000
+00000010000100100000011001100000
+00000000000000000000000000000000
+00100000000000001001111000000000
+10110111101000000010110111100100
+00011000111011000000001000011010
+00000000100001111000000000100001
+10100010000010010100100000010010
+01111110000010001000010110000000
+00100101111000000001100011101000
+00000010000010000000000000100000
+00000000000000000000000000000000
+01101000000101001100110000000100
+10110011000000000010110011000000
+00001000001101001000001010001111
+00000000100110110000000000100000
+11100000010010000011000000000010
+01001100000000001000000100000000
+00100000110000000000100010100000
+00000010000110100000000000110000
+00000000000000000000000000000000
+11101000000001001010100000000000
+11111010000000000011110010000000
+00101100111011000000001100111010
+11000000110010100000000000110000
+10000000101011010110000000001011
+01111001000000101100101000000000
+00110100100000000010110010100000
+00000011001110100000010001110000
+00000000000000000000000000000000
+01001000000100001010000000000000
+11111000000000000011111000010000
+01101111100001000000001111100000
+00010000111110000000000000111110
+00000001001011111000000000010011
+10000000100001001111100000000000
+00111110000000001000111011000000
+00000011110100100000000001100000
+00000000000000000000000000000000
+00001000000100001010010000000000
+11111001000000000011111001100000
+00001100100100000000001111100100
+00000000111110010000000100110010
+11000000000011001001100000001011
+00100100000000101100100111000000
+00111110010000000000110010010000
+00000011000000100000010000100000
+00000000000000000000000000000000
+10000000000001000010010000001000
+10111001000000000010111001010000
+00101010100111100010001011100100
+00000000101110010000000000101010
+01000001000010001001100100001010
+00100110000010001010100110000000
+00101110010110000000100010010000
+00000010101000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001001000
+00001000100100100000001011100100
+00000000101010010000000100101010
+01000000000010001001000000000010
+00100100100000001000100100000000
+00101111010000000010100011010000
+00000010000011100000000001000000
+00000000000000000000000000000000
+00001000000001001000010000000000
+10110001001000000010110001001000
+00001010000100000000001011000100
+00000000001100010010001000101000
+01101001001010001001000000001110
+00000100100000001000000100000000
+00101111010000000000100001010000
+00001010100010100000010100000000
+00000000000000000000000000000000
+10111000000111010110000101000000
+11111000010100000011110010010100
+00001100100000000100001111100001
+01000000111010000101000000110010
+00000000000011001000010101000011
+00100001010010001100100000000100
+00111110000101000000110011000101
+00000011001011100000001101010000
+00000000000000000000000000000000
+10111000000111011110010000000000
+10111001000100100011111001000100
+00001111110100000000001111110100
+00000100111110010001000000111110
+01000100000011111101000000010011
+11010100010000001111110100000000
+00111110010000000000111100010000
+00000011011001100000010001110000
+00000000000000000000000000000000
+00111000000001011110010000000000
+11111001000000000011001101000110
+00001100110100000000101100100100
+00000000110010010110000000111011
+01000010000011001101010000000001
+11110100010000001100110100000000
+00110001010100000000110011010000
+00000011001001100000000101110000
+00000000000000000000000000000000
+00011000000100001110000010000000
+10111000001000100010000000010000
+10001000100000000000001000100000
+10001000100010000100010000110110
+00010000000011111000001000001010
+00101000000000101000100000000000
+00100010000010000000111100000010
+10001010000011100000011000110000
+00000000000000000000000000000000
+01001000000000001000010000101000
+10110001010010000010000001001000
+00101000100110000000001000100100
+00100000100000010011000100100000
+01000000000010001001001000000110
+11000101100000001000100110000100
+00100000010000000100100100010000
+00001010100100100000000101100000
+00000000000000000000000000000000
+00011000010101001010010000010000
+10110001000000000010001001000000
+00001000101100000000001000100100
+00000010100000010000001000100110
+01000000000010111001000100001110
+00100100000001101000100100000000
+10100010010000000000001010010000
+00000010100001100000000000100000
+00000000000000000000000000000000
+10100000000001001010010000000000
+11111001000000001011001001000000
+00001100100110010000001100000100
+01000000110010010000000000111010
+01000000000011001001000011000011
+11100111000000001100000100000000
+00110010010000000010100110010110
+00000011101010000000010001110000
+00000000000000000000000000000000
+01101000000100001010010000000000
+11111001000000000011111001000000
+10001111100110000001001111100110
+00000000111110010000010000111110
+01001000000011111001100000001011
+11100100010000001111100100000000
+00111110010000000100111110010001
+00000011010100100000000001100000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11001000000000000011111000000001
+00001100100000000000001111100000
+00000000111010000000000000111100
+00000010000111001000000000000011
+00100011000000001100100000000001
+00111110000000001000110010000100
+00000011000000100000010000100000
+00000000000000000000000000000000
+00001000000001000010100000000000
+10001010000000000010110110000000
+00101000011010000001001011101000
+00000000101110100000000000101111
+10110000000010100110100000000010
+00111000000000001000111000000000
+00101111101000000000100011100000
+00000000000010100000000001000000
+00000000000000000000000000000000
+00001000000001010100110000000000
+10000011000000000010110010100000
+00001010001110100010001011001100
+00000000101000110000000000101100
+11010000000010000011100110000110
+00101110000000001010001100010000
+00101110110001000001101010110000
+01000010000010100000000001010000
+00000000000000000000000000000000
+00100000000100010001111011000000
+10000111001000000010110110010000
+00101010011100001000001011011100
+10000000101101110010010000101101
+10010000000010101111000000000010
+00011001000100001000011100000000
+00101111010000000000101001110000
+00000010001000000000010001000000
+00000000000000000000000000000000
+00101000000010001011111000000010
+11000111101100000011110110100000
+00101110011110000000001111011111
+00000000111001111011000000111100
+11100000010010000111100000001011
+00000110000000101110011110000000
+00111101111000000000111001111000
+00001011001000100000001000000000
+00000000000000000000000000000000
+00001000000101011010110110100000
+11111011000000000011111010000000
+00001101101100000000000111101100
+00101000111110110000000000111110
+10000000000011110011000000000001
+10101000000001001111101100000000
+00111110000000000010110110110000
+00000011110000100000010001100000
+00000000000000000000000000000000
+01100000000001001011111000000000
+11111111100010000011101110100000
+01001100011110000010001100111110
+00000001111111111001100000111001
+11100000010011000101100000000011
+00111010000000001100011110010000
+00110011011000000000111111111000
+00000011000100000000000000100000
+00000000000000000000000000000000
+10101000000100001001110000000000
+10110111000000100010000110000000
+00001000010100000000101000011100
+00000000111101110001000000111101
+00000010000010000100000000001010
+00111000010000001000011100000000
+00100001010001000000101101110000
+10000010001010100000011000100000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110011000000000010110110000000
+00001001111101000000001000011100
+00100000101101110000000000101101
+11000000001010001101000100000010
+00010001001000001000111100000000
+00100101010000000000101101110000
+00000010000001000000000000100000
+00000000000000000000000000000000
+01000000000101001000110000010000
+10110011000000000010010010000000
+00000001000100000000001000001111
+00000000101100110000000100101100
+00110000000010000000010101000010
+00101010000000001000001100000000
+00000100000000000000101100111100
+00000010000110000000000000100000
+00000000000000000000000000000000
+10101000000001011011110000000000
+10111111000000000011111000000000
+00001101001110000000001100111111
+00000000111111110000000000111000
+11110000000011001001110000000011
+00101110000000101100100100000000
+00110110110000000100111110110100
+00000011001010100000010001100000
+00000000000000000000000000000000
+10100000000100001110110000000000
+11111011000000000011100000000000
+01001110101110000000001111101100
+10000000111010110000000000111010
+10000000000011111001000001000011
+11101000000000001111100100000000
+00111010110000000000111110000100
+00000011111001000000000000110000
+00000000000000000000000000000000
+00000001000100001111110000000010
+11000111000000000011001111100000
+00001100110100000000001100111100
+00001000101111110000000000111111
+11000010000011011101000010010011
+00110100000000001100110110000000
+00110011111100000000110011110000
+10000011001010000000010000110000
+00000000000000000000000000000000
+10000001000001000110110000001000
+10001011000000000010001011000000
+00101000100110000100101000101100
+00000000101110110000000000101110
+10111000000010100011100000000010
+00101010000001001000000110000100
+00100010101000001000100010001101
+00000010001011000100000000010000
+00000000000000000000000000000000
+10000000000001010000110000000000
+10001011000000000010001000010100
+00001000101110000000001000101100
+00000000101110110000000000101110
+01100000000010011001100000000010
+00100010000000001000100100100000
+11100000010000000000100000110100
+00100010001000000000000001000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10000011000000000010000010000000
+00001000000100000000001000001100
+00000000101100110000000000101100
+00000000000010001000000000001010
+00000000000001101000000100000000
+00100000010000000000100000000000
+00000010000000100000010100000000
+00000000000000000000000000000000
+00000000000011010111110000000000
+11001111000000001011000011000000
+00001100100100000000001100111100
+00000000111111110000000000111110
+01000000000011011001000000001011
+00100000000010001100100100000001
+00110010010000000010110000110000
+00000011001000000000001101010000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+10001111110000000000001111111100
+00000000111111110000000000111111
+01000000100011111100000000000011
+11110000000100001111111100000000
+00111111000000000000111111000000
+00000011111010000000000001110000
+00000000000000000000000000000000
+11000000000101011101111000000000
+11111110100000010011111110100000
+00001111111100110010001101111100
+11000000111111011000010000110001
+01100000000011001101000000000011
+00110000000001001101110010000000
+00110011101000000000110011110000
+00000011001100000000000001110000
+00000000000000000000000000000000
+11000000000010001110111000000000
+10001010100001000010111000100000
+00001011111100100000101000111100
+01000000101110010000000100100010
+00000000000010101000100000000010
+00100110000000001011100100000010
+00100010110000001100100010000000
+00001010001100000000010000110000
+00000000000000000000000000000000
+11001000000001011100110000000000
+10100011000000000010110010000000
+00001011001100010000001011001100
+00000000101100010010100010101010
+01000000000010000001000000000010
+00000000000010001001000000000000
+10100010110000000000100000110000
+00000010001100100000000101110000
+00000000000000000000000000000000
+11000000000001011010110000000100
+10101010000000000010111000010100
+00001011001100000000001010101100
+00000000101110010000000000100010
+11100000000010101000100000000010
+00101110001000000011000110001000
+00100010110000100000100000111100
+00000000001100000000010001100000
+00000000000000000000000000000000
+10000100000100011110110000000000
+11101010000000000011111010100000
+00001011101100000010001111101100
+00000000111110110000000000110000
+01101000000011001000101000001011
+00100110000000001101100110000000
+00110010110001000000110010111000
+00000001000000000000010001110000
+00000000000000000000000000000000
+11100000000000011011110001000000
+11011110000010000011111100000001
+00001111111100000100101001111100
+00000000111111110000000000011111
+11000000000011110000000000100011
+11100100000000001111111100000010
+00111111110000000000111111000000
+00000000111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11011011000000000011111011010110
+00001110101100000000001100101100
+00000000111110010000000000111110
+01010000000011001011000000000011
+00100100000000001100101101100000
+00111110110100000100110010111100
+00001011000100000000010000100000
+00000000000000000000000000000000
+11011000000001010000111000000000
+00001010000010000010111001010000
+00001011111100000000001101111100
+00000000101110010000000000101110
+11000000000010101010100000010010
+00101110000100001000101101000000
+00101100111000000000100010111000
+01100010001101100000000001000000
+00000000000000000000000000000000
+11000000000001000000110000000000
+10010010110000000010110001010000
+00001011001100000000101010001100
+00000000101110010000000000100100
+01000000000010000001000000010010
+00001110000000000010000100000000
+00101100111000000000100000110000
+00000010101110100000000001010000
+00000000000000000000000000000000
+11110000000000000011011000000001
+10000111100000000010110101100000
+00001011011110010000001001011110
+00000000101101011000010001101111
+11100000000000100111110100000010
+00011110001000001010010110000000
+00101101111000000010100011111000
+00000000101111000000000001000000
+00000000000000000000000000000000
+01001000000110000000110010100010
+11010011000000000111110010000000
+10011111101100000000001110001100
+00000000111100010000000000111100
+01000100000011000001000010000011
+00000000010000001110000100000000
+00111110110000100100110000110000
+00001011100100100000001000000000
+00000000000000000000000000000000
+11000000100111001011110000000000
+11111111000000000011111110000010
+00001111111100000000001101111101
+01000000111111010000000000111111
+11000000000011111111000001001011
+11111100000000101101110100010000
+00111111110001000000111101110000
+00000011010100000000011001100000
+00000000000000000000000000000000
+00001000000001011110110000000000
+11011010010000000011111001010000
+00001111101101110000001100101101
+11000000111110110000000000111110
+01000000010011111001100000000011
+00101100000000001111101100000000
+00111100110000000000110010110000
+00000011001010100000000001110000
+00000000000000000000000000000000
+11001000100000011001110000000000
+10000111001010100010110101001010
+00001011111100110000001000011100
+00000000111001110000000000101101
+11000000000010110101000001000010
+00011100000000001011011100000000
+00101101110000000000100001110000
+00000010001100100000010001100000
+00000000000000000000000000000000
+00100001000000001011111000000000
+10010111100100000010110111100000
+00001011011110000000101000011110
+00000000101001011000000001101101
+01100000000010110011100000000010
+01010110000000001011011110000000
+00101111111000000000100001111000
+00001010001000000000000000100000
+00000000000000000000000000000000
+01101000000101001100110000001000
+10000011000000000010110011000000
+00001011001100000000001000001100
+00000000101000010000000000101100
+11100000000010110011110100000010
+01001101001000001011001111100000
+00101100010111000000100000110000
+00000010000100100000010000110000
+00000000000000000000000000000000
+11100000100001001010101010001000
+11011010000000000011111010010000
+00001011101000000000001100101000
+00000000111010100010000000111111
+10000010000011111110110100000011
+01111001000000001111111011000010
+00111111101100000010110011100000
+00000011001110100000010001100000
+00000000000000000000000000000000
+01001000000100001010000000000000
+11111000010000010011111000010010
+01001111000000000000001111100000
+00000000111010000000000000111110
+00000010100011111000000000001011
+10100001000001001111100000010001
+00111110000000000000111110000000
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001010010000001010
+11001001000000000011111001000000
+00001111100100000000001100100100
+00010000111110010000000000110010
+01000000000011111001100000000011
+11100100000000001111100100000100
+00110010010000000000110000010000
+00000011000000100000010000110000
+00000000000000000000000000000000
+10000001010001000000010000000000
+10001011000000000010111011101000
+00000011100100000100001000100100
+00000000111100010000000000100010
+01000000000010111001100000000010
+11100111100010000011100100000110
+00100000010100001000110110011000
+11000010001000000000000000010000
+00000000000000000000000000000000
+00011000000000010010010000000000
+10001011000000000010111001000100
+00001011100100000000001000100100
+00010000101110010000000000100010
+01000000000010111001001000000110
+11100100010000000001000101100000
+10100010010110000100100010010001
+00000010000001100000000001000000
+00000000000000000000000000000000
+00001000000001000010010000010000
+10000011000000010110110001000000
+01001011000100101000001000000100
+10100000101110010000000000100000
+01000000000010110001101000000010
+11000100100000001011000100000000
+00100010010000000000100100010010
+00000010000000100000000100000000
+00000000000000000000000000000000
+10111000000111010110000000000000
+11001000000000000011111000000000
+01001111100000100000101100100000
+10000001101110000000000010110010
+00010100000011111000000000000011
+11100000000000001111100001010000
+00110010000101000000110000000101
+00001011001011100000001101010000
+00000000000000000000000000000000
+11111000100111011101010000000000
+11111001000000000011111001000000
+00011111100100101001101111100100
+10100000111011010010100000111111
+01000000000011111111000100000011
+11110100010010001111110100000000
+10111111010000000000111111010001
+00000011111001100000011001110000
+00000000000000000000000000000000
+10111001000011011111010000000000
+11111001000000000011111001000000
+01001111100100101000001101100100
+11000000111110010100000000111100
+01010000000011110101001000000011
+00110100000010001111110100010000
+00111110010000000000110010010010
+00000011001001100000000001110000
+00000000000000000000000000000000
+01011001000000000110000000000100
+11101000000000000010111000000000
+00001110100000100000001010100010
+01000000101110001000000000101110
+00001000000010111000000000010010
+00100001010000001011100000000000
+00101110000010100010100011000110
+10000011000011100000010000110000
+00000000000000000000000000000000
+01001000000000000000010000001000
+10110001100000000010110001000000
+10011011000100101000001011000100
+10000000101100010000000000101100
+01001000000010110001010001000010
+00001110000000001011000100100000
+00101101011000000000100001010001
+00000010010100100000000101110000
+00000000000000000000000000000000
+00011000000101001010010010010000
+10101001000000110010111001000000
+00000010000100000000001010100100
+00000000101110010000000000101110
+01010100000010111011100000010010
+00100100010000001011101100000000
+00101101011000000010100011010010
+00000010000001100000010001100000
+00000000000000000000000000000000
+10100000100001001010011000001000
+11111001000000000011111001111001
+00000111100100000000001111100100
+00000000111110011000000000111110
+01010000000011111001110000001011
+00100110000000001111100110000000
+00111110010000000000110010010010
+00000011011010000000010001110000
+00000000000000000000000000000000
+01101010000100001010011000000000
+11111001000000100011111001100100
+00001111100100000000101111100100
+00000000111110010010000000011110
+01100000000011110001000011000011
+11100110000000001111100101000000
+00111110010000000000111100010000
+00001011110110100000000001100000
+00000000000000000000000000000000
+01101010000100001010000000000000
+11111000000000000011111000010010
+01001111100000000000101110100000
+00011000110010000000000000111110
+00000001100011001000010000000011
+00100010000000001111100000000000
+00110010000000000000110010000100
+00000011000010100000010000100000
+00000000000000000000000000000000
+10000000000001000010101000000000
+10111010100000000010111010101000
+00001011101000000000001010101000
+00010010100010100000011000101110
+10000000011010001110101001000010
+00111000000001001011101000001000
+00100010100000100000100010100000
+00000010000010100000000001000000
+00000000000000000000000000000000
+01001000000001010100011001000000
+10110011100000000010110011000000
+00001011001100000000101010001100
+00000000100000110000000000101100
+11000000000010000010010000000010
+00000100000000001011000100000000
+00100000110000000010100000111000
+00001010000010100000000001010000
+00000000000000000000000000000000
+01100001000000010001110000000000
+10110110000010000010110111000000
+00011011011100000000001010011110
+00001000000001110000010000101111
+11101000000010000101000000001010
+00010100000000001011010010000000
+00100001110000000000100001110000
+10000010001010000000000001000000
+00000000000000000000000000000000
+00101000100000000001011000000000
+11110111100000000011110111100000
+00001111111110010000101110111110
+00000000010001111000010000111101
+11110000000011000101100000000011
+00010110000000001111010110000000
+00110011101000000000110011101000
+00001011001010100000001000000000
+00000000000000000000000000000000
+01001010000101011010110000000001
+10111011011010000011111000000010
+00001111101100000010101111101100
+00000000111110110000001000111110
+11000000000011111001000000010011
+11100100000001001111000000000000
+10111110100000000000111110100110
+00000011110000100000011001100000
+00000000000000000000000000000000
+11100010010001001011111000001101
+11111111100100000010111101100100
+00001101111110001000001110111110
+00010010100011111001000001111111
+11100000000011111110100000000011
+00010110010000001100110110000000
+00110001111000000100110011111100
+00001011010100000000000001110000
+00000000000000000000000000000000
+10101001000000001001110000001000
+11100100000000000010110111010000
+00001101011100010000001000011100
+10000000100001110001000101101101
+11001000000010110101000100000010
+00010100000010001000010000100000
+00100001110000000000101001110001
+00000011111010100000010001100000
+00000000000000000000000000000000
+00010010000000001001110001000000
+10100111000000100010111101000000
+10001000011100000000001011011100
+00000100100001110001010000101101
+11000010000010110101010000000010
+00010100000010001000110100001000
+01100011100100000000100001100000
+00000010000001000000000000100000
+00000000000000000000000000000000
+01000000000101001000110001000100
+10100001010000000010110000000000
+01001001001100000000001001001100
+00000000100000110000000000101110
+11110000000010110001100001000010
+00001101000000001000000011000000
+10100000100000000000101000101101
+00000010110110100000010000110000
+00000000000000000000000000000000
+11111000000000010010011000000000
+11101001000000000011111010000000
+00001100111100000000101111111100
+00000000100011110000000000111111
+11110100000011111010010010000011
+00100110000100001100100110000000
+00110000010000000000110010010100
+00000011001011100000010001100000
+00000000000000000000000000000000
+10100100000100001110110000000000
+11101001010001000011111010010100
+00001111101100000000001110001100
+00000000111110110000000000111110
+11000000000011111001000000001011
+11100110000000001111100101000000
+00111110011000000100111110010000
+00100011111000000000000000110000
+00000000000000000000000000000000
+11000001000100001111010000001100
+11001101010010000011001111000000
+00001111101100000000101100101100
+00000000110011110000000000111111
+11000000000010101111000000000011
+11010000001000001100110100011000
+00110011000100000000110010000100
+10000011001000000000010000110000
+00000000000000000000000000000000
+10000001010000000100110000010000
+10100001010000000010101000010000
+00001110101100000000001101101100
+00001000100010110000001000101110
+11000000000010001001110000000010
+11100001001000101000100000000001
+00100010000000000000100010000000
+00000010001000000000000000010000
+00000000000000000000000000000000
+10000000010001010110110000001001
+10011011010000000010101001000000
+01001011001100000000011000101100
+00000000100010110000000000101110
+11000000000010101011100000000010
+11100100000000001000001100000000
+00100010010000000100100000010000
+00000010001000000000000001000000
+00000000000000000000000000000000
+00001010000000000010110000000000
+10101001000000000010100011000000
+00001011001100000000101001001100
+00000000000000110000000000101100
+11000000000010100001000000000010
+11000100000000001000001100000000
+10100010110000000000100000110000
+00001010000000100000000100000000
+00000000000000000000000000000000
+10000000000110000110110000000001
+11011011000000100011101001000000
+00001111111100000000001100101100
+00000000110010110000010000111110
+11000000000011101001000000000011
+11100100000000001100100100000000
+00110010000000000010110010000000
+00000011001000000000001101010000
+00000000000000000000000000000000
+10100010000111011111110000000000
+11111101000000000011110100000000
+00001110111100000000001111111100
+00000000111111110000001000111111
+11000000000011010101000000000010
+11111100000000001101010000000000
+00111111000000000000111111000000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11000100100000000011001100001000
+00001100011000000000001100111110
+00000000111111110100000000110011
+11000000010011110100100000000010
+00111100000000001100111100111000
+00110011011000000010110011101000
+00000011001100000000000001110000
+00000000000000000000000000000000
+10000000000100001110011000000010
+10001000100000000010001010110000
+01001000100001000001001000100110
+00000000101111110111000000101011
+11000000010010111000100000000010
+00111101010000001000111101000100
+00100010110000000000100010011000
+00010010101000000000010000110000
+00000000000000000000000000000000
+10001000000001011110110000000000
+10001010000000001010000010000100
+00001000001001000000001000001100
+00000000101100110000001000100000
+11000000000010110011000000001010
+00001100000000001000001100100000
+00100000010000000010100010010000
+00001010001000100000000101110000
+00000000000000000000000000000000
+11000000000101011010010000000000
+10001010000000000010001010100000
+00001000100100000000001000101100
+00010000101110110000000000101010
+11000000000010111001110000101010
+00101100000000001000001100000000
+00100010110000000000100010011000
+00000010101100000000010001100000
+00000000000000000000000000000000
+00000000000101011100110000000000
+10001000000000000011001001100000
+00101000101000001000001100101100
+00000000111110110000000000110010
+11000000010011111000110000001011
+00101100000000001100101100000000
+00110010010000001000110000001000
+00000010000000000000010001110000
+00000000000000000000000000000000
+11100000000000011011010001000000
+11111100010010000011111111000000
+00001111111000000000001111110100
+00000100111111110000001000111111
+11000000000011111100000000000011
+11111100000000001111101100000000
+00111111111100000000111111010000
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010110010000000
+11111010000000000011001010100000
+00001101101000100000001100101100
+00000000111110110000000000110010
+11000000000011111011100001000000
+00101100001000001100101100000000
+00110010010000100000110010010000
+01000001000100000000010000100000
+00000000000000000000000000000000
+11001000000001010010010100000000
+10110010000000000010000010000000
+00001000001011100000001000101101
+01000000101111110000000000100011
+11000000000010110000100000000010
+00111110000010001000111100000000
+10100010111100000010100010010010
+00000011011100100000000001000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110001000000000010010000000001
+00001000001001000100001000001100
+00000000101110110000000000100000
+11000000000010110000000010000010
+00101101000000001000001110000000
+00100010111000000000100000000000
+01000010001110000000000001010000
+00000000000000000000000000000000
+00100000000000010001111000000000
+00110100100000000010011100110100
+01001000110010000000001000010110
+00000000101100111000000000100001
+11100000100010110100100100000010
+00011110001000011000011111001000
+00100001111001000010100001011100
+00000010010110000000000001000000
+00000000000000000000000000000000
+01001000010010000000110000000000
+11110001010000001011010000000100
+00001100001000000100001100001100
+00010000111100110001000010100000
+11000001100011110001000000000011
+00101100000000001100001100010011
+00110010110000110000110000010000
+00000011000100100000001000000000
+00000000000000000000000000000000
+01000000000111011011110000000000
+11111100000000000011100100000101
+00101110110000000000001111111100
+00000000111111110100001100111111
+11000000000011111101000000001011
+11111100001000001011111100000000
+00111111110000000010111101010000
+00000011110100000000011001100000
+00000000000000000000000000000000
+10101000000001011110110111000000
+11111001000000000011110001000000
+00001100101000000000101100101100
+11100000111110110000000000110110
+11110010000011100000000000000000
+10101100100001101100101100101000
+00111110110000000010110010000000
+00000011111010100000000001110000
+00000000000000000000000000000000
+01001000000100011001110010100000
+10110100000000100010110111000000
+01001000011000000000001000010100
+10000000101101110110000000100111
+11010000000010000101000000000010
+00011100001000001000011101000000
+00101111110000000000101001010000
+00010010110100100000010001100000
+00000000000000000000000000000000
+11000000000000001001111010000000
+10110100100000000010111110100000
+00001000011010000000001000011110
+10000000100001111010010001101101
+11100000010010101101100000000110
+10011110100010001000011110000000
+00101101111000000000100101011000
+00000010111100000000000000100000
+00000000000000000000000000000000
+01001000000101001100110000001000
+10110000010010000010110010001000
+00000000001011001000001000001100
+00000000101100110000000001101100
+11000000000010000001000000000010
+00001100000000000000001100000000
+00101110110000000000101100010000
+00000010110100100000010000110000
+00000000000000000000000000000000
+11101000000101011010100000001100
+11111110000000100011111110010000
+00100000111011100000000100101000
+00000000110010100000000000111110
+10000000000011101110010000000011
+10101000000000000100101000000001
+00111110100000000000110111100000
+00000011111110100000010001100000
+00000000000000000000000000000000
+01001000010000001110000100000000
+11111000010001000011110000010100
+01001111000000000000001111100000
+00000000111110000000000000110110
+00000000000011111000001000000011
+11100000000001001111100000000000
+00111110000000000010111010000000
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110010001000000
+11111001000000000011111001000000
+00001100100100000000101100100100
+10000000111110010000000000111110
+01000000000011111001100000000010
+01100110100000000100100100000000
+00100010011000000000100010010000
+00000011110000100000010000110000
+00000000000000000000000000000000
+10000000000001000110110100100000
+10111001010010110010111001010000
+00001000100101000000101000101110
+00000000101110010000000000101110
+01000000010010110001010000000010
+00100110000001001000100100000000
+00100010011101000010100010010000
+00000010111000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000001
+00001000100100001000001000100100
+00000000101110010000000000101110
+01000000000010111001000100000010
+11000100000000101010000100010000
+00101010010000000100101010010000
+00000010110001100000000001000000
+00000000000000000000000000000000
+00001000000001001000010000000000
+10110001000000000010110001001001
+00001000000100100000001000000100
+00000000001100010010010000101100
+01001000000010111001000000000010
+10000100100000001010000100100000
+00101000011000000001101000010000
+00000010110000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000000011111010000000
+00101100100001010000101100100000
+00000000111110000101000000111110
+00010100000011111010000000010011
+11000001010000001110100001010000
+00111010000101000010111010100000
+00100011111011100000001101010000
+00000000000000000000000000000000
+10011000000011011110010000000000
+11111101000000010011111101000100
+00000111010100010000001111100100
+00000000111110010001000000111110
+01000100000011111101000000000010
+01100100010000001101100100010000
+10110111010000000000110111010000
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11111001000000000011011101000000
+00001100010100100000001100100100
+00000100111110010000100000111110
+01000000000011111101000000000011
+10110100010000001100110100010000
+00110011010000000010110011110000
+00000011001001100000000001110000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000010010001000010100
+00001000100001101000000010100000
+00000000101110000100000000101110
+00010100000010111000000000000010
+00100001010000001000000000000000
+00100010000010100000100010100000
+00100010000011100000010000110000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10111001100000000010010001000000
+00001010000100010000001000000100
+00000000101100010010100000101100
+01001010010010110001000000000110
+10000100100000101000000101100100
+00100010010000000000100000110000
+00000010010000100000000101110000
+00000000000000000000000000000000
+00011000010101011010010000000000
+10111001100000000010001001000000
+00001001000100001000001010100100
+00000100101110010000000000001110
+01000000000010111001001000000010
+00100100000000001010000100000000
+10101010010000000100000010110001
+00000010010001100000010001100000
+00000000000000000000000000000000
+10100000000101001010010000010100
+11110001000001000011011001001000
+00001110100101000000001100100110
+01000000101110010000000000011110
+01000000000011110001111000000011
+10100100000100001100100100000000
+00100000010000000000110000011000
+00001011011010000000010001110000
+00000000000000000000000000000000
+00101000010000001010010000100000
+11111011000000100011111001001000
+10101110100100000000001111100110
+00010000111110010000000000111110
+01000000000011111001100010000011
+11100100000000001101100100000000
+00110110010000100000111110011000
+10010011100010100000000001100000
+00000000000000000000000000000000
+00101000000100001010000001000000
+11111000000010000011110000010000
+01001101100001000000101101100000
+01111000111110000000010100111110
+00000000000011001000000100000011
+00000000001000001111100000001000
+00110010000000000000110010000100
+00000011110010100000010000100000
+00000000000000000000000000000000
+00101000000001000010100100000000
+10111010010001000010111110110000
+00101000111000100000001000101011
+00000000101110100000010100101110
+10000000000010001110100000000011
+01111000001001001011111001000000
+00100011101000000000110111100000
+00000010110010100000000001000000
+00000000000000000000000000000000
+00101000000001010100110100000000
+10110011010000000010110010110011
+10101000001000000000001001001101
+00000001101100110000001000101100
+11000000000110000011000000000110
+01001111000000001011000101000000
+00100000111000000100101000110100
+00000010110010100000000001010000
+00000000000000000000000000000000
+00100000000000010001100000000100
+10110111000000000010110110000010
+00001000011000000000001000011000
+00000000101101110010000000101100
+11101000000010000110000000000010
+01011100000000000011010100000000
+10100001110000100000101101110000
+00000010111010000000000001000000
+00000000000000000000000000000000
+00101000000010000001111001000000
+11110111100100010010110010100000
+00101100011110000100001101010110
+00110000101101111010001000111101
+11101100001011000111100000000011
+01011110000000001111011110000000
+00110011111000001000111001111000
+00000011111010100000001000000000
+00000000000000000000000000000000
+00001000000011011010100000010000
+10111011010000000011111011000000
+00001110101001000000001111100000
+00000000111110110110100000011110
+11011100000011110011000000000011
+11101100000000001111100100000000
+00111110010000000000110110110000
+00000011110000100000011001100000
+00000000000000000000000000000000
+01000000000001011111111000000000
+11111111100000000011111101100001
+00001100111011010000101100111110
+00000000101111111001100000110011
+11100000000011001111100000000010
+10111010010000101100110110000000
+00110011011000000000110011111000
+00100011110100000000000001110000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110110000000010010110110010000
+10001000010000111000101000011001
+00000000101101110000000000101001
+11000000000010000110000100000010
+00111000010000001000010000000000
+00100011010000000000100001110001
+00010010111010100000010001100000
+00000000000000000000000000000000
+00000000000000001001000000100000
+10110111000100000010110001000000
+10111001011110000100001000011100
+01100000101101110000001000100100
+11000000001010000110000000000010
+10011000000010001001001100000000
+00100001010000000010100101110000
+00000010110001000000000000100000
+00000000000000000000000000000000
+01100000000101001100001000000100
+10110011011000000000110011000000
+00001001000011000000101000001000
+00000001001100110000010000101000
+11000000000000000010000000000010
+00001000000000001001000000000000
+01100010010000000010100100111101
+00000010110110000000010000110000
+00000000000000000000000000000000
+10101000000101011010011000000000
+10111011010000000011111010100000
+00100001101010000000100100101110
+00000001101111110000000001110011
+11000000000011000011110000000011
+10101000000001001101000100000000
+00100010111000000110110110110000
+00100011111011100000010001100000
+00000000000000000000000000000000
+10000000000000001110000000000000
+11111011000000000011111011100000
+10001110001000000000001111101101
+00000101111110110000000001111110
+11000000010011111011111000000011
+11101100000001001110100100000000
+00111110110101000000111010110100
+00000011111000010000000000110000
+00000000000000000000000000000000
+00000001010100001111111001000000
+11111111000000000011111110000000
+00101100111100011000001100110111
+00000000110010110000001000110111
+11000000110011001111000000100011
+01011000000000001100110110100000
+00110011110000000000100011110000
+10000011001000000000010000110000
+00000000000000000000000000000000
+10000001000001000110101000000000
+10111011000000100010110011010001
+00001000101000000010101000000101
+00000000100010110000000000100010
+11000000000010001011110010000010
+00101101010001101000100100000000
+00100010011000000000100000110100
+01001010001000000100000000010000
+00000000000000000000000000000000
+10000000000001010010010000000000
+10111011000000000010111001000000
+00001000101000000000001000100000
+00000000100000110000000000100000
+11000000000010001010100000101010
+01101001000000011000100100000000
+10100010111100000000101010111000
+00000010001000000000000001000000
+00000000000000000000000000000000
+00001000000101000000010000000000
+00110011100000000010111011000000
+00011000001000000000001000100000
+00000000100000110000000000100000
+11000000000010001000000000000010
+00001000000000011000000000000000
+00100000110000000001101010010000
+00000010000000100000000100000000
+00000000000000000000000000000000
+00000000000011010110000000000000
+11111011000000000011111001000000
+01001100111100000000101100100000
+00000010110011110000000010110111
+11000000000011001010000000000011
+01101000000000001100100100000000
+01110010110000000010111010110000
+00000011001000000000001101010000
+00000000000000000000000000000000
+10100000000101011111000000000001
+11111111000000000011111111000000
+00011111011000000000001111110000
+00001001111111110000001000111111
+11000000001011110110000000000011
+11110000000000001111110000000000
+00111111000000000010110111000000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011111110000000000
+11001101100000000011011111001001
+00001100111100100010001100110010
+01000000110001001000001010110011
+11000000000011110100100000000011
+00010010000000001111110010000000
+00111101001000000000110011110000
+00100011001100000000000001110000
+00000000000000000000000000000000
+11000000000110001111111101000000
+10001001100000000000111111100001
+00001000111100101011001000100000
+00000000100010010000001100100011
+11010000000010111001000000000010
+10100010000000001011100010000000
+00101110100000000000101010111100
+00010010101100000000010000110000
+00000000000000000000000000000000
+11001000000001011100110000000001
+10000001000000000010010011010000
+00001000001100110001001000001000
+00000011100010100010100000100000
+11000100000010111000000000010010
+10000000000000011011000000000000
+00101100110000000000100100010100
+00000010001100100000000101110000
+00000000000000000000000000000000
+11000000000001011010110000000000
+10001001110000000010111011000000
+00001000101100000000001000101100
+00000000000010110000000000100010
+11000000000010111001000000000010
+10100011000000011011101000000000
+00101100111000000000101110011000
+00000010101100000000010001100000
+00000000000000000000000000000000
+11000000000101011110110000000000
+11001000100000000011011011000000
+00001100101100000010001100100000
+00010000110010000000000000110010
+11000000100011110001110100000011
+10100010000000001111100010000001
+00111110111000000000110100010000
+00000011000100000000010001110000
+00000000000000000000000000000000
+11100000000000011000110000000010
+11111101000000000011110011000001
+00001111111100000000001111110000
+00001000111111000000000000111111
+11000000000011111111000000000011
+11110100000000001111111000010000
+00111111110000011000111011010000
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11001000010000000011111011000000
+00001100101100000000001100101000
+00000000111110000000000000110110
+11100010000011001001010000000011
+00100101001000001100100000010000
+00111110111000000000110010110000
+00000011110101010000010000100000
+00000000000000000000000000000000
+11000000000001010011111000010000
+10001001101000000000111111000000
+10001000111100000000001000101100
+00000000101100000000000000100011
+11010000000000001001011000001010
+10100101100000001000101001010000
+00101110110000000000100010111000
+10000010111100100000000001000000
+00000000000000000000000000000000
+11000000000001000100110000001000
+10000000100001000000110011000000
+00001000101100000000001001100100
+00010000101100000000000000100100
+11000000000010000001000000010010
+01000010000000001001000010000000
+00101100100000000000100000010000
+00000010111110000000000001010000
+00000000000000000000000000000000
+10111000000100000101111000000000
+10010110100000000010110111100000
+00001001001110000001101001010110
+00000000101111011000010001100000
+11100000001010000111110100000010
+11011110000000011001010010000000
+00101111101100000010100001011100
+00000010111011000001000001000000
+00000000000000000000000000000000
+01001010000010000100110000100000
+11000011000000000011110011000001
+00001100001100000000001101001000
+00000100111100100000000000110100
+11000000010011000001000000100011
+01000100000000001101001000000000
+00111100110000000000110000110000
+00000011110100100000001000000000
+00000000000000000000000000000000
+11000000000101011011110000100000
+11101111000100000011111111000000
+00001110111100011000101110111101
+01001000111111110000000000111111
+11000000000011111101000000000001
+10111100010000001010111000010000
+00111111110000000000111111110001
+00000011110100000000011001100000
+00000000000000000000000000000000
+00001000000001011110110010100000
+11011011000000000011111011010110
+00001100101101101000001100000111
+00010000110010000000000000111010
+11010010001011000001000000000011
+10100000000000001111001010001000
+00110010111000000000110000010000
+00000011001010100000000001110000
+00000000000000000000000000000000
+11001000100110011000110010000100
+10000101000000000010110111001000
+00001000001100000000101000010100
+00000010100011000000000000101001
+11011000000010000111000000000010
+00011100000000001011011000000000
+00100001110000000000101001010000
+00000010101100100000010001100000
+00000000000000000000000000000000
+00100000000000000001111010000010
+10100111100011000110110111101001
+00111000011110100000001000111010
+00000000100001001000000000101001
+11101000000010101101110000000010
+10010110000000001011111010000000
+00100011110000100010101001111000
+00000010001000000000000000100000
+00000000000000000000000000000000
+01101000000001001100110000000000
+10100011101000000110110011000000
+00001000001100000100011000001100
+00000000100000000100000001101000
+11000000000010110001000000000010
+00001100000010001011001010010000
+00100010111000000000101000110000
+00000010100100100000010000110000
+00000000000000000000000000000000
+11100000000101010110100000000000
+11101110100000100011111010000000
+00001100101000000000001100101000
+00010000110011100010000000111000
+10000000000011101110010000000011
+10111001000000001111101000000000
+10110011100100000000111010100000
+00000011001110100000010001100000
+00000000000000000000000000000000
+01001000000000011010000000010000
+10001000000000000011111000000000
+00001111100000000000001111100000
+00001000111110000000100000110110
+00000000000001001000000001001011
+11100001000000001111100001000000
+00111110000100100000101110000000
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001000010000000000
+11001001000000000010110001000000
+00001000000100000010011100101100
+00010000111110010000000000110110
+01100000000011001001101010000011
+00100100001010001011101110100000
+00111110010000000010010000010000
+00000011000000100000010000110000
+00000000000000000000000000000000
+10000000000000000110011000000000
+10001001000000000010111001000000
+00001000100100000000001101100100
+00000000101110010000000000100010
+01100000000010000001010000000010
+10100100100000001001100111000000
+00111010010100000000100010010000
+00000010001000000000000000010000
+00000000000000000000000000000000
+00111010000001010010010001000110
+10001001000000000010111001000000
+00001010100100000000101000101100
+00000000101100010000000100100110
+01001000000010001011010000000010
+00100100100000001011100101000000
+00101110010000000000101010010000
+00000010000001100000000001000000
+00000000000000000000000000000000
+00101000000101000000010010100000
+10000001000000100010110001001010
+00101010000100101000001000000100
+00000000001100010000000000100000
+01101000001110000001000000000010
+10000100000000011001000100000000
+00101000110000000000101000011010
+00001010000000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000010000000
+11001000000000000011111000001000
+11001110100000100000001000100000
+00000000111110000101000000110100
+00010100000011001000010100000011
+00100000000011001111100000000000
+00111110000101000000111010000000
+00000011001011100000001101010000
+00000000000000000000000000000000
+11011000100101011110010000000100
+11111101000000000011110001000000
+10000101100100101100101111100100
+10100000111111010000000000111110
+01000100000011111101000000000001
+11110100000001000111100100000000
+00111001110000000100110111010001
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000010000011110010010101000
+11001001000000000011001001000000
+00001000100100000010001100100101
+00010000111110010000011010110011
+01011000000011001101010000000011
+00110100000000001100110100000000
+00111111010100000000110011110010
+00100011000001100000000001110000
+00000000000000000000000000000000
+01111000000110001110000100000000
+10001010000000000010001000000001
+00001000100000100001001000000000
+00000000101110000010100100100010
+00000000000010001000001000000010
+00100000000000001000100000000000
+00101110000000000000110110000100
+00000010100011100000010000110000
+00000000000000000000000000000000
+01001000000000001000010000000000
+10001001000001000010000001010000
+00001000000101001000001000000100
+10000000101100010000000000100000
+01011000000010000001000000001010
+00100100000000001010000100000000
+00101100010010000000100100010001
+00000010000100100000000101110000
+00000000000000000000000000000000
+00011000000001001010010000010010
+10001001000000000010001001000000
+00001000100100000000001000100100
+10000000101100010000000001100000
+01000000000010000001000100000010
+00100101000000001010100100000000
+00101100111000000000100110010010
+00000010100001100000010001100000
+00000000000000000000000000000000
+10100000000100011100010000000000
+11000001000000000011001001000000
+00101100100100000000101100100100
+10000000111110011000000000110010
+01000000010011001001000000000011
+00000100000000001110100100000001
+00111110010100000010110100010000
+00000011001010000000010001110000
+00000000000000000000000000000000
+01001000000000011010110000000000
+11111011100100101011110011000001
+00001111100100000010001111100100
+00000000111110011010000000111110
+01000000001011111001000000000011
+11100100000000101101100111000000
+00111110010000010010111110010000
+00000011110110100000000001100000
+00000000000000000000000000000000
+01001000000100001010000010001000
+11001000010000000011111000001000
+00001100100000000000001100100000
+00000000110010000000010000111110
+00000000000011001000000000000011
+00100000110000001111100000000001
+00111110000100000010110010000001
+00000011110010100000010000100000
+00000000000000000000000000000000
+00101000010001010010100000000000
+10001010010000000010111010100000
+00001000101000000000001101101000
+00000000100010100000010000111111
+10000000000010001110011100010010
+00111000000000001011111000000000
+00101111100000000000100011100000
+00000011100010100000000001000000
+00000000000000000000000000000000
+01101000000001010100110100000010
+10000010001000000010110011110001
+00101011101100000000001001001100
+00000000000100110000000000101100
+01000000001010000011110000010010
+00000110000000000011001100010000
+00101100111000000000100000010000
+00000010110010100000000001010000
+00000000000000000000000000000000
+10000000000100010001010000000001
+10000100000000000010110111000010
+00011011001100000001001001011110
+00000000100101110010000000001000
+01000000000010000111000000000010
+00011100000000001011011100000000
+00101101110100000000100001010000
+00000010101010000000000001000000
+00000000000000000000000000000000
+10001000100010001000011000000010
+11000110100100000011110011100010
+00101111011111110010001101011110
+10000000110101111100010000101101
+10100000000011001111100000001011
+00011110000000001111011110000001
+00111111111000000010110001011000
+00000011111010100000001000000000
+00000000000000000000000000000000
+00001010000101011010010000100100
+11111000010000000011111011001000
+00001100101100100000001111101100
+10110010111010110110000000111110
+00000000000011111001011010001011
+11101100000001001011101100000000
+00111110100000000100111110010000
+00000011110000100000011001100000
+00000000000000000000000000000000
+00000010000001001011101000000000
+11001111100100000011111100100000
+00001100111110000000001100111110
+00100000111111111100000000111111
+01100001000011101111100000000011
+00111110000100001111010110010000
+00110011011000000000110011011001
+00000011000000000000000001110000
+00000000000000000000000000000000
+10101000000110001001000000000010
+10000101000100100010110100011000
+00001000011100010100101000011100
+00000000101101110001000000101101
+01000100000010000111000000000010
+00011100000100001011010100000000
+00110101110001000000100001110000
+00000010101010100000010001100000
+00000000000000000000000000000000
+00000000100000001000000000000010
+10000111010110010010110000000000
+00111000011100000000101001011100
+00000000101101110000000000101101
+10000000000010100111000000000010
+00011000011000001011010100001000
+00100011010000000000100001010000
+00000110000000000000000000100000
+00000000000000000000000000000000
+00100000000001001000000000000000
+10000001000000010010110000000000
+00011000001100000000001001001101
+10000000101100110100000000101100
+00000000000010001001110000000010
+00001011100000001011000110000000
+00100100101000000000100000110000
+00000010100010000000010000110000
+00000000000000000000000000000000
+10101000000100011010110000000000
+11001010010000000011111010000000
+00101100111100000000001101111101
+00010000111111110000000000111110
+00000000000011101001000000000011
+00001111000000001111101100000000
+00110010100000100010110010010000
+00000011001010100000010001100000
+00000000000000000000000000000000
+10000000000000001110010000000100
+11111000000000010011111010010000
+00001111001100000010001110101100
+00000000111110110010000000111101
+01000000000011111001010100000011
+11101000000000001111101100000000
+00111110010100000000111110010000
+00000011111000000000000000110000
+00000000000000000000000000000000
+00100001000100001101010000001000
+11011110000000000011110110000000
+00001100111100000000001100111100
+00000000111111110000000000111110
+10000000000011001101000010000011
+00111100000000101100111000000001
+00111111101010000000110001010000
+00000011000000000100010000110000
+00000000000000000000000000000000
+10100001010001000110010000000010
+10001000011000000010111010000000
+00001100101100000000001000101100
+00000000101110110000000000101110
+00010000000010101001100000010010
+00101011110000001000100111000000
+00100110000100000000100010001100
+10000010001000000000000000010000
+00000000000000000000000000000000
+10000000000001010010100000000000
+10001010000000000010111000000000
+00001000101100000100101000101100
+00001000101110110000000000101110
+00010000000010001011100010000010
+00101100000010001000100110001001
+00101100000000000000100010011000
+00100010001000000000000001000000
+00000000000000000000000000000000
+00001010000101000000000000000000
+10000000000000000010110000000000
+00001000001100000000111000001100
+00010000101100110000000000101100
+01000000000010100011000000000010
+00001000000001001000000100000100
+00100100010000000010100000010000
+00000010000000100000000100000000
+00000000000000000000000000000000
+00000000000011010110000000000000
+11001010000000000011111000000000
+00101100011100000000001100111100
+00000000111111110000001000111110
+10000000000011000111000000000011
+00101000000000001100100000000000
+00111110000000000000110010010000
+00001011000000000000001101010000
+00000000000000000000000000000000
+10100010000101011111000000000000
+11111100000000000011111100000000
+00001110111100000000001111111100
+00001000111111110000010000111111
+00000000000011111100000000000011
+11111000000010000111110100000000
+00111101000000000000111101000000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011101011000000000
+11111111000000000011001111001000
+00001101110010010001001100111110
+00000000111111110011000000110011
+11001010000011001111100000000011
+11111100111010001111111110000000
+00110011110000000000110011100000
+00000011001100000000000001110000
+00000000000000000000000000000000
+10000000000100001110010000000000
+10111011100001000010001111110000
+00001000100010000001001000101110
+00000000101111110011000000111011
+11111010010010001011100000000010
+11111101000100001011101110000010
+00101011111100010000101010101100
+00010010001000000000010000110000
+00000000000000000000000000000000
+10001000000001011100010000000000
+10110011000000000010000011000101
+00101001001000100100001000001100
+00000000101100110000000000100000
+11000000001010000011000000000010
+11001100100000001011101100000000
+00100000110100000000100000000100
+00000010001000100000000101110000
+00000000000000000000000000000000
+11000000000101011010010000000100
+10111011000000001010001011000000
+01001000100000000000101000101100
+00000000101110110000010000101110
+11000000010010001011000000000010
+11101100000000001011101100000000
+00101010110000000000101010000000
+10000010001100000000010001100000
+00000000000000000000000000000000
+01000000000101011110010000000000
+11111011000000000011001011000000
+01001101100100000000001100100110
+01000000111110110000000000110010
+11000000000010001011000000000011
+11101100000000001111001100000000
+00110010110000000000110010111101
+00000011000100000000010001110000
+00000000000000000000000000000000
+11100000000000011011010000000000
+11110011000010000011111111000001
+01101111110100010000001111110100
+00001000111101110000000000111011
+11000000000011111111000111000011
+11111100000100001111111110010000
+00111111110000010000111101110000
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11101011000000100011001011100000
+00001111101100000010001101100100
+01100000111110110000000000111110
+11000000000011001011000000000011
+11101100000110001111101110000000
+00111110110000000000111110010000
+10000011000100000000010000100000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10001111000001000010000111010000
+00001011100100000000001011100101
+00000000101111110000010000101111
+11000000000010001011110000010010
+11111100000000001011101100000000
+00101101110000110100101110010100
+00000010001100100000000001000000
+00000000000000000000000000000000
+11100000000001010100010000000000
+10100011100100000010000011000010
+00001011100000000000001011001101
+00000000101100110000001000101110
+11000000000010000001010000000010
+01001100000000001011000101100000
+01101100110000001000101100110101
+01000010001110000000000001010000
+00000000000000000000000000000000
+00100000000000010011011000010000
+00000111100100000010000111100000
+00001011011110000000001011011110
+01000000101101111000000000101100
+11100000001010000101100010000010
+11011110000000001011010110000000
+00101101111000000000101100111000
+00000010000010000000000001000000
+00000000000000000000000000000000
+01001000000010000000010000000000
+11100011000000000011000011000000
+00001111001000000000001111001100
+00000000111100110000000000111100
+11000000000011000001000000000011
+01001100000000001111001100010000
+00111100110000000000111100110000
+00100011000100100000001000000000
+00000000000000000000000000000000
+01000000000111011011010000000000
+11111111000010001011111111000000
+00001111111100000000001111111100
+00000000111111110000000001111111
+11000000000011101101000000100011
+11111100011000001111111100000100
+00111111110000000100111111110001
+00000011110100000000011001100000
+00000000000000000000000000000000
+10101000000001011110010000000000
+11111011000000100011001011001010
+00001011100000000000001111101111
+11000000110110110011100000111110
+11000100000011001011101000000000
+00101110100000001100100101100000
+00111110110010000000111110110000
+00000011111010100000000001110000
+00000000000000000000000000000000
+01001000000100011001010000000000
+10110111001000001010000111010000
+00001011011100000001001011011100
+10110000100001110010000000101101
+11000010000010000111011010000010
+10001100001000001000010101101000
+00101101110100100100101101110000
+00000010110100100000010001100000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110011100000000010000111100000
+00001011011010000001001011111110
+10001000100101111010000000101101
+11100000000010001111100000000010
+00011110100000001000011110000000
+00101101111010000000101101111000
+00000010111100000000000000100000
+00000000000000000000000000000000
+01001000000101001100111000000000
+10110011000000000010000011000000
+00001011001100000000001011001110
+00000000100000110000000000101100
+11000000000010000011100000000010
+10001100000000001000001100000000
+00101100110000000001101100110000
+00100110110100100000010000110000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011001010000001
+00001111011001000000001111101000
+00100000110110100000000000101110
+10000000000011001010101000100011
+00101000000000101100101000000000
+00111110100000000000111111100100
+00000011111110100000010001100000
+00000000000000000000000000000000
+01001000000000001110000001000100
+11111000000000010011111000000000
+01001111100000001000001111100000
+00000000111100000000000000111110
+00000000001011111000000000000011
+11100000000000001111100001000010
+00111110000000010000111110000000
+10000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11110001100100000011001001000000
+00101100100100000000001100100100
+00000000111110010000000000110000
+01000000000011001001000000000011
+11100100000000001111100100000000
+00111100011000000000110000010000
+00000011000000100000010000110000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010000001000000
+00001000100100000000001000101110
+01000100101110010000000000100010
+01000001000010001011000000000010
+11100100000000001011101101000001
+00101110010001010000100010010010
+00000010001000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001010000001010001001000000
+00001000101100000000001000100100
+00001000101110010000000000100010
+01000000001010001001000000000010
+11100100000000001011100101000000
+00101110010000000000100010010000
+00000010000001100000000001000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001001000000010000001001000
+10001000100100000000001000001100
+00000000101100010010000000100000
+01001000000010000001000000000010
+11000100100000001011000100000000
+00101100010010000010100000010010
+00001010000000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000101000000
+11111000000000000011001010000000
+00001100100001010000001100100000
+00000000111110000101000010110000
+00010100000011001000000000000011
+11100001010000001111100000000000
+00111110000000000100110010000000
+00000011001011100000001101010000
+00000000000000000000000000000000
+10011000000111011111010000000000
+11111001000100000011111001000100
+00001111110100000000101111000100
+00000000101110010001010000111110
+01000100000011110001000001000011
+11100100010000001111100100000100
+00111110010001010100111111010001
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000000001011110010001000000
+11111001000000000011001101000000
+00001110100100000000001111100100
+00010000111110010000110000110010
+01000010000011111001000000000011
+11100100010000001111100100000010
+00101111010000000000111111010000
+00100001000001100000000001110000
+00000000000000000000000000000000
+00111000000100001110000000001000
+10111000010100000010001000010100
+01001000100000101000001011100000
+00000000101110000000000000101010
+00001010100010111000000000000010
+11000001010000001011100000000000
+00101110000000001000101110000000
+00000010000011100000010000110000
+00000000000000000000000000000000
+00001000000001011100010010000000
+10110001000000001010000001000000
+00001010000100000100001011000100
+00000000101100010000100000100000
+01000000000010110001000000000010
+11000100100000001011000100000000
+00101100010100001101101100010100
+00000010000000100000000101110000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000000000010001001000001
+00001000100100010000001011100100
+00000000101110010000000000101010
+01000000000010111001000000000110
+11100100000000001011100100100010
+01101110010000000001101110010010
+00100010000001100000010001100000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11111001000000000011001001000000
+10001110100110000000001011100100
+00000000111110010000000000010010
+01000000000010111001000000000011
+11100100000001001111100100000000
+00111110010000000000111110010000
+00000011001010000000010001110000
+00000000000000000000000000000000
+00101000000000011010011001000000
+11110011000000001011111001000000
+01001111100100000000001111100100
+00001000111110010000010000111110
+01000000000011111001000000000011
+11100100000000001111100110000000
+00111110010000010100111110010000
+10001011110010100000000001100000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11001000000010000011110000000000
+00001101100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000101100100000000000
+00111110000000001000110010000001
+00000011000010100000010000100000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10001010000000000010111110000000
+10001000101000000000001011101010
+10000000101110100000000000101110
+10000000000010111010001100000010
+11101000000001001000101000000000
+00101110100000000000100001100100
+00000010000010100000000001000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10000011100000000010110011000100
+00001001001100000000001011001100
+00000000101110110000000001101100
+11000000010010110011100000000010
+11001100000000001000001100010000
+00101100110001000000100100011100
+00001010000010100000000001010000
+00000000000000000000000000000000
+10100000000000010001111011000000
+00000101010000010010110011000000
+00001000011100110000001011011100
+00000100101101110010001000101101
+11001000000010110110000000000010
+11011110100000001000011000000000
+00101101111000000000100100110000
+00000010001010000000000001000000
+00000000000000000000000000000000
+10101000000010000011111010000010
+11000110100010000011110111100000
+00001101011110010001001111011010
+01001000111101111011000000111101
+11111010000011110111100000000011
+11011110000000001100011110001000
+00111100111000000010110101011000
+00000011001010100000001000000000
+00000000000000000000000000000000
+00001000000111011010110110100000
+11111011011000000011111010000000
+00001111101100100000001111100101
+10000000111110110000000000111110
+11000000100011111010000010000011
+11101100010000001111101100100010
+00111110010000000000111010110000
+00000011110000100000011001100000
+00000000000000000000000000000000
+00000000000001011111111000000000
+10111100100100000011001101100101
+00001100111110000000001110110110
+00000000111111111000100000111111
+11100000000011111101100100000011
+11111111000000001100110110010000
+00111111111000000000101111011001
+00000011000000000000000001110000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110101000100001010000111001100
+00101000011100001000001000011100
+00000000101101110000010000101101
+11000000000010110111000000000010
+11011100000000001000010000000000
+00101101110010010000101101010011
+00001010001010100000010001100000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110110000001010010000101000000
+00001000111100000000001011010000
+00000000101101110000000000101101
+11000000000010110101000000100010
+11011100000000001001010100000000
+01101101110000000000101100010000
+00100010000000000000000000100000
+00000000000000000000000000000000
+00100000000101001100110000000001
+10110011000000000010000010000000
+00011000001110100000001001000100
+00000000101100110000010000101100
+11000000000010110011000000000010
+11101100000000001001000100000000
+00101100010000000000101100010000
+00000010000010000000010000110000
+00000000000000000000000000000000
+10101000000101011011110000000000
+10111011000000000010001010000000
+00001100111100000000001011101100
+00000000101111110000001000101111
+11000000000011111011000000000011
+11111100000000001101101100000000
+00111110110000000000111110010000
+00000011001010100000010001100000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011010000000011111011000000
+00001111101100000000001100101000
+00000000111110110000000000111110
+11000000000011111000010000000011
+11101100000010001110100001000010
+00111110110000000000111110000100
+00010011111000000000000000110000
+00000000000000000000000000000000
+00000001000100001111110000000010
+11001011001000000011001110000000
+00001111111100000000001100111000
+00000000111111110000000010110011
+11000000000011111111000000000011
+11101100000001001100111010100000
+00111111110000000000111111010000
+00000011000000000100010000110000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10000011110000100010001010100000
+00001011101100000010001000100000
+00000000101110110000000001100010
+11000000000010111000011000000010
+11101100000001001000100000000001
+00101110011000000000101100010000
+00000011011000000100000000010000
+00000000000000000000000000000000
+10000000000001010000110000000000
+10011011000010000010001010100000
+01001011001100000100001000100100
+00001000101100110000001000100010
+11000000000010111000100000000010
+11101100000000001000101101000010
+00101110010001000000101110010110
+00000010001000000000000001000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10000011000000000010000011100000
+10001011001100000000011000001010
+00000000101100110000000000100000
+11000000000010110000000000000010
+11001100000011001000000000000000
+00101100010000000100101100010000
+00000010010000100000000100000000
+00000000000000000000000000000000
+00000000000011010111110000000000
+11011011000000001011001010000000
+01001111111100000100001100100000
+00000100111111110000000001100011
+11000000000011111000000000000011
+11111100000000001100101000000010
+00011110010000000100111110010000
+00001011000000000000001101010000
+00000000000000000000000000000000
+10100000000111011111110000000000
+01111111000000000011110110000001
+00001111011100000000101111110000
+00000000111111110000010000111111
+11000000000011111100000000100011
+11111100000000001111110000000000
+00111111010000010100111111010000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011101110010000000
+11111101100000000011101100100000
+00001100110110000000001111110010
+00000100110011110010010000110011
+11000000000011001100010000000011
+10110000000100001100110110000000
+00110011010010000000110011110100
+00100011001100000000000001110000
+00000000000000000000000000000000
+10000000000100001111111101001000
+10111001100000000010001001100000
+10001000100110000010001011100110
+00000000100011110101000100100011
+11010000000010001000001000000010
+10100000001101001000001100001100
+00100010010101100000101011110101
+00010010001000000000010000110000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10111011000000000000100010000000
+00001000000000000000001011100000
+00000000100000110010100000100000
+11010001000010100000000000010010
+00000100100010001000001100100000
+00100000010010000000100100110010
+00000010001000100000000101110000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000001000010001011000000
+00101000100110000000001011100100
+00000000100000110000010010100010
+11000000001010100000010000000010
+10100110000000101000101100000000
+00100010010000000000001110110000
+00000010001100000000010001100000
+00000000000000000000000000000000
+01000000000100011110110000000000
+11110001100100000011100000010010
+00001100100011001000001111100010
+00000000110010110000000000110010
+11000000000011101011010100000010
+10100010100100001100101110010001
+00100010010000000010110110011000
+00001011000100000000010001110000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111101000000000011111101000000
+00001111110000000010001111111110
+10000000111111110000000000111110
+11000000000011011001100000000011
+11110000001000001111111100000000
+10111100010000001010111001011001
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010110000000100
+11001011001001000111111010010001
+10001111100100000000011111100000
+10000000111110110000000000111100
+11000000000011001011010000000011
+00100101000000001111101100001000
+00110010010000000000110010010000
+00001011000100000000010000100000
+00000000000000000000000000000000
+11001000000001010011111000000000
+10001011110000000010111011000000
+00001011100100000000011111001100
+00010000101111110000000000101111
+11000000000000001001111000000001
+00100100000100001011101101000000
+00110011010000001000100010011010
+00000010001100100000000001000000
+00000000000000000000000000000000
+11100000000001010100110000000001
+10000011000100000010110000000000
+00001011000100000010001011001001
+00000001101100110000000000101100
+11000001000010000000001000101010
+00100000000001001011101100000010
+00100000010000010000101000010000
+01000010001110000000000001010000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10000111100000000010110100100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000001010000110100101001010
+01010010000000001011011110000000
+00100101011000000000101000011000
+00000010000010000000000001000000
+00000000000000000000000000000000
+01001000000010000000110000100000
+11000011000000000010110011000000
+00001111001000000000001011001000
+01000000111100110000000000111100
+11000110000011000001000100001011
+00000100011000001111001100100000
+10110000010010000010111000010000
+00000011000100100000001000000000
+00000000000000000000000000000000
+01000000000111011011110000100010
+11111111000000000011111111010100
+00001111111100000000001110111101
+00000000111111110000000000111111
+11000001000011111111000100000000
+10110100000000001111111100000000
+00111011010000000000110111011001
+00000011110100000000011001100000
+00000000000000000000000000000000
+10101000000001011110111010000010
+11001011000000000011110000101000
+00001100101110000000001100100001
+00000000111110110010100000111110
+11010010000011111010000001000011
+00110000000000000011101100000001
+00111110011000010000110010110010
+00000011001010100000000001110000
+00000000000000000000000000000000
+01001000000100011000110011000000
+10000111000000000010110100000000
+00001000010100000001001000011100
+00000100101101110000000000101101
+11011000000010110010000000000010
+00010100000000001011011100000001
+00101101010110000000100000110001
+00000010000100100000010001100000
+00000000000000000000000000000000
+11000000000000001001111010000000
+10000111100000000010111111100000
+00001000111110000000101000010010
+00100000101101111001000000101101
+11101000000010110111110000000010
+00011110000000001011011110000100
+00101100010000000000100001111000
+00000010001100000000000000100000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10000011000000000010110011000000
+10001000001101010000001000001100
+00010000101100110000000000101100
+11000000000010111011110000000010
+00001100100000001011001110010001
+00101100010000000000100000110001
+00000010000100100000010000110000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11001010000000000011111010000000
+00101100111010000000001100101010
+00000000111110100000000000111110
+10000000000011111110100000001011
+00111001000000001111101000000010
+00111110100000000110110010101000
+01001011001110100000010001100000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000010011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000001111000000010000011
+11100000000000001111100000000000
+00111110000000000000111110000100
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001100000000011111011000100
+00011111100100011000001111101101
+00000000111110010000000010110010
+01000000000011111001000000000011
+00000100100000001100100110010001
+00110010010000000000110010010000
+00000011000000100000010000110000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001100000000110111001110000
+00001011100100000000001011100101
+00000000101110010000000000100010
+01000000000010111001000000000011
+01100111100000001101000111100000
+00100010010000000100100010010110
+00000010001000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001001000000010111001000010
+00001011100100000000001011100100
+00000000101100010000001001100010
+01000000000010111001000000000010
+00100100000000001000100100000000
+10100000011000000000100000010000
+00000010000001100000000001000000
+00000000000000000000000000000000
+00001000000001000000010010100000
+10110001000000000010110001000000
+00001011000100000000001011001100
+00000000101100010010100001100000
+01001000000010110001001000000010
+01000100100100001001100100000000
+00100000011010000010100000010010
+00001010000000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000010000000
+11111010000000000010111000000000
+00001011100000000000001111100000
+00000000111110000111000000110010
+00010100000011111000010100000011
+00100001010000001100100001010000
+00110010000101000000110010000101
+00000011001011100000001101010000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111101000000100011111001000000
+00001111010100000000001111100100
+00000000111110010000000000111110
+01000100000011111101000100000011
+11111100010001001111110100000001
+00111111010001000000111111010001
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000000001011110010010100000
+11111101000001000011111001000000
+00001111100100000010001111100100
+00000000110010010010000000111011
+01001000000011001001001001000011
+00101101000000001100000101000000
+00111110010100100000110010010010
+00000011000001100000000001110000
+00000000000000000000000000000000
+00111000000100001110000100000000
+10111000000000010010111000000000
+00001011100000000000001011100000
+00000000100010000110100000100010
+00011010010010001000011010000011
+00100001110000001000100000100000
+00101110000100000000110111000110
+10000010000011100000010000110000
+00000000000000000000000000000000
+00001000000001011100110000000000
+10110001000000000110110001000000
+00001011001100000000001011000100
+00010000100000010001010000101000
+01000100000010010101010000000010
+01010100100000001000010100000000
+00101111010010000000100001010001
+00000010010000100000000101110000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001001000010010111001110000
+00001011100110000000001011100100
+00000000100010010000010000100010
+01000000000010010011010000000010
+00011100000000000000110100000001
+00101111110000000000100101010000
+00000010010001100000010001100000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11111001000000000011111001000000
+00001111100101100000001111000100
+00000000110010010000000000111010
+01000000000011011001000000000011
+01100111000000001100100110000000
+00111100010000000000110010010000
+00000011011010000000010001110000
+00000000000000000000000000000000
+00101000000000011010110000001000
+11111001000000000011111011000001
+01001111101100000000001101101100
+00000010111110010000000010111100
+01000000100011101001000000001011
+11100110010000101111100100100000
+00111110010000100000111110010000
+10000011100010100000000001100000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000100000011001000010000
+10001111100011000000001111100000
+00000000111110000000000000110010
+00000000000011001000010000000011
+00100000000000001100100000100000
+00110010000001000000111110000000
+00000011000010100000010000100000
+00000000000000000000000000000000
+00101000000001010010100000010000
+10111110110000000010001010100000
+00001011101000000010001011101000
+00000000101110100000000000100010
+10001000000010001010010001000010
+00101000000100001000101001001000
+00100010100000000100101110100000
+00000010100010100000000001000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011110010001010010011000000
+00001011001100000000001011001100
+00000000101110110000000000100000
+11100000001010000011100010000010
+00001110000000001010001110000001
+10100000111100010000101100111100
+00000010000010100000000001010000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110111100000000010010111010000
+00001011011100000000001011011100
+00000000101100110010000000100001
+11100000000010000111010000000010
+00011101000001001010111110000000
+00100001110000010000101101111100
+00000010101010000000000001000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110101100000000011010110100010
+00001111010110010000001111010110
+00000000111101111010000010110000
+11000000000011001111100000001011
+00111110000000101110011110000000
+00110001111000000000111111110000
+10001011001010100000001000000000
+00000000000000000000000000000000
+00001000000111011010110000100000
+01110011000000000011101010001000
+00001111100101000000001111100001
+00000000111110110101000000111110
+11000001000011111011000000010011
+11101100000000001101101100000000
+00111110110000010000111110110110
+00000011110000100000011001100000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11111111100000000011111111100000
+00001111111010000000001111111111
+00000000111111111100000000110011
+11100001000011001101100000000011
+00110110010000001111111010000100
+00110011101000000000110011001000
+00000011000000000000000001110000
+00000000000000000000000000000000
+10101000000100011001010000000100
+10110111000000000010110111000100
+00001011011000000011001011011101
+00000100101101110001000000100011
+01000000000010000111000100000010
+00011100110000001011011100011001
+00100001100001000010100001100000
+00000010001010100000010001100000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110110000100000010110100010000
+00001011010001000000001011010100
+01100000101100110000000000100001
+11000100000010000001000000000010
+00010101000000001011011000000000
+00100001110000000010100001010000
+00000010000000000000000000100000
+00000000000000000000000000000000
+00100000000101001100010000010000
+10110001000001000010110000000000
+00001011000010010100001011000011
+00000000101100110000000000100010
+01000000000010000011000000000010
+00000100000000001011101010000000
+10100010110000000000100000110000
+00000010000010000000010000110000
+00000000000000000000000000000000
+10101000000101011010000000000000
+11111001000000100011111001000000
+00001111101101000000001111101010
+00000000111111110000010010110010
+11000000000011001010000001001011
+00101000000000001111100100000000
+00110010010000000000110010110000
+00000011001010100000010001100000
+00000000000000000000000000000000
+10000000000000001110100000000100
+11111000010000000011111001000000
+00001111101100000000001111101101
+00000000111110110000000000111110
+11000000000011111011010100000011
+11101101000000001111100100000000
+00111110010100000010111100110100
+00000011111000000000000000110000
+00000000000000000000000000000000
+00000001000100001101001000000000
+11001101000000110011111100110000
+00001111111100000000001111110000
+00101000111111110000000000111111
+11000000000011000110101000000011
+00111000000000001100110100010000
+00110010110000000000110010111000
+00000011000000000100010000110000
+00000000000000000000000000000000
+10000001000001000110101000010000
+10001000100000000010111000100000
+00001011101110000100001011100000
+00000000101110110000000000101110
+11000000110010001011010000001010
+00101001000000001000100100000000
+00100010111101000000101010111000
+00000010001000000100000000010000
+00000000000000000000000000000000
+10000000000001010010000001000010
+10001001110000000010111011000000
+00001011100000010001001011101000
+00001000101110110000000000101110
+11000000000010001000000000000010
+00000000000010101000101000000000
+00100010000000001000100010000110
+00000010001000000000000001000000
+00000000000000000000000000000000
+00001000000001000000001000000000
+10000001000000000010110011000000
+00001011000000000000001011001100
+00001100101100110000000000101100
+01000000000010000000000000000010
+00001100000000001000001100000000
+10100000000000000000101000000000
+00000010000000100000000100000000
+00000000000000000000000000000000
+00000000000011010110000000000000
+11001000000000000011111000000000
+00001111100000000000001111100000
+00000000111111110000000000111110
+11000000000011001000000000000011
+00100000000000001100000000000000
+00110010000000000010110010000000
+01000011000000000000001101010000
+00000000000000000000000000000000
+10100000000111011111000000000000
+11111101000000000011111100000001
+00001111110000000000001111110000
+00000000111111110000010000111111
+01000000000011111100000000000011
+11110000000000001111110000000000
+00111111000000000000111111000000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111111100000000111101111010000
+00001100011100100000001111111100
+00000000010011111000000000111111
+11001000010011001111001100000011
+00111110000000001111111110000000
+00110001111000000000110011011000
+01000011011100000000000001110000
+00000000000000000000000000000000
+10000000000100001110110000000000
+10111111110000000010001011010100
+00001000111111010000001011111101
+10100000101010111000010000101111
+11000100000010000111001000000010
+10100110000101001011101110000001
+01101010111000000000101010011000
+01010010001100000000010000110000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110011000100000010100011001000
+00001000001100000100000011001101
+00000000100000010000000000101100
+11001010000010000011001100010010
+00001100000000001011101100000000
+00100100110000000000100000010000
+00000010011100100000000101110000
+00000000000000000000000000000000
+11000000000101011010110000010000
+10111011000000000010000011000000
+00001000101100000000001011101100
+00001000101010010000000000101110
+11000000000010001011000000000010
+10100100000000001011101100000000
+00101110110000100000101010010000
+00000010001100000000010001100000
+00000000000000000000000000000000
+01000000000101011110110000000000
+11111011000000000010101011000000
+01101000101100000000001111101100
+00000000110010110000000000111110
+11000000001011001011000000000011
+00101110010001001111001100000000
+00100110110100000000110010011000
+00000011010000000000010001110000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000011111011000000
+00001111111100001000001111011100
+00010000111111111001010000111101
+11000000000011110111000000000011
+11110100000100001111111110010000
+00111011011100000000111111011001
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11110011000000000011001011000001
+01001110101100000000001100101100
+00000001110010010000100000111110
+11000000001011001011000000000011
+10101110000000001111101100001000
+00111110110000000000110010010000
+00000011110101000000010000100000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111111011000010010001111000000
+00001000111101000000001000111100
+00000000101010010000000000101111
+11000000010010001111000000000010
+00100100000000001011101111000000
+00101100110000100000110100011000
+00000010111100100000000001000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011100010000010000011000001
+00101010001110010000001000001100
+00000000101000111100000000101100
+11000000000010000011000000000010
+00001100100000001011000101010000
+00101100110000000000100000011001
+00000010111110100000000001010000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10110111100000000010000111100000
+00001000011110000100001000011110
+01000000101001111000100000101100
+11100000000010000111100000000000
+00011110000000001011011110000000
+00101111111000000000100101011000
+00000010111111000000000001000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11110011000000000011000011000000
+00001110001100000000101100101100
+00000000100000110000001000111100
+11000000000011000011000000000011
+00001100000000001111000100000000
+00111100110000000000110000010000
+00000011110100100000001000000000
+00000000000000000000000000000000
+01000000000111011010110000000000
+11110011000000001001111011000000
+00001111101101000000001111101100
+00000000010110110000000000111110
+11000010000011111011000010000011
+11101101001000001111101101001000
+00111110110000000000111110010001
+00000011110100000000011001100000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011010000000011111011000000
+10001001001101010000001110101111
+01000000110010110011100000101110
+11010010000011111011010000000011
+11101101000000001011100101000000
+00111100110000000100110110010000
+00000001111010100000000001110000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110111010010000010110111001000
+00001000011100000100001000001100
+10100000101001110000000000101101
+11000000000010110111001010000010
+11011100000000001011011100000000
+00101101100000000000100001110000
+00000010111100100000010001100000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110111100000000010110011101100
+00001001011110100110001010011110
+00000000100001111000000000101101
+11101000010010110111100000100010
+11011110100000001011010110000001
+00101011111000010000100101011000
+00000010111000000000000000100000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010111011000000
+10001000001100000000001000001100
+00000001101000110000000000101100
+11000000000010111011000000000010
+11001100000001001011001100000000
+00101100111100100101100000111000
+00000010110100100000010000110000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011111010000000
+00001101101000000000001110101000
+00000000100010100000000100111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00111011100000100000110110101010
+00000011111110100000010001100000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111000000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100001000100
+00111110000000000000111110000000
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001100100100000000101100100100
+00000000111110011000000000111110
+01000000000011001001000000000011
+00100100000000001100100100010000
+00111110010000000010110010011000
+00000011110000100000010000110000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001010000000010111001000000
+00011000100101000000001000100100
+00000000001110111001000000101110
+01000000010010001001000000000010
+00001100000000001101101101001000
+00101100010000000100100010010000
+00000010111000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+01101000100100000000001000100100
+00000000001110010100000000101100
+01000000000010101001000000000010
+00100100000000001000100100000000
+00101110010010000000100010010001
+00000010110001100000000001000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001001000000010110001001000
+00001000000100100000001000000100
+10000100101100010000000000101100
+01001000000010100001001000000010
+00100110000000001001000100000000
+00001110010000000000100000010000
+00000010110000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000101000000
+11111010000000000011111000010100
+00001000101000000100001100100001
+01000000111110000000000000111110
+00010100001011101000010100000011
+00100000000000001100100000000000
+00111110000000000000110010000000
+00000011111011100000001101010000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000100000010111001000100
+00001111100100010000001111100100
+01000000111110010000000000111110
+01000100000011011001000100001011
+11100100000000001111100100000100
+00111111010000000100111111010000
+00000011111001100000011001110000
+00000000000000000000000000000000
+00011000000001011110010001000000
+11001101000000000011101001000100
+00001101110100100000001111100100
+10000100110010010000000100111110
+01001001000010111001010000000011
+11100100000100000011100100000000
+00111111010000000000110001010000
+00000011111001100000000001110000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10001000010100000010001000010100
+00001000100001000000001011100000
+00010000100010000000000000101110
+00011010000010111000000001000010
+11100000000000001011100000000000
+00101110000000000000101010000000
+00000010110011100000010000110000
+00000000000000000000000000000000
+00001000000001011100010010000000
+10000001000000000010100001001000
+00001000000100010000001011000101
+10100000100000010000000000101100
+01000100000010110001010000000010
+11000100000000001011000100000000
+00101110010000000000100000010000
+00000010110100100000000101110000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10001001000000000010001001000000
+01001000100100000000001011000100
+00000110100010010000000001101110
+01000000000110111001000000000010
+11100100000000001011100100000000
+00101110010000000001101010010000
+00000010110001100000010001100000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11001001000000000011101001000000
+00001100100100000000001111100100
+00000000100010011000000000111110
+01000000100011111001000000000010
+11100100000000001111100100000000
+00111110011001100000110010010000
+00000011111010000000010001110000
+00000000000000000000000000000000
+00101000000000011010010000000010
+11110001000000000010110001000000
+00101110100100001000001111100100
+00000000111110010001000000111110
+01000000000011111001000001000011
+11100100000000001111100100001000
+00111110011000000000111110010000
+00000011110110100000000001100000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000001
+00000000100000000001001111100000
+00000001111110000000000100111110
+00000000001011001000000000000011
+11100000000000001111100000000100
+00111110000000000000110010000000
+00000011100010100000010000100000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111110000110000010111010000000
+00001000111000000000001011101000
+00000000101110100000100000101110
+10000000000010001010000000000010
+11101000000000001011101000000000
+00101100100000000000110110101000
+10000010000010100000000001000000
+00000000000000000000000000000000
+00101000000001010110110000000000
+10110011000000000010110011000000
+00101000001101010000001011001100
+00000000101100110000000000101100
+11000000000010010011000000000010
+11001110000000001011001100000000
+00101100111000000000100100110000
+00000010100010100000000001010000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110110000000000010110011001000
+00001000011100000000001011011100
+00000000101101010000000000101101
+11100000000010010111001100000010
+11010000001000001011011100000000
+00101111110000110000100111111000
+01000010001010000000000001000000
+00000000000000000000000000000000
+10101000000010000001111100000000
+11110111100000000011110111100000
+01001100011110000000001111011110
+00000000101101101000001000111111
+11100001010011010111100100010001
+11011110001001001111011110000000
+00111101111000000000110101111000
+00000011101010100000001000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111010000000000011111011011101
+01001111101000000000001111101100
+00000100111110110110100000111110
+11010000000011101011000000000001
+11100000100000001111100001101000
+00111100010000000000111110110000
+00000011110000100000011001100000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11111111100000000011101111110000
+10001100111010010000001111111111
+00100000111111111001000000110011
+11110010000011111111100001000011
+11111110000001001111111010000000
+00111111111000000000110011111000
+00000011110100000000000001110000
+00000000000000000000000000000000
+10101000000100011001110001000000
+10110101000000000010000111000100
+00001000010100000000001011011100
+00000000101101010000000000101001
+11000100000010110111000000000010
+11010000000000001011011100010000
+00101101110001010000101001110001
+00000010111010100000010001100000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110110000000000010100111000000
+00101000011000000000001011011100
+00000000101111000000000001100001
+11000000000010010111000000000010
+11011100000000001011011000000000
+00101111110000000000100001110000
+10000010110001000000000000100000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10110000000000000010000011000000
+00001000000000000000000011001100
+00000001101100010000000001101000
+11000000000010110011000000000010
+11000000000000001011000000010000
+00101100010100000000101000111000
+00000010110110000000010000110000
+00000000000000000000000000000000
+10101000000101011011110000000000
+11111001000000000011101111000000
+00000100100100000000001011111100
+00000000111110110000000000110011
+11000000000011011111000000000011
+11101110001000001111100110000000
+00111100111100100001110010110000
+00000011111010100000010001100000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111000000001000011111011000000
+00001111100100000000001111101100
+00000000111110000100000000111110
+11000000000011110011000000000011
+11101100000000001111100100000001
+00111110110010000000111110110000
+00000011111001000000000000110000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111101100000000011110011000000
+10001100010100000000101100111100
+00000000111111100000000000111111
+11000000000011111111000000000011
+00111000000000001111111111000000
+00011111110010000000110011111000
+00000011111000000000010000110000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111000100000000010111011000001
+01001000100000000000001000101100
+00000000101110100000010000101110
+11000000000010111011000000000010
+00101000011001001011100010000000
+00101110011000000000100010111001
+00000010111000010000000000010000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000100000010111011000000
+00001000101000010000001000101100
+00000000101010110100000000101010
+11000000010010111011000000000110
+00100100000000011011100000000000
+00101110010000000000100010110000
+00100010111000000000000001000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110001000000000010110011000000
+00101000000100000000001000001100
+00000000101100000000000000101100
+11000000000010110011000000001000
+00000100000000011011000100000000
+00101110010000000000100000110000
+00000010110000100000000100000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111010000000000011111111000000
+00001100101000000000011100111100
+00000000111010000000000000111011
+11000000000011111111000000000011
+00100000000000001111101000000001
+00111110010000000010110010110000
+00000011111000000000001101010000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11110100000000000011111111000000
+00000111110000000000001111111100
+00000000111101000000000100111111
+11000000000011111111000000000010
+11110000000000001111110000000000
+00111101010000000000111111010000
+00000011111010000000011001110000
+00000000000000000000000000000000
+11000000000001011111001000000000
+11111100100000100011001100100001
+00001100110010000000001111010110
+00010000110011011000000000110001
+01100000100011001100100000000011
+11110000000000001100110000000000
+00110011110001000000110011101000
+00010011001100000000000001110000
+00000000000000000000000000000000
+10000000000100001110111000000000
+10111011100000100010001000100000
+00001000101010000000001011100110
+00000000100010000000000000100010
+01000000000010001010100000000010
+11101010000000101000100100000000
+00101011110000001000100010101000
+00000010001000000000010000110000
+00000000000000000000000000000000
+10001000000001011100000000000001
+10110000000000000010000000100000
+00001000000000000000011011000000
+00000000100010000000000000101000
+01000000001010000010000000100010
+11000100000000001000000000000000
+00100000110000000010100000100000
+00001010001000100000000101110000
+00000000000000000000000000000000
+11000000000101011010110000000001
+10111011000000100010001000000000
+01001000101000000000001011100010
+00000000100010011000000000101010
+11000000000010001010100000000010
+11100100000000101000100000000010
+00101010110000000010100010100000
+00000010001100000000010001100000
+00000000000000000000000000000000
+00000000000100011110000100100000
+11111000000000000011001001000000
+01001100100100000000001111100010
+00000000110000011010000000111000
+01000000000011001000110000000011
+11100000100000101100100010010000
+10110010110000000000110000101001
+10000011000100000000010001110000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111110000010100011111100010000
+00001111111000000010001011110100
+00000000111111010000001000110111
+01000000000011111100000000000011
+11101000000000001111011100000000
+00111110110000010000111111110000
+00000011111110000000000001100000
+00000000000000000000000000000000
+01000000000100001010000001000000
+11111001000000000000111011000000
+00001111100101000010001111100100
+11000000110010000000000000111110
+11001000000011001000011000000001
+11001101000001001100100100100000
+10110000110000000010110010110100
+10000011110100000000010000100000
+00000000000000000000000000000000
+11001000000001010010111000010000
+10110011010000010010110010110100
+01001011101000000000001110000100
+00000000100010010000000000001110
+11010000001010001000001000000010
+11101111001000001000101100000000
+00100011110111000010100010111100
+10000010111100100000000001000000
+00000000000000000000000000000000
+11100000000001010100001000000000
+10110000100000000010110010010001
+00001011000000000000001011000101
+00000000100000010000000000101100
+01010100000010000000010000000010
+11000001001000001000001001000000
+00100000110000000000100000001000
+00000010111110000000000001010000
+00000000000000000000000000000000
+01100000000000010001101000000001
+10110111100101000010110111100010
+00001011011110000000001010111110
+00000000100001101000001000101101
+01100100000010000110100000000010
+11011010000000001000010110011000
+00100001111001000000100001001000
+00000010110010000000000001000000
+00000000000000000000000000000000
+01001000000010000000000000000000
+11110000000010000011110010000000
+00001111000001000000001111001100
+00000000110000110000000000111100
+01000100000011000010010100000011
+11000000000000101100101000010001
+01110000110001000100110000100000
+01000011110100100000001000000000
+00000000000000000000000000000000
+01000000000111011011100000000000
+11111111000000000011111111010000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000100000010111110000000000011
+11110000000000001111110000010000
+00111111110001100000111111100100
+00000011110100000000011001100000
+00000000000000000000000000000000
+10101000000001011110010000000000
+11110000110000000011001001001000
+00001111000111100000001100101000
+00000000111110110000000000110010
+01000000010011001000000000000011
+11100100000000101100101000000000
+10110000110010000000110010010110
+00000011111010100000000001110000
+00000000000000000000000000000000
+01001000000100011001110001000000
+10110110000100000010000101000000
+00001011011100001000001000011100
+00000000101111010000000000110111
+01000000000010000110000000000010
+11011100000000001000011100000000
+00100001110011000000100001010000
+00000010110100100000010001100000
+00000000000000000000000000000000
+11000001000000001001011000000001
+10111101100000000010100111110000
+00001011110110000000001001010110
+00100000101101111000000000100001
+11100000000010000110110000000010
+11001110000000001010001110000000
+00100001111010000000100001111000
+00000010111100000000000000100000
+00000000000000000000000000000000
+01001000000101001100110100000000
+10110011000000000010000011000000
+00001011001100000000001001001100
+00100100101110111111000000100100
+11100000000010000011100000000010
+11001110010000001010001101110000
+00100000110000000000100000110000
+00000010110100100000010000110000
+00000000000000000000000000000000
+11101000000101011000100100000000
+11111010010000000011101010000000
+00001111101001000000001101111010
+00000000111111100100000000110010
+10101000001011001110100000000011
+11111001000010001110111011000000
+00110010100000000000110010100100
+00000011111110100000010001100000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000010001011111000110000
+00001111100000001000101110100001
+00000000111110000000000000111110
+00000000001011111000000000000011
+11100000001000000001000000000000
+00111110000000000010111110001000
+00000011110100100000000000110000
+00000000000000000000000000000000
+00001000000100001110110000100000
+11011011010000000011111011000000
+00001111101110000000001111100100
+01000000101110010000000000110010
+01000000000011001001000010000011
+11000110100000001100100100000011
+00110000010000001000110010111000
+00000011110000100000010000110000
+00000000000000000000000000000000
+10000000100001000110010000000000
+10001001010000000010111001011000
+00001011100110000000001011100111
+00000000101110010000001000100000
+01100000000010001001000000000010
+11100110000000101000100101000010
+00100010010000000010100010011100
+00000010111000000000000000010000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10011001000010000010111001000100
+00001011100100100000001011101100
+00000000101110010000000010100010
+01001000000010001001001001000010
+11100101000000001000100101000000
+10100010010000000000100010010010
+00000010110001100000000001000000
+00000000000000000000000000000000
+00001000000001000010010000000000
+10000001000001000010110001000000
+00001011000100000010011011000100
+00000000101100010000000000100010
+01000000000010000001000000000010
+11000100100000101000000100100000
+00100000010010000000100000011000
+00000010110000100000000100000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11011000000000000011111000000000
+00001111100000000000001111101000
+00000100111110000101000000110010
+00010100000011001010000000010011
+11100000000000001100100001010000
+10110010000101000000110010000000
+00100011111011100000001101010000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111110100
+00000000111111010000000000111111
+01000000001011111101000000000011
+11110100010000001111111100010000
+00111110010001000010111111010000
+00000011111001100000011001110000
+00000000000000000000000000000000
+10011001000101011100010000000000
+11111101000000010011111101000000
+00001100100100000000001111110100
+00000000111110010100000000111101
+01000000000011000101000000000011
+00110100001000001100110100000000
+00110011010110100100110010010000
+00000011110001100000000001110000
+00000000000000000000000000000000
+00111001000110001110000000010000
+10111000000000100010111000000000
+10001101100000000000001011101000
+00001000101110000000001000101110
+00000000000010001000000000000010
+00100000000000001000000001100000
+10100010000100000010101010000000
+00000010110011100000010000110000
+00000000000000000000000000000000
+00001000000001011100010000001000
+10110001000000000010111001000000
+00001000000100000010011011000100
+00000000101100010010000000101100
+01001010000010000001100000011010
+00000100000000101000000101001000
+10100000010000000010100000010000
+00000010110000100000000101110000
+00000000000000000000000000000000
+00011000000001011010010000000000
+10111001010000000010111001000000
+00001001100100000000011011100100
+01000000101110010010000100101110
+01001000001010001001000000000010
+00100101000000001000100100000010
+00100010010000000000101010010010
+10000010110001100000010001100000
+00000000000000000000000000000000
+10100000000101001010010000000000
+11111001010000100011111001000001
+00001100100100000000001111100111
+00000000111110010010000000111110
+01000000010011000001010000000011
+00100110000001001100100101000000
+10110010010000000010110010010000
+00000011111010000000010001110000
+00000000000000000000000000000000
+00101010000000001010110000001100
+11111001000000000011111001001000
+00001111101100000000001011100100
+00010000111110011000000000111110
+01100000100011111001001000000011
+11100111000000001111100100001010
+00111110010000000000111110110000
+00000011110010100000000001100000
+00000000000000000000000000000000
+00101010000100001010000000000000
+11001000001000000011111000000000
+00001111100000000000001111100010
+01000000101110000000000000111110
+00000000000011001000000010000011
+00000000000000001111100001000000
+10110000000000000010110010000000
+00000011000010100000010000100000
+00000000000000000000000000000000
+10100000100001000010100000000000
+10001110000000000010110110101000
+00001011101000000000000011111000
+00000000101110100000000000101111
+10100010001010001110010010001010
+00111010010000001011111011000000
+00100011100000001000110110100000
+00000010000010100000000001000000
+00000000000000000000000000000000
+00101000000001010100111001000000
+10000011000000000010110011100010
+01001011001110010000000011001100
+00000000101100110000000000101110
+11100000000010000011010000000110
+00001000010101001011101110000000
+00100000001000000000100000110010
+00100010000010100000000001010000
+00000000000000000000000000000000
+01100001000000010001111000000000
+10000101010000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+01000000000010001111000000000010
+00011100000000001011011101000000
+00100000010100000010100111111000
+00000010001010000000000001000000
+00000000000000000000000000000000
+00101000000010000001111000000000
+11000111100000000011110111100000
+00001111011110000000001111010110
+00000000101101111010001000111101
+11100000000011000111100000000011
+00011110000000001111011110000000
+00110001001000000010110001001000
+00001011001010100000001000000000
+00000000000000000000000000000000
+01001000000111011010110000101010
+11111010000000100011111010000000
+10001111101100000000001111101100
+00000000111110110000000000111110
+01000000000011111001000000000010
+11101100000000001111101000000000
+00111110010000000000111100000000
+10000011110000100000011001100000
+00000000000000000000000000000000
+11000000000001011111011000000000
+11111111100100000011111101100100
+00001111110111010000001111111110
+01000000111111111000100000111111
+11100000000011001111100000000011
+11111110010000001100111010000000
+10110011101000001000110011111000
+00000011000000000000000001110000
+00000000000000000000000000000000
+10101000000000011001110100000000
+10110111000000000010110111000000
+10001011010101000000001011011000
+00000000001101110000000000101111
+11000000000010000111000000000010
+11011100000000001101010100000000
+00110101010000000000101001110000
+00000010101010100000010001100000
+00000000000000000000000000000000
+00011001000000001001010000000000
+10110111000000010010110111000000
+00011011010100000001001011011100
+00000001101101110000000000101101
+11000000000010100110000000000010
+11001100001010001001011000000000
+00100001100000000000100001000000
+00000010000000000000000000100000
+00000000000000000000000000000000
+01100010000101001100110001001001
+10110001111000000010110000010000
+00001011000100100000001011000100
+10000001100100111100000000101100
+11000000000010100000010000000010
+11001110000000001001000000100010
+00100100010000000000101000000000
+10000010100010000000010000110000
+00000000000000000000000000000000
+11111000000101011010100000000000
+11111001000000000011111001000000
+00001111101010100000001111100101
+00000000111111110000000000111110
+10000000001011101011000100000011
+11001110000000001101100101000000
+00110010000000000000110010000000
+00100011001010100000010001100000
+00000000000000000000000000000000
+10000000000000001110000100100000
+11111001010100000011111001010000
+00001111101001000000001111100101
+01000000111110110011000000111110
+01010100100001011010100000000011
+11101101000000001111001100010000
+00111110000100000000111110100100
+00000011111000000000000000110000
+00000000000000000000000000000000
+11000001000100001111101000000000
+11111101000000100011111101000010
+00001111110000000000001100110000
+00000000111111110000000001111111
+00000000000011001111000100000011
+11111100000000001100110110010100
+00110001000000000000110011000000
+00000011000000000100010000110000
+00000000000000000000000000000000
+10000001000001000110001000000000
+10111000110001000010011001100001
+00001011000000000000001000100110
+10000000110010110000001001111100
+01101000001010001000011000000010
+01101111100000001000101010000010
+00100010000100001000100000000000
+00000011001000000100000000010000
+00000000000000000000000000000000
+10000000000000010110000001000000
+10111000110000000010111000100010
+00001011101000100000101000100110
+00000000101110110000010000101110
+10100000000010001001000000000010
+11100110000001001000100000000000
+00100010100000100000100010000110
+00000010001000000000000001000000
+00000000000000000000000000000000
+00001000000000000000000000000000
+10110001000000000110010001000000
+00001011001000000000001000000000
+00001000101000110000001000101000
+11000000000010000000000000000010
+01001100000000001000000100000000
+10100000000000001100100000110000
+00000010000000100000000100000000
+00000000000000000000000000000000
+10000000000000000110000000000000
+11111000000000000011111000000000
+00001111100000000000001100100000
+00000000111110110000000000101110
+00000001000011001000000000000011
+11101100000001001100000000000000
+10110000100000000100110010000000
+00001011000000000000001101010000
+00000000000000000000000000000000
+10100000010110011111000000010000
+11111101000000000011011101000000
+00001111110000000000001111110100
+00001000110011110000000000111111
+01000000000011111100000000000011
+01111100000010000111110000000000
+00111111000000000000111101000000
+00000011101010000000011001110000
+00000000000000000000000000000000
+00000000110001010100000100000011
+01110000010000001001110001010000
+00000111000001000000110111000101
+00000001011100010100000011011100
+00010000001101110000010000001101
+11000101000000110111000101000000
+11011100000100000011011100000100
+00001101110000000011000100000000
+00000000000000000000000000000000
+00000000110001010100010000000101
+01110001000000010101110001000000
+01110111000100000001010111000100
+00000101011100011000000101011100
+01000000010001110001000000010101
+11000100000001010111000100000001
+01011100010000000101011100010000
+00010101110000000011000101010000
+00000000000000000000000000000000
+00000000100000000000001000000001
+00100000100000000100100001100000
+00010010000010000000010010000110
+00000001001000001000000001001000
+00100000000100100000100000000100
+10000010000000010010000110000000
+01001000001000000001001000001000
+00000100100000000010000000000000
+00000000000000000000000000000000
+00000000100000000000000000000001
+01100000000000000101100000000000
+00010110000000000000010110000000
+00000101011000010000000001011000
+00000000000100100000000000000101
+10000100000000010110000000000000
+01011000000000000001011000000000
+00000101100000000010000000000000
+00000000000000000000000000000000
+00000000110001010100100000000101
+01110010000000010101110010000000
+01010111001000000001010111001001
+00000101011100100000000101011100
+10000000010101110011000000010101
+11001010000001010111001000000001
+01011100100000000101011100100000
+00010101110000000011000101010000
+00000000000000000000000000000000
+00000000110001010100000000000000
+01100000000000000001100001000000
+00000110000000000000000110000010
+00000000011000000000000000011000
+00000000000001100000000000000001
+10000000000000000110000101000000
+00011000000000000000011000000000
+00000001100000000011000100000000
+00000000000000000000000000000000
+00000000110001010100100000000100
+00100010000000010000100000100000
+01000010001000000001000010000100
+00000100001000100000000100001000
+10000000010000100011000000010000
+10001000000001000010001110000001
+00001000100000000100001000100000
+00010000100000000011000100000000
+00000000000000000000000000000000
+00000000110001010100111100000101
+01000010100000010101000001110000
+00010100001010000001010100000010
+00000001010000101000000101010000
+10100000010101000010100000010101
+00001010000001010100001010000001
+01010000101100000101010000111100
+00010101000000000011000101010000
+00000000000000000000000000000000
+00000000100000000000111000000001
+00010011000000000101010111000000
+00010001011100000000010101001100
+00000001010100110000000000010101
+11000000000101010111000000000101
+01001100000000010101011100000000
+01000000110000000001000100110000
+00000100010000000010000000000000
+00000000000000000000000000000000
+00000000100000000000010000000000
+00010000000000000001000001000000
+01000001000000000000000100001100
+00000000010000000000000000010000
+00000000000001000001000000000001
+00000000000000000100000100000000
+00000000000000000000000100011000
+00000000010000010010000000000000
+00000000000000000000000000000000
+00000000110001010110000000000010
+00011000000000001000001000000000
+00100001100000000000100000100000
+00000010000010000000000010000010
+00000000001000001000000000001000
+00100000000000100000100000000000
+10000010000000000010000110000000
+00001000010000010011000101010000
+00000000000000000000000000000000
+00000000110001010100000000000101
+01100000000000010101100100000000
+01010110010000000001010110000000
+00000111011000000000000101011001
+00000000010101100100000000010101
+10000000000001010110010000000001
+01001000000000000101011000000000
+00010101100000000011000100000000
+00000000000000000000000000000000
+00000000110001010100000000000011
+01100000000000001101100000000000
+00010110000000000000110110001000
+00000001011000000000000011011000
+00000000001101100000000000001101
+10000000000000110110000000000000
+11011000000000000011011000000000
+00001101100000000011000100000000
+00000000000000000000000000000000
+00000000110001010100001000000100
+00110000100000010000110000100000
+01100011000010000001000011000011
+00000100001100001000000100001100
+00100000010000110000100000010000
+11000010000001000011000010000001
+00001100001000000100001100001000
+00010000110000000011000101010000
+00000000000000000000000000000000
+00000000100000000000000000000000
+00110000000000000000110010000000
+00000011000000000000000011000000
+00000000001100000000000000001100
+00000000000000110000000000000000
+11000000000000000011000000000000
+00001100000000000000001100000000
+00000000110000000010000000000000
+00000000000000000000000000000000
+00000000100000000000001000000001
+00110000100000000100110010110000
+00010011000010000000010011000010
+00000101001100001000000001001100
+00100000000100110000100000000100
+11000010000000010011000010000000
+01001100001000000001001100001000
+00000100110000000010000000000000
+00000000000000000000000000000000
+00000000110001010100001000000101
+01100000100000010101100000110000
+01010111000010000001010110000011
+00000101011000001000000101011000
+00100000010101100000100000010101
+10000010000001010110000010000001
+01011000001000000101011000001000
+00010101100000000011000101010000
+00000000000000000000000000000000
+00000000110001010100001000000000
+00100000100000000000100000100000
+00000110000010000000000010000010
+00000000001100001000000000001000
+00100000000000100000100000000000
+10000010000000000010000010000000
+00001000001000000000001000001000
+00000000100000000011000100000000
+00000000000000000000000000000000
+00000000110001010101001000000100
+01100000100000010001100100100000
+01000010000010000001000110010010
+00000100001100001000000100011000
+00100000010001100100100000010001
+10000010000001000110010010000001
+00011001001000000100011001001000
+00010001100000000011000100000000
+00000000000000000000000000000000
+00000000110001010110000000000101
+01011000000000010101011000000000
+00010001100000000001010101100000
+00000000000110000000000101010110
+00000000010101011000000000010101
+01100000000001010101100000000001
+01010110000000000100010110000000
+00010101010000000011000101010000
+00000000000000000000000000000000
+00000000100000000000011000000001
+01000001100000000101000001100000
+00010100000110000000010100000110
+00000001010000011000000001010000
+01100000000101000001100000000101
+00000110000000010100000110000000
+01010000011000000000010000011000
+00000100000000000010000000000000
+00000000000000000000000000000000
+00000000100000000001001000000001
+00000000100000000100000100100000
+01010000000010000000010000010010
+00000001000000001000000001000000
+00100000000100000100100000000100
+00000010000000010000010010000000
+01000001001000000001000001001000
+00000100000000000010000100000000
+00000000000000000000000000000000
+00000000110001010100011000000011
+01010001100000001101010001100000
+00110101000110000000110101000110
+00000011010100011000000011010100
+01100000001101010001100000001101
+01000110000000110101000110000000
+11010100011000000011010100011000
+00001001010000000011000101010000
+00000000000000000000000000000000
+00000000110001010100011000000101
+01110001100000010101110001100000
+01010111000110000001010111000110
+00000111011100011000000100011100
+01100000010101110001100000010001
+11000110000001010111000110000001
+01011100011000000101011100011000
+00010101110000000011000100000000
+00000000000000000000000000000000
+00000000010001010100011000000011
+01110001100000001101110001100000
+00010111000110000000110111000110
+00000000011100011000000011011100
+01100000001101110001100000001001
+11000110000000110111000110000000
+11011100011000000011011100011000
+00001101110000000001000100000000
+00000000000000000000000000000000
+00000000010001010100011000000101
+01110001100000010101110001100000
+01100111000110000001010111000110
+00000000001100011000000101011100
+01100000010101110001100000010101
+11000110000001010111000110000001
+01011100011000000101011100011000
+00010101110000000001000101010000
+00000000000000000000000000000000
+00000000000000000000001000000001
+00100000100000000100100000100000
+00010010000010000000010010000010
+00000001011100001000000001001000
+00100000000100100000100000000100
+10000010000000010010000010000000
+01001000001000000001001000001000
+00000100100000000000000000000000
+00000000000000000000000000000000
+00000000010000000000011000000001
+01100001100000000101100001100000
+00010010000110000000010110000110
+00000101011000011000000001011000
+01100000000101100001100000000001
+10000110000000010110000110000000
+00011000011000000000011000011000
+00000101100000000000000100000000
+00000000000000000000000000000000
+00000000010001010100000000000101
+01110000000000010101110000000000
+01010111000000000001010111000000
+00000101011100000000000100011100
+00000000010001110000000000010100
+11000000000001010111000000000001
+01001100000000000100011100000000
+00010101110000000001000101010000
+00000000000000000000000000000000
+00000000010001000100001000000000
+01100000100000000001100000100000
+00000110000010000000000110000010
+00000000011000001000000000011000
+00100000000001100000110000000000
+10000010000000000110000011000000
+00001000001000000000011000001000
+00000001100000000001000100000000
+00000000000000000000000000000000
+00000000010001010100001000000100
+00100000100000010000100000100000
+01000010000010000001000010000010
+00000100001000001000000100001000
+00100000010000100000100000010001
+10000010000001000010001010000001
+00011000001000000100001000001000
+00010000100000000001000100000000
+00000000000000000000000000000000
+00000000010001010100001000000101
+01000000100000010101000000100000
+00010100000010000001010100000010
+00000001010000001000000101010000
+00100000010101000000100000010101
+01000010000001010100000010000001
+01010100001000000101010000001000
+00010101000000000001000101010000
+00000000000000000000000000000000
+00000000000000000000001000000001
+01010000110000000101010000100000
+00010101000011000000010101000011
+00000001010100001100000001010100
+00110000000101010000110000000101
+01000011000000010101001010000000
+01010100001100000001010100001000
+00000101010000000000000000000000
+00000000000000000000000000000000
+00000000010000000000100000000000
+01000010000000000001000010000000
+01000100001000000000000100001000
+00000000010000100000000000010000
+10000000000001000000000001000001
+00001000000000000100000000000000
+00010000100000000000010000100000
+00000001000000000000000000000000
+00000000000000000000000000000000
+00000000010001010100001000000010
+00100000100000001000000000100000
+00100000000010000000100000000010
+00000000000000001000000010000000
+00100000001000000010100000001000
+00000010000000100000000010000000
+10000000001100000010000000001000
+00001000000000000001000101010000
+00000000000000000000000000000000
+00000000010001000100000000000101
+01100000000000010101100000000000
+01010110000000000001010110000000
+00000111011000000000000101011000
+00000000010101100000000000010101
+10000000000001010110000000000001
+01011000000000000101011000000000
+00010101100000000001000100000000
+00000000000000000000000000000000
+00000000110001010100000000000011
+01100000000000011101100000000001
+01010010000000000000110110000000
+00000001011100000000000011011000
+00000000001101100000000000001101
+10000000000000010110000000000000
+11011000000000000011011000000000
+00001101100000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000100000100
+00110000000000000000110000010000
+01000010000000000001000011000000
+00000100011000000000000100001100
+00000000010000110000000000000000
+11000000000000000011000000000001
+00001100000000000100001100000100
+00010000110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00110000000000000000110101000000
+00000010000110000000000011010000
+00000000001001000000000000001100
+01000000000000110001000000000000
+11010000000000000011010110000000
+00001100000000000000001100000000
+00000000110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000010100000001
+00110001010000010100110001110000
+01010010000101000000010011000101
+00000101001100010100000001001100
+01010000000100110001110000000100
+11000101000000010011000100100000
+01001100010000000001001100010100
+00000100110000000000000000000000
+00000000000000000000000000000000
+00000000000000000010001100000101
+01101000110000000101101000110000
+00010110100011000001010110100011
+00000101011010001100000101011010
+01110000010101101001110000010101
+10100011000001010110100011000001
+01011010001100000101011010001100
+00010101100000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00100000000000000000100101000000
+00000010000100000000000010010000
+00000000001001000000000000001000
+00010000000000100010000000000000
+10010000000000000010010100000000
+00001000000000000000001000000000
+00000000100000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100001000100
+01100010000100000001100010000000
+00000110001000000001000110001000
+01000100011000100001000100011000
+10000000010001100000000110010001
+10001000010001000110000000010001
+00011000100001000100011000100001
+00010001100000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000001000101
+01010000000100000101010000000100
+00010101000000010001010101000000
+10000000010100000001000100010100
+00000100010101010000000001010101
+01000000010001010101000000011001
+01010100000001000101010100000001
+00010101010000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100000100000
+01000010000010000101000010000010
+00000100001000001000010100001000
+00100001010000100000000001010000
+10000010000101000010000010000101
+01001000000000010100001000000000
+00010100100000100001010000100000
+10000101000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000101000000001
+00000010100000000100000010111110
+01010000001010000000010000001010
+01000001000000101000000001000000
+10100000000100000010100000000000
+00001010000000010000001010000000
+00000000101000000001000000101010
+01000100000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000110010000011
+01010011000000000101010011001110
+00110101001100000000110101001100
+01000011010100110000000011010100
+11000000001101010011000000000000
+01001100000000010101001100100000
+10000100110000000011010100110010
+00001101010000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100010000101
+01110010000000010101110010010000
+01000111001000000001010111001000
+00000110011100100000000101011100
+10000000010101110010000000010101
+11001000000001100111001000001001
+00011100100000000101011100100010
+00010101110000000000000000000000
+00000000000000000000000000000000
+00000000000000000010001100001000
+01001000110001100001000000110000
+00000100000011000110000100100011
+00000000010010001100010000010000
+00110001100001000000110000100001
+00100011000100000100000011000000
+00010010001100001000010010001100
+00100001000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+01001111111111111101001111111111
+11110100111111111111110100111111
+11111111010011111111111111010011
+11111111111101001111111111111101
+00111111111111110100111111111111
+11010011111111111111010011111111
+11111101000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000010110111111011
+00001011001101101100001001011111
+11110100100100110110110000101100
+10011111010010110011011001000010
+01001101101100001111101001101100
+00101100110110010000111111111110
+01000010110011011011000010110111
+11101100000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011001111111100
+01001100110011110001001101011111
+11110100110101001111000100110010
+10111111010011001100111101000011
+01010011110001001111101011110001
+00110011001111010000111111111111
+01000011001100111100010011001111
+11110001000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011101100011110
+01001110110111111001001110010001
+10000100111001011111100100111010
+01111000010011101101111110000011
+10010111111001001000100111111001
+00111011011111100000100011000111
+10000011101100011110010011101100
+01111001000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000100000110
+01110000010001011001110001010000
+00110011000001000000110111000101
+00000001011100010100000000011100
+00010000001001110000010000001001
+11000001000000100111000001000001
+00011100000100000110011100010100
+00000001110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000010000000001
+01110001000000010101110001000000
+00010011000100000001010011000000
+00000111001100000000000101011100
+01000000010101110001000000010101
+11000100000001010111000100000001
+01011100010000000101011100010000
+00000101110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000001000000001
+00100000100000000100100000100000
+00010010000010000000000010000010
+00000000001000001000000001001000
+00100000000100100000100000000100
+10000010000000010010000010000000
+01001000001000000001001000001000
+00000100100000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000100
+01100000000000010001100101100000
+00000110000000000000000110010010
+00000000011001000000000100011000
+00000000000001100000000000000001
+10000000000000000110000000000000
+00011000000000000100011000010000
+01000001100000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100100000000
+01110010000000000001110010000000
+00010010001000000001000111001000
+00000100011100101000000100011100
+10000000010001110010010000010001
+11001000000001000111001000000001
+00011100100000000100011100101000
+00010001110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01100000000000000001100100000000
+01000110000000000000000110010000
+00000000011001000000000000011000
+00000000000001100000000000000001
+10000000000000000110000000000000
+00011000000000000000011000000000
+00000001100000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100000000000
+00100010000000000000100100000000
+01000010001000000001000010010000
+00000100001001000000000100001000
+10000000010000100010000000010000
+10001000000001000010010000000001
+00001000100000000100001001100000
+00010000100000000000000000000000
+00000000000000000000000000000000
+00000000000000000010111100000000
+01001010110001000001001000100000
+01000100101010000001000100100011
+00000000010010001000000000010010
+10100000010001001010000000010001
+00101010000001000100100011000001
+00010010101100000000010010101100
+00010001000000000000000000000000
+00000000000000000000000000000000
+00001000110000000000110000000000
+00010010000000000000010010000000
+00000000001100000000000101001000
+00000000000100110000000000010100
+11000000000001010011000000000100
+00001100000000000101001100000000
+01000000110000000000000100110000
+00000000010000000001000000000000
+00000000000000000000000000000000
+00000000110000000000010000000000
+00010001100000000000010101100000
+00000000000000000000000100010110
+00000100000101100000000000011000
+00000000000001000001000000000001
+00000000000000000100010000000001
+00000100000000000000000101000000
+00000000010000000011000000000000
+00000000000000000000000000000000
+00001000110000000100000000000000
+00010000000000001000010000000000
+01100000000000000000100000000000
+00000010000100000000000010000000
+00000000001000000000000000001000
+00000000000000100000000000000000
+10000000000000000010000100000000
+00000000010000000011000000000000
+00000000000000000000000000000000
+00001000110000000100000000000100
+01100000000000010001100000000000
+01000010000000000000000110000000
+00000000011000000000000110011000
+00000000010001100000000000010001
+10000000000001000110000000000001
+00011000000000000100011000000000
+00111001100000000011000000000000
+00000000000000000000000000000000
+00010000000000000100000000000000
+01100000000000100001100000000000
+00100110000000000000100110000000
+00000000011000100000000000011000
+00000000001001100000000000001001
+10000000000000100110000000000000
+00011000000000000010011000000000
+00001001100000100000000000000000
+00000000000000000000000000000000
+01000000010001010100001000000000
+00110000100000000000110000100000
+00000011000010000001000011000010
+00010110001100001000000100001100
+00100000010000110000100000010000
+11000010000001000011000010000001
+10001100001000000100001100001000
+00010000110000000001000101010000
+00000000000000000000000000000000
+01000000010000000000000000000000
+00110000000000000000110010000000
+00000011000000000000000011001000
+00000000001100000000000000001100
+00000000000000110000000000000000
+11000000000000000011001000000000
+00001100000000000000001100000000
+00000000110000000001000001000000
+00000000000000000000000000000000
+01000000000000000000001000000000
+00110000100000000000110010110000
+00000011000010000000000011001011
+00000000001100001100000100001100
+00100000000000110000100000000000
+11000010000000000001001011000000
+00001100001000000000001100001000
+00000000110000000000000000000000
+00000000000000000000000000000000
+01000000010001010100000000000100
+01100000000000010001100000011000
+00000011000010000001000110000001
+00000100011100001100000100011000
+00100000010001100000100000010001
+10000010000001000110000011000001
+00011100001000000100011000001000
+00010001100000000001000101010000
+00000000000000000000000000000000
+01000000000000010100001000000000
+00100000100000000000100000100000
+01000010000010000000000010000010
+00000000011000001000000000001100
+00100000000000100000100000000000
+10000010000000000010000010000000
+00011000001000000000001000001000
+00000000100000000000000000000000
+00000000000000000000000000000000
+01010000000000000100001000000100
+01100000100000010001100000100000
+01000010000010000001000110000010
+00000100001000001000000100001100
+00100000010001100000100000010001
+10000010000001000110000010000001
+00001000001000000100011000001000
+00010001100000000000000000000000
+00000000000000000000000000000000
+01000000010001010100000000000100
+01010000000000010001010000000000
+01010001000000000001000101000000
+00000000000100000000000000000100
+00000000010001010000000000010001
+01000000000001000101000000000000
+00000100000000000100010100000000
+00010001010000100001000101010000
+00000000000000000000000000000000
+01001000010000000000011000000000
+01000001100000000001000001100000
+00000100000110000000000100000110
+11000000010000011000000000010000
+01100000000001000001100000000001
+00000110000000000100000110000000
+00010000011000000000010000011000
+00000001000000000000000000000000
+00000000000000000000000000000000
+01001000000000000000001000000001
+00000000101010000100000000101100
+00010000000010000000010000000010
+11010101000000001001000001000000
+00100000000100000000100000000100
+00000010000000010000000010000001
+01000000001000000001000000001000
+00000100000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100011000100001
+01010001101000000101010001100110
+01110001000110000000110101000110
+11000011010100011001000011010100
+01100000001101010001100000001101
+01000110000000110101000110000000
+11010100011000000011010100011000
+00001101010000000001000101010000
+00000000000000000000000000000000
+00000000000000010100011000101110
+01110001100010011001110001000010
+01010011000110000001000111000100
+10100100011100010010000110011100
+01100000010001110001100000010001
+11000110000001000111000110000001
+00011100011000000100011100011000
+00010001110000000000000000000000
+00000000000000000000000000000000
+01000000000000010100011000000010
+01110001100000001001110001100000
+00110111000110000000110111000110
+00000001011100011000000000011100
+01100000001001110001100000001001
+11000110000000100111000110000001
+00011100011000000010011100011000
+00001101110000000000000000000000
+00000000000000000000000000000000
+01010000010001010100011000000101
+01110001100000010101110001100100
+00000111000110000001010010000110
+00000111001100011000010100001100
+01100000010101110001100000010101
+11000110000001010111000110000001
+00001100011000000101011100011000
+00010100110000100001000101010000
+00000000000000000000000000000000
+01000000000000000001001000000001
+00100100100000000100100100100100
+00010010000010000000010010010010
+00000001011000001000000001011100
+00100000000100100100100000000100
+10000010000000010010010010000000
+00001001001000000001001001001000
+00000101100000000000000000000000
+00000000000000000000000000000000
+01000000000000000000011000000000
+01100001100000000001100001100000
+00000010000110000000000110000110
+00000001011000011000000100011000
+01100000000001100001100000000001
+10000110000000000110000110000001
+00001000011000000000011000011000
+00000001100000000000000000000000
+00000000000000000000000000000000
+00000000010001010110000000010100
+01111000000000010001111000000010
+00000011100000000001000111100000
+00000100011110000000000100011110
+00000000010001111000000000010001
+11100000000001000111100000000001
+00011110000000000100011110000000
+00010001110000000001000101010000
+00000000000000000000000000000000
+01000000000000010101001000000000
+01100100100000000001100100101000
+01000010000010000000000110010010
+00000000011000001000000000011000
+00100000000001100100100000000001
+10000010000000000110010010000000
+00011001001000000000011001001000
+00000001100000000000000000000000
+00000000000000000000000000000000
+01000000000000010101001000000100
+00100100100000010000100100101000
+01000110000010000001000010010010
+00000100001000001000000100001000
+00100000010000100000100000010000
+10000010000001000010000010000001
+00001000001000000100001000001000
+00010000100000000000000000000000
+00000000000000000000000000000000
+01000000010001010100001000000100
+01000000100000010001000000011000
+01000101000010000001000100000010
+00000000010000001000000000010000
+00100000010001000000100000010001
+00000010000101000100000010000000
+00010000001000000100010000001000
+00010001000000000001000101010000
+00000000000000000000000000000000
+01000000000000000001001000000000
+01010100100000000001010100100000
+00000101000011000000000101010010
+00000000010100001100000000010100
+00110000000001010000110000000001
+01000011000000000101000010000000
+00010100001000000000010100001000
+00000001010000000000000000000000
+00000000000000000000000000000000
+01000000000000010000100000000000
+01100010000000000001100100000100
+00000110001000000000000100001000
+00000100010000100000000000010000
+10000000000001000010000000000001
+00001000000000000100001000000001
+00010000100000000000010000100000
+00000001000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100001000100010
+00000000100010001000000000100110
+00000000000010000000100000000010
+00100010000000001000000010000000
+00100000001000000000100000001000
+00000010000000100000000010000000
+10000000001000000010000000001000
+00001000000000000001000101010000
+00000000000000000000000000000000
+01000000000000010100000010000100
+01100000000000010001100100001100
+01000110000000000000000110000000
+01000100011000000001000110011000
+00000000010001100000000000010001
+10000000000001000110000000000001
+00011000000000000100011000000000
+00010001100000000000000000000000
+00000000000000000000000000000000
+01000000000000010100000010000010
+01100000001000001001100100001100
+00000010000000000000100110000000
+10100000001000000001000000011101
+00000000011001100100000001011001
+10000000000000100110010000000000
+00001000000000000010011000000000
+00001001100000000000000000000000
+00000000000000000000000000000000
+01000000010001010110000010000100
+00111000001000010000111000000110
+00000010100000000001000011100000
+00100110001010000000100100011010
+00000000011000111000000000010000
+11100000000001000011100000000001
+10001010000000000100001110000000
+00010000110000000001000101010000
+00000000000000000000000000000000
+01010000000000000000000100000000
+00110000010000000000110001010100
+00000010000001000000000011000001
+00000000001000000100000000001000
+01010000000000110001010000000000
+11000001000000000011000101000000
+00001000000100000000001100000100
+00000000110000000000000000000000
+00000000000000000000000000000000
+01000000000000000000010000000000
+00110001000000000000110101001000
+00000010000101000000000011000100
+00100000001000010100100100001101
+01010000000000110101010000010000
+11000101000000000011010100000000
+00001000010000000000001100010000
+00000000110000100000000000000000
+00000000000000000000000000000000
+01000000010001010100001100000100
+01100000110000010001100000111000
+00000110000011000001000110000011
+00000100011000001100000100011000
+00110000000001100000110000000001
+10000011000001000110000111000001
+00011000001100000100011000001100
+00010001100000000001000101010000
+00000000000000000000000000000000
+01000000000000010100000000000000
+00100000000000000000100011000000
+01000010000000000000000010000000
+00000000001000000000000000001000
+01000000000000100001000000000000
+10000000000000000010000000000000
+00001000000000000000001000000000
+00000000100000000000000000000000
+00000000000000000000000000000000
+01000000000000010100100001000100
+01100010000100010001100011000100
+01000110001000010001000110001000
+01000100011000100001000100011000
+10000000000001100010000000000001
+10001000010001000110001000000001
+00011000100001000100011000100001
+00010001100000000000000000000000
+00000000000000000000000000000000
+01000000010001010100000001000100
+01010000000100010001010000000100
+01000101000000010001000101000000
+01000001000000000001000000010100
+00010100000001010000010000000001
+01000000010001000101000100010000
+00010100000001000100010100000001
+00010001010000000001000101010000
+00000000000000000000000000000000
+01000000010000000000100000100000
+01000010000010000001000010001010
+00000101001000001000000100001000
+10100000010000100000100000010000
+10000010000001000010000010000001
+00001000001000000100001000001000
+00010000100000100000010000100000
+00000001000000000000000000000000
+00000000000000000000000000000000
+00000000000000000100101000000001
+00000010100000000100000010100000
+00000000001010000000010000001010
+01000101000000101000100001000000
+10100000000100000010100000000100
+00001010000000010000001010000001
+01000000101000000001000000101000
+00000100000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100110100000011
+01010011010010001101010011010010
+00000001001101000000110101001101
+01000011010100110100000011010100
+11010000001101010011010000001101
+01001101000000110101001101000000
+11010100110100000011010100110100
+00001101010000000001000101010000
+00000000000000000000000000000000
+01000000000000010100100010000000
+01110010000000000001110010000000
+01100111001000000001000111001000
+10000100011100100000000110011100
+10000000010001110010000000010001
+11001000000001000111001000000001
+00011100100000000100011100100000
+00010001110000000000000000000000
+00000000000000000000000000000000
+00000000000000000010001100001000
+01001000110000100001000000110000
+00000100100011000110000100100011
+00000000010010001100010000010000
+00110001100001000000110000100001
+00100011000110000100000011000000
+00010010001100001000010010001100
+00000001000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+01001111111111111101001111111111
+11110100111111111111110100111111
+11111111010011111111111111010011
+11111111111101001111111111111101
+00111111111111110100111111111111
+11010011111111111111010011111111
+11111101000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000001000000
+00000000000100000000000010000100
+00100000000000000000000000000000
+01000010000000000000000010000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000010110111111011
+00001011011111101100001111111111
+11110100101100110110110000101101
+11111111010010110011011111010010
+01001101101100001001001001101100
+00101100110110110000100100110110
+11000010110011011011000010110011
+01111101000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011001111111100
+01001100111111110001001111111111
+11110100110011001111000100110011
+11111111010011001100111111010011
+01010011110001001101001011110001
+00110011001111000100110101001111
+00010011001100111100010011001100
+11111101000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011101100011110
+01001110110001111001001000110001
+10000100111011011111100100111011
+00011000010011101101111000010011
+10010111111001001110000111111001
+00111011011111100100111001000110
+00010011101100011110010011101100
+01111001000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000001010000100
+00000000101000010000000000101000
+01000000000010100001000000000010
+10000100000000001010000011001100
+00101000010000000000101000001100
+11000010100001000000000010100001
+00000000001010000100000000001010
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100000000100
+00000010000000010000000010000000
+01000000001000000001000000001000
+00000100000000100000000100000000
+10000000010000000010000000010000
+00001000000001000000001000000001
+00000000100000000100000000100000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000100
+00000000001000010000000000001000
+01000000000000100001000000000000
+10000100000000000010000100000000
+00001000010000000000001000010000
+00000000100001000000000000100001
+00000000000010000100000000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000100
+00000000000000010000000000000000
+01000000000000000001000000000000
+00000100000000000000000100000000
+00000000010000000000000000010000
+00000000000001000000000000000001
+00000000000000000100000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000000
+00000000001000001100110000001000
+00110011000000100000000000000000
+10000000000000000010000000000000
+00001000000000000000001000000000
+00000000100000000000000000100000
+00000000000010000000000000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000000001000000000
+00000000100000000000000000100000
+00000000000010000000000000000010
+00000000000000001000000000000000
+00100000000000000000100000000000
+00000010000000000000000010000000
+00000000001000000000000000001000
+00000000000000100000000000000000
+00000000000000000000000000000000
+00001000000000000000100010000000
+00000010001000000000000010001000
+00000000001000100000000000001000
+10000000000000100010000000000000
+10001000000000000010001000000000
+00001000100000000000001000100000
+00000000100010000000000000100010
+00000000000000100000000000000000
+00000000000000000000000000000000
+00001000000000000000100000000000
+00000010000000001100110010000000
+00110011001000000000000000001000
+00000000000000100000000000000000
+10000000000000000010000000000000
+00001000000000000000001000000000
+00000000100000000000000000100000
+00000000000000100000000000000000
+00000000000000000000000000000000
+00001000000000000000101010000100
+00000010101000010000000010101000
+01000000001010100001000000001010
+10000100000000101010000100000000
+10101000010000000010101000010000
+00001010100001000000001010100001
+00000000101010000100000000101010
+00010000000000100000000000000000
+00000000000000000000000000000000
+00001000000000000000100000000100
+00000010000000010000000010000000
+01000000001000000001000000001000
+00000100000000100000000100000000
+10000000010000000010000000010000
+00001000000001000000001000000001
+00000000100000000100000000100000
+00010000000000100000000000000000
+00000000000000000000000000000000
+00001000000000000000000010000100
+00000000001000010000000000001000
+01000000000000100001000000000000
+10000100000000000010000100000000
+00001000010000000000001000010000
+00000000100001000000000000100001
+00000000000010000100000000000010
+00010000000000100000000000000000
+00000000000000000000000000000000
+00001000000100000000000000000111
+00110000000000011100110000000000
+01110011000000000001110011000000
+00000111001100000000000111001100
+00000000011100110000000000011100
+11000000000001110011000000000001
+11001100000000000111001100000000
+00011100110000100000010000000000
+00000000000000000000000000000000
+00001000000000000000000010000100
+00000000001000010000000000001000
+01110011000000100001000000000000
+10000111001100000010000100000000
+00001000010000000000001000011100
+11000000100001000000000000100001
+00000000000010000100000000000010
+00010000000000100000000000000000
+00000000000000000000000000000000
+00000000000000000000001000000000
+00000000100000000000000000100000
+01000000000010000000000000000010
+00000100000000001000000000000000
+00100000000000000000100000010000
+00000010000000000000000010000000
+00000000001000000000000000001000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000000
+00000000001000000000000000001000
+01000000000000100000000000000000
+10000100000000000010000000000000
+00001000000000000000001000010000
+00000000100000000000000000100000
+00000000000010000000000000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000100001000000000000000
+00000000000000000000000000000000
+00110011000000000000000000000000
+00000011001100000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000010000100000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00111100001111000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011110000111100000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000001010000100
+00000000101000010000000000101000
+01000000000010100001000000000010
+10000100000000001010000100000000
+00101000010000000000101000010000
+00000010100001000000000010100001
+00000000001010000100000000001010
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000100
+00000000000000010000000000000000
+01000000000000000001000000000000
+00000100000000100000000100000000
+10000000010000000010000000010000
+00001000000001000000001000000001
+00000000100000000100000000100000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100010000100
+00000000001000010000000010001000
+01000000001000100001000000001000
+10000100000000100010000100000000
+00001000010000000000001000010000
+00000000100001000000000000100001
+00000000000010000100000000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000100
+00000000000000010000000000000000
+01000000000000000001000000000000
+00000100000000000000000100000000
+00000000010000000000000000010000
+00000000000001000000000000000001
+00000000000000000100000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000000
+00000000001000000000000000001000
+00000000000000100000000000000000
+10000000000000000010000000000000
+00001000000000000000001000000000
+00000000100000000000000000100000
+00000000000010000000000000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000000001000000000
+00000000100000000000000000100000
+00000000000010000000000000000010
+00000000000000001000000000000000
+00100000000000000000100000000000
+00000010000000000000000010000000
+00000000001000000000000000001000
+00000000000000100000000000000000
+00000000000000000000000000000000
+00000000000000000000100010000000
+00000010001000000000000010001000
+00000000001000100000000000001000
+10000000000000100010000000000000
+10001000000000000010001000000000
+00001000100000000000001000100000
+00000000100010000000000000100010
+00000000000000100000000000000000
+00000000000000000000000000000000
+00001000000000000000000000000000
+00000000000000000000000000000000
+00000000001000000000000000000000
+00000000000000000000000000000000
+10000000000000000010000000000000
+00001000000000000000001000000000
+00000000100000000000000000100000
+00000000000000100000000000000000
+00000000000000000000000000000000
+00001000000000000000101010000111
+00110010101000010000000010101000
+01110011001010100001000000001010
+10000100000000101010000100000000
+10101000010000000010101000010000
+00001010100001000000001010100001
+00000000101010000100000000101010
+00011100110000100000000000000000
+00000000000000000000000000000000
+00001000000000000000100000000100
+00000010000000010000000010000000
+01000000001000000001000000001000
+00000100000000100000000100000000
+10000000010000000010000000010000
+00001000000001000000001000000001
+00000000100000000100000000100000
+00010000000000100000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000000
+00000000001000010000000000001000
+00000000000000100001000000000000
+10000100000000000010000100000000
+00001000010000000000001000010000
+00000000100001000000000000100001
+00000000000010000100000000000010
+00010000000000100000000000000000
+00000000000000000000000000000000
+00001000000100000000000000000100
+00000000000000011100110000000000
+01000000000000000001110011000000
+00000100000000000000000111001100
+00000000011100110000000000011100
+11000000000001110011000000000001
+11001100000000000111001100000000
+00011100110000100000010000000000
+00000000000000000000000000000000
+00001000000000000000000010000100
+00000000001000010000000000001000
+01000000000000100001000000000000
+10000100000000000010000100000000
+00001000010000000000001000010000
+00000000100001000000000000100001
+00000000000010000100000000000010
+00010000000000100000000000000000
+00000000000000000000000000000000
+00000000000000000000001000000000
+00000000100000000000000000100000
+00000000000010000000000000000010
+00000000000000001000000000000000
+00100000000000000000100000000000
+00000010000000000000000010000000
+00000000001000000000000000001000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000000
+00000000001000000000000000001000
+00000000000000100000000000000000
+10000000000000000010000000000000
+00001000000000000000001000000000
+00000000100000000000000000100000
+00000000000010000000000000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000100001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000010000100000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00111100001111000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011110000111100000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00110000000000000010000000000001
+00000010000000000000000000000000
+00110000000000000100001001001001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00110000000000000010000000000001
+00000010000000100000000000000000
+00110000000000000100001001000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00110000000000000000000000000001
+00000000000000001010001010111110
+00110000000000001000000000000001
+00000000000000000000000000000011
+00110000000000000100000000001001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00110000000000001000000000000001
+00000000000000000000000000000101
+00110000000000001010000000000001
+00000000000000000000000000000000
+00110000000000000000000000000001
+00000000000000001100000101111101
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
diff --git a/drivers/dahdi/proslic.h b/drivers/dahdi/proslic.h
new file mode 100644
index 0000000..933bd34
--- /dev/null
+++ b/drivers/dahdi/proslic.h
@@ -0,0 +1,190 @@
+// ProSlic Header File
+
+typedef struct {
+ unsigned char address;
+ unsigned char altaddr;
+ char *name;
+ unsigned short initial;
+} alpha;
+
+typedef struct {
+ unsigned char chip_number;
+ unsigned char DTMF_digit;
+ unsigned char interrupt_line;
+ unsigned char hook_status;
+ unsigned long half_pulses[20]; // Contains the time stamps of incomming half pulses.
+ unsigned char half_pulses_detected; // Contains the number of half pulses detected.
+ unsigned char Pulse_digit;
+ unsigned long On_Hook_time;
+ unsigned long Off_Hook_time;
+} chipStruct;
+
+// Defines
+#define LPT 0X378
+
+#define IDA_LO 28
+#define IDA_HI 29
+
+#define IAA 30
+#define ID_ACCES_STATUS 31
+#define IAS_BIT 1
+
+#define I_STATUS 31
+
+#define SPI_MODE 0
+#define PCM_MODE 1
+#define PCM_XMIT_START_COUNT_LSB 2
+#define PCM_XMIT_START_COUNT_MSB 3
+#define PCM_RCV_START_COUNT_LSB 4
+#define PCM_RCV_START_COUNT_MSB 5
+#define DIO 6
+
+#define AUDIO_LOOPBACK 8
+#define AUDIO_GAIN 9
+#define LINE_IMPEDANCE 10
+#define HYBRID 11
+#define RESERVED12 12
+#define RESERVED13 13
+#define PWR_DOWN1 14
+#define PWR_DOWN2 15
+#define RESERVED16 16
+#define RESERVED17 17
+#define INTRPT_STATUS1 18
+#define INTRPT_STATUS2 19
+#define INTRPT_STATUS3 20
+#define INTRPT_MASK1 21
+#define INTRPT_MASK2 22
+#define INTRPT_MASK3 23
+#define DTMF_DIGIT 24
+#define RESERVED25 25
+#define RESERVED26 26
+#define RESERVED27 27
+#define I_DATA_LOW 28
+#define I_DATA_HIGH 29
+#define I_ADDRESS 30
+#define I_STATUS 31
+#define OSC1 32
+#define OSC2 33
+#define RING_OSC_CTL 34
+#define PULSE_OSC 35
+#define OSC1_ON__LO 36
+#define OSC1_ON_HI 37
+#define OSC1_OFF_LO 38
+#define OSC1_OFF_HI 39
+#define OSC2_ON__LO 40
+#define OSC2_ON_HI 41
+#define OSC2_OFF_LO 42
+#define OSC2_OFF_HI 43
+#define PULSE_ON__LO 44
+#define PULSE_ON_HI 45
+#define PULSE_OFF_LO 46
+#define PULSE_OFF_HI 47
+#define RING_ON__LO 48
+#define RING_ON_HI 49
+#define RING_OFF_LO 50
+#define RING_OFF_HI 51
+#define RESERVED52 52
+#define RESERVED53 53
+#define RESERVED54 54
+#define RESERVED55 55
+#define RESERVED56 56
+#define RESERVED57 57
+#define RESERVED58 58
+#define RESERVED59 59
+#define RESERVED60 60
+#define RESERVED61 61
+#define RESERVED62 62
+#define RESERVED63 63
+#define LINE_STATE 64
+#define ACTIVATE_LINE 0x11
+#define RING_LINE 0x44
+#define BIAS_SQUELCH 65
+#define BAT_FEED 66
+#define AUTO_STATE 67
+#define LOOP_STAT 68
+#define LOOP_DEBOUCE 69
+#define RT_DEBOUCE 70
+#define LOOP_I_LIMIT 71
+#define OFF_HOOK_V 72
+#define COMMON_V 73
+#define BAT_V_HI 74
+#define BAT_V_LO 75
+#define PWR_STAT_DEV 76
+#define PWR_STAT 77
+#define LOOP_V_SENSE 78
+#define LOOP_I_SENSE 79
+#define TIP_V_SENSE 80
+#define RING_V_SENSE 81
+#define BAT_V_HI_SENSE 82
+#define BAT_V_LO_SENSE 83
+#define IQ1 84
+#define IQ2 85
+#define IQ3 86
+#define IQ4 87
+#define IQ5 88
+#define IQ6 89
+#define RESERVED90 90
+#define RESERVED91 91
+#define DCDC_PWM_OFF 92
+#define DCDC 93
+#define DCDC_PW_OFF 94
+#define RESERVED95 95
+#define CALIBR1 96
+#define CALIBRATE_LINE 0x78
+#define NORMAL_CALIBRATION_COMPLETE 0x20
+#define CALIBR2 97
+#define RING_GAIN_CAL 98
+#define TIP_GAIN_CAL 99
+#define DIFF_I_CAL 100
+#define COMMON_I_CAL 101
+#define I_LIMIT_GAIN_CAL 102
+#define ADC_OFFSET_CAL 103
+#define DAC_ADC_OFFSET 104
+#define DAC_OFFSET_CAL 105
+#define COMMON_BAL_CAL 106
+#define DC_PEAK_CAL 107
+
+// Indirect Register (decimal)
+#define DTMF_ROW_0_PEAK 0
+#define DTMF_ROW_1_PEAK 1
+#define DTMF_ROW2_PEAK 2
+#define DTMF_ROW3_PEAK 3
+#define DTMF_COL1_PEAK 4
+#define DTMF_FWD_TWIST 5
+#define DTMF_RVS_TWIST 6
+#define DTMF_ROW_RATIO_THRESH 7
+#define DTMF_COL_RATIO_THRESH 8
+#define DTMF_ROW_2ND_HARM 9
+#define DTMF_COL_2ND_HARM 10
+#define DTMF_PWR_MIN_THRESH 11
+#define DTMF_HOT_LIM_THRESH 12
+#define OSC1_COEF 13
+#define OSC1X 14
+#define OSC1Y 15
+#define OSC2_COEF 16
+#define OSC2X 17
+#define OSC2Y 18
+#define RING_V_OFF 19
+#define RING_OSC_COEF 20
+#define RING_X 21
+#define RING_Y 22
+#define PULSE_ENVEL 23
+#define PULSE_X 24
+#define PULSE_Y 25
+#define RECV_DIGITAL_GAIN 26
+#define XMIT_DIGITAL_GAIN 27
+#define LOOP_CLOSE_THRESH 28
+#define RING_TRIP_THRESH 29
+#define COMMON_MIN_THRESH 30
+#define COMMON_MAX_THRESH 31
+#define PWR_ALARM_Q1Q2 32
+#define PWR_ALARM_Q3Q4 33
+#define PWR_ALARM_Q5Q6 34
+#define LOOP_CLOSURE_FILTER 35
+#define RING_TRIP_FILTER 36
+#define THERM_LP_POLE_Q1Q2 37
+#define THERM_LP_POLE_Q3Q4 38
+#define THERM_LP_POLE_Q5Q6 39
+#define CM_BIAS_RINGING 40
+#define DCDC_MIN_V 41
+#define DCDC_XTRA 42
diff --git a/drivers/dahdi/sec-2.h b/drivers/dahdi/sec-2.h
new file mode 100644
index 0000000..94ce6ab
--- /dev/null
+++ b/drivers/dahdi/sec-2.h
@@ -0,0 +1,451 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * echo.c - An echo cancellor, suitable for electrical and acoustic
+ * cancellation. This code does not currently comply with
+ * any relevant standards (e.g. G.164/5/7/8). One day....
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ * Based on a bit from here, a bit from there, eye of toad,
+ * ear of bat, etc - plus, of course, my own 2 cents.
+ *
+ * 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.
+ *
+ */
+
+/* TODO:
+ Finish the echo suppressor option, however nasty suppression may be
+ Add an option to reintroduce side tone at -24dB under appropriate conditions.
+ Improve double talk detector (iterative!)
+*/
+
+#ifndef _ZAPTEL_SEC_H
+#define _ZAPTEL_SEC_H
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#define MALLOC(a) kmalloc((a), GFP_KERNEL)
+#define FREE(a) kfree(a)
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#define MALLOC(a) malloc(a)
+#define FREE(a) free(a)
+#endif
+
+#include "fir.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#define NONUPDATE_DWELL_TIME 600 /* 600 samples, or 75ms */
+
+struct echo_can_state
+{
+ int tx_power;
+ int rx_power;
+ int clean_rx_power;
+
+ int rx_power_threshold;
+ int nonupdate_dwell;
+
+ fir16_state_t fir_state;
+ int16_t *fir_taps16; /* 16-bit version of FIR taps */
+ int32_t *fir_taps32; /* 32-bit version of FIR taps */
+
+ int curr_pos;
+
+ int taps;
+ int tap_mask;
+ int use_nlp;
+ int use_suppressor;
+
+ int32_t supp_test1;
+ int32_t supp_test2;
+ int32_t supp1;
+ int32_t supp2;
+
+ int32_t latest_correction; /* Indication of the magnitude of the latest
+ adaption, or a code to indicate why adaption
+ was skipped, for test purposes */
+};
+
+static void echo_can_free(struct echo_can_state *ec);
+static int16_t echo_can_update(struct echo_can_state *ec, int16_t tx, int16_t rx);
+
+static void echo_can_init(void)
+{
+ printk("Zaptel Echo Canceller: STEVE2%s\n", ZAPTEL_ECHO_AGGRESSIVE);
+}
+
+static void echo_can_identify(char *buf, size_t len)
+{
+ zap_copy_string(buf, "STEVE2", len);
+}
+
+static void echo_can_shutdown(void)
+{
+}
+
+/*
+ * According to Jim...
+ */
+#define MIN_TX_POWER_FOR_ADAPTION 512
+#define MIN_RX_POWER_FOR_ADAPTION 64
+
+/*
+ * According to Steve...
+ */
+/* #define MIN_TX_POWER_FOR_ADAPTION 4096
+#define MIN_RX_POWER_FOR_ADAPTION 64 */
+
+static int echo_can_create(struct zt_echocanparams *ecp, struct zt_echocanparam *p,
+ struct echo_can_state **ec)
+{
+ size_t size;
+
+ if (ecp->param_count > 0) {
+ printk(KERN_WARNING "SEC-2 echo canceler does not support parameters; failing request\n");
+ return -EINVAL;
+ }
+
+ size = sizeof(**ec) + ecp->tap_length * sizeof(int32_t) + ecp->tap_length * 3 * sizeof(int16_t);
+
+ if (!(*ec = MALLOC(size)))
+ return -ENOMEM;
+
+ memset(*ec, 0, size);
+
+ (*ec)->taps = ecp->tap_length;
+ (*ec)->curr_pos = ecp->tap_length - 1;
+ (*ec)->tap_mask = ecp->tap_length - 1;
+ (*ec)->fir_taps32 = (int32_t *) (*ec + sizeof(**ec));
+ (*ec)->fir_taps16 = (int16_t *) (*ec + sizeof(**ec) + ecp->tap_length * sizeof(int32_t));
+ /* Create FIR filter */
+ fir16_create(&(*ec)->fir_state, (*ec)->fir_taps16, (*ec)->taps);
+ (*ec)->rx_power_threshold = 10000000;
+ (*ec)->use_suppressor = FALSE;
+ /* Non-linear processor - a fancy way to say "zap small signals, to avoid
+ accumulating noise". */
+ (*ec)->use_nlp = FALSE;
+
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline void echo_can_free(struct echo_can_state *ec)
+{
+ fir16_free(&ec->fir_state);
+ FREE(ec);
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline int16_t echo_can_update(struct echo_can_state *ec, int16_t tx, int16_t rx)
+{
+ int offset1;
+ int offset2;
+ int32_t echo_value;
+ int clean_rx;
+ int nsuppr;
+ int i;
+ int correction;
+
+ /* Evaluate the echo - i.e. apply the FIR filter */
+ /* Assume the gain of the FIR does not exceed unity. Exceeding unity
+ would seem like a rather poor thing for an echo cancellor to do :)
+ This means we can compute the result with a total disregard for
+ overflows. 16bits x 16bits -> 31bits, so no overflow can occur in
+ any multiply. While accumulating we may overflow and underflow the
+ 32 bit scale often. However, if the gain does not exceed unity,
+ everything should work itself out, and the final result will be
+ OK, without any saturation logic. */
+ /* Overflow is very much possible here, and we do nothing about it because
+ of the compute costs */
+ /* 16 bit coeffs for the LMS give lousy results (maths good, actual sound
+ bad!), but 32 bit coeffs require some shifting. On balance 32 bit seems
+ best */
+ echo_value = fir16 (&ec->fir_state, tx);
+
+ /* And the answer is..... */
+ clean_rx = rx - echo_value;
+
+ /* That was the easy part. Now we need to adapt! */
+ if (ec->nonupdate_dwell > 0)
+ ec->nonupdate_dwell--;
+
+ /* If there is very little being transmitted, any attempt to train is
+ futile. We would either be training on the far end's noise or signal,
+ the channel's own noise, or our noise. Either way, this is hardly good
+ training, so don't do it (avoid trouble). */
+ /* If the received power is very low, either we are sending very little or
+ we are already well adapted. There is little point in trying to improve
+ the adaption under these circumstanceson, so don't do it (reduce the
+ compute load). */
+ if (ec->tx_power > MIN_TX_POWER_FOR_ADAPTION
+ &&
+ ec->rx_power > MIN_RX_POWER_FOR_ADAPTION)
+ {
+ /* This is a really crude piece of decision logic, but it does OK
+ for now. */
+ if (ec->tx_power > 2*ec->rx_power)
+ {
+ /* There is no far-end speech detected */
+ if (ec->nonupdate_dwell == 0)
+ {
+ /* ... and we are not in the dwell time from previous speech. */
+ //nsuppr = saturate((clean_rx << 16)/ec->tx_power);
+ nsuppr = clean_rx >> 3;
+
+ /* Update the FIR taps */
+ offset2 = ec->curr_pos + 1;
+ offset1 = ec->taps - offset2;
+ ec->latest_correction = 0;
+ for (i = ec->taps - 1; i >= offset1; i--)
+ {
+ correction = ec->fir_state.history[i - offset1]*nsuppr;
+ /* Leak to avoid false training on signals with multiple
+ strong correlations. */
+ ec->fir_taps32[i] -= (ec->fir_taps32[i] >> 12);
+ ec->fir_taps32[i] += correction;
+ ec->fir_state.coeffs[i] = ec->fir_taps32[i] >> 15;
+ ec->latest_correction += abs(correction);
+ }
+ for ( ; i >= 0; i--)
+ {
+ correction = ec->fir_state.history[i + offset2]*nsuppr;
+ /* Leak to avoid false training on signals with multiple
+ strong correlations. */
+ ec->fir_taps32[i] -= (ec->fir_taps32[i] >> 12);
+ ec->fir_taps32[i] += correction;
+ ec->fir_state.coeffs[i] = ec->fir_taps32[i] >> 15;
+ ec->latest_correction += abs(correction);
+ }
+ }
+ else
+ {
+ ec->latest_correction = -1;
+ }
+ }
+ else
+ {
+ ec->nonupdate_dwell = NONUPDATE_DWELL_TIME;
+ ec->latest_correction = -2;
+ }
+ }
+ else
+ {
+ ec->nonupdate_dwell = 0;
+ ec->latest_correction = -3;
+ }
+ /* Calculate short term power levels using very simple single pole IIRs */
+ /* TODO: Is the nasty modulus approach the fastest, or would a real
+ tx*tx power calculation actually be faster? */
+ ec->tx_power += ((abs(tx) - ec->tx_power) >> 5);
+ ec->rx_power += ((abs(rx) - ec->rx_power) >> 5);
+ ec->clean_rx_power += ((abs(clean_rx) - ec->clean_rx_power) >> 5);
+
+#if defined(XYZZY)
+ if (ec->use_suppressor)
+ {
+ ec->supp_test1 += (ec->fir_state.history[ec->curr_pos] - ec->fir_state.history[(ec->curr_pos - 7) & ec->tap_mask]);
+ ec->supp_test2 += (ec->fir_state.history[(ec->curr_pos - 24) & ec->tap_mask] - ec->fir_state.history[(ec->curr_pos - 31) & ec->tap_mask]);
+ if (ec->supp_test1 > 42 && ec->supp_test2 > 42)
+ supp_change = 25;
+ else
+ supp_change = 50;
+ supp = supp_change + k1*ec->supp1 + k2*ec->supp2;
+ ec->supp2 = ec->supp1;
+ ec->supp1 = supp;
+ clean_rx *= (1 - supp);
+ }
+#endif
+
+ if (ec->use_nlp && ec->rx_power < 32)
+ clean_rx = 0;
+
+ /* Roll around the rolling buffer */
+ if (ec->curr_pos <= 0)
+ ec->curr_pos = ec->taps;
+ ec->curr_pos--;
+
+ return clean_rx;
+}
+
+#if 0
+static inline int16_t echo_can_update(struct echo_can_state *ec, int16_t tx, int16_t rx)
+{
+ int offset;
+ int limit;
+ int32_t echo_value;
+ int clean_rx;
+ int nsuppr;
+ int i;
+ int correction;
+
+ ec->tx_history[ec->curr_pos] = tx;
+
+ /* Evaluate the echo - i.e. apply the FIR filter */
+ /* Assume the gain of the FIR does not exceed unity. Exceeding unity
+ would seem like a rather poor thing for an echo cancellor to do :)
+ This means we can compute the result with a total disregard for
+ overflows. 16bits x 16bits -> 31bits, so no overflow can occur in
+ any multiply. While accumulating we may overflow and underflow the
+ 32 bit scale often. However, if the gain does not exceed unity,
+ everything should work itself out, and the final result will be
+ OK, without any saturation logic. */
+ /* Overflow is very much possible here, and we do nothing about it because
+ of the compute costs */
+ /* 16 bit coeffs for the LMS give lousy results (maths good, actual sound
+ bad!), but 32 bit coeffs require some shifting. On balance 32 bit seems
+ best */
+ offset = ec->curr_pos;
+ limit = ec->taps - offset;
+ echo_value = 0;
+ for (i = 0; i < limit; i++)
+ echo_value += (ec->fir_taps[i] >> 16)*ec->tx_history[i + offset];
+ offset = ec->taps - ec->curr_pos;
+ for ( ; i < ec->taps; i++)
+ echo_value += (ec->fir_taps[i] >> 16)*ec->tx_history[i - offset];
+ echo_value >>= 16;
+
+ /* And the answer is..... */
+ clean_rx = rx - echo_value;
+
+ /* That was the easy part. Now we need to adapt! */
+ if (ec->nonupdate_dwell > 0)
+ ec->nonupdate_dwell--;
+
+ /* If there is very little being transmitted, any attempt to train is
+ futile. We would either be training on the far end's noise or signal,
+ the channel's own noise, or our noise. Either way, this is hardly good
+ training, so don't do it (avoid trouble). */
+ /* If the received power is very low, either we are sending very little or
+ we are already well adapted. There is little point in trying to improve
+ the adaption under these circumstanceson, so don't do it (reduce the
+ compute load). */
+ if (ec->tx_power > MIN_TX_POWER_FOR_ADAPTION
+ &&
+ ec->rx_power > MIN_RX_POWER_FOR_ADAPTION)
+ {
+ /* This is a really crude piece of decision logic, but it does OK
+ for now. */
+ if (ec->tx_power > 2*ec->rx_power)
+ {
+ /* There is no far-end speech detected */
+ if (ec->nonupdate_dwell == 0)
+ {
+ /* ... and we are not in the dwell time from previous speech. */
+ //nsuppr = saturate((clean_rx << 16)/ec->tx_power);
+ nsuppr = clean_rx >> 3;
+
+ /* Update the FIR taps */
+ offset = ec->curr_pos;
+ limit = ec->taps - offset;
+ ec->latest_correction = 0;
+ for (i = 0; i < limit; i++)
+ {
+ correction = ec->tx_history[i + offset]*nsuppr;
+ ec->fir_taps[i] += correction;
+ //ec->latest_correction += abs(correction);
+ }
+ offset = ec->taps - ec->curr_pos;
+ for ( ; i < ec->taps; i++)
+ {
+ correction = ec->tx_history[i - offset]*nsuppr;
+ ec->fir_taps[i] += correction;
+ //ec->latest_correction += abs(correction);
+ }
+ }
+ else
+ {
+ ec->latest_correction = -3;
+ }
+ }
+ else
+ {
+ ec->nonupdate_dwell = NONUPDATE_DWELL_TIME;
+ ec->latest_correction = -2;
+ }
+ }
+ else
+ {
+ ec->nonupdate_dwell = 0;
+ ec->latest_correction = -1;
+ }
+ /* Calculate short term power levels using very simple single pole IIRs */
+ /* TODO: Is the nasty modulus approach the fastest, or would a real
+ tx*tx power calculation actually be faster? */
+ ec->tx_power += ((abs(tx) - ec->tx_power) >> 5);
+ ec->rx_power += ((abs(rx) - ec->rx_power) >> 5);
+ ec->clean_rx_power += ((abs(clean_rx) - ec->clean_rx_power) >> 5);
+
+#if defined(XYZZY)
+ if (ec->use_suppressor)
+ {
+ ec->supp_test1 += (ec->tx_history[ec->curr_pos] - ec->tx_history[(ec->curr_pos - 7) & ec->tap_mask]);
+ ec->supp_test2 += (ec->tx_history[(ec->curr_pos - 24) & ec->tap_mask] - ec->tx_history[(ec->curr_pos - 31) & ec->tap_mask]);
+ if (ec->supp_test1 > 42 && ec->supp_test2 > 42)
+ supp_change = 25;
+ else
+ supp_change = 50;
+ supp = supp_change + k1*ec->supp1 + k2*ec->supp2;
+ ec->supp2 = ec->supp1;
+ ec->supp1 = supp;
+ clean_rx *= (1 - supp);
+ }
+#endif
+
+ if (ec->use_nlp && ec->rx_power < 32)
+ clean_rx = 0;
+
+ /* Roll around the rolling buffer */
+ ec->curr_pos = (ec->curr_pos + 1) & ec->tap_mask;
+
+ return clean_rx;
+}
+/*- End of function --------------------------------------------------------*/
+#endif
+
+static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+ /* Reset hang counter to avoid adjustments after
+ initial forced training */
+ ec->nonupdate_dwell = ec->taps << 1;
+ if (pos >= ec->taps)
+ return 1;
+ ec->fir_taps32[pos] = val << 17;
+ ec->fir_taps16[pos] = val << 1;
+ if (++pos >= ec->taps)
+ return 1;
+ return 0;
+}
+
+/*- End of file ------------------------------------------------------------*/
+#endif
diff --git a/drivers/dahdi/sec.h b/drivers/dahdi/sec.h
new file mode 100644
index 0000000..be31807
--- /dev/null
+++ b/drivers/dahdi/sec.h
@@ -0,0 +1,310 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * echo.c - An echo cancellor, suitable for electrical and acoustic
+ * cancellation. This code does not currently comply with
+ * any relevant standards (e.g. G.164/5/7/8). One day....
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ * Various optimizations and improvements by Mark Spencer <markster@digium.com>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ * Based on a bit from here, a bit from there, eye of toad,
+ * ear of bat, etc - plus, of course, my own 2 cents.
+ *
+ * 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.
+ *
+ */
+
+/* TODO:
+ Finish the echo suppressor option, however nasty suppression may be
+ Add an option to reintroduce side tone at -24dB under appropriate conditions.
+ Improve double talk detector (iterative!)
+*/
+
+#ifndef _ZAPTEL_SEC_H
+#define _ZAPTEL_SEC_H
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#define MALLOC(a) kmalloc((a), GFP_KERNEL)
+#define FREE(a) kfree(a)
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#define MALLOC(a) malloc(a)
+#define FREE(a) free(a)
+#endif
+
+#include "arith.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#define USE_SHORTS
+
+#define NONUPDATE_DWELL_TIME 600 /* 600 samples, or 75ms */
+
+struct echo_can_state
+{
+ int tx_power;
+ int rx_power;
+ int clean_rx_power;
+
+ int rx_power_threshold;
+ int nonupdate_dwell;
+
+ int16_t *tx_history; /* Last N tx samples */
+ int32_t *fir_taps; /* Echo FIR taps */
+ int16_t *fir_taps_short; /* Echo FIR taps, shorts instead of ints */
+
+ int curr_pos;
+
+ int taps;
+ int tap_mask;
+ int use_nlp;
+ int use_suppressor;
+
+ int32_t supp_test1;
+ int32_t supp_test2;
+ int32_t supp1;
+ int32_t supp2;
+
+ int32_t latest_correction; /* Indication of the magnitude of the latest
+ adaption, or a code to indicate why adaption
+ was skipped, for test purposes */
+};
+
+static void echo_can_init(void)
+{
+ printk("Zaptel Echo Canceller: STEVE%s\n", ZAPTEL_ECHO_AGGRESSIVE);
+}
+
+static void echo_can_identify(char *buf, size_t len)
+{
+ zap_copy_string(buf, "STEVE", len);
+}
+
+static void echo_can_shutdown(void)
+{
+}
+
+static void echo_can_free(struct echo_can_state *ec);
+static int16_t echo_can_update(struct echo_can_state *ec, int16_t tx, int16_t rx);
+
+/* Original parameters :
+#define MIN_TX_POWER_FOR_ADAPTION 256
+#define MIN_RX_POWER_FOR_ADAPTION 128
+*/
+
+#define MIN_TX_POWER_FOR_ADAPTION 256
+#define MIN_RX_POWER_FOR_ADAPTION 64
+
+/* Better ones found by Jim
+#define MIN_TX_POWER_FOR_ADAPTION 128
+#define MIN_RX_POWER_FOR_ADAPTION 64
+*/
+
+static int echo_can_create(struct zt_echocanparams *ecp, struct zt_echocanparam *p,
+ struct echo_can_state **ec)
+{
+ size_t size;
+
+ if (ecp->param_count > 0) {
+ printk(KERN_WARNING "SEC echo canceler does not support parameters; failing request\n");
+ return -EINVAL;
+ }
+
+ size = sizeof(**ec) + ecp->tap_length * sizeof(int32_t) + ecp->tap_length * 3 * sizeof(int16_t);
+
+ if (!(*ec = MALLOC(size)))
+ return -ENOMEM;
+
+ memset(*ec, 0, size);
+
+ (*ec)->taps = ecp->tap_length;
+ (*ec)->tap_mask = ecp->tap_length - 1;
+ (*ec)->tx_history = (int16_t *) (*ec + sizeof(**ec));
+ (*ec)->fir_taps = (int32_t *) (*ec + sizeof(**ec) +
+ ecp->tap_length * 2 * sizeof(int16_t));
+ (*ec)->fir_taps_short = (int16_t *) (*ec + sizeof(**ec) +
+ ecp->tap_length * sizeof(int32_t) +
+ ecp->tap_length * 2 * sizeof(int16_t));
+ (*ec)->rx_power_threshold = 10000000;
+ (*ec)->use_suppressor = FALSE;
+ /* Non-linear processor - a fancy way to say "zap small signals, to avoid
+ accumulating noise". */
+ (*ec)->use_nlp = TRUE;
+
+ return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline void echo_can_free(struct echo_can_state *ec)
+{
+ FREE(ec);
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline int16_t echo_can_update(struct echo_can_state *ec, int16_t tx, int16_t rx)
+{
+ int32_t echo_value;
+ int clean_rx;
+ int nsuppr;
+
+ ec->tx_history[ec->curr_pos] = tx;
+ ec->tx_history[ec->curr_pos + ec->taps] = tx;
+
+ /* Evaluate the echo - i.e. apply the FIR filter */
+ /* Assume the gain of the FIR does not exceed unity. Exceeding unity
+ would seem like a rather poor thing for an echo cancellor to do :)
+ This means we can compute the result with a total disregard for
+ overflows. 16bits x 16bits -> 31bits, so no overflow can occur in
+ any multiply. While accumulating we may overflow and underflow the
+ 32 bit scale often. However, if the gain does not exceed unity,
+ everything should work itself out, and the final result will be
+ OK, without any saturation logic. */
+ /* Overflow is very much possible here, and we do nothing about it because
+ of the compute costs */
+ /* 16 bit coeffs for the LMS give lousy results (maths good, actual sound
+ bad!), but 32 bit coeffs require some shifting. On balance 32 bit seems
+ best */
+#ifdef USE_SHORTS
+ echo_value = CONVOLVE2(ec->fir_taps_short, ec->tx_history + ec->curr_pos, ec->taps);
+#else
+ echo_value = CONVOLVE(ec->fir_taps, ec->tx_history + ec->curr_pos, ec->taps);
+#endif
+ echo_value >>= 16;
+
+ /* And the answer is..... */
+ clean_rx = rx - echo_value;
+
+ /* That was the easy part. Now we need to adapt! */
+ if (ec->nonupdate_dwell > 0)
+ ec->nonupdate_dwell--;
+
+ /* If there is very little being transmitted, any attempt to train is
+ futile. We would either be training on the far end's noise or signal,
+ the channel's own noise, or our noise. Either way, this is hardly good
+ training, so don't do it (avoid trouble). */
+ /* If the received power is very low, either we are sending very little or
+ we are already well adapted. There is little point in trying to improve
+ the adaption under these circumstanceson, so don't do it (reduce the
+ compute load). */
+ if (ec->tx_power > MIN_TX_POWER_FOR_ADAPTION
+ &&
+ ec->rx_power > MIN_RX_POWER_FOR_ADAPTION)
+ {
+ /* This is a really crude piece of decision logic, but it does OK
+ for now. */
+ if (ec->tx_power > ec->rx_power << 1)
+ {
+ /* There is no far-end speech detected */
+ if (ec->nonupdate_dwell == 0)
+ {
+ /* ... and we are not in the dwell time from previous speech. */
+ //nsuppr = saturate((clean_rx << 16)/ec->tx_power);
+ nsuppr = (clean_rx << 16) / ec->tx_power;
+ nsuppr >>= 4;
+ if (nsuppr > 512)
+ nsuppr = 512;
+ if (nsuppr < -512)
+ nsuppr = -512;
+
+ /* Update the FIR taps */
+ ec->latest_correction = 0;
+#ifdef USE_SHORTS
+ UPDATE2(ec->fir_taps, ec->fir_taps_short, ec->tx_history + ec->curr_pos, nsuppr, ec->taps);
+#else
+ UPDATE(ec->fir_taps, ec->fir_taps_short, ec->tx_history + ec->curr_pos, nsuppr, ec->taps);
+#endif
+ } else
+ {
+ ec->latest_correction = -3;
+ }
+ }
+ else
+ {
+ ec->nonupdate_dwell = NONUPDATE_DWELL_TIME;
+ ec->latest_correction = -2;
+ }
+ }
+ else
+ {
+ ec->nonupdate_dwell = 0;
+ ec->latest_correction = -1;
+ }
+ /* Calculate short term power levels using very simple single pole IIRs */
+ /* TODO: Is the nasty modulus approach the fastest, or would a real
+ tx*tx power calculation actually be faster? */
+ ec->tx_power += ((abs(tx) - ec->tx_power) >> 5);
+ ec->rx_power += ((abs(rx) - ec->rx_power) >> 5);
+ ec->clean_rx_power += ((abs(clean_rx) - ec->clean_rx_power) >> 5);
+
+#if defined(XYZZY)
+ if (ec->use_suppressor)
+ {
+ ec->supp_test1 += (ec->tx_history[ec->curr_pos] - ec->tx_history[(ec->curr_pos - 7) & ec->tap_mask]);
+ ec->supp_test2 += (ec->tx_history[(ec->curr_pos - 24) & ec->tap_mask] - ec->tx_history[(ec->curr_pos - 31) & ec->tap_mask]);
+ if (ec->supp_test1 > 42 && ec->supp_test2 > 42)
+ supp_change = 25;
+ else
+ supp_change = 50;
+ supp = supp_change + k1*ec->supp1 + k2*ec->supp2;
+ ec->supp2 = ec->supp1;
+ ec->supp1 = supp;
+ clean_rx *= (1 - supp);
+ }
+#endif
+
+ if (ec->use_nlp && ec->rx_power < 32)
+ clean_rx = 0;
+
+ /* Roll around the rolling buffer */
+ ec->curr_pos = (ec->curr_pos - 1) & ec->tap_mask;
+
+ return clean_rx;
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+ /* Reset hang counter to avoid adjustments after
+ initial forced training */
+ ec->nonupdate_dwell = ec->taps << 1;
+ if (pos >= ec->taps)
+ return 1;
+ ec->fir_taps[pos] = val << 17;
+ ec->fir_taps_short[pos] = val << 1;
+ if (++pos >= ec->taps)
+ return 1;
+ return 0;
+}
+
+/*- End of file ------------------------------------------------------------*/
+#endif
diff --git a/drivers/dahdi/tor2-hw.h b/drivers/dahdi/tor2-hw.h
new file mode 100644
index 0000000..8da5c52
--- /dev/null
+++ b/drivers/dahdi/tor2-hw.h
@@ -0,0 +1,187 @@
+/*
+ * Tormenta 2 Quad-T1 PCI Driver
+ *
+ * Written by Mark Spencer <markster@linux-suppot.net>
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001, Linux Support Services, 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.
+ *
+ */
+
+#ifndef _TOR2_HW_H
+#define _TOR2_HW_H
+
+/*
+ * The Tormenta two consists of the following block architecture:
+ *
+ * [ Spartan ] --- [ DS 21Q352 ] -- Xfrms -- Span 1
+ * | | | | | | |
+ * Local Bus +----- Span 2
+ * | | | |
+ * [ PCI 9030 ] +----- Span 3
+ * | | | | | |
+ * PCI BUS +----- Span 4
+ *
+ * All communicatiosn to the framer (21Q352) are performed
+ * through the PCI 9030 part using memory mapped I/O.
+ *
+ * The Tormenta 2 requires a 2 2k wondows memory space
+ * which is mapped as follows:
+ *
+ * First (32 bit) space:
+ *
+ * 0x0000 -> 0x07FF: Memory map of Tx and Rx buffers. They are stored
+ * with increasing channel number, with each span in
+ * a byte of a 32-bit long word:
+ * Bits 31-24: Span 1
+ * Bits 23-16: Span 2
+ * Bits 16- 8: Span 3
+ * Bits 7- 0: Span 4
+ *
+ *
+ * Second (8 bit) space:
+ *
+ * 0x0000 -> 0x00FF: Registers for Transceiver 1
+ * 0x0100 -> 0x01FF: Registers for Transceiver 2
+ * 0x0200 -> 0x02FF: Registers for Transceiver 3
+ * 0x0300 -> 0x03FF: Registers for Transceiver 4
+ *
+ * 0x400 Write -> Firmware load location for Xilinx. This is the only valid
+ * register until the Xilinx is programmed to decode
+ * the remainder!
+ *
+ * 0x400 Write -> clkreg (sync source)
+ * 0=free run, 1=span 1, 2=span 2, 3=span 3, 4=span 4.
+ *
+ * 0x400 Read -> statreg
+ * bit 0 - Interrupt Enabled
+ * bit 1 - Interrupt Active
+ * bit 2 - Dallas Interrupt Active
+ *
+ * 0x401 Write -> ctlreg as follows:
+ * bit 0 - Interrupt Enable
+ * bit 1 - Drives "TEST1" signal ("Interrupt" outbit)
+ * bit 2 - Dallas Interrupt Enable (Allows DINT signal to drive INT)
+ * bit 3 - External Syncronization Enable (MASTER signal).
+ * bit 4 - Select E1 Divisor Mode (0 for T1, 1 for E1).
+ * bit 5 - Remote serial loopback (When set to 1, TSER is driven from RSER)
+ * bit 6 - Local serial loopback (When set to 1, Rx buffers are driven from Tx buffers)
+ * bit 7 - Interrupt Acknowledge (set to 1 to acknowledge interrupt)
+ *
+ * 0x402 Write -> LED register as follows:
+ * bit 0 - Span 1 Green
+ * bit 1 - Span 1 Red
+ * bit 2 - Span 2 Green
+ * bit 3 - Span 2 Red
+ * bit 4 - Span 3 Green
+ * bit 5 - Span 3 Red
+ * bit 6 - Span 4 Green
+ * bit 7 - Span 4 Red
+ * NOTE: turning on both red and green yields yellow.
+ *
+ * 0x403 Write -> TEST2, writing to bit 0 drives TEST2 pin.
+ *
+ * 0x404 Write -> ctlreg1 as follows:
+ * bit 0 - Non-REV.A Mode (Set this bit for Dallas chips later then Rev. A)
+ */
+
+#ifdef NEED_PCI_IDS
+/*
+ * Provide routines for identifying a tormenta card
+ */
+
+#define PCI_VENDOR_ID_PLX 0x10b5
+
+#ifdef __KERNEL__
+static struct pci_device_id tor2_pci_ids[] =
+#else
+#define PCI_ANY_ID -1
+static struct tor2_pci_id {
+ int vendor;
+ int device;
+ int subvendor;
+ int subdevice;
+ int class;
+ int classmask;
+ unsigned long driver_data;
+} tor2_pci_ids[] =
+#endif /* __KERNEL__ */
+{
+ { PCI_VENDOR_ID_PLX, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)"PLX 9030" }, /* PLX 9030 Development board */
+ { PCI_VENDOR_ID_PLX, 0x3001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)"PLX Development Board" }, /* PLX 9030 Development board */
+ { PCI_VENDOR_ID_PLX, 0xD00D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)"Tormenta 2 Quad T1/PRI or E1/PRA" }, /* Tormenta 2 */
+ { PCI_VENDOR_ID_PLX, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)"Tormenta 2 Quad T1/E1 (non-Digium clone)" }, /* Tormenta 2 clone */
+ { 0, }
+};
+
+#ifndef __KERNEL__
+/* We provide a simple routine to match the given ID's */
+static inline int tor2_pci_match(int vendorid, int deviceid, char **variant)
+{
+ /* Returns 1 if this is a tormenta card or 0 if it isn't */
+ int x;
+ for (x = 0; x< sizeof(tor2_pci_ids) / sizeof(tor2_pci_ids[0]); x++)
+ if (((tor2_pci_ids[x].vendor == PCI_ANY_ID) ||
+ (tor2_pci_ids[x].vendor == vendorid)) &&
+ ((tor2_pci_ids[x].device == PCI_ANY_ID) ||
+ (tor2_pci_ids[x].device == deviceid))) {
+ *variant = (char *)tor2_pci_ids[x].driver_data;
+ return 1;
+ }
+ if (variant)
+ *variant = NULL;
+ return 0;
+}
+#endif /* __KERNEL__ */
+#endif /* NEED_PCI_IDS */
+
+/*
+ * PLX PCI9030 PCI Configuration Registers
+ *
+ * This is not an all-inclusive list, just some interesting ones
+ * that we need and that are not standard.
+ *
+ */
+#define PLX_PCI_VPD_ADDR 0x4e /* Set address here */
+#define PLX_PCI_VPD_DATA 0x50 /* Read/Write data here */
+
+#define PLX_LOC_WP_BOUNDARY 0x4e /* Bits 6-0 here */
+#define PLX_LOC_GPIOC 0x54 /* GPIO control register */
+
+/* The 4 GPIO data bits we are interested in */
+
+#define LOC_GPIOC_GPIO4 0x4000 /* GPIO4 data */
+#define LOC_GPIOC_GPIO5 0x20000 /* GPIO5 data */
+#define LOC_GPIOC_GPIO6 0x100000 /* GPIO6 data */
+#define LOC_GPIOC_GPIO7 0x800000 /* GPIO7 data */
+
+/* define the initialization of the GPIOC register */
+
+#define LOC_GPIOC_INIT_VALUE 0x2036000 /* GPIO 4&5 in write and
+ both high and GPIO 8 in write low */
+
+/* The defines by what they actually do */
+
+#define GPIO_WRITE LOC_GPIOC_GPIO4
+#define GPIO_PROGRAM LOC_GPIOC_GPIO5
+#define GPIO_INIT LOC_GPIOC_GPIO6
+#define GPIO_DONE LOC_GPIOC_GPIO7
+
+#endif /* _TOR2_HW_H */
+
diff --git a/drivers/dahdi/tor2.c b/drivers/dahdi/tor2.c
new file mode 100644
index 0000000..cbff7a2
--- /dev/null
+++ b/drivers/dahdi/tor2.c
@@ -0,0 +1,1521 @@
+/*
+ * Tormenta 2 Quad-T1 PCI Driver
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Based on previous works, designs, and archetectures conceived and
+ * written by Jim Dixon <jim@lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001, Linux Support Services, 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/pci.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include "zaptel.h"
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+#define NEED_PCI_IDS
+#include "tor2-hw.h"
+#include "tor2fw.h"
+
+/*
+ * Tasklets provide better system interactive response at the cost of the
+ * possibility of losing a frame of data at very infrequent intervals. If
+ * you are more concerned with the performance of your machine, enable the
+ * tasklets. If you are strict about absolutely no drops, then do not enable
+ * tasklets.
+ */
+
+/* #define ENABLE_TASKLETS */
+
+/* this stuff needs to work for 64 bit systems, however using the macro causes
+ it to take twice as long */
+/* #define FIXTHISFOR64 */ /* as of now, un-comment for 32 bit only system */
+
+#define SPANS_PER_CARD 4
+#define MAX_SPANS 16
+
+#define FLAG_STARTED (1 << 0)
+
+#define TYPE_T1 1 /* is a T1 card */
+#define TYPE_E1 2 /* is an E1 card */
+
+struct tor2_chan {
+ /* Private pointer for channel. We want to know our
+ channel and span */
+ struct tor2 *tor;
+ int span; /* Index from 0 */
+};
+
+struct tor2_span {
+ /* Private pointer for span. We want to know our
+ span number and pointer to the tor device */
+ struct tor2 *tor;
+ int span; /* Index from 0 */
+};
+
+struct tor2 {
+ /* This structure exists one per card */
+ struct pci_dev *pci; /* Pointer to PCI device */
+ int num; /* Which card we are */
+ int syncsrc; /* active sync source */
+ int syncs[SPANS_PER_CARD]; /* sync sources */
+ int psyncs[SPANS_PER_CARD]; /* span-relative sync sources */
+ int alarmtimer[SPANS_PER_CARD]; /* Alarm timer */
+ char *type; /* Type of tormenta 2 card */
+ int irq; /* IRQ used by device */
+ int order; /* Order */
+ int flags; /* Device flags */
+ int syncpos[SPANS_PER_CARD]; /* span-relative sync sources */
+ int master; /* Are we master */
+ unsigned long plx_region; /* phy addr of PCI9030 registers */
+ unsigned long plx_len; /* length of PLX window */
+ volatile unsigned short *plx; /* Virtual representation of local space */
+ unsigned long xilinx32_region; /* 32 bit Region allocated to Xilinx */
+ unsigned long xilinx32_len; /* Length of 32 bit Xilinx region */
+ volatile unsigned int *mem32; /* Virtual representation of 32 bit Xilinx memory area */
+ unsigned long xilinx8_region; /* 8 bit Region allocated to Xilinx */
+ unsigned long xilinx8_len; /* Length of 8 bit Xilinx region */
+ volatile unsigned char *mem8; /* Virtual representation of 8 bit Xilinx memory area */
+ struct zt_span spans[SPANS_PER_CARD]; /* Spans */
+ struct tor2_span tspans[SPANS_PER_CARD]; /* Span data */
+ struct zt_chan *chans[SPANS_PER_CARD]; /* Pointers to blocks of 24(30/31) contiguous zt_chans for each span */
+ struct tor2_chan tchans[32 * SPANS_PER_CARD]; /* Channel user data */
+ unsigned char txsigs[SPANS_PER_CARD][16]; /* Copy of tx sig registers */
+ int loopupcnt[SPANS_PER_CARD]; /* loop up code counter */
+ int loopdowncnt[SPANS_PER_CARD];/* loop down code counter */
+ int spansstarted; /* number of spans started */
+ spinlock_t lock; /* lock context */
+ unsigned char leds; /* copy of LED register */
+ unsigned char ec_chunk1[SPANS_PER_CARD][32][ZT_CHUNKSIZE]; /* first EC chunk buffer */
+ unsigned char ec_chunk2[SPANS_PER_CARD][32][ZT_CHUNKSIZE]; /* second EC chunk buffer */
+#ifdef ENABLE_TASKLETS
+ int taskletrun;
+ int taskletsched;
+ int taskletpending;
+ int taskletexec;
+ int txerrors;
+ struct tasklet_struct tor2_tlet;
+#endif
+ int cardtype; /* card type, T1 or E1 */
+ unsigned int *datxlt; /* pointer to datxlt structure */
+ unsigned int passno; /* number of interrupt passes */
+};
+
+#define t1out(tor,span,reg,val) tor->mem8[((span - 1) * 0x100) + reg] = val
+#define t1in(tor,span,reg) tor->mem8[((span - 1) * 0x100) + reg]
+
+#ifdef ENABLE_TASKLETS
+static void tor2_tasklet(unsigned long data);
+#endif
+
+#define GPIOC (PLX_LOC_GPIOC >> 1) /* word-oriented address for PLX GPIOC reg. (32 bit reg.) */
+#define LAS2BRD (0x30 >> 1)
+#define LAS3BRD (0x34 >> 1)
+#define INTCSR (0x4c >> 1) /* word-oriented address for PLX INTCSR reg. */
+#define PLX_INTENA 0x43 /* enable, hi-going, level trigger */
+
+#define SYNCREG 0x400
+#define CTLREG 0x401
+#define LEDREG 0x402
+#define STATREG 0x400
+#define SWREG 0x401
+#define CTLREG1 0x404
+
+#define INTENA (1 + ((loopback & 3) << 5))
+#define OUTBIT (2 + ((loopback & 3) << 5))
+#define E1DIV 0x10
+#define INTACK (0x80 + ((loopback & 3) << 5))
+#define INTACTIVE 2
+#define MASTER (1 << 3)
+
+/* un-define this if you dont want NON-REV A hardware support */
+/* #define NONREVA 1 */
+
+#define SYNCSELF 0
+#define SYNC1 1
+#define SYNC2 2
+#define SYNC3 3
+#define SYNC4 4
+#define SYNCEXTERN 5
+
+#define LEDRED 2
+#define LEDGREEN 1
+
+#define MAX_TOR_CARDS 64
+
+struct tor2 *cards[MAX_TOR_CARDS];
+
+/* signalling bits */
+#define TOR_ABIT 8
+#define TOR_BBIT 4
+
+static int debug;
+static int japan;
+static int loopback;
+static int highestorder;
+static int timingcable;
+
+static void set_clear(struct tor2 *tor);
+static int tor2_startup(struct zt_span *span);
+static int tor2_shutdown(struct zt_span *span);
+static int tor2_rbsbits(struct zt_chan *chan, int bits);
+static int tor2_maint(struct zt_span *span, int cmd);
+static int tor2_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data);
+ZAP_IRQ_HANDLER(tor2_intr);
+
+/* translations of data channels for 24 channels in a 32 bit PCM highway */
+unsigned datxlt_t1[] = {
+ 1 ,2 ,3 ,5 ,6 ,7 ,9 ,10,11,13,14,15,17,18,19,21,22,23,25,26,27,29,30,31 };
+
+/* translations of data channels for 30/31 channels in a 32 bit PCM highway */
+unsigned datxlt_e1[] = {
+ 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
+ 25,26,27,28,29,30,31 };
+
+static int tor2_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+ int i;
+ struct tor2_span *p = span->pvt;
+
+ if (debug)
+ printk("Tor2: Configuring span %d\n", span->spanno);
+
+ span->syncsrc = p->tor->syncsrc;
+
+ /* remove this span number from the current sync sources, if there */
+ for (i = 0; i < SPANS_PER_CARD; i++) {
+ if (p->tor->syncs[i] == span->spanno) {
+ p->tor->syncs[i] = 0;
+ p->tor->psyncs[i] = 0;
+ }
+ }
+ p->tor->syncpos[p->span] = lc->sync;
+ /* if a sync src, put it in the proper place */
+ if (lc->sync) {
+ p->tor->syncs[lc->sync - 1] = span->spanno;
+ p->tor->psyncs[lc->sync - 1] = p->span + 1;
+ }
+ /* If we're already running, then go ahead and apply the changes */
+ if (span->flags & ZT_FLAG_RUNNING)
+ return tor2_startup(span);
+
+ return 0;
+}
+
+static int tor2_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ int alreadyrunning;
+ unsigned long flags;
+ struct tor2_chan *p = chan->pvt;
+
+ alreadyrunning = chan->span->flags & ZT_FLAG_RUNNING;
+ if (debug) {
+ if (alreadyrunning)
+ printk("Tor2: Reconfigured channel %d (%s) sigtype %d\n", chan->channo, chan->name, sigtype);
+ else
+ printk("Tor2: Configured channel %d (%s) sigtype %d\n", chan->channo, chan->name, sigtype);
+ }
+ /* nothing more to do if an E1 */
+ if (p->tor->cardtype == TYPE_E1) return 0;
+ spin_lock_irqsave(&p->tor->lock, flags);
+ if (alreadyrunning)
+ set_clear(p->tor);
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+ return 0;
+}
+
+static int tor2_open(struct zt_chan *chan)
+{
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static int tor2_close(struct zt_chan *chan)
+{
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static void init_spans(struct tor2 *tor)
+{
+ int x, y, c;
+ for (x = 0; x < SPANS_PER_CARD; x++) {
+ sprintf(tor->spans[x].name, "Tor2/%d/%d", tor->num, x + 1);
+ snprintf(tor->spans[x].desc, sizeof(tor->spans[x].desc) - 1,
+ "Tormenta 2 (PCI) Quad %s Card %d Span %d",
+ (tor->cardtype == TYPE_T1) ? "T1" : "E1", tor->num, x + 1);
+ tor->spans[x].manufacturer = "Digium";
+ zap_copy_string(tor->spans[x].devicetype, tor->type, sizeof(tor->spans[x].devicetype));
+ snprintf(tor->spans[x].location, sizeof(tor->spans[x].location) - 1,
+ "PCI Bus %02d Slot %02d", tor->pci->bus->number, PCI_SLOT(tor->pci->devfn) + 1);
+ tor->spans[x].spanconfig = tor2_spanconfig;
+ tor->spans[x].chanconfig = tor2_chanconfig;
+ tor->spans[x].startup = tor2_startup;
+ tor->spans[x].shutdown = tor2_shutdown;
+ tor->spans[x].rbsbits = tor2_rbsbits;
+ tor->spans[x].maint = tor2_maint;
+ tor->spans[x].open = tor2_open;
+ tor->spans[x].close = tor2_close;
+ if (tor->cardtype == TYPE_T1) {
+ tor->spans[x].channels = 24;
+ tor->spans[x].deflaw = ZT_LAW_MULAW;
+ tor->spans[x].linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
+ tor->spans[x].spantype = "T1";
+ } else {
+ tor->spans[x].channels = 31;
+ tor->spans[x].deflaw = ZT_LAW_ALAW;
+ tor->spans[x].linecompat = ZT_CONFIG_HDB3 | ZT_CONFIG_CCS | ZT_CONFIG_CRC4;
+ tor->spans[x].spantype = "E1";
+ }
+ tor->spans[x].chans = tor->chans[x];
+ tor->spans[x].flags = ZT_FLAG_RBS;
+ tor->spans[x].ioctl = tor2_ioctl;
+ tor->spans[x].pvt = &tor->tspans[x];
+ tor->tspans[x].tor = tor;
+ tor->tspans[x].span = x;
+ init_waitqueue_head(&tor->spans[x].maintq);
+ for (y=0;y<tor->spans[x].channels;y++) {
+ struct zt_chan *mychans = tor->chans[x] + y;
+ sprintf(mychans->name, "Tor2/%d/%d/%d", tor->num, x + 1, y + 1);
+ mychans->sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_FXSLS | ZT_SIG_FXSGS | ZT_SIG_FXSKS |
+ ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_FXOKS | ZT_SIG_CAS | ZT_SIG_SF | ZT_SIG_EM_E1;
+ c = (x * tor->spans[x].channels) + y;
+ mychans->pvt = &tor->tchans[c];
+ mychans->chanpos = y + 1;
+ tor->tchans[c].span = x;
+ tor->tchans[c].tor = tor;
+ }
+ }
+}
+
+static int __devinit tor2_launch(struct tor2 *tor)
+{
+ if (tor->spans[0].flags & ZT_FLAG_REGISTERED)
+ return 0;
+ printk("Tor2: Launching card: %d\n", tor->order);
+ if (zt_register(&tor->spans[0], 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", tor->spans[0].name);
+ return -1;
+ }
+ if (zt_register(&tor->spans[1], 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", tor->spans[1].name);
+ zt_unregister(&tor->spans[0]);
+ return -1;
+ }
+ if (zt_register(&tor->spans[2], 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", tor->spans[2].name);
+ zt_unregister(&tor->spans[0]);
+ zt_unregister(&tor->spans[1]);
+ return -1;
+ }
+ if (zt_register(&tor->spans[3], 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", tor->spans[3].name);
+ zt_unregister(&tor->spans[0]);
+ zt_unregister(&tor->spans[1]);
+ zt_unregister(&tor->spans[2]);
+ return -1;
+ }
+ tor->plx[INTCSR] = cpu_to_le16(PLX_INTENA); /* enable PLX interrupt */
+#ifdef ENABLE_TASKLETS
+ tasklet_init(&tor->tor2_tlet, tor2_tasklet, (unsigned long)tor);
+#endif
+ return 0;
+}
+
+static int __devinit tor2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int res,x,f;
+ struct tor2 *tor;
+ unsigned long endjif;
+ volatile unsigned long *gpdata_io,*lasdata_io;
+ unsigned long gpdata,lasdata;
+
+ res = pci_enable_device(pdev);
+ if (res)
+ return res;
+ tor = kmalloc(sizeof(struct tor2), GFP_KERNEL);
+ if (!tor)
+ return -ENOMEM;
+ memset(tor,0,sizeof(struct tor2));
+ spin_lock_init(&tor->lock);
+ for (x = 0; x < SPANS_PER_CARD; x++) {
+ tor->chans[x] = kmalloc(sizeof(struct zt_chan) * 31,GFP_KERNEL);
+ if (!tor->chans[x])
+ return -ENOMEM;
+ memset(tor->chans[x],0,sizeof(struct zt_chan) * 31);
+ }
+ /* Load the resources */
+ tor->pci = pdev;
+ tor->irq = pdev->irq;
+ if (tor->irq < 1) {
+ printk(KERN_ERR "No IRQ allocated for device\n");
+ goto err_out_free_tor;
+ }
+ tor->plx_region = pci_resource_start(pdev, 0);
+ tor->plx_len = pci_resource_len(pdev, 0);
+ tor->plx = ioremap(tor->plx_region, tor->plx_len);
+ /* We don't use the I/O space, so we dont do anything with section 1 */
+ tor->xilinx32_region = pci_resource_start(pdev, 2);
+ tor->xilinx32_len = pci_resource_len(pdev, 2);
+ tor->mem32 = ioremap(tor->xilinx32_region, tor->xilinx32_len);
+ tor->xilinx8_region = pci_resource_start(pdev, 3);
+ tor->xilinx8_len = pci_resource_len(pdev, 3);
+ tor->mem8 = ioremap(tor->xilinx8_region, tor->xilinx8_len);
+ /* Record what type */
+ tor->type = (char *)ent->driver_data;
+ /* Verify existence and accuracy of resources */
+ if (!tor->plx_region || !tor->plx ||
+ (pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+ printk(KERN_ERR "Invalid PLX 9030 Base resource\n");
+ goto err_out_free_tor;
+ }
+ if (!tor->xilinx32_region || !tor->mem32 ||
+ (pci_resource_flags(pdev, 2) & IORESOURCE_IO)) {
+ printk(KERN_ERR "Invalid Xilinx 32 bit Base resource\n");
+ goto err_out_free_tor;
+ }
+ if (!tor->xilinx8_region || !tor->mem8 ||
+ (pci_resource_flags(pdev, 3) & IORESOURCE_IO)) {
+ printk(KERN_ERR "Invalid Xilinx 8 bit Base resource\n");
+ goto err_out_free_tor;
+ }
+ /* Request regions */
+ if (!request_mem_region(tor->plx_region, tor->plx_len, tor->type)) {
+ printk(KERN_ERR "Unable to reserve PLX memory %08lx window at %08lx\n",
+ tor->plx_len, tor->plx_region);
+ goto err_out_free_tor;
+ }
+ if (!request_mem_region(tor->xilinx32_region, tor->xilinx32_len, tor->type)) {
+ printk(KERN_ERR "Unable to reserve Xilinx 32 bit memory %08lx window at %08lx\n",
+ tor->xilinx32_len, tor->xilinx32_region);
+ goto err_out_release_plx_region;
+ }
+ if (!request_mem_region(tor->xilinx8_region, tor->xilinx8_len, tor->type)) {
+ printk(KERN_ERR "Unable to reserve Xilinx memory %08lx window at %08lx\n",
+ tor->xilinx8_len, tor->xilinx8_region);
+ goto err_out_release_plx_region;
+ }
+ pci_set_drvdata(pdev, tor);
+ printk("Detected %s at 0x%lx/0x%lx irq %d\n", tor->type,
+ tor->xilinx32_region, tor->xilinx8_region,tor->irq);
+
+ for (x = 0; x < MAX_TOR_CARDS; x++) {
+ if (!cards[x]) break;
+ }
+ if (x >= MAX_TOR_CARDS) {
+ printk("No cards[] slot available!!\n");
+ goto err_out_release_all;
+ }
+ tor->num = x;
+ cards[x] = tor;
+
+ /* start programming mode */
+ gpdata_io = (unsigned long *)&tor->plx[GPIOC];
+ gpdata = le32_to_cpu(*gpdata_io);
+
+ gpdata |= GPIO_WRITE; /* make sure WRITE is not asserted */
+ *gpdata_io = cpu_to_le32(gpdata);
+
+ gpdata &= ~GPIO_PROGRAM; /* activate the PROGRAM signal */
+ *gpdata_io = cpu_to_le32(gpdata);
+
+ /* wait for INIT and DONE to go low */
+ endjif = jiffies + 10;
+ while (le32_to_cpu(*gpdata_io) & (GPIO_INIT | GPIO_DONE) && (jiffies <= endjif));
+
+ if (endjif < jiffies) {
+ printk("Timeout waiting for INIT and DONE to go low\n");
+ goto err_out_release_all;
+ }
+ if (debug) printk("fwload: Init and done gone to low\n");
+ gpdata |= GPIO_PROGRAM;
+ *gpdata_io = cpu_to_le32(gpdata); /* de-activate the PROGRAM signal */
+ /* wait for INIT to go high (clearing done */
+ endjif = jiffies + 10;
+ while (!(le32_to_cpu(*gpdata_io) & GPIO_INIT) && (jiffies <= endjif));
+ if (endjif < jiffies) {
+ printk("Timeout waiting for INIT to go high\n");
+ goto err_out_release_all;
+ }
+
+ if (debug) printk("fwload: Init went high (clearing done)\nNow loading...\n");
+ /* assert WRITE signal */
+ gpdata &= ~GPIO_WRITE;
+ *gpdata_io = cpu_to_le32(gpdata);
+ for (x = 0; x < sizeof(tor2fw); x++)
+ {
+ /* write the byte */
+ *tor->mem8 = tor2fw[x];
+ /* if DONE signal, we're done, exit */
+ if (le32_to_cpu(*gpdata_io) & GPIO_DONE) break;
+ /* if INIT drops, we're screwed, exit */
+ if (!(le32_to_cpu(*gpdata_io) & GPIO_INIT)) break;
+ }
+ if (debug) printk("fwload: Transferred %d bytes into chip\n",x);
+ /* Wait for FIFO to clear */
+ endjif = jiffies + 2;
+ while (jiffies < endjif); /* wait */
+ /* de-assert write signal */
+ gpdata |= GPIO_WRITE;
+ *gpdata_io = cpu_to_le32(gpdata);
+ if (debug) printk("fwload: Loading done!\n");
+
+ /* Wait for FIFO to clear */
+ endjif = jiffies + 2;
+ while (jiffies < endjif); /* wait */
+ if (!(le32_to_cpu(*gpdata_io) & GPIO_INIT))
+ {
+ printk("Drove Init low!! CRC Error!!!\n");
+ goto err_out_release_all;
+ }
+ if (!(le32_to_cpu(*gpdata_io) & GPIO_DONE))
+ {
+ printk("Did not get DONE signal. Short file maybe??\n");
+ goto err_out_release_all;
+ }
+ printk("Xilinx Chip successfully loaded, configured and started!!\n");
+
+ tor->mem8[SYNCREG] = 0;
+ tor->mem8[CTLREG] = 0;
+ tor->mem8[CTLREG1] = 0;
+ tor->mem8[LEDREG] = 0;
+
+ /* set the LA2BRD register so that we enable block transfer, read
+ pre-fetch, and set to maximum read pre-fetch size */
+ lasdata_io = (unsigned long *)&tor->plx[LAS2BRD];
+ lasdata = *lasdata_io;
+ lasdata |= 0x39;
+ *lasdata_io = lasdata;
+
+ /* set the LA3BRD register so that we enable block transfer */
+ lasdata_io = (unsigned long *)&tor->plx[LAS3BRD];
+ lasdata = *lasdata_io;
+ lasdata |= 1;
+ *lasdata_io = lasdata;
+
+ /* check part revision data */
+ x = t1in(tor,1,0xf) & 15;
+#ifdef NONREVA
+ if (x > 3)
+ {
+ tor->mem8[CTLREG1] = NONREVA;
+ }
+#endif
+ for (x = 0; x < 256; x++) tor->mem32[x] = 0x7f7f7f7f;
+
+
+ if (request_irq(tor->irq, tor2_intr, ZAP_IRQ_SHARED_DISABLED, "tor2", tor)) {
+ printk(KERN_ERR "Unable to request tormenta IRQ %d\n", tor->irq);
+ goto err_out_release_all;
+ }
+
+ if (t1in(tor,1,0xf) & 0x80) {
+ printk("Tormenta 2 Quad E1/PRA Card\n");
+ tor->cardtype = TYPE_E1;
+ tor->datxlt = datxlt_e1;
+ } else {
+ printk("Tormenta 2 Quad T1/PRI Card\n");
+ tor->cardtype = TYPE_T1;
+ tor->datxlt = datxlt_t1;
+ }
+ init_spans(tor);
+
+ tor->order = tor->mem8[SWREG];
+ printk("Detected Card number: %d\n", tor->order);
+
+ /* Launch cards as appropriate */
+ x = 0;
+ for (;;) {
+ /* Find a card to activate */
+ f = 0;
+ for (x=0;cards[x];x++) {
+ if (cards[x]->order <= highestorder) {
+ tor2_launch(cards[x]);
+ if (cards[x]->order == highestorder)
+ f = 1;
+ }
+ }
+ /* If we found at least one, increment the highest order and search again, otherwise stop */
+ if (f)
+ highestorder++;
+ else
+ break;
+ }
+
+ return 0;
+
+err_out_release_all:
+ release_mem_region(tor->xilinx32_region, tor->xilinx32_len);
+ release_mem_region(tor->xilinx8_region, tor->xilinx8_len);
+err_out_release_plx_region:
+ release_mem_region(tor->plx_region, tor->plx_len);
+err_out_free_tor:
+ if (tor->plx) iounmap((void *)tor->plx);
+ if (tor->mem8) iounmap((void *)tor->mem8);
+ if (tor->mem32) iounmap((void *)tor->mem32);
+ if (tor) {
+ for (x = 0; x < 3; x++) kfree(tor->chans[x]);
+ kfree(tor);
+ }
+ return -ENODEV;
+}
+
+static struct pci_driver tor2_driver;
+
+static void __devexit tor2_remove(struct pci_dev *pdev)
+{
+ int x;
+ struct tor2 *tor;
+ tor = pci_get_drvdata(pdev);
+ if (!tor)
+ BUG();
+ tor->mem8[SYNCREG] = 0;
+ tor->mem8[CTLREG] = 0;
+ tor->mem8[LEDREG] = 0;
+ tor->plx[INTCSR] = cpu_to_le16(0);
+ free_irq(tor->irq, tor);
+ if (tor->spans[0].flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&tor->spans[0]);
+ if (tor->spans[1].flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&tor->spans[1]);
+ if (tor->spans[2].flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&tor->spans[2]);
+ if (tor->spans[3].flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&tor->spans[3]);
+ release_mem_region(tor->plx_region, tor->plx_len);
+ release_mem_region(tor->xilinx32_region, tor->xilinx32_len);
+ release_mem_region(tor->xilinx8_region, tor->xilinx8_len);
+ if (tor->plx) iounmap((void *)tor->plx);
+ if (tor->mem8) iounmap((void *)tor->mem8);
+ if (tor->mem32) iounmap((void *)tor->mem32);
+
+ cards[tor->num] = 0;
+ pci_set_drvdata(pdev, NULL);
+ for (x = 0; x < 3; x++)
+ if (tor->chans[x])
+ kfree(tor->chans[x]);
+ kfree(tor);
+}
+
+static struct pci_driver tor2_driver = {
+ name: "tormenta2",
+ probe: tor2_probe,
+#ifdef LINUX26
+ remove: __devexit_p(tor2_remove),
+#else
+ remove: tor2_remove,
+#endif
+ id_table: tor2_pci_ids,
+};
+
+static int __init tor2_init(void) {
+ int res;
+ res = zap_pci_module(&tor2_driver);
+ printk("Registered Tormenta2 PCI\n");
+ return res;
+}
+
+static void __exit tor2_cleanup(void) {
+ pci_unregister_driver(&tor2_driver);
+ printk("Unregistered Tormenta2\n");
+}
+
+static void set_clear(struct tor2 *tor)
+{
+ int i,j,s;
+ unsigned short val=0;
+ for (s = 0; s < SPANS_PER_CARD; s++) {
+ for (i = 0; i < 24; i++) {
+ j = (i/8);
+ if (tor->spans[s].chans[i].flags & ZT_FLAG_CLEAR)
+ val |= 1 << (i % 8);
+
+ if ((i % 8)==7) {
+#if 0
+ printk("Putting %d in register %02x on span %d\n",
+ val, 0x39 + j, 1 + s);
+#endif
+ t1out(tor,1 + s, 0x39 + j, val);
+ val = 0;
+ }
+ }
+ }
+
+}
+
+
+static int tor2_rbsbits(struct zt_chan *chan, int bits)
+{
+ u_char m,c;
+ int k,n,b;
+ struct tor2_chan *p = chan->pvt;
+ unsigned long flags;
+#if 0
+ printk("Setting bits to %d on channel %s\n", bits, chan->name);
+#endif
+ if (p->tor->cardtype == TYPE_E1) { /* do it E1 way */
+ if (chan->chanpos == 16) return 0;
+ n = chan->chanpos - 1;
+ if (chan->chanpos > 16) n--;
+ k = p->span;
+ b = (n % 15) + 1;
+ c = p->tor->txsigs[k][b];
+ m = (n / 15) * 4; /* nibble selector */
+ c &= (15 << m); /* keep the other nibble */
+ c |= (bits & 15) << (4 - m); /* put our new nibble here */
+ p->tor->txsigs[k][b] = c;
+ /* output them to the chip */
+ t1out(p->tor,k + 1,0x40 + b,c);
+ return 0;
+ }
+ n = chan->chanpos - 1;
+ k = p->span;
+ b = (n / 8); /* get byte number */
+ m = 1 << (n & 7); /* get mask */
+ c = p->tor->txsigs[k][b];
+ c &= ~m; /* clear mask bit */
+ /* set mask bit, if bit is to be set */
+ if (bits & ZT_ABIT) c |= m;
+ p->tor->txsigs[k][b] = c;
+ spin_lock_irqsave(&p->tor->lock, flags);
+ t1out(p->tor,k + 1,0x70 + b,c);
+ b += 3; /* now points to b bit stuff */
+ /* get current signalling values */
+ c = p->tor->txsigs[k][b];
+ c &= ~m; /* clear mask bit */
+ /* set mask bit, if bit is to be set */
+ if (bits & ZT_BBIT) c |= m;
+ /* save new signalling values */
+ p->tor->txsigs[k][b] = c;
+ /* output them into the chip */
+ t1out(p->tor,k + 1,0x70 + b,c);
+ b += 3; /* now points to c bit stuff */
+ /* get current signalling values */
+ c = p->tor->txsigs[k][b];
+ c &= ~m; /* clear mask bit */
+ /* set mask bit, if bit is to be set */
+ if (bits & ZT_CBIT) c |= m;
+ /* save new signalling values */
+ p->tor->txsigs[k][b] = c;
+ /* output them into the chip */
+ t1out(p->tor,k + 1,0x70 + b,c);
+ b += 3; /* now points to d bit stuff */
+ /* get current signalling values */
+ c = p->tor->txsigs[k][b];
+ c &= ~m; /* clear mask bit */
+ /* set mask bit, if bit is to be set */
+ if (bits & ZT_DBIT) c |= m;
+ /* save new signalling values */
+ p->tor->txsigs[k][b] = c;
+ /* output them into the chip */
+ t1out(p->tor,k + 1,0x70 + b,c);
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+ return 0;
+}
+
+static int tor2_shutdown(struct zt_span *span)
+{
+ int i;
+ int tspan;
+ int wasrunning;
+ unsigned long flags;
+ struct tor2_span *p = span->pvt;
+
+ tspan = p->span + 1;
+ if (tspan < 0) {
+ printk("Tor2: Span '%d' isn't us?\n", span->spanno);
+ return -1;
+ }
+
+ spin_lock_irqsave(&p->tor->lock, flags);
+ wasrunning = span->flags & ZT_FLAG_RUNNING;
+
+ span->flags &= ~ZT_FLAG_RUNNING;
+ /* Zero out all registers */
+ if (p->tor->cardtype == TYPE_E1) {
+ for (i = 0; i < 192; i++)
+ t1out(p->tor,tspan, i, 0);
+ } else {
+ for (i = 0; i < 160; i++)
+ t1out(p->tor,tspan, i, 0);
+ }
+ if (wasrunning)
+ p->tor->spansstarted--;
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+ if (!(p->tor->spans[0].flags & ZT_FLAG_RUNNING) &&
+ !(p->tor->spans[1].flags & ZT_FLAG_RUNNING) &&
+ !(p->tor->spans[2].flags & ZT_FLAG_RUNNING) &&
+ !(p->tor->spans[3].flags & ZT_FLAG_RUNNING))
+ /* No longer in use, disable interrupts */
+ p->tor->mem8[CTLREG] = 0;
+ if (debug)
+ printk("Span %d (%s) shutdown\n", span->spanno, span->name);
+ return 0;
+}
+
+
+static int tor2_startup(struct zt_span *span)
+{
+ unsigned long endjif;
+ int i;
+ int tspan;
+ unsigned long flags;
+ char *coding;
+ char *framing;
+ char *crcing;
+ int alreadyrunning;
+ struct tor2_span *p = span->pvt;
+
+ tspan = p->span + 1;
+ if (tspan < 0) {
+ printk("Tor2: Span '%d' isn't us?\n", span->spanno);
+ return -1;
+ }
+
+ spin_lock_irqsave(&p->tor->lock, flags);
+
+ alreadyrunning = span->flags & ZT_FLAG_RUNNING;
+
+ /* initialize the start value for the entire chunk of last ec buffer */
+ for (i = 0; i < span->channels; i++)
+ {
+ memset(p->tor->ec_chunk1[p->span][i],
+ ZT_LIN2X(0,&span->chans[i]),ZT_CHUNKSIZE);
+ memset(p->tor->ec_chunk2[p->span][i],
+ ZT_LIN2X(0,&span->chans[i]),ZT_CHUNKSIZE);
+ }
+ /* Force re-evaluation of the timing source */
+ if (timingcable)
+ p->tor->syncsrc = -1;
+
+ if (p->tor->cardtype == TYPE_E1) { /* if this is an E1 card */
+ unsigned char tcr1,ccr1,tcr2;
+ if (!alreadyrunning) {
+ p->tor->mem8[SYNCREG] = SYNCSELF;
+ p->tor->mem8[CTLREG] = E1DIV;
+ p->tor->mem8[LEDREG] = 0;
+ /* Force re-evaluation of sync src */
+ /* Zero out all registers */
+ for (i = 0; i < 192; i++)
+ t1out(p->tor,tspan, i, 0);
+
+ /* Set up for Interleaved Serial Bus operation in byte mode */
+ /* Set up all the spans every time, so we are sure they are
+ in a consistent state. If we don't, a card without all
+ its spans configured misbehaves in strange ways. */
+ t1out(p->tor,1,0xb5,9);
+ t1out(p->tor,2,0xb5,8);
+ t1out(p->tor,3,0xb5,8);
+ t1out(p->tor,4,0xb5,8);
+
+ t1out(p->tor,tspan,0x1a,4); /* CCR2: set LOTCMC */
+ for (i = 0; i <= 8; i++) t1out(p->tor,tspan,i,0);
+ for (i = 0x10; i <= 0x4f; i++) if (i != 0x1a) t1out(p->tor,tspan,i,0);
+ t1out(p->tor,tspan,0x10,0x20); /* RCR1: Rsync as input */
+ t1out(p->tor,tspan,0x11,6); /* RCR2: Sysclk=2.048 Mhz */
+ t1out(p->tor,tspan,0x12,9); /* TCR1: TSiS mode */
+ }
+ ccr1 = 0;
+ crcing = "";
+ tcr1 = 9; /* base TCR1 value: TSis mode */
+ tcr2 = 0;
+ if (span->lineconfig & ZT_CONFIG_CCS) {
+ ccr1 |= 8; /* CCR1: Rx Sig mode: CCS */
+ coding = "CCS";
+ } else {
+ tcr1 |= 0x20;
+ coding = "CAS";
+ }
+ if (span->lineconfig & ZT_CONFIG_HDB3) {
+ ccr1 |= 0x44; /* CCR1: TX and RX HDB3 */
+ framing = "HDB3";
+ } else framing = "AMI";
+ if (span->lineconfig & ZT_CONFIG_CRC4) {
+ ccr1 |= 0x11; /* CCR1: TX and TX CRC4 */
+ tcr2 |= 0x02; /* TCR2: CRC4 bit auto */
+ crcing = "/CRC4";
+ }
+ t1out(p->tor,tspan,0x12,tcr1);
+ t1out(p->tor,tspan,0x13,tcr2);
+ t1out(p->tor,tspan,0x14,ccr1);
+ t1out(p->tor,tspan, 0x18, 0x20); /* 120 Ohm, normal */
+
+ if (!alreadyrunning) {
+ t1out(p->tor,tspan,0x1b,0x8a); /* CCR3: LIRST & TSCLKM */
+ t1out(p->tor,tspan,0x20,0x1b); /* TAFR */
+ t1out(p->tor,tspan,0x21,0x5f); /* TNAFR */
+ t1out(p->tor,tspan,0x40,0xb); /* TSR1 */
+ for (i = 0x41; i <= 0x4f; i++) t1out(p->tor,tspan,i,0x55);
+ for (i = 0x22; i <= 0x25; i++) t1out(p->tor,tspan,i,0xff);
+ /* Wait 100 ms */
+ endjif = jiffies + 10;
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+ while (jiffies < endjif); /* wait 100 ms */
+ spin_lock_irqsave(&p->tor->lock, flags);
+ t1out(p->tor,tspan,0x1b,0x9a); /* CCR3: set also ESR */
+ t1out(p->tor,tspan,0x1b,0x82); /* CCR3: TSCLKM only now */
+
+ span->flags |= ZT_FLAG_RUNNING;
+ p->tor->spansstarted++;
+
+ /* enable interrupts */
+ p->tor->mem8[CTLREG] = INTENA | E1DIV;
+ }
+
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+
+ if (debug) {
+ if (alreadyrunning)
+ printk("Tor2: Reconfigured span %d (%s/%s%s) 120 Ohms\n", span->spanno, coding, framing, crcing);
+ else
+ printk("Tor2: Startup span %d (%s/%s%s) 120 Ohms\n", span->spanno, coding, framing, crcing);
+ }
+ } else { /* is a T1 card */
+
+ if (!alreadyrunning) {
+ p->tor->mem8[SYNCREG] = SYNCSELF;
+ p->tor->mem8[CTLREG] = 0;
+ p->tor->mem8[LEDREG] = 0;
+ /* Zero out all registers */
+ for (i = 0; i < 160; i++)
+ t1out(p->tor,tspan, i, 0);
+
+ /* Set up for Interleaved Serial Bus operation in byte mode */
+ /* Set up all the spans every time, so we are sure they are
+ in a consistent state. If we don't, a card without all
+ its spans configured misbehaves in strange ways. */
+ t1out(p->tor,1,0x94,9);
+ t1out(p->tor,2,0x94,8);
+ t1out(p->tor,3,0x94,8);
+ t1out(p->tor,4,0x94,8);
+ /* Full-on Sync required (RCR1) */
+ t1out(p->tor,tspan, 0x2b, 8);
+ /* RSYNC is an input (RCR2) */
+ t1out(p->tor,tspan, 0x2c, 8);
+ /* RBS enable (TCR1) */
+ t1out(p->tor,tspan, 0x35, 0x10);
+ /* TSYNC to be output (TCR2) */
+ t1out(p->tor,tspan, 0x36, 4);
+ /* Tx & Rx Elastic store, sysclk(s) = 2.048 mhz, loopback controls (CCR1) */
+ t1out(p->tor,tspan, 0x37, 0x9c);
+ /* Set up received loopup and loopdown codes */
+ t1out(p->tor,tspan, 0x12, 0x22);
+ t1out(p->tor,tspan, 0x14, 0x80);
+ t1out(p->tor,tspan, 0x15, 0x80);
+ /* Setup japanese mode if appropriate */
+ t1out(p->tor,tspan,0x19,(japan ? 0x80 : 0x00)); /* no local loop */
+ t1out(p->tor,tspan,0x1e,(japan ? 0x80 : 0x00)); /* no local loop */
+ }
+ /* Enable F bits pattern */
+ i = 0x20;
+ if (span->lineconfig & ZT_CONFIG_ESF)
+ i = 0x88;
+ if (span->lineconfig & ZT_CONFIG_B8ZS)
+ i |= 0x44;
+ t1out(p->tor,tspan, 0x38, i);
+ if (i & 0x80)
+ coding = "ESF";
+ else
+ coding = "SF";
+ if (i & 0x40)
+ framing = "B8ZS";
+ else {
+ framing = "AMI";
+ t1out(p->tor,tspan,0x7e,0x1c); /* F bits pattern (0x1c) into FDL register */
+ }
+ t1out(p->tor,tspan, 0x7c, span->txlevel << 5);
+
+ if (!alreadyrunning) {
+ /* LIRST to reset line interface */
+ t1out(p->tor,tspan, 0x0a, 0x80);
+
+ /* Wait 100 ms */
+ endjif = jiffies + 10;
+
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+
+ while (jiffies < endjif); /* wait 100 ms */
+
+ spin_lock_irqsave(&p->tor->lock, flags);
+
+ t1out(p->tor,tspan,0x0a,0x30); /* LIRST back to normal, Resetting elastic stores */
+
+ span->flags |= ZT_FLAG_RUNNING;
+ p->tor->spansstarted++;
+
+ /* enable interrupts */
+ p->tor->mem8[CTLREG] = INTENA;
+ }
+
+ set_clear(p->tor);
+
+ spin_unlock_irqrestore(&p->tor->lock, flags);
+
+ if (debug) {
+ if (alreadyrunning)
+ printk("Tor2: Reconfigured span %d (%s/%s) LBO: %s\n", span->spanno, coding, framing, zt_lboname(span->txlevel));
+ else
+ printk("Tor2: Startup span %d (%s/%s) LBO: %s\n", span->spanno, coding, framing, zt_lboname(span->txlevel));
+ }
+ }
+ if (p->tor->syncs[0] == span->spanno) printk("SPAN %d: Primary Sync Source\n",span->spanno);
+ if (p->tor->syncs[1] == span->spanno) printk("SPAN %d: Secondary Sync Source\n",span->spanno);
+ if (p->tor->syncs[2] == span->spanno) printk("SPAN %d: Tertiary Sync Source\n",span->spanno);
+ if (p->tor->syncs[3] == span->spanno) printk("SPAN %d: Quaternary Sync Source\n",span->spanno);
+ return 0;
+}
+
+static int tor2_maint(struct zt_span *span, int cmd)
+{
+ struct tor2_span *p = span->pvt;
+
+ int tspan = p->span + 1;
+
+ if (p->tor->cardtype == TYPE_E1)
+ {
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ t1out(p->tor,tspan,0xa8,0); /* no loops */
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ t1out(p->tor,tspan,0xa8,0x40); /* local loop */
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ t1out(p->tor,tspan,0xa8,0x80); /* remote loop */
+ break;
+ case ZT_MAINT_LOOPUP:
+ case ZT_MAINT_LOOPDOWN:
+ case ZT_MAINT_LOOPSTOP:
+ return -ENOSYS;
+ default:
+ printk("Tor2: Unknown maint command: %d\n", cmd);
+ break;
+ }
+ return 0;
+ }
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ t1out(p->tor,tspan,0x19,(japan ? 0x80 : 0x00)); /* no local loop */
+ t1out(p->tor,tspan,0x0a,0); /* no remote loop */
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ t1out(p->tor,tspan,0x19,0x40 | (japan ? 0x80 : 0x00)); /* local loop */
+ t1out(p->tor,tspan,0x0a,0); /* no remote loop */
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ t1out(p->tor,tspan,0x1e,(japan ? 0x80 : 0x00)); /* no local loop */
+ t1out(p->tor,tspan,0x0a,0x40); /* remote loop */
+ break;
+ case ZT_MAINT_LOOPUP:
+ t1out(p->tor,tspan,0x30,2); /* send loopup code */
+ t1out(p->tor,tspan,0x12,0x22); /* send loopup code */
+ t1out(p->tor,tspan,0x13,0x80); /* send loopup code */
+ break;
+ case ZT_MAINT_LOOPDOWN:
+ t1out(p->tor,tspan,0x30,2); /* send loopdown code */
+ t1out(p->tor,tspan,0x12,0x62); /* send loopdown code */
+ t1out(p->tor,tspan,0x13,0x90); /* send loopdown code */
+ break;
+ case ZT_MAINT_LOOPSTOP:
+ t1out(p->tor,tspan,0x30,0); /* stop sending loopup code */
+ break;
+ default:
+ printk("Tor2: Unknown maint command: %d\n", cmd);
+ break;
+ }
+ return 0;
+}
+
+static inline void tor2_run(struct tor2 *tor)
+{
+ int x,y;
+ for (x = 0; x < SPANS_PER_CARD; x++) {
+ if (tor->spans[x].flags & ZT_FLAG_RUNNING) {
+ /* since the Tormenta 2 PCI is double-buffered, you
+ need to delay the transmit data 2 entire chunks so
+ that the transmit will be in sync with the receive */
+ for (y=0;y<tor->spans[x].channels;y++) {
+ zt_ec_chunk(&tor->spans[x].chans[y],
+ tor->spans[x].chans[y].readchunk,
+ tor->ec_chunk2[x][y]);
+ memcpy(tor->ec_chunk2[x][y],tor->ec_chunk1[x][y],
+ ZT_CHUNKSIZE);
+ memcpy(tor->ec_chunk1[x][y],
+ tor->spans[x].chans[y].writechunk,
+ ZT_CHUNKSIZE);
+ }
+ zt_receive(&tor->spans[x]);
+ }
+ }
+ for (x = 0; x < SPANS_PER_CARD; x++) {
+ if (tor->spans[x].flags & ZT_FLAG_RUNNING)
+ zt_transmit(&tor->spans[x]);
+ }
+}
+
+#ifdef ENABLE_TASKLETS
+static void tor2_tasklet(unsigned long data)
+{
+ struct tor2 *tor = (struct tor2 *)data;
+ tor->taskletrun++;
+ if (tor->taskletpending) {
+ tor->taskletexec++;
+ tor2_run(tor);
+ }
+ tor->taskletpending = 0;
+}
+#endif
+
+static int syncsrc = 0;
+static int syncnum = 0 /* -1 */;
+static int syncspan = 0;
+#ifdef DEFINE_SPINLOCK
+static DEFINE_SPINLOCK(synclock);
+#else
+static spinlock_t synclock = SPIN_LOCK_UNLOCKED;
+#endif
+
+static int tor2_findsync(struct tor2 *tor)
+{
+ int i;
+ int x;
+ unsigned long flags;
+ int p;
+ int nonzero;
+ int newsyncsrc = 0; /* Zaptel span number */
+ int newsyncnum = 0; /* tor2 card number */
+ int newsyncspan = 0; /* span on given tor2 card */
+ spin_lock_irqsave(&synclock, flags);
+#if 1
+ if (!tor->num) {
+ /* If we're the first card, go through all the motions, up to 8 levels
+ of sync source */
+ p = 1;
+ while (p < 8) {
+ nonzero = 0;
+ for (x=0;cards[x];x++) {
+ for (i = 0; i < SPANS_PER_CARD; i++) {
+ if (cards[x]->syncpos[i]) {
+ nonzero = 1;
+ if ((cards[x]->syncpos[i] == p) &&
+ !(cards[x]->spans[i].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_LOOPBACK)) &&
+ (cards[x]->spans[i].flags & ZT_FLAG_RUNNING)) {
+ /* This makes a good sync source */
+ newsyncsrc = cards[x]->spans[i].spanno;
+ newsyncnum = x;
+ newsyncspan = i + 1;
+ /* Jump out */
+ goto found;
+ }
+ }
+ }
+ }
+ if (nonzero)
+ p++;
+ else
+ break;
+ }
+found:
+ if ((syncnum != newsyncnum) || (syncsrc != newsyncsrc) || (newsyncspan != syncspan)) {
+ syncnum = newsyncnum;
+ syncsrc = newsyncsrc;
+ syncspan = newsyncspan;
+ if (debug) printk("New syncnum: %d, syncsrc: %d, syncspan: %d\n", syncnum, syncsrc, syncspan);
+ }
+ }
+#endif
+ /* update sync src info */
+ if (tor->syncsrc != syncsrc) {
+ tor->syncsrc = syncsrc;
+ /* Update sync sources */
+ for (i = 0; i < SPANS_PER_CARD; i++) {
+ tor->spans[i].syncsrc = tor->syncsrc;
+ }
+ if (syncnum == tor->num) {
+#if 1
+ /* actually set the sync register */
+ tor->mem8[SYNCREG] = syncspan;
+#endif
+ if (debug) printk("Card %d, using sync span %d, master\n", tor->num, syncspan);
+ tor->master = MASTER;
+ } else {
+#if 1
+ /* time from the timing cable */
+ tor->mem8[SYNCREG] = SYNCEXTERN;
+#endif
+ tor->master = 0;
+ if (debug) printk("Card %d, using Timing Bus, NOT master\n", tor->num);
+ }
+ }
+ spin_unlock_irqrestore(&synclock, flags);
+ return 0;
+}
+
+ZAP_IRQ_HANDLER(tor2_intr)
+{
+ int n, i, j, k, syncsrc;
+ unsigned int rxword,txword;
+
+ unsigned char c, rxc;
+ unsigned char abits, bbits;
+ struct tor2 *tor = (struct tor2 *) dev_id;
+
+ /* make sure its a real interrupt for us */
+ if (!(tor->mem8[STATREG] & INTACTIVE)) /* if not, just return */
+ {
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+ }
+
+ if (tor->cardtype == TYPE_E1)
+ /* set outbit, interrupt enable, and ack interrupt */
+ tor->mem8[CTLREG] = OUTBIT | INTENA | INTACK | E1DIV | tor->master;
+ else
+ /* set outbit, interrupt enable, and ack interrupt */
+ tor->mem8[CTLREG] = OUTBIT | INTENA | INTACK | tor->master;
+
+#if 0
+ if (!tor->passno)
+ printk("Interrupt handler\n");
+#endif
+
+ /* do the transmit output */
+ for (n = 0; n < tor->spans[0].channels; n++) {
+ for (i = 0; i < ZT_CHUNKSIZE; i++) {
+ /* span 1 */
+ txword = tor->spans[0].chans[n].writechunk[i] << 24;
+ /* span 2 */
+ txword |= tor->spans[1].chans[n].writechunk[i] << 16;
+ /* span 3 */
+ txword |= tor->spans[2].chans[n].writechunk[i] << 8;
+ /* span 4 */
+ txword |= tor->spans[3].chans[n].writechunk[i];
+ /* write to part */
+#ifdef FIXTHISFOR64
+ tor->mem32[tor->datxlt[n] + (32 * i)] = txword;
+#else
+ tor->mem32[tor->datxlt[n] + (32 * i)] = cpu_to_le32(txword);
+#endif
+ }
+ }
+
+ /* Do the receive input */
+ for (n = 0; n < tor->spans[0].channels; n++) {
+ for (i = 0; i < ZT_CHUNKSIZE; i++) {
+ /* read from */
+#ifdef FIXTHISFOR64
+ rxword = tor->mem32[tor->datxlt[n] + (32 * i)];
+#else
+ rxword = le32_to_cpu(tor->mem32[tor->datxlt[n] + (32 * i)]);
+#endif
+ /* span 1 */
+ tor->spans[0].chans[n].readchunk[i] = rxword >> 24;
+ /* span 2 */
+ tor->spans[1].chans[n].readchunk[i] = (rxword & 0xff0000) >> 16;
+ /* span 3 */
+ tor->spans[2].chans[n].readchunk[i] = (rxword & 0xff00) >> 8;
+ /* span 4 */
+ tor->spans[3].chans[n].readchunk[i] = rxword & 0xff;
+ }
+ }
+
+ i = tor->passno & 15;
+ /* if an E1 card, do rx signalling for it */
+ if ((i < 3) && (tor->cardtype == TYPE_E1)) { /* if an E1 card */
+ for (j = (i * 5); j < (i * 5) + 5; j++) {
+ for (k = 1; k <= SPANS_PER_CARD; k++) {
+ c = t1in(tor,k,0x31 + j);
+ rxc = c & 15;
+ if (rxc != tor->spans[k - 1].chans[j + 16].rxsig) {
+ /* Check for changes in received bits */
+ if (!(tor->spans[k - 1].chans[j + 16].sig & ZT_SIG_CLEAR))
+ zt_rbsbits(&tor->spans[k - 1].chans[j + 16], rxc);
+ }
+ rxc = c >> 4;
+ if (rxc != tor->spans[k - 1].chans[j].rxsig) {
+ /* Check for changes in received bits */
+ if (!(tor->spans[k - 1].chans[j].sig & ZT_SIG_CLEAR))
+ zt_rbsbits(&tor->spans[k - 1].chans[j], rxc);
+ }
+ }
+ }
+ }
+
+ /* if a T1, do the signalling */
+ if ((i < 12) && (tor->cardtype == TYPE_T1)) {
+ k = (i / 3); /* get span */
+ n = (i % 3); /* get base */
+ abits = t1in(tor,k + 1, 0x60 + n);
+ bbits = t1in(tor,k + 1, 0x63 + n);
+ for (j=0; j< 8; j++) {
+ /* Get channel number */
+ i = (n * 8) + j;
+ rxc = 0;
+ if (abits & (1 << j)) rxc |= ZT_ABIT;
+ if (bbits & (1 << j)) rxc |= ZT_BBIT;
+ if (tor->spans[k].chans[i].rxsig != rxc) {
+ /* Check for changes in received bits */
+ if (!(tor->spans[k].chans[i].sig & ZT_SIG_CLEAR)) {
+ zt_rbsbits(&tor->spans[k].chans[i], rxc);
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < SPANS_PER_CARD; i++) { /* Go thru all the spans */
+ /* if alarm timer, and it's timed out */
+ if (tor->alarmtimer[i]) {
+ if (!--tor->alarmtimer[i]) {
+ /* clear recover status */
+ tor->spans[i].alarms &= ~ZT_ALARM_RECOVER;
+ if (tor->cardtype == TYPE_E1)
+ t1out(tor,i + 1,0x21,0x5f); /* turn off yel */
+ else
+ t1out(tor,i + 1,0x35,0x10); /* turn off yel */
+ zt_alarm_notify(&tor->spans[i]); /* let them know */
+ }
+ }
+ }
+
+ i = tor->passno & 15;
+ if ((i >= 10) && (i <= 13) && !(tor->passno & 0x30))
+ {
+ j = 0; /* clear this alarm status */
+ i -= 10;
+ if (tor->cardtype == TYPE_T1) {
+ c = t1in(tor,i + 1,0x31); /* get RIR2 */
+ tor->spans[i].rxlevel = c >> 6; /* get rx level */
+ t1out(tor,i + 1,0x20,0xff);
+ c = t1in(tor,i + 1,0x20); /* get the status */
+ /* detect the code, only if we are not sending one */
+ if ((!tor->spans[i].mainttimer) && (c & 0x80)) /* if loop-up code detected */
+ {
+ /* set into remote loop, if not there already */
+ if ((tor->loopupcnt[i]++ > 80) &&
+ (tor->spans[i].maintstat != ZT_MAINT_REMOTELOOP))
+ {
+ t1out(tor,i + 1,0x1e,(japan ? 0x80 : 0x00)); /* no local loop */
+ t1out(tor,i + 1,0x0a,0x40); /* remote loop */
+ tor->spans[i].maintstat = ZT_MAINT_REMOTELOOP;
+ }
+ } else tor->loopupcnt[i] = 0;
+ /* detect the code, only if we are not sending one */
+ if ((!tor->spans[i].mainttimer) && (c & 0x40)) /* if loop-down code detected */
+ {
+ /* if in remote loop, get out of it */
+ if ((tor->loopdowncnt[i]++ > 80) &&
+ (tor->spans[i].maintstat == ZT_MAINT_REMOTELOOP))
+ {
+ t1out(tor,i + 1,0x1e,(japan ? 0x80 : 0x00)); /* no local loop */
+ t1out(tor,i + 1,0x0a,0); /* no remote loop */
+ tor->spans[i].maintstat = ZT_MAINT_NONE;
+ }
+ } else tor->loopdowncnt[i] = 0;
+ if (c & 3) /* if red alarm */
+ {
+ j |= ZT_ALARM_RED;
+ }
+ if (c & 8) /* if blue alarm */
+ {
+ j |= ZT_ALARM_BLUE;
+ }
+ } else { /* its an E1 card */
+ t1out(tor,i + 1,6,0xff);
+ c = t1in(tor,i + 1,6); /* get the status */
+ if (c & 9) /* if red alarm */
+ {
+ j |= ZT_ALARM_RED;
+ }
+ if (c & 2) /* if blue alarm */
+ {
+ j |= ZT_ALARM_BLUE;
+ }
+ }
+ /* only consider previous carrier alarm state */
+ tor->spans[i].alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN);
+ n = 1; /* set to 1 so will not be in yellow alarm if we dont
+ care about open channels */
+ /* if to have yellow alarm if nothing open */
+ if (tor->spans[i].lineconfig & ZT_CONFIG_NOTOPEN)
+ {
+ /* go thru all chans, and count # open */
+ for (n = 0,k = 0; k < tor->spans[i].channels; k++)
+ {
+ if (((tor->chans[i] + k)->flags & ZT_FLAG_OPEN) ||
+ ((tor->chans[i] + k)->flags & ZT_FLAG_NETDEV)) n++;
+ }
+ /* if none open, set alarm condition */
+ if (!n) j |= ZT_ALARM_NOTOPEN;
+ }
+ /* if no more alarms, and we had some */
+ if ((!j) && tor->spans[i].alarms)
+ {
+ tor->alarmtimer[i] = ZT_ALARMSETTLE_TIME;
+ }
+ if (tor->alarmtimer[i]) j |= ZT_ALARM_RECOVER;
+ /* if going into alarm state, set yellow alarm */
+ if ((j) && (!tor->spans[i].alarms)) {
+ if (tor->cardtype == TYPE_E1)
+ t1out(tor,i + 1,0x21,0x7f);
+ else
+ t1out(tor,i + 1,0x35,0x11);
+ }
+ if (c & 4) /* if yellow alarm */
+ j |= ZT_ALARM_YELLOW;
+ if (tor->spans[i].maintstat || tor->spans[i].mainttimer) j |= ZT_ALARM_LOOPBACK;
+ tor->spans[i].alarms = j;
+ c = (LEDRED | LEDGREEN) << (2 * i);
+ tor->leds &= ~c; /* mask out bits for this span */
+ /* light LED's if span configured and running */
+ if (tor->spans[i].flags & ZT_FLAG_RUNNING) {
+ if (j & ZT_ALARM_RED) tor->leds |= LEDRED << (2 * i);
+ else if (j & ZT_ALARM_YELLOW) tor->leds |= (LEDRED | LEDGREEN) << (2 * i);
+ else tor->leds |= LEDGREEN << (2 * i);
+ }
+ tor->mem8[LEDREG] = tor->leds;
+ zt_alarm_notify(&tor->spans[i]);
+ }
+ if (!(tor->passno % 1000)) /* even second boundary */
+ {
+ /* do all spans */
+ for (i = 1; i <= SPANS_PER_CARD; i++)
+ {
+ if (tor->cardtype == TYPE_E1)
+ {
+ /* add this second's BPV count to total one */
+ tor->spans[i - 1].bpvcount += t1in(tor,i,1) + (t1in(tor,i,0) << 8);
+ if (tor->spans[i - 1].lineconfig & ZT_CONFIG_CRC4)
+ {
+ tor->spans[i - 1].crc4count += t1in(tor,i,3) + ((t1in(tor,i,2) & 3) << 8);
+ tor->spans[i - 1].ebitcount += t1in(tor,i,5) + ((t1in(tor,i,4) & 3) << 8);
+ }
+ tor->spans[i - 1].fascount += (t1in(tor,i,4) >> 2) + ((t1in(tor,i,2) & 0x3F) << 6);
+ }
+ else
+ {
+ /* add this second's BPV count to total one */
+ tor->spans[i - 1].bpvcount += t1in(tor,i,0x24) + (t1in(tor,i,0x23) << 8);
+ }
+ }
+ }
+ if (!timingcable) {
+ /* re-evaluate active sync src (no cable version) */
+ tor->syncsrc = 0;
+ syncsrc = 0;
+ /* if primary sync specified, see if we can use it */
+ if (tor->psyncs[0])
+ {
+ /* if no alarms, use it */
+ if (!(tor->spans[tor->psyncs[0] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE |
+ ZT_ALARM_LOOPBACK))) {
+ tor->syncsrc = tor->psyncs[0];
+ syncsrc = tor->syncs[0];
+ }
+ }
+ /* if any others specified, see if we can use them */
+ for (i = 1; i < SPANS_PER_CARD; i++) {
+ /* if we dont have one yet, and there is one specified at this level, see if we can use it */
+ if ((!tor->syncsrc) && (tor->psyncs[i])) {
+ /* if no alarms, use it */
+ if (!(tor->spans[tor->psyncs[i] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE |
+ ZT_ALARM_LOOPBACK))) {
+ tor->syncsrc = tor->psyncs[i];
+ syncsrc = tor->syncs[i];
+ }
+ }
+ }
+ /* update sync src info */
+ for (i = 0; i < SPANS_PER_CARD; i++) tor->spans[i].syncsrc = syncsrc;
+
+ /* actually set the sync register */
+ tor->mem8[SYNCREG] = tor->syncsrc;
+ } else /* Timing cable version */
+ tor2_findsync(tor);
+
+ tor->passno++;
+
+#ifdef ENABLE_TASKLETS
+ if (!tor->taskletpending) {
+ tor->taskletpending = 1;
+ tor->taskletsched++;
+ tasklet_hi_schedule(&tor->tor2_tlet);
+ } else {
+ tor->txerrors++;
+ }
+#else
+ tor2_run(tor);
+#endif
+ /* We are not the timing bus master */
+ if (tor->cardtype == TYPE_E1)
+ /* clear OUTBIT and enable interrupts */
+ tor->mem8[CTLREG] = INTENA | E1DIV | tor->master;
+ else
+ /* clear OUTBIT and enable interrupts */
+ tor->mem8[CTLREG] = INTENA | tor->master;
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+}
+
+
+static int tor2_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
+{
+ switch(cmd) {
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+MODULE_AUTHOR("Mark Spencer");
+MODULE_DESCRIPTION("Tormenta 2 PCI Quad T1 or E1 Zaptel Driver");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+#ifdef LINUX26
+module_param(debug, int, 0600);
+module_param(loopback, int, 0600);
+module_param(timingcable, int, 0600);
+module_param(japan, int, 0600);
+#else
+MODULE_PARM(debug, "i");
+MODULE_PARM(loopback, "i");
+MODULE_PARM(timingcable, "i");
+MODULE_PARM(japan, "i");
+#endif
+
+MODULE_DEVICE_TABLE(pci, tor2_pci_ids);
+
+module_init(tor2_init);
+module_exit(tor2_cleanup);
diff --git a/drivers/dahdi/torisa.c b/drivers/dahdi/torisa.c
new file mode 100644
index 0000000..9fa24b8
--- /dev/null
+++ b/drivers/dahdi/torisa.c
@@ -0,0 +1,1172 @@
+/*
+ * Zapata Telephony "Tormenta" ISA card LINUX driver, version 2.2 11/29/01
+ *
+ * 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.
+ *
+ * Modified from original tor.c by Mark Spencer <markster@digium.com>
+ * original by Jim Dixon <jim@lambdatel.com>
+ */
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#include <linux/config.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+/* Board address offsets (specified in word (not byte) offsets) */
+#define DDATA 0 /* Data I/O Register */
+#define DADDR 0x100 /* Dallas Card Address Reg., 0x200 in byte offset higher */
+#define CTLREG 0x100 /* Control/Status Reg., 0x200 in byte offset */
+
+/* Control register bits */
+#define OUTBIT 8 /* Status output bit (for external measurements) */
+#define INTENA 4 /* Interrupt enable bit */
+#define MASTERVAL 0x41 /* Enable E1 master clock on Rev. B board */
+#define ENA16 0x80 /* 16 bit bus cycle enable bit */
+
+#define TYPE_T1 1 /* is a T1 card */
+#define TYPE_E1 2 /* is an E1 card */
+
+#define E1SYNCSTABLETHRESH 15000 /* amount of samples needed for E1 Sync stability */
+
+static int syncsrc;
+
+static int syncs[2];
+
+static int debug;
+
+#define MASTERCLOCK (*clockvals) /* value for master clock */
+
+/* clock values */
+static u_char clockvals_t1[] = {MASTERVAL,0x12,0x22,MASTERVAL};
+static u_char clockvals_e1[] = {MASTERVAL,0x13,0x23,MASTERVAL};
+
+static u_char *clockvals;
+
+/* translations of data channels for 24 channels in a 32 bit PCM highway */
+unsigned datxlt_t1[] = { 0,
+ 1 ,2 ,3 ,5 ,6 ,7 ,9 ,10,11,13,14,15,17,18,19,21,22,23,25,26,27,29,30,31 };
+
+/* translations of data channels for 30/31 channels in a 32 bit PCM highway */
+unsigned datxlt_e1[] = { 0,
+ 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
+ 25,26,27,28,29,30,31 };
+
+unsigned int *datxlt;
+
+/* This is the order that the data (audio) channels get
+scanned in. This was done in this rather poopy manner because when outputting
+(and inputting) a sine wave, such as in the case of TDD, any repeated samples
+(because of PCM bus contention) will result in nasty-sounding distortion. The
+Mitel STPA chips (MT8920) have a contention mechanism, which results in a
+situation where, if the processor accesses a timeslot that is currently
+being transmitted or received, it will HOLD the bus until it is done with
+the timeslot. This means that there can be cases where we are trying
+to write to a timeslot, and its already outputting the same value
+as the last one (since we didnt get there in time), and in a sine-wave
+output, distortion will occur. In any other output, it will be utterly
+un-noticeable. So, what we do is use a pattern that gives us the most
+flexibility in how long our interrupt latency is (note: Even with this,
+our interrupt latency must be between 4 and 28 microseconds!!!) Essentially
+we receive the interrupt just after the 24th channel is read. It will
+take us AT LEAST 30 microseconds to read it, but could take as much as
+35 microseconds to read all the channels. In any case it's the very
+first thing we do in the interrupt handler. Worst case (30 microseconds)
+is that the MT8920 has only moved 7 channels. That's where the 6 comes from.
+*/
+
+static int chseq_t1[] =
+ { 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,1,2,3,4,5 } ;
+
+static int chseq_e1[] =
+ { 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,1,2,3,4,5 } ;
+
+static int *chseq;
+
+struct torisa_pvt {
+ int span;
+};
+
+static struct zt_span spans[2];
+static struct zt_chan chans[64];
+static struct torisa_pvt pvts[64];
+static u_char txsigs[2][16];
+static int loopupcnt[2];
+static int loopdowncnt[2];
+static int alarmtimer[2];
+
+static int channels_per_span = 24;
+
+static int card_type = TYPE_T1;
+
+static int prefmaster = 0;
+
+static int spansstarted = 0;
+
+#ifdef DEFINE_RWLOCK
+static DEFINE_RWLOCK(torisa);
+#else
+static rwlock_t torisa = RW_LOCK_UNLOCKED;
+#endif
+
+static u_char readdata[2][64][ZT_MAX_CHUNKSIZE];
+static u_char writedata[2][64][ZT_MAX_CHUNKSIZE];
+static u_char last_ecwrite[2][32];
+static int curread;
+
+static unsigned long base;
+volatile static unsigned short *maddr;
+
+static int irq;
+static unsigned int irqcount = 0;
+static unsigned int taskletsched = 0;
+static unsigned int taskletrun = 0;
+static unsigned int taskletexec = 0;
+
+/* set the control register */
+static void setctlreg(unsigned char val)
+{
+volatile register char *cp;
+
+ cp = (char *) &maddr[CTLREG];
+ *cp = val;
+}
+
+/* output a byte to one of the registers in one of the Dallas T-1 chips */
+static void t1out(int spanno, int loc, unsigned char val)
+{
+register int n;
+volatile register char *cp;
+
+ /* get the memory offset */
+ n = spanno << 9;
+ /* point a char * at the address location */
+ cp = (char *) &maddr[DADDR + n];
+ *cp = loc; /* set address in T1 chip */
+ /* point a char * at the data location */
+ cp = (char *) &maddr[DDATA + n];
+ *cp = val; /* out the value */
+}
+
+/* get a byte from one of the registers in one of the Dallas T-1 chips */
+static unsigned char t1in(int spanno, int loc)
+{
+register int n;
+volatile register char *cp;
+
+ /* get the memory offset */
+ n = spanno << 9;
+ /* point a char * at the address location */
+ cp = (char *) &maddr[DADDR + n];
+ *cp = loc; /* set address in T1 chip */
+ cp = (char *) &maddr[DDATA + n];
+ /* point a char * at the data location */
+ return(*cp);
+}
+
+/* get input from the status register */
+static unsigned char getctlreg(void)
+{
+register char *cp;
+
+ cp = (char *) &maddr[CTLREG];
+ return(*cp);
+}
+
+static void set_clear(void)
+{
+ int i,j,s;
+ unsigned short val=0;
+ for (s=0;s<2;s++) {
+ for (i=0;i<channels_per_span;i++) {
+ j = (i/8);
+ if (spans[s].chans[i].flags & ZT_FLAG_CLEAR)
+ val |= 1 << (i % 8);
+
+ if ((i % 8)==7) {
+#if 0
+ printk("Putting %d in register %02x on span %d\n",
+ val, 0x39 + j, 1 + s);
+#endif
+ t1out(1 + s, 0x39 + j, val);
+ val = 0;
+ }
+ }
+ }
+
+}
+
+/* device probe routine .. determines if the Tormenta device is present in
+ the system */
+static int
+tor_probe(void)
+{
+ int i,status;
+ u_char c1,c2;
+ maddr = phys_to_virt(base);
+
+ status = -1; /* default status return is 'not present' */
+
+ clockvals = clockvals_t1;
+ datxlt = datxlt_t1;
+ chseq = chseq_t1;
+
+ /* initialize control register */
+ setctlreg(MASTERCLOCK);
+
+ /* init all the registers in first T-1 chip to 0 */
+ for(i = 0; i <= 0xff; i++) t1out(1,i,0); /* set register to 0 */
+ /* simple test that will fail if tried in an array of standard memory */
+ /* put an 0x55 here */
+ t1out(1,0x2b,0x55);
+ /* put an 0xaa here */
+ t1out(1,0x2c,0xaa);
+ /* get input from first location */
+ c1 = t1in(1,0x2b);
+ /* get input from second location */
+ c2 = t1in(1,0x2c);
+ /* see if we read back what we put in */
+ if ((c1 == 0x55) && (c2 == 0xaa)) {
+ /* We now need to determine card type */
+ /* This test is documented in Dallas app note 341 */
+ t1out(1, 0x7D, 0);
+ t1out(1, 0x36, 0);
+ t1out(1, 0x15, 0);
+ t1out(1, 0x19, 0);
+ t1out(1, 0x23, 0x55);
+ c1 = t1in(1, 0x23);
+ if (c1 == 0x55) { /* if this is an E-1 card */
+
+ clockvals = clockvals_e1;
+ chseq = chseq_e1;
+ channels_per_span = 31;
+ datxlt = datxlt_e1;
+ card_type = TYPE_E1;
+
+ /* initialize control register */
+ setctlreg(MASTERCLOCK);
+ }
+ /* Try to get the irq if the user didn't specify one */
+ if (irq < 1) {
+#ifdef LINUX26
+ unsigned long irqs;
+ unsigned long delay = jiffies + 5;
+ irqs = probe_irq_on();
+ setctlreg(MASTERCLOCK|INTENA);
+ while((long)(jiffies - delay) < 0);
+ irq = probe_irq_off(irqs);
+#else
+ autoirq_setup(0);
+ setctlreg(MASTERCLOCK|INTENA);
+ /* Wait a jiffie -- that's plenty of time */
+ irq = autoirq_report(5);
+#endif
+ }
+ /* disable interrupts having gotten one */
+ setctlreg(MASTERCLOCK);
+ if (irq == 2)
+ irq = 9;
+ if (irq) {
+ /* init both STPA's to all silence */
+ for(i = 0; i < 32; i++) maddr[i] = 0x7f7f;
+
+ status = 0; /* found */
+ if (debug)
+ printk("ISA Tormenta %s Card found at base addr 0x%lx, irq %d\n",
+ ((card_type == TYPE_E1) ? "E1" : "T1"),
+ base,irq);
+ } else
+ printk("ISA Tormenta %s Card found at base addr 0x%lx, but unable to determine IRQ. Try using irq= option\n",
+ ((card_type == TYPE_E1) ? "E1" : "T1"), base );
+ }
+ return status;
+}
+
+static void make_chans(void)
+{
+ int x,y;
+ int c;
+ for (x=0;x<2;x++)
+ for (y=0;y<channels_per_span;y++) {
+ c = x * channels_per_span + y;
+ sprintf(chans[c].name, "TorISA/%d/%d", x + 1, y + 1);
+ chans[c].sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_FXSLS | ZT_SIG_FXSGS | ZT_SIG_FXSKS |
+ ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_FXOKS | ZT_SIG_CAS | ZT_SIG_SF;
+ chans[c].pvt = &pvts[c];
+ pvts[c].span = x;
+ chans[c].chanpos = y + 1;
+ }
+
+}
+
+static int torisa_rbsbits(struct zt_chan *chan, int bits)
+{
+ u_char m,c;
+ int k,n,b;
+ struct torisa_pvt *p = chan->pvt;
+ unsigned long flags;
+#if 0
+ printk("Setting bits to %x hex on channel %s\n", bits, chan->name);
+#endif
+ if (card_type == TYPE_E1) { /* do it E1 way */
+ if (chan->chanpos > 30) return 0; /* cant do this for chan 31 */
+ n = chan->chanpos - 1;
+ k = p->span;
+ b = (n % 15) + 1;
+ c = txsigs[k][b];
+ m = (n / 15) * 4; /* nibble selector */
+ c &= (15 << m); /* keep the other nibble */
+ c |= (bits & 15) << (4 - m); /* put our new nibble here */
+ txsigs[k][b] = c;
+ /* output them into the chip */
+ t1out(k + 1,0x40 + b,c);
+ return 0;
+ }
+ n = chan->chanpos - 1;
+ k = p->span;
+ b = (n / 8); /* get byte number */
+ m = 1 << (n & 7); /* get mask */
+ c = txsigs[k][b];
+ c &= ~m; /* clear mask bit */
+ /* set mask bit, if bit is to be set */
+ if (bits & ZT_ABIT) c |= m;
+ txsigs[k][b] = c;
+ write_lock_irqsave(&torisa, flags);
+ t1out(k + 1,0x70 + b,c);
+ b += 3; /* now points to b bit stuff */
+ /* get current signalling values */
+ c = txsigs[k][b];
+ c &= ~m; /* clear mask bit */
+ /* set mask bit, if bit is to be set */
+ if (bits & ZT_BBIT) c |= m;
+ /* save new signalling values */
+ txsigs[k][b] = c;
+ /* output them into the chip */
+ t1out(k + 1,0x70 + b,c);
+ b += 3; /* now points to c bit stuff */
+ /* get current signalling values */
+ c = txsigs[k][b];
+ c &= ~m; /* clear mask bit */
+ /* set mask bit, if bit is to be set */
+ if (bits & ZT_CBIT) c |= m;
+ /* save new signalling values */
+ txsigs[k][b] = c;
+ /* output them into the chip */
+ t1out(k + 1,0x70 + b,c);
+ b += 3; /* now points to d bit stuff */
+ /* get current signalling values */
+ c = txsigs[k][b];
+ c &= ~m; /* clear mask bit */
+ /* set mask bit, if bit is to be set */
+ if (bits & ZT_DBIT) c |= m;
+ /* save new signalling values */
+ txsigs[k][b] = c;
+ /* output them into the chip */
+ t1out(k + 1,0x70 + b,c);
+ write_unlock_irqrestore(&torisa, flags);
+ return 0;
+}
+
+static inline int getspan(struct zt_span *span)
+{
+ if (span == spans)
+ return 1;
+ if (span == spans + 1)
+ return 2;
+ return -1;
+}
+
+static int torisa_shutdown(struct zt_span *span)
+{
+ int i;
+ int tspan;
+ int wasrunning;
+ unsigned long flags;
+
+ tspan = getspan(span);
+ if (tspan < 0) {
+ printk("TorISA: Span '%d' isn't us?\n", span->spanno);
+ return -1;
+ }
+
+ write_lock_irqsave(&torisa, flags);
+ wasrunning = span->flags & ZT_FLAG_RUNNING;
+
+ span->flags &= ~ZT_FLAG_RUNNING;
+ /* Zero out all registers */
+ for (i = 0; i< 0xff; i++) t1out(tspan, i, 0);
+ if (wasrunning)
+ spansstarted--;
+ write_unlock_irqrestore(&torisa, flags);
+ if (!spans[0].flags & ZT_FLAG_RUNNING &&
+ !spans[1].flags & ZT_FLAG_RUNNING)
+ /* No longer in use, disable interrupts */
+ setctlreg(clockvals[syncsrc]);
+
+ if (debug)
+ printk("Span %d (%s) shutdown\n", span->spanno, span->name);
+ return 0;
+}
+
+static int torisa_startup(struct zt_span *span)
+{
+ unsigned long endjif;
+ int i;
+ int tspan;
+ unsigned long flags;
+ char *coding;
+ char *framing;
+ char *crcing;
+ int alreadyrunning;
+
+ tspan = getspan(span);
+ if (tspan < 0) {
+ printk("TorISA: Span '%d' isn't us?\n", span->spanno);
+ return -1;
+ }
+
+
+ write_lock_irqsave(&torisa, flags);
+
+ alreadyrunning = span->flags & ZT_FLAG_RUNNING;
+
+ /* initialize the start value for the last ec buffer */
+ for(i = 0; i < span->channels; i++)
+ {
+ last_ecwrite[tspan - 1][i] = ZT_LIN2X(0,&span->chans[i]);
+ }
+ crcing = "";
+ if (card_type == TYPE_T1) { /* if its a T1 card */
+ if (!alreadyrunning) {
+
+ setctlreg(MASTERCLOCK);
+ /* Zero out all registers */
+ for (i = 0x20; i< 0x40; i++)
+ t1out(tspan, i, 0);
+ for (i = 0x60; i< 0x80; i++)
+ t1out(tspan, i, 0);
+
+ /* Full-on Sync required (RCR1) */
+ t1out(tspan, 0x2b, 8);
+ /* RSYNC is an input (RCR2) */
+ t1out(tspan, 0x2c, 8);
+ /* RBS enable (TCR1) */
+ t1out(tspan, 0x35, 0x10);
+ /* TSYNC to be output (TCR2) */
+ t1out(tspan, 0x36, 4);
+ /* Tx & Rx Elastic store, sysclk = 2.048 mhz, loopback controls (CCR1) */
+ t1out(tspan, 0x37, 0x8c);
+ }
+ /* Enable F bits pattern */
+ i = 0x20;
+ if (span->lineconfig & ZT_CONFIG_ESF)
+ i = 0x88;
+ if (span->lineconfig & ZT_CONFIG_B8ZS)
+ i |= 0x44;
+ t1out(tspan, 0x38, i);
+ if (i & 0x80)
+ coding = "ESF";
+ else
+ coding = "SF";
+ if (i & 0x40)
+ framing = "B8ZS";
+ else {
+ framing = "AMI";
+ t1out(tspan,0x7e,0x1c); /* F bits pattern (0x1c) into FDL register */
+ }
+ t1out(tspan, 0x7c, span->txlevel << 5);
+
+ if (!alreadyrunning) {
+ /* LIRST to 1 in CCR3 */
+ t1out(tspan, 0x30, 1);
+
+ /* Wait 100 ms */
+ endjif = jiffies + 10;
+ write_unlock_irqrestore(&torisa, flags);
+
+ while(jiffies < endjif); /* wait 100 ms */
+
+ write_lock_irqsave(&torisa, flags);
+ t1out(tspan,0x30,0x40); /* set CCR3 to 0x40, resetting Elastic Store */
+
+ span->flags |= ZT_FLAG_RUNNING;
+ spansstarted++;
+
+#if 0
+ printk("Enabling interrupts: %d\n", clockvals[syncsrc] | INTENA);
+#endif
+
+ /* output the clock info and enable interrupts */
+ setctlreg(clockvals[syncsrc] | INTENA);
+ }
+ set_clear(); /* this only applies to a T1 */
+ } else { /* if its an E1 card */
+ u_char ccr1 = 0, tcr1 = 0;
+
+ if (!alreadyrunning) {
+ t1out(tspan,0x1a,4); /* CCR2: set LOTCMC */
+ for(i = 0; i <= 8; i++) t1out(tspan,i,0);
+ for(i = 0x10; i <= 0x4f; i++) if (i != 0x1a) t1out(tspan,i,0);
+ t1out(tspan,0x10,0x20); /* RCR1: Rsync as input */
+ t1out(tspan,0x11,6); /* RCR2: Sysclk=2.048 Mhz */
+ t1out(tspan,0x12,8); /* TCR1: TSiS mode */
+ }
+ tcr1 = 8; /* base TCR1 value: TSis mode */
+ if (span->lineconfig & ZT_CONFIG_CCS) {
+ ccr1 |= 8; /* CCR1: Rx Sig mode: CCS */
+ coding = "CCS";
+ } else {
+ tcr1 |= 0x20;
+ coding = "CAS";
+ }
+ if (span->lineconfig & ZT_CONFIG_HDB3) {
+ ccr1 |= 0x44; /* CCR1: TX and RX HDB3 */
+ framing = "HDB3";
+ } else framing = "AMI";
+ if (span->lineconfig & ZT_CONFIG_CRC4) {
+ ccr1 |= 0x11; /* CCR1: TX and TX CRC4 */
+ crcing = "/CRC4";
+ }
+ t1out(tspan,0x12,tcr1);
+ t1out(tspan,0x14,ccr1);
+ t1out(tspan, 0x18, 0x80);
+
+ if (!alreadyrunning) {
+ t1out(tspan,0x1b,0x8a); /* CCR3: LIRST & TSCLKM */
+ t1out(tspan,0x20,0x1b); /* TAFR */
+ t1out(tspan,0x21,0x5f); /* TNAFR */
+ t1out(tspan,0x40,0xb); /* TSR1 */
+ for(i = 0x41; i <= 0x4f; i++) t1out(tspan,i,0x55);
+ for(i = 0x22; i <= 0x25; i++) t1out(tspan,i,0xff);
+ /* Wait 100 ms */
+ endjif = jiffies + 10;
+ write_unlock_irqrestore(&torisa, flags);
+ while(jiffies < endjif); /* wait 100 ms */
+ write_lock_irqsave(&torisa, flags);
+ t1out(tspan,0x1b,0x9a); /* CCR3: set also ESR */
+ t1out(tspan,0x1b,0x82); /* CCR3: TSCLKM only now */
+
+ /* output the clock info and enable interrupts */
+ setctlreg(clockvals[syncsrc] | INTENA);
+ }
+
+ }
+
+ write_unlock_irqrestore(&torisa, flags);
+
+ if (debug) {
+ if (card_type == TYPE_T1) {
+ if (alreadyrunning)
+ printk("TorISA: Reconfigured span %d (%s/%s) LBO: %s\n", span->spanno, coding, framing, zt_lboname(span->txlevel));
+ else
+ printk("TorISA: Startup span %d (%s/%s) LBO: %s\n", span->spanno, coding, framing, zt_lboname(span->txlevel));
+ } else {
+ if (alreadyrunning)
+ printk("TorISA: Reconfigured span %d (%s/%s%s) 120 ohms\n", span->spanno, coding, framing, crcing);
+ else
+ printk("TorISA: Startup span %d (%s/%s%s) 120 ohms\n", span->spanno, coding, framing, crcing);
+ }
+ }
+ if (syncs[0] == span->spanno) printk("SPAN %d: Primary Sync Source\n",span->spanno);
+ if (syncs[1] == span->spanno) printk("SPAN %d: Secondary Sync Source\n",span->spanno);
+ return 0;
+}
+
+static int torisa_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+ if (debug)
+ printk("TorISA: Configuring span %d\n", span->spanno);
+
+ span->syncsrc = syncsrc;
+
+ /* remove this span number from the current sync sources, if there */
+ if (syncs[0] == span->spanno) syncs[0] = 0;
+ if (syncs[1] == span->spanno) syncs[1] = 0;
+ /* if a sync src, put it in proper place */
+ if (lc->sync) syncs[lc->sync - 1] = span->spanno;
+
+ /* If we're already running, then go ahead and apply the changes */
+ if (span->flags & ZT_FLAG_RUNNING)
+ return torisa_startup(span);
+
+ return 0;
+}
+
+static int torisa_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ int alreadyrunning;
+ unsigned long flags;
+ alreadyrunning = chan->span->flags & ZT_FLAG_RUNNING;
+ if (debug) {
+ if (alreadyrunning)
+ printk("TorISA: Reconfigured channel %d (%s) sigtype %d\n", chan->channo, chan->name, sigtype);
+ else
+ printk("TorISA: Configured channel %d (%s) sigtype %d\n", chan->channo, chan->name, sigtype);
+ }
+ write_lock_irqsave(&torisa, flags);
+ if (alreadyrunning && (card_type == TYPE_T1))
+ set_clear();
+ write_unlock_irqrestore(&torisa, flags);
+ return 0;
+}
+
+static int torisa_open(struct zt_chan *chan)
+{
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static int torisa_close(struct zt_chan *chan)
+{
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static int torisa_maint(struct zt_span *span, int cmd)
+{
+ int tspan = getspan(span);
+
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ t1out(tspan,0x1a,4); /* clear system */
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ t1out(tspan,0x1a,5); /* local loopback */
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ t1out(tspan,0x37,6); /* remote loopback */
+ break;
+ case ZT_MAINT_LOOPUP:
+ if (card_type == TYPE_E1) return -ENOSYS;
+ t1out(tspan,0x30,2); /* send loopup code */
+ break;
+ case ZT_MAINT_LOOPDOWN:
+ if (card_type == TYPE_E1) return -ENOSYS;
+ t1out(tspan,0x30,4); /* send loopdown code */
+ break;
+ case ZT_MAINT_LOOPSTOP:
+ if (card_type == TYPE_T1)
+ t1out(tspan,0x30,0); /* stop sending loopup code */
+ break;
+ default:
+ printk("torisa: Unknown maint command: %d\n", cmd);
+ break;
+ }
+ return 0;
+}
+
+static int taskletpending;
+
+static struct tasklet_struct torisa_tlet;
+
+static void torisa_tasklet(unsigned long data)
+{
+ int x,y;
+ u_char mychunk[2][ZT_CHUNKSIZE];
+ taskletrun++;
+ if (taskletpending) {
+ taskletexec++;
+ /* Perform receive data calculations. Reverse to run most
+ likely master last */
+ if (spans[1].flags & ZT_FLAG_RUNNING) {
+ /* Perform echo cancellation */
+ for (x=0;x<channels_per_span;x++)
+ {
+ for(y = 0; y < ZT_CHUNKSIZE; y++)
+ {
+ mychunk[1][y] = last_ecwrite[1][x];
+ last_ecwrite[1][x] =
+ writedata[1-curread][x + channels_per_span][y];
+ }
+ zt_ec_chunk(&spans[1].chans[x],
+ spans[1].chans[x].readchunk,mychunk[1]);
+ }
+ zt_receive(&spans[1]);
+ }
+ if (spans[0].flags & ZT_FLAG_RUNNING) {
+ /* Perform echo cancellation */
+ for (x=0;x<channels_per_span;x++)
+ {
+ for(y = 0; y < ZT_CHUNKSIZE; y++)
+ {
+ mychunk[0][y] = last_ecwrite[0][x];
+ last_ecwrite[0][x] = writedata[1-curread][x][y];
+ }
+ zt_ec_chunk(&spans[0].chans[x],
+ spans[0].chans[x].readchunk,mychunk[0]);
+ }
+ zt_receive(&spans[0]);
+ }
+
+ /* Prepare next set for transmission */
+ if (spans[1].flags & ZT_FLAG_RUNNING)
+ zt_transmit(&spans[1]);
+ if (spans[0].flags & ZT_FLAG_RUNNING)
+ zt_transmit(&spans[0]);
+ }
+ taskletpending = 0;
+}
+
+static int txerrors;
+
+ZAP_IRQ_HANDLER(torisa_intr)
+{
+ static unsigned int passno = 0, mysynccnt = 0, lastsyncsrc = -1;
+ int n, n1, i, j, k, x, mysyncsrc, oldn;
+ static unsigned short rxword[33],txword[33];
+ unsigned char txc, rxc, c;
+ unsigned char abits, bbits, cbits, dbits;
+
+
+ irqcount++;
+
+ /* 1. Do all I/O Immediately -- Normally we would ask for
+ the transmission first, but because of the incredibly
+ tight timing we're lucky to be able to do the I/O
+ at this point */
+
+ /* make sure its a real interrupt for us */
+ if (!(getctlreg() & 1)) /* if not, just return */
+ {
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+ }
+
+ /* set outbit and put int 16 bit bus mode, reset interrupt enable */
+ setctlreg(clockvals[syncsrc] | OUTBIT | ENA16);
+
+#if 0
+ if (!passno)
+ printk("Interrupt handler\n");
+#endif
+
+ /* Do the actual transmit and receive in poopy order */
+ for(n1 = 0; n1 < channels_per_span; n1++)
+ {
+ n = chseq[n1];
+ maddr[DDATA + datxlt[n]] = txword[n];
+ rxword[n] = maddr[DDATA + datxlt[n]]; /* get rx word */
+ }
+
+
+ setctlreg(clockvals[syncsrc] | OUTBIT); /* clear 16 bit mode */
+
+ /* Calculate the transmit, and receive go thru all the chans */
+ oldn = -1;
+ for(n1 = 0; n1 < channels_per_span; n1++) {
+ n = chseq[n1];
+ txword[n] = 0;
+ if (n < oldn) {
+ /* We've circled around.
+ Now we increment the passno and stuff */
+ if ((passno % ZT_CHUNKSIZE) == (ZT_CHUNKSIZE - 1)) {
+ /* Swap buffers */
+ for (x = 0;x < (channels_per_span * 2);x++) {
+ chans[x].readchunk = readdata[curread][x];
+ chans[x].writechunk = writedata[curread][x];
+ }
+ /* Lets work with the others now which presumably have been filled */
+ curread = 1 - curread;
+ if (!taskletpending) {
+ taskletpending = 1;
+ taskletsched++;
+ tasklet_hi_schedule(&torisa_tlet);
+ } else {
+ txerrors++;
+ }
+ }
+ passno++;
+ }
+ oldn = n;
+ /* go thru both spans */
+ for(j = 0; j < 2; j++)
+ {
+ /* enter the transmit stuff with i being channel number,
+ leaving with txc being character to transmit */
+ txc = writedata[curread][j * channels_per_span + n-1][passno % ZT_CHUNKSIZE];
+ txword[n] |= txc << (j * 8);
+
+ /* receive side */
+ i = n + (j * channels_per_span); /* calc chan number */
+ rxc = (rxword[n] >> (j * 8)) & 0xff;
+ readdata[curread][j * channels_per_span + n - 1][passno % ZT_CHUNKSIZE] = rxc;
+ }
+ }
+
+ i = passno & 127;
+ /* if an E1 card, do rx signalling for it */
+ if (i < 3 && (card_type == TYPE_E1)) { /* if an E1 card */
+ for(j = (i * 3); j < (i * 3) + 5; j++)
+ {
+ for(k = 1,x = j; k <= 2; k++,x += channels_per_span) {
+ c = t1in(k,0x31 + j);
+ rxc = c & 15;
+ if (rxc != chans[x + 15].rxsig) {
+ /* Check for changes in received bits */
+ if (!(chans[x + 15].sig & ZT_SIG_CLEAR))
+ zt_rbsbits(&chans[x + 15], rxc);
+ }
+ rxc = c >> 4;
+ if (rxc != chans[x].rxsig) {
+ /* Check for changes in received bits */
+ if (!(chans[x].sig & ZT_SIG_CLEAR))
+ zt_rbsbits(&chans[x], rxc);
+ }
+ }
+ }
+ }
+ /* if a t1 card, do rx signalling for it */
+ if ((i < 6) && (card_type == TYPE_T1)) {
+ k = (i / 3); /* get span */
+ n = (i % 3); /* get base */
+ abits = t1in(k + 1, 0x60 + n);
+ bbits = t1in(k + 1, 0x63 + n);
+ cbits = t1in(k + 1, 0x66 + n);
+ dbits = t1in(k + 1, 0x69 + n);
+ for (j=0; j< 8; j++) {
+ /* Get channel number */
+ i = (k * 24) + (n * 8) + j;
+ rxc = 0;
+ if (abits & (1 << j)) rxc |= ZT_ABIT;
+ if (bbits & (1 << j)) rxc |= ZT_BBIT;
+ if (cbits & (1 << j)) rxc |= ZT_CBIT;
+ if (dbits & (1 << j)) rxc |= ZT_DBIT;
+ if (chans[i].rxsig != rxc) {
+ /* Check for changes in received bits */
+ if (!(chans[i].sig & ZT_SIG_CLEAR))
+ zt_rbsbits(&chans[i], rxc);
+ }
+ }
+ }
+
+ if (!(passno & 0x7)) {
+ for(i = 0; i < 2; i++)
+ {
+ /* if alarm timer, and it's timed out */
+ if (alarmtimer[i]) {
+ if (!--alarmtimer[i])
+ {
+ /* clear recover status */
+ spans[i].alarms &= ~ZT_ALARM_RECOVER;
+ if (card_type == TYPE_T1)
+ t1out(i + 1,0x35,0x10); /* turn off yel */
+ else
+ t1out(i + 1,0x21,0x5f); /* turn off remote alarm */
+ zt_alarm_notify(&spans[i]); /* let them know */
+ }
+ }
+ }
+ }
+
+ i = passno & 511;
+ if ((i == 100) || (i == 101))
+ {
+ j = 0; /* clear this alarm status */
+ i -= 100;
+ if (card_type == TYPE_T1) {
+ c = t1in(i + 1,0x31); /* get RIR2 */
+ spans[i].rxlevel = c >> 6; /* get rx level */
+ t1out(i + 1,0x20,0xff);
+ c = t1in(i + 1,0x20); /* get the status */
+ /* detect the code, only if we are not sending one */
+ if ((!spans[i].mainttimer) && (c & 0x80)) /* if loop-up code detected */
+ {
+ /* set into remote loop, if not there already */
+ if ((loopupcnt[i]++ > 80) &&
+ (spans[i].maintstat != ZT_MAINT_REMOTELOOP))
+ {
+ t1out(i + 1,0x37,0x9c); /* remote loopback */
+ spans[i].maintstat = ZT_MAINT_REMOTELOOP;
+ }
+ } else loopupcnt[i] = 0;
+ /* detect the code, only if we are not sending one */
+ if ((!spans[i].mainttimer) && (c & 0x40)) /* if loop-down code detected */
+ {
+ /* if in remote loop, get out of it */
+ if ((loopdowncnt[i]++ > 80) &&
+ (spans[i].maintstat == ZT_MAINT_REMOTELOOP))
+ {
+ t1out(i + 1,0x37,0x8c); /* normal */
+ spans[i].maintstat = ZT_MAINT_NONE;
+ }
+ } else loopdowncnt[i] = 0;
+ if (c & 3) /* if red alarm */
+ {
+ j |= ZT_ALARM_RED;
+ }
+ if (c & 8) /* if blue alarm */
+ {
+ j |= ZT_ALARM_BLUE;
+ }
+ } else { /* its an E1 card */
+ t1out(i + 1,6,0xff);
+ c = t1in(i + 1,6); /* get the status */
+ if (c & 9) /* if red alarm */
+ {
+ j |= ZT_ALARM_RED;
+ }
+ if (c & 2) /* if blue alarm */
+ {
+ j |= ZT_ALARM_BLUE;
+ }
+ }
+ /* only consider previous carrier alarm state */
+ spans[i].alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN);
+ n = 1; /* set to 1 so will not be in yellow alarm if we dont
+ care about open channels */
+ /* if to have yellow alarm if nothing open */
+ if (spans[i].lineconfig & ZT_CONFIG_NOTOPEN)
+ {
+ /* go thru all chans, and count # open */
+ for(n = 0,k = (i * channels_per_span); k < (i * channels_per_span) + channels_per_span; k++)
+ {
+ if ((chans[k].flags & ZT_FLAG_OPEN) ||
+ (chans[k].flags & ZT_FLAG_NETDEV)) n++;
+ }
+ /* if none open, set alarm condition */
+ if (!n) j |= ZT_ALARM_NOTOPEN;
+ }
+ /* if no more alarms, and we had some */
+ if ((!j) && spans[i].alarms)
+ {
+ alarmtimer[i] = ZT_ALARMSETTLE_TIME;
+ }
+ if (alarmtimer[i]) j |= ZT_ALARM_RECOVER;
+ /* if going into alarm state, set yellow (remote) alarm */
+ if ((j) && (!spans[i].alarms)) {
+ if (card_type == TYPE_T1) t1out(i + 1,0x35,0x11);
+ else t1out(i + 1,0x21,0x7f);
+ }
+ if (c & 4) /* if yellow alarm */
+ j |= ZT_ALARM_YELLOW;
+ if (spans[i].maintstat || spans[i].mainttimer) j |= ZT_ALARM_LOOPBACK;
+ spans[i].alarms = j;
+ zt_alarm_notify(&spans[i]);
+ }
+ if (!(passno % 8000)) /* even second boundary */
+ {
+ /* do both spans */
+ for(i = 1; i <= 2; i++)
+ {
+ if (card_type == TYPE_T1) {
+ /* add this second's BPV count to total one */
+ spans[i - 1].bpvcount += t1in(i,0x24) + (t1in(i,0x23) << 8);
+ } else {
+ /* add this second's BPV count to total one */
+ spans[i - 1].bpvcount += t1in(i,1) + (t1in(i,0) << 8);
+ }
+ }
+ }
+ /* re-evaluate active sync src */
+ mysyncsrc = 0;
+ /* if primary sync specified, see if we can use it */
+ if (syncs[0])
+ {
+ /* if no alarms, use it */
+ if (!(spans[syncs[0] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE |
+ ZT_ALARM_LOOPBACK))) mysyncsrc = syncs[0];
+ }
+ /* if we dont have one yet, and there is a secondary, see if we can use it */
+ if ((!mysyncsrc) && (syncs[1]))
+ {
+ /* if no alarms, use it */
+ if (!(spans[syncs[1] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE |
+ ZT_ALARM_LOOPBACK))) mysyncsrc = syncs[1];
+ }
+ /* on the E1 card, the PLL takes a bit of time to lock going
+ between internal and external clocking. There needs to be some
+ settle time before actually changing the source, otherwise it will
+ oscillate between in and out of sync */
+ if (card_type == TYPE_E1)
+ {
+ /* if stable, add to count */
+ if (lastsyncsrc == mysyncsrc) mysynccnt++; else mysynccnt = 0;
+ lastsyncsrc = mysyncsrc;
+ /* if stable sufficiently long, change it */
+ if (mysynccnt >= E1SYNCSTABLETHRESH)
+ {
+ mysynccnt = 0;
+ syncsrc = mysyncsrc;
+ }
+ }
+ else syncsrc = mysyncsrc; /* otherwise on a T1 card, just use current value */
+ /* update sync src info */
+ spans[0].syncsrc = spans[1].syncsrc = syncsrc;
+ /* If this is the last pass, then prepare the next set */
+ /* clear outbit, restore interrupt enable */
+ setctlreg(clockvals[syncsrc] | INTENA);
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+}
+
+
+static int torisa_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
+{
+ struct torisa_debug td;
+ switch(cmd) {
+ case TORISA_GETDEBUG:
+ td.txerrors = txerrors;
+ td.irqcount = irqcount;
+ td.taskletsched = taskletsched;
+ td.taskletrun = taskletrun;
+ td.taskletexec = taskletexec;
+ td.span1flags = spans[0].flags;
+ td.span2flags = spans[1].flags;
+ if (copy_to_user((struct torisa_debug *)data, &td, sizeof(td)))
+ return -EFAULT;
+ return 0;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int __init tor_init(void)
+{
+ if (!base) {
+ printk("Specify address with base=0xNNNNN\n");
+ return -EIO;
+ }
+ if (tor_probe()) {
+ printk(KERN_ERR "No ISA tormenta card found at %05lx\n", base);
+ return -EIO;
+ }
+ if (request_irq(irq, torisa_intr, ZAP_IRQ_DISABLED, "torisa", NULL)) {
+ printk(KERN_ERR "Unable to request tormenta IRQ %d\n", irq);
+ return -EIO;
+ }
+ if (!request_mem_region(base, 4096, "Tormenta ISA")) {
+ printk(KERN_ERR "Unable to request 4k memory window at %lx\n", base);
+ free_irq(irq, NULL);
+ return -EIO;
+ }
+
+ strcpy(spans[0].name, "TorISA/1");
+ zap_copy_string(spans[0].desc, "ISA Tormenta Span 1", sizeof(spans[0].desc));
+ spans[0].manufacturer = "Digium";
+ zap_copy_string(spans[0].devicetype, "Tormenta ISA", sizeof(spans[0].devicetype));
+ spans[0].spanconfig = torisa_spanconfig;
+ spans[0].chanconfig = torisa_chanconfig;
+ spans[0].startup = torisa_startup;
+ spans[0].shutdown = torisa_shutdown;
+ spans[0].rbsbits = torisa_rbsbits;
+ spans[0].maint = torisa_maint;
+ spans[0].open = torisa_open;
+ spans[0].close = torisa_close;
+ spans[0].channels = channels_per_span;
+ spans[0].chans = &chans[0];
+ spans[0].flags = ZT_FLAG_RBS;
+ spans[0].ioctl = torisa_ioctl;
+ spans[0].irq = irq;
+
+ if (card_type == TYPE_E1) {
+ spans[0].spantype = "E1";
+ spans[0].linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
+ spans[0].deflaw = ZT_LAW_ALAW;
+ } else {
+ spans[0].spantype = "T1";
+ spans[0].linecompat = ZT_CONFIG_HDB3 | ZT_CONFIG_CCS | ZT_CONFIG_CRC4;
+ spans[0].deflaw = ZT_LAW_MULAW;
+ }
+
+ spans[1] = spans[0];
+ strcpy(spans[1].name, "TorISA/2");
+ strcpy(spans[1].desc, "ISA Tormenta Span 2");
+ spans[1].chans = &chans[channels_per_span];
+
+ init_waitqueue_head(&spans[0].maintq);
+ init_waitqueue_head(&spans[1].maintq);
+
+ make_chans();
+ if (zt_register(&spans[0], prefmaster)) {
+ printk(KERN_ERR "Unable to register span %s\n", spans[0].name);
+ return -EIO;
+ }
+ if (zt_register(&spans[1], 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", spans[1].name);
+ zt_unregister(&spans[0]);
+ return -EIO;
+ }
+ tasklet_init(&torisa_tlet, torisa_tasklet, (long)0);
+ printk("TORISA Loaded\n");
+ return 0;
+}
+
+
+#if !defined(LINUX26)
+static int __init set_tor_base(char *str)
+{
+ base = simple_strtol(str, NULL, 0);
+ return 1;
+}
+
+__setup("tor=", set_tor_base);
+#endif
+
+static void __exit tor_exit(void)
+{
+ free_irq(irq, NULL);
+ release_mem_region(base, 4096);
+ if (spans[0].flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&spans[0]);
+ if (spans[1].flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&spans[1]);
+}
+
+MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
+MODULE_DESCRIPTION("Tormenta ISA Zapata Telephony Driver");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+#ifdef LINUX26
+module_param(prefmaster, int, 0600);
+module_param(base, long, 0600);
+module_param(irq, int, 0600);
+module_param(syncsrc, int, 0600);
+module_param(debug, int, 0600);
+#else
+MODULE_PARM(prefmaster, "i");
+MODULE_PARM(base, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(syncsrc, "i");
+MODULE_PARM(debug, "i");
+#endif
+
+module_init(tor_init);
+module_exit(tor_exit);
diff --git a/drivers/dahdi/tormenta2.rbt b/drivers/dahdi/tormenta2.rbt
new file mode 100644
index 0000000..9238b8a
--- /dev/null
+++ b/drivers/dahdi/tormenta2.rbt
@@ -0,0 +1,17482 @@
+Xilinx ASCII Bitstream
+Created by Bitstream F.23
+Design name: tormenta2.ncd
+Architecture: spartan2
+Part: 2s50pq208
+Date: Thu Oct 10 09:00:52 2002
+Bits: 559200
+11111111111111111111111111111111
+10101010100110010101010101100110
+00110000000000001000000000000001
+00000000000000000000000000000111
+00110000000000010110000000000001
+00000000000000000000000000001011
+00110000000000010010000000000001
+00000000100000000011111100101101
+00110000000000001100000000000001
+00000000000000000000000000000000
+00110000000000001000000000000001
+00000000000000000000000000001001
+00110000000000000010000000000001
+00000000000000000000000000000000
+00110000000000001000000000000001
+00000000000000000000000000000001
+00110000000000000100000000000000
+01010000000000000011111000000100
+00000000000100100011000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000100
+10000000000000000000000000000000
+00000000000000000000000000000000
+00000000000100100011000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000010000000000100
+10000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000100000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+10000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000100000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+10000000000000000000000000000000
+00000000000000000000000000000000
+00000000000100100000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000100
+10000000000000000000000000000000
+00000000000000000000000000000000
+00000000000100100000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000100
+10000000000000000000000000000000
+00000000000000000000000000000000
+00000000000100100000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000010000000000100
+00000000000000000000000000000000
+00000000000000000000000000000000
+11111111000100100000000000000000
+00000000000000011000000000000000
+01000000000000000001100000000000
+00000100000000000000000010000000
+00000000011000000000000000011000
+00000000000010100000000000000010
+10000000000000000010000000000000
+00101000000000000000001000000000
+00000000000000000000000000100000
+00000000000010000001111111000100
+00000000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111101000000000
+11111111100000000011111100000000
+10001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111110000
+00000011011111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110001000000000
+10111011100000000010111000110100
+00001011101110000000001011101110
+00000000101110111000000000101110
+11100000000010111011100000000010
+11101110000000001011101110000000
+00101110111000000000101110111000
+00000010101011100000000010111011
+10000000001011101110000000001011
+10111000000000101110000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100100000000000
+10100011000000000010110010000000
+00001011001100000010011010001100
+00000000101100110000000000101000
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010010011000000000010110011
+00000000001011001100000000001011
+00110000000001101110001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010000000000000
+10111011000000000010111011000010
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110010
+10000010111011000000000010111011
+00000000001011101100000000011011
+10110000000000101111000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000101011110110100000000
+11111011000000000011111000010000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110111100
+00000011011011000000000011111011
+00000000001111101100000000001111
+10110000010000111100100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011000001000000
+11111111000000000011111010100100
+00001111111100000000000111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111110111000
+00000011101111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000010011111000010000
+00101100101100000000001111101100
+00000000111110110000000000110110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111100110000
+00000011101011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010000000000000
+10111011000101100010111010000000
+00001000101100000000001011101100
+00000000101110110000000000100110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010001011000000000010111011
+00000000001011101100000000001011
+10111000100000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100010000000000
+10110011000000000010110001000000
+00001000001100000000001001001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100000000
+00000010100011000000000010110011
+00000000001011001100000000001011
+00111110000000101111000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+01100000000000010001001000000000
+10110111100000000010110100100000
+00001000011110000100001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101001000
+00000010000111100000000010110111
+10000000001011011110000000001011
+01111000000000101101100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110001000000
+11110011000000000011110011000000
+00001100001100010010001111001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110000000000111100000000
+00000011100011000000000011110011
+00000000001111001100000000001111
+00110000000000111101101000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011000000010000
+11111111000000000011111111000100
+00001111111100000000001111111100
+00001000111111110000000000110111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111000000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000011011110010000010000
+11111011000000000011111001000000
+00001100101100000000001111101100
+00001000111110110000000001111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111100000000
+00000011001011000000000011111011
+00000000001111101100000000001111
+10110000000000111110101000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000000011001000000000000
+10110111000000000010110001000000
+00001000011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101000000
+00000010000111000000000010110111
+00000000001011011100000000001011
+01110000000000101101001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000001000000001001111000000000
+10110111100000000010110111100000
+00011000011110000001001011011110
+00000001101101111000000100101001
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101111000000
+00000010000111100000000010110111
+10000000001011011110000000001011
+01111000000000101111000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000100101001100000000000000
+10110011000000000010110011000000
+00011000001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100000000
+00000010000011000000000010110011
+00000000001011001100000000001011
+00110000000000101101001100000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011011100000000000
+11111010000000000011111110011100
+00101100101000000000001111101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00111110100000000000111111100000
+00000011001010000000000011111010
+00000000001111101000000000001111
+00100000000000111111101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000010000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000100000000111101001000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001100000000011110001000000
+00001101100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000110000001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000100000010111001000000
+00001000100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10011000000010100010000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010110000000000
+10111001000000000010111001000000
+00001000100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010010100000100000011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001100000000010110001001000
+00101000000100000000001011000100
+00000000100100010000000001101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000100100010010
+10000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000100000001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000001010110000000000000
+11111000000000000011111000000000
+00001100100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000010
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000110010111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000101011111010000000000
+11111001000001000011111101000100
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111111010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+10011000000001011110010000000000
+11001001000000000011111001000000
+00001100100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011001001000000000011111001
+00000000001111100100000000001111
+01010000000000111110011000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10001000000000000010111000000000
+00001000100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010101000000000000010111000
+00000000001011100000000000001011
+10000000000000101100111000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011110010000000000
+10000001000000000010100001000000
+00001000000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+10000100000000001011000100000000
+00101100010000000000101110010000
+00000010000001000000000010110001
+00000000001011000100000000001011
+00010000000001101100001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10001001000000000010111001001010
+00001000100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010101001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011100010001000010
+11001001000000010011111001000000
+00101100100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111100010000
+00000011001001000000000011111001
+00000000001111100100000000001111
+10010000000000111110100000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010011000000000
+11111011000000010011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11001000000000000011110000000000
+00001100100000000000001111100000
+00000000111110000000000000110110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000100000110000101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000001010010100000000000
+10001010000000000010111010000000
+00001000101000000000001011101000
+00000000101110100000000000100110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+11100000000000100000101000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000010
+10000010000001000010110011000000
+00001000001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000100100101000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010011110000000000
+10000111010000000010110111000000
+00001000011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01111000000000100100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11000100100000010011110011100000
+00101100011110000000001111011110
+00000000111101111000000000111101
+11100000000011110111100000000011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01101000000000110100101000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011000110000000000
+11111000011000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000110110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000010001111
+10000000000010111000001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111110110000100011001111100000
+00001100111110000000001101111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011001111100000000011111111
+10000000001111111110000000001111
+11111000000000111101000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000100000
+10110111000000000011010111000000
+00001000011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000011110111000000000010110111
+00000000001011011100000000001011
+01100010000000101110101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00010000000000001001110000000000
+10110110000000000010000111000000
+00001000011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010000111000000000010110111
+00000000001011011100000000001011
+01110000000000101100010000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01100000000101001100110000000000
+10110010000000000010010011000000
+00001000001100000000001011001100
+00000000101100110000000000100100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00000000000001101101100100000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11111000000101011010110100000000
+11111011000000000011001011000010
+00101100101100000000001101101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011001011000000000011111011
+00000000001111101100000000001111
+10010000000000111110101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000100000000001110110000000000
+11111011000000010011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111100110000
+00000011111011000000000011111011
+00000010001111101100000000001111
+10010000000000111110010000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001111110000100000
+11111101100000010011111011000010
+00001111111100000000001110111100
+00000000111111110000000000111111
+11000000000010111111000000000011
+11111100000000001111111100000000
+00111111110000000000111110110000
+00000011001111000000000011111111
+00000000001111111100000000001111
+11101000000000111110000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000100
+10111000110110000010111011000000
+00001001101100000000001011101100
+00000000101110110000000000101110
+11000000000010011011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010101011000000000010111011
+00000000001011101100000000001011
+10000000000000101110000101100000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111001000000000010111011000000
+00001011101100000000001001101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010001011000000000010111011
+00000000001011101100000001001011
+10010010000100101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110001000000000010110011000000
+00001001001100000000001011001100
+00000000101100110000000000101100
+11000000000110010011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010100011000000000010110011
+00000000001011001100000000001011
+00000000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+10000000000011010110110000000000
+11111001000000000011111011000000
+00001111101100000000001110101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011001011000000000011111011
+00000000001111101100000000001111
+10110000000000111110000000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11110100000001000011111111000000
+00001101111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11000000000000111110100000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111111000000000011111111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111110010000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11001000000000110111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110111000000000
+10111011110100010010111011100000
+00001011101110000000001110101110
+00000000101110111000000000101110
+11100000000010111011100000000010
+11101110000000001011100010000000
+00101110111000000000101110111000
+00000010111011100000000010111011
+10000000001011101110000000001011
+10001000000000100010000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10100011000001000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011000000000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00000000000001100110001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000010000
+10111011000000000010111011000000
+00001011101100000000001010101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000011011100000001000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000011011
+10110000000000100111000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011110110000000000
+11111111000000100011111011000000
+00001111101100000000001011101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000010111011
+00000000001111101100000000001011
+10011001000000110101000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000000111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000100001111111100100000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11000000000000111011100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011001000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111100101000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10010000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111111100000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011100100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+00110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011010000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011000000000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00100010000000101111100100000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011010010000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01001000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110001000000
+11110011000010000011110011000000
+00001111001100000000001111001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110000000000111100110001
+00000011110011000000000011110011
+00000000001111001100000000001111
+00100000000000111101001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000010000
+11111111000000100011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111101000000
+00111111110000000000111111110000
+01000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111111100000000011001011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101000000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10111000000000110010101000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110111100000000011010111000000
+00001110011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011000000000
+00101101110000000000101101110000
+00010010110111000000000010110111
+00000000001011011100000000001011
+01000000000000110101001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110011100000000010100111100000
+00011011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+01101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000001100011000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001010001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100110000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110010000000100101001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011101010000000
+00001111101000000000001111101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001111101010000000
+00111110100000010001111110100000
+00000011111010000000000011111010
+00000000001111101000000000001111
+11100000000000110011101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011011000000000
+00001110100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000100000000111101001000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111101100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10011100000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001100000000010111001000000
+00001011100100000000001011100100
+00000000101010010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010101000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001101010000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000001000000011111000000000
+00001111100000000000001111100000
+00000000111010000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000011011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111101100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+01010000000000111110011000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11111101100000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+11010000000000111100011000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000010100000010111000000000
+00001110100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001011100000000000001011
+10100000000000101100111000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000000000000111001000000
+00001010100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000011011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000011011
+10010000010000101100011000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101010110010000000000
+11111001000000000010111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100110010000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10011000000000111110100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000000100
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100110000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10011001000000111100101000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011001000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000100000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111110100001000010001010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+11100000100000101100101000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110000000000001010100011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00111000000000101100001000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110100110000000010100111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01100000000000101110000000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000001000
+11110100100000000011100111100000
+00001111011110000000001111011110
+00000000111101111000000000111101
+11100000000011110111100000000011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01011000000000111110101000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000010011011010110000000000
+11110000000000100011011011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10000000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11111110100000000011001111100100
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111011110000000
+00110011111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111001000000110000000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110110000000000010000111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101001110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000100001011
+01100000000010100010101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110110000000000010000111000000
+00011011011100000000001011011100
+00000000101001110000000000101101
+11000000000010110111000000000010
+11011100000000001011111100000000
+00100001110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+11110000100001100000000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10110000000000000010000011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101000110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00101100000000100000100000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010110000000000
+11111001000000001011001011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00110010110000000000111110110000
+00000011111011000000000010111011
+00000000001111101100000000001011
+00110000000000110010101100000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111000010000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11110101000000000011001111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11000100100000110000000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111001000000000010001011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010011011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10001000000000101010000001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000010000010001011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10010100000000100010000000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110010000000000010000011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010010011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+10010000000000101000001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111011000000000011001011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10000000000000110000100000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000100
+11110101000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011011111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+01000000000000111110000000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111101000000000
+11111100100000000011111111100000
+00001101111110010000001101111110
+01001000110011111000000000110111
+00000000000011111111100000000011
+11111100000000001101111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000100001110011000000000
+10111000100000000010111011100000
+00001011101100000000001000001100
+00001000100010111000000000101110
+10110000000010111011100000000010
+11111110000000001010101110000000
+00101110111000000000101110111000
+00000010111011100000000010111011
+10000000001011101110000000001011
+10111000000000101111000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11001000000001011100100000000000
+10110001000000000010110011000000
+00001011001100100001001001001100
+10000011100000110000000000101100
+00010000000010110011000000000010
+11001100000000001001001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000100011010010100000000
+10111011000000000010111011000000
+00001011001100000000001000001100
+00000000100010110000001000001110
+11000110000010111011000000000010
+11101100000000000010101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111000000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011110110000000000
+11111010010000000011111011000000
+01001101101100000001001101101100
+00000000110010110000000000111110
+01100000000010111011000000000011
+11101100000000001101101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101010000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011011100000000
+11111110000000000011111111000000
+00000011111100000000001111111100
+00000000111111110000010000001110
+11100000000011111111000000000011
+11101100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000100000100001010110100000000
+11101001010000000011111011000000
+00001101101100001000001111101100
+11000000110010110000000000111110
+00010000000011001011000000000011
+11001100000100001110101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101010000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+11011000000001010010010000000001
+10001011000000000010111011000000
+00001001101111000000001011101111
+00000000110110110000000000101110
+11000000000011011011000000000010
+11111100000000001000101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111001000000100
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100000000010000
+10100001000000000010110011000000
+00001011001100000000001011001100
+00000000100100110000000000101100
+00000000010010000011000000000000
+11001100000000001010001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10110000100000010011001000001000
+10000100100000000110110111100001
+00001011011110000000001011011110
+00000000100101111000010000101101
+00100000000010010111100000000010
+11011110000000001010011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101110110000000100
+00010000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000000000000000
+10100001000000000011110011000000
+00001111001100001000001111001100
+00000000110100110001000000111100
+10000000000011000011000000000011
+11001100000000001110001100000000
+00111100110000000000111100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00110001000000111101001000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011001000001000000
+11111110000100000011111111000000
+00001101111100000000001111111100
+00000000111111110000000000111111
+10000000000011111111000000000011
+11111100000000001101111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110100000010000
+11111011001010000001111011000000
+00001111101100000001101100101110
+00000000110010110000000000111110
+01000000000011001011000000000011
+11101100110000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11001000100100011001000000000000
+00110110000000000010110111000000
+00001011011100000000001000111100
+00000000101001110000000000101100
+11000000000010100111000000000010
+11011100010000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101111001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001001101000000000
+10110101110000000010110111100000
+00001011011110000000001000011110
+00000000100001111000000000101101
+01100000000010000111100000000010
+11011110100000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100001110000000
+10110010100000010110110011000000
+00001011101100000000001000001100
+00000000101000110000000000101100
+11111000000010100011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101101000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+11100000000101011011100000100000
+11110010000000000011111010000000
+00001111101000000000001100101000
+00000000110010100000000000111111
+10110000000011001010000000000011
+11101000000000001111101000000000
+00111110100000000000111110100000
+00000011111010000000000011111010
+00000000001111101000000000001111
+10100000000000111111101100000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111100
+00000100000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000100
+11111011000000100011001001000000
+00001111100110000000001110100110
+00000000111110010000000000111110
+01000000000011001001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010101001000000
+00001011100100000000001000100110
+00000000101110010000000000101110
+01000000000010001001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000100101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111011000000000010001001000000
+00001011100100100000001010100100
+10000000101110010000000000101110
+01000000000010001001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100111000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10111001000000000010100001000000
+00001011000100000000001000000100
+00000000101100010000000000101100
+01001000000010000001000000100010
+11000100101000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100101000000101
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000000011001000000000
+00001111001001010000001110101001
+01000000111110000000000000111110
+00000000001011001000000000000011
+11100000100000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011111010000000000
+11111001000000000010111001000000
+00001111100100000000001111100100
+00000000111110010000000000111111
+01000100000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011100010000000000
+11111001000000000011111001000000
+00001111110100000000001100110100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100011000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01111000000100001110000000000000
+10111000000000100010111000000000
+00001011100000000000001101100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001011100000000000001011
+10000000000000101100111000000110
+00110000000000000000000000000000
+00000000000000000000000000000000
+01001000000001011100010000000000
+10110001000000000110110001000000
+00001011000100000000001000000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000110000110111001000000
+00001011100100000000001001100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11111001100000000011111001000000
+00001111100100000000001100100100
+00000000111110010000000000111110
+01101100000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+01101000000000011010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000010000111110
+01100000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11101000010000000011111000000000
+00001111100000000000001111100000
+00000000110010000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10001010000000000010111010000000
+00001011111011000000001011111001
+00000000100010100000000000101110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100101000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10100011000000000010110011000000
+00001011101111001000001011001111
+00100000100000110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101100000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010011111000000000
+10000111000000000010110111000000
+00001011011100001000001001011011
+00000000100001110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101110000000000100
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11100111100000000011110111100000
+00001111011110000000001111111110
+00000010110001111000000000111101
+11100000000011110111100000000011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000011000111110001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000100011111011000000
+00001111101100000000001111100100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11111111100000100101111111100100
+00001111110110010000001100110110
+00000000110011111000000000111111
+11100000000011111111100000000011
+11111110000000001110111110000000
+00111111111000000000111111111000
+00000011011111100000000011111111
+10000000001111111110000000001111
+11111000000000111100000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000000000110110111000000
+00001011110000000000001101010000
+00000000101001110000000000111101
+11000000000010110111000000000010
+11011100000000001000011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110001000000101110101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000000010110111000000
+01001011010100000010001000011100
+00000000100001110000000000101101
+11000000000010110111000000000010
+11011100000000001010011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001100110010000000
+10110011010100000010110011000000
+00001011100100000000001000100000
+00000000101000110000000000101000
+11100100000010110011000000000010
+11001100000000001000001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100100000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010111110000000
+11111011010000000011111011000000
+00001111101000000010101000101100
+00000000110010110000000000101110
+11010100000011111011000000000011
+11101100000000001110101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000001000111
+10110000001100101110101100000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011001000000011111011000000
+00001111100000000000001111101001
+00000000111110110000000000111110
+11000000000011111011000000000011
+11001100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111111000000000011111111000000
+00001111111010000000001100111000
+00000000110011110000000000111101
+11000000000011001111000000000011
+11101100000000001100111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000000011
+11110000000000111100100001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110110000000000
+10111011000001000010111011000000
+00001011101011010000001010101011
+00100000110110110000000000101110
+11000000000010101011000000000010
+11101100000000001010101100000000
+00101110110000000000101110110000
+00000010011011000000000010111011
+00000000000011101100000000001011
+10110000000000101110100001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000000010010110000000000
+10111011000000000110111011000000
+00001011101101000000001000100100
+01000000100010110000000000101110
+11000000000010001011000000000010
+11101100000000001000101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000000001101100000000001011
+10110000000000101110000000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010110011000001
+00001011000000000000001000000000
+00000000100100110000000000100100
+11000000001010000011000000000010
+11001100000000001010001100000000
+00101100110000000000101100110000
+00000010010011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111011000000000011111011000000
+01001111100000000000101100000100
+00000000110010110000000000111110
+11000000000011001011000000000011
+11101100000000001100101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100000000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000010111111000000
+00001111110000000000001111110000
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000001111110100001000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111111001000000011001111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+00111110000000001111111110000000
+00111111111000000000111111110000
+00000011011111100000000011111111
+10000000001111111110000000001111
+11111000000000110011000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10100000000100001110111000000000
+10111111110100000000001011100000
+00001011101110000000001011101110
+00000000101110111000000000101110
+11100000000010111011100000000010
+10101110000000001011101110000000
+00101110111000000000101111110000
+00000010101011100000000010111011
+10000000001011101110000000001011
+10110000000000101010000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000100
+10110001000001000010000011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010111001000000000010
+00001100000000001011001100000000
+00101100110000000000101100110000
+00000010010011000000000010110011
+00000000001011001100000000001011
+00110000000000100010001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000101011010110000000000
+10111000000010000010001011000000
+00001011101100000000001011101100
+00000000101110110000000000100110
+11000000000110111001110000000010
+10101100000000001011101100000000
+00100110110000000000101110110000
+00000010101011000000000010111011
+00000000001011101100000000001011
+10110000000000101011000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000101011110110000000000
+11111101000000001011001011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011110000000011
+00101100000000001111101100000000
+00111110110000000000111110110000
+00000011011011000000000011111011
+00000000001111101100000000001111
+10110000000000110000000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000000011011110000000000
+11110101000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100001000
+00111111110000000000111110110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011101011000000
+00001111101100000000001101101100
+00000000111110110000000000111110
+11000000000011111001000100000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011001011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000000010001011000000
+00001001101100000000001001101100
+00000000101110110000000000101110
+11000000000010110001000000000010
+11101100000000001011101100001000
+00101110110000000000101111110000
+00001010001011000000000010011011
+00000000001011101100000000001011
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011100100000010100011000000
+00001001001100000000001011001100
+00000000101100110000000000101100
+11000000000010110010000000000010
+11001100000000001011001111000000
+00101100110000000000101110110000
+00000010000011000000000010010011
+00000000001011001100000000001011
+10110000000000101111100000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+01100000000000010001111000000000
+10110111100000000010000111100000
+00001001011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110010000
+00101101111000000000101101111001
+00000010000111100000000010010111
+10000000001011011110000000001011
+01111000000000101101100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110001000000
+11110001000000000011100011000000
+00001101001100000000001111001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110000000000111100110000
+00000011000011000000000011010011
+00000000001111001100000000001111
+00110000000000111101001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000010100
+11110101100000000011111111000000
+00001101111100000000001101111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000100
+00111111110000000000111111110100
+00000011111111000000000011011111
+00000000001111111100000000001111
+11110000000000111101000000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011110110000000000
+11110001011000000011001011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+00101100000000001111001110000000
+00110010110000000000111110110001
+00001011001011000000000011111011
+00000000001111101100000000001111
+10110000000000111110101000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110101000010010000000111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+10011100000000001011011100000000
+00110101110000000000101100110010
+00000010000111000000000010110111
+00000000001011011100000000001011
+01110000000000101101001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000001000000001001111000000100
+10110111100000100000000111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010111111100000000010
+00011110000000001011011110000000
+00100001111000000000101101111000
+00000010000111100000000010110111
+10000000001011011110000000001011
+01111000000000101111000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011010100001010000011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+10001100000000001011001100000000
+00100100110000000000101100110000
+00000010000011000000000010110011
+00000000001011001100000000001011
+00110000010000101101001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11110110110000000011001010000000
+01001111101000000000001111101000
+00000000111110100000000000111110
+10000000000011111110000000000011
+00101000000000001111101000000000
+00110010100000000000111110100000
+00000011001010000000000011111010
+00000000001111101000000000001111
+10100000000000111111101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000010000
+11111000000010000011111000000000
+00001111100000000000000111100000
+00000000111110000000000000111110
+00000000000011111000100000000011
+11100000000000001111100001000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011001001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001100000000011
+00100100000000001111100100100000
+00111110010000000000111100010000
+00000011001001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000100001000110010000000000
+10111001000000000110001001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010110001100000000011
+01100100000000001011100111001000
+00101110010000000000101110010000
+00000010001001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000001000010001001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001001000000010
+00100100000000001011100100000000
+00101110010000000000101110010000
+00000010001001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10111001001010000010100001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010111001000000000010
+01000100000000001011000100000000
+00101100010000000000101100010010
+10000010000001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000001000001010001000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+00100000000000001111100000000000
+00111110000000000100111110001010
+00001011001000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111101000000000011011001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011110101000000000011
+11100100000000001111100100000000
+00111110010000000000111110010010
+10000011111001000000000011111001
+00000000001111100100000000001111
+10010010100000111110011000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+10011000000001011110010000000000
+11111101100000001011001001000000
+00001011100100000000001111100100
+00000000111110010000000000111110
+01000000000011111101000000000011
+11100100000000001111110100000000
+00111110010000000000111110010000
+00000000101001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000010000
+10111000000000000011011000000000
+00001011100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010101000000000000010111000
+00000000001011100000000000001011
+10000000000000101100111000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001010000001010000001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001100000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010000001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001001000000010011001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000001000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010101001000000000010111001
+00000000001011100100000000000011
+10010000010000101100011000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000001000
+11111001001000100011001001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001010000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011001001000000000011111001
+00000000001111100100000000001111
+10010000000000111110100000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11110001100000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001101000000011
+11100100000000001111100100001000
+00111110010000000000111100010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000010000000011001000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000010000
+00111110000000000100111110000000
+00001011001000000001000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000001010010100000000000
+10111010100000001010001010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010111010101000000010
+11101000000000001011111000000000
+00101110100000000000101110100000
+00000010001010000000000010111010
+00000000001011101000000000001011
+10100000010000101100101000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011100000000010000011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110001000000000010
+11001100000000001011001110000000
+00101100110000010000101100110000
+00000010000011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110111010000000010000111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011010000000000
+00101101110000000000101101110000
+00000010000111000000000010110111
+00000000001011011100000000001011
+01110010000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110011100000001011000111100000
+00001111011110000000001111011110
+00000000111101111000000000111101
+11100000010011110111100000000011
+11011110000000001111010010000000
+00111101111000000000111100111000
+00000011000111100000000011110111
+10000000001111011110000000001111
+01111000000000111100101000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000000111100000000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110001000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111111100000000011001111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001011110010010000
+00111111111000000000111111111000
+10000011001111100000000011111111
+10000000001111111110000000001011
+11111001000000111101000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110101000000000010000111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011010000000000
+00101101110000000000101101110000
+00000010100111000000000010110111
+00000000001011011100000000001011
+01110000000100101110101000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+00010000000000001001110000000000
+10110011000000000010000111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011010000000010
+00101101110000000000101100110000
+00000010000111000000000010110111
+00000000001011011100000000001011
+01110000001000101100011000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01100000000101001100110000000000
+10110001001000000010000011000000
+00001011001100000000001011001100
+00000000101100110000000001101100
+11000000000010110011010010000010
+11001100000000001011000000000000
+00101100110000000000101110110000
+00000010100011000000000010110011
+00000000001011001100000000001011
+00110000000000101101100000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+11111000000101011010110000000000
+11111011000000001011001011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011010000000011
+11101100000000001111100000000000
+00111110110000000000111111110000
+00000011001011000000000011111011
+00000000001011101100000000001111
+11110000000000111110111000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000100000000001110110000000000
+11111011000000010011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111100001000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001011101100000000001111
+10110000000000111110000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001111110000000000
+11110111000000000011001111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111100000000011
+11111100000010001111110000000000
+00111111110000000000111111110000
+00000011001111000000000011111111
+00000000001111111100000101001111
+11110000000100111110000001100100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000001000
+10111011000000000000101011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011100000000010
+11101100000000001011100011100000
+00101110110000000000101110110000
+00000010101011000000000010111011
+00000010001011101100000000001011
+10110000000000101110000001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010001011000000
+00001011101100000000001011101100
+00000000101110110000000000101010
+11000000000010111011000100000010
+11101100000000001011100010000000
+00101110110000000000101110110000
+00000010001011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110001000000000010100011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000011011000000000000
+00101100110000000000101100110000
+00000010100011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001000000101
+00000000000000000000000000000000
+00000000000000000000000000000000
+10000000000011010110110000000000
+11111011000000001011001011000000
+00001111101100000000001111101100
+00000000111110110000000000111010
+11000000000011111011000000000011
+11101100000000001111100000000000
+00111110110000000000111110110000
+00000011001011000000000011111011
+00000000001111101100000001001111
+10110000000100111110000000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000010000
+11111101000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000000111110000000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000011111111100000000001111
+11110000000000111110100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000011011111111000000000
+11101111100000000011111111100000
+01001111111110000000001100111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111011000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001110111000000000
+10111011100000000010111011100000
+00001011101000100000001000101110
+00000000101110111000000000101110
+11100000000010111011100000000010
+11101110000000001011101100000000
+00101110111000000000101110111000
+00000010111011100000000010111011
+10000000001011101110000000001011
+10111000000000101111000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+11001000000001011100110000000000
+10100011000000000010110011000000
+00001011000100001000111001001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001010
+00110000000000101011001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000110111011000000
+00001011000100001000001001101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000010000101111000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10010000000101011110110000000000
+11101011000000000011111011000000
+10001111100100010000001101101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001011101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111000100000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000001000011111111000000
+00001111110000000001001110111100
+00000100111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01010000000100001010110000000000
+11101011000000000011111011000000
+01001111100101100000101100101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000110001010100000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000010000000111011000000
+10001011101101000000001000101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10111000000000100011001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000001000
+10110011111001000000110011000000
+00001011001100010000001001001100
+00000000001100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110011000000100011000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+11110000000000010001111000000100
+10110111100000000010110111100000
+00001011011010010000011001011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000010100011110000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001010000000000000110000000000
+11110011000000000011110011000000
+10011111101100010110001101001100
+00000000111100110001000000111100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110000000000111100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00110000000000110001101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011011110000000000
+11111111000000000011111111000000
+00001111111000010000001110111100
+00000000111111110000010000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+01110000000001111101000000000110
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011000000000011111011000000
+00011111100111001000001100101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11001000100100011001110000000000
+10110111000000000010110111000000
+00001011110100000000001000011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101111001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001001111000000000
+10110111100000000010110111100000
+00001010010110000001001000011110
+00000000101001111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010100111
+10000000001011011110000000001010
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00011011001100110000001000001100
+00010000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11100000000101011010100000000000
+11111010000000000011111010000000
+00001110101000000000101100101000
+00000000111010100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00101110100000000000111110100000
+00000011111010000000000011101010
+00000000001111101000000000001110
+10100000000000101111101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000100000000111101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011101001000000
+00001111101100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000110000001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10110001000000000010001001000000
+00001011100110010000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+00010000100000101010000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001010000000010001001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000100000011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010000001000000
+10001011001100000000001011000100
+00000000100100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101000001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000100
+11111000000000001011101000000000
+00001111100001010000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000110010111000000111
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100110101000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110111100000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+10011000000001011110010000000001
+11111101000000001011001001000000
+00001111110100000000001100100100
+00000000111110010000000000111110
+01000000000111111001000000000011
+11100100000000001111100100010000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+11010000000000111110111000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+01111000000100001110000000000000
+10111000000000000010001000000000
+00001011000000000000001000100000
+00000000101110000000000000101110
+00000000000011111000000000000010
+11100000000000001011100010100000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001011100000000000001011
+10000000000000101100011000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+01001000000001011100010000000000
+10110001000000000010010001000000
+00011011000100000000011001000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100100000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000001101101001000000001
+01100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000001
+10111011000000000010011001000000
+00001011001100000000001001100100
+00000000101110010000000000101110
+01000000000010101001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000010011011
+10010000000000101100011000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+10111001000000100011011001000000
+01001111100111110000101101100100
+00000000111110010000000000111110
+01000000000010111001000000000011
+11100100000000001011100100000000
+00111110010000000000101110010000
+00000011111001000000000011111001
+00000000001111100100000000001011
+10010000000000111110000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01101000000000011010010000000000
+11111001000000000011101001000000
+00001111100110000000001110100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000100000111101101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000001000011111000000000
+00001111100000011000001100100000
+00000000111110000000000000111110
+00000000000011111000000001000011
+11100000000000001111100000000000
+00110010000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10110110000010010010111010000000
+00001011111010000000001000101000
+00000000101110100000000000101110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101010100000000000111010100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+11101100000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110000000000000010110011000000
+00001011001111000000001001001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00100000110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00111000000000101100001000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110101000000000010110111000000
+00001011010000000000001001011100
+00000000101101110000001000101101
+11000000000010110111000000000010
+11011100000000001011011110000000
+00101001110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01100000100000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110100100000000011110111100000
+01001111011110000000101101011110
+00000000101101111000000000111101
+11100000000011110111100000000011
+11011110000000001111111110000000
+00110001111000000000101101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111100001000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111000000000000011111011000000
+10001111101000000000001110101100
+00001000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111010110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000001011111111000000000
+11111110100000000011111111100000
+00011111011110000000001110111110
+00000000111111111001000000111111
+11100100000001111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000101101100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+11100111000100000010110111000000
+00001011010100100000001101011100
+00000000101101110000000000111101
+11000000000011110111000000000010
+11011100000000001011011100000000
+00101101110000000000111001110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01000000000000101110101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00010000000000001001110000000000
+10110110000000000010110111000000
+00001010111100000000001011011100
+00000000101101110000000100101101
+11000000000110110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001010
+01100000000000101100010000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01101000000101001100110000000000
+10100010000000000010110011000000
+00001011100000000000001000001100
+00000000101100110000000000101000
+11000000000010100011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000000011
+00000000000000101101000100000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10111000000101011010110000000000
+11111000000000000011111011000000
+00001110101100001000001011101100
+00001000111110110000000000101110
+11000000000010111011000000000011
+11101100000000001111111100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10010000000000101110001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11101001010000000011111011000000
+00001111100000001000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111010110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10000000001100111110010100000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001111110000000000
+11111100001000000011111111000000
+00001111110110000000001100111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11011000000000111110000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000000000110110000000000
+10111001110000000010111011000000
+00001011100001000000001111101100
+00000000101110110000000000101110
+11000000000011001011000000000010
+11101100000000001011111100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10010000000000101110000001100000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000001000
+10111010000000000010111011000000
+01001011101000100000011000101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110010000000101110100000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000001
+10110001000000000010110011000000
+00001011000000000000101001001100
+00000000101100110000000000100100
+11000000000010000011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00000000000000101100101000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+10000000000011010110110000000000
+10111010000000000011111011000000
+00001111101100000000001100101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10100000000000111110000000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111101000000000011111111000000
+00001111110000000000001110111100
+00000000111111110000000000111111
+11000000000011101111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000001001111
+11000000000000111110100000100110
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000011011111111000000000
+11111111100000000011111111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111110000000000110011111000
+00000011010100100000001011001111
+10000000001111111100000000001111
+11111000000000111111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001110111000000000
+10111011100000000010111011100000
+00001011101110000000001110101110
+00000000101110111000000000101110
+11100001000010111011100000000010
+11101110000000001011101110000000
+00101111110000000000101000110000
+00000010001000100000000010001011
+10000000001011111110000000001011
+10111000000000101111000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11001000000001011100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000100100110000
+00000010110010000000000010000011
+00000000001011001100000000001011
+00110000000000101111001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010111011000000
+00001011101100000000001010101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000010
+00101110110000000000101110110000
+00000010111010000010000010001011
+00000000001011101100000000001011
+10110000000000101111000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000100000101011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000110110110000
+00000011111000010000000011001011
+00000000001111101100000000001111
+10110000000000111100000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111100110000000000111011110000
+01000011001101100100000011111111
+00000000001111101100000000001111
+11110000000000111111110000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000010110010110000
+00000011111010000000000011011011
+00000000001111101100000100001110
+10110000000000111101010000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11011000000000010010110000000000
+10111011000000000010111011000000
+00001110101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000010000010
+11101100000000001011101100000000
+00101111110000000000100010110000
+00000010000011000000000010001011
+00000000001011111100000000001000
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011000000000010110011000000
+00001001001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011100000000010
+11001100000000001011001100000000
+00101100110000000000100010110000
+00000010100001000000000010010011
+00000000001011001100000000001010
+00110000000000101111000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+11110000100000010001111000000100
+10110111100000000010110111100000
+00001010011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000100001111001
+00000010001101100000000010000111
+10000000001011011100000000001000
+01111000000001101111110000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000000000000110001000000
+11110011000000000011110011000000
+00001111001100000000001111001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+11001100000000001111001100010000
+00111100110000000000110000110000
+00000011100001000000000011010011
+00000000001111001100010000001110
+00110000000000111101001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011011110000000000
+11111111000000000011111111000000
+00001110111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000010
+11111100000000001111111100000000
+00111111110001000000111111110000
+01000011101101000000000011111111
+00000000001111111100100000001111
+11110000000000111101000000000110
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000100
+11111011000000100011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110111010100000110010110000
+00000011001010000000000011111011
+00000000001111101100110000001100
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11001000100100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110100000000101001110000
+00000010000111000000000010110111
+00000000001011001100010000001010
+01110000000000101111001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000001000000001001111000000000
+10110111100000000010110111100000
+00001011011110000000001010011110
+00000000101001111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101110000000000100001110000
+00000010000110100000000010110111
+10000000001011011110100000001000
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000100101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001001001100000000
+00101100110000000000101000110000
+00000010000011110000000010110011
+00000000001011001100000000001010
+00110000010000101101101000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11100000000101011010100000001000
+11111010000000000011111010000000
+00001111101000000000001111101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00111110100000000010110010100000
+00000010001110101000000010111010
+00000000001111101000000000001000
+10100000000000101111101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000010
+00111100000000000010111110000100
+00000011111000001000000011111000
+00000000001111000000000000001111
+10000000010000111101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001101100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001100000000011
+11100100000000001111100100000000
+00111110010000000000110110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000001000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001100000000010
+11100100000000001011100100000000
+00101110010000000000110110010110
+00000010111001000000000010111001
+00000000001011100100000000001000
+10010000000000101110100000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001001000000010
+11100100000000001011100100000000
+00101110010000000000100110010000
+00000010111001000000000010111001
+00000000001011100100000000001010
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000110
+11000100000000001011000100000000
+00101100010010100010100100010000
+00000010110001000000000010110001
+00000010011011000100101000001000
+00010000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000101110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111100001010000000110110000000
+00000011111000000000000111111000
+00000000001111100000100100011110
+10000000001001111110111000000111
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000001
+11100100000000001111100100000010
+00111110011010100000111100010010
+10000011111101000000000011111001
+00000000001111100100000000001110
+10010000000000111110011000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+10011000000101011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111101000000000011
+11100100000000001111100100000000
+00111110010000000000110011010000
+00000011001101000000000011111001
+00000000001111100100000000001111
+10010000000000111110111000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+01111000000010001110000000000000
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000000111110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000100010000000
+00000010001000000000000010111000
+00000000001011100000000000001011
+10000000000000111100111000000010
+00110000000000000000000000000000
+00000000000000000000000000000000
+01001000000001011100010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000010100000010000
+00000010010001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101010010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000100010010000
+00000010011001000000000010111001
+00000000001011100100000000001011
+10010000010000101000011000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000001011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000101110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000110010010000
+01000011011001100100000011111001
+00000000001111100100000000001011
+10010000000000101110100000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+01101000000000011010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011101001100000000011111001
+00000000001111100100000000001111
+10010000000000111101101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000000001010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000110010000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000001010010100000000000
+10111010000000000010111010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010111010100000000010
+11101000000000001011101000000000
+00101110100000000000110101100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110001100000000110
+11001100000000001011001100000000
+00101110110000000000100000000000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001100000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000100010001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000010000010
+11011100000000001011011100000000
+00101101110000000000100101001000
+00000010110111000000000010110111
+00000000001011011100000001001011
+01110000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000000000001111000000000
+11110111100000000011110111100000
+00001111011110000000001111011110
+00000000101101111000000000111101
+11100000000011110111100000000011
+11011110000000001111011110000000
+00111111111100000000110001010000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111100101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000101011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000100001111101100000000
+00111110110010100000111110010000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111001000000
+11111111100000000011111111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111011001000
+00000011000111100000000011001111
+10000000001111111110000000001100
+11111001000000111101100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000001
+00101101110000000000100001000000
+00000011010111000100000011010111
+00000000001011011100000000001101
+01110000001000101110101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00010000000000001001110000001000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101001010000
+00000010001111000000000010000111
+00000000001011011100000000001000
+01110000001000001100010000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01100000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101110110000000000100010010000
+00000010010011000000000010010011
+00000000001011001100000000001001
+00110000000000101101000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011110011000000000011
+11101100000000001111101100000000
+00111111110000000010111010100000
+00000011001011010000000011001011
+00000000001111101100000000001000
+10110000000000111110111000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10010100000000001110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000010011
+11101100000000001111101100000000
+00111110110000000000111110100000
+00000011111011001000000011111011
+00000000001111001100000100001111
+10110000000000111110100000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+00111100000000001111111100000000
+00111110110000000000110011110001
+00000011001111000000000011111111
+00000000001111101100000000001100
+11110000000000111110000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011100000000010
+00101100000000001011101100000000
+00101110110000000000100010110000
+01000010101011000000000010111011
+00000000001011101100000000001010
+10110000000000101110010001100000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000100000010
+00101100000000001011101100000000
+00101110110000000000100010100000
+00000010001011000000000010111011
+00000000001011101100000000001000
+10110000000100101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+00001100000000001011001100000000
+00101100110000000000100000100000
+00000010100011000000000010110011
+00000000001011001100000000001010
+00110000000000101100001000000100
+00000000000000000000000000000000
+00000000000000000000000000000000
+10000000000011010110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+00101100000000001111101100000000
+00111111110000000000110000110000
+00010011001011000001000011111011
+00000000001111101100000000001100
+10110000000000111110000000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000010011111111000000000011
+11111100000000001111111100000010
+00111111110000000010111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111110100000100100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000011011111111000000000
+11111111100000000011111111100000
+00001111111110000000011111111110
+01000000111111111000000000110011
+11100000000011111111110000000011
+00111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000010001110111000000000
+10111011100000000010111011100000
+00001011101110000000001011101100
+10000000101110111000000000101010
+11100000000010111011000000000011
+01101110000000001011101110000000
+00101110111000000000101110111000
+00000010111011100000000010111011
+10000000001011101110000100001011
+10111000000000101111000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110011000000000010110011000000
+00001011001100000000011011001100
+00000000101100110000000000100000
+11000000000010110011001000000010
+00001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001010
+00110000000000101011001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011010110000000000
+10111011000000000010111011000000
+00001011101100000001001011101100
+00000000101110110000000000101010
+11000000000010111011000000000010
+01101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000010000101111100000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000101011110110000000000
+11111011000000000011111001000100
+00001111101100000000001011101100
+00000000111100110000000000110010
+11000000000011110011000000000011
+00101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000100111100100000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000011111101100000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111001010000
+00001111101100000000001111101100
+01000000111110110000000000111110
+11000000000011111011001000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101010000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000000010111011000010
+10001011101100000000001011101111
+01000000101110110110000000101110
+11000000000010111011101000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11000000000001000100110000000000
+10110011000000000010110010100000
+00001001001100000000001011001100
+00000000101100110010000000101100
+11000000000010110011010000100010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01100000000000000101111000000000
+10110111100000000010110111000000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101111110000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000000000100110000000000
+11110011000000000011110010010100
+00001101001100000000001111001100
+00000000111100110000000101111100
+11000000010011110011000000000011
+11001100000000001111001100000000
+00111100110000000000111100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011011110000000000
+11111111000000100011111110000000
+00001111111100000001001111111100
+00000000111111110000000101111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000110
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000101011110110000000000
+11111011000000000011111010100000
+00011101101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100101000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000000011001110000000000
+10110111000000000010110111000000
+00001000011100000000001011011100
+00000001101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101111001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00100000000100001001111000000000
+10110111100000000010111101100000
+01001000011110000101001010011110
+00010000101001111000000000101101
+11100000010010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01101000000101001100110000000000
+10110011000000000010110011000000
+00001000001100000000001011001100
+00000100101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011110100000000000
+11111010000000000011111110101100
+00001101101000000000001111101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00111110100000000000111110100000
+00000011111010000000000011111010
+00000000001111101000000000001111
+10100000000000111111101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000011010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100001
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+10000000110010010100000000111110
+01000000000011111001001000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001100000
+00001011100100000000001011100100
+00100010100010011100000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110100000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00111000000001010010010000000000
+10111001000000000010111001000100
+00001011100100000000001011000100
+00000000100010010000000000101110
+01000000000010111001000010000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000100000110000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000001010110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100001
+01000000110010000000000000111110
+00000000000011111000010100000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110011000000111
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000101011110010000000000
+11111001000000000011110111000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+10011000000101011010010000000000
+11111001000000000011111101000000
+00001111100100000000001111110100
+00000000111111010000000000111110
+01000000000011111101000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110111000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000000010111000000000
+01001011100000000000001110000000
+00000000111110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000011101000000000000010111000
+00000000001011100000000000001011
+10000000000000101100011000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000001001000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000010010110001000000000110
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000001
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000000000010010000000000
+10111001000000000010111001000000
+00001011100100000000001010101100
+00000001101010010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010101001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000001011110010000000000
+11111001000000000011111001110000
+00000111100100000000001111100100
+00000000101110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000101110100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000011010010000000000
+11111001000000000011111001110000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011101001000000000011111001
+00000000001111100100000000001111
+10010000000000111101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000000001010000000000000
+11111000000000000011111000010000
+00001111100000000000001111100000
+00000000110110000000000000111110
+00000000010011111000100000001011
+00100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000101010010100000000000
+10111010000000000010111010100000
+00001011101000000100001011111011
+00000000110111101000000000101110
+10000000000010111110000000000010
+00101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001101
+00100000100000111000000000101100
+11000000000010110011000100000010
+01001100000000001010001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001100000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10000000000100010001110000000000
+10110111000000000010110101010000
+00001011011100000000001011011011
+00000000100101110000100000101101
+11000000000010110101100000000010
+01011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10001000000010000001111000000000
+11110111100000000011110111100000
+00001111011110000000001111011110
+00000000110001101000000000111101
+11100000000011111111100000000011
+01011110000000001110011110000000
+00111101111000000000101101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111100101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011010110000000000
+11111011000000000011111001000000
+00001111101100000000001111100000
+00000000111110000000000000111110
+11000000000011111011000000000011
+10101100000000001101101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000011111
+10110000000000111100001000000010
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000001001011111000000000
+11111111100000000011110111100000
+00001110111110000000001111111110
+00000000110001011000000000110011
+11100000000010111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111101100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000110001001110000000000
+10110111000001000010110111000100
+00011000011100000000001110111000
+00000000101001110000000000110101
+11000000000010110100001000000010
+11011100000000001011011100000000
+00101101110000000000111001110000
+00000011110111000000000010110111
+00000000001011011100000000001111
+01110000000000101110001000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00010000000000001001110000000000
+10110111000000000010110101000000
+00001010011100000000001011011100
+00000000100001000000000000100001
+11000000000010110101000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101000011001000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01100000000001001000110000000000
+10110011000000000010110001110000
+00001000001100000000001010101000
+00000000101000000000000000100100
+11000000000010111001000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010100011000000000010110011
+00000000001011001100000000001010
+00110000000000101101000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011010110000000000
+11111011000000000011110011000010
+00001110101100000000001111100100
+00001000110010110000000000110010
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000010111011000000000010111011
+00000000001111101100000001001011
+10110000000100111110111000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000100000000001110110000000000
+11111011000000000011111011000000
+00001111101100000000001111100101
+00000100111110100100000000111110
+11000000000011111001010000000011
+11101100000000001111101100000000
+00111110110000000000111010110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000001100111110100000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10100000000100001111110000000000
+11111111000000000011111111110010
+00001100111100000000001111111000
+01000000110011110000010000110011
+11000000000011111111100100001011
+00111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111110000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10100001000001000110110000000000
+10111011000000000010111011100000
+00001010101100000001001011100000
+00000000100000000110000000101010
+11000000000011111001000000000010
+00101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000011101011
+00000000001011101100000000001011
+10110000001000101110000001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001000101100000000001011100100
+00000000100010010000000000101010
+11000000000010111011000010000010
+00101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000101000000110000000000
+10110011000000000010111011000000
+00001010001100000100001011000000
+00000010100000100000000000101000
+11000000000010100001000000000010
+00001100000000001011001100000000
+00101100110000000000101100110000
+00000010010011000000000010110011
+00000010001011001100000000001001
+00110000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+10000000000011010110110000000000
+10111011000000000011111011000000
+00001100101100000000001111100100
+00001000110010010000000000111010
+11000000000010111011000000000011
+00101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110000000000110
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011111110000000000
+11111111000000000001111111000000
+00001111111100000000001111110000
+00000000111111000000000000111111
+11000000000011111101000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011101111
+00000000001111111100000000001111
+11110000000000111110100000100110
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000011011111111000000000
+11111111100000000011111111100000
+00001111111110000000001101111110
+00000000111111111000000000111111
+00000000000011001100000000000011
+11110000000000001100110000000000
+00110011000000000000110011000000
+00000011111101000000000011001111
+10000000011111111110000000011111
+11111000000000111011000000000001
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001110111000000000
+10111011100000000010111011100000
+00001011101100000000001000101110
+00000000101110111000010000101110
+00000001000010001000100000000010
+11100000000000001100100010000000
+00100010001000000000100010001000
+00000010111001100000000010001011
+10000000001011101110000000001011
+10111000000101101111000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+11001000000001011100110000000000
+10110011000000000010110011000000
+00001011001100000000001001001100
+00000000101100110000000000101100
+01000000000010010001000000000010
+11000000000000001001001000000001
+00100100000000000000100000000000
+00000010110001000000000010010011
+00000000001011001100000000001011
+00110000000000101111001000000001
+00110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010111011000000
+00001011001100000000001001101100
+00000000101110110000000000101110
+01000000000010011001000000000010
+11100000011000101000101000000000
+00100110000000000000100010000000
+10000010111001000010000010011011
+00000000001011101100000000001011
+10110000010001101111000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10010000000101011110110000000000
+11111011000000000010111011000000
+00001111101100000000001101101100
+00000000111110110000000000111110
+10000000001011011000000100010011
+11100011000000101101100100000000
+10110110011000000010110010000101
+00010010111001010100001011011011
+00000000001011101100000000001011
+10110000000000111000100000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000011111111000000
+00001111111100000000001110111100
+00000000111111110000000000111101
+10000000000011101000100000000011
+11100010000000001111110100000000
+00111011011001000000111110001000
+00000011110001100000000011101111
+00000000001111111100000000001111
+11110000000000111111100000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+00001111101100000000001110101100
+00000000111110110000000000111110
+11000000000011101001001000000011
+00000001000000101100001100000000
+00110100010000000000110010000100
+00000011001001010000000011001011
+00000000001111101100000000001111
+10110000001000111101010000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11011000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001000101100
+00000000101110110000000000101110
+11000000000010001001011000000010
+00100000000000001101101100000100
+00100010011100100010100010000000
+00001010001001000000000010001011
+00000000001011101110010000001011
+10110000010000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000001000
+10110011000000000010110011000000
+00001011001100000000001010001100
+00000000101100110000000000101100
+00000000000010100010110000001010
+00001100000000001000000010000100
+00100000101100100000100000110000
+00001010000010000000001010000011
+00000000001011001101000000001011
+00110000000001101111001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+11110000000000010001111000000000
+10110111100000000010110111100000
+00001011011110000000001000011110
+00000000101101111000000001101101
+00100000000010000110100000000010
+00011110000000101001010010001000
+00100000101001000000100001111001
+00000010000110100000000010010111
+10000000001011011110001000001011
+01111000000000101111110000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000000000000110000000100
+11110011000000100011110011000000
+00001011101100000000001110001100
+00000000111100110000000000111110
+01000000000011100011000000000011
+00001100000000001100001000000000
+00110100100001000000100000110001
+00000011000010000000000011000011
+00000000001111001100000000001111
+00110000000000111101101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000100101011011110000000000
+11111111000000000011111111000000
+00001111111100000000001110111100
+00000000111111110000000000111111
+01000000000011111111000100000011
+11111100010000001111011000010000
+10111111100001000000111111110001
+00000011111110100100000011101111
+00000000001111111100000000001111
+11110000000000111101000000000110
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+10000000000011011010000000000011
+00101110000000001100100100000000
+00110010110000000000110010111000
+00000011001010000000000011011011
+00000000001111101100000000011111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11001000100100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101111
+10000000000010000110000000000010
+00001100000000001000010100000000
+00110001110000000000100000110000
+00000010000010000000010110000111
+00000000001011011100000000001011
+01110000000000111011001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000001000000001001111000010000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010010011100000000010
+00011110000000001000001110000000
+00100000111000000000100101111000
+00000010000110100000000010000111
+10000000001011011110000000001011
+01111000010000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000100000010000011000000000010
+00001100000000001000001100000000
+00100000110000000000100000110000
+00000010000010000000000010000011
+00000000001011001100000000001011
+00110000000000101001001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11100000000101011010100000000000
+11111010000000000011111010000000
+00001111101000000000001011101000
+00000000111110100000000000111110
+10100000000011011010000000001011
+00101000000000101100101001000000
+10110010100100000010110110100000
+00001011001110000000001011001010
+00000000001011101000000000001011
+10100000000000101111101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000010000111100
+00000000000011110000010000000011
+11100000000000001111100000001000
+00111000000000100000111110000000
+00000011110100000000000011111000
+00000000001111100000000000001111
+10000000000000111001001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011001001010000000011
+00100100000000001111000100000000
+00110010010000000000110010010000
+00000011111001000000000011001001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000010000001000110010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000010010001001111000000010
+00100100000000001011100100000000
+00100010010000000000100010010000
+00100010111001000000000010001001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010011001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010001101000000000010
+00110100000000001011110100100000
+00100011010101000000100011010000
+00000010111101000000000010001001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000100100010000000000101101
+01001011001010000101001010001010
+00010100101000001011010100101000
+10100001010010100000100001010010
+10000010110101001010000010000001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00001000000011001000001000000011
+00100000100000001111100000100000
+00110010000010000010110010000010
+00000011111100001000001011001000
+00000000001111100000000100011111
+10000000000000111110111000000111
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111001000000
+00001111100100101000001111100100
+00000000111110010000000000111110
+01101010000011111001000000000011
+11100110101000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000001111110111000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+10011000000001011110010000000000
+11111001000000000011111001000000
+00001111100100000000001110100100
+00000000111110010000000000111110
+01000000000011010101000000000011
+11100100000000001100110100000000
+00110011010000000000110010010000
+00000011111001000000000011111001
+00000000001111110100000000001111
+10010000000000111110111000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01111000000100001110000000000000
+11111000000000000010111000000000
+00001011100000000000001011100000
+00000000101110000000000000101100
+00000000000011011000000000000010
+11000000000000001100100000000000
+00100010000000000000110110000000
+00000010111000000000000110111000
+00000000001011100000000000001111
+10000000000000101100011000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+01001000000001011100010000000000
+10110001000000000010110001000000
+00001011000100000000001010000100
+00000000101100010000000000101100
+01000000000010010001000000000010
+11000100000010001001000100000000
+00100000010000000000100000010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10101001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101100
+01010000000010011001010000000010
+11100100000000001000100100100000
+00100010010000000000100110010000
+00000010111001000000000010111001
+00000000001011100100000000001010
+10010000000000101100011000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+10111001000000000010111001000000
+00001111100100000000001110100100
+00000000111110010000000000111110
+01000000000011011001000000000011
+11100100000000101101100100000000
+10110010010000000000110010010000
+00000011111001000000000010111001
+00000000001111100100000000001011
+10010000000000111110100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01101000000000011010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000011111100100000000001111
+10010000000000111101101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011101000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011001000000010000011
+01100000000000001100000000000000
+00111110000000100000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001110
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000001010010100000000000
+10111010000000000010111010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010001110010000000010
+00101000000000001000101010000000
+00101101101100000000101110100000
+00000010111110000000000010111010
+00000000001011111000011000001000
+10100000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010100011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010000001010100000010
+00101100000000001000001110000000
+00101100111100000000101100110000
+00000010110010000000000010110011
+00000000001011001111000000001010
+00110000000000101100001000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110111000000000010110111000000
+00001011011100100000001011011100
+00000000101101110000000000101101
+11000000000010000110100000000010
+00011100000000001000010100001000
+00101101000000100000101101110000
+00000010110110000000000010110111
+00000000001011011110000000001000
+01110000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110111100000000011100111100000
+00001111011110110000001111011110
+00000000111101111000000000111101
+11101000000011000110100000000011
+01011111000000101100010110000000
+00111101001000000000111101111000
+00000011110110100000000011110111
+10000000001111011110000000001110
+01111000000100111100101000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00001111101101110000001111101100
+00000000111110110000000100111110
+11001100011011111010000000001011
+11101100100000001111100100000000
+00111110000000000000111110110000
+00000011111010000000000011111011
+00000000001111001100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111001000000
+11111111100000000011111111100000
+00001111111110000000001100111110
+00000000111111111000000000111011
+11110000000011000110100000100011
+00111111000001001111110110000010
+00110011001000000000111111111000
+00000011001110100100001011001111
+10000000001111111110000000001111
+11111000000000111101100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001101011100
+00000000101101110000000000111011
+11001000000011010110011000000010
+00111100000000001010010100000000
+00100001000100000000101101110000
+00000010000110000000000010000111
+00000000001011010000000000011011
+01110000000000111110101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00010000000000001001110000010000
+10110111000000000010110111000000
+00001011011100000000001001011100
+00000000101101110000000000101001
+11000000100010000110000000000010
+00011100000000001011010100000000
+00100001000000000000101101110000
+00000010000110010000100110000111
+00000000001011011100000000001011
+01110000000000101100010010000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01100000000101001100110000000000
+10110011000000000010110011000000
+10001011101100000000001001001100
+00000000101100110000000000101010
+11000000001010010010000000001010
+00001100000000001010000100000000
+00100000000000000000101100110000
+00000010000010100000000010000011
+00000000001011000000000000011011
+00110000000000101001100100000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010110000000000
+11111011000000000011111011000000
+00001111111100000000001001101100
+00000000111110110000000000111011
+11000000000010001010000000000011
+00111100000000101111100100000000
+10110010000000000000111110110000
+00001010001010011000000010001011
+00000000001111100000000000001011
+10110000000000101110111000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10010100000000001110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011110010010000000011
+11101100000000001111000100000000
+00111110000100000000111100110000
+00000011110010000000000011111011
+00000000001111100000000000001111
+10110000000000111110000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001111110000000000
+11111111000000000011111111000000
+00011111111100000000001100111100
+00000000111111110000000000111111
+11000000000011001110001000000011
+00111100000000001110100100010000
+00110001000000000000110010110000
+00000011001010000000000011001111
+00000000001111110010000000001100
+11110000000000111110010001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110110000000000
+10111011000000000010111011000000
+00001011101100000000001010101100
+00000000101110110000000000100110
+11000000000011011010110000000010
+00101100000000001101100100000000
+00100010001100000010100010110000
+00001010001010000000000010001011
+00000000001011000001000000001010
+10110000001000101110000001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000011000101100
+00000000101110110000000000100110
+11000000000010001010000000000010
+00001100000000001010100100000000
+00100010001000000000100010110000
+00000010101010000000000010001011
+00000000001011101101100000001000
+10110000000000101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010110011000000
+00001011001100000000001010001100
+00000000101100110000000000100100
+11000000000010010010000000000010
+00001100000000001001000100000000
+10100000000000000010100000110000
+00011010100010000000000010000011
+00000000001011000000000000000010
+00110000000000101100101000000100
+00000000000000000000000000000000
+00000000000000000000000000000000
+10000000000011010110110000000000
+10111011000000000011111011000000
+00001011011100000000001100101100
+00000000111110110000000000110111
+11000000000011001010000000001011
+00111100000000101110100100000000
+00110010000000000000110010110000
+00010011101010000000001011001011
+00000000001111101100000000001100
+10110000000000111110000000100010
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000110111
+11000000000011111110000000000011
+11111100000000001111110100000010
+00111111000000000000111111110000
+00000011011110000000000011111111
+00000000001111110000000000001111
+11110000000100111110100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111100000000000011001111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000110011111110100001000011
+00111110000000001111111110000000
+00111111111000000000110111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110111000000000
+10111000110000000010001011100000
+00001011101110000000001011101110
+00000000101110111000000000101110
+11100000100010111001100000000010
+00101110000000001011101110000000
+00101110111000000000101110111000
+00000010111011100000000010111011
+10000000001011101110000000001011
+10111000000000101111000000000110
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110000010000001010000011000000
+00001011001100000000001011001100
+00000000101000110000000000101100
+11000000000010111011000000000010
+00001100000010001011001100000000
+00101100110000000000100100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111000000110000010001011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011100000000010
+00101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000000011101100000000001011
+10110000000000101111000000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011110110000000000
+11111100110000000011001011000000
+00001111101100000000001111101100
+00000000111010110000000000111110
+11000000000011111010100000000011
+00101100000000001111101100000000
+00111110110000000000110110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101010000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11110000100000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111010011000001011001011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011001000000011
+10101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101010000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010111000000000
+10111000010000000110001011000000
+00001011101100000000001011101100
+00000000101110110000000000001110
+11000000000010110011000000000011
+01101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011100100000010000011000000
+00000011001100000000001011001100
+00000000101100110000000000001100
+11000000000010110010010000000010
+10001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111100000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10110111100000000010000111100000
+00001001011110000000001001011110
+00000001101101111000000000101101
+11100000000010110111100100000010
+01011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010010111
+10000000001011011110000000001011
+01111000000000101110110000000100
+00010000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110000100000
+11110011000000000010000011000000
+00001111001100000000001111001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+10001100010000001111001100000000
+00111100110000000000111100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101101000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000000000
+11111111000100000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011110111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111000000000000011001011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011110010000000000011
+00101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110110000000000010000111000000
+00001011011100000000001011011100
+00010000101101110000000000101101
+11000000000010110111000000000010
+10011100000000001011011100000000
+00111101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101111001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110010100000000010010111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+00011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110010011100000010000011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000100000010
+10001100000000001011001100000000
+00101000110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101001000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111110000000001011011010000001
+00001111101000000000001111101000
+00000000111110100000000000111110
+10000000000011110110100000000011
+00101000000000001111101000000000
+00101110100000000000111110100000
+00000011111010000000000011111010
+00000000001111101000000000001111
+10100000000000111111101000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000010000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011001001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000001011
+00100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010100000000
+10110001110000000010001001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000100000010
+00100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000001000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010100000000
+10111001001000000010001001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+00100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100111000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110011001000000010000001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110011000000000010
+00000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100101000000101
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000001011001000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+00100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111101000100000011111001000000
+00001111100100000000001111100100
+00000000101110010000000000111110
+01000000000011111101000000000011
+11100100000000001111100100000000
+01111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11111101100000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111101000001000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100011000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001011100000000000001011
+10000000000000101100111000000110
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001010000000010110001000000
+01001011000100000000011011000100
+00000001101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001010000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11111001000000000010111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001110100000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010110000100000
+11111001010000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000110011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000001000000011
+00100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010101110000000
+10111110101000000010111010000000
+00001011101000000001001011101000
+00000000101110100000000000101110
+10000000000010111110011000000011
+01101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100101000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100100100000000
+10110010000000000010110011000000
+00001011001100000000001011001100
+00000001101100110000000000101100
+11000000000010110011000000000010
+00001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001000000000000
+10110100000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111100000000010
+01011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101110000000000100
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001101000001000
+11110111100000000010110111100001
+10001111011110000000001111011110
+00000000111101111000000000111101
+11100000010011110111100000100011
+00011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111110001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010000110101000
+11111010000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011110011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001101101100000000001111
+10110000000000111100001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11100100100100000011101111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+10111110010000001111111110010000
+00111111111001000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111100000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001010100000000
+10000100000000000010000111000100
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000001000010110111000000000010
+10011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101110101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10100101000000000110100111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010111111010010000010
+00011100000001001011011100000001
+00101101110000000000001101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001100010000000000
+10000000100000000110000011000000
+00001011001100000000001011001100
+00000000101100110000000001101100
+11000000000010110011100000000010
+10001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010100000000000
+11100010000010000011101011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011110010010000000011
+10101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110101000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110100100000000
+11111000000000000011111011000000
+00001111101100000000001111101100
+00000100111110110000000000111110
+11000000000011111011010000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001011101100000000001111
+10110000000000111110000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111111000000000
+11111111000000100011101111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111101000000000011
+00111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000001001111
+11110000000100111100100001000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001010001000110111100000000
+10111011010000000010001011000001
+00001011101100000000001001101100
+00000000101110110000000000111010
+11000000000010111001100000000010
+10101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110100001000100
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010000001000000
+10111000010000000010101011000000
+00011011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011100010000010
+00101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000000000000000
+10111000000000000010100011000000
+00001011001100000000001001001100
+00000000101100110000000000101000
+11000000000010110011000000000010
+10001100000000001011001100000000
+00101100110000000000101100110000
+00000010010011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001000000101
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011010110010000000000
+11111001000000000011101011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+00101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100000000100011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000110011101010000000000
+11111101000000000011011111000000
+00001111111100000000001111111100
+00000000111111110000000000111011
+11000000000011110111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111110100100000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111111100000000011111111100000
+00001111111110000000001111111110
+00000000111111111000000000110111
+11100000000011001111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11001000000000111111000000000101
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110111000000000
+10111011100000000010111011100000
+00001011001100000000001011101110
+00000000101100110000000000100010
+11000000000011011011100000000010
+11101110000000001011101110000000
+00101110111000000000101110111000
+00000010111011100000000010111011
+10000000001011101110000000001011
+10101000000000101110000000000110
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110011000000000010110011000000
+00001011001100000000001010001100
+00000000101100110000000000100100
+11000000000010000011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00010000000000101110001000000001
+00110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000100010
+11000000000010011011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10000100010000101111000000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011110110000001000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000110110
+11000000000011001011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10000000000000111100000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+10111111000000000011111111000000
+00001101111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001101111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11100000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+00001101101100000000001110101100
+00000000111110110000000000111010
+11000000000011101011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110100000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001000101100
+00000000101110110000000000100010
+11000000000010001011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10100000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001010001100
+00000000101110110000000000101010
+11000000000010100011000000000010
+11001100000000001001001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00000000000000101111100000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10110111100000000010110111100000
+00001011011110000000001000011110
+00000000101101111000000000100001
+11100000000010000111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101101100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11110011000000000011110011000000
+00001111001100000000001110001100
+00000000111100110000000000111010
+11000000000011100011000000000011
+11001100000000001111001100000000
+00111100110000000000101100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00010000000000111101001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11010000000000111101000000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011000000000011111011000000
+00001111101110000000001101101100
+00000000111110111000000000110010
+11000000001011001011000000000011
+11101100000000001111101100000000
+00111110110000000000111010110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10001000000000110110101000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110111000000000010110111000000
+00001011111100000000001000011100
+00000000101101110000000000100011
+11000000000010000111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000010001011
+01110000000000100001001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110111100000000010110111100000
+00001011011110000000001001011110
+00000000101101111000000010100001
+11100000000010000111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+11111000000000100111000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001000001100
+00000000101100110000000000100000
+11000000000010000011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000100001001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011111010000000
+00001111101000000000001101101000
+00000000111110100000000000110010
+10000000000011001010000000000011
+11101000000000001111101000000000
+00111110100000000000111110100000
+00000011111010000000000011111010
+00000000001111101000000000001111
+11101000100000110111101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011001001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000001010001001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101100
+01000000000010001001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010000001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111100000000000000111110
+00000000000011001000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111001000000
+00001111100100101000001111100100
+00000000111110011010100000111110
+01101010000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+01010000000000111110011000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000110010
+01000000000011001001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000000101110000000000000101000
+00000000000010101000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001011100000000000001011
+10100000000000101100111000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000100000
+01000000000010000001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101100010000000000101010
+01000000000010101001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000001000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000110010
+01000000000011001001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110100000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000000000
+10111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10011010000000111100101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000110010
+00000000000011001000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111010000000000010111010000000
+00001001101000000000001001101000
+00000000101110100000000010100010
+10000000001010001010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100101000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000100010
+11000000000010000011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110111000000000010110111000000
+00001001011100100000001001011100
+00000000101101110001000000100001
+11000000000010000111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110111100000000011110111100000
+00001111011110000000001111011110
+00000000111111111010000000110001
+11100000000011000111100000000011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111100101000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00000101101100011000001001101100
+00000000111110110000100000111110
+11010100000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011011011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11111111100000000011111111100000
+00001111111110000000001100111110
+00000000111111111000000000111011
+11110000000011011111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001101111110000000001110
+01111000000000110001000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001101011100
+00000000101101110000000000110101
+11000000000010100111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000100000110110101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000000010110111000000
+00001011011100000000001000011100
+00000000101101110000000000101001
+11000000000010010111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010010111000000000010110111
+00000000001011011100000000001011
+11110000000000100000010010000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10110011000000000010110011000000
+00001011101100000000001001001100
+00000000101110110000000000100100
+11000000000010100011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000010001011
+00111100000000100101101000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010110000000000
+11111011000000000011111011000000
+00001111111100000000001100101100
+00000000111111110000000000111011
+11000000000011011011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001101101100000000001110
+10111101000000110010101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110010000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111111000000000011111111000000
+00001111111100000000001100111100
+00000000111111110000000000110011
+11000000000011001111000000000011
+11111100000000001110111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000000001
+11110000000000111110000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111011000000000010111011000000
+00001011101100000000001010101100
+00000000101110110000000000101010
+11000000000010101011000000000010
+11101100000000001001101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000000011101100000001001001
+10110000001000101110000001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001010101100
+00000000101110110000000000100000
+11000000000010001011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000001000010111011
+00000000001001101100000000001001
+10110000000000101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010110011000000
+00001011001100000000001010001100
+00000000101100110000000000101000
+11000000000010100011000000000010
+11001100000000001001001100000000
+00101100110000000000101100110000
+00000000110011000000000010110011
+00000000001011001100000000001001
+00110000000000101100001000000100
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111011000000000011111011000000
+00001111011100000000001100101100
+00000000111101110000000000110001
+11000000000011001011000000000011
+11101100000000001110101100000000
+00111110110000000000111110110000
+00000001111011000000000011111011
+00000000001111101100000000001101
+10110000000000111110000000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+00001111111100000000001011111100
+00000000111111110000001000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000011000001110100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11101111100000000011101111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+00111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110111000000000
+10111011100000000000111011100000
+00001011101110000000001011101110
+00000000101110111000000000101110
+11100000000010111011100000010010
+10101110000000001011101110000000
+00101110111000000000111010111000
+00000010111011100000000010111011
+10000000001011101110000000001011
+10111000000000101111000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110011000000000110100011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+00001100000010001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+10101100000000001011101100000000
+00101110110000000000100110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011110110000000000
+11101011000000000011101011000000
+00001111101100000000001011101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+00101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100010000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111011110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000100
+01000000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011011011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000100
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010110011110100000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000100100110000000000101100
+11000000000010110011000100000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00100000000000000001111000000000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100001000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101110110000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11110011000000000011110011000000
+00001111001100000000001111001100
+00000000110100110000000000111100
+11000000000011110011000000000011
+11001100010000001111001100000000
+00111100110000000000111100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101001000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111001011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000000
+11111100000100001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001011111100000000001111
+11110000000000111101000000000110
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000101100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101111001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10100111100000000010110111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101101000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11101010000000000010111010000000
+00001011101000000000001111101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000001001111101000000010
+00111110100000000000111110100000
+00000011111010000000000011111010
+00000000001111101000000000001111
+10100000000000101111101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001100000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000100000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000001000111111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111010000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000111
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000001
+11111001000000000111111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000001111110111000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11101001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111101000001000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001110
+10010000000000111000111000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001011100000000000001011
+10000000000000101100011000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10100001000000000010110001000000
+00001011000100000000001010000100
+00000000101100010000000000101100
+01000000000010110001000000100010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001010
+00010000000000101001001000000001
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000010000
+10111001000001000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000001000010
+11100100000000001011100100000100
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000010000101100011000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11101001000000000011111001000000
+00001011100100000000001110100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001110
+10010000000000111010100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000100111111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111101101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11101000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000111111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111010000000000010111010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010111110110100000010
+11101000000000001011101000000000
+00101110100000000000100110100000
+00000010111010000000000011101010
+00000000001011101000000000001011
+10100000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10100011000000000010110011000000
+00001011001100000000011011001100
+00000000101100110000000000101100
+11000000000010110011110000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000010000
+10110111000001000010110111000000
+00001011011100000000001011011100
+00000100101101110000000000101101
+11000000000010110110010000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010100111
+00000000001011011100000000001011
+01110000000000101100100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11100111100000000011110111100000
+00001111011110000000001111011110
+00000000111101111000000000111101
+11100000000010110101100000000011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111100101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000110110110000
+00000011111011000000000011101011
+00000000001111101100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000011111111000000000
+11111111100000010011111111100000
+01001111111110000010001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110001000000
+11110111000100000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111010000000010
+11011100000000001110011100000000
+00111001110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101110101000000010
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101001110000000000100101
+11000000000010100111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001010001100000000
+00101000110000000000100100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000110110
+11000000000011101000000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110101100000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11101011000000000011111011000000
+00001111101100000000001111101100
+00000100111110110000000000111110
+11000000000011111000000000000011
+11101100000010001111101100000000
+00111110110000000001111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110100000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111011110000000000111111
+11000000000011111101000000000011
+11111100000000001111111100000000
+00111111110000000001111111110000
+00100011111111000000000011111111
+00000000001111111100000001001111
+11110000000100111100000101000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+11101011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111001110000000010
+11101100000000001001101100000000
+00101110110000000001101110110000
+00000010111011000000000011101011
+00000000001011101100000000001011
+10110000000000101110000001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101010
+11000000000010111001100000000110
+11101100000000001011101100000001
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10100011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110001000000000110
+11001100000000001001001100000000
+00101100110000000000101100110000
+00000010110011000000000010100011
+00000000001011001100000000001011
+00110000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111010
+11000000000010111001000000000011
+11101100000000001111101100000000
+00111110110000000000101110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100000000100110
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111101000000000000
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000010001111111100000000001111
+11110000000000111110100000000011
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111111100000000011111111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11001000000000110011000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110111000000000
+10111011100000000010111011100000
+00001011101110000000001011101110
+00000000101110111000000000101110
+11100000000010111011100000000010
+11101110000000001011101110000000
+00101110111000000000101110111000
+00000010111011100000000010111011
+10000000001011101110000000001011
+10001000000000100011000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10100011000000000010110011000000
+00001011001100000000001010001100
+00000000101100110000000000101000
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010100011000000000010110011
+00000000001011001100000000001011
+10000000000000100011001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010111011000000
+00001011101100000001001011101100
+00000000101110110000000000100110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000010100011000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10100100100000110000000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011011111000000000011111111
+00000000001111111100000000001111
+11000000000000111111100000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000100111110110000001000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10100000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000001001011
+00110000000000101111011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011000000000010110011000000
+00001001001100000000001001001100
+00000000101100110000000000100100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010010011000000000010110011
+00000000001011001100000000001011
+00010000000000101111101000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01011000000000101111110000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11110011000000000011110011000000
+00001101001100000000001111001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110000000000111100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00000000000000111101101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000110
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000011011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111010110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000000011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01010000000000101111001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101001111000000000101001
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01101000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000001011011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011111010000000
+00001111101000000000001111101000
+00000000111010100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00111110100000000000111110100000
+00000011111010000000000011111010
+00000000001111101000000000001111
+11100000100000111111101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000110110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000011
+11100100000000001011100100000000
+00101110010000000000100110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010101001000000000010111001
+00000000001011100100000000011011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000100100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00100000000000000000000000000000
+00000000000000000000000000000000
+10111000000001010110000000000000
+11111000000000000010111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011101000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000111
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000101011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+10100100000000001111100100000000
+00111110010000000000110110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+11010000000000111110111000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+00010000000000111110111000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001011100000000000001011
+10000000000000101100011000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001000000000010100001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000011011
+10010000100000101100011000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010100001000111110100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10011010000000111101101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000100000000110000101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111010000000000010111010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000100000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000100100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000001001011
+00110000000000100100001000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+11111000000000100100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110111100000000011110111100000
+00001111011110000000001111011110
+00000000111101111000000000111101
+11100000000011110111100000000011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000110100101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000001
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000010001111
+10110000000010111000001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11111111100000000011111111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111101100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000100001011011100000000001011
+01110010000000101110101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100010010000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000011011
+00111100000000101101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10111000100000111110101000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000001001111101100000000001111
+10110000000000111110110000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000100000111110000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000001000010111011
+00000000001011101100000101001011
+10110000001000101110000101000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001001101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110000000100110
+00000000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000010100111110100000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11101111100000000011111111100000
+00001111111110010000001101110000
+10000000110011111000000000111011
+11100000000011111111000000000011
+00110010000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110111000000000
+11111011100000000011101011100000
+00001011101100000000001000101011
+00000000100010111000000000111010
+11100000000010111011110100000010
+00100000000000001011101110000000
+00101110111000000000101110111000
+00000010111011100000000010111011
+10000000001011101110000000001011
+10111000000000101110000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110011000000000010110011000000
+00001011001100000000101000000000
+01000100100000110000000001101100
+11000000000010110011000000000110
+00000100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101110001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010111011000000
+00001011001100000000001000100001
+00000000100010110000000000101110
+11000000000010111011000001000010
+00100110001000001011101100000000
+00101110110000000000101110111000
+10000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111000000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011110110000000000
+11101011000000000011111011000000
+00001111101100000000001101100110
+01000010110010110000000000111110
+11000000000011111011000000000011
+00100010000000001111101100000000
+00111110110000000000111110111000
+00100011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11101111000000000011101111000000
+00001111111100000000000111111000
+00000000111111110000000000111011
+11000000000011111111000001001011
+11110000000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+00001111101100000000001110001100
+00000000111110110000000000111110
+11000000000011111011000110000011
+11101101000000001100101100000000
+00111110110001000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000000010111011000000
+00001011101111110000001000101100
+00000000101110110000000000101110
+11000000000010110111000000000010
+11101100000000001010101100000000
+00101110111101000000101110010000
+00000010111011000000000010111011
+00000100001011101100000000001011
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001000000000
+00001000101100110000000000101100
+11000000000010110011110000000010
+11000000000000001000001100000000
+00101100111000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111000000000100
+00000000000000000000000000000000
+00000000000000000000000000000000
+00100000000000000001111000000000
+10110111100000000010110111100000
+00001011011110000100101000011110
+00000000101101111000000000100101
+11100000000010110111100000000010
+11010010000000001010011110000000
+00101101111000000000101101110001
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11110011000000000011110011000000
+00001111101100000001001110000000
+00000000111100110000000000111100
+11000000000011110011000000000011
+11100000000000001100001100000000
+00111100110000000000111100110000
+00000111110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101001000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111001011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111000
+00000000111111110000000000111111
+11000000000011111111000010000011
+11110100000000011111111100000000
+00111111110000000000111111110001
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000110
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011000000000011111011000000
+00001111101100000000101100100100
+00000000110010110000000000111110
+11000000000011111011100000000011
+00100000000000001111101100000000
+00111100111000000000110010110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000000011001110000000000
+10110111000000000010110111000000
+00001011111100000000001000011100
+00000000110101110000000001101101
+11000000000010110111001000000010
+00011000000000001011011100000000
+00101101110000000000110101100000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110111100000000010110111100000
+00001011011110000000001000000110
+00000000100001111000000000101001
+11100000000010110011101000000010
+00011010000000001011011110000000
+00101101111000000000100001111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00011011001100000000001000001110
+00000000100100110000000000101100
+11000000000010110011000001000010
+00101100000000001011001100000000
+00101100110000000000100100111101
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101101000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011111010000000
+00001111101000000000001100111011
+00000000110010100000000000111110
+10000000000011111010000000000011
+00111010100000001111101000000000
+00111110100000000000110011100101
+00000011111010000000010011111010
+00000100001111101000000000001111
+10100000000000111111101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+01100000111110000000000000111110
+00000000000011111000000000001011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001100000100
+00000000110010010000000000111110
+01000000000111111001100000000011
+11100110000000001100100100000000
+00111110010000000000111110010000
+00100011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001000000
+00001011100110010000101000100100
+00000000101010010000000000101110
+01000000000110111001010000000010
+11100110000000001000100100000000
+00101110010100000000101110010000
+00000010111001000000000011111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+00001011000100001000001000100100
+00000000100010010000000000101110
+01000000010010111001000101000010
+11100100010000001000100100000000
+01101110010000100000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001000000100
+10000000101000010000000000101100
+01000000000010110001001000000010
+11000100000000101000000100000000
+01101100010000000000100100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000001000110000000000000
+11111000000000000011111000000000
+00001111100001010000001100100000
+00000000110010000000010000111110
+00000000000010111010000000000011
+11100001010010001100100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000111
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111110100
+01000000111110010000000000111110
+01000000000011111001000101000011
+11110100000000001111100100000000
+00111110010000000000111111010000
+00000011111001000000000011101001
+00000000001111100100000000001111
+10010000000000111110111000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000000011110010000000000
+11111001000000000011111001000000
+00001111110100000000001111100100
+00000000110110010000000000111110
+01000000000011111101000000001011
+01110100000000001100100100000000
+00111111010000000000110010010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100111000000101
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000000010111000000000
+00001110000000000000001011100000
+00000000110110000000000000101110
+00000000000010111000000000000010
+00100010100000001101100000000000
+00101110000000000000110110000000
+00000011101000000000000010111000
+00000000001011100000000000001011
+10000000000000101100011000000010
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001000000000010100001000000
+00001011000100000000011011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+00001110001000001000000100000000
+00101100010000000000100000010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000001
+01100000000000000000000000000000
+00000000000000000000000000000000
+00011000000100011010010000000000
+10111001000000000010111001000000
+00001010100100000000001011100100
+00000000100110010000000000101110
+01000000000010111001000000000010
+00100100100000001001100100000100
+00101110010000000000100110010100
+00000010101001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11111001000000000011101001000000
+00001111100100000000001111100111
+00100000111110010000000000111110
+01000000000011111001000000000011
+01100100000000001100100100000000
+00111100010000000000110010010000
+00000011111001000000010011111001
+00000000001111100100000000001111
+10010000000000111110100000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11111001000000000011111001000000
+00001110100100000000001111100111
+00000000111010010000000000111110
+01000000000011111001000010000011
+11100100000000001111100100000000
+00111110010000000000111110010100
+00000001111001000000000011111001
+00000000001011100100000000001111
+10010000000000111101101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000000
+00001111100000100000001100000000
+00000000110110000000000000111110
+00000000000111111000000100000011
+11100000000000001100100000000000
+00111110000010000000111110000100
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111010000000000010111010000000
+00001011111011000000101000101000
+00000000111110100000000000111010
+10000000000010110110000000000010
+01101000000000101000101000000000
+00101111100110000000111110100000
+00000010111010000000000011101010
+00000000001011101000000000001011
+10100000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001110000000001001001100
+00000000100000110000000000101100
+11000000000010110011110000000010
+11101100000000001000001100000000
+00101100001000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110111000000000010110111000000
+00001011010110001000001001001100
+00000000101001110000000000100001
+11000000000010110111000000000110
+01011100000000001000011100000000
+00101101100000000000101001110000
+00000010110111000000000010100111
+00000000001011011100000000001011
+01110000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110111100000000011110111100000
+00001111011110000000001101011110
+00000100100001111000000000111101
+11100000000010110110100000000011
+11110110000000001100011110000000
+00111101001000000000101101111000
+00000011110111100000000011110111
+10000000011111011110000000001111
+01111000000000111100101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00001111101000000000001110101100
+00000000111110110000000000111010
+11000000000011111011000001000011
+11100100000000001111101100000000
+00111110100000000000111110110000
+00000011111011000000000011101011
+00000000001111101100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11111111100000000011111111100000
+00001111111110000000001100111110
+00000000111111111000000000111111
+11100000000011111110100000000011
+00111110000000001100111110000000
+00111111001000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111101100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000000000011110111000000
+00001011110000000000011000011100
+00000000101101110000000000101101
+11000000000010110110000000000011
+01011100000000001101011100000000
+00101101000000000000111001110001
+10000011110111000000000010110111
+00000000001011011100000000001011
+01110000000000101110101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000000010110111000000
+00001011010100000000001000011100
+00000000101101110000000000101101
+11000000000010110110000000000010
+00110100000000001001011100000000
+00101101010000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10110011000000000010100011000000
+00001011100000000000001000001111
+01001000101100110000000000101100
+11000000000010110010000000000010
+01100101001000001001001100000000
+00101100000000000000101100110000
+00000010100011000000010010110011
+00000000001011001100000000001011
+00110000000000101101000100000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010110000000000
+11111011000000000010111011000000
+00001111101000000000101100101100
+00001000111110110000000000111110
+11000000000011111001000000000011
+00101101000000001101101100000000
+00111110000000000000111110111000
+00000010111011000001000011111011
+00000000001111101100000000001111
+10110000000000111110101100000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011111011000000
+00001111101001000000001111101100
+10000100111110110000000000111110
+11000000000011111011000000000011
+11101110000000001111101100000000
+00111110000000000000111010110010
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110100000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111111000000000011111111000000
+00001111111111000000001110011100
+00000000110011110000000000111111
+11000000000011111110000000000011
+00110100000000001100111100000000
+00111111000000000000111111110000
+00000011001111000000000011111111
+00000000001111111100000000001111
+11110000000000111100000101000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111011000000000010111011000000
+00001011101000000000101000101100
+00000000100010110000000000101110
+11000000000010110011100000000011
+01110100000000001000101100000000
+00101110001000000000101100110000
+00000011111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011100101000000001000101100
+00000000100010110000000000101110
+11000000000010111010000100000010
+00100110000000001000101100000000
+00101110000001000000101110110000
+00000010001011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010110011000000
+00001001000000000000001000001100
+00000010100000110000000000101100
+11000000000010110010000000000010
+01000100000000001000001100000000
+00101100000000000000101110110000
+00000010010011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111011000000000010111011000000
+00001111100100000000001110101100
+00000000110010110000000000101110
+11000000000011111010000000000011
+00101100000000001100101100000000
+00111110010000000000111110110000
+00000011001011000000000011111011
+00000000001111101100000000001111
+10110000000000111100000000000110
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+00001111110000000000001111111100
+00000000111111110000000000111111
+11000000000011110110000000000011
+11011100000000001111111100000000
+00111111000000000100111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111110100000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111111100000000011111111100000
+00001111111110000000001110111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011001111
+10000000001111111110000000001111
+11111000000000111011000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110111000000000
+10111011100000000010111011100000
+00001011101110000000001100101110
+00000000101110111000000000101110
+11100000000010111011100000000010
+11101110000000001011101110000000
+00101110111000000000101110111000
+00000010111011100000000011011011
+10000000001011101110000000001110
+10111000000000101111000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10100011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00100100110000000000101100110000
+00000010110011000000000010000011
+00000000001011001100000000001011
+00110000000000101111001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010111011000000
+00001011101100000000001010101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010011011
+00000000001011101100000000001010
+10110000000000101111100000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000001011110110000000000
+11111011000000000011111011000000
+00001111001100000000001111101100
+00000000111110110000000000111110
+11000000000010111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011110011000000000011001011
+00000000001111101100000000001111
+10110000000000111100100000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000100011011110000000000
+11111111000000000011111111000000
+00001111111100000000001101111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000011111111100000000001111
+11110000000000111111100000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011101011000000
+00001111101100000000001100101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011101011000100000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001000101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101110001100001011
+10110000000000101111000000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11000000000001000000110000000000
+10110011000000000010100011000000
+00001011001110010000001001001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+10001100000000001011001100000000
+00101100110000000000101100110000
+00000010100011110010000010110011
+00000000001011001111001000001011
+00110000000000101111000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00100000000000000001111000000000
+10110111100000000010110111100000
+00001011011100000000001001011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000011011
+01111000000000001111111000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000110000000110000000000
+11110011000000000011100011000000
+00001111001100010000001101001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110000000000111100110000
+00000011100011000000000011110011
+00000000001111001100010000001111
+00110000000000111101101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111001011110000000000
+11111111000000000011111111000000
+00001111011100100000001110111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000100011111
+11110000000000111101000000000010
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000101011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111010110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100101000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000010011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101111001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00100000000000001001111000000000
+10110111100000000010110111100000
+00001011011110000000011011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101001111000000000101101111000
+00000010110111100000000110110111
+10000000001011011110000000001011
+01111000000000101100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+11101000000001001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000001011011001100000000001011
+00110000000000101101001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101001010100000000000
+11111010000000000011111010000000
+00001111101000000000001111101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00111010100000000000111110100000
+00000011110010000000000011111010
+00000000001111101000000000001111
+10100000000000111111101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10001000000100001010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011011001
+00000000001111100100010000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000010010000000000
+10111001000000000010111001000000
+00001011100100100000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001001000000010001001
+00000000001011100110000000001011
+10010000000000101110000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010101001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010011001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010000001
+00000000001011001100000000001011
+00010000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000111010110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011101000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011011000
+00000000001111100000000000001111
+10000000000000111110111000000111
+01010000000000000000000000000000
+00000000000000000000000000000000
+10111000000111011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110111100000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000101011110010000000000
+11111001000000000011111001000000
+00001111110100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111101000000000011111001
+00000000001111110100000000001111
+10010000000100111110111000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000000001010000000000000
+10111000000000000011101000000000
+00001011100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001011100000000000001011
+10000000000000101100011000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+01001000000001001000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101000010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101001010010000000000
+10111001000000000010101001000000
+10001011101100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000001001011100100000000001011
+10010000000000101100011000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111010010000000000111110010000
+00000011111001000000000011111001
+00000000011111100100000000001111
+10010000000000111110000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01101000000000001010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100001000001111
+10010000000000111101101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011101000000000
+00001111100000001000001110100000
+00000000111110000000000000111110
+00000000000011101000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000010000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000010100000000000
+10111010000000000010111010000000
+00001011111010000000001011101000
+00000000101110100000000000101110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000010111110000000000010111010
+00000000001011111001000000000011
+10100000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001010100110000000000
+10110011000000000010100011000000
+00001011001100000000001010001100
+00000000101100110000000000101100
+11000000000010100011000000000010
+10001100000000001011001100000000
+00101000110000000000101100110000
+00000010110011100000000010110011
+00000000001011001110000000001011
+00110000000000101100001000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001110000000000
+10110111000000000010110111000000
+00001011011100001000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111010000000110110111
+00000000001011010101000000001011
+01110000000000101100000000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000110000001111000000000
+11110111100000000011100111100000
+00001111011110000000001110011110
+00000000111101111000000000111101
+11100000000011100111100000000011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000010001111
+01111000001000111100101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111010000000000011111011
+00000000001111100000000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+01100000000001001011111000000000
+11111111100000000011111111100000
+00001111111010010000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111110100100000011111111
+10000000001111111010000000001100
+11111000000000111101000000000001
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000000001001110000000000
+10110111000000000010110111000000
+00001011010000000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110101000000000011100111
+00000000001011011100000000001101
+01110000000000101110101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000000010110111000000
+00001011011000000000011011011100
+00000000101001110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110110000000000110110111
+00000000001011010000000000001000
+01110000000000101100010000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01000000000101001000110000000000
+10110011000000000010110011000000
+00001011000000000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000110110000000000000010100011
+00000000001011000000000000011001
+00110000000000101101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011010110000000000
+11111011000000000011111011000000
+00001111100100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111001000000000011111011
+00000000001111001100000000001100
+10110000000000111110101000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10100000000100001110110000000000
+11111011000000000011111011000000
+00001111100100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000111101011
+00000010001111100100000000001111
+10110000000000111110110000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111111000000000011111111000000
+00001111110000000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111101100000000011111111
+00000000001111111100000000101100
+11110000000000111110000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111011000000000010111011000000
+00001011100011000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111010100000000010111011
+00000000001011100000000000001000
+10110000000000101110010001100000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010110110000000000
+10111011000000000010111011000000
+00001011101100010000001011101100
+00000000101110110000000000101110
+11000000000010101011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111000000100000010111011
+00000000001011101000000001001000
+10110000000100101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010110011000000
+00001011000100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110001000000000010110011
+00000000001011001100000000001000
+00110000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000110000110110000000000
+11111011000000000011111011000000
+00001111101000000000001111101100
+00000000111110110000000000111110
+11000000000011101011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111000000000000011111011
+00000000001111100000000000001100
+10110000000000101110100000000110
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011011110000000000
+11111111000000000011111111000000
+00001111110000000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111100000000000011111111
+00000000001111010000000000001111
+11110000000000111110000000100110
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111111100000000011111111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111110100000000011
+10111100000000101100110110000000
+00110011111000000000111111111000
+00000011001111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110111000000000
+10111011100000000010111011100000
+00001011101110000100001011101110
+00011000101110111000001000101110
+11100000000010111010100000000010
+00111110000000101000100100000000
+00100010111000010000101110111000
+00000011011011100000000010111011
+10000000001011101110000000001011
+10111000000000101110000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010111010000000000010
+10000100000000001010001100000000
+00100000110000000000101100110000
+00000010000011000000000010110011
+00000000001011001100000000001011
+00110000000000101110001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111010100010010010
+00100100000000001000100100000000
+00100010110000000000101110110000
+00000010011011000000000010111011
+00000000001011101100000000001011
+10110000000000101111000000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000100111110110000000000111110
+11000000010011111010110000000011
+10111100000000101110100100000000
+00110010110000000000111100110000
+00100011001011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000100111
+11000000000011111110000000000011
+11101100011000101111111100000000
+10111111110000000000111111110000
+00010011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111010010000000011
+11000100000000001100101100000000
+00111110110000000000110110110010
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000100001011101100
+00000000101110110000000000101110
+11000000000010110010000000000010
+11100101001000101000101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111001000000100
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011000000000010110011000000
+00001001001100000000001011001100
+00000000101100110000000000100100
+11000000000010110000100100000010
+11000100000000101000100100000000
+00101100110000000000100100110100
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111100000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10110111100000000010110111100000
+00001001011110000000001011011110
+00000100101101111000000000101101
+11100000000010110100100000000010
+11010110010000001000010110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000000011011110000000001011
+01111000000000101100100000000100
+00010000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11110011000000000011110011000000
+00001101001100000000001111001100
+00000000111100110000000000111100
+11000000000011110010000000000011
+11001100000000001100001100000000
+00111100110000000000110100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101101000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111100000100000011
+11111111000000001111110100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111001000000000011
+11100101000000001110100100000000
+00111110110000000000111100111000
+00000011001011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000001001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11010100000000001000011100000000
+00101101110000000000101101110000
+00000011010111000000000010110111
+00000000001011011100000000001011
+01110000000000101101001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001010011111000000
+00101101111000000000101101111000
+00000010000111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000111010010
+11001100000000001000001110000000
+00101100110000000000101100110000
+00000010010011000000000010110011
+00000000001011001100000000001011
+00110000000000101101001000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011111010000000
+00001111101000000000001111101000
+00000000111110100000000000111110
+10000000000011110110100000000011
+11101000000000001110101000000001
+00111110100000010000111110100000
+00000011001010000000000011111010
+00000000001111101000000000001111
+10100000000000111111101100000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000100
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001110001000011
+00100100000000001100100100000000
+00111110010000000000111110011001
+00000000111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001100000001010
+00000100000000001000100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+00100110001000101000100100000001
+00101110010000010000101110010000
+10000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100111000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010010001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+00000100100000001000000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100101000000101
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+00100000000000101100100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000010011111101000001000011
+11010100010000101111110100101000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001101100100000000001111
+10010000000000111110011000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111101000000000011
+10110110000000101100100100000000
+00110010010000000000111111010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100011000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+00100000000000001000100010100000
+00110110000000010000101110000000
+00000000111000000000000010111000
+00000000001011100000000000001011
+10000000000000101100111000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101000010000000000101100
+01000000000010111001000000000010
+10000101000000001000100100001000
+00100000010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001001000000010
+00100100100000001000100100000100
+00100110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11111001000000000011111001000000
+00001111100100000000001011100100
+00000000111010010000000000111110
+01000000000011111001100000000011
+10000100000000001100000110000000
+00110010010000000000111110010000
+01000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001100000000011
+11100110001000101111100100100000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+00100000000001001100100000000100
+00111110000000000000111110000001
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100001000000100
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111010000000000010111010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010110010100000000011
+01111001000001001010101000000000
+00101110100000000000101111101100
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100101000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110001000000000010
+00001000000000001000001100000000
+00101100110000000000101100101100
+10000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101100000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110111000000000010110111000000
+00001011011100000000001001011100
+00000000101101110000000000101101
+11000000000010111101010000000010
+01011001000000001010011100000000
+00101101110000000000101101100000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101110000000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110111100000000010110111100000
+00001111011110000000001111011110
+00000000111101111000000000111101
+11100000000011110101100000000011
+00011110000000001100011110000000
+00111101111000000000111101011000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111110001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00001111101100000100001111101100
+00000000111110110000000000111110
+11000000000011110001000000000011
+11000000000000001111101100000000
+00111110110000000000111110000000
+00000011111011000000000011111011
+00000000001101101100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11111111100000000011101111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111101100000000011
+10111010000000001100111110000000
+00111111111000000000111111001000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111100000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000000000011100111000000
+00001011011100000000001111011100
+00000000101101110000000000111101
+11000000000010110101000000000010
+00011000010000001000011100000000
+00101101110000000000101101000000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101110101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010111111000000000010
+10010100000000001000011100001000
+00101101110000000000101101000000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001010001100
+00000000101100110000000000101000
+11000000000010110011100000000010
+00000000000000101000001110000000
+00101100110000000000101100000000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010110000000000
+11111011000000000011111011000000
+00001111101100000000001011101100
+00000000111110110000000000101110
+11000000000011111011100010000011
+10000000000000101100111110000000
+00111110110000000000111110000000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110101000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011101011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111001000000100011
+01100000000000001111101100000000
+00111110110000000000111110000000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11100100000000001100111100000000
+00111111110000000000111111011000
+00000011111111000000000011111111
+00000000001101111100000000001111
+11110000000000111100100001000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111011000000000010111011000000
+00001011101100000100001011101100
+00000000101110110000001000101110
+11000000000010111001100000010010
+11100010000000101000111100000000
+00101110110000000000101110001001
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110100001000100
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000100000010
+11100010001000001000101100000000
+00101110110000000000101110000000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010110011000000
+00001011001100000000001001001100
+00000000101100110000000000100100
+11000000000010010001000000000010
+11000000000000001000001100000000
+00101100110000000000101100000000
+00000010010011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001000000101
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000010011111011000000000011
+11100000000010001100101100000000
+00111110110000000000111110000000
+00000011111011000000000011111011
+00000000001101101100000000001111
+10110000000000111100000000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000001111110000000001111111
+11000000000011110111000000000011
+11110000000000001111111100000000
+00111111110000000000111111000000
+00000011111111000000000011111111
+00000000001111111100000000001101
+11110000000000111110100000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111111100000000011111111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111100
+10000000001111111110000000001111
+11111000000000111111000000000001
+01100000000000000000000000000000
+00000000000000000000000000000000
+10100000000100001110111000000000
+10111011100000000010111011100000
+00001011101110000000001011101110
+00000000101110111000000000101110
+11100000000010111011100000000010
+11101110000000001011101110000000
+00101110111000000000101110111000
+00000010111011100000000010111001
+10000000001011101110000000001011
+10111000000000101110100000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010100011000000000010110010
+00000000001011001100000000001011
+00110000000000101110001000000001
+00110000000000000000000000000000
+00000000000000000000000000000000
+11100000000101011010110000000000
+10111011000000000010111011000000
+00001011101100000100001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111100000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000100011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111000
+10000000001111101100000000001111
+10110000000000111100000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000001111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111100
+10010000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111001
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001110101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111001
+00000000001011101100000000001011
+10110000010000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000001
+10110011000000000010110011000000
+00001001001100000000001001001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010010000
+00000000001011001100000000001011
+00110000000000101111100000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001111000000100
+10110111100000000010110111100000
+00001011011110000000001010011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110101
+10000000001011011110000000001011
+01111000000000101101100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11110011000000000011110011000000
+00001111001100000000001111001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110000000000101100110000
+00000011110011000000000011110010
+00100000001111001100010000001111
+00110000000000111101001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000011011011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000010
+01100000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111010110000
+00000011111011000000000011111010
+00000000001111101100000000001111
+10110000000000111110001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110110
+00000000001011011100000000001011
+01110000000000101101001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000010001101111000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+11000000001011001100000000001011
+00110000000000101101001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011111010000000
+00001111101000000000001111101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00111110100000000000111110100000
+00000011111010000000000011111110
+11011000001111101000000000001111
+10100000000000111111101100000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000100011111101
+00000000001111100100000000001111
+10010000000000111110011000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001011100000000000001011
+10000000000000101100111000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00001100001011100100000000001011
+10010000000000101100011000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101001010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+11000000001111100100000000001111
+10010000000000111110100000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000000001010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00100000001111100100000000001111
+10010000000000111100101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001000010100000000000
+10111010000000000010111010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100101000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000010001011
+01110000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000010000001111000000000
+11110111100000000011110111100000
+00001111011110000000001111011110
+00000000111101111000000000111101
+11100000000011110111100000000011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111100101000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000001011111111000000000
+11111111100000000011111111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011110111
+10000000001100111110000000001111
+11111000000100111101000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001101011100000000001011
+01110000000000101110101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010111111
+00000000001010011100000000001011
+01110000000000101100010000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01100000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00001000001011001100000000001011
+00110000000000101101100000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001110101100000000001111
+10110000000000111110101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001001101100000000000111
+10110000000000111110010000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001100111100000001001111
+11110000010100111110000001100100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010110011
+00000000001000101100000000001011
+10110000000000101110000101000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010110110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001000101100000001001011
+10110000010000101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000000110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010111011
+00000000001000001100000000001011
+00110000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000010000110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001100101100000000001111
+10110000000000111110000000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000101111111100000000001111
+11110000000000111110100000000010
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000000011111111000000000
+11111111100000000011111111100000
+00001111110110000001001101111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110111000000000
+10111011100000000010111011100000
+00001011100110000000001000001100
+00100000101110111000000000101110
+11100000000010111011100000000010
+11101110000001001011101110000000
+00101110111000000000101110111000
+00000010111011100000000010111011
+10000000001011101110000000001011
+10111000000000101110000000000010
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110011000000000010100011000000
+00001010001100000000001001001100
+10000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000001
+00101100110000000001101100110000
+00000010110011000000000010110011
+00000000001011001100000000001010
+00110000000000101010001000000001
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010111011000000
+00001011101100001000001000101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111000000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011110110000000000
+11111011000000000011111011000000
+00001111101111000000001101101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000011111111000000
+10001111111110100000001110111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00010011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+00001111101110100010101100101100
+00100010110010110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000000010111011000000
+00001011001110000000001000101111
+00000000100010110000000000111110
+11000000000010111011000000000010
+11101100000010001011101100000000
+00101110110000000000101110110000
+00000011111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011000000000010110011000000
+00001011000001000000001000001101
+00000000100000110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10110111100000000010110111100000
+00001011011010000000001000011110
+00100000100001111000000000101001
+11100000000010110111100000000010
+11011110000000011011011110000000
+00101101111000000000101101111000
+00000010100111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000000000000110000000000
+11110011000000000011110011000000
+00001111000100000000001100001100
+00000000110000110000010001101100
+11000000000011110011000000000011
+11001100010000001111001100000000
+00111100110000000000111100110000
+00000010110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101001000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000000000
+11111111000000000011111111000000
+00001111011000000000001111111100
+01000000111111110000000000111111
+11000000000011111111000000000011
+11111100000100001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011000000000011111011000000
+00001111001010000000001100001100
+00000000110010110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001101011100
+00000000101001110000000000111001
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110111100000000010110111100000
+00001010011110000010001000011110
+00000000100001111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001011001100100000101001001100
+00000000000000110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000100100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101101000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011111010000000
+00001111111000001000001100101000
+00000010110010100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00111110100000000000111110100000
+00000011111010000000000011111010
+00000000001111101000000000001111
+10100000000000111111101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+10001111100001000000001111100000
+00000000111110000000000000111010
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100111
+00000000110010010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010011001000000
+00001011100111001000001011100111
+00000000100010010000000000101110
+01000000000010111001000001000010
+11100100000000001011100100000000
+00101110010000000000100110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010011001000000
+00001011100110000000001011000101
+00000000100010010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010010001000000
+00001011000100000000001011000100
+00000010101000010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00100000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000000011011000000000
+00001111100000000000001111100001
+01000000110010000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000111
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011011001000000
+00001111110100000000001111100100
+00000000110110010000000000111110
+01000000000011111001000000000010
+11100100000000001111100100000000
+00111110010000000000110110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110111100000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11101001000000000011111001000000
+00001111110100000000001111110100
+00000000110010010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100111000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000010100010000000000000101110
+00000000000011111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001110100000000000001011
+10000000000000101100011000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10100001000000000010110001000000
+00001011000100000000001011000100
+00000000100100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000001
+01100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000000000010111001000000
+00001011100100100000001011000100
+00000000100110010000000000101110
+01000000000010101001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001010100100000000001011
+10010000000000101100011000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11101001000000000011111001000000
+00001111100101100000001111100100
+00000010110110010000000000111110
+01000000000010111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111010010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001110100100000000001111
+10010000000000111101101100000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000000
+00001111100001000000001111100000
+10000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000100
+00011110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111010000000000010111010000000
+00001011111010001000001011111010
+10000000101110100000000000101110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001101100000001011001110
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110111000000000010110111000000
+00001011010100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110111100000000011110111100000
+00001111010110000000001111011110
+00000000111101111000000000111101
+11100000000011110111100000000011
+11011110000000001111011110000000
+00111101111000000000101101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111100001000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00001111100100000000001111101000
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000101011111111000000000
+11111111100000000011111111100000
+00001111011110000000001100110110
+00000000110011111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111101100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000000000010110111000000
+00001011011101000000001101011100
+00000000100001110000000000111101
+11000000000011110111000000000010
+11011100000000001011011100000000
+00111101110000000000111001110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101110101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000000010110111000000
+00001010011000000000001001011000
+00000000100001110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001010
+01110000000000101100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10110011000000000010110011000000
+00001011001000010000101000001000
+00000000100000110000000000001000
+11000000000000100011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011010110000000000
+10111011000000000011111011000000
+00001111000100000000001001101000
+00000010110010110000000000101110
+11000000000010111011000000000011
+11101100000000001111101100000000
+00111110110000000000101110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011111011000000
+10001111100101100000001111101100
+00000000111110110000000000111110
+11000000000111111011000000000011
+11101100000001001111101100000000
+00111010110000000000111010110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000000001111110000000000
+11101111000000000011111111000000
+00001111110100000000001100110010
+00000000111111110000000000111111
+11000000000011111111000001000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111100000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111011000000000010111011000000
+00001011100011000000001010101001
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000100001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011100110000000001000100101
+01000000101010110000000000101110
+11000000000010111011000000000110
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110100000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010110011000000
+00001011000100000000101000001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111011000000000011111011000000
+00001111100000000000001100000000
+00000000111010110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100000000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+00001111110000000000001110111000
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000001111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111110100000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000011011111111000000000
+11111111100000100011111111100000
+00001101111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000001
+01100000000000000000000000000000
+00000000000000000000000000000000
+11100000000000001110111000000000
+10111011100000000010111011100000
+00001011101110000000001011101110
+00000000101110111000000000101110
+11100000000010111011100000000010
+11101110000000001011101110000000
+00101110111000000000101110111000
+00000010111011100000000010111011
+10000010001011101110000000001011
+10111000000000101111000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+11001000000001011100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001001001100000000
+00101100110000000000101100110000
+00000010100011000000000010110011
+00000000001011001100000000001011
+00110000000000101111001000000001
+00110000000000000000000000000000
+00000000000000000000000000000000
+11100000000101011010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000101011110110000000000
+11111011000000000011111011000000
+00001101101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000100001111
+10110000000000111100000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000010000
+11111111000000000011111111000000
+00000111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000001000111111100000000100
+01000000000000000000000000000000
+00000000000000000000000000000000
+01010100000100001010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000110110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000001000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010010011000000000010110011
+00000000001011001100000000001001
+00110000000000101111000100000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+10110000000000010001111000000000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101111111000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000000000000110000000000
+11110011000000000011110011000000
+00001111001100000000001111001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110000000000101100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101001100000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000010
+00100000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111010110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11001000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000011110111000000000011110111
+00000000001011011100000000001111
+01110000000000111111001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001001111000000000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101001111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010100011000000000010100011
+00000000001011001100000000001010
+00110000000000101001101000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011111010000000
+00001111101000000000001111101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00111110100000000000111110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101111101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000110110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000000011
+10010000000000101110000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+00001001100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00100000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000111
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000011111100100000000001111
+10010000000000111110111000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000011011110010000000000
+11111001000000000011111001000000
+00001111100100000000001110100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011101001000000000111111001
+00000000001111100100000000001111
+10010000000000111110111000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000000001110000000000000
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000000111010000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001011100000000000001111
+10000000000000111100011000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+01001000000001011100010000000000
+10110001000000000010110001000000
+00001011000100000000001010000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010100001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101010010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001010
+10010000000000101000011000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101001010010000000000
+11111001000000000011111001000000
+00001111100100000000001110100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011101001000000000010111001
+00000000001111100100000000001011
+10010000000000101110100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01101000000000001010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111010010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111101101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000010001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001000010100000000000
+10111010000000000010111010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010111010000000000011
+10101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001100000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+10011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000100101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000000000001111000000000
+11110111100000000010110111100000
+00001111011110000000001111011110
+00000000111101111000000000111101
+11100000000011110111100000000011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111100101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000101011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+10101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000001011111111000000000
+11111111100000000011111111100000
+00001110111110000000001111111110
+00000000111011111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111101100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001111
+01110000000000101110101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000000010110111000000
+00001010011100000000001011011100
+00000000101001110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101001110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100010000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01100000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001010
+00110000000000101101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010110000000000
+11111011000000000011111011000000
+00001110101100000000001011101100
+00000000111010110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111010110000
+00000010111011000000000011111011
+00000000001111101100000000001011
+10110000000000111110101000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000010000111110110000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001101
+11110000000000111110000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000111110
+11000000000010111011000000000011
+10101100000000001011101100000000
+00101110110000000000101110110000
+00000011111011000000000010111011
+00000000001011101100000000001011
+10110000010000101110000001100000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010110110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000000110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101000
+11000000000010110011000000000010
+10001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000010000110110000000000
+11111011000000000010111011000000
+00001111101100000000001111101100
+00000000111110110000000000101110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001101
+10110000000000111110000000000110
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000110011111110000000000
+11111111000000000011111111000000
+00001111111100000000011111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011101111000000000011111111
+00000000001111111100000000001111
+11110000001000111110100000100010
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000000011111111000000000
+11111111100000000011111111100000
+00001101111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111100000000001011111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110111000000000
+10111011100000000010111011100000
+00001011101110000000001011101110
+00000000101110111000000000101110
+11100000000010111011100000000010
+11111110000000001011101110000000
+00101110111000000000101110111000
+00000010011011100000000010111011
+10000000001011101110000000001011
+10111000000000101110000000000110
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110011000000000010110011000001
+00001011001100000100001011001100
+00000000101100110000000000001000
+11000000000010110011000000000010
+11001100000000001001001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001010
+00110000000000101010001000000001
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11111100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111000000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111010
+11000000000011111011000000000010
+11101100000000001111101100000000
+00111110110000011000111110110000
+00000001111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011011111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+00011111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100001000001111101100000000
+00111110110000000000111110110000
+00000111111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000100010111011000001
+10001011101100000000001011101100
+00001000101110110000000000111110
+11000000000010111011000000000010
+11101111000000001110101100000000
+00101110110000000000101110110000
+00000011111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001101010000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001111000000000
+10110111100000000010110111100000
+10011011011110000010001011011110
+00000000101101111000000000101001
+11100000000010110111100000000010
+11011110000000001010011110000000
+00101101111000000000101101111000
+00000010100111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000100
+00010000000000000000000000000000
+00000000000000000000000000000000
+01001000000000000000110000000000
+11110011000000000011110011000000
+00001011001100000000001111001100
+00000000111100110000000000101100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110000000000111100110000
+00000010110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101001000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000000000
+11111111000000000011111111000000
+00001111111100000010001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111110000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011000000000011111011000000
+00001110101100000001001111101100
+00000000011110110000000000111110
+11000000000011111011000000000011
+11001100010000001100101100000000
+00111110110000000000101110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110111000000000010110111000000
+00000011011100000000001011011100
+00000001101101110000000000111001
+11000000000010010111000000000010
+11011100100000001010011100000000
+00101101110000000000001101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101101001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110111100000000010110111100000
+00001011011110000000001010011110
+00000001101001111000000000101101
+11100000000010110111100000000010
+11011110000000001000011110000000
+00101101111000000000101101111000
+00100010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000100001011001100
+00000000101100110000000000101100
+11000000000010010011000000000010
+11001100000000001010001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101101000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011111010000000
+00001111101000000000001111101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001100101000000000
+00111110100000000000111110100000
+00000011111010000000000011111010
+00000000001111101000000000001111
+10100000000000111111101000000100
+01010000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000001001111100000
+00000100111110000000000000111010
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001100100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000111010010000000000101110
+01000000000010111001000000010010
+11010101000000001000100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000000010010010000000000
+10111001000000000010111001000000
+00011011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001000100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100111000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000110110001000000
+00001011000100000000001011000100
+00000000101000010000000000101100
+01000000000010110001000000000010
+11000100001000101000000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100101000000101
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011000010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11101010100000001100100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000011011110010000000000
+11111001000000000011111001000000
+00001111100100000000001011100100
+00000000111010010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000101110010000000000111110
+01000000000011111001000000000011
+11110110000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100011000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000110111000000000000010111000
+00000000001011100000000000001011
+10000000000000101100111000000110
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000100101100010000000001101100
+01000000000010110001000000000010
+11000101000000001011000100000000
+00101100010000000000101100010000
+00000000110001000000000010110001
+00000000001011000100000000001010
+00010000000000101101001000000001
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000100011010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000011011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000001000
+11111001000000000011111001000000
+00001111100100000000001011100100
+00000001101110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000010111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00101000010000011010010000000000
+11111001000000000011111001000000
+00001111100100000010001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000100000001011100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111010000000000010111010000000
+00001011101000000001001011101000
+00000000111010100000000000101110
+10000000000010111010000000000010
+11111000000000001011101000000000
+00101110100000001000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100101000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000001100110000000000001100
+11000000000010110011000000000010
+11000100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11010101000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101110000000000100
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110111100000000011110111100000
+00001111011110000000001111011110
+00000000111101111000000001111101
+11100000010011110111100000100011
+11010110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111110001000000010
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000011011010110000001000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111010110000000000111110
+11000000000011111011000000000011
+11100100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001011
+10110000000000111100001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11111111100100000011111111100100
+00001011111110010000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11110110000000001100111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000100001011011100
+01010000101101110000000000101101
+11000000000010110111000000000010
+11010101000000001010011100000000
+00101101110000000000101101110000
+00000001100111000000000010110111
+00000000001011011100000000001011
+01110000000000101110001000000110
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001001110000000000
+10110111000000010010110111000000
+00000010011100000010001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11000100000000001001011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101000000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000100101100110000001000101100
+11000000000010110011000000000010
+11000100000000001011001100000000
+00101100110000000000101100110000
+00000000100011000000000010110011
+00000000001011001100000000000011
+00110000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010110000000000
+11111011000000000011111011000000
+00001111101100000000001011101100
+00000000111110110000000000001110
+11000000000011111011000000000011
+11000100000000001101101100000000
+00111110110000000000101110110000
+00000010111011000000000011111011
+00000000001111101100000000001011
+10110000000000111110101100000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000100111110
+11000000010011111011000000000011
+11101100000000001110101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11110100100000001101111100000000
+00111111110000000001111111110000
+00000011101111000000000011111111
+00000000001111111100000000001111
+11110000000000111100100001000100
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000111110
+11000000000010111011000000000010
+11101110000000001000101100000000
+00101110110000000000101110110000
+00000011101011000000000010111011
+00000000001011101100000000001011
+10110000000000101110100001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010101011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101000000000001001101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000000
+10110011000000000010110011000000
+00011011001100000000001011001100
+00000001101100110000000000101000
+11000000000010110011000000000010
+11001100000000001000001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000011011
+00110000000000101100001000000100
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000011010110110000000000
+11111011000000000011101011000000
+00001111101100000000001111101100
+00000000111110110000000000101110
+11000000000011111011000000000011
+11101100000000001101101100000000
+00111110110000000000101110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100000000000011
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000110011111110000000000
+11111111000000000011111111000000
+00001111111100000000011111111100
+00000000111111110000000001111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000001111111110000
+00000011101111000000000011111111
+00000000001111111100000000011111
+11110000000000111110100000000101
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11101111100000000011111111100001
+10001111111110000000001101111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110111000000000
+10111011100000000011101011100000
+00001011101110000000001011101110
+00000000101110111000000000101110
+11100000000010111011100000000010
+11101110000000001011101110000000
+00101110111000000000101110111000
+00000011111011100000000010111011
+10000000001111101110000000001111
+10111000010000101110000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10100011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00100100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101110001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010101011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010101011000000000000111011
+00000000001010101100000000001010
+10110000000001101111000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000101011110110000000000
+11101011000000000011111011000000
+00001111101100000000001101101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000010111011000000000011111011
+00000000001011101100000000001011
+10110000000000111100000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000011111111000000
+00001111111100000000000111111100
+00000000111111110000000000111111
+11000000000001111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000010000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000010001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111100100000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+01100000000000010001111000000000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101101100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11110011000000000011110011000000
+00001111001100000000001111001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110000000000111100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000000000
+11111111000000000011111111000000
+00001111111100000000011111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000010
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011000000000011111011000000
+00001110101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000001111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110101000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001111011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001110011100000000001111
+01110000000000111101001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10110111100000000010110111100000
+00001010011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+01000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101111000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001010001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000100100110000
+00000010110011000000000010110011
+00000000001010001100000000001010
+00110000000000101001001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111010000000000011111010000000
+00001110101000000000001011101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00111110100000000000111110100000
+00000011111010000000000011111010
+00000000001111101000000000001011
+10100000000000101111101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001110100000000001001111
+10000000000000111101001000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000000111001000000
+00001011100100000000001011100100
+00000000100110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00100000000000000000000000000000
+00000000000000000000000000000000
+10111000000011000110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000110110010000000000111110
+01000000000011111001000000000010
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+10011000000001011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+11111000000000000011101000000000
+00001011100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000001110000000
+00000010111000000000000011111000
+00000000001011100000000000001111
+10000000000000101100111000000100
+00010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10101001000000000010101001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010101001
+00000000001011100100000000001010
+10010000000000101100011000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+10111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000010111001
+00000000001111100100000000001011
+10010000000000111110100000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111010000000000010111010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100101000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000010000
+11110111100000000011110111100000
+00001111011110000000001111011110
+00000000111101111000000000111101
+11100000000011110111100000000011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111100101000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000111111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000001000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000001011111111000000000
+11111111100000000011111111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111101000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110001000000
+10110111000000000010110111000000
+00001011011100000000001110011100
+00000000101101110000000001101101
+11000000000011100111000000000010
+11011100000000011011011100000000
+00101101110000000000101101110000
+00000011110111000000000011110111
+00000000001011011100000000001110
+01110000000000111110101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00010000000000001001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100010000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01100000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001010001100
+00000000101100110000000000101100
+11000000000010100011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010100011000000000010100011
+00000000001011001100000000001010
+00110000000000101001100100000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10111000000101011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000001000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000010111011000000000010111011
+00000000001111101100000000001011
+10110000000000101110101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011111011000000
+00001111101100000000001110101100
+00000000111110110000000000111110
+11000000000011101011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000011001110
+10110000000000111110010100000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10010000000100001111110000000000
+11111111000000000011111111000000
+00001111111100000000001110111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000001111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111110000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000000011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000001100000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000001110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101010110000000000101110110000
+00000010111011000000000110111011
+00000000001011101100000000001011
+10110000000100101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000011000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10000000000011010110110000000000
+11111011000000000011111011000000
+00001111101100000000001110101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000101110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110000000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000010000111111110000
+00000011111111000000000011111111
+00000000001111111100000000011111
+11110000000000111110100000000111
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111011000000000
+11001111100000000011001100000000
+00001000111110000000001100111110
+00000100111111111000010000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110010000000000
+10001010000000000010001010000000
+00001000101100000000101000101110
+00000000101110111000000000101110
+11100000000010111011100000000010
+11101110000000001011101110000000
+00101110111000000000101110111000
+00000010111011100000100010111011
+10000000001011101110000000001011
+10111000000000101110000000000110
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011110110000000010
+10001011000000000010000000000000
+01001000001100000000001000001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000110110011000000000010110011
+00000000001011001100000000001011
+00110000000000101110001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010011000000000
+10001011000000000010001011010000
+00001000001100000100001000101100
+00000000101110110000000100101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000010000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111000000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000101011110111110000100
+11000010100000001011001000000000
+00101100101100000000001100101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000001001111101100000100001111
+10110000000000111101000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011010000000000
+11111110101000100011111100000000
+00101111111100000010001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000100111111110000
+00010011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110100000000
+11001011000100000011000011010010
+00001000101100000000001011101100
+00000000111110110000000000111110
+11000000010011111011000001000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000010111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010000110010000000
+10001010000000100010001011000011
+00001000101111011000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000001000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100010000000000
+10000011000010010010000001000000
+00101000001110000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001001000000010
+10001110100000000010000111100100
+00001000011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000100010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000010110000000000
+11000011000000010011001000000100
+00101100001100010000001111001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110000000000111100110000
+00000011110011000100000011110011
+00000000001111001100000000001111
+00110000000000111101001000000010
+00010000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000000010
+11110100000000101011111110000100
+00001111111100010000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000010
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011100010000000010
+11001011000000000010001001010010
+01001100101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000000111101100000000001111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001010000000000
+10001110000000000010000101000000
+00001000011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000100101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101101001000000110
+01000000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001011111000100000
+10000111100000000010000110100010
+00001000011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000001101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100111000000000
+10000000010010001010000011000000
+00001000001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101101000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011001100100000000
+11001110010000010011001010010000
+00101100101000000000001111101000
+00010000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00101110100000000000111110100000
+00000011111010000000000011111010
+00000000001111101000000000001111
+10100000000000111111101000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000100000
+11111000000000000011110000010010
+00001111100000000000001111100000
+00000100111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110011000000000
+11001001000100000011001011000100
+00001100100111000100001100100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110011100001000
+10001001110000000010001001110000
+00101000100110000000101000100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000010001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010001000010
+10000011010000000010001001000000
+01001000000100000000001000100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100111000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000010011000000000
+10000001010000001010000011001000
+00001000000101000010101000000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000010010110001
+00000000001011000100000000001011
+00010000000100101100101000000101
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000100000000
+11001000010000010011000000000101
+00001100101001000000001100100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+01111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011111010000100000
+11111101000000000011111001010000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+01000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11001001000000000011001001000000
+00001100100100000000000111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000000111100100000000001111
+10010000000000111100011000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001100000000000010
+10001000000000001010001000000000
+00001000110000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010111000
+00000000001011100000000000001011
+10000000000000101100111000000110
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011101010000000010
+10000101000000000010000101000000
+00001000010100000100001001000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001001000100000000
+01101100010000000000001100010000
+00100000110001000000000010110001
+00000000001011000100000000001011
+00010000000000101101001000000001
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010011000001000
+10000101000000000010000101000000
+00001000111100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000100110010000
+00000000111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010010000010
+11001001001000000011001001101000
+00101100100100000000001101100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001101100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000100100
+11111001100101000011111001001000
+00001111100100000000001111100100
+00000100111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111101001000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000100000000
+11001000110001000011001000100000
+00001111100000000000001100100000
+00001000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000001010011111000
+00000000000111100000000001001111
+10000000010000111100001000000100
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010101100000000
+10001010000000000010001010001000
+00001011101000000000001000101000
+00000000101110100000000000101110
+10000000000010111010000000000010
+11101000000010001011101000000010
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100101000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010110110101000000
+10000011000000000010000011100000
+00001011001110000000001000001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10000111000000001010000111000000
+00001011011111000000001000011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000010
+00101101110000000000101101110000
+01000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101110000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001101000000010
+11001111100000001011000111100000
+00001111111010010000101100011110
+00001000111101111000000000111101
+11100000100011110111100000000011
+11011110000000001111011110000000
+00011101111000000000111101111000
+00000011110111100000100011110111
+10000000001111011110000000001111
+01111000000000111110001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010000000000000
+11111000000000000011111010000000
+00001111101000000010001111101100
+00000000111110110000000000111110
+11000000000011111011000000000010
+11101100000001001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001011101100000000001111
+10110000000000111100001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000001011111111000000000
+11001111100000000011001111100100
+00001100111110000000001010111110
+01000000111111111000001000011111
+11100000100001111111100000000011
+11111110000000001111111110010000
+00111111111000000000111111111001
+00000010111111100100100011111111
+10000000001111111110000000001011
+11111001000000111100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000000011001110000000000
+10000111001010000010000101000010
+00001000011100100000001000011100
+00000000001101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110001
+00010010010111000000000010110111
+00000000001011011100000000001011
+01110000000000101110101000000110
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000100001001100000000000
+10000111000000010110000111000000
+10001000010000000100001000011100
+00000000101101110000000000100101
+11000000000010110111000000000010
+11011100000000001011011100000010
+00101101110000000000101101110000
+00100000110111000000100010110111
+00000000001011011100000000001011
+01110000001000101100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001110001001000000
+10001000000000100100001000110000
+00001000100000000000001000001100
+00000000101100110000000001100100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000010000100100110000
+00000010010011000000000010110011
+00000000001011001100000100001011
+00110000000000101100100100000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010110000000010
+11001001010000010011001011000000
+00001100101100000000100100101100
+00000000111110110000000000110110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000001111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110100000000
+11111011000000000011111011000000
+00001111100000000000001111101100
+00000000111110110000000100111110
+11000000010011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00010011011011000000000011111011
+00000000001111101100000001001111
+10110000000000111110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111110000100000
+11001101000010000011001101000010
+01001100111100000000001101111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111100100001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110010110010000
+10001000010000000010001000010000
+00001000101000000000011000101100
+00000000101110110000000000101110
+11000000000010111011000001000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110100001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010001000000010
+10001000100010000010001010110000
+00001000101110000010001000101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101010110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000000000000010
+10000011000000001010000000000000
+01001000000000000000001000001100
+00000100101100110000000000101100
+11000000000010110011000000010010
+11001100000000001011001100000000
+00001100110000000000101100110000
+00000000110011000000000110110011
+00000000001011001100000001001011
+00110000000000101100001000000101
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000001010100100000000000
+11000000000000000011000011000000
+01001100000100000000101100101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100000000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011111000000000000
+11111100000000000011111100000000
+00000111110000000100001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000010000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111110100000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11111111100000000011111111100000
+00001110111110000000001101111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001101111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000001111111110000000001111
+11111000000000111111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110111000000000
+10111011100000000010111011100000
+00001011101110000001001011101110
+00000000101110111000000000101110
+11100000100010111011100000000010
+11101110000000001011101110000000
+00101110111000000000101110111000
+00000010111011100000000010111011
+10000000001011101110000000001011
+10111000000000101110000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10110011000000000010110011000000
+00001010001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00100100110000001000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101110001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000100111011000000000000111011
+00000000001011101100000000001011
+10110000000000101111000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000101011110110000000000
+11111011000001010011111011000000
+01001110101100000000001101101100
+00000000111110110000000000111110
+11000000000011111011000001000011
+11101100000000001101101100000000
+00111110110000000000111110110000
+00000011111011000001000011111011
+00000000001111101100000000001111
+10110000000000111100100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000000000011111111000000
+00000111111100000000001011111100
+00000000111111110000000000011111
+11000000000001111111000000000011
+11111100000000001111111100000000
+01111111110000000000111111110000
+00010011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+00001110101100000000001110101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10110011000000000010110011000001
+00000011001100000100000011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000001000000110011
+00000000001011001100000000001011
+00110000000000101111000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+01100000000000010001111000000000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101101111000000001101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101101100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11110011000000000011110011000000
+00001111001100010000001110001100
+00000000111100110000000001111100
+11000000000011110011000001010011
+11001100000000001111001100000000
+00111100110001000000111100110000
+01000011110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101101000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000000000
+11111111000000000011111111000000
+00001111111100000100001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000010000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110101000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000011011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000001101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101101001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000001000000001001111000000000
+10110111100000000010110111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101111000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000100101100110000000000101100
+11000000000010110011000000100010
+11001100000000001011001100000000
+00101100110000000001100100110000
+00000010010011000000000010110011
+00000000001011001100000000001011
+00110000000000101101001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000100101011010100000000000
+11111010000000000011111010000000
+00001111101000000000001111101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000000
+00111110100000000000111110100000
+00000011111010000000000011111010
+00000000001111101000000000001111
+10100000000000111111101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01001010000000001110000000000000
+11111000000000010011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000001001111
+10000000000000111101001000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001010000100001110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00100000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000010
+11100100000000001011100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+10011000000001011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000001
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000000111000000000000010111000
+00000000001011100000000000001011
+10000000010000101100111000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011100010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000100010111001000000000010
+11100100000000001011100100000000
+00101110010000010000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+10111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110100000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100101000010000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100001010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000001000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000100001010010100000000000
+10111010000000000010111010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000010111010000000000010111010
+00000000001011101000000000001011
+10100000000000101100101000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100101000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000000000010001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000001000010110111
+00000000001011011100000000001011
+01110000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110111100000000011110111100000
+00001111011110000000001111011110
+00000000111101111000000000111101
+11100000000011110111100000000011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111100101000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000010
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000001000
+11111111100000000011111111100000
+00001111111110000000001111111110
+00000000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011111111100000000011111111
+10000000000111111110000000001111
+11111000000000111101000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+11101000000100011001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000100101101
+11000000000110110111000000000010
+11011100000001001011011100000000
+00101101110000000000101101110000
+00000010110111000100000010110111
+00000000001011011100000000011011
+01110000000000101110101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000000001001110000000000
+10110111000000000010110111000000
+00001011011100000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100010001000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00100000000101001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000001000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101101101000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000111111011000000000011111011
+00000010001111101100000011001111
+10110000000100111110111000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000010001111101100000100
+00111110110000000000111110110000
+00000011111011000000100011111011
+00000001001111101100000000001111
+10110000001000111110000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+11000000000100001111110000000000
+11111111000000000011111111000000
+00001111111100000000001111111100
+00000000111111110000000000111011
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111110000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111011000000000010111011000000
+00001011101100000000000011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11101100000000001011101100000001
+00101110110000000000101110110000
+00000010111011000000000010111011
+00000100000001101100000000001011
+10110000000000101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000100
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000100010110011
+00000100001011001100000000001011
+00110000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10000000000011010110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111010
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110000000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+11100000000111011111110000000000
+11111111000000000011111111000001
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000010000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111110100000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000000
+11000100100000100011001111100000
+00001100111010000000001111111110
+00000000110011111000000000111111
+11100000000011111111100000000011
+11111110000000001100111110000110
+00111111111000000000111111111000
+00000011111111100000000011001111
+10000000001111111110000000001111
+11111000000000111111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110111000000000
+10001001100001100010001011100001
+00001000101010000000001011101110
+00000010100010111000000000101110
+11100001100010111011100000000010
+11101110000000101000101110000000
+00101110111000000000101110111000
+01000010111011100000010010001011
+10000000001011101110000000001011
+10111000000000101110000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10011010000000000010010011000000
+00001001001000000000001011001100
+00000000100000110000000000101100
+11000000000010110011000000000010
+11001100000000001000001100000000
+00101100110000001000001100110000
+00000010110011000000001010010011
+00000000001011001100000000001011
+00110000000000101110001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000101011010110000000000
+10011001000000000010011011000000
+01001001101000000010001011101100
+00000000100010110000000000101110
+11000000000010111011000000000010
+11101100000000001000101100000000
+00101110110000010000101110110000
+00000010111011000000000010011011
+00000000001011101100000000001011
+10110000000000101111000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000101001000110000000000
+11011011100100000011010011000000
+00001101101000000100001111101100
+00000010110010110000000000111110
+11000000000011111011000000000011
+11101100000000001100101100000000
+00111110110000000000101110110000
+00000011111011000000100011011011
+00000000001111101100000000001111
+10110000000000111100000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+11100001000000001011110000001000
+11101100000000010011101111000000
+00001110111000000001001111111100
+00000000111111110000000000110111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000100111111110000
+00010011111111000000000011101111
+00000000001111111100000000001111
+11110000000000111111100000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11001011000000000011001011000000
+00001100101000010010001100101100
+00010000111110110000000000111110
+11000000000011111011000000110011
+11101100000010001111101100000000
+00111110110000000000111110110000
+01100011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001000010110000000100
+10000010000000000010001011000001
+00001000101011000000001000001100
+00000000101110110000000000101110
+11000000000010111011000000000010
+11001100000000001011101100000000
+00101110110000000000101110110000
+00000010110011000000000010111011
+00000000001011101100000000001011
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000000000
+10000000000000000010010011000000
+00001001001010000000001000001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101111000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001111100000000
+10001100110000000010010111110000
+10001001011011000000001000011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000000
+00101101111000000000101101111000
+00100010110111100000010010110111
+10000000001011011110000000001011
+01111000000000101100100000010100
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11000010000000000011010011000100
+00001101001000010000001100001100
+00000000111100110000000000111100
+11000000100011110011000000000011
+11001100000000001111001100000000
+00111100110001000000111100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011000110000000000
+11111010000000100011100011000001
+00001010001000000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000010001111101100000000
+00111110110000001000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011110110000000000
+11110000000000000010001011000000
+00001111101000000100001111101100
+00001000011110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000101110110000
+00000011110011100001001011001011
+00000000001111101100000000001111
+10110000000000111100001000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10110100000000000010000111000000
+00001011011000000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000000
+00101101110000000100101101110000
+00000010110111000000000010000111
+00000000001011011100000000001011
+01110000001000101101001000000100
+01000000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000000
+10111110100000001010000111100000
+00001011011010000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000001
+00101101111000000000001101111000
+00000010110111100000000010000111
+10000000001011011110000000001011
+01111000000000101100100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10110010000000000010000011000000
+00001011001000000000001011001100
+00000000101100110000000001101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000010000101100110000
+00000010110011000000000010000011
+00000000001011001100000000001011
+00110000000000101101101000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11111110000000000011001010000000
+00001111111000000000001111101000
+00000000111110100000000000111110
+10000000000011111010000000000011
+11101000000000001111101000000010
+00111110100000000000111110100000
+00000011111010000000000011001010
+00000000001111101000000000001111
+10100000000000111111101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000001000
+11111000100000001011111000000000
+00001111100000000000001111100000
+00000100111110000000000000111110
+00000000000011111000000000000011
+11100000000010001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111101001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000001011001001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000000110010000000000
+10110001000000000010001001000001
+00001011100100000000001110100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000100
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00011000000001000010011000000001
+10111011100001000010001001100000
+00001011100110000000001011100100
+00000000101110010000000000101010
+01000000000010111001000000000010
+11100100000000001011100100000010
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000010000
+10110001000000000010000001000000
+00001011000100000001001010000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000010011011000100000000
+00101100010000000000101100010000
+00000010110001000000010010110001
+00000000001011000100000000001011
+00010000000100101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000010010110000000000000
+11111000000000000011001000000001
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011111010000000000
+11111101000000000011111001000000
+00001111100100000000001110100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+01000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110111000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+00011000000001011110010000000000
+11111011000000000011001001000000
+00001111100100000000001111110100
+00000000111110010000000000110110
+01000000000011111001000000000011
+11110100000000001111100100000000
+00111110010000000000111110010000
+00000011111101000000000011001001
+00000000001111100100000000001111
+10010000000000111100111000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+00111100000100001110000000000000
+10111000000000000010001000000000
+00001011110000000000001011100000
+00000000001110000000000000101110
+00000000000010111000000000010010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000000010001000
+00000000001011100000000000001011
+10000000000000101100011000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00001000000001011101010000000000
+10111101000000000010010101000001
+00001011010100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000001010000001
+00000000001011000100000000001011
+00010000000000101101001000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111101100000001010011101000000
+00001011110100000000001011100100
+00010000101110010000000000101110
+01000000000110111001000000100010
+11100100000001000011100100000101
+00101110010000000000100110010000
+00000010111001000000000010001001
+00000000011011100100000000001011
+10010000000000101100011000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000101001010010000010000
+11111001100000000011011001000000
+00001111100100000000001111100100
+00000000111110010000000100110110
+01000000100011111001000000100011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011001001
+00000000001111100100000010001111
+10010000000000111110100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101010000000001010010000000000
+11111001000000000011101001000000
+00001111100100000000001111100100
+00000100111110010000000000101110
+01000000000011111001000000000001
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111101101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101010000100001010000000000000
+11111000000000000011111000000000
+00001111110000100000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000001001111100000000000
+00111110000000000000011110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000100001000010100000000100
+10110010000000000010111010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000010110010000000000010111010
+00000000001011101000000000001011
+10100000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000000000
+10110011000000100010110011000000
+00001011001000000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000100010110011
+00000000001011001100000000001011
+00110000000000101100001100000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00100000000000010001100000010000
+10110110000000000010110110000000
+00001011011000000000001011011100
+00000000101101110000000000101101
+11000000000010110111000000000010
+11011100000000001011011100000001
+00101101110000000000101101110000
+00000010110111000000000010110111
+00000000001011011100000000001011
+01110000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00111000000010000001011000000000
+11110101100000000011110101100000
+00001111010010000000001111011110
+00000000111101111000001000111101
+11100000000011110111100000100011
+11011110000000001111011110000000
+00111101111000000000111101111000
+00000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111100101000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010000000000000
+11111000000000000011111000000000
+10001111100000000000001111101100
+00010100111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000010
+00111110110000000000111110110000
+01000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000001011111111000000010
+11001111100000000011111111100000
+00001111111110010000001111111110
+00000000111111111001000000111111
+11100000000011111111100000000011
+11111110000000001111111110010000
+00111111111001000000111111111000
+00000011110111100000000011001111
+10000000001111111110000000001111
+11111000000000111101100000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001100001010000
+11010110000100000010110110000000
+00001011011100000000001001011100
+00000100111101110000000100101101
+11000000010010110111000100000010
+11011100000000001011011100000000
+00111101110000000000101101110000
+01010010110111000000010010000111
+00000000001011011100000000001011
+01110000000000101110101000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001011010000000000
+10000101000010000010110101000000
+00001011010110000000011001011100
+00000000101001110000000001101101
+11000000000010110111000000000010
+11011100000000001011011100000010
+01100101110000000001101101110000
+00000010110111000000000010000111
+00000000001011011100000000001011
+01110000000000101100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01100000000101001100000000000010
+10000000100000000010110000000000
+00001011000100000000001001001100
+00000100101100110000000000101100
+11000000000110110011000001000010
+11001100000100000011001100000100
+00101000110000010000101100110000
+00000010110011000001001010000011
+00000100001011001100000100001011
+00110000000000101101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+10101000000101011010110000000000
+10000011110000000011111011000000
+00001111101000000000001101101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001011101100000000
+00101110110000000000111110110000
+00000011111011000001000011001011
+00000000001111101100000000001111
+10110000001100111110101000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110100000010000
+11111010000010000011111010000000
+01001111101000000000001101101100
+00000000111010110000000100111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+01111110110000000000111110110000
+00000011111011000000000011111011
+00000010001111101100000001001111
+10110000000000111110100000010100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00000001000100001111010000000000
+11111101000000000011001101000000
+00001111110000000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000100111111110000
+00010011111111000000100011111111
+00000000001111111100000000001111
+11110000000000111100000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11000001000001000110000000010000
+10111000000000000010001000000000
+00001011100000000100001011101100
+00010000101110110000000000101110
+11000001000110111011000000010010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000010111011000001000010111011
+00000000001011101100000000001011
+10110000000000101110000001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+11000000000001010010110000001000
+10111011000000000010001011000000
+00001011101100000000001010101100
+00000000101110110000000000101110
+11000000010010101011000000010010
+11101100000010001011101100000000
+00101110110000000000101110110000
+00000000111011000000000010111011
+00000000001011101100000001001011
+10110000000100101110000000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00001000010000000000100000000000
+10111010000000001010000010000000
+01001011001100000001001011001100
+00000000101100110000000000101100
+11000000000010110011000000010010
+11001100000000001011001100000001
+00101100110000000000101100110000
+00000010110011000000010010110011
+00000000001011001100000001001011
+00110000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000011000110010000000000
+11111001000000000011001001000000
+00001111100100000000001110101100
+00000000111110110000000000111110
+11000000000011101011000000000011
+11101100000010001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000011100000000000110
+00000000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011101000000000000
+01111100000001000011111100000001
+00001111110100000100001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000011111111100000000
+00111111110000010000111111110000
+01000011111111000001000011111111
+00000000001111111100000000001111
+11110000010000111110100000000010
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000001011111111000000010
+11001111100000000011111111100000
+10001111111110000000001101111110
+00001000111111111000000000111111
+11100000000011111111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111000
+00000011011111100000011011001111
+10000000001111111110000000001111
+11111000000000111111000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001110111000000000
+10001011100000000010111011100000
+00001011101110000001001011101110
+00001000101110111000001100101110
+11100000010010111011100000010010
+11101110000000001011101110000000
+00101110111000000000101110111000
+00010010011011100000000010001011
+10000000001011101110000000001011
+10111000000000101110000000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10001000000001011100110000000000
+10000011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101100110000
+00000010110011000000000010000011
+00000000001011001100000000001011
+00110000000000101110001000000001
+01110000000000000000000000000000
+00000000000000000000000000000000
+11000000000100011010110000000000
+10001011000001000010111011000000
+00001011101100000000001011101100
+00000000101110110000000000100110
+11000000000000111011000001000010
+11101100000000001011101100000000
+00101110110000001000101110110000
+00000110011011000000000010001011
+00000000001011101100000000000011
+10110000000000101111000000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00000000000101011110110000000000
+11001011000000000011111011000000
+00001111101100000000001101101100
+00000000111110110000000000111110
+11000001000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011011011000000010011001011
+00000100001111101100000000001111
+10110000000000111101000000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+11100000000000011011110000000000
+11111111000001000011111111000000
+00000111111100000100001111111100
+00000000111111110000000000101111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00010011111111000001000011111111
+00000000001111111100000000001111
+11110000000000111111100000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000100001010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00011000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00010011111011000000010011111011
+00000100001111101100000000001111
+10110000000000111101000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+11001000000001010000110000000000
+10111011000001000010111011000000
+00001011101100000100001011101100
+00000000111110110000010000101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000000101110110000
+00000000110011000001000010111011
+00000000001011101100000000001011
+10110000000000101111001000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+11100000000001010100110000010000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000001100110000
+00000010110011000000000010110011
+00000000001011001100000100000011
+00110000000000101111100000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+01100000010000010001111000000000
+10110111100000000110110111100000
+00001011011110000000001011011110
+00000000101101111000000000101101
+11100000000010110111100000000010
+11011110000000001011011110000100
+00101101111000000000101101111000
+00000010110111100000000010110111
+10000000001011011110000000001011
+01111000000000101100100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+01001000000010000000110000000000
+11110011000000000011110011000001
+00001111001100010000001111001100
+00000000111100110000000000111100
+11000000000011110011000000000011
+11001100000000001111001100000000
+00111100110001000100111100110000
+00000011110011000000000011110011
+00000000001111001100000000001111
+00110000000000111101001000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000111011011110000000001
+11111111000000000011111111000000
+00000111111100010100001111111100
+00000000111011110000000001111111
+11000000000011111111000000010011
+11111100010000001111111100010000
+00111111110000000000111111110001
+00010111111111000000000011111111
+00000000001111111100000000001111
+11110000000000111101000000000010
+01100000000000000000000000000000
+00000000000000000000000000000000
+10101000000001011100111000000000
+11001011000000000011111011000000
+00001111101100000000001111001110
+00000000110010110000000000111110
+11000000000011111011000000000011
+11001110000000001100101100000000
+00111110110000001000111110110000
+00000011110011100000000011001011
+00000000001111101100000000001111
+10110000000000111110101000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+01001000000100011001110000000000
+10000111000000000010110111000000
+00001011011100000001001011011100
+00000000100001110000000001101101
+11000000000010110111000000000010
+11011100000000001000011100000100
+00101101110000000000100101110000
+00000010110111000000000010000111
+00000000001011011100000000001011
+01110000000000101101001000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+11000000000000001001111000000010
+10000111100000000010110111100000
+00001011011110000000001011011110
+00010011100101111000000000101101
+11100000000010110111100001100010
+11011110000010101000011110000000
+00101101111000000000101101111000
+00000010110111100000011010000111
+10000100001011011110000000001011
+01111000000000101111000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01001000000101001100110000000000
+10000011000000010010110011000000
+00001011001100000000001011001100
+00000000100100110000000000101100
+11000000000010110011000000000010
+11001100000000001000001100000001
+00101100110000000001100100110000
+00000010110011000000000010000011
+00000000001011001100000000001011
+00110000000000101101001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+11101000000101011010100000000000
+11001010000000000011111010000000
+00001111101000000000001111101000
+00000000110110100000000000111110
+10000000000011111010000000000111
+11101000000000001100101000000000
+00111110100000000000111110100000
+01000011111010000000000011001010
+00000000011111101000000000001111
+10100000000000111111101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+01001000000000001110000000000000
+11111000000000100011111000000000
+00001011100000000000001111100000
+00000000111010000000000000111110
+00000000000011111000000000000111
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000001001111
+10000000000100111101001000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000100001110010000000000
+11111001000000000011101001000000
+00001111100100000000001111100100
+00000000111110010000000000111110
+01000000000011111001000000000011
+11100100000001001111100100000000
+00111110010000000000111110010000
+01100011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100001000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000001000110010000000000
+10111001000000000010111001000000
+00001011100100000000001011100100
+00000000100110010000000000101110
+01000000000010111001000000000010
+11100100000000001011100100000000
+00101110010000000000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101110000000000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+00011000000001010010010000000000
+10111001000000000010111001000001
+00001011100100000000001011100100
+00000000101110010000000000101110
+01000000000010111001000000000010
+10100100000000001011100100000000
+00101110010000000000001110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000010010
+11000100000000001011000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+10111000000011010110000000000000
+11111000000000000011101000000000
+00001111100000000000001111100000
+00000000111110000000000000111110
+00000000000011111000000000000011
+11100000000000001111100000000000
+00111110000000000000111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111110111000000011
+01010000000000000000000000000000
+00000000000000000000000000000000
+10011000000111011110010000000000
+11111001000000000011111001000000
+01001111100100000000001111100100
+00000000110110010000000000111110
+01000000000011111001000000000001
+11100100000001001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110011000000110
+01110000000000000000000000000000
+00000000000000000000000000000000
+10011000000001011111010000000000
+11111001000000000011111001000000
+00001111100100000000001111110100
+00000000111110010000000000110110
+01000000000011111001000000000011
+11110100000000001111100100000000
+00111110010000000000111110010000
+00000011111101000000000011111001
+00000000001111100100000000001111
+10010000000000111100011000000001
+01100000000000000000000000000000
+00000000000000000000000000000000
+00111000000100001110000000000000
+10111000000000000010111000000000
+00001011100000000000001011100000
+00000000101110000000000000101110
+00000000000010111000000000000010
+11100000000000001011100000000000
+00101110000000000000101110000000
+00000010111000000000010010111000
+00000000001011100000000000001011
+10000000000000101100111000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+00001000000000001100010000000000
+10110001000000000010110001000000
+00001011000100000000001011000100
+00000000101100010000000000101100
+01000000000010110001000000000010
+11000100000000001010000100000000
+00101100010000000000101100010000
+00000010110001000000000010110001
+00000000001011000100000000001011
+00010000000000101100001000000001
+00110000000000000000000000000000
+00000000000000000000000000000000
+00011000000101011010010000000000
+10111001000000000010111001000000
+00001011100100000000011011100100
+00000000101110010000000100101110
+01000000000010111001000001000010
+11100100000000001011100100000000
+00101110010000010000101110010000
+00000010111001000000000010111001
+00000000001011100100000000001011
+10010000000000101100011000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10100000000101011110010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00010000111110010000010000110110
+01000000000011111001000000000011
+11100100000000001110100100000000
+00111110010000000000111110010000
+00000010111001000000000011111001
+00000000001111100100000000001111
+10010000000000111110100000000100
+01110000000000000000000000000000
+00000000000000000000000000000000
+00101000000000011010010000000000
+11111001000000000011111001000000
+00001111100100000000001111100100
+00000000111110010000000000101110
+01000000000011111001000000000011
+11100100000000001111100100000000
+00111110010000000000111110010000
+00000011111001000000000011111001
+00000000001111100100000000001111
+10010000000000111100101000000000
+01100000000000000000000000000000
+00000000000000000000000000000000
+00101000000100000010000000000000
+11111000000000000011111000000000
+00001111100000000000001111100000
+00000000111110000000000001111110
+00000001000011111000000000000011
+11100000000000001111100000000000
+00111110000000000001111110000000
+00000011111000000000000011111000
+00000000001111100000000000001111
+10000000000000111100101000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010010100000000000
+10111010000000000010111010000000
+00001011101000000000001011101000
+00000000101110100000000000101110
+10000000000010111010000000000010
+11101000000000001011101000000000
+00101110100000000000101110100000
+00000011101010000000000010111010
+00000000001011101000000000001011
+10100000000000101100101000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00101000000001010100110000010000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000100
+00101100110000000000101100110000
+00000010110011000000000010110011
+00000000001011001100000000001011
+00110000010000101100101000000000
+01010000000000000000000000000000
+00000000000000000000000000000000
+10100000010000010001110000000000
+10110111000000000010110111000000
+00011011011100000000001011011100
+00000000101101110000000000001101
+11000000000010110111000000000010
+11011100000000001011011100000001
+00101101110000000000101101110000
+00000000100111000000000010110111
+00000000001011011100000000001011
+01110000000000101110100000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+10101000000010000001111000000000
+11110111100001000111110111100000
+00001111011110000000001111011110
+00000000111101111000000000101101
+11100000000011110111100000000011
+11011110000000001111011110000000
+00111101111000000000101101111000
+01000011110111100000000011110111
+10000000001111011110000000001111
+01111000000000111110101000000010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000111011010110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000100111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100001000000110
+01100000000000000000000000000000
+00000000000000000000000000000000
+01000000000001011111111000000000
+11111111100000000011111111100100
+00001111111110000000001111111110
+00000000111111111000011000111111
+11100000000011101111100000000011
+11111110000000001111111110000000
+00111111111000000000111111111001
+00000011111111100000000011111111
+00100000001111111110000000001111
+11111000000000111100000000000000
+01110000000000000000000000000000
+00000000000000000000000000000000
+10101000000100011001110000000000
+10110111000100000010110111000000
+00001011011100000000001011011100
+00000000101101110001000000101101
+11000000010010110111000000000010
+11011100000010001011011100000000
+00101101110000000000101101110001
+00000010110111000100000010110111
+00000000001011011100000010001011
+01110000000000101110101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+00011000000000001001110000000000
+10110111000000000010110111000001
+00011011011100000000001011011100
+00000000101101110000000000101101
+11000000000010100111000000000010
+11011100000000001011011100000000
+00101101110000000000101101110000
+00000110110111000000000010110111
+00010000001011011100000000001011
+01110000000000101100000000000000
+00100000000000000000000000000000
+00000000000000000000000000000000
+01100000000100001100110000000000
+10110011000000000010110011000000
+00001011001100000000001011001100
+00000101101100110000000000101100
+11000001000010110011000000000010
+11001100000000001011001100000000
+00101100110000000001101100110000
+01000010110011000000000010110011
+00000000001011001100000000001011
+00110000000000101100100000000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10111000000101011010110000000000
+11111011000000000111111011000000
+00001111101100000010001111101100
+00000000111110110000000000111110
+11000000000011101011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111110101000000100
+01100000000000000000000000000000
+00000000000000000000000000000000
+10000000000000001110110000000000
+11111011000000000011111011000000
+00001111101100000000001111101100
+00000000111110110000000000111110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000111110110000
+00000011111011000000000011111011
+00000001001111101100000000000111
+10110000000000111110000000000000
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000000000100001111110000000000
+11111111000000000011111111000000
+00001111111100000000001110111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000000000111111110000
+00000011111111000000000011111111
+00000000001111111100000000001111
+11110000000000111100000001000100
+00110000000000000000000000000000
+00000000000000000000000000000000
+10000001000001000110110000000000
+10111011000000010011101011000000
+00001011101100000000000011101100
+00000000101110110000000001101110
+11000000000010111011000000000010
+11101100000000001011101100000000
+00101110110000000001111010110000
+00000011101011000000110010111011
+00000100001011101100000000001011
+10110000000000101110000001000000
+00010000000000000000000000000000
+00000000000000000000000000000000
+10000000000001010010110000000000
+10111011000000000010111011000000
+00001011101100000000001011101100
+00000000101110110000010000101110
+11000000000010111011000000000110
+11101100000000001011101100000000
+00101110110000010000101110110000
+00000010111011000000000010111011
+00000000001011101100000000001011
+10110000000000101110000000000000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00001000000001000000110000000100
+10110011000000000010100011000001
+00001011001100000000001011001100
+00000000101100110000000000101100
+11000000000010110011000000000010
+11001100000000001011001100000000
+00101100110000000000101000110000
+00010010100011000001100010110011
+00000100001011001100000000001011
+00110000000000101100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+10000000000011010110110000000100
+11111011000000100011111011000000
+10001111101100000000001110101100
+00000000101110110000000000101110
+11000000000011111011000000000011
+11101100000000001111101100000000
+00111110110000000000101110110000
+00000011111011000000000011111011
+00000000001111101100000000001111
+10110000000000111100000000000011
+00010000000000000000000000000000
+00000000000000000000000000000000
+10100000000111011111110000000000
+11111111000000000011111111000001
+00001111111100000000001111111100
+00000000111111110000000000111111
+11000000000011111111000000000011
+11111100000000001111111100000000
+00111111110000010000111011110000
+00000011101111000000000011111111
+00000000001111111100000000001111
+11110000000000111110100100000011
+01110000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010000000000000010
+01110001010000001001110000010000
+00110111000111000101010111000001
+00000011011100000100000010011100
+00010000001101110001010000001101
+11000111000000110111000111000001
+11011100010100000111011100010100
+00010101110000010000000101110000
+01000000010111000001000001010111
+00000100000111011100000000100001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000110000010100010000100101
+01110001000000010101110001000000
+01010111000100000001010001000100
+00000101011100010000000001011100
+01000000010101110001000001010101
+11000100000001010011000100000001
+01011100010000000101011100010000
+00011100100001000000010000110001
+00000001110111000100000001010111
+00010000000101011100000000010001
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000100001000000001000000001
+00100000100000000100100000100000
+00010010000110000000000010000010
+00000001001000001000000001001000
+00100000000100100000100000000100
+10000010000000000010000010000000
+01001000011000000001001000011000
+00000100100000100000000101110000
+10000000010010000010000000010010
+00001000000001001000000000100000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00000000100000000000000000000001
+01100000000000000101100000000000
+00010110000000000000010110000000
+00000001011000000000010001010000
+00000000000101100000000000000101
+10000100000000010110000100000000
+01011000000000000001011000001000
+00000001100000000010010101100000
+00000000010110000000000000010110
+00000000000101011000000000110001
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000010001010100100101000101
+01110010000000010001110010000000
+01000111001000000000010111001000
+00000101011100100000000000011100
+10000000010101110010000000010101
+11001000000001010111001000000000
+01011100110000000001011100100000
+00000101110010000000010101110010
+00000001010111001000000001000111
+00100000000100011100000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010100000000000000
+01100000000000000001100000000000
+00000110000000000000000110000000
+00000000011000000000000100011000
+00010000000001100000000000000001
+10000000000000000110000000000000
+00011000000000000000011000000000
+00000000100001000000000001100000
+00000000000110000000000000000110
+00010000000000011000000000110001
+01000000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010100100000000100
+00100010000000010000100010010000
+01000010000000000000000010001000
+00000100001000000000000100001000
+10000000010000100010000000010000
+10001000000001000010001000000000
+00001000101000000000001000000100
+00000000100001000000010000100000
+00000001000010000000000001000010
+00110000000100001000000000100001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010100111100000101
+01000010100000010101000011100000
+01010100000000000000010100001010
+00000101010000001000000101010000
+11100000010101000010110000010101
+00001010000001010100001111000001
+01010000111000000101010000000000
+00000100000000100000000101000000
+11000000010100000010000001000100
+00101100000000010000000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000100000000001110100000001
+00010011000000000101010111000000
+00010101011100000001010101011100
+00000001000001110000000001000001
+11000000000100000111000000000100
+01011100000000010101001100000000
+01000101110000000001010100110000
+00000101010111000000000101010011
+00000000010001011100000000010101
+00110000000001000100000000100000
+01000000000000000000000000000000
+00000000000000000000000000000000
+00000000100001000000010000000000
+00010000000000000001000001000000
+00000100001110000000000100000000
+00000000000000000000000000000000
+01100001000001000000000000000000
+01000000000000000100000110000000
+00000100010000000000010000110000
+00000001000011000000000001000000
+00000001000001001000000000000100
+00010000000000000100000100100001
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000110000010110000000000010
+00011000000000001000001000000000
+00100000100000000000100000100000
+00000010000010000000000110000010
+00000000001000001000000010001000
+01100000000000100000100000000000
+10000110000000000010000010000000
+00001000001001000000001000001000
+00000000100001100000000000100000
+10000000000010000100000100010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010001000000000101
+01100000000000010101100100000000
+01010110010000000000110110010000
+00000001001001000000000001001001
+00000000010101100100000000010101
+10010000000000010110000000000000
+01011001000000000001011000000000
+00011101100100100000011101100000
+00000001010110010000000001110110
+00000000000101011000000000010001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010100000000000001
+01100000000000001101100000000000
+00110110001000000000010110000000
+00000111011000000000000011011000
+00000001001101100000000000001101
+10000000000001110110000000000001
+11011000000000000101011000100000
+00010101100010000000010101110000
+00000000010110001000000001010110
+00000000000111011000000000100001
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010100001000000100
+00110000100001010000110000100000
+01000011000011000001000011000010
+00000100001100001000000000001100
+00100001010000110000100001010000
+11000010000001000011000010000001
+00001100001000000010001100001000
+00000000110000100000010001100000
+10000001100011000010000001100011
+00001000000100001100000000110001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000100000000000000000000000
+00110000000000000000110000000000
+00000011000000000000000011000000
+00000000001100100000000000001100
+00000000000000110000000000000000
+11000000000000000011000000000000
+00001100000000000000001100000000
+00000000110000000000000000100010
+00000000000011000000000000000011
+00000000000000001100000000000001
+01000000000000000000000000000000
+00000000000000000000000000000000
+00000000100000000000001000000001
+00110000100000000100110000100000
+00010011000010000001010011000010
+00000101001100101100000001001100
+00100000000100110000100000000100
+11000010000000010011000010000000
+01001100001000000001001100001100
+00000100110000110000000100110010
+11000000010011000011000000010011
+00001000000001001100000000110001
+01000000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010100001000000101
+01100000100000010101100000100000
+01010110000011000001000110000010
+00000001011000001100000000001000
+00100000010101100000100000010101
+10000010000000010110000010000000
+01011000001000000001011000001100
+00010101100000110000000101100000
+11000001010111000011000001010110
+00001000000001011000000000010000
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010100001000000000
+00100000100000000000100000100000
+00000010000010000000000011000010
+00000000011000001000000100001000
+00100000000000100000100000000000
+10000010000000000010000010000000
+00001000001000000000001000001000
+00000000110000100000010000110000
+10000000000110000010000000000011
+00001000000000001000000000110001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010001001000000100
+01100000100000010001100100100000
+01000110010010000001000011010010
+00000000001001001000000100001001
+00100000010001100100100000010001
+10000010000000000110010010000000
+00011001001000000000011001001000
+00010000110100100000010000110100
+10000001000010000010000001000011
+01001000000000011000000000000001
+01000000000000000000000000000000
+00000000000000000000000000000000
+00000000010001010110000000000101
+01011000000000010101011000000000
+01000101100000000000000001100000
+00000001010110000000000100000010
+00000000010101011000000000010101
+01100000000001010101100000000001
+01010110000000000001010110000000
+00010100011000000000010100011000
+00000000010001100000000000010001
+10000000000101010100000000000001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000100001000010011000000001
+01000001100000000101000001100000
+00010100000110000000010100000110
+00000001010000011000000001010000
+01100000000101000001100000000101
+00000110000000010100000110000000
+01010000011000000001010000011000
+00000001000000100000000101000001
+10000000010100000110000000010100
+00011000000001010000000000010001
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000100000000001001000000001
+00000000100000000100000100100000
+00010000010010000000010000010010
+00000001000001001000000001000001
+00100000000100100100100000000100
+00000010000000010000010010000100
+01000001001000000001000001001000
+00010100000100100000000100000100
+10000001010000000010000000010000
+01001000000001000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010100011000000011
+01010001100000001101010001100000
+00110101000110000000110101000110
+00000011010100011000000111000000
+01100000001101010001100000001101
+01000110000000110101000110000000
+11010100011000000001010100011000
+00000101010001100000001101010001
+10000000110101000110000000110101
+00011000000011010100000000110001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010100001000000111
+01110001100000010101110001100000
+00010111000110000000110111000110
+00000000011100011000001001011100
+01100000000101110001000000010101
+11000110000000010111000110000000
+01011100011000001110011100011000
+00010101110001100000011101110001
+10000001010111000110000001110111
+00011000000001011100000000010001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000010001010100011000000011
+01110001100000001101110001100000
+01100111000110000101010111000110
+00000010011100011000000011011100
+01100000011101110001100000001101
+11000110000001100111000110000001
+11011100011000000010011100011000
+00010001110001100000010101110001
+10000000010111000110000001010111
+00011000000011011100000000000001
+01000000000000000000000000000000
+00000000000000000000000000000000
+00000000010001010100011000000101
+01110001100000010101110001100000
+01010111000110000001000011000110
+00000101011100011000000000011100
+01100001010101110001100000010100
+11000110000101010111000110000001
+01011100011000000101011100011000
+00011000110001100000011001110001
+10000001100111000110000001000011
+00011000000101011100000000000001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000001000000001
+00100000100000000100100000100000
+00010010000010000000010111000010
+00000001001000001000000001001000
+00100000000100100000100000000101
+10000010000000010010000010000000
+01001000001000000001001000001000
+00000101110000100000000100110000
+10000000010010000010000000010111
+00001000000001001000000000010000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000010000000000011000000001
+01100001100000000101100001100000
+00010110000110000000010110000110
+00000001011000011000000001001000
+01100000000101100001100000000101
+10000110000001010110000110000001
+00011000011000000001011000011000
+00000101100001100000000101100001
+10000000010010000110000000010110
+00011000000001011000000000100001
+01000000000000000000000000000000
+00000000000000000000000000000000
+00000000010001010100000000000101
+01110000000000010101110000000000
+00010011000000000001010011000000
+00000101001100000000000001001100
+00000000000000110000000000010101
+11000000000000010111000000000001
+01011100000000000101011100000000
+00000101110000000000010100110000
+00000001000111000000000000010011
+00000000000101011100000000110001
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000010001000100001100000000
+01100000100000000001100000110000
+00000010000010000000000010000010
+00000000001000001000000100011000
+00100000000000100000100000000001
+10000010000000000110000010000000
+00011000001000000000011000001000
+00000000000000100000000000100000
+10000000000110000010000000000010
+00001000000000011000000000000001
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000010001000100001000000100
+00100000100000010000100000100000
+00000110000010000001000110001010
+00000100011000001000000100001000
+10100000000001100100100000010000
+10000010000000000010000010000001
+00001000001000000100001000001000
+00000000100000100000010000100000
+10000001000010000010000000000110
+00001000000100001000000000010001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000010001000100001100000101
+01000000100000010101000000100000
+01010101000011000001010101000011
+00000101010100001100000101010100
+00110000010101010000100000010101
+00000010000000010100000010000000
+01010000001000000101010000001000
+00000100000100110000000100000000
+10000000010100000011000001000101
+00001000000101010000000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000010000001100000001
+00010000110000000101010000110000
+00010101000011000000010101001010
+00000001010100001000000001010100
+10100000000101010000100000000101
+01000011000000010101000010000000
+01010100001100000001010100001100
+00000101010000110000000101010000
+10000000010101000011000000010101
+00001000000001010100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000010000100000000000
+00010010000000000001000000000000
+00000100000000000000000100000000
+00000000011000000000000000011000
+00000000000001000010000000000001
+00001000000000000100001000000000
+00010000100000000000010000100000
+01000001000100000000000001000010
+00000001000110000000000000000100
+00100000000000010000000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000010001000100001100000010
+00010000100000001000000010100000
+00100000001010000000100000000010
+00000010000000001000000110000000
+00100000001000000000100000001000
+00000010000000100000000010000000
+10000000001000000010000000001000
+00001000000110100100001000000000
+10000000100000001010000000100000
+00001000000010000000000000110001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000000001010100000000001001
+01100000000000010101100000000000
+00010110000000000000110110000000
+00000101011000000000001001011000
+00000000000101100100000010010101
+10000000000000010110000000000001
+01011000000000000101011000000000
+00011101100000000000011101100000
+00000001010110000000000010110110
+00000000001001011000000000010001
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000110001010100000000000010
+01100000000000011101100000000000
+00010110000000000000010111000000
+00000000011000000000000001001000
+00000000001101100000000000000101
+10000000000000010110000000000000
+10011000000000000011011000000000
+00000101110000000000000101110000
+00000000110010000000000000010111
+00000000000011011000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000100
+00110000000000000000110000000000
+01000011000000000000000110000000
+00000100001100000000000000001000
+00000001010000110100000000000000
+11000000000000000011000000000001
+00001100000000000100001100000000
+00010001100000000000010001100000
+00000000100010000000000001000110
+00000000000100001100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000010000000000
+00110100000000000000110001101000
+00000011010000000001000010000100
+00000000001101000000000000001000
+00000000000000110101000000000000
+11010100000001000011010000000000
+00001101010000000000001101000000
+00000000100101001000000000100100
+00000000000010010000000000000010
+00000000000000001100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000011000000001
+00110001010000010100110001010000
+00010011000101000001010011000110
+10000001001100010000000001001000
+01000000000100110101100000000100
+11000101000000010011000100000000
+01001100010100000001001100010100
+01010100111001011000010100110001
+00000000010010000101000001010011
+00010000000001001100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000010001100000101
+01101000110000000101101000110000
+01000110100011000001010100100011
+10000101011010001100000001011010
+00110000010101101101110000010101
+10100011000001010110100011000001
+01011010000100000101001010001100
+00010001101000100000010101101000
+11000001010110100011000001010110
+10001100000100011000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000010000000000
+00100100000000000000100011000000
+00000010011000000000000010000100
+00000000001001000000000100001000
+00000000000000100100000000000000
+10010101000000000010010000000000
+00001001000000000000001001000000
+00000000100111000000000000110100
+00000000000010011000000000000010
+00000000000000001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100000000100
+01100010000100000001100000000100
+01000110000000010001000110000000
+01000100011000000001000100011000
+00000100010001100010000000010001
+10001000000001000110001000010001
+00011000100000000100001000100001
+00010001100000000100010000110010
+00010001000110000000010001000110
+00100001000100011000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000001000101
+01010000000100000101010000000000
+01000101000000100000000101000000
+01100101010100000001000100010100
+00000100010001010000000100010101
+01000000010101010101000000010001
+00010100000100000100010100000000
+00000101010000010000000100010000
+00010000010101000000010000000101
+00000001000101010100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100000100001
+01000010000000000001000010000010
+00010101001000001000000101001000
+00100001010100100000100000010100
+10000010000101010010000000000101
+00001000000000010100001000000000
+01010000100000000001010000100010
+10000101000010000010000101010010
+00001000010100001000001000010101
+00100000100001010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000101000000001
+00000010100000000100000010100000
+01000000001010010000010000001010
+00000100000000101000000100000000
+10100000000100000010100000000100
+00001010000000010000001010000000
+01000000101000000001000000101001
+01000100000010100000000100000010
+10000000010000001010000000000000
+00101000000001000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000110010000011
+01010011000000000101010011000000
+00100001001100000000000101001100
+00000010000100110000000000000100
+11001000001000010011000000000101
+01001100000000010101001100100000
+11010100110000000011010100110001
+00001101010011000000001000010011
+00000000010101001100000000100001
+00110010000011010100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100010000101
+01110010000000010001110010000000
+01010111001000000001010111001000
+00001101011100100000001101011100
+10001000010101100010000000011001
+11001000000001000111001000001001
+01011100100000000100011100100000
+00001001110010000000011101100010
+00000001010111001000000001110111
+00100000100101011100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000001100001000
+01001000110001000001000000110000
+10000100000011000000000100000011
+00001000010000001100000000010000
+00110000100001000000110000000001
+00000011000100000100100011000000
+00010000001100000000010010001100
+00000001000000110000000001001000
+11000000000100000011000100000100
+10001100001000010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+01001111111111111101001111111111
+11110100111111111111110100111111
+11111111010011111111111111010011
+11111111111101000111111111011101
+00011111111111110100111111111111
+11010011111111111111010011111111
+11111101001111111111111101001111
+11111111110100111111111111110100
+11111111111111010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111011
+00001011001101111101001111111111
+10110000101101111111110100111110
+11011011000010110011011011000010
+11011111101100000111101101011101
+00011110110111110100101101111111
+11010011111111111111010010110111
+11111101001111111111101100001011
+00110110110000101100110110110000
+10110111111011000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111100
+01001100110011111101001111111111
+11000100110011111111110100111111
+00111100010011001100111100010011
+00111111110001000111110011011101
+00011111001111110100110011111111
+11010011111111111111010011001111
+11111101001111111111110001001100
+11001111000100110011001111000100
+11001111111100010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011101100011110
+01001110110111111001001000110111
+11100100100011011110000100100011
+00011110010010001100011000010010
+00110001111001000110110001011101
+00011011011111100100111011000111
+10010011101101111110010011101101
+11100001001000110111100001001110
+11000110000100100011011110000100
+11101100011110010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000100000010
+01110000010000001001110000010000
+00100111000001000000100111000001
+00000010011100000100000010011100
+00010000001100110000010000001001
+11000001000000100111000001000001
+10011100000100010110011100000100
+00001001110000010000001001110000
+01000000100111000001000001100111
+00000100000110011100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000010000000101
+01110001000000010101110001000000
+01010111000100000001010111000100
+00000101011100010000000101011100
+01000000010100110001000000010101
+11000100000001010111000100000001
+01011100010000000101011100010000
+00010101110001000000010101110001
+00000001010111000100000001010111
+00010000000101011100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000001000000001
+00100000100000000100100000100000
+00010010000010000000010010000010
+00000001001000001000000001001000
+00100000000100100000100000000100
+10000010000000010010000010000000
+01001000001000000001001000001000
+00000100100000100000000100100000
+10000000010010000010000000010010
+00001000000001001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01100000000000000001100000000000
+00000110000000000000000110000000
+00000000011000000000000000011000
+00000000000001100000000000000001
+10000000000000000110000000000000
+00011000000000010000011000000000
+00000001100000000001000001100000
+00000000000110000000000000000110
+00000000000000011000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100000000100
+01110010000000010001110010000000
+01000111001000000001000111001000
+00000100011100100000000100011100
+10000000010001110010000000010001
+11001000000001000111001000000000
+00011100100000000000011100100000
+00010001110010000000010001110010
+00000001000111001000000000000111
+00100000000000011100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01100000000000000001100000000000
+00000110000000000000000110000000
+00000000011000000000000000011000
+00000000000001100000000000000001
+10000000000000000110000000000000
+00011000000000000000011000000000
+00000001100000000000000001100000
+00000000000110000000000000000110
+00000000000000011000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000100000000100
+00100010000000010000100010000000
+01000010001000000001000010001000
+00000100001000100000000100001000
+10000000010000100010000000010000
+10001000000001000010001000000000
+00001000100000000000001000100000
+00010000100010000000010000100010
+00000001000010001000000000000010
+00100000000000001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000010101000000100
+01001010100000010001001010100000
+01000100101010000001000100101010
+00000100010010101000000100010010
+10100000010001001010100000010001
+00101010000001000100101010000001
+00010010101000000000010010101000
+00010001001010100000010001001010
+10000001000100101010000001000100
+10101000000100010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000110000000000110000000000
+01010011000000000001010011000000
+00000101001100000000000101001100
+00000000010100110000000000010100
+11000000000001010011000000000001
+01001100000000000101001100000000
+00010100110000000100010100110000
+00000001010011000000000001010011
+00000000000101001100000000000101
+00110000000000010100000000010000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000110000000000000000000000
+01000000000000000001000000000000
+00000100000000000000000100000000
+00000000010000000000000000010000
+00000001000001000000000000000001
+00000000000000000100000000000000
+00010000000000000000010000000000
+00000001000000000000000001000000
+00000000000100000000000000000100
+00000000000000010000000000110000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000110000000100000000000010
+00000000000000001000000000000000
+00100000000000000000100000000000
+00000010000000000000000010000000
+00000000001000000000000000001000
+00000000000000100000000000000000
+10000000000000000010000000000000
+00001000000000000000001000000000
+00000000100000000000000000100000
+00000000000010000000000000110000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000110000000100000000000100
+01100000000000010001100000000000
+01000110000000000000000110000000
+00000000011000000000000100011000
+00000000010001100000000000010001
+10000000000010000110000000000000
+00011000000000000000011000000000
+00010001100000000000000001100000
+00000001000110000000000000000110
+00000000000000011000000000110000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00010000000000010100000000000010
+01100000000000001001100000000000
+00100110000000000000100110000000
+00010110011000000000000010011000
+00000000001001100000000000001001
+10000000000000100110000000000000
+10011000000000000010011000000000
+00001001100000000000001001100000
+00000000100110000000000000100110
+00000000000010011000001000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100001000000100
+00110000100000010000110000100000
+01000011000010000001000011000010
+00000100001100001000000100001100
+00100000010000110000100000010000
+11000010000001000011000010000001
+00001100001000000100001100001000
+00010000110000100000010000110000
+10000001000011000010000001000011
+00001000000100001100000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01000000000000000000000000000000
+00110000000000000000110000000000
+00000011000000000000000011000000
+00000000001100000000000000001100
+00000000000000110000000000000000
+11000000000000000011000000000000
+00001100000000000000001100000000
+00000000110000000000000000110000
+00000000000011000000000000000011
+00000000000000001100000000110001
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000000000000001000000000
+00110000100000000000110000100000
+00000011000010000000000011000010
+00000000001100001000000000001100
+00100000000000110000100000000000
+11000010000000000011000010000000
+00001100001000000000001100001000
+00000000110000100000000000110000
+10000000000011000010000000000011
+00001000000000001100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100001000000100
+01100000100000010001100000100000
+01000110000010000001000110000010
+00000000011000001000000100011000
+00100000010001100000100000010001
+10000010000001000110000010000001
+00011000001000000100011000001000
+00010001100000100000010001100000
+10000001000110000010000001000110
+00001000000100011000000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01000000000000010100001000000000
+00100000100000000000100000100000
+00000010000010000000000010000010
+00000000001000001000000000001000
+00100000000000100000100000000000
+10000010000000000010000010000000
+00001000001000000000001000001000
+00000000100000100000000000100000
+10000000000010000010000000000010
+00001000000000001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01010000010000010100001000000100
+01100000100000010001100000100000
+01000110000010000001000110000010
+00000000011000001000000100011000
+00100000010001100000100000010001
+10000010000001000110000010000001
+00011000001000000100011000001000
+00010001100000100000010001100000
+10000001000110000010000001000110
+00001000000100011000000000010000
+01000000000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100000000000100
+01010000000000010001010000000000
+01000101000000000001000101000000
+00000000010100000000000100010100
+00000000010001010000000000010001
+01000000000001000101000000000001
+00010100000000000100010100000000
+00010001010000000000010001010000
+00000001000101000000000001000101
+00000000000100010100001000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01001000010000010000011000000000
+01000001100000000001000001100000
+00000100000110000000000100000110
+00000100010000011000000000010000
+01100000000001000001100000000001
+00000110000000000100000110000000
+00010000011000000000010000011000
+00000001000001100000000001000001
+10000000000100000110000000000100
+00011000000000010000000000010000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01001000000001000000001000000001
+00000000100000000100000000100000
+00010000000010000000010000000010
+00000001000000001000000001000000
+00100000000100000000100000000100
+00000010000000010000000010000000
+01000000001000000001000000001000
+00000100000000100000000100000000
+10000000010000000010000000010000
+00001000000001000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100011000000011
+01010001100000001101010001100000
+00110101000110000000110101000110
+00000011010100011000000011010100
+01100000001101010001100000001101
+01000110000000110101000110000000
+11010100011000000011010100011000
+00001101010001100000001101010001
+10000000110101000110000000110101
+00011000000011010100000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000010000011000000100
+01110001100000010001110001100000
+01000111000110000001000111000110
+00000100011100011000000100011100
+01100000010001110001100000010001
+11000110000001000111000110000001
+00011100011000000100011100011000
+00010001110001100000010001110001
+10000001000111000110000001000111
+00011000000100011100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000000010100011000000000
+01110001100000001001110001100000
+00100111000110000000100111000110
+00000010011100011000010110011100
+01100000001001110001100000001001
+11000110000000100111000110000000
+10011100011000000010011100011000
+00011001110001100000001001110001
+10000000100111000110000000100111
+00011000000010011100000000010001
+00010000000000000000000000000000
+00000000000000000000000000000000
+01010000010001010100011000000001
+01110001100000010101110001100000
+01010111000110000001010111000110
+00000101011100011000000101011100
+01100000010101110001100000010101
+11000110000001010111000110000001
+01011100011000000101011100011000
+00010101110001100000010101110001
+10000001010111000110000001010111
+00011000000101011100001000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01000000000000010000001000000001
+00100000100000000100100000100000
+00010010000010000000010010000010
+00000001001000001000000001001000
+00100000000100100000100000000100
+10000010000000010010000010000000
+01001000001000000001001000001000
+00000100100000100000000100100000
+10000000010010000010000000010010
+00001000000001001000000000010001
+01000000000000000000000000000000
+00000000000000000000000000000000
+01000000000000000000011000000000
+01100001100000000001100001100000
+00000110000110000000000110000110
+00000000011000011000000000011000
+01100000000001100001100000000001
+10000110000000000110000110000000
+00011000011000000000011000011000
+00000001100001100000000001100001
+10000000000110000110000000000110
+00011000000000011000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000010001010110000000000100
+01111000000000010001111000000000
+01000111100000000001000111100000
+00000100011110000000000000011110
+00000000010001111000000000010001
+11100000000001000111100000000001
+00011110000000000100011110000000
+00000001111000000000010001111000
+00000001000111100000000001000111
+10000000000100011100000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01000000000000010100001000000000
+01100000100000000001100000100000
+00000110000010000000000110000010
+00000000011000001000000000011000
+00100000000001100000100000000001
+10000010000000000110000010000000
+00011000001000000000011000001000
+00000001100000100000000001100000
+10000000000110000010000000000110
+00001000000000011000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000000010100001000000100
+00100000100000010000100000100000
+01000010000010000001000010000010
+00000100001000001000000000001000
+00100000010000100000100000010000
+10000010000001000010000010000001
+00001000001000000100001000001000
+00000000100000100000010000100000
+10000001000010000010000001000010
+00001000000100001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100001000000100
+01000000100000010001000000100000
+01000100000010000001000100000010
+00000100010000001000000100010000
+00100001010001000000100000010001
+00000010000001000100000010000001
+00010000001000000100010000001000
+00010001000000100000010001000000
+10000001000100000010000001000100
+00001000000100010000000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01000000000000000000001100000001
+00000000110000000001010000110000
+00000101000011000000000101000011
+00000000010100001100000000010100
+00110000000001010000110000000001
+01000011000000000101000011000000
+00010100001100000000010100001100
+00000001010000110000000001010000
+11000000000101000011000000000101
+00001100000000010100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000000000000100000000100
+01000010000000000001000010000001
+00000100001000000000000100001000
+00000000010000100000000000010000
+10000000000001000010000000000001
+00001000000000000100001000000000
+00010000100000000000010000100000
+00000000000010000000000001000010
+00000000000100001000000000000100
+00100000000000010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100001000000000
+00000000100000001000000000100000
+00100000000010000000100000000010
+00000010000000001000000010000000
+00100000001000000000100000001000
+00000010000000100000000010000000
+10000000001000000010000000001000
+00001000000000100000001000000000
+10000000100000000010000000100000
+00001000000010000000000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01000000000000010100000000000100
+01100000000000010001100000000000
+01000110000000000001000110000000
+00000100011000000000000000011000
+00000000010001100000000000010001
+10000000000001000110000000000001
+00011000000000000100011000000000
+00100100100000000000010001100000
+00000001000110000000000001000110
+00000000000100011000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000000010100000000000010
+01100000000000001001100000000000
+00000110000000000000100110000000
+00000010011000000000000010011000
+00000000001001100000000000001001
+10000000000100100110000000000000
+10011000000000000110011000000000
+00001001100000000000001001100000
+00000000100110000000000100100110
+00000000000010011000000000000001
+00010000000000000000000000000000
+00000000000000000000000000000000
+01000000010001010110000000000100
+00111000000000010000111000000000
+00000011100000000001000011100000
+00000100001110000000000100001110
+00000000010000111000000000010000
+11100000000000000011100000000001
+00001110000000000100001110000000
+00010000111000000000010000111000
+00000001000011100000000001000011
+10000000000100001100000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01010000000000000000000100000000
+00110000010000000000110000010000
+00000011000001000000000011000001
+00000000001100000100000000001100
+00010000000000110000010000000000
+11000001000000000011000001000000
+00001100000100000000001100000100
+00000000110000010000000000110000
+01000000000011000001000000000011
+00000100000000001100000000000001
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000000000000010100000000
+00110001010000000000110001010000
+00000011000101000000000011000101
+00010000001100010100000000001100
+01010000000000110001010000000000
+11000101000000000011000101000000
+00001100010100000000001100010100
+00000000110001010000000000110001
+01000000000011000101000000000011
+00010100000000001100001000010000
+01000000000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100001100000100
+01100000110000010001100000110000
+01000110000011000001000110000011
+00000100011000001100000100011000
+00110000010001100000110000010001
+10000011000001000110000011000001
+00011000001100000000011000001100
+00010001100000110000010001100000
+11000001000110000011000001000110
+00001100000100011000000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01000000000000010100000000000000
+00100000000000000000100000000000
+00000010000000000000000010000000
+00000000001000000000000000001000
+00000000000000100000000000000000
+10000000000000000010000000000000
+00001000000000000000001000000000
+00000000100000000000000000100000
+00000000000010000000000000000010
+00000000000000001000000000110000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000000000010000100001000100
+01100010000100010001100010000100
+01000110001000010001000110001000
+01000100011000100001000100011000
+10000100010001100010000100010001
+10001000010001000110001000010001
+00011000100001000000011000100001
+00010001100010000100010001100010
+00010001000110001000010001000110
+00100001000100011000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100000001000100
+01010000000100010001010000000100
+01000101000000010001000101000000
+01000100010100000001000100010100
+00000100010001010000000100010001
+01000000010001000101000000010001
+00010100000001000100010100000001
+00010100000000000100010001010000
+00010001000101000000010001000101
+00000001000100010100000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01000000000001010000100000100000
+01000010000010000001000010000010
+00000100001000001000000100001000
+00100000010000100000100000010000
+10000010000001000010000010000001
+00001000001000000100001000001000
+00010000100000100000010000100000
+10000001000010000010000001000010
+00001000000100001000001000000100
+00100000100000010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000101000000001
+00000010100000000100000010100000
+01010000001010000000010000001010
+00000001000000101000010001000000
+10100000000100000010100000000100
+00001010000000010000001010000000
+01000000101000000001000000101000
+00000100000010100000000100000010
+10000000010000001010000000010000
+00101000000001000000000000010001
+01000000000000000000000000000000
+00000000000000000000000000000000
+01000000010001010100110100000011
+01010011010000001101010011010000
+00010101001101000000110101001101
+00000011010100110100000011010100
+11010000001101010011010000001101
+01001101000000010101001101000000
+11010100110100000011010100110100
+00001101010011010000001101010011
+01000000110101001101000000110101
+00110100000011010100000000010001
+01010000000000000000000000000000
+00000000000000000000000000000000
+01000000000000010100100000000100
+01110010000000010001110010000000
+01000111001000000001000111001000
+00000000011100100000000100011100
+10000000010001110010000000010001
+11001000000001000111001000000001
+00011100100000000000011100100000
+00010001110010000000010001110010
+00000001000101001000000001000111
+00100000000100011100000000110001
+00010000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000010001100011000
+01001000110001100001001000110001
+10000100100011000110000100100011
+00011000010010001100011000010010
+00110001100001001000110001100001
+00100011000110000100100011000110
+00010010001100011000010010001100
+01100001001000110001100001001000
+11000110000100100011000110000100
+10001100011000010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+01001111111111111101001111111111
+11110100111111111111110100111111
+11111111010011111111111111010011
+11111111111101001111111111111101
+00111111111111110100111111111111
+11010011111111111111010011111111
+11111101001111111111111101001111
+11111111110100111111111111110100
+11111111111111010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000010110011011011
+00001011001101101100001011001101
+10110000101100110110110000101100
+11011011000010110011011011000010
+11001101101100001011001101101100
+00101100110110110000101100110110
+11000010110011011011000010110011
+01101100001011001101101100001011
+00110110110000101100110110110000
+10110011011011000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011001100111100
+01001100110011110001001100110011
+11000100110011001111000100110011
+00111100010011001100111100010011
+00110011110001001100110011110001
+00110011001111000100110011001111
+00010011001100111100010011001100
+11110001001100110011110001001100
+11001111000100110011001111000100
+11001100111100010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011101101111110
+01001110110111111001001110110111
+11100100111011011111100100111011
+01111110010011101101111110010011
+10110111111001001110110111111001
+00111011011111100100111011011111
+10010011101101111110010011101101
+11111001001110110111111001001110
+11011111100100111011011111100100
+11101101111110010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000001010000101
+00100000001000010000000100101000
+01000001000010100001000000010010
+10000010001100001010000011000101
+00101000010000000000101000011000
+00010010100001000010000010100001
+00000000001010000111000100001010
+00010100000000001000010000101100
+10100001000000000010010001000010
+00001001000100001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000100
+00010000000100010000010000000000
+01000010001010000001000000111000
+00000110000001000000000100001000
+00000000010100110010000000010100
+00011000000001010011010000000001
+11000000000000000111000100000000
+00010000000000000000010000111000
+00000001000000000010010001000000
+00000000000100000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011000010000101
+00100100100000010000100000000000
+01000011000000100001000010000000
+10000101001000000001000100001000
+00001000011000100000001000011000
+10000000100001110011001000100001
+11001010000010000111001000000010
+00010100000100101000010000100000
+00100001000000110000000001000010
+00000001000100001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000101
+00000000100100010000101100000000
+01000011000000000001000010000000
+00000100001000000001000100001111
+00000000010000110000000000010000
+10000000000001110000010000000001
+10001011000000000101001100000000
+00010100000000000000010000010000
+00000001000000000000000001000010
+00000000000100001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000000
+00010100001000001100110100001000
+00000001000010100000010011000000
+10000001000001000010000011000001
+00001000001100000000001000000000
+00010000100000110001010000100000
+00001000000010000000000000000010
+00000100110100001000000000110000
+00100000000000000000000000000000
+00000010000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000000001000000001
+00000000100100000000000000000000
+00000010000000000000010001000010
+00000011000000001000000000001000
+00100000000100000000100000001000
+00000010000000100000000010000000
+00000000001000000000000000001000
+00000100100000100000000100110000
+10000000000000000000000000000000
+00001000000000000000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000001000010000001
+00100010101000000000100110001100
+00000001001000100000100010001000
+10000011000001100010000000001010
+10001000001100000010001000000100
+00001000100000010010111000100000
+00001000100010000000000000100010
+00000000111110001000000100111110
+00100000000010011000110000000010
+00100010000000001000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000000100000000011
+00000010000000001100110110100000
+00000001001010000000010001001000
+00000010000000100000000000001000
+10000000001000000000000000000000
+00001000000000000010001000000000
+00001010100000000000000000100000
+00001000110010000000001100011010
+00000000000010001010010000000010
+00100000000000001000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000011101010000111
+00101010001000010000010010101000
+01000011001000010001000010001000
+10000101000100101010000101000000
+10101000011000000010101000010000
+01001010100001100001001010100001
+10000001101010000100000100101010
+00010100111010001000010100000010
+00100001000000001000100001000000
+00100010000100000000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000001100000000100
+00101110000000010000100010000000
+01000011001010000001000011101000
+00000101000010100000000100000001
+10000000011100000010000000010000
+11101010000001010010011000000001
+00001100100000000100001100100000
+00010100110110100000011100100110
+00000001000001111000000001000001
+00101001000100000000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000000000010000100
+00000000101000010000110100000100
+01000011000000100001000010100010
+10000000001010000010000101001010
+00001000011100000000001000010000
+11010000100001100001100000100000
+01001000000010000101001000000010
+00010100100000001000011100110000
+10100001000010100000100001000010
+00000010000100001000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000100000000000000000111
+00100000000000010000110000000000
+01000001010010000001000011010010
+00000110000001000000000101001000
+00000000011000110100000000011100
+01110000000001010011010000000001
+01000000000000000101000001000000
+00011100100000100100011000100000
+10000001110001000000000001110001
+00000000000100001000001000000100
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000010000010000111
+00000100101000010000100000100000
+01110000010000100001010000010000
+10000101001101000010000111001110
+00001000010100100000001000011100
+01000010100001110000000000100001
+00000001000010000111001110000010
+00011000100000001000011100010000
+00100001110011010000100001000000
+00000001000100001000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000001001000000001
+00001000000000000000010100000100
+01000010000000000000100010100010
+00000101000110001000000100001000
+00000000001000100100100000010000
+01000000000001000010100010000000
+00000000001000000111000001001000
+00010100100100000000011000100000
+10000001000000000000000000000011
+11000000000000000100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000001
+00100100101000000000100100000000
+01000010010010100000010011000010
+10000111001001000010000100001110
+00001000000100110100001000010000
+10000000100001000011100000100000
+00001000000010000111000001000010
+00010100000000101000010100111000
+10100001000000000000000000000010
+01000010000000001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000100001000000000000011
+00100000100000000000000100100100
+00000001100010000000000011000000
+00000001001100000000000011001000
+00100000000100101000000000000000
+00100010000000000010000000000000
+00001001000000000010001100000000
+00001100001000100100000100101000
+00000000110011010010000000000001
+00001000000000001000000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000001000000010000
+01000000100000000000000000000000
+00000000000000000001000000010000
+00000000000000000000000000000000
+00000000000100000000000000000000
+10010000000000000000000000000000
+00000000000000000001000000000000
+00000000100100000010000000000000
+00000000000000000000000000000000
+00000000001000001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00111100001111000011000000000000
+10000000100000000000000000000000
+00010000000000000000000000110000
+10000000000000001000000000000000
+00000000000100000010000000010000
+00110000100000000000000010000000
+00000000000000000000000000100000
+00010000001100000000000000000000
+01000000000000000000000000010000
+00000000000000000000111100001111
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000011001
+10000000000110011000000000111111
+11011001101111111101100110000000
+00011001101111111101100100000000
+00011111101100101011100011001111
+10000000000000000001100110100110
+00000000000000011000111101001011
+01101000010000000001100110000000
+00011001110000000011111111011001
+10111111110110011000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000001000000000111110
+10111110101111101011111010000000
+00000000000000000010000000000000
+00010010000100101000011010000010
+00010110100000000001011010100000
+00000000000001100000010000000000
+00010000000000000000000000000000
+00000000000000000010100000010000
+00111110100101101100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010001000
+01000100100000010100000110000000
+00000000000000000000000000000000
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000110000000000000000000000
+00000000000000000000000000000000
+00000000000000001000000101111000
+01000001101100010000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111101111111111111111111111
+11000000000000000000000000000000
+00000000001111111111111111101111
+11111101110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000101101
+11111111101011101111111111000000
+00000000000000000000000000000000
+00111111101111111111111111111110
+00000000000000000000000000000000
+00000000001101111111111011111111
+01111111110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111101
+11111111111111111011111111000000
+00000000000000000000000000000000
+00111111101111111111111111111111
+11000000000000000000000000000000
+00000000001111111111111111111111
+11111111110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000001111111111111111111111
+11111111110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111100111111
+11000000000000000000000000000000
+00000000001111111111111111111111
+11111111110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111101111111111111111000000
+00000000000000000000000000000000
+00111111111111111011111111111111
+11000000000000000000000000000000
+00000000001111111111111100111111
+11111111110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000011000111
+00100100101000010000100000001000
+01000001000000100001000010010010
+10000100000000001010000000001000
+00101000010000010000101000011000
+10110010110001010000010010100001
+00001000001010000100000100001010
+00010000101100101000011100000100
+10110001000001000000100001000000
+00000010000100000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000001000111
+00010000100000010000110000000000
+01000011000000000001000001110000
+00000101000010000000000000001001
+00000000010000100000000000011100
+01000000000001100000100000000001
+00000000000000000111001000000000
+00010000001000000000011100101100
+00000001000010000000000001000000
+00000000000100000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000001000011000111
+00101000001000010000100100101100
+01000011000010100001000010000000
+10000110000001000010000000001000
+00001000010000010000001100011100
+10000000100001010000010000100001
+00001000000010000101000000000001
+00010000100000001000011100000000
+00000001000011000000010001000000
+00001010000100000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000001000000000100
+00101000000000010000010100000000
+01000011000000000001000010000000
+00000100000001000000000000001101
+00000000010000000000000000011000
+00000000000001010000010000000001
+00000010000000000110000100000001
+00010000100000000000010000010000
+00010001000010110010000001000000
+00001000000100000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000010001011000000
+00100000101000000000000100001000
+00000010000000100000000010000000
+10000000000000000010000000000101
+00001000001100100000001000000100
+00100000110000000000000000100000
+10001001000010000010000000000010
+00001100000000000100000000000000
+00110000000000010000010000000000
+00000001000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000000000001000000
+00000000000000000000010000100000
+00000000000010000000000001000010
+00000000000000001000000000001100
+00100000000100010000100000001000
+00000010000000000000000010000000
+01000000001000000001000000001000
+00001100010000100100000000100000
+10000000000000000010000000000001
+00001000000000000100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000001101000000000
+00100110001000000000100110101100
+00000010001000100000010010001000
+10000001000001100010000000001101
+10001000001100100010001100000100
+10011000100000000000011000100000
+10001001100010000010000000100010
+00001100100010000100000000011110
+00100000000010011000000000000010
+00101010000000001000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000010100000000000
+00000110100000000000000010000000
+00000010001000000000010000001000
+00000001000000100000000000000010
+10000000001000000010000000000000
+10001000000000000000011000000000
+00001000100000000000000000100000
+00000100000110000100000000001010
+00000000000010001000000000000010
+00100000000000001000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000000101010000111
+00101010101000010000010110001000
+01000001001010100001000010001010
+10000101000100101010000110000001
+10101000011000000010101000010000
+01101000100001010001001010100001
+01000001101010000100000000101001
+00010100000010100000011100100010
+10000001000001011010000001000001
+00101001000100000000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000010100000000111
+00110010000000010000110010000000
+01010011001000000001000001101000
+00000111000010100000000101000100
+10000000011100100010000000010000
+10101000000001100010001010000001
+10001000100000000100000000100001
+00011000110010000100011100010110
+00000001000010001000010001000010
+00100001000100000100001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000111
+00110000001000010000110100001000
+01000010000000010001000010100000
+10000111001010000010000110001000
+00001000010100010000001000010000
+01000010100001010000100000100001
+01000101000010000101000000000010
+00010100111000001000011100100000
+00100001000001100000000001000001
+00000001000100001000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000100000001000000000111
+00010100000000011100010000100000
+01100011000000000001110001000000
+00000101000111000000000101001100
+00000000010100100000000000011100
+11000010000001110011010000000001
+11001100000000000101000010000000
+00011100010100000100011100010100
+00000001110011000000010001110010
+00000001000111001100001000000100
+00000000000000000000000000000000
+00000000000000000000000000000000
+00001000000000000000001010000100
+00001000001000010000000000001000
+01000010010000010001000010000000
+10000111000000000010000101000010
+00001000010000100000001000010100
+00010000100001110010100010100001
+01001010000010000101000000000010
+00011100000000001000010100100000
+00110001100001100000010001000010
+01000010000100000000001000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000001000000000000
+00000100100000000000000100100000
+00000010000010000000000011110010
+00000011000010001000000010001001
+00100000000100100000100000001000
+01100010000001000010000000000000
+10000001001000000011000000001000
+00011000100100100000001000101000
+10000000010010010010000000000010
+00001001000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000001000010000000
+00100100001000000000100000101000
+00000011000000100000000010010000
+10000011001001000010000001001100
+00001000000000111100001000000100
+10010010100001000010100000100000
+01001000000010000011000001000001
+00010100100000000100000100101000
+00100000000011000000010000000010
+01000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000100001010001000000000
+00100000000000000000101000000000
+00000010100000010000000011000000
+00000001001000000000000001001000
+00000000001000111000000000000000
+10000000000000110010000010000000
+00000000000000000000000010000001
+00000000100100000000000000110000
+00000000100010000000000000000011
+10000001000000000000000000000100
+00100000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000001000000000000
+01000000000000000000000000000000
+00000000000000000001000000010000
+00000000000000000000000000000000
+00000000000100000000000000000000
+10010000000000000000000000000000
+00000000000000000001000010000000
+00100000100100000000000000000000
+00000000000000000000000000000000
+00000000001000001000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00111100001111000011000000000000
+10100000000000000000000000000000
+00010000000000000000000000110000
+10000000000000001000000000000000
+00000000000000000010000000010000
+10110000100000000000000010000000
+00000000000000000001000000100000
+00010000101100000000000001000000
+11000000000000000000000000010000
+00000000000000000000111100001111
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000100000000111111
+11011001101111111101100110000000
+00100110010110011001100100000000
+00011111001100010111100000011101
+11011001100000000010011001000000
+00000000000010001000001111001000
+01101111100000000001100110000000
+00000000110000000011111111011001
+10111111110110011000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000101000
+00101001001010000010000001000000
+00000000000000000010000010000000
+00000100100001101000010010000110
+00000000000000000000000000100000
+10000000000000101001001000010000
+10000100000000000000000000000000
+00000000100000000010100000000000
+00101000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000010000100
+10000001000000010101000100000000
+00000000000000000000000000000000
+11000000000000000000000000000000
+00000000000000000000000000000000
+00000000100000000000000000000000
+00000000000000000000000000000000
+00000000000000001000000101111000
+01001000101100010100000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000101111
+11111011111111111110111111000000
+00000000000000000000000000000000
+00011111100111111001111111011111
+11000000000000000000000000000000
+00000000001011111111111111111111
+11110111110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+01011111010011101111111111000000
+00000000000000000000000000000000
+00101111011011110110111111111101
+01000000000000000000000000000000
+00000000001111110011111101001111
+11111111110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000011111
+11111111101111111111111111000000
+00000000000000000000000000000000
+00101111001111111011111111111111
+11000000000000000000000000000000
+00000000001111110111111110111111
+11111111110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000001111111111111011111111
+11111111110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111110111111
+11000000000000000000000000000000
+00000000001111111111111111111111
+11111111110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000011111111111111
+11111111111111111100000000000000
+00000000000000000000000000111111
+11111111111111111111111111000000
+00000000000000000000000000000000
+00111111111111111111111111111111
+11000000000000000000000000000000
+00000000001111111111111111111111
+11111111110000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00110000000000000010000000000001
+00000010000000000000000000000000
+00110000000000000100001100001100
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00110000000000000010000000000001
+00000010000000100000000000000000
+00110000000000000100001100000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00110000000000000000000000000001
+00000000000000001010100001101000
+00110000000000001000000000000001
+00000000000000000000000000000011
+00110000000000000100000000001100
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00110000000000001000000000000001
+00000000000000000000000000000101
+00110000000000001010000000000001
+00000000000000000000000000000000
+00110000000000000000000000000001
+00000000000000001110000101011010
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
+00000000000000000000000000000000
diff --git a/drivers/dahdi/voicebus.c b/drivers/dahdi/voicebus.c
new file mode 100644
index 0000000..40494e5
--- /dev/null
+++ b/drivers/dahdi/voicebus.c
@@ -0,0 +1,1492 @@
+/*
+ * VoiceBus(tm) Interface Library.
+ *
+ * Written by Shaun Ruffell <sruffell@digium.com>
+ * and based on previous work by Mark Spencer <markster@digium.com>,
+ * Matthew Fredrickson <creslin@digium.com>, and
+ * Michael Spiceland <mspiceland@digium.com>
+ *
+ * Copyright (C) 2007-2008 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.
+ *
+ * VoiceBus is a registered trademark of Digium.
+ *
+ * \todo Make the client drivers back out gracefully when presented with a
+ * signal.
+ * \todo Modify clients to sleep with timeout when waiting for interrupt.
+ * \todo Check on a 64-bit CPU / Kernel
+ */
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+
+#include "voicebus.h"
+
+#define assert(__x__) BUG_ON(!(__x__))
+
+#define INTERRUPT 0 /* Run the deferred processing in the ISR. */
+#define TASKLET 1 /* Run in a tasklet. */
+#define TIMER 2 /* Run in a system timer. */
+#define WORKQUEUE 3 /* Run in a workqueue. */
+#ifndef VOICEBUS_DEFERRED
+#define VOICEBUS_DEFERRED INTERRUPT
+#endif
+#if VOICEBUS_DEFERRED == WORKQUEUE
+#define VOICEBUS_ALLOC_FLAGS GFP_KERNEL
+#else
+#define VOICEBUS_ALLOC_FLAGS GFP_ATOMIC
+#endif
+
+#if VOICEBUS_DEFERRED == TIMER
+#if HZ < 1000
+/* \todo Put an error message here. */
+#endif
+#endif
+
+/*! The number of descriptors in both the tx and rx descriptor ring. */
+#define DRING_SIZE (1 << 5) /* Must be a power of 2 */
+#define DRING_MASK (DRING_SIZE-1)
+
+/* Interrupt status' reported in SR_CSR5 */
+#define TX_COMPLETE_INTERRUPT 0x00000001
+#define TX_STOPPED_INTERRUPT 0x00000002
+#define TX_UNAVAILABLE_INTERRUPT 0x00000004
+#define TX_JABBER_TIMEOUT_INTERRUPT 0x00000008
+#define TX_UNDERFLOW_INTERRUPT 0x00000020
+#define RX_COMPLETE_INTERRUPT 0x00000040
+#define RX_UNAVAILABLE_INTERRUPT 0x00000080
+#define RX_STOPPED_INTERRUPT 0x00000100
+#define RX_WATCHDOG_TIMEOUT_INTERRUPT 0x00000200
+#define TIMER_INTERRUPT 0x00000800
+#define FATAL_BUS_ERROR_INTERRUPT 0x00002000
+#define ABNORMAL_INTERRUPT_SUMMARY 0x00008000
+#define NORMAL_INTERRUPT_SUMMARY 0x00010000
+
+#define SR_CSR5 0x0028
+#define NAR_CSR6 0x0030
+
+#define IER_CSR7 0x0038
+#define CSR7_TCIE 0x00000001 /* tx complete */
+#define CSR7_TPSIE 0x00000002 /* tx processor stopped */
+#define CSR7_TDUIE 0x00000004 /* tx desc unavailable */
+#define CSR7_TUIE 0x00000020 /* tx underflow */
+#define CSR7_RCIE 0x00000040 /* rx complete */
+#define CSR7_RUIE 0x00000080 /* rx desc unavailable */
+#define CSR7_RSIE 0x00000100 /* rx processor stopped */
+#define CSR7_FBEIE 0x00002000 /* fatal bus error */
+#define CSR7_AIE 0x00008000 /* abnormal enable */
+#define CSR7_NIE 0x00010000 /* normal enable */
+
+#define DEFAULT_INTERRUPTS ( CSR7_TCIE | CSR7_TPSIE | CSR7_TDUIE | \
+ CSR7_RUIE | CSR7_RSIE | CSR7_FBEIE | \
+ CSR7_AIE | CSR7_NIE)
+
+#define CSR9 0x0048
+#define CSR9_MDC 0x00010000
+#define CSR9_MDO 0x00020000
+#define CSR9_MMC 0x00040000
+#define CSR9_MDI 0x00080000
+
+#define OWN_BIT (1 << 31)
+
+/* In memory structure shared by the host and the adapter. */
+struct voicebus_descriptor {
+ u32 des0;
+ u32 des1;
+ u32 buffer1;
+ u32 container; /* Unused */
+} __attribute__((packed));
+
+struct voicebus_descriptor_list {
+ /* Pointer to an array of descriptors to give to hardware. */
+ struct voicebus_descriptor* desc;
+ /* Read completed buffers from the head. */
+ unsigned int head;
+ /* Write ready buffers to the tail. */
+ unsigned int tail;
+ /* Array to save the kernel virtual address of pending buffers. */
+ void * pending[DRING_SIZE];
+ /* PCI Bus address of the descriptor list. */
+ dma_addr_t desc_dma;
+ /*! either DMA_FROM_DEVICE or DMA_TO_DEVICE */
+ unsigned int direction;
+ /*! The number of buffers currently submitted to the hardware. */
+ atomic_t count;
+ /*! The number of bytes to pad each descriptor for cache alignment. */
+ unsigned int padding;
+};
+
+
+/*! * \brief Represents a VoiceBus interface on a Digium telephony card.
+ */
+struct voicebus {
+ /*! Name of this card. */
+ const char *board_name;
+ /*! The system pci device for this VoiceBus interface. */
+ struct pci_dev *pdev;
+ /*! Protects access to card registers and this structure. You should
+ * hold this lock before accessing most of the members of this data
+ * structure or the card registers. */
+ spinlock_t lock;
+ /*! The size of the transmit and receive buffers for this card. */
+ u32 framesize;
+ /*! The number of u32s in the host system cache line. */
+ u8 cache_line_size;
+ /*! Pool to allocate memory for the tx and rx descriptor rings. */
+ struct voicebus_descriptor_list rxd;
+ struct voicebus_descriptor_list txd;
+ /*! Level of debugging information. 0=None, 5=Insane. */
+ atomic_t debuglevel;
+ /*! Cache of buffer objects. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ kmem_cache_t *buffer_cache;
+#else
+ struct kmem_cache *buffer_cache;
+#endif
+ /*! Base address of the VoiceBus interface registers in I/O space. */
+ u32 iobase;
+ /*! The IRQ line for this VoiceBus interface. */
+ unsigned int irq;
+#if VOICEBUS_DEFERRED == WORKQUEUE
+ /*! Process buffers in the context of this workqueue. */
+ struct workqueue_struct *workqueue;
+ /*! Work item to process tx / rx buffers. */
+ struct work_struct workitem;
+#elif VOICEBUS_DEFERRED == TASKLET
+ /*! Process buffers in the context of a tasklet. */
+ struct tasklet_struct tasklet;
+#elif VOICEBUS_DEFERRED == TIMER
+ /*! Process buffers in a timer without generating interrupts. */
+ struct timer_list timer;
+#endif
+ /*! Callback function to board specific module to process frames. */
+ void (*handle_receive)(void *vbb, void *context);
+ void (*handle_transmit)(void *vbb, void *context);
+ /*! Data to pass to the receive and transmit callback. */
+ void *context;
+ struct completion stopped_completion;
+ /*! Flags */
+ unsigned long flags;
+ /* \todo see about removing this... */
+ u32 sdi;
+ /*! Number of tx buffers to queue up before enabling interrupts. */
+ unsigned int min_tx_buffer_count;
+};
+
+/*
+ * Use the following macros to lock the VoiceBus interface, and it won't
+ * matter if the deferred processing is running inside the interrupt handler,
+ * in a tasklet, or in a workqueue.
+ */
+#if VOICEBUS_DEFERRED == WORKQUEUE
+/*
+ * When the deferred processing is running in a workqueue, voicebus will never
+ * be locked from the context of the interrupt handler, and therefore we do
+ * not need to lock interrupts.
+ */
+#define LOCKS_VOICEBUS
+#define LOCKS_FROM_DEFERRED
+#define VBLOCK(_vb_) spin_lock(&((_vb_)->lock))
+#define VBUNLOCK(_vb_) spin_unlock(&((_vb_)->lock))
+#define VBLOCK_FROM_DEFERRED(_vb_) spin_lock(&((_vb_)->lock))
+#define VBUNLOCK_FROM_DEFERRED(_vb_) spin_lock(&((_vb_)->lock))
+#else
+#define LOCKS_VOICEBUS unsigned long _irqflags
+#define LOCKS_FROM_DEFERRED
+#define VBLOCK(_vb_) spin_lock_irqsave(&((_vb_)->lock), _irqflags)
+#define VBUNLOCK(_vb_) spin_unlock_irqrestore(&((_vb_)->lock), _irqflags)
+#define VBLOCK_FROM_DEFERRED(_vb_) spin_lock(&((_vb_)->lock))
+#define VBUNLOCK_FROM_DEFERRED(_vb_) spin_lock(&((_vb_)->lock))
+#endif
+
+#define VB_PRINTK(_vb, _lvl, _fmt, _args...) \
+ printk(KERN_##_lvl "%s: " _fmt, (_vb)->board_name, ## _args)
+
+/* Bit definitions for struct voicebus.flags */
+#define TX_UNDERRUN 1
+#define RX_UNDERRUN 2
+#define IN_DEFERRED_PROCESSING 3
+#define STOP 4
+
+#if VOICEBUS_DEFERRED == WORKQUEUE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+/*! \brief Make the current task real-time. */
+static void
+vb_setup_deferred(void *data)
+#else
+static void
+vb_setup_deferred(struct work_struct *work)
+#endif
+{
+ struct sched_param param = { .sched_priority = 99 };
+ sched_setscheduler(current, SCHED_FIFO, &param);
+}
+/*! \brief Schedule a work item to make the voicebus workqueue real-time. */
+static void
+vb_set_workqueue_priority(struct voicebus *vb)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ DECLARE_WORK(deferred_setup, vb_setup_deferred, NULL);
+#else
+ DECLARE_WORK(deferred_setup, vb_setup_deferred);
+#endif
+ queue_work(vb->workqueue, &deferred_setup);
+ flush_workqueue(vb->workqueue);
+}
+#endif
+#endif
+
+#ifdef DBG
+static inline int
+assert_in_vb_deferred(struct voicebus *vb)
+{
+ assert(test_bit(IN_DEFERRED_PROCESSING, &vb->flags));
+}
+
+static inline void
+start_vb_deferred(struct voicebus *vb)
+{
+ set_bit(IN_DEFERRED_PROCESSING, &vb->flags);
+}
+
+static inline void
+stop_vb_deferred(struct voicebus *vb)
+{
+ clear_bit(IN_DEFERRED_PROCESSING, &vb->flags);
+}
+#else
+#define assert_in_vb_deferred(_x_) do {;} while(0)
+#define start_vb_deferred(_x_) do {;} while(0)
+#define stop_vb_deferred(_x_) do {;} while(0)
+#endif
+
+static inline struct voicebus_descriptor *
+vb_descriptor(struct voicebus_descriptor_list *dl, int index)
+{
+ struct voicebus_descriptor *d;
+ d = (struct voicebus_descriptor *)((u8*)dl->desc +
+ ((sizeof(*d) + dl->padding) * index));
+ return d;
+}
+
+static int
+vb_initialize_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl,
+ u32 des1, unsigned int direction)
+{
+ int i;
+ struct voicebus_descriptor *d;
+ const u32 END_OF_RING = 0x02000000;
+
+ assert(dl);
+
+ /*
+ * Add some padding to each descriptor to ensure that they are
+ * aligned on host system cache-line boundaries, but only for the
+ * cache-line sizes that we support.
+ *
+ */
+ if ((0x08 == vb->cache_line_size) || (0x10 == vb->cache_line_size) ||
+ (0x20 == vb->cache_line_size))
+ {
+ dl->padding = (vb->cache_line_size*sizeof(u32)) - sizeof(*d);
+ } else {
+ dl->padding = 0;
+ }
+
+ dl->desc = pci_alloc_consistent(vb->pdev,
+ (sizeof(*d) + dl->padding) * DRING_SIZE, &dl->desc_dma);
+ if (!dl->desc) {
+ return -ENOMEM;
+ }
+
+ memset(dl->desc, 0, (sizeof(*d) + dl->padding) * DRING_SIZE);
+ for ( i = 0; i < DRING_SIZE; ++i) {
+ d = vb_descriptor(dl, i);
+ d->des1 = des1;
+ }
+ d->des1 |= cpu_to_le32(END_OF_RING);
+ dl->direction = direction;
+ atomic_set(&dl->count, 0);
+ return 0;
+}
+
+static int
+vb_initialize_tx_descriptors(struct voicebus *vb)
+{
+ return vb_initialize_descriptors(
+ vb, &vb->txd, 0xe4800000 | vb->framesize, DMA_TO_DEVICE);
+}
+
+static int
+vb_initialize_rx_descriptors(struct voicebus *vb)
+{
+ return vb_initialize_descriptors(
+ vb, &vb->rxd, vb->framesize, DMA_FROM_DEVICE);
+}
+
+/*! \brief Use to set the minimum number of buffers queued to the hardware
+ * before enabling interrupts.
+ */
+int
+voicebus_set_minlatency(struct voicebus *vb, unsigned int ms)
+{
+ LOCKS_VOICEBUS;
+ /*
+ * One millisecond of latency means that we have 3 buffers pending,
+ * since two are always going to be waiting in the TX fifo on the
+ * interface chip.
+ *
+ */
+#define MESSAGE "%d ms is an invalid value for minumum latency. Setting to %d ms.\n"
+ if ( DRING_SIZE < ms ) {
+ VB_PRINTK(vb, WARNING, MESSAGE, ms, DRING_SIZE);
+ return -EINVAL;
+ } else if (VOICEBUS_DEFAULT_LATENCY > ms ) {
+ VB_PRINTK(vb, WARNING, MESSAGE, ms, VOICEBUS_DEFAULT_LATENCY);
+ return -EINVAL;
+ }
+ VBLOCK(vb);
+ vb->min_tx_buffer_count = ms;
+ VBUNLOCK(vb);
+ return 0;
+}
+
+/*! \brief Returns the number of buffers currently on the transmit queue. */
+int
+voicebus_current_latency(struct voicebus *vb)
+{
+ LOCKS_VOICEBUS;
+ int latency;
+ VBLOCK(vb);
+ latency = vb->min_tx_buffer_count;
+ VBUNLOCK(vb);
+ return latency;
+}
+
+/*!
+ * \brief Read one of the hardware control registers without acquiring locks.
+ */
+static inline u32
+__vb_getctl(struct voicebus *vb, u32 addr)
+{
+ return le32_to_cpu(inl(vb->iobase + addr));
+}
+
+/*!
+ * \brief Read one of the hardware control registers with locks held.
+ */
+static inline u32
+vb_getctl(struct voicebus *vb, u32 addr)
+{
+ LOCKS_VOICEBUS;
+ u32 val;
+ VBLOCK(vb);
+ val = __vb_getctl(vb, addr);
+ VBUNLOCK(vb);
+ return val;
+}
+
+/*!
+ * \brief Returns whether or not the interface is running.
+ *
+ * NOTE: Running in this case means whether or not the hardware reports the
+ * transmit processor in any state but stopped.
+ *
+ * \return 1 of the process is stopped, 0 if running.
+ */
+static int
+vb_is_stopped(struct voicebus *vb)
+{
+ u32 reg;
+ reg = vb_getctl(vb, SR_CSR5);
+ reg = (reg >> 17)&0x38;
+ return (0 == reg) ? 1 : 0;
+}
+
+static void
+vb_cleanup_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
+{
+ unsigned int i;
+ struct voicebus_descriptor *d;
+
+ assert(vb_is_stopped(vb));
+
+ for (i=0; i < DRING_SIZE; ++i) {
+ d = vb_descriptor(dl, i);
+ if (d->buffer1) {
+ d->buffer1 = 0;
+ assert(dl->pending[i]);
+ voicebus_free(vb, dl->pending[i]);
+ dl->pending[i] = NULL;
+ }
+ d->des0 &= ~OWN_BIT;
+ }
+ dl->head = 0;
+ dl->tail = 0;
+ atomic_set(&dl->count, 0);
+}
+
+static void
+vb_free_descriptors(struct voicebus *vb, struct voicebus_descriptor_list *dl)
+{
+ if (NULL == dl->desc) {
+ WARN_ON(1);
+ return;
+ }
+ vb_cleanup_descriptors(vb, dl);
+ pci_free_consistent(
+ vb->pdev,
+ (sizeof(struct voicebus_descriptor)+dl->padding)*DRING_SIZE,
+ dl->desc, dl->desc_dma);
+}
+
+/*!
+ * \brief Write one of the hardware control registers without acquiring locks.
+ */
+static inline void
+__vb_setctl(struct voicebus *vb, u32 addr, u32 val)
+{
+ wmb();
+ outl(cpu_to_le32(val), vb->iobase + addr);
+}
+
+/*!
+ * \brief Write one of the hardware control registers with locks held.
+ */
+static inline void
+vb_setctl(struct voicebus *vb, u32 addr, u32 val)
+{
+ LOCKS_VOICEBUS;
+ VBLOCK(vb);
+ __vb_setctl(vb, addr, val);
+ VBUNLOCK(vb);
+}
+
+static int
+__vb_sdi_clk(struct voicebus* vb)
+{
+ unsigned int ret;
+ vb->sdi &= ~CSR9_MDC;
+ __vb_setctl(vb, 0x0048, vb->sdi);
+ ret = __vb_getctl(vb, 0x0048);
+ vb->sdi |= CSR9_MDC;
+ __vb_setctl(vb, 0x0048, vb->sdi);
+ return (ret & CSR9_MDI) ? 1: 0;
+}
+
+static void
+__vb_sdi_sendbits(struct voicebus *vb, u32 bits, int count)
+{
+ vb->sdi &= ~CSR9_MMC;
+ __vb_setctl(vb, 0x0048, vb->sdi);
+ while(count--) {
+ if (bits & (1 << count)) {
+ vb->sdi |= CSR9_MDO;
+ } else {
+ vb->sdi &= ~CSR9_MDO;
+ }
+ __vb_sdi_clk(vb);
+ }
+}
+
+#if 0 /* this function might be useful in the future for debugging. */
+static unsigned int
+__vb_sdi_recvbits(struct voicebus *vb, int count)
+{
+ unsigned int bits=0;
+ vb->sdi |= CSR9_MMC;
+ __vb_setctl(vb, 0x0048, vb->sdi);
+ while(count--) {
+ bits <<= 1;
+ if (__vb_sdi_clk(vb))
+ bits |= 1;
+ else
+ bits &= ~1;
+ }
+ return bits;
+}
+#endif
+
+static void
+vb_setsdi(struct voicebus *vb, int addr, u16 val)
+{
+ LOCKS_VOICEBUS;
+ u32 bits;
+ /* Send preamble */
+ bits = 0xffffffff;
+ VBLOCK(vb);
+ __vb_sdi_sendbits(vb, bits, 32);
+ bits = (0x5 << 12) | (1 << 7) | (addr << 2) | 0x2;
+ __vb_sdi_sendbits(vb, bits, 16);
+ __vb_sdi_sendbits(vb, val, 16);
+ VBUNLOCK(vb);
+}
+
+static void
+vb_enable_io_access(struct voicebus *vb)
+{
+ LOCKS_VOICEBUS;
+ u32 reg;
+ assert(vb->pdev);
+ VBLOCK(vb);
+ pci_read_config_dword(vb->pdev, 0x0004, &reg);
+ reg |= 0x00000007;
+ pci_write_config_dword(vb->pdev, 0x0004, reg);
+ VBUNLOCK(vb);
+}
+
+/*! \todo Insert comments...
+ * context: !in_interrupt()
+ */
+void*
+voicebus_alloc(struct voicebus *vb)
+{
+ void *vbb;
+ vbb = kmem_cache_alloc(vb->buffer_cache, VOICEBUS_ALLOC_FLAGS);
+ return vbb;
+}
+
+void
+voicebus_setdebuglevel(struct voicebus *vb, u32 level)
+{
+ atomic_set(&vb->debuglevel, level);
+}
+
+int
+voicebus_getdebuglevel(struct voicebus *vb)
+{
+ return atomic_read(&vb->debuglevel);
+}
+
+/*! \brief Resets the voicebus hardware interface. */
+static int
+vb_reset_interface(struct voicebus *vb)
+{
+ unsigned long timeout;
+ u32 reg;
+ u32 pci_access;
+ const u32 DEFAULT_PCI_ACCESS = 0xfff80002;
+ BUG_ON(in_interrupt());
+
+ switch (vb->cache_line_size) {
+ case 0x08:
+ pci_access = DEFAULT_PCI_ACCESS | (0x1 << 14);
+ break;
+ case 0x10:
+ pci_access = DEFAULT_PCI_ACCESS | (0x2 << 14);
+ break;
+ case 0x20:
+ pci_access = DEFAULT_PCI_ACCESS | (0x3 << 14);
+ break;
+ default:
+ VB_PRINTK(vb, WARNING, "Host system set a cache size "\
+ "of %d which is not supported. " \
+ "Disabling memory write line and memory read line.",
+ vb->cache_line_size);
+ pci_access = 0xfe584202;
+ break;
+ }
+
+ /* The transmit and receive descriptors will have the same padding. */
+ pci_access |= ((vb->txd.padding / sizeof(u32)) << 2) & 0x7c;
+
+ vb_setctl(vb, 0x0000, pci_access | 1);
+
+ timeout = jiffies + HZ/10; /* 100ms interval */
+ do {
+ reg = vb_getctl(vb, 0x0000);
+ } while ((reg & 0x00000001) && time_before(jiffies, timeout));
+
+ if (reg & 0x00000001) {
+ VB_PRINTK(vb, ERR, "Hardware did not come out of reset "\
+ "within 100ms!");
+ return -EIO;
+ }
+
+ vb_setctl(vb, 0x0000, pci_access);
+
+ vb_cleanup_descriptors(vb, &vb->txd);
+ vb_cleanup_descriptors(vb, &vb->rxd);
+
+ /* Pass bad packets, runt packets, disable SQE function,
+ * store-and-forward */
+ vb_setctl(vb, 0x0030, 0x00280048);
+ /* ...disable jabber and the receive watchdog. */
+ vb_setctl(vb, 0x0078, 0x00000013);
+
+ /* Tell the card where the descriptors are in host memory. */
+ vb_setctl(vb, 0x0020, (u32)vb->txd.desc_dma);
+ vb_setctl(vb, 0x0018, (u32)vb->rxd.desc_dma);
+
+ reg = vb_getctl(vb, 0x00fc);
+ vb_setctl(vb, 0x00fc, (reg & ~0x7) | 0x7);
+ vb_setsdi(vb, 0x00, 0x0100);
+ vb_setsdi(vb, 0x16, 0x2100);
+
+ reg = vb_getctl(vb, 0x00fc);
+
+ vb_setctl(vb, 0x00fc, (reg & ~0x7) | 0x4);
+ vb_setsdi(vb, 0x00, 0x0100);
+ vb_setsdi(vb, 0x16, 0x2100);
+ reg = vb_getctl(vb, 0x00fc);
+
+
+ /*
+ * The calls to setsdi above toggle the reset line of the CPLD. Wait
+ * here to give the CPLD time to stabilize after reset.
+ */
+ mdelay(1);
+
+ return ((reg&0x7) == 0x4) ? 0 : -EIO;
+}
+
+#define OWNED(_d_) (((_d_)->des0)&OWN_BIT)
+#define SET_OWNED(_d_) do { wmb(); (_d_)->des0 |= OWN_BIT; wmb();} while (0)
+
+#ifdef DBG
+static void
+dump_descriptor(struct voicebus *vb, volatile struct voicebus_descriptor *d)
+{
+ VB_PRINTK(vb, DEBUG, "Displaying descriptor at address %08x\n", (unsigned int)d);
+ VB_PRINTK(vb, DEBUG, " des0: %08x\n", d->des0);
+ VB_PRINTK(vb, DEBUG, " des1: %08x\n", d->des1);
+ VB_PRINTK(vb, DEBUG, " buffer1: %08x\n", d->buffer1);
+ VB_PRINTK(vb, DEBUG, " container: %08x\n", d->container);
+}
+
+static void
+show_buffer(struct voicebus *vb, void *vbb)
+{
+ int x;
+ unsigned char *c;
+ c = vbb;
+ printk("Packet %d\n", count);
+ for (x = 1; x <= vb->framesize; ++x) {
+ printk("%02x ", c[x]);
+ if (x % 16 == 0) {
+ printk("\n");
+ }
+ }
+ printk("\n\n");
+}
+#endif
+
+static inline int
+vb_submit(struct voicebus *vb, struct voicebus_descriptor_list *dl, void *vbb)
+{
+ volatile struct voicebus_descriptor *d;
+ unsigned int tail = dl->tail;
+ assert_in_vb_deferred(vb);
+
+ d = vb_descriptor(dl, tail);
+
+ if (unlikely(d->buffer1)) {
+ /* Do not overwrite a buffer that is still in progress. */
+ WARN_ON(1);
+ voicebus_free(vb, vbb);
+ return -EBUSY;
+ }
+
+ dl->pending[tail] = vbb;
+ dl->tail = (++tail) & DRING_MASK;
+ d->buffer1 = dma_map_single(
+ &vb->pdev->dev, vbb, vb->framesize, dl->direction);
+ SET_OWNED(d); /* That's it until the hardware is done with it. */
+ atomic_inc(&dl->count);
+ return 0;
+}
+
+static inline void*
+vb_retrieve(struct voicebus *vb, struct voicebus_descriptor_list *dl)
+{
+ volatile struct voicebus_descriptor *d;
+ void *vbb;
+ unsigned int head = dl->head;
+ assert_in_vb_deferred(vb);
+ d = vb_descriptor(dl, head);
+ if (!OWNED(d)) {
+ dma_unmap_single(&vb->pdev->dev, d->buffer1,
+ vb->framesize, dl->direction);
+ vbb = dl->pending[head];
+ dl->head = (++head) & DRING_MASK;
+ d->buffer1 = 0;
+ atomic_dec(&dl->count);
+ return vbb;
+ } else {
+ return NULL;
+ }
+}
+
+/*!
+ * \brief Give a frame to the hardware to transmit.
+ *
+ */
+int
+voicebus_transmit(struct voicebus *vb, void *vbb)
+{
+ return vb_submit(vb, &vb->txd, vbb);
+}
+
+/*!
+ * \brief Give a frame to the hardware to use for receiving.
+ *
+ */
+static inline int
+vb_submit_rxb(struct voicebus *vb, void *vbb)
+{
+ return vb_submit(vb, &vb->rxd, vbb);
+}
+
+/*!
+ * \brief Remove the next completed transmit buffer (txb) from the tx
+ * descriptor ring.
+ *
+ * NOTE: This function doesn't need any locking because only one instance is
+ * ever running on the deferred processing routine and it only looks at
+ * the head pointer. The deferred routine should only ever be running
+ * on one processor at a time (no multithreaded workqueues allowed!)
+ *
+ * Context: Must be called from the voicebus deferred workqueue.
+ *
+ * \return Pointer to buffer, or NULL if not available.
+ */
+static inline void *
+vb_get_completed_txb(struct voicebus *vb)
+{
+ return vb_retrieve(vb, &vb->txd);
+}
+
+static inline void *
+vb_get_completed_rxb(struct voicebus *vb)
+{
+ return vb_retrieve(vb, &vb->rxd);
+}
+
+/*!
+ * \brief Free a buffer for reuse.
+ *
+ */
+void
+voicebus_free(struct voicebus *vb, void *vbb)
+{
+ kmem_cache_free(vb->buffer_cache, vbb);
+}
+
+/*!
+ * \brief Instruct the hardware to check for a new tx descriptor.
+ */
+inline static void
+__vb_tx_demand_poll(struct voicebus *vb)
+{
+ __vb_setctl(vb, 0x0008, 0x00000000);
+}
+
+/*!
+ * \brief Command the hardware to check if it owns the next transmit
+ * descriptor.
+ */
+static void
+vb_tx_demand_poll(struct voicebus *vb)
+{
+ LOCKS_VOICEBUS;
+ VBLOCK(vb);
+ __vb_tx_demand_poll(vb);
+ VBUNLOCK(vb);
+}
+
+/*!
+ * \brief Command the hardware to check if it owns the next receive
+ * descriptor.
+ */
+inline static void
+__vb_rx_demand_poll(struct voicebus *vb)
+{
+ __vb_setctl(vb, 0x0010, 0x00000000);
+}
+
+static void
+vb_rx_demand_poll(struct voicebus *vb)
+{
+ LOCKS_VOICEBUS;
+ VBLOCK(vb);
+ __vb_rx_demand_poll(vb);
+ VBUNLOCK(vb);
+}
+
+static void
+__vb_enable_interrupts(struct voicebus *vb)
+{
+ __vb_setctl(vb, IER_CSR7, DEFAULT_INTERRUPTS);
+}
+
+static void
+__vb_disable_interrupts(struct voicebus *vb)
+{
+ __vb_setctl(vb, IER_CSR7, 0);
+}
+
+static void
+vb_disable_interrupts(struct voicebus *vb)
+{
+ LOCKS_VOICEBUS;
+ VBLOCK(vb);
+ __vb_disable_interrupts(vb);
+ VBUNLOCK(vb);
+}
+
+/*!
+ * \brief Starts the VoiceBus interface.
+ *
+ * When the VoiceBus interface is started, it is actively transferring
+ * frames to and from the backend of the card. This means the card will
+ * generate interrupts.
+ *
+ * This function should only be called from process context, with interrupts
+ * enabled, since it can sleep while running the self checks.
+ *
+ * \return zero on success. -EBUSY if device is already running.
+ */
+int
+voicebus_start(struct voicebus *vb)
+{
+ LOCKS_VOICEBUS;
+ u32 reg;
+ int i;
+ void *vbb;
+ int ret;
+
+ assert(!in_interrupt());
+
+ if (!vb_is_stopped(vb)) {
+ return -EBUSY;
+ }
+
+ if ((ret=vb_reset_interface(vb))) {
+ return ret;
+ }
+
+ /* We must set up a minimum of three buffers to start with, since two
+ * are immediately read into the TX FIFO, and the descriptor of the
+ * third is read as soon as the first buffer is done.
+ */
+
+ /*
+ * NOTE: The very first buffer after coming out of reset is used to
+ * prime the pump and is lost. So we do not want the client driver to
+ * prepare it, since it will never see the corresponding receive
+ * buffer.
+ * NOTE: handle_transmit is normally only called in the context of the
+ * deferred processing thread. Since the deferred processing thread
+ * is known to not be running at this point, it is safe to call the
+ * handle transmit as if it were.
+ */
+ start_vb_deferred(vb);
+ /* Ensure that all the rx slots are ready for a buffer. */
+ for ( i = 0; i < DRING_SIZE; ++i) {
+ vbb = voicebus_alloc(vb);
+ if (unlikely(NULL == vbb)) {
+ BUG_ON(1);
+ /* \todo I need to make sure the driver can recover
+ * from this condition. .... */
+ } else {
+ vb_submit_rxb(vb, vbb);
+ }
+ }
+
+ for ( i=0; i < vb->min_tx_buffer_count; ++i) {
+ vbb = voicebus_alloc(vb);
+ if (unlikely(NULL == vbb)) {
+ BUG_ON(1);
+ } else {
+ vb->handle_transmit(vbb, vb->context);
+ }
+ }
+ stop_vb_deferred(vb);
+
+ VBLOCK(vb);
+ clear_bit(STOP, &vb->flags);
+#if VOICEBUS_DEFERRED == TIMER
+ vb->timer.expires = jiffies + HZ/1000;
+ add_timer(&vb->timer);
+#else
+ /* Clear the interrupt status register. */
+ __vb_setctl(vb, SR_CSR5, 0xffffffff);
+ __vb_enable_interrupts(vb);
+#endif
+ /* Start the transmit and receive processors. */
+ reg = __vb_getctl(vb, 0x0030);
+ __vb_setctl(vb, 0x0030, reg|0x00002002);
+ /* Tell the interface to poll the tx and rx descriptors. */
+ __vb_rx_demand_poll(vb);
+ __vb_tx_demand_poll(vb);
+ VBUNLOCK(vb);
+
+ assert(!vb_is_stopped(vb));
+
+ return 0;
+}
+
+static void
+vb_clear_start_transmit_bit(struct voicebus *vb)
+{
+ LOCKS_VOICEBUS;
+ u32 reg;
+ VBLOCK(vb);
+ reg = __vb_getctl(vb, NAR_CSR6);
+ reg &= ~0x00002000;
+ __vb_setctl(vb, NAR_CSR6, reg);
+ VBUNLOCK(vb);
+}
+
+static void
+vb_clear_start_receive_bit(struct voicebus *vb)
+{
+ LOCKS_VOICEBUS;
+ u32 reg;
+ VBLOCK(vb);
+ reg = __vb_getctl(vb, NAR_CSR6);
+ reg &= ~0x00000002;
+ __vb_setctl(vb, NAR_CSR6, reg);
+ VBUNLOCK(vb);
+}
+
+unsigned long
+vb_wait_for_completion_timeout(struct completion *x, unsigned long timeout)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+ /* There is a race condition here. If x->done is reset to 0
+ * before the call to wait_for_completion after this thread wakes.
+ */
+ timeout = wait_event_timeout(x->wait, x->done, timeout);
+ if (timeout) {
+ wait_for_completion(x);
+ }
+ return timeout;
+#else
+ return wait_for_completion_timeout(x, timeout);
+#endif
+}
+
+/*!
+ * \brief Stops the VoiceBus interface.
+ *
+ * Stops the VoiceBus interface and waits for any outstanding DMA transactions
+ * to complete. When this functions returns the VoiceBus interface tx and rx
+ * states will both be suspended.
+ *
+ * Only call this function from process context, with interrupt enabled,
+ * without any locks held since it sleeps.
+ *
+ * \return zero on success, -1 on error.
+ */
+int
+voicebus_stop(struct voicebus *vb)
+{
+ assert(!in_interrupt());
+ if (vb_is_stopped(vb)) {
+ return 0;
+ }
+ INIT_COMPLETION(vb->stopped_completion);
+ set_bit(STOP, &vb->flags);
+ vb_clear_start_transmit_bit(vb);
+ if (vb_wait_for_completion_timeout(&vb->stopped_completion, HZ)) {
+#if VOICEBUS_DEFERRED == TIMER
+ del_timer_sync(&vb->timer);
+#else
+ vb_disable_interrupts(vb);
+#endif
+ assert(vb_is_stopped(vb));
+ clear_bit(STOP, &vb->flags);
+ }
+ else {
+ VB_PRINTK(vb, WARNING, "Timeout while waiting for board to "\
+ "stop.\n");
+ }
+ return 0;
+}
+
+/*!
+ * \brief Prepare the interface for module unload.
+ *
+ * Stop the interface and free all the resources allocated by the driver. The
+ * caller should have returned all VoiceBus buffers to the VoiceBus layer
+ * before calling this function.
+ *
+ * context: !in_interrupt()
+ */
+void
+voicebus_release(struct voicebus *vb)
+{
+ assert(!in_interrupt());
+
+ /* quiesce the hardware */
+ voicebus_stop(vb);
+#if VOICEBUS_DEFERRED == WORKQUEUE
+ destroy_workqueue(vb->workqueue);
+#elif VOICEBUS_DEFERRED == TASKLET
+ tasklet_kill(&vb->tasklet);
+#endif
+ vb_reset_interface(vb);
+#if VOICEBUS_DEFERRED != TIMER
+ free_irq(vb->pdev->irq, vb);
+#endif
+
+ /* Cleanup memory and software resources. */
+ vb_free_descriptors(vb, &vb->txd);
+ vb_free_descriptors(vb, &vb->rxd);
+ kmem_cache_destroy(vb->buffer_cache);
+ release_region(vb->iobase, 0xff);
+ pci_disable_device(vb->pdev);
+ kfree(vb);
+}
+
+void
+__vb_increase_latency(struct voicebus *vb)
+{
+ static int __warn_once = 1;
+ void *vbb;
+ int latency;
+
+ assert_in_vb_deferred(vb);
+
+ latency = atomic_read(&vb->txd.count);
+ if (DRING_SIZE == latency) {
+ if (__warn_once) {
+ /* We must subtract two from this number since there
+ * are always two buffers in the TX FIFO.
+ */
+ VB_PRINTK(vb,ERR,
+ "ERROR: Unable to service card within %d ms "\
+ "and unable to further increase latency.\n",
+ DRING_SIZE-2);
+ __warn_once = 0;
+ }
+ } else {
+ /* Because there are 2 buffers in the transmit FIFO on the
+ * hardware, setting 3 ms of latency means that the host needs
+ * to be able to service the cards within 1ms. This is because
+ * the interface will load up 2 buffers into the TX FIFO then
+ * attempt to read the 3rd descriptor. If the OWN bit isn't
+ * set, then the hardware will set the TX descriptor not
+ * available interrupt.
+ */
+ VB_PRINTK(vb, INFO, "Missed interrupt. " \
+ "Increasing latency to %d ms in order to compensate.\n",
+ latency+1);
+ /* Set the minimum latency in case we're restarted...we don't
+ * want to wait for the buffer to grow to this depth again in
+ * that case.
+ */
+ voicebus_set_minlatency(vb, latency+1);
+ vbb = voicebus_alloc(vb);
+ if (unlikely(NULL == vbb)) {
+ BUG_ON(1);
+ } else {
+ vb->handle_transmit(vbb, vb->context);
+ }
+ }
+}
+
+/*!
+ * \brief Actually process the completed transmit and receive buffers.
+ *
+ * NOTE: This function may be called either from a tasklet, workqueue, or
+ * directly in the interrupt service routine depending on
+ * VOICEBUS_DEFERRED.
+ */
+static inline void
+vb_deferred(struct voicebus *vb)
+{
+ void *vbb;
+#ifdef DBG
+ static int count = 0;
+#endif
+ int stopping = test_bit(STOP, &vb->flags);
+ int underrun = test_bit(TX_UNDERRUN, &vb->flags);
+
+
+ start_vb_deferred(vb);
+ if (unlikely(stopping)) {
+ while((vbb = vb_get_completed_txb(vb))) {
+ voicebus_free(vb, vbb);
+ }
+ while((vbb = vb_get_completed_rxb(vb))) {
+ voicebus_free(vb, vbb);
+ }
+ stop_vb_deferred(vb);
+ return;
+ }
+
+ if (unlikely(underrun)) {
+ /* When we've underrun our FIFO, for some reason we're not
+ * able to keep enough transmit descriptors pending. This can
+ * happen if either interrupts or this deferred processing
+ * function is not run soon enough (within 1ms when using the
+ * default 3 transmit buffers to start). In this case, we'll
+ * insert an additional transmit buffer onto the descriptor
+ * list which decreases the sensitivity to latency, but also
+ * adds more delay to the TDM and SPI data.
+ */
+ __vb_increase_latency(vb);
+ }
+
+ /* Always handle the transmit buffers first. */
+ while ((vbb = vb_get_completed_txb(vb))) {
+ vb->handle_transmit(vbb, vb->context);
+ }
+
+ if (unlikely(underrun)) {
+ vb_rx_demand_poll(vb);
+ vb_tx_demand_poll(vb);
+ clear_bit(TX_UNDERRUN, &vb->flags);
+ }
+
+ while ((vbb = vb_get_completed_rxb(vb))) {
+ vb->handle_receive(vbb, vb->context);
+ vb_submit_rxb(vb, vbb);
+ }
+
+ stop_vb_deferred(vb);
+}
+
+
+/*!
+ * \brief Interrupt handler for VoiceBus interface.
+ *
+ * NOTE: This handler is optimized for the case where only a single interrupt
+ * condition will be generated at a time.
+ *
+ * ALSO NOTE: Only access the interrupt status register from this function
+ * since it doesn't employ any locking on the voicebus interface.
+ */
+static irqreturn_t
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+vb_isr(int irq, void *dev_id, struct pt_regs *regs)
+#else
+vb_isr(int irq, void *dev_id)
+#endif
+{
+ struct voicebus *vb = dev_id;
+ u32 int_status;
+
+ int_status = __vb_getctl(vb, SR_CSR5);
+ /* Mask out the reserved bits. */
+ int_status &= ~(0xfc004010);
+ int_status &= 0x7fff;
+
+ if (!int_status) {
+ return IRQ_NONE;
+ }
+
+ if (likely(int_status & TX_COMPLETE_INTERRUPT)) {
+ /* ******************************************************** */
+ /* NORMAL INTERRUPT CASE */
+ /* ******************************************************** */
+# if VOICEBUS_DEFERRED == WORKQUEUE
+ queue_work(vb->workqueue, &vb->workitem);
+# elif VOICEBUS_DEFERRED == TASKLET
+ tasklet_schedule(&vb->tasklet);
+# else
+ vb_deferred(vb);
+# endif
+ __vb_setctl(vb, SR_CSR5, TX_COMPLETE_INTERRUPT);
+ } else {
+ /* ******************************************************** */
+ /* ABNORMAL / ERROR CONDITIONS */
+ /* ******************************************************** */
+ if ((int_status & TX_UNAVAILABLE_INTERRUPT) ) {
+ /* This can happen if the host fails to service the
+ * interrupt within the required time interval (1ms
+ * for each buffer on the queue). Increasing the
+ * depth of the tx queue (up to a maximum of
+ * DRING_SIZE) can make the driver / system more
+ * tolerant of interrupt latency under periods of
+ * heavy system load, but also increases the general
+ * latency that the driver adds to the voice
+ * conversations.
+ */
+ set_bit(TX_UNDERRUN, &vb->flags);
+# if VOICEBUS_DEFERRED == WORKQUEUE
+ queue_work(vb->workqueue, &vb->workitem);
+# elif VOICEBUS_DEFERRED == TASKLET
+ tasklet_schedule(&vb->tasklet);
+# else
+ vb_deferred(vb);
+# endif
+ }
+
+ if (int_status & FATAL_BUS_ERROR_INTERRUPT) {
+ VB_PRINTK(vb, ERR, "Fatal Bus Error detected!\n");
+ }
+
+ if (int_status & TX_STOPPED_INTERRUPT) {
+ assert(test_bit(STOP, &vb->flags));
+ vb_clear_start_receive_bit(vb);
+ __vb_setctl(vb, SR_CSR5, DEFAULT_INTERRUPTS);
+ __vb_disable_interrupts(vb);
+ complete(&vb->stopped_completion);
+ }
+ if (int_status & RX_STOPPED_INTERRUPT) {
+ assert(test_bit(STOP, &vb->flags));
+ if (vb_is_stopped(vb)) {
+ complete(&vb->stopped_completion);
+ }
+ }
+
+ /* Clear the interrupt(s) */
+ __vb_setctl(vb, SR_CSR5, int_status);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#if VOICEBUS_DEFERRED == TIMER
+/*! \brief Called if the deferred processing is to happen in the context of
+ * the timer.
+ */
+static void
+vb_timer(unsigned long data)
+{
+ unsigned long start = jiffies;
+ struct voicebus *vb = (struct voicebus *)data;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ vb_isr(0, vb, 0);
+#else
+ vb_isr(0, vb);
+#endif
+ if (!vb_is_stopped(vb)) {
+ vb->timer.expires = start + HZ/1000;
+ add_timer(&vb->timer);
+ }
+}
+#endif
+
+#if VOICEBUS_DEFERRED == WORKQUEUE
+static void
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+vb_workfunc(void *data)
+{
+ struct voicebus *vb = data;
+#else
+vb_workfunc(struct work_struct *work)
+{
+ struct voicebus *vb = container_of(work, struct voicebus, workitem);
+#endif
+ vb_deferred(vb);
+}
+#elif VOICEBUS_DEFERRED == TASKLET
+static void
+vb_tasklet(unsigned long data)
+{
+ struct voicebus *vb = (struct voicebus*)data;
+ vb_deferred(vb);
+}
+#endif /* #if VOICEBUS_DEFERRED == WORKQUEUE */
+
+/*!
+ * \brief Initalize the voicebus interface.
+ *
+ * This function must be called in process context since it may sleep.
+ * \todo Complete this description.
+ */
+int
+voicebus_init(struct pci_dev *pdev, u32 framesize,
+ const char *board_name,
+ void (*handle_receive)(void *vbb, void *context),
+ void (*handle_transmit)(void *vbb, void *context),
+ void *context,
+ struct voicebus **vbp
+ )
+{
+ int retval = 0;
+ struct voicebus *vb;
+
+ assert(NULL != pdev);
+ assert(NULL != board_name);
+ assert(framesize);
+ assert(NULL != handle_receive);
+ assert(NULL != handle_transmit);
+
+ /* ----------------------------------------------------------------
+ Initialize the pure software constructs.
+ ---------------------------------------------------------------- */
+ *vbp = NULL;
+ vb = kmalloc(sizeof(*vb), GFP_KERNEL);
+ if (NULL == vb) {
+ VB_PRINTK(vb, DEBUG, "Failed to allocate memory for voicebus "\
+ "interface.\n");
+ retval = -ENOMEM;
+ goto cleanup;
+ }
+ memset(vb,0,sizeof(*vb));
+ /* \todo make sure there is a note that the caller needs to make sure
+ * board_name stays in memory until voicebus_release is called.
+ */
+ vb->board_name = board_name;
+ spin_lock_init(&vb->lock);
+ init_completion(&vb->stopped_completion);
+ vb->pdev = pdev;
+ set_bit(STOP, &vb->flags);
+ clear_bit(IN_DEFERRED_PROCESSING, &vb->flags);
+ vb->framesize = framesize;
+ vb->min_tx_buffer_count = VOICEBUS_DEFAULT_LATENCY;
+
+#if VOICEBUS_DEFERRED == WORKQUEUE
+ /* NOTE: This workqueue must be single threaded because locking is not
+ * used when buffers are removed or added to the descriptor list, and
+ * there should only be one producer / consumer (the hardware or the
+ * deferred processing function). */
+ vb->workqueue = create_singlethread_workqueue(board_name);
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ INIT_WORK(&vb->workitem, vb_workfunc, vb);
+# else
+ INIT_WORK(&vb->workitem, vb_workfunc);
+# endif
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+ vb_set_workqueue_priority(vb);
+# endif
+#elif VOICEBUS_DEFERRED == TASKLET
+ tasklet_init(&vb->tasklet, vb_tasklet, (unsigned long)vb);
+#elif VOICEBUS_DEFERRED == TIMER
+ init_timer(&vb->timer);
+ vb->timer.function = vb_timer;
+ vb->timer.data = (unsigned long)vb;
+#endif
+
+ vb->handle_receive = handle_receive;
+ vb->handle_transmit = handle_transmit;
+ vb->context = context;
+
+ /* \todo This cache should be shared by all instances supported by
+ * this driver. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+ vb->buffer_cache = kmem_cache_create(board_name, vb->framesize, 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+#else
+ vb->buffer_cache = kmem_cache_create(board_name, vb->framesize, 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+#endif
+ if (NULL == vb->buffer_cache) {
+ VB_PRINTK(vb, ERR, "Failed to allocate buffer cache.\n");
+ goto cleanup;
+ }
+
+
+ /* ----------------------------------------------------------------
+ Configure the hardware / kernel module interfaces.
+ ---------------------------------------------------------------- */
+ if (pci_read_config_byte(vb->pdev, 0x0c, &vb->cache_line_size)) {
+ VB_PRINTK(vb, ERR, "Failed read of cache line " \
+ "size from PCI configuration space.\n");
+ goto cleanup;
+ }
+
+ if (pci_enable_device(pdev)) {
+ VB_PRINTK(vb, ERR, "Failed call to pci_enable_device.\n");
+ retval = -EIO;
+ goto cleanup;
+ }
+
+ /* \todo This driver should be modified to use the memory mapped I/O
+ as opposed to IO space for portability and performance. */
+ if (0 == (pci_resource_flags(pdev, 0)&IORESOURCE_IO)) {
+ VB_PRINTK(vb, ERR, "BAR0 is not IO Memory.\n");
+ retval = -EIO;
+ goto cleanup;
+ }
+ vb->iobase = pci_resource_start(pdev, 0);
+ if(NULL == request_region(vb->iobase, 0xff, board_name)) {
+ VB_PRINTK(vb, ERR, "IO Registers are in use by another " \
+ "module.\n");
+ retval = -EIO;
+ goto cleanup;
+ }
+
+ if ((retval = vb_initialize_tx_descriptors(vb))) {
+ goto cleanup;
+ }
+ if ((retval = vb_initialize_rx_descriptors(vb))) {
+ goto cleanup;
+ }
+
+ /* ----------------------------------------------------------------
+ Configure the hardware interface.
+ ---------------------------------------------------------------- */
+ pci_set_master(pdev);
+ vb_enable_io_access(vb);
+
+#if VOICEBUS_DEFERRED != TIMER
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+# define VB_IRQ_SHARED SA_SHIRQ
+#else
+# define VB_IRQ_SHARED IRQF_SHARED
+#endif
+ if (request_irq(pdev->irq, vb_isr, VB_IRQ_SHARED, vb->board_name,
+ vb)) {
+ assert(0);
+ goto cleanup;
+ }
+#endif
+
+ *vbp = vb;
+ return retval;
+cleanup:
+ if (NULL == vb) {
+ return retval;
+ }
+#if VOICEBUS_DEFERRED == WORKQUEUE
+ if (vb->workqueue) {
+ destroy_workqueue(vb->workqueue);
+ }
+#elif VOICEBUS_DEFERRED == TASKLET
+ tasklet_kill(&vb->tasklet);
+#endif
+ /* Cleanup memory and software resources. */
+ if (vb->txd.desc) {
+ vb_free_descriptors(vb, &vb->txd);
+ }
+ if (vb->rxd.desc) {
+ vb_free_descriptors(vb, &vb->rxd);
+ }
+ if (vb->buffer_cache) {
+ kmem_cache_destroy(vb->buffer_cache);
+ }
+ if (vb->iobase) {
+ release_region(vb->iobase, 0xff);
+ }
+ if (vb->pdev) {
+ pci_disable_device(vb->pdev);
+ }
+ kfree(vb);
+ assert(0 != retval);
+ return retval;
+}
+
+
+/*! \brief Return the pci_dev in use by this voicebus interface. */
+struct pci_dev *
+voicebus_get_pci_dev(struct voicebus *vb)
+{
+ return vb->pdev;
+}
diff --git a/drivers/dahdi/voicebus.h b/drivers/dahdi/voicebus.h
new file mode 100644
index 0000000..c37b2b8
--- /dev/null
+++ b/drivers/dahdi/voicebus.h
@@ -0,0 +1,53 @@
+/*
+ * VoiceBus(tm) Interface Library.
+ *
+ * Written by Shaun Ruffell <sruffell@digium.com>
+ * and based on previous work by Mark Spencer <markster@digium.com>,
+ * Matthew Fredrickson <creslin@digium.com>, and
+ * Michael Spiceland <mspiceland@digium.com>
+ *
+ * Copyright (C) 2007-2008 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.
+ *
+ */
+#ifndef __VOICEBUS_H__
+#define __VOICEBUS_H__
+
+struct voicebus;
+
+#define VOICEBUS_DEFAULT_LATENCY 3
+
+void voicebus_setdebuglevel(struct voicebus *vb, u32 level);
+int voicebus_getdebuglevel(struct voicebus *vb);
+struct pci_dev * voicebus_get_pci_dev(struct voicebus *vb);
+int voicebus_init(struct pci_dev* pdev, u32 framesize,
+ const char *board_name,
+ void (*handle_receive)(void *buffer, void *context),
+ void (*handle_transmit)(void *buffer, void *context),
+ void *context,
+ struct voicebus **vb_p);
+void voicebus_release(struct voicebus *vb);
+int voicebus_start(struct voicebus *vb);
+int voicebus_stop(struct voicebus *vb);
+void * voicebus_alloc(struct voicebus* vb);
+void voicebus_free(struct voicebus *vb, void *vbb);
+int voicebus_transmit(struct voicebus *vb, void *vbb);
+int voicebus_set_minlatency(struct voicebus *vb, unsigned int milliseconds);
+int voicebus_current_latency(struct voicebus *vb) ;
+
+#endif /* __VOICEBUS_H__ */
diff --git a/drivers/dahdi/wcfxo.c b/drivers/dahdi/wcfxo.c
new file mode 100644
index 0000000..241053b
--- /dev/null
+++ b/drivers/dahdi/wcfxo.c
@@ -0,0 +1,1103 @@
+/*
+ * Wilcard X100P FXO Interface Driver for Zapata Telephony interface
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Matthew Fredrickson <creslin@digium.com>
+ *
+ * Copyright (C) 2001, Linux Support Services, 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/usb.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+/* Uncomment to enable tasklet handling in the FXO driver. Not recommended
+ in general, but may improve interactive performance */
+
+/* #define ENABLE_TASKLETS */
+
+/* Un-comment the following for POTS line support for Japan */
+/* #define JAPAN */
+
+/* Un-comment for lines (eg from and ISDN TA) that remove */
+/* phone power during ringing */
+/* #define ZERO_BATT_RING */
+
+#define WC_MAX_IFACES 128
+
+#define WC_CNTL 0x00
+#define WC_OPER 0x01
+#define WC_AUXC 0x02
+#define WC_AUXD 0x03
+#define WC_MASK0 0x04
+#define WC_MASK1 0x05
+#define WC_INTSTAT 0x06
+
+#define WC_DMAWS 0x08
+#define WC_DMAWI 0x0c
+#define WC_DMAWE 0x10
+#define WC_DMARS 0x18
+#define WC_DMARI 0x1c
+#define WC_DMARE 0x20
+
+#define WC_AUXFUNC 0x2b
+#define WC_SERCTL 0x2d
+#define WC_FSCDELAY 0x2f
+
+
+/* DAA registers */
+#define WC_DAA_CTL1 1
+#define WC_DAA_CTL2 2
+#define WC_DAA_DCTL1 5
+#define WC_DAA_DCTL2 6
+#define WC_DAA_PLL1_N1 7
+#define WC_DAA_PLL1_M1 8
+#define WC_DAA_PLL2_N2_M2 9
+#define WC_DAA_PLL_CTL 10
+#define WC_DAA_CHIPA_REV 11
+#define WC_DAA_LINE_STAT 12
+#define WC_DAA_CHIPB_REV 13
+#define WC_DAA_DAISY_CTL 14
+#define WC_DAA_TXRX_GCTL 15
+#define WC_DAA_INT_CTL1 16
+#define WC_DAA_INT_CTL2 17
+#define WC_DAA_INT_CTL3 18
+#define WC_DAA_INT_CTL4 19
+
+
+#define FLAG_EMPTY 0
+#define FLAG_WRITE 1
+#define FLAG_READ 2
+
+#ifdef ZERO_BATT_RING /* Need to debounce Off/On hook too */
+#define JAPAN
+#endif
+
+#define RING_DEBOUNCE 64 /* Ringer Debounce (in ms) */
+#ifdef JAPAN
+#define BATT_DEBOUNCE 30 /* Battery debounce (in ms) */
+#define OH_DEBOUNCE 350 /* Off/On hook debounce (in ms) */
+#else
+#define BATT_DEBOUNCE 80 /* Battery debounce (in ms) */
+#endif
+
+#define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */
+#define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */
+#define PEGCOUNT 5 /* 5 cycles of pegging means RING */
+
+#define wcfxo_printk(level, span, fmt, ...) \
+ printk(KERN_ ## level "%s-%s: %s: " fmt, #level, \
+ THIS_MODULE->name, (span).name, ## __VA_ARGS__)
+
+#define wcfxo_notice(span, fmt, ...) \
+ wcfxo_printk(NOTICE, span, fmt, ## __VA_ARGS__)
+
+#define wcfxo_dbg(span, fmt, ...) \
+ ((void)((debug) && wcfxo_printk(DEBUG, span, "%s: " fmt, \
+ __FUNCTION__, ## __VA_ARGS__) ) )
+
+struct reg {
+ unsigned long flags;
+ unsigned char index;
+ unsigned char reg;
+ unsigned char value;
+};
+
+static int wecareregs[] =
+{
+ WC_DAA_DCTL1, WC_DAA_DCTL2, WC_DAA_PLL2_N2_M2, WC_DAA_CHIPA_REV,
+ WC_DAA_LINE_STAT, WC_DAA_CHIPB_REV, WC_DAA_INT_CTL2, WC_DAA_INT_CTL4,
+};
+
+struct wcfxo {
+ struct pci_dev *dev;
+ char *variety;
+ struct zt_span span;
+ struct zt_chan chan;
+ int usecount;
+ int dead;
+ int pos;
+ unsigned long flags;
+ int freeregion;
+ int ring;
+ int offhook;
+ int battery;
+ int wregcount;
+ int readpos;
+ int rreadpos;
+ unsigned int pegtimer;
+ int pegcount;
+ int peg;
+ int battdebounce;
+ int nobatttimer;
+ int ringdebounce;
+#ifdef JAPAN
+ int ohdebounce;
+#endif
+ int allread;
+ int regoffset; /* How far off our registers are from what we expect */
+ int alt;
+ int ignoreread;
+ int reset;
+ /* Up to 6 register can be written at a time */
+ struct reg regs[ZT_CHUNKSIZE];
+ struct reg oldregs[ZT_CHUNKSIZE];
+ unsigned char lasttx[ZT_CHUNKSIZE];
+ /* Up to 32 registers of whatever we most recently read */
+ unsigned char readregs[32];
+ unsigned long ioaddr;
+ dma_addr_t readdma;
+ dma_addr_t writedma;
+ volatile int *writechunk; /* Double-word aligned write memory */
+ volatile int *readchunk; /* Double-word aligned read memory */
+#ifdef ZERO_BATT_RING
+ int onhook;
+#endif
+#ifdef ENABLE_TASKLETS
+ int taskletrun;
+ int taskletsched;
+ int taskletpending;
+ int taskletexec;
+ int txerrors;
+ int ints;
+ struct tasklet_struct wcfxo_tlet;
+#endif
+};
+
+#define FLAG_INVERTSER (1 << 0)
+#define FLAG_USE_XTAL (1 << 1)
+#define FLAG_DOUBLE_CLOCK (1 << 2)
+#define FLAG_RESET_ON_AUX5 (1 << 3)
+#define FLAG_NO_I18N_REGS (1 << 4) /*!< Uses si3035, rather si3034 */
+
+struct wcfxo_desc {
+ char *name;
+ unsigned long flags;
+};
+
+
+static struct wcfxo_desc wcx100p = { "Wildcard X100P",
+ FLAG_INVERTSER | FLAG_USE_XTAL | FLAG_DOUBLE_CLOCK };
+
+static struct wcfxo_desc wcx101p = { "Wildcard X101P",
+ FLAG_USE_XTAL | FLAG_DOUBLE_CLOCK };
+
+static struct wcfxo_desc generic = { "Generic Clone",
+ FLAG_USE_XTAL | FLAG_DOUBLE_CLOCK };
+
+static struct wcfxo *ifaces[WC_MAX_IFACES];
+
+static void wcfxo_release(struct wcfxo *wc);
+
+static int debug = 0;
+
+static int monitor = 0;
+
+static int quiet = 0;
+
+static int boost = 0;
+
+static int opermode = 0;
+
+static struct fxo_mode {
+ char *name;
+ int ohs;
+ int act;
+ int dct;
+ int rz;
+ int rt;
+ int lim;
+ int vol;
+} fxo_modes[] =
+{
+ { "FCC", 0, 0, 2, 0, 0, 0, 0 }, /* US */
+ { "CTR21", 0, 0, 3, 0, 0, 3, 0 }, /* Austria, Belgium, Denmark, Finland, France, Germany,
+ Greece, Iceland, Ireland, Italy, Luxembourg, Netherlands,
+ Norway, Portugal, Spain, Sweden, Switzerland, and UK */
+};
+
+static inline void wcfxo_transmitprep(struct wcfxo *wc, unsigned char ints)
+{
+ volatile int *writechunk;
+ int x;
+ int written=0;
+ unsigned short cmd;
+
+ /* if nothing to transmit, have to do the zt_transmit() anyway */
+ if (!(ints & 3)) {
+ /* Calculate Transmission */
+ zt_transmit(&wc->span);
+ return;
+ }
+
+ /* Remember what it was we just sent */
+ memcpy(wc->lasttx, wc->chan.writechunk, ZT_CHUNKSIZE);
+
+ if (ints & 0x01) {
+ /* Write is at interrupt address. Start writing from normal offset */
+ writechunk = wc->writechunk;
+ } else {
+ writechunk = wc->writechunk + ZT_CHUNKSIZE * 2;
+ }
+
+ zt_transmit(&wc->span);
+
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ /* Send a sample, as a 32-bit word, and be sure to indicate that a command follows */
+ if (wc->flags & FLAG_INVERTSER)
+ writechunk[x << 1] = cpu_to_le32(
+ ~((unsigned short)(ZT_XLAW(wc->chan.writechunk[x], (&wc->chan)))| 0x1) << 16
+ );
+ else
+ writechunk[x << 1] = cpu_to_le32(
+ ((unsigned short)(ZT_XLAW(wc->chan.writechunk[x], (&wc->chan)))| 0x1) << 16
+ );
+
+ /* We always have a command to follow our signal */
+ if (!wc->regs[x].flags) {
+ /* Fill in an empty register command with a read for a potentially useful register */
+ wc->regs[x].flags = FLAG_READ;
+ wc->regs[x].reg = wecareregs[wc->readpos];
+ wc->regs[x].index = wc->readpos;
+ wc->readpos++;
+ if (wc->readpos >= (sizeof(wecareregs) / sizeof(wecareregs[0]))) {
+ wc->allread = 1;
+ wc->readpos = 0;
+ }
+ }
+
+ /* Prepare the command to follow it */
+ switch(wc->regs[x].flags) {
+ case FLAG_READ:
+ cmd = (wc->regs[x].reg | 0x20) << 8;
+ break;
+ case FLAG_WRITE:
+ cmd = (wc->regs[x].reg << 8) | (wc->regs[x].value & 0xff);
+ written = 1;
+ /* Wait at least four samples before reading */
+ wc->ignoreread = 4;
+ break;
+ default:
+ printk("wcfxo: Huh? No read or write??\n");
+ cmd = 0;
+ }
+ /* Setup the write chunk */
+ if (wc->flags & FLAG_INVERTSER)
+ writechunk[(x << 1) + 1] = cpu_to_le32(~(cmd << 16));
+ else
+ writechunk[(x << 1) + 1] = cpu_to_le32(cmd << 16);
+ }
+ if (written)
+ wc->readpos = 0;
+ wc->wregcount = 0;
+
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ /* Rotate through registers */
+ wc->oldregs[x] = wc->regs[x];
+ wc->regs[x].flags = FLAG_EMPTY;
+ }
+
+}
+
+static inline void wcfxo_receiveprep(struct wcfxo *wc, unsigned char ints)
+{
+ volatile int *readchunk;
+ int x;
+ int realreg;
+ int realval;
+ int sample;
+ if (ints & 0x04)
+ /* Read is at interrupt address. Valid data is available at normal offset */
+ readchunk = wc->readchunk;
+ else
+ readchunk = wc->readchunk + ZT_CHUNKSIZE * 2;
+
+ /* Keep track of how quickly our peg alternates */
+ wc->pegtimer+=ZT_CHUNKSIZE;
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+
+ /* We always have a command to follow our signal. */
+ if (wc->oldregs[x].flags == FLAG_READ && !wc->ignoreread) {
+ realreg = wecareregs[(wc->regs[x].index + wc->regoffset) %
+ (sizeof(wecareregs) / sizeof(wecareregs[0]))];
+ realval = (le32_to_cpu(readchunk[(x << 1) +wc->alt]) >> 16) & 0xff;
+ if ((realval == 0x89) && (realreg != WC_DAA_PLL2_N2_M2)) {
+ /* Some sort of slippage, correct for it */
+ while(realreg != WC_DAA_PLL2_N2_M2) {
+ /* Find register 9 */
+ realreg = wecareregs[(wc->regs[x].index + ++wc->regoffset) %
+ (sizeof(wecareregs) / sizeof(wecareregs[0]))];
+ wc->regoffset = wc->regoffset % (sizeof(wecareregs) / sizeof(wecareregs[0]));
+ }
+ if (debug)
+ printk("New regoffset: %d\n", wc->regoffset);
+ }
+ /* Receive into the proper register */
+ wc->readregs[realreg] = realval;
+ }
+ /* Look for pegging to indicate ringing */
+ sample = (short)(le32_to_cpu(readchunk[(x << 1) + (1 - wc->alt)]) >> 16);
+ if ((sample > 32000) && (wc->peg != 1)) {
+ if ((wc->pegtimer < PEGTIME) && (wc->pegtimer > MINPEGTIME))
+ wc->pegcount++;
+ wc->pegtimer = 0;
+ wc->peg = 1;
+ } else if ((sample < -32000) && (wc->peg != -1)) {
+ if ((wc->pegtimer < PEGTIME) && (wc->pegtimer > MINPEGTIME))
+ wc->pegcount++;
+ wc->pegtimer = 0;
+ wc->peg = -1;
+ }
+ wc->chan.readchunk[x] = ZT_LIN2X((sample), (&wc->chan));
+ }
+ if (wc->pegtimer > PEGTIME) {
+ /* Reset pegcount if our timer expires */
+ wc->pegcount = 0;
+ }
+ /* Decrement debouncer if appropriate */
+ if (wc->ringdebounce)
+ wc->ringdebounce--;
+ if (!wc->offhook && !wc->ringdebounce) {
+ if (!wc->ring && (wc->pegcount > PEGCOUNT)) {
+ /* It's ringing */
+ if (debug)
+ printk("RING!\n");
+ zt_hooksig(&wc->chan, ZT_RXSIG_RING);
+ wc->ring = 1;
+ }
+ if (wc->ring && !wc->pegcount) {
+ /* No more ring */
+ if (debug)
+ printk("NO RING!\n");
+ zt_hooksig(&wc->chan, ZT_RXSIG_OFFHOOK);
+ wc->ring = 0;
+ }
+ }
+ if (wc->ignoreread)
+ wc->ignoreread--;
+
+ /* Do the echo cancellation... We are echo cancelling against
+ what we sent two chunks ago*/
+ zt_ec_chunk(&wc->chan, wc->chan.readchunk, wc->lasttx);
+
+ /* Receive the result */
+ zt_receive(&wc->span);
+}
+
+#ifdef ENABLE_TASKLETS
+static void wcfxo_tasklet(unsigned long data)
+{
+ struct wcfxo *wc = (struct wcfxo *)data;
+ wc->taskletrun++;
+ /* Run tasklet */
+ if (wc->taskletpending) {
+ wc->taskletexec++;
+ wcfxo_receiveprep(wc, wc->ints);
+ wcfxo_transmitprep(wc, wc->ints);
+ }
+ wc->taskletpending = 0;
+}
+#endif
+
+static void wcfxo_stop_dma(struct wcfxo *wc);
+static void wcfxo_restart_dma(struct wcfxo *wc);
+
+ZAP_IRQ_HANDLER(wcfxo_interrupt)
+{
+ struct wcfxo *wc = dev_id;
+ unsigned char ints;
+ unsigned char b;
+#ifdef DEBUG_RING
+ static int oldb = 0;
+ static int oldcnt = 0;
+#endif
+
+ ints = inb(wc->ioaddr + WC_INTSTAT);
+
+
+ if (!ints)
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+
+ outb(ints, wc->ioaddr + WC_INTSTAT);
+
+ if (ints & 0x0c) { /* if there is a rx interrupt pending */
+#ifdef ENABLE_TASKLETS
+ wc->ints = ints;
+ if (!wc->taskletpending) {
+ wc->taskletpending = 1;
+ wc->taskletsched++;
+ tasklet_hi_schedule(&wc->wcfxo_tlet);
+ } else
+ wc->txerrors++;
+#else
+ wcfxo_receiveprep(wc, ints);
+ /* transmitprep looks to see if there is anything to transmit
+ and returns by itself if there is nothing */
+ wcfxo_transmitprep(wc, ints);
+#endif
+ }
+
+ if (ints & 0x10) {
+ printk("FXO PCI Master abort\n");
+ /* Stop DMA andlet the watchdog start it again */
+ wcfxo_stop_dma(wc);
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#else
+ return;
+#endif
+ }
+
+ if (ints & 0x20) {
+ printk("PCI Target abort\n");
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#else
+ return;
+#endif
+ }
+ if (1 /* !(wc->report % 0xf) */) {
+ /* Check for BATTERY from register and debounce for 8 ms */
+ b = wc->readregs[WC_DAA_LINE_STAT] & 0xf;
+ if (!b) {
+ wc->nobatttimer++;
+#if 0
+ if (wc->battery)
+ printk("Battery loss: %d (%d debounce)\n", b, wc->battdebounce);
+#endif
+ if (wc->battery && !wc->battdebounce) {
+ if (debug)
+ printk("NO BATTERY!\n");
+ wc->battery = 0;
+#ifdef JAPAN
+ if ((!wc->ohdebounce) && wc->offhook) {
+ zt_hooksig(&wc->chan, ZT_RXSIG_ONHOOK);
+ if (debug)
+ printk("Signalled On Hook\n");
+#ifdef ZERO_BATT_RING
+ wc->onhook++;
+#endif
+ }
+#else
+ zt_hooksig(&wc->chan, ZT_RXSIG_ONHOOK);
+#endif
+ wc->battdebounce = BATT_DEBOUNCE;
+ } else if (!wc->battery)
+ wc->battdebounce = BATT_DEBOUNCE;
+ if ((wc->nobatttimer > 5000) &&
+#ifdef ZERO_BATT_RING
+ !(wc->readregs[WC_DAA_DCTL1] & 0x04) &&
+#endif
+ (!wc->span.alarms)) {
+ wc->span.alarms = ZT_ALARM_RED;
+ zt_alarm_notify(&wc->span);
+ }
+ } else if (b == 0xf) {
+ if (!wc->battery && !wc->battdebounce) {
+ if (debug)
+ printk("BATTERY!\n");
+#ifdef ZERO_BATT_RING
+ if (wc->onhook) {
+ wc->onhook = 0;
+ zt_hooksig(&wc->chan, ZT_RXSIG_OFFHOOK);
+ if (debug)
+ printk("Signalled Off Hook\n");
+ }
+#else
+ zt_hooksig(&wc->chan, ZT_RXSIG_OFFHOOK);
+#endif
+ wc->battery = 1;
+ wc->nobatttimer = 0;
+ wc->battdebounce = BATT_DEBOUNCE;
+ if (wc->span.alarms) {
+ wc->span.alarms = 0;
+ zt_alarm_notify(&wc->span);
+ }
+ } else if (wc->battery)
+ wc->battdebounce = BATT_DEBOUNCE;
+ } else {
+ /* It's something else... */
+ wc->battdebounce = BATT_DEBOUNCE;
+ }
+
+ if (wc->battdebounce)
+ wc->battdebounce--;
+#ifdef JAPAN
+ if (wc->ohdebounce)
+ wc->ohdebounce--;
+#endif
+
+ }
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+}
+
+static int wcfxo_setreg(struct wcfxo *wc, unsigned char reg, unsigned char value)
+{
+ int x;
+ if (wc->wregcount < ZT_CHUNKSIZE) {
+ x = wc->wregcount;
+ wc->regs[x].reg = reg;
+ wc->regs[x].value = value;
+ wc->regs[x].flags = FLAG_WRITE;
+ wc->wregcount++;
+ return 0;
+ }
+ printk("wcfxo: Out of space to write register %02x with %02x\n", reg, value);
+ return -1;
+}
+
+static int wcfxo_open(struct zt_chan *chan)
+{
+ struct wcfxo *wc = chan->pvt;
+ if (wc->dead)
+ return -ENODEV;
+ wc->usecount++;
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static int wcfxo_watchdog(struct zt_span *span, int event)
+{
+ printk("FXO: Restarting DMA\n");
+ wcfxo_restart_dma(span->pvt);
+ return 0;
+}
+
+static int wcfxo_close(struct zt_chan *chan)
+{
+ struct wcfxo *wc = chan->pvt;
+ wc->usecount--;
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ /* If we're dead, release us now */
+ if (!wc->usecount && wc->dead)
+ wcfxo_release(wc);
+ return 0;
+}
+
+static int wcfxo_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
+{
+ struct wcfxo *wc = chan->pvt;
+ int reg=0;
+ switch(txsig) {
+ case ZT_TXSIG_START:
+ case ZT_TXSIG_OFFHOOK:
+ /* Take off hook and enable normal mode reception. This must
+ be done in two steps because of a hardware bug. */
+ reg = wc->readregs[WC_DAA_DCTL1] & ~0x08;
+ wcfxo_setreg(wc, WC_DAA_DCTL1, reg);
+
+ reg = reg | 0x1;
+ wcfxo_setreg(wc, WC_DAA_DCTL1, reg);
+ wc->offhook = 1;
+#ifdef JAPAN
+ wc->battery = 1;
+ wc->battdebounce = BATT_DEBOUNCE;
+ wc->ohdebounce = OH_DEBOUNCE;
+#endif
+ break;
+ case ZT_TXSIG_ONHOOK:
+ /* Put on hook and enable on hook line monitor */
+ reg = wc->readregs[WC_DAA_DCTL1] & 0xfe;
+ wcfxo_setreg(wc, WC_DAA_DCTL1, reg);
+
+ reg = reg | 0x08;
+ wcfxo_setreg(wc, WC_DAA_DCTL1, reg);
+ wc->offhook = 0;
+ /* Don't accept a ring for another 1000 ms */
+ wc->ringdebounce = 1000;
+#ifdef JAPAN
+ wc->ohdebounce = OH_DEBOUNCE;
+#endif
+ break;
+ default:
+ printk("wcfxo: Can't set tx state to %d\n", txsig);
+ }
+ if (debug)
+ printk("Setting hook state to %d (%02x)\n", txsig, reg);
+ return 0;
+}
+
+static int wcfxo_initialize(struct wcfxo *wc)
+{
+ /* Zapata stuff */
+ sprintf(wc->span.name, "WCFXO/%d", wc->pos);
+ snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1);
+ sprintf(wc->chan.name, "WCFXO/%d/%d", wc->pos, 0);
+ snprintf(wc->span.location, sizeof(wc->span.location) - 1,
+ "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1);
+ wc->span.manufacturer = "Digium";
+ zap_copy_string(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype));
+ wc->chan.sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF;
+ wc->chan.chanpos = 1;
+ wc->span.chans = &wc->chan;
+ wc->span.channels = 1;
+ wc->span.hooksig = wcfxo_hooksig;
+ wc->span.irq = wc->dev->irq;
+ wc->span.open = wcfxo_open;
+ wc->span.close = wcfxo_close;
+ wc->span.flags = ZT_FLAG_RBS;
+ wc->span.deflaw = ZT_LAW_MULAW;
+ wc->span.watchdog = wcfxo_watchdog;
+#ifdef ENABLE_TASKLETS
+ tasklet_init(&wc->wcfxo_tlet, wcfxo_tasklet, (unsigned long)wc);
+#endif
+ init_waitqueue_head(&wc->span.maintq);
+
+ wc->span.pvt = wc;
+ wc->chan.pvt = wc;
+ if (zt_register(&wc->span, 0)) {
+ printk("Unable to register span with zaptel\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int wcfxo_hardware_init(struct wcfxo *wc)
+{
+ /* Hardware stuff */
+ /* Reset PCI Interface chip and registers */
+ outb(0x0e, wc->ioaddr + WC_CNTL);
+ if (wc->flags & FLAG_RESET_ON_AUX5) {
+ /* Set hook state to on hook for when we switch.
+ Make sure reset is high */
+ outb(0x34, wc->ioaddr + WC_AUXD);
+ } else {
+ /* Set hook state to on hook for when we switch */
+ outb(0x24, wc->ioaddr + WC_AUXD);
+ }
+ /* Set all to outputs except AUX 4, which is an input */
+ outb(0xef, wc->ioaddr + WC_AUXC);
+
+ /* Back to normal, with automatic DMA wrap around */
+ outb(0x01, wc->ioaddr + WC_CNTL);
+
+ /* Make sure serial port and DMA are out of reset */
+ outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, wc->ioaddr + WC_CNTL);
+
+ /* Configure serial port for MSB->LSB operation */
+ if (wc->flags & FLAG_DOUBLE_CLOCK)
+ outb(0xc1, wc->ioaddr + WC_SERCTL);
+ else
+ outb(0xc0, wc->ioaddr + WC_SERCTL);
+
+ if (wc->flags & FLAG_USE_XTAL) {
+ /* Use the crystal oscillator */
+ outb(0x04, wc->ioaddr + WC_AUXFUNC);
+ }
+
+ /* Delay FSC by 2 so it's properly aligned */
+ outb(0x2, wc->ioaddr + WC_FSCDELAY);
+
+ /* Setup DMA Addresses */
+ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */
+ outl(wc->writedma + ZT_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */
+ outl(wc->writedma + ZT_CHUNKSIZE * 16 - 4, wc->ioaddr + WC_DMAWE); /* End */
+
+ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */
+ outl(wc->readdma + ZT_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */
+ outl(wc->readdma + ZT_CHUNKSIZE * 16 - 4, wc->ioaddr + WC_DMARE); /* End */
+
+ /* Clear interrupts */
+ outb(0xff, wc->ioaddr + WC_INTSTAT);
+ return 0;
+}
+
+static void wcfxo_enable_interrupts(struct wcfxo *wc)
+{
+ /* Enable interrupts (we care about all of them) */
+ outb(0x3f, wc->ioaddr + WC_MASK0);
+ /* No external interrupts */
+ outb(0x00, wc->ioaddr + WC_MASK1);
+}
+
+static void wcfxo_start_dma(struct wcfxo *wc)
+{
+ /* Reset Master and TDM */
+ outb(0x0f, wc->ioaddr + WC_CNTL);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ outb(0x01, wc->ioaddr + WC_CNTL);
+ outb(0x01, wc->ioaddr + WC_OPER);
+}
+
+static void wcfxo_restart_dma(struct wcfxo *wc)
+{
+ /* Reset Master and TDM */
+ outb(0x01, wc->ioaddr + WC_CNTL);
+ outb(0x01, wc->ioaddr + WC_OPER);
+}
+
+
+static void wcfxo_stop_dma(struct wcfxo *wc)
+{
+ outb(0x00, wc->ioaddr + WC_OPER);
+}
+
+static void wcfxo_reset_tdm(struct wcfxo *wc)
+{
+ /* Reset TDM */
+ outb(0x0f, wc->ioaddr + WC_CNTL);
+}
+
+static void wcfxo_disable_interrupts(struct wcfxo *wc)
+{
+ outb(0x00, wc->ioaddr + WC_MASK0);
+ outb(0x00, wc->ioaddr + WC_MASK1);
+}
+
+static void wcfxo_set_daa_mode(struct wcfxo *wc)
+{
+ /* Set country specific parameters (OHS, ACT, DCT, RZ, RT, LIM, VOL) */
+ int reg16 = ((fxo_modes[opermode].ohs & 0x1) << 6) |
+ ((fxo_modes[opermode].act & 0x1) << 5) |
+ ((fxo_modes[opermode].dct & 0x3) << 2) |
+ ((fxo_modes[opermode].rz & 0x1) << 1) |
+ ((fxo_modes[opermode].rt & 0x1) << 0);
+ int reg17 = ((fxo_modes[opermode].lim & 0x3) << 3);
+ int reg18 = ((fxo_modes[opermode].vol & 0x3) << 3);
+
+ if (wc->flags & FLAG_NO_I18N_REGS) {
+ wcfxo_dbg(wc->span, "This card does not support international settings.\n");
+ return;
+ }
+
+ wcfxo_setreg(wc, WC_DAA_INT_CTL1, reg16);
+ wcfxo_setreg(wc, WC_DAA_INT_CTL2, reg17);
+ wcfxo_setreg(wc, WC_DAA_INT_CTL3, reg18);
+
+
+ /* Wait a couple of jiffies for our writes to finish */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1 + (ZT_CHUNKSIZE * HZ) / 800);
+
+ printk("wcfxo: DAA mode is '%s'\n", fxo_modes[opermode].name);
+}
+
+static int wcfxo_init_daa(struct wcfxo *wc)
+{
+ /* This must not be called in an interrupt */
+ /* We let things settle for a bit */
+ unsigned char reg15;
+ int chip_revb;
+// set_current_state(TASK_INTERRUPTIBLE);
+// schedule_timeout(10);
+
+ /* Soft-reset it */
+ wcfxo_setreg(wc, WC_DAA_CTL1, 0x80);
+
+ /* Let the reset go */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1 + (ZT_CHUNKSIZE * HZ) / 800);
+
+ /* We have a clock at 18.432 Mhz, so N1=1, M1=2, CGM=0 */
+ wcfxo_setreg(wc, WC_DAA_PLL1_N1, 0x0); /* This value is N1 - 1 */
+ wcfxo_setreg(wc, WC_DAA_PLL1_M1, 0x1); /* This value is M1 - 1 */
+ /* We want to sample at 8khz, so N2 = 9, M2 = 10 (N2-1, M2-1) */
+ wcfxo_setreg(wc, WC_DAA_PLL2_N2_M2, 0x89);
+
+ /* Wait until the PLL's are locked. Time is between 100 uSec and 1 mSec */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1 + HZ/1000 + (ZT_CHUNKSIZE * HZ) / 800);
+
+ /* No additional ration is applied to the PLL and faster lock times
+ * are possible */
+ wcfxo_setreg(wc, WC_DAA_PLL_CTL, 0x0);
+ /* Enable off hook pin */
+ wcfxo_setreg(wc, WC_DAA_DCTL1, 0x0a);
+ if (monitor) {
+ /* Enable ISOcap and external speaker and charge pump if present */
+ wcfxo_setreg(wc, WC_DAA_DCTL2, 0x80);
+ } else {
+ /* Enable ISOcap and charge pump if present (leave speaker disabled) */
+ wcfxo_setreg(wc, WC_DAA_DCTL2, 0xe0);
+ }
+
+ /* Wait a couple of jiffies for our writes to finish */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1 + (ZT_CHUNKSIZE * HZ) / 800);
+ reg15 = 0x0;
+ /* Go ahead and attenuate transmit signal by 6 db */
+ if (quiet) {
+ printk("wcfxo: Attenuating transmit signal for quiet operation\n");
+ reg15 |= (quiet & 0x3) << 4;
+ }
+ if (boost) {
+ printk("wcfxo: Boosting receive signal\n");
+ reg15 |= (boost & 0x3);
+ }
+ wcfxo_setreg(wc, WC_DAA_TXRX_GCTL, reg15);
+
+ /* REVB: reg. 13, bits 5:2 */
+ chip_revb = (wc->readregs[WC_DAA_CHIPB_REV] >> 2) & 0xF;
+ wcfxo_dbg(wc->span, "DAA chip REVB is %x\n", chip_revb);
+ switch(chip_revb) {
+ case 1: case 2: case 3:
+ /* This is a si3034. Nothing to do */
+ break;
+ case 4: case 5: case 7:
+ /* This is 3035. Has no support for international registers */
+ wc->flags |= FLAG_NO_I18N_REGS;
+ break;
+ default:
+ wcfxo_notice(wc->span, "Unknown DAA chip revision: REVB=%d\n",
+ chip_revb);
+ }
+
+ /* Didn't get it right. Register 9 is still garbage */
+ if (wc->readregs[WC_DAA_PLL2_N2_M2] != 0x89)
+ return -1;
+#if 0
+ { int x;
+ int y;
+ for (y=0;y<100;y++) {
+ printk(" reg dump ====== %d ======\n", y);
+ for (x=0;x<sizeof(wecareregs) / sizeof(wecareregs[0]);x++) {
+ printk("daa: Reg %d: %02x\n", wecareregs[x], wc->readregs[wecareregs[x]]);
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(100);
+ } }
+#endif
+ return 0;
+}
+
+static int __devinit wcfxo_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct wcfxo *wc;
+ struct wcfxo_desc *d = (struct wcfxo_desc *)ent->driver_data;
+ int x;
+
+ for (x=0;x<WC_MAX_IFACES;x++)
+ if (!ifaces[x]) break;
+ if (x >= WC_MAX_IFACES) {
+ printk(KERN_ERR "Too many interfaces: Found %d, can only handle %d.\n",
+ x, WC_MAX_IFACES - 1);
+ return -EIO;
+ }
+
+ if (pci_enable_device(pdev))
+ return -EIO;
+
+ wc = kmalloc(sizeof(struct wcfxo), GFP_KERNEL);
+ if (!wc) {
+ printk(KERN_ERR "wcfxo: Failed initializinf card. Not enough memory.");
+ return -ENOMEM;
+ }
+
+ ifaces[x] = wc;
+ memset(wc, 0, sizeof(struct wcfxo));
+ wc->ioaddr = pci_resource_start(pdev, 0);
+ wc->dev = pdev;
+ wc->pos = x;
+ wc->variety = d->name;
+ wc->flags = d->flags;
+ /* Keep track of whether we need to free the region */
+ if (request_region(wc->ioaddr, 0xff, "wcfxo"))
+ 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, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, &wc->writedma);
+ if (!wc->writechunk) {
+ printk("wcfxo: Unable to allocate DMA-able memory\n");
+ if (wc->freeregion)
+ release_region(wc->ioaddr, 0xff);
+ return -ENOMEM;
+ }
+
+ wc->readchunk = wc->writechunk + ZT_MAX_CHUNKSIZE * 4; /* in doublewords */
+ wc->readdma = wc->writedma + ZT_MAX_CHUNKSIZE * 16; /* in bytes */
+
+ if (wcfxo_initialize(wc)) {
+ printk("wcfxo: Unable to intialize modem\n");
+ if (wc->freeregion)
+ release_region(wc->ioaddr, 0xff);
+ kfree(wc);
+ return -EIO;
+ }
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, wc);
+
+ if (request_irq(pdev->irq, wcfxo_interrupt, ZAP_IRQ_SHARED, "wcfxo", wc)) {
+ printk("wcfxo: Unable to request IRQ %d\n", pdev->irq);
+ if (wc->freeregion)
+ release_region(wc->ioaddr, 0xff);
+ kfree(wc);
+ return -EIO;
+ }
+
+
+ wcfxo_hardware_init(wc);
+ /* Enable interrupts */
+ wcfxo_enable_interrupts(wc);
+ /* Initialize Write/Buffers to all blank data */
+ memset((void *)wc->writechunk,0,ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4);
+ /* Start DMA */
+ wcfxo_start_dma(wc);
+
+ /* Initialize DAA (after it's started) */
+ if (wcfxo_init_daa(wc)) {
+ printk("Failed to initailize DAA, giving up...\n");
+ wcfxo_stop_dma(wc);
+ wcfxo_disable_interrupts(wc);
+ zt_unregister(&wc->span);
+ free_irq(pdev->irq, wc);
+
+ /* Reset PCI chip and registers */
+ outb(0x0e, wc->ioaddr + WC_CNTL);
+
+ if (wc->freeregion)
+ release_region(wc->ioaddr, 0xff);
+ kfree(wc);
+ return -EIO;
+ }
+ wcfxo_set_daa_mode(wc);
+ printk("Found a Wildcard FXO: %s\n", wc->variety);
+
+ return 0;
+}
+
+static void wcfxo_release(struct wcfxo *wc)
+{
+ zt_unregister(&wc->span);
+ if (wc->freeregion)
+ release_region(wc->ioaddr, 0xff);
+ kfree(wc);
+ printk("Freed a Wildcard\n");
+}
+
+static void __devexit wcfxo_remove_one(struct pci_dev *pdev)
+{
+ struct wcfxo *wc = pci_get_drvdata(pdev);
+ if (wc) {
+
+ /* Stop any DMA */
+ wcfxo_stop_dma(wc);
+ wcfxo_reset_tdm(wc);
+
+ /* In case hardware is still there */
+ wcfxo_disable_interrupts(wc);
+
+ /* Immediately free resources */
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma);
+ free_irq(pdev->irq, wc);
+
+ /* Reset PCI chip and registers */
+ outb(0x0e, wc->ioaddr + WC_CNTL);
+
+ /* Release span, possibly delayed */
+ if (!wc->usecount)
+ wcfxo_release(wc);
+ else
+ wc->dead = 1;
+ }
+}
+
+static struct pci_device_id wcfxo_pci_tbl[] = {
+ { 0xe159, 0x0001, 0x8084, PCI_ANY_ID, 0, 0, (unsigned long) &generic },
+ { 0xe159, 0x0001, 0x8085, PCI_ANY_ID, 0, 0, (unsigned long) &wcx101p },
+ { 0xe159, 0x0001, 0x8086, PCI_ANY_ID, 0, 0, (unsigned long) &generic },
+ { 0xe159, 0x0001, 0x8087, PCI_ANY_ID, 0, 0, (unsigned long) &generic },
+ { 0x1057, 0x5608, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcx100p },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE (pci, wcfxo_pci_tbl);
+
+static struct pci_driver wcfxo_driver = {
+ name: "wcfxo",
+ probe: wcfxo_init_one,
+#ifdef LINUX26
+ remove: __devexit_p(wcfxo_remove_one),
+#else
+ remove: wcfxo_remove_one,
+#endif
+ id_table: wcfxo_pci_tbl,
+};
+
+static int __init wcfxo_init(void)
+{
+ int res;
+ int x;
+ if ((opermode >= sizeof(fxo_modes) / sizeof(fxo_modes[0])) || (opermode < 0)) {
+ printk("Invalid/unknown operating mode specified. Please choose one of:\n");
+ for (x=0;x<sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++)
+ printk("%d: %s\n", x, fxo_modes[x].name);
+ return -ENODEV;
+ }
+ res = zap_pci_module(&wcfxo_driver);
+ if (res)
+ return -ENODEV;
+ return 0;
+}
+
+static void __exit wcfxo_cleanup(void)
+{
+ pci_unregister_driver(&wcfxo_driver);
+}
+
+#ifdef LINUX26
+module_param(debug, int, 0644);
+module_param(quiet, int, 0444);
+module_param(boost, int, 0444);
+module_param(monitor, int, 0444);
+module_param(opermode, int, 0444);
+#else
+MODULE_PARM(debug, "i");
+MODULE_PARM(quiet, "i");
+MODULE_PARM(boost, "i");
+MODULE_PARM(monitor, "i");
+MODULE_PARM(opermode, "i");
+#endif
+MODULE_DESCRIPTION("Wildcard X100P Zaptel Driver");
+MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(wcfxo_init);
+module_exit(wcfxo_cleanup);
diff --git a/drivers/dahdi/wct1xxp.c b/drivers/dahdi/wct1xxp.c
new file mode 100644
index 0000000..cfc5edd
--- /dev/null
+++ b/drivers/dahdi/wct1xxp.c
@@ -0,0 +1,1438 @@
+/*
+ * Linux Support Services, Inc. Wildcard T100P T1/PRI card Driver
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Matthew Fredrickson <creslin@digium.com>
+ * William Meadows <wmeadows@digium.com>
+ *
+ * Copyright (C) 2001, Linux Support Services, 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/usb.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+#define WC_MAX_CARDS 32
+
+/*
+#define TEST_REGS
+*/
+
+/* Define to get more attention-grabbing but slightly more I/O using
+ alarm status */
+#define FANCY_ALARM
+
+
+#define DELAY 0x0 /* 30 = 15 cycles, 10 = 8 cycles, 0 = 3 cycles */
+
+#define WC_CNTL 0x00
+#define WC_OPER 0x01
+#define WC_AUXC 0x02
+#define WC_AUXD 0x03
+#define WC_MASK0 0x04
+#define WC_MASK1 0x05
+#define WC_INTSTAT 0x06
+
+#define WC_DMAWS 0x08
+#define WC_DMAWI 0x0c
+#define WC_DMAWE 0x10
+#define WC_DMARS 0x18
+#define WC_DMARI 0x1c
+#define WC_DMARE 0x20
+#define WC_CURPOS 0x24
+
+#define WC_SERC 0x2d
+#define WC_FSCDELAY 0x2f
+
+#define WC_USERREG 0xc0
+
+#define WC_CLOCK 0x0
+#define WC_LEDTEST 0x1
+#define WC_VERSION 0x2
+
+/* Offset between transmit and receive */
+#define WC_OFFSET 4
+
+#define BIT_CS (1 << 7)
+#define BIT_ADDR (0xf << 3)
+
+#define BIT_LED0 (1 << 0)
+#define BIT_LED1 (1 << 1)
+#define BIT_TEST (1 << 2)
+
+static char *chips[] =
+{
+ "DS2152",
+ "DS21352",
+ "DS21552",
+ "Unknown Chip (3)",
+ "DS2154",
+ "DS21354",
+ "DS21554",
+ "Unknown Chip (7)",
+};
+
+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 };
+
+#ifdef FANCY_ALARM
+static int altab[] = {
+0, 0, 0, 1, 2, 3, 4, 6, 8, 9, 11, 13, 16, 18, 20, 22, 24, 25, 27, 28, 29, 30, 31, 31, 32, 31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0,
+};
+#endif
+
+struct t1xxp {
+ struct pci_dev *dev;
+ spinlock_t lock;
+ int ise1;
+ int num;
+ /* Our offset for finding channel 1 */
+ int offset;
+ char *variety;
+ unsigned int intcount;
+ int usecount;
+ int clocktimeout;
+ int sync;
+ int dead;
+ int blinktimer;
+ int alarmtimer;
+ int loopupcnt;
+ int loopdowncnt;
+ int miss;
+ int misslast;
+ int *chanmap;
+#ifdef FANCY_ALARM
+ int alarmpos;
+#endif
+ unsigned char ledtestreg;
+ unsigned char outbyte;
+ unsigned long ioaddr;
+ unsigned short canary;
+ /* T1 signalling */
+ unsigned char txsiga[3];
+ unsigned char txsigb[3];
+ dma_addr_t readdma;
+ dma_addr_t writedma;
+ volatile unsigned char *writechunk; /* Double-word aligned write memory */
+ volatile unsigned char *readchunk; /* Double-word aligned read memory */
+ unsigned char ec_chunk1[31][ZT_CHUNKSIZE];
+ unsigned char ec_chunk2[31][ZT_CHUNKSIZE];
+ unsigned char tempo[32];
+ struct zt_span span; /* Span */
+ struct zt_chan chans[31]; /* Channels */
+};
+
+#define CANARY 0xca1e
+
+int debug = 0; /* doesnt do anything */
+
+static struct t1xxp *cards[WC_MAX_CARDS];
+
+static inline void start_alarm(struct t1xxp *wc)
+{
+#ifdef FANCY_ALARM
+ wc->alarmpos = 0;
+#endif
+ wc->blinktimer = 0;
+}
+
+static inline void stop_alarm(struct t1xxp *wc)
+{
+#ifdef FANCY_ALARM
+ wc->alarmpos = 0;
+#endif
+ wc->blinktimer = 0;
+}
+
+static inline void __select_framer(struct t1xxp *wc, int reg)
+{
+ /* Top four bits of address from AUX 6-3 */
+ wc->outbyte &= ~BIT_CS;
+ wc->outbyte &= ~BIT_ADDR;
+ wc->outbyte |= (reg & 0xf0) >> 1;
+ outb(wc->outbyte, wc->ioaddr + WC_AUXD);
+}
+
+static inline void __select_control(struct t1xxp *wc)
+{
+ if (!(wc->outbyte & BIT_CS)) {
+ wc->outbyte |= BIT_CS;
+ outb(wc->outbyte, wc->ioaddr + WC_AUXD);
+ }
+}
+
+static int t1xxp_open(struct zt_chan *chan)
+{
+ struct t1xxp *wc = chan->pvt;
+ if (wc->dead)
+ return -ENODEV;
+ wc->usecount++;
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static int __t1_get_reg(struct t1xxp *wc, int reg)
+{
+ unsigned char res;
+ __select_framer(wc, reg);
+ /* Get value */
+ res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));
+ return res;
+}
+
+static int __t1_set_reg(struct t1xxp *wc, int reg, unsigned char val)
+{
+ __select_framer(wc, reg);
+ /* Send address */
+ outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));
+ return 0;
+}
+
+static int __control_set_reg(struct t1xxp *wc, int reg, unsigned char val)
+{
+ __select_control(wc);
+ outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));
+ return 0;
+}
+
+static int control_set_reg(struct t1xxp *wc, int reg, unsigned char val)
+{
+ unsigned long flags;
+ int res;
+ spin_lock_irqsave(&wc->lock, flags);
+ res = __control_set_reg(wc, reg, val);
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return res;
+}
+
+static int __control_get_reg(struct t1xxp *wc, int reg)
+{
+ unsigned char res;
+ /* The following makes UTTERLY no sense, but what was happening
+ was that reads in some cases were not actually happening
+ on the physical bus. Why, we dunno. But in debugging, we found
+ that writing before reading (in this case to an unused position)
+ seems to get rid of the problem */
+ __control_set_reg(wc,3,0x69); /* do magic here */
+ /* now get the read byte from the Xilinx part */
+ res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));
+ return res;
+}
+
+static int control_get_reg(struct t1xxp *wc, int reg)
+{
+ unsigned long flags;
+ int res;
+ spin_lock_irqsave(&wc->lock, flags);
+ res = __control_get_reg(wc, reg);
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return res;
+}
+
+static void t1xxp_release(struct t1xxp *wc)
+{
+ zt_unregister(&wc->span);
+ kfree(wc);
+ printk("Freed a Wildcard\n");
+}
+
+static int t1xxp_close(struct zt_chan *chan)
+{
+ struct t1xxp *wc = chan->pvt;
+ wc->usecount--;
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ /* If we're dead, release us now */
+ if (!wc->usecount && wc->dead)
+ t1xxp_release(wc);
+ return 0;
+}
+
+static void t1xxp_enable_interrupts(struct t1xxp *wc)
+{
+ /* Clear interrupts */
+ outb(0xff, wc->ioaddr + WC_INTSTAT);
+ /* Enable interrupts (we care about all of them) */
+ outb(0x3c /* 0x3f */, wc->ioaddr + WC_MASK0);
+ /* No external interrupts */
+ outb(0x00, wc->ioaddr + WC_MASK1);
+}
+
+static void t1xxp_start_dma(struct t1xxp *wc)
+{
+ /* Reset Master and TDM */
+ outb(DELAY | 0x0f, wc->ioaddr + WC_CNTL);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ outb(DELAY | 0x01, wc->ioaddr + WC_CNTL);
+ outb(0x01, wc->ioaddr + WC_OPER);
+ if (debug) printk("Started DMA\n");
+}
+
+static void __t1xxp_stop_dma(struct t1xxp *wc)
+{
+ outb(0x00, wc->ioaddr + WC_OPER);
+}
+
+static void __t1xxp_disable_interrupts(struct t1xxp *wc)
+{
+ outb(0x00, wc->ioaddr + WC_MASK0);
+ outb(0x00, wc->ioaddr + WC_MASK1);
+}
+
+static void __t1xxp_set_clear(struct t1xxp *wc)
+{
+ /* Setup registers */
+ int x,y;
+ unsigned char b;
+
+ /* No such thing under E1 */
+ if (wc->ise1) {
+ printk("Can't set clear mode on an E1!\n");
+ return;
+ }
+
+ for (x=0;x<3;x++) {
+ b = 0;
+ for (y=0;y<8;y++)
+ if (wc->chans[x * 8 + y].sig & ZT_SIG_CLEAR)
+ b |= (1 << y);
+ __t1_set_reg(wc, 0x39 + x, b);
+ }
+}
+
+static void t1xxp_t1_framer_start(struct t1xxp *wc)
+{
+ int i;
+ char *coding, *framing;
+ unsigned long endjiffies;
+ int alreadyrunning = wc->span.flags & ZT_FLAG_RUNNING;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->lock, flags);
+
+ /* Build up config */
+ i = 0x20;
+ if (wc->span.lineconfig & ZT_CONFIG_ESF) {
+ coding = "ESF";
+ i = 0x88;
+ } else {
+ coding = "SF";
+ }
+ if (wc->span.lineconfig & ZT_CONFIG_B8ZS) {
+ framing = "B8ZS";
+ i |= 0x44;
+ } else {
+ framing = "AMI";
+ }
+ __t1_set_reg(wc, 0x38, i);
+ if (!(wc->span.lineconfig & ZT_CONFIG_ESF)) {
+ /* 1c in FDL bit */
+ __t1_set_reg(wc, 0x7e, 0x1c);
+ } else {
+ __t1_set_reg(wc, 0x7e, 0x00);
+ }
+
+ /* Set outgoing LBO */
+ __t1_set_reg(wc, 0x7c, wc->span.txlevel << 5);
+
+ printk("Using %s/%s coding/framing\n", coding, framing);
+ if (!alreadyrunning) {
+ /* Setup the clear channels */
+ __t1xxp_set_clear(wc);
+
+ /* Set LIRST bit to 1 */
+ __t1_set_reg(wc, 0x0a, 0x80);
+ spin_unlock_irqrestore(&wc->lock, flags);
+
+ /* Wait 100ms to give plenty of time for reset */
+ endjiffies = jiffies + 10;
+ while(endjiffies < jiffies);
+
+ spin_lock_irqsave(&wc->lock, flags);
+
+ /* Reset LIRST bit and reset elastic stores */
+ __t1_set_reg(wc, 0xa, 0x30);
+
+ wc->span.flags |= ZT_FLAG_RUNNING;
+ }
+ spin_unlock_irqrestore(&wc->lock, flags);
+}
+
+static void t1xxp_e1_framer_start(struct t1xxp *wc)
+{
+ int i;
+ char *coding, *framing;
+ unsigned long endjiffies;
+ int alreadyrunning = wc->span.flags & ZT_FLAG_RUNNING;
+ unsigned long flags;
+ char *crcing = "";
+ unsigned char ccr1, tcr1, tcr2;
+
+ spin_lock_irqsave(&wc->lock, flags);
+
+ /* Build up config */
+ ccr1 = 0;
+ tcr1 = 8;
+ tcr2 = 0;
+ if (wc->span.lineconfig & ZT_CONFIG_CCS) {
+ coding = "CCS"; /* Receive CCS */
+ ccr1 |= 8;
+ } else {
+ tcr1 |= 0x20;
+ coding = "CAS";
+ }
+ if (wc->span.lineconfig & ZT_CONFIG_HDB3) {
+ ccr1 |= 0x44; /* TX/RX HDB3 */
+ framing = "HDB3";
+ } else {
+ framing = "AMI";
+ }
+ if (wc->span.lineconfig & ZT_CONFIG_CRC4) {
+ ccr1 |= 0x11;
+ tcr2 |= 0x02;
+ crcing = " with CRC4";
+ }
+ __t1_set_reg(wc, 0x12, tcr1);
+ __t1_set_reg(wc, 0x13, tcr2);
+ __t1_set_reg(wc, 0x14, ccr1);
+ __t1_set_reg(wc, 0x18, 0x20); /* 120 Ohm */
+
+
+#if 0 /* XXX Does LBO Matter? XXX */
+ /* Set outgoing LBO */
+ __t1_set_reg(wc, 0x7c, wc->span.txlevel << 5);
+#endif
+
+ printk("Using %s/%s coding/framing%s 120 Ohms\n", coding, framing,crcing);
+ if (!alreadyrunning) {
+
+ __t1_set_reg(wc,0x1b,0x8a); /* CCR3: LIRST & TSCLKM */
+ __t1_set_reg(wc,0x20,0x1b); /* TAFR */
+ __t1_set_reg(wc,0x21,0x5f); /* TNAFR */
+ __t1_set_reg(wc,0x40,0xb); /* TSR1 */
+ for(i = 0x41; i <= 0x4f; i++) __t1_set_reg(wc,i,0x55);
+ for(i = 0x22; i <= 0x25; i++) __t1_set_reg(wc,i,0xff);
+ spin_unlock_irqrestore(&wc->lock, flags);
+
+ /* Wait 100ms to give plenty of time for reset */
+ endjiffies = jiffies + 10;
+ while(endjiffies < jiffies);
+
+ spin_lock_irqsave(&wc->lock, flags);
+
+ __t1_set_reg(wc, 0x1b, 0x9a); /* Set ESR */
+ __t1_set_reg(wc, 0x1b, 0x82); /* TSCLKM only now */
+
+ /* Reset LIRST bit and reset elastic stores */
+
+ wc->span.flags |= ZT_FLAG_RUNNING;
+ }
+ spin_unlock_irqrestore(&wc->lock, flags);
+}
+
+static int t1xxp_framer_sanity_check(struct t1xxp *wc)
+{
+ int res;
+ int chipid;
+ unsigned long flags;
+ int x;
+
+ /* Sanity check */
+ spin_lock_irqsave(&wc->lock, flags);
+ for (x=0x0;x<192;x++)
+ __t1_set_reg(wc, x, 0);
+ res = __t1_get_reg(wc, 0x0f);
+ res = __t1_get_reg(wc, 0x0f);
+ chipid = ((res & 0x80) >> 5) | ((res & 0x30) >> 4);
+ wc->ise1 = (res & 0x80) ? (1 << 4) : 0;
+ spin_unlock_irqrestore(&wc->lock, flags);
+
+ printk("Framer: %s, Revision: %d (%s)\n", chips[chipid], res & 0xf, wc->ise1 ? "E1" : "T1");
+ return 0;
+}
+
+static int t1xxp_framer_hard_reset(struct t1xxp *wc)
+{
+ int x;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->lock, flags);
+ /* Initialize all registers to 0 */
+ for (x=0x0;x<192;x++)
+ __t1_set_reg(wc, x, 0);
+
+ if (wc->ise1) {
+ /* Set LOTCMC (switch to RCLCK if TCLK fails) */
+ __t1_set_reg(wc, 0x1a, 0x04);
+
+ /* RSYNC is an input */
+ __t1_set_reg(wc, 0x10, 0x20);
+
+ /* Rx elastic store enabled, 2.048 Mhz (in theory) */
+ __t1_set_reg(wc, 0x11, 0x06);
+
+ /* TSYNC is an input, Tsis mode */
+ __t1_set_reg(wc, 0x12, 0x08);
+
+ /* Tx elastic store enabled, 2.048 Mhz (in theory) */
+ __t1_set_reg(wc, 0x1b, 0x82);
+
+
+
+ } else {
+ /* Full-on sync required for T1 */
+ __t1_set_reg(wc, 0x2b, 0x08);
+ /* RSYNC is an input */
+ __t1_set_reg(wc, 0x2c, 0x08);
+
+ /* Enable tx RBS bits */
+ __t1_set_reg(wc, 0x35, 0x10);
+
+ /* TSYNC is output */
+ __t1_set_reg(wc, 0x36, 0x04);
+
+ /* Tx and Rx elastic store enabled, 2.048 Mhz (in theory) */
+ __t1_set_reg(wc, 0x37, 0x9c);
+
+ /* Setup Loopup / Loopdown codes */
+ __t1_set_reg(wc, 0x12, 0x22);
+ __t1_set_reg(wc, 0x14, 0x80);
+ __t1_set_reg(wc, 0x15, 0x80);
+ }
+
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return 0;
+}
+
+static int t1xxp_rbsbits(struct zt_chan *chan, int bits)
+{
+ struct t1xxp *wc = chan->pvt;
+ unsigned long flags;
+ int b,o;
+ unsigned char mask;
+
+ /* Byte offset */
+ spin_lock_irqsave(&wc->lock, flags);
+ if (wc->ise1) {
+ if (chan->chanpos < 16) {
+ mask = ((bits << 4) | wc->chans[chan->chanpos - 1 + 16].txsig);
+ __t1_set_reg(wc, 0x40 + chan->chanpos, mask);
+ }
+ else if (chan->chanpos > 16) {
+ mask = (bits | (wc->chans[chan->chanpos - 1 - 16].txsig << 4));
+ __t1_set_reg(wc, 0x40 + chan->chanpos - 16, mask);
+ }
+ wc->chans[chan->chanpos - 1].txsig = bits;
+ } else {
+ b = (chan->chanpos - 1) / 8;
+ o = (chan->chanpos - 1) % 8;
+
+ mask = (1 << o);
+
+ if (bits & ZT_ABIT) {
+ /* Set A-bit */
+ wc->txsiga[b] |= mask;
+ } else {
+ /* Clear A-bit */
+ wc->txsiga[b] &= ~mask;
+ }
+ if (bits & ZT_BBIT) {
+ /* Set B-bit */
+ wc->txsigb[b] |= mask;
+ } else {
+ wc->txsigb[b] &= ~mask;
+ }
+ /* Output new values */
+ __t1_set_reg(wc, 0x70 + b, wc->txsiga[b]);
+ __t1_set_reg(wc, 0x73 + b, wc->txsigb[b]);
+ __t1_set_reg(wc, 0x76 + b, wc->txsiga[b]);
+ __t1_set_reg(wc, 0x79 + b, wc->txsigb[b]);
+ }
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return 0;
+}
+
+static int t1xxp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
+{
+ switch(cmd) {
+ default:
+ return -ENOTTY;
+ }
+}
+
+static int t1xxp_startup(struct zt_span *span)
+{
+ struct t1xxp *wc = span->pvt;
+
+ int i,alreadyrunning = span->flags & ZT_FLAG_RUNNING;
+
+ /* 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 */
+ if (wc->ise1)
+ t1xxp_e1_framer_start(wc);
+ else
+ t1xxp_t1_framer_start(wc);
+ printk("Calling startup (flags is %d)\n", span->flags);
+
+ if (!alreadyrunning) {
+ /* Only if we're not already going */
+ t1xxp_enable_interrupts(wc);
+ t1xxp_start_dma(wc);
+ span->flags |= ZT_FLAG_RUNNING;
+ }
+ return 0;
+}
+
+static int t1xxp_shutdown(struct zt_span *span)
+{
+ struct t1xxp *wc = span->pvt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->lock, flags);
+ __t1xxp_stop_dma(wc);
+ __t1xxp_disable_interrupts(wc);
+ span->flags &= ~ZT_FLAG_RUNNING;
+ spin_unlock_irqrestore(&wc->lock, flags);
+
+ t1xxp_framer_hard_reset(wc);
+ return 0;
+}
+
+static int t1xxp_maint(struct zt_span *span, int cmd)
+{
+ struct t1xxp *wc = span->pvt;
+ int res = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&wc->lock, flags);
+ if (wc->ise1) {
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ __t1_set_reg(wc,0xa8,0); /* no loops */
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ __t1_set_reg(wc,0xa8,0x40); /* local loop */
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ __t1_set_reg(wc,0xa8,0x80); /* remote loop */
+ break;
+ case ZT_MAINT_LOOPUP:
+ case ZT_MAINT_LOOPDOWN:
+ case ZT_MAINT_LOOPSTOP:
+ res = -ENOSYS;
+ break;
+ default:
+ printk("wct1xxp/E1: Unknown maint command: %d\n", cmd);
+ res = -EINVAL;
+ break;
+ }
+ } else {
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ __t1_set_reg(wc,0x19,0); /* no local loop */
+ __t1_set_reg(wc,0x0a,0); /* no remote loop */
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ __t1_set_reg(wc,0x19,0x40); /* local loop */
+ __t1_set_reg(wc,0x0a,0); /* no remote loop */
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ __t1_set_reg(wc,0x1e,0); /* no local loop */
+ __t1_set_reg(wc,0x0a,0x40); /* remote loop */
+ break;
+ case ZT_MAINT_LOOPUP:
+ __t1_set_reg(wc,0x30,2); /* send loopup code */
+ __t1_set_reg(wc,0x12,0x22); /* send loopup code */
+ __t1_set_reg(wc,0x13,0x80); /* send loopup code */
+ break;
+ case ZT_MAINT_LOOPDOWN:
+ __t1_set_reg(wc,0x30,2); /* send loopdown code */
+ __t1_set_reg(wc,0x12,0x62); /* send loopdown code */
+ __t1_set_reg(wc,0x13,0x90); /* send loopdown code */
+ break;
+ case ZT_MAINT_LOOPSTOP:
+ __t1_set_reg(wc,0x30,0); /* stop sending loopup code */
+ break;
+ default:
+ printk("wct1xxp/T1: Unknown maint command: %d\n", cmd);
+ res = -EINVAL;
+ }
+ }
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return res;
+}
+
+static int t1xxp_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ struct t1xxp *wc = chan->pvt;
+ unsigned long flags;
+ int alreadyrunning = chan->span->flags & ZT_FLAG_RUNNING;
+
+ spin_lock_irqsave(&wc->lock, flags);
+
+ if (alreadyrunning && !wc->ise1)
+ __t1xxp_set_clear(wc);
+
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return 0;
+}
+
+static int t1xxp_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+ struct t1xxp *wc = span->pvt;
+
+ /* Do we want to SYNC on receive or not */
+ wc->sync = lc->sync;
+ /* If already running, apply changes immediately */
+ if (span->flags & ZT_FLAG_RUNNING)
+ return t1xxp_startup(span);
+
+ return 0;
+}
+static int t1xxp_software_init(struct t1xxp *wc)
+{
+ int x;
+ /* Find position */
+ for (x=0;x<WC_MAX_CARDS;x++) {
+ if (!cards[x]) {
+ cards[x] = wc;
+ break;
+ }
+ }
+ if (x >= WC_MAX_CARDS)
+ return -1;
+ wc->num = x;
+ sprintf(wc->span.name, "WCT1/%d", wc->num);
+ snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num);
+ wc->span.manufacturer = "Digium";
+ zap_copy_string(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype));
+ snprintf(wc->span.location, sizeof(wc->span.location) - 1,
+ "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1);
+ wc->span.spanconfig = t1xxp_spanconfig;
+ wc->span.chanconfig = t1xxp_chanconfig;
+ wc->span.irq = wc->dev->irq;
+ 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.chans = wc->chans;
+ wc->span.flags = ZT_FLAG_RBS;
+ wc->span.ioctl = t1xxp_ioctl;
+ wc->span.pvt = wc;
+ if (wc->ise1) {
+ wc->span.channels = 31;
+ wc->span.deflaw = ZT_LAW_ALAW;
+ wc->span.linecompat = ZT_CONFIG_HDB3 | ZT_CONFIG_CCS | ZT_CONFIG_CRC4;
+ wc->span.spantype = "E1";
+ } else {
+ wc->span.channels = 24;
+ wc->span.deflaw = ZT_LAW_MULAW;
+ wc->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
+ wc->span.spantype = "T1";
+ }
+ 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)) {
+ printk("Unable to register span with zaptel\n");
+ return -1;
+ }
+ return 0;
+}
+
+static inline void __handle_leds(struct t1xxp *wc)
+{
+ int oldreg;
+ wc->blinktimer++;
+
+ if (wc->span.alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE)) {
+ /* Red/Blue alarm */
+#ifdef FANCY_ALARM
+ if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) {
+ wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0;
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ }
+ if (wc->blinktimer == 0xf) {
+ wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1);
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ wc->blinktimer = -1;
+ wc->alarmpos++;
+ if (wc->alarmpos >= (sizeof(altab) / sizeof(altab[0])))
+ wc->alarmpos = 0;
+ }
+#else
+ if (wc->blinktimer == 160) {
+ wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0;
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ } else if (wc->blinktimer == 480) {
+ wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1);
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ wc->blinktimer = 0;
+ }
+#endif
+ } else if (wc->span.alarms & ZT_ALARM_YELLOW) {
+ /* Yellow Alarm */
+ if (!(wc->blinktimer % 2))
+ wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0;
+ else
+ wc->ledtestreg = (wc->ledtestreg | BIT_LED0) & ~BIT_LED1;
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ } else {
+ /* No Alarm */
+ oldreg = wc->ledtestreg;
+ if (wc->span.maintstat != ZT_MAINT_NONE)
+ wc->ledtestreg |= BIT_TEST;
+ else
+ wc->ledtestreg &= ~BIT_TEST;
+ if (wc->span.flags & ZT_FLAG_RUNNING)
+ wc->ledtestreg = (wc->ledtestreg | BIT_LED0) & ~BIT_LED1;
+ else
+ wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1);
+ if (oldreg != wc->ledtestreg)
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ }
+}
+
+static void t1xxp_transmitprep(struct t1xxp *wc, int ints)
+{
+ volatile unsigned char *txbuf;
+ int x,y;
+ int pos;
+ if (ints & 0x04 /* 0x01 */) {
+ /* We just finished sending the first buffer, start filling it
+ now */
+ txbuf = wc->writechunk;
+ } else {
+ /* Just finished sending second buffer, fill it now */
+ txbuf = wc->writechunk + 32 * ZT_CHUNKSIZE;
+ }
+ zt_transmit(&wc->span);
+ for (x=0;x<wc->offset;x++)
+ txbuf[x] = wc->tempo[x];
+ for (y=0;y<ZT_CHUNKSIZE;y++) {
+ for (x=0;x<wc->span.channels;x++) {
+ pos = y * 32 + wc->chanmap[x] + wc->offset;
+ /* Put channel number as outgoing data */
+ if (pos < 32 * ZT_CHUNKSIZE)
+ txbuf[pos] = wc->chans[x].writechunk[y];
+ else
+ wc->tempo[pos - 32 * ZT_CHUNKSIZE] = wc->chans[x].writechunk[y];
+ }
+ }
+}
+
+static void t1xxp_receiveprep(struct t1xxp *wc, int ints)
+{
+ volatile unsigned char *rxbuf;
+ volatile unsigned int *canary;
+ int x;
+ int y;
+ unsigned int oldcan;
+ if (ints & 0x04) {
+ /* Just received first buffer */
+ rxbuf = wc->readchunk;
+ canary = (unsigned int *)(wc->readchunk + ZT_CHUNKSIZE * 64 - 4);
+ } else {
+ rxbuf = wc->readchunk + ZT_CHUNKSIZE * 32;
+ canary = (unsigned int *)(wc->readchunk + ZT_CHUNKSIZE * 32 - 4);
+ }
+ oldcan = *canary;
+ if (((oldcan & 0xffff0000) >> 16) != CANARY) {
+ /* Check top part */
+ if (debug) printk("Expecting top %04x, got %04x\n", CANARY, (oldcan & 0xffff0000) >> 16);
+ wc->span.irqmisses++;
+ } else if ((oldcan & 0xffff) != ((wc->canary - 1) & 0xffff)) {
+ if (debug) printk("Expecting bottom %d, got %d\n", wc->canary - 1, oldcan & 0xffff);
+ wc->span.irqmisses++;
+ }
+ for (y=0;y<ZT_CHUNKSIZE;y++) {
+ for (x=0;x<wc->span.channels;x++) {
+ /* XXX Optimize, remove * and + XXX */
+ /* Must map received channels into appropriate data */
+ wc->chans[x].readchunk[y] =
+ rxbuf[32 * y + ((wc->chanmap[x] + WC_OFFSET + wc->offset) & 0x1f)];
+ }
+ if (!wc->ise1) {
+ for (x=3;x<32;x+=4) {
+ if (rxbuf[32 * y + ((x + WC_OFFSET) & 0x1f)] == 0x7f) {
+ if (wc->offset != (x-3)) {
+ /* Resync */
+ control_set_reg(wc, WC_CLOCK, 0x02 | wc->sync | wc->ise1);
+ wc->clocktimeout = 100;
+#if 1
+ if (debug) printk("T1: Lost our place, resyncing\n");
+#endif
+ }
+ }
+ }
+ } else {
+ if (!wc->clocktimeout && !wc->span.alarms) {
+ if ((rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)] & 0x7f) != 0x1b) {
+ if (wc->miss) {
+ if (debug) printk("Double miss (%d, %d)...\n", wc->misslast, rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)]);
+ control_set_reg(wc, WC_CLOCK, 0x02 | wc->sync | wc->ise1);
+ wc->clocktimeout = 100;
+ } else {
+ wc->miss = 1;
+ wc->misslast = rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)];
+ }
+ } else {
+ wc->miss = 0;
+ }
+ } else {
+ wc->miss = 0;
+ }
+ }
+ }
+ /* Store the next canary */
+ canary = (unsigned int *)(rxbuf + ZT_CHUNKSIZE * 32 - 4);
+ *canary = (wc->canary++) | (CANARY << 16);
+ 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);
+}
+
+static void t1xxp_check_sigbits(struct t1xxp *wc, int x)
+{
+ int a,b,i,y,rxs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->lock, flags);
+ if (wc->ise1) {
+ /* Read 5 registers at a time, loading 10 channels at a time */
+ for (i = (x * 5); i < (x * 5) + 5; i++) {
+ a = __t1_get_reg(wc, 0x31 + i);
+ /* Get high channel in low bits */
+ rxs = (a & 0xf);
+ if (!(wc->chans[i+16].sig & ZT_SIG_CLEAR)) {
+ if (wc->chans[i+16].rxsig != rxs) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_rbsbits(&wc->chans[i+16], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ rxs = (a >> 4) & 0xf;
+ if (!(wc->chans[i].sig & ZT_SIG_CLEAR)) {
+ if (wc->chans[i].rxsig != rxs) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_rbsbits(&wc->chans[i], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ }
+ } else {
+ a = __t1_get_reg(wc, 0x60 + x);
+ b = __t1_get_reg(wc, 0x63 + x);
+ for (y=0;y<8;y++) {
+ i = x * 8 + y;
+ rxs = 0;
+ if (a & (1 << y))
+ rxs |= ZT_ABIT;
+ if (b & (1 << y))
+ rxs |= ZT_BBIT;
+ if (!(wc->chans[i].sig & ZT_SIG_CLEAR)) {
+ if (wc->chans[i].rxsig != rxs) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_rbsbits(&wc->chans[i], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ }
+ }
+ spin_unlock_irqrestore(&wc->lock, flags);
+}
+
+static void t1xxp_check_alarms(struct t1xxp *wc)
+{
+ unsigned char c,d;
+ int alarms;
+ int x,j;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->lock, flags);
+
+ if (wc->ise1) {
+ __t1_set_reg(wc, 0x06, 0xff);
+ c = __t1_get_reg(wc, 0x6);
+ } else {
+ /* Get RIR2 */
+ c = __t1_get_reg(wc, 0x31);
+ wc->span.rxlevel = c >> 6;
+
+ /* Get status register s*/
+ __t1_set_reg(wc, 0x20, 0xff);
+ c = __t1_get_reg(wc, 0x20);
+ }
+
+ /* Assume no alarms */
+ alarms = 0;
+
+ /* And consider only carrier alarms */
+ wc->span.alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN);
+
+ if (wc->ise1) {
+ /* XXX Implement me XXX */
+ } else {
+ /* Detect loopup code if we're not sending one */
+ if ((!wc->span.mainttimer) && (c & 0x80)) {
+ /* Loop-up code detected */
+ if ((wc->loopupcnt++ > 80) && (wc->span.maintstat != ZT_MAINT_REMOTELOOP)) {
+ __t1_set_reg(wc, 0x1e, 0); /* No local loop */
+ __t1_set_reg(wc, 0x0a, 0x40); /* Remote Loop */
+ wc->span.maintstat = ZT_MAINT_REMOTELOOP;
+ }
+ } else {
+ wc->loopupcnt = 0;
+ }
+ /* Same for loopdown code */
+ if ((!wc->span.mainttimer) && (c & 0x40)) {
+ /* Loop-down code detected */
+ if ((wc->loopdowncnt++ > 80) && (wc->span.maintstat == ZT_MAINT_REMOTELOOP)) {
+ __t1_set_reg(wc, 0x1e, 0); /* No local loop */
+ __t1_set_reg(wc, 0x0a, 0x0); /* No 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->chans[x].flags & ZT_FLAG_OPEN) ||
+ (wc->chans[x].flags & ZT_FLAG_NETDEV))
+ j++;
+ if (!j)
+ alarms |= ZT_ALARM_NOTOPEN;
+ }
+
+ if (wc->ise1) {
+ if (c & 0x9)
+ alarms |= ZT_ALARM_RED;
+ if (c & 0x2)
+ alarms |= ZT_ALARM_BLUE;
+ } else {
+ /* Check actual alarm status */
+ if (c & 0x3)
+ alarms |= ZT_ALARM_RED;
+ if (c & 0x8)
+ alarms |= ZT_ALARM_BLUE;
+ }
+ /* Keep track of recovering */
+ if ((!alarms) && wc->span.alarms)
+ wc->alarmtimer = ZT_ALARMSETTLE_TIME;
+
+ /* If receiving alarms, go into Yellow alarm state */
+ if (alarms && (!wc->span.alarms)) {
+#if 0
+ printk("Going into yellow alarm\n");
+#endif
+ if (wc->ise1)
+ __t1_set_reg(wc, 0x21, 0x7f);
+ else
+ __t1_set_reg(wc, 0x35, 0x11);
+ }
+
+ if (wc->span.alarms != alarms) {
+ d = __control_get_reg(wc, WC_CLOCK);
+ start_alarm(wc);
+ if (!(alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_LOOPBACK)) &&
+ wc->sync) {
+ /* Use the recieve signalling */
+ wc->span.syncsrc = wc->span.spanno;
+ d |= 1;
+ } else {
+ wc->span.syncsrc = 0;
+ d &= ~1;
+ }
+ __control_set_reg(wc, WC_CLOCK, d);
+ }
+ if (wc->alarmtimer)
+ alarms |= ZT_ALARM_RECOVER;
+ if (c & 0x4)
+ alarms |= ZT_ALARM_YELLOW;
+
+ wc->span.alarms = alarms;
+
+ spin_unlock_irqrestore(&wc->lock, flags);
+
+ zt_alarm_notify(&wc->span);
+}
+
+static void t1xxp_do_counters(struct t1xxp *wc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->lock, flags);
+ if (wc->alarmtimer) {
+ if (!--wc->alarmtimer) {
+ wc->span.alarms &= ~(ZT_ALARM_RECOVER);
+ /* Clear yellow alarm */
+#if 0
+ printk("Coming out of alarm\n");
+#endif
+ if (wc->ise1)
+ __t1_set_reg(wc, 0x21, 0x5f);
+ else
+ __t1_set_reg(wc, 0x35, 0x10);
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_alarm_notify(&wc->span);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ spin_unlock_irqrestore(&wc->lock, flags);
+}
+
+ZAP_IRQ_HANDLER(t1xxp_interrupt)
+{
+ struct t1xxp *wc = dev_id;
+ unsigned char ints;
+ unsigned long flags;
+ int x;
+
+ ints = inb(wc->ioaddr + WC_INTSTAT);
+ if (!ints)
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+
+ outb(ints, wc->ioaddr + WC_INTSTAT);
+
+ if (!wc->intcount) {
+ if (debug) printk("Got interrupt: 0x%04x\n", ints);
+ }
+ wc->intcount++;
+
+ if (wc->clocktimeout && !--wc->clocktimeout)
+ control_set_reg(wc, WC_CLOCK, 0x00 | wc->sync | wc->ise1);
+
+ if (ints & 0x0f) {
+ t1xxp_receiveprep(wc, ints);
+ t1xxp_transmitprep(wc, ints);
+ }
+ spin_lock_irqsave(&wc->lock, flags);
+
+#if 1
+ __handle_leds(wc);
+#endif
+
+ spin_unlock_irqrestore(&wc->lock, flags);
+
+ /* Count down timers */
+ t1xxp_do_counters(wc);
+
+ /* Do some things that we don't have to do very often */
+ x = wc->intcount & 15 /* 63 */;
+ switch(x) {
+ case 0:
+ case 1:
+ case 2:
+ t1xxp_check_sigbits(wc, x);
+ break;
+ case 4:
+ /* Check alarms 1/4 as frequently */
+ if (!(wc->intcount & 0x30))
+ t1xxp_check_alarms(wc);
+ break;
+ }
+
+ if (ints & 0x10)
+ printk("PCI Master abort\n");
+
+ if (ints & 0x20)
+ printk("PCI Target abort\n");
+
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+}
+
+static int t1xxp_hardware_init(struct t1xxp *wc)
+{
+ /* Hardware PCI stuff */
+ /* Reset chip and registers */
+ outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL);
+ /* Set all outputs to 0 */
+ outb(0x00, wc->ioaddr + WC_AUXD);
+ /* Set all to outputs except AUX1 (TDO). */
+ outb(0xfd, wc->ioaddr + WC_AUXC);
+ /* Configure the serial port: double clock, 20ns width, no inversion,
+ MSB first */
+ outb(0xc8, wc->ioaddr + WC_SERC);
+
+ /* Internally delay FSC by one */
+ outb(0x01, wc->ioaddr + WC_FSCDELAY);
+
+ /* Back to normal, with automatic DMA wrap around */
+ outb(DELAY | 0x01, wc->ioaddr + WC_CNTL);
+
+ /* Make sure serial port and DMA are out of reset */
+ outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, WC_CNTL);
+
+ /* Setup DMA Addresses */
+ /* Start at writedma */
+ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */
+ /* First frame */
+ outl(wc->writedma + ZT_CHUNKSIZE * 32 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */
+ /* Second frame */
+ outl(wc->writedma + ZT_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMAWE); /* End */
+
+ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */
+ /* First frame */
+ outl(wc->readdma + ZT_CHUNKSIZE * 32 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */
+ /* Second frame */
+ outl(wc->readdma + ZT_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMARE); /* End */
+
+ if (debug) printk("Setting up DMA (write/read = %08lx/%08lx)\n", (long)wc->writedma, (long)wc->readdma);
+
+ /* Check out the controller */
+ if (debug) printk("Controller version: %02x\n", control_get_reg(wc, WC_VERSION));
+
+
+ control_set_reg(wc, WC_LEDTEST, 0x00);
+
+ /* Sanity check also determines e1 or t1 */
+ if (t1xxp_framer_sanity_check(wc))
+ return -1;
+ if (wc->ise1)
+ wc->chanmap = chanmap_e1;
+ else
+ wc->chanmap = chanmap_t1;
+ /* Setup clock appropriately */
+ control_set_reg(wc, WC_CLOCK, 0x02 | wc->sync | wc->ise1);
+ wc->clocktimeout = 100;
+
+ /* Reset the T1 and report */
+ t1xxp_framer_hard_reset(wc);
+ start_alarm(wc);
+ return 0;
+
+}
+
+static int __devinit t1xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int res;
+ struct t1xxp *wc;
+ unsigned int *canary;
+
+ if (pci_enable_device(pdev)) {
+ res = -EIO;
+ } else {
+ wc = kmalloc(sizeof(struct t1xxp), GFP_KERNEL);
+ if (wc) {
+ memset(wc, 0x0, sizeof(struct t1xxp));
+ spin_lock_init(&wc->lock);
+ wc->ioaddr = pci_resource_start(pdev, 0);
+ wc->dev = pdev;
+ wc->offset = 28; /* And you thought 42 was the answer */
+
+ wc->writechunk =
+ /* 32 channels, Double-buffer, Read/Write */
+ (unsigned char *)pci_alloc_consistent(pdev, ZT_MAX_CHUNKSIZE * 32 * 2 * 2, &wc->writedma);
+ if (!wc->writechunk) {
+ printk("wct1xxp: Unable to allocate DMA-able memory\n");
+ return -ENOMEM;
+ }
+
+ /* Read is after the whole write piece (in bytes) */
+ wc->readchunk = wc->writechunk + ZT_CHUNKSIZE * 32 * 2;
+
+ /* Same thing... */
+ wc->readdma = wc->writedma + ZT_CHUNKSIZE * 32 * 2;
+
+ /* Initialize Write/Buffers to all blank data */
+ memset((void *)wc->writechunk,0x00,ZT_MAX_CHUNKSIZE * 2 * 2 * 32);
+ /* Initialize canary */
+ canary = (unsigned int *)(wc->readchunk + ZT_CHUNKSIZE * 64 - 4);
+ *canary = (CANARY << 16) | (0xffff);
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, wc);
+
+ if (request_irq(pdev->irq, t1xxp_interrupt, ZAP_IRQ_SHARED_DISABLED, "t1xxp", wc)) {
+ printk("t1xxp: Unable to request IRQ %d\n", pdev->irq);
+ kfree(wc);
+ return -EIO;
+ }
+ /* Initialize hardware */
+ t1xxp_hardware_init(wc);
+
+ /* We now know which version of card we have */
+ if (wc->ise1)
+ wc->variety = "Digium Wildcard E100P E1/PRA";
+ else
+ wc->variety = "Digium Wildcard T100P T1/PRI";
+
+ /* Misc. software stuff */
+ t1xxp_software_init(wc);
+
+ printk("Found a Wildcard: %s\n", wc->variety);
+ res = 0;
+ } else
+ res = -ENOMEM;
+ }
+ return res;
+}
+
+static void t1xxp_stop_stuff(struct t1xxp *wc)
+{
+ /* Kill clock */
+ control_set_reg(wc, WC_CLOCK, 0);
+
+ /* Turn off LED's */
+ control_set_reg(wc, WC_LEDTEST, 0);
+
+ /* Reset the T1 */
+ t1xxp_framer_hard_reset(wc);
+
+}
+
+static void __devexit t1xxp_remove_one(struct pci_dev *pdev)
+{
+ struct t1xxp *wc = pci_get_drvdata(pdev);
+ if (wc) {
+
+ /* Stop any DMA */
+ __t1xxp_stop_dma(wc);
+
+ /* In case hardware is still there */
+ __t1xxp_disable_interrupts(wc);
+
+ t1xxp_stop_stuff(wc);
+
+ /* Immediately free resources */
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 32 * 4, (void *)wc->writechunk, wc->writedma);
+ free_irq(pdev->irq, wc);
+
+ /* Reset PCI chip and registers */
+ outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL);
+
+ /* Release span, possibly delayed */
+ if (!wc->usecount)
+ t1xxp_release(wc);
+ else
+ wc->dead = 1;
+ }
+}
+
+static struct pci_device_id t1xxp_pci_tbl[] = {
+ { 0xe159, 0x0001, 0x6159, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard T100P T1/PRI or E100P E1/PRA Board" },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci,t1xxp_pci_tbl);
+
+static struct pci_driver t1xxp_driver = {
+ name: "t1xxp",
+ probe: t1xxp_init_one,
+#ifdef LINUX26
+ remove: __devexit_p(t1xxp_remove_one),
+#else
+ remove: t1xxp_remove_one,
+#endif
+ suspend: NULL,
+ resume: NULL,
+ id_table: t1xxp_pci_tbl,
+};
+
+static int __init t1xxp_init(void)
+{
+ int res;
+ res = zap_pci_module(&t1xxp_driver);
+ if (res)
+ return -ENODEV;
+ return 0;
+}
+
+static void __exit t1xxp_cleanup(void)
+{
+ pci_unregister_driver(&t1xxp_driver);
+}
+
+#ifdef LINUX26
+module_param(debug, int, 0600);
+#else
+MODULE_PARM(debug, "i");
+#endif
+MODULE_DESCRIPTION("Wildcard T100P/E100P Zaptel Driver");
+MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(t1xxp_init);
+module_exit(t1xxp_cleanup);
diff --git a/drivers/dahdi/wct4xxp/Kbuild b/drivers/dahdi/wct4xxp/Kbuild
new file mode 100644
index 0000000..96909f4
--- /dev/null
+++ b/drivers/dahdi/wct4xxp/Kbuild
@@ -0,0 +1,27 @@
+obj-m += wct4xxp.o
+
+FIRM_DIR := ../../firmware
+
+EXTRA_CFLAGS := -I$(src)/.. $(shell $(src)/../oct612x/octasic-helper cflags $(src)/../oct612x) -Wno-undef
+
+ifeq ($(HOTPLUG_FIRMWARE),yes)
+ EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
+endif
+
+wct4xxp-objs := base.o vpm450m.o $(shell $(src)/../oct612x/octasic-helper objects ../oct612x)
+
+ifneq ($(HOTPLUG_FIRMWARE),yes)
+wct4xxp-objs += $(FIRM_DIR)/zaptel-fw-oct6114-064.o $(FIRM_DIR)/zaptel-fw-oct6114-128.o
+endif
+
+$(obj)/$(FIRM_DIR)/zaptel-fw-oct6114-064.o: $(obj)/base.o
+ $(MAKE) -C $(obj)/$(FIRM_DIR) zaptel-fw-oct6114-064.o
+
+$(obj)/$(FIRM_DIR)/zaptel-fw-oct6114-128.o: $(obj)/base.o
+ $(MAKE) -C $(obj)/$(FIRM_DIR) zaptel-fw-oct6114-128.o
+
+$(obj)/base.o: $(src)/vpm450m.h $(src)/wct4xxp.h
+$(obj)/base.o: $(src)/../zaptel.h
+
+$(obj)/vpm450m.o: $(src)/vpm450m.h
+$(obj)/vpm450m.o: $(src)/../oct612x/include/oct6100api/oct6100_api.h
diff --git a/drivers/dahdi/wct4xxp/Makefile b/drivers/dahdi/wct4xxp/Makefile
new file mode 100644
index 0000000..4f0961e
--- /dev/null
+++ b/drivers/dahdi/wct4xxp/Makefile
@@ -0,0 +1,36 @@
+ifneq ($(KBUILD_EXTMOD),)
+# We only get here on kernels 2.6.0-2.6.9 .
+# For newer kernels, Kbuild will be included directly by the kernel
+# build system.
+include $(src)/Kbuild
+
+else
+
+FIRM_DIR := ../../firmware
+
+OCTASIC_OBJS:=$(shell ../oct612x/octasic-helper objects ../oct612x)
+OCTASIC_CFLAGS:=$(shell ../oct612x/octasic-helper cflags ../oct612x) -Wno-undef
+
+all: wct4xxp.o
+
+%.o: %.c
+ $(CC) $(KFLAGS) $(OCTASIC_CFLAGS) -o $@ -c $<
+
+base.o: ../zaptel.h vpm450m.h wct4xxp.h
+
+vpm450m.o: vpm450m.h ../oct612x/include/oct6100api/oct6100_api.h
+
+$(FIRM_DIR)/zaptel-fw-oct6114-064.o: base.o
+ $(MAKE) -C $(FIRM_DIR) zaptel-fw-oct6114-064.o
+
+$(FIRM_DIR)/zaptel-fw-oct6114-128.o: base.o
+ $(MAKE) -C $(FIRM_DIR) zaptel-fw-oct6114-128.o
+
+wct4xxp.o: base.o vpm450m.o $(OCTASIC_OBJS) $(FIRM_DIR)/zaptel-fw-oct6114-064.o $(FIRM_DIR)/zaptel-fw-oct6114-128.o
+ $(LD) -r -o $@ $^
+
+clean:
+ rm -f *.o
+ rm -f $(OCTASIC_OBJS)
+
+endif
diff --git a/drivers/dahdi/wct4xxp/base.c b/drivers/dahdi/wct4xxp/base.c
new file mode 100644
index 0000000..28a8ecc
--- /dev/null
+++ b/drivers/dahdi/wct4xxp/base.c
@@ -0,0 +1,3892 @@
+/*
+ * TE410P Quad-T1/E1 PCI Driver version 0.1, 12/16/02
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Based on previous works, designs, and archetectures conceived and
+ * written by Jim Dixon <jim@lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2005, 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/pci.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include "zaptel.h"
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+#include "wct4xxp.h"
+#include "vpm450m.h"
+
+/* Work queues are a way to better distribute load on SMP systems */
+#if defined(LINUX26) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
+/*
+ * Work queues can significantly improve performance and scalability
+ * on multi-processor machines, but requires bypassing some kernel
+ * API's, so it's not guaranteed to be compatible with all kernels.
+ */
+/* #define ENABLE_WORKQUEUES */
+#endif
+
+/* Enable prefetching may help performance */
+#define ENABLE_PREFETCH
+
+/* Support first generation cards? */
+#define SUPPORT_GEN1
+
+/* Define to get more attention-grabbing but slightly more I/O using
+ alarm status */
+#define FANCY_ALARM
+
+/* Define to support Digium Voice Processing Module expansion card */
+#define VPM_SUPPORT
+
+#define DEBUG_MAIN (1 << 0)
+#define DEBUG_DTMF (1 << 1)
+#define DEBUG_REGS (1 << 2)
+#define DEBUG_TSI (1 << 3)
+#define DEBUG_ECHOCAN (1 << 4)
+#define DEBUG_RBS (1 << 5)
+#define DEBUG_FRAMER (1 << 6)
+
+#ifdef ENABLE_WORKQUEUES
+#include <linux/cpu.h>
+
+/* XXX UGLY!!!! XXX We have to access the direct structures of the workqueue which
+ are only defined within workqueue.c because they don't give us a routine to allow us
+ to nail a work to a particular thread of the CPU. Nailing to threads gives us substantially
+ higher scalability in multi-CPU environments though! */
+
+/*
+ * The per-CPU workqueue (if single thread, we always use cpu 0's).
+ *
+ * The sequence counters are for flush_scheduled_work(). It wants to wait
+ * until until all currently-scheduled works are completed, but it doesn't
+ * want to be livelocked by new, incoming ones. So it waits until
+ * remove_sequence is >= the insert_sequence which pertained when
+ * flush_scheduled_work() was called.
+ */
+
+struct cpu_workqueue_struct {
+
+ spinlock_t lock;
+
+ long remove_sequence; /* Least-recently added (next to run) */
+ long insert_sequence; /* Next to add */
+
+ struct list_head worklist;
+ wait_queue_head_t more_work;
+ wait_queue_head_t work_done;
+
+ struct workqueue_struct *wq;
+ task_t *thread;
+
+ int run_depth; /* Detect run_workqueue() recursion depth */
+} ____cacheline_aligned;
+
+/*
+ * The externally visible workqueue abstraction is an array of
+ * per-CPU workqueues:
+ */
+struct workqueue_struct {
+ /* TODO: Find out exactly where the API changed */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
+ struct cpu_workqueue_struct *cpu_wq;
+#else
+ struct cpu_workqueue_struct cpu_wq[NR_CPUS];
+#endif
+ const char *name;
+ struct list_head list; /* Empty if single thread */
+};
+
+/* Preempt must be disabled. */
+static void __t4_queue_work(struct cpu_workqueue_struct *cwq,
+ struct work_struct *work)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cwq->lock, flags);
+ work->wq_data = cwq;
+ list_add_tail(&work->entry, &cwq->worklist);
+ cwq->insert_sequence++;
+ wake_up(&cwq->more_work);
+ spin_unlock_irqrestore(&cwq->lock, flags);
+}
+
+/*
+ * Queue work on a workqueue. Return non-zero if it was successfully
+ * added.
+ *
+ * We queue the work to the CPU it was submitted, but there is no
+ * guarantee that it will be processed by that CPU.
+ */
+static inline int t4_queue_work(struct workqueue_struct *wq, struct work_struct *work, int cpu)
+{
+ int ret = 0;
+ get_cpu();
+ if (!test_and_set_bit(0, &work->pending)) {
+ BUG_ON(!list_empty(&work->entry));
+ __t4_queue_work(wq->cpu_wq + cpu, work);
+ ret = 1;
+ }
+ put_cpu();
+ return ret;
+}
+
+#endif
+
+static int pedanticpci = 1;
+static int debug=0;
+static int timingcable = 0;
+static int highestorder;
+static int t1e1override = -1; //0xFF; // -1 = jumper; 0xFF = E1
+static int j1mode = 0;
+static int sigmode = FRMR_MODE_NO_ADDR_CMP;
+static int loopback = 0;
+static int alarmdebounce = 0;
+#ifdef VPM_SUPPORT
+static int vpmsupport = 1;
+/* If set to auto, vpmdtmfsupport is enabled for VPM400M and disabled for VPM450M */
+static int vpmdtmfsupport = -1; /* -1=auto, 0=disabled, 1=enabled*/
+static int vpmspans = 4;
+#define VPM_DEFAULT_DTMFTHRESHOLD 1000
+static int dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
+static int lastdtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
+#endif
+/* Enabling bursting can more efficiently utilize PCI bus bandwidth, but
+ can also cause PCI bus starvation, especially in combination with other
+ aggressive cards. Please note that burst mode has no effect on CPU
+ utilization / max number of calls / etc. */
+static int noburst = 1;
+/* For 56kbps links, set this module parameter to 0x7f */
+static int hardhdlcmode = 0xff;
+
+#ifdef FANCY_ALARM
+static int altab[] = {
+0, 0, 0, 1, 2, 3, 4, 6, 8, 9, 11, 13, 16, 18, 20, 22, 24, 25, 27, 28, 29, 30, 31, 31, 32, 31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0,
+};
+#endif
+
+#define MAX_SPANS 16
+
+#define FLAG_STARTED (1 << 0)
+#define FLAG_NMF (1 << 1)
+#define FLAG_SENDINGYELLOW (1 << 2)
+
+
+#define TYPE_T1 1 /* is a T1 card */
+#define TYPE_E1 2 /* is an E1 card */
+#define TYPE_J1 3 /* is a running J1 */
+
+#define FLAG_2NDGEN (1 << 3)
+#define FLAG_2PORT (1 << 4)
+#define FLAG_VPM2GEN (1 << 5)
+#define FLAG_OCTOPT (1 << 6)
+#define FLAG_3RDGEN (1 << 7)
+#define FLAG_BURST (1 << 8)
+#define FLAG_EXPRESS (1 << 9)
+
+#define CANARY 0xc0de
+
+struct devtype {
+ char *desc;
+ unsigned int flags;
+};
+
+static struct devtype wct4xxp = { "Wildcard TE410P/TE405P (1st Gen)", 0 };
+static struct devtype wct420p4 = { "Wildcard TE420 (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_EXPRESS };
+static struct devtype wct410p4 = { "Wildcard TE410P (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN };
+static struct devtype wct410p3 = { "Wildcard TE410P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN };
+static struct devtype wct405p4 = { "Wildcard TE405P (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN };
+static struct devtype wct405p3 = { "Wildcard TE405P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN };
+static struct devtype wct410p2 = { "Wildcard TE410P (2nd Gen)", FLAG_2NDGEN };
+static struct devtype wct405p2 = { "Wildcard TE405P (2nd Gen)", FLAG_2NDGEN };
+static struct devtype wct220p4 = { "Wildcard TE220 (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT | FLAG_EXPRESS };
+static struct devtype wct205p4 = { "Wildcard TE205P (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT };
+static struct devtype wct205p3 = { "Wildcard TE205P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT };
+static struct devtype wct210p4 = { "Wildcard TE210P (4th Gen)", FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT };
+static struct devtype wct210p3 = { "Wildcard TE210P (3rd Gen)", FLAG_2NDGEN | FLAG_3RDGEN | FLAG_2PORT };
+static struct devtype wct205 = { "Wildcard TE205P ", FLAG_2NDGEN | FLAG_2PORT };
+static struct devtype wct210 = { "Wildcard TE210P ", FLAG_2NDGEN | FLAG_2PORT };
+
+
+struct t4;
+
+struct t4_span {
+ struct t4 *owner;
+ unsigned int *writechunk; /* Double-word aligned write memory */
+ unsigned int *readchunk; /* Double-word aligned read memory */
+ int spantype; /* card type, T1 or E1 or J1 */
+ int sync;
+ int psync;
+ int alarmtimer;
+ int redalarms;
+ int notclear;
+ int alarmcount;
+ int spanflags;
+ int syncpos;
+#ifdef SUPPORT_GEN1
+ int e1check; /* E1 check */
+#endif
+ struct zt_span span;
+ unsigned char txsigs[16]; /* Transmit sigs */
+ int loopupcnt;
+ int loopdowncnt;
+#ifdef SUPPORT_GEN1
+ unsigned char ec_chunk1[31][ZT_CHUNKSIZE]; /* first EC chunk buffer */
+ unsigned char ec_chunk2[31][ZT_CHUNKSIZE]; /* second EC chunk buffer */
+#endif
+ int irqmisses;
+
+ /* HDLC controller fields */
+ struct zt_chan *sigchan;
+ unsigned char sigmode;
+ int sigactive;
+ int frames_out;
+ int frames_in;
+
+#ifdef VPM_SUPPORT
+ unsigned long dtmfactive;
+ unsigned long dtmfmask;
+ unsigned long dtmfmutemask;
+ short dtmfenergy[31];
+ short dtmfdigit[31];
+#endif
+#ifdef ENABLE_WORKQUEUES
+ struct work_struct swork;
+#endif
+ struct zt_chan chans[0]; /* Individual channels */
+};
+
+struct t4 {
+ /* This structure exists one per card */
+ struct pci_dev *dev; /* Pointer to PCI device */
+ unsigned int intcount;
+ int num; /* Which card we are */
+ int t1e1; /* T1/E1 select pins */
+ int globalconfig; /* Whether global setup has been done */
+ int syncsrc; /* active sync source */
+ struct t4_span *tspans[4]; /* Individual spans */
+ int numspans; /* Number of spans on the card */
+ int blinktimer;
+#ifdef FANCY_ALARM
+ int alarmpos;
+#endif
+ int irq; /* IRQ used by device */
+ int order; /* Order */
+ int flags; /* Device flags */
+ int master; /* Are we master */
+ int ledreg; /* LED Register */
+ unsigned int gpio;
+ unsigned int gpioctl;
+ int e1recover; /* E1 recovery timer */
+ spinlock_t reglock; /* lock register access */
+ int spansstarted; /* number of spans started */
+ volatile unsigned int *writechunk; /* Double-word aligned write memory */
+ volatile unsigned int *readchunk; /* Double-word aligned read memory */
+ unsigned short canary;
+#ifdef ENABLE_WORKQUEUES
+ atomic_t worklist;
+ struct workqueue_struct *workq;
+#endif
+ unsigned int passno; /* number of interrupt passes */
+ char *variety;
+ int last0; /* for detecting double-missed IRQ */
+
+ /* DMA related fields */
+ unsigned int dmactrl;
+ dma_addr_t readdma;
+ dma_addr_t writedma;
+ unsigned long memaddr; /* Base address of card */
+ unsigned long memlen;
+ volatile unsigned int *membase; /* Base address of card */
+
+ /* Add this for our softlockup protector */
+ unsigned int oct_rw_count;
+
+ /* Flags for our bottom half */
+ unsigned long checkflag;
+ struct tasklet_struct t4_tlet;
+ unsigned int vpm400checkstatus;
+
+#ifdef VPM_SUPPORT
+ struct vpm450m *vpm450m;
+ int vpm;
+#endif
+
+};
+
+#define T4_VPM_PRESENT (1 << 28)
+
+
+#ifdef VPM_SUPPORT
+static void t4_vpm400_init(struct t4 *wc);
+static void t4_vpm450_init(struct t4 *wc);
+static void t4_vpm_set_dtmf_threshold(struct t4 *wc, unsigned int threshold);
+#endif
+static void __set_clear(struct t4 *wc, int span);
+static int t4_startup(struct zt_span *span);
+static int t4_shutdown(struct zt_span *span);
+static int t4_rbsbits(struct zt_chan *chan, int bits);
+static int t4_maint(struct zt_span *span, int cmd);
+#ifdef SUPPORT_GEN1
+static int t4_reset_dma(struct t4 *wc);
+#endif
+static void t4_hdlc_hard_xmit(struct zt_chan *chan);
+static int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data);
+static void t4_tsi_assign(struct t4 *wc, int fromspan, int fromchan, int tospan, int tochan);
+static void t4_tsi_unassign(struct t4 *wc, int tospan, int tochan);
+static void __t4_set_timing_source(struct t4 *wc, int unit, int master, int slave);
+static void t4_check_alarms(struct t4 *wc, int span);
+static void t4_check_sigbits(struct t4 *wc, int span);
+
+#define WC_RDADDR 0
+#define WC_WRADDR 1
+#define WC_COUNT 2
+#define WC_DMACTRL 3
+#define WC_INTR 4
+/* #define WC_GPIO 5 */
+#define WC_VERSION 6
+#define WC_LEDS 7
+#define WC_GPIOCTL 8
+#define WC_GPIO 9
+#define WC_LADDR 10
+#define WC_LDATA 11
+#define WC_LCS (1 << 11)
+#define WC_LCS2 (1 << 12)
+#define WC_LALE (1 << 13)
+#define WC_LFRMR_CS (1 << 10) /* Framer's ChipSelect signal */
+#define WC_ACTIVATE (1 << 12)
+#define WC_LREAD (1 << 15)
+#define WC_LWRITE (1 << 16)
+
+#define WC_OFF (0)
+#define WC_RED (1)
+#define WC_GREEN (2)
+#define WC_YELLOW (3)
+
+#define MAX_T4_CARDS 64
+
+static void t4_isr_bh(unsigned long data);
+
+static struct t4 *cards[MAX_T4_CARDS];
+
+
+#define MAX_TDM_CHAN 32
+#define MAX_DTMF_DET 16
+
+#define HDLC_IMR0_MASK (FRMR_IMR0_RME | FRMR_IMR0_RPF)
+#if 0
+#define HDLC_IMR1_MASK (FRMR_IMR1_ALLS | FRMR_IMR1_XDU | FRMR_IMR1_XPR)
+#else
+#define HDLC_IMR1_MASK (FRMR_IMR1_XDU | FRMR_IMR1_XPR)
+#endif
+
+static inline unsigned int __t4_pci_in(struct t4 *wc, const unsigned int addr)
+{
+ unsigned int res = readl(&wc->membase[addr]);
+ if (pedanticpci) {
+ /* Even though we do not support fast back-to-back
+ * transactions, some host bridges appear to generate them.
+ * This delay prevents this.
+ */
+ if (!test_bit(T4_LOADING_FW, &wc->checkflag))
+ udelay(3);
+ }
+ return res;
+}
+
+static inline void __t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
+{
+ unsigned int tmp;
+ writel(value, &wc->membase[addr]);
+ if (pedanticpci) {
+ /* Even though we do not support fast back-to-back
+ * transactions, some host bridges appear to generate them.
+ * This delay prevents this.
+ */
+ if (!test_bit(T4_LOADING_FW, &wc->checkflag))
+ udelay(3);
+ tmp = __t4_pci_in(wc, WC_VERSION);
+ if ((tmp & 0xffff0000) != 0xc01a0000)
+ printk("TE4XXP: Version Synchronization Error!\n");
+ }
+#if 0
+ tmp = __t4_pci_in(wc, addr);
+ if ((value != tmp) && (addr != WC_LEDS) && (addr != WC_LDATA) &&
+ (addr != WC_GPIO) && (addr != WC_INTR))
+ printk("Tried to load %08x into %08x, but got %08x instead\n", value, addr, tmp);
+#endif
+}
+
+static inline void __t4_gpio_set(struct t4 *wc, unsigned bits, unsigned int val)
+{
+ unsigned int newgpio;
+ newgpio = wc->gpio & (~bits);
+ newgpio |= val;
+ if (newgpio != wc->gpio) {
+ wc->gpio = newgpio;
+ __t4_pci_out(wc, WC_GPIO, wc->gpio);
+ }
+}
+
+static inline void __t4_gpio_setdir(struct t4 *wc, unsigned int bits, unsigned int val)
+{
+ unsigned int newgpioctl;
+ newgpioctl = wc->gpioctl & (~bits);
+ newgpioctl |= val;
+ if (newgpioctl != wc->gpioctl) {
+ wc->gpioctl = newgpioctl;
+ __t4_pci_out(wc, WC_GPIOCTL, wc->gpioctl);
+ }
+}
+
+static inline void t4_gpio_setdir(struct t4 *wc, unsigned int bits, unsigned int val)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t4_gpio_setdir(wc, bits, val);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline void t4_gpio_set(struct t4 *wc, unsigned int bits, unsigned int val)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t4_gpio_set(wc, bits, val);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline void t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t4_pci_out(wc, addr, value);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline void __t4_set_led(struct t4 *wc, int span, int color)
+{
+ int oldreg = wc->ledreg;
+ wc->ledreg &= ~(0x3 << (span << 1));
+ wc->ledreg |= (color << (span << 1));
+ if (oldreg != wc->ledreg)
+ __t4_pci_out(wc, WC_LEDS, wc->ledreg);
+}
+
+static inline void t4_activate(struct t4 *wc)
+{
+ wc->ledreg |= WC_ACTIVATE;
+ t4_pci_out(wc, WC_LEDS, wc->ledreg);
+}
+
+static inline unsigned int t4_pci_in(struct t4 *wc, const unsigned int addr)
+{
+ unsigned int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ ret = __t4_pci_in(wc, addr);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return ret;
+}
+
+static inline unsigned int __t4_framer_in(struct t4 *wc, int unit, const unsigned int addr)
+{
+ unsigned int ret;
+ unit &= 0x3;
+ __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
+ __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | WC_LFRMR_CS | WC_LREAD);
+ if (pedanticpci) {
+ __t4_pci_out(wc, WC_VERSION, 0);
+ }
+ ret = __t4_pci_in(wc, WC_LDATA);
+ __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
+ return ret & 0xff;
+}
+
+static inline unsigned int t4_framer_in(struct t4 *wc, int unit, const unsigned int addr)
+{
+ unsigned long flags;
+ unsigned int ret;
+ spin_lock_irqsave(&wc->reglock, flags);
+ ret = __t4_framer_in(wc, unit, addr);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return ret;
+
+}
+
+static inline void __t4_framer_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value)
+{
+ unit &= 0x3;
+ if (unlikely(debug & DEBUG_REGS))
+ printk("Writing %02x to address %02x of unit %d\n", value, addr, unit);
+ __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
+ __t4_pci_out(wc, WC_LDATA, value);
+ __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | WC_LFRMR_CS | WC_LWRITE);
+ __t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
+ if (unlikely(debug & DEBUG_REGS)) printk("Write complete\n");
+#if 0
+ if ((addr != FRMR_TXFIFO) && (addr != FRMR_CMDR) && (addr != 0xbc))
+ { unsigned int tmp;
+ tmp = __t4_framer_in(wc, unit, addr);
+ if (tmp != value) {
+ printk("Expected %d from unit %d register %d but got %d instead\n", value, unit, addr, tmp);
+ } }
+#endif
+}
+
+static inline void t4_framer_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t4_framer_out(wc, unit, addr, value);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+#ifdef VPM_SUPPORT
+
+static inline void wait_a_little(void)
+{
+ unsigned long newjiffies=jiffies+2;
+ while(jiffies < newjiffies);
+}
+
+static inline unsigned int __t4_vpm_in(struct t4 *wc, int unit, const unsigned int addr)
+{
+ unsigned int ret;
+ unit &= 0x7;
+ __t4_pci_out(wc, WC_LADDR, (addr & 0x1ff) | ( unit << 12));
+ __t4_pci_out(wc, WC_LADDR, (addr & 0x1ff) | ( unit << 12) | (1 << 11) | WC_LREAD);
+ ret = __t4_pci_in(wc, WC_LDATA);
+ __t4_pci_out(wc, WC_LADDR, 0);
+ return ret & 0xff;
+}
+
+static inline void __t4_raw_oct_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
+{
+ int octopt = wc->tspans[0]->spanflags & FLAG_OCTOPT;
+ if (!octopt)
+ __t4_gpio_set(wc, 0xff, (addr >> 8));
+ __t4_pci_out(wc, WC_LDATA, 0x10000 | (addr & 0xffff));
+ if (!octopt)
+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE));
+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE));
+ if (!octopt)
+ __t4_gpio_set(wc, 0xff, (value >> 8));
+ __t4_pci_out(wc, WC_LDATA, (value & 0xffff));
+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE | WC_LCS));
+ __t4_pci_out(wc, WC_LADDR, (0));
+}
+
+static inline unsigned int __t4_raw_oct_in(struct t4 *wc, const unsigned int addr)
+{
+ unsigned int ret;
+ int octopt = wc->tspans[0]->spanflags & FLAG_OCTOPT;
+ if (!octopt)
+ __t4_gpio_set(wc, 0xff, (addr >> 8));
+ __t4_pci_out(wc, WC_LDATA, 0x10000 | (addr & 0xffff));
+ if (!octopt)
+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE));
+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE));
+#ifdef PEDANTIC_OCTASIC_CHECKING
+ __t4_pci_out(wc, WC_LADDR, (WC_LALE));
+#endif
+ if (!octopt) {
+ __t4_gpio_setdir(wc, 0xff, 0x00);
+ __t4_gpio_set(wc, 0xff, 0x00);
+ }
+ __t4_pci_out(wc, WC_LADDR, (WC_LREAD | WC_LALE | WC_LCS));
+ if (octopt) {
+ ret = __t4_pci_in(wc, WC_LDATA) & 0xffff;
+ } else {
+ ret = __t4_pci_in(wc, WC_LDATA) & 0xff;
+ ret |= (__t4_pci_in(wc, WC_GPIO) & 0xff) << 8;
+ }
+ __t4_pci_out(wc, WC_LADDR, (0));
+ if (!octopt)
+ __t4_gpio_setdir(wc, 0xff, 0xff);
+ return ret & 0xffff;
+}
+
+static inline unsigned int __t4_oct_in(struct t4 *wc, unsigned int addr)
+{
+#ifdef PEDANTIC_OCTASIC_CHECKING
+ int count = 1000;
+#endif
+ __t4_raw_oct_out(wc, 0x0008, (addr >> 20));
+ __t4_raw_oct_out(wc, 0x000a, (addr >> 4) & ((1 << 16) - 1));
+ __t4_raw_oct_out(wc, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (1));
+#ifdef PEDANTIC_OCTASIC_CHECKING
+ while((__t4_raw_oct_in(wc, 0x0000) & (1 << 8)) && --count);
+ if (count != 1000)
+ printk("Yah, read can be slow...\n");
+ if (!count)
+ printk("Read timed out!\n");
+#endif
+ return __t4_raw_oct_in(wc, 0x0004);
+}
+
+static inline unsigned int t4_oct_in(struct t4 *wc, const unsigned int addr)
+{
+ unsigned long flags;
+ unsigned int ret;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ ret = __t4_oct_in(wc, addr);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return ret;
+}
+
+static inline unsigned int t4_vpm_in(struct t4 *wc, int unit, const unsigned int addr)
+{
+ unsigned long flags;
+ unsigned int ret;
+ spin_lock_irqsave(&wc->reglock, flags);
+ ret = __t4_vpm_in(wc, unit, addr);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return ret;
+}
+
+static inline void __t4_vpm_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value)
+{
+ unit &= 0x7;
+ if (debug & DEBUG_REGS)
+ printk("Writing %02x to address %02x of ec unit %d\n", value, addr, unit);
+ __t4_pci_out(wc, WC_LADDR, (addr & 0xff));
+ __t4_pci_out(wc, WC_LDATA, value);
+ __t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff) | (1 << 11));
+ __t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff) | (1 << 11) | WC_LWRITE);
+ __t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff) | (1 << 11));
+ __t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff));
+ __t4_pci_out(wc, WC_LADDR, 0);
+ if (debug & DEBUG_REGS) printk("Write complete\n");
+
+
+#if 0
+ { unsigned int tmp;
+ tmp = t4_vpm_in(wc, unit, addr);
+ if (tmp != value) {
+ printk("Expected %d from unit %d echo register %d but got %d instead\n", value, unit, addr, tmp);
+ } }
+#endif
+}
+
+static inline void __t4_oct_out(struct t4 *wc, unsigned int addr, unsigned int value)
+{
+#ifdef PEDANTIC_OCTASIC_CHECKING
+ int count = 1000;
+#endif
+ __t4_raw_oct_out(wc, 0x0008, (addr >> 20));
+ __t4_raw_oct_out(wc, 0x000a, (addr >> 4) & ((1 << 16) - 1));
+ __t4_raw_oct_out(wc, 0x0004, value);
+ __t4_raw_oct_out(wc, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (3 << 12) | 1);
+#ifdef PEDANTIC_OCTASIC_CHECKING
+ while((__t4_raw_oct_in(wc, 0x0000) & (1 << 8)) && --count);
+ if (count != 1000)
+ printk("Yah, write can be slow\n");
+ if (!count)
+ printk("Write timed out!\n");
+#endif
+}
+
+static inline void t4_oct_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t4_oct_out(wc, addr, value);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline void t4_vpm_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t4_vpm_out(wc, unit, addr, value);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static const char vpm_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', '*', '#'};
+
+static void t4_check_vpm450(struct t4 *wc)
+{
+ int channel, tone, start, span;
+
+ if (vpm450m_checkirq(wc->vpm450m)) {
+ while(vpm450m_getdtmf(wc->vpm450m, &channel, &tone, &start)) {
+ span = channel & 0x3;
+ channel >>= 2;
+ if (!wc->t1e1)
+ channel -= 5;
+ else
+ channel -= 1;
+ if (unlikely(debug))
+ printk("Got tone %s of '%c' on channel %d of span %d\n",
+ (start ? "START" : "STOP"), tone, channel, span + 1);
+ if (test_bit(channel, &wc->tspans[span]->dtmfmask) && (tone != 'u')) {
+ if (start) {
+ /* The octasic is supposed to mute us, but... Yah, you
+ guessed it. */
+ if (test_bit(channel, &wc->tspans[span]->dtmfmutemask)) {
+ unsigned long flags;
+ struct zt_chan *chan = &wc->tspans[span]->span.chans[channel];
+ int y;
+ spin_lock_irqsave(&chan->lock, flags);
+ for (y=0;y<chan->numbufs;y++) {
+ if ((chan->inreadbuf > -1) && (chan->readidx[y]))
+ memset(chan->readbuf[chan->inreadbuf], ZT_XLAW(0, chan), chan->readidx[y]);
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ }
+ set_bit(channel, &wc->tspans[span]->dtmfactive);
+ zt_qevent_lock(&wc->tspans[span]->span.chans[channel], (ZT_EVENT_DTMFDOWN | tone));
+ } else {
+ clear_bit(channel, &wc->tspans[span]->dtmfactive);
+ zt_qevent_lock(&wc->tspans[span]->span.chans[channel], (ZT_EVENT_DTMFUP | tone));
+ }
+ }
+ }
+ }
+}
+
+static void t4_check_vpm400(struct t4 *wc, unsigned int newio)
+{
+ unsigned int digit, regval = 0;
+ unsigned int regbyte;
+ int x, i;
+ short energy=0;
+ static unsigned int lastio = 0;
+ struct t4_span *ts;
+
+ if (debug && (newio != lastio))
+ printk("Last was %08x, new is %08x\n", lastio, newio);
+
+ lastio = newio;
+
+ for(x = 0; x < 8; x++) {
+ if (newio & (1 << (7 - x)))
+ continue;
+ ts = wc->tspans[x%4];
+ /* Start of DTMF detection process */
+ regbyte = t4_vpm_in(wc, x, 0xb8);
+ t4_vpm_out(wc, x, 0xb8, regbyte); /* Write 1 to clear */
+ regval = regbyte << 8;
+ regbyte = t4_vpm_in(wc, x, 0xb9);
+ t4_vpm_out(wc, x, 0xb9, regbyte);
+ regval |= regbyte;
+
+ for(i = 0; (i < MAX_DTMF_DET) && regval; i++) {
+ if(regval & 0x0001) {
+ int channel = (i << 1) + (x >> 2);
+ int base = channel - 1;
+
+ if (!wc->t1e1)
+ base -= 4;
+ regbyte = t4_vpm_in(wc, x, 0xa8 + i);
+ digit = vpm_digits[regbyte];
+ if (!(wc->tspans[0]->spanflags & FLAG_VPM2GEN)) {
+ energy = t4_vpm_in(wc, x, 0x58 + channel);
+ energy = ZT_XLAW(energy, ts->chans);
+ ts->dtmfenergy[base] = energy;
+ }
+ set_bit(base, &ts->dtmfactive);
+ if (ts->dtmfdigit[base]) {
+ if (ts->dtmfmask & (1 << base))
+ zt_qevent_lock(&ts->span.chans[base], (ZT_EVENT_DTMFUP | ts->dtmfdigit[base]));
+ }
+ ts->dtmfdigit[base] = digit;
+ if (test_bit(base, &ts->dtmfmask))
+ zt_qevent_lock(&ts->span.chans[base], (ZT_EVENT_DTMFDOWN | digit));
+ if (test_bit(base, &ts->dtmfmutemask)) {
+ /* Mute active receive buffer*/
+ unsigned long flags;
+ struct zt_chan *chan = &ts->span.chans[base];
+ int y;
+ spin_lock_irqsave(&chan->lock, flags);
+ for (y=0;y<chan->numbufs;y++) {
+ if ((chan->inreadbuf > -1) && (chan->readidx[y]))
+ memset(chan->readbuf[chan->inreadbuf], ZT_XLAW(0, chan), chan->readidx[y]);
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ }
+ if (debug)
+ printk("Digit Seen: %d, Span: %d, channel: %d, energy: %02x, 'channel %d' chip %d\n", digit, x % 4, base + 1, energy, channel, x);
+
+ }
+ regval = regval >> 1;
+ }
+ if (!(wc->tspans[0]->spanflags & FLAG_VPM2GEN))
+ continue;
+
+ /* Start of DTMF off detection process */
+ regbyte = t4_vpm_in(wc, x, 0xbc);
+ t4_vpm_out(wc, x, 0xbc, regbyte); /* Write 1 to clear */
+ regval = regbyte << 8;
+ regbyte = t4_vpm_in(wc, x, 0xbd);
+ t4_vpm_out(wc, x, 0xbd, regbyte);
+ regval |= regbyte;
+
+ for(i = 0; (i < MAX_DTMF_DET) && regval; i++) {
+ if(regval & 0x0001) {
+ int channel = (i << 1) + (x >> 2);
+ int base = channel - 1;
+
+ if (!wc->t1e1)
+ base -= 4;
+ clear_bit(base, &ts->dtmfactive);
+ if (ts->dtmfdigit[base]) {
+ if (test_bit(base, &ts->dtmfmask))
+ zt_qevent_lock(&ts->span.chans[base], (ZT_EVENT_DTMFUP | ts->dtmfdigit[base]));
+ }
+ digit = ts->dtmfdigit[base];
+ ts->dtmfdigit[base] = 0;
+ if (debug)
+ printk("Digit Gone: %d, Span: %d, channel: %d, energy: %02x, 'channel %d' chip %d\n", digit, x % 4, base + 1, energy, channel, x);
+
+ }
+ regval = regval >> 1;
+ }
+
+ }
+}
+#endif
+
+static void hdlc_stop(struct t4 *wc, unsigned int span)
+{
+ struct t4_span *t = wc->tspans[span];
+ unsigned char imr0, imr1, mode;
+ int i = 0;
+
+ if (debug & DEBUG_FRAMER) printk("Stopping HDLC controller on span %d\n", span+1);
+
+ /* Clear receive and transmit timeslots */
+ for (i = 0; i < 4; i++) {
+ t4_framer_out(wc, span, FRMR_RTR_BASE + i, 0x00);
+ t4_framer_out(wc, span, FRMR_TTR_BASE + i, 0x00);
+ }
+
+ imr0 = t4_framer_in(wc, span, FRMR_IMR0);
+ imr1 = t4_framer_in(wc, span, FRMR_IMR1);
+
+ /* Disable HDLC interrupts */
+ imr0 |= HDLC_IMR0_MASK;
+ t4_framer_out(wc, span, FRMR_IMR0, imr0);
+
+ imr1 |= HDLC_IMR1_MASK;
+ t4_framer_out(wc, span, FRMR_IMR1, imr1);
+
+ mode = t4_framer_in(wc, span, FRMR_MODE);
+ mode &= ~FRMR_MODE_HRAC;
+ t4_framer_out(wc, span, FRMR_MODE, mode);
+
+ t->sigactive = 0;
+}
+
+static inline void __t4_framer_cmd(struct t4 *wc, unsigned int span, int cmd)
+{
+ __t4_framer_out(wc, span, FRMR_CMDR, cmd);
+}
+
+static inline void t4_framer_cmd_wait(struct t4 *wc, unsigned int span, int cmd)
+{
+ int sis;
+ int loops = 0;
+
+ /* XXX could be time consuming XXX */
+ for (;;) {
+ sis = t4_framer_in(wc, span, FRMR_SIS);
+ if (!(sis & 0x04))
+ break;
+ if (!loops++ && (debug & DEBUG_FRAMER)) {
+ printk("!!!SIS Waiting before cmd %02x\n", cmd);
+ }
+ }
+ if (loops && (debug & DEBUG_FRAMER))
+ printk("!!!SIS waited %d loops\n", loops);
+
+ t4_framer_out(wc, span, FRMR_CMDR, cmd);
+}
+
+static int hdlc_start(struct t4 *wc, unsigned int span, struct zt_chan *chan, unsigned char mode)
+{
+ struct t4_span *t = wc->tspans[span];
+ unsigned char imr0, imr1;
+ int offset = chan->chanpos;
+ unsigned long flags;
+
+ if (debug & DEBUG_FRAMER) printk("Starting HDLC controller for channel %d span %d\n", offset, span+1);
+
+ if (mode != FRMR_MODE_NO_ADDR_CMP)
+ return -1;
+
+ mode |= FRMR_MODE_HRAC;
+
+ /* Make sure we're in the right mode */
+ t4_framer_out(wc, span, FRMR_MODE, mode);
+ t4_framer_out(wc, span, FRMR_TSEO, 0x00);
+ t4_framer_out(wc, span, FRMR_TSBS1, hardhdlcmode);
+
+ /* Set the interframe gaps, etc */
+ t4_framer_out(wc, span, FRMR_CCR1, FRMR_CCR1_ITF|FRMR_CCR1_EITS);
+
+ t4_framer_out(wc, span, FRMR_CCR2, FRMR_CCR2_RCRC);
+
+ /* Set up the time slot that we want to tx/rx on */
+ t4_framer_out(wc, span, FRMR_TTR_BASE + (offset / 8), (0x80 >> (offset % 8)));
+ t4_framer_out(wc, span, FRMR_RTR_BASE + (offset / 8), (0x80 >> (offset % 8)));
+
+ imr0 = t4_framer_in(wc, span, FRMR_IMR0);
+ imr1 = t4_framer_in(wc, span, FRMR_IMR1);
+
+ /* Enable our interrupts again */
+ imr0 &= ~HDLC_IMR0_MASK;
+ t4_framer_out(wc, span, FRMR_IMR0, imr0);
+
+ imr1 &= ~HDLC_IMR1_MASK;
+ t4_framer_out(wc, span, FRMR_IMR1, imr1);
+
+ /* Reset the signaling controller */
+ t4_framer_cmd_wait(wc, span, FRMR_CMDR_SRES);
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ t->sigchan = chan;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ t->sigactive = 0;
+
+ return 0;
+}
+
+static void __set_clear(struct t4 *wc, int span)
+{
+ int i,j;
+ int oldnotclear;
+ unsigned short val=0;
+ struct t4_span *ts = wc->tspans[span];
+
+ oldnotclear = ts->notclear;
+ if ((ts->spantype == TYPE_T1) || (ts->spantype == TYPE_J1)) {
+ for (i=0;i<24;i++) {
+ j = (i/8);
+ if (ts->span.chans[i].flags & ZT_FLAG_CLEAR) {
+ val |= 1 << (7 - (i % 8));
+ ts->notclear &= ~(1 << i);
+ } else
+ ts->notclear |= (1 << i);
+ if ((i % 8)==7) {
+ if (debug)
+ printk("Putting %d in register %02x on span %d\n",
+ val, 0x2f + j, span + 1);
+ __t4_framer_out(wc, span, 0x2f + j, val);
+ val = 0;
+ }
+ }
+ } else {
+ for (i=0;i<31;i++) {
+ if (ts->span.chans[i].flags & ZT_FLAG_CLEAR)
+ ts->notclear &= ~(1 << i);
+ else
+ ts->notclear |= (1 << i);
+ }
+ }
+ if (ts->notclear != oldnotclear) {
+ unsigned char reg;
+ reg = __t4_framer_in(wc, span, FRMR_IMR0);
+ if (ts->notclear)
+ reg &= ~0x08;
+ else
+ reg |= 0x08;
+ __t4_framer_out(wc, span, FRMR_IMR0, reg);
+ }
+}
+
+#if 0
+static void set_clear(struct t4 *wc, int span)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __set_clear(wc, span);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+#endif
+
+static int t4_dacs(struct zt_chan *dst, struct zt_chan *src)
+{
+ struct t4 *wc;
+ struct t4_span *ts;
+ wc = dst->pvt;
+ ts = wc->tspans[dst->span->offset];
+ if (src && (src->pvt != dst->pvt)) {
+ if (ts->spanflags & FLAG_2NDGEN)
+ t4_tsi_unassign(wc, dst->span->offset, dst->chanpos);
+ wc = src->pvt;
+ if (ts->spanflags & FLAG_2NDGEN)
+ t4_tsi_unassign(wc, src->span->offset, src->chanpos);
+ if (debug)
+ printk("Unassigning %d/%d by default and...\n", src->span->offset, src->chanpos);
+ if (debug)
+ printk("Unassigning %d/%d by default\n", dst->span->offset, dst->chanpos);
+ return -1;
+ }
+ if (src) {
+ t4_tsi_assign(wc, src->span->offset, src->chanpos, dst->span->offset, dst->chanpos);
+ if (debug)
+ printk("Assigning channel %d/%d -> %d/%d!\n", src->span->offset, src->chanpos, dst->span->offset, dst->chanpos);
+ } else {
+ t4_tsi_unassign(wc, dst->span->offset, dst->chanpos);
+ if (debug)
+ printk("Unassigning channel %d/%d!\n", dst->span->offset, dst->chanpos);
+ }
+ return 0;
+}
+
+#ifdef VPM_SUPPORT
+
+void oct_set_reg(void *data, unsigned int reg, unsigned int val)
+{
+ struct t4 *wc = data;
+ t4_oct_out(wc, reg, val);
+}
+
+unsigned int oct_get_reg(void *data, unsigned int reg)
+{
+ struct t4 *wc = data;
+ unsigned int ret;
+ ret = t4_oct_in(wc, reg);
+ return ret;
+}
+
+static int t4_vpm_unit(int span, int channel)
+{
+ int unit = 0;
+ switch(vpmspans) {
+ case 4:
+ unit = span;
+ unit += (channel & 1) << 2;
+ break;
+ case 2:
+ unit = span;
+ unit += (channel & 0x3) << 1;
+ break;
+ case 1:
+ unit = span;
+ unit += (channel & 0x7);
+ }
+ return unit;
+}
+
+static int t4_echocan(struct zt_chan *chan, int eclen)
+{
+ struct t4 *wc = chan->pvt;
+ int channel;
+ int unit;
+
+ if (!wc->vpm)
+ return -ENODEV;
+
+ if (chan->span->offset >= vpmspans)
+ return -ENODEV;
+
+ if (wc->t1e1)
+ channel = chan->chanpos;
+ else
+ channel = chan->chanpos + 4;
+ if (wc->vpm450m) {
+ channel = channel << 2;
+ channel |= chan->span->offset;
+ if(debug & DEBUG_ECHOCAN)
+ printk("echocan: Card is %d, Channel is %d, Span is %d, offset is %d length %d\n",
+ wc->num, chan->chanpos, chan->span->offset, channel, eclen);
+ vpm450m_setec(wc->vpm450m, channel, eclen);
+// Mark msleep(10);
+// msleep(100); // longer test
+ } else {
+ unit = t4_vpm_unit(chan->span->offset, channel);
+ if(debug & DEBUG_ECHOCAN)
+ printk("echocan: Card is %d, Channel is %d, Span is %d, unit is %d, unit offset is %d length %d\n",
+ wc->num, chan->chanpos, chan->span->offset, unit, channel, eclen);
+ if (eclen)
+ t4_vpm_out(wc,unit,channel,0x3e);
+ else
+ t4_vpm_out(wc,unit,channel,0x01);
+ }
+ return 0;
+}
+#endif
+
+static int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
+{
+ struct t4_regs regs;
+ int x;
+ struct t4 *wc = chan->pvt;
+#ifdef VPM_SUPPORT
+ int j;
+ int channel;
+ struct t4_span *ts = wc->tspans[chan->span->offset];
+#endif
+
+#ifdef VPM_SUPPORT
+ if (dtmfthreshold == 0)
+ dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
+ if (lastdtmfthreshold != dtmfthreshold) {
+ lastdtmfthreshold = dtmfthreshold;
+ t4_vpm_set_dtmf_threshold(wc, dtmfthreshold);
+ }
+#endif
+
+ switch(cmd) {
+ case WCT4_GET_REGS:
+ for (x=0;x<NUM_PCI;x++)
+ regs.pci[x] = t4_pci_in(wc, x);
+ for (x=0;x<NUM_REGS;x++)
+ regs.regs[x] = t4_framer_in(wc, chan->span->offset, x);
+ if (copy_to_user((struct t4_regs *)data, &regs, sizeof(regs)))
+ return -EFAULT;
+ break;
+#ifdef VPM_SUPPORT
+ case ZT_TONEDETECT:
+ if (get_user(j, (int *)data))
+ return -EFAULT;
+ if (!wc->vpm)
+ return -ENOSYS;
+ if (j && (vpmdtmfsupport == 0))
+ return -ENOSYS;
+ if (j & ZT_TONEDETECT_ON)
+ set_bit(chan->chanpos - 1, &ts->dtmfmask);
+ else
+ clear_bit(chan->chanpos - 1, &ts->dtmfmask);
+ if (j & ZT_TONEDETECT_MUTE)
+ set_bit(chan->chanpos - 1, &ts->dtmfmutemask);
+ else
+ clear_bit(chan->chanpos - 1, &ts->dtmfmutemask);
+ if (wc->vpm450m) {
+ channel = (chan->chanpos) << 2;
+ if (!wc->t1e1)
+ channel += (4 << 2);
+ channel |= chan->span->offset;
+ vpm450m_setdtmf(wc->vpm450m, channel, j & ZT_TONEDETECT_ON, j & ZT_TONEDETECT_MUTE);
+ }
+ return 0;
+#endif
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static void inline t4_hdlc_xmit_fifo(struct t4 *wc, unsigned int span, struct t4_span *ts)
+{
+ int res, i, size = 32;
+ unsigned char buf[32];
+
+ res = zt_hdlc_getbuf(ts->sigchan, buf, &size);
+ if (debug & DEBUG_FRAMER) printk("Got buffer sized %d and res %d for %d\n", size, res, span);
+ if (size > 0) {
+ ts->sigactive = 1;
+
+ if (debug & DEBUG_FRAMER) {
+ printk("TX(");
+ for (i = 0; i < size; i++)
+ printk((i ? " %02x" : "%02x"), buf[i]);
+ printk(")\n");
+ }
+
+ for (i = 0; i < size; i++)
+ t4_framer_out(wc, span, FRMR_TXFIFO, buf[i]);
+
+ if (res) /* End of message */ {
+ if (debug & DEBUG_FRAMER) printk("transmiting XHF|XME\n");
+ t4_framer_cmd_wait(wc, span, FRMR_CMDR_XHF | FRMR_CMDR_XME);
+#if 0
+ ts->sigactive = (__t4_framer_in(wc, span, FRMR_SIS) & FRMR_SIS_XFW) ? 0 : 1;
+#endif
+ ++ts->frames_out;
+ if ((debug & DEBUG_FRAMER) && !(ts->frames_out & 0x0f))
+ printk("Transmitted %d frames on span %d\n", ts->frames_out, span);
+ } else { /* Still more to transmit */
+ if (debug & DEBUG_FRAMER) printk("transmiting XHF\n");
+ t4_framer_cmd_wait(wc, span, FRMR_CMDR_XHF);
+ }
+ }
+ else if (res < 0)
+ ts->sigactive = 0;
+}
+
+static void t4_hdlc_hard_xmit(struct zt_chan *chan)
+{
+ struct t4 *wc = chan->pvt;
+ int span = chan->span->offset;
+ struct t4_span *ts = wc->tspans[span];
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ if (!ts->sigchan) {
+ printk("t4_hdlc_hard_xmit: Invalid (NULL) signalling channel\n");
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ if (debug & DEBUG_FRAMER) printk("t4_hdlc_hard_xmit on channel %s (sigchan %s), sigactive=%d\n", chan->name, ts->sigchan->name, ts->sigactive);
+
+ if ((ts->sigchan == chan) && !ts->sigactive)
+ t4_hdlc_xmit_fifo(wc, span, ts);
+}
+
+static int t4_maint(struct zt_span *span, int cmd)
+{
+ struct t4_span *ts = span->pvt;
+ struct t4 *wc = ts->owner;
+
+ if (ts->spantype == TYPE_E1) {
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ printk("XXX Turn off local and remote loops E1 XXX\n");
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ printk("XXX Turn on local loopback E1 XXX\n");
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ printk("XXX Turn on remote loopback E1 XXX\n");
+ break;
+ case ZT_MAINT_LOOPUP:
+ printk("XXX Send loopup code E1 XXX\n");
+ break;
+ case ZT_MAINT_LOOPDOWN:
+ printk("XXX Send loopdown code E1 XXX\n");
+ break;
+ case ZT_MAINT_LOOPSTOP:
+ printk("XXX Stop sending loop codes E1 XXX\n");
+ break;
+ default:
+ printk("TE%dXXP: Unknown E1 maint command: %d\n", wc->numspans, cmd);
+ break;
+ }
+ } else {
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ printk("XXX Turn off local and remote loops T1 XXX\n");
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ printk("XXX Turn on local loop and no remote loop XXX\n");
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ printk("XXX Turn on remote loopup XXX\n");
+ break;
+ case ZT_MAINT_LOOPUP:
+ t4_framer_out(wc, span->offset, 0x21, 0x50); /* FMR5: Nothing but RBS mode */
+ break;
+ case ZT_MAINT_LOOPDOWN:
+ t4_framer_out(wc, span->offset, 0x21, 0x60); /* FMR5: Nothing but RBS mode */
+ break;
+ case ZT_MAINT_LOOPSTOP:
+ t4_framer_out(wc, span->offset, 0x21, 0x40); /* FMR5: Nothing but RBS mode */
+ break;
+ default:
+ printk("TE%dXXP: Unknown T1 maint command: %d\n", wc->numspans, cmd);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int t4_rbsbits(struct zt_chan *chan, int bits)
+{
+ u_char m,c;
+ int k,n,b;
+ struct t4 *wc = chan->pvt;
+ struct t4_span *ts = wc->tspans[chan->span->offset];
+ unsigned long flags;
+
+ if(debug & DEBUG_RBS) printk("Setting bits to %d on channel %s\n", bits, chan->name);
+ spin_lock_irqsave(&wc->reglock, flags);
+ k = chan->span->offset;
+ if (ts->spantype == TYPE_E1) { /* do it E1 way */
+ if (chan->chanpos == 16) {
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return 0;
+ }
+ n = chan->chanpos - 1;
+ if (chan->chanpos > 15) n--;
+ b = (n % 15);
+ c = ts->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 */
+ ts->txsigs[b] = c;
+ /* output them to the chip */
+ __t4_framer_out(wc,k,0x71 + b,c);
+ } else if (ts->span.lineconfig & ZT_CONFIG_D4) {
+ n = chan->chanpos - 1;
+ b = (n/4);
+ c = ts->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 */
+ ts->txsigs[b] = c;
+ /* output them to the chip */
+ __t4_framer_out(wc,k,0x70 + b,c);
+ __t4_framer_out(wc,k,0x70 + b + 6,c);
+ } else if (ts->span.lineconfig & ZT_CONFIG_ESF) {
+ n = chan->chanpos - 1;
+ b = (n/2);
+ c = ts->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 */
+ ts->txsigs[b] = c;
+ /* output them to the chip */
+ __t4_framer_out(wc,k,0x70 + b,c);
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (debug & DEBUG_RBS)
+ printk("Finished setting RBS bits\n");
+ return 0;
+}
+
+static int t4_shutdown(struct zt_span *span)
+{
+ int tspan;
+ int wasrunning;
+ unsigned long flags;
+ struct t4_span *ts = span->pvt;
+ struct t4 *wc = ts->owner;
+
+ tspan = span->offset + 1;
+ if (tspan < 0) {
+ printk("T%dXXP: Span '%d' isn't us?\n", wc->numspans, span->spanno);
+ return -1;
+ }
+
+ if (debug & DEBUG_MAIN) printk("Shutting down span %d (%s)\n", span->spanno, span->name);
+
+ /* Stop HDLC controller if runned */
+ if (ts->sigchan)
+ hdlc_stop(wc, span->offset);
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ wasrunning = span->flags & ZT_FLAG_RUNNING;
+
+ span->flags &= ~ZT_FLAG_RUNNING;
+ __t4_set_led(wc, span->offset, WC_OFF);
+ if (((wc->numspans == 4) &&
+ (!(wc->tspans[0]->span.flags & ZT_FLAG_RUNNING)) &&
+ (!(wc->tspans[1]->span.flags & ZT_FLAG_RUNNING)) &&
+ (!(wc->tspans[2]->span.flags & ZT_FLAG_RUNNING)) &&
+ (!(wc->tspans[3]->span.flags & ZT_FLAG_RUNNING)))
+ ||
+ ((wc->numspans == 2) &&
+ (!(wc->tspans[0]->span.flags & ZT_FLAG_RUNNING)) &&
+ (!(wc->tspans[1]->span.flags & ZT_FLAG_RUNNING)))) {
+ /* No longer in use, disable interrupts */
+ printk("TE%dXXP: Disabling interrupts since there are no active spans\n", wc->numspans);
+ set_bit(T4_STOP_DMA, &wc->checkflag);
+ } else
+ set_bit(T4_CHECK_TIMING, &wc->checkflag);
+
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ /* Wait for interrupt routine to shut itself down */
+ msleep(10);
+ if (wasrunning)
+ wc->spansstarted--;
+
+ if (debug & DEBUG_MAIN)
+ printk("Span %d (%s) shutdown\n", span->spanno, span->name);
+ return 0;
+}
+
+static int t4_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+ int i;
+ struct t4_span *ts = span->pvt;
+ struct t4 *wc = ts->owner;
+
+ printk("About to enter spanconfig!\n");
+ if (debug & DEBUG_MAIN)
+ printk("TE%dXXP: Configuring span %d\n", wc->numspans, span->spanno);
+
+ if (lc->sync < 0)
+ lc->sync = 0;
+ if (lc->sync > 4)
+ lc->sync = 0;
+
+ /* remove this span number from the current sync sources, if there */
+ for(i = 0; i < wc->numspans; i++) {
+ if (wc->tspans[i]->sync == span->spanno) {
+ wc->tspans[i]->sync = 0;
+ wc->tspans[i]->psync = 0;
+ }
+ }
+ wc->tspans[span->offset]->syncpos = lc->sync;
+ /* if a sync src, put it in proper place */
+ if (lc->sync) {
+ wc->tspans[lc->sync - 1]->sync = span->spanno;
+ wc->tspans[lc->sync - 1]->psync = span->offset + 1;
+ }
+ set_bit(T4_CHECK_TIMING, &wc->checkflag);
+
+ /* Make sure this is clear in case of multiple startup and shutdown
+ * iterations */
+ clear_bit(T4_STOP_DMA, &wc->checkflag);
+
+ /* If we're already running, then go ahead and apply the changes */
+ if (span->flags & ZT_FLAG_RUNNING)
+ return t4_startup(span);
+ printk("Done with spanconfig!\n");
+ return 0;
+}
+
+static int t4_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ int alreadyrunning;
+ unsigned long flags;
+ struct t4 *wc = chan->pvt;
+ struct t4_span *ts = wc->tspans[chan->span->offset];
+
+ alreadyrunning = ts->span.flags & ZT_FLAG_RUNNING;
+ if (debug & DEBUG_MAIN) {
+ if (alreadyrunning)
+ printk("TE%dXXP: Reconfigured channel %d (%s) sigtype %d\n", wc->numspans, chan->channo, chan->name, sigtype);
+ else
+ printk("TE%dXXP: Configured channel %d (%s) sigtype %d\n", wc->numspans, chan->channo, chan->name, sigtype);
+ }
+
+ spin_lock_irqsave(&wc->reglock, flags);
+
+ if (alreadyrunning)
+ __set_clear(wc, chan->span->offset);
+
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ /* (re)configure signalling channel */
+ if ((sigtype == ZT_SIG_HARDHDLC) || (ts->sigchan == chan)) {
+ if (debug & DEBUG_FRAMER)
+ printk("%sonfiguring hardware HDLC on %s\n", ((sigtype == ZT_SIG_HARDHDLC) ? "C" : "Unc"), chan->name);
+ if (alreadyrunning) {
+ if (ts->sigchan)
+ hdlc_stop(wc, ts->sigchan->span->offset);
+ if (sigtype == ZT_SIG_HARDHDLC) {
+ if (hdlc_start(wc, chan->span->offset, chan, ts->sigmode)) {
+ printk("Error initializing signalling controller\n");
+ return -1;
+ }
+ } else {
+ spin_lock_irqsave(&wc->reglock, flags);
+ ts->sigchan = NULL;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ }
+
+ }
+ else {
+ spin_lock_irqsave(&wc->reglock, flags);
+ ts->sigchan = (sigtype == ZT_SIG_HARDHDLC) ? chan : NULL;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ ts->sigactive = 0;
+ }
+ }
+ return 0;
+}
+
+static int t4_open(struct zt_chan *chan)
+{
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#else
+ try_module_get(THIS_MODULE);
+#endif
+
+ return 0;
+}
+
+static int t4_close(struct zt_chan *chan)
+{
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#else
+ module_put(THIS_MODULE);
+#endif
+ return 0;
+}
+
+/* The number of cards we have seen with each
+ possible 'order' switch setting.
+*/
+static unsigned int order_index[16];
+
+static void init_spans(struct t4 *wc)
+{
+ int x,y;
+ int gen2;
+ int offset = 1;
+ struct t4_span *ts;
+
+ gen2 = (wc->tspans[0]->spanflags & FLAG_2NDGEN);
+ if (!wc->t1e1)
+ offset += 4;
+ for (x = 0; x < wc->numspans; x++) {
+ ts = wc->tspans[x];
+ sprintf(ts->span.name, "TE%d/%d/%d", wc->numspans, wc->num, x + 1);
+ snprintf(ts->span.desc, sizeof(ts->span.desc) - 1,
+ "T%dXXP (PCI) Card %d Span %d", wc->numspans, wc->num, x+1);
+ ts->span.manufacturer = "Digium";
+ zap_copy_string(ts->span.devicetype, wc->variety, sizeof(ts->span.devicetype));
+ if (wc->vpm == T4_VPM_PRESENT) {
+ if (!wc->vpm450m)
+ strncat(ts->span.devicetype, " with VPM400M", sizeof(ts->span.devicetype) - 1);
+ else
+ strncat(ts->span.devicetype, (wc->numspans > 2) ? " with VPMOCT128" : " with VPMOCT064",
+ sizeof(ts->span.devicetype) - 1);
+ }
+ if (order_index[wc->order] == 1)
+ snprintf(ts->span.location, sizeof(ts->span.location) - 1, "Board ID Switch %d", wc->order);
+ else
+ snprintf(ts->span.location, sizeof(ts->span.location) - 1,
+ "PCI%s Bus %02d Slot %02d", (ts->spanflags & FLAG_EXPRESS) ? " Express" : " ",
+ wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1);
+ switch (ts->spantype) {
+ case TYPE_T1:
+ ts->span.spantype = "T1";
+ break;
+ case TYPE_E1:
+ ts->span.spantype = "E1";
+ break;
+ case TYPE_J1:
+ ts->span.spantype = "J1";
+ break;
+ }
+ ts->span.spanconfig = t4_spanconfig;
+ ts->span.chanconfig = t4_chanconfig;
+ ts->span.irq = wc->dev->irq;
+ ts->span.startup = t4_startup;
+ ts->span.shutdown = t4_shutdown;
+ ts->span.rbsbits = t4_rbsbits;
+ ts->span.maint = t4_maint;
+ ts->span.open = t4_open;
+ ts->span.close = t4_close;
+
+ /* HDLC Specific init */
+ ts->sigchan = NULL;
+ ts->sigmode = sigmode;
+ ts->sigactive = 0;
+
+ if (ts->spantype == TYPE_T1 || ts->spantype == TYPE_J1) {
+ ts->span.channels = 24;
+ ts->span.deflaw = ZT_LAW_MULAW;
+ ts->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
+ } else {
+ ts->span.channels = 31;
+ ts->span.deflaw = ZT_LAW_ALAW;
+ ts->span.linecompat = ZT_CONFIG_HDB3 | ZT_CONFIG_CCS | ZT_CONFIG_CRC4;
+ }
+ ts->span.chans = ts->chans;
+ ts->span.flags = ZT_FLAG_RBS;
+ ts->span.ioctl = t4_ioctl;
+ ts->span.hdlc_hard_xmit = t4_hdlc_hard_xmit;
+ if (gen2) {
+#ifdef VPM_SUPPORT
+ ts->span.echocan = t4_echocan;
+#endif
+ ts->span.dacs = t4_dacs;
+ }
+ ts->span.pvt = ts;
+ ts->owner = wc;
+ ts->span.offset = x;
+ ts->writechunk = (void *)(wc->writechunk + x * 32 * 2);
+ ts->readchunk = (void *)(wc->readchunk + x * 32 * 2);
+ init_waitqueue_head(&ts->span.maintq);
+ for (y=0;y<wc->tspans[x]->span.channels;y++) {
+ struct zt_chan *mychans = ts->chans + y;
+ sprintf(mychans->name, "TE%d/%d/%d/%d", wc->numspans, wc->num, x + 1, y + 1);
+ mychans->sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_FXSLS | ZT_SIG_FXSGS | ZT_SIG_FXSKS | ZT_SIG_HARDHDLC | ZT_SIG_MTP2 |
+ ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_FXOKS | ZT_SIG_CAS | ZT_SIG_EM_E1 | ZT_SIG_DACS_RBS;
+ mychans->pvt = wc;
+ mychans->chanpos = y + 1;
+ if (gen2) {
+ mychans->writechunk = (void *)(wc->writechunk + (x * 32 + y + offset) * 2);
+ mychans->readchunk = (void *)(wc->readchunk + (x * 32 + y + offset) * 2);
+ }
+ }
+ }
+}
+
+static void t4_serial_setup(struct t4 *wc, int unit)
+{
+ if (!wc->globalconfig) {
+ wc->globalconfig = 1;
+ printk("TE%dXXP: Setting up global serial parameters\n", wc->numspans);
+ t4_framer_out(wc, 0, 0x85, 0xe0); /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */
+ t4_framer_out(wc, 0, 0x08, 0x01); /* IPC: Interrupt push/pull active low */
+
+ /* Global clocks (8.192 Mhz CLK) */
+ t4_framer_out(wc, 0, 0x92, 0x00);
+ t4_framer_out(wc, 0, 0x93, 0x18);
+ t4_framer_out(wc, 0, 0x94, 0xfb);
+ t4_framer_out(wc, 0, 0x95, 0x0b);
+ t4_framer_out(wc, 0, 0x96, 0x00);
+ t4_framer_out(wc, 0, 0x97, 0x0b);
+ t4_framer_out(wc, 0, 0x98, 0xdb);
+ t4_framer_out(wc, 0, 0x99, 0xdf);
+ }
+
+ /* Configure interrupts */
+ t4_framer_out(wc, unit, FRMR_GCR, 0x00); /* GCR: Interrupt on Activation/Deactivation of each */
+
+ /* Configure system interface */
+ t4_framer_out(wc, unit, FRMR_SIC1, 0xc2); /* SIC1: 8.192 Mhz clock/bus, double buffer receive / transmit, byte interleaved */
+ t4_framer_out(wc, unit, FRMR_SIC2, 0x20 | (unit << 1)); /* SIC2: No FFS, no center receive eliastic buffer, phase */
+ t4_framer_out(wc, unit, FRMR_SIC3, 0x04); /* SIC3: Edges for capture */
+ t4_framer_out(wc, unit, FRMR_CMR2, 0x00); /* CMR2: We provide sync and clock for tx and rx. */
+ if (!wc->t1e1) { /* T1 mode */
+ t4_framer_out(wc, unit, FRMR_XC0, 0x03); /* XC0: Normal operation of Sa-bits */
+ t4_framer_out(wc, unit, FRMR_XC1, 0x84); /* XC1: 0 offset */
+ if (wc->tspans[unit]->spantype == TYPE_J1)
+ t4_framer_out(wc, unit, FRMR_RC0, 0x83); /* RC0: Just shy of 1023 */
+ else
+ t4_framer_out(wc, unit, FRMR_RC0, 0x03); /* RC0: Just shy of 1023 */
+ t4_framer_out(wc, unit, FRMR_RC1, 0x84); /* RC1: The rest of RC0 */
+ } else { /* E1 mode */
+ t4_framer_out(wc, unit, FRMR_XC0, 0x00); /* XC0: Normal operation of Sa-bits */
+ t4_framer_out(wc, unit, FRMR_XC1, 0x04); /* XC1: 0 offset */
+ t4_framer_out(wc, unit, FRMR_RC0, 0x04); /* RC0: Just shy of 1023 */
+ t4_framer_out(wc, unit, FRMR_RC1, 0x04); /* RC1: The rest of RC0 */
+ }
+
+ /* Configure ports */
+ t4_framer_out(wc, unit, 0x80, 0x00); /* PC1: SPYR/SPYX input on RPA/XPA */
+ t4_framer_out(wc, unit, 0x81, 0x22); /* PC2: RMFB/XSIG output/input on RPB/XPB */
+ t4_framer_out(wc, unit, 0x82, 0x65); /* PC3: Some unused stuff */
+ t4_framer_out(wc, unit, 0x83, 0x35); /* PC4: Some more unused stuff */
+ t4_framer_out(wc, unit, 0x84, 0x01); /* PC5: XMFS active low, SCLKR is input, RCLK is output */
+ if (debug & DEBUG_MAIN)
+ printk("Successfully initialized serial bus for unit %d\n", unit);
+}
+
+static int syncsrc = 0;
+static int syncnum = 0 /* -1 */;
+static int syncspan = 0;
+#ifdef DEFINE_SPINLOCK
+static DEFINE_SPINLOCK(synclock);
+#else
+static spinlock_t synclock = SPIN_LOCK_UNLOCKED;
+#endif
+
+static void __t4_set_timing_source(struct t4 *wc, int unit, int master, int slave)
+{
+ unsigned int timing;
+ int x;
+ if (unit != wc->syncsrc) {
+ timing = 0x34; /* CMR1: RCLK unit, 8.192 Mhz TCLK, RCLK is 8.192 Mhz */
+ if ((unit > -1) && (unit < 4)) {
+ timing |= (unit << 6);
+ for (x=0;x<wc->numspans;x++) /* set all 4 receive reference clocks to unit */
+ __t4_framer_out(wc, x, 0x44, timing);
+ wc->dmactrl |= (1 << 29);
+ } else {
+ for (x=0;x<wc->numspans;x++) /* set each receive reference clock to itself */
+ __t4_framer_out(wc, x, 0x44, timing | (x << 6));
+ wc->dmactrl &= ~(1 << 29);
+ }
+ if (slave)
+ wc->dmactrl |= (1 << 25);
+ else
+ wc->dmactrl &= ~(1 << 25);
+ if (master)
+ wc->dmactrl |= (1 << 24);
+ else
+ wc->dmactrl &= ~(1 << 24);
+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+ if (!master && !slave)
+ wc->syncsrc = unit;
+ if ((unit < 0) || (unit > 3))
+ unit = 0;
+ else
+ unit++;
+ if (!master && !slave) {
+ for (x=0;x<wc->numspans;x++)
+ wc->tspans[x]->span.syncsrc = unit;
+ }
+ } else {
+ if (debug & DEBUG_MAIN)
+ printk("TE%dXXP: Timing source already set to %d\n", wc->numspans, unit);
+ }
+#if 0
+ printk("wct4xxp: Timing source set to %d\n",unit);
+#endif
+}
+
+static inline void __t4_update_timing(struct t4 *wc)
+{
+ int i;
+ /* update sync src info */
+ if (wc->syncsrc != syncsrc) {
+ printk("Swapping card %d from %d to %d\n", wc->num, wc->syncsrc, syncsrc);
+ wc->syncsrc = syncsrc;
+ /* Update sync sources */
+ for (i = 0; i < wc->numspans; i++) {
+ wc->tspans[i]->span.syncsrc = wc->syncsrc;
+ }
+ if (syncnum == wc->num) {
+ __t4_set_timing_source(wc, syncspan-1, 1, 0);
+ if (debug) printk("Card %d, using sync span %d, master\n", wc->num, syncspan);
+ } else {
+ __t4_set_timing_source(wc, syncspan-1, 0, 1);
+ if (debug) printk("Card %d, using Timing Bus, NOT master\n", wc->num);
+ }
+ }
+}
+
+static int __t4_findsync(struct t4 *wc)
+{
+ int i;
+ int x;
+ unsigned long flags;
+ int p;
+ int nonzero;
+ int newsyncsrc = 0; /* Zaptel span number */
+ int newsyncnum = 0; /* wct4xxp card number */
+ int newsyncspan = 0; /* span on given wct4xxp card */
+ spin_lock_irqsave(&synclock, flags);
+#if 1
+ if (!wc->num) {
+ /* If we're the first card, go through all the motions, up to 8 levels
+ of sync source */
+ p = 1;
+ while (p < 8) {
+ nonzero = 0;
+ for (x=0;cards[x];x++) {
+ for (i = 0; i < wc->numspans; i++) {
+ if (cards[x]->tspans[i]->syncpos) {
+ nonzero = 1;
+ if ((cards[x]->tspans[i]->syncpos == p) &&
+ !(cards[x]->tspans[i]->span.alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_LOOPBACK)) &&
+ (cards[x]->tspans[i]->span.flags & ZT_FLAG_RUNNING)) {
+ /* This makes a good sync source */
+ newsyncsrc = cards[x]->tspans[i]->span.spanno;
+ newsyncnum = x;
+ newsyncspan = i + 1;
+ /* Jump out */
+ goto found;
+ }
+ }
+ }
+ }
+ if (nonzero)
+ p++;
+ else
+ break;
+ }
+found:
+ if ((syncnum != newsyncnum) || (syncsrc != newsyncsrc) || (newsyncspan != syncspan)) {
+ if (debug) printk("New syncnum: %d (was %d), syncsrc: %d (was %d), syncspan: %d (was %d)\n", newsyncnum, syncnum, newsyncsrc, syncsrc, newsyncspan, syncspan);
+ syncnum = newsyncnum;
+ syncsrc = newsyncsrc;
+ syncspan = newsyncspan;
+ for (x=0;cards[x];x++) {
+ __t4_update_timing(cards[x]);
+ }
+ }
+ } else
+ set_bit(T4_CHECK_TIMING, &cards[0]->checkflag);
+#endif
+ spin_unlock_irqrestore(&synclock, flags);
+ return 0;
+}
+
+static void __t4_set_timing_source_auto(struct t4 *wc)
+{
+ int x;
+ printk("timing source auto card %d!\n", wc->num);
+ clear_bit(T4_CHECK_TIMING, &wc->checkflag);
+ if (timingcable) {
+ __t4_findsync(wc);
+ } else {
+ for (x=0;x<wc->numspans;x++) {
+ if (wc->tspans[x]->sync) {
+ if ((wc->tspans[wc->tspans[x]->psync - 1]->span.flags & ZT_FLAG_RUNNING) &&
+ !(wc->tspans[wc->tspans[x]->psync - 1]->span.alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE) )) {
+ /* Valid timing source */
+ __t4_set_timing_source(wc, wc->tspans[x]->psync - 1, 0, 0);
+ return;
+ }
+ }
+ }
+ __t4_set_timing_source(wc, 4, 0, 0);
+ }
+}
+
+static void __t4_configure_t1(struct t4 *wc, int unit, 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 = 0x9c; /* FMR1: Mode 1, T1 mode, CRC on for ESF, 8.192 Mhz system data rate, no XAIS */
+ fmr2 = 0x22; /* FMR2: no payload loopback, auto send yellow alarm */
+ if (loopback)
+ fmr2 |= 0x4;
+ 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 */
+ __t4_framer_out(wc, unit, 0x1d, fmr1);
+ __t4_framer_out(wc, unit, 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;
+ }
+ __t4_framer_out(wc, unit, 0x1c, fmr0);
+ __t4_framer_out(wc, unit, 0x20, fmr4);
+ __t4_framer_out(wc, unit, 0x21, 0x40); /* FMR5: Enable RBS mode */
+
+ __t4_framer_out(wc, unit, 0x37, 0xf0 ); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */
+ __t4_framer_out(wc, unit, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */
+
+ __t4_framer_out(wc, unit, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */
+ __t4_framer_out(wc, unit, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */
+
+ __t4_framer_out(wc, unit, 0x3a, lim2); /* LIM2: 50% peak amplitude is a "1" */
+ __t4_framer_out(wc, unit, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */
+ __t4_framer_out(wc, unit, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */
+
+ /* Generate pulse mask for T1 */
+ switch(mytxlevel) {
+ case 3:
+ __t4_framer_out(wc, unit, 0x26, 0x07); /* XPM0 */
+ __t4_framer_out(wc, unit, 0x27, 0x01); /* XPM1 */
+ __t4_framer_out(wc, unit, 0x28, 0x00); /* XPM2 */
+ break;
+ case 2:
+ __t4_framer_out(wc, unit, 0x26, 0x8c); /* XPM0 */
+ __t4_framer_out(wc, unit, 0x27, 0x11); /* XPM1 */
+ __t4_framer_out(wc, unit, 0x28, 0x01); /* XPM2 */
+ break;
+ case 1:
+ __t4_framer_out(wc, unit, 0x26, 0x8c); /* XPM0 */
+ __t4_framer_out(wc, unit, 0x27, 0x01); /* XPM1 */
+ __t4_framer_out(wc, unit, 0x28, 0x00); /* XPM2 */
+ break;
+ case 0:
+ default:
+ __t4_framer_out(wc, unit, 0x26, 0xd7); /* XPM0 */
+ __t4_framer_out(wc, unit, 0x27, 0x22); /* XPM1 */
+ __t4_framer_out(wc, unit, 0x28, 0x01); /* XPM2 */
+ break;
+ }
+
+ /* Don't mask framer interrupts if hardware HDLC is in use */
+ __t4_framer_out(wc, unit, FRMR_IMR0, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR0_MASK : 0)); /* IMR0: We care about CAS changes, etc */
+ __t4_framer_out(wc, unit, FRMR_IMR1, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR1_MASK : 0)); /* IMR1: We care about nothing */
+ __t4_framer_out(wc, unit, 0x16, 0x00); /* IMR2: We care about all the alarm stuff! */
+ __t4_framer_out(wc, unit, 0x17, 0xf4); /* IMR3: We care about AIS and friends */
+ __t4_framer_out(wc, unit, 0x18, 0x3f); /* IMR4: We care about slips on transmit */
+
+ printk("TE%dXXP: Span %d configured for %s/%s\n", wc->numspans, unit + 1, framing, line);
+}
+
+static void __t4_configure_e1(struct t4 *wc, int unit, int lineconfig)
+{
+ unsigned int fmr2, fmr1, fmr0;
+ unsigned int cas = 0;
+ unsigned int imr3extra=0;
+ char *crc4 = "";
+ char *framing, *line;
+ fmr1 = 0x44; /* 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 (loopback)
+ fmr2 |= 0x4;
+ if (lineconfig & ZT_CONFIG_CRC4) {
+ fmr1 |= 0x08; /* CRC4 transmit */
+ fmr2 |= 0xc0; /* CRC4 receive */
+ crc4 = "/CRC4";
+ }
+ __t4_framer_out(wc, unit, 0x1d, fmr1);
+ __t4_framer_out(wc, unit, 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";
+ imr3extra = 0x28;
+ } else {
+ framing = "CAS";
+ cas = 0x40;
+ }
+ __t4_framer_out(wc, unit, 0x1c, fmr0);
+
+ __t4_framer_out(wc, unit, 0x37, 0xf0 /*| 0x6 */ ); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */
+ __t4_framer_out(wc, unit, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */
+
+ __t4_framer_out(wc, unit, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */
+ __t4_framer_out(wc, unit, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */
+
+ /* Condition receive line interface for E1 after reset */
+ __t4_framer_out(wc, unit, 0xbb, 0x17);
+ __t4_framer_out(wc, unit, 0xbc, 0x55);
+ __t4_framer_out(wc, unit, 0xbb, 0x97);
+ __t4_framer_out(wc, unit, 0xbb, 0x11);
+ __t4_framer_out(wc, unit, 0xbc, 0xaa);
+ __t4_framer_out(wc, unit, 0xbb, 0x91);
+ __t4_framer_out(wc, unit, 0xbb, 0x12);
+ __t4_framer_out(wc, unit, 0xbc, 0x55);
+ __t4_framer_out(wc, unit, 0xbb, 0x92);
+ __t4_framer_out(wc, unit, 0xbb, 0x0c);
+ __t4_framer_out(wc, unit, 0xbb, 0x00);
+ __t4_framer_out(wc, unit, 0xbb, 0x8c);
+
+ __t4_framer_out(wc, unit, 0x3a, 0x20); /* LIM2: 50% peak amplitude is a "1" */
+ __t4_framer_out(wc, unit, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */
+ __t4_framer_out(wc, unit, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */
+
+ __t4_framer_out(wc, unit, 0x20, 0x9f); /* XSW: Spare bits all to 1 */
+ __t4_framer_out(wc, unit, 0x21, 0x1c|cas); /* XSP: E-bit set when async. AXS auto, XSIF to 1 */
+
+
+ /* Generate pulse mask for E1 */
+ __t4_framer_out(wc, unit, 0x26, 0x54); /* XPM0 */
+ __t4_framer_out(wc, unit, 0x27, 0x02); /* XPM1 */
+ __t4_framer_out(wc, unit, 0x28, 0x00); /* XPM2 */
+
+ /* Don't mask framer interrupts if hardware HDLC is in use */
+ __t4_framer_out(wc, unit, FRMR_IMR0, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR0_MASK : 0)); /* IMR0: We care about CRC errors, CAS changes, etc */
+ __t4_framer_out(wc, unit, FRMR_IMR1, 0x3f & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR1_MASK : 0)); /* IMR1: We care about loopup / loopdown */
+ __t4_framer_out(wc, unit, 0x16, 0x00); /* IMR2: We care about all the alarm stuff! */
+ __t4_framer_out(wc, unit, 0x17, 0xc4 | imr3extra); /* IMR3: We care about AIS and friends */
+ __t4_framer_out(wc, unit, 0x18, 0x3f); /* IMR4: We care about slips on transmit */
+
+ printk("TE%dXXP: Span %d configured for %s/%s%s\n", wc->numspans, unit + 1, framing, line, crc4);
+}
+
+static int t4_startup(struct zt_span *span)
+{
+#ifdef SUPPORT_GEN1
+ int i;
+#endif
+ int tspan;
+ unsigned long flags;
+ int alreadyrunning;
+ struct t4_span *ts = span->pvt;
+ struct t4 *wc = ts->owner;
+
+ printk("About to enter startup!\n");
+ tspan = span->offset + 1;
+ if (tspan < 0) {
+ printk("TE%dXXP: Span '%d' isn't us?\n", wc->numspans, span->spanno);
+ return -1;
+ }
+
+ spin_lock_irqsave(&wc->reglock, flags);
+
+ alreadyrunning = span->flags & ZT_FLAG_RUNNING;
+
+#ifdef SUPPORT_GEN1
+ /* initialize the start value for the entire chunk of last ec buffer */
+ for(i = 0; i < span->channels; i++)
+ {
+ memset(ts->ec_chunk1[i],
+ ZT_LIN2X(0,&span->chans[i]),ZT_CHUNKSIZE);
+ memset(ts->ec_chunk2[i],
+ ZT_LIN2X(0,&span->chans[i]),ZT_CHUNKSIZE);
+ }
+#endif
+ /* Force re-evaluation fo timing source */
+ if (timingcable)
+ wc->syncsrc = -1;
+
+ if (ts->spantype == TYPE_E1) { /* if this is an E1 card */
+ __t4_configure_e1(wc, span->offset, span->lineconfig);
+ } else { /* is a T1 card */
+ __t4_configure_t1(wc, span->offset, span->lineconfig, span->txlevel);
+ }
+
+ /* Note clear channel status */
+ wc->tspans[span->offset]->notclear = 0;
+ __set_clear(wc, span->offset);
+
+ if (!alreadyrunning) {
+ span->flags |= ZT_FLAG_RUNNING;
+ wc->spansstarted++;
+ /* enable interrupts */
+ /* Start DMA, enabling DMA interrupts on read only */
+ wc->dmactrl = 1 << 29;
+#if 0
+ /* Enable framer only interrupts */
+ wc->dmactrl |= 1 << 27;
+#endif
+ wc->dmactrl |= (ts->spanflags & FLAG_2NDGEN) ? 0xc0000000 : 0xc0000003;
+#ifdef VPM_SUPPORT
+ wc->dmactrl |= wc->vpm;
+#endif
+ /* Seed interrupt register */
+ __t4_pci_out(wc, WC_INTR, 0x0c);
+ if (noburst && !(ts->spanflags & FLAG_BURST))
+ wc->dmactrl |= (1 << 26);
+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+
+ /* Startup HDLC controller too */
+ }
+
+ if (ts->sigchan) {
+ struct zt_chan *sigchan = ts->sigchan;
+
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (hdlc_start(wc, span->offset, sigchan, ts->sigmode)) {
+ printk("Error initializing signalling controller\n");
+ return -1;
+ }
+ spin_lock_irqsave(&wc->reglock, flags);
+ }
+
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ t4_check_alarms(wc, span->offset);
+ t4_check_sigbits(wc, span->offset);
+
+ if (wc->tspans[0]->sync == span->spanno) printk("SPAN %d: Primary Sync Source\n",span->spanno);
+ if (wc->tspans[1]->sync == span->spanno) printk("SPAN %d: Secondary Sync Source\n",span->spanno);
+ if (wc->numspans == 4) {
+ if (wc->tspans[2]->sync == span->spanno) printk("SPAN %d: Tertiary Sync Source\n",span->spanno);
+ if (wc->tspans[3]->sync == span->spanno) printk("SPAN %d: Quaternary Sync Source\n",span->spanno);
+ }
+#ifdef VPM_SUPPORT
+ if (!alreadyrunning && !wc->vpm) {
+ wait_a_little();
+ t4_vpm400_init(wc);
+ if (!wc->vpm)
+ t4_vpm450_init(wc);
+ wc->dmactrl |= wc->vpm;
+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+ }
+#endif
+ printk("Completed startup!\n");
+ return 0;
+}
+
+#ifdef SUPPORT_GEN1
+static inline void e1_check(struct t4 *wc, int span, int val)
+{
+ struct t4_span *ts = wc->tspans[span];
+ if ((ts->span.channels > 24) &&
+ (ts->span.flags & ZT_FLAG_RUNNING) &&
+ !(ts->span.alarms) &&
+ (!wc->e1recover)) {
+ if (val != 0x1b) {
+ ts->e1check++;
+ } else
+ ts->e1check = 0;
+ if (ts->e1check > 100) {
+ /* Wait 1000 ms */
+ wc->e1recover = 1000 * 8;
+ wc->tspans[0]->e1check = wc->tspans[1]->e1check = 0;
+ if (wc->numspans == 4)
+ wc->tspans[2]->e1check = wc->tspans[3]->e1check = 0;
+ if (debug & DEBUG_MAIN)
+ printk("Detected loss of E1 alignment on span %d!\n", span);
+ t4_reset_dma(wc);
+ }
+ }
+}
+
+static void t4_receiveprep(struct t4 *wc, int irq)
+{
+ volatile unsigned int *readchunk;
+ int dbl = 0;
+ int x,y,z;
+ unsigned int tmp;
+ int offset=0;
+ if (!wc->t1e1)
+ offset = 4;
+ if (irq & 1) {
+ /* First part */
+ readchunk = wc->readchunk;
+ if (!wc->last0)
+ dbl = 1;
+ wc->last0 = 0;
+ } else {
+ readchunk = wc->readchunk + ZT_CHUNKSIZE * 32;
+ if (wc->last0)
+ dbl = 1;
+ wc->last0 = 1;
+ }
+ if (dbl) {
+ for (x=0;x<wc->numspans;x++)
+ wc->tspans[x]->irqmisses++;
+ if (debug & DEBUG_MAIN)
+ printk("TE%dXXP: Double/missed interrupt detected\n", wc->numspans);
+ }
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ for (z=0;z<24;z++) {
+ /* All T1/E1 channels */
+ tmp = readchunk[z+1+offset];
+ if (wc->numspans == 4) {
+ wc->tspans[3]->span.chans[z].readchunk[x] = tmp & 0xff;
+ wc->tspans[2]->span.chans[z].readchunk[x] = (tmp & 0xff00) >> 8;
+ }
+ wc->tspans[1]->span.chans[z].readchunk[x] = (tmp & 0xff0000) >> 16;
+ wc->tspans[0]->span.chans[z].readchunk[x] = tmp >> 24;
+ }
+ if (wc->t1e1) {
+ if (wc->e1recover > 0)
+ wc->e1recover--;
+ tmp = readchunk[0];
+ if (wc->numspans == 4) {
+ e1_check(wc, 3, (tmp & 0x7f));
+ e1_check(wc, 2, (tmp & 0x7f00) >> 8);
+ }
+ e1_check(wc, 1, (tmp & 0x7f0000) >> 16);
+ e1_check(wc, 0, (tmp & 0x7f000000) >> 24);
+ for (z=24;z<31;z++) {
+ /* Only E1 channels now */
+ tmp = readchunk[z+1];
+ if (wc->numspans == 4) {
+ if (wc->tspans[3]->span.channels > 24)
+ wc->tspans[3]->span.chans[z].readchunk[x] = tmp & 0xff;
+ if (wc->tspans[2]->span.channels > 24)
+ wc->tspans[2]->span.chans[z].readchunk[x] = (tmp & 0xff00) >> 8;
+ }
+ if (wc->tspans[1]->span.channels > 24)
+ wc->tspans[1]->span.chans[z].readchunk[x] = (tmp & 0xff0000) >> 16;
+ if (wc->tspans[0]->span.channels > 24)
+ wc->tspans[0]->span.chans[z].readchunk[x] = tmp >> 24;
+ }
+ }
+ /* Advance pointer by 4 TDM frame lengths */
+ readchunk += 32;
+ }
+ for (x=0;x<wc->numspans;x++) {
+ if (wc->tspans[x]->span.flags & ZT_FLAG_RUNNING) {
+ for (y=0;y<wc->tspans[x]->span.channels;y++) {
+ /* Echo cancel double buffered data */
+ zt_ec_chunk(&wc->tspans[x]->span.chans[y],
+ wc->tspans[x]->span.chans[y].readchunk,
+ wc->tspans[x]->ec_chunk2[y]);
+ memcpy(wc->tspans[x]->ec_chunk2[y],wc->tspans[x]->ec_chunk1[y],
+ ZT_CHUNKSIZE);
+ memcpy(wc->tspans[x]->ec_chunk1[y],
+ wc->tspans[x]->span.chans[y].writechunk,
+ ZT_CHUNKSIZE);
+ }
+ zt_receive(&wc->tspans[x]->span);
+ }
+ }
+}
+#endif
+
+#if (ZT_CHUNKSIZE != 8)
+#error Sorry, nextgen does not support chunksize != 8
+#endif
+
+static inline void __receive_span(struct t4_span *ts)
+{
+#ifdef VPM_SUPPORT
+ int y;
+ unsigned long merged;
+ merged = ts->dtmfactive & ts->dtmfmutemask;
+ if (merged) {
+ for (y=0;y<ts->span.channels;y++) {
+ /* Mute any DTMFs which are supposed to be muted */
+ if (test_bit(y, &merged)) {
+ memset(ts->span.chans[y].readchunk, ZT_XLAW(0, (ts->span.chans + y)), ZT_CHUNKSIZE);
+ }
+ }
+ }
+#endif
+
+#ifdef ENABLE_PREFETCH
+ prefetch((void *)(ts->readchunk));
+ prefetch((void *)(ts->writechunk));
+ prefetch((void *)(ts->readchunk + 8));
+ prefetch((void *)(ts->writechunk + 8));
+ prefetch((void *)(ts->readchunk + 16));
+ prefetch((void *)(ts->writechunk + 16));
+ prefetch((void *)(ts->readchunk + 24));
+ prefetch((void *)(ts->writechunk + 24));
+ prefetch((void *)(ts->readchunk + 32));
+ prefetch((void *)(ts->writechunk + 32));
+ prefetch((void *)(ts->readchunk + 40));
+ prefetch((void *)(ts->writechunk + 40));
+ prefetch((void *)(ts->readchunk + 48));
+ prefetch((void *)(ts->writechunk + 48));
+ prefetch((void *)(ts->readchunk + 56));
+ prefetch((void *)(ts->writechunk + 56));
+#endif
+
+ zt_ec_span(&ts->span);
+ zt_receive(&ts->span);
+}
+
+static inline void __transmit_span(struct t4_span *ts)
+{
+ zt_transmit(&ts->span);
+}
+
+#ifdef ENABLE_WORKQUEUES
+static void workq_handlespan(void *data)
+{
+ struct t4_span *ts = data;
+ struct t4 *wc = ts->owner;
+
+ __receive_span(ts);
+ __transmit_span(ts);
+ atomic_dec(&wc->worklist);
+ if (!atomic_read(&wc->worklist))
+ t4_pci_out(wc, WC_INTR, 0);
+}
+#else
+static void t4_prep_gen2(struct t4 *wc)
+{
+ int x;
+ for (x=0;x<wc->numspans;x++) {
+ if (wc->tspans[x]->span.flags & ZT_FLAG_RUNNING) {
+ __receive_span(wc->tspans[x]);
+ __transmit_span(wc->tspans[x]);
+ }
+ }
+}
+
+#endif
+#ifdef SUPPORT_GEN1
+static void t4_transmitprep(struct t4 *wc, int irq)
+{
+ volatile unsigned int *writechunk;
+ int x,y,z;
+ unsigned int tmp;
+ int offset=0;
+ if (!wc->t1e1)
+ offset = 4;
+ if (irq & 1) {
+ /* First part */
+ writechunk = wc->writechunk + 1;
+ } else {
+ writechunk = wc->writechunk + ZT_CHUNKSIZE * 32 + 1;
+ }
+ for (y=0;y<wc->numspans;y++) {
+ if (wc->tspans[y]->span.flags & ZT_FLAG_RUNNING)
+ zt_transmit(&wc->tspans[y]->span);
+ }
+
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ /* Once per chunk */
+ for (z=0;z<24;z++) {
+ /* All T1/E1 channels */
+ tmp = (wc->tspans[3]->span.chans[z].writechunk[x]) |
+ (wc->tspans[2]->span.chans[z].writechunk[x] << 8) |
+ (wc->tspans[1]->span.chans[z].writechunk[x] << 16) |
+ (wc->tspans[0]->span.chans[z].writechunk[x] << 24);
+ writechunk[z+offset] = tmp;
+ }
+ if (wc->t1e1) {
+ for (z=24;z<31;z++) {
+ /* Only E1 channels now */
+ tmp = 0;
+ if (wc->numspans == 4) {
+ if (wc->tspans[3]->span.channels > 24)
+ tmp |= wc->tspans[3]->span.chans[z].writechunk[x];
+ if (wc->tspans[2]->span.channels > 24)
+ tmp |= (wc->tspans[2]->span.chans[z].writechunk[x] << 8);
+ }
+ if (wc->tspans[1]->span.channels > 24)
+ tmp |= (wc->tspans[1]->span.chans[z].writechunk[x] << 16);
+ if (wc->tspans[0]->span.channels > 24)
+ tmp |= (wc->tspans[0]->span.chans[z].writechunk[x] << 24);
+ writechunk[z] = tmp;
+ }
+ }
+ /* Advance pointer by 4 TDM frame lengths */
+ writechunk += 32;
+ }
+
+}
+#endif
+
+static void t4_check_sigbits(struct t4 *wc, int span)
+{
+ int a,i,rxs;
+ struct t4_span *ts = wc->tspans[span];
+
+ if (debug & DEBUG_RBS)
+ printk("Checking sigbits on span %d\n", span + 1);
+
+ if (!(ts->span.flags & ZT_FLAG_RUNNING))
+ return;
+ if (ts->spantype == TYPE_E1) {
+ for (i = 0; i < 15; i++) {
+ a = t4_framer_in(wc, span, 0x71 + i);
+ /* Get high channel in low bits */
+ rxs = (a & 0xf);
+ if (!(ts->span.chans[i+16].sig & ZT_SIG_CLEAR)) {
+ if (ts->span.chans[i+16].rxsig != rxs)
+ zt_rbsbits(&ts->span.chans[i+16], rxs);
+ }
+ rxs = (a >> 4) & 0xf;
+ if (!(ts->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ if (ts->span.chans[i].rxsig != rxs)
+ zt_rbsbits(&ts->span.chans[i], rxs);
+ }
+ }
+ } else if (ts->span.lineconfig & ZT_CONFIG_D4) {
+ for (i = 0; i < 24; i+=4) {
+ a = t4_framer_in(wc, span, 0x70 + (i>>2));
+ /* Get high channel in low bits */
+ rxs = (a & 0x3) << 2;
+ if (!(ts->span.chans[i+3].sig & ZT_SIG_CLEAR)) {
+ if (ts->span.chans[i+3].rxsig != rxs)
+ zt_rbsbits(&ts->span.chans[i+3], rxs);
+ }
+ rxs = (a & 0xc);
+ if (!(ts->span.chans[i+2].sig & ZT_SIG_CLEAR)) {
+ if (ts->span.chans[i+2].rxsig != rxs)
+ zt_rbsbits(&ts->span.chans[i+2], rxs);
+ }
+ rxs = (a >> 2) & 0xc;
+ if (!(ts->span.chans[i+1].sig & ZT_SIG_CLEAR)) {
+ if (ts->span.chans[i+1].rxsig != rxs)
+ zt_rbsbits(&ts->span.chans[i+1], rxs);
+ }
+ rxs = (a >> 4) & 0xc;
+ if (!(ts->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ if (ts->span.chans[i].rxsig != rxs)
+ zt_rbsbits(&ts->span.chans[i], rxs);
+ }
+ }
+ } else {
+ for (i = 0; i < 24; i+=2) {
+ a = t4_framer_in(wc, span, 0x70 + (i>>1));
+ /* Get high channel in low bits */
+ rxs = (a & 0xf);
+ if (!(ts->span.chans[i+1].sig & ZT_SIG_CLEAR)) {
+ /* XXX Not really reset on every trans! XXX */
+ if (ts->span.chans[i+1].rxsig != rxs) {
+ zt_rbsbits(&ts->span.chans[i+1], rxs);
+ }
+ }
+ rxs = (a >> 4) & 0xf;
+ if (!(ts->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ /* XXX Not really reset on every trans! XXX */
+ if (ts->span.chans[i].rxsig != rxs) {
+ zt_rbsbits(&ts->span.chans[i], rxs);
+ }
+ }
+ }
+ }
+}
+
+static void t4_check_alarms(struct t4 *wc, int span)
+{
+ unsigned char c,d;
+ int alarms;
+ int x,j;
+ struct t4_span *ts = wc->tspans[span];
+ unsigned long flags;
+
+ if (!(ts->span.flags & ZT_FLAG_RUNNING))
+ return;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+
+ c = __t4_framer_in(wc, span, 0x4c);
+ d = __t4_framer_in(wc, span, 0x4d);
+
+ /* Assume no alarms */
+ alarms = 0;
+
+ /* And consider only carrier alarms */
+ ts->span.alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN);
+
+ if (ts->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 (!(ts->spanflags & FLAG_NMF)) {
+ __t4_framer_out(wc, span, 0x20, 0x9f | 0x20); /* LIM0: Force RAI High */
+ ts->spanflags |= FLAG_NMF;
+ printk("NMF workaround on!\n");
+ }
+ __t4_framer_out(wc, span, 0x1e, 0xc3); /* Reset to CRC4 mode */
+ __t4_framer_out(wc, span, 0x1c, 0xf2); /* Force Resync */
+ __t4_framer_out(wc, span, 0x1c, 0xf0); /* Force Resync */
+ } else if (!(c & 0x02)) {
+ if ((ts->spanflags & FLAG_NMF)) {
+ __t4_framer_out(wc, span, 0x20, 0x9f); /* LIM0: Clear forced RAI */
+ ts->spanflags &= ~FLAG_NMF;
+ printk("NMF workaround off!\n");
+ }
+ }
+ } else {
+ /* Detect loopup code if we're not sending one */
+ if ((!ts->span.mainttimer) && (d & 0x08)) {
+ /* Loop-up code detected */
+ if ((ts->loopupcnt++ > 80) && (ts->span.maintstat != ZT_MAINT_REMOTELOOP)) {
+ __t4_framer_out(wc, span, 0x36, 0x08); /* LIM0: Disable any local loop */
+ __t4_framer_out(wc, span, 0x37, 0xf6 ); /* LIM1: Enable remote loop */
+ ts->span.maintstat = ZT_MAINT_REMOTELOOP;
+ }
+ } else
+ ts->loopupcnt = 0;
+ /* Same for loopdown code */
+ if ((!ts->span.mainttimer) && (d & 0x10)) {
+ /* Loop-down code detected */
+ if ((ts->loopdowncnt++ > 80) && (ts->span.maintstat == ZT_MAINT_REMOTELOOP)) {
+ __t4_framer_out(wc, span, 0x36, 0x08); /* LIM0: Disable any local loop */
+ __t4_framer_out(wc, span, 0x37, 0xf0 ); /* LIM1: Disable remote loop */
+ ts->span.maintstat = ZT_MAINT_NONE;
+ }
+ } else
+ ts->loopdowncnt = 0;
+ }
+
+ if (ts->span.lineconfig & ZT_CONFIG_NOTOPEN) {
+ for (x=0,j=0;x < ts->span.channels;x++)
+ if ((ts->span.chans[x].flags & ZT_FLAG_OPEN) ||
+ (ts->span.chans[x].flags & ZT_FLAG_NETDEV))
+ j++;
+ if (!j)
+ alarms |= ZT_ALARM_NOTOPEN;
+ }
+
+ if (c & 0xa0) {
+ if (ts->alarmcount >= alarmdebounce)
+ alarms |= ZT_ALARM_RED;
+ else
+ ts->alarmcount++;
+ } else
+ ts->alarmcount = 0;
+ if (c & 0x4)
+ alarms |= ZT_ALARM_BLUE;
+
+ if (((!ts->span.alarms) && alarms) ||
+ (ts->span.alarms && (!alarms)))
+ set_bit(T4_CHECK_TIMING, &wc->checkflag);
+
+ /* Keep track of recovering */
+ if ((!alarms) && ts->span.alarms)
+ ts->alarmtimer = ZT_ALARMSETTLE_TIME;
+ if (ts->alarmtimer)
+ alarms |= ZT_ALARM_RECOVER;
+
+ /* If receiving alarms, go into Yellow alarm state */
+ if (alarms && !(ts->spanflags & FLAG_SENDINGYELLOW)) {
+ unsigned char fmr4;
+#if 1
+ printk("wct%dxxp: Setting yellow alarm on span %d\n", wc->numspans, span + 1);
+#endif
+ /* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */
+ fmr4 = __t4_framer_in(wc, span, 0x20);
+ __t4_framer_out(wc, span, 0x20, fmr4 | 0x20);
+ ts->spanflags |= FLAG_SENDINGYELLOW;
+ } else if ((!alarms) && (ts->spanflags & FLAG_SENDINGYELLOW)) {
+ unsigned char fmr4;
+#if 1
+ printk("wct%dxxp: Clearing yellow alarm on span %d\n", wc->numspans, span + 1);
+#endif
+ /* We manually do yellow alarm to handle RECOVER */
+ fmr4 = __t4_framer_in(wc, span, 0x20);
+ __t4_framer_out(wc, span, 0x20, fmr4 & ~0x20);
+ ts->spanflags &= ~FLAG_SENDINGYELLOW;
+ }
+
+ /* Re-check the timing source when we enter/leave alarm, not withstanding
+ yellow alarm */
+ if (c & 0x10)
+ alarms |= ZT_ALARM_YELLOW;
+ if (ts->span.mainttimer || ts->span.maintstat)
+ alarms |= ZT_ALARM_LOOPBACK;
+ ts->span.alarms = alarms;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ zt_alarm_notify(&ts->span);
+}
+
+static void t4_do_counters(struct t4 *wc)
+{
+ int span;
+ for (span=0;span<wc->numspans;span++) {
+ struct t4_span *ts = wc->tspans[span];
+ int docheck=0;
+
+ spin_lock(&wc->reglock);
+ if (ts->loopupcnt || ts->loopdowncnt)
+ docheck++;
+ if (ts->alarmtimer) {
+ if (!--ts->alarmtimer) {
+ docheck++;
+ ts->span.alarms &= ~(ZT_ALARM_RECOVER);
+ }
+ }
+ spin_unlock(&wc->reglock);
+ if (docheck) {
+ t4_check_alarms(wc, span);
+ zt_alarm_notify(&ts->span);
+ }
+ }
+}
+
+static inline void __handle_leds(struct t4 *wc)
+{
+ int x;
+
+ wc->blinktimer++;
+ for (x=0;x<wc->numspans;x++) {
+ struct t4_span *ts = wc->tspans[x];
+ if (ts->span.flags & ZT_FLAG_RUNNING) {
+ if (ts->span.alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE)) {
+#ifdef FANCY_ALARM
+ if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) {
+ __t4_set_led(wc, x, WC_RED);
+ }
+ if (wc->blinktimer == 0xf) {
+ __t4_set_led(wc, x, WC_OFF);
+ }
+#else
+ if (wc->blinktimer == 160) {
+ __t4_set_led(wc, x, WC_RED);
+ } else if (wc->blinktimer == 480) {
+ __t4_set_led(wc, x, WC_OFF);
+ }
+#endif
+ } else if (ts->span.alarms & ZT_ALARM_YELLOW) {
+ /* Yellow Alarm */
+ __t4_set_led(wc, x, WC_YELLOW);
+ } else if (ts->span.mainttimer || ts->span.maintstat) {
+#ifdef FANCY_ALARM
+ if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) {
+ __t4_set_led(wc, x, WC_GREEN);
+ }
+ if (wc->blinktimer == 0xf) {
+ __t4_set_led(wc, x, WC_OFF);
+ }
+#else
+ if (wc->blinktimer == 160) {
+ __t4_set_led(wc, x, WC_GREEN);
+ } else if (wc->blinktimer == 480) {
+ __t4_set_led(wc, x, WC_OFF);
+ }
+#endif
+ } else {
+ /* No Alarm */
+ __t4_set_led(wc, x, WC_GREEN);
+ }
+ } else
+ __t4_set_led(wc, x, WC_OFF);
+
+ }
+#ifdef FANCY_ALARM
+ if (wc->blinktimer == 0xf) {
+ wc->blinktimer = -1;
+ wc->alarmpos++;
+ if (wc->alarmpos >= (sizeof(altab) / sizeof(altab[0])))
+ wc->alarmpos = 0;
+ }
+#else
+ if (wc->blinktimer == 480)
+ wc->blinktimer = 0;
+#endif
+}
+
+static inline void t4_framer_interrupt(struct t4 *wc, int span)
+{
+ /* Check interrupts for a given span */
+ unsigned char gis, isr0, isr1, isr2, isr3, isr4;
+ int readsize = -1;
+ struct t4_span *ts = wc->tspans[span];
+ struct zt_chan *sigchan;
+ unsigned long flags;
+
+ if (debug & DEBUG_FRAMER)
+ printk("framer interrupt span %d:%d!\n", wc->num, span + 1);
+
+ /* 1st gen cards isn't used interrupts */
+ gis = t4_framer_in(wc, span, FRMR_GIS);
+ isr0 = (gis & FRMR_GIS_ISR0) ? t4_framer_in(wc, span, FRMR_ISR0) : 0;
+ isr1 = (gis & FRMR_GIS_ISR1) ? t4_framer_in(wc, span, FRMR_ISR1) : 0;
+ isr2 = (gis & FRMR_GIS_ISR2) ? t4_framer_in(wc, span, FRMR_ISR2) : 0;
+ isr3 = (gis & FRMR_GIS_ISR3) ? t4_framer_in(wc, span, FRMR_ISR3) : 0;
+ isr4 = (gis & FRMR_GIS_ISR4) ? t4_framer_in(wc, span, FRMR_ISR4) : 0;
+
+ if (debug & DEBUG_FRAMER)
+ printk("gis: %02x, isr0: %02x, isr1: %02x, isr2: %02x, isr3: %02x, isr4: %02x\n", gis, isr0, isr1, isr2, isr3, isr4);
+
+ if (isr0)
+ t4_check_sigbits(wc, span);
+
+ if (ts->spantype == TYPE_E1) {
+ /* E1 checks */
+ if ((isr3 & 0x38) || isr2 || isr1)
+ t4_check_alarms(wc, span);
+ } else {
+ /* T1 checks */
+ if (isr2 || (isr3 & 0x08))
+ t4_check_alarms(wc, span);
+ }
+ if (!ts->span.alarms) {
+ if ((isr3 & 0x3) || (isr4 & 0xc0))
+ ts->span.timingslips++;
+
+ if (debug & DEBUG_MAIN) {
+ if (isr3 & 0x02)
+ printk("TE%d10P: RECEIVE slip NEGATIVE on span %d\n", wc->numspans, span + 1);
+ if (isr3 & 0x01)
+ printk("TE%d10P: RECEIVE slip POSITIVE on span %d\n", wc->numspans, span + 1);
+ if (isr4 & 0x80)
+ printk("TE%dXXP: TRANSMIT slip POSITIVE on span %d\n", wc->numspans, span + 1);
+ if (isr4 & 0x40)
+ printk("TE%d10P: TRANSMIT slip NEGATIVE on span %d\n", wc->numspans, span + 1);
+ }
+ } else
+ ts->span.timingslips = 0;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ /* HDLC controller checks - receive side */
+ if (!ts->sigchan) {
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return;
+ }
+
+ sigchan = ts->sigchan;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ if (isr0 & FRMR_ISR0_RME) {
+ readsize = (t4_framer_in(wc, span, FRMR_RBCH) << 8) | t4_framer_in(wc, span, FRMR_RBCL);
+ if (debug & DEBUG_FRAMER) printk("Received data length is %d (%d)\n", readsize, readsize & FRMR_RBCL_MAX_SIZE);
+ /* RPF isn't set on last part of frame */
+ if ((readsize > 0) && ((readsize &= FRMR_RBCL_MAX_SIZE) == 0))
+ readsize = 32;
+ } else if (isr0 & FRMR_ISR0_RPF)
+ readsize = 32;
+
+ if (readsize > 0) {
+ int i;
+ unsigned char readbuf[readsize];
+
+ if (debug & DEBUG_FRAMER) printk("Framer %d: Got RPF/RME! readsize is %d\n", sigchan->span->offset, readsize);
+
+ for (i = 0; i < readsize; i++)
+ readbuf[i] = t4_framer_in(wc, span, FRMR_RXFIFO);
+
+ /* Tell the framer to clear the RFIFO */
+ t4_framer_cmd_wait(wc, span, FRMR_CMDR_RMC);
+
+ if (debug & DEBUG_FRAMER) {
+ printk("RX(");
+ for (i = 0; i < readsize; i++)
+ printk((i ? " %02x" : "%02x"), readbuf[i]);
+ printk(")\n");
+ }
+
+ if (isr0 & FRMR_ISR0_RME) {
+ /* Do checks for HDLC problems */
+ unsigned char rsis = readbuf[readsize-1];
+#if 0
+ unsigned int olddebug = debug;
+#endif
+ unsigned char rsis_reg = t4_framer_in(wc, span, FRMR_RSIS);
+
+#if 0
+ if ((rsis != 0xA2) || (rsis != rsis_reg))
+ debug |= DEBUG_FRAMER;
+#endif
+
+ ++ts->frames_in;
+ if ((debug & DEBUG_FRAMER) && !(ts->frames_in & 0x0f))
+ printk("Received %d frames on span %d\n", ts->frames_in, span);
+ if (debug & DEBUG_FRAMER) printk("Received HDLC frame %d. RSIS = 0x%x (%x)\n", ts->frames_in, rsis, rsis_reg);
+ if (!(rsis & FRMR_RSIS_CRC16)) {
+ if (debug & DEBUG_FRAMER) printk("CRC check failed %d\n", span);
+ zt_hdlc_abort(sigchan, ZT_EVENT_BADFCS);
+ } else if (rsis & FRMR_RSIS_RAB) {
+ if (debug & DEBUG_FRAMER) printk("ABORT of current frame due to overflow %d\n", span);
+ zt_hdlc_abort(sigchan, ZT_EVENT_ABORT);
+ } else if (rsis & FRMR_RSIS_RDO) {
+ if (debug & DEBUG_FRAMER) printk("HDLC overflow occured %d\n", span);
+ zt_hdlc_abort(sigchan, ZT_EVENT_OVERRUN);
+ } else if (!(rsis & FRMR_RSIS_VFR)) {
+ if (debug & DEBUG_FRAMER) printk("Valid Frame check failed on span %d\n", span);
+ zt_hdlc_abort(sigchan, ZT_EVENT_ABORT);
+ } else {
+ zt_hdlc_putbuf(sigchan, readbuf, readsize - 1);
+ zt_hdlc_finish(sigchan);
+ if (debug & DEBUG_FRAMER) printk("Received valid HDLC frame on span %d\n", span);
+ }
+#if 0
+ debug = olddebug;
+#endif
+ } else if (isr0 & FRMR_ISR0_RPF)
+ zt_hdlc_putbuf(sigchan, readbuf, readsize);
+ }
+
+ /* Transmit side */
+ if (isr1 & FRMR_ISR1_XDU) {
+ if (debug & DEBUG_FRAMER) printk("XDU: Resetting signal controler!\n");
+ t4_framer_cmd_wait(wc, span, FRMR_CMDR_SRES);
+ } else if (isr1 & FRMR_ISR1_XPR) {
+ if (debug & DEBUG_FRAMER)
+ printk("Sigchan %d is %p\n", sigchan->chanpos, sigchan);
+
+ if (debug & DEBUG_FRAMER) printk("Framer %d: Got XPR!\n", sigchan->span->offset);
+ t4_hdlc_xmit_fifo(wc, span, ts);
+ }
+
+ if (isr1 & FRMR_ISR1_ALLS) {
+ if (debug & DEBUG_FRAMER) printk("ALLS received\n");
+ }
+
+}
+
+#ifdef SUPPORT_GEN1
+ZAP_IRQ_HANDLER(t4_interrupt)
+{
+ struct t4 *wc = dev_id;
+ unsigned long flags;
+ int x;
+
+ unsigned int status;
+ unsigned int status2;
+
+#if 0
+ if (wc->intcount < 20)
+ printk("Pre-interrupt\n");
+#endif
+
+ /* Make sure it's really for us */
+ status = __t4_pci_in(wc, WC_INTR);
+
+ /* Process framer interrupts */
+ status2 = t4_framer_in(wc, 0, FRMR_CIS);
+ if (status2 & 0x0f) {
+ for (x = 0; x < wc->numspans; ++x) {
+ if (status2 & (1 << x))
+ t4_framer_interrupt(wc, x);
+ }
+ }
+
+ /* Ignore if it's not for us */
+ if (!status)
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+
+ __t4_pci_out(wc, WC_INTR, 0);
+
+ if (!wc->spansstarted) {
+ printk("Not prepped yet!\n");
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+ }
+
+ wc->intcount++;
+#if 0
+ if (wc->intcount < 20)
+ printk("Got interrupt, status = %08x\n", status);
+#endif
+
+ if (status & 0x3) {
+ t4_receiveprep(wc, status);
+ t4_transmitprep(wc, status);
+ }
+
+#if 0
+ if ((wc->intcount < 10) || !(wc->intcount % 1000)) {
+ status2 = t4_framer_in(wc, 0, FRMR_CIS);
+ printk("Status2: %04x\n", status2);
+ for (x = 0;x<4;x++) {
+ status2 = t4_framer_in(wc, x, FRMR_FRS0);
+ printk("FRS0/%d: %04x\n", x, status2);
+ }
+ }
+#endif
+ t4_do_counters(wc);
+
+ x = wc->intcount & 15 /* 63 */;
+ switch(x) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ t4_check_sigbits(wc, x);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ t4_check_alarms(wc, x - 4);
+ break;
+ }
+
+ spin_lock_irqsave(&wc->reglock, flags);
+
+ __handle_leds(wc);
+
+ if (test_bit(T4_CHECK_TIMING, &wc->checkflag))
+ __t4_set_timing_source_auto(wc);
+
+ spin_unlock_irqrestore(&wc->reglock, flags);
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+}
+#endif
+
+static void t4_isr_bh(unsigned long data)
+{
+ struct t4 *wc = (struct t4 *)data;
+
+#ifdef VPM_SUPPORT
+ if (wc->vpm) {
+ if (test_and_clear_bit(T4_CHECK_VPM, &wc->checkflag)) {
+ if (wc->vpm450m) {
+ /* How stupid is it that the octasic can't generate an
+ interrupt when there's a tone, in spite of what their
+ documentation says? */
+ t4_check_vpm450(wc);
+ } else
+ t4_check_vpm400(wc, wc->vpm400checkstatus);
+ }
+ }
+#endif
+}
+
+ZAP_IRQ_HANDLER(t4_interrupt_gen2)
+{
+ struct t4 *wc = dev_id;
+ unsigned int status;
+
+ /* Check this first in case we get a spurious interrupt */
+ if (unlikely(test_bit(T4_STOP_DMA, &wc->checkflag))) {
+ /* Stop DMA cleanly if requested */
+ wc->dmactrl = 0x0;
+ t4_pci_out(wc, WC_DMACTRL, 0x00000000);
+ /* Acknowledge any pending interrupts */
+ t4_pci_out(wc, WC_INTR, 0x00000000);
+ spin_lock(&wc->reglock);
+ __t4_set_timing_source(wc, 4, 0, 0);
+ spin_unlock(&wc->reglock);
+ return IRQ_RETVAL(1);
+ }
+
+ /* Make sure it's really for us */
+ status = __t4_pci_in(wc, WC_INTR);
+
+ /* Ignore if it's not for us */
+ if (!(status & 0x7)) {
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+ }
+
+#ifdef ENABLE_WORKQUEUES
+ __t4_pci_out(wc, WC_INTR, status & 0x00000008);
+#endif
+
+ if (unlikely(!wc->spansstarted)) {
+ printk("Not prepped yet!\n");
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+ }
+
+ wc->intcount++;
+
+ if (unlikely((wc->intcount < 20) && debug))
+
+ printk("2G: Got interrupt, status = %08x, CIS = %04x\n", status, t4_framer_in(wc, 0, FRMR_CIS));
+
+ if (likely(status & 0x2)) {
+#ifdef ENABLE_WORKQUEUES
+ int cpus = num_online_cpus();
+ atomic_set(&wc->worklist, wc->numspans);
+ if (wc->tspans[0]->span.flags & ZT_FLAG_RUNNING)
+ t4_queue_work(wc->workq, &wc->tspans[0]->swork, 0);
+ else
+ atomic_dec(&wc->worklist);
+ if (wc->tspans[1]->span.flags & ZT_FLAG_RUNNING)
+ t4_queue_work(wc->workq, &wc->tspans[1]->swork, 1 % cpus);
+ else
+ atomic_dec(&wc->worklist);
+ if (wc->numspans == 4) {
+ if (wc->tspans[2]->span.flags & ZT_FLAG_RUNNING)
+ t4_queue_work(wc->workq, &wc->tspans[2]->swork, 2 % cpus);
+ else
+ atomic_dec(&wc->worklist);
+ if (wc->tspans[3]->span.flags & ZT_FLAG_RUNNING)
+ t4_queue_work(wc->workq, &wc->tspans[3]->swork, 3 % cpus);
+ else
+ atomic_dec(&wc->worklist);
+ }
+#else
+ t4_prep_gen2(wc);
+#endif
+ t4_do_counters(wc);
+ spin_lock(&wc->reglock);
+ __handle_leds(wc);
+ spin_unlock(&wc->reglock);
+
+ }
+
+ if (unlikely(status & 0x1)) {
+ unsigned char cis;
+
+ cis = t4_framer_in(wc, 0, FRMR_CIS);
+ if (cis & FRMR_CIS_GIS1)
+ t4_framer_interrupt(wc, 0);
+ if (cis & FRMR_CIS_GIS2)
+ t4_framer_interrupt(wc, 1);
+ if (cis & FRMR_CIS_GIS3)
+ t4_framer_interrupt(wc, 2);
+ if (cis & FRMR_CIS_GIS4)
+ t4_framer_interrupt(wc, 3);
+ }
+
+ if (wc->vpm && vpmdtmfsupport) {
+ if (wc->vpm450m) {
+ /* How stupid is it that the octasic can't generate an
+ interrupt when there's a tone, in spite of what their
+ documentation says? */
+ if (!(wc->intcount & 0xf)) {
+ set_bit(T4_CHECK_VPM, &wc->checkflag);
+ }
+ } else if ((status & 0xff00) != 0xff00) {
+ wc->vpm400checkstatus = (status & 0xff00) >> 8;
+ set_bit(T4_CHECK_VPM, &wc->checkflag);
+ }
+ }
+
+ spin_lock(&wc->reglock);
+
+ if (unlikely(test_bit(T4_CHECK_TIMING, &wc->checkflag))) {
+ __t4_set_timing_source_auto(wc);
+ }
+
+ spin_unlock(&wc->reglock);
+
+ if (unlikely(test_bit(T4_CHECK_VPM, &wc->checkflag)))
+ tasklet_schedule(&wc->t4_tlet);
+
+#ifndef ENABLE_WORKQUEUES
+ __t4_pci_out(wc, WC_INTR, 0);
+#endif
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+}
+
+#ifdef SUPPORT_GEN1
+static int t4_reset_dma(struct t4 *wc)
+{
+ /* Turn off DMA and such */
+ wc->dmactrl = 0x0;
+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+ t4_pci_out(wc, WC_COUNT, 0);
+ t4_pci_out(wc, WC_RDADDR, 0);
+ t4_pci_out(wc, WC_WRADDR, 0);
+ t4_pci_out(wc, WC_INTR, 0);
+ /* Turn it all back on */
+ t4_pci_out(wc, WC_RDADDR, wc->readdma);
+ t4_pci_out(wc, WC_WRADDR, wc->writedma);
+ t4_pci_out(wc, WC_COUNT, ((ZT_MAX_CHUNKSIZE * 2 * 32 - 1) << 18) | ((ZT_MAX_CHUNKSIZE * 2 * 32 - 1) << 2));
+ t4_pci_out(wc, WC_INTR, 0);
+#ifdef VPM_SUPPORT
+ wc->dmactrl = 0xc0000000 | (1 << 29) | wc->vpm;
+#else
+ wc->dmactrl = 0xc0000000 | (1 << 29);
+#endif
+ if (noburst)
+ wc->dmactrl |= (1 << 26);
+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+ return 0;
+}
+#endif
+
+#ifdef VPM_SUPPORT
+static void t4_vpm_set_dtmf_threshold(struct t4 *wc, unsigned int threshold)
+{
+ unsigned int x;
+
+ for (x = 0; x < 8; x++) {
+ t4_vpm_out(wc, x, 0xC4, (threshold >> 8) & 0xFF);
+ t4_vpm_out(wc, x, 0xC5, (threshold & 0xFF));
+ }
+ printk("VPM: DTMF threshold set to %d\n", threshold);
+}
+
+static unsigned int t4_vpm_mask(int chip)
+{
+ unsigned int mask=0;
+ switch(vpmspans) {
+ case 4:
+ mask = 0x55555555 << (chip >> 2);
+ break;
+ case 2:
+ mask = 0x11111111 << (chip >> 1);
+ break;
+ case 1:
+ mask = 0x01010101 << chip;
+ break;
+ }
+ return mask;
+}
+
+static int t4_vpm_spanno(int chip)
+{
+ int spanno = 0;
+ switch(vpmspans) {
+ case 4:
+ spanno = chip & 0x3;
+ break;
+ case 2:
+ spanno = chip & 0x1;
+ break;
+ /* Case 1 is implicit */
+ }
+ return spanno;
+}
+
+static int t4_vpm_echotail(void)
+{
+ int echotail = 0x01ff;
+ switch(vpmspans) {
+ case 4:
+ echotail = 0x007f;
+ break;
+ case 2:
+ echotail = 0x00ff;
+ break;
+ /* Case 1 is implicit */
+ }
+ return echotail;
+}
+
+static void t4_vpm450_init(struct t4 *wc)
+{
+ unsigned int check1, check2;
+ int laws[4] = { 0, };
+ int x;
+ unsigned int vpm_capacity;
+ struct firmware embedded_firmware;
+ const struct firmware *firmware = &embedded_firmware;
+#if !defined(HOTPLUG_FIRMWARE)
+ extern void _binary_zaptel_fw_oct6114_064_bin_size;
+ extern void _binary_zaptel_fw_oct6114_128_bin_size;
+ extern u8 _binary_zaptel_fw_oct6114_064_bin_start[];
+ extern u8 _binary_zaptel_fw_oct6114_128_bin_start[];
+#else
+ static const char oct064_firmware[] = "zaptel-fw-oct6114-064.bin";
+ static const char oct128_firmware[] = "zaptel-fw-oct6114-128.bin";
+#endif
+
+ if (!vpmsupport) {
+ printk("VPM450: Support Disabled\n");
+ return;
+ }
+
+ /* Turn on GPIO/DATA mux if supported */
+ t4_gpio_setdir(wc, (1 << 24), (1 << 24));
+ __t4_raw_oct_out(wc, 0x000a, 0x5678);
+ __t4_raw_oct_out(wc, 0x0004, 0x1234);
+ check1 = __t4_raw_oct_in(wc, 0x0004);
+ check2 = __t4_raw_oct_in(wc, 0x000a);
+ if (debug)
+ printk("OCT Result: %04x/%04x\n", __t4_raw_oct_in(wc, 0x0004), __t4_raw_oct_in(wc, 0x000a));
+ if (__t4_raw_oct_in(wc, 0x0004) != 0x1234) {
+ printk("VPM450: Not Present\n");
+ return;
+ }
+
+ /* Setup alaw vs ulaw rules */
+ for (x = 0;x < wc->numspans; x++) {
+ if (wc->tspans[x]->span.channels > 24)
+ laws[x] = 1;
+ }
+
+ switch ((vpm_capacity = get_vpm450m_capacity(wc))) {
+ case 64:
+#if defined(HOTPLUG_FIRMWARE)
+ if ((request_firmware(&firmware, oct064_firmware, &wc->dev->dev) != 0) ||
+ !firmware) {
+ printk("VPM450: firmware %s not available from userspace\n", oct064_firmware);
+ return;
+ }
+#else
+ embedded_firmware.data = _binary_zaptel_fw_oct6114_064_bin_start;
+ /* Yes... this is weird. objcopy gives us a symbol containing
+ the size of the firmware, not a pointer a variable containing
+ the size. The only way we can get the value of the symbol
+ is to take its address, so we define it as a pointer and
+ then cast that value to the proper type.
+ */
+ embedded_firmware.size = (size_t) &_binary_zaptel_fw_oct6114_064_bin_size;
+#endif
+ break;
+ case 128:
+#if defined(HOTPLUG_FIRMWARE)
+ if ((request_firmware(&firmware, oct128_firmware, &wc->dev->dev) != 0) ||
+ !firmware) {
+ printk("VPM450: firmware %s not available from userspace\n", oct128_firmware);
+ return;
+ }
+#else
+ embedded_firmware.data = _binary_zaptel_fw_oct6114_128_bin_start;
+ /* Yes... this is weird. objcopy gives us a symbol containing
+ the size of the firmware, not a pointer a variable containing
+ the size. The only way we can get the value of the symbol
+ is to take its address, so we define it as a pointer and
+ then cast that value to the proper type.
+ */
+ embedded_firmware.size = (size_t) &_binary_zaptel_fw_oct6114_128_bin_size;
+#endif
+ break;
+ default:
+ printk("Unsupported channel capacity found on VPM module (%d).\n", vpm_capacity);
+ return;
+ }
+
+ set_bit(T4_LOADING_FW, &wc->checkflag);
+ if (!(wc->vpm450m = init_vpm450m(wc, laws, wc->numspans, firmware))) {
+ printk("VPM450: Failed to initialize\n");
+ if (firmware != &embedded_firmware)
+ release_firmware(firmware);
+ clear_bit(T4_LOADING_FW, &wc->checkflag);
+ return;
+ }
+ clear_bit(T4_LOADING_FW, &wc->checkflag);
+
+ if (firmware != &embedded_firmware)
+ release_firmware(firmware);
+
+ if (vpmdtmfsupport == -1) {
+ printk("VPM450: hardware DTMF disabled.\n");
+ vpmdtmfsupport = 0;
+ }
+
+ wc->vpm = T4_VPM_PRESENT;
+ printk("VPM450: Present and operational servicing %d span(s)\n", wc->numspans);
+
+}
+
+static void t4_vpm400_init(struct t4 *wc)
+{
+ unsigned char reg;
+ unsigned int mask;
+ unsigned int ver;
+ unsigned int i, x, y, gen2vpm=0;
+
+ if (!vpmsupport) {
+ printk("VPM400: Support Disabled\n");
+ return;
+ }
+
+ switch(vpmspans) {
+ case 4:
+ case 2:
+ case 1:
+ break;
+ default:
+ printk("VPM400: %d is not a valid vpmspans value, using 4\n", vpmspans);
+ vpmspans = 4;
+ }
+
+ for (x=0;x<8;x++) {
+ int spanno = t4_vpm_spanno(x);
+ struct t4_span *ts = wc->tspans[spanno];
+ int echotail = t4_vpm_echotail();
+
+ ver = t4_vpm_in(wc, x, 0x1a0); /* revision */
+ if ((ver != 0x26) && (ver != 0x33)) {
+ printk("VPM400: %s\n", x ? "Inoperable" : "Not Present");
+ return;
+ }
+ if (ver == 0x33) {
+ if (x && !gen2vpm) {
+ printk("VPM400: Inconsistent\n");
+ return;
+ }
+ ts->spanflags |= FLAG_VPM2GEN;
+ gen2vpm++;
+ } else if (gen2vpm) {
+ printk("VPM400: Inconsistent\n");
+ return;
+ }
+
+
+ /* Setup GPIO's */
+ for (y=0;y<4;y++) {
+ t4_vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */
+ t4_vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */
+ t4_vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */
+ }
+
+ /* Setup TDM path - sets fsync and tdm_clk as inputs */
+ reg = t4_vpm_in(wc, x, 0x1a3); /* misc_con */
+ t4_vpm_out(wc, x, 0x1a3, reg & ~2);
+
+ /* Setup timeslots */
+ t4_vpm_out(wc, x, 0x02f, 0x20 | (spanno << 3));
+
+ /* Setup Echo length (128 taps) */
+ t4_vpm_out(wc, x, 0x022, (echotail >> 8));
+ t4_vpm_out(wc, x, 0x023, (echotail & 0xff));
+
+ /* Setup the tdm channel masks for all chips*/
+ mask = t4_vpm_mask(x);
+ for (i = 0; i < 4; i++)
+ t4_vpm_out(wc, x, 0x30 + i, (mask >> (i << 3)) & 0xff);
+
+ /* Setup convergence rate */
+ reg = t4_vpm_in(wc,x,0x20);
+ reg &= 0xE0;
+ if (ts->spantype == TYPE_E1) {
+ if (x < vpmspans)
+ printk("VPM400: Span %d A-law mode\n", spanno);
+ reg |= 0x01;
+ } else {
+ if (x < vpmspans)
+ printk("VPM400: Span %d U-law mode\n", spanno);
+ reg &= ~0x01;
+ }
+ t4_vpm_out(wc,x,0x20,(reg | 0x20));
+
+ /* Initialize echo cans */
+ for (i = 0 ; i < MAX_TDM_CHAN; i++) {
+ if (mask & (0x00000001 << i))
+ t4_vpm_out(wc,x,i,0x00);
+ }
+
+ wait_a_little();
+
+ /* Put in bypass mode */
+ for (i = 0 ; i < MAX_TDM_CHAN ; i++) {
+ if (mask & (0x00000001 << i)) {
+ t4_vpm_out(wc,x,i,0x01);
+ }
+ }
+
+ /* Enable bypass */
+ for (i = 0 ; i < MAX_TDM_CHAN ; i++) {
+ if (mask & (0x00000001 << i))
+ t4_vpm_out(wc,x,0x78 + i,0x01);
+ }
+
+ /* set DTMF detection threshold */
+ t4_vpm_set_dtmf_threshold(wc, dtmfthreshold);
+
+ /* Enable DTMF detectors (always DTMF detect all spans) */
+ for (i = 0; i < MAX_DTMF_DET; i++) {
+ t4_vpm_out(wc, x, 0x98 + i, 0x40 | (i * 2) | ((x < 4) ? 0 : 1));
+ }
+ for (i = 0x34; i < 0x38; i++)
+ t4_vpm_out(wc, x, i, 0x00);
+ for (i = 0x3C; i < 0x40; i++)
+ t4_vpm_out(wc, x, i, 0x00);
+
+ for (i = 0x48; i < 0x4B; i++)
+ t4_vpm_out(wc, x, i, 0x00);
+ for (i = 0x50; i < 0x53; i++)
+ t4_vpm_out(wc, x, i, 0x00);
+ for (i = 0xB8; i < 0xBE; i++)
+ t4_vpm_out(wc, x, i, 0xFF);
+ if (gen2vpm) {
+ for (i = 0xBE; i < 0xC0; i++)
+ t4_vpm_out(wc, x, i, 0xFF);
+ } else {
+ for (i = 0xBE; i < 0xC0; i++)
+ t4_vpm_out(wc, x, i, 0x00);
+ }
+ for (i = 0xC0; i < 0xC4; i++)
+ t4_vpm_out(wc, x, i, (x < 4) ? 0x55 : 0xAA);
+
+ }
+ if (vpmdtmfsupport == -1) {
+ printk("VPM400: hardware DTMF enabled.\n");
+ vpmdtmfsupport = 0;
+ }
+ printk("VPM400%s: Present and operational servicing %d span(s)\n", (gen2vpm ? " (2nd Gen)" : ""), wc->numspans);
+ wc->vpm = T4_VPM_PRESENT;
+}
+
+#endif
+
+static void t4_tsi_reset(struct t4 *wc)
+{
+ int x;
+ for (x=0;x<128;x++) {
+ wc->dmactrl &= ~0x00007fff;
+ wc->dmactrl |= (0x00004000 | (x << 7));
+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+ }
+ wc->dmactrl &= ~0x00007fff;
+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+}
+
+/* Note that channels here start from 1 */
+static void t4_tsi_assign(struct t4 *wc, int fromspan, int fromchan, int tospan, int tochan)
+{
+ unsigned long flags;
+ int fromts, tots;
+
+ fromts = (fromspan << 5) |(fromchan);
+ tots = (tospan << 5) | (tochan);
+
+ if (!wc->t1e1) {
+ fromts += 4;
+ tots += 4;
+ }
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->dmactrl &= ~0x00007fff;
+ wc->dmactrl |= (0x00004000 | (tots << 7) | (fromts));
+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+ wc->dmactrl &= ~0x00007fff;
+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static void t4_tsi_unassign(struct t4 *wc, int tospan, int tochan)
+{
+ unsigned long flags;
+ int tots;
+
+ tots = (tospan << 5) | (tochan);
+
+ if (!wc->t1e1)
+ tots += 4;
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->dmactrl &= ~0x00007fff;
+ wc->dmactrl |= (0x00004000 | (tots << 7));
+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+ if (debug & DEBUG_TSI)
+ printk("Sending '%08x\n", wc->dmactrl);
+ wc->dmactrl &= ~0x00007fff;
+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags)
+{
+ unsigned int version;
+
+ version = t4_pci_in(wc, WC_VERSION);
+ printk("TE%dXXP version %08x, burst %s\n", wc->numspans, version, (!(cardflags & FLAG_BURST) && noburst) ? "OFF" : "ON");
+#ifdef ENABLE_WORKQUEUES
+ printk("TE%dXXP running with work queues.\n", wc->numspans);
+#endif
+
+ /* Make sure DMA engine is not running and interrupts are acknowledged */
+ wc->dmactrl = 0x0;
+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+ /* Reset Framer and friends */
+ t4_pci_out(wc, WC_LEDS, 0x00000000);
+
+ /* Set DMA addresses */
+ t4_pci_out(wc, WC_RDADDR, wc->readdma);
+ t4_pci_out(wc, WC_WRADDR, wc->writedma);
+
+ /* Setup counters, interrupt flags (ignored in Gen2) */
+ if (cardflags & FLAG_2NDGEN) {
+ t4_tsi_reset(wc);
+ } else {
+ t4_pci_out(wc, WC_COUNT, ((ZT_MAX_CHUNKSIZE * 2 * 32 - 1) << 18) | ((ZT_MAX_CHUNKSIZE * 2 * 32 - 1) << 2));
+ }
+
+ /* Reset pending interrupts */
+ t4_pci_out(wc, WC_INTR, 0x00000000);
+
+ /* Read T1/E1 status */
+ if (t1e1override > -1)
+ wc->t1e1 = t1e1override;
+ else
+ wc->t1e1 = ((t4_pci_in(wc, WC_LEDS)) & 0x0f00) >> 8;
+ wc->order = ((t4_pci_in(wc, WC_LEDS)) & 0xf0000000) >> 28;
+ order_index[wc->order]++;
+ return 0;
+}
+
+static int t4_hardware_init_2(struct t4 *wc)
+{
+ int x;
+ unsigned int falcver;
+
+ if (t4_pci_in(wc, WC_VERSION) >= 0xc01a0165) {
+ wc->tspans[0]->spanflags |= FLAG_OCTOPT;
+ printk("Octasic optimized!\n");
+ }
+ /* Setup LEDS, take out of reset */
+ t4_pci_out(wc, WC_LEDS, 0x000000ff);
+ t4_activate(wc);
+
+ t4_framer_out(wc, 0, 0x4a, 0xaa);
+ falcver = t4_framer_in(wc, 0 ,0x4a);
+ printk("FALC version: %08x, Board ID: %02x\n", falcver, wc->order);
+
+ for (x=0;x< 11;x++)
+ printk("Reg %d: 0x%08x\n", x, t4_pci_in(wc, x));
+ return 0;
+}
+
+static int __devinit t4_launch(struct t4 *wc)
+{
+ int x;
+ unsigned long flags;
+ if (wc->tspans[0]->span.flags & ZT_FLAG_REGISTERED)
+ return 0;
+ printk("TE%dXXP: Launching card: %d\n", wc->numspans, wc->order);
+
+ /* Setup serial parameters and system interface */
+ for (x=0;x<4;x++)
+ t4_serial_setup(wc, x);
+
+ if (zt_register(&wc->tspans[0]->span, 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", wc->tspans[0]->span.name);
+ return -1;
+ }
+ if (zt_register(&wc->tspans[1]->span, 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", wc->tspans[1]->span.name);
+ zt_unregister(&wc->tspans[0]->span);
+ return -1;
+ }
+
+ if (wc->numspans == 4) {
+ if (zt_register(&wc->tspans[2]->span, 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", wc->tspans[2]->span.name);
+ zt_unregister(&wc->tspans[0]->span);
+ zt_unregister(&wc->tspans[1]->span);
+ return -1;
+ }
+ if (zt_register(&wc->tspans[3]->span, 0)) {
+ printk(KERN_ERR "Unable to register span %s\n", wc->tspans[3]->span.name);
+ zt_unregister(&wc->tspans[0]->span);
+ zt_unregister(&wc->tspans[1]->span);
+ zt_unregister(&wc->tspans[2]->span);
+ return -1;
+ }
+ }
+ set_bit(T4_CHECK_TIMING, &wc->checkflag);
+ spin_lock_irqsave(&wc->reglock, flags);
+ __t4_set_timing_source(wc,4, 0, 0);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc);
+ return 0;
+}
+
+static int __devinit t4_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int res;
+ struct t4 *wc;
+ struct devtype *dt;
+ int x,f;
+ int basesize;
+#if 0
+ int y;
+ unsigned int *canary;
+#endif
+
+
+ if (pci_enable_device(pdev)) {
+ res = -EIO;
+ } else {
+ wc = kmalloc(sizeof(struct t4), GFP_KERNEL);
+ if (wc) {
+ memset(wc, 0x0, sizeof(struct t4));
+ spin_lock_init(&wc->reglock);
+ dt = (struct devtype *)(ent->driver_data);
+ if (dt->flags & FLAG_2NDGEN)
+ basesize = ZT_MAX_CHUNKSIZE * 32 * 4;
+ else
+ basesize = ZT_MAX_CHUNKSIZE * 32 * 2 * 4;
+
+ if (dt->flags & FLAG_2PORT)
+ wc->numspans = 2;
+ else
+ wc->numspans = 4;
+
+ wc->variety = dt->desc;
+
+ wc->memaddr = pci_resource_start(pdev, 0);
+ wc->memlen = pci_resource_len(pdev, 0);
+ wc->membase = ioremap(wc->memaddr, wc->memlen);
+ /* This rids of the Double missed interrupt message after loading */
+ wc->last0 = 1;
+#if 0
+ if (!request_mem_region(wc->memaddr, wc->memlen, wc->variety))
+ printk("wct4: Unable to request memory region :(, using anyway...\n");
+#endif
+ if (pci_request_regions(pdev, wc->variety))
+ printk("wct%dxxp: Unable to request regions\n", wc->numspans);
+
+ printk("Found TE%dXXP at base address %08lx, remapped to %p\n", wc->numspans, wc->memaddr, wc->membase);
+
+ wc->dev = pdev;
+
+ wc->writechunk =
+ /* 32 channels, Double-buffer, Read/Write, 4 spans */
+ (unsigned int *)pci_alloc_consistent(pdev, basesize * 2, &wc->writedma);
+ if (!wc->writechunk) {
+ printk("wct%dxxp: Unable to allocate DMA-able memory\n", wc->numspans);
+ return -ENOMEM;
+ }
+
+ /* Read is after the whole write piece (in words) */
+ wc->readchunk = wc->writechunk + basesize / 4;
+
+ /* Same thing but in bytes... */
+ wc->readdma = wc->writedma + basesize;
+
+ /* Initialize Write/Buffers to all blank data */
+ memset((void *)wc->writechunk,0x00, basesize);
+ memset((void *)wc->readchunk,0xff, basesize);
+#if 0
+ memset((void *)wc->readchunk,0xff,ZT_MAX_CHUNKSIZE * 2 * 32 * 4);
+ /* Initialize canary */
+ canary = (unsigned int *)(wc->readchunk + ZT_CHUNKSIZE * 64 * 4 - 4);
+ *canary = (CANARY << 16) | (0xffff);
+#endif
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, wc);
+
+ /* Initialize hardware */
+ t4_hardware_init_1(wc, dt->flags);
+
+ for(x = 0; x < MAX_T4_CARDS; x++) {
+ if (!cards[x]) break;
+ }
+
+ if (x >= MAX_T4_CARDS) {
+ printk("No cards[] slot available!!\n");
+ return -ENOMEM;
+ }
+
+ wc->num = x;
+ cards[x] = wc;
+
+
+#ifdef ENABLE_WORKQUEUES
+ if (dt->flags & FLAG_2NDGEN) {
+ char tmp[20];
+ sprintf(tmp, "te%dxxp[%d]", wc->numspans, wc->num);
+ wc->workq = create_workqueue(tmp);
+ }
+#endif
+
+ /* Allocate pieces we need here */
+ for (x=0;x<4;x++) {
+ if (wc->t1e1 & (1 << x)) {
+ wc->tspans[x] = kmalloc(sizeof(struct t4_span) + sizeof(struct zt_chan) * 31, GFP_KERNEL);
+ if (wc->tspans[x]) {
+ memset(wc->tspans[x], 0, sizeof(struct t4_span) + sizeof(struct zt_chan) * 31);
+ wc->tspans[x]->spantype = TYPE_E1;
+ }
+ } else {
+ wc->tspans[x] = kmalloc(sizeof(struct t4_span) + sizeof(struct zt_chan) * 24, GFP_KERNEL);
+ if (wc->tspans[x]) {
+ memset(wc->tspans[x], 0, sizeof(struct t4_span) + sizeof(struct zt_chan) * 24);
+ if (j1mode)
+ wc->tspans[x]->spantype = TYPE_J1;
+ else
+ wc->tspans[x]->spantype = TYPE_T1;
+ }
+ }
+ if (!wc->tspans[x])
+ return -ENOMEM;
+#ifdef ENABLE_WORKQUEUES
+ INIT_WORK(&wc->tspans[x]->swork, workq_handlespan, wc->tspans[x]);
+#endif
+ wc->tspans[x]->spanflags |= dt->flags;
+ }
+
+
+ /* Continue hardware intiialization */
+ t4_hardware_init_2(wc);
+
+
+#ifdef SUPPORT_GEN1
+ if (request_irq(pdev->irq, (dt->flags & FLAG_2NDGEN) ? t4_interrupt_gen2 :t4_interrupt, ZAP_IRQ_SHARED_DISABLED, (wc->numspans == 2) ? "wct2xxp" : "wct4xxp", wc))
+#else
+ if (!(wc->tspans[0]->spanflags & FLAG_2NDGEN)) {
+ printk("This driver does not support 1st gen modules\n");
+ kfree(wc);
+ return -ENODEV;
+ }
+ if (request_irq(pdev->irq, t4_interrupt_gen2, ZAP_IRQ_SHARED_DISABLED, "t4xxp", wc))
+#endif
+ {
+ printk("t4xxp: Unable to request IRQ %d\n", pdev->irq);
+ kfree(wc);
+ return -EIO;
+ }
+
+ init_spans(wc);
+
+ /* Launch cards as appropriate */
+ for (;;) {
+ /* Find a card to activate */
+ f = 0;
+ for (x=0;cards[x];x++) {
+ if (cards[x]->order <= highestorder) {
+ t4_launch(cards[x]);
+ if (cards[x]->order == highestorder)
+ f = 1;
+ }
+ }
+ /* If we found at least one, increment the highest order and search again, otherwise stop */
+ if (f)
+ highestorder++;
+ else
+ break;
+ }
+
+ printk("Found a Wildcard: %s\n", wc->variety);
+ wc->gpio = 0x00000000;
+ t4_pci_out(wc, WC_GPIO, wc->gpio);
+ t4_gpio_setdir(wc, (1 << 17), (1 << 17));
+ t4_gpio_setdir(wc, (0xff), (0xff));
+
+#if 0
+ for (x=0;x<0x10000;x++) {
+ __t4_raw_oct_out(wc, 0x0004, x);
+ __t4_raw_oct_out(wc, 0x000a, x ^ 0xffff);
+ if (__t4_raw_oct_in(wc, 0x0004) != x)
+ printk("Register 4 failed %04x\n", x);
+ if (__t4_raw_oct_in(wc, 0x000a) != (x ^ 0xffff))
+ printk("Register 10 failed %04x\n", x);
+ }
+#endif
+ res = 0;
+ } else
+ res = -ENOMEM;
+ }
+ return res;
+}
+
+static int t4_hardware_stop(struct t4 *wc)
+{
+
+ /* Turn off DMA, leave interrupts enabled */
+ set_bit(T4_STOP_DMA, &wc->checkflag);
+
+ /* Wait for interrupts to stop */
+ msleep(25);
+
+ /* Turn off counter, address, etc */
+ if (wc->tspans[0]->spanflags & FLAG_2NDGEN) {
+ t4_tsi_reset(wc);
+ } else {
+ t4_pci_out(wc, WC_COUNT, 0x000000);
+ }
+ t4_pci_out(wc, WC_RDADDR, 0x0000000);
+ t4_pci_out(wc, WC_WRADDR, 0x0000000);
+ wc->gpio = 0x00000000;
+ t4_pci_out(wc, WC_GPIO, wc->gpio);
+ t4_pci_out(wc, WC_LEDS, 0x00000000);
+
+ printk("\nStopped TE%dXXP, Turned off DMA\n", wc->numspans);
+ return 0;
+}
+
+static void __devexit t4_remove_one(struct pci_dev *pdev)
+{
+ struct t4 *wc = pci_get_drvdata(pdev);
+ int x;
+ if (wc) {
+ /* Stop hardware */
+ t4_hardware_stop(wc);
+
+ /* Release vpm450m */
+ if (wc->vpm450m)
+ release_vpm450m(wc->vpm450m);
+ wc->vpm450m = NULL;
+ /* Unregister spans */
+ if (wc->tspans[0]->span.flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&wc->tspans[0]->span);
+ if (wc->tspans[1]->span.flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&wc->tspans[1]->span);
+ if (wc->numspans == 4) {
+ if (wc->tspans[2]->span.flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&wc->tspans[2]->span);
+ if (wc->tspans[3]->span.flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&wc->tspans[3]->span);
+ }
+#ifdef ENABLE_WORKQUEUES
+ if (wc->workq) {
+ flush_workqueue(wc->workq);
+ destroy_workqueue(wc->workq);
+ }
+#endif
+
+ free_irq(pdev->irq, wc);
+
+ if (wc->membase)
+ iounmap((void *)wc->membase);
+
+ pci_release_regions(pdev);
+
+ /* Immediately free resources */
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 32 * 4, (void *)wc->writechunk, wc->writedma);
+
+ order_index[wc->order]--;
+
+ cards[wc->num] = NULL;
+ pci_set_drvdata(pdev, NULL);
+ for (x=0;x<wc->numspans;x++) {
+ if (wc->tspans[x])
+ kfree(wc->tspans[x]);
+ }
+ kfree(wc);
+ }
+}
+
+
+static struct pci_device_id t4_pci_tbl[] __devinitdata =
+{
+ { 0x10ee, 0x0314, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct4xxp },
+
+ { 0xd161, 0x0420, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct420p4 },
+ { 0xd161, 0x0410, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct410p4 },
+ { 0xd161, 0x0405, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct405p4 },
+ { 0xd161, 0x0410, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct410p3 },
+ { 0xd161, 0x0405, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct405p3 },
+ { 0xd161, 0x0410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct410p2 },
+ { 0xd161, 0x0405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct405p2 },
+
+ { 0xd161, 0x0220, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct220p4 },
+ { 0xd161, 0x0205, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct205p4 },
+ { 0xd161, 0x0210, 0x0004, PCI_ANY_ID, 0, 0, (unsigned long)&wct210p4 },
+ { 0xd161, 0x0205, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct205p3 },
+ { 0xd161, 0x0210, 0x0003, PCI_ANY_ID, 0, 0, (unsigned long)&wct210p3 },
+ { 0xd161, 0x0205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct205 },
+ { 0xd161, 0x0210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct210 },
+ { 0, }
+};
+
+static struct pci_driver t4_driver = {
+ name: "wct4xxp",
+ probe: t4_init_one,
+#ifdef LINUX26
+ remove: __devexit_p(t4_remove_one),
+#else
+ remove: t4_remove_one,
+#endif
+ suspend: NULL,
+ resume: NULL,
+ id_table: t4_pci_tbl,
+};
+
+static int __init t4_init(void)
+{
+ int res;
+ res = zap_pci_module(&t4_driver);
+ if (res)
+ return -ENODEV;
+ return 0;
+}
+
+static void __exit t4_cleanup(void)
+{
+ pci_unregister_driver(&t4_driver);
+}
+
+
+MODULE_AUTHOR("Mark Spencer");
+MODULE_DESCRIPTION("Unified TE4XXP-TE2XXP PCI Driver");
+#if defined(MODULE_ALIAS)
+MODULE_ALIAS("wct2xxp");
+#endif
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef LINUX26
+module_param(pedanticpci, int, 0600);
+module_param(debug, int, 0600);
+module_param(loopback, int, 0600);
+module_param(noburst, int, 0600);
+module_param(timingcable, int, 0600);
+module_param(t1e1override, int, 0600);
+module_param(alarmdebounce, int, 0600);
+module_param(j1mode, int, 0600);
+module_param(sigmode, int, 0600);
+#ifdef VPM_SUPPORT
+module_param(vpmsupport, int, 0600);
+module_param(vpmdtmfsupport, int, 0600);
+module_param(vpmspans, int, 0600);
+module_param(dtmfthreshold, int, 0600);
+#endif
+#else
+MODULE_PARM(pedanticpci, "i");
+MODULE_PARM(debug, "i");
+MODULE_PARM(loopback, "i");
+MODULE_PARM(noburst, "i");
+MODULE_PARM(hardhdlcmode, "i");
+MODULE_PARM(timingcable, "i");
+MODULE_PARM(t1e1override, "i");
+MODULE_PARM(alarmdebounce, "i");
+MODULE_PARM(j1mode, "i");
+MODULE_PARM(sigmode, "i");
+#ifdef VPM_SUPPORT
+MODULE_PARM(vpmsupport, "i");
+MODULE_PARM(vpmdtmfsupport, "i");
+MODULE_PARM(vpmspans, "i");
+MODULE_PARM(dtmfthreshold, "i");
+#endif
+#endif
+
+MODULE_DEVICE_TABLE(pci, t4_pci_tbl);
+
+module_init(t4_init);
+module_exit(t4_cleanup);
diff --git a/drivers/dahdi/wct4xxp/vpm450m.c b/drivers/dahdi/wct4xxp/vpm450m.c
new file mode 100644
index 0000000..674dd49
--- /dev/null
+++ b/drivers/dahdi/wct4xxp/vpm450m.c
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2005-2006 Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * All Rights Reserved
+ */
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/version.h>
+
+#include "vpm450m.h"
+#include "oct6100api/oct6100_api.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#include <linux/config.h>
+#else
+#include <linux/autoconf.h>
+#endif
+
+/* API for Octasic access */
+UINT32 Oct6100UserGetTime(tPOCT6100_GET_TIME f_pTime)
+{
+ /* Why couldn't they just take a timeval like everyone else? */
+ struct timeval tv;
+ unsigned long long total_usecs;
+ unsigned int mask = ~0;
+
+ do_gettimeofday(&tv);
+ total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) +
+ (((unsigned long long)(tv.tv_usec)));
+ f_pTime->aulWallTimeUs[0] = (total_usecs & mask);
+ f_pTime->aulWallTimeUs[1] = (total_usecs >> 32);
+ return cOCT6100_ERR_OK;
+}
+
+UINT32 Oct6100UserMemSet(PVOID f_pAddress, UINT32 f_ulPattern, UINT32 f_ulLength)
+{
+ memset(f_pAddress, f_ulPattern, f_ulLength);
+ return cOCT6100_ERR_OK;
+}
+
+UINT32 Oct6100UserMemCopy(PVOID f_pDestination, const void *f_pSource, UINT32 f_ulLength)
+{
+ memcpy(f_pDestination, f_pSource, f_ulLength);
+ return cOCT6100_ERR_OK;
+}
+
+UINT32 Oct6100UserCreateSerializeObject(tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate)
+{
+ return cOCT6100_ERR_OK;
+}
+
+UINT32 Oct6100UserDestroySerializeObject(tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy)
+{
+#ifdef OCTASIC_DEBUG
+ printk("I should never be called! (destroy serialize object)\n");
+#endif
+ return cOCT6100_ERR_OK;
+}
+
+UINT32 Oct6100UserSeizeSerializeObject(tPOCT6100_SEIZE_SERIALIZE_OBJECT f_pSeize)
+{
+ /* Not needed */
+ return cOCT6100_ERR_OK;
+}
+
+UINT32 Oct6100UserReleaseSerializeObject(tPOCT6100_RELEASE_SERIALIZE_OBJECT f_pRelease)
+{
+ /* Not needed */
+ return cOCT6100_ERR_OK;
+}
+
+UINT32 Oct6100UserDriverWriteApi(tPOCT6100_WRITE_PARAMS f_pWriteParams)
+{
+ oct_set_reg(f_pWriteParams->pProcessContext, f_pWriteParams->ulWriteAddress, f_pWriteParams->usWriteData);
+ return cOCT6100_ERR_OK;
+}
+
+UINT32 Oct6100UserDriverWriteSmearApi(tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams)
+{
+ unsigned int x;
+ for (x=0;x<f_pSmearParams->ulWriteLength;x++) {
+ oct_set_reg(f_pSmearParams->pProcessContext, f_pSmearParams->ulWriteAddress + (x << 1), f_pSmearParams->usWriteData);
+ }
+ return cOCT6100_ERR_OK;
+}
+
+UINT32 Oct6100UserDriverWriteBurstApi(tPOCT6100_WRITE_BURST_PARAMS f_pBurstParams)
+{
+ unsigned int x;
+ for (x=0;x<f_pBurstParams->ulWriteLength;x++) {
+ oct_set_reg(f_pBurstParams->pProcessContext, f_pBurstParams->ulWriteAddress + (x << 1), f_pBurstParams->pusWriteData[x]);
+ }
+ return cOCT6100_ERR_OK;
+}
+
+UINT32 Oct6100UserDriverReadApi(tPOCT6100_READ_PARAMS f_pReadParams)
+{
+ *(f_pReadParams->pusReadData) = oct_get_reg(f_pReadParams->pProcessContext, f_pReadParams->ulReadAddress);
+ return cOCT6100_ERR_OK;
+}
+
+UINT32 Oct6100UserDriverReadBurstApi(tPOCT6100_READ_BURST_PARAMS f_pBurstParams)
+{
+ unsigned int x;
+ for (x=0;x<f_pBurstParams->ulReadLength;x++) {
+ f_pBurstParams->pusReadData[x] = oct_get_reg(f_pBurstParams->pProcessContext, f_pBurstParams->ulReadAddress + (x << 1));
+ }
+ return cOCT6100_ERR_OK;
+}
+
+#define SOUT_G168_1100GB_ON 0x40000004
+#define SOUT_DTMF_1 0x40000011
+#define SOUT_DTMF_2 0x40000012
+#define SOUT_DTMF_3 0x40000013
+#define SOUT_DTMF_A 0x4000001A
+#define SOUT_DTMF_4 0x40000014
+#define SOUT_DTMF_5 0x40000015
+#define SOUT_DTMF_6 0x40000016
+#define SOUT_DTMF_B 0x4000001B
+#define SOUT_DTMF_7 0x40000017
+#define SOUT_DTMF_8 0x40000018
+#define SOUT_DTMF_9 0x40000019
+#define SOUT_DTMF_C 0x4000001C
+#define SOUT_DTMF_STAR 0x4000001E
+#define SOUT_DTMF_0 0x40000010
+#define SOUT_DTMF_POUND 0x4000001F
+#define SOUT_DTMF_D 0x4000001D
+
+#define ROUT_G168_2100GB_ON 0x10000000
+#define ROUT_G168_2100GB_WSPR 0x10000002
+#define ROUT_SOUT_G168_2100HB_END 0x50000003
+#define ROUT_G168_1100GB_ON 0x10000004
+
+#define ROUT_DTMF_1 0x10000011
+#define ROUT_DTMF_2 0x10000012
+#define ROUT_DTMF_3 0x10000013
+#define ROUT_DTMF_A 0x1000001A
+#define ROUT_DTMF_4 0x10000014
+#define ROUT_DTMF_5 0x10000015
+#define ROUT_DTMF_6 0x10000016
+#define ROUT_DTMF_B 0x1000001B
+#define ROUT_DTMF_7 0x10000017
+#define ROUT_DTMF_8 0x10000018
+#define ROUT_DTMF_9 0x10000019
+#define ROUT_DTMF_C 0x1000001C
+#define ROUT_DTMF_STAR 0x1000001E
+#define ROUT_DTMF_0 0x10000010
+#define ROUT_DTMF_POUND 0x1000001F
+#define ROUT_DTMF_D 0x1000001D
+
+#if 0
+#define cOCT6100_ECHO_OP_MODE_DIGITAL cOCT6100_ECHO_OP_MODE_HT_FREEZE
+#else
+#define cOCT6100_ECHO_OP_MODE_DIGITAL cOCT6100_ECHO_OP_MODE_POWER_DOWN
+#endif
+
+struct vpm450m {
+ tPOCT6100_INSTANCE_API pApiInstance;
+ UINT32 aulEchoChanHndl[ 128 ];
+ int chanflags[128];
+ int ecmode[128];
+ int numchans;
+};
+
+#define FLAG_DTMF (1 << 0)
+#define FLAG_MUTE (1 << 1)
+#define FLAG_ECHO (1 << 2)
+
+static unsigned int tones[] = {
+ SOUT_DTMF_1,
+ SOUT_DTMF_2,
+ SOUT_DTMF_3,
+ SOUT_DTMF_A,
+ SOUT_DTMF_4,
+ SOUT_DTMF_5,
+ SOUT_DTMF_6,
+ SOUT_DTMF_B,
+ SOUT_DTMF_7,
+ SOUT_DTMF_8,
+ SOUT_DTMF_9,
+ SOUT_DTMF_C,
+ SOUT_DTMF_STAR,
+ SOUT_DTMF_0,
+ SOUT_DTMF_POUND,
+ SOUT_DTMF_D,
+ SOUT_G168_1100GB_ON,
+
+ ROUT_DTMF_1,
+ ROUT_DTMF_2,
+ ROUT_DTMF_3,
+ ROUT_DTMF_A,
+ ROUT_DTMF_4,
+ ROUT_DTMF_5,
+ ROUT_DTMF_6,
+ ROUT_DTMF_B,
+ ROUT_DTMF_7,
+ ROUT_DTMF_8,
+ ROUT_DTMF_9,
+ ROUT_DTMF_C,
+ ROUT_DTMF_STAR,
+ ROUT_DTMF_0,
+ ROUT_DTMF_POUND,
+ ROUT_DTMF_D,
+ ROUT_G168_1100GB_ON,
+};
+
+static void vpm450m_setecmode(struct vpm450m *vpm450m, int channel, int mode)
+{
+ tOCT6100_CHANNEL_MODIFY *modify;
+ UINT32 ulResult;
+
+ if (vpm450m->ecmode[channel] == mode)
+ return;
+ modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC);
+ if (!modify) {
+ printk("wct4xxp: Unable to allocate memory for setec!\n");
+ return;
+ }
+ Oct6100ChannelModifyDef(modify);
+ modify->ulEchoOperationMode = mode;
+ modify->ulChannelHndl = vpm450m->aulEchoChanHndl[channel];
+ ulResult = Oct6100ChannelModify(vpm450m->pApiInstance, modify);
+ if (ulResult != GENERIC_OK) {
+ printk("Failed to apply echo can changes on channel %d!\n", channel);
+ } else {
+#ifdef OCTASIC_DEBUG
+ printk("Echo can on channel %d set to %d\n", channel, mode);
+#endif
+ vpm450m->ecmode[channel] = mode;
+ }
+ kfree(modify);
+}
+
+void vpm450m_setdtmf(struct vpm450m *vpm450m, int channel, int detect, int mute)
+{
+ tOCT6100_CHANNEL_MODIFY *modify;
+ UINT32 ulResult;
+
+ modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_KERNEL);
+ if (!modify) {
+ printk("wct4xxp: Unable to allocate memory for setdtmf!\n");
+ return;
+ }
+ Oct6100ChannelModifyDef(modify);
+ modify->ulChannelHndl = vpm450m->aulEchoChanHndl[channel];
+ if (mute) {
+ vpm450m->chanflags[channel] |= FLAG_MUTE;
+ modify->VqeConfig.fDtmfToneRemoval = TRUE;
+ } else {
+ vpm450m->chanflags[channel] &= ~FLAG_MUTE;
+ modify->VqeConfig.fDtmfToneRemoval = FALSE;
+ }
+ if (detect)
+ vpm450m->chanflags[channel] |= FLAG_DTMF;
+ else
+ vpm450m->chanflags[channel] &= ~FLAG_DTMF;
+ if (vpm450m->chanflags[channel] & (FLAG_DTMF|FLAG_MUTE)) {
+ if (!(vpm450m->chanflags[channel] & FLAG_ECHO)) {
+ vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_RESET);
+ vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_FREEZE);
+ }
+ } else {
+ if (!(vpm450m->chanflags[channel] & FLAG_ECHO))
+ vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_DIGITAL);
+ }
+
+ ulResult = Oct6100ChannelModify(vpm450m->pApiInstance, modify);
+ if (ulResult != GENERIC_OK) {
+ printk("Failed to apply dtmf mute changes on channel %d!\n", channel);
+ }
+/* printk("VPM450m: Setting DTMF on channel %d: %s / %s\n", channel, (detect ? "DETECT" : "NO DETECT"), (mute ? "MUTE" : "NO MUTE")); */
+ kfree(modify);
+}
+
+void vpm450m_setec(struct vpm450m *vpm450m, int channel, int eclen)
+{
+ if (eclen) {
+ vpm450m->chanflags[channel] |= FLAG_ECHO;
+ vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_RESET);
+ vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_NORMAL);
+ } else {
+ vpm450m->chanflags[channel] &= ~FLAG_ECHO;
+ if (vpm450m->chanflags[channel] & (FLAG_DTMF | FLAG_MUTE)) {
+ vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_RESET);
+ vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_FREEZE);
+ } else
+ vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_DIGITAL);
+ }
+/* printk("VPM450m: Setting EC on channel %d to %d\n", channel, eclen); */
+}
+
+int vpm450m_checkirq(struct vpm450m *vpm450m)
+{
+ tOCT6100_INTERRUPT_FLAGS InterruptFlags;
+
+ Oct6100InterruptServiceRoutineDef(&InterruptFlags);
+ Oct6100InterruptServiceRoutine(vpm450m->pApiInstance, &InterruptFlags);
+
+ return InterruptFlags.fToneEventsPending ? 1 : 0;
+}
+
+int vpm450m_getdtmf(struct vpm450m *vpm450m, int *channel, int *tone, int *start)
+{
+ tOCT6100_TONE_EVENT tonefound;
+ tOCT6100_EVENT_GET_TONE tonesearch;
+ UINT32 ulResult;
+
+ Oct6100EventGetToneDef(&tonesearch);
+ tonesearch.pToneEvent = &tonefound;
+ tonesearch.ulMaxToneEvent = 1;
+ ulResult = Oct6100EventGetTone(vpm450m->pApiInstance, &tonesearch);
+ if (tonesearch.ulNumValidToneEvent) {
+ if (channel)
+ *channel = tonefound.ulUserChanId;
+ if (tone) {
+ switch(tonefound.ulToneDetected) {
+ case SOUT_DTMF_1:
+ *tone = '1';
+ break;
+ case SOUT_DTMF_2:
+ *tone = '2';
+ break;
+ case SOUT_DTMF_3:
+ *tone = '3';
+ break;
+ case SOUT_DTMF_A:
+ *tone = 'A';
+ break;
+ case SOUT_DTMF_4:
+ *tone = '4';
+ break;
+ case SOUT_DTMF_5:
+ *tone = '5';
+ break;
+ case SOUT_DTMF_6:
+ *tone = '6';
+ break;
+ case SOUT_DTMF_B:
+ *tone = 'B';
+ break;
+ case SOUT_DTMF_7:
+ *tone = '7';
+ break;
+ case SOUT_DTMF_8:
+ *tone = '8';
+ break;
+ case SOUT_DTMF_9:
+ *tone = '9';
+ break;
+ case SOUT_DTMF_C:
+ *tone = 'C';
+ break;
+ case SOUT_DTMF_STAR:
+ *tone = '*';
+ break;
+ case SOUT_DTMF_0:
+ *tone = '0';
+ break;
+ case SOUT_DTMF_POUND:
+ *tone = '#';
+ break;
+ case SOUT_DTMF_D:
+ *tone = 'D';
+ break;
+ case SOUT_G168_1100GB_ON:
+ *tone = 'f';
+ break;
+ default:
+#ifdef OCTASIC_DEBUG
+ printk("Unknown tone value %08x\n", tonefound.ulToneDetected);
+#endif
+ *tone = 'u';
+ break;
+ }
+ }
+ if (start)
+ *start = (tonefound.ulEventType == cOCT6100_TONE_PRESENT);
+ return 1;
+ }
+ return 0;
+}
+
+unsigned int get_vpm450m_capacity(void *wc)
+{
+ UINT32 ulResult;
+
+ tOCT6100_API_GET_CAPACITY_PINS CapacityPins;
+
+ Oct6100ApiGetCapacityPinsDef(&CapacityPins);
+ CapacityPins.pProcessContext = wc;
+ CapacityPins.ulMemoryType = cOCT6100_MEM_TYPE_DDR;
+ CapacityPins.fEnableMemClkOut = TRUE;
+ CapacityPins.ulMemClkFreq = cOCT6100_MCLK_FREQ_133_MHZ;
+
+ ulResult = Oct6100ApiGetCapacityPins(&CapacityPins);
+ if (ulResult != cOCT6100_ERR_OK) {
+ printk("Failed to get chip capacity, code %08x!\n", ulResult);
+ return 0;
+ }
+
+ return CapacityPins.ulCapacityValue;
+}
+
+struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct firmware *firmware)
+{
+ tOCT6100_CHIP_OPEN *ChipOpen;
+ tOCT6100_GET_INSTANCE_SIZE InstanceSize;
+ tOCT6100_CHANNEL_OPEN *ChannelOpen;
+ UINT32 ulResult;
+ struct vpm450m *vpm450m;
+ int x,y,law;
+#ifdef CONFIG_4KSTACKS
+ unsigned long flags;
+#endif
+
+ if (!(vpm450m = kmalloc(sizeof(struct vpm450m), GFP_KERNEL)))
+ return NULL;
+
+ memset(vpm450m, 0, sizeof(struct vpm450m));
+
+ if (!(ChipOpen = kmalloc(sizeof(tOCT6100_CHIP_OPEN), GFP_KERNEL))) {
+ kfree(vpm450m);
+ return NULL;
+ }
+
+ memset(ChipOpen, 0, sizeof(tOCT6100_CHIP_OPEN));
+
+ if (!(ChannelOpen = kmalloc(sizeof(tOCT6100_CHANNEL_OPEN), GFP_KERNEL))) {
+ kfree(vpm450m);
+ kfree(ChipOpen);
+ return NULL;
+ }
+
+ memset(ChannelOpen, 0, sizeof(tOCT6100_CHANNEL_OPEN));
+
+ for (x=0;x<128;x++)
+ vpm450m->ecmode[x] = -1;
+
+ vpm450m->numchans = numspans * 32;
+ printk("VPM450: echo cancellation for %d channels\n", vpm450m->numchans);
+
+ Oct6100ChipOpenDef(ChipOpen);
+
+ /* Setup Chip Open Parameters */
+ ChipOpen->ulUpclkFreq = cOCT6100_UPCLK_FREQ_33_33_MHZ;
+ Oct6100GetInstanceSizeDef(&InstanceSize);
+
+ ChipOpen->pProcessContext = wc;
+
+ ChipOpen->pbyImageFile = firmware->data;
+ ChipOpen->ulImageSize = firmware->size;
+ ChipOpen->fEnableMemClkOut = TRUE;
+ ChipOpen->ulMemClkFreq = cOCT6100_MCLK_FREQ_133_MHZ;
+ ChipOpen->ulMaxChannels = vpm450m->numchans;
+ ChipOpen->ulMemoryType = cOCT6100_MEM_TYPE_DDR;
+ ChipOpen->ulMemoryChipSize = cOCT6100_MEMORY_CHIP_SIZE_32MB;
+ ChipOpen->ulNumMemoryChips = 1;
+ ChipOpen->ulMaxTdmStreams = 4;
+ ChipOpen->aulTdmStreamFreqs[0] = cOCT6100_TDM_STREAM_FREQ_8MHZ;
+ ChipOpen->ulTdmSampling = cOCT6100_TDM_SAMPLE_AT_FALLING_EDGE;
+#if 0
+ ChipOpen->fEnableAcousticEcho = TRUE;
+#endif
+
+ ulResult = Oct6100GetInstanceSize(ChipOpen, &InstanceSize);
+ if (ulResult != cOCT6100_ERR_OK) {
+ printk("Failed to get instance size, code %08x!\n", ulResult);
+ kfree(vpm450m);
+ kfree(ChipOpen);
+ kfree(ChannelOpen);
+ return NULL;
+ }
+
+
+ vpm450m->pApiInstance = vmalloc(InstanceSize.ulApiInstanceSize);
+ if (!vpm450m->pApiInstance) {
+ printk("Out of memory (can't allocate %d bytes)!\n", InstanceSize.ulApiInstanceSize);
+ kfree(vpm450m);
+ kfree(ChipOpen);
+ kfree(ChannelOpen);
+ return NULL;
+ }
+
+ /* I don't know what to curse more in this comment, the problems caused by
+ * the 4K kernel stack limit change or the octasic API for being so darn
+ * stack unfriendly. Stupid, stupid, stupid. So we disable IRQs so we
+ * don't run the risk of overflowing the stack while we initialize the
+ * octasic. */
+#ifdef CONFIG_4KSTACKS
+ local_irq_save(flags);
+#endif
+ ulResult = Oct6100ChipOpen(vpm450m->pApiInstance, ChipOpen);
+ if (ulResult != cOCT6100_ERR_OK) {
+ printk("Failed to open chip, code %08x!\n", ulResult);
+#ifdef CONFIG_4KSTACKS
+ local_irq_restore(flags);
+#endif
+ kfree(vpm450m);
+ kfree(ChipOpen);
+ kfree(ChannelOpen);
+ return NULL;
+ }
+ for (x=0;x<128;x++) {
+ /* execute this loop always on 4 span cards but
+ * on 2 span cards only execute for the channels related to our spans */
+ if (( numspans > 2) || ((x & 0x03) <2)) {
+ /* span timeslots are interleaved 12341234...
+ * therefore, the lower 2 bits tell us which span this
+ * timeslot/channel
+ */
+ if (isalaw[x & 0x03])
+ law = cOCT6100_PCM_A_LAW;
+ else
+ law = cOCT6100_PCM_U_LAW;
+ Oct6100ChannelOpenDef(ChannelOpen);
+ ChannelOpen->pulChannelHndl = &vpm450m->aulEchoChanHndl[x];
+ ChannelOpen->ulUserChanId = x;
+ ChannelOpen->TdmConfig.ulRinPcmLaw = law;
+ ChannelOpen->TdmConfig.ulRinStream = 0;
+ ChannelOpen->TdmConfig.ulRinTimeslot = x;
+ ChannelOpen->TdmConfig.ulSinPcmLaw = law;
+ ChannelOpen->TdmConfig.ulSinStream = 1;
+ ChannelOpen->TdmConfig.ulSinTimeslot = x;
+ ChannelOpen->TdmConfig.ulSoutPcmLaw = law;
+ ChannelOpen->TdmConfig.ulSoutStream = 2;
+ ChannelOpen->TdmConfig.ulSoutTimeslot = x;
+ ChannelOpen->TdmConfig.ulRoutPcmLaw = law;
+ ChannelOpen->TdmConfig.ulRoutStream = 3;
+ ChannelOpen->TdmConfig.ulRoutTimeslot = x;
+ ChannelOpen->VqeConfig.fEnableNlp = TRUE;
+ ChannelOpen->VqeConfig.fRinDcOffsetRemoval = TRUE;
+ ChannelOpen->VqeConfig.fSinDcOffsetRemoval = TRUE;
+
+ ChannelOpen->fEnableToneDisabler = TRUE;
+ ChannelOpen->ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_DIGITAL;
+
+ ulResult = Oct6100ChannelOpen(vpm450m->pApiInstance, ChannelOpen);
+ if (ulResult != GENERIC_OK) {
+ printk("Failed to open channel %d!\n", x);
+ }
+ for (y=0;y<sizeof(tones) / sizeof(tones[0]); y++) {
+ tOCT6100_TONE_DETECTION_ENABLE enable;
+ Oct6100ToneDetectionEnableDef(&enable);
+ enable.ulChannelHndl = vpm450m->aulEchoChanHndl[x];
+ enable.ulToneNumber = tones[y];
+ if (Oct6100ToneDetectionEnable(vpm450m->pApiInstance, &enable) != GENERIC_OK)
+ printk("Failed to enable tone detection on channel %d for tone %d!\n", x, y);
+ }
+ }
+ }
+
+#ifdef CONFIG_4KSTACKS
+ local_irq_restore(flags);
+#endif
+ kfree(ChipOpen);
+ kfree(ChannelOpen);
+ return vpm450m;
+}
+
+void release_vpm450m(struct vpm450m *vpm450m)
+{
+ UINT32 ulResult;
+ tOCT6100_CHIP_CLOSE ChipClose;
+
+ Oct6100ChipCloseDef(&ChipClose);
+ ulResult = Oct6100ChipClose(vpm450m->pApiInstance, &ChipClose);
+ if (ulResult != cOCT6100_ERR_OK) {
+ printk("Failed to close chip, code %08x!\n", ulResult);
+ }
+ vfree(vpm450m->pApiInstance);
+ kfree(vpm450m);
+}
diff --git a/drivers/dahdi/wct4xxp/vpm450m.h b/drivers/dahdi/wct4xxp/vpm450m.h
new file mode 100644
index 0000000..41d7c60
--- /dev/null
+++ b/drivers/dahdi/wct4xxp/vpm450m.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2005-2006 Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _VPM450M_H
+#define _VPM450M_H
+
+#include <linux/firmware.h>
+
+struct vpm450m;
+
+/* From driver */
+unsigned int oct_get_reg(void *data, unsigned int reg);
+void oct_set_reg(void *data, unsigned int reg, unsigned int val);
+
+/* From vpm450m */
+struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct firmware *firmware);
+unsigned int get_vpm450m_capacity(void *wc);
+void vpm450m_setec(struct vpm450m *instance, int channel, int eclen);
+void vpm450m_setdtmf(struct vpm450m *instance, int channel, int dtmfdetect, int dtmfmute);
+int vpm450m_checkirq(struct vpm450m *vpm450m);
+int vpm450m_getdtmf(struct vpm450m *vpm450m, int *channel, int *tone, int *start);
+void release_vpm450m(struct vpm450m *instance);
+
+#endif
diff --git a/drivers/dahdi/wct4xxp/wct4xxp-diag.c b/drivers/dahdi/wct4xxp/wct4xxp-diag.c
new file mode 100644
index 0000000..8c14611
--- /dev/null
+++ b/drivers/dahdi/wct4xxp/wct4xxp-diag.c
@@ -0,0 +1,414 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <string.h>
+#include "zaptel.h"
+#include "wct4xxp.h"
+
+static struct t4_reg_def {
+ int reg;
+ char *name;
+ int global;
+};
+static struct t4_reg_def xreginfo[] = {
+ { 0x00, "RDADDR" },
+ { 0x01, "WRADDR" },
+ { 0x02, "COUNT" },
+ { 0x03, "DMACTRL" },
+ { 0x04, "WCINTR" },
+ { 0x06, "VERSION" },
+ { 0x07, "LEDS" },
+ { 0x08, "GPIOCTL" },
+ { 0x09, "GPIO" },
+ { 0x0A, "LADDR" },
+ { 0x0b, "LDATA" },
+};
+
+static struct t4_reg_def reginfo[] = {
+ { 0x00, "XFIFO" },
+ { 0x01, "XFIFO" },
+ { 0x02, "CMDR" },
+ { 0x03, "MODE" },
+ { 0x04, "RAH1" },
+ { 0x05, "RAH2" },
+ { 0x06, "RAL1" },
+ { 0x07, "RAL2" },
+ { 0x08, "IPC", 1 },
+ { 0x09, "CCR1" },
+ { 0x0a, "CCR2" },
+ { 0x0c, "RTR1" },
+ { 0x0d, "RTR2" },
+ { 0x0e, "RTR3" },
+ { 0x0f, "RTR4" },
+ { 0x10, "TTR1" },
+ { 0x11, "TTR2" },
+ { 0x12, "TTR3" },
+ { 0x13, "TTR4" },
+ { 0x14, "IMR0" },
+ { 0x15, "IMR1" },
+ { 0x16, "IMR2" },
+ { 0x17, "IMR3" },
+ { 0x18, "IMR4" },
+ { 0x1b, "IERR" },
+ { 0x1c, "FMR0" },
+ { 0x1d, "FMR1" },
+ { 0x1e, "FMR2" },
+ { 0x1f, "LOOP" },
+ { 0x20, "XSW" },
+ { 0x21, "XSP" },
+ { 0x22, "XC0" },
+ { 0x23, "XC1" },
+ { 0x24, "RC0" },
+ { 0x25, "RC1" },
+ { 0x26, "XPM0" },
+ { 0x27, "XPM1" },
+ { 0x28, "XPM2" },
+ { 0x29, "TSWM" },
+ { 0x2b, "IDLE" },
+ { 0x2c, "XSA4" },
+ { 0x2d, "XSA5" },
+ { 0x2e, "XSA6" },
+ { 0x2f, "XSA7" },
+ { 0x30, "XSA8" },
+ { 0x31, "FMR3" },
+ { 0x32, "ICB1" },
+ { 0x33, "ICB2" },
+ { 0x34, "ICB3" },
+ { 0x35, "ICB4" },
+ { 0x36, "LIM0" },
+ { 0x37, "LIM1" },
+ { 0x38, "PCD" },
+ { 0x39, "PCR" },
+ { 0x3a, "LIM2" },
+ { 0x3b, "LCR1" },
+ { 0x3c, "LCR2" },
+ { 0x3d, "LCR3" },
+ { 0x3e, "SIC1" },
+ { 0x3f, "SIC2" },
+ { 0x40, "SIC3" },
+ { 0x44, "CMR1" },
+ { 0x45, "CMR2" },
+ { 0x46, "GCR" },
+ { 0x47, "ESM" },
+ { 0x60, "DEC" },
+ { 0x70, "XS1" },
+ { 0x71, "XS2" },
+ { 0x72, "XS3" },
+ { 0x73, "XS4" },
+ { 0x74, "XS5" },
+ { 0x75, "XS6" },
+ { 0x76, "XS7" },
+ { 0x77, "XS8" },
+ { 0x78, "XS9" },
+ { 0x79, "XS10" },
+ { 0x7a, "XS11" },
+ { 0x7b, "XS12" },
+ { 0x7c, "XS13" },
+ { 0x7d, "XS14" },
+ { 0x7e, "XS15" },
+ { 0x7f, "XS16" },
+ { 0x80, "PC1" },
+ { 0x81, "PC2" },
+ { 0x82, "PC3" },
+ { 0x83, "PC4" },
+ { 0x84, "PC5" },
+ { 0x85, "GPC1", 1 },
+ { 0x87, "CMDR2" },
+ { 0x8d, "CCR5" },
+ { 0x92, "GCM1", 1 },
+ { 0x93, "GCM2", 1 },
+ { 0x94, "GCM3", 1 },
+ { 0x95, "GCM4", 1 },
+ { 0x96, "GCM5", 1 },
+ { 0x97, "GCM6", 1 },
+ { 0x98, "GCM7", 1 },
+ { 0x99, "GCM8", 1 },
+ { 0xa0, "TSEO" },
+ { 0xa1, "TSBS1" },
+ { 0xa8, "TPC0" },
+};
+
+static struct t4_reg_def t1_reginfo[] = {
+ { 0x00, "XFIFO" },
+ { 0x01, "XFIFO" },
+ { 0x02, "CMDR" },
+ { 0x03, "MODE" },
+ { 0x04, "RAH1" },
+ { 0x05, "RAH2" },
+ { 0x06, "RAL1" },
+ { 0x07, "RAL2" },
+ { 0x08, "IPC", 1 },
+ { 0x09, "CCR1" },
+ { 0x0a, "CCR2" },
+ { 0x0c, "RTR1" },
+ { 0x0d, "RTR2" },
+ { 0x0e, "RTR3" },
+ { 0x0f, "RTR4" },
+ { 0x10, "TTR1" },
+ { 0x11, "TTR2" },
+ { 0x12, "TTR3" },
+ { 0x13, "TTR4" },
+ { 0x14, "IMR0" },
+ { 0x15, "IMR1" },
+ { 0x16, "IMR2" },
+ { 0x17, "IMR3" },
+ { 0x18, "IMR4" },
+ { 0x1b, "IERR" },
+ { 0x1c, "FMR0" },
+ { 0x1d, "FMR1" },
+ { 0x1e, "FMR2" },
+ { 0x1f, "LOOP" },
+ { 0x20, "FMR4" },
+ { 0x21, "FMR5" },
+ { 0x22, "XC0" },
+ { 0x23, "XC1" },
+ { 0x24, "RC0" },
+ { 0x25, "RC1" },
+ { 0x26, "XPM0" },
+ { 0x27, "XPM1" },
+ { 0x28, "XPM2" },
+ { 0x2b, "IDLE" },
+ { 0x2c, "XDL1" },
+ { 0x2d, "XDL2" },
+ { 0x2e, "XDL3" },
+ { 0x2f, "CCB1" },
+ { 0x30, "CCB2" },
+ { 0x31, "CCB3" },
+ { 0x32, "ICB1" },
+ { 0x33, "ICB2" },
+ { 0x34, "ICB3" },
+ { 0x36, "LIM0" },
+ { 0x37, "LIM1" },
+ { 0x38, "PCD" },
+ { 0x39, "PCR" },
+ { 0x3a, "LIM2" },
+ { 0x3b, "LCR1" },
+ { 0x3c, "LCR2" },
+ { 0x3d, "LCR3" },
+ { 0x3e, "SIC1" },
+ { 0x3f, "SIC2" },
+ { 0x40, "SIC3" },
+ { 0x44, "CMR1" },
+ { 0x45, "CMR2" },
+ { 0x46, "GCR" },
+ { 0x47, "ESM" },
+ { 0x60, "DEC" },
+ { 0x70, "XS1" },
+ { 0x71, "XS2" },
+ { 0x72, "XS3" },
+ { 0x73, "XS4" },
+ { 0x74, "XS5" },
+ { 0x75, "XS6" },
+ { 0x76, "XS7" },
+ { 0x77, "XS8" },
+ { 0x78, "XS9" },
+ { 0x79, "XS10" },
+ { 0x7a, "XS11" },
+ { 0x7b, "XS12" },
+ { 0x80, "PC1" },
+ { 0x81, "PC2" },
+ { 0x82, "PC3" },
+ { 0x83, "PC4" },
+ { 0x84, "PC5" },
+ { 0x85, "GPC1", 1 },
+ { 0x87, "CMDR2" },
+ { 0x8d, "CCR5" },
+ { 0x92, "GCM1", 1 },
+ { 0x93, "GCM2", 1 },
+ { 0x94, "GCM3", 1 },
+ { 0x95, "GCM4", 1 },
+ { 0x96, "GCM5", 1 },
+ { 0x97, "GCM6", 1 },
+ { 0x98, "GCM7", 1 },
+ { 0x99, "GCM8", 1 },
+ { 0xa0, "TSEO" },
+ { 0xa1, "TSBS1" },
+ { 0xa8, "TPC0" },
+};
+
+static struct t4_reg_def t1_sreginfo[] = {
+ { 0x00, "RFIFO" },
+ { 0x01, "RFIFO" },
+ { 0x49, "RBD" },
+ { 0x4a, "VSTR", 1 },
+ { 0x4b, "RES" },
+ { 0x4c, "FRS0" },
+ { 0x4d, "FRS1" },
+ { 0x4e, "FRS2" },
+ { 0x4f, "Old FRS1" },
+ { 0x50, "FECL" },
+ { 0x51, "FECH" },
+ { 0x52, "CVCL" },
+ { 0x53, "CVCH" },
+ { 0x54, "CECL" },
+ { 0x55, "CECH" },
+ { 0x56, "EBCL" },
+ { 0x57, "EBCH" },
+ { 0x58, "BECL" },
+ { 0x59, "BECH" },
+ { 0x5a, "COEC" },
+ { 0x5c, "RDL1" },
+ { 0x5d, "RDL2" },
+ { 0x5e, "RDL3" },
+ { 0x62, "RSP1" },
+ { 0x63, "RSP2" },
+ { 0x64, "SIS" },
+ { 0x65, "RSIS" },
+ { 0x66, "RBCL" },
+ { 0x67, "RBCH" },
+ { 0x68, "ISR0" },
+ { 0x69, "ISR1" },
+ { 0x6a, "ISR2" },
+ { 0x6b, "ISR3" },
+ { 0x6c, "ISR4" },
+ { 0x6e, "GIS" },
+ { 0x6f, "CIS", 1 },
+ { 0x70, "RS1" },
+ { 0x71, "RS2" },
+ { 0x72, "RS3" },
+ { 0x73, "RS4" },
+ { 0x74, "RS5" },
+ { 0x75, "RS6" },
+ { 0x76, "RS7" },
+ { 0x77, "RS8" },
+ { 0x78, "RS9" },
+ { 0x79, "RS10" },
+ { 0x7a, "RS11" },
+ { 0x7b, "RS12" },
+};
+
+static struct t4_reg_def sreginfo[] = {
+ { 0x00, "RFIFO" },
+ { 0x01, "RFIFO" },
+ { 0x49, "RBD" },
+ { 0x4a, "VSTR", 1 },
+ { 0x4b, "RES" },
+ { 0x4c, "FRS0" },
+ { 0x4d, "FRS1" },
+ { 0x4e, "RSW" },
+ { 0x4f, "RSP" },
+ { 0x50, "FECL" },
+ { 0x51, "FECH" },
+ { 0x52, "CVCL" },
+ { 0x53, "CVCH" },
+ { 0x54, "CEC1L" },
+ { 0x55, "CEC1H" },
+ { 0x56, "EBCL" },
+ { 0x57, "EBCH" },
+ { 0x58, "CEC2L" },
+ { 0x59, "CEC2H" },
+ { 0x5a, "CEC3L" },
+ { 0x5b, "CEC3H" },
+ { 0x5c, "RSA4" },
+ { 0x5d, "RSA5" },
+ { 0x5e, "RSA6" },
+ { 0x5f, "RSA7" },
+ { 0x60, "RSA8" },
+ { 0x61, "RSA6S" },
+ { 0x62, "RSP1" },
+ { 0x63, "RSP2" },
+ { 0x64, "SIS" },
+ { 0x65, "RSIS" },
+ { 0x66, "RBCL" },
+ { 0x67, "RBCH" },
+ { 0x68, "ISR0" },
+ { 0x69, "ISR1" },
+ { 0x6a, "ISR2" },
+ { 0x6b, "ISR3" },
+ { 0x6c, "ISR4" },
+ { 0x6e, "GIS" },
+ { 0x6f, "CIS", 1 },
+ { 0x70, "RS1" },
+ { 0x71, "RS2" },
+ { 0x72, "RS3" },
+ { 0x73, "RS4" },
+ { 0x74, "RS5" },
+ { 0x75, "RS6" },
+ { 0x76, "RS7" },
+ { 0x77, "RS8" },
+ { 0x78, "RS9" },
+ { 0x79, "RS10" },
+ { 0x7a, "RS11" },
+ { 0x7b, "RS12" },
+ { 0x7c, "RS13" },
+ { 0x7d, "RS14" },
+ { 0x7e, "RS15" },
+ { 0x7f, "RS16" },
+};
+
+static char *tobin(int x)
+{
+ static char s[9] = "";
+ int y,z=0;
+ for (y=7;y>=0;y--) {
+ if (x & (1 << y))
+ s[z++] = '1';
+ else
+ s[z++] = '0';
+ }
+ s[z] = '\0';
+ return s;
+}
+
+static char *tobin32(unsigned int x)
+{
+ static char s[33] = "";
+ int y,z=0;
+ for (y=31;y>=0;y--) {
+ if (x & (1 << y))
+ s[z++] = '1';
+ else
+ s[z++] = '0';
+ }
+ s[z] = '\0';
+ return s;
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int x;
+ char fn[256];
+ struct t4_regs regs;
+ if ((argc < 2) || ((*(argv[1]) != '/') && !atoi(argv[1]))) {
+ fprintf(stderr, "Usage: wct4xxp-diag <channel>\n");
+ exit(1);
+ }
+ if (*(argv[1]) == '/')
+ zap_copy_string(fn, argv[1], sizeof(fn));
+ else
+ snprintf(fn, sizeof(fn), "/dev/zap/%d", atoi(argv[1]));
+ fd = open(fn, O_RDWR);
+ if (fd <0) {
+ fprintf(stderr, "Unable to open '%s': %s\n", fn, strerror(errno));
+ exit(1);
+ }
+ if (ioctl(fd, WCT4_GET_REGS, &regs)) {
+ fprintf(stderr, "Unable to get registers: %s\n", strerror(errno));
+ exit(1);
+ }
+ printf("PCI Registers:\n");
+ for (x=0;x<sizeof(xreginfo) / sizeof(xreginfo[0]);x++) {
+ fprintf(stdout, "%s (%02x): %08x (%s)\n", xreginfo[x].name, xreginfo[x].reg, regs.pci[xreginfo[x].reg], tobin32(regs.pci[xreginfo[x].reg]));
+ }
+ printf("\nE1 Control Registers:\n");
+ for (x=0;x<sizeof(reginfo) / sizeof(reginfo[0]);x++) {
+ fprintf(stdout, "%s (%02x): %02x (%s)\n", reginfo[x].name, reginfo[x].reg, regs.regs[reginfo[x].reg], tobin(regs.regs[reginfo[x].reg]));
+ }
+ printf("\nE1 Status Registers:\n");
+ for (x=0;x<sizeof(sreginfo) / sizeof(sreginfo[0]);x++) {
+ fprintf(stdout, "%s (%02x): %02x (%s)\n", sreginfo[x].name, sreginfo[x].reg, regs.regs[sreginfo[x].reg], tobin(regs.regs[sreginfo[x].reg]));
+ }
+ printf("\nT1 Control Registers:\n");
+ for (x=0;x<sizeof(t1_reginfo) / sizeof(t1_reginfo[0]);x++) {
+ fprintf(stdout, "%s (%02x): %02x (%s)\n", t1_reginfo[x].name, t1_reginfo[x].reg, regs.regs[t1_reginfo[x].reg], tobin(regs.regs[t1_reginfo[x].reg]));
+ }
+ printf("\nT1 Status Registers:\n");
+ for (x=0;x<sizeof(t1_sreginfo) / sizeof(t1_sreginfo[0]);x++) {
+ fprintf(stdout, "%s (%02x): %02x (%s)\n", t1_sreginfo[x].name, t1_sreginfo[x].reg, regs.regs[t1_sreginfo[x].reg], tobin(regs.regs[t1_sreginfo[x].reg]));
+ }
+ exit(0);
+}
diff --git a/drivers/dahdi/wct4xxp/wct4xxp.h b/drivers/dahdi/wct4xxp/wct4xxp.h
new file mode 100644
index 0000000..7d14b85
--- /dev/null
+++ b/drivers/dahdi/wct4xxp/wct4xxp.h
@@ -0,0 +1,114 @@
+/*
+ * Wilcard T400P FXS Interface Driver for Zapata Telephony interface
+ *
+ * Written by Mark Spencer <markster@linux-support.net>
+ *
+ * Copyright (C) 2001, Linux Support Services, 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/ioctl.h>
+
+#define FRMR_TTR_BASE 0x10
+#define FRMR_RTR_BASE 0x0c
+#define FRMR_TSEO 0xa0
+#define FRMR_TSBS1 0xa1
+#define FRMR_CCR1 0x09
+#define FRMR_CCR1_ITF 0x08
+#define FRMR_CCR1_EITS 0x10
+#define FRMR_CCR2 0x0a
+#define FRMR_CCR2_RCRC 0x04
+#define FRMR_CCR2_RADD 0x10
+#define FRMR_MODE 0x03
+#define FRMR_MODE_NO_ADDR_CMP 0x80
+#define FRMR_MODE_SS7 0x20
+#define FRMR_MODE_HRAC 0x08
+#define FRMR_IMR0 0x14
+#define FRMR_IMR0_RME 0x80
+#define FRMR_IMR0_RPF 0x01
+#define FRMR_IMR1 0x15
+#define FRMR_IMR1_ALLS 0x20
+#define FRMR_IMR1_XDU 0x10
+#define FRMR_IMR1_XPR 0x01
+#define FRMR_XC0 0x22
+#define FRMR_XC1 0x23
+#define FRMR_RC0 0x24
+#define FRMR_RC1 0x25
+#define FRMR_SIC1 0x3e
+#define FRMR_SIC2 0x3f
+#define FRMR_SIC3 0x40
+#define FRMR_CMR1 0x44
+#define FRMR_CMR2 0x45
+#define FRMR_GCR 0x46
+#define FRMR_ISR0 0x68
+#define FRMR_ISR0_RME 0x80
+#define FRMR_ISR0_RPF 0x01
+#define FRMR_ISR1 0x69
+#define FRMR_ISR1_ALLS 0x20
+#define FRMR_ISR1_XDU 0x10
+#define FRMR_ISR1_XPR 0x01
+#define FRMR_ISR2 0x6a
+#define FRMR_ISR3 0x6b
+#define FRMR_ISR4 0x6c
+#define FRMR_GIS 0x6e
+#define FRMR_GIS_ISR0 0x01
+#define FRMR_GIS_ISR1 0x02
+#define FRMR_GIS_ISR2 0x04
+#define FRMR_GIS_ISR3 0x08
+#define FRMR_GIS_ISR4 0x10
+#define FRMR_CIS 0x6f
+#define FRMR_CIS_GIS1 0x01
+#define FRMR_CIS_GIS2 0x02
+#define FRMR_CIS_GIS3 0x04
+#define FRMR_CIS_GIS4 0x08
+#define FRMR_CMDR 0x02
+#define FRMR_CMDR_SRES 0x01
+#define FRMR_CMDR_XRES 0x10
+#define FRMR_CMDR_RMC 0x80
+#define FRMR_CMDR_XTF 0x04
+#define FRMR_CMDR_XHF 0x08
+#define FRMR_CMDR_XME 0x02
+#define FRMR_RSIS 0x65
+#define FRMR_RSIS_VFR 0x80
+#define FRMR_RSIS_RDO 0x40
+#define FRMR_RSIS_CRC16 0x20
+#define FRMR_RSIS_RAB 0x10
+#define FRMR_RBCL 0x66
+#define FRMR_RBCL_MAX_SIZE 0x1f
+#define FRMR_RBCH 0x67
+#define FRMR_RXFIFO 0x00
+#define FRMR_SIS 0x64
+#define FRMR_SIS_XFW 0x40
+#define FRMR_TXFIFO 0x00
+
+#define NUM_REGS 0xa9
+#define NUM_PCI 12
+
+struct t4_regs {
+ unsigned int pci[NUM_PCI];
+ unsigned char regs[NUM_REGS];
+};
+
+#define T4_CHECK_VPM 0
+#define T4_LOADING_FW 1
+#define T4_STOP_DMA 2
+#define T4_CHECK_TIMING 3
+
+#define WCT4_GET_REGS _IOW (ZT_CODE, 60, struct t4_regs)
+
diff --git a/drivers/dahdi/wctc4xxp/Kbuild b/drivers/dahdi/wctc4xxp/Kbuild
new file mode 100644
index 0000000..353290f
--- /dev/null
+++ b/drivers/dahdi/wctc4xxp/Kbuild
@@ -0,0 +1,20 @@
+obj-m += wctc4xxp.o
+
+FIRM_DIR := ../../firmware
+
+EXTRA_CFLAGS := -I$(src)/.. -Wno-undef
+
+ifeq ($(HOTPLUG_FIRMWARE),yes)
+ EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
+endif
+
+wctc4xxp-objs := base.o
+
+ifneq ($(HOTPLUG_FIRMWARE),yes)
+wctc4xxp-objs += $(FIRM_DIR)/zaptel-fw-tc400m.o
+endif
+
+$(obj)/base.o: $(src)/../zaptel.h
+
+$(obj)/$(FIRM_DIR)/zaptel-fw-tc400m.o: $(obj)/base.o
+ $(MAKE) -C $(obj)/$(FIRM_DIR) zaptel-fw-tc400m.o
diff --git a/drivers/dahdi/wctc4xxp/Makefile b/drivers/dahdi/wctc4xxp/Makefile
new file mode 100644
index 0000000..725abc4
--- /dev/null
+++ b/drivers/dahdi/wctc4xxp/Makefile
@@ -0,0 +1,16 @@
+ifneq ($(KBUILD_EXTMOD),)
+# We only get here on kernels 2.6.0-2.6.9 .
+# For newer kernels, Kbuild will be included directly by the kernel
+# build system.
+include $(src)/Kbuild
+
+else
+
+tests: codec_test
+
+codec_test: codec_test.c ../zaptel.h
+ $(CC) -o $@ $< $(CFLAGS)
+
+clean:
+ rm -rf codec_test
+endif
diff --git a/drivers/dahdi/wctc4xxp/base.c b/drivers/dahdi/wctc4xxp/base.c
new file mode 100644
index 0000000..4845c6b
--- /dev/null
+++ b/drivers/dahdi/wctc4xxp/base.c
@@ -0,0 +1,2023 @@
+/*
+ * 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
+#include "zaptel.h"
+
+/* #define USE_TEST_HW */
+#define USE_TDM_CONFIG
+#define QUIET_DSP
+
+#define WC_MAX_IFACES 128
+
+#define NUM_CARDS 24
+#define NUM_EC 4
+
+/* NUM_CHANNELS must be checked if new firmware (dte_firm.h) is used */
+#define NUM_CHANNELS 120
+
+#define DTE_FORMAT_ULAW 0x00
+#define DTE_FORMAT_G723_1 0x04
+#define DTE_FORMAT_ALAW 0x08
+#define DTE_FORMAT_G729A 0x12
+#define DTE_FORMAT_UNDEF 0xFF
+
+#define G729_LENGTH 20
+#define G723_LENGTH 30
+
+#define G729_SAMPLES 160 /* G.729 */
+#define G723_SAMPLES 240 /* G.723.1 */
+
+#define G729_BYTES 20 /* G.729 */
+#define G723_6K_BYTES 24 /* G.723.1 at 6.3kb/s */
+#define G723_5K_BYTES 20 /* G.723.1 at 5.3kb/s */
+#define G723_SID_BYTES 4 /* G.723.1 SID frame */
+
+#define ACK_SPACE 20
+
+#define MAX_COMMANDS (NUM_CHANNELS + ACK_SPACE)
+#define MAX_RCV_COMMANDS 16
+
+/* 1432 for boot, 274 for 30msec ulaw, 194 for 20mec ulaw */
+#define BOOT_CMD_LEN 1500
+#define OTHER_CMD_LEN 300
+
+#define MAX_COMMAND_LEN BOOT_CMD_LEN /* Must be the larger of BOOT_CMD_LEN or OTHER_CMD_LEN */
+
+#define ERING_SIZE (NUM_CHANNELS / 2) /* Maximum ring size */
+
+#define SFRAME_SIZE MAX_COMMAND_LEN
+
+#define PCI_WINDOW_SIZE ((2* 2 * ERING_SIZE * SFRAME_SIZE) + (2 * ERING_SIZE * 4))
+
+#define MDIO_SHIFT_CLK 0x10000
+#define MDIO_DATA_WRITE0 0x00000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB 0x00000
+#define MDIO_ENB_IN 0x40000
+#define MDIO_DATA_READ 0x80000
+
+#define RCV_CSMENCAPS 1
+#define RCV_RTP 2
+#define RCV_CSMENCAPS_ACK 3
+#define RCV_OTHER 99
+
+
+/* TDM Commands */
+#define CMD_MSG_TDM_SELECT_BUS_MODE_LEN 30
+#define CMD_MSG_TDM_SELECT_BUS_MODE(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x01, 0x00,0x06,0x17,0x04, 0xFF,0xFF, \
+ 0x04,0x00 }
+#define CMD_MSG_TDM_ENABLE_BUS_LEN 30
+#define CMD_MSG_TDM_ENABLE_BUS(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x02, 0x00,0x06,0x05,0x04, 0xFF,0xFF, \
+ 0x04,0x00 }
+#define CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN 34
+#define CMD_MSG_SUPVSR_SETUP_TDM_PARMS(s,p1,p2,p3) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x10, p1, 0x00,0x06,0x07,0x04, 0xFF,0xFF, \
+ p2,0x83, 0x00,0x0C, 0x00,0x00, p3,0x00 }
+#define CMD_MSG_TDM_OPT_LEN 30
+#define CMD_MSG_TDM_OPT(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x35,0x04, 0xFF,0xFF, \
+ 0x00,0x00 }
+#define CMD_MSG_DEVICE_SET_COUNTRY_CODE_LEN 30
+#define CMD_MSG_DEVICE_SET_COUNTRY_CODE(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x1B,0x04, 0xFF,0xFF, \
+ 0x00,0x00 }
+
+/* CPU Commands */
+#define CMD_MSG_SET_ARM_CLK_LEN 32
+#define CMD_MSG_SET_ARM_CLK(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x11,0x04, 0x00,0x00, \
+ 0x2C,0x01, 0x00,0x00 }
+#define CMD_MSG_SET_SPU_CLK_LEN 32
+#define CMD_MSG_SET_SPU_CLK(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x12,0x04, 0x00,0x00, \
+ 0x2C,0x01, 0x00,0x00 }
+#define CMD_MSG_SPU_FEATURES_CONTROL_LEN 30
+#define CMD_MSG_SPU_FEATURES_CONTROL(s,p1) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x13,0x00, 0xFF,0xFF, \
+ p1,0x00 }
+#define CMD_MSG_DEVICE_STATUS_CONFIG_LEN 30
+#define CMD_MSG_DEVICE_STATUS_CONFIG(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x0F,0x04, 0xFF,0xFF, \
+ 0x05,0x00 }
+
+/* General IP/RTP Commands */
+#define CMD_MSG_SET_ETH_HEADER_LEN 44
+#define CMD_MSG_SET_ETH_HEADER(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x18, 0x00, 0x00,0x06,0x00,0x01, 0xFF,0xFF, \
+ 0x01,0x00, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x00,0x11,0x22,0x33,0x44,0x55, 0x08,0x00 }
+#define CMD_MSG_IP_SERVICE_CONFIG_LEN 30
+#define CMD_MSG_IP_SERVICE_CONFIG(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x02,0x03, 0xFF,0xFF, \
+ 0x00,0x02 }
+#define CMD_MSG_ARP_SERVICE_CONFIG_LEN 30
+#define CMD_MSG_ARP_SERVICE_CONFIG(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x05,0x01, 0xFF,0xFF, \
+ 0x01,0x00 }
+#define CMD_MSG_ICMP_SERVICE_CONFIG_LEN 30
+#define CMD_MSG_ICMP_SERVICE_CONFIG(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x04,0x03, 0xFF,0xFF, \
+ 0x01,0xFF }
+#define CMD_MSG_IP_OPTIONS_LEN 30
+#define CMD_MSG_IP_OPTIONS(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x06,0x03, 0xFF,0xFF, \
+ 0x02,0x00 }
+
+/* Supervisor channel commands */
+#define CMD_MSG_CREATE_CHANNEL_LEN 32
+#define CMD_MSG_CREATE_CHANNEL(s,t) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0C, 0x00, 0x00,0x06,0x10,0x00, 0x00,0x00, \
+ 0x02,0x00, (t&0x00FF), ((t&0xFF00) >> 8) }
+#define CMD_MSG_QUERY_CHANNEL_LEN 30
+#define CMD_MSG_QUERY_CHANNEL(s,t) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x01,0x06,0x10,0x00, 0x00,0x00, \
+ (t&0x00FF), ((t&0xFF00) >> 8) }
+#define CMD_MSG_TRANS_CONNECT_LEN 38
+#define CMD_MSG_TRANS_CONNECT(s,e,c1,c2,f1,f2) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x12, 0x00, 0x00,0x06,0x22,0x93, 0x00,0x00, \
+ e,0x00, (c1&0x00FF),((c1&0xFF00)>>8), f1,0x00, (c2&0x00FF),((c2&0xFF00)>>8), f2,0x00 }
+#define CMD_MSG_DESTROY_CHANNEL_LEN 32
+#define CMD_MSG_DESTROY_CHANNEL(s,t) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x11,0x00, 0x00,0x00, \
+ (t&0x00FF),((t&0xFF00)>>8), 0x00, 0x00 }
+
+/* Individual channel config commands */
+#define CMD_MSG_SET_IP_HDR_CHANNEL_LEN 58
+#define CMD_MSG_SET_IP_HDR_CHANNEL(s,c,t2,t1) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00) >> 8),(c&0x00FF), 0x26, 0x00, 0x00,0x02,0x00,0x90, 0x00,0x00, \
+ 0x00,0x00, 0x45,0x00, 0x00,0x00, 0x00,0x00, 0x40,0x00, 0x80,0x11, 0x00,0x00, \
+ 0xC0,0xA8,0x09,0x03, 0xC0,0xA8,0x09,0x03, \
+ ((t2&0xFF00)>>8)+0x50,(t2&0x00FF), ((t1&0xFF00)>>8)+0x50,(t1&0x00FF), 0x00,0x00, 0x00,0x00 }
+#define CMD_MSG_VOIP_VCEOPT_LEN 40
+#define CMD_MSG_VOIP_VCEOPT(s,c,l,w) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x12, 0x00, 0x00,0x02,0x01,0x80, 0x00,0x00, \
+ 0x21,l, 0x00,0x1C, 0x04,0x00, 0x00,0x00, w,0x00, 0x80,0x11 }
+#define CMD_MSG_VOIP_VOPENA_LEN 44
+#define CMD_MSG_VOIP_VOPENA(s,c,f) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x16, 0x00, 0x00,0x02,0x00,0x80, 0x00,0x00, \
+ 0x01,0x00, 0x80,f, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x12,0x34, 0x56,0x78, 0x00,0x00 }
+#define CMD_MSG_VOIP_VOPENA_CLOSE_LEN 32
+#define CMD_MSG_VOIP_VOPENA_CLOSE(s,c) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x00,0x80, 0x00,0x00, \
+ 0x00,0x00, 0x00,0x00 }
+#define CMD_MSG_VOIP_INDCTRL_LEN 32
+#define CMD_MSG_VOIP_INDCTRL(s,c) {0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x84,0x80, 0x00,0x00, \
+ 0x07,0x00, 0x00,0x00 }
+#define CMD_MSG_VOIP_DTMFOPT_LEN 32
+#define CMD_MSG_VOIP_DTMFOPT(s,c) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x02,0x80, 0x00,0x00, \
+ 0x08,0x00, 0x00,0x00 }
+
+#define CMD_MSG_VOIP_TONECTL_LEN 32
+#define CMD_MSG_VOIP_TONECTL(s,c) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, ((c&0xFF00)>>8),(c&0x00FF), 0x0A, 0x00, 0x00,0x02,0x5B,0x80, 0x00,0x00, \
+ 0x00,0x00, 0x00,0x00 }
+
+/* CPU ACK command */
+#define CMD_MSG_ACK_LEN 20
+#define CMD_MSG_ACK(s,c) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s, 0xE0, (c&0x00FF), ((c>>8)&0x00FF) }
+
+/* Wrapper for RTP packets */
+#define CMD_MSG_IP_UDP_RTP_LEN 54
+#define CMD_MSG_IP_UDP_RTP(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x08,0x00, \
+ 0x45,0x00, p1,p2, 0x00,p3, 0x40,0x00, 0x80,0x11, p4,p5, \
+ 0xC0,0xA8,0x09,0x03, 0xC0,0xA8,0x09,0x03, p6,p7, p8,p9, p10,p11, p12,p13, \
+ 0x80,p14, p15,p16, p17,p18,p19,p20, 0x12,0x34,0x56,(s&0xFF)}
+
+#define CMD_MSG_DW_WRITE_LEN 38
+#define CMD_MSG_DW_WRITE(s,a,d) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01,s&0x0F,0x00,0x00,0x00,0x00,0x00,0x04,0x17,0x00,0x00, \
+ ((a>>24)&0x00FF),((a>>16)&0x00FF), ((a>>8)&0x00FF),(a&0x00FF), \
+ ((d>>24)&0x00FF),((d>>16)&0x00FF), ((d>>8)&0x00FF),(d&0x00FF) }
+
+#define CMD_MSG_FORCE_ALERT_LEN 32
+#define CMD_MSG_FORCE_ALERT(s) { \
+ 0x00,0x11,0x22,0x33,0x44,0x55, 0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, 0x88,0x9B, \
+ 0x00,0x01, s&0x0F, 0x01, 0xFF,0xFF, 0x0A, 0x00, 0x00,0x06,0x09,0x04, 0x00,0x00, \
+ 0x24,0x00, 0x00,0x00 }
+
+#define zt_send_cmd(wc, command, length, hex) \
+ ({ \
+ int ret = 0; \
+ do { \
+ if (ret == 2) \
+ { \
+ wc->ztsnd_rtx++; \
+ if (hex == 0x0010) \
+ wc->ztsnd_0010_rtx++; \
+ } \
+ down(&wc->cmdqsem); \
+ wc->last_command_sent = hex; \
+ if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug ) \
+ printk("wcdte error: cmdq is full.\n"); \
+ else { \
+ unsigned char fifo[OTHER_CMD_LEN] = command; \
+ int i; \
+ wc->cmdq[wc->cmdq_wndx].cmdlen = length; \
+ for (i = 0; i < length; i++) \
+ wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i]; \
+ wc->last_seqno = fifo[16]; \
+ wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS; \
+ } \
+ __transmit_demand(wc); \
+ up(&wc->cmdqsem); \
+ if (hex == 0x0000) \
+ ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS_ACK, 2); \
+ else { \
+ ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 0); \
+ if (wc->dsp_crashed) \
+ return 1; \
+ } \
+ if (ret == 1) \
+ return(1); \
+ } while (ret == 2); \
+ })
+
+
+struct cmdq {
+ unsigned int cmdlen;
+ unsigned char cmd[MAX_COMMAND_LEN];
+};
+
+struct wcdte {
+ struct pci_dev *dev;
+ char *variety;
+ unsigned int intcount;
+ unsigned int rxints;
+ unsigned int txints;
+ unsigned int intmask;
+ int pos;
+ int freeregion;
+ int rdbl;
+ int tdbl;
+ int cards;
+ spinlock_t reglock;
+ wait_queue_head_t regq;
+ int rcvflags;
+
+ struct semaphore chansem;
+ struct semaphore cmdqsem;
+ struct cmdq cmdq[MAX_COMMANDS];
+ unsigned int cmdq_wndx;
+ unsigned int cmdq_rndx;
+
+ unsigned int last_seqno;
+ unsigned int last_rseqno;
+ unsigned int last_command_sent;
+ unsigned int last_rcommand;
+ unsigned int last_rparm1;
+ unsigned int seq_num;
+ long timeout;
+
+ unsigned int dsp_crashed;
+ unsigned int dumping;
+
+ unsigned int ztsnd_rtx;
+ unsigned int ztsnd_0010_rtx;
+
+ unsigned char numchannels;
+ unsigned char complexname[40];
+
+ unsigned long iobase;
+ dma_addr_t readdma;
+ dma_addr_t writedma;
+ dma_addr_t descripdma;
+ volatile unsigned int *writechunk; /* Double-word aligned write memory */
+ volatile unsigned int *readchunk; /* Double-word aligned read memory */
+ volatile unsigned int *descripchunk; /* Descriptors */
+
+ int wqueints;
+ struct workqueue_struct *dte_wq;
+ struct work_struct dte_work;
+
+ struct zt_transcoder *uencode;
+ struct zt_transcoder *udecode;
+};
+
+struct wcdte_desc {
+ char *name;
+ int flags;
+};
+
+static struct wcdte_desc wctc400p = { "Wildcard TC400P+TC400M", 0 };
+static struct wcdte_desc wctce400 = { "Wildcard TCE400+TC400M", 0 };
+
+static struct wcdte *ifaces[WC_MAX_IFACES];
+
+
+
+/*
+ * The following is the definition of the state structure
+ * used by the G.721/G.723 encoder and decoder to preserve their internal
+ * state between successive calls. The meanings of the majority
+ * of the state structure fields are explained in detail in the
+ * CCITT Recommendation G.721. The field names are essentially indentical
+ * to variable names in the bit level description of the coding algorithm
+ * included in this Recommendation.
+ */
+struct dte_state {
+ int encoder; /* If we're an encoder */
+ struct wcdte *wc;
+
+ unsigned int timestamp;
+ unsigned int seqno;
+
+ unsigned int cmd_seqno;
+
+ unsigned int timeslot_in_num; /* DTE chennel on which results we be received from */
+ unsigned int timeslot_out_num; /* DTE channel to send data to */
+
+ unsigned int chan_in_num; /* DTE chennel on which results we be received from */
+ unsigned int chan_out_num; /* DTE channel to send data to */
+
+ unsigned int packets_sent;
+ unsigned int packets_received;
+
+ unsigned int last_dte_seqno;
+ unsigned int dte_seqno_rcv;
+
+ unsigned char ssrc;
+};
+
+
+static struct zt_transcoder *uencode;
+static struct zt_transcoder *udecode;
+static struct dte_state *encoders;
+static struct dte_state *decoders;
+static int debug = 0;
+static int debug_des = 0; /* Set the number of descriptor packet bytes to output on errors, 0 disables output */
+static int debug_des_cnt = 0; /* Set the number of times descriptor packets are displayed before the output is disabled */
+static int force_alert = 0;
+static int debug_notimeout = 0;
+static char *mode;
+static int debug_packets = 0;
+
+static int wcdte_create_channel(struct wcdte *wc, int simple, int complicated, int part1_id, int part2_id, unsigned int *dte_chan1, unsigned int *dte_chan2);
+static int wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2);
+static int __wcdte_setup_channels(struct wcdte *wc);
+
+static int __dump_descriptors(struct wcdte *wc)
+{
+ volatile unsigned char *writechunk, *readchunk;
+ int o2, i, j;
+
+ if (debug_des_cnt == 0)
+ return 1;
+
+ printk("Transmit Descriptors (wc->tdbl = %d)\n", wc->tdbl);
+ for (i = 0; i < ERING_SIZE; i++)
+ {
+ writechunk = (volatile unsigned char *)(wc->writechunk);
+ writechunk += i * SFRAME_SIZE;
+ o2 = i * 4;
+
+ if (i == wc->tdbl)
+ printk("->");
+ else
+ printk(" ");
+ if ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000))
+ printk("AN983 owns : ");
+ else
+ printk("Driver owns: ");
+
+ for (j = 0; j < debug_des; j++)
+ printk("%02X ", writechunk[j]);
+ printk("\n");
+ }
+
+ printk("Receive Descriptors (wc->rdbl = %d)\n", wc->rdbl);
+ for (i = 0; i < ERING_SIZE; i++)
+ {
+ readchunk = (volatile unsigned char *)wc->readchunk;
+ readchunk += i * SFRAME_SIZE;
+ o2 = i * 4;
+ o2 += ERING_SIZE * 4;
+
+ if (i == wc->rdbl)
+ printk("->");
+ else
+ printk(" ");
+ if ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000))
+ printk("AN983 owns : ");
+ else
+ printk("Driver owns: ");
+
+ for (j = 0; j < debug_des; j++)
+ printk("%02X ", readchunk[j]);
+ printk("\n");
+ }
+ if (debug_des_cnt > 0)
+ debug_des_cnt--;
+ return 0;
+}
+
+/* Sanity check values */
+static inline int zt_tc_sanitycheck(struct zt_transcode_header *zth, unsigned int outbytes)
+{
+ if (zth->dstoffset >= sizeof(zth->dstdata))
+ return 0;
+ if (zth->dstlen >= sizeof(zth->dstdata))
+ return 0;
+ if (outbytes >= sizeof(zth->dstdata))
+ return 0;
+ if ((zth->dstoffset + zth->dstlen + outbytes) >= sizeof(zth->dstdata))
+ return 0;
+ if (zth->srcoffset >= sizeof(zth->srcdata))
+ return 0;
+ if (zth->srclen >= sizeof(zth->srcdata))
+ return 0;
+ if ((zth->srcoffset + zth->srclen) > sizeof(zth->srcdata))
+ return 0;
+ return 1;
+}
+
+static void dte_init_state(struct dte_state *state_ptr, int encoder, unsigned int channel, struct wcdte *wc)
+{
+ state_ptr->encoder = encoder;
+ state_ptr->wc = wc;
+ state_ptr->timestamp = 0;
+ state_ptr->seqno = 0;
+
+ state_ptr->cmd_seqno = 0;
+
+ state_ptr->packets_sent = 0;
+ state_ptr->packets_received = 0;
+ state_ptr->last_dte_seqno = 0;
+ state_ptr->dte_seqno_rcv = 0;
+
+ state_ptr->chan_in_num = 999;
+ state_ptr->chan_out_num = 999;
+
+ state_ptr->ssrc = 0x78;
+
+ if (encoder == 1)
+ {
+ state_ptr->timeslot_in_num = channel * 2;
+ state_ptr->timeslot_out_num = channel * 2 + 1;
+ } else {
+ state_ptr->timeslot_in_num = channel * 2 + 1;
+ state_ptr->timeslot_out_num = channel * 2;
+ }
+}
+
+static unsigned int wcdte_zapfmt_to_dtefmt(unsigned int fmt)
+{
+ unsigned int pt;
+
+ switch(fmt)
+ {
+ case ZT_FORMAT_G723_1:
+ pt = DTE_FORMAT_G723_1;
+ break;
+ case ZT_FORMAT_ULAW:
+ pt = DTE_FORMAT_ULAW;
+ break;
+ case ZT_FORMAT_ALAW:
+ pt = DTE_FORMAT_ALAW;
+ break;
+ case ZT_FORMAT_G729A:
+ pt = DTE_FORMAT_G729A;
+ break;
+ default:
+ pt = DTE_FORMAT_UNDEF;
+ }
+
+ return(pt);
+}
+
+static inline void __wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
+{
+ outl(val, wc->iobase + addr);
+}
+
+static inline unsigned int __wcdte_getctl(struct wcdte *wc, unsigned int addr)
+{
+ return inl(wc->iobase + addr);
+}
+
+static inline void wcdte_setctl(struct wcdte *wc, unsigned int addr, unsigned int val)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->reglock, flags);
+ __wcdte_setctl(wc, addr, val);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline void wcdte_reinit_descriptor(struct wcdte *wc, int tx, int dbl, char *s)
+{
+ int o2 = 0;
+ o2 += dbl * 4;
+
+ if (!tx)
+ o2 += ERING_SIZE * 4;
+ wc->descripchunk[o2] = cpu_to_le32(0x80000000);
+
+ wcdte_setctl(wc, 0x0008, 0x00000000);
+}
+
+static inline unsigned int wcdte_getctl(struct wcdte *wc, unsigned int addr)
+{
+ unsigned long flags;
+ unsigned int val;
+ spin_lock_irqsave(&wc->reglock, flags);
+ val = __wcdte_getctl(wc, addr);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return val;
+}
+
+static inline int __transmit_demand(struct wcdte *wc)
+{
+ volatile unsigned char *writechunk;
+ int o2,i,j;
+ unsigned int reg, xmt_length;
+
+ reg = wcdte_getctl(wc, 0x0028) & 0x00700000;
+
+ /* Already transmiting, no need to demand another */
+ if (!((reg == 0) || (reg = 6)))
+ return(1);
+
+ /* Nothing to transmit */
+ if (wc->cmdq_rndx == wc->cmdq_wndx)
+ return(1);
+
+ /* Nothing to transmit */
+ if (wc->cmdq[wc->cmdq_rndx].cmdlen == 0 )
+ return(1);
+
+ writechunk = (volatile unsigned char *)(wc->writechunk);
+
+ writechunk += wc->tdbl * SFRAME_SIZE;
+
+ o2 = wc->tdbl * 4;
+
+ do
+ {
+ } while ((le32_to_cpu(wc->descripchunk[o2]) & 0x80000000));
+
+ xmt_length = wc->cmdq[wc->cmdq_rndx].cmdlen;
+ if (xmt_length < 64)
+ xmt_length = 64;
+
+ wc->descripchunk[o2+1] = cpu_to_le32((le32_to_cpu(wc->descripchunk[o2+1]) & 0xFBFFF800) | xmt_length);
+
+ for(i = 0; i < wc->cmdq[wc->cmdq_rndx].cmdlen; i++)
+ writechunk[i] = wc->cmdq[wc->cmdq_rndx].cmd[i];
+ for (j = i; j < xmt_length; j++)
+ writechunk[j] = 0;
+
+ if (debug_packets && (writechunk[12] == 0x88) && (writechunk[13] == 0x9B))
+ {
+ printk("wcdte debug: TX: ");
+ for (i=0; i<debug_packets; i++)
+ printk("%02X ", writechunk[i]);
+ printk("\n");
+ }
+
+ wc->cmdq[wc->cmdq_rndx].cmdlen = 0;
+
+ wc->descripchunk[o2] = cpu_to_le32(0x80000000);
+ wcdte_setctl(wc, 0x0008, 0x00000000); /* Transmit Poll Demand */
+
+ wc->tdbl = (wc->tdbl + 1) % ERING_SIZE;
+
+ wc->cmdq_rndx = (wc->cmdq_rndx + 1) % MAX_COMMANDS;
+
+ return(0);
+}
+
+static inline int transmit_demand(struct wcdte *wc)
+{
+ int val;
+ down(&wc->cmdqsem);
+ val = __transmit_demand(wc);
+ up(&wc->cmdqsem);
+ return val;
+}
+
+static int dte_operation(struct zt_transcoder_channel *ztc, int op)
+{
+ struct zt_transcoder_channel *compl_ztc;
+ struct dte_state *st = ztc->pvt, *compl_st;
+ struct zt_transcode_header *zth = ztc->tch;
+ struct wcdte *wc = st->wc;
+ unsigned char *chars;
+ unsigned int inbytes = 0;
+ unsigned int timestamp_inc = 0;
+ int i = 0;
+ int res = 0;
+ unsigned int ipchksum, ndx;
+ switch(op) {
+ case ZT_TCOP_ALLOCATE:
+ down(&wc->chansem);
+ if (ztc->chan_built == 0)
+ {
+ if (st->encoder == 1)
+ wcdte_create_channel(wc, wcdte_zapfmt_to_dtefmt(zth->srcfmt), wcdte_zapfmt_to_dtefmt(zth->dstfmt),
+ st->timeslot_in_num, st->timeslot_out_num, &(st->chan_in_num), &(st->chan_out_num));
+ else
+ wcdte_create_channel(wc, wcdte_zapfmt_to_dtefmt(zth->dstfmt), wcdte_zapfmt_to_dtefmt(zth->srcfmt),
+ st->timeslot_out_num, st->timeslot_in_num, &(st->chan_out_num), &(st->chan_in_num));
+ /* Mark this channel as built */
+ ztc->chan_built = 1;
+ ztc->built_fmts = zth->dstfmt | zth->srcfmt;
+
+ /* Mark the channel complement (other half of encoder/decoder pair) as built */
+ ndx = st->timeslot_in_num/2;
+ if (st->encoder == 1)
+ compl_ztc = &(wc->udecode->channels[ndx]);
+ else
+ compl_ztc = &(wc->uencode->channels[ndx]);
+ compl_ztc->chan_built = 1;
+ compl_ztc->built_fmts = zth->dstfmt | zth->srcfmt;
+ compl_st = compl_ztc->pvt;
+ compl_st->chan_in_num = st->chan_out_num;
+ compl_st->chan_out_num = st->chan_in_num;
+ }
+ up(&wc->chansem);
+ break;
+ case ZT_TCOP_RELEASE:
+ down(&wc->chansem);
+ ndx = st->timeslot_in_num/2;
+
+ if (st->encoder == 1)
+ compl_ztc = &(wc->udecode->channels[ndx]);
+ else
+ compl_ztc = &(wc->uencode->channels[ndx]);
+
+ /* If the channel complement (other half of the encoder/decoder pair) is not being used... */
+ if ((compl_ztc->flags & ZT_TC_FLAG_BUSY) == 0)
+ {
+ if (st->encoder == 1)
+ wcdte_destroy_channel(wc, st->chan_in_num, st->chan_out_num);
+ else
+ wcdte_destroy_channel(wc, st->chan_out_num, st->chan_in_num);
+
+ /* Mark this channel as not built */
+ ztc->chan_built = 0;
+ ztc->built_fmts = 0;
+ st->chan_in_num = 999;
+ st->chan_out_num = 999;
+
+ /* Mark the channel complement as not built */
+ compl_ztc->chan_built = 0;
+ compl_ztc->built_fmts = 0;
+ compl_st = compl_ztc->pvt;
+ compl_st->chan_in_num = 999;
+ compl_st->chan_out_num = 999;
+ }
+ st->dte_seqno_rcv = 0;
+ up(&wc->chansem);
+ break;
+ case ZT_TCOP_TRANSCODE:
+ if ( (((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) && ((zth->dstfmt == ZT_FORMAT_G729A && zth->srclen >= G729_SAMPLES) ||(zth->dstfmt == ZT_FORMAT_G723_1 && zth->srclen >= G723_SAMPLES)) )
+ || ((zth->srcfmt == ZT_FORMAT_G729A) && (zth->srclen >= G729_BYTES))
+ || ((zth->srcfmt == ZT_FORMAT_G723_1) && (zth->srclen >= G723_SID_BYTES)) )
+ {
+ do
+ {
+ chars = (unsigned char *)(zth->srcdata + zth->srcoffset);
+
+ if ((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) {
+ if (zth->dstfmt == ZT_FORMAT_G729A) {
+ inbytes = G729_SAMPLES;
+ timestamp_inc = G729_SAMPLES;
+ } else if (zth->dstfmt == ZT_FORMAT_G723_1) {
+ inbytes = G723_SAMPLES;
+ timestamp_inc = G723_SAMPLES;
+ }
+ } else if (zth->srcfmt == ZT_FORMAT_G729A) {
+ inbytes = G729_BYTES;
+ timestamp_inc = G729_SAMPLES;
+ } else if (zth->srcfmt == ZT_FORMAT_G723_1) {
+ /* determine the size of the frame */
+ switch (chars[0] & 0x03) {
+ case 0x00:
+ inbytes = G723_6K_BYTES;
+ break;
+ case 0x01:
+ inbytes = G723_5K_BYTES;
+ break;
+ case 0x02:
+ inbytes = G723_SID_BYTES;
+ break;
+ case 0x03:
+ /* this is a 'reserved' value in the G.723.1
+ spec and should never occur in real media streams */
+ inbytes = G723_SID_BYTES;
+ break;
+ }
+ timestamp_inc = G723_SAMPLES;
+ }
+
+ zth->srclen -= inbytes;
+
+ {
+ unsigned char fifo[OTHER_CMD_LEN] = CMD_MSG_IP_UDP_RTP(
+ ((inbytes+40) >> 8) & 0xFF,
+ (inbytes+40) & 0xFF,
+ st->seqno & 0xFF,
+ 0x00,
+ 0x00,
+ (((st->timeslot_out_num) >> 8)+0x50) & 0xFF,
+ (st->timeslot_out_num) & 0xFF,
+ (((st->timeslot_in_num) >> 8)+0x50) & 0xFF,
+ (st->timeslot_in_num) & 0xFF,
+ ((inbytes+20) >> 8) & 0xFF,
+ (inbytes+20) & 0xFF,
+ 0x00,
+ 0x00,
+ wcdte_zapfmt_to_dtefmt(zth->srcfmt),
+ ((st->seqno) >> 8) & 0xFF,
+ (st->seqno) & 0xFF,
+ ((st->timestamp) >> 24) & 0xFF,
+ ((st->timestamp) >> 16) & 0xFF,
+ ((st->timestamp) >> 8) & 0xFF,
+ (st->timestamp) & 0xFF,
+ (st->ssrc) & 0xFF);
+
+ ipchksum = 0x9869 + (fifo[16] << 8) + fifo[17]
+ + (fifo[18] << 8) + fifo[19];
+ while (ipchksum >> 16)
+ ipchksum = (ipchksum & 0xFFFF) + (ipchksum >> 16);
+ ipchksum = (~ipchksum) & 0xFFFF;
+
+ fifo[24] = ipchksum >> 8;
+ fifo[25] = ipchksum & 0xFF;
+
+ st->seqno += 1;
+ st->timestamp += timestamp_inc;
+
+ for (i = 0; i < inbytes; i++)
+ fifo[i+CMD_MSG_IP_UDP_RTP_LEN]= chars[i];
+
+ down(&wc->cmdqsem);
+
+ if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug )
+ printk("wcdte error: cmdq is full.\n");
+ else
+ {
+ wc->cmdq[wc->cmdq_wndx].cmdlen = CMD_MSG_IP_UDP_RTP_LEN+inbytes;
+ for (i = 0; i < CMD_MSG_IP_UDP_RTP_LEN+inbytes; i++)
+ wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i];
+ wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS;
+ }
+
+ __transmit_demand(wc);
+ up(&wc->cmdqsem);
+ }
+ st->packets_sent++;
+
+
+
+ zth->srcoffset += inbytes;
+
+
+ } while ((((zth->srcfmt == ZT_FORMAT_ULAW) || (zth->srcfmt == ZT_FORMAT_ALAW)) && ((zth->dstfmt == ZT_FORMAT_G729A && zth->srclen >= G729_SAMPLES) ||(zth->dstfmt == ZT_FORMAT_G723_1 && zth->srclen >= G723_SAMPLES)) )
+ || ((zth->srcfmt == ZT_FORMAT_G729A) && (zth->srclen >= G729_BYTES))
+ || ((zth->srcfmt == ZT_FORMAT_G723_1) && (zth->srclen >= G723_SID_BYTES)) );
+
+ } else {
+ zt_transcoder_alert(ztc);
+ }
+
+ res = 0;
+ break;
+ }
+ return res;
+}
+
+static void wcdte_stop_dma(struct wcdte *wc);
+
+static inline void wcdte_receiveprep(struct wcdte *wc, int dbl)
+{
+ volatile unsigned char *readchunk;
+ struct zt_transcoder_channel *ztc = NULL;
+ struct zt_transcode_header *zth = NULL;
+ struct dte_state *st = NULL;
+ int o2,i;
+ unsigned char rseq, rcodec;
+ unsigned int rcommand, rchannel, rlen, rtp_rseq, rtp_eseq;
+ unsigned char *chars = NULL;
+ unsigned int ztc_ndx;
+
+ readchunk = (volatile unsigned char *)wc->readchunk;
+ readchunk += dbl * SFRAME_SIZE;
+
+ o2 = dbl * 4;
+ o2 += ERING_SIZE * 4;
+
+ /* Control in packet */
+ if ((readchunk[12] == 0x88) && (readchunk[13] == 0x9B))
+ {
+ if (debug_packets)
+ {
+ printk("wcdte debug: RX: ");
+ for (i=0; i<debug_packets; i++)
+ printk("%02X ", readchunk[i]);
+ printk("\n");
+ }
+ /* See if message must be ACK'd */
+ if ((readchunk[17] & 0x80) == 0)
+ {
+ rcommand = readchunk[24] | (readchunk[25] << 8);
+ rchannel = readchunk[18] | (readchunk[19] << 8);
+ rseq = readchunk[16];
+
+ down(&wc->cmdqsem);
+ if ((readchunk[17] & 0x40) == 0) {
+ if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug )
+ printk("wcdte error: cmdq is full (rndx = %d, wndx = %d).\n", wc->cmdq_rndx, wc->cmdq_wndx);
+ else
+ {
+ unsigned char fifo[OTHER_CMD_LEN] = CMD_MSG_ACK(rseq++, rchannel);
+
+ wc->cmdq[wc->cmdq_wndx].cmdlen = CMD_MSG_ACK_LEN;
+ for (i = 0; i < wc->cmdq[wc->cmdq_wndx].cmdlen; i++)
+ wc->cmdq[wc->cmdq_wndx].cmd[i] = fifo[i];
+ wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS;
+ }
+
+ __transmit_demand(wc);
+ }
+
+ wc->rcvflags = RCV_CSMENCAPS;
+ if (rcommand == wc->last_command_sent) {
+ wc->last_rcommand = rcommand;
+ wc->last_rparm1 = readchunk[28] | (readchunk[29] << 8);
+ wake_up(&wc->regq);
+ } else {
+ if (debug)
+ printk("wcdte error: unexpected command response received (sent: %04X, received: %04X)\n", wc->last_command_sent, rcommand);
+ }
+ up(&wc->cmdqsem);
+ }
+ else
+ {
+ wc->last_rseqno = readchunk[16];
+ wc->rcvflags = RCV_CSMENCAPS_ACK;
+ if (!wc->dumping)
+ wake_up_interruptible(&wc->regq);
+ else
+ wake_up(&wc->regq);
+ }
+
+ if ((readchunk[22] == 0x75) && (readchunk[23] = 0xC1))
+ {
+ if (debug)
+ printk("wcdte error: received alert (0x%02X%02X) from dsp\n", readchunk[29], readchunk[28]);
+ if (debug_des) {
+ down(&wc->cmdqsem);
+ __dump_descriptors(wc);
+ up(&wc->cmdqsem);
+ }
+ }
+
+ if (wc->dumping && (readchunk[22] == 0x04) && (readchunk[23] = 0x14)) {
+ for (i = 27; i < 227; i++)
+ printk("%02X ", readchunk[i]);
+ printk("\n");
+ }
+ }
+
+ /* IP/UDP in packet */
+ else if ((readchunk[12] == 0x08) && (readchunk[13] == 0x00)
+ && (readchunk[50] == 0x12) && (readchunk[51] == 0x34) && (readchunk[52] = 0x56) && (readchunk[53] == 0x78))
+ {
+ rchannel = (readchunk[37] | (readchunk[36] << 8)) - 0x5000;
+ rlen = (readchunk[39] | (readchunk[38] << 8)) - 20;
+ rtp_rseq = (readchunk[45] | (readchunk[44] << 8));
+ rcodec = readchunk[43];
+
+ ztc_ndx = rchannel/2;
+
+ if (ztc_ndx >= wc->numchannels)
+ {
+ if (debug)
+ printk("wcdte error: Invalid channel number received (ztc_ndx = %d) (numchannels = %d)\n", ztc_ndx, wc->numchannels);
+ rcodec = DTE_FORMAT_UNDEF;
+ }
+
+ if ((rcodec == 0x00) || (rcodec == 0x08)) /* ulaw or alaw (decoders) */
+ {
+ ztc = &(wc->udecode->channels[ztc_ndx]);
+ zth = ztc->tch;
+ st = ztc->pvt;
+
+ if (zth == NULL)
+ {
+ if (debug)
+ printk("wcdte error: Tried to put DTE data into a freed zth header! (ztc_ndx = %d, ztc->chan_built = %d)\n", ztc_ndx, ztc->chan_built);
+ if (debug_des) {
+ down(&wc->cmdqsem);
+ __dump_descriptors(wc);
+ up(&wc->cmdqsem);
+ }
+ rcodec = DTE_FORMAT_UNDEF;
+ } else {
+ chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen);
+ st->packets_received++;
+ }
+
+ }
+
+ if ((rcodec == 0x04) || (rcodec == 0x12)) /* g.723 or g.729 (encoders) */
+ {
+ ztc = &(wc->uencode->channels[ztc_ndx]);
+ zth = ztc->tch;
+ st = ztc->pvt;
+
+ if (zth == NULL)
+ {
+ if (debug)
+ printk("wcdte error: Tried to put DTE data into a freed zth header! (ztc_ndx = %d, ztc->chan_built = %d)\n", ztc_ndx, ztc->chan_built);
+ if (debug_des) {
+ down(&wc->cmdqsem);
+ __dump_descriptors(wc);
+ up(&wc->cmdqsem);
+ }
+ rcodec = DTE_FORMAT_UNDEF;
+ } else {
+ chars = (unsigned char *)(zth->dstdata + zth->dstoffset + zth->dstlen);
+ st->packets_received++;
+ }
+
+ }
+
+ if (st->dte_seqno_rcv == 0)
+ {
+ st->dte_seqno_rcv = 1;
+ st->last_dte_seqno = rtp_rseq;
+ } else {
+ rtp_eseq = (st->last_dte_seqno + 1) & 0xFFFF;
+ if ( (rtp_rseq != rtp_eseq) && debug )
+ printk("wcdte error: Bad seqno from DTE! [%04X][%d][%d][%d]\n", (readchunk[37] | (readchunk[36] << 8)), rchannel, rtp_rseq, st->last_dte_seqno);
+
+ st->last_dte_seqno = rtp_rseq;
+ }
+
+ if (rcodec == 0x00) /* ulaw */
+ {
+ if (zt_tc_sanitycheck(zth, rlen) && ((zth->srcfmt == ZT_FORMAT_G729A && rlen == G729_SAMPLES) || (zth->srcfmt == ZT_FORMAT_G723_1 && rlen == G723_SAMPLES))) {
+ for (i = 0; i < rlen; i++)
+ chars[i] = readchunk[i+54];
+
+ zth->dstlen += rlen;
+ zth->dstsamples = zth->dstlen;
+
+ } else {
+ ztc->errorstatus = -EOVERFLOW;
+ }
+ zt_transcoder_alert(ztc);
+ }
+ else if (rcodec == 0x08) /* alaw */
+ {
+ if (zt_tc_sanitycheck(zth, rlen) && ((zth->srcfmt == ZT_FORMAT_G729A && rlen == G729_SAMPLES) || (zth->srcfmt == ZT_FORMAT_G723_1 && rlen == G723_SAMPLES))) {
+
+ for (i = 0; i < rlen; i++)
+ chars[i] = readchunk[i+54];
+
+ zth->dstlen += rlen;
+ zth->dstsamples = zth->dstlen;
+
+ } else {
+ ztc->errorstatus = -EOVERFLOW;
+ }
+ zt_transcoder_alert(ztc);
+ }
+ else if (rcodec == 0x04) /* G.723.1 */
+ {
+ if (zt_tc_sanitycheck(zth, rlen) &&
+ ((rlen == G723_6K_BYTES) || (rlen == G723_5K_BYTES) || (rlen == G723_SID_BYTES)))
+ {
+ for (i = 0; i < rlen; i++)
+ chars[i] = readchunk[i+54];
+
+ zth->dstlen += rlen;
+ zth->dstsamples += G723_SAMPLES;
+
+ } else {
+ ztc->errorstatus = -EOVERFLOW;
+ }
+
+ if (!(zth->dstsamples % G723_SAMPLES))
+ {
+ zt_transcoder_alert(ztc);
+ }
+ }
+ else if (rcodec == 0x12) /* G.729a */
+ {
+ if (zt_tc_sanitycheck(zth, rlen) && (rlen == G729_BYTES))
+ {
+ for (i = 0; i < rlen; i++)
+ chars[i] = readchunk[i+54];
+
+ zth->dstlen += rlen;
+ zth->dstsamples = zth->dstlen * 8;
+
+ } else {
+ ztc->errorstatus = -EOVERFLOW;
+ }
+
+ if (!(zth->dstsamples % G729_SAMPLES))
+ {
+ zt_transcoder_alert(ztc);
+ }
+ }
+ }
+}
+
+
+
+
+
+/* static inline int wcdte_check_descriptor(struct wcdte *wc) */
+static int wcdte_check_descriptor(struct wcdte *wc)
+{
+ int o2 = 0;
+
+ o2 += ERING_SIZE * 4;
+ o2 += wc->rdbl * 4;
+
+ if (!(le32_to_cpu(wc->descripchunk[o2]) & 0x80000000)) {
+ wc->rxints++;
+ wcdte_receiveprep(wc, wc->rdbl);
+ wcdte_reinit_descriptor(wc, 0, wc->rdbl, "rxchk");
+ wc->rdbl = (wc->rdbl + 1) % ERING_SIZE;
+
+ return 1;
+ }
+ return 0;
+}
+
+static void wcdte_init_descriptors(struct wcdte *wc)
+{
+ volatile unsigned int *descrip;
+ dma_addr_t descripdma;
+ dma_addr_t writedma;
+ dma_addr_t readdma;
+ int x;
+
+ descrip = wc->descripchunk;
+ descripdma = wc->descripdma;
+ writedma = wc->writedma;
+ readdma = wc->readdma;
+
+ for (x=0;x<ERING_SIZE;x++) {
+ if (x < ERING_SIZE - 1)
+ descripdma += 16;
+ else
+ descripdma = wc->descripdma;
+
+ /* Transmit descriptor */
+ descrip[0 ] = cpu_to_le32(0x00000000);
+ descrip[1 ] = cpu_to_le32(0xe5800000 | (SFRAME_SIZE));
+ descrip[2 ] = cpu_to_le32(writedma + x*SFRAME_SIZE);
+ descrip[3 ] = cpu_to_le32(descripdma);
+
+ /* Receive descriptor */
+ descrip[0 + ERING_SIZE * 4] = cpu_to_le32(0x80000000);
+ descrip[1 + ERING_SIZE * 4] = cpu_to_le32(0x01000000 | (SFRAME_SIZE));
+ descrip[2 + ERING_SIZE * 4] = cpu_to_le32(readdma + x*SFRAME_SIZE);
+ descrip[3 + ERING_SIZE * 4] = cpu_to_le32(descripdma + ERING_SIZE * 16);
+
+ /* Advance descriptor */
+ descrip += 4;
+ }
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+static void dte_wque_run(struct work_struct *work)
+{
+ struct wcdte *wc = container_of(work, struct wcdte, dte_work);
+#else
+static void dte_wque_run(void *work_data)
+{
+ struct wcdte *wc = work_data;
+#endif
+ int res;
+
+ do {
+ res = wcdte_check_descriptor(wc);
+ } while(res);
+
+ transmit_demand(wc);
+}
+
+ZAP_IRQ_HANDLER(wcdte_interrupt)
+{
+ struct wcdte *wc = dev_id;
+ unsigned int ints;
+
+ /* Read and clear interrupts */
+ ints = wcdte_getctl(wc, 0x0028);
+ wcdte_setctl(wc, 0x0028, ints);
+
+ if (!ints)
+ return IRQ_NONE;
+ ints &= wc->intmask;
+
+ if (ints & 0x00000041) {
+ wc->wqueints = ints;
+ queue_work(wc->dte_wq, &wc->dte_work);
+ }
+
+ if ((ints & 0x00008000) && debug)
+ printk("wcdte: Abnormal Interrupt: ");
+
+ if ((ints & 0x00002000) && debug)
+ printk("wcdte: Fatal Bus Error INT\n");
+
+ if ((ints & 0x00000100) && debug)
+ printk("wcdte: Receive Stopped INT\n");
+
+ if ((ints & 0x00000080) && debug)
+ printk("wcdte: Receive Desciptor Unavailable INT\n");
+
+ if ((ints & 0x00000020) && debug)
+ printk("wcdte: Transmit Under-flow INT\n");
+
+ if ((ints & 0x00000008) && debug)
+ printk("wcdte: Jabber Timer Time-out INT\n");
+
+ if ((ints & 0x00000004) && debug)
+ printk("wcdte: Transmit Descriptor Unavailable INT\n");
+
+ if ((ints & 0x00000002) && debug)
+ printk("wcdte: Transmit Processor Stopped INT\n");
+
+ return IRQ_RETVAL(1);
+
+}
+
+static int wcdte_hardware_init(struct wcdte *wc)
+{
+ /* Hardware stuff */
+ unsigned int reg;
+ unsigned long newjiffies;
+
+ /* Initialize descriptors */
+ wcdte_init_descriptors(wc);
+
+ /* Enable I/O Access */
+ pci_read_config_dword(wc->dev, 0x0004, &reg);
+ reg |= 0x00000007;
+ pci_write_config_dword(wc->dev, 0x0004, reg);
+
+ wcdte_setctl(wc, 0x0000, 0xFFF88001);
+
+ newjiffies = jiffies + HZ/10;
+ while(((reg = wcdte_getctl(wc,0x0000)) & 0x00000001) && (newjiffies > jiffies));
+
+ wcdte_setctl(wc, 0x0000, 0xFFFA0000);
+
+ /* Configure watchdogs, access, etc */
+ wcdte_setctl(wc, 0x0030, 0x00280048);
+ wcdte_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */);
+
+ reg = wcdte_getctl(wc, 0x00fc);
+ wcdte_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7);
+
+ reg = wcdte_getctl(wc, 0x00fc);
+
+ return 0;
+}
+
+static void wcdte_setintmask(struct wcdte *wc, unsigned int intmask)
+{
+ wc->intmask = intmask;
+ wcdte_setctl(wc, 0x0038, intmask);
+}
+
+static void wcdte_enable_interrupts(struct wcdte *wc)
+{
+ /* Enable interrupts */
+ if (!debug)
+ wcdte_setintmask(wc, 0x00010041);
+ else
+ wcdte_setintmask(wc, 0x0001A1EB);
+}
+
+static void wcdte_start_dma(struct wcdte *wc)
+{
+ unsigned int reg;
+ wmb();
+ wcdte_setctl(wc, 0x0020, wc->descripdma);
+ wcdte_setctl(wc, 0x0018, wc->descripdma + (16 * ERING_SIZE));
+ /* Start receiver/transmitter */
+ reg = wcdte_getctl(wc, 0x0030);
+ wcdte_setctl(wc, 0x0030, reg | 0x00002002); /* Start XMT and RCD */
+ wcdte_setctl(wc, 0x0010, 0x00000000); /* Receive Poll Demand */
+ reg = wcdte_getctl(wc, 0x0028);
+ wcdte_setctl(wc, 0x0028, reg);
+
+}
+
+static void wcdte_stop_dma(struct wcdte *wc)
+{
+ /* Disable interrupts and reset */
+ unsigned int reg;
+ /* Disable interrupts */
+ wcdte_setintmask(wc, 0x00000000);
+ wcdte_setctl(wc, 0x0084, 0x00000000);
+ wcdte_setctl(wc, 0x0048, 0x00000000);
+ /* Reset the part to be on the safe side */
+ reg = wcdte_getctl(wc, 0x0000);
+ reg |= 0x00000001;
+ wcdte_setctl(wc, 0x0000, reg);
+}
+
+static void wcdte_disable_interrupts(struct wcdte *wc)
+{
+ /* Disable interrupts */
+ wcdte_setintmask(wc, 0x00000000);
+ wcdte_setctl(wc, 0x0084, 0x00000000);
+}
+
+static int wcdte_waitfor_csmencaps(struct wcdte *wc, unsigned int mask, int wait_mode)
+{
+ int ret;
+
+
+ if (wait_mode == 1)
+ ret = wait_event_interruptible_timeout(wc->regq, (wc->rcvflags == mask), wc->timeout);
+ else if (wait_mode == 2)
+ ret = wait_event_timeout(wc->regq, (wc->rcvflags == mask), wc->timeout);
+ else {
+ if (!debug_notimeout) {
+ ret = wait_event_timeout(wc->regq, ((wc->last_rcommand == wc->last_command_sent) && (wc->last_seqno == wc->last_rseqno) && (wc->rcvflags == mask)), wc->timeout);
+ }
+ else {
+ ret = wait_event_interruptible(wc->regq, ((wc->last_rcommand == wc->last_command_sent) && (wc->last_seqno == wc->last_rseqno) && (wc->rcvflags == mask)));
+ if (ret == 0)
+ ret = 1;
+ }
+ }
+ wc->rcvflags = 0;
+ wc->last_rcommand = 0;
+ wc->last_seqno = 0;
+
+ if (ret < 0)
+ {
+ if (debug)
+ printk("wcdte error: Wait interrupted, need to stop boot (ret = %d)\n", ret);
+ return(1);
+ }
+ if (ret == 0)
+ {
+ if (debug)
+ printk("wcdte error: Waitfor CSMENCAPS response timed out (ret = %d) (cmd_snt = %04X)\n", ret, wc->last_command_sent);
+ if (debug_des) {
+ down(&wc->cmdqsem);
+ __dump_descriptors(wc);
+ up(&wc->cmdqsem);
+ }
+ return(2);
+ }
+ if (wait_mode == 0)
+ wc->last_command_sent = 999;
+ wc->last_rseqno = 999;
+ return(0);
+}
+
+
+static int wcdte_read_phy(struct wcdte *wc, int location)
+{
+ int i;
+ long mdio_addr = 0x0048;
+ int read_cmd = (0xf6 << 10) | (1 << 5) | location;
+ int retval = 0;
+
+ /* Establish sync by sending at least 32 logic ones. */
+ for (i = 32; i >= 0; i--) {
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1);
+ wcdte_getctl(wc, mdio_addr);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
+ wcdte_getctl(wc, mdio_addr);
+ }
+ /* Shift the read command bits out. */
+ for (i = 17; i >= 0; i--) {
+ int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval);
+ wcdte_getctl(wc, mdio_addr);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK);
+ wcdte_getctl(wc, mdio_addr);
+ }
+
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN);
+ wcdte_getctl(wc, mdio_addr);
+ retval = (retval << 1) | ((wcdte_getctl(wc, mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
+ wcdte_getctl(wc, mdio_addr);
+ }
+ retval = (retval>>1) & 0xffff;
+ return retval;
+}
+
+void wcdte_write_phy(struct wcdte *wc, int location, int value)
+{
+ int i;
+ int cmd = (0x5002 << 16) | (1 << 23) | (location<<18) | value;
+ long mdio_addr = 0x0048;
+
+ /* Establish sync by sending 32 logic ones. */
+ for (i = 32; i >= 0; i--) {
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1);
+ wcdte_getctl(wc, mdio_addr);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
+ wcdte_getctl(wc, mdio_addr);
+ }
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval);
+ wcdte_getctl(wc, mdio_addr);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB | dataval | MDIO_SHIFT_CLK);
+ wcdte_getctl(wc, mdio_addr);
+ }
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN);
+ wcdte_getctl(wc, mdio_addr);
+ wcdte_setctl(wc, mdio_addr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
+ wcdte_getctl(wc, mdio_addr);
+ }
+ return;
+}
+
+static int wcdte_boot_processor(struct wcdte *wc, const struct firmware *firmware, int full)
+{
+ int i, j, byteloc, last_byteloc, length, delay_count;
+ unsigned int reg, ret;
+
+#ifndef USE_TEST_HW
+ /* Turn off auto negotiation */
+ wcdte_write_phy(wc, 0, 0x2100);
+ if (debug)
+ printk("wcdte: PHY register 0 = %X", wcdte_read_phy(wc, 0));
+
+ /* Set reset */
+ wcdte_setctl(wc, 0x00A0, 0x04000000);
+
+ /* Wait 1000msec to ensure processor reset */
+ mdelay(4);
+
+ /* Clear reset */
+ wcdte_setctl(wc, 0x00A0, 0x04080000);
+
+ /* Waitfor ethernet link */
+ delay_count = 0;
+ do
+ {
+ reg = wcdte_getctl(wc, 0x00fc);
+ mdelay(2);
+ delay_count++;
+
+ if (delay_count >= 5000)
+ {
+ printk("wcdte error: Failed to link to DTE processor!\n");
+ return(1);
+ }
+ } while ((reg & 0xE0000000) != 0xE0000000);
+
+
+ /* Turn off booted LED */
+ wcdte_setctl(wc, 0x00A0, 0x04084000);
+
+
+#endif
+
+ reg = wcdte_getctl(wc, 0x00fc);
+ if (debug)
+ printk("wcdte: LINK STATUS: reg(0xfc) = %X\n", reg);
+
+ reg = wcdte_getctl(wc, 0x00A0);
+
+ byteloc = 17;
+ j = 0;
+ do
+ {
+ last_byteloc = byteloc;
+
+ length = (firmware->data[byteloc] << 8) |firmware->data[byteloc+1];
+ byteloc += 2;
+
+ down(&wc->cmdqsem);
+ if ( (((wc->cmdq_wndx + 1) % MAX_COMMANDS) == wc->cmdq_rndx) && debug )
+ printk("wcdte error: cmdq is full.\n");
+ else
+ {
+ wc->cmdq[wc->cmdq_wndx].cmdlen = length;
+ for (i = 0; i < length; i++)
+ wc->cmdq[wc->cmdq_wndx].cmd[i] = firmware->data[byteloc++];
+ wc->cmdq_wndx = (wc->cmdq_wndx + 1) % MAX_COMMANDS;
+ }
+
+ ret = __transmit_demand(wc);
+ up(&wc->cmdqsem);
+
+ ret = wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS_ACK, 1);
+ if (ret == 1)
+ return(1);
+ else if (ret == 2) /* Retransmit if dte processor times out */
+ byteloc = last_byteloc;
+ j++;
+
+ if (!full && (byteloc > 189)) { /* Quit if not fully booting */
+ wcdte_setctl(wc, 0x00A0, 0x04080000);
+ return 0;
+ }
+
+
+ } while (byteloc < firmware->size-20);
+ wc->timeout = 10 * HZ;
+ wc->last_command_sent = 0;
+ if (wcdte_waitfor_csmencaps(wc, RCV_CSMENCAPS, 1))
+ return(1);
+
+ /* Turn on booted LED */
+ wcdte_setctl(wc, 0x00A0, 0x04080000);
+ if(debug)
+ printk("wcdte: Successfully booted DTE processor.\n");
+
+ return(0);
+}
+
+static int wcdte_create_channel(struct wcdte *wc, int simple, int complicated, int part1_id, int part2_id, unsigned int *dte_chan1, unsigned int *dte_chan2)
+{
+ int length = 0;
+ unsigned char chan1, chan2;
+ struct zt_transcoder_channel *ztc1, *ztc2;
+ struct dte_state *st1, *st2;
+ if(complicated == DTE_FORMAT_G729A)
+ length = G729_LENGTH;
+ else if (complicated == DTE_FORMAT_G723_1)
+ length = G723_LENGTH;
+
+ /* Create complex channel */
+ zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part1_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010);
+ zt_send_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part1_id), CMD_MSG_QUERY_CHANNEL_LEN, 0x0010);
+ chan1 = wc->last_rparm1;
+
+ /* Create simple channel */
+ zt_send_cmd(wc, CMD_MSG_CREATE_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_CREATE_CHANNEL_LEN, 0x0010);
+ zt_send_cmd(wc, CMD_MSG_QUERY_CHANNEL(wc->seq_num++, part2_id), CMD_MSG_QUERY_CHANNEL_LEN, 0x0010);
+ chan2 = wc->last_rparm1;
+
+ ztc1 = &(wc->uencode->channels[part1_id/2]);
+ ztc2 = &(wc->udecode->channels[part2_id/2]);
+ st1 = ztc1->pvt;
+ st2 = ztc2->pvt;
+
+ /* Configure complex channel */
+ zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(st1->cmd_seqno++, chan1, part2_id, part1_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st1->cmd_seqno++, chan1, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001);
+
+ /* Configure simple channel */
+ zt_send_cmd(wc, CMD_MSG_SET_IP_HDR_CHANNEL(st2->cmd_seqno++, chan2, part1_id, part2_id), CMD_MSG_SET_IP_HDR_CHANNEL_LEN, 0x9000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VCEOPT(st2->cmd_seqno++, chan2, length, 0), CMD_MSG_VOIP_VCEOPT_LEN, 0x8001);
+
+#ifdef QUIET_DSP
+ zt_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_TONECTL_LEN, 0x805B);
+ zt_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002);
+ zt_send_cmd(wc, CMD_MSG_VOIP_TONECTL(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_TONECTL_LEN, 0x805B);
+ zt_send_cmd(wc, CMD_MSG_VOIP_DTMFOPT(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_DTMFOPT_LEN, 0x8002);
+ zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084);
+ zt_send_cmd(wc, CMD_MSG_VOIP_INDCTRL(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_INDCTRL_LEN, 0x8084);
+#endif
+
+ zt_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 1, chan1, chan2, complicated, simple), CMD_MSG_TRANS_CONNECT_LEN, 0x9322);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(st1->cmd_seqno++, chan1, complicated), CMD_MSG_VOIP_VOPENA_LEN, 0x8000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA(st2->cmd_seqno++, chan2, simple), CMD_MSG_VOIP_VOPENA_LEN, 0x8000);
+
+ *dte_chan1 = chan1;
+ *dte_chan2 = chan2;
+
+ return 1;
+}
+
+static int wcdte_destroy_channel(struct wcdte *wc, unsigned int chan1, unsigned int chan2)
+{
+ struct zt_transcoder_channel *ztc1, *ztc2;
+ struct dte_state *st1, *st2;
+
+ ztc1 = &(wc->uencode->channels[chan1/2]);
+ ztc2 = &(wc->udecode->channels[chan2/2]);
+ st1 = ztc1->pvt;
+ st2 = ztc2->pvt;
+
+ /* Turn off both channels */
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(st1->cmd_seqno++, chan1), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000);
+ zt_send_cmd(wc, CMD_MSG_VOIP_VOPENA_CLOSE(st2->cmd_seqno++, chan2), CMD_MSG_VOIP_VOPENA_CLOSE_LEN, 0x8000);
+
+ /* Disconnect the channels */
+ zt_send_cmd(wc, CMD_MSG_TRANS_CONNECT(wc->seq_num++, 0, chan1, chan2, 0, 0), CMD_MSG_TRANS_CONNECT_LEN, 0x9322);
+
+ /* Remove the channels */
+ zt_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan1), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011);
+ zt_send_cmd(wc, CMD_MSG_DESTROY_CHANNEL(wc->seq_num++, chan2), CMD_MSG_DESTROY_CHANNEL_LEN, 0x0011);
+
+ return 1;
+}
+
+
+static int __wcdte_setup_channels(struct wcdte *wc)
+{
+ wc->seq_num = 6;
+
+#ifndef USE_TEST_HW
+ zt_send_cmd(wc, CMD_MSG_SET_ARM_CLK(wc->seq_num++), CMD_MSG_SET_ARM_CLK_LEN, 0x0411);
+ zt_send_cmd(wc, CMD_MSG_SET_SPU_CLK(wc->seq_num++), CMD_MSG_SET_SPU_CLK_LEN, 0x0412);
+#endif
+
+#ifdef USE_TDM_CONFIG
+ zt_send_cmd(wc, CMD_MSG_TDM_SELECT_BUS_MODE(wc->seq_num++), CMD_MSG_TDM_SELECT_BUS_MODE_LEN, 0x0417);
+ zt_send_cmd(wc, CMD_MSG_TDM_ENABLE_BUS(wc->seq_num++), CMD_MSG_TDM_ENABLE_BUS_LEN, 0x0405);
+ zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x03, 0x20, 0x00), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
+ zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x04, 0x80, 0x04), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
+ zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x05, 0x20, 0x08), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
+ zt_send_cmd(wc, CMD_MSG_SUPVSR_SETUP_TDM_PARMS(wc->seq_num++, 0x06, 0x80, 0x0C), CMD_MSG_SUPVSR_SETUP_TDM_PARMS_LEN, 0x0407);
+#endif
+
+ zt_send_cmd(wc, CMD_MSG_SET_ETH_HEADER(wc->seq_num++), CMD_MSG_SET_ETH_HEADER_LEN, 0x0100);
+ zt_send_cmd(wc, CMD_MSG_IP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_IP_SERVICE_CONFIG_LEN, 0x0302);
+ zt_send_cmd(wc, CMD_MSG_ARP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_ARP_SERVICE_CONFIG_LEN, 0x0105);
+ zt_send_cmd(wc, CMD_MSG_ICMP_SERVICE_CONFIG(wc->seq_num++), CMD_MSG_ICMP_SERVICE_CONFIG_LEN, 0x0304);
+
+#ifdef USE_TDM_CONFIG
+ zt_send_cmd(wc, CMD_MSG_DEVICE_SET_COUNTRY_CODE(wc->seq_num++), CMD_MSG_DEVICE_SET_COUNTRY_CODE_LEN, 0x041B);
+#endif
+
+ zt_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x02), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013);
+ zt_send_cmd(wc, CMD_MSG_IP_OPTIONS(wc->seq_num++), CMD_MSG_IP_OPTIONS_LEN, 0x0306);
+ zt_send_cmd(wc, CMD_MSG_SPU_FEATURES_CONTROL(wc->seq_num++, 0x04), CMD_MSG_SPU_FEATURES_CONTROL_LEN, 0x0013);
+
+#ifdef USE_TDM_CONFIG
+ zt_send_cmd(wc, CMD_MSG_TDM_OPT(wc->seq_num++), CMD_MSG_TDM_OPT_LEN, 0x0435);
+#endif
+
+ wc->timeout = HZ/10 + 1; /* 100msec */
+
+ return(0);
+}
+
+static int wcdte_setup_channels(struct wcdte *wc)
+{
+ down(&wc->chansem);
+ __wcdte_setup_channels(wc);
+ up(&wc->chansem);
+
+ return 0;
+}
+
+static int __devinit wcdte_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int res, reg;
+ struct wcdte *wc;
+ struct wcdte_desc *d = (struct wcdte_desc *)ent->driver_data;
+ int x;
+ static int initd_ifaces=0;
+ unsigned char g729_numchannels, g723_numchannels, min_numchannels, dte_firmware_ver, dte_firmware_ver_minor;
+ unsigned int complexfmts;
+
+ struct firmware embedded_firmware;
+ const struct firmware *firmware = &embedded_firmware;
+#if !defined(HOTPLUG_FIRMWARE)
+ extern void _binary_zaptel_fw_tc400m_bin_size;
+ extern u8 _binary_zaptel_fw_tc400m_bin_start[];
+#else
+ static const char tc400m_firmware[] = "zaptel-fw-tc400m.bin";
+#endif
+
+ if (!initd_ifaces) {
+ memset((void *)ifaces,0,(sizeof(struct wcdte *))*WC_MAX_IFACES);
+ initd_ifaces=1;
+ }
+ for (x=0;x<WC_MAX_IFACES;x++)
+ if (!ifaces[x]) break;
+ if (x >= WC_MAX_IFACES) {
+ printk("wcdte: Too many interfaces\n");
+ return -EIO;
+ }
+
+ if (pci_enable_device(pdev)) {
+ res = -EIO;
+ } else {
+
+ wc = vmalloc(sizeof(struct wcdte));
+ if (wc) {
+ ifaces[x] = wc;
+ memset(wc, 0, sizeof(struct wcdte));
+ spin_lock_init(&wc->reglock);
+ sema_init(&wc->chansem, 1);
+ sema_init(&wc->cmdqsem, 1);
+ wc->cards = NUM_CARDS;
+ wc->iobase = pci_resource_start(pdev, 0);
+ wc->dev = pdev;
+ wc->pos = x;
+ wc->variety = d->name;
+
+ wc->tdbl = 0;
+ wc->rdbl = 0;
+ wc->rcvflags = 0;
+ wc->last_seqno = 999;
+ wc->last_command_sent = 0;
+ wc->last_rcommand = 0;
+ wc->last_rparm1 = 0;
+ wc->cmdq_wndx = 0;
+ wc->cmdq_rndx = 0;
+ wc->seq_num = 6;
+ wc->timeout = 1 * HZ; /* 1 sec */
+ wc->dsp_crashed = 0;
+ wc->dumping = 0;
+ wc->ztsnd_rtx = 0;
+ wc->ztsnd_0010_rtx = 0;
+
+ /* Keep track of whether we need to free the region */
+ if (request_region(wc->iobase, 0xff, "wcdte"))
+ wc->freeregion = 1;
+
+ /* Allocate enought memory for all TX buffers, RX buffers, and descriptors */
+ wc->writechunk = (int *)pci_alloc_consistent(pdev, PCI_WINDOW_SIZE, &wc->writedma);
+ if (!wc->writechunk) {
+ printk("wcdte error: Unable to allocate DMA-able memory\n");
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ return -ENOMEM;
+ }
+
+ wc->readchunk = wc->writechunk + (SFRAME_SIZE * ERING_SIZE) / 4; /* in doublewords */
+ wc->readdma = wc->writedma + (SFRAME_SIZE * ERING_SIZE); /* in bytes */
+
+ wc->descripchunk = wc->readchunk + (SFRAME_SIZE * ERING_SIZE) / 4; /* in doublewords */
+ wc->descripdma = wc->readdma + (SFRAME_SIZE * ERING_SIZE); /* in bytes */
+
+ /* Initialize Write/Buffers to all blank data */
+ memset((void *)wc->writechunk,0x00, SFRAME_SIZE * 2);
+ memset((void *)wc->readchunk, 0x00, SFRAME_SIZE * 2);
+
+ init_waitqueue_head(&wc->regq);
+
+ /* Initialize the work queue */
+ wc->dte_wq = create_singlethread_workqueue("tc400b");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+ INIT_WORK(&wc->dte_work, dte_wque_run);
+#else
+ INIT_WORK(&wc->dte_work, dte_wque_run, wc);
+#endif
+
+#if defined(HOTPLUG_FIRMWARE)
+ if ((request_firmware(&firmware, tc400m_firmware, &wc->dev->dev) != 0) ||
+ !firmware) {
+ printk("TC400M: firmware %s not available from userspace\n", tc400m_firmware);
+ return -EIO;
+ }
+#else
+ embedded_firmware.data = _binary_zaptel_fw_tc400m_bin_start;
+ embedded_firmware.size = (size_t) &_binary_zaptel_fw_tc400m_bin_size;
+#endif
+
+ dte_firmware_ver = firmware->data[0];
+ dte_firmware_ver_minor = firmware->data[16];
+ g729_numchannels = firmware->data[1];
+ g723_numchannels = firmware->data[2];
+
+ if (g723_numchannels < g729_numchannels)
+ min_numchannels = g723_numchannels;
+ else
+ min_numchannels = g729_numchannels;
+
+ /* Setup Encoders and Decoders */
+
+ if (!mode || strlen(mode) < 4) {
+ sprintf(wc->complexname, "G.729a / G.723.1");
+ complexfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1;
+ wc->numchannels = min_numchannels;
+ } else if (mode[3] == '9') { /* "G.729" */
+ sprintf(wc->complexname, "G.729a");
+ complexfmts = ZT_FORMAT_G729A;
+ wc->numchannels = g729_numchannels;
+ } else if (mode[3] == '3') { /* "G.723.1" */
+ sprintf(wc->complexname, "G.723.1");
+ complexfmts = ZT_FORMAT_G723_1;
+ wc->numchannels = g723_numchannels;
+ } else {
+ sprintf(wc->complexname, "G.729a / G.723.1");
+ complexfmts = ZT_FORMAT_G729A | ZT_FORMAT_G723_1;
+ wc->numchannels = min_numchannels;
+ }
+
+ uencode = zt_transcoder_alloc(wc->numchannels);
+ udecode = zt_transcoder_alloc(wc->numchannels);
+ encoders = vmalloc(sizeof(struct dte_state) * wc->numchannels);
+ decoders = vmalloc(sizeof(struct dte_state) * wc->numchannels);
+ memset(encoders, 0, sizeof(struct dte_state) * wc->numchannels);
+ memset(decoders, 0, sizeof(struct dte_state) * wc->numchannels);
+ if (!uencode || !udecode || !encoders || !decoders) {
+ if (uencode)
+ zt_transcoder_free(uencode);
+ if (udecode)
+ zt_transcoder_free(udecode);
+ if (encoders)
+ vfree(encoders);
+ if (decoders)
+ vfree(decoders);
+ return -ENOMEM;
+ }
+ sprintf(udecode->name, "DTE Decoder");
+ sprintf(uencode->name, "DTE Encoder");
+
+ udecode->srcfmts = uencode->dstfmts = complexfmts;
+ udecode->dstfmts = uencode->srcfmts = ZT_FORMAT_ULAW | ZT_FORMAT_ALAW;
+
+ udecode->operation = uencode->operation = dte_operation;
+
+ for (x=0;x<wc->numchannels;x++) {
+ dte_init_state(encoders + x, 1, x, wc);
+ encoders[x].encoder = 1;
+ decoders[x].encoder = 0;
+ dte_init_state(decoders + x, 0, x, wc);
+ uencode->channels[x].pvt = encoders + x;
+ udecode->channels[x].pvt = decoders + x;
+ }
+
+ wc->uencode = uencode;
+ wc->udecode = udecode;
+
+ zt_transcoder_register(uencode);
+ zt_transcoder_register(udecode);
+
+ printk("Zaptel DTE (%s) Transcoder support LOADED (firm ver = %d.%d)\n", wc->complexname, dte_firmware_ver, dte_firmware_ver_minor);
+
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, wc);
+
+ if (request_irq(pdev->irq, wcdte_interrupt, ZAP_IRQ_SHARED, "tc400b", wc)) {
+ printk("wcdte error: Unable to request IRQ %d\n", pdev->irq);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ vfree(wc);
+ return -EIO;
+ }
+
+
+ if (wcdte_hardware_init(wc)) {
+ /* Set Reset Low */
+ wcdte_stop_dma(wc);
+ /* Free Resources */
+ free_irq(pdev->irq, wc);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ vfree(wc);
+ return -EIO;
+
+ }
+
+ /* Enable interrupts */
+ wcdte_enable_interrupts(wc);
+
+ /* Start DMA */
+ wcdte_start_dma(wc);
+
+ if (wcdte_boot_processor(wc,firmware,1)) {
+ if (firmware != &embedded_firmware)
+ release_firmware(firmware);
+
+ /* Set Reset Low */
+ wcdte_stop_dma(wc);
+ /* Free Resources */
+ free_irq(pdev->irq, wc);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ vfree(wc);
+ return -EIO;
+ }
+ if (firmware != &embedded_firmware)
+ release_firmware(firmware);
+
+ if (wcdte_setup_channels(wc)) {
+ /* Set Reset Low */
+ wcdte_stop_dma(wc);
+ /* Free Resources */
+ free_irq(pdev->irq, wc);
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ vfree(wc);
+ return -EIO;
+ }
+
+ reg = wcdte_getctl(wc, 0x00fc);
+ if (debug)
+ printk("wcdte debug: (post-boot) Reg fc is %08x\n", reg);
+
+ printk("Found and successfully installed a Wildcard TC: %s \n", wc->variety);
+ if (debug) {
+ printk("TC400B operating in DEBUG mode\n");
+ printk("debug_des = %d, debug_des_cnt = %d, force_alert = %d,\n debug_notimeout = %d, debug_packets = %d\n",
+ debug_des, debug_des_cnt, force_alert, debug_notimeout, debug_packets);
+ }
+ res = 0;
+ } else
+ res = -ENOMEM;
+ }
+ return res;
+}
+
+static void wcdte_release(struct wcdte *wc)
+{
+ if (wc->freeregion)
+ release_region(wc->iobase, 0xff);
+ vfree(wc);
+}
+
+static void __devexit wcdte_remove_one(struct pci_dev *pdev)
+{
+ int i;
+ struct wcdte *wc = pci_get_drvdata(pdev);
+ struct zt_transcoder_channel *ztc_en, *ztc_de;
+ struct dte_state *st_en, *st_de;
+
+ if (wc) {
+ if (debug)
+ {
+ printk("wcdte debug: wc->ztsnd_rtx = %d\n", wc->ztsnd_rtx);
+ printk("wcdte debug: wc->ztsnd_0010_rtx = %d\n", wc->ztsnd_0010_rtx);
+
+ for(i = 0; i < wc->numchannels; i++)
+ {
+ ztc_en = &(wc->uencode->channels[i]);
+ st_en = ztc_en->pvt;
+
+ ztc_de = &(wc->udecode->channels[i]);
+ st_de = ztc_de->pvt;
+
+ printk("wcdte debug: en[%d] snt = %d, rcv = %d [%d]\n", i, st_en->packets_sent, st_en->packets_received, st_en->packets_sent - st_en->packets_received);
+ printk("wcdte debug: de[%d] snt = %d, rcv = %d [%d]\n", i, st_de->packets_sent, st_de->packets_received, st_de->packets_sent - st_de->packets_received);
+ }
+ }
+
+ zt_transcoder_unregister(wc->udecode);
+ zt_transcoder_unregister(wc->uencode);
+ zt_transcoder_free(wc->uencode);
+ zt_transcoder_free(wc->udecode);
+ vfree(wc->uencode->channels[0].pvt);
+ vfree(wc->udecode->channels[0].pvt);
+
+ /* Stop any DMA */
+ wcdte_stop_dma(wc);
+
+ /* In case hardware is still there */
+ wcdte_disable_interrupts(wc);
+
+ /* Kill workqueue */
+ destroy_workqueue(wc->dte_wq);
+
+ /* Immediately free resources */
+ pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+ free_irq(pdev->irq, wc);
+
+ /* Release span, possibly delayed */
+ wcdte_release(wc);
+ }
+}
+
+static struct pci_device_id wcdte_pci_tbl[] = {
+#ifndef USE_TEST_HW
+ { 0xd161, 0x3400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctc400p }, /* Digium board */
+ { 0xd161, 0x8004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctce400 }, /* Digium board */
+#else
+ { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctc400p }, /* reference board */
+#endif
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, wcdte_pci_tbl);
+
+static struct pci_driver wcdte_driver = {
+ name: "wctc4xxp",
+ probe: wcdte_init_one,
+ remove: __devexit_p(wcdte_remove_one),
+ suspend: NULL,
+ resume: NULL,
+ id_table: wcdte_pci_tbl,
+};
+
+int ztdte_init(void)
+{
+ int res;
+
+ res = zap_pci_module(&wcdte_driver);
+ if (res)
+ return -ENODEV;
+ return 0;
+}
+
+void ztdte_cleanup(void)
+{
+ pci_unregister_driver(&wcdte_driver);
+}
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+module_param(debug_des, int, S_IRUGO | S_IWUSR);
+module_param(debug_des_cnt, int, S_IRUGO | S_IWUSR);
+module_param(debug_notimeout, int, S_IRUGO | S_IWUSR);
+module_param(force_alert, int, S_IRUGO | S_IWUSR);
+module_param(mode, charp, S_IRUGO | S_IWUSR);
+MODULE_DESCRIPTION("Wildcard TC400P+TC400M Driver");
+MODULE_AUTHOR("John Sloan <jsloan@digium.com>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(ztdte_init);
+module_exit(ztdte_cleanup);
diff --git a/drivers/dahdi/wctc4xxp/codec_test.c b/drivers/dahdi/wctc4xxp/codec_test.c
new file mode 100644
index 0000000..287979d
--- /dev/null
+++ b/drivers/dahdi/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/drivers/dahdi/wctdm.c b/drivers/dahdi/wctdm.c
new file mode 100644
index 0000000..00c8128
--- /dev/null
+++ b/drivers/dahdi/wctdm.c
@@ -0,0 +1,2559 @@
+/*
+ * Wilcard TDM400P TDM FXS/FXO Interface Driver for Zapata Telephony interface
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Matthew Fredrickson <creslin@digium.com>
+ *
+ * Copyright (C) 2001, Linux Support Services, 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 <asm/io.h>
+#include "proslic.h"
+#include "wctdm.h"
+/*
+ * Define for audio vs. register based ring detection
+ *
+ */
+/* #define AUDIO_RINGCHECK */
+
+/*
+ Experimental max loop current limit for the proslic
+ Loop current limit is from 20 mA to 41 mA in steps of 3
+ (according to datasheet)
+ So set the value below to:
+ 0x00 : 20mA (default)
+ 0x01 : 23mA
+ 0x02 : 26mA
+ 0x03 : 29mA
+ 0x04 : 32mA
+ 0x05 : 35mA
+ 0x06 : 37mA
+ 0x07 : 41mA
+*/
+static int loopcurrent = 20;
+
+static int reversepolarity = 0;
+
+static alpha indirect_regs[] =
+{
+{0,255,"DTMF_ROW_0_PEAK",0x55C2},
+{1,255,"DTMF_ROW_1_PEAK",0x51E6},
+{2,255,"DTMF_ROW2_PEAK",0x4B85},
+{3,255,"DTMF_ROW3_PEAK",0x4937},
+{4,255,"DTMF_COL1_PEAK",0x3333},
+{5,255,"DTMF_FWD_TWIST",0x0202},
+{6,255,"DTMF_RVS_TWIST",0x0202},
+{7,255,"DTMF_ROW_RATIO_TRES",0x0198},
+{8,255,"DTMF_COL_RATIO_TRES",0x0198},
+{9,255,"DTMF_ROW_2ND_ARM",0x0611},
+{10,255,"DTMF_COL_2ND_ARM",0x0202},
+{11,255,"DTMF_PWR_MIN_TRES",0x00E5},
+{12,255,"DTMF_OT_LIM_TRES",0x0A1C},
+{13,0,"OSC1_COEF",0x7B30},
+{14,1,"OSC1X",0x0063},
+{15,2,"OSC1Y",0x0000},
+{16,3,"OSC2_COEF",0x7870},
+{17,4,"OSC2X",0x007D},
+{18,5,"OSC2Y",0x0000},
+{19,6,"RING_V_OFF",0x0000},
+{20,7,"RING_OSC",0x7EF0},
+{21,8,"RING_X",0x0160},
+{22,9,"RING_Y",0x0000},
+{23,255,"PULSE_ENVEL",0x2000},
+{24,255,"PULSE_X",0x2000},
+{25,255,"PULSE_Y",0x0000},
+//{26,13,"RECV_DIGITAL_GAIN",0x4000}, // playback volume set lower
+{26,13,"RECV_DIGITAL_GAIN",0x2000}, // playback volume set lower
+{27,14,"XMIT_DIGITAL_GAIN",0x4000},
+//{27,14,"XMIT_DIGITAL_GAIN",0x2000},
+{28,15,"LOOP_CLOSE_TRES",0x1000},
+{29,16,"RING_TRIP_TRES",0x3600},
+{30,17,"COMMON_MIN_TRES",0x1000},
+{31,18,"COMMON_MAX_TRES",0x0200},
+{32,19,"PWR_ALARM_Q1Q2",0x07C0},
+{33,20,"PWR_ALARM_Q3Q4",0x2600},
+{34,21,"PWR_ALARM_Q5Q6",0x1B80},
+{35,22,"LOOP_CLOSURE_FILTER",0x8000},
+{36,23,"RING_TRIP_FILTER",0x0320},
+{37,24,"TERM_LP_POLE_Q1Q2",0x008C},
+{38,25,"TERM_LP_POLE_Q3Q4",0x0100},
+{39,26,"TERM_LP_POLE_Q5Q6",0x0010},
+{40,27,"CM_BIAS_RINGING",0x0C00},
+{41,64,"DCDC_MIN_V",0x0C00},
+{42,255,"DCDC_XTRA",0x1000},
+{43,66,"LOOP_CLOSE_TRES_LOW",0x1000},
+};
+
+#include "zaptel.h"
+
+#include "fxo_modes.h"
+
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+#define NUM_FXO_REGS 60
+
+#define WC_MAX_IFACES 128
+
+#define WC_CNTL 0x00
+#define WC_OPER 0x01
+#define WC_AUXC 0x02
+#define WC_AUXD 0x03
+#define WC_MASK0 0x04
+#define WC_MASK1 0x05
+#define WC_INTSTAT 0x06
+#define WC_AUXR 0x07
+
+#define WC_DMAWS 0x08
+#define WC_DMAWI 0x0c
+#define WC_DMAWE 0x10
+#define WC_DMARS 0x18
+#define WC_DMARI 0x1c
+#define WC_DMARE 0x20
+
+#define WC_AUXFUNC 0x2b
+#define WC_SERCTL 0x2d
+#define WC_FSCDELAY 0x2f
+
+#define WC_REGBASE 0xc0
+
+#define WC_SYNC 0x0
+#define WC_TEST 0x1
+#define WC_CS 0x2
+#define WC_VER 0x3
+
+#define BIT_CS (1 << 2)
+#define BIT_SCLK (1 << 3)
+#define BIT_SDI (1 << 4)
+#define BIT_SDO (1 << 5)
+
+#define FLAG_EMPTY 0
+#define FLAG_WRITE 1
+#define FLAG_READ 2
+
+#define DEFAULT_RING_DEBOUNCE 64 /* Ringer Debounce (64 ms) */
+
+#define POLARITY_DEBOUNCE 64 /* Polarity debounce (64 ms) */
+
+#define OHT_TIMER 6000 /* How long after RING to retain OHT */
+
+#define FLAG_3215 (1 << 0)
+
+#define NUM_CARDS 4
+
+#define MAX_ALARMS 10
+
+#define MOD_TYPE_FXS 0
+#define MOD_TYPE_FXO 1
+
+#define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */
+#define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */
+#define PEGCOUNT 5 /* 5 cycles of pegging means RING */
+
+#define NUM_CAL_REGS 12
+
+struct calregs {
+ unsigned char vals[NUM_CAL_REGS];
+};
+
+enum proslic_power_warn {
+ PROSLIC_POWER_UNKNOWN = 0,
+ PROSLIC_POWER_ON,
+ PROSLIC_POWER_WARNED,
+};
+
+enum battery_state {
+ BATTERY_UNKNOWN = 0,
+ BATTERY_PRESENT,
+ BATTERY_LOST,
+};
+
+struct wctdm {
+ struct pci_dev *dev;
+ char *variety;
+ struct zt_span span;
+ unsigned char ios;
+ int usecount;
+ unsigned int intcount;
+ int dead;
+ int pos;
+ int flags[NUM_CARDS];
+ int freeregion;
+ int alt;
+ int curcard;
+ int cardflag; /* Bit-map of present cards */
+ enum proslic_power_warn proslic_power;
+ spinlock_t lock;
+
+ union {
+ struct fxo {
+#ifdef AUDIO_RINGCHECK
+ unsigned int pegtimer;
+ int pegcount;
+ int peg;
+ int ring;
+#else
+ int wasringing;
+ int lastrdtx;
+#endif
+ int ringdebounce;
+ int offhook;
+ unsigned int battdebounce;
+ unsigned int battalarm;
+ enum battery_state battery;
+ int lastpol;
+ int polarity;
+ int polaritydebounce;
+ } fxo;
+ struct fxs {
+ int oldrxhook;
+ int debouncehook;
+ int lastrxhook;
+ int debounce;
+ int ohttimer;
+ int idletxhookstate; /* IDLE changing hook state */
+ int lasttxhook;
+ int palarms;
+ struct calregs calregs;
+ } fxs;
+ } mod[NUM_CARDS];
+
+ /* Receive hook state and debouncing */
+ int modtype[NUM_CARDS];
+ unsigned char reg0shadow[NUM_CARDS];
+ unsigned char reg1shadow[NUM_CARDS];
+
+ unsigned long ioaddr;
+ dma_addr_t readdma;
+ dma_addr_t writedma;
+ volatile unsigned int *writechunk; /* Double-word aligned write memory */
+ volatile unsigned int *readchunk; /* Double-word aligned read memory */
+ struct zt_chan chans[NUM_CARDS];
+};
+
+
+struct wctdm_desc {
+ char *name;
+ int flags;
+};
+
+static struct wctdm_desc wctdm = { "Wildcard S400P Prototype", 0 };
+static struct wctdm_desc wctdme = { "Wildcard TDM400P REV E/F", 0 };
+static struct wctdm_desc wctdmh = { "Wildcard TDM400P REV H", 0 };
+static struct wctdm_desc wctdmi = { "Wildcard TDM400P REV I", 0 };
+static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 };
+
+static struct wctdm *ifaces[WC_MAX_IFACES];
+
+static void wctdm_release(struct wctdm *wc);
+
+static unsigned int battdebounce;
+static unsigned int battalarm;
+static unsigned int battthresh;
+static int ringdebounce = DEFAULT_RING_DEBOUNCE;
+static int fwringdetect = 0;
+static int debug = 0;
+static int robust = 0;
+static int timingonly = 0;
+static int lowpower = 0;
+static int boostringer = 0;
+static int fastringer = 0;
+static int _opermode = 0;
+static char *opermode = "FCC";
+static int fxshonormode = 0;
+static int alawoverride = 0;
+static int fastpickup = 0;
+static int fxotxgain = 0;
+static int fxorxgain = 0;
+static int fxstxgain = 0;
+static int fxsrxgain = 0;
+
+static int wctdm_init_proslic(struct wctdm *wc, int card, int fast , int manual, int sane);
+
+static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char ints)
+{
+ volatile unsigned int *writechunk;
+ int x;
+ if (ints & 0x01)
+ /* Write is at interrupt address. Start writing from normal offset */
+ writechunk = wc->writechunk;
+ else
+ writechunk = wc->writechunk + ZT_CHUNKSIZE;
+ /* Calculate Transmission */
+ zt_transmit(&wc->span);
+
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ /* Send a sample, as a 32-bit word */
+ writechunk[x] = 0;
+#ifdef __BIG_ENDIAN
+ if (wc->cardflag & (1 << 3))
+ writechunk[x] |= (wc->chans[3].writechunk[x]);
+ if (wc->cardflag & (1 << 2))
+ writechunk[x] |= (wc->chans[2].writechunk[x] << 8);
+ if (wc->cardflag & (1 << 1))
+ writechunk[x] |= (wc->chans[1].writechunk[x] << 16);
+ if (wc->cardflag & (1 << 0))
+ writechunk[x] |= (wc->chans[0].writechunk[x] << 24);
+#else
+ if (wc->cardflag & (1 << 3))
+ writechunk[x] |= (wc->chans[3].writechunk[x] << 24);
+ if (wc->cardflag & (1 << 2))
+ writechunk[x] |= (wc->chans[2].writechunk[x] << 16);
+ if (wc->cardflag & (1 << 1))
+ writechunk[x] |= (wc->chans[1].writechunk[x] << 8);
+ if (wc->cardflag & (1 << 0))
+ writechunk[x] |= (wc->chans[0].writechunk[x]);
+#endif
+ }
+
+}
+
+#ifdef AUDIO_RINGCHECK
+static inline void ring_check(struct wctdm *wc, int card)
+{
+ int x;
+ short sample;
+ if (wc->modtype[card] != MOD_TYPE_FXO)
+ return;
+ wc->mod[card].fxo.pegtimer += ZT_CHUNKSIZE;
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ /* Look for pegging to indicate ringing */
+ sample = ZT_XLAW(wc->chans[card].readchunk[x], (&(wc->chans[card])));
+ if ((sample > 10000) && (wc->mod[card].fxo.peg != 1)) {
+ if (debug > 1) printk("High peg!\n");
+ if ((wc->mod[card].fxo.pegtimer < PEGTIME) && (wc->mod[card].fxo.pegtimer > MINPEGTIME))
+ wc->mod[card].fxo.pegcount++;
+ wc->mod[card].fxo.pegtimer = 0;
+ wc->mod[card].fxo.peg = 1;
+ } else if ((sample < -10000) && (wc->mod[card].fxo.peg != -1)) {
+ if (debug > 1) printk("Low peg!\n");
+ if ((wc->mod[card].fxo.pegtimer < (PEGTIME >> 2)) && (wc->mod[card].fxo.pegtimer > (MINPEGTIME >> 2)))
+ wc->mod[card].fxo.pegcount++;
+ wc->mod[card].fxo.pegtimer = 0;
+ wc->mod[card].fxo.peg = -1;
+ }
+ }
+ if (wc->mod[card].fxo.pegtimer > PEGTIME) {
+ /* Reset pegcount if our timer expires */
+ wc->mod[card].fxo.pegcount = 0;
+ }
+ /* Decrement debouncer if appropriate */
+ if (wc->mod[card].fxo.ringdebounce)
+ wc->mod[card].fxo.ringdebounce--;
+ if (!wc->mod[card].fxo.offhook && !wc->mod[card].fxo.ringdebounce) {
+ if (!wc->mod[card].fxo.ring && (wc->mod[card].fxo.pegcount > PEGCOUNT)) {
+ /* It's ringing */
+ if (debug)
+ printk("RING on %d/%d!\n", wc->span.spanno, card + 1);
+ if (!wc->mod[card].fxo.offhook)
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
+ wc->mod[card].fxo.ring = 1;
+ }
+ if (wc->mod[card].fxo.ring && !wc->mod[card].fxo.pegcount) {
+ /* No more ring */
+ if (debug)
+ printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ wc->mod[card].fxo.ring = 0;
+ }
+ }
+}
+#endif
+static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char ints)
+{
+ volatile unsigned int *readchunk;
+ int x;
+
+ if (ints & 0x08)
+ readchunk = wc->readchunk + ZT_CHUNKSIZE;
+ else
+ /* Read is at interrupt address. Valid data is available at normal offset */
+ readchunk = wc->readchunk;
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+#ifdef __BIG_ENDIAN
+ if (wc->cardflag & (1 << 3))
+ wc->chans[3].readchunk[x] = (readchunk[x]) & 0xff;
+ if (wc->cardflag & (1 << 2))
+ wc->chans[2].readchunk[x] = (readchunk[x] >> 8) & 0xff;
+ if (wc->cardflag & (1 << 1))
+ wc->chans[1].readchunk[x] = (readchunk[x] >> 16) & 0xff;
+ if (wc->cardflag & (1 << 0))
+ wc->chans[0].readchunk[x] = (readchunk[x] >> 24) & 0xff;
+#else
+ if (wc->cardflag & (1 << 3))
+ wc->chans[3].readchunk[x] = (readchunk[x] >> 24) & 0xff;
+ if (wc->cardflag & (1 << 2))
+ wc->chans[2].readchunk[x] = (readchunk[x] >> 16) & 0xff;
+ if (wc->cardflag & (1 << 1))
+ wc->chans[1].readchunk[x] = (readchunk[x] >> 8) & 0xff;
+ if (wc->cardflag & (1 << 0))
+ wc->chans[0].readchunk[x] = (readchunk[x]) & 0xff;
+#endif
+ }
+#ifdef AUDIO_RINGCHECK
+ for (x=0;x<wc->cards;x++)
+ ring_check(wc, x);
+#endif
+ /* XXX We're wasting 8 taps. We should get closer :( */
+ for (x = 0; x < NUM_CARDS; x++) {
+ if (wc->cardflag & (1 << x))
+ zt_ec_chunk(&wc->chans[x], wc->chans[x].readchunk, wc->chans[x].writechunk);
+ }
+ zt_receive(&wc->span);
+}
+
+static void wctdm_stop_dma(struct wctdm *wc);
+static void wctdm_reset_tdm(struct wctdm *wc);
+static void wctdm_restart_dma(struct wctdm *wc);
+
+static inline void __write_8bits(struct wctdm *wc, unsigned char bits)
+{
+ /* Drop chip select */
+ int x;
+ wc->ios |= BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ wc->ios &= ~BIT_CS;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ for (x=0;x<8;x++) {
+ /* Send out each bit, MSB first, drop SCLK as we do so */
+ if (bits & 0x80)
+ wc->ios |= BIT_SDI;
+ else
+ wc->ios &= ~BIT_SDI;
+ wc->ios &= ~BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ /* Now raise SCLK high again and repeat */
+ wc->ios |= BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ bits <<= 1;
+ }
+ /* Finally raise CS back high again */
+ wc->ios |= BIT_CS;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+
+}
+
+static inline void __reset_spi(struct wctdm *wc)
+{
+ /* Drop chip select and clock once and raise and clock once */
+ wc->ios |= BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ wc->ios &= ~BIT_CS;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ wc->ios |= BIT_SDI;
+ wc->ios &= ~BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ /* Now raise SCLK high again and repeat */
+ wc->ios |= BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ /* Finally raise CS back high again */
+ wc->ios |= BIT_CS;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ /* Clock again */
+ wc->ios &= ~BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ /* Now raise SCLK high again and repeat */
+ wc->ios |= BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+
+}
+
+static inline unsigned char __read_8bits(struct wctdm *wc)
+{
+ unsigned char res=0, c;
+ int x;
+ wc->ios |= BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ /* Drop chip select */
+ wc->ios &= ~BIT_CS;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ for (x=0;x<8;x++) {
+ res <<= 1;
+ /* Get SCLK */
+ wc->ios &= ~BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ /* Read back the value */
+ c = inb(wc->ioaddr + WC_AUXR);
+ if (c & BIT_SDO)
+ res |= 1;
+ /* Now raise SCLK high again */
+ wc->ios |= BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ }
+ /* Finally raise CS back high again */
+ wc->ios |= BIT_CS;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+ wc->ios &= ~BIT_SCLK;
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+
+ /* And return our result */
+ return res;
+}
+
+static void __wctdm_setcreg(struct wctdm *wc, unsigned char reg, unsigned char val)
+{
+ outb(val, wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2));
+}
+
+static unsigned char __wctdm_getcreg(struct wctdm *wc, unsigned char reg)
+{
+ return inb(wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2));
+}
+
+static inline void __wctdm_setcard(struct wctdm *wc, int card)
+{
+ if (wc->curcard != card) {
+ __wctdm_setcreg(wc, WC_CS, (1 << card));
+ wc->curcard = card;
+ }
+}
+
+static void __wctdm_setreg(struct wctdm *wc, int card, unsigned char reg, unsigned char value)
+{
+ __wctdm_setcard(wc, card);
+ if (wc->modtype[card] == MOD_TYPE_FXO) {
+ __write_8bits(wc, 0x20);
+ __write_8bits(wc, reg & 0x7f);
+ } else {
+ __write_8bits(wc, reg & 0x7f);
+ }
+ __write_8bits(wc, value);
+}
+
+static void wctdm_setreg(struct wctdm *wc, int card, unsigned char reg, unsigned char value)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->lock, flags);
+ __wctdm_setreg(wc, card, reg, value);
+ spin_unlock_irqrestore(&wc->lock, flags);
+}
+
+static unsigned char __wctdm_getreg(struct wctdm *wc, int card, unsigned char reg)
+{
+ __wctdm_setcard(wc, card);
+ if (wc->modtype[card] == MOD_TYPE_FXO) {
+ __write_8bits(wc, 0x60);
+ __write_8bits(wc, reg & 0x7f);
+ } else {
+ __write_8bits(wc, reg | 0x80);
+ }
+ return __read_8bits(wc);
+}
+
+static inline void reset_spi(struct wctdm *wc, int card)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->lock, flags);
+ __wctdm_setcard(wc, card);
+ __reset_spi(wc);
+ __reset_spi(wc);
+ spin_unlock_irqrestore(&wc->lock, flags);
+}
+
+static unsigned char wctdm_getreg(struct wctdm *wc, int card, unsigned char reg)
+{
+ unsigned long flags;
+ unsigned char res;
+ spin_lock_irqsave(&wc->lock, flags);
+ res = __wctdm_getreg(wc, card, reg);
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return res;
+}
+
+static int __wait_access(struct wctdm *wc, int card)
+{
+ unsigned char data = 0;
+ long origjiffies;
+ int count = 0;
+
+ #define MAX 6000 /* attempts */
+
+
+ origjiffies = jiffies;
+ /* Wait for indirect access */
+ while (count++ < MAX)
+ {
+ data = __wctdm_getreg(wc, card, I_STATUS);
+
+ if (!data)
+ return 0;
+
+ }
+
+ if(count > (MAX-1)) printk(" ##### Loop error (%02x) #####\n", data);
+
+ return 0;
+}
+
+static unsigned char translate_3215(unsigned char address)
+{
+ int x;
+ for (x=0;x<sizeof(indirect_regs)/sizeof(indirect_regs[0]);x++) {
+ if (indirect_regs[x].address == address) {
+ address = indirect_regs[x].altaddr;
+ break;
+ }
+ }
+ return address;
+}
+
+static int wctdm_proslic_setreg_indirect(struct wctdm *wc, int card, unsigned char address, unsigned short data)
+{
+ unsigned long flags;
+ int res = -1;
+ /* Translate 3215 addresses */
+ if (wc->flags[card] & FLAG_3215) {
+ address = translate_3215(address);
+ if (address == 255)
+ return 0;
+ }
+ spin_lock_irqsave(&wc->lock, flags);
+ if(!__wait_access(wc, card)) {
+ __wctdm_setreg(wc, card, IDA_LO,(unsigned char)(data & 0xFF));
+ __wctdm_setreg(wc, card, IDA_HI,(unsigned char)((data & 0xFF00)>>8));
+ __wctdm_setreg(wc, card, IAA,address);
+ res = 0;
+ };
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return res;
+}
+
+static int wctdm_proslic_getreg_indirect(struct wctdm *wc, int card, unsigned char address)
+{
+ unsigned long flags;
+ int res = -1;
+ char *p=NULL;
+ /* Translate 3215 addresses */
+ if (wc->flags[card] & FLAG_3215) {
+ address = translate_3215(address);
+ if (address == 255)
+ return 0;
+ }
+ spin_lock_irqsave(&wc->lock, flags);
+ if (!__wait_access(wc, card)) {
+ __wctdm_setreg(wc, card, IAA, address);
+ if (!__wait_access(wc, card)) {
+ unsigned char data1, data2;
+ data1 = __wctdm_getreg(wc, card, IDA_LO);
+ data2 = __wctdm_getreg(wc, card, IDA_HI);
+ res = data1 | (data2 << 8);
+ } else
+ p = "Failed to wait inside\n";
+ } else
+ p = "failed to wait\n";
+ spin_unlock_irqrestore(&wc->lock, flags);
+ if (p)
+ printk(p);
+ return res;
+}
+
+static int wctdm_proslic_init_indirect_regs(struct wctdm *wc, int card)
+{
+ unsigned char i;
+
+ for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++)
+ {
+ if(wctdm_proslic_setreg_indirect(wc, card, indirect_regs[i].address,indirect_regs[i].initial))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int wctdm_proslic_verify_indirect_regs(struct wctdm *wc, int card)
+{
+ int passed = 1;
+ unsigned short i, initial;
+ int j;
+
+ for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++)
+ {
+ if((j = wctdm_proslic_getreg_indirect(wc, card, (unsigned char) indirect_regs[i].address)) < 0) {
+ printk("Failed to read indirect register %d\n", i);
+ return -1;
+ }
+ initial= indirect_regs[i].initial;
+
+ if ( j != initial && (!(wc->flags[card] & FLAG_3215) || (indirect_regs[i].altaddr != 255)))
+ {
+ printk("!!!!!!! %s iREG %X = %X should be %X\n",
+ indirect_regs[i].name,indirect_regs[i].address,j,initial );
+ passed = 0;
+ }
+ }
+
+ if (passed) {
+ if (debug)
+ printk("Init Indirect Registers completed successfully.\n");
+ } else {
+ printk(" !!!!! Init Indirect Registers UNSUCCESSFULLY.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
+{
+ int res;
+ /* Check loopback */
+ res = wc->reg1shadow[card];
+ if (!res && (res != wc->mod[card].fxs.lasttxhook)) {
+ res = wctdm_getreg(wc, card, 8);
+ if (res) {
+ printk("Ouch, part reset, quickly restoring reality (%d)\n", card);
+ wctdm_init_proslic(wc, card, 1, 0, 1);
+ } else {
+ if (wc->mod[card].fxs.palarms++ < MAX_ALARMS) {
+ printk("Power alarm on module %d, resetting!\n", card + 1);
+ if (wc->mod[card].fxs.lasttxhook == 4)
+ wc->mod[card].fxs.lasttxhook = 1;
+ wctdm_setreg(wc, card, 64, wc->mod[card].fxs.lasttxhook);
+ } else {
+ if (wc->mod[card].fxs.palarms == MAX_ALARMS)
+ printk("Too many power alarms on card %d, NOT resetting!\n", card + 1);
+ }
+ }
+ }
+}
+
+static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card)
+{
+#define MS_PER_CHECK_HOOK 16
+
+#ifndef AUDIO_RINGCHECK
+ unsigned char res;
+#endif
+ signed char b;
+ int poopy = 0;
+ struct fxo *fxo = &wc->mod[card].fxo;
+
+ /* Try to track issues that plague slot one FXO's */
+ b = wc->reg0shadow[card];
+ if ((b & 0x2) || !(b & 0x8)) {
+ /* Not good -- don't look at anything else */
+ if (debug)
+ printk("Poopy (%02x) on card %d!\n", b, card + 1);
+ poopy++;
+ }
+ b &= 0x9b;
+ if (fxo->offhook) {
+ if (b != 0x9)
+ wctdm_setreg(wc, card, 5, 0x9);
+ } else {
+ if (b != 0x8)
+ wctdm_setreg(wc, card, 5, 0x8);
+ }
+ if (poopy)
+ return;
+ if (!fxo->offhook) {
+ if (fwringdetect) {
+ res = wc->reg0shadow[card] & 0x60;
+ if (fxo->ringdebounce--) {
+ if (res && (res != fxo->lastrdtx) &&
+ (fxo->battery == BATTERY_PRESENT)) {
+ if (!fxo->wasringing) {
+ fxo->wasringing = 1;
+ if (debug)
+ printk("RING on %d/%d!\n", wc->span.spanno, card + 1);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
+ }
+ fxo->lastrdtx = res;
+ fxo->ringdebounce = 10;
+ } else if (!res) {
+ if ((fxo->ringdebounce == 0) && fxo->wasringing) {
+ fxo->wasringing = 0;
+ if (debug)
+ printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ }
+ }
+ } else if (res && (fxo->battery == BATTERY_PRESENT)) {
+ fxo->lastrdtx = res;
+ fxo->ringdebounce = 10;
+ }
+ } else {
+ res = wc->reg0shadow[card];
+ if ((res & 0x60) && (fxo->battery == BATTERY_PRESENT)) {
+ fxo->ringdebounce += (ZT_CHUNKSIZE * 16);
+ if (fxo->ringdebounce >= ZT_CHUNKSIZE * ringdebounce) {
+ if (!fxo->wasringing) {
+ fxo->wasringing = 1;
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
+ if (debug)
+ printk("RING on %d/%d!\n", wc->span.spanno, card + 1);
+ }
+ fxo->ringdebounce = ZT_CHUNKSIZE * ringdebounce;
+ }
+ } else {
+ fxo->ringdebounce -= ZT_CHUNKSIZE * 4;
+ if (fxo->ringdebounce <= 0) {
+ if (fxo->wasringing) {
+ fxo->wasringing = 0;
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ if (debug)
+ printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);
+ }
+ fxo->ringdebounce = 0;
+ }
+ }
+ }
+ }
+
+ b = wc->reg1shadow[card];
+
+ if (abs(b) < battthresh) {
+ /* possible existing states:
+ battery lost, no debounce timer
+ battery lost, debounce timer (going to battery present)
+ battery present or unknown, no debounce timer
+ battery present or unknown, debounce timer (going to battery lost)
+ */
+
+ if (fxo->battery == BATTERY_LOST) {
+ if (fxo->battdebounce) {
+ /* we were going to BATTERY_PRESENT, but battery was lost again,
+ so clear the debounce timer */
+ fxo->battdebounce = 0;
+ }
+ } else {
+ if (fxo->battdebounce) {
+ /* going to BATTERY_LOST, see if we are there yet */
+ if (--fxo->battdebounce == 0) {
+ fxo->battery = BATTERY_LOST;
+ if (debug)
+ printk("NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1);
+#ifdef JAPAN
+ if (!wc->ohdebounce && wc->offhook) {
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
+ if (debug)
+ printk("Signalled On Hook\n");
+#ifdef ZERO_BATT_RING
+ wc->onhook++;
+#endif
+ }
+#else
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
+ /* set the alarm timer, taking into account that part of its time
+ period has already passed while debouncing occurred */
+ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK;
+#endif
+ }
+ } else {
+ /* start the debounce timer to verify that battery has been lost */
+ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK;
+ }
+ }
+ } else {
+ /* possible existing states:
+ battery lost or unknown, no debounce timer
+ battery lost or unknown, debounce timer (going to battery present)
+ battery present, no debounce timer
+ battery present, debounce timer (going to battery lost)
+ */
+
+ if (fxo->battery == BATTERY_PRESENT) {
+ if (fxo->battdebounce) {
+ /* we were going to BATTERY_LOST, but battery appeared again,
+ so clear the debounce timer */
+ fxo->battdebounce = 0;
+ }
+ } else {
+ if (fxo->battdebounce) {
+ /* going to BATTERY_PRESENT, see if we are there yet */
+ if (--fxo->battdebounce == 0) {
+ fxo->battery = BATTERY_PRESENT;
+ if (debug)
+ printk("BATTERY on %d/%d (%s)!\n", wc->span.spanno, card + 1,
+ (b < 0) ? "-" : "+");
+#ifdef ZERO_BATT_RING
+ if (wc->onhook) {
+ wc->onhook = 0;
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ if (debug)
+ printk("Signalled Off Hook\n");
+ }
+#else
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+#endif
+ /* set the alarm timer, taking into account that part of its time
+ period has already passed while debouncing occurred */
+ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK;
+ }
+ } else {
+ /* start the debounce timer to verify that battery has appeared */
+ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK;
+ }
+ }
+ }
+
+ if (fxo->lastpol >= 0) {
+ if (b < 0) {
+ fxo->lastpol = -1;
+ fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK;
+ }
+ }
+ if (fxo->lastpol <= 0) {
+ if (b > 0) {
+ fxo->lastpol = 1;
+ fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK;
+ }
+ }
+
+ if (fxo->battalarm) {
+ if (--fxo->battalarm == 0) {
+ /* the alarm timer has expired, so update the battery alarm state
+ for this channel */
+ zt_alarm_channel(&wc->chans[card], fxo->battery ? ZT_ALARM_NONE : ZT_ALARM_RED);
+ }
+ }
+
+ if (fxo->polaritydebounce) {
+ if (--fxo->polaritydebounce == 0) {
+ if (fxo->lastpol != fxo->polarity) {
+ if (debug)
+ printk("%lu Polarity reversed (%d -> %d)\n", jiffies,
+ fxo->polarity,
+ fxo->lastpol);
+ if (fxo->polarity)
+ zt_qevent_lock(&wc->chans[card], ZT_EVENT_POLARITY);
+ fxo->polarity = fxo->lastpol;
+ }
+ }
+ }
+#undef MS_PER_CHECK_HOOK
+}
+
+static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
+{
+ char res;
+ int hook;
+
+ /* For some reason we have to debounce the
+ hook detector. */
+
+ res = wc->reg0shadow[card];
+ hook = (res & 1);
+ if (hook != wc->mod[card].fxs.lastrxhook) {
+ /* Reset the debounce (must be multiple of 4ms) */
+ wc->mod[card].fxs.debounce = 8 * (4 * 8);
+#if 0
+ printk("Resetting debounce card %d hook %d, %d\n", card, hook, wc->mod[card].fxs.debounce);
+#endif
+ } else {
+ if (wc->mod[card].fxs.debounce > 0) {
+ wc->mod[card].fxs.debounce-= 16 * ZT_CHUNKSIZE;
+#if 0
+ printk("Sustaining hook %d, %d\n", hook, wc->mod[card].fxs.debounce);
+#endif
+ if (!wc->mod[card].fxs.debounce) {
+#if 0
+ printk("Counted down debounce, newhook: %d...\n", hook);
+#endif
+ wc->mod[card].fxs.debouncehook = hook;
+ }
+ if (!wc->mod[card].fxs.oldrxhook && wc->mod[card].fxs.debouncehook) {
+ /* Off hook */
+#if 1
+ if (debug)
+#endif
+ printk("wctdm: Card %d Going off hook\n", card);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ if (robust)
+ wctdm_init_proslic(wc, card, 1, 0, 1);
+ wc->mod[card].fxs.oldrxhook = 1;
+
+ } else if (wc->mod[card].fxs.oldrxhook && !wc->mod[card].fxs.debouncehook) {
+ /* On hook */
+#if 1
+ if (debug)
+#endif
+ printk("wctdm: Card %d Going on hook\n", card);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
+ wc->mod[card].fxs.oldrxhook = 0;
+ }
+ }
+ }
+ wc->mod[card].fxs.lastrxhook = hook;
+}
+
+ZAP_IRQ_HANDLER(wctdm_interrupt)
+{
+ struct wctdm *wc = dev_id;
+ unsigned char ints;
+ int x;
+ int mode;
+
+ ints = inb(wc->ioaddr + WC_INTSTAT);
+
+ if (!ints)
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+
+ outb(ints, wc->ioaddr + WC_INTSTAT);
+
+ if (ints & 0x10) {
+ /* Stop DMA, wait for watchdog */
+ printk("TDM PCI Master abort\n");
+ wctdm_stop_dma(wc);
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#else
+ return;
+#endif
+ }
+
+ if (ints & 0x20) {
+ printk("PCI Target abort\n");
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#else
+ return;
+#endif
+ }
+
+ for (x=0;x<4;x++) {
+ if (wc->cardflag & (1 << x) &&
+ (wc->modtype[x] == MOD_TYPE_FXS)) {
+ if (wc->mod[x].fxs.lasttxhook == 0x4) {
+ /* RINGing, prepare for OHT */
+ wc->mod[x].fxs.ohttimer = OHT_TIMER << 3;
+ if (reversepolarity)
+ wc->mod[x].fxs.idletxhookstate = 0x6; /* OHT mode when idle */
+ else
+ wc->mod[x].fxs.idletxhookstate = 0x2;
+ } else {
+ if (wc->mod[x].fxs.ohttimer) {
+ wc->mod[x].fxs.ohttimer-= ZT_CHUNKSIZE;
+ if (!wc->mod[x].fxs.ohttimer) {
+ if (reversepolarity)
+ wc->mod[x].fxs.idletxhookstate = 0x5; /* Switch to active */
+ else
+ wc->mod[x].fxs.idletxhookstate = 0x1;
+ if ((wc->mod[x].fxs.lasttxhook == 0x2) || (wc->mod[x].fxs.lasttxhook == 0x6)) {
+ /* Apply the change if appropriate */
+ if (reversepolarity)
+ wc->mod[x].fxs.lasttxhook = 0x5;
+ else
+ wc->mod[x].fxs.lasttxhook = 0x1;
+ wctdm_setreg(wc, x, 64, wc->mod[x].fxs.lasttxhook);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (ints & 0x0f) {
+ wc->intcount++;
+ x = wc->intcount & 0x3;
+ mode = wc->intcount & 0xc;
+ if (wc->cardflag & (1 << x)) {
+ switch(mode) {
+ case 0:
+ /* Rest */
+ break;
+ case 4:
+ /* Read first shadow reg */
+ if (wc->modtype[x] == MOD_TYPE_FXS)
+ wc->reg0shadow[x] = wctdm_getreg(wc, x, 68);
+ else if (wc->modtype[x] == MOD_TYPE_FXO)
+ wc->reg0shadow[x] = wctdm_getreg(wc, x, 5);
+ break;
+ case 8:
+ /* Read second shadow reg */
+ if (wc->modtype[x] == MOD_TYPE_FXS)
+ wc->reg1shadow[x] = wctdm_getreg(wc, x, 64);
+ else if (wc->modtype[x] == MOD_TYPE_FXO)
+ wc->reg1shadow[x] = wctdm_getreg(wc, x, 29);
+ break;
+ case 12:
+ /* Perform processing */
+ if (wc->modtype[x] == MOD_TYPE_FXS) {
+ wctdm_proslic_check_hook(wc, x);
+ if (!(wc->intcount & 0xf0))
+ wctdm_proslic_recheck_sanity(wc, x);
+ } else if (wc->modtype[x] == MOD_TYPE_FXO) {
+ wctdm_voicedaa_check_hook(wc, x);
+ }
+ break;
+ }
+ }
+ if (!(wc->intcount % 10000)) {
+ /* Accept an alarm once per 10 seconds */
+ for (x=0;x<4;x++)
+ if (wc->modtype[x] == MOD_TYPE_FXS) {
+ if (wc->mod[x].fxs.palarms)
+ wc->mod[x].fxs.palarms--;
+ }
+ }
+ wctdm_receiveprep(wc, ints);
+ wctdm_transmitprep(wc, ints);
+ }
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+
+}
+
+static int wctdm_voicedaa_insane(struct wctdm *wc, int card)
+{
+ int blah;
+ blah = wctdm_getreg(wc, card, 2);
+ if (blah != 0x3)
+ return -2;
+ blah = wctdm_getreg(wc, card, 11);
+ if (debug)
+ printk("VoiceDAA System: %02x\n", blah & 0xf);
+ return 0;
+}
+
+static int wctdm_proslic_insane(struct wctdm *wc, int card)
+{
+ int blah,insane_report;
+ insane_report=0;
+
+ blah = wctdm_getreg(wc, card, 0);
+ if (debug)
+ printk("ProSLIC on module %d, product %d, version %d\n", card, (blah & 0x30) >> 4, (blah & 0xf));
+
+#if 0
+ if ((blah & 0x30) >> 4) {
+ printk("ProSLIC on module %d is not a 3210.\n", card);
+ return -1;
+ }
+#endif
+ if (((blah & 0xf) == 0) || ((blah & 0xf) == 0xf)) {
+ /* SLIC not loaded */
+ return -1;
+ }
+ if ((blah & 0xf) < 2) {
+ printk("ProSLIC 3210 version %d is too old\n", blah & 0xf);
+ return -1;
+ }
+ if (wctdm_getreg(wc, card, 1) & 0x80)
+ /* ProSLIC 3215, not a 3210 */
+ wc->flags[card] |= FLAG_3215;
+
+ blah = wctdm_getreg(wc, card, 8);
+ if (blah != 0x2) {
+ printk("ProSLIC on module %d insane (1) %d should be 2\n", card, blah);
+ return -1;
+ } else if ( insane_report)
+ printk("ProSLIC on module %d Reg 8 Reads %d Expected is 0x2\n",card,blah);
+
+ blah = wctdm_getreg(wc, card, 64);
+ if (blah != 0x0) {
+ printk("ProSLIC on module %d insane (2)\n", card);
+ return -1;
+ } else if ( insane_report)
+ printk("ProSLIC on module %d Reg 64 Reads %d Expected is 0x0\n",card,blah);
+
+ blah = wctdm_getreg(wc, card, 11);
+ if (blah != 0x33) {
+ printk("ProSLIC on module %d insane (3)\n", card);
+ return -1;
+ } else if ( insane_report)
+ printk("ProSLIC on module %d Reg 11 Reads %d Expected is 0x33\n",card,blah);
+
+ /* Just be sure it's setup right. */
+ wctdm_setreg(wc, card, 30, 0);
+
+ if (debug)
+ printk("ProSLIC on module %d seems sane.\n", card);
+ return 0;
+}
+
+static int wctdm_proslic_powerleak_test(struct wctdm *wc, int card)
+{
+ unsigned long origjiffies;
+ unsigned char vbat;
+
+ /* Turn off linefeed */
+ wctdm_setreg(wc, card, 64, 0);
+
+ /* Power down */
+ wctdm_setreg(wc, card, 14, 0x10);
+
+ /* Wait for one second */
+ origjiffies = jiffies;
+
+ while((vbat = wctdm_getreg(wc, card, 82)) > 0x6) {
+ if ((jiffies - origjiffies) >= (HZ/2))
+ break;;
+ }
+
+ if (vbat < 0x06) {
+ printk("Excessive leakage detected on module %d: %d volts (%02x) after %d ms\n", card,
+ 376 * vbat / 1000, vbat, (int)((jiffies - origjiffies) * 1000 / HZ));
+ return -1;
+ } else if (debug) {
+ printk("Post-leakage voltage: %d volts\n", 376 * vbat / 1000);
+ }
+ return 0;
+}
+
+static int wctdm_powerup_proslic(struct wctdm *wc, int card, int fast)
+{
+ unsigned char vbat;
+ unsigned long origjiffies;
+ int lim;
+
+ /* Set period of DC-DC converter to 1/64 khz */
+ wctdm_setreg(wc, card, 92, 0xff /* was 0xff */);
+
+ /* Wait for VBat to powerup */
+ origjiffies = jiffies;
+
+ /* Disable powerdown */
+ wctdm_setreg(wc, card, 14, 0);
+
+ /* If fast, don't bother checking anymore */
+ if (fast)
+ return 0;
+
+ while((vbat = wctdm_getreg(wc, card, 82)) < 0xc0) {
+ /* Wait no more than 500ms */
+ if ((jiffies - origjiffies) > HZ/2) {
+ break;
+ }
+ }
+
+ if (vbat < 0xc0) {
+ if (wc->proslic_power == PROSLIC_POWER_UNKNOWN)
+ printk("ProSLIC on module %d failed to powerup within %d ms (%d mV only)\n\n -- DID YOU REMEMBER TO PLUG IN THE HD POWER CABLE TO THE TDM400P??\n",
+ card, (int)(((jiffies - origjiffies) * 1000 / HZ)),
+ vbat * 375);
+ wc->proslic_power = PROSLIC_POWER_WARNED;
+ return -1;
+ } else if (debug) {
+ printk("ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n",
+ card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ)));
+ }
+ wc->proslic_power = PROSLIC_POWER_ON;
+
+ /* Proslic max allowed loop current, reg 71 LOOP_I_LIMIT */
+ /* If out of range, just set it to the default value */
+ lim = (loopcurrent - 20) / 3;
+ if ( loopcurrent > 41 ) {
+ lim = 0;
+ if (debug)
+ printk("Loop current out of range! Setting to default 20mA!\n");
+ }
+ else if (debug)
+ printk("Loop current set to %dmA!\n",(lim*3)+20);
+ wctdm_setreg(wc,card,LOOP_I_LIMIT,lim);
+
+ /* Engage DC-DC converter */
+ wctdm_setreg(wc, card, 93, 0x19 /* was 0x19 */);
+#if 0
+ origjiffies = jiffies;
+ while(0x80 & wctdm_getreg(wc, card, 93)) {
+ if ((jiffies - origjiffies) > 2 * HZ) {
+ printk("Timeout waiting for DC-DC calibration on module %d\n", card);
+ return -1;
+ }
+ }
+
+#if 0
+ /* Wait a full two seconds */
+ while((jiffies - origjiffies) < 2 * HZ);
+
+ /* Just check to be sure */
+ vbat = wctdm_getreg(wc, card, 82);
+ printk("ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n",
+ card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ)));
+#endif
+#endif
+ return 0;
+
+}
+
+static int wctdm_proslic_manual_calibrate(struct wctdm *wc, int card){
+ unsigned long origjiffies;
+ unsigned char i;
+
+ wctdm_setreg(wc, card, 21, 0);//(0) Disable all interupts in DR21
+ wctdm_setreg(wc, card, 22, 0);//(0)Disable all interupts in DR21
+ wctdm_setreg(wc, card, 23, 0);//(0)Disable all interupts in DR21
+ wctdm_setreg(wc, card, 64, 0);//(0)
+
+ wctdm_setreg(wc, card, 97, 0x18); //(0x18)Calibrations without the ADC and DAC offset and without common mode calibration.
+ wctdm_setreg(wc, card, 96, 0x47); //(0x47) Calibrate common mode and differential DAC mode DAC + ILIM
+
+ origjiffies=jiffies;
+ while( wctdm_getreg(wc,card,96)!=0 ){
+ if((jiffies-origjiffies)>80)
+ return -1;
+ }
+//Initialized DR 98 and 99 to get consistant results.
+// 98 and 99 are the results registers and the search should have same intial conditions.
+
+/*******************************The following is the manual gain mismatch calibration****************************/
+/*******************************This is also available as a function *******************************************/
+ // Delay 10ms
+ origjiffies=jiffies;
+ while((jiffies-origjiffies)<1);
+ wctdm_proslic_setreg_indirect(wc, card, 88,0);
+ wctdm_proslic_setreg_indirect(wc,card,89,0);
+ wctdm_proslic_setreg_indirect(wc,card,90,0);
+ wctdm_proslic_setreg_indirect(wc,card,91,0);
+ wctdm_proslic_setreg_indirect(wc,card,92,0);
+ wctdm_proslic_setreg_indirect(wc,card,93,0);
+
+ wctdm_setreg(wc, card, 98,0x10); // This is necessary if the calibration occurs other than at reset time
+ wctdm_setreg(wc, card, 99,0x10);
+
+ for ( i=0x1f; i>0; i--)
+ {
+ wctdm_setreg(wc, card, 98,i);
+ origjiffies=jiffies;
+ while((jiffies-origjiffies)<4);
+ if((wctdm_getreg(wc,card,88)) == 0)
+ break;
+ } // for
+
+ for ( i=0x1f; i>0; i--)
+ {
+ wctdm_setreg(wc, card, 99,i);
+ origjiffies=jiffies;
+ while((jiffies-origjiffies)<4);
+ if((wctdm_getreg(wc,card,89)) == 0)
+ break;
+ }//for
+
+/*******************************The preceding is the manual gain mismatch calibration****************************/
+/**********************************The following is the longitudinal Balance Cal***********************************/
+ wctdm_setreg(wc,card,64,1);
+ while((jiffies-origjiffies)<10); // Sleep 100?
+
+ wctdm_setreg(wc, card, 64, 0);
+ wctdm_setreg(wc, card, 23, 0x4); // enable interrupt for the balance Cal
+ wctdm_setreg(wc, card, 97, 0x1); // this is a singular calibration bit for longitudinal calibration
+ wctdm_setreg(wc, card, 96,0x40);
+
+ wctdm_getreg(wc,card,96); /* Read Reg 96 just cause */
+
+ wctdm_setreg(wc, card, 21, 0xFF);
+ wctdm_setreg(wc, card, 22, 0xFF);
+ wctdm_setreg(wc, card, 23, 0xFF);
+
+ /**The preceding is the longitudinal Balance Cal***/
+ return(0);
+
+}
+#if 1
+static int wctdm_proslic_calibrate(struct wctdm *wc, int card)
+{
+ unsigned long origjiffies;
+ int x;
+ /* Perform all calibrations */
+ wctdm_setreg(wc, card, 97, 0x1f);
+
+ /* Begin, no speedup */
+ wctdm_setreg(wc, card, 96, 0x5f);
+
+ /* Wait for it to finish */
+ origjiffies = jiffies;
+ while(wctdm_getreg(wc, card, 96)) {
+ if ((jiffies - origjiffies) > 2 * HZ) {
+ printk("Timeout waiting for calibration of module %d\n", card);
+ return -1;
+ }
+ }
+
+ if (debug) {
+ /* Print calibration parameters */
+ printk("Calibration Vector Regs 98 - 107: \n");
+ for (x=98;x<108;x++) {
+ printk("%d: %02x\n", x, wctdm_getreg(wc, card, x));
+ }
+ }
+ return 0;
+}
+#endif
+
+static void wait_just_a_bit(int foo)
+{
+ long newjiffies;
+ newjiffies = jiffies + foo;
+ while(jiffies < newjiffies);
+}
+
+/*********************************************************************
+ * Set the hwgain on the analog modules
+ *
+ * card = the card position for this module (0-23)
+ * gain = gain in dB x10 (e.g. -3.5dB would be gain=-35)
+ * tx = (0 for rx; 1 for tx)
+ *
+ *******************************************************************/
+static int wctdm_set_hwgain(struct wctdm *wc, int card, __s32 gain, __u32 tx)
+{
+ if (!(wc->modtype[card] == MOD_TYPE_FXO)) {
+ printk("Cannot adjust gain. Unsupported module type!\n");
+ return -1;
+ }
+ if (tx) {
+ if (debug)
+ printk("setting FXO tx gain for card=%d to %d\n", card, gain);
+ if (gain >= -150 && gain <= 0) {
+ wctdm_setreg(wc, card, 38, 16 + (gain/-10));
+ wctdm_setreg(wc, card, 40, 16 + (-gain%10));
+ } else if (gain <= 120 && gain > 0) {
+ wctdm_setreg(wc, card, 38, gain/10);
+ wctdm_setreg(wc, card, 40, (gain%10));
+ } else {
+ printk("FXO tx gain is out of range (%d)\n", gain);
+ return -1;
+ }
+ } else { /* rx */
+ if (debug)
+ printk("setting FXO rx gain for card=%d to %d\n", card, gain);
+ if (gain >= -150 && gain <= 0) {
+ wctdm_setreg(wc, card, 39, 16+ (gain/-10));
+ wctdm_setreg(wc, card, 41, 16 + (-gain%10));
+ } else if (gain <= 120 && gain > 0) {
+ wctdm_setreg(wc, card, 39, gain/10);
+ wctdm_setreg(wc, card, 41, (gain%10));
+ } else {
+ printk("FXO rx gain is out of range (%d)\n", gain);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int wctdm_init_voicedaa(struct wctdm *wc, int card, int fast, int manual, int sane)
+{
+ unsigned char reg16=0, reg26=0, reg30=0, reg31=0;
+ long newjiffies;
+ wc->modtype[card] = MOD_TYPE_FXO;
+ /* Sanity check the ProSLIC */
+ reset_spi(wc, card);
+ if (!sane && wctdm_voicedaa_insane(wc, card))
+ return -2;
+
+ /* Software reset */
+ wctdm_setreg(wc, card, 1, 0x80);
+
+ /* Wait just a bit */
+ wait_just_a_bit(HZ/10);
+
+ /* Enable PCM, ulaw */
+ if (alawoverride)
+ wctdm_setreg(wc, card, 33, 0x20);
+ else
+ wctdm_setreg(wc, card, 33, 0x28);
+
+ /* Set On-hook speed, Ringer impedence, and ringer threshold */
+ reg16 |= (fxo_modes[_opermode].ohs << 6);
+ reg16 |= (fxo_modes[_opermode].rz << 1);
+ reg16 |= (fxo_modes[_opermode].rt);
+ wctdm_setreg(wc, card, 16, reg16);
+
+ if(fwringdetect) {
+ /* Enable ring detector full-wave rectifier mode */
+ wctdm_setreg(wc, card, 18, 2);
+ wctdm_setreg(wc, card, 24, 0);
+ } else {
+ /* Set to the device defaults */
+ wctdm_setreg(wc, card, 18, 0);
+ wctdm_setreg(wc, card, 24, 0x19);
+ }
+
+ /* Set DC Termination:
+ Tip/Ring voltage adjust, minimum operational current, current limitation */
+ reg26 |= (fxo_modes[_opermode].dcv << 6);
+ reg26 |= (fxo_modes[_opermode].mini << 4);
+ reg26 |= (fxo_modes[_opermode].ilim << 1);
+ wctdm_setreg(wc, card, 26, reg26);
+
+ /* Set AC Impedence */
+ reg30 = (fxo_modes[_opermode].acim);
+ wctdm_setreg(wc, card, 30, reg30);
+
+ /* Misc. DAA parameters */
+ if (fastpickup)
+ reg31 = 0xb3;
+ else
+ reg31 = 0xa3;
+
+ reg31 |= (fxo_modes[_opermode].ohs2 << 3);
+ wctdm_setreg(wc, card, 31, reg31);
+
+ /* Set Transmit/Receive timeslot */
+ wctdm_setreg(wc, card, 34, (3-card) * 8);
+ wctdm_setreg(wc, card, 35, 0x00);
+ wctdm_setreg(wc, card, 36, (3-card) * 8);
+ wctdm_setreg(wc, card, 37, 0x00);
+
+ /* Enable ISO-Cap */
+ wctdm_setreg(wc, card, 6, 0x00);
+
+ if (fastpickup)
+ wctdm_setreg(wc, card, 17, wctdm_getreg(wc, card, 17) | 0x20);
+
+ /* Wait 1000ms for ISO-cap to come up */
+ newjiffies = jiffies;
+ newjiffies += 2 * HZ;
+ while((jiffies < newjiffies) && !(wctdm_getreg(wc, card, 11) & 0xf0))
+ wait_just_a_bit(HZ/10);
+
+ if (!(wctdm_getreg(wc, card, 11) & 0xf0)) {
+ printk("VoiceDAA did not bring up ISO link properly!\n");
+ return -1;
+ }
+ if (debug)
+ printk("ISO-Cap is now up, line side: %02x rev %02x\n",
+ wctdm_getreg(wc, card, 11) >> 4,
+ (wctdm_getreg(wc, card, 13) >> 2) & 0xf);
+ /* Enable on-hook line monitor */
+ wctdm_setreg(wc, card, 5, 0x08);
+
+ /* Take values for fxotxgain and fxorxgain and apply them to module */
+ wctdm_set_hwgain(wc, card, fxotxgain, 1);
+ wctdm_set_hwgain(wc, card, fxorxgain, 0);
+
+ /* NZ -- crank the tx gain up by 7 dB */
+ if (!strcmp(fxo_modes[_opermode].name, "NEWZEALAND")) {
+ printk("Adjusting gain\n");
+ wctdm_set_hwgain(wc, card, 7, 1);
+ }
+
+ if(debug)
+ printk("DEBUG fxotxgain:%i.%i fxorxgain:%i.%i\n", (wctdm_getreg(wc, card, 38)/16)?-(wctdm_getreg(wc, card, 38) - 16) : wctdm_getreg(wc, card, 38), (wctdm_getreg(wc, card, 40)/16)? -(wctdm_getreg(wc, card, 40) - 16):wctdm_getreg(wc, card, 40), (wctdm_getreg(wc, card, 39)/16)? -(wctdm_getreg(wc, card, 39) - 16) : wctdm_getreg(wc, card, 39),(wctdm_getreg(wc, card, 41)/16)?-(wctdm_getreg(wc, card, 41) - 16):wctdm_getreg(wc, card, 41));
+
+ return 0;
+
+}
+
+static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual, int sane)
+{
+
+ unsigned short tmp[5];
+ unsigned char r19,r9;
+ int x;
+ int fxsmode=0;
+
+ /* Sanity check the ProSLIC */
+ if (!sane && wctdm_proslic_insane(wc, card))
+ return -2;
+
+ /* By default, don't send on hook */
+ if (reversepolarity)
+ wc->mod[card].fxs.idletxhookstate = 5;
+ else
+ wc->mod[card].fxs.idletxhookstate = 1;
+
+ if (sane) {
+ /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */
+ wctdm_setreg(wc, card, 14, 0x10);
+ }
+
+ if (wctdm_proslic_init_indirect_regs(wc, card)) {
+ printk(KERN_INFO "Indirect Registers failed to initialize on module %d.\n", card);
+ return -1;
+ }
+
+ /* Clear scratch pad area */
+ wctdm_proslic_setreg_indirect(wc, card, 97,0);
+
+ /* Clear digital loopback */
+ wctdm_setreg(wc, card, 8, 0);
+
+ /* Revision C optimization */
+ wctdm_setreg(wc, card, 108, 0xeb);
+
+ /* Disable automatic VBat switching for safety to prevent
+ Q7 from accidently turning on and burning out. */
+ wctdm_setreg(wc, card, 67, 0x07); /* Note, if pulse dialing has problems at high REN loads
+ change this to 0x17 */
+
+ /* Turn off Q7 */
+ wctdm_setreg(wc, card, 66, 1);
+
+ /* Flush ProSLIC digital filters by setting to clear, while
+ saving old values */
+ for (x=0;x<5;x++) {
+ tmp[x] = wctdm_proslic_getreg_indirect(wc, card, x + 35);
+ wctdm_proslic_setreg_indirect(wc, card, x + 35, 0x8000);
+ }
+
+ /* Power up the DC-DC converter */
+ if (wctdm_powerup_proslic(wc, card, fast)) {
+ printk("Unable to do INITIAL ProSLIC powerup on module %d\n", card);
+ return -1;
+ }
+
+ if (!fast) {
+
+ /* Check for power leaks */
+ if (wctdm_proslic_powerleak_test(wc, card)) {
+ printk("ProSLIC module %d failed leakage test. Check for short circuit\n", card);
+ }
+ /* Power up again */
+ if (wctdm_powerup_proslic(wc, card, fast)) {
+ printk("Unable to do FINAL ProSLIC powerup on module %d\n", card);
+ return -1;
+ }
+#ifndef NO_CALIBRATION
+ /* Perform calibration */
+ if(manual) {
+ if (wctdm_proslic_manual_calibrate(wc, card)) {
+ //printk("Proslic failed on Manual Calibration\n");
+ if (wctdm_proslic_manual_calibrate(wc, card)) {
+ printk("Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n");
+ return -1;
+ }
+ printk("Proslic Passed Manual Calibration on Second Attempt\n");
+ }
+ }
+ else {
+ if(wctdm_proslic_calibrate(wc, card)) {
+ //printk("ProSlic died on Auto Calibration.\n");
+ if (wctdm_proslic_calibrate(wc, card)) {
+ printk("Proslic Failed on Second Attempt to Auto Calibrate\n");
+ return -1;
+ }
+ printk("Proslic Passed Auto Calibration on Second Attempt\n");
+ }
+ }
+ /* Perform DC-DC calibration */
+ wctdm_setreg(wc, card, 93, 0x99);
+ r19 = wctdm_getreg(wc, card, 107);
+ if ((r19 < 0x2) || (r19 > 0xd)) {
+ printk("DC-DC cal has a surprising direct 107 of 0x%02x!\n", r19);
+ wctdm_setreg(wc, card, 107, 0x8);
+ }
+
+ /* Save calibration vectors */
+ for (x=0;x<NUM_CAL_REGS;x++)
+ wc->mod[card].fxs.calregs.vals[x] = wctdm_getreg(wc, card, 96 + x);
+#endif
+
+ } else {
+ /* Restore calibration registers */
+ for (x=0;x<NUM_CAL_REGS;x++)
+ wctdm_setreg(wc, card, 96 + x, wc->mod[card].fxs.calregs.vals[x]);
+ }
+ /* Calibration complete, restore original values */
+ for (x=0;x<5;x++) {
+ wctdm_proslic_setreg_indirect(wc, card, x + 35, tmp[x]);
+ }
+
+ if (wctdm_proslic_verify_indirect_regs(wc, card)) {
+ printk(KERN_INFO "Indirect Registers failed verification.\n");
+ return -1;
+ }
+
+
+#if 0
+ /* Disable Auto Power Alarm Detect and other "features" */
+ wctdm_setreg(wc, card, 67, 0x0e);
+ blah = wctdm_getreg(wc, card, 67);
+#endif
+
+#if 0
+ if (wctdm_proslic_setreg_indirect(wc, card, 97, 0x0)) { // Stanley: for the bad recording fix
+ printk(KERN_INFO "ProSlic IndirectReg Died.\n");
+ return -1;
+ }
+#endif
+
+ if (alawoverride)
+ wctdm_setreg(wc, card, 1, 0x20);
+ else
+ wctdm_setreg(wc, card, 1, 0x28);
+ // U-Law 8-bit interface
+ wctdm_setreg(wc, card, 2, (3-card) * 8); // Tx Start count low byte 0
+ wctdm_setreg(wc, card, 3, 0); // Tx Start count high byte 0
+ wctdm_setreg(wc, card, 4, (3-card) * 8); // Rx Start count low byte 0
+ wctdm_setreg(wc, card, 5, 0); // Rx Start count high byte 0
+ wctdm_setreg(wc, card, 18, 0xff); // clear all interrupt
+ wctdm_setreg(wc, card, 19, 0xff);
+ wctdm_setreg(wc, card, 20, 0xff);
+ wctdm_setreg(wc, card, 73, 0x04);
+ if (fxshonormode) {
+ fxsmode = acim2tiss[fxo_modes[_opermode].acim];
+ wctdm_setreg(wc, card, 10, 0x08 | fxsmode);
+ if (fxo_modes[_opermode].ring_osc)
+ wctdm_proslic_setreg_indirect(wc, card, 20, fxo_modes[_opermode].ring_osc);
+ if (fxo_modes[_opermode].ring_x)
+ wctdm_proslic_setreg_indirect(wc, card, 21, fxo_modes[_opermode].ring_x);
+ }
+ if (lowpower)
+ wctdm_setreg(wc, card, 72, 0x10);
+
+#if 0
+ wctdm_setreg(wc, card, 21, 0x00); // enable interrupt
+ wctdm_setreg(wc, card, 22, 0x02); // Loop detection interrupt
+ wctdm_setreg(wc, card, 23, 0x01); // DTMF detection interrupt
+#endif
+
+#if 0
+ /* Enable loopback */
+ wctdm_setreg(wc, card, 8, 0x2);
+ wctdm_setreg(wc, card, 14, 0x0);
+ wctdm_setreg(wc, card, 64, 0x0);
+ wctdm_setreg(wc, card, 1, 0x08);
+#endif
+
+ if (fastringer) {
+ /* Speed up Ringer */
+ wctdm_proslic_setreg_indirect(wc, card, 20, 0x7e6d);
+ wctdm_proslic_setreg_indirect(wc, card, 21, 0x01b9);
+ /* Beef up Ringing voltage to 89V */
+ if (boostringer) {
+ wctdm_setreg(wc, card, 74, 0x3f);
+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x247))
+ return -1;
+ printk("Boosting fast ringer on slot %d (89V peak)\n", card + 1);
+ } else if (lowpower) {
+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x14b))
+ return -1;
+ printk("Reducing fast ring power on slot %d (50V peak)\n", card + 1);
+ } else
+ printk("Speeding up ringer on slot %d (25Hz)\n", card + 1);
+ } else {
+ /* Beef up Ringing voltage to 89V */
+ if (boostringer) {
+ wctdm_setreg(wc, card, 74, 0x3f);
+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x1d1))
+ return -1;
+ printk("Boosting ringer on slot %d (89V peak)\n", card + 1);
+ } else if (lowpower) {
+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x108))
+ return -1;
+ printk("Reducing ring power on slot %d (50V peak)\n", card + 1);
+ }
+ }
+
+ if(fxstxgain || fxsrxgain) {
+ r9 = wctdm_getreg(wc, card, 9);
+ switch (fxstxgain) {
+
+ case 35:
+ r9+=8;
+ break;
+ case -35:
+ r9+=4;
+ break;
+ case 0:
+ break;
+ }
+
+ switch (fxsrxgain) {
+
+ case 35:
+ r9+=2;
+ break;
+ case -35:
+ r9+=1;
+ break;
+ case 0:
+ break;
+ }
+ wctdm_setreg(wc,card,9,r9);
+ }
+
+ if(debug)
+ printk("DEBUG: fxstxgain:%s fxsrxgain:%s\n",((wctdm_getreg(wc, card, 9)/8) == 1)?"3.5":(((wctdm_getreg(wc,card,9)/4) == 1)?"-3.5":"0.0"),((wctdm_getreg(wc, card, 9)/2) == 1)?"3.5":((wctdm_getreg(wc,card,9)%2)?"-3.5":"0.0"));
+
+ wctdm_setreg(wc, card, 64, 0x01);
+ return 0;
+}
+
+
+static int wctdm_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
+{
+ struct wctdm_stats stats;
+ struct wctdm_regs regs;
+ struct wctdm_regop regop;
+ struct wctdm_echo_coefs echoregs;
+ struct zt_hwgain hwgain;
+ struct wctdm *wc = chan->pvt;
+ int x;
+ switch (cmd) {
+ case ZT_ONHOOKTRANSFER:
+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
+ return -EINVAL;
+ if (get_user(x, (int *)data))
+ return -EFAULT;
+ wc->mod[chan->chanpos - 1].fxs.ohttimer = x << 3;
+ if (reversepolarity)
+ wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 0x6; /* OHT mode when idle */
+ else
+ wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 0x2;
+ if (wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x1 || wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x5) {
+ /* Apply the change if appropriate */
+ if (reversepolarity)
+ wc->mod[chan->chanpos - 1].fxs.lasttxhook = 0x6;
+ else
+ wc->mod[chan->chanpos - 1].fxs.lasttxhook = 0x2;
+ wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook);
+ }
+ break;
+ case ZT_SETPOLARITY:
+ if (get_user(x, (int *)data))
+ return -EFAULT;
+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
+ return -EINVAL;
+ /* Can't change polarity while ringing or when open */
+ if ((wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x04) ||
+ (wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x00))
+ return -EINVAL;
+
+ if ((x && !reversepolarity) || (!x && reversepolarity))
+ wc->mod[chan->chanpos - 1].fxs.lasttxhook |= 0x04;
+ else
+ wc->mod[chan->chanpos - 1].fxs.lasttxhook &= ~0x04;
+ wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook);
+ break;
+ case WCTDM_GET_STATS:
+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
+ stats.tipvolt = wctdm_getreg(wc, chan->chanpos - 1, 80) * -376;
+ stats.ringvolt = wctdm_getreg(wc, chan->chanpos - 1, 81) * -376;
+ stats.batvolt = wctdm_getreg(wc, chan->chanpos - 1, 82) * -376;
+ } else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
+ stats.tipvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000;
+ stats.ringvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000;
+ stats.batvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000;
+ } else
+ return -EINVAL;
+ if (copy_to_user((struct wctdm_stats *)data, &stats, sizeof(stats)))
+ return -EFAULT;
+ break;
+ case WCTDM_GET_REGS:
+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
+ for (x=0;x<NUM_INDIRECT_REGS;x++)
+ regs.indirect[x] = wctdm_proslic_getreg_indirect(wc, chan->chanpos -1, x);
+ for (x=0;x<NUM_REGS;x++)
+ regs.direct[x] = wctdm_getreg(wc, chan->chanpos - 1, x);
+ } else {
+ memset(&regs, 0, sizeof(regs));
+ for (x=0;x<NUM_FXO_REGS;x++)
+ regs.direct[x] = wctdm_getreg(wc, chan->chanpos - 1, x);
+ }
+ if (copy_to_user((struct wctdm_regs *)data, &regs, sizeof(regs)))
+ return -EFAULT;
+ break;
+ case WCTDM_SET_REG:
+ if (copy_from_user(&regop, (struct wctdm_regop *)data, sizeof(regop)))
+ return -EFAULT;
+ if (regop.indirect) {
+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
+ return -EINVAL;
+ printk("Setting indirect %d to 0x%04x on %d\n", regop.reg, regop.val, chan->chanpos);
+ wctdm_proslic_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val);
+ } else {
+ regop.val &= 0xff;
+ printk("Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos);
+ wctdm_setreg(wc, chan->chanpos - 1, regop.reg, regop.val);
+ }
+ break;
+ case WCTDM_SET_ECHOTUNE:
+ printk("-- Setting echo registers: \n");
+ if (copy_from_user(&echoregs, (struct wctdm_echo_coefs*)data, sizeof(echoregs)))
+ return -EFAULT;
+
+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
+ /* Set the ACIM register */
+ wctdm_setreg(wc, chan->chanpos - 1, 30, echoregs.acim);
+
+ /* Set the digital echo canceller registers */
+ wctdm_setreg(wc, chan->chanpos - 1, 45, echoregs.coef1);
+ wctdm_setreg(wc, chan->chanpos - 1, 46, echoregs.coef2);
+ wctdm_setreg(wc, chan->chanpos - 1, 47, echoregs.coef3);
+ wctdm_setreg(wc, chan->chanpos - 1, 48, echoregs.coef4);
+ wctdm_setreg(wc, chan->chanpos - 1, 49, echoregs.coef5);
+ wctdm_setreg(wc, chan->chanpos - 1, 50, echoregs.coef6);
+ wctdm_setreg(wc, chan->chanpos - 1, 51, echoregs.coef7);
+ wctdm_setreg(wc, chan->chanpos - 1, 52, echoregs.coef8);
+
+ printk("-- Set echo registers successfully\n");
+
+ break;
+ } else {
+ return -EINVAL;
+
+ }
+ break;
+ case ZT_SET_HWGAIN:
+ if (copy_from_user(&hwgain, (struct zt_hwgain*) data, sizeof(hwgain)))
+ return -EFAULT;
+
+ wctdm_set_hwgain(wc, chan->chanpos-1, hwgain.newgain, hwgain.tx);
+
+ if (debug)
+ printk("Setting hwgain on channel %d to %d for %s direction\n",
+ chan->chanpos-1, hwgain.newgain, hwgain.tx ? "tx" : "rx");
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+
+}
+
+static int wctdm_open(struct zt_chan *chan)
+{
+ struct wctdm *wc = chan->pvt;
+ if (!(wc->cardflag & (1 << (chan->chanpos - 1))))
+ return -ENODEV;
+ if (wc->dead)
+ return -ENODEV;
+ wc->usecount++;
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#else
+ try_module_get(THIS_MODULE);
+#endif
+ return 0;
+}
+
+static int wctdm_watchdog(struct zt_span *span, int event)
+{
+ printk("TDM: Restarting DMA\n");
+ wctdm_restart_dma(span->pvt);
+ return 0;
+}
+
+static int wctdm_close(struct zt_chan *chan)
+{
+ struct wctdm *wc = chan->pvt;
+ wc->usecount--;
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#else
+ module_put(THIS_MODULE);
+#endif
+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
+ if (reversepolarity)
+ wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 5;
+ else
+ wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 1;
+ }
+ /* If we're dead, release us now */
+ if (!wc->usecount && wc->dead)
+ wctdm_release(wc);
+ return 0;
+}
+
+static int wctdm_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
+{
+ struct wctdm *wc = chan->pvt;
+ int reg=0;
+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
+ /* XXX Enable hooksig for FXO XXX */
+ switch(txsig) {
+ case ZT_TXSIG_START:
+ case ZT_TXSIG_OFFHOOK:
+ wc->mod[chan->chanpos - 1].fxo.offhook = 1;
+ wctdm_setreg(wc, chan->chanpos - 1, 5, 0x9);
+ break;
+ case ZT_TXSIG_ONHOOK:
+ wc->mod[chan->chanpos - 1].fxo.offhook = 0;
+ wctdm_setreg(wc, chan->chanpos - 1, 5, 0x8);
+ break;
+ default:
+ printk("wcfxo: Can't set tx state to %d\n", txsig);
+ }
+ } else {
+ switch(txsig) {
+ case ZT_TXSIG_ONHOOK:
+ switch(chan->sig) {
+ case ZT_SIG_EM:
+ case ZT_SIG_FXOKS:
+ case ZT_SIG_FXOLS:
+ wc->mod[chan->chanpos-1].fxs.lasttxhook = wc->mod[chan->chanpos-1].fxs.idletxhookstate;
+ break;
+ case ZT_SIG_FXOGS:
+ wc->mod[chan->chanpos-1].fxs.lasttxhook = 3;
+ break;
+ }
+ break;
+ case ZT_TXSIG_OFFHOOK:
+ switch(chan->sig) {
+ case ZT_SIG_EM:
+ wc->mod[chan->chanpos-1].fxs.lasttxhook = 5;
+ break;
+ default:
+ wc->mod[chan->chanpos-1].fxs.lasttxhook = wc->mod[chan->chanpos-1].fxs.idletxhookstate;
+ break;
+ }
+ break;
+ case ZT_TXSIG_START:
+ wc->mod[chan->chanpos-1].fxs.lasttxhook = 4;
+ break;
+ case ZT_TXSIG_KEWL:
+ wc->mod[chan->chanpos-1].fxs.lasttxhook = 0;
+ break;
+ default:
+ printk("wctdm: Can't set tx state to %d\n", txsig);
+ }
+ if (debug)
+ printk("Setting FXS hook state to %d (%02x)\n", txsig, reg);
+
+#if 1
+ wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos-1].fxs.lasttxhook);
+#endif
+ }
+ return 0;
+}
+
+static int wctdm_initialize(struct wctdm *wc)
+{
+ int x;
+
+ /* Zapata stuff */
+ sprintf(wc->span.name, "WCTDM/%d", wc->pos);
+ snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1);
+ snprintf(wc->span.location, sizeof(wc->span.location) - 1,
+ "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1);
+ wc->span.manufacturer = "Digium";
+ zap_copy_string(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype));
+ if (alawoverride) {
+ printk("ALAW override parameter detected. Device will be operating in ALAW\n");
+ wc->span.deflaw = ZT_LAW_ALAW;
+ } else
+ wc->span.deflaw = ZT_LAW_MULAW;
+ for (x = 0; x < NUM_CARDS; x++) {
+ sprintf(wc->chans[x].name, "WCTDM/%d/%d", wc->pos, x);
+ wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_SF | ZT_SIG_EM | ZT_SIG_CLEAR;
+ wc->chans[x].sigcap |= ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF | ZT_SIG_CLEAR;
+ wc->chans[x].chanpos = x+1;
+ wc->chans[x].pvt = wc;
+ }
+ wc->span.chans = wc->chans;
+ wc->span.channels = NUM_CARDS;
+ wc->span.hooksig = wctdm_hooksig;
+ wc->span.irq = wc->dev->irq;
+ wc->span.open = wctdm_open;
+ wc->span.close = wctdm_close;
+ wc->span.flags = ZT_FLAG_RBS;
+ wc->span.ioctl = wctdm_ioctl;
+ wc->span.watchdog = wctdm_watchdog;
+ init_waitqueue_head(&wc->span.maintq);
+
+ wc->span.pvt = wc;
+ if (zt_register(&wc->span, 0)) {
+ printk("Unable to register span with zaptel\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void wctdm_post_initialize(struct wctdm *wc)
+{
+ int x;
+
+ /* Finalize signalling */
+ for (x = 0; x < NUM_CARDS; x++) {
+ if (wc->cardflag & (1 << x)) {
+ if (wc->modtype[x] == MOD_TYPE_FXO)
+ wc->chans[x].sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF | ZT_SIG_CLEAR;
+ else
+ wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_SF | ZT_SIG_EM | ZT_SIG_CLEAR;
+ } else if (!(wc->chans[x].sigcap & ZT_SIG_BROKEN)) {
+ wc->chans[x].sigcap = 0;
+ }
+ }
+}
+
+static int wctdm_hardware_init(struct wctdm *wc)
+{
+ /* Hardware stuff */
+ unsigned char ver;
+ unsigned char x,y;
+ int failed;
+
+ /* Signal Reset */
+ outb(0x01, wc->ioaddr + WC_CNTL);
+
+ /* Check Freshmaker chip */
+ x=inb(wc->ioaddr + WC_CNTL);
+ ver = __wctdm_getcreg(wc, WC_VER);
+ failed = 0;
+ if (ver != 0x59) {
+ printk("Freshmaker version: %02x\n", ver);
+ for (x=0;x<255;x++) {
+ /* Test registers */
+ if (ver >= 0x70) {
+ __wctdm_setcreg(wc, WC_CS, x);
+ y = __wctdm_getcreg(wc, WC_CS);
+ } else {
+ __wctdm_setcreg(wc, WC_TEST, x);
+ y = __wctdm_getcreg(wc, WC_TEST);
+ }
+ if (x != y) {
+ printk("%02x != %02x\n", x, y);
+ failed++;
+ }
+ }
+ if (!failed) {
+ printk("Freshmaker passed register test\n");
+ } else {
+ printk("Freshmaker failed register test\n");
+ return -1;
+ }
+ /* Go to half-duty FSYNC */
+ __wctdm_setcreg(wc, WC_SYNC, 0x01);
+ y = __wctdm_getcreg(wc, WC_SYNC);
+ } else {
+ printk("No freshmaker chip\n");
+ }
+
+ /* Reset PCI Interface chip and registers (and serial) */
+ outb(0x06, wc->ioaddr + WC_CNTL);
+ /* Setup our proper outputs for when we switch for our "serial" port */
+ wc->ios = BIT_CS | BIT_SCLK | BIT_SDI;
+
+ outb(wc->ios, wc->ioaddr + WC_AUXD);
+
+ /* Set all to outputs except AUX 5, which is an input */
+ outb(0xdf, wc->ioaddr + WC_AUXC);
+
+ /* Select alternate function for AUX0 */
+ outb(0x4, wc->ioaddr + WC_AUXFUNC);
+
+ /* Wait 1/4 of a sec */
+ wait_just_a_bit(HZ/4);
+
+ /* Back to normal, with automatic DMA wrap around */
+ outb(0x30 | 0x01, wc->ioaddr + WC_CNTL);
+
+ /* Make sure serial port and DMA are out of reset */
+ outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, wc->ioaddr + WC_CNTL);
+
+ /* Configure serial port for MSB->LSB operation */
+ outb(0xc1, wc->ioaddr + WC_SERCTL);
+
+ /* Delay FSC by 0 so it's properly aligned */
+ outb(0x0, wc->ioaddr + WC_FSCDELAY);
+
+ /* Setup DMA Addresses */
+ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */
+ outl(wc->writedma + ZT_CHUNKSIZE * 4 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */
+ outl(wc->writedma + ZT_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMAWE); /* End */
+
+ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */
+ outl(wc->readdma + ZT_CHUNKSIZE * 4 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */
+ outl(wc->readdma + ZT_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMARE); /* End */
+
+ /* Clear interrupts */
+ outb(0xff, wc->ioaddr + WC_INTSTAT);
+
+ /* Wait 1/4 of a second more */
+ wait_just_a_bit(HZ/4);
+
+ for (x = 0; x < NUM_CARDS; x++) {
+ int sane=0,ret=0,readi=0;
+#if 1
+ /* Init with Auto Calibration */
+ if (!(ret=wctdm_init_proslic(wc, x, 0, 0, sane))) {
+ wc->cardflag |= (1 << x);
+ if (debug) {
+ readi = wctdm_getreg(wc,x,LOOP_I_LIMIT);
+ printk("Proslic module %d loop current is %dmA\n",x,
+ ((readi*3)+20));
+ }
+ printk("Module %d: Installed -- AUTO FXS/DPO\n",x);
+ } else {
+ if(ret!=-2) {
+ sane=1;
+ /* Init with Manual Calibration */
+ if (!wctdm_init_proslic(wc, x, 0, 1, sane)) {
+ wc->cardflag |= (1 << x);
+ if (debug) {
+ readi = wctdm_getreg(wc,x,LOOP_I_LIMIT);
+ printk("Proslic module %d loop current is %dmA\n",x,
+ ((readi*3)+20));
+ }
+ printk("Module %d: Installed -- MANUAL FXS\n",x);
+ } else {
+ printk("Module %d: FAILED FXS (%s)\n", x, fxshonormode ? fxo_modes[_opermode].name : "FCC");
+ wc->chans[x].sigcap = __ZT_SIG_FXO | ZT_SIG_BROKEN;
+ }
+ } else if (!(ret = wctdm_init_voicedaa(wc, x, 0, 0, sane))) {
+ wc->cardflag |= (1 << x);
+ printk("Module %d: Installed -- AUTO FXO (%s mode)\n",x, fxo_modes[_opermode].name);
+ } else
+ printk("Module %d: Not installed\n", x);
+ }
+#endif
+ }
+
+ /* Return error if nothing initialized okay. */
+ if (!wc->cardflag && !timingonly)
+ return -1;
+ __wctdm_setcreg(wc, WC_SYNC, (wc->cardflag << 1) | 0x1);
+ return 0;
+}
+
+static void wctdm_enable_interrupts(struct wctdm *wc)
+{
+ /* Enable interrupts (we care about all of them) */
+ outb(0x3f, wc->ioaddr + WC_MASK0);
+ /* No external interrupts */
+ outb(0x00, wc->ioaddr + WC_MASK1);
+}
+
+static void wctdm_restart_dma(struct wctdm *wc)
+{
+ /* Reset Master and TDM */
+ outb(0x01, wc->ioaddr + WC_CNTL);
+ outb(0x01, wc->ioaddr + WC_OPER);
+}
+
+static void wctdm_start_dma(struct wctdm *wc)
+{
+ /* Reset Master and TDM */
+ outb(0x0f, wc->ioaddr + WC_CNTL);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ outb(0x01, wc->ioaddr + WC_CNTL);
+ outb(0x01, wc->ioaddr + WC_OPER);
+}
+
+static void wctdm_stop_dma(struct wctdm *wc)
+{
+ outb(0x00, wc->ioaddr + WC_OPER);
+}
+
+static void wctdm_reset_tdm(struct wctdm *wc)
+{
+ /* Reset TDM */
+ outb(0x0f, wc->ioaddr + WC_CNTL);
+}
+
+static void wctdm_disable_interrupts(struct wctdm *wc)
+{
+ outb(0x00, wc->ioaddr + WC_MASK0);
+ outb(0x00, wc->ioaddr + WC_MASK1);
+}
+
+static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int res;
+ struct wctdm *wc;
+ struct wctdm_desc *d = (struct wctdm_desc *)ent->driver_data;
+ int x;
+ int y;
+
+ for (x=0;x<WC_MAX_IFACES;x++)
+ if (!ifaces[x]) break;
+ if (x >= WC_MAX_IFACES) {
+ printk("Too many interfaces\n");
+ return -EIO;
+ }
+
+ if (pci_enable_device(pdev)) {
+ res = -EIO;
+ } else {
+ wc = kmalloc(sizeof(struct wctdm), GFP_KERNEL);
+ if (wc) {
+ int cardcount = 0;
+
+ ifaces[x] = wc;
+ memset(wc, 0, sizeof(struct wctdm));
+ spin_lock_init(&wc->lock);
+ wc->curcard = -1;
+ wc->ioaddr = pci_resource_start(pdev, 0);
+ wc->dev = pdev;
+ wc->pos = x;
+ wc->variety = d->name;
+ for (y=0;y<NUM_CARDS;y++)
+ wc->flags[y] = d->flags;
+ /* Keep track of whether we need to free the region */
+ if (request_region(wc->ioaddr, 0xff, "wctdm"))
+ 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 = pci_alloc_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, &wc->writedma);
+ if (!wc->writechunk) {
+ printk("wctdm: Unable to allocate DMA-able memory\n");
+ if (wc->freeregion)
+ release_region(wc->ioaddr, 0xff);
+ return -ENOMEM;
+ }
+
+ wc->readchunk = wc->writechunk + ZT_MAX_CHUNKSIZE * 2; /* in doublewords */
+ wc->readdma = wc->writedma + ZT_MAX_CHUNKSIZE * 8; /* in bytes */
+
+ if (wctdm_initialize(wc)) {
+ printk("wctdm: Unable to intialize FXS\n");
+ /* Set Reset Low */
+ x=inb(wc->ioaddr + WC_CNTL);
+ outb((~0x1)&x, wc->ioaddr + WC_CNTL);
+ /* Free Resources */
+ free_irq(pdev->irq, wc);
+ if (wc->freeregion)
+ release_region(wc->ioaddr, 0xff);
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma);
+ kfree(wc);
+ return -EIO;
+ }
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, wc);
+
+ if (request_irq(pdev->irq, wctdm_interrupt, ZAP_IRQ_SHARED, "wctdm", wc)) {
+ printk("wctdm: Unable to request IRQ %d\n", pdev->irq);
+ if (wc->freeregion)
+ release_region(wc->ioaddr, 0xff);
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ kfree(wc);
+ return -EIO;
+ }
+
+
+ if (wctdm_hardware_init(wc)) {
+ unsigned char x;
+
+ /* Set Reset Low */
+ x=inb(wc->ioaddr + WC_CNTL);
+ outb((~0x1)&x, wc->ioaddr + WC_CNTL);
+ /* Free Resources */
+ free_irq(pdev->irq, wc);
+ if (wc->freeregion)
+ release_region(wc->ioaddr, 0xff);
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma);
+ pci_set_drvdata(pdev, NULL);
+ zt_unregister(&wc->span);
+ kfree(wc);
+ return -EIO;
+
+ }
+
+ wctdm_post_initialize(wc);
+
+ /* Enable interrupts */
+ wctdm_enable_interrupts(wc);
+ /* Initialize Write/Buffers to all blank data */
+ memset((void *)wc->writechunk,0,ZT_MAX_CHUNKSIZE * 2 * 2 * 4);
+
+ /* Start DMA */
+ wctdm_start_dma(wc);
+
+ for (x = 0; x < NUM_CARDS; x++) {
+ if (wc->cardflag & (1 << x))
+ cardcount++;
+ }
+
+ printk("Found a Wildcard TDM: %s (%d modules)\n", wc->variety, cardcount);
+ res = 0;
+ } else
+ res = -ENOMEM;
+ }
+ return res;
+}
+
+static void wctdm_release(struct wctdm *wc)
+{
+ zt_unregister(&wc->span);
+ if (wc->freeregion)
+ release_region(wc->ioaddr, 0xff);
+ kfree(wc);
+ printk("Freed a Wildcard\n");
+}
+
+static void __devexit wctdm_remove_one(struct pci_dev *pdev)
+{
+ struct wctdm *wc = pci_get_drvdata(pdev);
+ if (wc) {
+
+ /* Stop any DMA */
+ wctdm_stop_dma(wc);
+ wctdm_reset_tdm(wc);
+
+ /* In case hardware is still there */
+ wctdm_disable_interrupts(wc);
+
+ /* Immediately free resources */
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma);
+ free_irq(pdev->irq, wc);
+
+ /* Reset PCI chip and registers */
+ outb(0x0e, wc->ioaddr + WC_CNTL);
+
+ /* Release span, possibly delayed */
+ if (!wc->usecount)
+ wctdm_release(wc);
+ else
+ wc->dead = 1;
+ }
+}
+
+static struct pci_device_id wctdm_pci_tbl[] = {
+ { 0xe159, 0x0001, 0xa159, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm },
+ { 0xe159, 0x0001, 0xe159, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm },
+ { 0xe159, 0x0001, 0xb100, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme },
+ { 0xe159, 0x0001, 0xb1d9, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmi },
+ { 0xe159, 0x0001, 0xb118, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmi },
+ { 0xe159, 0x0001, 0xb119, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmi },
+ { 0xe159, 0x0001, 0xa9fd, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh },
+ { 0xe159, 0x0001, 0xa8fd, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh },
+ { 0xe159, 0x0001, 0xa800, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh },
+ { 0xe159, 0x0001, 0xa801, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh },
+ { 0xe159, 0x0001, 0xa908, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh },
+ { 0xe159, 0x0001, 0xa901, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh },
+#ifdef TDM_REVH_MATCHALL
+ { 0xe159, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdmh },
+#endif
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, wctdm_pci_tbl);
+
+static struct pci_driver wctdm_driver = {
+ name: "wctdm",
+ probe: wctdm_init_one,
+#ifdef LINUX26
+ remove: __devexit_p(wctdm_remove_one),
+#else
+ remove: wctdm_remove_one,
+#endif
+ suspend: NULL,
+ resume: NULL,
+ id_table: wctdm_pci_tbl,
+};
+
+static int __init wctdm_init(void)
+{
+ int res;
+ int x;
+
+ for (x = 0; x < (sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) {
+ if (!strcmp(fxo_modes[x].name, opermode))
+ break;
+ }
+ if (x < sizeof(fxo_modes) / sizeof(fxo_modes[0])) {
+ _opermode = x;
+ } else {
+ printk("Invalid/unknown operating mode '%s' specified. Please choose one of:\n", opermode);
+ for (x = 0; x < sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++)
+ printk(" %s\n", fxo_modes[x].name);
+ printk("Note this option is CASE SENSITIVE!\n");
+ return -ENODEV;
+ }
+
+ if (!strcmp(opermode, "AUSTRALIA")) {
+ boostringer = 1;
+ fxshonormode = 1;
+ }
+
+ /* for the voicedaa_check_hook defaults, if the user has not overridden
+ them by specifying them as module parameters, then get the values
+ from the selected operating mode
+ */
+ if (battdebounce == 0) {
+ battdebounce = fxo_modes[_opermode].battdebounce;
+ }
+ if (battalarm == 0) {
+ battalarm = fxo_modes[_opermode].battalarm;
+ }
+ if (battthresh == 0) {
+ battthresh = fxo_modes[_opermode].battthresh;
+ }
+
+ res = zap_pci_module(&wctdm_driver);
+ if (res)
+ return -ENODEV;
+ return 0;
+}
+
+static void __exit wctdm_cleanup(void)
+{
+ pci_unregister_driver(&wctdm_driver);
+}
+
+#ifdef LINUX26
+module_param(debug, int, 0600);
+module_param(loopcurrent, int, 0600);
+module_param(reversepolarity, int, 0600);
+module_param(robust, int, 0600);
+module_param(opermode, charp, 0600);
+module_param(timingonly, int, 0600);
+module_param(lowpower, int, 0600);
+module_param(boostringer, int, 0600);
+module_param(fastringer, int, 0600);
+module_param(fxshonormode, int, 0600);
+module_param(battdebounce, uint, 0600);
+module_param(battalarm, uint, 0600);
+module_param(battthresh, uint, 0600);
+module_param(ringdebounce, int, 0600);
+module_param(fwringdetect, int, 0600);
+module_param(alawoverride, int, 0600);
+module_param(fastpickup, int, 0600);
+module_param(fxotxgain, int, 0600);
+module_param(fxorxgain, int, 0600);
+module_param(fxstxgain, int, 0600);
+module_param(fxsrxgain, int, 0600);
+#else
+MODULE_PARM(debug, "i");
+MODULE_PARM(loopcurrent, "i");
+MODULE_PARM(reversepolarity, "i");
+MODULE_PARM(robust, "i");
+MODULE_PARM(opermode, "s");
+MODULE_PARM(timingonly, "i");
+MODULE_PARM(lowpower, "i");
+MODULE_PARM(boostringer, "i");
+MODULE_PARM(fastringer, "i");
+MODULE_PARM(fxshonormode, "i");
+MODULE_PARM(battdebounce, "i");
+MODULE_PARM(battalarm, "i");
+MODULE_PARM(battthresh, "i");
+MODULE_PARM(ringdebounce, "i");
+MODULE_PARM(fwringdetect, "i");
+MODULE_PARM(alawoverride, "i");
+MODULE_PARM(fastpickup, "i");
+MODULE_PARM(fxotxgain, "i");
+MODULE_PARM(fxorxgain, "i");
+MODULE_PARM(fxstxgain, "i");
+MODULE_PARM(fxsrxgain, "i");
+#endif
+MODULE_DESCRIPTION("Wildcard TDM400P Zaptel Driver");
+MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
+#if defined(MODULE_ALIAS)
+MODULE_ALIAS("wcfxs");
+#endif
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(wctdm_init);
+module_exit(wctdm_cleanup);
diff --git a/drivers/dahdi/wctdm.h b/drivers/dahdi/wctdm.h
new file mode 100644
index 0000000..73703aa
--- /dev/null
+++ b/drivers/dahdi/wctdm.h
@@ -0,0 +1,69 @@
+/*
+ * Wilcard S100P FXS Interface Driver for Zapata Telephony interface
+ *
+ * Written by Mark Spencer <markster@linux-support.net>
+ *
+ * Copyright (C) 2001, Linux Support Services, 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.
+ *
+ */
+
+#ifndef _WCTDM_H
+#define _WCTDM_H
+
+#include <linux/ioctl.h>
+
+#define NUM_REGS 109
+#define NUM_INDIRECT_REGS 105
+
+struct wctdm_stats {
+ int tipvolt; /* TIP voltage (mV) */
+ int ringvolt; /* RING voltage (mV) */
+ int batvolt; /* VBAT voltage (mV) */
+};
+
+struct wctdm_regs {
+ unsigned char direct[NUM_REGS];
+ unsigned short indirect[NUM_INDIRECT_REGS];
+};
+
+struct wctdm_regop {
+ int indirect;
+ unsigned char reg;
+ unsigned short val;
+};
+
+struct wctdm_echo_coefs {
+ unsigned char acim;
+ unsigned char coef1;
+ unsigned char coef2;
+ unsigned char coef3;
+ unsigned char coef4;
+ unsigned char coef5;
+ unsigned char coef6;
+ unsigned char coef7;
+ unsigned char coef8;
+};
+
+#define WCTDM_GET_STATS _IOR (ZT_CODE, 60, struct wctdm_stats)
+#define WCTDM_GET_REGS _IOR (ZT_CODE, 61, struct wctdm_regs)
+#define WCTDM_SET_REG _IOW (ZT_CODE, 62, struct wctdm_regop)
+#define WCTDM_SET_ECHOTUNE _IOW (ZT_CODE, 63, struct wctdm_echo_coefs)
+
+
+#endif /* _WCTDM_H */
diff --git a/drivers/dahdi/wctdm24xxp/GpakApi.c b/drivers/dahdi/wctdm24xxp/GpakApi.c
new file mode 100644
index 0000000..9997b07
--- /dev/null
+++ b/drivers/dahdi/wctdm24xxp/GpakApi.c
@@ -0,0 +1,1627 @@
+/*
+ * Copyright (c) 2005, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakApi.c
+ *
+ * Description:
+ * This file contains user API functions to communicate with DSPs executing
+ * G.PAK software. The file is integrated into the host processor connected
+ * to C55X G.PAK DSPs via a Host Port Interface.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 06/15/05 - Initial release.
+ * 11/15/2006 - 24 TDM-TDM Channels EC release
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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/version.h>
+#include <asm/semaphore.h>
+
+#include "zaptel.h"
+
+#include "GpakHpi.h"
+#include "GpakCust.h"
+#include "GpakApi.h"
+#include "gpakenum.h"
+
+/* DSP to Host interface block offsets. */
+#define REPLY_MSG_PNTR_OFFSET 0 /* I/F blk offset to Reply Msg Pointer */
+#define CMD_MSG_PNTR_OFFSET 2 /* I/F blk offset to Command Msg Pointer */
+#define EVENT_MSG_PNTR_OFFSET 4 /* I/F blk offset to Event Msg Pointer */
+#define PKT_BUFR_MEM_OFFSET 6 /* I/F blk offset to Packet Buffer memory */
+#define DSP_STATUS_OFFSET 8 /* I/F blk offset to DSP Status */
+#define VERSION_ID_OFFSET 9 /* I/F blk offset to G.PAK Version Id */
+#define MAX_CMD_MSG_LEN_OFFSET 10 /* I/F blk offset to Max Cmd Msg Length */
+#define CMD_MSG_LEN_OFFSET 11 /* I/F blk offset to Command Msg Length */
+#define REPLY_MSG_LEN_OFFSET 12 /* I/F blk offset to Reply Msg Length */
+#define NUM_CHANNELS_OFFSET 13 /* I/F blk offset to Num Built Channels */
+#define NUM_PKT_CHANNELS_OFFSET 14 /* I/F blk offset to Num Pkt Channels */
+#define NUM_CONFERENCES_OFFSET 15 /* I/F blk offset to Num Conferences */
+//#define CPU_USAGE_OFFSET_1MS 16 /* I/F blk offset to CPU Usage statistics */
+#define CPU_USAGE_OFFSET 18 /* I/F blk offset to CPU Usage statistics */
+//#define CPU_USAGE_OFFSET_10MS 20 /* I/F blk offset to CPU Usage statistics */
+#define FRAMING_STATS_OFFSET 22 /* I/F blk offset to Framing statistics */
+
+//#define GPAK_RELEASE_Rate rate10ms
+// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+// Macro to reconstruct a 32-bit value from two 16-bit values.
+// Parameter p32: 32-bit-wide destination
+// Parameter p16: 16-bit-wide source array of length 2 words
+#define RECONSTRUCT_LONGWORD(p32, p16) p32 = (DSP_ADDRESS)p16[0]<<16; \
+ p32 |= (unsigned long)p16[1]
+// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+
+/* DSP Status value definitions. */
+#define DSP_INIT_STATUS 0x5555 /* DSP Initialized status value */
+#define HOST_INIT_STATUS 0xAAAA /* Host Initialized status value */
+
+/* Circular packet buffer information structure offsets. */
+#define CB_BUFR_BASE 0 /* pointer to base of circular buffer */
+#define CB_BUFR_SIZE 2 /* size of buffer (words) */
+#define CB_BUFR_PUT_INDEX 3 /* offset in buffer for next write */
+#define CB_BUFR_TAKE_INDEX 4 /* offset in buffer for next read */
+#define CIRC_BUFFER_INFO_STRUCT_SIZE 6
+
+/* Miscellaneous definitions. */
+#define MSG_BUFFER_SIZE 100 /* size (words) of Host msg buffer */
+#define WORD_BUFFER_SIZE 84 /* size of DSP Word buffer (words) */
+
+#ifdef __TMS320C55XX__ // debug sections if not on host
+#pragma DATA_SECTION(pDspIfBlk,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(MaxCmdMsgLen,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(MaxChannels,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(DlByteBufr,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(DlWordBufr,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(pEventFifoAddress,"GPAKAPIDEBUG_SECT")
+#endif
+
+/* Host variables related to Host to DSP interface. */
+static DSP_ADDRESS pDspIfBlk[MAX_DSP_CORES]; /* DSP address of I/F block */
+static DSP_WORD MaxCmdMsgLen[MAX_DSP_CORES]; /* max Cmd msg length (octets) */
+static unsigned short int MaxChannels[MAX_DSP_CORES]; /* max num channels */
+
+//static unsigned short int MaxPktChannels[MAX_DSP_CORES]; /* max num pkt channels */
+//static unsigned short int MaxConfs[MAX_DSP_CORES]; /* max num conferences */
+//static DSP_ADDRESS pPktInBufr[MAX_DSP_CORES][MAX_PKT_CHANNELS]; /* Pkt In buffer */
+//static DSP_ADDRESS pPktOutBufr[MAX_DSP_CORES][MAX_PKT_CHANNELS]; /* Pkt Out buffer */
+static DSP_ADDRESS pEventFifoAddress[MAX_DSP_CORES]; /* event fifo */
+
+static unsigned char DlByteBufr[DOWNLOAD_BLOCK_SIZE * 2]; /* Dowload byte buf */
+static DSP_WORD DlWordBufr[DOWNLOAD_BLOCK_SIZE]; /* Dowload word buffer */
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CheckDspReset - Check if the DSP was reset.
+ *
+ * FUNCTION
+ * This function determines if the DSP was reset and is ready. If reset
+ * occurred, it reads interface parameters and calculates DSP addresses.
+ *
+ * RETURNS
+ * -1 = DSP is not ready.
+ * 0 = Reset did not occur.
+ * 1 = Reset occurred.
+ *
+ */
+static int CheckDspReset(
+ int DspId /* DSP Identifier (0 to MaxDSPCores-1) */
+ )
+{
+ DSP_ADDRESS IfBlockPntr; /* Interface Block pointer */
+ DSP_WORD DspStatus; /* DSP Status */
+ DSP_WORD DspChannels; /* number of DSP channels */
+ DSP_WORD Temp[2];
+#if 0
+ DSP_WORD DspConfs; /* number of DSP conferences */
+ DSP_ADDRESS PktBufrMem; /* address of Packet Buffer */
+ unsigned short int i; /* loop index / counter */
+#endif
+
+ /* Read the pointer to the Interface Block. */
+ gpakReadDspMemory(DspId, DSP_IFBLK_ADDRESS, 2, Temp);
+ RECONSTRUCT_LONGWORD(IfBlockPntr, Temp);
+
+ /* If the pointer is zero, return with an indication the DSP is not
+ ready. */
+ if (IfBlockPntr == 0)
+ return (-1);
+
+ /* Read the DSP's Status. */
+ gpakReadDspMemory(DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1, &DspStatus);
+
+ /* If status indicates the DSP was reset, read the DSP's interface
+ parameters and calculate DSP addresses. */
+ if (DspStatus == DSP_INIT_STATUS ||
+ ((DspStatus == HOST_INIT_STATUS) && (pDspIfBlk[DspId] == 0)))
+ {
+ /* Save the address of the DSP's Interface Block. */
+ pDspIfBlk[DspId] = IfBlockPntr;
+
+ /* Read the DSP's interface parameters. */
+ gpakReadDspMemory(DspId, IfBlockPntr + MAX_CMD_MSG_LEN_OFFSET, 1,
+ &(MaxCmdMsgLen[DspId]));
+
+ /* read the number of configured DSP channels */
+ gpakReadDspMemory(DspId, IfBlockPntr + NUM_CHANNELS_OFFSET, 1,
+ &DspChannels);
+ if (DspChannels > MAX_CHANNELS)
+ MaxChannels[DspId] = MAX_CHANNELS;
+ else
+ MaxChannels[DspId] = (unsigned short int) DspChannels;
+#if 0
+ /* read the number of configured DSP conferences */
+ gpakReadDspMemory(DspId, IfBlockPntr + NUM_CONFERENCES_OFFSET, 1,
+ &DspConfs);
+ if (DspConfs > MAX_CONFS)
+ MaxConfs[DspId] = MAX_CONFS;
+ else
+ MaxConfs[DspId] = (unsigned short int) DspConfs;
+
+
+ /* read the number of configured DSP packet channels */
+ gpakReadDspMemory(DspId, IfBlockPntr + NUM_PKT_CHANNELS_OFFSET, 1,
+ &DspChannels);
+ if (DspChannels > MAX_PKT_CHANNELS)
+ MaxPktChannels[DspId] = MAX_PKT_CHANNELS;
+ else
+ MaxPktChannels[DspId] = (unsigned short int) DspChannels;
+
+
+ /* read the pointer to the circular buffer infor struct table */
+ gpakReadDspMemory(DspId, IfBlockPntr + PKT_BUFR_MEM_OFFSET, 2, Temp);
+ RECONSTRUCT_LONGWORD(PktBufrMem, Temp);
+
+
+ /* Determine the addresses of each channel's Packet buffers. */
+ for (i = 0; i < MaxPktChannels[DspId]; i++)
+ {
+ pPktInBufr[DspId][i] = PktBufrMem;
+ pPktOutBufr[DspId][i] = PktBufrMem + CIRC_BUFFER_INFO_STRUCT_SIZE;
+ PktBufrMem += (CIRC_BUFFER_INFO_STRUCT_SIZE*2);
+ }
+#endif
+
+ /* read the pointer to the event fifo info struct */
+ gpakReadDspMemory(DspId, IfBlockPntr + EVENT_MSG_PNTR_OFFSET, 2, Temp);
+ RECONSTRUCT_LONGWORD(pEventFifoAddress[DspId], Temp);
+
+ /* Set the DSP Status to indicate the host recognized the reset. */
+ DspStatus = HOST_INIT_STATUS;
+ gpakWriteDspMemory(DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1,
+ &DspStatus);
+
+ /* Return with an indication that a reset occurred. */
+ return (1);
+ }
+
+ /* If status doesn't indicate the host recognized a reset, return with an
+ indication the DSP is not ready. */
+ if ((DspStatus != HOST_INIT_STATUS) || (pDspIfBlk[DspId] == 0))
+ return (-1);
+
+ /* Return with an indication that a reset did not occur. */
+ return (0);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * WriteDspCmdMessage - Write a Host Command/Request message to DSP.
+ *
+ * FUNCTION
+ * This function writes a Host Command/Request message into DSP memory and
+ * informs the DSP of the presence of the message.
+ *
+ * RETURNS
+ * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready)
+ * 0 = Temporarily unable to write message (previous Cmd Msg busy)
+ * 1 = Message written successfully
+ *
+ */
+static int WriteDspCmdMessage(
+ int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */
+ DSP_WORD *pMessage, /* pointer to Command message */
+ DSP_WORD MsgLength /* length of message (octets) */
+ )
+{
+ DSP_WORD CmdMsgLength; /* current Cmd message length */
+ DSP_WORD Temp[2];
+ DSP_ADDRESS BufferPointer; /* message buffer pointer */
+
+ /* Check if the DSP was reset and is ready. */
+ if (CheckDspReset(DspId) == -1)
+ return (-1);
+
+ /* Make sure the message length is valid. */
+ if ((MsgLength < 1) || (MsgLength > MaxCmdMsgLen[DspId]))
+ return (-1);
+
+ /* Make sure a previous Command message is not in use by the DSP. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1,
+ &CmdMsgLength);
+ if (CmdMsgLength != 0)
+ return (0);
+
+ /* Purge any previous Reply message that wasn't read. */
+ gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1,
+ &CmdMsgLength);
+
+ /* Copy the Command message into DSP memory. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_PNTR_OFFSET, 2, Temp);
+ RECONSTRUCT_LONGWORD(BufferPointer, Temp);
+ gpakWriteDspMemory(DspId, BufferPointer, (MsgLength + 1) / 2, pMessage);
+
+ /* Store the message length in DSP's Command message length (flags DSP that
+ a Command message is ready). */
+ CmdMsgLength = MsgLength;
+ gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1,
+ &CmdMsgLength);
+
+ /* Return with an indication the message was written. */
+ return (1);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ReadDspReplyMessage - Read a DSP Reply message from DSP.
+ *
+ * FUNCTION
+ * This function reads a DSP Reply message from DSP memory.
+ *
+ * RETURNS
+ * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready)
+ * 0 = No message available (DSP Reply message empty)
+ * 1 = Message read successfully (message and length stored in variables)
+ *
+ */
+static int ReadDspReplyMessage(
+ int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */
+ DSP_WORD *pMessage, /* pointer to Reply message buffer */
+ DSP_WORD *pMsgLength /* pointer to msg length var (octets) */
+ )
+{
+ DSP_WORD MsgLength; /* message length */
+ DSP_ADDRESS BufferPointer; /* message buffer pointer */
+ DSP_WORD Temp[2];
+
+ /* Check if the DSP was reset and is ready. */
+ if (CheckDspReset(DspId) == -1)
+ return (-1);
+
+ /* Check if a Reply message is ready. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1,
+ &MsgLength);
+ if (MsgLength == 0)
+ return (0);
+
+ /* Make sure the message length is valid. */
+ if (MsgLength > *pMsgLength)
+ return (-1);
+
+ /* Copy the Reply message from DSP memory. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_PNTR_OFFSET, 2, Temp);
+ RECONSTRUCT_LONGWORD(BufferPointer, Temp);
+ gpakReadDspMemory(DspId, BufferPointer, (MsgLength + 1) / 2, pMessage);
+
+ /* Store the message length in the message length variable. */
+ *pMsgLength = MsgLength;
+
+ /* Indicate a Reply message is not ready. */
+ MsgLength = 0;
+ gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1,
+ &MsgLength);
+
+ /* Return with an indication the message was read. */
+ return (1);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ReadCircBuffer - Read from a DSP circular buffer.
+ *
+ * FUNCTION
+ * This function reads a block of words from a DSP circular buffer. The Take
+ * address is incremented by the number of words read adjusting for buffer
+ * wrap.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+static void ReadCircBuffer(
+ int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */
+ DSP_ADDRESS BufrBaseAddress, /* address of base of circular buffer */
+ DSP_ADDRESS BufrLastAddress, /* address of last word in buffer */
+ DSP_ADDRESS *TakeAddress, /* pointer to address in buffer for read */
+ DSP_WORD *pWordBuffer, /* pointer to buffer for words read */
+ DSP_WORD NumWords /* number of words to read */
+ )
+{
+ DSP_WORD WordsTillEnd; /* number of words until end of buffer */
+
+ /* Determine the number of words from the start address until the end of the
+ buffer. */
+ WordsTillEnd = BufrLastAddress - *TakeAddress + 1;
+
+ /* If a buffer wrap will occur, read the first part at the end of the
+ buffer followed by the second part at the beginning of the buffer. */
+ if (NumWords > WordsTillEnd)
+ {
+ gpakReadDspMemory(DspId, *TakeAddress, WordsTillEnd, pWordBuffer);
+ gpakReadDspMemory(DspId, BufrBaseAddress, NumWords - WordsTillEnd,
+ &(pWordBuffer[WordsTillEnd]));
+ *TakeAddress = BufrBaseAddress + NumWords - WordsTillEnd;
+ }
+
+ /* If a buffer wrap will not occur, read all words starting at the current
+ take address in the buffer. */
+ else
+ {
+ gpakReadDspMemory(DspId, *TakeAddress, NumWords, pWordBuffer);
+ if (NumWords == WordsTillEnd)
+ *TakeAddress = BufrBaseAddress;
+ else
+ *TakeAddress = *TakeAddress + NumWords;
+ }
+ return;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * VerifyReply - Verify the reply message is correct for the command sent.
+ *
+ * FUNCTION
+ * This function verifies correct reply message content for the command that
+ * was just sent.
+ *
+ * RETURNS
+ * 0 = Incorrect
+ * 1 = Correct
+ *
+ */
+static int VerifyReply(
+ DSP_WORD *pMsgBufr, /* pointer to Reply message buffer */
+ int CheckType, /* reply check type */
+ DSP_WORD CheckValue /* reply check value */
+ )
+{
+
+ /* Verify Channel or Conference Id. */
+ if (CheckType == 1)
+ {
+ if (((pMsgBufr[1] >> 8) & 0xFF) != CheckValue)
+ return (0);
+ }
+
+ /* Verify Test Mode Id. */
+ else if (CheckType == 2)
+ {
+ if (pMsgBufr[1] != CheckValue)
+ return (0);
+ }
+
+ /* Return with an indication of correct reply. */
+ return (1);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * TransactCmd - Send a command to the DSP and receive it's reply.
+ *
+ * FUNCTION
+ * This function sends the specified command to the DSP and receives the DSP's
+ * reply.
+ *
+ * RETURNS
+ * Length of reply message (0 = Failure)
+ *
+ */
+static unsigned int TransactCmd(
+ int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */
+ DSP_WORD *pMsgBufr, /* pointer to Cmd/Reply message buffer */
+ DSP_WORD CmdLength, /* length of command message (octets) */
+ DSP_WORD ReplyType, /* required type of reply message */
+ DSP_WORD ReplyLength, /* required length of reply message (octets) */
+ int ReplyCheckType, /* reply check type */
+ DSP_WORD ReplyCheckValue /* reply check value */
+ )
+{
+ int FuncStatus; /* function status */
+ int LoopCount; /* wait loop counter */
+ DSP_WORD RcvReplyLength; /* received Reply message length */
+ DSP_WORD RcvReplyType; /* received Reply message type code */
+ DSP_WORD RetValue; /* return value */
+
+ /* Default the return value to indicate a failure. */
+ RetValue = 0;
+
+ /* Lock access to the DSP. */
+ gpakLockAccess(DspId);
+
+ /* Attempt to write the command message to the DSP. */
+ LoopCount = 0;
+ while ((FuncStatus = WriteDspCmdMessage(DspId, pMsgBufr, CmdLength)) != 1)
+ {
+ if (FuncStatus == -1)
+ break;
+ if (++LoopCount > MAX_WAIT_LOOPS)
+ break;
+ gpakHostDelay();
+ }
+
+ /* Attempt to read the reply message from the DSP if the command message was
+ sent successfully. */
+ if (FuncStatus == 1)
+ {
+ for (LoopCount = 0; LoopCount < MAX_WAIT_LOOPS; LoopCount++)
+ {
+ RcvReplyLength = MSG_BUFFER_SIZE * 2;
+ FuncStatus = ReadDspReplyMessage(DspId, pMsgBufr, &RcvReplyLength);
+ if (FuncStatus == 1)
+ {
+ RcvReplyType = (pMsgBufr[0] >> 8) & 0xFF;
+ if ((RcvReplyLength >= ReplyLength) &&
+ (RcvReplyType == ReplyType) &&
+ VerifyReply(pMsgBufr, ReplyCheckType, ReplyCheckValue))
+ {
+ RetValue = RcvReplyLength;
+ break;
+ }
+ else if (RcvReplyType == MSG_NULL_REPLY)
+ break;
+ }
+ else if (FuncStatus == -1)
+ break;
+ gpakHostDelay();
+ }
+ }
+
+ /* Unlock access to the DSP. */
+ gpakUnlockAccess(DspId);
+
+ /* Return the length of the reply message (0 = failure). */
+ return (RetValue);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakConfigurePorts - Configure a DSP's serial ports.
+ *
+ * FUNCTION
+ * This function configures a DSP's serial ports.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakConfigPortStatus_t gpakConfigurePorts(
+ unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */
+ GpakPortConfig_t *pPortConfig, /* pointer to Port Config info */
+ GPAK_PortConfigStat_t *pStatus /* pointer to Port Config Status */
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (CpsInvalidDsp);
+
+ /* Build the Configure Serial Ports message. */
+ MsgBuffer[0] = MSG_CONFIGURE_PORTS << 8;
+ MsgBuffer[1] = (DSP_WORD)
+ ((pPortConfig->SlotsSelect1 << 12) |
+ ((pPortConfig->FirstBlockNum1 << 8) & 0x0F00) |
+ ((pPortConfig->SecBlockNum1 << 4) & 0x00F0));
+ MsgBuffer[2] = (DSP_WORD) pPortConfig->FirstSlotMask1;
+ MsgBuffer[3] = (DSP_WORD) pPortConfig->SecSlotMask1;
+ MsgBuffer[4] = (DSP_WORD)
+ ((pPortConfig->SlotsSelect2 << 12) |
+ ((pPortConfig->FirstBlockNum2 << 8) & 0x0F00) |
+ ((pPortConfig->SecBlockNum2 << 4) & 0x00F0));
+ MsgBuffer[5] = (DSP_WORD) pPortConfig->FirstSlotMask2;
+ MsgBuffer[6] = (DSP_WORD) pPortConfig->SecSlotMask2;
+ MsgBuffer[7] = (DSP_WORD)
+ ((pPortConfig->SlotsSelect3 << 12) |
+ ((pPortConfig->FirstBlockNum3 << 8) & 0x0F00) |
+ ((pPortConfig->SecBlockNum3 << 4) & 0x00F0));
+ MsgBuffer[8] = (DSP_WORD) pPortConfig->FirstSlotMask3;
+ MsgBuffer[9] = (DSP_WORD) pPortConfig->SecSlotMask3;
+
+ MsgBuffer[10] = (DSP_WORD)
+ (((pPortConfig->DxDelay1 << 11) & 0x0800) |
+ ((pPortConfig->RxDataDelay1 << 9) & 0x0600) |
+ ((pPortConfig->TxDataDelay1 << 7) & 0x0180) |
+ ((pPortConfig->RxClockPolarity1 << 6) & 0x0040) |
+ ((pPortConfig->TxClockPolarity1 << 5) & 0x0020) |
+ ((pPortConfig->RxFrameSyncPolarity1 << 4) & 0x0010) |
+ ((pPortConfig->TxFrameSyncPolarity1 << 3) & 0x0008) |
+ ((pPortConfig->CompandingMode1 << 1) & 0x0006) |
+ (pPortConfig->SerialWordSize1 & 0x0001));
+
+ MsgBuffer[11] = (DSP_WORD)
+ (((pPortConfig->DxDelay2 << 11) & 0x0800) |
+ ((pPortConfig->RxDataDelay2 << 9) & 0x0600) |
+ ((pPortConfig->TxDataDelay2 << 7) & 0x0180) |
+ ((pPortConfig->RxClockPolarity2 << 6) & 0x0040) |
+ ((pPortConfig->TxClockPolarity2 << 5) & 0x0020) |
+ ((pPortConfig->RxFrameSyncPolarity2 << 4) & 0x0010) |
+ ((pPortConfig->TxFrameSyncPolarity2 << 3) & 0x0008) |
+ ((pPortConfig->CompandingMode2 << 1) & 0x0006) |
+ (pPortConfig->SerialWordSize1 & 0x0001));
+
+ MsgBuffer[12] = (DSP_WORD)
+ (((pPortConfig->DxDelay3 << 11) & 0x0800) |
+ ((pPortConfig->RxDataDelay3 << 9) & 0x0600) |
+ ((pPortConfig->TxDataDelay3 << 7) & 0x0180) |
+ ((pPortConfig->RxClockPolarity3 << 6) & 0x0040) |
+ ((pPortConfig->TxClockPolarity3 << 5) & 0x0020) |
+ ((pPortConfig->RxFrameSyncPolarity3 << 4) & 0x0010) |
+ ((pPortConfig->TxFrameSyncPolarity3 << 3) & 0x0008) |
+ ((pPortConfig->CompandingMode3 << 1) & 0x0006) |
+ (pPortConfig->SerialWordSize3 & 0x0001));
+
+ MsgBuffer[13] = (DSP_WORD) pPortConfig->ThirdSlotMask1;
+ MsgBuffer[14] = (DSP_WORD) pPortConfig->FouthSlotMask1;
+ MsgBuffer[15] = (DSP_WORD) pPortConfig->FifthSlotMask1;
+ MsgBuffer[16] = (DSP_WORD) pPortConfig->SixthSlotMask1;
+ MsgBuffer[17] = (DSP_WORD) pPortConfig->SevenSlotMask1;
+ MsgBuffer[18] = (DSP_WORD) pPortConfig->EightSlotMask1;
+
+ MsgBuffer[19] = (DSP_WORD) pPortConfig->ThirdSlotMask2;;
+ MsgBuffer[20] = (DSP_WORD) pPortConfig->FouthSlotMask2;
+ MsgBuffer[21] = (DSP_WORD) pPortConfig->FifthSlotMask2;;
+ MsgBuffer[22] = (DSP_WORD) pPortConfig->SixthSlotMask2;
+ MsgBuffer[23] = (DSP_WORD) pPortConfig->SevenSlotMask2;;
+ MsgBuffer[24] = (DSP_WORD) pPortConfig->EightSlotMask2;
+
+ MsgBuffer[25] = (DSP_WORD) pPortConfig->ThirdSlotMask3;;
+ MsgBuffer[26] = (DSP_WORD) pPortConfig->FouthSlotMask3;
+ MsgBuffer[27] = (DSP_WORD) pPortConfig->FifthSlotMask3;;
+ MsgBuffer[28] = (DSP_WORD) pPortConfig->SixthSlotMask3;
+ MsgBuffer[29] = (DSP_WORD) pPortConfig->SevenSlotMask3;;
+ MsgBuffer[30] = (DSP_WORD) pPortConfig->EightSlotMask3;
+
+
+ /* Attempt to send the Configure Serial Ports message to the DSP and receive
+ it's reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 62, MSG_CONFIG_PORTS_REPLY, 4, 0, 0))
+ return (CpsDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ *pStatus = (GPAK_PortConfigStat_t) (MsgBuffer[1] & 0xFF);
+ if (*pStatus == Pc_Success)
+ return (CpsSuccess);
+ else
+ return (CpsParmError);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakConfigureChannel - Configure a DSP's Channel.
+ *
+ * FUNCTION
+ * This function configures a DSP's Channel.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakConfigChanStatus_t gpakConfigureChannel(
+ unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */
+ unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */
+ GpakChanType ChannelType, /* Channel Type */
+ GpakChannelConfig_t *pChanConfig, /* pointer to Channel Config info */
+ GPAK_ChannelConfigStat_t *pStatus /* pointer to Channel Config Status */
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD MsgLength; /* message length */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (CcsInvalidDsp);
+
+ /* Make sure the Channel Id is valid. */
+ if (ChannelId >= MaxChannels[DspId])
+ return (CcsInvalidChannel);
+
+ /* Build the Configure Channel message based on the Channel Type. */
+ switch (ChannelType)
+ {
+
+ /* PCM to Packet channel type. */
+ case tdmToTdm:
+
+ MsgBuffer[2] = (DSP_WORD)
+ ((pChanConfig->PcmInPortA << 8) |
+ (pChanConfig->PcmInSlotA & 0xFF));
+ MsgBuffer[3] = (DSP_WORD)
+ ((pChanConfig->PcmOutPortA << 8) |
+ (pChanConfig->PcmOutSlotA & 0xFF));
+
+ MsgBuffer[4] = (DSP_WORD)
+ ((pChanConfig->PcmInPortB << 8) |
+ (pChanConfig->PcmInSlotB & 0xFF));
+ MsgBuffer[5] = (DSP_WORD)
+ ((pChanConfig->PcmOutPortB << 8) |
+ (pChanConfig->PcmOutSlotB & 0xFF));
+
+ MsgBuffer[6] = (DSP_WORD)
+ (
+ ((pChanConfig->FaxCngDetB <<11) & 0x0800) |
+ ((pChanConfig->FaxCngDetA <<10) & 0x0400) |
+ ((pChanConfig->MuteToneB << 9) & 0x0200) |
+ ((pChanConfig->MuteToneA << 8) & 0x0100) |
+ ((pChanConfig->FrameRate << 6) & 0x00C0) |
+ ((pChanConfig->ToneTypesB << 5) & 0x0020) |
+ ((pChanConfig->ToneTypesA << 4) & 0x0010) |
+ ((pChanConfig->SoftwareCompand & 3) << 2) |
+ (pChanConfig->EcanEnableB << 1) |
+ (pChanConfig->EcanEnableA & 1)
+ );
+
+ MsgBuffer[7] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanTapLength;
+ MsgBuffer[8] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNlpType;
+ MsgBuffer[9] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanAdaptEnable;
+ MsgBuffer[10] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanG165DetEnable;
+ MsgBuffer[11] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanDblTalkThresh;
+ MsgBuffer[12] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNlpThreshold;
+ MsgBuffer[13] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNlpConv;
+ MsgBuffer[14] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNlpUnConv;
+ MsgBuffer[15] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNlpMaxSuppress;
+
+ MsgBuffer[16] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanCngThreshold;
+ MsgBuffer[17] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanAdaptLimit;
+ MsgBuffer[18] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanCrossCorrLimit;
+ MsgBuffer[19] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNumFirSegments;
+ MsgBuffer[20] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanFirSegmentLen;
+
+ MsgBuffer[21] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanTapLength;
+ MsgBuffer[22] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNlpType;
+ MsgBuffer[23] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanAdaptEnable;
+ MsgBuffer[24] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanG165DetEnable;
+ MsgBuffer[25] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanDblTalkThresh;
+ MsgBuffer[26] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNlpThreshold;
+ MsgBuffer[27] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNlpConv;
+ MsgBuffer[28] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNlpUnConv;
+ MsgBuffer[29] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNlpMaxSuppress;
+ MsgBuffer[30] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanCngThreshold;
+ MsgBuffer[31] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanAdaptLimit;
+ MsgBuffer[32] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanCrossCorrLimit;
+ MsgBuffer[33] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNumFirSegments;
+ MsgBuffer[34] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanFirSegmentLen;
+
+ MsgLength = 70; // byte number == 35*2
+ break;
+
+
+ /* Unknown (invalid) channel type. */
+ default:
+ *pStatus = Cc_InvalidChannelType;
+ return (CcsParmError);
+ }
+
+ MsgBuffer[0] = MSG_CONFIGURE_CHANNEL << 8;
+ MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ChannelType & 0xFF));
+
+ /* Attempt to send the Configure Channel message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, MsgLength, MSG_CONFIG_CHAN_REPLY, 4, 1,
+ (DSP_WORD) ChannelId))
+ return (CcsDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ *pStatus = (GPAK_ChannelConfigStat_t) (MsgBuffer[1] & 0xFF);
+ if (*pStatus == Cc_Success)
+ return (CcsSuccess);
+ else
+ return (CcsParmError);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakTearDownChannel - Tear Down a DSP's Channel.
+ *
+ * FUNCTION
+ * This function tears down a DSP's Channel.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakTearDownStatus_t gpakTearDownChannel(
+ unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */
+ unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */
+ GPAK_TearDownChanStat_t *pStatus /* pointer to Tear Down Status */
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (TdsInvalidDsp);
+
+ /* Make sure the Channel Id is valid. */
+ if (ChannelId >= MaxChannels[DspId])
+ return (TdsInvalidChannel);
+
+ /* Build the Tear Down Channel message. */
+ MsgBuffer[0] = MSG_TEAR_DOWN_CHANNEL << 8;
+ MsgBuffer[1] = (DSP_WORD) (ChannelId << 8);
+
+ /* Attempt to send the Tear Down Channel message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 3, MSG_TEAR_DOWN_REPLY, 4, 1,
+ (DSP_WORD) ChannelId))
+ return (TdsDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ *pStatus = (GPAK_TearDownChanStat_t) (MsgBuffer[1] & 0xFF);
+ if (*pStatus == Td_Success)
+ return (TdsSuccess);
+ else
+ return (TdsError);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakAlgControl - Control an Algorithm.
+ *
+ * FUNCTION
+ * This function controls an Algorithm
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakAlgControlStat_t gpakAlgControl(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GpakAlgCtrl_t ControlCode, // algorithm control code
+ GPAK_AlgControlStat_t *pStatus // pointer to return status
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (AcInvalidDsp);
+
+ /* Make sure the Channel Id is valid. */
+ if (ChannelId >= MaxChannels[DspId])
+ return (AcInvalidChannel);
+
+ MsgBuffer[0] = MSG_ALG_CONTROL << 8;
+ MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ControlCode & 0xFF));
+
+ /* Attempt to send the Tear Down Channel message to the DSP and receive it's
+ reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 4, MSG_ALG_CONTROL_REPLY, 4, 1,
+ (DSP_WORD) ChannelId))
+ return (AcDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ *pStatus = (GPAK_AlgControlStat_t) (MsgBuffer[1] & 0xFF);
+ if (*pStatus == Ac_Success)
+ return (AcSuccess);
+ else
+ return (AcParmError);
+
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadEventFIFOMessage - read from the event fifo
+ *
+ * FUNCTION
+ * This function reads a single event from the event fifo if one is available
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ * Notes: This function should be called in a loop until the return status
+ * indicates that the fifo is empty.
+ *
+ * If the event code equals "EventLoopbackTeardownComplete", then the
+ * contents of *pChannelId hold the coderBlockId that was assigned to
+ * the loopback coder that was torn down.
+ */
+gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pChannelId, // pointer to channel identifier
+ GpakAsyncEventCode_t *pEventCode, // pointer to Event Code
+ GpakAsyncEventData_t *pEventData // pointer to Event Data Struct
+ )
+{
+ DSP_WORD WordBuffer[WORD_BUFFER_SIZE]; /* DSP words buffer */
+ GpakAsyncEventCode_t EventCode; /* DSP's event code */
+ DSP_WORD EventDataLength; /* Length of event to read */
+ DSP_WORD ChannelId; /* DSP's channel Id */
+ DSP_ADDRESS EventInfoAddress; /* address of EventFIFO info structure */
+ DSP_ADDRESS BufrBaseAddress; /* base address of EventFIFO buffer */
+ DSP_ADDRESS BufrLastAddress; /* last address of EventFIFO buffer */
+ DSP_ADDRESS TakeAddress; /* current take address in fifo buffer */
+ DSP_WORD BufrSize; /* size (in words) of event FIFO buffer */
+ DSP_WORD PutIndex; /* event fifo put index */
+ DSP_WORD TakeIndex; /* event fifo take index */
+ DSP_WORD WordsReady; /* number words ready for read out of event fifo */
+ DSP_WORD EventError; /* flag indicating error with event fifo msg */
+#if 0
+ DSP_WORD *pDebugData; /* debug data buffer pointer in event data struct */
+#endif
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RefInvalidDsp);
+
+ /* Lock access to the DSP. */
+ gpakLockAccess(DspId);
+
+ /* Check if the DSP was reset and is ready. */
+ if (CheckDspReset(DspId) == -1)
+ {
+ gpakUnlockAccess(DspId);
+ return (RefDspCommFailure);
+ }
+
+ /* Check if an event message is ready in the DSP. */
+ EventInfoAddress = pEventFifoAddress[DspId];
+ gpakReadDspMemory(DspId, EventInfoAddress, CIRC_BUFFER_INFO_STRUCT_SIZE,
+ WordBuffer);
+ RECONSTRUCT_LONGWORD(BufrBaseAddress, ((DSP_WORD *)&WordBuffer[CB_BUFR_BASE]));
+ BufrSize = WordBuffer[CB_BUFR_SIZE];
+ PutIndex = WordBuffer[CB_BUFR_PUT_INDEX];
+ TakeIndex = WordBuffer[CB_BUFR_TAKE_INDEX];
+ if (PutIndex >= TakeIndex)
+ WordsReady = PutIndex - TakeIndex;
+ else
+ WordsReady = PutIndex + BufrSize - TakeIndex;
+
+ if (WordsReady < 2)
+ {
+ gpakUnlockAccess(DspId);
+ return (RefNoEventAvail);
+ }
+
+ /* Read the event header from the DSP's Event FIFO. */
+ TakeAddress = BufrBaseAddress + TakeIndex;
+ BufrLastAddress = BufrBaseAddress + BufrSize - 1;
+ ReadCircBuffer(DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress,
+ WordBuffer, 2);
+ TakeIndex += 2;
+ if (TakeIndex >= BufrSize)
+ TakeIndex -= BufrSize;
+
+ ChannelId = (WordBuffer[0] >> 8) & 0xFF;
+ EventCode = (GpakAsyncEventCode_t)(WordBuffer[0] & 0xFF);
+ EventDataLength = WordBuffer[1];
+ EventError = 0;
+
+ switch (EventCode)
+ {
+ case EventToneDetect:
+ if (EventDataLength > WORD_BUFFER_SIZE)
+ {
+ gpakUnlockAccess(DspId);
+#if 0
+ printk("EventDataLength > WORD_BUFFER_SIZE (%d)\n", EventDataLength);
+#endif
+ return (RefInvalidEvent);
+ }
+ ReadCircBuffer(DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress,
+ WordBuffer, EventDataLength);
+ pEventData->toneEvent.ToneCode = (GpakToneCodes_t)
+ (WordBuffer[0] & 0xFF);
+ pEventData->toneEvent.ToneDuration = WordBuffer[1];
+ pEventData->toneEvent.Direction = WordBuffer[2];
+ pEventData->toneEvent.DebugToneStatus = WordBuffer[3];
+ TakeIndex += EventDataLength;
+ if (TakeIndex >= BufrSize)
+ TakeIndex -= BufrSize;
+ if (EventDataLength != 4) {
+#if 0
+ printk("EventDataLength != 4 it's %d\n", EventDataLength);
+#endif
+ EventError = 1;
+ }
+ break;
+
+ default:
+#if 0
+ printk("Event Code not in switch\n");
+#endif
+ EventError = 1;
+ break;
+ };
+
+ /* Update the Take index in the DSP's Packet Out buffer information. */
+ gpakWriteDspMemory(DspId, EventInfoAddress + CB_BUFR_TAKE_INDEX, 1,
+ &TakeIndex);
+
+ /* Unlock access to the DSP. */
+ gpakUnlockAccess(DspId);
+
+ if (EventError)
+ return(RefInvalidEvent);
+
+ *pChannelId = ChannelId;
+ *pEventCode = EventCode;
+ return(RefEventAvail);
+
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakPingDsp - ping the DSP to see if it's alive
+ *
+ * FUNCTION
+ * This function checks if the DSP is still communicating with the host
+ * and returns the DSP SW version
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakPingDspStat_t gpakPingDsp(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pDspSwVersion // DSP software version
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (PngInvalidDsp);
+
+ /* send value of 1, DSP increments it */
+ MsgBuffer[0] = (MSG_PING << 8);
+
+ /* Attempt to send the ping message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 1, MSG_PING_REPLY, 6, 0, 0))
+ return (PngDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ {
+ *pDspSwVersion = MsgBuffer[2];
+ return (PngSuccess);
+ }
+ else
+ return (PngDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakSerialTxFixedValue - transmit a fixed value on a timeslot
+ *
+ * FUNCTION
+ * This function controls transmission of a fixed value out onto a serial
+ * port's timeslot.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id
+ unsigned short int PcmOutSlot, // PCM Output Time Slot
+ unsigned short int Value, // 16-bit value
+ GpakActivation State // activation state
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (TfvInvalidDsp);
+
+ /* Make sure the Channel Id is valid. */
+ if (ChannelId >= MaxChannels[DspId])
+ return (TfvInvalidChannel);
+
+
+ /* Build the message. */
+ MsgBuffer[0] = MSG_SERIAL_TXVAL << 8;
+ MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (State & 0xFF));
+ MsgBuffer[2] = (DSP_WORD) ((PcmOutPort << 8) | (PcmOutSlot & 0xFF));
+ MsgBuffer[3] = (DSP_WORD) Value;
+
+ /* Attempt to send the message to the DSP and receive it's
+ reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 8, MSG_SERIAL_TXVAL_REPLY, 4,
+ 1, ChannelId))
+ return (TfvDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ return (TfvSuccess);
+ else
+ return (TfvDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakControlTdmLoopBack - control a serial port's loopback state
+ *
+ * FUNCTION
+ * This function enables/disables the tdm input to output looback mode on a
+ * serial port
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(
+ unsigned short int DspId, // DSP identifier
+ GpakSerialPort_t SerialPort, // Serial Port Id
+ GpakActivation LoopBackState // Loopback State
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (ClbInvalidDsp);
+
+ /* Build the message. */
+ MsgBuffer[0] = MSG_TDM_LOOPBACK << 8;
+ MsgBuffer[1] = (DSP_WORD) ((SerialPort << 8) | (LoopBackState & 0xFF));
+
+ /* Attempt to send the message to the DSP and receive it's
+ reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 4, MSG_TDM_LOOPBACK_REPLY, 4, 0, 0))
+ return (ClbDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ return (ClbSuccess);
+ else
+ return (ClbDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadCpuUsage - Read CPU usage statistics from a DSP.
+ *
+ * FUNCTION
+ * This function reads the CPU usage statistics from a DSP's memory. The
+ * average CPU usage in units of .1 percent are obtained for each of the frame
+ * rates.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakReadCpuUsageStat_t gpakReadCpuUsage(
+ unsigned short int DspId, // Dsp Identifier
+ unsigned short int *pPeakUsage, // pointer to peak usage variable
+ unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second
+ )
+{
+ DSP_WORD ReadBuffer[2]; /* DSP read buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RcuInvalidDsp);
+
+ /* Lock access to the DSP. */
+ gpakLockAccess(DspId);
+
+ /* Check if the DSP was reset and is ready. */
+ if (CheckDspReset(DspId) == -1)
+ return (RcuDspCommFailure);
+
+ /* Read the CPU Usage statistics from the DSP. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CPU_USAGE_OFFSET, 2,
+ ReadBuffer);
+
+ /* Unlock access to the DSP. */
+ gpakUnlockAccess(DspId);
+
+ /* Store the usage statistics in the specified variables. */
+ *pPrev1SecPeakUsage = ReadBuffer[0];
+ *pPeakUsage = ReadBuffer[1];
+
+ /* Return with an indication the usage staistics were read successfully. */
+ return (RcuSuccess);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetCpuUsageStats - reset the cpu usage statistics
+ *
+ * FUNCTION
+ * This function resets the cpu utilization statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakResetCpuUsageStat_t gpakResetCpuUsageStats(
+ unsigned short int DspId // DSP identifier
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RstcInvalidDsp);
+
+ MsgBuffer[0] = (MSG_RESET_USAGE_STATS << 8);
+
+ /* Attempt to send the message to the DSP and receive it's reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 2, MSG_RESET_USAGE_STATS_REPLY, 4, 0, 0))
+ return (RstcDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ return (RstcSuccess);
+ else
+ return (RstcDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadFramingStats
+ *
+ * FUNCTION
+ * This function reads a DSP's framing interrupt statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakReadFramingStatsStatus_t gpakReadFramingStats(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pFramingError1Count, // port 1 Framing error count
+ unsigned short int *pFramingError2Count, // port 2 Framing error count
+ unsigned short int *pFramingError3Count, // port 3 Framing error count
+ unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count
+ unsigned short int *pDmaSlipStatsBuffer // DMA slips count
+ )
+{
+ DSP_WORD ReadBuffer[10]; /* DSP read buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RfsInvalidDsp);
+
+ /* Lock access to the DSP. */
+ gpakLockAccess(DspId);
+
+ /* Check if the DSP was reset and is ready. */
+ if (CheckDspReset(DspId) == -1)
+ return (RfsDspCommFailure);
+
+ /* Read the framing interrupt statistics from the DSP. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + FRAMING_STATS_OFFSET, 10,
+ ReadBuffer);
+
+ /* Unlock access to the DSP. */
+ gpakUnlockAccess(DspId);
+
+ /* Store the framing statistics in the specified variables. */
+ *pFramingError1Count = ReadBuffer[0];
+ *pFramingError2Count = ReadBuffer[1];
+ *pFramingError3Count = ReadBuffer[2];
+ *pDmaStopErrorCount = ReadBuffer[3];
+
+ if(pDmaSlipStatsBuffer != 0)
+ // If users want to get the DMA slips count
+ {
+ pDmaSlipStatsBuffer[0] = ReadBuffer[4];
+ pDmaSlipStatsBuffer[1] = ReadBuffer[5];
+ pDmaSlipStatsBuffer[2] = ReadBuffer[6];
+ pDmaSlipStatsBuffer[3] = ReadBuffer[7];
+ pDmaSlipStatsBuffer[4] = ReadBuffer[8];
+ pDmaSlipStatsBuffer[5] = ReadBuffer[9];
+
+ }
+ /* Return with an indication the statistics were read successfully. */
+ return (RfsSuccess);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetFramingStats - reset a DSP's framing interrupt statistics
+ *
+ * FUNCTION
+ * This function resets a DSP's framing interrupt statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakResetFramingStatsStatus_t gpakResetFramingStats(
+ unsigned short int DspId // DSP identifier
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RstfInvalidDsp);
+
+ MsgBuffer[0] = (MSG_RESET_FRAME_STATS << 8);
+
+ /* Attempt to send the message to the DSP and receive it's reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 2, MSG_RESET_FRAME_STATS_REPLY, 4, 0, 0))
+ return (RstfDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ return (RstfSuccess);
+ else
+ return (RstfDspCommFailure);
+}
+
+/*
+ * gpakDownloadDsp - Download a DSP's Program and initialized Data memory.
+ *
+ * FUNCTION
+ * This function reads a DSP's Program and Data memory image from the
+ * specified file and writes the image to the DSP's memory.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakDownloadStatus_t gpakDownloadDsp(
+ unsigned short DspId, /* DSP Identifier (0 to MaxDSPCores-1) */
+ GPAK_FILE_ID FileId /* G.PAK Download File Identifier */
+ )
+{
+ gpakDownloadStatus_t RetStatus; /* function return status */
+ int NumRead; /* number of file bytes read */
+ DSP_ADDRESS Address; /* DSP address */
+ unsigned int WordCount; /* number of words in record */
+ unsigned int NumWords; /* number of words to read/write */
+ unsigned int i; /* loop index / counter */
+ unsigned int j; /* loop index */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (GdlInvalidDsp);
+
+ /* Lock access to the DSP. */
+ gpakLockAccess(DspId);
+
+ RetStatus = GdlSuccess;
+ while (RetStatus == GdlSuccess)
+ {
+
+ /* Read a record header from the file. */
+ NumRead = gpakReadFile(FileId, DlByteBufr, 6);
+ if (NumRead == -1)
+ {
+ RetStatus = GdlFileReadError;
+ break;
+ }
+ if (NumRead != 6)
+ {
+ RetStatus = GdlInvalidFile;
+ break;
+ }
+ Address = (((DSP_ADDRESS) DlByteBufr[1]) << 16) |
+ (((DSP_ADDRESS) DlByteBufr[2]) << 8) |
+ ((DSP_ADDRESS) DlByteBufr[3]);
+ WordCount = (((unsigned int) DlByteBufr[4]) << 8) |
+ ((unsigned int) DlByteBufr[5]);
+
+ /* Check for the End Of File record. */
+ if (DlByteBufr[0] == 0xFF)
+ break;
+
+ /* Verify the record is for a valid memory type. */
+ if ((DlByteBufr[0] != 0x00) && (DlByteBufr[0] != 0x01))
+ {
+ RetStatus = GdlInvalidFile;
+ break;
+ }
+
+ /* Read a block of words at a time from the file and write to the
+ DSP's memory .*/
+ while (WordCount != 0)
+ {
+ if (WordCount < DOWNLOAD_BLOCK_SIZE)
+ NumWords = WordCount;
+ else
+ NumWords = DOWNLOAD_BLOCK_SIZE;
+ WordCount -= NumWords;
+ NumRead = gpakReadFile(FileId, DlByteBufr, NumWords * 2);
+ if (NumRead == -1)
+ {
+ RetStatus = GdlFileReadError;
+ break;
+ }
+ if (NumRead != (NumWords * 2))
+ {
+ RetStatus = GdlInvalidFile;
+ break;
+ }
+ for (i = 0, j = 0; i < NumWords; i++, j += 2)
+ DlWordBufr[i] = (((DSP_WORD) DlByteBufr[j]) << 8) |
+ ((DSP_WORD) DlByteBufr[j + 1]);
+ gpakWriteDspMemory(DspId, Address, NumWords, DlWordBufr);
+ Address += ((DSP_ADDRESS) NumWords);
+ }
+ }
+
+ /* Unlock access to the DSP. */
+ gpakUnlockAccess(DspId);
+
+ /* Return with an indication of success or failure. */
+ return (RetStatus);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadCpuUsage - Read CPU usage statistics from a DSP.
+ *
+ * FUNCTION
+ * This function reads the memory map register section of DSP memory.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(
+ unsigned short int DspId, // Dsp Identifier
+ unsigned short int *pDest, // Buffer on host to hold DSP memory map
+ DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out
+ unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP reply's status */
+ int i; /* loop index / counter */
+
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RmmInvalidDsp);
+
+ /* Verify the message buffer is large enough */
+ if (MSG_BUFFER_SIZE < MemoryLength_Word16 )
+ return (RmmSizeTooBig);
+
+ MsgBuffer[0] = MSG_READ_DSP_MEMORY << 8;
+ MsgBuffer[1] = (DSP_WORD) ((BufrBaseAddress >> 16) & 0xFFFF);
+ MsgBuffer[2] = (DSP_WORD) (BufrBaseAddress & 0xFFFF);
+ MsgBuffer[3] = (DSP_WORD) MemoryLength_Word16;
+
+ /* Attempt to send the Read memory section message to the DSP and receive it's
+ reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 8, MSG_READ_DSP_MEMORY_REPLY,
+ (MemoryLength_Word16+2)*2, 0, 0) )
+ return (RmmInvalidAddress);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus != 0)
+ return (RmmFailure);
+
+ for (i = 0; i < MemoryLength_Word16; i++)
+ pDest[i] = (short int) MsgBuffer[2 + i];
+
+
+ return (RmmSuccess);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakAccessGPIO - change Direction/read/write the GPIO on DSP
+ *
+ * FUNCTION
+ * This function read/write GPIO and change the GPIO direction
+ *
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakAccessGPIOStat_t gpakAccessGPIO(
+ unsigned short int DspId, // DSP identifier
+ GpakGPIOCotrol_t gpakControlGPIO,// select oeration, changeDIR/write/read
+ unsigned short int *pGPIOValue // DSP software version
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (GPIOInvalidDsp);
+
+ /* send value of 1, DSP increments it */
+ MsgBuffer[0] = (MSG_ACCESSGPIO << 8);
+ MsgBuffer[1] = (DSP_WORD) ((gpakControlGPIO << 8) | (*pGPIOValue & 0xFF) );
+ /* Attempt to send the ping message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 4, MSG_ACCESSGPIO_REPLY, 6, 0, 0))
+ return (GPIODspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ {
+ *pGPIOValue = MsgBuffer[2];
+ return (GPIOSuccess);
+ }
+ else
+ return (GPIODspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakWriteSystemParms - Write a DSP's System Parameters.
+ *
+ * FUNCTION
+ * This function writes a DSP's System Parameters information.
+ *
+ * Note:
+ * Or-together the desired bit-mask #defines that are listed below. Only
+ * those algorithm parameters whose bit-mask is selected in the UpdateBits
+ * function parameter will be updated.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+
+gpakWriteSysParmsStatus_t gpakWriteSystemParms(
+ unsigned short int DspId, // DSP identifier
+ GpakSystemParms_t *pSysParms, /* pointer to System Parms info var */
+ unsigned short int UpdateBits, /* input: flags indicating which parms to update */
+ GPAK_SysParmsStat_t *pStatus /* pointer to Write System Parms Status */
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (WspInvalidDsp);
+
+ /* Build the Write System Parameters message. */
+ MsgBuffer[0] = MSG_WRITE_SYS_PARMS << 8;
+
+ if (UpdateBits & DTMF_UPDATE_MASK)
+ {
+ MsgBuffer[1] |= DTMF_UPDATE_MASK;
+ MsgBuffer[8] = (DSP_WORD) pSysParms->MinSigLevel;
+ MsgBuffer[9] = (DSP_WORD) (pSysParms->FreqDeviation & 0xff);
+ if (pSysParms->SNRFlag)
+ MsgBuffer[9] |= (1<<8);
+ }
+
+ MsgBuffer[10] = (DSP_WORD) 0;
+ if (UpdateBits & DTMF_TWIST_UPDATE_MASK)
+ {
+ MsgBuffer[1] |= DTMF_TWIST_UPDATE_MASK;
+ MsgBuffer[10] |= (DSP_WORD) (pSysParms->DtmfFwdTwist & 0x000f);
+ MsgBuffer[10] |= (DSP_WORD) ((pSysParms->DtmfRevTwist << 4) & 0x00f0);
+ }
+
+
+ if (UpdateBits & DTMF_VALID_MASK)
+ {
+ MsgBuffer[1] |= DTMF_VALID_MASK;
+ MsgBuffer[11] = (DSP_WORD) (pSysParms->DtmfValidityMask & 0x00ff);
+ }
+
+ /* Attempt to send the ping message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 24, MSG_WRITE_SYS_PARMS_REPLY, 6, 0, 0))
+ return (WspDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ *pStatus = (GPAK_SysParmsStat_t) (MsgBuffer[2] );
+
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ return (WspSuccess);
+ else
+ return (WspDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadSystemParms - Read a DSP's System Parameters.
+ *
+ * FUNCTION
+ * This function reads a DSP's System Parameters information.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakReadSysParmsStatus_t gpakReadSystemParms(
+ unsigned short int DspId, // DSP identifier
+ GpakSystemParms_t *pSysParms /* pointer to System Parms info var */
+ )
+{
+
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RspInvalidDsp);
+
+ /* Build the Read System Parameters message. */
+ MsgBuffer[0] = MSG_READ_SYS_PARMS << 8;
+
+ /* Attempt to send the ping message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 2, MSG_READ_SYS_PARMS_REPLY, 22, 0, 0))
+ return (RspDspCommFailure);
+
+ /* Extract the System Parameters information from the message. */
+ pSysParms->DtmfValidityMask = (short int)(MsgBuffer[7]) ;
+
+ pSysParms->MinSigLevel = (short int)MsgBuffer[8];
+ pSysParms->SNRFlag = (short int)((MsgBuffer[9]>>8) & 0x1);
+ pSysParms->FreqDeviation = (short int)(MsgBuffer[9] & 0xff);
+ pSysParms->DtmfFwdTwist = (short int)MsgBuffer[10] & 0x000f;
+ pSysParms->DtmfRevTwist = (short int)(MsgBuffer[10] >> 4) & 0x000f;
+
+ /* Return with an indication that System Parameters info was obtained. */
+ return (RspSuccess);
+}
diff --git a/drivers/dahdi/wctdm24xxp/GpakApi.h b/drivers/dahdi/wctdm24xxp/GpakApi.h
new file mode 100644
index 0000000..df57c09
--- /dev/null
+++ b/drivers/dahdi/wctdm24xxp/GpakApi.h
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2005 , Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakApi.h
+ *
+ * Description:
+ * This file contains the function prototypes and data types for the user
+ * API functions that communicate with DSPs executing G.PAK software. The
+ * file is used by application software in the host processor connected to
+ * C55X G.PAK DSPs via a Host Port Interface.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 06/15/05 - Initial release.
+ * 11/15/2006 - 24 TDM-TDM Channels EC release
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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.
+ */
+
+#ifndef _GPAKAPI_H /* prevent multiple inclusion */
+#define _GPAKAPI_H
+#include "gpakErrs.h"
+#include "gpakenum.h"
+
+// Bit masks to select which algorithm's parameters to update: Or-together the
+// desired masks into the UpdateBits function parameter.
+#define DTMF_UPDATE_MASK 0x0010 // update DTMF params, MinLevel, SNRFlag and Freq
+#define DTMF_TWIST_UPDATE_MASK 0x0020 // update DTMF TWIST system params
+#define DTMF_VALID_MASK 0x0080 // update DTMF ValidMask params
+
+#define DSP_DEBUG_BUFF_SIZE 42 // units of 16-bit words
+
+/* Definition of an Asynchronous Event Data Structure */
+typedef union
+{
+ struct
+ {
+ GpakToneCodes_t ToneCode; // detected tone code
+ unsigned short int ToneDuration; // tone duration
+ GpakTdmDirection Direction; // detected on A r B side
+ short int DebugToneStatus;// reserved for debug info
+ } toneEvent;
+
+} GpakAsyncEventData_t;
+
+/* Definition of an Echo Canceller Parameters information structure. */
+typedef struct
+{
+ short int EcanTapLength; // Echo Can Num Taps (tail length)
+ short int EcanNlpType; // Echo Can NLP Type
+ short int EcanAdaptEnable; // Echo Can Adapt Enable flag
+ short int EcanG165DetEnable; // Echo Can G165 Detect Enable flag
+ short int EcanDblTalkThresh; // Echo Can Double Talk threshold
+ short int EcanNlpThreshold; // Echo Can NLP threshold
+ short int EcanNlpConv; // Dynamic NLP control, NLP limit when EC about to converged
+ short int EcanNlpUnConv;// Dynamic NLP control, NLP limit when EC not converged yet
+ short int EcanNlpMaxSuppress; // suppression level for NLP_SUPP mode
+ short int EcanCngThreshold; // Echo Can CNG Noise threshold
+ short int EcanAdaptLimit; // Echo Can Max Adapts per frame
+ short int EcanCrossCorrLimit; // Echo Can Cross Correlation limit
+ short int EcanNumFirSegments; // Echo Can Num FIR Segments
+ short int EcanFirSegmentLen; // Echo Can FIR Segment Length
+} GpakEcanParms_t;
+
+/* Definition of a Channel Configuration information structure. */
+typedef struct
+{
+ GpakSerialPort_t PcmInPortA; // A side PCM Input Serial Port Id
+ unsigned short int PcmInSlotA; // A side PCM Input Time Slot
+ GpakSerialPort_t PcmOutPortA; // A side PCM Output Serial Port Id
+ unsigned short int PcmOutSlotA; // A side PCM Output Time Slot
+ GpakSerialPort_t PcmInPortB; // B side PCM Input Serial Port Id
+ unsigned short int PcmInSlotB; // B side PCM Input Time Slot
+ GpakSerialPort_t PcmOutPortB; // B side PCM Output Serial Port Id
+ unsigned short int PcmOutSlotB; // B side PCM Output Time Slot
+ GpakToneTypes ToneTypesA; // A side Tone Detect Types
+ GpakToneTypes ToneTypesB; // B side Tone Detect Types
+ GpakActivation EcanEnableA; // Echo Cancel A Enabled
+ GpakActivation EcanEnableB; // Echo Cancel B Enabled
+ GpakEcanParms_t EcanParametersA; // Echo Cancel parameters
+ GpakEcanParms_t EcanParametersB; // Echo Cancel parameters
+ GpakCompandModes SoftwareCompand; // software companding
+ GpakRate_t FrameRate; // Gpak Frame Rate
+ GpakActivation MuteToneA; // A side mute DTMF Enabled
+ GpakActivation MuteToneB; // B side mute DTMF Enabled
+ GpakActivation FaxCngDetA; // A side FaxCng Tone Detector Enabled
+ GpakActivation FaxCngDetB; // B side FaxCng Tone Detector Enabled
+
+} GpakChannelConfig_t;
+
+
+/* Definition of a Serial Port Configuration Structure */
+typedef struct
+{
+ GpakSlotCfg_t SlotsSelect1; // port 1 Slot selection
+ unsigned short int FirstBlockNum1; // port 1 first group Block Number
+ unsigned short int FirstSlotMask1; // port 1 first group Slot Mask
+ unsigned short int SecBlockNum1; // port 1 second group Block Number
+ unsigned short int SecSlotMask1; // port 1 second group Slot Mask
+
+ GpakSerWordSize_t SerialWordSize1; // port 1 serial word size
+ GpakCompandModes CompandingMode1; // port 1 companding mode
+ GpakSerFrameSyncPol_t TxFrameSyncPolarity1; // port 1 Tx Frame Sync Polarity
+ GpakSerFrameSyncPol_t RxFrameSyncPolarity1; // port 1 Rx Frame Sync Polarity
+ GpakSerClockPol_t TxClockPolarity1; // port 1 Tx Clock Polarity
+ GpakSerClockPol_t RxClockPolarity1; // port 1 Rx Clock Polarity
+ GpakSerDataDelay_t TxDataDelay1; // port 1 Tx data delay
+ GpakSerDataDelay_t RxDataDelay1; // port 1 Rx data delay
+ GpakActivation DxDelay1; // port 1 DX Delay
+
+ unsigned short int ThirdSlotMask1; // port 1 3rd group Slot Mask
+ unsigned short int FouthSlotMask1; // port 1 4th group Slot Mask
+ unsigned short int FifthSlotMask1; // port 1 5th group Slot Mask
+ unsigned short int SixthSlotMask1; // port 1 6th group Slot Mask
+ unsigned short int SevenSlotMask1; // port 1 7th group Slot Mask
+ unsigned short int EightSlotMask1; // port 1 8th group Slot Mask
+
+
+ GpakSlotCfg_t SlotsSelect2; // port 2 Slot selection
+ unsigned short int FirstBlockNum2; // port 2 first group Block Number
+ unsigned short int FirstSlotMask2; // port 2 first group Slot Mask
+ unsigned short int SecBlockNum2; // port 2 second group Block Number
+ unsigned short int SecSlotMask2; // port 2 second group Slot Mask
+ GpakSerWordSize_t SerialWordSize2; // port 2 serial word size
+ GpakCompandModes CompandingMode2; // port 2 companding mode
+ GpakSerFrameSyncPol_t TxFrameSyncPolarity2; // port 2 Tx Frame Sync Polarity
+ GpakSerFrameSyncPol_t RxFrameSyncPolarity2; // port 2 Rx Frame Sync Polarity
+ GpakSerClockPol_t TxClockPolarity2; // port 2 Tx Clock Polarity
+ GpakSerClockPol_t RxClockPolarity2; // port 2 Rx Clock Polarity
+ GpakSerDataDelay_t TxDataDelay2; // port 2 Tx data delay
+ GpakSerDataDelay_t RxDataDelay2; // port 2 Rx data delay
+ GpakActivation DxDelay2; // port 2 DX Delay
+
+ unsigned short int ThirdSlotMask2; // port 2 3rd group Slot Mask
+ unsigned short int FouthSlotMask2; // port 2 4th group Slot Mask
+ unsigned short int FifthSlotMask2; // port 2 5th group Slot Mask
+ unsigned short int SixthSlotMask2; // port 2 6th group Slot Mask
+ unsigned short int SevenSlotMask2; // port 2 7th group Slot Mask
+ unsigned short int EightSlotMask2; // port 2 8th group Slot Mask
+
+ GpakSlotCfg_t SlotsSelect3; // port 3 Slot selection
+ unsigned short int FirstBlockNum3; // port 3 first group Block Number
+ unsigned short int FirstSlotMask3; // port 3 first group Slot Mask
+ unsigned short int SecBlockNum3; // port 3 second group Block Number
+ unsigned short int SecSlotMask3; // port 3 second group Slot Mask
+ GpakSerWordSize_t SerialWordSize3; // port 3 serial word size
+ GpakCompandModes CompandingMode3; // port 3 companding mode
+ GpakSerFrameSyncPol_t TxFrameSyncPolarity3; // port 3 Tx Frame Sync Polarity
+ GpakSerFrameSyncPol_t RxFrameSyncPolarity3; // port 3 Rx Frame Sync Polarity
+ GpakSerClockPol_t TxClockPolarity3; // port 3 Tx Clock Polarity
+ GpakSerClockPol_t RxClockPolarity3; // port 3 Rx Clock Polarity
+ GpakSerDataDelay_t TxDataDelay3; // port 3 Tx data delay
+ GpakSerDataDelay_t RxDataDelay3; // port 3 Rx data delay
+ GpakActivation DxDelay3; // port 3 DX Delay
+
+ unsigned short int ThirdSlotMask3; // port 3 3rd group Slot Mask
+ unsigned short int FouthSlotMask3; // port 3 4th group Slot Mask
+ unsigned short int FifthSlotMask3; // port 3 5th group Slot Mask
+ unsigned short int SixthSlotMask3; // port 3 6th group Slot Mask
+ unsigned short int SevenSlotMask3; // port 3 7th group Slot Mask
+ unsigned short int EightSlotMask3; // port 3 8th group Slot Mask
+
+} GpakPortConfig_t;
+
+/* Definition of a Tone Generation Parameter Structure */
+/*
+typedef struct
+{
+ GpakToneGenType_t ToneType; // Tone Type
+ unsigned short int Frequency[4]; // Frequency (Hz)
+ short int Level[4]; // Frequency's Level (1 dBm)
+ unsigned short int OnTime[4]; // On Times (msecs)
+ unsigned short int OffTime[4]; // Off Times (msecs)
+} GpakToneGenParms_t;
+*/
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakConfigureChannel return status. */
+typedef enum
+{
+ CcsSuccess = 0, /* Channel Configured successfully */
+ CcsParmError = 1, /* Channel Config Parameter error */
+ CcsInvalidChannel = 2, /* invalid channel */
+ CcsInvalidDsp = 3, /* invalid DSP */
+ CcsDspCommFailure = 4 /* failed to communicate with DSP */
+} gpakConfigChanStatus_t;
+
+/*
+ * gpakConfigureChannel - Configure a DSP's Channel.
+ *
+ * FUNCTION
+ * This function configures a DSP's Channel.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+extern gpakConfigChanStatus_t gpakConfigureChannel(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GpakChanType ChannelType, // channel type
+ GpakChannelConfig_t *pChanConfig, // pointer to channel config info
+ GPAK_ChannelConfigStat_t *pStatus // pointer to Channel Config Status
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakTearDownChannel return status. */
+typedef enum
+{
+ TdsSuccess = 0, /* Channel Tear Down successful */
+ TdsError = 1, /* Channel Tear Down error */
+ TdsInvalidChannel = 2, /* invalid channel */
+ TdsInvalidDsp = 3, /* invalid DSP */
+ TdsDspCommFailure = 4 /* failed to communicate with DSP */
+} gpakTearDownStatus_t;
+
+/*
+ * gpakTearDownChannel - Tear Down a DSP's Channel.
+ *
+ * FUNCTION
+ * This function tears down a DSP's Channel.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+
+extern gpakTearDownStatus_t gpakTearDownChannel(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GPAK_TearDownChanStat_t *pStatus // pointer to Tear Down Status
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakAlgControl return status. */
+typedef enum
+{
+ AcSuccess = 0, /* control successful */
+ AcInvalidChannel = 1, /* invalid channel identifier */
+ AcInvalidDsp = 2, /* invalid DSP */
+ AcParmError = 3, /* invalid control parameter */
+ AcDspCommFailure = 4 /* failed to communicate with DSP */
+} gpakAlgControlStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakAlgControl - Control an Algorithm.
+ *
+ * FUNCTION
+ * This function controls an Algorithm
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+extern gpakAlgControlStat_t gpakAlgControl(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GpakAlgCtrl_t ControlCode, // algorithm control code
+ GPAK_AlgControlStat_t *pStatus // pointer to return status
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakConfigurePorts return status. */
+typedef enum
+{
+ CpsSuccess = 0, /* Serial Ports configured successfully */
+ CpsParmError = 1, /* Configure Ports Parameter error */
+ CpsInvalidDsp = 2, /* invalid DSP */
+ CpsDspCommFailure = 3 /* failed to communicate with DSP */
+} gpakConfigPortStatus_t;
+
+/*
+ * gpakConfigurePorts - Configure a DSP's serial ports.
+ *
+ * FUNCTION
+ * This function configures a DSP's serial ports.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+extern gpakConfigPortStatus_t gpakConfigurePorts(
+ unsigned short int DspId, // DSP identifier
+ GpakPortConfig_t *pPortConfig, // pointer to Port Config info
+ GPAK_PortConfigStat_t *pStatus // pointer to Port Config Status
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakDownloadDsp return status. */
+typedef enum
+{
+ GdlSuccess = 0, /* DSP download successful */
+ GdlFileReadError = 1, /* error reading Download file */
+ GdlInvalidFile = 2, /* invalid Download file content */
+ GdlInvalidDsp = 3 /* invalid DSP */
+} gpakDownloadStatus_t;
+
+/*
+ * gpakDownloadDsp - Download a DSP's Program and initialized Data memory.
+ *
+ * FUNCTION
+ * This function reads a DSP's Program and Data memory image from the
+ * specified file and writes the image to the DSP's memory.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+extern gpakDownloadStatus_t gpakDownloadDsp(
+ unsigned short int DspId, // DSP identifier
+ GPAK_FILE_ID FileId // G.PAK download file identifier
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakReadEventFIFOMessage return status */
+typedef enum
+{
+ RefEventAvail = 0, /* an event was successfully read from the fifo */
+ RefNoEventAvail = 1, /* no event was in the fifo */
+ RefInvalidDsp = 2, /* invalid DSP identifier */
+ RefInvalidEvent = 3, /* invalid event */
+ RefDspCommFailure = 4 /* error communicating with DSP */
+} gpakReadEventFIFOMessageStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadEventFIFOMessage - read from the event fifo
+ *
+ * FUNCTION
+ * This function reads a single event from the event fifo if one is available
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ * Note: This function should be called in a loop until the return status
+ * indicates that the fifo is empty.
+ */
+extern gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pChannelId, // pointer to channel identifier
+ GpakAsyncEventCode_t *pEventCode, // pointer to Event Code
+ GpakAsyncEventData_t *pEventData // pointer to Event Data Struct
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakPingDsp return status values */
+typedef enum
+{
+ PngSuccess = 0, /* DSP responded successfully */
+ PngInvalidDsp = 1, /* invalid DSP identifier */
+ PngDspCommFailure = 2 /* error communicating with DSP */
+} gpakPingDspStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakPingDsp - ping the DSP to see if it's alive
+ *
+ * FUNCTION
+ * This function checks if the DSP is still communicating with the host
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakPingDspStat_t gpakPingDsp(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pDspSwVersion // DSP software version
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakSerialTxFixedValue return status values */
+typedef enum
+{
+ TfvSuccess = 0, /* operation successful */
+ TfvInvalidChannel = 1, /* invalid channel identifier */
+ TfvInvalidDsp = 2, /* invalid DSP identifier */
+ TfvDspCommFailure = 3 /* failed to communicate with DSP */
+} gpakSerialTxFixedValueStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakSerialTxFixedValue - transmit a fixed value on a timeslot
+ *
+ * FUNCTION
+ * This function controls transmission of a fixed value out onto a serial
+ * port's timeslot.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id
+ unsigned short int PcmOutSlot, // PCM Output Time Slot
+ unsigned short int Value, // 16-bit value
+ GpakActivation State // activation state
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakControlTdmLoopBack return status values */
+typedef enum
+{
+ ClbSuccess = 0, /* operation successful */
+ ClbSerPortInactive = 1, /* serial port is inactive */
+ ClbInvalidDsp = 2, /* invalid DSP identifier */
+ ClbDspCommFailure = 3 /* failed to communicate with DSP */
+} gpakControlTdmLoopBackStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakControlTdmLoopBack - control a serial port's loopback state
+ *
+ * FUNCTION
+ * This function enables/disables the tdm input to output looback mode on a
+ * serial port
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(
+ unsigned short int DspId, // DSP identifier
+ GpakSerialPort_t SerialPort, // Serial Port Id
+ GpakActivation LoopBackState // Loopback State
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakReadCpuUsage return status values */
+typedef enum
+{
+ RcuSuccess = 0, /* operation successful */
+ RcuInvalidDsp = 1, /* invalid DSP identifier */
+ RcuDspCommFailure = 2 /* communication failure */
+} gpakReadCpuUsageStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadCpuUsage - read the cpu usage statistics
+ *
+ * FUNCTION
+ * This function reads cpu utilization from the DSP.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakReadCpuUsageStat_t gpakReadCpuUsage(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pPeakUsage, // pointer to peak usage variable
+ unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakResetCpuUsageStats return status values */
+typedef enum
+{
+ RstcSuccess = 0, /* operation successful */
+ RstcInvalidDsp = 1, /* invalid DSP identifier */
+ RstcDspCommFailure = 2 /* communication failure */
+} gpakResetCpuUsageStat_t;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetCpuUsageStats - reset the cpu usage statistics
+ *
+ * FUNCTION
+ * This function resets the cpu utilization statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakResetCpuUsageStat_t gpakResetCpuUsageStats(
+ unsigned short int DspId // DSP identifier
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakReadFramingStats return status values */
+typedef enum
+{
+ RfsSuccess = 0, /* operation successful */
+ RfsInvalidDsp = 1, /* invalid DSP identifier */
+ RfsDspCommFailure = 2 /* communication failure */
+} gpakReadFramingStatsStatus_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadFramingStats
+ *
+ * FUNCTION
+ * This function reads a DSP's framing interrupt statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakReadFramingStatsStatus_t gpakReadFramingStats(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pFramingError1Count, // port 1 Framing error count
+ unsigned short int *pFramingError2Count, // port 2 Framing error count
+ unsigned short int *pFramingError3Count, // port 3 Framing error count
+ unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count
+ unsigned short int *pDmaSlipStatsBuffer // DMA slips count
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakResetFramingStats return values */
+typedef enum
+{
+ RstfSuccess = 0, /* operation successful */
+ RstfInvalidDsp = 1, /* invalid DSP identifier */
+ RstfDspCommFailure = 2 /* communication failure */
+} gpakResetFramingStatsStatus_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetFramingStats - reset a DSP's framing interrupt statistics
+ *
+ * FUNCTION
+ * This function resets a DSP's framing interrupt statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakResetFramingStatsStatus_t gpakResetFramingStats(
+ unsigned short int DspId // DSP identifier
+ );
+
+
+typedef enum
+{
+ RmmSuccess =0,
+ RmmInvalidDsp = 1,
+ RmmSizeTooBig = 2,
+ RmmFailure = 3,
+ RmmInvalidAddress = 4
+
+} gpakReadDSPMemoryStat_t;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetFramingStats - read a section of DSP memory
+ * to get access DSP registers, since 0x00--0x60 not HPI-accessable
+ *
+ * FUNCTION
+ * This function resets a DSP's framing interrupt statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+
+extern gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(
+ unsigned short int DspId, // Dsp Identifier
+ unsigned short int *pDest, // Buffer on host to hold DSP memory map
+ DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out
+ unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word
+ );
+
+typedef enum
+{
+ GPIOSuccess =0,
+ GPIOInvalidDsp = 1,
+ GPIODspCommFailure = 2
+}gpakAccessGPIOStat_t;
+
+extern gpakAccessGPIOStat_t gpakAccessGPIO(
+ unsigned short int DspId, // DSP identifier
+ GpakGPIOCotrol_t gpakControlGPIO,// select oeration, changeDIR/write/read
+ unsigned short int *pGPIOValue // pointer for the read/write value or DIR mask
+ );
+
+/* gpakWriteSystemParms return status. */
+typedef enum
+{
+ WspSuccess = 0, /* System Parameters written successfully */
+ WspParmError = 1, /* Write System Parms's Parameter error */
+ WspInvalidDsp = 2, /* invalid DSP */
+ WspDspCommFailure = 3 /* failed to communicate with DSP */
+} gpakWriteSysParmsStatus_t;
+
+/* Definition of a System Parameters information structure. */
+typedef struct
+{
+ /* DTMF Parameters */
+ short int MinSigLevel; /* 0 = Disabled, Min Sig Power Level for detection */
+ short int SNRFlag; /* 0 = Disabled, relax SNR tolerances */
+ short int FreqDeviation; /* 0 = Disabled, X Percent Deviation times 10 (e.g. 1.7% is entered as 17) */
+ short int DtmfFwdTwist; /* 0 to 8 db */
+ short int DtmfRevTwist; /* 0 to 8 db */
+
+ short int DtmfValidityMask; /* This flag allows users to relax the trailing conditions of the tone */
+
+} GpakSystemParms_t;
+/* gpakReadSystemParms return status. */
+typedef enum
+{
+ RspSuccess = 0, /* System Parameters read successfully */
+ RspInvalidDsp = 1, /* invalid DSP */
+ RspDspCommFailure = 2 /* failed to communicate with DSP */
+} gpakReadSysParmsStatus_t;
+
+extern gpakReadSysParmsStatus_t gpakReadSystemParms(
+ unsigned short int DspId, // DSP identifier
+ GpakSystemParms_t *pSysParms /* pointer to System Parms info var */
+ );
+
+extern gpakWriteSysParmsStatus_t gpakWriteSystemParms(
+ unsigned short int DspId, // DSP identifier
+ GpakSystemParms_t *pSysParms, /* pointer to System Parms info var */
+ unsigned short int UpdateBits, /* input: flags indicating which parms to update */
+ GPAK_SysParmsStat_t *pStatus /* pointer to Write System Parms Status */
+ );
+
+#endif // end multiple inclusion
+
diff --git a/drivers/dahdi/wctdm24xxp/GpakCust.c b/drivers/dahdi/wctdm24xxp/GpakCust.c
new file mode 100644
index 0000000..23f2096
--- /dev/null
+++ b/drivers/dahdi/wctdm24xxp/GpakCust.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2005, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakCust.c
+ *
+ * Description:
+ * This file contains host system dependent functions to support generic
+ * G.PAK API functions. The file is integrated into the host processor
+ * connected to C55x G.PAK DSPs via a Host Port Interface.
+ *
+ * Note: This file needs to be modified by the G.PAK system integrator.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 06/15/05 - Initial release.
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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/version.h>
+#include <linux/delay.h>
+#include <asm/semaphore.h>
+
+#include "zaptel.h"
+#include "wctdm24xxp.h"
+#include "GpakCust.h"
+
+char vpm150mtone_to_zaptone(GpakToneCodes_t tone)
+{
+ switch (tone) {
+ case DtmfDigit0:
+ return '0';
+ case DtmfDigit1:
+ return '1';
+ case DtmfDigit2:
+ return '2';
+ case DtmfDigit3:
+ return '3';
+ case DtmfDigit4:
+ return '4';
+ case DtmfDigit5:
+ return '5';
+ case DtmfDigit6:
+ return '6';
+ case DtmfDigit7:
+ return '7';
+ case DtmfDigit8:
+ return '8';
+ case DtmfDigit9:
+ return '9';
+ case DtmfDigitPnd:
+ return '#';
+ case DtmfDigitSt:
+ return '*';
+ case DtmfDigitA:
+ return 'A';
+ case DtmfDigitB:
+ return 'B';
+ case DtmfDigitC:
+ return 'C';
+ case DtmfDigitD:
+ return 'D';
+ case EndofCngDigit:
+ return 'f';
+ default:
+ return 0;
+ }
+}
+
+static inline struct wctdm * wc_find_iface(unsigned short dspid)
+{
+ int i;
+ struct wctdm *ret = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ifacelock, flags);
+ for (i = 0; i < WC_MAX_IFACES; i++)
+ if (ifaces[i] && ifaces[i]->vpm150m && (ifaces[i]->vpm150m->dspid == dspid))
+ ret = ifaces[i];
+ spin_unlock_irqrestore(&ifacelock, flags);
+
+ return ret;
+}
+
+static inline struct vpm150m_cmd * vpm150m_empty_slot(struct wctdm *wc)
+{
+ int x;
+
+ for (x = 0; x < VPM150M_MAX_COMMANDS; x++)
+ if (!wc->vpm150m->cmdq[x].desc) {
+ return &wc->vpm150m->cmdq[x];
+ }
+ return NULL;
+}
+
+/* Wait for any outstanding commands to be completed. */
+static inline int vpm150m_io_wait(struct wctdm *wc)
+{
+ int x;
+ int ret=0;
+ for (x=0; x < VPM150M_MAX_COMMANDS;) {
+ if (wc->vpm150m->cmdq[x].desc) {
+ if ((ret=schluffen(&wc->regq))) {
+ return ret;
+ }
+ x=0;
+ }
+ else {
+ ++x;
+ }
+ }
+ return ret;
+}
+
+int wctdm_vpm150m_getreg_full_async(struct wctdm *wc, int pagechange, unsigned int len,
+ unsigned short addr, unsigned short *outbuf, struct vpm150m_cmd **hit_p)
+{
+ int ret=0;
+ unsigned long flags;
+ BUG_ON(!hit_p);
+ spin_lock_irqsave(&wc->reglock, flags);
+ (*hit_p) = vpm150m_empty_slot(wc);
+ if (*hit_p) {
+ (*hit_p)->desc = __VPM150M_RD;
+ if (pagechange) {
+ (*hit_p)->desc |= __VPM150M_RWPAGE;
+ }
+ (*hit_p)->datalen = len;
+ (*hit_p)->addr = addr;
+ memset((*hit_p)->data, 0, len*sizeof(outbuf[0]));
+ }
+ else {
+ ret = -EBUSY;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return ret;
+}
+
+int wctdm_vpm150m_getreg_full_return(struct wctdm *wc, int pagechange, unsigned int len,
+ unsigned short addr, unsigned short *outbuf, struct vpm150m_cmd **hit_p)
+{
+ int ret = 0;
+ unsigned long flags;
+ BUG_ON(!hit_p);
+ spin_lock_irqsave(&wc->reglock, flags);
+ do {
+ if ((*hit_p)->desc & __VPM150M_FIN) {
+ memcpy(outbuf, (*hit_p)->data, len*(sizeof(outbuf[0])));
+ (*hit_p)->desc = 0;
+ (*hit_p) = NULL;
+ ret = 0;
+ }
+ else {
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if ((ret=schluffen(&wc->regq))) {
+ return ret;
+ }
+ spin_lock_irqsave(&wc->reglock, flags);
+ ret = -EBUSY;
+ }
+ } while (-EBUSY == ret);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return ret;
+}
+
+int wctdm_vpm150m_getreg_full(struct wctdm *wc, int pagechange, unsigned int len, unsigned short addr, unsigned short *outbuf)
+{
+ struct vpm150m_cmd *hit = 0;
+ int ret = 0;
+ do {
+ ret = wctdm_vpm150m_getreg_full_async(wc, pagechange, len, addr, outbuf, &hit);
+ if (!hit) {
+ if ( -EBUSY == ret ) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ BUG_ON(0 != ret);
+ }
+ } while (!hit);
+ ret = wctdm_vpm150m_getreg_full_return(wc, pagechange, len, addr, outbuf, &hit);
+ return ret;
+}
+
+int wctdm_vpm150m_setreg_full(struct wctdm *wc, int pagechange, unsigned int len, unsigned int addr, unsigned short *data)
+{
+ unsigned long flags;
+ struct vpm150m_cmd *hit;
+ int ret, i;
+ do {
+ spin_lock_irqsave(&wc->reglock, flags);
+ hit = vpm150m_empty_slot(wc);
+ if (hit) {
+ hit->desc = __VPM150M_WR;
+ if (pagechange)
+ hit->desc |= __VPM150M_RWPAGE;
+ hit->addr = addr;
+ hit->datalen = len;
+ for (i = 0; i < len; i++)
+ hit->data[i] = data[i];
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (!hit) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ } while (!hit);
+ return (hit) ? 0 : -1;
+}
+
+int wctdm_vpm150m_setpage(struct wctdm *wc, unsigned short addr)
+{
+ addr &= 0xf;
+ /* Let's optimize this a little bit */
+ if (wc->vpm150m->curpage == addr)
+ return 0;
+ else {
+ wc->vpm150m->curpage = addr;
+ }
+
+ return wctdm_vpm150m_setreg_full(wc, 1, 1, 0, &addr);
+}
+
+unsigned char wctdm_vpm150m_getpage(struct wctdm *wc)
+{
+ unsigned short res;
+ wctdm_vpm150m_getreg_full(wc, 1, 1, 0, &res);
+ return res;
+}
+
+unsigned short wctdm_vpm150m_getreg(struct wctdm *wc, unsigned int len, unsigned int addr, unsigned short *data)
+{
+ unsigned short res;
+ wctdm_vpm150m_setpage(wc, addr >> 16);
+ if ((addr >> 16) != ((addr + len) >> 16))
+ printk("getreg: You found it!\n");
+ res = wctdm_vpm150m_getreg_full(wc, 0, len, addr & 0xffff, data);
+ return res;
+}
+
+int wctdm_vpm150m_setreg(struct wctdm *wc, unsigned int len, unsigned int addr, unsigned short *data)
+{
+ int res;
+ wctdm_vpm150m_setpage(wc, addr >> 16);
+ if ((addr >> 16) != ((addr + len) >> 16))
+ printk("getreg: You found it!\n");
+ res = wctdm_vpm150m_setreg_full(wc, 0, len, addr & 0xffff, data);
+ return res;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadDspMemory - Read DSP memory.
+ *
+ * FUNCTION
+ * This function reads a contiguous block of words from DSP memory starting at
+ * the specified address.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+void gpakReadDspMemory(
+ unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ DSP_ADDRESS DspAddress, /* DSP's memory address of first word */
+ unsigned int NumWords, /* number of contiguous words to read */
+ DSP_WORD *pWordValues /* pointer to array of word values variable */
+ )
+{
+ struct wctdm *wc = wc_find_iface(DspId);
+ int i;
+ int transcount;
+ int ret;
+
+ vpm150m_io_wait(wc);
+ if ( NumWords < VPM150M_MAX_COMMANDS ) {
+ struct vpm150m_cmd* cmds[VPM150M_MAX_COMMANDS] = {0};
+ wctdm_vpm150m_setpage(wc, DspAddress >> 16);
+ DspAddress &= 0xffff;
+ for (i=0; i < NumWords; ++i) {
+ ret = wctdm_vpm150m_getreg_full_async(wc,0,1,DspAddress+i,&pWordValues[i],
+ &cmds[i]);
+ if (0 != ret) {
+ return;
+ }
+ }
+ for (i=NumWords-1; i >=0; --i) {
+ ret = wctdm_vpm150m_getreg_full_return(wc,0,1,DspAddress+i,&pWordValues[i],
+ &cmds[i]);
+ if (0 != ret) {
+ return;
+ }
+ }
+ }
+ else {
+ for (i = 0; i < NumWords;) {
+ if ((NumWords - i) > VPM150M_MAX_DATA)
+ transcount = VPM150M_MAX_DATA;
+ else
+ transcount = NumWords - i;
+ wctdm_vpm150m_getreg(wc, transcount, DspAddress + i, &pWordValues[i]);
+ i += transcount;
+ }
+ }
+ return;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakWriteDspMemory - Write DSP memory.
+ *
+ * FUNCTION
+ * This function writes a contiguous block of words to DSP memory starting at
+ * the specified address.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+void gpakWriteDspMemory(
+ unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ DSP_ADDRESS DspAddress, /* DSP's memory address of first word */
+ unsigned int NumWords, /* number of contiguous words to write */
+ DSP_WORD *pWordValues /* pointer to array of word values to write */
+ )
+{
+
+ struct wctdm *wc = wc_find_iface(DspId);
+ int i;
+ int transcount;
+
+ //printk("Writing %d words to memory\n", NumWords);
+ if (wc && wc->vpm150m) {
+ for (i = 0; i < NumWords;) {
+ if ((NumWords - i) > VPM150M_MAX_DATA)
+ transcount = VPM150M_MAX_DATA;
+ else
+ transcount = NumWords - i;
+
+ wctdm_vpm150m_setreg(wc, transcount, DspAddress + i, &pWordValues[i]);
+ i += transcount;
+ }
+#if 0
+ for (i = 0; i < NumWords; i++) {
+ if (wctdm_vpm150m_getreg(wc, DspAddress + i) != pWordValues[i]) {
+ printk("Error in write. Address %x is not %x\n", DspAddress + i, pWordValues[i]);
+ }
+ }
+#endif
+ }
+ return;
+
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakHostDelay - Delay for a fixed time interval.
+ *
+ * FUNCTION
+ * This function delays for a fixed time interval before returning. The time
+ * interval is the Host Port Interface sampling period when polling a DSP for
+ * replies to command messages.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+void gpakHostDelay(void)
+{
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakLockAccess - Lock access to the specified DSP.
+ *
+ * FUNCTION
+ * This function aquires exclusive access to the specified DSP.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+void gpakLockAccess(unsigned short DspId)
+{
+ struct wctdm *wc;
+
+ wc = wc_find_iface(DspId);
+
+ if (wc) {
+ struct vpm150m *vpm = wc->vpm150m;
+
+ if (vpm)
+ down_interruptible(&vpm->sem);
+ }
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakUnlockAccess - Unlock access to the specified DSP.
+ *
+ * FUNCTION
+ * This function releases exclusive access to the specified DSP.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+void gpakUnlockAccess(unsigned short DspId)
+{
+ struct wctdm *wc;
+
+ wc = wc_find_iface(DspId);
+
+ if (wc) {
+ struct vpm150m *vpm = wc->vpm150m;
+
+ if (vpm)
+ up(&vpm->sem);
+ }
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadFile - Read a block of bytes from a G.PAK Download file.
+ *
+ * FUNCTION
+ * This function reads a contiguous block of bytes from a G.PAK Download file
+ * starting at the current file position.
+ *
+ * RETURNS
+ * The number of bytes read from the file.
+ * -1 indicates an error occurred.
+ * 0 indicates all bytes have been read (end of file)
+ *
+ */
+int gpakReadFile(
+ GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */
+ unsigned char *pBuffer, /* pointer to buffer for storing bytes */
+ unsigned int NumBytes /* number of bytes to read */
+ )
+{
+#ifdef VPM150M_SUPPORT
+ struct wctdm_firmware *fw = FileId;
+ unsigned int i, count;
+
+ if (!fw || !fw->fw)
+ return -1;
+
+ if (NumBytes > (fw->fw->size - fw->offset))
+ count = fw->fw->size - fw->offset;
+ else
+ count = NumBytes;
+
+ for (i = 0; i < count; i++)
+ pBuffer[i] = fw->fw->data[fw->offset + i];
+
+ fw->offset += count;
+
+ return count;
+#endif
+}
diff --git a/drivers/dahdi/wctdm24xxp/GpakCust.h b/drivers/dahdi/wctdm24xxp/GpakCust.h
new file mode 100644
index 0000000..418d6a7
--- /dev/null
+++ b/drivers/dahdi/wctdm24xxp/GpakCust.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2005, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakCust.h
+ *
+ * Description:
+ * This file contains host system dependent definitions and prototypes of
+ * functions to support generic G.PAK API functions. The file is used when
+ * integrating G.PAK API functions in a specific host processor environment.
+ *
+ * Note: This file may need to be modified by the G.PAK system integrator.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 06/15/05 - Initial release.
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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.
+ */
+
+#ifndef _GPAKCUST_H /* prevent multiple inclusion */
+#define _GPAKCUST_H
+
+#include "wctdm24xxp.h"
+#ifdef VPM150M_SUPPORT
+#include <linux/device.h>
+#include <linux/firmware.h>
+#endif
+#include "gpakenum.h"
+
+
+struct wctdm_firmware {
+ const struct firmware *fw;
+ unsigned int offset;
+};
+
+/* Host and DSP system dependent related definitions. */
+#define MAX_DSP_CORES 128 /* maximum number of DSP cores */
+//#define MAX_CONFS 1 /* maximum number of conferences */
+//#define MAX_PKT_CHANNELS 8 /* maximum number of packet channels */
+#define MAX_CHANNELS 32 /* maximum number of channels */
+#define MAX_WAIT_LOOPS 50 /* max number of wait delay loops */
+#define DSP_IFBLK_ADDRESS 0x0100 /* DSP address of I/F block pointer */
+#define DOWNLOAD_BLOCK_SIZE 512 /* download block size (DSP words) */
+//#define MAX_CIDPAYLOAD_BYTES 512 /* max size of a CID payload (octets) */
+typedef unsigned short DSP_WORD; /* 16 bit DSP word */
+typedef unsigned int DSP_ADDRESS; /* 32 bit DSP address */
+typedef struct wctdm_firmware* GPAK_FILE_ID; /* G.PAK Download file identifier */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadDspMemory - Read DSP memory.
+ *
+ * FUNCTION
+ * This function reads a contiguous block of words from DSP memory starting at
+ * the specified address.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+extern void gpakReadDspMemory(
+ unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ DSP_ADDRESS DspAddress, /* DSP's memory address of first word */
+ unsigned int NumWords, /* number of contiguous words to read */
+ DSP_WORD *pWordValues /* pointer to array of word values variable */
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakWriteDspMemory - Write DSP memory.
+ *
+ * FUNCTION
+ * This function writes a contiguous block of words to DSP memory starting at
+ * the specified address.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+extern void gpakWriteDspMemory(
+ unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ DSP_ADDRESS DspAddress, /* DSP's memory address of first word */
+ unsigned int NumWords, /* number of contiguous words to write */
+ DSP_WORD *pWordValues /* pointer to array of word values to write */
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakHostDelay - Delay for a fixed time interval.
+ *
+ * FUNCTION
+ * This function delays for a fixed time interval before returning. The time
+ * interval is the Host Port Interface sampling period when polling a DSP for
+ * replies to command messages.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+extern void gpakHostDelay(void);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakLockAccess - Lock access to the specified DSP.
+ *
+ * FUNCTION
+ * This function aquires exclusive access to the specified DSP.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+extern void gpakLockAccess(
+ unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakUnlockAccess - Unlock access to the specified DSP.
+ *
+ * FUNCTION
+ * This function releases exclusive access to the specified DSP.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+extern void gpakUnlockAccess(
+ unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadFile - Read a block of bytes from a G.PAK Download file.
+ *
+ * FUNCTION
+ * This function reads a contiguous block of bytes from a G.PAK Download file
+ * starting at the current file position.
+ *
+ * RETURNS
+ * The number of bytes read from the file.
+ * -1 indicates an error occurred.
+ * 0 indicates all bytes have been read (end of file)
+ *
+ */
+extern int gpakReadFile(
+ GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */
+ unsigned char *pBuffer, /* pointer to buffer for storing bytes */
+ unsigned int NumBytes /* number of bytes to read */
+ );
+
+
+unsigned char wctdm_vpm150m_getpage(struct wctdm *wc);
+
+int wctdm_vpm150m_setpage(struct wctdm *wc, unsigned short addr);
+
+int wctdm_vpm150m_setreg(struct wctdm *wc, unsigned int len, unsigned int addr, unsigned short *data);
+
+unsigned short wctdm_vpm150m_getreg(struct wctdm *wc, unsigned int len, unsigned int addr, unsigned short *data);
+
+char vpm150mtone_to_zaptone(GpakToneCodes_t tone);
+
+#endif /* prevent multiple inclusion */
+
+
diff --git a/drivers/dahdi/wctdm24xxp/GpakHpi.h b/drivers/dahdi/wctdm24xxp/GpakHpi.h
new file mode 100644
index 0000000..49e4ef9
--- /dev/null
+++ b/drivers/dahdi/wctdm24xxp/GpakHpi.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2001, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakHpi.h
+ *
+ * Description:
+ * This file contains common definitions related to the G.PAK interface
+ * between a host processor and a DSP processor via the Host Port Interface.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 10/17/01 - Initial release.
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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.
+ */
+
+#ifndef _GPAKHPI_H /* prevent multiple inclusion */
+#define _GPAKHPI_H
+
+
+/* Definition of G.PAK Command/Reply message type codes. */
+#define MSG_NULL_REPLY 0 /* Null Reply (unsupported Command) */
+#define MSG_SYS_CONFIG_RQST 1 /* System Configuration Request */
+#define MSG_SYS_CONFIG_REPLY 2 /* System Configuration Reply */
+#define MSG_READ_SYS_PARMS 3 /* Read System Parameters */
+#define MSG_READ_SYS_PARMS_REPLY 4 /* Read System Parameters Reply */
+#define MSG_WRITE_SYS_PARMS 5 /* Write System Parameters */
+#define MSG_WRITE_SYS_PARMS_REPLY 6 /* Write System Parameters Reply */
+#define MSG_CONFIGURE_PORTS 7 /* Configure Serial Ports */
+#define MSG_CONFIG_PORTS_REPLY 8 /* Configure Serial Ports Reply */
+#define MSG_CONFIGURE_CHANNEL 9 /* Configure Channel */
+#define MSG_CONFIG_CHAN_REPLY 10 /* Configure Channel Reply */
+#define MSG_TEAR_DOWN_CHANNEL 11 /* Tear Down Channel */
+#define MSG_TEAR_DOWN_REPLY 12 /* Tear Down Channel Reply */
+#define MSG_CHAN_STATUS_RQST 13 /* Channel Status Request */
+#define MSG_CHAN_STATUS_REPLY 14 /* Channel Status Reply */
+
+#define MSG_TEST_MODE 17 /* Configure/Perform Test Mode */
+#define MSG_TEST_REPLY 18 /* Configure/Perform Test Mode Reply */
+
+#define MSG_ALG_CONTROL 27 /* algorithm control */
+#define MSG_ALG_CONTROL_REPLY 28 /* algorithm control reply */
+#define MSG_GET_TXCID_ADDRESS 29 /* get tx cid buffer start address */
+#define MSG_GET_TXCID_ADDRESS_REPLY 30 /* get tx cid buffer start addr reply */
+
+#define MSG_PING 35 /* ping command */
+#define MSG_PING_REPLY 36 /* ping command reply */
+#define MSG_SERIAL_TXVAL 37 /* transmit serial fixed value */
+#define MSG_SERIAL_TXVAL_REPLY 38 /* transmit serial fixed value reply */
+#define MSG_TDM_LOOPBACK 39 /* tdm loopback control */
+#define MSG_TDM_LOOPBACK_REPLY 40 /* tdm loopback control reply */
+#define MSG_RESET_USAGE_STATS 41 /* reset cpu usage stats */
+#define MSG_RESET_USAGE_STATS_REPLY 42 /* reset cpu usage stats reply */
+
+#define MSG_RESET_FRAME_STATS 47 /* reset framing stats */
+#define MSG_RESET_FRAME_STATS_REPLY 48 /* reset framing stats reply */
+
+#define MSG_READ_DSP_MEMORY 49 /* read small section of DSP's memory */
+#define MSG_READ_DSP_MEMORY_REPLY 50 /* read memory reply */
+
+#define MSG_ACCESSGPIO 51
+#define MSG_ACCESSGPIO_REPLY 52
+#endif /* prevent multiple inclusion */
diff --git a/drivers/dahdi/wctdm24xxp/Kbuild b/drivers/dahdi/wctdm24xxp/Kbuild
new file mode 100644
index 0000000..6698a87
--- /dev/null
+++ b/drivers/dahdi/wctdm24xxp/Kbuild
@@ -0,0 +1,25 @@
+obj-m += wctdm24xxp.o
+
+FIRM_DIR := ../../firmware
+
+EXTRA_CFLAGS := -I$(src)/.. -Wno-undef
+
+ifeq ($(HOTPLUG_FIRMWARE),yes)
+ EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
+endif
+
+wctdm24xxp-objs := base.o GpakCust.o GpakApi.o ../voicebus.o
+
+ifneq ($(HOTPLUG_FIRMWARE),yes)
+wctdm24xxp-objs += $(FIRM_DIR)/zaptel-fw-vpmadt032.o
+endif
+
+$(obj)/$(FIRM_DIR)/zaptel-fw-vpmadt032.o: $(obj)/base.o
+ $(MAKE) -C $(obj)/$(FIRM_DIR) zaptel-fw-vpmadt032.o
+
+$(obj)/base.o: $(src)/GpakCust.h $(src)/wctdm24xxp.h
+$(obj)/base.o: $(src)/../zaptel.h
+
+$(obj)/GpakCust.o: $(src)/GpakCust.h
+
+$(obj)/GpakApi.o: $(src)/GpakApi.h
diff --git a/drivers/dahdi/wctdm24xxp/Makefile b/drivers/dahdi/wctdm24xxp/Makefile
new file mode 100644
index 0000000..9c4cd51
--- /dev/null
+++ b/drivers/dahdi/wctdm24xxp/Makefile
@@ -0,0 +1,27 @@
+ifneq ($(KBUILD_EXTMOD),)
+# We only get here on kernels 2.6.0-2.6.9 .
+# For newer kernels, Kbuild will be included directly by the kernel
+# build system.
+include $(src)/Kbuild
+
+else
+
+all: wctdm24xxp.o
+
+%.o: %.c
+ $(CC) $(KFLAGS) -o $@ -c $<
+
+base.o: ../zaptel.h GpakCust.h ../wctdm.h
+
+GpakCust.o: GpakCust.h
+
+../firmware/zaptel-fw-vpmadt032.o: base.o
+ $(MAKE) -C ../firmware zaptel-fw-vpmadt032.o
+
+wctdm24xxp.o: base.o GpakCust.o GpakApi.o ../firmware/zaptel-fw-vpmadt032.o
+ $(LD) -r -o $@ $^
+
+clean:
+ rm -f *.o
+
+endif
diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c
new file mode 100644
index 0000000..2a0f550
--- /dev/null
+++ b/drivers/dahdi/wctdm24xxp/base.c
@@ -0,0 +1,4063 @@
+/*
+ * Wildcard TDM2400P TDM FXS/FXO Interface Driver for Zapata Telephony interface
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Support for TDM800P and VPM150M by Matthew Fredrickson <creslin@digium.com>
+ *
+ * Copyright (C) 2005 - 2008 Digium, Inc.
+ * All rights reserved.
+ *
+ * Sections for QRV cards written by Jim Dixon <jim@lambdatel.com>
+ * Copyright (C) 2006, Jim Dixon and QRV Communications
+ * 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.
+ *
+ */
+/* For QRV DRI cards, gain is signed short, expressed in hundredths of
+db (in reference to 1v Peak @ 1000Hz) , as follows:
+
+Rx Gain: -11.99 to 15.52 db
+Tx Gain - No Pre-Emphasis: -35.99 to 12.00 db
+Tx Gain - W/Pre-Emphasis: -23.99 to 0.00 db
+*/
+
+#include <linux/version.h>
+#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/delay.h>
+#include <asm/semaphore.h>
+
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+#include "zaptel.h"
+#include "proslic.h"
+#include "wctdm.h"
+
+#include "wctdm24xxp.h"
+
+#ifdef VPM150M_SUPPORT
+#include "adt_lec.h"
+#endif
+
+#include "GpakCust.h"
+#include "GpakApi.h"
+
+/*
+ Experimental max loop current limit for the proslic
+ Loop current limit is from 20 mA to 41 mA in steps of 3
+ (according to datasheet)
+ So set the value below to:
+ 0x00 : 20mA (default)
+ 0x01 : 23mA
+ 0x02 : 26mA
+ 0x03 : 29mA
+ 0x04 : 32mA
+ 0x05 : 35mA
+ 0x06 : 37mA
+ 0x07 : 41mA
+*/
+static int loopcurrent = 20;
+
+static alpha indirect_regs[] =
+{
+{0,255,"DTMF_ROW_0_PEAK",0x55C2},
+{1,255,"DTMF_ROW_1_PEAK",0x51E6},
+{2,255,"DTMF_ROW2_PEAK",0x4B85},
+{3,255,"DTMF_ROW3_PEAK",0x4937},
+{4,255,"DTMF_COL1_PEAK",0x3333},
+{5,255,"DTMF_FWD_TWIST",0x0202},
+{6,255,"DTMF_RVS_TWIST",0x0202},
+{7,255,"DTMF_ROW_RATIO_TRES",0x0198},
+{8,255,"DTMF_COL_RATIO_TRES",0x0198},
+{9,255,"DTMF_ROW_2ND_ARM",0x0611},
+{10,255,"DTMF_COL_2ND_ARM",0x0202},
+{11,255,"DTMF_PWR_MIN_TRES",0x00E5},
+{12,255,"DTMF_OT_LIM_TRES",0x0A1C},
+{13,0,"OSC1_COEF",0x7B30},
+{14,1,"OSC1X",0x0063},
+{15,2,"OSC1Y",0x0000},
+{16,3,"OSC2_COEF",0x7870},
+{17,4,"OSC2X",0x007D},
+{18,5,"OSC2Y",0x0000},
+{19,6,"RING_V_OFF",0x0000},
+{20,7,"RING_OSC",0x7EF0},
+{21,8,"RING_X",0x0160},
+{22,9,"RING_Y",0x0000},
+{23,255,"PULSE_ENVEL",0x2000},
+{24,255,"PULSE_X",0x2000},
+{25,255,"PULSE_Y",0x0000},
+//{26,13,"RECV_DIGITAL_GAIN",0x4000}, // playback volume set lower
+{26,13,"RECV_DIGITAL_GAIN",0x2000}, // playback volume set lower
+{27,14,"XMIT_DIGITAL_GAIN",0x4000},
+//{27,14,"XMIT_DIGITAL_GAIN",0x2000},
+{28,15,"LOOP_CLOSE_TRES",0x1000},
+{29,16,"RING_TRIP_TRES",0x3600},
+{30,17,"COMMON_MIN_TRES",0x1000},
+{31,18,"COMMON_MAX_TRES",0x0200},
+{32,19,"PWR_ALARM_Q1Q2",0x07C0},
+{33,20,"PWR_ALARM_Q3Q4", 0x4C00 /* 0x2600 */},
+{34,21,"PWR_ALARM_Q5Q6",0x1B80},
+{35,22,"LOOP_CLOSURE_FILTER",0x8000},
+{36,23,"RING_TRIP_FILTER",0x0320},
+{37,24,"TERM_LP_POLE_Q1Q2",0x008C},
+{38,25,"TERM_LP_POLE_Q3Q4",0x0100},
+{39,26,"TERM_LP_POLE_Q5Q6",0x0010},
+{40,27,"CM_BIAS_RINGING",0x0C00},
+{41,64,"DCDC_MIN_V",0x0C00},
+{42,255,"DCDC_XTRA",0x1000},
+{43,66,"LOOP_CLOSE_TRES_LOW",0x1000},
+};
+
+#ifdef FANCY_ECHOCAN
+static char ectab[] = {
+0, 0, 0, 1, 2, 3, 4, 6, 8, 9, 11, 13, 16, 18, 20, 22, 24, 25, 27, 28, 29, 30, 31, 31, 32,
+32, 32, 32, 32, 32, 32, 32, 32, 32, 32 ,32 ,32, 32,
+32, 32, 32, 32, 32, 32, 32, 32, 32, 32 ,32 ,32, 32,
+32, 32, 32, 32, 32, 32, 32, 32, 32, 32 ,32 ,32, 32,
+31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0,
+};
+static int ectrans[4] = { 0, 1, 3, 2 };
+#define EC_SIZE (sizeof(ectab))
+#define EC_SIZE_Q (sizeof(ectab) / 4)
+#endif
+
+/* Undefine to enable Power alarm / Transistor debug -- note: do not
+ enable for normal operation! */
+/* #define PAQ_DEBUG */
+
+#define DEBUG_CARD (1 << 0)
+#define DEBUG_ECHOCAN (1 << 1)
+
+#include "fxo_modes.h"
+
+struct wctdm_desc {
+ char *name;
+ int flags;
+ int ports;
+};
+
+static struct wctdm_desc wctdm2400 = { "Wildcard TDM2400P", 0, 24 };
+static struct wctdm_desc wctdm800 = { "Wildcard TDM800P", 0, 8 };
+static struct wctdm_desc wctdm410 = { "Wildcard TDM410P", 0, 4 };
+static struct wctdm_desc wcaex2400 = { "Wildcard AEX2400", FLAG_EXPRESS, 24 };
+static struct wctdm_desc wcaex800 = { "Wildcard AEX800", FLAG_EXPRESS, 8 };
+static struct wctdm_desc wcaex410 = { "Wildcard AEX410", FLAG_EXPRESS, 4 };
+
+static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 };
+
+struct wctdm *ifaces[WC_MAX_IFACES];
+spinlock_t ifacelock = SPIN_LOCK_UNLOCKED;
+
+static void wctdm_release(struct wctdm *wc);
+
+static int fxovoltage = 0;
+static unsigned int battdebounce;
+static unsigned int battalarm;
+static unsigned int battthresh;
+static int debug = 0;
+static int robust = 0;
+static int lowpower = 0;
+static int boostringer = 0;
+static int fastringer = 0;
+static int _opermode = 0;
+static char *opermode = "FCC";
+static int fxshonormode = 0;
+static int alawoverride = 0;
+static int fxo_addrs[4] = { 0x00, 0x08, 0x04, 0x0c };
+static int fxotxgain = 0;
+static int fxorxgain = 0;
+static int fxstxgain = 0;
+static int fxsrxgain = 0;
+static int nativebridge = 0;
+static int ringdebounce = DEFAULT_RING_DEBOUNCE;
+static int fwringdetect = 0;
+static int latency = VOICEBUS_DEFAULT_LATENCY;
+#ifdef VPM_SUPPORT
+static int vpmsupport = 1;
+static int vpmdtmfsupport = 0;
+#define VPM_DEFAULT_DTMFTHRESHOLD 1250
+static int dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
+/*
+ * This parameter is used to adjust the NLP type used. The options are:
+ * 0 : None
+ * 1 : Mute
+ * 2 : Random Noise
+ * 3 : Hoth Noise
+ * 4 : Suppression NLP - In order to use this, you must set the vpmnlpmaxsupp parameter to
+ * some value in order to give the amount of dB to suppress to the suppressor
+ */
+static int vpmnlptype = 1;
+/* This is the threshold (in dB) for enabling and disabling of the NLP */
+static int vpmnlpthresh = 24;
+/* See vpmnlptype = 4 for more info */
+static int vpmnlpmaxsupp = 0;
+#endif
+
+static int wctdm_init_proslic(struct wctdm *wc, int card, int fast , int manual, int sane);
+
+static inline int CMD_BYTE(int card, int bit, int altcs)
+{
+ /* Let's add some trickery to make the TDM410 work */
+ if (altcs == 3) {
+ if (card == 2) {
+ card = 4;
+ altcs = 0;
+ } else if (card == 3) {
+ card = 5;
+ altcs = 2;
+ }
+ }
+
+ return (((((card) & 0x3) * 3 + (bit)) * 7) \
+ + ((card) >> 2) + (altcs) + ((altcs) ? -21 : 0));
+}
+
+/* sleep in user space until woken up. Equivilant of tsleep() in BSD */
+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 wctdm *wc, int card)
+{
+ int x;
+ for (x=0;x<USER_COMMANDS;x++) {
+ if (!wc->cmdq[card].cmds[x])
+ return x;
+ }
+ return -1;
+}
+
+#ifdef VPM_SUPPORT
+static inline void cmd_dequeue_vpm150m(struct wctdm *wc, volatile unsigned char *writechunk, int whichframe)
+{
+ unsigned long flags;
+ struct vpm150m_cmd *curcmd = NULL;
+ struct vpm150m *vpm150m = wc->vpm150m;
+ int x;
+ unsigned char leds = ~((wc->intcount / 1000) % 8) & 0x7;
+
+ /* Skip audio */
+ writechunk += 24;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+
+ if (test_bit(VPM150M_SPIRESET, &vpm150m->control) || test_bit(VPM150M_HPIRESET, &vpm150m->control)) {
+ if (debug & DEBUG_ECHOCAN)
+ printk("HW Resetting VPMADT032...\n");
+ for (x = 24; x < 28; x++) {
+ if (x == 24) {
+ if (test_and_clear_bit(VPM150M_SPIRESET, &vpm150m->control))
+ writechunk[CMD_BYTE(x, 0, 0)] = 0x08;
+ else if (test_and_clear_bit(VPM150M_HPIRESET, &vpm150m->control))
+ writechunk[CMD_BYTE(x, 0, 0)] = 0x0b;
+ } else
+ writechunk[CMD_BYTE(x, 0, 0)] = 0x00 | leds;
+ writechunk[CMD_BYTE(x, 1, 0)] = 0;
+ writechunk[CMD_BYTE(x, 2, 0)] = 0x00;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return;
+ }
+
+
+ /* Search for something waiting to transmit */
+ for (x = 0; x < VPM150M_MAX_COMMANDS; x++) {
+ if ((vpm150m->cmdq[x].desc & (__VPM150M_RD | __VPM150M_WR)) &&
+ !(vpm150m->cmdq[x].desc & (__VPM150M_FIN | __VPM150M_TX))) {
+ curcmd = &vpm150m->cmdq[x];
+ curcmd->txident = wc->txident;
+ curcmd->desc |= __VPM150M_TX;
+ break;
+ }
+ }
+ if (curcmd) {
+#if 0
+ printk("Found command txident = %d, desc = 0x%x, addr = 0x%x, data = 0x%x\n", curcmd->txident, curcmd->desc, curcmd->addr, curcmd->data);
+#endif
+ if (curcmd->desc & __VPM150M_RWPAGE) {
+ /* Set CTRL access to page*/
+ writechunk[CMD_BYTE(24, 0, 0)] = (0x8 << 4);
+ writechunk[CMD_BYTE(24, 1, 0)] = 0;
+ writechunk[CMD_BYTE(24, 2, 0)] = 0x20;
+
+ /* Do a page write */
+ if (curcmd->desc & __VPM150M_WR)
+ writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | 0x4) << 4);
+ else
+ writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | 0x4 | 0x1) << 4);
+ writechunk[CMD_BYTE(25, 1, 0)] = 0;
+ if (curcmd->desc & __VPM150M_WR)
+ writechunk[CMD_BYTE(25, 2, 0)] = curcmd->data[0] & 0xf;
+ else
+ writechunk[CMD_BYTE(25, 2, 0)] = 0;
+
+ /* Clear XADD */
+ writechunk[CMD_BYTE(26, 0, 0)] = (0x8 << 4);
+ writechunk[CMD_BYTE(26, 1, 0)] = 0;
+ writechunk[CMD_BYTE(26, 2, 0)] = 0;
+
+ /* Fill in to buffer to size */
+ writechunk[CMD_BYTE(27, 0, 0)] = 0;
+ writechunk[CMD_BYTE(27, 1, 0)] = 0;
+ writechunk[CMD_BYTE(27, 2, 0)] = 0;
+
+ } else {
+ /* Set address */
+ writechunk[CMD_BYTE(24, 0, 0)] = ((0x8 | 0x4) << 4);
+ writechunk[CMD_BYTE(24, 1, 0)] = (curcmd->addr >> 8) & 0xff;
+ writechunk[CMD_BYTE(24, 2, 0)] = curcmd->addr & 0xff;
+
+ /* Send/Get our data */
+ if (curcmd->desc & __VPM150M_WR) {
+ if (curcmd->datalen > 1)
+ writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | (0x1 << 1)) << 4);
+ else
+ writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | (0x3 << 1)) << 4);
+ } else
+ if (curcmd->datalen > 1)
+ writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | (0x1 << 1) | 0x1) << 4);
+ else
+ writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | (0x3 << 1) | 0x1) << 4);
+ writechunk[CMD_BYTE(25, 1, 0)] = (curcmd->data[0] >> 8) & 0xff;
+ writechunk[CMD_BYTE(25, 2, 0)] = curcmd->data[0] & 0xff;
+
+ if (curcmd->datalen > 1) {
+ if (curcmd->desc & __VPM150M_WR)
+ writechunk[CMD_BYTE(26, 0, 0)] = ((0x8 | (0x1 << 1)) << 4);
+ else
+ writechunk[CMD_BYTE(26, 0, 0)] = ((0x8 | (0x1 << 1) | 0x1) << 4);
+ writechunk[CMD_BYTE(26, 1, 0)] = (curcmd->data[1] >> 8) & 0xff;
+ writechunk[CMD_BYTE(26, 2, 0)] = curcmd->data[1] & 0xff;
+ } else {
+ /* Fill in the rest */
+ writechunk[CMD_BYTE(26, 0, 0)] = 0;
+ writechunk[CMD_BYTE(26, 1, 0)] = 0;
+ writechunk[CMD_BYTE(26, 2, 0)] = 0;
+ }
+
+ if (curcmd->datalen > 2) {
+ if (curcmd->desc & __VPM150M_WR)
+ writechunk[CMD_BYTE(27, 0, 0)] = ((0x8 | (0x1 << 1)) << 4);
+ else
+ writechunk[CMD_BYTE(27, 0, 0)] = ((0x8 | (0x1 << 1) | 0x1) << 4);
+ writechunk[CMD_BYTE(27, 1, 0)] = (curcmd->data[2] >> 8) & 0xff;
+ writechunk[CMD_BYTE(27, 2, 0)] = curcmd->data[2] & 0xff;
+ } else {
+ /* Fill in the rest */
+ writechunk[CMD_BYTE(27, 0, 0)] = 0;
+ writechunk[CMD_BYTE(27, 1, 0)] = 0;
+ writechunk[CMD_BYTE(27, 2, 0)] = 0;
+ }
+
+
+ }
+ } else if (test_and_clear_bit(VPM150M_SWRESET, &vpm150m->control)) {
+ printk("Booting VPMADT032\n");
+ for (x = 24; x < 28; x++) {
+ if (x == 24)
+ writechunk[CMD_BYTE(x, 0, 0)] = (0x8 << 4);
+ else
+ writechunk[CMD_BYTE(x, 0, 0)] = 0x00;
+ writechunk[CMD_BYTE(x, 1, 0)] = 0;
+ if (x == 24)
+ writechunk[CMD_BYTE(x, 2, 0)] = 0x01;
+ else
+ writechunk[CMD_BYTE(x, 2, 0)] = 0x00;
+ }
+ } else {
+ for (x = 24; x < 28; x++) {
+ writechunk[CMD_BYTE(x, 0, 0)] = 0x00;
+ writechunk[CMD_BYTE(x, 1, 0)] = 0x00;
+ writechunk[CMD_BYTE(x, 2, 0)] = 0x00;
+ }
+ }
+
+#ifdef VPM150M_SUPPORT
+ /* Add our leds in */
+ for (x = 24; x < 28; x++)
+ writechunk[CMD_BYTE(x, 0, 0)] |= leds;
+
+ /* Now let's figure out if we need to check for DTMF */
+ if (test_bit(VPM150M_ACTIVE, &vpm150m->control) && !whichframe && !(wc->intcount % 100))
+ queue_work(vpm150m->wq, &vpm150m->work);
+#endif
+
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+#endif /* VPM_SUPPORT */
+
+static inline void cmd_dequeue(struct wctdm *wc, volatile unsigned char *writechunk, int card, int pos)
+{
+ unsigned long flags;
+ unsigned int curcmd=0;
+ int x;
+ int subaddr = card & 0x3;
+#ifdef FANCY_ECHOCAN
+ int ecval;
+ ecval = wc->echocanpos;
+ ecval += EC_SIZE_Q * ectrans[(card & 0x3)];
+ ecval = ecval % EC_SIZE;
+#endif
+
+ /* if a QRV card, map it to its first channel */
+ if ((wc->modtype[card] == MOD_TYPE_QRV) && (card & 3))
+ {
+ return;
+ }
+ if (wc->altcs[card])
+ subaddr = 0;
+
+
+
+ /* Skip audio */
+ writechunk += 24;
+ spin_lock_irqsave(&wc->reglock, flags);
+ /* Search for something waiting to transmit */
+ if (pos) {
+ for (x=0;x<MAX_COMMANDS;x++) {
+ if ((wc->cmdq[card].cmds[x] & (__CMD_RD | __CMD_WR)) &&
+ !(wc->cmdq[card].cmds[x] & (__CMD_TX | __CMD_FIN))) {
+ curcmd = wc->cmdq[card].cmds[x];
+#if 0
+ printk("Transmitting command '%08x' in slot %d\n", wc->cmdq[card].cmds[x], wc->txident);
+#endif
+ wc->cmdq[card].cmds[x] |= (wc->txident << 24) | __CMD_TX;
+ break;
+ }
+ }
+ }
+ if (!curcmd) {
+ /* If nothing else, use filler */
+ if (wc->modtype[card] == MOD_TYPE_FXS)
+ curcmd = CMD_RD(64);
+ else if (wc->modtype[card] == MOD_TYPE_FXO)
+ curcmd = CMD_RD(12);
+ else if (wc->modtype[card] == MOD_TYPE_QRV)
+ curcmd = CMD_RD(3);
+ else if (wc->modtype[card] == MOD_TYPE_VPM) {
+#ifdef FANCY_ECHOCAN
+ if (wc->blinktimer >= 0xf) {
+ curcmd = CMD_WR(0x1ab, 0x0f);
+ } else if (wc->blinktimer == (ectab[ecval] >> 1)) {
+ curcmd = CMD_WR(0x1ab, 0x00);
+ } else
+#endif
+ curcmd = CMD_RD(0x1a0);
+ }
+ }
+ if (wc->modtype[card] == MOD_TYPE_FXS) {
+ writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = (1 << (subaddr));
+ if (curcmd & __CMD_WR)
+ writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0x7f;
+ else
+ writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x80 | ((curcmd >> 8) & 0x7f);
+ writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
+ } else if (wc->modtype[card] == MOD_TYPE_FXO) {
+ if (curcmd & __CMD_WR)
+ writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x20 | fxo_addrs[subaddr];
+ else
+ writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x60 | fxo_addrs[subaddr];
+ writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0xff;
+ writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
+ } else if (wc->modtype[card] == MOD_TYPE_FXSINIT) {
+ /* Special case, we initialize the FXS's into the three-byte command mode then
+ switch to the regular mode. To send it into thee byte mode, treat the path as
+ 6 two-byte commands and in the last one we initialize register 0 to 0x80. All modules
+ read this as the command to switch to daisy chain mode and we're done. */
+ writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00;
+ writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00;
+ if ((card & 0x1) == 0x1)
+ writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x80;
+ else
+ writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00;
+#ifdef VPM_SUPPORT
+ } else if (wc->modtype[card] == MOD_TYPE_VPM) {
+ if (curcmd & __CMD_WR)
+ writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = ((card & 0x3) << 4) | 0xc | ((curcmd >> 16) & 0x1);
+ else
+ writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = ((card & 0x3) << 4) | 0xa | ((curcmd >> 16) & 0x1);
+ writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0xff;
+ writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
+ } else if (wc->modtype[card] == MOD_TYPE_VPM150M) {
+#endif
+ } else if (wc->modtype[card] == MOD_TYPE_QRV) {
+
+ writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00;
+ if (!curcmd)
+ {
+ writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00;
+ writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00;
+ }
+ else
+ {
+ if (curcmd & __CMD_WR)
+ writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x40 | ((curcmd >> 8) & 0x3f);
+ else
+ writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0xc0 | ((curcmd >> 8) & 0x3f);
+ writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
+ }
+ } else if (wc->modtype[card] == MOD_TYPE_NONE) {
+ writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00;
+ writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00;
+ writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00;
+ }
+#if 0
+ /* XXX */
+ if (cmddesc < 40)
+ printk("Pass %d, card = %d (modtype=%d), pos = %d, CMD_BYTES = %d,%d,%d, (%02x,%02x,%02x) curcmd = %08x\n", cmddesc, card, wc->modtype[card], pos, CMD_BYTE(card, 0), CMD_BYTE(card, 1), CMD_BYTE(card, 2), writechunk[CMD_BYTE(card, 0)], writechunk[CMD_BYTE(card, 1)], writechunk[CMD_BYTE(card, 2)], curcmd);
+#endif
+ spin_unlock_irqrestore(&wc->reglock, flags);
+#if 0
+ /* XXX */
+ cmddesc++;
+#endif
+}
+
+#ifdef VPM_SUPPORT
+static inline void cmd_decifer_vpm150m(struct wctdm *wc, volatile unsigned char *readchunk)
+{
+ unsigned long flags;
+ unsigned char ident;
+ int x, i;
+
+ /* Skip audio */
+ readchunk += 24;
+ spin_lock_irqsave(&wc->reglock, flags);
+ /* Search for any pending results */
+ for (x = 0; x < VPM150M_MAX_COMMANDS; x++) {
+ if ((wc->vpm150m->cmdq[x].desc & (__VPM150M_RD | __VPM150M_WR)) &&
+ (wc->vpm150m->cmdq[x].desc & (__VPM150M_TX)) &&
+ !(wc->vpm150m->cmdq[x].desc & (__VPM150M_FIN))) {
+ ident = wc->vpm150m->cmdq[x].txident;
+ if (ident == wc->rxident) {
+ /* Store result */
+ for (i = 0; i < wc->vpm150m->cmdq[x].datalen; i++) {
+ wc->vpm150m->cmdq[x].data[i] = (0xff & readchunk[CMD_BYTE((25 + i), 1, 0)]) << 8;
+ wc->vpm150m->cmdq[x].data[i] |= readchunk[CMD_BYTE((25 + i), 2, 0)];
+ }
+ if (wc->vpm150m->cmdq[x].desc & __VPM150M_WR) {
+ /* Go ahead and clear out writes since they need no acknowledgement */
+ wc->vpm150m->cmdq[x].desc = 0;
+ } else
+ wc->vpm150m->cmdq[x].desc |= __VPM150M_FIN;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+#endif /* VPM_SUPPORT */
+
+static inline void cmd_decifer(struct wctdm *wc, volatile unsigned char *readchunk, int card)
+{
+ unsigned long flags;
+ unsigned char ident;
+ int x;
+
+ /* if a QRV card, map it to its first channel */
+ if ((wc->modtype[card] == MOD_TYPE_QRV) && (card & 3))
+ {
+ return;
+ }
+ /* Skip audio */
+ readchunk += 24;
+ spin_lock_irqsave(&wc->reglock, flags);
+ /* Search for any pending results */
+ for (x=0;x<MAX_COMMANDS;x++) {
+ if ((wc->cmdq[card].cmds[x] & (__CMD_RD | __CMD_WR)) &&
+ (wc->cmdq[card].cmds[x] & (__CMD_TX)) &&
+ !(wc->cmdq[card].cmds[x] & (__CMD_FIN))) {
+ ident = (wc->cmdq[card].cmds[x] >> 24) & 0xff;
+ if (ident == wc->rxident) {
+ /* Store result */
+ wc->cmdq[card].cmds[x] |= readchunk[CMD_BYTE(card, 2, wc->altcs[card])];
+ wc->cmdq[card].cmds[x] |= __CMD_FIN;
+ if (wc->cmdq[card].cmds[x] & __CMD_WR) {
+ /* Go ahead and clear out writes since they need no acknowledgement */
+ wc->cmdq[card].cmds[x] = 0x00000000;
+ } else if (x >= USER_COMMANDS) {
+ /* Clear out ISR reads */
+ wc->cmdq[card].isrshadow[x - USER_COMMANDS] = wc->cmdq[card].cmds[x] & 0xff;
+ wc->cmdq[card].cmds[x] = 0x00000000;
+ }
+ break;
+ }
+ }
+ }
+#if 0
+ /* XXX */
+ if (!pos && (cmddesc < 256))
+ printk("Card %d: Command '%08x' => %02x\n",card, wc->cmdq[card].lasttx[pos], wc->cmdq[card].lastrd[pos]);
+#endif
+ spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline void cmd_checkisr(struct wctdm *wc, int card)
+{
+ if (!wc->cmdq[card].cmds[USER_COMMANDS + 0]) {
+ if (wc->sethook[card]) {
+ wc->cmdq[card].cmds[USER_COMMANDS + 0] = wc->sethook[card];
+ wc->sethook[card] = 0;
+ } else if (wc->modtype[card] == MOD_TYPE_FXS) {
+ wc->cmdq[card].cmds[USER_COMMANDS + 0] = CMD_RD(68); /* Hook state */
+ } else if (wc->modtype[card] == MOD_TYPE_FXO) {
+ wc->cmdq[card].cmds[USER_COMMANDS + 0] = CMD_RD(5); /* Hook/Ring state */
+ } else if (wc->modtype[card] == MOD_TYPE_QRV) {
+ wc->cmdq[card & 0xfc].cmds[USER_COMMANDS + 0] = CMD_RD(3); /* COR/CTCSS state */
+#ifdef VPM_SUPPORT
+ } else if (wc->modtype[card] == MOD_TYPE_VPM) {
+ wc->cmdq[card].cmds[USER_COMMANDS + 0] = CMD_RD(0xb9); /* DTMF interrupt */
+#endif
+ }
+ }
+ if (!wc->cmdq[card].cmds[USER_COMMANDS + 1]) {
+ if (wc->modtype[card] == MOD_TYPE_FXS) {
+#ifdef PAQ_DEBUG
+ wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(19); /* Transistor interrupts */
+#else
+ wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(64); /* Battery mode */
+#endif
+ } else if (wc->modtype[card] == MOD_TYPE_FXO) {
+ wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(29); /* Battery */
+ } else if (wc->modtype[card] == MOD_TYPE_QRV) {
+ wc->cmdq[card & 0xfc].cmds[USER_COMMANDS + 1] = CMD_RD(3); /* Battery */
+#ifdef VPM_SUPPORT
+ } else if (wc->modtype[card] == MOD_TYPE_VPM) {
+ wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(0xbd); /* DTMF interrupt */
+#endif
+ }
+ }
+}
+
+static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char *writechunk)
+{
+ int x,y;
+
+ /* Calculate Transmission */
+ if (likely(wc->initialized)) {
+ zt_transmit(&wc->span);
+ }
+
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ /* Send a sample, as a 32-bit word */
+ for (y=0;y < wc->cards;y++) {
+ if (!x) {
+ cmd_checkisr(wc, y);
+ }
+
+ if (likely(wc->initialized)) {
+ if (y < wc->type)
+ writechunk[y] = wc->chans[y].writechunk[x];
+ }
+ cmd_dequeue(wc, writechunk, y, x);
+ }
+#ifdef VPM_SUPPORT
+ if (!x)
+ wc->blinktimer++;
+ if (wc->vpm) {
+ for (y=24;y<28;y++) {
+ if (!x) {
+ cmd_checkisr(wc, y);
+ }
+ cmd_dequeue(wc, writechunk, y, x);
+ }
+#ifdef FANCY_ECHOCAN
+ if (wc->vpm && wc->blinktimer >= 0xf) {
+ wc->blinktimer = -1;
+ wc->echocanpos++;
+ }
+#endif
+ } else if (wc->vpm150m) {
+ cmd_dequeue_vpm150m(wc, writechunk, x);
+ }
+#endif
+ if (x < ZT_CHUNKSIZE - 1) {
+ writechunk[EFRAME_SIZE] = wc->ctlreg;
+ writechunk[EFRAME_SIZE + 1] = wc->txident++;
+#if 1
+ if ((wc->type == 4) && ((wc->ctlreg & 0x10) || (wc->modtype[NUM_CARDS] == MOD_TYPE_NONE))) {
+ writechunk[EFRAME_SIZE + 2] = 0;
+ for (y = 0; y < 4; y++) {
+ if (wc->modtype[y] == MOD_TYPE_NONE)
+ writechunk[EFRAME_SIZE + 2] |= (1 << y);
+ }
+ } else
+ writechunk[EFRAME_SIZE + 2] = 0xf;
+#endif
+ }
+ writechunk += (EFRAME_SIZE + EFRAME_GAP);
+ }
+}
+
+static inline int wctdm_setreg_full(struct wctdm *wc, int card, int addr, int val, int inisr)
+{
+ unsigned long flags;
+ int hit=0;
+ int ret;
+
+ /* if a QRV card, use only its first channel */
+ if (wc->modtype[card] == MOD_TYPE_QRV)
+ {
+ if (card & 3) return(0);
+ }
+ do {
+ spin_lock_irqsave(&wc->reglock, flags);
+ hit = empty_slot(wc, card);
+ if (hit > -1) {
+ wc->cmdq[card].cmds[hit] = CMD_WR(addr, val);
+ }
+ 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 wctdm_setreg_intr(struct wctdm *wc, int card, int addr, int val)
+{
+ return wctdm_setreg_full(wc, card, addr, val, 1);
+}
+static inline int wctdm_setreg(struct wctdm *wc, int card, int addr, int val)
+{
+ return wctdm_setreg_full(wc, card, addr, val, 0);
+}
+
+static inline int wctdm_getreg(struct wctdm *wc, int card, int addr)
+{
+ unsigned long flags;
+ int hit;
+ int ret=0;
+
+ /* if a QRV card, use only its first channel */
+ if (wc->modtype[card] == MOD_TYPE_QRV)
+ {
+ if (card & 3) return(0);
+ }
+ do {
+ spin_lock_irqsave(&wc->reglock, flags);
+ hit = empty_slot(wc, card);
+ if (hit > -1) {
+ wc->cmdq[card].cmds[hit] = CMD_RD(addr);
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (hit < 0) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ } while (hit < 0);
+ do {
+ spin_lock_irqsave(&wc->reglock, flags);
+ if (wc->cmdq[card].cmds[hit] & __CMD_FIN) {
+ ret = wc->cmdq[card].cmds[hit] & 0xff;
+ wc->cmdq[card].cmds[hit] = 0x00000000;
+ hit = -1;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (hit > -1) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ } while (hit > -1);
+ return ret;
+}
+
+#ifdef VPM_SUPPORT
+static inline unsigned char wctdm_vpm_in(struct wctdm *wc, int unit, const unsigned int addr)
+{
+ return wctdm_getreg(wc, unit + NUM_CARDS, addr);
+}
+
+static inline void wctdm_vpm_out(struct wctdm *wc, int unit, const unsigned int addr, const unsigned char val)
+{
+ wctdm_setreg(wc, unit + NUM_CARDS, addr, val);
+}
+
+static inline void cmd_vpm150m_retransmit(struct wctdm *wc)
+{
+ unsigned long flags;
+ int x;
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ for (x = 0; x < VPM150M_MAX_COMMANDS; x++) {
+ if (!(wc->vpm150m->cmdq[x].desc & __VPM150M_FIN)) {
+ //printk("Retransmit!\n");
+ wc->vpm150m->cmdq[x].desc &= ~(__VPM150M_TX);
+ }
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+}
+#endif
+
+static inline void cmd_retransmit(struct wctdm *wc)
+{
+ int x,y;
+ unsigned long flags;
+ /* Force retransmissions */
+ spin_lock_irqsave(&wc->reglock, flags);
+ for (x=0;x<MAX_COMMANDS;x++) {
+ for (y=0;y<wc->cards;y++) {
+ if (!(wc->cmdq[y].cmds[x] & __CMD_FIN))
+ wc->cmdq[y].cmds[x] &= ~(__CMD_TX | (0xff << 24));
+ }
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+#ifdef VPM_SUPPORT
+ if (wc->vpm150m)
+ cmd_vpm150m_retransmit(wc);
+#endif
+}
+
+static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char *readchunk)
+{
+ int x,y;
+ unsigned char expected;
+
+ BUG_ON(NULL == readchunk);
+
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ 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);
+ }
+ }
+ for (y=0;y < wc->cards;y++) {
+ if (likely(wc->initialized)) {
+ if (y < wc->type) {
+ wc->chans[y].readchunk[x] = readchunk[y];
+ }
+ }
+ cmd_decifer(wc, readchunk, y);
+ }
+#ifdef VPM_SUPPORT
+ if (wc->vpm) {
+ for (y=NUM_CARDS;y < NUM_CARDS + NUM_EC; y++)
+ cmd_decifer(wc, readchunk, y);
+ } else if (wc->vpm150m)
+ cmd_decifer_vpm150m(wc, readchunk);
+#endif
+
+ readchunk += (EFRAME_SIZE + EFRAME_GAP);
+ }
+ /* XXX We're wasting 8 taps. We should get closer :( */
+ if (likely(wc->initialized)) {
+ for (x=0;x<wc->type;x++) {
+ if (wc->cardflag & (1 << x))
+ zt_ec_chunk(&wc->chans[x], wc->chans[x].readchunk, wc->chans[x].writechunk);
+ }
+ zt_receive(&wc->span);
+ }
+ /* Wake up anyone sleeping to read/write a new register */
+ wake_up_interruptible(&wc->regq);
+}
+
+static int wait_access(struct wctdm *wc, int card)
+{
+ unsigned char data=0;
+ long origjiffies;
+ int count = 0;
+
+ #define MAX 10 /* attempts */
+
+
+ origjiffies = jiffies;
+ /* Wait for indirect access */
+ while (count++ < MAX)
+ {
+ data = wctdm_getreg(wc, card, I_STATUS);
+
+ if (!data)
+ return 0;
+
+ }
+
+ if(count > (MAX-1)) printk(" ##### Loop error (%02x) #####\n", data);
+
+ return 0;
+}
+
+static unsigned char translate_3215(unsigned char address)
+{
+ int x;
+ for (x=0;x<sizeof(indirect_regs)/sizeof(indirect_regs[0]);x++) {
+ if (indirect_regs[x].address == address) {
+ address = indirect_regs[x].altaddr;
+ break;
+ }
+ }
+ return address;
+}
+
+static int wctdm_proslic_setreg_indirect(struct wctdm *wc, int card, unsigned char address, unsigned short data)
+{
+ int res = -1;
+ /* Translate 3215 addresses */
+ if (wc->flags[card] & FLAG_3215) {
+ address = translate_3215(address);
+ if (address == 255)
+ return 0;
+ }
+ if(!wait_access(wc, card)) {
+ wctdm_setreg(wc, card, IDA_LO,(unsigned char)(data & 0xFF));
+ wctdm_setreg(wc, card, IDA_HI,(unsigned char)((data & 0xFF00)>>8));
+ wctdm_setreg(wc, card, IAA,address);
+ res = 0;
+ };
+ return res;
+}
+
+static int wctdm_proslic_getreg_indirect(struct wctdm *wc, int card, unsigned char address)
+{
+ int res = -1;
+ char *p=NULL;
+ /* Translate 3215 addresses */
+ if (wc->flags[card] & FLAG_3215) {
+ address = translate_3215(address);
+ if (address == 255)
+ return 0;
+ }
+ if (!wait_access(wc, card)) {
+ wctdm_setreg(wc, card, IAA, address);
+ if (!wait_access(wc, card)) {
+ unsigned char data1, data2;
+ data1 = wctdm_getreg(wc, card, IDA_LO);
+ data2 = wctdm_getreg(wc, card, IDA_HI);
+ res = data1 | (data2 << 8);
+ } else
+ p = "Failed to wait inside\n";
+ } else
+ p = "failed to wait\n";
+ if (p)
+ printk(p);
+ return res;
+}
+
+static int wctdm_proslic_init_indirect_regs(struct wctdm *wc, int card)
+{
+ unsigned char i;
+
+ for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++)
+ {
+ if(wctdm_proslic_setreg_indirect(wc, card, indirect_regs[i].address,indirect_regs[i].initial))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int wctdm_proslic_verify_indirect_regs(struct wctdm *wc, int card)
+{
+ int passed = 1;
+ unsigned short i, initial;
+ int j;
+
+ for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++)
+ {
+ if((j = wctdm_proslic_getreg_indirect(wc, card, (unsigned char) indirect_regs[i].address)) < 0) {
+ printk("Failed to read indirect register %d\n", i);
+ return -1;
+ }
+ initial= indirect_regs[i].initial;
+
+ if ( j != initial && (!(wc->flags[card] & FLAG_3215) || (indirect_regs[i].altaddr != 255)))
+ {
+ printk("!!!!!!! %s iREG %X = %X should be %X\n",
+ indirect_regs[i].name,indirect_regs[i].address,j,initial );
+ passed = 0;
+ }
+ }
+
+ if (passed) {
+ if (debug & DEBUG_CARD)
+ printk("Init Indirect Registers completed successfully.\n");
+ } else {
+ printk(" !!!!! Init Indirect Registers UNSUCCESSFULLY.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
+{
+ int res;
+#ifdef PAQ_DEBUG
+ res = wc->cmdq[card].isrshadow[1];
+ res &= ~0x3;
+ if (res) {
+ wc->cmdq[card].isrshadow[1]=0;
+ wc->mods[card].fxs.palarms++;
+ if (wc->mods[card].fxs.palarms < MAX_ALARMS) {
+ printk("Power alarm (%02x) on module %d, resetting!\n", res, card + 1);
+ if (wc->mods[card].fxs.lasttxhook == 4)
+ wc->mods[card].fxs.lasttxhook = 0x11;
+ wc->sethook[card] = CMD_WR(19, res);
+#if 0
+ wc->sethook[card] = CMD_WR(64, wc->mods[card].fxs.lasttxhook);
+#endif
+
+ /* wctdm_setreg_intr(wc, card, 64, wc->mods[card].fxs.lasttxhook); */
+ /* Update shadow register to avoid extra power alarms until next read */
+ wc->cmdq[card].isrshadow[1] = 0;
+ } else {
+ if (wc->mods[card].fxs.palarms == MAX_ALARMS)
+ printk("Too many power alarms on card %d, NOT resetting!\n", card + 1);
+ }
+ }
+#else
+ res = wc->cmdq[card].isrshadow[1];
+ /* This makes sure the lasthook was put in reg 64 the linefeed reg */
+ if (((res & 0x0f) | 0x10) == wc->mods[card].fxs.lasttxhook)
+ wc->mods[card].fxs.lasttxhook &= 0x0f;
+
+ res = !res && /* reg 64 has to be zero at last isr read */
+ !(wc->mods[card].fxs.lasttxhook & 0x10 ) && /* not a transition */
+ wc->mods[card].fxs.lasttxhook; /* not an intended zero */
+
+ if (res) {
+ wc->mods[card].fxs.palarms++;
+ if (wc->mods[card].fxs.palarms < MAX_ALARMS) {
+ printk("Power alarm on module %d, resetting!\n", card + 1);
+ if (wc->mods[card].fxs.lasttxhook == 4)
+ wc->mods[card].fxs.lasttxhook = 0x11;
+ wc->mods[card].fxs.lasttxhook |= 0x10;
+ wc->sethook[card] = CMD_WR(64, wc->mods[card].fxs.lasttxhook);
+
+ /* wctdm_setreg_intr(wc, card, 64, wc->mods[card].fxs.lasttxhook); */
+ /* Update shadow register to avoid extra power alarms until next read */
+ wc->cmdq[card].isrshadow[1] = wc->mods[card].fxs.lasttxhook;
+ } else {
+ if (wc->mods[card].fxs.palarms == MAX_ALARMS)
+ printk("Too many power alarms on card %d, NOT resetting!\n", card + 1);
+ }
+ }
+#endif
+}
+
+static inline void wctdm_qrvdri_check_hook(struct wctdm *wc, int card)
+{
+ signed char b,b1;
+ int qrvcard = card & 0xfc;
+
+
+ if (wc->qrvdebtime[card] >= 2) wc->qrvdebtime[card]--;
+ b = wc->cmdq[qrvcard].isrshadow[0]; /* Hook/Ring state */
+ b &= 0xcc; /* use bits 3-4 and 6-7 only */
+
+ if (wc->radmode[qrvcard] & RADMODE_IGNORECOR) b &= ~4;
+ else if (!(wc->radmode[qrvcard] & RADMODE_INVERTCOR)) b ^= 4;
+ if (wc->radmode[qrvcard + 1] | RADMODE_IGNORECOR) b &= ~0x40;
+ else if (!(wc->radmode[qrvcard + 1] | RADMODE_INVERTCOR)) b ^= 0x40;
+
+ if ((wc->radmode[qrvcard] & RADMODE_IGNORECT) ||
+ (!(wc->radmode[qrvcard] & RADMODE_EXTTONE))) b &= ~8;
+ else if (!(wc->radmode[qrvcard] & RADMODE_EXTINVERT)) b ^= 8;
+ if ((wc->radmode[qrvcard + 1] & RADMODE_IGNORECT) ||
+ (!(wc->radmode[qrvcard + 1] & RADMODE_EXTTONE))) b &= ~0x80;
+ else if (!(wc->radmode[qrvcard + 1] & RADMODE_EXTINVERT)) b ^= 0x80;
+ /* now b & MASK should be zero, if its active */
+ /* check for change in chan 0 */
+ if ((!(b & 0xc)) != wc->qrvhook[qrvcard + 2])
+ {
+ wc->qrvdebtime[qrvcard] = wc->debouncetime[qrvcard];
+ wc->qrvhook[qrvcard + 2] = !(b & 0xc);
+ }
+ /* if timed-out and ready */
+ if (wc->qrvdebtime[qrvcard] == 1)
+ {
+ b1 = wc->qrvhook[qrvcard + 2];
+if (debug) printk("QRV channel %d rx state changed to %d\n",qrvcard,wc->qrvhook[qrvcard + 2]);
+ zt_hooksig(&wc->chans[qrvcard],
+ (b1) ? ZT_RXSIG_OFFHOOK : ZT_RXSIG_ONHOOK);
+ wc->qrvdebtime[card] = 0;
+ }
+ /* check for change in chan 1 */
+ if ((!(b & 0xc0)) != wc->qrvhook[qrvcard + 3])
+ {
+ wc->qrvdebtime[qrvcard + 1] = QRV_DEBOUNCETIME;
+ wc->qrvhook[qrvcard + 3] = !(b & 0xc0);
+ }
+ if (wc->qrvdebtime[qrvcard + 1] == 1)
+ {
+ b1 = wc->qrvhook[qrvcard + 3];
+if (debug) printk("QRV channel %d rx state changed to %d\n",qrvcard + 1,wc->qrvhook[qrvcard + 3]);
+ zt_hooksig(&wc->chans[qrvcard + 1],
+ (b1) ? ZT_RXSIG_OFFHOOK : ZT_RXSIG_ONHOOK);
+ wc->qrvdebtime[card] = 0;
+ }
+ return;
+}
+
+static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card)
+{
+#define MS_PER_CHECK_HOOK 1
+
+ unsigned char res;
+ signed char b;
+ struct fxo *fxo = &wc->mods[card].fxo;
+
+ /* Try to track issues that plague slot one FXO's */
+ b = wc->cmdq[card].isrshadow[0]; /* Hook/Ring state */
+ b &= 0x9b;
+ if (fxo->offhook) {
+ if (b != 0x9)
+ wctdm_setreg_intr(wc, card, 5, 0x9);
+ } else {
+ if (b != 0x8)
+ wctdm_setreg_intr(wc, card, 5, 0x8);
+ }
+ if (!fxo->offhook) {
+ if (fwringdetect) {
+ res = wc->cmdq[card].isrshadow[0] & 0x60;
+ if (fxo->ringdebounce--) {
+ if (res && (res != fxo->lastrdtx) && (fxo->battery == 1)) {
+ if (!fxo->wasringing) {
+ fxo->wasringing = 1;
+ if (debug)
+ printk("RING on %d/%d!\n", wc->span.spanno, card + 1);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
+ }
+ fxo->lastrdtx = res;
+ fxo->ringdebounce = 10;
+ } else if (!res) {
+ if ((fxo->ringdebounce == 0) && fxo->wasringing) {
+ fxo->wasringing = 0;
+ if (debug)
+ printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ }
+ }
+ } else if (res && (fxo->battery == BATTERY_PRESENT)) {
+ fxo->lastrdtx = res;
+ fxo->ringdebounce = 10;
+ }
+ } else {
+ res = wc->cmdq[card].isrshadow[0];
+ if ((res & 0x60) && (fxo->battery == BATTERY_PRESENT)) {
+ fxo->ringdebounce += (ZT_CHUNKSIZE * 16);
+ if (fxo->ringdebounce >= ZT_CHUNKSIZE * ringdebounce) {
+ if (!fxo->wasringing) {
+ fxo->wasringing = 1;
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
+ if (debug)
+ printk("RING on %d/%d!\n", wc->span.spanno, card + 1);
+ }
+ fxo->ringdebounce = ZT_CHUNKSIZE * ringdebounce;
+ }
+ } else {
+ fxo->ringdebounce -= ZT_CHUNKSIZE * 4;
+ if (fxo->ringdebounce <= 0) {
+ if (fxo->wasringing) {
+ fxo->wasringing = 0;
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ if (debug)
+ printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);
+ }
+ fxo->ringdebounce = 0;
+ }
+
+ }
+ }
+ }
+
+ b = wc->cmdq[card].isrshadow[1]; /* Voltage */
+
+ if (fxovoltage) {
+ if (!(wc->intcount % 100)) {
+ printk("Port %d: Voltage: %d Debounce %d\n", card + 1,
+ b, fxo->battdebounce);
+ }
+ }
+
+ if (abs(b) < battthresh) {
+ /* possible existing states:
+ battery lost, no debounce timer
+ battery lost, debounce timer (going to battery present)
+ battery present or unknown, no debounce timer
+ battery present or unknown, debounce timer (going to battery lost)
+ */
+
+ if (fxo->battery == BATTERY_LOST) {
+ if (fxo->battdebounce) {
+ /* we were going to BATTERY_PRESENT, but battery was lost again,
+ so clear the debounce timer */
+ fxo->battdebounce = 0;
+ }
+ } else {
+ if (fxo->battdebounce) {
+ /* going to BATTERY_LOST, see if we are there yet */
+ if (--fxo->battdebounce == 0) {
+ fxo->battery = BATTERY_LOST;
+ if (debug)
+ printk("NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1);
+#ifdef JAPAN
+ if (!wc->ohdebounce && wc->offhook) {
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
+ if (debug)
+ printk("Signalled On Hook\n");
+#ifdef ZERO_BATT_RING
+ wc->onhook++;
+#endif
+ }
+#else
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
+ /* set the alarm timer, taking into account that part of its time
+ period has already passed while debouncing occurred */
+ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK;
+#endif
+ }
+ } else {
+ /* start the debounce timer to verify that battery has been lost */
+ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK;
+ }
+ }
+ } else {
+ /* possible existing states:
+ battery lost or unknown, no debounce timer
+ battery lost or unknown, debounce timer (going to battery present)
+ battery present, no debounce timer
+ battery present, debounce timer (going to battery lost)
+ */
+
+ if (fxo->battery == BATTERY_PRESENT) {
+ if (fxo->battdebounce) {
+ /* we were going to BATTERY_LOST, but battery appeared again,
+ so clear the debounce timer */
+ fxo->battdebounce = 0;
+ }
+ } else {
+ if (fxo->battdebounce) {
+ /* going to BATTERY_PRESENT, see if we are there yet */
+ if (--fxo->battdebounce == 0) {
+ fxo->battery = BATTERY_PRESENT;
+ if (debug)
+ printk("BATTERY on %d/%d (%s)!\n", wc->span.spanno, card + 1,
+ (b < 0) ? "-" : "+");
+#ifdef ZERO_BATT_RING
+ if (wc->onhook) {
+ wc->onhook = 0;
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ if (debug)
+ printk("Signalled Off Hook\n");
+ }
+#else
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+#endif
+ /* set the alarm timer, taking into account that part of its time
+ period has already passed while debouncing occurred */
+ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK;
+ }
+ } else {
+ /* start the debounce timer to verify that battery has appeared */
+ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK;
+ }
+ }
+
+ if (fxo->lastpol >= 0) {
+ if (b < 0) {
+ fxo->lastpol = -1;
+ fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK;
+ }
+ }
+ if (fxo->lastpol <= 0) {
+ if (b > 0) {
+ fxo->lastpol = 1;
+ fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK;
+ }
+ }
+ }
+
+ if (fxo->battalarm) {
+ if (--fxo->battalarm == 0) {
+ /* the alarm timer has expired, so update the battery alarm state
+ for this channel */
+ zt_alarm_channel(&wc->chans[card], fxo->battery ? ZT_ALARM_NONE : ZT_ALARM_RED);
+ }
+ }
+
+ if (fxo->polaritydebounce) {
+ fxo->polaritydebounce--;
+ if (fxo->polaritydebounce < 1) {
+ if (fxo->lastpol != fxo->polarity) {
+ if (debug & DEBUG_CARD)
+ printk("%lu Polarity reversed (%d -> %d)\n", jiffies,
+ fxo->polarity,
+ fxo->lastpol);
+ if (fxo->polarity)
+ zt_qevent_lock(&wc->chans[card], ZT_EVENT_POLARITY);
+ fxo->polarity = fxo->lastpol;
+ }
+ }
+ }
+#undef MS_PER_CHECK_HOOK
+}
+
+static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
+{
+ char res;
+ int hook;
+
+ /* For some reason we have to debounce the
+ hook detector. */
+
+ res = wc->cmdq[card].isrshadow[0]; /* Hook state */
+ hook = (res & 1);
+
+ if (hook != wc->mods[card].fxs.lastrxhook) {
+ /* Reset the debounce (must be multiple of 4ms) */
+ wc->mods[card].fxs.debounce = 8 * (4 * 8);
+#if 0
+ printk("Resetting debounce card %d hook %d, %d\n", card, hook, wc->mods[card].fxs.debounce);
+#endif
+ } else {
+ if (wc->mods[card].fxs.debounce > 0) {
+ wc->mods[card].fxs.debounce-= 4 * ZT_CHUNKSIZE;
+#if 0
+ printk("Sustaining hook %d, %d\n", hook, wc->mods[card].fxs.debounce);
+#endif
+ if (!wc->mods[card].fxs.debounce) {
+#if 0
+ printk("Counted down debounce, newhook: %d...\n", hook);
+#endif
+ wc->mods[card].fxs.debouncehook = hook;
+ }
+ if (!wc->mods[card].fxs.oldrxhook && wc->mods[card].fxs.debouncehook) {
+ /* Off hook */
+ if (debug & DEBUG_CARD)
+ printk("wctdm: Card %d Going off hook\n", card);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ if (robust)
+ wctdm_init_proslic(wc, card, 1, 0, 1);
+ wc->mods[card].fxs.oldrxhook = 1;
+
+ } else if (wc->mods[card].fxs.oldrxhook && !wc->mods[card].fxs.debouncehook) {
+ /* On hook */
+ if (debug & DEBUG_CARD)
+ printk("wctdm: Card %d Going on hook\n", card);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
+ wc->mods[card].fxs.oldrxhook = 0;
+ }
+ }
+ }
+ wc->mods[card].fxs.lastrxhook = hook;
+}
+
+
+#ifdef VPM_SUPPORT
+static inline void wctdm_vpm_check(struct wctdm *wc, int x)
+{
+ if (wc->cmdq[x].isrshadow[0]) {
+ if (debug & DEBUG_ECHOCAN)
+ printk("VPM: Detected dtmf ON channel %02x on chip %d!\n", wc->cmdq[x].isrshadow[0], x - NUM_CARDS);
+ wc->sethook[x] = CMD_WR(0xb9, wc->cmdq[x].isrshadow[0]);
+ wc->cmdq[x].isrshadow[0] = 0;
+ /* Cancel most recent lookup, if there is one */
+ wc->cmdq[x].cmds[USER_COMMANDS+0] = 0x00000000;
+ } else if (wc->cmdq[x].isrshadow[1]) {
+ if (debug & DEBUG_ECHOCAN)
+ printk("VPM: Detected dtmf OFF channel %02x on chip %d!\n", wc->cmdq[x].isrshadow[1], x - NUM_CARDS);
+ wc->sethook[x] = CMD_WR(0xbd, wc->cmdq[x].isrshadow[1]);
+ wc->cmdq[x].isrshadow[1] = 0;
+ /* Cancel most recent lookup, if there is one */
+ wc->cmdq[x].cmds[USER_COMMANDS+1] = 0x00000000;
+ }
+}
+
+#include "adt_lec.c"
+
+static int wctdm_echocan_with_params(struct zt_chan *chan, struct zt_echocanparams *ecp, struct zt_echocanparam *p)
+{
+ struct wctdm *wc = chan->pvt;
+
+ if (wc->vpm) {
+ int channel;
+ int unit;
+
+ channel = (chan->chanpos - 1);
+ unit = (chan->chanpos - 1) & 0x3;
+ if (wc->vpm < 2)
+ channel >>= 2;
+
+ if(debug & DEBUG_ECHOCAN)
+ printk("echocan: Unit is %d, Channel is %d length %d\n",
+ unit, channel, ecp->tap_length);
+ if (ecp->tap_length)
+ wctdm_vpm_out(wc,unit,channel,0x3e);
+ else
+ wctdm_vpm_out(wc,unit,channel,0x01);
+
+ return 0;
+#ifdef VPM150M_SUPPORT
+ } else if (wc->vpm150m) {
+ struct vpm150m *vpm150m = wc->vpm150m;
+ unsigned int ret;
+ int channo = chan->chanpos - 1;
+
+ if ((ret = adt_lec_parse_params(&vpm150m->desiredecstate[channo], ecp, p)))
+ return ret;
+
+ vpm150m->desiredecstate[channo].tap_length = ecp->tap_length;
+
+ if (memcmp(&vpm150m->curecstate[channo], &vpm150m->desiredecstate[channo], sizeof(vpm150m->curecstate[channo]))
+ && test_bit(VPM150M_ACTIVE, &vpm150m->control))
+ queue_work(vpm150m->wq, &vpm150m->work);
+
+ return 0;
+#endif
+ } else
+ return -ENODEV;
+}
+#endif
+
+static inline void wctdm_isr_misc(struct wctdm *wc)
+{
+ int x;
+
+ if (unlikely(!wc->initialized)) {
+ return;
+ }
+
+ for (x=0;x<wc->cards;x++) {
+ if (wc->cardflag & (1 << x)) {
+ if (wc->modtype[x] == MOD_TYPE_FXS) {
+ if (!(wc->intcount % 10000)) {
+ /* Accept an alarm once per 10 seconds */
+ if (wc->mods[x].fxs.palarms)
+ wc->mods[x].fxs.palarms--;
+ }
+ wctdm_proslic_check_hook(wc, x);
+ if (!(wc->intcount & 0xfc))
+ wctdm_proslic_recheck_sanity(wc, x);
+ if (wc->mods[x].fxs.lasttxhook == 0x4) {
+ /* RINGing, prepare for OHT */
+ wc->mods[x].fxs.ohttimer = OHT_TIMER << 3;
+ wc->mods[x].fxs.idletxhookstate = 0x2; /* OHT mode when idle */
+ } else {
+ if (wc->mods[x].fxs.ohttimer) {
+ wc->mods[x].fxs.ohttimer-= ZT_CHUNKSIZE;
+ if (!wc->mods[x].fxs.ohttimer) {
+ wc->mods[x].fxs.idletxhookstate = 0x1; /* Switch to active */
+ if (wc->mods[x].fxs.lasttxhook == 0x2) {
+ /* Apply the change if appropriate */
+ wc->mods[x].fxs.lasttxhook = 0x11;
+ wc->sethook[x] = CMD_WR(64, wc->mods[x].fxs.lasttxhook);
+ /* wctdm_setreg_intr(wc, x, 64, wc->mods[x].fxs.lasttxhook); */
+ }
+ }
+ }
+ }
+ } else if (wc->modtype[x] == MOD_TYPE_FXO) {
+ wctdm_voicedaa_check_hook(wc, x);
+ } else if (wc->modtype[x] == MOD_TYPE_QRV) {
+ wctdm_qrvdri_check_hook(wc, x);
+ }
+ }
+ }
+#ifdef VPM_SUPPORT
+ if (wc->vpm > 0) {
+ for (x=NUM_CARDS;x<NUM_CARDS+NUM_EC;x++) {
+ wctdm_vpm_check(wc, x);
+ }
+ }
+#endif
+}
+
+void handle_receive(void* vbb, void* context)
+{
+ struct wctdm *wc = context;
+ wc->rxints++;
+ wctdm_receiveprep(wc, vbb);
+}
+
+void handle_transmit(void* vbb, void* context)
+{
+ struct wctdm *wc = context;
+ memset(vbb, 0, SFRAME_SIZE);
+ wc->txints++;
+ wctdm_transmitprep(wc, vbb);
+ wctdm_isr_misc(wc);
+ wc->intcount++;
+ voicebus_transmit(wc->vb, vbb);
+}
+
+static int wctdm_voicedaa_insane(struct wctdm *wc, int card)
+{
+ int blah;
+ blah = wctdm_getreg(wc, card, 2);
+ if (blah != 0x3)
+ return -2;
+ blah = wctdm_getreg(wc, card, 11);
+ if (debug & DEBUG_CARD)
+ printk("VoiceDAA System: %02x\n", blah & 0xf);
+ return 0;
+}
+
+static int wctdm_proslic_insane(struct wctdm *wc, int card)
+{
+ int blah,insane_report;
+ insane_report=0;
+
+ blah = wctdm_getreg(wc, card, 0);
+ if (debug & DEBUG_CARD)
+ printk("ProSLIC on module %d, product %d, version %d\n", card, (blah & 0x30) >> 4, (blah & 0xf));
+
+#if 0
+ if ((blah & 0x30) >> 4) {
+ printk("ProSLIC on module %d is not a 3210.\n", card);
+ return -1;
+ }
+#endif
+ if (((blah & 0xf) == 0) || ((blah & 0xf) == 0xf)) {
+ /* SLIC not loaded */
+ return -1;
+ }
+ if ((blah & 0xf) < 2) {
+ printk("ProSLIC 3210 version %d is too old\n", blah & 0xf);
+ return -1;
+ }
+ if (wctdm_getreg(wc, card, 1) & 0x80)
+ /* ProSLIC 3215, not a 3210 */
+ wc->flags[card] |= FLAG_3215;
+
+ blah = wctdm_getreg(wc, card, 8);
+ if (blah != 0x2) {
+ printk("ProSLIC on module %d insane (1) %d should be 2\n", card, blah);
+ return -1;
+ } else if ( insane_report)
+ printk("ProSLIC on module %d Reg 8 Reads %d Expected is 0x2\n",card,blah);
+
+ blah = wctdm_getreg(wc, card, 64);
+ if (blah != 0x0) {
+ printk("ProSLIC on module %d insane (2)\n", card);
+ return -1;
+ } else if ( insane_report)
+ printk("ProSLIC on module %d Reg 64 Reads %d Expected is 0x0\n",card,blah);
+
+ blah = wctdm_getreg(wc, card, 11);
+ if (blah != 0x33) {
+ printk("ProSLIC on module %d insane (3)\n", card);
+ return -1;
+ } else if ( insane_report)
+ printk("ProSLIC on module %d Reg 11 Reads %d Expected is 0x33\n",card,blah);
+
+ /* Just be sure it's setup right. */
+ wctdm_setreg(wc, card, 30, 0);
+
+ if (debug & DEBUG_CARD)
+ printk("ProSLIC on module %d seems sane.\n", card);
+ return 0;
+}
+
+static int wctdm_proslic_powerleak_test(struct wctdm *wc, int card)
+{
+ unsigned long origjiffies;
+ unsigned char vbat;
+
+ /* Turn off linefeed */
+ wctdm_setreg(wc, card, 64, 0);
+
+ /* Power down */
+ wctdm_setreg(wc, card, 14, 0x10);
+
+ /* Wait for one second */
+ origjiffies = jiffies;
+
+ while((vbat = wctdm_getreg(wc, card, 82)) > 0x6) {
+ if ((jiffies - origjiffies) >= (HZ/2))
+ break;;
+ }
+
+ if (vbat < 0x06) {
+ printk("Excessive leakage detected on module %d: %d volts (%02x) after %d ms\n", card,
+ 376 * vbat / 1000, vbat, (int)((jiffies - origjiffies) * 1000 / HZ));
+ return -1;
+ } else if (debug & DEBUG_CARD) {
+ printk("Post-leakage voltage: %d volts\n", 376 * vbat / 1000);
+ }
+ return 0;
+}
+
+static int wctdm_powerup_proslic(struct wctdm *wc, int card, int fast)
+{
+ unsigned char vbat;
+ unsigned long origjiffies;
+ int lim;
+
+ /* Set period of DC-DC converter to 1/64 khz */
+ wctdm_setreg(wc, card, 92, 0xc0 /* was 0xff */);
+
+ /* Wait for VBat to powerup */
+ origjiffies = jiffies;
+
+ /* Disable powerdown */
+ wctdm_setreg(wc, card, 14, 0);
+
+ /* If fast, don't bother checking anymore */
+ if (fast)
+ return 0;
+
+ while((vbat = wctdm_getreg(wc, card, 82)) < 0xc0) {
+ /* Wait no more than 500ms */
+ if ((jiffies - origjiffies) > HZ/2) {
+ break;
+ }
+ }
+
+ if (vbat < 0xc0) {
+ printk("ProSLIC on module %d failed to powerup within %d ms (%d mV only)\n\n -- DID YOU REMEMBER TO PLUG IN THE HD POWER CABLE TO THE TDM CARD??\n",
+ card, (int)(((jiffies - origjiffies) * 1000 / HZ)),
+ vbat * 375);
+ return -1;
+ } else if (debug & DEBUG_CARD) {
+ printk("ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n",
+ card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ)));
+ }
+
+ /* Proslic max allowed loop current, reg 71 LOOP_I_LIMIT */
+ /* If out of range, just set it to the default value */
+ lim = (loopcurrent - 20) / 3;
+ if ( loopcurrent > 41 ) {
+ lim = 0;
+ if (debug & DEBUG_CARD)
+ printk("Loop current out of range! Setting to default 20mA!\n");
+ }
+ else if (debug & DEBUG_CARD)
+ printk("Loop current set to %dmA!\n",(lim*3)+20);
+ wctdm_setreg(wc,card,LOOP_I_LIMIT,lim);
+
+ /* Engage DC-DC converter */
+ wctdm_setreg(wc, card, 93, 0x19 /* was 0x19 */);
+#if 0
+ origjiffies = jiffies;
+ while(0x80 & wctdm_getreg(wc, card, 93)) {
+ if ((jiffies - origjiffies) > 2 * HZ) {
+ printk("Timeout waiting for DC-DC calibration on module %d\n", card);
+ return -1;
+ }
+ }
+
+#if 0
+ /* Wait a full two seconds */
+ while((jiffies - origjiffies) < 2 * HZ);
+
+ /* Just check to be sure */
+ vbat = wctdm_getreg(wc, card, 82);
+ printk("ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n",
+ card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ)));
+#endif
+#endif
+ return 0;
+
+}
+
+static int wctdm_proslic_manual_calibrate(struct wctdm *wc, int card)
+{
+ unsigned long origjiffies;
+ unsigned char i;
+
+ wctdm_setreg(wc, card, 21, 0);//(0) Disable all interupts in DR21
+ wctdm_setreg(wc, card, 22, 0);//(0)Disable all interupts in DR21
+ wctdm_setreg(wc, card, 23, 0);//(0)Disable all interupts in DR21
+ wctdm_setreg(wc, card, 64, 0);//(0)
+
+ wctdm_setreg(wc, card, 97, 0x18); //(0x18)Calibrations without the ADC and DAC offset and without common mode calibration.
+ wctdm_setreg(wc, card, 96, 0x47); //(0x47) Calibrate common mode and differential DAC mode DAC + ILIM
+
+ origjiffies=jiffies;
+ while( wctdm_getreg(wc,card,96)!=0 ){
+ if((jiffies-origjiffies)>80)
+ return -1;
+ }
+//Initialized DR 98 and 99 to get consistant results.
+// 98 and 99 are the results registers and the search should have same intial conditions.
+
+/*******************************The following is the manual gain mismatch calibration****************************/
+/*******************************This is also available as a function *******************************************/
+ // Delay 10ms
+ origjiffies=jiffies;
+ while((jiffies-origjiffies)<1);
+ wctdm_proslic_setreg_indirect(wc, card, 88,0);
+ wctdm_proslic_setreg_indirect(wc,card,89,0);
+ wctdm_proslic_setreg_indirect(wc,card,90,0);
+ wctdm_proslic_setreg_indirect(wc,card,91,0);
+ wctdm_proslic_setreg_indirect(wc,card,92,0);
+ wctdm_proslic_setreg_indirect(wc,card,93,0);
+
+ wctdm_setreg(wc, card, 98,0x10); // This is necessary if the calibration occurs other than at reset time
+ wctdm_setreg(wc, card, 99,0x10);
+
+ for ( i=0x1f; i>0; i--)
+ {
+ wctdm_setreg(wc, card, 98,i);
+ origjiffies=jiffies;
+ while((jiffies-origjiffies)<4);
+ if((wctdm_getreg(wc,card,88)) == 0)
+ break;
+ } // for
+
+ for ( i=0x1f; i>0; i--)
+ {
+ wctdm_setreg(wc, card, 99,i);
+ origjiffies=jiffies;
+ while((jiffies-origjiffies)<4);
+ if((wctdm_getreg(wc,card,89)) == 0)
+ break;
+ }//for
+
+/*******************************The preceding is the manual gain mismatch calibration****************************/
+/**********************************The following is the longitudinal Balance Cal***********************************/
+ wctdm_setreg(wc,card,64,1);
+ while((jiffies-origjiffies)<10); // Sleep 100?
+
+ wctdm_setreg(wc, card, 64, 0);
+ wctdm_setreg(wc, card, 23, 0x4); // enable interrupt for the balance Cal
+ wctdm_setreg(wc, card, 97, 0x1); // this is a singular calibration bit for longitudinal calibration
+ wctdm_setreg(wc, card, 96,0x40);
+
+ wctdm_getreg(wc,card,96); /* Read Reg 96 just cause */
+
+ wctdm_setreg(wc, card, 21, 0xFF);
+ wctdm_setreg(wc, card, 22, 0xFF);
+ wctdm_setreg(wc, card, 23, 0xFF);
+
+ /**The preceding is the longitudinal Balance Cal***/
+ return(0);
+
+}
+
+static int wctdm_proslic_calibrate(struct wctdm *wc, int card)
+{
+ unsigned long origjiffies;
+ int x;
+ /* Perform all calibrations */
+ wctdm_setreg(wc, card, 97, 0x1f);
+
+ /* Begin, no speedup */
+ wctdm_setreg(wc, card, 96, 0x5f);
+
+ /* Wait for it to finish */
+ origjiffies = jiffies;
+ while(wctdm_getreg(wc, card, 96)) {
+ if ((jiffies - origjiffies) > 2 * HZ) {
+ printk("Timeout waiting for calibration of module %d\n", card);
+ return -1;
+ }
+ }
+
+ if (debug & DEBUG_CARD) {
+ /* Print calibration parameters */
+ printk("Calibration Vector Regs 98 - 107: \n");
+ for (x=98;x<108;x++) {
+ printk("%d: %02x\n", x, wctdm_getreg(wc, card, x));
+ }
+ }
+ return 0;
+}
+
+static void wait_just_a_bit(int foo)
+{
+ long newjiffies;
+ newjiffies = jiffies + foo;
+ while(jiffies < newjiffies);
+}
+
+/*********************************************************************
+ * Set the hwgain on the analog modules
+ *
+ * card = the card position for this module (0-23)
+ * gain = gain in dB x10 (e.g. -3.5dB would be gain=-35)
+ * tx = (0 for rx; 1 for tx)
+ *
+ *******************************************************************/
+static int wctdm_set_hwgain(struct wctdm *wc, int card, __s32 gain, __u32 tx)
+{
+ if (!(wc->modtype[card] == MOD_TYPE_FXO)) {
+ printk("Cannot adjust gain. Unsupported module type!\n");
+ return -1;
+ }
+ if (tx) {
+ if (debug)
+ printk("setting FXO tx gain for card=%d to %d\n", card, gain);
+ if (gain >= -150 && gain <= 0) {
+ wctdm_setreg(wc, card, 38, 16 + (gain/-10));
+ wctdm_setreg(wc, card, 40, 16 + (-gain%10));
+ } else if (gain <= 120 && gain > 0) {
+ wctdm_setreg(wc, card, 38, gain/10);
+ wctdm_setreg(wc, card, 40, (gain%10));
+ } else {
+ printk("FXO tx gain is out of range (%d)\n", gain);
+ return -1;
+ }
+ } else { /* rx */
+ if (debug)
+ printk("setting FXO rx gain for card=%d to %d\n", card, gain);
+ if (gain >= -150 && gain <= 0) {
+ wctdm_setreg(wc, card, 39, 16+ (gain/-10));
+ wctdm_setreg(wc, card, 41, 16 + (-gain%10));
+ } else if (gain <= 120 && gain > 0) {
+ wctdm_setreg(wc, card, 39, gain/10);
+ wctdm_setreg(wc, card, 41, (gain%10));
+ } else {
+ printk("FXO rx gain is out of range (%d)\n", gain);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int wctdm_init_voicedaa(struct wctdm *wc, int card, int fast, int manual, int sane)
+{
+ unsigned char reg16=0, reg26=0, reg30=0, reg31=0;
+ long newjiffies;
+
+ if (wc->modtype[card & 0xfc] == MOD_TYPE_QRV) return -2;
+
+ wc->modtype[card] = MOD_TYPE_NONE;
+ /* Wait just a bit */
+ wait_just_a_bit(HZ/10);
+
+ wc->modtype[card] = MOD_TYPE_FXO;
+ wait_just_a_bit(HZ/10);
+
+ if (!sane && wctdm_voicedaa_insane(wc, card))
+ return -2;
+
+ /* Software reset */
+ wctdm_setreg(wc, card, 1, 0x80);
+
+ /* Wait just a bit */
+ wait_just_a_bit(HZ/10);
+
+ /* Enable PCM, ulaw */
+ if (alawoverride)
+ wctdm_setreg(wc, card, 33, 0x20);
+ else
+ wctdm_setreg(wc, card, 33, 0x28);
+
+ /* Set On-hook speed, Ringer impedence, and ringer threshold */
+ reg16 |= (fxo_modes[_opermode].ohs << 6);
+ reg16 |= (fxo_modes[_opermode].rz << 1);
+ reg16 |= (fxo_modes[_opermode].rt);
+ wctdm_setreg(wc, card, 16, reg16);
+
+ if(fwringdetect) {
+ /* Enable ring detector full-wave rectifier mode */
+ wctdm_setreg(wc, card, 18, 2);
+ wctdm_setreg(wc, card, 24, 0);
+ } else {
+ /* Set to the device defaults */
+ wctdm_setreg(wc, card, 18, 0);
+ wctdm_setreg(wc, card, 24, 0x19);
+ }
+
+ /* Enable ring detector full-wave rectifier mode */
+ wctdm_setreg(wc, card, 18, 2);
+ wctdm_setreg(wc, card, 24, 0);
+
+ /* Set DC Termination:
+ Tip/Ring voltage adjust, minimum operational current, current limitation */
+ reg26 |= (fxo_modes[_opermode].dcv << 6);
+ reg26 |= (fxo_modes[_opermode].mini << 4);
+ reg26 |= (fxo_modes[_opermode].ilim << 1);
+ wctdm_setreg(wc, card, 26, reg26);
+
+ /* Set AC Impedence */
+ reg30 = (fxo_modes[_opermode].acim);
+ wctdm_setreg(wc, card, 30, reg30);
+
+ /* Misc. DAA parameters */
+ reg31 = 0xa3;
+ reg31 |= (fxo_modes[_opermode].ohs2 << 3);
+ wctdm_setreg(wc, card, 31, reg31);
+
+ /* Set Transmit/Receive timeslot */
+ wctdm_setreg(wc, card, 34, (card * 8) & 0xff);
+ wctdm_setreg(wc, card, 35, (card * 8) >> 8);
+ wctdm_setreg(wc, card, 36, (card * 8) & 0xff);
+ wctdm_setreg(wc, card, 37, (card * 8) >> 8);
+
+ /* Enable ISO-Cap */
+ wctdm_setreg(wc, card, 6, 0x00);
+
+ /* Wait 1000ms for ISO-cap to come up */
+ newjiffies = jiffies;
+ newjiffies += 2 * HZ;
+ while((jiffies < newjiffies) && !(wctdm_getreg(wc, card, 11) & 0xf0))
+ wait_just_a_bit(HZ/10);
+
+ if (!(wctdm_getreg(wc, card, 11) & 0xf0)) {
+ printk("VoiceDAA did not bring up ISO link properly!\n");
+ return -1;
+ }
+ if (debug & DEBUG_CARD)
+ printk("ISO-Cap is now up, line side: %02x rev %02x\n",
+ wctdm_getreg(wc, card, 11) >> 4,
+ (wctdm_getreg(wc, card, 13) >> 2) & 0xf);
+ /* Enable on-hook line monitor */
+ wctdm_setreg(wc, card, 5, 0x08);
+
+ /* Take values for fxotxgain and fxorxgain and apply them to module */
+ wctdm_set_hwgain(wc, card, fxotxgain, 1);
+ wctdm_set_hwgain(wc, card, fxorxgain, 0);
+
+ if(debug)
+ printk("DEBUG fxotxgain:%i.%i fxorxgain:%i.%i\n", (wctdm_getreg(wc, card, 38)/16) ? -(wctdm_getreg(wc, card, 38) - 16) : wctdm_getreg(wc, card, 38), (wctdm_getreg(wc, card, 40)/16) ? -(wctdm_getreg(wc, card, 40) - 16) : wctdm_getreg(wc, card, 40), (wctdm_getreg(wc, card, 39)/16) ? -(wctdm_getreg(wc, card, 39) - 16): wctdm_getreg(wc, card, 39), (wctdm_getreg(wc, card, 41)/16)?-(wctdm_getreg(wc, card, 41) - 16) : wctdm_getreg(wc, card, 41));
+
+ return 0;
+
+}
+
+static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual, int sane)
+{
+
+ unsigned short tmp[5];
+ unsigned char r19,r9;
+ int x;
+ int fxsmode=0;
+
+ if (wc->modtype[card & 0xfc] == MOD_TYPE_QRV) return -2;
+
+ /* Sanity check the ProSLIC */
+ if (!sane && wctdm_proslic_insane(wc, card))
+ return -2;
+
+ /* By default, don't send on hook */
+ wc->mods[card].fxs.idletxhookstate = 1;
+ wc->mods[card].fxs.lasttxhook = 0x10;
+
+ if (sane) {
+ /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */
+ wctdm_setreg(wc, card, 14, 0x10);
+ }
+
+ if (wctdm_proslic_init_indirect_regs(wc, card)) {
+ printk(KERN_INFO "Indirect Registers failed to initialize on module %d.\n", card);
+ return -1;
+ }
+
+ /* Clear scratch pad area */
+ wctdm_proslic_setreg_indirect(wc, card, 97,0);
+
+ /* Clear digital loopback */
+ wctdm_setreg(wc, card, 8, 0);
+
+ /* Revision C optimization */
+ wctdm_setreg(wc, card, 108, 0xeb);
+
+ /* Disable automatic VBat switching for safety to prevent
+ Q7 from accidently turning on and burning out. */
+ wctdm_setreg(wc, card, 67, 0x07); /* If pulse dialing has trouble at high REN
+ loads change this to 0x17 */
+
+ /* Turn off Q7 */
+ wctdm_setreg(wc, card, 66, 1);
+
+ /* Flush ProSLIC digital filters by setting to clear, while
+ saving old values */
+ for (x=0;x<5;x++) {
+ tmp[x] = wctdm_proslic_getreg_indirect(wc, card, x + 35);
+ wctdm_proslic_setreg_indirect(wc, card, x + 35, 0x8000);
+ }
+
+ /* Power up the DC-DC converter */
+ if (wctdm_powerup_proslic(wc, card, fast)) {
+ printk("Unable to do INITIAL ProSLIC powerup on module %d\n", card);
+ return -1;
+ }
+
+ if (!fast) {
+
+ /* Check for power leaks */
+ if (wctdm_proslic_powerleak_test(wc, card)) {
+ printk("ProSLIC module %d failed leakage test. Check for short circuit\n", card);
+ }
+ /* Power up again */
+ if (wctdm_powerup_proslic(wc, card, fast)) {
+ printk("Unable to do FINAL ProSLIC powerup on module %d\n", card);
+ return -1;
+ }
+#ifndef NO_CALIBRATION
+ /* Perform calibration */
+ if(manual) {
+ if (wctdm_proslic_manual_calibrate(wc, card)) {
+ //printk("Proslic failed on Manual Calibration\n");
+ if (wctdm_proslic_manual_calibrate(wc, card)) {
+ printk("Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n");
+ return -1;
+ }
+ printk("Proslic Passed Manual Calibration on Second Attempt\n");
+ }
+ }
+ else {
+ if(wctdm_proslic_calibrate(wc, card)) {
+ //printk("ProSlic died on Auto Calibration.\n");
+ if (wctdm_proslic_calibrate(wc, card)) {
+ printk("Proslic Failed on Second Attempt to Auto Calibrate\n");
+ return -1;
+ }
+ printk("Proslic Passed Auto Calibration on Second Attempt\n");
+ }
+ }
+ /* Perform DC-DC calibration */
+ wctdm_setreg(wc, card, 93, 0x99);
+ r19 = wctdm_getreg(wc, card, 107);
+ if ((r19 < 0x2) || (r19 > 0xd)) {
+ printk("DC-DC cal has a surprising direct 107 of 0x%02x!\n", r19);
+ wctdm_setreg(wc, card, 107, 0x8);
+ }
+
+ /* Save calibration vectors */
+ for (x=0;x<NUM_CAL_REGS;x++)
+ wc->mods[card].fxs.calregs.vals[x] = wctdm_getreg(wc, card, 96 + x);
+#endif
+
+ } else {
+ /* Restore calibration registers */
+ for (x=0;x<NUM_CAL_REGS;x++)
+ wctdm_setreg(wc, card, 96 + x, wc->mods[card].fxs.calregs.vals[x]);
+ }
+ /* Calibration complete, restore original values */
+ for (x=0;x<5;x++) {
+ wctdm_proslic_setreg_indirect(wc, card, x + 35, tmp[x]);
+ }
+
+ if (wctdm_proslic_verify_indirect_regs(wc, card)) {
+ printk(KERN_INFO "Indirect Registers failed verification.\n");
+ return -1;
+ }
+
+
+#if 0
+ /* Disable Auto Power Alarm Detect and other "features" */
+ wctdm_setreg(wc, card, 67, 0x0e);
+ blah = wctdm_getreg(wc, card, 67);
+#endif
+
+#if 0
+ if (wctdm_proslic_setreg_indirect(wc, card, 97, 0x0)) { // Stanley: for the bad recording fix
+ printk(KERN_INFO "ProSlic IndirectReg Died.\n");
+ return -1;
+ }
+#endif
+
+ if (alawoverride)
+ wctdm_setreg(wc, card, 1, 0x20);
+ else
+ wctdm_setreg(wc, card, 1, 0x28);
+ // U-Law 8-bit interface
+ wctdm_setreg(wc, card, 2, (card * 8) & 0xff); // Tx Start count low byte 0
+ wctdm_setreg(wc, card, 3, (card * 8) >> 8); // Tx Start count high byte 0
+ wctdm_setreg(wc, card, 4, (card * 8) & 0xff); // Rx Start count low byte 0
+ wctdm_setreg(wc, card, 5, (card * 8) >> 8); // Rx Start count high byte 0
+ wctdm_setreg(wc, card, 18, 0xff); // clear all interrupt
+ wctdm_setreg(wc, card, 19, 0xff);
+ wctdm_setreg(wc, card, 20, 0xff);
+ wctdm_setreg(wc, card, 22, 0xff);
+ wctdm_setreg(wc, card, 73, 0x04);
+ if (fxshonormode) {
+ fxsmode = acim2tiss[fxo_modes[_opermode].acim];
+ wctdm_setreg(wc, card, 10, 0x08 | fxsmode);
+ if (fxo_modes[_opermode].ring_osc)
+ wctdm_proslic_setreg_indirect(wc, card, 20, fxo_modes[_opermode].ring_osc);
+ if (fxo_modes[_opermode].ring_x)
+ wctdm_proslic_setreg_indirect(wc, card, 21, fxo_modes[_opermode].ring_x);
+ }
+ if (lowpower)
+ wctdm_setreg(wc, card, 72, 0x10);
+
+#if 0
+ wctdm_setreg(wc, card, 21, 0x00); // enable interrupt
+ wctdm_setreg(wc, card, 22, 0x02); // Loop detection interrupt
+ wctdm_setreg(wc, card, 23, 0x01); // DTMF detection interrupt
+#endif
+
+#if 0
+ /* Enable loopback */
+ wctdm_setreg(wc, card, 8, 0x2);
+ wctdm_setreg(wc, card, 14, 0x0);
+ wctdm_setreg(wc, card, 64, 0x0);
+ wctdm_setreg(wc, card, 1, 0x08);
+#endif
+
+ if (fastringer) {
+ /* Speed up Ringer */
+ wctdm_proslic_setreg_indirect(wc, card, 20, 0x7e6d);
+ wctdm_proslic_setreg_indirect(wc, card, 21, 0x01b9);
+ /* Beef up Ringing voltage to 89V */
+ if (boostringer) {
+ wctdm_setreg(wc, card, 74, 0x3f);
+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x247))
+ return -1;
+ printk("Boosting fast ringer on slot %d (89V peak)\n", card + 1);
+ } else if (lowpower) {
+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x14b))
+ return -1;
+ printk("Reducing fast ring power on slot %d (50V peak)\n", card + 1);
+ } else
+ printk("Speeding up ringer on slot %d (25Hz)\n", card + 1);
+ } else {
+ /* Beef up Ringing voltage to 89V */
+ if (boostringer) {
+ wctdm_setreg(wc, card, 74, 0x3f);
+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x1d1))
+ return -1;
+ printk("Boosting ringer on slot %d (89V peak)\n", card + 1);
+ } else if (lowpower) {
+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x108))
+ return -1;
+ printk("Reducing ring power on slot %d (50V peak)\n", card + 1);
+ }
+ }
+
+ if (fxstxgain || fxsrxgain) {
+ r9 = wctdm_getreg(wc, card, 9);
+ switch (fxstxgain) {
+
+ case 35:
+ r9+=8;
+ break;
+ case -35:
+ r9+=4;
+ break;
+ case 0:
+ break;
+ }
+
+ switch (fxsrxgain) {
+
+ case 35:
+ r9+=2;
+ break;
+ case -35:
+ r9+=1;
+ break;
+ case 0:
+ break;
+ }
+ wctdm_setreg(wc, card, 9, r9);
+ }
+
+ if (debug)
+ printk("DEBUG: fxstxgain:%s fxsrxgain:%s\n",((wctdm_getreg(wc, card, 9)/8) == 1)?"3.5":(((wctdm_getreg(wc,card,9)/4) == 1)?"-3.5":"0.0"),((wctdm_getreg(wc, card, 9)/2) == 1)?"3.5":((wctdm_getreg(wc,card,9)%2)?"-3.5":"0.0"));
+
+ wc->mods[card].fxs.lasttxhook = 0x11;
+ wctdm_setreg(wc, card, 64, 0x01);
+ return 0;
+}
+
+static int wctdm_init_qrvdri(struct wctdm *wc, int card)
+{
+ unsigned char x,y;
+ unsigned long endjif;
+
+ /* have to set this, at least for now */
+ wc->modtype[card] = MOD_TYPE_QRV;
+ if (!(card & 3)) /* if at base of card, reset and write it */
+ {
+ wctdm_setreg(wc,card,0,0x80);
+ wctdm_setreg(wc,card,0,0x55);
+ wctdm_setreg(wc,card,1,0x69);
+ wc->qrvhook[card] = wc->qrvhook[card + 1] = 0;
+ wc->qrvhook[card + 2] = wc->qrvhook[card + 3] = 0xff;
+ wc->debouncetime[card] = wc->debouncetime[card + 1] = QRV_DEBOUNCETIME;
+ wc->qrvdebtime[card] = wc->qrvdebtime[card + 1] = 0;
+ wc->radmode[card] = wc->radmode[card + 1] = 0;
+ wc->txgain[card] = wc->txgain[card + 1] = 3599;
+ wc->rxgain[card] = wc->rxgain[card + 1] = 1199;
+ } else { /* channel is on same card as base, no need to test */
+ if (wc->modtype[card & 0x7c] == MOD_TYPE_QRV)
+ {
+ /* only lower 2 are valid */
+ if (!(card & 2)) return 0;
+ }
+ wc->modtype[card] = MOD_TYPE_NONE;
+ return 1;
+ }
+ x = wctdm_getreg(wc,card,0);
+ y = wctdm_getreg(wc,card,1);
+ /* if not a QRV card, return as such */
+ if ((x != 0x55) || (y != 0x69))
+ {
+ wc->modtype[card] = MOD_TYPE_NONE;
+ return 1;
+ }
+ for(x = 0; x < 0x30; x++)
+ {
+ if ((x >= 0x1c) && (x <= 0x1e)) wctdm_setreg(wc,card,x,0xff);
+ else wctdm_setreg(wc,card,x,0);
+ }
+ wctdm_setreg(wc,card,0,0x80);
+ endjif = jiffies + (HZ/10);
+ while(endjif > jiffies);
+ wctdm_setreg(wc,card,0,0x10);
+ wctdm_setreg(wc,card,0,0x10);
+ endjif = jiffies + (HZ/10);
+ while(endjif > jiffies);
+ /* set up modes */
+ wctdm_setreg(wc,card,0,0x1c);
+ /* set up I/O directions */
+ wctdm_setreg(wc,card,1,0x33);
+ wctdm_setreg(wc,card,2,0x0f);
+ wctdm_setreg(wc,card,5,0x0f);
+ /* set up I/O to quiescent state */
+ wctdm_setreg(wc,card,3,0x11); /* D0-7 */
+ wctdm_setreg(wc,card,4,0xa); /* D8-11 */
+ wctdm_setreg(wc,card,7,0); /* CS outputs */
+ /* set up timeslots */
+ wctdm_setreg(wc,card,0x13,card + 0x80); /* codec 2 tx, ts0 */
+ wctdm_setreg(wc,card,0x17,card + 0x80); /* codec 0 rx, ts0 */
+ wctdm_setreg(wc,card,0x14,card + 0x81); /* codec 1 tx, ts1 */
+ wctdm_setreg(wc,card,0x18,card + 0x81); /* codec 1 rx, ts1 */
+ /* set up for max gains */
+ wctdm_setreg(wc,card,0x26,0x24);
+ wctdm_setreg(wc,card,0x27,0x24);
+ wctdm_setreg(wc,card,0x0b,0x01); /* "Transmit" gain codec 0 */
+ wctdm_setreg(wc,card,0x0c,0x01); /* "Transmit" gain codec 1 */
+ wctdm_setreg(wc,card,0x0f,0xff); /* "Receive" gain codec 0 */
+ wctdm_setreg(wc,card,0x10,0xff); /* "Receive" gain codec 1 */
+ return 0;
+}
+
+static void qrv_dosetup(struct zt_chan *chan,struct wctdm *wc)
+{
+int qrvcard;
+unsigned char r;
+long l;
+
+ /* actually do something with the values */
+ qrvcard = (chan->chanpos - 1) & 0xfc;
+ if (debug) printk("@@@@@ radmodes: %d,%d rxgains: %d,%d txgains: %d,%d\n",
+ wc->radmode[qrvcard],wc->radmode[qrvcard + 1],
+ wc->rxgain[qrvcard],wc->rxgain[qrvcard + 1],
+ wc->txgain[qrvcard],wc->txgain[qrvcard + 1]);
+ r = 0;
+ if (wc->radmode[qrvcard] & RADMODE_DEEMP) r |= 4;
+ if (wc->radmode[qrvcard + 1] & RADMODE_DEEMP) r |= 8;
+ if (wc->rxgain[qrvcard] < 1200) r |= 1;
+ if (wc->rxgain[qrvcard + 1] < 1200) r |= 2;
+ wctdm_setreg(wc, qrvcard, 7, r);
+ if (debug) printk("@@@@@ setting reg 7 to %02x hex\n",r);
+ r = 0;
+ if (wc->radmode[qrvcard] & RADMODE_PREEMP) r |= 3;
+ else if (wc->txgain[qrvcard] >= 3600) r |= 1;
+ else if (wc->txgain[qrvcard] >= 1200) r |= 2;
+ if (wc->radmode[qrvcard + 1] & RADMODE_PREEMP) r |= 0xc;
+ else if (wc->txgain[qrvcard + 1] >= 3600) r |= 4;
+ else if (wc->txgain[qrvcard + 1] >= 1200) r |= 8;
+ wctdm_setreg(wc, qrvcard, 4, r);
+ if (debug) printk("@@@@@ setting reg 4 to %02x hex\n",r);
+ r = 0;
+ if (wc->rxgain[qrvcard] >= 2400) r |= 1;
+ if (wc->rxgain[qrvcard + 1] >= 2400) r |= 2;
+ wctdm_setreg(wc, qrvcard, 0x25, r);
+ if (debug) printk("@@@@@ setting reg 0x25 to %02x hex\n",r);
+ r = 0;
+ if (wc->txgain[qrvcard] < 2400) r |= 1; else r |= 4;
+ if (wc->txgain[qrvcard + 1] < 2400) r |= 8; else r |= 0x20;
+ wctdm_setreg(wc, qrvcard, 0x26, r);
+ if (debug) printk("@@@@@ setting reg 0x26 to %02x hex\n",r);
+ l = ((long)(wc->rxgain[qrvcard] % 1200) * 10000) / 46875;
+ if (l == 0) l = 1;
+ if (wc->rxgain[qrvcard] >= 2400) l += 181;
+ wctdm_setreg(wc, qrvcard, 0x0b, (unsigned char)l);
+ if (debug) printk("@@@@@ setting reg 0x0b to %02x hex\n",(unsigned char)l);
+ l = ((long)(wc->rxgain[qrvcard + 1] % 1200) * 10000) / 46875;
+ if (l == 0) l = 1;
+ if (wc->rxgain[qrvcard + 1] >= 2400) l += 181;
+ wctdm_setreg(wc, qrvcard, 0x0c, (unsigned char)l);
+ if (debug) printk("@@@@@ setting reg 0x0c to %02x hex\n",(unsigned char)l);
+ l = ((long)(wc->txgain[qrvcard] % 1200) * 10000) / 46875;
+ if (l == 0) l = 1;
+ wctdm_setreg(wc, qrvcard, 0x0f, (unsigned char)l);
+ if (debug) printk("@@@@@ setting reg 0x0f to %02x hex\n", (unsigned char)l);
+ l = ((long)(wc->txgain[qrvcard + 1] % 1200) * 10000) / 46875;
+ if (l == 0) l = 1;
+ wctdm_setreg(wc, qrvcard, 0x10,(unsigned char)l);
+ if (debug) printk("@@@@@ setting reg 0x10 to %02x hex\n",(unsigned char)l);
+ return;
+}
+
+static int wctdm_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
+{
+ struct wctdm_stats stats;
+ struct wctdm_regs regs;
+ struct wctdm_regop regop;
+ struct wctdm_echo_coefs echoregs;
+ struct zt_hwgain hwgain;
+ struct wctdm *wc = chan->pvt;
+ int x;
+ union {
+ struct zt_radio_stat s;
+ struct zt_radio_param p;
+ } stack;
+
+ switch (cmd) {
+ case ZT_ONHOOKTRANSFER:
+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
+ return -EINVAL;
+ if (get_user(x, (int *)data))
+ return -EFAULT;
+ wc->mods[chan->chanpos - 1].fxs.ohttimer = x << 3;
+ wc->mods[chan->chanpos - 1].fxs.idletxhookstate = 0x2; /* OHT mode when idle */
+ if (wc->mods[chan->chanpos - 1].fxs.lasttxhook == 0x1) {
+ /* Apply the change if appropriate */
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x12;
+ wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook);
+ /* wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mods[chan->chanpos - 1].fxs.lasttxhook); */
+ }
+ break;
+ case WCTDM_GET_STATS:
+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
+ stats.tipvolt = wctdm_getreg(wc, chan->chanpos - 1, 80) * -376;
+ stats.ringvolt = wctdm_getreg(wc, chan->chanpos - 1, 81) * -376;
+ stats.batvolt = wctdm_getreg(wc, chan->chanpos - 1, 82) * -376;
+ } else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
+ stats.tipvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000;
+ stats.ringvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000;
+ stats.batvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000;
+ } else
+ return -EINVAL;
+ if (copy_to_user((struct wctdm_stats *)data, &stats, sizeof(stats)))
+ return -EFAULT;
+ break;
+ case WCTDM_GET_REGS:
+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
+ for (x=0;x<NUM_INDIRECT_REGS;x++)
+ regs.indirect[x] = wctdm_proslic_getreg_indirect(wc, chan->chanpos -1, x);
+ for (x=0;x<NUM_REGS;x++)
+ regs.direct[x] = wctdm_getreg(wc, chan->chanpos - 1, x);
+ } else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_QRV) {
+ memset(&regs, 0, sizeof(regs));
+ for (x=0;x<0x32;x++)
+ regs.direct[x] = wctdm_getreg(wc, chan->chanpos - 1, x);
+ } else {
+ memset(&regs, 0, sizeof(regs));
+ for (x=0;x<NUM_FXO_REGS;x++)
+ regs.direct[x] = wctdm_getreg(wc, chan->chanpos - 1, x);
+ }
+ if (copy_to_user((struct wctdm_regs *)data, &regs, sizeof(regs)))
+ return -EFAULT;
+ break;
+ case WCTDM_SET_REG:
+ if (copy_from_user(&regop, (struct wctdm_regop *)data, sizeof(regop)))
+ return -EFAULT;
+ if (regop.indirect) {
+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
+ return -EINVAL;
+ printk("Setting indirect %d to 0x%04x on %d\n", regop.reg, regop.val, chan->chanpos);
+ wctdm_proslic_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val);
+ } else {
+ regop.val &= 0xff;
+ if (regop.reg == 64)
+ wc->mods[chan->chanpos-1].fxs.lasttxhook = (regop.val & 0x0f) | 0x10;
+
+ printk("Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos);
+ wctdm_setreg(wc, chan->chanpos - 1, regop.reg, regop.val);
+ }
+ break;
+ case WCTDM_SET_ECHOTUNE:
+ printk("-- Setting echo registers: \n");
+ if (copy_from_user(&echoregs, (struct wctdm_echo_coefs*)data, sizeof(echoregs)))
+ return -EFAULT;
+
+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
+ /* Set the ACIM register */
+ wctdm_setreg(wc, chan->chanpos - 1, 30, echoregs.acim);
+
+ /* Set the digital echo canceller registers */
+ wctdm_setreg(wc, chan->chanpos - 1, 45, echoregs.coef1);
+ wctdm_setreg(wc, chan->chanpos - 1, 46, echoregs.coef2);
+ wctdm_setreg(wc, chan->chanpos - 1, 47, echoregs.coef3);
+ wctdm_setreg(wc, chan->chanpos - 1, 48, echoregs.coef4);
+ wctdm_setreg(wc, chan->chanpos - 1, 49, echoregs.coef5);
+ wctdm_setreg(wc, chan->chanpos - 1, 50, echoregs.coef6);
+ wctdm_setreg(wc, chan->chanpos - 1, 51, echoregs.coef7);
+ wctdm_setreg(wc, chan->chanpos - 1, 52, echoregs.coef8);
+
+ printk("-- Set echo registers successfully\n");
+
+ break;
+ } else {
+ return -EINVAL;
+
+ }
+ break;
+ case ZT_SET_HWGAIN:
+ if (copy_from_user(&hwgain, (struct zt_hwgain*) data, sizeof(hwgain)))
+ return -EFAULT;
+
+ wctdm_set_hwgain(wc, chan->chanpos-1, hwgain.newgain, hwgain.tx);
+
+ if (debug)
+ printk("Setting hwgain on channel %d to %d for %s direction\n",
+ chan->chanpos-1, hwgain.newgain, hwgain.tx ? "tx" : "rx");
+ break;
+#ifdef VPM_SUPPORT
+ case ZT_TONEDETECT:
+ if (get_user(x, (int *) data))
+ return -EFAULT;
+ if (!wc->vpm && !wc->vpm150m)
+ return -ENOSYS;
+ if ((wc->vpm || wc->vpm150m) && (x && !vpmdtmfsupport))
+ return -ENOSYS;
+ if (x & ZT_TONEDETECT_ON) {
+ set_bit(chan->chanpos - 1, &wc->dtmfmask);
+ } else {
+ clear_bit(chan->chanpos - 1, &wc->dtmfmask);
+ }
+ if (x & ZT_TONEDETECT_MUTE) {
+ if (wc->vpm150m) {
+ set_bit(chan->chanpos - 1, &wc->vpm150m->desireddtmfmutestate);
+ }
+ } else {
+ if (wc->vpm150m) {
+ clear_bit(chan->chanpos - 1, &wc->vpm150m->desireddtmfmutestate);
+ }
+ }
+ return 0;
+#endif
+ case ZT_RADIO_GETPARAM:
+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_QRV)
+ return -ENOTTY;
+ if (copy_from_user(&stack.p,(struct zt_radio_param *)data,sizeof(struct zt_radio_param))) return -EFAULT;
+ stack.p.data = 0; /* start with 0 value in output */
+ switch(stack.p.radpar) {
+ case ZT_RADPAR_INVERTCOR:
+ if (wc->radmode[chan->chanpos - 1] & RADMODE_INVERTCOR)
+ stack.p.data = 1;
+ break;
+ case ZT_RADPAR_IGNORECOR:
+ if (wc->radmode[chan->chanpos - 1] & RADMODE_IGNORECOR)
+ stack.p.data = 1;
+ break;
+ case ZT_RADPAR_IGNORECT:
+ if (wc->radmode[chan->chanpos - 1] & RADMODE_IGNORECT)
+ stack.p.data = 1;
+ break;
+ case ZT_RADPAR_EXTRXTONE:
+ stack.p.data = 0;
+ if (wc->radmode[chan->chanpos - 1] & RADMODE_EXTTONE)
+ {
+ stack.p.data = 1;
+ if (wc->radmode[chan->chanpos - 1] & RADMODE_EXTINVERT)
+ {
+ stack.p.data = 2;
+ }
+ }
+ break;
+ case ZT_RADPAR_DEBOUNCETIME:
+ stack.p.data = wc->debouncetime[chan->chanpos - 1];
+ break;
+ case ZT_RADPAR_RXGAIN:
+ stack.p.data = wc->rxgain[chan->chanpos - 1] - 1199;
+ break;
+ case ZT_RADPAR_TXGAIN:
+ stack.p.data = wc->txgain[chan->chanpos - 1] - 3599;
+ break;
+ case ZT_RADPAR_DEEMP:
+ stack.p.data = 0;
+ if (wc->radmode[chan->chanpos - 1] & RADMODE_DEEMP)
+ {
+ stack.p.data = 1;
+ }
+ break;
+ case ZT_RADPAR_PREEMP:
+ stack.p.data = 0;
+ if (wc->radmode[chan->chanpos - 1] & RADMODE_PREEMP)
+ {
+ stack.p.data = 1;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (copy_to_user((struct zt_radio_param *)data,&stack.p,sizeof(struct zt_radio_param))) return -EFAULT;
+ break;
+ case ZT_RADIO_SETPARAM:
+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_QRV)
+ return -ENOTTY;
+ if (copy_from_user(&stack.p,(struct zt_radio_param *)data,sizeof(struct zt_radio_param))) return -EFAULT;
+ switch(stack.p.radpar) {
+ case ZT_RADPAR_INVERTCOR:
+ if (stack.p.data)
+ wc->radmode[chan->chanpos - 1] |= RADMODE_INVERTCOR;
+ else
+ wc->radmode[chan->chanpos - 1] &= ~RADMODE_INVERTCOR;
+ return 0;
+ case ZT_RADPAR_IGNORECOR:
+ if (stack.p.data)
+ wc->radmode[chan->chanpos - 1] |= RADMODE_IGNORECOR;
+ else
+ wc->radmode[chan->chanpos - 1] &= ~RADMODE_IGNORECOR;
+ return 0;
+ case ZT_RADPAR_IGNORECT:
+ if (stack.p.data)
+ wc->radmode[chan->chanpos - 1] |= RADMODE_IGNORECT;
+ else
+ wc->radmode[chan->chanpos - 1] &= ~RADMODE_IGNORECT;
+ return 0;
+ case ZT_RADPAR_EXTRXTONE:
+ if (stack.p.data)
+ wc->radmode[chan->chanpos - 1] |= RADMODE_EXTTONE;
+ else
+ wc->radmode[chan->chanpos - 1] &= ~RADMODE_EXTTONE;
+ if (stack.p.data > 1)
+ wc->radmode[chan->chanpos - 1] |= RADMODE_EXTINVERT;
+ else
+ wc->radmode[chan->chanpos - 1] &= ~RADMODE_EXTINVERT;
+ return 0;
+ case ZT_RADPAR_DEBOUNCETIME:
+ wc->debouncetime[chan->chanpos - 1] = stack.p.data;
+ return 0;
+ case ZT_RADPAR_RXGAIN:
+ /* if out of range */
+ if ((stack.p.data <= -1200) || (stack.p.data > 1552))
+ {
+ return -EINVAL;
+ }
+ wc->rxgain[chan->chanpos - 1] = stack.p.data + 1199;
+ break;
+ case ZT_RADPAR_TXGAIN:
+ /* if out of range */
+ if (wc->radmode[chan->chanpos -1] & RADMODE_PREEMP)
+ {
+ if ((stack.p.data <= -2400) || (stack.p.data > 0))
+ {
+ return -EINVAL;
+ }
+ }
+ else
+ {
+ if ((stack.p.data <= -3600) || (stack.p.data > 1200))
+ {
+ return -EINVAL;
+ }
+ }
+ wc->txgain[chan->chanpos - 1] = stack.p.data + 3599;
+ break;
+ case ZT_RADPAR_DEEMP:
+ if (stack.p.data)
+ wc->radmode[chan->chanpos - 1] |= RADMODE_DEEMP;
+ else
+ wc->radmode[chan->chanpos - 1] &= ~RADMODE_DEEMP;
+ wc->rxgain[chan->chanpos - 1] = 1199;
+ break;
+ case ZT_RADPAR_PREEMP:
+ if (stack.p.data)
+ wc->radmode[chan->chanpos - 1] |= RADMODE_PREEMP;
+ else
+ wc->radmode[chan->chanpos - 1] &= ~RADMODE_PREEMP;
+ wc->txgain[chan->chanpos - 1] = 3599;
+ break;
+ default:
+ return -EINVAL;
+ }
+ qrv_dosetup(chan,wc);
+ return 0;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int wctdm_open(struct zt_chan *chan)
+{
+ struct wctdm *wc = chan->pvt;
+ if (!(wc->cardflag & (1 << (chan->chanpos - 1))))
+ return -ENODEV;
+ if (wc->dead)
+ return -ENODEV;
+ wc->usecount++;
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#else
+ try_module_get(THIS_MODULE);
+#endif
+ return 0;
+}
+
+static int wctdm_watchdog(struct zt_span *span, int event)
+{
+ printk("TDM: Called watchdog\n");
+ return 0;
+}
+
+static int wctdm_close(struct zt_chan *chan)
+{
+ struct wctdm *wc = chan->pvt;
+ int x;
+ signed char reg;
+ wc->usecount--;
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#else
+ module_put(THIS_MODULE);
+#endif
+ for (x=0;x<wc->cards;x++) {
+ if (wc->modtype[x] == MOD_TYPE_FXS)
+ wc->mods[x].fxs.idletxhookstate = 1;
+ if (wc->modtype[x] == MOD_TYPE_QRV)
+ {
+ int qrvcard = x & 0xfc;
+
+ wc->qrvhook[x] = 0;
+ wc->qrvhook[x + 2] = 0xff;
+ wc->debouncetime[x] = QRV_DEBOUNCETIME;
+ wc->qrvdebtime[x] = 0;
+ wc->radmode[x] = 0;
+ wc->txgain[x] = 3599;
+ wc->rxgain[x] = 1199;
+ reg = 0;
+ if (!wc->qrvhook[qrvcard]) reg |= 1;
+ if (!wc->qrvhook[qrvcard + 1]) reg |= 0x10;
+ wc->sethook[qrvcard] = CMD_WR(3, reg);
+ qrv_dosetup(chan,wc);
+ }
+ }
+ /* If we're dead, release us now */
+ if (!wc->usecount && wc->dead)
+ wctdm_release(wc);
+ return 0;
+}
+
+static int wctdm_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
+{
+ struct wctdm *wc = chan->pvt;
+ int reg=0,qrvcard;
+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_QRV) {
+ qrvcard = (chan->chanpos - 1) & 0xfc;
+ switch(txsig) {
+ case ZT_TXSIG_START:
+ case ZT_TXSIG_OFFHOOK:
+ wc->qrvhook[chan->chanpos - 1] = 1;
+ break;
+ case ZT_TXSIG_ONHOOK:
+ wc->qrvhook[chan->chanpos - 1] = 0;
+ break;
+ default:
+ printk("wctdm24xxp: Can't set tx state to %d\n", txsig);
+ }
+ reg = 0;
+ if (!wc->qrvhook[qrvcard]) reg |= 1;
+ if (!wc->qrvhook[qrvcard + 1]) reg |= 0x10;
+ wc->sethook[qrvcard] = CMD_WR(3, reg);
+ /* wctdm_setreg(wc, qrvcard, 3, reg); */
+ } else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
+ switch(txsig) {
+ case ZT_TXSIG_START:
+ case ZT_TXSIG_OFFHOOK:
+ wc->mods[chan->chanpos - 1].fxo.offhook = 1;
+ wc->sethook[chan->chanpos - 1] = CMD_WR(5, 0x9);
+ /* wctdm_setreg(wc, chan->chanpos - 1, 5, 0x9); */
+ break;
+ case ZT_TXSIG_ONHOOK:
+ wc->mods[chan->chanpos - 1].fxo.offhook = 0;
+ wc->sethook[chan->chanpos - 1] = CMD_WR(5, 0x8);
+ /* wctdm_setreg(wc, chan->chanpos - 1, 5, 0x8); */
+ break;
+ default:
+ printk("wctdm24xxp: Can't set tx state to %d\n", txsig);
+ }
+ } else {
+ switch(txsig) {
+ case ZT_TXSIG_ONHOOK:
+ switch(chan->sig) {
+ case ZT_SIG_EM:
+ case ZT_SIG_FXOKS:
+ case ZT_SIG_FXOLS:
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10 |
+ wc->mods[chan->chanpos - 1].fxs.idletxhookstate;
+ break;
+ case ZT_SIG_FXOGS:
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x13;
+ break;
+ }
+ break;
+ case ZT_TXSIG_OFFHOOK:
+ switch(chan->sig) {
+ case ZT_SIG_EM:
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x15;
+ break;
+ default:
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10 |
+ wc->mods[chan->chanpos - 1].fxs.idletxhookstate;
+ break;
+ }
+ break;
+ case ZT_TXSIG_START:
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x14;
+ break;
+ case ZT_TXSIG_KEWL:
+ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10;
+ break;
+ default:
+ printk("wctdm24xxp: Can't set tx state to %d\n", txsig);
+ }
+ if (debug & DEBUG_CARD)
+ printk("Setting FXS hook state to %d (%02x)\n", txsig, reg);
+
+
+ wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook);
+ /* wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mods[chan->chanpos - 1].fxs.lasttxhook); */
+ }
+ return 0;
+}
+
+static void wctdm_dacs_connect(struct wctdm *wc, int srccard, int dstcard)
+{
+
+ if (wc->dacssrc[dstcard] > - 1) {
+ printk("wctdm_dacs_connect: Can't have double sourcing yet!\n");
+ return;
+ }
+ if (!((wc->modtype[srccard] == MOD_TYPE_FXS)||(wc->modtype[srccard] == MOD_TYPE_FXO))){
+ printk("wctdm_dacs_connect: Unsupported modtype for card %d\n", srccard);
+ return;
+ }
+ if (!((wc->modtype[dstcard] == MOD_TYPE_FXS)||(wc->modtype[dstcard] == MOD_TYPE_FXO))){
+ printk("wctdm_dacs_connect: Unsupported modtype for card %d\n", dstcard);
+ return;
+ }
+ if (debug)
+ printk("connect %d => %d\n", srccard, dstcard);
+ wc->dacssrc[dstcard] = srccard;
+
+ /* make srccard transmit to srccard+24 on the TDM bus */
+ if (wc->modtype[srccard] == MOD_TYPE_FXS) {
+ /* proslic */
+ wctdm_setreg(wc, srccard, PCM_XMIT_START_COUNT_LSB, ((srccard+24) * 8) & 0xff);
+ wctdm_setreg(wc, srccard, PCM_XMIT_START_COUNT_MSB, ((srccard+24) * 8) >> 8);
+ } else if(wc->modtype[srccard] == MOD_TYPE_FXO) {
+ /* daa */
+ wctdm_setreg(wc, srccard, 34, ((srccard+24) * 8) & 0xff); /* TX */
+ wctdm_setreg(wc, srccard, 35, ((srccard+24) * 8) >> 8); /* TX */
+ }
+
+ /* have dstcard receive from srccard+24 on the TDM bus */
+ if (wc->modtype[dstcard] == MOD_TYPE_FXS) {
+ /* proslic */
+ wctdm_setreg(wc, dstcard, PCM_RCV_START_COUNT_LSB, ((srccard+24) * 8) & 0xff);
+ wctdm_setreg(wc, dstcard, PCM_RCV_START_COUNT_MSB, ((srccard+24) * 8) >> 8);
+ } else if(wc->modtype[dstcard] == MOD_TYPE_FXO) {
+ /* daa */
+ wctdm_setreg(wc, dstcard, 36, ((srccard+24) * 8) & 0xff); /* RX */
+ wctdm_setreg(wc, dstcard, 37, ((srccard+24) * 8) >> 8); /* RX */
+ }
+
+}
+
+static void wctdm_dacs_disconnect(struct wctdm *wc, int card)
+{
+ if (wc->dacssrc[card] > -1) {
+ if (debug)
+ printk("wctdm_dacs_disconnect: restoring TX for %d and RX for %d\n",wc->dacssrc[card], card);
+
+ /* restore TX (source card) */
+ if(wc->modtype[wc->dacssrc[card]] == MOD_TYPE_FXS){
+ wctdm_setreg(wc, wc->dacssrc[card], PCM_XMIT_START_COUNT_LSB, (wc->dacssrc[card] * 8) & 0xff);
+ wctdm_setreg(wc, wc->dacssrc[card], PCM_XMIT_START_COUNT_MSB, (wc->dacssrc[card] * 8) >> 8);
+ } else if(wc->modtype[wc->dacssrc[card]] == MOD_TYPE_FXO){
+ wctdm_setreg(wc, card, 34, (card * 8) & 0xff);
+ wctdm_setreg(wc, card, 35, (card * 8) >> 8);
+ } else {
+ printk("WARNING: wctdm_dacs_disconnect() called on unsupported modtype\n");
+ }
+
+ /* restore RX (this card) */
+ if(wc->modtype[card] == MOD_TYPE_FXS){
+ wctdm_setreg(wc, card, PCM_RCV_START_COUNT_LSB, (card * 8) & 0xff);
+ wctdm_setreg(wc, card, PCM_RCV_START_COUNT_MSB, (card * 8) >> 8);
+ } else if(wc->modtype[card] == MOD_TYPE_FXO){
+ wctdm_setreg(wc, card, 36, (card * 8) & 0xff);
+ wctdm_setreg(wc, card, 37, (card * 8) >> 8);
+ } else {
+ printk("WARNING: wctdm_dacs_disconnect() called on unsupported modtype\n");
+ }
+
+ wc->dacssrc[card] = -1;
+ }
+}
+
+static int wctdm_dacs(struct zt_chan *dst, struct zt_chan *src)
+{
+ struct wctdm *wc;
+
+ if(!nativebridge)
+ return 0; /* should this return -1 since unsuccessful? */
+
+ wc = dst->pvt;
+
+ if(src) {
+ wctdm_dacs_connect(wc, src->chanpos - 1, dst->chanpos - 1);
+ if (debug)
+ printk("dacs connecct: %d -> %d!\n\n", src->chanpos, dst->chanpos);
+ } else {
+ wctdm_dacs_disconnect(wc, dst->chanpos - 1);
+ if (debug)
+ printk("dacs disconnect: %d!\n", dst->chanpos);
+ }
+ return 0;
+}
+
+static int wctdm_initialize(struct wctdm *wc)
+{
+ int x;
+ struct pci_dev *pdev = voicebus_get_pci_dev(wc->vb);
+
+ /* Zapata stuff */
+ sprintf(wc->span.name, "WCTDM/%d", wc->pos);
+ snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1);
+ snprintf(wc->span.location, sizeof(wc->span.location) - 1,
+ "PCI%s Bus %02d Slot %02d", (wc->flags[0] & FLAG_EXPRESS) ? " Express" : "",
+ pdev->bus->number, PCI_SLOT(pdev->devfn) + 1);
+ wc->span.manufacturer = "Digium";
+ strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1);
+ if (alawoverride) {
+ printk("ALAW override parameter detected. Device will be operating in ALAW\n");
+ wc->span.deflaw = ZT_LAW_ALAW;
+ } else
+ wc->span.deflaw = ZT_LAW_MULAW;
+ for (x=0;x<wc->cards;x++) {
+ sprintf(wc->chans[x].name, "WCTDM/%d/%d", wc->pos, x);
+ wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_SF | ZT_SIG_EM | ZT_SIG_CLEAR;
+ wc->chans[x].sigcap |= ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF | ZT_SIG_CLEAR;
+ wc->chans[x].chanpos = x+1;
+ wc->chans[x].pvt = wc;
+ }
+ wc->span.chans = wc->chans;
+ wc->span.channels = wc->type;
+ wc->span.irq = pdev->irq;
+ wc->span.hooksig = wctdm_hooksig;
+ wc->span.open = wctdm_open;
+ wc->span.close = wctdm_close;
+ wc->span.flags = ZT_FLAG_RBS;
+ wc->span.ioctl = wctdm_ioctl;
+ wc->span.watchdog = wctdm_watchdog;
+ wc->span.dacs= wctdm_dacs;
+#ifdef VPM_SUPPORT
+ wc->span.echocan_with_params = wctdm_echocan_with_params;
+#endif
+ init_waitqueue_head(&wc->span.maintq);
+
+ wc->span.pvt = wc;
+ return 0;
+}
+
+static void wctdm_post_initialize(struct wctdm *wc)
+{
+ int x;
+
+ /* Finalize signalling */
+ for (x = 0; x <wc->cards; x++) {
+ if (wc->cardflag & (1 << x)) {
+ if (wc->modtype[x] == MOD_TYPE_FXO)
+ wc->chans[x].sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF | ZT_SIG_CLEAR;
+ else if (wc->modtype[x] == MOD_TYPE_FXS)
+ wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_SF | ZT_SIG_EM | ZT_SIG_CLEAR;
+ else if (wc->modtype[x] == MOD_TYPE_QRV)
+ wc->chans[x].sigcap = ZT_SIG_SF | ZT_SIG_EM | ZT_SIG_CLEAR;
+ } else if (!(wc->chans[x].sigcap & ZT_SIG_BROKEN)) {
+ wc->chans[x].sigcap = 0;
+ }
+ }
+
+ if (wc->vpm)
+ strncat(wc->span.devicetype, " with VPM100M", sizeof(wc->span.devicetype) - 1);
+ else if (wc->vpm150m)
+ strncat(wc->span.devicetype, " with VPMADT032", sizeof(wc->span.devicetype) - 1);
+}
+
+#ifdef VPM_SUPPORT
+
+#ifdef VPM150M_SUPPORT
+
+void vpm150m_set_chanconfig_from_state(struct adt_lec_params * parms, int channum, GpakChannelConfig_t *chanconfig)
+{
+ chanconfig->PcmInPortA = 3;
+ chanconfig->PcmInSlotA = channum;
+ chanconfig->PcmOutPortA = SerialPortNull;
+ chanconfig->PcmOutSlotA = channum;
+ chanconfig->PcmInPortB = 2;
+ chanconfig->PcmInSlotB = channum;
+ chanconfig->PcmOutPortB = 3;
+ chanconfig->PcmOutSlotB = channum;
+ if (vpmdtmfsupport) {
+ chanconfig->ToneTypesA = DTMF_tone;
+ chanconfig->MuteToneA = Enabled;
+ chanconfig->FaxCngDetA = Enabled;
+ } else {
+ chanconfig->ToneTypesA = Null_tone;
+ chanconfig->MuteToneA = Disabled;
+ chanconfig->FaxCngDetA = Disabled;
+ }
+ chanconfig->ToneTypesB = Null_tone;
+ chanconfig->EcanEnableA = Enabled;
+ chanconfig->EcanEnableB = Disabled;
+ chanconfig->MuteToneB = Disabled;
+ chanconfig->FaxCngDetB = Disabled;
+
+ if (alawoverride)
+ chanconfig->SoftwareCompand = cmpPCMA;
+ else
+ chanconfig->SoftwareCompand = cmpPCMU;
+
+ chanconfig->FrameRate = rate2ms;
+ chanconfig->EcanParametersA.EcanTapLength = 1024;
+ chanconfig->EcanParametersA.EcanNlpType = parms->nlp_type;
+ chanconfig->EcanParametersA.EcanAdaptEnable = 1;
+ chanconfig->EcanParametersA.EcanG165DetEnable = 1;
+ chanconfig->EcanParametersA.EcanDblTalkThresh = 6;
+ chanconfig->EcanParametersA.EcanNlpThreshold = parms->nlp_threshold;
+ chanconfig->EcanParametersA.EcanNlpConv = 0;
+ chanconfig->EcanParametersA.EcanNlpUnConv = 0;
+ chanconfig->EcanParametersA.EcanNlpMaxSuppress = parms->nlp_max_suppress;
+ chanconfig->EcanParametersA.EcanCngThreshold = 43;
+ chanconfig->EcanParametersA.EcanAdaptLimit = 50;
+ chanconfig->EcanParametersA.EcanCrossCorrLimit = 15;
+ chanconfig->EcanParametersA.EcanNumFirSegments = 3;
+ chanconfig->EcanParametersA.EcanFirSegmentLen = 64;
+
+ chanconfig->EcanParametersB.EcanTapLength = 1024;
+ chanconfig->EcanParametersB.EcanNlpType = parms->nlp_type;
+ chanconfig->EcanParametersB.EcanAdaptEnable = 1;
+ chanconfig->EcanParametersB.EcanG165DetEnable = 1;
+ chanconfig->EcanParametersB.EcanDblTalkThresh = 6;
+ chanconfig->EcanParametersB.EcanNlpThreshold = parms->nlp_threshold;
+ chanconfig->EcanParametersB.EcanNlpConv = 0;
+ chanconfig->EcanParametersB.EcanNlpUnConv = 0;
+ chanconfig->EcanParametersB.EcanNlpMaxSuppress = parms->nlp_max_suppress;
+ chanconfig->EcanParametersB.EcanCngThreshold = 43;
+ chanconfig->EcanParametersB.EcanAdaptLimit = 50;
+ chanconfig->EcanParametersB.EcanCrossCorrLimit = 15;
+ chanconfig->EcanParametersB.EcanNumFirSegments = 3;
+ chanconfig->EcanParametersB.EcanFirSegmentLen = 64;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void vpm150m_bh(void *data)
+{
+ struct vpm150m *vpm150m = data;
+#else
+static void vpm150m_bh(struct work_struct *data)
+{
+ struct vpm150m *vpm150m = container_of(data, struct vpm150m, work);
+#endif
+ struct wctdm *wc = vpm150m->wc;
+ int i;
+
+ for (i = 0; i < wc->type; i++) {
+ int enable = -1;
+ if (test_bit(i, &vpm150m->desireddtmfmutestate)) {
+ if (!test_bit(i, &vpm150m->curdtmfmutestate)) {
+ enable = 1;
+ }
+ } else {
+ if (test_bit(i, &vpm150m->curdtmfmutestate)) {
+ enable = 0;
+ }
+ }
+ if (enable > -1) {
+ unsigned int start = wc->intcount;
+ GPAK_AlgControlStat_t pstatus;
+ int res;
+
+ if (enable) {
+ res = gpakAlgControl(vpm150m->dspid, i, EnableDTMFMuteA, &pstatus);
+ if (debug & DEBUG_ECHOCAN)
+ printk("DTMF mute enable took %d ms\n", wc->intcount - start);
+ } else {
+ res = gpakAlgControl(vpm150m->dspid, i, DisableDTMFMuteA, &pstatus);
+ if (debug & DEBUG_ECHOCAN)
+ printk("DTMF mute disable took %d ms\n", wc->intcount - start);
+ }
+ if (!res)
+ change_bit(i, &vpm150m->curdtmfmutestate);
+ }
+ }
+
+ if (test_bit(VPM150M_DTMFDETECT, &vpm150m->control)) {
+ unsigned short channel;
+ GpakAsyncEventCode_t eventcode;
+ GpakAsyncEventData_t eventdata;
+ gpakReadEventFIFOMessageStat_t res;
+ unsigned int start = wc->intcount;
+
+ do {
+ res = gpakReadEventFIFOMessage(vpm150m->dspid, &channel, &eventcode, &eventdata);
+
+ if (debug & DEBUG_ECHOCAN)
+ printk("ReadEventFIFOMessage took %d ms\n", wc->intcount - start);
+
+ if (res == RefInvalidEvent || res == RefDspCommFailure) {
+ printk("VPM Comm Error\n");
+ continue;
+ }
+
+ if (res == RefNoEventAvail) {
+ continue;
+ }
+
+ if (eventcode == EventToneDetect) {
+ GpakToneCodes_t tone = eventdata.toneEvent.ToneCode;
+ int duration = eventdata.toneEvent.ToneDuration;
+ char zaptone = vpm150mtone_to_zaptone(tone);
+
+ if (debug & DEBUG_ECHOCAN)
+ printk("Channel %d: Detected DTMF tone %d of duration %d!!!\n", channel + 1, tone, duration);
+
+ if (test_bit(channel, &wc->dtmfmask) && (eventdata.toneEvent.ToneDuration > 0)) {
+ struct zt_chan *chan = &wc->chans[channel];
+
+ if ((tone != EndofMFDigit) && (zaptone != 0)) {
+ vpm150m->curtone[channel] = tone;
+
+ if (test_bit(channel, &vpm150m->curdtmfmutestate)) {
+ unsigned long flags;
+ int y;
+
+ /* Mute the audio data buffers */
+ spin_lock_irqsave(&chan->lock, flags);
+ for (y = 0; y < chan->numbufs; y++) {
+ if ((chan->inreadbuf > -1) && (chan->readidx[y]))
+ memset(chan->readbuf[chan->inreadbuf], ZT_XLAW(0, chan), chan->readidx[y]);
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ }
+ if (!test_bit(channel, &wc->dtmfactive)) {
+ if (debug & DEBUG_ECHOCAN)
+ printk("Queuing DTMFDOWN %c\n", zaptone);
+ set_bit(channel, &wc->dtmfactive);
+ zt_qevent_lock(chan, (ZT_EVENT_DTMFDOWN | zaptone));
+ }
+ } else if ((tone == EndofMFDigit) && test_bit(channel, &wc->dtmfactive)) {
+ if (debug & DEBUG_ECHOCAN)
+ printk("Queuing DTMFUP %c\n", vpm150mtone_to_zaptone(vpm150m->curtone[channel]));
+ zt_qevent_lock(chan, (ZT_EVENT_DTMFUP | vpm150mtone_to_zaptone(vpm150m->curtone[channel])));
+ clear_bit(channel, &wc->dtmfactive);
+ }
+ }
+ }
+ } while ((res != RefNoEventAvail) && (res != RefInvalidEvent) && (res != RefDspCommFailure));
+ }
+
+ for (i = 0; i < wc->type; i++) {
+ unsigned int start = wc->intcount;
+ GPAK_AlgControlStat_t pstatus;
+ int res = 1;
+
+ if ((vpm150m->desiredecstate[i].nlp_type != vpm150m->curecstate[i].nlp_type)
+ || (vpm150m->desiredecstate[i].nlp_threshold != vpm150m->curecstate[i].nlp_threshold)
+ || (vpm150m->desiredecstate[i].nlp_max_suppress != vpm150m->curecstate[i].nlp_max_suppress)) {
+
+ GPAK_ChannelConfigStat_t cstatus;
+ GPAK_TearDownChanStat_t tstatus;
+ GpakChannelConfig_t chanconfig;
+
+ if (debug & DEBUG_ECHOCAN)
+ printk("Reconfiguring chan %d for nlp %d, nlp_thresh %d, and max_supp %d\n", i + 1, vpm150m->desiredecstate[i].nlp_type,
+ vpm150m->desiredecstate[i].nlp_threshold, vpm150m->desiredecstate[i].nlp_max_suppress);
+
+ vpm150m_set_chanconfig_from_state(&vpm150m->desiredecstate[i], i, &chanconfig);
+
+ if ((res = gpakTearDownChannel(vpm150m->dspid, i, &tstatus))) {
+ goto vpm_bh_out;
+ }
+
+ if ((res = gpakConfigureChannel(vpm150m->dspid, i, tdmToTdm, &chanconfig, &cstatus))) {
+ goto vpm_bh_out;
+ }
+
+ if (!vpm150m->desiredecstate[i].tap_length)
+ res = gpakAlgControl(vpm150m->dspid, i, BypassEcanA, &pstatus);
+
+ } else if (vpm150m->desiredecstate[i].tap_length != vpm150m->curecstate[i].tap_length) {
+ if (vpm150m->desiredecstate[i].tap_length) {
+ res = gpakAlgControl(vpm150m->dspid, i, EnableEcanA, &pstatus);
+ if (debug & DEBUG_ECHOCAN)
+ printk("Echocan enable took %d ms\n", wc->intcount - start);
+ } else {
+ res = gpakAlgControl(vpm150m->dspid, i, BypassEcanA, &pstatus);
+ if (debug & DEBUG_ECHOCAN)
+ printk("Echocan disable took %d ms\n", wc->intcount - start);
+ }
+ }
+
+vpm_bh_out:
+ if (!res)
+ vpm150m->curecstate[i] = vpm150m->desiredecstate[i];
+ }
+
+ return;
+}
+
+static int vpm150m_config_hw(struct wctdm *wc)
+{
+ struct vpm150m *vpm150m = wc->vpm150m;
+ gpakConfigPortStatus_t configportstatus;
+ GpakPortConfig_t portconfig;
+ GPAK_PortConfigStat_t pstatus;
+ GpakChannelConfig_t chanconfig;
+ GPAK_ChannelConfigStat_t cstatus;
+ GPAK_AlgControlStat_t algstatus;
+
+ int res, i;
+
+ memset(&portconfig, 0, sizeof(GpakPortConfig_t));
+
+ /* First Serial Port config */
+ portconfig.SlotsSelect1 = SlotCfgNone;
+ portconfig.FirstBlockNum1 = 0;
+ portconfig.FirstSlotMask1 = 0x0000;
+ portconfig.SecBlockNum1 = 1;
+ portconfig.SecSlotMask1 = 0x0000;
+ portconfig.SerialWordSize1 = SerWordSize8;
+ portconfig.CompandingMode1 = cmpNone;
+ portconfig.TxFrameSyncPolarity1 = FrameSyncActHigh;
+ portconfig.RxFrameSyncPolarity1 = FrameSyncActHigh;
+ portconfig.TxClockPolarity1 = SerClockActHigh;
+ portconfig.RxClockPolarity1 = SerClockActHigh;
+ portconfig.TxDataDelay1 = DataDelay0;
+ portconfig.RxDataDelay1 = DataDelay0;
+ portconfig.DxDelay1 = Disabled;
+ portconfig.ThirdSlotMask1 = 0x0000;
+ portconfig.FouthSlotMask1 = 0x0000;
+ portconfig.FifthSlotMask1 = 0x0000;
+ portconfig.SixthSlotMask1 = 0x0000;
+ portconfig.SevenSlotMask1 = 0x0000;
+ portconfig.EightSlotMask1 = 0x0000;
+
+ /* Second Serial Port config */
+ portconfig.SlotsSelect2 = SlotCfg2Groups;
+ portconfig.FirstBlockNum2 = 0;
+ portconfig.FirstSlotMask2 = 0xffff;
+ portconfig.SecBlockNum2 = 1;
+ portconfig.SecSlotMask2 = 0xffff;
+ portconfig.SerialWordSize2 = SerWordSize8;
+ portconfig.CompandingMode2 = cmpNone;
+ portconfig.TxFrameSyncPolarity2 = FrameSyncActHigh;
+ portconfig.RxFrameSyncPolarity2 = FrameSyncActHigh;
+ portconfig.TxClockPolarity2 = SerClockActHigh;
+ portconfig.RxClockPolarity2 = SerClockActLow;
+ portconfig.TxDataDelay2 = DataDelay0;
+ portconfig.RxDataDelay2 = DataDelay0;
+ portconfig.DxDelay2 = Disabled;
+ portconfig.ThirdSlotMask2 = 0x0000;
+ portconfig.FouthSlotMask2 = 0x0000;
+ portconfig.FifthSlotMask2 = 0x0000;
+ portconfig.SixthSlotMask2 = 0x0000;
+ portconfig.SevenSlotMask2 = 0x0000;
+ portconfig.EightSlotMask2 = 0x0000;
+
+ /* Third Serial Port Config */
+ portconfig.SlotsSelect3 = SlotCfg2Groups;
+ portconfig.FirstBlockNum3 = 0;
+ portconfig.FirstSlotMask3 = 0xffff;
+ portconfig.SecBlockNum3 = 1;
+ portconfig.SecSlotMask3 = 0xffff;
+ portconfig.SerialWordSize3 = SerWordSize8;
+ portconfig.CompandingMode3 = cmpNone;
+ portconfig.TxFrameSyncPolarity3 = FrameSyncActHigh;
+ portconfig.RxFrameSyncPolarity3 = FrameSyncActHigh;
+ portconfig.TxClockPolarity3 = SerClockActHigh;
+ portconfig.RxClockPolarity3 = SerClockActLow;
+ portconfig.TxDataDelay3 = DataDelay0;
+ portconfig.RxDataDelay3 = DataDelay0;
+ portconfig.DxDelay3 = Disabled;
+ portconfig.ThirdSlotMask3 = 0x0000;
+ portconfig.FouthSlotMask3 = 0x0000;
+ portconfig.FifthSlotMask3 = 0x0000;
+ portconfig.SixthSlotMask3 = 0x0000;
+ portconfig.SevenSlotMask3 = 0x0000;
+ portconfig.EightSlotMask3 = 0x0000;
+
+ if ((configportstatus = gpakConfigurePorts(vpm150m->dspid, &portconfig, &pstatus))) {
+ printk("Configuration of ports failed (%d)!\n", configportstatus);
+ return -1;
+ } else {
+ if (debug & DEBUG_ECHOCAN)
+ printk("Configured McBSP ports successfully\n");
+ }
+
+ if ((res = gpakPingDsp(vpm150m->dspid, &vpm150m->version))) {
+ printk("Error pinging DSP (%d)\n", res);
+ return -1;
+ }
+
+ for (i = 0; i < wc->type; i++) {
+ vpm150m->curecstate[i].tap_length = 0;
+ vpm150m->curecstate[i].nlp_type = vpmnlptype;
+ vpm150m->curecstate[i].nlp_threshold = vpmnlpthresh;
+ vpm150m->curecstate[i].nlp_max_suppress = vpmnlpmaxsupp;
+
+ vpm150m->desiredecstate[i].tap_length = 0;
+ vpm150m->desiredecstate[i].nlp_type = vpmnlptype;
+ vpm150m->desiredecstate[i].nlp_threshold = vpmnlpthresh;
+ vpm150m->desiredecstate[i].nlp_max_suppress = vpmnlpmaxsupp;
+
+ vpm150m_set_chanconfig_from_state(&vpm150m->curecstate[i], i, &chanconfig);
+
+ if ((res = gpakConfigureChannel(vpm150m->dspid, i, tdmToTdm, &chanconfig, &cstatus))) {
+ printk("Unable to configure channel (%d)\n", res);
+ if (res == 1) {
+ printk("Reason %d\n", cstatus);
+ }
+
+ return -1;
+ }
+
+ if ((res = gpakAlgControl(vpm150m->dspid, i, BypassEcanA, &algstatus))) {
+ printk("Unable to disable echo can on channel %d (reason %d:%d)\n", i + 1, res, algstatus);
+ return -1;
+ }
+
+ if (vpmdtmfsupport) {
+ if ((res = gpakAlgControl(vpm150m->dspid, i, DisableDTMFMuteA, &algstatus))) {
+ printk("Unable to disable dtmf muting on channel %d (reason %d:%d)\n", i + 1, res, algstatus);
+ return -1;
+ }
+ }
+ }
+
+ if ((res = gpakPingDsp(vpm150m->dspid, &vpm150m->version))) {
+ printk("Error pinging DSP (%d)\n", res);
+ return -1;
+ }
+
+ vpm150m->wq = create_singlethread_workqueue("wctdm24xxp");
+ vpm150m->wc = wc;
+
+ if (!vpm150m->wq) {
+ printk("Unable to create work queue!\n");
+ return -1;
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ INIT_WORK(&vpm150m->work, vpm150m_bh, vpm150m);
+#else
+ INIT_WORK(&vpm150m->work, vpm150m_bh);
+#endif
+
+ /* Turn on DTMF detection */
+ if (vpmdtmfsupport)
+ set_bit(VPM150M_DTMFDETECT, &vpm150m->control);
+
+ set_bit(VPM150M_ACTIVE, &vpm150m->control);
+
+ return 0;
+}
+#endif /* VPM150M_SUPPORT */
+
+enum vpmadt032_init_result {
+ VPMADT032_SUCCESS,
+ VPMADT032_NOT_FOUND,
+ VPMADT032_FAILED,
+ VPMADT032_DISABLED,
+};
+
+static enum vpmadt032_init_result wctdm_vpm150m_init(struct wctdm *wc)
+{
+ unsigned short i;
+ struct vpm150m *vpm150m;
+ unsigned short reg;
+ unsigned long flags;
+ struct pci_dev* pdev = voicebus_get_pci_dev(wc->vb);
+ enum vpmadt032_init_result res = VPMADT032_FAILED;
+
+#ifdef VPM150M_SUPPORT
+ struct wctdm_firmware fw;
+ struct firmware embedded_firmware;
+ const struct firmware *firmware = &embedded_firmware;
+#if !defined(HOTPLUG_FIRMWARE)
+ extern void _binary_zaptel_fw_vpmadt032_bin_size;
+ extern u8 _binary_zaptel_fw_vpmadt032_bin_start[];
+#else
+ static const char vpmadt032_firmware[] = "zaptel-fw-vpmadt032.bin";
+#endif
+ gpakDownloadStatus_t downloadstatus;
+ gpakPingDspStat_t pingstatus;
+#endif
+
+ if (!vpmsupport) {
+ printk("VPM: Support Disabled\n");
+ wc->vpm150m = NULL;
+ return VPMADT032_DISABLED;
+ }
+
+ vpm150m = kmalloc(sizeof(struct vpm150m), GFP_KERNEL);
+
+ if (!vpm150m) {
+ printk("Unable to allocate VPM150M!\n");
+ return VPMADT032_FAILED;
+ }
+
+ memset(vpm150m, 0, sizeof(struct vpm150m));
+
+ /* Init our vpm150m struct */
+ sema_init(&vpm150m->sem, 1);
+ vpm150m->curpage = 0x80;
+
+ for (i = 0; i < WC_MAX_IFACES; i++) {
+ if (ifaces[i] == wc)
+ vpm150m->dspid = i;
+ }
+
+ if (debug & DEBUG_ECHOCAN)
+ printk("Setting VPMADT032 DSP ID to %d\n", vpm150m->dspid);
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->vpm150m = vpm150m;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ for (i = 0; i < 10; i++)
+ schluffen(&wc->regq);
+
+ if (debug & DEBUG_ECHOCAN)
+ printk("VPMADT032 Testing page access: ");
+ for (i = 0; i < 0xf; i++) {
+ int x;
+ for (x = 0; x < 3; x++) {
+ wctdm_vpm150m_setpage(wc, i);
+ reg = wctdm_vpm150m_getpage(wc);
+ if (reg != i) {
+ if (debug & DEBUG_ECHOCAN)
+ printk("Failed: Sent %x != %x VPMADT032 Failed HI page test\n", i, reg);
+ res = VPMADT032_NOT_FOUND;
+ goto failed_exit;
+ }
+ }
+ }
+ if (debug & DEBUG_ECHOCAN)
+ printk("Passed\n");
+
+ /* Set us up to page 0 */
+ wctdm_vpm150m_setpage(wc, 0);
+ if (debug & DEBUG_ECHOCAN)
+ printk("VPMADT032 now doing address test: ");
+ for (i = 0; i < 16; i++) {
+ int x;
+ for (x = 0; x < 2; x++) {
+ wctdm_vpm150m_setreg(wc, 1, 0x1000, &i);
+ wctdm_vpm150m_getreg(wc, 1, 0x1000, &reg);
+ if (reg != i) {
+ printk("VPMADT032 Failed address test\n");
+ goto failed_exit;
+ }
+
+ }
+ }
+ if (debug & DEBUG_ECHOCAN)
+ printk("Passed\n");
+
+#ifndef VPM150M_SUPPORT
+ printk("Found VPMADT032 module but it is not able to function in anything less than a version 2.6 kernel\n");
+ printk("Please update your kernel to a 2.6 or later kernel to enable it\n");
+ goto failed_exit;
+#else
+
+#if 0
+ /* Load the firmware */
+ set_bit(VPM150M_SPIRESET, &vpm150m->control);
+
+ /* Wait for it to boot */
+ msleep(7000);
+
+ pingstatus = gpakPingDsp(vpm150m->dspid, &version);
+
+ if (pingstatus || (version != 0x106)) {
+#endif
+#if defined(HOTPLUG_FIRMWARE)
+ if ((request_firmware(&firmware, vpmadt032_firmware, &pdev->dev) != 0) ||
+ !firmware) {
+ printk("VPMADT032: firmware %s not available from userspace\n", vpmadt032_firmware);
+ goto failed_exit;
+ }
+#else
+ embedded_firmware.data = _binary_zaptel_fw_vpmadt032_bin_start;
+ embedded_firmware.size = (size_t) &_binary_zaptel_fw_vpmadt032_bin_size;
+#endif
+ fw.fw = firmware;
+ fw.offset = 0;
+
+ set_bit(VPM150M_HPIRESET, &vpm150m->control);
+
+ while (test_bit(VPM150M_HPIRESET, &vpm150m->control))
+ schluffen(&wc->regq);
+
+ printk("VPMADT032 Loading firwmare... ");
+ downloadstatus = gpakDownloadDsp(vpm150m->dspid, &fw);
+
+ if (firmware != &embedded_firmware)
+ release_firmware(firmware);
+
+ if (downloadstatus != 0) {
+ printk("Unable to download firmware to VPMADT032 with cause %d\n", downloadstatus);
+ goto failed_exit;
+ } else {
+ printk("Success\n");
+ }
+
+ set_bit(VPM150M_SWRESET, &vpm150m->control);
+
+ while (test_bit(VPM150M_SWRESET, &vpm150m->control))
+ schluffen(&wc->regq);
+
+#if 0
+ }
+#endif
+
+ pingstatus = gpakPingDsp(vpm150m->dspid, &vpm150m->version);
+
+ if (!pingstatus) {
+ if (debug & DEBUG_ECHOCAN)
+ printk("Version of DSP is %x\n", vpm150m->version);
+ } else {
+ printk("VPMADT032 Failed! Unable to ping the DSP (%d)!\n", pingstatus);
+ goto failed_exit;
+ }
+
+ if (vpm150m_config_hw(wc)) {
+ goto failed_exit;
+ }
+
+ return VPMADT032_SUCCESS;
+#endif /* VPM150M_SUPPORT */
+
+failed_exit:
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->vpm150m = NULL;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ kfree(vpm150m);
+
+ return res;
+}
+
+static void wctdm_vpm_set_dtmf_threshold(struct wctdm *wc, unsigned int threshold)
+{
+ unsigned int x;
+
+ for (x = 0; x < 4; x++) {
+ wctdm_vpm_out(wc, x, 0xC4, (threshold >> 8) & 0xFF);
+ wctdm_vpm_out(wc, x, 0xC5, (threshold & 0xFF));
+ }
+ printk("VPM: DTMF threshold set to %d\n", threshold);
+}
+
+static void wctdm_vpm_init(struct wctdm *wc)
+{
+ unsigned char reg;
+ unsigned int mask;
+ unsigned int ver;
+ unsigned char vpmver=0;
+ unsigned int i, x, y;
+
+ if (!vpmsupport) {
+ printk("VPM: Support Disabled\n");
+ wc->vpm = 0;
+ return;
+ }
+
+ for (x=0;x<NUM_EC;x++) {
+ ver = wctdm_vpm_in(wc, x, 0x1a0); /* revision */
+ if (debug & DEBUG_ECHOCAN)
+ printk("VPM100: Chip %d: ver %02x\n", x, ver);
+ if (ver != 0x33) {
+ printk("VPM100: %s\n", x ? "Inoperable" : "Not Present");
+ wc->vpm = 0;
+ return;
+ }
+
+ if (!x) {
+ vpmver = wctdm_vpm_in(wc, x, 0x1a6) & 0xf;
+ printk("VPM Revision: %02x\n", vpmver);
+ }
+
+
+ /* Setup GPIO's */
+ for (y=0;y<4;y++) {
+ wctdm_vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */
+ if (y == 3)
+ wctdm_vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */
+ else
+ wctdm_vpm_out(wc, x, 0x1ac + y, 0xff); /* GPIO dir */
+ wctdm_vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */
+ }
+
+ /* Setup TDM path - sets fsync and tdm_clk as inputs */
+ reg = wctdm_vpm_in(wc, x, 0x1a3); /* misc_con */
+ wctdm_vpm_out(wc, x, 0x1a3, reg & ~2);
+
+ /* Setup Echo length (256 taps) */
+ wctdm_vpm_out(wc, x, 0x022, 0);
+
+ /* Setup timeslots */
+ if (vpmver == 0x01) {
+ wctdm_vpm_out(wc, x, 0x02f, 0x00);
+ wctdm_vpm_out(wc, x, 0x023, 0xff);
+ mask = 0x11111111 << x;
+ } else {
+ wctdm_vpm_out(wc, x, 0x02f, 0x20 | (x << 3));
+ wctdm_vpm_out(wc, x, 0x023, 0x3f);
+ mask = 0x0000003f;
+ }
+
+ /* Setup the tdm channel masks for all chips*/
+ for (i = 0; i < 4; i++)
+ wctdm_vpm_out(wc, x, 0x33 - i, (mask >> (i << 3)) & 0xff);
+
+ /* Setup convergence rate */
+ reg = wctdm_vpm_in(wc,x,0x20);
+ reg &= 0xE0;
+ if (alawoverride) {
+ if (!x)
+ printk("VPM: A-law mode\n");
+ reg |= 0x01;
+ } else {
+ if (!x)
+ printk("VPM: U-law mode\n");
+ reg &= ~0x01;
+ }
+ wctdm_vpm_out(wc,x,0x20,(reg | 0x20));
+
+ /* Initialize echo cans */
+ for (i = 0 ; i < MAX_TDM_CHAN; i++) {
+ if (mask & (0x00000001 << i))
+ wctdm_vpm_out(wc,x,i,0x00);
+ }
+
+ for (i=0;i<30;i++)
+ schluffen(&wc->regq);
+
+ /* Put in bypass mode */
+ for (i = 0 ; i < MAX_TDM_CHAN ; i++) {
+ if (mask & (0x00000001 << i)) {
+ wctdm_vpm_out(wc,x,i,0x01);
+ }
+ }
+
+ /* Enable bypass */
+ for (i = 0 ; i < MAX_TDM_CHAN ; i++) {
+ if (mask & (0x00000001 << i))
+ wctdm_vpm_out(wc,x,0x78 + i,0x01);
+ }
+
+ /* Enable DTMF detectors (always DTMF detect all spans) */
+ for (i = 0; i < 6; i++) {
+ if (vpmver == 0x01)
+ wctdm_vpm_out(wc, x, 0x98 + i, 0x40 | (i << 2) | x);
+ else
+ wctdm_vpm_out(wc, x, 0x98 + i, 0x40 | i);
+ }
+
+ for (i = 0xB8; i < 0xC0; i++)
+ wctdm_vpm_out(wc, x, i, 0xFF);
+ for (i = 0xC0; i < 0xC4; i++)
+ wctdm_vpm_out(wc, x, i, 0xff);
+
+ }
+ /* set DTMF detection threshold */
+ wctdm_vpm_set_dtmf_threshold(wc, dtmfthreshold);
+
+ if (vpmver == 0x01)
+ wc->vpm = 2;
+ else
+ wc->vpm = 1;
+
+ printk("Enabling VPM100 gain adjustments on any FXO ports found\n");
+ for (i = 0; i < wc->type; i++) {
+ if (wc->modtype[i] == MOD_TYPE_FXO) {
+ /* Apply negative Tx gain of 4.5db to DAA */
+ wctdm_setreg(wc, i, 38, 0x14); /* 4db */
+ wctdm_setreg(wc, i, 40, 0x15); /* 0.5db */
+
+ /* Apply negative Rx gain of 4.5db to DAA */
+ wctdm_setreg(wc, i, 39, 0x14); /* 4db */
+ wctdm_setreg(wc, i, 41, 0x15); /* 0.5db */
+ }
+ }
+
+}
+
+#endif
+
+static int wctdm_locate_modules(struct wctdm *wc)
+{
+ int x;
+ unsigned long flags;
+ unsigned int startinglatency = voicebus_current_latency(wc->vb);
+ wc->ctlreg = 0x00;
+
+ /* Make sure all units go into daisy chain mode */
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->span.irqmisses = 0;
+ for (x=0;x<wc->cards;x++)
+ wc->modtype[x] = MOD_TYPE_FXSINIT;
+#ifdef VPM_SUPPORT
+ wc->vpm = -1;
+ for (x = wc->cards; x < wc->cards+NUM_EC; x++)
+ wc->modtype[x] = MOD_TYPE_VPM;
+#endif
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ /* Wait just a bit */
+ for (x=0;x<10;x++)
+ schluffen(&wc->regq);
+ spin_lock_irqsave(&wc->reglock, flags);
+ for (x=0;x<wc->cards;x++)
+ wc->modtype[x] = MOD_TYPE_FXS;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+#if 0
+ /* XXX */
+ cmddesc = 0;
+#endif
+ /* Now that all the cards have been reset, we can stop checking them all if there aren't as many */
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->cards = wc->type;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ /* Reset modules */
+ for (x=0;x<wc->cards;x++) {
+ int sane=0,ret=0,readi=0;
+retry:
+ if (voicebus_current_latency(wc->vb) > startinglatency) {
+ return -EAGAIN;
+ }
+ /* Init with Auto Calibration */
+ if (!(ret = wctdm_init_proslic(wc, x, 0, 0, sane))) {
+ wc->cardflag |= (1 << x);
+ if (debug & DEBUG_CARD) {
+ readi = wctdm_getreg(wc,x,LOOP_I_LIMIT);
+ printk("Proslic module %d loop current is %dmA\n",x,
+ ((readi*3)+20));
+ }
+ printk("Port %d: Installed -- AUTO FXS/DPO\n", x + 1);
+ } else {
+ if(ret!=-2) {
+ sane=1;
+ /* Init with Manual Calibration */
+ if (!wctdm_init_proslic(wc, x, 0, 1, sane)) {
+ wc->cardflag |= (1 << x);
+ if (debug & DEBUG_CARD) {
+ readi = wctdm_getreg(wc,x,LOOP_I_LIMIT);
+ printk("Proslic module %d loop current is %dmA\n",x,
+ ((readi*3)+20));
+ }
+ printk("Port %d: Installed -- MANUAL FXS\n",x + 1);
+ } else {
+ printk("Port %d: FAILED FXS (%s)\n", x + 1, fxshonormode ? fxo_modes[_opermode].name : "FCC");
+ wc->chans[x].sigcap = ZT_SIG_BROKEN | __ZT_SIG_FXO;
+ }
+ } else if (!(ret = wctdm_init_voicedaa(wc, x, 0, 0, sane))) {
+ wc->cardflag |= (1 << x);
+ printk("Port %d: Installed -- AUTO FXO (%s mode)\n",x + 1, fxo_modes[_opermode].name);
+ } else if (!wctdm_init_qrvdri(wc,x)) {
+ wc->cardflag |= 1 << x;
+ printk("Port %d: Installed -- QRV DRI card\n",x + 1);
+ } else {
+ if ((wc->type != 24) && ((x & 0x3) == 1) && !wc->altcs[x]) {
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->altcs[x] = 2;
+ if (wc->type == 4) {
+ wc->altcs[x+1] = 3;
+ wc->altcs[x+2] = 3;
+ }
+ wc->modtype[x] = MOD_TYPE_FXSINIT;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ schluffen(&wc->regq);
+ schluffen(&wc->regq);
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->modtype[x] = MOD_TYPE_FXS;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (debug & DEBUG_CARD)
+ printk("Trying port %d with alternate chip select\n", x + 1);
+ goto retry;
+ } else {
+ printk("Port %d: Not installed\n", x + 1);
+ wc->modtype[x] = MOD_TYPE_NONE;
+ wc->cardflag |= (1 << x);
+ }
+ }
+ }
+ }
+#ifdef VPM_SUPPORT
+ wctdm_vpm_init(wc);
+ if (wc->vpm) {
+ printk("VPM: Present and operational (Rev %c)\n", 'A' + wc->vpm - 1);
+ wc->ctlreg |= 0x10;
+ } else {
+ enum vpmadt032_init_result res;
+ spin_lock_irqsave(&wc->reglock, flags);
+ for (x = NUM_CARDS; x < NUM_CARDS + NUM_EC; x++)
+ wc->modtype[x] = MOD_TYPE_NONE;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ res = wctdm_vpm150m_init(wc);
+ /* In case there was an error while we were loading the VPM module. */
+ if (voicebus_current_latency(wc->vb) > startinglatency) {
+ return -EAGAIN;
+ }
+ switch (res) {
+ case VPMADT032_SUCCESS:
+ printk("VPMADT032: Present and operational (Firmware version %x)\n", wc->vpm150m->version);
+ wc->ctlreg |= 0x10;
+ break;
+ case VPMADT032_DISABLED:
+ case VPMADT032_NOT_FOUND:
+ /* nothing */
+ break;
+ default:
+ return -EIO;
+ }
+ }
+#endif
+ /* In case there was an error while we were loading the VPM module. */
+ if (voicebus_current_latency(wc->vb) > startinglatency) {
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static struct pci_driver wctdm_driver;
+
+static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct wctdm *wc;
+ struct wctdm_desc *d = (struct wctdm_desc *)ent->driver_data;
+ int i;
+ int y;
+ int ret;
+
+retry:
+ wc = kmalloc(sizeof(struct wctdm), GFP_KERNEL);
+ if (!wc) {
+ /* \todo Print debug message. */
+ return -ENOMEM;
+ }
+ memset(wc, 0, sizeof(*wc));
+ spin_lock(&ifacelock);
+ /* \todo this is a candidate for removal... */
+ for (i = 0; i < WC_MAX_IFACES; ++i) {
+ if (!ifaces[i]) {
+ ifaces[i] = wc;
+ break;
+ }
+ }
+ spin_unlock(&ifacelock);
+
+ snprintf(wc->board_name, sizeof(wc->board_name)-1, "%s%d",
+ wctdm_driver.name, i);
+ ret = voicebus_init(pdev, SFRAME_SIZE, wc->board_name,
+ handle_receive, handle_transmit, wc, &wc->vb);
+ if (ret) {
+ kfree(wc);
+ return ret;
+ }
+ BUG_ON(!wc->vb);
+
+ if (VOICEBUS_DEFAULT_LATENCY != latency) {
+ voicebus_set_minlatency(wc->vb, latency);
+ }
+
+ spin_lock_init(&wc->reglock);
+ wc->curcard = -1;
+ wc->cards = NUM_CARDS;
+ wc->type = d->ports;
+ wc->pos = i;
+ wc->variety = d->name;
+ wc->txident = 1;
+ for (y=0;y<NUM_CARDS;y++) {
+ wc->flags[y] = d->flags;
+ wc->dacssrc[y] = -1;
+ }
+
+ init_waitqueue_head(&wc->regq);
+
+ if (wctdm_initialize(wc)) {
+ voicebus_release(wc->vb);
+ wc->vb = NULL;
+ kfree(wc);
+ return -EIO;
+ }
+
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, wc);
+
+ /* Start the hardware processing. */
+ if (voicebus_start(wc->vb)) {
+ BUG_ON(1);
+ }
+
+ /* Now track down what modules are installed */
+ ret = wctdm_locate_modules(wc);
+ if (-EAGAIN == ret ) {
+ /* The voicebus library increased the latency during
+ * initialization. There is a chance that the hardware is in
+ * an inconsistent state, so lets increase the default latency
+ * and start the initialization over.
+ */
+ printk(KERN_NOTICE "%s: Restarting board initialization " \
+ "after increasing latency.\n", wc->board_name);
+ latency = voicebus_current_latency(wc->vb);
+ wctdm_release(wc);
+ goto retry;
+ }
+
+ /* Final initialization */
+ wctdm_post_initialize(wc);
+
+ /* We should be ready for zaptel to come in now. */
+ if (zt_register(&wc->span, 0)) {
+ printk("Unable to register span with zaptel\n");
+ return -1;
+ }
+
+ wc->initialized = 1;
+
+ printk("Found a Wildcard TDM: %s (%d modules)\n", wc->variety, wc->type);
+ ret = 0;
+
+ return ret;
+}
+
+static void wctdm_release(struct wctdm *wc)
+{
+ int i;
+
+ if (wc->initialized) {
+ zt_unregister(&wc->span);
+ }
+
+ voicebus_release(wc->vb);
+ wc->vb = NULL;
+
+ spin_lock(&ifacelock);
+ for (i = 0; i < WC_MAX_IFACES; i++)
+ if (ifaces[i] == wc)
+ break;
+ ifaces[i] = NULL;
+ spin_unlock(&ifacelock);
+
+ kfree(wc);
+}
+
+static void __devexit wctdm_remove_one(struct pci_dev *pdev)
+{
+ struct wctdm *wc = pci_get_drvdata(pdev);
+
+#ifdef VPM150M_SUPPORT
+ unsigned long flags;
+ struct vpm150m *vpm150m = wc->vpm150m;
+#endif
+
+ if (wc) {
+
+#ifdef VPM150M_SUPPORT
+ if (vpm150m) {
+ clear_bit(VPM150M_DTMFDETECT, &vpm150m->control);
+ clear_bit(VPM150M_ACTIVE, &vpm150m->control);
+ flush_workqueue(vpm150m->wq);
+ destroy_workqueue(vpm150m->wq);
+ }
+#endif
+ voicebus_stop(wc->vb);
+
+#ifdef VPM150M_SUPPORT
+ if (vpm150m) {
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->vpm150m = NULL;
+ vpm150m->wc = NULL;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ kfree(wc->vpm150m);
+ }
+#endif
+ /* Release span, possibly delayed */
+ if (!wc->usecount) {
+ wctdm_release(wc);
+ printk("Freed a Wildcard\n");
+ }
+ else
+ wc->dead = 1;
+ }
+}
+
+static struct pci_device_id wctdm_pci_tbl[] = {
+ { 0xd161, 0x2400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm2400 },
+ { 0xd161, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm800 },
+ { 0xd161, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcaex800 },
+ { 0xd161, 0x8003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcaex2400 },
+ { 0xd161, 0x8005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm410 },
+ { 0xd161, 0x8006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcaex410 },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, wctdm_pci_tbl);
+
+static struct pci_driver wctdm_driver = {
+ name: "wctdm24xxp",
+ probe: wctdm_init_one,
+#ifdef LINUX26
+ remove: __devexit_p(wctdm_remove_one),
+#else
+ remove: wctdm_remove_one,
+#endif
+ suspend: NULL,
+ resume: NULL,
+ id_table: wctdm_pci_tbl,
+};
+
+static int __init wctdm_init(void)
+{
+ int res;
+ int x;
+
+ for (x = 0; x < (sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) {
+ if (!strcmp(fxo_modes[x].name, opermode))
+ break;
+ }
+ if (x < sizeof(fxo_modes) / sizeof(fxo_modes[0])) {
+ _opermode = x;
+ } else {
+ printk("Invalid/unknown operating mode '%s' specified. Please choose one of:\n", opermode);
+ for (x = 0; x < sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++)
+ printk(" %s\n", fxo_modes[x].name);
+ printk("Note this option is CASE SENSITIVE!\n");
+ return -ENODEV;
+ }
+
+ if (!strcmp(opermode, "AUSTRALIA")) {
+ boostringer = 1;
+ fxshonormode = 1;
+ }
+
+ /* for the voicedaa_check_hook defaults, if the user has not overridden
+ them by specifying them as module parameters, then get the values
+ from the selected operating mode
+ */
+ if (battdebounce == 0) {
+ battdebounce = fxo_modes[_opermode].battdebounce;
+ }
+ if (battalarm == 0) {
+ battalarm = fxo_modes[_opermode].battalarm;
+ }
+ if (battthresh == 0) {
+ battthresh = fxo_modes[_opermode].battthresh;
+ }
+
+ res = zap_pci_module(&wctdm_driver);
+ if (res)
+ return -ENODEV;
+ return 0;
+}
+
+static void __exit wctdm_cleanup(void)
+{
+ pci_unregister_driver(&wctdm_driver);
+}
+
+#ifdef LINUX26
+module_param(debug, int, 0600);
+module_param(fxovoltage, int, 0600);
+module_param(loopcurrent, int, 0600);
+module_param(robust, int, 0600);
+module_param(opermode, charp, 0600);
+module_param(lowpower, int, 0600);
+module_param(boostringer, int, 0600);
+module_param(fastringer, int, 0600);
+module_param(fxshonormode, int, 0600);
+module_param(battdebounce, uint, 0600);
+module_param(battalarm, uint, 0600);
+module_param(battthresh, uint, 0600);
+module_param(alawoverride, int, 0600);
+module_param(nativebridge, int, 0600);
+module_param(fxotxgain, int, 0600);
+module_param(fxorxgain, int, 0600);
+module_param(fxstxgain, int, 0600);
+module_param(fxsrxgain, int, 0600);
+module_param(ringdebounce, int, 0600);
+module_param(fwringdetect, int, 0600);
+module_param(latency, int, 0600);
+#ifdef VPM_SUPPORT
+module_param(vpmsupport, int, 0600);
+module_param(vpmdtmfsupport, int, 0600);
+module_param(dtmfthreshold, int, 0600);
+module_param(vpmnlptype, int, 0600);
+module_param(vpmnlpthresh, int, 0600);
+module_param(vpmnlpmaxsupp, int, 0600);
+#endif
+#else
+MODULE_PARM(debug, "i");
+MODULE_PARM(fxovoltage, "i");
+MODULE_PARM(loopcurrent, "i");
+MODULE_PARM(robust, "i");
+MODULE_PARM(opermode, "s");
+MODULE_PARM(lowpower, "i");
+MODULE_PARM(boostringer, "i");
+MODULE_PARM(fastringer, "i");
+MODULE_PARM(fxshonormode, "i");
+MODULE_PARM(battdebounce, "i");
+MODULE_PARM(battalarm, "i");
+MODULE_PARM(battthresh, "i");
+MODULE_PARM(alawoverride, "i");
+MODULE_PARM(nativebridge, "i");
+MODULE_PARM(fxotxgain, "i");
+MODULE_PARM(fxorxgain, "i");
+MODULE_PARM(fxstxgain, "i");
+MODULE_PARM(fxsrxgain, "i");
+MODULE_PARM(ringdebounce, "i");
+MODULE_PARM(fwringdetect, "i");
+#ifdef VPM_SUPPORT
+MODULE_PARM(vpmsupport, "i");
+MODULE_PARM(vpmdtmfsupport, "i");
+MODULE_PARM(dtmfthreshold, "i");
+MODULE_PARM(vpmnlptype, "i");
+MODULE_PARM(vpmnlpthresh, "i");
+MODULE_PARM(vpmnlpmaxsupp, "i");
+#endif
+#endif
+MODULE_DESCRIPTION("Wildcard TDM2400P/TDM800P Zaptel Driver");
+MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
+#if defined(MODULE_ALIAS)
+MODULE_ALIAS("wctdm8xxp");
+#endif
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(wctdm_init);
+module_exit(wctdm_cleanup);
diff --git a/drivers/dahdi/wctdm24xxp/gpakErrs.h b/drivers/dahdi/wctdm24xxp/gpakErrs.h
new file mode 100644
index 0000000..3413f97
--- /dev/null
+++ b/drivers/dahdi/wctdm24xxp/gpakErrs.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2002 - 2004, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakErrs.h
+ *
+ * Description:
+ * This file contains DSP reply status codes used by G.PAK API functions to
+ * indicate specific errors.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 10/17/01 - Initial release.
+ * 07/03/02 - Updates for conferencing.
+ * 06/15/04 - Tone type updates.
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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.
+ */
+
+#ifndef _GPAKERRS_H /* prevent multiple inclusion */
+#define _GPAKERRS_H
+
+/* Configure Serial Ports reply status codes. */
+typedef enum
+{
+ Pc_Success = 0, /* serial ports configured successfully */
+ Pc_ChannelsActive = 1, /* unable to configure while channels active */
+ Pc_TooManySlots1 = 2, /* too many slots selected for port 1 */
+ Pc_InvalidBlockCombo1 = 3, /* invalid combination of blocks for port 1 */
+ Pc_NoSlots1 = 4, /* no slots selected for port 1 */
+ Pc_InvalidSlots1 = 5, /* invalid slot (> max) selected for port 1 */
+ Pc_TooManySlots2 = 6, /* too many slots selected for port 2 */
+ Pc_InvalidBlockCombo2 = 7, /* invalid combination of blocks for port 2 */
+ Pc_NoSlots2 = 8, /* no slots selected for port 2 */
+ Pc_InvalidSlots2 = 9, /* invalid slot (> max) selected for port 2 */
+ Pc_TooManySlots3 = 10, /* too many slots selected for port 3 */
+ Pc_InvalidBlockCombo3 = 11, /* invalid combination of blocks for port 3 */
+ Pc_NoSlots3 = 12, /* no slots selected for port 3 */
+ Pc_InvalidSlots3 = 13 /* invalid slot (> max) selected for port 3 */
+} GPAK_PortConfigStat_t;
+
+/* Configure Channel reply status codes. */
+typedef enum
+{
+ Cc_Success = 0, /* channel configured successfully */
+ Cc_InvalidChannelType = 1, /* invalid Channel Type */
+ Cc_InvalidChannel = 2, /* invalid Channel A Id */
+ Cc_ChannelActiveA = 3, /* Channel A is currently active */
+ Cc_InvalidInputPortA = 4, /* invalid Input A Port */
+ Cc_InvalidInputSlotA = 5, /* invalid Input A Slot */
+ Cc_BusyInputSlotA = 6, /* busy Input A Slot */
+ Cc_InvalidOutputPortA = 7, /* invalid Output A Port */
+ Cc_InvalidOutputSlotA = 8, /* invalid Output A Slot */
+ Cc_BusyOutputSlotA = 9, /* busy Output A Slot */
+ Cc_InvalidInputPortB = 10, /* invalid Input B Port */
+ Cc_InvalidInputSlotB = 11, /* invalid Input B Slot */
+ Cc_BusyInputSlotB = 12, /* busy Input B Slot */
+ Cc_InvalidPktInCodingA = 13, /* invalid Packet In A Coding */
+ Cc_InvalidPktOutCodingA = 14, /* invalid Packet Out A Coding */
+ Cc_InvalidPktInSizeA = 15, /* invalid Packet In A Frame Size */
+ Cc_InvalidPktOutSizeA = 16, /* invalid Packet Out A Frame Size */
+
+ Cc_ChanTypeNotConfigured = 21, /* channel type was not configured */
+ Cc_InsuffECResources = 22, /* insufficient ecan resources avail. */
+ Cc_InsuffTDMResources = 23, /* insufficient tdm block resources avail. */
+
+ Cc_InsuffPktBufResources = 25, /* insufficient pkt buffer resources avail. */
+ Cc_InsuffPcmBufResources = 26, /* insufficient pcm buffer resources avail. */
+
+ Cc_BadPcmEcNlpType = 30, /* invalid EC Nlp type */
+ Cc_BadPcmEcTapLength = 31, /* invalid EC tap length */
+ Cc_BadPcmEcDblTalkThresh = 32, /* invalid EC double-talk threshold */
+ Cc_BadPcmEcNlpThreshold = 33, /* invalid EC Nlp threshold */
+ Cc_BadPcmEcCngThreshold = 34, /* invalid EC Cng threshold */
+ Cc_BadPcmEcAdaptLimit = 35, /* invalid EC Adapt Limit */
+ Cc_BadPcmEcCrossCorrLim = 36, /* invalid EC Cross Correlation Limit */
+ Cc_BadPcmEcNumFirSegs = 37, /* invalid EC Number of FirSegments */
+ Cc_BadPcmEcFirSegLen = 38, /* invalid EC Fir Segment Length */
+
+ /*Cc_InvalidNumEcsEnabled = 48, */ /* more than 1 Ec enabled on channel */
+ Cc_InvalidFrameRate = 49, /* invalid gpak frame rate */
+ Cc_InvalidSoftCompand = 50, /* invalid softCompanding type */
+
+ Cc_InvalidMuteToneA = 51, /* invalid MuteToneA set, no detector */
+ Cc_InvalidMuteToneB = 52, /* invalid MuteToneB set, no detector */
+ Cc_InsuffFaxCngDetResources = 53 /* insufficient tdm block resources avail. */
+
+} GPAK_ChannelConfigStat_t;
+
+/* Tear Down Channel reply status codes. */
+typedef enum
+{
+ Td_Success = 0, /* channel torn down successfully */
+ Td_InvalidChannel = 1, /* invalid Channel Id */
+ Td_ChannelNotActive = 2 /* channel is not active */
+} GPAK_TearDownChanStat_t;
+
+
+typedef enum
+{
+ Ac_Success = 0, /* algorithm control is successfull */
+ Ac_InvalidChannel = 1, /* invalid channel identifier */
+ Ac_InvalidCode = 2, /* invalid algorithm control code */
+ Ac_ECNotEnabled = 3, /* echo canceller was not allocated */
+ Ac_InvalidSoftComp = 4, /* invalid softcompanding, 'cause serial port not in companding mode */
+ Ac_InvalidDTMFMuteA = 5, /* A side invalid Mute, since no dtmf detector */
+ Ac_InvalidDTMFMuteB = 6, /* B side invalid Mute, since no dtmf detector */
+ Ac_InvalidFaxCngA = 7, /* A side FAXCNG detector not available */
+ Ac_InvalidFaxCngB = 8, /* B side FAXCNG detector not available */
+ Ac_InvalidSysConfig = 9 /* No new system parameters (DTMF config) wrriten yet */
+} GPAK_AlgControlStat_t;
+
+/* Write System Parameters reply status codes. */
+typedef enum
+{
+ Sp_Success = 0, /* System Parameters written successfully */
+ Sp_BadTwistThresh = 29 /* invalid twist threshold */
+
+} GPAK_SysParmsStat_t;
+
+#endif /* prevent multiple inclusion */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/drivers/dahdi/wctdm24xxp/gpakenum.h b/drivers/dahdi/wctdm24xxp/gpakenum.h
new file mode 100644
index 0000000..91e4311
--- /dev/null
+++ b/drivers/dahdi/wctdm24xxp/gpakenum.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2005, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: gpakenum.h
+ *
+ * Description:
+ * This file contains common enumerations related to G.PAK application
+ * software.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 06/15/05 - Initial release.
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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.
+ */
+
+#ifndef _GPAKENUM_H /* prevent multiple inclusion */
+#define _GPAKENUM_H
+
+/* G.PAK Serial Port Word Size */
+typedef enum
+{
+ SerWordSize8 = 0, // 8-bit seial word
+ SerWordSize16 = 1 // 16-bit serial word
+} GpakSerWordSize_t;
+
+/* G.PAK Serial Port FrameSync Polarity */
+typedef enum
+{
+ FrameSyncActLow = 0, // active low frame sync signal
+ FrameSyncActHigh = 1 // active high frame sync signal
+} GpakSerFrameSyncPol_t;
+
+/* G.PAK Serial Port Clock Polarity */
+typedef enum
+{
+ SerClockActLow = 0, // active low serial clock
+ SerClockActHigh = 1 // active high serial clock
+} GpakSerClockPol_t;
+
+/* G.PAK Serial Port Data Delay */
+typedef enum
+{
+ DataDelay0 = 0, // no data delay
+ DataDelay1 = 1, // 1-bit data delay
+ DataDelay2 = 2 // 2-bit data delay
+} GpakSerDataDelay_t;
+
+/* G.PAK Serial Port Ids. */
+typedef enum
+{
+ SerialPortNull = 0, // null serial port
+ SerialPort1 = 1, // first PCM serial stream port (McBSP0)
+ SerialPort2 = 2, // second PCM serial stream port (McBSP1)
+ SerialPort3 = 3 // third PCM serial stream port (McBSP2)
+} GpakSerialPort_t;
+
+/* G.PAK serial port Slot Configuration selection codes. */
+typedef enum
+{
+ SlotCfgNone = 0, // no time slots used
+ SlotCfg2Groups = 2, // 2 groups of 16 time slots used, 32 Channels system
+ SlotCfg8Groups = 8 // 8-partition mode for 128-channel system
+} GpakSlotCfg_t;
+
+/* G.PAK serial port Companding Mode codes. */
+typedef enum
+{
+ cmpPCMU=0, // u-Law
+ cmpPCMA=1, // A-Law
+ cmpNone=2 // none
+} GpakCompandModes;
+
+/* G.PAK Active/Inactive selection codes. */
+typedef enum
+{
+ Disabled=0, // Inactive
+ Enabled=1 // Active
+} GpakActivation;
+
+/* G.PAK Channel Type codes. */
+typedef enum
+{
+ inactive=0, // channel inactive
+ tdmToTdm=1 // tdmToTdm
+} GpakChanType;
+
+/* G.PAK Algorithm control commands */
+typedef enum
+{
+ EnableEcanA = 0, // Enable A side echo canceller
+ BypassEcanA = 1, // Bypass A side echo canceller
+ ResetEcanA = 2, // Reset A side echo canceller
+ EnableEcanB = 3, // Enable B side echo canceller
+ BypassEcanB = 4, // Bypass B side echo canceller
+ ResetEcanB = 5, // Reset B side echo canceller
+
+ EnableMuLawSwCompanding = 6,// Enable Mu-law Software companding
+ EnableALawSwCompanding = 7, // Enable Mu-law Software companding
+ BypassSwCompanding = 8, // Bypass Software companding
+ EnableDTMFMuteA = 9, // Mute A side Dtmf digit after tone detected
+ DisableDTMFMuteA = 10, // Do not mute A side Dtmf digit once tone detected
+ EnableDTMFMuteB = 11, // Mute B side Dtmf digit after tone detected
+ DisableDTMFMuteB = 12, // Do not mute B side Dtmf digit once tone detected
+ EnableFaxCngDetectA = 13, // Enable A side Fax CNG detector, channel must be configed already
+ DisableFaxCngDetectA = 14, // Disable A side Fax CNG detector, channel must be configed already
+ EnableFaxCngDetectB = 15, // Enable B side Fax CNG detector, channel must be configed already
+ DisableFaxCngDetectB = 16 // Disable B side Fax CNG detector, channel must be configed already
+} GpakAlgCtrl_t;
+
+/* G.PAK Tone types. */
+typedef enum
+{
+ Null_tone = 0, // no tone detection
+ DTMF_tone = 1 // DTMF tone
+} GpakToneTypes;
+
+/* G.PAK direction. */
+typedef enum
+{
+ TDMAToB = 0, // A to B
+ TDMBToA = 1 // B to A
+} GpakTdmDirection;
+
+
+typedef enum
+{
+ rate1ms=0,
+ rate2ms=1,
+ rate10ms=2
+} GpakRate_t;
+
+/* G.PAK Asynchronous Event Codes */
+typedef enum
+{
+ EventToneDetect = 0, // Tone detection event
+ EventDSPDebug = 7 // DSP debug data event
+} GpakAsyncEventCode_t;
+
+/* G.PAK MF Tone Code Indices */
+typedef enum
+{
+ DtmfDigit1 = 0, // DTMF Digit 1
+ DtmfDigit2 = 1, // DTMF Digit 2
+ DtmfDigit3 = 2, // DTMF Digit 3
+ DtmfDigitA = 3, // DTMF Digit A
+ DtmfDigit4 = 4, // DTMF Digit 4
+ DtmfDigit5 = 5, // DTMF Digit 5
+ DtmfDigit6 = 6, // DTMF Digit 6
+ DtmfDigitB = 7, // DTMF Digit B
+ DtmfDigit7 = 8, // DTMF Digit 7
+ DtmfDigit8 = 9, // DTMF Digit 8
+ DtmfDigit9 = 10, // DTMF Digit 9
+ DtmfDigitC = 11, // DTMF Digit C
+ DtmfDigitSt = 12, // DTMF Digit *
+ DtmfDigit0 = 13, // DTMF Digit 0
+ DtmfDigitPnd = 14, // DTMF Digit #
+ DtmfDigitD = 15, // DTMF Digit D
+
+ FaxCngDigit = 90, // Fax Calling Tone (1100 Hz)
+
+ EndofMFDigit = 100, // End of MF digit
+ EndofCngDigit = 101 // End of Cng Digit
+} GpakToneCodes_t;
+
+/* GPIO control code*/
+typedef enum
+{
+ GPIO_READ = 0,
+ GPIO_WRITE = 1,
+ GPIO_DIR = 2
+} GpakGPIOCotrol_t;
+
+
+#endif // end multiple inclusion
diff --git a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
new file mode 100644
index 0000000..30e4fb9
--- /dev/null
+++ b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
@@ -0,0 +1,277 @@
+/*
+ * Wildcard TDM2400P TDM FXS/FXO Interface Driver for Zapata Telephony interface
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Support for TDM800P and VPM150M by Matthew Fredrickson <creslin@digium.com>
+ *
+ * Copyright (C) 2005, 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.
+ *
+ */
+
+#ifndef _WCTDM24XXP_H
+#define _WCTDM24XXP_H
+
+#include "../zaptel.h"
+#include "../voicebus.h"
+#include <asm/semaphore.h>
+
+#define NUM_FXO_REGS 60
+
+#define WC_MAX_IFACES 128
+
+/*!
+ * \brief Default ringer debounce (in ms)
+ */
+#define DEFAULT_RING_DEBOUNCE 128
+
+#define POLARITY_DEBOUNCE 64 /* Polarity debounce (in ms) */
+
+#define OHT_TIMER 6000 /* How long after RING to retain OHT */
+
+#define FLAG_3215 (1 << 0)
+#define FLAG_EXPRESS (1 << 1)
+
+#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 MAX_ALARMS 10
+
+#define MOD_TYPE_NONE 0
+#define MOD_TYPE_FXS 1
+#define MOD_TYPE_FXO 2
+#define MOD_TYPE_FXSINIT 3
+#define MOD_TYPE_VPM 4
+#define MOD_TYPE_QRV 5
+#define MOD_TYPE_VPM150M 6
+
+#define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */
+#define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */
+#define PEGCOUNT 5 /* 5 cycles of pegging means RING */
+
+#define SDI_CLK (0x00010000)
+#define SDI_DOUT (0x00020000)
+#define SDI_DREAD (0x00040000)
+#define SDI_DIN (0x00080000)
+
+#define PCI_WINDOW_SIZE ((2 * 2 * 2 * SFRAME_SIZE) + (2 * ERING_SIZE * 4))
+
+#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 CMD_WR(a,b) (((a) << 8) | (b) | __CMD_WR)
+#define CMD_RD(a) (((a) << 8) | __CMD_RD)
+
+#if 0
+#define CMD_BYTE(card,bit,altcs) (((((card) & 0x3) * 3 + (bit)) * 7) \
+ + ((card) >> 2) + (altcs) + ((altcs) ? -21 : 0))
+#endif
+#define NUM_CARDS 24
+#define NUM_EC 4
+#define NUM_SLOTS 6
+#define MAX_TDM_CHAN 31
+
+#define NUM_CAL_REGS 12
+
+#define USER_COMMANDS 8
+#define ISR_COMMANDS 2
+#define QRV_DEBOUNCETIME 20
+
+#define MAX_COMMANDS (USER_COMMANDS + ISR_COMMANDS)
+
+#define __VPM150M_RWPAGE (1 << 4)
+#define __VPM150M_RD (1 << 3)
+#define __VPM150M_WR (1 << 2)
+#define __VPM150M_FIN (1 << 1)
+#define __VPM150M_TX (1 << 0)
+
+#define VPM150M_HPI_CONTROL 0x00
+#define VPM150M_HPI_ADDRESS 0x02
+#define VPM150M_HPI_DATA 0x03
+
+#define VPM150M_MAX_COMMANDS 8
+
+/* Some Bit ops for different operations */
+#define VPM150M_SPIRESET 0
+#define VPM150M_HPIRESET 1
+#define VPM150M_SWRESET 2
+#define VPM150M_DTMFDETECT 3
+#define VPM150M_ACTIVE 4
+
+#define VPM150M_MAX_DATA 1
+
+#define VPM_SUPPORT
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define VPM150M_SUPPORT
+#endif
+
+#ifdef VPM_SUPPORT
+
+/* Define to get more attention-grabbing but slightly more CPU using echocan status */
+#define FANCY_ECHOCAN
+
+#endif
+
+#ifdef VPM150M_SUPPORT
+#include "adt_lec.h"
+#endif
+
+struct vpm150m_cmd {
+ unsigned int addr;
+ unsigned char datalen;
+ unsigned char desc;
+ unsigned char txident;
+ unsigned short data[VPM150M_MAX_DATA];
+};
+
+struct vpm150m {
+#ifdef VPM150M_SUPPORT
+ struct workqueue_struct *wq;
+ struct work_struct work;
+#endif
+ struct wctdm *wc;
+
+ int dspid;
+ struct semaphore sem;
+ unsigned long control;
+ unsigned char curpage;
+ unsigned short version;
+ struct adt_lec_params curecstate[24];
+ struct adt_lec_params desiredecstate[24];
+ unsigned long curdtmfmutestate;
+ unsigned long desireddtmfmutestate;
+ struct vpm150m_cmd cmdq[VPM150M_MAX_COMMANDS];
+ unsigned char curtone[24];
+};
+
+struct calregs {
+ unsigned char vals[NUM_CAL_REGS];
+};
+
+struct cmdq {
+ unsigned int cmds[MAX_COMMANDS];
+ unsigned char isrshadow[ISR_COMMANDS];
+};
+
+enum battery_state {
+ BATTERY_UNKNOWN = 0,
+ BATTERY_PRESENT,
+ BATTERY_LOST,
+};
+
+struct wctdm {
+ char *variety;
+ char board_name[80];
+ struct zt_span span;
+ unsigned char ios;
+ unsigned int sdi;
+ int usecount;
+ unsigned int intcount;
+ unsigned int rxints;
+ unsigned int txints;
+ unsigned char txident;
+ unsigned char rxident;
+ int dead;
+ int pos;
+ int flags[NUM_CARDS];
+ int alt;
+ int curcard;
+ unsigned char ctlreg;
+ int cards;
+ int cardflag; /* Bit-map of present cards */
+ int altcs[NUM_CARDS + NUM_EC];
+ char qrvhook[NUM_CARDS];
+ unsigned short qrvdebtime[NUM_CARDS];
+ int radmode[NUM_CARDS];
+#define RADMODE_INVERTCOR 1
+#define RADMODE_IGNORECOR 2
+#define RADMODE_EXTTONE 4
+#define RADMODE_EXTINVERT 8
+#define RADMODE_IGNORECT 16
+#define RADMODE_PREEMP 32
+#define RADMODE_DEEMP 64
+ unsigned short debouncetime[NUM_CARDS];
+ signed short rxgain[NUM_CARDS];
+ signed short txgain[NUM_CARDS];
+ spinlock_t reglock;
+ wait_queue_head_t regq;
+ /* FXO Stuff */
+ union {
+ struct fxo {
+ int wasringing;
+ int lastrdtx;
+ int ringdebounce;
+ int offhook;
+ int battdebounce;
+ int battalarm;
+ enum battery_state battery;
+ int lastpol;
+ int polarity;
+ int polaritydebounce;
+ } fxo;
+ struct fxs {
+ int oldrxhook;
+ int debouncehook;
+ int lastrxhook;
+ int debounce;
+ int ohttimer;
+ int idletxhookstate; /* IDLE changing hook state */
+ int lasttxhook;
+ int palarms;
+ struct calregs calregs;
+ } fxs;
+ } mods[NUM_CARDS];
+ struct cmdq cmdq[NUM_CARDS + NUM_EC];
+ /* Receive hook state and debouncing */
+ int modtype[NUM_CARDS + NUM_EC];
+ /* Set hook */
+ int sethook[NUM_CARDS + NUM_EC];
+ int dacssrc[NUM_CARDS];
+ int type;
+
+#ifdef VPM_SUPPORT
+ int vpm;
+ unsigned long dtmfactive;
+ unsigned long dtmfmask;
+ unsigned long dtmfmutemask;
+ short dtmfenergy[NUM_CARDS];
+ short dtmfdigit[NUM_CARDS];
+
+ struct vpm150m *vpm150m;
+#ifdef FANCY_ECHOCAN
+ int echocanpos;
+ int blinktimer;
+#endif
+#endif
+ struct voicebus *vb;
+ struct zt_chan chans[NUM_CARDS];
+ int initialized;
+};
+
+
+int schluffen(wait_queue_head_t *q);
+
+extern spinlock_t ifacelock;
+extern struct wctdm *ifaces[WC_MAX_IFACES];
+
+#endif
diff --git a/drivers/dahdi/wcte11xp.c b/drivers/dahdi/wcte11xp.c
new file mode 100644
index 0000000..2d2c79e
--- /dev/null
+++ b/drivers/dahdi/wcte11xp.c
@@ -0,0 +1,1644 @@
+/*
+ * Digium, Inc. Wildcard TE110P T1/PRI card Driver
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Matthew Fredrickson <creslin@digium.com>
+ * William Meadows <wmeadows@digium.com>
+ *
+ * Copyright (C) 2004, 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/usb.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include "zaptel.h"
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+/* XXX: fix this */
+#include "wct4xxp/wct4xxp.h" /* For certain definitions */
+
+#define WC_MAX_CARDS 32
+
+/*
+#define TEST_REGS
+*/
+
+/* Define to get more attention-grabbing but slightly more I/O using
+ alarm status */
+#define FANCY_ALARM
+
+/* Define to enable the V2.1 errata register settings */
+#if 0
+#define TRUST_INFINEON_ERRATA
+#endif
+
+#define DELAY 0x0 /* 30 = 15 cycles, 10 = 8 cycles, 0 = 3 cycles */
+
+#define WC_CNTL 0x00
+#define WC_OPER 0x01
+#define WC_AUXC 0x02
+#define WC_AUXD 0x03
+#define WC_MASK0 0x04
+#define WC_MASK1 0x05
+#define WC_INTSTAT 0x06
+
+#define WC_DMAWS 0x08
+#define WC_DMAWI 0x0c
+#define WC_DMAWE 0x10
+#define WC_DMARS 0x18
+#define WC_DMARI 0x1c
+#define WC_DMARE 0x20
+#define WC_CURPOS 0x24
+
+#define WC_SERC 0x2d
+#define WC_FSCDELAY 0x2f
+
+#define WC_USERREG 0xc0
+
+#define WC_CLOCK 0x0
+#define WC_LEDTEST 0x1
+#define WC_VERSION 0x2
+
+/* Offset between transmit and receive */
+#define WC_OFFSET 4
+
+#define BIT_CS (1 << 7)
+#define BIT_ADDR (0xf << 3)
+
+#define BIT_LED1 (1 << 0)
+#define BIT_LED0 (1 << 1)
+#define BIT_TEST (1 << 2)
+
+#define FLAG_STARTED (1 << 0)
+#define FLAG_NMF (1 << 1)
+#define FLAG_SENDINGYELLOW (1 << 2)
+#define FLAG_FALC12 (1 << 3)
+
+#define TYPE_T1 1 /* is a T1 card */
+#define TYPE_E1 2 /* is an E1 card */
+
+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 };
+
+
+#ifdef FANCY_ALARM
+static int altab[] = {
+0, 0, 0, 1, 2, 3, 4, 6, 8, 9, 11, 13, 16, 18, 20, 22, 24, 25, 27, 28, 29, 30, 31, 31, 32, 31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0,
+};
+#endif
+
+struct t1 {
+ struct pci_dev *dev;
+ spinlock_t lock;
+ int spantype;
+ int spanflags; /* Span flags */
+ unsigned char txsigs[16]; /* Copy of tx sig registers */
+ int num;
+ int alarmcount; /* How much red alarm we've seen */
+ int alarmdebounce;
+ /* Our offset for finding channel 1 */
+ int offset;
+ char *variety;
+ unsigned int intcount;
+ int usecount;
+ int clocktimeout;
+ int sync;
+ int dead;
+ int blinktimer;
+ int alarmtimer;
+ int checktiming; /* Set >0 to cause the timing source to be checked */
+ int loopupcnt;
+ int loopdowncnt;
+ int miss;
+ int misslast;
+ int *chanmap;
+#ifdef FANCY_ALARM
+ int alarmpos;
+#endif
+ unsigned char ledtestreg;
+ unsigned char outbyte;
+ unsigned long ioaddr;
+ unsigned short canary;
+ /* T1 signalling */
+ dma_addr_t readdma;
+ dma_addr_t writedma;
+ volatile unsigned char *writechunk; /* Double-word aligned write memory */
+ volatile unsigned char *readchunk; /* Double-word aligned read memory */
+ unsigned char ec_chunk1[32][ZT_CHUNKSIZE];
+ unsigned char ec_chunk2[32][ZT_CHUNKSIZE];
+ unsigned char tempo[33];
+ struct zt_span span; /* Span */
+ struct zt_chan chans[32]; /* Channels */
+};
+
+#define CANARY 0xca1e
+
+static int debug = 0; /* doesnt do anything */
+static int j1mode = 0;
+static int alarmdebounce = 0;
+static int loopback = 0;
+static int clockextra = 0;
+static int t1e1override = -1;
+static int unchannelized = 0;
+
+static struct t1 *cards[WC_MAX_CARDS];
+
+static inline void start_alarm(struct t1 *wc)
+{
+#ifdef FANCY_ALARM
+ wc->alarmpos = 0;
+#endif
+ wc->blinktimer = 0;
+}
+
+static inline void stop_alarm(struct t1 *wc)
+{
+#ifdef FANCY_ALARM
+ wc->alarmpos = 0;
+#endif
+ wc->blinktimer = 0;
+}
+
+static inline void __select_framer(struct t1 *wc, int reg)
+{
+ /* Top four bits of address from AUX 6-3 */
+ wc->outbyte &= ~BIT_CS;
+ wc->outbyte &= ~BIT_ADDR;
+ wc->outbyte |= (reg & 0xf0) >> 1;
+ outb(wc->outbyte, wc->ioaddr + WC_AUXD);
+}
+
+static inline void __select_control(struct t1 *wc)
+{
+ if (!(wc->outbyte & BIT_CS)) {
+ wc->outbyte |= BIT_CS;
+ outb(wc->outbyte, wc->ioaddr + WC_AUXD);
+ }
+}
+
+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 __control_set_reg(struct t1 *wc, int reg, unsigned char val)
+{
+ __select_control(wc);
+ outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));
+ return 0;
+}
+
+static int control_set_reg(struct t1 *wc, int reg, unsigned char val)
+{
+ unsigned long flags;
+ int res;
+ spin_lock_irqsave(&wc->lock, flags);
+ res = __control_set_reg(wc, reg, val);
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return res;
+}
+
+static int __control_get_reg(struct t1 *wc, int reg)
+{
+ unsigned char res;
+ /* The following makes UTTERLY no sense, but what was happening
+ was that reads in some cases were not actually happening
+ on the physical bus. Why, we dunno. But in debugging, we found
+ that writing before reading (in this case to an unused position)
+ seems to get rid of the problem */
+ __control_set_reg(wc,3,0x69); /* do magic here */
+ /* now get the read byte from the Xilinx part */
+ res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));
+ return res;
+}
+
+static int control_get_reg(struct t1 *wc, int reg)
+{
+ unsigned long flags;
+ int res;
+ spin_lock_irqsave(&wc->lock, flags);
+ res = __control_get_reg(wc, reg);
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return res;
+}
+
+static inline unsigned int __t1_framer_in(struct t1 *wc, const unsigned int reg)
+{
+ unsigned char res;
+ __select_framer(wc, reg);
+ /* Get value */
+ res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));
+ return res;
+#if 0
+ unsigned int ret;
+ __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
+ __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | ( 1 << 10) | WC_LREAD);
+ ret = __t1_pci_in(wc, WC_LDATA);
+ __t1_pci_out(wc, WC_LADDR, 0);
+ return ret & 0xff;
+#endif
+}
+
+static inline unsigned int t1_framer_in(struct t1 *wc, const unsigned int addr)
+{
+ unsigned long flags;
+ unsigned int ret;
+ spin_lock_irqsave(&wc->lock, flags);
+ ret = __t1_framer_in(wc, addr);
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return ret;
+
+}
+
+static inline void __t1_framer_out(struct t1 *wc, const unsigned int reg, const unsigned int val)
+{
+ if (debug > 1)
+ printk("Writing %02x to address %02x\n", val, reg);
+ __select_framer(wc, reg);
+ /* Send address */
+ outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));
+#if 0
+ __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
+ __t1_pci_out(wc, WC_LDATA, value);
+ __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10));
+ __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10) | WC_LWRITE);
+ __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10));
+ __t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
+ __t1_pci_out(wc, WC_LADDR, 0);
+ if (debug) printk("Write complete\n");
+#endif
+#if 0
+ { unsigned int tmp;
+ tmp = t1_framer_in(wc, unit, addr);
+ if (tmp != value) {
+ printk("Expected %d from unit %d register %d but got %d instead\n", value, unit, addr, tmp);
+ } }
+#endif
+}
+
+static inline void t1_framer_out(struct t1 *wc, const unsigned int addr, const unsigned int value)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&wc->lock, flags);
+ __t1_framer_out(wc, addr, value);
+ spin_unlock_irqrestore(&wc->lock, flags);
+}
+
+static void t1xxp_release(struct t1 *wc)
+{
+ zt_unregister(&wc->span);
+ kfree(wc);
+ printk("Freed a Wildcard\n");
+}
+
+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)
+ t1xxp_release(wc);
+ return 0;
+}
+
+static void t1xxp_enable_interrupts(struct t1 *wc)
+{
+ /* Clear interrupts */
+ outb(0xff, wc->ioaddr + WC_INTSTAT);
+ /* Enable interrupts (we care about all of them) */
+ outb(0x3c /* 0x3f */, wc->ioaddr + WC_MASK0);
+ /* No external interrupts */
+ outb(0x00, wc->ioaddr + WC_MASK1);
+ if (debug) printk("Enabled interrupts!\n");
+}
+
+static void t1xxp_start_dma(struct t1 *wc)
+{
+ /* Reset Master and TDM */
+ outb(DELAY | 0x0f, wc->ioaddr + WC_CNTL);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ outb(DELAY | 0x01, wc->ioaddr + WC_CNTL);
+ outb(0x01, wc->ioaddr + WC_OPER);
+ if (debug) printk("Started DMA\n");
+ outb(0x03, wc->ioaddr + WC_OPER);
+ outb(0x01, wc->ioaddr + WC_OPER);
+}
+
+static void __t1xxp_stop_dma(struct t1 *wc)
+{
+ outb(0x00, wc->ioaddr + WC_OPER);
+}
+
+static void __t1xxp_disable_interrupts(struct t1 *wc)
+{
+ outb(0x00, wc->ioaddr + WC_MASK0);
+ outb(0x00, wc->ioaddr + WC_MASK1);
+}
+
+static void __t1xxp_set_clear(struct t1 *wc)
+{
+ int i,j;
+ 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) {
+ if (debug > 1)
+ printk("Putting %d in register %02x\n",
+ val, 0x2f + j);
+ __t1_framer_out(wc, 0x2f + j, val);
+ val = 0;
+ }
+ }
+}
+
+static int t1xxp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
+{
+ struct t4_regs regs;
+ int x;
+ struct t1 *wc;
+ switch(cmd) {
+ case WCT4_GET_REGS:
+ wc = chan->pvt;
+ for (x=0;x<NUM_PCI;x++)
+#if 1
+ regs.pci[x] = (inb(wc->ioaddr + (x << 2))) |
+ (inb(wc->ioaddr + (x << 2) + 1) << 8) |
+ (inb(wc->ioaddr + (x << 2) + 2) << 16) |
+ (inb(wc->ioaddr + (x << 2) + 3) << 24);
+#else
+ regs.pci[x] = (inb(wc->ioaddr + x));
+#endif
+
+ for (x=0;x<NUM_REGS;x++)
+ regs.regs[x] = t1_framer_in(wc, x);
+ if (copy_to_user((struct t4_regs *)data, &regs, sizeof(regs)))
+ return -EFAULT;
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+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:
+ printk("XXX Turn off local and remote loops E1 XXX\n");
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ printk("XXX Turn on local loopback E1 XXX\n");
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ printk("XXX Turn on remote loopback E1 XXX\n");
+ break;
+ case ZT_MAINT_LOOPUP:
+ printk("XXX Send loopup code E1 XXX\n");
+ break;
+ case ZT_MAINT_LOOPDOWN:
+ printk("XXX Send loopdown code E1 XXX\n");
+ break;
+ case ZT_MAINT_LOOPSTOP:
+ printk("XXX Stop sending loop codes E1 XXX\n");
+ break;
+ default:
+ printk("TE110P: Unknown E1 maint command: %d\n", cmd);
+ break;
+ }
+ } else {
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ printk("XXX Turn off local and remote loops T1 XXX\n");
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ printk("XXX Turn on local loop and no remote loop XXX\n");
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ printk("XXX Turn on remote loopup XXX\n");
+ break;
+ case ZT_MAINT_LOOPUP:
+ t1_framer_out(wc, 0x21, 0x50); /* FMR5: Nothing but RBS mode */
+ break;
+ case ZT_MAINT_LOOPDOWN:
+ t1_framer_out(wc, 0x21, 0x60); /* FMR5: Nothing but RBS mode */
+ break;
+ case ZT_MAINT_LOOPSTOP:
+ t1_framer_out(wc, 0x21, 0x40); /* FMR5: Nothing but RBS mode */
+ break;
+ default:
+ printk("TE110P: Unknown T1 maint command: %d\n", cmd);
+ break;
+ }
+ }
+ 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;
+
+ if(debug > 1) printk("Setting bits to %d on channel %s\n", bits, chan->name);
+ spin_lock_irqsave(&wc->lock, flags);
+ if (wc->spantype == TYPE_E1) { /* do it E1 way */
+ if (chan->chanpos == 16) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return 0;
+ }
+ n = chan->chanpos - 1;
+ if (chan->chanpos > 15) n--;
+ b = (n % 15);
+ 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;
+ /* output them to the chip */
+ __t1_framer_out(wc,0x71 + b,c);
+ } else if (wc->span.lineconfig & ZT_CONFIG_D4) {
+ n = chan->chanpos - 1;
+ b = (n/4);
+ 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;
+ /* output them to the chip */
+ __t1_framer_out(wc,0x70 + b,c);
+ __t1_framer_out(wc,0x70 + b + 6,c);
+ } else if (wc->span.lineconfig & ZT_CONFIG_ESF) {
+ n = chan->chanpos - 1;
+ b = (n/2);
+ 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;
+ /* output them to the chip */
+ __t1_framer_out(wc,0x70 + b,c);
+ }
+ spin_unlock_irqrestore(&wc->lock, flags);
+ if (debug > 1)
+ printk("Finished setting RBS bits\n");
+ return 0;
+}
+
+static void t1_check_sigbits(struct t1 *wc)
+{
+ int a,i,rxs;
+ unsigned long flags;
+
+ if (!(wc->span.flags & ZT_FLAG_RUNNING))
+ return;
+
+ spin_lock_irqsave(&wc->lock, flags);
+
+ if (wc->spantype == TYPE_E1) {
+ for (i = 0; i < 15; i++) {
+ a = __t1_framer_in(wc, 0x71 + i);
+ /* 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) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_rbsbits(&wc->span.chans[i+16], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ rxs = (a >> 4) & 0xf;
+ if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i].rxsig != rxs) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_rbsbits(&wc->span.chans[i], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ }
+ } else if (wc->span.lineconfig & ZT_CONFIG_D4) {
+ for (i = 0; i < 24; i+=4) {
+ a = __t1_framer_in(wc, 0x70 + (i>>2));
+ /* 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) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_rbsbits(&wc->span.chans[i+3], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ rxs = (a & 0xc);
+ if (!(wc->span.chans[i+2].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i+2].rxsig != rxs) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_rbsbits(&wc->span.chans[i+2], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ rxs = (a >> 2) & 0xc;
+ if (!(wc->span.chans[i+1].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i+1].rxsig != rxs) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_rbsbits(&wc->span.chans[i+1], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ rxs = (a >> 4) & 0xc;
+ if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i].rxsig != rxs) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_rbsbits(&wc->span.chans[i], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < 24; i+=2) {
+ a = __t1_framer_in(wc, 0x70 + (i>>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) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_rbsbits(&wc->span.chans[i+1], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ rxs = (a >> 4) & 0xf;
+ if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i].rxsig != rxs) {
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_rbsbits(&wc->span.chans[i], rxs);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ }
+ }
+ spin_unlock_irqrestore(&wc->lock, flags);
+}
+
+static void t4_serial_setup(struct t1 *wc)
+{
+ printk("TE110P: Setting up global serial parameters for %s %s\n",
+ wc->spantype == TYPE_E1 ? (unchannelized ? "Unchannelized E1" : "E1") : "T1",
+ wc->spanflags & FLAG_FALC12 ? "FALC V1.2" : "FALC V2.2");
+ t1_framer_out(wc, 0x85, 0xe0); /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */
+ t1_framer_out(wc, 0x08, 0x05); /* IPC: Interrupt push/pull active low */
+ if (wc->spanflags & FLAG_FALC12) {
+ t1_framer_out(wc, 0x92, 0x00);
+ t1_framer_out(wc, 0x93, 0x58);
+ t1_framer_out(wc, 0x94, 0xd2);
+ t1_framer_out(wc, 0x95, 0xc2);
+ t1_framer_out(wc, 0x96, 0x03);
+ t1_framer_out(wc, 0x97, 0x10);
+ } else {
+ /* Global clocks (8.192 Mhz CLK) */
+ t1_framer_out(wc, 0x92, 0x00);
+ t1_framer_out(wc, 0x93, 0x18);
+ t1_framer_out(wc, 0x94, 0xfb);
+ t1_framer_out(wc, 0x95, 0x0b);
+ t1_framer_out(wc, 0x96, 0x00);
+ t1_framer_out(wc, 0x97, 0x0b);
+ t1_framer_out(wc, 0x98, 0xdb);
+ t1_framer_out(wc, 0x99, 0xdf);
+ }
+ /* Configure interrupts */
+ t1_framer_out(wc, 0x46, 0x40); /* GCR: Interrupt on Activation/Deactivation of AIX, LOS */
+
+ /* Configure system interface */
+ t1_framer_out(wc, 0x3e, 0x02); /* SIC1: 4.096 Mhz clock/bus, double buffer receive / transmit, byte interleaved */
+ t1_framer_out(wc, 0x3f, 0x00); /* SIC2: No FFS, no center receive eliastic buffer, phase 0 */
+ t1_framer_out(wc, 0x40, 0x04); /* SIC3: Edges for capture */
+ t1_framer_out(wc, 0x44, 0x30); /* CMR1: RCLK is at 8.192 Mhz dejittered */
+ t1_framer_out(wc, 0x45, 0x00); /* CMR2: We provide sync and clock for tx and rx. */
+ t1_framer_out(wc, 0x22, 0x00); /* XC0: Normal operation of Sa-bits */
+ t1_framer_out(wc, 0x23, 0x04); /* XC1: 0 offset */
+ t1_framer_out(wc, 0x24, 0x07); /* RC0: Just shy of 255 */
+ if (wc->spanflags & FLAG_FALC12)
+ t1_framer_out(wc, 0x25, 0x04); /* RC1: The rest of RC0 */
+ else
+ t1_framer_out(wc, 0x25, 0x05); /* RC1: The rest of RC0 */
+
+ /* Configure ports */
+ t1_framer_out(wc, 0x80, 0x00); /* PC1: SPYR/SPYX input on RPA/XPA */
+ t1_framer_out(wc, 0x81, 0x22); /* PC2: RMFB/XSIG output/input on RPB/XPB */
+ t1_framer_out(wc, 0x82, 0x65); /* PC3: Some unused stuff */
+ t1_framer_out(wc, 0x83, 0x35); /* PC4: Some more unused stuff */
+ t1_framer_out(wc, 0x84, 0x31); /* PC5: XMFS active low, SCLKR is input, RCLK is output */
+ t1_framer_out(wc, 0x86, 0x03); /* PC6: CLK1 is Tx Clock output, CLK2 is 8.192 Mhz from DCO-R */
+ t1_framer_out(wc, 0x3b, 0x00); /* Clear LCR1 */
+ printk("TE110P: Successfully initialized serial bus for card\n");
+}
+
+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 = 0x1c; /* 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_framer_out(wc, 0x1d, fmr1);
+ __t1_framer_out(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_framer_out(wc, 0x1c, fmr0);
+
+ __t1_framer_out(wc, 0x20, fmr4);
+ __t1_framer_out(wc, 0x21, 0x40); /* FMR5: Enable RBS mode */
+
+ __t1_framer_out(wc, 0x37, 0xf8); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */
+ __t1_framer_out(wc, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */
+
+ __t1_framer_out(wc, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */
+ __t1_framer_out(wc, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */
+
+ __t1_framer_out(wc, 0x3a, lim2); /* LIM2: 50% peak amplitude is a "1" */
+ __t1_framer_out(wc, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */
+ __t1_framer_out(wc, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */
+
+ if (j1mode)
+ __t1_framer_out(wc, 0x24, 0x80); /* J1 overide */
+
+ /* Generate pulse mask for T1 */
+ switch(mytxlevel) {
+ case 3:
+ __t1_framer_out(wc, 0x26, 0x07); /* XPM0 */
+ __t1_framer_out(wc, 0x27, 0x01); /* XPM1 */
+ __t1_framer_out(wc, 0x28, 0x00); /* XPM2 */
+ break;
+ case 2:
+ __t1_framer_out(wc, 0x26, 0x8c); /* XPM0 */
+ __t1_framer_out(wc, 0x27, 0x11); /* XPM1 */
+ __t1_framer_out(wc, 0x28, 0x01); /* XPM2 */
+ break;
+ case 1:
+ __t1_framer_out(wc, 0x26, 0x8c); /* XPM0 */
+ __t1_framer_out(wc, 0x27, 0x01); /* XPM1 */
+ __t1_framer_out(wc, 0x28, 0x00); /* XPM2 */
+ break;
+ case 0:
+ default:
+ __t1_framer_out(wc, 0x26, 0xd7); /* XPM0 */
+ __t1_framer_out(wc, 0x27, 0x22); /* XPM1 */
+ __t1_framer_out(wc, 0x28, 0x01); /* XPM2 */
+ break;
+ }
+ printk("TE110P: 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 = 0x44; /* 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_framer_out(wc, 0x1d, fmr1);
+ __t1_framer_out(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_framer_out(wc, 0x1c, fmr0);
+
+ if (unchannelized)
+ __t1_framer_out(wc, 0x1f, 0x40);
+
+ __t1_framer_out(wc, 0x37, 0xf0 /*| 0x6 */ ); /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */
+ __t1_framer_out(wc, 0x36, 0x08); /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */
+
+ __t1_framer_out(wc, 0x02, 0x50); /* CMDR: Reset the receiver and transmitter line interface */
+ __t1_framer_out(wc, 0x02, 0x00); /* CMDR: Reset the receiver and transmitter line interface */
+
+ /* Condition receive line interface for E1 after reset */
+ __t1_framer_out(wc, 0xbb, 0x17);
+ __t1_framer_out(wc, 0xbc, 0x55);
+ __t1_framer_out(wc, 0xbb, 0x97);
+ __t1_framer_out(wc, 0xbb, 0x11);
+ __t1_framer_out(wc, 0xbc, 0xaa);
+ __t1_framer_out(wc, 0xbb, 0x91);
+ __t1_framer_out(wc, 0xbb, 0x12);
+ __t1_framer_out(wc, 0xbc, 0x55);
+ __t1_framer_out(wc, 0xbb, 0x92);
+ __t1_framer_out(wc, 0xbb, 0x0c);
+ __t1_framer_out(wc, 0xbb, 0x00);
+ __t1_framer_out(wc, 0xbb, 0x8c);
+
+ __t1_framer_out(wc, 0x3a, 0x20); /* LIM2: 50% peak amplitude is a "1" */
+ __t1_framer_out(wc, 0x38, 0x0a); /* PCD: LOS after 176 consecutive "zeros" */
+ __t1_framer_out(wc, 0x39, 0x15); /* PCR: 22 "ones" clear LOS */
+
+ __t1_framer_out(wc, 0x20, 0x9f); /* XSW: Spare bits all to 1 */
+ if (unchannelized)
+ __t1_framer_out(wc, 0x21, 0x3c);
+ else
+ __t1_framer_out(wc, 0x21, 0x1c|cas); /* XSP: E-bit set when async. AXS auto, XSIF to 1 */
+
+
+ /* Generate pulse mask for E1 */
+ __t1_framer_out(wc, 0x26, 0x54); /* XPM0 */
+ __t1_framer_out(wc, 0x27, 0x02); /* XPM1 */
+ __t1_framer_out(wc, 0x28, 0x00); /* XPM2 */
+ printk("TE110P: 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;
+
+ spin_lock_irqsave(&wc->lock, 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);
+ }
+
+ if (!alreadyrunning)
+ wc->span.flags |= ZT_FLAG_RUNNING;
+
+ spin_unlock_irqrestore(&wc->lock, flags);
+}
+
+
+static int t1xxp_startup(struct zt_span *span)
+{
+ struct t1 *wc = span->pvt;
+
+ int i,alreadyrunning = span->flags & ZT_FLAG_RUNNING;
+
+ /* 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);
+ printk("Calling startup (flags is %d)\n", span->flags);
+
+ if (!alreadyrunning) {
+ /* Only if we're not already going */
+ t1xxp_enable_interrupts(wc);
+ t1xxp_start_dma(wc);
+ span->flags |= ZT_FLAG_RUNNING;
+ }
+ return 0;
+}
+
+static int t1xxp_shutdown(struct zt_span *span)
+{
+ struct t1 *wc = span->pvt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->lock, flags);
+ __t1_framer_out(wc, 0x46, 0x41); /* GCR: Interrupt on Activation/Deactivation of AIX, LOS */
+ __t1xxp_stop_dma(wc);
+ __t1xxp_disable_interrupts(wc);
+ span->flags &= ~ZT_FLAG_RUNNING;
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return 0;
+}
+
+
+static int t1xxp_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ struct t1 *wc = chan->pvt;
+ unsigned long flags;
+ int alreadyrunning = chan->span->flags & ZT_FLAG_RUNNING;
+
+ spin_lock_irqsave(&wc->lock, flags);
+
+ if (alreadyrunning && (wc->spantype != TYPE_E1))
+ __t1xxp_set_clear(wc);
+
+ spin_unlock_irqrestore(&wc->lock, flags);
+ return 0;
+}
+
+static int t1xxp_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+ struct t1 *wc = span->pvt;
+
+ /* Do we want to SYNC on receive or not */
+ wc->sync = lc->sync;
+ /* If already running, apply changes immediately */
+ if (span->flags & ZT_FLAG_RUNNING)
+ return t1xxp_startup(span);
+
+ return 0;
+}
+
+static int t1xxp_software_init(struct t1 *wc)
+{
+ int x;
+ /* Find position */
+ for (x=0;x<WC_MAX_CARDS;x++) {
+ if (!cards[x]) {
+ cards[x] = wc;
+ break;
+ }
+ }
+ if (x >= WC_MAX_CARDS)
+ return -1;
+ t4_serial_setup(wc);
+ wc->num = x;
+ sprintf(wc->span.name, "WCT1/%d", wc->num);
+ snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num);
+ wc->span.manufacturer = "Digium";
+ zap_copy_string(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype));
+ snprintf(wc->span.location, sizeof(wc->span.location) - 1,
+ "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1);
+ wc->span.spanconfig = t1xxp_spanconfig;
+ wc->span.chanconfig = t1xxp_chanconfig;
+ wc->span.irq = wc->dev->irq;
+ 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;
+ if (wc->spantype == TYPE_E1) {
+ if (unchannelized)
+ wc->span.channels = 32;
+ else
+ wc->span.channels = 31;
+ wc->span.deflaw = ZT_LAW_ALAW;
+ wc->span.spantype = "E1";
+ wc->span.linecompat = ZT_CONFIG_HDB3 | ZT_CONFIG_CCS | ZT_CONFIG_CRC4;
+ } else {
+ wc->span.channels = 24;
+ wc->span.deflaw = ZT_LAW_MULAW;
+ wc->span.spantype = "T1";
+ wc->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
+ }
+ wc->span.chans = wc->chans;
+ wc->span.flags = ZT_FLAG_RBS;
+ wc->span.ioctl = t1xxp_ioctl;
+ wc->span.pvt = wc;
+ 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_MTP2 |
+ 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)) {
+ printk("Unable to register span with zaptel\n");
+ return -1;
+ }
+ return 0;
+}
+
+static inline void __handle_leds(struct t1 *wc)
+{
+ int oldreg;
+
+ if (wc->span.alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE)) {
+ /* Red/Blue alarm */
+ wc->blinktimer++;
+#ifdef FANCY_ALARM
+ if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) {
+ wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0;
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ }
+ if (wc->blinktimer >= 0xf) {
+ wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1);
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ wc->blinktimer = -1;
+ wc->alarmpos++;
+ if (wc->alarmpos >= (sizeof(altab) / sizeof(altab[0])))
+ wc->alarmpos = 0;
+ }
+#else
+ if (wc->blinktimer == 160) {
+ wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0;
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ } else if (wc->blinktimer == 480) {
+ wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1);
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ wc->blinktimer = 0;
+ }
+#endif
+ } else if (wc->span.alarms & ZT_ALARM_YELLOW) {
+ /* Yellow Alarm */
+ if (!(wc->blinktimer % 2))
+ wc->ledtestreg = (wc->ledtestreg | BIT_LED1) & ~BIT_LED0;
+ else
+ wc->ledtestreg = (wc->ledtestreg | BIT_LED0) & ~BIT_LED1;
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ } else {
+ /* No Alarm */
+ oldreg = wc->ledtestreg;
+ if (wc->span.maintstat != ZT_MAINT_NONE)
+ wc->ledtestreg |= BIT_TEST;
+ else
+ wc->ledtestreg &= ~BIT_TEST;
+ if (wc->span.flags & ZT_FLAG_RUNNING)
+ wc->ledtestreg = (wc->ledtestreg | BIT_LED0) & ~BIT_LED1;
+ else
+ wc->ledtestreg = wc->ledtestreg & ~(BIT_LED0 | BIT_LED1);
+ if (oldreg != wc->ledtestreg)
+ __control_set_reg(wc, WC_LEDTEST, wc->ledtestreg);
+ }
+}
+
+static void t1xxp_transmitprep(struct t1 *wc, int ints)
+{
+ volatile unsigned char *txbuf;
+ int x,y;
+ int pos;
+ if (ints & 0x04 /* 0x01 */) {
+ /* We just finished sending the first buffer, start filling it
+ now */
+ txbuf = wc->writechunk;
+ } else {
+ /* Just finished sending second buffer, fill it now */
+ txbuf = wc->writechunk + 32 * ZT_CHUNKSIZE;
+ }
+ zt_transmit(&wc->span);
+ for (x=0;x<wc->offset;x++)
+ txbuf[x] = wc->tempo[x];
+ for (y=0;y<ZT_CHUNKSIZE;y++) {
+ for (x=0;x<wc->span.channels;x++) {
+ pos = y * 32 + wc->chanmap[x] + wc->offset;
+ /* Put channel number as outgoing data */
+ if (pos < 32 * ZT_CHUNKSIZE)
+ txbuf[pos] = wc->chans[x].writechunk[y];
+ else
+ wc->tempo[pos - 32 * ZT_CHUNKSIZE] = wc->chans[x].writechunk[y];
+ }
+ }
+}
+
+static void t1xxp_receiveprep(struct t1 *wc, int ints)
+{
+ volatile unsigned char *rxbuf;
+ volatile unsigned int *canary;
+ int x;
+ int y;
+ unsigned int oldcan;
+ if (ints & 0x04) {
+ /* Just received first buffer */
+ rxbuf = wc->readchunk;
+ canary = (unsigned int *)(wc->readchunk + ZT_CHUNKSIZE * 64 - 4);
+ } else {
+ rxbuf = wc->readchunk + ZT_CHUNKSIZE * 32;
+ canary = (unsigned int *)(wc->readchunk + ZT_CHUNKSIZE * 32 - 4);
+ }
+ oldcan = *canary;
+ if (((oldcan & 0xffff0000) >> 16) != CANARY) {
+ /* Check top part */
+ if (debug) printk("Expecting top %04x, got %04x\n", CANARY, (oldcan & 0xffff0000) >> 16);
+ wc->span.irqmisses++;
+ } else if ((oldcan & 0xffff) != ((wc->canary - 1) & 0xffff)) {
+ if (debug) printk("Expecting bottom %d, got %d\n", wc->canary - 1, oldcan & 0xffff);
+ wc->span.irqmisses++;
+ }
+ for (y=0;y<ZT_CHUNKSIZE;y++) {
+ for (x=0;x<wc->span.channels;x++) {
+ /* XXX Optimize, remove * and + XXX */
+ /* Must map received channels into appropriate data */
+ wc->chans[x].readchunk[y] =
+ rxbuf[32 * y + ((wc->chanmap[x] + WC_OFFSET + wc->offset) & 0x1f)];
+ }
+ if (wc->spantype != TYPE_E1) {
+ for (x=3;x<32;x+=4) {
+ if (rxbuf[32 * y + ((x + WC_OFFSET) & 0x1f)] == 0x7f) {
+ if (wc->offset != (x-3)) {
+ /* Resync */
+ control_set_reg(wc, WC_CLOCK, 0x06 | wc->sync | clockextra);
+ wc->clocktimeout = 100;
+#if 1
+ if (debug) printk("T1: Lost our place, resyncing\n");
+#endif
+ }
+ }
+ }
+ } else if (!unchannelized) {
+ if (!wc->clocktimeout && !wc->span.alarms) {
+ if ((rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)] & 0x7f) != 0x1b) {
+ if (wc->miss) {
+ if (debug) printk("Double miss (%d, %d)...\n", wc->misslast, rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)]);
+ control_set_reg(wc, WC_CLOCK, 0x06 | wc->sync | clockextra);
+ wc->clocktimeout = 100;
+ } else {
+ wc->miss = 1;
+ wc->misslast = rxbuf[32 * y + ((3 + WC_OFFSET + wc->offset) & 0x1f)];
+ }
+ } else {
+ wc->miss = 0;
+ }
+ } else {
+ wc->miss = 0;
+ }
+ }
+ }
+ /* Store the next canary */
+ canary = (unsigned int *)(rxbuf + ZT_CHUNKSIZE * 32 - 4);
+ *canary = (wc->canary++) | (CANARY << 16);
+ 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);
+}
+
+static void t1_check_alarms(struct t1 *wc)
+{
+ unsigned char c,d;
+ int alarms;
+ int x,j;
+ unsigned long flags;
+
+ if (!(wc->span.flags & ZT_FLAG_RUNNING))
+ return;
+
+ spin_lock_irqsave(&wc->lock, flags);
+
+ c = __t1_framer_in(wc, 0x4c);
+ if (wc->spanflags & FLAG_FALC12)
+ d = __t1_framer_in(wc, 0x4f);
+ else
+ d = __t1_framer_in(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->spanflags & FLAG_NMF)) {
+ __t1_framer_out(wc, 0x20, 0x9f | 0x20); /* LIM0: Force RAI High */
+ wc->spanflags |= FLAG_NMF;
+ printk("NMF workaround on!\n");
+ }
+ __t1_framer_out(wc, 0x1e, 0xc3); /* Reset to CRC4 mode */
+ __t1_framer_out(wc, 0x1c, 0xf2); /* Force Resync */
+ __t1_framer_out(wc, 0x1c, 0xf0); /* Force Resync */
+ } else if (!(c & 0x02)) {
+ if ((wc->spanflags & FLAG_NMF)) {
+ __t1_framer_out(wc, 0x20, 0x9f); /* LIM0: Clear forced RAI */
+ wc->spanflags &= ~FLAG_NMF;
+ 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_framer_out(wc, 0x36, 0x08); /* LIM0: Disable any local loop */
+ __t1_framer_out(wc, 0x37, 0xf6 ); /* 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_framer_out(wc, 0x36, 0x08); /* LIM0: Disable any local loop */
+ __t1_framer_out(wc, 0x37, 0xf0 ); /* 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;
+
+ if (((!wc->span.alarms) && alarms) ||
+ (wc->span.alarms && (!alarms)))
+ wc->checktiming = 1;
+
+ /* 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->spanflags & FLAG_SENDINGYELLOW)) {
+ unsigned char fmr4;
+#if 1
+ printk("wcte1xxp: Setting yellow alarm\n");
+#endif
+ /* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */
+ fmr4 = __t1_framer_in(wc, 0x20);
+ __t1_framer_out(wc, 0x20, fmr4 | 0x20);
+ wc->spanflags |= FLAG_SENDINGYELLOW;
+ } else if ((!alarms) && (wc->spanflags & FLAG_SENDINGYELLOW)) {
+ unsigned char fmr4;
+#if 1
+ printk("wcte1xxp: Clearing yellow alarm\n");
+#endif
+ /* We manually do yellow alarm to handle RECOVER */
+ fmr4 = __t1_framer_in(wc, 0x20);
+ __t1_framer_out(wc, 0x20, fmr4 & ~0x20);
+ wc->spanflags &= ~FLAG_SENDINGYELLOW;
+ }
+
+ /* Re-check the timing source when we enter/leave alarm, not withstanding
+ yellow alarm */
+ if ((c & 0x10) && !unchannelized)
+ alarms |= ZT_ALARM_YELLOW;
+ if (wc->span.mainttimer || wc->span.maintstat)
+ alarms |= ZT_ALARM_LOOPBACK;
+ wc->span.alarms = alarms;
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_alarm_notify(&wc->span);
+}
+
+
+static void t1_do_counters(struct t1 *wc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wc->lock, flags);
+ if (wc->alarmtimer) {
+ if (!--wc->alarmtimer) {
+ wc->span.alarms &= ~(ZT_ALARM_RECOVER);
+ spin_unlock_irqrestore(&wc->lock, flags);
+ zt_alarm_notify(&wc->span);
+ spin_lock_irqsave(&wc->lock, flags);
+ }
+ }
+ spin_unlock_irqrestore(&wc->lock, flags);
+}
+
+ZAP_IRQ_HANDLER(t1xxp_interrupt)
+{
+ struct t1 *wc = dev_id;
+ unsigned char ints;
+ unsigned long flags;
+ int x;
+
+ ints = inb(wc->ioaddr + WC_INTSTAT);
+ if (!ints)
+#ifdef LINUX26
+ return IRQ_NONE;
+#else
+ return;
+#endif
+
+ outb(ints, wc->ioaddr + WC_INTSTAT);
+
+ if (!wc->intcount) {
+ if (debug) printk("Got interrupt: 0x%04x\n", ints);
+ }
+ wc->intcount++;
+
+ if (wc->clocktimeout && !--wc->clocktimeout)
+ control_set_reg(wc, WC_CLOCK, 0x04 | wc->sync | clockextra);
+
+ if (ints & 0x0f) {
+ t1xxp_receiveprep(wc, ints);
+ t1xxp_transmitprep(wc, ints);
+ }
+ spin_lock_irqsave(&wc->lock, flags);
+
+#if 1
+ __handle_leds(wc);
+#endif
+
+ spin_unlock_irqrestore(&wc->lock, flags);
+
+ /* Count down timers */
+ t1_do_counters(wc);
+
+ /* Do some things that we don't have to do very often */
+ x = wc->intcount & 15 /* 63 */;
+ switch(x) {
+ case 0:
+ case 1:
+ break;
+ case 2:
+ t1_check_sigbits(wc);
+ break;
+ case 4:
+ /* Check alarms 1/4 as frequently */
+ if (!(wc->intcount & 0x30))
+ t1_check_alarms(wc);
+ break;
+ }
+
+ if (ints & 0x10)
+ printk("PCI Master abort\n");
+
+ if (ints & 0x20)
+ printk("PCI Target abort\n");
+
+#ifdef LINUX26
+ return IRQ_RETVAL(1);
+#endif
+}
+
+static int t1xxp_hardware_init(struct t1 *wc)
+{
+ unsigned int falcver;
+ unsigned int x;
+ /* Hardware PCI stuff */
+ /* Reset chip and registers */
+ outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL);
+ /* Set all outputs to 0 */
+ outb(0x00, wc->ioaddr + WC_AUXD);
+ /* Set all to outputs except AUX1 (TDO). */
+ outb(0xfd, wc->ioaddr + WC_AUXC);
+ /* Configure the serial port: double clock, 20ns width, no inversion,
+ MSB first */
+ outb(0xc8, wc->ioaddr + WC_SERC);
+
+ /* Internally delay FSC by one */
+ outb(0x01, wc->ioaddr + WC_FSCDELAY);
+
+ /* Back to normal, with automatic DMA wrap around */
+ outb(DELAY | 0x01, wc->ioaddr + WC_CNTL);
+
+ /* Make sure serial port and DMA are out of reset */
+ outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, WC_CNTL);
+
+ /* Setup DMA Addresses */
+ /* Start at writedma */
+ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */
+ /* First frame */
+ outl(wc->writedma + ZT_CHUNKSIZE * 32 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */
+ /* Second frame */
+ outl(wc->writedma + ZT_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMAWE); /* End */
+
+ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */
+ /* First frame */
+ outl(wc->readdma + ZT_CHUNKSIZE * 32 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */
+ /* Second frame */
+ outl(wc->readdma + ZT_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMARE); /* End */
+
+ if (debug) printk("Setting up DMA (write/read = %08lx/%08lx)\n", (long)wc->writedma, (long)wc->readdma);
+
+ if (t1e1override > -1) {
+ if (t1e1override)
+ wc->spantype = TYPE_E1;
+ else
+ wc->spantype = TYPE_T1;
+ } else {
+ if (control_get_reg(wc, WC_CLOCK) & 0x20)
+ wc->spantype = TYPE_T1;
+ else
+ wc->spantype = TYPE_E1;
+ }
+
+ /* Check out the controller */
+ if (debug) printk("Controller version: %02x\n", control_get_reg(wc, WC_VERSION));
+
+
+ control_set_reg(wc, WC_LEDTEST, 0x00);
+
+ if (wc->spantype == TYPE_E1) {
+ if (unchannelized)
+ wc->chanmap = chanmap_e1uc;
+ else
+ wc->chanmap = chanmap_e1;
+ } else
+ wc->chanmap = chanmap_t1;
+ /* Setup clock appropriately */
+ control_set_reg(wc, WC_CLOCK, 0x06 | wc->sync | clockextra);
+ wc->clocktimeout = 100;
+
+ /* Perform register test on FALC */
+ for (x=0;x<256;x++) {
+ t1_framer_out(wc, 0x14, x);
+ if ((falcver = t1_framer_in(wc, 0x14)) != x)
+ printk("Wrote '%x' but read '%x'\n", x, falcver);
+ }
+
+ t1_framer_out(wc, 0x4a, 0xaa);
+ falcver = t1_framer_in(wc ,0x4a);
+ printk("FALC version: %08x\n", falcver);
+ if (!falcver)
+ wc->spanflags |= FLAG_FALC12;
+
+
+ start_alarm(wc);
+ return 0;
+
+}
+
+static int __devinit t1xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int res;
+ struct t1 *wc;
+ unsigned int *canary;
+
+ if (pci_enable_device(pdev)) {
+ res = -EIO;
+ } else {
+ wc = kmalloc(sizeof(struct t1), GFP_KERNEL);
+ if (wc) {
+ memset(wc, 0x0, sizeof(struct t1));
+ spin_lock_init(&wc->lock);
+ wc->ioaddr = pci_resource_start(pdev, 0);
+ wc->dev = pdev;
+ wc->offset = 28; /* And you thought 42 was the answer */
+
+ wc->writechunk =
+ /* 32 channels, Double-buffer, Read/Write */
+ (unsigned char *)pci_alloc_consistent(pdev, ZT_MAX_CHUNKSIZE * 32 * 2 * 2, &wc->writedma);
+ if (!wc->writechunk) {
+ printk("wcte11xp: Unable to allocate DMA-able memory\n");
+ return -ENOMEM;
+ }
+
+ /* Read is after the whole write piece (in bytes) */
+ wc->readchunk = wc->writechunk + ZT_CHUNKSIZE * 32 * 2;
+
+ /* Same thing... */
+ wc->readdma = wc->writedma + ZT_CHUNKSIZE * 32 * 2;
+
+ /* Initialize Write/Buffers to all blank data */
+ memset((void *)wc->writechunk,0x00,ZT_MAX_CHUNKSIZE * 2 * 2 * 32);
+ /* Initialize canary */
+ canary = (unsigned int *)(wc->readchunk + ZT_CHUNKSIZE * 64 - 4);
+ *canary = (CANARY << 16) | (0xffff);
+
+ /* Enable bus mastering */
+ pci_set_master(pdev);
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, wc);
+
+ if (request_irq(pdev->irq, t1xxp_interrupt, ZAP_IRQ_SHARED_DISABLED, "wcte11xp", wc)) {
+ printk("wcte11xp: Unable to request IRQ %d\n", pdev->irq);
+ kfree(wc);
+ return -EIO;
+ }
+ /* Initialize hardware */
+ t1xxp_hardware_init(wc);
+
+ /* We now know which version of card we have */
+ wc->variety = "Digium Wildcard TE110P T1/E1";
+
+ /* Misc. software stuff */
+ t1xxp_software_init(wc);
+
+ printk("Found a Wildcard: %s\n", wc->variety);
+ res = 0;
+ } else
+ res = -ENOMEM;
+ }
+ return res;
+}
+
+static void t1xxp_stop_stuff(struct t1 *wc)
+{
+ /* Kill clock */
+ control_set_reg(wc, WC_CLOCK, 0);
+
+ /* Turn off LED's */
+ control_set_reg(wc, WC_LEDTEST, 0);
+
+}
+
+static void __devexit t1xxp_remove_one(struct pci_dev *pdev)
+{
+ struct t1 *wc = pci_get_drvdata(pdev);
+ if (wc) {
+
+ /* Stop any DMA */
+ __t1xxp_stop_dma(wc);
+
+ /* In case hardware is still there */
+ __t1xxp_disable_interrupts(wc);
+
+ t1xxp_stop_stuff(wc);
+
+ /* Immediately free resources */
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 32 * 4, (void *)wc->writechunk, wc->writedma);
+ free_irq(pdev->irq, wc);
+
+ /* Reset PCI chip and registers */
+ outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL);
+
+ /* Release span, possibly delayed */
+ if (!wc->usecount)
+ t1xxp_release(wc);
+ else
+ wc->dead = 1;
+ }
+}
+
+static struct pci_device_id t1xxp_pci_tbl[] = {
+ { 0xe159, 0x0001, 0x71fe, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard TE110P T1/E1 Board" },
+ { 0xe159, 0x0001, 0x79fe, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard TE110P T1/E1 Board" },
+ { 0xe159, 0x0001, 0x795e, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard TE110P T1/E1 Board" },
+ { 0xe159, 0x0001, 0x79de, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard TE110P T1/E1 Board" },
+ { 0xe159, 0x0001, 0x797e, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard TE110P T1/E1 Board" },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci,t1xxp_pci_tbl);
+
+static struct pci_driver t1xxp_driver = {
+ name: "wcte11xp",
+ probe: t1xxp_init_one,
+#ifdef LINUX26
+ remove: __devexit_p(t1xxp_remove_one),
+#else
+ remove: t1xxp_remove_one,
+#endif
+ suspend: NULL,
+ resume: NULL,
+ id_table: t1xxp_pci_tbl,
+};
+
+static int __init t1xxp_init(void)
+{
+ int res;
+ res = zap_pci_module(&t1xxp_driver);
+ if (res)
+ return -ENODEV;
+ return 0;
+}
+
+static void __exit t1xxp_cleanup(void)
+{
+ pci_unregister_driver(&t1xxp_driver);
+}
+
+#ifdef LINUX26
+module_param(alarmdebounce, int, 0600);
+module_param(loopback, int, 0600);
+module_param(t1e1override, int, 0600);
+module_param(unchannelized, int, 0600);
+module_param(clockextra, int, 0600);
+module_param(debug, int, 0600);
+module_param(j1mode, int, 0600);
+#else
+MODULE_PARM(alarmdebounce, "i");
+MODULE_PARM(loopback, "i");
+MODULE_PARM(t1e1override, "i");
+MODULE_PARM(unchannelized, "i");
+MODULE_PARM(clockextra, "i");
+MODULE_PARM(debug, "i");
+MODULE_PARM(j1mode, "i");
+#endif
+MODULE_DESCRIPTION("Wildcard TE110P Zaptel Driver");
+MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(t1xxp_init);
+module_exit(t1xxp_cleanup);
diff --git a/drivers/dahdi/wcte12xp/GpakApi.c b/drivers/dahdi/wcte12xp/GpakApi.c
new file mode 100644
index 0000000..944c327
--- /dev/null
+++ b/drivers/dahdi/wcte12xp/GpakApi.c
@@ -0,0 +1,1617 @@
+/*
+ * Copyright (c) 2005, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakApi.c
+ *
+ * Description:
+ * This file contains user API functions to communicate with DSPs executing
+ * G.PAK software. The file is integrated into the host processor connected
+ * to C55X G.PAK DSPs via a Host Port Interface.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 06/15/05 - Initial release.
+ * 11/15/2006 - 24 TDM-TDM Channels EC release
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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 "zaptel.h"
+
+#include "GpakHpi.h"
+#include "vpmadt032.h"
+#include "GpakApi.h"
+#include "gpakenum.h"
+
+#ifdef VPM_SUPPORT
+
+/* DSP to Host interface block offsets. */
+#define REPLY_MSG_PNTR_OFFSET 0 /* I/F blk offset to Reply Msg Pointer */
+#define CMD_MSG_PNTR_OFFSET 2 /* I/F blk offset to Command Msg Pointer */
+#define EVENT_MSG_PNTR_OFFSET 4 /* I/F blk offset to Event Msg Pointer */
+#define PKT_BUFR_MEM_OFFSET 6 /* I/F blk offset to Packet Buffer memory */
+#define DSP_STATUS_OFFSET 8 /* I/F blk offset to DSP Status */
+#define VERSION_ID_OFFSET 9 /* I/F blk offset to G.PAK Version Id */
+#define MAX_CMD_MSG_LEN_OFFSET 10 /* I/F blk offset to Max Cmd Msg Length */
+#define CMD_MSG_LEN_OFFSET 11 /* I/F blk offset to Command Msg Length */
+#define REPLY_MSG_LEN_OFFSET 12 /* I/F blk offset to Reply Msg Length */
+#define NUM_CHANNELS_OFFSET 13 /* I/F blk offset to Num Built Channels */
+#define NUM_PKT_CHANNELS_OFFSET 14 /* I/F blk offset to Num Pkt Channels */
+#define NUM_CONFERENCES_OFFSET 15 /* I/F blk offset to Num Conferences */
+//#define CPU_USAGE_OFFSET_1MS 16 /* I/F blk offset to CPU Usage statistics */
+#define CPU_USAGE_OFFSET 18 /* I/F blk offset to CPU Usage statistics */
+//#define CPU_USAGE_OFFSET_10MS 20 /* I/F blk offset to CPU Usage statistics */
+#define FRAMING_STATS_OFFSET 22 /* I/F blk offset to Framing statistics */
+
+//#define GPAK_RELEASE_Rate rate10ms
+// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+// Macro to reconstruct a 32-bit value from two 16-bit values.
+// Parameter p32: 32-bit-wide destination
+// Parameter p16: 16-bit-wide source array of length 2 words
+#define RECONSTRUCT_LONGWORD(p32, p16) p32 = (DSP_ADDRESS)p16[0]<<16; \
+ p32 |= (unsigned long)p16[1]
+// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+
+/* DSP Status value definitions. */
+#define DSP_INIT_STATUS 0x5555 /* DSP Initialized status value */
+#define HOST_INIT_STATUS 0xAAAA /* Host Initialized status value */
+
+/* Circular packet buffer information structure offsets. */
+#define CB_BUFR_BASE 0 /* pointer to base of circular buffer */
+#define CB_BUFR_SIZE 2 /* size of buffer (words) */
+#define CB_BUFR_PUT_INDEX 3 /* offset in buffer for next write */
+#define CB_BUFR_TAKE_INDEX 4 /* offset in buffer for next read */
+#define CIRC_BUFFER_INFO_STRUCT_SIZE 6
+
+/* Miscellaneous definitions. */
+#define MSG_BUFFER_SIZE 100 /* size (words) of Host msg buffer */
+#define WORD_BUFFER_SIZE 84 /* size of DSP Word buffer (words) */
+
+#ifdef __TMS320C55XX__ // debug sections if not on host
+#pragma DATA_SECTION(pDspIfBlk,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(MaxCmdMsgLen,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(MaxChannels,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(DlByteBufr,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(DlWordBufr,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(pEventFifoAddress,"GPAKAPIDEBUG_SECT")
+#endif
+
+/* Host variables related to Host to DSP interface. */
+static DSP_ADDRESS pDspIfBlk[MAX_DSP_CORES]; /* DSP address of I/F block */
+static DSP_WORD MaxCmdMsgLen[MAX_DSP_CORES]; /* max Cmd msg length (octets) */
+static unsigned short int MaxChannels[MAX_DSP_CORES]; /* max num channels */
+
+//static unsigned short int MaxPktChannels[MAX_DSP_CORES]; /* max num pkt channels */
+//static unsigned short int MaxConfs[MAX_DSP_CORES]; /* max num conferences */
+//static DSP_ADDRESS pPktInBufr[MAX_DSP_CORES][MAX_PKT_CHANNELS]; /* Pkt In buffer */
+//static DSP_ADDRESS pPktOutBufr[MAX_DSP_CORES][MAX_PKT_CHANNELS]; /* Pkt Out buffer */
+static DSP_ADDRESS pEventFifoAddress[MAX_DSP_CORES]; /* event fifo */
+
+static unsigned char DlByteBufr[DOWNLOAD_BLOCK_SIZE * 2]; /* Dowload byte buf */
+static DSP_WORD DlWordBufr[DOWNLOAD_BLOCK_SIZE]; /* Dowload word buffer */
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CheckDspReset - Check if the DSP was reset.
+ *
+ * FUNCTION
+ * This function determines if the DSP was reset and is ready. If reset
+ * occurred, it reads interface parameters and calculates DSP addresses.
+ *
+ * RETURNS
+ * -1 = DSP is not ready.
+ * 0 = Reset did not occur.
+ * 1 = Reset occurred.
+ *
+ */
+static int CheckDspReset(
+ int DspId /* DSP Identifier (0 to MaxDSPCores-1) */
+ )
+{
+ DSP_ADDRESS IfBlockPntr; /* Interface Block pointer */
+ DSP_WORD DspStatus; /* DSP Status */
+ DSP_WORD DspChannels; /* number of DSP channels */
+ DSP_WORD Temp[2];
+#if 0
+ DSP_WORD DspConfs; /* number of DSP conferences */
+ DSP_ADDRESS PktBufrMem; /* address of Packet Buffer */
+ unsigned short int i; /* loop index / counter */
+#endif
+
+ /* Read the pointer to the Interface Block. */
+ gpakReadDspMemory(DspId, DSP_IFBLK_ADDRESS, 2, Temp);
+ RECONSTRUCT_LONGWORD(IfBlockPntr, Temp);
+
+ /* If the pointer is zero, return with an indication the DSP is not
+ ready. */
+ if (IfBlockPntr == 0)
+ return (-1);
+
+ /* Read the DSP's Status. */
+ gpakReadDspMemory(DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1, &DspStatus);
+
+ /* If status indicates the DSP was reset, read the DSP's interface
+ parameters and calculate DSP addresses. */
+ if (DspStatus == DSP_INIT_STATUS ||
+ ((DspStatus == HOST_INIT_STATUS) && (pDspIfBlk[DspId] == 0)))
+ {
+ /* Save the address of the DSP's Interface Block. */
+ pDspIfBlk[DspId] = IfBlockPntr;
+
+ /* Read the DSP's interface parameters. */
+ gpakReadDspMemory(DspId, IfBlockPntr + MAX_CMD_MSG_LEN_OFFSET, 1,
+ &(MaxCmdMsgLen[DspId]));
+
+ /* read the number of configured DSP channels */
+ gpakReadDspMemory(DspId, IfBlockPntr + NUM_CHANNELS_OFFSET, 1,
+ &DspChannels);
+ if (DspChannels > MAX_CHANNELS)
+ MaxChannels[DspId] = MAX_CHANNELS;
+ else
+ MaxChannels[DspId] = (unsigned short int) DspChannels;
+#if 0
+ /* read the number of configured DSP conferences */
+ gpakReadDspMemory(DspId, IfBlockPntr + NUM_CONFERENCES_OFFSET, 1,
+ &DspConfs);
+ if (DspConfs > MAX_CONFS)
+ MaxConfs[DspId] = MAX_CONFS;
+ else
+ MaxConfs[DspId] = (unsigned short int) DspConfs;
+
+
+ /* read the number of configured DSP packet channels */
+ gpakReadDspMemory(DspId, IfBlockPntr + NUM_PKT_CHANNELS_OFFSET, 1,
+ &DspChannels);
+ if (DspChannels > MAX_PKT_CHANNELS)
+ MaxPktChannels[DspId] = MAX_PKT_CHANNELS;
+ else
+ MaxPktChannels[DspId] = (unsigned short int) DspChannels;
+
+
+ /* read the pointer to the circular buffer infor struct table */
+ gpakReadDspMemory(DspId, IfBlockPntr + PKT_BUFR_MEM_OFFSET, 2, Temp);
+ RECONSTRUCT_LONGWORD(PktBufrMem, Temp);
+
+
+ /* Determine the addresses of each channel's Packet buffers. */
+ for (i = 0; i < MaxPktChannels[DspId]; i++)
+ {
+ pPktInBufr[DspId][i] = PktBufrMem;
+ pPktOutBufr[DspId][i] = PktBufrMem + CIRC_BUFFER_INFO_STRUCT_SIZE;
+ PktBufrMem += (CIRC_BUFFER_INFO_STRUCT_SIZE*2);
+ }
+#endif
+
+ /* read the pointer to the event fifo info struct */
+ gpakReadDspMemory(DspId, IfBlockPntr + EVENT_MSG_PNTR_OFFSET, 2, Temp);
+ RECONSTRUCT_LONGWORD(pEventFifoAddress[DspId], Temp);
+
+ /* Set the DSP Status to indicate the host recognized the reset. */
+ DspStatus = HOST_INIT_STATUS;
+ gpakWriteDspMemory(DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1,
+ &DspStatus);
+
+ /* Return with an indication that a reset occurred. */
+ return (1);
+ }
+
+ /* If status doesn't indicate the host recognized a reset, return with an
+ indication the DSP is not ready. */
+ if ((DspStatus != HOST_INIT_STATUS) || (pDspIfBlk[DspId] == 0))
+ return (-1);
+
+ /* Return with an indication that a reset did not occur. */
+ return (0);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * WriteDspCmdMessage - Write a Host Command/Request message to DSP.
+ *
+ * FUNCTION
+ * This function writes a Host Command/Request message into DSP memory and
+ * informs the DSP of the presence of the message.
+ *
+ * RETURNS
+ * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready)
+ * 0 = Temporarily unable to write message (previous Cmd Msg busy)
+ * 1 = Message written successfully
+ *
+ */
+static int WriteDspCmdMessage(
+ int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */
+ DSP_WORD *pMessage, /* pointer to Command message */
+ DSP_WORD MsgLength /* length of message (octets) */
+ )
+{
+ DSP_WORD CmdMsgLength; /* current Cmd message length */
+ DSP_WORD Temp[2];
+ DSP_ADDRESS BufferPointer; /* message buffer pointer */
+
+ /* Check if the DSP was reset and is ready. */
+ if (CheckDspReset(DspId) == -1)
+ return (-1);
+
+ /* Make sure the message length is valid. */
+ if ((MsgLength < 1) || (MsgLength > MaxCmdMsgLen[DspId]))
+ return (-1);
+
+ /* Make sure a previous Command message is not in use by the DSP. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1,
+ &CmdMsgLength);
+ if (CmdMsgLength != 0)
+ return (0);
+
+ /* Purge any previous Reply message that wasn't read. */
+ gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1,
+ &CmdMsgLength);
+
+ /* Copy the Command message into DSP memory. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_PNTR_OFFSET, 2, Temp);
+ RECONSTRUCT_LONGWORD(BufferPointer, Temp);
+ gpakWriteDspMemory(DspId, BufferPointer, (MsgLength + 1) / 2, pMessage);
+
+ /* Store the message length in DSP's Command message length (flags DSP that
+ a Command message is ready). */
+ CmdMsgLength = MsgLength;
+ gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1,
+ &CmdMsgLength);
+
+ /* Return with an indication the message was written. */
+ return (1);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ReadDspReplyMessage - Read a DSP Reply message from DSP.
+ *
+ * FUNCTION
+ * This function reads a DSP Reply message from DSP memory.
+ *
+ * RETURNS
+ * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready)
+ * 0 = No message available (DSP Reply message empty)
+ * 1 = Message read successfully (message and length stored in variables)
+ *
+ */
+static int ReadDspReplyMessage(
+ int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */
+ DSP_WORD *pMessage, /* pointer to Reply message buffer */
+ DSP_WORD *pMsgLength /* pointer to msg length var (octets) */
+ )
+{
+ DSP_WORD MsgLength; /* message length */
+ DSP_ADDRESS BufferPointer; /* message buffer pointer */
+ DSP_WORD Temp[2];
+
+ /* Check if the DSP was reset and is ready. */
+ if (CheckDspReset(DspId) == -1)
+ return (-1);
+
+ /* Check if a Reply message is ready. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1,
+ &MsgLength);
+ if (MsgLength == 0)
+ return (0);
+
+ /* Make sure the message length is valid. */
+ if (MsgLength > *pMsgLength)
+ return (-1);
+
+ /* Copy the Reply message from DSP memory. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_PNTR_OFFSET, 2, Temp);
+ RECONSTRUCT_LONGWORD(BufferPointer, Temp);
+ gpakReadDspMemory(DspId, BufferPointer, (MsgLength + 1) / 2, pMessage);
+
+ /* Store the message length in the message length variable. */
+ *pMsgLength = MsgLength;
+
+ /* Indicate a Reply message is not ready. */
+ MsgLength = 0;
+ gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1,
+ &MsgLength);
+
+ /* Return with an indication the message was read. */
+ return (1);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ReadCircBuffer - Read from a DSP circular buffer.
+ *
+ * FUNCTION
+ * This function reads a block of words from a DSP circular buffer. The Take
+ * address is incremented by the number of words read adjusting for buffer
+ * wrap.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+static void ReadCircBuffer(
+ int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */
+ DSP_ADDRESS BufrBaseAddress, /* address of base of circular buffer */
+ DSP_ADDRESS BufrLastAddress, /* address of last word in buffer */
+ DSP_ADDRESS *TakeAddress, /* pointer to address in buffer for read */
+ DSP_WORD *pWordBuffer, /* pointer to buffer for words read */
+ DSP_WORD NumWords /* number of words to read */
+ )
+{
+ DSP_WORD WordsTillEnd; /* number of words until end of buffer */
+
+ /* Determine the number of words from the start address until the end of the
+ buffer. */
+ WordsTillEnd = BufrLastAddress - *TakeAddress + 1;
+
+ /* If a buffer wrap will occur, read the first part at the end of the
+ buffer followed by the second part at the beginning of the buffer. */
+ if (NumWords > WordsTillEnd)
+ {
+ gpakReadDspMemory(DspId, *TakeAddress, WordsTillEnd, pWordBuffer);
+ gpakReadDspMemory(DspId, BufrBaseAddress, NumWords - WordsTillEnd,
+ &(pWordBuffer[WordsTillEnd]));
+ *TakeAddress = BufrBaseAddress + NumWords - WordsTillEnd;
+ }
+
+ /* If a buffer wrap will not occur, read all words starting at the current
+ take address in the buffer. */
+ else
+ {
+ gpakReadDspMemory(DspId, *TakeAddress, NumWords, pWordBuffer);
+ if (NumWords == WordsTillEnd)
+ *TakeAddress = BufrBaseAddress;
+ else
+ *TakeAddress = *TakeAddress + NumWords;
+ }
+ return;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * VerifyReply - Verify the reply message is correct for the command sent.
+ *
+ * FUNCTION
+ * This function verifies correct reply message content for the command that
+ * was just sent.
+ *
+ * RETURNS
+ * 0 = Incorrect
+ * 1 = Correct
+ *
+ */
+static int VerifyReply(
+ DSP_WORD *pMsgBufr, /* pointer to Reply message buffer */
+ int CheckType, /* reply check type */
+ DSP_WORD CheckValue /* reply check value */
+ )
+{
+
+ /* Verify Channel or Conference Id. */
+ if (CheckType == 1)
+ {
+ if (((pMsgBufr[1] >> 8) & 0xFF) != CheckValue)
+ return (0);
+ }
+
+ /* Verify Test Mode Id. */
+ else if (CheckType == 2)
+ {
+ if (pMsgBufr[1] != CheckValue)
+ return (0);
+ }
+
+ /* Return with an indication of correct reply. */
+ return (1);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * TransactCmd - Send a command to the DSP and receive it's reply.
+ *
+ * FUNCTION
+ * This function sends the specified command to the DSP and receives the DSP's
+ * reply.
+ *
+ * RETURNS
+ * Length of reply message (0 = Failure)
+ *
+ */
+static unsigned int TransactCmd(
+ int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */
+ DSP_WORD *pMsgBufr, /* pointer to Cmd/Reply message buffer */
+ DSP_WORD CmdLength, /* length of command message (octets) */
+ DSP_WORD ReplyType, /* required type of reply message */
+ DSP_WORD ReplyLength, /* required length of reply message (octets) */
+ int ReplyCheckType, /* reply check type */
+ DSP_WORD ReplyCheckValue /* reply check value */
+ )
+{
+ int FuncStatus; /* function status */
+ int LoopCount; /* wait loop counter */
+ DSP_WORD RcvReplyLength; /* received Reply message length */
+ DSP_WORD RcvReplyType; /* received Reply message type code */
+ DSP_WORD RetValue; /* return value */
+
+ /* Default the return value to indicate a failure. */
+ RetValue = 0;
+
+ /* Lock access to the DSP. */
+ gpakLockAccess(DspId);
+
+ /* Attempt to write the command message to the DSP. */
+ LoopCount = 0;
+ while ((FuncStatus = WriteDspCmdMessage(DspId, pMsgBufr, CmdLength)) != 1)
+ {
+ if (FuncStatus == -1)
+ break;
+ if (++LoopCount > MAX_WAIT_LOOPS)
+ break;
+ gpakHostDelay();
+ }
+
+ /* Attempt to read the reply message from the DSP if the command message was
+ sent successfully. */
+ if (FuncStatus == 1)
+ {
+ for (LoopCount = 0; LoopCount < MAX_WAIT_LOOPS; LoopCount++)
+ {
+ RcvReplyLength = MSG_BUFFER_SIZE * 2;
+ FuncStatus = ReadDspReplyMessage(DspId, pMsgBufr, &RcvReplyLength);
+ if (FuncStatus == 1)
+ {
+ RcvReplyType = (pMsgBufr[0] >> 8) & 0xFF;
+ if ((RcvReplyLength >= ReplyLength) &&
+ (RcvReplyType == ReplyType) &&
+ VerifyReply(pMsgBufr, ReplyCheckType, ReplyCheckValue))
+ {
+ RetValue = RcvReplyLength;
+ break;
+ }
+ else if (RcvReplyType == MSG_NULL_REPLY)
+ break;
+ }
+ else if (FuncStatus == -1)
+ break;
+ gpakHostDelay();
+ }
+ }
+
+ /* Unlock access to the DSP. */
+ gpakUnlockAccess(DspId);
+
+ /* Return the length of the reply message (0 = failure). */
+ return (RetValue);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakConfigurePorts - Configure a DSP's serial ports.
+ *
+ * FUNCTION
+ * This function configures a DSP's serial ports.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakConfigPortStatus_t gpakConfigurePorts(
+ unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */
+ GpakPortConfig_t *pPortConfig, /* pointer to Port Config info */
+ GPAK_PortConfigStat_t *pStatus /* pointer to Port Config Status */
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (CpsInvalidDsp);
+
+ /* Build the Configure Serial Ports message. */
+ MsgBuffer[0] = MSG_CONFIGURE_PORTS << 8;
+ MsgBuffer[1] = (DSP_WORD)
+ ((pPortConfig->SlotsSelect1 << 12) |
+ ((pPortConfig->FirstBlockNum1 << 8) & 0x0F00) |
+ ((pPortConfig->SecBlockNum1 << 4) & 0x00F0));
+ MsgBuffer[2] = (DSP_WORD) pPortConfig->FirstSlotMask1;
+ MsgBuffer[3] = (DSP_WORD) pPortConfig->SecSlotMask1;
+ MsgBuffer[4] = (DSP_WORD)
+ ((pPortConfig->SlotsSelect2 << 12) |
+ ((pPortConfig->FirstBlockNum2 << 8) & 0x0F00) |
+ ((pPortConfig->SecBlockNum2 << 4) & 0x00F0));
+ MsgBuffer[5] = (DSP_WORD) pPortConfig->FirstSlotMask2;
+ MsgBuffer[6] = (DSP_WORD) pPortConfig->SecSlotMask2;
+ MsgBuffer[7] = (DSP_WORD)
+ ((pPortConfig->SlotsSelect3 << 12) |
+ ((pPortConfig->FirstBlockNum3 << 8) & 0x0F00) |
+ ((pPortConfig->SecBlockNum3 << 4) & 0x00F0));
+ MsgBuffer[8] = (DSP_WORD) pPortConfig->FirstSlotMask3;
+ MsgBuffer[9] = (DSP_WORD) pPortConfig->SecSlotMask3;
+
+ MsgBuffer[10] = (DSP_WORD)
+ (((pPortConfig->DxDelay1 << 11) & 0x0800) |
+ ((pPortConfig->RxDataDelay1 << 9) & 0x0600) |
+ ((pPortConfig->TxDataDelay1 << 7) & 0x0180) |
+ ((pPortConfig->RxClockPolarity1 << 6) & 0x0040) |
+ ((pPortConfig->TxClockPolarity1 << 5) & 0x0020) |
+ ((pPortConfig->RxFrameSyncPolarity1 << 4) & 0x0010) |
+ ((pPortConfig->TxFrameSyncPolarity1 << 3) & 0x0008) |
+ ((pPortConfig->CompandingMode1 << 1) & 0x0006) |
+ (pPortConfig->SerialWordSize1 & 0x0001));
+
+ MsgBuffer[11] = (DSP_WORD)
+ (((pPortConfig->DxDelay2 << 11) & 0x0800) |
+ ((pPortConfig->RxDataDelay2 << 9) & 0x0600) |
+ ((pPortConfig->TxDataDelay2 << 7) & 0x0180) |
+ ((pPortConfig->RxClockPolarity2 << 6) & 0x0040) |
+ ((pPortConfig->TxClockPolarity2 << 5) & 0x0020) |
+ ((pPortConfig->RxFrameSyncPolarity2 << 4) & 0x0010) |
+ ((pPortConfig->TxFrameSyncPolarity2 << 3) & 0x0008) |
+ ((pPortConfig->CompandingMode2 << 1) & 0x0006) |
+ (pPortConfig->SerialWordSize1 & 0x0001));
+
+ MsgBuffer[12] = (DSP_WORD)
+ (((pPortConfig->DxDelay3 << 11) & 0x0800) |
+ ((pPortConfig->RxDataDelay3 << 9) & 0x0600) |
+ ((pPortConfig->TxDataDelay3 << 7) & 0x0180) |
+ ((pPortConfig->RxClockPolarity3 << 6) & 0x0040) |
+ ((pPortConfig->TxClockPolarity3 << 5) & 0x0020) |
+ ((pPortConfig->RxFrameSyncPolarity3 << 4) & 0x0010) |
+ ((pPortConfig->TxFrameSyncPolarity3 << 3) & 0x0008) |
+ ((pPortConfig->CompandingMode3 << 1) & 0x0006) |
+ (pPortConfig->SerialWordSize3 & 0x0001));
+
+ MsgBuffer[13] = (DSP_WORD) pPortConfig->ThirdSlotMask1;
+ MsgBuffer[14] = (DSP_WORD) pPortConfig->FouthSlotMask1;
+ MsgBuffer[15] = (DSP_WORD) pPortConfig->FifthSlotMask1;
+ MsgBuffer[16] = (DSP_WORD) pPortConfig->SixthSlotMask1;
+ MsgBuffer[17] = (DSP_WORD) pPortConfig->SevenSlotMask1;
+ MsgBuffer[18] = (DSP_WORD) pPortConfig->EightSlotMask1;
+
+ MsgBuffer[19] = (DSP_WORD) pPortConfig->ThirdSlotMask2;;
+ MsgBuffer[20] = (DSP_WORD) pPortConfig->FouthSlotMask2;
+ MsgBuffer[21] = (DSP_WORD) pPortConfig->FifthSlotMask2;;
+ MsgBuffer[22] = (DSP_WORD) pPortConfig->SixthSlotMask2;
+ MsgBuffer[23] = (DSP_WORD) pPortConfig->SevenSlotMask2;;
+ MsgBuffer[24] = (DSP_WORD) pPortConfig->EightSlotMask2;
+
+ MsgBuffer[25] = (DSP_WORD) pPortConfig->ThirdSlotMask3;;
+ MsgBuffer[26] = (DSP_WORD) pPortConfig->FouthSlotMask3;
+ MsgBuffer[27] = (DSP_WORD) pPortConfig->FifthSlotMask3;;
+ MsgBuffer[28] = (DSP_WORD) pPortConfig->SixthSlotMask3;
+ MsgBuffer[29] = (DSP_WORD) pPortConfig->SevenSlotMask3;;
+ MsgBuffer[30] = (DSP_WORD) pPortConfig->EightSlotMask3;
+
+
+ /* Attempt to send the Configure Serial Ports message to the DSP and receive
+ it's reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 62, MSG_CONFIG_PORTS_REPLY, 4, 0, 0))
+ return (CpsDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ *pStatus = (GPAK_PortConfigStat_t) (MsgBuffer[1] & 0xFF);
+ if (*pStatus == Pc_Success)
+ return (CpsSuccess);
+ else
+ return (CpsParmError);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakConfigureChannel - Configure a DSP's Channel.
+ *
+ * FUNCTION
+ * This function configures a DSP's Channel.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakConfigChanStatus_t gpakConfigureChannel(
+ unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */
+ unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */
+ GpakChanType ChannelType, /* Channel Type */
+ GpakChannelConfig_t *pChanConfig, /* pointer to Channel Config info */
+ GPAK_ChannelConfigStat_t *pStatus /* pointer to Channel Config Status */
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD MsgLength; /* message length */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (CcsInvalidDsp);
+
+ /* Make sure the Channel Id is valid. */
+ if (ChannelId >= MaxChannels[DspId])
+ return (CcsInvalidChannel);
+
+ /* Build the Configure Channel message based on the Channel Type. */
+ switch (ChannelType)
+ {
+
+ /* PCM to Packet channel type. */
+ case tdmToTdm:
+
+ MsgBuffer[2] = (DSP_WORD)
+ ((pChanConfig->PcmInPortA << 8) |
+ (pChanConfig->PcmInSlotA & 0xFF));
+ MsgBuffer[3] = (DSP_WORD)
+ ((pChanConfig->PcmOutPortA << 8) |
+ (pChanConfig->PcmOutSlotA & 0xFF));
+
+ MsgBuffer[4] = (DSP_WORD)
+ ((pChanConfig->PcmInPortB << 8) |
+ (pChanConfig->PcmInSlotB & 0xFF));
+ MsgBuffer[5] = (DSP_WORD)
+ ((pChanConfig->PcmOutPortB << 8) |
+ (pChanConfig->PcmOutSlotB & 0xFF));
+
+ MsgBuffer[6] = (DSP_WORD)
+ (
+ ((pChanConfig->FaxCngDetB <<11) & 0x0800) |
+ ((pChanConfig->FaxCngDetA <<10) & 0x0400) |
+ ((pChanConfig->MuteToneB << 9) & 0x0200) |
+ ((pChanConfig->MuteToneA << 8) & 0x0100) |
+ ((pChanConfig->FrameRate << 6) & 0x00C0) |
+ ((pChanConfig->ToneTypesB << 5) & 0x0020) |
+ ((pChanConfig->ToneTypesA << 4) & 0x0010) |
+ ((pChanConfig->SoftwareCompand & 3) << 2) |
+ (pChanConfig->EcanEnableB << 1) |
+ (pChanConfig->EcanEnableA & 1)
+ );
+
+ MsgBuffer[7] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanTapLength;
+ MsgBuffer[8] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNlpType;
+ MsgBuffer[9] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanAdaptEnable;
+ MsgBuffer[10] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanG165DetEnable;
+ MsgBuffer[11] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanDblTalkThresh;
+ MsgBuffer[12] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNlpThreshold;
+ MsgBuffer[13] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNlpConv;
+ MsgBuffer[14] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNlpUnConv;
+ MsgBuffer[15] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNlpMaxSuppress;
+
+ MsgBuffer[16] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanCngThreshold;
+ MsgBuffer[17] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanAdaptLimit;
+ MsgBuffer[18] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanCrossCorrLimit;
+ MsgBuffer[19] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanNumFirSegments;
+ MsgBuffer[20] = (DSP_WORD)
+ pChanConfig->EcanParametersA.EcanFirSegmentLen;
+
+ MsgBuffer[21] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanTapLength;
+ MsgBuffer[22] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNlpType;
+ MsgBuffer[23] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanAdaptEnable;
+ MsgBuffer[24] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanG165DetEnable;
+ MsgBuffer[25] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanDblTalkThresh;
+ MsgBuffer[26] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNlpThreshold;
+ MsgBuffer[27] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNlpConv;
+ MsgBuffer[28] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNlpUnConv;
+ MsgBuffer[29] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNlpMaxSuppress;
+ MsgBuffer[30] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanCngThreshold;
+ MsgBuffer[31] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanAdaptLimit;
+ MsgBuffer[32] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanCrossCorrLimit;
+ MsgBuffer[33] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanNumFirSegments;
+ MsgBuffer[34] = (DSP_WORD)
+ pChanConfig->EcanParametersB.EcanFirSegmentLen;
+
+ MsgLength = 70; // byte number == 35*2
+ break;
+
+
+ /* Unknown (invalid) channel type. */
+ default:
+ *pStatus = Cc_InvalidChannelType;
+ return (CcsParmError);
+ }
+
+ MsgBuffer[0] = MSG_CONFIGURE_CHANNEL << 8;
+ MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ChannelType & 0xFF));
+
+ /* Attempt to send the Configure Channel message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, MsgLength, MSG_CONFIG_CHAN_REPLY, 4, 1,
+ (DSP_WORD) ChannelId))
+ return (CcsDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ *pStatus = (GPAK_ChannelConfigStat_t) (MsgBuffer[1] & 0xFF);
+ if (*pStatus == Cc_Success)
+ return (CcsSuccess);
+ else
+ return (CcsParmError);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakTearDownChannel - Tear Down a DSP's Channel.
+ *
+ * FUNCTION
+ * This function tears down a DSP's Channel.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakTearDownStatus_t gpakTearDownChannel(
+ unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */
+ unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */
+ GPAK_TearDownChanStat_t *pStatus /* pointer to Tear Down Status */
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (TdsInvalidDsp);
+
+ /* Make sure the Channel Id is valid. */
+ if (ChannelId >= MaxChannels[DspId])
+ return (TdsInvalidChannel);
+
+ /* Build the Tear Down Channel message. */
+ MsgBuffer[0] = MSG_TEAR_DOWN_CHANNEL << 8;
+ MsgBuffer[1] = (DSP_WORD) (ChannelId << 8);
+
+ /* Attempt to send the Tear Down Channel message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 3, MSG_TEAR_DOWN_REPLY, 4, 1,
+ (DSP_WORD) ChannelId))
+ return (TdsDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ *pStatus = (GPAK_TearDownChanStat_t) (MsgBuffer[1] & 0xFF);
+ if (*pStatus == Td_Success)
+ return (TdsSuccess);
+ else
+ return (TdsError);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakAlgControl - Control an Algorithm.
+ *
+ * FUNCTION
+ * This function controls an Algorithm
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakAlgControlStat_t gpakAlgControl(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GpakAlgCtrl_t ControlCode, // algorithm control code
+ GPAK_AlgControlStat_t *pStatus // pointer to return status
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (AcInvalidDsp);
+
+ /* Make sure the Channel Id is valid. */
+ if (ChannelId >= MaxChannels[DspId])
+ return (AcInvalidChannel);
+
+ MsgBuffer[0] = MSG_ALG_CONTROL << 8;
+ MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ControlCode & 0xFF));
+
+ /* Attempt to send the Tear Down Channel message to the DSP and receive it's
+ reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 4, MSG_ALG_CONTROL_REPLY, 4, 1,
+ (DSP_WORD) ChannelId))
+ return (AcDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ *pStatus = (GPAK_AlgControlStat_t) (MsgBuffer[1] & 0xFF);
+ if (*pStatus == Ac_Success)
+ return (AcSuccess);
+ else
+ return (AcParmError);
+
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadEventFIFOMessage - read from the event fifo
+ *
+ * FUNCTION
+ * This function reads a single event from the event fifo if one is available
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ * Notes: This function should be called in a loop until the return status
+ * indicates that the fifo is empty.
+ *
+ * If the event code equals "EventLoopbackTeardownComplete", then the
+ * contents of *pChannelId hold the coderBlockId that was assigned to
+ * the loopback coder that was torn down.
+ */
+gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pChannelId, // pointer to channel identifier
+ GpakAsyncEventCode_t *pEventCode, // pointer to Event Code
+ GpakAsyncEventData_t *pEventData // pointer to Event Data Struct
+ )
+{
+ DSP_WORD WordBuffer[WORD_BUFFER_SIZE]; /* DSP words buffer */
+ GpakAsyncEventCode_t EventCode; /* DSP's event code */
+ DSP_WORD EventDataLength; /* Length of event to read */
+ DSP_WORD ChannelId; /* DSP's channel Id */
+ DSP_ADDRESS EventInfoAddress; /* address of EventFIFO info structure */
+ DSP_ADDRESS BufrBaseAddress; /* base address of EventFIFO buffer */
+ DSP_ADDRESS BufrLastAddress; /* last address of EventFIFO buffer */
+ DSP_ADDRESS TakeAddress; /* current take address in fifo buffer */
+ DSP_WORD BufrSize; /* size (in words) of event FIFO buffer */
+ DSP_WORD PutIndex; /* event fifo put index */
+ DSP_WORD TakeIndex; /* event fifo take index */
+ DSP_WORD WordsReady; /* number words ready for read out of event fifo */
+ DSP_WORD EventError; /* flag indicating error with event fifo msg */
+#if 0
+ DSP_WORD *pDebugData; /* debug data buffer pointer in event data struct */
+#endif
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RefInvalidDsp);
+
+ /* Lock access to the DSP. */
+ gpakLockAccess(DspId);
+
+ /* Check if the DSP was reset and is ready. */
+ if (CheckDspReset(DspId) == -1)
+ {
+ gpakUnlockAccess(DspId);
+ return (RefDspCommFailure);
+ }
+
+ /* Check if an event message is ready in the DSP. */
+ EventInfoAddress = pEventFifoAddress[DspId];
+ gpakReadDspMemory(DspId, EventInfoAddress, CIRC_BUFFER_INFO_STRUCT_SIZE,
+ WordBuffer);
+ RECONSTRUCT_LONGWORD(BufrBaseAddress, ((DSP_WORD *)&WordBuffer[CB_BUFR_BASE]));
+ BufrSize = WordBuffer[CB_BUFR_SIZE];
+ PutIndex = WordBuffer[CB_BUFR_PUT_INDEX];
+ TakeIndex = WordBuffer[CB_BUFR_TAKE_INDEX];
+ if (PutIndex >= TakeIndex)
+ WordsReady = PutIndex - TakeIndex;
+ else
+ WordsReady = PutIndex + BufrSize - TakeIndex;
+
+ if (WordsReady < 2)
+ {
+ gpakUnlockAccess(DspId);
+ return (RefNoEventAvail);
+ }
+
+ /* Read the event header from the DSP's Event FIFO. */
+ TakeAddress = BufrBaseAddress + TakeIndex;
+ BufrLastAddress = BufrBaseAddress + BufrSize - 1;
+ ReadCircBuffer(DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress,
+ WordBuffer, 2);
+ TakeIndex += 2;
+ if (TakeIndex >= BufrSize)
+ TakeIndex -= BufrSize;
+
+ ChannelId = (WordBuffer[0] >> 8) & 0xFF;
+ EventCode = (GpakAsyncEventCode_t)(WordBuffer[0] & 0xFF);
+ EventDataLength = WordBuffer[1];
+ EventError = 0;
+
+ switch (EventCode)
+ {
+ case EventToneDetect:
+ if (EventDataLength > WORD_BUFFER_SIZE)
+ {
+ gpakUnlockAccess(DspId);
+ return (RefInvalidEvent);
+ }
+ ReadCircBuffer(DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress,
+ WordBuffer, EventDataLength);
+ pEventData->toneEvent.ToneCode = (GpakToneCodes_t)
+ (WordBuffer[0] & 0xFF);
+ pEventData->toneEvent.ToneDuration = WordBuffer[1];
+ pEventData->toneEvent.Direction = WordBuffer[2];
+ pEventData->toneEvent.DebugToneStatus = WordBuffer[3];
+ TakeIndex += EventDataLength;
+ if (TakeIndex >= BufrSize)
+ TakeIndex -= BufrSize;
+ if (EventDataLength != 4)
+ EventError = 1;
+ break;
+
+ default:
+ EventError = 1;
+ break;
+ };
+
+ /* Update the Take index in the DSP's Packet Out buffer information. */
+ gpakWriteDspMemory(DspId, EventInfoAddress + CB_BUFR_TAKE_INDEX, 1,
+ &TakeIndex);
+
+ /* Unlock access to the DSP. */
+ gpakUnlockAccess(DspId);
+
+ if (EventError)
+ return(RefInvalidEvent);
+
+ *pChannelId = ChannelId;
+ *pEventCode = EventCode;
+ return(RefEventAvail);
+
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakPingDsp - ping the DSP to see if it's alive
+ *
+ * FUNCTION
+ * This function checks if the DSP is still communicating with the host
+ * and returns the DSP SW version
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakPingDspStat_t gpakPingDsp(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pDspSwVersion // DSP software version
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (PngInvalidDsp);
+
+ /* send value of 1, DSP increments it */
+ MsgBuffer[0] = (MSG_PING << 8);
+
+ /* Attempt to send the ping message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 1, MSG_PING_REPLY, 6, 0, 0))
+ return (PngDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ {
+ *pDspSwVersion = MsgBuffer[2];
+ return (PngSuccess);
+ }
+ else
+ return (PngDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakSerialTxFixedValue - transmit a fixed value on a timeslot
+ *
+ * FUNCTION
+ * This function controls transmission of a fixed value out onto a serial
+ * port's timeslot.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id
+ unsigned short int PcmOutSlot, // PCM Output Time Slot
+ unsigned short int Value, // 16-bit value
+ GpakActivation State // activation state
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (TfvInvalidDsp);
+
+ /* Make sure the Channel Id is valid. */
+ if (ChannelId >= MaxChannels[DspId])
+ return (TfvInvalidChannel);
+
+
+ /* Build the message. */
+ MsgBuffer[0] = MSG_SERIAL_TXVAL << 8;
+ MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (State & 0xFF));
+ MsgBuffer[2] = (DSP_WORD) ((PcmOutPort << 8) | (PcmOutSlot & 0xFF));
+ MsgBuffer[3] = (DSP_WORD) Value;
+
+ /* Attempt to send the message to the DSP and receive it's
+ reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 8, MSG_SERIAL_TXVAL_REPLY, 4,
+ 1, ChannelId))
+ return (TfvDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ return (TfvSuccess);
+ else
+ return (TfvDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakControlTdmLoopBack - control a serial port's loopback state
+ *
+ * FUNCTION
+ * This function enables/disables the tdm input to output looback mode on a
+ * serial port
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(
+ unsigned short int DspId, // DSP identifier
+ GpakSerialPort_t SerialPort, // Serial Port Id
+ GpakActivation LoopBackState // Loopback State
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (ClbInvalidDsp);
+
+ /* Build the message. */
+ MsgBuffer[0] = MSG_TDM_LOOPBACK << 8;
+ MsgBuffer[1] = (DSP_WORD) ((SerialPort << 8) | (LoopBackState & 0xFF));
+
+ /* Attempt to send the message to the DSP and receive it's
+ reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 4, MSG_TDM_LOOPBACK_REPLY, 4, 0, 0))
+ return (ClbDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ return (ClbSuccess);
+ else
+ return (ClbDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadCpuUsage - Read CPU usage statistics from a DSP.
+ *
+ * FUNCTION
+ * This function reads the CPU usage statistics from a DSP's memory. The
+ * average CPU usage in units of .1 percent are obtained for each of the frame
+ * rates.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakReadCpuUsageStat_t gpakReadCpuUsage(
+ unsigned short int DspId, // Dsp Identifier
+ unsigned short int *pPeakUsage, // pointer to peak usage variable
+ unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second
+ )
+{
+ DSP_WORD ReadBuffer[2]; /* DSP read buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RcuInvalidDsp);
+
+ /* Lock access to the DSP. */
+ gpakLockAccess(DspId);
+
+ /* Check if the DSP was reset and is ready. */
+ if (CheckDspReset(DspId) == -1)
+ return (RcuDspCommFailure);
+
+ /* Read the CPU Usage statistics from the DSP. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CPU_USAGE_OFFSET, 2,
+ ReadBuffer);
+
+ /* Unlock access to the DSP. */
+ gpakUnlockAccess(DspId);
+
+ /* Store the usage statistics in the specified variables. */
+ *pPrev1SecPeakUsage = ReadBuffer[0];
+ *pPeakUsage = ReadBuffer[1];
+
+ /* Return with an indication the usage staistics were read successfully. */
+ return (RcuSuccess);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetCpuUsageStats - reset the cpu usage statistics
+ *
+ * FUNCTION
+ * This function resets the cpu utilization statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakResetCpuUsageStat_t gpakResetCpuUsageStats(
+ unsigned short int DspId // DSP identifier
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RstcInvalidDsp);
+
+ MsgBuffer[0] = (MSG_RESET_USAGE_STATS << 8);
+
+ /* Attempt to send the message to the DSP and receive it's reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 2, MSG_RESET_USAGE_STATS_REPLY, 4, 0, 0))
+ return (RstcDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ return (RstcSuccess);
+ else
+ return (RstcDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadFramingStats
+ *
+ * FUNCTION
+ * This function reads a DSP's framing interrupt statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakReadFramingStatsStatus_t gpakReadFramingStats(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pFramingError1Count, // port 1 Framing error count
+ unsigned short int *pFramingError2Count, // port 2 Framing error count
+ unsigned short int *pFramingError3Count, // port 3 Framing error count
+ unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count
+ unsigned short int *pDmaSlipStatsBuffer // DMA slips count
+ )
+{
+ DSP_WORD ReadBuffer[10]; /* DSP read buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RfsInvalidDsp);
+
+ /* Lock access to the DSP. */
+ gpakLockAccess(DspId);
+
+ /* Check if the DSP was reset and is ready. */
+ if (CheckDspReset(DspId) == -1)
+ return (RfsDspCommFailure);
+
+ /* Read the framing interrupt statistics from the DSP. */
+ gpakReadDspMemory(DspId, pDspIfBlk[DspId] + FRAMING_STATS_OFFSET, 10,
+ ReadBuffer);
+
+ /* Unlock access to the DSP. */
+ gpakUnlockAccess(DspId);
+
+ /* Store the framing statistics in the specified variables. */
+ *pFramingError1Count = ReadBuffer[0];
+ *pFramingError2Count = ReadBuffer[1];
+ *pFramingError3Count = ReadBuffer[2];
+ *pDmaStopErrorCount = ReadBuffer[3];
+
+ if(pDmaSlipStatsBuffer != 0)
+ // If users want to get the DMA slips count
+ {
+ pDmaSlipStatsBuffer[0] = ReadBuffer[4];
+ pDmaSlipStatsBuffer[1] = ReadBuffer[5];
+ pDmaSlipStatsBuffer[2] = ReadBuffer[6];
+ pDmaSlipStatsBuffer[3] = ReadBuffer[7];
+ pDmaSlipStatsBuffer[4] = ReadBuffer[8];
+ pDmaSlipStatsBuffer[5] = ReadBuffer[9];
+
+ }
+ /* Return with an indication the statistics were read successfully. */
+ return (RfsSuccess);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetFramingStats - reset a DSP's framing interrupt statistics
+ *
+ * FUNCTION
+ * This function resets a DSP's framing interrupt statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakResetFramingStatsStatus_t gpakResetFramingStats(
+ unsigned short int DspId // DSP identifier
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RstfInvalidDsp);
+
+ MsgBuffer[0] = (MSG_RESET_FRAME_STATS << 8);
+
+ /* Attempt to send the message to the DSP and receive it's reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 2, MSG_RESET_FRAME_STATS_REPLY, 4, 0, 0))
+ return (RstfDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ return (RstfSuccess);
+ else
+ return (RstfDspCommFailure);
+}
+
+/*
+ * gpakDownloadDsp - Download a DSP's Program and initialized Data memory.
+ *
+ * FUNCTION
+ * This function reads a DSP's Program and Data memory image from the
+ * specified file and writes the image to the DSP's memory.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakDownloadStatus_t gpakDownloadDsp(
+ unsigned short DspId, /* DSP Identifier (0 to MaxDSPCores-1) */
+ GPAK_FILE_ID FileId /* G.PAK Download File Identifier */
+ )
+{
+ gpakDownloadStatus_t RetStatus; /* function return status */
+ int NumRead; /* number of file bytes read */
+ DSP_ADDRESS Address; /* DSP address */
+ unsigned int WordCount; /* number of words in record */
+ unsigned int NumWords; /* number of words to read/write */
+ unsigned int i; /* loop index / counter */
+ unsigned int j; /* loop index */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (GdlInvalidDsp);
+
+ /* Lock access to the DSP. */
+ gpakLockAccess(DspId);
+
+ RetStatus = GdlSuccess;
+ while (RetStatus == GdlSuccess)
+ {
+
+ /* Read a record header from the file. */
+ NumRead = gpakReadFile(FileId, DlByteBufr, 6);
+ if (NumRead == -1)
+ {
+ RetStatus = GdlFileReadError;
+ break;
+ }
+ if (NumRead != 6)
+ {
+ RetStatus = GdlInvalidFile;
+ break;
+ }
+ Address = (((DSP_ADDRESS) DlByteBufr[1]) << 16) |
+ (((DSP_ADDRESS) DlByteBufr[2]) << 8) |
+ ((DSP_ADDRESS) DlByteBufr[3]);
+ WordCount = (((unsigned int) DlByteBufr[4]) << 8) |
+ ((unsigned int) DlByteBufr[5]);
+
+ /* Check for the End Of File record. */
+ if (DlByteBufr[0] == 0xFF)
+ break;
+
+ /* Verify the record is for a valid memory type. */
+ if ((DlByteBufr[0] != 0x00) && (DlByteBufr[0] != 0x01))
+ {
+ RetStatus = GdlInvalidFile;
+ break;
+ }
+
+ /* Read a block of words at a time from the file and write to the
+ DSP's memory .*/
+ while (WordCount != 0)
+ {
+ if (WordCount < DOWNLOAD_BLOCK_SIZE)
+ NumWords = WordCount;
+ else
+ NumWords = DOWNLOAD_BLOCK_SIZE;
+ WordCount -= NumWords;
+ NumRead = gpakReadFile(FileId, DlByteBufr, NumWords * 2);
+ if (NumRead == -1)
+ {
+ RetStatus = GdlFileReadError;
+ break;
+ }
+ if (NumRead != (NumWords * 2))
+ {
+ RetStatus = GdlInvalidFile;
+ break;
+ }
+ for (i = 0, j = 0; i < NumWords; i++, j += 2)
+ DlWordBufr[i] = (((DSP_WORD) DlByteBufr[j]) << 8) |
+ ((DSP_WORD) DlByteBufr[j + 1]);
+ gpakWriteDspMemory(DspId, Address, NumWords, DlWordBufr);
+ Address += ((DSP_ADDRESS) NumWords);
+ }
+ }
+
+ /* Unlock access to the DSP. */
+ gpakUnlockAccess(DspId);
+
+ /* Return with an indication of success or failure. */
+ return (RetStatus);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadCpuUsage - Read CPU usage statistics from a DSP.
+ *
+ * FUNCTION
+ * This function reads the memory map register section of DSP memory.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(
+ unsigned short int DspId, // Dsp Identifier
+ unsigned short int *pDest, // Buffer on host to hold DSP memory map
+ DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out
+ unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP reply's status */
+ int i; /* loop index / counter */
+
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RmmInvalidDsp);
+
+ /* Verify the message buffer is large enough */
+ if (MSG_BUFFER_SIZE < MemoryLength_Word16 )
+ return (RmmSizeTooBig);
+
+ MsgBuffer[0] = MSG_READ_DSP_MEMORY << 8;
+ MsgBuffer[1] = (DSP_WORD) ((BufrBaseAddress >> 16) & 0xFFFF);
+ MsgBuffer[2] = (DSP_WORD) (BufrBaseAddress & 0xFFFF);
+ MsgBuffer[3] = (DSP_WORD) MemoryLength_Word16;
+
+ /* Attempt to send the Read memory section message to the DSP and receive it's
+ reply. */
+ //need_reply_len;
+ if (!TransactCmd(DspId, MsgBuffer, 8, MSG_READ_DSP_MEMORY_REPLY,
+ (MemoryLength_Word16+2)*2, 0, 0) )
+ return (RmmInvalidAddress);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus != 0)
+ return (RmmFailure);
+
+ for (i = 0; i < MemoryLength_Word16; i++)
+ pDest[i] = (short int) MsgBuffer[2 + i];
+
+
+ return (RmmSuccess);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakAccessGPIO - change Direction/read/write the GPIO on DSP
+ *
+ * FUNCTION
+ * This function read/write GPIO and change the GPIO direction
+ *
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+gpakAccessGPIOStat_t gpakAccessGPIO(
+ unsigned short int DspId, // DSP identifier
+ GpakGPIOCotrol_t gpakControlGPIO,// select oeration, changeDIR/write/read
+ unsigned short int *pGPIOValue // DSP software version
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (GPIOInvalidDsp);
+
+ /* send value of 1, DSP increments it */
+ MsgBuffer[0] = (MSG_ACCESSGPIO << 8);
+ MsgBuffer[1] = (DSP_WORD) ((gpakControlGPIO << 8) | (*pGPIOValue & 0xFF) );
+ /* Attempt to send the ping message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 4, MSG_ACCESSGPIO_REPLY, 6, 0, 0))
+ return (GPIODspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ {
+ *pGPIOValue = MsgBuffer[2];
+ return (GPIOSuccess);
+ }
+ else
+ return (GPIODspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakWriteSystemParms - Write a DSP's System Parameters.
+ *
+ * FUNCTION
+ * This function writes a DSP's System Parameters information.
+ *
+ * Note:
+ * Or-together the desired bit-mask #defines that are listed below. Only
+ * those algorithm parameters whose bit-mask is selected in the UpdateBits
+ * function parameter will be updated.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+
+gpakWriteSysParmsStatus_t gpakWriteSystemParms(
+ unsigned short int DspId, // DSP identifier
+ GpakSystemParms_t *pSysParms, /* pointer to System Parms info var */
+ unsigned short int UpdateBits, /* input: flags indicating which parms to update */
+ GPAK_SysParmsStat_t *pStatus /* pointer to Write System Parms Status */
+ )
+{
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+ DSP_WORD DspStatus; /* DSP's reply status */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (WspInvalidDsp);
+
+ /* Build the Write System Parameters message. */
+ MsgBuffer[0] = MSG_WRITE_SYS_PARMS << 8;
+
+ if (UpdateBits & DTMF_UPDATE_MASK)
+ {
+ MsgBuffer[1] |= DTMF_UPDATE_MASK;
+ MsgBuffer[8] = (DSP_WORD) pSysParms->MinSigLevel;
+ MsgBuffer[9] = (DSP_WORD) (pSysParms->FreqDeviation & 0xff);
+ if (pSysParms->SNRFlag)
+ MsgBuffer[9] |= (1<<8);
+ }
+
+ MsgBuffer[10] = (DSP_WORD) 0;
+ if (UpdateBits & DTMF_TWIST_UPDATE_MASK)
+ {
+ MsgBuffer[1] |= DTMF_TWIST_UPDATE_MASK;
+ MsgBuffer[10] |= (DSP_WORD) (pSysParms->DtmfFwdTwist & 0x000f);
+ MsgBuffer[10] |= (DSP_WORD) ((pSysParms->DtmfRevTwist << 4) & 0x00f0);
+ }
+
+
+ if (UpdateBits & DTMF_VALID_MASK)
+ {
+ MsgBuffer[1] |= DTMF_VALID_MASK;
+ MsgBuffer[11] = (DSP_WORD) (pSysParms->DtmfValidityMask & 0x00ff);
+ }
+
+ /* Attempt to send the ping message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 24, MSG_WRITE_SYS_PARMS_REPLY, 6, 0, 0))
+ return (WspDspCommFailure);
+
+ /* Return with an indication of success or failure based on the return
+ status in the reply message. */
+ *pStatus = (GPAK_SysParmsStat_t) (MsgBuffer[2] );
+
+ DspStatus = (MsgBuffer[1] & 0xFF);
+ if (DspStatus == 0)
+ return (WspSuccess);
+ else
+ return (WspDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadSystemParms - Read a DSP's System Parameters.
+ *
+ * FUNCTION
+ * This function reads a DSP's System Parameters information.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+gpakReadSysParmsStatus_t gpakReadSystemParms(
+ unsigned short int DspId, // DSP identifier
+ GpakSystemParms_t *pSysParms /* pointer to System Parms info var */
+ )
+{
+
+ DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */
+
+ /* Make sure the DSP Id is valid. */
+ if (DspId >= MAX_DSP_CORES)
+ return (RspInvalidDsp);
+
+ /* Build the Read System Parameters message. */
+ MsgBuffer[0] = MSG_READ_SYS_PARMS << 8;
+
+ /* Attempt to send the ping message to the DSP and receive it's
+ reply. */
+ if (!TransactCmd(DspId, MsgBuffer, 2, MSG_READ_SYS_PARMS_REPLY, 22, 0, 0))
+ return (RspDspCommFailure);
+
+ /* Extract the System Parameters information from the message. */
+ pSysParms->DtmfValidityMask = (short int)(MsgBuffer[7]) ;
+
+ pSysParms->MinSigLevel = (short int)MsgBuffer[8];
+ pSysParms->SNRFlag = (short int)((MsgBuffer[9]>>8) & 0x1);
+ pSysParms->FreqDeviation = (short int)(MsgBuffer[9] & 0xff);
+ pSysParms->DtmfFwdTwist = (short int)MsgBuffer[10] & 0x000f;
+ pSysParms->DtmfRevTwist = (short int)(MsgBuffer[10] >> 4) & 0x000f;
+
+ /* Return with an indication that System Parameters info was obtained. */
+ return (RspSuccess);
+}
+#endif
diff --git a/drivers/dahdi/wcte12xp/GpakApi.h b/drivers/dahdi/wcte12xp/GpakApi.h
new file mode 100644
index 0000000..e676b32
--- /dev/null
+++ b/drivers/dahdi/wcte12xp/GpakApi.h
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2005 , Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakApi.h
+ *
+ * Description:
+ * This file contains the function prototypes and data types for the user
+ * API functions that communicate with DSPs executing G.PAK software. The
+ * file is used by application software in the host processor connected to
+ * C55X G.PAK DSPs via a Host Port Interface.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 06/15/05 - Initial release.
+ * 11/15/2006 - 24 TDM-TDM Channels EC release
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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.
+ */
+
+#ifndef _GPAKAPI_H /* prevent multiple inclusion */
+#define _GPAKAPI_H
+#include "GpakErrs.h"
+#include "gpakenum.h"
+
+// Bit masks to select which algorithm's parameters to update: Or-together the
+// desired masks into the UpdateBits function parameter.
+#define DTMF_UPDATE_MASK 0x0010 // update DTMF params, MinLevel, SNRFlag and Freq
+#define DTMF_TWIST_UPDATE_MASK 0x0020 // update DTMF TWIST system params
+#define DTMF_VALID_MASK 0x0080 // update DTMF ValidMask params
+
+#define DSP_DEBUG_BUFF_SIZE 42 // units of 16-bit words
+
+/* Definition of an Asynchronous Event Data Structure */
+typedef union
+{
+ struct
+ {
+ GpakToneCodes_t ToneCode; // detected tone code
+ unsigned short int ToneDuration; // tone duration
+ GpakTdmDirection Direction; // detected on A r B side
+ short int DebugToneStatus;// reserved for debug info
+ } toneEvent;
+
+} GpakAsyncEventData_t;
+
+/* Definition of an Echo Canceller Parameters information structure. */
+typedef struct
+{
+ short int EcanTapLength; // Echo Can Num Taps (tail length)
+ short int EcanNlpType; // Echo Can NLP Type
+ short int EcanAdaptEnable; // Echo Can Adapt Enable flag
+ short int EcanG165DetEnable; // Echo Can G165 Detect Enable flag
+ short int EcanDblTalkThresh; // Echo Can Double Talk threshold
+ short int EcanNlpThreshold; // Echo Can NLP threshold
+ short int EcanNlpConv; // Dynamic NLP control, NLP limit when EC about to converged
+ short int EcanNlpUnConv;// Dynamic NLP control, NLP limit when EC not converged yet
+ short int EcanNlpMaxSuppress; // suppression level for NLP_SUPP mode
+ short int EcanCngThreshold; // Echo Can CNG Noise threshold
+ short int EcanAdaptLimit; // Echo Can Max Adapts per frame
+ short int EcanCrossCorrLimit; // Echo Can Cross Correlation limit
+ short int EcanNumFirSegments; // Echo Can Num FIR Segments
+ short int EcanFirSegmentLen; // Echo Can FIR Segment Length
+} GpakEcanParms_t;
+
+/* Definition of a Channel Configuration information structure. */
+typedef struct
+{
+ GpakSerialPort_t PcmInPortA; // A side PCM Input Serial Port Id
+ unsigned short int PcmInSlotA; // A side PCM Input Time Slot
+ GpakSerialPort_t PcmOutPortA; // A side PCM Output Serial Port Id
+ unsigned short int PcmOutSlotA; // A side PCM Output Time Slot
+ GpakSerialPort_t PcmInPortB; // B side PCM Input Serial Port Id
+ unsigned short int PcmInSlotB; // B side PCM Input Time Slot
+ GpakSerialPort_t PcmOutPortB; // B side PCM Output Serial Port Id
+ unsigned short int PcmOutSlotB; // B side PCM Output Time Slot
+ GpakToneTypes ToneTypesA; // A side Tone Detect Types
+ GpakToneTypes ToneTypesB; // B side Tone Detect Types
+ GpakActivation EcanEnableA; // Echo Cancel A Enabled
+ GpakActivation EcanEnableB; // Echo Cancel B Enabled
+ GpakEcanParms_t EcanParametersA; // Echo Cancel parameters
+ GpakEcanParms_t EcanParametersB; // Echo Cancel parameters
+ GpakCompandModes SoftwareCompand; // software companding
+ GpakRate_t FrameRate; // Gpak Frame Rate
+ GpakActivation MuteToneA; // A side mute DTMF Enabled
+ GpakActivation MuteToneB; // B side mute DTMF Enabled
+ GpakActivation FaxCngDetA; // A side FaxCng Tone Detector Enabled
+ GpakActivation FaxCngDetB; // B side FaxCng Tone Detector Enabled
+
+} GpakChannelConfig_t;
+
+
+/* Definition of a Serial Port Configuration Structure */
+typedef struct
+{
+ GpakSlotCfg_t SlotsSelect1; // port 1 Slot selection
+ unsigned short int FirstBlockNum1; // port 1 first group Block Number
+ unsigned short int FirstSlotMask1; // port 1 first group Slot Mask
+ unsigned short int SecBlockNum1; // port 1 second group Block Number
+ unsigned short int SecSlotMask1; // port 1 second group Slot Mask
+
+ GpakSerWordSize_t SerialWordSize1; // port 1 serial word size
+ GpakCompandModes CompandingMode1; // port 1 companding mode
+ GpakSerFrameSyncPol_t TxFrameSyncPolarity1; // port 1 Tx Frame Sync Polarity
+ GpakSerFrameSyncPol_t RxFrameSyncPolarity1; // port 1 Rx Frame Sync Polarity
+ GpakSerClockPol_t TxClockPolarity1; // port 1 Tx Clock Polarity
+ GpakSerClockPol_t RxClockPolarity1; // port 1 Rx Clock Polarity
+ GpakSerDataDelay_t TxDataDelay1; // port 1 Tx data delay
+ GpakSerDataDelay_t RxDataDelay1; // port 1 Rx data delay
+ GpakActivation DxDelay1; // port 1 DX Delay
+
+ unsigned short int ThirdSlotMask1; // port 1 3rd group Slot Mask
+ unsigned short int FouthSlotMask1; // port 1 4th group Slot Mask
+ unsigned short int FifthSlotMask1; // port 1 5th group Slot Mask
+ unsigned short int SixthSlotMask1; // port 1 6th group Slot Mask
+ unsigned short int SevenSlotMask1; // port 1 7th group Slot Mask
+ unsigned short int EightSlotMask1; // port 1 8th group Slot Mask
+
+
+ GpakSlotCfg_t SlotsSelect2; // port 2 Slot selection
+ unsigned short int FirstBlockNum2; // port 2 first group Block Number
+ unsigned short int FirstSlotMask2; // port 2 first group Slot Mask
+ unsigned short int SecBlockNum2; // port 2 second group Block Number
+ unsigned short int SecSlotMask2; // port 2 second group Slot Mask
+ GpakSerWordSize_t SerialWordSize2; // port 2 serial word size
+ GpakCompandModes CompandingMode2; // port 2 companding mode
+ GpakSerFrameSyncPol_t TxFrameSyncPolarity2; // port 2 Tx Frame Sync Polarity
+ GpakSerFrameSyncPol_t RxFrameSyncPolarity2; // port 2 Rx Frame Sync Polarity
+ GpakSerClockPol_t TxClockPolarity2; // port 2 Tx Clock Polarity
+ GpakSerClockPol_t RxClockPolarity2; // port 2 Rx Clock Polarity
+ GpakSerDataDelay_t TxDataDelay2; // port 2 Tx data delay
+ GpakSerDataDelay_t RxDataDelay2; // port 2 Rx data delay
+ GpakActivation DxDelay2; // port 2 DX Delay
+
+ unsigned short int ThirdSlotMask2; // port 2 3rd group Slot Mask
+ unsigned short int FouthSlotMask2; // port 2 4th group Slot Mask
+ unsigned short int FifthSlotMask2; // port 2 5th group Slot Mask
+ unsigned short int SixthSlotMask2; // port 2 6th group Slot Mask
+ unsigned short int SevenSlotMask2; // port 2 7th group Slot Mask
+ unsigned short int EightSlotMask2; // port 2 8th group Slot Mask
+
+ GpakSlotCfg_t SlotsSelect3; // port 3 Slot selection
+ unsigned short int FirstBlockNum3; // port 3 first group Block Number
+ unsigned short int FirstSlotMask3; // port 3 first group Slot Mask
+ unsigned short int SecBlockNum3; // port 3 second group Block Number
+ unsigned short int SecSlotMask3; // port 3 second group Slot Mask
+ GpakSerWordSize_t SerialWordSize3; // port 3 serial word size
+ GpakCompandModes CompandingMode3; // port 3 companding mode
+ GpakSerFrameSyncPol_t TxFrameSyncPolarity3; // port 3 Tx Frame Sync Polarity
+ GpakSerFrameSyncPol_t RxFrameSyncPolarity3; // port 3 Rx Frame Sync Polarity
+ GpakSerClockPol_t TxClockPolarity3; // port 3 Tx Clock Polarity
+ GpakSerClockPol_t RxClockPolarity3; // port 3 Rx Clock Polarity
+ GpakSerDataDelay_t TxDataDelay3; // port 3 Tx data delay
+ GpakSerDataDelay_t RxDataDelay3; // port 3 Rx data delay
+ GpakActivation DxDelay3; // port 3 DX Delay
+
+ unsigned short int ThirdSlotMask3; // port 3 3rd group Slot Mask
+ unsigned short int FouthSlotMask3; // port 3 4th group Slot Mask
+ unsigned short int FifthSlotMask3; // port 3 5th group Slot Mask
+ unsigned short int SixthSlotMask3; // port 3 6th group Slot Mask
+ unsigned short int SevenSlotMask3; // port 3 7th group Slot Mask
+ unsigned short int EightSlotMask3; // port 3 8th group Slot Mask
+
+} GpakPortConfig_t;
+
+/* Definition of a Tone Generation Parameter Structure */
+/*
+typedef struct
+{
+ GpakToneGenType_t ToneType; // Tone Type
+ unsigned short int Frequency[4]; // Frequency (Hz)
+ short int Level[4]; // Frequency's Level (1 dBm)
+ unsigned short int OnTime[4]; // On Times (msecs)
+ unsigned short int OffTime[4]; // Off Times (msecs)
+} GpakToneGenParms_t;
+*/
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakConfigureChannel return status. */
+typedef enum
+{
+ CcsSuccess = 0, /* Channel Configured successfully */
+ CcsParmError = 1, /* Channel Config Parameter error */
+ CcsInvalidChannel = 2, /* invalid channel */
+ CcsInvalidDsp = 3, /* invalid DSP */
+ CcsDspCommFailure = 4 /* failed to communicate with DSP */
+} gpakConfigChanStatus_t;
+
+/*
+ * gpakConfigureChannel - Configure a DSP's Channel.
+ *
+ * FUNCTION
+ * This function configures a DSP's Channel.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+extern gpakConfigChanStatus_t gpakConfigureChannel(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GpakChanType ChannelType, // channel type
+ GpakChannelConfig_t *pChanConfig, // pointer to channel config info
+ GPAK_ChannelConfigStat_t *pStatus // pointer to Channel Config Status
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakTearDownChannel return status. */
+typedef enum
+{
+ TdsSuccess = 0, /* Channel Tear Down successful */
+ TdsError = 1, /* Channel Tear Down error */
+ TdsInvalidChannel = 2, /* invalid channel */
+ TdsInvalidDsp = 3, /* invalid DSP */
+ TdsDspCommFailure = 4 /* failed to communicate with DSP */
+} gpakTearDownStatus_t;
+
+/*
+ * gpakTearDownChannel - Tear Down a DSP's Channel.
+ *
+ * FUNCTION
+ * This function tears down a DSP's Channel.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+
+extern gpakTearDownStatus_t gpakTearDownChannel(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GPAK_TearDownChanStat_t *pStatus // pointer to Tear Down Status
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakAlgControl return status. */
+typedef enum
+{
+ AcSuccess = 0, /* control successful */
+ AcInvalidChannel = 1, /* invalid channel identifier */
+ AcInvalidDsp = 2, /* invalid DSP */
+ AcParmError = 3, /* invalid control parameter */
+ AcDspCommFailure = 4 /* failed to communicate with DSP */
+} gpakAlgControlStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakAlgControl - Control an Algorithm.
+ *
+ * FUNCTION
+ * This function controls an Algorithm
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+extern gpakAlgControlStat_t gpakAlgControl(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GpakAlgCtrl_t ControlCode, // algorithm control code
+ GPAK_AlgControlStat_t *pStatus // pointer to return status
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakConfigurePorts return status. */
+typedef enum
+{
+ CpsSuccess = 0, /* Serial Ports configured successfully */
+ CpsParmError = 1, /* Configure Ports Parameter error */
+ CpsInvalidDsp = 2, /* invalid DSP */
+ CpsDspCommFailure = 3 /* failed to communicate with DSP */
+} gpakConfigPortStatus_t;
+
+/*
+ * gpakConfigurePorts - Configure a DSP's serial ports.
+ *
+ * FUNCTION
+ * This function configures a DSP's serial ports.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+extern gpakConfigPortStatus_t gpakConfigurePorts(
+ unsigned short int DspId, // DSP identifier
+ GpakPortConfig_t *pPortConfig, // pointer to Port Config info
+ GPAK_PortConfigStat_t *pStatus // pointer to Port Config Status
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakDownloadDsp return status. */
+typedef enum
+{
+ GdlSuccess = 0, /* DSP download successful */
+ GdlFileReadError = 1, /* error reading Download file */
+ GdlInvalidFile = 2, /* invalid Download file content */
+ GdlInvalidDsp = 3 /* invalid DSP */
+} gpakDownloadStatus_t;
+
+/*
+ * gpakDownloadDsp - Download a DSP's Program and initialized Data memory.
+ *
+ * FUNCTION
+ * This function reads a DSP's Program and Data memory image from the
+ * specified file and writes the image to the DSP's memory.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ */
+extern gpakDownloadStatus_t gpakDownloadDsp(
+ unsigned short int DspId, // DSP identifier
+ GPAK_FILE_ID FileId // G.PAK download file identifier
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakReadEventFIFOMessage return status */
+typedef enum
+{
+ RefEventAvail = 0, /* an event was successfully read from the fifo */
+ RefNoEventAvail = 1, /* no event was in the fifo */
+ RefInvalidDsp = 2, /* invalid DSP identifier */
+ RefInvalidEvent = 3, /* invalid event */
+ RefDspCommFailure = 4 /* error communicating with DSP */
+} gpakReadEventFIFOMessageStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadEventFIFOMessage - read from the event fifo
+ *
+ * FUNCTION
+ * This function reads a single event from the event fifo if one is available
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ *
+ * Note: This function should be called in a loop until the return status
+ * indicates that the fifo is empty.
+ */
+extern gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pChannelId, // pointer to channel identifier
+ GpakAsyncEventCode_t *pEventCode, // pointer to Event Code
+ GpakAsyncEventData_t *pEventData // pointer to Event Data Struct
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakPingDsp return status values */
+typedef enum
+{
+ PngSuccess = 0, /* DSP responded successfully */
+ PngInvalidDsp = 1, /* invalid DSP identifier */
+ PngDspCommFailure = 2 /* error communicating with DSP */
+} gpakPingDspStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakPingDsp - ping the DSP to see if it's alive
+ *
+ * FUNCTION
+ * This function checks if the DSP is still communicating with the host
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakPingDspStat_t gpakPingDsp(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pDspSwVersion // DSP software version
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakSerialTxFixedValue return status values */
+typedef enum
+{
+ TfvSuccess = 0, /* operation successful */
+ TfvInvalidChannel = 1, /* invalid channel identifier */
+ TfvInvalidDsp = 2, /* invalid DSP identifier */
+ TfvDspCommFailure = 3 /* failed to communicate with DSP */
+} gpakSerialTxFixedValueStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakSerialTxFixedValue - transmit a fixed value on a timeslot
+ *
+ * FUNCTION
+ * This function controls transmission of a fixed value out onto a serial
+ * port's timeslot.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int ChannelId, // channel identifier
+ GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id
+ unsigned short int PcmOutSlot, // PCM Output Time Slot
+ unsigned short int Value, // 16-bit value
+ GpakActivation State // activation state
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakControlTdmLoopBack return status values */
+typedef enum
+{
+ ClbSuccess = 0, /* operation successful */
+ ClbSerPortInactive = 1, /* serial port is inactive */
+ ClbInvalidDsp = 2, /* invalid DSP identifier */
+ ClbDspCommFailure = 3 /* failed to communicate with DSP */
+} gpakControlTdmLoopBackStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakControlTdmLoopBack - control a serial port's loopback state
+ *
+ * FUNCTION
+ * This function enables/disables the tdm input to output looback mode on a
+ * serial port
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(
+ unsigned short int DspId, // DSP identifier
+ GpakSerialPort_t SerialPort, // Serial Port Id
+ GpakActivation LoopBackState // Loopback State
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakReadCpuUsage return status values */
+typedef enum
+{
+ RcuSuccess = 0, /* operation successful */
+ RcuInvalidDsp = 1, /* invalid DSP identifier */
+ RcuDspCommFailure = 2 /* communication failure */
+} gpakReadCpuUsageStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadCpuUsage - read the cpu usage statistics
+ *
+ * FUNCTION
+ * This function reads cpu utilization from the DSP.
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakReadCpuUsageStat_t gpakReadCpuUsage(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pPeakUsage, // pointer to peak usage variable
+ unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakResetCpuUsageStats return status values */
+typedef enum
+{
+ RstcSuccess = 0, /* operation successful */
+ RstcInvalidDsp = 1, /* invalid DSP identifier */
+ RstcDspCommFailure = 2 /* communication failure */
+} gpakResetCpuUsageStat_t;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetCpuUsageStats - reset the cpu usage statistics
+ *
+ * FUNCTION
+ * This function resets the cpu utilization statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakResetCpuUsageStat_t gpakResetCpuUsageStats(
+ unsigned short int DspId // DSP identifier
+ );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakReadFramingStats return status values */
+typedef enum
+{
+ RfsSuccess = 0, /* operation successful */
+ RfsInvalidDsp = 1, /* invalid DSP identifier */
+ RfsDspCommFailure = 2 /* communication failure */
+} gpakReadFramingStatsStatus_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadFramingStats
+ *
+ * FUNCTION
+ * This function reads a DSP's framing interrupt statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakReadFramingStatsStatus_t gpakReadFramingStats(
+ unsigned short int DspId, // DSP identifier
+ unsigned short int *pFramingError1Count, // port 1 Framing error count
+ unsigned short int *pFramingError2Count, // port 2 Framing error count
+ unsigned short int *pFramingError3Count, // port 3 Framing error count
+ unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count
+ unsigned short int *pDmaSlipStatsBuffer // DMA slips count
+ );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakResetFramingStats return values */
+typedef enum
+{
+ RstfSuccess = 0, /* operation successful */
+ RstfInvalidDsp = 1, /* invalid DSP identifier */
+ RstfDspCommFailure = 2 /* communication failure */
+} gpakResetFramingStatsStatus_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetFramingStats - reset a DSP's framing interrupt statistics
+ *
+ * FUNCTION
+ * This function resets a DSP's framing interrupt statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+extern gpakResetFramingStatsStatus_t gpakResetFramingStats(
+ unsigned short int DspId // DSP identifier
+ );
+
+
+typedef enum
+{
+ RmmSuccess =0,
+ RmmInvalidDsp = 1,
+ RmmSizeTooBig = 2,
+ RmmFailure = 3,
+ RmmInvalidAddress = 4
+
+} gpakReadDSPMemoryStat_t;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetFramingStats - read a section of DSP memory
+ * to get access DSP registers, since 0x00--0x60 not HPI-accessable
+ *
+ * FUNCTION
+ * This function resets a DSP's framing interrupt statistics
+ *
+ * RETURNS
+ * Status code indicating success or a specific error.
+ */
+
+extern gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(
+ unsigned short int DspId, // Dsp Identifier
+ unsigned short int *pDest, // Buffer on host to hold DSP memory map
+ DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out
+ unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word
+ );
+
+typedef enum
+{
+ GPIOSuccess =0,
+ GPIOInvalidDsp = 1,
+ GPIODspCommFailure = 2
+}gpakAccessGPIOStat_t;
+
+extern gpakAccessGPIOStat_t gpakAccessGPIO(
+ unsigned short int DspId, // DSP identifier
+ GpakGPIOCotrol_t gpakControlGPIO,// select oeration, changeDIR/write/read
+ unsigned short int *pGPIOValue // pointer for the read/write value or DIR mask
+ );
+
+/* gpakWriteSystemParms return status. */
+typedef enum
+{
+ WspSuccess = 0, /* System Parameters written successfully */
+ WspParmError = 1, /* Write System Parms's Parameter error */
+ WspInvalidDsp = 2, /* invalid DSP */
+ WspDspCommFailure = 3 /* failed to communicate with DSP */
+} gpakWriteSysParmsStatus_t;
+
+/* Definition of a System Parameters information structure. */
+typedef struct
+{
+ /* DTMF Parameters */
+ short int MinSigLevel; /* 0 = Disabled, Min Sig Power Level for detection */
+ short int SNRFlag; /* 0 = Disabled, relax SNR tolerances */
+ short int FreqDeviation; /* 0 = Disabled, X Percent Deviation times 10 (e.g. 1.7% is entered as 17) */
+ short int DtmfFwdTwist; /* 0 to 8 db */
+ short int DtmfRevTwist; /* 0 to 8 db */
+
+ short int DtmfValidityMask; /* This flag allows users to relax the trailing conditions of the tone */
+
+} GpakSystemParms_t;
+/* gpakReadSystemParms return status. */
+typedef enum
+{
+ RspSuccess = 0, /* System Parameters read successfully */
+ RspInvalidDsp = 1, /* invalid DSP */
+ RspDspCommFailure = 2 /* failed to communicate with DSP */
+} gpakReadSysParmsStatus_t;
+
+extern gpakReadSysParmsStatus_t gpakReadSystemParms(
+ unsigned short int DspId, // DSP identifier
+ GpakSystemParms_t *pSysParms /* pointer to System Parms info var */
+ );
+
+extern gpakWriteSysParmsStatus_t gpakWriteSystemParms(
+ unsigned short int DspId, // DSP identifier
+ GpakSystemParms_t *pSysParms, /* pointer to System Parms info var */
+ unsigned short int UpdateBits, /* input: flags indicating which parms to update */
+ GPAK_SysParmsStat_t *pStatus /* pointer to Write System Parms Status */
+ );
+
+#endif // end multiple inclusion
+
diff --git a/drivers/dahdi/wcte12xp/GpakErrs.h b/drivers/dahdi/wcte12xp/GpakErrs.h
new file mode 100644
index 0000000..3413f97
--- /dev/null
+++ b/drivers/dahdi/wcte12xp/GpakErrs.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2002 - 2004, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakErrs.h
+ *
+ * Description:
+ * This file contains DSP reply status codes used by G.PAK API functions to
+ * indicate specific errors.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 10/17/01 - Initial release.
+ * 07/03/02 - Updates for conferencing.
+ * 06/15/04 - Tone type updates.
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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.
+ */
+
+#ifndef _GPAKERRS_H /* prevent multiple inclusion */
+#define _GPAKERRS_H
+
+/* Configure Serial Ports reply status codes. */
+typedef enum
+{
+ Pc_Success = 0, /* serial ports configured successfully */
+ Pc_ChannelsActive = 1, /* unable to configure while channels active */
+ Pc_TooManySlots1 = 2, /* too many slots selected for port 1 */
+ Pc_InvalidBlockCombo1 = 3, /* invalid combination of blocks for port 1 */
+ Pc_NoSlots1 = 4, /* no slots selected for port 1 */
+ Pc_InvalidSlots1 = 5, /* invalid slot (> max) selected for port 1 */
+ Pc_TooManySlots2 = 6, /* too many slots selected for port 2 */
+ Pc_InvalidBlockCombo2 = 7, /* invalid combination of blocks for port 2 */
+ Pc_NoSlots2 = 8, /* no slots selected for port 2 */
+ Pc_InvalidSlots2 = 9, /* invalid slot (> max) selected for port 2 */
+ Pc_TooManySlots3 = 10, /* too many slots selected for port 3 */
+ Pc_InvalidBlockCombo3 = 11, /* invalid combination of blocks for port 3 */
+ Pc_NoSlots3 = 12, /* no slots selected for port 3 */
+ Pc_InvalidSlots3 = 13 /* invalid slot (> max) selected for port 3 */
+} GPAK_PortConfigStat_t;
+
+/* Configure Channel reply status codes. */
+typedef enum
+{
+ Cc_Success = 0, /* channel configured successfully */
+ Cc_InvalidChannelType = 1, /* invalid Channel Type */
+ Cc_InvalidChannel = 2, /* invalid Channel A Id */
+ Cc_ChannelActiveA = 3, /* Channel A is currently active */
+ Cc_InvalidInputPortA = 4, /* invalid Input A Port */
+ Cc_InvalidInputSlotA = 5, /* invalid Input A Slot */
+ Cc_BusyInputSlotA = 6, /* busy Input A Slot */
+ Cc_InvalidOutputPortA = 7, /* invalid Output A Port */
+ Cc_InvalidOutputSlotA = 8, /* invalid Output A Slot */
+ Cc_BusyOutputSlotA = 9, /* busy Output A Slot */
+ Cc_InvalidInputPortB = 10, /* invalid Input B Port */
+ Cc_InvalidInputSlotB = 11, /* invalid Input B Slot */
+ Cc_BusyInputSlotB = 12, /* busy Input B Slot */
+ Cc_InvalidPktInCodingA = 13, /* invalid Packet In A Coding */
+ Cc_InvalidPktOutCodingA = 14, /* invalid Packet Out A Coding */
+ Cc_InvalidPktInSizeA = 15, /* invalid Packet In A Frame Size */
+ Cc_InvalidPktOutSizeA = 16, /* invalid Packet Out A Frame Size */
+
+ Cc_ChanTypeNotConfigured = 21, /* channel type was not configured */
+ Cc_InsuffECResources = 22, /* insufficient ecan resources avail. */
+ Cc_InsuffTDMResources = 23, /* insufficient tdm block resources avail. */
+
+ Cc_InsuffPktBufResources = 25, /* insufficient pkt buffer resources avail. */
+ Cc_InsuffPcmBufResources = 26, /* insufficient pcm buffer resources avail. */
+
+ Cc_BadPcmEcNlpType = 30, /* invalid EC Nlp type */
+ Cc_BadPcmEcTapLength = 31, /* invalid EC tap length */
+ Cc_BadPcmEcDblTalkThresh = 32, /* invalid EC double-talk threshold */
+ Cc_BadPcmEcNlpThreshold = 33, /* invalid EC Nlp threshold */
+ Cc_BadPcmEcCngThreshold = 34, /* invalid EC Cng threshold */
+ Cc_BadPcmEcAdaptLimit = 35, /* invalid EC Adapt Limit */
+ Cc_BadPcmEcCrossCorrLim = 36, /* invalid EC Cross Correlation Limit */
+ Cc_BadPcmEcNumFirSegs = 37, /* invalid EC Number of FirSegments */
+ Cc_BadPcmEcFirSegLen = 38, /* invalid EC Fir Segment Length */
+
+ /*Cc_InvalidNumEcsEnabled = 48, */ /* more than 1 Ec enabled on channel */
+ Cc_InvalidFrameRate = 49, /* invalid gpak frame rate */
+ Cc_InvalidSoftCompand = 50, /* invalid softCompanding type */
+
+ Cc_InvalidMuteToneA = 51, /* invalid MuteToneA set, no detector */
+ Cc_InvalidMuteToneB = 52, /* invalid MuteToneB set, no detector */
+ Cc_InsuffFaxCngDetResources = 53 /* insufficient tdm block resources avail. */
+
+} GPAK_ChannelConfigStat_t;
+
+/* Tear Down Channel reply status codes. */
+typedef enum
+{
+ Td_Success = 0, /* channel torn down successfully */
+ Td_InvalidChannel = 1, /* invalid Channel Id */
+ Td_ChannelNotActive = 2 /* channel is not active */
+} GPAK_TearDownChanStat_t;
+
+
+typedef enum
+{
+ Ac_Success = 0, /* algorithm control is successfull */
+ Ac_InvalidChannel = 1, /* invalid channel identifier */
+ Ac_InvalidCode = 2, /* invalid algorithm control code */
+ Ac_ECNotEnabled = 3, /* echo canceller was not allocated */
+ Ac_InvalidSoftComp = 4, /* invalid softcompanding, 'cause serial port not in companding mode */
+ Ac_InvalidDTMFMuteA = 5, /* A side invalid Mute, since no dtmf detector */
+ Ac_InvalidDTMFMuteB = 6, /* B side invalid Mute, since no dtmf detector */
+ Ac_InvalidFaxCngA = 7, /* A side FAXCNG detector not available */
+ Ac_InvalidFaxCngB = 8, /* B side FAXCNG detector not available */
+ Ac_InvalidSysConfig = 9 /* No new system parameters (DTMF config) wrriten yet */
+} GPAK_AlgControlStat_t;
+
+/* Write System Parameters reply status codes. */
+typedef enum
+{
+ Sp_Success = 0, /* System Parameters written successfully */
+ Sp_BadTwistThresh = 29 /* invalid twist threshold */
+
+} GPAK_SysParmsStat_t;
+
+#endif /* prevent multiple inclusion */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/drivers/dahdi/wcte12xp/GpakHpi.h b/drivers/dahdi/wcte12xp/GpakHpi.h
new file mode 100644
index 0000000..790bb3c
--- /dev/null
+++ b/drivers/dahdi/wcte12xp/GpakHpi.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2001, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakHpi.h
+ *
+ * Description:
+ * This file contains common definitions related to the G.PAK interface
+ * between a host processor and a DSP processor via the Host Port Interface.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 10/17/01 - Initial release.
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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.
+ */
+
+#ifndef _GPAKHPI_H /* prevent multiple inclusion */
+#define _GPAKHPI_H
+
+
+/* Definition of G.PAK Command/Reply message type codes. */
+#define MSG_NULL_REPLY 0 /* Null Reply (unsupported Command) */
+#define MSG_SYS_CONFIG_RQST 1 /* System Configuration Request */
+#define MSG_SYS_CONFIG_REPLY 2 /* System Configuration Reply */
+#define MSG_READ_SYS_PARMS 3 /* Read System Parameters */
+#define MSG_READ_SYS_PARMS_REPLY 4 /* Read System Parameters Reply */
+#define MSG_WRITE_SYS_PARMS 5 /* Write System Parameters */
+#define MSG_WRITE_SYS_PARMS_REPLY 6 /* Write System Parameters Reply */
+#define MSG_CONFIGURE_PORTS 7 /* Configure Serial Ports */
+#define MSG_CONFIG_PORTS_REPLY 8 /* Configure Serial Ports Reply */
+#define MSG_CONFIGURE_CHANNEL 9 /* Configure Channel */
+#define MSG_CONFIG_CHAN_REPLY 10 /* Configure Channel Reply */
+#define MSG_TEAR_DOWN_CHANNEL 11 /* Tear Down Channel */
+#define MSG_TEAR_DOWN_REPLY 12 /* Tear Down Channel Reply */
+#define MSG_CHAN_STATUS_RQST 13 /* Channel Status Request */
+#define MSG_CHAN_STATUS_REPLY 14 /* Channel Status Reply */
+
+#define MSG_TEST_MODE 17 /* Configure/Perform Test Mode */
+#define MSG_TEST_REPLY 18 /* Configure/Perform Test Mode Reply */
+
+#define MSG_ALG_CONTROL 27 /* algorithm control */
+#define MSG_ALG_CONTROL_REPLY 28 /* algorithm control reply */
+#define MSG_GET_TXCID_ADDRESS 29 /* get tx cid buffer start address */
+#define MSG_GET_TXCID_ADDRESS_REPLY 30 /* get tx cid buffer start addr reply */
+
+#define MSG_PING 35 /* ping command */
+#define MSG_PING_REPLY 36 /* ping command reply */
+#define MSG_SERIAL_TXVAL 37 /* transmit serial fixed value */
+#define MSG_SERIAL_TXVAL_REPLY 38 /* transmit serial fixed value reply */
+#define MSG_TDM_LOOPBACK 39 /* tdm loopback control */
+#define MSG_TDM_LOOPBACK_REPLY 40 /* tdm loopback control reply */
+#define MSG_RESET_USAGE_STATS 41 /* reset cpu usage stats */
+#define MSG_RESET_USAGE_STATS_REPLY 42 /* reset cpu usage stats reply */
+
+#define MSG_RESET_FRAME_STATS 47 /* reset framing stats */
+#define MSG_RESET_FRAME_STATS_REPLY 48 /* reset framing stats reply */
+
+#define MSG_READ_DSP_MEMORY 49 /* read small section of DSP's memory */
+#define MSG_READ_DSP_MEMORY_REPLY 50 /* read memory reply */
+
+#define MSG_ACCESSGPIO 51
+#define MSG_ACCESSGPIO_REPLY 52
+#endif /* prevent multiple inclusion */
diff --git a/drivers/dahdi/wcte12xp/Kbuild b/drivers/dahdi/wcte12xp/Kbuild
new file mode 100644
index 0000000..5df6b9b
--- /dev/null
+++ b/drivers/dahdi/wcte12xp/Kbuild
@@ -0,0 +1,25 @@
+obj-m += wcte12xp.o
+
+FIRM_DIR := ../../firmware
+
+EXTRA_CFLAGS := -I$(src)/.. -Wno-undef
+
+ifeq ($(HOTPLUG_FIRMWARE),yes)
+ EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
+endif
+
+wcte12xp-objs := base.o vpmadt032.o GpakApi.o ../voicebus.o
+
+ifneq ($(HOTPLUG_FIRMWARE),yes)
+wcte12xp-objs += $(FIRM_DIR)/zaptel-fw-vpmadt032.o
+endif
+
+$(obj)/$(FIRM_DIR)/zaptel-fw-vpmadt032.o: $(obj)/base.o
+ $(MAKE) -C $(obj)/$(FIRM_DIR) zaptel-fw-vpmadt032.o
+
+$(obj)/base.o: $(src)/vpmadt032.h $(src)/wcte12xp.h
+$(obj)/base.o: $(src)/../zaptel.h
+
+$(obj)/vpmadt032.o: $(src)/vpmadt032.h
+
+$(obj)/GpakApi.o: $(src)/GpakApi.h
diff --git a/drivers/dahdi/wcte12xp/Makefile b/drivers/dahdi/wcte12xp/Makefile
new file mode 100644
index 0000000..fb0fbc5
--- /dev/null
+++ b/drivers/dahdi/wcte12xp/Makefile
@@ -0,0 +1,25 @@
+ifneq ($(KBUILD_EXTMOD),)
+# We only get here on kernels 2.6.0-2.6.9 .
+# For newer kernels, Kbuild will be included directly by the kernel
+# build system.
+include $(src)/Kbuild
+
+else
+
+# building for 2.4 kernels means no VPM support, so none of the VPM support
+# modules are included in the Makefile rules
+
+all: wcte12xp.o
+
+%.o: %.c
+ $(CC) $(KFLAGS) -o $@ -c $<
+
+base.o: ../zaptel.h
+
+wcte12xp.o: base.o
+ $(LD) -r -o $@ $^
+
+clean:
+ rm -f *.o
+
+endif
diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c
new file mode 100644
index 0000000..b08d4ac
--- /dev/null
+++ b/drivers/dahdi/wcte12xp/base.c
@@ -0,0 +1,1763 @@
+/*
+ * Digium, Inc. Wildcard TE12xP T1/E1 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-2008, 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/proc_fs.h>
+
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+#include "zaptel.h"
+
+#include "../wct4xxp/wct4xxp.h" /* For certain definitions */
+
+#include "../voicebus.h"
+#include "wcte12xp.h"
+
+#if defined(VPM_SUPPORT)
+#include "vpmadt032.h"
+#include "GpakApi.h"
+#endif
+
+struct pci_driver te12xp_driver;
+
+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 };
+
+int debug = 0;
+static int j1mode = 0;
+static int alarmdebounce = 0;
+static int loopback = 0;
+static int t1e1override = -1;
+static int unchannelized = 0;
+static int latency = VOICEBUS_DEFAULT_LATENCY;
+#ifdef VPM_SUPPORT
+int vpmsupport = 1;
+int vpmdtmfsupport = 0;
+int vpmtsisupport = 0;
+int vpmnlptype = 1;
+int vpmnlpthresh = 24;
+int vpmnlpmaxsupp = 0;
+#endif
+
+struct t1 *ifaces[WC_MAX_IFACES];
+spinlock_t ifacelock = SPIN_LOCK_UNLOCKED;
+
+struct t1_desc {
+ char *name;
+ int flags;
+};
+
+static struct t1_desc te120p = { "Wildcard TE120P", 0 };
+static struct t1_desc te122 = { "Wildcard TE122", 0 };
+static struct t1_desc te121 = { "Wildcard TE121", 0 };
+
+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 cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int eframe, int slot)
+{
+ struct command *curcmd=NULL;
+ unsigned int x;
+
+ /* Skip audio */
+ writechunk += 66;
+ /* Search for something waiting to transmit */
+ if ((slot < 6) && (eframe) && (eframe < ZT_CHUNKSIZE - 1)) {
+ /* only 6 useable cs slots per */
+
+ /* framer */
+ 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];
+ 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,0)] = 0x0c; /* 0c write command */
+ else if (curcmd->flags & __CMD_LEDS)
+ writechunk[CMD_BYTE(slot,0,0)] = 0x10 | ((curcmd->address) & 0x0E); /* led set command */
+ else if (curcmd->flags & __CMD_PINS)
+ writechunk[CMD_BYTE(slot,0,0)] = 0x30; /* CPLD2 pin state */
+ else
+ writechunk[CMD_BYTE(slot,0,0)] = 0x0a; /* read command */
+ writechunk[CMD_BYTE(slot,1,0)] = curcmd->address;
+ writechunk[CMD_BYTE(slot,2,0)] = curcmd->data;
+ }
+
+}
+
+static inline void cmd_decipher(struct t1 *wc, volatile unsigned char *readchunk)
+{
+ unsigned char ident, cs_slot;
+ unsigned int x;
+ unsigned int is_vpm = 0;
+
+ /* Skip audio */
+ readchunk += 66;
+ /* 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,is_vpm)];
+ /*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]));
+ }
+ }
+ }
+}
+
+static inline int t1_setreg_full(struct t1 *wc, int addr, int val, int inisr, int vpm_num)
+{
+ unsigned long flags;
+ int hit;
+ int ret;
+
+
+ do {
+ if (!inisr)
+ 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;
+ if(vpm_num >= 0) {
+ wc->cmdq.cmds[hit].flags |= __CMD_VPM;
+ wc->cmdq.cmds[hit].vpm_num = vpm_num;
+ }
+ }
+ if (inisr)
+ break;
+
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ 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, NOT_VPM);
+}
+
+/***************************************************************************
+ * clean_leftovers()
+ *
+ * Check for unconsumed isr register reads and clean them up.
+ **************************************************************************/
+static inline void clean_leftovers(struct t1 *wc)
+{
+ unsigned int x;
+ int count = 0;
+
+ /* 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]));
+ }
+ }
+}
+
+/********************************************************************
+ * 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)
+{
+ int hit=-1;
+ int ret;
+ unsigned int x;
+
+ /* 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].address==addr))
+ {
+ if (wc->cmdq.cmds[x].flags & __CMD_FIN) {
+ hit = x;
+ break;
+ }
+ else {
+ /* still in progress. */
+ return -1;
+ }
+ }
+ }
+
+ if (hit < 0) {
+ 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));
+
+ return ret;
+}
+
+static inline int t1_getreg_full(struct t1 *wc, int addr, int inisr, int vpm_num)
+{
+ unsigned long flags;
+ int hit;
+ int ret = 0;
+
+ do {
+ if (!inisr) {
+ 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(vpm_num >= 0) {
+ wc->cmdq.cmds[hit].flags |= __CMD_VPM;
+ wc->cmdq.cmds[hit].vpm_num = vpm_num;
+ }
+ if (inisr)
+ wc->cmdq.cmds[hit].flags |= __CMD_ISR;
+ }
+ if (inisr) /* must be requested in t1_getreg_isr() */
+ return (hit > -1) ? 0 : -1;
+ else {
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ }
+ 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_getreg(struct t1 *wc, int addr, int inisr)
+{
+ return t1_getreg_full(wc, addr, inisr, NOT_VPM);
+}
+
+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 {
+ if (!inisr) {
+ 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;
+ }
+ if (inisr) {
+ break;
+ } else {
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ }
+ 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 __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, NOT_VPM);
+ 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);
+ 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;
+
+ /* 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,NOT_VPM);
+ } 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,NOT_VPM);
+ t1_setreg_full(wc,0x70 + b + 6,c,1,NOT_VPM);
+ } 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,NOT_VPM);
+ }
+ 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) {
+ spin_unlock(&wc->reglock);
+ zt_rbsbits(&wc->span.chans[i+16], rxs);
+ spin_lock(&wc->reglock);
+ }
+ }
+ rxs = (a >> 4) & 0xf;
+ if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i].rxsig != rxs) {
+ spin_unlock(&wc->reglock);
+ zt_rbsbits(&wc->span.chans[i], rxs);
+ spin_lock(&wc->reglock);
+ }
+ }
+ }
+ }
+ } 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) {
+ spin_unlock(&wc->reglock);
+ zt_rbsbits(&wc->span.chans[i+3], rxs);
+ spin_lock(&wc->reglock);
+ }
+ }
+ rxs = (a & 0xc);
+ if (!(wc->span.chans[i+2].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i+2].rxsig != rxs) {
+ spin_unlock(&wc->reglock);
+ zt_rbsbits(&wc->span.chans[i+2], rxs);
+ spin_lock(&wc->reglock);
+ }
+ }
+ rxs = (a >> 2) & 0xc;
+ if (!(wc->span.chans[i+1].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i+1].rxsig != rxs) {
+ spin_unlock(&wc->reglock);
+ zt_rbsbits(&wc->span.chans[i+1], rxs);
+ spin_lock(&wc->reglock);
+ }
+ }
+ rxs = (a >> 4) & 0xc;
+ if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i].rxsig != rxs) {
+ spin_unlock(&wc->reglock);
+ zt_rbsbits(&wc->span.chans[i], rxs);
+ spin_lock(&wc->reglock);
+ }
+ }
+ }
+ }
+ } 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) {
+ spin_unlock(&wc->reglock);
+ zt_rbsbits(&wc->span.chans[i+1], rxs);
+ spin_lock(&wc->reglock);
+ }
+ }
+ rxs = (a >> 4) & 0xf;
+ if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+ if (wc->span.chans[i].rxsig != rxs) {
+ spin_unlock(&wc->reglock);
+ zt_rbsbits(&wc->span.chans[i], rxs);
+ spin_lock(&wc->reglock);
+ }
+ }
+ }
+ }
+ }
+}
+
+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)
+{
+ unsigned int x;
+ struct t1 *wc = chan->pvt;
+
+ switch (cmd) {
+ case WCT4_GET_REGS:
+ /* Since all register access was moved into the voicebus
+ * module....this was removed. Although...why does the client
+ * library need access to the registers (debugging)? \todo ..
+ */
+ WARN_ON(1);
+ return -ENOSYS;
+ break;
+#ifdef VPM_SUPPORT
+ case ZT_TONEDETECT:
+ if (get_user(x, (int *) data))
+ return -EFAULT;
+ if (!wc->vpm150m)
+ return -ENOSYS;
+ if (wc->vpm150m && (x && !vpmdtmfsupport))
+ return -ENOSYS;
+ if (x & ZT_TONEDETECT_ON) {
+ set_bit(chan->chanpos - 1, &wc->dtmfmask);
+ module_printk("turning on tone detection\n");
+ } else {
+ clear_bit(chan->chanpos - 1, &wc->dtmfmask);
+ module_printk("turning off tone detection\n");
+ }
+ if (x & ZT_TONEDETECT_MUTE) {
+ if(wc->vpm150m)
+ set_bit(chan->chanpos - 1, &wc->vpm150m->desireddtmfmutestate);
+ } else {
+ if(wc->vpm150m)
+ clear_bit(chan->chanpos - 1, &wc->vpm150m->desireddtmfmutestate);
+ }
+ return 0;
+#endif
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+#ifdef VPM_SUPPORT
+
+#include "adt_lec.c"
+
+static int t1xxp_echocan_with_params(struct zt_chan *chan, struct zt_echocanparams *ecp, struct zt_echocanparam *p)
+{
+ struct adt_lec_params params;
+ struct t1 *wc = chan->pvt;
+ struct vpm150m *vpm150m = wc->vpm150m;
+ unsigned int flags;
+ struct vpm150m_workentry *work;
+ unsigned int ret;
+
+ if (!wc->vpm150m)
+ return -ENODEV;
+
+ adt_lec_init_defaults(&params, 32);
+
+ if ((ret = adt_lec_parse_params(&params, ecp, p)))
+ return ret;
+
+ /* we can't really control the tap length, but the value is used
+ to control whether the ec is on or off, so translate it */
+ params.tap_length = ecp->tap_length ? 1 : 0;
+
+ if (!(work = kmalloc(sizeof(*work), GFP_KERNEL)))
+ return -ENOMEM;
+
+ work->params = params;
+ work->wc = wc;
+ work->chan = chan;
+ spin_lock_irqsave(&vpm150m->lock, flags);
+ list_add_tail(&work->list, &vpm150m->worklist);
+ spin_unlock_irqrestore(&vpm150m->lock, flags);
+
+ /* we must do this later since we cannot sleep in the echocan function */
+ if (test_bit(VPM150M_ACTIVE, &vpm150m->control))
+ queue_work(vpm150m->wq, &vpm150m->work_echocan);
+
+ return 0; /* how do I return the status since it is done later by the workqueue? */
+}
+#endif
+
+static int t1_software_init(struct t1 *wc)
+{
+ int x;
+ struct pci_dev* dev;
+
+ dev = voicebus_get_pci_dev(wc->vb);
+
+ /* 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);
+ snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num);
+ wc->span.manufacturer = "Digium";
+ strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1);
+
+#if defined(VPM_SUPPORT)
+ if (wc->vpm150m)
+ strncat(wc->span.devicetype, " with VPMADT032", sizeof(wc->span.devicetype) - 1);
+#endif
+
+ snprintf(wc->span.location, sizeof(wc->span.location) - 1,
+ "PCI Bus %02d Slot %02d", dev->bus->number, PCI_SLOT(dev->devfn) + 1);
+
+ wc->span.spanconfig = t1xxp_spanconfig;
+ wc->span.chanconfig = t1xxp_chanconfig;
+ wc->span.irq = dev->irq;
+ 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;
+#ifdef VPM_SUPPORT
+ wc->span.echocan_with_params = t1xxp_echocan_with_params;
+#endif
+
+ if (wc->spantype == TYPE_E1) {
+ if (unchannelized)
+ wc->span.channels = 32;
+ else
+ wc->span.channels = 31;
+ wc->span.spantype = "E1";
+ wc->span.linecompat = ZT_CONFIG_HDB3 | ZT_CONFIG_CCS | ZT_CONFIG_CRC4;
+ wc->span.deflaw = ZT_LAW_ALAW;
+ } else {
+ wc->span.channels = 24;
+ wc->span.spantype = "T1";
+ wc->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
+ wc->span.deflaw = ZT_LAW_MULAW;
+ }
+ wc->span.chans = wc->chans;
+ wc->span.flags = ZT_FLAG_RBS;
+ wc->span.pvt = wc;
+ 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_MTP2 |
+ 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;
+}
+
+#ifdef VPM_SUPPORT
+static inline unsigned char t1_vpm_in(struct t1 *wc, int unit, const unsigned int addr)
+{
+ return t1_getreg_full(wc, addr, 0, unit);
+}
+
+static inline unsigned char t1_vpm_out(struct t1 *wc, int unit, const unsigned int addr, const unsigned char val)
+{
+ return t1_setreg_full(wc, addr, val, 0, unit);
+}
+
+#endif
+
+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);
+
+#ifdef VPM_SUPPORT
+ t1_vpm150m_init(wc);
+ if (wc->vpm150m) {
+ module_printk("VPM present and operational (Firmware version %x)\n", wc->vpm150m->version);
+ wc->ctlreg |= 0x10; /* turn on vpm (RX audio from vpm module) */
+ if (vpmtsisupport) {
+ debug_printk(1, "enabling VPM TSI pin\n");
+ wc->ctlreg |= 0x01; /* turn on vpm timeslot interchange pin */
+ }
+ }
+#endif
+
+ 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, NOT_VPM); /* LIM0: Force RAI High */
+ wc->flags.nmf = 1;
+ module_printk("NMF workaround on!\n");
+ }
+ t1_setreg_full(wc, 0x1e, 0xc3, 1, NOT_VPM); /* Reset to CRC4 mode */
+ t1_setreg_full(wc, 0x1c, 0xf2, 1, NOT_VPM); /* Force Resync */
+ t1_setreg_full(wc, 0x1c, 0xf0, 1, NOT_VPM); /* Force Resync */
+ } else if (!(c & 0x02)) {
+ if (wc->flags.nmf) {
+ t1_setreg_full(wc, 0x20, 0x9f, 1, NOT_VPM); /* 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, NOT_VPM); /* LIM0: Disable any local loop */
+ t1_setreg_full(wc, 0x37, 0xf6, 1, NOT_VPM); /* 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, NOT_VPM); /* LIM0: Disable any local loop */
+ t1_setreg_full(wc, 0x37, 0xf0, 1, NOT_VPM); /* 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, NOT_VPM);
+ 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, NOT_VPM);
+ 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;
+ spin_unlock(&wc->reglock);
+ zt_alarm_notify(&wc->span);
+ spin_lock(&wc->reglock);
+}
+
+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)
+{
+ const unsigned int x = wc->intcount & 0x3f;
+ int buffer_count = voicebus_current_latency(wc->vb);
+
+ if (unlikely(!wc->initialized)) return;
+
+ __handle_leds(wc);
+
+ __t1_do_counters(wc);
+
+ if ( 0 == x ) {
+ __t1_check_sigbits_reads(wc);
+ }
+ else if ( 1 == x ) {
+ if (!(wc->intcount & 0x30)) {
+ __t1_check_alarms_reads(wc);
+ wc->alarms_read=1;
+ }
+ }
+ else if ( x == buffer_count*2) {
+ __t1_check_sigbits(wc);
+ }
+ else if ( x == (buffer_count*2)+1 ) {
+ if (wc->alarms_read) {
+ __t1_check_alarms(wc);
+ wc->alarms_read=0;
+ }
+ }
+ else if ( x == (buffer_count*2)+2) {
+ clean_leftovers(wc);
+ }
+}
+
+static inline void t1_transmitprep(struct t1 *wc, unsigned char* writechunk)
+{
+ int x;
+ int y;
+ int chan;
+
+ /* Calculate Transmission */
+ if (likely(wc->initialized)) {
+ spin_unlock(&wc->reglock);
+ zt_transmit(&wc->span);
+ spin_lock(&wc->reglock);
+ }
+
+ 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);
+ }
+#ifdef VPM_SUPPORT
+ if(likely(wc->vpm150m)) {
+ vpm150m_cmd_dequeue(wc, writechunk, x);
+ }
+#endif
+
+ 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;
+
+ 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;
+ }
+ }
+}
+
+static inline void t1_receiveprep(struct t1 *wc, unsigned char* readchunk)
+{
+ int x,chan;
+ unsigned char expected;
+
+ 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];
+ wc->statreg = readchunk[EFRAME_SIZE + 2];
+ if (wc->rxident != expected) {
+ wc->span.irqmisses++;
+ cmd_retransmit(wc);
+ if (unlikely(debug && wc->initialized))
+ module_printk("oops: rxident=%d expected=%d x=%d\n", wc->rxident, expected, x);
+ }
+ }
+ cmd_decipher(wc, readchunk);
+#ifdef VPM_SUPPORT
+ if(wc->vpm150m)
+ vpm150m_cmd_decipher(wc, readchunk);
+#endif
+ readchunk += (EFRAME_SIZE + EFRAME_GAP);
+ }
+
+ /* echo cancel */
+ if (likely(wc->initialized)) {
+ spin_unlock(&wc->reglock);
+ 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);
+ spin_lock(&wc->reglock);
+ }
+
+ /* Wake up anyone sleeping to read/write a new register */
+ wake_up_interruptible(&wc->regq);
+}
+
+static void
+t1_handle_transmit(void* vbb, void* context)
+{
+ struct t1* wc = context;
+ /* Either this function is called from within interrupt context, or
+ * the reglock will never be acquired from interrupt context, so it's
+ * safe to grab it without locking interrupt.
+ */
+ memset(vbb, 0, SFRAME_SIZE);
+ spin_lock(&wc->reglock);
+ wc->txints++;
+ t1_transmitprep(wc, vbb);
+ wc->intcount++;
+ t1_isr_misc(wc);
+ spin_unlock(&wc->reglock);
+ voicebus_transmit(wc->vb, vbb);
+}
+
+static void
+t1_handle_receive(void* vbb, void* context)
+{
+ struct t1* wc = context;
+ wc->rxints++;
+ /* Either this function is called from within interrupt context, or
+ * the reglock will never be acquired from interrupt context, so it's
+ * safe to grab it without locking interrupt.
+ */
+ spin_lock(&wc->reglock);
+ t1_receiveprep(wc, vbb);
+ spin_unlock(&wc->reglock);
+}
+
+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;
+ int res;
+ int startinglatency;
+
+ 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;
+ }
+
+retry:
+ wc = kmalloc(sizeof(*wc), GFP_KERNEL);
+ if (!wc)
+ return -ENOMEM;
+
+ ifaces[x] = wc;
+ memset(wc, 0, sizeof(*wc));
+ spin_lock_init(&wc->reglock);
+ wc->variety = d->name;
+ wc->txident = 1;
+
+ init_waitqueue_head(&wc->regq);
+ snprintf(wc->name, sizeof(wc->name)-1, "wcte12xp%d", x);
+ if ((res=voicebus_init(pdev, SFRAME_SIZE, wc->name,
+ t1_handle_receive, t1_handle_transmit, wc, &wc->vb)))
+ {
+ WARN_ON(1);
+ kfree(wc);
+ return res;
+ }
+
+ /* Keep track of which device we are */
+ pci_set_drvdata(pdev, wc);
+ if (VOICEBUS_DEFAULT_LATENCY != latency) {
+ voicebus_set_minlatency(wc->vb, latency);
+ }
+ voicebus_start(wc->vb);
+ startinglatency = voicebus_current_latency(wc->vb);
+ t1_hardware_post_init(wc);
+ t1_software_init(wc);
+ if (voicebus_current_latency(wc->vb) > startinglatency) {
+ /* The voicebus library increased the latency during
+ * initialization because the host wasn't able to service the
+ * interrupts from the adapter quickly enough. In this case,
+ * we'll increase our latency and restart the initialization.
+ */
+ printk(KERN_NOTICE "%s: Restarting board initialization " \
+ "after increasing latency.\n", wc->name);
+ latency = voicebus_current_latency(wc->vb);
+ zt_unregister(&wc->span);
+ voicebus_release(wc->vb);
+ wc->vb = NULL;
+ kfree(wc);
+ wc = NULL;
+ goto retry;
+ }
+ 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);
+#ifdef VPM_SUPPORT
+ unsigned long flags;
+ struct vpm150m *vpm150m = wc->vpm150m;
+#endif
+ if (!wc)
+ return;
+
+#ifdef VPM_SUPPORT
+ if(vpm150m) {
+ clear_bit(VPM150M_DTMFDETECT, &vpm150m->control);
+ clear_bit(VPM150M_ACTIVE, &vpm150m->control);
+ flush_workqueue(vpm150m->wq);
+ destroy_workqueue(vpm150m->wq);
+ }
+#endif
+
+ BUG_ON(!wc->vb);
+ voicebus_release(wc->vb);
+ wc->vb = NULL;
+
+ if (debug && wc->isrreaderrors)
+ debug_printk(1, "isrreaderrors=%d\n", wc->isrreaderrors);
+
+#ifdef VPM_SUPPORT
+ if(vpm150m) {
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->vpm150m = NULL;
+ vpm150m->wc = NULL;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ kfree(wc->vpm150m);
+ }
+#endif
+ /* 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) &te120p},
+ { 0xd161, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &te121},
+ { 0xd161, 0x8001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &te122},
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, te12xp_pci_tbl);
+
+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 = zap_pci_module(&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);
+module_param(latency, int, S_IRUGO | S_IWUSR);
+#ifdef VPM_SUPPORT
+module_param(vpmsupport, int, S_IRUGO | S_IWUSR);
+module_param(vpmdtmfsupport, int, S_IRUGO | S_IWUSR);
+module_param(vpmtsisupport, int, S_IRUGO | S_IWUSR);
+#endif
+#else
+MODULE_PARM(debug, "i");
+MODULE_PARM(loopback, "i");
+MODULE_PARM(t1e1override, "i");
+MODULE_PARM(j1mode, "i");
+MODULE_PARM(alarmdebounce, "i");
+#ifdef VPM_SUPPORT
+MODULE_PARM(vpmsupport, "i");
+MODULE_PARM(vpmdtmfsupport, "i");
+MODULE_PARM(vpmtsisupport, "i");
+MODULE_PARM(vpmnlptype, "i");
+MODULE_PARM(vpmnlpthresh, "i");
+MODULE_PARM(vpmnlpmaxsupp, "i");
+#endif
+#endif
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(te12xp_init);
+module_exit(te12xp_cleanup);
diff --git a/drivers/dahdi/wcte12xp/gpakenum.h b/drivers/dahdi/wcte12xp/gpakenum.h
new file mode 100644
index 0000000..ed14a1a
--- /dev/null
+++ b/drivers/dahdi/wcte12xp/gpakenum.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2005, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: gpakenum.h
+ *
+ * Description:
+ * This file contains common enumerations related to G.PAK application
+ * software.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ * 06/15/05 - Initial release.
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc. The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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.
+ */
+
+#ifndef _GPAKENUM_H /* prevent multiple inclusion */
+#define _GPAKENUM_H
+
+/* G.PAK Serial Port Word Size */
+typedef enum
+{
+ SerWordSize8 = 0, // 8-bit seial word
+ SerWordSize16 = 1 // 16-bit serial word
+} GpakSerWordSize_t;
+
+/* G.PAK Serial Port FrameSync Polarity */
+typedef enum
+{
+ FrameSyncActLow = 0, // active low frame sync signal
+ FrameSyncActHigh = 1 // active high frame sync signal
+} GpakSerFrameSyncPol_t;
+
+/* G.PAK Serial Port Clock Polarity */
+typedef enum
+{
+ SerClockActLow = 0, // active low serial clock
+ SerClockActHigh = 1 // active high serial clock
+} GpakSerClockPol_t;
+
+/* G.PAK Serial Port Data Delay */
+typedef enum
+{
+ DataDelay0 = 0, // no data delay
+ DataDelay1 = 1, // 1-bit data delay
+ DataDelay2 = 2 // 2-bit data delay
+} GpakSerDataDelay_t;
+
+/* G.PAK Serial Port Ids. */
+typedef enum
+{
+ SerialPortNull = 0, // null serial port
+ SerialPort1 = 1, // first PCM serial stream port (McBSP0)
+ SerialPort2 = 2, // second PCM serial stream port (McBSP1)
+ SerialPort3 = 3 // third PCM serial stream port (McBSP2)
+} GpakSerialPort_t;
+
+/* G.PAK serial port Slot Configuration selection codes. */
+typedef enum
+{
+ SlotCfgNone = 0, // no time slots used
+ SlotCfg2Groups = 2, // 2 groups of 16 time slots used, 32 Channels system
+ SlotCfg8Groups = 8 // 8-partition mode for 128-channel system
+} GpakSlotCfg_t;
+
+/* G.PAK serial port Companding Mode codes. */
+typedef enum
+{
+ cmpPCMU=0, // u-Law
+ cmpPCMA=1, // A-Law
+ cmpNone=2 // none
+} GpakCompandModes;
+
+/* G.PAK Active/Inactive selection codes. */
+typedef enum
+{
+ Disabled=0, // Inactive
+ Enabled=1 // Active
+} GpakActivation;
+
+/* G.PAK Channel Type codes. */
+typedef enum
+{
+ inactive=0, // channel inactive
+ tdmToTdm=1 // tdmToTdm
+} GpakChanType;
+
+/* G.PAK Algorithm control commands */
+typedef enum
+{
+ EnableEcanA = 0, // Enable A side echo canceller
+ BypassEcanA = 1, // Bypass A side echo canceller
+ ResetEcanA = 2, // Reset A side echo canceller
+ EnableEcanB = 3, // Enable B side echo canceller
+ BypassEcanB = 4, // Bypass B side echo canceller
+ ResetEcanB = 5, // Reset B side echo canceller
+
+ EnableMuLawSwCompanding = 6,// Enable Mu-law Software companding
+ EnableALawSwCompanding = 7, // Enable Mu-law Software companding
+ BypassSwCompanding = 8, // Bypass Software companding
+ EnableDTMFMuteA = 9, // Mute A side Dtmf digit after tone detected
+ DisableDTMFMuteA = 10, // Do not mute A side Dtmf digit once tone detected
+ EnableDTMFMuteB = 11, // Mute B side Dtmf digit after tone detected
+ DisableDTMFMuteB = 12, // Do not mute B side Dtmf digit once tone detected
+ EnableFaxCngDetectA = 13, // Enable A side Fax CNG detector, channel must be configed already
+ DisableFaxCngDetectA = 14, // Disable A side Fax CNG detector, channel must be configed already
+ EnableFaxCngDetectB = 15, // Enable B side Fax CNG detector, channel must be configed already
+ DisableFaxCngDetectB = 16 // Disable B side Fax CNG detector, channel must be configed already
+} GpakAlgCtrl_t;
+
+/* G.PAK Tone types. */
+typedef enum
+{
+ Null_tone = 0, // no tone detection
+ DTMF_tone = 1 // DTMF tone
+} GpakToneTypes;
+
+/* G.PAK direction. */
+typedef enum
+{
+ TDMAToB = 0, // A to B
+ TDMBToA = 1 // B to A
+} GpakTdmDirection;
+
+
+typedef enum
+{
+ rate1ms=0,
+ rate2ms=1,
+ rate10ms=2
+} GpakRate_t;
+
+/* G.PAK Asynchronous Event Codes */
+typedef enum
+{
+ EventToneDetect = 0, // Tone detection event
+ EventDSPDebug = 7 // DSP debug data event
+} GpakAsyncEventCode_t;
+
+/* G.PAK MF Tone Code Indices */
+typedef enum
+{
+ DtmfDigit1 = 0, // DTMF Digit 1
+ DtmfDigit2 = 1, // DTMF Digit 2
+ DtmfDigit3 = 2, // DTMF Digit 3
+ DtmfDigitA = 3, // DTMF Digit A
+ DtmfDigit4 = 4, // DTMF Digit 4
+ DtmfDigit5 = 5, // DTMF Digit 5
+ DtmfDigit6 = 6, // DTMF Digit 6
+ DtmfDigitB = 7, // DTMF Digit B
+ DtmfDigit7 = 8, // DTMF Digit 7
+ DtmfDigit8 = 9, // DTMF Digit 8
+ DtmfDigit9 = 10, // DTMF Digit 9
+ DtmfDigitC = 11, // DTMF Digit C
+ DtmfDigitSt = 12, // DTMF Digit *
+ DtmfDigit0 = 13, // DTMF Digit 0
+ DtmfDigitPnd = 14, // DTMF Digit #
+ DtmfDigitD = 15, // DTMF Digit D
+
+ FaxCngDigit = 90, // Fax Calling Tone (1100 Hz)
+
+ EndofMFDigit = 100, // End of MF digit
+ EndofCngDigit = 101 // End of Cng Digit
+} GpakToneCodes_t;
+
+/* GPIO control code*/
+typedef enum
+{
+ GPIO_READ = 0,
+ GPIO_WRITE = 1,
+ GPIO_DIR = 2
+} GpakGPIOCotrol_t;
+
+#endif // end multiple inclusion
diff --git a/drivers/dahdi/wcte12xp/vpmadt032.c b/drivers/dahdi/wcte12xp/vpmadt032.c
new file mode 100644
index 0000000..141b000
--- /dev/null
+++ b/drivers/dahdi/wcte12xp/vpmadt032.c
@@ -0,0 +1,1307 @@
+/*
+ * Digium, Inc. Wildcard TE12xP T1/E1 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/delay.h>
+#include <asm/semaphore.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/list.h>
+
+#include "zaptel.h"
+#include "voicebus.h"
+
+#include "wcte12xp.h"
+#include "vpmadt032.h"
+#include "GpakApi.h"
+
+extern struct t1 *ifaces[WC_MAX_IFACES];
+
+extern int vpmnlptype;
+extern int vpmnlpthresh;
+extern int vpmnlpmaxsupp;
+
+#ifdef VPM_SUPPORT
+
+inline void vpm150m_cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int whichframe)
+{
+ struct vpm150m_cmd *curcmd = NULL;
+ struct vpm150m *vpm150m = wc->vpm150m;
+ int x;
+ unsigned char leds = ~((wc->intcount / 1000) % 8) & 0x7;
+
+ /* Skip audio */
+ writechunk += 66;
+
+ if (test_bit(VPM150M_SPIRESET, &vpm150m->control) || test_bit(VPM150M_HPIRESET, &vpm150m->control)) {
+ debug_printk(1, "HW Resetting VPMADT032 ...\n");
+ for (x = 0; x < 4; x++) {
+ if (!x) {
+ if (test_and_clear_bit(VPM150M_SPIRESET, &vpm150m->control))
+ writechunk[CMD_BYTE(x, 0, 1)] = 0x08;
+ else if (test_and_clear_bit(VPM150M_HPIRESET, &vpm150m->control))
+ writechunk[CMD_BYTE(x, 0, 1)] = 0x0b;
+ } else
+ writechunk[CMD_BYTE(x, 0, 1)] = 0x00 | leds;
+ writechunk[CMD_BYTE(x, 1, 1)] = 0;
+ writechunk[CMD_BYTE(x, 2, 1)] = 0x00;
+ }
+ return;
+ }
+
+ /* Search for something waiting to transmit */
+ for (x = 0; x < VPM150M_MAX_COMMANDS; x++) {
+ if ((vpm150m->cmdq[x].flags & (__VPM150M_RD | __VPM150M_WR)) &&
+ !(vpm150m->cmdq[x].flags & (__VPM150M_FIN | __VPM150M_TX))) {
+ curcmd = &vpm150m->cmdq[x];
+ curcmd->ident = wc->txident;
+ curcmd->flags |= __VPM150M_TX;
+ break;
+ }
+ }
+ if (curcmd) {
+#if 0
+ printk("Found command txident = %d, desc = 0x%x, addr = 0x%x, data = 0x%x\n", curcmd->txident, curcmd->desc, curcmd->addr, curcmd->data);
+#endif
+ if (curcmd->flags & __VPM150M_RWPAGE) {
+ /* Set CTRL access to page*/
+ writechunk[CMD_BYTE(0, 0, 1)] = (0x8 << 4);
+ writechunk[CMD_BYTE(0, 1, 1)] = 0;
+ writechunk[CMD_BYTE(0, 2, 1)] = 0x20;
+
+ /* Do a page write */
+ if (curcmd->flags & __VPM150M_WR)
+ writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | 0x4) << 4);
+ else
+ writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | 0x4 | 0x1) << 4);
+ writechunk[CMD_BYTE(1, 1, 1)] = 0;
+ if (curcmd->flags & __VPM150M_WR)
+ writechunk[CMD_BYTE(1, 2, 1)] = curcmd->data[0] & 0xf;
+ else
+ writechunk[CMD_BYTE(1, 2, 1)] = 0;
+
+ if (curcmd->flags & __VPM150M_WR) {
+ /* Fill in buffer to size */
+ writechunk[CMD_BYTE(2, 0, 1)] = 0;
+ writechunk[CMD_BYTE(2, 1, 1)] = 0;
+ writechunk[CMD_BYTE(2, 2, 1)] = 0;
+ } else {
+ /* Do reads twice b/c of vpmadt032 bug */
+ writechunk[CMD_BYTE(2, 0, 1)] = ((0x8 | 0x4 | 0x1) << 4);
+ writechunk[CMD_BYTE(2, 1, 1)] = 0;
+ writechunk[CMD_BYTE(2, 2, 1)] = 0;
+ }
+
+ /* Clear XADD */
+ writechunk[CMD_BYTE(3, 0, 1)] = (0x8 << 4);
+ writechunk[CMD_BYTE(3, 1, 1)] = 0;
+ writechunk[CMD_BYTE(3, 2, 1)] = 0;
+
+ /* Fill in buffer to size */
+ writechunk[CMD_BYTE(4, 0, 1)] = 0;
+ writechunk[CMD_BYTE(4, 1, 1)] = 0;
+ writechunk[CMD_BYTE(4, 2, 1)] = 0;
+
+ } else {
+ /* Set address */
+ writechunk[CMD_BYTE(0, 0, 1)] = ((0x8 | 0x4) << 4);
+ writechunk[CMD_BYTE(0, 1, 1)] = (curcmd->address >> 8) & 0xff;
+ writechunk[CMD_BYTE(0, 2, 1)] = curcmd->address & 0xff;
+
+ /* Send/Get our data */
+ if (curcmd->flags & __VPM150M_WR) {
+ if (curcmd->datalen > 1)
+ writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | (0x1 << 1)) << 4);
+ else
+ writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | (0x3 << 1)) << 4);
+ } else
+ if (curcmd->datalen > 1)
+ writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | (0x1 << 1) | 0x1) << 4);
+ else
+ writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | (0x3 << 1) | 0x1) << 4);
+ writechunk[CMD_BYTE(1, 1, 1)] = (curcmd->data[0] >> 8) & 0xff;
+ writechunk[CMD_BYTE(1, 2, 1)] = curcmd->data[0] & 0xff;
+
+ if (curcmd->flags & __VPM150M_WR) {
+ /* Fill in */
+ writechunk[CMD_BYTE(2, 0, 1)] = 0;
+ writechunk[CMD_BYTE(2, 1, 1)] = 0;
+ writechunk[CMD_BYTE(2, 2, 1)] = 0;
+ } else {
+ /* Do this again for reads b/c of the bug in vpmadt032 */
+ writechunk[CMD_BYTE(2, 0, 1)] = ((0x8 | (0x3 << 1) | 0x1) << 4);
+ writechunk[CMD_BYTE(2, 1, 1)] = (curcmd->data[0] >> 8) & 0xff;
+ writechunk[CMD_BYTE(2, 2, 1)] = curcmd->data[0] & 0xff;
+ }
+
+ if (curcmd->datalen > 1) {
+ if (curcmd->flags & __VPM150M_WR)
+ writechunk[CMD_BYTE(3, 0, 1)] = ((0x8 | (0x1 << 1)) << 4);
+ else
+ writechunk[CMD_BYTE(3, 0, 1)] = ((0x8 | (0x1 << 1) | 0x1) << 4);
+ writechunk[CMD_BYTE(3, 1, 1)] = (curcmd->data[1] >> 8) & 0xff;
+ writechunk[CMD_BYTE(3, 2, 1)] = curcmd->data[1] & 0xff;
+ } else {
+ /* Fill in the rest */
+ writechunk[CMD_BYTE(3, 0, 1)] = 0;
+ writechunk[CMD_BYTE(3, 1, 1)] = 0;
+ writechunk[CMD_BYTE(3, 2, 1)] = 0;
+ }
+
+ if (curcmd->datalen > 2) {
+ if (curcmd->flags & __VPM150M_WR)
+ writechunk[CMD_BYTE(4, 0, 1)] = ((0x8 | (0x1 << 1)) << 4);
+ else
+ writechunk[CMD_BYTE(4, 0, 1)] = ((0x8 | (0x1 << 1) | 0x1) << 4);
+ writechunk[CMD_BYTE(4, 1, 1)] = (curcmd->data[2] >> 8) & 0xff;
+ writechunk[CMD_BYTE(4, 2, 1)] = curcmd->data[2] & 0xff;
+ } else {
+ /* Fill in the rest */
+ writechunk[CMD_BYTE(4, 0, 1)] = 0;
+ writechunk[CMD_BYTE(4, 1, 1)] = 0;
+ writechunk[CMD_BYTE(4, 2, 1)] = 0;
+ }
+ }
+ } else if (test_and_clear_bit(VPM150M_SWRESET, &vpm150m->control)) {
+ debug_printk(1, "Booting VPMADT032\n");
+ for (x = 0; x < 7; x++) {
+ if (x == 0)
+ writechunk[CMD_BYTE(x, 0, 1)] = (0x8 << 4);
+ else
+ writechunk[CMD_BYTE(x, 0, 1)] = 0x00;
+ writechunk[CMD_BYTE(x, 1, 1)] = 0;
+ if (x == 0)
+ writechunk[CMD_BYTE(x, 2, 1)] = 0x01;
+ else
+ writechunk[CMD_BYTE(x, 2, 1)] = 0x00;
+ }
+ } else {
+ for (x = 0; x < 7; x++) {
+ writechunk[CMD_BYTE(x, 0, 1)] = 0x00;
+ writechunk[CMD_BYTE(x, 1, 1)] = 0x00;
+ writechunk[CMD_BYTE(x, 2, 1)] = 0x00;
+ }
+ }
+
+ /* Add our leds in */
+ for (x = 0; x < 7; x++)
+ writechunk[CMD_BYTE(x, 0, 1)] |= leds;
+
+#if 0
+ int y;
+ for (x = 0; x < 7; x++) {
+ for (y = 0; y < 3; y++) {
+ if (writechunk[CMD_BYTE(x, y, 1)] & 0x2) {
+ module_printk("the test bit is high for byte %d\n", y);
+ }
+ }
+ }
+#endif
+
+ /* Now let's figure out if we need to check for DTMF */
+ /* polling */
+ if (test_bit(VPM150M_ACTIVE, &vpm150m->control) && !whichframe && !(wc->intcount % 100))
+ queue_work(vpm150m->wq, &vpm150m->work_dtmf);
+
+#if 0
+ /* This may be needed sometime in the future to troubleshoot ADT related issues. */
+ if (test_bit(VPM150M_ACTIVE, &vpm150m->control) && !whichframe && !(wc->intcount % 10000))
+ queue_work(vpm150m->wq, &vpm150m->work_debug);
+#endif
+}
+
+inline void vpm150m_cmd_decipher(struct t1 *wc, volatile unsigned char *readchunk)
+{
+ unsigned char ident;
+ int x, i;
+
+ /* Skip audio */
+ readchunk += 66;
+ /* Search for any pending results */
+ for (x = 0; x < VPM150M_MAX_COMMANDS; x++) {
+ if ((wc->vpm150m->cmdq[x].flags & (__VPM150M_RD | __VPM150M_WR)) &&
+ (wc->vpm150m->cmdq[x].flags & (__VPM150M_TX)) &&
+ !(wc->vpm150m->cmdq[x].flags & (__VPM150M_FIN))) {
+ ident = wc->vpm150m->cmdq[x].ident;
+ if (ident == wc->rxident) {
+ /* Store result */
+ for (i = 0; i < wc->vpm150m->cmdq[x].datalen; i++) {
+ wc->vpm150m->cmdq[x].data[i] = (0xff & readchunk[CMD_BYTE((2 + i), 1, 1)]) << 8;
+ wc->vpm150m->cmdq[x].data[i] |= readchunk[CMD_BYTE((2 + i), 2, 1)];
+ }
+ if (wc->vpm150m->cmdq[x].flags & __VPM150M_WR) {
+ /* Go ahead and clear out writes since they need no acknowledgement */
+ wc->vpm150m->cmdq[x].flags = 0;
+ } else
+ wc->vpm150m->cmdq[x].flags |= __VPM150M_FIN;
+ break;
+ }
+ }
+ }
+}
+
+static inline struct t1 * wc_find_iface(unsigned short dspid)
+{
+ int i;
+ struct t1 *ret = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ifacelock, flags);
+ for (i = 0; i < WC_MAX_IFACES; i++)
+ if (ifaces[i] && ifaces[i]->vpm150m && (ifaces[i]->vpm150m->dspid == dspid))
+ ret = ifaces[i];
+ spin_unlock_irqrestore(&ifacelock, flags);
+
+ return ret;
+}
+
+static struct vpm150m_cmd * vpm150m_empty_slot(struct t1 *wc)
+{
+ unsigned int x;
+
+ for (x = 0; x < VPM150M_MAX_COMMANDS; x++) {
+ if (!wc->vpm150m->cmdq[x].flags) {
+ return &wc->vpm150m->cmdq[x];
+ }
+ }
+ return NULL;
+}
+
+/* Wait for any outstanding commands to be completed. */
+static inline int vpm150m_io_wait(struct t1 *wc)
+{
+ int x;
+ int ret=0;
+ for (x=0; x < VPM150M_MAX_COMMANDS;) {
+ if (wc->vpm150m->cmdq[x].flags) {
+ if ((ret=schluffen(&wc->regq))) {
+ return ret;
+ }
+ x=0;
+ }
+ else {
+ ++x;
+ }
+ }
+ return ret;
+}
+
+int t1_vpm150m_getreg_full_async(struct t1 *wc, int pagechange, unsigned int len,
+ unsigned short addr, unsigned short *outbuf, struct vpm150m_cmd **hit_p)
+{
+ int ret=0;
+ unsigned long flags;
+ BUG_ON(!hit_p);
+ spin_lock_irqsave(&wc->reglock, flags);
+ (*hit_p) = vpm150m_empty_slot(wc);
+ if (*hit_p) {
+ (*hit_p)->flags = __VPM150M_RD;
+ if (pagechange) {
+ (*hit_p)->flags |= __VPM150M_RWPAGE;
+ }
+ (*hit_p)->datalen = len;
+ (*hit_p)->address = addr;
+ memset((*hit_p)->data, 0, len*sizeof(outbuf[0]));
+ }
+ else {
+ ret = -EBUSY;
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return ret;
+}
+
+int t1_vpm150m_getreg_full_return(struct t1 *wc, int pagechange, unsigned int len,
+ unsigned short addr, unsigned short *outbuf, struct vpm150m_cmd **hit_p)
+{
+ int ret = 0;
+ unsigned long flags;
+ BUG_ON(!hit_p);
+ spin_lock_irqsave(&wc->reglock, flags);
+ do {
+ if ((*hit_p)->flags & __VPM150M_FIN) {
+ memcpy(outbuf, (*hit_p)->data, len*(sizeof(outbuf[0])));
+ (*hit_p)->flags = 0;
+ (*hit_p) = NULL;
+ ret = 0;
+ }
+ else {
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if ((ret=schluffen(&wc->regq))) {
+ return ret;
+ }
+ spin_lock_irqsave(&wc->reglock, flags);
+ ret = -EBUSY;
+ }
+ } while (-EBUSY == ret);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ return ret;
+}
+
+int t1_vpm150m_getreg_full(struct t1 *wc, int pagechange, unsigned int len, unsigned short addr, unsigned short *outbuf)
+{
+ struct vpm150m_cmd *hit = 0;
+ int ret = 0;
+ do {
+ ret = t1_vpm150m_getreg_full_async(wc, pagechange, len, addr, outbuf, &hit);
+ if (!hit) {
+ if ( -EBUSY == ret ) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ BUG_ON( 0 != ret);
+ }
+ } while (!hit);
+
+ ret = t1_vpm150m_getreg_full_return(wc, pagechange, len, addr, outbuf, &hit);
+ return ret;
+}
+
+int t1_vpm150m_setreg_full(struct t1 *wc, int pagechange, unsigned int len, unsigned int addr, unsigned short *data)
+{
+ unsigned long flags;
+ struct vpm150m_cmd *hit;
+ int ret, i;
+ do {
+ spin_lock_irqsave(&wc->reglock, flags);
+ hit = vpm150m_empty_slot(wc);
+ if (hit) {
+ hit->flags = __VPM150M_WR;
+ if (pagechange)
+ hit->flags |= __VPM150M_RWPAGE;
+ hit->address = addr;
+ hit->datalen = len;
+ for (i = 0; i < len; i++)
+ hit->data[i] = data[i];
+ }
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ if (!hit) {
+ if ((ret = schluffen(&wc->regq)))
+ return ret;
+ }
+ } while (!hit);
+ return (hit) ? 0 : -1;
+}
+
+int t1_vpm150m_setpage(struct t1 *wc, unsigned short addr)
+{
+ addr &= 0xf;
+ /* Let's optimize this a little bit */
+ if (wc->vpm150m->curpage == addr)
+ return 0;
+ else {
+ wc->vpm150m->curpage = addr;
+ }
+
+ return t1_vpm150m_setreg_full(wc, 1, 1, 0, &addr);
+}
+
+unsigned char t1_vpm150m_getpage(struct t1 *wc)
+{
+ unsigned short res;
+ t1_vpm150m_getreg_full(wc, 1, 1, 0, &res);
+ return res;
+}
+
+int t1_vpm150m_setreg(struct t1 *wc, unsigned int len, unsigned int addr, unsigned short *data)
+{
+ int res;
+ t1_vpm150m_setpage(wc, addr >> 16);
+ if ((addr >> 16) != ((addr + len) >> 16))
+ module_printk("setreg: You found it!\n");
+ res = t1_vpm150m_setreg_full(wc, 0, len, addr & 0xffff, data);
+ return res;
+}
+
+unsigned short t1_vpm150m_getreg(struct t1 *wc, unsigned int len, unsigned int addr, unsigned short *data)
+{
+ unsigned short res;
+ t1_vpm150m_setpage(wc, addr >> 16);
+ if ((addr >> 16) != ((addr + len) >> 16))
+ module_printk("getreg: You found it!\n");
+ res = t1_vpm150m_getreg_full(wc, 0, len, addr & 0xffff, data);
+ return res;
+}
+
+static char vpm150mtone_to_zaptone(GpakToneCodes_t tone)
+{
+ switch (tone) {
+ case DtmfDigit0:
+ return '0';
+ case DtmfDigit1:
+ return '1';
+ case DtmfDigit2:
+ return '2';
+ case DtmfDigit3:
+ return '3';
+ case DtmfDigit4:
+ return '4';
+ case DtmfDigit5:
+ return '5';
+ case DtmfDigit6:
+ return '6';
+ case DtmfDigit7:
+ return '7';
+ case DtmfDigit8:
+ return '8';
+ case DtmfDigit9:
+ return '9';
+ case DtmfDigitPnd:
+ return '#';
+ case DtmfDigitSt:
+ return '*';
+ case DtmfDigitA:
+ return 'A';
+ case DtmfDigitB:
+ return 'B';
+ case DtmfDigitC:
+ return 'C';
+ case DtmfDigitD:
+ return 'D';
+ case EndofCngDigit:
+ return 'f';
+ default:
+ return 0;
+ }
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void vpm150m_echocan_bh(void *data)
+{
+ struct vpm150m *vpm150m = data;
+#else
+static void vpm150m_echocan_bh(struct work_struct *data)
+{
+ struct vpm150m *vpm150m = container_of(data, struct vpm150m, work_echocan);
+#endif
+ struct t1 *wc = vpm150m->wc;
+ struct list_head *task;
+ struct list_head *next_task;
+ unsigned long flags;
+
+ list_for_each_safe(task, next_task, &vpm150m->worklist) {
+ struct vpm150m_workentry *we = list_entry(task, struct vpm150m_workentry, list);
+ struct zt_chan *chan = we->chan;
+ int deflaw;
+ int res;
+ GPAK_AlgControlStat_t pstatus;
+
+ if (we->params.tap_length) {
+ /* configure channel for the ulaw/alaw */
+ unsigned int start = wc->intcount;
+
+ if (memcmp(&we->params, &vpm150m->chan_params[chan->chanpos - 1], sizeof(we->params))) {
+ /* set parameters */
+ vpm150m->chan_params[chan->chanpos - 1] = we->params;
+ }
+
+ deflaw = chan->span->deflaw;
+ debug_printk(1, "Enabling EC on channel %d (law %d)\n", chan->chanpos, deflaw);
+ if (deflaw == 2) /* alaw */
+ res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, EnableALawSwCompanding, &pstatus);
+ else if (deflaw == 1) /* alaw */
+ res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, EnableMuLawSwCompanding, &pstatus);
+ else {
+ module_printk("Undefined law for channel %d.\n", chan->chanpos);
+ res = -1;
+ }
+
+ if (res) {
+ module_printk("Unable to set SW Companding on channel %d (reason %d)\n", chan->chanpos, res);
+ }
+
+ res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, EnableEcanA, &pstatus);
+ debug_printk(2, "Echo can enable took %d ms\n", wc->intcount - start);
+ } else {
+ unsigned int start = wc->intcount;
+ debug_printk(1, "Disabling EC on channel %d\n", chan->chanpos);
+ res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, BypassSwCompanding, &pstatus);
+ if (res)
+ module_printk("Unable to disable sw companding on echo cancellation channel %d (reason %d)\n", chan->chanpos, res);
+ res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, BypassEcanA, &pstatus);
+ if (res)
+ module_printk("Unable to disable echo can on channel %d (reason %d)\n", chan->chanpos, res);
+ debug_printk(2, "Echocan disable took %d ms\n", wc->intcount - start);
+ }
+ if (res) {
+ module_printk("Unable to toggle echo cancellation on channel %d (reason %d)\n", chan->chanpos, res);
+ }
+
+ spin_lock_irqsave(&vpm150m->lock, flags);
+ list_del(task);
+ spin_unlock_irqrestore(&vpm150m->lock, flags);
+ kfree(we);
+ }
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void vpm150m_debug_bh(void *data)
+{
+ struct vpm150m *vpm150m = data;
+#else
+static void vpm150m_debug_bh(struct work_struct *data)
+{
+ struct vpm150m *vpm150m = container_of(data, struct vpm150m, work_debug);
+#endif
+ unsigned short int FrammingError1Count, FramingError2Count, FramingError3Count,
+ DmaStopErrorCount, DmaSlipStatsBuffer;
+
+ if (gpakReadFramingStats(vpm150m->dspid, &FrammingError1Count, &FramingError2Count, &FramingError3Count,
+ &DmaStopErrorCount, &DmaSlipStatsBuffer))
+ {
+ module_printk("There was an error getting framing stats.\n");
+ }
+ if (FrammingError1Count||FramingError2Count||FramingError3Count||DmaStopErrorCount||DmaSlipStatsBuffer)
+ {
+ module_printk("FramingStats Error: %d %d %d %d %d\n",
+ FrammingError1Count, FramingError2Count, FramingError3Count, DmaStopErrorCount, DmaSlipStatsBuffer);
+ }
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void vpm150m_dtmf_bh(void *data)
+{
+ struct vpm150m *vpm150m = data;
+#else
+static void vpm150m_dtmf_bh(struct work_struct *data)
+{
+ struct vpm150m *vpm150m = container_of(data, struct vpm150m, work_dtmf);
+#endif
+ struct t1 *wc = vpm150m->wc;
+ int i;
+
+ for (i = 0; i < wc->span.channels; i++) {
+ int enable = -1;
+ if (test_bit(i, &vpm150m->desireddtmfmutestate)) {
+ if (!test_bit(i, &vpm150m->curdtmfmutestate)) {
+ enable = 1;
+ }
+ } else {
+ if (test_bit(i, &vpm150m->curdtmfmutestate)) {
+ enable = 0;
+ }
+ }
+ if (enable > -1) {
+ unsigned int start = wc->intcount;
+ GPAK_AlgControlStat_t pstatus;
+ int res;
+
+ if (enable) {
+ res = gpakAlgControl(vpm150m->dspid, i, EnableDTMFMuteA, &pstatus);
+ debug_printk(2, "DTMF mute enable took %d ms\n", wc->intcount - start);
+ } else {
+ res = gpakAlgControl(vpm150m->dspid, i, DisableDTMFMuteA, &pstatus);
+ debug_printk(2, "DTMF mute disable took %d ms\n", wc->intcount - start);
+ }
+ if (!res)
+ change_bit(i, &vpm150m->curdtmfmutestate);
+ }
+ }
+
+ if (test_bit(VPM150M_DTMFDETECT, &vpm150m->control)) {
+ unsigned short channel;
+ GpakAsyncEventCode_t eventcode;
+ GpakAsyncEventData_t eventdata;
+ gpakReadEventFIFOMessageStat_t res;
+ unsigned int start = wc->intcount;
+
+ do {
+ res = gpakReadEventFIFOMessage(vpm150m->dspid, &channel, &eventcode, &eventdata);
+ debug_printk(3, "ReadEventFIFOMessage took %d ms\n", wc->intcount - start);
+
+ if (res == RefInvalidEvent || res == RefDspCommFailure) {
+ module_printk("Uh oh (%d)\n", res);
+ continue;
+ }
+
+ if (eventcode == EventToneDetect) {
+ GpakToneCodes_t tone = eventdata.toneEvent.ToneCode;
+ int duration = eventdata.toneEvent.ToneDuration;
+ char zaptone = vpm150mtone_to_zaptone(tone);
+
+ debug_printk(1, "Channel %d: Detected DTMF tone %d of duration %d\n", channel + 1, tone, duration);
+
+ if (test_bit(channel, &wc->dtmfmask) && (eventdata.toneEvent.ToneDuration > 0)) {
+ struct zt_chan *chan = &wc->chans[channel];
+
+ module_printk("DTMF detected channel=%d tone=%d duration=%d\n", channel + 1, tone, duration);
+
+ if ((tone != EndofMFDigit) && (zaptone != 0)) {
+ vpm150m->curtone[channel] = tone;
+
+ if (test_bit(channel, &vpm150m->curdtmfmutestate)) {
+ unsigned long flags;
+ int y;
+
+ /* Mute the audio data buffers */
+ spin_lock_irqsave(&chan->lock, flags);
+ for (y = 0; y < chan->numbufs; y++) {
+ if ((chan->inreadbuf > -1) && (chan->readidx[y]))
+ memset(chan->readbuf[chan->inreadbuf], ZT_XLAW(0, chan), chan->readidx[y]);
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ }
+ if (!test_bit(channel, &wc->dtmfactive)) {
+ debug_printk(1,"Queuing DTMFDOWN %c\n", zaptone);
+ set_bit(channel, &wc->dtmfactive);
+ zt_qevent_lock(chan, (ZT_EVENT_DTMFDOWN | zaptone));
+ }
+ } else if ((tone == EndofMFDigit) && test_bit(channel, &wc->dtmfactive)) {
+ debug_printk(1,"Queuing DTMFUP %c\n", vpm150mtone_to_zaptone(vpm150m->curtone[channel]));
+ zt_qevent_lock(chan, (ZT_EVENT_DTMFUP | vpm150mtone_to_zaptone(vpm150m->curtone[channel])));
+ clear_bit(channel, &wc->dtmfactive);
+ }
+ }
+ }
+ } while ((res == RefEventAvail));
+ }
+
+ return;
+}
+
+void t1_vpm150m_init(struct t1 *wc) {
+ struct vpm150m *vpm150m;
+ unsigned short i;
+ unsigned short reg;
+ unsigned long flags;
+ gpakPingDspStat_t pingstatus;
+ gpakDownloadStatus_t downloadstatus;
+ struct t1_firmware fw;
+ struct firmware embedded_firmware;
+ const struct firmware *firmware = &embedded_firmware;
+#if !defined(HOTPLUG_FIRMWARE)
+ extern void _binary_zaptel_fw_vpmadt032_bin_size;
+ extern u8 _binary_zaptel_fw_vpmadt032_bin_start[];
+#else
+ static const char vpmadt032_firmware[] = "zaptel-fw-vpmadt032.bin";
+ struct pci_dev* pdev = voicebus_get_pci_dev(wc->vb);
+#endif
+
+#if 0
+ unsigned short omsg[4] = { 0xdead, 0xbeef, 0x1111, 0x2222};
+ unsigned short imsg[4];
+#endif
+
+ if (!vpmsupport) {
+ module_printk("VPM Support Disabled\n");
+ wc->vpm150m = NULL;
+ return;
+ }
+
+ vpm150m = kmalloc(sizeof(struct vpm150m), GFP_KERNEL);
+
+ if (!vpm150m) {
+ module_printk("Unable to allocate VPMADT032!\n");
+ return;
+ }
+ memset(vpm150m, 0, sizeof(struct vpm150m));
+
+ /* Init our vpm150m struct */
+ sema_init(&vpm150m->sem, 1);
+ vpm150m->curpage = 0x80;
+
+ for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) {
+ if (ifaces[i] == wc)
+ vpm150m->dspid = i;
+ }
+
+ debug_printk(1, "Setting VPMADT032 DSP ID to %d\n", vpm150m->dspid);
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->vpm150m = vpm150m;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ for (i = 0; i < 10; i++)
+ schluffen(&wc->regq);
+
+ debug_printk(1, "Looking for VPMADT032 by testing page access: ");
+ for (i = 0; i < 0xf; i++) {
+ int x;
+ for (x = 0; x < 3; x++) {
+ t1_vpm150m_setpage(wc, i);
+ reg = t1_vpm150m_getpage(wc);
+ if (reg != i) {
+ /* If they have debug turned on we want them to be able to
+ * report where in the code the module failed to come up. */
+ debug_printk(1, "Either no VPMADT032 module present or the module failed VPM page access test (%x != %x)\n", i, reg);
+ goto failed_exit;
+ }
+ }
+ }
+ debug_printk(1, "Passed\n");
+
+ set_bit(VPM150M_HPIRESET, &vpm150m->control);
+ msleep(2000);
+
+ /* Set us up to page 0 */
+ t1_vpm150m_setpage(wc, 0);
+ debug_printk(1, "VPMADT032 now doing address test: ");
+ for (i = 0; i < 16; i++) {
+ int x;
+ for (x = 0; x < 2; x++) {
+ t1_vpm150m_setreg(wc, 1, 0x1000, &i);
+ t1_vpm150m_getreg(wc, 1, 0x1000, &reg);
+ if (reg != i) {
+ module_printk("VPMADT032 Failed address test: sent %x != %x on try %d\n", i, reg, x);
+ goto failed_exit;
+ }
+ }
+ }
+ debug_printk(1, "Passed\n");
+
+#define TEST_SIZE 2
+ if (debug) {
+ int i;
+ unsigned short msg[TEST_SIZE];
+
+ set_bit(VPM150M_HPIRESET, &vpm150m->control);
+ msleep(2000);
+ gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ for (i = 0; i< TEST_SIZE; i++)
+ printk("%x ", msg[i]);
+ printk("\n");
+ for (i = 0; i< TEST_SIZE; i++)
+ msg[i] = 0xdead;
+ gpakWriteDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ gpakWriteDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ for (i = 0; i< TEST_SIZE; i++)
+ printk("%x ", msg[i]);
+ printk("\n");
+ gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ for (i = 0; i< TEST_SIZE; i++)
+ printk("%x ", msg[i]);
+ printk("\n");
+ for (i = 0; i< TEST_SIZE; i++)
+ msg[i] = 0xbeef;
+ gpakWriteDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ for (i = 0; i< TEST_SIZE; i++)
+ printk("%x ", msg[i]);
+ printk("\n");
+ gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ for (i = 0; i< TEST_SIZE; i++)
+ printk("%x ", msg[i]);
+ printk("\n");
+ for (i = 0; i< TEST_SIZE; i++)
+ msg[i] = 0x1111;
+ gpakWriteDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ for (i = 0; i< TEST_SIZE; i++)
+ printk("%x ", msg[i]);
+ printk("\n");
+ gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ for (i = 0; i< TEST_SIZE; i++)
+ printk("%x ", msg[i]);
+ printk("\n");
+ for (i = 0; i< TEST_SIZE; i++)
+ msg[i] = 0x2222;
+ gpakWriteDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ for (i = 0; i< TEST_SIZE; i++)
+ printk("%x ", msg[i]);
+ printk("\n");
+ gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+ for (i = 0; i< TEST_SIZE; i++)
+ printk("%x ", msg[i]);
+ printk("\n");
+ }
+
+#if defined(HOTPLUG_FIRMWARE)
+ if ((request_firmware(&firmware, vpmadt032_firmware, &pdev->dev) != 0) ||
+ !firmware) {
+ printk("VPMADT032: firmware %s not available from userspace\n", vpmadt032_firmware);
+ goto failed_exit;
+ }
+#else
+ embedded_firmware.data = _binary_zaptel_fw_vpmadt032_bin_start;
+ embedded_firmware.size = (size_t) &_binary_zaptel_fw_vpmadt032_bin_size;
+#endif
+ fw.fw = firmware;
+ fw.offset = 0;
+
+ set_bit(VPM150M_HPIRESET, &vpm150m->control);
+
+ while (test_bit(VPM150M_HPIRESET, &vpm150m->control))
+ schluffen(&wc->regq);
+
+ module_printk("VPMADT032 Loading firwmare... ");
+ downloadstatus = gpakDownloadDsp(vpm150m->dspid, &fw);
+
+ if (firmware != &embedded_firmware)
+ release_firmware(firmware);
+
+ if (downloadstatus != 0) {
+ module_printk("Unable to download firmware to VPMADT032 with cause %d\n", downloadstatus);
+ goto failed_exit;
+ } else {
+ module_printk("Success\n");
+ }
+
+ set_bit(VPM150M_SWRESET, &vpm150m->control);
+
+ while (test_bit(VPM150M_SWRESET, &vpm150m->control))
+ schluffen(&wc->regq);
+
+ msleep(700);
+#if 0
+ }
+#endif
+
+ pingstatus = gpakPingDsp(vpm150m->dspid, &vpm150m->version);
+
+ if (!pingstatus) {
+ debug_printk(1, "Version of DSP is %x\n", vpm150m->version);
+ } else {
+ module_printk("Unable to ping the DSP (%d)!\n", pingstatus);
+ goto failed_exit;
+ }
+
+ /* workqueue for DTMF and wc->span functions that cannot sleep */
+ spin_lock_init(&vpm150m->lock);
+ vpm150m->wq = create_singlethread_workqueue("wcte12xp");
+ vpm150m->wc = wc;
+ if (!vpm150m->wq) {
+ module_printk("Unable to create work queue!\n");
+ goto failed_exit;
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ INIT_WORK(&vpm150m->work_echocan, vpm150m_echocan_bh, vpm150m);
+ INIT_WORK(&vpm150m->work_dtmf, vpm150m_dtmf_bh, vpm150m);
+ INIT_WORK(&vpm150m->work_debug, vpm150m_debug_bh, vpm150m);
+#else
+ INIT_WORK(&vpm150m->work_echocan, vpm150m_echocan_bh);
+ INIT_WORK(&vpm150m->work_dtmf, vpm150m_dtmf_bh);
+ INIT_WORK(&vpm150m->work_debug, vpm150m_debug_bh);
+#endif
+ INIT_LIST_HEAD(&wc->vpm150m->worklist); /* list of echocan tasks */
+
+ if (vpm150m_config_hw(wc)) {
+ goto failed_exit;
+ }
+
+ return;
+
+failed_exit:
+ if (vpm150m->wq) {
+ destroy_workqueue(vpm150m->wq);
+ }
+ spin_lock_irqsave(&wc->reglock, flags);
+ wc->vpm150m = NULL;
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ kfree(vpm150m);
+
+ return;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadDspMemory - Read DSP memory.
+ *
+ * FUNCTION
+ * This function reads a contiguous block of words from DSP memory starting at
+ * the specified address.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+void gpakReadDspMemory(
+ unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ DSP_ADDRESS DspAddress, /* DSP's memory address of first word */
+ unsigned int NumWords, /* number of contiguous words to read */
+ DSP_WORD *pWordValues /* pointer to array of word values variable */
+ )
+{
+ struct t1 *wc = wc_find_iface(DspId);
+ int i;
+ int transcount;
+ int ret;
+
+ vpm150m_io_wait(wc);
+ if ( NumWords < VPM150M_MAX_COMMANDS ) {
+ struct vpm150m_cmd* cmds[VPM150M_MAX_COMMANDS] = {0};
+ t1_vpm150m_setpage(wc, DspAddress >> 16);
+ DspAddress &= 0xffff;
+ for (i=0; i < NumWords; ++i) {
+ ret = t1_vpm150m_getreg_full_async(wc,0,1,DspAddress+i,&pWordValues[i],
+ &cmds[i]);
+ if (0 != ret) {
+ return;
+ }
+ }
+ for (i=NumWords-1; i >=0; --i) {
+ ret = t1_vpm150m_getreg_full_return(wc,0,1,DspAddress+i,&pWordValues[i],
+ &cmds[i]);
+ if (0 != ret) {
+ return;
+ }
+ }
+ }
+ else {
+ for (i = 0; i < NumWords;) {
+ if ((NumWords - i) > VPM150M_MAX_DATA)
+ transcount = VPM150M_MAX_DATA;
+ else
+ transcount = NumWords - i;
+ t1_vpm150m_getreg(wc, transcount, DspAddress + i, &pWordValues[i]);
+ i += transcount;
+ }
+ }
+ return;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakWriteDspMemory - Write DSP memory.
+ *
+ * FUNCTION
+ * This function writes a contiguous block of words to DSP memory starting at
+ * the specified address.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+void gpakWriteDspMemory(
+ unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ DSP_ADDRESS DspAddress, /* DSP's memory address of first word */
+ unsigned int NumWords, /* number of contiguous words to write */
+ DSP_WORD *pWordValues /* pointer to array of word values to write */
+ )
+{
+
+ struct t1 *wc = wc_find_iface(DspId);
+ int i;
+ int transcount;
+
+ if (wc && wc->vpm150m) {
+ for (i = 0; i < NumWords;) {
+ if ((NumWords - i) > VPM150M_MAX_DATA)
+ transcount = VPM150M_MAX_DATA;
+ else
+ transcount = NumWords - i;
+ t1_vpm150m_setreg(wc, transcount, DspAddress + i, &pWordValues[i]);
+ i += transcount;
+ }
+ }
+ return;
+
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakHostDelay - Delay for a fixed time interval.
+ *
+ * FUNCTION
+ * This function delays for a fixed time interval before returning. The time
+ * interval is the Host Port Interface sampling period when polling a DSP for
+ * replies to command messages.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+void gpakHostDelay(void)
+{
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakLockAccess - Lock access to the specified DSP.
+ *
+ * FUNCTION
+ * This function aquires exclusive access to the specified DSP.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+void gpakLockAccess(unsigned short DspId)
+{
+ struct t1 *wc;
+
+ wc = wc_find_iface(DspId);
+
+ if (wc) {
+ struct vpm150m *vpm = wc->vpm150m;
+
+ if (vpm)
+ down_interruptible(&vpm->sem);
+ }
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakUnlockAccess - Unlock access to the specified DSP.
+ *
+ * FUNCTION
+ * This function releases exclusive access to the specified DSP.
+ *
+ * RETURNS
+ * nothing
+ *
+ */
+void gpakUnlockAccess(unsigned short DspId)
+{
+ struct t1 *wc;
+
+ wc = wc_find_iface(DspId);
+
+ if (wc) {
+ struct vpm150m *vpm = wc->vpm150m;
+
+ if (vpm)
+ up(&vpm->sem);
+ }
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadFile - Read a block of bytes from a G.PAK Download file.
+ *
+ * FUNCTION
+ * This function reads a contiguous block of bytes from a G.PAK Download file
+ * starting at the current file position.
+ *
+ * RETURNS
+ * The number of bytes read from the file.
+ * -1 indicates an error occurred.
+ * 0 indicates all bytes have been read (end of file)
+ *
+ */
+int gpakReadFile(
+ GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */
+ unsigned char *pBuffer, /* pointer to buffer for storing bytes */
+ unsigned int NumBytes /* number of bytes to read */
+ )
+{
+ struct t1_firmware *fw = FileId;
+ unsigned int i, count;
+
+ if (!fw || !fw->fw)
+ return -1;
+
+ if (NumBytes > (fw->fw->size - fw->offset))
+ count = fw->fw->size - fw->offset;
+ else
+ count = NumBytes;
+
+ for (i = 0; i < count; i++)
+ pBuffer[i] = fw->fw->data[fw->offset + i];
+
+ fw->offset += count;
+
+ return count;
+}
+
+int vpm150m_config_hw(struct t1 *wc)
+{
+ struct vpm150m *vpm150m = wc->vpm150m;
+ gpakConfigPortStatus_t configportstatus;
+ GpakPortConfig_t portconfig;
+ GPAK_PortConfigStat_t pstatus;
+ GpakChannelConfig_t chanconfig;
+ GPAK_ChannelConfigStat_t cstatus;
+ GPAK_AlgControlStat_t algstatus;
+
+ int res, i;
+
+ memset(&portconfig, 0, sizeof(GpakPortConfig_t));
+
+ /* First Serial Port config */
+ portconfig.SlotsSelect1 = SlotCfgNone;
+ portconfig.FirstBlockNum1 = 0;
+ portconfig.FirstSlotMask1 = 0x0000;
+ portconfig.SecBlockNum1 = 1;
+ portconfig.SecSlotMask1 = 0x0000;
+ portconfig.SerialWordSize1 = SerWordSize8;
+ portconfig.CompandingMode1 = cmpNone;
+ portconfig.TxFrameSyncPolarity1 = FrameSyncActHigh;
+ portconfig.RxFrameSyncPolarity1 = FrameSyncActHigh;
+ portconfig.TxClockPolarity1 = SerClockActHigh;
+ portconfig.RxClockPolarity1 = SerClockActHigh;
+ portconfig.TxDataDelay1 = DataDelay0;
+ portconfig.RxDataDelay1 = DataDelay0;
+ portconfig.DxDelay1 = Disabled;
+ portconfig.ThirdSlotMask1 = 0x0000;
+ portconfig.FouthSlotMask1 = 0x0000;
+ portconfig.FifthSlotMask1 = 0x0000;
+ portconfig.SixthSlotMask1 = 0x0000;
+ portconfig.SevenSlotMask1 = 0x0000;
+ portconfig.EightSlotMask1 = 0x0000;
+
+ /* Second Serial Port config */
+ portconfig.SlotsSelect2 = SlotCfg8Groups;
+ portconfig.FirstBlockNum2 = 0;
+ portconfig.FirstSlotMask2 = 0x5554;
+ portconfig.SecBlockNum2 = 1;
+ portconfig.SecSlotMask2 = 0x5555;
+ portconfig.ThirdSlotMask2 = 0x5555;
+ portconfig.FouthSlotMask2 = 0x5555;
+ portconfig.SerialWordSize2 = SerWordSize8;
+ portconfig.CompandingMode2 = cmpNone;
+ portconfig.TxFrameSyncPolarity2 = FrameSyncActHigh;
+ portconfig.RxFrameSyncPolarity2 = FrameSyncActHigh;
+ portconfig.TxClockPolarity2 = SerClockActHigh;
+ portconfig.RxClockPolarity2 = SerClockActHigh;
+ portconfig.TxDataDelay2 = DataDelay0;
+ portconfig.RxDataDelay2 = DataDelay0;
+ portconfig.DxDelay2 = Disabled;
+ portconfig.FifthSlotMask2 = 0x0001;
+ portconfig.SixthSlotMask2 = 0x0000;
+ portconfig.SevenSlotMask2 = 0x0000;
+ portconfig.EightSlotMask2 = 0x0000;
+
+ /* Third Serial Port Config */
+ portconfig.SlotsSelect3 = SlotCfg8Groups;
+ portconfig.FirstBlockNum3 = 0;
+ portconfig.FirstSlotMask3 = 0x5554;
+ portconfig.SecBlockNum3 = 1;
+ portconfig.SecSlotMask3 = 0x5555;
+ portconfig.SerialWordSize3 = SerWordSize8;
+ portconfig.CompandingMode3 = cmpNone;
+ portconfig.TxFrameSyncPolarity3 = FrameSyncActHigh;
+ portconfig.RxFrameSyncPolarity3 = FrameSyncActHigh;
+ portconfig.TxClockPolarity3 = SerClockActHigh;
+ portconfig.RxClockPolarity3 = SerClockActLow;
+ portconfig.TxDataDelay3 = DataDelay0;
+ portconfig.RxDataDelay3 = DataDelay0;
+ portconfig.DxDelay3 = Disabled;
+ portconfig.ThirdSlotMask3 = 0x5555;
+ portconfig.FouthSlotMask3 = 0x5555;
+ portconfig.FifthSlotMask3 = 0x0001;
+ portconfig.SixthSlotMask3 = 0x0000;
+ portconfig.SevenSlotMask3 = 0x0000;
+ portconfig.EightSlotMask3 = 0x0000;
+
+ if ((configportstatus = gpakConfigurePorts(vpm150m->dspid, &portconfig, &pstatus))) {
+ module_printk("Configuration of ports failed (%d)!\n", configportstatus);
+ return -1;
+ } else {
+ debug_printk(1, "Configured McBSP ports successfully\n");
+ }
+
+ if ((res = gpakPingDsp(vpm150m->dspid, &vpm150m->version))) {
+ module_printk("Error pinging DSP (%d)\n", res);
+ return -1;
+ }
+
+ for (i = 0; i < 32; i++) {
+ /* Let's configure a channel */
+ chanconfig.PcmInPortA = 3;
+ chanconfig.PcmInSlotA = (i + 1) * 2;
+ chanconfig.PcmOutPortA = 2;
+ chanconfig.PcmOutSlotA = (i + 1) * 2;
+ chanconfig.PcmInPortB = 2;
+ chanconfig.PcmInSlotB = (i + 1) * 2;
+ chanconfig.PcmOutPortB = 3;
+ chanconfig.PcmOutSlotB = (i + 1) * 2;
+ if (vpmdtmfsupport) {
+ chanconfig.ToneTypesA = DTMF_tone;
+ chanconfig.MuteToneA = Enabled;
+ chanconfig.FaxCngDetA = Enabled;
+ } else {
+ chanconfig.ToneTypesA = Null_tone;
+ chanconfig.MuteToneA = Disabled;
+ chanconfig.FaxCngDetA = Disabled;
+ }
+ chanconfig.ToneTypesB = Null_tone;
+ chanconfig.EcanEnableA = Enabled;
+ chanconfig.EcanEnableB = Disabled;
+ chanconfig.MuteToneB = Disabled;
+ chanconfig.FaxCngDetB = Disabled;
+
+ chanconfig.SoftwareCompand = cmpNone;
+
+ chanconfig.FrameRate = rate10ms;
+
+ chanconfig.EcanParametersA.EcanTapLength = 1024;
+ chanconfig.EcanParametersA.EcanNlpType = vpmnlptype;
+ chanconfig.EcanParametersA.EcanAdaptEnable = 1;
+ chanconfig.EcanParametersA.EcanG165DetEnable = 1;
+ chanconfig.EcanParametersA.EcanDblTalkThresh = 6;
+ chanconfig.EcanParametersA.EcanNlpThreshold = vpmnlpthresh;
+ chanconfig.EcanParametersA.EcanNlpConv = 0;
+ chanconfig.EcanParametersA.EcanNlpUnConv = 0;
+ chanconfig.EcanParametersA.EcanNlpMaxSuppress = vpmnlpmaxsupp;
+ chanconfig.EcanParametersA.EcanCngThreshold = 43;
+ chanconfig.EcanParametersA.EcanAdaptLimit = 50;
+ chanconfig.EcanParametersA.EcanCrossCorrLimit = 15;
+ chanconfig.EcanParametersA.EcanNumFirSegments = 3;
+ chanconfig.EcanParametersA.EcanFirSegmentLen = 64;
+
+ chanconfig.EcanParametersB.EcanTapLength = 1024;
+ chanconfig.EcanParametersB.EcanNlpType = vpmnlptype;
+ chanconfig.EcanParametersB.EcanAdaptEnable = 1;
+ chanconfig.EcanParametersB.EcanG165DetEnable = 1;
+ chanconfig.EcanParametersB.EcanDblTalkThresh = 6;
+ chanconfig.EcanParametersB.EcanNlpThreshold = vpmnlpthresh;
+ chanconfig.EcanParametersB.EcanNlpConv = 0;
+ chanconfig.EcanParametersB.EcanNlpUnConv = 0;
+ chanconfig.EcanParametersB.EcanNlpMaxSuppress = vpmnlpmaxsupp;
+ chanconfig.EcanParametersB.EcanCngThreshold = 43;
+ chanconfig.EcanParametersB.EcanAdaptLimit = 50;
+ chanconfig.EcanParametersB.EcanCrossCorrLimit = 15;
+ chanconfig.EcanParametersB.EcanNumFirSegments = 3;
+ chanconfig.EcanParametersB.EcanFirSegmentLen = 64;
+
+ if ((res = gpakConfigureChannel(vpm150m->dspid, i, tdmToTdm, &chanconfig, &cstatus))) {
+ module_printk("Unable to configure channel (%d)\n", res);
+ if (res == 1) {
+ module_printk("Reason %d\n", cstatus);
+ }
+
+ return -1;
+ }
+
+ if ((res = gpakAlgControl(vpm150m->dspid, i, BypassEcanA, &algstatus))) {
+ module_printk("Unable to disable echo can on channel %d (reason %d:%d)\n", i + 1, res, algstatus);
+ return -1;
+ }
+
+ if (vpmdtmfsupport) {
+ if ((res = gpakAlgControl(vpm150m->dspid, i, DisableDTMFMuteA, &algstatus))) {
+ module_printk("Unable to disable dtmf muting on channel %d (reason %d:%d)\n", i + 1, res, algstatus);
+ return -1;
+ }
+ }
+ }
+
+ if ((res = gpakPingDsp(vpm150m->dspid, &vpm150m->version))) {
+ module_printk("Error pinging DSP (%d)\n", res);
+ return -1;
+ }
+
+ /* Turn on DTMF detection */
+ if (vpmdtmfsupport)
+ set_bit(VPM150M_DTMFDETECT, &vpm150m->control);
+ set_bit(VPM150M_ACTIVE, &vpm150m->control);
+
+ return 0;
+}
+
+#endif
diff --git a/drivers/dahdi/wcte12xp/vpmadt032.h b/drivers/dahdi/wcte12xp/vpmadt032.h
new file mode 100644
index 0000000..e103e05
--- /dev/null
+++ b/drivers/dahdi/wcte12xp/vpmadt032.h
@@ -0,0 +1,148 @@
+/*
+ * Digium, Inc. Wildcard TE12xP T1/E1 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.
+ *
+ */
+
+#ifndef _VPM150M_H
+#define _VPM150M_H
+
+#include "wcte12xp.h"
+#include "adt_lec.h"
+
+struct t1_firmware {
+ const struct firmware *fw;
+ unsigned int offset;
+};
+
+/* Host and DSP system dependent related definitions. */
+#define MAX_DSP_CORES 128 /* maximum number of DSP cores */
+//#define MAX_CONFS 1 /* maximum number of conferences */
+//#define MAX_PKT_CHANNELS 8 /* maximum number of packet channels */
+#define MAX_CHANNELS 32 /* maximum number of channels */
+#define MAX_WAIT_LOOPS 50 /* max number of wait delay loops */
+#define DSP_IFBLK_ADDRESS 0x0100 /* DSP address of I/F block pointer */
+#define DOWNLOAD_BLOCK_SIZE 512 /* download block size (DSP words) */
+//#define MAX_CIDPAYLOAD_BYTES 512 /* max size of a CID payload (octets) */
+typedef unsigned short DSP_WORD; /* 16 bit DSP word */
+typedef unsigned int DSP_ADDRESS; /* 32 bit DSP address */
+typedef struct t1_firmware* GPAK_FILE_ID; /* G.PAK Download file identifier */
+
+#define __VPM150M_RWPAGE (1 << 4)
+#define __VPM150M_RD (1 << 3)
+#define __VPM150M_WR (1 << 2)
+#define __VPM150M_FIN (1 << 1)
+#define __VPM150M_TX (1 << 0)
+
+#define VPM150M_HPI_CONTROL 0x00
+#define VPM150M_HPI_ADDRESS 0x02
+#define VPM150M_HPI_DATA 0x03
+
+#define VPM150M_MAX_COMMANDS 8
+
+/* Some Bit ops for different operations */
+#define VPM150M_SPIRESET 0
+#define VPM150M_HPIRESET 1
+#define VPM150M_SWRESET 2
+#define VPM150M_DTMFDETECT 3
+#define VPM150M_ACTIVE 4
+#define VPM150M_MAX_DATA 1
+
+struct vpm150m_cmd {
+ unsigned short address;
+ unsigned short data[VPM150M_MAX_DATA];
+ unsigned char ident;
+ unsigned char datalen;
+ unsigned int flags;
+ unsigned char cs_slot;
+};
+
+struct vpm150m {
+ unsigned short dspid;
+ unsigned long control;
+ unsigned char curpage;
+ unsigned short version;
+ struct vpm150m_cmd cmdq[VPM150M_MAX_COMMANDS];
+ spinlock_t lock; /* control access to list of bottom half tasks */
+ struct semaphore sem;
+ struct workqueue_struct *wq;
+ struct work_struct work_dtmf;
+ struct work_struct work_debug;
+ struct work_struct work_echocan;
+ struct list_head worklist;
+ unsigned char curtone[32];
+ unsigned long curdtmfmutestate;
+ unsigned long desireddtmfmutestate;
+ struct adt_lec_params chan_params[32];
+ struct t1 *wc;
+};
+
+/* linked list for vpm echocan workqueue*/
+struct vpm150m_workentry {
+ struct list_head list;
+ struct t1 *wc; /* what card are we dealing with? */
+ struct zt_chan *chan; /* what channels are we going to deal with? */
+ struct adt_lec_params params; /* how should we behave? */
+};
+
+extern int debug;
+extern int vpmsupport;
+extern int vpmdtmfsupport;
+extern struct pci_driver te12xp_driver;
+
+void t1_vpm150m_init(struct t1 *wc);
+void vpm150m_cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int whichframe);
+void vpm150m_cmd_decipher(struct t1 *wc, volatile unsigned char *readchunk);
+int vpm150m_config_hw(struct t1 *wc);
+
+/* gpak API functions */
+void gpakReadDspMemory(
+ unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ DSP_ADDRESS DspAddress, /* DSP's memory address of first word */
+ unsigned int NumWords, /* number of contiguous words to read */
+ DSP_WORD *pWordValues /* pointer to array of word values variable */
+ );
+void gpakWriteDspMemory(
+ unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ DSP_ADDRESS DspAddress, /* DSP's memory address of first word */
+ unsigned int NumWords, /* number of contiguous words to write */
+ DSP_WORD *pWordValues /* pointer to array of word values to write */
+ );
+void gpakHostDelay(void);
+void gpakLockAccess(
+ unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ );
+void gpakUnlockAccess(
+ unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+ );
+int gpakReadFile(
+ GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */
+ unsigned char *pBuffer, /* pointer to buffer for storing bytes */
+ unsigned int NumBytes /* number of bytes to read */
+ );
+
+#endif
diff --git a/drivers/dahdi/wcte12xp/wcte12xp.h b/drivers/dahdi/wcte12xp/wcte12xp.h
new file mode 100644
index 0000000..aa6306b
--- /dev/null
+++ b/drivers/dahdi/wcte12xp/wcte12xp.h
@@ -0,0 +1,166 @@
+/*
+ * Digium, Inc. Wildcard TE12xP T1/E1 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.
+ *
+ */
+
+#ifndef _WCTE12XP_H
+#define _WCTE12XP_H
+
+#ifdef LINUX26
+/* Comment to disable VPM support */
+#define VPM_SUPPORT 1
+#endif
+
+#define WC_MAX_IFACES 8
+
+#ifdef VPM_SUPPORT
+#define MAX_TDM_CHAN 31
+#endif
+
+#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*2 /* 42 bytes /3 (cntl,addr,data) /2 (cs) */
+
+#define NUM_EC 4
+
+#define __CMD_VPM (1 << 16) /* flag for VPM action */
+#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 CMD_BYTE(slot, a, is_vpm) (slot*6)+(a*2)+is_vpm /* only even slots */
+//TODO: make a separate macro
+
+#define TYPE_T1 1
+#define TYPE_E1 2
+
+#define NOT_VPM -1
+
+#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)
+extern spinlock_t ifacelock;
+
+struct command {
+ unsigned short address;
+ unsigned char data;
+ unsigned char ident;
+ unsigned int flags;
+ unsigned char cs_slot;
+ unsigned char vpm_num; /* ignored for all but vpm commmands */
+};
+
+struct cmdq {
+ struct command cmds[MAX_COMMANDS];
+};
+
+struct vpm150m;
+
+struct t1 {
+ spinlock_t reglock;
+ unsigned char txident;
+ unsigned char rxident;
+ unsigned char statreg; /* bit 0 = vpmadt032 int */
+ 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;
+ char name[80];
+ 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 char ec_chunk1[32][ZT_CHUNKSIZE];
+ unsigned char ec_chunk2[32][ZT_CHUNKSIZE];
+ struct zt_span span; /* Span */
+ struct zt_chan chans[32]; /* Channels */
+ wait_queue_head_t regq;
+ struct cmdq cmdq;
+ struct command dummy; /* preallocate for dummy noop command */
+ unsigned char ctlreg;
+ unsigned int rxints;
+ unsigned int txints;
+ int usecount;
+ struct voicebus* vb;
+ unsigned int isrreaderrors;
+#ifdef VPM_SUPPORT
+ int vpm;
+ struct vpm150m *vpm150m;
+ unsigned long dtmfactive;
+ unsigned long dtmfmask;
+ unsigned long dtmfmutemask;
+#endif
+};
+
+int schluffen(wait_queue_head_t *q);
+
+#endif
diff --git a/drivers/dahdi/wcusb.c b/drivers/dahdi/wcusb.c
new file mode 100644
index 0000000..15205a4
--- /dev/null
+++ b/drivers/dahdi/wcusb.c
@@ -0,0 +1,1490 @@
+/*
+ * Wildcard S100U USB FXS Interface Zapata Telephony Driver
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Matthew Fredrickson <creslin@digium.com>
+ *
+ * Copyright (C) 2001, Linux Support Services, 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.
+ *
+ */
+
+/* Save power at the expense of not always being able to transmit on hook. If
+ this is set, we only transit on hook for some time after a ring
+ (POWERSAVE_TIMEOUT) */
+
+/* #define PROSLIC_POWERSAVE */
+#define POWERSAVE_TIME 4000
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/errno.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,19)
+#define USB2420
+#endif
+
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif /* STANDALONE_ZAPATA */
+
+#include "wcusb.h"
+#include "proslic.h"
+
+#ifndef FILL_CONTROL_URB
+#define FILL_CONTROL_URB usb_fill_control_urb
+#endif
+
+#ifdef DEBUG_WILDCARD
+#define DPRINTK(x) printk x
+#else
+#define DPRINTK(x)
+#endif
+
+// Function prototypes
+static int readProSlicDirectReg(struct usb_device *dev, unsigned char address, unsigned char* data);
+static int initializeIndirectRegisters(struct usb_device *dev);
+static int verifyIndirectRegisters(struct usb_device *dev);
+static int writeProSlicDirectReg(struct usb_device *dev, unsigned char address, unsigned char data);
+static int writeProSlicInDirectReg(struct usb_device *dev, unsigned char address, unsigned short data);
+static int readProSlicInDirectReg(struct usb_device *dev, unsigned char address, unsigned short *data);
+static int writeProSlicInDirectReg(struct usb_device *dev, unsigned char address, unsigned short data);
+
+static alpha indirect_regs[] =
+{
+{0,255,"DTMF_ROW_0_PEAK",0x55C2},
+{1,255,"DTMF_ROW_1_PEAK",0x51E6},
+{2,255,"DTMF_ROW2_PEAK",0x4B85},
+{3,255,"DTMF_ROW3_PEAK",0x4937},
+{4,255,"DTMF_COL1_PEAK",0x3333},
+{5,255,"DTMF_FWD_TWIST",0x0202},
+{6,255,"DTMF_RVS_TWIST",0x0202},
+{7,255,"DTMF_ROW_RATIO_TRES",0x0198},
+{8,255,"DTMF_COL_RATIO_TRES",0x0198},
+{9,255,"DTMF_ROW_2ND_ARM",0x0611},
+{10,255,"DTMF_COL_2ND_ARM",0x0202},
+{11,255,"DTMF_PWR_MIN_TRES",0x00E5},
+{12,255,"DTMF_OT_LIM_TRES",0x0A1C},
+{13,0,"OSC1_COEF",0x7B30},
+{14,1,"OSC1X",0x0063},
+{15,2,"OSC1Y",0x0000},
+{16,3,"OSC2_COEF",0x7870},
+{17,4,"OSC2X",0x007D},
+{18,5,"OSC2Y",0x0000},
+{19,6,"RING_V_OFF",0x0000},
+{20,7,"RING_OSC",0x7EF0},
+{21,8,"RING_X",0x0160},
+{22,9,"RING_Y",0x0000},
+{23,255,"PULSE_ENVEL",0x2000},
+{24,255,"PULSE_X",0x2000},
+{25,255,"PULSE_Y",0x0000},
+//{26,"RECV_DIGITAL_GAIN",0x4000}, // playback volume set lower
+{26,13,"RECV_DIGITAL_GAIN",0x2000}, // playback volume set lower
+{27,14,"XMIT_DIGITAL_GAIN",0x4000},
+//{27,"XMIT_DIGITAL_GAIN",0x2000},
+{28,15,"LOOP_CLOSE_TRES",0x1000},
+{29,16,"RING_TRIP_TRES",0x3600},
+{30,17,"COMMON_MIN_TRES",0x1000},
+{31,18,"COMMON_MAX_TRES",0x0200},
+{32,19,"PWR_ALARM_Q1Q2",0x07C0},
+{33,20,"PWR_ALARM_Q3Q4",0x2600},
+{34,21,"PWR_ALARM_Q5Q6",0x1B80},
+{35,22,"LOOP_CLOSURE_FILTER",0x8000},
+{36,23,"RING_TRIP_FILTER",0x0320},
+{37,24,"TERM_LP_POLE_Q1Q2",0x008C},
+{38,25,"TERM_LP_POLE_Q3Q4",0x0100},
+{39,26,"TERM_LP_POLE_Q5Q6",0x0010},
+{40,27,"CM_BIAS_RINGING",0x0C00},
+{41,64,"DCDC_MIN_V",0x0C00},
+{42,255,"DCDC_XTRA",0x1000},
+{43,66,"LOOP_CLOSE_TRES_LOW",0x1000},
+};
+
+static int debug = 0;
+
+#define FLAG_FLIP_RELAYS (1 << 0)
+
+static struct wc_usb_desc wcusb = { "Wildcard S100U USB FXS Interface" };
+static struct wc_usb_desc wcusb2 = { "Wildcard S110U USB FXS Interface", FLAG_FLIP_RELAYS };
+static struct wc_usb_desc wc_usb_phone = { "Wildcard Phone Test driver" };
+static struct wc_usb_pvt *ifaces[WC_MAX_IFACES];
+
+
+
+static void wcusb_check_keypad(struct wc_usb_pvt *p);
+static int set_aux_ctrl(struct wc_usb_pvt *p, char auxpins, int on);
+
+
+
+static int Wcusb_WriteWcRegs(struct usb_device *dev, unsigned char index,
+ unsigned char *data, int len)
+{
+ unsigned int pipe = usb_sndctrlpipe(dev, 0);
+ int requesttype;
+ int res;
+
+ requesttype = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+
+ res = usb_control_msg(dev, pipe, REQUEST_NORMAL, requesttype,
+ 0, index, data, len, CONTROL_TIMEOUT_JIFFIES);
+ if (res == -ETIMEDOUT) {
+ printk("wcusb: timeout on vendor write\n");
+ return -1;
+ } else if (res < 0) {
+ printk("wcusb: Error executing control: status=%d\n", le32_to_cpu(res));
+ return -1;
+ }
+ return 0;
+}
+
+static int Wcusb_ReadWcRegs(struct usb_device *dev, unsigned char index,
+ unsigned char *data, int len)
+{
+ unsigned int pipe = usb_rcvctrlpipe(dev, 0);
+ int requesttype;
+ int res;
+
+ requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+
+ res = usb_control_msg(dev, pipe, REQUEST_NORMAL, requesttype,
+ 0, index, data, len, CONTROL_TIMEOUT_JIFFIES);
+ if (res == -ETIMEDOUT) {
+ printk("wcusb: timeout on vendor write\n");
+ return -1;
+ } else if (res < 0) {
+ printk("wcusb: Error executing control: status=%d\n", le32_to_cpu(res));
+ return -1;
+ } else {
+ DPRINTK(("wcusb: Executed read, result = %d (data = %04x)\n", le32_to_cpu(res), (int) *data));
+ }
+ return 0;
+}
+
+#ifdef USB2420
+#if defined(LINUX26) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb, struct pt_regs *regs));
+static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb, struct pt_regs *regs));
+static void wcusb_async_control(struct urb *urb, struct pt_regs *regs);
+#else
+static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb));
+static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb));
+static void wcusb_async_control(struct urb *urb);
+#endif /* LINUX26 */
+#else
+static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(urb_t *urb));
+static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(urb_t *urb));
+static void wcusb_async_control(urb_t *urb);
+#endif
+
+static void proslic_read_direct_async(struct wc_usb_pvt *p, unsigned char address)
+{
+ p->wcregindex = address;
+ p->wcregbuf[0] = address | 0x80;
+ p->wcregbuf[1] = 0;
+ p->wcregbuf[2] = 0;
+ p->wcregbuf[3] = 0x67;
+ wcusb_async_write(p, WCUSB_SPORT0, p->wcregbuf, 4, STATE_WCREAD_WRITEREG, wcusb_async_control);
+}
+
+static void proslic_write_direct_async(struct wc_usb_pvt *p, unsigned char address, unsigned char val)
+{
+ p->wcregindex = address;
+ p->wcregbuf[0] = address & 0x7f;
+ p->wcregbuf[1] = val;
+ p->wcregbuf[2] = 0;
+ p->wcregbuf[3] = 0x27;
+ wcusb_async_write(p, WCUSB_SPORT0, p->wcregbuf, 4, STATE_WCWRITE_WRITERES, wcusb_async_control);
+}
+
+#ifdef USB2420
+#if defined(LINUX26) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+static void wcusb_async_control(struct urb *urb, struct pt_regs *regs)
+#else
+static void wcusb_async_control(struct urb *urb)
+#endif
+#else
+static void wcusb_async_control(urb_t *urb)
+#endif
+{
+ struct wc_usb_pvt *p = urb->context;
+ p->urbcount--;
+ if (urb->status) {
+ printk("Error in transfer...\n");
+ /* return is the "right thing", but don't... */
+ p->timer = 50;
+ /* return; */
+ }
+ if (!(p->flags & FLAG_RUNNING)) {
+ return;
+ }
+ switch (p->controlstate) {
+ case STATE_WCREAD_WRITEREG:
+ /* We've written the register to sport0, now read form sport 1 */
+ wcusb_async_read(p, WCUSB_SPORT1, &p->wcregval, 1, STATE_WCREAD_READRES, wcusb_async_control);
+ return;
+ case STATE_WCREAD_READRES:
+ switch(p->wcregindex) {
+ case 68:
+ if (!p->hookstate && (p->wcregval & 1)) {
+ p->hookstate = 1;
+ if (debug)
+ printk("Going off hook...\n");
+ zt_hooksig(&p->chan, ZT_RXSIG_OFFHOOK);
+ } else if (p->hookstate && !(p->wcregval & 1)) {
+ p->hookstate = 0;
+ if (debug)
+ printk("Going on hook...\n");
+ zt_hooksig(&p->chan, ZT_RXSIG_ONHOOK);
+ }
+ /* Set outgoing hook state if necessary */
+ if (p->txhook != p->newtxhook) {
+ if (debug)
+ printk("Really setting hook state to %d\n", p->newtxhook);
+ p->txhook = p->newtxhook;
+ proslic_write_direct_async(p, 64, p->newtxhook);
+ } else
+ p->timer = 50;
+ break;
+ case 64:
+ if (debug)
+ printk("Read hook state as %02x\n", p->wcregval);
+ p->timer = 50;
+ break;
+ default:
+ printk("dunno what to do with read/regindex %d\n", p->wcregindex);
+ p->wcregindex = 0;
+ }
+ return;
+ case STATE_WCWRITE_WRITERES:
+ switch(p->wcregindex) {
+ case 64:
+ if (debug) {
+ printk("Hook transition complete to %d\n", ((char *)(urb->transfer_buffer))[1]);
+#ifdef BOOST_RINGER
+ }
+ if (p->txhook == 4) {
+ /* Ringing -- boost battery to 96V */
+ proslic_write_direct_async(p, 74, 0x3f);
+ } else {
+ /* Leave battery at default 75V */
+ proslic_write_direct_async(p, 74, 0x32);
+ }
+ break;
+ case 74:
+ if (debug) {
+ printk("Battery set to -%dV\n", ((char *)(urb->transfer_buffer))[1] * 3 / 2);
+#endif
+ proslic_read_direct_async(p, 64);
+ } else
+ p->timer = 50;
+ break;
+ default:
+ printk("dunno what to do with write/regindex %d\n", p->wcregindex);
+ p->wcregindex = 0;
+ }
+ return;
+ default:
+ printk("async control in unknown state %d\n", p->controlstate);
+ }
+}
+
+#ifdef USB2420
+#if defined(LINUX26) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+static void keypad_check_done(struct urb *urb, struct pt_regs *regs)
+#else
+static void keypad_check_done(struct urb *urb)
+#endif
+#else
+static void keypad_check_done(urb_t *urb)
+#endif
+{
+ struct wc_usb_pvt *p = urb->context;
+ struct wc_keypad_data *d = p->pvt_data;
+ static char aux_pattern[] = {0x1e, 0x1d, 0x17, 0xf};
+ char digit = 'z';
+
+ p->urbcount--;
+ if (!d->running) {
+ printk("Stopping stream (check_done)\n");
+ return;
+ }
+
+ if (urb->status) {
+ printk("status %d\n", urb->status);
+ }
+
+ if (debug) printk("i is %d\n", d->i);
+ switch (d->state) {
+loop_start:
+ case STATE_FOR_LOOP_1_OUT:
+ if (debug) printk("data12 is %x\n", d->data12);
+ if(d->i < sizeof(aux_pattern) / sizeof(char)) {
+ d->tmp = aux_pattern[d->i] | (d->data12 & 0xe0);
+ d->state = STATE_FOR_LOOP_2_IN;
+ if (debug) printk("tmp is %x\n", d->tmp);
+ wcusb_async_write(p, 0x12, &d->tmp, 1, 0, keypad_check_done);
+ return;
+ } else {
+ goto func_end;
+ }
+ case STATE_FOR_LOOP_2_IN:
+ d->state = STATE_FOR_LOOP_PROC_DATA;
+ wcusb_async_read(p, 0xc0, &d->data, 1, 0, keypad_check_done);
+ return;
+ case STATE_FOR_LOOP_PROC_DATA:
+ d->state = STATE_FOR_LOOP_CLEAR_DIGIT;
+ if(debug) printk("data is %x\n", d->data);
+ if ((d->data & 0x1f) != 0x1f) {
+ if(d->data == 0xe && aux_pattern[d->i] == 0x1e) { digit = '1';}
+ else if(d->data == 0xd && aux_pattern[d->i] == 0x1e) { digit = '2';}
+ else if(d->data == 0xb && aux_pattern[d->i] == 0x1e) { digit = '3';}
+ else if(d->data == 0x7 && aux_pattern[d->i] == 0x1e) {
+ p->hookstate = 0; /* On||Off */
+ zt_hooksig(&p->chan, ZT_RXSIG_ONHOOK);
+ }
+
+ else if(d->data == 0xe && aux_pattern[d->i] == 0x1d) { digit = '4';}
+ else if(d->data == 0xd && aux_pattern[d->i] == 0x1d) { digit = '5';}
+ else if(d->data == 0xb && aux_pattern[d->i] == 0x1d) { digit = '6';}
+ else if(d->data == 0x7 && aux_pattern[d->i] == 0x1d) {
+ p->hookstate = 1;/* Dial */
+ zt_hooksig(&p->chan, ZT_RXSIG_OFFHOOK);
+ }
+
+ else if(d->data == 0xe && aux_pattern[d->i] == 0x17) { digit = '7';}
+ else if(d->data == 0xd && aux_pattern[d->i] == 0x17) { digit = '8';}
+ else if(d->data == 0xb && aux_pattern[d->i] == 0x17) { digit = '9';}
+ else if(d->data == 0x7 && aux_pattern[d->i] == 0x17) d->scanned_event = 15; /* ReDial */
+
+ else if(d->data == 0xe && aux_pattern[d->i] == 0xf) { digit = '*';}/* '*' */
+ else if(d->data == 0xd && aux_pattern[d->i] == 0xf) { digit = '0';}
+ else if(d->data == 0xb && aux_pattern[d->i] == 0xf) { digit = '#';} /* '#' */
+ else if(d->data == 0x7 && aux_pattern[d->i] == 0xf) d->scanned_event = 16; /* Volume? */
+ else {
+ (d->i)++;
+ if (debug) printk("Scanned event %d; data = %x\n", d->scanned_event, d->data);
+ goto loop_start;
+ }
+ } else {
+ if(debug) printk("Hit new if\n");
+ goto func_end;
+ }
+ if (debug) printk("wcusb: got digit %d\n", d->scanned_event);
+ if (digit != 'z') {
+ d->tone = zt_mf_tone(&p->chan, digit, p->chan.digitmode);
+ if (!d->tone) {
+ printk("wcusb: Didn't get a tone structure\n");
+ goto func_end;
+ }
+ zt_init_tone_state(&d->ts, d->tone);
+ p->sample = STREAM_DTMF;
+ }
+ d->count = 0;
+ case STATE_FOR_LOOP_CLEAR_DIGIT:
+ if (((d->data & 0xf) != 0xf) && d->count < 200) {
+ wcusb_async_read(p, 0xc0, &d->data, 1, 0, keypad_check_done);
+ return;
+ }
+ (d->i)++;
+ p->sample = STREAM_NORMAL;
+ goto loop_start;
+ }
+func_end:
+ p->timer = 100;
+ return;
+}
+
+static void wcusb_check_interrupt(struct wc_usb_pvt *p)
+{
+ /* Start checking for interrupts */
+ if (p->devclass == WC_KEYPAD) {
+ wcusb_check_keypad(p);
+ } else {
+ proslic_read_direct_async(p, 68);
+ }
+ return;
+}
+
+#ifdef USB2420
+#if defined(LINUX26) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb, struct pt_regs *regs))
+#else
+static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb))
+#endif /* LINUX26 */
+#else
+static int wcusb_async_read(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(urb_t *urb))
+#endif
+{
+ __u16 size = len;
+ __u16 ind = index;
+#ifdef USB2420
+ struct urb *urb = &p->control;
+ memset(urb, 0, sizeof(struct urb));
+
+ p->dr.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ p->dr.bRequest = REQUEST_NORMAL;
+ p->dr.wValue = 0;
+ p->dr.wIndex = cpu_to_le16(ind);
+ p->dr.wLength = cpu_to_le16(size);
+#else
+ urb_t *urb = &p->control;
+ memset(urb, 0, sizeof(urb_t));
+
+ p->dr.requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ p->dr.request = REQUEST_NORMAL;
+ p->dr.value = 0;
+ p->dr.index = cpu_to_le16(ind);
+ p->dr.length = cpu_to_le16(size);
+#endif
+
+ FILL_CONTROL_URB(urb, p->dev, usb_rcvctrlpipe(p->dev, 0), (unsigned char *)&p->dr, data, len, complete, p);
+#ifdef LINUX26
+ if (usb_submit_urb(urb, GFP_KERNEL))
+#else
+ if (usb_submit_urb(urb))
+#endif
+ {
+ printk("wcusb_async_read: control URB died\n");
+ p->timer = 50;
+ return -1;
+ }
+ p->controlstate = state;
+ p->urbcount++;
+ return 0;
+}
+
+#ifdef USB2420
+#if defined(LINUX26) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb, struct pt_regs *regs))
+#else
+static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(struct urb *urb))
+#endif /* LINUX26 */
+#else
+static int wcusb_async_write(struct wc_usb_pvt *p, unsigned char index, unsigned char *data, int len, int state, void (*complete)(urb_t *urb))
+#endif
+{
+ __u16 size = len;
+ __u16 ind = index;
+#ifdef USB2420
+ struct urb *urb = &p->control;
+ memset(urb, 0, sizeof(struct urb));
+
+ p->dr.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ p->dr.bRequest = REQUEST_NORMAL;
+ p->dr.wValue = 0;
+ p->dr.wIndex = cpu_to_le16(ind);
+ p->dr.wLength = cpu_to_le16(size);
+#else
+ urb_t *urb = &p->control;
+ memset(urb, 0, sizeof(urb_t));
+
+ p->dr.requesttype = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ p->dr.request = REQUEST_NORMAL;
+ p->dr.value = 0;
+ p->dr.index = cpu_to_le16(ind);
+ p->dr.length = cpu_to_le16(size);
+#endif
+
+ FILL_CONTROL_URB(urb, p->dev, usb_sndctrlpipe(p->dev, 0), (unsigned char *)&p->dr, data, len, complete, p);
+#ifdef LINUX26
+ if (usb_submit_urb(urb, GFP_KERNEL))
+#else
+ if (usb_submit_urb(urb))
+#endif
+ {
+ printk("wcusb_async_write: control URB died\n");
+ return -1;
+ }
+ p->controlstate = state;
+ p->urbcount++;
+ return 0;
+}
+
+/*
+** Write register to Wc560
+*/
+static int wcoutp(struct usb_device *dev, unsigned char address, unsigned char data)
+{
+ if (!Wcusb_WriteWcRegs(dev, address, &data, 1))
+ return 0;
+
+ return -1;
+}
+
+/*
+** read register from Wc560
+*/
+static int wcinp(struct usb_device *dev, unsigned char address, unsigned char* data )
+{
+ if (!Wcusb_ReadWcRegs(dev, address, data, 1))
+ return 0;
+
+ return -1;
+}
+
+static int waitForProSlicIndirectRegAccess(struct usb_device *dev)
+{
+ unsigned char count, data;
+ count = 0;
+ while (count++ < 3)
+ {
+ data = 0;
+ readProSlicDirectReg(dev, I_STATUS, &data);
+
+ if (!data)
+ return 0;
+
+ }
+
+ if(count > 2) printk(" ##### Loop error #####\n");
+
+ return -1;
+}
+
+static int writeProSlicInDirectReg(struct usb_device *dev, unsigned char address, unsigned short data)
+{
+
+ if(!waitForProSlicIndirectRegAccess(dev))
+ {
+ if (!writeProSlicDirectReg(dev, IDA_LO,(unsigned char)(data & 0xFF)))
+ {
+ if(!writeProSlicDirectReg(dev, IDA_HI,(unsigned char)((data & 0xFF00)>>8)))
+ {
+ if(!writeProSlicDirectReg(dev, IAA,address))
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+/*
+** Read register from ProSlic
+*/
+int readProSlicDirectReg(struct usb_device *dev, unsigned char address, unsigned char* dataRead)
+{
+ unsigned char data[4];
+
+ data[0] = address | 0x80;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0x67;
+
+ // write to WC register 0x26
+ Wcusb_WriteWcRegs(dev, WCUSB_SPORT0, data, 4);
+ Wcusb_ReadWcRegs(dev, WCUSB_SPORT1, data, 1);
+ *dataRead = data[0];
+
+ return 0;
+}
+
+/*
+** Write register to ProSlic
+*/
+int writeProSlicDirectReg(struct usb_device *dev, unsigned char address, unsigned char RegValue)
+{
+ unsigned char data[4];
+
+ data[0] = address & 0x7f;
+ data[1] = RegValue;
+ data[2] = 0;
+ data[3] = 0x27;
+
+ // write to WC register 0x26
+ return Wcusb_WriteWcRegs(dev, WCUSB_SPORT0, data, 4);
+}
+
+static int readProSlicInDirectReg(struct usb_device *dev, unsigned char address, unsigned short *data)
+{
+ if (!waitForProSlicIndirectRegAccess(dev))
+ {
+ if (!writeProSlicDirectReg(dev,IAA,address))
+ {
+ if(!waitForProSlicIndirectRegAccess(dev))
+ {
+ unsigned char data1, data2;
+
+ if (!readProSlicDirectReg(dev,IDA_LO, &data1) && !readProSlicDirectReg (dev, IDA_HI, &data2))
+ {
+ *data = data1 | (data2 << 8);
+ return 0;
+ } else
+ printk("Failed to read direct reg\n");
+ } else
+ printk("Failed to wait inside\n");
+ } else
+ printk("failed write direct IAA\n");
+ } else
+ printk("failed to wait\n");
+
+ return -1;
+}
+
+static int initializeIndirectRegisters(struct usb_device *dev)
+{
+ unsigned char i;
+
+ for (i=0; i<43; i++)
+ {
+ if(writeProSlicInDirectReg(dev, i,indirect_regs[i].initial))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int verifyIndirectRegisters(struct usb_device *dev)
+{
+ int passed = 1;
+ unsigned short i,j, initial;
+
+ for (i=0; i<43; i++)
+ {
+ if(readProSlicInDirectReg(dev, (unsigned char) i, &j)) {
+ printk("Failed to read indirect register %d\n", i);
+ return -1;
+ }
+ initial= indirect_regs[i].initial;
+
+ if ( j != initial )
+ {
+ printk("!!!!!!! %s iREG %X = %X should be %X\n",
+ indirect_regs[i].name,i,j,initial );
+ passed = 0;
+ }
+ }
+
+ if (passed) {
+ if (debug)
+ printk("Init Indirect Registers completed successfully.\n");
+ } else {
+ printk(" !!!!! Init Indirect Registers UNSUCCESSFULLY.\n");
+ }
+
+ return 0;
+}
+
+static int calibrateAndActivateProSlic(struct usb_device *dev)
+{
+ unsigned char x;
+
+ if(writeProSlicDirectReg(dev, 92, 0xc8))
+ return -1;
+
+ if(writeProSlicDirectReg(dev, 97, 0))
+ return -1;
+
+ if(writeProSlicDirectReg(dev, 93, 0x19))
+ return -1;
+
+ if(writeProSlicDirectReg(dev, 14, 0))
+ return -1;
+
+ if(writeProSlicDirectReg(dev, 93, 0x99))
+ return -1;
+
+ if(!readProSlicDirectReg (dev, 93, &x))
+ {
+ if (debug)
+ printk("DC Cal x=%x\n",x);
+
+ if (!writeProSlicDirectReg(dev, 97, 0))
+ {
+ if(!writeProSlicDirectReg(dev, CALIBR1, CALIBRATE_LINE))
+ {
+ unsigned char data;
+
+ if(!readProSlicDirectReg(dev, CALIBR1, &data))
+ return writeProSlicDirectReg(dev, LINE_STATE,ACTIVATE_LINE);
+ }
+ }
+ }
+
+ return -1;
+}
+
+static int InitProSlic(struct usb_device *dev)
+{
+ if (writeProSlicDirectReg(dev, 67, 0x0e))
+ /* Disable Auto Power Alarm Detect and other "features" */
+ return -1;
+ if (initializeIndirectRegisters(dev)) {
+ printk(KERN_INFO "Indirect Registers failed to initialize.\n");
+ return -1;
+ }
+ if (verifyIndirectRegisters(dev)) {
+ printk(KERN_INFO "Indirect Registers failed verification.\n");
+ return -1;
+ }
+ if (calibrateAndActivateProSlic(dev)) {
+ printk(KERN_INFO "ProSlic Died on Activation.\n");
+ return -1;
+ }
+ if (writeProSlicInDirectReg(dev, 97, 0x0)) { // Stanley: for the bad recording fix
+ printk(KERN_INFO "ProSlic IndirectReg Died.\n");
+ return -1;
+ }
+ if (writeProSlicDirectReg(dev, 1, 0x2a)) { // U-Law GCI 8-bit interface
+ printk(KERN_INFO "ProSlic DirectReg Died.\n");
+ return -1;
+ }
+ if (writeProSlicDirectReg(dev, 2, 0)) // Tx Start count low byte 0
+ return -1;
+ if (writeProSlicDirectReg(dev, 3, 0)) // Tx Start count high byte 0
+ return -1;
+ if (writeProSlicDirectReg(dev, 4, 0)) // Rx Start count low byte 0
+ return -1;
+ if (writeProSlicDirectReg(dev, 5, 0)) // Rx Start count high byte 0
+ return -1;
+ if (writeProSlicDirectReg(dev, 8, 0x0)) // disable loopback
+ return -1;
+ if (writeProSlicDirectReg(dev, 18, 0xff)) // clear all interrupt
+ return -1;
+ if (writeProSlicDirectReg(dev, 19, 0xff))
+ return -1;
+ if (writeProSlicDirectReg(dev, 20, 0xff))
+ return -1;
+ if (writeProSlicDirectReg(dev, 21, 0x00)) // enable interrupt
+ return -1;
+ if (writeProSlicDirectReg(dev, 22, 0x02)) // Loop detection interrupt
+ return -1;
+ if (writeProSlicDirectReg(dev, 23, 0x01)) // DTMF detection interrupt
+ return -1;
+ if (writeProSlicDirectReg(dev, 72, 0x20))
+ return -1;
+#ifdef BOOST_RINGER
+ /* Beef up Ringing voltage to 89V */
+ if (writeProSlicInDirectReg(dev, 23, 0x1d1))
+ return -1;
+#endif
+ return 0;
+}
+
+static int init_hardware(struct wc_usb_pvt *p)
+{
+ struct usb_device *dev = p->dev;
+
+ switch (p->devclass) {
+ case WC_PROSLIC:
+ if (wcoutp(dev, 0x12, 0x00)) /* AUX6 as output, set to low */
+ return -1;
+ if (wcoutp(dev, 0x13, 0x40)) /* AUX6 is output */
+ return -1;
+ if (wcoutp(dev, 0, 0x50)) /* extrst, AUX2 is suspend */
+ return -1;
+ if (wcoutp(dev, 0x29, 0x20)) /* enable SerialUP AUX pin definition */
+ return -1;
+ if (wcoutp(dev, 0, 0x51)) /* no extrst, AUX2 is suspend */
+ return -1;
+ /* Make sure there is no gain */
+ if (wcoutp(dev, 0x22, 0x00))
+ return -1;
+ if (wcoutp(dev, 0x23, 0xf2))
+ return -1;
+ if (wcoutp(dev, 0x24, 0x00))
+ return -1;
+ if (wcoutp(dev, 0x25, 0xc9))
+ return -1;
+ if (InitProSlic(dev)) {
+ printk("wcusb: Failed to initialize proslic\n");
+ return -1;
+ }
+ case WC_KEYPAD:
+ set_aux_ctrl(p, WC_AUX0, 1);
+ set_aux_ctrl(p, WC_AUX1, 1);
+ set_aux_ctrl(p, WC_AUX2, 1);
+ set_aux_ctrl(p, WC_AUX3, 1);
+ }
+
+ if (debug) printk("wcusb: Setting correct interfaces.\n");
+
+ /* Setup correct settings (8000 Hz, signed linear) */
+ if (usb_set_interface(dev, 2, 1)) {
+ printk("wcusb: Unable to setup USB interface 2 to altsetting 1\n");
+ return -1;
+ }
+ if (usb_set_interface(dev, 3, 1)) {
+ printk("wcusb: Unable to setup USB interface 3 to altsetting 1\n");
+ return -1;
+ }
+ return 0;
+}
+
+/* Don't call from an interrupt context */
+static int set_aux_ctrl(struct wc_usb_pvt *p, char uauxpins, int on)
+{
+ char udata12 = 0;
+ char udata13 = 0;
+
+ wcinp(p->dev, 0x12, &udata12);
+ wcinp(p->dev, 0x13, &udata13);
+
+ wcoutp(p->dev, 0x12, on ? (uauxpins | udata12) : (~uauxpins & udata12));
+ wcoutp(p->dev, 0x13, uauxpins | udata13);
+
+ return 0;
+}
+
+static void wcusb_check_keypad(struct wc_usb_pvt *p)
+{
+ struct wc_keypad_data *d = p->pvt_data;
+
+ if (!d->running) {
+ printk("Stopping keypad stream\n");
+ return;
+ }
+ if (debug) printk("Launched a packet\n");
+ d->state = STATE_FOR_LOOP_1_OUT;
+ d->data = -1;
+ d->data12 = -1;
+ d->scanned_event = -1;
+ d->i = 0;
+ wcusb_async_read(p, 0x12, &d->data12, 1, 0, keypad_check_done);
+ return;
+}
+
+static char wc_dtmf(struct wc_usb_pvt *p)
+{
+ struct wc_keypad_data *d = p->pvt_data;
+ short linsample = 0;
+
+ if (!d) {
+ printk("NULL pointer, go away\n");
+ return 0;
+ }
+
+ linsample = zt_tone_nextsample(&d->ts, d->tone);
+
+
+ return ZT_LIN2MU(linsample);
+}
+
+#if defined(LINUX26) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+static void wcusb_read_complete(struct urb *q, struct pt_regs *regs)
+#else
+static void wcusb_read_complete(struct urb *q)
+#endif
+{
+ struct wc_usb_pvt *p = q->context;
+ short *chunk = q->transfer_buffer;
+ int x;
+
+ if (!p->flags & FLAG_RUNNING) {
+ /* Stop sending URBs since we're not running anymore */
+ p->urbcount--;
+ return;
+ }
+
+ switch (p->sample) {
+ case STREAM_NORMAL:
+ for (x = 0; x < ZT_CHUNKSIZE; x++) {
+ p->chan.readchunk[x] = ZT_LIN2MU(le16_to_cpu(chunk[x]));
+ }
+ break;
+ case STREAM_DTMF:
+ for (x = 0; x < ZT_CHUNKSIZE; x++) {
+ p->chan.readchunk[x] = wc_dtmf(p);
+ }
+ break;
+ }
+ /* XXX We could probably optimize some here XXX */
+ zt_ec_chunk(&p->chan, p->chan.readchunk, p->chan.writechunk);
+
+ zt_receive(&p->span);
+
+ q->dev = p->dev;
+
+#ifdef LINUX26
+ if (usb_submit_urb(q, GFP_KERNEL))
+#else
+ if (usb_submit_urb(q))
+#endif
+ {
+ printk("wcusb: Read cycle failed\n");
+ }
+
+ if (p->timer && !--p->timer) {
+ if (p->devclass == WC_KEYPAD) {
+ if(debug) printk("Checking keypad\n");
+ wcusb_check_keypad(p);
+ } else {
+ wcusb_check_interrupt(p);
+ }
+ }
+
+#ifdef PROSLIC_POWERSAVE
+ if (p->devclass != WC_KEYPAD) {
+ if (p->lowpowertimer && !--p->lowpowertimer) {
+ /* Switch back into low power mode */
+ p->idletxhookstate = 1;
+ if (p->txhook == 2)
+ p->newtxhook = p->idletxhookstate;
+ }
+ }
+#endif
+ return;
+}
+
+#if defined(LINUX26) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+static void wcusb_write_complete(struct urb *q, struct pt_regs *regs)
+#else
+static void wcusb_write_complete(struct urb *q)
+#endif
+{
+ struct wc_usb_pvt *p = q->context;
+ short *chunk = q->transfer_buffer;
+ int x;
+
+ if (!p->flags & FLAG_RUNNING) {
+ /* Stop sending URBs since we're not running anymore */
+ p->urbcount--;
+ return;
+ }
+
+ zt_transmit(&p->span);
+ for (x = 0; x < ZT_CHUNKSIZE; x++) {
+ chunk[x] = cpu_to_le16(ZT_MULAW(p->chan.writechunk[x]));
+ }
+ q->dev = p->dev;
+
+#ifdef LINUX26
+ if (usb_submit_urb(q, GFP_KERNEL))
+#else
+ if (usb_submit_urb(q))
+#endif
+ {
+ printk("wcusb: Write cycle failed\n");
+ }
+
+ return;
+}
+
+static int StopTransmit(struct wc_usb_pvt *p)
+{
+ p->flags &= ~FLAG_RUNNING;
+
+ if (p->devclass == WC_KEYPAD) {
+ struct wc_keypad_data *d = p->pvt_data;
+ d->running = 0;
+ }
+ while(p->urbcount) {
+ schedule_timeout(1);
+ }
+ printk("ending transmit\n");
+ return 0;
+}
+
+static int flip_relays(struct wc_usb_pvt *p, int onoff)
+{
+ unsigned char ctl;
+ unsigned char data;
+ /* Read data */
+ if (wcinp(p->dev, 0x12, &data))
+ return -1;
+ /* Read control */
+ if (wcinp(p->dev, 0x13, &ctl))
+ return -1;
+ /* Setup values properly -- Pins AUX3 & AUX4 control the relays */
+ ctl |= 0x18;
+ if (onoff) {
+ data |= 0x18;
+ } else {
+ data &= 0xe7;
+ }
+ if (wcoutp(p->dev, 0x12, data))
+ return -1;
+ if (wcoutp(p->dev, 0x13, ctl))
+ return -1;
+ return 0;
+}
+
+static int prepare_transfer_urbs(struct wc_usb_pvt *p)
+{
+ int x;
+ /* Endpoint 6 is the wave-in device */
+ unsigned int readpipe = usb_rcvisocpipe(p->dev, 0x06);
+ /* Endpoint 7 is the wave-out device */
+ unsigned int writepipe = usb_sndisocpipe(p->dev, 0x07);
+
+ for (x = 0; x < 2; x++) {
+ p->dataread[x].urb.dev = p->dev;
+ p->dataread[x].urb.pipe = readpipe;
+#ifdef LINUX26
+ p->dataread[x].urb.transfer_flags = URB_ISO_ASAP;
+#else
+ p->dataread[x].urb.transfer_flags = USB_ISO_ASAP;
+#endif
+ p->dataread[x].urb.number_of_packets = 1;
+ p->dataread[x].urb.context = p;
+ p->dataread[x].urb.complete = wcusb_read_complete;
+ p->dataread[x].urb.iso_frame_desc[0].length = ZT_CHUNKSIZE * 2;
+ p->dataread[x].urb.iso_frame_desc[0].offset = 0;
+ p->dataread[x].urb.transfer_buffer = p->readchunk + ZT_CHUNKSIZE * x;
+ p->dataread[x].urb.transfer_buffer_length = ZT_CHUNKSIZE * 2;
+
+ p->datawrite[x].urb.dev = p->dev;
+ p->datawrite[x].urb.pipe = writepipe;
+#ifdef LINUX26
+ p->datawrite[x].urb.transfer_flags = URB_ISO_ASAP;
+#else
+ p->datawrite[x].urb.transfer_flags = USB_ISO_ASAP;
+#endif
+ p->datawrite[x].urb.number_of_packets = 1;
+ p->datawrite[x].urb.context = p;
+ p->datawrite[x].urb.complete = wcusb_write_complete;
+ p->datawrite[x].urb.iso_frame_desc[0].length = ZT_CHUNKSIZE * 2;
+ p->datawrite[x].urb.iso_frame_desc[0].offset = 0;
+ p->datawrite[x].urb.transfer_buffer = p->writechunk + ZT_CHUNKSIZE * x;
+ p->datawrite[x].urb.transfer_buffer_length = ZT_CHUNKSIZE * 2;
+
+ }
+ return 0;
+}
+
+static int begin_transfer(struct wc_usb_pvt *p)
+{
+
+ int x;
+ p->urbcount = 4;
+ p->flags |= FLAG_RUNNING;
+
+ for (x = 0; x < 2; x++) {
+#ifdef LINUX26
+ if (usb_submit_urb(&p->dataread[x].urb, GFP_KERNEL))
+#else
+ if (usb_submit_urb(&p->dataread[x].urb))
+#endif
+ {
+ printk(KERN_ERR "wcusb: Read submit failed\n");
+ return -1;
+ }
+#ifdef LINUX26
+ if (usb_submit_urb(&p->datawrite[x].urb, GFP_KERNEL))
+#else
+ if (usb_submit_urb(&p->datawrite[x].urb))
+#endif
+ {
+ printk(KERN_ERR "wcusb: Write submit failed\n");
+ return -1;
+ }
+ }
+ /* Start checking for interrupts */
+ wcusb_check_interrupt(p);
+ return 0;
+}
+
+static int wc_usb_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
+{
+ struct wc_usb_pvt *p = chan->pvt;
+
+ switch (p->devclass) {
+ case WC_PROSLIC:
+#ifdef PROSLIC_POWERSAVE
+ if (p->txhook == 4) {
+ /* Switching out of ring... Be sure we idle at 2, not 1 at least
+ for a bit so we can transmit caller*ID */
+ p->idletxhookstate = 2;
+ p->lowpowertimer = POWERSAVE_TIME;
+ }
+#endif
+
+ p->txhook = -1;
+ switch(txsig) {
+ case ZT_TXSIG_ONHOOK:
+ switch(chan->sig) {
+ case ZT_SIG_FXOKS:
+ case ZT_SIG_FXOLS:
+ p->newtxhook = p->idletxhookstate;
+ break;
+ case ZT_SIG_FXOGS:
+ p->newtxhook = 3;
+ break;
+ }
+ break;
+ case ZT_TXSIG_OFFHOOK:
+ p->newtxhook = p->idletxhookstate;
+ break;
+ case ZT_TXSIG_START:
+ p->newtxhook = 4;
+ break;
+ case ZT_TXSIG_KEWL:
+ p->newtxhook = 0;
+ break;
+ }
+ case WC_KEYPAD:
+ switch (txsig) {
+ case ZT_TXSIG_ONHOOK:
+ break;
+ case ZT_TXSIG_OFFHOOK:
+ break;
+ case ZT_TXSIG_START:
+ break;
+ case ZT_TXSIG_KEWL:
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+static int wc_usb_open(struct zt_chan *chan)
+{
+ struct wc_usb_pvt *p = chan->pvt;
+ if (p->dead)
+ return -1;
+ switch (p->devclass) {
+ case WC_KEYPAD:
+ p->hookstate = 0;
+ zt_hooksig(&p->chan, ZT_RXSIG_ONHOOK);
+ break;
+ default:
+ break;
+ }
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+ p->usecount++;
+ return 0;
+}
+
+static int wc_usb_close(struct zt_chan *chan)
+{
+ struct wc_usb_pvt *p = chan->pvt;
+ p->usecount--;
+ if (!p->usecount && p->dead) {
+ /* Someone unplugged us while we were running, so now
+ that the program exited, we can release our resources */
+ zt_unregister(&p->span);
+ ifaces[p->pos] = NULL;
+ if (p->pvt_data)
+ kfree(p->pvt_data);
+ kfree(p);
+ }
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static struct wc_usb_pvt *wc_detect_device(struct usb_device *dev, struct wc_usb_pvt *orig)
+{
+ struct wc_usb_pvt *p;
+
+ p = orig;
+ if (!p) {
+ p = kmalloc(sizeof(struct wc_usb_pvt), GFP_KERNEL);
+ if (!p) {
+ printk("wcusb: kmalloc failed\n");
+ return NULL;
+ }
+
+ memset(p, 0, sizeof(struct wc_usb_pvt));
+ }
+ p->dev = dev;
+
+#ifdef PROSLIC_POWERSAVE
+ /* By default we can't send on hook */
+ p->idletxhookstate = 1;
+#else
+ /* By default we can always send on hook */
+ p->idletxhookstate = 2;
+#endif
+
+ printk("wcusb: wc_detect_device\n");
+ if (dev->descriptor.idProduct == 0xb210) {
+ struct wc_keypad_data *d = kmalloc(sizeof(struct wc_keypad_data), GFP_KERNEL);
+ printk("wcusb: Found a WC Keyed Phone\n");
+ p->devclass = WC_KEYPAD;
+ if (!d) {
+ printk("wcusb: kmalloc failed in init_device_pvt\n");
+ return NULL;
+ }
+ memset(d, 0, sizeof(struct wc_keypad_data));
+ p->pvt_data = d;
+ d->count = 0;
+ d->running = 1;
+ d->tone = NULL;
+ return p;
+ } else {
+ p->pvt_data = NULL;
+ p->devclass = WC_PROSLIC;
+ }
+ printk("Second exit\n");
+ return p;
+}
+
+static int wc_set_zaptel(struct wc_usb_pvt *p)
+{
+ int x;
+
+ for (x = 0; x < WC_MAX_IFACES; x++)
+ if (!ifaces[x]) break;
+ if (x >= WC_MAX_IFACES) {
+ printk("wcusb: Too many interfaces\n");
+ return -1;
+ }
+
+ sprintf(p->span.name, "WCUSB/%d", x);
+ snprintf(p->span.desc, sizeof(p->span.desc) - 1, "%s %d", p->span.name, x);
+ sprintf(p->chan.name, "WCUSB/%d/%d", x, 0);
+ p->span.manufacturer = "Digium";
+ zap_copy_string(p->span.devicetype, p->variety, sizeof(p->span.devicetype));
+
+ p->chan.sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS; /* We're capabable of both FXOKS and FXOLS */
+ p->chan.chanpos = 1;
+ p->span.deflaw = ZT_LAW_MULAW;
+ p->span.chans = &p->chan;
+ p->span.channels = 1;
+ p->span.hooksig = wc_usb_hooksig;
+ p->span.open = wc_usb_open;
+ p->span.close = wc_usb_close;
+
+ ifaces[x] = p;
+ p->pos = x;
+ p->span.flags = ZT_FLAG_RBS;
+ init_waitqueue_head(&p->span.maintq);
+ p->span.pvt = p;
+ p->chan.pvt = p;
+
+ /* Set the stream to just pass the data from the device uninhibited */
+ p->sample = STREAM_NORMAL;
+
+ if (zt_register(&p->span, 0)) {
+ printk("wcusb: Unable to register span %s\n", p->span.name);
+ return -1;
+ }
+
+ return 0;
+}
+
+#ifdef LINUX26
+static int wc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+#else
+static void *wc_usb_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
+#endif
+{
+ struct wc_usb_pvt *p = NULL;
+ struct wc_usb_desc *d = (struct wc_usb_desc *)id->driver_info;
+#ifdef LINUX26
+ struct usb_device *dev = interface_to_usbdev(intf);
+#endif
+
+ int x;
+ for (x=0;x<WC_MAX_IFACES;x++) {
+ /* Find first dead or empty space */
+ p = ifaces[x];
+ if (!p) {
+ if (debug)
+ printk("Device slot %d is free\n", x);
+ break;
+ }
+ if (p->dead) {
+ if (debug)
+ printk("Device slot %d can be revived\n", x);
+ break;
+ }
+ if (debug)
+ printk("Device slot %d is still in use\n", x);
+ }
+
+ if (!(p = wc_detect_device(dev, p))) {
+ printk("wcusb: No wcusb devices found\n");
+#ifdef LINUX26
+ return -ENODEV;
+#else
+ return NULL;
+#endif
+ }
+
+#ifndef LINUX26
+ if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) < 0) {
+ printk("wcusb: set_configuration failed (ConfigValue 0x%x)\n", dev->config[0].bConfigurationValue);
+ return NULL;
+ }
+#endif
+
+ if (init_hardware(p)) {
+ printk("wcusb: Hardware intialization failed.\n");
+ goto cleanup;
+ }
+
+ if (prepare_transfer_urbs(p)) {
+ printk("wcusb: problem preparing the urbs for transfer\n");
+ goto cleanup;
+ }
+
+ if (d->flags & FLAG_FLIP_RELAYS) {
+ flip_relays(p, 1);
+ }
+
+ if (!p->dead && wc_set_zaptel(p)) {
+ printk("wcusb: Error in starting the zaptel stuff\n");
+ goto cleanup;
+ }
+
+ if (begin_transfer(p)) {
+ printk("wcusb: Something went wrong when starting the transfer\n");
+ goto cleanup;
+ }
+
+ if (p->dead)
+ printk("wcusb: Rekindling a %s (%s)\n", d->name, p->span.name);
+ else
+ printk("wcusb: Found a %s (%s)\n", d->name, p->span.name);
+
+ /* Reset deadness */
+ p->dead = 0;
+ /* Clear alarms */
+ p->span.alarms = 0;
+ p->variety = d->name;
+ zt_alarm_notify(&p->span);
+#ifdef LINUX26
+ usb_set_intfdata(intf, p);
+ return 0;
+#else
+ return p;
+#endif
+
+cleanup:
+ printk("cleanup\n");
+ if (p) {
+ if (p->pvt_data) {
+ kfree(p->pvt_data);
+ }
+ kfree(p);
+ }
+#ifdef LINUX26
+ return -ENODEV;
+#else
+ return NULL;
+#endif
+}
+
+#ifdef LINUX26
+static void wc_usb_disconnect(struct usb_interface *intf)
+#else
+static void wc_usb_disconnect(struct usb_device *dev, void *ptr)
+#endif
+{
+ /* Doesn't handle removal if we're in use right */
+#ifdef LINUX26
+ struct wc_usb_pvt *p = usb_get_intfdata(intf);
+#else
+ struct wc_usb_pvt *p = ptr;
+#endif
+ if (p) {
+ StopTransmit(p);
+ p->dev = NULL;
+ if (!p->usecount) {
+ zt_unregister(&p->span);
+ if (p->pvt_data)
+ kfree(p->pvt_data);
+ ifaces[p->pos] = NULL;
+ kfree(p);
+ } else {
+ /* Generate alarm and note that we're dead */
+ p->span.alarms = ZT_ALARM_RED;
+ zt_alarm_notify(&p->span);
+ p->dead = 1;
+ }
+ }
+ printk("wcusb: Removed a Wildcard device\n");
+#ifdef LINUX26
+ usb_set_intfdata(intf, NULL);
+#endif
+ return;
+}
+
+static struct usb_device_id wc_dev_ids[] = {
+ /* This needs to be a USB audio device, and it needs to be made by us and have the right device ID */
+ {
+ match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_DEVICE),
+ bInterfaceClass: USB_CLASS_AUDIO,
+ bInterfaceSubClass: 1,
+ idVendor: 0x06e6,
+ idProduct: 0x831c, /* Product ID / Chip configuration (you can't change this) */
+ driver_info: (unsigned long)&wcusb,
+ },
+ {
+ match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_DEVICE),
+ bInterfaceClass: USB_CLASS_AUDIO,
+ bInterfaceSubClass: 1,
+ idVendor: 0x06e6,
+ idProduct: 0x831e,
+ driver_info: (unsigned long)&wcusb2,
+ },
+ {
+ match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_DEVICE),
+ bInterfaceClass: USB_CLASS_AUDIO,
+ bInterfaceSubClass: 1,
+ idVendor: 0x06e6,
+ idProduct: 0xb210,
+ driver_info: (unsigned long)&wc_usb_phone,
+ },
+ { } /* Terminating Entry */
+};
+
+static struct usb_driver wc_usb_driver =
+{
+#ifdef LINUX26
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+ owner: THIS_MODULE,
+#endif
+#else
+ fops: NULL,
+ minor: 0,
+#endif
+ name: "wcusb",
+ probe: wc_usb_probe,
+ disconnect: wc_usb_disconnect,
+ id_table: wc_dev_ids,
+};
+
+static int __init wc_init (void)
+{
+ int res;
+ res = usb_register(&wc_usb_driver);
+ if (res)
+ return res;
+ printk("Wildcard USB FXS Interface driver registered\n");
+ return 0;
+}
+
+static void __exit wc_cleanup(void)
+{
+ usb_deregister(&wc_usb_driver);
+}
+
+MODULE_AUTHOR("Matthew Fredrickson <creslin@digium.com>");
+MODULE_DESCRIPTION("Wildcard USB FXS Interface driver");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+MODULE_DEVICE_TABLE(usb, wc_dev_ids);
+
+module_init(wc_init);
+module_exit(wc_cleanup);
diff --git a/drivers/dahdi/wcusb.h b/drivers/dahdi/wcusb.h
new file mode 100644
index 0000000..f22d0ac
--- /dev/null
+++ b/drivers/dahdi/wcusb.h
@@ -0,0 +1,142 @@
+
+#ifndef _WCUSB_H
+#define _WCUSB_H
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,19)
+#define USB2420
+#endif
+
+#include "zaptel.h"
+
+#define WC_MAX_IFACES 128
+
+#define POWERSAVE_TIME 4000 /* Powersaving timeout for devices with a proslic */
+
+/* Various registers and data ports on the tigerjet part */
+#define WCUSB_SPORT0 0x26
+#define WCUSB_SPORT1 0x27
+#define WCUSB_SPORT2 0x28
+#define WCUSB_SPORT_CTRL 0x29
+
+#define WC_AUX0 0x1
+#define WC_AUX1 0x2
+#define WC_AUX2 0x4
+#define WC_AUX3 0x8
+
+#define CONTROL_TIMEOUT_MS (500) /* msec */
+#define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ) / 1000)
+
+#define REQUEST_NORMAL 4
+
+#define FLAG_RUNNING (1 << 0)
+
+/* Important data structures and data types */
+
+
+/* States for the Proslic read state machine */
+typedef enum {
+ STATE_WCREAD_WRITEREG,
+ STATE_WCREAD_READRES,
+ STATE_WCWRITE_WRITEREG,
+ STATE_WCWRITE_WRITERES,
+} proslic_state_t;
+
+/* Used for current stream state */
+typedef enum {
+ STREAM_NORMAL, /* Sends normal (unmodified) audio data */
+ STREAM_DTMF, /* (For keypad device) Sends dtmf data */
+} stream_t;
+
+/* States for the Keypad state machine */
+typedef enum {
+ STATE_FOR_LOOP_1_OUT,
+ STATE_FOR_LOOP_2_IN,
+ STATE_FOR_LOOP_PROC_DATA,
+ STATE_FOR_LOOP_CLEAR_DIGIT,
+} keypad_state_t;
+
+/* Device types. For radical changes in a new device, use a switch based on the device type */
+typedef enum {
+ WC_KEYPAD, /* The tigerjet phone with the keypad. That was a bugger to implement */
+ WC_PROSLIC, /* For various devices with a proslic */
+} dev_type_t;
+
+struct wc_keypad_data {
+ keypad_state_t state; /* Current state in the keypad detect routine */
+#ifdef USB2420
+ struct urb urb; /* urb used for the keypad data transport ... can't remember whether it is used or not */
+#else
+ urb_t urb; /* urb used for the keypad data transport ... can't remember whether it is used or not */
+#endif
+ int running;
+ char data;
+ char data12;
+ char tmp;
+ int scanned_event;
+ int i;
+ int count;
+ /* DTMF tone generation stuff for zaptel */
+ struct zt_tone_state ts;
+ struct zt_tone *tone;
+};
+
+struct stinky_urb {
+#ifdef USB2420
+ struct urb urb;
+#ifndef LINUX26
+ struct iso_packet_descriptor isoframe[1];
+#endif
+#else
+ urb_t urb;
+ iso_packet_descriptor_t isoframe[1];
+#endif
+};
+
+struct wc_usb_pvt {
+ const char *variety;
+ struct usb_device *dev;
+ dev_type_t devclass;
+ int usecount;
+ int dead;
+ struct zt_span span;
+ struct zt_chan chan;
+ struct stinky_urb dataread[2];
+ struct stinky_urb datawrite[2];
+#ifdef USB2420
+ struct urb control;
+ struct usb_ctrlrequest dr;
+#else
+ urb_t control;
+ devrequest dr;
+#endif
+ proslic_state_t controlstate;
+ int urbcount;
+ int flags;
+ int timer;
+ int lowpowertimer;
+ int idletxhookstate;
+ int hookstate;
+ __u8 newtxhook;
+ __u8 txhook;
+ int pos;
+ unsigned char auxstatus;
+ unsigned char wcregindex;
+ unsigned char wcregbuf[4];
+ unsigned char wcregval;
+ short readchunk[ZT_MAX_CHUNKSIZE * 2];
+ short writechunk[ZT_MAX_CHUNKSIZE * 2];
+ stream_t sample;
+ void *pvt_data;
+};
+
+struct wc_usb_desc {
+ char *name;
+ int flags;
+};
+#endif
diff --git a/drivers/dahdi/xpp/.version b/drivers/dahdi/xpp/.version
new file mode 100644
index 0000000..e39d44b
--- /dev/null
+++ b/drivers/dahdi/xpp/.version
@@ -0,0 +1 @@
+trunk-r5744
diff --git a/drivers/dahdi/xpp/Changelog_xpp b/drivers/dahdi/xpp/Changelog_xpp
new file mode 100644
index 0000000..348bc1c
--- /dev/null
+++ b/drivers/dahdi/xpp/Changelog_xpp
@@ -0,0 +1,317 @@
+Tue, 13 May 2008 Oron Peled <oron@actcom.co.il> - xpp.r5744
+ * New firmware protocol version: 30
+ * New numbers for the device types: (e.g. in card_init* scripts)
+ - FXS: 1 (was: 3)
+ - FXO: 2 (was: 4)
+ - BRI: 3 (was: 6 for TE, 7 for NT)
+ - PRI: 4 (was: 9)
+ * Init scripts of FXS and FXO modules are now written in Perl as well
+ (be sure to have File::Basename, e.g: perl-modules in Debian).
+ * calibrate_slics merged into init_card_1_30 .
+ * Each of the init_card_* scripts now runs no more than once per card even
+ if this card represents several XPD's (e.g: quad PRI, BRI). This means
+ maximum of 4 script runs per Astribank.
+ * Zaptel registration now briefly flash all LED's (not just the green ones as
+ before).
+ * Module parameter print_dbg was renamed to debug for consistency with
+ the rest of zaptel.
+ * init_fxo_modes removed: content moved into init_card_2_30, verified
+ at build time.
+ * FXO: removed polling for power-denial. New firmware notifies us.
+ * Code tested with sparse. Most warnings were fixed.
+ * Set ZT_SIG_DACS for the bchans in the PRI and BRI modules to not get
+ ignored by ztscan.
+ * fpga_load: Handle null config_desc we get from some crazy USB controllers.
+ * genzaptelconf: Fix reporting of empty slots in list mode.
+ * xpp_blink can now blink the led of a single analog port.
+ * "slics" has been renamed "chipregs".
+ * Fixed a small typo in fpga_load(8).
+ * Fixed bashism in xpp_fxloader.
+
+Thu, 20 Mar 2008 Oron Peled <oron@actcom.co.il> - xpp.r5566
+ * Build:
+ - Zaptel >= 1.4.9 is migrating to storing kernel stuff in zaptel/kernel/*
+ - We conditionally use old/new directory scheme:
+ In xpp/Kbuild and xpp/utils/Makefile use ZAP_KERNEL variable, so it's
+ not confused with ZAPTEL_DIR (which appears in zaptel/Makefile as well).
+ - Fix compile warnings on 64 bit systems.
+ - Compile fixes for kernel-2.6.24
+ * UDEV:
+ - /etc/udev/rules.d/xpp.rules now uses XPP_INIT_DIR to find astribank_hook.
+ - astribank_hook: Modify to do nothing. Add some documentation.
+ * Autoconfiguration -- zapconf:
+ - Don't fail zapconf et.al. if no config file was found.
+ - Skip the 'IRQ Missing:' line in /proc/zaptel/nnn for wcte1xp(?).
+ - Add some newer Digium cards to our hardware inventory.
+ - Partially handle cases where the /proc/zaptel strings does not contain
+ info about E1/T1/J1 or NT/TE.
+ * Better SYNC:
+ - Finer tuning of PLL (New firmware).
+ - Change calculation algorithm of sync offset. It now copes better
+ with the variance in USB frame reception timing.
+ - Statistics:
+ . The view of results was moved from /proc/xpp/XBUS-*/summary to
+ a new /sys/bus/astribanks/devices/xbus-*/timing and enhanced.
+ . A new xpp_timing script shows all astribanks.
+ . A new write only /sys/bus/astribanks/devices/xbus-*/cls is
+ used to clear statistics. Eventually, clearing of XBUS related
+ statistics should be done here. One that was migrated is the
+ clearing of 'PCM [TR]X:' numbers currently appearing in
+ /proc/xpp/XBUS-*/summary (they should be moved too later).
+ - Shorten the strings representation sync_mode ("SYNC_MODE_AB" -> "AB")
+ adapted their use in printk and /proc so the text is clear.
+ - Added a command line parameter xpp.disable_pll_sync to stop all
+ adjustments command to AB (calculations still continue as usual).
+ * PRI:
+ - 4 port support
+ - set clocking master span via ztcfg, like other zaptel devices.
+ * FXO:
+ - Fix false hangups in some countries (voltage fluctuations).
+ - Some countries send caller-id before first ring.
+ Added code to handle caller-id PCM pass through according to
+ a new command line parameter (xpd_fxo.caller_id_style).
+ - No longer sends an event on zt_open. See #12160 .
+ * FXS: Re-enable dtmf_detection.
+ * Misc:
+ - Adapt to zaptel-1.4.8 and above ztscan: added fields returend by
+ new ZT_SPANSTAT_V2 ioctl()
+ - Document sysfs and waitfor_xpds.
+ - Miscelaneous optimizations and bugfixes.
+ - Remove deprecated pcm_tasklet parameter. The rx_tasklet parameter has
+ replaced it a long time ago.
+ - Add RX_CMD counter to /proc/xpp/XBUS-*/summary
+ - Unclutter some of the usb disconnect messages.
+ - xpp_usb: minor preformance improvements in receive.
+ Expose the number of pending receive URB's in /proc/xpp/XBUS-*/xpp_usb
+Thu Jan 10 2008 Oron Peled <oron.peled@xorcom.com> - xpp.r5254
+ * Improved polarity reversal hangups in FXO (r5194).
+ Fixed false detection of polarity reversals.
+ * Optimize xframe allocation, by not zeroing the whole
+ memory (in get_xframe()).
+ * Fixed erronous error message that appeared sometimes
+ from fpga_load during USB renumeration.
+ * Zaptel::Chans now provides battery() reporting for some FXO
+ channels (Astribank FXO and wcfxo).
+
+Tue Dec 25 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com> - xpp.r5179
+ * xpd_pri: Basically ready.
+ * PCM synchronization changes:
+ - Each Astribank unit ticks independently. Each with its own PLL.
+ - HOST synchronization is gone. Loading of xpp will no longer cause
+ useless 250 ticks per second if you have no Astribank.
+ - Synchronization from the zaptel sync master requires setting
+ ZAPTEL as sync source (xpp_sync ZAPTEL).
+ * rx_tasklet is now a parameter of the module xpp, rather than of xpp_usb.
+ * New FPGA firmware: 5128 (1151) / 5122 (1141, 1131):
+ - Fixes synchronization issues.
+ - PRI module: E1/T1 should now work.
+ * perl module and utilities:
+ - Modules no longer magically scan system on initialization.
+ - Scanning is by calling explicit methods.
+ - "Serial" has been renamed "Label". It is basically unique, but
+ should be modifieble.
+ - Some basic documentation of zaptel perl modules.
+ * Default sort order of zt_registration is back to SORT_CONNCTOR.
+ * zt_registration proc file now shows the number of span registered to
+ if registered. Try: grep . /proc/xpp/XBUS-*/XPD-*/zt_registration
+ * genzaptelconf: Allow using a custom command instead of
+ /etc/init.d/asterisk to start/stop asterisk.
+ * Fixed the typo "Slagish".
+
+Wed Nov 14 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com> - xpp.r5010
+ * Fix a deadlock spotted on some SMP installations.
+ * increase FXS ring detect debounce interval.
+ * Improve (reduce) signal attenuation on FXO ports.
+ * zaptel-perl: further fixes to handling of empty slots.
+
+Wed Oct 3 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com> - xpp.r4900
+ * Zaptel/Hardware perl modules:
+ - Use sysfs directly. Don't rely on lspci/lsusb.
+ - Each device has a description and driver name.
+ - Zaptel::Hardware::drivers() to show the list of required drivers
+ for this system (see zaptel_drivers).
+ - zaptel_hardware shows a description and a (suggested?) driver.
+ * zt_registration sorts by Serial first and only then by connector.
+ * USB_FW.hex replaces all the USB_11x0.hex .
+ - Separate USB interface for the management processor.
+ - Hence fpga_load can now work even with drivers loaded.
+ * Fix firmware upgrading.
+ * Fix manual firmware loading while auto-loading.
+ * Fix opermode parameter for FXO initialization (broken in r4648).
+
+Wed Oct 3 2007 Oron Peled <oron@actcom.co.il> - xpp.r4786
+ * New firmware protocol version: 2.9 .
+ * fpga_load: initial clean-ups before interface split.
+ * genzaptelconf: Don't leave an empty directory behind (4784)
+ * Increase xpp poll_timeout to 1000ms - useful for CentOS 4 (r4781).
+ * Fix initialization anoyance: if AB don't answer to polls, don't
+ waitfor_xpds, and show no waiting XPDs (r4725).
+ * Disable dtmf_detection by default once again (r4712).
+ * Don't check twice for asterisk to stop. The second test was done
+ while Asterisk was still stopping (r4708).
+ * Support building the kernel with M= instead of with SUBDIRS= , as
+ used in some newer build systems (r4677).
+
+Tue Sep 11 2007 Oron Peled <oron@actcom.co.il> - xpp.r4648
+ * New firmware protocol version: 2.8 .
+ * Cleanup INFO() messages during module loading.
+
+ * USB: Receive queue with TASKLETS [r4600]. Controlled by rx_tasklet
+ parameter to xpp_usb module (can be changed in runtime).
+ * The pcm_tasklet parameter in xpp module is deprecated:
+ - Does not actually do anything.
+ - If set during module loading, shows an ERR() message.
+ - Also appears in /proc/xpp/sync
+
+ * FXS: Hardware DTMF detection by default, can be disabled
+ by setting dtmf_detection=0 parameter to xpd_fxs.
+ PCM is muted when DTMF key is pressed.
+
+ * zapconf:
+ - Can now generate users.conf compatible with asterisk-gui.
+ - Optional command-line arguments denoting which files to generate.
+ Possible values are 'zaptel', 'zapata' and 'users'.
+ - Defaults to creating zaptel and zapata.
+
+ * Update to zaptel-1.4.5.1, zaptel-1.2.20.1
+ * Fix building on kernel 2.6.23rc1, from Axel Thimm.
+ * New firmware to fix FXS leds irregularities.
+ * Less noise at build time - don't echo version, test compile ony once.
+ * zapconf can generate users.conf snippets.
+
+Thu Aug 16 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com> - xpp.r4515
+ * Don't use Astribanks connected to USB1 interfaces
+ Unless the user set the option usb1=1 for xpp_usb (r4504).
+ * README.Astribank can now be generated from the makefile (r4503).
+ * Demote the messages about PCM in non-PCM from notice to debug (r4501).
+ * Fix sample BRI zapata.conf: NT instead of TE (r4498).
+ * Disable FXS hardware DTMF detection by default (r4492).
+ * Extra Zaptel PCI IDs (from Philipp Kempgen) (r4466).
+
+Thu Aug 2 2007 Oron Peled <oron@actcom.co.il> - xpp.r4464
+ * Jump to zaptel-1.2.19 and zaptel-1.4.4 (with/without bristuff)
+ * BRI improvement: an 'nt_keepalive' parameter to xpd_bri forces
+ a BRI_NT to retry a connection indefinitely (this is our default).
+ When false it revert to the behaviour in changeset:4415 ("Bezeq like")
+ * Improvement in DBG macros. The print_dbg parameter is now set of
+ flags to debug. They are defined in zap_debug.h
+ * PRI configuration improvements (r4462):
+ - Hardcoded default (in init_card_9_26) is TE.
+ - The variable XPP_PRI_SETUP (in /etc/default/zaptel) may config
+ all PRI ports or some of them as we wish. Full docs are in
+ the utils/example_default_zaptel.
+ * PRI D-channel indication: Similar to BRI (r4464).
+
+Thu Jul 30 2007 Oron Peled <oron@actcom.co.il> - xpp.r4415
+ * Show Astribank 6+2 as 6/2 channels and not 8/8 channels.
+ - Added as a "subtype" to the device type (r4391).
+ * Fixed a panic in BRI span shutdown method (r4393).
+ * Changes to debug macros.
+ * Add proper sysfs support (r4406)
+ - A bus on whuch all of the Astribanks reside.
+ - Replaces useless sysfs code that existed in the module.
+ - Currently used to set the sync source automatically at device
+ adition / removal.
+ * BRI: We do need the T1 timer in NT. If it gets into G2 state (rr4407).
+
+Thu Jul 12 2007 Oron Peled <oron@actcom.co.il> - xpp.r4372
+ * Update to zaptel-1.2.18 and zaptel-1.4.3 (r4308 onward)
+ * Fix a critical race with zaptel synchronization (r4362)
+ * Added a /proc/xpp/cmds for statistics about command timing (r4360)
+ * Fix a digit mapping bug with hardware dtmf detection (r4357)
+ * In xpp/utils/Makefile add perl syntax checks to our scripts (r4337)
+ * Better USB data error checking (r4336)
+ * udev rules (xpp.rules) avoid false calls from wrong nodes (r4331)
+ * Improve hardware detection and reporting in lszaptel,
+ zaptel_hardware. zapconf is basically functional.
+ * Leds are blinked synchronously on all Astribanks now (r4262)
+ * Fix a BRI bug if OPTIMIZE_CHANMUTE was compiled into zaptel (r4258)
+ (This feature was not yet accepted into official zaptel)
+ * Removed compile warning about HZ != 1000 (r4218)
+ * Firmware updates.
+ * xpd_pri: the PRI module
+ * fpga_load now supports USB pathes without zeros (r4211)
+ * XPD numbers have changed to '<Unit><Subunit>' (r4196)
+ * Proper support for ZT_VMWI ioctl, if used in zaptel (r4092)
+ * Fix FXO power denial detection (r4054)
+ * FXO could accidentally go off-hook with some compilers (r4048)
+
+Tue May 1 2007 Oron Peled <oron@actcom.co.il> - xpp.r3898
+ * Tested with zaptel-1.2.17.1
+ * Add D-Channel TX, RX and BAD frames count in /proc/xpp/XBUS-*/XPD-*/bri_info
+ * Adjust output of xpp_sync script. Pad for 8 port BRI.
+ * Added a debugging module parport_debug (not compiled by default).
+ * Added an optional patch to zaptel:
+ - compiles only if ZAPTEL_SYNC_TICK is defined
+ - Allow interested driver to register for "sync" notification.
+ - Does not affect drivers that do not use this feature.
+ * Added external synchronization feature:
+ - Only if ZAPTEL_SYNC_TICK feature is compiled in
+ - Than XPP may be synchronized by another card (e.g: an Astribank
+ with FXS can be synchronized by a Digium PRI card).
+ - May be enabled/disabled in runtime via the 'sync_tick_active' module
+ parameter to the xpp.ko module.
+ * Fixed a potential bug in D-Channel hexdump printing.
+ * New visual indications in BRI leds:
+ - Constant ON RED/GREEN: Shows the port type -- NT/TE.
+ - Very fast "double blink": Layer1 work, no D-Channel yet.
+ - Steady blinking (1/2 sec): D-Channel trafic detected.
+ * xpp_fxloader moved to /usr/share/zaptel .
+ * adj_clock removed: never really used.
+
+Thu, 19 Apr 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com> - xpp.r3814
+ * No need for extra patch beyond bristuff for Astribank BRI.
+ * Protocol no. 2.6: syncing improvements.
+ * Default poll intervals changed: 500 in BRI and FXO.
+ * Allow changing FXS polls interval at run time.
+ * BRI initalization fixed on SUSE (path to logger).
+ * When using the SUSE zaptel rpm package, set modules_var=ZAPTEL_MODULES in
+ /etc/sysconfig/zaptel .
+ * zt_registration not verbose by default.
+ * xpp_sync warns if FXO is sync slave.
+ * Extra PCM metrics data in /proc/xpp/XBUS-NN/summary .
+ * Extra USB metrics data in /proc/xpp/XBUS-NN/usb_info .
+
+Wed, 11 Apr 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com> - xpp.r3768
+ * Removed "go away" notice and solved sync of a restarted device.
+ * Resetting firmware: rmmod xpp_usb; /etc/hotplug/usb/xpp_fxloader reset
+ * Perl modules use strict.
+ * genzaptelconf -F will not generate zapata configuration for NT spans.
+ * genzaptelconf uses perl utilities to start.
+ * Initial support for 2nd XHFC (BRI) chip.
+
+Sun, 1 Apr 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com> - xpp.r3712
+ * New protocol version (2.5).
+ * Luckily firmware unloading now works.
+ * Solves "multiple ticks" bug. No need for pcm_tasklets workaround.
+ * genzaptelconf -z will generate zapscan.conf for the asterisk-gui.
+ * Fixed hardware detection for the BRI.
+
+Wed, 14 Mar 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com> - xpp.r3608
+ * Initial verssion of firmware unloading.
+ * PCM bugfixes.
+ * Defaults of kernel parameters are now part of parameter description.
+ * Removed zaptel sync code for now.
+ * genzaptelconf will detect vzaphfc.
+ * genzaptelconf defaults to ptmp for BRI.
+ * Documentation updates.
+
+Mon, 26 Feb 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com> - xpp.r3517
+ * genzaptelconf now uses ls for FXS lines by default .
+ * World-readable kernel parameters.
+
+Thu, 22 Feb 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com> - xpp.r3440
+ * /proc/xpp/sync: 'm 0' is, while depracated, can still be used.
+ * New firmware with PCM improvements.
+ * Improvements to the xpp helper scripts.
+ * Bug fixes.
+ * zaptel/perl is now installed by xpp/utils/Makefile.
+
+Wed, 14 Feb 2007 Tzafrir Cohen <tzafrir.cohen@xorcom.com> - xpp.r3365
+ * Kewlstart support on the FXS ports (already existed on the FXO ports).
+ * The format of /proc/xpp/sync has changed (still self-documented).
+ * Better notification of FXS lines that were off-hook on registration time.
+ * Parallel polling of Astribanks (faster startup when there are multiple
+ devices)
+ * zconf: scripts and perl modules to automate the work with Zaptel and the
+ Astribank. Current scripts: zt_registration, xpp_sync.
diff --git a/drivers/dahdi/xpp/Kbuild b/drivers/dahdi/xpp/Kbuild
new file mode 100644
index 0000000..f7f180b
--- /dev/null
+++ b/drivers/dahdi/xpp/Kbuild
@@ -0,0 +1,58 @@
+ifdef SUBDIRS
+ ZAP_KERNEL = $(SUBDIRS)
+else
+ ZAP_KERNEL = $(M)
+endif
+
+EXTRA_CFLAGS = $(XPP_LOCAL_CFLAGS) \
+ -I$(ZAP_KERNEL) \
+ -DDEBUG \
+ -DPOLL_DIGITAL_INPUTS \
+ -DWITH_ECHO_SUPPRESSION \
+ -DDEBUG_PCMTX \
+ -DPROTOCOL_DEBUG \
+ -g
+ #
+
+ifneq (,$(shell grep -w echo_can_state_t $(ZAP_KERNEL)/zaptel.h))
+EXTRA_CFLAGS += -DZAPTEL_EC_TYPEDEF
+endif
+
+obj-m += xpp.o xpd_fxs.o xpd_fxo.o xpd_pri.o
+
+HAS_BRISTUFF := $(shell grep '^[[:space:]]*\#[[:space:]]*define[[:space:]]\+CONFIG_ZAPATA_BRI_DCHANS\>' $(ZAP_KERNEL)/zconfig.h)
+
+# Build only supported modules
+ifneq (,$(filter y m,$(CONFIG_USB)))
+obj-m += xpp_usb.o
+endif
+ifneq (,$(HAS_BRISTUFF))
+obj-m += xpd_bri.o
+endif
+
+xpp-y += xbus-core.o xbus-sysfs.o xbus-pcm.o xframe_queue.o xpp_zap.o xproto.o card_global.o zap_debug.o
+xpd_fxs-y += card_fxs.o
+xpd_fxo-y += card_fxo.o
+xpd_bri-y += card_bri.o
+xpd_pri-y += card_pri.o
+
+ifeq (y,$(PARPORT_DEBUG))
+EXTRA_CFLAGS += -DDEBUG_SYNC_PARPORT
+obj-m += parport_debug.o
+endif
+
+# Handle versioning
+XPP_VERSION_STR ?= $(shell if [ -r $(obj)/.version ]; then echo "\"`cat $(obj)/.version`\""; else echo '"Unknown"'; fi)
+clean-files := xpp_version.h
+
+$(obj)/card_fxs.o $(obj)/card_fxo.o $(obj)/card_bri.o $(obj)/card_pri.o $(obj)/xpp_usb.o $(obj)/xpp.o: $(obj)/xpp_version.h
+
+$(obj)/xpp_version.h: FORCE
+ $(Q)echo '#define XPP_VERSION $(XPP_VERSION_STR)' > $@.tmp
+ $(Q)if cmp -s $@.tmp $@ ; then echo; else \
+ mv $@.tmp $@ ; \
+ fi
+ $(Q)rm -f $@.tmp
+
+.PHONY: FORCE
+FORCE:
diff --git a/drivers/dahdi/xpp/Makefile b/drivers/dahdi/xpp/Makefile
new file mode 100644
index 0000000..00fc5ee
--- /dev/null
+++ b/drivers/dahdi/xpp/Makefile
@@ -0,0 +1,7 @@
+# We only get here on kernels 2.6.0-2.6.9 .
+# For newer kernels, Kbuild will be included directly by the kernel
+# build system.
+-include $(src)/Kbuild
+
+ctags:
+ ctags *.[ch]
diff --git a/drivers/dahdi/xpp/README.Astribank b/drivers/dahdi/xpp/README.Astribank
new file mode 100644
index 0000000..af43eb1
--- /dev/null
+++ b/drivers/dahdi/xpp/README.Astribank
@@ -0,0 +1,1374 @@
+Xorcom Astribank Documentation
+==============================
+Xorcom Team <support@xorcom.com>
+$Revision$, $Date$
+
+This file documents the Zaptel drivers for the Xorcom Channel Bank.
+The drivers reside in a separate subdirectory, kernel/xpp/ .
+
+It is generally a more technical document than the
+http://www.xorcom.com/documentation/manuals/[Astribank User Manual]
+
+An HTML version of the latest version of this document could be found at
+http://zaptel.tzafrir.org.il/README.Astribank.html[]
+
+Building and Installation
+-------------------------
+Building and installation is basically like the normal procedure of
+installing Zaptel with some additions.
+
+Building drivers
+~~~~~~~~~~~~~~~~
+Apart from the standard Zaptel build requirements, you also need libusb
+development headers to build the fpga_load firmware loader. This is
+typically the package libusb-dev on Debian (and derivatives like Ubuntu)
+or libusb-devel on RedHat (and derivatives like CentOS/Trixbox).
+
+On Zaptel 1.2 you will need to run the following extra step to build the
+user space utilities, apart from the standard 'make; make install':
+
+ make -C xpp/utils install
+
+Though this should be done automatically on Zaptel >= 1.4.1 .
+
+
+Sample Configurations
+---------------------
+We generally recommend to generate the configuration by using utility
+genzaptelconf or zapconf which are included with Zaptel. Nevertheless,
+the following can serve as reference configurations for a system where
+Astribank devices are used.
+
+
+Zaptel Init Configuration File
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The zaptel init.d script, genzaptelconf and the XPD init scripts uses the
+parameters located in file /etc/default/zaptel (on Debian) or
+/etc/sysconfig/zaptel (on RedHats). There is a number of useful parameters
+that may be defined there:
+
+-----------------------------------------------------------
+# Lines beginning with '#' are considered comments and ignored.
+
+# A two-letter country code. genzaptelconf uses it to better guess
+# the configuration it generates. E.g: the signalling of E1 spans, and
+# a few other country-specific settings.
+#lc_country=us
+
+# See genzaptelconf(8) and the script itself for a longer list of
+# variables.
+
+# Equivalent to the parameter opermode to the module wctdm: country-specific
+# settings to the FXO lines. For a complete list of possible values, see
+# /usr/share/zaptel/init_fxo_mode .
+#opermode=FRANCE
+
+# xpp_sync runs with the value of 'XPP_SYNC' as its parameter to set the
+# synchronization source. The default is 'auto' that selects the best
+# Astribank. 'ZAPTEL' gets synchronization from the Zaptel sync master
+# span. Or a specific XBUS number.
+#XPP_SYNC=ZAPTEL
+
+# Disables hot-plug firmware loading
+#XPP_HOTPLUG_DISABLED=yes
+#
+
+# Disables udev hook called when an Astribank is added and ready
+# or removed.
+#ASTRIBANK_HOOK_DISABLED=yes
+
+# Setup for the Astribank PRI module:
+# All the ports in the unit connected to the USB port 0000:00:1d.7-1
+# will be NT and E1. Ports no. 1 and 3 of all the other Astribanks will
+# be NT and E1 (and thus ports 0 and 2 will be TE and E1).
+#XPP_PRI_SETUP='
+# CONNECTOR/usb-0000:00:1d.7-1/XPD-01=NT,E1
+# NUM/*/XPD-0[13]=NT,E1
+# '
+-----------------------------------------------------------
+
+/etc/zaptel.conf
+~~~~~~~~~~~~~~~~
+
+Astribank 8
+^^^^^^^^^^^
+ fxoks=1-14
+
+Astribank 6FXS/2FXO
+^^^^^^^^^^^^^^^^^^^
+ fxoks=1-12
+ fxsks=13-14
+
+Astribank 16: 8FXS/8FXO
+^^^^^^^^^^^^^^^^^^^^^^^
+ fxoks=1-14
+ fxsks=15-22
+
+Astribank 4 BRI
+^^^^^^^^^^^^^^^
+ # Assumed ports settings:
+ # Ports 1,3: TE
+ # Ports 2,4: NT
+ span=1,1,1,ccs,ami
+ span=2,0,1,ccs,ami
+ span=3,2,1,ccs,ami
+ span=4,0,1,ccs,ami
+ bchan=1-2,4-5,7-8,10-11
+ dchan=3,6,9,12
+
+Astribank 4 PRI E1
+^^^^^^^^^^^^^^^^^^
+ # Assumed ports settings:
+ # Ports 1,3: TE (CPE)
+ # Ports 2,4: NT (Net)
+ span=1,1,1,ccs,hdb3,crc4
+ span=2,0,1,ccs,hdb3,crc4
+ span=3,2,1,ccs,hdb3,crc4
+ span=4,0,1,ccs,hdb3,crc4
+ bchan=1-15,17-30,31-45,47-60,61-75,77-90,91-105,107-120
+ dchan=16,46,76,106
+
+Astribank 4 PRI T1
+^^^^^^^^^^^^^^^^^^
+ # Assumed ports settings:
+ # Ports 1,3: TE (CPE)
+ # Ports 2,4: NT (Net)
+ span=1,1,1,esf,b8zs
+ span=2,0,1,esf,b8zs
+ span=3,2,1,esf,b8zs
+ span=4,0,1,esf,b8zs
+ bchan=1-23,25-47,49-71,73-95
+ dchan=24,48,72,96
+
+
+/etc/asterisk/zapata.conf
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Astribank 8
+^^^^^^^^^^^
+ [channels]
+ signalling=fxo_ks
+ ; The real analog ports:
+ context=from-internal
+ echocancel=yes
+ ; echocancelwhenbriged=yes
+ ; echotraining=no
+ channel => 1-8
+
+ ; output ports:
+ context=astbank-output
+ channel => 9-10
+ ; input ports:
+ immediate=yes
+ context=astbank-input
+ channel => 11-14
+ immediate=no
+
+Astribank 6FXS/2FXO
+^^^^^^^^^^^^^^^^^^^
+ [channels]
+ signalling=fxo_ks
+ ; The real analog ports:
+ context=from-internal
+ echocancel=yes
+ ; echocancelwhenbriged=yes
+ ; echotraining=no
+ channel => 1-6
+
+ ; output ports:
+ context=astbank-output
+ channel => 7-8
+ ; input ports:
+ immediate=yes
+ context=astbank-input
+ channel => 9-12
+ immediate=no
+
+ ; FXO ports
+ signalling=fxs_ks
+ context=from-pstn
+ callerid=asreceived
+ channel => 13-14
+
+Astribank 16: 8FXS/8FXO
+^^^^^^^^^^^^^^^^^^^^^^^
+ [channels]
+ signalling=fxo_ks
+ ; The real analog ports:
+ context=from-internal
+ echocancel=yes
+ ; echocancelwhenbriged=yes
+ ; echotraining=no
+ channel => 1-8
+
+ ; output ports:
+ context=astbank-output
+ channel => 9-10
+ ; input ports:
+ immediate=yes
+ context=astbank-input
+ channel => 11-14
+ immediate=no
+
+ ; FXO ports
+ signalling=fxs_ks
+ context=from-pstn
+ callerid=asreceived
+ channel => 15-22
+
+Astribank 4 BRI
+^^^^^^^^^^^^^^^
+ ; Assumed ports settings:
+ ; Ports 1,3: TE
+ ; Ports 2,4: NT
+ [channels]
+ switchtype = euroisdn
+ callerid = asreceived
+
+ ; TE ports:
+ signalling = bri_cpe_ptmp
+ ;signalling = bri_cpe
+ context = from-pstn
+ group = 1,11
+ channel => 1,2
+
+ group = 1,13
+ channel => 7,8
+
+ ; NT ports:
+ signalling = bri_net_ptmp
+ ;signalling = bri_net
+ context = from-internal
+ group = 2,12
+ channel => 4,5
+
+ group = 2,14
+ channel => 10,11
+
+Astribank 4 PRI E1
+^^^^^^^^^^^^^^^^^^
+ ; Assumed ports settings:
+ ; Ports 1,3: TE
+ ; Ports 2,4: NT
+ [channels]
+ switchtype = euroisdn
+ callerid = asreceived
+
+ ; TE ports:
+ signalling = pri_cpe
+ context = from-pstn
+ group = 1,11
+ channel => 1-15,17-30
+
+ group = 1,13
+ channel => 61-75,77-90
+
+ ; NT ports:
+ signalling = pri_net
+ ;signalling = pri_net
+ context = from-internal
+ group = 2,12
+ channel => 31-45,47-60
+
+ group = 2,14
+ channel => 91-105,107-120
+
+Astribank 4 PRI T1
+^^^^^^^^^^^^^^^^^^
+ ; Assumed ports settings:
+ ; Ports 1,3: TE
+ ; Ports 2,4: NT
+ [channels]
+ switchtype = national
+ callerid = asreceived
+
+ ; TE ports:
+ signalling = pri_cpe
+ context = from-pstn
+ group = 1,11
+ channel => 1-23
+
+ group = 1,13
+ channel => 49-71
+
+ ; NT ports:
+ signalling = pri_cpe
+ ;signalling = pri_net
+ context = from-internal
+ group = 2,12
+ channel => 25-47
+
+ group = 2,14
+ channel => 73-95
+
+
+/etc/asterisk/extensions.conf
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Sample dialplan (extensions.conf) for all the above:
+
+-----------------------------------------------------------
+[phones-zap]
+; 6001 will dial to channel 1, 6020, to Zaptel channel 20, etc.
+exten => _6XXX,1,Dial(ZAP/${EXTEN:1})
+; Useful for debugging trunks. Will potentially allow users to
+; bypass context limitations.
+;exten => _6XXX.,1,Dial(ZAP/${EXTEN:1:3}/${EXTEN:4})
+
+[trunk]
+; A number that begins with 9: dial it through a trunk
+; (we put FXO channels and TE channels in group 0).
+; The leading 9 is stripped.
+exten => _9.,1,Dial(Zap/g0/${EXTEN:1})
+; dialing a number that begins with 83 will dial it through
+; span 3, and so forth. The two leading digits are stripped.
+; (Each digital span is also added to group 10+span number).
+exten => _8X.,1,Dial(Zap/g1${EXTEN:1:1}/${EXTEN:2})
+
+[from-internal]
+; The context of FXS ports: analog phones.
+; They are allowed to dial to all other phones
+include => phones-zap
+; They are also allowed to call through the trunk:
+include => trunk
+; some simple tests:
+include => astbank-test
+
+[from-pstn]
+; Calls from the PSTN enter here. Redirect calls to an IVR
+; or a default extension in the s context here. In this case we
+; redirect calls to Zaptel channel 1:
+exten => s,1,Dial(Zap/1)
+
+; Alternatively, the following will redirect you to the demo IVR
+; from the sample extensions.conf of Asterisk:
+include => demo
+
+; An extra context with some simple tests
+[astbank-test]
+; 200: echo test
+exten => 200,1,Answer
+exten => 200,n,Wait(1)
+exten => 200,n,Echo()
+exten => 200,n,Hangup
+
+; 203: say extension number. Will only work if caller ID
+; is properly set in zapata.conf / zapata-channels.conf
+exten => 203,1,Answer
+exten => 203,n,Wait(1)
+exten => 203,n,SayNumber(${CALLERID(num)})
+exten => 203,n,Hangup
+
+[astbank-input]
+exten => s,1,Set(ZAP_CHAN=${CUT(CHANNEL,-,1)})
+exten => s,n,Set(ZAP_CHAN=${CUT(ZAP_CHAN,/,2)})
+; 11 is the number of the first input port. At least in the sample
+; configuration below.
+;exten => s,n,Set(INPUT_NUM=$[${ZAP_CHAN}-11)])
+; The sample below just logs the signal.
+exten => s,n,NoOp(Got signal from Zaptel Channel ${ZAP_CHAN})
+; Alternatively:
+;exten => s,n,System(run something)
+
+; No. We did not forget the context astbank-outputs. Output
+; ports only get calls from the PBX. Thus they don't need a context
+; of their own. Sending them to a context of their on makes
+; 'zap show channels' in the CLI provide useful display, though.
+-----------------------------------------------------------
+
+
+
+
+Troubleshooting
+---------------
+The following commands provide useful information for debugging:
+
+lsusb Test
+~~~~~~~~~~
+Check USB level status. You can use one of the following utilities for it:
+
+ zaptel_hardware -v
+ or
+ lsusb | grep e4e4
+
+- Look for the USB Product ID (the second number after e4e4).
+- If you see *11x2* (e.g: 1152)- the FPGA firmware has been loaded.
+ Move on.
+ zaptel_hardware will also show you some more details if the driver
+ is loaded while the lsusb will just list the device.
+- If it shows something as product ID *11x0* - the USB firmware is not
+ loaded. Maybe you need to run fxload. Or maybe just unplug and plug again
+ the device. Also make sure that you have fxload installed.
+- If lsusb shows the Product ID as *11x1* - only the USB firmware is loaded
+ and not the FPGA firmware is loaded. If this is still the case after
+ a while - either the firmware loading has failed or you don't have
+ fpga_load. Make sure you have libusb-dev(el) installed when
+ building Zaptel. After you have installed it, you may need to re-run
+ ./configure .
+- It should list all of your Astribank devices. If it doesn't (for
+ more than period of time needed for the initial firmware
+ loading) - Check that the Astribank is connected indeed.
+
+
+Zaptel Registration
+~~~~~~~~~~~~~~~~~~~
+Check if the Astribank spans are registered in Zaptel
+
+ zt_registration
+
+- This should give useful results after the drivers have identified
+ and your devices are initialized.
+- It should list all Astribank XPDs. For each of them it should write
+ "on" or "off". If the registration status is "off", then it means that
+ the span has not been registered in Zaptel and therefore can not be used
+ yet.
+- Registration is normally done as part of `/etc/init.d/zaptel start`.
+ If you want to register the spans manually, then run command:
+ `zt_registration on` .
+- Disabling of the automatic Astribank spans registration give you full
+ control on the order of Zaptel spans. See the module parameter
+ **zap_autoreg** for the further details.
+
+
+Zaptel Level Information
+~~~~~~~~~~~~~~~~~~~~~~~~
+You can get some information regarding Zaptel channels by running one of the
+following commands:
+
+ lszaptel
+ or
+ cat /proc/zaptel/*
+
+- Those two are almost the same. The lszaptel produced more correctly sorted
+ output if you have more than 10 spans, and also make the output listing
+ looks a little bit nicer.
+- You can see if your Zaptel spans and channels were loaded, if
+ they were configured by ztcfg and if they are in use (typically by
+ Asterisk).
+ For example:
+ Not configured Astribank FXS channel will be displayed as:
+
+ 42 FXS
+
+- When a channel has been configured with *ztcfg* (that applies
+ /etc/zaptel.conf), you will see an extra column for the signalling
+ type of the channel. The same channel after it has been configured:
+
+ 42 FXS FXOKS
+
+- If a program (which is typically Asterisk) uses it, you'll see:
+
+ 42 FXS FXOKS (In use)
+
+
+
+Asterisk Level Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+ asterisk -rx 'zap show channels'
+
+- If you get error "Unable to connect to remote asterisk" then it
+ means that the Asterisk is not running. It is possible that Asterisk
+ has failed to start due to misconfigured zapata.conf or whatever reason.
+ Check /var/log/asterisk/messages or /var/log/asterisk/full .
+- If you get the error that "there is no such command" then it means that
+ chan_zap.so is not loaded. There are two reasons for such problem:
+ * chan_zap.so is not even built. Check if the file exists:
+
+ ls -l /usr/lib/asterisk/modules/chan_zap.so
+
+ * the chan_zap.so file exists but it is not loaded. Try to load it manually:
+
+ asterisk -rx 'load module chan_zap.so'
+
+- You see "pseudo" channel only. It means that you have not configured any
+ channels. If you have configured channels in zapata.conf, you may
+ need either to restart the Asterisk or unload/load chan_zap.so manually.
+ You can use the following Asterisk CLI commands for it: `unload chan_zap.so`
+ and `load chan_zap.so`
+
+
+Known Issues
+~~~~~~~~~~~~
+Empty /proc dir
+^^^^^^^^^^^^^^^
+.Symptoms:
+- Error message:
+
+ "ERR-xpd_fxo: XBUS-00/XPD-00: Failed initializing registers (-22)"
+
+- Likewise for all XPDs.
+- The directory /proc/xpp exists but is empty (not even the files
+ 'xbuses' and 'sync').
+
+.Cause:
+The driver failed to recreate the procfs directory /proc/xpp and hence
+everything under it. This is because it has already existed. And it
+existed because a process still uses it. This is typically because you
+have a shell whose working directory is /proc/xpp or somewhere under
+it:
+
+ # lsof /proc/xpp
+ COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
+ bash 2741 root cwd DIR 0,3 0 4026532684 /proc/xpp
+
+.Fix:
+Move that process from that directory, or close the file it uses from
+under /proc/xpp and reload the zaptel / xpp drivers.
+
+
+Bad Firmware Version
+^^^^^^^^^^^^^^^^^^^^
+.Symptoms:
+- An Astribank finishes initialization quickly, the /proc/XBUS-nn
+ directory has no XPD-mm subdirectories.
+- Error in the kernel logs about:
+
+ NOTICE-xpp: XBUS-00: XPD at 00: type=6.0 has bad firmware revision 2.6
+
+.Cause:
+This is normally caused by an Astribank with an older firmware connected
+to a
+
+The protocol version supported by the firmware will typically be the same
+one as in the device initialization scripts installed to
+/usr/share/zaptel . Hence if this version installed
+`/usr/share/zaptel/init_card_3_29` it will probably include firmware of
+protocol version 29.
+
+.Fix:
+Reset the firmware:
+
+ /usr/share/zaptel/xpp_fxloader reset
+
+Or disconnect the Astribank from the power and reocnnect. On some older
+versions of the USB firmware resetting the firmware (or any operation of
+fpga_load) would fail if the driver is loaded. Hence you would need to
+run `rmmod xpp_usb` . In the end, reload the drivers.
+
+
+USB Errors at Shutdown
+^^^^^^^^^^^^^^^^^^^^^^
+.Symptoms:
+You see USB-related errors similar to the following whenever you shut
+down the drivers of the Astribank or disconnect its drivers:
+
+ ERR-xpp_usb: XBUS-00: Failed to submit a receive urb
+
+.Cause:
+This is a normal part of the shutdown of the USB connection.
+
+.Fix:
+Ignore them. Unless the USB should not have disconnected at that time.
+
+
+BRI Layer 1 Down
+^^^^^^^^^^^^^^^^
+.Symptoms:
+With the BRI module only, and not in the middle of an active call, you
+notice that suddenly the line goes down. The LED of the port stops
+blinking, layer1 not listed as "active" in the bri_info file in
+/proc/xpp, and the span is in RED alarm in Zaptel.
+
+You may also see an error message such as:
+
+ NOTICE-xpd_bri: XBUS-00/XPD-02: D-Chan RX Bad checksum: [2A:01=FC] (252)
+
+from the exact time of the disconnecting.
+
+.Cause:
+This is expected with most european BRI PtMP providers. If they support
+PtMP, they are normally also expected to support ISDN phones, that get
+the power from the provider. And thus they shut down the line whenever
+there's no active call.
+
+Sometimes the line is shut down in the middle of a layer 2 message. In
+the BRI driver the HDLC decoding/encoding is done in the card. In that
+case we may get the above error.
+
+.Fix:
+Normaly this is not a problem. The driver will re-establish a connection
+once a new call needs to be made.
+
+
+Both default and sysconfig Exist
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.Symptoms:
+The firmware fails to load. Manually running xpp_fxloader gives:
+
+ Both '/etc/default/zaptel' and '/etc/sysconfig/zaptel' exist
+
+Alternatively: an initialization script fails and gives the error
+
+ An '/etc/default/zaptel' collides with 'etc/sysconfig/zaptel'
+
+.Cause:
+/etc/default/<service name> is the place used in Debian-based
+systems for initialization scripts. /etc/sysconfig/<service name> is
+used in Redhat and similar for the same purpose. For historical reasons
+many of our programs read configuration from there: either from
+/etc/default/zaptel or from /etc/sysconfig/zaptel .
+
+The problem is what to do if both of those exist. Selecting an arbitrary
+one can lead to unexpected results. Likewise sourcing both of them.
+Therefore we prefer to fail in a noisy and expected way. In the future
+we will probably me to reading configuration from a file under /etc/zaptel .
+
+.Fix:
+Remove one of those two. There should be no reason to have both on the
+same system.
+
+
+Astribank not initialized: Premature packet end
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.Symptoms:
+After upgrading to Zaptel 1.4.12 / 1.2.25 the initialization of the
+Astribank times out. In the logs you see:
+
+ kernel: NOTICE-xpp: XBUS-00(00): FIRMWARE: ERROR_CODE CODE = 0x3 (Premature packet end)
+
+.Cause:
+When an Astribank is detected, the driver asks it what is its version
+and what components it has. Normally if the version of the firmware and
+of the driver does not match the driver gives an ugly message and fails
+the initialization.
+
+However in the change of the protocol between versions 2.9 (29) and 3.0
+(30), the response that the new driver recieves from a device with the
+old version is now considered to be an illegal packet and gets
+discarded. As a result, the Astribank waits till time-out for the
+initilization to end.
+
+.Fix:
+Reset the firmware of the Astribank by either:
+
+ /usr/share/zaptel/xpp_fxloader reset
+
+or disconnecting it from the power and reconnecting it.
+
+
+Reference
+---------
+LEDs Indication
+~~~~~~~~~~~~~~~
+The Astribank has 4 global indication leds and one or two per-port leds.
+On some of the models the LEDs are located on the left side on the front
+panel. If there are no separate LEDs there, then the red LEDs of the
+upper left-most ports of the device are used as the indication LEDs. Don't
+confuse them with green port status LEDs.
+
+The first led is the "Power" led. It is on if the unit gets power.
+The second led is the "Active" led, which is on when there is at
+least one "active" port (in a call / off-hook, though the meaning of this is
+different in BRI).
+The last led is called "Hardware OK", but is actually only is on in case of
+the hardware failure.
+
+The third led is the "Sync" led. If it blinks, the device is synchronized
+with the driver on the computer. If the device is selected to be the
+synchronization source for all of the Astribank devices then it will blink
+a quick single blink.
+If the device gets synchronization from the driver, it will blink in a
+more steady frequency.
+
+"Double blink" indicates that the unit has an FXO module, and still is
+getting synchronization from the computer, and is not the synchronization
+source.
+
+The per-port green led on analog (both FXS and FXO) indicates that the
+port is off-hook.
+
+On the BRI, the green led indicates a TE port whereas an orange led
+indicates an NT port. If the led is solid, the port is down (not even
+layer-1 connection is up). If it is blinking a double blink, layer 1
+is up. A slower single blinking indicates that layer 2 is up as well
+(which means that Asterisk is driving the port).
+
+
+PRI Ports Configuration
+~~~~~~~~~~~~~~~~~~~~~~~
+Astribank PRI module has two RJ-45 sockets for each PRI port. The lower
+socket provides typical PRI CPE side wiring: Rx- pins 1,2; Tx - pins
+4,5. The upper socket provides typical PRI Network side wiring: Rx- pins
+4,5; Tx - pins 1,2. The both sockets are permanently active and you can
+use any of them regardless of any configuration parameters (Both
+connectors are live. And connecting both of them with a flat 8-wire
+ethernet cable is a simple way to do a loop test for the port).
+
+
+For each port there are two optional parameters that define its
+behavior:
+
+Each port in the PRI module can be configured either as E1 or T1. The
+port type defaults to E1 and can be changed to T1 in the Zaptel Init
+Configuration File.
+
+The Astribank xpp driver uses that information for correct hardware
+initialization that is performed before the Zaptel span registration
+process takes place. Because of that, xpp driver can't use the
+information from file zaptel.conf.
+
+Another parameter that also can be defined in the Zaptel Init
+Configuration File is the function group TE (CPE) or NT (Network). This
+parameter is used for (a) building correct Zaptel & Asterisk
+configuration by genzaptelconf and (b) control RJ-45 sockets LEDs for
+better visual port control:
+
+A port in the PRI module can be either E1 (default) or T1. It can also be
+either "TE" (default) or "NT".
+
+TE::
+ Green LED of the lower socket will light. Hint that this is a TE
+ (CPE) port. This is the default.
+
+NT::
+ Orange LED of the upper socket will light. Hint that this is an
+ NT (network) port.
+
+To set them to a non-default value, you should use the variable
+XPP_PRI_SETUP in the
+xref:_zaptel_init_configuration_file[Zaptel Init Configuration File]
+(/etc/sysconfig/zaptel on Redhats, /etc/default/zaptel on Debians).
+This value is a whitespace-separated list of conditions. When a port is
+initialized it checks those conditions and uses the first one that
+matches.
+
+Match expressions may be:
+- CONNECTOR/usb..../XPD-nn To identify by physical connector
+- NUM/XBUS-mm/XPD-nn To identify by bus number
+
+Match expressions may contain "wildcards":
+
+- * matches zero or more characters.
+- ? matches one charater
+- [xyz] - any of 'x', 'y', or 'z'.
+
+For each line you should define both if it is E1 or T1 and if it is NT
+or TE.
+
+The list implicitly contains an 'NUM/*=TE,E1' catch all default, appended
+to its end.
+
+A number of useful examples. Note that you should use just one of them.
+---------------------------------------------
+# All ports are E1 and CPE
+#XPP_PRI_SETUP= #no need to set it
+
+# All ports are T1 and CPE:
+XPP_PRI_SETUP='NUM/*=T1,TE'
+
+# Now you want to test a loop between ports 1 and 2 and between
+# port 3 and 4. So let's make ports 2 and 4 network:
+XPP_PRI_SETUP='NUM/*/XPD-0[24]=E1,NT'
+
+# The same with T1. In this case we also need to set the default of all
+# the others to T1. Note that we can use more than one item and the
+# first one that matches counts:
+XPP_PRI_SETUP='
+ NUM/*/XPD-0[24]=T1,NT
+ NUM/*=T1,TE
+'
+
+# Actually, there is an implicit 'NUM/*=E1,TE' added to the end of the
+# value and set as the value if there is none. This is how the default
+# is set.
+
+# If you have more than one Astribank and you wish to configure
+# different Astribanks differently, you can use the CONNECTOR option:
+# e.g: set one specific Astribank as E1 network. The others default to
+# E1 CPE:
+XPP_PRI_SETUP='CONNECTOR/usb-0000:00:10.4-4/*=E1,NT'
+
+# Theoretically you could use: XPP_PRI_SETUP='NUM/XBUS-01/*=E1,NT'
+# but the XBUS number depends on the specific load order and is thus
+# might differ in a manual load and a system boot.
+---------------------------------------------
+
+This is currently implemented by writing a value to the
+xref:_proc_xpp_xbus_nn_xpd_mm_pri_info[pri_info file in procfs], but
+that may change in future versions.
+
+
+Device Startup
+~~~~~~~~~~~~~~
+This section describes in great depth the initialization of the Xorcom
+Astribank. Normally it would not be really needed, as the standard
+installation of Zaptel should put everything in place.
+
+Terminology
+^^^^^^^^^^^
+There are some technical terms that are used in this document and in the
+driver / zaptel.
+
+span:
+Zaptel breaks the channels it knows about to logical units called
+"spans". A port in a E1/T1/ISDN card is usually a span. An whole
+analog card is also a "span". You can see the list of spans as the list
+of files under /proc/zaptel directory or in output of the zttool
+utility.
+
+XBUS:
+A funny way to call an Astribank device.
+
+XPD:
+Basically this is a logical unit of the Astribank. It will be registered in
+Zaptel as a single span. This can be either an analog (FXS or FXO)
+module or a single port in case of a BRI module.
+
+
+Loading Firmware
+^^^^^^^^^^^^^^^^
+Normally this is done using the script /usr/share/zaptel/xpp_fxloader.
+If it works fine, you don't need to bother reading this section.
+Once the firmware is loaded the USB Vendor ID and Product ID of the Astribank
+became to be e4e4 11x2, and now the driver can pick it up.
+
+First and foremost: the simplest and most useful tool to debug problems
+is lsusb. The output of lsusb should show you if the device is connected
+if its firmware is loaded.
+
+The firmware files are named *.hex. They are presented in the text
+hexadecimal format The files are copied from xpp/utils to /usr/share/zaptel
+folder during the Zaptel installation.
+
+The Astribank needs a firmware loaded into it. Without the firmware,
+the device will appear in lsusb with Vendor ID e4e4 and Product ID 1130.
+The firmware loading process consists of two stages. In the first stage the
+"USB" firmware is loaded by using program fxload. When the first stage is
+completed the Vendor ID is e4e4 and the Product ID is 1131.
+
+You can use the following command in order to load the "USB" firmware
+manually:
+
+ fxload -t fx2 -D /proc/bus/usb/MMM/NNN -I /usr/share/zaptel/USB_FW.hex
+
+where,
+
+fxload::
+ A standard program that is typically part either of package 'fxload'
+ or 'hotplug-utils' .
+/proc/bus/usb::
+ The mount point of the USB file-system (usbfs).
+MMM::
+ the first number (bus number)
+NNN::
+ the second number (device number) you see for the device in lsusb
+
+If the loading process has been completed successfully, the device
+disconnects and then connects again itself with USB Product ID 1131
+(and a new device number).
+
+In the second stage, the "FPGA" firmware is loaded.
+The second-stage firmware loading is performed by using program fpga_load,
+which is built in the directory xpp/utils and then copied to folder
+/usr/sbin during Zaptel installation.
+
+The command syntax is similar to the syntax of fxload. You can use the
+following command in order to load the FPGA firmware manually:
+
+ fpga_load -D /proc/bus/usb/MMM/NNN -I /usr/share/zaptel/FPGA_1151.hex
+
+Please note, that NNN value differs from that that was used for the
+fxload command due to the fact that device has "reconnected" itself
+with another Product ID number. So you need to run lsusb again and get
+the new NNN value. Usually, the new value is equal to the old value
+incremented by 1.
+
+
+Firmware Loading with Hotplug
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The Hotplug framework was popular for hot-plugging different devices and
+usually also for automatic device drivers loading. If Hotplug is used in
+your system, you'll see many files in folder /etc/hotplug. Hotplug will
+automatically load the most relevant USB and PCI kernel modules according
+to the USB and PCI IDs provided by devices. Please note, that if the
+Hotplug framework is in place and the correct configuration files are
+located in the right place, then the firmware should be loaded automatically.
+
+In order to get the Hotplug framework to load the firmware into the
+Astribank automatically, the configuration file xpp_fxloader.usermap and
+the script xpp_fxloader should be copied into /etc/hotplug/usb/ . This is
+done by 'make -C xpp/utils install'.
+
+File xpp_fxloader.usermap includes a map of USB IDs and the command to run
+when such devices are encountered. It instructs the Hotplug to run the script
+xpp_fxloader from that directory. This is also done by 'make -C
+xpp/utils install' .
+
+When xpp_fxloader is run without any parameters it assumes that it was
+run by the hotplug scripts. Then it will check if the "add" event was
+accepted and if so, xpp_fxloader will install the required firmware file.
+The xpp_fxloader will be called twice, as after the load of the USB
+firmware the device will re-enumerate itself and thus "unplug" and
+"replug" in order to load the FPGA firmware.
+
+
+Firmware Loading with UDEV
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+The UDEV framework has replaced Hotplug in most recent systems. If you
+have a recent 2.6 system without Hotplug and with many files in folder
+/etc/udev, then there are good chances that are you using udev.
+As in case of Hotplug, if your udev framework is configured properly
+then the firmware should be loaded automatically.
+
+In order to get udev to automatically load the firmware into the Astribank,
+the configuration file xpp.rules should be copied into folder /etc/udev/rules.d
+and the script xpp_fxloader should be copied into folder /etc/hotplug/usb/ .
+This is done by 'make -C xpp/utils install' during Zaptel installation.
+
+File xpp.rules instructs the udevd daemon to run xpp_fxloader script with
+the option "udev" and with the Astribank USB ID obtained from the
+device when it is plugged in.
+Please note, that exactly like in case of Hotplug, the xpp_fxloader will be
+called twice by the udevd. First time for the USB firmware loading and the
+second time for FPGA firmware loading.
+
+
+Firmware Resetting
+^^^^^^^^^^^^^^^^^^
+Newer versions of the USB firmware can now be reset using 'fpga_load -r'.
+
+Also you can try the following:
+
+ /usr/share/zaptel/xpp_fxloader reset
+ # if asterisk was running: you may need to stop/restart it now.
+ # if there are some "disconnected" spans in /proc/xpp/xbuses
+ # wait a while, until you see the 1152 IDs again, and then:
+ /etc/init.d/zaptel start
+ # and start/restart asterisk.
+
+
+Loading The Modules
+^^^^^^^^^^^^^^^^^^^
+Here is what should happen:
+In short: you should plug the Astribank device(s) or have them plugged in at
+the boot time. Then all the modules should be loaded automatically.
+You will see xpp_usb , xpd_fxs and, possibly, xpd_fxo in the modules list
+(the output of lsmod).
+
+After the module xpp is loaded, you'll also be able to see the directory
+/proc/xpp. For any Astribank device discovered, you will see there a
+directory /proc/xpp/XBUS-n (where n is a number: typically 0). Once a unit have
+been discovered you'll see subdirectories: /proc/xpp/XBUS-n/XPD-m (where
+m may be another number: 0, 1 ,etc).
+
+Now to the ugly details:
+
+The driver of the Astribank is composed of several modules:
+
+* xpp - the basic module, that communicates with Zaptel and provides
+ some common services to other modules.
+* xpd_fxs - the module for controlling FXS modules.
+* xpd_fxo - the module for controlling FXO modules.
+* xpd_bri - the module for controlling BRI modules.
+* xpd_pri - the module for controlling E1/T1 modules.
+* xpd_usb - the module that holds the functionality needed to connect to the
+ USB bus.
+
+All modules depend on xpp, and modprobing them will install xpp as well.
+However the xpd_* modules are installed on-demand: no need to install
+the xpd_fxo if you have only Astribank FXS.
+
+Once an Astribank device connected and the firmware is loaded, the
+Vendor-ID/Product-ID of the device will be e4e4/1132 . The handler for that
+combination is listed as the kernel module xpp_usb. Therefore, the system
+runs 'modprobe xpp_usb' if that module is not already loaded.
+
+The module xpp_usb depends on the zaptel and xpp modules. Both of them
+are loaded before xpp_usb. As usual, parameters and rules form
+/etc/modprobe.conf and/or from /etc/modprobe.d/* will be applied to
+the module.
+
+When command 'modprobe xpp_usb' returns, the span type specific modules
+(e.g., xpd_fxs, xpd_fxo) may or may not have been loaded yet.
+
+At this point the xpp driver "asks" the box about its software
+(firmware) version) and the type of telephony modules it has. According
+to the answers it receives, the xpp driver will "modprobe" the required
+xpd_* modules.
+
+
+Device Initializations Scripts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The chips in the device need to be initialized. This requires sending a
+bunch of values to certain registers in those chips. We decided that
+hardwiring those values in the driver code is not a good idea.
+Before registering a XPD as a span in Zaptel, we run an initialization
+script: /usr/share/zaptel/init_card_N_MM (
+where,
+
+* N - is 3 for an FXS span and 4 for an FXO span, and 6 or 7 for BRI.
+* MM - is a version number. Currently it equals 26
+
+Those scripts must be executable. Funny things happen if such a script
+exists but is not executable.
+
+If because of some reasons this fails (the script is not in the place, or the
+file doesn't have the executable permissions), then you will get an error
+message in the logs and the XPD will then be removed (you won't see directory
+for that XPD under the corresponding /proc/xpp/XBUS-* directory) and will not
+be registered in Zaptel.
+
+As the XPD is initialized, you'll see the green LEDs of the ports steadily
+turn on and later off ("a train of lights"). This is a bit slower than the
+faster "blinking" when the XPDs register as Zaptel spans. The initialization
+of an FXS XPD may take a few seconds.
+
+
+Registering in Zaptel
+^^^^^^^^^^^^^^^^^^^^^
+The XPDs will not automatically register as Zaptel spans. This is
+intended to allow you to set the registration order (and hence the order
+of Zaptel spans and channels) among multiple Astribank devices,
+or between an Astribank and a different Zaptel device.
+
+When the XPD registers to Zaptel, all the green LEDs will be lit for a
+short while.
+
+Spans are normally registered with the utility zt_registration. Simply
+running 'zt_registration' shows the available XPDs and whether or not
+they are registered. To register:
+
+ zt_registration on
+
+For a system with several spans you'll see a "fast train of lights".
+
+If you have multiple Astribank devices, zt_registration will register
+them by the order of the "connector" field. This means that as long as
+the same Astribank is connected to the same port, the order of plugging
+is not important..
+
+zt_registration checks if a span is registered or tries to register a
+span using the file /proc/xpp/XBUS-nn/XPD-mm/zt_registration . Reading
+from that file returns 0 if the span is unregisters or 1 if it is
+registered. You can register a span or ask to unregister it by writing 1
+(register) or 0 (unregister) to that file. Registration should
+generally always succeed. Unregistration may fail if a span is in use.
+
+You may choose to register the XPDs in Zaptel automatically. This may
+make the startup sequence a bit simpler, but is generally not
+recommended on a system with more than one Astribank or an Astribank and
+a different Zaptel device. This behavior may be defined by setting
+parameter zap_autoreg in the modprobe configuration file (A file under
+/etc/modprobe.d or /etc/modprobe.conf):
+
+ options xpp zap_autoreg=1
+
+
+Zaptel And Above
+^^^^^^^^^^^^^^^^
+From here you get a standard Zaptel span. It still needs to be
+configured by ztcfg and used by a program such as Asterisk like any
+other Zaptel device. In order for you to get a dial-tone in a phone
+connected to the FXS port or a fully synchronized BRI port (layer 2
+activated, as signalled by a more steady blink) you will actually need
+both the span configured by Zaptel and the channels configured in
+Asterisk.
+
+You should generally refer to the general Zaptel documentation on how to
+configure those levels. e.g, the README file in the top-level directory,
+and
+
+ http://voip-info.org/wiki/view/Asterisk+config+zapata.conf[]
+
+
+Zaptel now includes a utility called genzaptelconf (written as a big
+ugly shell script) to configure Zaptel automatically as good as
+possible. For analog channels it works quite well (because, IMHO, the
+"configuration" level on Zaptel should be optional there - there are
+already sane defaults). For digital spans - BRI and PRI , it may take
+some tuning.
+
+Alternatively, write you own configuration, based on the sample from the
+"Sample Configurations" section.
+
+
+/proc Interface
+~~~~~~~~~~~~~~~
+The Astribank drivers provide their own /proc interface under /proc/xpp.
+Here we review the more useful details of the procfs interface. There
+are many other debugging details that are exposed through the procfs
+interface.
+
+Also note that those details are subject to changes. Generally the
+recommended stable interface are the Zaptel-perl utilities from the
+xpp/utils directory.
+
+
+/proc/xpp/xbuses
+^^^^^^^^^^^^^^^^
+File /proc/xpp/xbuses lists the connected Astribank devices (one line
+per device).
+
+A device is normally has status "connected". The status "missing" means that
+the device has been disconnected, but Asterisk still holds channels from it
+open.
+
+
+/proc/xpp/sync
+^^^^^^^^^^^^^^
+A read/write file. It contains information about current synchronization
+source. You can change the synchronization source by writing special
+command to the file. For example, command
+ echo SYNC=01 > /proc/xpp/sync
+
+Possible values are:
+
+<number>::
+ Make the Astribank XBUS-<number> the sync source for other Astribanks.
+
+ZAPTEL::
+ Make the Astribanks synchronize with the Zaptel timing master span.
+ You probably need this to get faxes from a non-Astribank adapter to an
+ Astribank.
+
+Though you'll normally use xpp_sync(8) for that.
+
+For each Astribank device there is folder /proc/xpp/XBUS-nn and for each device
+module (span in the terms of Zaptel) there is folder /proc/XBUS-nn/XPD-mm.
+
+
+/proc/xpp/XBUS-nn/waitfor_xpds
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Reading from this file only returns when the Astribank has finished
+initialization of the XPDs or in case of a timeout. It prints the number
+of XPDs to initialize, and the number initialize. Unless something went
+wrong, those two numbers are the same. Once the span was initialized,
+reading from this file returns immediately:
+
+ XPDS_READY: XBUS-00: 3/3
+
+
+/proc/xpp/XBUS-nn/XPD-mm/zt_registration
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+is a read/write file. Reading from it gives 0 if the span is
+unregistered, or the span number if it is registered.
+
+Writing to it allows manual registration / unregistration from Zaptel:
+writing 1 registers a span (if it wasn't already registered) and writing
+0 attempts to unregister it (if it is registered. Span unregistration
+will fail if some channels from the span are used (e.g: by Asterisk).
+
+A more convenient interface to this is the command zt_registration that
+registers or unregisters all the spans at once with a predefined order,
+and this is what you should normally use.
+
+Alternatively you can use the parameter zap_autoreg to register spans
+automatically. But this is only recommended on a system with a single
+Astribank and no other Zaptel device.
+
+
+/proc/xpp/XBUS-nn/XPD-mm/summary
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Contains detailed information about port statuses of the device module
+(off-hook, on-hook etc.) For example, you can run the following command
+in order to monitor the port statuses in the real time:
+
+ watch -n1 cat /proc/xpp/XBUS-00/XPD-00/summary
+
+
+/proc/xpp/XBUS-nn/XPD-mm/slics
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Provides direct read/write interface to the registers of each chip.
+Reading from the file shows the result of the last read request. To make
+either a read request or a write request you need to write to that file.
+
+It is mainly used by the initialization scripts (card_init_*).
+
+Incorrect usage of this file is one possible way of damaging the
+Astribank.
+
+
+/proc/xpp/XBUS-nn/XPD-mm/fxo_info
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Only for FXO modules. Apart from showing the status of the LEDs, it also
+shows for each FXO port if it is connected to a provider: look for the
+value of "battery" for that specific port, and a bunch of other
+characteristics of the port.
+
+
+/proc/xpp/XBUS-nn/XPD-mm/bri_info
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In addition to the usual information about the LEDs, this file also
+provides useful information regarding ISDN Layer 1 and Layer 2 status.
+For example, you can run the following command in order to monitor
+the Layer 1 port statuses for all BRI devices in the real time:
+
+ watch -n1 -d 'grep "Layer 1:" /proc/xpp/XBUS-*/XPD-*/bri_info'
+
+For the status of the D channel of the ports on all BRI spans, run:
+
+ watch -n1 -d 'grep D-Channel: /proc/xpp/XBUS-*/XPD-*/bri_info'
+
+
+/proc/xpp/XBUS-nn/XPD-mm/pri_info
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In addition to the usual information about the LEDs, this file also
+provides useful information regarding ISDN Layer 1 and Layer 2 status.
+For example, you can run the following command in order to monitor
+the Layer 1 port statuses for all E1/T1 devices in the real time:
+
+ watch -n1 -d 'grep "Layer 1:" /proc/xpp/XBUS-*/XPD-*/pri_info'
+
+For the status of the D channel of the ports on all PRI spans, run:
+
+ watch -n1 -d 'grep D-Channel: /proc/xpp/XBUS-*/XPD-*/pri_info'
+
+Note: the layer 2 status is much more of a guesswork based on changes in
+the contents of the channel that is supposed to be the D channel.
+
+Writing to this file can be used to change the type of the device. The
+device type can only be changed when the XPD is not registered as a
+Zaptel span. The value is a whitespace-separated list of values that can
+be of:
+
+E1::
+ Provides 31 channels, of which channel 16 is normally the D-channel.
+ Common in places outside of North America and Japan. This is the
+ default setup.
+
+T1::
+ T1 provides 24 channels. The last one is normally the D-Channel.
+ Common in North America.
+
+TE::
+ Use the bottom port (green LED) and don't invert any wiring. Hint to
+ higher layers that this will be the TE side of the connection. This is
+ the default setup.
+
+NT::
+ Use the top port (orange LED) and invert wiring (this is done to allow
+ connecting an NT port and a TE port using a standard straight 8 wires
+ "ethernet" cable). Hint to higher layers that this will be the NT side
+ of the connection.
+
+LOCALOOP::
+ Set the device into local loop mode: loops the transmitted channels
+ directly into the received channels.
+
+NOLOCALLOOP::
+ Ends local loop mode.
+
+Normally those are set by the PRI initialization script . See the
+definition of XPP_PRI_SETUP in
+xref:_zaptel_init_configuration_file[the sample Zaptel init
+configuration file] .
+
+
+There are a bunch of other status files under /proc/xpp/.
+
+
+/sys Interface
+~~~~~~~~~~~~~~~
+When an Astribank device loads it generates a device node in the bus
+'astribanks' in sysfs. You can see a directory for each device under
+/sys/bus/astribanks/devices/ and under it there are several attributes
+for each Astribank (such as its connector string).
+
+On each time an Astribank is initialized or destroyed a udev event is
+generated. The rules from our sample udev rules file (xpp/utils/xpp.rules)
+make that event run the script /usr/share/zaptel/astribank_hook with the
+parameter 'add' or 'remove', if such script exists. An example script
+that just adjusts the Astribank sync settings is included in xpp/utils.
+
+cls::
+ CLear Statistics: writing to this file clear the procfs statistics for
+ this bus.
+
+connector::
+ Connector string for the device. The place to which the Astribank is
+ connected. e.g: usb-0000:00:03.3-2
+
+label::
+ The label string of the Astribank unit. E.g: usb:00000135
+
+status::
+ 'connected' (normal operation) or 'disconnected' (has been disconnected,
+ some channels are still open).
+
+timing::
+ Provides some statistics in case the Astribank is not the sync source.
+ The format of this file is subject to future changes.
+
+
+Useful Module Parameters
+~~~~~~~~~~~~~~~~~~~~~~~~
+Compilation-time defaults for the all modules can be shown as part of the
+description line for the parameter in the "modinfo" command output.
+
+zap_autoreg (xpp)::
+ Register spans automatically (1) or not (0). Default: 0.
+ Setting it simplifies operations with a single Astribank and no other
+ Zaptel hardware. However if you have such systems, automatic
+ registration can cause the order of spans to be unpredictable.
+ The standard startup scripts use 'zt_registration on' instead of this.
+
+initdir (xpp)::
+ This is the directory containing the initialization scripts.
+ The default is /usr/share/zaptel .
+ Setting this value could be useful if that location is inconvenient for you.
+
+rx_tasklet (xpp)::
+ Enable (1) or disable (0) doing most of the packets processing in
+ separate tasklets. This should probably help on higher-end systems with
+ multiple Astribanks.
+
+debug (all modules)::
+ It will make the driver to print tons of debugging messages. You can
+ set/unset the parameter at run-time. The parameter value is a bitmask
+ of several values. The different bits meaning as it defined in
+ xpp/zap_debug.h:
+
+ * 0 - Disable debug messages
+ * 1 - GENERAL - General debug comments.
+ * 2 - PCM - PCM-related messages. Tends to flood logs.
+ * 4 - LEDS - Anything related to the LEDs status control. The driver
+ produces a lot of messages when the option is enabled.
+ * 8 - SYNC - Synchronization related messages.
+ * 16 - SIGNAL - Zaptel signalling related messages.
+ * 32 - PROC - Messages related to the procfs interface.
+ * 64 - REGS - Reading and writing to chip registers. Tends to flood
+ logs.
+ * 128 - DEVICES - Device instantiation, destruction and such.
+ * 256 - COMMANDS - Protocol commands. Tends to flood logs.
+
+ For example,
+
+ echo 33 >/sys/modules/xpp/parameters/debug
+
+ forces module xpp to print general debugging messages (1) and procfs
+ debugging messages (32).
+
+vmwineon (xpd_fxs)::
+ Enable (1) or disable (0) sending the voicemail message waiting indication
+ signal to phones equipped with the Message Waiting neon lamp. It is
+ disabled by default because the feature requires extra work of the driver
+ even when such a phone is not used and also may cause some unusual
+ side effects with some phone models.
+
+usb1 (xpp_usb)::
+ Enable (1) or disable (0) support of USB1 devices. Disabled by default.
+
+ USB1 devices are not well-tested. It seems that they don't work at all
+ for Astribank BRI. Generally they should work with the current code, but
+ we expect the voice quality issues. Hence we would like to make it
+ very clear that you if you have a USB1 port (rather than a USB2 one, as
+ recommended) you will have to take an action to enable the device.
+
+poll intervals (various)::
+ There are various values which the driver occasionally polls the device
+ for. For instance, the parameter poll_battery_interval for xpd_fxo
+ to poll the battery, in order to know if the telco line is actually
+ connected.
+
+ The value of those parameters is typically a number in milliseconds.
+ 0 is used to disable polling. Under normal operation there should be
+ no reason to play with those parameters.
+
+dtmf_detection (xpd_fxs)::
+ Enable (1) or disable (0) support of hardware DTMF detection by the
+ Astribank.
+
+
+NOTE: XPP here does not stand for X Printing Panel, XML Pull Parser,
+X-Windows Phase Plane or XML Professional Publisher. It is simply the
+Xorcom Peripheral Protocol, which connects a computer to a XPD (Xorcom
+Peripheral Device). An XBUS (originally XPP Bus) is actually a single
+Astribank device and the XPDs have become the single modules in it.
diff --git a/drivers/dahdi/xpp/calibrate_slics b/drivers/dahdi/xpp/calibrate_slics
new file mode 100755
index 0000000..0d9245d
--- /dev/null
+++ b/drivers/dahdi/xpp/calibrate_slics
@@ -0,0 +1,308 @@
+#!/usr/bin/perl -w
+
+#
+# $Id$
+#
+
+use strict;
+
+my $SlicsFile = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/$ENV{XPD_NAME}/slics";
+
+my @SlicNums = (0 .. 7);
+
+if ( ! -f $SlicsFile ) {
+ exit 1
+}
+
+my $debug = 0;
+# set DEBUG_CALIBRATION in /etc/default/zaptel or similar
+if (exists $ENV{DEBUG_CALIBRATION}) {
+ $debug = 1;
+}
+
+sub mysleep($) {
+ my $timeout = shift;
+ select(undef,undef,undef,$timeout);
+}
+
+sub logger($) {
+ print STDERR "LOG: @_\n";
+ system("logger @_");
+}
+
+sub debug($) {
+ logger(@_) if ($debug);
+}
+
+sub write_to_slic_file($) {
+ my $write_str = shift;
+
+ open(SLICS,">$SlicsFile") or
+ die("Failed writing to slics file $SlicsFile");
+ print SLICS $write_str;
+ close(SLICS);
+ mysleep(0.001);
+
+}
+
+sub read_reg($$$) {
+ my $read_slic = shift;
+ my $read_reg = shift;
+ my $direct = shift;
+
+ write_to_slic_file(
+ sprintf("%d R%s %02X", $read_slic, $direct, $read_reg));
+ mysleep(0.001);
+ open(SLICS,$SlicsFile) or
+ die("Failed reading from slics file $SlicsFile");
+ #awk '/^SLIC_REPLY:/{print $5}' $SLICS | cut -dx -f2
+ my @reply = ();
+ while(<SLICS>){
+ #if (/^ /) {
+ # debug "answer line: $_";
+ #}
+ if (/^ \d*\s+[RW][DIS]\s+[[:xdigit:]]+\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)/){
+ @reply = (hex($1), hex($2));
+ #debug "got [$reply]\n";
+ last;
+ }
+ }
+ close(SLICS);
+ if ($direct eq 'I') {
+ return @reply;
+ } else {
+ return $reply[0];
+ }
+}
+
+# TODO: rearange arguments
+sub write_reg{#($$$$$) {
+ my $read_slic = shift;
+ my $read_reg = shift;
+ my $direct = shift;
+ my $reg_val_low = shift;
+ my $reg_val_hi = shift;
+
+ my $str = sprintf "%d W%s %02X %02X",
+ $read_slic, $direct, $read_reg, $reg_val_low;
+ if ($direct eq 'I') {
+ $str .= sprintf " %02X", $reg_val_hi;
+ }
+ write_to_slic_file($str);
+}
+
+sub log_calib_params() {
+ for my $i (100 .. 107) {
+ my $line="Calib Reg $i: ";
+ for my $slic (@SlicNums) {
+ $line .= " ".read_reg($slic, $i, 'D');
+ }
+ debug($line);
+ }
+}
+
+sub init_indirect_registers() {
+ return write_to_slic_file("#
+31 WI 00 C2 55
+31 WI 01 E6 51
+31 WI 02 85 4B
+31 WI 03 37 49
+
+31 WI 04 33 33
+31 WI 05 02 02
+31 WI 06 02 02
+31 WI 07 98 01
+
+31 WI 08 98 01
+31 WI 09 11 06
+31 WI 0A 02 02
+31 WI 0B E5 00
+
+31 WI 0C 1C 0A
+31 WI 0D 30 7B
+31 WI 0E 63 00
+31 WI 0F 00 00
+
+31 WI 10 70 78
+31 WI 11 7D 00
+31 WI 12 00 00
+31 WI 13 00 00
+
+31 WI 14 F0 7E
+31 WI 15 C0 01
+31 WI 16 00 00
+31 WI 17 00 20
+
+31 WI 18 00 20
+31 WI 19 00 00
+31 WI 1A 00 20
+31 WI 1B 00 40
+
+31 WI 1C 00 10
+31 WI 1D 00 36
+31 WI 1E 00 10
+31 WI 1F 00 02
+
+31 WI 20 C0 07
+31 WI 21 00 26
+31 WI 22 F4 0F
+31 WI 23 00 80
+
+#31 WI 24 20 03
+#31 WI 25 8C 08
+#31 WI 26 00 01
+#31 WI 27 10 00
+
+31 WI 24 00 08
+31 WI 25 00 08
+31 WI 26 00 08
+31 WI 27 00 08
+
+31 WI 28 00 0C
+31 WI 29 00 0C
+31 WI 2B 00 01
+
+31 WI 63 DA 00
+31 WI 64 60 6B
+31 WI 65 74 00
+31 WI 66 C0 79
+
+31 WI 67 20 11
+31 WI 68 E0 3B
+#");
+}
+
+sub init_early_direct_regs() {
+ return write_to_slic_file("#
+31 WD 08 00
+31 WD 4A 34
+31 WD 4B 10
+31 WD 40 00
+#")
+}
+
+my @FilterParams = ();
+
+sub save_indirect_filter_params() {
+ for my $slic (@SlicNums) {
+ for my $reg (35 .. 39) {
+ $FilterParams[$slic][$reg] =
+ [read_reg($slic, $reg, 'I')];
+ write_reg($slic, $reg, 'I', 0, 0x80);
+ }
+ }
+
+}
+
+sub restore_indirect_filter_params() {
+ for my $slic (@SlicNums) {
+ for my $reg (35 .. 39) {
+ write_reg($slic, $reg, 'I',
+ @{$FilterParams[$slic][$reg]});
+ }
+ }
+}
+
+my $ManualCalibrationSleepTime = 0.04; # 40ms
+
+sub manual_calibrate_loop($$) {
+ my $write_reg = shift;
+ my $read_reg = shift;
+
+ # counters to count down to (at most) 0
+ my @slic_counters = ();
+ for my $i (0 .. $#SlicNums) {
+ $slic_counters[$i] = 0x1F;
+ }
+
+ # start calibration:
+ my $calibration_in_progress = 1;
+ write_reg(31, $write_reg, 'D', 0x1F);
+ mysleep $ManualCalibrationSleepTime;
+
+ # wait until all slics have finished calibration, or for timeout
+ while ($calibration_in_progress) {
+ $calibration_in_progress = 0; # until proven otherwise
+ my $debug_calib_str = "ManualCalib:: ";
+ for my $slic(@SlicNums) {
+ my $value = read_reg($slic, $read_reg, 'D');
+ $debug_calib_str .= " [$slic_counters[$slic]:$value]";
+ if ($value != 0 && $slic_counters[$slic] >= 0) {
+ $calibration_in_progress = 1;
+ $slic_counters[$slic]--;
+ write_reg($slic,$write_reg,'D',$slic_counters[$slic]);
+ }
+ }
+ debug($debug_calib_str);
+ # TODO: unnecessary sleep in the last round:
+ mysleep $ManualCalibrationSleepTime;
+ }
+}
+
+sub manual_calibrate() {
+ manual_calibrate_loop(98, 88);
+ manual_calibrate_loop(99, 89);
+}
+
+sub auto_calibrate($$) {
+ my $calib_96 = shift;
+ my $calib_97 = shift;
+
+ #log_calib_params();
+ # start calibration:
+ write_to_slic_file(
+ sprintf
+ "31 WD 61 %02X\n".
+ "31 WD 60 %02X\n".
+ "", $calib_96, $calib_97
+
+ );
+ # wait until all slics have finished calibration, or for timeout
+ my $sleep_cnt = 0;
+ # time periods in seconds:
+ my $sleep_time = 0.1;
+ my $timeout_time = 2;
+ CALIB_LOOP: for my $slic (@SlicNums) {
+ debug("checking slic $slic");
+ while(1) {
+ if ((read_reg($slic, 60, 'D')) == 0) {
+ # move to next register
+ debug("slic $slic calibrated");
+ last;
+ }
+ if ( $sleep_cnt > $timeout_time/$sleep_time) {
+ debug("Auto Calibration: Exiting on timeout: $timeout_time.");
+ last CALIB_LOOP;
+ }
+ debug("auto_calibrate not done yet: slic #$slic\n");
+ mysleep(0.1);
+ $sleep_cnt++;
+ }
+ }
+ #log_calib_params();
+}
+
+###########################################################
+#
+# main
+#
+
+# TODO: for all slics check the following reads to check communication
+#read_reg($slic, 0x08, 'D'): 0x02
+#read_reg($slic, 0x0B, 'D'): 0x33
+#read_reg($slic, 0x40, 'D'): 0x00 (?)
+
+debug "starting\n";
+
+init_indirect_registers();
+debug "after init_indirect_registers\n";
+init_early_direct_regs();
+debug "after init_early_direct_regs\n";
+auto_calibrate(0x47, 0x1E);
+debug "after auto_calibrate\n";
+manual_calibrate();
+debug "after manul_calibrate\n";
+auto_calibrate(0x40, 0x01);
+debug "after auto_calibrate 2\n";
+
+
diff --git a/drivers/dahdi/xpp/card_bri.c b/drivers/dahdi/xpp/card_bri.c
new file mode 100644
index 0000000..086dbea
--- /dev/null
+++ b/drivers/dahdi/xpp/card_bri.c
@@ -0,0 +1,1506 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * Parts derived from Cologne demo driver for the chip.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include "xpd.h"
+#include "xproto.h"
+#include "xpp_zap.h"
+#include "card_bri.h"
+#include "zap_debug.h"
+#include "xbus-core.h"
+
+static const char rcsid[] = "$Id$";
+
+#ifndef CONFIG_ZAPATA_BRI_DCHANS
+#error CONFIG_ZAPATA_BRI_DCHANS is not defined
+#endif
+
+static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before zap_debug.h */
+static DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in milliseconds (0 - disable)");
+static DEF_PARM_BOOL(nt_keepalive, 1, 0644, "Force BRI_NT to keep trying connection");
+
+enum xhfc_states {
+ ST_RESET = 0, /* G/F0 */
+ /* TE */
+ ST_TE_SENSING = 2, /* F2 */
+ ST_TE_DEACTIVATED = 3, /* F3 */
+ ST_TE_SIGWAIT = 4, /* F4 */
+ ST_TE_IDENT = 5, /* F5 */
+ ST_TE_SYNCED = 6, /* F6 */
+ ST_TE_ACTIVATED = 7, /* F7 */
+ ST_TE_LOST_FRAMING = 8, /* F8 */
+ /* NT */
+ ST_NT_DEACTIVATED = 1, /* G1 */
+ ST_NT_ACTIVATING = 2, /* G2 */
+ ST_NT_ACTIVATED = 3, /* G3 */
+ ST_NT_DEACTIVTING = 4, /* G4 */
+};
+
+static const char *xhfc_state_name(bool is_nt, enum xhfc_states state)
+{
+ const char *p;
+
+#define _E(x) [ST_ ## x] = #x
+ static const char *te_names[] = {
+ _E(RESET),
+ _E(TE_SENSING),
+ _E(TE_DEACTIVATED),
+ _E(TE_SIGWAIT),
+ _E(TE_IDENT),
+ _E(TE_SYNCED),
+ _E(TE_ACTIVATED),
+ _E(TE_LOST_FRAMING),
+ };
+ static const char *nt_names[] = {
+ _E(RESET),
+ _E(NT_DEACTIVATED),
+ _E(NT_ACTIVATING),
+ _E(NT_ACTIVATED),
+ _E(NT_DEACTIVTING),
+ };
+#undef _E
+ if(is_nt) {
+ if ((state < ST_RESET) || (state > ST_NT_DEACTIVTING))
+ p = "NT ???";
+ else
+ p = nt_names[state];
+ } else {
+ if ((state < ST_RESET) || (state > ST_TE_LOST_FRAMING))
+ p = "TE ???";
+ else
+ p = te_names[state];
+ }
+ return p;
+}
+
+/* xhfc Layer1 physical commands */
+#define HFC_L1_ACTIVATE_TE 0x01
+#define HFC_L1_FORCE_DEACTIVATE_TE 0x02
+#define HFC_L1_ACTIVATE_NT 0x03
+#define HFC_L1_DEACTIVATE_NT 0x04
+
+#define HFC_L1_ACTIVATING 1
+#define HFC_L1_ACTIVATED 2
+#define HFC_TIMER_T1 2500
+#define HFC_TIMER_T3 8000 /* 8s activation timer T3 */
+#define HFC_TIMER_OFF -1 /* timer disabled */
+
+#define A_SU_WR_STA 0x30 /* ST/Up state machine register */
+#define V_SU_LD_STA 0x10
+#define V_SU_ACT 0x60 /* start activation/deactivation */
+#define STA_DEACTIVATE 0x40 /* start deactivation in A_SU_WR_STA */
+#define STA_ACTIVATE 0x60 /* start activation in A_SU_WR_STA */
+#define V_SU_SET_G2_G3 0x80
+
+#define A_SU_RD_STA 0x30
+typedef union {
+ struct {
+ byte v_su_sta:4;
+ byte v_su_fr_sync:1;
+ byte v_su_t2_exp:1;
+ byte v_su_info0:1;
+ byte v_g2_g3:1;
+ } bits;
+ byte reg;
+} su_rd_sta_t;
+
+#define REG30_LOST 3 /* in polls */
+#define DCHAN_LOST 15000 /* in ticks */
+
+#define BRI_DCHAN_SIGCAP ( \
+ ZT_SIG_EM | \
+ ZT_SIG_CLEAR | \
+ ZT_SIG_FXSLS | \
+ ZT_SIG_FXSGS | \
+ ZT_SIG_FXSKS | \
+ ZT_SIG_FXOLS | \
+ ZT_SIG_FXOGS | \
+ ZT_SIG_FXOKS | \
+ ZT_SIG_CAS | \
+ ZT_SIG_SF \
+ )
+#define BRI_BCHAN_SIGCAP (ZT_SIG_CLEAR | ZT_SIG_DACS)
+
+#define IS_NT(xpd) ((xpd)->direction == TO_PHONE)
+#define BRI_PORT(xpd) ((xpd)->addr.subunit)
+
+/* shift in PCM highway */
+#define SUBUNIT_PCM_SHIFT 4
+#define PCM_SHIFT(mask, sunit) ((mask) << (SUBUNIT_PCM_SHIFT * (sunit)))
+
+/*---------------- BRI Protocol Commands ----------------------------------*/
+
+static int write_state_register(xpd_t *xpd, byte value);
+static bool bri_packet_is_valid(xpacket_t *pack);
+static void bri_packet_dump(const char *msg, xpacket_t *pack);
+static int proc_bri_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int bri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc);
+static int bri_chanconfig(struct zt_chan *chan, int sigtype);
+static int bri_startup(struct zt_span *span);
+static int bri_shutdown(struct zt_span *span);
+
+#define PROC_REGISTER_FNAME "slics"
+#define PROC_BRI_INFO_FNAME "bri_info"
+
+enum led_state {
+ BRI_LED_OFF = 0x0,
+ BRI_LED_ON = 0x1,
+ /*
+ * We blink by software from driver, so that
+ * if the driver malfunction that blink would stop.
+ */
+ // BRI_LED_BLINK_SLOW = 0x2, /* 1/2 a second blink cycle */
+ // BRI_LED_BLINK_FAST = 0x3 /* 1/4 a second blink cycle */
+};
+
+enum bri_led_names {
+ GREEN_LED = 0,
+ RED_LED = 1
+};
+
+#define NUM_LEDS 2
+#define LED_TICKS 100
+
+
+struct bri_leds {
+ byte state:2;
+ byte led_sel:1; /* 0 - GREEN, 1 - RED */
+ byte reserved:5;
+};
+
+#ifndef MAX_DFRAME_LEN_L1
+#define MAX_DFRAME_LEN_L1 300
+#endif
+
+#define DCHAN_BUFSIZE MAX_DFRAME_LEN_L1
+
+struct BRI_priv_data {
+ struct proc_dir_entry *bri_info;
+ su_rd_sta_t state_register;
+ bool initialized;
+ int t1; /* timer 1 for NT deactivation */
+ int t3; /* timer 3 for TE activation */
+ ulong l1_flags;
+ bool reg30_good;
+ uint reg30_ticks;
+ bool layer1_up;
+ xpp_line_t card_pcm_mask;
+
+ /*
+ * D-Chan: buffers + extra state info.
+ */
+ int dchan_r_idx;
+ byte dchan_rbuf[DCHAN_BUFSIZE];
+ byte dchan_tbuf[DCHAN_BUFSIZE];
+ bool txframe_begin;
+
+ uint tick_counter;
+ uint poll_counter;
+ uint dchan_tx_counter;
+ uint dchan_rx_counter;
+ uint dchan_rx_drops;
+ bool dchan_alive;
+ uint dchan_alive_ticks;
+ uint dchan_notx_ticks;
+ uint dchan_norx_ticks;
+ enum led_state ledstate[NUM_LEDS];
+};
+
+static xproto_table_t PROTO_TABLE(BRI);
+
+
+DEF_RPACKET_DATA(BRI, SET_LED, /* Set one of the LED's */
+ struct bri_leds bri_leds;
+ );
+
+static /* 0x33 */ DECLARE_CMD(BRI, SET_LED, enum bri_led_names which_led, enum led_state to_led_state);
+
+#define DO_LED(xpd, which, tostate) \
+ CALL_PROTO(BRI, SET_LED, (xpd)->xbus, (xpd), (which), (tostate))
+
+#define DEBUG_BUF_SIZE (100)
+static void dump_hex_buf(xpd_t *xpd, char *msg, byte *buf, size_t len)
+{
+ char debug_buf[DEBUG_BUF_SIZE + 1];
+ int i;
+ int n = 0;
+
+ debug_buf[0] = '\0';
+ for(i = 0; i < len && n < DEBUG_BUF_SIZE; i++)
+ n += snprintf(&debug_buf[n], DEBUG_BUF_SIZE - n, "%02X ", buf[i]);
+ XPD_DBG(GENERAL, xpd, "%s[0..%zd]: %s%s\n", msg, len-1, debug_buf,
+ (n >= DEBUG_BUF_SIZE)?"...":"");
+}
+
+static void dump_dchan_packet(xpd_t *xpd, bool transmit, byte *buf, int len)
+{
+ struct BRI_priv_data *priv;
+ char msgbuf[MAX_PROC_WRITE];
+ char ftype = '?';
+ char *direction;
+ int frame_begin;
+
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(transmit) {
+ direction = "TX";
+ frame_begin = priv->txframe_begin;
+ } else {
+ direction = "RX";
+ frame_begin = 1;
+ }
+ if(frame_begin) { /* Packet start */
+ if(!IS_SET(buf[0], 7))
+ ftype = 'I'; /* Information */
+ else if(IS_SET(buf[0], 7) && !IS_SET(buf[0], 6))
+ ftype = 'S'; /* Supervisory */
+ else if(IS_SET(buf[0], 7) && IS_SET(buf[0], 6))
+ ftype = 'U'; /* Unnumbered */
+ else
+ XPD_NOTICE(xpd, "Unknown frame type 0x%X\n", buf[0]);
+
+ snprintf(msgbuf, MAX_PROC_WRITE, "D-Chan %s = (%c) ", direction, ftype);
+ } else {
+ snprintf(msgbuf, MAX_PROC_WRITE, "D-Chan %s = ", direction);
+ }
+ dump_hex_buf(xpd, msgbuf, buf, len);
+}
+
+static void set_bri_timer(xpd_t *xpd, const char *name, int *bri_timer, int value)
+{
+ if(value == HFC_TIMER_OFF)
+ XPD_DBG(SIGNAL, xpd, "Timer %s DISABLE\n", name);
+ else
+ XPD_DBG(SIGNAL, xpd, "Timer %s: set to %d\n", name, value);
+ *bri_timer = value;
+}
+
+static void dchan_state(xpd_t *xpd, bool up)
+{
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(priv->dchan_alive == up)
+ return;
+ if(up) {
+ XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel RUNNING\n");
+ priv->dchan_alive = 1;
+ } else {
+ XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n");
+ priv->dchan_rx_counter = priv->dchan_tx_counter = priv->dchan_rx_drops = 0;
+ priv->dchan_alive = 0;
+ priv->dchan_alive_ticks = 0;
+ }
+}
+
+static void layer1_state(xpd_t *xpd, bool up)
+{
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(priv->layer1_up == up)
+ return;
+ priv->layer1_up = up;
+ XPD_DBG(SIGNAL, xpd, "STATE CHANGE: Layer1 %s\n", (up)?"UP":"DOWN");
+ if(!up)
+ dchan_state(xpd, 0);
+}
+
+static void te_activation(xpd_t *xpd, bool on)
+{
+ struct BRI_priv_data *priv;
+ xbus_t *xbus;
+ byte curr_state;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ curr_state = priv->state_register.bits.v_su_sta;
+ xbus = xpd->xbus;
+ XPD_DBG(SIGNAL, xpd, "%s\n", (on)?"ON":"OFF");
+ if(on) {
+ if(curr_state == ST_TE_DEACTIVATED) {
+ XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_TE\n");
+ set_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
+ write_state_register(xpd, STA_ACTIVATE);
+ set_bri_timer(xpd, "T3", &priv->t3, HFC_TIMER_T3);
+ } else {
+ XPD_DBG(SIGNAL, xpd,
+ "HFC_L1_ACTIVATE_TE (state %d, ignored)\n",
+ curr_state);
+ }
+ } else { /* happen only because of T3 expiry */
+ switch (curr_state) {
+ case ST_TE_DEACTIVATED: /* F3 */
+ case ST_TE_SYNCED: /* F6 */
+ case ST_TE_ACTIVATED: /* F7 */
+ XPD_DBG(SIGNAL, xpd,
+ "HFC_L1_FORCE_DEACTIVATE_TE (state %d, ignored)\n",
+ curr_state);
+ break;
+ case ST_TE_SIGWAIT: /* F4 */
+ case ST_TE_IDENT: /* F5 */
+ case ST_TE_LOST_FRAMING: /* F8 */
+ XPD_DBG(SIGNAL, xpd, "HFC_L1_FORCE_DEACTIVATE_TE\n");
+ write_state_register(xpd, STA_DEACTIVATE);
+ break;
+ default:
+ XPD_NOTICE(xpd, "Bad TE state: %d\n", curr_state);
+ break;
+ }
+ }
+}
+
+static void nt_activation(xpd_t *xpd, bool on)
+{
+ struct BRI_priv_data *priv;
+ xbus_t *xbus;
+ byte curr_state;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ curr_state = priv->state_register.bits.v_su_sta;
+ xbus = xpd->xbus;
+ XPD_DBG(SIGNAL, xpd, "%s\n", (on)?"ON":"OFF");
+ if(on) {
+ switch(curr_state) {
+ case ST_RESET: /* F/G 0 */
+ case ST_NT_DEACTIVATED: /* G1 */
+ case ST_NT_DEACTIVTING: /* G4 */
+ XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_NT\n");
+ set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_T1);
+ set_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
+ write_state_register(xpd, STA_ACTIVATE);
+ break;
+ case ST_NT_ACTIVATING: /* G2 */
+ case ST_NT_ACTIVATED: /* G3 */
+ XPD_DBG(SIGNAL, xpd,
+ "HFC_L1_ACTIVATE_NT (in state %d, ignored)\n",
+ curr_state);
+ break;
+ }
+ } else {
+ switch(curr_state) {
+ case ST_RESET: /* F/G 0 */
+ case ST_NT_DEACTIVATED: /* G1 */
+ case ST_NT_DEACTIVTING: /* G4 */
+ XPD_DBG(SIGNAL, xpd,
+ "HFC_L1_DEACTIVATE_NT (in state %d, ignored)\n",
+ curr_state);
+ break;
+ case ST_NT_ACTIVATING: /* G2 */
+ case ST_NT_ACTIVATED: /* G3 */
+ XPD_DBG(SIGNAL, xpd, "HFC_L1_DEACTIVATE_NT\n");
+ write_state_register(xpd, STA_DEACTIVATE);
+ break;
+ default:
+ XPD_NOTICE(xpd, "Bad NT state: %d\n", curr_state);
+ break;
+ }
+ }
+}
+
+
+/*
+ * D-Chan receive
+ */
+static int rx_dchan(xpd_t *xpd, reg_cmd_t *regcmd)
+{
+ xbus_t *xbus;
+ struct BRI_priv_data *priv;
+ byte *src;
+ byte *dst;
+ byte *dchan_buf;
+ struct zt_chan *dchan;
+ uint len;
+ bool eoframe;
+ int idx;
+ int ret = 0;
+
+ src = REG_XDATA(regcmd);
+ len = regcmd->bytes;
+ eoframe = regcmd->eoframe;
+ if(len <= 0)
+ return 0;
+ if(!SPAN_REGISTERED(xpd)) /* Nowhere to copy data */
+ return 0;
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ xbus = xpd->xbus;
+#ifdef XPP_DEBUGFS
+ xbus_log(xbus, xpd, 0, regcmd, sizeof(reg_cmd_t)); /* 0 = RX */
+#endif
+ dchan = &xpd->span.chans[2];
+ if(!IS_SET(xpd->offhook, 2)) { /* D-chan is used? */
+ static int rate_limit;
+
+ if((rate_limit++ % 1000) == 0)
+ XPD_DBG(SIGNAL, xpd, "D-Chan unused\n");
+ dchan->bytes2receive = 0;
+ dchan->bytes2transmit = 0;
+ goto out;
+ }
+ dchan_buf = dchan->readchunk;
+ idx = priv->dchan_r_idx;
+ if(idx + len >= DCHAN_BUFSIZE) {
+ XPD_ERR(xpd, "D-Chan RX overflow: %d\n", idx);
+ dump_hex_buf(xpd, " current packet", src, len);
+ dump_hex_buf(xpd, " dchan_buf", dchan_buf, idx);
+ ret = -ENOSPC;
+ if(eoframe)
+ goto drop;
+ goto out;
+ }
+ dst = dchan_buf + idx;
+ idx += len;
+ priv->dchan_r_idx = idx;
+ memcpy(dst, src, len);
+ if(!eoframe)
+ goto out;
+ if(idx < 4) {
+ XPD_NOTICE(xpd, "D-Chan RX short frame (idx=%d)\n", idx);
+ dump_hex_buf(xpd, "D-Chan RX: current packet", src, len);
+ dump_hex_buf(xpd, "D-Chan RX: chan_buf", dchan_buf, idx);
+ ret = -EPROTO;
+ goto drop;
+ }
+ if(dchan_buf[idx-1]) {
+ XPD_NOTICE(xpd, "D-Chan RX Bad checksum: [%02X:%02X=%02X] (%d)\n",
+ dchan_buf[idx-3], dchan_buf[idx-2], dchan_buf[idx-1], dchan_buf[idx-1]);
+ dump_hex_buf(xpd, "D-Chan RX: current packet", src, len);
+ dump_hex_buf(xpd, "D-Chan RX: chan_buf", dchan_buf, idx);
+ ret = -EPROTO;
+ goto drop;
+ }
+ if(debug)
+ dump_dchan_packet(xpd, 0, dchan_buf, idx /* - 3 */); /* Print checksum? */
+ /*
+ * Tell Zaptel that we received idx-1 bytes. They include the data and a 2-byte checksum.
+ * The last byte (that we don't pass on) is 0 if the checksum is correct. If it were wrong,
+ * we would drop the packet in the "if(dchan_buf[idx-1])" above.
+ */
+ dchan->bytes2receive = idx - 1;
+ dchan->eofrx = 1;
+ priv->dchan_rx_counter++;
+ priv->dchan_norx_ticks = 0;
+drop:
+ priv->dchan_r_idx = 0;
+out:
+ return ret;
+}
+
+/*
+ * D-Chan transmit
+ */
+static int tx_dchan(xpd_t *xpd)
+{
+ struct BRI_priv_data *priv;
+ struct zt_chan *dchan;
+ int len;
+ int eoframe;
+ int ret;
+
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(!SPAN_REGISTERED(xpd) || !(xpd->span.flags & ZT_FLAG_RUNNING))
+ return 0;
+ dchan = &xpd->chans[2];
+ len = dchan->bytes2transmit; /* dchan's hdlc package len */
+ eoframe = dchan->eoftx; /* dchan's end of frame */
+ dchan->bytes2transmit = 0;
+ dchan->eoftx = 0;
+ dchan->bytes2receive = 0;
+ dchan->eofrx = 0;
+ if(len <= 0)
+ return 0; /* Nothing to transmit on D channel */
+ if(len > MULTIBYTE_MAX_LEN) {
+ XPD_ERR(xpd, "%s: len=%d. need to split. Unimplemented.\n", __FUNCTION__, len);
+ return -EINVAL;
+ }
+ if(!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags) && !test_bit(HFC_L1_ACTIVATING, &priv->l1_flags)) {
+ XPD_DBG(SIGNAL, xpd, "Want to transmit: Kick D-Channel transmiter\n");
+ if(xpd->direction == TO_PSTN)
+ te_activation(xpd, 1);
+ else
+ nt_activation(xpd, 1);
+ return 0;
+ }
+ if(debug)
+ dump_dchan_packet(xpd, 1, priv->dchan_tbuf, len);
+ if(eoframe)
+ priv->txframe_begin = 1;
+ else
+ priv->txframe_begin = 0;
+ ret = send_multibyte_request(xpd->xbus, xpd->addr.unit, xpd->addr.subunit,
+ eoframe, priv->dchan_tbuf, len);
+ if(ret < 0)
+ XPD_NOTICE(xpd, "%s: failed sending xframe\n", __FUNCTION__);
+ if(eoframe)
+ priv->dchan_tx_counter++;
+ priv->dchan_notx_ticks = 0;
+ return ret;
+}
+
+/*---------------- BRI: Methods -------------------------------------------*/
+
+static void bri_proc_remove(xbus_t *xbus, xpd_t *xpd)
+{
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(PROC, xpd, "\n");
+#ifdef CONFIG_PROC_FS
+ if(priv->bri_info) {
+ XPD_DBG(PROC, xpd, "Removing '%s'\n", PROC_BRI_INFO_FNAME);
+ remove_proc_entry(PROC_BRI_INFO_FNAME, xpd->proc_xpd_dir);
+ }
+#endif
+}
+
+static int bri_proc_create(xbus_t *xbus, xpd_t *xpd)
+{
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(PROC, xpd, "\n");
+#ifdef CONFIG_PROC_FS
+ XPD_DBG(PROC, xpd, "Creating '%s'\n", PROC_BRI_INFO_FNAME);
+ priv->bri_info = create_proc_read_entry(PROC_BRI_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_bri_info_read, xpd);
+ if(!priv->bri_info) {
+ XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_BRI_INFO_FNAME);
+ goto err;
+ }
+ priv->bri_info->owner = THIS_MODULE;
+#endif
+ return 0;
+err:
+ bri_proc_remove(xbus, xpd);
+ return -EINVAL;
+}
+
+static xpd_t *BRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, bool to_phone)
+{
+ xpd_t *xpd = NULL;
+ int channels = min(3, CHANNELS_PERXPD);
+
+ XBUS_DBG(GENERAL, xbus, "\n");
+ xpd = xpd_alloc(sizeof(struct BRI_priv_data), proto_table, channels);
+ if(!xpd)
+ return NULL;
+ xpd->direction = (to_phone) ? TO_PHONE : TO_PSTN;
+ xpd->type_name = (to_phone) ? "BRI_NT" : "BRI_TE";
+ if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0)
+ goto err;
+ if(bri_proc_create(xbus, xpd) < 0)
+ goto err;
+ return xpd;
+err:
+ xpd_free(xpd);
+ return NULL;
+}
+
+static int BRI_card_init(xbus_t *xbus, xpd_t *xpd)
+{
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ XPD_DBG(GENERAL, xpd, "\n");
+ priv = xpd->priv;
+ set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF);
+ write_state_register(xpd, 0); /* Enable L1 state machine */
+ priv->initialized = 1;
+ return 0;
+}
+
+static int BRI_card_remove(xbus_t *xbus, xpd_t *xpd)
+{
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(GENERAL, xpd, "\n");
+ bri_proc_remove(xbus, xpd);
+ return 0;
+}
+
+static int BRI_card_zaptel_preregistration(xpd_t *xpd, bool on)
+{
+ xbus_t *xbus;
+ struct BRI_priv_data *priv;
+ xpp_line_t tmp_pcm_mask;
+ int tmp_pcm_len;
+ unsigned long flags;
+ int i;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ BUG_ON(!xbus);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
+ if(!on) {
+ /* Nothing to do yet */
+ return 0;
+ }
+#ifdef ZT_SPANSTAT_V2
+ xpd->span.spantype = "BRI";
+#endif
+ xpd->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_CCS;
+ xpd->span.deflaw = ZT_LAW_ALAW;
+ BIT_SET(xpd->digital_signalling, 2); /* D-Channel */
+ for_each_line(xpd, i) {
+ struct zt_chan *cur_chan = &xpd->chans[i];
+
+ XPD_DBG(GENERAL, xpd, "setting BRI channel %d\n", i);
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%02d/%1d%1d/%d",
+ xpd->type_name, xbus->num,
+ xpd->addr.unit, xpd->addr.subunit, i);
+ cur_chan->chanpos = i + 1;
+ cur_chan->pvt = xpd;
+ if(i == 2) { /* D-CHAN */
+ cur_chan->sigcap = BRI_DCHAN_SIGCAP;
+ cur_chan->flags |= ZT_FLAG_BRIDCHAN;
+ cur_chan->flags &= ~ZT_FLAG_HDLC;
+
+ /* Setup big buffers for D-Channel rx/tx */
+ cur_chan->readchunk = priv->dchan_rbuf;
+ cur_chan->writechunk = priv->dchan_tbuf;
+ priv->dchan_r_idx = 0;
+ priv->txframe_begin = 1;
+
+ cur_chan->maxbytes2transmit = MULTIBYTE_MAX_LEN;
+ cur_chan->bytes2transmit = 0;
+ cur_chan->bytes2receive = 0;
+ } else
+ cur_chan->sigcap = BRI_BCHAN_SIGCAP;
+ }
+ xpd->offhook = BIT(0) | BIT(1); /* 2*bchan */
+
+ /*
+ * Compute PCM lentgh and mask
+ * We know all cards have been initialized until now
+ */
+ tmp_pcm_mask = 0;
+ if(xpd->addr.subunit == 0) {
+ int line_count = 0;
+
+ for(i = 0; i < MAX_SUBUNIT; i++) {
+ xpd_t *sub_xpd = xpd_byaddr(xbus, xpd->addr.unit, i);
+ if(sub_xpd) {
+ tmp_pcm_mask |= PCM_SHIFT(sub_xpd->wanted_pcm_mask, i);
+ line_count += 2;
+ }
+ }
+ tmp_pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE;
+ } else
+ tmp_pcm_len = 0;
+ spin_lock_irqsave(&xpd->lock, flags);
+ xpd->pcm_len = tmp_pcm_len;
+ xpd->wanted_pcm_mask = xpd->offhook;
+ priv->card_pcm_mask = tmp_pcm_mask;
+ xpd->span.spanconfig = bri_spanconfig;
+ xpd->span.chanconfig = bri_chanconfig;
+ xpd->span.startup = bri_startup;
+ xpd->span.shutdown = bri_shutdown;
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return 0;
+}
+
+static int BRI_card_zaptel_postregistration(xpd_t *xpd, bool on)
+{
+ xbus_t *xbus;
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ BUG_ON(!xbus);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
+ return(0);
+}
+
+static int BRI_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
+{
+ LINE_DBG(SIGNAL, xpd, pos, "%s\n", txsig2str(txsig));
+ return 0;
+}
+
+/*
+ * LED managment is done by the driver now:
+ * - Turn constant ON RED/GREEN led to indicate NT/TE port
+ * - Very fast "Double Blink" to indicate Layer1 alive (without D-Channel)
+ * - Constant blink (1/2 sec cycle) to indicate D-Channel alive.
+ */
+static void handle_leds(xbus_t *xbus, xpd_t *xpd)
+{
+ struct BRI_priv_data *priv;
+ unsigned int timer_count;
+ int which_led;
+ int other_led;
+ int mod;
+
+ BUG_ON(!xpd);
+ if(IS_NT(xpd)) {
+ which_led = RED_LED;
+ other_led = GREEN_LED;
+ } else {
+ which_led = GREEN_LED;
+ other_led = RED_LED;
+ }
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ timer_count = xpd->timer_count;
+ if(xpd->blink_mode) {
+ if((timer_count % DEFAULT_LED_PERIOD) == 0) {
+ // led state is toggled
+ if(priv->ledstate[which_led] == BRI_LED_OFF) {
+ DO_LED(xpd, which_led, BRI_LED_ON);
+ DO_LED(xpd, other_led, BRI_LED_ON);
+ } else {
+ DO_LED(xpd, which_led, BRI_LED_OFF);
+ DO_LED(xpd, other_led, BRI_LED_OFF);
+ }
+ }
+ return;
+ }
+ if(priv->ledstate[other_led] != BRI_LED_OFF)
+ DO_LED(xpd, other_led, BRI_LED_OFF);
+ if(priv->dchan_alive) {
+ mod = timer_count % 1000;
+ switch(mod) {
+ case 0:
+ DO_LED(xpd, which_led, BRI_LED_ON);
+ break;
+ case 500:
+ DO_LED(xpd, which_led, BRI_LED_OFF);
+ break;
+ }
+ } else if(priv->layer1_up) {
+ mod = timer_count % 1000;
+ switch(mod) {
+ case 0:
+ case 100:
+ DO_LED(xpd, which_led, BRI_LED_ON);
+ break;
+ case 50:
+ case 150:
+ DO_LED(xpd, which_led, BRI_LED_OFF);
+ break;
+ }
+ } else {
+ if(priv->ledstate[which_led] != BRI_LED_ON)
+ DO_LED(xpd, which_led, BRI_LED_ON);
+ }
+}
+
+static void handle_bri_timers(xpd_t *xpd)
+{
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(IS_NT(xpd)) {
+ if (priv->t1 > HFC_TIMER_OFF) {
+ if (--priv->t1 == 0) {
+ set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF);
+ if(!nt_keepalive) {
+ if(priv->state_register.bits.v_su_sta == ST_NT_ACTIVATING) { /* G2 */
+ XPD_DBG(SIGNAL, xpd, "T1 Expired. Deactivate NT\n");
+ clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
+ nt_activation(xpd, 0); /* Deactivate NT */
+ } else
+ XPD_DBG(SIGNAL, xpd,
+ "T1 Expired. (state %d, ignored)\n",
+ priv->state_register.bits.v_su_sta);
+ }
+ }
+ }
+ } else {
+ if (priv->t3 > HFC_TIMER_OFF) {
+ /* timer expired ? */
+ if (--priv->t3 == 0) {
+ XPD_DBG(SIGNAL, xpd, "T3 expired. Deactivate TE\n");
+ set_bri_timer(xpd, "T3", &priv->t3, HFC_TIMER_OFF);
+ clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
+ te_activation(xpd, 0); /* Deactivate TE */
+ }
+ }
+ }
+}
+
+/* Poll the register ST/Up-State-machine Register, to see if the cable
+ * if a cable is connected to the port.
+ */
+static int BRI_card_tick(xbus_t *xbus, xpd_t *xpd)
+{
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(!priv->initialized || !xbus->self_ticking)
+ return 0;
+ if(poll_interval != 0 && (priv->tick_counter % poll_interval) == 0) {
+ // XPD_DBG(GENERAL, xpd, "%d\n", priv->tick_counter);
+ priv->poll_counter++;
+ xpp_register_request(xbus, xpd,
+ BRI_PORT(xpd), /* portno */
+ 0, /* writing */
+ A_SU_RD_STA, /* regnum */
+ 0, /* do_subreg */
+ 0, /* subreg */
+ 0, /* data_low */
+ 0, /* do_datah */
+ 0, /* data_high */
+ 0 /* should_reply */
+ );
+
+ if(IS_NT(xpd) && nt_keepalive &&
+ !test_bit(HFC_L1_ACTIVATED, &priv->l1_flags) &&
+ !test_bit(HFC_L1_ACTIVATING, &priv->l1_flags)) {
+ XPD_DBG(SIGNAL, xpd, "Kick NT D-Channel\n");
+ nt_activation(xpd, 1);
+ }
+ }
+ /* Detect D-Channel disconnect heuristic */
+ priv->dchan_notx_ticks++;
+ priv->dchan_norx_ticks++;
+ priv->dchan_alive_ticks++;
+ if(priv->dchan_alive && (priv->dchan_notx_ticks > DCHAN_LOST || priv->dchan_norx_ticks > DCHAN_LOST)) {
+ /*
+ * No tx_dchan() or rx_dchan() for many ticks
+ * This D-Channel is probabelly dead.
+ */
+ dchan_state(xpd, 0);
+ } else if(priv->dchan_rx_counter > 1 && priv->dchan_tx_counter > 1) {
+ if(!priv->dchan_alive)
+ dchan_state(xpd, 1);
+ }
+ /* Detect Layer1 disconnect */
+ if(priv->reg30_good && priv->reg30_ticks > poll_interval * REG30_LOST) {
+ /* No reply for 1/2 a second */
+ XPD_ERR(xpd, "Lost state tracking for %d ticks\n", priv->reg30_ticks);
+ priv->reg30_good = 0;
+ layer1_state(xpd, 0);
+ }
+ handle_leds(xbus, xpd);
+ handle_bri_timers(xpd);
+ tx_dchan(xpd);
+ priv->tick_counter++;
+ priv->reg30_ticks++;
+ return 0;
+}
+
+static int BRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
+{
+ BUG_ON(!xpd);
+ if(!TRANSPORT_RUNNING(xpd->xbus))
+ return -ENODEV;
+ switch (cmd) {
+ case ZT_TONEDETECT:
+ /*
+ * Asterisk call all span types with this (FXS specific)
+ * call. Silently ignore it.
+ */
+ LINE_DBG(SIGNAL, xpd, pos, "BRI: Starting a call\n");
+ return -ENOTTY;
+ default:
+ report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd);
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int BRI_card_close(xpd_t *xpd, lineno_t pos)
+{
+ struct zt_chan *chan = &xpd->span.chans[pos];
+
+ /* Clear D-Channel pending data */
+ chan->bytes2receive = 0;
+ chan->eofrx = 0;
+ chan->bytes2transmit = 0;
+ chan->eoftx = 0;
+ return 0;
+}
+
+/*
+ * Called only for 'span' keyword in /etc/zaptel.conf
+ */
+static int bri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+ xpd_t *xpd = span->pvt;
+ const char *framingstr = "";
+ const char *codingstr = "";
+ const char *crcstr = "";
+
+ /* framing first */
+ if (lc->lineconfig & ZT_CONFIG_B8ZS)
+ framingstr = "B8ZS";
+ else if (lc->lineconfig & ZT_CONFIG_AMI)
+ framingstr = "AMI";
+ else if (lc->lineconfig & ZT_CONFIG_HDB3)
+ framingstr = "HDB3";
+ /* then coding */
+ if (lc->lineconfig & ZT_CONFIG_ESF)
+ codingstr = "ESF";
+ else if (lc->lineconfig & ZT_CONFIG_D4)
+ codingstr = "D4";
+ else if (lc->lineconfig & ZT_CONFIG_CCS)
+ codingstr = "CCS";
+ /* E1's can enable CRC checking */
+ if (lc->lineconfig & ZT_CONFIG_CRC4)
+ crcstr = "CRC4";
+ XPD_DBG(GENERAL, xpd, "[%s]: span=%d (%s) lbo=%d lineconfig=%s/%s/%s (0x%X) sync=%d\n",
+ IS_NT(xpd)?"NT":"TE",
+ lc->span,
+ lc->name,
+ lc->lbo,
+ framingstr, codingstr, crcstr,
+ lc->lineconfig,
+ lc->sync);
+ /*
+ * FIXME: validate
+ */
+ span->lineconfig = lc->lineconfig;
+ return 0;
+}
+
+/*
+ * Set signalling type (if appropriate)
+ * Called from zaptel with spinlock held on chan. Must not call back
+ * zaptel functions.
+ */
+static int bri_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ DBG(GENERAL, "channel %d (%s) -> %s\n", chan->channo, chan->name, sig2str(sigtype));
+ // FIXME: sanity checks:
+ // - should be supported (within the sigcap)
+ // - should not replace fxs <->fxo ??? (covered by previous?)
+ return 0;
+}
+
+/*
+ * Called only for 'span' keyword in /etc/zaptel.conf
+ */
+static int bri_startup(struct zt_span *span)
+{
+ xpd_t *xpd = span->pvt;
+ struct BRI_priv_data *priv;
+ struct zt_chan *dchan;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(!TRANSPORT_RUNNING(xpd->xbus)) {
+ XPD_DBG(GENERAL, xpd, "Startup called by zaptel. No Hardware. Ignored\n");
+ return -ENODEV;
+ }
+ XPD_DBG(GENERAL, xpd, "STARTUP\n");
+ // Turn on all channels
+ CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1);
+ if(SPAN_REGISTERED(xpd)) {
+ dchan = &span->chans[2];
+ span->flags |= ZT_FLAG_RUNNING;
+ /*
+ * Zaptel (wrongly) assume that D-Channel need HDLC decoding
+ * and during zaptel registration override our flags.
+ *
+ * Don't Get Mad, Get Even: Now we override zaptel :-)
+ */
+ dchan->flags |= ZT_FLAG_BRIDCHAN;
+ dchan->flags &= ~ZT_FLAG_HDLC;
+ }
+ return 0;
+}
+
+/*
+ * Called only for 'span' keyword in /etc/zaptel.conf
+ */
+static int bri_shutdown(struct zt_span *span)
+{
+ xpd_t *xpd = span->pvt;
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(!TRANSPORT_RUNNING(xpd->xbus)) {
+ XPD_DBG(GENERAL, xpd, "Shutdown called by zaptel. No Hardware. Ignored\n");
+ return -ENODEV;
+ }
+ XPD_DBG(GENERAL, xpd, "SHUTDOWN\n");
+ // Turn off all channels
+ CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 0);
+ return 0;
+}
+
+static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t wanted_lines, xpacket_t *pack)
+{
+ byte *pcm;
+ struct zt_chan *chans;
+ unsigned long flags;
+ int i;
+ int subunit;
+ xpp_line_t pcm_mask = 0;
+
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ BUG_ON(!pack);
+ pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
+ for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) {
+ xpd_t *tmp_xpd;
+
+ tmp_xpd = xpd_byaddr(xbus, xpd->addr.unit, subunit);
+ if(!tmp_xpd || !tmp_xpd->card_present)
+ continue;
+ spin_lock_irqsave(&tmp_xpd->lock, flags);
+ chans = tmp_xpd->span.chans;
+ for_each_line(tmp_xpd, i) {
+ if(IS_SET(wanted_lines, i)) {
+ if(SPAN_REGISTERED(tmp_xpd)) {
+#ifdef DEBUG_PCMTX
+ if(pcmtx >= 0 && pcmtx_chan == i)
+ memset((u_char *)pcm, pcmtx, ZT_CHUNKSIZE);
+ else
+#endif
+ memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE);
+ // fill_beep((u_char *)pcm, tmp_xpd->addr.subunit, 2);
+ } else
+ memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE);
+ pcm += ZT_CHUNKSIZE;
+ }
+ }
+ pcm_mask |= PCM_SHIFT(wanted_lines, subunit);
+ XPD_COUNTER(tmp_xpd, PCM_WRITE)++;
+ spin_unlock_irqrestore(&tmp_xpd->lock, flags);
+ }
+ RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = pcm_mask;
+}
+
+static void BRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
+{
+ byte *pcm;
+ xpp_line_t pcm_mask;
+ unsigned long flags;
+ int subunit;
+ int i;
+
+ /*
+ * Subunit 0 handle all other subunits
+ */
+ if(xpd->addr.subunit != 0)
+ return;
+ if(!SPAN_REGISTERED(xpd))
+ return;
+ pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm);
+ pcm_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines);
+ for(subunit = 0; subunit < MAX_SUBUNIT; subunit++, pcm_mask >>= SUBUNIT_PCM_SHIFT) {
+ xpd_t *tmp_xpd;
+
+ if(!pcm_mask)
+ break; /* optimize */
+ tmp_xpd = xpd_byaddr(xbus, xpd->addr.unit, subunit);
+ if(!tmp_xpd || !tmp_xpd->card_present || !SPAN_REGISTERED(tmp_xpd))
+ continue;
+ spin_lock_irqsave(&tmp_xpd->lock, flags);
+ for (i = 0; i < 2; i++) {
+ xpp_line_t tmp_mask = pcm_mask & (BIT(0) | BIT(1));
+ volatile u_char *r;
+
+ if(IS_SET(tmp_mask, i)) {
+ r = tmp_xpd->span.chans[i].readchunk;
+ // memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG
+ // fill_beep((u_char *)r, 1, 1); // DEBUG: BEEP
+ memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
+ pcm += ZT_CHUNKSIZE;
+ }
+ }
+ XPD_COUNTER(tmp_xpd, PCM_READ)++;
+ spin_unlock_irqrestore(&tmp_xpd->lock, flags);
+ }
+}
+
+/*---------------- BRI: HOST COMMANDS -------------------------------------*/
+
+static /* 0x0F */ HOSTCMD(BRI, XPD_STATE, bool on)
+{
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF");
+ if(on) {
+ if(!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags)) {
+ if(xpd->direction == TO_PSTN)
+ te_activation(xpd, 1);
+ else
+ nt_activation(xpd, 1);
+ }
+ } else if(IS_NT(xpd))
+ nt_activation(xpd, 0);
+ return 0;
+}
+
+static /* 0x33 */ HOSTCMD(BRI, SET_LED, enum bri_led_names which_led, enum led_state to_led_state)
+{
+ int ret = 0;
+ xframe_t *xframe;
+ xpacket_t *pack;
+ struct bri_leds *bri_leds;
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xbus);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ XPD_DBG(LEDS, xpd, "%s -> %d\n",
+ (which_led)?"RED":"GREEN",
+ to_led_state);
+ XFRAME_NEW_CMD(xframe, pack, xbus, BRI, SET_LED, xpd->xbus_idx);
+ bri_leds = &RPACKET_FIELD(pack, BRI, SET_LED, bri_leds);
+ bri_leds->state = to_led_state;
+ bri_leds->led_sel = which_led;
+ XPACKET_LEN(pack) = RPACKET_SIZE(BRI, SET_LED);
+ ret = send_cmd_frame(xbus, xframe);
+ priv->ledstate[which_led] = to_led_state;
+ return ret;
+}
+
+static int write_state_register(xpd_t *xpd, byte value)
+{
+ int ret;
+
+ XPD_DBG(REGS, xpd, "value = 0x%02X\n", value);
+ ret = xpp_register_request(xpd->xbus, xpd,
+ BRI_PORT(xpd), /* portno */
+ 1, /* writing */
+ A_SU_WR_STA, /* regnum */
+ 0, /* do_subreg */
+ 0, /* subreg */
+ value, /* data_low */
+ 0, /* do_datah */
+ 0, /* data_high */
+ 0 /* should_reply */
+ );
+ return ret;
+}
+
+/*---------------- BRI: Astribank Reply Handlers --------------------------*/
+static void su_new_state(xpd_t *xpd, byte reg_x30)
+{
+ xbus_t *xbus;
+ struct BRI_priv_data *priv;
+ su_rd_sta_t new_state;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ xbus = xpd->xbus;
+ if(!priv->initialized) {
+ XPD_ERR(xpd, "%s called on uninitialized AB\n", __FUNCTION__);
+ return;
+ }
+ new_state.reg = reg_x30;
+ if(new_state.bits.v_su_t2_exp) {
+ XPD_NOTICE(xpd, "T2 Expired\n");
+ }
+ priv->reg30_ticks = 0;
+ priv->reg30_good = 1;
+ if (priv->state_register.bits.v_su_sta == new_state.bits.v_su_sta)
+ return; /* same same */
+ XPD_DBG(SIGNAL, xpd, "%02X ---> %02X (info0=%d) (%s%i)\n",
+ priv->state_register.reg,
+ reg_x30,
+ new_state.bits.v_su_info0,
+ IS_NT(xpd)?"G":"F",
+ new_state.bits.v_su_sta);
+ if(!IS_NT(xpd)) {
+ switch (new_state.bits.v_su_sta) {
+ case ST_TE_DEACTIVATED: /* F3 */
+ XPD_DBG(SIGNAL, xpd, "State ST_TE_DEACTIVATED (F3)\n");
+ clear_bit(HFC_L1_ACTIVATED, &priv->l1_flags);
+ layer1_state(xpd, 0);
+ break;
+ case ST_TE_SIGWAIT: /* F4 */
+ XPD_DBG(SIGNAL, xpd, "State ST_TE_SIGWAIT (F4)\n");
+ layer1_state(xpd, 0);
+ break;
+ case ST_TE_IDENT: /* F5 */
+ XPD_DBG(SIGNAL, xpd, "State ST_TE_IDENT (F5)\n");
+ layer1_state(xpd, 0);
+ break;
+ case ST_TE_SYNCED: /* F6 */
+ XPD_DBG(SIGNAL, xpd, "State ST_TE_SYNCED (F6)\n");
+ layer1_state(xpd, 0);
+ break;
+ case ST_TE_ACTIVATED: /* F7 */
+ XPD_DBG(SIGNAL, xpd, "State ST_TE_ACTIVATED (F7)\n");
+ set_bri_timer(xpd, "T3", &priv->t3, HFC_TIMER_OFF);
+ clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
+ set_bit(HFC_L1_ACTIVATED, &priv->l1_flags);
+ layer1_state(xpd, 1);
+ update_xpd_status(xpd, ZT_ALARM_NONE);
+ break;
+ case ST_TE_LOST_FRAMING: /* F8 */
+ XPD_DBG(SIGNAL, xpd, "State ST_TE_LOST_FRAMING (F8)\n");
+ layer1_state(xpd, 0);
+ break;
+ default:
+ XPD_NOTICE(xpd, "Bad TE state: %d\n", new_state.bits.v_su_sta);
+ break;
+ }
+
+ } else {
+ switch (new_state.bits.v_su_sta) {
+ case ST_NT_DEACTIVATED: /* G1 */
+ XPD_DBG(SIGNAL, xpd, "State ST_NT_DEACTIVATED (G1)\n");
+ clear_bit(HFC_L1_ACTIVATED, &priv->l1_flags);
+ set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF);
+ layer1_state(xpd, 0);
+ break;
+ case ST_NT_ACTIVATING: /* G2 */
+ XPD_DBG(SIGNAL, xpd, "State ST_NT_ACTIVATING (G2)\n");
+ layer1_state(xpd, 0);
+ if(!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags))
+ nt_activation(xpd, 1);
+ break;
+ case ST_NT_ACTIVATED: /* G3 */
+ XPD_DBG(SIGNAL, xpd, "State ST_NT_ACTIVATED (G3)\n");
+ clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
+ set_bit(HFC_L1_ACTIVATED, &priv->l1_flags);
+ set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF);
+ layer1_state(xpd, 1);
+ update_xpd_status(xpd, ZT_ALARM_NONE);
+ break;
+ case ST_NT_DEACTIVTING: /* G4 */
+ XPD_DBG(SIGNAL, xpd, "State ST_NT_DEACTIVTING (G4)\n");
+ set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF);
+ layer1_state(xpd, 0);
+ break;
+ default:
+ XPD_NOTICE(xpd, "Bad NT state: %d\n", new_state.bits.v_su_sta);
+ break;
+ }
+ }
+ priv->state_register.reg = new_state.reg;
+}
+
+static int BRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
+{
+ unsigned long flags;
+ struct BRI_priv_data *priv;
+ struct xpd_addr addr;
+ xpd_t *orig_xpd;
+ int ret;
+
+ /* Map UNIT + PORTNUM to XPD */
+ orig_xpd = xpd;
+ addr.unit = orig_xpd->addr.unit;
+ addr.subunit = info->portnum;
+ xpd = xpd_byaddr(xbus, addr.unit, addr.subunit);
+ if(!xpd) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) < 5)
+ notify_bad_xpd(__FUNCTION__, xbus, addr , orig_xpd->xpdname);
+ return -EPROTO;
+ }
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(REG_FIELD(info, do_subreg)) {
+ XPD_DBG(REGS, xpd, "RI %02X %02X %02X\n",
+ REG_FIELD(info, regnum), REG_FIELD(info, subreg), REG_FIELD(info, data_low));
+ } else {
+ if (REG_FIELD(info, regnum) != A_SU_RD_STA)
+ XPD_DBG(REGS, xpd, "RD %02X %02X\n",
+ REG_FIELD(info, regnum), REG_FIELD(info, data_low));
+ else
+ XPD_DBG(REGS, xpd, "Got SU_RD_STA=%02X\n",
+ REG_FIELD(info, data_low));
+ }
+ if(info->is_multibyte) {
+ XPD_DBG(REGS, xpd, "Got Multibyte: %d bytes, eoframe: %d\n",
+ info->bytes, info->eoframe);
+ ret = rx_dchan(xpd, info);
+ if (ret < 0) {
+ priv->dchan_rx_drops++;
+ if(atomic_read(&xpd->open_counter) > 0)
+ XPD_NOTICE(xpd, "Multibyte Drop: errno=%d\n", ret);
+ }
+ goto end;
+ }
+ if(REG_FIELD(info, regnum) == A_SU_RD_STA) {
+ su_new_state(xpd, REG_FIELD(info, data_low));
+ }
+
+ /* Update /proc info only if reply relate to the last slic read request */
+ if(
+ REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) &&
+ REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) &&
+ REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) {
+ xpd->last_reply = *info;
+ }
+
+end:
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return 0;
+}
+
+static xproto_table_t PROTO_TABLE(BRI) = {
+ .owner = THIS_MODULE,
+ .entries = {
+ /* Table Card Opcode */
+ },
+ .name = "BRI", /* protocol name */
+ .ports_per_subunit = 1,
+ .type = XPD_TYPE_BRI,
+ .xops = {
+ .card_new = BRI_card_new,
+ .card_init = BRI_card_init,
+ .card_remove = BRI_card_remove,
+ .card_zaptel_preregistration = BRI_card_zaptel_preregistration,
+ .card_zaptel_postregistration = BRI_card_zaptel_postregistration,
+ .card_hooksig = BRI_card_hooksig,
+ .card_tick = BRI_card_tick,
+ .card_pcm_fromspan = BRI_card_pcm_fromspan,
+ .card_pcm_tospan = BRI_card_pcm_tospan,
+ .card_ioctl = BRI_card_ioctl,
+ .card_close = BRI_card_close,
+ .card_register_reply = BRI_card_register_reply,
+
+ .XPD_STATE = XPROTO_CALLER(BRI, XPD_STATE),
+ },
+ .packet_is_valid = bri_packet_is_valid,
+ .packet_dump = bri_packet_dump,
+};
+
+static bool bri_packet_is_valid(xpacket_t *pack)
+{
+ const xproto_entry_t *xe = NULL;
+ // DBG(GENERAL, "\n");
+ xe = xproto_card_entry(&PROTO_TABLE(BRI), XPACKET_OP(pack));
+ return xe != NULL;
+}
+
+static void bri_packet_dump(const char *msg, xpacket_t *pack)
+{
+ DBG(GENERAL, "%s\n", msg);
+}
+/*------------------------- REGISTER Handling --------------------------*/
+
+static int proc_bri_info_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xpd_t *xpd = data;
+ struct BRI_priv_data *priv;
+
+ DBG(PROC, "\n");
+ if(!xpd)
+ return -ENODEV;
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ len += sprintf(page + len, "%05d Layer 1: ", priv->poll_counter);
+ if(priv->reg30_good) {
+ len += sprintf(page + len, "%-5s ", (priv->layer1_up) ? "UP" : "DOWN");
+ len += sprintf(page + len, "%c%d %-15s -- fr_sync=%d t2_exp=%d info0=%d g2_g3=%d\n",
+ IS_NT(xpd)?'G':'F',
+ priv->state_register.bits.v_su_sta,
+ xhfc_state_name(IS_NT(xpd), priv->state_register.bits.v_su_sta),
+ priv->state_register.bits.v_su_fr_sync,
+ priv->state_register.bits.v_su_t2_exp,
+ priv->state_register.bits.v_su_info0,
+ priv->state_register.bits.v_g2_g3);
+ } else
+ len += sprintf(page + len, "Unkown\n");
+ if(IS_NT(xpd)) {
+ len += sprintf(page + len, "T1 Timer: %d\n", priv->t1);
+ } else {
+ len += sprintf(page + len, "T3 Timer: %d\n", priv->t3);
+ }
+ len += sprintf(page + len, "Tick Counter: %d\n", priv->tick_counter);
+ len += sprintf(page + len, "Last Poll Reply: %d ticks ago\n", priv->reg30_ticks);
+ len += sprintf(page + len, "reg30_good=%d\n", priv->reg30_good);
+ len += sprintf(page + len, "D-Channel: TX=[%5d] RX=[%5d] BAD=[%5d] ",
+ priv->dchan_tx_counter, priv->dchan_rx_counter, priv->dchan_rx_drops);
+ if(priv->dchan_alive) {
+ len += sprintf(page + len, "(alive %d K-ticks)\n",
+ priv->dchan_alive_ticks/1000);
+ } else {
+ len += sprintf(page + len, "(dead)\n");
+ }
+ len += sprintf(page + len, "dchan_notx_ticks: %d\n", priv->dchan_notx_ticks);
+ len += sprintf(page + len, "dchan_norx_ticks: %d\n", priv->dchan_norx_ticks);
+ len += sprintf(page + len, "LED: %-10s = %d\n", "GREEN", priv->ledstate[GREEN_LED]);
+ len += sprintf(page + len, "LED: %-10s = %d\n", "RED", priv->ledstate[RED_LED]);
+ len += sprintf(page + len, "\nDCHAN:\n");
+ len += sprintf(page + len, "\n");
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+}
+
+static int __init card_bri_startup(void)
+{
+ DBG(GENERAL, "\n");
+
+ INFO("revision %s\n", XPP_VERSION);
+ xproto_register(&PROTO_TABLE(BRI));
+ return 0;
+}
+
+static void __exit card_bri_cleanup(void)
+{
+ DBG(GENERAL, "\n");
+ xproto_unregister(&PROTO_TABLE(BRI));
+}
+
+MODULE_DESCRIPTION("XPP BRI Card Driver");
+MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(XPP_VERSION);
+MODULE_ALIAS_XPD(XPD_TYPE_BRI);
+
+module_init(card_bri_startup);
+module_exit(card_bri_cleanup);
diff --git a/drivers/dahdi/xpp/card_bri.h b/drivers/dahdi/xpp/card_bri.h
new file mode 100644
index 0000000..a7b69de
--- /dev/null
+++ b/drivers/dahdi/xpp/card_bri.h
@@ -0,0 +1,31 @@
+#ifndef CARD_BRI_H
+#define CARD_BRI_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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 "xpd.h"
+
+enum bri_opcodes {
+ XPROTO_NAME(BRI, SET_LED) = 0x33,
+};
+
+#endif /* CARD_BRI_H */
diff --git a/drivers/dahdi/xpp/card_fxo.c b/drivers/dahdi/xpp/card_fxo.c
new file mode 100644
index 0000000..2e48dca
--- /dev/null
+++ b/drivers/dahdi/xpp/card_fxo.c
@@ -0,0 +1,1289 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include "xpd.h"
+#include "xproto.h"
+#include "xpp_zap.h"
+#include "card_fxo.h"
+#include "zap_debug.h"
+#include "xbus-core.h"
+
+static const char rcsid[] = "$Id$";
+
+static DEF_PARM(int, debug, 0, 0644, "Print DBG statements");
+static DEF_PARM(uint, poll_battery_interval, 500, 0644, "Poll battery interval in milliseconds (0 - disable)");
+#ifdef WITH_METERING
+static DEF_PARM(uint, poll_metering_interval, 500, 0644, "Poll metering interval in milliseconds (0 - disable)");
+#endif
+static DEF_PARM(int, ring_debounce, 50, 0644, "Number of ticks to debounce a false RING indication");
+static DEF_PARM(int, caller_id_style, 0, 0444, "Caller-Id detection style: 0 - [BELL], 1 - [BT], 2 - [PASS]");
+
+/* Backward compatibility plug */
+#ifndef ZT_GET_PARAMS_V1
+#define zt_alarm_channel(a,b) zt_qevent_lock(a,( (b)==ZT_ALARM_NONE )? \
+ ZT_EVENT_NOALARM : ZT_EVENT_ALARM)
+#endif
+
+enum cid_style {
+ CID_STYLE_BELL = 0, /* E.g: US (Bellcore) */
+ CID_STYLE_ETSI_POLREV = 1, /* E.g: UK (British Telecom) */
+ CID_STYLE_PASS_ALWAYS = 2, /* E.g: DK */
+};
+
+/* Signaling is opposite (fxs signalling for fxo card) */
+#if 1
+#define FXO_DEFAULT_SIGCAP (ZT_SIG_FXSKS | ZT_SIG_FXSLS)
+#else
+#define FXO_DEFAULT_SIGCAP (ZT_SIG_SF)
+#endif
+
+enum fxo_leds {
+ LED_GREEN,
+ LED_RED,
+};
+
+#define NUM_LEDS 2
+#define DELAY_UNTIL_DIALTONE 3000
+
+/*
+ * Minimum duration for polarity reversal detection (in ticks)
+ * Should be longer than the time to detect a ring, so voltage
+ * fluctuation during ring won't trigger false detection.
+ */
+#define POLREV_THRESHOLD 200
+#define BAT_THRESHOLD 3
+#define BAT_DEBOUNCE 1000 /* compensate for battery voltage fluctuation (in ticks) */
+#define POWER_DENIAL_CURRENT 3
+#define POWER_DENIAL_TIME 80 /* ticks */
+#define POWER_DENIAL_SAFEZONE 100 /* ticks */
+#define POWER_DENIAL_DELAY 2500 /* ticks */
+
+/* Shortcuts */
+#define DAA_WRITE 1
+#define DAA_READ 0
+#define DAA_DIRECT_REQUEST(xbus,xpd,port,writing,reg,dL) \
+ xpp_register_request((xbus), (xpd), (port), (writing), (reg), 0, 0, (dL), 0, 0, 0)
+
+/*---------------- FXO Protocol Commands ----------------------------------*/
+
+static /* 0x0F */ DECLARE_CMD(FXO, XPD_STATE, bool on);
+
+static bool fxo_packet_is_valid(xpacket_t *pack);
+static void fxo_packet_dump(const char *msg, xpacket_t *pack);
+static int proc_fxo_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
+#ifdef WITH_METERING
+static int proc_xpd_metering_read(char *page, char **start, off_t off, int count, int *eof, void *data);
+#endif
+static void zap_report_battery(xpd_t *xpd, lineno_t chan);
+
+#define PROC_REGISTER_FNAME "slics"
+#define PROC_FXO_INFO_FNAME "fxo_info"
+#ifdef WITH_METERING
+#define PROC_METERING_FNAME "metering_read"
+#endif
+
+#define REG_DAA_CONTROL1 0x05 /* 5 - DAA Control 1 */
+#define REG_DAA_CONTROL1_OH BIT(0) /* Off-Hook. */
+#define REG_DAA_CONTROL1_ONHM BIT(3) /* On-Hook Line Monitor */
+
+#define DAA_REG_METERING 0x11 /* 17 */
+#define DAA_REG_CURRENT 0x1C /* 28 */
+#define DAA_REG_VBAT 0x1D /* 29 */
+
+enum battery_state {
+ BATTERY_UNKNOWN = 0,
+ BATTERY_ON = 1,
+ BATTERY_OFF = -1
+};
+
+enum polarity_state {
+ POL_UNKNOWN = 0,
+ POL_POSITIVE = 1,
+ POL_NEGATIVE = -1
+};
+
+enum power_state {
+ POWER_UNKNOWN = 0,
+ POWER_ON = 1,
+ POWER_OFF = -1
+};
+
+struct FXO_priv_data {
+#ifdef WITH_METERING
+ struct proc_dir_entry *meteringfile;
+#endif
+ struct proc_dir_entry *fxo_info;
+ uint poll_counter;
+ signed char battery_voltage[CHANNELS_PERXPD];
+ signed char battery_current[CHANNELS_PERXPD];
+ enum battery_state battery[CHANNELS_PERXPD];
+ ushort nobattery_debounce[CHANNELS_PERXPD];
+ enum polarity_state polarity[CHANNELS_PERXPD];
+ ushort polarity_debounce[CHANNELS_PERXPD];
+ enum power_state power[CHANNELS_PERXPD];
+ xpp_line_t maybe_power_denial;
+ ushort power_denial_debounce[CHANNELS_PERXPD];
+ ushort power_denial_delay[CHANNELS_PERXPD];
+ ushort power_denial_minimum[CHANNELS_PERXPD];
+ ushort power_denial_safezone[CHANNELS_PERXPD];
+ xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
+ xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */
+ int led_counter[NUM_LEDS][CHANNELS_PERXPD];
+ atomic_t ring_debounce[CHANNELS_PERXPD];
+#ifdef WITH_METERING
+ uint metering_count[CHANNELS_PERXPD];
+ xpp_line_t metering_tone_state;
+#endif
+};
+
+/*
+ * LED counter values:
+ * n>1 : BLINK every n'th tick
+ */
+#define LED_COUNTER(priv,pos,color) ((priv)->led_counter[color][pos])
+#define IS_BLINKING(priv,pos,color) (LED_COUNTER(priv,pos,color) > 0)
+#define MARK_BLINK(priv,pos,color,t) ((priv)->led_counter[color][pos] = (t))
+#define MARK_OFF(priv,pos,color) do { BIT_CLR((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0)
+#define MARK_ON(priv,pos,color) do { BIT_SET((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0)
+
+#define LED_BLINK_RING (1000/8) /* in ticks */
+
+/*---------------- FXO: Static functions ----------------------------------*/
+
+static void reset_battery_readings(xpd_t *xpd, lineno_t pos)
+{
+ struct FXO_priv_data *priv = xpd->priv;
+
+ priv->nobattery_debounce[pos] = 0;
+ priv->power_denial_debounce[pos] = 0;
+ priv->power_denial_delay[pos] = 0;
+ BIT_CLR(priv->maybe_power_denial, pos);
+}
+
+static const int led_register_mask[] = { BIT(7), BIT(6), BIT(5) };
+
+/*
+ * LED control is done via DAA register 0x20
+ */
+static int do_led(xpd_t *xpd, lineno_t chan, byte which, bool on)
+{
+ int ret = 0;
+ struct FXO_priv_data *priv;
+ xbus_t *xbus;
+ byte value;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ which = which % NUM_LEDS;
+ if(IS_SET(xpd->digital_outputs, chan) || IS_SET(xpd->digital_inputs, chan))
+ goto out;
+ if(chan == PORT_BROADCAST) {
+ priv->ledstate[which] = (on) ? ~0 : 0;
+ } else {
+ if(on) {
+ BIT_SET(priv->ledstate[which], chan);
+ } else {
+ BIT_CLR(priv->ledstate[which], chan);
+ }
+ }
+ value = 0;
+ value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]);
+ value |= (on) ? BIT(0) : 0;
+ value |= (on) ? BIT(1) : 0;
+ LINE_DBG(LEDS, xpd, chan, "LED: which=%d -- %s\n", which, (on) ? "on" : "off");
+ ret = DAA_DIRECT_REQUEST(xbus, xpd, chan, DAA_WRITE, 0x20, value);
+out:
+ return ret;
+}
+
+static void handle_fxo_leds(xpd_t *xpd)
+{
+ int i;
+ unsigned long flags;
+ const enum fxo_leds colors[] = { LED_GREEN, LED_RED };
+ enum fxo_leds color;
+ unsigned int timer_count;
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xpd);
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+ timer_count = xpd->timer_count;
+ for(color = 0; color < ARRAY_SIZE(colors); color++) {
+ for_each_line(xpd, i) {
+ if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
+ continue;
+ if((xpd->blink_mode & BIT(i)) || IS_BLINKING(priv, i, color)) { // Blinking
+ int mod_value = LED_COUNTER(priv, i, color);
+
+ if(!mod_value)
+ mod_value = DEFAULT_LED_PERIOD; /* safety value */
+ // led state is toggled
+ if((timer_count % mod_value) == 0) {
+ LINE_DBG(LEDS, xpd, i, "ledstate=%s\n", (IS_SET(priv->ledstate[color], i))?"ON":"OFF");
+ if(!IS_SET(priv->ledstate[color], i)) {
+ do_led(xpd, i, color, 1);
+ } else {
+ do_led(xpd, i, color, 0);
+ }
+ }
+ } else if(IS_SET(priv->ledcontrol[color], i) && !IS_SET(priv->ledstate[color], i)) {
+ do_led(xpd, i, color, 1);
+ } else if(!IS_SET(priv->ledcontrol[color], i) && IS_SET(priv->ledstate[color], i)) {
+ do_led(xpd, i, color, 0);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+}
+
+static void update_zap_ring(xpd_t *xpd, int pos, bool on)
+{
+ zt_rxsig_t rxsig;
+
+ BUG_ON(!xpd);
+ if(on) {
+ if(caller_id_style == CID_STYLE_BELL) {
+ LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: off\n");
+ BIT_CLR(xpd->cid_on, pos);
+ }
+ rxsig = ZT_RXSIG_RING;
+ } else {
+ if(caller_id_style == CID_STYLE_BELL) {
+ LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: on\n");
+ BIT_SET(xpd->cid_on, pos);
+ }
+ rxsig = ZT_RXSIG_OFFHOOK;
+ }
+ pcm_recompute(xpd, 0);
+ /*
+ * We should not spinlock before calling zt_hooksig() as
+ * it may call back into our xpp_hooksig() and cause
+ * a nested spinlock scenario
+ */
+ if(SPAN_REGISTERED(xpd))
+ zt_hooksig(&xpd->chans[pos], rxsig);
+}
+
+static void mark_ring(xpd_t *xpd, lineno_t pos, bool on, bool update_zap)
+{
+ struct FXO_priv_data *priv;
+
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ atomic_set(&priv->ring_debounce[pos], 0); /* Stop debouncing */
+ /*
+ * We don't want to check battery during ringing
+ * due to voltage fluctuations.
+ */
+ reset_battery_readings(xpd, pos);
+ if(on && !xpd->ringing[pos]) {
+ LINE_DBG(SIGNAL, xpd, pos, "START\n");
+ xpd->ringing[pos] = 1;
+ MARK_BLINK(priv, pos, LED_GREEN, LED_BLINK_RING);
+ if(update_zap)
+ update_zap_ring(xpd, pos, on);
+ } else if(!on && xpd->ringing[pos]) {
+ LINE_DBG(SIGNAL, xpd, pos, "STOP\n");
+ xpd->ringing[pos] = 0;
+ if(IS_BLINKING(priv, pos, LED_GREEN))
+ MARK_BLINK(priv, pos, LED_GREEN, 0);
+ if(update_zap)
+ update_zap_ring(xpd, pos, on);
+ }
+}
+
+static int do_sethook(xpd_t *xpd, int pos, bool to_offhook)
+{
+ unsigned long flags;
+ xbus_t *xbus;
+ struct FXO_priv_data *priv;
+ int ret = 0;
+ byte value;
+
+ BUG_ON(!xpd);
+ BUG_ON(xpd->direction == TO_PHONE); // We can SETHOOK state only on PSTN
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(priv->battery[pos] != BATTERY_ON && to_offhook) {
+ LINE_NOTICE(xpd, pos, "Cannot take offhook while battery is off!\n");
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&xpd->lock, flags);
+ mark_ring(xpd, pos, 0, 0); // No more rings
+ value = REG_DAA_CONTROL1_ONHM; /* Bit 3 is for CID */
+ if(to_offhook)
+ value |= REG_DAA_CONTROL1_OH;
+ LINE_DBG(SIGNAL, xpd, pos, "SETHOOK: value=0x%02X %s\n", value, (to_offhook)?"OFFHOOK":"ONHOOK");
+ if(to_offhook)
+ MARK_ON(priv, pos, LED_GREEN);
+ else
+ MARK_OFF(priv, pos, LED_GREEN);
+ ret = DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, REG_DAA_CONTROL1, value);
+ if(to_offhook) {
+ BIT_SET(xpd->offhook, pos);
+ } else {
+ BIT_CLR(xpd->offhook, pos);
+ }
+ if(caller_id_style != CID_STYLE_PASS_ALWAYS) {
+ LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: off\n");
+ BIT_CLR(xpd->cid_on, pos);
+ }
+#ifdef WITH_METERING
+ priv->metering_count[pos] = 0;
+ priv->metering_tone_state = 0L;
+ DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, DAA_REG_METERING, 0x2D);
+#endif
+ reset_battery_readings(xpd, pos); /* unstable during hook changes */
+ priv->power_denial_safezone[pos] = (to_offhook) ? POWER_DENIAL_SAFEZONE : 0;
+ if(!to_offhook)
+ priv->power[pos] = POWER_UNKNOWN;
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return ret;
+}
+
+/*---------------- FXO: Methods -------------------------------------------*/
+
+static void fxo_proc_remove(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(PROC, xpd, "\n");
+#ifdef CONFIG_PROC_FS
+#ifdef WITH_METERING
+ if(priv->meteringfile) {
+ XPD_DBG(PROC, xpd, "Removing xpd metering tone file\n");
+ priv->meteringfile->data = NULL;
+ remove_proc_entry(PROC_METERING_FNAME, xpd->proc_xpd_dir);
+ priv->meteringfile = NULL;
+ }
+#endif
+ if(priv->fxo_info) {
+ XPD_DBG(PROC, xpd, "Removing xpd FXO_INFO file\n");
+ remove_proc_entry(PROC_FXO_INFO_FNAME, xpd->proc_xpd_dir);
+ priv->fxo_info = NULL;
+ }
+#endif
+}
+
+static int fxo_proc_create(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+#ifdef CONFIG_PROC_FS
+ XPD_DBG(PROC, xpd, "Creating FXO_INFO file\n");
+ priv->fxo_info = create_proc_read_entry(PROC_FXO_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_fxo_info_read, xpd);
+ if(!priv->fxo_info) {
+ XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_FXO_INFO_FNAME);
+ goto err;
+ }
+ priv->fxo_info->owner = THIS_MODULE;
+#ifdef WITH_METERING
+ XPD_DBG(PROC, xpd, "Creating Metering tone file\n");
+ priv->meteringfile = create_proc_read_entry(PROC_METERING_FNAME, 0444, xpd->proc_xpd_dir,
+ proc_xpd_metering_read, xpd);
+ if(!priv->meteringfile) {
+ XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_METERING_FNAME);
+ goto err;
+ }
+ priv->meteringfile->owner = THIS_MODULE;
+#endif
+#endif
+ return 0;
+err:
+ return -EINVAL;
+}
+
+static xpd_t *FXO_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, bool to_phone)
+{
+ xpd_t *xpd = NULL;
+ int channels;
+
+ if(to_phone) {
+ XBUS_NOTICE(xbus,
+ "XPD=%d%d: try to instanciate FXO with reverse direction\n",
+ unit, subunit);
+ return NULL;
+ }
+ if(subtype == 2)
+ channels = min(2, CHANNELS_PERXPD);
+ else
+ channels = min(8, CHANNELS_PERXPD);
+ xpd = xpd_alloc(sizeof(struct FXO_priv_data), proto_table, channels);
+ if(!xpd)
+ return NULL;
+ xpd->direction = TO_PSTN;
+ xpd->type_name = "FXO";
+ if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0)
+ goto err;
+ if(fxo_proc_create(xbus, xpd) < 0)
+ goto err;
+ return xpd;
+err:
+ xpd_free(xpd);
+ return NULL;
+}
+
+static int FXO_card_init(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXO_priv_data *priv;
+ int i;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ // Hanghup all lines
+ for_each_line(xpd, i) {
+ do_sethook(xpd, i, 0);
+ priv->polarity[i] = POL_UNKNOWN; /* will be updated on next battery sample */
+ priv->battery[i] = BATTERY_UNKNOWN; /* will be updated on next battery sample */
+ priv->power[i] = POWER_UNKNOWN; /* will be updated on next battery sample */
+ }
+ XPD_DBG(GENERAL, xpd, "done\n");
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 0);
+ }
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 1);
+ msleep(50);
+ }
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 0);
+ msleep(50);
+ }
+ pcm_recompute(xpd, 0);
+ return 0;
+}
+
+static int FXO_card_remove(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(GENERAL, xpd, "\n");
+ fxo_proc_remove(xbus, xpd);
+ return 0;
+}
+
+static int FXO_card_zaptel_preregistration(xpd_t *xpd, bool on)
+{
+ xbus_t *xbus;
+ struct FXO_priv_data *priv;
+ int i;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF");
+#ifdef ZT_SPANSTAT_V2
+ xpd->span.spantype = "FXO";
+#endif
+ for_each_line(xpd, i) {
+ struct zt_chan *cur_chan = &xpd->chans[i];
+
+ XPD_DBG(GENERAL, xpd, "setting FXO channel %d\n", i);
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXO/%02d/%1d%1d/%d",
+ xbus->num, xpd->addr.unit, xpd->addr.subunit, i);
+ cur_chan->chanpos = i + 1;
+ cur_chan->pvt = xpd;
+ cur_chan->sigcap = FXO_DEFAULT_SIGCAP;
+ }
+ for_each_line(xpd, i) {
+ MARK_ON(priv, i, LED_GREEN);
+ msleep(4);
+ MARK_ON(priv, i, LED_RED);
+ }
+ return 0;
+}
+
+static int FXO_card_zaptel_postregistration(xpd_t *xpd, bool on)
+{
+ xbus_t *xbus;
+ struct FXO_priv_data *priv;
+ int i;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF");
+ for_each_line(xpd, i) {
+ zap_report_battery(xpd, i);
+ MARK_OFF(priv, i, LED_GREEN);
+ msleep(2);
+ MARK_OFF(priv, i, LED_RED);
+ msleep(2);
+ }
+ return 0;
+}
+
+static int FXO_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
+{
+ struct FXO_priv_data *priv;
+ int ret = 0;
+
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ LINE_DBG(SIGNAL, xpd, pos, "%s\n", txsig2str(txsig));
+ BUG_ON(xpd->direction != TO_PSTN);
+ /* XXX Enable hooksig for FXO XXX */
+ switch(txsig) {
+ case ZT_TXSIG_START:
+ break;
+ case ZT_TXSIG_OFFHOOK:
+ ret = do_sethook(xpd, pos, 1);
+ break;
+ case ZT_TXSIG_ONHOOK:
+ ret = do_sethook(xpd, pos, 0);
+ break;
+ default:
+ XPD_NOTICE(xpd, "Can't set tx state to %s (%d)\n",
+ txsig2str(txsig), txsig);
+ return -EINVAL;
+ }
+ pcm_recompute(xpd, 0);
+ return ret;
+}
+
+static void zap_report_battery(xpd_t *xpd, lineno_t chan)
+{
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ if(SPAN_REGISTERED(xpd)) {
+ switch(priv->battery[chan]) {
+ case BATTERY_UNKNOWN:
+ /* no-op */
+ break;
+ case BATTERY_OFF:
+ LINE_DBG(SIGNAL, xpd, chan, "Send ZT_ALARM_RED\n");
+ zt_alarm_channel(&xpd->chans[chan], ZT_ALARM_RED);
+ break;
+ case BATTERY_ON:
+ LINE_DBG(SIGNAL, xpd, chan, "Send ZT_ALARM_NONE\n");
+ zt_alarm_channel(&xpd->chans[chan], ZT_ALARM_NONE);
+ break;
+ }
+ }
+}
+
+static int FXO_card_open(xpd_t *xpd, lineno_t chan)
+{
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ return 0;
+}
+
+static void poll_battery(xbus_t *xbus, xpd_t *xpd)
+{
+ int i;
+
+ for_each_line(xpd, i) {
+ DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_VBAT, 0);
+ }
+}
+
+#ifdef WITH_METERING
+static void poll_metering(xbus_t *xbus, xpd_t *xpd)
+{
+ int i;
+
+ for_each_line(xpd, i) {
+ if (IS_SET(xpd->offhook, i))
+ DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_METERING, 0);
+ }
+}
+#endif
+
+static void handle_fxo_ring(xpd_t *xpd)
+{
+ struct FXO_priv_data *priv;
+ int i;
+
+ priv = xpd->priv;
+ for_each_line(xpd, i) {
+ if(atomic_read(&priv->ring_debounce[i]) > 0) {
+ /* Maybe start ring */
+ if(atomic_dec_and_test(&priv->ring_debounce[i]))
+ mark_ring(xpd, i, 1, 1);
+ } else if (atomic_read(&priv->ring_debounce[i]) < 0) {
+ /* Maybe stop ring */
+ if(atomic_inc_and_test(&priv->ring_debounce[i]))
+ mark_ring(xpd, i, 0, 1);
+ }
+ }
+}
+
+static void handle_fxo_power_denial(xpd_t *xpd)
+{
+ struct FXO_priv_data *priv;
+ int i;
+
+ priv = xpd->priv;
+ for_each_line(xpd, i) {
+ if(priv->power_denial_minimum[i] > 0) {
+ priv->power_denial_minimum[i]--;
+ if(priv->power_denial_minimum[i] <= 0) {
+ /*
+ * But maybe the FXS started to ring (and the firmware haven't
+ * detected it yet). This would cause false power denials.
+ * So we just flag it and schedule more ticks to wait.
+ */
+ LINE_DBG(SIGNAL, xpd, i, "Possible Power Denial Hangup\n");
+ priv->power_denial_debounce[i] = 0;
+ BIT_SET(priv->maybe_power_denial, i);
+ }
+ }
+ if(priv->power_denial_safezone[i] > 0) {
+ if(--priv->power_denial_safezone[i]) {
+ /*
+ * Poll current, previous answers are meaningless
+ */
+ DAA_DIRECT_REQUEST(xpd->xbus, xpd, i, DAA_READ, DAA_REG_CURRENT, 0);
+ }
+ }
+ if(IS_SET(priv->maybe_power_denial, i) && !xpd->ringing[i] && IS_SET(xpd->offhook, i)) {
+ /*
+ * Ring detection by the firmware takes some time.
+ * Therefore we delay our decision until we are
+ * sure that no ring has started during this time.
+ */
+ priv->power_denial_delay[i]++;
+ if (priv->power_denial_delay[i] >= POWER_DENIAL_DELAY) {
+ LINE_DBG(SIGNAL, xpd, i, "Power Denial Hangup\n");
+ priv->power_denial_delay[i] = 0;
+ BIT_CLR(priv->maybe_power_denial, i);
+ do_sethook(xpd, i, 0);
+ update_line_status(xpd, i, 0);
+ pcm_recompute(xpd, 0);
+ }
+ } else {
+ priv->power_denial_delay[i] = 0;
+ BIT_CLR(priv->maybe_power_denial, i);
+ }
+ }
+}
+
+static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(poll_battery_interval != 0 && (priv->poll_counter % poll_battery_interval) == 0)
+ poll_battery(xbus, xpd);
+#ifdef WITH_METERING
+ if(poll_metering_interval != 0 && (priv->poll_counter % poll_metering_interval) == 0)
+ poll_metering(xbus, xpd);
+#endif
+ handle_fxo_leds(xpd);
+ handle_fxo_ring(xpd);
+ handle_fxo_power_denial(xpd);
+ priv->poll_counter++;
+ return 0;
+}
+
+/* FIXME: based on data from from wctdm.h */
+#include <wctdm.h>
+/*
+ * The first register is the ACIM, the other are coefficient registers.
+ * We define the array size explicitly to track possible inconsistencies
+ * if the struct is modified.
+ */
+static const char echotune_regs[sizeof(struct wctdm_echo_coefs)] = {30, 45, 46, 47, 48, 49, 50, 51, 52};
+
+static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
+{
+ int i,ret;
+ unsigned char echotune_data[ARRAY_SIZE(echotune_regs)];
+
+ BUG_ON(!xpd);
+ if(!TRANSPORT_RUNNING(xpd->xbus))
+ return -ENODEV;
+ switch (cmd) {
+ case WCTDM_SET_ECHOTUNE:
+ XPD_DBG(GENERAL, xpd, "-- Setting echo registers: \n");
+ /* first off: check if this span is fxs. If not: -EINVALID */
+ if (copy_from_user(&echotune_data, (void __user *)arg, sizeof(echotune_data)))
+ return -EFAULT;
+
+ for (i = 0; i < ARRAY_SIZE(echotune_regs); i++) {
+ XPD_DBG(REGS, xpd, "Reg=0x%02X, data=0x%02X\n", echotune_regs[i], echotune_data[i]);
+ ret = DAA_DIRECT_REQUEST(xpd->xbus, xpd, pos, DAA_WRITE, echotune_regs[i], echotune_data[i]);
+ if (ret < 0) {
+ LINE_NOTICE(xpd, pos, "Couldn't write %0x02X to register %0x02X\n",
+ echotune_data[i], echotune_regs[i]);
+ return ret;
+ }
+ msleep(1);
+ }
+
+ XPD_DBG(GENERAL, xpd, "-- Set echo registers successfully\n");
+ break;
+ case ZT_TONEDETECT:
+ /*
+ * Asterisk call all span types with this (FXS specific)
+ * call. Silently ignore it.
+ */
+ LINE_DBG(GENERAL, xpd, pos,
+ "ZT_TONEDETECT (FXO: NOTIMPLEMENTED)\n");
+ return -ENOTTY;
+ default:
+ report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd);
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+/*---------------- FXO: HOST COMMANDS -------------------------------------*/
+
+static /* 0x0F */ HOSTCMD(FXO, XPD_STATE, bool on)
+{
+ int ret = 0;
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on) ? "on" : "off");
+ return ret;
+}
+
+/*---------------- FXO: Astribank Reply Handlers --------------------------*/
+
+HANDLER_DEF(FXO, SIG_CHANGED)
+{
+ xpp_line_t sig_status = RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_status);
+ xpp_line_t sig_toggles = RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_toggles);
+ unsigned long flags;
+ int i;
+ struct FXO_priv_data *priv;
+
+ if(!xpd) {
+ notify_bad_xpd(__FUNCTION__, xbus, XPACKET_ADDR(pack), cmd->name);
+ return -EPROTO;
+ }
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ XPD_DBG(SIGNAL, xpd, "(PSTN) sig_toggles=0x%04X sig_status=0x%04X\n", sig_toggles, sig_status);
+ spin_lock_irqsave(&xpd->lock, flags);
+ for_each_line(xpd, i) {
+ int debounce;
+
+ if(IS_SET(sig_toggles, i)) {
+ if(priv->battery[i] == BATTERY_OFF) {
+ /*
+ * With poll_battery_interval==0 we cannot have BATTERY_OFF
+ * so we won't get here
+ */
+ LINE_NOTICE(xpd, i, "SIG_CHANGED while battery is off. Ignored.\n");
+ continue;
+ }
+ /* First report false ring alarms */
+ debounce = atomic_read(&priv->ring_debounce[i]);
+ if(debounce)
+ LINE_NOTICE(xpd, i, "debounced false ring (only %d ticks)\n", debounce);
+ /*
+ * Now set a new ring alarm.
+ * It will be checked in handle_fxo_ring()
+ */
+ debounce = (IS_SET(sig_status, i)) ? ring_debounce : -ring_debounce;
+ atomic_set(&priv->ring_debounce[i], debounce);
+ }
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return 0;
+}
+
+static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno)
+{
+ struct FXO_priv_data *priv;
+ enum polarity_state pol;
+ int msec;
+
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ priv->battery_voltage[portno] = data_low;
+ if(xpd->ringing[portno])
+ goto ignore_reading; /* ring voltage create false alarms */
+ if(abs((signed char)data_low) < BAT_THRESHOLD) {
+ /*
+ * Check for battery voltage fluctuations
+ */
+ if(priv->battery[portno] != BATTERY_OFF) {
+ int milliseconds;
+
+ milliseconds = priv->nobattery_debounce[portno]++ *
+ poll_battery_interval;
+ if(milliseconds > BAT_DEBOUNCE) {
+ LINE_DBG(SIGNAL, xpd, portno, "BATTERY OFF voltage=%d\n", data_low);
+ priv->battery[portno] = BATTERY_OFF;
+ if(SPAN_REGISTERED(xpd))
+ zap_report_battery(xpd, portno);
+ priv->polarity[portno] = POL_UNKNOWN; /* What's the polarity ? */
+ priv->power[portno] = POWER_UNKNOWN; /* What's the current ? */
+ /*
+ * Stop further processing for now
+ */
+ goto ignore_reading;
+ }
+
+ }
+ } else {
+ priv->nobattery_debounce[portno] = 0;
+ if(priv->battery[portno] != BATTERY_ON) {
+ LINE_DBG(SIGNAL, xpd, portno, "BATTERY ON voltage=%d\n", data_low);
+ priv->battery[portno] = BATTERY_ON;
+ if(SPAN_REGISTERED(xpd))
+ zap_report_battery(xpd, portno);
+ }
+ }
+#if 0
+ /*
+ * Mark FXO ports without battery!
+ */
+ if(priv->battery[portno] != BATTERY_ON)
+ MARK_ON(priv, portno, LED_RED);
+ else
+ MARK_OFF(priv, portno, LED_RED);
+#endif
+ if(priv->battery[portno] != BATTERY_ON) {
+ priv->polarity[portno] = POL_UNKNOWN; /* What's the polarity ? */
+ return;
+ }
+ /*
+ * Handle reverse polarity
+ */
+ if(data_low == 0)
+ pol = POL_UNKNOWN;
+ else if(IS_SET(data_low, 7))
+ pol = POL_NEGATIVE;
+ else
+ pol = POL_POSITIVE;
+ if(priv->polarity[portno] == pol) {
+ /*
+ * Same polarity, reset debounce counter
+ */
+ priv->polarity_debounce[portno] = 0;
+ return;
+ }
+ /*
+ * Track polarity reversals and debounce spikes.
+ * Only reversals with long duration count.
+ */
+ msec = priv->polarity_debounce[portno]++ * poll_battery_interval;
+ if (msec >= POLREV_THRESHOLD) {
+ priv->polarity_debounce[portno] = 0;
+ if(pol != POL_UNKNOWN) {
+ char *polname = NULL;
+
+ if(pol == POL_POSITIVE)
+ polname = "Positive";
+ else if(pol == POL_NEGATIVE)
+ polname = "Negative";
+ else
+ BUG();
+ LINE_DBG(SIGNAL, xpd, portno,
+ "Polarity changed to %s\n", polname);
+ /*
+ * Inform zaptel/Asterisk:
+ * 1. Maybe used for hangup detection during offhook
+ * 2. In some countries used to report caller-id during onhook
+ * but before first ring.
+ */
+ if(caller_id_style == CID_STYLE_ETSI_POLREV) {
+ LINE_DBG(SIGNAL, xpd, portno, "Caller-ID PCM: on\n");
+ BIT_SET(xpd->cid_on, portno); /* will be cleared on ring/offhook */
+ }
+ if(SPAN_REGISTERED(xpd)) {
+ LINE_DBG(SIGNAL, xpd, portno,
+ "Send ZT_EVENT_POLARITY: %s\n", polname);
+ zt_qevent_lock(&xpd->chans[portno], ZT_EVENT_POLARITY);
+ }
+ }
+ priv->polarity[portno] = pol;
+ }
+ return;
+ignore_reading:
+ /*
+ * Reset debounce counters to prevent false alarms
+ */
+ reset_battery_readings(xpd, portno); /* unstable during hook changes */
+}
+
+static void update_battery_current(xpd_t *xpd, byte data_low, xportno_t portno)
+{
+ struct FXO_priv_data *priv;
+
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ priv->battery_current[portno] = data_low;
+ /*
+ * During ringing, current is not stable.
+ * During onhook there should not be current anyway.
+ */
+ if(xpd->ringing[portno] || !IS_SET(xpd->offhook, portno))
+ goto ignore_it;
+ /*
+ * Power denial with no battery voltage is meaningless
+ */
+ if(priv->battery[portno] != BATTERY_ON)
+ goto ignore_it;
+ /* Safe zone after offhook */
+ if(priv->power_denial_safezone[portno] > 0)
+ goto ignore_it;
+ if(data_low < POWER_DENIAL_CURRENT) {
+ if(priv->power[portno] == POWER_ON) {
+ LINE_DBG(SIGNAL, xpd, portno, "power: ON -> OFF\n");
+ priv->power[portno] = POWER_OFF;
+ priv->power_denial_minimum[portno] = POWER_DENIAL_TIME;
+ }
+ } else {
+ LINE_DBG(SIGNAL, xpd, portno, "power: ON\n");
+ priv->power[portno] = POWER_ON;
+ priv->power_denial_minimum[portno] = 0;
+ update_line_status(xpd, portno, 1);
+ }
+ return;
+ignore_it:
+ BIT_CLR(priv->maybe_power_denial, portno);
+ priv->power_denial_debounce[portno] = 0;
+}
+
+#ifdef WITH_METERING
+#define BTD_BIT BIT(0)
+
+static void update_metering_state(xpd_t *xpd, byte data_low, lineno_t portno)
+{
+ struct FXO_priv_data *priv;
+ bool metering_tone = data_low & BTD_BIT;
+ bool old_metering_tone;
+
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ old_metering_tone = IS_SET(priv->metering_tone_state, portno);
+ LINE_DBG(SIGNAL, xpd, portno, "METERING: %s [dL=0x%X] (%d)\n",
+ (metering_tone) ? "ON" : "OFF",
+ data_low, priv->metering_count[portno]);
+ if(metering_tone && !old_metering_tone) {
+ /* Rising edge */
+ priv->metering_count[portno]++;
+ BIT_SET(priv->metering_tone_state, portno);
+ } else if(!metering_tone && old_metering_tone)
+ BIT_CLR(priv->metering_tone_state, portno);
+ if(metering_tone) {
+ /* Clear the BTD bit */
+ data_low &= ~BTD_BIT;
+ DAA_DIRECT_REQUEST(xpd->xbus, xpd, portno, DAA_WRITE, DAA_REG_METERING, data_low);
+ }
+}
+#endif
+
+static int FXO_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
+{
+ struct FXO_priv_data *priv;
+ lineno_t portno;
+
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ portno = info->portnum;
+ switch(REG_FIELD(info, regnum)) {
+ case DAA_REG_VBAT:
+ update_battery_voltage(xpd, REG_FIELD(info, data_low), portno);
+ break;
+ case DAA_REG_CURRENT:
+ update_battery_current(xpd, REG_FIELD(info, data_low), portno);
+ break;
+#ifdef WITH_METERING
+ case DAA_REG_METERING:
+ update_metering_state(xpd, REG_FIELD(info, data_low), portno);
+ break;
+#endif
+ }
+ LINE_DBG(REGS, xpd, portno, "%c reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
+ ((info->bytes == 3)?'I':'D'),
+ REG_FIELD(info, regnum),
+ REG_FIELD(info, data_low),
+ REG_FIELD(info, data_high));
+ /* Update /proc info only if reply relate to the last slic read request */
+ if(
+ REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) &&
+ REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) &&
+ REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) {
+ xpd->last_reply = *info;
+ }
+ return 0;
+}
+
+
+static xproto_table_t PROTO_TABLE(FXO) = {
+ .owner = THIS_MODULE,
+ .entries = {
+ /* Prototable Card Opcode */
+ XENTRY( FXO, FXO, SIG_CHANGED ),
+ },
+ .name = "FXO", /* protocol name */
+ .ports_per_subunit = 8,
+ .type = XPD_TYPE_FXO,
+ .xops = {
+ .card_new = FXO_card_new,
+ .card_init = FXO_card_init,
+ .card_remove = FXO_card_remove,
+ .card_zaptel_preregistration = FXO_card_zaptel_preregistration,
+ .card_zaptel_postregistration = FXO_card_zaptel_postregistration,
+ .card_hooksig = FXO_card_hooksig,
+ .card_tick = FXO_card_tick,
+ .card_pcm_fromspan = generic_card_pcm_fromspan,
+ .card_pcm_tospan = generic_card_pcm_tospan,
+ .card_ioctl = FXO_card_ioctl,
+ .card_open = FXO_card_open,
+ .card_register_reply = FXO_card_register_reply,
+
+ .XPD_STATE = XPROTO_CALLER(FXO, XPD_STATE),
+ },
+ .packet_is_valid = fxo_packet_is_valid,
+ .packet_dump = fxo_packet_dump,
+};
+
+static bool fxo_packet_is_valid(xpacket_t *pack)
+{
+ const xproto_entry_t *xe;
+
+ //DBG(GENERAL, "\n");
+ xe = xproto_card_entry(&PROTO_TABLE(FXO), XPACKET_OP(pack));
+ return xe != NULL;
+}
+
+static void fxo_packet_dump(const char *msg, xpacket_t *pack)
+{
+ DBG(GENERAL, "%s\n", msg);
+}
+
+/*------------------------- DAA Handling --------------------------*/
+
+static int proc_fxo_info_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xpd_t *xpd = data;
+ struct FXO_priv_data *priv;
+ int i;
+
+ if(!xpd)
+ return -ENODEV;
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ len += sprintf(page + len, "\t%-17s: ", "Channel");
+ for_each_line(xpd, i) {
+ if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
+ len += sprintf(page + len, "%4d ", i % 10);
+ }
+ len += sprintf(page + len, "\nLeds:");
+ len += sprintf(page + len, "\n\t%-17s: ", "state");
+ for_each_line(xpd, i) {
+ if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
+ len += sprintf(page + len, " %d%d ",
+ IS_SET(priv->ledstate[LED_GREEN], i),
+ IS_SET(priv->ledstate[LED_RED], i));
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "blinking");
+ for_each_line(xpd, i) {
+ if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
+ len += sprintf(page + len, " %d%d ",
+ IS_BLINKING(priv,i,LED_GREEN),
+ IS_BLINKING(priv,i,LED_RED));
+ }
+ len += sprintf(page + len, "\nBattery-Data:");
+ len += sprintf(page + len, "\n\t%-17s: ", "voltage");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%4d ", priv->battery_voltage[i]);
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "current");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%4d ", priv->battery_current[i]);
+ }
+ len += sprintf(page + len, "\nBattery:");
+ len += sprintf(page + len, "\n\t%-17s: ", "on");
+ for_each_line(xpd, i) {
+ char *bat;
+
+ if(priv->battery[i] == BATTERY_ON)
+ bat = "+";
+ else if(priv->battery[i] == BATTERY_OFF)
+ bat = "-";
+ else
+ bat = ".";
+ len += sprintf(page + len, "%4s ", bat);
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "debounce");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%4d ", priv->nobattery_debounce[i]);
+ }
+ len += sprintf(page + len, "\nPolarity-Reverse:");
+ len += sprintf(page + len, "\n\t%-17s: ", "polarity");
+ for_each_line(xpd, i) {
+ char *polname;
+
+ if(priv->polarity[i] == POL_POSITIVE)
+ polname = "+";
+ else if(priv->polarity[i] == POL_NEGATIVE)
+ polname = "-";
+ else
+ polname = ".";
+ len += sprintf(page + len, "%4s ", polname);
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "debounce");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%4d ", priv->polarity_debounce[i]);
+ }
+ len += sprintf(page + len, "\nPower-Denial:");
+ len += sprintf(page + len, "\n\t%-17s: ", "power");
+ for_each_line(xpd, i) {
+ char *curr;
+
+ if(priv->power[i] == POWER_ON)
+ curr = "+";
+ else if(priv->power[i] == POWER_OFF)
+ curr = "-";
+ else
+ curr = ".";
+ len += sprintf(page + len, "%4s ", curr);
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "maybe");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%4d ", IS_SET(priv->maybe_power_denial, i));
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "debounce");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%4d ", priv->power_denial_debounce[i]);
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "safezone");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%4d ", priv->power_denial_safezone[i]);
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "delay");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%4d ", priv->power_denial_delay[i]);
+ }
+#ifdef WITH_METERING
+ len += sprintf(page + len, "\nMetering:");
+ len += sprintf(page + len, "\n\t%-17s: ", "count");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%4d ", priv->metering_count[i]);
+ }
+#endif
+ len += sprintf(page + len, "\n");
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+}
+
+#ifdef WITH_METERING
+static int proc_xpd_metering_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xpd_t *xpd = data;
+ struct FXO_priv_data *priv;
+ int i;
+
+ if(!xpd)
+ return -ENODEV;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ spin_lock_irqsave(&xpd->lock, flags);
+ len += sprintf(page + len, "# Chan\tMeter (since last read)\n");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%d\t%d\n",
+ i, priv->metering_count[i]);
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ /* Zero meters */
+ for_each_line(xpd, i)
+ priv->metering_count[i] = 0;
+ return len;
+}
+#endif
+
+static int __init card_fxo_startup(void)
+{
+ if(ring_debounce <= 0) {
+ ERR("ring_debounce=%d. Must be positive number of ticks\n", ring_debounce);
+ return -EINVAL;
+ }
+ INFO("revision %s\n", XPP_VERSION);
+#ifdef WITH_METERING
+ INFO("FEATURE: WITH METERING Detection\n");
+#else
+ INFO("FEATURE: NO METERING Detection\n");
+#endif
+ xproto_register(&PROTO_TABLE(FXO));
+ return 0;
+}
+
+static void __exit card_fxo_cleanup(void)
+{
+ xproto_unregister(&PROTO_TABLE(FXO));
+}
+
+MODULE_DESCRIPTION("XPP FXO Card Driver");
+MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(XPP_VERSION);
+MODULE_ALIAS_XPD(XPD_TYPE_FXO);
+
+module_init(card_fxo_startup);
+module_exit(card_fxo_cleanup);
diff --git a/drivers/dahdi/xpp/card_fxo.h b/drivers/dahdi/xpp/card_fxo.h
new file mode 100644
index 0000000..9f31441
--- /dev/null
+++ b/drivers/dahdi/xpp/card_fxo.h
@@ -0,0 +1,42 @@
+#ifndef CARD_FXO_H
+#define CARD_FXO_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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 "xpd.h"
+
+enum fxo_opcodes {
+ XPROTO_NAME(FXO, SIG_CHANGED) = 0x06,
+/**/
+ XPROTO_NAME(FXO, DAA_WRITE) = 0x0F, /* Write to DAA */
+ XPROTO_NAME(FXO, XPD_STATE) = 0x0F, /* Write to DAA */
+ XPROTO_NAME(FXO, CHAN_CID) = 0x0F, /* Write to DAA */
+ XPROTO_NAME(FXO, LED) = 0x0F, /* Write to DAA */
+};
+
+
+DEF_RPACKET_DATA(FXO, SIG_CHANGED,
+ xpp_line_t sig_status; /* channels: lsb=1, msb=8 */
+ xpp_line_t sig_toggles; /* channels: lsb=1, msb=8 */
+ );
+
+#endif /* CARD_FXO_H */
diff --git a/drivers/dahdi/xpp/card_fxs.c b/drivers/dahdi/xpp/card_fxs.c
new file mode 100644
index 0000000..eeb02c9
--- /dev/null
+++ b/drivers/dahdi/xpp/card_fxs.c
@@ -0,0 +1,1488 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include "xpd.h"
+#include "xproto.h"
+#include "xpp_zap.h"
+#include "card_fxo.h"
+#include "zap_debug.h"
+#include "xbus-core.h"
+
+static const char rcsid[] = "$Id$";
+
+static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before zap_debug.h */
+static DEF_PARM_BOOL(reversepolarity, 0, 0644, "Reverse Line Polarity");
+static DEF_PARM_BOOL(vmwineon, 0, 0644, "Indicate voicemail to a neon lamp");
+static DEF_PARM_BOOL(dtmf_detection, 1, 0644, "Do DTMF detection in hardware");
+#ifdef POLL_DIGITAL_INPUTS
+static DEF_PARM(uint, poll_digital_inputs, 1000, 0644, "Poll Digital Inputs");
+#endif
+
+#ifdef ZT_VMWI
+static DEF_PARM_BOOL(vmwi_ioctl, 0, 0644, "Asterisk support VMWI notification via ioctl");
+#else
+#define vmwi_ioctl 0 /* not supported */
+#endif
+
+/* Signaling is opposite (fxo signalling for fxs card) */
+#if 1
+#define FXS_DEFAULT_SIGCAP (ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS)
+#else
+#define FXS_DEFAULT_SIGCAP (ZT_SIG_SF | ZT_SIG_EM)
+#endif
+
+#define LINES_DIGI_OUT 2
+#define LINES_DIGI_INP 4
+
+enum fxs_leds {
+ LED_GREEN,
+ LED_RED,
+ OUTPUT_RELAY,
+};
+
+#define NUM_LEDS 2
+
+/* Shortcuts */
+#define SLIC_WRITE 1
+#define SLIC_READ 0
+#define SLIC_DIRECT_REQUEST(xbus,xpd,port,writing,reg,dL) \
+ xpp_register_request((xbus), (xpd), (port), (writing), (reg), 0, 0, (dL), 0, 0, 0)
+#define SLIC_INDIRECT_REQUEST(xbus,xpd,port,writing,reg,dL,dH) \
+ xpp_register_request((xbus), (xpd), (port), (writing), 0x1E, 1, (reg), (dL), 1, (dH), 0)
+
+#define VALID_PORT(port) (((port) >= 0 && (port) <= 7) || (port) == PORT_BROADCAST)
+
+#define REG_DIGITAL_IOCTRL 0x06 /* LED and RELAY control */
+
+/* Values of SLIC linefeed control register (0x40) */
+enum fxs_state {
+ FXS_LINE_OPEN = 0x00, /* Open */
+ FXS_LINE_ACTIVE = 0x01, /* Forward active */
+ FXS_LINE_OHTRANS = 0x02, /* Forward on-hook transmission */
+ FXS_LINE_TIPOPEN = 0x03, /* TIP open */
+ FXS_LINE_RING = 0x04, /* Ringing */
+ FXS_LINE_REV_ACTIVE = 0x05, /* Reverse active */
+ FXS_LINE_REV_OHTRANS = 0x06, /* Reverse on-hook transmission */
+ FXS_LINE_RING_OPEN = 0x07 /* RING open */
+};
+
+#define FXS_LINE_POL_ACTIVE ((reversepolarity) ? FXS_LINE_REV_ACTIVE : FXS_LINE_ACTIVE)
+#define FXS_LINE_POL_OHTRANS ((reversepolarity) ? FXS_LINE_REV_OHTRANS : FXS_LINE_OHTRANS)
+
+/*
+ * DTMF detection
+ */
+#define REG_DTMF_DECODE 0x18 /* 24 - DTMF Decode Status */
+#define REG_BATTERY 0x42 /* 66 - Battery Feed Control */
+#define REG_BATTERY_BATSL BIT(1) /* Battery Feed Select */
+
+#define REG_LOOPCLOSURE 0x44 /* 68 - Loop Closure/Ring Trip Detect Status */
+#define REG_LOOPCLOSURE_LCR BIT(0) /* Loop Closure Detect Indicator. */
+
+/*---------------- FXS Protocol Commands ----------------------------------*/
+
+static /* 0x0F */ DECLARE_CMD(FXS, XPD_STATE, bool on);
+
+static bool fxs_packet_is_valid(xpacket_t *pack);
+static void fxs_packet_dump(const char *msg, xpacket_t *pack);
+static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
+#ifdef WITH_METERING
+static int proc_xpd_metering_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+#endif
+static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos);
+
+#define PROC_REGISTER_FNAME "slics"
+#define PROC_FXS_INFO_FNAME "fxs_info"
+#ifdef WITH_METERING
+#define PROC_METERING_FNAME "metering_gen"
+#endif
+
+struct FXS_priv_data {
+#ifdef WITH_METERING
+ struct proc_dir_entry *meteringfile;
+#endif
+ struct proc_dir_entry *fxs_info;
+ xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
+ xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */
+ xpp_line_t search_fsk_pattern;
+ xpp_line_t found_fsk_pattern;
+ xpp_line_t update_offhook_state;
+ xpp_line_t want_dtmf_events; /* what zaptel want */
+ xpp_line_t want_dtmf_mute; /* what zaptel want */
+ int led_counter[NUM_LEDS][CHANNELS_PERXPD];
+ int ohttimer[CHANNELS_PERXPD];
+#define OHT_TIMER 6000 /* How long after RING to retain OHT */
+ enum fxs_state idletxhookstate[CHANNELS_PERXPD]; /* IDLE changing hook state */
+ enum fxs_state lasttxhook[CHANNELS_PERXPD];
+};
+
+/*
+ * LED counter values:
+ * n>1 : BLINK every n'th tick
+ */
+#define LED_COUNTER(priv,pos,color) ((priv)->led_counter[color][pos])
+#define IS_BLINKING(priv,pos,color) (LED_COUNTER(priv,pos,color) > 0)
+#define MARK_BLINK(priv,pos,color,t) ((priv)->led_counter[color][pos] = (t))
+#define MARK_OFF(priv,pos,color) do { BIT_CLR((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0)
+#define MARK_ON(priv,pos,color) do { BIT_SET((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0)
+
+#define LED_BLINK_RING (1000/8) /* in ticks */
+
+/*---------------- FXS: Static functions ----------------------------------*/
+static int linefeed_control(xbus_t *xbus, xpd_t *xpd, lineno_t chan, enum fxs_state value)
+{
+ struct FXS_priv_data *priv;
+
+ priv = xpd->priv;
+ LINE_DBG(SIGNAL, xpd, chan, "value=0x%02X\n", value);
+ priv->lasttxhook[chan] = value;
+ return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, value);
+}
+
+static int do_chan_power(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on)
+{
+ int value = (on) ? REG_BATTERY_BATSL : 0x00;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on) ? "up" : "down");
+ return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_BATTERY, value);
+}
+
+/*
+ * LED and RELAY control is done via SLIC register 0x06:
+ * 7 6 5 4 3 2 1 0
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | M2 | M1 | M3 | C2 | O1 | O3 | C1 | C3 |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ *
+ * Cn - Control bit (control one digital line)
+ * On - Output bit (program a digital line for output)
+ * Mn - Mask bit (only the matching output control bit is affected)
+ *
+ * C3 - OUTPUT RELAY (0 - OFF, 1 - ON)
+ * C1 - GREEN LED (0 - OFF, 1 - ON)
+ * O3 - Output RELAY (this line is output)
+ * O1 - Output GREEN (this line is output)
+ * C2 - RED LED (0 - OFF, 1 - ON)
+ * M3 - Mask RELAY. (1 - C3 effect the OUTPUT RELAY)
+ * M2 - Mask RED. (1 - C2 effect the RED LED)
+ * M1 - Mask GREEN. (1 - C1 effect the GREEN LED)
+ *
+ * The OUTPUT RELAY (actually a relay out) is connected to line 0 and 4 only.
+ */
+
+// GREEN RED OUTPUT RELAY
+static const int led_register_mask[] = { BIT(7), BIT(6), BIT(5) };
+static const int led_register_vals[] = { BIT(4), BIT(1), BIT(0) };
+
+/*
+ * pos can be:
+ * - A line number
+ * - ALL_LINES. This is not valid anymore since 8-Jan-2007.
+ */
+static int do_led(xpd_t *xpd, lineno_t chan, byte which, bool on)
+{
+ int ret = 0;
+ struct FXS_priv_data *priv;
+ int value;
+ xbus_t *xbus;
+
+ BUG_ON(!xpd);
+ BUG_ON(chan == ALL_LINES);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ which = which % NUM_LEDS;
+ if(IS_SET(xpd->digital_outputs, chan) || IS_SET(xpd->digital_inputs, chan))
+ goto out;
+ if(chan == PORT_BROADCAST) {
+ priv->ledstate[which] = (on) ? ~0 : 0;
+ } else {
+ if(on) {
+ BIT_SET(priv->ledstate[which], chan);
+ } else {
+ BIT_CLR(priv->ledstate[which], chan);
+ }
+ }
+ LINE_DBG(LEDS, xpd, chan, "LED: which=%d -- %s\n", which, (on) ? "on" : "off");
+ value = BIT(2) | BIT(3);
+ value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]);
+ if(on)
+ value |= led_register_vals[which];
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE,
+ REG_DIGITAL_IOCTRL, value);
+out:
+ return ret;
+}
+
+static void handle_fxs_leds(xpd_t *xpd)
+{
+ int i;
+ const enum fxs_leds colors[] = { LED_GREEN, LED_RED };
+ enum fxs_leds color;
+ unsigned int timer_count;
+ struct FXS_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ timer_count = xpd->timer_count;
+ for(color = 0; color < ARRAY_SIZE(colors); color++) {
+ for_each_line(xpd, i) {
+ if(IS_SET(xpd->digital_outputs | xpd->digital_inputs, i))
+ continue;
+ if((xpd->blink_mode & BIT(i)) || IS_BLINKING(priv, i, color)) { // Blinking
+ int mod_value = LED_COUNTER(priv, i, color);
+
+ if(!mod_value)
+ mod_value = DEFAULT_LED_PERIOD; /* safety value */
+ // led state is toggled
+ if((timer_count % mod_value) == 0) {
+ LINE_DBG(LEDS, xpd, i, "ledstate=%s\n", (IS_SET(priv->ledstate[color], i))?"ON":"OFF");
+ if(!IS_SET(priv->ledstate[color], i)) {
+ do_led(xpd, i, color, 1);
+ } else {
+ do_led(xpd, i, color, 0);
+ }
+ }
+ } else if(IS_SET(priv->ledcontrol[color] & ~priv->ledstate[color], i)) {
+ do_led(xpd, i, color, 1);
+ } else if(IS_SET(~priv->ledcontrol[color] & priv->ledstate[color], i)) {
+ do_led(xpd, i, color, 0);
+ }
+
+ }
+ }
+}
+
+static void restore_leds(xpd_t *xpd)
+{
+ struct FXS_priv_data *priv;
+ int i;
+
+ priv = xpd->priv;
+ for_each_line(xpd, i) {
+ if(IS_SET(xpd->offhook, i))
+ MARK_ON(priv, i, LED_GREEN);
+ else
+ MARK_OFF(priv, i, LED_GREEN);
+ }
+}
+
+#ifdef WITH_METERING
+static int metering_gen(xpd_t *xpd, lineno_t chan, bool on)
+{
+ byte value = (on) ? 0x94 : 0x00;
+
+ LINE_DBG(SIGNAL, xpd, chan, "METERING Generate: %s\n", (on)?"ON":"OFF");
+ return SLIC_DIRECT_REQUEST(xpd->xbus, xpd, chan, SLIC_WRITE, 0x23, value);
+}
+#endif
+
+/*---------------- FXS: Methods -------------------------------------------*/
+
+static void fxs_proc_remove(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXS_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+#ifdef CONFIG_PROC_FS
+#ifdef WITH_METERING
+ if(priv->meteringfile) {
+ XPD_DBG(PROC, xpd, "Removing xpd metering tone file\n");
+ priv->meteringfile->data = NULL;
+ remove_proc_entry(PROC_METERING_FNAME, xpd->proc_xpd_dir);
+ priv->meteringfile = NULL;
+ }
+#endif
+ if(priv->fxs_info) {
+ XPD_DBG(PROC, xpd, "Removing xpd FXS_INFO file\n");
+ remove_proc_entry(PROC_FXS_INFO_FNAME, xpd->proc_xpd_dir);
+ priv->fxs_info = NULL;
+ }
+#endif
+}
+
+static int fxs_proc_create(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXS_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+
+#ifdef CONFIG_PROC_FS
+ XPD_DBG(PROC, xpd, "Creating FXS_INFO file\n");
+ priv->fxs_info = create_proc_read_entry(PROC_FXS_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_fxs_info_read, xpd);
+ if(!priv->fxs_info) {
+ XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_FXS_INFO_FNAME);
+ goto err;
+ }
+ priv->fxs_info->owner = THIS_MODULE;
+#ifdef WITH_METERING
+ XPD_DBG(PROC, xpd, "Creating Metering tone file\n");
+ priv->meteringfile = create_proc_entry(PROC_METERING_FNAME, 0200, xpd->proc_xpd_dir);
+ if(!priv->meteringfile) {
+ XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_METERING_FNAME);
+ goto err;
+ }
+ priv->meteringfile->owner = THIS_MODULE;
+ priv->meteringfile->write_proc = proc_xpd_metering_write;
+ priv->meteringfile->read_proc = NULL;
+ priv->meteringfile->data = xpd;
+#endif
+#endif
+ return 0;
+err:
+ return -EINVAL;
+}
+
+static xpd_t *FXS_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, bool to_phone)
+{
+ xpd_t *xpd = NULL;
+ int channels;
+ int regular_channels;
+ struct FXS_priv_data *priv;
+ int i;
+
+ if(!to_phone) {
+ XBUS_NOTICE(xbus,
+ "XPD=%d%d: try to instanciate FXS with reverse direction\n",
+ unit, subunit);
+ return NULL;
+ }
+ if(subtype == 2)
+ regular_channels = min(6, CHANNELS_PERXPD);
+ else
+ regular_channels = min(8, CHANNELS_PERXPD);
+ channels = regular_channels;
+ if(unit == 0)
+ channels += 6; /* 2 DIGITAL OUTPUTS, 4 DIGITAL INPUTS */
+ xpd = xpd_alloc(sizeof(struct FXS_priv_data), proto_table, channels);
+ if(!xpd)
+ return NULL;
+ if(unit == 0) {
+ XBUS_DBG(GENERAL, xbus, "First XPD detected. Initialize digital outputs/inputs\n");
+ xpd->digital_outputs = BITMASK(LINES_DIGI_OUT) << regular_channels;
+ xpd->digital_inputs = BITMASK(LINES_DIGI_INP) << (regular_channels + LINES_DIGI_OUT);
+ }
+ xpd->direction = TO_PHONE;
+ xpd->type_name = "FXS";
+ if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0)
+ goto err;
+ if(fxs_proc_create(xbus, xpd) < 0)
+ goto err;
+ priv = xpd->priv;
+ for_each_line(xpd, i) {
+ priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE;
+ }
+ return xpd;
+err:
+ xpd_free(xpd);
+ return NULL;
+}
+
+static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXS_priv_data *priv;
+ int ret = 0;
+ int i;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ /*
+ * Setup ring timers
+ */
+ /* Software controled ringing (for CID) */
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, PORT_BROADCAST, SLIC_WRITE, 0x22, 0x00); /* Ringing Oscilator Control */
+ if(ret < 0)
+ goto err;
+ for_each_line(xpd, i) {
+ linefeed_control(xbus, xpd, i, FXS_LINE_POL_ACTIVE);
+ }
+ XPD_DBG(GENERAL, xpd, "done\n");
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 0);
+ do_led(xpd, i, LED_RED, 0);
+ }
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 1);
+ msleep(50);
+ }
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 0);
+ msleep(50);
+ }
+ restore_leds(xpd);
+ pcm_recompute(xpd, 0);
+ /*
+ * We should query our offhook state long enough time after we
+ * set the linefeed_control()
+ * So we do this after the LEDs
+ */
+ for_each_line(xpd, i) {
+ if(IS_SET(xpd->digital_outputs | xpd->digital_inputs, i))
+ continue;
+ SLIC_DIRECT_REQUEST(xbus, xpd, i, SLIC_READ, REG_LOOPCLOSURE, 0);
+ }
+ return 0;
+err:
+ fxs_proc_remove(xbus, xpd);
+ XPD_ERR(xpd, "Failed initializing registers (%d)\n", ret);
+ return ret;
+}
+
+static int FXS_card_remove(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXS_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(GENERAL, xpd, "\n");
+ fxs_proc_remove(xbus, xpd);
+ return 0;
+}
+
+static int FXS_card_zaptel_preregistration(xpd_t *xpd, bool on)
+{
+ xbus_t *xbus;
+ struct FXS_priv_data *priv;
+ int i;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
+#ifdef ZT_SPANSTAT_V2
+ xpd->span.spantype = "FXS";
+#endif
+ for_each_line(xpd, i) {
+ struct zt_chan *cur_chan = &xpd->chans[i];
+
+ XPD_DBG(GENERAL, xpd, "setting FXS channel %d\n", i);
+ if(IS_SET(xpd->digital_outputs, i)) {
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_OUT/%02d/%1d%1d/%d",
+ xbus->num, xpd->addr.unit, xpd->addr.subunit, i);
+ } else if(IS_SET(xpd->digital_inputs, i)) {
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%02d/%1d%1d/%d",
+ xbus->num, xpd->addr.unit, xpd->addr.subunit, i);
+ } else {
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXS/%02d/%1d%1d/%d",
+ xbus->num, xpd->addr.unit, xpd->addr.subunit, i);
+ }
+ cur_chan->chanpos = i + 1;
+ cur_chan->pvt = xpd;
+ cur_chan->sigcap = FXS_DEFAULT_SIGCAP;
+ }
+ for_each_line(xpd, i) {
+ MARK_ON(priv, i, LED_GREEN);
+ msleep(4);
+ MARK_ON(priv, i, LED_RED);
+ }
+ return 0;
+}
+
+static int FXS_card_zaptel_postregistration(xpd_t *xpd, bool on)
+{
+ xbus_t *xbus;
+ struct FXS_priv_data *priv;
+ int i;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
+ for_each_line(xpd, i) {
+ MARK_OFF(priv, i, LED_GREEN);
+ msleep(2);
+ MARK_OFF(priv, i, LED_RED);
+ msleep(2);
+ }
+ restore_leds(xpd);
+ return 0;
+}
+
+/*
+ * Called with XPD spinlocked
+ */
+static void __do_mute_dtmf(xpd_t *xpd, int pos, bool muteit)
+{
+ LINE_DBG(SIGNAL, xpd, pos, "%s\n", (muteit) ? "MUTE" : "UNMUTE");
+ if(muteit)
+ BIT_SET(xpd->mute_dtmf, pos);
+ else
+ BIT_CLR(xpd->mute_dtmf, pos);
+}
+
+static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
+{
+ int ret = 0;
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+
+ LINE_DBG(SIGNAL, xpd, pos, "%s%s\n", (on)?"ON":"OFF", (vmwineon)?"":" (Ignored)");
+ if (!vmwineon)
+ return 0;
+ if (on) {
+ /* A write to register 0x40 will now turn on/off the VM led */
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xE8, 0x03);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xEF, 0x7B);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x9F, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x19);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0xE0);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x01);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0xF0);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x05);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x46);
+ } else {
+ /* A write to register 0x40 will now turn on/off the ringer */
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0x00, 0x00);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0x60, 0x01);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0xF0, 0x7E);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36);
+ }
+
+ return (ret ? -EPROTO : 0);
+}
+
+static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos)
+{
+ struct FXS_priv_data *priv;
+ bool on;
+
+ BUG_ON(!xpd);
+ if (!vmwineon || IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos))
+ return;
+ priv = xpd->priv;
+ on = IS_SET(xpd->msg_waiting, pos);
+ LINE_DBG(SIGNAL, xpd, pos, "%s\n", (on)?"ON":"OFF");
+ set_vm_led_mode(xbus, xpd, pos, on);
+ do_chan_power(xbus, xpd, pos, on);
+ linefeed_control(xbus, xpd, pos, (on) ? FXS_LINE_RING : priv->idletxhookstate[pos]);
+}
+
+static int relay_out(xpd_t *xpd, int pos, bool on)
+{
+ int value;
+ int which = pos;
+ int relay_channels[] = { 0, 4 };
+
+ BUG_ON(!xpd);
+ /* map logical position to output port number (0/1) */
+ which -= (xpd->subtype == 2) ? 6 : 8;
+ LINE_DBG(SIGNAL, xpd, pos, "which=%d -- %s\n", which, (on) ? "on" : "off");
+ which = which % ARRAY_SIZE(relay_channels);
+ value = BIT(2) | BIT(3);
+ value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[OUTPUT_RELAY]);
+ if(on)
+ value |= led_register_vals[OUTPUT_RELAY];
+ return SLIC_DIRECT_REQUEST(xpd->xbus, xpd, relay_channels[which],
+ SLIC_WRITE, REG_DIGITAL_IOCTRL, value);
+}
+
+static int send_ring(xpd_t *xpd, lineno_t chan, bool on)
+{
+ int ret = 0;
+ xbus_t *xbus;
+ struct FXS_priv_data *priv;
+ enum fxs_state value = (on) ? FXS_LINE_RING : FXS_LINE_POL_ACTIVE;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on)?"on":"off");
+ priv = xpd->priv;
+ set_vm_led_mode(xbus, xpd, chan, 0);
+ do_chan_power(xbus, xpd, chan, on); // Power up (for ring)
+ ret = linefeed_control(xbus, xpd, chan, value);
+ if(on) {
+ MARK_BLINK(priv, chan, LED_GREEN, LED_BLINK_RING);
+ } else {
+ if(IS_BLINKING(priv, chan, LED_GREEN))
+ MARK_BLINK(priv, chan, LED_GREEN, 0);
+ }
+ return ret;
+}
+
+static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
+{
+ struct FXS_priv_data *priv;
+ int ret = 0;
+ struct zt_chan *chan = NULL;
+ enum fxs_state txhook;
+ unsigned long flags;
+
+ LINE_DBG(SIGNAL, xpd, pos, "%s\n", txsig2str(txsig));
+ priv = xpd->priv;
+ BUG_ON(xpd->direction != TO_PHONE);
+ if (IS_SET(xpd->digital_inputs, pos)) {
+ LINE_DBG(SIGNAL, xpd, pos, "Ignoring signal sent to digital input line\n");
+ return 0;
+ }
+ if(SPAN_REGISTERED(xpd))
+ chan = &xpd->span.chans[pos];
+ switch(txsig) {
+ case ZT_TXSIG_ONHOOK:
+ spin_lock_irqsave(&xpd->lock, flags);
+ xpd->ringing[pos] = 0;
+ BIT_CLR(xpd->cid_on, pos);
+ BIT_CLR(priv->search_fsk_pattern, pos);
+ BIT_CLR(priv->want_dtmf_events, pos);
+ BIT_CLR(priv->want_dtmf_mute, pos);
+ __do_mute_dtmf(xpd, pos, 0);
+ __pcm_recompute(xpd, 0); /* already spinlocked */
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output OFF\n", txsig2str(txsig));
+ ret = relay_out(xpd, pos, 0);
+ return ret;
+ }
+ if (priv->lasttxhook[pos] == FXS_LINE_OPEN) {
+ /*
+ * Restore state after KEWL hangup.
+ */
+ LINE_DBG(SIGNAL, xpd, pos, "KEWL STOP\n");
+ linefeed_control(xbus, xpd, pos, FXS_LINE_POL_ACTIVE);
+ if(IS_SET(xpd->offhook, pos))
+ MARK_ON(priv, pos, LED_GREEN);
+ }
+ ret = send_ring(xpd, pos, 0); // RING off
+ if (!IS_SET(xpd->offhook, pos))
+ start_stop_vm_led(xbus, xpd, pos);
+ txhook = priv->lasttxhook[pos];
+ if(chan) {
+ switch(chan->sig) {
+ case ZT_SIG_EM:
+ case ZT_SIG_FXOKS:
+ case ZT_SIG_FXOLS:
+ txhook = priv->idletxhookstate[pos];
+ break;
+ case ZT_SIG_FXOGS:
+ txhook = FXS_LINE_TIPOPEN;
+ break;
+ }
+ }
+ ret = linefeed_control(xbus, xpd, pos, txhook);
+ break;
+ case ZT_TXSIG_OFFHOOK:
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ LINE_NOTICE(xpd, pos, "%s -> Is digital output. Ignored\n", txsig2str(txsig));
+ return -EINVAL;
+ }
+ txhook = priv->lasttxhook[pos];
+ if(xpd->ringing[pos]) {
+ BIT_SET(xpd->cid_on, pos);
+ pcm_recompute(xpd, 0);
+ txhook = FXS_LINE_OHTRANS;
+ }
+ xpd->ringing[pos] = 0;
+ if(chan) {
+ switch(chan->sig) {
+ case ZT_SIG_EM:
+ txhook = FXS_LINE_POL_ACTIVE;
+ break;
+ default:
+ txhook = priv->idletxhookstate[pos];
+ break;
+ }
+ }
+ ret = linefeed_control(xbus, xpd, pos, txhook);
+ break;
+ case ZT_TXSIG_START:
+ xpd->ringing[pos] = 1;
+ BIT_CLR(xpd->cid_on, pos);
+ BIT_CLR(priv->search_fsk_pattern, pos);
+ pcm_recompute(xpd, 0);
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output ON\n", txsig2str(txsig));
+ ret = relay_out(xpd, pos, 1);
+ return ret;
+ }
+ ret = send_ring(xpd, pos, 1); // RING on
+ break;
+ case ZT_TXSIG_KEWL:
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ LINE_DBG(SIGNAL, xpd, pos, "%s -> Is digital output. Ignored\n", txsig2str(txsig));
+ return -EINVAL;
+ }
+ linefeed_control(xbus, xpd, pos, FXS_LINE_OPEN);
+ MARK_OFF(priv, pos, LED_GREEN);
+ break;
+ default:
+ XPD_NOTICE(xpd, "%s: Can't set tx state to %s (%d)\n",
+ __FUNCTION__, txsig2str(txsig), txsig);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/*
+ * Private ioctl()
+ * We don't need it now, since we detect vmwi via FSK patterns
+ */
+static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
+{
+ struct FXS_priv_data *priv;
+ xbus_t *xbus;
+ int val;
+ unsigned long flags;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ if(!TRANSPORT_RUNNING(xbus))
+ return -ENODEV;
+ if (pos < 0 || pos >= xpd->channels) {
+ XPD_NOTICE(xpd, "Bad channel number %d in %s(), cmd=%u\n",
+ pos, __FUNCTION__, cmd);
+ return -EINVAL;
+ }
+
+ switch (cmd) {
+ case ZT_ONHOOKTRANSFER:
+ if (get_user(val, (int __user *)arg))
+ return -EFAULT;
+ LINE_DBG(SIGNAL, xpd, pos, "ZT_ONHOOKTRANSFER (%d millis)\n", val);
+ if (IS_SET(xpd->digital_inputs | xpd->digital_outputs, pos))
+ return 0; /* Nothing to do */
+ BIT_CLR(xpd->cid_on, pos);
+ if(priv->lasttxhook[pos] == FXS_LINE_POL_ACTIVE) {
+ priv->ohttimer[pos] = OHT_TIMER;
+ priv->idletxhookstate[pos] = FXS_LINE_POL_OHTRANS;
+ BIT_SET(priv->search_fsk_pattern, pos);
+ pcm_recompute(xpd, priv->search_fsk_pattern);
+ }
+ if(!IS_SET(xpd->offhook, pos))
+ start_stop_vm_led(xbus, xpd, pos);
+ return 0;
+ case ZT_TONEDETECT:
+ if (get_user(val, (int __user *)arg))
+ return -EFAULT;
+ LINE_DBG(SIGNAL, xpd, pos, "ZT_TONEDETECT: %s %s (dtmf_detection=%s)\n",
+ (val & ZT_TONEDETECT_ON) ? "ON" : "OFF",
+ (val & ZT_TONEDETECT_MUTE) ? "MUTE" : "NO-MUTE",
+ (dtmf_detection ? "YES" : "NO"));
+ if(!dtmf_detection) {
+ spin_lock_irqsave(&xpd->lock, flags);
+ if(IS_SET(priv->want_dtmf_events, pos)) {
+ /* Detection mode changed: Disable DTMF interrupts */
+ SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x17, 0);
+ }
+ BIT_CLR(priv->want_dtmf_events, pos);
+ BIT_CLR(priv->want_dtmf_mute, pos);
+ __do_mute_dtmf(xpd, pos, 0);
+ __pcm_recompute(xpd, 0); /* already spinlocked */
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return -ENOTTY;
+ }
+ /*
+ * During natively bridged calls, Asterisk
+ * will request one of the sides to stop sending
+ * dtmf events. Check the requested state.
+ */
+ spin_lock_irqsave(&xpd->lock, flags);
+ if(val & ZT_TONEDETECT_ON) {
+ if(!IS_SET(priv->want_dtmf_events, pos)) {
+ /* Detection mode changed: Enable DTMF interrupts */
+ LINE_DBG(SIGNAL, xpd, pos,
+ "ZT_TONEDETECT: Enable Hardware DTMF\n");
+ SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x17, 1);
+ }
+ BIT_SET(priv->want_dtmf_events, pos);
+ } else {
+ if(IS_SET(priv->want_dtmf_events, pos)) {
+ /* Detection mode changed: Disable DTMF interrupts */
+ LINE_DBG(SIGNAL, xpd, pos,
+ "ZT_TONEDETECT: Disable Hardware DTMF\n");
+ SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x17, 0);
+ }
+ BIT_CLR(priv->want_dtmf_events, pos);
+ }
+ if(val & ZT_TONEDETECT_MUTE) {
+ BIT_SET(priv->want_dtmf_mute, pos);
+ } else {
+ BIT_CLR(priv->want_dtmf_mute, pos);
+ __do_mute_dtmf(xpd, pos, 0);
+ __pcm_recompute(xpd, 0);
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return 0;
+ case ZT_SETPOLARITY:
+ if (get_user(val, (int __user *)arg))
+ return -EFAULT;
+ /* Can't change polarity while ringing or when open */
+ if (priv->lasttxhook[pos] == FXS_LINE_RING || priv->lasttxhook[pos] == FXS_LINE_OPEN) {
+ LINE_ERR(xpd, pos, "ZT_SETPOLARITY: %s Cannot change when lasttxhook=0x%X\n",
+ (val)?"ON":"OFF", priv->lasttxhook[pos]);
+ return -EINVAL;
+ }
+ LINE_DBG(SIGNAL, xpd, pos, "ZT_SETPOLARITY: %s\n", (val)?"ON":"OFF");
+ if ((val && !reversepolarity) || (!val && reversepolarity))
+ priv->lasttxhook[pos] |= FXS_LINE_RING;
+ else
+ priv->lasttxhook[pos] &= ~FXS_LINE_RING;
+ linefeed_control(xbus, xpd, pos, priv->lasttxhook[pos]);
+ return 0;
+#ifdef ZT_VMWI
+ case ZT_VMWI: /* message-waiting led control */
+ if (get_user(val, (int __user *)arg))
+ return -EFAULT;
+ if(!vmwi_ioctl) {
+ LINE_NOTICE(xpd, pos, "Got ZT_VMWI notification but vmwi_ioctl parameter is off. Ignoring.\n");
+ return 0;
+ }
+ /* Digital inputs/outputs don't have VM leds */
+ if (IS_SET(xpd->digital_inputs | xpd->digital_outputs, pos))
+ return 0;
+ if (val)
+ BIT_SET(xpd->msg_waiting, pos);
+ else
+ BIT_CLR(xpd->msg_waiting, pos);
+ return 0;
+#endif
+ default:
+ report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd);
+ }
+ return -ENOTTY;
+}
+
+static int FXS_card_open(xpd_t *xpd, lineno_t chan)
+{
+ struct FXS_priv_data *priv;
+ bool is_offhook;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ is_offhook = IS_SET(xpd->offhook, chan);
+ if(is_offhook)
+ LINE_NOTICE(xpd, chan, "Already offhook during open. OK.\n");
+ else
+ LINE_DBG(SIGNAL, xpd, chan, "is onhook\n");
+ /*
+ * Delegate updating zaptel to FXS_card_tick():
+ * The problem is that zt_hooksig() is spinlocking the channel and
+ * we are called by zaptel with the spinlock already held on the
+ * same channel.
+ */
+ BIT_SET(priv->update_offhook_state, chan);
+ return 0;
+}
+
+static int FXS_card_close(xpd_t *xpd, lineno_t chan)
+{
+ struct FXS_priv_data *priv;
+
+ BUG_ON(!xpd);
+ LINE_DBG(GENERAL, xpd, chan, "\n");
+ priv = xpd->priv;
+ priv->idletxhookstate[chan] = FXS_LINE_POL_ACTIVE;
+ return 0;
+}
+
+#ifdef POLL_DIGITAL_INPUTS
+/*
+ * INPUT polling is done via SLIC register 0x06 (same as LEDS):
+ * 7 6 5 4 3 2 1 0
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | I1 | I3 | | | I2 | I4 | | |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ *
+ */
+static int input_channels[] = { 6, 7, 2, 3 }; // Slic numbers of input relays
+
+static void poll_inputs(xpd_t *xpd)
+{
+ int i;
+
+ BUG_ON(xpd->xbus_idx != 0); // Only unit #0 has digital inputs
+ for(i = 0; i < ARRAY_SIZE(input_channels); i++) {
+ byte pos = input_channels[i];
+
+ SLIC_DIRECT_REQUEST(xpd->xbus, xpd, pos, SLIC_READ, 0x06, 0);
+ }
+}
+#endif
+
+static void handle_linefeed(xpd_t *xpd)
+{
+ struct FXS_priv_data *priv;
+ int i;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ for_each_line(xpd, i) {
+ if (priv->lasttxhook[i] == FXS_LINE_RING) {
+ /* RINGing, prepare for OHT */
+ priv->ohttimer[i] = OHT_TIMER;
+ priv->idletxhookstate[i] = FXS_LINE_POL_OHTRANS;
+ } else {
+ if (priv->ohttimer[i]) {
+ priv->ohttimer[i]--;
+ if (!priv->ohttimer[i]) {
+ priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE;
+ BIT_CLR(xpd->cid_on, i);
+ BIT_CLR(priv->search_fsk_pattern, i);
+ pcm_recompute(xpd, 0);
+ if (priv->lasttxhook[i] == FXS_LINE_POL_OHTRANS) {
+ /* Apply the change if appropriate */
+ linefeed_control(xpd->xbus, xpd, i, FXS_LINE_POL_ACTIVE);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Optimized memcmp() like function. Only test for equality (true/false).
+ * This optimization reduced the detect_vmwi() runtime by a factor of 3.
+ */
+static inline bool mem_equal(const char a[], const char b[], size_t len)
+{
+ int i;
+
+ for(i = 0; i < len; i++)
+ if(a[i] != b[i])
+ return 0;
+ return 1;
+}
+
+/*
+ * Detect Voice Mail Waiting Indication
+ */
+static void detect_vmwi(xpd_t *xpd)
+{
+ struct FXS_priv_data *priv;
+ xbus_t *xbus;
+ static const byte FSK_COMMON_PATTERN[] = { 0xA8, 0x49, 0x22, 0x3B, 0x9F, 0xFF, 0x1F, 0xBB };
+ static const byte FSK_ON_PATTERN[] = { 0xA2, 0x2C, 0x1F, 0x2C, 0xBB, 0xA1, 0xA5, 0xFF };
+ static const byte FSK_OFF_PATTERN[] = { 0xA2, 0x2C, 0x28, 0xA5, 0xB1, 0x21, 0x49, 0x9F };
+ int i;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ for_each_line(xpd, i) {
+ struct zt_chan *chan = &xpd->span.chans[i];
+ byte *writechunk = chan->writechunk;
+
+ if(IS_SET(xpd->offhook | xpd->cid_on | xpd->digital_inputs | xpd->digital_outputs, i))
+ continue;
+#if 0
+ if(writechunk[0] != 0x7F && writechunk[0] != 0) {
+ int j;
+
+ LINE_DBG(GENERAL, xpd, pos, "MSG:");
+ for(j = 0; j < ZT_CHUNKSIZE; j++) {
+ if(debug)
+ printk(" %02X", writechunk[j]);
+ }
+ if(debug)
+ printk("\n");
+ }
+#endif
+ if(unlikely(mem_equal(writechunk, FSK_COMMON_PATTERN, ZT_CHUNKSIZE)))
+ BIT_SET(priv->found_fsk_pattern, i);
+ else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) {
+ BIT_CLR(priv->found_fsk_pattern, i);
+ if(unlikely(mem_equal(writechunk, FSK_ON_PATTERN, ZT_CHUNKSIZE))) {
+ LINE_DBG(SIGNAL, xpd, i, "MSG WAITING ON\n");
+ BIT_SET(xpd->msg_waiting, i);
+ start_stop_vm_led(xbus, xpd, i);
+ } else if(unlikely(mem_equal(writechunk, FSK_OFF_PATTERN, ZT_CHUNKSIZE))) {
+ LINE_DBG(SIGNAL, xpd, i, "MSG WAITING OFF\n");
+ BIT_CLR(xpd->msg_waiting, i);
+ start_stop_vm_led(xbus, xpd, i);
+ } else {
+ int j;
+
+ LINE_NOTICE(xpd, i, "MSG WAITING Unexpected:");
+ for(j = 0; j < ZT_CHUNKSIZE; j++) {
+ printk(" %02X", writechunk[j]);
+ }
+ printk("\n");
+ }
+ }
+ }
+}
+
+static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXS_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+#ifdef POLL_DIGITAL_INPUTS
+ if(poll_digital_inputs && xpd->xbus_idx == 0) {
+ if((xpd->timer_count % poll_digital_inputs) == 0)
+ poll_inputs(xpd);
+ }
+#endif
+ handle_fxs_leds(xpd);
+ handle_linefeed(xpd);
+ if(priv->update_offhook_state) { /* set in FXS_card_open() */
+ int i;
+
+ for_each_line(xpd, i) {
+ if(!IS_SET(priv->update_offhook_state, i))
+ continue;
+ /*
+ * Update zaptel with current state of line.
+ */
+ if(IS_SET(xpd->offhook, i)) {
+ update_line_status(xpd, i, 1);
+ } else {
+ update_line_status(xpd, i, 0);
+ }
+ BIT_CLR(priv->update_offhook_state, i);
+ }
+ }
+ if(SPAN_REGISTERED(xpd)) {
+ if(vmwineon && !vmwi_ioctl)
+ detect_vmwi(xpd); /* Detect via FSK modulation */
+ }
+ return 0;
+}
+
+/*---------------- FXS: HOST COMMANDS -------------------------------------*/
+
+static /* 0x0F */ HOSTCMD(FXS, XPD_STATE, bool on)
+{
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
+ return 0;
+}
+
+/*---------------- FXS: Astribank Reply Handlers --------------------------*/
+
+/*
+ * Should be called with spinlocked XPD
+ */
+static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_mask)
+{
+ xbus_t *xbus;
+ struct FXS_priv_data *priv;
+ int i;
+
+ BUG_ON(!xpd);
+ BUG_ON(xpd->direction != TO_PHONE);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ XPD_DBG(SIGNAL, xpd, "offhook=0x%X change_mask=0x%X\n", offhook, change_mask);
+ for_each_line(xpd, i) {
+ if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
+ continue;
+ if(IS_SET(change_mask, i)) {
+ xpd->ringing[i] = 0; /* No more ringing... */
+#ifdef WITH_METERING
+ metering_gen(xpd, i, 0); /* Stop metering... */
+#endif
+ MARK_BLINK(priv, i, LED_GREEN, 0);
+ if(IS_SET(offhook, i)) {
+ LINE_DBG(SIGNAL, xpd, i, "OFFHOOK\n");
+ MARK_ON(priv, i, LED_GREEN);
+ update_line_status(xpd, i, 1);
+ } else {
+ LINE_DBG(SIGNAL, xpd, i, "ONHOOK\n");
+ MARK_OFF(priv, i, LED_GREEN);
+ update_line_status(xpd, i, 0);
+ }
+ }
+ }
+ __pcm_recompute(xpd, 0); /* in a spinlock */
+}
+
+HANDLER_DEF(FXS, SIG_CHANGED)
+{
+ xpp_line_t sig_status = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_status);
+ xpp_line_t sig_toggles = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_toggles);
+ unsigned long flags;
+
+ BUG_ON(!xpd);
+ BUG_ON(xpd->direction != TO_PHONE);
+ XPD_DBG(SIGNAL, xpd, "(PHONE) sig_toggles=0x%04X sig_status=0x%04X\n", sig_toggles, sig_status);
+#if 0
+ Is this needed?
+ for_each_line(xpd, i) {
+ if(IS_SET(sig_toggles, i))
+ do_chan_power(xpd->xbus, xpd, BIT(i), 0); // Power down (prevent overheating!!!)
+ }
+#endif
+ spin_lock_irqsave(&xpd->lock, flags);
+ process_hookstate(xpd, sig_status, sig_toggles);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return 0;
+}
+
+#ifdef POLL_DIGITAL_INPUTS
+static void process_digital_inputs(xpd_t *xpd, const reg_cmd_t *info)
+{
+ int i;
+ bool offhook = (REG_FIELD(info, data_low) & 0x1) == 0;
+ xpp_line_t lines = BIT(info->portnum);
+
+ /* Map SLIC number into line number */
+ for(i = 0; i < ARRAY_SIZE(input_channels); i++) {
+ int channo = input_channels[i];
+ int newchanno;
+
+ if(IS_SET(lines, channo)) {
+ newchanno = xpd->channels - LINES_DIGI_INP + i;
+ BIT_CLR(lines, channo);
+ BIT_SET(lines, newchanno);
+ xpd->ringing[newchanno] = 0; // Stop ringing. No leds for digital inputs.
+ if(offhook && !IS_SET(xpd->offhook, newchanno)) { // OFFHOOK
+ LINE_DBG(SIGNAL, xpd, newchanno, "OFFHOOK\n");
+ update_line_status(xpd, newchanno, 1);
+ } else if(!offhook && IS_SET(xpd->offhook, newchanno)) { // ONHOOK
+ LINE_DBG(SIGNAL, xpd, newchanno, "ONHOOK\n");
+ update_line_status(xpd, newchanno, 0);
+ }
+ }
+ }
+}
+#endif
+
+static const char dtmf_digits[] = {
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#', 'A', 'B', 'C', 'D'
+};
+
+/*
+ * This function is called with spinlocked XPD
+ */
+static void process_dtmf(xpd_t *xpd, xpp_line_t lines, byte val)
+{
+ int i;
+ byte digit;
+ bool is_down = val & 0x10;
+ struct FXS_priv_data *priv;
+
+ if(!dtmf_detection)
+ return;
+ if(!SPAN_REGISTERED(xpd))
+ return;
+ priv = xpd->priv;
+ val &= 0xF;
+ if(val <= 0) {
+ if(is_down)
+ XPD_NOTICE(xpd, "Bad DTMF value %d. Ignored\n", val);
+ return;
+ }
+ val--;
+ digit = dtmf_digits[val];
+ for_each_line(xpd, i) {
+ if(IS_SET(lines, i)) {
+ int event = (is_down) ? ZT_EVENT_DTMFDOWN : ZT_EVENT_DTMFUP;
+ bool want_mute = IS_SET(priv->want_dtmf_mute, i);
+ bool want_event = IS_SET(priv->want_dtmf_events, i);
+
+ if(want_event) {
+ LINE_DBG(SIGNAL, xpd, i,
+ "DTMF digit %s (val=%d) '%c' (want_mute=%s)\n",
+ (is_down)?"DOWN":"UP", val, digit,
+ (want_mute) ? "yes" : "no");
+ } else {
+ LINE_DBG(SIGNAL, xpd, i,
+ "Ignored DTMF digit %s '%c'\n",
+ (is_down)?"DOWN":"UP", digit);
+ }
+ /*
+ * FIXME: we currently don't use the want_dtmf_mute until
+ * we are sure about the logic in Asterisk native bridging.
+ * Meanwhile, simply mute it on button press.
+ */
+ if(is_down && want_mute)
+ __do_mute_dtmf(xpd, i, 1);
+ else
+ __do_mute_dtmf(xpd, i, 0);
+ __pcm_recompute(xpd, 0); /* XPD is locked */
+ if(want_event)
+ zt_qevent_lock(&xpd->chans[i], event | digit);
+ break;
+ }
+ }
+}
+
+static int FXS_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
+{
+ unsigned long flags;
+ struct FXS_priv_data *priv;
+ byte regnum;
+ bool indirect;
+
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ indirect = (REG_FIELD(info, regnum) == 0x1E);
+ regnum = (indirect) ? REG_FIELD(info, subreg) : REG_FIELD(info, regnum);
+ XPD_DBG(REGS, xpd, "%s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
+ (indirect)?"I":"D",
+ regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high));
+ if(!indirect && regnum == REG_DTMF_DECODE) {
+ byte val = REG_FIELD(info, data_low);
+ xpp_line_t lines = BIT(info->portnum);
+
+ process_dtmf(xpd, lines, val);
+ }
+#ifdef POLL_DIGITAL_INPUTS
+ /*
+ * Process digital inputs polling results
+ */
+ else if(xpd->xbus_idx == 0 && !indirect && regnum == REG_DIGITAL_IOCTRL) {
+ process_digital_inputs(xpd, info);
+ }
+#endif
+ else if(!indirect && regnum == REG_LOOPCLOSURE) { /* OFFHOOK ? */
+ byte val = REG_FIELD(info, data_low);
+ xpp_line_t mask = BIT(info->portnum);
+ xpp_line_t offhook;
+
+ offhook = (val & REG_LOOPCLOSURE_LCR) ? mask : 0;
+ LINE_DBG(SIGNAL, xpd, info->portnum,
+ "REG_LOOPCLOSURE: dataL=0x%X (offhook=0x%X mask=0x%X\n",
+ val, offhook, mask);
+ process_hookstate(xpd, offhook, mask);
+ } else {
+#if 0
+ XPD_NOTICE(xpd, "Spurious register reply(ignored): %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
+ (indirect)?"I":"D",
+ regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high));
+#endif
+ }
+ /* Update /proc info only if reply relate to the last slic read request */
+ if(
+ REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) &&
+ REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) &&
+ REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) {
+ xpd->last_reply = *info;
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return 0;
+}
+
+static xproto_table_t PROTO_TABLE(FXS) = {
+ .owner = THIS_MODULE,
+ .entries = {
+ /* Prototable Card Opcode */
+ XENTRY( FXS, FXS, SIG_CHANGED ),
+ },
+ .name = "FXS", /* protocol name */
+ .ports_per_subunit = 8,
+ .type = XPD_TYPE_FXS,
+ .xops = {
+ .card_new = FXS_card_new,
+ .card_init = FXS_card_init,
+ .card_remove = FXS_card_remove,
+ .card_zaptel_preregistration = FXS_card_zaptel_preregistration,
+ .card_zaptel_postregistration = FXS_card_zaptel_postregistration,
+ .card_hooksig = FXS_card_hooksig,
+ .card_tick = FXS_card_tick,
+ .card_pcm_fromspan = generic_card_pcm_fromspan,
+ .card_pcm_tospan = generic_card_pcm_tospan,
+ .card_open = FXS_card_open,
+ .card_close = FXS_card_close,
+ .card_ioctl = FXS_card_ioctl,
+ .card_register_reply = FXS_card_register_reply,
+
+ .XPD_STATE = XPROTO_CALLER(FXS, XPD_STATE),
+ },
+ .packet_is_valid = fxs_packet_is_valid,
+ .packet_dump = fxs_packet_dump,
+};
+
+static bool fxs_packet_is_valid(xpacket_t *pack)
+{
+ const xproto_entry_t *xe;
+
+ // DBG(GENERAL, "\n");
+ xe = xproto_card_entry(&PROTO_TABLE(FXS), XPACKET_OP(pack));
+ return xe != NULL;
+}
+
+static void fxs_packet_dump(const char *msg, xpacket_t *pack)
+{
+ DBG(GENERAL, "%s\n", msg);
+}
+
+/*------------------------- SLIC Handling --------------------------*/
+
+static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xpd_t *xpd = data;
+ struct FXS_priv_data *priv;
+ int i;
+ int led;
+
+ if(!xpd)
+ return -ENODEV;
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ len += sprintf(page + len, "%-8s %-10s %-10s %-10s\n",
+ "Channel",
+ "idletxhookstate",
+ "lasttxhook",
+ "ohttimer"
+ );
+ for_each_line(xpd, i) {
+ char pref;
+
+ if(IS_SET(xpd->digital_outputs, i))
+ pref = 'O';
+ else if(IS_SET(xpd->digital_inputs, i))
+ pref = 'I';
+ else
+ pref = ' ';
+ len += sprintf(page + len, "%c%7d %10d %10d %10d\n",
+ pref,
+ i,
+ priv->idletxhookstate[i],
+ priv->lasttxhook[i],
+ priv->ohttimer[i]
+ );
+ }
+ len += sprintf(page + len, "\n");
+ for(led = 0; led < NUM_LEDS; led++) {
+ len += sprintf(page + len, "LED #%d", led);
+ len += sprintf(page + len, "\n\t%-17s: ", "ledstate");
+ for_each_line(xpd, i) {
+ if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
+ len += sprintf(page + len, "%d ", IS_SET(priv->ledstate[led], i));
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "ledcontrol");
+ for_each_line(xpd, i) {
+ if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
+ len += sprintf(page + len, "%d ", IS_SET(priv->ledcontrol[led], i));
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "led_counter");
+ for_each_line(xpd, i) {
+ if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
+ len += sprintf(page + len, "%d ", LED_COUNTER(priv,i,led));
+ }
+ len += sprintf(page + len, "\n");
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+}
+
+#ifdef WITH_METERING
+static int proc_xpd_metering_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ xpd_t *xpd = data;
+ char buf[MAX_PROC_WRITE];
+ lineno_t chan;
+ int num;
+ int ret;
+
+ if(!xpd)
+ return -ENODEV;
+ if(count >= MAX_PROC_WRITE - 1) {
+ XPD_ERR(xpd, "Metering string too long (%lu)\n", count);
+ return -EINVAL;
+ }
+ if(copy_from_user(&buf, buffer, count))
+ return -EFAULT;
+ buf[count] = '\0';
+ ret = sscanf(buf, "%d", &num);
+ if(ret != 1) {
+ XPD_ERR(xpd, "Metering value should be number. Got '%s'\n", buf);
+ return -EINVAL;
+ }
+ chan = num;
+ if(chan != PORT_BROADCAST && chan > xpd->channels) {
+ XPD_ERR(xpd, "Metering tone: bad channel number %d\n", chan);
+ return -EINVAL;
+ }
+ if((ret = metering_gen(xpd, chan, 1)) < 0) {
+ XPD_ERR(xpd, "Failed sending metering tone\n");
+ return ret;
+ }
+ return count;
+}
+#endif
+
+static int __init card_fxs_startup(void)
+{
+ INFO("revision %s\n", XPP_VERSION);
+#ifdef POLL_DIGITAL_INPUTS
+ INFO("FEATURE: with DIGITAL INPUTS support (polled every %d msec)\n",
+ poll_digital_inputs);
+#else
+ INFO("FEATURE: without DIGITAL INPUTS support\n");
+#endif
+#ifdef ZT_VMWI
+ INFO("FEATURE: ZT_VMWI\n");
+#else
+ INFO("FEATURE: NO ZT_VMWI\n");
+#endif
+#ifdef WITH_METERING
+ INFO("FEATURE: WITH METERING Generation\n");
+#else
+ INFO("FEATURE: NO METERING Generation\n");
+#endif
+ xproto_register(&PROTO_TABLE(FXS));
+ return 0;
+}
+
+static void __exit card_fxs_cleanup(void)
+{
+ xproto_unregister(&PROTO_TABLE(FXS));
+}
+
+MODULE_DESCRIPTION("XPP FXS Card Driver");
+MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(XPP_VERSION);
+MODULE_ALIAS_XPD(XPD_TYPE_FXS);
+
+module_init(card_fxs_startup);
+module_exit(card_fxs_cleanup);
diff --git a/drivers/dahdi/xpp/card_fxs.h b/drivers/dahdi/xpp/card_fxs.h
new file mode 100644
index 0000000..0b36d3d
--- /dev/null
+++ b/drivers/dahdi/xpp/card_fxs.h
@@ -0,0 +1,42 @@
+#ifndef CARD_FXS_H
+#define CARD_FXS_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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 "xpd.h"
+
+enum fxs_opcodes {
+ XPROTO_NAME(FXS, SIG_CHANGED) = 0x06,
+/**/
+ XPROTO_NAME(FXS, XPD_STATE) = 0x0F, /* Write to SLIC */
+ XPROTO_NAME(FXS, CHAN_POWER) = 0x0F, /* Write to SLIC */
+ XPROTO_NAME(FXS, CHAN_CID) = 0x0F, /* Write to SLIC */
+ XPROTO_NAME(FXS, LED) = 0x0F, /* Write to SLIC */
+};
+
+
+DEF_RPACKET_DATA(FXS, SIG_CHANGED,
+ xpp_line_t sig_status; /* channels: lsb=1, msb=8 */
+ xpp_line_t sig_toggles; /* channels: lsb=1, msb=8 */
+ );
+
+#endif /* CARD_FXS_H */
diff --git a/drivers/dahdi/xpp/card_global.c b/drivers/dahdi/xpp/card_global.c
new file mode 100644
index 0000000..7a3d101
--- /dev/null
+++ b/drivers/dahdi/xpp/card_global.c
@@ -0,0 +1,835 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include "xdefs.h"
+#include "xpd.h"
+#include "xpp_zap.h"
+#include "xproto.h"
+#include "zap_debug.h"
+#include "xbus-core.h"
+#include "parport_debug.h"
+
+static const char rcsid[] = "$Id$";
+
+DEF_PARM(charp,initdir, "/usr/share/zaptel", 0644, "The directory of card initialization scripts");
+
+#define CHIP_REGISTERS "chipregs"
+
+extern int debug;
+
+/*---------------- GLOBAL PROC handling -----------------------------------*/
+
+static int proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xpd_t *xpd = data;
+ reg_cmd_t *info;
+
+ if(!xpd)
+ return -ENODEV;
+ spin_lock_irqsave(&xpd->lock, flags);
+ info = &xpd->last_reply;
+ len += sprintf(page + len, "# Writing bad data into this file may damage your hardware!\n");
+ len += sprintf(page + len, "# Consult firmware docs first\n");
+ len += sprintf(page + len, "#\n");
+ if(REG_FIELD(info, do_subreg)) {
+ len += sprintf(page + len, "#CH\tOP\tReg.\tSub\tDL\n");
+ len += sprintf(page + len, "%2d\tRS\t%02X\t%02X\t%02X\n",
+ info->portnum,
+ REG_FIELD(info, regnum), REG_FIELD(info, subreg), REG_FIELD(info, data_low));
+ } else {
+ len += sprintf(page + len, "#CH\tOP\tReg.\tDL\n");
+ len += sprintf(page + len, "%2d\tRD\t%02X\t%02X\n",
+ info->portnum,
+ REG_FIELD(info, regnum), REG_FIELD(info, data_low));
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+}
+
+static int parse_hexbyte(const char *buf)
+{
+ char *endp;
+ unsigned val;
+
+ val = simple_strtoul(buf, &endp, 16);
+ if(*endp != '\0' || val > 0xFF)
+ return -EBADR;
+ return (byte)val;
+}
+
+static int execute_chip_command(xpd_t *xpd, const int argc, char *argv[])
+{
+ int argno;
+ char num_args;
+ int portno;
+ bool writing;
+ int op; /* [W]rite, [R]ead */
+ int addr_mode; /* [D]irect, [I]ndirect, [Mm]ulti */
+ bool do_indirect = 0;
+ int regnum;
+ int subreg;
+ int data_low;
+ bool do_datah;
+ int data_high;
+ int ret = -EBADR;
+
+ num_args = 2; /* port + operation */
+ if(argc < num_args) {
+ XPD_ERR(xpd, "Not enough arguments (%d)\n", argc);
+ XPD_ERR(xpd,
+ "Any Command is composed of at least %d words (got only %d)\n",
+ num_args, argc);
+ goto out;
+ }
+ /* Process the arguments */
+ argno = 0;
+ if(strcmp(argv[argno], "*") == 0) {
+ portno = PORT_BROADCAST;
+ //XPD_DBG(REGS, xpd, "Port broadcast\n");
+ } else {
+ portno = parse_hexbyte(argv[argno]);
+ if(portno < 0 || portno >= 8) {
+ XPD_ERR(xpd, "Illegal port number '%s'\n", argv[argno]);
+ goto out;
+ }
+ //XPD_DBG(REGS, xpd, "Port is %d\n", portno);
+ }
+ argno++;
+ if(strlen(argv[argno]) != 2) {
+ XPD_ERR(xpd, "Wrong operation codes '%s'\n", argv[argno]);
+ goto out;
+ }
+ op = argv[argno][0];
+ switch(op) {
+ case 'W':
+ writing = 1;
+ num_args++; /* data low */
+ //XPD_DBG(REGS, xpd, "WRITING\n");
+ break;
+ case 'R':
+ writing = 0;
+ //XPD_DBG(REGS, xpd, "READING\n");
+ break;
+ default:
+ XPD_ERR(xpd, "Unkown operation type '%c'\n", op);
+ goto out;
+ }
+ addr_mode = argv[argno][1];
+ switch(addr_mode) {
+ case 'I':
+ do_indirect = 1;
+ num_args += 2; /* register + subreg */
+ //XPD_DBG(REGS, xpd, "INDIRECT\n");
+ break;
+ case 'D':
+ do_indirect = 0;
+ num_args++; /* register */
+ //XPD_DBG(REGS, xpd, "DIRECT\n");
+ break;
+ case 'M':
+ case 'm':
+ if(op != 'W') {
+ XPD_ERR(xpd,
+ "Can use Multibyte (%c) only with op 'W'\n", addr_mode);
+ goto out;
+ }
+ num_args--; /* No data low */
+ //XPD_DBG(REGS, xpd, "Multibyte (%c)\n", addr_mode);
+ break;
+ default:
+ XPD_ERR(xpd, "Unkown addressing type '%c'\n", addr_mode);
+ goto out;
+ }
+ if(argv[argno][2] != '\0') {
+ XPD_ERR(xpd, "Bad operation field '%s'\n", argv[argno]);
+ goto out;
+ }
+ if(argc < num_args) {
+ XPD_ERR(xpd,
+ "Command \"%s\" is composed of at least %d words (got only %d)\n",
+ argv[argno], num_args, argc);
+ goto out;
+ }
+ argno++;
+ if(addr_mode == 'M' || addr_mode == 'm') {
+ if(argno < argc) {
+ XPD_ERR(xpd,
+ "Magic-Multibyte(%c) with %d extra arguments\n",
+ addr_mode, argc - argno);
+ goto out;
+ }
+ ret = send_multibyte_request(xpd->xbus, xpd->addr.unit, portno,
+ addr_mode == 'm', NULL, 0);
+ goto out;
+ }
+ /* Normal (non-Magic) register commands */
+ do_datah = 0;
+ if(argno >= argc) {
+ XPD_ERR(xpd, "Missing register number\n");
+ goto out;
+ }
+ regnum = parse_hexbyte(argv[argno]);
+ if(regnum < 0) {
+ XPD_ERR(xpd, "Illegal register number '%s'\n", argv[argno]);
+ goto out;
+ }
+ //XPD_DBG(REGS, xpd, "Register is %X\n", regnum);
+ argno++;
+ if(do_indirect) {
+ if(argno >= argc) {
+ XPD_ERR(xpd, "Missing subregister number\n");
+ goto out;
+ }
+ subreg = parse_hexbyte(argv[argno]);
+ if(subreg < 0) {
+ XPD_ERR(xpd, "Illegal subregister number '%s'\n", argv[argno]);
+ goto out;
+ }
+ //XPD_DBG(REGS, xpd, "Subreg is %X\n", subreg);
+ argno++;
+ } else
+ subreg = 0;
+ if(writing) {
+ if(argno >= argc) {
+ XPD_ERR(xpd, "Missing data low number\n");
+ goto out;
+ }
+ data_low = parse_hexbyte(argv[argno]);
+ if(data_low < 0) {
+ XPD_ERR(xpd, "Illegal data_low number '%s'\n", argv[argno]);
+ goto out;
+ }
+ //XPD_DBG(REGS, xpd, "Data Low is %X\n", data_low);
+ argno++;
+ } else
+ data_low = 0;
+ if(argno < argc) {
+ do_datah = 1;
+ if(!argv[argno]) {
+ XPD_ERR(xpd, "Missing data high number\n");
+ goto out;
+ }
+ data_high = parse_hexbyte(argv[argno]);
+ if(data_high < 0) {
+ XPD_ERR(xpd, "Illegal data_high number '%s'\n", argv[argno]);
+ goto out;
+ }
+ //XPD_DBG(REGS, xpd, "Data High is %X\n", data_high);
+ argno++;
+ } else
+ data_high = 0;
+ if(argno < argc) {
+ XPD_ERR(xpd,
+ "Command contains an extra %d argument\n",
+ argc - argno);
+ goto out;
+ }
+#if 0
+ XPD_DBG(REGS, xpd,
+ "portno=%d writing=%d regnum=%d do_subreg=%d subreg=%d dataL=%d do_datah=%d dataH=%d\n",
+ portno, /* portno */
+ writing, /* writing */
+ regnum,
+ do_indirect, /* use subreg */
+ subreg, /* subreg */
+ data_low,
+ do_datah, /* use data_high*/
+ data_high);
+#endif
+ ret = xpp_register_request(xpd->xbus, xpd, portno,
+ writing, regnum, do_indirect, subreg,
+ data_low, do_datah, data_high, 1);
+out:
+ return ret;
+}
+
+static int parse_chip_command(xpd_t *xpd, char *cmdline)
+{
+ xbus_t *xbus;
+ int ret = -EBADR;
+ byte buf[MAX_PROC_WRITE];
+ char *str;
+ char *p;
+ static const int MAX_ARGS = 10;
+ char *argv[MAX_ARGS + 1];
+ int argc;
+ int i;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ if(!XBUS_GET(xbus)) {
+ XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down.\n");
+ return -EBUSY;
+ }
+ strlcpy(buf, cmdline, MAX_PROC_WRITE); /* Save a copy */
+ if(buf[0] == '#' || buf[0] == ';')
+ XPD_DBG(REGS, xpd, "Note: '%s'\n", buf);
+ if((p = strchr(buf, '#')) != NULL) /* Truncate comments */
+ *p = '\0';
+ if((p = strchr(buf, ';')) != NULL) /* Truncate comments */
+ *p = '\0';
+ for(p = buf; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */
+ ;
+ str = p;
+ for(i = 0; (p = strsep(&str, " \t")) != NULL && i < MAX_ARGS; ) {
+ if(*p != '\0') {
+ argv[i] = p;
+ // XPD_DBG(REGS, xpd, "ARG %d = '%s'\n", i, p);
+ i++;
+ }
+ }
+ argv[i] = NULL;
+ argc = i;
+ if(p) {
+ XPD_ERR(xpd, "Too many words (%d) to process. Last was '%s'\n", i, p);
+ goto out;
+ }
+ if(argc)
+ ret = execute_chip_command(xpd, argc, argv);
+ else
+ ret = 0; /* empty command - no op */
+out:
+ XBUS_PUT(xbus);
+ return ret;
+}
+
+
+static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ xpd_t *xpd = data;
+ char buf[MAX_PROC_WRITE];
+ char *p;
+ int i;
+ int ret;
+
+ if(!xpd)
+ return -ENODEV;
+ for(i = 0; i < count; /* noop */) {
+ for(p = buf; p < buf + MAX_PROC_WRITE; p++) { /* read a line */
+ if(i >= count)
+ break;
+ if(get_user(*p, buffer + i))
+ return -EFAULT;
+ i++;
+ if(*p == '\n' || *p == '\r') /* whatever */
+ break;
+ }
+ if(p >= buf + MAX_PROC_WRITE)
+ return -E2BIG;
+ *p = '\0';
+ ret = parse_chip_command(xpd, buf);
+ if(ret < 0) {
+ XPD_NOTICE(xpd, "Failed writing command: '%s'\n", buf);
+ return ret;
+ }
+ msleep(1); /* don't overflow command queue */
+ }
+ return count;
+}
+
+void chip_proc_remove(xbus_t *xbus, xpd_t *xpd)
+{
+ BUG_ON(!xpd);
+#ifdef CONFIG_PROC_FS
+ if(xpd->proc_xpd_chipregs) {
+ XBUS_DBG(PROC, xbus, "UNIT %d: Removing %s\n", xpd->addr.unit, CHIP_REGISTERS);
+ xpd->proc_xpd_chipregs->data = NULL;
+ remove_proc_entry(CHIP_REGISTERS, xpd->proc_xpd_dir);
+ }
+#endif
+}
+
+int chip_proc_create(xbus_t *xbus, xpd_t *xpd)
+{
+ BUG_ON(!xpd);
+#ifdef CONFIG_PROC_FS
+ XBUS_DBG(PROC, xbus, "UNIT %d: Creating %s\n", xpd->addr.unit, CHIP_REGISTERS);
+ xpd->proc_xpd_chipregs = create_proc_entry(CHIP_REGISTERS, 0644, xpd->proc_xpd_dir);
+ if(!xpd->proc_xpd_chipregs) {
+ XPD_ERR(xpd, "Failed to create proc file '%s'\n", CHIP_REGISTERS);
+ goto err;
+ }
+ xpd->proc_xpd_chipregs->owner = THIS_MODULE;
+ xpd->proc_xpd_chipregs->write_proc = proc_xpd_register_write;
+ xpd->proc_xpd_chipregs->read_proc = proc_xpd_register_read;
+ xpd->proc_xpd_chipregs->data = xpd;
+#endif
+ return 0;
+err:
+ chip_proc_remove(xbus, xpd);
+ return -EINVAL;
+}
+
+/*---------------- GLOBAL Protocol Commands -------------------------------*/
+
+static bool global_packet_is_valid(xpacket_t *pack);
+static void global_packet_dump(const char *msg, xpacket_t *pack);
+
+/*---------------- GLOBAL: HOST COMMANDS ----------------------------------*/
+
+/* 0x07 */ HOSTCMD(GLOBAL, AB_REQUEST)
+{
+ int ret = 0;
+ xframe_t *xframe;
+ xpacket_t *pack;
+
+ if(!xbus) {
+ DBG(DEVICES, "NO XBUS\n");
+ return -EINVAL;
+ }
+ XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, AB_REQUEST, 0);
+ RPACKET_FIELD(pack, GLOBAL, AB_REQUEST, rev) = XPP_PROTOCOL_VERSION;
+ XBUS_DBG(DEVICES, xbus, "Protocol Version %d\n", XPP_PROTOCOL_VERSION);
+ ret = send_cmd_frame(xbus, xframe);
+ return ret;
+}
+
+int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno,
+ bool writing, byte regnum, bool do_subreg, byte subreg,
+ byte data_low, bool do_datah, byte data_high, bool should_reply)
+{
+ int ret = 0;
+ xframe_t *xframe;
+ xpacket_t *pack;
+ reg_cmd_t *reg_cmd;
+
+ if(!xbus) {
+ DBG(REGS, "NO XBUS\n");
+ return -EINVAL;
+ }
+ XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->xbus_idx);
+ LINE_DBG(REGS, xpd, portno, "%c%c %02X %02X %02X %02X\n",
+ (writing)?'W':'R',
+ (do_subreg)?'S':'D',
+ regnum, subreg, data_low, data_high);
+ reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd);
+ reg_cmd->bytes = sizeof(*reg_cmd) - 1; // do not count the 'bytes' field
+ reg_cmd->is_multibyte = 0;
+ if(portno == PORT_BROADCAST) {
+ reg_cmd->portnum = 0;
+ REG_FIELD(reg_cmd, all_ports_broadcast) = 1;
+ } else {
+ reg_cmd->portnum = portno;
+ REG_FIELD(reg_cmd, all_ports_broadcast) = 0;
+ }
+ reg_cmd->eoframe = 0;
+ REG_FIELD(reg_cmd, reserved) = 0; /* force reserved bits to 0 */
+ REG_FIELD(reg_cmd, read_request) = (writing) ? 0 : 1;
+ REG_FIELD(reg_cmd, do_subreg) = do_subreg;
+ REG_FIELD(reg_cmd, regnum) = regnum;
+ REG_FIELD(reg_cmd, subreg) = subreg;
+ REG_FIELD(reg_cmd, do_datah) = do_datah;
+ REG_FIELD(reg_cmd, data_low) = data_low;
+ REG_FIELD(reg_cmd, data_high) = data_high;
+ if(should_reply)
+ xpd->requested_reply = *reg_cmd;
+ if(debug & DBG_REGS) {
+ dump_reg_cmd("REG_REQ", 1, xbus, xpd->addr.unit, reg_cmd->portnum, reg_cmd);
+ dump_packet("REG_REQ", pack, 1);
+ }
+ ret = send_cmd_frame(xbus, xframe);
+ return ret;
+}
+
+int send_multibyte_request(xbus_t *xbus,
+ unsigned unit, xportno_t portno,
+ bool eoftx, byte *buf, unsigned len)
+{
+ xframe_t *xframe;
+ xpacket_t *pack;
+ reg_cmd_t *reg_cmd;
+ int ret;
+
+ /*
+ * Zero length multibyte is legal and has special meaning for the
+ * firmware:
+ * eoftx==1: Start sending us D-channel packets.
+ * eoftx==0: Stop sending us D-channel packets.
+ */
+ if(len > MULTIBYTE_MAX_LEN) {
+ PORT_ERR(xbus, unit, portno, "%s: len=%d is too long. dropping.\n", __FUNCTION__, len);
+ return -EINVAL;
+ }
+ XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, unit);
+ reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd);
+ reg_cmd->bytes = len;
+ reg_cmd->is_multibyte = 1;
+ reg_cmd->portnum = portno;
+ reg_cmd->eoframe = eoftx;
+ if(len > 0) {
+ memcpy(REG_XDATA(reg_cmd), (byte *)buf, len);
+ } else {
+ PORT_DBG(REGS, xbus, unit, portno, "Magic Packet (eoftx=%d)\n", eoftx);
+ }
+ if(debug & DBG_REGS)
+ dump_xframe(__FUNCTION__, xbus, xframe, debug);
+ ret = send_cmd_frame(xbus, xframe);
+ if(ret < 0)
+ PORT_ERR(xbus, unit, portno, "%s: failed sending xframe\n", __FUNCTION__);
+ return ret;
+}
+
+/*
+ * The XPD parameter is totaly ignored by the driver and firmware as well.
+ */
+/* 0x19 */ HOSTCMD(GLOBAL, SYNC_SOURCE, enum sync_mode mode, int drift)
+{
+ xframe_t *xframe;
+ xpacket_t *pack;
+ const char *mode_name;
+
+ BUG_ON(!xbus);
+ if((mode_name = sync_mode_name(mode)) == NULL) {
+ XBUS_ERR(xbus, "SYNC_SOURCE: bad sync_mode=0x%X\n", mode);
+ return -EINVAL;
+ }
+ XBUS_DBG(SYNC, xbus, "%s (0x%X), drift=%d\n", mode_name, mode, drift);
+ XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, SYNC_SOURCE, 0);
+ RPACKET_FIELD(pack, GLOBAL, SYNC_SOURCE, sync_mode) = mode;
+ RPACKET_FIELD(pack, GLOBAL, SYNC_SOURCE, drift) = drift;
+ send_cmd_frame(xbus, xframe);
+ return 0;
+}
+
+/* 0x23 */ HOSTCMD(GLOBAL, RESET_SYNC_COUNTERS)
+{
+ xframe_t *xframe;
+ xpacket_t *pack;
+
+ BUG_ON(!xbus);
+ //XBUS_DBG(SYNC, xbus, "\n");
+ XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, RESET_SYNC_COUNTERS, 0);
+ RPACKET_FIELD(pack, GLOBAL, RESET_SYNC_COUNTERS, mask) = 0x10;
+ send_cmd_frame(xbus, xframe);
+ return 0;
+}
+
+/*---------------- GLOBAL: Astribank Reply Handlers -----------------------*/
+
+HANDLER_DEF(GLOBAL, NULL_REPLY)
+{
+ XBUS_DBG(GENERAL, xbus, "got len=%d\n", XPACKET_LEN(pack));
+ return 0;
+}
+
+HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */
+{
+ struct xbus_workqueue *worker = xbus->worker;
+ byte rev;
+ struct unit_descriptor *units;
+ int count_units;
+ int i;
+ int ret = 0;
+
+ rev = RPACKET_FIELD(pack, GLOBAL, AB_DESCRIPTION, rev);
+ units = RPACKET_FIELD(pack, GLOBAL, AB_DESCRIPTION, unit_descriptor);
+ count_units = XPACKET_LEN(pack) - ((byte *)units - (byte *)pack);
+ count_units /= sizeof(*units);
+ if(rev != XPP_PROTOCOL_VERSION) {
+ XBUS_NOTICE(xbus, "Bad protocol version %d (should be %d)\n",
+ rev, XPP_PROTOCOL_VERSION);
+ ret = -EPROTO;
+ goto proto_err;
+ }
+ if(count_units > NUM_UNITS) {
+ XBUS_NOTICE(xbus, "Too many units %d (should be %d)\n",
+ count_units, NUM_UNITS);
+ ret = -EPROTO;
+ goto proto_err;
+ }
+ if(count_units <= 0) {
+ XBUS_NOTICE(xbus, "Empty astribank? (%d units)\n",
+ count_units);
+ ret = -EPROTO;
+ goto proto_err;
+ }
+ XBUS_INFO(xbus, "DESCRIPTOR: %d cards, protocol revision %d\n", count_units, rev);
+ xbus->revision = rev;
+ if(!worker) {
+ XBUS_ERR(xbus, "missing worker\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ for(i = 0; i < count_units; i++) {
+ struct unit_descriptor *this_unit = &units[i];
+ struct card_desc_struct *card_desc;
+ unsigned long flags;
+
+ if((card_desc = KZALLOC(sizeof(struct card_desc_struct), GFP_ATOMIC)) == NULL) {
+ XBUS_ERR(xbus, "Card description allocation failed.\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ card_desc->magic = CARD_DESC_MAGIC;
+ INIT_LIST_HEAD(&card_desc->card_list);
+ card_desc->type = this_unit->type;
+ card_desc->subtype = this_unit->subtype;
+ card_desc->xpd_addr = this_unit->addr;
+ card_desc->numchips = this_unit->numchips;
+ card_desc->ports_per_chip = this_unit->ports_per_chip;
+ card_desc->port_dir = this_unit->port_dir;
+ card_desc->ports = card_desc->numchips * card_desc->ports_per_chip;
+ XBUS_INFO(xbus, " CARD %d type=%d.%d ports=%d (%dx%d), port-dir=0x%02X\n",
+ card_desc->xpd_addr.unit,
+ card_desc->type,
+ card_desc->subtype,
+ card_desc->ports,
+ card_desc->numchips,
+ card_desc->ports_per_chip,
+ card_desc->port_dir
+ );
+ spin_lock_irqsave(&worker->worker_lock, flags);
+ worker->num_units++;
+ XBUS_COUNTER(xbus, UNITS)++;
+ list_add_tail(&card_desc->card_list, &worker->card_list);
+ spin_unlock_irqrestore(&worker->worker_lock, flags);
+ }
+ /* Initialize the work. (adapt to kernel API changes). */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+ INIT_WORK(&worker->xpds_init_work, xbus_populate);
+#else
+ INIT_WORK(&worker->xpds_init_work, xbus_populate, worker);
+#endif
+ xbus = get_xbus(xbus->num); /* released in xbus_populate() */
+ BUG_ON(!xbus);
+ /* Now send it */
+ if(!queue_work(worker->wq, &worker->xpds_init_work)) {
+ XBUS_ERR(xbus, "Failed to queue xpd initialization work\n");
+ return -ENODEV;
+ }
+ return 0;
+proto_err:
+ dump_packet("AB_DESCRIPTION", pack, DBG_ANY);
+err:
+ return ret;
+}
+
+HANDLER_DEF(GLOBAL, REGISTER_REPLY)
+{
+ reg_cmd_t *reg = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REPLY, regcmd);
+
+ if(!xpd) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) < 5)
+ notify_bad_xpd(__FUNCTION__, xbus, XPACKET_ADDR(pack), "");
+ return -EPROTO;
+ }
+ if(debug & DBG_REGS) {
+ dump_reg_cmd("REG_REPLY", 0, xbus, xpd->addr.unit, reg->portnum, reg);
+ dump_packet("REG_REPLY", pack, 1);
+ }
+ return CALL_XMETHOD(card_register_reply, xbus, xpd, reg);
+}
+
+HANDLER_DEF(GLOBAL, SYNC_REPLY)
+{
+ byte mode = RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, sync_mode);
+ byte drift = RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, drift);
+ const char *mode_name;
+
+ BUG_ON(!xbus);
+ if((mode_name = sync_mode_name(mode)) == NULL) {
+ XBUS_ERR(xbus, "SYNC_REPLY: bad sync_mode=0x%X\n", mode);
+ return -EINVAL;
+ }
+ XBUS_DBG(SYNC, xbus, "%s (0x%X), drift=%d\n", mode_name, mode, drift);
+ //dump_packet("SYNC_REPLY", pack, debug & DBG_SYNC);
+ got_new_syncer(xbus, mode, drift);
+ return 0;
+}
+
+#define TMP_NAME_LEN (XBUS_NAMELEN + XPD_NAMELEN + 5)
+
+HANDLER_DEF(GLOBAL, ERROR_CODE)
+{
+ byte errorcode;
+ char tmp_name[TMP_NAME_LEN];
+ static long rate_limit;
+ const char *msg;
+ const static char *fw_messages[] = {
+ [1] = "Packet too short",
+ [2] = "Len field is too small",
+ [3] = "Premature packet end",
+ [4] = "Invalid op code",
+ [5] = "Invalid packet len",
+ [6] = "SPI fifo full",
+ };
+
+ BUG_ON(!xbus);
+ if((rate_limit++ % 5003) > 200)
+ return 0;
+ errorcode = RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, errorcode);
+ msg = (errorcode < ARRAY_SIZE(fw_messages))
+ ? fw_messages[errorcode]
+ : "UNKNOWN CODE";
+ if(!xpd) {
+ snprintf(tmp_name, TMP_NAME_LEN, "%s(%1d%1d)", xbus->busname,
+ XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack));
+ } else {
+ snprintf(tmp_name, TMP_NAME_LEN, "%s/%s", xbus->busname, xpd->xpdname);
+ }
+ NOTICE("%s: FIRMWARE: %s CODE = 0x%X (%s) (rate_limit=%ld)\n",
+ tmp_name, cmd->name, errorcode, msg, rate_limit);
+ dump_packet("FIRMWARE: ", pack, 1);
+ /*
+ * FIXME: Should implement an error recovery plan
+ */
+ return 0;
+}
+
+
+xproto_table_t PROTO_TABLE(GLOBAL) = {
+ .entries = {
+ /* Prototable Card Opcode */
+ XENTRY( GLOBAL, GLOBAL, NULL_REPLY ),
+ XENTRY( GLOBAL, GLOBAL, AB_DESCRIPTION ),
+ XENTRY( GLOBAL, GLOBAL, SYNC_REPLY ),
+ XENTRY( GLOBAL, GLOBAL, ERROR_CODE ),
+ XENTRY( GLOBAL, GLOBAL, REGISTER_REPLY ),
+ },
+ .name = "GLOBAL",
+ .packet_is_valid = global_packet_is_valid,
+ .packet_dump = global_packet_dump,
+};
+
+static bool global_packet_is_valid(xpacket_t *pack)
+{
+ const xproto_entry_t *xe;
+
+ //DBG(GENERAL, "\n");
+ xe = xproto_global_entry(XPACKET_OP(pack));
+ return xe != NULL;
+}
+
+static void global_packet_dump(const char *msg, xpacket_t *pack)
+{
+ DBG(GENERAL, "%s\n", msg);
+}
+
+#define MAX_ENV_STR 40
+#define MAX_PATH_STR 60
+
+int run_initialize_registers(xpd_t *xpd)
+{
+ int ret;
+ xbus_t *xbus;
+ char busstr[MAX_ENV_STR];
+ char unitstr[MAX_ENV_STR];
+ char subunitsstr[MAX_ENV_STR];
+ char typestr[MAX_ENV_STR];
+ char directionstr[MAX_ENV_STR];
+ char revstr[MAX_ENV_STR];
+ char connectorstr[MAX_ENV_STR];
+ char init_card[MAX_PATH_STR];
+ byte direction_mask;
+ int i;
+ char *argv[] = {
+ init_card,
+ NULL
+ };
+ char *envp[] = {
+ busstr,
+ unitstr,
+ subunitsstr,
+ typestr,
+ directionstr,
+ revstr,
+ connectorstr,
+ NULL
+ };
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ if(!initdir || !initdir[0]) {
+ XPD_NOTICE(xpd, "Missing initdir parameter\n");
+ return -EINVAL;
+ }
+ direction_mask = 0;
+ for(i = 0; i < xpd->subunits; i++) {
+ xpd_t *su = xpd_byaddr(xbus, xpd->addr.unit, i);
+
+ if(!su) {
+ XPD_ERR(xpd,
+ "Have %d subunits, but not subunit #%d\n",
+ xpd->subunits, i);
+ continue;
+ }
+ direction_mask |= (su->direction == TO_PHONE) ? BIT(i) : 0;
+ }
+ snprintf(busstr, MAX_ENV_STR, "XBUS_NAME=%s", xbus->busname);
+ snprintf(unitstr, MAX_ENV_STR, "UNIT_NUMBER=%d", xpd->addr.unit);
+ snprintf(typestr, MAX_ENV_STR, "UNIT_TYPE=%d", xpd->type);
+ snprintf(subunitsstr, MAX_ENV_STR, "UNIT_SUBUNITS=%d", xpd->subunits);
+ snprintf(directionstr, MAX_ENV_STR, "UNIT_SUBUNITS_DIR=%d", direction_mask);
+ snprintf(revstr, MAX_ENV_STR, "XBUS_REVISION=%d", xbus->revision);
+ snprintf(connectorstr, MAX_ENV_STR, "XBUS_CONNECTOR=%s", xbus->location);
+ if(snprintf(init_card, MAX_PATH_STR, "%s/init_card_%d_%d",
+ initdir, xpd->type, xbus->revision) > MAX_PATH_STR) {
+ XPD_NOTICE(xpd, "Cannot initialize. pathname is longer than %d characters.\n", MAX_PATH_STR);
+ return -E2BIG;
+ }
+ if(!XBUS_GET(xbus)) {
+ XBUS_ERR(xbus, "Skipped register initialization. XBUS is going down\n");
+ return -ENODEV;
+ }
+ XPD_DBG(DEVICES, xpd, "running '%s' for type=%d revision=%d\n",
+ init_card, xpd->type, xbus->revision);
+ ret = call_usermodehelper(init_card, argv, envp, 1);
+ /*
+ * Carefully report results
+ */
+ if(ret == 0)
+ XPD_DBG(DEVICES, xpd, "'%s' finished OK\n", init_card);
+ else if(ret < 0) {
+ XPD_ERR(xpd, "Failed running '%s' (errno %d)\n", init_card, ret);
+ } else {
+ byte exitval = ((unsigned)ret >> 8) & 0xFF;
+ byte sigval = ret & 0xFF;
+
+ if(!exitval) {
+ XPD_ERR(xpd, "'%s' killed by signal %d\n", init_card, sigval);
+ } else {
+ XPD_ERR(xpd, "'%s' aborted with exitval %d\n", init_card, exitval);
+ }
+ ret = -EINVAL;
+ }
+ XBUS_PUT(xbus);
+ return ret;
+}
+
+EXPORT_SYMBOL(sync_mode_name);
+EXPORT_SYMBOL(run_initialize_registers);
+EXPORT_SYMBOL(xpp_register_request);
+EXPORT_SYMBOL(send_multibyte_request);
diff --git a/drivers/dahdi/xpp/card_global.h b/drivers/dahdi/xpp/card_global.h
new file mode 100644
index 0000000..c71f74d
--- /dev/null
+++ b/drivers/dahdi/xpp/card_global.h
@@ -0,0 +1,113 @@
+#ifndef CARD_GLOBAL_H
+#define CARD_GLOBAL_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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 "xdefs.h"
+#include "xbus-pcm.h"
+
+enum global_opcodes {
+ XPROTO_NAME(GLOBAL, AB_REQUEST) = 0x07,
+ XPROTO_NAME(GLOBAL, AB_DESCRIPTION) = 0x08,
+ XPROTO_NAME(GLOBAL, REGISTER_REQUEST) = 0x0F,
+ XPROTO_NAME(GLOBAL, REGISTER_REPLY) = 0x10,
+/**/
+ XPROTO_NAME(GLOBAL, PCM_WRITE) = 0x11,
+ XPROTO_NAME(GLOBAL, PCM_READ) = 0x12,
+/**/
+ XPROTO_NAME(GLOBAL, SYNC_SOURCE) = 0x19,
+ XPROTO_NAME(GLOBAL, SYNC_REPLY) = 0x1A,
+/**/
+ XPROTO_NAME(GLOBAL, ERROR_CODE) = 0x22,
+ XPROTO_NAME(GLOBAL, RESET_SYNC_COUNTERS) = 0x23,
+ XPROTO_NAME(GLOBAL, NULL_REPLY) = 0xFE,
+};
+
+struct unit_descriptor {
+ struct xpd_addr addr;
+ byte subtype:4;
+ byte type:4;
+ byte numchips;
+ byte ports_per_chip;
+ byte port_dir; /* bitmask: 0 - PSTN, 1 - PHONE */
+ byte reserved[2];
+ struct xpd_addr ec_addr;
+};
+
+#define NUM_UNITS 6
+
+DEF_RPACKET_DATA(GLOBAL, NULL_REPLY);
+DEF_RPACKET_DATA(GLOBAL, AB_REQUEST,
+ byte rev;
+ byte reserved;
+ );
+DEF_RPACKET_DATA(GLOBAL, AB_DESCRIPTION,
+ byte rev;
+ byte reserved[3];
+ struct unit_descriptor unit_descriptor[NUM_UNITS];
+ );
+DEF_RPACKET_DATA(GLOBAL, REGISTER_REQUEST,
+ reg_cmd_t reg_cmd;
+ );
+DEF_RPACKET_DATA(GLOBAL, PCM_WRITE,
+ xpp_line_t lines;
+ byte pcm[PCM_CHUNKSIZE];
+ );
+DEF_RPACKET_DATA(GLOBAL, PCM_READ,
+ xpp_line_t lines;
+ byte pcm[PCM_CHUNKSIZE];
+ );
+DEF_RPACKET_DATA(GLOBAL, SYNC_SOURCE,
+ byte sync_mode;
+ byte drift;
+ );
+DEF_RPACKET_DATA(GLOBAL, SYNC_REPLY,
+ byte sync_mode;
+ byte drift;
+ );
+DEF_RPACKET_DATA(GLOBAL, REGISTER_REPLY,
+ reg_cmd_t regcmd;
+ );
+DEF_RPACKET_DATA(GLOBAL, RESET_SYNC_COUNTERS,
+ byte mask;
+ );
+DEF_RPACKET_DATA(GLOBAL, ERROR_CODE,
+ byte errorcode;
+ byte bad_packet[0];
+ );
+
+/* 0x07 */ DECLARE_CMD(GLOBAL, AB_REQUEST);
+/* 0x19 */ DECLARE_CMD(GLOBAL, SYNC_SOURCE, enum sync_mode mode, int drift);
+/* 0x23 */ DECLARE_CMD(GLOBAL, RESET_SYNC_COUNTERS);
+
+void chip_proc_remove(xbus_t *xbus, xpd_t *xpd);
+int chip_proc_create(xbus_t *xbus, xpd_t *xpd);
+int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno,
+ bool writing, byte regnum, bool do_subreg, byte subreg,
+ byte data_low, bool do_datah, byte data_high, bool should_reply);
+int send_multibyte_request(xbus_t *xbus, unsigned unit, xportno_t portno,
+ bool eoftx, byte *buf, unsigned len);
+extern xproto_table_t PROTO_TABLE(GLOBAL);
+int run_initialize_registers(xpd_t *xpd);
+extern charp initdir;
+
+#endif /* CARD_GLOBAL_H */
diff --git a/drivers/dahdi/xpp/card_pri.c b/drivers/dahdi/xpp/card_pri.c
new file mode 100644
index 0000000..335b933
--- /dev/null
+++ b/drivers/dahdi/xpp/card_pri.c
@@ -0,0 +1,1632 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * Parts derived from Cologne demo driver for the chip.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include "xpd.h"
+#include "xproto.h"
+#include "xpp_zap.h"
+#include "card_pri.h"
+#include "zap_debug.h"
+#include "xpd.h"
+#include "xbus-core.h"
+
+static const char rcsid[] = "$Id$";
+
+static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before zap_debug.h */
+static DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in milliseconds (0 - disable)");
+
+#define PRI_LINES_BITMASK BITMASK(31)
+#define PRI_DCHAN_SIGCAP ( \
+ ZT_SIG_EM | \
+ ZT_SIG_CLEAR | \
+ ZT_SIG_FXSLS | \
+ ZT_SIG_FXSGS | \
+ ZT_SIG_FXSKS | \
+ ZT_SIG_FXOLS | \
+ ZT_SIG_FXOGS | \
+ ZT_SIG_FXOKS | \
+ ZT_SIG_CAS | \
+ ZT_SIG_DACS | \
+ ZT_SIG_SF \
+ )
+#define PRI_BCHAN_SIGCAP (ZT_SIG_CLEAR | ZT_SIG_DACS)
+#define MAX_SLAVES 4 /* we have MUX of 4 clocks */
+
+#define PRI_PORT(xpd) ((xpd)->addr.subunit)
+
+/*---------------- PRI Protocol Commands ----------------------------------*/
+
+static bool pri_packet_is_valid(xpacket_t *pack);
+static void pri_packet_dump(const char *msg, xpacket_t *pack);
+static int proc_pri_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int proc_pri_info_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+static int pri_startup(struct zt_span *span);
+static int pri_shutdown(struct zt_span *span);
+static int pri_lineconfig(xpd_t *xpd, int lineconfig);
+
+#define PROC_REGISTER_FNAME "slics"
+#define PROC_PRI_INFO_FNAME "pri_info"
+
+enum pri_protocol {
+ PRI_PROTO_0 = 0,
+ PRI_PROTO_E1 = 1,
+ PRI_PROTO_T1 = 2,
+ PRI_PROTO_J1 = 3
+};
+
+static const char *pri_protocol_name(enum pri_protocol pri_protocol)
+{
+ static const char *protocol_names[] = {
+ [PRI_PROTO_0] = "??", /* unkown */
+ [PRI_PROTO_E1] = "E1",
+ [PRI_PROTO_T1] = "T1",
+ [PRI_PROTO_J1] = "J1"
+ };
+ return protocol_names[pri_protocol];
+}
+
+static int pri_num_channels(enum pri_protocol pri_protocol)
+{
+ static int num_channels[] = {
+ [PRI_PROTO_0] = 0,
+ [PRI_PROTO_E1] = 31,
+ [PRI_PROTO_T1] = 24,
+ [PRI_PROTO_J1] = 0
+ };
+ return num_channels[pri_protocol];
+}
+
+static const char *type_name(enum pri_protocol pri_protocol, bool is_nt)
+{
+ static const char *names[2][4] = {
+ /* TE */ [0] = {
+ [PRI_PROTO_0] = "Unknown_TE",
+ [PRI_PROTO_E1] = "E1_TE",
+ [PRI_PROTO_T1] = "T1_TE",
+ [PRI_PROTO_J1] = "J1_TE"
+ },
+ /* NT */ [1] = {
+ [PRI_PROTO_0] = "Unknown_NT",
+ [PRI_PROTO_E1] = "E1_NT",
+ [PRI_PROTO_T1] = "T1_NT",
+ [PRI_PROTO_J1] = "J1_NT"
+ }
+ };
+ int term = (is_nt) ? 1 : 0;
+
+ return names[term][pri_protocol];
+}
+
+static int pri_linecompat(enum pri_protocol pri_protocol)
+{
+ static const int linecompat[] = {
+ [PRI_PROTO_0] = 0,
+ [PRI_PROTO_E1] =
+ /* coding */
+ ZT_CONFIG_CCS |
+ // CAS |
+ ZT_CONFIG_CRC4 |
+ /* framing */
+ ZT_CONFIG_AMI | ZT_CONFIG_HDB3,
+ [PRI_PROTO_T1] =
+ /* coding */
+ // ZT_CONFIG_D4 |
+ ZT_CONFIG_ESF |
+ /* framing */
+ ZT_CONFIG_AMI | ZT_CONFIG_B8ZS,
+ [PRI_PROTO_J1] = 0
+ };
+
+ DBG(GENERAL, "pri_linecompat: pri_protocol=%d\n", pri_protocol);
+ return linecompat[pri_protocol];
+}
+
+#define PRI_DCHAN_IDX(priv) ((priv)->dchan_num - 1)
+
+enum pri_led_state {
+ PRI_LED_OFF = 0x0,
+ PRI_LED_ON = 0x1,
+ /*
+ * We blink by software from driver, so that
+ * if the driver malfunction that blink would stop.
+ */
+ // PRI_LED_BLINK_SLOW = 0x2, /* 1/2 a second blink cycle */
+ // PRI_LED_BLINK_FAST = 0x3 /* 1/4 a second blink cycle */
+};
+
+enum pri_led_selectors {
+ TE_RED_LED = 0,
+ TE_GREEN_LED = 1,
+ NT_RED_LED = 2,
+ NT_GREEN_LED = 3,
+};
+
+#define NUM_LEDS 4
+
+struct pri_leds {
+ byte state:2; /* enum pri_led_state */
+ byte led_sel:2; /* enum pri_led_selectors */
+ byte reserved:4;
+};
+
+#define REG_FRS0 0x4C /* Framer Receive Status Register 0 */
+#define REG_FRS0_T1_FSR BIT(0) /* T1 - Frame Search Restart Flag */
+#define REG_FRS0_LMFA BIT(1) /* Loss of Multiframe Alignment */
+#define REG_FRS0_E1_NMF BIT(2) /* E1 - No Multiframe Alignment Found */
+#define REG_FRS0_RRA BIT(4) /* Receive Remote Alarm: T1-YELLOW-Alarm */
+#define REG_FRS0_LFA BIT(5) /* Loss of Frame Alignment */
+#define REG_FRS0_AIS BIT(6) /* Alarm Indication Signal: T1-BLUE-Alarm */
+#define REG_FRS0_LOS BIT(7) /* Los Of Signal: T1-RED-Alarm */
+
+#define REG_FRS1 0x4D /* Framer Receive Status Register 1 */
+
+#define REG_LIM0 0x36
+#define REG_LIM0_MAS BIT(0) /* Master Mode, DCO-R circuitry is frequency
+ synchronized to the clock supplied by SYNC */
+#define REG_LIM0_RTRS BIT(5) /*
+ * Receive Termination Resistance Selection:
+ * integrated resistor to create 75 Ohm termination (100 || 300 = 75)
+ * 0 = 100 Ohm
+ * 1 = 75 Ohm
+ */
+#define REG_LIM0_LL BIT(1) /* LL (Local Loopback) */
+
+#define REG_FMR0 0x1C
+#define REG_FMR0_E_RC0 BIT(4) /* Receive Code - LSB */
+#define REG_FMR0_E_RC1 BIT(5) /* Receive Code - MSB */
+#define REG_FMR0_E_XC0 BIT(6) /* Transmit Code - LSB */
+#define REG_FMR0_E_XC1 BIT(7) /* Transmit Code - MSB */
+
+#define REG_FMR1 0x1D
+#define REG_FMR1_XAIS BIT(0) /* Transmit AIS toward transmit end */
+#define REG_FMR1_SSD0 BIT(1)
+#define REG_FMR1_ECM BIT(2)
+#define REG_FMR1_XFS BIT(3)
+#define REG_FMR1_PMOD BIT(4) /* E1 = 0, T1/J1 = 1 */
+#define REG_FMR1_EDL BIT(5)
+#define REG_FMR1_AFR BIT(6)
+
+#define REG_FMR2 0x1E
+#define REG_FMR2_E_ALMF BIT(0) /* Automatic Loss of Multiframe */
+#define REG_FMR2_T_EXZE BIT(0) /* Excessive Zeros Detection Enable */
+#define REG_FMR2_E_AXRA BIT(1) /* Automatic Transmit Remote Alarm */
+#define REG_FMR2_T_AXRA BIT(1) /* Automatic Transmit Remote Alarm */
+#define REG_FMR2_E_PLB BIT(2) /* Payload Loop-Back */
+#define REG_FMR2_E_RFS0 BIT(6) /* Receive Framing Select - LSB */
+#define REG_FMR2_E_RFS1 BIT(7) /* Receive Framing Select - MSB */
+#define REG_FMR2_T_SSP BIT(5) /* Select Synchronization/Resynchronization Procedure */
+#define REG_FMR2_T_MCSP BIT(6) /* Multiple Candidates Synchronization Procedure */
+#define REG_FMR2_T_AFRS BIT(7) /* Automatic Force Resynchronization */
+
+#define REG_FMR4 0x20
+#define REG_FMR4_FM1 BIT(1)
+
+#define REG_XSP_E 0x21
+#define REG_FMR5_T 0x21
+#define REG_XSP_E_XSIF BIT(2) /* Transmit Spare Bit For International Use (FAS Word) */
+#define REG_FMR5_T_XTM BIT(2) /* Transmit Transparent Mode */
+#define REG_XSP_E_AXS BIT(3) /* Automatic Transmission of Submultiframe Status */
+#define REG_XSP_E_EBP BIT(4) /* E-Bit Polarity, Si-bit position of every outgoing CRC multiframe */
+#define REG_XSP_E_CASEN BIT(7) /* Channel Associated Signaling Enable */
+
+#define REG_RC0 0x24
+#define REG_RC0_SJR BIT(7) /* T1 = 0, J1 = 1 */
+
+#define REG_CMR1 0x44
+#define REG_CMR1_DRSS (BIT(7) | BIT(6))
+#define REG_CMR1_RS (BIT(5) | BIT(4))
+#define REG_CMR1_STF BIT(2)
+
+struct PRI_priv_data {
+ bool is_nt;
+ bool clock_source;
+ struct proc_dir_entry *pri_info;
+ enum pri_protocol pri_protocol;
+ int deflaw;
+ unsigned int dchan_num;
+ bool initialized;
+ bool local_loopback;
+ uint poll_noreplies;
+ uint layer1_replies;
+ byte reg_frs0;
+ byte reg_frs1;
+ bool layer1_up;
+ int alarms;
+ byte dchan_tx_sample;
+ byte dchan_rx_sample;
+ uint dchan_tx_counter;
+ uint dchan_rx_counter;
+ bool dchan_alive;
+ uint dchan_alive_ticks;
+ enum pri_led_state ledstate[NUM_LEDS];
+};
+
+static xproto_table_t PROTO_TABLE(PRI);
+
+DEF_RPACKET_DATA(PRI, SET_LED, /* Set one of the LED's */
+ struct pri_leds pri_leds;
+ );
+
+
+static /* 0x33 */ DECLARE_CMD(PRI, SET_LED, enum pri_led_selectors led_sel, enum pri_led_state to_led_state);
+
+#define DO_LED(xpd, which, tostate) \
+ CALL_PROTO(PRI, SET_LED, (xpd)->xbus, (xpd), (which), (tostate))
+
+/*---------------- PRI: Methods -------------------------------------------*/
+
+static int query_subunit(xpd_t *xpd, byte regnum)
+{
+ XPD_DBG(REGS, xpd, "(%d%d): REG=0x%02X\n",
+ xpd->addr.unit, xpd->addr.subunit,
+ regnum);
+ return xpp_register_request(
+ xpd->xbus, xpd,
+ PRI_PORT(xpd), /* portno */
+ 0, /* writing */
+ regnum,
+ 0, /* do_subreg */
+ 0, /* subreg */
+ 0, /* data_L */
+ 0, /* do_datah */
+ 0, /* data_H */
+ 0 /* should_reply */
+ );
+}
+
+
+static int write_subunit(xpd_t *xpd, byte regnum, byte val)
+{
+ XPD_DBG(REGS, xpd, "(%d%d): REG=0x%02X dataL=0x%02X\n",
+ xpd->addr.unit, xpd->addr.subunit,
+ regnum, val);
+ return xpp_register_request(
+ xpd->xbus, xpd,
+ PRI_PORT(xpd), /* portno */
+ 1, /* writing */
+ regnum,
+ 0, /* do_subreg */
+ 0, /* subreg */
+ val, /* data_L */
+ 0, /* do_datah */
+ 0, /* data_H */
+ 0 /* should_reply */
+ );
+}
+
+static int pri_write_reg(xpd_t *xpd, int regnum, byte val)
+{
+ XPD_DBG(REGS, xpd, "(%d%d): REG=0x%02X dataL=0x%02X\n",
+ xpd->addr.unit, xpd->addr.subunit,
+ regnum, val);
+ return xpp_register_request(
+ xpd->xbus, xpd,
+ PRI_PORT(xpd), /* portno */
+ 1, /* writing */
+ regnum,
+ 0, /* do_subreg */
+ 0, /* subreg */
+ val, /* data_L */
+ 0, /* do_datah */
+ 0, /* data_H */
+ 0 /* should_reply */
+ );
+}
+
+static void pri_proc_remove(xbus_t *xbus, xpd_t *xpd)
+{
+ struct PRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(PROC, xpd, "\n");
+#ifdef CONFIG_PROC_FS
+ if(priv->pri_info) {
+ XPD_DBG(PROC, xpd, "Removing xpd PRI_INFO file\n");
+ remove_proc_entry(PROC_PRI_INFO_FNAME, xpd->proc_xpd_dir);
+ }
+#endif
+}
+
+static int pri_proc_create(xbus_t *xbus, xpd_t *xpd)
+{
+ struct PRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(PROC, xpd, "\n");
+#ifdef CONFIG_PROC_FS
+ XPD_DBG(PROC, xpd, "Creating PRI_INFO file\n");
+ priv->pri_info = create_proc_entry(PROC_PRI_INFO_FNAME, 0644, xpd->proc_xpd_dir);
+ if(!priv->pri_info) {
+ XPD_ERR(xpd, "Failed to create proc '%s'\n", PROC_PRI_INFO_FNAME);
+ goto err;
+ }
+ priv->pri_info->owner = THIS_MODULE;
+ priv->pri_info->write_proc = proc_pri_info_write;
+ priv->pri_info->read_proc = proc_pri_info_read;
+ priv->pri_info->data = xpd;
+#endif
+ return 0;
+err:
+ pri_proc_remove(xbus, xpd);
+ return -EINVAL;
+}
+
+static bool valid_pri_modes(const xpd_t *xpd)
+{
+ struct PRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ if(
+ priv->pri_protocol != PRI_PROTO_E1 &&
+ priv->pri_protocol != PRI_PROTO_T1 &&
+ priv->pri_protocol != PRI_PROTO_J1)
+ return 0;
+ return 1;
+}
+
+/*
+ * Set E1/T1/J1
+ * May only be called on unregistered xpd's
+ * (the span and channel description are set according to this)
+ */
+static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto)
+{
+ struct PRI_priv_data *priv;
+ int deflaw;
+ unsigned int dchan_num;
+ byte fmr1 =
+ REG_FMR1_AFR |
+ REG_FMR1_XFS |
+ REG_FMR1_ECM;
+ int default_lineconfig = 0;
+ byte rc0 = 0; /* FIXME: PCM offsets */
+ int ret;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ if(SPAN_REGISTERED(xpd)) {
+ XPD_NOTICE(xpd, "Registered as span %d. Cannot do setup pri protocol (%s)\n",
+ xpd->span.spanno, __FUNCTION__);
+ return -EBUSY;
+ }
+ switch(set_proto) {
+ case PRI_PROTO_E1:
+ deflaw = ZT_LAW_ALAW;
+ dchan_num = 16;
+ default_lineconfig = ZT_CONFIG_CRC4 | ZT_CONFIG_HDB3;
+ break;
+ case PRI_PROTO_T1:
+ deflaw = ZT_LAW_MULAW;
+ dchan_num = 24;
+ default_lineconfig = ZT_CONFIG_ESF | ZT_CONFIG_B8ZS;
+ fmr1 |= REG_FMR1_PMOD;
+ break;
+ case PRI_PROTO_J1:
+ /*
+ * Check all assumptions
+ */
+ deflaw = ZT_LAW_MULAW;
+ dchan_num = 24;
+ fmr1 |= REG_FMR1_PMOD;
+ rc0 |= REG_RC0_SJR;
+ default_lineconfig = 0; /* FIXME: J1??? */
+ XPD_NOTICE(xpd, "J1 is not supported yet\n");
+ return -ENOSYS;
+ default:
+ XPD_ERR(xpd, "%s: Unknown pri protocol = %d\n",
+ __FUNCTION__, set_proto);
+ return -EINVAL;
+ }
+ priv->pri_protocol = set_proto;
+ xpd->channels = pri_num_channels(set_proto);
+ xpd->pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + xpd->channels * ZT_CHUNKSIZE;
+ xpd->wanted_pcm_mask = BITMASK(xpd->channels);
+ priv->deflaw = deflaw;
+ priv->dchan_num = dchan_num;
+ xpd->type_name = type_name(priv->pri_protocol, priv->is_nt);
+ XPD_DBG(GENERAL, xpd, "%s, channels=%d, dchan_num=%d, deflaw=%d\n",
+ pri_protocol_name(set_proto),
+ xpd->channels,
+ priv->dchan_num,
+ priv->deflaw
+ );
+ write_subunit(xpd, REG_FMR1, fmr1);
+#ifdef JAPANEZE_SUPPORT
+ if(rc0)
+ write_subunit(xpd, REG_RC0, rc0);
+#endif
+ /*
+ * Must set default now, so layer1 polling (Register REG_FRS0) would
+ * give reliable results.
+ */
+ ret = pri_lineconfig(xpd, default_lineconfig);
+ if(ret) {
+ XPD_NOTICE(xpd, "Failed setting PRI default line config\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void zap_update_syncsrc(xpd_t *xpd)
+{
+ struct PRI_priv_data *priv;
+ xpd_t *subxpd;
+ int best_spanno = 0;
+ int i;
+
+ if(!SPAN_REGISTERED(xpd))
+ return;
+ for(i = 0; i < MAX_SLAVES; i++) {
+ subxpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, i);
+ if(!subxpd)
+ continue;
+ priv = subxpd->priv;
+ if(priv->clock_source) {
+ if(best_spanno)
+ XPD_ERR(xpd, "Duplicate XPD's with clock_source=1\n");
+ best_spanno = subxpd->span.spanno;
+ }
+ }
+ for(i = 0; i < MAX_SLAVES; i++) {
+ subxpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, i);
+ if(!subxpd)
+ continue;
+ if(subxpd->span.syncsrc == best_spanno)
+ XPD_DBG(SYNC, xpd, "Setting SyncSource to span %d\n", best_spanno);
+ else
+ XPD_DBG(SYNC, xpd, "Slaving to span %d\n", best_spanno);
+ subxpd->span.syncsrc = best_spanno;
+ }
+}
+
+/*
+ * Called from:
+ * - set_master_mode() --
+ * As a result of ztcfg or writing to /proc/xpp/XBUS-??/XPD-/??/pri_info
+ * - layer1_state() --
+ * As a result of an alarm.
+ */
+static void set_clocking(xpd_t *xpd)
+{
+ xbus_t *xbus;
+ xpd_t *best_xpd = NULL;
+ int best_subunit = -1; /* invalid */
+ int best_subunit_prio = 0;
+ int i;
+
+ xbus = get_xbus(xpd->xbus->num);
+ /* Find subunit with best timing priority */
+ for(i = 0; i < MAX_SLAVES; i++) {
+ struct PRI_priv_data *priv;
+ xpd_t *subxpd;
+
+ subxpd = xpd_byaddr(xbus, xpd->addr.unit, i);
+ if(!subxpd)
+ continue;
+ priv = subxpd->priv;
+ if(priv->alarms != 0)
+ continue;
+ if(subxpd->timing_priority > best_subunit_prio) {
+ best_xpd = subxpd;
+ best_subunit = i;
+ best_subunit_prio = subxpd->timing_priority;
+ }
+ }
+ /* Now set it */
+ if(best_xpd && ((struct PRI_priv_data *)(best_xpd->priv))->clock_source == 0) {
+ byte cmr1_val =
+ REG_CMR1_RS |
+ REG_CMR1_STF |
+ (REG_CMR1_DRSS & (best_subunit << 6));
+ XPD_DBG(SYNC, best_xpd,
+ "ClockSource Set: cmr1=0x%02X\n", cmr1_val);
+ pri_write_reg(xpd, REG_CMR1, cmr1_val);
+ ((struct PRI_priv_data *)(best_xpd->priv))->clock_source = 1;
+ }
+ /* clear old clock sources */
+ for(i = 0; i < MAX_SLAVES; i++) {
+ struct PRI_priv_data *priv;
+ xpd_t *subxpd;
+
+ subxpd = xpd_byaddr(xbus, xpd->addr.unit, i);
+ if(subxpd && subxpd != best_xpd) {
+ XPD_DBG(SYNC, subxpd, "Clearing clock source\n");
+ priv = subxpd->priv;
+ priv->clock_source = 0;
+ }
+ }
+ zap_update_syncsrc(xpd);
+ put_xbus(xbus);
+}
+
+/*
+ * Normally set by the timing parameter in zaptel.conf
+ * If this is called by ztcfg, than it's too late to change
+ * zaptel sync priority (we are already registered)
+ * There are two workarounds to mitigate this problem:
+ * 1. So we set *our* sync master at least.
+ * 2. And we try to call it with a sane default from set_nt()
+ * which is called before zaptel registration.
+ */
+static int set_master_mode(const char *msg, xpd_t *xpd)
+{
+ struct PRI_priv_data *priv;
+ byte lim0 = 0;
+ byte xsp = 0;
+ bool is_master_mode = xpd->timing_priority == 0;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ lim0 |= (priv->local_loopback) ? REG_LIM0_LL : 0;
+ if(is_master_mode)
+ lim0 |= REG_LIM0_MAS;
+ else
+ lim0 &= ~REG_LIM0_MAS;
+ if(priv->pri_protocol == PRI_PROTO_E1)
+ {
+ lim0 &= ~REG_LIM0_RTRS; /* Receive termination: Integrated resistor is switched off (100 Ohm, no internal 300 Ohm) */;
+ xsp |= REG_XSP_E_EBP | REG_XSP_E_AXS | REG_XSP_E_XSIF;
+ } else if(priv->pri_protocol == PRI_PROTO_T1) {
+ lim0 |= REG_LIM0_RTRS; /* Receive termination: Integrated resistor is switched on (100 Ohm || 300 Ohm = 75 Ohm) */
+ xsp |= REG_FMR5_T_XTM;
+ }
+ XPD_DBG(SIGNAL, xpd, "%s(%s): %s\n", __FUNCTION__, msg, (is_master_mode) ? "MASTER" : "SLAVE");
+ write_subunit(xpd, REG_LIM0 , lim0);
+ write_subunit(xpd, REG_XSP_E, xsp);
+ set_clocking(xpd);
+ return 0;
+}
+
+static int set_nt(const char *msg, xpd_t *xpd, bool is_nt)
+{
+ struct PRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ if(SPAN_REGISTERED(xpd)) {
+ XPD_NOTICE(xpd, "Registered as span %d. Cannot do %s(%s)\n",
+ xpd->span.spanno, __FUNCTION__, msg);
+ return -EBUSY;
+ }
+ priv->is_nt = is_nt;
+ xpd->type_name = type_name(priv->pri_protocol, is_nt);
+ xpd->direction = (is_nt) ? TO_PHONE : TO_PSTN;
+ XPD_DBG(SIGNAL, xpd, "%s(%s): %s %s\n", __FUNCTION__, msg, xpd->type_name, (is_nt) ? "NT" : "TE");
+ if(xpd->timing_priority == 0 && !is_nt) /* by default set timing priority from NT/TE */
+ xpd->timing_priority = 1;
+ set_master_mode(msg, xpd);
+ return 0;
+}
+
+static int set_localloop(const char *msg, xpd_t *xpd, bool localloop)
+{
+ struct PRI_priv_data *priv;
+ byte lim0 = 0;
+ byte xsp = 0;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ if(SPAN_REGISTERED(xpd)) {
+ XPD_NOTICE(xpd, "Registered as span %d. Cannot do %s(%s)\n",
+ xpd->span.spanno, __FUNCTION__, msg);
+ return -EBUSY;
+ }
+ lim0 |= (localloop) ? REG_LIM0_LL : 0;
+ if(priv->is_nt)
+ lim0 |= REG_LIM0_MAS;
+ else
+ lim0 &= ~REG_LIM0_MAS;
+ if(priv->pri_protocol == PRI_PROTO_E1)
+ {
+ lim0 |= REG_LIM0_RTRS; /* Receive termination: Integrated resistor is switched on (100 Ohm || 300 Ohm = 75 Ohm) */
+ xsp |= REG_XSP_E_EBP | REG_XSP_E_AXS | REG_XSP_E_XSIF;
+ } else if(priv->pri_protocol == PRI_PROTO_T1) {
+ lim0 &= ~REG_LIM0_RTRS ; /* Receive termination: Integrated resistor is switched off (100 Ohm, no internal 300 Ohm) */;
+ xsp |= REG_FMR5_T_XTM;
+ }
+ priv->local_loopback = localloop;
+ XPD_DBG(SIGNAL, xpd, "%s(%s): %s\n", __FUNCTION__, msg, (localloop) ? "LOCALLOOP" : "NO");
+ write_subunit(xpd, REG_LIM0 , lim0);
+ write_subunit(xpd, REG_XSP_E, xsp);
+ return 0;
+}
+
+#define VALID_CONFIG(bit,flg,str) [bit] = { .flags = flg, .name = str }
+
+static const struct {
+ const char *name;
+ const int flags;
+} valid_spanconfigs[sizeof(unsigned int)*8] = {
+ /* These apply to T1 */
+// VALID_CONFIG(4, ZT_CONFIG_D4, "D4"), FIXME: should support
+ VALID_CONFIG(5, ZT_CONFIG_ESF, "ESF"),
+ VALID_CONFIG(6, ZT_CONFIG_AMI, "AMI"),
+ VALID_CONFIG(7, ZT_CONFIG_B8ZS, "B8ZS"),
+ /* These apply to E1 */
+ VALID_CONFIG(8, ZT_CONFIG_CCS, "CCS"),
+ VALID_CONFIG(9, ZT_CONFIG_HDB3, "HDB3"),
+ VALID_CONFIG(10, ZT_CONFIG_CRC4, "CRC4"),
+};
+
+static int pri_lineconfig(xpd_t *xpd, int lineconfig)
+{
+ struct PRI_priv_data *priv;
+ const char *framingstr = "";
+ const char *codingstr = "";
+ const char *crcstr = "";
+ byte fmr0 = 0; /* Dummy initilizations to */
+ byte fmr2 = 0; /* silense false gcc warnings */
+ byte fmr4 = 0; /* Dummy initilizations to */
+ unsigned int bad_bits;
+ int i;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ /*
+ * validate
+ */
+ bad_bits = lineconfig & pri_linecompat(priv->pri_protocol);
+ bad_bits = bad_bits ^ lineconfig;
+ for(i = 0; i < ARRAY_SIZE(valid_spanconfigs); i++) {
+ unsigned int flags = valid_spanconfigs[i].flags;
+
+ if(bad_bits & BIT(i)) {
+ if(flags) {
+ XPD_ERR(xpd,
+ "Bad config item '%s' for %s. Ignore\n",
+ valid_spanconfigs[i].name,
+ pri_protocol_name(priv->pri_protocol));
+ } else {
+ /* we got real garbage */
+ XPD_ERR(xpd,
+ "Unknown config item 0x%lX for %s. Ignore\n",
+ BIT(i),
+ pri_protocol_name(priv->pri_protocol));
+ }
+ }
+ if(flags && flags != BIT(i)) {
+ ERR("%s: BUG: i=%d flags=0x%X\n",
+ __FUNCTION__, i, flags);
+ // BUG();
+ }
+ }
+ if(bad_bits)
+ goto bad_lineconfig;
+ if(priv->pri_protocol == PRI_PROTO_E1) {
+ fmr2 = REG_FMR2_E_AXRA | REG_FMR2_E_ALMF; /* 0x03 */
+ fmr4 = 0x9F; /* E1.XSW: All spare bits = 1*/
+ } else if(priv->pri_protocol == PRI_PROTO_T1) {
+ fmr2 = REG_FMR2_T_SSP | REG_FMR2_T_AXRA; /* 0x22 */
+ fmr4 = 0x0C;
+ } else if(priv->pri_protocol == PRI_PROTO_J1) {
+ fmr4 = 0x1C;
+ XPD_ERR(xpd, "J1 unsupported yet\n");
+ return -ENOSYS;
+ }
+ if(priv->local_loopback)
+ fmr2 |= REG_FMR2_E_PLB;
+ /* framing first */
+ if (lineconfig & ZT_CONFIG_B8ZS) {
+ framingstr = "B8ZS";
+ fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_XC0 | REG_FMR0_E_RC1 | REG_FMR0_E_RC0;
+ } else if (lineconfig & ZT_CONFIG_AMI) {
+ framingstr = "AMI";
+ fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_RC1;
+ } else if (lineconfig & ZT_CONFIG_HDB3) {
+ framingstr = "HDB3";
+ fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_XC0 | REG_FMR0_E_RC1 | REG_FMR0_E_RC0;
+ }
+ /* then coding */
+ if (lineconfig & ZT_CONFIG_ESF) {
+ codingstr = "ESF";
+ fmr4 |= REG_FMR4_FM1;
+ fmr2 |= REG_FMR2_T_AXRA | REG_FMR2_T_MCSP | REG_FMR2_T_SSP;
+ } else if (lineconfig & ZT_CONFIG_D4) {
+ codingstr = "D4";
+ } else if (lineconfig & ZT_CONFIG_CCS) {
+ codingstr = "CCS";
+ /* do nothing */
+ }
+ /* E1's can enable CRC checking */
+ if (lineconfig & ZT_CONFIG_CRC4) {
+ crcstr = "CRC4";
+ fmr2 |= REG_FMR2_E_RFS1;
+ }
+ XPD_DBG(GENERAL, xpd, "[%s] lineconfig=%s/%s/%s %s (0x%X)\n",
+ (priv->is_nt)?"NT":"TE",
+ framingstr, codingstr, crcstr,
+ (lineconfig & ZT_CONFIG_NOTOPEN)?"YELLOW":"",
+ lineconfig);
+ if(fmr0 != 0) {
+ XPD_DBG(GENERAL, xpd, "%s: fmr0(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR0, fmr0);
+ write_subunit(xpd, REG_FMR0, fmr0);
+ }
+ XPD_DBG(GENERAL, xpd, "%s: fmr4(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR4, fmr4);
+ write_subunit(xpd, REG_FMR4, fmr4);
+ XPD_DBG(GENERAL, xpd, "%s: fmr2(0x%02X) = 0x%02X\n", __FUNCTION__, REG_FMR2, fmr2);
+ write_subunit(xpd, REG_FMR2, fmr2);
+ return 0;
+bad_lineconfig:
+ XPD_ERR(xpd, "Bad lineconfig. Abort\n");
+ return -EINVAL;
+}
+
+/*
+ * Called only for 'span' keyword in /etc/zaptel.conf
+ */
+
+static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+ xpd_t *xpd = span->pvt;
+ struct PRI_priv_data *priv;
+ int ret;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ if(lc->span != xpd->span.spanno) {
+ XPD_ERR(xpd, "I am span %d but got spanconfig for span %d\n",
+ xpd->span.spanno, lc->span);
+ return -EINVAL;
+ }
+ /*
+ * FIXME: lc->name is unused by ztcfg and zaptel...
+ * We currently ignore it also.
+ */
+ XPD_DBG(GENERAL, xpd, "[%s] lbo=%d lineconfig=0x%X sync=%d\n",
+ (priv->is_nt)?"NT":"TE", lc->lbo, lc->lineconfig, lc->sync);
+ ret = pri_lineconfig(xpd, lc->lineconfig);
+ if(!ret) {
+ span->lineconfig = lc->lineconfig;
+ xpd->timing_priority = lc->sync;
+ set_master_mode("spanconfig", xpd);
+ elect_syncer("PRI-master_mode");
+ }
+ return ret;
+}
+
+/*
+ * Set signalling type (if appropriate)
+ * Called from zaptel with spinlock held on chan. Must not call back
+ * zaptel functions.
+ */
+static int pri_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ DBG(GENERAL, "channel %d (%s) -> %s\n", chan->channo, chan->name, sig2str(sigtype));
+ // FIXME: sanity checks:
+ // - should be supported (within the sigcap)
+ // - should not replace fxs <->fxo ??? (covered by previous?)
+ return 0;
+}
+
+static xpd_t *PRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, bool to_phone)
+{
+ xpd_t *xpd = NULL;
+ struct PRI_priv_data *priv;
+ int channels = min(31, CHANNELS_PERXPD); /* worst case */
+ int ret = 0;
+
+ XBUS_DBG(GENERAL, xbus, "\n");
+ xpd = xpd_alloc(sizeof(struct PRI_priv_data), proto_table, channels);
+ if(!xpd)
+ return NULL;
+ priv = xpd->priv;
+ priv->pri_protocol = PRI_PROTO_0; /* Default, changes in set_pri_proto() */
+ priv->deflaw = ZT_LAW_DEFAULT; /* Default, changes in set_pri_proto() */
+ xpd->type_name =
+ type_name(priv->pri_protocol, 0); /* Default, changes in set_nt() */
+ if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0)
+ goto err;
+ if(pri_proc_create(xbus, xpd) < 0)
+ goto err;
+ /* Assume E1, changes later from user space */
+ ret = set_pri_proto(xpd, PRI_PROTO_E1);
+ if(ret < 0)
+ goto err;
+ return xpd;
+err:
+ xpd_free(xpd);
+ return NULL;
+}
+
+static int PRI_card_init(xbus_t *xbus, xpd_t *xpd)
+{
+ struct PRI_priv_data *priv;
+ int ret = 0;
+ xproto_table_t *proto_table;
+
+ BUG_ON(!xpd);
+ XPD_DBG(GENERAL, xpd, "\n");
+ xpd->type = XPD_TYPE_PRI;
+ proto_table = &PROTO_TABLE(PRI);
+ priv = xpd->priv;
+ /*
+ * initialization script should have set correct
+ * operating modes.
+ */
+ if(!valid_pri_modes(xpd)) {
+ XPD_NOTICE(xpd, "PRI protocol not set\n");
+ goto err;
+ }
+ for(ret = 0; ret < NUM_LEDS; ret++) {
+ DO_LED(xpd, ret, PRI_LED_ON);
+ msleep(20);
+ DO_LED(xpd, ret, PRI_LED_OFF);
+ }
+ priv->initialized = 1;
+ return 0;
+err:
+ pri_proc_remove(xbus, xpd);
+ XPD_ERR(xpd, "Failed initializing registers (%d)\n", ret);
+ return ret;
+}
+
+static int PRI_card_remove(xbus_t *xbus, xpd_t *xpd)
+{
+ struct PRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ XPD_DBG(GENERAL, xpd, "\n");
+ pri_proc_remove(xbus, xpd);
+ return 0;
+}
+
+static int PRI_card_zaptel_preregistration(xpd_t *xpd, bool on)
+{
+ xbus_t *xbus;
+ struct PRI_priv_data *priv;
+ int i;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ BUG_ON(!xbus);
+ XPD_DBG(GENERAL, xpd, "%s (proto=%s, channels=%d, deflaw=%d)\n",
+ (on)?"on":"off",
+ pri_protocol_name(priv->pri_protocol),
+ xpd->channels,
+ priv->deflaw);
+ if(!on) {
+ /* Nothing to do yet */
+ return 0;
+ }
+#ifdef ZT_SPANSTAT_V2
+ xpd->span.spantype = pri_protocol_name(priv->pri_protocol);
+#endif
+ xpd->span.linecompat = pri_linecompat(priv->pri_protocol);
+ xpd->span.deflaw = priv->deflaw;
+ for_each_line(xpd, i) {
+ struct zt_chan *cur_chan = &xpd->chans[i];
+ bool is_dchan = i == PRI_DCHAN_IDX(priv);
+
+ XPD_DBG(GENERAL, xpd, "setting PRI channel %d (%s)\n", i,
+ (is_dchan)?"DCHAN":"CLEAR");
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%02d/%1d%1d/%d",
+ xpd->type_name, xbus->num, xpd->addr.unit, xpd->addr.subunit, i);
+ cur_chan->chanpos = i + 1;
+ cur_chan->pvt = xpd;
+ if(is_dchan) { /* D-CHAN */
+ cur_chan->sigcap = PRI_DCHAN_SIGCAP;
+ //FIXME: cur_chan->flags |= ZT_FLAG_PRIDCHAN;
+ cur_chan->flags &= ~ZT_FLAG_HDLC;
+ } else
+ cur_chan->sigcap = PRI_BCHAN_SIGCAP;
+ }
+ xpd->offhook = xpd->wanted_pcm_mask;
+ xpd->span.spanconfig = pri_spanconfig;
+ xpd->span.chanconfig = pri_chanconfig;
+ xpd->span.startup = pri_startup;
+ xpd->span.shutdown = pri_shutdown;
+ return 0;
+}
+
+static int PRI_card_zaptel_postregistration(xpd_t *xpd, bool on)
+{
+ xbus_t *xbus;
+ struct PRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ BUG_ON(!xbus);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
+ zap_update_syncsrc(xpd);
+ return(0);
+}
+
+static int PRI_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
+{
+ LINE_DBG(SIGNAL, xpd, pos, "%s\n", txsig2str(txsig));
+ return 0;
+}
+
+static void dchan_state(xpd_t *xpd, bool up)
+{
+ struct PRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(priv->dchan_alive == up)
+ return;
+ if(!priv->layer1_up) /* No layer1, kill dchan */
+ up = 0;
+ if(up) {
+ XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel RUNNING\n");
+ priv->dchan_alive = 1;
+ } else {
+ int d = PRI_DCHAN_IDX(priv);
+
+ if(SPAN_REGISTERED(xpd) && d >= 0 && d < xpd->channels) {
+ byte *pcm;
+
+ pcm = (byte *)xpd->span.chans[d].readchunk;
+ pcm[0] = 0x00;
+ pcm = (byte *)xpd->span.chans[d].writechunk;
+ pcm[0] = 0x00;
+ }
+ XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n");
+ priv->dchan_rx_counter = priv->dchan_tx_counter = 0;
+ priv->dchan_alive = 0;
+ priv->dchan_alive_ticks = 0;
+ priv->dchan_rx_sample = priv->dchan_tx_sample = 0x00;
+ }
+}
+
+/*
+ * LED managment is done by the driver now:
+ * - Turn constant ON RED/GREEN led to indicate NT/TE port
+ * - Very fast "Double Blink" to indicate Layer1 alive (without D-Channel)
+ * - Constant blink (1/2 sec cycle) to indicate D-Channel alive.
+ */
+static void handle_leds(xbus_t *xbus, xpd_t *xpd)
+{
+ struct PRI_priv_data *priv;
+ unsigned int timer_count;
+ int which_led;
+ int other_led;
+ enum pri_led_state ledstate;
+ int mod;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(priv->is_nt) {
+ which_led = NT_RED_LED;
+ other_led = TE_GREEN_LED;
+ } else {
+ which_led = TE_GREEN_LED;
+ other_led = NT_RED_LED;
+ }
+ ledstate = priv->ledstate[which_led];
+ timer_count = xpd->timer_count;
+ if(xpd->blink_mode) {
+ if((timer_count % DEFAULT_LED_PERIOD) == 0) {
+ // led state is toggled
+ if(ledstate == PRI_LED_OFF) {
+ DO_LED(xpd, which_led, PRI_LED_ON);
+ DO_LED(xpd, other_led, PRI_LED_ON);
+ } else {
+ DO_LED(xpd, which_led, PRI_LED_OFF);
+ DO_LED(xpd, other_led, PRI_LED_OFF);
+ }
+ }
+ return;
+ }
+ if(priv->ledstate[other_led] != PRI_LED_OFF)
+ DO_LED(xpd, other_led, PRI_LED_OFF);
+ if(priv->dchan_alive) {
+ mod = timer_count % 1000;
+ switch(mod) {
+ case 0:
+ DO_LED(xpd, which_led, PRI_LED_ON);
+ break;
+ case 500:
+ DO_LED(xpd, which_led, PRI_LED_OFF);
+ break;
+ }
+ } else if(priv->layer1_up) {
+ mod = timer_count % 1000;
+ switch(mod) {
+ case 0:
+ case 100:
+ DO_LED(xpd, which_led, PRI_LED_ON);
+ break;
+ case 50:
+ case 150:
+ DO_LED(xpd, which_led, PRI_LED_OFF);
+ break;
+ }
+ } else {
+ if(priv->ledstate[which_led] != PRI_LED_ON)
+ DO_LED(xpd, which_led, PRI_LED_ON);
+ }
+}
+
+static int PRI_card_tick(xbus_t *xbus, xpd_t *xpd)
+{
+ struct PRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(!priv->initialized || !xbus->self_ticking)
+ return 0;
+ /*
+ * Poll layer1 status (cascade subunits)
+ */
+ if(poll_interval != 0 &&
+ ((xpd->timer_count % poll_interval) == 0)) {
+ priv->poll_noreplies++;
+ query_subunit(xpd, REG_FRS0);
+ //query_subunit(xpd, REG_FRS1);
+ }
+ if(priv->dchan_tx_counter >= 1 && priv->dchan_rx_counter > 1) {
+ dchan_state(xpd, 1);
+ priv->dchan_alive_ticks++;
+ }
+ handle_leds(xbus, xpd);
+ return 0;
+}
+
+static int PRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
+{
+ BUG_ON(!xpd);
+ if(!TRANSPORT_RUNNING(xpd->xbus))
+ return -ENODEV;
+ switch (cmd) {
+ case ZT_TONEDETECT:
+ /*
+ * Asterisk call all span types with this (FXS specific)
+ * call. Silently ignore it.
+ */
+ LINE_DBG(SIGNAL, xpd, pos, "PRI: Starting a call\n");
+ return -ENOTTY;
+ default:
+ report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd);
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int PRI_card_close(xpd_t *xpd, lineno_t pos)
+{
+ //struct zt_chan *chan = &xpd->span.chans[pos];
+ dchan_state(xpd, 0);
+ return 0;
+}
+
+/*
+ * Called only for 'span' keyword in /etc/zaptel.conf
+ */
+static int pri_startup(struct zt_span *span)
+{
+ xpd_t *xpd = span->pvt;
+ struct PRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(!TRANSPORT_RUNNING(xpd->xbus)) {
+ XPD_DBG(GENERAL, xpd, "Startup called by zaptel. No Hardware. Ignored\n");
+ return -ENODEV;
+ }
+ XPD_DBG(GENERAL, xpd, "STARTUP\n");
+ // Turn on all channels
+ CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1);
+ return 0;
+}
+
+/*
+ * Called only for 'span' keyword in /etc/zaptel.conf
+ */
+static int pri_shutdown(struct zt_span *span)
+{
+ xpd_t *xpd = span->pvt;
+ struct PRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(!TRANSPORT_RUNNING(xpd->xbus)) {
+ XPD_DBG(GENERAL, xpd, "Shutdown called by zaptel. No Hardware. Ignored\n");
+ return -ENODEV;
+ }
+ XPD_DBG(GENERAL, xpd, "SHUTDOWN\n");
+ // Turn off all channels
+ CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 0);
+ return 0;
+}
+
+/*! Copy PCM chunks from the buffers of the xpd to a new packet
+ * \param xbus xbus of source xpd.
+ * \param xpd source xpd.
+ * \param lines a bitmask of the active channels that need to be copied.
+ * \param pack packet to be filled.
+ *
+ * On PRI this function is should also shift the lines mask one bit, as
+ * channel 0 on the wire is an internal chip control channel. We only
+ * send 31 channels to the device, but they should be called 1-31 rather
+ * than 0-30 .
+ */
+static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack)
+{
+ struct PRI_priv_data *priv;
+ byte *pcm;
+ struct zt_chan *chans;
+ unsigned long flags;
+ int i;
+ int physical_chan;
+ int physical_mask = 0;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ BUG_ON(!pack);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
+ spin_lock_irqsave(&xpd->lock, flags);
+ chans = xpd->span.chans;
+ physical_chan = 0;
+ for_each_line(xpd, i) {
+ if(priv->pri_protocol == PRI_PROTO_E1) {
+ /* In E1 - Only 0'th channel is unused */
+ if(i == 0) {
+ physical_chan++;
+ }
+ } else if(priv->pri_protocol == PRI_PROTO_T1) {
+ /* In T1 - Every 4'th channel is unused */
+ if((i % 3) == 0) {
+ physical_chan++;
+ }
+ }
+ if(IS_SET(lines, i)) {
+ physical_mask |= BIT(physical_chan);
+ if(SPAN_REGISTERED(xpd)) {
+ if(i == PRI_DCHAN_IDX(priv)) {
+ if(priv->dchan_tx_sample != chans[i].writechunk[0]) {
+ priv->dchan_tx_sample = chans[i].writechunk[0];
+ priv->dchan_tx_counter++;
+ } else if(chans[i].writechunk[0] == 0xFF)
+ dchan_state(xpd, 0);
+ }
+#ifdef DEBUG_PCMTX
+ if(pcmtx >= 0 && pcmtx_chan == i)
+ memset((u_char *)pcm, pcmtx, ZT_CHUNKSIZE);
+ else
+#endif
+ memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE);
+ // fill_beep((u_char *)pcm, xpd->addr.subunit, 2);
+ } else
+ memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE);
+ pcm += ZT_CHUNKSIZE;
+ }
+ physical_chan++;
+ }
+ RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = physical_mask;
+ XPD_COUNTER(xpd, PCM_WRITE)++;
+ spin_unlock_irqrestore(&xpd->lock, flags);
+}
+
+/*! Copy PCM chunks from the packet we recieved to the xpd struct.
+ * \param xbus xbus of target xpd.
+ * \param xpd target xpd.
+ * \param pack Source packet.
+ *
+ * On PRI this function is should also shift the lines back mask one bit, as
+ * channel 0 on the wire is an internal chip control channel.
+ *
+ * \see PRI_card_pcm_fromspan
+ */
+static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
+{
+ struct PRI_priv_data *priv;
+ byte *pcm;
+ struct zt_chan *chans;
+ xpp_line_t physical_mask;
+ unsigned long flags;
+ int i;
+ int logical_chan;
+
+ if(!SPAN_REGISTERED(xpd))
+ return;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm);
+ physical_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines);
+ spin_lock_irqsave(&xpd->lock, flags);
+ chans = xpd->span.chans;
+ logical_chan = 0;
+ for (i = 0; i < CHANNELS_PERXPD; i++) {
+ volatile u_char *r;
+
+ if(priv->pri_protocol == PRI_PROTO_E1) {
+ /* In E1 - Only 0'th channel is unused */
+ if(i == 0)
+ continue;
+ } else if(priv->pri_protocol == PRI_PROTO_T1) {
+ /* In T1 - Every 4'th channel is unused */
+ if((i % 4) == 0)
+ continue;
+ }
+ if(logical_chan == PRI_DCHAN_IDX(priv)) {
+ if(priv->dchan_rx_sample != pcm[0]) {
+ if(debug & DBG_PCM) {
+ XPD_INFO(xpd, "RX-D-Chan: prev=0x%X now=0x%X\n",
+ priv->dchan_rx_sample, pcm[0]);
+ dump_packet("RX-D-Chan", pack, 1);
+ }
+ priv->dchan_rx_sample = pcm[0];
+ priv->dchan_rx_counter++;
+ } else if(pcm[0] == 0xFF)
+ dchan_state(xpd, 0);
+ }
+ if(IS_SET(physical_mask, i)) {
+ r = chans[logical_chan].readchunk;
+ // memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG
+ // fill_beep((u_char *)r, 1, 1); // DEBUG: BEEP
+ memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
+ pcm += ZT_CHUNKSIZE;
+ }
+ logical_chan++;
+ }
+ XPD_COUNTER(xpd, PCM_READ)++;
+ spin_unlock_irqrestore(&xpd->lock, flags);
+}
+
+/*---------------- PRI: HOST COMMANDS -------------------------------------*/
+
+static /* 0x0F */ HOSTCMD(PRI, XPD_STATE, bool on)
+{
+ BUG_ON(!xpd);
+ XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
+ return 0;
+}
+
+static /* 0x33 */ HOSTCMD(PRI, SET_LED, enum pri_led_selectors led_sel, enum pri_led_state to_led_state)
+{
+ int ret = 0;
+ xframe_t *xframe;
+ xpacket_t *pack;
+ struct pri_leds *pri_leds;
+ struct PRI_priv_data *priv;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ XPD_DBG(LEDS, xpd, "led_sel=%d to_state=%d\n", led_sel, to_led_state);
+ XFRAME_NEW_CMD(xframe, pack, xbus, PRI, SET_LED, xpd->xbus_idx);
+ pri_leds = &RPACKET_FIELD(pack, PRI, SET_LED, pri_leds);
+ pri_leds->state = to_led_state;
+ pri_leds->led_sel = led_sel;
+ pri_leds->reserved = 0;
+ XPACKET_LEN(pack) = RPACKET_SIZE(PRI, SET_LED);
+ ret = send_cmd_frame(xbus, xframe);
+ priv->ledstate[led_sel] = to_led_state;
+ return ret;
+}
+
+/*---------------- PRI: Astribank Reply Handlers --------------------------*/
+static void layer1_state(xpd_t *xpd, byte data_low)
+{
+ struct PRI_priv_data *priv;
+ int alarms = 0;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ priv->poll_noreplies = 0;
+ if(data_low & REG_FRS0_LOS)
+ alarms |= ZT_ALARM_RED;
+ if(data_low & REG_FRS0_AIS)
+ alarms |= ZT_ALARM_BLUE;
+ if(data_low & REG_FRS0_RRA)
+ alarms |= ZT_ALARM_YELLOW;
+ priv->layer1_up = alarms == 0;
+#if 0
+ /*
+ * Some bad bits (e.g: LMFA and NMF have no alarm "colors"
+ * associated. However, layer1 is still not working if they are set.
+ * FIXME: These behave differently in E1/T1, so ignore them for while.
+ */
+ if(data_low & (REG_FRS0_LMFA | REG_FRS0_E1_NMF))
+ priv->layer1_up = 0;
+#endif
+ priv->alarms = alarms;
+ if(!priv->layer1_up)
+ dchan_state(xpd, 0);
+ if(SPAN_REGISTERED(xpd) && xpd->span.alarms != alarms) {
+ char str1[MAX_PROC_WRITE];
+ char str2[MAX_PROC_WRITE];
+
+ alarm2str(xpd->span.alarms, str1, sizeof(str1));
+ alarm2str(alarms, str2, sizeof(str2));
+ XPD_NOTICE(xpd, "Alarms: 0x%X (%s) => 0x%X (%s)\n",
+ xpd->span.alarms, str1,
+ alarms, str2);
+ xpd->span.alarms = alarms;
+ zt_alarm_notify(&xpd->span);
+ set_clocking(xpd);
+ }
+ priv->reg_frs0 = data_low;
+ priv->layer1_replies++;
+ XPD_DBG(REGS, xpd, "subunit=%d data_low=0x%02X\n", xpd->addr.subunit, data_low);
+}
+
+static int PRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
+{
+ unsigned long flags;
+ struct PRI_priv_data *priv;
+ struct xpd_addr addr;
+ xpd_t *orig_xpd;
+
+ /* Map UNIT + PORTNUM to XPD */
+ orig_xpd = xpd;
+ addr.unit = orig_xpd->addr.unit;
+ addr.subunit = info->portnum;
+ xpd = xpd_byaddr(xbus, addr.unit, addr.subunit);
+ if(!xpd) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) < 5)
+ notify_bad_xpd(__FUNCTION__, xbus, addr , orig_xpd->xpdname);
+ return -EPROTO;
+ }
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(info->is_multibyte) {
+ XPD_NOTICE(xpd, "Got Multibyte: %d bytes, eoframe: %d\n",
+ info->bytes, info->eoframe);
+ goto end;
+ }
+ if(REG_FIELD(info, regnum) == REG_FRS0 && !REG_FIELD(info, do_subreg))
+ layer1_state(xpd, REG_FIELD(info, data_low));
+ if(REG_FIELD(info, regnum) == REG_FRS1 && !REG_FIELD(info, do_subreg))
+ priv->reg_frs1 = REG_FIELD(info, data_low);
+ /* Update /proc info only if reply relate to the last slic read request */
+ if(
+ REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) &&
+ REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) &&
+ REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) {
+ xpd->last_reply = *info;
+ }
+
+end:
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return 0;
+}
+
+static xproto_table_t PROTO_TABLE(PRI) = {
+ .owner = THIS_MODULE,
+ .entries = {
+ /* Table Card Opcode */
+ },
+ .name = "PRI", /* protocol name */
+ .ports_per_subunit = 1,
+ .type = XPD_TYPE_PRI,
+ .xops = {
+ .card_new = PRI_card_new,
+ .card_init = PRI_card_init,
+ .card_remove = PRI_card_remove,
+ .card_zaptel_preregistration = PRI_card_zaptel_preregistration,
+ .card_zaptel_postregistration = PRI_card_zaptel_postregistration,
+ .card_hooksig = PRI_card_hooksig,
+ .card_tick = PRI_card_tick,
+ .card_pcm_fromspan = PRI_card_pcm_fromspan,
+ .card_pcm_tospan = PRI_card_pcm_tospan,
+ .card_ioctl = PRI_card_ioctl,
+ .card_close = PRI_card_close,
+ .card_register_reply = PRI_card_register_reply,
+
+ .XPD_STATE = XPROTO_CALLER(PRI, XPD_STATE),
+ },
+ .packet_is_valid = pri_packet_is_valid,
+ .packet_dump = pri_packet_dump,
+};
+
+static bool pri_packet_is_valid(xpacket_t *pack)
+{
+ const xproto_entry_t *xe_nt = NULL;
+ const xproto_entry_t *xe_te = NULL;
+ // DBG(GENERAL, "\n");
+ xe_nt = xproto_card_entry(&PROTO_TABLE(PRI), XPACKET_OP(pack));
+ return xe_nt != NULL || xe_te != NULL;
+}
+
+static void pri_packet_dump(const char *msg, xpacket_t *pack)
+{
+ DBG(GENERAL, "%s\n", msg);
+}
+/*------------------------- REGISTER Handling --------------------------*/
+static int proc_pri_info_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ xpd_t *xpd = data;
+ struct PRI_priv_data *priv;
+ char buf[MAX_PROC_WRITE];
+ char *p;
+ char *tok;
+ static const char *msg = "PROC"; /* for logs */
+ int ret = 0;
+ bool got_localloop = 0;
+ bool got_nolocalloop = 0;
+ bool got_te = 0;
+ bool got_nt = 0;
+ bool got_e1 = 0;
+ bool got_t1 = 0;
+ bool got_j1 = 0;
+
+ if(!xpd)
+ return -ENODEV;
+ priv = xpd->priv;
+ if(count >= MAX_PROC_WRITE) { /* leave room for null */
+ XPD_ERR(xpd, "write too long (%ld)\n", count);
+ return -E2BIG;
+ }
+ if(copy_from_user(buf, buffer, count)) {
+ XPD_ERR(xpd, "Failed reading user data\n");
+ return -EFAULT;
+ }
+ buf[count] = '\0';
+ XPD_DBG(PROC, xpd, "PRI-SETUP: got %s\n", buf);
+ /*
+ * First parse. Act only of *everything* is good.
+ */
+ p = buf;
+ while((tok = strsep(&p, " \t\v\n")) != NULL) {
+ if(*tok == '\0')
+ continue;
+ XPD_DBG(PROC, xpd, "Got token='%s'\n", tok);
+ if(strnicmp(tok, "LOCALLOOP", 8) == 0)
+ got_localloop = 1;
+ else if(strnicmp(tok, "NOLOCALLOOP", 8) == 0)
+ got_nolocalloop = 1;
+ else if(strnicmp(tok, "NT", 2) == 0)
+ got_nt = 1;
+ else if(strnicmp(tok, "TE", 2) == 0)
+ got_te = 1;
+ else if(strnicmp(tok, "E1", 2) == 0)
+ got_e1 = 1;
+ else if(strnicmp(tok, "T1", 2) == 0)
+ got_t1 = 1;
+ else if(strnicmp(tok, "J1", 2) == 0) {
+ got_j1 = 1;
+ } else {
+ XPD_NOTICE(xpd, "PRI-SETUP: unknown keyword: '%s'\n", tok);
+ return -EINVAL;
+ }
+ }
+ if(got_e1)
+ ret = set_pri_proto(xpd, PRI_PROTO_E1);
+ else if(got_t1)
+ ret = set_pri_proto(xpd, PRI_PROTO_T1);
+ else if(got_j1)
+ ret = set_pri_proto(xpd, PRI_PROTO_J1);
+ if(priv->pri_protocol == PRI_PROTO_0) {
+ XPD_ERR(xpd,
+ "Must set PRI protocol (E1/T1/J1) before setting other parameters\n");
+ return -EINVAL;
+ }
+ if(got_localloop)
+ ret = set_localloop(msg, xpd, 1);
+ if(got_nolocalloop)
+ ret = set_localloop(msg, xpd, 0);
+ if(got_nt)
+ ret = set_nt(msg, xpd, 1);
+ if(got_te)
+ ret = set_nt(msg, xpd, 0);
+ return (ret) ? ret : count;
+}
+
+
+static int proc_pri_info_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xpd_t *xpd = data;
+ struct PRI_priv_data *priv;
+ int i;
+
+ DBG(PROC, "\n");
+ if(!xpd)
+ return -ENODEV;
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ len += sprintf(page + len, "PRI: %s %s%s (deflaw=%d, dchan=%d)\n",
+ (priv->is_nt) ? "NT" : "TE",
+ pri_protocol_name(priv->pri_protocol),
+ (priv->local_loopback) ? " LOCALLOOP" : "",
+ priv->deflaw, priv->dchan_num);
+ len += sprintf(page + len, "%05d Layer1: ", priv->layer1_replies);
+ if(priv->poll_noreplies > 1)
+ len += sprintf(page + len, "No Replies [%d]\n",
+ priv->poll_noreplies);
+ else {
+ len += sprintf(page + len, "%s\n",
+ ((priv->layer1_up) ? "UP" : "DOWN"));
+ len += sprintf(page + len,
+ "Framer Status: FRS0=0x%02X, FRS1=0x%02X ALARMS:",
+ priv->reg_frs0, priv->reg_frs1);
+ if(priv->reg_frs0 & REG_FRS0_LOS)
+ len += sprintf(page + len, " RED");
+ if(priv->reg_frs0 & REG_FRS0_AIS)
+ len += sprintf(page + len, " BLUE");
+ if(priv->reg_frs0 & REG_FRS0_RRA)
+ len += sprintf(page + len, " YELLOW");
+ len += sprintf(page + len, "\n");
+ }
+ len += sprintf(page + len, "D-Channel: TX=[%5d] (0x%02X) RX=[%5d] (0x%02X) ",
+ priv->dchan_tx_counter, priv->dchan_tx_sample,
+ priv->dchan_rx_counter, priv->dchan_rx_sample);
+ if(priv->dchan_alive) {
+ len += sprintf(page + len, "(alive %d K-ticks)\n",
+ priv->dchan_alive_ticks/1000);
+ } else {
+ len += sprintf(page + len, "(dead)\n");
+ }
+ for(i = 0; i < NUM_LEDS; i++)
+ len += sprintf(page + len, "LED #%d: %d\n", i, priv->ledstate[i]);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+}
+
+static int __init card_pri_startup(void)
+{
+ DBG(GENERAL, "\n");
+
+ INFO("revision %s\n", XPP_VERSION);
+ xproto_register(&PROTO_TABLE(PRI));
+ return 0;
+}
+
+static void __exit card_pri_cleanup(void)
+{
+ DBG(GENERAL, "\n");
+ xproto_unregister(&PROTO_TABLE(PRI));
+}
+
+MODULE_DESCRIPTION("XPP PRI Card Driver");
+MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(XPP_VERSION);
+MODULE_ALIAS_XPD(XPD_TYPE_PRI);
+
+module_init(card_pri_startup);
+module_exit(card_pri_cleanup);
diff --git a/drivers/dahdi/xpp/card_pri.h b/drivers/dahdi/xpp/card_pri.h
new file mode 100644
index 0000000..dbe83c0
--- /dev/null
+++ b/drivers/dahdi/xpp/card_pri.h
@@ -0,0 +1,32 @@
+#ifndef CARD_PRI_H
+#define CARD_PRI_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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 "xpd.h"
+
+enum pri_opcodes {
+ XPROTO_NAME(PRI, SET_LED) = 0x33,
+};
+
+
+#endif /* CARD_PRI_H */
diff --git a/drivers/dahdi/xpp/firmwares/FPGA_1141.hex b/drivers/dahdi/xpp/firmwares/FPGA_1141.hex
new file mode 100644
index 0000000..0d844df
--- /dev/null
+++ b/drivers/dahdi/xpp/firmwares/FPGA_1141.hex
@@ -0,0 +1,651 @@
+#
+# $Id: FPGA_1141.hex 5615 2008-04-08 09:39:14Z dima $
+#
+:020000040000FA
+:80000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AD6FF400048120A006AD6FF400048120A006AD6FF400048120A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4455544455557475577775577675577775577765566665563625523235D2E37C2B5111155111155111155111A2
+:80008000155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111000000000000000000000000000000000000002552222552222552220025522225522200000000001AA1111AA1110025522200001AA1111AA111001AA11100001AA1111AA11100001AA1111AA1111AA113
+:80010000110000002552222552222F21F112122F21F112122552222552222552222552220000001AA111255222255222255222255222255222255222255222255222255222255222000000002F21F112122F21F1121200002552222552221AA1111AA1112552222F21F1121200001AA1112F21F1121200002F21F112122F21F112121AA100
+:80018000110025522225522200000000002552220000000025522225522200000000002552220000FFF9F99F9F7F78F8878700000000000000000000000000000000000000000000000000000000002552220000000025522225522200002552222552222552222552222552222552222552222552222552220025522200000000004F44D4
+:80020000F444444F44F44444000000004F44F444444F44F44444004F44F4444400004F44F444444F44F444440000004F44F444446F64F446466F64F44646000000004F48F884846F69F996962F21F11212000000CAACCC2F2DFDD2D22F21F112124F48F884842F21F11212004F4CFCC4C46F6DFDD6D62F21F1121200006F6DFDD6D66F6DF0
+:80028000FDD6D66F6DFDD6D6000000008AA8882F29F992922F21F112120000004F4CFCC4C46F6DFDD6D62F21F112128AA8882F21F11212004F4CFCC4C46F6DFDD6D62F21F1121200006F6DFDD6D6CFC5F55C5CBFBEFEEBEB006F6DFDD6D66F6DFDD6D6000000008F8CFCC8C8AFACFCCACA255222000000CFC4F44C4CCFC4F44C4C008F8C66
+:80030000FCC8C825522200CFC4F44C4CCFC4F44C4C000000CFC4F44C4CCFC4F44C4CCFC4F44C4C00000000CFCCFCCCCCCFCCFCCCCC000000008F84F44848AFA4F44A4A255222CFCCFCCCCC0000CFC4F44C4CEFE4F44E4E2552220000EFE4F44E4EEFE4F44E4EEFE4F44E4E00000000CFC8F88C8CCFC8F88C8C000000008F84F44848AFA4A9
+:80038000F44A4A255222CFC8F88C8C0000CFC4F44C4CEFE4F44E4E2552220000EFE4F44E4EEFE4F44E4EEFE4F44E4E00000000CFC8F88C8CCFC8F88C8C000000008F8CFCC8C8AFACFCCACA255222CFC8F88C8C0000CFCCFCCCCCEFECFCCECE2552220000EFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F88C8CCFCBFBBCBC3AA33379
+:800400000000008F8CFCC8C8AFADFDDADA2F21F11212CFC8F88C8C3AA33300CFCCFCCCCCEFEDFDDEDE2F21F112120000AFA9F99A9AFFFEFEEFEF00EFEDFDDEDEEFEDFDDEDEEFEDFDDEDE000000008AA888BAABBB3AA333000000CFCCFCCCCCEFEEFEEEEE2F22F222228AA8883AA33300CFCCFCCCCCEFEEFEEEEE2F22F222220000EFEEFEFD
+:80048000EEEEEFEEFEEEEEEFEEFEEEEE000000004AA4441F14F44141155111000000CFCCFCCCCCFFFFFFFFFF3F33F333334AA44415511100CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000008F84F448489F95F559591F11F11111000000CFCCFCCCCCFFFEFEEFEF3F32F223238F84F448481F11AF
+:80050000F1111100CFCCFCCCCCFFFEFEEFEF3F32F223230000FFFEFEEFEFFFFEFEEFEFFFFEFEEFEF00000000CFC4F44C4CFFF4F44F4F3553330000008F8CFCC8C8BFBFFFFBFB3F33F33333CFC4F44C4C35533300CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004554444F42F224242AA2220092
+:8005800000008F8CFCC8C8BFBFFFFBFB3F33F333334554442AA22200CFCCFCCCCCFFFFFFFFFF3F33F33333008F81F118189F9EFEE9E90000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004AA4446AA6662AA222000000CFCCFCCCCCFFFFFFFFFF3F33F333334AA4442AA22200CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFF8D
+:80060000FFFFFFFFFFFFFFFFFF00000000CFC4F44C4CCFC6F66C6C2AA2220000008F8CFCC8C8BFBFFFFBFB3F33F33333CFC4F44C4C2AA22200CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F48F884846F68F886862552220000008F8CFCC8C8BFBFFFFBFB3F33F333334F48F884842552221B
+:80068000008F8CFCC8C8BFBFFFFBFB3F33F333330000BFBFFFFBFBBFBFFFFBFBBFBFFFFBFB000000004F48F884846F68F88686255222000000CFCCFCCCCCFFFFFFFFFF3F33F333334F48F8848425522200CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F48F884846F68F8868625522200009B
+:8007000000CFCCFCCCCCFFFFFFFFFF3F33F333334F48F8848425522200CFCCFCCCCCFFFFFFFFFF3F33F33333EAAEEE7F75F55757000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F44F444447F75F557573F31F11313000000CFC8F88C8CDFDBFBBDBD1F13F331314F44F444443F31F1131300CFC8F88C8CDFDBFBBDBD1F13F33105
+:80078000310000DFDBFBBDBDDFDBFBBDBDDFDBFBBDBD000000004F44F444445F55F555551F11F111110000008F8CFCC8C88F8EFEE8E82AA2224F44F444441F11F11111008F8CFCC8C88F8EFEE8E82AA22200008F8EFEE8E88F8EFEE8E88F8EFEE8E8000000004F44F444445F57F775751F13F33131000000CFCCFCCCCCDFDEFEEDED1F1261
+:80080000F221214F44F444441F13F3313100CFCCFCCCCCDFDEFEEDED1F12F221210000DFDEFEEDEDDFDEFEEDEDDFDEFEEDED000000004F44F444444F47F774743AA333000000CFCCFCCCCCDFDFFFFDFD1F13F331314F44F444441F13F3313100CFCCFCCCCCCFCFFFFCFC3AA3330000CFCFFFFCFCCFCFFFFCFCCFCFFFFCFC0000000000009C
+:800880000000000000000000000000008F84F448485F5DFDD5D5000000000000000000000000000000000000000000000000000000000000FFE40F481800000000000000000000000000001400000000000000000000000000005F22020000000000000000000000000000000000000000000000000000000000F04FFE80840100000000D3
+:80090000000000000000000000400100000000000000000000000000F02522000000000000000000000000000000000000000000000000000000000000FFE40F28000014000048400128004840012800000028004800001082040000800414001082040000217F270C00000000000000000000000000000000000000000000000000000068
+:800980000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F481800280000000021000000210014001002400100004001280000808802880080880200003F7107008084010000200100000000000000120000400100000000000014000000000050358084410128004840818102214860118075
+:800A000002211A01148002211A041400B01281041480028004148828108204808802214800CF5506481800280000000021000000210014001002400100004001280000808802000088280000F08CBF000000000000000000000000000000000000000000000000000000000000FFE40F00000000000010020000000000001800000000004C
+:800A8000800200008828000000000000BFDB0C0000220000000000000010020000100280010000400100000000000080280200008FB90D0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000002100000000000000000000000082000000FFF401000022000000002100000000
+:800B000000000000000000000000000000000000000000F0D8B400000000000000000000000000000000000000140000000022000000000000630A000000000000000000000000000000000000000000000000000020020000EF1C04000000000000000000000000000000000000002002000000000000000000EFBC0E000000000000004A
+:800B8000000000210000001800120000000000000082000000000000F0119A000000000000000000000000000000000000000022000000820000000000004F76090000000000182118000000000000008002000000000000002210010000000000224FE60B00000000002480010000000000000022000000000000002002000000000000CA
+:800C0000283FB40100000000001800000000000000000000000000002800000086010000000000F0352B000000000000000010010020012008802101000000000000000000000000002A08F0E78C000000000000000000000000000000000000000000000000000000000000FFE40F00002800000000000000000000000000000000000096
+:800C80000000000000000000003F8D0E000000000000200100002420011002000080012800800100000000008220020000006FFF0E000000000000000000000040020000000000000000000000008220020000001F1C080000220000000012000000211200000000800122008001000000000000000000001F2A0E0000000000000000004D
+:800D0000000000000000000000000000000000000000A02400706A0C00220000200120010000000000000000000000002200000000000000000000F0B88200800200000000000000000000000000000000800200000000000000000000EF2D0D00000000120012000000000000000000000000000000000000000000A02400E0C70D000050
+:800D800000000000000000000012001821000000000000000000008082140200200200F7F20000420000001800800200002800001800001880210218004800000000802402000000009F1E050020010080020000000000000080022800008008280000000000000000000000D02B0C00000000280000000000008001C0222002200118827A
+:800E00008001000000000080440200002800E0CA090020010000800100000000280000000000002220020000000000004200000000F0993300002800001200001800120018800118000000200100001200000000000000000000F0194D2002220022220000002818120000188001000000120000200100000000000000002004006FC30C9E
+:800E80000000002800000018200120020000001818180012220000120080010000000000000000CFA3010000002002222822000028001880018001280000002001000012000000002200200400003F3601000022000000222880011200800118008001001222000012008001220000420000004200002F720C0000000000008082020000CF
+:800F00000000000000002200000000000000000000000000D78D002022023800280000000000000000002002000000000000000000280000000048F0B96D0000800200280000000000002002000000000022000000000000000000000014F0E1CD0080040020022200800200008002218083818801004001008004001800000028000048B8
+:800F8000110021F0164F0080022A222102282A82A22200A011000000808102221222002822000000001A0100000022002024240414F067F62002A022A0228002000012228001208123810180A1118001808102180018001A01280000420000804401C041F0F28C00200200282232002082A1112003221812181A02008001A011120028A020
+:80100000111200000000000000000000F03F1380020082000000000020032220022220022A01000000000000180000000082008004488004690B2222002AA2332AA2222AA22200001AA322A0222AA2333A81A3312A22A2222A022A021200A022800100122A020000A0CC8A0A004A442124044AD42708226A0448AAA2332AA2222AA2222A09
+:80108000022A021AA1323A03A0333E122B311AB32223A2881AA1A3001A51112A42A122A05580041AA1220000A022CAACA800A044114632424AB442F46F88808286A2222AA2332AA2222AA222A022288081A133002AA1312B113AA11228881A21A122A0112E212A022A021A0500123A020000284A0400008014A244F09EA18082A6226AA251
+:80110000221AA322222A22A2222A82021AA1321A012AA2131AB312E123218282A833BA02A011142A12A122A05120041AA133000080A2442200A044801442A2448F2C0900002220022200000000000000000000001800000000200200000000000000003F7F0F00220000002002001812002001800100800120210200200100800100000072
+:801180000000420000706D012AB411021B21421B2123B411B24291212B9419B24219B14229F342B1222F142BD212AB421CEB22C4A12E421E212E529E212E5296C1429AC2421B292CB59142B29122B491B242B181324219B24298212B84112B84222B84222B842AB442A8424AE822E4C80F2AB41184B41122B411B242B111324219B2429900
+:80120000212BB419B24229F142B1F042B1D0129B422DB12CC5B12CEC11CA528E212E5296C1439E212C34912CB591C6421B29421B282B141B282394212B841992A21B482324B2422892822AB44238222B8426F261980082480000000000280000000021008008000014000000000000002228000000002541717B0B22000000002822800184
+:801280000012128002181228001222188022022200000000002200000000000000630118828048018002000000230180010020044880011818000000000000A82100800442C0211148001C026FCC0C200C40018002800218801202800124202101C2A021002219022800420000002821002200428002400214F0E444A01200880000800202
+:801300000000121812200212A0420012208121010000000000808802004800404181048002BF9403000022400200180000008022A124000000008082010000000000200800004002000000DF740A220000802222220818141880050000204601220000004820020080081248000000142100004800E0E4052200800200288218001280017C
+:80138000200222A04200220000288004280000001200820000240000800400C7F4000000209222002041012004001842001400000020010000008200420000001100210000001F240D1800221001224800428004004280029011009848002001808224220222808112010080840C200288622428009FFB0728203411000000282800182626
+:8014000021080000244A828229210200001480018004001002A0428820028200400200CF620742000000002001000013040010010000001A0220020000008248222A0400000000002004426F1802680038400128428083024212228800221031116822A04128202301222848282200208116B12204A02448C800A20022A02480F41938805C
+:8014800001100100000048001061144800000000000000008001800282800200800800008848000097F31041013011110000199481111C8184288281026848402222048021090080A54100109112424242230400000000801402F05743802281240118184021080082002028044021022018111101200280A882802C21030040C142110046
+:8015000022800C24802282045FAD0C80440100100120810218160180012006284200A084000000421200002091428248002100001022120220F25BCA002061140011284200200400001811188008220022A0822800001CA881400125031450229042660148482820044A0222F09686140010611200806618221442820020280400000000A4
+:8015800020044A0888000020012100100210020000000028371A8001280028220022200200000010222C84C511184A82A4213800424820041C140180042904000024000048000017EB20820118121212111400881180918122111A02820000C0811414141400288A019AA4A14814112288221160122115024022542210822204CBED008649
+:801600008102000022000014001200000000482A818204480000002021240421000000108208000014F0E44980011C04820028004800281C04000020B882041822C8002082C8418800A04100001488004081464142022828002114FFE20F141358114021812392618A6214AA4231111561182A22A1241429B84124AC41212A78618124A296
+:80168000B226212284A4114A2C2528B41151214A16A2CC11401191412D2223243842242148E01684F2DDFBA01292281CB181432111611211121D814A24A81500A013A047A08242141A84A224171514424880AACC13830815418244A24C2CE2148424D4120200249042B042021426F29B82A0211C2533511238111C22848806111C89848875
+:80170000E1188904288A88062A22A441171A189A84A2884882A0188AB111AB1166D11231121511522225D2238214C241B0224C82E22622B22202F0A7478002288002008008888028C181221C28C3812214221400001882A0288002190228808281C282288022044260242242004880046D29F031211F13E112A2531F11A1111A011F14B43C
+:8017800081A24C15F1C1C117181B5C2AF2B1B11F18F2E1612E223F1EBEE1BAE1BE42F621211F16A417428AFC61612AAAA4AAA6E21F1EFE8161AAFAA1212E211F14E626F263631F1EAACC2E621F3252333D433D423F34B622E22EFE62422D222F26B662A6264AE426763E061F13A37F2AA2331F13A3111AA1221F16B681A2C41F1AFAE1E1CF
+:801800008AA1F41F1AF8B1B1AAA3F717323F3EBE63BCE1BE62F721211F1EAE552AA2C91F1CFEA1211F14AAA24EC1CAACEC1F1EAE8817111F14E627F351533F14A4666E621F36F643433F3296431F14B442E4287822F242622F22F262622B664E412E625F2B0A1F13D311F421211AF131311AA1331F12F2414119AA66CEC11F14DE11F851FC
+:80188000511F1EACB3987AF7A1832B662F1EACEA1D716AF661C11F17A566AAF6E1E12A621E8A86ACCCEAACE81F1858111F16F451333F35F5C1C33F1EFE41431F34F463633D22372435F342422F287822D222B242A666214AE422F68BEBF031311F1BF531311B121F13F331311D111B221F1696A16AF661611F1CF611911F17A5441F1BD31A
+:8019000011AB778E823F16F6C2C1AEA21F16A6661F16FE51516AE611FD416115611EA81BE6DAFCE1C11F19AEAA17111F17F451333F37F7C3C33F1CF4616335F323213D2333F4414125F2A2A22B462F24B622B262B662E216E622F292F6400114C011E01A0122601200121001130111308110210428A024200400C081C081C01348184002D3
+:801980002440030000002800F0941F0080012200282220060046110100200442008092411A022820048005180000484601001400001400200222CFA402481B21B01122B411324219B242B111B64299212B941B412B94222F1429F342913AD412A9421CE922C4812F2264112E4296E12265192E429AE222B491E222B49162221B29621B29FF
+:801A00002B161B282396212B8619B64298412B84AAB442AA422BA42A94822A84E822F4F2C180B41186B41122B4113242282D111B612384D212B311B6422173422153323AC4113B4229B92185F923C2122E5216F12152122E4316E12234912E421B492E42132926F86213133862F022811994A2682D838AD42282C4A22A84B82294822E42A5
+:801A80007F630722824800000000002800000000000088000040010080840200000000280000000025012FA9068214008011021E2111828A4201901100A048424880022011012818524A01800C11A014002A48012082844401244824004240F1CDD61021088621018042021214481C458202180028220062221002A024280012002A01880C
+:801B000024220000C08224C82C04002E42624081F4BE380082C041181820922111821C3A611C011601004A4802A021202A4101A01219A24120014081844402881100288E42248A4602230427262C264481F45F6D401101820021C01280018044220212004AA242004A02100222425800800C2A01982082020000481448000000004F560964
+:801B800000002C01220048A04800000020A92400241022140100880000802181011C01002228000000004200F02FC500202122022C01A0812001399D114A082B814001280000004840A212800328002400004E228288820010222224AA842280045F570900126022000098800888138108888088024042024800009A021A020020810118FA
+:801C0000C022822A8802400222202A2C0400D60F00802201360220041A042F110442301230114222000040810410020022204102400142008200008004200242F0DFBE002242100112121D42800288000028190190828002180011211041023200144842144800000088A024008850224220F274CF00A03418282A810228800100382400E5
+:801C80000021230400981242A24200821420210248008002422084082288304280420280B4E545010000002400400148000000001400000020A324000000008042010022210000002008008FD8480128181828002C41032814824240024001214211280012488221188018A2210011804481C221002002888048028222232804F0E1CE00B8
+:801D00002002141AA21220061800800120820120080000C02148282A040018280000420048809482002A04480000A0427F8C0B40210112582662240020880100214001001A1411012448C01316A1422082810412206412144A9882284AA22410220400420000F085381001001420011242210018142100008004802404000018001918313B
+:801D800012224280A8C1282004212148000000224042F28D7B800480A434A0141142A014204401001420A241288002282311822104282006002002008004888008008084082A0826028FA20C001A0411420020044230422901001800004229190220040012824220880224188800C880080021488880082084F81576E011042800002324DC
+:801E0000120128284082410122280086210800301288422041020020021B4100282424110080240223088200F048F70000000018A08100A03880180288A01223F122121818224A2101802101404121020000C2888028844881040022214800F063C100C04100141110022901502113010000203442112304200413011022212808884A2895
+:801E8000A228190148202602230400000000F0EB1200111001121984011842114800121A0225418228022A44A31414100111001301281180810129848222020010022304282121C021F0317320031C8404002001002582020011002011828809292881042048A148428888C8C0620000009042282420222484041042F3AFFAF041111541A5
+:801F0000011B5118484229A4811AA5282E42198121015012E022A5516E92EE614A9462122B45481B151321075A7841E1189831288AE424E311E914C4C26AA444EE8229269841480042AA02230A3421CFEA02229011C0211321E4110419241411F252831593822D1114132292824A8264212543D232041C415112381824482221AA2903E279
+:801F80001A292E08292206232414A2660048C8C041F0E174141A041AB241044AF431132D121AE3241122240523C11228111A882221621119B881A816182C212588C58212AE718A39418A084AA24239328328A82A8AD421F8428250224221C82F249C8228A0222CE89D021A42A1211428142824282C8882083C2881288218011242121003E9
+:8020000029012098118A0228142888004003220000482440220222242A042A045FC20B1B571F15F311111B721F1FF751511E332AE226F643432B441F3EF6C2C21F14D413A3AB1F1A58212F1A4AB292A9AA17141F2EAAAE2F26F631212D823F1DBDC12CE92AB2F2EF36BEA2EE18FCE181AAA8F95E422BA82F1EAEC8EAEE2EFEE2C23F1AFE08
+:80208000828215C1222B642B22EEE22F2EEE3CBEE2AE222AE22EFE2523F071511F11F631313AA7D57AA7752E624E523F3EBFC2FCE1632BEE1F1CFD81913AF3B1912E222B882E222F2DBDC2FD5111EABFE1AEEE1F17E724FCD3D15AB591F1A1232BF5FE732F18AEC81F1AAC8ABAAD45BEA1EAAECCEAEE2CBEE2FEA3E12F2A5E314AA6662A58
+:80210000E22ABCE2AEEEAABA62A4662F2E7C540E1F15F711411F13B321F351511F15E517B522E424F4C3C17AF741C32B281F1CFC11111AF281A18E822B223E322BBB2BFE1F15E11EABCC6A7E11E125F493D11E415AE437BED2EF23BA82B2A1F8B1E1BAAABB16B2A2BAE3AEEEEAEE2AFE82E23F1AFEC2E2355122212B66EEC22F2EEE3CB84A
+:80218000A23A226AE62EDC64041F1547F111111F15F171311F14F171512AF472323F14A1771D832F2CE615F513119AFB13311F2A5A123E322B992BFE1F17E32EEA14FC62E21F11F1D2523F15A5DD1E113EB32BD51F2BB3C3ACCE1F13AAABFAEB25F473F22BEE6AAEEE6E622F2EFE23612F2C5E332F26F442622B664E422F2EFE42222BEE39
+:80220000E02242F23169400100008004000000120020A124A024002004421800420022A08280012A8924824402000080040000F02338201201282212262261221280021225211312812202323081D0222484014814188021C4811280A2161924022A88240200800400488024045F910A481B21141B21421B21272419F2421319B242B91190
+:80228000F2429213F14291222F1439312F1429F342913AC4911F22C4812F2264112F2265191F2264192D529AC2421B293CB591D222B89122B4917262B381324219B24298212B84112B84222B84222B842229A842882E422F840C481B61A02146A121271419B242B181A2141B294AB291B24231A12B14B225214B31B21CD122C5B12CEC11AB
+:80230000EA2265112A6C113CA9213CBC81C2521B612CB911E224B8912236812394212B84282DA319C282224A28F2428222882B42882F22F4F1540082480000000000280000000000000000000000000000000000000000004001FFD50B4800004816321120011E4120C14142242880045260221490212228801182820188188008382AA462
+:8023800042E0180411144280068A328280280222377714328A0312223E8121002D212321023490212D1112522C6212288A02001800298182018021342212182B81158218012400822448114880642242408174334981250D126036C011D0122161162230434E21112A81E12462225A22281123C81100E0219211281212C25A828199122EF6
+:802400001320024601302124481B24482044C2C24021F62E9220820220A2812C01801222011301D0220142400128220028222829010000240080086A984120181281880400A22928022200DF130A00202102241280442201004012410100280048004221422A0118281400C01148002140A24800002C0820880220F21CC12022020014A852
+:80248000112602204402305280E52821E31224041C2444C1421681A112002828460240012813C1324A22888C0A800842808C820420021F930B0020811221184322045224001240410319242442212484448194222081022C140114A0211B1418208828A284200820880CC80028F0D25E208202002022210210024022042B1498322200423B
+:802500001041828181212402382200001160224A12822418020042108202280022BF5401121842204222021448182001282221000023028094911110011001284A82413211489081480082800460228848A084C08282A084BF490968A0241CA314008002502220840200002A14921124A898524222480048140000484800280080022002F1
+:80258000820023440348F08F7C0080012002244800003012001415A224210042002012021200210020022502282400402208000000144240F274D5146818181C21249222B042828451221224182400146848901146821EE111843621420010021820034622A8241022084A8208248842602842824A8824FC9B75800122282A010014000005
+:80260000482002112490222200004002200142224A02501210120128000021008008420000E034091132400122194421041B1280012AA181118084A82128422542222401244642024AB2229112D0121402142B428A44A24821100229A44823248424140280082FAF0B488086A441002A018224002B285022180021290800001091210000B4
+:8026800000238451214A82081002281CA4821C4811218A8882088800F0B1EB00480024000022201202282880921100481858682301E8272422132604281180829211481A042B2800004A0211210020022A08624FA10F00484A0316122124A1143B241190222100A0823880813821302100121A280125218482080010A281002324180229F1
+:802700000210A28421882448007F330E4220210120212211022A0100882982082BC248C280082C820100800221200412202A08A80080024A2888820200484222217B773011141946210129428382226414282C020014250126022B481002800440022001D0120119A414120028000011C0C24002100280FCD82620A221002268200180913A
+:8027800082001083088214131821031308111C110121484A024229622214A814142848192888224C010020C22220820226F293E780218C210223A114206421A041290180028820051A084A0242428A81A4122E4122C04148002200282A8584848402A88248A0C2808C82286812826FAB02004880C441284042010028001814483452195251
+:802800001286814181288281042C68112C2822021A2C214202106222C846224422020040013082F052BC7011A11C132382B2437212A12225226A122327032AC22223C12117291F3AA23113E619D11133223B44A0A81C8242A124622F24E426C12211881E611E4219E224266C2C424E22A82724CE811F1C062B284A642A3022601266F2C3BD
+:802880001580B38182B11164211E524A91115AF513226819CF1282E01AA8921B881CA8814EC29A08CE82883E2118423F25F522523B1223E221A2A16823DC227623B1E2B1E128BAA299A24868A2421F18022C98A26A042BC427128AB862EC388A7CF2014AA443284E314A25B2216615284AF153123421257212321211B062B44275A2C1710F
+:802900006ABC22C4432456F1315120ED24C6C229E41251122AE413A131111CB25225E12294A32B822DC12B4A2A9C4321EE42882EA2808AA428A028CF2A420100204801001C2881082C08200840321130113083100129211822088220180288C09211241124112440022400400200F04DA3A0551F15F111311AF751515AE415F561632B66B2
+:80298000EAA64C1F16F6A183822B28157181E122F2E2A21B2ACA7C41C14119AC443F2616E236F4A3832B222ABA62AEEECE21EAAEAA1F1EB222FA2141AE22681F16F621614AE41CEC12D411784132411BE4484E822BCCCAFCA1A2AAAAE44AAEEC6F8A0F7E711F13073AF371716AA6641D232B66AAE31FF7C1C11F192A28A8222AE22ABAE2C6
+:802A0000FEA1D3FE932BBEBEB11F12F342411F365E121F36FCB3D32BAB2BA21CACEFFE736A86B683A2A21F12E612A2371F37FC63613F34E41EEA3EBE41EC1C38411BCC2F2CFC428223A4CCA0EE29A2CCEAFEF453141F15F531611F11F211311F15F571615E511F36F663611F16FF5171CADF118388F831B11F1869282B843BBA1BDD3F1A24
+:802A8000E311B561FBE1E21F24BC23F661633F31F1B3A12E22CE618AE222FA6262211F3AA6A21F1AFAA1231F3BFFF2622B6E3F3EFEC2C23F2EFC63C33F24F241823BC42F22F242A22F2CF8C2C22F3EAEAA2BA22AEA2EFE7D2D145E111F13021F12F311D11F17F653711F34F643511F16FF12714AF793938829F8B1B13F18E922FA62E11F23
+:802B00001AFDB3913F1AEB19F9A1A31F18F841433F13F6E1613F1DF953632AE22CA46D1F27FF62622F2EFEB1212AFAF1B11F3AFAB3F32F2FFEE3E12F2EEE2EFEE3E21F26FEC2833F28BCC2FCA2A22F26FAE2A22F2CFCE2E22BEE6AA688EEE2AE340040013400400324483440321100200912422014A2241142114221422901002100C01109
+:802B8000C081481440A14880C4228082A42400821FD80BA02100181B612001111880013081001C0821222008200116312220022400281892A04825022038224821822724200480142202241F2F0B481B21221B214AB111326219B242B111B24299212F2439112B94222F1429F342933AD412AB431CE922C4812F2264112E4296F12252964F
+:802C0000D122A5292CB491C2531B2925B29132421B292F24B181364219B242B881B24218F14282A22B84222B842229A84A882E427F5B0A1CB511A2421B214AB111726291612B161B612F1618B142BB11B242092F1423D1123B312DA13343D123C5311F226C11488E212E5296C1539E212E42923CA56926236136112F22116126112F24981D
+:802C8000212F2482F242832242A22F24289A822B422344F28E57008248000000000028000000000000880000000000481400000000800200000040011FAA08421222122A41A1120000002446318200008A02A88200212001002902001011C1128E127A8884043083C2882C04008002A200DF33031621480124283116227172222C223582CC
+:802D0000821823252AD32221A438124A728282861132222C82298485B823083681899843008018A2242E421041817242026825B281844421F463D98025888225113111002986848214F283229812281E2216C242281AA8A123E82882012B21282938412304390846018829C412E8424221682E812A2C18D1228204482D221D426A48016FA8
+:802D80005E0D1412146022282322911212290818824230428200A89228489042100220011A8288021AC291113C218801884082141221042480028800481F530620812141022E1128222818128044018800B23882400211424001422908200100202288810400400224004022024840F293A1E01421C22122183210A1411C4811D1212148DD
+:802E0000E22106E82D4242200440012880C2122A21222282B4238991222C8818B28192828683B882224681488172222284A284232AA84888AF770E18121C2341023880821891111182A041C062488A2483082414114810418233A228A0411C4102D02202160286C2828A22042948818212C222E2218860288FB30D4681022818381119A293
+:802E8000411982011223542122298848A21220040020022818420022248A2221828828C8A14A180180420124102204A028488A04DFBA4B21015230310028140048232104242041022121141C24842904142014218304805212002502000022002221298804242A884402EF8103004220045021100200A02440020000240098002308130107
+:802F0000481422190482482304002C02118008220000222400D0C8064011E11201008004131111210800002822804502110022602200001002806218306120220800208284020000D0F80E1214121B215A02D021724102184683218C042582012200002111426018B031042A012213342231206638800223C2812800D0228284062221008D
+:802F8000B0A2080014400100001440010000249022E014914142002428002142480080082502904122008008008800808A0424AFCD0E20041C05210000100140420280344223015229082212221C2802283220622C12244AA1428A84123242C290218622040000002800BF810D0048102111828124082B18210018481800A01E1462148066
+:8030000024018018022AC882121394812001428800004210024A480222804882F8A1F514400160140080410320412204180028422044024260242C612412484860110090A120034880860810A348883022482400003F7606628024042388440120247441228401009200008001228A010028212C04802208002002101212820822808888DB
+:803080008888A884286F980C130100184212242818134403A041A0244823821402821200000088A08240820200C022288082280200820000212602281CF8EAF600002002100182189280022F2108120022D222E22A69221C81228222824881AE141CA98122A0384082188202882100242280028210022FB509000090112148480021802940
+:803100002804C0428008182004881446014200E012882442A13800004280088220840628482848002672F1031C8584044200004081A224004A2828A41822800200422014324248460114480000888064160028290888208416C2820000F0E98800A0421212482A85440188E031982100120000100218128811425012C041246012112A04A5
+:8031800000002280A4248012228848029022222302BDB9C01142221E41111B44238124C4814A88692319898C21A4149E92242A8CAB43121B426A25E11EA6D62F243422A22A22DE23F3126182222A24812BF4C3624AA2A42E823C9482484AA4A4C2B04244A2C2A21CA482FFA94EB15102002CA4116A64141286D2317582C341212C7182A2F3
+:803200009220B262048A848186880217212522E21C9C412B481C6812423B338AAA212A0C2B222A18A24A28294252322122267222E22A38228220A8283FA20F481C044AE11553221813D11286011B253B944622A5C52B411AB442843212721B842B8E21246E1118158182B142A2142CA6CD1B9A1C54112F18A9382AC442A04224C2AAA84823
+:803280008AA8888A94E2A880DA2282AA2225F2E2461428804281428242A121A02834922440220B122C0228922882281828312821A082D012011C081800002002244002002C02800448F0A66E147E6142281B731F2757112B646E722B761F14F4C1431F16F7C1531F3CCC222AA798CE922F22A3268AA8329AB122A24C4E423F14F471E31D69
+:80330000412B663D432BEE2AA6E61F19F2D341E011A3EB9AE822B262F6C1C14A84A8AA2A8EACC8CAEE2AB262A688EEE22F28F8C2C2AAAAAA6E422FA34561112A86F231311F15F131315AE726B742B561B651F521231F16F783812BCC6E622AEF2EBA4265248E822B44422B54E02CFC73611F15FC41414AF4C3C33F1EAE446AF633611F1EDF
+:80338000EE16A2B3BAAE8826B262F4C1816AA662AAAAE22AAEC8CAEE26BAE2AE22EAFE22222F2ABA62ACE66AFECEE8145E51482217131F1555116AF471522B111F14FCE1E13F15FDD1F33F3C9C422B3BFAEB2DB9F2BF22A2CC2BF6DAADFE826EE23D411F17D711E426F6C3C12F1EAE6AAAFEB1F31F1DADD91B3BBAA3D92E622B441F1CAC95
+:80340000CC4AAC222AB642EE24BCC26C242B66EEE22F2EFEC2C22B882BAAEAEE26F6DED5147E6120F231111F37F351412B571F23B532F3C1C11F1FEF1CFCD3F33F3CBCD2AD4C2BDDEEA22BDD2AB2E2BEE2EF2FAF66AAEA26FE33711F3FB721F662623F1EFEE2E1EAEC2EEE1BF7E1611BF9BAABBF8AEC22B662F4C1C3EA8EA6AA8E622BEC58
+:80348000CABCE2EC24B262A6EE2F2EFEE2C22BEE2BAA8AEA22FA17A58001001800481448000000A048002880022880024A024A22222402001880012248884002800482800448002882EF330B18288042A1612302181B29181B282D1280A1422921822912A242982A842822752102228229244822E8123191802206248A2606888A422208D8
+:8035000080223242222304C0433F4F0A1CB41142B11162341B2123B411F2421319F242921B212F3419F14292322F1429F342933AD412BB31C4B11F22E414FA22421E211F22E519F222D29E212F22A5292D521B292D531B2925B391F242111B292B941B28272619F2428219F24283112F1428F24282222BA42229A842882E425EB480A42141
+:80358000481A22B4117242A12123B411B242A8612F24BA81E61421734221D31228D912BB13849B521C9B83283D529A82ED19F22251922D538AC2131B692C81E214B191A2948A7262139182284EA1281C28A2A4824A2A9A822B4A882B424FDF0E004882000000000000000000000000000000008004000000000000000000006FC50D111133
+:8036000011002E13E0250282CAF183122410022100009822002842808181332218902100111822144EA200008A3282C0429042422C02A24A22043F4E44212402180018C042112022042C44711182250520242132C24002211022E42284082822241318D12241812634222D41214825024200E02802E018029D6D304140A141B021014A8219
+:80368000D412A8412E912B422124142D112B4118408221E1212228CA4230121827231B2416021C02629093282D11193222422722197422A2C2212384142244622286822646F22FC20019020090121221C082003042002004A0482820040000004A820822400114B042880400820024200428822880084F1A09A021181A022880A212402140
+:8037000021944100210011460128002014210416914280040000001C01004AB881140221C082A2002008484FCC024001141C022C0250221E226021121532412642A3212C24C3110039042622342280E22182015823471271226211522904282422C08121824A02002914228404DF7B0460123011142800002C031042512140214233611898
+:803780002890418052124240F1221280242102115012463211200248190890824220024821C8003DEF0012122828C022282E125012184A31512442282129818441011002482C240232481280B4424102292281210400292A74820320C2828810028084F47713002004400222420000800210020040420198130124181421122501100248C3
+:8038000048A02490420000A0422C8228840C8042029F8E4C31111C62151442C061001411222842582430412002211100986024828004221433820216A14220021160245023908122210022202848024FD70900800212400229241303140042121381240428A02411800220230480012082912214219021002018020024C0220048F0D17C9A
+:803880009011260128421632612C828424C221C04148208411812604194281166111662238124E3123841292332C021B121A92221129542146011092821C28C42220944290828A02243FF60B82C01111000024113C010018502219840100000000000012000000422822208214124102248008A8220042F076EA002800144A018011014863
+:8039000012208144711241020012230450238026B12104000000122C0420043022627082828482240E80248848F258860011C031182413140190111502111180031C011414140020C2411239042944220290211312312112423023214001421082022348820A68F0749860181811000000002A04400122210018800211142882501212A007
+:803980004142200480020022422242801401488008282400F01BDF0000C01211802204481001622502150221211400186021112126022CC222241F210212190380120214800882800823122204808A82B2FB080080022219A4259021181A8234422152002902121200004242423041008A014E122C01421C82044830212998422B82A04275
+:803A000023024810928220C8C19F8709688002288042C221C02100800400102132422111290711100224248846821101009012242224882288800A00004A880400BB71000080D4210580458204180011120000800100002848298204280028480020042800003304100200222220F2B31610B181122184020022000046410211800221904D
+:803A8000214E11C0112182000048141431144081040000800230228004800800241FC40D8218481800804101C011800218214041218211021B16484A081100221C238922011A9422805222130882422084220840A2842A0410023D8280E21A83C2411AA2314A061B76B053065225717122B4230116531224152122E112523139B2C29C1232
+:803B0000182E1221296112391161221712142AC212302330838A1682B44188A62228A882212821A6E122F4FFDAC0418214322E113314E214011C022E33A0442D413CA12133A1229032181D114E42190446012AF2426325E12424B7D244F11243171120E63434124A44A2422CA8821CBE62883442B0424402CABAC2AC82A8A88C4F1131118C
+:803B80001138423C54113A721211C1111B451911012B413434311532311AA421352184E52255314E43111B642AE228C6B23E224A81E3219331116A5222CAD631A222232466282738AE822724222B4C2BC42E42228A22042FC20D800122482C01200120220100322422200332200A2242230221A0924218A012200224200200002480020086
+:803C0000288A0448F05CA1141F1DF521211E111F12D611FA11B11F14F461723B541F2616F321311F3251223982A3323E313E313F33F323231F16F76171EEE22BAE1F12F261231F36F672723F15F721611F22B2F2E62FBE12E323127331D213A6667AE527F7C3C327323F12BA22F2C1833F3AFC414329F222222F26F642422BC46E422F2E26
+:803C80002E04CE82AE28145E511F14F411111F11F551911B3F1115F343711F24D613D411F441711D433B241F16F221313E113E333F33F123233F16E416E72EBDA2EA22E832F621832F37F773733F22F223232B476E632B221F22F2534337233D611F16A6772B773F1CFC23213F12FA22A23F3AFEC3E31F34BC82B822F262422F2CF442C21B
+:803D00002F24F6E2622B662A6224AF6B44E114F431711F11B131B341F751311B551F37F753511F22F253111F17E72153222F24F411532B332E112B323F23B133F373511F17E732F162211F32F8612317362F27F653631F126232BAE32BAD751F23F223611F3333236AA6776E623F3AFE22233F1A9A22CEC22B641F1C7481F322222F26F6D9
+:803D800042422F2CFC22622BEC2BA24AA2EE2947E11EF631711F13B371B351F571323B331F36F653711D223F17F361611F15D531F463433D633F13D312F122312F21B132F343411F1747F22221241F32F681412F33F673623F22F222232B3B1F2CBE72F731223F33F713333B261B227E722F26F6E3E33F32F2A3A12F28FA82A22F2CFC417C
+:803E0000C33F18B862B662E22CF4C2C22F26B6E2BE62A2266AF635AC20021C01182082240200800448000000421100100100002240011420022448148224000080820482288228826FCF0F4828182818282F12216114284E111982011412348001188001008024941290421A822465128081021AB46201803262E0242848824482842808BA
+:803E800022E012F455AA80B411A2121B2146B291B242B111B24291212F26B911B24239112B94322F3429F24291322D913AC4912E421CE82264152E5296F122429E212F22A52D2CB591E222B591E222B191E224B19132621B282394612B8419F24282112B84222BA4222BA4A229AA42882E426FE3071CB411A6121B21141962241B212B14C3
+:803F00001B216E821B212F24BB11F24282322F1439314E83322B843B431CF922521CF92382422B529691518E212E535AD232B181F222521B692B121B284E131B294A11918219F6428119F242A3E01428B2422AD2222A9AA22B42212E423FA3022008000000000000001008000000880000400122880000000000000000000000F064EC0013
+:803F8000108441022820312120021D92001B853B248CC2810000104141A1424C921248304213220140A1822018084228311C48A2488722228982348280C288F097ED9041AE11404BF42882141BA1311225C2832024BD82031213048904520068482902C04121222E8421332482011934B14691C1236411290CB0114422042301108C4421C3
+:80400000F4F45D80641C418311342A28191B11119221228E53582B1213A1144A22C84A0012E0182294212244211304434431514240C1C12AE118748822E434C1A2111B8234C8832292281042AE4220B47702141A02112188250129A1212482218028E8243821851101A014004814214222561182F222822821281820328190410042001AD6
+:80408000448254221242820089085BBE101401408302160800828800122902004601000085011C1282C24200C08140A22114822D117042022140220122801402232402F06B5E8082D1141138241C31121C32322D192CD221C141211B41311641632A19C1285AB2182272418416B25192525B349724282E1272132202128593941C0129071C
+:80410000144641834CF28142C64202898288AA4868421F1E0922169111812C9231D08191329126020011169311142221814800432414925137211E246668242840318120D118F28114960223444281441112D22128562246322882200EF07AB1400441404522814222011B183F24084A1182022968111B24381E28221428942862194423FA
+:80418000229172282840622110C1112A91421003C81229240800244A0A6248DF3E062155DA4164A2482384012D1A20C82430883814121A52422800244D41278498290317828018097062882152811D4220A4422004822136142844422804A116022E18446C0C1184520024000012252649A42822102601212184828089C442C0621433E42D
+:8042000028348480441884251402008139C24125542222250444812C42A2C24490A62082120844CD114890418240111802124001841442130128250C404418042200212C81222232812014A11400800C124288A2424400B04D4E92214D224C612249F4441348D08321A88133321A63A8181A827122311681258134184D8162E129C2421102
+:8042800089C285802E68221A64238584A1242F1824041416BA811202272490128443AC28A722126A3814446F450210511884248418602400804808113014200240C1428120058D242C042D485026420026912121208224840419941286281434421088440489022E420012911081212252182C21211128041418226140024521020033029A
+:804300001C01292121E484214181826A14A041800418800118210018800188687D9F14288140110811441811008022888102E08244084068144593188314C4A28501288129088381280428142908004484848304304A82200626029E172092283223022216082002289280E24214C1141180B82404002854E0190284891248012C946800D5
+:80438000261101400221001002202812A842302884DB11104204800280C1212002800282A280240881002372480143088324C142A08140081672112808114240180441219082D60820026210F4DEA2202812D141024AC22842848C42A1348001164214110490252823014C2262221F4411C1220050222C02262104000000428200904825C4
+:804400009442A13042C011FF760C504100005021201412E112C1281A283211C068834148C88C281C01301E00804101824864822014220442922128840083018304420021F0765400000050124430118850822C0811482133682482423188008C0C8C882B6194271884621608481502502288001C45881488041228880020043FAC038041F7
+:80448000081280818241A8210000422441001983C8288800252101A082A052C28921280A23022E5100B012042420342224002822882220F48AF3141480844148010040410489820241328383021C911289A41A811A08818131289440029042122CC28860A64001CC8191328CB188218888C11218101AF8CECA242E214B181D2825810114F5
+:804500004B1217919562114AF22918C898882F1C43F243F92E182F883314CCE883DE1168828483CCC14227218F26E583A1498FAC21558833E9347121A14225A228242C34138D28AC984829129A9AABC2822128429CF258287F9508B01912B821C2212AF221384A12EA12B2213B112189B12232611723165544891878C1BC2C31882B248FE7
+:8045800054B229B137F33114BE28AE11151848BA1284FC8233B033E224349342278442BB9144421A51828FA1856188842BB5221E922AB48884F4AC331460C216614185B841311A1584E38511A2129284821E7545B42633284AC681AF12D631022255F21643E4C7889D939D282B212B2C9B84A82D322E442EA289AC289CD211859C42A014BD
+:8046000012E36421429E885E42432CF258282B46282225F6B7D4004501004E81704421612460142004308124120000100129044890439092009082302A50385028D028082C08240000480000F0FDB214825F45F12929DFD3F6A8281F23F276445F66F43A3AAFB2F3D3D16E62B7D68FACB8D2FF84E66F6C7D27F7C6DC6E6A3F33F1D54DCF8B
+:80468000D9F9F1E11F1EF8297BFF74F44ECE6FD8F8694BBF3EFD323A2F2DFF4A4AFAEB21F976BE2B331F12F271783F95F3DBC9AB668F84F4D8988F8DBD38E34FBD58F14A789AB8DAFDF6F62F2AF83A38BAA9668F825288DF634913F27D7C8F83F33D6D8F86EE2FF756544F62F26A6ABFB7F7D7F52CF24B2D8FADB912F5E4A26F2FFD27377F
+:804700006FCCEDAFFF331B7FDFF6BDBD1F157F41F1ADEFF5DEEEF8EE6D9FB4F4CBC32FB2F2626A2F84A4BB3EB2FF77FF3BB99F9AFAF1F91F97F3DBC98B264AB452F1DDD17E784F4FEF25F14A789E92AF2DFDFEF62F2AFA7A7A2F2BBB22E686F64C4CFDF5145F42F215748FA37317F72B281F25F57B595762AFA3F35A581F5D4DF21B298E87
+:80478000CA2BDD5F62F5665667626F4FF9686ABF17F7FF6DDF59F9E9F18F8EF82DEFFFF2F22F2FEFDEFEA8AA2F18F872618FABFFCA48FEF8FEE26F6AFE8A289FBBBBF3FF7B71BF1DFCE2EA2B444AF5D8DC8F2BFB5A682F85B15AB5D8FDDA986FEFFFFADAAF83A3BA2B6687828FA4F53127347F4AF21D749FB3F37727BF82F23133BF91F154
+:8048000075773F33F333391F5BFB6163FF91F198DA2BD94F6FF9F6D43F73F3FFFD8FAFFFFBF9BFDFF4BD9D9F967F68F82DEFFFF5F4AD2FAFDBF3F86AAFAAFA6A68BE7A2F8DA5FFFEF24F6BBFB2FBB1B11BFFBB77BF3DFCE2EA2F24F4DAD89F55E5AFFF5E6AAFA5F17A588FADFDDA5AEFEFFFFA7AAFA7B7E2BF22F62828CFE4F4A31920023C
+:8048800040480100244021010000118524B14822D948328189028131810018422180092180011800004820018E482496082004003D2D5014008001C190188001818031112C084A0228501880029011141D1281B018D222043011142821192204463211207148021816180A18122901C049EF3F096D521F4152281F4132481FC1326E1F41B4
+:80490000F24A121D24AB941B28AB9451AB9453FA4A9343F2429147822D914F82C4915FA2E414F8264A56F1264AD6F1214AD6D5A2E449D2A2F591242CF49124A7221FC9324A1FC9724AF1812CAF24D1C1B24AD981F24A9251AB9443B24A39242B94478229F9A448984FA2F41633D0A685F62C41137162D2C1746EF3114CA7161F48F46814A4
+:804980001F48F6483259B64AA14A8F44B335E434712498126F82E414F9265A4AD983E85542EA557222F858241CF888242E5317C149B411342817418F34E841F2688215F44A121F48F268941F48F24AB2518B9443B24A09AF44B98494926F8884F1265ABFAB0584820020080000002800000000000000000000401884040000004004000027
+:804A0000000000F099BE8022D184C1141C410222A3818231811C4171520312832422480442222022361174F042111AA4212922011C681A197932C82185E28192239042848344484884889858508242C0C2AF8E0AA02828142C34C41B5A001A042A612486041F420C3932126C26422C81043314C1446041200858114A21014002C0818A2148
+:804A800028081308861172621822B838A4C18B189611F8718D80E28EE1C162411A94443B8322A13841A6D12141B451C2842489A4128E66265648A04124AA946156044439B551A8122B5299A141881B283C0C2342D2189A112C2808875E10584228218B1C89F51A4289256928CDCD0000113488428081842121348125B2218431212100A0E9
+:804B000014221001115429010000301120B128111128B12208428440C881B04A2808228882C0489C0D2601008012022734822A01344021812241032880826444264291111CC2120000282228181121282A8172420214005012802201324A224844F2E55120849331512691122A3823C0628A042361A18224172528221681E41334411428A8
+:804B800080B3428224D621A414562231125818262262221981042824D012012B14C2248227242E882398824828F0BDD72004131241039023F08222C2301312111835A221222521828416812442E11265126024801182218102282129220223022582012140C28212A6E222014A88026F614731213218442832290A33848403109A82A052B9
+:804C0000408121B41142813424D02203422C472185C4122862182C1321C211582848211411C0521C0C2248A1826A0844F01CA79042844812680012252462818825022424902214201122E21244440120022D268053122CC242430122418B8288271480B449084029862212880A248A8424F6712C0016882C52C2872200B042D84202C0C21B
+:804C80001AE2420114492142D882260180B932E424728428113149295448A0182688E811C448141068113880644130222C8138412428241058289F4C04001A484102842284401201441114444C8144028810289C2815022442000000241180120632002220A8481240489144528120025FF24382242121916A81843642FC22823821244DB1
+:804D0000C2126722412B121E412622A18418944E8419F2124262472A52257548A234202255248826E1C4C2A988298721E68804128F348821628A42499C12814A28E424F26A9120089021458212028014388121403111104504812688A24240C821248180120265082D821A4221414204154821611248882024114288A242008942F8DD13FA
+:804D800000002284401C031302123C081228989088C011400200337422422292222128821424480022000040220800002200424280F2B895002141184021011984841881258506482934221D182502009041104105A0210081C4114C722284110416919282385AC212D25E211A282339188826042684D49208A290214800F0122829228186
+:804E0000018001241782181688032812222280C25568211C0412100222802181020025220448341122810022682800DF8E01C02821008B1420042481282850421A04A22E428844B021082D842342024B8119A412488860212888404122014B82B02188928121880042882D446C08442904DFDB0A1200001120429124211282252228083497
+:804E80008284188A0200C0446200242A044400844C023011000060242004200400204438124781601400002438001412CC448102404208422112001C0400198183581426612180A14248410016024022342262342442AC02222081A12148AF8E05640036122448012D4242118842484222424210210482002414442338842981018288408D
+:804F000001804222328182180010C2149844242C215486442748F0E6CE1416E81831114621189821810048898802141C48F12811142120C521222BA48021084200211116A2281800202282823223111111408204409241001C044F550C25C8282B4221200519C43A8C51145C36121C6281488E24884E142A3481882D1480B1228428A142E0
+:804F8000139841821621018480A4122441186512140444004226223122624C02282127429FC50C3936812D121B61C41A7133D81131421835B188F452211AC5518E123CD239C63219E211AC629EA42B224B842127222F35C2621E456813A122748699841B444C92263AF32414F09124367281A4611F2222E5247411A24232301E3F2844C44C
+:8050000024264BB2A90F18AFA8426124824E884D1327A61CF112681AF111398A7143B24A3A218AEC87E958B422991629C911242F3A36614159F91194EA52126E3212882921B11A32242E1190231A6122212D9327322B813CF491814D515AD1A2A6A12A87FA66382AD414BA54F482BB6061325B222A019D412889F629621776478C6AF8215F
+:80508000C230144A7E713C82AF87F8584B11921302C0621F15E44274E6D123F8F1122DC4989A61212B222E81604124122F22D216B884A82242CE412312B242B282BA4C71A262244746484B144E542B22EB2A4004441444424424448004401104534112443285100561100321443948844114424401002440011C091C091C18C4824188849C
+:8051000088848816088FB20E3F15F4263C6B315F31D31BF41C56EF24916CAB754F45B738F249C23F14FD4714BF9DEF56F6C9C7CF56F2CDC95FDCFC47454F42D31551645F58FC23215F57F756F44F44F437175F57F1A1426F497194F696941E9417525F53F134344F63F23121474237337F52F311B51BDD1F18B3A1D155F993836F4DFBFEB4
+:805180007E2D82EF49FD9C734B48CD6CCFC8DECCF47CAE147F55F4267C7F21F13773F7D4CFF1F51E58CF82B648F47574DFD3F3C8DA3F16FD4744FFDEEC56F4E94DDFF6F46DC93F9CFC43436F4EFFA5B11AF181815F58F933214F47FFB6941F3BFB41135F7EF4A6A49E828B994C7849FD35154F42D244F2313147623F33F227351DA55F4C40
+:80520000FCA1311F42D955FDB7A52B33AFA7DF66B89AFDFC74CFC2F87E7C4F48F8665657BAF0575529F512341F3153CE8FB5F15A1D8F92F65C741F15F6782C8FAFBEC2FF4351FFC9FD6161DF9CFCEEE91F5DFCE1A23F14F527211F52A3BA1F1EFC61E14F73F714744F65F531533F1FF5F4772116F292984B9149F415154F41F334267F53A4
+:80528000F2243447435F5AFBA1251F56FA51A11F31B283D145F93222AFA7F7C2526FC7FC34F7CF82F4A6E44B734D547F4542F15353EF42F333363F37538ACFF5F11A5E8F82F62E641B77BFD7F7F8FA3F3CFF5745BF8DFC7171DF9FFF6DC9BFF7FDE3EB7F5DFD67D11F5AE92AFBE5E57F77EE13E66BF7B5945F7BF3D3522F3FF7B6B44F6900
+:80530000F892984B91C9F431154F42F324345F53F324344F43F2A5351F7BF3E1653F17FE15237F6CF1A3132F2BFB7E7E6F4EF5F24A4F67FF6444CFCFFF1C1E4F66B6E4062A011C010047121214841482144800249A041904120028214A9212901542490149084B921004224002346022482440044C026C024C028D24B0230F8216044C0213
+:80538000442031421E242128184331425138418531242B1453034100545D1280042B12120023922180822121028042014621412142A2412344284408F07583C0421F4152281F41B248F19124A7241D24AB141F48B24A9921AB9451AF243935AF3439242F347B25D812F925481CF9244A4E817FA264116FA2E419F2234A9E252D4A9E24ACB8
+:80540000F591242D431F49D23AF89124A7141F49324A1F49F24A111F41F24A911B21AF1419F54A914B42AB9447822B94478229F924484AF9244A5FFC0765B811169E216B141F81B244D181B24AF181242D141D2CABB419F24214322744842F546B824CF122484CF1A35A4E154FA228D1A4E411C2481E24BCE448D294F591284D4B688D5205
+:805480009E24C3B411724C81B24E81F24A944CB24A9B24A9B934B4427824B84A3924A9B826B44838A22F830284B01404000000400428000000000000000000004008480000800840042880028400002501F6480212209113539114841C210114182D4216A5846B242811A2821B12486210E14114A141AA25813814222213012D9188521694
+:8055000032184018C12140810412902823A48281838C047FEC0526641AC0212A64A2282829D21492238B86818A011921893428702A011211A3982223C238282422302289C91186220111828A0232A240629A183414198A82644242807228C1224F43054C6294E012B11136284B2183D212D31491252658281859A3842F47284228522A2EDE
+:8055800011181A7682E238B234C439328E122217281A32181E211B8127851B181928C4A212328114532212C14219A21AA02429A448A44A62162CF2214110A22100211741210028211B48188A14321180C421821C0A4211810020A4421240A482001002981281A0824072818811011428844C2202861808FFBC011800501410042051320022
+:80560000008C44244804421618881408008121901420022100800118100221191408248424908222006028FF16014C22C13585E122012E112CC5172880298C512112E024027034081922D2240439B21116227168022C512816011CA31287228E222A5822C0832A012488F148A88E48482608228266C828EFD60E44181644F81126C03560CB
+:8056800011381400181189158414044D6889511822412127121B4121214E2212002D1130313884128622012D8324002D881442214E8827248C0820C82885B2340532C02111002055262424984A081002A821800128424608801288411864218C022100282DA228240038601424C130A80022222280A4823FC50556C11A8B1444100228124E
+:8057000025463418842142230324002648482282A6826044214810922224601145AA2129A424871242A9D114C2228128161C28068B82288BC2522E822800373F204228248184211122040044808268862D2584282054244188989B21284004285216A112288480142808004A614146388258320000242C04E024F831FE100200A18C8244D5
+:805780008A820115022412241028484201000045022001428820149612442A0118892212028800008243A185128C92188C1448F88149B03364211849914A8CA341298257422184A121212DB28962528C2812638410840C4FB1F22442800529A6A418244D321216943242178B2C3228412E528CB848A281581282C3AB2C76B828B1229D281F
+:80580000818E4AAF940200814002401822011301A01460248421902840248222020041402241A225144423028302832471220118104A2804208188148804F0F6FF10144508120015828105241414190212145863B21808162294888484838424249228182C82011232002412902240088284008126B8285428828065247F12024820133831
+:80588000482315128814C2188124000045820222001420040038248286B1880482468894428C028082C138412302821220821122820181F0BEE400800110642422E022248433141823712162241824818C021008002A88711AC218241063882860828AB3322821140100A4CB14A1C688A134212A01809688812F4601843211284421108820
+:80590000420410084004228C6224608421002041420830C168001883A241818042228806A08140028B421088880800F0FA5AA0294022A124160224000092D0120828404401141820442141021002802102408204800100490200232188D1240380042288CFC64811D4419428301199963818169218938242023012202258844400AC0422AB
+:8059800029B2280484222B218042210881008289022118008428850200802192242984F28729C04100681004004022144108444929043848124200A08429212482048481128400222410922884A32441242101004A28B82204181248EF15091C628214101488C2314AD2282206100125A324442D480000008480C12820E1A481810422283E
+:805A00003018004E224A01266282864202901A1082A5184E22C0828417F640880146110913141258143CD16145C838123844299514182B414E1821A01442882116024F8408341888162881C482162803142C05B028A1C228C02288820029A94921F0F2BA807295F829121B455AB44A91282C8392288F31141154B1D02582DC21E14671681D
+:805A8000954C4A8531488181818FA422F468125AF7DA72181B313B219A826581208AB26AD413A2664AD3C8B188786488C1182B861E382FA583B48219324483A944DE367041E444018C52CC15E2237428F87A123F26A5162781AC391A1C695227673A522A2CF19228941A14018CA453218B4129728A4E89F442488A0183C3223E6829A11B7F
+:805B000028F018122393262E38A182211E38253224AB3483A6732AE184B928F85B2C144F13E412E29122D231F3146C271437114847C13D286E72B711183F21B21291346F44F414E86F81A21683012D4ACA643624BAD5A26381222AF8328A8B828CA8928CB228F1CA928F8152221E128F231C52882662219ED2A5FA9842812ABC88A88B1E33
+:805B800022CE829AA64225BA380B004001144002141214840000344003144001144011024908290800181002180084260224200442C02410082011F83BAB14557444F5181A2F83F26D645F45F15A581F92D14EF43A19AFA5532AAB99B092DB54B285FE3534FFCEFF4C6CFD2F1D4995F94A4B3F94F4894B3FB6F66B6B9F13F43C6E8B928D34
+:805C00004ADAEC1CFC8121AAE883F1381A8B738F88A8997AF76323AFA5F74A7AEFA1F1829A8FCEEC81F958F8AFA4B48AFB6C44CFCCF5F9FA2B234F48BC38FE786A5F9D47F155545D2D95FA3278CFE2F33576AFA5F72B2BEFC1F7287A8FE7772BF2B3B5A5B892DB65F3C7F77F62F3FFF6BFB4D7DFD18AF54858AFB555938F8AFB727ABFB7AF
+:805C8000FE7B4BEFE5F41A889FA3F4F2C23F1EFDB921BAF8387887A1AFA3F78A889E92AFA5F463232F85F7587AEFA1F18A8A8F8FFF1298AFA1F99A82AF8DFD2C8CCFEDFFFADB27266F4CBD18F8283A8F79074F42D254F4283BBF83F26D6C7F45F14B4A1FB6F55F55FFD2F15B7EAD2AAF295BA82B9947535F6FFD3437EFEFFF7F6DEFC3F33E
+:805D00001A485AF5495AAF94F448CAAFA2F36A7AAF85F67A6ACFE3F91A6B2B292B4D1F91A3323A7738FA9AB8AFAAF892922F25F643732F27F56272AFC1F388BA9EB25ED2AF81D9AAF18A98CFC7FDE2D8AEB81AF496C49AACFEDF974AF17475CF12D2B8F25B38DFC6B777F35B7ABFB6F65F7DFFF7F77B7B9FB3F297B1B7812B9B5F43F2F758
+:805D8000D72F73F39EBEEFE7F61F5D9F91E425F5495AA5F939A9AFA7F7FA6AAFA5F67A7AEFCFF8F8EB2F2FF6FB581F9BABBA8B338FA1F15A3AAD1A2F29F95A5A3F34B75AF51232AFC1F3A82A8FA9EBA4FC1A9AAFADFDDAD8CFE3F9F2FA2FAFB542F4D6D48BC98F8E5E96F02411003024842041638140081214C0261264C0241200428012FC
+:805E000082921228184221A0128001290118202201000012249220A924124A22D8C2028211188C22848241384284A061218424E0543121A119B4421101841413021B128121422492848008248C8288021A82810428A90925628200894208A260825F39032CF4112485F2112483F41124A7261D24AB161F41B24A9921AB9455B84A3924AFBC
+:805E80003439242F3479A4D812F924481CF9A44A1CF8244A16F1244A96F1264A96C54A9E242DCA1F49D222F491248D121F49324A1FC9B24AF18124AF16D941F24A9219B24AB985B44AB924B44AB924B44A7B2498924F8394984FA2F49696C04A1F41D628F41124AF24E1417268D341B46E7111F44A841F48F24AB25F88B24839A4AF34395C
+:805F0000A42F3479A4D812B926F442914F82C1916F226C154722D6712268112F32E459F222C89E2C2D431F48D228F59124A3F4812CA9E9C8F222911D2C2F449921AF44BB95324A43BB422891AA4B4229F936488D946F22F549BE8014820400000000800200000000000000004001400848000000004C040000000040019F160B444006529E
+:805F8000002887118B418B411A8E116C141B1ACCC81842390853043C62841992481D242584A1492482493244122038228CE98174280210C2111992418A24FC1248421E48622B42A1A28C26F257D824A02823C21126B218921A166342860314811B8423C84A112C7811F42852930D16041748254214C2186722846B211E24F0122349D84257
+:80600000038C51412982C1288F44291B2238888711112C922810489914481C28F4346F24412632241CE421C22829F121128D141847845A18582C282C788134983721BCFB81524521313153681A60324D182AD182741232A445717235126F8621B832348189271322C522436112AE499384F86A1289925826D88252684AE81CA2215F120346
+:8060800000241242128160121F8894121982B181E414F83148816044488148442483542287446110263924122290840084CD1210C828CD829214822069142004421C9412228148F7CD60124002008184210020144111E124688118118845180840922811402204800149013482216012402108B0421844028D82400288A281248F6A0110E8
+:80610000C3116088AD112C81612264112719148124162E02222CE292859141843B249011272136894578322824845223244C13C4112622F148121216022385B11924A82C221E482024868114FC8C3160121418218812161808241112508115123D428091212A5584831438413018181E212C8464834842002021082212182711002321C99E
+:8061800049882388280429242221542C8F1F0124400181B1242CC122412413681400182E828C21429289121424289023254328410A20819217213D242574124192218C0498214823C414A0248D228C0180AC2884F0FC61249902481A9229002B289C11011D14942991244048D24182618245C812816D42CC1901844C841A2105A22A618492
+:806200002214A082482238188140E61AC18867228E148B16872132456A4480F642861028F1284684901818124922444804814A438404602212502141909148891412229111253482207842180842A741200120011624860484005022281A42F4D9461446041065244068282041618200812482888351482004282860211044088304221217
+:80628000426021181200254438480040028242002009004FDF0C1C0485D4121348C8182B122D3C131161928511B8141494CA248B12CB1229314416C12C291208422546A4384E184B4120890487231381B18A2394368C22C41800337188F28422C92911F822121684846322F73130A61222C46623014081142841221108204805894208603F
+:806300004471565182818C0424B02288E222090042440018160880A1482304422E48189088430249F41AEE4002100116029022C02C9022C0182301142C0810C818C02200252882442822C141244042880141108C442201854421246382180048411841DFE2064238322812602140A2282C8182810185432201342448400800A60241445814
+:8063800044412D14482D24704804800481928089181492442141984182588908EFE2068210A81413C12124282A410235D88418482202282120016027420000102802008001A1221008243848C05218004082044200F0F192101281048D228984021011811481524219A4121812C044142140C442888A8481A841841C22028C082A44820848
+:806400002082010000850490A2004C032426F8A3F800121814000000813612088490821002802148AA28842B14A913012081042954222812181880238401301188C0124A01208885A1218A42F1BDCD00143018812481002D312200008C0221B023850A8100001042088114848043816444C9240122884682654800008C420282244221F0E5
+:80648000944A204682068828121289010080218121316138004810019084A021238141A4121218174490422800820040244464288A8402222A21220821825FC60C3088608424130112004351484181A8002012B812844122C441904142A025482004800312250200582CC44180B418842D022981084800284AB8660F268892482811860868
+:806500002C062C0515941129160244408401112741281842881200B04148A1C14215B848A1C2A02128520022604280022144E044A281409412E09B4422E2AAB238F2692813E81269211226B283C22E19311F8D4829FA422316B24372827221A2C781CCD818B166F2424A4B44AF292892144AD488868195121F323413ACE82435DAA02D3E63
+:80658000484E5A8A92168ADC84C8C1258A95181A38421252494491A8FF8C0E4AF483111818BCD18892322B3289E122352187144CE12191189F81919216E3438111A6511AE1A2C6C1004E582F21E284B41C51414B454B854721CAF1242232CD2C2E148021041F220430D825A6A427432225E443E3421D64468542F4CB1D802241E811B41817
+:80660000725312C8422B2116B11EF1222A8E2B70142A62422A8172528971431138420027312AC211B2847AA922BCA2442F41E28491322381B214C2484922B952A1451B354CA51949E524D2C2E22AA2C8C2AED21AA1BB8AF4B23A24000084660242A08420044243E1143214461344116414418511062110624870C8846148228604862C22B9
+:80668000282208E0222821022443C822413014288012047FC448B2E2F22123AF82A2328F2CF463E98F86E626F32A681F33FC6AC826D222E4A1F5CAC89FC2F3C3C66F745517FFC5F4E7A44F54F4C5D87FD7F6C6A6AFA47417D7AAFAC3C3AFCEFEC484CF4DF464E48FC7FFAFA44D475F55B838F89CC48F84A48BCF4CFC3C64EAFA23E36BF6F5
+:806700001F14F1F8DA6F65FD56144F42B316E14AE34E2DF4E4F44F44E18BF954CCFF27036E623F92E782E38347F29311AF87E626F23A783DC13F16EE27D7EED6ECF4CEDE8FF4F493975D344F14F4282B3F3EFA4754DF9CAD773F38F84ECE3F35F12ABA3F37F57A6CCFCCF9F8617AFE48CE6FE9F9A1A23F92DEAAF89C9C8F8EAD13CF44F507
+:80678000DCC46AF273F32F477FC1F1E8EA2F2595326F43F336322F6AFBE2F44F44E1245D468E88DED81F7303F01173BF91F2283816D213F16B3929F53A38173CB75AAF96F412326F65F1868C4E594B8859E251F14A492BAA7B459E9C6E781F3EFA48CAF7F1AFA4F64363EF8363497EC96AF4DC5A3FE5E43DFF1173CFC8F238388F8DAF237B
+:806800008F84F46828CAFCB3732F48F521318FADFF9ADA2BD54F26F71A1CBEB26BEB3AF2C4D42B9A4FCBE984FD5DF7242F28F61B319F93F2793887293F95F57B2B2F22F63A3A373CBF3CF63B3BEFA1F15A12AF2CFD111A5F29F954715E56BFA2F2E7A44F14F581949F96F7C486CFC4F45B1BAF8EF77173EF8BFAD81C4FC7AE27CFAFF7B2DF
+:80688000A65F61F13B33EFEBF3BAB8CFC7F734348F8EFFE8A84AF4F3712B5D1F17F2D8EAAF89F524966F23F13A1E2F2BBBF6FE7434EABFB2F8B48CCED8BF6E0F002A0118A01212221222842001120020A1242004282142A02420842184012A0100410048220000482081228882242408829FEF0F90215081859221225022281411294118CA
+:806900000A2922921210028901C04281201102260824422412248418302CC0121A24041886B84201A5021812889A8448F111E2D022F51124A5F2912487261FC9324A1D24AB141D24AB941B28AB9453B14A3934AF343BA42F147924F84A914F82D418F9244A1CF8264A16F1264A96F1264A875D4D4A9E244D5A1F49D224F49124C5F2912C76
+:8069800083F49124A3F48124AF26F1112CAB9419F24A9251AF747924F84AB443F3429447822D944F82D448F9244A8FB30B29F5116CA5F2112466F2912423D441B24AD1C1B24AF99124AB345B29A74453F94A2653FA4814578AAD147F8AD44AB1A5D548F127C816F5275887196D4A8F5952348F58F2245A96DCB4F49164473217C983729181
+:806A0000BC4AF18124AB161FC1F26A8515F44A33518F747114F848B443F142A445D842D382E444F922527F710320880400000040040011440000001002001008220080080000000040040000000000B0AB01181C1128C2244884112E1858A1481671C8014818382B1224442240388B150844418F149A226314B81428C186D01238221B869D
+:806A800043041058812460298C412681A42144C0446232F08211102198148C01867912E4A102A8821E884229D149C8189348914C8391184568C81742C0428F44C211AB5230182CA2828B24298621836181182F83C828121822181E2A8420C128184638221A32221847142CF24D5940212D81C324872C16DC2132388A71822868435E8191E1
+:806B0000121A68216284472126688847111D88972862B026649C2A7141E282984CA3172477928133812B878C021293022827C3814138424280E262A4611AE6217242011811C1841001160868E0816434844CC8488531218D1412A14144260A488594158361228163022A092C0924846A410C1281C01216C882122C418861832D2412214057
+:806B8000044FE705002428420028004A08891801128822006082812A0484002002902820210285628840040020040040882801411800F01CEC604126041100211181242021042B81C7288741C058412D884314113C2322A02129B848111202424180A12841488C21088C1418128868E400A96462828A024220F47BBA901440122104000079
+:806C00002988415821988C49088C542489384414261C110816028301218C02180022820000400200101228C81280084220F4C43100498284022490218120044E848042E641288201608285E22184A2822022A84221004844288CD128C84C42168C08834428146848CB420027844982C824120018EFC50D224002444AA224810040C848001D
+:806C80002B2129622200A81008841912023400440012001800282200002A08148200488048D8480189F8E12D00240018A140A4420029018991188081618244128E441842100816440840A8491220028C2252828502661804008011089012890112A800E731241004412811800188860820044249080080012004843012812112844100000C
+:806D0000002081312842001002181A02800600C0E1001002304342CC818278884218384883911243E3214208225212C0488503493113A121852448040089012598282082220488242008122B41182A64811A088177E730224424444B128C22024200124212A04229082841984318880422811008803158181222208202B022E181140C8002
+:806D80000213112881028182702408829FFA01000000002100204408825084244D484018480800003018218280021008220086988810688840180800000040F845FE00490243410C2189218128098180281138428904848240425884244284848002202102702218381886083088001200228B818C388C10C48882F0D35E00268424110CB1
+:806E0000408A01186084842008678442418486480225D84848028410280200404808228921988830880018810088814908418840F83F7E50888B444A1404108201824D8445B424A222A21281107842481252A28B111AA1898A8804811231887038C8288B444AB44A1208849088504C4D8C4B222A322828838118082484881AF1FE170000E5
+:806E8000400200812008002008000084100400442100000024001800182200844008884008000000A30381841A8404440048C044414C228202401808822490121218888C08001419410181AC6424480081004014C424268802100820582290121FA90D84424A2401200100409488282D8800008100254898148008000086018184124800D9
+:806F000000008048248802880012001002BF3306800400120000448002000018002180018884000014008480240100001048148802840000002180F1137C00120000000000100800001008008100400400000000001200008880084881000000004F790C8931482005000088457484B424223222004484400245A2111A329460881008110A
+:806F8000111181B048242404000083584449B824A22622128484002C4842A2115F8C0150881A840400008048D844A8242800840050822512061E98888841004041018487811A8414020000405448842E28000000504225F4AF530040048001000040488884118A088100104888020000000021001A880200810000000088200200F07CC180
+:80700000000000200100000084000090881008410044000082001280180280010081000084000000004D1A00E04101A011128084A84889D888285482004187818189088184430281414100A09840022112238802160881A08850888190188100800841F0CDDC2021010080010000820018A18C088484814181C42608C42544080000121800
+:8070800025C21220012200848488848784008C080000412B7D00001A41120440088800853AC882100820484858448141100800000020A118120018008D8881888242828648182821220800EF73096F22F212222E122B11122B11C0122592821E111F11B188E999F848888F18F4484842151981548985B844E444F424444B244F4222E24253
+:8071000002286554442E246F22F212222AB192A1812B99822C5122881E1B1F11A1989E898F84B888E48424E48404488558884F84F47777F0262265A2121A211102502229C8133B1119EC89F818888F18A44C4246591148848588F6484C45B444A222224400444584F226222D822AA1131AB8822828582229C8111B1119EC89F818888B487A
+:80718000CA240480445C884877DC00000000000028220000008022020000000000000000000000000000000000002FF7030000000000802202002222220000000000000042422084A4444A2404004242000000000000F0ECE6000000222822008022822202222002000000004800482004A0440000A0440020040000000000F08EA80000B3
+:80720000802202000028A02200000022220000002004A04400480000A044000042000000000000DF110200000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF70300000000008022020000002822000000000000000040
+:8072800000000000000000000000F0723F00000000000000002200008002000080A4444800004200008084248404000000000000F07DFE00000000000028220000008022020000000000000000000000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F00000000000028224C
+:807300000000008022020000000000000000000000000000000000002FF7030000000000802202000000280000000000000000202424040000000000000000B0A90300000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002F
+:807380002FF70300000000008022020000002822000000000000000000000000000000000000F0723F0000000000002822000000800200000000000000004242420000000000000000009B3A00000000000028220000008022020000000000000000000000000000000000002FF70300000000008022020000002822000000000000000069
+:8074000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF7030000000000802202000000280000000000000000202424040000000000000000B0A90300000000008022020000002822000000000000000000000000000000000000F0723F0000000000002822000000E7
+:807480008022020000000000000000000000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F0000000000002822000000800200000000000000004242420000000000000000009B3A00000000000028220000008022020000000000000000000000000000000000002FF703B2
+:8075000000000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF7030000000000802202000000280000000000000000202424040000000000000000B0A903000000000080220200000028220000000000000000000000E3
+:8075800000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F0000000000002822000000800200000000000000004242420000000000000000009B3A0000000000002822000000802202EF
+:807600000000000000000000000000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF7030000000000802202000000280000000000000000202424040000000000000000B0A903000000A7
+:8076800000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000008002000000000000000042424200000000C3
+:8077000000000000009B3A00000000000028220000008022020000000000000000000000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF7030000000000802202000000280000000000AB
+:80778000000000202424040000000000000000B0A90300000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F0000000000002864
+:8078000022000000800200000000000000004242420000000000000000009B3A00000000000028220000008022020000000000000000000000000000000000002FF70300000020020028222200220020020000002004200400A044484800202404000000000000B02D0C0000282220020020022228222002A0220000000000A044004200EF
+:8078800000A044480042000000000000CF5D0500002822000080022A02002002220000000042004A04800400004A040000000000000000F75D00000000000028220000008022020000000000000000000000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F00000000000051
+:8079000028220000008022020000000000000000000000000000000000002FF7030000002A022828000028000000220000004848480020044200004248800442000000000000DF930F00000000008022020000002822000000000000000000000000000000000000F0723F000000000000282200000080220200000000000000000000009E
+:80798000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F0000000000002822000000800200000000000000004242420000000000000000009B3A00000000000028220000008022020000000000000000000000000000000000002FF703000000000080220200000028220063
+:807A00000000000000000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF7030000000000800200220000000000000000004242424A848404004200000000000000F0C13D00000000000028220000008022020000000000000000000000000000000000002FF7030047
+:807A8000000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF7030000000000802202000000280000000000000000202424040000000000000000B0A903000000000080220200000028220000000000000000000000005E
+:807B0000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F000000200200000000000020220200004848480020040000A0444800000000000000003FBB0F0000000000802202000000285B
+:807B800022000000000000000000000000000000000000F0723F0000000000002822000000800200000000000000004242420000000000000000009B3A000080220222000022282220022022020000000000A04400420000A0440020040000000000F089B20000802202000028A022000000200200000042004A04800400004A0400200434
+:807C00000000000000F0353100000000000028220000008022020000000000000000000000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000222082020000000000000000424242000042000000000000F0CF9700000020020000288082020000222A
+:807C8000000000000048484A044A0400A044488004420000000000002F760900000000008022020000002822000000000000000000000000000000000000F0723F0000000000002822000000800200000000000000004242420000000000000000009B3A00000022282200802282220222202202220000004800482004A0440000A044000A
+:807D000020040000000000D0BE0100002822000080022A02000020020000002004A04400480000A0440000000000000000B0D70600000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF703000000002022820200000009
+:807D8000800200000020242404002004000020240442000000000000CF6A0B000080020000A0228002000020020000000000484800000042484800420000000000006F33010000002002002222200222008002000000484A84044200000000004200420000000000005B9D00000022280000288022020000000000000000802404000000B2
+:807E0000484200000000000000F0FFF1000080220222002200282228000028220000000000A044002004004842802404000000000000AE7E000080220200000022222822222222222A22020000202424A444000000004248202424040000000000F0292200000000000028222002222222222A222202000000000000000020042024240411
+:807E80000000000000F017D6000000002200208202A02222000000000080A444482004000000004842484A24040000000000F01ADD000000282A020000280022000080220200000000A044424A24240400484AA4444AA444000000000000F0D46B00000028220000008002000000220000004242A044484848000020842484240400000081
+:807F00000000007FB7080000000000802202000000280000000000000000202424040000000000000000B0A90300000028008002222800000000000000480048000048000080240448000000000000F01B3A00008022820200802282228202800200000000000048428024040080240400000000000000F044160000000000002228280026
+:807F8000000080220200000000424800A04442A0440000000000000000006FD30700000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000008022020000000000000000000000000000000000002FF70300000000008002000000800200000020242404000000000042202404000060
+:80800000000000F05C12000000800200002082020000220000008004800420044A04002084044848420000000000002B6700000000000028220000008022020000000000000000000000000000000000002FF7030000000000800200200200282222000000424242000000420042000042000000000000BF720F0000282220020020022231
+:8080800020020028220000000000A0440042000020040042000000000000EF5B0700002822000080022A02000020220200000042004A04800400004A0400000000000000008FF40100000000008022020000002822000000000000000000000000000000000000F0723F000000000000282200000080220200000000000000000000000098
+:808100000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F0000000000002822000000800200000000000000004242420000000000000000009B3A0000000022002002208222028002280000004848480020240448004800424248000000000000F0D7D9000000222082022828FA
+:8081800028208222020080020000800400004242000000484A2404000000000000F09141000080228222020020822282220200220000000000004A8404420000A0444800000000000000F0F3D50000802202000028A022200200000000000042004A04800400004A0400000000000000002B3B000000000000282200000080220200000059
+:808200000000000000000000000000000000002FF70300000000008022020000002822000000000000000000000000000000000000F0723F00000000000028220000202282020000000000000000424242000000000000000000EF9B09000000282200002280020000200200008004800420044A04404474449444444C5444430444444503
+:80828000440450444100F0E26C00000000000028220000008022020000000000000000004554444144450440445444414544440400F019F60000000000002822000000802202000000000000000040544441450400004400451454444100F08B57000000000000A022000000802202000080040000004800444554444054444514044445B4
+:808300001444445444451404003F1C0E0000000000802202000000280000000000000000206444474441400445140444455444445044414100D0DF0700000020020028000000002800000000000042200400444514344444474445140444451414544441450400F09843000000002A02808282020022008022020000800400200442420076
+:808380005044453444444143140444444544444454444100F05FF1000000282A0200800280220200800200000000004842000000444D44457444D44454440040544400411004002F790F000000000000000000002A022200000042004A2484840448424014544447444C0442004410445444440000BDEE00464848088C840130142921482D
+:8084000004882C0644126824002301822198218981188C2802401842C8488C8424030060420068C0644448428420F9167D20A4211848C945D468F4144846A4844420514826167C24F24832262EF922988AB148C9886728124D12F08812828CA1388147A8C30222812CA481B0A861846872281AA218436842C14C92182A81CBB8929A14F8D3
+:80848000318100841248126021200449014034840028326E828728A0412444002C88013088008504400821800A281200A21004200282588818F079F22084032024143C18448E1620881108460A46480E288284848061418028889924814D2228C02200D884121800A01218829048448D442064828448846FF4098004814184480048004122
+:80850000006160618001C082188288211881210010081008428448428982248402440020228101881888F0D8A50010088441604400000022284D2200208101822400219018841288820000810084488002004428490230243800A0815FE408000000000000004022080000000000800100000000000042800100000012484400B0B5081213
+:808580000016F41148422210282484C18149140843782102C48908402242184CA4C2128748245028A2CAA2212013C118005441101248048484283024288004DB61400426840245B81264C1B01498988158808408D02424D242A4419241004A9111A12223C228424A8101219B2988288200888181841860882012A21890488B128E18484FF7
+:8086000027051220C2241F8144A842C311684C8C4CC8C1496484824C38216934242FC48884482642381455A2C2224DA828218D421AAA861AB288032008D014184C588283413488818D22228A4184C6388A84F4842410044112C044290120812181010000248420810100838411C812402884012440A1292661810000000000002012088954
+:8086800001CFA70C22122144400812000042000012201302442410442422440824002822824B121A6222860884211110210442C0220012608842F042FD905614229962123F628164821A741814225138152851C1413C6282B041E215725148D18132291115C2143C9528D22A2C8191841E21248581E43126A28130CC8112118929A1A186C0
+:80870000384849CA488D444A8128F4F37BD04242210226420816281108128503400C2C42A82129226684154248091382648428524A288122A21A642226F21842909821CD416011108821C82881A28311C818008F48075218219D24141E25298422C4160042941811411921021CC41116051CC22415446241172184882302184918816391F1
+:8087800042132A022048084621298483384244484C242C8CF423C37012D424E261668258255C2C1D2481129E2844890252A4C220481858488441424B94830680C6E1157448263268C622041681014280278283D248914162842E8418691114B84CC242818DF5502880840180024810041880220110484484222144844911081221111284B3
+:808800008120042200184C0181488144122A08800220081E22F062768004810000168841081609C884008C22A31216A14180883222A021294888C1620041181200488604130242800100284244800200442F3F44E24451261E2C1688119E2863831528781198186084182384226B428D14CB248C81C8642F44D2813438882CB511CA6456FF
+:808880006C824C863112C031424308417826A842181246813828901423813288682885F4FD1C002824284210548181128B12008A844188481868811423119244002824608242241002C80080014AB1110248188C122821044EA422444150844A011F7104400412102692421812162831148321226181C02132162B3111408242224822D46D
+:808900002195442C81C152182C81C122184608800400421E88A021800128301400CF67054B142126982E902816941424823042604C21C1233482604449821452421420018412004444114B281902004C61A11124818009441840C4848CA114CC9988418D24CFC60B000082184D281A0212100221842190221240840152001121180018806D
+:80898000318400411304130480521489848801006082811881209642BFF20BA02121428120180828401688221108242014028A041082A848242AC84C212CD241022914A4414321C4225241212E12184A9124184244529842C42082019F730A4400404689042820C4426883014901A41924810810088C0219014449010030114800100221C0
+:808A000025028A0182A0484443088A04208828F679B4002822160836040068008082026117422A01688181108834288112996112C185817444618228682E1927D1430214156C3211C058008484622828413012822FDA4A8232146C04129018298404818C0868418880010048904241800800000010448684288A1986060000861424AE43B1
+:808A80004441421A884348F4FF1F80048440084088511412301820011212107252029A0400221641C124C011490189239418844344044810440400488488000050422A04E799D082024964421200262402400449524840085084801812C414A081480022E81CC2888284B02404AA044332442081C22480C2144820C434C44018CA88BFFEE0
+:808B0000056F46F12624F06E148D1A444FA3F12C445AE24C4208D04404C145E81293214D263D448E48CE484D148429E28371922151924F52725368C225F881C22BC447242371DCB4EBB5A264C45556285532124AB14CD28445B49C7248B454D348D1C8D128D9C8E325FA4C483F234582A4118D281A22B139C3242361227018F21882228F31
+:808B8000A8312816D62A7414622316B824B812918142C04815C2D8144C7311EA42D42491C48D155743DC13B42155444F657326825647DCA342881A6149C964444B422E844F8496444789C0544CFA95AD804272244648548683E48483B131A1142B44AFC531524FC1D382A911A3F842114AF55832421E122D4855268232418D1243AF5449CC
+:808C0000A9211F41B3548223F328343CA2A1941A75428136321D989A828CA8952AAC918B483AA827444B8B8782A27743004120026B12482190824888488812888098412880024224C01240A22855224802260324C081400234408304822008822098280082F0B6DC246F66F4161E65F62674CF42F21D1765F66E242B667F5CF79E1829B5FF
+:808C80008AF8C414CF29D12AF19E9E57783F38F22C3C4FCBFB28387AFB4E4E45F66A6A2B669FB5E4ACFC6F6F7F15FF18AEBE36AFE5FDDA545F35F4541AA7A11F71FE5BAD8F4DEA44F66266F5FD8E863F16A74685B8485C884BA2CFC5F464448F46F4ACE84F82F32C3CCF8AF788ECBF3E45F266466FE77526FE266CCF62721F771EFC343695
+:808D00007AF79735AFC9A1988F48FA9414CF69F19696EFE9F986363F39F33C5C4FEBF97A788F87FB5C5CE5F868EAAFA4F55BD92F9DFDDCCEFFF5FD1AFDEFCBF37CFEFFFDF557552F83F53C18FFD1FA482CCF4DCE641F5256BDDF7BFA7775FAF4383C8B448F81714C7C5CFCB81C8FC5F5FCE8CF82D3CEF23C788FC9BF1A41B236F61454CF92
+:808D8000E1F13E362FA3F23727CF85F64C345E525F75ED45B1C2EC24F65696EF41F19C966F61F136962BE6CFC7F3B4B8AF89A599CFC455448F867C32F24B491E18CFCBFB5676EFDFE74BF358C86FEFF7F6B44F43F71C3A4F69FADE8CCF4EEE24F62264EFE2F2AEB42F42A3928F88BB18FD98984F46FFDCDC4F46FCF8DC8F8EFE9898EFC277
+:808E0000FAA4AC8FC2FBB687246F63F63E76AFE1F17E36EFC3F33D25EFE7F676747E725F71FB58588F84B4CCFC54D4CFE1F1161EEFE9F92EBE3F17FF7C7C4FCBFBDA588F8DF94C5CC5FE6A4A8F83F1C9599E9BEFE3F35D7DCFCBF7BC3EEFE7FFB53D9AEB23F33E38FFD9FB483CCF69BE46F62565C5FEAFB76AA7CFCF89BB8CFD8898CFCE3C
+:808E8000FFFCFCCFCEFFC8FC8F8FFE9C98CFC9FB9CBCCFCEFFCCE58001188441844008001224008444802201200400420020342410242402430249014B124824122212A04100281A842241244104BDF750242847229014284B14286A014E121242846C214112A114D048A2488901852432181924712158482A311820C81112406816842568
+:808F00008252148C6214A08484884D4888844A48C8242688C849BE8CD024F4112487221F41326C1F41B24AD141B24AD141B24A9921AB9453B14A3924AF14B925F4429157822DB15F82E414F9254A1CF8254A16F1245A96F1254A9E25ACE449C24A1F49C2431F4952381F497248F39124A7341FC8F24A131D64AF14D981B64A19B54A39247C
+:808F8000AB9443B24A792498B24F8284F9244A4FE50E65FA116487221741C356418F14D141B24C91214E951D2CABB453B14A38242F14F921482F647985D812F327481CF925581CF925C816F124589651859AC2499E2526E8C9D214B49156181E2487341F41E234E8C8F248138E248D151D24ABB419F24A9443B34A3824AF44798498326F56
+:809000008294924FA2F53E88404A04000000400100000000002100800800002100000000840000000000000000F0C6173024105628109824108981220144C28C324981C1C05C1E21C9C62A008D12D02A61132C02184327012048692216184C0A00AC41489842458804C3342885644C80F2928E4011054C11889112844C8192484A823188DB
+:8090800053C1121A280213318142180081205214D084C4228942D2146426121228C22213B2252841D1120498C819A1282E928B483AC842A2843695445F790E1564442187218487211E24301870248826C38C4CE5A2F1815883420447B976B144313860888C81921E2F12312C112B2143162E34428A5181628353945F8802144944B2281885
+:8091000008C3AA2446C8582E48CF22C8482AB114A6F82012114404008445A1214212001C080081132104894202002114203422811813252201282C0822901250121688A1482F14012C29C8A410328444707B0600490118400249A14120081D4844C0121388012921084881003D485022852172580440022521611200131104180013292401
+:8091800001C09422608288F0F2E6242A24312212A3FA2354296981A5F12788A992432361482D185B49418C5118218D641B148450165C942326B4157274C1162022F822124382C2164D221A6483224F2AA41288392C3F11241CC1884B618D8262528E2418682CF81BCD2422244B12B01A5A238225D894F112228332831888601150121012DE
+:80920000A618845052172434542E124D61B46083822721412C024D1219A712224B482564281B1818111118124351284B82206283A888F79E14421880014B34122C01CF1408482147B4C9E148341489D981018B164601488144282E4854126321324480221272149122400819A32120A42C189227148C282688A5164C0842F0B53D0043013B
+:809280001D18528044C4114C318143C18814988911B488048C82423814C024844D48C82D9885548215048A32881CE444614289011601411662241442704AA14289A841448448AC29149428DFEE094A41686428442226082E8400C4909849C2868C45064125820BA480012E8448122EC111266281151824348880614220B121C42486B28CF7
+:809300000260822220048110A618488FC40820322841248149911A8A0432004C54812182188381B14C0180240811188002224820263822800821269C22828B81008880014D8880832B028344B447054AE1428162111E4683F2384643E145C2148A136888CD815B18E9D882C1C6702498428BA144462A18C84C1A8241EE96684222B21338DB
+:80938000411AD2484888713235281896A28386B1A22488A44189AAC1A0128B5A8143348C2E448FAB0800C5C22C004048011412A04181124E84169818128D349012C03440D12434C82A012054824AD2244824220950244C6216CC14424C5281815048491408B8A014849DED20A2484C5224425800122286A84280441A988820942182411DFA
+:809400004419529215828212081528988C82001342611484894318981112421480411808002AA48200821FAF05441424852152522442448D1148807512B1446142100221641400450245227814924886128412523894244006104106269688242CD858088846A8821840488401EFCF01249604188C028150848D14120000B02264224094CB
+:80948000412611D281C424441120422182046841100C3800422A213441128624112844840282844CC1684866F25ADEA061288B212880D262741C021002A143142684914A40594242444146B228642164512C02842187284AC24A242420441544011024B32884B41228B28201234424042642F836E30022A412421A044800282240081A3282
+:809500004200100113069130212A190893D881328812220013D212943126088C8262185C0A1882608A85648B8883218281E811F4426FC048008483418802A442244608008211108114281608888F1982282408E0454861241A68119044838304480010D841442981058064C388802881F2AEB9001414344718866515441814141048455180
+:80958000126011624B211028D1848291448341951138122428618086420860541D226485721862242C2218412281418284A4184484F0E7BB20319C1241408282A22449924800801134142E412246A24A412848628044018123024B41478183447848044414524142E046A821521441885694244B14C4414CB4886624846FE103848024427C
+:809600006482442C41622424E4428C324A192408800810828101888582420128142845618211688481302813210514CC188412088A140888207122084FA141A1322F88B22D1112915471A395181E12312F2414CA481D4C4F14F212198D3146D144B2C4A4424AE687D643E298F4413C1F22C6254E288AEA8EF4C8242F2465881A564D50483F
+:809680009B44CCB468F6234842AF5657182B228E3D45B5C8D482AC984B444A8822A9141E8123F2A213A0441F4B01DFC3F2A86E1FC3A8674C7422786BD488C228AC7419E424E1226D2C19E422F6495135045742D18B86FB221227818B1A271313F2128667229AF879212125D9136211218B1554CF11B112A6893DCC8EC9B9F851921A71988F
+:80970000F2742C3E926FCBF5C8884AF414AC8D288E686FC40543D114E4A1C21363F54823E44D3247654D69DE4283227544331E35EC427C6202A6C2A97FD4C219544D4B567422F38485778195721A992D1E88CFC2D2467461E1267228F667781E295F1252856CD21851254B3F1F25E1217488C8884F4293488F8812D844F52CB48B4A6E52ED
+:8097800083F58D9800001880490800004044081508111880010042000018002022140400410000000010022902000042FF4E0B4F41F615259791DD455778DF74F61F1FED2A6F64F48FBF3FBCED24F44A465F75F41E3AE784AFA5F1381A24FEB2AF93FB2829CF97B374F4A2C96FEAF47C5F4F62FC9794A5FB5251AD8A25F26A8AFF59FD332B
+:80980000716F56722EFE2368B55888CFA4F47E6BEFE5F54BC95D823D6AAF6EF459D9FFF8F86A6AEF8AD264B98EFC5158C78889F4D4DC26F8FF14D044F6D56595F32D275FF7F1256F7F75F716662725BF7CFB8F9FAFA2F22A26D771FFF5F76E293F3DFD22433F35F5A5A6FFB27A22F17C1DFFE7F5A383FFC2F97D5DDFE2F697B82FB1F3426B
+:80988000697FFAFA921A2FA5F88F8D3F33F32767F5FE3734BF87F72928CFE4F45A45CD1E2F22F7F6D44EFA2F2BDB11D8DFF8EC7CCB5DCD96EF43FB59FC8FC9BB2AFF74FC2F83F513AA141F11F43145DFB1B21ED375F24B67FFF5D5EEF7567CFD2FAFE2F22A622D227D57FFF5F5662FBFFEFA7A1BBFB4F4EEAFEF9AF87E7C5F16D674F382BF
+:809900008B6F92FC4C4D4F62F4B696AFA3F3F353AFB4FE2266AFAEFAB2BB7F73F72667A5FB232BA5F82C2C8FA5F34A6AAFA7F3EAAAAFE8DAABFECBE28F85FCDB898F86F4AC8E6F43BB94ED83F9BC98EFC3F4F4DCEEDA6F6846F111611F5BF61C28DF91F35DFFEFE9F35F7FED7E5E3ABF35F35B5FAFA6F246627F74F17F5F4FF7F3D99FA7C9
+:80998000B6BFB7F5BFBFFF9AFC7775D5FF293F3F3AF83F29DFD5F73C5E6FEBF9333B3FBFF5C6EF2FCBF7F2AA7F3AFA37377D27F5FF37373D49CFC2F27C3EAFE6D6AAF1A2E2AFEEDEABFACBE28F8DFDDB9B6FCEFE8CC6EF4BFBB4B4CFC7FFBCFCCFC3FF54D68FAABD770F2A014941D8224178244238241E48228424008C44C24828C024B089
+:809A000048024C12F24824290121422B824261501670244188C148454158148C048A4421494548A44928488524394882BFCE0D406412D014A121460118118810180543880342D048884404C04880C42126084D484AC2984CC2434C2202D0C122C4242F327181A4948CB24A216844B0489B44A8268899444C029FA3012CF41124A5F2112408
+:809A80008B141F41B24AD1C1B24AD141B24AB911B24A19F54A944782AF147924F8429147822D914F82C4914FA2F448814FA264114FA274D8E1A27498C54A8F49E2A2F4D1244D421F4952281F49324C1F49324A1F48B24AD141B24A9921AF2419F54A9243F24A9247822BB4478229F924484AF9244A9F9F063CF41164AD421D248D121D642B
+:809B00004AD141F24A121D24AD161F41D62ABA11E66438252F3439254E935782987F8294925F8215B82728F1264887593B1283D832F598252A7481D482B59116EA49726EF18124AB141F48B24AD141F24A9419F24AB259F2489243E22459844A7B2498B26F82B442F9241A230F2088040000000000004420010021008008000014008400BE
+:809B80000000000000000000005012F011A6E021244338121221182440042C618B000080922283289258440041218111A1418118003228478180028483220815D881CC914884781230128A91241E24228E5200822082B62844484828023528F4118817858D2455C84C155C841D44C3146412914D28948346342C19A2256283641518141226
+:809C00001421A7118301495116D6C8321038914B12948CA6C38C2222659843F41DE3E021A43C84181A22028420522415B228E8189158CC12119C21678217A8B0143414914F88523C89165C411D2817438C66858521E1948363915018001E2C5CF884488D21A71E8E198A61821CB21822783288AA244F127172F4A9CF00408262248C9418B8
+:809C8000104A0416A8148414504848850446F424488113020000260A480052004054221A92188424802101601443B14881A4348031148908EF8A0C008280080088000000000000000000000000000000000000000010010011400170E705212811115C914C6E2250442F84A41170284598842502482AE118586184288B414524CE23850A5F
+:809D000023011B488051482A2A951344491868184A12D4E36212488941B842CA424B112220C2A689E88131849F3246922210817118E84EC2410047C12B32488543889A424316E6680914A0318E484C7844D1215298221B45B09601858CA2C690139AC484CB2654104498222AD418C18C8AD226A417218E8641228F810BC2BBFB0020082063
+:809D80000880080000000000000000000000000000000000000000110010011400FFF402219018B022018B1248232441018150484F8154621128B04A4198280011548C441462140024282C81B2224148014A81120883846414004880A4340082288E48EBE2206213C021F06318B01962238E492351281229C94114228B4812844D21141646
+:809E0000541C2D24C1421622B63DE421386C386B148E42284062223E482E142223247B818A88C118828B144F88D248B2140AAC22048B18289FF54222A212830112B9B4289111214814103282518D1128A5A121815B4194C15440018C41E615E234280229E42826D22282C1221D68281A2222C181230800424B28844A2332284240A848FF5C
+:809E8000140E400126912232B048E2253299294198181889C44425840C2483021A42782244CC452C845684124D4832160612602281124C219442834A384858932568818C342443A8142480883B282FA80E1815082A415284C3322412418B12125518C812184911012614911489A241E0442218E112618181148E44A041E084911810F421F5
+:809F000088008840614624800444182021588212842FD108428CB1491281014001204898148A042A08260C812129184492841628082B48C0814681025160C4222880012C31414428114C843A142282208302231564242FCA04132202604414008314081902105828C8100180C2110000002003A018A042405414812022C228202121C94425
+:809F8000F04218608684200100BFAC0A19A7211D281CC356857128644248C4835A188CA1488CF12A824C54C1148D2425C114C34282B84802148691181E89424B82821985C2144D184551488F180326220A2E115AA2944C38142F8291848CB32821829948497148F22FB90011004004118901181A4241081298220020DA1281441404245AAE
+:80A0000002282084418404222800221287144410418226840448200112008FF209641094164800812218461A01215818808124292982210220213811116021701822410220113284960814800441430124482A2108826604A6F4AE8140810128B01284228481C8A18114888C1882A3424142002100846621022A042841001594888D824C5C
+:80A08000023021411849022E1442004888008B4B800884BFFA4A1114110C8121A4814682048C66848424228942082127223022C46432004112471180830420024225C412A04321968228B1A4011A088961298D1480118809DED160148D24004C62824828896212184418410042499C942604004641318422424041120120D282941468804C
+:80A100000452111D64804104B023440444688825022384FCB5C520286421801191481830188324129843851448341270A1082A05211146044B8526111201A248802461210080928140A118828B148A81054280444428144471A843E184026815024818422002211888181C04004882601142221114298225222A02008C0219041E612004A9
+:80A180004830284C0410E842082008A21A08123FAD0B8C81121818084443129481141814160410482408424004005211004248000086820CA024824022D443041419022B4118005842C0B8485F2B0E1818188383342C4512C14A4304524483016870210844504840111442521824422400408CA1240040044812001C3A228088018AC23849
+:80A20000228CD184418AF2C26640188446222281812141285841C24A221C8C2D98422086312249A21226812801162847781205128C021AA6258D2482B0145228B8284482A8342C2808102826B22644F8B363E014F4C23149D1297162B4117238548A5E1493F8894A1E388D4C3B1148814F86E5CC2CBCC4245C82144A12B112C472AE89141E
+:80A280001817152D631281164261A98AB854B61684C3285F71C6421723CB1B19BA11DB21F1A881CA01AEA61A69ADC8436E5426FC1E5AD041711C6443008F46F5445A5A85F422CC1CB82A84D98CDCA4F1242189921E482782224B333E22C5D134F22C21121B1543B323A63826B82602A5A4166B943E3A27221302422AF1181529AB24EAF10E
+:80A300002844A0512B822DC8184F8A86B8C892A84F823C8ABF6B47B11422D2A8F236288FA15682F021248FA2E2152377417151634C8B8D2F85A4811B236F41E871AAE14849F1214426D441786191661D5256F92442188E144AA51249A62211188F44F2C486BED1C21B24439CC31263EC497841F21446DA213148CB723E182FC1B598E32539
+:80A38000FE71CC140000486110461866882541182258124825214825490540022440220440224432411001118848206122488044012C82040000001F294F31514F42E362F22B654E42BF3472427663F318127DB7BFA8FD2333BFACFC4797EF6CDC3BF1F6D6AF36FBE3B3BFB7F9D6D6CFC4F671713F53F2426237187F75F56AEA2F33F37AFE
+:80A40000782F29FF5A4A6F4FED23F27F773743EE8E3F3AF23153A5B8F1EC1DF6C5C58F84D522F8D9D92CF24B491E818F89FC46962B224AA5CECD449AD9CC2DF21842AF95061F15A4548723BF12F25C16BF1557EA3732AF24F5DFB5FF75F96331AF7EFFC3D16F64FF6634FFDFE93FFFF3F3AFADFD17D7AF86F661712D372F64F623B36F77FB
+:80A48000F66A6A4F75F54A7B2F3D7F5BFBF6D43AF2757D1F63F2A3F5AEA23F33F35B791B3BDEF15F48F94D5E7F7EFFCBCD1F3FF7EB799E918FBDD964B5A2FBE4C44F4BFDA4A4EADD46E58AE9A3F11E613427752F637722FE391D4E4ABF91F45A76BF92F2185A7FD9F5BBDF3B13BFBCFED755EFECBC32F3DEDC9F6BFFD7D6EFEAF1E6F4FF37
+:80A50000D4A6135F56F745637F52FA5577AFA4E435F57E7C7F79FF5A794F69BB12F1141D3E159ED66F6BFB1717BF91B1B1E915FDF5A59FB5F5C2C2BFDFED24FEDBF95F5CFCCD9E6F43BF9288EB8BFD1C9C8F89FB76F89AD86CFFFFBD347F77F63676E7E3FFD3F33E7EFFD7F65C76FFF7F67C76FF5FFBF953AF97F5DDF3FFDDFDFC5EFFD7FA
+:80A58000F79CDC5F47FFD5D4DFDEFFA474FFD7F634165F56F667677F53F27737AF96F75457EFF3F3F6F7AF97F3B4B62B114F71F132372F49FBB5A76F61F15E7C1F47EF1FFFA5B5DFD6F7E7F79F9BF971F3BF9CFFC5C5DFF9FD76369AF924A44FCBF974BC8F8AFB747C8FCFFF6CFCBF85062601430229012284E08824C248148A04844088F9
+:80A60000A24828112880126144A024A024220020028830248028613292229A442149820412809428C024D0710543081820A42142129021001816082A6414823CA24146054A0146352112408444812424128134112612314411224842114A084280A848A04A8182809488AE417F2B0B3CF4112485F3112483F49164A3D441B24AF1812CABA1
+:80A68000941D28AF147985B84A3924AF14B9A4F44291478B2D954F82D418F9244A8D814FA264114FA2641D2E4A96D5A4F4D8242D4A1F4DD226F49124A5F2912C87241F49F24E821FC9F66E121D24AB9419F64A9259F44A9243F24A964F82F44296478229F92448984FA2F43765D032F41164AD431E2C85F11168A71419F242111B21AF44C8
+:80A70000D981F24AB18CD21AA943AD974B438F5429D31AB822D41AF9245A8D914F227C18F1254A83F8241A87594D5B8F11D2A6F1912C6D1A1B69E5F2912C4E121FC9F244121F8872445281AD961D2C8DB255F8429736D8626B824E9647834CF9364829F9245A7FCA0900000000200800280000004410420110080000250100000000004025
+:80A780004104001800000000FFC9021D464511911CBB14584D281393111524420843548123046816F1144389521422D14011043622F418444362854314842A3214C4004D228143D18101A9244118846441410044CA2266421F2E01219A528228283041EC84C4621EC8129311B114443348A968CC214CA4128E5422A312384A146D41433126
+:80A80000239022302218211D22288A72580413B64A029A622319D84188E5882312F884488A3128418601DF6A091D44274784367441A841D9D468237121B42415F82118444F84119242A9F21C834F24C14245A1342F4132228659C2112F35C2543D7415D48222D44A022B24288584C8146C322987471981326A2F52D1480828494264CC1287
+:80A88000266242C2324EAF10125112842B122092414681948A129041141914A84842118D24324C58818120044410282215042A094D1328228C04482184981288114E149E4818842058488A8412743A0A00001468421698128C8401885018848849042004442014942843028C012C012A014382021218CC9212280018C012402388E18294EC
+:80A900001886088043F8AF3FE01431129C51424344483121481721704138191E441E4443941C60848F44C11D87448361822D2946581689D141E424C2399018A12743522971110A2628E192344A8D1283C24A4E18A96CA98C94482698924CA21276B4282428F2EC2A3011189C11541481108141818164814C511C4664C142844F847111DCEE
+:80A98000844438289C8454424D2841AC658100258AC25622858111D828E2946286AC11384812D678827848A18487218C4BEC8298648023F238DBC0420021426213743882E4811412398142528182414820044C012952488D21181C249221182D182AC114221812211A32142C012062218724805122812242381212832618D84649924144CD
+:80AA00006346D484283244141C25A2284190112902837444024C21911E8B421242150822588447120088821412488143041891CC442288232181021B1212428D1440C234F075F4C0187048518242164828C1288B149484478181DC83180412D08214321444C12E124841844904471189058420B211840100412860419314C221486F2228AF
+:80AA800008842284C50283F41DC580220213224925120820410100200100144210C821416024001A9428228721484A010012288222100A208868C1811CE484A221421A8808F03C7C904122ED228D21833431468C3131588B129180D114018741411212AD41CB14C912F82548976250248C111895282A748822CC41181C61814B4122981D15
+:80AB000028EC428A39188A611189F12E82688B348C741824499424486FF5012F8A4144419414C4221538488CC281901815182A2884141284014A110420A4424249A4254931181880810200004442001D64218246049880A34281868841F848FB40141461149058008C041800202142091024019490288001001442280012000012C0222C99
+:80AB8000C4980084102412120200806882EF7707112128211502284224C1421881164452244441662241D818742244048004C0413011161804284845021281124008D042020016244824488448A412447772601C134101123048008B4310210480A134584C4188041A84028142C1488095281028011A02608122840022C66A4C4141008402
+:80AC00000022212240E2B803219048B0480229119933102232161E4246024082820214D028042D42C05249512870120217215022810000218112186941A218C08A20221242480480F42D159014204121240642482283841111088384148891148458144249021250811E410000808181012021428242A82818828890A8238838A88880085A
+:80AC8000D058490180445882810016182121043048400800100829020000000040C82828A01424208141B882921A6C82014C08812260822A283362824F46044256322C43410128691114248292124444109222272484C0241614840440012228441400C424101A8652262210044088410830122414830120F4D1FE00C7180088188001182B
+:80AD00003041450822841B124781002325210442004638480083A612200184810060221828C04482C08610822238222502821E8189F25B27C018A0412212824A3121202442C4438D624CA134244241280021C0144888696141A1460114212884A041282502001200460428D0480850488826921825A4188FF54CB21574D3E682D25AE43880
+:80AD8000A6943E181F55F55864224A93111487854D168F46F1484EA7214C13B442744CB151E74422A444A0414B4587841D414A013185028FA2662181442FA1A22136C2422B215ABC82F388888A48E6E23A882F627982F22285282EAC1E158E24ADC31414829D14196285162894222CF1511C20E664D52481E2A144F1444C6B432D288CC160
+:80AE0000484181C904D08451D82B4246E241B42813A4113A02185682817122942A2781AE9287684A381641E183A8A2824C7888D22689E1126AA77F9F0A4E144D1916612199D12886562815D82CB638E431761FC844AB4529B233A31246F2381483B13151784B422F6212B852754A951217112B128F9232128391224CB112119C2227A122AD
+:80AE8000AC81B12853C86D382E42184CE1883816258AF228288C628A928A94C81FD54F235424B024016184671248211082044004284824C0242044224422542128244224442444400444400444000000184118418D11418141421FB842F141433FB4D147C1627DC64F67F644441F31F272625F72F228582CF4624A6F44F45E12FF74D27FBD
+:80AF0000F51252AFA7F76C6C2CF559499F527218D28242B81251EE37B44FE6F62727ED4E2FA1F1141A6F23B322F3442665F23E7A8B33C7414554468D126F41F9DCDA21AF88F8981EA3F83C868F8168489E344F43DBA8E84BEB45F7DCCC9FF642F243411E581E323D31DF6BF27C664F66F75333FFF3F36D2F8FC4D121F57B77EF44F45E76ED
+:80AF8000FFF6D27FF11A52AFC7F47C6C5E5A3F95F57931EF65F5226A2F8CBD12F45ECE2F24F45D5C57519FA5F6363E4F91F13C384F63F33664C7A1EFA2F33E24CF41D18AD2AAF21A386FC3FBDCDE2F23FB2A28C7E8EF81FB3486AF81F8B2362F4BF336B76F68F8A2B46E74CFCBFBC938243F11D511D589F22527B794AF83E225F677255F93
+:80B0000054F42F258D4E3F11F5587AEF64F44E46AF67F21B47AFA3F73214EFE6F72634EFD1F32D49CD588FA6F24A888FA454AC5F91F1262CDFD7F61C4F8F82F21A1C3E384F43E323D762F13A3AEFC3F33828AFA3F13A3AEF62F11212AFEBFB5A1AAF89FB9416A9D82AFB8CAEAF89D124E822F89494AF8AF27CF88F8EFD7CD6F05155DF716F
+:80B08000F13F2EFFD3F379792B238F85F77D3FFFD7F77F2587A53B14DF31F74E46EF66F5783EBF71F528622F63F26E7E6FC2F3173DDFF7F14C5EAF82F658C88FA1F5DD5F5F51F13E3CD7F1AFB5F63C3CBFC1E1A3F332326F43D3E8F12A3AAF83F23C3CEFE3F12A2AEFC3F3B2A8AFEFFF7ABAAF897B84F63A982F2AFBAEACAFA2BA36F9268D
+:80B100008EAF8BFB2A28CF8EFFECDC5F650549011C014008124116280234482412241E488584A42411830428001810148801180080418801242022098440480224842C020000AFAB03141008141A3248114306808241E844C1484C02301483041840C4488148858464542281002A0100264288E18112286124289841608A00608288169858
+:80B18000288AF4A517D036F41124A5F21124A7241F41724AD2C1F24A131D64AF249921AB9459B44A3925AF5439242F14F92448AD914F82E414F9244A4E816FA264156FA27498F1224AD6D5A2E449D2A2F491242D421F49522A1F4932481F49324A1F48B24AD1C1B64A9921AB9451AB944782AF443924AF447924D842F924484E944FAAF4B9
+:80B20000A7B450121F41964E19F24E121B6145C2688D134CE674D981D6489B45A9B924B44A39242D934F82D412B922F442954F82E514F926885E817782922B52D655969E246F92F4812C69F59164EF227491344E1F49324E1F48F246121D64AF44D941F24AB25B284A29FA4A14A22F44698AAD142B4A2F44E98AF17C770082000014000072
+:80B2800000000000001002188008000014008C020000000040042820410400001470F20612D012912916A114405814581E2880C44846C9488B21C41A8428051AD48462944668A18002894284110212121884D082236A81128CB2184448788882C828001E448481A28328F2F22CB0463285008E42997818842114384119116241417044A1AC
+:80B3000034304283821108200220113415182812182410A12141241D182228200888008019042E161C4C48C18A9F94433214174C29416111A71C4D18811D44F0255820A6145784467828E5448134C21E28188B41EB2181833E18A0214436341128218361214E18143648942893CB2822288909A61C28688200498171834A689883F95D7156
+:80B38000A04240C128C21220011E483011214508A01426880142006014002100851124810100184022112281412844088221801924742428240A26F261E5004481001902008051810000001C0120022400004008800228580000001504200418000000220040DAF60418112022642184F04A1114C8608445824104244284124004282214A0
+:80B4000085222142440A24113014200126062816081A1891823048442B8120182898284329F2BEF7004481289011A1D018112148618464184140220518284124001088410824229022481604002821174200CA011820148401828C02228E14A4DD998041018024022442A04184000000118100002222142480121408408101200141008C43
+:80B48000015021824008290800828120F24E6410022884180000820000000064C02428804284042002000042130200100100001280080000188C4104417F8B0F22000022193214284200004141D021028064444800100400008002800200818001562208004444905200224280F859DD0012440042008181004008840084410084004008A0
+:80B50000008C04220021C02100281100000000608120080010E8EB4E22826142841268114428480040185484205242614C16C4482244420028C0482002482601140084141880041280181464A118821289C24460C87F4A0F00000022128186080000001181002A04005048000000221082220290210020918200000048001800F024EB0082
+:80B580000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE004800000000448002000000100218800800001400848004000000400428000000002180F1F3B5000000000000000000000000000000000000000000000000009A
+:80B600000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000006C
+:80B6800000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000EC
+:80B70000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000022002041020000000080040000000000000000200200000000000000F0C2AC00008144812281448304811002002714008C0444401248020042128400000044201842218412084812812218000041F08CF8
+:80B780005F2418244428390218212480022028A1183088458811348184101861821018410A4222800232819A1278110449824121113198111841A1809144988C025E61200180C2248122812024120800009C1484C1484004248410022024C148220080426841201862124A811218E181841168421200A01841F0594D1002618425012C014D
+:80B80000454208402288214922180844131808811189028111812100200218A082844D111004141220482141420812460489028FB503181902111468851271260289814402200851422242224002C024221694848301002821002062C140880188194462881482248289618288438832849F1101422C9121A166C2111F42C45848C829C8A8
+:80B880001219C448157A1831652D181AB212C42C4611C8444222811744AC02301289841B3111381CE222C11E2C824B7444A32818E01801239D1A860C42986B41424448DF3C0B0031A1269112263141272248A0412481943151678116823464002C04001CE482118401843A4801108133322722A8456811A218C012884603C4821E48A242C1
+:80B900004304F0F519A04119231281946146DC8231442CB81808271442E08188162126433861844142224D28434226482A210428271132225048168C01460688139481A4981E888821C0182F418898248E44CD3A201262446041228428C141348141414874841A120814568221B412CA82166282322061124F261104A824890510614140BE
+:80B9800042C84C81F08241004302228064E418F0E871008487241C93488444161881824113942184D02404182A01A42001C18088084001818480A14218282881200418100287412008C4260223087028494211244204430145820221189048190188411485E28601101C0491102201000048002200D0A401430880180821A50212008042CE
+:80BA0000F6567E1414C02E49D1483124414D32C5213212A502511D4870C224911932A9041285A428848489B2820120C2146508882CE1822121C22116C816484928154832C86C016722B02C01304440F4A4DA7022420419226481818422441413018C841155284302841CE381042C4454241611828221014A02A0420028004184248485044D
+:80BA8000299A21819088002223648838F036C7E054125458212442890211152A01214818228721128145181884C814110062816602200100242400182C04142D822482150483121842080081004F8805241C0226381145028713200A281192812024B81484041E81222241A6460A361224430849028C014381E1841312422201408D81023C
+:80BB000020011884210046F8247F00242041EA15220427A4419346582C47A44224200250422A88112812A8218123028429811288022884848044088416348824A89E222C2A93882602328872834872370929021C14C544A021898421043D445810145D41D1252802818448181155421494880000183C981840C1811C42D1126144881C81B8
+:80BB800001C0148328848128E8610429053F3309961585121A3119447028210120711412212122210221251905512490B18082E18822E11148888204422B12294108802419C882102122294808848042F15279400840321850810041211D1426C821422724814E2248191121B242820284401218110126C1284058223C8C01800121218167
+:80BC000044112818002B4218212A212218F2561F808412040030111211846C4801814C48114202811280044001482502150490114C2181312141952212241241A682434208302A8422008821889F4243410221462522B246213226624B4312642031124303121A624360481110B1148291144E11812A01003028002DC9421814496525702F
+:80BC8000111218C288C0228652281602C283A1244FEF0F84B028843244C134432404706A249428412842D3445118002311A4121E24881534418348824881088619810C30288011484441041EA12581C944184CCA888816D86226F97686241CE21A722188F171526554186E598785CE7483A1474FC454214F61C1216B43EF53D58254D92468
+:80BD0000389A9C25285DA92149C16BC3D41813091B2322172115F81382819FDBE222B51B9213C5D4447C923A897B818B881F11F88A88AF21E184A1229EA82782E0733ACACFC70F2A5424E5F4226985D898F127328594155512D7924AF382489176D298C22A8F1491126D351F92E8522264422664111F58B272D1B34EEA43A12249381982C3
+:80BD8000AB3286D82161249B241816E7253241C959B28D2235E282A3212AF638228F69592849BDD8FAC84822CFCF46715556433C526D45F571625E4C1F21F2226127926E7A9D12BB13CF45F14248ED941F6431C136E423568887494D188F4255158D12DF62737A524CAA31122F88AA118788185C6B2549F15221297D12C94AD092F59212F1
+:80BE000015A1B1A6A511E3E822E1CCB88258822921F92258181EC25F2804426100200240880888C084122C084C188102106144000011860486846148148614624840444204283428001441904424418512241404FF5A41F25356664EF831751F15F758148F877465F642484F66B8DEADACBF2CFC5197EF89F9F5D37F9EFD1181CF91F91922
+:80BE80001B3F23B1ACBA84FA444422DFB2E2B3F21488BE91BE7FDF5AD1CCF8A48487CA575A5D875F5A7A89FDAD2F5D855755BF935347DFC2F26527B5F921211D84DD8C6FC8DBC4B8C4EC42F23A2C4F62BAA2FA282C8E442EE27FCB46F115537F72D68DE251F55975BF45F5787C9F76F5627B7F77FFFBD51FB6F77A725FF4FDD7D17F17F724
+:80BF00004559AF31F936B1CFA17136FAAEB9DF98FB2C3847429FF2F2332DBEBEBF77FB39FFFF5B7988A9A28FC3FBBDAD1B2B3EF2BD8FFFFBFAD1211F35F11B197F42D3CD7547741DF43BB3BFD3FB998A3FA8FBB6A6EF2BEA62E3C1F2B6BCCFCEFE2ABCCECC4FE9FDF6AC246F65D57756C39F53F35579EF67F77A587FD6F64B6FBF7EF66A97
+:80BF8000EC2B66BF84F6D155CFC5FD7563BFB6F2A6255F9EF2353D5F43F18E81D798DD1DCFD2D29DFA3939CF91C3F36FB1FF213796A1B34BA21FC2F2A1221F13FE15833F7AF323C1BF17F23F2D97A1AFC5F14D1EBFF2B392A8A9BF98F98A98CFA8F992942AF23E388FAAFBBEBCAF86FC1CD88FAEF7BF37144F25F12727DD2EBF57F2596DD6
+:80C00000BF67F77B7CBFD6F77B7FBF7FF77AFA3FBFFF5B7B7FFDF55FDDEFEFFF6B7DFF7BF3F7336FA37336F8AE3DDFD9F32D29CFD252FDF7F3FFFBF36F77DFB9F7BB37EFC1A8334B3B1FCBF335A62F23729FFBBBBEFF7FF77A22F7F1BFA3F27E7CFFF4F13BB5BF39F99BBBBFB9F98F9D4F2AFBBA9E2F22F316986FE8F9DAD88F86FF54F815
+:80C080004FECFDD4CCA0120084188445425814402141A341641A446681853611850485044C02808192128902812A0100254148013C6181349A4462811484248648A24985022810081FC80C821554224C62121F413642688B16482B128C34428487142A641422422228124E241170245818704804163122121880A12124128732480014C49E
+:80C1000020C99282983288842892E083A48486F386CBD024F41124A5F2112483F61124A3D441B24AF1812CAB941B28AB9453F94A9643FA4A9143FA42954782ADB14F82E414F9244A5CF8244A56F1244A87192ECA96C5CA9E24ACFD91242CFC9124AD821F49F248821F49324A1F48F64A121D24AB941D28AB9451AB9443F24A924B42AF245E
+:80C180007924B842F92448984FAAF463B5C04A1B61AD421F4132681741A3D441B242F1812CAF44B981B24ABB91F24A9243DA18B9A5F4429445D812BBA7F442112E1A1CF924CA5E8177A296E1226C19BCEC18C2DA9E281CBC91F62AC21B298B841B2983B481F44A12442F543981ABB411AF1429F24A922AF44A9226B842792288F9A25A4F84
+:80C20000FE030000004002440000000000001200800800001400460800880014001100280000000000CF420E1A440114167118043051C68B220800221E485188224847111164848902464E9328128C082888106293E02482110C22223F2231C982482189822709EB8421439248245F494682622881696284172287442222C0982572414227
+:80C28000944233414252852D8A8D1583CA28948654218C11117441145126A4C421232401D08238281E212E1A89B14308163218A1818A111E688180618436A1483F9C0F233341A5621285611169044AB34978B69882135224482D211A54161768A45D52936312167C8668A8184784644698119546D822126824564808291EF224182A21E138
+:80C3000028723491C98B822D48848F22E8442321318C257224381816F25386800440A414CC12884201002724001281102A1A3884811130218115423125908250848221E01201811E281484A7221944229112102211688885828481A4248AE48E054044C12424112E1248A38204826081811B413C4208550822838484120115482112782277
+:80C38000024924445141C18400002A290850181281400418004120F8F41BA0161CC21815BA24A442897414683189F84A2183E484F1438657242849E854B9C5817828D4583135263188819CD422F43448BD146B82B01442829372A0825C71219424244518B928D12AA21A8229B8C1719A62A98B38CC624C96A4242866F848B58061528413D0
+:80C4000062443B243E48478525E12438484E8883D469984129512445C141884443A3522A1408465818AC451A8C8221B412B243111148448402A18B828B82804189B84121981825783488CC9480B228FC3FA5A042C01185342200218F2142C82160211A548413E612E885C894459928945548214A49C3425C6253A6022D24444222444B2852
+:80C4800017811C12044419C1128722A22C88C18AACC1842A09443064009FCF05461C22042E14A7126CF218242301C1148A8112948C411447288912420260843CD9290422403448191128028C826412214B12C0229A028460422949928889244488E18852825028BFD30412C4AF44022304830149128892384D48281116110225081C42168A
+:80C50000611143DA84086C24081CC2212684E28441021D621842401649711814658210811484A1214C0290361A22784C0B2011912B841800871449011082941880B44812E144A11881165848212021120112C042441422400822148C01202401299848478190820043820182429F44014F248151C1A12784259124274259129428972283C5
+:80C580002934151E842183768A742438A3441911B8825248372426B4810259B348F254224CB241C22228267931A2244F1271143A281AD8848451288233344CAD842985C52C43A1288921C8C28F3D0140342219B224E181921816B84A61812021048115684411341A8441181875481431182C04000084120024000011271212858182628973
+:80C6000018908822209218438243D8990244248044021260422841A084102245041902201654818129946490858C3C881460A21154144128422858901432130C8B1488CA420247824E18188C011EEA49F452497041C224288992414839943831A7483D824A183918518F42088922648428494142C241C30247224826415142244CA12180A4
+:80C680009418C02123042110C2182B84B0421331C8C6182272420826186288EF4C0B444884409838C441850440824118289482211817211281492868A830241A3424C04848812810810211001418002001414D224141D08408A44884F0D87B001158211110011B14C048002858306C4463A842868171120148241C49A841242285623148AC
+:80C70000801C88041E81134598A1281D84202468148C212411084A0110025F5A0A8A0289022584C4228927E184CA128A4432114D1244002821182213914430414062214A01611024322613312414490469A182830448882A4C846448291484044488367284F375FF608424108816331851890484916B824A528383C8888521C42C212994EF
+:80C78000A2818860A114503490484216EA1441088001602294239818502A41AB21299818922CA181242C9534003F5348420150161200602260147018014828A04A88B0281401008442264808981280048410082484833844158272180184888501248A444204424270224B021302008100004008638402484C54415081158822011A12131C
+:80C800001281A242121200C0281C8242446114422641018444114C115284424120A881884828404A9444004393422314724114E24132442824903282A72196614C412126421484B814CC224411241C1811F84228808C442801892168882348042880031A08844484E081F2E47B241D224F5AB21A3223122F41E6F4B224E491526C17241709
+:80C88000259F8461254731237424F84283CBDA2F92D1A8D85423A94199F426548CD244E122BD2CE484D298C4182E1838539228CB921924BC63E128324183BC1E7842EA84786232492F2C78E4C8442B6443745A98928F88E21876A8FAE8EED0160410F8412D87A49B412C522C218718ADE82F799C5EA18B6B8BE4CD241B251B289E348B46D4
+:80C900004CB225F8C28E46F92354AF2672426C351633462F29F45242BF32B4C2E412043AD22C94489F81B51AF731228CB3898DF51CCC4F48FC38718F41FD5A9A4B99AF6185D468B422F8681249FC111460443D4247A2ECC4421B1229F15B1C3F46F5E1E82D5C824352811FC4D7E4F88214AE4825F75C423F167411F82591A50A8D2247355B
+:80C980001EC95F11D243BAABEC6101CD25125C7211C82D141753167142E5DAD81678A16111A328F81211555C224358C88EA8497114B854E581785274E74B2101164801264148C1481412148454004890410000308110011190914421C644614C60481C61482444244002244022014002242024085BF4F064645FD5F13E16BF42F454563F79
+:80CA000022F61644BB264D449F6CBAC8B82BB2D819514A4DC4ABDC4B95CF89F914996F79F85415D7D18FF7F6C6CF6F66F53E28CD4EEFE4F45E582E365F89FD8C8A5E545F79F9C5E14F1AFBB83CDFDBFBFDD8DF87B4C3784DF54B449FD1B9DBADD5AF85DD8DFC57E3EF24BDAEDF44F8CED8CFC5F19E9CCF46FD8898CFABFEFC64F065645FDA
+:80CA800052F62C241F43F34D46F5B67BB76BF65D44FF6EFEC3C63F22F6DBB63FA4D1A3F5A4C86FACF9F7FD8F8FFD36F96F5BFC7655DFD1F1786F6FFCFC6FDF4F47F62DCFEFE5F57A7EEF62F39ADFCFE8F81C1ABFF3F123254F5AFFBC389FD2F26145FFCFFD5F1CBF16F34B74BF59FBDBD4AF8DFDFAFC7F54FDCFDFEF6CF8EEAC6FCCF9CE7D
+:80CB0000DC6FC5F59A9CCFCBF188988FA77FC242F376741F52F62C249F52F25C5C9D496FC6F66F654FE4F64DE78FC5F96323AFACFF4755E9F4A6C4ABDC4F2AFEF79B4F8FFBB7C5EF41E549F8697F5D4D4F647C17F56C4C775C4F2DF5F296DE9D27214F29FB133F1F53F3A171DF81FB31359FD5F7597A6F49FD1812AF47F5B8BEAF4DED25BD
+:80CB8000FDDAF85F24FC53C3EF2CBCBAEF2BF8FAD8CFE5F58E9CEFCAF918D8CDDE9F1B4FF375755F52F23C3C1FD3F34D47FD45FFD2F66F25FFF3F7EFA7BFBDF96BABFFBCFD475FFD4FEF8AFC8EDAFFFEFEF3DB7F9BFFBFDDDFD3F5A5859FF6F7C5CFFFF7F43537FFFEF5CB4F8FEFF5EED7EFAD5DAE8FE9FB323B7F1BFBA5319FC3FB2121FA
+:80CC00005F3DFFDFBBAFB5F5CF17BF76F5BBA7BF3DDDAAFCCEEA7F6DFDDBD9EF6DFDFAFA6FAEFDEADAEFE5F59A9CCFCBFBD8784FE4FD6B2530223026842148228C34248C040012404852818922C92450481142118314534819A92488422B124001188400184888860882C04824008A4424018242823F31078A440410E84106444150288A7D
+:80CC80003448304243A2144118482714124C0A4C48E84122022C6448848554249044C0111D24411F8106CC828192184898D058A9418DA4224A5184812A8441F9C585C0421F4152381FC132681F41324A1D2CAB141D6CAB9419B24A5985AB9443F24A955B422F54F924482D914F82C4915FAAD418F8254A16F1254A96F1214A8759ACEC4D28
+:80CD0000D2A2F4D1243CF4912485F291248F14F19124A3F4812CEB141D24AB941D28AB9453B14A7924B84A7924B8427924B842F9A448984FA2F432CDC04B4CC6431D2C87361FC17242D3C1D232F1816CAF1651412DA11D68AF3439A4AD155B4A25F42448AD917F82F442915FAA81F227D21AF8254A923FA264411CEC5DD2A2E8CDE232FCC1
+:80CD800091648DC28E248F34F991242F24F89124EF34D141F642971F41F24AB253394243F2429243F24292478A2B14278A2D944D5AFF920200000000004004000000000090120000000000840000000000158484020010080021F0B619D0234242618184942D361C422952224812424391454AB145C14687224324921859642293D2415102
+:80CE000041183611A8411688245112009011844D218B28174123A18491141D4829C9484C18840112460849F45BA73044B28723246042818B142D4281111117A481429642082328B48842382530C1508226629885961522A8446D21423CF32812164108184C7142E862C818224A08838462872D884998244E842A6819817FC50417665AF2DF
+:80CE80001B228311581C472126D992445814257168754238548636184E15272C26FAA44A26C8111E4517288B286391219CF128113D1C1B431EA8488F51324156392A23111128B388524B2AB81A3C29AE44248E488B244B4387484CC9245E8266A8182FC1F49AFA1002002128A3A2412428214818001B4142408404D048024A1251184522BC
+:80CF000018040045022128181189014561414E12160440D18184018D8200402408F08DFC90424429011440121144C41213683486489244464248038514052285141338224002108801255141254144012416088281129882A511C4828608122008B0AA073460B2ECC14446585248B49F2498415816981191872185F44481A74246088C1234
+:80CF800048992189F22441184599112CD82448D284928412121285D18411CA1C4443931A2961A2813D5C8652288B21484939228D448B218314F8F76924243028253C414091428537811B14199C1986497142489A449C2204228485D134621254508120C88284234214514150491D1CA170129814253A1884186B481C081829C8861245B803
+:80D00000181808EFDE081344C6112C11D428144401C9143212422941D82461448659628185545820124838682B12441C115242D0488198122CC111007018448482091E228CD8A11158A6896A84182242224884ED19502B244B240014402C8431218C62CA2548A41825820124C0188B41454148480819288182C42422421D1290481A420801
+:80D08000129012450257822311064825480244418C3428486FAE05402814A114410037814528C8112841128188418981919146068141981391142901128711C2F01128284CB12114219514841601819044821C312C26140441308A244424AF1C038011211162218D148002160823014031741441259444824410421414020000AB410080E4
+:80D100000122112221843011180000884C4188011218C11FC40714214C921123655149412853488E281D38961A3C14984F23486421448E444C35588515161454621908204166841CC7317011C8318B2559618216414818924823C811C126D486480616140A4781C7243FEB0D2112250100A144A714125C012100153842135148122D118699
+:80D180004804818487111812181AC248CAA2124062412200C0129012441CB111C212490248205148C0841E4828F079A200408A04904891C5C2824A2828489211C665A845812208890911218110011301180090818D1211C0858433081130118D8211701845820116062822C481DF710740841204444C12064028118AA88418218918123862
+:80D200008260398C888804C582410E242492218C044F218801124C0129823222228301102818029084A082F0CAFC101201130214412215521815B41184016011129CA214181800100800203114001884151294133012411281128282002821160C442988D282418441F234296024904424810024424C8411021184400441630482810041DE
+:80D28000298121684824E041426841448148448514528144884441D0419A1400458811145424844518E4320F8611C8212214848C62866018231448E12108254282014008189C180210D2184101448125180200251141C8882001908A46421E014602242A01A28243F8EB47400A8D4200190127414A813118148504118100129918D24212BF
+:80D30000024AB185C2B9140022115444174425028E4C41002514D243321A378212002410328882208201F01FE56044442181444411000088508412C812288280080088481014140212880082008486084004002008800800810000EF3C4A53141C1454184501468114114431482711AD1184A1C44911474108805128A481A18544721154EF
+:80D38000820060414C04241652412415582451D021622184103414450A6484438821F153C84068211914141A0811A183042514842244440142234441B123081C4181682124A648582414411662841981A41420011886888BC9148119CB982B81838889818161812182BF3C4551422738814D435416596857942573C8FC99429F39F18C12D3
+:80D400009E912F2C745C54226B126D421F24751A38888EA8854BF186442CD1AA511636E36271117A2458E64582F4531445F21D147D8895949175A2B2D1BAB939A19547611D8487888F4DF194822447A1A6FC8C188DA841EF9D055B445594219782F145E414F22852DF84D125C5192F84781351A98F81C11ACF116129C089860315B193B81A
+:80D48000887C687818711564E13D14A311C21289C9484764242B98218779272147B18781C7312F2153198EA865931B1E1B1E9249D88AB116F122146B11A84F4841F61CF72434837526DF424218F925482D24482D81274448C44115F183C186DCD9E2557B8A84B835A8115082157322489198CF8858144D142748123F41F18391C57819C500
+:80D5000042184D18A748443748AE842D2425F2892886185A46254AE4488892282743128B895EFF00000080044888488880A8418813811801130112308142001128118021C811C21C214821C8118214400126214801280040042882F05FC3341F24F4571B1F22F22B6D911E149F46F46126EF24F4D3937BDDBF9D7893F69B9BCFECFB9A9A6B
+:80D58000AFA9F12E1EEFCB7786D6CEF8B838DFC33182E0A45574C5F69A9B8FC9F91C1C85F21E1C9AF18486DEC44F48F9989AEFE9F99A9CFFC1E8C8F883848F8BFA2FACC9F129888FCCFD9E9EAFA1F92C2C4F87F61616EF81792697164F43FBBC18EFE1F85523145F74F417575FB2F22B2FD5F51D159F66F63577E724BF2DFD4B86BFBDFDAD
+:80D60000B3BFAFA9F95DB66F39FD9F9BE7F2FFDF567675FF32385F4BE1117189F1898A7FD252ECF7F98FF9F93F3FF771EFE1F19C1EF7F81F69F88755FFE8F99717BFE9F99F9CDFE8798FF49D8E7DA49F69B18BF969FAFFF8F91BB8CFEAF3FE7AE761EFA9F93626EF23F3A6B4CF8AF8889A2F9D4EF341427F51F52922FFF2528B4FC1F16177
+:80D680002D3FE6F64F4E7FF9FD53DDBFB9FC1B32BFB8F95E9EEFFDF9191DC7FAFF9B7C4A59932F937B3DDDB859114D8E45573CAF99F9ACB7FFF1517867492F49F8951F5F69F885579FC9799BFF9F8CFFF1F182987F78F9BABCBFF3DB4AF9B92BAF8DFF9F93FFA1D9CCF9C4DC6F69F11E9C6F7293126F4BFBBCB4CF68F937E6345F64F417CF
+:80D7000017FD2AFFF252CDDFD1F12D6FFFF7D7FFF4DFDDBF91F5DBCBFFA9F39B9BFFE7F1C6DF3FD971ACFDFFCFAFBDF113992F93F33D8D8D1B9D81DD8E7FD253FDFFF9F1BABFFFF3F31817EFE9F19A9E7FF1F1918675F58F8E7F71F18B8E7FF1F98F9FFF78F19F9F7F71F99B93BF39F9DB79FFB9F93F9A6D9EEF8CFD9E16EF89F936366BFE
+:80D78000336F42FBBC38CFE8F8F8CA00000020E2810400482440014410A84100001042048110088001001884188418126088240084000000852408F095BCA04810C2242184472212C714842D1280014A011847812C0A89285B1880D881048C215182124183182681046100100C4128181E28891884698889019832448428843F26012CF4E0
+:80D80000112485F2112483F41124A3D441B64AF18164AB941B68AB9453B94AB9B4F44A9143F2429147832D914F83C4914FAAF448814FA27418F1264A96E1A26C592E4A9E24ACF5D1242D521F49D228F1912483F49124AB141FC8B24AD141B26AB981B24A19B54A3924AB9447822B94478A2D944F8A84FB244AAF7B016D4B1E643CE5C172FB
+:80D880004CE1C1D21AD141B64AE1C8D616E1C8F642311F897242F2B548872453A294178329F832482D815FAAA51449E811FA274216F425C89E242FB2E458C258CE2C6D538E648D519E24E7348E244E138E248F34E141F268959E24AF3493648F3419C4B64B424E96B24CF196482D244F82F58D2A4048240100001008448002000000100241
+:80D90000000000001441400800400800000080011002005012F09DDE005542082941E1A4018D44183C483B8113A11844160A2B411283048984140283524294614502212D88184522211814A212496882C71112928928012184211249C81A2A21C12444CF5A0E2B142B2949011D464061811532881608AC748892412602835485241285850C
+:80D98000012C449C158011A8218362414992422052872711842416C15428A1601193187884C8111E248418608C419621F896472456724462C1C044253111A1118A919425EA92C4198A048C217443042FA45114B012143282578325440A12912761A883042F866118164328C1858F4261E283918414A60145381923118849E2AC3114B6A5F2
+:80DA000081FFB20FB01102D012018324714C425818112C28D8123124254298181240B84801424508601145C8242302452A1104E54204282981C41180618989419882C024124416880210F4E4DA005018404108448115581840214822C11340228821815124464542941244218110A84228221942021884818061818800843C0888822484AF
+:80DA800088438281F438FE30447C4112B81C14D3167D23C841325012A914D2C3DC8118E678118C912D41578881842D218B4185B61814D921C282282124412118A4519022C321021891853291218F2204652846242361822CF817FD001611183218118682429111941495028D8113D824A11880D11821E1D158248C1422D442618121222792
+:80DB00002826082CC2262216421A0522001200C0110088C122A138A012881FA64791446411811744A5B21554498334281032428662442D18255161C1239824444058141C721A443A44948501246200110012A481CCA112849885416AA819F8224A9082484188361428E4C941522118544844E04104441420447428145C28C8511D184C5179
+:80DB800012E4122C04141034218111443241221249F381442E98F028111648C82444492212921A18121240449424460AF037F3101CC44859425818102C331CC01BC46A210116480820622181208841118281311C2E4100CC01211A040070122181931381430A441002D029016C2143F262CB001052281210881228040080444402488142C8
+:80DC000042501444EC02504A412602E0810200848084280221118001403822508412190800B0510E54695112264B18883424167811048421465C84648C148F4194418B4160446368423125F42A15C331292D24324991241869D384A892482E8960314117621922218861412D2212858461C1218C2141F2B36F1002C1444911911C8443C2D5
+:80DC800048B0111428A1148498704861812912941811D081880800168404262801C0118420F12812842A2181C12825421828014024C8244984023FDA064011944419148144014825F81A41C8422A0420048841541045644130541009838C081410AA12220018121D42281D8288871A4019286828C022868831848AD2E301360883112882FF
+:80DD00001141489881800844131818022D8D34893B28A04290281C62124188CC781422A1826088A8A4A4427022D88202508228101802182638A88442418C41F27823B013041601212411166614851445621110044A511416040040081C14264802190149028C1AC54812248D212B214902301224143974461121420216064400F092F44064
+:80DD8000344C90111558420012A01427482899124A841208CC029084202828418A8802883018001248140010628141228441109414A1004098284484DF240E82181022542841114508812C018A210446E544114904418718254481140991478889844106822081480145292134121C2A2892188440A8822041A228401AF4E288141005D161
+:80DE00004921046304298108843B248E125B9425622818394882B142C288002721811E24105481AD8181A0284D83116118AA64144B811942041E8260418129381240B818081A188298B900C024001C21422843032628023184890840B2281101148126884A01281A120428000012421821948481254904241054484F810828408804EF2A54
+:80DE80000F44404172185284124214CC814141144C9482121781108808642830858186420880A4212331343604001484440088C011464201284542D224981545824881F2D8AB704219C848124448C9341225144241B411BC8213985124A028291211781228B488012C98242C18A4A4229400842D224DC1428B1221942822845048821A66D8
+:80DF0000618A81022088413492845FF447D214F194444971187E1148C3241A546299B112D1A8E833C84AC7842788EF217114799252E48C5B148E86CD288E848D1D437226D84C98A8DB441F2C88BB28E141782124722232229B2117426C129928997883E813D2234211C51C36E888389416716E4A4885F23C79B0724458B8118F24E545F461
+:80DF80004242BFE4E191D382D4E8BC11A46CFB8D1D479F65EC149C4A883B88271289D218F441C585B9C47A18F289B11447CA9AF2385C674216688A86F2121A4F99692129A5155E1186FC32124991888F28A9CCC42D164B8BA76889D128F8A4988AA8814F98EC88F85666141554191F41D2147526D58FD11D5114D9749457112F18D34BC160
+:80E00000152BB84D11221F64D9DDF3282187691D1C4F823122F021423D394676B21AE3C21974989AA21C92B49F481ED1D164B6AFA8722FB872D391F4A22E3C5283CD19FF255598AD2249DB26D2C2D32AC214CF48F31812C7227718800228618A8281026880068444407421088244111061441144001901002A080045012A896412501460E1
+:80E080001220220180024C025CA241804474E642A1751F93F2212A1F82F6486C9FE7F37A7CBFF692437F7ABEA6F783413F4EF4D614FFE5F76EAE2F12AA8A3F98FA323AEF3ABA9C49F8E2E8CF8CFCA4366FF3E3A342FAA7AC5FCBF1B47ECFC2AB335F5AFB31131F6B7A94B487B8FAFEBFA4AF87F76B4CEFC8DACE528A9D8BBF58F85B11BF9A
+:80E1000011B33ABB925B2621EF22FA82C24F44BCC4FC66EA6F5543F145757E6C1E1E57E19F95F77F7D3FD5F5595F3F13F7B7F53FDBF711D3BF9DF55BD3BFEEFDCA4BAD8BC7426F58FB3A38FF1AFABEB15F13F3B8B9DF9CFCA4B65F73731CFB8587FFC2F2F5B4DFF3F72CBC3AF32D3D1F7BF923C65D867F18F8BABA7F6BFA7B6C9FF2F28604
+:80E18000867F71F33F3E9FB8F9BAFF3F34F11B192BBB2F2B5B2665FA8E9B6F89FDC6DC8AF8B4BEDF1E4FB271F5156555FE1B198F86F4497BAF95F55F4F3F43F393963F49F1B3A1BFADFFDAD2FFDDFD54DEBF91F9BE946F99DBF6F2AEA9EFD1F1818D4FDAFBEDE94F66FE321B4FD3F3111B7FD2FAB57D4FDBF73C9EABB34FC8EB23F13767DD
+:80E20000EF41F31F22AB23DF7AFA62687FC6F68FAC9D2B35FEABBBBF1DFB5913AF11B1B8FBBC98E7E227826FEABBD2F98ECCCB88CF2AF9BBD7347F57F519651FE37317FF77DDFFD4F7777FFFF5F51F167F7BFB93111F33FADB58BF35F54B5DFFDDF56FBFEF4BF996B3FFFAF22FA1CF91F19591CFD2F3EDE94FE7FE3637EFB3F39797FFDA04
+:80E28000F27571CFF2F72A8EAF82FA25BD5F7BF3A7A7DF78FA1F32AFA1F3A7A7FFD4F6352FFF7AFA1333BFE3FBABBBFFBDFF4713BF91A1BAABBB67626FC3F9A6BE6FCFFB84CCCFCCFCACBEBB8410040014841884608920084044489441209128800210C124C02480B2240929011C014B82841440C24841860800481440648128001008AF89
+:80E300009F051C2511648143048F3441A414867442618142122B8412204847C8144331484183048591126082875443128898212CA121221564221E4862122428D0819288D0525184B882812289084C098FA60F2E421F41722CF2112487261F41B26AD141B26AD141F66A9219B64A19F54A9443F24AB543FA4AB147822D954F82F448914FEF
+:80E38000A2C4854FA27458F5244A87192E4A87592E4A9E24ACFC91242CF4912487221F4932681FC9364A1F48B26AF11164AB9619B24A5985AB944782ABB443B2427B24B842FB24484AFB244A2FEA042CF4114CC53111872415B44CD141D41E5141AD9615E4140BAF741BF1421643F8428513D242F127482B141F22C5242EDA563525F02298
+:80E400004296E53264594DCA1FC1C2429AF6284315B426E141744AA128AF16C944AF7618F142A459F24292418F240B2F244B98A26598B22E1A1F1F078482000000008411800240020000218001100100400140080000200200442008000000702241F1368130121604160817413441428290439470CC62284AF984122486F4A24186341446
+:80E4800043C888459846255812882122ACC282881E844512342C6D818D82888564648E3400901163440440D448024180D212014324C83819921A6043E022C1188AC6121A74121832188512B81C528141A08287142904384449F1421C473A168665424B21221485A181483817831838B0C342225948930816082F8891128E6136783449FCB4
+:80E50000E49720648C265829841415148682B824D412E1A394184E8E8D828A24712A748A96C188B23FC15882C3C856C12D144F88F122855B122B3443B888E349724118E2A8621C8E329658482E146B28471A20DA4971CA0112B08E9116C66382366DC1EF5808696141181A8261412A014E1216888854121022D12871848811C1244144488E
+:80E580004A488202142904218127224440541C161444681212421223042901444181002688321420F2DE480028813024484014082448002901290130A44A024400004890141E242C31184896E422180100001242281892008800860848814528049F640F1524B124119441412D4283D422C7D8A9C51829D14AD12844B48894148B49A19675
+:80E600002CA1698F14D28534422F14C3244F84522A84AB24302660414CCA26AE1A1AE24112120941A7184829541865480A2D248F48942A481882A46F3B05A0128514C4214440F8122827898395122381411294924188844604C048BC0418448D66163818AC45088E14434805881A8201930100925029C184B02EC8842D48468801F05E1F14
+:80E6800014512003436424422D44424602464852688B146084188D524B288B92124B871912C44266A1421074229422182F44021A32A249F21A22606200426CE298213442804802C0482250844A18E8B84A52380084265A484911C86844842230212121890C8022C2124C1201EC6111229844BC0113D28223C144414818401101003210A42F
+:80E70000128924C1444800C4124483F4F5FC00C417412F224484212251428B141621442CC2449932125488C411868221942618848BC114160A1A56850014188C0646148A42A1214D1213D82811541428C38281211202242224EFB601000000812200C0112349040083E1510243481C0100400600442098442C0A1122298221614187142211
+:80E78000C02112200126088C410400B05D49512100A1899214C1182D4CC951185E2123416524A49A44EC4922024CC134469224842D191E4E1978187618D14292242D1843348541896221429961134D11871126C6B13C8131148C65424A02A444841014E8CE0721444D11286542A8128C22828401890825342181134151845C6A88141110B9
+:80E80000842822018015A882122E421214284722002026018C021160818D141A8403441228483F9D0C25C225504A246C426442232111C828D0840841104452241084024D42360880C414424FA28111CA11294874128611A218811C02460460849044260442122648944412F04ACA404402118181C01828001828124D222221252AC29816D6
+:80E88000A8814008484561811602160B8B2813C8A416160149881809424384822203C3012034240084814D48486F4C4F0184812662228481420028812181A504450114281528425124444121441C4412A84860282002261C41486C44818C01811112181608414A91484008009F8803410000427012086C8211129C22001820011008408356
+:80E90000212132228CC442001124182420A481008888001014098884401444826884F026A1208811480824004C31E8830442104848B84C6882460622164612082323C4144508930341124314022302A084A0121238C088B042A14118A04180034C81F289598042462201144C22022120044A11B244C81200211412211011449C2A80014840
+:80E98000942841B044B218444A282202D084081E8CC08410088988A8C144C480F84612508221000000844C014C0800211C0211812220420448008125221144428888681190816018A0488904814420040000800410F4478C20024464624448412944E82201A1611AC4214B421449C4214F211244541882902882200490A624281110D148DC
+:80EA0000114154874C02890B898281088745CB848484838E24249882FF7F028C848204A02420147442021F44024A0242214A721228048421C0188B822C4846284804168141C128A0422021A1189082C0844C2884C68888A0811084881842F8BE4D146F2224588867912A52856D2424EF43E144F13A18AF847446F2C2448D1E15F63812158B
+:80EA80008852632D188F4992145568249AF13B38222313761872347432DAA17A31728223E5F2F2498D141F915892624F89B1ACCDA88F1A88B148F84AD8CC93C8DEAC43D448FA48D829289584DF4E4BC224A7324502A4AF4244F85A6CF01642283A88721C18B468D641F2644485FBB84887514F82712144D645F846264596364E488FE1C583
+:80EB0000142D428BB82581AB116992164B28A18B384A92A8A9E4C1028CD284E89845A44D8490C8EE48418E4418229F6E07F0142421876223E42422B42461248F826A241D2285C8122B24697846D12AF873144B241F22022C12589A8F82048DCEDD124AF843489F8C43F4881467584F425E7183F112129E9845F48CD48E454A0ACB121AB13C
+:80EB800058741424918C4F4491581E18496142C784CDCC278C3FF10B4200800448C0488848881A84A841A81D488819841A812881182184012018044140011C092601140048200982200892200882428285F41D2CD066F2323AA5FA1E5EEFE6F22D2FCFC2F26C2C706AFA8AA23F3BFBB296AFA1F99AB82F2EF89F944F65F39B9EC7EF9E134C
+:80EC00004F42FA8CBCAFA918BB68A3124F67F726EC8DCAA5F8ACACEFC8FB8C1E6F79F8C6646F5BFB8888AFD9F99614AEA3274CCFEDF93EFCCFC212A4318FC555ECED688D888D488588B414F11C184F41FD14143E24EFB30C6F62F2727AA5F21E5EED2EDFF2F22E2EEF82022B8AEF4AFA39711E36AFA1BC927826F63F1E4F6BFBBB9EE7EB86
+:80EC8000BE116F42FBACBC8FA859298F2EBB22F37EF66D8CAFE4FCCCDECFB7F78CBACFCAFB8C8D4F4EFEB6EF8FA8FA8A9D6F49E93AFAEAEC8FE9F996D44F4AF31C3C8F89E38773C4DE86C6181E58C6A854CF8FD7A8F416545E1CCFC7FBC59BF066262F2357E86F41F16E26BF36764CF46C222F84F3EEAA2F66F633232F25F69A1EAF84F932
+:80ED00007C1BFF55F3DEB7F774DFE6D917F3A624CFC3D934F18F858F22EA23F37476EFE27298DECEF4ACEDEFC8FB989A7FFBFBD7F67F535789BFF9F99F94DF7BFB83944F6AFABEBCCF82EB41A9338F89DBECD8CEDC88F9D8DC85A8CC4FC5F97CBCEF41DDC4FCAC7C37D2F06666EF23576A6F65F16E2EBFB6F66E6EEFA7F7527A2FA6F6E233
+:80ED8000F63F1FFE564A8FADF542D26F7FFD7F7FEFF7F7EFCFFFE6FD2F318FCBF33CBC343F38F83EA22B33EFEFF7726AAFEDF48E8EEF64F486B2EF6BFBA5AD5F2EFE3F371FA2F2BBBBFF49F9B5B7BFCEFFE8EEEFCBFBA4B88FCBEB8BFBD8E84FECFCEEDC4E98CFCDFDC49C4F4CFDFCFC8FCEFE96D44FCCFCECFCDFB60722100663022412F5
+:80EE0000200884200882288244828D24828524180844008883A482800188100249481824018C041608844048E481040020042FD901824481100C43C228C0242B1280494816C11453921A121C018D2411442E4283712492284880319822C0111B2841178120F16881104404A014A014006044478189828441F159ECC0431F417228F311240E
+:80EE800087141F41324A1D24AB141D24AB9419B24A19B54A3925AF143B252F147925D812FB25481CF9254A4E815FA264115FA265191FA26459ACE449C24A1F49C2431F4952381F497248F19124A7141F48F24A111D64AB9419F24A9151AF143924ABB443B2427B24B842F92448984FA2F48533C012CCF62852448D121E6483D241941A1F43
+:80EF000048D66AA968ADB65B6829F9A448ADB14B4A2D934F8A84FBA64829F8A45A4E816FA22DD4A4A4282ECA96F422C996F4224A178D259A618B421F48326A17498366488B921F48F46A1482AF44A3288B1443B84A33842B3447882B342F8A84B1A4F57A9F4008480000000044000000000021008008000000400800000024104104000097
+:80EF8000000000F08F5C001B215022267444120881162A39191054388448911E8850421D44400C1024C124B24C92242A082048E41281D184784124123A3A00301820C118222E1442E084111C3448DF420764828181D08262414CA212304890488B1863642881472A41C3B148A11A22426D414E228149125252D022046964224A92822D888A
+:80F0000015AA413014809C141A9429C8111DC821161882688180C111F0DF44003354288464CB426D18C028124F88042287419D442127845C221858E241F0184213A42C616C33244F116A42590248814E82431498194F8114C524212D684449C529F20025E82261428A84E1A4C11849B118F4B12710A421002302C024188429711138488236
+:80F0800021860886D84A31144AB1B184124404810021D022A42861282322F82291908248188498120081118F1429112801841004F0D1A6004041541A442332112B147048022F340110B442094200004044C8242489022800A021006041002C0841124284890185148421484408260848BFB50725C4142761124113D221114446466181812E
+:80F1000042478C2948E88168C89742239C141F8C8234C2218C7116C8548460A1186384D44182E18843D84832226084842788BC89388229B4829148444668224EB38321443828DFFE0E90143981518110D35251224191189911D228C8848C88C8888148C048484F2408163E1C47838422181823044322A192C1302282A141822C0112299412
+:80F18000144904C843B299C41822842AF496FE1006454254425CA212B0440123548223849444B042618143742431824931A1244088422204400A415A4201811287420042812D18871CACC8882489186841847022024608815FEA0CCCD4429111211A0800121880582422141008848564412418C4124490680028502300526044A156E442E9
+:80F20000011470220414B044C244120014812124488CF276B22484108246C428708102C4145983B12401101408006C448516F41122461504008741D348BC24014D38930E89421918041001828CD228013248A818489E2281241F83041211448D11824460880089410242414581444101288400A884C0121022882A22011512012E1100120C
+:80F280002A6115002C0121A0824222D14426886442F0A9FB60417911F3281112450881235184118E3121691544151C0985C4244CC41481415C92451E680000A74265286311548D2187114A732461814D211F2134241416318229944C9A2283F484288D142782D84126FA75869042D0240141281001128901184001425018804148B12484A3
+:80F30000CA8A502410A2284F82298841C4421AD22488126C812001000045C8122024022024B24802DFAE4C82D11A01124158241E4143218101232221311416341216061504D0820481191544B444514180810580B12881A3523C0228440082285B48400800E48844005F150440425221002141209C423902C223924230C5214240C81590D1
+:80F3800046228882848448818D44904190212441002044B84122044284A084814B8280088C58241AF8B279142341049064144810444134122C41854402100110440419E82418A4244420240415082A0400811889042A440420C842837A440248428800A44CF215D1408802004E24304260410080026641410126C918908241A44160981680
+:80F40000A98210C2411094834428248844115121908B1958828C384120042382024840E8C30949A421214002001A4495122001431126512483110412189044248311044C011C845184584118D058018489840400840049018604C04424A012B03241016051501860111C41029C4461C41C31421880119432224824438848A88212224004A0
+:80F48000141200421E4829A221244512C48280416228105228602285D4224228928226D8A80D0040260C480048800C4880488304893481822904806A24830210089400C02241C04414821038A98C2844182438847088240426648860489F9105822328611240311200212001402422044290288460288180A2411A120884604444520084A1
+:80F50000448C0424484100428004818018198444017F6B014558416C0430160021004C14D242021002811223A1182B4846C81243D4680831108848958314454894C4248149420460882964C4C02185044694484D28428C121402F344C2141F29D142C1278F48F417132C34142574D47618E212341827354E46671146775643F646212D9C3A
+:80F580008D845564282FE4E444BA13D514D4DC81628420F4425446D241E526B22419B7A4F5254B53D82434482E651B18428A44B4C7C1C84EC82CAC62472447A8CCCC198D988F214D9142271A1721502766341317144110F14192672453084E223110061AE281C492CCBC8458A64B242F28819214C5724958CC9D895C245C142CF2282E2FBE
+:80F60000445248A784255482E788421C384AFDC32EC441E5E4C2F24684AF125A42C346E522F2EF757014D2C41294134A82A41429E525D113F542542381C3546B312ED41AF181549F85F1385897128AA14DE314B9A87428FE78AC1373D8DC4184AC5143311549E2417118AC118781384C64164B681D82ADC88FA8C4A8C65888876C30CC856B
+:80F68000E8C8B42822E822788674CF4C2154144001144083C481C081481C0888198498412C1A010080022815224822482248232822088234822460324002344022482258280082F08D171416F22125F021658FCC7445F544465F55E141D157F89A883F18F8A8987F11B9C2FFE4B21F19E931F99A898FCAD9DDF1C8C88D98EF85B888B8284C
+:80F700009448CD4ABF19F88882AFA8FC824AAFA1F9589E7F79B852F174B6AFA1F9B99B8D789FF8FACA8885FACA889F32F21A588D82AF88D8BDB89A5D2C23742C7646D414B824F844483A5364FFF74B7112F2766416F22464CFC6F676646F45F455454F41D164FD8A9C3711AD387F51BDD2FD74722B116BD12FA9F988ECCD2CEFCCFD8CDC54
+:80F78000EF8DF9CE88EFA8F71A32CFEFF71E24C741CFC8F8884BAFA1FC5898CFCDE86DF952DC8F21FAB9D78F89DDE4724AF888888314F81C5C8FACF8CAECCF88B89CDDEC34C2C76E6FE4F686844B8AEF8EA633CFEAB14A44F351471F71A5111F52F24CCE5F75F552523F35F5575557588FC1D833F149795F59F157D52F25F551514F59F1ED
+:80F8000054DDAFE2F18F9DEF8DFC9C984F6CFD8A828BC62B11A7829F33D14AE188C4CBCFC5F1D21C5FD1F4D4944F61F5BA18BFD3F1D8FEBD2F29D4A8F4CAC895FF5A5EAFA8F8CAE8DFFCFC9ADAEFACF84642EF62F4E6844F28FCAE8CE5FCBCBCCD3E8F4546F357477F7155337F76F24F4F5F75F543413F35F557577F7DF55B993F39F94B98
+:80F880005B5F7DF557D53F3DFD53537F7DF557DFBFF6F6BFBDCBDCCFA8F5C4D6EF6CF87CEEAF27F67D6DDF71F29A8CC6FA42CACFC5F5DE1C5FFDFC5717EF41F5B8323F7BF97C5EFFF2F2C3C7EFECFC4A4AB5FF5BDFAFACF8CE8AFF7CF89FDFEFECFCCE86AF6EF8EEEE7F6AFEAE8CCFCAFAB4B4CFEAFAD2B7901210022502000024004002F3
+:80F9000044400481304882817048845148493148418304800122846184C048418C0400484484448CC42482004C02CB5850141A521440E14166345014E014011C01275411281185528538419882442A04178200814100444D412881C446824243744CE2886234848D82E034082470482252484840F868C4D034F4112485F311248F14F1116F
+:80F9800024A7141D24AF14F18124AF16B981F24A9153F84A9153FA4A9153FA4291578A2DB15F82C4915FA2C4815FA2E411F2254ADE211FA2EC59C2CA9E24ACFC91242EC31F49D238F891248F24F89124AF36F98124AF36D941F24A9319F24A9351AF343924AF243924AF24792498924F8284F9244A6FFF0A45EA41F628421E244AE1C132AA
+:80FA00004E1B2185C2646E14159C3A5F81364A43533A4B43144F82E414F32648984F8285F926C81AD2A6E41542EA41C24B4CC25A1FC1E2A2C4648D524CB248F11124AB16448B1617414E94CCB24ABB15B24838A4AB1443BA4A712488F9B648184FAAF59267608882480000000000810000000021008008001002804108000000004004006D
+:80FA800000000040017F2D47D12441A4214418414651864C21088388C5181CC4184841008001C24440914489349445A8C241844B28699A141084D81882881268C1182481B0110422848D4449184CA848413F310E263181219F2201269A1424D028A1140025C2145522513885C42684428F42942925D882F42218286521948130226B24299E
+:80FB0000C141217012984243B14C5186290E19CC881088D8842234848022342426C528FF8543C134538CC23118C72219556249E12138448928761292456452C5022C522852E0855A2E8A94124B2469246548137626A224A7228E44274430122B484C32982D268C9C184B1882A3122894249088466C4A467A24E818B618725C06349012C478
+:80FB800021104408841880418871110811851404F048241140D81802859184858108456849262101C470113844842244464108C091844A1204400444415E2800111440922147144481100210014022024825048004001502004502002D8100107811480288190448215022128800002260226FA30A200200491118133315934151236028EC
+:80FC000019924912218F110268C0220000264282149824800122250149C222204248229818422334848638542AA414002016E46A0800110069714D12011D149341021150121528022E5944484002001429420284440013082110480A23820888460825022321250600A024B0F602906100302110541A1016C12121882846221102212C0280
+:80FC800068A08100102244962160812168143024130340984121182F4482948483988480056022D024F3FBC31014143418504948142818942482144944C3889C236841800A4682420110451854480044174860411224004A11A41282100241290118A44425B84848046F390322146042510081421428118011024B618012028C814201686D
+:80FD00002044088142120080028116C885902584421062811CC48800210012442870BE0D111041022422412142001181200990190048141004164828A51212403A8400902988218112304110010042C861C248224A0846084FBC0819421174284255E1506942200233C812412CA141B08913063E48224683E214C21846B845210287448CB3
+:80FD8000514241532892148D8216C88DB02564D42A241802484F88241892827026A28542C3068FD20641441416042006221B41851101152834818DA4178320018214400400818C711804800800871212248021011214901A11241A44A441830481478800BFDE03000041444150324800AD12C0121028010000222800002508101812011667
+:80FE0000041002428001100112AD86A08426080000F0618620820212172111A48C04A6183382C25431915018431401191C14014D224221E1282190142261212C62883B214423081890828388442118010041614212222AF4EC67208202901561812914914A25025027135192841C01004603284002407C2A02506940064C52221810021233
+:80FE80001012484181D8831822081082448282F4974950888B444A24051141A4205A544D864F86AB222200844C1441328225E611A1314BA9CA7882020015D11181529A85B848B5483C61618242202178847444B424A22326044226481444721212A213EF9D0E00002542044048020084001088048200110000C0282400000000002100214E
+:80FF00000010088004800400F046B524818C25840500004014C4242229826484000024901213919482A8210060111484818C642419141201400844418D24222942020000109212AF9E0284801501002125024004284800C0114111104284011C0841209241350140888104244B18182DA200400428890440A814800821F092284082040008
+:80FF800010820240042810081400485012800188000050110025082924018800005062800280040040120249F1392100000020010024241002000014000044441302800280082400000000C800400A0000420000F0C27290188B445AB44201240011244514B424A222238281149141400245A21143A1A98A280880521150218518B848A414
+:020000040001F9
+:80000000C5234C820100504445B424A2222200C908401242B214D1D3085088A04429128201482100454CE886421218080025513221A011A0A84400404101D08811A24482240010025044A022480000101216B21701211004002410022481800442118820020041008C024200000018102491228001111002212484C048004A0200F0D78825
+:80008000002301148001000000001100200400C021004440020040022100005022884042088C84C41200000000FF480524186C612128215022464852221028E484C441428D881146041511140547428C8292448302001022C1124496A1281653222CD883180281A4508A484028A14600006FBD0B200115512247211622522300A12185027B
+:80010000424814421332810044450415114484A2222048421212E2210121292911224C4202A184424E12A1C14800104434D624231122810190120021002484A118B5091E41480014702101222221243042290140222158222C18842142022121704882044A8428048200412FEC056F22F212222E122B11122B11C0123592821E111F11B140
+:8001800089E989F848888F18F44848421F9454111C548995F844488F44F424444B244F4222E24202286554442E246F22F212222AB192A1812B99828E923592822F31F111139B989E888F84B888F44848424E4880548885F84448DF9B086F2252262AA1131221405122213CF1131119F8918887818F18A44C4214154151818588F44844C586
+:80020000B444A2262200405444286F2252262AA1131AB88228485122212D131F1191811F897818B888A44C420040588848CFB1050000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000015
+:800280000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000A0
+:8003000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000001F
+:80038000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000009F
+:800400000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000001E
+:8004800000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000009E
+:80050000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000001D
+:800580000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F009D
+:8006000000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE42B
+:800680000F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000000000000000000007F
+:80070000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000001B
+:800780000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000000000009B
+:8008000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000000001A
+:80088000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000009A
+:800900000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000019
+:8009800000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000099
+:800A0000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000018
+:800A80000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000098
+:800B000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000017
+:800B8000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000097
+:800C00000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000016
+:800C800000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000096
+:800D0000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000015
+:800D80000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000095
+:800E000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE14
+:800E8000000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F0E1
+:800F00004FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000003
+:800F800000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000000000000093
+:80100000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000000000000012
+:801080000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000092
+:8011000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000011
+:80118000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000091
+:801200000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F4661852581549460828422B02421614236
+:8012800040424EC4240085213858122744189091899285189B946034001E28E088C44120123424411400C026004C428202308812572730221C121889744834446E1449D434072214C46E842A24921237434EB2F6921888C9C8828E412D3525C29789B1694894CC8C68B41364149114C969C487442E484E825AFA1224B8364DEC147824CA37
+:80130000242B416D388E121ABA122875C2F2B928002814424240B81C34242C46249121414228211214106288884528C44112348E2482681941C4820026018908448314247A8242015C1134A123922261446022128384F46E36242A64812100C024001981214244C884E324022921C449124E1890847022A4188951488C98844814344258CA
+:801380001130D4C02410A441321A6A828442812044CA320092245F350900815049468C848244040000002280682A0050221A18015012001008118130418501E0820444440000001E22800800215718106114508100000028008002412564423218001A08002114181661848988344800810089042084020040441404388029088AF14F2AF7
+:801400000080010000000000004400000000000000000000000000001C01000000000000DFB70D0084002341040082A0144C4188721118944422830870840A6218222240C528838A3481008290482887141342028C28021C01490249283824811888F0A64714473114222771C029841C83C5818B1414402244022C22582C286048484D68E2
+:8014800024144123984129CA4218C02282172197411FA24162681282383242144004108292128C2185425884AFA3475124148114218D31811C02148B1420D12481C422197124126482830860884C84361344238A54428CB69A028A0216329C17A146C826932402E0843821C0117024022E86981283A41281416DF1C01160221644024112DF
+:801500004A21881821048110084A189422C0844D4289022002118E210048112918418142228831812E121A02004100007024880188841E54302428C116040028148AE214082021042C09850114A28143022E4828220012220092228281822100130100B04A9841252191123048122008F0332220C111212322D2344152782A410A3C18C872
+:8015800043414FA11844BA34E4214A9844C0417948548241B3A13425BC527822A6812382792223012024CA8699D11C818401CC211824181442A8C142861CF4A535C024195148290119114201A2254142E8143142961802E984529282846C9281462242022C11B82238222728182C028400004C19321C42304A167C820100A944A881100427
+:80160000CFEB0E1828214C8242046D283943A88413081044D42449E811A218E042041C4464C28143C2196816844524A128981B2823612820841AC119112081C84160412949041242C28918749109F044292489118C113122181400312604126084224E2211AC344181214D182C11A4121E289210210580614E828982A141201104008002AF
+:8016800000004866AA41846F3A02852454C122002548418912A12460128C8464493013444026018988018C42180418130118850217A48C218108441582C2114501142822602840C418242868FFDB0F1100101124220100200843410141842002501444200282408902218002001018484184814208A18301222184004481F08A3E501447F1
+:80170000125538224441242A1109112250144C849514248B126C0245B81154486788C43226CC388962811A42220410922D1AA8128CC948455141222894404808266228814416382C1E4889F4BBE6000016581812A71211181902482D81901811884D4814481C8204110010229814860112181222122C48180818C01216C411401281210239
+:801780000020848422F241BE00830418101A044100004B1842002004819011288582420400848184910011008C1868848111401838184008834128140880016B188081C11A8181181880A1A11884888028C1888302167184C19C2C4291811187222002822200822230B1A226621A112A2123222202181281008400282868FF3701004044F5
+:801800009424C4104A4448A81290184C2211444C2121028C010044118E18871120080018200484181400008001844082011200F0E69A40C524800221144901921C880200A114C09143528686810824F4702A216812C012264122022A5881180020C8881100100822B02201004810E8B70C2890244240B22804CB42C0288220881264824157
+:801880001244A24426588422405884C4842A281C08292828140A8800938A04400800008423118845885412BFB7098422812608450821128420022480A38116288863111A6248228C195814288002840024160248988911011200921218200184222001528283F4E6890016044381210185141226011998129081251153122788001582588C
+:8019000042412840031602258202C011128C028A8202819B21142800841200841028C218221F270D44002147810012002308126088842041280820010020118214224182842101100890188011482801800898128001122470360B84D014041440C22826810244902444138812115422904961924C8182192108008E118170828898422023
+:8019800081810A82404114C8284A02000081704228F1E52D50443885D6C823D18E714C982647942B311F81C1A813D146B81AA482A95B8A1E48277A2FC82162212F815BA454A7832E224F28EA83D428A952A728AD422D822C61388F91216E28878A121F81F948112A81E98361811688C12885B818638160811AC79189F642FD80E141C418EE
+:801A0000521C21D143614183D24C388A81A81AE142F8161915F814211F48E18149F118CD4F1839281742435214CD111185338184842882321938211A23D2119278871AB21C3229281889B1589818882189241128E2A1726238B2902147824D216352EC26C4228D1A2F41238A2AA2188286F88924B6D141D13E9825DB835B381FC27285B280
+:801A800088D88BC226354CA928367898A28394322B887A91828D888F81A9812E89288C5889948181C028A011269A128D185846B84824F1598D100111104112011124112440022C022400112811100211901310031828182814009012000000000000000020742F4FB134F3343D8F33F22F25957E11F75D537F12F26744DFB3FA3B23AF2381
+:801B0000F333111E16AF81F31D9D8F31F88F8555F5149A7F5BFB61C855F51D895F52DAC4F132143D1BBF9BF9F8FA2F8BFBE1CA2B8A7E792B882F29FA812B9F13A2233E321F3AB288D119F169511F13F3A1A13AE1C381A1DD8B22AA4A721A084E5A8F87B7B8EB22F657B6141F13F3347516F33F3D17E116FE7872FFD3F26B68CFCBFBAC2E63
+:801B80003F3BFB92B49E948FA9F93F9D1F13FB8D8DD5F49D1B9F59F9C3C99FDAF23FA99F12FA878B3F23D19BF9B5958F8FEF83E2BEFCA282AF95F5A8A82F28F2836B9F13E28BFBB8B29F3BB398F1B9B19F1EBC31F3BDB583F3282C89F1C8E88B228F2B7B1A321A87815AF52A288BEFAFA3F3A8FFF011113E74DB33DF42F21C1F4F61F15AFC
+:801C00005A7F42F26E69CFA2F222A43AF381A14F69F11E98DF7BFB1F17B7515F58F8949A6F51F87F4D9D8DCF9AFB2625EFC2FA38191FA2F3AB898FA6B6B2FBE8C38F2BE9ACECA9E92BF8A1D38DB9BAF338B83F89FB3228AEB11F9EF731399FDAEA83B31893188F8DAD118FA8F8222AAB11184E58AF87A7B9789F454AA1334F43B331F33DF3
+:801C80003C16FF161EBFB7F72726AFB6F6BE3EBFD9F939394F28F88616ED9AFFF3F1B7B7F5FF8F85DFB9F99B11DFDEF6A9AFCFB2F3A8A3FFF2F83B1BBFBAF3BB9BBFBDFDB3BBAFAEBCBAF9E9EA2FA1E12BF1BB939F91EB8BF338B83F89FB1A388F19FBE9699F93F3B9BD3E38C992188F8EAC118FA9F9323AAB118D184AF568688FADFF4836
+:801D00007A4F8E07000041302412200992200184441285048922091185144284410481888121800829498841A882848884608140088428168822110881F02E56A01A4449819214441884698132221688285842922D21112D94135B42538132A14422C01A1CF221828021088225328123022A08881122112A01000000A901A0414A43F19912
+:801D8000FCC0421F4152281FC132681FC1324A1D24AB141D24AB9419B24A19B54AB924F44AB147822F14FB25482D915F82C4B14FA2C4814FA264115FA264191FA264592E4A9E242E5A1F49E222F4912485F3912483F49124A3F49164AB141D24AB9419B24A3915AB9443B24A39242B944F8294924F82A4944FA2F432B7C05A1F4196481F5F
+:801E0000C1326A17C183D44196121D6C8F44D941B24A9B258B9449F448B145C8B15F82E414792798B84B52B85F82EC11F8254883BC21654D266B4C2E1B17C92E5A9E448D431F4932488E24AB141F49B64AF18164AF44D941B24ABB95B24AB9B4344A4382F9244829F9A6484AF1245ACF950B84000000000044001800000010021880080030
+:801E80000000508200000000204104280000000021F0D33E00384100831218341811260830181A14042C91141E2410488808440021C28041488A04122001190100818C0A12D022084668815284842018F8BEAF008216183428200100204208860855483481A480E24841388400811844AC6484882E4414212544089C02008C01121284132E
+:801F0000012001C012981816019F980CE0844148848242088901C9226282841A0CD1241F48D124439228CB181E88436848402A21C8481F81C488C1A714212744811840012041B83C28219111290A83351852A41E8A1212F0AD8900284901818418441001001281413014400800000000490421A042001200871212008100100824000012A5
+:801F8000008884EF760A00A021414481503412230420011121824482145058A200404A542460A2009684081C490400112384A286200410140260814C2828C448AFED0B41E042111209136182166882A08118898CAC848847811B48284113284FF183644239A22412A01482205C2249D252C1242E1113A884AAC1842812200856A148830471
+:802000008181242266082AF83FF510041634228541D4180185160812188C8988088A1184581486F128142A7864011CC2286341A414890A40E222080082821A820822420042C28121841068488014F8D3BD0080224104902813E1212224084842172482C44E8122001C4C83C84280042440022CBC8411D441F1A1141D341148825522868158
+:802080008A28C411604400841229E28C02E8AFDC014872805341450169021481469288328001C42A84C1811686D118444464912644110441150C49820447240000222810028342418818A22418272422850246F847B5004638182180412824A1128012342C1227828814208272289224124001A018811C413821C011608342184C428102F9
+:802100009126144428120218181008C0225828BF8B448241544100811224840081122440210400180041408802220000A1A0214118111A14260100408101522800A0811004B0F20C522A31182953418D112462842A41C82A924301AB1242808432B12A3114C304C54189B2A14168118544588247124A614190124C14222112392421818CC9
+:80218000511289853A12285022C02C18281F21062144450140941844291101488184291181588528125084281144881A120441004C021222284911A1121524022200110020014889A1492820C4488F9E0E41874280014012981441001841183014284860412051421088010098801188014C02D889B8148428120880628800100490288082
+:8022000011086B1DD021E224410624C11149418B02AD11341C511819E922781822C212848E1841A28C01881A041A482841391120112211763212283112249146911A1D228140820180012218F076C7005082484110A4120090288400321440711144343300111B24F0A114448180014A11A1124081B241A1861E2114122021011021210233
+:80228000800100F06A3A40011014381283521210B2181292242142418180210241854208211484122A1111C7A12850168391441100844119029180016C231248E222014C0B4487429F9D05869424108411082844284100411888302820020010844118244118410814410028A8220040182802000000840000A5B18D4922014941480884F6
+:802300008468E08461432001848922A118458222C8244308008032814488430A4028A4414110648841008230111852281A28A11480A12181F0DE2E00181440C11116011183011514117821444274824211028182818100100881008222A428213562688C03A34162117022098400801282028092243BE4002140084110C4184428008484E8
+:802380008382080028221440548183618226051A8828018100205118190860111614088118241281188124282011F29E2F40089C84C11180432132184064811C1214848108111C5141A9031909193883823100142B8212478259C14120044F14629242204104194241420244005042F024FF2062486381D128C11819B218E1979218CF25C3
+:8024000063811C21A15293381F24390B47115C28918A95681189F18885B0899111442AB98BD238014E141D167BF86CB281B111D194C228181D988F8181D3898181E282A9112B1218AAA1114772F0F57B2464672185648194F3711859869D16636282BD31413D1845E182A88A16C8417587322947F28C5254849457822A7112F1888686D1E0
+:8024800048022845F61E221C42B469E4C2E298FA3B148D12169D282A729901142B12A524423C12412A02AF82F292A67015E1825791E7441741442E161F5212E4C102229FA1525C97C14F41C33EABBA123AF32A146F8993B847482CB84932112B354FD9C2A816E98129E91769411B33132261332F99B95E7C6C021715B11E4331A4125727FF
+:802500001662212483B528B212028F8151448F9C06112111001430223022100221501240218812011160284424D0215848245024812240010065012130225012501241108412044100F074C7342F22D2124231118D8BC555FE5D371F14566EAFA4F6293313D237D1BFF2B7B4DFABF9AA223F1AF234166F41A13B1B1B4FE8583BE5F6171745
+:802580004B337F437116F69A988F89F1BEB4AF19F114367F7153F667613F3BFBD41ECF78FADC4415F76262DF72B281D828F13B12C5E625F62236AFC9F92626EFA5F52E1E6F635144CF83537637B2343F32F2177A85F118113C781C7724FF11393F15F42A366F67F73931BF11F21F1737B17F8BFBB53A2F22F233337F63F116342BBB8B3B58
+:80260000CF895915DFF8F91F1FCF83BB22738EFE9A9A2F91B9BAFB9A93FFD1F114366D722F21F1B3B36FE9ABB8EF657D23FF5A53CD15EF68F92A322D26CFE1F154452F62F38A8C67616F8564A223B336F2382C6F63F34C83F035376F62F61B1817C1CFF1F11D15AF91D357F3496B4F41F16A6CBF12D3B9D2D551DF4F7AFAAEAABF3BF92293
+:80268000B26F727127FDB6211F9AD2D5F189899D8A946F12F2BDBB8F99788DFFAAB9CFEAFAA8A847E27D277F527415D677F8BE8D7F58F2D9E6BF51F34B51F7518FFBDB9AF11B39B5F957462F22F3BEBAE5FA7A7EAD3A2B1165F41C184D1E8FB54AF33236EF63F319184FD151749F31F131397FD1F37C6BCFE2E347F73B3197B14FF17115F8
+:80270000FDA4BF6FEAFAB393AEB277723FD2F2A5A51F9AD2F5F98B8BAFB148F9BB299FBADBB9D8DFE88AFAACAE9FA859D74D367F72F337377F7AFAAAA87F54FBD9D59FF3F14959F7D18F5BFB2932D5F81F1D3F35F42232EFA8781EFA52442E2267434B238FE3F22C3D17D81002004110040000144024C82612285048001100008D24418149
+:802780002A08004302002B82842A2841414841480124C0268424800281D03C08472228C14418129021C02C1828811100208232212153825881541518180111203288002411142841190484001800150800848184218002FF65022CF41124A5F21124A3F4112CA3F6112CAB161D24AB941F81B24A3915AB945F82F44A9157822F14F92448CA
+:802800002DB14F82C4914FA2E414FA244A5E214FA27498E1A2E559C24A8F4DC24A1F49C2431F49D228F19124C3F49124AB141F48B24AD141B24AB991B64A3915AB9443B34A39342B94478B29F93448984FA2F42693C0581D64A9F5112423E4C12276113C281D444CF911688BA45B21884F83E4147824F842115F8194A27F8384F8245A4E34
+:80288000312ECA4E215FA2051F22E548D2A4E51CF224121F88C2528E64CD538AF24C118AF24E111B68EB121B68AF42E949F44A211AD25AB8B4B44A28F342A4BE483D842F83C4844D5A8F83038E28820000140000440000000000218001880000400100001A020000000028840000005012F0A5CA8001008441001244008444818483011078
+:802900002811948400104808000084328001A28459012812288042182101400A100840F53BCD00434818041A024919088C010082411008220090283021009420028140011C424401001C8844814421514881221230182A05894219F836BC00C64808841E24001844450822448C58848C0130281612348400AA015018800240D91803624033
+:802980001148012681C421496412831315288251288C215228265818C42F810B18444004001E84818001810000840000608210114808001008001311A42860412088010040880100A04100004D6600000084003081810011814004890242400100428440821214081012015024002849014008120000000000AFC30C1D2440CC122290118A
+:802A00008722882002508240C84810C424178242841428C018102111E1814202481110428241A1428148802481449842812A94184342C228428C04FE6AC024406C214008221081021009818460822814501814008C4148012661C18421001002274120024604800185020081430200006F250911008002191138828881002184C04410142A
+:802A8000E4842204800248002C0128002C444101401221C42818204428842144282601248322C448F0FDDE00235424184411101408A021404108702402442084381800000010182301809244818021982881414781160887518C0240044078188211F825FF00460800448400400841431244381816D12841382124162411541C008A010060
+:802B000013022850844220442504004120021240289418006602426F5D0510849128000000400880181402001608400150A446C42281004008000010082C0181002C08204204808201005FD5042420B11A4214054181008440455C4823D1241118282164498141C141A0388110282281024942142854848AB428111804846041168812C476
+:802B8000448381C2182A2131485E2200444100100800811A0280088113C212418D21001190818998461002244008000030110021848921C1821508100800C04800CF89090040342470140122441C0294009028C02460424C0100844C428802818444242002801408814008000010840281B01862488309AB91C02800201152280010829484
+:802C000044895424842484248C11483828846304882054862200251C440850224220110483184818688881901843081084814474350940440884450241842184901280518418441144002890284C41082081220120410481441281128522011220412401402A11088110783508148100418C74140160811C4448121C084116E241642116D2
+:802C8000242135440044491102C428901240118C1418522414004342C342A021242C04101854481881B0660728800318291288828202288445022032288D223028228143022628123828220089120429022C028C828C0200228C0284C0282A01002A051A14F235F240A42184418C1294224184C028005084204104C482844018440400842F
+:802D00001041410800804404406641831248341C301800209118904890484D9C0010C5481100A5524100121B845641311600198404484901290148824C11A414C1461431164A2194484921D44211A281284C61411A1801441A4834524604824014E453038624088302812284301A12A9011880538624182818444502282416881204A02139
+:802D800023110112008428818C921883022818441826029018000024F0D7562484414D6140010045410664168232110014812C04304242892188181408008501508649C221281683828442A14124648016C41A64244472485042F0BDAC10B48822121414FE14224165B11E12D128D4815883455644E54E5C574E4644124C5222656441266A
+:802E00001CD44412D688F4281A501612405428AD242E56C5322A8F48D258F2AC181B221081057E163042A57828F4488883715CDC4AF452784074841469849F33431C437429C21A8D221E188F64B51451938B112859E18676167812C8484F83F144488786451A78984468812213C14C154CB216B14C42B8447452C92C178147A18CE141F431
+:802E80001C12AB85897198D4281168A116E6444118C44C1884CF270F3B22124FD1D24842EC24F2281DAD28CC42F422592827118F44B4187122A81387228F21B128B12CFB2C148B4487422883BA146682A37728B414C224CF217218D246F12164E01262A18932D24A8331322884AC73164CF8142C2D886F42F3881843A1513E748AE12814D8
+:802F000074C80C112213213211221126122112210234C02280022880022880925128584C8245B42205481122112A11A1121162114A18A186A084414A1A8418841A242428F49C8C242564148F91D1DDF51D8CEFB6741F792D51A9ED1FBF94F169189F9DFD4C174F1183F11C1A3D25AFD5F5CC8E8FC455CCCF81F5184846D65BF7494FEFE4AA
+:802F8000F41C5A8FC4F4445C5FC55488EFF4F456544741455518DD17D7E17F74F5998B3F1DFD5D745F5CF2D95BAFA7F5DBD9CF8DF1D87CEFE4B596F9D652AF4DF14D44CF89B89CF88884C5DCC6487327F5155887D29FD1F54D58DD1A6D12F571295AEFEFC5F15819FEFC5E51CF91E361F1163E3FD1F15A5FAFCDFD487EAD3C8D18EFC16357
+:80300000E4BFD85D71AD8E8FA1F74C68CD1816F16C4CCFE5F55D5D5F5351D426F34F5DB7A3ED1EAFABF8D3D9DFC5F7C4348FE8F19B9BAF8DFFDC1CCFA9F38A9EAFECFE9E1EEB1D9F45F5D8A4EF49B9CCF91E16DFCA43D153A2731D281B224D314FA6F61E2AFF42D2D2F22232AF64B771F7D9FBDFF5F51E1FAF83F33E1A3F73F37757AF6FBB
+:80308000EF46F52624CB734F66F7662E2FC2FE341EEFE2F276126B624F82E3B3F2747665F2171D5F55F72464DD26BB32EFF1F2667E2F2DFEB7A6EF54D2CCCE2E2F2AFA4331D845F2A2BEAF63F14AD2E3F4E8EC8F43B45EFD18D4CF64F5FBB5F02624CB225F43F364354F17FE24327F32F32E212F72F226263F77E717F7DCFADFD5F53F1744
+:80310000AF43F3363E3FF3F373772F6FFF6A742F43E323F1242667E62FC3EEE7F7BA3EAF27F332748F87F514362F23F34E462FC1F17474CB225F62F27B38AFB3F3727ABFBFFFAFAEEFD4A2D11F33F36363CE88496C622F26F7EEEAED8AA7448BFFCB67CF45FD5CD2CF44F5C1AA100200000041122448C0484484104122091242400481000A
+:803180002100100441100440D8244808400200244002002009F01E43000044000000200112211220110200004008240040024522014002002502A1281800000084000000CFF50E4D421F4152281F4132481F41324A1D2CAB141D24AB9419B24A19B54A3924AF547924F8429147822D914F82C4954FA2C4814FA264114FA264594FA2749870
+:80320000D5A4E449C24A1F49C2421F4952281FC932481F49324A1F48B64AD141B64A9961AB9459F44A944B43AF44B924F4429447832D944F8AC4944FA2F4C152F0244A1B412E5217C14B161F81B46451816E1215EC467981BC4A9B248F24094EB584ADA548ADA5218DB549C5A18CCCA42D4A8F59D224F598254F12758884F4912C2E4A1F5E
+:8032800049642217C9CB1213B92A7111948E1B282F4279919CA25F89D2427894D84A3AB4AD8443F94AA463FA48144F22F1C35640280800000000448002000000100218800800001400848004000000400428180000005012F08A42000012800224000000604100404608000010A41418490240022411008002800184854108814048040074
+:8033000082C0226FBD042068C12200001881C021810022004008008110040081188011880118A4120000844902284004901110E8C104C01989F4AECB14608C812800000090212604200200502A001230840048812A1181119812F04318A41280028011448862C244001C01841E4C24881C81D2FB0600492101280029410810083014005025
+:803380008400400800411218440000000000008128508100811018040010C8483FAC0100001828830222001140080090281242000000002004004002002021820400001240180889014A028344F8D6239024004149021200800200181884100400834208302485746894244782228B162743498442C124412881188CA1214228200180216A
+:80340000312822524D181228F0B491902400C0248002288042010040082688810483420820022E48284782281A64434828112880C2182848324828000084C02832A0121848816F7102004024813218000000841218004100000010441C148404831212042144440012160800802101128901814A7144082608AFB9085084800844000020F2
+:803480001214149418002002252401400C440040983828200115081281818982012181840090141008608100BF5C0C40D848228211020021281841182062411800142784608526021A4408812082248104848004000028498102C018834208001C334118F0A81C8001608825040000840020010016082A0122004004224A212204000040EA
+:80350000820843514200001800000022111128811F4B0112414942321425040021898201491134381684412882538412464842A84144225222283E482248001548A2188116982200122818403828CC0100224E1810E8120700818C02000000280018008001144828801244440884C048800118000010448C811242180818001028820138E7
+:80358000F0543D301212181A02188444C418C422840000490290484982F444284C324400221200A025301430148C1228028916A421302889810484808202466482484658618002491242822221C2124400004122800126882211048904122A311CB0188291120090128C0240982880C6480048408841088091284800DB370000000000000C
+:803600000044400C00800200282A01100400221200222424000081400830480000120000B0640B45684212411A120418228C02008400220044424628025082844528E28102362814B828211214321860816810944800002002444883820420F2958780229228104848841204800100404438281018143424C148228024260400621200A02A
+:8036800042488483041260846041B01C04844212008944B835081844448301441244808282424404388422200300250849A2411840088C342489024CB42231284008004844282200128032642608284822F0359410022012848212020010C2124508004018A44248484A01212418E041425228424301411820311442183200121A04200201
+:80370000806186814D2812225F210C86388800AA012001001004104404850444848C0200A02442200400424008438281041028B2280481814880068114001C22B5370584238114143418260C384122C480022422C52202002180014BC2410020E29401608290421222289024001846043884428C31488084012548E4E8012F2372B4F82CBE
+:8037800034442E824D24168402A0228C41D4481162428902CC92188D6C165C484CC42432428F61B11421C214A0248C654343F322286B112281893248184F84028D28587048084B4289C2488B721361468D689CA3415F780B188212EB224F4182F128182B11A4C9422852844084013A322284B06CA622CB2246F848423E5822448B31288BEA
+:80380000632FA39128409414D0EAA3143E1C2E688F8454488D64E08272180889B14822F22424425088411C7464F88A9924444C031A91188783497224F434343644841212149C2C6742C51CE8423264F0444246F82C424D244C92648B668CB478C41A8D44724E782C67618F8222E183A244E042A2527E186A31484AB51465841E184E1883AE
+:8038800064818F868727366889F217D4004184401802A1100AA9014C41C814841880011800007048044220040042006148002011E48104001A041A0440250140F49DCBC0222982D2C862E82C42D4E8F11E3E1E224D183E1A2F4151EC6B11CFA1F112184D122F81A1311E182E588D188F8242F26656EFC3F15C1A69E483F11C5C8F21D1C6A0
+:8039000083F534541E166FE1F314166F2337124F45F358184744CFC5B12483041E18C5A441CD148B42CF4121D444514445EC8311F8623F50646FC7A5114F41E76AE221E221F22A2EE5FE3C2ACCE3A2F22A284F61B116F3282A214F22B312F12828626F82F52C7CEFA357464F6CFD16143EB22F42E283F13C1C9F33F1563E2F15F53C1C2E66
+:80398000162F65F71E2E6FA1773AF83C348B374F42B244D284564C2AF2787C4D448D284F426282CFC3A326C7C6CF66F46E6C7AF57E78AF7A4FE221F31674CD2C1E348F81F13E348FE3D346A111A7816C932A28CFE111F22C2AAF82F238222F82732C7824F8726C87C56E5C6CF426A2EFC1F47C7AED488F86D4CCF7487B6D76AD784FC1E726
+:803A000065F71276EF8151444AF65C3C8F84F24424CF85F144148FC7F768284E284F44F15858CF46A3558B378B158FD2E7C3F3666C1AB16CF7DB57244F61F23E648783CFC7721CFC3E3C8D2C4F63F33E3C6F43C232AB318D2845F63E18CFE3712E7C38BA22F1381883F67C6CC7E54FE6F52E64CF27FE7E7C8FEFF56A4C8F86F56C7C8FB76F
+:803A8000F71E7EBF82F7747C7E762F61F73E3AEFE7F35A78CF45B748F42C6CCFC7F374748F45A764CF85F714548F87F574745E588F87F578188FC7E7C1F5266C1E52CF82F4DA59A012A012A012901420222122011220C1241244D048028F44024E24C024184C028118302200200223022AC148402842088C0480028D24A024B04802DF2239
+:803B000001400444C1001A120400100410082816280418008440082E1812A0258412221281100800221A0400128190182064814008F0985ED024F4112485F21124A3F41124A3D4C1B24AD1C1B24AD981B24A5985AF443924AF5439242F147924D812F924481CF9244A1CF8244A87114FA264592E4A96C54A9E24ACF491242CF4912485F2EE
+:803B80009124A3F49124A3F48124AB141D24AB941D28AB9451AB9443B24A39242B94478229F92448984FA2F43E7AD082F4116429F4112427241FC17242D2417242D241F2429619F242A259F24892224E8347824E8147822D916F82D412F9245A1CF826C85E8123621D67A2D651B49E214D4A1F8D12B491964E1B28E11B68E3B491324E1B3C
+:803C0000212D841D64ABB41B21AD843AD44AB824B44269832D842F82D442E9A2F4583240288804000000008002000000100818800A0000140000480000000000280000000025014E881004400400200112004008001228400400490441188C8401400800008100220018000028208214080089F4585C008A22080060420000001004000052
+:803C800000814400001012C82400480000000000100881C0182001404801DF720B44CE28884400802201412002000000244460814486044440081128818148420081000010042608809218224A4148021489C49E000000004400180010180480210200004800122C244148040000000028001800100800004008F0D9EB0044000040080099
+:803D0000000000000000400100000000004400810000001008180000002200BF7D01008440110420110410488441044100122041082001100200810022000000001200000084402801009F7509401408400481184400100441100480011210010000001008C0240084000080018180011008841828005FE3050000110000001008120000E6
+:803D8000000084001240020000000000000000000000000000F0461F00000054000000008100000000000000224004214002008002288400000000844200008437FD24008504120000840010120400002006400800124800480000004400000080010000880000F0612A0000410012440012000020010000001004441400000022004181F1
+:803E00000020028142400800000000F065572400C12041210140880100C1000000420040044119810241482100210044280084100810080000000081BF850600400444400400400200180000220081000048000020024014088022028084010040A8840000D0A7070000200185080010010000000000000000000088220000000080020051
+:803E8000100800008001CFF90D0000000000820000000000000000000000000000000000000000000000002F8C08004100000012000000000000000000000000000000000000000000000000D0290E0000000020010000000000000000000000000000000000000000000000002F890400410000008008000000000000000000000000000F
+:803F000000000000000000000000F0639900000000000000004004000000000020018200000000000000000000800200001F17020010080000440000000000000000100200001002120000000000000000180000F0D7A9000000000000000000000000000000000000000000000000000000000000FFE40F0014004008000000000000212B
+:803F800000000000000000000000000000000000000000FD5400000000000000000000000044000000000000000081000000000000000000EF1D080000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0040080000440000DC
+:8040000000440000004100100200820000000084000000000000380000F03AC80040010084000000000000100200000080010010021800000000000000000000008F3C0B0000000000000000000000000000000000000000000000000000000000F04FFE00400100800454000048400400210044001002188088022180018840080000280C
+:80408000840000800200009FD2010014000048405588281082044480022100448002214818808802214818448828842148408481421882041E148002211A01445C030000000000484001000000000000000000008002000088000000804208000000F0FBB60040010080045400004840840410024004002180018828100218800884008436
+:804100000028840000800200003F56010000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00210000000000800221000028000000280048000000484004281082044400108204440010F22EAA0000000000000000000000AE
+:8041800000000000000000000000000000000000000000FFE40F000000000000140000000000000000008002000000800800000028840000000027E8000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000002800000000000000000000000000FFD70400000000000000
+:4B42000014000000000000000000000000000088000000804208000000F0B2BDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD
+:00000001FF
diff --git a/drivers/dahdi/xpp/firmwares/FPGA_1151.hex b/drivers/dahdi/xpp/firmwares/FPGA_1151.hex
new file mode 100644
index 0000000..ecefb3d
--- /dev/null
+++ b/drivers/dahdi/xpp/firmwares/FPGA_1151.hex
@@ -0,0 +1,702 @@
+#
+# $Id: FPGA_1151.hex 5615 2008-04-08 09:39:14Z dima $
+#
+:020000040000FA
+:80000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AD6FF400048DD0A006AD6FF400048DD0A006AD6FF400048DD0A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4455544455557475577775577675577775577765566665563625523235D2E37C2B511115511115511115511141
+:80008000155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111000000000000000000000000000000000000002552222552222552220025522225522200000000001AA1111AA1110025522200001AA1111AA111001AA11100001AA1111AA11100001AA1111AA1111AA113
+:80010000110000002552222552222F21F112122F21F112122552222552222552222552220000001AA111255222255222255222255222255222255222255222255222255222255222000000002F21F112122F21F1121200002552222552221AA1111AA1112552222F21F1121200001AA1112F21F112121AA111002F21F112122F21F11212EF
+:800180001AA11100255222255222000000000025522200000000255222255222000000000025522200001F1BFBB1B1755777000000000000000000000000001AA1111AA11100000000000000000000000000002552220000000025522225522200002552222552222552222552222552222552222552222552222552220025522200000066
+:8002000000004F44F444444F44F44444000000004554444F41F114141AA1114F44F4444400004F44F444444F44F444440000004F44F444446F64F446466F64F44646000000004F48F884846F69F996962F21F112120000004AA4442F25F552522F21F112124F48F884846F61F116164554444AA4446F65F556566F61F116164F41F1141411
+:800280004554446F65F556566F65F556566F65F55656000000008AA8882F29F992922F21F112120000004F44F444446F65F556562F21F112128AA8882F21F11212004F4CFCC4C46F6DFDD6D62F21F112122F21F11212006F6DFDD6D68AA888255222006F6DFDD6D66F6DFDD6D6000000008F8CFCC8C8AFACFCCACA255222000000455444CE
+:80030000455444008F8CFCC8C8255222004F44F444444F44F444440000004F44F444444F44F444444F44F4444400000000CFCCFCCCCCCFCCFCCCCC000000008F88F88888AFA8F88A8A255222CFCCFCCCCCC55CCCC55CCCCAACCCEFECFCCECEE55EEEC55CCCC55CCCEFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F88C8CCFC8F88CB8
+:800380008C000000008F84F44848AFA4F44A4A255222CFC8F88C8CC55CCCC55CCCCAACCCEFECFCCECEE55EEEC55CCCC55CCCEFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F88C8CCFC8F88C8C000000008F84F44848AFA4F44A4A255222CFC8F88C8CC55CCCC55CCCCAACCCEFECFCCECEE55EEEC55CCCC55CCCEFECFCCECEEFECFCE8
+:80040000CECEEFECFCCECE00000000CFC8F88C8CCFCBFBBCBC3AA3330000008F84F44848AFA5F55A5A2F21F11212CFC8F88C8CCFC3F33C3CC55CCCCAACCCEFEDFDDEDEEFE1F11E1ECFC1F11C1CC55CCC4F4CFCC4C48F8BFBB8B800EFEDFDDEDEEFEDFDDEDEEFEDFDDEDE000000008AA8889AA9991AA111000000CFC4F44C4CEFE6F66E6E1A
+:800480002F22F222228AA8883AA33300CFCCFCCCCCEFECFCCECE2552220000EFECFCCECEEFECFCCECEEFECFCCECE000000004AA4441F14F44141155111000000CFC8F88C8CFFFBFBBFBF3F33F333334AA44415511100CFCCFCCCCCFFFFFFFFFF3F33F3333315511100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000008F84F448489F95F51A
+:8005000059591F11F11111000000CFC8F88C8CFFFAFAAFAF3F32F223238F84F448489F91F119198558884F4CFCC4C4FFFEFEEFEFBFB2F22B2B955999855888FFFEFEEFEFFFFEFEEFEFFFFEFEEFEF00000000CFC4F44C4CFFF4F44F4F3553330000008F88F88888BFBBFBBBBB3F33F33333CFC4F44C4CF55FFFC55CCCCAACCCFFFFFFFFFF9E
+:80058000FFF3F33F3FD55DDDC55CCCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004554444F42F224242AA2220000008F8CFCC8C8BFBFFFFBFB3F33F333334554444F42F224244554448F8CFCC8C8FFFFFFFFFF7F73F337374F42F224244AA4446F6CFCC6C600455444FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004AA4446AA6662AB6
+:80060000A222000000CFC8F88C8CFFFBFBBFBF3F33F333334AA4442AA22200CFCCFCCCCCFFFFFFFFFF3F33F333332AA22200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000CFC4F44C4CCFC6F66C6C2AA2220000008F88F88888BFBBFBBBBB3F33F33333CFC4F44C4CCFC2F22C2CC55CCCCAACCCFFFFFFFFFFFFF3F33F3FCFC2F22C2CC571
+:800680005CCCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F48F884846F68F886862552220000008F84F44848BFB7F77B7B3F33F333334F48F88484255222008F8CFCC8C8BFBFFFFBFB3F33F333330000BFBFFFFBFBBFBFFFFBFBBFBFFFFBFB000000004F48F884846F68F88686255222000000CFC4F44C4CFFF7F77F7F3F33F33333C3
+:800700004F48F8848425522200CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F48F884846F68F88686255222000000CFC4F44C4CFFF7F77F7F3F33F333334F48F884846556664554448F8CFCC8C8FFFFFFFFFF7F73F337375F59F9959585588800655666455444FFFFFFFFFFFFFFFFFFFFFFC6
+:80078000FFFFFFFF000000004F44F444447F75F557573F31F11313000000CFC8F88C8CCFCBFBBCBC3AA3334F44F444443F31F1131300CFC8F88C8CCFCBFBBCBC3AA3330000CFCBFBBCBCCFCBFBBCBCCFCBFBBCBC000000004F44F444445F54F445451551110000008F8CFCC8C88F8FFFF8F83AA3334F44F444441F15F551514AA4448F88ED
+:80080000F888888F8EFEE8E86AA6664AA4444AA4448F8EFEE8E88F8EFEE8E88F8EFEE8E8000000004F44F444444F47F774743AA333000000CFCCFCCCCCDFDEFEEDED1F12F221214F44F444441F17F771714AA444CFC8F88C8CCFCEFEECEC6AA6664AA4444AA444CFCEFEECECCFCEFEECECCFCEFEECEC000000004F44F444444F47F774740C
+:800880003AA3330000008F8CFCC8C89F9FFFF9F91F13F331314F44F444441F17F771714AA4448F88F888888F8FFFF8F87AA7774AA4444AA4448F8FFFF8F88F8FFFF8F88F8FFFF8F80000000000000000000000000000000000008F8FFFF8F88F8DFDD8D800008001000000000000000000001400000014000000000000000000000000F07D
+:80090000ECE8800400000000000000000000000000000000000000000000000000000000E0EB040000000000000000000000000000000000000000000000000000000000F04FFE80040018000000000000000000004001000040010000000000000000000000003F8105000000000000000000000000000000000000000000000000000030
+:80098000000000F04FFE800200400100800414800280041480020000800280040000214840010080041400108204000021BF26050000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F481800280000000021000000210014CD
+:800A0000001002400100000080020000882800008088020000EFE40F0080840100002001000000000000402101000014000000140000001400000000007028034818148002800414182810820416012810A21140012810A2414001002B11484001280048408188022148008828108204F05C658084018002000000100200001002400100D7
+:800A800021001400000000280000808802000088280000F04EFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000001002000000000028000000000000880000002D5F000020020000002400000024000000200180010000000000008028020000200200006F6F0F0000009E
+:800B0000000000000000000000002001000000000000000000000000000000BF240F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000080010000008002000020020000820000009F320B000000000000240000000000000000000000000000000082000000000000F00C
+:800B8000D3DF00002002000000000000400200000021000000000000000000000000000000F03937000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000000000000020020000EF1C040000180000000000001002000000001002000000000000000000FF
+:800C000000000000002FB5020000000020020042000048000000000040022200000000000000000000000000D90A000018000000000000240000000000100200000000000000000000000000004F160700000000800200480000480000000000400222000000000000000000000000006FBB0E00000000200100000020110100000080015F
+:800C800000000019010000000000400100002088028F21460100000000000000000000000000190200800800000000200200000000000000BFB604000012208104001021080000148001000000002800000020011200212800000000002002FDA1800228282800200228230118901222801222052A24280442586A818122011824180020BD
+:800D0000021722482004222004292802800400F0E6BA80022228388081040018800118002220052A0400481A842181A21220410200A012B011220420028044022200002002DF750600000000226022402148022840120112202804004A02000080010000244082042800200800480000DD8D000040012200000000000000200400280000A2
+:800D8000222022840822004800000000248002000000CF7D052220238201190128001210020000000020044820242306800800008880028880220400480020244221047FEE0228A012280036010000000000000000480080A42142002A08000000008880820400420080840200EFD40E0000190100220012100200000080040068002022EA
+:800E000002802408282088240200000010220200402104FF790718002820321100126021200200420022008A012002000022124848181248000000202284C821202C0442408204D7A200808104002219021420210282C20020E9282424A225002A88022002221200808404A828000000288002222442248074B50600002A012001A0812AFC
+:800E80004402800100008022040048200180082100822021815422E800481002002088020028FFAD050018282A2122A121260196C1322C0120210C002A28A824AA840620868201202A132284210948122A0C4200284829480162804A028084664F800148004001200148002008480018480000A800002200520000184082B222088004007F
+:800F00008088042A240440D1A70328200228601228002800C081002022220200202902422002282002004224188A23228442020066820400480048F08F8800424800110028283022241128124002248820028200828004482502212100008221802208102208002002800448DF42070020022200280000821A84A841A041202102004288F7
+:800F80008004000018A012A01228481225220880040026022820022860127B6500282004480000800428C042822200000020022129A882A880088829B84288018022288802000028232408000010F237E980022008110000001081020022008004002200424200002200001082182204102204002814220000ADA60000228850210022280B
+:801000000028130800800422000088000042210024802204292802001002284282220042482123028F680600002C020024000038002005881A028008290810120222702202400224120000008822009082000020048FF303A024008002280080028200200222480088822200202224228222022228222240222408000080020020826612BF
+:8010800029F49F25008004008004480028286028822440021002184888002121294881882102291C023280020000280028200400211427E60068A02490212220022CA22210A141421AEC26A1412232008824AA0824C82B26C8809A222BB1B022ABA138321A98122C24280C4221A0646E228A8A022A84226212682FA80228220010022A82E9
+:80110000A2622004A0228A38822823C2222B1C00A0883826825822486229062C2872820227222C044AE223A2AA2A0A8008C22229142222A424003C26F493B120222422A2226651112904212260228E911F18682100284A88A2226882A04428206428286E82272222242AC24220C6222F2AA188212924425222224082280228C0424A26140B
+:80118000F2911C000000230623042304230221A014A01480830448C0420080A128202C222822292201200642A084A08480082C02000000423FDE022AA226282AA2641F34F463622F2492622E622D224E42223F19F983A32B81DEC22B663E322BDDEA2804CEC22F2C3C222E2225F212122F21B522D822FC82A227282F29ABA82B1D2BB3AED3
+:80120000E22F2DBDB2B882AEEA2BECA8CEC22F2CAC8A4A8CAE44006E412E416E626A8656121F8B0B2AA24E282AC22237323F16A6242E622F22F642622C82F283813F3DBDD2EC29B832E127B732612623A4442BD5CAEC2ABB2242F2D2D22F29BF62F823C32F287AA2F31232B0A2F622822F2BFBC2E22F2CFF82722BC82BEE6AEE2858222BCE
+:8012800064884AFC62622B8AA0466AA4222B662A26F4F499A0222A86A2222CD213F26121682CB26282B262C4221F31F9C1C22F2CFD82822F23F322222F24B63295224AA498826AEE2252222F28E82ABC22F482632B282DA22D221AB382B422EA2AFA92922F2FBC82AAAE2BA8CAC682259222CAE428E42CACAAA0462E616AB662A66248EF47
+:8013000042072AA26A282A82F261633F3692622AE226B242B62242F281831F39F982922F28F862622F27F722222B532942A2D486F272E22B22242F24F422622B462F3AF682223F22DA22F2B2B22B2A2F23FBB2B22F2EFEB2B22F29BBC2B862AE2A2CF8C2C22B4482CAF4626223021B466AA6666AA6624E418FFB0E220040023440022400F4
+:80138000402108802208000021100221001002212002880080080000000011200428F0DDD30020029021220028220050128200004A22A224202402002A240428222002002E82481868238244820448248A84024A22828224045D4A80B51122B21122B611326219B26291212B9619B24239112B943AF442913AF442913AD412AB421CE92295
+:80140000E414E82264112E42D6E122EC1DE222AC292EC21B292ED21B292CB991A2161B2927261B282396612B8419B24218F142822AB4422AB2422A92822AA4842E424F5603481B61481321B411364219B64291412F2499414EB213C9A23AC4833AC4831AC48129D412E92AE514E922E811E82244A1D216D1326C112C3C11D81B4129B991C5
+:80148000B64231912B841B28421B282B841B282BA413B8422AB24228B2422892822B42882D424FC50B2088040000280000000000001002290188200400140000800100000000000000200814F044772048C1219021202184028228200C008081054A02284200112C04424212C82242A0219012426022280022201882842882A4828008223C
+:801500008F9A06128A83B1116221184A8252219A8432C2421824138402282302183041A622A6422322E11401122602821A622814881904F888200C2C5C218064182A240848282214F08E958031C1141E411621A1244819826122622A84014222002341A21220A668AAA142192A715281345180A482684A98122CB811041A849A2248A02422
+:80158000268388A4842AA482484824A214229B9C001AA2122826021828248A8428088A44120180A3428004119042102204001A92828001260180A482008220180221148800A22800B017048002400122200414408204112492002820944100000052218200000020818146820400C082800288002200CFB3041B24A082408202002110C29C
+:801600004182195122826026800418201402212846023220E22138618E221362222C8A440200304280081082C622202404F0921D00228840220200400300342488A042214880C44100248002521A02281829E22812018221A0242442304280881802222602424800CFED08130628100122C04200C0412B48181190920028800142210060EF
+:8016800024102208821904222C2282851102000000902242820022009FD90E8001104121430118113982288A2102204122138205E8B828422738146014482129842822C1414022228422C42100214A42220200402204CFDD0B14481A12011280A124800220324182200542904280028E121A2402121B84142A013828002AA424328A0421B3
+:80170000003420D422222A84044240022AE8210E281001182240120112482142E02401211322328188224221001800122820081229110120088024028004002008004A0AF083CF40818103E01281426212181A5232A0481B4116021A3421623B82481A4482C22238183C9811190924B012A41223238122C4124A8284A4241C123142244226
+:801780002A98228A0442A0A420F863E120021C14C1118031114240818608A04A2480011882282AA48420E4220420A4425A828882081411228A8208230200244824200400004226F1AB92001A0400004001242414110014181180A1481D8240012902E021A8842180288128A8824288D02209884824220028002124004822F0387C200418BB
+:801800000018108221180220B8238404140088004880048A248104881212104211412126218492228A02008A2404232408006028828FD40D004840022424003440022214208E210832281400100221908360140080820A00824022440246020021100222C041F7490011004A82364220044A812404004A0100809812A01822C82482002094
+:8018800048228824B4810413280AA04A8008C8800888282908292C88027FEA06404101803212188081010025821182238181E51214118284840223218184A484529212001124922303242480042168002440026824F09EA20012000040022140022811001428001002181A02A048100218502200200400230280028002210000109242F0F9
+:801900007F2220044021080000800814484A8801000021981800002008004800482002002004292802800880028200884F6E0D200842222113018001200220611420828158121846015022400200480012005021800421214A825422001002000014429FF70C00190480015812482100290631001488002B42828A818188044800142024F8
+:8019800034214820242622840480228402424262228004234CF1BB7780F4914190418828342420092423826434102324011E421F16AA284A988178282724296C244A88A4C84E12CA295411A219F881622998422722AA32E2A0442964242A56224E422A5222908268AE214AF4CFFF008AD111014827232B4129D112D422C5422B842C7482EC
+:801A0000014AA5141CE312A391806127230966A242C886B21245D212A8141B41A051A8284826A17A5E22682424AA9682C223288824D822A42A602842142B88DF2E0C4200E022A214181AA411B013011415B223F613811E411B8311828AA9481D111D418A245122A011882B488212882F219482481D8166A18416A292882BC44827242E22BD
+:801A80002682248418220825A2442AE8240C7F3305C011001166126124132134114A082C088812881200281100009012008001002240012C01002E8280088880082C082C0A4200FF4201CA8411011F147413914119F44253373C2F25FDC3C2EE8139EC2CFAC2C33B986AC6119AE92DFD91111B1F2F1DEC1CAC564A14B2D2CD822F28B8C112
+:801B0000A4C93CACD97ABE41A8A21BE24AEC2BADC4E82BA2AE62CA84A2CECAA46C2CB4C2AC4A23F82221AEA28AA8CC2B8CBF4F044AF4415180F461611F3596431D422F3575C3D33359232F14D231FCC2C13F34F413111B8A1F1BA918DAFDF2F1DE911F1CFD81816AAC664EC2DEC24EC22F28FC82C19AE924EC29BD32FF81C18EA11BA81B6D
+:801B8000EC2BCB2BC48ABCA2BAA232E2EAAAEC2B4C2B4C8EC22F2CAC6A23F821222BEE2BC8CAACCC5FAC094A84951115012F36F612132B153B141F38F4139335E214F283422F24FC52532D11BAEB18A999DAFDC2C1BAB9C1BDC1ACC650222F29E928F88282CE419AEC29ADD9DABDA1AEAA1BAAEEC12F2BB9C2AEA8AAFA22A22B448A8AA6D7
+:801C0000C44AA4884AB42238222B88B062A4CCCAF891C2A04C1D511D1117146AE631F3121146F253122F29D522F9C3C227141F38F442C13F3CFC131113F231119AA9DDFEF1BEB11F1CFCC1416AA466CE42DEC2DED22F28BC82AC99CEC29ED22BD91F1AEA18BA81FAE1E12B8B2BDD2B882B8A2B8223A6262BCC4AEC2454222F2CBC22FA22CE
+:801C8000222F28B842A4EACAAC4C2F180A00000000200140021001802201001100008009008880012E8120022E92004800804402002C020028F06F530011181122135122112C1141021440A1412521C12112881B4310A1842210022142292884219842112213081022488262242824004002004282A0484F2B0C481B211CB11162261B6114
+:801D000027241B612B141B612F2499612F2499412F1429F3429113F342B1222D911B421CEB22C4812E421E212F2264192F2265192DC2DAC2521B2D2D421B2926B39162341B292B141B2827261B282B861B682B8413B84228FA4282A22F2428BA43A8424AE822F44857808486B511021B41211986B18196821B68B81B482F143BA14E911BE7
+:801D8000482B94222D913B4A4E113F2281C8D25E812662142A68113CEC1182BC11C2C21AE632B811C48319968219B66238816213B842328128AA14A24A42A2302288272277FA008248000000002008000000000000800200000000000040010000000000004001AFA802821C812102290119C212800212484219A481582B42222111421733
+:801E0000244220112298124288222071220200126026132282622480849842230888A042006022630B192208141A12C1312121CE13869221822486E121B221446111428AA6249A8268222683262282867A7282B822DC1224A43827121991814E138842311429E21208108154224632612C08A2148AF43799802228E1128482012712237191
+:801E8000C2239A21B22413C4723A64251E414AF2824214929E412B42866225222CA2342CB8C1C1A2822F34612462C0111961358A2494232683E61228267843820824226E822488142E829F9C07141301C012112E11001224004888111C188102282AA4240033820282A02426022A04229227128008269221002400004825A2481304200282
+:801F000048378C0012A02180848104001100002819842293324888114248421870212284012064124021480218280062828034422200208A22A824822FC40F42A012A02120221191122F22E42124C11182334582C28211481911011130222862482622A44212228223AA28B01288B682167242A24AB04212824882084E822842C22200EFC1
+:801F800089024280022024220525021140416215242290117840114121A442186862484248182A0482190227282AB4A214022B82686E82806C2422802882A848884888FF7B0D2021A1212A01121081E12422951212882032412A782202138508482420021123921222008E232888821880C12248421002108208482162222228B0D608122E
+:802000004A228202B0410222488223A2182212800813021A9422C042482AA51438888042214112A13420818494412A642214682246212808258218022C24420248DF6F0F1148002822902142218014A216481E813041822A04238C01808102002D81271424222A2108800C98822048222422448202002820C8422822DFFB0E422011814408
+:802080000224148001400310828144A228C0211C82023448B0120200003022282222104221021042820442488880028848F0D91C6014001C82C42248D012268469241A48834491824E111C869472821B121F2482223621628822399A422490232A812282021682D421B28122A4421B242C8C08482B84882820822C023F320F18282A01228F
+:8021000060121942022428A0411892008822882A042084A88529012901202122C1C2802128B681A482002825028054224002A0422908422AF4BC830014001C024A62223C8204922C01181BA12F12241202622818A042E011843122000026022304146022282442A0423424404242022B28248848481C84F2F9DD00181921051A1221048A39
+:802180008201A01C210082228880613282828642224802121218200211802225848188182132411121000014002908B0A904001081820425214401298404501210022212482228E01284A8162436C22248209141142A38131A0C124210823841281304420030429022286621F4FC5180010018110038C2218221CA2222088A048220012D0D
+:80220000C100402181082AC82188122C88810424822122CA0280080028108282820421F0E1D4203411111110611211195121004A21112221042082041242882A24A28480828124442201380018822D31231C033042212B8421422322084A1802006F9A0600800122C042241819052428406212243212281CD412041B52184643922190429C
+:80228000400114291401004621C42148132414A12428422A08152204804882F8F4CE0000400112000000280000001022280182000060118004002A2482820200220000100200210021F0E95C00000018122A012240022083222102208102280098221200A04120A483292881812401800200200CC2208282044214425BD600800418421059
+:80230000021814482228422304290412409142141816A1821420C8422A68121C090048C80011108108A88002001011011012F289C8001180041B141AD611022F387B41818CB512A831BA7C21E1240E2AA84416A1222BAA421BCB1D611EC1218224AAA5148E114E43A2171914D218882866B2A3BC81021F3416221CE2242AA288114682A46F
+:802380004426A164DFD60180C1111813E31382A1442F2127961227212723CA24D421B34224B22221E823023C7C41C181185233EC13D32222B611A2612E821B113DC22D9238186AF4D3221631814E214A04A226830C82242823728221824A01675BA04116117111C131481732272317121B4112C2422C712252122C3382281A83B161B751F4
+:80240000A141AAE614F222122E32243AB812B54228A24123A2142A32112AEE21A2523F2495E2E012F8614329B84154224E422B422127224E62E82334824E4229F818F30018C011A01420062E834888C082801A8108888038114A02100120882128223C22421C082A88642200482E81E0120888C082800A3C0A4A0A4AFAE221A0551F15F179
+:8024800011111AB571BF71A4443F36F443713BD42F29F982522BD72BD52BF92F2DB562FD42822BB9A22EE26AE71AF852211F18EC2EF731332EE117383EB22F2ABEF1A62B7EB31F3BE623FAF293211AA5733F1AFA6162373C3B88CAE82EFEE3A12F2CF4C2822B6C2BAE8AB8A2B8C1BCE2EA2AAAAEAAF6A2A14FAC0E5AF551511F11B111B576
+:80250000F1B1717651F363633B346ED21F38F982122B7D5EC29ED23F3DF7E2432F24BC92A91AFAB563B7B1FE21711F14E436FE72623F33FE33933EB22F2EFFF2613AAAA23F13FA71E33F3A5D13587AF3F3B31F35F5C1C33F1CBC81F861E32F3EFEE3E32BCC2BCC2F2EAEA22F2ABA43FCE2E32ABAE2AEEA6AF2963DA0551F11D511E111B1CA
+:8025800071B371E524F273433F15B7C3B7D2E524B952B7D2F592522F27FD63532F2CB492A3B16AB6E2EF12E514F7E1416EE21F33E112F61133BE322F25FC72E13AE62FF4B1531F33FAB2F19AA9997AF763213F26F7E3E33BCC1F1CE826BCE2FE42622F2CBC42B4E2BE22BAA2A8C62BEE2BE22BAE2AA6623FFC05B011D511F141111B131B5D
+:80260000771F31F373633B353F3EF743D32F24BD52F592522F21FD73F32F36F4C2422B912AAB771F1EFF31711F12F661416E633F33F6B3633F33E32BF3F2722BE53AE62FF473D31F37FEA2A23F1BAB9C7A7373F373631F3EFEC3C11BA81F36F4E2E33F3CF6C2C22B4C2F2EBE22F2A2A22B662F2C9C42CAAC484E411FB703184001180012B3
+:802680000000A041A0412400000000201401181002188001008880896412200224000010012800F0D7DA00121811181B21262241B111122211022132250128324213A21411A81B42F022122022B122042612E12235112A082A91412724809841241926044210022982B442022848DF520B581B21181B216E111B212F1691612F36B111F62F
+:8027000042911B212F2419B14239212F142BF242B1222D911B434EB12E421CFA214216F1225296F1224296E122A5292E421B2D2D421B292E831B296E921B6927241B282396612F3698212F1418F14282222F2428F242A2222BA42AA4A42E429FEE0718198681A214B042012B141B68981B684A3A814A3BA12D91AAF44281A22D913B4A8842
+:802780002D521CF821521AA84296C1C286E1326C1D2A38912EC21A64321924369123368162112F1618E1149A212B84B0420A2BA490A221A82F28F463860082000080010000000000000000002008000000000000800400000000000014F0FB7D80022222001832121AE418061641C1811414C22CA2214AA142A04200122B141828186242C3
+:802800005812182C31812142C0124862802A242434C222628268000082FF5B07189641C1118682374242422722182C052C096A99823393112422181A8298C2290226E2288491221AC8122AB8216414209221112242248008211411002113242868181B244EA12AD4790922CE11E012013622A524182722B21AE41261398621CF812F19E4C5
+:8028800022C13216A21420DD222C8AB13224A52129B181A3414A2194115225912200468224842892422E4130C22420A886C0826226817A520B1860126028482021A4414601210011212214A024223822004022188282042B821B2148A0821146818201230288001904224AC241204811A184482F8E0818122211B01144120128002480B8DE
+:802900001144032C08460120829841B02244D12305226022122200282583C2124880346200488004222922820A42F024FA30611C22A112262362132872A04A29A449113C2182C38226E1220C56814241C2224A422381622720242126B823B81342818BEC1284A8242186A1483424247022A248C84242882828CFD2064212121B2126812443
+:802980001102209A4288311F21A8522C8248E2289441460114881462341592212602422CA2428E221B2839012868588A04422986044824482848E82AA44A88009FF1053691212840B211322119A2432842A01400111601338A02122222242A54222A84A1412325021212002819F28213823C024E2230818234100225622A00004A22F276E1
+:802A0000D840E112A1212200484E22121C21021921028840A121002381042986A1854A8201321C02A84002A048182C810421008084C46220021342028602283F764F010048A042000000A0C21819138214811232422828E018613230812B42334C21011C8168121448238404C0213582220622A04A00A024482C2402FF45066A01111CC1F8
+:802A8000218082B121044262211100903282118038114882218001188004258282018023328228802484181102148088724102A82220BC454BA1341422408122E421E4138481829212C62191A1243691911D2220C571422A5812199572822B165E812A847182B221211843C1327218422413C641882221421C34222828484AA2488220F637
+:802B0000BB8B40A1211CB51122822482021142481400122148280082602242800216418202200218282048A2482302243022192404A04888C02290222A846218FF860C281828124240512190212E1118211D821C9A123012221211480014002262C0620024803422281420A948204402240024D0220426022002289F210142424800A02468
+:802B80002331412388080012601586C1118023A841202A818121818AC13220A24100248008002522462204426A288622049022A08229F4454C001382C6412A8182820318200123011A42C2210021121CB452020088820020282302208141018002484280440288200222808C4271F603008002198101282123A44AC22084848831822A811B
+:802C000028124201122200002862001A0868221A982120880280022820840A23044810023F1D06224A0212001100463221211882138888A32421192862120019022420020010228406A0252B422AC88348822130421002002190420048B06F051A0458284222241D221400222382821283081A18622590A3C8420000222812251121022153
+:802C8000483100800280220848902280842208502242EF850A2001002C04A0141C082008004260120010020000000012882440820480840580022880080020042D821022F8BFE800860114122024044800103212221148201281241342828224022140811273120258208482052DC2402242C2828248244A0810014AC8C128CF810300196C
+:802D00000519E2140120A2128223081E6140912200142B84161162128A012A08128081488101322C820C331131112006422084928200261221042221827F670748AA84E31301F0632125911117263531B28AF181C13F12B171A2382F3C33311B1296F3A1614E511712130A4E122A22B12282532229E22131422CA5262F213A222F1C3911F2
+:802D80001F29E824A8462F2684D2222EA44428296422297421F242A2001C08FF5D097AE21C2381A2241B53121B322D6229EE22A484482CA1C81CF833C23A84F212A31B224AD1211282BA2281026A0A621B21241F1222B3B2622180A123AE8148822308232494C227282BCC6223E426A22414298A64122BC23B990013611213E413E514C20A
+:802E0000421E4266E119A1A92CF3228223E12192124611F18291B0422DA1834ACF4112228A818128A1923A3C822C271422F25163114AE714B122C622282E42222488242CAAE89042482CA4AECE62CAE27A05800122D0120126224101421246011001001130814215022C042C248824B822252822BC222178220114004880048A04482848E8
+:802E800024C023800228DFAF041A314115B131F311933B311B113B223B663B8E19A8A9AAFC835239A3FE3F2BEB2BB713E129FB82A322A6F1B2C22F3EAC322E622F24F652B22CACCA3B6EEAEF1FAFBA6AA3A62EA21BE3CAA299BA1BC2622F22F242222F2ABA62E424F882C22E222BEA2B223B662BAA2F22A2A2EABE62FED8DEA0111B661D39
+:802F0000211B511F3FB713A7311D112F27F7D2D32BFFCEE22F28DE32F542423E332F1FFFF2733F32F212323F1BBB22F2D1112E423F3AEA26BF22E426FE52922EE2AAFCE2632E322B33AAEF2AFF22E22EA21F2AEA14FAF1F11BBA25F2E2E22F22B262F2A2E229F642822F24FA62222B266AB243B2E1BAA2BA22E21EAEE63F26065AF5214173
+:802F800015F131311D111F25B313B523B333B3E3B841ACFC9AFB431239A1FF3F2FED2BBDB3FBB1B22F1B3A33BE811B762F1EBE22AA275AB292F79212E22F36BA22A3333AA3BE2E622F2BF331B12B3D9AF9F1F12B222E622F26F262622F2AFA4262242F28EC2ABAA2BE22B262B6829A222BA2EA8EF46F9AA0751D611D311F13F371711F3406
+:80300000F612731F32F372723F3CBDA3BB92F392923F34F143521F3BF9F3D12F3FFF93A33F2BFBB3B11B631F1DB861F6A3A12B6776B2F2B292F5B232F22F26EA27F5F2D2FAEF27F73212BE321F3AF842A11F17BFE1FA62222B662F26F262622F2AFE82C22D822F26FCC2E22F2EEE26F64222CEA22BEC286EE1EA7E150D2A010018C01248BD
+:80308000204822081224001228801221042880022888282290824218200218488044022440220882400148428220684E80311190214AB11112922126924180423281003C9241241388A2425021A0429042F0224280A5242230225022192222C813A0824822484270422242A2422422A04828485D4580B511A2121B216AB111F2621319F224
+:8031000062131B282F1699612F2499412F14B921F4429313F2429313D212B921E414FB21421CE82264112E529E212EC29E212E429AF222C21B2D2E421B2927221B2927161B2927341B282394612B8419B64298412F24A8422F24AA422F24AA4229AA42A82E424FA807581B615813A1141AB242014213A91419B6429A414ABBA1744231A16D
+:803180002F14218BB1A2042F2A012CCD812E4286C1C216E112AC282EC31B212E8219E622B811E616A8292B16112B841996821B282B2419968222A8224AAA4A282B42A82F22F43D2100824800002200000000800800008001000000000000008820020010020000000014F079B280021C222181032AE421848232412100882CA1A1212A2459
+:8032000082621228400242314E82B02281A9142A28A321808291112226C221132C22EA2488840CCA0222A2282228426ECA00AE1180824831121229826119AAC1414E821B941F25B2618874214231C24882C8272E1C869131282932714622863242864222088A86B642084221212110018A021C880442194CE122F84C1100CE211CA24312CE
+:803280001C91122A25962226C143228AB483C5728A346211708282B681E22122E828228134238E4213B11126E924A1481A282608821E23C22C621417242823AAC22028AA2419A824822E426A4881FE6D8F202201808802901212989A62140013C831922D221B424A02A0484A9243B0210123A22425A224222826221182A21648226022821E
+:803300000024192404880022408142F27A9F001902C01200122C01140080019880A24AA0421C22021112241200232281A121001C89028A04A082489041884821482088A24A0080F4F66280032A8122822731222842222A351229EC183413222D11272424130DC2304329926223612E1E212AA1412A88D2229431382230222E131C96A22C8C
+:80338000C421172222463181882382CC628A0442E8AA04E736200112E021A261122122902158A084D682C12234A0484E81281B842846722122D722A1522B1280822262211C2363112C021E2230822EC21CC22128136418212142A22B6882A0C24A08DF53022219228202001A82314260222C0114111A288176222281840225010082142A54
+:803400009152982CA12400A880621C1C86024230438848824A22880462428082F4437360142842121800211011511218221A042146A21211B022041CD42282290531F082531C8632824AA152212A8104001C6628428200428E21222382AA2826022C0286D2970E005621A2241911021AA2129810A242A0121A12128122338211A8A01288DC
+:803480006A016A011448000088298D424102002820284A028A4402214886A224489F5C0318001001A0341148226A018200C02110120222800422800422181228231281022442298842120148130800820048422A880428578630112811381216430219E2126522193312C25822123C66221D22322820CC2228722A35432C6618582CA728D5
+:803500002A6117281A2A89C481222831422A040086C1A2A82AA8822B24AA8428E42CB29C0A4880016601A06118C091480020D122021C01A0481C722122040080A1252302244224400227224092412C08881388A8482420042304212A84022FD1092A0100808203242E4218210050328082C311282064142084511248280048160113041389
+:80358000213821901142C8400324A0A4820000424226028FAA0A008006161241028280412129042018022084016022002424001002002180848C1C52211148882B844601422308A888888084D4A4052002123643E121A4242C4221962124202142021C82921211422092111542024811901248002112001A02242223D21218C121241488E0
+:803600004824002002222FFF07809441000020850190121A12021218100210612242822068218842681C166124883248004290810010420200242248C0429042F096D20000002682240213D422042A01122C211211012005149042221E412001292402002C068006144021328282002823044200002214FF19032A0180018082110219610D
+:80368000221128241420821181022180012100222840C212001248420080A448114022A2842348023022888002228FB70A0028000000001A0800E800A01848823424822858A0144800140019061C041196221902200480020088000000EE971081218222210118620019043042583C522100271416017846031C4242212106207441221284
+:80370000011110211411020019C82113044A982288808804E05104808204282110828111018082021218208211D22201181188184043D1226A11884002C84280028822884021840200C848001082747E051E11302158282F122234425AF2D1123B442992121E121A7262A2223F1181B2124812E125012E422CD612673823F121522D422A7E
+:80378000B422C252242A922219091B446A9182143BC235B18358128E2323C4C12B48E022A44E2084C64168AFBA09221A8422E32381C172122E5225E121B3316813824A944127312AB211D121E111C791141F1364142F152811E334B442F261214E224E421D81118E431F2761111364121BC1171C424222421D823B841DC313E424B8C2B4E5
+:80380000C288088A3C622262FFD70B282A022811167232E12213A242143C1511D222E1118B612827122E2123A64519F4422229382117221A85210929A81123A544330421C8288AE221F583C28E238E223C24A842B0A2022C8892228A08A024219FE209111021120100C082C0838088841A810888114A084A18A3242110211C220CC21482B7
+:803880001460124825010000204882044824822008001B82141B335A7121F12161F013122F1556222B711F2DA75C1F26B2A268282B381E622B991F1BF1B1132F23F3D2C2CEC18AB932E228885313128A98233F14FE41C22F28691C8AE828F8D2123AAA62242BA8DA5811222EA13F1898811B42B0C3AA8886928221888EC22AA6222F22F676
+:80390000B452141B331F1327F2113117313D122F34F662622B333B6E3F1EF6E1A12BB98E122B5C3BCE2F2AF8B1132F1AF1B1B22BFF23A4511F26B7A2EA227422F1C1C22F28FCC3C21F34EC34F882922F1C15C2232F2BF732B12A62342BAADE811374A1F223A13F1898812F26AE8C2B88CE422B8C2B442B8A888AB422A6662E6237FD143EBD
+:80398000111A071F137311D323F142632F24B522F671F26AF7E1E23D211AA8119EE235F131911F33F192B23F16F442511F14E52AFB23231CFA12131AF151113F3DFA4343CE432F28B64258112CF493532B911F18A8EC1F3DBFC2D811A446AEA13F1CDC11A8683F18F8C3822F28F8C242882B4688C82B222AA262CF6F49E113A13315A131FB
+:803A000016F213322F35F662722F23F323A23F34F463612F28D922B942F523213F3AFA31B32D133F31F3F3F1DED11F11F5E1E33F12E232F232331F3DF593D33F35F54143CE622F29B7535D131F3AFAB3333F11F981811F1EFA31B33F1DB941F463623F1AFAC3C31D832F2C7E43B1C3EC2CB4C2A8CC2BCE88484AA6662AF4DACD8001001802
+:803A8000001220418244220100130112301100281110021828209412009012200218008224823482340000820028F093C2001922922126321124686692412A11C112202413322125222204C04242221224421D124280024221281800482D821B4826021400484A286824A200802444F3D8DE80B411A2121B21421B21271619F242121B297E
+:803B00002F34B981F2429113F84292AAF442B313FB4291A22F14A94A4E91AE424E812F22E411F22242D6F122C2D6D122AC2D2CBC91C2C21B292CB89122B49136421B28273419F242811B282F2498412B84AAF44282AAB442289A822AA4842E42AA0B481B612AB41122B411726291212B141B296E811B282F14BB8192921B482BB4B22F14A6
+:803B800039A14A39A24E913B1A4AC9821EA11B42D22A681D3CA82D3CA8293CAC692E831AC4819A7642B181724292214AB881D222B88184AA4A25A24A42A229B822B4426822FFE80100000000000000004800200400008824002A0100000000000000002800000000004F2103201111B141013220C361299581F042114E1288822ED12B16B9
+:803C00000062624842150219C21118423E422C811BE13248C181211231B811342A841232811448238A88220200E022F47568B03134212280A2347041028822C0410017225A02112C92411812133A22681B521A3422E23382084229A7412A0118484A03482B481C98414E8120044228C22026A2861C28F8E21EB0112667121448687041822F
+:803C8000B3412205221B145226A2521EC11B412CC2424AA3421EA12934E13B34197432E125B22174F1C2126A791291414E311938122CE4128461348AD412E612641C2E81114A3242222A84226222E8886AF896AF0011002E11122A01203822136834403281882229021480818402A012800800A0242E92008021A182402148028004A2884A
+:803D00008280040024EF560A002212003C816622282F3228C18100122522DB22B3110482284846011C021421422322041A020011624829814403001041210A00002228F09D398032211901363173481311828D6122C0D22419884231C1A0121CA1142290422C21826A142928C5121A7C42B261C11313013391811115028A96E142234402AD
+:803D80004682842688AC484A282CF8436B2032211E211219723291512B24212DE21C2222881C822882F182612B413219A16168244828218603822985C1422CB31166113951211C651C193141252132210015026E8242428248824AA842F0BA1F00002081041C2122A18123118301335122A621410188001C041C8122C24348222C848904D2
+:803E0000008042020023AC484622041400282088848288F8A35B80044A032818001CA41280C3811342211B82E1186124102205422C13012722122CC2218098211B42298682810618142221222221422982A2C24200C02282F015C88002428024028012A2284229210220C421001223041BC280812C2421244181262205002A0C808EC281B7
+:803E800010C1C124886821208222844C22042FF70F20011C135121582A11022414602818142C02806216008022840111281C286428009830111118360321424A2A0888002440220C284A88A2C2CF360A4812283826E1122165221C14827A5231832C882188342292484E114258A2684A9251423522A681422223AA161B81238282A2433C7D
+:803F000021C82113A6A42AB841428204242A88B2422824A8A48AA4865F520C22801121042112221A022818111413932213412192220019042488A021181C3222C210A142C0111309286E12C0824021988282272422424828A02480026FA70F11C2130119C5122424224228000080428221691848425023682C0211001A242841C341282A26
+:803F800031212280848242012142E0220466220222C242A0823F7E0800808302114246D122021811821B2860312200003400404102162201C021202104602100002880020024202484082AC882486F8B0C228A210220822582011CC1221424241421E012C83212121800C03248422820B212E2248241414103001092422446011448906215
+:8040000000210080064FD8061190411001501200281218A812220000400158423400124846013C0428200116227422020029042501391A0200240088004F490B4A01124224408194112A7512C24190121C24E12821232108211011424281410226222181D4210628222D2119044A621428284228282008623062E2824062363F7904208436
+:80408000044002160121488081828884328124A069D02204B0228444311210C24125410200121A24A1244002002084020042408204002FA50A0048181812002800800A000014110014408109001C0120280118002002214001221C04C0414002000020F85C7EA012A6011C4222A2412A31421C012C021911220198868212028004114880A0
+:80410000849611224E222085820110238482866424002124A04221228848222A04F0DDD620888124048002001582448222A12425413122B0214491121418A081194441014001201491410040021411132254218E2100001002B0220C17C680A739904136A21239E123E516257141B3513131181B1425E1218AF8B21114EA8661314AD432F5
+:80418000C4412D134651321C57222CA4A129E61224F111111A7362A2142B42468294413D411B241F122294821DC266522223C442824AA4421CF4C2826FD60317111B4817111AD11155221C5412002B322B621C61212F11A81637122D331D223E3229094225032A32413D421B1116F211513AA14216A1113F148442C2213F1384A22231428C
+:80420000282C141222A42420E222A4862382A82C4E822AF417DE202284A326A02176B241F213223F262741D222B883A8281E6218138BB882781173419151191171D3A263124A3461221B242F2CE126F143222AA14217121B112C622429E426F22221667222A1441F3274811392624A8612A2E42B2888AA82D2AD4421440114C013006012DF
+:80428000483412148A8402240000203482008021043022422004C011480080044824008A040040024A02D023041CE317A3223AE618E23BF212212B223E422B223E21382F1A082F18E328BA1221B88321FA3153481B112F29B881E812F3717346F111532F23F212123B112B11CEA32D633AB661F221213B43173125A24415914317323D23DF
+:8043000015611215B3426222624AE42CAC26244AA888216F51013AA33B2A2285BBA2E321F323332F2385923229B3823B122D122F2AF82311213F19FB23333F13B712A5558AED2CFCE3E13F37E135D933F533623F17E717F71272DEB23F31B273B2317731B223E316B422F662621712373437242F147641F141633F34F441412522F46262D5
+:804380002B886A82B4A2ACA62B46AFC446F141611F13F731311F13F361611F26B623B263F611511F32F263621F36F193A215B3D3ED2CFA1212BEB22F287931F351712B551F11E124F541412EA31F37A3151F31F472223F37F612132B33EEC22D731AF621611F127233B25132422A52133B621553333F36D613F241C33F1CC8422F26E42463
+:80440000A4CC2F2E9A222BA68AE824FC67F4141B771B2A1F12F311111B763F36F733333F22F613131D213F16F763713F197913F153532F2FFF23313F12F2B3B13F33F333711F11F551511D433F34F463E33F37F591133D432F27F673717E722F21E62DFC13733B651F1363333F23A3672B622F26F263213F36F663622F16F663233F14F4DE
+:80448000C1C31F1CDC2234422F24F4C2C22F2EB242A6C6AEA2EEE29B1D800118602220A241141A044002002001112001001190120000422921A412400125832402226012483440830480220800F03CA9002880A218128602260280921292243214D0122A9A32601415022256112175224281A12822112112141B21220050321904110020CE
+:80450000420200282AA484147BB680B41122B21162241B212F2491212B1619F242921B612B9413F842921B422F342BFA4291222D912AE414E922C4813F22E411E222641D2F2265192F22A42D2DC21B2D2D431B292E121B294E111B6923B481724292612F1498612B8413B842A8422B84222B84222B842A84EA2AF443FD001A26A2414268F0
+:804580004A91212B162829A9292B248A929213E8142BFA4291322F14BB22E414B9A2E114F121C21ABA21641C2E12D6E112641D2CB8D142B391E622A5291CB19136421B682582D61298614A9A61212AB442A84A2B842AA4842388BA22F4D3E7802488040000001400000000008100100400002200000000000000000000008004008FF60B3B
+:804600001D241828342E414A42C241241C041B4119017129B2928446C1C3CB210026B146622613821224CC494AC312C03126B4A1D1638281081B282C4292E1232482C44120346689A4C282C82882E07D0823358116B42881E118C1142AD912012B92A608844AA11C442D882E142311A1124F88811441E841C442324323738286C464296486
+:8046800021441222481B3449648822188A9212C0921D4418242A58825883826154287F23075B41D24C61112717AE1141291391432368162E117041A624522B483C622C8523E1C87151C265AE4827452CA2218E644AF213822443E41461624F15A2122B21C8B0A1248892832A3822625E82484225366823AE14AC8622089F780F231221C273
+:8047000028808491C129012A6189409812922D8426C81413C134222002C02148441887114B4252268282215816001B61418C12A2612324011154124A22182888286144222F920A6110C2282322011246C14825810448428028A2941AA424A024484624624424838881820C2A249C94A082842A0129210800E0140814222082082820A44841
+:80478000BFA5025A22428451414E281866AA921EA1181A88E41128E8255A41836112C094136B818293C84139A1145B43C22F24A921CE188A61514AC22112A224871286C4181F28C4814AFA6192241A3844C22B84C6B228E4223C846A0922AF1301274622C018353428C0188E311582A141B011085AD816C8284AAB41188E218B41406116E8
+:804800001C61219E65243AAC81C6A8A41B1C481982C188281480681411422AC8418844C24A281C02274AE2484AF8396B2001258422A241126682B4B844212884A48428201101498E8182DC480C2D4448849A042B421812444BA1A082281662A28E14892138822A6835882331412C022889AE862001229F6B0A2944E884D24161848418128F
+:80488000218116E81421A11227241668481A248A4231441D4882411849828A62441D142A440631811A22E181189488901819C81A8C8242FA6C9230821A32182AA8A1881A6A8442BF2448018C23149222263144804454418C22E8162881288152229058AB1A8694642F82985158F01C81204229890183048CC244B022C4684129C4241D1494
+:80490000145A28120C4224808454A420F23B8D201236128C321448228525032800840087268420210232805448812CC54232860A68823011908422290192281E28008C110260812D884AB2180443012A01BF3B45E32224D322F214233E4885B12454612A011B122689E895B812F41288874327852B8229B34162CD1BC143F22A84DCC4589C
+:8049800058BF42F142241741E0421812E211A4128B124D2A6422767828B281068C32282D9A8D14256C283AC83289A9588E14C9B81884F6FF8400448941188486618142C4811A8401004A28029018228D248A2484C82422C2188B282F8224851901908492188E48881694181E2C2D111321A448241638488CA42422423228F0FFDF80414249
+:804A00005182432101108462A2824D4B125C062A091A22644481850442C85221CB2441830883922243189224611A72268AC4344E884C219CD1844018442852488384C6842228F0B6A840446882422082A224248001801868B24182001811203226103281200422444883C441A3010038483041008E648E12602241800C212638144E1A4383
+:804A800092F8401204437141186485412E5D960484863184704244488454419061845644E24201E0814CD284E344C8982819810298C14A3844A8875245B824119159A1449634284F81282259C2122098882F5E0F8412488304130400208434122D21799188172214244091142E11942A4861224D49112609264A42CA2200154232118291A7
+:804B000048A2251118326489324B9042422180C21828F06A746038468A41311400298411C28100528128185814482524842428088344642142111820A142921C4218E12412410412838C02421182E229728A22828C14C814148FD80846041D44212728144CA4124846C42892482094114D41D0848161846041904D2A9885422D244399146B
+:804B8000A0214141514394444919140C611480081142282048C4444487484028F24DC7241628810689922899421818480200122481814A62C8114D28822A14022182142227244848424042020020C5219021C0832CE84182911218328CA121188288F0DCCA143151C443324347241514352119981199C22890822F44082E4645088C21210B
+:804C0000D2494862C44122308928CF28A184C729124B841286028F1821D38218D22254482D482280C449824604448618324444C3FC256840085880120AAD12B06891426C257144011888AD1110033043901816C1B884241242215460181628B8112402821182838AC1324CC1112C03491598128818488A12022DFE3011CE1E4712643F425F
+:804C8000F42C5847116E2C2F44F368184E688B856E555B194D2243AC18ED194CF44294471143A631DD212B866DC92D2C421A75E9671687444AD74CE292F1446417881741B21FF1A5811F8C2AFE4821637271D811D424F8564C1F98B812D38EA4894F6C3872CBCC4B424F1CD284F2F757D032051FA1B248F1482844BF84B2137528F887C4E6
+:804D0000818E42A7894E828BD1AFA3716828F572114D413B541E25DF96E824E1B8642A3E1317D8DFB4A891AFE1B7A6FC2A885AD843A28825B688D842A1AEA6E461D49A42DC91C1F28FAB2115F97452CD889E94CF84B612B584E283B318C3142B822FDF485244F3D14AD187F614133F14E26214FC15431AF233933D3815D2527443DD51FE57
+:804D800017A71F4AD4AC528185DC89C544AECCCD241F45B34CF42EC22E246D6849E8A17394F6225A4F2DFC13134B376D13DD22E1FB74EF12D145FCB7D28F4D7E8AB142FA83792CD14AE26EE426F2221687828DDC25E4C8F838888F68F43E891440012E11C0924003348C64120000C022112C084A0842118314A12421421100422044416808
+:804E000012C083402241A248A041144880848244024220F4E9C9344F697446F624176FE1F45AE5BF97F73415E7C35E3D8FA1EB18D988F82A8BBFA4B89FFE7E6C6F41719EFC5CCCAB994B9918CF88F8FEAC4F48FE8C1C4F41C1C49FADF5EC5ECF8FE5ECF582BEEFFAF526366F6AF7B4B44F2BF386C66F29F61C1816FE39384E44A7918FAB54
+:804E8000EBA1E32BE421F1DCE8CFA1F9E6C2EFC7DFE4F8189C4E14CF42F1DC18EFCAF8CA3D244F44F4165CCD1E65FE6664CF86FE6465CFC7F65414CF8DFFB4948F88F8CADEBFEDF8DFE5DFDBF63634DFCDF15CFC95FD15172F41F79DCDFFEAD746FA67C6EF41F14A45CFDDFFEDDACFADFDEFBFAFA9FBCC5FFFFDF7B6364FCFFFB6A3EF89B2
+:804F0000F9FEB9CFCF7B9CFD3D39CFD2FA75B8DFC1F359791F7CF25214CFD8F8189A6F6EFC54564F44FC38F4CFEABA2AFBDC98AF88F9EF13345F31D523D499F239392F57F77B3BAB13BFB2F65215BFB2FB92B79FA8FA99AB3F24B89FFD6AC13F9179AAFF7B89AF35F11E19BF19FB1D518FBCFF81EB8FB27841FF284FBFBFFDECA3FF9CFDF9
+:804F8000C8DFAFEEFA8ACA3FB2D233F5B3F15F2BF2A7B37F29579FBFEEFABBB83F67F733139FEFFB3BB89DE89F99F9CDCAEF23FB2CF8FEFC7EAAAFC5DB42F47ED44BF1CF6EFD9A84241F1DF51B11DF93F339395F77FF7F7B2F27F17F2B7F75F1FFFB3F7FFBABA3FF9DFDD296EFFFFDB8CF3F3BF9FB3BBFB7FF8A8EFFD1F19ABDCFF1F5A97B
+:805000006B3FD6FE634B3794AFF6F6FEFFFFBEFFDF99CFFCF9EAAABFACFCF7F87F2FFFB3F1FFBBFBBFBBFFBDFFFFFBF7FBFFA9F9FFDE7FA7F9DBBEBFBFFFCEC2BF7DFDCF8D8FA7F16CEE2FAFFF62E2AF63FFEACCABF64DF2EEE2CFDB091880011820822422412248023484800413012004280000808221B42221F42211001042A81212A013
+:805080004120098A442288220848208122F8951E00008418198601A04942848F24099819840A80041AC421862814B2489213C0C883B1223D88250288822981B2622918E881F42881824E111D2829012B8484812A14220A8240F13F3DD022F41124A5F21124CB161F41B24AD141B24ED141B64AD981B64A9945AF44B924F44A9143F2429187
+:8051000047832F54F924484E954FAAE414F8244A56F1244AD6E5A264594D4ADE24ACF4D1242CF4912487221F4932481FC9B24EF89164EB141F48B24AB911B64A9945AF44B924F44A944B42ABB44F8AD41AF924484CF9244A2FDF0669A461E3827466D2817244C22845C2288F42499CBA19D24A29F2428717884E26B6F8481523FA42151F7D
+:80518000A2E144F8211A5E8484CE2577A2924D4BDE2145FAD12845A269CD439A7244E189521C1B68C3B481D248F9116429EB81D45AA843AD843AD44AA84B8F4438228F44B922F1BC6F0082184002A041004004280000000021480000002044010000000000004400200100100421F0DAC58002258A02521853856499AB183458138428A1F5
+:8052000043CBC28CE345721801881C9A41B0481134CC2CA5A14B862C034F214482A882184AE8834428954521824AA8C1853518460C22A8869824688928F8258F241F24210888C341214448084E212A058E184633648694128A04B014281208464432381611CC42859244894521284388D88432821E6247228C2BC82829426828472880C8FD
+:8052800096835422884CE11284F4ACCF2468272C8423C21C56A1414324E481F8A31816F1324413613C4849574276B814463B84A89BA113B484C45887434E948F61E42438616F2264858F2104D28C82F9A4482B415AB26471F11CA2282B2C6E9C4D8A478123044339EA27284D824E146E8892BD42C011008800701118182184068E4830348A
+:8053000088BE488880210100002185011AD284280115C4822888008E2885022182810011884588280284282280F4F4CF2012013024208204284A088714927081082084044181800830228141858121011AB2240829012412218CF46482488002008022C884B048210848CF8C0B1228874136C2118B424F213C184E182F857822B2190CA10B
+:80538000272C681A32B81E281F819A44CE31D88E2189D212C21813B12424ED24B22498886AC8424AB1136A42A7285BE1626C0716318868C81ABC4239C2DA624429C62A491C8423E482F82C66202282816242683E86841881425628542282238262825AC24849246684C0A822872136D1489444A42816A84A122B6837212E14A9C8D61A3268
+:8054000052A11B488AA424E82C2928AC1C004DA849FC14481A02228FA70B1814C112271184425846B832FC22828651188E18421DC8189281AE11E051A8181B28501200288A91614B1882A04249A182403221424C829434250820E42104284E26AA44022028C4C87F5A0EAD114462A99834168CD24A4198126D189496621218922AA824328B
+:805480004CB3C223641499A8281842881B94488A6681C04C2E58004A2A081E4421409822824A2124A824824CEA410420489358284FBC0A81233148444618034827424C14342230A441144C11282C44989249C24249C41115C4B8450816CA43E6AA1825B812A461436122AC42B888925419C49C95048E185691252341281AC81427815E8287
+:8055000028C29D61800243E1110A2212141B4189226A214883454822C4128514021038242428AC81041E224084214201008C21A12849C528222468A60824818B422B4180A224C02110D8384B723132141E264F9261865D2870597446CB6C2B839B1223BD841568389E442AD16AA82416A8148F12F424C36C26B249913A8961212A7512EEE9
+:8055800086312C1B6158289E241EAA8723CC63CD4CC42B8D828922AB4188E48F257AF8A42D83A21289A9C1842E88730D0081D02421E122012A2151284052814C2181C2484A33142BA482448488114448C6A542838824D8220D211200A04823E28122E441E214C84889B8117442011004491422A234488F6D0642964242280619913828819A
+:805600008988914241421811150228004824484BC2A0488B18286B148AC444C086181C283314406524C4241684C2A882448249A24A2849A121430445016F6D0D248120229126101431D40098812938C449012622186698444C04246C44021B81882088A8241CCA248282222411C214684004008A0441108638342441FFEC4E22210A11446B
+:805680001043C21438588E18001118888E281638448E184848E088042A51814200AC81A224A44C042582B288A148121562818328024601258108838802806C12282B340000494168114A22286424204414883343001B86842611C494921C5182881284442E4982189011144004232603298284819C8843123844902821881601C082F02D85
+:80570000C52062112501004C216633818E4114A5A184008AA4148A242A61D88A11DD42C8214229048A01493448882AA91A122CC2A8517044210423924110A214282782464442A62846844284F84C8B4011B214D421012906CC012C0A25A4183F41B24E210817424121C8100840521445D83231216422418514481A3811161198142B2845D4
+:8057800068424561285E21D014186241844E14814440C488817FAC0FC0487048E491581885022100800210586110C31B44180014C4840024112490521C441801447023081A3281420018212084818201802101CFB84112213A1925024E8230414125911582112B58142118888100429442814E1160114A58C2A2812E1816044C4452488492
+:80580000132D14C8112FC401B91192499678C5781A022F81284291124814643F280B8C0648605443314421831454284624842258412123054E151F82241142C114218B81004816782264182861844B281C04648C684982A289084CC5824A820149889489892882382AA2FF810D33B4C9237143964217382F11F44258AF22F613B289B1491C
+:80588000A8DB412B561E511F74F143622F23F658344AB241F844592CE9349C1FC7863D415AB884638A4BE82A77347E25B837E5383A141D24471C371D67218FA7F8462D6F42E91AFC438875A3413F54952227C629B283E18A88A4618E118AF2C423243E43B21D12C7839F6FF14C1445942C59D1C434C11887249F659D8D6B84233138D551A1
+:8059000084FF5BF81445966444B564922771CFA4F18A592F22F44D412787CE8C8AEB74EE74321426532497A32EBE1CDD52F2A9921F8536417842DF4C28B8ECF588824F8D89721421B824F828292742EF3A0828255A5A1C51942B639F247331665583FE16CB2F2954172788967389B484F88491CE883F3ACC588F8891885D4947884EE65872
+:805980001A48F2118D2F615B68E7214AB498A1889742BDB4AF8BC9F4C9F4C9245B581A3488AD3283BB88DFA2F12C821E8C49F72844CFE3D842F34634CE144D864D8A6FCA4521444108484048414821418144414862814C02001011081041149128008881214221841480488808341648638114964822490224122011F86BAD241E732FA548
+:805A000012FA15578F84F13F1CBF85E542F212526CBA5421F4EA5D87848AE624EC15F5F4B42B957EB1AF12D488187916F3C6CBCFBEA7118BD5CF4DE56FE111F134366F42E259BD4BE44DE58F6B682F88FC25AE7F4652474FE9F1585E8B841F24E182A21B4E8A6F217F44F45C9ECFC3F19596DFC2FA24B64F41FE14242F99F82D65242B732B
+:805A80002D688F11711A724AF82D5CBFB7E366F35A7B2F6473429582AF88FE48827F4CF84DDC5F34FCD1D2BF8FFD363D6F33D6CE14F486936F3CFC64E22E348F35F5C6C45F64F4B5BBDFB7B7EAFA14F5DF15F614755F1F7F97B716EF8AB8F3BFD3F5A222FFD5F94CD84F4C8DF6513446F647C4EE2C7AA9B75F81E99AEB4ABF16AD892F4268
+:805B0000FB2732241F31F73363B5F914179FD4F27B38FF87F32729FFD1F129A3BFF55D31AFBCF2CF8F6F58FC42436F55F5E2B1FFFCE9A3FBEFCCAD8D9F54FCCCDA3FA8F82EAD9FB3F31B5BBFBDF5721FAF95F53EFDCFC1F2585E3FACF5D1563F2BF789849F98F86D6ECFD6FA5EC4DFFDFD595EB796BF65F179ABBF39FB5BDBDFB1FD5C8ED3
+:805B8000EFE7FB3E466F63FA8EAC6F4BFB5644CFC1F28812AD94343F13F73931CFD151FE3F74F27C7EEFD7F36F3CFFF7F7EFB7AF9DDD9BF88B89FF5CF8CF9FEFFCFDDED9AF9FFFFBD96FD3FBEFE9FFDCFCDDCBCFF8FC838FDFF6F27B7F2F31F5C9CBCFF6F7ECEB8FBBFFEAA2FFE5FFD7DA7F6DFFB773EFE9F8FFBB3F1FFEFDF9FF8DF1CB99
+:805C00009BFFE5FD1FDBBFFFFB5BBBFF8DFDC95FDFECFDF2BAAF87F97AF22FA1F892BA2BFF5AED29E972D2BF0522800145034722100424001A441441B6914412514860441146044E242901219012B0220822C011909248141A24822402200848281220880228F0DF5B208802A0121DC84A21019A3642D028094A2888210B8AA4348A84017F
+:805C8000882588422881EC14A282D222C0D180A82883022989D21A084A282884140288AE48004A2208A2DFA40C2D521F417228F21124A3F41164A3F41124AB141F41B24AB981B24A9945AB944B43AF143924AF147B24D812FB24481CF9244A1CF8244A16F1244A96F1244A8F59C24A9E244DCA1F4DF224421F49522C1F4932481F49F24A56
+:805D0000821F48B24ED941B24A9921AB9453F84A944B4AAB9443B242792498924F8284F9A44A6FBF042B121E6C6B421311FA1164A3E44132421E242F44E948B24ABB84F642134B434E91412F545B842DB17F8294924FA2C5915FA2AC815FA2644D47A28F19D234E419D284FCD12863F21148EDC29A724CB191F24E8219B24E89F248854C92
+:805D8000F248B18AF24A85AAF44814228F4429C2842F82D448F8A2587F230D840000000000442400400400828121480000000014008400000000814004210000000014F0D1AC9064114494839213290742BA94C283C2D8248B48182B4246A68415A23414AA21222A34182D6A18424D282CE484C9421A68251C9212C0E88F2AA184C221BA85
+:805E00000419AA1829A418CA11E489D422BE243168DA02B01A0C23719294184D221D44C30293E52112C51AD60152122B2C96241AE84B6458CE141934C1002D2444E8499A9218281EA82AB482A218412B2111318922B179088BA42331429810A2942818112114471C816FD70E3A644543513C8B249D145A9251424B3CC3BD41628E422784E7
+:805E80002B524B834F28E488F441242F7CB215E411262128383AE3B422E942B4AED121A4835E288B1E2B254A8A21C3481F82C1E8C81CA74A8B4AA6F1A2468A2519B28435A82D624D312726984D41128F7C016512118852342821842E121125628918129882232402921882881B4A2848442242888031482C082C381165022E83822112A9E7
+:805F00002841228101A049A0419810B8218448F847AB40820280216124C400884823249818224C4128348444130B4588080042690C2E92A05280241108E04882813664802188084212809422A01422890AFF17436345D012D124C32C4D484D11325E228C9B181C09184B841EC8668238355AE284314CBA246244282965838A21E3246A447D
+:805F8000D286B461E14882E24A7112B24CA34143989C86A2858F1AE41204372DCCB88494341A72186429CC681DC0845F5F47C212281124C323E54481A12189C818162184F85884888088A5D246ACC14230848021A35812688E548AE448B611E248A2128D84214F8482C4148B282C046846C1821EC34D88C6B414E22412247998A428894853
+:80600000F6E8373044901249038544732488B42281A8842118B048E34156825C12247129A48387424226224448B2C46228268281212404321229B1A48198548E248AB589810A808401128B1224481B142888A72D701C31118CA2422F22B1114224A52154274B8CA2212D54188A329226712402122B21664844841592A40022A4D39A388C1A
+:80608000B58292641B81321114E012942800429F4421C425224932848400483614F85AEE248141418F11445184528545381244128942C244902C46D88208824D421285024C6142AB818AD424B288C414118284111A2402388C81D1A40149B6293834239884682C4498781A72C88464E28CA484EF46074A02004410982280460840488801DD
+:8061000018184C934C82412AAC821028942890142A84C1441C8205448C9844228A16E211C4880024008442002C33BC8200BF3E022D454381721138345D381A7451E421926136B81842CA5A56AC12874B99B222584289E54E915C8F2228924427C2448B6849B22AF84C3283F328D41935111AB211C8385B3499239D472F8144342872AF2419
+:8061800038C41C246282AA8461632ED4C3321C8CE8570A2A11118C5232502C8C126841290818412018A2418D14324C082849C484002F82056045604880B2224C34248200221E2826E188C681C01140C4482744478189E28814A8484A82F487FAA01418248C325148890280A24292E048611143324492A0122420C4428044220530442B4843
+:80620000008904004800244A020048246044A081632286848232481E243E1D902251910053418472488218D248D226012F842284813428302144A122008B42440040EC41C461204804284E124B248A442462442F1588435884006284208114048CF8816B00281285044868841694442A014200002A243145582A61410022632421A5248AF0
+:8062800091841008284094541286820A2C06008AA28428CB18A0488A22A2422088F45A77400848121D2828C0148018C88481A81382584889994488802882681220210A86042826219864C2288284824230528AC12828211825E88831228421441889899414F0C18FF0822418C453422C4286B219C214892C0411814B2422542244431804B6
+:806300003860412228494122014688261894683024481146210A3EC1482829012939246318944A8A8298888449F8F148008CC441003048158414481458848982282104809311602C1384250421861838488C21521444006888604A41104286E8443984184842282088044CA1288B42FFA20F1608408261111448800229838206818800C068
+:806380002820414208002218284001848400502424004100448110048181002084043E431004704222062C51284D215218448A152481A12184C64121A4140026210200424B28B014180841124B12001014041200800488121A1844083A6842F046A7C0488D254925414444810400448022648881222048241866189824984934244BA18092
+:80640000468188826448C81288842284C6061674828C9424842528242401129012F02349247091C912D14F14B411B22CD488A5261A8426BD3C68488F9268442A78C8B91C742584B312E12525C6215A7442A2111E284D724F44FCF2484D244AF248444B24C32EA24C1AF125467B8C4956246BE22C4D78824AF4624247CCACB488D444AF4660
+:806480005EF847491EA426F8EF21B024F66C148781367822F824441D327B261E43CF28F854888DA24E588D825AF61C981E3C4BB26E215AEB94C4848D841EC31B4249B234D24402F6A42928E6F88941848A64414F48F3341486B2C2C2642E182F4B7A4966118AB758C2D8CF8928B2B4C124C6E88128CA48D048B72D0E2F458152552D769F22
+:8065000041E31461D444FD1C6E348B122F8241365519A16ACB441A8468185F43B88436241B282D882692582B4E4F4AC5882E18CD841AE5C2B8A4C284288889E244CC882672C2A4441AB1C6B2729894E3C414A9BB4AFA56882382036AFBEC584B8C4F8B0E80012601003400822182252108824486887281886289441788448C019800800827
+:80658000888008890981F0288270280124400224400289028120F459CA241AF2742C2E243E648F84F25D4C4E243E349FA1D58CFD1A3AAFA1B2B2F11A182B295AF598188F83F3B911D7135F29F16C2CCB2FD7555F7CF4EA7AAB12CDA41AF8484A2F66BED1DF44DE981428ECC4F9383C4CEE87F6A1A9AD4C8D2487C88FD1B3FCEF83F338DC37
+:80660000C5F81C38CFC9F1D8588F4DBF91FE19588F89AD998F89F9FE885F7E0F4B775B625F63F33222C791DF95F46C258FA7F32C6E4B66AFC3E387F5587CAF85F512417AF578589F97F27D659711CD5EAF84B54CF54C54CFE4F46AEAEF47F618845E444E762F6FEF15FF6C6C8F94D444A4448F42F73838CFC1F3646E1FBEF26B6F8F45A111
+:80668000374F7DF9FEF67E788FADFF5C148FA9F99C1CCFEDFDFCFC5B6B2AE422B3F6FF9C91EFCCFBA377247AF23565541F733343DFC5F561663F53F31B7ACDF8AFCDFF48E88FADFF1D9F9BDD4BF7FEF8CFC7FBF1F95F17FC9D996F46FBF4B81F14F9C9E94F62FA32784FC1A489CFADF45ADE8FDFFFB8B8CFCCE48838C44BD8BE348FC9A930
+:806700006FFF58B48AF496BA2F29F15373BF4FFF72BAAF81FF9A9A2F89F98E8EAF8DF9DEBA6BE98F8BFF98D8EFCEFDB81CCF8EF94FA5B074F73531CF71F133335F15F55D58DF66F67B73FFF4F47CF8AFAFFF5AD8CFADFD1D9F1F1DFD74F48F8DFC7DAD5FDFFE31A14F5AFF6AF84F8EEB14FCC1C1CFE6F6746C9E4C9E844F6FF7F2B68FC5BC
+:80678000FFFCFCDFCCF484E44F4CF4A4B48F8BF3B4B44F4EF6CF45BF7EF6F6BE6F4FF37F7DBF6FFED28AAFADFD5E1EEFEDFDBE1EEFEDF9FEFAEF8FFEB8D9BAFBFEDCBED74F4CFE63E23022400129012A41280222001A4404440019840200420010180449080041302400908412452221024048C448448400008F44029EC32008188C224297
+:8068000048818421018021C1144588F314483880A14128C02167228081E22231188828182880A212A012108282A121A0284282301428844C63818B242218222773D026F51124CF22F11124C3F41124E3F41124EF24D141F24A9219F24A9251AB9443F24A9143F34A915783ADB54F83D458FB254A8D814FA27418F1245A96E5A26559ACECD5
+:8068800049C24A1F4DE222F49124C5F2912C8B141FC9326A1FC8B66AD1C1B24AD981B24A19B54A3924AF4439242BB4478229FB24484AF9244AEF4A042D121F81D628257148B111764AA2212F34B181C6121F48F6483247888D114B4AAF1431B12F54219B122B4B27144F2AC5142EC24E852E1246E1A2695DBCFD58244D8A1F85E222FC112B
+:806900004C4DC21D2449B9917662D341A6928E642D1719F648A259F2488243DA28B984B448BB84943A6B4A29F9841AAE274008480000000026040000000030220000200424001041084904000022008008000084005012F022B5800624897128314429965429D14828C11842D04868849810D94164814D389C926441842534144889B241C9
+:8069800008493444162424F1A1149246A461156824241F4862251882672149810120F824D889A81630448FEE0B6D121B282B124962448311C828541A62144A88D1C2652418837422B414D82282A6844B4186B84892424A83F221161E812E1849E189A292224BA12884642C497452B2A4812C25481B8198818C22B988F21824302414CF1188
+:806A00003428BF2F0E6F23B44102167C61745826A41661C381658D76146CCC128A64428D946511E2C1F419246F81C24CC238321D56381DA811CB284C7C189444724F88C15249A83439E148D72294254BC1B023C89492289289BA3C684DCF28A24347951E44DF7C0D002F228112088342CC118A4201241A44C2488D1240A1428B34A2428A92
+:806A80008452A2461484D281289514522A81A292601286E42441744802889A4472114802256581006082100126F8FBE7003024124F24E14106124306A981B44801184781E08854184303432124223424448CA1248C218401589288124180018006190400002A14B2244434A4428228486E742428362281C228E09122C418818A961860812E
+:806B000063A82C67A24CE34D22E44A844678C83484241A5642B9614449081A7A2498644F266118AA11684A1B583EC9128F62E442591246A9141C7DD4A1812E8CB0D882654B728F45B824F896B20024A0218F2422460989019884128D12888D9445E88AF1A8541A962418486AC8C4906216346A528A042849E24128082A088A419161528F4C
+:806B800042D442088180A9186A4934644688997438896A48DF65452222B314024361412A21E54214B84A22354890144A7222324414448AB44442588430246C416811C441181AE884A1244C3793491168421AEC81880219173341521CD41444628A30B44B4282C24B144AF23DEB30442658188E6842214C321F408A2834883B5229150838E0
+:806C00003B21301886E68281084971853A58301883FA482213724248C8542244811021E84472112E64928CD2483812288C84022828616816D44AF48F11701A32144C82A4128D1518284249B2548221B12C18383226DC14243818282C324181668201881AC64211291121C13C1129A43814360410084D2280C164AC44816284893644186ED1
+:806C8000928A81048F12060027219220027014881518080088588140842815A424CC0848221022018800A8004391486B1A2A34114A88210144114216827914C21844406882828FA54BC2544CF11C23182AC1214CD3873218CD42D28183F9845248237354F818431B1A453838E8CD418B68C64664648383C2583FA8331828833414473128D0
+:806D00004C521CC986AB862E494CD842B521618283C841213E488E688D226AE1622164864D488744DF4A012428218C6224160C1243A42183A2412415981886883224208138143890285018485221E022249812282A0C98122C514160418F1481122A612416681490124B4185044C2B8923F8CECBB024F58A24412A411832182B16224BC2AD
+:806D80001229CD2C9844238131328E2C1C0C4C22C124004244001486B544A1284B34428497496048409484114A280411241118614004244C944483F4C362100210081A0284168421044200821441184D18148AC14442C1008B2143A2488901148C34811F41488194182C94851D284A61E2131111C888218C6A4842860400E02201DDDD30CC
+:806E0000249A044158444C1482044100204414848824A12498438828180440A1184162281C02A21A241A04128032C42604284A01412292229A6248418C6288288DFF601170183442248344212C1242138831468429628CA9042366414222242C2182A4414F88448414426848482128112820F29144141242381C014F152285198108221A16
+:806E8000882912F4DC69241032222844A0422816E428A224EA21C19282141A24624A24863144C2222B2CC02480C248A0C14A6881881AE4840856C8E822481C28A482A0484A012442221A14C4448161D012F46B68008504C0281218184820480490248924C2128984280190424901000040C414001438412821482866242211080042101C8F
+:806F0000042848424B414B82CF170D200184290440088D14004048281A120400004C0148848182400828004082012048981A8C119C418C421868818302268838182880086FFD024282A41004A15082814B1230C2445214414A8801268482416824A021481E4849614C8C4288B4192242848208190100918A911182473C82442BD21828C012
+:806F8000A42A1142F83DF44028C24116F412818F440A40034044AA245084178A40120C502282184B126948042120415142440081441A52489884882042041A42240446A841D21E488C5882F09C5A244F61B4AC34141A6121EB6BAD1E21A754EFC8F871368ABA4AF2C614ECF942A9AFECFDD2E48D163B492AA9D44F27F11684CE421849E284
+:80700000450447884CB19439842FC9FC54328E81EE4B4D9943EB2CDA44DA14F265489EA14FC9F5618117141CE861E1586A292D644CE4447954B4A8EE42667285B4740C237692D4C87264FA8C6DB0517628A83248C8AB142C0C4B4693BA34921C4BEE8DA41D218684A824AB822E2416D488F3A1E82B55CD424E448C17BCA1AC468F4171B8BD
+:80708000E4C4B32471E17839FC8221CFA6B161A2111AF358581B4CAF85B466A51CB628E888F21412EB1DDA7A62F88C9B9031AC43D34AB242E1C4015AF714423A13A6411E1C8BC1A1474115217212F844186F41B434E248E4AA54446D426E4841C7454C78C1E8927278B46152585B312819522889E411A1DC8F41C9448D8189F6288886524A
+:807100001C49D148BA3CB84CBB34A2D246CC88CD5849FE35B21021120111241145F2114826E288446289248A44022C224832812018281848022C18C882812C082E82C083800829012D811046482141014008100800F023EF1417313FD5B321E272F34899DFDBF37436CFD2D214F346181F15A32287C6EF85A16D1E121AF314B64FC5F132D5
+:80718000181F2AB124FB3C38AFE3FA2A66CF2A771AF8589CAF41F94652A9F4486C2FC3FB422BAF13F7D4666DAAA5E8E1548AA771A7A4E5F7DA58ED9569E113F3685AA7942BD58F83A2974F42F268884F44A99149A4D167A24BF37032F6937FBFC3F3181FCFF7F37DBDDF57F62C2D4F51F3D53D4F27A336DAB714B114F114155F15B7C4EFE2
+:807200008FFD34381B776B99CF8BFFEEFEEF68F8CEE2EF87F77C9CEF4BF992D22F21F43BAD2F46F662236F7BFF96B54F9552BCE7C58D88AF75F54A49CFD9F8D89CAD9DEFDCFFB8B18FE17346F54AF88FE7F7FEB8CB368F8EDE44F914D8EDCC1E94CFCAF98A19245E427F43F738336F42F3E978AFE3F373332F27F24F78EFE7F1D3F52F2B88
+:80728000FA5A28EFE5B1DAFC26377F17F77EBE6F4DF972333F1ABB76AFFBCFE6FFA2EC4DCC87A17F57F3F9F7DF1CF591DBAF97F7B8BE4FC6F2B5FF6F4DB7855E898FE9F85A5A9751AF85F1CDA9DFEDF54DEF8FC4F779719FADFFDF99FFC5FD2CA88FC7FF2CB46AFA7C1CDE98AFC4E489F924185F4149F27547FF6BF33E3FEFE3F3676EBF68
+:80730000F7F77E64EF65F457727FFFFBFAFEAFAEFFD2D2EFEDFDDED6EFF6F57FDBEFEFFBFADE6FBFFFF7F14BDD4F2BFFECEE2FEAFA46ECCFE7F7FF1D9FFFFD99DBBF99FCFCE94F6FEF6FFBB3F55F5FFF9DF3FFB8F8BE8C8FADFFD955BFF4F6DFFD9FEDFB49FF9FDCFFB9B1DFADFDDF99FFC6F9FCBEEFCFBFECAFEECFCAFB94D8CFCAFC8C1D
+:8073800098CF8AFA1D57A01210044180210148200112441F814464812812000042C0241800201218042E111004418CF42411160882149220490444001281E04422180B2C6141A02123C868272A4843022B16102A9112B2253284244F82044B4A4A71A4820A83D184E449826141E045222209448B121222A0828A04CC2206248481A229A12E
+:807400004A4E14E04422285494CF52042E421F41522A1F4132481F41B24AF11124AB161D64AB941B61AB9455B84AB924F44A9143FA42B157832D914F8AC4B14FAAD418F8244A56F1244A96F124CA96C54ADE242E4A1F49C2C21F49523C1F49324C1F49B24AF18124EF14D941B24AB911F24A9351AF343924AB9443F24A9447822D944F82A2
+:8074800084F9244A8D17E012F4114C2D431F417248F111244E111B2126F181445CB191E644B28596184B438F14B9A4E4147BB5086F8AD418FBA45A8D914FA2EC15F8251AD6F125928745BCE855E2A278D1CC821E6CCDC31F41F24C821B28AF24E148D23E99612F44E841D21A9B648D914B424A39242F4429DA42F92448884FA2E587072020
+:807500000800002860484004400100000021000000180014008480040011000018000000000081F07F376034325C712A64168CE252041C91684A22B3188414C8141C395886328126B18CB11838848382A621451128B1C46148228C62484988283A1253F638864DE24C28911981661852488A742208A618E228644448884B282FC20B2E1475
+:80758000822922C1921A94824D68872249E828C189148D844E148C24C6249F42C14C432544258458C3484AE1544251282662C52F4184A352639116266C211C84A12166A74AE661191F2CA148CC31C429EE41247A38B488F284188595488F2C0C59B4C242158AFC12228E24418931C84F24826A878D84C381B1817658A4A12D814D131E888E
+:807600001E894B8126E85C22C4414414C3686845D8187338048E141694662E14D9AA184B825F21D48192E51FA2B421594883F42642888D32888354A2874443B83CF4F859A012122B121E242E118C64148C66324C827911488124D484842152584D484A924444488825A82149F14821185223A2256924F824D2B022688146A3416726122285
+:807680009A142869248AC49486A8244B482843EB442A1928F885C8C042440081174140044818101A218404800800904488840014604124008094218192200982810084818A24248908888028828874E1023812451A04244813C25822A146C841492411341843B644C228182E4487428302460464830889888431129E241843A8823048C021
+:807700004826028118285A48C898C3B248C1841E48C93818439C1441FF16032A04008118481D24522283914894A014448991644304182A5484492608502414C01C0021824886A182928324C8482A0800A01486A8148C2A99844884924302482FFA0D182741C5C24450412140285442B02274440148008A922850242816084D480083088836
+:80778000482981C13489B12414082001248184166482832A34884C9148E0813884818A34942D148F9B0119010060A24A611216482AA8388143A41413E244D2C312A412290122C02400400843536884104401891124022E844828238509128A81114AC4128088E2418862488303221AE28211C81C0085B441224608122948B81A480820440A
+:8078000008C481244E215628011692882800286928028216041A5484818189D62825084A088440C8141868003F6404412444142831224200100912544220B1981288B49422240A4424812A81420232AA0420018484830200280084A3442C0190E426CA880022FF970253C2221644311417A24A015E212A948A81249E44875419CB2445F94E
+:8078800028942218822A244A344740E8826122C31B3A386AC82686011638844D288382228482C6288F21A41846C8C88C5184122B428F43B88AA2D200AF6B0918128342782802221D6C8184B0919218C0128C744822031E48A3343485448822325829011870240200411A028418B044495C2816A8945028926C01008D8480118432A47F6F54
+:807900000B0014844068220000110014001200400841401848080000002001100C00000018824A082081080040F284D69014808281226441465814462124041B41108882D48474485448184008800144C4008022020018241AA212204228088284809A88202108892838C86B6400302148228384224481644448A041148002462404160849
+:807980004140480841810020028112004428120000804828AC8284188882408858221F980E8D1C8B444856086041251814514455A4222E21228480455848C5522225B218A11192128440041100878285A8444AA414858221022284474845B434A22A2280081840D22218E285F9ACF51024010000000000810000588181840084282800003A
+:807A0000800100000000220082802808008008400881DF7F028184421F410400000044CC22A2244800005022901A129882880040114101848C24A44100000044614C228282088001002129F171694028B414040012288C044084A4248100410000218001891808004001818528A141007012082508214C082882240000002508EF8804805A
+:807A800004004100004584840200420000218118800800260814008508480000002048042800000084100218FDB300000018004001800400404808004008000020020000000000000000000082808208005F880C893148124384422401004D44844B222A2202814142834452A2241A2121293888001011115388B048242404120000451419
+:807B0000B424AA2A2200004002244B11F77E10548C484A04000040445448E082028004001012028B1188880022404101848C81840424100282504844A062008008101A16F2874500129011000011000084A04140488802001088022830280040021200122480012100828004908200818100B01D0400000000002004800442001008C1801A
+:807B80000228000000000018800200008240028001400800005FC804411249D151014524018C1401818014A8144A544412620000002A5288902800180000181A81420221A088828180082421828222888518044FC1024024012812001120A4448B44844E481078486884101858888568822E2800002A020020812101206181264208240024
+:807C0000828081081E88850800C13FCA061684014301802102004018084800895488848441100881226082002424001200109212104282A8888A3842C28200008410083F360F6F22F216222E122B11122B11C0122592832F31F111119BD89658888F18F44848421D49114895588C4E488F44F42C444B242A22E24202284554642E246F223F
+:807C8000F212222E122B111AB892092C592229F812139F11A1989E89878489A444424E4880548885F844489E19F0262225A2123A211102142592823CF1111119F8918887818D414A2444591148C485C8488F4454444B244B22224400255444286F2252222AA1131A388282502229D8B2F1111219EC897818B888BC48244408405C888CB4F6
+:807D0000DE0700000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000024002450222552220024242400000000410000401404001014040000004B980000000000000021002100254212020010022440020000004141000044415044410041000000D05B0600000000000040024002003A
+:807D800021000024000024000000444441000044504444000010140400F0D8CC00000000000000000000000000000000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C000000000000000000000000000000000000000000004014040000004441005C
+:807E0000001FC1090000000000005022212100240000005022002100000000000000004400410000440000FFF60700000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000000000000000000000000000000401404000000444100001FC1090000000000000000000000000000000000A9
+:807E80000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A0300000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000000000000000000000000000000401404000000444100001FC10900000000000000CC
+:807F0000000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A0300000000000000000000000000000000000000000000444100000040140400F0119C000000000000000000000000000000000000000000004014040000004441000034
+:807F80001FC10900000000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A0300000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000000000000000000000000000000A8
+:80800000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A0300000000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000004A
+:8080800000000000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A0300000000000000000000000000000000000000000000444100000040140400F0119C0000CA
+:808100000000000000000000000000000000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A0300000000000000000000000000000000000000000000444100003E
+:808180000040140400F0119C00000000000000000000000000000000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A03000000000000000000000000000000004E
+:80820000000000000000444100000040140400F0119C00000000000000000000000000000000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A0300000000000048
+:8082800000000000000000000000000000000000444100000040140400F0119C00000000000000000000000000000000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400435
+:8083000000006A0300000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000000000000000000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000000004042420200000000000010
+:808380000000004441000000400400006A0300000000000000000000000000000000000000000000444100000040140400F0119C000000000000002400240024401212120224242400000000000000401414040000100400009F4703000000000000000010022424000010125222400200000045140400004110140410045044000047E24B
+:80840000000000000000002400240010020040020000000000444441000044504444001004410000F0E55C00000000000000000000000000000000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000000000000000000000B5
+:808480000000401404000000444100001FC109000000000000101212022410420200401202104202000000004144440000400400004100009F150500000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000000000000000000000000000000401404000000444100001FC1090000000019
+:80850000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A0300000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000000000000000000000000000000401404000000446F
+:808580004100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000024244042121212022400000000000000004004001004000000001FE30500000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000000000000000000D8
+:80860000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A0300000000000000000000000000000000000000000000444100000040140400F0119C00000000000044
+:8086800000000000000000000000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C00000000000000212121400200000024210000000000001004000044000000101404002F670F000000000000000000000000000000000000000000004441000000A6
+:8087000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A03000000000000000010022424000010022440020000004514040000415044410010140400003F310C0000000000004002400200210000240000240000004444410000445044440000004100009732000000000000000043
+:808780000000000000000000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000000004042420200400200000000000040140400100441440000F084C700000000000000000025120224210040120221212400000044004100004404
+:808800004440040000410000EFDA0F00000000000000000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A03000000000000100210025022242100002140022400000010140400401404451404101404410000FF4407000000000000EF
+:808880004002400200210000240000000000404414040040044544040000410000F0E79F00000000000000000000000000000000000000000000401404000000444100001FC10900000000000000000000000000000000000000000000444100000040140400F0119C00000000000000242424000024000040420240020000000000414173
+:808900004400000000440000F0BA6F0000000000000000002121000000242121002400000000440000504400440000100400D0F20A0000000000005022212124002400000024400224000000000000101404100400400400002FAC06000000000000000050221002000050220000000000004100004400444100000000002F550F00000014
+:8089800000000000001002244002000010522200000000451404004100444514040040140400F012140000000000000024242424000000002421242542420200004044140400001004411014141454444100F071A400000000000000000000000000244042424202000000000000444100411014145444414100F06F580000000000000014
+:808A000025121242024002000050225022255222000000000000104404004100000000F093D60000000000000000002542125222240000255222502221000000104414040040441404410000444100F048C80000000000000024244012120221000024250250220000004004444100000040040000100400A7CC000000000000000000008D
+:808A800000404242020000000000000000004441000000400400006A0300000000000010021002100221000025020021000000000000441004440000000000B0B901000000000000000000105222000000100200000040544441000044414445140440040000004D4100000000000000004012020024250224210000000000000000004109
+:808B00004440040000401404008F3B0300000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000000000000000000000000000000401404000000444100001FC109000000000000404242020000000040024042020000000000004400000000440000F019AB0000000000000021002124DA
+:808B800010421202002421002125020000000000000041400400100400001FD40400000000000000000000000000000000000000000000444100000040140400F0119C0000000000000024242400000024002400244002000000000000440000000044414100F0EF7400000000000000000021404202000000244002000000451404000099
+:808C0000411014040040140400E062030000000000004002400200210000240000000000404414040040044544040000414100006FAA0400000000000000000000000000000000000000000000444100000040140400F0119C00000000000000000000000000000000000000000000401404000000444100001FC1090000000000000000D9
+:808C80000000000000000000000000000000444100000040140400F0119C0000000000000000000000404242020000000000000000004441000000400400006A030000000000001012120224242400210021242425022100000000000010040041004004440000E7270000000000000021004042420200005022255222000000000041402C
+:808D00000444444400410000400400F037BD0000000000000000002121254202000021212502000000004514040000415044410000410000F0788C0000000000000024002400100200400200000000004444410000445044441004000000007F4E0D00000000000000000000000000000000000000000000444100000040140400F0119C15
+:808D800000000000000000000000000000000000000000000000401404000000444100001FC109000000000000000000000024242400000000000000000040140400004141440000F067370000000000000021002124502224210040120210C242484A248484A444428084A44448004B444240040000410000CF4C0800000000000000007B
+:808E000000000000000000004AA44442484A048084A444424AC444490400000044410000DF2B0F00000000000000000000000000000080A444424A04000048004A64444B444200000044410000B78E0000000000000021000000100200000080A4444A04484AA4444280A4444248484AF4444442000000444100002BC10000000000000058
+:808E800000000000404242020000484A240448A0444280A4444A84044E444324040000400400007DB60000000000000000004042020000002400484A242484A4444A241484A44442424A64444A0441000040040000CF6C0A000000000000100200404242020000002424A0444A24842424241484C4444A84C4444CE444241404000044415F
+:808F000000008DB4000000000000000000002100000024002180A4444AA4444AA44444414449A4440046044604444100400400005F540E000000000000400240022110022502002400212448424AA44448401404482084A444480000005044100400DFF5494121414811C4482A6482214849018B1244000044682001252824120218891132
+:808F8000088185420416088448488C61814800222244006C42042C8222216181BF170C681D4831819C44D42CC1444E24498382420449D284C22476E4822181439818160223213112AD2421188B12103428222816889418A162622CE2222422D184084F22D868023827C323D92839882C6C447C08111211818148CCD122220249014400005F
+:80900000228001810048223012C3028002810018180042832104100282801834222428888C4A28C818EF1D022A44021419440840B44403228303408C82544848224048082418800116084074228CC2282064A18084E12284061845082484411A321880012CC4469FEC074041084120344C4800000010848122222181110200002301400848
+:809080000000840028220000000010041A420200FFF801C04800408402002200444C220241120000122123012440088301000081201408840022282241432202214425029812F0D4B514009011000000000000001200880082000000420000000000000000410020080000F0D89714281E22856481331541229218462444CA1848100819D7
+:80910000068C6282C459C6282219D28414CC6840081AD4868101002100831188911AB028088C016082824D188668811818F0F29100541361128CD248346846C124A5C1124A9941C331474ABB8494986598452324C5184E81A4468C62141223A1426908882AB4248132B44D224B68E5C2464AB181E4246A3118D02218DC226A281E42A27661
+:80918000B484C44842C2CFB24621C233919CB312541C8D622E4116364142882F94C142441290614113924856EC926186872219924445C8680020941C1A02A01A4C82449A48A3E519B482C3138B29248721642E828C88B81ABAA491548CA141883F9702409414702881043028C42CE18104478146E18AE4446889A14D482902463481D08469
+:809200009428192491128B2469289182424B122845026F22489414008C14022018082CA241448C94884880F4531240428461416364C1141D4C85828601420011A0488901814343215218454834244611D248E28284021A92C411496181241308007028618924118100A0848688288808CF6409636622442126286623124371143A485E284E
+:80928000981E495AE8C421126E4A276B8289F494289D8444682A91588743CF13286441848D144531122CC18A225EAC83F3441916C8824F81EA28041B844E984B498F417A44388844122E44C149A42CBFDF0A27662634141686E482912143558423C5488B25421842479530448B124D82814F8136884908841889F214482F813A684E28849C
+:8093000018804491941638A8A14984018B81118B8146829814CC588480A4814CC88880F8443200101262C246642191128D2429011A68948A012C32884D823288E0516292C5B14492244B41261115941428C41F61929412A12932541B389341C8822674E80213B81994C82A8194884348A842448E442AF4D9384002382818442C6141278141
+:809380002D18AD8442182698146D928E548721869144921816140AD9E18834448465988244134C785492182A44481882839122198286C1986CE1536441981018082146C44421AFC50D2B4341807444D881123421422AC4142229A4128148844C66843285413E287026828B911288121181119604898884C12418958438143088CC082784FD
+:80940000812840084C12F814A896688263F1C1AB40844144888291488400C01824C2482828211E2424426014A6810819628232481223140628284391241A382482830282448082886888288AE14128B524052888428FC7052B614143C32862D44D4A4D2B8D128997184AB112E481F818462A9CEE4E168F5BD424B49194145B34A66B423964
+:809480007271C82C12ED5214E99446478832221A32141A9A268743A6E24221A842888AB19A7419C4983AE8888128C51EA648FC48844CF4D4E950241200C9A12118124290828C42820443C11226083281848180588490528B28200982184694924483428C318189012661C889C128248A44047014D848A2424CA14B28F0776630428414708C
+:809500004261211442AD236296632C18E044A84244872486423884203888200226D816B98241C41416B411128A68891E884C489E84C08180C882C032144FA4A282C280084AA88180785E04122B12854288028003844344085D9884103225904123042E1160261311080013EA845282434C314411E014021024611244111C5A184388711837
+:80958000C414421888444022A41E00441064924992682904C634238CE4881418829418C21CA41819E34807AE442B288C94114C042A9828A2202AA982800B6AC8116A49A886132804C282828483228862482841C2A748CF730F00A02100402404842E8480024148803164508181C01141200116081486518244844904484448814189018BAB
+:80960000124800432208424088C1C81228C74F20041424121218181C028800218305218923829288204841228142814225D1A4411401534108921991A29122121091881311430182801818048245B8B20A61302C4448414841814D18A02143E144C88236244654814418442485541A8584514881480089C1141840444C0484441184002983
+:809680004218E424084614180810381CF08A3580C312608184AD42854188052C41440821841E8135821142011906184081542284460146013562841912111108205141121818828C012200123842368402FF1C0E5034C02160922285031C8824411493212D8881124A9898848C08148800166118142584682230A41B1292418C32A1153251
+:80970000A182823635881502249424408C028A8304E08302262AC262C012421829021A124886AC248041028C42229221212218222A28222362886018002508682001D04844C4482287418006418C820A430190464AF2E1B3242F21D1827328518ABF96E586E292D4A8E412D228D598A9C68D44442CB46A64141E555A7611F2482197521F91
+:809780002252A9A6F219189D2115DC83D229F125CD4729CCB195D1D1515489ED817241F11C179B3853F1841CDF12C1951F29F3898987395B488F79F484888FC1B488AC19CB82CE848BDCEAB882FA458BE0463411357C15C2225D461B145F41F2484A1745CE468B1869789FD24AFA14323EC25D22A6D244F2A31449E318FCA4211714411280
+:809800004F11C1912FD21AF8288148142B813B911D29CD844F881E9182A59981C45F8914B87252838D816BA2A7426B24628C48A85147C21E5E47C6EF950B2847622CE24223B11AF11A222B1639F1A4A81B212FA1E2ADE194EC9C61C8AD1CAF86D89BF9EAD81E88CE8816E844D882FA62242AF16862B6A6499AE2C4F39EA2AF66FA8422EA12
+:809880007694B4A16143AEE84714AEE48F11A6E9282EC918F82D1417841AA28A45A8229E144B22124189B41C0F5014501450145014124503262241244134114411641A44B41154484885845448218198B0241DB824054712A012844F260143462806464348022C012C0389028110F8A881E021F5141E3E1A4F62F6486A6D2687144F64B257
+:809900004AF39C349E9A2B912F82F941817B982B3BFFB8F9BEBE2F29FDB33A7F3DF9EC2CAAF8F6C51F16FAE4343E391F36F7E763BFBBF86B6913F85678DE5B2F79F3D2D14B3C8F89B9A9F849C81F18DA59FC81F51BD4DF54F265791F16EE44F111559F197318E8A8F126462B118782128F82B324FB2CA8FF2247F252122F85F73833AB72BA
+:8099800087346F66B262F24E3CAF16F7BCB4FEFF2F29FDD2F89F1CF8CFF8FE72FFBBFFB4DEAFADFDF3BA7FBFFBE6AC8F8EFCE6F6BFAEF8E6943E391F27FED7F31F3BFAB79CDECD2F4BBB94F9B6BB3F5DBE94FF9C9C9BBBDEE61F4CFE89E94F88AEDCDF46FA3CBE9BB2CEB6CDCDDFB8FA18848D9EEF66BC32F9A4944BDAEFC4A4A26B13BFF5
+:809A0000F9071AD555F4191ADD27DD2E7D27FF54D275F2571C7F5BFFDB86AF2EF3DAFA5F78F8DD98FFDEF3FEFAEFE7F2F6B67FEFFB97F1EFCAFAC4C4CFFAFBA5C5CFC2FA747DDFF3F3F7F3BFBAFAFFFD9E234FA9EBA8F3D2FF2F19F8B4F48FC9FBBD94DF89F8E7E3BF58F8E1B59FCCFB99F11FDAF93323AF8DFB13D7BF15DDEE7186F8F431
+:809A8000F48AF8283C8FCDFDAE2C4B7FCF86FF73D5246F65D77FF63F37FF56F26D67FFF7F64F6CFFD1F75F5DFF59FDFBFBAFABF7DADAFF78B8FFFDBD37EFAFFFFE9EEFD7F1E7BE7F9BFFB4BCCFFBFBECEFDFFAFE3EAC4FD7F7BD3EFFBFFFABAA7FCBFBF4EEEFEFFFBEBE6F7FFFB2B55F5BFB98ACDF4BFBFDEEFFFBFBBBBD4FCFFAF8BCDFE7
+:809B000042F6B8BEBF36F7CE9AEDCFFFB6FCAE96EF88F87C748F8AFA2CBCCF82FFDCDC8FAFFB6CF8BF15042A012A01228426C2482284A0482484C048108102281301801202201484120441100400004D11122008840080048220088220E87C0261116552814F2C31115041429674226181214874F048B412AD8619D44839A4184788145561
+:809B800058181F22718894148E218492251A8129F12881174860C8A113186841263111A93884256182AF4408608146741498282E413FD9056D421F41522C1F41324E1F41724ED241F24E121D24AF26B911B24A19F54A9743F34A9553F24A975783AF54F935488F54F9244A8F54F8254A87555FA27498F5224A875D4DCA8F4DD2A4FDD1249C
+:809C00004D521F497228F3912CC3F4916CEB141FC8F64A111D6CAF14D981F64A915F81F44A954783AB944783AB944782AD914F8294984FA2F4B45CD0A2A4618D421A12EA41764AC224A5C2648F66B91192B88A764A23D31AB925D422B931A4947B432B944FA2E514D8A5ADA51D489AF2224AC6D53628DDA479D1D824A1492E431F48324C79
+:809C80001B494B148AF44A114CF442951F48B648B194E45432B44243F142844129F92648984F22E5E20184800400000000000000000012000000000000108404481008240014000000220000F0B5B5208461818481482E583AB419B214F44228218492812694394F815E25884F11C238608800112E184A8133425062414B142B1223382652
+:809D000014D13241442A71D802168168298C998A2E188911F486628C054E2824CF51026B21333222143D54ED12512563442D8192528A51842F183199C60483B868A148C843C821A6048C821492858D94C98181B22118D441419A3C8AD184AC12836D2414893A888911458131844AE8818AA128485C78C4D8AE0E4B415E288C52295375521A
+:809D80007471D81276586475C72E18B28817898F42F915288B52937812E829E28A614896282818E8A184218318D1226142CBC2324B8129B227D54898BC1634DC4E124E134B828E188B924D119729813E888B148863DDA229B448D224F897AF70221291121048182671222388811478141812A1844348A44A46850413C224C02122425D8256
+:809E000087454D184430116512114CC811482220628881112018224924D84823A224C0848C94C1001D2421120000E041129821834448F231484A618114128884A048102101448416443A18C8286901C54308824364482724922E911E48409818924447814A22823834812AB4C941B142022A912E83321E1E288D1415784831C24A31139012
+:809E8000538676217422B4A8D11C762871F4514845688C8C628417A589C5962CB2442328F342942E811A88E818F2922DA7438973217834784449C88289E811748114F4D2288A36844F81944C998414FCA355006432CB218722CC816141841F44828C125928126E8925D5847188E15431894F8842E4C8A4841412899518CCC9142E528381D9
+:809F0000AC4A388A51492E8897218B12488C2A153C298A11921185C4844B83838AF624484176048CF48897342AC4211002C02881118311EA31A414D021C4146E12281AC228221B14814098288354214604235286883662615C088835C2A486343C15762C32D19889648846C8911692484B414C2891C885314843622114183618984C4B4254
+:809F8000948E245C4288C48245E8289218A74186A481902414834182716843A6524F1822628149A5481674890644CB824BC29217C884274244297258E442645D1E228D82844D2881445C3428C14308842D88DF844B322840A441886721182443D422411824B1A4846412E1CC25E8C69125ECC141409818834C248802B021E184091602C1F5
+:80A000001A644294E0A1846A88851481C5C11F254AA4212C01421263A242F083E3D041544213812289C288252803121903008C01148C05804C88281804812D2481AF12912842282601122C22A2144AA11E40111242081604428C58184B18230148490125477331E2423118C3A1612D3D65D836E243944286D81821E1C87516681A2B81530B
+:80A08000A4426A71318CDD81758822B82AC4298D24CCB218368A1E28EE148B694D219E24236948A9FB28528F46E1216CA28D54AB4A2F9964B346B254B84D39461E8C811E82C321C1644384F8DB81904450142841A0128481122D12282C084247818564818D94550845081B42851464442492415E2141812184C0248B1215141431241AE408
+:80A100001248049098150884284B41AD24484C088943F8D3D5602486C218902217814C41011F848991822118983888889688A48180988244886A314592133888304486241854412E88130C841308821941381881C014A21252C014008823F86E1B80014180912242811C1102704C41014260342430481812844E82222450A4121489612222
+:80A18000124E164A223812872226F2912440062CCAA22C0A18214824888B422E8249B2249928484F1B48028A06428C0181208462244042426214254951288551811C52811C4444414201960D26841404211290541A1258C1B8832108A082414C6A41414BA14B189882C816A4181F9A0E80C122190110544800294A81196844181860144535
+:80A20000124408405882148845236441429692484A826122A2248148002E44447846A441804482040049012149F28FD820B31822018D222E48C014228903480088608621400822381E2480B22191149941681815C8841AC484901241A2102411044B21C01849A4814623022248446812C826F11C5E002460A342121E2822162208B2C18274
+:80A28000207812B1A8C5218219A21882823812818022E2449282289C084C885218448D85E08288821D68584C0A10684440842282110444A736400C11401164144221241120012581022448122180140280044810884408800612A100002024546212272420084220442804483FF10D42828480280C4A2104182C61241344033018189E21F4
+:80A3000012850194501810A884408262111412188115141134114C810119044241133411E04A042741202882015FD24C72210A2C060028302880CA4488898AC4812E84212A18B42488D892028F120988722248628644092886C885481282822CA2488722848144886B28242C81018682840469048FED0723F1B8228456E385EAC2B81C6136
+:80A38000D42AE1219B312D814F44958A17142DA21F86F3228885F2188C17D53ADB28F12188860D1B2711C57911E4B8B1E8C26449B944E26A43D288F254128FAA52988AA212AE1E2E1449D222E24441E21161414AA2428F42B444B3D4D444E41585F474D1242E422B483F21912885724851C18B31AF3124B812E829F28A82822F2834118B58
+:80A40000881F2CE58338812B9A93E8883C84CB86B9CA492F87F521C42B922AD8C1F8949A3FCDA48B2BC55FDAD124F1A8AD2D8413F938849E244AFADCE18FACE88238166B5530446F41BC44F344B244CCA3378F48FA2494CFE8094E3518CB2229B123B112A76649A424AF92E42AA45416F9114B4B81EE51277187113F1CF72653C942F931EC
+:80A4800021A7152C62932C7184E52DF3C849DF4496568356186C15A4A13F5B984153F164945D1B4DC28B4115BA31B4D8E5A8FE8184FF6EF4A2F22CE1493892BEC22AA888412B2C8F870317442A51412352412312312217812220023014281A84A241284828484CD221844282C282282C014F220100619012B06201430220084041C82482A1
+:80A50000448428844E248446F436E7144F5CF6352F85FE15575DE51F31F94E266D158D39AFA6F383A125F3F2875D8F7F58FA16B3DE954E41AEDBED9E3FBEF928E81F1BB956F4E38AAFACF13B49CD887FBBF91E1E7FFA7889FCE2EA6FFEFEECE62F6DF4C397AB99DF79F9F1717F4BFA6326AFABFF121A7D27FFBCF81A122F23D171F1473538
+:80A580008F8AEA2647F2621BF5FE2A8ECFC6E3C27368F94762342F35F523639FF153EECF67FE6B237F35D41664113F3EF2D2942F1CF1E2B7BFB8F8C3E15F37F2323417188FA9FD8B8A7FCDF9ABE81BDC2F2CE58CF868AB2F32F25E5F8F9DFCDCDFAFB8FCC8CB4F49FAF4B5EFCFEF4CFEB5FD9EBC1F1BFFF9FD3F1EFE72B2EFEBF67E5EFF17
+:80A600007DFADAEEAFA3FBC2F26F74FC56D5CF83FE34364F21F9F69EEFE2FB46C66BF6EEF8EF8DFDDFF290613E62DFB2F2383EAD6AEFCBF34F6D4F64F74B7A8F2EFBD3B53F1CFAD3E32DD22F2CFD74B3EE9D2F3FFFEADBEFE6FEA3C12BA29F9FFDEDF14F1AEC22FE394BEFC6F6BD9DCFE6F7FD8DA7DD4F4FFFC8CE4FEEFEF6663F79BDBAA3
+:80A68000F9BF97BFBFF7FDEE9FCEFABEFCABFDFF54F66BAFAFA5FDD2B23F74F94F9D4F4CEA2EFB74B6ABD87FC1F5A2C46F44FFA8F44FC6C5D9247F6FF73333CFA1F31A3EBF97F675374FC7E626F77B789F1EBAF2FBF3B17F3DDFBBFDE7D67F37FBF2B63FBEFEFADAFFA7FFB9D89F83FBA1B25F5AFAADCFAF92F63231CFD7F7B8DBEFDBF74D
+:80A70000BAC9AF8FF61CEEFFCDFDF6FC4F6DF3BFB68FE1FBEDA78F6BF1BD978F8DFBAE6CEF4EF2CFA5BF9CFA7AFA2F2DDD77F94E9D4BA46F66FE74F2FF4FFFF6FCEFCEFE54F48F6EFFE4F9F7ECC011C011C011004834481440A24124005028504812000083048384080098000084408841084880440224488004480000DF420748282562C8
+:80A780008862841C71110C19A21490181242122C42A814901880421828028C418469448CC12445A8244B12123CE841024C32268489E141A2828429A8414C084C23C384B24634344A18F437BFF022421F41D22AF11124A7161F41724AF11124AF16D141F24A9119B24A3915AB9453F34AB153F342915F82F442915F82E414FB244A4E815F68
+:80A80000A2E411F2254A96F125CA96F5245A9E244D5A1F49F224421F49522C1F49B26CF19164EF16F18164EB141F48B24A9921AB9455F84A9443F24AB443F3429447822F44FB24484EB44FAAF475DB7022D141F628521741A7161F41726A71117462F1812CAF5629F948B14B29AF1438B4ADA14B494EA14F88F442B1678A4EB11FA8E1445B
+:80A88000FB248A1EA14D4A1E21ACEC18F224DAC6C55A1F89F224D81F49B428A4288F32B981F42C921F48F468928AF248151B21ABB48CF242914788AF6433344EA6844ADB86F442B44F8AF562CC0082000020030044820000000010020000002440010080840241800100000000000040018D4D8081514A3845414854181693888611FA1130
+:80A9000088928CC8122E1813718421A284131214818A54921B143331854C32822931244B14121425722492114371A411E8C1B811048D314814874480326444818289E54493441D8170447182A412E1AC26C5682C688449A3419248C116B381C4442C327889F821188B1C6A31884C44281698448B2493F11824CB484A28F242A14963838DDF
+:80A98000114D284E284E181E45624788182CCC9825AC184B242D1C84CE1249BA38C48494F03DBDF04112C226CE1C4F14925ACB428D8216F914884F2895187698189348E181C6133EC983FAB84387154112C2836C8487111D14937C34B1A8F1449846957C13C5272E182D7236F948341FC97211648E4991141CF2B24830D42E44296284494C
+:80AA0000EDC2682EC3D11467415908411694122881001146824221C88143C8129A5442224400A24A7381C824241CC2424243125826A082B0222801151C04428C94141F88049E48245518088D1443420289A1488148CF720A008280080088000000000000000000000000000000000000000010010011400170E745B2220459412493281447
+:80AA8000461444F823119A16C88823C4424129E123A818541A88628814481546E814BA1964882181584E262B829015441A38288E21424952E2221AE53808218C9414D2268258421688B388F4FEF8F022623015CC3528A88714646528A1121F18068C582283B42437922C082685E281B1894C35442E228C71589141842318C8144B442EA288
+:80AB00002159413C388A4A61444116B82281C6838221844B338AD42208441AC12883F8C9E70020088008800800000000000000000000000000000000000000001100100114009772E02201614C421131288483A22121112552813412208802A845884288420821288446C1422849A121882860414A41140C2E12B02801904420E844034A88
+:80AB8000220143C824846F19491341E18251218936321E444F14E27134C976A11A5E884E165E8449B436EC45725478C8D414A51E9243DC2174446283CB164B944B874F22694218221534762F21A8122972222EA2C2493AC449227862DA2829C89462852264484EA84F8D32188BC1281FD5021121C9415412239278C97421243D52922D129F
+:80AC0000168268452A21F42844422A852152841D4246EA219248B24B844F337C6402121363628A2242C67840084F24CA2488264898868604CF2402228E488C4D3C28841FD24CA221112392216698114113B248D11A922113B248D849C455212F48B4148A7188D414F88468988A844244C83443C43800384942B442C9122CA1216449B264FE
+:80AC8000E84822018933422B1848182A8C81B4442863428A31D42CE2D84161424D48C31288944A10D481E121A412430125CC268D2489E58211C21427234CA841308C1D948CF51248271C4991224CB4898182628863C6942887414981032122144B14388044588220C214812C1824F6833C80E4810428284C4382412412912482148A12710C
+:80AD00002224B4241482C8122887242AA4D240A42148C96881176441496152421118C048248C222264448902EA014084C2442449C41200AFD6012C011127110085840285348891A3258C810944122A44384844860410241214022042428201288122400C4781418C02A54234144C02CB14232128034E28885F8C044C371426952BC078849E
+:80AD80004C91154F8491818C735AD2586C28182B426E1A4CF434421E2856B43464648DC41D44482FC4F1813423F5268889A138442B12271226B421391838184CC1228C417428C13287214C11C42CC0766614B42A85D984622EEF1B0F24102861264445821288B22A1181084C71A5D84811C432806888608828228741262214044974483422
+:80AE000022C44D92108412CC4C872284438226C448A0484A01A5448821490442F0B2820041004622226111807232110220252186085289B8840200440040E4218884B8446242228198824CB2A421112481829282200880084B84682F41C8A884F0E29B141A064C81A2214210B8445114422622A418843314B2442134A52C018314410448B0
+:80AE800030864844448183D1226C8860421604212840048880A821211A9814888D124C18284502CF3A0D8082022C6141352844088821181D4449282241880B41888200282800882324C2141982B142819214C02281560410044A0248984B124468240082888CE2D80C4418118741206444216902811584880141A22312A281A0141260487C
+:80AF0000249843A414180046014860C1488448008712818045024D380010342281002334447727149212C04487448001428E144A82A1947041228E3844830C006682082842672196128491158443614948A2A02492449041438384880A214D22288888218AA6858489D212F8D7E30000404141C818848C022E44256988884144384921A439
+:80AF80005222828081E18108002442471300A62401122021082144280000204238C8C0242200EF2D0B1CC22D4C4181C22850141460199C08608183814101001C1412C4481110118C1411C8812C04004800A02422463818422400928522013018211062844F6F06008D211A02842944A2128860814185422438462400CA02268421684C28E5
+:80B000001A0C124E84220022444400C822414B142228214298411082B244034C8102288E24EF610684814846584143111102124186041D24404802222614941429A18418244D8260248821601485011608488E4412822908608884160429B224148414220342482B85F0D3FD1412C74A45A436243F24714A56128B114F48098F1498984EF7
+:80B08000853D885B134B262220AB236B658AAC818AE412B21291C26FEDA5444AF157245E48CF131544E4C2D344A1853E424C7824344145A4148B626230CC5A981E1E1446A4218C742CE481D2180DDF9B042A8183433C78CF43E211E5A4B143024FA4EB837251B41571D4F68A8C1A7846B5C693954BCC2E948F253284884F49E486725401CC
+:80B100002F29F99482844CCA242F24BFD639882A08CA9A362B1436F45218CF88E225E821CE821A718466416E822CF82A928F45BA1229E4A6D246FCB37DF0412417819713DB415D758C548197414FC2F438231F1BF483122B48878889E524F682568F29E783EC44D64861182E141954C4246CC4168845D452A442CB1817A4B6A4624321F17D
+:80B180008C744931B89ADE1CB62862422328B88251622AA32A6B28CB6BCE4C6F2AA16C8BCA828FAEF2E7E10045014008100420098444124048658154164861814645484548C19814450841D0140118100CC14800414881488150484844400220011DA2F044444FC5F11C1CDD448FA4F44B4AA5DAAAF14A488F84FCC85AAFA6F74A4CCFEC38
+:80B20000FC4EFC1F84FC5849FFF6F4AFCDCD5D55FFADB99F18FD188155F18D1FFFF5D4ECDC737899FB9898449E8C8F82F2B5371F19E38C7BA8B834F6282887C32B429FF3F37B7D3EBE2B938F8AF3BA984D84CD8CEF8CA4EECFA8F8ECCC8FADFDB6FA8F87648A6F4BE8CB4FF154544FC1F71C1DDFC1F54141BFB5F75A53E5F651511F4CFDE8
+:80B28000C9FEBFB4EF8EFEC4CE7FDDFF47D88FB4FD7E5E6F4EFDC4D55D1FED888B8B8D9195F94CCE67657F74F59F8FDFFDF89ADC2F11F588AC8FE7F3BB6F1F1DE58B7FA8FCA8EC3EB22F4BFA3AE85F73F75B598FE5FF36948F88F19ABE8D8A4CFAE642AFCAFAA4A2CFEEFCDEFA6F8FFF5A488AF8A6969FDD42D155F414548FD1F11D148FA9
+:80B30000E3F37B3AAFA4F44B53AF85F591819F7DFDAA223F1DF79D9FAFE8F94B8AAF9DF44EAE6F41FD45D4CF59F8A6F84FC8BD45F58C896CF856467F55F48C9C9E821F1CFCC8CD8FC9F8A8884FEFAB1C8A2DFBBC284B6E4F4BB2E2F7793FAFC7F6383EAFE5B9A2BB925B8E6B886F4CAEEEEFE1F8BE9CAF87F9366CAF8F3F882E924BB714BA
+:80B380005AF51D35DD1DDFC5F27169BFB7F65E4FF5FF5B599DB81F2CF753F39F9DFFCDCF7FD7FD7FDA2F3DFD37B7AF86FD65D4CF19FD25F94FCBBDC5FC84819FF6745EFE56567F7579DEFEC7C5EF89F9DCBCCFEFFBB6FEFAFFB8B4C7CB4F4FFB74F2EFCBFA7AF85F77F77E48CFE6F64ACE2B3AEFADFD42422F4AF9EEEEAFCEFF76266FEFAB
+:80B40000FDFEFE6FCFFFF8F8AEA2AEC2DEF110044302450218844302248420480428928D24D04822018242D048124294120081002220028884881E48141A2482040000102811088B24F0546130A612108181324A1311FA9144F01128881240D84A09219280D4480A890880054DCA83A41286D42425898492141628E2413424004480162269
+:80B48000C18243014006444828343F680C4F22F5112485F2112487241F41324A1D24AF24F19124AF269921AB9453F14A9443F24A9743F3429547832D954F8BC4914FA2C4814FA264514FA264194FA26D596D4A9E244D5A1F49D222F59124CD121F49324C1F49324E1F48B64ED141B24A9961AB9451AB9443F24A9443F242B64782AB944FE1
+:80B500008284F9244A5A034F22C54C2CF1116447241B61E7141B21AD121F49726AD641F44AB25B61AF54B834F44A954B438F54F83448AD856F8B54182E1A8D954FA2FC18854FA254184FA27D98D5B6CC244FA26D886D521B68CD921FC9766C72919C1E1FC8B26CD1C1E244F181242DA219F2429443DA623BA42DA6478A8BA46F8A84F8A49D
+:80B580005A8FBD0E8480040000000082000000400400008002812042014008000000000080120100000000BF640E30122D32241C21344215B844E128A5241628D9A121C1844C71316851C32972488181C22823C2124E228724A87890884BA4185D42D014D863B92438C246584A2522161228C5484CF524184E242F42C4C42260424B842296
+:80B600007F6C4FC2448E2415D44142B42451212C0573C2982B848523C8C48B12A3D442ECA2C863CB1849B284D414348291611C813854CD829E22433712E68629831288342898788AF618841322038E142948028C512AC3D48234D82E11CF24581480E446B114722267514995412143B476F81CA28C3DB83CA118CD92CC64531B821BE1B666
+:80B680006A16444B43278827BA164471822AEC4A94118B184CF38864174123647A8AE1222424942E4AF8628C6932284A91144B2DC12762CB34E3C4248D42C9BB24B158FA95B9502650120028211F81941211230434866844222CE188D46851842554844A198102B02225B42431182F22E84492C21229AC2150C169E88892981A34221214D7
+:80B7000012E088142223042CC84821484A5824BF9F031410022C01AB141141124E1190121181821041A2411882428C0451811D1A81002C2D812C11C62449496822107A11D42869414AE18144022D831E4829A84821431A48784824F2C63F341E26124D3983F248248C7124721CE281C448283E898D8296BC44E1D3F414AACCF811C4CF18C8
+:80B78000B2CEF238414D294F12F84A242E484F1122C2968B1C4D53C9F284688D3643A6861E811538821FC1B458E8487328A2248B2884A28E588E481AE442F828464D214C8E65424A212BF4D7CFD0628111823264ACC114A5848191518B281886B448D118382C448E42871147822E9185F484298F44420D162B91125CF1528E8D44E26B41FD
+:80B800004E84471391296852F014288F51A2852DA812C298883D8243256E2C4E842847828CC4984AF29B5EC021F01429818C11326813714A344828137182981B444B438AD18338154EA42B588CC461482162DB21284D88C68884A21A168C3222881E84848F24B1C831822489921483343889D482A4148B82A59625225E8420E14244F2BB24
+:80B8800078244C917241CD2318400450A43247841A6A9816A4144F8248921815C81A8CC911C0142A681318FF24185C421E4411568812B84431846081205A128C6A212E4843912248243E888422AB481604AC89C5184FB1450184462121348336688187225210042E1484652881844C74828684E29104C9182A04481426B88B021D12914A3E
+:80B90000122838422E118D442C064B2C10A429452104B042A11221C14E2600DF2A0913420410C8C421244822481C41280400CC82228202C3644282424261A02198E0410460256011C912D46A88C1141A0419484828C818462214044E281A02C4481F8A47D141D24202C5924825E6822131286B522B438D1112993414CCB12CF128428BC32A
+:80B980008CB21CBA18ECC471219C842E4E9B1467211538482F11383C1A2AF521121E414CF114884782C7219B928B587C35882ADC82C61A837841F418428B85481E422AF8221C1E288CFF184483F4C88990121245B11182914141842344084889389485828418045121C02148002848C6B42641C442874484408242213842446722286A61F9
+:80BA0000411C08188220522A43B2488144140414BEBE00472A450881109144441282222448C01812492CC242004A0180941283418168488810A44942491558842688031811A48212688A447112A886418C71840A438E21F82F8F10041100182483011148148140826818004B184145084698822608484026311486A42190228902424C44DF
+:80BA8000381590182384641211282002C02110981810F48A7D14288260412813922417A21648C234901225C488412648B81888B448A982228210221294188628E44834784974224C2248E4884274841868C844382C01124518C8488F418222083A0422148F43440223C1111114C0184224854429880858222182254208428DC40000882B16
+:80BB000048230584C01840084880024AC132484483429288424A512400482B1200848CF277D3001844444311011884484083618C8248203414824C028244461C4D648300AC8841242898242D84882B812C89AC8448208AE12CC14212A21860888022614180F8DECE204482A2218368844880820A8CC444418B411A825C432E412E15869110
+:80BB80004424422E111246012A782482022F1249A8429038221544114118A1281D4C1180B28502418118278743988A89E84894261FF20C49912110010014311586844301212D8829C11210088421A018282123941484006022C01810622220322230122182204842242828041144482185F2F17DC0228216081F41B2C4D14A0218839428B4
+:80BC000096C888814448431208802129E3A8334829644340247418944248203114902880142422C8488289641A1212890416B484061849846256F0D669249C118416A884268861424E228886C14411A81044A81288242A845242144B12E084482422A1421548B18114648CB0840427291882284CCA1222A544982249612A481213182A02B0
+:80BC80002981F4FD582426F19514AD185D21AE1C8483B321741BD22D7278F8A83145D1C8D44A38168E24AFEDF424916AF532154B665E62CF257862D984F25C3183FCB2822EC84F61D421E4457ED4638C18C72A8332915FE4B285E285B5C178FC7B71F252A82D11AFB636D1CF74E828638616B431EC48A114CBAA4D4743F883A5C05686625C
+:80BD000012C4C5F151C52F74F154342AE29C94421AB8D9918496EAC8F9599847124AD2ACB8C4EA41C88886D82CFE7242214382768CE68AF3C88C4362421A7972C49847C88D8C2B592D846B282E224CDF4E34215E221AD844FC32188F87B81AB24CD52AF2348987425E5C7E918DE28F544FB116B222F215241AB151B228D38452B84F84F1A8
+:80BD800012841F58FA414A2D8A23AC548F26362298278927598C7488F8A4141B428654182E461E5C5D1C5AB14AB816E188D188FF26644DE22F41C6A24F22A6828F87F12881CB11218EB88F28F5A1888A911A4845F484D4AAEA8CD12AF216E8C02826FCADAC20742401224822482248432228A249241A8482C4261B488D2213D14822B948C4
+:80BE0000328128118D242998289880180880012541D83441C88140210886482108008A4421282438489F674C7345766457441FC17519FF331D3C752AD4FFF31F9F6B991F32F9A3C14F49F1CA6C4F85FB9CD66DA66F68DCEEF12244CFC4F644D43BC44FAAF88C6C4E426FE4FCA616AFA4F4E2CE27454F67FE4A4B2F62F242C66F62FA1A18BC
+:80BE80004FC3EE259CA4DFA5BDE6F449426CF8FEF2BF93F9FAC94B55BF84B438B354F17CBEBFACFF3A188D18CF87F19818AFF7F2CD52345F42F2747C4F41D2D5F4292BFFD2F7243BEF42D3EEF19EDE2F53FBA9BBBF12FB9C14AFCCF2F4B8CF4BFB951F6F69F987976F6CFDE6E4CFC2F7D7D6ED8ADFB6FE76726FE5FC46D62BD567E5BFDDBE
+:80BF0000E467F726636FE5F752E44DC48FC3B93AFB49C78F47FE15326BEFDFEDFC429AFF76FF7BDB2F77F9D442BF86F6787CCFC7F33C9E3F87FD3F1CEFAFF56E78CFC1F13E1E3FC94FF345666F72F625251FD3F3596FBFD3F34873BF73F25F7BDFF9F29BAFAF3AF3DAE86FC1F1DA54CF2FFBFEDE6F6AFB67D7EFC2F1B5C5EFC7F674D49FDE
+:80BF80008EF7A58BCFE27E2BF37E7E6F2BF16A4E2FEEFD52414F6FFECA5A2E7E2F22FF32F2AF81F93FADAFA5FC2DA9DFE3FBE777BF2DDD71F8FAF6BF93F9DAF91F14F5CFCE8F23B166F13C9EEFEDFDFAD8CFC3F57E7C8F89FD687E8774345F27F73F776F41F3452D9FB7F77F7DCFB6F76F77FF36F7FFEFAFBFF2ABB3BFADF7D65EAFCFF539
+:80C00000FCEACFEFFFE7EFBFBFF56FFFFFD7FFFAECCFEFFFEDFEF7BADFB6F63F33EFCBF6FCDCCFCEFEF6FEAFDDF4F8FEEFACFD54766F45FE1496AFC3F91F9DFF74F46FE7FFE7FFEFFFFFEDFDC7BFBF7EFFFBFBEFBDFFDDCFFFECFC787EEFC7FBFC9EEFCFFDFEDCEF4FFDE6F44F69FDECDF2F1801450118841400844192149648618124007C
+:80C0800016482601400400004429010020240241B0240922484100004864C02450481A84229128E0DC054302ED11A01211144C824124568130144A78A48851812958814E8496B848728112B821B4488241D4A40C4DD8524D881A928412888C726821F8481192348E488D131F88D428014E1184889E488D2641282E484C7224FAEE89F026CB
+:80C10000431F41522C1FC132681F41726EF11124EB141F48B26AB991B24A3915AF44B925F44AB743FA4A974783AF14F9B4488F54FBA44A8F14F8264A8F11F2255A875D6FA27C98F522DA8F49D2A4FD91242CFD91248D121F49324C1FC9B64AF1812CAF24F9916CAF24F98168AF145985AB944F82F44A94478A2F24F924482F14F9344889AC
+:80C18000F9244A5F7E0367B21B61CF22741138241D6CCF12B111B624F18148AF46F98124899A618F44B821D44AAB485C9B444EA12B4A4EA54B184EA54FA2EC519A51DE2449EC18F222C95E2449FD9128D81F4896481F49324C1B6867241D248F26F991648F66E949F442A15B28AB143AF44A8443CB824F8B24F4B6488B14AAF119E520281E
+:80C20000280100840000400200000000810000004100000000A088000082008002008042024114F0D8AB70160285D114826114498251128B2C2A61288B8143041789541B961E24A68435448F1671814E4AA224255142E912B442084D884A11D424EA81C8389CE8424923A3822F22E131A61A94CC658527EE3AF418642B684C92328B28CA1B
+:80C280007224F896F18034A16C6221157C9AD418352443534188830483315C43B418184E784221B818388442AE44479484478652821E884F8231B45227289A361222444C44A2428D848D1486442884886818188119981C8B1444149C81F813AAA041CE2126342616B6C5D11881F323144EA949DA283CA84A81B11C7C81C444382742244B0F
+:80C300001C1937944FA2BC84B42AD412B4167422E888F111641AC8148F25C8764EA4A668C25784B63421A3B184E342B924B5124A98541BE1A7472B145AE28AA1436C32211C33B48FDD0D6502853111A5413864444084011845784814D12871B158481B484A49D848D8A104150847829084442D884CC2CA80289112128830428E248502A5E5
+:80C3800081C48186182898285788274445981286B84848B8B20B400428200180018911110800002145082608481C52840000160412000088440042108202110010042004182E48B024F43341C012190344814483C4269149223C2818B048C1242149A2842812437414110C2C26C1642183166224A2482F512AB5140A88848A032015810D18
+:80C400001241898DF212482218851412C484818FC20DE041024C4268414243C211448B1426698120440426225C84188946C44C11AC044F22042841421A42C2114AC1244044A883429012204D8111A48180011A442AB128C484C46FAB0912250100104842288208008C811212042840641180C22412008394123082422E8480298808008032
+:80C48000641200008CC4268924024410044AB2180A0049428811810140180884144488412901001181001124002AC12C4C712288614480028441004714002001182064420040482454844FD20DC012194154248962426F9431188084A1418C01448C8182C81C43818894284226726488C174412344A84141182388C134901889E14813C216
+:80C5000028890A8011222409A42A8481212382F851948002100200106425001002180044601443010042000080028602111011162206181880046098118116284148A4420022CF220C221245114E8662412D484381344270583211E048412E231884351500481C4622913449514ACD321A34842514A1121762412781424CCA4581884812A2
+:80C58000128D811334D847818D1226C81489E64182644AEB4F00B022011815287211146881811240480418406481548283648240F248242024A2249028185229081884411E282C21A1128C0240220180024280012884CFB2050000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000073
+:80C6000000000000000000000000000000000000000000FFE40F8004000000400428000000002180018800004001400848000000004480020000001002183F5F0B0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000015
+:80C68000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40FDC
+:80C700000000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FF4E
+:80C78000E40F21002002400200000000000000000000440000000000211800862801004002000000F0DC94244C42C224A432426484444A0889082001411B1400203124824011244482282401805441458228421438A44082818208584088824914E284024904C739004414401418012611522100AB815189612889C828884D48D08104473D
+:80C8000026400883422492A2424C422203174185E2380219E18441241411082117418282842242418828F081517022449624843664844542084A489288F0821854844CB8433128824628716128A84214858464224C28248184622419438699282748845B1A8145A21426814882951486884A4894424E288242F0C5CB004001214001473221
+:80C8800040010018126088004440044421008180B2220841100445012603A041004008400120890244C024F055129016C0125024008460812A41084308E04468818553844C51844A02502414002C054812296C41222841114304C0688182181B418800D048028100208474544DC1621E2213C2288B1287114D311D144E21490A3A94888DAE
+:80C900004127C82FEB44C36449A61A46E816D949D11474262A36146B4147816B828F22E9429888CC81B885311489F326888B828D859F4AE141E8416E47A82CA8141D4C29D5C2495284AE441243B78404A6F843D92444283483B21882713401461104804869C8CC51218B61BC84311C8E289C01260425026CA1388810A89443C1844CC1187C
+:80C98000218348C8212E5C432A8B89A1415C1462898546C828121E244C0C68AF51017223313210541AD09421628B1AB23844E868042BC22F44183424CC2A9455496674846B2417414E148443F42A124BC296524882368192241FC2B82494858E1C824E184C84D2218C48A841252442C4C48004488D82BF864AA134841724894244140425BF
+:80CA00004866412432A71185948484182A0126C224856485B044D821311448421150C1841AF28E114E2451A245280E84AE1120E3826148C130424F88E121088093328E448CE68F0D21482E14128CB11842D88441044484A24830228A0486415868121212C0898314D81428323284198842882624120240C864B014040080311821282818D5
+:80CA8000822118B04109902281114221601218C02822008001648432188100A912820221128032224144301218819018281229040010428802418843C24842002FF749911270117C3219783248D8C1D28241942A26285883A449C948648BA136D848F114284961A48C724A75617814F882413E4213D128C2A88D2426F46215222CE3820811
+:80CB0000AA048B5239830583C182C4167828B214E86289B814B228A5434B498CF21BEBE0228422024B1444411241800129A14144228812148002810020114204284004122C68414501C1163828444A48E44281828242A2418180028800585F2F0229110835A4146240C828A8402824081834890412885A821122A81210224124312230189B
+:80CB800044128C38885048411412221349014A088088C438228C2248348423FC44886084324C2201148B24411D42308B424441223481D0284181014842941144308A001AC4282065821428C41522847422C41281184C088C1444362460244398484860821F790B24009029102214411C8104821E8800292202221126A11210F4221684843E
+:80CC0000101448068C08418891601A1C01008082128284286181908280088E146F2D0B160C80227158443422250440568429121481450883420442824C01100441238C321213344224844840A54182004C32C89018802292884D824F820125886282F0BD4AA04884258402416200428820341480C411621728A04192008884114C248401B2
+:80CC80001223C182882505009021412E48CB8288136E81C4830842282182C024287048F1D95F5021B011524121221289A224230281804482E888A418188886210220624283C18818508441C1402501C1466182250C18B02201000038442410A8484448F01A9D3022280084111140684840144878821808001721844284904146011241C880
+:80CD000011234881024221481082618261481744203852685821218015044844211FFB0349D22401D02402451841344846484282E14481146228004A528160A4008C841884A81C83082D44181514440448B08482684160811E28A69284A342D42885082AC4248388086F450D15081FA124D112D4283111484001449068504A80C12422009F
+:80CD80002F5229AA16A082A048935182441C4A0884822CC44222821A04808442042888A92128420818F0126843F2712A241E249A41437358F914684E25B7A24E22862254A883B45678443442AD189A92B88B122D58681E246AB184CC7C2FC27284B8D85984ED858FA872984C4AF611458F987828BC4854261D2183B2B8A31A1E1193B8884E
+:80CE000088FC84886636E4C5E86BF836884F88D88878C4F4481D49F8EFFB302481E3B116F2256246931F49D411B429768981944648ABB91F21F441C22D18277219F2A4A11F13F121198EE26245D138914245E86969252F429926F977173824708412F16825EE145F241852246AE28423F2F412A1782D3E8E3218839442AE148C34846E1C29
+:80CE80001FE60B3F34F5222E1F42F3211429F129143E484A722CFC468C8C2844FE881CA4CD8916B1682CF11281524E884A5C829D211332548F41D84294418E5843E52221ACDC2C514688455B81EBC19E7547448F45F287CC3EC11E38AD284A948A1AF872C4AD282CF728264B642AEA22BE8A762E041304000040C34826810440A249F0149C
+:80CF0000482C1244121518141831481901304800184214284128214821104218A248214062880044920000F0828D144E5317C445F11E789FB1F1532FB55B2AF5F845AC8F880887424D922B384F4CF98BD9A7421FF1F1262C3F11F1685D1F5EFC7BE95F78B8CB31632D8627E52F757451F35A222F49FA786B2F48782173E7D519D21156C8C9
+:80CF8000BDAFBFB4F41212FEE83F76F3BF1AAF85FC188A6FA1F5C664EF26BF6EF72C3E6F41B132B782EA8195C41E486FEA4EF264536FD65574DFF3F77843BF77F16F2BE724AFA6F6C2E3AFC898488F44F6C4C8CF69DB6FF1CBDBAFCEF4B19D4D1C4F66F1FBDD1F5FFFE7F51F34FC6E86FFA7D1E6F856162F5CFDC5DBBFBCE6C9EA3DFCBAA4
+:80D00000B41776FFDAF48925BD648D4D3F7BFA47454F49F9F2E87F7EFEB79FAF87F4A8ACCF81F14466AF64F5EAFACFEBF11E1E4F63FF2C2C2FCF7F6CF8863E8F4C073F24F721646F32F21F3FDF35F41F35BFD4E656F66D617F5CFACA8C8724AF84F2C696AF8CE98CF9D7D52F26D2B7F3A2A97F58F87B595F1AF8E8185FFAFA4FED7F17F180
+:80D080001A1CCE98CE5F1F75FC52C32F6DFF7E685FC9F991B36F28B42A7821D9A8F211B5BF99E141F1FCCA9F56FBF3D58FA6D5AAF35E5AEF6CFC2E82EF8EFD684A2F8BF87C78EAFE36784BC28DFC2F3549F24572EF525776DFF7F37C7B6FD3F34F6FFF62F26F687F5CFECAC88F24F44E486FC1F8FA5A2FA4F5D7D72FAFF5A79B6FD3F3BA69
+:80D1000099BF9DFD9DBBCFCAF8C14BEFE6F67F1B67C8DED8DE4D5FFDFDD66FDEFEDFADFCB7AD1F7D7A8EF2AE86F7E6EFB6F6F4E75F3CF6B6B4CFAFFFEDF79F5FFDE8DAEF88FB9E9AEF6CFC7E46EF8FFDECCE6FEAF87EFEAFCAFAF4FC4F2EFC8CCCBFA60B18B0260126012248804401A04940081200421321348128B04802003022102414DD
+:80D18000048810044988142428C248C048004CE281D42822C8243048F0AFDE3082280029C1481C5141E18A0600846C21918A2A0480230A10081614428479981424C4988218908815048CC2119A226288149200641288844604A0424C6818AF340C2CF41124ED121F4132481F41724AD241B26AD1C1B64A9921AB9453F94A9243F34A914F54
+:80D2000082F44AB147822D915F82C4915FA2C4814FA264116FA265192E4A96D5A2E44DC25A1F49D224F4912485F2912487141F49724AF18124AB141F48F24A9119B64A19B54A3924AB9443F3429447822B944F8284F9A44ACFBC0145BA11D626B511324C1B21C7248CE222C144AF44D981B648BB95F24A824B432D1159F4483147822D11D1
+:80D280007F8A84F92558984F8268114F8269193362499CE448C29817C949AC49A5E349541A9E24A5D1C1921A9E24AD151D24ABB453988843B24A39A44E844782AB846B42884FABE4550700002400000000000000204404000000000000841004002021020040480100000021F0418410C11484450228621148638868189B841246048745FD
+:80D300001DE8496288424598A9001C761882F18A262E85107284C2944229D12201828B214C742C021E28493288948E494D1246BC444116644AC8628316A4284E6860628E221116C8261524713CA2214A62A318808831881127611B94148B181BC243D1181C0D3B24453911187D88818C44E21238A45C68C88733465618296981141A88A299
+:80D3800021608C18278A848688C11486049641742E021536648449413422484F2281F46284CF286119178682161468658F64B2A531884E121B688F51381895641CB3D7C191B17C38811578C4C2964E2124D64FEC1338562D4D672112893214C342699AC3D168B45408AD8449BA44C1C28322A1A1AFF60122122541382215A41215A8122035
+:80D4000002881242828531914211895884281B4820022552482B1285141208826B9280483828B02848C8118A82A821428A94122658488021C824484C18F483D19042200221488901228281B048014C11948A00411848148400508444880083048200221E28236241436441A028A04881128D844821B28F442281818403EFEC439114396200
+:80D48000811C61814D3143742428A12178A99882ADC52483D84193F44F22958157884D218E38821C7A6112994199D21494A863CCB4CA13B294C225256818CDC289B281B328FC19A483B1482322C942C02C438B048A342C8B184964425F464AB14601841693181B124944047048022B84CC08A7481D9822481188D01808A66122304151C2DA
+:80D50000899882874E8A3582AE144184112746221B4322CB182628A4848A81718294282B1218C440A8814A21F23FBB403221380046941826A8122A29938883D11294142449B214CC3686D41CB14582C388C04115183C28152462441222001722289E288D82163C84CE1C1922B91882128814C84449A8864A82ED4192484C12F411A1C011D5
+:80D58000181002188091288314C8611A222161D10028B05188028843C1881418A8584D28421D18124C44A84211A9321487188369144481144188A0212883163412262A993A80F963E524902413E4822114469224406443818C3AC5A028C43088CC64A24CE4411228A9844A410480283185A65C21894164CC0000CB218688B89C248253C293
+:80D60000428420048228648624F52E18C022604200848B42465812384830422444258228412101129447142CC221A722AC5281C412A42A041A22862123286247282452442183118814B8120812B04401888B24F09E7624142983B22221148CD42E97294B241AC64827855D422C311888C0888C91714E344791418AB243F2122825DC1282D3
+:80D6800024CB488B348B8253B242E24211CCA82AF19C41884662CC49C88116381849A441AB288B421E4412C99CA28D148E244AF8CB3FA012444541482231280016189821889244535A4A121C92448908281F88444468142A31884D1885C4128694145218E0320941288B121FC18241B84A81C28284811200213218A283041FE54D02490172
+:80D70000A352243824449022608828418A21421C810841D081D1270449C442411292150A1AB8886421141881830828D084442142C3314186084022018C81440822F79F60210044848189420812C045141E4114198491843041221188806428118501482A04A41128A02888328E3A80235368C028428304206284A084823263C82A70B64BFD
+:80D78000E244C1280021412924D2C2171481348C8A1496448280146C810022682658842E42828762428D122234000000814C6288824130882284888443928818234EA82860C447B7400191121B21211129144169852B825623611440E222C8122C2398244088018850812192230C2182942008CA9112484242214E2142822BA4E304184B0B
+:80D80000242145A2849082F09EB3A028200241841881004220442804C328210A98008C1124210222BA14088CB2848238142844212810084181413081240080031888812CD814E8230C4849E4212412183444418C31440082D028429412004084A814D0A1413842253184601383240100922002438114742801400480A841C8906C83120425
+:80D8800043025F7A0C0044418012026021121538121D22921782501C252408151415814141012B41003082A012001440011C11828403148480012441218023915AF0C9F750211826040099219444502822308C0040B814941C8092444C92881A4478C814480888488C86241508882D488117482128418C146814422E4812161CA82143048B
+:80D9000041608C9F43018CC2221E41121C2341041CE294C22144A4282860222A41682AC088238AF4221463822862542531824C41012184C04140A128800281C0A480026200454A12A44221226F570C24CE242E2245D448F1141C4F46B468F4583D9D2C22835A3223782231258F29912863F622246FC1D81482E71196A42D88AD41AFA2D451
+:80D98000257412F8A982CF8165231DE58A83214B86F25A1A3628F4388C578685F849281E88C6744A688C2AF44C184F82F962284F45B21294444F3274887C68026E652312E781F2112B249FA141B621F46451AF35F44129CF85FE499B4B44AF4482F223118ED4DF888D61C2874953E6B6A43257A65BA4AF8AD948D18283F8CAA8A388E81185
+:80DA0000C4288C688214AF48D368B246C2676B1245B14842C182899E38367448F688422E9ACE9C2ABB88A8E68E1E243B11CB111E1D2F223124AB222551864522D18191C21B184F41B499CB416D8C4FE9381816A2281B885F1458EAA5F45C474065551F2EEE1574C28261A62357439817188AB9A10E5F138D34884CE222F4A1419DE88A949D
+:80DA800016522CBC12F21414AB484B22A7C88C13F67C6F100111100111204102248260881412148214304892100100984488442A490415A412159C121534221129119112B0220118412C0200002081B2CC42A3322F31F22A211FB3F62F2EAFB2F258235F64F238317D6597123F13FB1B543DD33F39FBBAB917921F129319CFF3FEF6D57A2F
+:80DB0000FFA189AF97B68CEA2AF32A2A9FB6FABCBBFFCDF615458FEFF242C44F4DF57C251F1F7F41F13D3CC7F1A7B3DF79F11D9CCFFDFEDBCB95F61D59BF81F6DBC7ABCC9E92EFE6F2DAC4EFA29116ED1E2F4DA55B45FCD44E8FBB45F323313FA7F62A315F91F2291ABFA3F14A2FAD2FAF53F33A39DF53F13939BF7BF9979F3F33FAB2B30B
+:80DB800037928F4AF2A8A3EFFBFEFEDF3F5FFF21C9EFA2F7A4E27F725A93DFB2F2FF6BBFAFFFD5C7AFF7F2C2C4DED95FC6F2E4E45FDCFCB9B8DFE9FD3A9BDFD9F37F86FFA5F25E4ACFD1F17E54BF9DFED3E94F44FC9C9EAFE6F3DEDAEFADFD829A6FE7F35674AF86A446CFE7B5E442F221312F23F72F245FE1F23E2FAFE2F25B627F65F7A0
+:80DC00003A317F52F22B273F12FE9BB95F78F59FDF7B228FBAFA24A4CFC3FBADAA7BAAFFCAF2A4AC9FD2F3ACA54F66FE2E2E9FD6F29D9FBFA2FF95CF6F1EF6EAA88FACFCD6AE4F47B7A1F6A823CF6BF3BF1CBF8FF55CDFEFC6F74A48BF47D5F9F4697B9F14FE98D26F48F82C2C8FEDFCEEDA6F2CFD3E1EAFC7F52A484F45F74476DED43403
+:80DC80002B32EF63F72F344FD1F23833AFA3F15376AFF1F33A35FFD3F23B37BF92F29FBB6FF979BBFB2F2AFFEAFABF35CFCBFBBDAEBF8BFBAFAC5FFAF62D6E6F7AFE6666BF96F66D6F7FF2FFBFFE1FBDFC7E6AAF86FAE56E2F2DFA71718F1AFE2C278F2EFB2F9CAF9FF77C95CFEEFBCDC9EFD6F6785E9FB6DFB9F89A92AF8CFC485CCFADD1
+:80DD0000FDFEDA6FECFD763E6F45F778588F87F76C6CBFAF034901230241008441008414842448445028123081000028212819281412880818200222482248002212340012A049241A0400F03816B084245128D028418481B44241E81401985B492148296188184B4800188C44D18474486122567121082E98522242A0218908981E48C17E
+:80DD800012C38294188A148884E9824462884C034C2AD8485214FF790E2D521F41522A1FC1324A1F41326E1F41B24AD1C1B24AF98128AB9453B94A3934AF1439A42F347924D812F9B4488D914FA2D418F8244A16F1264A96F121DA96E5A2EC49C2DA1F49E222F491248F22F1912C8B161F49326E1F48B24ED1C1B26A9921AB9451AB9447FE
+:80DE000083ABB443B34A7924D842F924484CF9244ADFDE0DACE541D42EE481326A16346E288354C18F447981BC4833812F447184F84A81824E1545F848912358588E5885E482EC41E8A264515DCA1E244F924CD484FC912C4F82FC81444B421FC8326C1749CB861F49B24CF8112C8F4638118BA45B21AF447894F84A344B43AB9422A93939
+:80DE8000364CC818EFD20E00480000420040042812008504000000400210C42100002280040000000000180000001002EFBF44022343C421AB148B21C56251241BC2181286994420C4329E41290883518443318885122C34412F287424688849849814281C53618C3228C932188E18F449712438282788AC45A4818D248744924CB124AC36
+:80DF0000248F42B144029F660319227813921C003B418C72184528984212182CD84822CC284E124F82684E8A93C8444E816042C418CAD14224722418E8413C86B2166449822B824CA2288608524A038CC1488A04C3324889412468114AFA8B21246025167434381A124725389741AF12A88121166C45282784628F3388CD844F297638F43C
+:80DF800044988749AC788438248D449887664E881F44427C18F4688619F24522C97298F428842F81E88861CAA74147824F22A42C6A7118A41C8B8646B814CA487E8846B22481A441FBAE6032283411428C521A150C48A0411C088843C2924824261828086014205421422949048A0212492989810228431281088961818502814144844CA4
+:80E0000011C42486C834A23D9A702242444158364C32242846410828244180943241A88288848122420045421402224248122522F82492162402249E2889C8482931110060811884890323048324F2B9452021C1142F118291581D58AB41257AB493188B9483C91844CB12C5A268C9C4328F12C1319A6288E72A83D224041913D485919857
+:80E080002AF89224438CAB1225C82B8338AF31152477129428A72481871581467224C8B6F044388B281A368445F87A48006371150235C2385D5883563ABC4328010049D64AB22438242AB89B92198C39288C3E22482141418591288E62AAA4482A21C12251A6180F29A15863F512283315820456C2144992224C140A4C4CB8750F2903F030
+:80E1000028114331442C82213484126E888C791A1494182C81B448880128288225441854241E2330149230141694822B28A7493618C2A2115F883228814048C819818489E28891182E18E22A153824AE6AB01184C16141366442812982D44853A48C92224D4184855484222382722498421115628129180826185C81002185542118C39172
+:80E1800022360446A6124D2840A482264A042B2143212483828881B248F9CC27402464C125224432148C7135283454804298542A21314C8BC116286161288C6243884CB22831840045A1829068822A2438144229C128858185321AE042C1118A012AAC21218D44284EA68C41E2850B10041881A17044430225018488501229C8111446242F
+:80E200004818E448048504443120C2681884124A011114D0182A01E0816818188A241C844418C848128C4408F0BFB560414C31284331188722169835E3D32456282658829C941426F41A845CF233C8CB24874146D441B22D485E84837228748611982945C892806715181594324E248712C93422C386BB8821E88895C2968464CF2E128C50
+:80E28000B11CE682BC48BB28F148825FE50F1C044D1370664254248C643416E81401308487241781E0810412A816082C840244188912042A844248C482288959412C21A9121781188425A12130152432C0484A021004183F630500490140921481248184301284288341B424E821188412282404472883212104248C22E214B828813128F9
+:80E30000802182C4721E4888102412C818004A011A02C426348826F42B8FA041C1209112288984B4486244422312A4388918144B495181181A1433A1AC3C31484512712C3281888E4849128208450329012012014E18181364348440622400421844E08D06290220223214288021A118218850221400282CC1814448C14E22818D21894464
+:80E38000C2411E224002828048C82284AA81294888021200388A12888808818122F065D80012504284214094232C0A17448511A821A0811110A3422A919224141A84188108812C8644082A04888813048448CA01144664214246042082F438441A286481842F740F8621711408848321411874421804A812418492C308856268C0144C54E5
+:80E400001A50244885A44800AA01310022100881001881C0148061818CA21222100418822F94054181220040884208215CD28481C888124190142021522889C9941142874100D282202204002D288225088CA121ACA483CC0289830C128444812810041F230248404202001200824400124B28000080681814A024008828214658488828E2
+:80E480001E4400B02421B144A228424140A4481021841872420818892118F4FF8E24302422438212480125B11402482155028814F0218C44148E44E121224436C18118601200A0142031A80026480189A261228A440811368806124921BA8402224F190A4D28213904112828445684385885441102118382023246443822284941DA244897
+:80E5000012DD83C8484041088CA228488C29080060884954484D228E2381824483C18C2A0830228CF82885F04224C399142E26AF92721282D3E48162E881687CA19163E8A3781474A8D149FB34181EA64B938FB9F611C4CF1A722CF828696F84C4815F8CB4387AA278126AAA1D482AC88826F328281E84AB21A489A6118B251F8232181E2A
+:80E580008585DA18A4241AB22AA3654F85F364B4C7411E848FCAF8EAB1F0241228160690188F8314F83F5DAB6127A466F3198815F238188D1485D9847AA451286E41CA564447B625F813535B148F51518683D292A5646EC44BA42B165A25C2282B898E588CE15BA68A8F8EEE8AB512A82A8D581F19B122B928E186C94A2FC239888528DC1C
+:80E600008413D4B6469241CCF12A216981F12428458166244B964BD93538A6C788A877181BB815642135B58751C81B94AB281F64EC447A12D62178D9D6327AC192888B2885A1A14CA229CB882CB12BA2C28B145E181444CF44E5847564B2427455E889D868A481C36842922E38838AF277B510011110011904480014122001001228009206
+:80E680000080014084418408181504158458412951C12117412117880090443084A0480000D0C64DF151637FE3731DFA33334F51D145F31D7CDFB2F65251CF62F3545A9FB5F1838D6FC1F999B9CF81FBB5B11F13F98189CF82B3F3FF49599F957CF7FFCFCDBFEAB555F4519B3F34FC761A7F36F492F84F48F234119F7BF6B67447D8BE3F30
+:80E700007F7BFDF6444F54F5782B5D877FC7F2E123BF9493218FB7FD4FCE3F1CEE44F7E8766F62F4E7F85BFE2AEF88F41C98AFEBFA74A1347E623FA7F7193A7F31F73E1FFFE3F13F7CCFB3F75B58EF2DFD524C9F95F5A189EF48F9BDADDFD9FA3DBD9F9BFB818F8FB1F3B7B1FF9DF555DD7D7DDFDCFE49EA3B755F65F4CDCE5F37F14543E8
+:80E780009FB9F5A62EEF93F9995F2B4BEEC98F73F1AD571F3FFFFAF36F7FFFF55FFF4DF3F8322911F91CBBFD97FF59F9C87C8F6DF72E623FCFFFBDB48F22FDA64C4F91F9BE3ECF2C47E365F6327687B12D13BD122D326F75F76F63AF95F52CBEDEDE9FBEFE8BA16FE8F99B8B6FF9F3BAB1DF5AF885A9DF88F993D46F43FD59D14F7EFD8F4F
+:80E80000857FF2F84D5E5FF5F54781BE5FAF1EFC848FAFA8FC16522FEAFF93D148DFA1F39A949FB3FC9AD8DFCFFF63C28FB7F22EA48FCFBF61F458EBBFB5F8DFCD5AFDECDA6FC3F566784F8AFBA4F4EFC8F61C88CFEAFB7E2F245F77F63E768FB3F36633BF22F33A3AEFF7F77E73FFC7F17E9A2FADFCE8EBBF18FA9E967F5BF994AD8F9BE7
+:80E88000F3A5A54FF8FABD9F7F59BDA4FD55CF5FBEFEAFADFFF2F27D7FDFF4F5CD888FFBF7C8E1CFFEFEE2EAFFA5FDB2BE7F5AAFEADF2BF96995CFC9BDA8FFD9C87FEEFDC8B3EF46FAB9B99B128FB1D97FF9D9D18F89FBDCF2EF22F6F2FCCFCFFFACD4EFCAF7149BCFCAFA82421004219012848034248A0440410884708148164114F148CD
+:80E9000024138802830481882888422A21F42291E0120126C1481CC148148C246289341240880289028100F0F5313082122244241A724C42B84821592216D82828594853093281128B84923085F0274A9014142925F52288F022888280D238081CA928228089C211488119240489A14B23343420D24829F2AB44C0521F41D228F1112483DE
+:80E98000F41124EB141F41F64A121F41B64AF91128AF143915AB9443F34A9143F34A9347832D914F8BC4954FA2C4814FA264114FA265194FA264594D5A9E24ACFC91242CF5912485F291248B941F49B24AF1912CAB161D24AB941D28AB9455F84A944B42AF44B9A4F442B44F83B442FBA44889FB244AAF1F0FBCE141D438E5C17248C12466
+:80EA0000AD114CD43AD141F62A948E68AF1412F4489143B2483B242F3478849832AE4829F9245A1CF824C81E814FA264182E4A82BCA428ACFC112C2CFC81648D429E248F24E841E224F8912C87268E244E141D28ABB41B28A9A14AA9A14829F3B5482B346F8894B24B5ACB3400004002400100002800000040180240840240044001008026
+:80EA800001000000842604000000004001ED4F502190133223D24A058C823419238A88C84C17816143F1122199D8822C09C9684824224D12A4CC6448186D828A93A82B248288A71121159C8822429D128344C8D11391424068482246A6822883C864811BA1C03443094412249522D5529244A446480223B88132A28DC218346841281CF488
+:80EB000062881189E252C4822E1A8A323885C614982743224485A1182F1491811C0396B1119228849817C528148B948B38421E4C2E119621B817025B214E142052221E44B02891258F7491AC838CC844A91AF292268E2B8938CAC60283B816DC2AAE282E1873D42EE828837AADE2C27112BC4A98944A721259125B81ADD1E011542987147A
+:80EB800047838F147239225D848C728421FCEC1222CF24C1B8471F1AF82B5840022D1116A41284A5833442400224841C31A5A0411C119132414C1201114426285484122921A8821A322282418481E012888221492109E014016083A048281440D89B0C4B121004008712800126A12825018845084124009A8468884E2424008314245422E8
+:80EC00008288124901456181261181C84822822A21582248184381895448100881227F9E07112410784226D126092F12E422A8188116D2E1051BC28CE288741468484912384C5C348287424C6142E082889924224D2A2A94A14C4258228761C72C4441876DC331423618D84889C468A0181AB45C6843590249F4B265001044187612621B7E
+:80EC800090338833A8823CC11C29386128C24D18008889C8414A48824104229A546260482B341B8226143512154A6C484C24D8C221321860C83058208DD148342C288128AF88031E25100248101C8224A22184211C04478881C1244338248C6544C99826C312849248C30828A88C02430184842F4291C121812E5C8229855AA21A84C524FE
+:80ED000098904C981815044974E70154484427414AD24865828D1410442EC5888D3180412182110820964219A38245F2482480B228C1441190284682741194214E2481501419E24231151628928A10021A32114B128129C9341AF24357B01292621A4248184204456124822CC214411A6452234148C434A11E468C41C8828812245698524E
+:80ED8000218D23863C128582E841241A04928522E2814438A4B0220983E441288B8408446184527F350680012841141062858301842C0410C2844542084B9200414944110982814112604218414012287122E241C2186024812A24849411284784C44D212022223488AFF14FE27182A2216F8281D243654269D114B41444E2A463A44781F2
+:80EE00004E12363117C912921C27414C9118C44E852571186542AC65846D184B6125E2428191844062D24CB22248BE21B138F424128A32284A1932411E24C9F448244B384C3228288C96882FC503201104C3441848981884A908B8111084088D1422898AA424582822D0A224A8122884874880D22264414F12094A61812B12C4148CD4182B
+:80EE8000A141218E488D1282B812204134944CE112F45FF9901422241E262662412A0125028904008D42602420082024084240220C8022048634A42A188481C212E082840A4634384280C8248002A24B21440026F46613404264418112482934146881211E4410031B41290825582181C0481B822F82212144068221828C188104004781E1
+:80EF000044122148CA01448E120020A6588951488682A8484918F2E3990012400281184601144C489348000000218280044C080081C28604A024212800841A648200C02248004412C6240241422A61825246F992DA80040081290228222B82144488883F4298828121408814886284248CD6288C2128824464521D18C0438F198202143DC9
+:80EF80008470445A18202826C4238A04814F2284048444006FA204A21281305412284D28800481E3480284006088A0486088888410089082A22484228843422A021084223842AA412841418512684200422144229F2305457848E24265848902008145588400469888108848080084C05880881404222C4448840C40552582881B14536885
+:80F00000454B81172412211A8801188721E02211A4218B124C78E802200212809448C044184890413848207C180112848521810117214111290C15486814104208980010181288028A42944A103884211318240810F27AAF00419066C0265082212450424482C0826024908246840824800844852222042C0224481843CA92609416845149
+:80F08000242C484AC8844384981420840184C35412884F660B4E2880060040012A2848041F842202448A6248800A2D844818688C0A43C4588418468114C41813C841304812112414144064842C324860642014A1439022124FF301412F6C82D26824F5162426F2392889F26AA4550A118E89C8B1C82B1824A1468848542829F8185343F4AA
+:80F100004642257862688C244DA2E7442F46BC62E113183414B721872A46D96AF247822562258F8283587223C8241E2A6D128D314D268A64C6AE15E7425F110E2E6489F124164B1227A28F26B1520227242C71CA7418328E9724372486728242F38A841FA8E9486A888B868C3888AE2885C28583A4E8E9EAC835281E6B828A12E718DB612A
+:80F18000A15C6D49DF41B525EC91F141F43D282CB84AB5C9DC48B218FC68846E484C68124B87C9F314615AFA36B5A0144333182F85D24883945847742E448689CC414ECE58CF8AA2C187C48BC28490488F14E488B5D1F6446A428C66814F48CC122E414AEA8494814992C18F487339F6A828411B9122D28F4834A48F4ABDD2544449B155CB
+:80F200003D644B588F41B2C6A41DAD3E8A442AF8B39C00400886088051812A5181188011C41145C81143C21143C211411C1244117218018711301820812804841C410884A04114126081608120019648012029F439E9E025F55216A5F812566F46F66232EFE6F7392BEFE7D633F257D3DAF8594BFD8DAFAD7F5BFE5BCE6F62F69F9B9FE1EB
+:80F28000F399364F44F4FD31DFC7FA2DAEAFAEF775555DC91F9CF52636FFFFB7D2F478F86FD3FFBCA47F7EF757266F41524C2F4BFE727CFFDDFAEDFD5F4C74CDBDDE81F8B89CCFEDF94E4CCFC6F7A4AAEFEEFA7E51CF45FD949C2E848FC5FDFA48AF520D4F61F112566F41F1181C7E72AFA5F75E5E1FB7F67666EFEDFF52D69F9DF8786A0E
+:80F30000FFD9F957F7B7EDBFE5FCB7F7FFB9D9EBFA83667F52F6DD99BFA7FB2BAA7FD6FF311B4F81F5C4D46F66F7B73F6F79F44ECEEFD2FEFD2D6F6EFBF7FFEFF9F2BAE62F63F672767F5DFBADBB3758C7C42F6CEC29A9E85F75FD43E54F4EFFEC8ECFEFBB6AF47CF44FC8F92AEC8FD4FE7A583FDE0A5E522F61761A781AF67E6E6F66F2D7
+:80F380004E7CCFE4F74F4FAB55AFECFC4252BFBCFAD311FFDCFC4A5BEFACFC5753AFC24AB9A4F857D18FCEF268198F82FC29EB4FE6F61C5AAFA8F4BBAB2F8FF64C5DCFCAF2AE6E6FEBFA67F519FE1DAC5D15EFEDFCDEDEEFE7F36F7FFFE1F1ECAE8F6DFB4AF8AFADFBDF9DCFCCFCE4F48FABFFEEFE6FCFFDE5FE6FCAFBA284BE944F4AF38D
+:80F4000076A7F054543E34CF41F3383CCFE7FF7E6EEFC5F5447EFF76F64E6EBFBDFD4B5BAF2CFECFC5BFBFF5CA5B6F2CBC46FC3BBFAFB1B9E6BC76FFC98F8FBAF1EECEEFE6F6797BDD4BEF68FC7B6BAF8FFC6CFEEFEEF6BF7A7FF1FCA6F49F1AFF9D2FBFFFFB5F4FEF6DFD7E3FFFDEFFD95FFFF7F3DBFBAF8FFFCAD85F75FD7694CFCEFF86
+:80F48000FCDEEFEFFFA79C4FEFFDA29CCFCFFDF8DFCFCE7EBB09219012C012A012402208004002240082832408828304422094848028142414044B820000484582044800140040064C028D2482BF4E0E43024128E72284418423429488704A628824844A688825420884812C94280060482362446181272290841B21211261131174913823
+:80F500002216884918A2412D842AD448A1424A0889A149427062074D421F41522C1F41B24AF1112CA3D441F26A111D24AF14D981F24A9351AB9443F24A9147822F147924D812F924481CF9244A1CFA244A16F1244A96E5A26459ACE449C24A1F4DE222FC9124E7221F49B248F19124A3F4912CEB161F41B64A9921AB9453B14A3934ABB4B7
+:80F5800043FA42B14782A9F9B4484AF9244A7793D0A4B511562C1D284AD1C1B64AD141366A1D6C2B841FC8F64AA241AF54B824F4428545F8428545D852D886D452F8245A5CDA84CCA52FA264582E4A86E1B264482ECA17C42AF89164AF22E449F268921F49A486963C2A1AF46A8413B94ABB15B24A38B4AF243A348B34478AA9B9343442E3
+:80F600004D5A7B18008200100400001604008004810000000000004001004100480000000021004001005012F0BF9F244414811A324645C2382D7844362AE2888444829821821149888892112A088A52856922B444B21598286130248214209922CB1A286A29D3413184308813C88880A1382AC82482B014784418F4DB7BA0128E221821F7
+:80F68000282784403249C88D812F227188714458A58A3164D88CD2729184864439A82142B0248138485CE48224361227262AF11224442C28C41411469C4221826AA1141859D54846F44518F048348A23621B8CE4830563A12C211662444829726A524116FA258A4EB82746C964489AE242242DDA23413214828B8329EA48D442A2344B2894
+:80F70000DCFD2C4153C66241AB82372143263882DE2C222A24D663644849B848BA21ED8821C4642E845323B22889B8A4D1147812F874182012D128816222C4892131488A06D01808A5138118514843C8A413D8180250811024045082A01242221249811262411C69C1180012005C6181188E48444984038B3449F41B1CD02201412810219D
+:80F78000841482C411111882244353121225171458812800601124144844693418488AB2220124C082008C22022502428264200444D048210843F267439044241F825182259C34DC7312C87E166BA43E421C741AE49CC1884D1A8E241A245141381D841C1899268C321249F12A14812A11542C60443163512443B324D48411E6419C128BD9
+:80F80000872648F8471A8B144B81C931128B1AA9085A2285DC1E42B24441F21D2222C42216344A8F2164858D411C24F1821C8DC38E2C8331341691124112430884211631124C712458683E44416C84F844121444459214237618322438188C194AA28416A6812C81C19888C981AA144CF4DA4740024018D241B1498291261127212A714214
+:80F880000118165214237842444469921C6218144C922824112B41008341889222D022018A421444686C906228837419344A4187449024A1A014A082EF4B0E4D4843961821312584D224614187428E211421497244D1227188C2124309256CD4A02486E2884138228046E14211E6C94233484CA42812A1254C94341A68461A22247218C44B
+:80F900001889C1282483961221876620F4EDCC002B14542064824185B14882149812448183A2824048021393A24D188125C834826481842941C18A3014830946094604AC02708812C112A61CD22424DC42089280991249F1182417B92400508136941152210012819E4823215185524184448218400460438901180022002C2231128112C3
+:80F980008A2341C148124088210800874610C82880048F890A244C2151324A628249D285A125811E8A16B84A11589443318ACC61884532381B1A16DC6864A8457828C4342538482D112664C243118131161E288127844B18CCC2115226A6214628B112582C426F8278486288A3A1282E584B4126F41854904628C541D8347111E42401E1CA
+:80FA00004C6612112C38144E12178A4E12D062015CD884042220225182A012C012822F8268412BC2D01228D124C1282CC12489E8894421918A45A814960843A234901A41C0489F584922C412142C5181121121121748160819816948902200292CA8184189482288211164488981410623684829DC4288C88C8286341A4C11622822C420F4
+:80FA8000524245C22490284C88D224887272072241484D416A5184101801461131841C24147284C81219981984282D28240094C1218034281C022C064912F811242B128D24E02C22C824224E1430588C61248880B244B842124818B4E6032C41410240C94230448200A3041A32141843C1488225482C1182080090148A443482822C15043B
+:80FB00001098810023052420949246022384414822440816048BAF40084848112495141C823482008E16004A823814441981998543B821410260898425B482444808C8188221406244411022044314A2844048220C4014C218EF650B824144244218204121412338388413D41218144882210130282460521004800541D021341883D14129
+:80FB800011443841C014704112688420C48444444608800185F2DC7F2052221163019048464402186C115424412C34194472CC24125E82241C01301200405214A12381022506834102828820C81638892A8821B922388286283C841A087F2C0163641138002122200242974224200150122308881422444444184502A3D88208C021400810
+:80FC0000282400A281702844282208902828002260822A04FFE30D160410011444246451A18C01948001810080622112C0121002104404100500005184442508410088A018A18881102289043FEC0F84814904855224B041812111748244021443CC42902890223082A01A83820A2420511A14884048A441810000421784214490246508E3
+:80FC8000400810082126F44857C0728E14671149115255FF24965F1532C41E428671847512C3114F45C112C741572B6B5C9E8287411D9827C22312B22E72189284CF689892876350C9644502A9D164989C89F884A4AD1C12E5122A33AAA7212FC8AA91CB838E2C298ABAC8F21CA844EF42F1E3C524474611157612568824C416D652F2122C
+:80FD000014A13B81AD589FC8FD55422F1878865912D817A1AD284F8AE141B288D81518E431C11421E048147722DA22BA31FC81A4EF62E8E93839257C241233E48AE88256212F24D38428246146862E02A78E2DC48AA15F281FCB0B2371168BF241411F36F51A181446B814D531F8C5198D3A361274A2C4428F47C69AAF84D248B821C1A1BF
+:80FD8000C72A47218E222E9A1161EC7112785CEA8CD54428B842B142A45149D29231B115FC48421EC2EF6451414BCE89E445F584C88F24F48E4229D12EF8C8486C446842C948FA622F8002288002281428881A8228810888228822144021C82100000020088A028A028A82A128248C021E68400800124008004880047FD249F142643F52B8
+:80FE000052245F13763D7C2DFD11149F26F335357F5ABADBB5A37AC8F2DD9E1B1D6F4EF8C5651F13F37414172FDF41BA9CF119919799E5FC2436E742C5F69E9E2B99CF2DFD7A5AAF88FAACAC1F3FEF2DFD64B2CF8BFBACA88FA8FA2FA32BEE2F6EDF26F16763AF8CAC66AF8CFC545E2F45FF66B6EFE2F32C2C47C44F66F68EEECF86F65860
+:80FE8000186FE3F61FE4142F26F433525F23F33761F7D3D7729FD7F36E366F44F5D5C7FFDDFDB3B2AFACF9CF8A7BEE7F7BFBE7C78FA9FA5121BF237237F61F115F51D1FDD9EEE22AFA3C36CF61F19E1EAFC9F95C4EBFF3E568F28C8EFFFDF5F1F76FCEFB9C9C4F49F498BEFFFAFACFC3EF6CFC161C7FF6F6C7C72B77AFAEFF5E1E2F65F50B
+:80FF000046C6EF6BFB24266FE4F46E6EEFE4FA6EBC8D4C6FE6F721DA147E543F53F524265F51D1DDF259591F57F759125D157F58F87B7D3F88F8583ADFFDA9156F4CF86D5DDF59FB5434C7F7CFC1F21F198F81F12838B79A5F727A2E5C888E82AF88F8DCDAAFBFFD8A28CFC8F8C14BBEF24D528F29F99E12AF8AD8BDFACACA2FECF83A7AA8
+:80FF80007FB4F4CAEC4AF6DAFA6F6CFD42D6EFE6FF2EBEC7C2EE484F26B6EEFACE889ED82E1ACF5544F142623F6151257F57D3DFF25953BFD5F17F377F57F7D5C3BFDEF69392AFACF1CD8B7F1EF1F397FFFCF79C967F5FF8EE6F6F43F8BE185F51F82C2EFFF2FA21A3CFE3D3ECF1981EAFE9F9DCCEAFB7C526CFEAFA47471F7DFD3EF48F66
+:020000040001F9
+:800000002B7B54F4B99DDFF8FAEFEB6FECFCBA7A7FF4F4CBEF2B35AFACFFCEDE2F6CFD42C6EF637B2CF6E2CAEFAEF6AEE8CFC2EBEFFB244E9F5E0E4110042100484100404208190416081A4404004411858401211002415014800125415814004021412249648924822048244804CFC10A8A311121901816542ED024211128511243411103
+:80008000D442012D86908843938884886582024449211904252811026116484204822C414482522810322450848D2200361858143F1D0E2E421F41722AF31124A3F6112CE7261D2CAF26F19164AF26F99168AF14B985F44A9643FA4AB15B4A2F347B25D812FBA5485CF9254A1CF8264A16F1264A96F124CA96E5A2FD98242FA2FC91246F9B
+:8001000022FC9124AF22F89124CF26F99124EB861F49B26AF18164AF24B981B24A3915AB9443F34A924782AF247924F842914F82E444F9A44A5EB9E092F411648F12E541B228E1C1B66AE181F268119E648F46F991688F14BA81B64A39A48F14BBA5B44A3B25B83F8A84D18595B84BC21E814FA27498E1227CC8E1127918A5C217C52AB8EC
+:8001800011F428C215E4267911A8821F8924F681442F62F98168A9BB15968A4B438F247B24D822BB24B442FB22484AFBA45A6D9D0080240200000044C024001002001002000000001400004840020080484104288001000000F071C124181429D15A911895542115383890A880D11444018CD9423418169949884961688674269914C1838D
+:80020000E118C44447222A84F814428614B283229213421D888591898221860210CA5424874488A48A42C81C43F81B71145932869426924529924A472159D4A1E431A4181D4885F214881D164944826424AA51491D2881002B2448259414AB1284863436212818183D1C43486E43274949D141248F21492488F81824967228E448044C6884
+:800280001289F4A4E324455143A3D118E68114D782542D8D6193B48D37826E1D95C2987CB18865241E4856E3337C815818278927688695166C044DC32E5C26B644E812984E6B82428E21AD121B18478459F81A811F88611C4B482CC914448E28493C3887648CC2482DA24368C18F29F4CD87A01240634165C1283412490121129044544055
+:8003000016048481414C130426A824848741184088921612241229D1411204AB124441442B128008211264924C3884408812F4D4C22032111812401804418C4443088C048C84C148A524121201844A12041890429046800180A29244228CC6111788812084344212200100844C084443F852971425051D2CC4CCE124A1E1C57218622112CE
+:8003800052144C417112C2484B8330584A9854871550241C32428C944249D1848DE3A4722864444B24864248D81C1195226A9121EE122E8287138CD8849C882CE44271F2EC88A2C15E283816081FC54801121F8211341C4E184B424416AC14192145C114156285252854828C9782481D48814C54250042448F488184124A34648289436485
+:80040000D1C432198BA21427281229985482422D229E48828CB42C084C91841F314A322511411608241A480AA121A1C048001AE4C24904424D1112203222428F21042B4146B214C2481E244280928281222E43114648892A366946388881124961422688A9142A4108FFC14262841098411745293421896523842824221852881E6825249F
+:800480000826E86601403A4822882538442903C1321885A441400486E2417242D44288C1143A24628888324B828C2862414538829A14F434DC608218198441D8842221084D1230118742931C0444248C01882449A124294181C1C426C428841E412332824722469A448E24284624318889014B424430382118845249C218816AC92AA04221
+:800500001F5408184C82922A2819C14869984A4011881142280181502E41844048C42291181400281885041C418211820330211A04118182484140288524021048F2889F141A922493F2221883D1416385E5A241A1149911CA11CB41988F41524A1E8A8526BA6C81716842C66B811E441782482782266283AB281AF24214441AD842A21266
+:80058000822DAA8F22C1946E14181E4880C48422AAB19866814C33C428C628B247052924011147368C64121A3428163422C0128E480042100285044410081E212444478212584449414423312630441249D141240414288D92868861818744414A4298388688D114F4E34D10810212264812D428314442210046021A04004C120244421052
+:800600001C88C418422148808204322081C44800324B1812504281A24D228A848201890881823F150E24128042048141901C8B2C4604B028C5888388880824492169C8478424A082284148601145A2214810048542A12119014E2140A118800528418848608222423FB6460224B43449B411944448DCC14918A50148203141185210414890
+:8006800004B110D12241440840A242142C32481821608724C048860A2250344110849464439818E044C9258F110D1D48141A041143022601220023C48188C169111862889A849C221024A4A18504284002408208841C824822E42402211C88984829022924E128416182100485F235B600210060A18453322810010040024121818C018174
+:80070000488094494684412802802462244068A1432532422223848422169A1570842242243414008C7188F2989C806141F0221883021C210114442E444718856255421C01838141142444B24108808224051C444101122880C2228081E1822891444C91444A22A51200242A84C218A0422FB1074A2232241584482442081E848288811249
+:800780002243880420041820080084288044840558440000A02841002110012180712212080000DFD809437981084032412C622424105A214D421124502842468E9441814A0850C229C11242212391122150122812231282011110C4248088816C288248A081B092824811F4CB536082D0813448118392113031A2135148E0C1120990287E
+:80080000A0182B28482D1A8438A0844084820A1C84081608C894811820C411A1384C21B2120248822394291C014B122B84709246A1449A62918782BCE495D5A9F1245C1E376CF52688AD883764CF24C5232C54A38D5AAFA5E5281BF11484CF4DA94C3B24AD423F1384A6116B442127244824252194482F2398128FCDC4319AA4518FB6D391
+:80088000849215DAF8B352DE455E22182CE84638C949F88898C7819CD76CF2E91FA0311B1A242F41B58CB22DF2126513352A8B8293D911944C1D89BF89F1DC1C1A34848285BCC68EE182C48C8DC9C42449D84AB618A2644CA11449F871529A3312849F23C23227A42B2466B51674D8A124281081F5C4642B6C6D422E38271423A31A4621F1
+:80090000F8211524573225DF49D23172214436248D235D485F9DC2514E2288124B4688CF1C2142A4451E19AF8404A5524443F448188FE73164262A9B4127211B66282E462A134C098B432E112D22822F623DB22E13C7C46D1A6B882F22B83481B316FC3874284CB29CE886CC5F000000422004422002A04800201A28324822200A001008CF
+:8009800086048604860486041748F0814490418811888488400220080000EE4C141F34F43731C517E2CDD572D71BF65B37BB73BFF2BEDBD939F68B81AF29FCD78C2F28F887D56F6DBDB6FB76BE7F7BF91C5C4FCFFFEAEE3F76D4ECF423294FE2F2323A4F23F3B2D64D566D841EB6FF58D864F4169E6CFAB7A5CF67F2B6B72F1DFB5557BFE1
+:800A0000EFFF67A73F3AFAC2423F7EF94F872F28F364462B514F48F8CB82F5F43818CFC2F324946FF7FA77DF3437317FB3F71F1F6D462F85F15F27FF97F62767FF96F6FFBFFF7DFDCBA3BF98FA9796FFCDFF8A92BF18FDDED66F8AFAA6BE7F5AF8B6B4CFCDFDB8FA37324F625B336F22FE262A4F23F7B2B61D132DC22F65FFB7DF2F29FD16
+:800A800072FA8F61FBAFBFAB8C2FB7F712137F7BFA3B364F6CF372F63DA32F24FB1F876F49F1E6844DE66F6EFA7F7EE5FF2A3AEF42B238F84E1CBFE44EF141437F13F52D272F83F3783D2F757113F13377BF13F3FBAF3FDDDB31F48BA1A5735FF55FC7FFD5FD76FEEB913FBDFB93B1EFC1F5DCCCDFF8FFC7EF5DCF7F57F77C7E2FA1F13C5E
+:800B00003A2F63E33CBD52F1D4323FD4F2E1E32F21F78C2A2F43F3F9F3AF23F357363F25F5BABF6F6FF322A62BE79FB5FECC562F24FD64C67E524F6AF8C2826F46F63C1CEFC2F324D44FEAFFA933343F31F43F33FFF3F3561EAF8BF33F67FF93F67F2FFF93F5BFFFBFFDFFCA82BF98F89797FF5FFD8F97FFDCFD76FEED887FF8FB8FBDCF34
+:800B8000C9FDF8FCDDFFFFF4FE7D6FFFF5F4EE4A6D4ACFA3F772764F7CFD12526F2DF7B3E77F72D62AF69C32AFEAFB4F47AFA7F7F7A63F2FFE7A7F6FE4FB73733F19F3585AEF68F546D46F4FF9F6F66766EFEDFD5E4EEFCBFB2E3C8F27FD6C6D27F4F024113024842A4168121628220186088A4415011648B49164441246147148044418FC
+:800C00004218280022E0120140088C448244E28144A2412041A1488054288A9428124282EFA302341341024714126714D01AE1415412482521D11A91442B14908284A1824A410A24144D4A81241248522522442241A221241A22022CC1246AA848244D482C284234B4214118431A18F4A151D032F41124AD121F41724EF21164E7341D6409
+:800C8000EF24D1C1F64A9219F64A925B48AF24B934F44A934B4BAF34FB2448AF14FBA4481CFB244A1CFA264A1E216FA27498F5225A96D5A2E449F2224A1F49D222F49124AF22F19124A7161F49726AF19164EF16F18164AF16B981F24A915788AF6439A4AF4439B42F4479B498924F8AD448FBA44ACFB30D25F91164A9F51124A5A26185E1
+:800D00009361AF24F18168AF6691412DB25F88D62AB1B454384B4BAF34B224F448B1678A2D314F8AC5316F82EC11DAA2F488212F8265592DC99E252FA27C91DC82FC8164AF22ED49F26A819E24AF12E849F46E918AF46A1582AF14F38128AF64217B4A24FB4214478B29F1A2482D34AAF5B92D20280800000020411482021410040000008A
+:800D8000000000401144020000000000000000000040012F4A458182518229C14950144B42B0146414A13C34182C91484688F6241212D902624A08E12953C29F64111872428494484E2427442E124D3844218299D65872724F621522A711D04874A468811A92142502C3480CBF7645626182135128184B25AB142CE1A3E43862812C391856
+:800E0000572C46FC14814B292D8B46E82428A54881222B2448425829E241C42822AF61C2A418223182211FA2B514A28142828D248289082B84124249DA4A2C94C55B611362138CF2939D1412272C16381A3784483D144D2287255F22914D23795BD4A6F4442827C84A61A64D482F216CE280A649257284E821344C6FB461852CC24427A7A8
+:800E80009CD62C65442B14965C221123C1288B422F4AD14AB216E8A22823F4481468AC83F114421CD43244CD151AF287453026121480E14132481A24A24818843091181B418DA61388034E118A1428A2242C848281522481224449882292212342B468E148E2145941871460145038827084C8844F8A0443C834A28942F839B780118101D5
+:800F0000810044401842180218004348118408462108211002254A0410022411005041210028832218021490889018122002F02AFD1411002B212A54144D48249965121E68257148420321C9924242B129A1414CD221024C062823A4A51820012142222F8278A89248C0846372115294589492442F88C4245A7282265448214CB8846286D1
+:800F80001FB10A11111229A342544841279426A31435384211215024C6048423288172214282042562245A4804502220042AD828024562284922D1496284838858241C18C4EA4592484490A44CFA4822EF450C8921041008C180413828506828122126083C54141846C245989024822860822301190184241722468868841141401182533E
+:80100000214C819248221882181618120260BD9021D041134C24A24230241121384865182412561800128644014071440226C82C294C4404481490245C4814A424412215628C4280581421282328C8148CC4848481FFE503486C0225E212D1821154969C04460923C11210642142861A0890288A9444282712CC2108001E429825C22440F2
+:8010800001112A652818448AC2114002C84C148821B42804182A31244F85470218803248241218901218118480941226C8124800201154228418241248321A02282004182118144321D48111882281D528018C1134248182418008CFBE01424122ACF2182123227115D82DD42121611121E991442CB22CD118411828011698C4274426CAB3
+:8011000054C42D38222B12186CA428233444703451521564524B5869D149E1B2A82C52565228412D1426B882B288B4244528918883F2C8877022A1216D1344436481672620028714288B145022434182F442820043C82100311C9212824D48C24322810127120082181A248224028D1100924E818C44341460884634843841EF6F0E00248C
+:80118000441400288180081014028D118242A08440418212048442008400001004210011904100002443880842490400226FAD0F0081203242901228A5C31214A4925086216D11238138244508424002259688D062C1624221222652242488288A51148012C822162128C4188C014024480422427F610A002480120223012598822185C243
+:8012000092508639D1428921C84445022C2402008E48301427A2150280526244860210148182042901002182402404212848EF430485B848B4483444144220628214474145B524B224220281142904A6528225A3111AB194B882788A0624D011D411048D2885B848E424248422490110792454454BA26AE28261C900484C481652221AF3AB
+:80128000BDE600002120012140010000000048000080124112240242002180018A011212800800000046180820880290F710C848422C04258401105242414C32288C029100804802296141988288100840414118C84823944200000044414C22820200004002299161400A48144002100240041C128204A0144003218041841804204242A7
+:8013000001401882140141800200449028000012422410024FE702A041800110912100150428200400140031800188000024140084214800218200004490282004000010021827B95022121800000000212400105A84200200008082028001250200800188820000008100484241480000F016A8248D188B444A6425240000504445B42489
+:80138000A226A3021001422440A2111AA18B8E818200100111A5781AB848A4C41724822100004554444B2283262201004002241AF145260085084A0412000021A4450C2AA214001100502225041A11B8840828404141012485084A240216024A48015044A02224008004506225E4940D0010021421244200211008141394884800401421B9
+:80140000120490448002880020D14231120084000081212004000000008F8C040049012260A1002100004800000000100422002410020000200818801801000020048C080000F0864D00406621246B111A5132501225124242114251818811488200144443022220020010022C110221128301420081A142801402A0440010F41387701231
+:801480002221C11128501A502200812181484A344A844262111014044C628244612CA222422308241223E149E128A9286B180011110050884AA4144E48892805822841F0CC8A2490121821211542222244420181467A488841511C1E4100110043021D21414C14682125022502250224371188881823AA880040080050840000009FC404B5
+:801500006F22F212222E122B11122B11C0132592821E111F11B189E999F848888F18F44848421F9454111C548985F844488F44F424444B244F4222E24202286554442E246F22F212222AB192A1812B99828E922592831E111F11B189E989F848888B488F8424E48404488558884F84F4C27CF0262265A2123A2111025022213CF1131119E9
+:80158000E8897818F88841CA2444511114155889488F44544C4B246A220200444584F2262265A2123AA1812B8882142512C2133F1191811F897818B888A44C4200405888485F5D0C0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000000000000000049
+:801600000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000000000000C
+:8016800000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000000008C
+:80170000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000B
+:801780000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000008B
+:8018000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000A
+:80188000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000008A
+:801900000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000009
+:8019800000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000089
+:801A0000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000008
+:801A80000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000088
+:801B000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000007
+:801B8000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000087
+:801C00000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000006
+:801C800000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE86
+:801D0000000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F052
+:801D80004FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000075
+:801E000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000000000000004
+:801E8000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000000000000084
+:801F00000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000003
+:801F800000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000083
+:80200000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000002
+:802080000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000082
+:8021000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000001
+:80218000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000081
+:802200000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000
+:8022800000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000080
+:80230000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000FF
+:802380000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000007F
+:8024000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000FE
+:80248000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F7E
+:802500000000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFF0
+:80258000E40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000000000000000007C
+:8026000000FFE40F42408814D4846422412251205248821415C422A48B2117288503207982040011499189492914284441C118C041488C3814308400404CC126441E288D2224D21628098E191426E191D61251181D48B01C7468C244E849A281A245D824E2A244343515A625B2924E924242271D337192F32C928689E79234884F36581CEA
+:80268000488B14318F38D48458844B2587268E647663428A93B5824D228126924463818F328283D442F953E4001120D4C1048422408102CC121401249194C89180844544220188141E2890C84C422C14D8128114026A688121964224E9484128221202844A22044861BF124C816227120046EC6441823484A0818889081784446C62221C20
+:802700003112800848C260314C5284B044034602C011818282466841206852201221485182448C441482116888F069F1101108840028896442424400604228211880422281C182901200812B1811883081481100851118148824042220124404264282C282221218F086A6200491140040042820024042240249018A820821881134881942
+:80278000014A5818104801480053046042262404000044E041228181988220E9AD0A000000000000000000000000000000000000000000002100000000000000DFE405601100211F224102184A123822A99149908414904424884501A82B289011A0822E481D44282F4834121AC212418308290483422894A1822248484A9842803444843E
+:80280000902C1A62A67D9824124432D44A02181C8584188181F41682188427A84C921282582816C141244441915945823188124444141444C97889041934844F9A512222428368289024166A218728768224D88494842BAC14181C8143228682511218C2812B212785CB4829C18439382463012B5826011DE22C18C41515E852BC48325545
+:80288000F0821249810271478887688DC4702841FC412488A0244AC842B02214C84241460AC3E245C2C81FB50A214450C13011211A24844201241301848502428210C4118002001224E082684460411C0100142024D82899212B821028A884412C21F148823242828143F227FE5024284058284418106888001C0818118D848424130816E2
+:8029000008204452185140084810022A014F12410411221D244AA14820C81180A1410018124A2A08F0E81300742E14126B121AB62464854C736482821862E84467AC22572C26D4283634118F15E232180966D482B152D241B32B24BB48E24D8276C6911310621A42541AB424183C21588118236468CCAA41C9A248CCB148E38DB288F4A2CD
+:80298000FF4014134432144B1416E484E14231882188825042F318928C2186D14212F841288602246021781D1A8982C1224AA924C60716022230242AE44288CC2148141602400884424AA8288A9648D7A80049B222C1188332222A04814B24281073882421E4C8924147228B4218132191218714F04C21E5012664148AC64849422263114C
+:802A0000264534814611711184150C928C014AE141FC82244AC1349847831E488321F8B165A0141E44CC213114C301A5C1441886AD2538C95D48914E888B12AE15E45D88A622311188C81044214508A542B461918C2904404A2418B28541525884284AE1411826B2226146C12394824CE141F2BA2D30231904C048148122702CE261042CDC
+:802A800042018AC3124400C04A1D641280C8271AC484844029A821248148C72147826856110C8C42C4141986C6848430C84216A8419022896481EDAB00241932220029040040220440624224812A01160448AC1684818242661236441408480098208862622C140820190A1E28418728204264C482702F0E195514268BD248C1112D4A839D
+:802B0000C24445C85230521E4445E882E1829D322F98D22833894F8C82448192424D132AE448626593D228C288CC63314D82C01C1E248CB611E8C268626E8F454868121AF8944896783234E8AF240B4B6129946CCB1CF09F3B302212692121440C11A021AD811A4672810813584245C8144144125C83B448188492141484901444214A82F5
+:802B800004248648C2442480012D118C6424404448048F444348240847821F2A4802282422492121414808460A0088A025818634240080052DA41924029048848846881234841110C849284634811934D11428C0186282168418842212D4C2B4AE0A12200200460213644282E0280148654191828724B02A188478216292902800603140C6
+:802C000002248485022424A88418224C8182822124440425414208412A21F2F998C05644898281C46484001981B1880418183AC4881D24807411A42814212011C4C86014C04400824889237224C1648442828D342598212182330823882298442B28C800F038354021840450A21429420125C22246D8241208212114290148214188422AC8
+:802C800014641A84491CC242501C2111006044306142A800424E2488602183A212A01246082978DD02428425CC22384362864848518812432208118E1146480129852402292604448D4282118A23628220284801863184446018153492881414920036248434142212148F554A224204844120C12485C4C826C822248C12C8884D483028D0
+:802D00008230284684CC824902224C18482844318460464712824E212128463811008022285141424C081212848B8120F2A44E00003048120029120210082D4224401244880A2141854408402114140142431841120448801A18A241208144148261818008824004EF470E412844A3114298244601841C04828441DE28441C269214444453
+:802D800017468842008006928C3184141128124C42C4291441C362212A28E42448228164234124CCE26241CC4484C8FE7A4018C2414644C3420026E62882E3C88595242A190441C8AA64141C788222C21490834845D8120849C841A22886089A24088088384440D24141A1281722432822088C8C84918245E8C60C4C5448282D56698102A1
+:802E00003F44C4446B263EE18F23EA2854642F296C32BCF847414BCA2F42B1F4B1A5B424F823A45148424B445D8987888B8C2B4C8829EA383AE25F71D352BAC452F28F5AD444F21D614F2973A8B541A8122F212CE91C9464AF42A8232F21ECC1534E4942E7CCF2F8C2244D326B62848F83E2747626F615322E289D228FB878887A82989494
+:802E8000A024EF81B6594274417D84D252C4281B4C48CCF636A84D618E248E662B445D5FCF41E864766858C45D64AE88221742837245A88CEE982F9294328E513DC18AF246153F21189224F04414AB462E187E141A18F8F3FF305324C77230188F85F56A487066D941B142A154A787AD988D1C1F4CF986548F8AD22AE2859EA94E847CF24F
+:802F0000C412AF2E686493322883D61128D18123E858342188815B18341B6CA88F8244F441845BC52F23A229171419DC84E34FE929F18E948B2A4B88DADE889C3C6BC21F640113245281904122843484A0418004168842488204000050482428244002244224C01200100621502492244824922C628864922492441270C843F3574735D752
+:802F80006BF21223AFB5715AFE474FAD6EAB443F24F4DF31A724AF6E546AEF41F326173F17FD638197969F54B118D588E614FC544567184F627523F9644C7D85EF743492EAF6E2222F34F44E641718676B67635F22F24E4C7D47E7ECED188FE4F1997D1F1CFDD2D15ED41E52CFC1FC2EECCF8288F8A888EB178FC3FAA8A84FCC6F2B3F9D2F
+:8030000041F252423FB256EF6F73F25A1B3FB3F2664C8FC4F64C43FDA63F7DF33212AF6DF78A86EF41F12E17AF8BD9197A4DFD199DCF4BDBCEF2A4C56F74F5A6AF2FA65ED74FE6F6852DE7F83F31F94757EEE44F64F4CFE73D23DFC3FE15847D458F8EFE6BCB67A8BF88F1E9D89F9FFFF5F51BDF1F4DFF55549D49CD4C4D862E34CFC3F1F0
+:8030800078144F87F72A2CDEFC2B9873072B675B628F72F22A2AFFE6F66E6A7FF4F46367FFA6F6474FBF7DFF4AE2AF25FF4646EFE5F1E4AAFFB6FC6BAF9FF6F6EE54BF19F1EF6D5F14FC64F54F9EF42CEC5FF2F6664C5FFAFC884ADF79F4F261AAF64C4E5FFCFCE3451F5B7535F72526FF7474C5FDCE489FBCFC57777F1DFF93D53F3DBDCA
+:80310000537F43F313C16F6BFABE9C2F23FBDAD8AFE1F11ED8AF8FFFC8F88FCEFD34AE243F15F42922E5FD3E2EFFE5F5372F4FC6F46367FFB6F61FBF3F3DFFAABAEBDCEF6DFD5E1CCFC3F2BF8DBDA5FFE4F43E9EBF1FFFED6D5F3AFC64E76FBAF86A6815FB626C5FFCF6C8487F59F9D455EEE6EFC4F4C7ED5F56F4BD976F4BF86725CF6EAE
+:80318000FEE9E12F8EF4F17FEFEDFFDEFB3F7BFFF3E27F2DFC47477F74FC7636EFEBF92EBEEFEDFD7E5AAFC3FF7C7CCFEDFFECCC6FE403430240F82612208244224803248A04130817884C028113880200445048108828842824024F12084D8148490849A8481440A1410000004E24124A22F81C75708202C02880B4445181421E2C8326D0
+:8032000088018981D4428314BA34F44A8140A4484E24A0248092C452D048322413948412008302221E48262111A26921D052A84A2534B4211AD44278848868123FF70D2E421F4152281FC132681F41364A1D2CAB141FC1B64A9961AB945B49AB944782AF14FBA4482F14F934482D914F82E414F9254A1CF8254A87515FA2E419F2214A96DA
+:80328000C54ADE24ACFC91242CF491248D121F49324C1F49724AF18124EB141F49B24AB981B24AB995B44A39A4ABB443FB4294478B29F934484CFBA44A9F450B26FA1164CD421FC122F2116CA3C42C8B141FC1D64AD84196B25F89F64A1445D81AFBA4481CF134481CF926484E915F8285F921CA8F41D825A4291FA26449BCE45DC28A1FDC
+:80330000C9C2421F48D628F59124C3A429A7141F48B246B1917248F4812489BB95B64879B4B84872B4F84894478B882F89D448FBA45A1BEB0020012100000000400800000021000000004001508200008118000000000000008221F01C27701232342504C4490185944824198B528141838D58481A34888B1282261464CA22285934441B3B
+:80338000298187488CA4288280D32482B811721438A326A42C89A4838922810C484F84CA44B68404481283F188646F9A094A2268214991422712114A62124306244E828460461B61302143386913842914314483C211492432111A624143652B43641812A4E8188B845C0190811C12E93138842088A41AC326E144621AD01509424E342579
+:8034000012C448364441AC2426F2248126628EC44E18229B12D081E282F1814217424961CF1322C84D17451F433C281781428A71D421E344E1F482A8121E6C8AA2681CCD48384F98C2312E491E816B84CB86414E84B84D282449C7184F89F49D2EF022129014126512016885C144184003884B4846A441884398284888004B4228006048B7
+:803480002E184C028223228851812D821311CC2420088008004A282384A414802AF24238808142022D1148101118611282188C14128112D4121221044A020000C0824E214B824062412F22F111241450224814192402211D488800000048004243F857C92460214428435258378389F744A12D8AE021442119E181BC81C448444DC899B171
+:803500004148BC45C84AB031341CD341452881C4D41C6448881694321C51148F24280143C5428816381913B856C88C8F4A35184F2992141E844789F0D488241822642C126454818374C154282681081A08132D32482844128A94685304E0135484164CA4421260681CE14A9114502215C245C24A81622490821212114A39845E8C18D84175
+:80358000414F8429F82E17002C01E01251281B122E11263A8180351346581284195C2415C4C91784144488831402181413183BA442584D4230A353A11212401B01492134498C588182618128842626210944DFB9081448191232248581D41A8201356482281F284138131221A5C1121C18C8241E882B84AC4C81228692821E41004C5152B8
+:8036000068B02261218004204484A8212C0489088061412A488621F1847800290581168861C2102162C2142C12042829DA14C1244C82F264824813159485C726856218481651185869028B185850482814B849E14394383745842B6853813442681628224478220816BCE9498205452811120224424A8188810512814D488304832401117D
+:80368000442428C044184C314428888602484416044CC4929028869884881C422838141827C821428223811808BFCC065223D184D22831181CD148962846A112A816A9144D138911B822DC6171247128B211C22C5C56C125C22948CD221B3C6CD44131481E828E242741132D2321614719A861C9E14CC2244A1839984D5244299C62184AF6
+:80370000E344E881E8821848F89DCD5012400347228424112981541A2824822413D368C148814B41888A14A2484E844D428D2529042A21AC124200614445C22C2412298892189E482D118A324213A81416D86848081229128411F4ABBB244449C2244183011B2185F6411448C02A8415A44185451438242641E612984540112122444404D3
+:80378000112E884200112882191292A813B452D21246C8B111731118C888002A514A5888421F320C1E28850116120127843944121108008428899481C840012240A242241D2216E122048E2444241524CC24881562485142C08489B82208418025922426A62188C88883012F7B041A42121808121236084C24052C8644814C411165414B78
+:803800003443342416221494424521445114411045788184C82249E24482922328843051A02848255424008C0849E4C23124A6FC654E248C941228390226140185C222A6028644A228242C7824921848A30882488A01142048A48100A04A2400001A08C88241008B14A082200250C23800F0E17E602848341A1418812264114001141886FA
+:80388000048444118011020088118216081F82240950414A4204489024522C4283CA281885167148B218C482A0212C1898841814FF710944388D44E014F248224820628183C8C486C8828361824B428188002242149021A9283222126908418222104211846488861AC81C1843C48C23449C9210CA18902480C4482D64172C0081180021ED
+:80390000101238811220444C02808DB22298828880C88240364424400242280028406228482534849041A04218008A0222200110027F4906403511D450484411B09832431B4A21A3984444393822219041481188192421048E41222AE414E114C221822814708801199414258124F112821C242844810427284C08B8844C08FF3A0E482462
+:8039800048281012289262C02644804782041A2495D222308A4692184849082413652160188E424894882C04204101001144804232841816048400218AF17CFE245E52A6C22242D085F3486835F2152BEF14B2F4BBC314A91416F861828CF842284FC814F3247419D64D8494C18E1473E44EE65951418CAE134BE6192EE84E6812B062D8EC
+:803A000074EC3EF55E428776AFAC74C7DA36B3C8FE44D1B73427A2CF4241B88CE1C1FA82264D248B3C4F11B138FC4E13005F947118D198D3B8336A1F11B14C914A172185A3224EA887491F44D548F26D4287321F2561693FA9684CCA6834A72819C662157161FA5231569683442233D211C6841F2262E86A32191FC29A822E94D891E0A19D
+:803A800012B44895C226E26112928C8B1A8CE8E2B444F2F6CBF02624AF41F2271C774333447626E292A616AED83D48ACF886426DCBEF2AD8867482F595D42F12AAF646B122E812A298467162435D2629FC24427F1AF1844583687C4FD44EB28782581523D846EA18B18136153E21FEC81F13718AE441F49481CE2AAF483B22AAE183F15284
+:803B0000C84F41B4886848BFCE094200224001241A040048A0410040486681428450824A5282C018C0185082100221100A188C04846088228C048062892810280882F05B6FE066F6312355B218D3ECF96262EF24D43FF6466D5F53F3DFF99F94F468864764EF44FBE5A5D5F21E96CFF17927B337F12D2DDF4272135BB3EFB2D1AEF4266342
+:803B80006F1DF96E2EEFF3F2A3626FAC72C2F981227F42F2A5AFB7BAC75A3F12F4BD6E3D427F31F173139F36FE9EF82F18F4A99D3F18D9BB52CCCFE37122F43282EFA2F8CECA8FC4EC48B872FE4F56246F63F23B699FF3F13931DF66F77A72EF35F56F63FFF7F33FB7BFF7DBBBF84BAB6FE1F1DE967F5AFAEFA85F537134F22BBBBFA3FF88
+:803C00006FE9DBA21D9B3DCBEFB6BC47F42E6ADF9FFF7F6F4F6BF9FE7B2FA8F2A66CDFF8FAA6A45F7AFEAB2BCF5AFEEBAD3F79F19276FFFFFF3317BF6AFBC3B42F1AF8D1F33F3C59F7ED2E6F62F822362F23F98696AFAFFBCEDC8F9CFD6E6C9F82062F64F625675F31F31F35FFE3F37767FF47F45777AFF4F67B75BFE5F7E3E9AF2CFEDE02
+:803C8000C66FADFDE3EFBF5AFABCB64F75FBB5A3FF99FDEFED5FDAFA8193ABC8AF16FE42634F72F6BABBAFCEFBB6A72F53F7CCE48F2E56E777626F6AFEA72D3FBAF26361DFEFFEDB9A6728FFBFFBEFE3AFCFFFD3419FBCFFC795EFD8F91C1C8FE2F2A6166B9ACFABB8FEFEFAECFEFC6EF81FFB49F26466FF52F2391FFF53F37FF4FF77F77C
+:803D00007F5F7FF7F77B3FBF7FFAFBFB3FBAFECBCBFFF9F9DFDFFFFAFAEFED5F53F35D6F7F73F397D57F56F4A5AD1D439F38FC6E67FFF4F626663F3BFFF5F7FFFBF976748F48FAA8E27FF8F8A2E27F7AFAA72F3FBEFAC98F3F79F9FABCFFFEF6FFFFFF6AFBEBB8BF9BF8D9DBFFFCF9CA9BEFE1F3BABEEFEAF3AEBAEFE8F9FAF8EFCDECBDAF
+:803D8000FD64ECBFAC09230222C01280C14845012286482149658828922C0242C02482422128219092422B928008290863022A082E921E482E82860884E081448404864822282489022FF6064905184C6214686A3111A33691214825C1482D1149B4423884A714C0B4865848488151812A74D8A4828751108884A24290888223648145421C
+:803E000048C24866628881822948886A8A642618283248F01DC4C0421F41722AF2112C83F4112CA7241F41F26A111D64AB9419B24AB915F44A914B42AF147934F8429347832F54F924481CF9244A4E816FA2E411F2274A96E1A2E559E2A2E549C24A1F49D232F49124AD821F49B24EF89124AF14F1816CAB141FC9F26A911F88B24AD985D5
+:803E8000B44A39A4ABB44782ABB4478A2D944F8AC4944FAAF4685850841AF62E421781E3E481764EB3117268D141F64A941D24ABB44B61AF14B925F44A9147832F347835E854F927482D915F82E514F926C81EA16FA224C95A9E254FA265596D489E2C6D481B61ADC11F49F24E819A82F1816C6F14E1C9F262141FC9F242315F88F64A9157
+:803F0000B24EA447838BB4B6D842F1A2484CF1A458FFA30D8628080000000000000000000000000000400100000000200240040000000040013FC4054A424218488193284816348183088C2464C1504968148902D4414942041226284881032827822614840A2749849B2849C28423023082815A2864886E12E048948A8381B2186812DF7C
+:803F8000B147432189321228444822832481513882861591214A12225824D38AE482984887244E28A9426481450A23B44661241C241E0426C14224138522C5894A49315231822C864882612188481442AF3E0D68C69A2818144C3248228584B88C51182B824DC14CC1219742296218C7221F624815E481028B288C433818542A2104A73488
+:804000008F1264446A48D2146A8421274430128D814A51122F422488D828A2E1257294C298868AE4916824FF82052521414228222182A41413013048501820840410C848899A4487442D42302482A450225E2422442A480412F081282E118E24628028D828B11124A448004290122220E2B20C2144271244144C128C02281450388242006F
+:80408000A02400AAC4214001008D21C8874888839142002002211788C18488A08413112201504240048B142084F4AB9F0018C1E08196112651841624888688147881A4681E282F125CC31C94641C518419483C6167868D4400248564442880D11231852AD8258DB2A2D123C95283451182D818F4C4118C84F8A84281844982E18138887B50
+:804100001E244006B041A1215C62824120069304C68528D232EA8402221B834D2913486926CC84C42860C8884E1800160211821741B3F21224A531C28384DC120146282D3484814548984CA0C1F08A150018CD21418342454824A128118870820868168854141C64444800441422C114C2244548A6240019C1A428292C68889818234101AD
+:804180002968115181216A18022A8111C8C84F714E821592491144192482280127E2182C1A18044311046088164891828889782482924212848081018268890A121921014C9222001A428111420C1818A2881242EF1E0114811E4618831388A41428481D8415886328831468841160811444282751811C888431984384521449584864C9CA
+:804200008294141DA42A2444B81214423628C1284C082A0C4A51428514124AC82A8F920A80121208181698A546A11212001C051062A1136142628846E884C266414004818621242296214844004425A64820A494860129084D48122B42844860814446043FC7063B14237212D482B118324156D814E111C2328D82948AF151886508278559
+:80428000F413E18182C4881499FA8822C5D12482D282984CA84684F22458C024288D145C624359C1C82C65464C7883081249D848E52621F24812438531B2C185E4A4B2360A84501811411628822684E4122141024284441210D4183A148B244964442094145218850196041D24294CA482824682D42201241A2642988211248287440045D0
+:804300001828A814F01755001084A4412220021C02224288152838826048448B5800AC150940048C0442C844282E128810982110052C42A824201468140020036200C9D4AC4F021A74210A11C13011118146281102241244D03AC41114228721282E924846914221214651922823B24B598213C284194524244801172988911811230800B3
+:804380002001818A43F23EC960821922022412287048041902409484008A42A2688004142280C2884100008DC1A024A021402428C462124220142244648248C339424C1C281AA4129F3E032420F1112681192454245068884881341144143024403414142064822D48181548A24810828104184823A8143C032308281228888200A0424986
+:80440000382886944400E7260012650181165814902182805261002712281411112840912289781C41C2487042D12148C488290214881CC8232C28042818212D11812D11B4182244212C0120C25843B228430300522A414282041C0420823A88820081243024228820C481442100A821437483420449142892284484A21F4822E21842826C
+:80448000820429248262224A3214248477AA0028001444891111C212848514D2218502864122258111110824104211411492481480A141811002202A1861812480088A12A21240981824812908BF4301828621511690412C322441412E824800101C12048A12442842C8418A021018084B82228388021E41804172182235492744482004A8
+:8045000042004146242404524142C756C03A4148840011488C821C51C18468406122A88241A81335121C9412142A18014C011814004598222A24882D082114C04244683841830189116248430989049FD448F322228E152AF21111181F114471135744C7922D816843D242FC8E82A08843F2211BA6F18194511813E2A2D8289461E95424F8
+:8045800025D611B42AE82AF8268C1E413D6676F195821F1967122EA82F24B18132651FBAF231122E21135291AE81A332664FC2E28DB224D2246A4246762874410F18272947714E4E1AB222F1292249E212F481D28F2272585A89173417826D842E2486F3C2C4674183E4126231AB942F18F2362827261718B528642C8E5C2324F1E1AA4146
+:804600002B982825FA543689C4648F96B892A3142B6C95B2D24DE244A5214CD12AB124E58CA15E49B394FD44687F1C0FB021D68131269D49C7C42F41A446BD2846F481481392428A4171B15B33A8C11BB46B235E5C9F82C26B9B44171C94564ED19C95824F34C2289F2C96127A91292694888AFCD2134F18D82244F31AC4F042C8B05A1CF0
+:804680004688A4C521AF415CC28F85DC88C2123F620B800122704442A816A014A016C014C0168418842484000000526041215604446044401448144814489488908810181428015018124410F8A623346F61F2332155F717158FADF11A5AAF84F46B39FFF5F31B7A2F85B742F37A1C5F51F515BC5F42FB391DBF93F34BCFFF74F5351D1BDB
+:8047000073CFC151A8AFBCF849594F53F11193BFB1711FFD8591CFC2D324F21E5F7F3BF915755738FD2FFFBBF3771DDFB77E4FFDFFBD9F96F23FBBBFBBFBBBBB1FF3F19B9DDFFCFF7E7CC7E5EFE7B732F7B4F6EFCBFFECEC4F4AFC26267FEA42F316263F93D755F315359F87F778388FA1D7DFF77D7EFF66DACEFC2A78BFD5F7C1811D8931
+:804780006F42FBB9BDBF93F3CBC9DF9FFFB59D2B73CFC3F3BAB9AF9CFE41C9DFF2F647459F81711FFD85D5FFD6F7B6B66D64DF59FF17755FFBF7AF27FFDBFB7DFFDFFFFEEF679FDFFBE9E1DF99F7BD37BF93F399BDDFD9F9CDD7EFA7F77E648FA7F77A7AEFFBFEC6E6CFC7F7BCDCEFE7F73C36347F51F111415FE3F2373D9FA3F37E3C1E1C
+:8048000051BF93F62B3DCF7EFA82E41E622B34DD4D5F58F834255F5AE928F85BDD4F57F7BEDD2F93F518188F86F7CBA99F96FE2545FFF4741FFF4E5C1F18F47E6D8AFE9EDC3F9BF9D4D63F1AF61CB6BF9BF3F576AFBFF7EE77BFFFFF7F31FFFBF2FA369FB7E728FEDBDBFF6CFD3E3CCFC6F34C6E2B774F6FFFBAFCEFCFFFE4F44F62F3FBCD
+:8048800081347F73F33B333D3F7FF1F2FB3AEF63B733F35D2FFFD6F33D7EAFCAF8782A7F34F55F1D5F58F834245F5AFB2123BFBBFB7FF7FFD3FD31698FA3F3E9F3BFBCFE6161DFD2F65F5F97B1FF54F58541EFDFFEBE7AEFEAF6E5FB7F7DFDBF315F7BFBBF295FEFF7FC7B6F7EF7FABB7F1FFF3FFF3F56F7F9D95FB4F45B5F7F6CFD3E3AD6
+:80490000EF46F7ECEE6F6FFEAEFE6F4FF77A7CCFE6E7E6B75A072D113022B02241681870242348022486482148022882421301118B24101803002A1898828001002F2281E4328864121A2402200800826CA24828400457518081921284A11644C2245081242810456282748028234488E288043F8214984685C4428014A84282488A82A9CD
+:804980002825A241228AA414169412481848182AF44222488D144846648218ACF4968EC0421F41F228131F41324C1F41366E1F41B64AF11164AB961B61AB945B41AF643934AF5439342F147924D812F924481CF9A44A4E814FA264154FA265192E5A875D2FA2E549C25A1F4DC2421F4952281F4932481F49324A1F48B24AF98124AB941B59
+:804A000028AF2419B54A3924AB944B42AB944782AB944F82D448F9244A7F6E074D4A4CF628521A324C1F4136641FC1344A1F41F662841E68ABA41B61AF6428F348853698822E48982F82E414F9A41A8F14F124824E854FA2651C2E58874C2F32E548C25ADE2CA49E648D429E2483F49124A3F48124AB948E24AF44E948B2489B248B944B7F
+:804A800043AB844B428B944783AB8423DA48F124528FA9058482480000000012000041002C040042180000004001400800100400000000000000701201BF770C004001261118869425211192112424A083C0228420386C13180420888404A91288040013B14C21982444465418AB14145800218901E0210C0083F24FBB50248A431A242264
+:804B00000122008C2402889024154402811384028221224664C446912C4392480049032C0A248003A284430C8184882508420044132446C144A7D1009285C24128388463021534461322CA819024142480D23A242298A833B88431444D48882E4C4CD481C428844E1460847011924C8A13B48442D484588694662858A28001D024C14340C1
+:804B80006141EBEB502428400411004228818001245042B240080049042200460128240028A02821800122304819A4148001008304A048A042E082B4EB01002B1210144182344890124001248C14280141008810084221812100824722120000242880021200428608002AE444AA420044411F9F0E284C012422C05413012B242A3862894C
+:804C0000C8141C046CAC842D6862E8281D488CA24862C4A042D028E4C2C44820C444290B85B22411B8429998128B2C2CC4A8A0414843BC8C768802128C52484E88814E9A0024282428119042801432229014106AC88A259444C8228948280C450A2E4290488CA4844302489A02842F4102239CA8C01842824283282464442869A634508465
+:804C80008B84C48F2106224981014130541C61A4221A2A9489601442482127822828304128842A840481409224843052640040C228121218E2D0820258C0848B828B8488302810042FEF0317448944864168811A0423817121A4142C82011608561284450320449884002D1816C4824200412AA4424C820100434428410438008A23488695
+:804D0000C1158A810243F4568E00893418006D2128408844048C121C5C2243048145724418B448721A22948818604883021E2861823281481022714402238264244E844A82060022E088048C4424942ADF6B0F210081430421002824281846110100208281021445424168444002442A011012341226848681028048410840881444489491
+:804D8000810020E8490515048741A9811496627012A82500186D5145981A6944121874524884464254D240D442D128C1825AA2128249012664422D24484724302646A8181364825810A8292A48CC88444828484AFA688C90420010FC1128180060321A16484801A041443A442512D881344830184883382450A44480B222042921A112128F
+:804E0000224880948248008044042F442199984150845F2F4D0230142242286222484912221202258403220025D44244820262842C1688622C640010240C81214924C124818C24088904896286809848100824F0ACFFA01418281210321212808402450128420016624100002618820426842402002A440821214E228100460241602242C4
+:804E800041808881B1488208888CF8F4C940C424001800484146218464145400230248A041C04242210000008A260600848810820242208A262608C282C42881101802484FA90D140044901414414048C2111AC2684F84112401002031184100299814103242006A012E42281822102804400880B18822010088A0128CC24449F2E78D0097
+:804F000042184345244102240014400424008469140880010000424008444824008C34244828302442202801002200A0812212F03DB8A01441CC1688422446024CE21442229112100222490610044CA412A6D284984426088722C022423042004448008448001A624A28424008288B21412508881FAD0F288400D022C414442811290141EE
+:804F8000C01118444C011216840460842122C0440000008092222812801406002120C11240822A4802888CC2244F4806A2A20048482084043042482C442302901848460842005844004188622944120888280028C04880A2421A3C4C8282800844160182871A42CFA70F84121C94284D89224184142114CC42C22184C41218411022711652
+:8050000028E2444184282AA4128049112282034821000089C2848844A021810020062200F0DCDF10F2C82449D24C32842F45A7462F41D432B646E414D28287924C4F51D462B134014F4195124FC564448F846442AF869452467464742AA442AE488C8C042AB424E12A622B8C7252A242A044428DC4CAA8158B6B8B995E14293884228D4465
+:805080001E31CB23A3FAAC214B42DFBA0E4A229B183AE17536245D344668448F32D22265363F447541D783D18414B2246324418112122B64644B2A21284E4A4AB242F8C2322B262F254282848C424274488852CE87E226C824284D8CD0884CA8822B819E88E0A8089CB948F88517F031544961534618483212430215342111473129D12853
+:80510000A223207128E865941269C51643816224C7821A9C2449C1224342C2448B244E22A121A7462A96244A2582A62C2AB4A2EC2481A4286885A8286AF2284829C1A8482F48F23EE51031241508191418B1288194181088048002648440284428440884128416C48856041604168468418112A14821108214022143181214321421412040
+:8051800028F4929D341A71247524F12521D7C43F33F3575B7FC4F51C1D7F53F367683F96F27316B5DF8BF21E162F21F13236AFC5F54A4EE5FE1C5CCFC1F12C62EFA2F2AE3AEF81B53CFB3C3C8FC3F2A694EFA2F53236214F64B566F5323626F83E1E4FE3F13C4E2E38CFE2D2EEF2ACEE4B8C8E822F2EDD24F15894CF6EFEAAAA6F23F37A20
+:805200007CCFF1933A8F83F32CACCFA2D23D4EF311314FDAF62C255F53F36D2E2F27F3527C5D7EEFD7F77F3D3FD6F64369BFD4F611158FF1F13E342F21F13232EFE757E4ED4E6FC1F51C5CCFA3D7ACF224AAEFC2F62C2AEFE3F3322C4F4AF7A5713E344F71F14E144F26F5BAFEAFABFB2E2EAD6A8FA3F4485AE7E42FA2F624EECEC225F256
+:80528000DEDECFA1F95896EF64F48E8C4B138F47F71C3EED1ECFC3FB48EACFA6F5B1B4F011313AB531B235F37477AFE3F37672FF47E636F76E2D1F77F76B211F35734DFC5F1B8FA5B132F33434CFE7F34218AF81F1565C8FC1F16476AFA2F226A8CFA2D622F23E2E6FA2F3AEAAAFF7A6226F41F1444E2F45F482C24F61F32A2A6F42F27E05
+:805300006C6E7AEFC6F22C2CEFCEEE6EB862FA48B82B11CFADF9C6C4CFC8A8324F26F32F2CCFCAFB3A384FCAFA647C1E4F144F41F7BC34DFC3F33D3C4F76F66E7E7F55F71D66EFD6F765273F17F77973EFB5F54445FFF5F17E3E4F43F234348FA6F31616CFC5F554548FC5F46C76AFA2B226F62C6EEB33CFC3F224724F2EF6F8EF3AD323F0
+:80538000F462287E46AF2BFB86ACAFA2F2747CEFC7F66878CFE6B262F66EECEAEE26F64E882B99CF8DE924F48A8A2B324F26FB3A388F88F9BEBC8F8EFE6C6EFF3C0961B0240126024150240040027416081224484412460428C02480024A1202230200290822000048228A048E484008128148818242F01DB6200200241A248422924146E6
+:8054000082C211484A3124002880810424444842002C6448A4460446044C72240280240481802811088584C48443084398B8504843D8CB014F32F4112485F3112487141F41F66A111F41F64A111F41B64A9961AB9459B44A3924AF143B242F147924F842914F82E414F9244A1CF8244A56F1245A96E1A2655DACED49C25A1F4DC2521F497F
+:80548000D22AF991248F24F19124EF26F18164AF24F18124AF249961AF243985AF24B9A4F44AB247832F24792498924F8AA4944FA2F415B6E0A2A5412CE4C1B248C16CAB121E4C83F4116CAF44D88196BA5D68A9B924F44AB1224E9147822F147926E814F9241A1CF924C84E814F8265182E5A46E5B2ED58C2581FCCC21A1F48D62AFD8174
+:8055000024CB141F48B26CB181B46CF181248D141D648BB45B2989B884A43447834A7AA488F1B6484AFA2458FFFF0A200800000000004001000000001800000040014008000014180040042800100410022501BBBD2008004880240200003042240021850284C06200108831484C688400802402238104482840648CC0C8E0C48802A04893
+:805580000028F018269F110D6018800192214421200448440042414230846800400224800200482B28001004410000000010250400824001FF3C4501C22081A481482604304420128444024140C2822A0428218A01241883C2841304248A226486241248442002418C082EC490444922044A08244031387F3801100100100221002004214C
+:805600002004234448440848400284800484800400400420040042100889480100802802419FEC05200120040000000000004008400440084800000000000000002800800400000080089F5A07484302002C8104110080080080122282080000008200844C21044818809242808108410000814008188A22984810F88B6A8084028004232C
+:80568000041100000000222189820800100842820080810448128032420000410080041008182A88488848F88E850049010012000000880000000040040000004048040000008021082200008100000048005F2B0A1C0100504840840188000040042220040000004002800200002002000029080000413022840042F0EF8500100826E2EA
+:805700001285041002800148004281000040344840840800484004214C020028293418880012008822184844224C8281F2A4F1400400440011844A41014001004400402404002001000012000010384290144480041088110220084200E0C80F59018160628C81442121358180410100496482004442008420214802800200212840880462
+:805780004C112C0800811032242C211AA8424458284F1D0C0000D0410644850200004240040042004084044100004218440041602260224818B042081880210820140422001FA4030000301110480800001008000000000000000000000020220881A021000000200100001FF70B000000000000000000000000000000000000000000004C
+:8058000000000000000000F04FFE00000010041002000000000000000000000000000012000000000000000000F0A37F000000000000000000000000000000000000000018000000000000000000F0D73E000000100424000000000000000000000000000000000000000000000000007BE900000000004400000000000000000000004064
+:8058800002000000000000000000180000F08CD2000081008100000000000010024004000000820000000081000000000000280000F0FC25000000000000008004000000000000000000000000000000000000000000F04F95000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000044001E
+:80590000000000400220010000000000000000000000000000FFC6070000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000800100000000000000000000F053F70000840081004400004240040021004100100218800810020000810000000000000000002F870EC6
+:80598000000000000000000000000000000000000000180000000000000000380000F0ACF7000000000000000000000000000000000000000000000000000000000000FFE40F00000000400500800444001002400400218001882810021880088400008042080000280000B0140100140000484055882810820444800221004480022148E3
+:805A000018808802214818448828842148408481421882041E148002211A01445C03000040010080041400000000000000000000002800008008000000288400000000BF7405000000004005008004440010024004002180018828908280018840084008804208000028000070220200000000000000000000000000000000000000000097
+:805A80000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0021001400004800800221000028000000280048000000484004281082044400108204440010F2448D000000000000000000000000000000000000000000000000000000000000FFE40F000000000000140000007E
+:805B00000000000000008002000000800800000028840000000027E8000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000002800000000000000000000000000FFD70400000000000014000000000000000000000000000088000000804208000000F0B2BDFFFFFFFFAB
+:2B5B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25
+:00000001FF
diff --git a/drivers/dahdi/xpp/firmwares/FPGA_FXS.hex b/drivers/dahdi/xpp/firmwares/FPGA_FXS.hex
new file mode 100644
index 0000000..a8b5cab
--- /dev/null
+++ b/drivers/dahdi/xpp/firmwares/FPGA_FXS.hex
@@ -0,0 +1,650 @@
+#
+# $Id: FPGA_1131.hex 5615 2008-04-08 09:39:14Z dima $
+#
+:020000040000FA
+:80000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AD6FF4000E00D0A006AD6FF4000E00D0A006AD6FF4000E00D0A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4455544455557475577775577675577775577765566665563625523235D2E37C2B5111155111155111155111E9
+:80008000155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111000000000000000000000000000000000000002552222552222552220025522225522200000000001AA1111AA1110025522200000000001AA1110000000000000000000000002552222552222F21F11211
+:80010000122F21F112122552222552222552222552220000001AA111255222255222255222255222255222255222255222255222255222255222000000002F21F112122F21F1121200002552222552221AA1111AA1112552222F21F1121200001AA1112F21F112121AA111002F21F112122F21F112121AA111002552222552220000000087
+:800180000025522200001AA1111AA111255222255222000000000025522200005F51F115151F1AFAA1A1000000000000000000000000001AA1111AA11100000000000000000000000000002552220000000025522225522200002552222552222552222552222552222552222552222552222552220025522200000000004AA4444AA44402
+:80020000000000004F44F444445F55F555551F11F111114F44F4444400004AA4444AA4440000004AA4442F24F442422F24F44242000000004F48F884846F69F996962F21F11212000000CAACCC2F2DFDD2D22F21F112124F48F884846F61F11616455444CAACCC6F6DFDD6D66F61F116166F61F116164554446F6DFDD6D66F6DFDD6D66FA9
+:800280006DFDD6D6000000008AA8882F29F992922F21F112120000004F4CFCC4C46F6DFDD6D62F21F112128AA8882F21F11212004F4CFCC4C46F6DFDD6D62F21F112122F21F11212006F6DFDD6D61F1CFCC1C17F7DFDD7D7006F6DFDD6D66F6DFDD6D600000000CAACCC2F2CFCC2C2255222000000CFCCFCCCCCCFCCFCCCCC008F8CFCC8DC
+:80030000C8255222004F4CFCC4C44F4CFCC4C40000004F4CFCC4C44F4CFCC4C44F4CFCC4C400000000CFC4F44C4CCFC4F44C4C000000008F8CFCC8C8AFACFCCACA255222CFCCFCCCCCC55CCCC55CCC4AA444EFE4F44E4EE55EEEC55CCCC55CCCEFE4F44E4EEFE4F44E4EEFE4F44E4E00000000CFC8F88C8CCFC8F88C8C000000008F8CFCE1
+:80038000C8C8AFACFCCACA255222CFC8F88C8CC55CCCC55CCCCAACCCEFECFCCECEE55EEEC55CCCC55CCCEFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F88C8CCFC8F88C8C000000008F8CFCC8C8AFACFCCACA255222CFC8F88C8CC55CCCC55CCCCAACCCEFECFCCECEE55EEEC55CCCC55CCCEFECFCCECEEFECFCCECEEFECFCCECE003C
+:80040000000000CFC8F88C8CCFCBFBBCBC3AA3330000008F8CFCC8C8AFADFDDADA2F21F11212CFC8F88C8CCFC3F33C3CC55CCCCAACCCEFEDFDDEDEEFE1F11E1ECFC1F11C1CC55CCC4F46F664642F27F7727200EFEDFDDEDEEFEDFDDEDEEFEDFDDEDE000000008AA8889AA9991AA111000000CFCCFCCCCCEFEEFEEEEE2F22F222228AA888C8
+:800480003AA33300CFCCFCCCCCEFECFCCECE2552220000EFECFCCECEEFECFCCECEEFECFCCECE000000004AA4441F14F44141155111000000CFCCFCCCCCFFFFFFFFFF3F33F333334AA44415511100CFCCFCCCCCFFFFFFFFFF3F33F3333315511100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000008F84F448489F95F559591F11F111110056
+:800500000000CFCCFCCCCCFFFEFEEFEF3F32F223238F84F448489F91F119198558884F4CFCC4C4FFFEFEEFEFBFB2F22B2B955999855888FFFEFEEFEFFFFEFEEFEFFFFEFEEFEF00000000CFC4F44C4CFFF4F44F4F3553330000008F8CFCC8C8BFBFFFFBFB3F33F33333CFC4F44C4CF55FFFC55CCCCAACCCFFFFFFFFFFFFF3F33F3FF55FFFBD
+:80058000C55CCCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004554444F42F224242AA2220000008F8CFCC8C8BFBFFFFBFB3F33F333334554444F42F224244554448F8CFCC8C8FFFFFFFFFF7F73F337374554444AA44435533300455444FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004AA4446AA6662AA222000000CFCCFCCCCCFFFFCD
+:80060000FFFFFF3F33F333334AA4442AA22200CFCCFCCCCCFFFFFFFFFF3F33F333332AA22200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000CFC4F44C4CCFC6F66C6C2AA2220000008F8CFCC8C8BFBFFFFBFB3F33F33333CFC4F44C4CCFC2F22C2CC55CCCCAACCCFFFFFFFFFFFFF3F33F3FCFC2F22C2CC55CCCFFFFFFFFFFFFFFFFFFFF24
+:80068000FFFFFFFFFF000000004F48F884846F68F886862552220000008F8CFCC8C8BFBFFFFBFB3F33F333334F48F88484255222008F8CFCC8C8BFBFFFFBFB3F33F333330000BFBFFFFBFBBFBFFFFBFBBFBFFFFBFB000000008AA8882F28F88282255222000000CFCCFCCCCCDFDFFFFDFD1F13F331314F48F88484255222008F8CFCC8C8B7
+:800700009F9FFFF9F91F13F3313100009F9FFFF9F99F9FFFF9F99F9FFFF9F9000000004F48F884846F68F88686255222000000CFCCFCCCCCFFFFFFFFFF3F33F333334F48F884846556664554448F8CFCC8C8FFFFFFFFFF7F73F337374F4FFFF4F4BFB2F22B2B00455444455444FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F44F444F8
+:80078000447F74F44747355333000000CFC8F88C8CDFDBFBBDBD1F13F331314F44F444447F71F117174554448F88F88888DFDAFAADAD5F52F22525455444455444DFDAFAADADDFDAFAADADDFDAFAADAD000000004F44F444445F54F44545155111000000CFCCFCCCCCEFEFFFFEFE2F23F332324F44F444441F11F1111100CFCCFCCCCCCF7B
+:80080000CEFEECEC2AA2220000CFCEFEECECCFCEFEECECCFCEFEECEC000000004F44F444444F47F774743AA333000000CFCCFCCCCCFFFCFCCFCF3553334F44F444441F17F771714AA444CFC8F88C8CCFCCFCCCCC4AA4444AA4444AA444CFCCFCCCCCCFCCFCCCCCCFCCFCCCCC000000004F44F444444F47F774743AA333000000CFCCFCCC3A
+:80088000CCDFDDFDDDDD1F11F111114F44F444441F17F771714AA444CFC8F88C8CCFCDFDDCDC5AA5555AA5554AA444CFCDFDDCDCCFCDFDDCDCCFCDFDDCDC000000000000000000000000000000000000BFB7F77B7BCFC1F11C1C000080010000000000000000000000000000000000000000000000000000D0510F4800000000000000004C
+:80090000000000000000400100000000000000280000000000004F72060000000000000000000000000000000000000000000000000000000000F04FFE8004001800000000000000000000000040010000000000000028000000000000AFC6060000000000000000000000000000000000000000000000000000000000F04FFE800200408B
+:800980000100800414800280041480020000800280040000214840010080041400108204000021BF26050000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F48180028000000002100000021001400100240010000008002F7
+:800A00000000882800008088020000EFE40F008084010000200100000000000000120000400100004001000040012800000000F092548084410128004840818102214860118002211A01148002211A041400B01281041480028004148828108204808802214800CF550648180028000000002100000021001400100240010000008002005B
+:800A800000882800008088020000EFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000014001002000000000000000000000000280000F0A1A3000080020000001002000010020000200120010000002002000088000000880000004FDE080000000000000000000000004C
+:800B0000008001200100000000000000000000000000F06D7A000000000000000000000000000000000000000000000000000020080000F0CEBE000000000000000000000000000000000000000000000000000000000000FFE40F000028000000000000001002000000000000000000000000000000000000E09D04000000000000100299
+:800B80000000000011002400000000000000000082000000000000F0ED6F000000000000000000000000000000000000000000000000000000220000F0CE41000000000000000000000000000000000000000022000000000000000000F0CEEB00000000000000000000000000000000800200002002000000000000000000EF8F050000DF
+:800C0000008004000000000000000010820210020040420100000000000000000000F01A9D00000000000000000000000000108202100200001400000000000000000000008FE50A00000020040000000000000000000000200240020028000000000000000000F07C980018000000000000001100000020080000000000000000800282DF
+:800C800000000000008200BF5F080000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F1200280000000020091200100300000025818101989082001828288800200200008200000000D02F05120022000000000000002400D3
+:800D000000004042812101000080012800000000008200000000F017E800000000000000922001001100000000008009290800228008002200000000000000F0AB8800000000000000400200000010010000001800800800260126010022000000000000F036E3008001002001400200000010010000000040020000200200000000000002
+:800D800028800200008F66020012000012000000000000000000000000000020021400000000000000000070CF0A0000000000240000210010010014000000301200200800289021002002000028800200004F32070000000000402201400214002100212009000000140080280200000022002200002100002FE50300A01400002200007A
+:800E0000000000002011029200800100143824800100800200140022280020020070A90F18000000001812000012000000001001001001001400008028020000000000008004F0C6A32001000000220024002011020000120014008041010013012021028228000000002200200248006F94070020010000121880010010011002000000F8
+:800E800000000028248008008002001902000040020000DEB100008001000018800112000080010000110020088200000000008022420100000080022822EF9902001200290100188001120000111814000000240018C032002400182800000000000022220000F0A35D001820019012000010820800004002000000002008142280022864
+:800F00008211222800200211000020222202F03EEE002001180010020000880000140000000000800200200882200A00200222000000002002EF7106000000008081818101001240818101240000881820C8112418800228180000000000220000002820F2ECA40018005022502200000000400100000014880000C021282250228082025C
+:800F80002082020000110022280000F0EAA90000000000000018200100000000400100188001002820888102002200000028000000F06CF800001200000000202801001011018001820000801982010000880080028002112002000040016F2401004800400200008022084001001002408108002042810228B022040028000000281100A7
+:8010000000130210025FD10D00A0112424242480012C01188A081840C11100000015210880A82388320088200B2800222A82C221000000281322A2221422BF31012081011218230121A011A0119A08184011011E11000014002120F18182169221282E2229B22282AA891C082A820200281411000080021C82F21D6B001812801102212091
+:801080000112001A011001131111422201130820018A81A1322921022602182A22A2220020220211262122A22222280022F0398700002048022400000082200111000000100100880000901280080022200200148200000000F0A139A0111A0112121E122B1124211A01121AA111881A0114141CF11112002301864181A811A0181F28F36E
+:8011000032321E1140B212A3111AA311008022828222B281B8810A2AA2223021222222F01FF9A0115A051A25180221A0111AA1113AA3198AA21100111AF111112120019814A011A0188EB33E322B112A22F252722B13BAAF932AA222282AA222A022288E811F18A822A0222A322124232212E2D60BA04100401242128201A03118881AA1C2
+:801180001114141F11F111112180011C48011A018AE138F112123A8342B22286A239BAA122A0222AA22200281111A0222220223222A0221E19001AA4115AA1112F21B1125122211AA1111AA1319AA98A1A011415F111111F11018001135111A011002CEB23B2328322B22286A2AC3AA9222A828222A2222A0210A1222022A222282B222C1B
+:80120000A222EF6C0F0018800100002001000000130100000000000022200200180000200200000000288002AFF1030000244002208121018009100140010010010020692290122002218AA2122002222002001400800200002F4C0B481B21B01162241B21272419B24291212F2499212B9413B84229F3429113F24291222D912AC4912E04
+:80128000421CF8214216E12264192F2264192CAC292CBC91C2421B292D821B294AB891F262811B282396212B8419F24281112F1428B24228B2422892822A84E822F4C95180B51186B41162241B212F2491212B1419F2429219A2B41B282B94322F1439212F14392129B922D412E922C5911F22AC812E4286F1225296C1C11E212DC21B299B
+:801300004819D622BD11A2841B292F1638812316B14298212F14AA282714222BA4222B842229B82294822E42D772008248000000000028200100000080010000000000800400000000000000000025014F5302008021110212001A2801000010010000000000A0122218002838284001262182080088000020820200AFAD0120088A02181C
+:8013800028001622828861211100A0812001820000522118190200A621810821198182082082820448A028A60100804281D2660E200C3A88210100A0298A214212010092C0122028018280110211192222E11288A1A416224291218082820220220828000024281422DF730C00002420220112218021010040010000008004182818000063
+:80140000200218801801822248800482190A208202004FBE0B00002A012420221102241224803211002021140111901180012228008810022C011C2128022200000080020000FF2101288021022382032488223216011418003813018200004200202269212A08281828802204802806480011282A8808200600CFB20D2220012821122113
+:80148000901220821112012814901120010014000028183229022816220212002008280010018200A02400704B070080228122022888238241210123011838008848140042130112200A888008002622C41182224A024200802282280200008D2D142818200218000010214131322E12821823212425843422289A02482601110086012C0D
+:8015000043A281124280242408003042222880024E22224A22086F910B180048A0482002781826220822001100882011328292800100281814284280C421100200202A028222480000009042BD96000018A082C012008800000020822202002044210212382018020000A08220020000008848000000F0BF4C141218800238C02280A28112
+:801580001C32121418388811298326248425328242A02114C031A0182388825522821120820400A8221002424228A042224A82089FD20F220012800412A04100881002211200B8008022428184820122002002181A62248280860800A048200A00100280A48410010019221382014A01222C0818220000881C0200100229821412220A80D8
+:801600002888A11A2084016016000013022200228006F07A4F2014419121100200809211181810823D22481868C01138A8208488010024381B2160212C4282212888722202002430422800238214022286F2FBDB0028224002138232113011003083002111800182888042218202111A28A142400188601423820810022302111042220276
+:80168000800220F49473202211216111480048800C48001022B912280221230422A0812028A28124004A488202112041222804200828004220048200281F6904180000180000808242022388489211802424828488B5222414129262424220225421008088261402486026000040820480A484DB444021010000184A8123028006182B126A
+:801700002002C011182442A0812931112001341A24A1818021A1141A2281A282191201A0281128224888200400FF5C01482001281322C141A08424304320280440822A0213080000481288001120820880820400C822482146014E824002280020F2991A001B2890211A489231281113881841011192221B1A8882881A2822082022836465
+:801780001513C212C882142C01C081821092424890222302904223843442483022481424EFBC0532A061180000001C15021B68482248A042250222299422582A88082022446111A048222AC142C022802288081442A024000024118A24B88204BF6E061A21FA1121281D212AF3223118141B84FA92222F1B4472D2A1312B442E121F1481A6
+:80180000B292F21151AA068216A2312E422E111D121BA12B482391628AF891522E2223AA1233A5422325B8A2E4147C42821832432C242292222D622A8286E4148AF8A768A0649A21A21286724322A1245AA5591C21039A446226BE3233A94B2B8B30821F15A1A2622811A85EA242467111E228B421B11123B2132831932AA1318A9B62A897
+:80188000281B2242241C14A14429A644884E41224AC2414AF674981417121D211817113A2111313111281DC2157141324119B8828888DA220A6AAC22882F2885AE4A2F26A41129A4632B5A186AA9856E41A88AC1121CC8E22B8C26E22668243342B12226C6822F1492A246422254222B8C82602A2F710CA012A012826E13601240210940B2
+:801900000124C0228228824A1221044A024A0228184229012242290118408224022E83482E82481C082C0888800242003F61061A22A221185E627E5323E11684A57613A8542B162F34BD82ABDC2B196E513F1BA1F62F2AADB39AF9B2A22B8AAE3229E421F823412E233F391CB192E9197831A1313F1AEB21F283E32B892B39200629B2811D
+:80198000EA2AAA8A141F18EA2CA88862AA88A2CAAAAC8229F2D561B031B371B631B231B7B1E323B362A7334AA4669E921F24B563F742D22F2CADDD2F29E117FDB3336E522BBA2F13FBC1B12EB22B2E2EA22F21F322223F32F632733F39EA39E829ADF81F1DF3B1B31F3FEF29FB93F33F1CA8AC9A6A222BA61F1CA8AA68283BC83B8C4A8293
+:801A000062222B8E2B262F2EBEA2AC862F22F29E5EE013B321F711213AE333F331213B311F16B641F561F11B5D5AF552733F3DBD93E92CBCC2F471733F1FADF72B793BEA1B8A6EF22BAA6EE22F22F432623F33F133233F3BFC82D12BC59AFFA1611F1AF6B3F1BEB21F3AF2B3A12F29FDC282EA22F883E333F662222F24B68218F322222715
+:801A800026EEA22F26B2E2BEA2BEE2AEA26AF6BCEE141F11B631B531F261311F11F261513B771F13B351F561E11F2DFD51733F35F7D3D33F2DED2EFC42C21F37FFF3F35E722B7FEEE11F1EEE26BEE2EE26F672722F27F773733F37F6F3E32F2DDD22BD92FFC1611F3EF6A3F32F2BFAF1333F1FFFF2722F25F6E2E22BEE3F36B6E2FEE2C225
+:801B00002B443B443BCC2F2EBE62E42EBE62B2C2BAE2BCE2EE26EE24F66911A0126012601248221A044800148A4422411281022880220800214A0290824229090029012F1288C412008A242248220848248A4482A42400F02EBB0012A02124122200822A01298194129228822C238811812B0A22C0121A22621100881B28188A622212293F
+:801B800028088A028A4201001422888022082A246438DF8F092AB411A2121B216E121B212B1619B242B191B242B981B24219F14292222F3429FA42B1A22DB11B421CEB22C4811F22E411E222E419E222EC19E222A5292F22B591C2421B292D121B294AB19132621B282396212F1698212B84112F1428B24228B24228B242AA42882E42BFD9
+:801C00001D092A94412AB511E226016E11282F1621D912B191B642A2212D832AC493AAC4B19AF442A133F242B12E124E913F22A8A517221AE222EC1CE23261182F2235D1241B682F32B591E224B191A2821B682726282E8319869A612F34282A24BA4222B242BAA294222E42BF7B0F2088040000000000000000000000000000002200489F
+:801C800000000000000000000010025FFB09601300243880C221B2002001001AA2A122828A84820222123812281A8AA2144A8801168101301224A0242240A348002200008A220426F115C20082148E1100301323018A71210246829121312480D4122102112902106118422158282829A8482DA2248A011722882831002200420026110205
+:801D00000014424FDE05200D8A012302372322AA814121C252C02260222222372848221A12228A21838196921302CA92828A34522129011C022223840226220A4222302100244200378A001942110112001C0188282180114121818984210A11280011860128585A0212B08182214822D122082601102104000021800AA0427FA6030018AC
+:801D800013210226A12180622212100148A8009200200822281100102208000028180011002612012004200882282004EFDE0900001220812484488114224111011B812860111422280020812481A81812290580F2229180A2821A0A158218032410010080048A06F0FB330000A012E0110280982100114081AA818018412102202292119D
+:801E00002001181223018092812812201A418238212124304100828028A24A48F0B3160080311100A0254822F04212204181041122181800A2000048602882884200243820A2281240410211000000200400F01D6F00121B34100114002C013012224001182E11280010029643021126028061182828200121004002822200220020022069
+:801E80000429F22CF78004A061A0126032190460126016122A81880290124228258228892402A03820C4414021022B1410220822241C42012082820260262200214D32143822108105000018004001000000100120012622046200141880882288292202C042482100250224000000EF6D498185A2211E214810613246018012021C212225
+:801F0000A812281002222488142925922123A62928188226611180D822213812206222F08322260300298202296222200428EFB503221214C0111A02001229118191413011001C218281041100100224802484042228182820A88200208404001002808402007FCD072800002111112542812188080014141100142824141800141C0800F6
+:801F80002C2822210A1219010028424001102202000022002FAE051110211181B112820448395222280090922602121002002222008084026021284061182823982220248226AA48294401AA8488248824C842703342011A022001182A848604211280214802002E11221601881002002220030000002840011420080086022828862208E7
+:8020000082485FFE05111110111181048012A1210000002A210300808128A11292222D81601800428002D012048A32228008222148008028024210F29FED0013A212003211210018280018311813C211190811381902101121918186011228122382C2112002100220081C082611022882280000CF2609180000468162212001882005520D
+:8020800026210142200160141222E0128C818162128A611218128012012834114A1A0121880022880048822B4888CFF14B010014280080542122800542240048C0510021981922A4280040A14842C8880018122E82C84A82148194414242C88004486022004AF2984300200100290412380080112243420226818801880021290128A01899
+:802100004002240088000000001100282948220222C021D0650D421848223A24042303001622A82420A4821828C22072420118149820228102143621A48411482048C18121800848D0210A88004021881482B8C7426112281AC3212683A71248E033C5131E32CA8885D122F521B33F22C1112A869D313C215A11882992121F11311133B8E2
+:8021800021A8991AB193A52588149AF121B21F1C3A2228111318A1448EE2822129A2E8806228EAAA8C1CA248D73F80F4311190117051B143E2359362282932821A22045A38121AB252223D3123B121022968322E4112E82A2885A2228EA22E22582811141226C2213F36B842A4A62AB8817842C1C2198828A2222B482EA12468CE432A983B
+:802200006D301140011B35241E4323E224314113A3822921315226214831211D9114262145A1481B311AE11A22EA18E3128A81E41224F4A28213A321A81421CE82A0221CA44C261131436E41A632428AA88680048827248F814F21046012482240021412A049A0412812B0110419041B4128488005D89041800918200218400200001440BD
+:80228000220800000000BFB50C1B151717111B231F21DC33D121B24223F463323F21F1A2322B532CB112C7123F39E932F312511F12F351D24E511E513F15F461E1CE533D133F15FC71D17E411ED119A5F516F1D3F3DEE23F13B321A298923F1C5E132F24B442F4C1C1A81F24B6627843F183222F26B422E82CBCA2B841CE824A8ADA22F407
+:8023000057E2001F1794111E519E323D1315C3322B763F22B212F1B2B22BBA242F21F183833F397B22B213A1BB1F135B131E514AF521A11F32FB53733F17F7B111AAB211EF12A55FEE423F3FFF62C23F17F711111BFB1B5F1F18F263C33F36B642A6EE8AFA41632BE41F3454116E4229E82CBEA2E81686B842A2A86E62AFCB041B771F1336
+:80238000F721211B111F277713F353614AE326F223323F217392B252C7122F25F5A3933F1BE932F352513AB331DB12E115F181511F18E832F871513F13F3119136E11FE91CA1F51E221F39EF2FFE13711B221F19F991913F1EFE82A33F34F663611F1CACAA1F2EFE43E137143F2CFCE2422BCE6E422BC64AA6CA2B426ACC423B4E146E6124
+:802400001F13D711F151111F27F553533F37E526F362723F33F312332F23BB52EE25F552523F3FFFB3B32F13F17371FAFF71F11B135AF181411F1CFC31231D312B671F1DED1BF9F191EAA3FFDEF23F3DFF72F23F13F511111BBE1F2FFCA1A32F3EFC63632B641F1EFAE1A11F36BE42FCC3C33F3CFC62622BEC6EE22BC66AA6CE6AA48AEE07
+:80248000E2CF480F2200C012E0128164221A2422091224134832112813A8241142132814A12439218429A4828029941240012E9148260226A148148214482088022882288200AF6D0214130112141224001A42012180013C211102381228821424001C92119A0212228229A12100348AC2811110E112082440032100004880F4CD17C041D2
+:802500001B21B01162141B21272419F242111B212F14B991B24239112B94322F1439312F1439212D911B431CE922C4812F2264112E5296F121D296D122A4292CBD91E222B591C2821B294E121B2923B481B24298212B8419F24283112B84222B84222F242892822A84E822B43808581B612A3411621B4127242823A4212B841B292F24B36C
+:8025800011A6843AF442A113B342B821D412B9339482581CFA22D21E812E5246B121295C324E212CB981F222531B492F22BD91A2141B29881B682B8419B22298412F14BA8192822A9482AA042A94822B42A82B4A5FF4072088040000000080020000000000002008000000800400000000000000000014F09F4D804121021A8494421238AD
+:802600002892001041B181042002282800241220881282B112A212002002D0122A410282212882482424200800282848CFEC054882208108101102203282160224001349110248221128800218132582082711883280212205264162124012011428006012144214F0B1122031C100584229849112229226224A4241924130811952222231
+:802680006232118A921228882833912129887212015A8222011B48181C1262388032A1002912820840826612F0334180042212880011220000121081081800000000001842181A8201880060221A0240820210824401006012140048A73C00004001349012130950228011C112221420048822000000A0425A822145220840818408212874
+:80270000000000880048208222F23EB100120058122248221021021C31832BB43011241B242712002488901230111A12A181828235A22426E122C1239082112B28882419281AD212189162228A46222814210C5BF30012001924611221B081116122404323253112E022048008002301A0212024EA286124601238311123388182822811F4
+:802780000029582142200882481422284F9A0D00001200482303003012981B2830211431130620328200C01140A11A5860112E42826022800429120229682A400122A82A44220422C8F087D6800280041120C12142128008481C81041430210021A0292022288401183428489041001C81043043862104882224200448484210B286084870
+:8028000011426022904100002420060028001200214A28290411400124141981081A2884840200822800200282800823088225F284AC000012000000881902211800180020020020212502302282001C01C0118008C0210022828004482828288008F0276F804401C02214130420842802215818482A1101122800882880272AC413281EEE
+:80288000822419C1C120C911421B2948001B841B284A82084890C228A22C26248448F242AA200220010012260118112988041100001C02004220051400008082011400006032000082008004802808F0D4C4902100001821421A220148002522112161122042C181108124422107262102111482460180880111308230222111190820087A
+:80290000A0488A829C82CFB60F4818381981428102102232231083082242208124211222024200200488122A912180A4122002800200000020840800009FC90610810228C02100002C0420542132111A4C022083242201241C0220A41210420114421800268202A211400229922228800280C4224F29021200000000B04201988200002133
+:80298000141CC981211200424A0814821414208882028210010028212100114288102294428012F2EA97A024280010012086820488C0412902A012624220280220223241222024E624A98420020080A242A028211C0648482282AA2404A2C882625D2A101111810225024A82B142811123B442812154125A02182242210080485122A082E8
+:802A00002218400211008820010080188102882100880021884F980F80210118120040826229112480018814C011121448420042121219840122008022214201111081089083884002881400002D66008211182062140042806811421C08CA91818811A0821800220010810188A04300200222001400422E82481042428222044041F2E591
+:802A8000630080041800000032C02180048084042121A0144A8808A04120C841A21148A042143212562104208428A42821C24200A21012023C061B63821180311121282682E226A78516022BC4423D912AE413A653681BCB1C112224A222E6A323221B223AA8422AE12488D2112692113A21815221282A08AE2213D221C4816E822B822E1A
+:802B0000C2A81F2CA8CE48AE812AF8FFBA14E019C2311AA12125E1148224C452237121E11CD9214DD3322546B2C1197191C21113A2422A248114F1425215611C1CA2819E622B63119021288AA222126E41241D222C3A422CF8428117242962284A22A862004E412D62BF1C09469111321C22C2321322A43123052F28177342B18121A32195
+:802B80001F1D0946E316019AAA1419A24C424815A1511AAC44CAC3811F18E1122C027A88D811E1148162128223DC112C2438828A2434822304248A4A22F815A7202402226012482248268244A34834482848288228A02480022880024A02802844210400004800A048A0482448A048248A04824282429FAA43B1417641B11181041E132B3A
+:802C000011A031212B5439918225B1527743B18268121E811571317341D111B852048A21C2822313A18A1B191AE93FFA22A11AF1412115F18141A21712111B2215D2317282E2220210F222A22B882A32A21BA28EC2A0882F22EA5B45F151511F14F521114826F213123B13481A65215AF481532EB23B513F2DDF33F193B119B581D9117100
+:802C80001191131BB14A858208242F3551131F19691892BE323BA61B331F14F221211F1FAF8A1F13B131B321F621221F3AFAA2A23F3AB622C2432D632F22F2A2A2AABEA2E816A2AA2B2AEAEA22E27145F151711F13F711112A42F2323323A4371AB342B642B553F1C2E12F18B8D2FD73233F1D681E1F136A121F13F1736113A176A0A2228F
+:802D000026F332433F13F5A1819E911AA15E1F1BBDA1F62161F0B1A1BA7B31F171211F16F221223DA32F2EFA63A33F343A412F24F462E22BAE6EA22BEE6AAEEA2BE2AAEE22FE95BE141F15F721611F12A2272E223F33F363617AA7772F27B752F5D3732F3DFFD1D11F1FFD63733F1FBFF1F5F1B11F12F371711BF61F13AB662AA262222E9C
+:802D8000622F37B763F6B1B18AAC7CFE523F2FBFE3F621611D211F1DAABB1F13F361611F16F621223F3AFAE2E23F3EFEC2E21F34F442C32F2AFAE2E2EEE22BAEEAAAEEEAAEEEEEE26F78091C011440020020010082200113011230110042201401318008002A08260198C01160320040010000000000ABE7200800001C010027241AC281CF
+:802E0000112F2418D11231114A08148214000060114081A429241308110000222814F022824013C182A22422882288802AF841A180B411021B2146B111724291212F2491212F24B981F64293112F14A9422F3429FA4293A22D912AE414F921421CE82264112E4296E12264192CA4292CBC91C2431B29241B29421B2927241B2823B481B218
+:802E80004298212F2418B14228FA4282A22F24289A82AA84E82A74810A2AB411A45213A1161223B211742292412F24B981D622A36927248AC4331B484EB3824EB129F442B11D121CCBC21EA12CE41DC2429E213CE51DE2222CCD531B692CB49162161339428A66148AF242811B684A92612B84AAB442A84A4AA84A2B8423AA84272A7F7EDB
+:802F000002000000000000A02800000000001800000000000048200200000080020000004001AD5E202802121081810611211218205423001200A0142488001860212002181308A228A218241224240024483082224222000000CFD20C1886410114182C2441230128308182402382248182060030412D21124880818184A2841260111314
+:802F80002858213041288800C0422400821182488E2142BFB8086016200113A1411A0615021822C0821431224A0124481A64218882112E11124E121021813481422A081AEE18C182146014204822064A4822242248C18240018F3F091840011440023412808231814240022081220200201402002A01182888122211002C012582020050DB
+:803000002222000080848AF485860028200100400121001002188220028200800400000000481100104102250224822501240000482800F01DC72042410115224221062214322C0117291922A843118E4148208C02224001260122202201284012312286A142110022800828C022480000428FDD032228204182024A0222313212D032C825
+:8030800021183A48A168008822200614C021200220818402503211822814219022310021C0224248280048CFEA0A1041011410011100002112808804114888420000000000220011002052212C04008220082800000000ABBF204521021248003022C021212A081C384222122CC412208414A2480028800216C24100000086218822481289
+:80310000811202002800800810E29F0600420018111814121420210200520000100296810100004814464111B222C41100000042002C28822898424002482229FA786800001400482004120011112008002AA8841100002810820100002028020021250124001124484888100200F04816204501005842181C8432111412119081298886B7
+:8031800021A41A42140014182222211A022C8564141120B811021482264241823422211728244AA88223480223882482F89CD100201281011440220128218214202401102228C44280040000000024302200822480081400002084040000224F7D0210012004407142018081080020818104184800003C8184835421822084050020041CB7
+:8032000022042004C60342200C238408003F950E62001822002321A14112231432122B4333044220219122B8800A1724400218182C911180B22281A11818298202002228002488222C02A2230480F82A110000141400210048212C01000020048004A068216840C1410034000000122800882823189182E0220448100200B0D904800120EC
+:80328000810118144A81A88428388842298F8188C3814A488202A085601123242221A241B2282021A2418682250823124291820021002288242880FAA3330000144886212404100280845822C8241A0C881C24314146014001321442108228010042B221821924F482414E2148421B48824888C84A028240F1AC62001120014800000098CB
+:8033000088A08118C8118824908200194622014200484280284801822028240840022400200224002C083F6E031A84A121001832142A0420332280040080926222190222D0128194520028222218002288809441152202008214002800800868288F2905188001130118100200800418000010011100200800260220C2812820820A204460
+:80338000225221002120022002228A02F0138700C0410048202441A141824230120080025A225822284A11818A424181014E11228084A1421814202122C2C12018810224880000D022023FA40F521321214131111E221CD4111161244AF962222B448E124AA44958D681B482E31D6826E01CB24184B543D122B51223C662682F1482E11BF9
+:803400000D281AE812E824B862F2618119A2C84AFA814119A8C81D82C82BA4AA24E42CA4242B882E812B8A5FC407224001524830435A82B492242949A2C525B2420829A9265A9C219E51142AC4222F24A2E211141C459192118AA8242B188081A41A488A7242127122F1428225724211A22CE024682229120248F0ED8880C511381D111B38
+:80348000524AA1141E1229A415182D62981A99221B912AA185281A7921B22284BA23062E8117111663151B4613A11376A2532B27A0231B13AAE22DA1611B1948AAF4622215A222C651214227222228A82AA8882AC222286F7B0A288042810268142880028A0440210248002028040010011142008811108118410200248A448344A248A058
+:8035000048A0482448A048B0E608782AA3333AA7351F13A3721F33F311111F33B372032F22E829B9D2FBA1A21BBAAE823F19EE2BFBB2922AF631712B222E21CA36123EE21E113AA2511B132B133E711F1CB441A7B91F13F391511F29D722F3C3811F3CF8A2A23573832186784161282724216A22A8262E624AA6662BE47FA9094AA376186B
+:803580001AA5641F1287D133F163611F36F66222CE922B118AACCA3F21B583ED2BDD13E32BBAA2EE1AEE33FB31312E214EF227257E732F15F172311F12E232F122422AF6F1511BF71F1CAE231F18D421F6D3A32BCBAE822F2E5E333D223F1AFA23A2212D222F2A92222AE222B222B2A2BEC2A42228AF5F063AC571181A21F741314AF5514A
+:80360000131F17F711132B553AF742E25E122B9D8E83CEC1EE823F1CEE2FBB72B322F7B1D14AE712A2E22B411D421CB471B631E717B572E327F792D32F34F592D22B33BE11DE712F2AFBC3A11F3EFAE2E23F34FCC1E14E232F1CFE41832F2CFC42822BCE6AAAECEE822BAE29ACAAA86F5B0C6AC5712AE31521F741316A77427343F17123F3
+:803680002724EEB22F2DED2CBDC2FCD2D32F1FEF2FF9C3F1EEE22BEEAEF17EF11F16E716E623F612431F31F512512F17F761616E422F22E423F692D32F37FFA2E23F12E21CE814FFF3B32BFD1F3EFA63233F1EF8C1E23F14F6C3E23F1CFCE3C3EEE22BEE6AEE2CBE62BC62AAC8EA8EEAD20300001C010080041224001A04120028138112C0
+:80370000A12480921128190100002A01002681A4124814482601144001288022880200BFDC0B48110014481001008A048028C8818A04224A28080040812404004230814840012C188128C88240234802002140020040F13A57A0421B21221B2166B111726292212F16B181F262921B282B94112F2429F242B1222F143B212D91AAC491AE78
+:80378000421CE82264113F2264193F2264192CA4292DC21B292CBC9142B291E224B89132421B28272419F2428219F24283112B84222F2428F24282222B842AA4842E427F1803581984256114112D121A744223E934388129BB11F442A2F04293C0923A84B8A2F44211AE121CE922EC11F82242922F22A42C2E13F022D11391C21B682F229A
+:803800001DE124B99162241B286632818096A21B6821AA5422AA042A9482238852225F2D05004882000000008002004001002180010000000000800400000000800200000000F0C4AB00001212142A0140C152140024800824480000400200000021000080611288240048002008243042200220F2E82E2004142848322531121227242851
+:80388000241482882C3311821345B3413851124A788322542190231C14A384298BC4513B84218A9181460224C02286110217241344221422C4820022A6012F7C0D42428082B42121832131427225210282297392011A7443229C41122F217881225C211063143113DC220956611423048812228280D2212804262184682400C86022202898
+:8039000072EE0900141218503200112150128200204801141280042400280080820429089811461241022502004612410224482502208202EFD209488001242830111428348A0210A2418819048A041328048004400100A0D28008215032002082048A2484C482820020088002AFBB080022141C220142169281424210438338322C48621C
+:80398000124A21220242142922914223022842E0289411903125218AE412C842821411103382214880A4C28022888CB8210542A012111522021B4116C281482B841001D83246011C84A482420011C012420028424286B281419221E0182284088A121181082C2C0800A28280A842824F9F0D00002818001128112210521221292818B222FF
+:803A0000284121024246220215220200B2480012350221198214820446324121244A084848800282F0EFB83011800100401281818302221498B0420130112005209D5210A114002446C1114A012188400120248246038800820010820CF055E814102124384114111400113012621A048220082140314248922222488085A11814C02290C0
+:803A800041229052212C022100883C249222480000201432BD002211960100284A02400100244240018800001001000022000012160180028242150200400200800820E45E47911126611119211401341C0619430248582C89282108330913852424946128145200AA81442103318E31D03224823242282E4135022C082888002482208413
+:803B0000E49407820040011428200119820114602448140000002412200452181022C14280012001C082480088194402230400A048002E26000000240014421440820C10020018218068244280819251218602421C2408009280042C04209882C848102208400280F88FBB60132003364261112C211212822115E13E2181E111248284083F
+:803B80002A0121C0322C428222C9111229238812011129B242A121868282082890212128002230A24A28067F74071B282218220058141126A1C312602140C1A113A2842820828881A8212581346121A084C22721181931221112822602625022800880088290C22084A282426F220160111413015A02282C8148420342908246C2122001D3
+:803C0000880018140018401162128228602124A22C212411024A8A18C34200423022A086200822AF95081200800221290218C0210023034082041280212804340010220126E22421C211C01200002220C4628242A602008200001CF861F20000111301002142182442881100C826812682A1824002290C80840D8814800840312180024862
+:803C80000020040082824A12222204F0457F2014212282140313241201002120148202108202242A810A8A11E2110226420188002800001002211081984182230200210046F2C869008A011880A324002E92A8804121B84198D12089A1248800869141A042480048388226711201A0284813212404628248400142268202280080F2A3DA97
+:803D000020084840210480042C04808304240040215512282A218109129041294291418094226840814282024012418142210224308288222308FFF60CE01891212E11121B422361161AE21A34122D125AA4C423E319E416E52126AA35148A661324297C6291126AB44255332F24E81327A2D1132E89A12227181F25931280B842E2286897
+:803D8000242AA2C44621A48221884AA88C10621A4AF67D669051822A91216E321E111C95222229A2141C12F282131F1415928237124A0F2B2B2B12A8828E239AC16329026A86E424A86913E621E9227E2113E122223271722326A2228AB8C114D123B8A128A4AA2F22A2222B222B2A8AAE248E82AFD10E3E2113232151112F242276117288
+:803E000043F35192AEE313C11213E128FA418217294A59122AA4141AA8182A29D62136119E121F23A2111F1931822D922F38D212D613B112021B912F18C8622CC7622CB44214D2327882A1481CD4224622F8824224C8628822FFF204421400481440A241246032402289020000208122082110023908219082422901250100240040013488
+:803E8000000040020070BE4F71D1F1111117111F11F731E23F317B337131F313432F31F9F3F33F37F733132592228EC11F14A8BBFEA12E223F17A6E21F18B812FA6161EE733F33C1922F25F572232F27F713722F2DFCC2633F33F311323F32B212B381ED2CF6637329A3224E622BE62F24F863E22C582323E42452222F22BA22A8662AA82E
+:803F00006EEAB462F64943141F12F2617115F121711F32D233FB63411B4717312F38F9F3D33F37F553312F24B8C2FF81C13F1CBC31F7F1B14E223F35B7A2FE9181B81F16FE61A13F1341D222F132223F3FFFC2632F2FBCC2FCF1931F39F163432F21F381E2CEC33F37314262242F26F442C22F36FE22E32DC32F1CEA2EBA82D822B2C2A41E
+:803F8000E44EC22B64CAE424F6AE74141F15F4115117111F11F1D1612F17F351611F33F353533F3FFBF3F32D321F15F7D2423B4D1F1CFCD181FAEB1FEE22F673712BFA1F18E922FBE1611F36FE33332CF1525227312F26FE42F12F2DFFD2F23F33FF51E32F23F712323F3BF8D2F23F37B742A6624E622BE66EA21F26E62C76C3B28284E274
+:804000002AF822A22BC6EAB6E2BCE2AE8A6ABA974CF1C1611D71F061111F36F662711F34F632323F35F5D3F31F3FBF12F351512F21B8F2FDE1E11F1FBAF3FBD1B15E323F17B7A2FFB1912CFAE1E31F36F67363222F24F543433F1FFFC2622F2FFF92823F3FFDD1533F13F511331F3FEA1DFD73112B442E4246F2E2422F2EFE63E33F1CFE76
+:8040800041811F1EEC26F2A2822DA22BCC4AAEC42BE48AE82CFAC7A10060126022208244032448A0413081B0818482049200000090124A020000501210022C01200882148A44A1482008822008F0776B001100142834123091904118F0428190921129094A2302244AD82244A1528044B1222D5D22131922611213094825822404621002AA
+:8041000021C02220042182883CF4517180B511C2111B214AB111F242131B212F2491212F2499212F3439912B94222F1429F24291A22D913AC491AE421CE82264113F2264193F2264192DC29AF222421B292F22BC91D222B1917262B1917262B281B26298212B8419F24283112F1428B24228F242A22229AA42A82E42CE2E8081C4511982C6
+:8041800081F6421319C212484E93284EB313A8A4F04291822F3421CA112B4229E92805C81E812B42922B42922DC19AF2224113BD22B88194429A326213796212E12618E12498214EA219E22428A284F042A2801A92A28E425F46072088040000000080020000000000008008000000800400000000C0280000004008F0FF18A0121D2218C2
+:8042000040011C0126A618272120041421588A12828302846240A1211CD222820227449082328A241202348E12481A08910042C0822842844848208122F4D48D60148A814881643110F81241841C860146180690115211532824111102214818301120296518221A48B51188E412641200228A64221592111C042002200A86015776A034BC
+:80428000C22100143341986229B912842166244502423E8180F12483428CA125603818681622522113C482422E91A852411C21643368926082482246016822102824C4A21282F0CB6A40B111A21811462101D01441683200841480012B141302001502805221282011248109488A521282348A44011081082532113C08422200002848AF8F
+:80430000FD0400250114003022402181011051128002850518000018822041325800880000108224224102889200002C220292287047032384824962238112122CB1281102218C48161864881D44524A384142C044244B12108C3122494BB2442181D312BA11A2286B58181F43441854186022304221AE184130442C9428428C84C24524A1
+:80438000001901331322218192224082318824151831882E41481DC4421880444284D148682180B2129442A0213119022745902242494201288825028308A04223148888027F8A0742222308400824181618830140441204411881144210043800A0124C1998141282A8122A282861558490185022A0C1801304412C8222C548288E4914AF
+:804400001F4413D2817124582481804518144108001B48C6881244180212A141C6D98124023035A07846052E130081A42C422C048542982C481088E18421E4812871162805482F960F0046029041240027122AA114121C61822244D02281B188C418682984227B3224211418124854181481411E411823D594098C0128284188442A682243
+:8044800044160400C9684229F129C70000804442081218001018014001442250481008008100422002008800002D2224000083080000228002F0DC271412211245C8443C04218C91133881181C11B88154843CC21484C81881902C2E4827573881815921C4D442111341B4113818A5E2C2582A2C02A1282280688826F2144843846823A074
+:804500008128421F280D4F12048583424218A841C024141A048414224A082443912A844E348C04118120448242887224082602004A3111411E4880124AA884450812209118D048F1244844F07E47E0110228512CC2418C524289D214B413123A1212248C01CE1822C122722C682200608124410047288140021E282842424800180049849B
+:804580000148A085C48A81B212482CFCFDA714241481404138120000521128945082104811488942A91280C581463889100882929E2189318150810025D8810649C2C811AC1291A42C022303618044E8830636912C268222923426843236281382124825116411A6A438A21E2418166448288444482F18041684B222314420240800AE14D2
+:80460000212602260222211200A582028481288412BB730016021281406194204448012022025081D0814814011958214E88599218430E122088A2291C22C8111038181412893118548341911816A8164143A482324D4812222F170D8662121C21D21A011216126123602411C011178118468881026820542283250129012E487022EC14AB
+:804680002204272122A3C12C214A028C02AC064784A42AC484844C312842414CB9245518AFC50B43041094448A9448905825A14185018489A442C906441840786208460829280222924160812284288122421644C71A4091128A8401803484872818188248828AF2A95A401854848450840000800140045041102114017912840829248AB6
+:8047000005811C0841148254C01110C8443442C014144885312221482430420048DFEC0C20911250421911D658110100840041825012C0D3D018011C08544115941893925412C0191001114933211A326118230617223041128081024A92588C22026FFD4D5184904437811228A0249014C02418D942246412224CD8480941274489B84494
+:8047800041850828001312E84281C848C044C4105241200415C2148829028446044A180410021F2846C1428E2315D2B8F246131D4863E584E1D4F144244A613410F44C13F06C3186E118F9B49547118F51E5B7F688A9FC7684F81641628CB795F3144897C1AFC2F394188DA4863191DF487229F879763F61F16421111B24218D2D3BC5934F
+:80480000542119B14CB61EBC4CA8524B8E2DA44B846EB12C711C0A36F11B148FC2911213734CF5281E81A3623127B289115B1813F368281A785CF8112895D8A137255F48712136A787114E1E8D662F17F86A8C86C1129AB862BC21E525F8221B2E811414C11D1A2F74F138539B152F23C1131E198715A7132D94CC7312D6CA92321AF11815
+:8048800044C9E482FA9E36D04533246B2157438D2C3E3219F235671B213B521B211F83E69171114CFC145715E8427E2E84B2E8E8841298464AD821045D919748488B324B62419D24921B72A8ACE14153842AFE18448F8256822E6242AE286DC68C6584A66A26AAB754F81842CF86F4A23816BCC8B4C44C2104008A0448148C448104004802
+:8049000080040000200442318188100188D01408881004141004148C04828004922048240882F08551141F1BE683F23C268F42A6631F5AF2337B3E344F66F23F3C3E323A13F81C14CFC135123F19FC28AAFFDAFB2DAD5F7FFF41415FD1F142811F3A78C3D4CCF51CD91F18B52BA39A9B447E58AF94A44F5E511FB1D133D283F76979AF850B
+:80498000F17A6B3FB5F5713112CF327611F35B473F35D41B7424F2C242ED2A2B674E42AFC8B44CA66225FAA167141F13F27272EFE2B232F7B1249F92F333371F53F33527BFA3F33E768B339F52F31C148F8153DFBF99F8A9ABFF5AEB1BFAFDA53F17743DFD99BFBFBADA8ED944F515511F13BB5FBDE4FD7878EAFD4AF18F86EE25FFD3F311
+:804A0000BF32FA1B599FB7774AFA7A683F15F179791AF12A333F29F16F373F34D41B722CE867F594127E787E688FA3578EFE687E3ADF4543F145411D4147625F71F14B6B9774BF35F55E1EEFC4F418581F77F55353B9525D5FF57443FBFFF59F3DF983959F98F8FDDDFFD6F6357D1F1CFDA9C94EC5DFD1F16D2B7FFBF5627D1FDAF94C4F91
+:804A8000EFAFF58A2C5FDCB671F7A1719FE9F31F3D5F76F75B5BBF67F677561F16F22141BFE6F65B8BBFBCFE5B59BF95F574B26F2DFB4A8A4FCFFF648E6BDBABDDCFCBFFA83ACF7D42F1C1614B51CFE1F15F1D9FB4F44CC6FF75F75F5FEFF7F55F4F3F75F55313FF81535D8FF7F44F4FFFDDFED9DB7F18FB9D8D5F5DFC7C695FD5F4C9FFC4
+:804B0000BFFEFE5F4BFFD1F56D6BFFFBF9CEDD5F5EFD787AAFAEDDCFFBC5ED1F39F9A3F3FFF3FB5F1DDFB6F76B4BFFF7F657571F17F71151BFA7F7FBDBFFBCBF4BF57B5B6F2FFDFE9EEFE8F8F6FE6FEFFF9EDCED9CCFCFFFE8B8AF5101411042581410042041618114403311449285243848D048028504421885044241420022800141847D
+:804B8000241E48200184248C44224162814412890244F09CFC80118141941A15181E9114840081128504895281005419442448415848214E25988504812A2C8418D118084E11200485830412271413110A8D248C6424840018B43D9BC0431F4152281F4132481F41324A1D24AF14D1C1F24A9119B24A19B54A3924AF1439242F147934D83C
+:804C000012F9B4481CF9244A1CFA244A87117FA264192ECA9E252E5A9E244DDA1F49C2C21F49F22C821F4932481F49B24EF98124AB141D24AB941D28AB9451AB9443B34A39242B9447822B944F82A4944FA274760626F311448F22741134281D44AF22C1442E134CF428971D448BB459929A4B4AAD1149F442B147812DA16F8BE414D886C2
+:804C8000E114FB268A1AB82564193DCA4CE2924DD4B2EDC8C2D11F41F62AC21749872686B4687981B46A41F422941B48AF449325A9B9A4344A43B842638A2F447186B842F3A418CF810C20880420081200400428000000000018000000400100800400000040042800000000008F530F20822211241228521849836112180011811416F86B
+:804D00002216904183110184808141882892A28E284C2221421181C6121064D1282F11D2186114208861416024810000A34211A418163281214607250A3480115852812DA6184901A0818D14424AD22214B4420129123418811636142B1C4E261A08263484686022288824228227244448212C826162446816014FB40DA03C2CF281126067
+:804D800024818722914D33411C92186581F22286701461A12A71926211832194428F483112182351481A782962688E28AB921E442345C1244232C02613A1827362121348B284622143C122482542828221D1180C418001411D242400802101101891180041D0842434211022042810081A92144624A22810B124881402C3022C618146822D
+:804E0000044800184782444840E2370F1001841828241E484184881220C814A0B449941800160860144004D0220118122A8932245012111468264118A641A02924846C01884904822002481F630E14A0212840A921143092482728D04A918113448821B888B584E118B44862144528324B15384CC96A86228E4845028A65111226E84174BA
+:804E800016AB412B488C066848828622EC877828D43888F22242A01482F0E96410112101128D212A3143442981989290848E14138432441281411C6586111128451941B28481A221424B2823226A3119D18112915A1B212B84498284A285248D82CE148938ACFC4882081820F4B29B0080628200608130884810D28241018B851289A858EA
+:804F00001AC88880344C304281C36482A3048B8118E04401005664724285324818422288002B4320248216228608BFF2072C82018302142414227012081285B11A240442128125CA1448008682110483440884801182E181144A0C233828C012262C024826A4145A486282C13A0C6870F90F93014A2221143A18C11D1884418C0143021390
+:804F8000E28489112102105422888719241AE48A041183D3244489F42844888A941180022522051544AA851E21122342480C001A4214F284DD144241151C110828004126C14180184402302830A484E094828282144804224200004128414A11EC8104001A94119082812420242112828861443F740A3C0485F52811872491AC41688345C5
+:805000004A410955E24124628530198144CC2164A6A8842447844B2846489128450846A2428222A7114D4826E2886422189041701282618127229668442D1881D2A8122CF4FEDBA01A16240200221544018B121A846188811994821A842292AA401401172252188304898225548212411694984418C42C412824B12AF111284AB88144A477
+:8050800041428428439222124E2441AFDC0E491202121A52814880641124141C018921B11CC48210A812A094288888128B14126042832634415644214541942C478410B4123228188123628828430400493154490822EFC8031064214511892451141248002095812190582819144218C4448C05628A2248618824A824850280A28120C1A4
+:8051000028223CA418A88210E214312222E7262426A88220C2827FDD088E414816081112830140E8C4A2418998911126840282E0222883120846084048C8183210CC42481018684166682148C4C04860812048B8420B8301004311F438D8001C01004C0610081281480082458124C5418449440884C08A40613C40C4140019021B41239274
+:8051800041B0429299281728202E0C3110388843042D446882843F3B0D4C62114C9228A5044CA2241A8292412849011810237222A892298884014126210611438101422C0848444C022810410127142810C188C014A01224522CA22483026F45081200112C422804424A01A0841324922A8889210813819241108111814112382421862876
+:805200000200C0228A647148204818D6C1412495488A3442422924081082F8796410322421410011C71191118486042C021824112C4428140117C8684890284A8A84C44860814441002110120C2F94115481002118293284802182C1948824174C6024C2459218460453A2411D22A02118818C280C16423111204449E81408258101129277
+:805280001954424C8141218123C189860111AB580080924146018C1118142404121441BF53436291249C4282B8350821104861C48012988C8906A400169422284C0B88488C66628041C94428C4118D44432501124C4224E418646583C132888849810147182908678181DF894AF353458E2667C18FD192825EA1548F5167224AF3186B6855
+:805300001A28F482181E9C1FA6FFE2125EC2BBD6AE111AE48615F444452E815E618CF1F15289B444EE8232DC8D254F84F144641923F11C124698181764EF54F586122D8523D528B593C24A2F11FA644C43E966E824545843C9C49641F43C9790244B4D8F1213F7651C63B23413F448211CA41485E98CE581F15181AB2A437119B1A843A8A8
+:80538000A13F56E319D259AC281B41268A92A8474CAF31B11CA4C247816C16A2414FE2D242F434457116A92B8F477628F2A9E11F84D23425F14852AB816E7C386FC1F174D22F6217F4283D89F29FCAE022D11341C2128D219D5C1FA434411F8175197821A495C5F181C1872241A5C5482549F34248C55848EE288F82384A188BC7941FB33C
+:8054000069C22F44D1C2E12C15D31141D419F1A1A81BB87E4EAB721D8A15F9D14845A88B8784BB9C13E828D32AF81C48B082A284FA93844FA8B84906200222482170220123022302218A44022811891201118117284A5221801818314800144214C0818C54144800418C440314480020480300F0DE8E246B411E12E7811AF448427F21374A
+:805480001625725A522183513BB5FF1B119FB5FF6DFB87A6AFACF852823FA9B982F83424CFC2D4AAD4EAF8894A25B252C88237C23E3C2FC7E742E277E243E313F364241E372F49E435F416448FB7F6CBEB6FC1F14185CF247A8AFAD255E034F37C766F25FBA6A26F2FDE66B6269A94CB93AFA2F81E2D346F41F6663EED2EFFC3F26C64DF66
+:8055000042F345246F66F25A629F23F75D6CBFB2F2BBFBBD519FBCFE6DFF8FABFEBBBA2FA7F8622A2F2AFC2764CF46F67556EF6CBC28FB28588FA1B492F5E464CFC2F2396D4F42F6B4EFEFE5B176F714544F6373A6F474DC4FC6F47C7EBF37F31A389F94F2E86EAFA3F17A78A7282F2DFDF6F66F25FF3E76EFA7F6CE2E6F2ADA46F3BCB4C9
+:805580003E96FF4941F247263F23F71E2CBB33AF84F57131CFE5F66878AF84F363218FE5F2E8E1AF94F6D91BBF15FD2DBF3FB6F3EBAB3F3FFCA9EB3F1EF867619FD2F2E97BDFD2FA2BE81F13F458481F357C2BFD35354FD7E54BE966F2277D3F12F735659F71F39787BF35F65F27EFF7F6EEBF7F56F52195AFF4FB4B598F95D33BF943D3B7
+:80560000EF25F3DEEAEFA2F65C5EEFE49EA265B434D164F18BB9347F75F72F76ED2EFF43F36E7EFFD6F745674F43F35A39BF97F3592F8F1EFFDAF997ACBFBEFC2FBFBFBFFFF9BABFBFF8EAABBF9EB867F621255F6EF7EDEDBF97F63153AFA3F493D1EEE5DFD6F62C6D4FCFFFF1FE7FF4B167F715159F63F3AF859FE7FF6F6FFFF7F7ECFF88
+:80568000EFCEFF68FEAFBEFF2B199F95F3DB533F2DFD7676EFEDFFBEFECFEDFD4DFE6F43FB96F44BBB4F62FBE422400100454148C14880041A44A148141781648E480083044624B8480290118029140222A0128001886022009200A0496088281E482482008182CF8C0782501820821812911215180A2958812931858902888E489880C3F8
+:805700004A8124811F22044D481A62824AE2A269412A24512C10C4488324794A038F340198842582C4142AF4422247824A21C184F0C124C0421F41D228F1112483F49124AB141D24AF14F11124AB9419B24A3985AB9443F24A9143F34A9147822D914F8AD418F9A44A4E814FA264114FA27498E1A27CD8C5CA9E242D4A1F4DC2421F49728F
+:8057800028F29124CB941FC9B64AF18164AB141D24AF26D981B64A19B54AB924B44A39A42F24792498924F8284FB244A4F490E2D5A1B41AD5211A9F11164AB14F04A111741AF4418F142B45788ADB24B428F143994AF24388429F9A648A9E12AA5944D8A1AF8244A87152EC287454D819E242D4BDE2C45EA49F628424CF224928E48C9F106
+:805800008164EB1619F42296CCB6489B24A9B924B44A39A42F64712488F9264829DBA4F58678400848001004004004280000000000181008000014000000000000008002000000C021F09594104641028D11118122814C922880419CCA35B41842B81102885811CE2410C1241A324845C224E0222924385422818E1483C222228A74240800
+:80588000A41880218464C52AA4846870680484DFA90762AAD182D841812421B1183C141924998186088014A142489C8424220381421884824E28814848B064018843219241419994242B1477A858221882212E8C3014184490113691C4190D3071865852871512608916143434A092C1254AA512842E1183C482621621088A21E38122F81B
+:805900004824C312E1218494D852E2844C986949B228B444E8E512BC1C34121216A224E249B544A3854224CB6136F194487F7F026B4210220111898116986189388181A0844885A14242114212284B4281194404834402488A024C120449A1210025811232812128200845180830244001F0AD530040112102008022820400004128122022
+:8059800012E882141801481248874400484081D2146141411A248404482B82122D11840044000000F032E78085911A8582351A1A129111894181410246422114E2A944B1E8C1116A11A548AB422F8481C148AD36288F41A2434B12D04202A8841B5221112781422113B44202B011C4284A2221E861C244326842FDAF20049311A924898136
+:805A0000410189034224C042144612E4814E81CA11837424A84846D1828511C86A668C82E541445241281116EC449252118C211492C12B253181118162808812A61242F02288806121408211820216011C2201000000293158222AC141A48302482C6541701488820222C0B4C01160244220942280014A2112240116840428487FFE0B2A04
+:805A800004190421144026115482222417222481842C035812A0124A321260A14A0880251122841168412E481449E4120100CD824C2182042684013018C8628222218F86074581916813E2413222487200118425343841C8104212884248081A4288D448088F24032849D1180189064823812184B84811A121C49180321282C668268226BC
+:805B0000220144A11F970B122342041018488802280010283116006C021214848D424200A3022608C0244882C014498212544829222424C612B042412A0400004220F458A9E052B122D18462122951188CC43412412D28A4D08241B812CC1C2C02AD4222849466784862842C3144218D2228284C913448684CE12261122E541744444A237C
+:805B8000F4C8224E188C0142AC2128082788222B214822818F7B0E484001472228C048230214281051428425220143832181438202834498285883C512C0481288106C41A0218D8284141624922127241225A44183A442188A24244884F4189E20824228041002005021418041284269819122801208124AA13C29F146212B422002115057
+:805C00008231288426045B21485684111102132516820146024200FF1E4943011281281AC2121C01273822102801671281444C82018501422364248C024460814C62842C644216C811811211214E224652388200888961E83018C183148228121CE215041042120880622483210528184E12811421202221042A210214C08840184438186D
+:805C8000444A61448011C434A4441844845304C01D2800301244100446F4BE95A02112001248814124493238481160421A2401F474141C8504301840041948A124253418C089441512A884128180038160A1C21532848A263884009012E0790A2308A3A2142C6282114D28104C2A430200321800801471190429083185C44469148414513D
+:805D0000284018245338400920028C86044448C444283E4488422CE444F26374401151343420381212282814241058A224442081741A0184428D11241C08608189810440C4181CD42234444006C416422402C14028422204244C269124F0C3D340A621182230146450863012854108302CF042252100221224680032223021C0232226013F
+:805D8000800200A6821221041814284A688118122410883292F096BC8005402291412811281890481901124815A24190484281811982122911711289014042243424251448C1441D38548551481185711811022184660428904441002F474241082D411018188C94148D416041906A221844502144811221D048B14282488482021E8A54F4
+:805E00008C3E121D482AB1340C22800162244064111F48064329F882224B1C80819122F0FDE2003399222D2A2A432291142E2CCF295188BF13D11281C43A33E481324137C2959A1113B628D42822B678A114465488D7615F8162448F44D641D4567211F55C329F91BB5CE2F862C287481FD1F3184D4F488454989B1CA7C1178C4BB84F63A7
+:805E80007434DC48E664C4942E344D4244DF1A44C21338B48B44219F82D7E1734196183FD4A6114E4887C15638348D534CF1144CCF31C241AD4889C4314B45BC7682D112F2A8916D31266916CD7A67A26B825E42435E4320324C19D28643326513F11B24172527815B548F41E463E48CE828B956911247864B418F42E124F47D89143F435C
+:805F000066229F413111837152342EAF11761622B223C22215D22A11FA342C67322F1281F156144E211E19167821594A1D4A87215F2162432B7CAD542A88F1582A9B122C457926D643B131F41E121F32B42EC432AB24943845E118F82683A784893342AE8243B28224A4A163F2384A4004441C41641420064A084282460142114A0228A0A7
+:805F800024114614A124114211C2200882200C82148A448104E03208002448284828844008844AF2C664141F2456755F72D266D49BF64C4E2B544B35AB735F1BF7F87A2F2AFAABC53D437FD4B615D1ECF46E4DE7449F16F7343C8F83B551F5714C2B669F865588C5A8B98FB1F172D76F45F9D4D6CF5DF5CDD5FEF53FCEF8A3226F4AFE9C2F
+:806000009D45F4ACA56F42F34F5FCFC4FD4CDBBF86F669454F25FDDFF3AF26BCEAFCE4C4EF48FC68614F2AFA2C2CCF4E5F2EBFC841F357677D4D342F21F57329CFC2F2484C6F45F17A3E7F5BF7DF4DCAFEC9A5FD459F94F67474E7E4E7F2EF42F43B327F67F33A788B55AFC6F5624A8FA67C1A588D4FC9F9949E2F65FD5FDD4FEDFD9A5D3B
+:806080005E583E716F5BFCB3272F43F33C3E4BA8CF42F22E39AF94F728F88F62BB22F268694FCDF9D8F28FAEFDECE62F4EFDF8D2FF46F69E98E5FCDCD4EF23B3614BF357673D433F32F21113CFE3F22A2AFFB6F21C78FF13F27DB33F55F94162BD29237444FC557D6D3F7FD2F247174F64F7147CBF93F57959DFA6F76F299F86DE39D41F11
+:80610000F43735DFFFFF7774FE65FE34CF65FD571D7E74AE446F62FA37367FD57515FDECAF6F66F24624FFFFF7DA5FBFA6B74BF7D4D7EFDDBDACFEECCA6FCEFFD6DC4F6EFEAEAC6F42F3C4FC4F66F786CA343F37761F577E1F15F1342EBF96F62D6FEFC3F71F3FFFD7FB1BD589D29D714EFE2A58DFD153F77FE6F62364FFF1F35F7DBF9309
+:80618000F7687BDFB2F2676B9FB6D63B944FFFDAFB5D5F7F41F5FC672FEEF44BEE3F75F5F6F46F5BF13F8F7F73F3DFFDDFD9FA6D2DFFD7F14B6BBFFFF7FB7B3FA6F64B785FFDF8FFCDCF8EFFACBE6FCEFFF47E6F4EFE9694CF83F7D4FE4F62F33CBE20024302472240424842486381241244844C528164800242801202212839012180018E
+:8062000023022F12413822A0121A041E482200122482241E48241289024270BA07672819120C4088113124C01150184022D148221112D148828481048C14E88265454B1242A4282A051C044044822404250142122581F44895224A2118A84887449038F0638AC0421F4152281F4132481F41324A1D24AB141D24AB9419B24A19B54A392490
+:80628000AF1439242F147924F842914F82E414F9244A4E814FA264154FA2641D2E4A96C54A8F49C24A1F4DC2421F4952281F4932481F49364A1F48B64AD141B24AB981B24A5985AB944B42ABB44B422B94478229F924484AF9244A8FB908A41B6189D141324A1E24A316314A19F24A9411AB3451ABB443B24A19F44A9126F8428165B84ADE
+:80630000E9A2A1844D9A52263AD82662584D4B8F49D234F4C12845BA91D628E449921C9E68611F88B64E014E941FC8B242D38594B84B42ADB449F442944392922F8AC4146B181F5C0384000000000044000000000021800188000040014008000000004004000000005012D09A038051822721D06204108892521914088034218542012B1A
+:806380008622224E228324048C024D41491148840219041C820211282A149A852921C48A20088D84481848CE146085B0F20730821228121323D1816513471830B84A2149F21821AC2188A14118524E1883282812081E8887222621A4214622B51208841289BD429212449878200884BC34842381C14586048A44E144B22807244285828360
+:806400006124188D11D034325413E6820460829953281C21F4A2121889B31822A868848CB2187828D516334126642483B1416184941289D412921244A3D1243214201A92C9442328755461444F2C81E49124F734280012290125F2112480F428118260891892241B4124822021A442428E428304008004841222422908222898482268880E
+:806480001B49A048818424828D1400822008418FC80748204218721104C4418C52228A140850814400902826084800814142988028812919044112221A9484118B14E024A9414621018008884B4A81121822BF6D0744123741411D1C83624138A188913C2111B48481A1128C6B8187184D411411B08426843518C143649118CC722602A6DB
+:80650000011B82211F48952A1C94E226E18601A081C314E561964C6AE1A30441412628743E0E44121D14848113214148CCA8913B84812029B1140250184B4200424B48B048419C4C1E44A0183886028A021918F284122A71C4011CE18483A9411B8141513A44A4426E88CE2484412E18288FCC084290224427518742414C1302212C811174
+:80658000145481B038981882941782148082041220D88101E41E2492519024121C6684B0836686602420E4810444A98C8111128401485F910A89021F42048400142118842F12C144228D12812E1A4196C944363A4840B952889242888001C140818232288C34184023467522487482CC11A028444044024606495184F0E8BC40014822882B
+:8066000023E221424448840285641143A21241840024D04102812B14941E84A2A0120014199548218A04306220128145342848298201892804282A01182D12AFBA0612001192118484001C1108A400C0111008004200008C042085C1242400242852804188848803A0418904213098004280F8572FC01110641216088C4101902135886456
+:80668000B124228D14CCE118D14824210446C2882D2248128212128741184C92612D4222A48322714223D31CD282324429CB29482B41CC052124836842E044311C86F2D6A8200A260124196222C4A11694181A12088D1416C82211819028845C528142488511B448022848001222802821842204462119280182008D84481848290300FFAA
+:80670000FE4B81414884024781154409849100842062818C0184412249182A0454901C5CB4214131481428481844194184C244604412441C118124A424412A34444911841114FAF8BB2414421312542E801244212811C81218414001881742832511D841249818814C822C2258481883048880092094814A018E281430222308188C2408D1
+:80678000240020F256352486C223241502281A024183028140240100144041745801142A04141954584444411644444484088C145181234598110030454C8134124228811200448744200148008954181098823413121842029022C901218344047012344848003042008542D821D24854A4151444D414321646C4584CF1411200444144CC
+:806800004921449A144C015F5E022450211428148484808102400120321813921113861141984144904884C0442011C84419480411103442144A41854402E4322A4102C01248008D41EF1D079481204484014001908185149834190811C0828411381D444100828200003028D0828404834AB1886262838A529240880144211A024144304E
+:8068800018223F73024A429564264408414C121211481481222813140428444490228942E142284284322818C122148440031827841008A1800C4081688210388218860844BFBD0E2008482028018381A181298A01908217892082296B8428C0884621141121DC8121248226486818111886E18822C2888E214824484C1409A04227412A4E
+:806900008504491488F1AD5AD08422924290A1260419012D2622442D8128315351423D228E1425041C12024991282E812524518242992118D6227444592848C6A61621100280514118385B42204102251808212417569024AE6E27422712CD864FC3DB51538818357C229321C721254882731D342F1E351D22CDA91F81771841E4D6E452DB
+:80698000924D9C7494C9615D781355C42B225F225641854AE978E117A222A632426AB491524A46F1413127114B244F21B24AB224A4211EC8812D4814448F6B44731131821CD26444185888471135B928AB918F884839183AB9A688E89152828F48B913417181D41594848D1826F4252413F446842653488B38CF4464883C74E5D161914D05
+:806A00009F4878CFFC4B254D7C2FC9796CF411111F21C944CE144CE142F534582F44B144E524F114184C598C83D36B042F22551955B241F222211334341D248526D9897222919315545617112FB281F1A58247136E44C7464FA2776A7889B255E49432C28DD497828F45D8942565B187446B8C4CB18628D1A6C5414DC8973BCD212D594E18
+:806A80004A48A721DD483F13A484649A72225E4E2D4443E141D1A6F6B23B00410050124823024523482249026482641028082044224422440224422094829082842988C48248888C8408888CC4824888C082C0849088A0848F5D061F6E66F2355775E7EA5FF6EEC6F5745FAF83F2111BDF91F1181897DA7D184B981D15CB18DF3858ACFFD6
+:806B0000D3F28E1BCF12F641492FA7F6AFAC6E4DA5FD468EEF39F194F637F137A1CF4FFF6E4DBD45456445A781FFC1FC7868DFC4F64BA8DD8F2D11476F7B198D198F4EFD9D114F2DD366F2DADAE7EA237C4CEC8DFDC4CC8F89791EBE7E43F271762F72567775F7666E4FE2F25C5CCFF5F53A289E18D7F19F81F1292D5D184F28EB41F11D3E
+:806B8000191F5848F63735FFD1F52F615F54F6627A7FF8FC829CBD4DFFE4F89F164F5BFF5C4C1FE1F5E8E4EFC656C55F44FC15455F41F815145F55F4454E75F4777F2F31F7D2263F5DF5C8899BBDDF69F1D7366F6AFDAE9CEFCEF1FC1CCFCCF9CCD6CD14CCD1AEF1A9A8243F63D277D4775267E7887FDFF62D3F6FD3E183F227AFBFDAFA84
+:806C00002AAA3F985AA32B993D966F1AFBB6A7EFBAFA3EBFEF5DF93F659F94F4E9F8DFAAFA62ECC5FE444ECFDFFF8EACDFD3F2544FCFCE7E6EFE87EF4F6EF6B4F6FFB9F19F8F8F8FF68BEDFF8CFABDBD5F4CF17586BFC1F48BDBAF84F71E962F25F596B45E56EFE3F85A2CCF89E985F54E4CCFC1F1ECFEFFA944F2B2266F72D277F227268E
+:806C8000EF86F63F28DFE3F3161DDFF3F2AFAEBFBAFA83ABFFB85AEF6F6BF9A7B6EFFBFBAFAFBFFAF8BFBF7F5FFD25655F76F6A9ABBF98FC55CDDD4FDFFCF4FDF56F5EFE7D7F6FF1F5ECE4EFE6F287A67F6EFEB7B7FFE9F99F9F2F6DFDE3E77F5CF4F5F51F6FFF7BB7BF95754BBBDBF95FD77F77F436744F4FFF6E9CEFC7F71C5CEF4DFDEB
+:806D00008E9CCD1ECFEEBE9D0E1C0126014501181200001440148122411211088F44024C125148118B2419A12400224001144041682284144800141A4401405828200481F037C7101211423422004424128928D122081882A184AD114388A1414641A8A42280748854841034184D428249249182863822484A28392870480100441AB442C2
+:806D8000024A33140040F161D6C0421F4152281F4932481F41324A1D24AB141D24AB941B21AB9451AF143924AF143924AF147924D812F9A4484E915FA2E414F8244A56F1244A96E1A2645D2ECADE24ACF491242CF4912485F2912C83F49164A7141F48B64AD1C1B64AB911B24A9945AB944B42AB9443B2427924D842F93448984FA2F42748
+:806E00006FD0A4F4116485F21124429E2C21CCB26241F848941B214A7A84B84833248F5479A4E85431242D916F8AE414F1241A8F14F8249A5671246A192E4A875D2E8B56C4899F4D82F4916449F49124C19E64C5F1816469F111648F44F811648B825D6889B924F44A9443E34429D24AF936484CF8265AFFE60E84824800000000448082FE
+:806E8000010000002100000000400100000000000000280000000021705F0C28403A18C024A414848341021820A1282CC1181480C8412248A41422622485A125408881158162831D841978246242D0145C844A21081CE14104408842044C04F04EE49013826381921210E581E822A8488CA181848D5144851121781824E11462888D44A0D0
+:806F0000248C94188CD181A38285F224584A92A474AA51421948D82291411A3819328A54821699118A54834D184C82745864265A2269D3F0E27780628C848C0322918368888B14C188328321A1821693181C0117284681A24124871C12265818A7122A914981B04811614685D1251831226311E118413C44302111AB254C0181582225E278
+:806F800044E18201CF83072D11D0260129415424136122822C21119841441508828524A124867848048B249028581A8238486B124AB22459412F22092A4988D941A4821638648A941A1789189A4445C824488D2449A4348244F04D681012312800288100200600000000000000C0480042490124005022004488100229012D8240042921F9
+:80700000088051845024DF5D074A41D4326111A1344001105281A9814408251304301A50414B24288124442816064A12443414444C4214F43648199144423412204108A02864489E4423220488F0DBC380058901D0210200245029830100212504701208142A2402244D4800604441444941C42641B04211250C3410820121418241882021
+:80708000028504418F7D082155D832361125088411004A022624140811004002414301818088C2142984032484804442742428112414826141F0822800282721424F25081E422048F2D473904300128C21042100260880082126682283A11841842058282862488AC218412D1461000010C8442582140648183018847082226221A0188416
+:807100004248B01B010010012260128123011800C9C1184881106889008148008C0200E08824A221281241008160A1163822132284D422D1848422B1440226248202F0E7A800902100122281190211004220842801002228261104A4000084248044422201222200A210082141000018200444D05C4E120100A01622281D28238182014234
+:8071800089311283F6182289C1981E8C8C0213D22824E28214886A8164CC61A82272222D12164428822244EA818834114682414EA42829C21618A6848214044FDE024860121391184052810085012048C44888000080628844002B420040624400000047248425624126823228704822714802182A041283242204140000100810C111113D
+:807200004260241002000000004002002A042A2818644120180481000000000080084E1240140448C7F9242424D0A201421181858228191193418464AC02C0D8488A022A080025C24844165442423224414922C214276110E8847842522881A084848182200820A4412881DFDB4C02242C441228441151211158111012082400896C24822B
+:8072800020020088812E44442880014188411006002484440040088882002C6444003FBC0B85B84AA444890100841628D84458644F16E21236226426088041D22212A2191AE129A8882123041879889C248D1CA5F868444A3654AC0184AC8C44524C444B6A2E282288001E4240D62291225E188F7F09210021001822A10021002008810036
+:8073000000000080028100820000180080110224000082200400820041EFFC0D812598421C040020042F4418C42622890200008228212921A1128888004091111484818C25840400400882414C62226840082004504229F1AFB54028A544001002004084C82A882400184042120218800800284C4401400C480000222100258488028E4201
+:80738000400C400421F01BAD004880010000400489020000002421800188002141611441400C48C0140021004004890200001840120618BF9C0C24800121000021002160841008000010048002000000000040020046020086421808000000006E6D1038482004214002884514B4242232221800002421641A21210982001015115188817A
+:807400008B44CA6444220024004948B224A2226200819024242544E241D1D103188588944100122114C08285C484A022008400002121221A99882A0800405114205188A05400000044C44544A222304A88421014121292E224201182814202000088818C0400820082000080024800800841604100108201242490828184800100480000F8
+:807480004FCA0D0012242001000000002400000000800200266442101402001888D024012180080048800400800800BFAD012011120325A211408808908885082C111208A088284120022200442A52444F48090016249114407212225282292818FA888287244A2438428412224308001F964D622125A2111A91220022312486928A27A867
+:80750000248304C08812000000402882044524044441008A614110022146424202254828C812848D84A04488410077D510820134201152222C04C800422788828100000041A022282821C31202244034141820C8221684410290828800A14A9448201444444454447F7A0F6F22F212222AB11221B112012C512329F812131F31B189E98944
+:80758000F848888F18F4484842151981548985F844488F44F424444B244F4222E24202284556442AF222222F21A2129AA1812B99822C512229F812131F31B188E999F848888B488F8424E4840448855C884E482F3B056F2252222AA113122140512229D832F1111119FC91888F81F88841CA2464141501C48588F44844C5B444A226224433
+:8076000000255444286F62D222E822A1131AB8822828582229D832B11191819E888F81B888A44C428400848588F429D1000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000A3
+:807680000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000002C
+:8077000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000AB
+:80778000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000002B
+:807800000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000AA
+:8078800000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000002A
+:80790000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000A9
+:807980000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000029
+:807A000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000A8
+:807A8000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0028
+:807B00000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FA5
+:807B8000FE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000000000000000000066
+:807C0000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000000000000000A6
+:807C80000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000026
+:807D000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000A5
+:807D8000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000000025
+:807E00000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000A4
+:807E800000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000024
+:807F0000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000A3
+:807F80000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000023
+:8080000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000A2
+:80808000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000022
+:808100000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000A1
+:8081800000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000021
+:80820000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000A0
+:808280000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0020
+:8083000000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE4AE
+:808380000F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000000000000000000002
+:80840000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000009E
+:808480000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000000000001E
+:8085000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000444445144444544441404454444400451404000000000000000000000000000000000000F011E10000005044451444544400444445144F
+:808580005444444400000000000000000000000000000000000000E03705000040544441450400004400451454444100000000000000000000000000000000000000371300004054444504444554444140544441444445544441000000000000000000000000000000000000003F550F0000444514044450444140544445440445141404A8
+:80860000000000000000000000000000000000000000F08B1B00004054444141444554444140544441414514544400000000000000000000000000000000000000F0CCDA000000455444414441414140445444444444451404000000000000000000000000000000000000F06ED700000044455444455444450400444504100441000000FF
+:8086800000000000000000000000000000000000A728000000444145544444000044104454444400000000000000000000000000000000000000F0582E004E2114408A44AA422002828D14822CCA222444850292860892B02201809298304C4E844602428480D4A68D0422882220290242EC02E021622942821212BFC80E4E218941689435
+:808700001E418168842C66241C22A328444C548449E2A162439E22622921592A824E821E228A319A218B859281869868A034834108C18F4AF546182E4246F422142889318CA6944249D24A1726A283A3C1828D821F3F0380422814C1482004001282888A042827821E2820440812A083002383186844002302814002274420A1C230140070
+:8087800080CA244038342D12488110F82A65C06152002C05242052221C2238182052841014542282128AC18829882402001250488820A42118424309C31F46E2441222B928618848872480042218002D82FF83024008851108004848004C424422021880C222400200128A11381AC2200C001018384884A02400200244002864003082125E
+:80880000F0437C00111400C0688C0222200210046124A0811888001052222008B0180846C8482004000084002800502440943280288A818871C40A000000000000000000000000000000008200000000000020020000000000F0A813144212009031C49502901860882C05818942012121221100228081840230222800108801B88C4202A0
+:808880009088C21841922246084829B1249C144B12287F3F0F2221125D124845A8414B162A34248256A1416088114C04A3B9C181A1486022488C2424F412821D488F41EAC5D284C448A069A081211C522447116E14438E4201141254CD124481614B2400C2C3F4C17B14462221711481D484924C5D4A48419219B4888514429868348B18D8
+:808900001A84214801608242581AAC421AE8817422A424001008A0128CC342482028084CA181C9924A81242E442A1CB494C264B766200200211381A121222881122091881144403281212A04262284042450838D2443324884A0D2C0921226614865E141B224885218481C0154124470422441242144D866012210120110781128922121E1
+:8089800015384A004904843014008122E022140881248145228408204841148492141D6829082502008B14400425040000BE2B341826E1825128400224D082E59108121416582889A18423D42244882182982280842364424914887812144695219E248B1816E124611240B288C51852482486F4845822AA8174483244222E44708E468285
+:808A0000732142480224403822897492411818011012984216041226288A220212C0248344E424E84118544113CA1549D9410126C4612483182204604588418A139648612243023BAF00A0129100841341923184112B14C0184D4816A884D022440800212C6484228C441254284002002A18085E2216113882588C911248D082E8C1240206
+:808A800048800448248FCC4F0129B212064D18101CD84101BC224184524818881014542641194104284F8196888006812444518522460829C42200204408230200124200262A02189F7C061C021C044031224CC22281404AD41234228224441D92288D228A0284204182088429921283C4821028141202A0188042468434284901408401B5
+:808B000012254214A8122F2D0448000020411108188008400400804808484B2C0090232113014C02421841221D382C4314B812C281008C01211221108401801484F4FBBF601623B213024C41F11A244962B2B011522A304225E841280817214722837A280446E84826C26A813932283D1216F84422863644184922C2382E12222D8823E15E
+:808B8000124804564A3A14102261450089C24481625FC90E000081001598148481128811444012C4844024C811411860410029840281104102A512314244182880140A001840041812212244243FA70F102102704102460346D8846234C14221130542818821842082041813199224814304001888802809004AC1841888298188010018E7
+:808C000088214908F09CB7208411CC18142A0112A028218301828190182823410814888840120840232401448484441308008210023B480080C2941698148118A6221208FFB40ED028421238880028C041288344440183018B41460884529082488B2440981845C8148444464844140850484410480484888A44168411D22892848E144326
+:808C800002412CE4AF0A244418176240244814480422104C641225414161119645C111345C61111414141E8114244012D121185121131211914B1D14111B12111B12111919098081C228128C8441E83C0F133222112215423821629542180524004200008E438C488161122944A11814219CD482110411210088232AA81C132214A225421C
+:808D0000304300820041802D24B456080024102884010040044812008008809212288100C01400484E28830400200228C141182220A214248141412008484410F2FCAD144C4421024B21131216014D1380081612884888222288014082014124004004442120A88200818084821C4A084460882002228C0822F0B7FE804212C84242A02428
+:808D800081423048284608428156311816619284C08215A82812124284894104120044111211D4411514481581984182E04118D88441944490141A820DB7DD400848008484000044903800400512489A54428051188828002381784881485481444821100918C014224C11A1341100812A0142D06202D7FD50212E133783AD1AB7D18913F2
+:808E00007931137188DA81529845444298188D199727941FABF1C81A9B1C5CE9227A44B118721421F11A1189714C5D446F84744C1A555417488E9233588C41471D95F844243356981B82C871418FC159C4C3722CE463F354646B914363246F4601902885E212A2242FB664448C26B463756AE4212CF4DA5983E48434514D792A9D885B8199
+:808E800026789132113F228691112E82150A151218884CBA81D1160826C32595D388F45435F0941529EF35A7149ED75C098B111E188A13E482A16E8DA648CF544FE1461697244904512B234354884515A426854894161F310A3019141CE4110C27988CF84149A19F1815F4952F2B515ED81E24442505811D21A81B988E2C1D84241F11C550
+:808F0000A2133F88171942BF81728482C8265AB888A88885A454A11F87414144614126E14144C344144CC4938CA492482C88848884180441100463084110221822089221122011228108002400402208824008846088F04A34142C7225772CFA2D489F83F31D1FEFC3F33D258D18DFF1F99AB88F88FBA89C8D92EFC9FA8C8DDFD8F828292A
+:808F80005F58F83C3D1F91E1DAFA998D47793F1854DC5FD1E1B7F697859E8B3F59E88BF61494ECDC5BF181941F5D7911D213D949D159B819F129311B331F32FB9B981F18FBB1945F38B113A1198B19CBBACB118BDD1AF92C488B558F29FCEB717024F6547CCFA3B31C554CCFC2F628288B638D18CDC48FC898588F82D3CCFD88B8DF51D5A2
+:80900000DDF139615F5BFA353D5751BF56FF899D5F5BF385459F94F911195FD77F117111F991D59FDAF658948F94FC8D951D11DF9DFD31211D519FD8F9313595F575755F15F5B535DFD3F1F1F11F5FF755559F91F388149E14BE948B11CF4EFFD89CEF8AB43CB588F9132D144F66F411738FC1518BFFC4F4793BAF87F77921CFC475C9FB8F
+:809080006ACC8F87F25868CE12EFC57C4DFD5D5DDFDEFB31319F9BF3D5DD3F9EFF9D991F3AF3A7E51DC11F91F1717BFD15D5F7DB197EF98CE4A955931F59F891C51D933F12FA91815F18F85DD1DF12F231351F76FED3F51F1CFAD1F15F38F8979D4FC9F19C984BBA4F88B9F4FDBCF86F42EEC8EF28F9BCF3141F34F62F45BFF2F26B2BBF92
+:80910000B5F56F6FFFD6F65961DFF4F5DB5BBF96FCF8E88FA5F6CE5EAF86FDDDDDDFD4F5EDFD9F93F3B5BD1F99FDA9F9DF98F9A587BFBAFC5B495FD1F1F57FBFB1F19F8F7F79F53EFD4D4C5FE9F5878F3751DF59FC21333F3EFA9B8DDFDBF349CD5FD7F775737F77FFDBFD9F9DFBD5B37F75F9BB99CF49F99C98CFCBF9B4B84F4FED4FFF93
+:80918000BCD84F8AE92CF8CCDF200221100222840022000012008192832408A024001098144222838401490118B02449884908208204484008844C2288024A028F1806902181288716112314612415284428042B1445681417812840311150214048D121012414184002144013011100141F48123A8110918280014212441A84E838F4E3A7
+:80920000D6D034F41124CF32F11124CF34F11124EF34D141F26E131D24AF36D981F24A9351AF743924AF343B242F34F924482D914F82C4914FA2C4816FA2F418216FA264192FA2E459D2A2E449D2A2F491242D421F49522A1F49724AF29124A7241F48F24A121D24AF249921AF2419F54A9243F24A9243F24A924782A9F9244889F9244A05
+:80928000EF4A0DACB411F6281213B148B111B24A91218B1619B26249BC48CB28AB9443F248B143E254F924485CF326488DB54FA245F524C88F55F224429E252E4A8F59D294E418D2A4F581288CD541F6285217488B141F41322C1B4989F11164AF44F911248BB41B21AF4429F2489443AB144382B922C4944F22F5ADED00000000000044E2
+:8093000000000000001280018800004001400848280000004004890200000000F03724004422514094222200AA441808242032111C7212824D8898485C9441382216681F801182C214A0218D212A014692286483223448002524C1421E882052844323C23CE0810C2D262824284914D82424D18204852286A814484184228B489428421205
+:80938000282788008400424124000088818B214998441A08181226218861884100478882824A4841F2922124262484C22448A042299348E0AC9268A684612441811C612A812F291428E121748924AC122216E81409176130224160871D288C93184C9C281E84A3A214C3058642B498C2428B1870885484472AA2CB2112DF640F244C421237
+:8094000011441C06210010880480227248311128488826281401842022040012008820026304009021200141002882184840F265FEC012112228D0410219048041081A0400101AB1483881000042A4C042282E42004448C011282A01890123A429218224409144230489A14188128B24F0B2742026C2121691141822459A1446EB88A61414
+:80948000604856C11832893B813022906899242C74228844141884C9AA1AD2128943012741E061048C08848280682118A8B04AAB2810B4842418F47628A0422382C2211811502100AB2100884E11812884002B248641088800484420A2432328339458202122C212128C0887288888822119E144088C658848448A6184446F820918112C97
+:809500008111C4342287444391494AB84801490512182E929C48C188A0249C24C44289460A8C544288264A12211241311612431408238403001221222724A832128846840A4F4304432192482D2A8D468824C110D44221C218A698182224120046A21458814538122D48298E6184828184C3732201249E4882161A184824911C165C28A0A4
+:80958000211229428861818A722222381428EF3C0789041A1621A112849A221248440160428A411408281592842648A1843011882228142044011F88046840042E422002158401280028004E14244210F415394002411220381488488814842005818B484444812648182484420881414321422402482800284200222004628638484508D7
+:8096000023080086184828F411ABB01484B214F2231AECA41285961490841311C8189E4816B838582CC12082A6144D7881AC48A8412B421AF264181342C4684CC2411B2C2428A8E4608426A42181182225B818542C2484002E1423C8488446F4FD9F4002818001188C22461892210044A0841244848571840819E5444252188444204808CC
+:80968000AC81029098A014842602E04154181E48888021822A91188A9428824C21F26C6C1021880181161411882132211A12084440381B8144854461224712A024448B824AA214001618010000112150829931424921C8282100842100188416026FE4016822C59224242800262208835C248328E442C894421C2A03828E48A0188142169B
+:80970000011F828881080049A8248968C28C1AD4183284214F8813A1346321786281092E1800006024DFE807202831495081902410111C21419818118082F1411812111021128111A5124061882810811201405121A01266A1411440112141021840082842F03DA890121381060081D0486244484442440040046042260C8B4850422628C3
+:80978000044C18D442161C38242918EC1804982A880C88B04202008081016B12B82748426170170F40048012064181218448412130281423014002A221004272850422008301001E288480827241A81426084881188004201188921840E1374201220020312815088D8428830218202498411A0280744208000048221B148C21214841A895
+:809800002110116211830481001D34440084182288A0483032213F4E074AC2128C1424182191122082D4420949C456824C1438846490844426B44C981C1664489011004044444C025084A4518850240040110B810020012388FCEF97102258222688822213028011C218130427948382022E4180223148621C042061848386079018008032
+:809880000200200243011B21124228002068641A6C4686F81A6E40084848A084A043129440042881440013042E81182521C819221C1A52586141414D212929C228142E41421288885E2288114A420480614440624238222221F052F23426612BCD222E4886DA194129618183DA18D418941446F4441C6B8C4CF851345A387C4F41E8483461
+:80990000246B42CE414E2C45B144E983F46841428CB728F21A194D2645D42DD688A222A656282F2EB898F2A282972880C232121F116221166A8249F128821AB618E232C988EF250229E64811D244A2226B833E12FB122E363D882E162EA81AB48F65211F92F6442B2782D11D1585D214F888DA4E2949FA2D417E488F11D248F1172C4F32DE
+:8099800076747414E84818A12812171A1954811B8A8D64172499A2121D441197928283241A28C184184F4E28F8442482BF5B01521CE281714A014C9628CC16F844254E282B1D854E98488534988D41AE31682F12B239E214F2898487A2124CF3A3444F14A2989F41B188C8147038A18226A181C5FA18914F1152914F82ED95F5546C6F175F
+:809A0000E32F7514D4319152CB54182CB332E289C2126E581AF442429F1F47030041824F140863042D819082908210924129A241A113113811441522D4210115224822CC1282248224821C01244434443C081C082C88845A842C18541841814128AFCD42F356561E32AFC151C44E424F57F22E6E3F3247F856F7EF2EFEAA828FCCF54FCB60
+:809A8000EF65FF7FFEBAFBF6866FEBFB373C4FE9F975CC4FCAF8868EBFAAF82E1A7F21B511F812882FE8FCB7A5CFC3F236A46F73FBA3A11F73F372BEFFD8F884566F5AF9898BCF4BFBA4B68F99FF8477BAA1B38E819FB9F1D8398F86FABCBCCF6AFB2C384CF19C1C4F41A8BF8FC6FA79C1144D242F89F6282C4D448FA4F47CAFCFC2F62195
+:809B000071EFC7F73EB7AF4EBA38F16AF8FFF4FC5EFCCF47BFB2FBBEBF6FFBFB465C4F88F9D6CCCAFCB4F44FCAFC6CFAEFA3F738B82B6B6FE1F5E7B7FFDCFE9E24EFF3FAAFAF7F5BFBB475CFF1D1467828F885878BFB8FAAEF8CFDB476FE346AAE8A8FA8E119F528A8CFCAFABCA6CF83B385FA88A86D844F4EFC5CD8FF4241D165E423F75E
+:809B800016166F82F24C8EDFD3D68BF26129CF61F1FD75BF46AE328F24F3DD1DEF8D75EDF9692BDF46F6EFBDD7F6FFDAF8EFFD5F59F9EDFDDFDCF86DAB9F91F15F695FF5F2154C5FFBF6B6EDCFE17284F4A52F6F4BFB34748B221F39F2BFADAFBAFAFBF1BFBEFA9F4D3F35FD73751F1BF211A13F31F95A18CFCFE381F82E3A2F4A89A151E8
+:809C00006BE74F4BFBC8DA8F664DF33774AB3BCFE2B266724CFE1D6F1F23F36329CF67F7BD379FAEF4A2988FA4F7CD4FCFEEF46ECD9FBEFA39729F9FFB6C7FFFDAFBECFDDFDFFFA9FBEFF8F47F6BCF97F6FA691F35F495E66FC7FB546DCF21729DFE27AD4F41F33537BF3BFB3BB99F83F3AE2FEF4DFFEBBB7FCEFF7BFA3F17F3F1711BB1C4
+:809C80003F31B952F5FC3C1E88AFE2F2A2B48AFBD4D45EC4BAF8E8FAED11200222302200160820C248A041A0482882441200850400819028514AB224112802004541086012844008486081141A0412004A22A924821FD30A22C012C44112144422150C121004844664815C6A824484A84D484A4AE844C218448C150812451831241321020E
+:809D00008322784222A816B022011884A50181104288418848F2A54AC0531F41523C1F41724CF11124E7141D24AB141D24AF149921AF1419B54A3924AF143934AF147B34D81AF924481CF9244A4E854FA264114FA265192E4AD6C54A9E24ACF591242CF4912485F29124C7241F49724EF28124EF24D141F24A9219F24A9251AF24B924F4F9
+:809D80004A924782AF247924989A4F8284F9244A1F58082D481E64A5A221421F81326A28AB141F41D24A88B242DB84B24A3934A938142DA14333426383E982A5944F8228F42458922E48D645E948C2591FC882F5916489E449B248F18124AB148E64AB141E242B864CB2483B15A98AE44429F242B4224CB122C494ACF5874A402888040083
+:809E00000000000000000000210080080000140000000000004004280000000014F0C8740039132A721C429A2826E121341121301214442424C281C4A012C028418D441246C434788592ACF861211B848082118402303400228418488CC948421883088742C0485F19044322A8128E11E041222101608181C094487018C12C484E22130572
+:809E800000822880024100001386820314224D1A8412421C48981200808261928428184009EB6C5024E6E3812278143816A1262115D18451283296C44440314C8C64621F212401328634EC184E244CE14146388952902913AC25281641C42E004E2413482862421880C85817861283CA12265C181678EB012212B011028CA21212241221E8
+:809F0000001100AD12A2C0482002840000280063A228652224020022128112184022110842360810080080B42A0C008280080088000000000000000000000000000000000000000010010011400170E7054A241243945483448312C24849E11632118C289C68630218227C0A1A51844E44823484288B4116B8C31108442A7A4232158D1C2E
+:809F80008A88E234247242D84C04141B1280688169A16220C2A6E08191482F550A1012E5C1914860144C0245B842A61334846D8483818124F222828E35848B8513C845D02462916A914811234898184CA684323118228F44D2184C48341429C141172290865E4C90142E84F08812E081BAC4F4DD1C0020088800800800000000000000000F
+:80A00000000000000000000000000000110010011400775E4042047024224152818116088281128542E824711488094C080040021944440A88E02228118202124592412210080020812901901882428002DFD70C274234181212473219614590821A761282C48A4B185881142D4445B811A6812245D1824404322932321AA6212289614800
+:80A080001C73828431221B382C81C1324C82343116A31C942443E483E86411B418E441C85846B82CF4313F246C42941230241D141227C4908232291982C984278183D1A6811C8C2228429448001E43248D22A0186028822D2282181AA2292422D0420219019A148199141E88124CE188044AC1682674220B400118182312931184162804CE
+:80A100008314981A4242144C014E951210111214829224181A862232381694114C0221741325814328843211218941822472441228E144190846F837D410021123C248C1A4260220D148814528028442230112290490220042284216144848515842488128C08430147018023014619012A0210048212272BD69C024284614E44142C2145D
+:80A18000C02848844C04200241007022584249911843942492288200421D8490282848200122808221840249826481608181842608211216F8346D20210183010020042228888051284860888D441492840040480410012844800132008400A302A0122100224334441260818100AFC40F6903302E686416042F84222491188A118811987D
+:80A200004430828D442528D48441B824048361428A22D441C14822441442303818902CB014921A8981E2228131468429C258CB528C21628184382A74BB0AA0214521911C848582023028684200108A9418C0314309241843024800008748C0242A0180028200224821008021410440280440F854C60022451104240014841482250416880B
+:80A28000622812189022181822002912C41825820241138282042C120828904822288041440481450200414982056E7C2024618321811C722982024B2122901850249048222125C4141446248186A2412E124440A22452421229014561252A84C88445B2440158828A81644842186A6184A01818244CF4E4BD002081C244442C2211081E25
+:80A30000481382122808120020884448C818488044C1644138801216712408498458145820221401218211824220A1244810A4188DCB604221410080043C65240014704481048F48A548AA044C419484490C4914012001280080A128222C22018C0264811C8144224544284418049AD482086C03821222811100A400260816941124201179
+:80A38000220212801182C268182A041C2C644428A0122902341831002E424826024860212C01004220222264146F150B002146018425081289C81218214182322240C214A254100824701212311A1C1102411C24810222122E1A8058412D11844414214058422043088132F0A1A3104281342230462022C4111422008445022800D184C87F
+:80A400004B24002841260428002C44440C188501471CDBA4441844436418234464C8308845C884380010F4C31D902243528281668802842688622412842094188C0223230140220844442521322144444441A0841800C200160180011682812481818A2224818418E8994EC14C21484141488041622440C4413812484882821B282148254E
+:80A4800001CC098880656142821482C028118C0594C021001211C486A1284004A4006286D4C282F83A95246823D92632245F4254242D411287866BD41B21272A1061A1288F822112A2A82E284E1C1A55484B4A2692425B32645E651441381C6E42484B211F29B324F669214F44EA4CA44C112484B0C3E421194CD448B868B21681634468F3
+:80A500004691C27F9B036556418F81C12C87848752AC92283F2171396A841CF31829184F4CF132582B6416E22AFD451647411E414734278242414F26213158182F41F362646226D224B31232218712AD182BC1BAF12C211E281A21B114E538E121E948847D1428E188D488A642BAF1D41CCF826AA49F9D04622E3226354BB04236282F827A
+:80A58000C14128AF3225F14714C391C9436429AF4CAB2123F3829151CCB884DFC8EA84E641F242477F1273A7FA64421A584447443B411F46991841172582B5B113782DF666647F46734BF151885461374DA9DCA635146A68C4682AE849F58414CF3A0B7024014302450134C08184884007248082442408114C0244C024B0881221088214F5
+:80A60000C214864C414C4208404108404108822410084210F89A93344F24343215D464D65372445712388B668F88B8C5FC1AAA2F675C337FBCFA7656AFA6F4B2922BDD6F7FFDC5D3DD1C4B982F42BC8CF868762F24F146F7E57A43F2B2965F44FC84244F68F48DA35F51A831CF91F394D28DA9DFD9BBDD7D45F3C2F235F7474BAD8A27146C
+:80A680007D15FF78FF8A8C4AF5E65CEF4A594445F44C884F4AFC1CC2AFA344E324B642F72F141D67FFF472467722CB312E71A5FAE3D6BFB1FA7BEF25F2C2D84F47F5684AAFAFFDD2F24F3FFDDDDDE5FC94C4EFCBFD84E48FACFD42126F66FDBA8E6F2EFA96963F5379A4E41AF6DCCE3F15FC84DCCF29FB1ED22F29F197B4DBFDDF36F6C7D6
+:80A70000F32D166FF1D1AAF872A175F583F36F68F846546F4CB5C2FD64644F61F58EC84B9B6F25FD89FB3445F637455D2AED2E7F74F26F2FBD23A9B368F738189FEDFFDA6A2B6DDFD9F98D8FEF64F74A48AFABBA92F984B73F5DFF4F5DCFD8F9ACDCCF4EF86CC66F63F5477375FFDAD73F53E91D85C6C27FB1FAD74519F7B9B59F1BFB7DAB
+:80A78000FC8F99F3FDFAB7352F2DFD3737BFD4F4191B3F14F34715FFF4FDDA845AF1E626EFCDFD381C2E44EF84F5A89CCD1E6F2746E346F63575FFE3F34F2BBFF4F26F2FBFB2D239F36B7BBFBAF86B7BBFADF6CF68DFD9F9C8DCEF67F76A4AAFAAFAD2722F7FFFFF7DDFD4F595D78FCABDA4FA7CEA6F46F7E3757FF3F27B773F73FFB27192
+:80A800002AF621E25FF3AA6FDF52F3193FBFB7FBFF7F2F2DFFCFEAFFB3F2B7B15F72F35B5C9FB5B5527354F4FEDAAFADF8D6D46F6EF6F2B88FC7E341F5ACF88FAEFD44DA5FFE0621B0260127222062812284262201001648E289843281850444E044024A92124421B0260122422901001840817424210112002448448E484480220982DFB4
+:80A880003702822885421844480125221108811240880280D41283B44801890820022A2184211404220028181AE62268411448811914A241449018414A034C83E44442F1984CE022F41124C7221F41324C1F41724AD141B64ED141B24AD981B24A19B54A39A4AF1439242F54FBA4482D954F82C4914FA2C4A54FA264114FA2E459E2A2E4C4
+:80A9000059C24A9E24ACF5D1244D421F49522C1F49324C1F49324A1F48B24AD141B24AD981B24A19B54A3924AB9443B24279A4B842F92448984FA2F4189BE0B2A44187221FC152181E2CA11E24818E244CF18168AD311F88D21A31A48F1411D412FBA4482D11678A1CF1245A1CEBA2EC11D8A5A4214D8A1E25BCEC41C2DB5E2C4DC319B61B
+:80A980002CB911B46C389183F41124AB944CE254D1C1F24A3249F24A1143B34A31244A39342B146782984F22F5B4EF000000000000000000200200210000000040012200000000004005280040080000F0E1CF00218322D28492188124281069818418248C541A184D21184381122806004CC2A11D4842184E282C6442408661182A21A696
+:80AA000084184A08E011CC118524011892284C2581E24413F48B5B008E22240015220612382A0112422D481E2141221826110248101888669412286C82084302D6868308434844A82425A2481128809141493248224604CCB44441A1488D7C4022942829922C8C5182A012224549A81248A93423D4125C82711282C2481A14688848266423
+:80AA80001B139664118C04E362254F2522C1811EA42A84EC26612C4A58144EA12E154D181C3524002A2465A55AE242B114F41BA70028210011621022A112128112E081142282312144002200281D4840082989B2240449088800448100001200008B14B2444144414282EFF4062E122840480210012821001608844A0242122884E0820459
+:80AB0000002342810448830C282444004302892909824212200884880048004226F825DD006028284F8291281887211743846812181C88E4285448CF2821C24A8921A4217024288202422263114846341444328D2484566882281D48157854C818831438182384898162458842721688F4739D20820289D2282302139124842081810983FD
+:80AB800028A4182A04224820C6282830221428414288444942942426145848262869889449A8141A44C89821002843014232488CF4F2D960212018124488512813819262009442486782451892582781811A424804228064241281CC1422418241086A018CB241018345180880B4188809484A08421628F29DC5242081026081403544413D
+:80AC0000530229C11C22845830842A4118228202208841C8188024348818486C01891404E2264228082440B814068441890889B14202125B24006084830114200283518481202422164224622428214C04D014231A88C124281018229228481982A2148504A04948196182414F149128800528560C2141123FA20C10544110140424320081
+:80AC80003840130844800160840022004904001218C0420080012A3118214004888100A301421822288122C2BF3206214419C218609180F2324487418C0229E1741168821614A41A6A2122B424042244C018E0C12222C112847229C216288B214E14CB128429F29248C21981185A9442848B41B088C24C8CA14280F84E872028110C4144AD
+:80AD0000504100141E28400848230444104A08223021284934180048838408484001006A0940048C021AD46821014984218342C82448AC0568328082428432248312046A6141A4004822882822A24868608240028042829A842248508421800280810118124400842E1418504823A241425F7C4E4242522412C40050126018822148816063
+:80AD8000894423022120424684C4282A840C8889644468408402448D86128840064240024915240483422848542A45F847DC200840246288214024148205444014022885040081284484805228000000440000828C4288284168825082008400425024229FC2464241568410A43445280422C4800480420444004184A048245084122A4454
+:80AE000008D0684204C084A841448304424614888824044218524724439A1C8C14AA18CF9704286081810040011CA281888440092E9800842E82002184008A42A84828848100200100830942801128140826028308222480840CBFBD0C002C02A0211A02128748842290281A74280428008038628C220862004146142444A886C08481888C
+:80AE8000423014444400008C598489012081042222F09D866044002821888449020060441364480085344800004B8441224C18A448800800414B48008188109892508448122941043012448618840112F08D1B0092188502800100102809200881818A02482420344800224908100848880010084984E481840480C448481E48482E48487F
+:80AF00004824434121F4F714408CA2423088004008224423C2241038261042143224230838444A8844682246C84614460284C042840020018412460C1A820141103481828022F8AEC28024D88881E28AB2C4C1185D228F92714142A822ABD1811528D842D6A472C63888214F4AE282F46A6C2E48628CF4C4442F88E122BC4AE6A494CACD1E
+:80AF80008A488843718C32288612E888342885688430488446C658A7C41AF448348D689B2427481E644F31B182D2E2072322BA32722212EE21B2284244146C58866A425FC4B444F128228F8B1118E842C222C8A8418E84CD646B26818BC44684486486226972842448FC84884F84A8124E842B194E164D945A85A914CD1852184245B8349D
+:80B00000F984441A316C8F14A884ED67245F44F2163245D68C4134281624062EA48B925A3D44248958C44968422A52A42A084682B8464218A8222AB28C62CAC1414E64E6A444260421853494C3E144B414B41854881E48AF21A6C1C7421AD4CAA943469482CDCA212E688D541F150F460444402444641460144062881440022440022008A0
+:80B0800010080010022908218008219082108294821229888488C482004062814284E07D46F241454741CD2A2D4EA5FC2434CFC4A444DFC1F1A4849F8DCD522B5EDF54F494BCCE46EFC9F924266F4466282B884F447488F8264445544447424F46EE82FAC4AE6F42F24C4A6B888F6CFCA2444F48F8541845F68EC44F64D464F84C4C4E427F
+:80B100002F2DF9C8D28A487262B4C2BDCAFB48462F49CD348F48FBD5984F89F94C7CCF48F984883F1541F346624F25F6282EEFE2B646B464F768484742DFC5A5CE9FC1652C2B6E4F44F49C9CCF6CF696B44F62F24E64A6B2A2F86664824F4FFD8C8C4F4AFB2C2CCFC2AEEA4F2EFA262C5D436F88F888A3ED2C4BCC4F85F58C8E6F48F44C7F
+:80B180004E4F69794CFA4242AFE8C956CFCDFDD8DA2F48DB86B58EC9448FCDFD48244FEDFFDFDC8B99CF42F3A4DEEFE9FD7DA7247F36F424728D3E8D2AE5B874F67868DD2D5F41F3E5E59F6DDD2AFEDAF8DF54F49C9E6F6FFFBE96AF22F2466EEFEAB282BA62F4E868CD5CCFC4F428C826E886F6A48C4FEEFEA6A6AFB4F48242AFA8F4A20A
+:80B200004A6F4CFC145464AF68F8CEC8EF88F8C4C62B444BDDAB448F6CBC82F85878AB44AF4CFDC8C22B546E4CCF4DEDACB89AF96E444FCFF9C4D4DF1A4DF362463E72CF81F3482C8D2C8F83F33C3C9F96F61938DFDAFA99D2AF2DFB9AF89F94F49D9F6F2FFFBE9EEFE2F24E4EEFEAB282AACE8F8AFA685CCFCCA8834FC6E48AF68CECCFB3
+:80B28000ACFEE6EEED4F6FECF4EB6A6FE2B2C6BC9CFD888AA7ACEFCCF48684C5F8184AEFCDFDDADC8F65F15A18CF84F5DED8EFE4F5D2CAAF85F5686C4FADFFCECE2F8DF564448F2FF944DE9BE820021884400884410016084820C824844C22C824A02470480483048D24414A1234480088000084411E4841486081C04844846081288220A0
+:80B3000001F0CC8AA0483022302212902122150828211150842D14100A21406482422200422C08A4C0824C9244502C10041810081848202124714214642443012A4484F4DA52D024F51124C5F21124CF24F11124E7241D24AF24D141F24A9219F24A9251AF243924AF34B9A4F4429347822D914F82C4914FA2D418F8264A16F1264A96F199
+:80B38000225A96F5224A9E242DCA1F49F222421F497228F29124A3F69124A3F68124AB141F41B64A9921AF249945AB944B42AB9443B24A7934B84AFB244889F9A44A1FB2096D1B1F41F62C421F41D22CF11164C7221E6485E34156581D64AF24E38152584B42AD114B4A2D114F82F442916F82C4914F82D518B122EC51F2264886F1265AA5
+:80B4000016E1B26451ACFC912C2E4A1D448F22F5112487261F41766A5241AD921F49764AF68124A9B385D628B1A4B44831A4AF247114B8487AA4981AAE5A5F270B00000000004004000000110000000000204801000000000020614200000000002501FA078A032D2823A2122092282418A39C429814848368414792C82741424658484840
+:80B4800042008C44D8A2243122224781242C4264222863A224A222193882844223A4418AA441445832892483F118244E24AF184842A128190821364241014218181548040020020022228440086800400800280083081584284308A11200E09811182212246414F07D26B013E224D228C2221A022D2193022D121EC24287530088497128F9
+:80B5000025361646223424328C2408837428628421399228831158224B242C022D2C488A22BA81135A848D422A81A14812438101621218CD512F41F64B97006018001A0200488112885181840088008481480081200412004120028082885214008224208404488D818C9432844C8284024F2A052400002810010000000000000022000050
+:80B58000008644028400280000008012820200802112020010F455EB8041042220012C0200004898004448220000002122200248280000880038408205400211890400180022001FE90B100228A01290210000008A01002002002200210028430840080088001A02206122800214001228210000449FE108184400004002000042004024E7
+:80B6000004000000800200482302002200004082044002C0480080018002D0E70300000000228002100840280200000000000000000028100400120020010000282001848497EF400428A43022482021648800290841008E4884904440414A013028103218008002000000000080898488210448428800B5060041301400218489024A11EE
+:80B6800048028410080000840010240100602900504280012081022004000000824100F048DC10044C024C11821422C328A2188181008122480043048551281100830100E028012810044C0180810200188880280128824C0181F077E500008421280081488148248221450884894808000000412824C0180000302200008001800412420C
+:80B7000000488024240884EFBE0D0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F8004000000400428000000002180018800004001400848000000004480020000001002183F5F0B0000000000000000000000000000C0
+:80B78000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000EB
+:80B800000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000006A
+:80B8800000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0010210200000000000000000000000020020021000000001008240000000000D0DC0E40023011A021008C1101800100894108008440084100142400008601284004001100210080048A
+:80B9000040040000CBEF24106442A440081214002508206198001041880820140813014341880A1E8400241C88C21140244104003012101224018004004F2E054004C011202211C11814001818008911080084104818840145418A02001C0829224204001504240000484440040000BF7B0221302684218418004042080017880010112801
+:80B9800008200410011880084909001C081C01411200002412240012004200F06C1100121011121118410218C0828481800120C3240041811018149814202204001004141A0416240400A9411848180200A042009FA50C235221161268A187212A91188B211611C812841810187811984844841C91482E814280072E142B282AB414688106
+:80BA00009A86041218414226E8A1E2A4028D522812141002844E288D248D148C084B4348EB4F8032111053228721388485021812100284D018C1481AC22C00138204848093166832168802803114411483C12A2E18A014008501814028149C1883082848BFCD08213012848311113811321911082D888311088C01100413914849480872B9
+:80BA80004185A4829084485A8804002024266144234438221229410A8121262812042A9454E0D3032301C312480860419C1104C4328130288608114C02212AB14401A8452A81524838424C61D15129935888008C21C1144698148014E48184A121420083231116A4213F57031002230120020012448880021084018392428041882801000F
+:80BB00001008142014081A241444082541C81881490241000080346A6085BFAF07008002000000180016082C01406811008048084312020028224800004488608280021481104812684116080012881FC74182116262810028128C011088018184831826D1482223044883C828C42E16284508844981924129850118418E1C8449C2491E85
+:80BB80002889D18114688544322984C118381248188CFC9CD40048811A12084044418421814888218201145018801304201102A02148284D1844228008428061812144000089018141402874244824F2CEB3002321628681192201008412400410048011D814B288442888981814830423415882463142800240041840084022414888826A
+:80BC0000041249011210F8CAAA00E0211401004008125048001800108148888304002001422008CC4324882224140484A02828128180253428008441482212EF2D01002A818401848C012280280883123414841C418C02112A984800811138288AE442211B811634881F44212181C144002822100412280080913480F2FD25001008242C15
+:80BC800005804141428201988881007014010026E182D4923842C04C86184211086113C142288160C42C8243C25A44002180E12112A421482001BBE12028041121901100118C0141888A01888001801188019012921A041241874245880412C352424283046302222110165C424200295248284302144FCB014082248222022011088D14B8
+:80BD00008200830100518D42138216822102111528248441111121011C214181026041811289011200800480012C21F286EF00002111114200121120A1210000800342142008C800202864181014C1814811008382819412814C8408428448650840042142FD7F2450228112918410082A11048192848D841200E011123812A34288048BB7
+:80BD800058504845C81180220249420515A8484148CC528442284518911C1618A81449012848002FD10984800422165218288481146C088902101808208411828C41841C021820483186181E48A048281845A8248E1224122497441828002C61822222002144BFC40C2486429A41222F11331380F139281E18A12748181A3118430112410D
+:80BE00009B411AF32929281B42C3D628359383052FCD5C41ED8439F2422F4213FA142C4F41C2184F8C62862B6C897388945A4E382781DD1CE56481B06CB426A1134B524F47E13181F599741082911A5633182446C91887811445E128D88C01AAD8C4C81884113665B61D4142CA88887853C8C11D184945A2892AF1C88C1392241E111B8A57
+:80BE80001F149141448F4175347256EEA262A729C494244E1889F6182A164A94241A022828BF820F30423AF222281D2917868991288011A9111AE8C958888AD148188891194B3887C29E52AF837488C862F048181CF4582C8B128B548E2847134B511F41D5445A382B42C715899524CC21B212817239120C1AA4146A95321A52C8446830CB
+:80BF00002C2F240800842641480100006088000020811231481311282884111891284D92C08200C081841400480049082C48482241044400120044130E25C2122F22F31B511CF24943A5F168688F825211D5C9122F4219D888F18C888B911E180047D44FC777657C12B828F2CC462FA2D382F811482E68CB6ADF44F5A2286712CF67F656FB
+:80BF80004417C4C5BC31325C8BAAC5FCFCCEEF2675BEFA9212B732AB9995B148F61C34CFE4F71E1A211E144F45A5334D342B67BF170825A2552F23F33B311F177719F111116E683AD311F1111586B2A212E881BB84B988E881011AD19153DE4FD4F1FA388F8ADAECF8326AA79116F9287AAFA3FA4AD92F82FA2E8AEFC6F661611BD9DDA8B2
+:80C000001B63D3B5B8FE1C6EEFEBFC6E7ACFABF29A1EBF36F2AABC9F11D18CF23C3CCFE6F77A1E2B32226E722B774D342B77EFF849F212122F21F51A3ABF11D1B9F27B7195F978788B229F1353D924AF81BB98F888988F89F9149C1E181A51118F95F172799F96E482FF28A8CFE6DEAAF142499F91F4144AEFE8F56A79BE32CF81F1557FC1
+:80C080006F44F4B5758FB9F13B39C755CF4FFB545AEFEFFE5642EFE3F87A6E3F3ABA1A53B92F85A1378FA7F77C7E23F13C385AB562A6324B76EFFC46F212122B51AFA1F31B33BFB7771BF31B198F87F738389F92F3181BAF89F998B883F13898CF48F98C848B111AA1339F96F358598FB6F7E8788F8EFE6C6EAFA1F558598795CF87F7F894
+:80C10000FC8F8EEF2AFAAC8E7FD7F771311BBB9FA2FA7B28D745CFCFFF547EEFEEFF4676EFE3FB7A783F3FDB8EF3191B2F87A5768F26F77E1E2B33CFC3F164742B772E324B76DF3A01002901400884220000160812002011381146042810088394148384012084010021481884402862814048E48184825448200428F07D27308210D88119
+:80C18000B22A3111211A1418911892218489084C4888115418431228286482830585018A12B498224244F1912443721108167864028B1212258204842D1400269812478310C41426F1D887C0421F417228F2112C87141FC1724AD141B24AD141B24AB981B24A5985AF443924AF143935AF1479A5D81AF9B5488D915FAAE414F8254A87110E
+:80C200005FA27598E1A2E459D2A2ED4DD2A2FC91242D421F49D238F8912C87141F49324A1F48B64AD141F24A9219F24A925781AB9443B24A39242B94478329F9244889F9244A6D9EC04A1F416622164CE1C1726AF11124AB141D24AF4499212BB415B84A3924AF143134AB8445D81A29938A4F22A5144F821CF826D283C9428E21BCE54D17
+:80C2800042FB912CACF411642CF1912C833611A3D441961A19F64A1619E224F315288B8443B24A29B242793498926F82A4942E5AFF53040048000000000000100400002100000010080000001100000040042800000000004DD7002721A4004048018021181854848C61818C9288C12032388C8612887148242182081A22031A4214D12491
+:80C300001864818346E464110433DC8144684130488034148440B484F2746380220818191408504882112D181A384820120118823089144482114D21128926A42583144CE4143A81198882C1214E834D8166035E21832C021446A84249822288022814815F1C04262254281819040085045721882AC148452853818382190C118C7172A4A0
+:80C380002886781164C47688A61A1D4832288F18B211F84481281642E41419685664465524AE418F125418C924C24828824B21A428419AF24C17001221008481112008169888414088018182608A1C4208112818004250484921240214866412846F16082B141AB248080018484C0242000045F8365C0044211A1208A041008100100214A8
+:80C400001210812201110081002A28C59881002601A02189C128148A14C248A11914924189082083010038F0633620111218821318122911BC82E382981889041644488631388304CB2D207C68342100484338222E442E8C4160114D1841448AA46883925C1212238191124D418C24C848C32AE1438441C8A43B252001A432834302468155
+:80C4800041B8A2A182128100841890182A84614114C04C81004A4224C34828902118E04142382813A4244588D12A61111221414860818922810384418F18022464001008160844818184482149411194121C12088BA4A08422130280E82C318843728844041187416041C8A8863852830442211B419C1C882896943044121AA2822F2C0B38
+:80C5000045C212488024621426451424624240220180210288452A924816822882B26141028162141F413241449D34260C00419416B81822932444442800822644882C22F5BD672081922816C8288100124042C411C1228D22848534144D28C440088CC9A81E421082221202140083820C4C34248100008394241818D0840400108221F1D5
+:80C58000A8C80000221210088400840081204142092A8142240840914810884144B428840400201202260841194C0121890C296184002AA12144D08E09182913081E282894174244412C429811C1842602C7212E188CB2A8C1244598888827821A746A6215872218852412B831944143F291284D282A644284418551489836482281244206
+:80C600009848824982A1842624D47F0E414823E281224428048901800228294198184015445482284881C0218002282146A4424400415024008C021287161904418D94F042140090283218F0A32410024048C81881810040088CC148132201404418088B84848341D818C4288904112246011024384C1E4889024041D8141488041828126D
+:80C68000204124458481F4EEBC80C2242CC424168222824286284144822808100226084A1A1A040000221A0484841C112144982128174812C01230121554B2459842128C0400201132143F67060081000081260822608228000037816081112A018228843018184688CD14118044014A4104902C8110A812121C1108808424044A01F03235
+:80C70000348021011A24428C41044C32888C02204111190A1828200881238C28024449722248014B42210000188B421C9141933221002811C328A8212082820226F828DC208A820281200210085048888420C21116C12918848028A81228A62801128C1404200820A1811038414C944484814D28141212002081242246F97613001642089E
+:80C78000000018008009009C080000218001484248424440C8441820820280023018181800288302C1100412612596441F5A094141432112261194228022514200C02644444C084829127812448484088822001C0249C244244CD48182521890248002290289022A24382C2042048921F2B11A00212129110284200283080040088D322636
+:80C800008801602A1C04844A8128C414814301C388042002908442894164142084C51413C68C4684C4244480C42470950D848005282200818460429024882042018008218982418118022518011421114D2816D48414D4490419A8482812421D1480024212844AA941490821F0E75DC024BAD36A22D36831382E2881C0288F88289288604E
+:80C88000882A92861698AC8D242EC2813A3813418B16629F8E66848FC4B724A1442E247D411E76444D434912CC588F48021B6B228D318D481E681AC1191AF13CC88BC926C894621A84E193E742F1429D1042648121D084427426E822318C18C0281AB8185C9487B35135215188A6E9A8B284F488881B81813088234237888D188C58141C22
+:80C9000044B428E856F6D4241F9288D5D4D16D71517E516432C37415D219E64C01C30418472440E684F646FD60234582F1443A2F8282311828CD28221AD28AD2247184081119F22A131E182E191AA124818FC648C2681E4829A87143F158484F91137448346143AE21C41F81712891148F943A485E492AC431B9E1B254486688F2441C7834
+:80C980004B654F41E642F9746441C16F47080084184821442144218421842182211124100814C0212414241424403288248348220882004048014541180225012882000000F0B6CD50641247C14FE3F35C4E8F2755CCCFE2F21A3EAE2E4F8949F2929A4D16897924F68E8D6D2CCF49F929298F2CBDE8F481817FE4F46E6587183F17D72B14
+:80CA0000FCEBC2CF27F6DFC7BFACFCA6A28FBCF433323F1AFCB4B6A7885F51E29CFE516C87855FCBFA1C76DF42F24E42BFA3F67B51BB11AB318B848B228F47A3DF4F46A6CC4F45A5113E24B7FDF034366F6556E64FE1F5586ACF65F71812A5F21A3E8FE8F2949E2F22F2B2BE4D9689DB65F28BA8ACF38E9C8F81F1C9D3BF1CF489813FA4CF
+:80CA8000F56E67AF12FA7B71BF24F4BBC28B459D498FB2F6AEA2CF4CF4FDB81F36F4F6FC87489F58F844491FC5F67828CFDFFE5C6FCF16F27E799F82F64D6D3D11AF84754CF46C784F47B3F4FD2424AEB22F42F3685C8FC3F3A68D244F61F1346487812FA3F31C14AB138FA1B122F21C38EF8AEAEBBB22F298B8EF48D128F93E1C4FD9D96C
+:80CB0000E6F2969CDFD2F284843F9BF9D1D1CFD6F74446BBE69FA7F7686BFED16F877615FD787F4F47FF7AF85FD3F321413EF62BA21F11F2C1ED1E248F8FF2BDA48F23B729F26A7C9F13F251731F24F41D158BB73E347E34EAAA374BFB29A455CFC677494BF234366F61F63E3E6FE7F33838EFC3F31C342CF23E38EF8AFA989C2E22EF899B
+:80CB8000FB8E948F22F93F3D9F9BDBA8F29E9DCFC3F3FDF5AF8FBFF8FF6C6F6FC4FC49489FA7F7686B8F1FFC7E68DFFBFBBAFE4FC7FF72FC5FF7F3E7C7AF43FF2CACDFDBFA6D6D8F41F2F828DFDFFF79739F56F27B7FBF93F25D5B9FB4F44C54CF46FA6C7CCFC7B3F4FB24244BBA6F46F66474CFC2B3F605002302234228422822284208C7
+:80CC00000080421838118B241328143148B04812B1480281492824024D8100D014C9481CE8810484E08104484048044460446044F08CD1602A1604160C00104888086088508414535112002288458828621420B4240158E08258412A2418C8242E11130811421118117011684432881E48808421034579AA052CF4112485F2112CCB141F64
+:80CC800041324E1D24EB141F41B24AD981B24A7995B84AB925F44A9343F24A9147822D914F82C4914FA2C4814FA264114FA264192E4A8759ACF49824ACF4D1242CF5912485F3912483F49124EB141FC8F64A131D64AF34D981F24A9251AF14B9A4B44ABB24B442792498924F8284F9244A874DD0A2F511642CD4C1324C1B61CB141B21CBA6
+:80CD0000141B2146F411284AFB152889F834488F2411F44AB143D212F936481CF924581CFB24C816F124D816E1827498E512F498241CF5812C8CE149D628E14932481D246B128CF22E124CE266D9C1F248B251893994A931A42B34478A29F3264829F9245A1F87070020020000004480020000000080010000000000800400000040040054
+:80CD80000010080021F04AB5002881C018400884284012485884156828811821D01834142828226082A11028028C282201232848A8249C922C839411001B14453148280028004840FCC589301292222222830138491148021B8182130D93018631481F88821261841788A012214A386C1B148C8424C11546921180B382741224012E1244AA
+:80CE00008F34C311A49648A21446BA1C6C2546B44CC1846E1142BFF80BA016812812108822C12800274289D884459891A1131962289CD614618693AA183290C2411971218824D81861254E112388C5484B528962428B611D141782148757162484C6424B1418801504EB4127CD9012200283628120110C24D018091C181108C0488D2100AF
+:80CE80000022702218E882344848C0184C02008AD222081C4148024E121224178885221168884E224954488AA434F08B27000070220220011246011C019044181220286488000081109891B02421046022100429C1442A4838480082250100441E48000020F2D95780C32416091911445186D048288149C8951488841C7868324143C2414E
+:80CF000066DC18C26883A243144828363A4828806144221E218D216C98381B414886A214BC42489A1882442E582988A4C34926A2524CF48DB180429419242C4214711804C9C91118184C094C488869822914A4841008C04811489E21305400120053D12162614813CF488B48188722100B008F61B248898428828283F2ABF42021026011BC
+:80CF800040020042888541118184118164186215B84C322166C8282A0181703832282A04306429821288E8C2010023449188901A884148003A944420344457FA6041209212C0221824518305648AB1280128214A0228A22364829042888412428901288A44092883416D12C0E482904227410000411214004D12180018DF870F8160848916
+:80D00000524811100110C841151805216618012410AA14488E182A288642624219022564141B42233128684004830128422A08614C01448333448608282138F0DDB234241001428100122038184092548186041210041100004994A248701864A2326024441AC8184818222648190866088AC44826CA411228284160C4484D7714290117C7
+:80D080002232C43C0224113088B4137914C844816B841180624283B42801A9284228E728D248C6218D1247AA4A93612366428969114C84E28128C26B4D188AC222B044C94C4C327230A84C6241F04814F03754502410482844881191141E48441A9428112D122289A24218908260144842A02445228401432244082C217124C128E0492449
+:80D10000421882048C04001618B814041229022848AFC502148002190300802822D21409882006660800588283C4424603811012A884368122564222228B428A6182298856C1149048000000291404C84CF239BF002200848490321221914C01D081422141C1121C011440B3811108860214453AC426244432819045442CA12460411128B3
+:80D180003013101A3416231422022181008FB1061112808101002028291862184813840219489882481592880080226812112C082AE8840810290480641288102102812100108282B3222402EFC5011642024062216698182922124304502222215022D01845C8E8422482A884948B418E420027E15470610231254424088D24A02410123C
+:80D20000344422414B2443120441001F3F0582121B122822280046018A024C48A12800221C12012100838401820084484220A22822830200848140012400C0424822004822C248DF3B0F240046480981421210C8189412001A58124E1892A094219011808164224644E142C1A11441450212442698866048818410011242414084048849A6
+:80D2800004417F190E004800812D1121100A23828122411A988829082341810180948824422C4844421C4822014180014E261811490162908482A028202112941843016D4D2001948C01121C61A285C12216028009296124811008890818003018222783889311281821417512924810187428C144200646082120221412B8428281028F3B
+:80D30000BE0A8422584002220041D048188242382411008AC249908B8C8413C8882280288442D12224480C482225B41122088223124244810A22440044006122DF550F1D11AAD111B118D18121F12862236724AB221B28AB124C7881A22819E215DA3AB84224011D11463B914A964887822E422E428724171CA14AF451613CD83218353547
+:80D380004622B191E56AB412E346742DB442C4212518C8C4244C2A2246A4228F44C194418FAA026021608450A816D188311AD032E829B28DE111E12261152D52848E8AA6F1DB488B849B5A8B8437183011A999812F9B95C45D3282AD8C2F42E64B5342AD38457C28FC22ACCB24D5FC85281CC32117274038444746214F24562445B842A464
+:80D4000061282AF2B554602129B23882F2382329D383C1221D318E868F83C1882711888DC9E7228332219F13D3ABC9138E481AC84885EA8538428E28AD281DA4A5EECFFC2EAEAE12578843E43246F722616D72418CE81AD838487821028F34F4849625A2214F264494322E624F417826B8E4C4443F6903115081100111508130812482209D
+:80D48000084012113821200A231218221132183928812881285112120029082D81D012012C41882188012C01008140F48CB5343F31F1131337121F13F33939BFB2F23B33AFB2F34B5B6F72F217933F33D2DBE811F158EAEFE4F49A8B2FA6B6F2DF28F833E22E68C82D623F24B2C2B422B752BCDAB5A2F3A3383B678F2EF34A136D17676BBA
+:80D500004F33D322F31426CFE4F15F9F6E6A6FF6FF545C4FE5B531F361735E5C4F69F194144F44F5F6B44F67F34464CFF4B2C2FEF4C44B572B263F5B4BF313133FA5F533311F83F73919BF82F27B5BBFB6F5535375F5979535F2ABAD1E918F817B2FFE9B8B3F24F6FBF9AF11F83AA92F8EE612AAF519BA289A522FA7F4D8428F2FF6B57F5A
+:80D58000AF98F79A18EFEFF2FEDF6F44F577663F61F21636E7E5FFFDF1EA6EFFEFF6EF7CDFF6F664441F36E7C757ACCAF644546BFF1E324F44F64C2E6F2CFEC6C44B557E72D736243F31B133F729199B339F93F32B3ABFB7F76A6A9FB4F5A6A63FF1FB83A3BDA91F19F1D9CA6F66F4CACB6E6B2F37F7726A3B41ADC82AEE38FDE3832F24B5
+:80D60000FC3A6AAFA475187A16F7A5AEAFD6EF4EFE5CCE3F94F4E7726F53761A6AA1CFE6F577DD2E2A2F14FD585E45F623243F23B24BF7C6C66F6868212BBE6F66F25674EFC6B2A6FEFACCFAFD6434DF824CF31313AF23F73B398F86F339192FA3F37B59AFB4F76B7B6F72F2BBBB3F22F28FA91F11F979DAFFE6F4CBCB3BECBFBFFFF3EB88
+:80D68000BF99F9E9E81F11E9B4FD6383AFA6F61A4AAFA6F7CAC8EFFCFDA77FAFC9F68434CFEEF7E7FF7F6DFC2767BD1B2FA1F37C4A7FFFFFA8AA3F3DFECDDF5F71F363453F27B44FF75E5E6F6EEC27B4E2FF26262B75EFD6B2C6FEEECC4BDD4F44F7573180012100842C216122402209826081241130114292008100218314169882B024BF
+:80D70000086160123024842A48F8248184268144A3412480A2416C8284024C02FF32012B1A9012281828A30620284208114E122246018F240A890814ACC481488315A2282A61112AD448925213A1C21A5222162C04C044801412110A259444250210142A08488FE3092D421F4152281F4132481F41324A1D24AB141F49F24A921B28AF245B
+:80D780003985AB9443F24A9353F34A9157822F14F9A4484E914FA2D418F8274A16F1274A87193FA2645D2DCA9E24ACFC91242CFC9124A5F3912487141F49B24AF98124AF14D941F24A9319B24A5985AB9443F24A924B422B944783A9F92448984FA2F46BAED0A2F41164241FC132481F41324A1D24E9F11168A7641D24AF2453858B1443F1
+:80D80000F24A974783AF145A842959862D914D1A8D916DC216F126CA87192F22645125EB41C24B1FC9C24A9E64A5F2912483E448B24AE149B24AE141F24A961F41B248DB85B24A31B4AD1243B24879B4B84AB13694922E5AFF8E03004800000000002800000000001880020000000080040018000000280000000014E068041290222218D7
+:80D8800083020081888A7288028246024002C218488184228732622B24524C662222AC0223C2938D24004AC244148119AC842C4AB848880445A22480A2844A9148483F3D4611A328121611D41251491C41D214C161009412814B42608826188C0428131A0889611889D22308A0411B864222182F12A8241C18EA22A4286022204C21F14286
+:80D9000032465828467C4812246A1841EF5A47331142E01142C41840014599E4A22A58188A61844890882578C42A854438A1AE1885D18234C14E1A5B86198282B689A4241B946F81C2E1E01678426436E01418042BC2C6A1142D224C744A22C4222CAC1C8F1824F5B14300282B12C01219521C12241214502800D04202200200228180E272
+:80D98000228122022502AC81128242026210088B82E026A8288184A041812285C448442210F4D8EF800100180020020085618885030018118942384848302510B1481202004100828D111126018592411828229224822C012800328100F0687720C2122E1A269123111E23222063987240044E9A8C827A21E88411E41C9321848314D882B9
+:80DA0000840438AF442A63828188412323028D4486E318117C247A5831482E42162111AC24108C84A416124249F8DF5C00122814230322282082880289582196C828221E288944288296488426C9481C84C4326212102448028B21103D8186394D1032689A1482582C4A02004AC2181848888FEC0332D082912211143C012812915285412A
+:80DA80001468242048611143E2954809426400831272842892288440A41A11114A426221C03C1F8106223C81810128452824A1420044AF9C0C10140441304826142116287412412411A141286024822548280149C861222230124412142458874240042EC86072424B12824649189A482EC84E11121210342218287FB343E181222181224C
+:80DB0000110800009362882588028118180021206144881842A93814C0222AC42919811298C828481480A1188100492284414418642812142180D44F021002610014241212000000888180A212601110A12425041246282201214800103122C04C400160218008121190448C463188007FC845C1224921912241C049241210F8492213490E
+:80DB80008411E181981880B6820189014246B412A4242F8138582128234568344A223288458396698D444D235287418212A12914D8480B4CE141D48247240268AF940D1810448441084C42A1614444854208202482012884144025C2258012A4214981322212184480028220C18128D0C10486A814488B148008608818F023251411215052
+:80DC0000128148149C44D241468844E18124852488148804208A028C0428400814411210821288C822A8848183364A861A28A84824869C86A308961228082F48F4396B409411C128154202290180483422289028230280C28814482184288182214601008324012419942213F14118242C848192514CD1840119810445921822189018F067
+:80DC8000B5D76014288091411289042FD1042D411C8204830248C04810822241C888244A0140E2144988C1226024183048002136018542C644464471820824A04821826282F0CDC610021181121386B348024A981483C4984609004E221C6184ACD1185581C82501815668811460256611A228821534111931E985A44800002A11829841C2
+:80DD00001889B12808888008A8CFEE03922002404871222253422C0118C01290222D222C8121142824140225022721502228251C61274861B01262414821902848194232882B411828419014408206214E97C04418442827842084211469843042508528C3C5184B249024484D12C042A83AA8480017838812006022481592481441C4233B
+:80DD800025618184409882812382C288428C082F83089FB90D404208101408008240361148000026081002A04140882404422621218801200849A82142808A242A0148428321A44218220028ADBB001419822131283890281A5214165184800290182225D2418402004002848CD3284844382148121C044841188C82039800501A30148227
+:80DE0000491152126A81C121247F24078C21825481800114C088C024242C1204444084A112505288EA11A8A422428034281481418608482028B281051021C244421A12084830242A14022148DA41D344749163C21CF248138F56F661334E4B76F46CCA8FC4A844AF34A244DB472AB2CCF15852DB244E4A4F96932147C5C83F247428983AE5
+:80DE80008BE483B449F4C2118651E41395229AD46253924E92CFB8D724E31CF1187B2F81B7B1FA181416DA62E138ECB1E8457444A889CF81F8D1B27E989AE891BA82F8E82950112B2211A5486881849B11A9D112E218912A8E14AF91913229A422F02214AB328E442F149551859228DE427A642B2B41B41F816CA13AD218E26D4C322117C2
+:80DF0000212B621747175CAD244287224E121F18B468FF94882B1439E1A8B128E9A6D24206207428E366D628095A81D11CF231121B412CB118B422D2A17691B4157431F3144811C4A42D442F82E2A124311A87828E232B2C8E8828A425C81A2A7128B26E965A2E182AB1427944019719888F83ECA36C42428D486E2A218B4497818B4CC35B
+:80DF80007292564EEE122B42AF28A2628A012B3A24442444604800002008004508411014180411818200001001008840011C08881004000014000084400884F0BA6AF071667FF2F237183E163F17F74E54AB46BF35F57E56AF36FD1AD99FB7F753555F5414DC24F47A54C7646B74EFA6F42B4DCF81F5187CAFA3FC6AC88FAEF45A1A8FA6B2
+:80E00000FE5A588FB5F5FAFBFFAFBF3242738EF6C2422F21F1383ABF8B72DDF4DD252F9EF462488F87B6A2BAFFBEC2FEDADC1F28B881EC4AF22E3C2F4CFEFEE4EE6B2FAEF8A8A88BA32FAEFEB231342F57F7656DDF21F13F517AFF5F5C3FA7F56343AFA5F56B53EFEDF57B7B3F17D74CF51E122F62F67A5E6F64F46E32AF66F6131F1FC4FC
+:80E08000F4193FAFA675A2F22A9A2FA7F3723A2FA5F5727A3FAFFF567BAFA352AAEFE1FD12423FB4F422232F3BF34E6CDF91FA7E5D2F873478BF17FA1FEC4E6AAFCEFAC2832BF84749EFC7F6ECEEEF6BF2BA822F8EF8AA888BABCF4FFF483C346B554F13F7383D9F23F37F74AF17F73A73BF35F47B638FB3FF78FFBFB6F75A791F55F54861
+:80E1000046AFA4F47E52AF65F74266AFA7F53751EF93E753E722FF62EA2FA6FC5212AFA7F77272AFB4F5F2F3CEE32FA1D2AAF2842E4F6DF533723F23F39312FF6DF1DD17BF9BD5EEF57A7A2EB29F47BF6AB7CAFF99921F28FDA4A6EFCAFBE6F46FCFBFE2BFFABFEAEF8FFFE4F6CD27144B559F73F71B17BB36DF47F77B39BFB7F76B63AFE4
+:80E18000A5F57BFB2F6FFF6B7BAF95F74D51BF75F56A6AEFA7F576722FE7F7627A7D193FC7F7393F8FA6FEA2A2AFA3F47232AFA7F77A3AAFB6F7F3F3AFA9FF526AAFA5F496FE6F69F43B73AFB3F39B9BFFA5FF95B3FFDFF53E5EAFA7F379BB9FC7FF787AEF8DFBDB9BBF2EF59496EF4FFFECF66FCFFBB2B1ABFFEEF8FEF8EE72EDA9200237
+:80E2000018842E118460812416088424124088E28114281108008B241008004200229012A012841884148C6422008420018C84E2818422A924924A02DF2D02184081021A2406229A344A288B1411144842A024A024C0218C840828488B24188F1882A82484C22111F08128432449A3212354816A89B248398120822948A2480088826F6C24
+:80E280000D2D421F41522A1F41724AF21124A3D441B24AF18124AF14B981B24A19B54A79A4F84AB153F24A91478A2F14FBA5488F14F9A54A1CF8244A1E214FA264191FA26459ACE449C24A1F4DC2C21F4952381F49F248811F49B64AF88124AF14D141F64A9219F24A9259F44A9143F24A9243B242792498924F8284F9244A9F270B2D5BFB
+:80E300001B61AD421A724AA321A7141F41724CD141F24A9519F24831112B9416F84891228B9480713218F824181CD9844CF124D896E18244C5598AD2B4F5912847829A14F8112487221749C3A428A9D141F24A9619D22A9B25AF2429F24892222F243924986B422999546BA80082480000000044800200000010021800000000000048007E
+:80E380000000004480020000005012E085064A11044713A122493211811901234441614126882142A5215484853448C42290448C0860448842325014672230281124163428112682082442244C44B24461228002F0B1A86012824301450396281214982A1B128321549242421240AA244F12A52144104894284C352900614024248221C1FD
+:80E400004222CC932846C2282D8846721842446841188183C218C9C1448D1126F2B716A061C2121E278429B218C81181897124E812B52121942D892421022C1271186481AF4114688850484A698250412142898364542129C56819C2242F8122D418B28CA2482E1441216443542836046991241C7112E29801144441501430242841112551
+:80E48000028111292122244165814E241B424C024422442A5448118064484004284B12400289417428022502A50283248101836483814881223F730226128111911412830226423828901200110089028922026014001312281268820020824262888002C4830466420890182044C81210184434244FEC0E1594144450218C9214A1127098
+:80E500009142484344D928531850248119041E680083A242C14C0762B02624268611266322388F51F422482B161B21A9971848894122147834AA244E284E22624008DBC340C5144C0174224D328432B029481812122952822012E812041E4880842232288C022E48856244422224442A818271414862821C153878218C018944384489C4AF
+:80E5800048E084028441FF870F223110216181844042C812C0114170111801850684222840418844B514240222222848382824862AC2362E484B148D226A0146089012C03A221E2262214441227FBC0F202202004169118314240226021C11C8314034122314341C64003028812187314642480481192281044B4134122230484441CC827C
+:80E6000091441800B0420116F23C362400112820B21834214424501C002821124612189221A1A021008E4310014081B134844414984821441181424112142222C84AB14208C0144A123222E085F8BA698042441C0321008001427018818112021122001C641440084A032942240440A2422280220128802444082121C02200A218103848B2
+:80E68000D0B14D223224555812004CD52542A514218470188321C21824156A6213334859744C0184144828A952428721D042C2442D242283229144148F4244331452948314D242CC582C82049A2214327846C88A6D58002082428252281200906100241311B231040000224421422B1285018024C55880043428188081248442840240A62E
+:80E7000049441244320080F4E92D2021024C0115144604261411021120020010518224412110A442460200A12C220485C32281004A8204222902C04880C41A28404A982A60869FB10D1416110189023012213120219222101102002302236114194173215824224A225281121C64228418A0122961148100405261421AB2220122184800F6
+:80E780000070AF0D1820C2218001000000302840284218A8244008842A0100848C0284288024140885E22204242C011881261218084082018041027F1409250800009111189018901290130024124C0262001026C518160823218402404A0820844121324820248201422A1102004C818441F2DB95200820012902210070220821816508C6
+:80E800002150528420144B512114844E2224100860220013924244001212328C23010020248111280118242BA1002250142B125481139222252512511214211002290121848084474CCC4644C0422054924220013618228116088120120822002A848204806284EF6D0AD0214105855428404C840100800126981C22800118410024228084
+:80E8800042816211128468244800848123140848214CA414182902A1A428228484F04756008422221440012810080028834251822821450183A4128442424004A448000013084884A4C028482C011140324820110880248282F23D53401884042C61812884602240044C022083022889C4442180018821848C858443012901299258604498
+:80E9000044182D12304840868142424648624225025042F06ED124121FA9722195117C711A1CF811242741221A92292B21412783C99222242B224B22A3764A087B471712115D19AD4649E182F44A13815817A2224692182AB24825F4484623F2681AAB41897172D212931E18AB272D4227A12B3527814229F16838CC827458061C410116AE
+:80E9800075389811155212222D118579121251231932239CB122C11AA5C1544964A1842D484D64897224C842872426F8423124124A022FA1548136C21C27811B74684678228814A8652B45AC858111E862133234213662846FA747012E14284F2282D234722659AC2CD245522240429118A48722CD2812641D29288B54548562B12F64A485
+:80EA000025AFC69232682E48A7834E21AF2194621F18D22AD182924E2E11853A12181E6289732102850A4B228B24268A74283A4880F128227D84244002400880012C0118800110014004000044604120010000000010040000002001430141100441F063BF50216FE3F337145773F7727F71D1F7F23626676155F5191A3E22371175F71382
+:80EA800019C5BE13F12E26AD2AA7827F91F154148F85F12A299F94D4BDF35533C7E2ED56BFB2711AFA295AAFA7F54A4AAF21F322223F99583B8D2AE7A12725A598228FA7F36262EF84F568481F5111F84818CFE7B752E747F55A5CCFC6F678728FC755C8EFE5F4BB3724315FD7F734367F53F73537FFE3D37FF23E2667617F51F33D3EBFFA
+:80EB0000B3F2332775F7131BE762BFA1F136362D223F32F2177BCFC5B558F51B1B3FB4F4CBEB7FB5F736BEED76BFB6F75A2ABF86B7387329FB32322F26F2FBEBB732AFA2F25A4AB7959F12F42822AF27B36AF65C7E2B77BF73B71A7148F86C6CAFA4F62A3C8FC253EEEF47F77A7C8FC3F36C7E2FB746B322F23474115773A713FFF1F11BC0
+:80EB80003FDF7253225F7151FBAFA2D333F217173553FE3F31516EAFA1712BFF171D6F47F368289F96F34D4D8FB2FA6321CFE7D12674317312D232F54A4AAF84F412382E223F39FC12122F21F33A266F67F21A1829F3683A2724AFC5F5381A2F21F31A12AF84E127F35E5C8B466F27F57A78CFC7F37A184B578FA4F5B1C5142AF23D777578
+:80EC0000F777354F73F33F3FBF71F32F3765F62727BFF3F32B3B7D236F615133E7F2BFB3F13E3EAFA1F32B2F7FD1F77E7C8F26F6495B7FF4F46BEB3FB7F7E66EED6EBFB7F65A2AAF36F77A72BFA7F532326E62BF3BFE3B1BAFA3F37E66FFF7F27B53AF23F37A32A724AFE5B732F35E72AF21714ABA72F34E4EAF22F27E78EFE5F57A388F56
+:80EC800087F37C78CFE6F4B4BF80012A0122842E124001248434404108C022114A0242B048024A12B2480220324821302200008C040012241E486081248CC4224880041242F08814208802124140433C24408102112523522812508425011841404804442128AC04184A4212E1124198121262A01600284200128122892192182A1448F3D5
+:80ED00003936C0421F4152281F4132481FC1324A1F41B24AF11124AB941B21AB9453B14A3924AF1439242F147924F84AB54F82C4914FA2C4816FA27418F5245ADE252E5ADE25ACE549E2A2F491242CF4912487221F4932481F49766AF1812CAB141D2CAB9619B24A3915AB9443B34A39242B94478229F92448984FA2D48A0B6D481F41D672
+:80ED80001EE441724EF1112C83F41124E7241F41F248841F41B24A3A15AF443835AF5439342F547914D85A7936D858FB24521CF922CA8D85AC65581D1886C41B9E24AC7591CC5A1F41D6287991F42C129E248F347181FC4A121D2C8F445941AF243B158B9432AF4428F24A9626D84AF92248AD942E5ABFA90A00480000000000280000007A
+:80EE0000002180018800004001608280040000004004280000000021F0FED680011440420381348114100800842A0181111284450828100AA110C22810862392112023C41185E1421161848041180843022C24C8646840F2D7A680E2184198381222224582C222A4002125A1249048142612880228261891281342A4248452218F410446F2
+:80EE80002448082924D2688412C86834224210D228A2412648888211D814048DAB142AB14141C118122821603250257028023922024A0124A01281A3028A018441A3446825848D474443E6846A812C8427D68164928C3341C324A243842D2826F82214402AEA6132484112AF9B08008128241122C4218C120A008014688214265818004152
+:80EF0000893221893223200221281880011400D02401418C4203000042262804422242F093359014111828610012002C01400800100A4484811302406482965482442588628200E012A121240084188C120200240084008534242848AE2A10816218601139E13811C41232311332112418211A84C444C483C641C04C2448299642E014C23B
+:80EF80001826C654422229F62512814D8A4E28497129B411E6828418E88194198C14B28812082D58838424442CF2AAF21041C111224C112118062C13118141082120445C84830284810041E041E892648189A241842C222691138C322212999231812C4248284118824A48781208453844844AE2BC024C21220825311213216121803122B7
+:80F000001190128005230449D48104471630422D622E48104254624C8206D041C2281E848D42444446883788A041852144420820648442224302DF6A4DA31200426213024018124482511822417086838421122A4168A41048422202873678290123D42A820242141011C122C0431218A9D2429B41421621022B414324F1C19510442432D0
+:80F08000421002160144141484241002488142186100181004004001498205818904C128844C11240444222D481870120428201182C218C7D90011433111D06841884491280010022011381110024001841014E184410200290200241A921A122382845118320000192842E124018C18085F760921516C1301ED238442944C1241311800EB
+:80F10000411287249CC1122A014009504841118B2590481AD44283159222894222541A8433D214642485A16112A9741288A9C168A014218B94C914F87F24B024012021260113414248042D221558224032854248508418304825082410022722282428481002CB121A826141A02110112241322425043822188042F2EC14000051100111DE
+:80F18000848110110821210000191442480440095140A42128288002007042082222501C00804108103242230200AD420050424218440000119014008081010000814442408C24642140220412438114263114211092228021843148222002840020F2A5F7001211401512011120E42112014A2201239318A44068141425411848012424FF
+:80F2000049911212121811182A41088D110019A121844C410A50280021104242F28FD1105214481218122301501C004061212400250100281044C362004460845484690628810011412514582600A143044724440022462404F0A72820110800204211080023013120013824008442400246584821108814982823E48443081A84218274ED
+:80F280004288243112004528A848482A240200F0D44D14004CC4145024480010010000004800100211210042856281288582028C4281C44800214128131244C44A80C4282822818122220087DE4041021188002602158202A02140045124844225054400000048401404414441446551C2100844914C840150220040018480F2A68E20390D
+:80F30000810051008004242E11811880013484411115484151221C44D1611218861404000016F2114A85813274844082582882812D8441261C9228004001DF1501152895410050214115024014C1241B2124002400422184384488211148C12C64165D424D12849044902410280280C424F042242004640021422504BFCE4892118643D1BC
+:80F3800045D4410100278490222225D4248141125214112114AD481C14DC43D212F421431548D282F4164C2D742FE2E494E6429122435228F951214D4826D468322A4574447852F2428824C784E5F2288823522A1CA2424854F012EC143088311E1182453343541155C942155381141F1104D021F2581881195415178284149512187E4882
+:80F40000714474487264324445F216624CF14925444E46255D52516548D221D31852884B11C7C11664424F44D224E282F22A42416214222F7D0716B15551447014D142E1319221851358111AF31811122F22B216A1112B112722457A4202811D4745324425E872D4C54482711888733A14A8431AF1141836B87CF11832AF8523E684726247
+:80F48000F11394388D422B4429EC845E22424284295282242CF2F5792400008001220000000000100820022210010000000000000024126081248400001044110441F0A3BA3425F1521245D554D414F815151F35F525273F3414F121233F31F11B1B65F612226F61B112F124247E62753F4245044E654E6445F62A226F76D67654226D4678
+:80F500007D2EAF81F132766F62A2675F5173195795EFD5F67335BF95A5315AF52E2E3B887E72AF2DFD4654ABDC8B46CEC247628FA4F46E2E6F62F26C6C416762BF3A43E131F1125965F5141547617F71F1535355F74B4B9551753F33F33B3F75F713236D162F21F136262FA756F72F24F465641F16F654776F74F6A5B79F24F462E66D4E6D
+:80F580008FE4F41A5E6FF4F47A7ACFF3F7767E2B661F17F7191D27D16F55F67535FFF7F776745E52FFF7F7EFE88B77CF2FFE4E54AF8CFFE4C44F4CFC44468FA6766ABA62F66E6C412E129F740B112F21F5151555F5151555F743435F72F2434B15F921273F32F31133757411F216162B115F62F37372E57C43F12F2C1F12F245555F46F40E
+:80F6000044C62FA2F266667D4725F21654EFF1F32E2EEFE2F6163E6F47F631718FE1D1FBF15E6D6FC7F3527C4D2EEFE4D4FFF29A9C8F27F6DAE84B44CBCCCD44CFAE7E22F2464EBFA6B262F66E68442E324F1E465333BF11F117155F117194F415163F25F52527BFA454191F72F233335F21D347F131126F61A1115771BFB554CE1F14F4BE
+:80F680004F4C1F14E4B4F566477F77FE4B437F7ED6F7F44C4EEFE1F45A4EAFE7F73F7E6F67F766645F53F7181EAFF1F156657F57F37B6FEFE6F66E6EFFF5F7FAFEAF27F7DAEAED4CEFCEFCECEEEF8EEE26F66E6CAFA6F26664CF8646E422F26B9A800141400214000000400224135128201401201402214461B026119816901200501250E8
+:80F70000248443820448804442C8244828480000ED5C40214121412101100800A11221001002254128548140621484148C048C54482D4A804454381634484C3266101A81C1282D124588819488100200008FA4036D421F41522A1F4132481F41F24A121D24EF24D141B24A9961AB9451AF24B924F44A9143F24A9147822D914F82C4914F04
+:80F78000A2D418F8254A16F1244AD6E1A2645DACE44DC24A1F49C2421F497228F2912483F49124A7241F48B24AF11124AF24D981B24A5985AB9443B24A39242F447924D842F924484CF9244ACF610A4D481F41D628F41124C39421EF22D141D63CD141F628951F41F64AA151AF74B934F4488543F24AB74B42AD9569D452C95A8D955DCAB8
+:80F800001E844FA2E41962A29645EB5962A217C92E4A1F48F428121F4932481F48F24A131F497248F29124AF64F181284AFB8528AB9443B24A6982AF2409ABB4278229EBA2F5D5DF2028080044000000800200000010021880080000002400480000000044000000000014F0666E4041611111441042D182819142804402C01150822426F4
+:80F8800028420129C24A28C12311381220424422041420C12286A221255838D0126181D446988C481820021282286FE341C232922136AA121141212601818118234454812481100BC3446484414014017A487468C614812D11269122C353B2172813916C112681C82846C24123C1142CB418829C14528CA22854F0BA3D3021231CA12128E8
+:80F90000003522C1124944A852250280512AA4A48722461CF11842228221450A8BB44C714502C48501421D2419341226E2E8E432414838242B14AB434D1818812B411A64412824121C28F3ADE790121391121598161161702801810048441548011001224440C4484C1221410226E8414222F12243288D12843C381122601213181A41130D
+:80F980007148B484942882A04189224A048F3A0590212100112100484A21014004211214001E4840228404492181244168411820421408181283044280212804000080844108F05B1A00002381811248731984021421142921044C042538522242420048625B242881248934485CA1142800814306478213C1488494278124484C428804A6
+:80FA000000424443F2FB550026012180124232186240021418460200304228C0424848422086844152488C11A4121008844304CC82119818AC1808424C4208802401444CF2E4EF00AC04181811841145014A311144244902B014444388915A428001E0416651228485A141481781484C0620A12146081C240415240721004200704208F0FB
+:80FA800037F4902150484443024825C91840480821488481608118112013C84214812644480C83043014000041449036CA5228821842888127414220B828C128C11284AF2248820118228444004624042C2401004C51222014280200242242324A430848893122430480010000100890420082240049A124224CF22BDD0014112301A593BE
+:80FB000014800219014002112004214392144444282810480482180000233111284828490520058051281A44186C854983041084D8954592111483B1221144CF168483061283042450818D1490122B14952423124CC221214F84528446088384149814460612124934244331248A167882081A840441836CA14B381A16986C4186F893E198
+:80FB800020024541742802421149815418D02201424082140828414C014A0289021AB224318818C0122820418102602412A04120416288AF246181444840C8348033248F190D181058410000210000002004000040022904488064418400000000004C04801801002004800400F099146022001221A18400482242830484442504004384D3
+:80FC000004624249628490242224462284251204442190241A0442881038421BC18C0C85D448A441384C0422848BC8A02121D02101848110022842810000002034420042442044A44250824242284448002022614442888880A49489084008200422F08A7C50888B444E484344020020544445B464A222264896440050242125A2172B11A4
+:80FC8000236F848002437141531119518885B848C4442304444800504455BE24E212A242704438444A2157242552221E182FB90230120000210000000000841004480000002924240200000000442002004800000058448200F0845210C84846820400004014C4248382028100484002292181A928490A00251141411848682448000042D0
+:80FD00004014C4642228004800502290124F124C42081A0420813122004244812820040040022304492182081008701201400858180000840044802604830420041002FF56028004124004004004288004428005100258484C2C0400400140081A0400000040048C02800400002180F1E63C000024800100000000000020044004481044B6
+:80FD80008404000000100218180000008184104808280010545D50888B4442420000115044414B222A22028100484602241AA56196242808001511115188818304420000004594444B222A22022008405222241AF1E675241885084A141222011001814584E4822214024822002516021A818808808244410112AD48484A05000000D044E7
+:80FE0000042A020020041012F27BCA00214C9112284018020040182824018400004840048C824404000000200128001011810481814818484608001004478C0018000000000000004800004800808204000000001841008001004008004200480000F07DD650222116840180210200102824A414A54888A4424A044A044C34448C02414816
+:80FE80002829941200808111820200150842488C4418A8548C948820021014E4620F128051222972125228210000848448484820240410242482824474421408000024001230141222481130488148008324A441480000AC44021A4122014921011111488110180842811244A044904443E4422496642024020020216161180018000020BD
+:80FF000014A844008C2464448200F0A3B6F026222F21E222B11221B112012C512239E811F111119B98179987848F18F44848421F9454111C548985F844488F44742494244F4222E24202286554442E246F22F212222AB112A1812B99C0922592832F31F111119BD81F99D888B888F44848428C04488558884F84F4FAABF0262265A2123A10
+:80FF8000211102142592823CF1131119E8897818D818A4444214158154818588F44844C5B444A6222200405444286F2252262AA1131A388282142512C2131F1191819E8887818B48CA240400848588F43C9D00000000000000000000000000000040110100000014110000000000000000003F7146110100111100000000000000000000B7
+:020000040001F9
+:8000000000001411001011110100000000000040420224502225D2220600150111100100000000000000001100004011411101001100000000002100212450222421004F3804501100001100000000000000001411000040011501000010110100000024002421002100F0BB35000000000000000000000000000000401101000000141158
+:800080000000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F710640411141010000000000000000000011000000100100001400000050222121000000008F4203000000000000000000AA
+:8001000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F013671001000000000000000000000000000014110000004001000000000000000024241FB2
+:80018000EA0F00000000000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F013671001000000000000000000000000000014110000004001A0
+:80020000000000000000000024241FEA0F00000000000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F013671001000000000000000000001E
+:800280000000000014110000004001000000000000000024241FEA0F00000000000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F013671039
+:8003000001000000000000000000000000000014110000004001000000000000000024241FEA0F00000000000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010031
+:8003800000000000000000F013671001000000000000000000000000000014110000004001000000000000000024241FEA0F00000000000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000AE
+:80040000000014110000004011010000000000000000F013671001000000000000000000000000000014110000004001000000000000000024241FEA0F00000000000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F71060000B6
+:800480000000000000000000000000000014110000004011010000000000000000F013671001000000000000000000000000000014110000004001000000000000000024241FEA0F00000000000000000000000000000014110000004011010000000000000000F013670000000000000000000000000000004011010000001411000000EC
+:800500000000000000003F710600000000000000000000000000000014110000004011010000000000000000F013671001000000000000000000000000000014110000004001000000000000000024241FEA0F00000000000000000000000000000014110000004011010000000000000000F013670000000000000000000000000000002C
+:8005800040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F013671001000000000000000000000000000014110000004001000000000000000024241FEA0F00000000000000000000000000000014110000004011010000000000000000F013670000000035
+:80060000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F013671001000000000000000000000000000014110000004001000000000000000024241FEA0F0000000000000000000000000000001411000000401101000000001E
+:8006800000000000F01367140010110100000000000000000000000014111100110010010000004002400240022421218C040015411101110000000000000000141100000011104101100150110000000000401242420200BFC4085011000000000000000000004011010000145011000011100100000040024012021002006FC90D000039
+:800700000000000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F013670011144001110000000000000000001140410100400100001001002E
+:8007800000002121210024212400F0E51800000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F71061100000000000000000000F4
+:80080000000000004011010000001400000000000000004042F2A1FE00000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F714684
+:8008800001001100000000000000000000001100400100110000000000000000002440421212F2FA3300000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F013670000000000000000000000000000004011010000001426
+:80090000110000000000000000003F71061100000000000000000000000000004011010000001400000000000000004042F2A1FE00000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F01367000000000000000000000018
+:800980000000000040110100000014110000000000000000003F71065011140000000000000000000000110000000000000011110000002121210024000070F40100000000000000000000000000000014110000004011010000000000000000F0136710010000000000000000000000000000141100000040010000000000000000242496
+:800A00001FEA0F001501111001000000000000004011010000104111010010110100000000004012424202005FE90F5011000011000000000000000014110000400115010000001100000040024012021002006F310F00000000000000000000000000000014110000004011010000000000000000F01367000000000000000000000000E9
+:800A800000000040110100000014110000000000000000003F710611000011000000000000000000000000141100001110410100000000000000002424CF420250111414141001000000000000000050110000400114000000110000000000105222401202F04B7D0000000000000000000000000000004011010000001411000000000048
+:800B0000000000003F71061100000000000000000000000000004011010000001400000000000000004042F2A1FE005011100111000000000000000010010000141114110010110111000000100210420225421202F0E9480015010000000000000000000014110000400115010000100100000040024012021002006FD50400000000008F
+:800B80000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F710600100110010000000000000000000011111400001100400100000040424202004002006FCC0E1041010011000000000000000040410100001501141400001001B8
+:800C0000000000000010020000DFDB060010110111000000000000000000000010110111000040010000005022212124002400003F4B08001411000000000000000000001100004001141100000000000000000050222100006B3B00141114141100000000000000004011010010014011010000141100000000004012420224006FCB0864
+:800C800010414111111101000000000000004011010000001111101111111151111100000024242424210000007FD50B10011011110100000000000000000000001411100111111111151111010000000000000000C7610040511115511111000000000000000000000010410110010000000000002512124202400200F0BF65001415111B
+:800D000041511100000000000000000014111100001400151101004011010000000040522221254202F0112C00111411141100000000000000000014150100000014000000100100004042022421211002009F4A071100000000000000000000000000004011010000001400000000000000004042F2A1FE0040110114000000000000001C
+:800D80000000000040011114000000000000001002100210022100EF4905401141010000000000000000001411000040114111010014000000000000002502212502005F2E021501000000000000000000000000000011141400000040110100000000241002405222E01C0D00000000000000000000000000000014110000004011010080
+:800E000000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F7106001001111100000000000000000000004001000000400100000040424202000000F068C8001114404111010000000000000000000000001114000010010000001002100224212421005FA10400000000000000A0
+:800E8000000000000000000014110000004011010000000000000000F013670011001110010000000000000000000000140000000014111100000024242400000024F0BDBA001001111001000000000000004011010000100111000040110100000000002421242400F0631C00150100000000000000000000141100004001150100001006
+:800F0000110100000024002421002100F0C78400000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F0136700000000000000000000000000000040110100000014110000000000000000003F71061100000000000000004E
+:800F80000000000000004011010000001400000000000000004042F2A1FE4001501111140000000000000000000011001001100111001440010000002121210024240021F0B4850040511111000000000000000000100111144041410111141100001400000010020040420200F0445E005011141100000000000000000014111400001036
+:80100000411141010010010000000000401252222400B0FB0A5011000000000000000000004011010000145011100100000000000024002421002100F0175600000000000000000000000000000040110100000014110000000000000000003F710600000000000000000000000000000014110000004011010000000000000000F01367FE
+:8010800010010000000000000000000000000000141100001011410100000000000000002424DFD90A104101141001000000000000000000000010011400000011000000100210022425421202F0DED100000000000000000000000000000040110100000014110000000000000000003F71060000000000000000000000000000001411EC
+:801100000000004011010000000000000000F013670000000000000000000000000000000015010000001411000000100200000021005F420A1100000000000000000000000000004011010000001400000000000000004042F2A1FE001001000000000000000000000011004001001001001400000000000024400200B0FC07001110113D
+:801180000100000000000000000050110014141400000040110100000021004002242400F0E364001410410100000000000000000014110000140014110000140000000000002502210000671E000011141001000000000000000040010000000000001501110000002400242502100225024DA814404941D824C1482A141414041048C4D4
+:8012000022C022167818E421D2280200A05229121208893368602442A0251484412062829044001882448C42444824A82D9242F05676706281558219744811741C3268682B421E24224F12411875281476248232421925612116544221181622711A248491488D218D211954812568149B41E9C45C1E444E24A81E242AD84842844A24E216
+:8012800041E281A234001E886B853D2A100240981121404422E242011C1148418802830113042424411E2218801108228024028901469814484B141822484C0245080040043A04824A41F61E466012872110110C6E124848460410084141442618823418214004422824604189078C84724A0119161381140222444C28818881885884220B
+:8013000084162828048988F44833801401484845088902002244C0222290146412001800400210028C0194400100844184468C0400002228413844A01240022FB2012054180048C1302400201204241022622228128001212011082004004840081184220022208242440400228028011AF8D91740020000000000000000000000000000DE
+:801380000000000000000000000000000000F0C97914181210614454248D24890118228384141A1C02290130441284118D4211002821244018412441C414190622190290882D22489084412921854C88084B8145F8F7A9400287112544113221004C52124091121032444444A419011051282226281223A4124E18684004104848C2142CCE
+:801400004464E4C922941888100847848CC21444416608F0EA7A40028D12444C5441261338184C8221822401652A14144498122041583826C2212411104298228414441048846441225C12C82CC6D88231421014D44861874B18C1C0488A41FA58A4802141114103C0240025018583140A44901240914410018C1428022AA421584240049D
+:80148000124116683260247044028082088908230442C08422444147BB404244421CC824C50183040024488150482004285018001028425484000020024184C0248501182004A30481483034818410048CE41D4BA2142C911460118D1220C424C3062211842994442D12222301151408875495346861C3344A428D4426A8122B24602460DA
+:801500008223C26C16B92484014D11282E5812E3A541A48D442D821A8C61412882414604108201118151420000248421448741282305008044081068C445984C841229066870240862194101181C012A44B21424C44246A229C66881444C02F07213244A711452248594182E1681F04824CC0622114283C442240060528485414DC5686520
+:80158000B8241482042222002440922845D848B24C2201444A6281AB14848311584841230118807844F83DD900004E112668221626125A824129011B12128481448544382824C01184268112D2817118D681C1224C21C334D048A7213028388400411C0282523850820042128120F11FFCC01680A12450D28110A424554819382248412458
+:8016000000224934C226A8122C4402182262400100904884215014604640C84822494188820252848032124116D88F08214C120400001941224102C1812100125260810010C84400A04212002422008322011216E9842114E2840182202551844905482055245FC542721422C2142826D83E5284218D114E2814231172186185A12444A055
+:8016800025CC24116812241CD24224D18163241907492182024923C228221C63811395584682E48423218461278CD1489418423A24614141DE27004430110018286502A951818512044181D0484188E288840283448812024F8211E8220118163422D02801894104CC02C487124488960800124604402844FAABCA002D12812D44401442D7
+:801700004424010024C44004101884144858221218412110861402000020024110048001D042028140080022226F640E12007018022051280016629219012781A01244501889311110088412101888621244800200C028284008C028251848484C1484911284494188F4D62A20810418008581014941880118442C418411044100120010A4
+:80178000080081002062848902008B4212182248100544902240040018F082A600244C04154448444244020020020000000019311811100500905826042818431248044442C48120952418A0141A122232123800CDA70028118C210100812800000014001400104888440884488002228180024249525A80021544144802248342121828C1
+:80180000433824C436F1EBB4400E502420018142000024400820C42810584A1C0428C0485048C4C1454104A4102822044C51824428182412C51228110842200221F02FE900000000211484148425184808400830181621014C11C114181100112211220044141301001628014C01121034124D222800A021F03B47400124811084140810C1
+:801880000850181041080080120441844144245D221464241061144110085018440094260180040022002182F047394048944810481848048442C48022040000101212820188C01800189483028C012A14148C021608842144842820018112A0211006EFD7011C4154A81674114214294108130489628127A4851A04601285A2159508857B
+:80190000F82211D5BC1841180A135648715982E1422611B434722838288C228191188F8213461274386881818322E28202CF5223F3B498404612435A88A4D0A271419218B018011D11C5941185B11823044D1C8588D19A4104124115516585C1382A727838282E4381281B24878411D46D148D544D2445711162816D1C8B252D121865E227
+:8019800025A331894164814AF276AB20917244E9C514C361C4C5544C4FA15288A4255928221244504485186112474148718F8184C14CE3E18254C6C516C224800287C2265C416D244B6183518497822D48905981255C44AF42E4C253862416B23483085FF40A150415081150812111291191128011841184118411441154184114501820CC
+:801A0000018311240112608141161802211042080040440884400884444F244F7216F7672FC5F4144637311F11F14E4667617F94F53723AF25941B3E155771FF75C617DFD1711CFC54441F52F214141FD3F31D15CF6454751FD6F615154FE5F41517CFB6D657C1121E1885DC51F141726FC551C4DFD1F7595115F71B1EED1C8FC2F22D2F1D
+:801A8000BF21F12222A7C24F41B15CF524242E3CCFC1F15C5E87A28F81D188F18C88E5F697BB2427317F72565FDF5151A81F91F14F45D7514FC5F4372FFF7495138F517315F34F57CD17DFD131144F44F52424DF71F13E3CCF41F14D5B55F7E4E44F41F15CDE5F71F16C6F7D1D9FB2F1341CCFC3D3DDF161726F41F5341C8F82F26967BFC2
+:801B000073D3CFF22C3EEFC2F32D2FF5F63A22BF51526CEF44F62C362D148FA3F36E6E26FA183A2FC2F38C88CFE1F3912E7011F22767B5F9141C4F61F11111BF947414FC4C5EDF52F34B4597212D33FD1BEF647412DBDFD18CF144449F9353C42F83F31C14DFB4556EAFC6FE1C1C5FD545F8747FF57F1ADDCCF21C3C5FD2F251626F42F655
+:801B8000143C5D25DFB4D6F3F21F1CCD1CC7E1FFD2F2191CA4AD3A6F61F15E5E6FE3F2263A6F63F17E5E27A2AF82F12628CF8BAB1227CD7011F22222E55CCC95FB1818EFE4741EFC554F4FC2F34A4C17A1E731BD1BEF64741A7F1F8DF144448FC353DDBFD3731CF4484AF5F76FE5CFC1F1DD5DC5FC7C7F757F3AFD3C3CCD2C5F52F2716230
+:801C00006F41C1284D24DFD5F5393D5D2EEFC2F3141EFFD252C987A1FF91F11C1EEFC7F53C3E69F13436EFE57522F23A386F43F1BC988B326FFA0D180084210084400884240015088481000000210010022110022601000026618122842601341224122C022880024C028F3C0886111118911444854144514110110824000000160884408B
+:801C8000088C514850589028430200C128C71210821222110A8901255284891214022001149F380F2CF411248D121FC17248F21124A7241D2CAF24D141F24A9219B24A19B54A3924AF1439242F147B25F842915F82D418F9254A1CF8254A87115FA264192E4A875DACE44DC24A1F49C2421F49522C1FC932481FC9324A1F48B64AD141B6F0
+:801D00004AD981B64A9945AB9443F24A944F82B442792498924F82A4944FA2F4215EF026481B4149F5112CC7241D2C4F24D1C1F62C121D648F64D941B6489B24AD914B42AF1439242F14DB85B442FB2748ABB45FA2A5845FA2B8587A25624CACF4C82534CE21ACF4C12C4D4A1B686D421F8822F4816CA11B68A991612F64D98196B8199679
+:801D80009A2AF442944F83D422F93448986F8AB442F1241ACFC2070048000000004400000000002180018800004001000000000000000000000010029F8E042418942110551800400181D02801811011018B414008428044C24840844202902210111854812912883218004018081034228400F086C2008641046022247018018400444047
+:801E0000064484251C4184421441342221001190128147224052C144902221441351344001250244383058812187421C11FC8E9C00135428001C1209830141608244165862844481A515E14104274111864602904811242A41DB481262248154844C5282255418453116142210128C01C53228A5120C83F171D8402251140044250214509F
+:801E80001800000040014088420848284810024100408252144002142818288140028180024A01208211F43683008021512A12C02C811A220400214011040043011181804242C412400A24104244414843A8141126024601218421901884182074248862829FEB06252242188412448101A1842931111224841608848553848B24262824E4
+:801F000046014C17F14C2145290452226641425A244C043481415C3212818F21041E4DCD222A449244472116242401DFFF042128182C51284C419114812A218421C1121042180434A05281484814224912C22C9048809422190614441354824642114491436024304843B24A11384418444A2221F21FB94002844428008902A1A41001104D
+:801F8000C811401858848524129128004A51141F24511C10220121648512584260118426624218842D18A44D11812890126458858442F8765400612C62120044644012C4120080024A0140912245981440044814251842812111C114AB14412501411285014089220A8584091A144422E4482162437F520800424098281821004921046E7D
+:8020000012002185014344188A011881128184D021714815040083140830294056948440F9241843013018818820110212EF690B00C0144351220011A1281400104248C421890258260140110100840084101204184C018001001200C024260400304800CF33071024E25261A18D22186114241A1211A241212D22C058224314E1826511E6
+:80208000445014139148118129914A4911486361105C124C312512241110A821984951844C6AC2839484203144C024EF1A062440024110042542081A0400101845618281D04802400810185218418001604120018470111C4C4851C181001218120023648928B0FD0C000000000080438241011048884112011400411911491888314846D7
+:80210000111442444158182D181C413C4810486164008614588600814C02419FD5444244420221493112212810420400400114200450A246A9211C4254426410110448260424442211C40013042302871483120A904C29644600F0E86E242418188100002118002125025084912721108281114252292216A121141147225028404651480F
+:80218000000011181846F4481610041823A4243850421800CF2D074006411100413826042054854451384311146411414511141844C2284420410822362104D081014800110010A82129840A5042C4228440F8E11DA028000045025012268202211601250210022100244002400869414254216024101A4214C81620241408424648012CA9
+:8022000054489024214048F1E5FB004008801201002428140000218301161108000084181008948122800100160420412111311AA04120A1212001B01202AFC2041425D8414216248121810114124C01128100C0180048008110041811192181A14100281E44182002608222225022A0420042800148F0817A00840024004052840000405F
+:8022800011080064A02110041840D1810121241004114111A111104409614E183015701412082923012128F03F344028D124455884107414081832C4C022001C419121808241418863121D8828290240CC21404108488001811904168804801281248804001A1246F4199FD024728E5A4E65424212217132C2121B222E186552581C5148C7
+:8023000018CC115A4227254C4141D642424652889D1514B5D9A2714868A44A455215105B621F91D1C452829941911889D288C1191981E224F9225C81CD524F66B118E2925148FBB22421602144214C53244D1A18268CD1228294132125711B59391F91E1A1C13417815D7270491AB11B52718CD28501CB216B21B71135F5644423515447DE
+:80238000458711811C014AF418686FC456212F44D44544F17486A954282F442612624268F034EB10A111195388D534142B114419B214122291111612143124214902151122518BF0283926B534333687211E14154584B2341242D2A8C2192E184634185D4516B94141E29745725AF2426A8E58844B244F2361418982411474A6031D24D0AD
+:8024000081021912181118113811811285311430243024814B42B0240449041800008122422200288032428C1282122641220116C8229228842CE281041E48F0E7E8F021271F52F31414CF62F2A127FFF1711EDE6AF1172D7FF3F31E3AAF2252BBE51CF32C2E6F71D166D222F2323E3F73F54C6C5E718FF6D4F2F62E7A2FE2F1272AF7D2BA
+:80248000C5FB1E163FA3F2424E2FB5F563637F37D1B7F236335F72F34A69BFB7F7723BBF12F65554DF76B742F4716385DEEEF44A48CFE4F164A66F23B36AF64C2256F868388F82F24E4DEF294D53621FD5F535377F72F6A626FFF1F11F1FBD176FC2F3272FFFF2F23B332F625266FFE1F322222F33D376D2F6F222363F53F55C6C4D27AFA2
+:80250000D3D1F8F6AEFB2FF2F227AFFF53D3BCF11F17AF71F1525EAF25F56B6B7F73D1F7F616175D47ED2DBFB3F356199D43FFD5F56D6F6B661F36D668721EF74A69CFE4F424266F63F37C74CF24F2442AAF86A2664F64F5356810F61751DFD3534CE5FC3737FF71F1161C6F62F23B33BF73F332381D333F31F1171495FB22223B1157F21C
+:802580002F83F15531BF91F53D1D8FB2F1462B7F86FA31377FF2F32F2DC5FA1D172FB1F1246E2FA1F5541E3F17D131F617177F71F13B1B9FB1F351191F91F57173BF14E547F77363AFA1D367F15F55EF66FF32B26FE1F1725C6F66F73E546F82B354D744F16115247F32B21CF51C1AEFE652DF6F63F31E166FC1F13737AF22F33A363FB337
+:80260000D326D3FFF12B1A3F3252FF757E23FB321A7F15F31D4D9FB7F5281BEFB4F27FAA3F73F2A73FFFD3F31C1ADF71F1363E4FE3F7125A4FE7F33717FD27FF73F35717FFF3F159731FF7F213591F33F75B518F47F77333EF21F11716DF57F57EF62F23FB36366FC7F77676EF43F73638CF83F344454F1D0D2210062200100400244011D5
+:8026800001120030112800118001491198148314040000418041088C642248C0487440A44124481400F0F7A9400114CC523240514118282712400120120A1C2202002618088912C421A40012224214502850288445321124901880012D14368841982280A1414449F452F2D024F4112485F2112483F41124A3D441B24AD141B24A9921AB6F
+:802700009459F44A9543F24A9543F2429557822D954F82C4955FA2C4854FA264514FA264193FA27498C54ADE242E4A1F49D224F49124C5F2912483F49124A3F4812CAB141D24AF349921AF1419F54A924782ABB443F24AB24782A9F9244889F9244ACFC9074F2294412E521741C35641AF24D141B24AD141F24A961D24A9AB61AF5429F1A4
+:802780004AA7F04AB716F84AB48CF442B5ACE544FA22CA1E856F8264192E4A87492E4AD675227A91FC224A1B69AF32B5917268F1916427161FC8B66EC124AF6488B2489A25AD824F88B44802AF240B8BA461ABA44F22F1CD226088820000000040042800000000218001880000400100000000000044000000001048012F154C02502240E8
+:8028000011415822008140110140420428800110488E011124181200214C1141180481248412115012841120040000816074EFB80960488608220012814511028421000083414A11A81281252404816084452246A424146221400113111A81469241224844C0248485024934424226011F614F03437C8218120184295182454308261C018E
+:802880000080410A8981731258C2874C29110887244172E01412E96621145814405982B158D0163421221504661448024125021443F1F795000020120100004003002441812214000000400112214424001100200120124102830400400848428C848274E20300458142022041311100144014810181004508002114A02145022420022000
+:80290000114204114312014C021100004008901820049FEA0C2D15104212C51A578124502211290144142145121874241A8821115148682054260043628427411002851238262508A391182184182C2101A446C821260A2E444008AF3E4B524110C52244123781404241111201512112250884840011642A04703202C024902410C21285E3
+:802980001224126A4225481802001200422668822189078C043FAA04182400151248C412111221124004114410CC267014280184108114542440924823010050284414C01118431298112C0110588214004100E0940200112048440419516210012001401104542150211002004004228423A821C122410041290890114128200510042454
+:802A000084298121F1CEC42424C02814418342020016840243022110068421A154800100A44829429142409241811904411181893112410043921481008324422835424116B69D03134202200884812100160240480824112100844400112411458801401404181224128150141C0200400181278124180084004FC20E11902914302424D2
+:802A80005021001C130200506215022505451945020015984C2830224427681924B11142224151285971124124011045181858682A11E88194184076B20F272210024184C1842941941200418D1284104144088440024041022562412044082A4104444184418628021400124A012981041082C414F04B6E00000020411111541814001446
+:802B00008C411204244481401804402A41D862C112121A02441889C114259815005480812212420236024351220000AFB204264414512283921281D0228102109B128111611012314821A411421421200420422334143283444261129011111813021430111844301448304400445F580310480115140444111818D021425122440040147F
+:802B80008801502A8420011200002502410000000091400441001014220100BFF306008C410490121281112112800112890240088012068042040012439411705409180048855442401484440180942810924441A021F0F5642419018110081121C123921600800284C1C014218181C4218150482445021440140E002041842161A1122C4C
+:802C0000018CD1426113008381711488011249311F508440444602C4458212454204282124412C01814100181800214110544225014088841414024044042899228202410023022210029FD90E10922200182002008082020014450240810544B01A142102114280044880021127114041C1244004140081424210828104EFD20386318410
+:802C80000014408521224182010041000010120200001006414441000000400800818100478210524800241828F05922C018F0164240440460410044A1280060812823810221D028038C1852421840681484464218C4411C8111022B41F012412444146800002858281002BFDC0B4C31881F814144D24251112D363FA3135522182427213B
+:802D00002217A125C212218D16A78440528E4D2C702A5866272267214CE12295166B144AA15442123D16163116FC51468564112483722CC2419763468462C4497412784686011674740B573282E511528812C94111EC41611125B12382014901C791247598248CB12845744A52A11287914C11485284441FC3542247431818D0A151514074
+:802D8000B115F12244CC7341094B110024C5F2421445A233123A14F4EA26241245C6264572275524163C14542F32D28461218549519225742C4C94241264A541781102A12C0443C414657113A44424C514D3C4C429471123A21483B1114593359391221D31314913743AA8113E224E540038F0F76CB01112D281021D288002841412001C85
+:802E0000011C61821C21C2112AD418A142142A54182A7418816411481A021A021B218002282304632631421223042744122324422243A143A042F0EDB51457535753DD1F2F5272AD7F2557B9BFE3D2CFF234252D123F21F11B18AF8161216F33F31313BF31F31F3DAFD37371F761291F12F2666117561FA6F233326FA4F471371F75F11417
+:802E8000148FA5F76634AFD3F175155F51B325E333F327277F74D776F222627F72F64D5F77342F25F56363BFF5F54313EFC4F46664224F66E465F76E7E7E1462286F46F67B3F347F72F17756DFF3F22765F7F27762F5FB2F3AFFE2F2262565F61312BFA2F11A1A2F23F132337F72F31E3EED3CEFF3F37715AF85A1444F777763F1CB8A3F04
+:802F000024F46BEB37155F757114F65B7F6F43F33E1E67E74B315B371E137F74F147676F55F622627F72F64B4F37146D163F12F25B5F3F15712ADC46A2644F62F26456EFE4F644262B266AF44476BFB243D277F31746DFF253EEFDAFF5FF2B2964EFC3F22D2D35F61212AF81B31311FB1D12AF12F31E166F42F13B1C9CF612184AF4211271
+:802F80002D692D8B2FA5F5171F4F63F614165F55F43C1F6D26EFE17316FE341419F71417557735F77351BFA17143F14D1B6B732F63F32221BFB5D346D5AAD146D246F256566F67F54E7E6F4197126AD444F32DF8347F71F21652D7F1EFD6D2FF721BFE2F2F75F72F3BFFD3D263F113139D3B3F21711BF23F36E5FD1F1F6742FFE3F11E6909
+:803000009F91A1331FA6D59AD69AF83A3AEFEED657F414165F74F43A1F6D36EFE153661F13B111F7343777716F76F43311DFE17146F7491B3F12F729373F14F45D1B7F51F51D1B6F44F46E446F62D166F74F5C4F43B52281F344442F17016100104408122641084043080040040000850400100441100421100418901470240100000044BF
+:8030800040044400D0CA0F00C5020089416412158401255181814518088145081608A400D086014004D02404480011405418160813118842214111142A714222018001DFDF082E521F41F228121FC132681FC1326A1D24AF24F1112CAF14D981B24A19F54A9153F24AB157822F347B25F84AB15F82E414FB254A8F14FA254A8F15F2254A76
+:803100008F1DF2235AD6F5225A9E242E5A1F49E232F591248F32F1912C83F6916CE3F49164AB141F41B64A9961AB945B41AB944B43AF24BB34B4427B34B842FB24484AFB244AAF2B038CD541D42875117C4872117C4A52C1AB141E2C4E851D2C2BB455F8429355F8429255B84A59858B94512B945D1A8B945D828B855183FC2118874C2E35
+:803180001B87582F2265C82E5B8AE43275913C221FC914FA9168211FC1969A1B61A9FB15482D844F81D42ABA14B4483B14295A8629DBA4F1B3EE0082480000000044800200000010420280080000140000480000000000280000000014F08761401211180211409122000014508240880100148140124418080028200300004911420A44C6
+:80320000008901218001408801D048F2889B00821005246041184982114108214C32184141811008450210011185028412814100244541081628420825880140180C490824406811C08A00234C58414011C21521414911618210D24A8211684181101871120A827110110820521887422044424548028D228441450826082508184140CA25
+:80328000128416F11824AFCB0210410200002A8102001100814100001004008481244028011200006041890100211218004508820000003FE101244001412002225012400100281128A0248485012800412841201208122302002484215028128502002445081230144220042F23071D2424384114183D120018404818082441848485918D
+:8033000018142250282426026502678212498512044184C0284018A42181C011901A00160C47A12C04302C847F1A0F4D21C0214480D132022800101908604285210222148712400227226042D08202842212220000A1814438A911381390181048081818008C44F8217740022901542001205112840000214018C95884008C0250242441E0
+:8033800041321E444006448190281002810000212441498111DC26240426049FA743020067821614020090281722004004100411A1409214144004282448410048A1004480220110014180123226212A410C444B12129F64074424441400001144418420425418002100211C8121021622228131141460428012B8491204471285041008BB
+:8034000010449128004C0248212901123F9208100200002100000000501800002004410084818481261208001200004184A012842100C400410000818FAD0300216712120021008C4219024154002100811C0150141662421828904822A1002189036052CC921484841A4218421158E22228128D44211014786F076502418445020014442E
+:80348000800200845081444001C0424C0200818C711814423424A0424041140400001400004016C424004381033FD60B145028400850842210080091100400811094441028123844484148221C04288022040041A021002C2191326087444225820418F05A440018D028412412124214082810081B2189122A32210022358A010024111C03
+:8035000044A6410041465422445042F022118312D118A112311414695142428C12043848C1BF840D0080025018402A02100940842182011826C41200002606C430210041101208302144C012105281244400004D1260814480F643822415220244244418241285342310121801400284401886022743004129024548140254224422258415
+:803580000140019012811088032840288405D0AF0E108842645244406C4264000023024421008942B428140422834484264102165884A4400284851218984860810028164A44088448460842CC24F1FF464088410C8053484001242228280040180A0080120422008D2211802201A481006012481822111800281821805282221008289F42
+:8036000066061A42C2138D32120021840050A22870229228160112501823914822154414188304504242208262822822302140480226C11911153824C9862412140428441B19A018230A30214001112134400224004002000028108884110440881114021004C1418502C424244004240000404401FF5603849055800841301222401481B2
+:80368000020010582880124AC216C084222212442342111442084D4381471218142665112284C49028448412450819448C721234484F384E6211835A3863F221A46F2352B545E852D224128312092539236438298202284D64A425D65C1228D26474265A412671226691644D26A12D2C25564844D7345C21711141031F91711498224146AA
+:803700001804C716859C444E1983F4C84D90312F28A211167612011285341B8184242511084C723A581A878199713878287418BA2C262252844CD612721944B346B218924441F0246245B22CF224234D194CD2819212AFC233123D3A25D2685179AFC253468F84722442BE44E4C661534D244F2506241AD1C5D2885384448554224D1A279D
+:80378000C23C3222265A8217221249424A421852942A7143942423E14256AC724A374485F644184E1681330287128C04BB23307C9F9242D2887138312835F1141816B238E742F45A682924A12149E483F447FE10115281108151815081100115084043C811D018018D115018400185010010042211508100230221166822160816081608A4
+:80380000160840018112F0DCF41417313F33F237274F72D235F22627BFF1517EDD27CF52F221231F32521B8553311F23F221122F23F1311135F811124B335F52F2272673D246F265455F72723EFE3632777446F6327EAFB3F6272125D23272227323D2BA52AA8FC1F16F6D15D175F13A323F32D373D133F117132D328F27F346248B22A557
+:80388000B822A6548FC6F76868FFB64FF131233B44D5F725675F727227F71F1FF5FF2F237F72F227271F22F22B253553331F63F22B36173217923F83F33138FFD3F1456DFFE7F527267F5AFB252D9FF6FC7A7A6F2777477743F73A7EAFA3F723291D232F34F62A2BBF22523AA5FA5A5CF5D599F13D17EF63F32A23BFF2F31B139FB1F12ABE
+:8039000022AF26F26E248F86F64A492F26F262686AD3AAF55937F021333F22F6171345F625254F43F31D1DC5FC3D3DCFC252711F22D29952B815F334234B321D2128AF93E382529B1E1CCFD6D744F225A54FC6F62C2EFFD5F23E7B6F32E672F4321C8FA5558235D76254ADF742CFF2F21F1995FE4B4DB5F91D149FE1F13333BFB1F31B11AA
+:80398000BFB1D16EF13E3E2B448784CD4C4FC6F612588F81D1CCF1BE1D343F32F32262F5FF64255F73F33637F55FFEFFF3F126273F72E222D29F523335F33627EFC2A3319D29A5E981712CFC153FCFF4F726262BA15792CFECF67F3BEFF3F726672D63AFE1F35A5A35D164D266D4EFF22F26E5F71F1FDFF4545EBF91F11D16BFE1F12B2B6D
+:803A0000DFB1F31A119FB1F12E16AFE757CECFE6D2EEF4626C2F86F2783ACFC2F655C9200222F0241250248422004002006C0200004E24C024212880128602831404002110423824841412224021410500850642E044024F470E86022CC12C00214418C480120830248504400884D084044181452274214A14A424254A2442342C10C82430
+:803A80008D1116742A125128125084A51284F1244842451832248911F496E6C0421F41522A1FC132481FC1324A1D2CAB141D2CAB941D28AB9455B84A7935F84A915783AF147935D81AF935488D915FA2D418F8254A87115FA264192E4A87594D4A9E24ACF491243CF4912485F3912C87161F49324A1F49F26A121FC1B24AF91128AB945796
+:803B000081AB944783AB9447832B94478329F93448984FA2F47666C0481F41D62AF4112C83F4112C23D4C1B24AD1C1E244D9C1B24A5B852B945783AB845781AB84578189B83794885F2295985BC28B81572283E9A2759855B49E218C65C9BCE44946E3C97268F19124A11F49F266121FC1F248841FC1B2427B15B8427814F84A8247834AAD
+:803B8000783498AA6B4329D9A4F59CA400800400000040042800000000218001890800001400004800000000000000000040016F524B213821100528602240021322514100841002200248002100406424188100000011212218800181444828230118C44088019B37008200008188902900000000001008000085042602000000400100B3
+:803C0000400800100140083110011445F824FD142006548012682A401234213251008100404208008A014140420421851108421001142122004301224480921AC011811512681116E8D90910010000001D280000000021002280042440082280240100000000901800101821040021410010F4493D0000000000000048000000000000002C
+:803C800000000000000000000000840000000010F485990000000050822400100100000000000081404804242002000019112801001116080084000000F082AE0000000010082100190400000000000084404804108202000012811800008941081008000010F4DF8E00000000100200000000000000000000000000000014000010010067
+:803D000000000000E0D708000041000000240000000000280000000000210000100224004008001810080000006FD60F000084180000008400104402690100110012102104808442127122422401142814165422120000008241400C00FF2707100100000000000000000000000000204404000000810000000021100218844200005F3A7C
+:803D800002100140080000008100104402210028110018102104442C041001C012840021161432180080114228180400004D8200001024010000100200003014000000000042002250222861001122110021400200201188544800F09EB90000444001000000000044000000414004000000882200000040082A01001008800100004FDA3A
+:803E0000090000000000000000000000000000000000000000000020020000000000001EBE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000022000000000000EA
+:803E8000E0E10B0000000000000000000000000000000000000000000000000000000000F04FFE000000100800000000000021000040022001001002180000000000000000120000F0D2B9000000000000000000000000000000000000000000000000000000000000FFE40F0010080000000000000000000000000000000000000000005C
+:803F0000000000000000DFDF04000000000000000000000000000000000000000081000000000000000000EF2C07000000000000000000000000000000000000000000000000000020020000EF1C040000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000100200002400180000001808
+:803F80000010080000000000200100001B5700008400840000000000000000000000000010020000000000000000800200006EDB000000000000000000000000000000000000000000000000000000000000FFE40F000000004005000040040021004400100218808802218001884008000028840000800200004FB1070014000048405585
+:8040000088281082044480022100448002214818808802214818448828842148408481421882041E148002211A01445C0300004001008004540000484004000040040000008002000088000000804208000000F0469900000000005400000044001002400400218001882810021880088400840028840000800200005FF90B000000000091
+:80408000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F002100140000480080022148008002000080028004000080044480022148400400214840040021FF18040000000000000000000000000000000000000000000000000000C1
+:80410000000000F04FFE000000000000400500440000000040040000280000000088000000804208000000F0D2ED000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000044000000000000008002000000000000000000000000F02BAF000000000000400500000000000044000000000001
+:3E418000000088000000804208000000F0B6BCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C
+:00000001FF
diff --git a/drivers/dahdi/xpp/firmwares/LICENSE.firmware b/drivers/dahdi/xpp/firmwares/LICENSE.firmware
new file mode 100644
index 0000000..b9bb89f
--- /dev/null
+++ b/drivers/dahdi/xpp/firmwares/LICENSE.firmware
@@ -0,0 +1,37 @@
+The firmware files (*.hex) in this directory are software for the
+Astribank itself and not intended to run on the Linux system itself.
+They are generally freely distriributable (see exact terms below).
+
+/****************************************************************************/
+/* Copyright (c) 2004-2006 Xorcom Inc. All Rights Reserved. */
+/* Redistribution and use of the microcode software ( Firmware ) is */
+/* permitted provided that the following conditions are met: */
+/* */
+/* 1. Firmware is redistributed verbatim without any modification; */
+/* 2. Any reproduction of Firmware must contain the above */
+/* copyright notice, this list of conditions and the below */
+/* disclaimer in the documentation and/or other materials */
+/* provided with the distribution; and */
+/* 3. The name of Xorcom may not be used to endorse or promote */
+/* products derived from this Firmware without specific prior */
+/* written consent. */
+/* */
+/* Disclaimer: Xorcom provides this firmware "as is" with no warranties */
+/* or indemnities whatsoever. Xorcom expressly disclaims any express, */
+/* statutory or implied warranties, including, but not limited to, the */
+/* implied warranties of merchantability, fitness for a particular */
+/* purpose and non-infringement. In no event shall Xorcom be liable for */
+/* any direct, indirect, incidental, special, exemplary, or consequential */
+/* damages (including, but not limited to, procurement of substitute */
+/* goods or services; loss of use, data, or profits; or business */
+/* interruption) however caused and on any theory of liability, whether */
+/* in contract, strict liability, or tort (including negligence or */
+/* otherwise) arising in any way out of the use of this firmware, even */
+/* if advised of the possibility of such damage. User acknowledges and */
+/* agrees that the purchase or use of the firmware will not create or */
+/* give grounds for a license by implication, estoppel, or otherwise in */
+/* any intellectual property rights (patent, copyright, trade secret, */
+/* mask work, or other proprietary right) embodied in any other Xorcom */
+/* hardware or firmware either solely or in combination with the firmware. */
+/****************************************************************************/
+
diff --git a/drivers/dahdi/xpp/firmwares/README b/drivers/dahdi/xpp/firmwares/README
new file mode 100644
index 0000000..e423aa6
--- /dev/null
+++ b/drivers/dahdi/xpp/firmwares/README
@@ -0,0 +1,19 @@
+This distribution includes the firmware files required by the Xorcom[tm]
+Astribank[tm].
+
+This distribution inlcudes just the firmware files. Be sure to use a
+zaptel distribution/package of a matching version.
+
+INSTALLATION
+""""""""""""
+run "make install" as root. (which will simply copy all the *.hex files
+to /usr/share/zaptel )
+
+USAGE
+"""""
+When the firmware files are in place everything should work
+automagically. Consult the xpp documentation included in the package
+zaptel (or the debian package zaptel) that you use for further information.
+
+
+For further information contact support@xorcom.com http://xorcom.com
diff --git a/drivers/dahdi/xpp/firmwares/USB_FW.hex b/drivers/dahdi/xpp/firmwares/USB_FW.hex
new file mode 100644
index 0000000..01f7ce9
--- /dev/null
+++ b/drivers/dahdi/xpp/firmwares/USB_FW.hex
@@ -0,0 +1,223 @@
+#
+# $Id:$
+#
+:100600001201000200000040E4E451110000010268
+:1006100003010A0600020000004001000902370041
+:1006200002010080320904000002FF0000040705F7
+:100630000202000200070586020002000904010010
+:1006400002FF0000050705040200020007058802FA
+:100650000002000902370002010080320904000094
+:1006600002FF0000040705020240000007058602A1
+:100670004000000904010002FF0000050705040214
+:100680004000000705880240000004030904160327
+:1006900058006F00720063006F006D0020004C0076
+:1006A0005400440014034100730074007200690098
+:1006B000620061006E006B001203490053004E009F
+:1006C00075006D006200650072000A03460050006C
+:1006D000470041002A034D0061006E006100670081
+:1006E00065006D0065006E0074002000500072000F
+:1006F0006F0063006500730073006F0072000000FC
+:0B0B6C00C2B675B5C4120B18D2B62239
+:100A6300E4901010F07A107B107D017F50120A9FE2
+:100A73007F501208567A107B007D107F50020A8344
+:1008F8007F031209EBEF2402FFE43EFEE516C394E2
+:1009080008501F74082516F582E43410F583E0FDBD
+:100918008F828E8375F002E5161205E8EDF0051654
+:0209280080DA73
+:01092A0022AA
+:10092B00E50B240AFDE4350AFC901003E02FFF0DC4
+:10093B00EDAA0470010C14F5828A83EFF090100479
+:10094B00E08D828C83F0D20512099090E680E05402
+:02095B00F7F0B3
+:01095D002277
+:1007000090E600E054E74410F090E60174C0F090E9
+:10071000E6107420F000000090E611F00000009058
+:10072000E6047480F0000000740FF0000000E4F0B4
+:1007300000000090E6187410F0000000E490E61944
+:10074000F000000090E61A7408F0000000E490E663
+:100750001BF000000090E6497482F0000000F000F9
+:10076000000090E6247402F0000000E490E625F01A
+:1007700000000090E6957480F0000000F00000009A
+:0407800043AF012260
+:040B18007F327E00AA
+:100B1C007C007D181205D6EF1FAC0670011E4C70C0
+:020B2C00F622AF
+:0A0784008E188F198B1A8A1B891C2E
+:10078E00E4F51DF51EC3E51E9519E51D95185033AC
+:10079E00AB1AAA1BA91C851E82851D83120587FF15
+:1007AE00E4FEC2B2EF1392B7EFC313FFD2B20EBE86
+:1007BE0008F0C2B220B002C322051EE51E70C605A7
+:0407CE001D80C2D3F5
+:0107D2002204
+:10029200E4901010F0F516F517C204E5AA54846034
+:1002A200030203F990F400E024FE700302036524C4
+:1002B200FA700302038724F870030203B324F07078
+:1002C200030203BD24E070030203D824C0700302BA
+:1002D20003D8247F60030203CC75160075170490BF
+:1002E200FC007401F090F401E090FC01F090F40243
+:1002F200E090FC02F090F401E07017A3E07013307C
+:10030200B01090E60174C0F0C2B6120B18D2B61249
+:100312000B1820B00330B44390E694E0FE90E695CB
+:10032200E07C002400FFEC3ECF24FCCF34FFFE7BB8
+:10033200017AF47904120784501990FC0330B40D49
+:100342007408F07FE87E03120B1C0203D87404F0D9
+:100352000203D890FC037402F0807B90FC037401CA
+:10036200F0807375160075170490FC007402F0E4B7
+:10037200A3F0A3F030B406A37410F0805990FC03EC
+:100382007420F0805175160075171190FC007408E6
+:10039200F0E4FF74002FF582E43410F583E0FE747C
+:1003A200012FF582E434FCF583EEF00FBF10E480F8
+:1003B2002590E6017403F07F02800A90E60174C082
+:1003C200F0C2B6E4FF12092B800C751600751701F6
+:1003D20090FC0074AAF0E51745166012E51690E647
+:1003E2009CF0000000E51790E69DF000000090E60A
+:0703F200957480F00000008B
+:0103F90022E1
+:020AFD00D32202
+:080B8C0090E6BAE0F528D3223F
+:100AEB0090E740E528F0E490E68AF090E68B04F07E
+:020AFB00D32204
+:080B940090E6BAE0F527D32238
+:100B5A0090E740E527F0E490E68AF090E68B04F00F
+:020B6A00D32294
+:100A160090E6B9E0242F600D04701990E604E0FF1B
+:100A2600430780800890E604E0FF53077F0000003C
+:070A3600EFF08002D322C3A0
+:010A3D002296
+:100ABB00C0E0C083C082D2015391EF90E65D740118
+:080ACB00F0D082D083D0E032AC
+:100B2E00C0E0C083C0825391EF90E65D7404F0D0B4
+:060B3E0082D083D0E032FA
+:100B4400C0E0C083C0825391EF90E65D7402F0D0A0
+:060B540082D083D0E032E4
+:10088E00C0E0C083C08285100C85110D850D828558
+:10089E000C83A37402F085080E85090F850F8285DF
+:1008AE000E83A37407F05391EF90E65D7410F0D0B1
+:0608BE0082D083D0E0327D
+:100AD300C0E0C083C082D2035391EF90E65D7408F7
+:080AE300F0D082D083D0E03294
+:10081900C0E0C083C08290E680E030E72085080C04
+:1008290085090D850D82850C83A37402F085100E50
+:1008390085110F850F82850E83A37407F05391EFFD
+:0D08490090E65D7420F0D082D083D0E032C4
+:0A0B8200000102020303040405054C
+:10050200C203C200C202C201120B6C120700120B1C
+:100512009C120A63750A06750B0075120675131292
+:1005220075080675091C7510067511537514067544
+:10053200158AD2E843D82090E668E04409F090E6B4
+:100542005CE0443DF0D2AF1208F87F0112092B5350
+:100552008EF8C203120292300105120070C20130FD
+:1005620003F2C203120A3E20001690E682E030E750
+:1005720004E020E1EF90E682E030E604E020E0E4EF
+:050582001209BF80CF4B
+:0B0B770090E50DE030E402C322D32221
+:1000700090E6B9E0700302012F1470030201A4247A
+:10008000FE700302021F24FB700302012914700397
+:1000900002012314700302011714700302011D24CE
+:1000A00005600302027E120AFD400302028A90E606
+:1000B000BBE024FE602714603824FD601114602723
+:1000C00024067050E50A90E6B3F0E50B803C120B75
+:1000D00077503EE51290E6B3F0E513802DE50C90E5
+:1000E000E6B3F0E50D8023E50E90E6B3F0E50F8072
+:1000F0001990E6BAE0FF1209EBAA06A9077B01EA0C
+:10010000494B600DEE90E6B3F0EF90E6B4F00202DA
+:100110008A020279020279120B5A02028A120B94A5
+:1001200002028A120B8C02028A120AEB02028A90E5
+:10013000E6B8E0247F601514601924027063A20001
+:10014000E43325E0FFA202E4334F8041E490E7402E
+:10015000F0803F90E6BCE0547EFF7E00E0D39480C8
+:100160007C0040047D0180027D00EC4EFEED4F24BA
+:1001700082F582740B3EF583E493FF3395E0FEEF46
+:1001800024A1FFEE34E68F82F583E0540190E7402E
+:10019000F0E4A3F090E68AF090E68B7402F002029D
+:1001A0008A02027990E6B8E024FE60162402600319
+:1001B00002028A90E6BAE0B40105C20002028A0295
+:1001C000027990E6BAE0705590E6BCE0547EFF7E7E
+:1001D00000E0D394807C0040047D0180027D00EC2F
+:1001E0004EFEED4F2482F582740B3EF583E493FFBF
+:1001F0003395E0FEEF24A1FFEE34E68F82F583E035
+:1002000054FEF090E6BCE05480131313541FFFE03B
+:10021000540F2F90E683F0E04420F0806D805A90D8
+:10022000E6B8E024FE60192402704E90E6BAE0B40D
+:100230000104D200805490E6BAE06402604C803938
+:1002400090E6BCE0547EFF7E00E0D394807C0040CA
+:10025000047D0180027D00EC4EFEED4F2482F5828C
+:10026000740B3EF583E493FF3395E0FEEF24A1FF8A
+:10027000EE34E68F82F583800D90E6A08008120AA6
+:1002800016500790E6A0E04401F090E6A0E044801C
+:01029000F07D
+:01029100224A
+:03003300020BA419
+:040BA40053D8EF3201
+:03004300020B00AD
+:03005300020B009D
+:100B0000020ABB00020B4400020B2E00020AD300B3
+:080B100002088E000208190022
+:1009BF0090E682E030E004E020E60B90E682E03043
+:1009CF00E119E030E71590E680E04401F07F147EF6
+:0C09DF00001207D390E680E054FEF022E6
+:1009900030050990E680E0440AF0800790E680E0A8
+:1009A0004408F07FDC7E051207D390E65D74FFF00B
+:0F09B00090E65FF05391EF90E680E054F7F0226D
+:080B9C00E4F526D2E9D2AF22F4
+:10085600AD0790E678E020E6F9C2E990E678E04454
+:1008660080F0ED25E090E679F090E678E030E0F96A
+:1008760090E678E04440F090E678E020E6F990E6ED
+:0808860078E030E1D6D2E9224E
+:10095E00AC0790E678E020E6F9E526702390E6787D
+:10096E00E04480F0EC25E090E679F08D21AF03A90C
+:10097E00077522018A238924E4F525752601D322E1
+:02098E00C32282
+:1008C400AC0790E678E020E6F9E526702590E67816
+:1008D400E04480F0EC25E0440190E679F08D21AF0E
+:1008E40003A9077522018A238924E4F525752603C3
+:0408F400D322C32226
+:03004B000203FAB3
+:1003FA00C0E0C083C082C085C084C086758600C044
+:10040A00D075D000C000C001C002C003C006C0073A
+:10041A0090E678E030E2067526060204E490E67873
+:10042A00E020E10CE526640260067526070204E472
+:10043A00E52624FE605F14603624FE70030204D5AC
+:10044A0024FC70030204E1240860030204E4AB22E2
+:10045A00AA23A924AF2505258F8275830012058753
+:10046A0090E679F0E52565217070752605806B9018
+:10047A00E679E0AB22AA23A924AE258E82758300F1
+:10048A001205B4752602E5216401704E90E678E003
+:10049A004420F08045E52124FEB5250790E678E062
+:1004AA004420F0E52114B5250A90E678E04440F0AE
+:1004BA0075260090E679E0AB22AA23A924AE258E00
+:1004CA00827583001205B40525800F90E678E04412
+:1004DA0040F075260080037526005391DFD007D0BF
+:1004EA0006D003D002D001D000D0D0D086D084D09C
+:0804FA0085D082D083D0E032EE
+:0209EB00A9075A
+:1009ED00AE14AF158F828E83A3E064037017AD0133
+:1009FD0019ED7001228F828E83E07C002FFDEC3E7D
+:080A0D00FEAF0580DFE4FEFFEF
+:010A150022BE
+:100A83001208C4E52624FA600E146006240770F3E6
+:0C0A9300D322E4F526D322E4F526D3227A
+:100A9F0012095EE52624FA600E146006240770F32F
+:0C0AAF00D322E4F526D322E4F526D3225E
+:100A3E0090E682E044C0F090E681F043870100002A
+:040A4E000000002282
+:1007D3008E188F1990E600E054187012E519240161
+:1007E300FFE43518C313F518EF13F519801590E6D8
+:1007F30000E05418FFBF100BE51925E0F519E518C3
+:1008030033F518E5191519AE18700215184E600561
+:06081300120A5280EE22E1
+:100A52007400F58690FDA57C05A3E582458370F9B7
+:010A62002271
+:030000000205F402
+:0C05F400787FE4F6D8FD7581280205022E
+:10058700BB010CE58229F582E5833AF583E0225029
+:1005970006E92582F8E622BBFE06E92582F8E22273
+:0D05A700E58229F582E5833AF583E493228D
+:1005B400F8BB010DE58229F582E5833AF583E8F07D
+:1005C400225006E92582C8F622BBFE05E92582C829
+:0205D400F22211
+:1005D600EF8DF0A4A8F0CF8CF0A428CE8DF0A42E39
+:0205E600FE22F3
+:0C05E800A42582F582E5F03583F583221E
+:00000001FF
+ \ No newline at end of file
diff --git a/drivers/dahdi/xpp/init_card_1_30 b/drivers/dahdi/xpp/init_card_1_30
new file mode 100755
index 0000000..68a6d02
--- /dev/null
+++ b/drivers/dahdi/xpp/init_card_1_30
@@ -0,0 +1,535 @@
+#! /usr/bin/perl -w
+use strict;
+
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2006, Xorcom
+#
+# 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.
+#
+# See the file LICENSE in the top level of this tarball.
+#
+
+#
+# $Id$
+#
+# Data format:
+# - A comment start with ';' or '#' until the end of line
+# - Blank lines are ignored
+# - Fields are whitespace separated (spaces or tabs)
+#
+# The fields are (in command line order):
+# 1. SLIC select in decimal (range 0-7).
+# * is a special value which means ALL SLICS (only some registers
+# accept settings for ALL SLICS).
+# 2. Command word:
+# - RD Read Direct register.
+# - RI Read Indirect register.
+# - WD Write Direct register.
+# - WI Write Indirect register.
+# 3. Register number in hexadecimal.
+# 4. Low data byte in hexadecimal. (for WD and WI commands).
+# 5. High data byte in hexadecimal. (for WI command only).
+#
+#
+
+package main;
+use File::Basename;
+use Getopt::Std;
+
+my $program = basename("$0");
+my $init_dir = dirname("$0");
+BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf"); }
+use Zaptel::Config::Defaults;
+my $unit_id;
+my %opts;
+$ENV{XPP_BASE} = '/proc/xpp';
+
+getopts('o:', \%opts);
+
+my $debug;
+my $skip_calib;
+
+my $xpd_name = sprintf("XPD-%1d0", $ENV{UNIT_NUMBER});
+my $chipregs = "$ENV{XPP_BASE}/$ENV{XBUS_NAME}/$xpd_name/chipregs";
+
+sub logit {
+ print STDERR "$unit_id: @_\n";
+}
+
+sub debug {
+ logit @_ if $debug;
+}
+
+# Arrange for error logging
+if (-t STDERR) {
+ $unit_id = 'Interactive';
+ logit "Interactive startup";
+} else {
+ $unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
+ open (STDERR, "| logger -t $program -p kern.info") || die;
+ logit "Non Interactive startup";
+}
+
+sub set_output() {
+ my $output;
+
+ if($opts{o}) {
+ $output = $opts{o};
+ } else {
+ # No subunits in FXS (everything is subunit 0)
+ $output = $chipregs;
+ }
+ open(REG, ">$output") || die "Failed to open '$output': $!\n";
+ my $oldfh = select REG;
+ print "# Setting output\n" if $opts{o};
+ return $oldfh;
+}
+
+sub mysleep($) {
+ my $timeout = shift;
+ select(undef,undef,undef,$timeout);
+}
+
+package FXS;
+
+sub gen {
+ my $fmt = shift;
+ $| = 1;
+ printf "$fmt\n", @_;
+}
+
+my @SlicNums = (0 .. 7);
+
+sub write_to_slic_file($) {
+ my $write_str = shift;
+
+ open(SLICS,">$chipregs") or
+ die("Failed writing to chipregs file $chipregs");
+ print SLICS $write_str;
+ close(SLICS) or die "Failed writing '$write_str' to '$chipregs': $!";
+ main::mysleep(0.001);
+
+}
+
+sub read_reg($$$) {
+ my $read_slic = shift;
+ my $read_reg = shift;
+ my $direct = shift;
+
+ write_to_slic_file(
+ sprintf("%s R%s %02X", $read_slic, $direct, $read_reg));
+ main::mysleep(0.005);
+ open(SLICS,$chipregs) or
+ die("Failed reading from chipregs file $chipregs");
+ #awk '/^SLIC_REPLY:/{print $5}' $SLICS | cut -dx -f2
+ my @reply = ();
+ while(<SLICS>){
+ #if (/^ /) {
+ # main::debug "answer line: $_";
+ #}
+ s/#.*//;
+ next unless /\S/;
+ if (/^ \d*\s+[RW][DI]\s+[[:xdigit:]]+\s+([[:xdigit:]]+)\s+([[:xdigit:]]*)/){
+ @reply = (hex($1), hex($2));
+ #main::debug "got [$reply]";
+ last;
+ } else {
+ main::logit("Got from '$chipregs' a non-matching line '$_'");
+ }
+ }
+ close(SLICS);
+ die("Failed reading from '$chipregs' ($read_slic,$read_reg,$direct)")
+ unless @reply;
+ if ($direct eq 'I') {
+ return @reply;
+ } else {
+ return $reply[0];
+ }
+}
+
+# TODO: rearange arguments
+sub write_reg{#($$$$$) {
+ my $read_slic = shift;
+ my $read_reg = shift;
+ my $direct = shift;
+ my $reg_val_low = shift;
+ my $reg_val_hi = shift;
+
+ my $str = sprintf "%s W%s %02X %02X",
+ $read_slic, $direct, $read_reg, $reg_val_low;
+ if ($direct eq 'I') {
+ $str .= sprintf " %02X", $reg_val_hi;
+ }
+ write_to_slic_file($str);
+}
+
+sub log_calib_params() {
+ for my $i (100 .. 107) {
+ my $line="Calib Reg $i: ";
+ for my $slic (@SlicNums) {
+ $line .= " ".read_reg($slic, $i, 'D');
+ }
+ main::debug($line);
+ }
+}
+
+sub init_indirect_registers() {
+ return write_to_slic_file("#
+* WI 1E 00 C2 55
+* WI 1E 01 E6 51
+* WI 1E 02 85 4B
+* WI 1E 03 37 49
+
+* WI 1E 04 33 33
+* WI 1E 05 02 02
+* WI 1E 06 02 02
+* WI 1E 07 98 01
+
+* WI 1E 08 98 01
+* WI 1E 09 11 06
+* WI 1E 0A 02 02
+* WI 1E 0B E5 00
+
+* WI 1E 0C 1C 0A
+* WI 1E 0D 30 7B
+* WI 1E 0E 63 00
+* WI 1E 0F 00 00
+
+* WI 1E 10 70 78
+* WI 1E 11 7D 00
+* WI 1E 12 00 00
+* WI 1E 13 00 00
+
+* WI 1E 14 F0 7E
+* WI 1E 15 C0 01
+* WI 1E 16 00 00
+* WI 1E 17 00 20
+
+* WI 1E 18 00 20
+* WI 1E 19 00 00
+* WI 1E 1A 00 20
+* WI 1E 1B 00 40
+
+* WI 1E 1C 00 10
+* WI 1E 1D 00 36
+* WI 1E 1E 00 10
+* WI 1E 1F 00 02
+
+* WI 1E 20 C0 07
+* WI 1E 21 00 26
+* WI 1E 22 F4 0F
+* WI 1E 23 00 80
+
+#* WI 1E 24 20 03
+#* WI 1E 25 8C 08
+#* WI 1E 26 00 01
+#* WI 1E 27 10 00
+
+* WI 1E 24 00 08
+* WI 1E 25 00 08
+* WI 1E 26 00 08
+* WI 1E 27 00 08
+
+* WI 1E 28 00 0C
+* WI 1E 29 00 0C
+* WI 1E 2B 00 01
+
+* WI 1E 63 DA 00
+* WI 1E 64 60 6B
+* WI 1E 65 74 00
+* WI 1E 66 C0 79
+
+* WI 1E 67 20 11
+* WI 1E 68 E0 3B
+#");
+}
+
+sub init_early_direct_regs() {
+ return write_to_slic_file("#
+* WD 08 00 # Audio Path Loopback Control
+* WD 4A 34 # High Battery Voltage
+* WD 4B 10 # Low Battery Voltage
+* WD 40 00 # Line Feed Control
+#")
+}
+
+my @FilterParams = ();
+
+sub save_indirect_filter_params() {
+ for my $slic (@SlicNums) {
+ for my $reg (35 .. 39) {
+ $FilterParams[$slic][$reg] =
+ [read_reg($slic, $reg, 'I')];
+ write_reg($slic, $reg, 'I', 0, 0x80);
+ }
+ }
+
+}
+
+sub restore_indirect_filter_params() {
+ for my $slic (@SlicNums) {
+ for my $reg (35 .. 39) {
+ write_reg($slic, $reg, 'I',
+ @{$FilterParams[$slic][$reg]});
+ }
+ }
+}
+
+my $ManualCalibrationSleepTime = 0.04; # 40ms
+
+sub manual_calibrate_loop($$) {
+ my $write_reg = shift;
+ my $read_reg = shift;
+
+ # counters to count down to (at most) 0
+ my @slic_counters = ();
+ for my $i (0 .. $#SlicNums) {
+ $slic_counters[$i] = 0x1F;
+ }
+
+ # start calibration:
+ my $calibration_in_progress = 1;
+ write_reg('*', $write_reg, 'D', 0x1F);
+ main::mysleep $ManualCalibrationSleepTime;
+
+ # wait until all slics have finished calibration, or for timeout
+ while ($calibration_in_progress) {
+ $calibration_in_progress = 0; # until proven otherwise
+ my $debug_calib_str = "ManualCalib:: ";
+ for my $slic(@SlicNums) {
+ my $value = read_reg($slic, $read_reg, 'D');
+ $debug_calib_str .= " [$slic_counters[$slic]:$value]";
+ if ($value != 0 && $slic_counters[$slic] > 0) {
+ $calibration_in_progress = 1;
+ $slic_counters[$slic]--;
+ write_reg($slic,$write_reg,'D',$slic_counters[$slic]);
+ }
+ }
+ main::debug($debug_calib_str);
+ # TODO: unnecessary sleep in the last round:
+ main::mysleep $ManualCalibrationSleepTime;
+ }
+}
+
+sub manual_calibrate() {
+ manual_calibrate_loop(98, 88);
+ manual_calibrate_loop(99, 89);
+}
+
+sub auto_calibrate($$) {
+ my $calib_96 = shift;
+ my $calib_97 = shift;
+
+ #log_calib_params();
+ # start calibration:
+ write_to_slic_file(
+ sprintf
+ "* WD 60 %02X\n".
+ "* WD 61 %02X\n".
+ "", $calib_96, $calib_97
+
+ );
+ # wait until all slics have finished calibration, or for timeout
+ my $sleep_cnt = 0;
+ # time periods in seconds:
+ my $sleep_time = 0.1;
+ my $timeout_time = 2;
+ CALIB_LOOP: for my $slic (@SlicNums) {
+ main::debug("checking slic $slic");
+ while(1) {
+ if ((read_reg($slic, 60, 'D')) == 0) {
+ # move to next register
+ main::debug("slic $slic calibrated");
+ last;
+ }
+ if ( $sleep_cnt > $timeout_time/$sleep_time) {
+ main::debug("Auto Calibration: Exiting on timeout: $timeout_time.");
+ last CALIB_LOOP;
+ }
+ main::debug("auto_calibrate not done yet: slic #$slic");
+ main::mysleep(0.1);
+ $sleep_cnt++;
+ }
+ }
+ #log_calib_params();
+}
+
+sub calibrate_slics() {
+ main::logit "Calibrating '$0'";
+ auto_calibrate(0x47, 0x1E);
+ main::debug "after auto_calibrate";
+ manual_calibrate();
+ main::debug "after manul_calibrate";
+ auto_calibrate(0x40, 0x01);
+ main::debug "after auto_calibrate 2";
+ main::logit "Continue '$0'";
+}
+
+sub read_defaults() {
+ # For lab tests
+ my $labfile = "$init_dir/genzaptelconf.env";
+
+ # Source default files
+ $ENV{ZAPTEL_DEFAULTS} = "$labfile" if -r "$labfile";
+ my $var_debug = 'DEBUG_INIT_FXS';
+ my $var_skip_calib = 'INIT_FXS_SKIP_CALIB';
+ my ($default_file, %source_defaults) =
+ Zaptel::Config::Defaults::source_vars($var_debug, $var_skip_calib);
+ $debug = $source_defaults{$var_debug};
+ $skip_calib = $source_defaults{$var_skip_calib};
+ main::logit "From $default_file: $var_debug=$debug $var_skip_calib=$skip_calib";
+}
+
+package main;
+
+main::logit "Starting '$0'";
+
+FXS::read_defaults;
+main::debug "before init_indirect_registers";
+FXS::init_indirect_registers();
+main::debug "after init_indirect_registers";
+FXS::init_early_direct_regs();
+main::debug "after init_early_direct_regs";
+if($skip_calib) {
+ main::logit "==== WARNING: SKIPPED SLIC CALIBRATION =====";
+} else {
+ FXS::calibrate_slics;
+}
+set_output;
+while(<DATA>) {
+ chomp;
+ s/[#;].*$//; # remove comments
+ s/^\s+//; # trim whitespace
+ s/\s+$//; # trim whitespace
+ s/\t+/ /g; # replace tabs with spaces (for logs)
+ next unless /\S/; # Skip empty lines
+ main::debug "writing: '$_'";
+ print "$_\n";
+}
+close REG;
+
+main::logit "Ending '$0'";
+close STDERR;
+exit 0;
+
+# ----------------------------------==== 8-channel FXS unit initialization ===-----------------------------------------
+
+__DATA__
+# Change SLICs states to "Open state"s (Off,all transfers tristated to avoid data collision), Voltage sense
+* WD 40 00
+
+# Flush out energy accumulators
+* WI 1E 58 00 00
+* WI 1E 59 00 00
+* WI 1E 5A 00 00
+* WI 1E 5B 00 00
+* WI 1E 5C 00 00
+* WI 1E 5D 00 00
+* WI 1E 5E 00 00
+* WI 1E 5F 00 00
+* WI 1E 61 00 00
+* WI 1E 58 00 00
+* WI 1E C1 00 00
+* WI 1E C2 00 00
+* WI 1E C3 00 00
+* WI 1E C4 00 00
+* WI 1E C5 00 00
+* WI 1E C6 00 00
+* WI 1E C7 00 00
+* WI 1E C8 00 00
+* WI 1E C9 00 00
+* WI 1E CA 00 00
+* WI 1E CB 00 00
+* WI 1E CC 00 00
+* WI 1E CD 00 00
+* WI 1E CE 00 00
+* WI 1E CF 00 00
+* WI 1E D0 00 00
+* WI 1E D1 00 00
+* WI 1E D2 00 00
+* WI 1E D3 00 00
+
+# Setting of SLICs offsets
+# New card initialization
+0 WD 02 00
+0 WD 04 00
+1 WD 02 08
+1 WD 04 08
+2 WD 02 10
+2 WD 04 10
+3 WD 02 18
+3 WD 04 18
+4 WD 02 20
+4 WD 04 20
+5 WD 02 28
+5 WD 04 28
+6 WD 02 30
+6 WD 04 30
+7 WD 02 38
+7 WD 04 38
+* WD 03 00
+* WD 05 00
+
+# Audio path. (also initialize 0A and 0B here if necessary)
+* WD 08 00
+* WD 09 C0
+
+# Automatic/Manual Control: defaults but:
+# Cancel AOPN - Power Alarm
+# Cancel ABAT - Battery Feed Automatic Select
+* WD 43 16
+
+# Loop Closure Debounce Interval
+* WD 45 0A
+
+# Ring Detect Debounce Interval
+* WD 46 47
+
+# Battery Feed Control: Battery low (DCSW low)
+* WD 42 00
+
+# Loop Current Limit
+* WD 47 00
+
+# Ring VBath:
+* WD 4A 3F
+
+
+* WD 6C 01
+
+* WI 1E 23 00 80
+* WI 1E 24 20 03
+* WI 1E 25 8C 08
+* WI 1E 26 00 01
+* WI 1E 27 10 00
+
+#------ Metering tone
+* WI 1E 17 61 15 # Amplitue Ramp-up
+* WI 1E 18 61 15 # Max Amplitude
+* WI 1E 19 FB 30 # Frequency
+* WD 2C 00 # Timer dL
+* WD 2D 03 # Timer dH
+
+# ------------------------------------- Initialization of direct registers --------------------------------------------
+
+# Mode(8-bit,u-Law,1 PCLK ) setting, Loopbacks and Interrupts clear
+
+* WD 01 29
+#* WD 0E 00
+
+#* WD 15 00
+#* WD 16 03
+
+# Clear pending interrupts
+* WD 12 FF
+* WD 13 FF
+* WD 14 FF
+
+#* WD 4A 34
+#* WD 4B 10
diff --git a/drivers/dahdi/xpp/init_card_2_30 b/drivers/dahdi/xpp/init_card_2_30
new file mode 100755
index 0000000..c682c19
--- /dev/null
+++ b/drivers/dahdi/xpp/init_card_2_30
@@ -0,0 +1,417 @@
+#! /usr/bin/perl -w
+use strict;
+
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2006, Xorcom
+#
+# 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.
+#
+# See the file LICENSE in the top level of this tarball.
+#
+
+#
+# $Id$
+#
+# Data format:
+# - A comment start with ';' or '#' until the end of line
+# - Blank lines are ignored
+# - Fields are whitespace separated (spaces or tabs)
+#
+# The fields are (in command line order):
+# 1. SLIC select in decimal (range 0-7).
+# * is a special value which means ALL SLICS (only some registers
+# accept settings for ALL SLICS).
+# 2. Command word:
+# - RD Read Direct register.
+# - RI Read Indirect register.
+# - WD Write Direct register.
+# - WI Write Indirect register.
+# 3. Register number in hexadecimal.
+# 4. Low data byte in hexadecimal. (for WD and WI commands).
+# 5. High data byte in hexadecimal. (for WI command only).
+#
+#
+
+package main;
+use File::Basename;
+use Getopt::Std;
+
+my $program = basename("$0");
+my $init_dir = dirname("$0");
+BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf", "$init_dir/utils/zconf"); }
+use Zaptel::Config::Defaults;
+my $unit_id;
+my %opts;
+$ENV{XPP_BASE} = '/proc/xpp';
+
+getopts('o:', \%opts);
+
+my $debug;
+
+my $xpd_name;
+my $chipregs;
+
+sub logit {
+ print STDERR "$unit_id: @_\n";
+}
+
+sub debug {
+ logit @_ if $debug;
+}
+
+# Arrange for error logging
+if (-t STDERR) {
+ $unit_id = 'Interactive';
+ main::debug "Interactive startup";
+} else {
+ $unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
+ $xpd_name = sprintf("XPD-%1d0", $ENV{UNIT_NUMBER});
+ $chipregs = "$ENV{XPP_BASE}/$ENV{XBUS_NAME}/$xpd_name/chipregs";
+ open (STDERR, "| logger -t $program -p kern.info") || die;
+ main::debug "Non Interactive startup";
+}
+
+sub set_output() {
+ my $output;
+
+ if($opts{o}) {
+ $output = $opts{o};
+ } else {
+ # No subunits in FXS (everything is subunit 0)
+ $output = $chipregs;
+ }
+ open(REG, ">$output") || die "Failed to open '$output': $!\n";
+ my $oldfh = select REG;
+ main::logit "# Setting output" if $opts{o};
+ return $oldfh;
+}
+
+package FXO;
+
+sub gen {
+ my $fmt = shift;
+ $| = 1;
+ printf "$fmt\n", @_;
+}
+
+my $OPERMODE = 'FCC';
+
+sub turn_off_leds() {
+ # Turning off red LEDs
+ # Warning: do not send WD 31 20 A0 !
+ foreach my $i (0..7) {
+ FXO::gen "$i WD 20 A0";
+ }
+}
+
+# This data is manually taken from utils/init_fxo_modes which is generated
+# during build.
+# Running this script with a single 'verify' argument, during build,
+# compare this data to a (possibly updated) utils/init_fxo_modes file.
+my $OPERMODE_DATA = "
+FCC reg16=01 reg26=C0 reg30=00 reg31=20
+TBR21 reg16=00 reg26=C2 reg30=02 reg31=20 ring_osc=7E6C ring_x=023A
+ARGENTINA reg16=00 reg26=C0 reg30=00 reg31=20
+AUSTRALIA reg16=40 reg26=30 reg30=03 reg31=20
+AUSTRIA reg16=00 reg26=C2 reg30=03 reg31=28
+BAHRAIN reg16=00 reg26=C2 reg30=02 reg31=20
+BELGIUM reg16=00 reg26=C2 reg30=02 reg31=28
+BRAZIL reg16=00 reg26=30 reg30=00 reg31=20
+BULGARIA reg16=00 reg26=C2 reg30=03 reg31=20
+CANADA reg16=00 reg26=C0 reg30=00 reg31=20
+CHILE reg16=00 reg26=C0 reg30=00 reg31=20
+CHINA reg16=00 reg26=30 reg30=0F reg31=20
+COLUMBIA reg16=00 reg26=C0 reg30=00 reg31=20
+CROATIA reg16=00 reg26=C2 reg30=02 reg31=20
+CYRPUS reg16=00 reg26=C2 reg30=02 reg31=20
+CZECH reg16=00 reg26=C2 reg30=02 reg31=20
+DENMARK reg16=00 reg26=C2 reg30=02 reg31=28
+ECUADOR reg16=00 reg26=C0 reg30=00 reg31=20
+EGYPT reg16=00 reg26=30 reg30=00 reg31=20
+ELSALVADOR reg16=00 reg26=C0 reg30=00 reg31=20
+FINLAND reg16=00 reg26=C2 reg30=02 reg31=28
+FRANCE reg16=00 reg26=C2 reg30=02 reg31=28
+GERMANY reg16=00 reg26=C2 reg30=03 reg31=28
+GREECE reg16=00 reg26=C2 reg30=02 reg31=28
+GUAM reg16=00 reg26=C0 reg30=00 reg31=20
+HONGKONG reg16=00 reg26=C0 reg30=00 reg31=20
+HUNGARY reg16=00 reg26=C0 reg30=00 reg31=20
+ICELAND reg16=00 reg26=C2 reg30=02 reg31=28
+INDIA reg16=00 reg26=C0 reg30=04 reg31=20
+INDONESIA reg16=00 reg26=C0 reg30=00 reg31=20
+IRELAND reg16=00 reg26=C2 reg30=02 reg31=28
+ISRAEL reg16=00 reg26=C2 reg30=02 reg31=20
+ITALY reg16=00 reg26=C2 reg30=02 reg31=28
+JAPAN reg16=00 reg26=30 reg30=00 reg31=20
+JORDAN reg16=00 reg26=30 reg30=00 reg31=20
+KAZAKHSTAN reg16=00 reg26=C0 reg30=00 reg31=20
+KUWAIT reg16=00 reg26=C0 reg30=00 reg31=20
+LATVIA reg16=00 reg26=C2 reg30=02 reg31=20
+LEBANON reg16=00 reg26=C2 reg30=02 reg31=20
+LUXEMBOURG reg16=00 reg26=C2 reg30=02 reg31=28
+MACAO reg16=00 reg26=C0 reg30=00 reg31=20
+MALAYSIA reg16=00 reg26=30 reg30=00 reg31=20
+MALTA reg16=00 reg26=C2 reg30=02 reg31=20
+MEXICO reg16=00 reg26=C0 reg30=00 reg31=20
+MOROCCO reg16=00 reg26=C2 reg30=02 reg31=20
+NETHERLANDS reg16=00 reg26=C2 reg30=02 reg31=28
+NEWZEALAND reg16=00 reg26=C0 reg30=04 reg31=20
+NIGERIA reg16=00 reg26=C2 reg30=02 reg31=20
+NORWAY reg16=00 reg26=C2 reg30=02 reg31=28
+OMAN reg16=00 reg26=30 reg30=00 reg31=20
+PAKISTAN reg16=00 reg26=30 reg30=00 reg31=20
+PERU reg16=00 reg26=C0 reg30=00 reg31=20
+PHILIPPINES reg16=00 reg26=30 reg30=00 reg31=20
+POLAND reg16=03 reg26=C0 reg30=00 reg31=20
+PORTUGAL reg16=00 reg26=C2 reg30=02 reg31=28
+ROMANIA reg16=00 reg26=C0 reg30=00 reg31=20
+RUSSIA reg16=00 reg26=30 reg30=00 reg31=20
+SAUDIARABIA reg16=00 reg26=C0 reg30=00 reg31=20
+SINGAPORE reg16=00 reg26=C0 reg30=00 reg31=20
+SLOVAKIA reg16=00 reg26=C0 reg30=03 reg31=20
+SLOVENIA reg16=00 reg26=C0 reg30=02 reg31=20
+SOUTHAFRICA reg16=42 reg26=C0 reg30=03 reg31=20
+SOUTHKOREA reg16=00 reg26=C0 reg30=00 reg31=20
+SPAIN reg16=00 reg26=C2 reg30=02 reg31=28
+SWEDEN reg16=00 reg26=C2 reg30=02 reg31=28
+SWITZERLAND reg16=00 reg26=C2 reg30=02 reg31=28
+SYRIA reg16=00 reg26=30 reg30=00 reg31=20
+TAIWAN reg16=00 reg26=30 reg30=00 reg31=20
+THAILAND reg16=00 reg26=30 reg30=00 reg31=20
+UAE reg16=00 reg26=C0 reg30=00 reg31=20
+UK reg16=00 reg26=C2 reg30=05 reg31=28
+USA reg16=00 reg26=C0 reg30=00 reg31=20
+YEMEN reg16=00 reg26=C0 reg30=00 reg31=20
+ ";
+
+my %opermode_table;
+
+sub opermode_setup() {
+ main::logit "Setting OPERMODE=$OPERMODE";
+ # Several countries (South Africa, UAE, anybody else)
+ # require a shorter delay:
+ if($OPERMODE eq 'SOUTHAFRICA' or $OPERMODE eq 'UAE') {
+ FXO::gen "* WD 17 2B";
+ }
+ # defaults, based on fxo_modes from wctdm.c .
+ # Decimal register numbers!
+ my %regs = (
+ 16 => 0,
+ 26 => 0,
+ 30 => 0,
+ 31 => 0x20,
+ );
+ my $mode = $opermode_table{$OPERMODE};
+ if(defined $mode) {
+ foreach my $k (keys %regs) {
+ my $fullkey = "reg$k";
+ $regs{$k} = $mode->{$fullkey};
+ }
+ }
+ foreach my $k (keys %regs) {
+ # Our values are HEXADECIMAL without a 0x prefix!!!
+ my $cmd = sprintf "* WD %02X %02X", $k, hex($regs{$k});
+ main::debug " regs: '$cmd'";
+ FXO::gen "$cmd";
+ }
+ main::debug "Finished Opermode";
+}
+
+sub parse_opermode_line($) {
+ my $line = shift or return();
+
+ chomp $line;
+ $line =~ s/#.*//;
+ my @params = split(/\s+/, $line);
+ my $location = shift @params;
+ my $entry = {};
+ foreach my $p (@params) {
+ my ($key, $val) = split(/=/, $p, 2);
+ $entry->{$key} = $val;
+ }
+ return ($location, $entry);
+}
+
+sub opermode_preprocess() {
+ undef %opermode_table;
+ foreach my $line (split(/\n/, $OPERMODE_DATA)) {
+ my ($location, $entry) = parse_opermode_line($line);
+ next unless defined $location;
+ #print "$location\t", ref($entry), "\n";
+ die "An entry for '$location' already exists\n"
+ if exists $opermode_table{$location};
+ $opermode_table{$location} = $entry;
+ }
+}
+
+sub opermode_to_string($) {
+ my $mode = shift or die;
+ my @params;
+
+ foreach my $k (sort keys %{$mode}) {
+ push(@params, "$k=$mode->{$k}");
+ }
+ return join(" ", @params);
+}
+
+sub opermode_verify($) {
+ my $input = shift or die;
+ my %verification_table;
+
+ open(F, $input) or die "$0: Failed opening '$input': $!\n";
+ while(<F>) {
+ chomp;
+ #print "$_\n";
+ s/#.*//;
+ my @params = split;
+ my $location = shift @params;
+ foreach my $p (@params) {
+ my ($key, $val) = split(/=/, $p, 2);
+ $verification_table{$location}{$key} = $val;
+ }
+ }
+ close F;
+ # First test: check for missing data in our program
+ foreach my $location (sort keys %verification_table) {
+ my $mode = $opermode_table{$location};
+ if(! defined $mode) {
+ printf STDERR "Missing $location\n";
+ next;
+ }
+ my $verify_mode = $verification_table{$location};
+ my $str1 = opermode_to_string($mode);
+ my $str2 = opermode_to_string($verify_mode);
+ if($str1 ne $str2) {
+ print STDERR "DIFF: $location:\n";
+ printf STDERR "\t%-20s: %s\n", "program", $str1;
+ printf STDERR "\t%-20s: %s\n", "verify", $str2;
+ }
+ }
+ # Second test: check for extra data in our program
+ foreach my $location (sort keys %opermode_table) {
+ my $mode = $verification_table{$location};
+ if(! defined $mode) {
+ printf STDERR "Extra $location\n";
+ next;
+ }
+ }
+}
+
+sub read_defaults() {
+ # For lab tests
+ my $labfile = "$init_dir/genzaptelconf.env";
+
+ # Source default files
+ $ENV{ZAPTEL_DEFAULTS} = "$labfile" if -r "$labfile";
+ my $var_debug = 'DEBUG_INIT_FXO';
+ my $var_opermode = 'opermode';
+ my ($default_file, %source_defaults) =
+ Zaptel::Config::Defaults::source_vars($var_debug, $var_opermode);
+ $debug = $source_defaults{$var_debug};
+ my $tmp_opermode = $source_defaults{$var_opermode};
+ if(defined($tmp_opermode) and $tmp_opermode) {
+ # Verify
+ my $mode = $opermode_table{$tmp_opermode};
+ if(! defined $mode) {
+ main::logit "Unknown opermode='$tmp_opermode'";
+ die;
+ }
+ $OPERMODE = $tmp_opermode;
+ }
+ main::logit "From $default_file: $var_debug=$debug $var_opermode=$tmp_opermode";
+}
+
+package main;
+
+FXO::opermode_preprocess; # Must be first
+
+if(@ARGV and $ARGV[0] =~ /^verify(.*)/) {
+ my $verify_file = $1;
+ die "Usage: $0 verify=filename\n" unless $verify_file =~ s/^=//;
+ main::debug "$0: opermode verification (input='$verify_file')";
+ FXO::opermode_verify($verify_file);
+ exit 0;
+}
+
+main::logit "Starting";
+
+FXO::read_defaults;
+die "OPERMODE is undefined" unless $OPERMODE;
+set_output;
+FXO::turn_off_leds;
+while(<DATA>) {
+ chomp;
+ s/[#;].*$//; # remove comments
+ s/^\s+//; # trim whitespace
+ s/\s+$//; # trim whitespace
+ s/\t+/ /g; # replace tabs with spaces (for logs)
+ next unless /\S/; # Skip empty lines
+ main::debug "writing: '$_'";
+ FXO::gen "$_";
+}
+FXO::opermode_setup;
+close REG;
+
+main::logit "Ending '$0'";
+close STDERR;
+exit 0;
+
+__DATA__
+* WD 21 28
+* WD 18 99
+* WD 06 00
+
+# ----------- DAA PCM start offset ----------
+
+0 WD 22 00
+0 WD 23 00
+0 WD 24 00
+0 WD 25 00
+
+1 WD 22 08
+1 WD 23 00
+1 WD 24 08
+1 WD 25 00
+
+2 WD 22 10
+2 WD 23 00
+2 WD 24 10
+2 WD 25 00
+
+3 WD 22 18
+3 WD 23 00
+3 WD 24 18
+3 WD 25 00
+
+4 WD 22 20
+4 WD 23 00
+4 WD 24 20
+4 WD 25 00
+
+5 WD 22 28
+5 WD 23 00
+5 WD 24 28
+5 WD 25 00
+
+6 WD 22 30
+6 WD 23 00
+6 WD 24 30
+6 WD 25 00
+
+7 WD 22 38
+7 WD 23 00
+7 WD 24 38
+7 WD 25 00
+
+# ----------- DAA ONHOOK --------------------
+* WD 05 00
+
+# Set tip to ring voltage to 3.5 volts while off-hook
+# instead of default of 3.1
+* WD 1A C0
diff --git a/drivers/dahdi/xpp/init_card_3_30 b/drivers/dahdi/xpp/init_card_3_30
new file mode 100755
index 0000000..ce8ad01
--- /dev/null
+++ b/drivers/dahdi/xpp/init_card_3_30
@@ -0,0 +1,439 @@
+#! /usr/bin/perl -w
+use strict;
+
+#
+# $Id$
+#
+
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2006, Xorcom
+#
+# 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.
+#
+# See the file LICENSE in the top level of this tarball.
+#
+
+# This script is run from the xpp kernel module upon detection
+# of a new XPD.
+#
+# Expects the following environment variables to be set:
+# XBUS_NAME - bus name
+# UNIT_NUMBER - xpd unit number
+# UNIT_SUBUNITS - number of subunits in this xpd
+# UNIT_TYPE - xpd type number (from protocol reply):
+# 1 - FXS
+# 2 - FXO
+# 3 - BRI
+# 4 - PRI
+# XBUS_REVISION - xbus revision number
+# XBUS_CONNECTOR - xbus connector string
+#
+# Output data format:
+# - An optional comment start with ';' or '#' until the end of line
+# - Optional Blank lines are ignored
+# - Fields are whitespace separated (spaces or tabs)
+#
+# The fields are (in command line order):
+# 1. CHIP select in decimal (ignored, taken from 3 LSB's of subunit number)
+# 2. Command word:
+# - RD Read Direct register.
+# - RI Read Indirect register.
+# - WD Write Direct register.
+# - RI Write Indirect register.
+# 3. Register number in hexadecimal.
+# 4. Subregister number in hexadecimal. (for RI and WI commands).
+# 5. Data byte in hexadecimal. (for WD and WI commands only).
+#
+
+package main;
+use File::Basename;
+use Getopt::Std;
+
+my $program = basename("$0");
+my $init_dir = dirname("$0");
+my $unit_id;
+my %opts;
+$ENV{XPP_BASE} = '/proc/xpp';
+
+getopts('o:', \%opts);
+
+sub logit {
+ print STDERR "$unit_id: @_\n";
+}
+
+# Arrange for error logging
+if (-t STDERR) {
+ $unit_id = 'Interactive';
+ logit "Interactive startup";
+} else {
+ $unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
+ open (STDERR, "| logger -t $program -p kern.info") || die;
+ logit "Non Interactive startup";
+}
+
+sub select_subunit($) {
+ my $subunit = shift;
+ die unless defined $subunit;
+ my $output;
+
+ if($opts{o}) {
+ $output = $opts{o};
+ } else {
+ my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit);
+ $output = "$ENV{XPP_BASE}/$ENV{XBUS_NAME}/$xpd_name/chipregs";
+ }
+ open(REG, ">$output") || die "Failed to open '$output': $!\n";
+ my $oldfh = select REG;
+ print "# Selecting subunit $subunit\n" if $opts{o};
+ return $oldfh;
+}
+
+package BRI;
+
+sub gen {
+ my $fmt = shift;
+ $| = 1;
+ printf "$fmt\n", @_;
+}
+
+# Turning on/off multi-byte packet reception.
+sub multibyte($) {
+ my $active = (shift) ? 'M' : 'm';
+ for my $subunit (0 .. $ENV{UNIT_SUBUNITS} - 1) {
+ #main::logit "multibyte(): $subunit -> $active";
+ main::select_subunit($subunit);
+
+ BRI::gen "$subunit W$active";
+ }
+}
+
+package BRI::Port;
+
+sub new {
+ my $pack = shift;
+ my $port = { @_ };
+ bless $port, $pack;
+}
+
+# zap_xhfc_su.c:995
+sub init_su {
+ my $port = shift;
+ my $portnum = $port->{PORT_NUM};
+ my $port_mode_up = $port->{PORT_MODE_UP};
+ my $port_mode_exch = $port->{PORT_MODE_EXCH};
+ my $bri_nt = $port->{BRI_NT};
+ #main::logit "init_su(portnum=$portnum, port_mode_up=$port_mode_up, bri_nt=$bri_nt)";
+
+ # Setting PLL
+ # R_PLL_CTRL = 0 (V_PLL_M = 0, Reset PLL, Disable PLL_
+ # R_CLK_CFG = 05 (PLL clock as system clock, output it to CLK_OUT pin)
+ # R_PLL_P = 1
+ # R_PLL_N = 6
+ # R_PLL_S = 1
+ # R_PLL_CTRL = 1 (V_PLL_M)
+
+ BRI::gen "#--------------------------- init_su($portnum, $bri_nt, $port_mode_up, $port_mode_exch)";
+ BRI::gen "$portnum WD 02 04";
+ BRI::gen "$portnum WD 50 00"; # disable PLL
+ BRI::gen "$portnum WD 51 02";
+ BRI::gen "$portnum WD 52 06";
+ BRI::gen "$portnum WD 53 04";
+ BRI::gen "$portnum WD 50 01"; # Enable PLL
+ BRI::gen "$portnum WD 02 05"; # Enable PLL
+
+ su_sel($portnum); # select port
+ if ("$port_mode_up" == 1) {
+ $port->{CTRL3} = 0x01; # A_ST_CTRL3: V_ST_SEL = 1
+ $port->{CTRL0} = 0x10; # A_SU_CTRL0: V_ST_SQ_EN = 1
+ BRI::gen "$portnum WD 34 0F"; # A_MS_TX:
+ # (multiframe/superframe transmit register)
+ } else {
+ $port->{CTRL3} = 0x00; # A_ST_CTRL3: V_ST_SEL = 0
+ $port->{CTRL0} = 0x00; # A_SU_CTRL0: V_ST_SQ_EN = 0
+ }
+ if ("$bri_nt" == 1) {
+ $port->{CTRL0} |= 0x04; # V_SU_MD
+ }
+ # ((V_SU_EXCH)?0x80:00) (change polarity)
+ if($port_mode_exch) {
+ $port->{CTRL2} = 0x80;
+ } else {
+ $port->{CTRL2} = 0x00;
+ }
+ BRI::gen "$portnum WD 35 %02X", $port->{CTRL3}; # A_ST_CTRL3
+ BRI::gen "$portnum WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0
+ BRI::gen "$portnum WD 35 F8"; # A_ST_CTRL3 = set end of pulse control to 0xF8
+ BRI::gen "$portnum WD 32 09"; # A_SU_CTRL1 = Ignore E-channel data, Force automatic transition from G2 to G3
+ BRI::gen "$portnum WD 33 %02X", $port->{CTRL2}; # A_SU_CTRL2
+
+ # zap_xhfc_su.c:1030 in init_su()
+ # A_SU_CLK_DLY
+ my $clk_dly;
+ if ("$bri_nt" == 1) {
+ $clk_dly = 0x6C;
+ } else {
+ $clk_dly = 0x0E;
+ }
+ #main::logit "clk_dly=$clk_dly";
+ BRI::gen "$portnum WD 37 %02X", "$clk_dly";
+}
+
+sub su_sel {
+ if (@_ != 1 ) {
+ main::logit "ERROR: su_sel() called with " . scalar(@_) . " parameters";
+ exit 1;
+ }
+ my $portnum = shift;
+ BRI::gen "$portnum WD 16 %02X", $portnum; # R_SU_SEL
+}
+
+# zap_xhfc_su.c:281
+sub xhfc_selfifo {
+ my $port = shift;
+ my $portnum = $port->{PORT_NUM};
+
+ if (@_ != 1 ) {
+ main::logit "ERROR: xhfc_selfifo() called with " . scalar(@_) . " parameters";
+ exit 1;
+ }
+ my $fifonum = shift;
+ #main::logit "xhfc_selfifo($fifonum)";
+ BRI::gen "$portnum WD 0F %02X", $fifonum;
+ # --> WAIT UNTIL (R_STATUS & M_BUSY) == 0
+}
+
+# zap_xhfc_su.c:295
+sub xhfc_resetfifo() {
+ my $port = shift;
+ my $portnum = $port->{PORT_NUM};
+
+ #main::logit "xhfc_resetfifo()";
+ # A_INC_RES_FIFO = M_RES_FIFO | M_RES_FIFO_ERR
+ BRI::gen "$portnum WD 0E 0A";
+ # --> WAIT UNTIL (R_STATUS & M_BUSY) == 0
+}
+
+# zap_xhfc_su.c:1040
+# Initialize fifo (called for each portnum, channel, direction)
+sub setup_fifo {
+ my $port = shift;
+ my $chan = shift;
+ my $direction = shift;
+ my $conhdlc = shift;
+ my $subcfg = shift;
+ my $fifoctrl = shift;
+ my $portnum = $port->{PORT_NUM};
+ my $port_mode_up = $port->{PORT_MODE_UP};
+ my $port_mode_exch = $port->{PORT_MODE_EXCH};
+ my $bri_nt = $port->{BRI_NT};
+
+ BRI::gen "#--------------------------- setup_fifo($portnum, $chan, $direction)";
+ # my $fifonum = 0x80 | ($portnum << 3) | ($chan << 1) | ($direction); # # MSB first
+ my $fifonum = ($portnum << 3) | ($chan << 1) | ($direction); # # MSB first
+ my $r_slot = ($portnum << 3) | ($chan << 1) | ($direction);
+
+ # channel order workaround, swap odd and even portnums in $r_slot for PCM (chan 0, 1) only
+ if ("$chan" == 0 || "$chan" == 1) {
+ $r_slot = $r_slot ^ 0x08;
+ }
+
+ my $short_portnum = $portnum & 0x03;
+ my $a_sl_cfg = (0x80 | ($short_portnum << 3) | ($chan << 1) | ($direction)); # receive data from STIO2, transmit to STIO1
+
+ #main::logit "setup_fifo($fifonum)";
+ $port->xhfc_selfifo($fifonum);
+ # A_CON_HDLC: transparent mode selection
+ BRI::gen "$portnum WD FA %02X", $conhdlc;
+ # A_SUBCH_CFG: subchnl params
+ BRI::gen "$portnum WD FB %02X", $subcfg;
+ # A_FIFO_CTRL: FIFO Control Register
+ BRI::gen "$portnum WD FF %02X", $fifoctrl;
+ $port->xhfc_resetfifo();
+ $port->xhfc_selfifo($fifonum); # wait for busy is builtin in this command
+ BRI::gen "$portnum WD 10 %02X", $r_slot; # R_SLOT
+ BRI::gen "$portnum WD D0 %02X", $a_sl_cfg; # A_SL_CFG
+
+ #system("/bin/echo \"----=====TE\" \"short_portnum=\"$short_portnum \"portnum=\" $portnum \"chan=\" $chan\"======----\n\" >>/root/xortel/test_init");
+}
+
+# zap_xhfc_su.c:1071
+sub setup_su {
+ my $port = shift;
+ my $bchan = shift;
+ my $portnum = $port->{PORT_NUM};
+ my $port_mode_exch = $port->{PORT_MODE_EXCH};
+ my $bri_nt = $port->{BRI_NT};
+
+ BRI::gen "#--------------------------- setup_su($portnum, $bchan)";
+ #main::logit "setup_su(portnum=$portnum, bchan=$bchan, port_mode_exch=$port_mode_exch, bri_nt=$bri_nt)";
+ $port->{CTRL0} |= (1 << $bchan) | $bri_nt;
+ $port->{CTRL2} |= ($port_mode_exch << 7) | (1 << $bchan);
+ su_sel($portnum); # Select port
+ BRI::gen "$portnum WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0: V_B1_TX_EN | V_SU_MD | (NT/TE)
+ BRI::gen "$portnum WD 33 %02X", $port->{CTRL2}; # A_SU_CTRL2: V_B1_RX_EN
+}
+
+sub xhfc_ph_command {
+ my $port = shift;
+ my $cmd = shift;
+ my $portnum = $port->{PORT_NUM};
+ #main::logit "xhfc_ph_command(portnum=$portnum)";
+ if ("$cmd" eq "HFC_L1_ACTIVATE_TE") {
+ su_sel($portnum); # Select port
+ BRI::gen "$portnum WD 30 60"; # A_SU_WR_STA = (M_SU_ACT & 0x03)
+ # (set activation)
+ } elsif ("$cmd" eq "HFC_L1_FORCE_DEACTIVATE_TE") {
+ su_sel($portnum); # Select port
+ BRI::gen "$portnum WD 30 40"; # A_SU_WR_STA = (M_SU_ACT & 0x02)
+ # (set deactivation)
+ } elsif ("$cmd" eq "HFC_L1_ACTIVATE_NT") {
+ su_sel($portnum); # Select port
+ BRI::gen "$portnum WD 30 E0"; # A_SU_WR_STA = (M_SU_ACT & 0x03) | 0x80
+ # (set activation + NT)
+ } elsif ("$cmd" eq "HFC_L1_DEACTIVATE_NT") {
+ su_sel($portnum); # Select port
+ BRI::gen "$portnum WD 30 40"; # A_SU_WR_STA = (M_SU_ACT & 0x02)
+ # (set deactivation)
+ }
+}
+
+
+sub zthfc_startup {
+ my $port = shift;
+ my $portnum = $port->{PORT_NUM};
+ my $port_mode_exch = $port->{PORT_MODE_EXCH};
+ my $bri_nt = $port->{BRI_NT};
+ #main::logit "zthfc_startup(portnum=$portnum, port_mode_exch=$port_mode_exch, bri_nt=$bri_nt)";
+
+ # PCM <-> ST/Up Configuration
+ foreach my $chan ( 0, 1 ) {
+ $port->setup_fifo($chan, 0, 0xFE, 0, 0);# Transparent mode, FIFO EN, ST->PCM
+ $port->setup_fifo($chan, 1, 0xFE, 0, 0);# Transparent mode, FIFO EN, ST->PCM
+ $port->setup_su($chan); # zap_xhfc_su.c:194
+ }
+
+ # Zaptel chan 2 used as HDLC D-Channel
+ $port->setup_fifo(2, 0, 0x05, 2, 0); # D-TX: zap_xhfc_su.c:205
+ $port->setup_fifo(2, 1, 0x05, 2, 0); # D-RX: zap_xhfc_su.c:206
+ # E-chan, Echo channel is ignored
+
+
+ # enable this port's state machine
+ su_sel($portnum); # Select port
+ # A_SU_WR_STA: reset port state machine
+ BRI::gen "$portnum WD 30 00";
+ if ("$bri_nt" == 0) {
+ $port->xhfc_ph_command("HFC_L1_ACTIVATE_TE");
+ } else {
+ $port->xhfc_ph_command("HFC_L1_ACTIVATE_NT");
+ }
+}
+
+package main;
+
+logit "Starting '$0'";
+
+#------------------------------------------- Instance detection
+
+# zap_xhfc_su.c:895
+sub init_xhfc($) {
+ my $portnum = shift;
+ main::logit "init_xhfc($portnum)";
+ BRI::gen "#--------------------------- init_xhfc";
+ BRI::gen "$portnum WD 0D 00"; # r_FIFO_MD: 16 fifos,
+ # 64 bytes for TX and RX each (FIFO mode config)
+
+ # software reset to enable R_FIFO_MD setting
+ BRI::gen "$portnum WD 00 08"; # R_CIRM = M_SRES (soft reset)
+ # --> WAIT 5u
+ BRI::gen "$portnum WD 00 00"; # R_CIRM = 0 (zero it to deactivate reset)
+
+ # amplitude
+ BRI::gen "$portnum WD 46 80"; # R_PWM_MD: (PWM output mode register)
+ # PWM push to zero only
+ BRI::gen "$portnum WD 39 18"; # R_PWM1: (modulator register for PWM1)
+ # set duty cycle
+
+ BRI::gen "$portnum WD 0C 11"; # R_FIFO_THRES: (FIFO fill lvl control register)
+ # RX/TX threshold = 16 bytes
+
+ # --> Wait until (R_STATUS & (M_BUSY | M_PCM_INIT))
+ # M_BUSY status will be checked after fifo selection
+ BRI::gen "$portnum WD 0F 80";
+ # set PCM !master mode
+ BRI::gen "$portnum WD 14 08"; # R_PCM_MD0 = PCM slave mode, F0IO duration is 2 HFC_PCLK's
+
+ # (C4IO, F0IO are inputs)
+
+ # set pll adjust
+ # WD 14 90 # R_PCM_MD0: Index value to select
+ # the register at address 15
+ # WD 15 2C # R_PCM_MD1: V_PLL_ADJ (DPLL adjust speed), C4IO is 16.384MHz(128 time slots)
+ # in the last slot of PCM frame
+ BRI::gen "$portnum WI 14 98 20"; # R_PCM_MD1: V_PLL_ADJ
+ # (DPLL adjust speed) in the
+ # last slot of PCM frame
+
+ BRI::gen "$portnum WD 4C 03"; # GPIOGPIO function (not PWM) on GPIO0 and GPIO1 pins
+ BRI::gen "$portnum WD 4A 03"; # Output enable for GPIO0 and GPIO1 pins
+}
+
+my @port_type = (
+ { 'BRI_NT' => 1 },
+ { 'BRI_NT' => 0 }
+ );
+
+# zap_xhfc_su.c:175
+sub main() {
+ my $subunit;
+ my $subunits_mask = pack("C", $ENV{UNIT_SUBUNITS_DIR});
+ my @direction = split(//, unpack("b*", $subunits_mask));
+
+ #logit "main(): UNIT_TYPE=$ENV{UNIT_TYPE} UNIT_SUBUNITS_DIR=[@direction]";
+ if(!$opts{o}) {
+ foreach my $var (qw(XBUS_NAME UNIT_NUMBER UNIT_TYPE UNIT_SUBUNITS UNIT_SUBUNITS_DIR XBUS_REVISION XBUS_CONNECTOR)) {
+ die "Missing mandatory '$var' environment variable" unless defined $var;
+ }
+ }
+ # Turn off multi-byte packet reception before initialization started
+ # Otherwise we mess with registers while the FPGA firmware tries to
+ # send us packets.
+ BRI::multibyte(0);
+
+ # Port initialization
+ for($subunit = 0; $subunit < $ENV{UNIT_SUBUNITS}; $subunit++) {
+ my $is_nt = $direction[$subunit];
+
+ main::select_subunit($subunit);
+ if(($subunit % 4) == 0) { # A new xhfc chip
+ #logit "main(): Initializing chip";
+ init_xhfc($subunit); # zap_xhfc_su.c:1173 in setup_instance()
+ }
+ #logit "main(): Initializing subunit $subunit is_nt=$is_nt";
+ my $p = BRI::Port->new(
+ 'PORT_NUM' => $subunit,
+ 'BRI_NT' => $is_nt,
+ 'PORT_MODE_UP' => 0,
+ 'PORT_MODE_EXCH' => 0
+ );
+ # zap_XHfc_su.c:1186 in setup_instance()
+ $p->init_su;
+ $p->zthfc_startup;
+ }
+ # Turn on multi-byte packet reception when ports initialization finished
+ BRI::multibyte(1);
+}
+
+main;
+
+logit "Ending '$0'";
+
+close REG;
+close STDERR;
+exit 0;
diff --git a/drivers/dahdi/xpp/init_card_4_30 b/drivers/dahdi/xpp/init_card_4_30
new file mode 100755
index 0000000..25e6ec7
--- /dev/null
+++ b/drivers/dahdi/xpp/init_card_4_30
@@ -0,0 +1,387 @@
+#! /usr/bin/perl -w
+use strict;
+
+#
+# $Id$
+#
+
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+#
+# 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.
+#
+# See the file LICENSE in the top level of this tarball.
+#
+
+# This script is run from the xpp kernel module upon detection
+# of a new XPD.
+#
+# Expects the following environment variables to be set:
+# XBUS_NAME - bus name
+# UNIT_NUMBER - xpd unit number
+# UNIT_SUBUNITS - number of subunits in this xpd
+# UNIT_TYPE - xpd type number (from protocol reply):
+# 1 - FXS
+# 2 - FXO
+# 3 - BRI
+# 4 - PRI
+# XBUS_REVISION - xbus revision number
+# XBUS_CONNECTOR - xbus connector string
+#
+# Output data format:
+# - An optional comment start with ';' or '#' until the end of line
+# - Optional Blank lines are ignored
+# - Fields are whitespace separated (spaces or tabs)
+#
+# The fields are (in command line order):
+# 1. CHIP select in decimal (ignored, taken from 3 LSB's of subunit number)
+# 2. Command word:
+# - RD Read Direct register.
+# - WD Write Direct register.
+# 3. Register number in hexadecimal.
+# 5. Data byte in hexadecimal. (for WD command only).
+#
+
+package main;
+use File::Basename;
+use Getopt::Std;
+
+my $program = basename("$0");
+my $init_dir = dirname("$0");
+my $unit_id;
+my %opts;
+$ENV{XPP_BASE} = '/proc/xpp';
+my @pri_specs;
+
+getopts('o:', \%opts);
+
+sub logit {
+ print STDERR "$unit_id: @_\n";
+}
+
+# Arrange for error logging
+if (-t STDERR) {
+ $unit_id = 'Interactive';
+ logit "Interactive startup";
+} else {
+ $unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
+ open (STDERR, "| logger -t $program -p kern.info") || die;
+ logit "Non Interactive startup";
+}
+
+sub select_subunit($) {
+ my $subunit = shift;
+ die unless defined $subunit;
+ my $output;
+
+ if($opts{o}) {
+ $output = $opts{o};
+ } else {
+ my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit);
+ $output = "$ENV{XPP_BASE}/$ENV{XBUS_NAME}/$xpd_name/chipregs";
+ }
+ open(REG, ">$output") || die "Failed to open '$output': $!\n";
+ my $oldfh = select REG;
+ print "# Selecting subunit $subunit\n" if $opts{o};
+ return $oldfh;
+}
+
+package PRI;
+
+sub gen {
+ my $fmt = shift;
+ $| = 1;
+ printf "$fmt\n", @_;
+}
+
+sub init_quad() {
+ main::select_subunit(0);
+ # Tuning of clocking unit to the 16.384 MHz reference frequence
+ # by setting Global Clock Mode registers (GCM[1:8]), same for E1 and T1/J1
+ PRI::gen "0 WD 92 00"; # GCM1
+ PRI::gen "0 WD 93 18"; # GCM2
+ PRI::gen "0 WD 94 FB"; # GCM3
+ PRI::gen "0 WD 95 0B"; # GCM4
+ PRI::gen "0 WD 96 01"; # GCM5
+ PRI::gen "0 WD 97 0B"; # GCM6
+ PRI::gen "0 WD 98 DB"; # GCM7
+ PRI::gen "0 WD 99 DF"; # GCM8
+}
+
+sub finish_quad() {
+ PRI::gen "0 WD BB FF"; # REGFP
+ PRI::gen "0 WD BC AC"; # REGFD
+ PRI::gen "0 WD BB 2B"; # REGFP
+ PRI::gen "0 WD BC 00"; # REGFD
+ PRI::gen "0 WD BB AB"; # REGFP
+ PRI::gen "0 WD BC 2A"; # REGFD
+ PRI::gen "0 WD BB FF"; # REGFP
+ PRI::gen "0 WD BC AA"; # REGFD
+ PRI::gen "0 WD BB 29"; # REGFP
+ PRI::gen "0 WD BC FF"; # REGFD
+ PRI::gen "0 WD BB A9"; # REGFP
+ PRI::gen "0 WD BC 28"; # REGFD
+ PRI::gen "0 WD BB 00"; # REGFP
+ PRI::gen "0 WD BC A8"; # REGFD
+ PRI::gen "0 WD BB 27"; # REGFP
+ PRI::gen "0 WD BC FF"; # REGFD
+ PRI::gen "0 WD BB A7"; # REGFP
+ PRI::gen "0 WD BC 00"; # REGFD
+
+# PRI::gen "0 WD 80 00"; # PC1 (Port configuration 1): RPB_1.SYPR , XPB_1.SYPX
+ PRI::gen "0 WD 81 0B"; # PC2 (Port configuration 2): RPB_1.GPOH (ResetID ), XPB_1.GPOL (MUX_SEL0)
+ PRI::gen "0 WD 82 9B"; # PC3 (Port configuration 3): RPC_1.GPI (nConfig0), XPC_1.GPOL (MUX_SEL1)
+ PRI::gen "0 WD 83 9B"; # PC4 (Port configuration 4): RPD_1.GPI (nConfig1), XPD_1.GPOL (MUX_SEL2)
+}
+
+sub read_pri_specs() {
+ # For lab tests
+ my $labfile = "${0}.setup";
+
+ # Source default files
+ $ENV{ZAPTEL_DEFAULTS} = "$labfile" if -r "$labfile";
+ my $setup_var = 'XPP_PRI_SETUP';
+ my $setup_string;
+ my ($default_file, %source_defaults) =
+ Zaptel::Config::Defaults::source_vars($setup_var);
+ $setup_string = $source_defaults{$setup_var};
+ $setup_string =~ s/^\s+//; # trim
+ $setup_string =~ s/\s+$//; # trim
+ $setup_string =~ s/\s+/\n/g; # cannonical spaces
+ #main::logit "From $default_file: $setup_var=\n$setup_string";
+ @pri_specs = split(/\s+/, $setup_string);
+ push(@pri_specs, 'NUM/*=TE,E1'); # Fall back default (last)
+ main::logit "pri_specs: @pri_specs";
+}
+
+package PRI::Port;
+
+sub new {
+ my $pack = shift;
+ my $port = { @_ };
+ bless $port, $pack;
+ $port->process_pri_spec;
+ return $port;
+}
+
+sub write_pri_info {
+ my $port = shift;
+ my $subunit = $port->{PORT_NUM};
+ my @pri_setup = @{$port->{PRI_SETUP}};
+ my $pri_type = $pri_setup[0] || die "Missing pri_type parameter";
+ my $pri_proto = $pri_setup[1] || die "Missing pri_proto parameter";
+ my $xpd_name = "XPD-$ENV{UNIT_NUMBER}$subunit";
+ my $info = "$ENV{XPP_BASE}/$ENV{XBUS_NAME}/$xpd_name/pri_info";
+
+ main::logit "$xpd_name: PRI_SETUP $pri_type $pri_proto";
+ open(INFO, ">$info") || die "Failed to open '$info': $!\n";
+ print INFO "$pri_type $pri_proto\n" || die "Failed writing to '$info': $!\n";
+ close INFO || die "Failed during close of '$info': $!\n";
+}
+
+sub process_pri_spec($) {
+ my $port = shift;
+ my $subunit = $port->{PORT_NUM};
+ my $xpd_name = "XPD-$ENV{UNIT_NUMBER}$subunit";
+ my $match;
+ my $setup;
+ my @pri_setup;
+SPEC:
+ for(my $i = 0; $i < @pri_specs; $i++) {
+ my $spec = $pri_specs[$i];
+ ($match, $setup) = split(/=/, $spec);
+ next unless defined $match and defined $setup;
+ # Convert "globs" to regex
+ $match =~ s/\*/.*/g;
+ $match =~ s/\?/./g;
+ #logit "match: $match";
+ my @patlist = (
+ "CONNECTOR/$ENV{XBUS_CONNECTOR}/$xpd_name",
+ "NUM/$ENV{XBUS_NAME}/$xpd_name"
+ );
+ foreach my $pattern (@patlist) {
+ #logit "testmatch: $pattern =~ $match";
+ if($pattern =~ $match) {
+ main::logit "$xpd_name: MATCH '$pattern' ~ '$match' setup=$setup";
+ last SPEC;
+ }
+ }
+ }
+ die "No setup matching $ENV{XBUS_NAME}/$xpd_name\n" unless defined $setup;
+ @pri_setup = split(/,/, $setup);
+ die "Bad setup string '$setup'\n" unless @pri_setup;
+ $port->{'PRI_SETUP'} = \@pri_setup;
+}
+
+sub port_setup($) {
+ my $port = shift;
+ my $portno = $port->{PORT_NUM};
+
+ # only one of the following loopbacks can be activated in the same time
+ my $LIM1_RL = 0 << 1; # RL (Remote Loopback)
+ my $lim1 = 0xB0 | $LIM1_RL;
+
+ PRI::gen "$portno WD 26 F6"; # XPM0: Pulse Shape Programming for R1=18Ohms
+ PRI::gen "$portno WD 27 02"; # XPM1: ...3V Pulse Level at the line (Vp-p=6v)
+ PRI::gen "$portno WD 28 00"; # XPM2: ~XLT (transmit line is not in the high impedance state)
+
+ # if (unchannelized)
+ #PRI::gen "$portno WD 1F 22"; # LOOP (Channel Looback):
+ # ECLB (Enable Channel Loop-Back)
+ # CLA (Channel Address)
+ PRI::gen "$portno WD 2B EF"; # IDL (Idle):
+ # If channel loopback is enabled than transmit this code on the outgoing
+ PRI::gen "$portno WD 1F 00"; # LOOP (Channel Looback):
+ #if($portno eq 0){
+ # PRI::gen "0 WD 1F 00"; # LOOP (Channel Looback):
+ # # channels (XL1/XL2)
+ #}else {
+ # PRI::gen "0 WD 1F 20"; # LOOP (Channel Looback):
+ #}
+
+ PRI::gen "$portno WD 37 %02X", $lim1;
+ # LIM1: ~RL (Remote Loop bit 0x02),
+ # ~DRS (Dual Rail Select, latch receive data while trasmit),
+ # RIL1, RIL0 (Receive Input Treshold 0.62 V),
+ # CLOS (Clear data in case of LOS)
+ PRI::gen "$portno WD 3A 20"; # LIM2: SLT1, SLT0 = 01
+ # (Receiver Slicer Threshold, the receive slicer
+ # generates a mark (digital one) if the voltage at
+ # RL1/2 exceeds 50% of the peak amplitude,
+ # default, recommended in E1 mode).
+
+ PRI::gen "$portno WD 38 0A"; # PCD: (Pulse Count Detection, LOS Detection after 176 consecutive 0s)
+ PRI::gen "$portno WD 39 15"; # PCR: (Pulse Count Recovery, LOS Recovery after 22 ones in PCD interval)
+
+ # Configure system interface
+ PRI::gen "$portno WD 3E C2"; # SIC1: SSC1 (System clock ) is 8.192 Mhz,
+ # SSD1 (System Data rate) is 8.192 Mbit/s,
+ # ~BIM (Byte interleaved mode),
+ # XBS (Transmit Buffer Size) is 2 frames
+ PRI::gen "$portno WD 40 04"; # SIC3: Edges for capture, Synchronous Pulse Receive @Rising Edge
+ PRI::gen "$portno WD 41 04"; # CMR4: RCLK is 8.192 MHz
+ PRI::gen "$portno WD 43 04"; # CMR5: TCLK is 8.192 MHz
+ PRI::gen "$portno WD 44 34"; # CMR6: Receive reference clock generated by channel 1,
+ # RCLK is at 8.192 Mhz dejittered, Clock recovered from the line
+ # TCLK is at 8.192 MHz is de-jittered by DCO-R to drive a6.176 MHz
+ # clock on RCLK.*/
+
+ PRI::gen "$portno WD 22 00"; # XC0: (Transmit Counter Offset = 497/T=2)
+ PRI::gen "$portno WD 23 04"; # XC1:
+
+ PRI::gen "$portno WD 24 00"; # RC0: (Receive Counter Offset = 497/T=2)
+ PRI::gen "$portno WD 25 05"; # RC1:
+
+ my $sic2 = sprintf("%x", 0x00 | ($portno << 1));
+
+ PRI::gen "$portno WD 3F $sic2"; # SIC2: No FFS, no center receive elastic buffer, data active at phase ($sic >> 1)
+
+ # enable the following interrupt sources
+ PRI::gen "$portno WD 16 00"; # IMR2 (Interrupt Mask Register2): Enable ALL
+
+ PRI::gen "$portno WD 17 3F"; # IMR3 ~ES, ~SEC (Enable ES and SEC interrupts)
+ PRI::gen "$portno WD 18 00"; # IMR4: Enable ALL
+
+ PRI::gen "$portno WD 08 04"; # IPC: SYNC is 8 Khz
+
+ PRI::gen "$portno WD 02 51"; # CMDR (Command Register): RRES, XRES, SRES (Receiver/Transmitter reset)
+ PRI::gen "$portno WD 02 00"; # CMDR
+
+
+ # Configure interrupts
+ PRI::gen "$portno WD 46 40"; # GCR: Interrupt on Activation/Deactivation of AIX, LOS
+
+ PRI::gen "$portno WD 45 00"; # CMR2: External sources for SYPR, SCLKR, SYPX, SCLKX for TX and RX.
+ #PRI::gen "$portno WD 22 00"; # XC0: Normal operation of Sa-bits
+ #PRI::gen "$portno WD 23 04"; # XC1: X=4 => T=4-X=0 offset
+ #PRI::gen "$portno WD 24 00"; # RC0: 0 offset
+ #PRI::gen "$portno WD 25 00"; # RC1: Remaining part of RC0
+
+ # Configure ports
+ PRI::gen "$portno WD 85 80"; # GPC1 (Global Port Configuration 1):
+ #PRI::gen "$portno WD 85 00"; # GPC1 (Global Port Configuration 1):
+ # SMM (System Interface Multiplex Mode)
+ PRI::gen "$portno WD 80 00"; # PC1: SYPR/SYPX provided to RPA/XPA inputs
+
+ PRI::gen "$portno WD 84 31"; # PC5: XMFS active low, SCLKR is input, RCLK is output (unused)
+ PRI::gen "$portno WD 86 03"; # PC6: CLK1 is Tx Clock output, CLK2 is 8.192 Mhz from DCO-R
+ PRI::gen "$portno WD 3B 00"; # Clear LCR1 - Loop Code Register 1
+
+ # printk("TE110P: Successfully initialized serial bus for card\n");
+
+ # Initialize PCM and SIG regs
+ PRI::gen "$portno WD A0 00"; # TSEO (Time Slot Even/Odd Select)
+ PRI::gen "$portno WD A1 FF"; # TSBS (Time Slot Bit Select)- only selected bits are used for HDLC channel 1
+ # in selected time slots
+ PRI::gen "$portno WD 03 89"; # Mode Register:
+ # MDS (Mode Select) = 100 (No address comparison)
+ # HRAC (Receiver Active - HDLC channel 1)
+ # RFT2 (HDLC Receive FIFO is 64 byte deep)
+ PRI::gen "$portno WD 09 18"; # CCR1 (Common Configuration Register1)
+ # EITS (Enable Internal Time Slot 0 to 31 Signalling)
+ # ITF (Interframe Time Fill)
+ PRI::gen "$portno WD 0A 04"; # CCR2 (Common Configuration Register2)
+ # RCRC (enable CRC - HDLC channel 1enable CRC - HDLC channel 1)
+ PRI::gen "$portno WD 0C 00"; # RTR1 (Receive Time Slot register 1)
+ PRI::gen "$portno WD 0D 00"; # RTR2 (Receive Time Slot register 2)
+ PRI::gen "$portno WD 0E 00"; # RTR3 (Receive Time Slot register 3), TS16 (Enable time slot 16)
+ PRI::gen "$portno WD 0F 00"; # RTR4 (Receive Time Slot register 4)
+
+ PRI::gen "$portno WD 10 00"; # TTR1 (Transmit Time Slot register 1)
+ PRI::gen "$portno WD 11 00"; # TTR2 (Transmit Time Slot register 2)
+ PRI::gen "$portno WD 12 00"; # TTR3 (Transmit Time Slot register 3), TS16 (Enable time slot 16)
+ PRI::gen "$portno WD 13 00"; # TTR4 (Transmit Time Slot register 4)
+
+ # configure the best performance of the Bipolar Violation detection for all four channels
+ PRI::gen "$portno WD BD 00"; # BFR (Bugfix Register): ~BVP (Bipolar Violations),
+ # use Improved Bipolar Violation Detection instead
+}
+
+package main;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
+use Zaptel::Config::Defaults;
+
+logit "Starting '$0'";
+
+PRI::read_pri_specs;
+
+sub main() {
+ my @ports;
+ my $subunit;
+
+ logit "main(): Initializing chip ($ENV{UNIT_SUBUNITS} ports)";
+ PRI::init_quad;
+ # Must initialize all 4 ports, regardless how much there are
+ for($subunit = 0; $subunit < 4; $subunit++) {
+ my $is_nt = 0;
+
+ #logit "main(): Initializing subunit $subunit is_nt=$is_nt";
+ my $p = PRI::Port->new(
+ 'PORT_NUM' => $subunit,
+ 'PRI_NT' => $is_nt,
+ 'EXIST' => ($subunit < $ENV{UNIT_SUBUNITS})
+ );
+ $p->port_setup;
+ push(@ports, $p);
+ }
+ PRI::finish_quad;
+ foreach my $p (@ports) {
+ if($p->{EXIST}) {
+ $p->write_pri_info;
+ }
+ }
+}
+
+main;
+
+logit "Ending '$0'";
+
+close REG;
+close STDERR;
+exit 0;
diff --git a/drivers/dahdi/xpp/param_doc b/drivers/dahdi/xpp/param_doc
new file mode 100755
index 0000000..5848728
--- /dev/null
+++ b/drivers/dahdi/xpp/param_doc
@@ -0,0 +1,40 @@
+#! /usr/bin/perl -w
+use strict;
+#
+# Extract parameter documentation from *.ko files.
+# Assumes that parameter description include the default
+# value in the format we use in our DEF_PARM() macro
+#
+
+@ARGV || die "Usage: $0 module.ko....\n";
+
+my $modinfo = '/sbin/modinfo';
+my @mod_params;
+
+foreach my $file (glob "@ARGV") {
+ undef @mod_params;
+ print "$file:\n";
+ open(F, "$modinfo '$file' |") || die;
+ while(<F>) {
+ chomp;
+ next unless s/^parm:\s*//;
+ my ($name, $description) = split(/:/, $_, 2);
+ # Extract type
+ $description =~ s/\s*\(([^)]+)\)$//;
+ my $type = $1;
+ # Extract default value
+ $description =~ s/\s*\[default\s+([^]]+)\]$//;
+ my $default = $1;
+ push(@mod_params, {
+ NAME => $name,
+ TYPE => $type,
+ DEFVAL => $default,
+ DESC => $description,
+ });
+ }
+ # Print sorted list
+ foreach my $p (sort { $a->{NAME} cmp $b->{NAME} } @mod_params) {
+ printf "\t%-8s %-22s = %-20s %s\n", $p->{TYPE}, $p->{NAME}, $p->{DEFVAL}, $p->{DESC};
+ }
+ close F || die;
+}
diff --git a/drivers/dahdi/xpp/parport_debug.c b/drivers/dahdi/xpp/parport_debug.c
new file mode 100644
index 0000000..93049ef
--- /dev/null
+++ b/drivers/dahdi/xpp/parport_debug.c
@@ -0,0 +1,113 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2007, Xorcom
+ *
+ * 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/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+# warning "This module is tested only with 2.6 kernels"
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/parport.h>
+#include "parport_debug.h"
+
+static struct parport *debug_sync_parport = NULL;
+static int parport_toggles[8]; /* 8 bit flip-flop */
+
+void flip_parport_bit(unsigned char bitnum)
+{
+ static unsigned char last_value;
+ spinlock_t lock = SPIN_LOCK_UNLOCKED;
+ unsigned long flags;
+ unsigned char mask;
+ unsigned char value;
+
+ if(!debug_sync_parport) {
+ if(printk_ratelimit()) {
+ printk(KERN_NOTICE "%s: no debug parallel port\n",
+ THIS_MODULE->name);
+ }
+ return;
+ }
+ BUG_ON(bitnum > 7);
+ mask = 1 << bitnum;
+ spin_lock_irqsave(&lock, flags);
+ value = last_value & ~mask;
+ if(parport_toggles[bitnum] % 2) /* square wave */
+ value |= mask;
+ last_value = value;
+ parport_toggles[bitnum]++;
+ spin_unlock_irqrestore(&lock, flags);
+ parport_write_data(debug_sync_parport, value);
+}
+EXPORT_SYMBOL(flip_parport_bit);
+
+static void parport_attach(struct parport *port)
+{
+ printk(KERN_INFO "%s: Using %s for debugging\n", THIS_MODULE->name, port->name);
+ if(debug_sync_parport) {
+ printk(KERN_ERR "%s: Using %s, ignore new attachment %s\n",
+ THIS_MODULE->name, debug_sync_parport->name, port->name);
+ return;
+ }
+ parport_get_port(port);
+ debug_sync_parport = port;
+}
+
+static void parport_detach(struct parport *port)
+{
+ printk(KERN_INFO "%s: Releasing %s\n", THIS_MODULE->name, port->name);
+ if(debug_sync_parport != port) {
+ printk(KERN_ERR "%s: Using %s, ignore new detachment %s\n",
+ THIS_MODULE->name, debug_sync_parport->name, port->name);
+ return;
+ }
+ parport_put_port(debug_sync_parport);
+ debug_sync_parport = NULL;
+}
+
+static struct parport_driver debug_parport_driver = {
+ .name = "parport_debug",
+ .attach = parport_attach,
+ .detach = parport_detach,
+};
+
+int __init parallel_dbg_init(void)
+{
+ int ret;
+
+ ret = parport_register_driver(&debug_parport_driver);
+ return ret;
+}
+
+void __exit parallel_dbg_cleanup(void)
+{
+ parport_unregister_driver(&debug_parport_driver);
+}
+
+MODULE_DESCRIPTION("Use parallel port to debug drivers");
+MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("$Id:");
+
+module_init(parallel_dbg_init);
+module_exit(parallel_dbg_cleanup);
diff --git a/drivers/dahdi/xpp/parport_debug.h b/drivers/dahdi/xpp/parport_debug.h
new file mode 100644
index 0000000..138af99
--- /dev/null
+++ b/drivers/dahdi/xpp/parport_debug.h
@@ -0,0 +1,31 @@
+#ifndef PARPORT_DEBUG_H
+#define PARPORT_DEBUG_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2007, Xorcom
+ *
+ * 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.
+ *
+ */
+
+#ifdef DEBUG_SYNC_PARPORT
+void flip_parport_bit(unsigned char bitnum);
+#else
+#define flip_parport_bit(bitnum)
+#endif
+
+#endif /* PARPORT_DEBUG_H */
diff --git a/drivers/dahdi/xpp/utils/Makefile b/drivers/dahdi/xpp/utils/Makefile
new file mode 100644
index 0000000..2e3624c
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/Makefile
@@ -0,0 +1,144 @@
+PEDANTIC = -ansi -pedantic -std=c99
+
+RANLIB = ranlib
+INSTALL = install
+INSTALL_DATA = install -m 644
+
+#
+# Ugly hack to find kernel directories before/after the split
+# to kernel/user-space.
+#
+# These variables should be passed to us. But until then...
+#
+ZAPTEL_DIR ?= $(shell if [ -f "../../zaptel.h" ]; then echo "../.."; else echo "../../.."; fi)
+ZAP_KERNEL ?= $(shell if [ -d "$(ZAPTEL_DIR)/kernel" ]; then echo "$(ZAPTEL_DIR)/kernel"; else echo "$(ZAPTEL_DIR)"; fi)
+
+-include $(ZAPTEL_DIR)/makeopts
+
+INSTALL_DATA = $(INSTALL) -m 644
+
+# In 1.4 those are provided by autoconf through makeopts
+prefix ?= /usr
+datadir ?= $(prefix)/share
+mandir ?= $(datadir)/man
+INSTALL ?= install
+
+INSTALL_DATA = $(INSTALL) -m 644
+
+SBINDIR = $(prefix)/sbin
+DATADIR = $(datadir)/zaptel
+MANDIR = $(mandir)/man8
+HOTPLUG_USB_DIR = /etc/hotplug/usb
+UDEV_RULES_DIR = /etc/udev/rules.d
+PERLLIBDIR := $(shell eval `perl -V:sitelib`; echo "$$sitelib")
+PERL_DIRS := $(shell cd zconf; find * -name '[A-Z]*' -type d| xargs)
+PERL_MODS_PAT := *.pm $(PERL_DIRS:%=%/*.pm)
+PERL_MODS := $(shell cd zconf; echo $(PERL_MODS_PAT))
+
+XPD_FIRMWARE = $(wildcard ../firmwares/*.hex)
+XPD_INIT_DATA = $(XPD_FIRMWARE) init_fxo_modes
+XPD_INIT = $(wildcard ../init_card_?_*) xpp_fxloader
+
+# Variables that should be defined above, but need sane defaults:
+# FIXME: Are those values really sane?
+HOSTCC ?= $(CC)
+
+ifeq (,$(PBX_LIBUSB))
+# No PBX_LIBUSB? Maybe we compile against zaptel-1.2
+# Let's make a poor man detection of libusb
+PBX_LIBUSB = $(shell if [ -r /usr/include/usb.h ]; then echo 1; else echo 0; fi)
+endif
+
+WCTDM=$(shell for i in $(ZAP_KERNEL)/wctdm.c $(ZAP_KERNEL)/fxo_modes.h; do [ -f "$$i" ] && echo "$$i"; done)
+
+CFLAGS = -g -Wall $(EXTRA_CFLAGS)
+
+%.8: %
+ pod2man --section 8 $^ > $@ || $(RM) $@
+PERL_SCRIPTS = \
+ zt_registration \
+ xpp_sync \
+ lszaptel \
+ xpp_blink \
+ zapconf \
+ zaptel_hardware \
+ #
+
+PERL_MANS = $(PERL_SCRIPTS:%=%.8)
+
+TARGETS = init_fxo_modes print_modes perlcheck
+PROG_INSTALL = genzaptelconf
+MAN_INSTALL = $(PROG_INSTALL:%=%.8)
+ifeq (1,$(PBX_LIBUSB))
+TARGETS += libhexfile.a fpga_load test_parse
+PROG_INSTALL += fpga_load
+endif
+ifneq (,$(PERLLIBDIR))
+PROG_INSTALL += $(PERL_SCRIPTS)
+TARGETS += $(PERL_MANS)
+endif
+
+all: $(TARGETS)
+
+docs: $(PERL_MANS)
+
+install: all
+ $(INSTALL) -d $(DESTDIR)$(SBINDIR)
+ $(INSTALL) $(PROG_INSTALL) $(DESTDIR)$(SBINDIR)/
+ $(INSTALL) -d $(DESTDIR)$(DATADIR)
+ $(INSTALL_DATA) $(XPD_INIT_DATA) $(DESTDIR)$(DATADIR)/
+ $(INSTALL) $(XPD_INIT) $(DESTDIR)$(DATADIR)/
+ $(INSTALL) -d $(DESTDIR)$(MANDIR)
+ $(INSTALL_DATA) $(MAN_INSTALL) $(DESTDIR)$(MANDIR)/
+ $(INSTALL) -d $(DESTDIR)$(HOTPLUG_USB_DIR)
+ $(INSTALL_DATA) xpp_fxloader.usermap $(DESTDIR)$(HOTPLUG_USB_DIR)/
+ # for backward compatibility and for hotplug users:
+ ln -sf $(DATADIR)/xpp_fxloader $(DESTDIR)$(HOTPLUG_USB_DIR)/
+ $(INSTALL) -d $(DESTDIR)$(UDEV_RULES_DIR)
+ $(INSTALL_DATA) xpp.rules $(DESTDIR)$(UDEV_RULES_DIR)/
+ifneq (,$(PERLLIBDIR))
+ $(INSTALL) -d $(DESTDIR)$(PERLLIBDIR)
+ for i in $(PERL_DIRS); \
+ do \
+ $(INSTALL) -d "$(DESTDIR)$(PERLLIBDIR)/$$i"; \
+ done
+ for i in $(PERL_MODS); \
+ do \
+ $(INSTALL_DATA) "zconf/$$i" "$(DESTDIR)$(PERLLIBDIR)/$$i"; \
+ done
+endif
+
+libhexfile.a: hexfile.o
+ $(AR) cru $@ $^
+ $(RANLIB) $@
+
+fpga_load: fpga_load.o libhexfile.a
+ $(CC) -L. -o $@ $@.o $(EXTRA_LIBS) -lhexfile -lusb
+
+fpga_load.o: CFLAGS+=-D_GNU_SOURCE # We use memrchr()
+
+hexfile.o: hexfile.c hexfile.h
+ $(CC) $(CFLAGS) $(PEDANTIC) -c $<
+
+test_parse.o: test_parse.c hexfile.h
+ $(CC) $(CFLAGS) $(PEDANTIC) -c $<
+
+test_parse: test_parse.o libhexfile.a
+ $(CC) -L. -o $@ $@.o $(EXTRA_LIBS) -lhexfile -lusb
+
+print_modes: print_modes.c wctdm_fxomodes.h
+ $(HOSTCC) -o $@ $(CFLAGS) $<
+
+wctdm_fxomodes.h: $(WCTDM)
+ @echo Building FXO modes from: $(WCTDM)
+ perl -n -e 'print if (/^static struct fxo_mode {$$/ .. /};$$/)' $(WCTDM) >$@ || rm -f $@
+
+init_fxo_modes: print_modes
+ ./$< >$@
+
+perlcheck: $(PERL_SCRIPTS)
+ for i in $^; do perl -I./zconf -c $$i || exit 1; done
+ touch $@
+
+clean:
+ $(RM) *.o $(TARGETS)
diff --git a/drivers/dahdi/xpp/utils/astribank_hook b/drivers/dahdi/xpp/utils/astribank_hook
new file mode 100755
index 0000000..8dd13c9
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/astribank_hook
@@ -0,0 +1,57 @@
+#! /bin/sh
+
+# This is an example of an Astribank device hook. The xpp.rules file
+# calls /usr/share/zaptel/astribank_hook after a new Astribank is ready
+# and after and old Astribank device has been destroyed.
+#
+
+set -e
+
+me=`basename $0`
+INIT_DIR=`dirname $0`
+XPP_BASE=/proc/xpp
+export XPP_BASE
+LOGGER="logger -s -t $me"
+
+ZAPTEL_BOOT_DEBIAN=${ZAPTEL_BOOT_DEBIAN:-/etc/default/zaptel}
+ZAPTEL_BOOT_FEDORA=${ZAPTEL_BOOT_FEDORA:-/etc/sysconfig/zaptel}
+
+# read default configuration from /etc/default/zaptel
+if [ -r $ZAPTEL_BOOT_DEBIAN ]; then . $ZAPTEL_BOOT_DEBIAN; fi
+if [ -r $ZAPTEL_BOOT_FEDORA ]; then . $ZAPTEL_BOOT_FEDORA; fi
+
+if [ "$ASTRIBANK_HOOK_DISABLED" != '' ]; then
+ $LOGGER -p kern.info "Exiting... ASTRIBANK_HOOK_DISABLED"
+ exit 0
+fi
+
+# Always redirect stderr somewhere, otherwise the shell script will die
+# when it tries to do I/O related stuff on closed file descriptor.
+# Our default is to throw it down the bit-bucket.
+#exec 2> /dev/console
+## If you wish to trace this script:
+#exec 2> "/tmp/astribank_hook_$XBUS_NAME"
+
+# Maybe add some logging
+#$LOGGER -p kern.info "$0: $ACTION: $*."
+
+case "$ACTION" in
+add)
+ # An Astribank was added and is initialized and ready.
+ # Put your shell commands bellow
+ :
+ ;;
+remove)
+ # An Astribank was Removed.
+ # Put your shell commands bellow
+ # You should not access /proc/xpp/... or run related utilities
+ # like xpp_sync, since this is likely to cause very bad race
+ # conditions during driver removal.
+ :
+ ;;
+*)
+ ;;
+esac
+
+# Maybe add some logging
+#$LOGGER -p kern.info "$0: Done: $ACTION: $*."
diff --git a/drivers/dahdi/xpp/utils/example_default_zaptel b/drivers/dahdi/xpp/utils/example_default_zaptel
new file mode 100644
index 0000000..f60b651
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/example_default_zaptel
@@ -0,0 +1,31 @@
+# Disables hotplug firmware loading
+#XPP_HOTPLUG_DISABLED=yes
+#
+# Disables udev hook called when an astribank is added and ready
+# or removed.
+#ASTRIBANK_HOOK_DISABLED=yes
+
+# Setup for XPP PRI. This allows to have fixed settings:
+# 1. The variable XPP_PRI_SETUP contains a whitespace separated list of
+# port specifications.
+# 2. Each port specification contains a match expression, a '=' and
+# a setting string.
+# 2. Match expressions may be:
+# - CONNECTOR/usb..../XPD-nn To identify by physical connector
+# - NUM/XBUS-mm/XPD-nn To identify by bus number
+# 4. Match expressions may contain "wildcards" (which are translated
+# internally to regular expressions):
+# * matches zero or more characters.
+# ? matches one charater
+# 5. The list of matches is scanned from beginning to end. First match wins.
+# 6. The list implicitly contains an 'NUM/*=TE,E1' catch all default, appended
+# to its end.
+# 7. The setting string is composed of comma separated settings. Valid
+# settings are:
+# - NT or TE
+# - E1 or T1 or J1
+#
+XPP_PRI_SETUP='
+ CONNECTOR/usb-0000:00:1d.7-1/XPD-01=NT,E1
+ NUM/*/XPD-03=NT,E1
+ '
diff --git a/drivers/dahdi/xpp/utils/fpga_load.8 b/drivers/dahdi/xpp/utils/fpga_load.8
new file mode 100644
index 0000000..dd21db0
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/fpga_load.8
@@ -0,0 +1,86 @@
+.TH "FPGA_LOAD" "8" "16 April 2006" "" ""
+
+.SH NAME
+fpga_load \- Xorcom Astribank (xpp) firmware tool
+.SH SYNOPSIS
+
+.B fpga_load
+[\fB-g\fR] [\fB-r\fR] [\fB-v\fR] \fB-D \fR{/proc/bus/usb|/dev/bus/usb}/\fIBUS/DEV\fR
+
+.B fpga_load
+[\fB-g\fR] [\fB-v\fR] \fB-D \fR{/proc/bus/usb|/dev/bus/usb}/\fIBUS/DEV\fR \fB-I \fIfirmware.hex\fR [\fB-b \fIdump.bin\fR] [\fB-i\fR]
+
+.B fpga_load -h
+
+.SH DESCRIPTION
+.B fpga_load
+loads the FPGA firmware to the Xorcom Astribank device.
+The syntax resembles that of fxload(8).
+
+.SH OPTIONS
+.B -b
+.I dump.bin
+.RS
+Before writing firmware, bump the processed binary file to
+.I dump.bin\fR.
+.RE
+
+.B -D
+.I DEVICE
+.RS
+Required. The device to read from/write to. On modern UDEV-based system
+this is usually /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR,
+where \fIbus_num\fR and \fIdevice_num\fR are the first two numbers in the
+output of lsusb(8).
+On older systems that use usbfs, it is usually
+/proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR.
+.RE
+
+.B -r
+.RS
+Reset the Astribank and renumerate its USB connection to power on product ID.
+.RE
+
+.B -g
+.RS
+Dump all eeprom data to standard output.
+.RE
+
+.B -I
+.I fireware_file
+.RS
+The firmware file to write to the device.
+.RE
+
+.B -i
+.RS
+Show information about the firmware file (valid only with \fB-I\fR option).
+Example:
+.PP
+ ./FPGA_1151.hex: Version=3297 Checksum=58270
+
+In particular, the calculated checksum should match the output of \fIsum(1)\fR
+on the binary firmware file generated by the \fB-b\fR option.
+.RE
+
+.B -v
+.RS
+Increase verbosity. May be used multiple times.
+.RE
+
+.B -h
+.RS
+Displays usage message.
+.RE
+
+.SH SEE ALSO
+fxload(8), lsusb(8)
+
+.SH AUTHOR
+This manual page was written by Tzafrir Cohen <tzafrir.cohen@xorcom.com> .
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/drivers/dahdi/xpp/utils/fpga_load.c b/drivers/dahdi/xpp/utils/fpga_load.c
new file mode 100644
index 0000000..7102501
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/fpga_load.c
@@ -0,0 +1,1007 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <usb.h>
+#include "hexfile.h"
+
+static const char rcsid[] = "$Id$";
+
+#define ERR(fmt, arg...) do { \
+ if(verbose >= LOG_ERR) \
+ fprintf(stderr, "%s: ERROR (%d): " fmt, \
+ progname, __LINE__, ## arg); \
+ } while(0);
+#define INFO(fmt, arg...) do { \
+ if(verbose >= LOG_INFO) \
+ fprintf(stderr, "%s: " fmt, \
+ progname, ## arg); \
+ } while(0);
+#define DBG(fmt, arg...) do { \
+ if(verbose >= LOG_DEBUG) \
+ fprintf(stderr, "%s: DBG: " fmt, \
+ progname, ## arg); \
+ } while(0);
+
+static int verbose = LOG_WARNING;
+static char *progname;
+static int disconnected = 0;
+
+#define MAX_HEX_LINES 10000
+#define PACKET_SIZE 512
+#define EEPROM_SIZE 16
+#define LABEL_SIZE 8
+#define TIMEOUT 5000
+
+
+/* My device parameters */
+#define MY_EP_OUT 0x04
+#define MY_EP_IN 0x88
+
+#define FPGA_EP_OUT 0x02
+#define FPGA_EP_IN 0x86
+
+/* USB firmware types */
+#define USB_11xx 0
+#define USB_FIRMWARE_II 1
+
+#define TYPE_ENTRY(t,ni,n,ne,out,in,...) \
+ [t] = { \
+ .type_code = (t), \
+ .num_interfaces = (ni), \
+ .my_interface_num = (n), \
+ .num_endpoints = (ne), \
+ .my_ep_in = (in), \
+ .my_ep_out = (out), \
+ .name = #t, \
+ .endpoints = { __VA_ARGS__ }, \
+ }
+
+static const struct astribank_type {
+ int type_code;
+ int num_interfaces;
+ int my_interface_num;
+ int num_endpoints;
+ int my_ep_out;
+ int my_ep_in;
+ char *name;
+ int endpoints[4]; /* for matching */
+} astribank_types[] = {
+ TYPE_ENTRY(USB_11xx, 1, 0, 4, MY_EP_OUT, MY_EP_IN,
+ FPGA_EP_OUT,
+ MY_EP_OUT,
+ FPGA_EP_IN,
+ MY_EP_IN),
+ TYPE_ENTRY(USB_FIRMWARE_II, 2, 1, 2, MY_EP_OUT, MY_EP_IN,
+ MY_EP_OUT,
+ MY_EP_IN),
+};
+#undef TYPE_ENTRY
+
+enum fpga_load_packet_types {
+ PT_STATUS_REPLY = 0x01,
+ PT_DATA_PACKET = 0x01,
+#ifdef XORCOM_INTERNAL
+ PT_EEPROM_SET = 0x04,
+#endif
+ PT_EEPROM_GET = 0x08,
+ PT_RENUMERATE = 0x10,
+ PT_RESET = 0x20,
+ PT_BAD_COMMAND = 0xAA
+};
+
+struct myeeprom {
+ uint8_t source;
+ uint16_t vendor;
+ uint16_t product;
+ uint8_t release_major;
+ uint8_t release_minor;
+ uint8_t reserved;
+ uint8_t label[LABEL_SIZE];
+} PACKED;
+
+struct fpga_packet_header {
+ struct {
+ uint8_t op;
+ } PACKED header;
+ union {
+ struct {
+ uint16_t seq;
+ uint8_t status;
+ } PACKED status_reply;
+ struct {
+ uint16_t seq;
+ uint8_t reserved;
+ uint8_t data[ZERO_SIZE];
+ } PACKED data_packet;
+ struct {
+ struct myeeprom data;
+ } PACKED eeprom_set;
+ struct {
+ struct myeeprom data;
+ } PACKED eeprom_get;
+ } d;
+} PACKED;
+
+enum fpga_load_status {
+ FW_FAIL_RESET = 1,
+ FW_FAIL_TRANS = 2,
+ FW_TRANS_OK = 4,
+ FW_CONFIG_DONE = 8
+};
+
+struct my_usb_device {
+ struct usb_device *dev;
+ usb_dev_handle *handle;
+ int my_interface_num;
+ int my_ep_out;
+ int my_ep_in;
+ char iManufacturer[BUFSIZ];
+ char iProduct[BUFSIZ];
+ char iSerialNumber[BUFSIZ];
+ char iInterface[BUFSIZ];
+ int is_usb2;
+ struct myeeprom eeprom;
+ const struct astribank_type *abtype;
+};
+
+const char *load_status2str(enum fpga_load_status s)
+{
+ switch(s) {
+ case FW_FAIL_RESET: return "FW_FAIL_RESET";
+ case FW_FAIL_TRANS: return "FW_FAIL_TRANS";
+ case FW_TRANS_OK: return "FW_TRANS_OK";
+ case FW_CONFIG_DONE: return "FW_CONFIG_DONE";
+ default: return "UNKNOWN";
+ }
+}
+
+/* return 1 if:
+ * - str has a number
+ * - It is larger than 0
+ * - It equals num
+ */
+int num_matches(int num, const char* str) {
+ int str_val = atoi(str);
+ if (str_val <= 0)
+ return 0;
+ return (str_val == num);
+}
+
+struct usb_device *dev_of_path(const char *path)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+ char dirname[PATH_MAX];
+ char filename[PATH_MAX];
+ const char *p;
+ int bnum;
+ int dnum;
+ int ret;
+
+ assert(path != NULL);
+ if(access(path, F_OK) < 0) {
+ perror(path);
+ return NULL;
+ }
+ /* Find last '/' */
+ if((p = memrchr(path, '/', strlen(path))) == NULL) {
+ ERR("Missing a '/' in %s\n", path);
+ return NULL;
+ }
+ /* Get the device number */
+ ret = sscanf(p + 1, "%d", &dnum);
+ if(ret != 1) {
+ ERR("Path tail is not a device number: '%s'\n", p);
+ return NULL;
+ }
+ /* Search for a '/' before that */
+ p = memrchr(path, '/', p - path);
+ if(p == NULL)
+ p = path; /* Relative path */
+ else
+ p++; /* skip '/' */
+ /* Get the bus number */
+ ret = sscanf(p, "%d", &bnum);
+ if(ret != 1) {
+ ERR("Path tail is not a bus number: '%s'\n", p);
+ return NULL;
+ }
+ sprintf(dirname, "%03d", bnum);
+ sprintf(filename, "%03d", dnum);
+ for (bus = usb_busses; bus; bus = bus->next) {
+ if (! num_matches(bnum, bus->dirname))
+ //if(strcmp(bus->dirname, dirname) != 0)
+ continue;
+ for (dev = bus->devices; dev; dev = dev->next) {
+ //if(strcmp(dev->filename, filename) == 0)
+ if (num_matches(dnum, dev->filename))
+ return dev;
+ }
+ }
+ ERR("no usb device match '%s'\n", path);
+ return NULL;
+}
+
+int get_usb_string(char *buf, unsigned int len, uint16_t item, usb_dev_handle *handle)
+{
+ char tmp[BUFSIZ];
+ int ret;
+
+ if (!item)
+ return 0;
+ ret = usb_get_string_simple(handle, item, tmp, BUFSIZ);
+ if (ret <= 0)
+ return ret;
+ return snprintf(buf, len, "%s", tmp);
+}
+
+void my_usb_device_cleanup(struct my_usb_device *mydev)
+{
+ assert(mydev != NULL);
+ if(!mydev->handle) {
+ return; /* Nothing to do */
+ }
+ if(!disconnected) {
+ if(usb_release_interface(mydev->handle, mydev->abtype->my_interface_num) != 0) {
+ ERR("Releasing interface: usb: %s\n", usb_strerror());
+ }
+ }
+ if(usb_close(mydev->handle) != 0) {
+ ERR("Closing device: usb: %s\n", usb_strerror());
+ }
+ disconnected = 1;
+ mydev->handle = NULL;
+}
+
+static void show_device_info(const struct my_usb_device *mydev)
+{
+ const struct myeeprom *eeprom;
+ uint8_t data[LABEL_SIZE + 1];
+
+ assert(mydev != NULL);
+ eeprom = &mydev->eeprom;
+ memset(data, 0, LABEL_SIZE + 1);
+ memcpy(data, eeprom->label, LABEL_SIZE);
+ printf("USB Firmware Type: [%s]\n", mydev->abtype->name);
+ printf("USB iManufacturer: [%s]\n", mydev->iManufacturer);
+ printf("USB iProduct: [%s]\n", mydev->iProduct);
+ printf("USB iSerialNumber: [%s]\n", mydev->iSerialNumber);
+ printf("EEPROM Source: 0x%02X\n", eeprom->source);
+ printf("EEPROM Vendor: 0x%04X\n", eeprom->vendor);
+ printf("EEPROM Product: 0x%04X\n", eeprom->product);
+ printf("EEPROM Release: %d.%03d\n", eeprom->release_major, eeprom->release_minor);
+ printf("EEPROM Label: HEX(%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X) [%s]\n",
+ data[0], data[1], data[2], data[3],
+ data[4], data[5], data[6], data[7], data);
+}
+
+void dump_packet(const char *msg, const char *buf, int len)
+{
+ int i;
+
+ for(i = 0; i < len; i++)
+ INFO("%s: %2d> 0x%02X\n", msg, i, (uint8_t)buf[i]);
+}
+
+int send_usb(const char *msg, struct my_usb_device *mydev, struct fpga_packet_header *phead, int len, int timeout)
+{
+ char *p = (char *)phead;
+ int ret;
+
+ if(verbose >= LOG_DEBUG)
+ dump_packet(msg, p, len);
+ if(mydev->my_ep_out & USB_ENDPOINT_IN) {
+ ERR("send_usb called with an input endpoint 0x%x\n", mydev->my_ep_out);
+ return -EINVAL;
+ }
+ ret = usb_bulk_write(mydev->handle, mydev->my_ep_out, p, len, timeout);
+ if(ret < 0) {
+ /*
+ * If the device was gone, it may be the
+ * result of renumeration. Ignore it.
+ */
+ if(ret != -ENODEV) {
+ ERR("bulk_write to endpoint 0x%x failed: %s\n", mydev->my_ep_out, usb_strerror());
+ dump_packet("send_usb[ERR]", p, len);
+ } else {
+ disconnected = 1;
+ my_usb_device_cleanup(mydev);
+ }
+ return ret;
+ } else if(ret != len) {
+ ERR("bulk_write to endpoint 0x%x short write: %s\n", mydev->my_ep_out, usb_strerror());
+ dump_packet("send_usb[ERR]", p, len);
+ return -EFAULT;
+ }
+ return ret;
+}
+
+int recv_usb(const char *msg, struct my_usb_device *mydev, char *buf, size_t len, int timeout)
+{
+ int ret;
+
+ if(mydev->my_ep_in & USB_ENDPOINT_OUT) {
+ ERR("recv_usb called with an output endpoint 0x%x\n", mydev->my_ep_in);
+ return -EINVAL;
+ }
+ ret = usb_bulk_read(mydev->handle, mydev->my_ep_in, buf, len, timeout);
+ if(ret < 0) {
+ ERR("bulk_read from endpoint 0x%x failed: %s\n", mydev->my_ep_in, usb_strerror());
+ return ret;
+ }
+ if(verbose >= LOG_DEBUG)
+ dump_packet(msg, buf, ret);
+ return ret;
+}
+
+#ifdef XORCOM_INTERNAL
+int eeprom_set(struct my_usb_device *mydev, const struct myeeprom *eeprom)
+{
+ int ret;
+ int len;
+ char buf[PACKET_SIZE];
+ struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+
+ DBG("%s Start...\n", __FUNCTION__);
+ assert(mydev != NULL);
+ phead->header.op = PT_EEPROM_SET;
+ memcpy(&phead->d.eeprom_set.data, eeprom, EEPROM_SIZE);
+ len = sizeof(phead->d.eeprom_set) + sizeof(phead->header.op);
+ ret = send_usb("eeprom_set[W]", mydev, phead, len, TIMEOUT);
+ if(ret < 0)
+ return ret;
+ ret = recv_usb("eeprom_set[R]", mydev, buf, sizeof(buf), TIMEOUT);
+ if(ret <= 0)
+ return ret;
+ phead = (struct fpga_packet_header *)buf;
+ if(phead->header.op == PT_BAD_COMMAND) {
+ ERR("Firmware rejected PT_EEPROM_SET command\n");
+ return -EINVAL;
+ } else if(phead->header.op != PT_EEPROM_SET) {
+ ERR("Got unexpected reply op=%d\n", phead->header.op);
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif
+
+int eeprom_get(struct my_usb_device *mydev)
+{
+ int ret;
+ int len;
+ char buf[PACKET_SIZE];
+ struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+ struct myeeprom *eeprom;
+
+ assert(mydev != NULL);
+ eeprom = &mydev->eeprom;
+ DBG("%s Start...\n", __FUNCTION__);
+ phead->header.op = PT_EEPROM_GET;
+ len = sizeof(phead->header.op); /* warning: sending small packet */
+ ret = send_usb("eeprom_get[W]", mydev, phead, len, TIMEOUT);
+ if(ret < 0)
+ return ret;
+ ret = recv_usb("eeprom_get[R]", mydev, buf, sizeof(buf), TIMEOUT);
+ if(ret <= 0)
+ return ret;
+ phead = (struct fpga_packet_header *)buf;
+ if(phead->header.op == PT_BAD_COMMAND) {
+ ERR("PT_BAD_COMMAND\n");
+ return -EINVAL;
+ } else if(phead->header.op != PT_EEPROM_GET) {
+ ERR("Got unexpected reply op=%d\n", phead->header.op);
+ return -EINVAL;
+ }
+ memcpy(eeprom, &phead->d.eeprom_get.data, EEPROM_SIZE);
+ return 0;
+}
+
+int send_hexline(struct my_usb_device *mydev, struct hexline *hexline, int seq)
+{
+ int ret;
+ int len;
+ uint8_t *data;
+ char buf[PACKET_SIZE];
+ struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+ enum fpga_load_status status;
+
+ assert(mydev != NULL);
+ assert(hexline != NULL);
+ if(hexline->d.content.header.tt != TT_DATA) {
+ DBG("Non data record %d type = %d\n", seq, hexline->d.content.header.tt);
+ return 0;
+ }
+ len = hexline->d.content.header.ll; /* don't send checksum */
+ data = hexline->d.content.tt_data.data;
+ phead->header.op = PT_DATA_PACKET;
+ phead->d.data_packet.seq = seq;
+ phead->d.data_packet.reserved = 0x00;
+ memcpy(phead->d.data_packet.data, data, len);
+ len += sizeof(hexline->d.content.header);
+ DBG("%04d+\r", seq);
+ ret = send_usb("hexline[W]", mydev, phead, len, TIMEOUT);
+ if(ret < 0)
+ return ret;
+ ret = recv_usb("hexline[R]", mydev, buf, sizeof(buf), TIMEOUT);
+ if(ret <= 0)
+ return ret;
+ DBG("%04d-\r", seq);
+ phead = (struct fpga_packet_header *)buf;
+ if(phead->header.op != PT_STATUS_REPLY) {
+ ERR("Got unexpected reply op=%d\n", phead->header.op);
+ dump_packet("hexline[ERR]", buf, ret);
+ return -EINVAL;
+ }
+ status = (enum fpga_load_status)phead->d.status_reply.status;
+ switch(status) {
+ case FW_TRANS_OK:
+ case FW_CONFIG_DONE:
+ break;
+ case FW_FAIL_RESET:
+ case FW_FAIL_TRANS:
+ ERR("status reply %s (%d)\n", load_status2str(status), status);
+ dump_packet("hexline[ERR]", buf, ret);
+ return -EPROTO;
+ default:
+ ERR("Unknown status reply %d\n", status);
+ dump_packet("hexline[ERR]", buf, ret);
+ return -EPROTO;
+ }
+ return 0;
+}
+
+//. returns > 0 - ok, the number of lines sent
+//. returns < 0 - error number
+int send_splited_hexline(struct my_usb_device *mydev, struct hexline *hexline, int seq, uint8_t maxwidth)
+{
+ struct hexline *extraline;
+ int linessent = 0;
+ int allocsize;
+ int extra_offset = 0;
+ unsigned int this_line = 0;
+ uint8_t bytesleft = 0;
+
+ assert(mydev != NULL);
+ if(!hexline) {
+ ERR("Bad record %d type = %d\n", seq, hexline->d.content.header.tt);
+ return -EINVAL;
+ }
+ bytesleft = hexline->d.content.header.ll;
+ // split the line into several lines
+ while (bytesleft > 0) {
+ int status;
+ this_line = (bytesleft >= maxwidth) ? maxwidth : bytesleft;
+ allocsize = sizeof(struct hexline) + this_line + 1;
+ // generate the new line
+ if((extraline = (struct hexline *)malloc(allocsize)) == NULL) {
+ ERR("Not enough memory for spliting the lines\n" );
+ return -EINVAL;
+ }
+ memset(extraline, 0, allocsize);
+ extraline->d.content.header.ll = this_line;
+ extraline->d.content.header.offset = hexline->d.content.header.offset + extra_offset;
+ extraline->d.content.header.tt = hexline->d.content.header.tt;
+ memcpy( extraline->d.content.tt_data.data, hexline->d.content.tt_data.data+extra_offset, this_line);
+ status = send_hexline(mydev, extraline, seq+linessent );
+ // cleanups
+ free(extraline);
+ extra_offset += this_line;
+ bytesleft -= this_line;
+ if (status)
+ return status;
+ linessent++;
+ }
+ return linessent;
+}
+
+int match_usb_device_identity(const struct usb_config_descriptor *config_desc,
+ const struct astribank_type *ab)
+{
+ struct usb_interface *interface;
+ struct usb_interface_descriptor *iface_desc;
+
+ if(config_desc->bNumInterfaces <= ab->my_interface_num)
+ return 0;
+ interface = &config_desc->interface[ab->my_interface_num];
+ iface_desc = interface->altsetting;
+
+ return iface_desc->bInterfaceClass == 0xFF &&
+ iface_desc->bInterfaceNumber == ab->my_interface_num &&
+ iface_desc->bNumEndpoints == ab->num_endpoints;
+}
+
+const struct astribank_type *my_usb_device_identify(const char devpath[], struct my_usb_device *mydev)
+{
+ struct usb_device_descriptor *dev_desc;
+ struct usb_config_descriptor *config_desc;
+ int i;
+
+ assert(mydev != NULL);
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ mydev->dev = dev_of_path(devpath);
+ if(!mydev->dev) {
+ ERR("Bailing out\n");
+ return 0;
+ }
+ dev_desc = &mydev->dev->descriptor;
+ config_desc = mydev->dev->config;
+ for(i = 0; i < sizeof(astribank_types)/sizeof(astribank_types[0]); i++) {
+ if(match_usb_device_identity(config_desc, &astribank_types[i])) {
+ DBG("Identified[%d]: interfaces=%d endpoints=%d: \"%s\"\n",
+ i,
+ astribank_types[i].num_interfaces,
+ astribank_types[i].num_endpoints,
+ astribank_types[i].name);
+ return &astribank_types[i];
+ }
+ }
+ return NULL;
+}
+
+int my_usb_device_init(const char devpath[], struct my_usb_device *mydev, const struct astribank_type *abtype)
+{
+ struct usb_device_descriptor *dev_desc;
+ struct usb_config_descriptor *config_desc;
+ struct usb_interface *interface;
+ struct usb_interface_descriptor *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int ret;
+ int i;
+
+ assert(mydev != NULL);
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ mydev->dev = dev_of_path(devpath);
+ if(!mydev->dev) {
+ ERR("Bailing out\n");
+ return 0;
+ }
+ mydev->handle = usb_open(mydev->dev);
+ if(!mydev->handle) {
+ ERR("Failed to open usb device '%s/%s': %s\n", mydev->dev->bus->dirname, mydev->dev->filename, usb_strerror());
+ return 0;
+ }
+ if(usb_claim_interface(mydev->handle, abtype->my_interface_num) != 0) {
+ ERR("usb_claim_interface: %s\n", usb_strerror());
+ return 0;
+ }
+ dev_desc = &mydev->dev->descriptor;
+ config_desc = mydev->dev->config;
+ if (!config_desc) {
+ ERR("usb interface without a configuration\n");
+ return 0;
+ }
+ interface = &config_desc->interface[abtype->my_interface_num];
+ iface_desc = interface->altsetting;
+ endpoint = iface_desc->endpoint;
+ mydev->is_usb2 = (endpoint->wMaxPacketSize == 512);
+ for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) {
+ if(endpoint->bEndpointAddress != abtype->endpoints[i]) {
+ ERR("Wrong endpoint 0x%X (at index %d)\n", endpoint->bEndpointAddress, i);
+ return 0;
+ }
+ if(endpoint->bEndpointAddress == MY_EP_OUT || endpoint->bEndpointAddress == MY_EP_IN) {
+ if(endpoint->wMaxPacketSize > PACKET_SIZE) {
+ ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize);
+ return 0;
+ }
+ }
+ }
+ mydev->abtype = abtype;
+ mydev->my_ep_in = abtype->my_ep_in;
+ mydev->my_ep_out = abtype->my_ep_out;
+ ret = get_usb_string(mydev->iManufacturer, BUFSIZ, dev_desc->iManufacturer, mydev->handle);
+ ret = get_usb_string(mydev->iProduct, BUFSIZ, dev_desc->iProduct, mydev->handle);
+ ret = get_usb_string(mydev->iSerialNumber, BUFSIZ, dev_desc->iSerialNumber, mydev->handle);
+ ret = get_usb_string(mydev->iInterface, BUFSIZ, iface_desc->iInterface, mydev->handle);
+ INFO("ID=%04X:%04X Manufacturer=[%s] Product=[%s] SerialNumber=[%s] Interface=[%s]\n",
+ dev_desc->idVendor,
+ dev_desc->idProduct,
+ mydev->iManufacturer,
+ mydev->iProduct,
+ mydev->iSerialNumber,
+ mydev->iInterface);
+ if(usb_clear_halt(mydev->handle, mydev->my_ep_out) != 0) {
+ ERR("Clearing output endpoint: %s\n", usb_strerror());
+ return 0;
+ }
+ if(usb_clear_halt(mydev->handle, mydev->my_ep_in) != 0) {
+ ERR("Clearing input endpoint: %s\n", usb_strerror());
+ return 0;
+ }
+ return 1;
+}
+
+int renumerate_device(struct my_usb_device *mydev, enum fpga_load_packet_types pt)
+{
+ char buf[PACKET_SIZE];
+ struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+ int ret;
+
+ assert(mydev != NULL);
+ DBG("Renumerating with 0x%X\n", pt);
+ phead->header.op = pt;
+ ret = send_usb("renumerate[W]", mydev, phead, 1, TIMEOUT);
+ if(ret < 0 && ret != -ENODEV)
+ return ret;
+#if 0
+ /*
+ * FIXME: we count on our USB firmware to reset the device... should we?
+ */
+ ret = usb_reset(mydev->handle);
+ if(ret < 0) {
+ ERR("usb_reset: %s\n", usb_strerror());
+ return -ENODEV;
+ }
+#endif
+ return 0;
+}
+
+/*
+ * Returns: true on success, false on failure
+ */
+int fpga_load(struct my_usb_device *mydev, const struct hexdata *hexdata)
+{
+ unsigned int i;
+ unsigned int j = 0;
+ int ret;
+ int finished = 0;
+ const char *v = hexdata->version_info;
+
+ v = (v[0]) ? v : "Unknown";
+ assert(mydev != NULL);
+ INFO("FPGA_LOAD (version %s)\n", v);
+ /*
+ * i - is the line number
+ * j - is the sequence number, on USB 2, i=j, but on
+ * USB 1 send_splited_hexline may increase the sequence
+ * number, as it needs
+ */
+ for(i = 0; i < hexdata->maxlines; i++) {
+ struct hexline *hexline = hexdata->lines[i];
+
+ if(!hexline)
+ break;
+ if(finished) {
+ ERR("Extra data after End Of Data Record (line %d)\n", i);
+ return 0;
+ }
+ if(hexline->d.content.header.tt == TT_EOF) {
+ DBG("End of data\n");
+ finished = 1;
+ continue;
+ }
+ if(mydev->is_usb2) {
+ if((ret = send_hexline(mydev, hexline, i)) != 0) {
+ perror("Failed sending hexline");
+ return 0;
+ }
+ } else {
+ if((ret = send_splited_hexline(mydev, hexline, j, 60)) < 0) {
+ perror("Failed sending hexline (splitting did not help)");
+ return 0;
+ }
+ j += ret;
+ }
+ }
+ DBG("Finished...\n");
+ return 1;
+}
+
+#include <getopt.h>
+
+void usage()
+{
+ fprintf(stderr, "Usage: %s -D {/proc/bus/usb|/dev/bus/usb}/<bus>/<dev> [options...]\n", progname);
+ fprintf(stderr, "\tOptions:\n");
+ fprintf(stderr, "\t\t[-r] # Reset the device\n");
+ fprintf(stderr, "\t\t[-b <binfile>] # Output to <binfile>\n");
+ fprintf(stderr, "\t\t[-I <hexfile>] # Input from <hexfile>\n");
+ fprintf(stderr, "\t\t[-H <hexfile>] # Output to <hexfile> ('-' is stdout)\n");
+ fprintf(stderr, "\t\t[-i] # Show hexfile information\n");
+ fprintf(stderr, "\t\t[-g] # Get eeprom from device\n");
+ fprintf(stderr, "\t\t[-v] # Increase verbosity\n");
+#ifdef XORCOM_INTERNAL
+ fprintf(stderr, "\t\t[-C srC byte] # Set Address sourCe (default: C0)\n");
+ fprintf(stderr, "\t\t[-V vendorid] # Set Vendor id on device\n");
+ fprintf(stderr, "\t\t[-P productid] # Set Product id on device\n");
+ fprintf(stderr, "\t\t[-R release] # Set Release. 2 dot separated decimals\n");
+ fprintf(stderr, "\t\t[-L label] # Set label.\n");
+#endif
+ exit(1);
+}
+
+static void parse_report_func(int level, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ if(level <= verbose)
+ vfprintf(stderr, msg, ap);
+ va_end(ap);
+}
+
+#ifdef XORCOM_INTERNAL
+static void eeprom_fill(struct myeeprom *myeeprom,
+ const char vendor[],
+ const char product[],
+ const char release[],
+ const char label[],
+ const char source[])
+{
+ // FF: address source is from device. C0: from eeprom
+ if (source)
+ myeeprom->source = strtoul(source, NULL, 0);
+ else
+ myeeprom->source = 0xC0;
+ if(vendor)
+ myeeprom->vendor = strtoul(vendor, NULL, 0);
+ if(product)
+ myeeprom->product = strtoul(product, NULL, 0);
+ if(release) {
+ int release_major = 0;
+ int release_minor = 0;
+
+ sscanf(release, "%d.%d", &release_major, &release_minor);
+ myeeprom->release_major = release_major;
+ myeeprom->release_minor = release_minor;
+ }
+ if(label) {
+ /* padding */
+ memset(myeeprom->label, 0, LABEL_SIZE);
+ memcpy(myeeprom->label, label, strlen(label));
+ }
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ const struct astribank_type *abtype;
+ struct my_usb_device mydev;
+ const char *devpath = NULL;
+ const char *binfile = NULL;
+ const char *inhexfile = NULL;
+ const char *outhexfile = NULL;
+ struct hexdata *hexdata = NULL;
+ int opt_reset = 0;
+ int opt_info = 0;
+ int opt_read_eeprom = 0;
+ int opt_output_width = 0;
+ int output_is_set = 0;
+#ifdef XORCOM_INTERNAL
+ int opt_write_eeprom = 0;
+ char *vendor = NULL;
+ char *source = NULL;
+ char *product = NULL;
+ char *release = NULL;
+ char *label = NULL;
+ const char options[] = "rib:D:ghH:I:vw:C:V:P:R:S:";
+#else
+ const char options[] = "rib:D:ghH:I:vw:";
+#endif
+ int ret = 0;
+
+ progname = argv[0];
+ assert(sizeof(struct fpga_packet_header) <= PACKET_SIZE);
+ assert(sizeof(struct myeeprom) == EEPROM_SIZE);
+ while (1) {
+ int c;
+
+ c = getopt (argc, argv, options);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'D':
+ devpath = optarg;
+ if(output_is_set++) {
+ ERR("Cannot set -D. Another output option is already selected\n");
+ return 1;
+ }
+ break;
+ case 'r':
+ opt_reset = 1;
+ break;
+ case 'i':
+ opt_info = 1;
+ break;
+ case 'b':
+ binfile = optarg;
+ if(output_is_set++) {
+ ERR("Cannot set -b. Another output option is already selected\n");
+ return 1;
+ }
+ break;
+ case 'g':
+ opt_read_eeprom = 1;
+ break;
+ case 'H':
+ outhexfile = optarg;
+ if(output_is_set++) {
+ ERR("Cannot set -H. Another output option is already selected\n");
+ return 1;
+ }
+ break;
+ case 'I':
+ inhexfile = optarg;
+ break;
+#ifdef XORCOM_INTERNAL
+ case 'V':
+ vendor = optarg;
+ break;
+ case 'C':
+ source = optarg;
+ break;
+ case 'P':
+ product = optarg;
+ break;
+ case 'R':
+ release = optarg;
+ break;
+ case 'S':
+ label = optarg;
+ {
+ const char GOOD_CHARS[] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789"
+ "-_.";
+ int len = strlen(label);
+ int goodlen = strspn(label, GOOD_CHARS);
+
+ if(len > LABEL_SIZE) {
+ ERR("Label too long (%d > %d)\n", len, LABEL_SIZE);
+ usage();
+ }
+ if(goodlen != len) {
+ ERR("Bad character in label number (pos=%d)\n", goodlen);
+ usage();
+ }
+ }
+ break;
+#endif
+ case 'w':
+ opt_output_width = strtoul(optarg, NULL, 0);
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'h':
+ default:
+ ERR("Unknown option '%c'\n", c);
+ usage();
+ }
+ }
+
+ if (optind != argc) {
+ usage();
+ }
+ if(inhexfile) {
+#ifdef XORCOM_INTERNAL
+ if(vendor || product || release || label || source ) {
+ ERR("The -I option is exclusive of -[VPRSC]\n");
+ return 1;
+ }
+#endif
+ parse_hexfile_set_reporting(parse_report_func);
+ hexdata = parse_hexfile(inhexfile, MAX_HEX_LINES);
+ if(!hexdata) {
+ ERR("Bailing out\n");
+ exit(1);
+ }
+ if(opt_info) {
+ printf("%s: Version=%s Checksum=%d\n",
+ inhexfile, hexdata->version_info,
+ bsd_checksum(hexdata));
+ }
+ if(binfile) {
+ dump_binary(hexdata, binfile);
+ return 0;
+ }
+ if(outhexfile) {
+ if(opt_output_width)
+ dump_hexfile2(hexdata, outhexfile, opt_output_width);
+ else
+ dump_hexfile(hexdata, outhexfile);
+ return 0;
+ }
+ }
+#ifdef XORCOM_INTERNAL
+ else if(vendor || product || release || label || source ) {
+ if(outhexfile) {
+ FILE *fp;
+
+ if(strcmp(outhexfile, "-") == 0)
+ fp = stdout;
+ else if((fp = fopen(outhexfile, "w")) == NULL) {
+ perror(outhexfile);
+ return 1;
+ }
+ memset(&mydev.eeprom, 0, sizeof(struct myeeprom));
+ eeprom_fill(&mydev.eeprom, vendor, product, release, label, source);
+ gen_hexline((uint8_t *)&mydev.eeprom, 0, sizeof(mydev.eeprom), fp);
+ gen_hexline(NULL, 0, 0, fp); /* EOF */
+ return 0;
+ }
+ }
+#endif
+ if(!devpath) {
+ ERR("Missing device path\n");
+ usage();
+ }
+ DBG("Startup %s\n", devpath);
+ if((abtype = my_usb_device_identify(devpath, &mydev)) == NULL) {
+ ERR("Bad device. Does not match our types.\n");
+ usage();
+ }
+ INFO("FIRMWARE: %s (type=%d)\n", abtype->name, abtype->type_code);
+ if(!my_usb_device_init(devpath, &mydev, abtype)) {
+ ERR("Failed to initialize USB device '%s'\n", devpath);
+ ret = -ENODEV;
+ goto dev_err;
+ }
+ ret = eeprom_get(&mydev);
+ if(ret < 0) {
+ ERR("Failed reading eeprom\n");
+ goto dev_err;
+ }
+#ifdef XORCOM_INTERNAL
+ if(vendor || product || release || label || source ) {
+ eeprom_fill(&mydev.eeprom, vendor, product, release, label, source);
+ opt_write_eeprom = 1;
+ opt_read_eeprom = 1;
+ }
+#endif
+ if(opt_read_eeprom) {
+ show_device_info(&mydev);
+ }
+ if(hexdata) {
+ if (!mydev.is_usb2)
+ INFO("Warning: working on a low end USB1 backend\n");
+ if(!fpga_load(&mydev, hexdata)) {
+ ERR("FPGA loading failed\n");
+ ret = -ENODEV;
+ goto dev_err;
+ }
+ ret = renumerate_device(&mydev, PT_RENUMERATE);
+ if(ret < 0) {
+ ERR("Renumeration failed: errno=%d\n", ret);
+ goto dev_err;
+ }
+ }
+#ifdef XORCOM_INTERNAL
+ else if(opt_write_eeprom) {
+ if(abtype->type_code == USB_FIRMWARE_II) {
+ ERR("No EEPROM burning command in %s. Use fxload for that\n",
+ abtype->name);
+ goto dev_err;
+ }
+ ret = eeprom_set(&mydev, &mydev.eeprom);
+ if(ret < 0) {
+ ERR("Failed writing eeprom: %s\n", strerror(-ret));
+ goto dev_err;
+ }
+ printf("------- RESULTS -------\n");
+ show_device_info(&mydev);
+ }
+#endif
+ if(opt_reset) {
+ DBG("Reseting to default\n");
+ ret = renumerate_device(&mydev, PT_RESET);
+ if(ret < 0) {
+ ERR("Renumeration to default failed: errno=%d\n", ret);
+ goto dev_err;
+ }
+ }
+ DBG("Exiting\n");
+dev_err:
+ my_usb_device_cleanup(&mydev);
+ return ret;
+}
diff --git a/drivers/dahdi/xpp/utils/genzaptelconf b/drivers/dahdi/xpp/utils/genzaptelconf
new file mode 100755
index 0000000..163f595
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/genzaptelconf
@@ -0,0 +1,1198 @@
+#! /bin/bash
+
+# genzaptelconf: generate as smartly as you can:
+# /etc/zaptel.conf
+# /etc/asterisk/zapata-channels.conf (to be #include-d into zapata.conf)
+# update:
+# With '-M' /etc/modules (list of modules to load)
+#
+# Copyright (C) 2005 by Xorcom <support@xorcom.com>
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# If you have any technical questions, contact
+# Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+#
+
+# The script uses a number of bash-specific features
+# TODO: either ditch them or convert to perl
+# Don't override variables here.
+# Override them in /etc/default/zaptel (debian) or /etc/sysconfig/zaptel
+# (redhat/centos)
+
+# /etc/default/zaptel may override the following variables
+VERSION=0.5.10
+rcsid='$Id$'
+lc_country=us
+# set to: ls, ks or gs for (Loopstart, Kewlstart and GroundStart)
+# on FXS channels (FXO signalling).
+fxs_default_start=ks
+base_exten=6000
+# If set: no context changes are made in zapata-channels.conf
+#context_manual=yes
+context_lines=from-pstn # context into which PSTN calls go
+context_phones=from-internal # context for internal phones calls.
+# The two below apply to input and output ports of the Xorcom Astribank:
+context_input=astbank-input
+context_output=astbank-output # useless, but helps marking the channels :-)
+# TODO: what about PRI/BRI?
+# If set: no group changes are made in zapata-channels.conf
+#group_manual=yes
+group_phones=5 # group for phones
+group_lines=0 # group for lines
+# Set fxs_immediate to 'yes' to make all FXS lines answer immediately.
+fxs_immediate=no
+
+ZAPCONF_FILE=${ZAPCONF_FILE:-/etc/zaptel.conf}
+ZAPCONF_FILE_SYSTEM=$ZAPCONF_FILE
+ZAPATA_FILE=${ZAPATA_FILE:-/etc/asterisk/zapata-channels.conf}
+ZAPSCAN_FILE=${ZAPSCAN_FILE:-/etc/asterisk/zapscan.conf}
+ZAPTEL_BOOT_DEBIAN=${ZAPTEL_BOOT_DEBIAN:-/etc/default/zaptel}
+ZAPTEL_BOOT_FEDORA=${ZAPTEL_BOOT_FEDORA:-/etc/sysconfig/zaptel}
+MODLIST_FILE=/etc/modules
+MODLIST_FILE_FEDORA=/etc/sysconfig/zaptel
+exten_base_dir=/etc/asterisk/extensions-phones.d
+exten_defs_file=/etc/asterisk/extensions-defs.conf
+# perl utilities:
+xpp_sync=/usr/sbin/xpp_sync
+zt_registration=/usr/sbin/zt_registration
+# how long to wait for /dev/zap/ctl to appear? (seconds)
+DEVZAP_TIMEOUT=${DEVZAP_TIMEOUT:-20}
+ZTCFG=${ZTCFG:-/sbin/ztcfg}
+# BRI/PRI spans will be in an additional per-span group whose number
+# is SPAN_GROUP_BASE + span-number
+SPAN_GROUP_BASE=10
+# set to "yes" to make BRI NT spans set overlapdial (handy for ISDN phones
+# and other devices).
+brint_overlap=no
+
+# a temporary directory to store whatever we need to remember.
+#
+# The main loop of genconf is run in a sub-process.
+tmp_dir=
+
+# A list of all modules:
+# - the list of modules which will be probed (in this order) if -d is used
+# - The module that will be deleted from /etc/modules , if -d -M is used
+ALL_MODULES="wct4xxp wcte12xp wcte11xp wct1xxp wanpipe tor2 torisa qozap vzaphfc zaphfc ztgsm wctdm24xxp wctdm opvxa1200 wcfxo pciradio wcusb xpp_usb"
+
+# The name of the variable in /etc/sysconfig/zaptel into which to set
+# the list of detected modules.
+modules_var=MODULES
+# On SuSE with the rpm package:
+#modules_var=ZAPTEL_MODULES
+
+# What signalling to give to ZapBRI channels?
+# bri: bri_net; bri_cpe (Bristuffed Asterisk. No multi- support)
+# bri_ptmpi: bri_net_ptmp; bri_cpe_ptmp (Bristuffed Asterisk, multi- support)
+# pri: pri_net; pri_cpe (Recent Asterisk. Experimental)
+#ZAPBRI_SIGNALLING=bri
+ZAPBRI_SIGNALLING=bri_ptmp
+#ZAPBRI_SIGNALLING=pri
+zapconf_def_termtype=te
+
+# A command to stop / start asterisk. Must support parameters "start"
+# and "stop" . This is the executable:
+ZAPCONF_ASTERISK_SCRIPT=/etc/init.d/asterisk
+#
+# Should you need to pass extra arguments:
+ZAPCONF_ASTERISK_CMD=$ZAPCONF_ASTERISK_SCRIPT
+
+# read default configuration from /etc/default/zaptel
+if [ -r $ZAPTEL_BOOT_DEBIAN ]; then . $ZAPTEL_BOOT_DEBIAN; fi
+if [ -r $ZAPTEL_BOOT_FEDORA ]; then . $ZAPTEL_BOOT_FEDORA; fi
+
+if [ ! -x "$ZTCFG" ]; then
+ # Work around a bug in the rpm package: ztcfg should be in
+ # /sbin as it may be required for starting a network interface
+ if [ -x /usr/sbin/ztcfg ]; then
+ ZTCFG=/usr/sbin/ztcfg
+ else
+ echo >&2 "ztcfg is not on found, do you have zaptel properly installed?"
+ exit_cleanup 1
+ fi
+fi
+
+XPP_SYNC=auto # sync mode. can be set to '0' or '1' or HOST explicitly.
+
+# it is safe to use -c twice: the last one will be used.
+ztcfg_cmd="$ZTCFG -c $ZAPCONF_FILE"
+
+# work around a bug (that was already fixed) in the installer:
+if [ "$lc_country" = '' ]; then lc_country=us; fi
+
+force_stop_ast=no
+do_detect=no
+do_unload=no
+do_module_list=no
+verbose=no
+do_restart=yes
+fxsdisable=no
+do_gen_zapscan=no
+
+span_te_timing_counter=1
+
+case "$ZAPBRI_SIGNALLING" in
+bri) ZAPBRI_NET=bri_net; ZAPBRI_CPE=bri_cpe ;;
+pri) ZAPBRI_NET=pri_net; ZAPBRI_CPE=pri_cpe ;;
+bri_ptmp) ZAPBRI_NET=bri_net_ptmp; ZAPBRI_CPE=bri_cpe_ptmp ;;
+*)
+ die "Incorrect value for ZAPBRI_SIGNALLING ($ZAPBRI_SIGNALLING). Abortring"
+ ;;
+esac
+
+die() {
+ echo "$@" >&2
+ exit_cleanup 1
+}
+
+say() {
+ if [ "$verbose" = no ]; then
+ return
+ fi
+ echo "$@" >&2
+}
+
+# exit (exit value is the optional $1), and clean up after us
+exit_cleanup() {
+ if [ -d "$tmp_dir" ]; then
+ # don't fail but don't hide error if directory is not
+ # empty
+ rmdir "$tmp_dir" || :
+ fi
+ exit $1
+}
+
+# Wait for udev to generate /dev/zap/ctl, if needed:
+wait_for_zapctl() {
+ # if device file already exists, or if zaptel has failed to load:
+ # no point waiting.
+ if [ -c /dev/zap/ctl ] || ! grep -q zaptel /proc/modules ; then
+ return
+ fi
+ say "Waiting for /dev/zap/ctl to be generated"
+ devzap_found=0
+ for i in `seq $DEVZAP_TIMEOUT`; do
+ sleep 1
+ if [ -c /dev/zap/ctl ]; then
+ devzap_found=1
+ break
+ fi
+ done
+ if [ "$devzap_found" != 1 ]; then
+ say "Still no /dev/zap/ctl after $devzap_timeout seconds."
+ echo >&2 "No /dev/zap/ctl: cannot run ztcfg. Aborting."
+ fi
+}
+
+run_ztcfg() {
+ # Run ztcfg itself
+ if [ "$verbose" = no ]; then
+ $ztcfg_cmd "$@"
+ else
+ say "Reconfiguring identified channels"
+ $ztcfg_cmd -vv "$@"
+ fi
+}
+
+update_module_list_debian() {
+ say "Updating Debian modules list $MODLIST_FILE."
+ del_args=`for i in $ALL_MODULES ztdummy
+ do
+ echo "$i" | sed s:.\*:-e\ '/^&/d':
+ done`
+ add_args=`for i in $*
+ do
+ echo "$i" | sed s:.\*:-e\ '\$a&':
+ done`
+
+ sed -i.bak $del_args "$MODLIST_FILE"
+ for i in $*
+ do
+ echo "$i"
+ done >> "$MODLIST_FILE"
+}
+
+update_module_list_fedora() {
+ say "Updating modules list in zaptel init config $MODLIST_FILE_FEDORA."
+ sed -i.bak -e "/^$modules_var=/d" "$MODLIST_FILE_FEDORA"
+ echo "$modules_var=\"$*\"" >> "$MODLIST_FILE_FEDORA"
+}
+
+update_module_list() {
+ if [ -f "$MODLIST_FILE" ]; then
+ update_module_list_debian "$@"
+ elif [ -f "$MODLIST_FILE_FEDORA" ]; then
+ update_module_list_fedora "$@"
+ else
+ die "Can't find a modules list to update. Tried: $MODLIST_FILE, $MODLIST_FILE_FEDORA. Aborting"
+ fi
+}
+
+
+
+zap_reg_xpp() {
+ if [ ! -d /proc/xpp ]; then return; fi
+
+ # Get a list of connected Astribank devices, sorted by the name of
+ # the USB connector. That order is rather arbitrary, but will not
+ # change without changes to the cabling.
+ xbusses=`sed -e '/STATUS=connected/!d' -e 's/ *STATUS=.*//' -e 's/ *CONNECTOR=//' /proc/xpp/xbuses | sort -t: -k 2 | cut -d: -f1`
+ say "Zaptel registration order:"
+ say "$xbusses"
+
+ # get a list of XPDs that were not yet registered as zaptel spans.
+ # this will be the case if you set the parameter zap_autoreg=0 to
+ # the module xpp
+ # Append /dev/null to provide a valid file name in case of an empty pattern.
+ xbusses_pattern=`echo $xbusses| sed -e 's|XBUS-[0-9]*|/proc/xpp/&/XPD-*/zt_registration|g'`' /dev/null'
+ xpds_to_register=`grep -l 0 $xbusses_pattern`
+ for file in $xpds_to_register; do
+ echo 1 >$file
+ done
+}
+
+# Initialize the Xorcom Astribank (xpp/)
+xpp_startup() {
+ # do nothing if the module xpp was not loaded, or if no
+ # Astribanks connected:
+ if [ ! -d /proc/xpp ]; then return 0; fi
+ if ! grep -q 'STATUS=connected' /proc/xpp/xbuses; then return 0; fi
+
+ echo "Waiting for Astribank devices to initialize:"
+ cat /proc/xpp/XBUS-[0-9]*/waitfor_xpds 2>/dev/null || true
+
+ # overriding locales for the above two, as perl can be noisy
+ # when locales are missing.
+ # No register all the devices if they didn't auto-register:
+ LC_ALL=C $zt_registration on
+
+ # this one could actually be run after ztcfg:
+ LC_ALL=C $xpp_sync "$XPP_SYNC"
+}
+
+
+
+usage() {
+ program=`basename $0`
+
+ echo >&2 "$program: generate zaptel.conf and zapata.conf"
+ echo >&2 "(version $VERSION, $rcsid)"
+ echo >&2 "usage:"
+ echo >&2 " $program [-sRdv] [-m k|l|g] [-c <country_code>] [-e <base_exten>] [-F]"
+ echo >&2 " $program [-sRdv] -l"
+ echo >&2 " $program -su"
+ echo >&2 " $program -h (this screen)"
+ echo >&2 ""
+ echo >&2 "Options:"
+ echo >&2 " -c CODE: set the country code (default: $lc_country)"
+ echo >&2 " -e NUM: set the base extension number (default: $base_exten)"
+ echo >&2 " -F: Don't print FXSs in zapata.conf"
+ echo >&2 " -l: output a list of detected channels instead of zaptel.conf"
+ echo >&2 " -d: Perform hardware detection"
+ echo >&2 " -u: Unload zaptel modules (will not restart Asterisk)."
+ echo >&2 " -v: verbose"
+ echo >&2 " -s: Stop Asterisk before running, and start it at the end."
+ echo >&2 " -R: Don't restart asterisk in the end."
+ echo >&2 " -z: also generate zapscan.conf for the asterisk GUI."
+}
+
+# print /etc/asterisk/zapscan.conf for the Asterisk-GUI
+# $1: port type. Currently only fxs/fxo . Note that this is the type, and
+# not the signalling (which would be the fxo fir an fxs port.
+# $2: port number. Probably a range of ports is also allowed.
+print_zapscan_port () {
+ if [ "$do_gen_zapscan" != 'yes' ]; then return 0; fi
+
+ echo "
+[$2]
+port=$1
+" >>$zapscan_file
+}
+
+# $1: channel number
+print_pattern() {
+ local astbank_type=''
+ local reset_values=""
+ OPTIND=1
+ while getopts 'a:' arg
+ do
+ case "$arg" in
+ a) case "$OPTARG" in input|output) astbank_type=$OPTARG;;esac ;;
+ esac
+ done
+ shift $(( $OPTIND-1 ))
+
+
+ local chan=$1
+ local sig=$2 #fxs/fxo
+ local mode=$3
+ local method
+
+ if [ "$sig" = 'fxs' ]; then
+ # Coutries in which we need to use busydetect:
+ # United Arab Emirats, Israel, Slovenia
+ case "$lc_country" in
+ ae|il|si)
+ method=ls
+ ;;
+ *)
+ method=ks
+ ;;
+ esac
+ else
+ method="$fxs_default_start"
+ fi
+ case "$sig" in
+ fxs) sig_name=FXO;;
+ fxo) sig_name=FXS;;
+ esac
+ case "$mode" in
+ list)
+ echo $chan $sig_name $astbank_type;;
+ files)
+ # sadly, both input ports and output ports go into the same span as
+ # the FXS ports. Thus we need to separate between them. See also
+ # the zapata.conf section:
+
+ echo ";;; line=\"$line\"" >> $zapata_file
+
+ if [ "$astbank_type" != '' ];
+ then echo "# astbanktype: $astbank_type" >>$zaptel_file;
+ fi
+ echo "${sig}$method=$chan" >>$zaptel_file
+ # zap2amp will rewrite those from zaptel.conf and hints there
+ if [ "$fxsdisable" = 'yes' ] && [ "$sig" = 'fxo' ]; then return; fi
+
+ echo "signalling=${sig}_$method" >>$zapata_file
+ if [ "$sig" = 'fxo' ]
+ then
+ # to preconfigure channel 1's extension to 550, set
+ # chan_1_exten=550
+ # in, e.g, /etc/default/zaptel
+ var_name=`echo chan_${chan}_exten`
+ cfg_exten=`echo ${!var_name} | tr -d -c 0-9`
+ var_name=`echo chan_${chan}_vmbox`
+ cfg_vmbox=`echo ${!var_name} | tr -d -c 0-9`
+ var_name=`echo chan_${chan}_cntxt`
+ cfg_cntxt=`echo ${!var_name} | tr -d -c 0-9`
+
+ if [ "$cfg_exten" = '' ]
+ then # No extension number set for this channel
+ exten=$(($chan+$base_exten))
+ else # use the pre-configured extension number
+ exten=$cfg_exten
+ fi
+ # is there any real need to set 'mailbox=' ?
+ if [ "x$cfg_vmbox" = x ]
+ then # No extension number set for this channel
+ vmbox=$exten
+ else # use the pre-configured extension number
+ vmbox=$cfg_vmbox
+ fi
+ echo "callerid=\"Channel $chan\" <$exten>" >> $zapata_file
+ reset_values="$reset_values callerid"
+ echo "mailbox=$exten" >> $zapata_file
+ reset_values="$reset_values mailbox"
+ if [ "$group_manual" != "yes" ]
+ then
+ echo "group=$group_phones" >> $zapata_file
+ reset_values="$reset_values group"
+ fi
+ if [ "$context_manual" != "yes" ]
+ then
+ if [ "$astbank_type" != '' ];
+ then
+ context_var_name=context_$astbank_type
+ echo context=${!context_var_name} >> $zapata_file
+ else
+ echo "context=$context_phones" >> $zapata_file
+ fi
+ reset_values="$reset_values context"
+ fi
+ else # this is an FXO (trunk/phone: FXO signalling)
+ # we have may have set it. So reset it:
+ echo "callerid=asreceived" >> $zapata_file
+ if [ "$group_manual" != "yes" ]
+ then
+ echo "group=$group_lines" >> $zapata_file
+ fi
+ if [ "$context_manual" != "yes" ]
+ then
+ echo "context=$context_lines" >> $zapata_file
+ reset_values="$reset_values context"
+ fi
+ if [ "$lc_country" = 'uk' ]
+ then
+ echo "cidsignalling=v23" >> $zapata_file
+ case $line in
+ *WCFXO*) echo "cidstart=history" >> $zapata_file;;
+ *) echo "cidstart=polarity" >> $zapata_file;;
+ esac
+ reset_values="$reset_values cidsignalling cidstart"
+ fi
+ case "$line" in
+ *XPP_FXO*)
+ if [ "$xpp_fxo_rxgain" != '' ]; then
+ echo "rxgain=$xpp_fxo_rxgain" >> $zapata_file
+ reset_values="$reset_values rxgain"
+ fi
+ ;;
+ esac
+ # if kewlstart is not used, busydetect has to be employed:
+ if [ "$method" = 'ls' ]
+ then
+ echo 'busydetect=yes' >> $zapata_file
+ reset_values="$reset_values busydetect"
+ fi
+ fi
+
+ if [ "$astbank_type" = 'input' ] || \
+ ( [ "$fxs_immediate" = 'yes' ] && [ "$sig" = "fxo" ] )
+ then
+ echo 'immediate=yes' >> $zapata_file
+ reset_values="$reset_values immediate"
+ fi
+ echo "channel => $chan" >> $zapata_file
+ reset_zapata_entry $zapata_file $reset_values
+ echo "" >> $zapata_file
+
+ print_zapscan_port "$sig" "$chan"
+ ;;
+ esac
+
+}
+
+# the number of channels from /proc/zaptel
+# must always print a number as its output.
+count_proc_zap_lines() {
+ # if zaptel is not loaded there are 0 channels:
+ if [ ! -d /proc/zaptel ]; then echo '0'; return; fi
+
+ (
+ for file in `echo /proc/zaptel/* |grep -v '\*'`
+ do sed -e 1,2d $file # remove the two header lines
+ done
+ ) | wc -l # the total number of lines
+}
+
+load_modules() {
+ say "Test Loading modules:"
+ for i in $ALL_MODULES
+ do
+ lines_before=`count_proc_zap_lines`
+ args="${i}_args"
+ eval "args=\$$args"
+ # a module is worth listing if it:
+ # a. loaded successfully, and
+ # b. added channels lines under /proc/zaptel/*
+ if /sbin/modprobe $i $args 2> /dev/null
+ then
+ check=0
+ case "$i" in
+ xpp_usb) check=`grep 'STATUS=connected' 2>/dev/null /proc/xpp/xbuses | wc -l` ;;
+ *) if [ $lines_before -lt `count_proc_zap_lines` ]; then check=1; fi ;;
+ esac
+ if [ "$check" != 0 ]
+ then
+ probed_modules="$probed_modules $i"
+ say " ok $i $args"
+ else
+ say " - $i $args"
+ rmmod $i
+ fi
+ else
+ say " - $i $args"
+ fi
+ done
+}
+
+# recursively unload a module and its dependencies, if possible.
+# where's modprobe -r when you need it?
+# inputs: module to unload.
+# returns: the result from
+unload_module() {
+ module="$1"
+ line=`lsmod 2>/dev/null | grep "^$1 "`
+ if [ "$line" = '' ]; then return; fi # module was not loaded
+
+ set -- $line
+ # $1: the original module, $2: size, $3: refcount, $4: deps list
+ mods=`echo $4 | tr , ' '`
+ # xpp_usb keeps the xpds below busy, and hence must be removed
+ # before them:
+ case "$module" in xpd_*) mods="xpp_usb $mods";; esac
+ for mod in $mods; do
+ # run in a subshell, so it won't step over our vars:
+ (unload_module $mod)
+ # TODO: the following is probably the error handling we want:
+ # if [ $? != 0 ]; then return 1; fi
+ done
+ rmmod $module
+}
+
+unload_modules() {
+ say "Unloading zaptel modules:"
+ unload_module zaptel
+ say ''
+}
+
+# sleep a while until the xpp modules fully register
+wait_for_xpp() {
+ if [ -d /proc/xpp ]
+ then
+ # wait for the XPDs to register:
+ # TODO: improve error reporting and produce a messagee here
+ cat /proc/xpp/XBUS-*/waitfor_xpds 2>/dev/null >/dev/null || true
+ fi
+}
+
+detect() {
+ unload_modules
+ temporary_zapconf save
+ load_modules
+ temporary_zapconf restore
+ modlist="$probed_modules"
+ modlist="$(echo $modlist)" # clean spaces
+ if [ "$do_module_list" = yes ]
+ then
+ update_module_list "$modlist"
+ fi
+ if echo $modlist | grep -q xpp_usb; then wait_for_xpp; fi
+}
+
+# The module configuration generated by zaptel includes a totally useless
+# automatic run of ztcfg after modules loading. As a workaround for that,
+# we provide an empty zaptel.conf temporarily.
+#
+# At hardware detection time we shouldn't really touch zaptel.conf . So we
+# must keep a copy of it somewhere.
+#
+# I use ZAPCONF_FILE_SYSTEM rather than ZAPCONF_FILE, as the bogus modprobe
+# entries will not be initiated by us.
+#
+# ZAPCONF_FILE_TMP is a "global", as it needs to be preserved between the
+# call to 'save' and to 'restore'
+ZAPCONF_FILE_TMP=
+temporary_zapconf() {
+ case "$1" in
+ save)
+ say "Temporarily moving zaptel.conf aside to work around broken modprobe.conf"
+ ZAPCONF_FILE_TMP=`mktemp /tmp/genzaptelconf-zaptel.conf-XXXXXX` || die "Error creating temporary zaptel.conf"
+ if [ -f $ZAPCONF_FILE_SYSTEM ]; then
+ cp -a $ZAPCONF_FILE_SYSTEM $ZAPCONF_FILE_TMP
+ fi
+ echo -n >$ZAPCONF_FILE_SYSTEM
+ ;;
+ restore)
+ # restore original zaptel.conf:
+ if [ "$ZAPCONF_FILE_TMP" = '' ]; then return; fi
+ mv $ZAPCONF_FILE_TMP $ZAPCONF_FILE_SYSTEM
+ ZAPCONF_FILE_TMP=''
+ ;;
+ esac
+}
+
+# run after the channel's entry. Used to reset all the values
+reset_zapata_entry() {
+ conf_file="$1"; shift
+
+ for arg in "$@"; do
+ case "$arg" in
+ busydetect) echo "$arg=no" >>$conf_file;;
+ context) echo "$arg=default" >>$conf_file;;
+ immediate) echo "$arg=no" >>$conf_file;;
+ overlapdial) echo "$arg=no" >>$conf_file;;
+ rxgain) echo "$arg=0" >>$conf_file;;
+ txgain) echo "$arg=0" >>$conf_file;;
+ *) echo "$arg=" >>$conf_file;;
+ esac
+ done
+}
+
+
+# we need to preserve the permissions of existing configurations files.
+# However we also don't want to be left with incomplete configurations in
+# case we are stopped in the middle. Thus we create a temporary file and
+# mv it to the original file only when done.
+#
+# This function gives the temporary file the permissions of the original,
+# or some sane defaults.
+#
+# The temporary file is generated here, and ths its name is passed through
+# a variable whose name is passed as a parameter (new_var).
+#
+# $1: orig_cfg_file
+# $2: new_var
+gen_tmp_conf() {
+ orig_cfg_file=$1
+ new_var=$2
+
+ # assign to new_var by reference:
+ eval $new_var=`mktemp /tmp/genzaptelconf-conf-XXXXXX` \
+ || die "Unable to create temporary config file for $orig_cfg_file"
+ if [ -r "$orig_cfg_file" ]; then
+ chown --reference="$orig_cfg_file" ${!new_var} 2>/dev/null
+ chmod --reference="$orig_cfg_file" ${!new_var} 2>/dev/null
+ else
+ chmod 644 ${!new_var}
+ fi
+}
+
+# Extract information from one digital channel (one line in a /proc/zaptel
+# file). Information is saved to $tmp_dir/span_foo variables.
+# FIXME: detection should move to when we know the number of channels
+# and hence can tell between an E1 and a T1.
+detect_digital_channel() {
+ line="$1"
+ chan_num="$2"
+ span_num="$3"
+
+ # PRI/BRI channel
+ # Rather than identifying cards by the header line, we identify
+ # them by the channel names. This is shorter.
+ # This also allows us to count the channel numbers and check if
+ # we have a E1 span, a T1 span or a BRI span.
+
+ # span_lastd is always the one before last
+ # channel. span_bchan is the last:
+ echo $chan_num >$tmp_dir/span_end
+
+ if [ "`cat $tmp_dir/span_begin`" != "-1" ]
+ then
+ return #we already configured this span.
+ fi
+
+ # Now we need to give initial configuration to the span
+ echo $chan_num >$tmp_dir/span_begin
+ echo $span_num >$tmp_dir/span_num
+
+ case "$line" in
+ *ZTHFC*/* | *ztqoz*/* | *XPP_BRI_*/*)
+ # BRI channel
+ echo 'ccs' >$tmp_dir/span_framing
+ echo 'euroisdn' >$tmp_dir/span_switchtype
+ if [ "`cat $tmp_dir/span_termtype`" = 'nt' 2>/dev/null ]
+ then
+ echo $ZAPBRI_NET >$tmp_dir/span_signalling
+ else
+ echo $ZAPBRI_CPE >$tmp_dir/span_signalling
+ fi
+ ;;
+ *ztgsm*/*)
+ # Junghanns's GSM cards.
+ echo 'ccs' >$tmp_dir/span_framing
+ #Does this mean anything?
+ echo 'gsm' >$tmp_dir/span_signalling
+ ;;
+ *TE[24]/* | *WCT1/* | *Tor2/* | *TorISA/* | *WP[TE]1/* | \
+ *R[124]T1/* | *XPP_[TEJ]1_*)
+ # FIXME: handle cwain around here.
+ # name: *cwain[12]/* . Always E1.
+
+ # PRI span (E1/T1)
+ echo 'esf' >$tmp_dir/span_framing
+ echo 'b8zs' >$tmp_dir/span_coding
+ echo 'national' >$tmp_dir/span_switchtype
+ if [ "`cat $tmp_dir/span_termtype`" = 'nt' 2>/dev/null ]
+ then
+ echo pri_net >$tmp_dir/span_signalling
+ else
+ echo pri_cpe >$tmp_dir/span_signalling
+ fi
+ # an example of country-specific setup. This is probably not accurate
+ # Contributions are welcome
+ case "$lc_country" in
+ nl)
+ # (Just an example for per-country info)
+ echo 'ccs' >$tmp_dir/span_framing
+ echo 'ami' >$tmp_dir/span_coding
+ #echo 'crc4' >$tmp_dir/span_yellow
+ #echo 'euroisdn' >$tmp_dir/span_switchtype
+ #echo 'pri_cpe' >$tmp_dir/span_signalling
+ ;;
+ il|de|au)
+ echo 'ccs' >$tmp_dir/span_framing
+ echo 'hdb3' >$tmp_dir/span_coding
+ echo 'crc4' >$tmp_dir/span_yellow
+ echo 'euroisdn' >$tmp_dir/span_switchtype
+ ;;
+ cl)
+ echo 'ccs' >$tmp_dir/span_framing
+ echo 'hdb3' >$tmp_dir/span_coding
+ #echo 'crc4' >$tmp_dir/span_yellow
+ echo 'national' >$tmp_dir/span_switchtype
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# read information from the $tmp_dir/span_foo files and generate
+# configuration for the span and its channels.
+write_digital_config() {
+ # if the current file we checked was not of a digital span, we have
+ # nothing to do:
+ if [ "`cat $tmp_dir/span_begin`" = -1 ]; then return; fi
+
+ # read files to variables:
+ for suffix in num begin end timing lbo framing \
+ coding switchtype signalling yellow termtype
+ do
+ eval span_$suffix=`cat $tmp_dir/span_$suffix 2>/dev/null`
+ done
+
+ # exactly the same logic is used in asterisk's chan_zap.c.
+ # also not that $(( )) is bash-specific
+ case "$((1+ $span_end - $span_begin))" in
+ 2|3|24) #ztgsm, BRI or T1
+ dchan=$span_end
+ bchans="$span_begin-$(($span_end-1))"
+ ;;
+ 31) #E1
+ dchan="$(($span_begin+15))"
+ bchans="$span_begin-$(($span_begin+14)),$(($span_begin+16))-$span_end"
+ if [ "$span_framing" = 'esf' ]; then
+ # don't leave an E1 span with defective defaults:
+ span_framing=ccs
+ span_coding=hdb3
+ span_switchtype=euroisdn
+ span_yellow=crc4
+ fi
+ ;;
+ esac
+ if [ "$span_yellow" != '' ]; then span_yellow=",$span_yellow"; fi
+ # Let's assume that a TE span should get the clock from the remote unit,
+ # and NT spans should provide timing. Just as a sane default.
+ # If we have several TE spans, the first will have priority 1,
+ # second: 2, etc.
+ case "$span_signalling" in *_cpe*)
+ span_timing=$span_te_timing_counter
+ span_te_timing_counter=$(($span_te_timing_counter + 1))
+ ;;
+ esac
+ case "$mode" in
+ files)
+ echo span=$span_num,$span_timing,$span_lbo,$span_framing,$span_coding$span_yellow >> $zaptel_file
+ # leave a comment in zaptel.conf that allows to tell if
+ # this span is TE or NT:
+ if [ "$span_termtype" != '' ]
+ then echo "# termtype: $span_termtype" >>$zaptel_file
+ fi
+
+ echo bchan=$bchans >>$zaptel_file
+ echo dchan=$dchan >>$zaptel_file
+ if [ "$fxsdisable" = 'yes' ] && [ "$span_termtype" = 'nt' ]; then return; fi
+ # You should not send content to zapata.conf below this line
+
+ span_group=$(($SPAN_GROUP_BASE + $span_num))
+
+ if [ "$span_termtype" != '' ]
+ then
+ # an ISDN card's span that we know if it is in NT mode or TE mode.
+ # NT is the same as FXS for us and TE is the same as FXO
+ if [ "$span_termtype" = 'nt' ]
+ then
+ echo "callerid=\"Channels $span_begin - $span_end\" <$span_begin>" >> $zapata_file
+ reset_values="$reset_values callerid"
+ #echo "mailbox=$exten"
+ if [ "$brint_overlap" = 'yes' ]
+ then
+ echo "overlapdial=yes" >> $zapata_file
+ reset_values="$reset_values overlapdial"
+ fi
+ if [ "$group_manual" != "yes" ]
+ then
+ echo "group=$group_phones,$span_group" >> $zapata_file
+ reset_values="$reset_values group"
+ fi
+ if [ "$context_manual" != "yes" ]
+ then
+ echo "context=$context_phones" >> $zapata_file
+ fi
+ else
+ #echo "mailbox="
+ if [ "$group_manual" != "yes" ]
+ then
+ echo "group=$group_lines,$span_group" >> $zapata_file
+ reset_values="$reset_values group"
+ fi
+ if [ "$context_manual" != "yes" ]
+ then
+ echo "context=$context_lines" >> $zapata_file
+ reset_values="$reset_values context"
+ fi
+ fi
+ fi
+ echo "switchtype = $span_switchtype" >> $zapata_file
+ echo "signalling = $span_signalling" >> $zapata_file
+ echo "channel => $bchans" >> $zapata_file
+ reset_zapata_entry $zapata_file $reset_values
+ reset_values=
+ ;;
+ list)
+ echo "### BRI/PRI: $span_termtype"
+ echo "$bchans Data"
+ echo "$dchan Control"
+ #echo BRI/PRI: chans: $bchans, control: $dchan
+ ;;
+ esac
+}
+
+# This is where the actual detection configuration detection work happens.
+genconf() {
+ local mode=$1
+ local reset_values=""
+
+# spanlist=`echo /proc/zaptel/* | grep -v '\*'`
+# spanlist=$(for i in `for i in /proc/zaptel/*; do if [ -f $i ]; then echo $i | cut -f 4 -d / ; fi; done | sort -n`; do echo -n "/proc/zaptel/$i "; done)
+# spanlist=(cd /proc/zaptel; ls | sort -n | sed 's|^|/proc/zaptel/|')
+ spanlist=`ls /proc/zaptel/ 2>/dev/null | sort -n | sed 's|^|/proc/zaptel/|'`
+
+ #if [ "$spanlist" == "" ]; then
+ # die "No zapata interfaces in /proc/zaptel"
+ #fi
+
+
+ case "$mode" in
+ files)
+ if [ "$do_gen_zapscan" = 'yes' ]; then
+ gen_tmp_conf "$ZAPSCAN_FILE" zapscan_file
+ cat <<EOF >$zapscan_file
+; zapscan.conf: information about detected zaptel channels
+; (currently: analog only)
+;
+; Automatically generated by $0 -- Please do not edit.
+
+EOF
+ fi
+ gen_tmp_conf "$ZAPTEL_FILE" zaptel_file
+ gen_tmp_conf "$ZAPATA_FILE" zapata_file
+ cat <<EOF >$zaptel_file
+# Autogenerated by $0 -- do not hand edit
+# Zaptel Configuration File
+#
+# This file is parsed by the Zaptel Configurator, ztcfg
+#
+
+# It must be in the module loading order
+
+EOF
+ cat <<EOF >$zapata_file
+; Autogenerated by $0 -- do not hand edit
+; Zaptel Channels Configurations (zapata.conf)
+;
+; This is not intended to be a complete zapata.conf. Rather, it is intended
+; to be #include-d by /etc/zapata.conf that will include the global settings
+;
+EOF
+ ;;
+ esac
+
+ # For each line in the spanlist: see if it represents a channel.
+ # if it does, test that the channel is usable.
+ # we do that by configuring it (using ztcfg with a 1-line config file)
+ # and then trying to read 1 byte from the device file.
+ #
+ # The '<(command)' syntax creates a temporary file whose content is is the
+ # output of 'command'.
+ #
+ # Another problem with such an approach is how to include an existing
+ # configuration file. For instance: how to include some default settings.
+ #
+ # Maybe an 'include' directive should be added to zaptel.conf ?
+ #cat $spanlist |
+ for procfile in $spanlist
+ do
+ span_num=`basename $procfile`
+ # the first line is the title line. It states the model name
+ # the second line is empty
+ title=`head -n 1 $procfile`
+ # stuff that needs to be remembered accross lines (for PRI/BRI support)
+ case "$mode" in
+ list) echo "### $title";;
+ files)
+ echo "" >>$zaptel_file
+ echo "# $title" >>$zaptel_file
+ echo "" >>$zapata_file
+ echo "; $title" >>$zapata_file
+ ;;
+ esac
+ echo '-1' >$tmp_dir/span_begin
+ echo '-1' >$tmp_dir/span_end
+ echo '0' >$tmp_dir/span_timing
+ echo '0' >$tmp_dir/span_lbo
+ echo '' >$tmp_dir/span_framing
+ echo 'ami' >$tmp_dir/span_coding
+ echo '' >$tmp_dir/span_switchtype
+ echo '' >$tmp_dir/span_signalling
+ if [ "$zapconf_def_termtype" != '' ]
+ then
+ echo "$zapconf_def_termtype" >$tmp_dir/span_termtype
+ fi
+
+ # Check if ZapBRI cards are in TE or NT mode
+ if echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[NT\]\ |octoBRI \[NT\] |HFC-S PCI A ISDN.* \[NT\] |Xorcom .* (BRI|T1|E1)_NT)'
+ then
+ echo 'nt' >$tmp_dir/span_termtype
+ elif echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[TE\]\ |octoBRI \[TE\] |HFC-S PCI A ISDN.* \[TE\] |Xorcom .* (BRI|T1|E1)_TE)'
+ then
+ echo 'te' >$tmp_dir/span_termtype
+ fi
+
+ # The rest of the lines are per-channel lines
+ sed -e 1,2d $procfile | \
+ while read line
+ do
+ # in case this is a real channel.
+ chan_num=`echo $line |awk '{print $1}'`
+ case "$line" in
+ *WCTDM/* | *\ WRTDM/* | *OPVXA1200/*)
+ # TDM400P/2400P and similar cards (Sangoma A200, OpenVox A1200)
+ # this can be either FXS or FXO
+ maybe_fxs=0
+ maybe_fxo=0
+ $ztcfg_cmd -c <(echo fxoks=$chan_num) &>/dev/null && maybe_fxs=1
+ $ztcfg_cmd -c <(echo fxsks=$chan_num) &>/dev/null && maybe_fxo=1
+ if [ $maybe_fxs = 1 ] && [ $maybe_fxo = 1 ]
+ then
+ # An installed module won't accept both FXS and FXO signalling types:
+ # this is an empty slot.
+ # TODO: I believe that the Sangoma A20x will reject both and thus
+ # print nothing here.
+ case "$mode" in
+ list) echo "# channel $chan_num, WCTDM, no module.";;
+ files) echo "# channel $chan_num, WCTDM, no module." >> $zaptel_file;;
+ esac
+ continue
+ fi
+
+ if [ $maybe_fxs = 1 ]; then print_pattern $chan_num fxo $mode; fi
+ if [ $maybe_fxo = 1 ]; then print_pattern $chan_num fxs $mode; fi
+ ;;
+ *WCFXO/*)
+ # X100P
+ print_pattern $chan_num fxs $mode || \
+ echo "# channel $chan_num, WCFXO, inactive." >>$zaptel_file
+ ;;
+ *WCUSB/*)
+ print_pattern $chan_num fxo $mode
+ ;;
+ *XPP_FXO/*)
+ # Astribank FXO span
+ print_pattern $chan_num fxs $mode
+ ;;
+ *XPP_FXS/*)
+ # Astribank FXS span (regular port)
+ print_pattern $chan_num fxo $mode
+ ;;
+ *' FXO'/*)
+ # FXO module (probably Rhino)
+ print_pattern $chan_num fxs $mode
+ ;;
+ *' FXS'/*)
+ # FXS module (probably Rhino)
+ print_pattern $chan_num fxo $mode
+ ;;
+ *' ---'/*)
+ # no module (probably Rhino)
+ continue
+ ;;
+ *XPP_OUT/*)
+ # Astribank FXS span (output port)
+ print_pattern -a output $chan_num fxo $mode
+ ;;
+ *XPP_IN/*)
+ # Astribank FXS span (input port)
+ print_pattern -a input $chan_num fxo $mode
+ ;;
+ *ZTHFC*/* | *ztqoz*/* |*ztgsm/* |*TE[24]/* | \
+ *WCT1/*|*Tor2/* | *TorISA/* | \
+ *XPP_BRI_*/* | *WP[TE]1/* | *R[124]T1/* | \
+ *XPP_[TE]1*/* )
+ detect_digital_channel "$line" "$chan_num" "$span_num"
+ ;;
+ '') ;; # Empty line (after span header)
+ *)
+ case "$mode" in
+ list) echo "# ??: $line";;
+ files)
+ echo "# ??: $line" >>$zaptel_file
+ echo "; ??: $line" >>$zapata_file
+ esac
+ ;;
+ esac
+ done
+ # end of part in sub-process.
+
+ write_digital_config
+ done
+
+ if [ "$mode" = 'files' ]
+ then
+ cat <<EOF >> ${zaptel_file}
+
+# Global data
+
+loadzone = $loadzone
+defaultzone = $defaultzone
+EOF
+ fi
+
+ if [ "$mode" = 'files' ]; then
+ mv ${ZAPCONF_FILE} ${ZAPCONF_FILE}.bak 2>/dev/null
+ mv $zaptel_file ${ZAPCONF_FILE}
+ mv ${ZAPATA_FILE} ${ZAPATA_FILE}.bak 2>/dev/nullk
+ mv $zapata_file ${ZAPATA_FILE}
+ if [ "$do_gen_zapscan" = 'yes' ]; then
+ mv $ZAPSCAN_FILE $ZAPSCAN_FILE.bak 2>/dev/null
+ mv $zapscan_file $ZAPSCAN_FILE
+ fi
+
+ zapata_file_name=`basename $ZAPATA_FILE`
+ if ! grep -q "^#include.*$zapata_file_name" \
+ /etc/asterisk/zapata.conf
+ then
+ say "Note: generated $ZAPATA_FILE not included in zapata.conf"
+ say "To fix: echo '#include $zapata_file_name' >>/etc/asterisk/zapata.conf"
+ fi
+ fi
+}
+
+while getopts 'c:de:Fhlm:MRsuvz' arg
+do
+ case "$arg" in
+ e) # guarantee that it is a number:
+ new_base_exten=`echo $OPTARG | tr -d -c 0-9`
+ if [ "x$new_base_exten" != x ]; then base_exten=$new_base_exten; fi
+ ;;
+ c) lc_country=`echo $OPTARG | tr -d -c a-z` ;;
+ d) do_detect=yes ;;
+ F) fxsdisable=yes;;
+ u) do_unload=yes ; force_stop_ast=yes ;;
+ v) verbose=yes ;;
+ l) mode='list' ;;
+ M) do_module_list=yes; do_detect=yes ;;
+ s) force_stop_ast=yes ;;
+ R) do_restart=no ;;
+ z) do_gen_zapscan=yes ;;
+ h) usage; exit 0;;
+ *) echo >&2 "unknown parameter -$arg, Aborting"; usage; exit 1;;
+ esac
+done
+shift $(( $OPTIND-1 ))
+if [ $# != 0 ]; then
+ echo >&2 "$0: too many parameters"
+ usage
+ exit 1
+fi
+
+tmp_dir=`mktemp -d /tmp/genzaptelconf-dir-XXXXXX` || \
+ die "$0: failed to create temporary directory. Aborting"
+
+
+case "$lc_country" in
+ # the list was generated from the source of zaptel:
+ #grep '{.*[0-9]\+,.*"[a-z][a-z]"' zonedata.c | cut -d'"' -f 2 | xargs |tr ' ' '|'
+ us|au|fr|nl|uk|fi|es|jp|no|at|nz|it|gr|tw|cl|se|be|sg|il|br|hu|lt|pl|za|pt|ee|mx|in|de|ch|dk|cz|cn):;;
+ *)
+ lc_country=us
+ echo >&2 "unknown country-code $lc_country, defaulting to \"us\""
+ ;;
+esac
+# any reason for loadzone and defaultzone to be different? If so, this is
+# the place to make that difference
+loadzone=$lc_country
+defaultzone=$loadzone
+
+# make sure asterisk is not in our way
+if [ "$force_stop_ast" = 'yes' ]
+then
+ $ZAPCONF_ASTERISK_CMD stop 1>&2
+else
+ # if asterisk is running and we wanted to detect modules
+ # or simply to unload modules, asterisk needs to go away.
+ if ( [ "$do_unload" = yes ] || [ "$do_detect" = yes ] ) && \
+ pidof asterisk >/dev/null
+ then
+ echo >&2 "Asterisk is already running. Configuration left untouched"
+ echo >&2 "You can use the option -s to shut down Asterisk for the"
+ echo >&2 "duration of the detection."
+ exit_cleanup 1
+ fi
+fi
+
+if [ "$do_unload" = yes ]
+then
+ unload_modules
+ exit_cleanup $?
+fi
+
+if [ "$do_detect" = yes ]
+then
+ detect
+fi
+
+if [ "$zapconf_use_perl" = yes ]; then
+ #redefine genconf to use perl utilities:
+ genconf() {
+ case "$1" in
+ list) zaptel_hardware ;;
+ files) zapconf ;;
+ esac
+ }
+fi
+
+if [ "$mode" = list ]; then
+ genconf list
+else
+ #zap_reg_xpp
+ xpp_startup
+ wait_for_zapctl
+ say "Generating '${ZAPCONF_FILE} and ${ZAPATA_FILE}'"
+ genconf files
+ run_ztcfg
+fi
+
+if [ "$tmp_dir" != '' ]
+then
+ rm -rf "$tmp_dir"
+fi
+
+if [ "$force_stop_ast" != 'yes' ] || [ "$do_restart" != 'yes' ]
+then
+ exit_cleanup 0
+fi
+
+if [ -x "$ZAPCONF_ASTERISK_SCRIPT" ]
+then
+ $ZAPCONF_ASTERISK_CMD start 1>&2
+fi
+
+# if in verbose mode: verify that asterisk is running
+if [ "$verbose" != 'no' ]
+ then
+ say "Checking channels configured in Asterisk:"
+ sleep 1 # give it some time. This is enough on our simple test server
+ if [ -x ast-cmd ]
+ then
+ ast-cmd cmd "zap show channels"
+ else
+ asterisk -rx "zap show channels"
+ fi
+fi
+
+# vim:ts=8:
diff --git a/drivers/dahdi/xpp/utils/genzaptelconf.8 b/drivers/dahdi/xpp/utils/genzaptelconf.8
new file mode 100644
index 0000000..c3f6f73
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/genzaptelconf.8
@@ -0,0 +1,326 @@
+.TH GENZAPTELCONF 8 "July 18th, 2005" "Xorcom Rapid Asterisk" "Linux Programmer's Manual"
+.SH "NAME"
+.B genzaptelconf
+-- generates zaptel configuration (TDM adaptors)
+.SH SYNOPSIS
+.PP
+.B genzaptelconf
+[-sRdvzF] [-c <country_code>] [-e <base_exten>]
+
+.B genzaptelconf
+[-sRdv] -l -- only list to standard output
+
+.B genzaptelconf
+-su -- only unload zaptel modules
+
+.B genzaptelconf
+-h -- Help screen
+
+.SH DESCRIPTION
+.B genzaptelconf
+is a script to detect zaptel devices (currently mostly TDM cards are
+supported). It generates both
+.I /etc/zaptel.conf
+and
+.I /etc/asterisk/zapata-channels.conf
+
+.I PRI
+and
+.I BRI
+(with ZapBRI) cards are basically identified as well. However the span
+configiration is a default that I only hope is sane. Looking for feedback
+
+.SH OPTIONS
+.B -c
+.I country_code
+.RS
+A two-letter country code. Sets the country-code for the zonezone
+entries in
+.I zaptel.conf
+, The default is the value of
+.I lc_country
+from
+.I /etc/default/zaptel
+and failing that, "us".
+.RE
+
+.B -d
+.RS
+Also try to detect modules. Unloads all zaptel modules and loads them
+one by one. Considers a module useful if it loaded successfully and if
+loading it has generated at least one zapata channel.
+
+The list of detected modules is written as the value of
+.I ZAPTEL_MODS
+in
+.I /etc/default/zaptel
+.RE
+
+.B -e
+.I base_exten_num
+.RS
+Configure channel
+.I i
+as extension
+.I exten_num
++
+.I i
+ . This is mostly for the caller-id values. Crude, but may be good enough.
+See also
+.I -r
+.RE
+
+.B -F
+.RS
+Disable writing FXS extensions in zapata.conf
+.RE
+
+.B -l
+.RS
+Only list deceted channels and their signalling. Don't write
+configuration files. Note, however that
+.I -ld
+will still rewrite the modules line in
+.I /etc/default/zaptel
+(see
+.I -d
+above).
+.RE
+
+.B -M
+.RS
+Update
+.I /etc/modules
+with a list of our modules, thereby
+triggers their loading via modprobe on the next boot.
+
+This triggers the
+.I -d
+option as well.
+.RE
+
+.B -R
+.RS
+Don't restart asterisk even if it was stopped using
+.I -s
+ .
+.RE
+
+.B -s
+.RS
+Stop asterisk for the duration of the test. The detection will only
+work if nobody uses the zaptel channels:
+
+* To allow unloading of modules
+
+* to allow reading configuration files.
+
+This option tells the script to stop asterisk (if it was running) and to
+try to start it after the end of the test.
+.RE
+
+.B -v
+.RS
+Be verbose. lists the detected modules if
+.I -d
+is used. Lists detected channls. In the end tries to connect to asterisk
+to get a list of configured zaptel channels.
+.RE
+
+.B -z
+.RS
+emulate the operation of zapscan.bin: generate
+.I /etc/asterisk/zapscan.conf
+with the results of the scan.
+.RE
+
+.SH CONFIGURATION
+Look at the beginning of the script for a number of variables that can
+be overriden through the configuraion file. Some variables can also be
+overriden through the environment. The configuration file is sourced by
+bash but for compatibility expected to have only 'var=VALUE' lines and
+comments or empty lines.
+
+The configuration will first be read from
+.I /etc/default/zaptel
+if it exists, and
+.I /etc/sysconfig/zaptel
+otherwise (But those file names may be overriden, see
+.I ZAPTEL_BOOT_DEBIAN
+and
+.I ZAPTEL_BOOT_FEDORA
+below). Variables set in those files will override the default settings
+and setting rom the environment.
+
+The following variables may be set from the environment:
+ZAPCONF_FILE, ZAPATA_FILE, ZAPTEL_BOOT_DEBIAN, ZAPTEL_BOOT_FEDORA,
+DEVZAP_TIMEOUT, ZTCFG
+
+.RS
+.I lc_country
+.RS
+The default country. Can be also overriden by the option -c
+.RE
+
+.I base_exten
+.RS
+The base number used for automatic numbering
+.RE
+
+.I context_manual
+.RS
+If set to 'yes', no context changes are made in zapata-channels.conf
+.RE
+
+.I context_lines
+.RS
+The context into which calls will go from zaptel trunks.
+.RE
+
+.I context_phones
+.RS
+The context into which calls will go from zaptel phones.
+.RE
+
+.I context_manual
+.RS
+If set to 'yes', no group settings are made in zapata-channels.conf
+.RE
+
+.I group_lines
+.RS
+The group number for zaptel trunks.
+.RE
+
+.I group_phones
+.RS
+The group number for zaptel phones.
+.RE
+
+.I ALL_MODULES
+.RS
+modules list. Used for unloading and modules detection. The order of modules
+is the same for both.
+.RE
+
+.I ZAPCONF_FILE
+.RS
+ztcfg's configuration file. The sane default is /etc/zaptel.conf .
+.RE
+
+.I ZAPATA_FILE
+.RS
+The generated partial zapata.conf snippet. Default:
+/etc/asterisk/zapata-channels.conf .
+.RE
+
+.I ZAPTEL_BOOT_DEBIAN
+.RS
+The Debian Zaptel defaults file. Normally
+.I /etc/default/zaptel
+.
+.RE
+
+
+.I ZAPTEL_BOOT_FEDORA
+.RS
+The Zaptel defaults file on various other distributions. Normally
+.I /etc/sysconfig/zaptel
+ .
+.RE
+
+.I DEVZAP_TIMEOUT
+.RS
+Maximal number of seconds to wait for /dev/zap to be initializaed by
+udev.
+.RE
+
+.I ZTCFG
+.RS
+The full path to the ztcfg tool. Default:
+.I /sbin/ztcfg
+genzaptelconf will also explicitly test for
+.I /usr/sbin/ztcfg
+as a last resort.
+.RE
+.RE
+
+.SH FILES
+.I /etc/zaptel.conf
+.RS
+The configuration file used by
+.I ztcfg
+to configure zaptel devices. re-written by
+.I genzaptelconf
+ . A backup copy is saved to
+.I /etc/zaptel.conf.bak
+ .
+.RE
+
+.I /etc/asterisk/zapata.conf
+.RS
+The configuration file of Asterisk's
+.I chan_zap.
+Not modified directly by
+.I genzaptelconf.
+If you want genzaptelconf's setting to take effect, add the following
+line at the end of
+.I zapata.conf:
+.RS
+#include "zapata-channels.conf"
+.RE
+.RE
+
+.I /etc/asterisk/zapata-channels.conf
+.RS
+This is the snippet of
+.I chan_zap
+configuration file that
+.I genzaptelconf generates.
+ . A backup copy is saved to
+.I /etc/asterisk/zapata-channels.conf.bak
+ .
+.RE
+
+.I /etc/default/zaptel
+.RS
+This file holds configuration for both
+.I genzaptelconf
+and
+.I /etc/init.d/zaptel .
+It is sourced by both scripts and can thus be used to override settings
+of variables from those scripts.
+.RE
+
+.I /etc/modules
+.RS
+A debian-specific list of kernel modules to be loaded by modprobe at
+boot time. When the option
+.I -d
+(detect) is used, genzaptelconf will write in this file zaptel modules
+to be loaded. If you want to use a different file, set
+.I MOD_FILELIST
+ . If it is rewritten, a backup copy is saved to
+.I /etc/modules.bak
+ .
+.RS
+The backup copy of
+.I /etc/modules
+.RE
+
+.SH "SEE ALSO"
+ztcfg(8) asterisk(8).
+
+.SH BUGS
+If you override a configuration variable both through the environment
+and through the configuration file, the value from the configuration
+file wins.
+
+.SH "AUTHOR"
+This manual page was written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/drivers/dahdi/xpp/utils/hexfile.c b/drivers/dahdi/xpp/utils/hexfile.c
new file mode 100644
index 0000000..2a01b3f
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/hexfile.c
@@ -0,0 +1,567 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2006, Xorcom
+ *
+ * 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 <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include "hexfile.h"
+
+static const char rcsid[] = "$Id$";
+
+static parse_hexfile_report_func_t report_func = NULL;
+
+parse_hexfile_report_func_t parse_hexfile_set_reporting(parse_hexfile_report_func_t rf)
+{
+ parse_hexfile_report_func_t old_rf = report_func;
+ report_func = rf;
+ return old_rf;
+}
+
+static void chomp(char buf[])
+{
+ size_t last = strlen(buf) - 1;
+ while(last >= 0 && isspace(buf[last]))
+ buf[last--] = '\0';
+}
+
+static int hexline_checksum(struct hexline *hexline)
+{
+ unsigned int i;
+ unsigned int chksm = 0;
+ int ll = hexline->d.content.header.ll;
+
+ for(i = 0; i <= sizeof(hexline->d.content.header) + ll; i++) {
+ chksm += hexline->d.raw[i];
+ }
+ return chksm & 0xFF;
+}
+
+int dump_hexline(int recordno, struct hexline *line, FILE *fp)
+{
+ uint8_t ll;
+ uint16_t offset;
+ uint8_t tt;
+ uint8_t old_chksum;
+ uint8_t new_chksum;
+ uint8_t *data;
+ unsigned int i;
+
+ ll = line->d.content.header.ll;
+ offset = line->d.content.header.offset;
+ tt = line->d.content.header.tt;
+ fprintf(fp, ":%02X%04X%02X", ll, offset, tt);
+ data = line->d.content.tt_data.data;
+ for(i = 0; i < ll; i++) {
+ fprintf(fp, "%02X", data[i]);
+ }
+ old_chksum = data[ll];
+ data[ll] = 0;
+ new_chksum = 0xFF - hexline_checksum(line) + 1;
+ data[ll] = old_chksum;
+ fprintf(fp, "%02X\n", new_chksum);
+ if(new_chksum != old_chksum) {
+ if(report_func)
+ report_func(LOG_ERR, "record #%d: new_chksum(%02X) != old_chksum(%02X)\n",
+ recordno, new_chksum, old_chksum);
+ return 0;
+ }
+ return 1;
+}
+
+struct hexline *new_hexline(uint8_t datalen, uint16_t offset, uint8_t tt)
+{
+ struct hexline *hexline;
+ size_t allocsize;
+
+ allocsize = sizeof(struct hexline) + datalen + 1; /* checksum byte */
+ if((hexline = malloc(allocsize)) == NULL) {
+ if(report_func)
+ report_func(LOG_ERR, "No more memory\n");
+ return NULL;
+ }
+ memset(hexline, 0, allocsize);
+ hexline->d.content.header.ll = datalen;
+ hexline->d.content.header.offset = offset;
+ hexline->d.content.header.tt = tt;
+ return hexline;
+}
+
+static int append_hexline(struct hexdata *hexdata, char *buf)
+{
+ int ret;
+ unsigned int ll, offset, tt;
+ char *p;
+ struct hexline *hexline;
+ unsigned int i;
+
+ if(hexdata->got_eof) {
+ if(report_func)
+ report_func(LOG_ERR, "Extranous data after EOF record\n");
+ return -EINVAL;
+ }
+ if(hexdata->last_line >= hexdata->maxlines) {
+ if(report_func)
+ report_func(LOG_ERR, "Hexfile too large (maxline %d)\n", hexdata->maxlines);
+ return -ENOMEM;
+ }
+ ret = sscanf(buf, "%02X%04X%02X", &ll, &offset, &tt);
+ if(ret != 3) {
+ if(report_func)
+ report_func(LOG_ERR, "Bad line header (only %d items out of 3 parsed)\n", ret);
+ return -EINVAL;
+ }
+ switch(tt) {
+ case TT_DATA:
+ break;
+ case TT_EOF:
+ if(ll != 0) {
+ if(report_func)
+ report_func(LOG_ERR,
+ "%d: Record %d(EOF): Bad len = %d\n",
+ hexdata->last_line, tt, ll);
+ return -EINVAL;
+ }
+ if(offset != 0) {
+ if(report_func)
+ report_func(LOG_ERR,
+ "%d: Record %d(EOF): Bad offset = %d\n",
+ hexdata->last_line, tt, offset);
+ return -EINVAL;
+ }
+ hexdata->got_eof = 1;
+ break;
+ case TT_EXT_SEG:
+ if(ll != 2) {
+ if(report_func)
+ report_func(LOG_ERR,
+ "%d: Record %d(EXT_SEG): Bad len = %d\n",
+ hexdata->last_line, tt, ll);
+ return -EINVAL;
+ }
+ if(offset != 0) {
+ if(report_func)
+ report_func(LOG_ERR,
+ "%d: Record %d(EXT_SEG): Bad offset = %d\n",
+ hexdata->last_line, tt, offset);
+ return -EINVAL;
+ }
+ break;
+ case TT_START_SEG:
+ if(ll != 4) {
+ if(report_func)
+ report_func(LOG_ERR,
+ "%d: Record %d(START_SEG): Bad len = %d\n",
+ hexdata->last_line, tt, ll);
+ return -EINVAL;
+ }
+ if(offset != 0) {
+ if(report_func)
+ report_func(LOG_ERR,
+ "%d: Record %d(START_SEG): Bad offset = %d\n",
+ hexdata->last_line, tt, offset);
+ return -EINVAL;
+ }
+ break;
+ case TT_EXT_LIN:
+ if(ll != 2) {
+ if(report_func)
+ report_func(LOG_ERR,
+ "%d: Record %d(EXT_LIN): Bad len = %d\n",
+ hexdata->last_line, tt, ll);
+ return -EINVAL;
+ }
+ if(offset != 0) {
+ if(report_func)
+ report_func(LOG_ERR,
+ "%d: Record %d(EXT_LIN): Bad offset = %d\n",
+ hexdata->last_line, tt, ll);
+ return -EINVAL;
+ }
+ break;
+ case TT_START_LIN: /* Unimplemented */
+ if(ll != 4) {
+ if(report_func)
+ report_func(LOG_ERR,
+ "%d: Record %d(EXT_LIN): Bad len = %d\n",
+ hexdata->last_line, tt, ll);
+ return -EINVAL;
+ }
+ if(offset != 0) {
+ if(report_func)
+ report_func(LOG_ERR,
+ "%d: Record %d(EXT_LIN): Bad offset = %d\n",
+ hexdata->last_line, tt, ll);
+ return -EINVAL;
+ }
+ break;
+ default:
+ if(report_func)
+ report_func(LOG_ERR, "%d: Unimplemented record type %d: %s\n",
+ hexdata->last_line, tt, buf);
+ return -EINVAL;
+ }
+ buf += 8; /* Skip header */
+ if((hexline = new_hexline(ll, offset, tt)) == NULL) {
+ if(report_func)
+ report_func(LOG_ERR, "No more memory for hexfile lines\n");
+ return -EINVAL;
+ }
+ p = buf;
+ for(i = 0; i < ll + 1; i++) { /* include checksum */
+ unsigned int val;
+
+ if((*p == '\0') || (*(p+1) == '\0')) {
+ if(report_func)
+ report_func(LOG_ERR, "Short data string '%s'\n", buf);
+ return -EINVAL;
+ }
+ ret = sscanf(p, "%02X", &val);
+ if(ret != 1) {
+ if(report_func)
+ report_func(LOG_ERR, "Bad data byte #%d\n", i);
+ return -EINVAL;
+ }
+ hexline->d.content.tt_data.data[i] = val;
+ p += 2;
+ }
+ if(hexline_checksum(hexline) != 0) {
+ if(report_func) {
+ report_func(LOG_ERR, "Bad checksum (%d instead of 0)\n",
+ hexline_checksum(hexline));
+ dump_hexline(hexdata->last_line, hexline, stderr);
+ }
+ return -EINVAL;
+ }
+ hexdata->lines[hexdata->last_line] = hexline;
+ if(hexdata->got_eof)
+ return 0;
+ hexdata->last_line++;
+ return 1;
+}
+
+void free_hexdata(struct hexdata *hexdata)
+{
+ if(hexdata) {
+ unsigned int i;
+
+ for(i = 0; i < hexdata->maxlines; i++)
+ if(hexdata->lines[i] != NULL)
+ free(hexdata->lines[i]);
+ free(hexdata);
+ }
+}
+
+int dump_hexfile(struct hexdata *hexdata, const char *outfile)
+{
+ FILE *fp;
+ unsigned int i;
+
+ if(report_func)
+ report_func(LOG_INFO, "Dumping hex data into '%s'\n", outfile);
+ if(!outfile || strcmp(outfile, "-") == 0)
+ fp = stdout;
+ else if((fp = fopen(outfile, "w")) == NULL) {
+ perror(outfile);
+ exit(1);
+ }
+ for(i = 0; i <= hexdata->last_line; i++) {
+ struct hexline *line = hexdata->lines[i];
+ if(!line) {
+ if(report_func)
+ report_func(LOG_ERR, "Missing line at #%d\n", i);
+ return -EINVAL;
+ }
+ if(!dump_hexline(i, line, fp))
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int dump_hexfile2(struct hexdata *hexdata, const char *outfile, uint8_t maxwidth)
+{
+ FILE *fp;
+ uint8_t tt;
+ unsigned int i;
+ struct hexline *line;
+
+ if(report_func)
+ report_func(LOG_INFO,
+ "Dumping hex data into '%s' (maxwidth=%d)\n",
+ outfile, maxwidth);
+ if(!outfile || strcmp(outfile, "-") == 0)
+ fp = stdout;
+ else if((fp = fopen(outfile, "w")) == NULL) {
+ perror(outfile);
+ exit(1);
+ }
+ if(maxwidth == 0)
+ maxwidth = UINT8_MAX;
+ for(i = 0; i <= hexdata->last_line; i++) {
+ int bytesleft = 0;
+ int extra_offset = 0;
+ int base_offset;
+ uint8_t *base_data;
+
+ line = hexdata->lines[i];
+ if(!line) {
+ if(report_func)
+ report_func(LOG_ERR, "Missing line at #%d\n", i);
+ return -EINVAL;
+ }
+ bytesleft = line->d.content.header.ll;
+ /* split the line into several lines */
+ tt = line->d.content.header.tt;
+ base_offset = line->d.content.header.offset;
+ base_data = line->d.content.tt_data.data;
+ while (bytesleft > 0) {
+ struct hexline *extraline;
+ uint8_t new_chksum;
+ unsigned int curr_bytes = (bytesleft >= maxwidth) ? maxwidth : bytesleft;
+
+ /* generate the new line */
+ if((extraline = new_hexline(curr_bytes, base_offset + extra_offset, tt)) == NULL) {
+ if(report_func)
+ report_func(LOG_ERR, "No more memory for hexfile lines\n");
+ return -EINVAL;
+ }
+ memcpy(extraline->d.content.tt_data.data, base_data + extra_offset, curr_bytes);
+ new_chksum = 0xFF - hexline_checksum(extraline) + 1;
+ extraline->d.content.tt_data.data[curr_bytes] = new_chksum;
+ /* print it */
+ dump_hexline(i, extraline, fp);
+ /* cleanups */
+ free(extraline);
+ extra_offset += curr_bytes;
+ bytesleft -= curr_bytes;
+ }
+ }
+ if(tt != TT_EOF) {
+ if(report_func)
+ report_func(LOG_ERR, "Missing EOF record\n");
+ return -EINVAL;
+ }
+ dump_hexline(i, line, fp);
+ return 0;
+}
+
+void process_comment(struct hexdata *hexdata, char buf[])
+{
+ char *dollar_start;
+ char *dollar_end;
+ const char id_prefix[] = "Id: ";
+ char tmp[BUFSIZ];
+ char *p;
+ int len;
+
+ if(report_func)
+ report_func(LOG_INFO, "Comment: %s\n", buf + 1);
+ /* Search for RCS keywords */
+ if((dollar_start = strchr(buf, '$')) == NULL)
+ return;
+ if((dollar_end = strchr(dollar_start + 1, '$')) == NULL)
+ return;
+ /* Crop the '$' signs */
+ len = dollar_end - dollar_start;
+ len -= 2;
+ memcpy(tmp, dollar_start + 1, len);
+ tmp[len] = '\0';
+ p = tmp;
+ if(strstr(tmp, id_prefix) == NULL)
+ return;
+ p += strlen(id_prefix);
+ if((p = strchr(p, ' ')) == NULL)
+ return;
+ p++;
+ snprintf(hexdata->version_info, BUFSIZ, "%s", p);
+ if((p = strchr(hexdata->version_info, ' ')) != NULL)
+ *p = '\0';
+}
+
+struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines)
+{
+ FILE *fp;
+ struct hexdata *hexdata = NULL;
+ int datasize;
+ char buf[BUFSIZ];
+ int line;
+ int dos_eof = 0;
+ int ret;
+
+ assert(fname != NULL);
+ if(report_func)
+ report_func(LOG_INFO, "Parsing %s\n", fname);
+ datasize = sizeof(struct hexdata) + maxlines * sizeof(char *);
+ hexdata = (struct hexdata *)malloc(datasize);
+ if(!hexdata) {
+ if(report_func)
+ report_func(LOG_ERR, "Failed to allocate %d bytes for hexfile contents\n", datasize);
+ goto err;
+ }
+ memset(hexdata, 0, datasize);
+ hexdata->maxlines = maxlines;
+ if((fp = fopen(fname, "r")) == NULL) {
+ if(report_func)
+ report_func(LOG_ERR, "Failed to open hexfile '%s'\n", fname);
+ goto err;
+ }
+ for(line = 1; fgets(buf, BUFSIZ, fp); line++) {
+ if(dos_eof) {
+ if(report_func)
+ report_func(LOG_ERR, "%s:%d - Got DOS EOF character before true EOF\n", fname, line);
+ goto err;
+ }
+ if(buf[0] == 0x1A && buf[1] == '\0') { /* DOS EOF char */
+ dos_eof = 1;
+ continue;
+ }
+ chomp(buf);
+ if(buf[0] == '\0') {
+ if(report_func)
+ report_func(LOG_ERR, "%s:%d - Short line\n", fname, line);
+ goto err;
+ }
+ if(buf[0] == '#') {
+ process_comment(hexdata, buf);
+ continue;
+ }
+ if(buf[0] != ':') {
+ if(report_func)
+ report_func(LOG_ERR, "%s:%d - Line begins with 0x%X\n", fname, line, buf[0]);
+ goto err;
+ }
+ if((ret = append_hexline(hexdata, buf + 1)) < 0) {
+ if(report_func)
+ report_func(LOG_ERR, "%s:%d - Failed parsing.\n", fname, line);
+ goto err;
+ }
+ }
+ fclose(fp);
+ if(report_func)
+ report_func(LOG_INFO, "%s parsed OK\n", fname);
+ return hexdata;
+err:
+ free_hexdata(hexdata);
+ return NULL;
+}
+
+void dump_binary(struct hexdata *hexdata, const char *outfile)
+{
+ FILE *fp;
+ unsigned int i;
+ size_t len;
+
+ if(report_func)
+ report_func(LOG_INFO, "Dumping binary data into '%s'\n", outfile);
+ if((fp = fopen(outfile, "w")) == NULL) {
+ perror(outfile);
+ exit(1);
+ }
+ for(i = 0; i < hexdata->maxlines; i++) {
+ struct hexline *hexline = hexdata->lines[i];
+
+ if(!hexline)
+ break;
+ switch(hexline->d.content.header.tt) {
+ case TT_EOF:
+ if(report_func)
+ report_func(LOG_INFO, "\ndump: good EOF record");
+ break;
+ case TT_DATA:
+ if(report_func)
+ report_func(LOG_INFO, "dump: %6d\r", i);
+ len = hexline->d.content.header.ll;
+ if(fwrite(hexline->d.content.tt_data.data, 1, len, fp) != len) {
+ perror("write");
+ exit(1);
+ }
+ break;
+ case TT_EXT_SEG:
+ case TT_START_SEG:
+ case TT_EXT_LIN:
+ case TT_START_LIN:
+ if(report_func)
+ report_func(LOG_INFO,
+ "\ndump(%d): ignored record type %d",
+ i, hexline->d.content.header.tt);
+ break;
+ default:
+ if(report_func)
+ report_func(LOG_ERR, "dump: Unknown record type %d\n",
+ hexline->d.content.header.tt);
+ exit(1);
+ }
+ }
+ if(report_func)
+ report_func(LOG_INFO, "\nDump finished\n");
+ fclose(fp);
+}
+
+void gen_hexline(const uint8_t *data, uint16_t addr, size_t len, FILE *output)
+{
+ struct hexline *hexline;
+
+ if(!data) {
+ fprintf(output, ":%02X%04X%02XFF\n", 0, 0, TT_EOF);
+ return;
+ }
+ if((hexline = new_hexline(len, addr, (!data) ? TT_EOF : TT_DATA)) == NULL) {
+ if(report_func)
+ report_func(LOG_ERR, "No more memory\n");
+ return;
+ }
+ if(data)
+ memcpy(&hexline->d.content.tt_data, data, len);
+ dump_hexline(0, hexline, output);
+ free(hexline);
+}
+
+/*
+ * Algorithm lifted of sum(1) implementation from coreutils.
+ * We chose the default algorithm (BSD style).
+ */
+int bsd_checksum(struct hexdata *hexdata)
+{
+ unsigned int i;
+ size_t len;
+ int ck = 0;
+
+ for(i = 0; i < hexdata->maxlines; i++) {
+ struct hexline *hexline = hexdata->lines[i];
+ unsigned char *p;
+
+ if(!hexline)
+ break;
+ if(hexline->d.content.header.tt == TT_EOF)
+ continue;
+ len = hexline->d.content.header.ll;
+ p = hexline->d.content.tt_data.data;
+ for(; len; p++, len--) {
+ ck = (ck >> 1) + ((ck & 1) << 15);
+ ck += *p;
+ ck &= 0xffff; /* Keep it within bounds. */
+ }
+ }
+ return ck;
+}
diff --git a/drivers/dahdi/xpp/utils/hexfile.h b/drivers/dahdi/xpp/utils/hexfile.h
new file mode 100644
index 0000000..f8bf6a9
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/hexfile.h
@@ -0,0 +1,123 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2006, Xorcom
+ *
+ * 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.
+ *
+ */
+
+#ifndef PARSE_HEXFILE_H
+#define PARSE_HEXFILE_H
+
+#include <stdarg.h>
+
+/*
+ * Some portability workarounds
+ */
+#ifdef _WINDOWS
+
+#include <windows.h> /* for UCHAR USHORT */
+typedef UCHAR uint8_t;
+typedef USHORT uint16_t;
+#define PACKED
+#define sscanf sscanf_s
+#define ZERO_SIZE 1
+
+/* From /usr/include/syslog.h */
+#define LOG_EMERG 0 /* system is unusable */
+#define LOG_ALERT 1 /* action must be taken immediately */
+#define LOG_CRIT 2 /* critical conditions */
+#define LOG_ERR 3 /* error conditions */
+#define LOG_WARNING 4 /* warning conditions */
+#define LOG_NOTICE 5 /* normal but significant condition */
+#define LOG_INFO 6 /* informational */
+#define LOG_DEBUG 7 /* debug-level messages */
+
+#ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+#else
+# define __BEGIN_DECLS
+# define __END_DECLS
+#endif
+
+#elif __GNUC__
+
+#include <stdint.h>
+#include <syslog.h>
+#define PACKED __attribute__((packed))
+#define ZERO_SIZE 1
+
+#else
+
+#error "Cannot compile on this platform"
+
+#endif
+
+/* Record types in hexfile */
+enum {
+ TT_DATA = 0,
+ TT_EOF = 1,
+ TT_EXT_SEG = 2,
+ TT_START_SEG = 3,
+ TT_EXT_LIN = 4,
+ TT_START_LIN = 5,
+ TT_NO_SUCH_TT
+};
+
+#pragma pack(1)
+struct hexline {
+ union {
+ uint8_t raw[ZERO_SIZE];
+ struct content {
+ struct header {
+ uint8_t ll; /* len */
+ uint16_t offset; /* offset */
+ uint8_t tt; /* type */
+ } PACKED header;
+ struct tt_data {
+ uint8_t data[ZERO_SIZE];
+ } tt_data;
+ } PACKED content;
+ } d;
+} PACKED;
+#pragma pack()
+
+struct hexdata {
+ unsigned int maxlines;
+ unsigned int last_line;
+ int got_eof;
+ char version_info[BUFSIZ];
+ struct hexline *lines[ZERO_SIZE];
+};
+
+
+__BEGIN_DECLS
+
+typedef void (*parse_hexfile_report_func_t)(int level, const char *msg, ...);
+
+parse_hexfile_report_func_t parse_hexfile_set_reporting(parse_hexfile_report_func_t rf);
+void free_hexdata(struct hexdata *hexdata);
+struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines);
+int dump_hexfile(struct hexdata *hexdata, const char *outfile);
+int dump_hexfile2(struct hexdata *hexdata, const char *outfile, uint8_t maxwidth);
+void dump_binary(struct hexdata *hexdata, const char *outfile);
+void gen_hexline(const uint8_t *data, uint16_t addr, size_t len, FILE *output);
+int bsd_checksum(struct hexdata *hexdata);
+__END_DECLS
+
+#endif
diff --git a/drivers/dahdi/xpp/utils/lszaptel b/drivers/dahdi/xpp/utils/lszaptel
new file mode 100755
index 0000000..a836d98
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/lszaptel
@@ -0,0 +1,108 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
+
+use Zaptel;
+use Zaptel::Span;
+use Zaptel::Xpp;
+use Zaptel::Xpp::Xbus;
+use Zaptel::Xpp::Xpd;
+
+my @xbuses = Zaptel::Xpp::xbuses("SORT_CONNECTOR");
+my @xpds = map { $_->xpds } @xbuses;
+
+foreach my $span (Zaptel::spans()) {
+ my $spanno = $span->num;
+ my $xpd = $span->xpd;
+ my @lines;
+ my $index = 0;
+
+ @lines = @{$xpd->lines} if defined $xpd;
+ printf "### Span %2d: %s %s\n", $span->num, $span->name, $span->description;
+ foreach my $chan ($span->chans()) {
+ my %type_map = (
+ OUT => 'Output',
+ IN => 'Input'
+ );
+ my ($type) = map { $type_map{$_} or $_ } $chan->type || ("unknown");
+ my $batt = "";
+ $batt = "(battery)" if $chan->battery;
+ printf "%3d %-10s %-10s %s %s\n",
+ $chan->num, $type, $chan->signalling, $chan->info, $batt;
+ $index++;
+ }
+}
+
+__END__
+
+=head1 NAME
+
+lszaptel - List all zaptel channels with their types and spans.
+
+=head1 SYNOPSIS
+
+lszaptel
+
+=head1 DESCRIPTION
+
+Example output:
+
+ ### Span 1: WCTDM/0 "Wildcard TDM400P REV E/F Board 1"
+ 1 FXO FXOLS (In use)
+ 2 FXS FXSKS
+ 3 FXS FXSKS
+ 4 FXS FXSKS
+ ### Span 2: XBUS-00/XPD-00 "Xorcom XPD #00/00: FXO"
+ 5 FXO FXSKS (In use)
+ 6 FXO FXSKS (In use) (no pcm)
+ 7 FXO FXSKS (In use) (no pcm)
+ 8 FXO FXSKS (In use) (no pcm)
+ 9 FXO FXSKS (In use) (no pcm)
+ 10 FXO FXSKS (In use) (no pcm)
+ 11 FXO FXSKS (In use) (no pcm)
+ 12 FXO FXSKS (In use) (no pcm)
+ ### Span 3: XBUS-00/XPD-10 "Xorcom XPD #00/10: FXO"
+ 13 FXO FXSKS (In use) (no pcm)
+ 14 FXO FXSKS (In use) (no pcm)
+ 15 FXO FXSKS (In use) (no pcm)
+ 16 FXO FXSKS (In use) (no pcm)
+ 17 FXO FXSKS (In use) (no pcm)
+ 18 FXO FXSKS (In use) (no pcm)
+ 19 FXO FXSKS (In use) (no pcm)
+ 20 FXO FXSKS (In use) (no pcm)
+
+ ...
+
+ ### Span 6: XBUS-01/XPD-00 "Xorcom XPD #01/00: FXS"
+ 37 FXS FXOLS (In use)
+ 38 FXS FXOLS (In use) (no pcm)
+ 39 FXS FXOLS (In use) (no pcm)
+ 40 FXS FXOLS (In use) (no pcm)
+ 41 FXS FXOLS (In use) (no pcm)
+ 42 FXS FXOLS (In use) (no pcm)
+ 43 FXS FXOLS (In use) (no pcm)
+ 44 FXS FXOLS (In use) (no pcm)
+ 45 Output FXOLS (In use) (no pcm)
+ 46 Output FXOLS (In use) (no pcm)
+ 47 Input FXOLS (In use) (no pcm)
+ 48 Input FXOLS (In use) (no pcm)
+ 49 Input FXOLS (In use) (no pcm)
+ 50 Input FXOLS (In use) (no pcm)
+
+The first column is the type of the channel (port, for an analog device)
+and the second one is the signalling (if set).
+
+=head1 FILES
+
+lszaptel is a somewhat glorified 'cat /proc/zaptel/*' . Unlike that
+command, it sorts the spans with the proper order. It also formats the
+output slightly differently.
diff --git a/drivers/dahdi/xpp/utils/print_modes.c b/drivers/dahdi/xpp/utils/print_modes.c
new file mode 100644
index 0000000..77e0e33
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/print_modes.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+
+#include "wctdm_fxomodes.h"
+
+int main() {
+ size_t i;
+
+ for (i=0; i<(sizeof(fxo_modes)/sizeof(struct fxo_mode)); i++) {
+ if (fxo_modes[i].name == NULL) break;
+ int reg16=0, reg26=0, reg30=0, reg31=0x20;
+ char ring_osc[BUFSIZ]="", ring_x[BUFSIZ] = "";
+
+ reg16 |= (fxo_modes[i].ohs << 6);
+ reg16 |= (fxo_modes[i].rz << 1);
+ reg16 |= (fxo_modes[i].rt);
+
+ reg26 |= (fxo_modes[i].dcv << 6);
+ reg26 |= (fxo_modes[i].mini << 4);
+ reg26 |= (fxo_modes[i].ilim << 1);
+
+ reg30 = (fxo_modes[i].acim);
+
+ reg31 |= (fxo_modes[i].ohs2 << 3);
+
+ if (fxo_modes[i].ring_osc)
+ snprintf(ring_osc, BUFSIZ, "ring_osc=%04X", fxo_modes[i].ring_osc);
+ if (fxo_modes[i].ring_x)
+ snprintf(ring_x, BUFSIZ, "ring_x=%04X", fxo_modes[i].ring_x);
+ printf("%-15s\treg16=%02X\treg26=%02X\treg30=%02X\treg31=%02X\t%s\t%s\n",
+ fxo_modes[i].name, reg16, reg26, reg30, reg31, ring_osc, ring_x);
+ }
+ return 0;
+}
diff --git a/drivers/dahdi/xpp/utils/test_parse.c b/drivers/dahdi/xpp/utils/test_parse.c
new file mode 100644
index 0000000..8ac2023
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/test_parse.c
@@ -0,0 +1,35 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include "hexfile.h"
+
+static void default_report_func(int level, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ vfprintf(stderr, msg, ap);
+ va_end(ap);
+}
+
+int main(int argc, char *argv[])
+{
+ struct hexdata *hd;
+ int i;
+
+ if(argc < 2) {
+ fprintf(stderr, "Usage: program hexfile...\n");
+ return 1;
+ }
+ parse_hexfile_set_reporting(default_report_func);
+ for(i = 1; i < argc; i++) {
+ hd = parse_hexfile(argv[i], 2000);
+ if(!hd) {
+ fprintf(stderr, "Parsing failed\n");
+ return 1;
+ }
+ fprintf(stderr, "=== %s === (version: %s)\n", argv[i], hd->version_info);
+ dump_hexfile2(hd, "-", 60 );
+ free_hexdata(hd);
+ }
+ return 0;
+}
diff --git a/drivers/dahdi/xpp/utils/xpp.rules b/drivers/dahdi/xpp/utils/xpp.rules
new file mode 100644
index 0000000..d3cc226
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/xpp.rules
@@ -0,0 +1,14 @@
+BUS!="usb", ACTION!="add", GOTO="xpp_usb_add_end"
+KERNEL=="*_ep*", GOTO="xpp_usb_add_end"
+KERNEL=="[0-9]*", GOTO="xpp_usb_add_end"
+
+# Load firmware into the Xorcom Astribank device:
+SYSFS{idVendor}=="e4e4", SYSFS{idProduct}=="11[345][01]", \
+ RUN+="/usr/share/zaptel/xpp_fxloader udev $sysfs{idVendor}/$sysfs{idProduct}/$sysfs{bcdDevice}"
+
+LABEL="xpp_usb_add_end"
+
+# Hotplug hook for Astribank up/down
+# By default XPP_INIT_DIR="/usr/share/zaptel"
+KERNEL=="xbus*" RUN+="%E{XPP_INIT_DIR}/astribank_hook udev $kernel $sysfs{status} $sysfs{connector}"
+
diff --git a/drivers/dahdi/xpp/utils/xpp_blink b/drivers/dahdi/xpp/utils/xpp_blink
new file mode 100755
index 0000000..7d0d845
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/xpp_blink
@@ -0,0 +1,168 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
+
+use Zaptel;
+use Zaptel::Span;
+use Zaptel::Xpp;
+use Zaptel::Xpp::Xbus;
+
+sub usage {
+ die "Usage: $0 {on|off|bzzt} {span <number> | chan <number> | xpd <bus num> [<xpd num>] | label <label>}\n";
+}
+
+my $state = shift;
+my $selector = shift;
+usage unless defined($state) and $state =~ /^(on|off|bzzt)$/;
+usage unless defined($selector) and $selector =~ /^(span|chan|xpd|label)$/i;
+
+my $xpd;
+my @blinklist;
+my @channels;
+
+if($selector =~ /^span$/i) {
+ my $number = shift;
+ usage unless defined($number) and $number =~ /^\d+/;
+ my $span = Zaptel::Span::by_number($number);
+ die "Unkown Span $number\n" unless $span;
+ $xpd = Zaptel::Xpp::xpd_of_span($span);
+ die "Span $number is not an XPD\n" unless defined $xpd;
+ my $xpdname = $xpd->fqn;
+ my $connector = $xpd->xbus->connector;
+ die "$xpdname is not connected\n" unless defined $connector;
+ push(@blinklist, $xpd);
+ my @chans = $span->chans();
+ @channels = join(' ', map { $_->num } @chans);
+ printf "Using %s (connected via $connector): channels @channels\n", $xpd->fqn;
+} elsif($selector =~ /^chan$/i) {
+ my $channo = shift;
+ usage unless defined($channo) and $channo =~ /^\d+/;
+ my @spans = Zaptel::spans();
+ my @chans = map { $_->chans() } @spans;
+ my ($chan) = grep { $_->num eq $channo } @chans;
+ die "Channel $channo was not found\n" unless defined $chan;
+ die "Cannot blink Input ports\n" if $chan->type eq 'IN';
+ die "Cannot blink Output ports\n" if $chan->type eq 'OUT';
+ push(@blinklist, $chan);
+} elsif($selector =~ /^xpd$/i) {
+ my $busnum = shift;
+ my $xpdnum = shift;
+ my $linenum = shift;
+ usage unless defined($busnum) and $busnum =~ /^\d+/;
+ my $xbus = Zaptel::Xpp::Xbus::by_number($busnum);
+ die "Unkown XBUS number $busnum\n" unless defined $xbus;
+ if(defined $xpdnum) {
+ usage unless $xpdnum =~ /^\d+/;
+ $xpd = $xbus->get_xpd_by_number($xpdnum);
+ die "Unkown XPD number $xpdnum on XBUS number $busnum\n" unless defined $xpd;
+ if(defined $linenum) {
+ usage unless $linenum =~ /^\d+/;
+ my $lines = $xpd->lines;
+ my $l = @{$lines}[$linenum];
+ die "Bad line number $linenum on XPD $xpd->fqn\n" unless defined $l;
+ push(@blinklist, $l);
+ } else {
+ push(@blinklist, $xpd);
+ }
+ } else {
+ @blinklist = $xbus->xpds;
+ die "XBUS number $busnum has no XPDS!\n" unless @blinklist;
+ }
+} elsif($selector =~ /^label$/i) {
+ my $label = shift;
+ usage unless defined($label);
+ my $xbus = Zaptel::Xpp::Xbus::by_label($label);
+ die "Unkown XBUS label $label\n" unless defined $xbus;
+ @blinklist = $xbus->xpds;
+ die "XBUS label '$label' has no XPDS!\n" unless @blinklist;
+}
+
+if($state eq 'on') {
+ $_->blink(1) foreach (@blinklist);
+} elsif($state eq 'off') {
+ $_->blink(0) foreach (@blinklist);
+} elsif($state eq 'bzzt') {
+ $_->blink(1) foreach (@blinklist);
+ sleep 1;
+ $_->blink(0) foreach (@blinklist);
+}
+
+__END__
+
+=head1 NAME
+
+xpp_blink - Blink the leds of a specified XPD
+
+=head1 SYNOPSIS
+
+xpp_blink {on|off|bzzt} {span <number> | chan <number> | xpd <bus num> [<xpd num> [<lineno>]]}
+
+=head1 DESCRIPTION
+
+Blink all the leds of an XPD.
+
+=head2 Blink mode:
+
+=over
+
+=item on
+
+Turn on constant blink
+
+=item off
+
+Turn off blink
+
+=item bzzt
+
+Blink briefly for 1 second.
+
+=back
+
+=head2 Selector:
+
+=over
+
+=item span
+
+Select by span number. This only work for XPD registered to zaptel.
+
+will also print the zaptel channels of the span and the xbus/xpd this
+span represents.
+
+=item chan
+
+Select by channel number. This only work for XPD registered to zaptel.
+
+=item xpd
+
+Select by xbus + xpd numbers. If only xbus number is given, all the
+XPDs of the selected xbus (Astribank) are blinked.
+
+=item label
+
+Select by xbus label. Affect the whole Astribank.
+
+=back
+
+=head1 EXAMPLES
+
+ $ xpp_blink bzzt span 2
+ Using XBUS-04/XPD-10 (connected via usb-0000:00:1d.7-1): channels 15 16 17 18 19 20 21 22
+
+ $ xpp_blink bzzt chan 18
+
+ $ xpp_blink on xpd 0 1 5
+
+ $ xpp_blink off xpd 0
+
+ $ xpp_blink bzzt label 'usb:00000238'
diff --git a/drivers/dahdi/xpp/utils/xpp_fxloader b/drivers/dahdi/xpp/utils/xpp_fxloader
new file mode 100644
index 0000000..5a26560
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/xpp_fxloader
@@ -0,0 +1,297 @@
+#!/bin/sh
+
+# xpp_fxloader: load Xorcom Astribank (XPP) firmware
+#
+# This script can be run manually or from hotplug/udev.
+#
+# Firmware files should be located in $FIRMWARE_DIR which defaults:
+# 1. /usr/share/zaptel
+# 2. Can be overidden by setting $FIRMWARE_DIR in the environment
+# 3. Can be overidden by setting $FIRMWARE_DIR in /etc/default/zaptel
+#
+# Manual Run
+# ##########
+#
+# path/to/xpp_fxloader load
+#
+# Make sure the firmware files are in $FIRMWARE_DIR
+#
+# UDEV Installation
+# #################
+#
+# Copy xpp.rules to /etc/udev/udev.d and xpp_fxloader to /etc/hotplug/usb/ .
+#
+# Hotplug Installation
+# ####################
+#
+# Copy this file and the file xpp_fxloader.usermap to /etc/hotplug/usb/ .
+#
+#
+# Written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+# Copyright (C) 2006, Xorcom
+#
+# 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.
+
+set -e
+
+# Make sure fxload is in the path:
+PATH="$PATH:/usr/local/sbin:/sbin:/usr/sbin"
+export PATH
+
+me=`basename $0`
+DEBIAN_DEFAULTS="/etc/default/zaptel"
+REDHAT_DEFAULTS="/etc/sysconfig/zaptel"
+
+status_fd=3
+
+if [ -r "$DEBIAN_DEFAULTS" -a -r "$REDHAT_DEFAULTS" ]; then
+ echo 1>&2 "$0: Both '$DEBIAN_DEFAULTS' and '$REDHAT_DEFAULTS' exist"
+ exit 1
+elif [ -r "$DEBIAN_DEFAULTS" ]; then
+ DEFAULTS="$DEBIAN_DEFAULTS"
+elif [ -r "$REDHAT_DEFAULTS" ]; then
+ DEFAULTS="$REDHAT_DEFAULTS"
+fi
+
+if [ -t 2 ]; then
+ LOGGER="logger -i -t '$me' -s"
+else
+ LOGGER="logger -i -t '$me'"
+fi
+
+USBFS_PREFIX=/proc/bus/usb
+DEVUSB_PREFIX=/dev/bus/usb
+USB_PREFIX=
+
+FIRMWARE_DIR="${FIRMWARE_DIR:-/usr/share/zaptel}"
+
+FIRM_FXS=$FIRMWARE_DIR/FPGA_FXS.hex
+
+FPGA_LOAD=${FPGA_LOAD:-/usr/sbin/fpga_load}
+USB_FW="${USB_FW:-USB_FW.hex}"
+
+if [ -r "$DEFAULTS" ]; then
+ . "$DEFAULTS"
+fi
+
+if [ "$USB_PREFIX" = '' ]; then
+ if [ -d "$DEVUSB_PREFIX" ]; then
+ USB_PREFIX=$DEVUSB_PREFIX
+ elif [ -r "$USBFS_PREFIX/devices" ]; then
+ USB_PREFIX=$USBFS_PREFIX
+ fi
+fi
+
+# With Kernels older that 2.6.10 it seems to be possible
+# to trigger a race condition by running fxload or fpga_load
+# immediately after the detection of the device.
+KERNEL_HAS_USB_RACE=0
+case "`uname -r`" in 2.6.[89]*) KERNEL_HAS_USB_RACE=1;; esac
+sleep_if_race() {
+ if [ "$KERNEL_HAS_USB_RACE" = '1' ]; then
+ sleep 2
+ fi
+}
+
+find_dev() {
+ v_id=$1
+ p_id=$2
+
+ lsusb | tr -d : | awk "/ ID $v_id$p_id/{printf \"$USB_PREFIX/%s/%s \",\$2,\$4}"
+}
+
+do_fxload() {
+ sleep_if_race
+ ( fxload -t fx2 $* 2>&1 1>/dev/null || exit 1 ) | $LOGGER
+}
+
+load_fw() {
+ v_id=$1
+ p_id=$2
+ fw=$3
+
+ devices=`find_dev $v_id $p_id`
+ for dev in $devices
+ do
+ $LOGGER "USB Firmware $FIRMWARE_DIR/$fw into $dev"
+ do_fxload -D $dev -I $FIRMWARE_DIR/$fw || exit 1
+ done
+}
+
+load_fpga() {
+ v_id=$1
+ p_id=$2
+ fw=$3
+
+ devices=`find_dev $v_id $p_id`
+ for dev in $devices
+ do
+ (
+ card_ver=`$FPGA_LOAD -g -D $dev | sed -n 's/^.*Release: *//'`
+
+ $LOGGER "FPGA Firmware into $dev"
+ sleep_if_race
+ (
+ $FPGA_LOAD -D "$dev" -I "$FIRMWARE_DIR/$fw" -i
+ echo $? >$status_fd
+ )>| $LOGGER
+ status=`cat <$status_fd`
+ if [ "$status" != 0 ]; then
+ echo "fpga_load failed with status $status" | $LOGGER
+ exit 77
+ fi
+ ) &
+ sleep 0.4
+ done
+ wait
+}
+
+numdevs() {
+ v_ids="$1"
+ p_ids="$2"
+
+ for v in $v_ids
+ do
+ (
+ for p in $p_ids
+ do
+ find_dev $v $p
+ done
+ )
+ done | wc -w
+}
+
+wait_renumeration() {
+ num="$1"
+ v_ids="$2"
+ p_ids="$3"
+
+ while
+ n=`numdevs "$v_ids" "$p_ids"`
+ [ "$num" -gt "$n" ]
+ do
+ echo -n "."
+ sleep 1
+ done
+ echo "Got all $num devices"
+}
+
+reset_fpga() {
+ totaldevs=`numdevs e4e4 '11[3456][012]'`
+ devices=`find_dev e4e4 '11[3456][12]'`
+ echo "Reseting devices [$totaldevs devices]"
+ for dev in $devices
+ do
+ $LOGGER "Resetting FPGA Firmware on $dev"
+ sleep_if_race
+ $FPGA_LOAD -D "$dev" -r 2>&1 >/dev/null | $LOGGER
+ status=$PIPESTATUS
+ if [ "$status" != 0 ]; then
+ echo "fpga_load failed removing with status $status" | $LOGGER
+ exit 78
+ fi
+ done
+ if [ "$1" = 'wait' ]; then
+ wait_renumeration $totaldevs e4e4 '11[3456]0'
+ fi
+}
+
+#########################
+##
+## Manual run
+##
+
+# to run manually, pass the parameter 'xppdetect'
+case "$1" in
+udev)
+ # the following emulate hotplug's environment from udev's environment:
+ DEVICE="$DEVNAME"
+ PRODUCT="$2"
+ # skip on to the rest of the script. Don't exit.
+ ;;
+reset-wait)
+ reset_fpga wait
+ ;;
+reset)
+ reset_fpga
+ ;;
+xppdetect|load|usb)
+ numdevs=`numdevs e4e4 '11[3456][01]'`
+ echo "--------- FIRMWARE LOADING: ($1) [$numdevs devices]"
+
+ load_fw e4e4 1130 $USB_FW
+ load_fw e4e4 1140 $USB_FW
+ load_fw e4e4 1150 $USB_FW
+ load_fw e4e4 1160 $USB_FW
+ wait_renumeration $numdevs e4e4 '11[3456]1'
+ if [ "$1" != 'usb' ]
+ then
+ load_fpga e4e4 1131 FPGA_FXS.hex
+ load_fpga e4e4 1141 FPGA_1141.hex
+ load_fpga e4e4 1151 FPGA_1151.hex
+ load_fpga e4e4 1161 FPGA_1161.hex
+ wait_renumeration $numdevs e4e4 '11[3456]2'
+ fi
+
+ sleep 3 # Let it stabilize
+ echo "--------- FIRMWARE IS LOADED"
+ exit 0
+ ;;
+help)
+ echo "$0: Astribank firmware loading script."
+ echo "Usage: "
+ echo "$0 load : manual firmware loading."
+ echo "$0 usb : manual firmware loading: USB firmware only."
+ echo "$0 help : this text."
+ echo ""
+ echo "('xppdetect' is an alias of 'load')"
+ exit 0
+ ;;
+esac
+
+#########################
+##
+## Hotplug run
+##
+
+# allow disabling automatic hotplugging:
+if [ "$XPP_HOTPLUG_DISABLED" != '' ]; then
+ $LOGGER -p kern.info "Exiting... XPP_HOTPLUG_DISABLED"
+ exit 0
+fi
+
+if [ "$ACTION" = "add" ] && [ -w "$DEVICE" ]
+then
+ $LOGGER "Trying to find what to do for product $PRODUCT, device $DEVICE"
+ prod_id=`echo "$PRODUCT" | cut -d/ -f2`
+ case "$PRODUCT" in
+ e4e4/11[345]0/*)
+ FIRM_USB="$FIRMWARE_DIR/$USB_FW"
+ $LOGGER "Loading firmware '$FIRM_USB' into '$DEVICE'"
+ do_fxload -D "$DEVICE" -I "$FIRM_USB"
+ ;;
+ e4e4/11[345]1/*)
+ if [ "$prod_id" = 1131 ]; then
+ FIRM_FPGA="$FIRMWARE_DIR/FPGA_FXS.hex" # Legacy
+ else
+ FIRM_FPGA="$FIRMWARE_DIR/FPGA_$prod_id.hex"
+ fi
+ sleep_if_race
+ $FPGA_LOAD -D "$DEVICE" -I "$FIRM_FPGA" 2>&1 >/dev/null | $LOGGER
+ ;;
+ esac
+fi
diff --git a/drivers/dahdi/xpp/utils/xpp_fxloader.usermap b/drivers/dahdi/xpp/utils/xpp_fxloader.usermap
new file mode 100644
index 0000000..8c14b72
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/xpp_fxloader.usermap
@@ -0,0 +1,10 @@
+# module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info
+xpp_fxloader 0x0003 0x04b4 0x8613 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
+xpp_fxloader 0x0003 0xe4e4 0x1130 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
+xpp_fxloader 0x0003 0xe4e4 0x1131 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
+xpp_fxloader 0x0003 0xe4e4 0x1140 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
+xpp_fxloader 0x0003 0xe4e4 0x1141 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
+xpp_fxloader 0x0003 0xe4e4 0x1150 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
+xpp_fxloader 0x0003 0xe4e4 0x1151 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
+xpp_fxloader 0x0003 0xe4e4 0x1160 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
+xpp_fxloader 0x0003 0xe4e4 0x1161 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
diff --git a/drivers/dahdi/xpp/utils/xpp_modprobe b/drivers/dahdi/xpp/utils/xpp_modprobe
new file mode 100644
index 0000000..e3bacc2
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/xpp_modprobe
@@ -0,0 +1,10 @@
+# Some debugging options for the brave of heart:
+#options zaptel debug=1
+#options wcfxo debug=1
+#options xpp debug=1
+#options xpp_usb debug=1
+#options xpd_fxs debug=1
+#options xpd_fxo debug=1
+
+# For pre-loading of card modules (e.g: xpp_fxs)
+#install xpp_usb /sbin/modprobe xpd_fxs && /sbin/modprobe --ignore-install xpp_usb
diff --git a/drivers/dahdi/xpp/utils/xpp_sync b/drivers/dahdi/xpp/utils/xpp_sync
new file mode 100755
index 0000000..1438f50
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/xpp_sync
@@ -0,0 +1,226 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
+
+use Zaptel::Xpp;
+use Zaptel::Xpp::Xbus;
+
+my $sync;
+my $autoselect;
+
+sub usage() {
+ print
+ "$0: show / set Astribank sync source\n".
+ "\n".
+ "Usage: $0 Show sync source.\n".
+ " $0 <auto|NN|zaptel> Set sync source.\n".
+ "";
+}
+
+if(@ARGV == 1) {
+ if ($ARGV[0] =~ /^(-h|--help|help)$/) {
+ usage;
+ exit(0);
+ }
+ $sync = shift;
+ $autoselect = 1 if $sync =~ /^auto$/i;
+}
+
+
+sub get_sorted_xpds() {
+ my @good_xpds;
+
+ foreach my $xbus (Zaptel::Xpp::xbuses('SORT_CONNECTOR')) {
+ next unless $xbus->status eq 'CONNECTED';
+ foreach my $xpd ($xbus->xpds()) {
+ my $isreg = $xpd->zt_registration();
+ if(!defined($isreg)) { # Failure
+ printf STDERR "%s: Failed %s\n", $xpd->fqn, $!;
+ next;
+ }
+ next unless $isreg; # Skip unregistered XPDs
+ push(@good_xpds, $xpd);
+ }
+ }
+ my @pri_nt_xpds = grep { $_->type =~ /(E1|T1|J1)_NT/; } @good_xpds;
+ my @pri_te_xpds = grep { $_->type =~ /(E1|T1|J1)_TE/; } @good_xpds;
+ my @bri_nt_xpds = grep { $_->type eq 'BRI_NT'; } @good_xpds;
+ my @bri_te_xpds = grep { $_->type eq 'BRI_TE'; } @good_xpds;
+ my @fxo_xpds = grep { $_->type eq 'FXO'; } @good_xpds;
+ my @fxs_xpds = grep { $_->type eq 'FXS'; } @good_xpds;
+
+ # Sync Priority
+ return
+ @pri_nt_xpds,
+ @bri_nt_xpds,
+ @fxo_xpds,
+ @pri_te_xpds,
+ @bri_te_xpds,
+ @fxs_xpds;
+}
+
+sub do_select(@) {
+ my $found;
+
+ foreach my $xpd (@_) {
+ my $xbus = $xpd->xbus;
+ my $busnum = $xbus->name;
+ die "Uknown bus name" unless $busnum;
+ $busnum =~ s/XBUS-//;
+ die "bad bus name" unless $busnum =~ /^\d+$/;
+ #printf "Setting sync: %-10s (%s)\n", $xpd->fqn, $xpd->type;
+ if(Zaptel::Xpp::sync($busnum)) {
+ #print "SET $busnum\n";
+ $found = 1;
+ last;
+ } else {
+ print STDERR "Failed to set $busnum: $!\n";
+ }
+ }
+}
+
+sub do_set($) {
+ my $sync = shift;
+ die "Failed to set sync to '$sync'" unless Zaptel::Xpp::sync($sync);
+}
+
+sub unique_xbus(@) {
+ my %seen;
+
+ grep { !$seen{$_->xbus}++; } @_;
+}
+
+my $curr_sync = Zaptel::Xpp::sync;
+my @sync_xpds = unique_xbus(get_sorted_xpds());
+
+sub show_sync() {
+ foreach my $xpd (@sync_xpds) {
+ my $xbus = $xpd->xbus;
+ my $xpdstr = '[ ' . $xbus->pretty_xpds . ' ]';
+ my $label = '[' . $xbus->label() . ']';
+ my $connector = '(' . $xbus->connector . ')';
+ my $mark = ($curr_sync =~ /\d+/ and $xbus->num == $curr_sync)?"+":"";
+ my $padding = ' ' x (40 - length $xpdstr);
+ printf " %1s %s %-25s %-14s %s\n", $mark, $xbus->name, $connector, $label, $xpdstr;
+ }
+}
+
+sub check_fxo_host_sync() {
+ my @host_synced_xpds = grep { $_->xbus->num() ne $curr_sync } @sync_xpds;
+ my @host_synced_fxos = grep($_->type eq 'FXO', @host_synced_xpds);
+ if(@host_synced_fxos) {
+ my @bad_xbus = map { $_->xbus } unique_xbus(@host_synced_fxos);
+ our $lines = join("\n\t", map { $_->name } @bad_xbus);
+ print STDERR <<"END";
+==================================================
+WARNING: FXO which is not the syncer cause bad PCM
+ Affected Astribanks are:
+--------------------------------------------------
+ $lines
+==================================================
+END
+ }
+}
+
+if($sync) {
+ if($autoselect) {
+ do_select(@sync_xpds);
+ } else {
+ $sync = uc($sync);
+ do_set($sync);
+ }
+ $curr_sync = Zaptel::Xpp::sync;
+ #print "New sync: ", Zaptel::Xpp::sync, "\n";
+} else {
+ print "Current sync: ", $curr_sync, "\n";
+ print "Best Available Syncers:\n";
+ show_sync;
+ check_fxo_host_sync;
+}
+
+__END__
+
+=head1 NAME
+
+xpp_sync - Handle sync selection of Xorcom Astribanks.
+
+=head1 SYNOPSIS
+
+xpp_sync [auto|zaptel|nn]
+
+=head1 DESCRIPTION
+
+On a normal operation one Astribank device provides timing for all the
+other Astribank devices.
+
+When run without parameters, xpp_sync will display a list of Astribanks
+(xbuses) that are connected and registered as Zaptel spans. The current
+xpp sync master will be marked.
+
+If you this an Astribank is connected and yet it does not appear on the
+output of xpp_sync, it may be unregistered. Try running zt_registration .
+
+=head2 Parameters
+
+=over
+
+=item auto
+
+Automatically selects the best Astribank for syncing.
+
+=item zaptel
+
+Gets synchronization from the Zaptel sync master.
+
+=item nn
+
+Sets XBUS-I<nn> as sync source.
+
+=back
+
+(Parameter name is case-insensitive)
+
+=head2 Example output:
+
+ Setting SYNC
+ Current sync: 01
+ Best Available Syncers:
+ + XBUS-01 (usb-0000:00:10.4-3) [usb:12345678] [ PRI_TE PRI_NT PRI_TE PRI_NT ]
+ XBUS-00 (usb-0000:00:10.4-2) [usb:QA-01] [ FXS FXO ]
+ ==================================================
+ WARNING: FXO which is not the syncer cause bad PCM
+ Affected Astribanks are:
+ --------------------------------------------------
+ XBUS-00
+ ==================================================
+
+In this example we see that the recommended xpp sync master is XBUS-02 -
+it is the first on the list. It is also the actual syncer, as we can see
+from the '+' beside it.
+
+xpp_sync is normally called from both the zaptel init.d script and the
+the Astribank udev script. The parameter it is called with defaults to
+I<auto>, but it is possible to override that parameter (e.g: set it to
+I<zaptel>) through the value of XPP_SYNC in either /etc/defualt/zaptel
+or /etc/sysconfig/zaptel .
+
+=head1 FILES
+
+=over
+
+=item /proc/xpp/sync
+
+xpp_sync is essentially a nicer interface to /proc/xpp/sync . That file
+shows the current xpp sync master (and in what format you need to write
+to it to set the master).
+
+=back
diff --git a/drivers/dahdi/xpp/utils/xpp_timing b/drivers/dahdi/xpp/utils/xpp_timing
new file mode 100755
index 0000000..f87215c
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/xpp_timing
@@ -0,0 +1,6 @@
+#! /bin/sh
+grep 'DRIFT:' /sys/bus/astribanks/devices/xbus-*/timing | sed \
+ -e 's,/sys/bus/astribanks/devices/,,' \
+ -e 's,/timing:,: ,' \
+ -e 's,DRIFT: ,,' \
+ -e 's/^[^:]*:/\U&/'
diff --git a/drivers/dahdi/xpp/utils/zapconf b/drivers/dahdi/xpp/utils/zapconf
new file mode 100755
index 0000000..7f94f6b
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zapconf
@@ -0,0 +1,603 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
+
+use Zaptel;
+use Zaptel::Xpp;
+use Zaptel::Config::Defaults;
+
+my %default_context = (
+ FXO => 'from-pstn',
+ FXS => 'from-internal',
+ IN => 'astbank-input',
+ OUT => 'astbank-output',
+ BRI_TE => 'from-pstn',
+ BRI_NT => 'from-internal',
+ E1_TE => 'from-pstn',
+ T1_TE => 'from-pstn',
+ J1_TE => 'from-pstn',
+ E1_NT => 'from-internal',
+ T1_NT => 'from-internal',
+ J1_NT => 'from-internal',
+ );
+
+my %default_group = (
+ FXO => 0,
+ FXS => "5",
+ IN => '',
+ OUT => '',
+ BRI_TE => 0,
+ BRI_NT => 6,
+ E1_TE => 0,
+ T1_TE => 0,
+ J1_TE => 0,
+ E1_NT => 6,
+ T1_NT => 6,
+ J1_NT => 6,
+ );
+
+my $fxs_default_start = 'ls';
+
+my %default_zaptel_signalling = (
+ FXO => 'fxsks',
+ FXS => "fxo{fxs_default_start}",
+ IN => "fxo{fxs_default_start}",
+ OUT => "fxo{fxs_default_start}",
+ );
+
+my %default_zapata_signalling = (
+ FXO => 'fxs_ks',
+ FXS => "fxo_{fxs_default_start}",
+ IN => "fxo_{fxs_default_start}",
+ OUT => "fxo_{fxs_default_start}",
+ );
+
+my $base_exten = 4000;
+my $fxs_immediate = 'no';
+my $lc_country = 'us';
+my $loadzone = $lc_country;
+my $defaultzone = $lc_country;
+my $bri_sig_style = 'bri_ptmp';
+my $brint_overlap = 'no';
+
+my %zaptel_default_vars = (
+ base_exten => \$base_exten,
+ fxs_immediate => \$fxs_immediate,
+ fxs_default_start => \$fxs_default_start,
+ lc_country => [
+ \$loadzone,
+ \$defaultzone,
+ ],
+ context_lines => \$default_context{FXO},
+ context_phones => \$default_context{FXS},
+ context_input => \$default_context{IN},
+ context_output => \$default_context{OUT},
+ group_phones => [
+ \$default_group{FXS},
+ \$default_group{IN},
+ \$default_group{OUT},
+ ],
+ group_lines => \$default_group{FXO},
+ ZAPBRI_SIGNALLING => \$bri_sig_style,
+ brint_overlap => \$brint_overlap,
+ );
+
+sub map_zaptel_defaults {
+ my %defaults = @_;
+ foreach my $name (keys %defaults) {
+ my $val = $defaults{$name};
+ my $ref = $zaptel_default_vars{$name};
+ my $type = ref $ref;
+ my @vars = ();
+ # Some broken shells (msh) export even variables
+ # That where not defined. Work around that.
+ next unless defined $val && $val ne '';
+ if($type eq 'SCALAR') {
+ @vars = ($ref);
+ } elsif($type eq 'ARRAY') {
+ @vars = @$ref;
+ } else {
+ die "$0: Don't know how to map '$name' (type=$type)\n";
+ }
+ foreach my $v (@vars) {
+ $$v = $val;
+ }
+ }
+}
+
+
+my $zapconf_file;
+my $zapatachannels_file;
+my $users_file;
+my $zapataconf_file;
+
+my %files = (
+ zaptel => { file => \$zapconf_file, func => \&gen_zaptelconf },
+ zapata => { file => \$zapatachannels_file, func => \&gen_zapatachannelsconf },
+ users => { file => \$users_file, func => \&gen_usersconf },
+ zapataconf => { file => \$zapataconf_file, func => \&gen_zapataconf },
+);
+
+my @default_files = ("zaptel", "zapata");
+
+my @spans = Zaptel::spans();
+
+sub bchan_range($) {
+ my $span = shift || die;
+ my $first_chan = ($span->chans())[0];
+ my $first_num = $first_chan->num();
+ my $range_start = $first_num;
+ my @range;
+ my $prev = undef;
+
+ die unless $span->is_digital();
+ foreach my $c (@{$span->bchan_list()}) {
+ my $curr = $c + $first_num;
+ if(!defined($prev)) {
+ $prev = $curr;
+ } elsif($curr != $prev + 1) {
+ push(@range, sprintf("%d-%d", $range_start, $prev));
+ $range_start = $curr;
+ }
+ $prev = $curr;
+ }
+ if($prev >= $first_num) {
+ push(@range, sprintf("%d-%d", $range_start, $prev));
+ }
+ return join(',', @range);
+}
+
+sub gen_zaptel_signalling($) {
+ my $chan = shift || die;
+ my $type = $chan->type;
+ my $num = $chan->num;
+
+ die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
+ if($type eq 'EMPTY') {
+ printf "# channel %d, %s, no module.\n", $num, $chan->fqn;
+ return;
+ }
+ my $sig = $default_zaptel_signalling{$type} || die "unknown default zaptel signalling for chan $chan type $type";
+ if ($type eq 'IN') {
+ printf "# astbanktype: input\n";
+ } elsif ($type eq 'OUT') {
+ printf "# astbanktype: output\n";
+ }
+ printf "$sig=$num\n";
+}
+
+my $bri_te_last_timing = 1;
+
+sub gen_zaptel_digital($) {
+ my $span = shift || die;
+ my $num = $span->num() || die;
+ die "Span #$num is analog" unless $span->is_digital();
+ my $termtype = $span->termtype() || die "$0: Span #$num -- unkown termtype [NT/TE]\n";
+ my $timing;
+ my $lbo = 0;
+ my $framing = $span->framing() || die "$0: No framing information for span #$num\n";
+ my $coding = $span->coding() || die "$0: No coding information for span #$num\n";
+ my $span_crc4 = $span->crc4();
+ $span_crc4 = (defined $span_crc4) ? ",$span_crc4" : '';
+ my $span_yellow = $span->yellow();
+ $span_yellow = (defined $span_yellow) ? ",$span_yellow" : '';
+
+ $timing = ($termtype eq 'NT') ? 0 : $bri_te_last_timing++;
+ printf "span=%d,%d,%d,%s,%s%s%s\n",
+ $num,
+ $timing,
+ $lbo,
+ $framing,
+ $coding,
+ $span_crc4,
+ $span_yellow;
+ printf "# termtype: %s\n", lc($termtype);
+ printf "bchan=%s\n", bchan_range($span);
+ my $dchan = $span->dchan();
+ printf "dchan=%d\n", $dchan->num();
+}
+
+sub gen_zaptelconf($) {
+ my $file = shift || die;
+ rename "$file", "$file.bak"
+ or $! == 2 # ENOENT (No dependency on Errno.pm)
+ or die "Failed to backup old config: $!\n";
+ open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+ my $old = select F;
+ printf "# Autogenerated by %s on %s -- do not hand edit\n", $0, scalar(localtime);
+ print <<"HEAD";
+# Zaptel Configuration File
+#
+# This file is parsed by the Zaptel Configurator, ztcfg
+#
+HEAD
+ foreach my $span (@spans) {
+ printf "# Span %d: %s %s\n", $span->num, $span->name, $span->description;
+ if($span->is_digital()) {
+ gen_zaptel_digital($span);
+ } else {
+ foreach my $chan ($span->chans()) {
+ if(1 || !defined $chan->type) {
+ my $type = $chan->probe_type;
+ my $num = $chan->num;
+ die "Failed probing type for channel $num"
+ unless defined $type;
+ $chan->type($type);
+ }
+ gen_zaptel_signalling($chan);
+ }
+ }
+ print "\n";
+ }
+ print <<"TAIL";
+# Global data
+
+loadzone = $loadzone
+defaultzone = $defaultzone
+TAIL
+ close F;
+ select $old;
+}
+
+my %DefaultConfigs = (
+ context => 'default',
+ group => '63', # FIXME: should not be needed.
+ overlapdial => 'no',
+ busydetect => 'no',
+ rxgain => 0,
+ txgain => 0,
+);
+
+sub reset_zapata_values {
+ foreach my $arg (@_) {
+ if (exists $DefaultConfigs{$arg}) {
+ print "$arg = $DefaultConfigs{$arg}\n";
+ } else {
+ print "$arg =\n";
+ }
+ }
+}
+
+sub gen_zapata_digital($) {
+ my $span = shift || die;
+ my $num = $span->num() || die;
+ die "Span #$num is analog" unless $span->is_digital();
+ my $type = $span->type() || die "$0: Span #$num -- unkown type\n";
+ my $termtype = $span->termtype() || die "$0: Span #$num -- unkown termtype [NT/TE]\n";
+ my $group = $default_group{"$type"};
+ my $context = $default_context{"$type"};
+ my @to_reset = qw/context group/;
+
+ die "$0: missing default group (termtype=$termtype)\n" unless defined($group);
+ die "$0: missing default context\n" unless $context;
+
+ my $sig = $span->signalling || die "missing signalling info for span #$num type $type";
+ grep($bri_sig_style eq $_, 'bri', 'bri_ptmp', 'pri') or die "unknown signalling style for BRI";
+ if($span->is_bri() and $bri_sig_style eq 'bri_ptmp') {
+ $sig .= '_ptmp';
+ }
+ if ($span->is_bri() && $termtype eq 'NT' && $brint_overlap eq 'yes') {
+ print "overlapdial = yes\n";
+ push(@to_reset, qw/overlapdial/);
+ }
+
+ $group .= "," . (10 + $num); # Invent unique group per span
+ printf "group=$group\n";
+ printf "context=$context\n";
+ printf "switchtype = %s\n", $span->switchtype;
+ printf "signalling = %s\n", $sig;
+ printf "channel => %s\n", bchan_range($span);
+ reset_zapata_values(@to_reset);
+}
+
+sub gen_zapata_channel($) {
+ my $chan = shift || die;
+ my $type = $chan->type;
+ my $num = $chan->num;
+ die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
+ my $exten = $base_exten + $num;
+ my $sig = $default_zapata_signalling{$type};
+ my $context = $default_context{$type};
+ my $group = $default_group{$type};
+ my $callerid;
+ my $immediate;
+
+ return if $type eq 'EMPTY';
+ die "missing default_zapata_signalling for chan #$num type $type" unless $sig;
+ $callerid = ($type eq 'FXO')
+ ? 'asreceived'
+ : sprintf "\"Channel %d\" <%04d>", $num, $exten;
+ if($type eq 'IN') {
+ $immediate = 'yes';
+ }
+ # FIXME: $immediage should not be set for 'OUT' channels, but meanwhile
+ # it's better to be compatible with genzaptelconf
+ $immediate = 'yes' if $fxs_immediate eq 'yes' and $sig =~ /^fxo_/;
+ my $signalling = $chan->signalling;
+ $signalling = " " . $signalling if $signalling;
+ my $info = $chan->info;
+ $info = " " . $info if $info;
+ printf ";;; line=\"%d %s%s%s\"\n", $num, $chan->fqn, $signalling, $info;
+ printf "signalling=$sig\n";
+ printf "callerid=$callerid\n";
+ printf "mailbox=%04d\n", $exten unless $type eq 'FXO';
+ if(defined $group) {
+ printf "group=$group\n";
+ }
+ printf "context=$context\n";
+ printf "immediate=$immediate\n" if defined $immediate;
+ printf "channel => %d\n", $num;
+ # Reset following values to default
+ printf "callerid=\n";
+ printf "mailbox=\n" unless $type eq 'FXO';
+ if(defined $group) {
+ printf "group=\n";
+ }
+ printf "context=default\n";
+ printf "immediate=no\n" if defined $immediate;
+ print "\n";
+}
+
+sub gen_zapatachannelsconf($) {
+ my $file = shift || die;
+ rename "$file", "$file.bak"
+ or $! == 2 # ENOENT (No dependency on Errno.pm)
+ or die "Failed to backup old config: $!\n";
+ open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+ my $old = select F;
+ printf "; Autogenerated by %s on %s -- do not hand edit\n", $0, scalar(localtime);
+ print <<"HEAD";
+; Zaptel Channels Configurations (zapata.conf)
+;
+; This is not intended to be a complete zapata.conf. Rather, it is intended
+; to be #include-d by /etc/zapata.conf that will include the global settings
+;
+
+HEAD
+ foreach my $span (@spans) {
+ printf "; Span %d: %s %s\n", $span->num, $span->name, $span->description;
+ if($span->is_digital()) {
+ gen_zapata_digital($span);
+ } else {
+ foreach my $chan ($span->chans()) {
+ gen_zapata_channel($chan);
+ }
+ }
+ print "\n";
+ }
+ close F;
+ select $old;
+}
+
+sub gen_users_channel($) {
+ my $chan = shift || die;
+ my $type = $chan->type;
+ my $num = $chan->num;
+ die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
+ my $exten = $base_exten + $num;
+ my $sig = $default_zapata_signalling{$type};
+ my $full_name = "$type $num";
+
+ die "missing default_zapata_signalling for chan #$num type $type" unless $sig;
+ print << "EOF";
+[$exten]
+callwaiting = yes
+context = numberplan-custom-1
+fullname = $full_name
+cid_number = $exten
+hasagent = no
+hasdirectory = no
+hasiax = no
+hasmanager = no
+hassip = no
+hasvoicemail = yes
+host = dynamic
+mailbox = $exten
+threewaycalling = yes
+vmsecret = 1234
+secret = 1234
+signalling = $sig
+zapchan = $num
+registeriax = no
+registersip = no
+canreinvite = no
+nat = no
+dtmfmode = rfc2833
+disallow = all
+allow = all
+
+EOF
+}
+
+# generate users.conf . The specific users.conf is strictly oriented
+# towards using with the asterisk-gui .
+#
+# This code could have generated a much simpler and smaller
+# configuration file, had there been minimal level of support for
+# configuration templates in the asterisk configuration rewriting. Right
+# now Asterisk's configuration rewriting simply freaks out in the face
+# of templates: http://bugs.digium.com/11442 .
+sub gen_usersconf($) {
+ my $file = shift || die;
+ rename "$file", "$file.bak"
+ or $! == 2 # ENOENT (No dependency on Errno.pm)
+ or die "Failed to backup old config: $!\n";
+ open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+ my $old = select F;
+ print <<"HEAD";
+;!
+;! Automatically generated configuration file
+;! Filename: @{[basename($file)]} ($file)
+;! Generator: $0
+;! Creation Date: @{[scalar(localtime)]}
+;!
+[general]
+;
+; Full name of a user
+;
+fullname = New User
+;
+; Starting point of allocation of extensions
+;
+userbase = @{[$base_exten+1]}
+;
+; Create voicemail mailbox and use use macro-stdexten
+;
+hasvoicemail = yes
+;
+; Set voicemail mailbox @{[$base_exten+1]} password to 1234
+;
+vmsecret = 1234
+;
+; Create SIP Peer
+;
+hassip = no
+;
+; Create IAX friend
+;
+hasiax = no
+;
+; Create Agent friend
+;
+hasagent = no
+;
+; Create H.323 friend
+;
+;hash323 = yes
+;
+; Create manager entry
+;
+hasmanager = no
+;
+; Remaining options are not specific to users.conf entries but are general.
+;
+callwaiting = yes
+threewaycalling = yes
+callwaitingcallerid = yes
+transfer = yes
+canpark = yes
+cancallforward = yes
+callreturn = yes
+callgroup = 1
+pickupgroup = 1
+localextenlength = @{[length($base_exten)]}
+
+
+HEAD
+ foreach my $span (@spans) {
+ next unless grep { $_ eq $span->type} ( 'FXS', 'IN', 'OUT' );
+ printf "; Span %d: %s %s\n", $span->num, $span->name, $span->description;
+ foreach my $chan ($span->chans()) {
+ gen_users_channel($chan);
+ }
+ print "\n";
+ }
+ close F;
+ select $old;
+}
+
+sub gen_zapataconf($) {
+ my $file = shift || die;
+ open(F, ">>$file") || die "$0: Failed to open $file: $!\n";
+ my $old = select F;
+ foreach my $span (@spans) {
+ next unless $span->type eq 'FXO';
+ my $current_sig = "";
+ for my $chan ($span->chans()) {
+ my $chan_num = $chan->num;
+ if ($default_zapata_signalling{$chan->type} ne $current_sig) {
+ $current_sig = $default_zapata_signalling{$chan->type};
+ print "\nsignalling = $current_sig";
+ print "\nchannel => $chan_num";
+ } else {
+ print ",$chan_num";
+ }
+ }
+ print "\n";
+ }
+ close F;
+ select $old;
+}
+
+sub set_defaults {
+ # Source default files
+ my ($default_file, %source_defaults) =
+ Zaptel::Config::Defaults::source_vars(keys(%zaptel_default_vars));
+ map_zaptel_defaults(%source_defaults);
+ # Fixups
+ foreach my $val (values %default_zaptel_signalling, values %default_zapata_signalling) {
+ $val =~ s/{fxs_default_start}/$fxs_default_start/g;
+ }
+ $zapconf_file = $ENV{ZAPCONF_FILE} || "/etc/zaptel.conf";
+ $zapatachannels_file = $ENV{ZAPATA_FILE} || "/etc/asterisk/zapata-channels.conf";
+ $users_file = $ENV{USERS_FILE} || "/etc/asterisk/users.conf";
+ $zapataconf_file = $ENV{ZAPATACONF_FILE} || "/etc/asterisk/zapata.conf";
+}
+
+sub parse_args {
+ return if @ARGV == 0;
+ @default_files = ();
+ for my $file (@ARGV) {
+ die "$0: Unknown file '$file'" unless defined $files{$file};
+ push @default_files, $file;
+ }
+}
+
+sub generate_files {
+ for my $file (@default_files) {
+ &{$files{$file}->{func}}(${$files{$file}->{file}});
+ }
+}
+set_defaults;
+parse_args;
+generate_files;
+
+__END__
+
+=head1 NAME
+
+zapconf - Generate configuration for zaptel channels.
+
+=head1 SYNOPSIS
+
+zapconf [FILES...]
+
+=head1 DESCRIPTION
+
+This script generate configuration files for Zaptel hardware.
+Currently it can generate three files: zaptel, zapata, users and zapataconf (see below).
+Without arguments, it generates only zaptel and zapata.
+
+=over 4
+
+=item zaptel - /etc/zaptel.conf
+
+Configuration for ztcfg(1). It's location may be overriden by the
+environment variable ZAPCONF_FILE.
+
+=item zapata - /etc/asterisk/zapata-channels.conf
+
+Configuration for asterisk(1). It should be included in the main /etc/asterisk/zapata.conf.
+It's location may be overriden by the environment variable ZAPATA_FILE.
+
+=item users - /etc/asterisk/users.conf
+
+Configuration for asterisk(1) and AsteriskGUI.
+It's location may be overriden by the environment variable USERS_FILE.
+
+=item zapataconf - /etc/asterisk/zapata.conf
+
+Configuration for asterisk(1) and AsteriskGUI.
+It's location may be overriden by the environment variable ZAPATACONF_FILE.
+
+
+=back
diff --git a/drivers/dahdi/xpp/utils/zaptel-helper b/drivers/dahdi/xpp/utils/zaptel-helper
new file mode 100644
index 0000000..1b2ca45
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zaptel-helper
@@ -0,0 +1,401 @@
+#!/bin/sh
+
+# zaptel-helper: helper script/functions for Zaptel
+
+# Wrriten by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+# Copyright (C) 2006-2007, Xorcom
+#
+# 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.
+
+# Should be possible to run with -e set. This is also recommended.
+
+# Constants:
+# maximal time (in seconds) to wait for /dev/zap/dtl to appear after
+# loading zaptel
+DEVZAP_TIMEOUT=${DEVZAP_TIMEOUT:-20}
+
+# Zaptel modules we'll try when detecting zaptel hardware:
+ALL_MODULES="${ALL_MODULES:-zaphfc qozap ztgsm wctdm wctdm24xxp wcfxo wcfxs pciradio tor2 torisa wct1xxp wct4xxp wcte11xp wanpipe wcusb xpp_usb}"
+
+# Where do we write the list of modules we detected (if at all):
+MODLIST_FILE_DEBIAN=${MODLIST_FILE_DEBIAN:-/etc/modules}
+MODLIST_FILE_REDHAT=${MODLIST_FILE_REDHAT:-/etc/sysconfig/zaptel}
+
+# The location of of the fxotune binary
+FXOTUNE="${FXOTUNE:-/usr/sbin/fxotune}"
+FXOTUNE_CONF="${FXOTUNE_CONF:-/etc/fxotune.conf}"
+
+# this is the context FXO zaptel channels are in.
+# See run_fxotune.
+FXO_CONTEXT=${FXO_CONTEXT:-from-pstn}
+
+ZTCFG="${ZTCFG:-/sbin/ztcfg}"
+
+# TODO: this may not be appropriate for a general-purpose script.
+# However you should not use a direct 'echo' to write output to the user
+#, to make it simple to override.
+say() {
+ echo "$@"
+}
+
+error() {
+ echo >&2 "$@"
+}
+
+die() {
+ error "$@"
+ exit 1
+}
+
+
+#############################################################################
+#####
+##### Init helper functions
+#####
+
+
+# Wait for udev to generate /dev/zap/ctl, if needed:
+wait_for_zapctl() {
+ # if device file already exists, or if zaptel has failed to load:
+ # no point waiting.
+ if [ -c /dev/zap/ctl ] || ! grep -q zaptel /proc/modules ; then
+ return
+ fi
+
+ say "Waiting for /dev/zap/ctl to be generated"
+ devzap_found=0
+ for i in `seq $DEVZAP_TIMEOUT`; do
+ sleep 1
+ if [ -c /dev/zap/ctl ]; then
+ devzap_found=1
+ break
+ fi
+ done
+ if [ "$devzap_found" != 1 ]; then
+ say "Still no /dev/zap/ctl after $devzap_timeout seconds."
+ error "No /dev/zap/ctl: cannot run ztcfg. Aborting."
+ fi
+}
+
+# load the fxotune parameters
+# FIXME: /etc/fxotune.conf is a bad location for that file .
+# /etc/zaptel/fxotune.conf?
+fxotune_load() {
+ if [ -x "$FXOTUNE" ] && [ -r "FXOTUNE_CONF" ]; then
+ $FROTUNE -s
+ fi
+}
+
+# If there is no zaptel timing source, load
+# ztdummy. Other modules should have been loaded by
+# now.
+guarantee_timing_source() {
+ if ! head -c 0 /dev/zap/pseudo 2>/dev/null
+ then modprobe ztdummy || true # will fail if there is no module package
+ fi
+}
+
+kill_zaptel_users() {
+ fuser -k /dev/zap/*
+}
+
+# recursively unload a module and its dependencies, if possible.
+# where's modprobe -r when you need it?
+# inputs: module to unload.
+# returns: the result from
+unload_module() {
+ module="$1"
+ line=`lsmod 2>/dev/null | grep "^$1 "`
+ if [ "$line" = '' ]; then return; fi # module was not loaded
+
+ set -- $line
+ # $1: the original module, $2: size, $3: refcount, $4: deps list
+ mods=`echo $4 | tr , ' '`
+ for mod in $mods; do
+ # run in a subshell, so it won't step over our vars:
+ (unload_module $mod)
+ # TODO: the following is probably the error handling we want:
+ # if [ $? != 0 ]; then return 1; fi
+ done
+ rmmod $module
+}
+
+# sleep a while until the xpp modules fully register
+wait_for_xpp() {
+ if [ -d /proc/xpp ]
+ then
+ # wait for the XPDs to register:
+ # TODO: improve error reporting and produce a messagee here
+ cat /proc/xpp/XBUS-*/waitfor_xpds 2>/dev/null >/dev/null || true
+ fi
+}
+
+zap_reg_xpp() {
+ if [ ! -d /proc/xpp ]; then return; fi
+
+ # Get a list of connected Astribank devices, sorted by the name of
+ # the USB connector. That order is rather arbitrary, but will not
+ # change without changes to the cabling.
+ xbusses=`sort -k 2 /proc/xpp/xbuses | awk -F: '/STATUS=connected/ {print $1}'`
+
+ # get a list of XPDs that were not yet registered as zaptel spans.
+ # this will be the case if you set the parameter zap_autoreg=0 to
+ # the module xpp
+ # Append /dev/null to provide a valid file name in case of an empty pattern.
+ xbusses_pattern=`echo $xbusses| sed -e 's|XBUS-[0-9]*|/proc/xpp/&/XPD-*/zt_registration|g'`' /dev/null'
+ xpds_to_register=`grep -l 0 $xbusses_pattern 2>/dev/null` || true
+ for file in $xpds_to_register; do
+ echo 1 >$file
+ done
+}
+
+# Set the sync source of the Astribank to the right value
+fix_asterisbank_sync() {
+ # do nothing if module not present
+ if [ ! -d /proc/xpp ]; then return; fi
+
+ #if ! grep -q '^HOST' /proc/xpp/sync 2>/dev/null; then return; fi
+
+ case "$XPP_SYNC" in
+ n*|N*) return;;
+ host|HOST) sync_value="HOST";;
+ [0-9]*)sync_value="$XPP_SYNC";;
+ *)
+ # find the number of the first bus, and sync from it:
+ fxo_pat=`awk -F: '/STATUS=connected/{print $1}' /proc/xpp/xbuses | sed -e 's|.*|/proc/xpp/&/*/fxo_info|'`
+ # find the first FXO unit, and set it as the sync master
+ bus=`ls -1 $fxo_pat 2> /dev/null | head -n1 | cut -d- -f2 | cut -d/ -f1`
+
+ # do nothing if there is no bus:
+ case "$bus" in [0-9]*):;; *) return;; esac
+ sync_value="$bus 0"
+ ;;
+ esac
+ # the built-in echo of bash fails to print a proper error on failure
+ if ! /bin/echo "$sync_value" >/proc/xpp/sync
+ then
+ error "Updating XPP sync source failed (used XPP_SYNC='$XPP_SYNC')"
+ fi
+}
+
+run_adj_clock() {
+ if [ "$XPP_RUN_ADJ_CLOCK" = '' ]; then return; fi
+
+ # daemonize adj_clock:
+ (adj_clock </dev/null >/dev/null 2>&1 &)&
+}
+
+init_astribank() {
+ wait_for_xpp
+ zap_reg_xpp
+ fix_asterisbank_sync
+ run_adj_clock
+}
+
+xpp_do_blink() {
+ val="$1"
+ shift
+ for xbus in $*
+ do
+ for xpd in /proc/xpp/XBUS-"$xbus"/XPD-*
+ do
+ echo "$val" > "$xpd/blink"
+ done
+ done
+}
+
+xpp_blink() {
+ xbuses=`grep STATUS=connected /proc/xpp/xbuses | sed -e 's/^XBUS-//' -e 's/:.*$//'`
+ num=`echo $1 | tr -c -d 0-9`
+ case "$num" in
+ [0-9]*)
+ shift
+ xpp_do_blink 1 $xbuses
+ sleep 2
+ xpp_do_blink 0 $xbuses
+ ;;
+ *)
+ shift
+ echo 1>&2 Enumerating $xbuses
+ xpp_do_blink 0 $xbuses
+ for i in $xbuses
+ do
+ echo "BLINKING: $i"
+ xpp_do_blink 1 "$i"
+ sleep 2
+ xpp_do_blink 0 "$i"
+ done
+ ;;
+ esac
+}
+
+# The current Debian start function.
+# The function is not responsible for loading the zaptel modules:
+# they will be loaded beforehand.
+debian_start() {
+ wait_for_xpp
+ zap_reg_xpp
+ fix_asterisbank_sync
+ wait_for_zapctl
+
+ if [ -r /etc/fxotune.conf ] && [ -x $FXOTUNE ]; then
+ $FXOTUNE -s
+ fi
+
+ # configure existing modules:
+ $ZTCFG
+}
+
+
+# run_fxotune: destroy all FXO channels and run fxotune.
+# This allows running fxotune without completly shutting down Asterisk.
+#
+# A simplistic assumption: every zaptel channel in the context from-pstn
+# is a FXO ones.
+# or rather: all tunable FXO channels are in the context from-pstn are
+# not defined by zaptel.
+run_fxotune() {
+ zap_fxo_chans=`asterisk -rx "zap show channels" | awk "/$FXO_CONTEXT/{print \$1}"`
+ xpp_fxo_chans=`cat /proc/zaptel/* | awk '/XPP_FXO/{print $1}'`
+ for chan in $xpp_fxo_chans $zap_fxo_chans; do
+ asterisk -rx "zap destroy channel $chan"
+ done
+ $FXOTUNE -i
+ asterisk -rx "zap restart"
+}
+
+
+# recursively unload a module and its dependencies, if possible.
+# where's modprobe -r when you need it?
+# inputs: module to unload.
+unload_module() {
+ set +e
+ module="$1"
+ line=`lsmod 2>/dev/null | grep "^$module "`
+ if [ "$line" = '' ]; then return; fi # module was not loaded
+
+ set -- $line
+ # $1: the original module, $2: size, $3: refcount, $4: deps list
+ mods=`echo $4 | tr , ' '`
+ # xpd_fxs actually sort of depends on xpp:
+ case "$module" in xpd_*) mods="xpp_usb $mods";; esac
+ for mod in $mods; do
+ # run in a subshell, so it won't step over our vars:
+ (unload_module $mod)
+ done
+ rmmod $module || true
+ set -e
+}
+
+unload() {
+ unload_module zaptel
+}
+
+# sleep a while until the xpp modules fully register
+wait_for_xpp() {
+ if [ -d /proc/xpp ] && \
+ [ "`cat /sys/module/xpp/parameters/zap_autoreg`" = 'Y' ]
+ then
+ # wait for the XPDs to register:
+ # TODO: improve error reporting and produce a messagee here
+ cat /proc/xpp/XBUS-*/waitfor_xpds 2>/dev/null >/dev/null || true
+ fi
+}
+
+#############################################################################
+#####
+##### Hardware detection functions
+#####
+
+load_modules() {
+ say "Test Loading modules:"
+ for i in $ALL_MODULES
+ do
+ lines_before=`count_proc_zap_lines`
+ args="${i}_args"
+ eval "args=\$$args"
+ # a module is worth listing if it:
+ # a. loaded successfully, and
+ # b. added channels lines under /proc/zaptel/*
+ if /sbin/modprobe $i $args 2> /dev/null
+ then
+ check=0
+ case "$i" in
+ xpp_usb) check=`grep 'STATUS=connected' 2>/dev/null /proc/xpp/xbuses | wc -l` ;;
+ # FIXME: zttranscode will always load, and will never
+ # add a span. Maybe try to read from /dev/zap/transcode .
+ zttranscode) : ;;
+ *) if [ $lines_before -lt `count_proc_zap_lines` ]; then check=1; fi ;;
+ esac
+ if [ "$check" != 0 ]
+ then
+ probed_modules="$probed_modules $i"
+ say " ok $i $args"
+ else
+ say " - $i $args"
+ rmmod $i
+ fi
+ else
+ say " - $i $args"
+ fi
+ done
+}
+
+update_module_list_debian() {
+ say "Updating Debian modules list $MODLIST_FILE_DEBIAN."
+ del_args=`for i in $ALL_MODULES ztdummy
+ do
+ echo "$i" | sed s:.\*:-e\ '/^&/d':
+ done`
+ add_args=`for i in $*
+ do
+ echo "$i" | sed s:.\*:-e\ '\$a&':
+ done`
+
+ sed -i.bak $del_args "$MODLIST_FILE_DEBIAN"
+ for i in $*
+ do
+ echo "$i"
+ done >> "$MODLIST_FILE_DEBIAN"
+}
+
+update_module_list_redhat() {
+ say "Updating modules list in zaptel init config $MODLIST_FILE_REDHAT."
+ sed -i.bak -e '/^MODULES=/d' "$MODLIST_FILE_REDHAT"
+ echo "MODULES=\"$*\"" >> "$MODLIST_FILE_REDHAT"
+}
+
+update_module_list() {
+ if [ -f "$MODLIST_FILE_DEBIAN" ]; then
+ update_module_list_debian "$@"
+ elif [ -f "$MODLIST_FILE_REDHAT" ]; then
+ update_module_list_redhat "$@"
+ else
+ die "Can't find a modules list to update. Tried: $MODLIST_FILE_DEBIAN, $MODLIST_FILE_REDHAT. Aborting"
+ fi
+}
+
+
+
+
+
+
+# unless we wanted to use this as a set of functions, run
+# the given function with its parameters:
+if [ "$ZAPHELPER_ONLY_INCLUDE" = '' ]; then
+ "$@"
+fi
diff --git a/drivers/dahdi/xpp/utils/zaptel_drivers b/drivers/dahdi/xpp/utils/zaptel_drivers
new file mode 100755
index 0000000..d7904c0
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zaptel_drivers
@@ -0,0 +1,9 @@
+#! /usr/bin/perl -w
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
+
+use Zaptel::Hardware;
+
+my $hardware = Zaptel::Hardware->scan;
+print join("\n", $hardware->drivers),"\n";
diff --git a/drivers/dahdi/xpp/utils/zaptel_hardware b/drivers/dahdi/xpp/utils/zaptel_hardware
new file mode 100755
index 0000000..004a44b
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zaptel_hardware
@@ -0,0 +1,164 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+use Getopt::Std;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
+
+use Zaptel;
+use Zaptel::Span;
+use Zaptel::Xpp;
+use Zaptel::Xpp::Xbus;
+use Zaptel::Hardware;
+
+sub usage {
+ die "Usage: $0 [-v][-x]\n";
+}
+
+our ($opt_v, $opt_x);
+getopts('vx') || usage;
+@ARGV == 0 or usage;
+
+my $hardware = Zaptel::Hardware->scan;
+my @spans = Zaptel::spans;
+
+sub show_xbus($) {
+ my $xbus = shift or die;
+ my @xpds = $xbus->xpds;
+ my $label = '[' . $xbus->label() . ']';
+ my $connector = ($xbus->status eq 'CONNECTED') ? $xbus->connector : "MISSING";
+ printf " LABEL=%-20s CONNECTOR=%-20s\n", $label, $connector;
+ foreach my $xpd (@xpds) {
+ my $reg = $xpd->zt_registration;
+ my $span;
+ my $spanstr;
+ if($reg && @spans) {
+ ($span) = grep { $_->name eq $xpd->fqn } @spans;
+ $spanstr = ($span) ? ("Span " . $span->num) : "";
+ } else {
+ $spanstr = "Unregistered";
+ }
+ my $master = '';
+ #$master = "XPP-SYNC" if $xpd->is_sync_master;
+ $master .= " ZAPTEL-SYNC" if defined($span) && $span->is_zaptel_sync_master;
+ printf "\t%-10s: %-8s %s %s\n", $xpd->fqn, $xpd->type, $spanstr, $master;
+ }
+}
+
+my %seen;
+my $format = "%-20s %-12s %4s:%4s %s\n";
+
+sub show_disconnected(%) {
+ my %seen = @_;
+
+ my $notified_lost = 0;
+ foreach my $xbus (Zaptel::Xpp::xbuses('SORT_CONNECTOR')) {
+ if(!$seen{$xbus->name}) {
+ print "----------- XPP Spans with disconnected hardware -----------\n"
+ unless $notified_lost++;
+ printf($format, $xbus->name, '', '', '', "NO HARDWARE");
+ show_xbus($xbus) if $opt_v;
+ }
+ }
+}
+
+foreach my $dev ($hardware->device_list) {
+ my $driver = $dev->driver || "";
+ my $xbus;
+ my $loaded;
+ if($dev->is_astribank) {
+ $xbus = $dev->xbus;
+ }
+ $loaded = $dev->loaded;
+ warn "driver should be '$driver' but is actually '$loaded'\n"
+ if defined($loaded) && $driver ne $loaded;
+ $driver = "$driver" . (($loaded) ? "+" : "-");
+ my $description = $dev->description || "";
+ printf $format, $dev->hardware_name, $driver, $dev->vendor, $dev->product, $description;
+ if(!defined $xbus || !$xbus) {
+ next;
+ }
+ $seen{$xbus->name} = 1;
+ show_xbus($xbus) if $opt_v;
+}
+
+show_disconnected(%seen) if $opt_x;
+
+__END__
+
+=head1 NAME
+
+zaptel_hardware - Shows Zaptel hardware devices.
+
+=head1 SYNOPSIS
+
+zaptel_hardware [-v][-x]
+
+=head1 OPTIONS
+
+=over
+
+=item -v
+
+Verbose ouput - show spans used by each device etc. Currently only
+implemented for the Xorcom Astribank.
+
+=item -x
+
+Show disconnected Astribank unit, if any.
+
+=back
+
+=head1 DESCRIPTION
+
+Show all zaptel hardware devices. Devices are recognized according to
+lists of PCI and USB IDs in Zaptel::Hardware::PCI.pm and
+Zaptel::Hardware::USB.pm . For PCI it is possible to detect by
+sub-vendor and sub-product ID as well.
+
+The first output column is the connector: a bus specific field that
+shows where this device is.
+
+The second field shows which driver should handle the device. a "-" sign
+marks that the device is not yet handled by this driver. A "+" sign
+means that the device is handled by the driver.
+
+For the Xorcom Astribank (and in the future: for other Zaptel devices)
+some further information is provided from the driver. Those extra lines
+always begin with spaces.
+
+Example output:
+
+Without drivers loaded:
+
+ usb:001/002 xpp_usb- e4e4:1152 Astribank-multi FPGA-firmware
+ usb:001/003 xpp_usb- e4e4:1152 Astribank-multi FPGA-firmware
+ pci:0000:01:0b.0 wctdm- e159:0001 Wildcard TDM400P REV H
+
+With drivers loaded, without -v:
+ usb:001/002 xpp_usb+ e4e4:1152 Astribank-multi FPGA-firmware
+ usb:001/003 xpp_usb+ e4e4:1152 Astribank-multi FPGA-firmware
+ pci:0000:01:0b.0 wctdm+ e159:0001 Wildcard TDM400P REV E/F
+
+With drivers loaded, with -v:
+ usb:001/002 xpp_usb+ e4e4:1152 Astribank-multi FPGA-firmware
+ LABEL=[usb:123] CONNECTOR=usb-0000:00:1d.7-1
+ XBUS-00/XPD-00: FXS Span 2
+ XBUS-00/XPD-10: FXS Span 3
+ XBUS-00/XPD-20: FXS Span 4
+ XBUS-00/XPD-30: FXS Span 5
+ usb:001/003 xpp_usb+ e4e4:1152 Astribank-multi FPGA-firmware
+ LABEL=[usb:4567] CONNECTOR=usb-0000:00:1d.7-4
+ XBUS-01/XPD-00: FXS Span 6 XPP-SYNC
+ XBUS-01/XPD-10: FXO Span 7
+ XBUS-01/XPD-20: FXO Span 8
+ XBUS-01/XPD-30: FXO Span 9
+ pci:0000:01:0b.0 wctdm+ e159:0001 Wildcard TDM400P REV E/F
+
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel.pm
new file mode 100644
index 0000000..a7e7d6c
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel.pm
@@ -0,0 +1,68 @@
+package Zaptel;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Zaptel::Span;
+
+=head1 NAME
+
+Zaptel - Perl interface to Zaptel information
+
+This package allows access from Perl to information about Zaptel
+hardware and loaded Zaptel devices.
+
+=head1 SYNOPSIS
+
+ # Listing channels in analog spans:
+ use Zaptel;
+ # scans system:
+ my @xbuses = Zaptel::spans();
+ for my $span (@spans) {
+ next if ($span->is_digital);
+ $span->num. " - [". $span->type ."] ". $span->name. "\n";
+ for my $chan ($span->chans) {
+ print " - ".$chan->num . " - [". $chan->type. "] ". $chan->fqn". \n";
+ }
+ }
+=cut
+
+my $proc_base = "/proc/zaptel";
+
+=head1 spans()
+
+Returns a list of span objects, ordered by span number.
+
+=cut
+
+sub spans() {
+ my @spans;
+
+ -d $proc_base or return ();
+ foreach my $zfile (glob "$proc_base/*") {
+ $zfile =~ s:$proc_base/::;
+ my $span = Zaptel::Span->new($zfile);
+ push(@spans, $span);
+ }
+ @spans = sort { $a->num <=> $b->num } @spans;
+ return @spans;
+}
+
+=head1 SEE ALSO
+
+Span objects: L<Zaptel::Span>.
+
+Zaptel channels objects: L<Zaptel::Chan>.
+
+Zaptel hardware devices information: L<Zaptel::Hardware>.
+
+Xorcom Astribank -specific information: L<Zaptel::Xpp>.
+
+=cut
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel/Chans.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel/Chans.pm
new file mode 100644
index 0000000..6f83f77
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel/Chans.pm
@@ -0,0 +1,202 @@
+package Zaptel::Chans;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Zaptel::Utils;
+
+=head1 NAME
+
+Zaptel::Chans - Perl interface to a Zaptel channel information
+
+This package allows access from perl to information about a Zaptel
+channel. It is part of the Zaptel Perl package.
+
+=head1 battery()
+
+Returns 1 if channel reports to have battery (A remote PBX connected to
+an FXO port), 0 if channel reports to not have battery and C<undef>
+otherwise.
+
+Currently only wcfxo and Astribank FXO modules report battery. For the
+rest of the channels
+
+=head1 fqn()
+
+(Fully Qualified Name) Returns the full "name" of the channel.
+
+=head1 index()
+
+Returns the number of this channel (in the span).
+
+=head1 num()
+
+Returns the number of this channel as a Zaptel channel.
+
+=head signalling()
+
+Returns the signalling set for this channel through /etc/zaptel.conf .
+This is always empty before ztcfg was run. And shows the "other" type
+for FXS and for FXO.
+
+=head1 span()
+
+Returns a reference to the span to which this channel belongs.
+
+=head1 type()
+
+Returns the type of the channel: 'FXS', 'FXO', 'EMPTY', etc.
+
+=cut
+
+sub new($$$$$$) {
+ my $pack = shift or die "Wasn't called as a class method\n";
+ my $span = shift or die "Missing a span parameter\n";
+ my $index = shift;
+ my $line = shift or die "Missing an input line\n";
+ defined $index or die "Missing an index parameter\n";
+ my $self = {
+ 'SPAN' => $span,
+ 'INDEX' => $index,
+ };
+ bless $self, $pack;
+ my ($num, $fqn, $rest) = split(/\s+/, $line, 3);
+ $num or die "Missing a channel number parameter\n";
+ $fqn or die "Missing a channel fqn parameter\n";
+ my $signalling = '';
+ my $info = '';
+ if(defined $rest) {
+ if($rest =~ s/^\s*(\w+)\s*//) {
+ $signalling = $1;
+ }
+ if($rest =~ s/(.*)//) {
+ $info = $1;
+ }
+ }
+ $self->{NUM} = $num;
+ $self->{FQN} = $fqn;
+ $self->{SIGNALLING} = $signalling;
+ $self->{INFO} = $info;
+ my $type;
+ if($fqn =~ m|\bXPP_(\w+)/.*$|) {
+ $type = $1; # An Astribank
+ } elsif ($fqn =~ m{\bWCFXO/.*}) {
+ $type = "FXO"; # wcfxo - x100p and relatives.
+ # A single port card. The driver issue RED alarm when
+ # There's no better
+ $self->{BATTERY} = !($span->description =~ /\bRED\b/);
+ } elsif ($fqn =~ m{\bFXS/.*}) {
+ $type = "FXS"; # likely Rhino
+ } elsif ($fqn =~ m{\bFXO/.*}) {
+ $type = "FXO"; # likely Rhino
+ } elsif ($fqn =~ m{\b---/.*}) {
+ $type = "EMPTY"; # likely Rhino, empty slot.
+ } elsif ($fqn =~ m{\b(TE[24]|WCT1|Tor2|TorISA|WP[TE]1|cwain[12])/.*}) {
+ # TE[24]: Digium wct4xxp
+ # WCT1: Digium single span card drivers?
+ # Tor2: Tor PCI cards
+ # TorISA: ISA ones (still used?)
+ # WP[TE]1: Sangoma. TODO: this one tells us if it is TE or NT.
+ # cwain: Junghanns E1 card.
+ $type = "PRI";
+ } elsif ($fqn =~ m{\b(ZTHFC%d*|ztqoz\d*)/.*}) {
+ # ZTHFC: HFC-s single-port card (zaphfc/vzaphfc)
+ # ztqoz: qozap (Junghanns) multi-port HFC card
+ $type = "BRI";
+ } elsif ($fqn =~ m{\bztgsm/.*}) {
+ # Junghanns GSM card
+ $type = "GSM";
+ } elsif(defined $signalling) {
+ $type = 'FXS' if $signalling =~ /^FXS/;
+ $type = 'FXO' if $signalling =~ /^FXO/;
+ } else {
+ $type = undef;
+ }
+ $self->type($type);
+ $self->span()->type($type)
+ if ! defined($self->span()->type()) ||
+ $self->span()->type() eq 'UNKNOWN';
+ return $self;
+}
+
+=head1 probe_type()
+
+In the case of some cards, the information in /proc/zaptel is not good
+enough to tell the type of each channel. In this case an extra explicit
+probe is needed.
+
+Currently this is implemented by using some invocations of ztcfg(8).
+
+It may later be replaced by ztscan(8).
+
+=cut
+
+my $ztcfg = $ENV{ZTCFG} || '/sbin/ztcfg';
+sub probe_type($) {
+ my $self = shift;
+ my $fqn = $self->fqn;
+ my $num = $self->num;
+ my $type;
+
+ if($fqn =~ m:WCTDM/| WRTDM/|OPVXA1200/:) {
+ my %maybe;
+
+ undef %maybe;
+ foreach my $sig (qw(fxo fxs)) {
+ my $cmd = "echo ${sig}ks=$num | $ztcfg -c /dev/fd/0";
+
+ $maybe{$sig} = system("$cmd >/dev/null 2>&1") == 0;
+ }
+ if($maybe{fxo} and $maybe{fxs}) {
+ $type = 'EMPTY';
+ } elsif($maybe{fxo}) {
+ $type = 'FXS';
+ } elsif($maybe{fxs}) {
+ $type = 'FXO';
+ } else {
+ $type = 'EMPTY';
+ }
+ } else {
+ $type = $self->type;
+ }
+ return $type;
+}
+
+sub battery($) {
+ my $self = shift or die;
+ my $span = $self->span or die;
+
+ return undef unless $self->type eq 'FXO';
+ return $self->{BATTERY} if defined $self->{BATTERY};
+
+ my $xpd = $span->xpd;
+ my $index = $self->index;
+ return undef if !$xpd;
+
+ # It's an XPD (FXO)
+ my @lines = @{$xpd->lines};
+ my $line = $lines[$index];
+ return $line->battery;
+}
+
+sub blink($$) {
+ my $self = shift or die;
+ my $on = shift;
+ my $span = $self->span or die;
+
+ my $xpd = $span->xpd;
+ my $index = $self->index;
+ return undef if !$xpd;
+
+ my @lines = @{$xpd->lines};
+ my $line = $lines[$index];
+ return $line->blink($on);
+}
+
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel/Config/Defaults.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel/Config/Defaults.pm
new file mode 100644
index 0000000..360ca0a
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel/Config/Defaults.pm
@@ -0,0 +1,56 @@
+package Zaptel::Config::Defaults;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+
+# Use the shell to source a file and expand a given list
+# of variables.
+sub do_source($@) {
+ my $file = shift;
+ my @vars = @_;
+ my @output = `env -i sh -ec '. $file; export @vars; for i in @vars; do eval echo \$i=\\\$\$i; done'`;
+ die "$0: Sourcing '$file' exited with $?" if $?;
+ my %vars;
+
+ foreach my $line (@output) {
+ chomp $line;
+ my ($k, $v) = split(/=/, $line, 2);
+ $vars{$k} = $v if grep /^$k$/, @vars;
+ }
+ return %vars;
+}
+
+sub source_vars {
+ my @vars = @_;
+ my $default_file;
+ my %system_files = (
+ "/etc/default/zaptel" => 'Debian and friends',
+ "/etc/sysconfig/zaptel" => 'Red Hat and friends',
+ );
+
+ if(defined $ENV{ZAPTEL_DEFAULTS}) {
+ $default_file = $ENV{ZAPTEL_DEFAULTS};
+ } else {
+ foreach my $f (keys %system_files) {
+ if(-r $f) {
+ if(defined $default_file) {
+ die "An '$f' collides with '$default_file'";
+ }
+ $default_file = $f;
+ }
+ }
+ }
+ if (! $default_file) {
+ return ("", ());
+ }
+ my %vars = Zaptel::Config::Defaults::do_source($default_file, @vars);
+ return ($default_file, %vars);
+}
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware.pm
new file mode 100644
index 0000000..ff7aeea
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware.pm
@@ -0,0 +1,168 @@
+package Zaptel::Hardware;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Zaptel::Hardware::USB;
+use Zaptel::Hardware::PCI;
+
+=head1 NAME
+
+Zaptel::Hardware - Perl interface to a Zaptel devices listing
+
+
+ use Zaptel::Hardware;
+
+ my $hardware = Zaptel::Hardware->scan;
+
+ # mini zaptel_hardware:
+ foreach my $device ($hardware->device_list) {
+ print "Vendor: device->{VENDOR}, Product: $device->{PRODUCT}\n"
+ }
+
+ # let's see if there are devices without loaded drivers, and sugggest
+ # drivers to load:
+ my @to_load = ();
+ foreach my $device ($hardware->device_list) {
+ if (! $device->{LOADED} ) {
+ push @to_load, ($device->${DRIVER});
+ }
+ }
+ if (@to_load) {
+ print "To support the extra devices you probably need to run:\n"
+ print " modprobe ". (join ' ', @to_load). "\n";
+ }
+
+
+This module provides information about available Zaptel devices on the
+system. It identifies devices by (USB/PCI) bus IDs.
+
+
+=head1 Device Attributes
+As usual, object attributes can be used in either upp-case or
+lower-case, or lower-case functions.
+
+=head2 bus_type
+
+'PCI' or 'USB'.
+
+
+=head2 description
+
+A one-line description of the device.
+
+
+=head2 driver
+
+Name of a Zaptel device driver that should handle this device. This is
+based on a pre-made list.
+
+
+=head2 vendor, product, subvendor, subproduct
+
+The PCI and USB vendor ID, product ID, sub-vendor ID and sub-product ID.
+(The standard short lspci and lsusb listings show only vendor and
+product IDs).
+
+
+=head2 loaded
+
+If the device is handled by a module - the name of the module. Else -
+undef.
+
+
+=head2 priv_device_name
+
+A string that shows the "location" of that device on the bus.
+
+
+=head2 is_astribank
+
+True if the device is a Xorcom Astribank (which may provide some extra
+attributes).
+
+=head2 serial
+
+(Astribank-specific attrribute) - the serial number string of the
+Astribank.
+
+=cut
+
+sub device_detected($$) {
+ my $dev = shift || die;
+ my $name = shift || die;
+ die unless defined $dev->{'BUS_TYPE'};
+ $dev->{IS_ASTRIBANK} = 0 unless defined $dev->{'IS_ASTRIBANK'};
+ $dev->{'HARDWARE_NAME'} = $name;
+}
+
+sub device_removed($) {
+ my $dev = shift || die;
+ my $name = $dev->hardware_name;
+ die "Missing zaptel device hardware name" unless $name;
+}
+
+
+=head1 device_list()
+
+Returns a list of the hardware devices on the system.
+
+You must run scan() first for this function to run meaningful output.
+
+=cut
+
+sub device_list($) {
+ my $self = shift || die;
+ my @types = @_;
+ my @list;
+
+ @types = qw(USB PCI) unless @types;
+ foreach my $t (@types) {
+ @list = ( @list, @{$self->{$t}} );
+ }
+ return @list;
+}
+
+
+=head1 drivers()
+
+Returns a list of drivers (currently sorted by name) that are used by
+the devices in the current system (regardless to whether or not they are
+loaded.
+
+=cut
+
+sub drivers($) {
+ my $self = shift || die;
+ my @devs = $self->device_list;
+ my @drvs = map { $_->{DRIVER} } @devs;
+ # Make unique
+ my %drivers;
+ @drivers{@drvs} = 1;
+ return sort keys %drivers;
+}
+
+
+=head1 scan()
+
+Scan the system for Zaptel devices (PCI and USB). Returns nothing but
+must be run to initialize the module.
+
+=cut
+
+sub scan($) {
+ my $pack = shift || die;
+ my $self = {};
+ bless $self, $pack;
+
+ $self->{USB} = [ Zaptel::Hardware::USB->devices ];
+ $self->{PCI} = [ Zaptel::Hardware::PCI->scan_devices ];
+ return $self;
+}
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware/PCI.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware/PCI.pm
new file mode 100644
index 0000000..a63b09f
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware/PCI.pm
@@ -0,0 +1,208 @@
+package Zaptel::Hardware::PCI;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Zaptel::Utils;
+use Zaptel::Hardware;
+
+our @ISA = qw(Zaptel::Hardware);
+
+# Lookup algorithm:
+# First match 'vendor:product/subvendor:subproduct' key
+# Else match 'vendor:product/subvendor' key
+# Else match 'vendor:product' key
+# Else not a zaptel hardware.
+my %pci_ids = (
+ # from wct4xxp
+ '10ee:0314' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE410P/TE405P (1st Gen)' },
+ 'd161:0420/0004' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE420 (4th Gen)' },
+ 'd161:0410/0004' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE410P (4th Gen)' },
+ 'd161:0405/0004' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE405P (4th Gen)' },
+ 'd161:0410/0003' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE410P (3rd Gen)' },
+ 'd161:0405/0003' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE405P (3rd Gen)' },
+ 'd161:0410' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE410P (2nd Gen)' },
+ 'd161:0405' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE405P (2nd Gen)' },
+ 'd161:0220/0004' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE220 (4th Gen)' },
+ 'd161:0205/0004' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE205P (4th Gen)' },
+ 'd161:0210/0004' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE210P (4th Gen)' },
+ 'd161:0205/0003' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE205P (3rd Gen)' },
+ 'd161:0210/0003' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE210P (3rd Gen)' },
+ 'd161:0205' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE205P ' },
+ 'd161:0210' => { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE210P ' },
+
+ # from wctdm24xxp
+ 'd161:2400' => { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard TDM2400P' },
+ 'd161:0800' => { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard TDM800P' },
+ 'd161:8002' => { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard AEX800' },
+ 'd161:8003' => { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard AEX2400' },
+ 'd161:8005' => { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard TDM410P' },
+ 'd161:8006' => { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard AEX410P' },
+
+ # from pciradio
+ 'e159:0001/e16b' => { DRIVER => 'pciradio', DESCRIPTION => 'PCIRADIO' },
+
+ # from wcfxo
+ 'e159:0001/8084' => { DRIVER => 'wcfxo', DESCRIPTION => 'Wildcard X101P clone' },
+ 'e159:0001/8085' => { DRIVER => 'wcfxo', DESCRIPTION => 'Wildcard X101P' },
+ 'e159:0001/8086' => { DRIVER => 'wcfxo', DESCRIPTION => 'Wildcard X101P clone' },
+ 'e159:0001/8087' => { DRIVER => 'wcfxo', DESCRIPTION => 'Wildcard X101P clone' },
+ '1057:5608' => { DRIVER => 'wcfxo', DESCRIPTION => 'Wildcard X100P' },
+
+ # from wct1xxp
+ 'e159:0001/6159' => { DRIVER => 'wct1xxp', DESCRIPTION => 'Digium Wildcard T100P T1/PRI or E100P E1/PRA Board' },
+
+ # from wctdm
+ 'e159:0001/a159' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard S400P Prototype' },
+ 'e159:0001/e159' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard S400P Prototype' },
+ 'e159:0001/b100' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV E/F' },
+ 'e159:0001/b1d9' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV I' },
+ 'e159:0001/b118' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV I' },
+ 'e159:0001/b119' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV I' },
+ 'e159:0001/a9fd' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+ 'e159:0001/a8fd' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+ 'e159:0001/a800' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+ 'e159:0001/a801' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+ 'e159:0001/a908' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+ 'e159:0001/a901' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+ #'e159:0001' => { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+
+ # from wcte11xp
+ 'e159:0001/71fe' => { DRIVER => 'wcte11xp', DESCRIPTION => 'Digium Wildcard TE110P T1/E1 Board' },
+ 'e159:0001/79fe' => { DRIVER => 'wcte11xp', DESCRIPTION => 'Digium Wildcard TE110P T1/E1 Board' },
+ 'e159:0001/795e' => { DRIVER => 'wcte11xp', DESCRIPTION => 'Digium Wildcard TE110P T1/E1 Board' },
+ 'e159:0001/79de' => { DRIVER => 'wcte11xp', DESCRIPTION => 'Digium Wildcard TE110P T1/E1 Board' },
+ 'e159:0001/797e' => { DRIVER => 'wcte11xp', DESCRIPTION => 'Digium Wildcard TE110P T1/E1 Board' },
+
+ # from wcte12xp
+ 'd161:0120' => { DRIVER => 'wcte12xp', DESCRIPTION => 'Wildcard TE12xP' },
+ 'd161:8000' => { DRIVER => 'wcte12xp', DESCRIPTION => 'Wildcard TE121' },
+ 'd161:8001' => { DRIVER => 'wcte12xp', DESCRIPTION => 'Wildcard TE122' },
+
+ # from tor2
+ '10b5:9030' => { DRIVER => 'tor2', DESCRIPTION => 'PLX 9030' },
+ '10b5:3001' => { DRIVER => 'tor2', DESCRIPTION => 'PLX Development Board' },
+ '10b5:D00D' => { DRIVER => 'tor2', DESCRIPTION => 'Tormenta 2 Quad T1/PRI or E1/PRA' },
+ '10b5:4000' => { DRIVER => 'tor2', DESCRIPTION => 'Tormenta 2 Quad T1/E1 (non-Digium clone)' },
+
+ # Cologne Chips:
+ # (Still a partial list)
+ '1397:08b4/b556' => { DRIVER => 'qozap', DESCRIPTION => 'Junghanns DuoBRI ISDN card' },
+ '1397:08b4' => { DRIVER => 'qozap', DESCRIPTION => 'Junghanns QuadBRI ISDN card' },
+ '1397:16b8' => { DRIVER => 'qozap', DESCRIPTION => 'Junghanns OctoBRI ISDN card' },
+ '1397:30b1' => { DRIVER => 'cwain', DESCRIPTION => 'HFC-E1 ISDN E1 card' },
+ '1397:2bd0' => { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+ '1397:f001' => { DRIVER => 'ztgsm', DESCRIPTION => 'HFC-GSM Cologne Chips GSM' },
+
+ # Rhino cards (based on pci.ids)
+ '0b0b:0105' => { DRIVER => 'r1t1', DESCRIPTION => 'Rhino R1T1' },
+ '0b0b:0205' => { DRIVER => 'r4fxo', DESCRIPTION => 'Rhino R14FXO' },
+ '0b0b:0206' => { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino RCB4FXO 4-channel FXO analog telphony card' },
+ '0b0b:0305' => { DRIVER => 'r1t1', DESCRIPTION => 'Rhino R1T1' },
+ '0b0b:0405' => { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino R8FXX' },
+ '0b0b:0406' => { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino RCB8FXX 8-channel modular analog telphony card' },
+ '0b0b:0505' => { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino R24FXX' },
+ '0b0b:0506' => { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino RCB24FXS 24-Channel FXS analog telphony card' },
+ '0b0b:0605' => { DRIVER => 'rxt1', DESCRIPTION => 'Rhino R2T1' },
+ '0b0b:0705' => { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino R24FXS' },
+ '0b0b:0706' => { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino RCB24FXO 24-Channel FXO analog telphony card' },
+ '0b0b:0906' => { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino RCB24FXX 24-channel modular analog telphony card' },
+
+ # Sangoma cards (based on pci.ids)
+ '1923:0040' => { DRIVER => 'wanpipe', DESCRIPTION => 'Sangoma Technologies Corp. A200/Remora FXO/FXS Analog AFT card' },
+ '1923:0100' => { DRIVER => 'wanpipe', DESCRIPTION => 'Sangoma Technologies Corp. A104d QUAD T1/E1 AFT card' },
+ '1923:0300' => { DRIVER => 'wanpipe', DESCRIPTION => 'Sangoma Technologies Corp. A101 single-port T1/E1' },
+ '1923:0400' => { DRIVER => 'wanpipe', DESCRIPTION => 'Sangoma Technologies Corp. A104u Quad T1/E1 AFT' },
+ );
+
+$ENV{PATH} .= ":/usr/sbin:/sbin:/usr/bin:/bin";
+
+sub pci_sorter {
+ return $a->priv_device_name() cmp $b->priv_device_name();
+}
+
+sub new($$) {
+ my $pack = shift or die "Wasn't called as a class method\n";
+ my $self = { @_ };
+ bless $self, $pack;
+ Zaptel::Hardware::device_detected($self,
+ sprintf("pci:%s", $self->{PRIV_DEVICE_NAME}));
+ return $self;
+}
+
+my %pci_devs;
+
+sub readfile($) {
+ my $name = shift || die;
+ open(F, $name) || die "Failed to open '$name': $!";
+ my $str = <F>;
+ close F;
+ chomp($str);
+ return $str;
+}
+
+sub scan_devices($) {
+ my @devices;
+
+ while(</sys/bus/pci/devices/*>) {
+ m,([^/]+)$,,;
+ my $name = $1;
+ my $l = readlink $_ || die;
+ $pci_devs{$name}{PRIV_DEVICE_NAME} = $name;
+ $pci_devs{$name}{DEVICE} = $l;
+ $pci_devs{$name}{VENDOR} = readfile "$_/vendor";
+ $pci_devs{$name}{PRODUCT} = readfile "$_/device";
+ $pci_devs{$name}{SUBVENDOR} = readfile "$_/subsystem_vendor";
+ $pci_devs{$name}{SUBPRODUCT} = readfile "$_/subsystem_device";
+ my $dev = $pci_devs{$name};
+ grep(s/0x//, $dev->{VENDOR}, $dev->{PRODUCT}, $dev->{SUBVENDOR}, $dev->{SUBPRODUCT});
+ $pci_devs{$name}{DRIVER} = '';
+ }
+
+ while(</sys/bus/pci/drivers/*/[0-9]*>) {
+ m,^(.*?)/([^/]+)/([^/]+)$,;
+ my $prefix = $1;
+ my $drvname = $2;
+ my $id = $3;
+ my $l = readlink "$prefix/$drvname/module";
+ # Find the real module name (if we can).
+ if(defined $l) {
+ my $moduledir = "$prefix/$drvname/$l";
+ my $modname = $moduledir;
+ $modname =~ s:^.*/::;
+ $drvname = $modname;
+ }
+ $pci_devs{$id}{LOADED} = $drvname;
+ }
+ foreach (sort keys %pci_devs) {
+ my $dev = $pci_devs{$_};
+ my $key;
+ # Try to match
+ $key = "$dev->{VENDOR}:$dev->{PRODUCT}/$dev->{SUBVENDOR}:$dev->{SUBPRODUCT}";
+ $key = "$dev->{VENDOR}:$dev->{PRODUCT}/$dev->{SUBVENDOR}" if !defined($pci_ids{$key});
+ $key = "$dev->{VENDOR}:$dev->{PRODUCT}" if !defined($pci_ids{$key});
+ next unless defined $pci_ids{$key};
+
+ my $d = Zaptel::Hardware::PCI->new(
+ BUS_TYPE => 'PCI',
+ PRIV_DEVICE_NAME => $dev->{PRIV_DEVICE_NAME},
+ VENDOR => $dev->{VENDOR},
+ PRODUCT => $dev->{PRODUCT},
+ SUBVENDOR => $dev->{SUBVENDOR},
+ SUBPRODUCT => $dev->{SUBPRODUCT},
+ LOADED => $dev->{LOADED},
+ DRIVER => $pci_ids{$key}{DRIVER},
+ DESCRIPTION => $pci_ids{$key}{DESCRIPTION},
+ );
+ push(@devices, $d);
+ }
+ @devices = sort pci_sorter @devices;
+ return @devices;
+}
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware/USB.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware/USB.pm
new file mode 100644
index 0000000..a2dc08f
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel/Hardware/USB.pm
@@ -0,0 +1,116 @@
+package Zaptel::Hardware::USB;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Zaptel::Utils;
+use Zaptel::Hardware;
+use Zaptel::Xpp;
+use Zaptel::Xpp::Xbus;
+
+our @ISA = qw(Zaptel::Hardware);
+
+my %usb_ids = (
+ # from wcusb
+ '06e6:831c' => { DRIVER => 'wcusb', DESCRIPTION => 'Wildcard S100U USB FXS Interface' },
+ '06e6:831e' => { DRIVER => 'wcusb2', DESCRIPTION => 'Wildcard S110U USB FXS Interface' },
+ '06e6:b210' => { DRIVER => 'wc_usb_phone', DESCRIPTION => 'Wildcard Phone Test driver' },
+
+ # from xpp_usb
+ 'e4e4:1130' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-8/16 no-firmware' },
+ 'e4e4:1131' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-8/16 USB-firmware' },
+ 'e4e4:1132' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-8/16 FPGA-firmware' },
+ 'e4e4:1140' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-BRI no-firmware' },
+ 'e4e4:1141' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-BRI USB-firmware' },
+ 'e4e4:1142' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-BRI FPGA-firmware' },
+ 'e4e4:1150' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-multi no-firmware' },
+ 'e4e4:1151' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-multi USB-firmware' },
+ 'e4e4:1152' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-multi FPGA-firmware' },
+ 'e4e4:1160' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-modular no-firmware' },
+ 'e4e4:1161' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-modular USB-firmware' },
+ 'e4e4:1162' => { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-modular FPGA-firmware' },
+ );
+
+
+$ENV{PATH} .= ":/usr/sbin:/sbin:/usr/bin:/bin";
+
+my @xbuses = Zaptel::Xpp::xbuses('SORT_CONNECTOR');
+
+sub usb_sorter() {
+ return $a->hardware_name cmp $b->hardware_name;
+}
+
+sub xbus_of_usb($) {
+ my $priv_device_name = shift;
+ my $dev = shift;
+
+ my ($wanted) = grep {
+ defined($_->usb_devname) &&
+ $priv_device_name eq $_->usb_devname
+ } @xbuses;
+ return $wanted;
+}
+
+sub new($$) {
+ my $pack = shift or die "Wasn't called as a class method\n";
+ my $self = { @_ };
+ bless $self, $pack;
+ my $xbus = xbus_of_usb($self->priv_device_name);
+ if(defined $xbus) {
+ $self->{XBUS} = $xbus;
+ $self->{LOADED} = 'xpp_usb';
+ } else {
+ $self->{XBUS} = undef;
+ $self->{LOADED} = undef;
+ }
+ Zaptel::Hardware::device_detected($self,
+ sprintf("usb:%s", $self->{PRIV_DEVICE_NAME}));
+ return $self;
+}
+
+sub devices($) {
+ my $pack = shift || die;
+ my $usb_device_list = "/proc/bus/usb/devices";
+ return unless (-r $usb_device_list);
+
+ my @devices;
+ open(F, $usb_device_list) || die "Failed to open $usb_device_list: $!";
+ local $/ = '';
+ while(<F>) {
+ my @lines = split(/\n/);
+ my ($tline) = grep(/^T/, @lines);
+ my ($pline) = grep(/^P/, @lines);
+ my ($sline) = grep(/^S:.*SerialNumber=/, @lines);
+ my ($busnum,$devnum) = ($tline =~ /Bus=(\w+)\W.*Dev#=\s*(\w+)\W/);
+ my $devname = sprintf("%03d/%03d", $busnum, $devnum);
+ my ($vendor,$product) = ($pline =~ /Vendor=(\w+)\W.*ProdID=(\w+)\W/);
+ my $serial;
+ if(defined $sline) {
+ $sline =~ /SerialNumber=(.*)/;
+ $serial = $1;
+ #$serial =~ s/[[:^print:]]/_/g;
+ }
+ my $model = $usb_ids{"$vendor:$product"};
+ next unless defined $model;
+ my $d = Zaptel::Hardware::USB->new(
+ IS_ASTRIBANK => ($model->{DRIVER} eq 'xpp_usb')?1:0,
+ BUS_TYPE => 'USB',
+ PRIV_DEVICE_NAME => $devname,
+ VENDOR => $vendor,
+ PRODUCT => $product,
+ SERIAL => $serial,
+ DESCRIPTION => $model->{DESCRIPTION},
+ DRIVER => $model->{DRIVER},
+ );
+ push(@devices, $d);
+ }
+ close F;
+ @devices = sort usb_sorter @devices;
+}
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel/Span.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel/Span.pm
new file mode 100644
index 0000000..be49c28
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel/Span.pm
@@ -0,0 +1,300 @@
+package Zaptel::Span;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Zaptel::Utils;
+use Zaptel::Chans;
+use Zaptel::Xpp::Xpd;
+
+=head1 NAME
+
+Zaptel::Spans - Perl interface to a Zaptel span information
+
+This package allows access from perl to information about a Zaptel
+channel. It is part of the Zaptel Perl package.
+
+A span is a logical unit of Zaptel channels. Normally a port in a
+digital card or a whole analog card.
+
+See documentation of module L<Zaptel> for usage example. Specifically
+C<Zaptel::spans()> must be run initially.
+
+=head1 by_number()
+
+Get a span by its Zaptel span number.
+
+=head1 Span Properties
+
+=head2 num()
+
+The span number.
+
+=head2 name()
+
+The name field of a Zaptel span. E.g.:
+
+ TE2/0/1
+
+=head2 description()
+
+The description field of the span. e.g:
+
+ "T2XXP (PCI) Card 0 Span 1" HDB3/CCS/CRC4 RED
+
+=head2 chans()
+
+The list of the channels (L<Zaptel::Chan> objects) of this span.
+In a scalar context returns the number of channels this span has.
+
+=head2 bchans()
+
+Likewise a list of bchannels (or a count in a scalar context).
+
+=head2 is_sync_master()
+
+Is this span the source of timing for Zaptel?
+
+=head2 type()
+
+Type of span, or "UNKNOWN" if could not be detected. Current known
+types:
+
+BRI_TE, BRI_NT, E1_TE, E1_NT, J1_TE, J1_NT, T1_TE, T1_NT, FXS, FXO
+
+=head2 is_pri()
+
+Is this an E1/J1/T1 span?
+
+=head2 is_bri()
+
+Is this a BRI span?
+
+=head2 is_digital()
+
+Is this a digital (as opposed to analog) span?
+
+=head2 termtype()
+
+Set for digital spans. "TE" or "NT". Will probably be assumed to be "TE"
+if there's no information pointing either way.
+
+=head2 coding()
+
+Suggested sane coding type (e.g.: "hdb3", "b8zs") for this type of span.
+
+=head2 framing()
+
+Suggested sane framing type (e.g.: "ccs", "esf") for this type of span.
+
+=head2 yellow(), crc4()
+
+Likewise, suggestions ofr the respective fields in the span= line in
+zaptel.conf for this span.
+
+=head2 signalling()
+
+Suggested zapata.conf signalling for channels of this span.
+
+=head2 switchtype()
+
+Suggested zapata.conf switchtype for channels of this span.
+
+=head1 Note
+
+Most of those properties are normally used as lower-case functions, but
+actually set in the module as capital-letter propeties. To look at e.g.
+"signalling" is set, look for "SIGNALLING".
+
+=cut
+
+my $proc_base = "/proc/zaptel";
+
+sub chans($) {
+ my $span = shift;
+ return @{$span->{CHANS}};
+}
+
+sub by_number($) {
+ my $span_number = shift;
+ die "Missing span number" unless defined $span_number;
+ my @spans = Zaptel::spans();
+
+ my ($span) = grep { $_->num == $span_number } @spans;
+ return $span;
+}
+
+my @bri_strings = (
+ 'BRI_(NT|TE)',
+ '(?:quad|octo)BRI PCI ISDN Card.* \[(NT|TE)\]\ ',
+ 'octoBRI \[(NT|TE)\] ',
+ 'HFC-S PCI A ISDN.* \[(NT|TE)\] '
+ );
+
+my @pri_strings = (
+ '(E1|T1|J1)_(NT|TE)',
+ 'Tormenta 2 .*Quad (E1|T1)', # tor2.
+ 'Digium Wildcard .100P (T1|E1)/', # wct1xxp
+ 'ISA Tormenta Span 1', # torisa
+ 'TE110P T1/E1', # wcte11xp
+ 'Wildcard TE120P', # wcte12xp
+ 'Wildcard TE121', # wcte12xp
+ 'Wildcard TE122', # wcte12xp
+ 'T[24]XXP \(PCI\) Card ', # wct4xxp
+ );
+
+our $ZAPBRI_NET = 'bri_net';
+our $ZAPBRI_CPE = 'bri_cpe';
+
+our $ZAPPRI_NET = 'pri_net';
+our $ZAPPRI_CPE = 'pri_cpe';
+
+sub init_proto($$) {
+ my $self = shift;
+ my $proto = shift;
+
+ $self->{PROTO} = $proto;
+ if($proto eq 'E1') {
+ $self->{DCHAN_IDX} = 15;
+ $self->{BCHAN_LIST} = [ 0 .. 14, 16 .. 30 ];
+ } elsif($proto eq 'T1') {
+ $self->{DCHAN_IDX} = 23;
+ $self->{BCHAN_LIST} = [ 0 .. 22 ];
+ }
+ $self->{TYPE} = "${proto}_$self->{TERMTYPE}";
+}
+
+sub new($$) {
+ my $pack = shift or die "Wasn't called as a class method\n";
+ my $num = shift or die "Missing a span number parameter\n";
+ my $self = { NUM => $num };
+ bless $self, $pack;
+ $self->{TYPE} = "UNKNOWN";
+ my @xpds = Zaptel::Xpp::Xpd::xpds_by_spanno;
+ my $xpd = $xpds[$num];
+ if(defined $xpd) {
+ die "Spanno mismatch: $xpd->spanno, $num" unless $xpd->spanno == $num;
+ $self->{XPD} = $xpd;
+ }
+ open(F, "$proc_base/$num") or die "Failed to open '$proc_base/$num\n";
+ my $head = <F>;
+ chomp $head;
+ $self->{IS_DIGITAL} = 0;
+ $self->{IS_BRI} = 0;
+ $self->{IS_PRI} = 0;
+ foreach my $cardtype (@bri_strings) {
+ if($head =~ m/$cardtype/) {
+ $self->{IS_DIGITAL} = 1;
+ $self->{IS_BRI} = 1;
+ $self->{TERMTYPE} = $1;
+ $self->{TYPE} = "BRI_$1";
+ $self->{DCHAN_IDX} = 2;
+ $self->{BCHAN_LIST} = [ 0, 1 ];
+ last;
+ }
+ }
+ foreach my $cardtype (@pri_strings) {
+ if($head =~ m/$cardtype/) {
+ my @info;
+
+ push(@info, $1) if defined $1;
+ push(@info, $2) if defined $2;
+ my ($proto) = grep(/(E1|T1|J1)/, @info);
+ $proto = 'UNKNOWN' unless defined $proto;
+ my ($termtype) = grep(/(NT|TE)/, @info);
+ $termtype = 'TE' unless defined $termtype;
+
+ $self->{IS_DIGITAL} = 1;
+ $self->{IS_PRI} = 1;
+ $self->{TERMTYPE} = $termtype;
+ $self->init_proto($proto);
+ last;
+ }
+ }
+ die "$0: Unkown TERMTYPE [NT/TE]\n"
+ if $self->is_digital and !defined $self->{TERMTYPE};
+ ($self->{NAME}, $self->{DESCRIPTION}) = (split(/\s+/, $head, 4))[2, 3];
+ $self->{IS_ZAPTEL_SYNC_MASTER} =
+ ($self->{DESCRIPTION} =~ /\(MASTER\)/) ? 1 : 0;
+ $self->{CHANS} = [];
+ my @channels;
+ my $index = 0;
+ while(<F>) {
+ chomp;
+ s/^\s*//;
+ s/\s*$//;
+ next unless /\S/;
+ next unless /^\s*\d+/; # must be a real channel string.
+ my $c = Zaptel::Chans->new($self, $index, $_);
+ push(@channels, $c);
+ $index++;
+ }
+ close F;
+ if($self->is_pri()) {
+ # Check for PRI with unknown type strings
+ if($index == 31) {
+ if($self->{PROTO} eq 'UNKNOWN') {
+ $self->init_proto('E1');
+ } elsif($self->{PROTO} ne 'E1') {
+ die "$index channels in a $self->{PROTO} span";
+ }
+ } elsif($index == 24) {
+ if($self->{PROTO} eq 'UNKNOWN') {
+ $self->init_proto('T1'); # FIXME: J1?
+ } elsif($self->{PROTO} ne 'T1') {
+ die "$index channels in a $self->{PROTO} span";
+ }
+ }
+ }
+ @channels = sort { $a->num <=> $b->num } @channels;
+ $self->{CHANS} = \@channels;
+ $self->{YELLOW} = undef;
+ $self->{CRC4} = undef;
+ if($self->is_bri()) {
+ $self->{CODING} = 'ami';
+ $self->{DCHAN} = ($self->chans())[$self->{DCHAN_IDX}];
+ $self->{BCHANS} = [ ($self->chans())[@{$self->{BCHAN_LIST}}] ];
+ # Infer some info from channel name:
+ my $first_chan = ($self->chans())[0] || die "$0: No channels in span #$num\n";
+ my $chan_fqn = $first_chan->fqn();
+ if($chan_fqn =~ m(ZTHFC.*/|ztqoz.*/|XPP_BRI_.*/)) { # BRI
+ $self->{FRAMING} = 'ccs';
+ $self->{SWITCHTYPE} = 'euroisdn';
+ $self->{SIGNALLING} = ($self->{TERMTYPE} eq 'NT') ? $ZAPBRI_NET : $ZAPBRI_CPE ;
+ } elsif($chan_fqn =~ m(ztgsm.*/)) { # Junghanns's GSM cards.
+ $self->{FRAMING} = 'ccs';
+ $self->{SIGNALLING} = 'gsm';
+ }
+ }
+ if($self->is_pri()) {
+ $self->{DCHAN} = ($self->chans())[$self->{DCHAN_IDX}];
+ $self->{BCHANS} = [ ($self->chans())[@{$self->{BCHAN_LIST}}] ];
+ if($self->{PROTO} eq 'E1') {
+ $self->{CODING} = 'hdb3';
+ $self->{FRAMING} = 'ccs';
+ $self->{SWITCHTYPE} = 'euroisdn';
+ $self->{CRC4} = 'crc4';
+ } elsif($self->{PROTO} eq 'T1') {
+ $self->{CODING} = 'b8zs';
+ $self->{FRAMING} = 'esf';
+ $self->{SWITCHTYPE} = 'national';
+ } else {
+ die "'$self->{PROTO}' unsupported yet";
+ }
+ $self->{SIGNALLING} = ($self->{TERMTYPE} eq 'NT') ? $ZAPPRI_NET : $ZAPPRI_CPE ;
+ }
+ return $self;
+}
+
+sub bchans($) {
+ my $self = shift || die;
+
+ return @{$self->{BCHANS}};
+}
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel/Utils.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel/Utils.pm
new file mode 100644
index 0000000..8d13ad7
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel/Utils.pm
@@ -0,0 +1,52 @@
+package Zaptel::Utils;
+
+# Accessors (miniperl does not have Class:Accessor)
+our $AUTOLOAD;
+sub AUTOLOAD {
+ my $self = shift;
+ my $name = $AUTOLOAD;
+ $name =~ s/.*://; # strip fully-qualified portion
+ return if $name =~ /^[A-Z_]+$/; # ignore special methods (DESTROY)
+ my $key = uc($name);
+ my $val = shift;
+ if (defined $val) {
+ #print STDERR "set: $key = $val\n";
+ return $self->{$key} = $val;
+ } else {
+ if(!exists $self->{$key}) {
+ #$self->xpp_dump;
+ #die "Trying to get uninitialized '$key'";
+ }
+ my $val = $self->{$key};
+ #print STDERR "get: $key ($val)\n";
+ return $val;
+ }
+}
+
+sub xpp_dump($) {
+ my $self = shift || die;
+ printf STDERR "Dump a %s\n", ref($self);
+ foreach my $k (sort keys %{$self}) {
+ my $val = $self->{$k};
+ $val = '**UNDEF**' if !defined $val;
+ printf STDERR " %-20s %s\n", $k, $val;
+ }
+}
+
+# Based on Autoloader
+
+sub import {
+ my $pkg = shift;
+ my $callpkg = caller;
+
+ #print STDERR "import: $pkg, $callpkg\n";
+ #
+ # Export symbols, but not by accident of inheritance.
+ #
+ die "Sombody inherited Zaptel::Utils" if $pkg ne 'Zaptel::Utils';
+ no strict 'refs';
+ *{ $callpkg . '::AUTOLOAD' } = \&AUTOLOAD;
+ *{ $callpkg . '::xpp_dump' } = \&xpp_dump;
+}
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp.pm
new file mode 100644
index 0000000..8b7458f
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp.pm
@@ -0,0 +1,199 @@
+package Zaptel::Xpp;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Zaptel::Xpp::Xbus;
+
+=head1 NAME
+
+Zaptel::Xpp - Perl interface to the Xorcom Astribank drivers.
+
+=head1 SYNOPSIS
+
+ # Listing all Astribanks:
+ use Zaptel::Xpp;
+ # scans hardware:
+ my @xbuses = Zaptel::Xpp::xbuses("SORT_CONNECTOR");
+ for my $xbus (@xbuses) {
+ print $xbus->name." (".$xbus->label .", ". $xbus->connector .")\n";
+ for my $xpd ($xbus->xpds) {
+ print " - ".$xpd->fqn,"\n";
+ }
+ }
+=cut
+
+
+my $proc_base = "/proc/xpp";
+
+# Nominal sorters for xbuses
+sub by_name {
+ return $a->name cmp $b->name;
+}
+
+sub by_connector {
+ return $a->connector cmp $b->connector;
+}
+
+sub by_label {
+ my $cmp = $a->label cmp $b->label;
+ return $cmp if $cmp != 0;
+ return $a->connector cmp $b->connector;
+}
+
+=head1 xbuses([sort_order])
+
+Scans system (/proc and /sys) and returns a list of Astribank (Xbus)
+objects. The optional parameter sort_order is the order in which
+the Astribanks will be returns:
+
+=over
+
+=item SORT_CONNECTOR
+
+Sort by the connector string. For USB this defines the "path" to get to
+the device through controllers, hubs etc.
+
+=item SORT_LABEL
+
+Sorts by the label of the Astribank. The label field is unique to the
+Astribank. It can also be viewed through 'lsusb -v' without the drivers
+loaded (the iSerial field in the Device Descriptor).
+
+=item SORT_NAME
+
+Sort by the "name". e.g: "XBUS-00". The order of Astribank names depends
+on the load order, and hence may change between different runs.
+
+=item custom function
+
+Instead of using a predefined sorter, you can pass your own sorting
+function. See the example sorters in the code of this module.
+
+=back
+
+=cut
+
+sub xbuses {
+ my $optsort = shift || 'SORT_CONNECTOR';
+ my @xbuses;
+
+ -d "$proc_base" or return ();
+ my @lines;
+ local $/ = "\n";
+ open(F, "$proc_base/xbuses") ||
+ die "$0: Failed to open $proc_base/xbuses: $!\n";
+ @lines = <F>;
+ close F;
+ foreach my $line (@lines) {
+ chomp $line;
+ my ($name, @attr) = split(/\s+/, $line);
+ $name =~ s/://;
+ $name =~ /XBUS-(\d\d)/ or die "Bad XBUS number: $name";
+ my $num = $1;
+ @attr = map { split(/=/); } @attr;
+ my $xbus = Zaptel::Xpp::Xbus->new(NAME => $name, NUM => $num, @attr);
+ push(@xbuses, $xbus);
+ }
+ my $sorter;
+ if($optsort eq "SORT_CONNECTOR") {
+ $sorter = \&by_connector;
+ } elsif($optsort eq "SORT_NAME") {
+ $sorter = \&by_name;
+ } elsif($optsort eq "SORT_LABEL") {
+ $sorter = \&by_label;
+ } elsif(ref($optsort) eq 'CODE') {
+ $sorter = $optsort;
+ } else {
+ die "Unknown optional sorter '$optsort'";
+ }
+ @xbuses = sort $sorter @xbuses;
+ return @xbuses;
+}
+
+sub xpd_of_span($) {
+ my $span = shift or die "Missing span parameter";
+ return undef unless defined $span;
+ foreach my $xbus (Zaptel::Xpp::xbuses('SORT_CONNECTOR')) {
+ foreach my $xpd ($xbus->xpds()) {
+ return $xpd if $xpd->fqn eq $span->name;
+ }
+ }
+ return undef;
+}
+
+=head1 sync([new_sync_source])
+
+Gets (and optionally sets) the internal Astribanks synchronization
+source. When used to set sync source, returns the original sync source.
+
+A synchronization source is a value valid writing into /proc/xpp/sync .
+For more information read that file and see README.Astribank .
+
+=cut
+
+sub sync {
+ my $newsync = shift;
+ my $result;
+ my $newapi = 0;
+
+ my $file = "$proc_base/sync";
+ return '' unless -f $file;
+ # First query
+ open(F, "$file") or die "Failed to open $file for reading: $!";
+ while(<F>) {
+ chomp;
+ /SYNC=/ and $newapi = 1;
+ s/#.*//;
+ if(/\S/) { # First non-comment line
+ s/^SYNC=\D*// if $newapi;
+ $result = $_;
+ last;
+ }
+ }
+ close F;
+ if(defined($newsync)) { # Now change
+ $newsync =~ s/.*/\U$&/;
+ if($newsync =~ /^(\d+)$/) {
+ $newsync = ($newapi)? "SYNC=$1" : "$1 0";
+ } elsif($newsync ne 'ZAPTEL') {
+ die "Bad sync parameter '$newsync'";
+ }
+ open(F, ">$file") or die "Failed to open $file for writing: $!";
+ print F $newsync;
+ close(F) or die "Failed in closing $file: $!";
+ }
+ return $result;
+}
+
+=head1 SEE ALSO
+
+=over
+
+=item L<Zaptel::Xpp::Xbus>
+
+Xbus (Astribank) object.
+
+=item L<Zaptel::Xpp::Xpd>
+
+XPD (the rough equivalent of a Zaptel span) object.
+
+=item L<Zaptel::Xpp::Line>
+
+Object for a line: an analog port or a time-slot in a adapter.
+Equivalent of a channel in Zaptel.
+
+=item L<Zaptel>
+
+General documentation in the master package.
+
+=back
+
+=cut
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Line.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Line.pm
new file mode 100644
index 0000000..2472c3b
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Line.pm
@@ -0,0 +1,95 @@
+package Zaptel::Xpp::Line;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2008, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Zaptel::Utils;
+
+my $proc_base = "/proc/xpp";
+
+sub new($$$) {
+ my $pack = shift or die "Wasn't called as a class method\n";
+ my $xpd = shift or die;
+ my $index = shift;
+ defined $index or die;
+ my $self = {};
+ bless $self, $pack;
+ $self->{XPD} = $xpd;
+ $self->{INDEX} = $index;
+ return $self;
+}
+
+sub blink($$) {
+ my $self = shift;
+ my $on = shift;
+ my $xpd = $self->xpd;
+ my $result;
+
+ my $file = "$proc_base/" . $xpd->fqn . "/blink";
+ die "$file is missing" unless -f $file;
+ # First query
+ open(F, "$file") or die "Failed to open $file for reading: $!";
+ $result = <F>;
+ chomp $result;
+ close F;
+ if(defined($on)) { # Now change
+ my $onbitmask = 1 << $self->index;
+ my $offbitmask = $result & ~$onbitmask;
+
+ $result = $offbitmask;
+ $result |= $onbitmask if $on;
+ open(F, ">$file") or die "Failed to open $file for writing: $!";
+ print F "$result";
+ if(!close(F)) {
+ if($! == 17) { # EEXISTS
+ # good
+ } else {
+ undef $result;
+ }
+ }
+ }
+ return $result;
+}
+
+sub create_all($$) {
+ my $pack = shift or die "Wasn't called as a class method\n";
+ my $xpd = shift || die;
+ my $procdir = shift || die;
+ local $/ = "\n";
+ my @lines;
+ for(my $i = 0; $i < $xpd->{CHANNELS}; $i++) {
+ my $line = Zaptel::Xpp::Line->new($xpd, $i);
+ push(@lines, $line);
+ }
+ $xpd->{LINES} = \@lines;
+ my ($infofile) = glob "$procdir/*_info";
+ die "Failed globbing '$procdir/*_info'" unless defined $infofile;
+ my $type = $xpd->type;
+ open(F, "$infofile") || die "Failed opening '$infofile': $!";
+ my $battery_info = 0;
+ while (<F>) {
+ chomp;
+ if($type eq 'FXO') {
+ $battery_info = 1 if /^Battery:/;
+ if($battery_info && s/^\s*on\s*:\s*//) {
+ my @batt = split;
+ foreach my $l (@lines) {
+ die unless @batt;
+ my $state = shift @batt;
+ $l->{BATTERY} = ($state eq '+') ? 1 : 0;
+ }
+ $battery_info = 0;
+ die if @batt;
+ }
+ }
+ }
+ close F;
+}
+
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm
new file mode 100644
index 0000000..e840f14
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm
@@ -0,0 +1,118 @@
+package Zaptel::Xpp::Xbus;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Zaptel::Utils;
+use Zaptel::Xpp::Xpd;
+
+my $proc_base = "/proc/xpp";
+
+sub xpds($) {
+ my $xbus = shift;
+ return @{$xbus->{XPDS}};
+}
+
+sub by_number($) {
+ my $busnumber = shift;
+ die "Missing xbus number parameter" unless defined $busnumber;
+ my @xbuses = Zaptel::Xpp::xbuses();
+
+ my ($xbus) = grep { $_->num == $busnumber } @xbuses;
+ return $xbus;
+}
+
+sub by_label($) {
+ my $label = shift;
+ die "Missing xbus label parameter" unless defined $label;
+ my @xbuses = Zaptel::Xpp::xbuses();
+
+ my ($xbus) = grep { $_->label eq $label } @xbuses;
+ return $xbus;
+}
+
+sub get_xpd_by_number($$) {
+ my $xbus = shift;
+ my $xpdid = shift;
+ die "Missing XPD id parameter" unless defined $xpdid;
+ my @xpds = $xbus->xpds;
+ my ($wanted) = grep { $_->id eq $xpdid } @xpds;
+ return $wanted;
+}
+
+sub new($$) {
+ my $pack = shift or die "Wasn't called as a class method\n";
+ my $self = {};
+ bless $self, $pack;
+ while(@_) {
+ my ($k, $v) = @_;
+ shift; shift;
+ # Keys in all caps
+ $k = uc($k);
+ # Some values are in all caps as well
+ if($k =~ /^(STATUS)$/) {
+ $v = uc($v);
+ }
+ $self->{$k} = $v;
+ }
+ # backward compat for drivers without labels.
+ if(!defined $self->{LABEL}) {
+ $self->{LABEL} = '[]';
+ }
+ $self->{LABEL} =~ s/^\[(.*)\]$/$1/ or die "$self->{NAME}: Bad label";
+ # Fix badly burned labels.
+ $self->{LABEL} =~ s/[[:^print:]]/_/g;
+ $self->{NAME} or die "Missing xbus name";
+ my $prefix = "$proc_base/" . $self->{NAME};
+ my $usbfile = "$prefix/xpp_usb";
+ if(open(F, "$usbfile")) {
+ my $head = <F>;
+ chomp $head;
+ close F;
+ $head =~ s/^device: +([^, ]+)/$1/i or die;
+ $self->{USB_DEVNAME} = $head;
+ }
+ @{$self->{XPDS}} = ();
+ foreach my $dir (glob "$prefix/XPD-??") {
+ my $xpd = Zaptel::Xpp::Xpd->new($self, $dir);
+ push(@{$self->{XPDS}}, $xpd);
+ }
+ @{$self->{XPDS}} = sort { $a->id <=> $b->id } @{$self->{XPDS}};
+ return $self;
+}
+
+sub pretty_xpds($) {
+ my $xbus = shift;
+ my @xpds = sort { $a->id <=> $b->id } $xbus->xpds();
+ my @xpd_types = map { $_->type } @xpds;
+ my $last_type = '';
+ my $mult = 0;
+ my $xpdstr = '';
+ foreach my $curr (@xpd_types) {
+ if(!$last_type || ($curr eq $last_type)) {
+ $mult++;
+ } else {
+ if($mult == 1) {
+ $xpdstr .= "$last_type ";
+ } elsif($mult) {
+ $xpdstr .= "$last_type*$mult ";
+ }
+ $mult = 1;
+ }
+ $last_type = $curr;
+ }
+ if($mult == 1) {
+ $xpdstr .= "$last_type ";
+ } elsif($mult) {
+ $xpdstr .= "$last_type*$mult ";
+ }
+ $xpdstr =~ s/\s*$//; # trim trailing space
+ return $xpdstr;
+}
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm b/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm
new file mode 100644
index 0000000..1ddb5c8
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm
@@ -0,0 +1,123 @@
+package Zaptel::Xpp::Xpd;
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Zaptel::Utils;
+use Zaptel::Xpp;
+use Zaptel::Xpp::Line;
+
+my $proc_base = "/proc/xpp";
+
+sub blink($$) {
+ my $self = shift;
+ my $on = shift;
+ my $result;
+
+ my $file = "$proc_base/" . $self->fqn . "/blink";
+ die "$file is missing" unless -f $file;
+ # First query
+ open(F, "$file") or die "Failed to open $file for reading: $!";
+ $result = <F>;
+ chomp $result;
+ close F;
+ if(defined($on) and $on ne $result) { # Now change
+ open(F, ">$file") or die "Failed to open $file for writing: $!";
+ print F ($on)?"0xFFFF":"0";
+ if(!close(F)) {
+ if($! == 17) { # EEXISTS
+ # good
+ } else {
+ undef $result;
+ }
+ }
+ }
+ return $result;
+}
+
+sub zt_registration($$) {
+ my $self = shift;
+ my $on = shift;
+ my $result;
+
+ my $file = "$proc_base/" . $self->fqn . "/zt_registration";
+ die "$file is missing" unless -f $file;
+ # First query
+ open(F, "$file") or die "Failed to open $file for reading: $!";
+ $result = <F>;
+ chomp $result;
+ close F;
+ if(defined($on) and $on ne $result) { # Now change
+ open(F, ">$file") or die "Failed to open $file for writing: $!";
+ print F ($on)?"1":"0";
+ if(!close(F)) {
+ if($! == 17) { # EEXISTS
+ # good
+ } else {
+ undef $result;
+ }
+ }
+ }
+ return $result;
+}
+
+sub xpds_by_spanno() {
+ my @xbuses = Zaptel::Xpp::xbuses("SORT_CONNECTOR");
+ my @xpds = map { $_->xpds } @xbuses;
+ @xpds = grep { $_->spanno } @xpds;
+ @xpds = sort { $a->spanno <=> $b->spanno } @xpds;
+ my @spanno = map { $_->spanno } @xpds;
+ my @idx;
+ @idx[@spanno] = @xpds; # The spanno is the index now
+ return @idx;
+}
+
+sub new($$) {
+ my $pack = shift or die "Wasn't called as a class method\n";
+ my $xbus = shift || die;
+ my $procdir = shift || die;
+ my $self = {};
+ bless $self, $pack;
+ $self->{XBUS} = $xbus;
+ $self->{DIR} = $procdir;
+ local $/ = "\n";
+ open(F, "$procdir/summary") || die "Missing summary file in $procdir";
+ my $head = <F>;
+ chomp $head; # "XPD-00 (BRI_TE ,card present, span 3)"
+ # The driver does not export the number of channels...
+ # Let's find it indirectly
+ while(<F>) {
+ chomp;
+ if(s/^\s*offhook\s*:\s*//) {
+ my @offhook = split;
+ @offhook || die "No channels in '$procdir/summary'";
+ $self->{CHANNELS} = @offhook;
+ last;
+ }
+ }
+ close F;
+ $head =~ s/^(XPD-(\d\d))\s+// || die;
+ $self->{ID} = $2;
+ $self->{FQN} = $xbus->name . "/" . $1;
+ $head =~ s/^.*\(// || die;
+ $head =~ s/\) */, / || die;
+ $head =~ s/\s*,\s*/,/g || die;
+ my ($type,$present,$span,$rest) = split(/,/, $head);
+ #warn "Garbage in '$procdir/summary': rest='$rest'\n" if $rest;
+ if($span =~ s/span\s+(\d+)//) { # since changeset:5119
+ $self->{SPANNO} = $1;
+ }
+ $self->{TYPE} = $type;
+ $self->{IS_BRI} = ($type =~ /BRI_(NT|TE)/);
+ $self->{IS_PRI} = ($type =~ /[ETJ]1_(NT|TE)/);
+ $self->{IS_DIGITAL} = ( $self->{IS_BRI} || $self->{IS_PRI} );
+ Zaptel::Xpp::Line->create_all($self, $procdir);
+ return $self;
+}
+
+1;
diff --git a/drivers/dahdi/xpp/utils/zt_registration b/drivers/dahdi/xpp/utils/zt_registration
new file mode 100755
index 0000000..3bdc642
--- /dev/null
+++ b/drivers/dahdi/xpp/utils/zt_registration
@@ -0,0 +1,125 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); }
+
+use Zaptel;
+use Zaptel::Span;
+use Zaptel::Xpp;
+use Zaptel::Xpp::Xbus;
+
+sub usage {
+ die "Usage: $0 [on|off|1|0]\n";
+}
+
+@ARGV == 0 or @ARGV == 1 or usage;
+my $on = shift;
+my $verbose = 0;
+my $should_output = 1;
+
+if(defined($on)) { # Translate to booleans
+ $on = uc($on);
+ $on =~ /^(ON|OFF|1|0)$/ or usage;
+ $on = ($on eq 'ON') ? 1 : 0;
+ $should_output = 0 unless $verbose;
+}
+
+sub state2str($) {
+ return (shift)?"on":"off";
+}
+
+sub myprintf {
+ printf @_ if $should_output;
+}
+
+my @spans = Zaptel::spans;
+
+foreach my $xbus (Zaptel::Xpp::xbuses('SORT_CONNECTOR')) {
+ myprintf "%-10s\t%s\t%s\n", $xbus->name, $xbus->label, $xbus->connector;
+ next unless $xbus->status eq 'CONNECTED';
+ foreach my $xpd ($xbus->xpds()) {
+ my $prev = $xpd->zt_registration($on);
+ if(!defined($prev)) { # Failure
+ printf "%s: Failed %s\n", $xpd->fqn, $!;
+ next;
+ }
+ myprintf "\t%-10s: ", $xpd->fqn;
+ if(!defined($on)) { # Query only
+ my ($span) = grep { $_->name eq $xpd->fqn } @spans;
+ my $spanstr = ($span) ? ("Span " . $span->num) : "";
+ myprintf "%s %s\n", state2str($prev), $spanstr ;
+ next;
+ }
+ myprintf "%3s ==> %3s\n", state2str($prev), state2str($on);
+ }
+}
+
+__END__
+
+=head1 NAME
+
+zt_registration - Handle registration of Xorcom XPD modules in zaptel.
+
+=head1 SYNOPSIS
+
+zt_registration [on|off]
+
+=head1 DESCRIPTION
+
+Without parameters, show all connected XPDs sorted by physical connector order.
+Each one is show to be unregistered (off), or registered to a specific zaptel
+span (the span number is shown).
+
+All registerations/deregisterations are sorted by physical connector string.
+
+Span registration should generally always succeed. Span unregistration may
+fail if channels from the span are in use by e.g. asterisk. In such a case
+you'll also see those channels as '(In use)' in the output of lszaptel(8).
+
+=head2 Parameters
+
+off -- deregisters all XPD's from zaptel.
+
+on -- registers all XPD's to zaptel.
+
+=head2 Sample Output
+
+An example of the output of zt_registration for some registered
+Astribanks:
+
+ $ zt_registration
+ XBUS-02 [] usb-0000:00:1d.7-4
+ XBUS-00/XPD-00: on Span 1
+ XBUS-00/XPD-10: on Span 2
+ XBUS-00 [usb:00000126] usb-0000:00:1d.7-2
+ XBUS-02/XPD-00: on Span 3
+ XBUS-02/XPD-10: on Span 4
+ XBUS-02/XPD-20: on Span 5
+ XBUS-02/XPD-30: on Span 6
+ XBUS-01 [usb:00000128] usb-0000:00:1d.7-1
+ XBUS-01/XPD-00: on Span 7
+ XBUS-01/XPD-10: on Span 8
+ XBUS-01/XPD-20: on Span 9
+ XBUS-01/XPD-30: on Span 10
+
+=head1 FILES
+
+=over
+
+=item /proc/xpp/XBUS-nn/XPD-mm/zt_registration
+
+Reading from this file shows if if the if the specific XPD is
+registered. Writing to it 0 or 1 registers / unregisters the device.
+
+This should allow you to register / unregister a specific XPD rather
+than all of them.
+
+=back
diff --git a/drivers/dahdi/xpp/xbus-core.c b/drivers/dahdi/xpp/xbus-core.c
new file mode 100644
index 0000000..26c31f5
--- /dev/null
+++ b/drivers/dahdi/xpp/xbus-core.c
@@ -0,0 +1,1708 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+# warning "This module is tested only with 2.6 kernels"
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#ifdef PROTOCOL_DEBUG
+#include <linux/ctype.h>
+#endif
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/delay.h> /* for msleep() to debug */
+#include "xpd.h"
+#include "xpp_zap.h"
+#include "xbus-core.h"
+#include "card_global.h"
+#ifdef XPP_DEBUGFS
+#include "xpp_log.h"
+#endif
+#include "zap_debug.h"
+
+static const char rcsid[] = "$Id$";
+
+/* Defines */
+#define INITIALIZATION_TIMEOUT (90*HZ) /* in jiffies */
+#define PROC_XBUSES "xbuses"
+#define PROC_XBUS_SUMMARY "summary"
+#define PROC_XBUS_WAITFOR_XPDS "waitfor_xpds"
+
+#ifdef PROTOCOL_DEBUG
+#define PROC_XBUS_COMMAND "command"
+static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+#endif
+
+/* Command line parameters */
+extern int debug;
+static DEF_PARM(uint, poll_timeout, 1000, 0644, "Timeout (in jiffies) waiting for units to reply");
+static DEF_PARM_BOOL(rx_tasklet, 0, 0644, "Use receive tasklets");
+
+static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data);
+static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, void *priv);
+static void transport_destroy(xbus_t *xbus);
+
+/* Data structures */
+static spinlock_t xbuses_lock = SPIN_LOCK_UNLOCKED;
+static int bus_count = 0;
+static struct proc_dir_entry *proc_xbuses = NULL;
+
+static struct xbus_desc {
+ xbus_t *xbus;
+ atomic_t xbus_refcount;
+ wait_queue_head_t can_release_xbus;
+} xbuses_array[MAX_BUSES];
+
+static void init_xbus(uint num, xbus_t *xbus)
+{
+ struct xbus_desc *desc;
+
+ BUG_ON(num >= ARRAY_SIZE(xbuses_array));
+ desc = &xbuses_array[num];
+ desc->xbus = xbus;
+ atomic_set(&desc->xbus_refcount, 0);
+ init_waitqueue_head(&desc->can_release_xbus);
+}
+
+static int refcount_xbus(uint num)
+{
+ BUG_ON(num >= ARRAY_SIZE(xbuses_array));
+ return atomic_read(&xbuses_array[num].xbus_refcount);
+}
+
+xbus_t *get_xbus(uint num)
+{
+ struct xbus_desc *desc;
+
+ if(num >= ARRAY_SIZE(xbuses_array))
+ return NULL;
+ desc = &xbuses_array[num];
+ atomic_inc(&desc->xbus_refcount);
+ if(!desc->xbus)
+ atomic_dec(&desc->xbus_refcount);
+ return desc->xbus;
+}
+
+void put_xbus(xbus_t *xbus)
+{
+ struct xbus_desc *desc;
+ int num;
+
+ BUG_ON(!xbus);
+ num = xbus->num;
+ BUG_ON(num >= ARRAY_SIZE(xbuses_array));
+ desc = &xbuses_array[num];
+ BUG_ON(desc->xbus != xbus);
+ if(atomic_dec_and_test(&desc->xbus_refcount)) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0)
+ XBUS_DBG(DEVICES, xbus,
+ "wake_up(can_release_xbus) (%d)\n", rate_limit);
+ wake_up(&desc->can_release_xbus);
+ }
+}
+
+static bool __must_check wait_for_xbus_release(uint xbus_num)
+{
+ xbus_t *xbus;
+ int ret;
+
+ xbus = get_xbus(xbus_num);
+ if(!xbus) {
+ ERR("%s: xbus #%d is already removed. Skip.\n",
+ __FUNCTION__, xbus_num);
+ return 0;
+ }
+ put_xbus(xbus);
+ DBG(DEVICES, "Waiting... refcount_xbus=%d\n", refcount_xbus(xbus_num));
+ ret = wait_event_interruptible(xbuses_array[xbus_num].can_release_xbus,
+ refcount_xbus(xbus_num) == 0);
+ if(ret) {
+ ERR("%s: waiting for xbus #%d interrupted!!!\n",
+ __FUNCTION__, xbus_num);
+ } else
+ DBG(DEVICES, "Waiting for refcount_xbus done.\n");
+ return 1;
+}
+
+static void initialize_xbuses_array(void)
+{
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(xbuses_array); i++)
+ init_xbus(i, NULL);
+}
+
+static void finalize_xbuses_array(void)
+{
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(xbuses_array); i++) {
+ if(xbuses_array[i].xbus != NULL) {
+ ERR("%s: xbus #%d is not NULL\n", __FUNCTION__, i);
+ BUG();
+ }
+ }
+}
+
+/*------------------------- Debugfs Handling -----------------------*/
+#ifdef XPP_DEBUGFS
+
+#define DEBUGFS_BUFSIZ 4096 /* must be power of two, otherwise POS_IN_BUF will have to use '%' instead of '&' */
+#define POS_IN_BUF(x) ((x) & (DEBUGFS_BUFSIZ-1))
+
+struct debugfs_data {
+ spinlock_t lock;
+ xbus_t *xbus;
+ char buffer[DEBUGFS_BUFSIZ];
+ unsigned long head, tail; /* reading and writing are performed at position (head % BUF_SIZ) and (tail % BUF_SIZ) */
+ wait_queue_head_t queue;
+};
+
+static unsigned long add_to_buf(struct debugfs_data *d, unsigned long tail, const void *buf, unsigned long len)
+{
+ unsigned long count = min(len, (unsigned long)(DEBUGFS_BUFSIZ - POS_IN_BUF(tail)));
+ memcpy(d->buffer + POS_IN_BUF(tail), buf, count); /* fill starting at position tail */
+ memcpy(d->buffer, (u_char *)buf + count, len - count); /* fill leftover */
+ return len;
+}
+
+int xbus_log(xbus_t *xbus, xpd_t *xpd, int direction, const void *buf, unsigned long len)
+{
+ unsigned long tail;
+ unsigned long flags;
+ struct debugfs_data *d;
+ struct log_header header;
+ int ret = 0;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ BUG_ON(sizeof(struct log_header) + len > DEBUGFS_BUFSIZ);
+ d = xbus->debugfs_data;
+ if (!d) /* no consumer process */
+ return ret;
+ spin_lock_irqsave(&d->lock, flags);
+ if (sizeof(struct log_header) + len > DEBUGFS_BUFSIZ - (d->tail - d->head)) {
+ ret = -ENOSPC;
+ XPD_DBG(GENERAL, xpd, "Dropping debugfs data of len %lu, free space is %lu\n", sizeof(struct log_header) + len,
+ DEBUGFS_BUFSIZ - (d->tail - d->head));
+ goto out;
+ }
+ header.len = sizeof(struct log_header) + len;
+ header.time = jiffies_to_msecs(jiffies);
+ header.xpd_num = xpd->xbus_idx;
+ header.direction = (char)direction;
+ tail = d->tail;
+ tail += add_to_buf(d, tail, &header, sizeof(header));
+ tail += add_to_buf(d, tail, buf, len);
+ d->tail = tail;
+ wake_up_interruptible(&d->queue);
+out:
+ spin_unlock_irqrestore(&d->lock, flags);
+ return ret;
+}
+
+static struct dentry *debugfs_root = NULL;
+static int debugfs_open(struct inode *inode, struct file *file);
+static ssize_t debugfs_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos);
+static int debugfs_release(struct inode *inode, struct file *file);
+
+static struct file_operations debugfs_operations = {
+ .open = debugfs_open,
+ .read = debugfs_read,
+ .release = debugfs_release,
+};
+
+/*
+ * As part of the "inode diet" the private data member of struct inode
+ * has changed in 2.6.19. However, Fedore Core 6 adopted this change
+ * a bit earlier (2.6.18). If you use such a kernel, Change the
+ * following test from 2,6,19 to 2,6,18.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+#define I_PRIVATE(inode) ((inode)->u.generic_ip)
+#else
+#define I_PRIVATE(inode) ((inode)->i_private)
+#endif
+
+static int debugfs_open(struct inode *inode, struct file *file)
+{
+ xbus_t *xbus = I_PRIVATE(inode);
+ struct debugfs_data *d;
+ struct log_global_header gheader;
+
+ BUG_ON(!xbus);
+ XBUS_DBG(GENERAL, xbus, "\n");
+ if (xbus->debugfs_data)
+ return -EBUSY;
+ d = KZALLOC(sizeof(struct debugfs_data), GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
+ try_module_get(THIS_MODULE);
+ spin_lock_init(&d->lock);
+ d->xbus = xbus;
+ d->head = d->tail = 0;
+ init_waitqueue_head(&d->queue);
+ file->private_data = d;
+
+ gheader.magic = XPP_LOG_MAGIC;
+ gheader.version = 1;
+ d->tail += add_to_buf(d, d->tail, &gheader, sizeof(gheader));
+
+ xbus->debugfs_data = d;
+ return 0;
+}
+
+static ssize_t debugfs_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+{
+ struct debugfs_data *d = file->private_data;
+ size_t len;
+
+ BUG_ON(!d);
+ BUG_ON(!d->xbus);
+ XBUS_DBG(GENERAL, d->xbus, "\n");
+ while (d->head == d->tail) {
+ if (wait_event_interruptible(d->queue, d->head != d->tail))
+ return -EAGAIN;
+ }
+ len = min(nbytes, (size_t)(d->tail - d->head));
+ if (copy_to_user(buf, d->buffer + POS_IN_BUF(d->head), len))
+ return -EFAULT;
+ d->head += len;
+ /* optimization to avoid future buffer wraparound */
+ if (d->head == d->tail) {
+ unsigned long flags;
+ spin_lock_irqsave(&d->lock, flags);
+ if (d->head == d->tail)
+ d->head = d->tail = 0;
+ spin_unlock_irqrestore(&d->lock, flags);
+ }
+ return len;
+}
+
+static int debugfs_release(struct inode *inode, struct file *file)
+{
+ struct debugfs_data *d = file->private_data;
+
+ BUG_ON(!d);
+ BUG_ON(!d->xbus);
+ XBUS_DBG(GENERAL, d->xbus, "\n");
+ d->xbus->debugfs_data = NULL;
+ kfree(d);
+ module_put(THIS_MODULE);
+ return 0;
+}
+#endif
+
+/*------------------------- Frame Handling ------------------------*/
+
+void xframe_init(xbus_t *xbus, xframe_t *xframe, void *buf, size_t maxsize, void *priv)
+{
+ memset(xframe, 0, sizeof(*xframe));
+ INIT_LIST_HEAD(&xframe->frame_list);
+ xframe->priv = priv;
+ xframe->xbus = xbus;
+ xframe->packets = xframe->first_free = buf;
+ xframe->frame_maxlen = maxsize;
+ atomic_set(&xframe->frame_len, 0);
+ do_gettimeofday(&xframe->tv_created);
+ xframe->xframe_magic = XFRAME_MAGIC;
+}
+
+/*
+ * Return pointer to next packet slot in the frame
+ * or NULL if the frame is full.
+ *
+ * FIXME: we do not use atomic_add_return() because kernel-2.6.8
+ * does not have it. This make this code a little racy,
+ * but we currently call xframe_next_packet() only in the
+ * PCM loop (xbus_tick() etc.)
+ */
+xpacket_t *xframe_next_packet(xframe_t *frm, int len)
+{
+ int newlen = XFRAME_LEN(frm);
+
+ newlen += len;
+// DBG(GENERAL, "len=%d, newlen=%d, frm->frame_len=%d\n", len, newlen, XFRAME_LEN(frm));
+ if (newlen > XFRAME_DATASIZE) {
+ return NULL;
+ }
+ atomic_add(len, &frm->frame_len);
+ return (xpacket_t *)(frm->packets + newlen - len);
+}
+
+static spinlock_t serialize_dump_xframe = SPIN_LOCK_UNLOCKED;
+
+static void do_hexdump(const char msg[], byte *data, uint16_t len)
+{
+ int i;
+ int debug = DBG_ANY; /* mask global debug */
+
+ for(i = 0; i < len; i++)
+ DBG(ANY, "%s: %3d> %02X\n", msg, i, data[i]);
+}
+
+void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, int debug)
+{
+ const uint16_t frm_len = XFRAME_LEN(xframe);
+ xpacket_t *pack;
+ uint16_t pos = 0;
+ uint16_t nextpos;
+ int num = 1;
+ bool do_print;
+ unsigned long flags;
+
+ if(xframe->xframe_magic != XFRAME_MAGIC) {
+ XBUS_ERR(xbus, "%s: bad xframe_magic %lX\n",
+ __FUNCTION__, xframe->xframe_magic);
+ return;
+ }
+ spin_lock_irqsave(&serialize_dump_xframe, flags);
+ do {
+ if(pos >= xbus->transport.max_send_size) {
+ if(printk_ratelimit()) {
+ XBUS_NOTICE(xbus, "%s: xframe overflow (%d bytes)\n",
+ msg, frm_len);
+ do_hexdump(msg, xframe->packets, frm_len);
+ }
+ break;
+ }
+ if(pos > frm_len) {
+ if(printk_ratelimit()) {
+ XBUS_NOTICE(xbus, "%s: packet overflow pos=%d frame_len=%d\n",
+ msg, pos, frm_len);
+ do_hexdump(msg, xframe->packets, frm_len);
+ }
+ break;
+ }
+ pack = (xpacket_t *)&xframe->packets[pos];
+ if(XPACKET_LEN(pack) <= 0) {
+ if(printk_ratelimit()) {
+ XBUS_NOTICE(xbus, "%s: xframe -- bad packet_len=%d pos=%d frame_len=%d\n",
+ msg, XPACKET_LEN(pack), pos, frm_len);
+ do_hexdump(msg, xframe->packets, frm_len);
+ }
+ break;
+ }
+ nextpos = pos + XPACKET_LEN(pack);
+ if(nextpos > frm_len) {
+ if(printk_ratelimit()) {
+ XBUS_NOTICE(xbus, "%s: packet overflow nextpos=%d frame_len=%d\n",
+ msg, nextpos, frm_len);
+ do_hexdump(msg, xframe->packets, frm_len);
+ }
+ break;
+ }
+ do_print = 0;
+ if(debug == DBG_ANY)
+ do_print = 1;
+ else if(XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_READ) &&
+ XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_WRITE))
+ do_print = 1;
+ else if(debug & DBG_PCM) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0)
+ do_print = 1;
+ }
+ if(do_print) {
+ if(num == 1) {
+ XBUS_DBG(ANY, xbus, "%s: frame_len=%d. %s\n",
+ msg, frm_len,
+ (XPACKET_IS_PCM(pack))
+ ? "(IS_PCM)"
+ : "");
+ }
+ XBUS_DBG(ANY, xbus, " %3d. DATALEN=%d pcm=%d slot=%d OP=0x%02X XPD-%d%d (pos=%d)\n",
+ num, XPACKET_LEN(pack),
+ XPACKET_IS_PCM(pack), XPACKET_PCMSLOT(pack),
+ XPACKET_OP(pack),
+ XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack),
+ pos);
+ dump_packet(" ", pack, debug);
+ }
+ num++;
+ pos = nextpos;
+ if(pos >= frm_len)
+ break;
+ } while(1);
+ spin_unlock_irqrestore(&serialize_dump_xframe, flags);
+}
+
+static bool xbus_ready(const xbus_t *xbus, const char msg[])
+{
+ if(!xbus) {
+ ERR("null xbus: %s\n", msg);
+ return 0;
+ }
+ if (!TRANSPORT_RUNNING(xbus)) {
+ XBUS_ERR(xbus, "%s -- hardware is not ready.", msg);
+ return 0;
+ }
+ if(!xbus->transport.ops) {
+ XBUS_ERR(xbus, "%s -- hardware is gone.", msg);
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ *
+ * Frame is freed:
+ * - In case of error, by this function.
+ * - Otherwise, by the underlying sending mechanism
+ */
+int send_pcm_frame(xbus_t *xbus, xframe_t *xframe)
+{
+ struct xbus_ops *ops;
+ int ret = -ENODEV;
+
+ BUG_ON(!xframe);
+ if(!xbus_ready(xbus, "Dropped a pcm frame")) {
+ ret = -ENODEV;
+ goto error;
+ }
+ ops = transportops_get(xbus);
+ BUG_ON(!ops);
+ ret = ops->xframe_send_pcm(xbus, xframe);
+ transportops_put(xbus);
+ if(ret)
+ XBUS_COUNTER(xbus, TX_BYTES) += XFRAME_LEN(xframe);
+ return ret;
+
+error:
+ FREE_SEND_XFRAME(xbus, xframe);
+ return ret;
+}
+
+static int really_send_cmd_frame(xbus_t *xbus, xframe_t *xframe)
+{
+ struct xbus_ops *ops;
+ int ret;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xframe);
+ BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
+ if(!xbus_ready(xbus, "Dropped command before sending")) {
+ FREE_SEND_XFRAME(xbus, xframe);
+ return -ENODEV;
+ }
+ ops = transportops_get(xbus);
+ BUG_ON(!ops);
+ if(debug & DBG_COMMANDS)
+ dump_xframe("TX-CMD", xbus, xframe, DBG_ANY);
+ ret = ops->xframe_send_cmd(xbus, xframe);
+ transportops_put(xbus);
+ if(ret == 0) {
+ XBUS_COUNTER(xbus, TX_CMD)++;
+ XBUS_COUNTER(xbus, TX_BYTES) += XFRAME_LEN(xframe);
+ }
+ return ret;
+}
+
+int xbus_command_queue_tick(xbus_t *xbus)
+{
+ xframe_t *frm;
+ int ret = 0;
+
+ frm = xframe_dequeue(&xbus->command_queue);
+ if(frm) {
+ BUG_ON(frm->xframe_magic != XFRAME_MAGIC);
+ ret = really_send_cmd_frame(xbus, frm);
+ if(ret < 0)
+ XBUS_ERR(xbus,
+ "Failed to send from command_queue (ret=%d)\n",
+ ret);
+ XBUS_PUT(xbus);
+ } else
+ wake_up(&xbus->command_queue_empty);
+ return ret;
+}
+
+static void xbus_command_queue_clean(xbus_t *xbus)
+{
+ xframe_t *frm;
+
+ XBUS_DBG(DEVICES, xbus, "count=%d\n", xbus->command_queue.count);
+ xframe_queue_disable(&xbus->command_queue);
+ while((frm = xframe_dequeue(&xbus->command_queue)) != NULL) {
+ FREE_SEND_XFRAME(xbus, frm);
+ XBUS_PUT(xbus);
+ }
+}
+
+static int xbus_command_queue_waitempty(xbus_t *xbus)
+{
+ int ret;
+
+ XBUS_DBG(DEVICES, xbus, "Waiting for command_queue to empty\n");
+ ret = wait_event_interruptible(xbus->command_queue_empty,
+ xframe_queue_count(&xbus->command_queue) == 0);
+ if(ret) {
+ XBUS_ERR(xbus, "waiting for command_queue interrupted!!!\n");
+ }
+ return ret;
+}
+
+int send_cmd_frame(xbus_t *xbus, xframe_t *xframe)
+{
+ static int rate_limit;
+ int ret = 0;
+
+
+ BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
+ if(!xbus_ready(xbus, "Dropped command before queueing")) {
+ ret = -ENODEV;
+ goto err;
+ }
+ if(!XBUS_GET(xbus)) {
+ /* shutting down */
+ ret = -ENODEV;
+ goto err;
+ }
+ if(!xframe_enqueue(&xbus->command_queue, xframe)) {
+ if((rate_limit++ % 1003) == 0) {
+ XBUS_ERR(xbus,
+ "Dropped command xframe. Cannot enqueue (%d)\n",
+ rate_limit);
+ dump_xframe("send_cmd_frame", xbus, xframe, DBG_ANY);
+ }
+ XBUS_PUT(xbus);
+ ret = -E2BIG;
+ goto err;
+ }
+ return 0;
+err:
+ FREE_SEND_XFRAME(xbus, xframe);
+ return ret;
+}
+
+/*------------------------- Receive Tasklet Handling ---------------*/
+
+static void xframe_enqueue_recv(xbus_t *xbus, xframe_t *xframe)
+{
+ int cpu = smp_processor_id();
+
+ BUG_ON(!xbus);
+ xbus->cpu_rcv_intr[cpu]++;
+ if(!xframe_enqueue(&xbus->receive_queue, xframe)) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0)
+ XBUS_ERR(xbus, "Failed to enqueue for receive_tasklet (%d)\n", rate_limit);
+ FREE_RECV_XFRAME(xbus, xframe); /* return to receive_pool */
+ return;
+ }
+ tasklet_schedule(&xbus->receive_tasklet);
+}
+
+/*
+ * process frames in the receive_queue in a tasklet
+ */
+static void receive_tasklet_func(unsigned long data)
+{
+ xbus_t *xbus = (xbus_t *)data;
+ xframe_t *xframe = NULL;
+ int cpu = smp_processor_id();
+
+ BUG_ON(!xbus);
+ xbus->cpu_rcv_tasklet[cpu]++;
+ while((xframe = xframe_dequeue(&xbus->receive_queue)) != NULL) {
+ xframe_receive(xbus, xframe);
+ }
+}
+
+void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe)
+{
+ BUG_ON(!xbus);
+ if(rx_tasklet) {
+ xframe_enqueue_recv(xbus, xframe);
+ } else {
+ if (likely(TRANSPORT_RUNNING(xbus)))
+ xframe_receive(xbus, xframe);
+ else
+ FREE_RECV_XFRAME(xbus, xframe); /* return to receive_pool */
+ }
+}
+
+/*------------------------- Bus Management -------------------------*/
+xpd_t *xpd_of(const xbus_t *xbus, int xpd_num)
+{
+ if(!VALID_XPD_NUM(xpd_num))
+ return NULL;
+ return xbus->xpds[xpd_num];
+}
+
+xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit)
+{
+ if(unit > MAX_UNIT || subunit > MAX_SUBUNIT)
+ return NULL;
+ return xbus->xpds[XPD_IDX(unit,subunit)];
+}
+
+int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd)
+{
+ unsigned int xpd_num = xpd->xbus_idx;
+ unsigned long flags;
+ int ret = 0;
+
+ xbus = get_xbus(xbus->num); /* until unregister */
+ BUG_ON(!xbus);
+ XBUS_DBG(DEVICES, xbus, "XPD #%d (xbus_refcount=%d)\n",
+ xpd_num, refcount_xbus(xbus->num));
+ spin_lock_irqsave(&xbus->lock, flags);
+ if(!VALID_XPD_NUM(xpd_num)) {
+ XBUS_ERR(xbus, "Bad xpd_num = %d\n", xpd_num);
+ ret = -EINVAL;
+ goto out;
+ }
+ if(xbus->xpds[xpd_num] != NULL) {
+ xpd_t *other = xbus->xpds[xpd_num];
+
+ XBUS_ERR(xbus, "xpd_num=%d is occupied by %p (%s)\n",
+ xpd_num, other, other->xpdname);
+ ret = -EINVAL;
+ goto out;
+ }
+ xbus->xpds[xpd_num] = xpd;
+ xpd->xbus = xbus;
+ xbus->num_xpds++;
+out:
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ return ret;
+}
+
+int xbus_unregister_xpd(xbus_t *xbus, xpd_t *xpd)
+{
+ unsigned int xpd_num = xpd->xbus_idx;
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&xbus->lock, flags);
+ XBUS_DBG(DEVICES, xbus, "XPD #%d (xbus_refcount=%d)\n",
+ xpd_num, refcount_xbus(xbus->num));
+ if(!VALID_XPD_NUM(xpd_num)) {
+ XBUS_ERR(xbus, "%s: Bad xpd_num = %d\n", __FUNCTION__, xpd_num);
+ goto out;
+ }
+ if(xbus->xpds[xpd_num] == NULL) {
+ XBUS_ERR(xbus, "%s: slot xpd_num=%d is empty\n", __FUNCTION__, xpd_num);
+ goto out;
+ }
+ if(xbus->xpds[xpd_num] != xpd) {
+ xpd_t *other = xbus->xpds[xpd_num];
+
+ XBUS_ERR(xbus, "%s: slot xpd_num=%d is occupied by %p (%s)\n",
+ __FUNCTION__, xpd_num, other, other->xpdname);
+ goto out;
+ }
+ xbus->xpds[xpd_num] = NULL;
+ xbus->num_xpds--;
+ xpd->xbus = NULL;
+ put_xbus(xbus); /* we got it in xbus_register_xpd() */
+ ret = 0;
+out:
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ return ret;
+}
+
+/*
+ * Called with xbus->worker locked.
+ */
+static int new_card(xbus_t *xbus,
+ int unit,
+ byte type,
+ byte subtype,
+ byte numchips,
+ byte ports_per_chip,
+ byte ports,
+ byte port_dir)
+{
+ const xproto_table_t *proto_table;
+ const xops_t *xops;
+ int i;
+ int subunits;
+ int ret = 0;
+
+ proto_table = xproto_get(type);
+ if(!proto_table) {
+ XBUS_NOTICE(xbus,
+ "CARD %d: missing protocol table for type %d. Ignored.\n",
+ unit, type);
+ return -EINVAL;
+ }
+ subunits = (ports + proto_table->ports_per_subunit - 1) /
+ proto_table->ports_per_subunit;
+ XBUS_DBG(DEVICES, xbus, "CARD %d type=%d.%d ports=%d (%dx%d), %d subunits, port-dir=0x%02X\n",
+ unit,
+ type,
+ subtype,
+ ports,
+ numchips,
+ ports_per_chip,
+ subunits,
+ port_dir
+ );
+ xops = &proto_table->xops;
+ BUG_ON(!xops);
+ xbus->worker->num_units += subunits - 1;
+ for(i = 0; i < subunits; i++) {
+ if(!TRANSPORT_RUNNING(xbus)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ XBUS_DBG(DEVICES, xbus, "Creating XPD=%d%d type=%d.%d\n",
+ unit,
+ i,
+ type,
+ subtype);
+ if(!XBUS_GET(xbus)) {
+ XBUS_ERR(xbus, "Aborting creation. Is shutting down.\n");
+ ret = -ENODEV;
+ goto out;
+ }
+ ret = create_xpd(xbus, proto_table, unit, i, type, subtype, subunits, port_dir);
+ XBUS_PUT(xbus);
+ if(ret < 0) {
+ XBUS_ERR(xbus, "Creation of XPD=%d%d failed %d\n",
+ unit, i, ret);
+ goto out;
+ }
+ xbus->worker->num_units_initialized++;
+ }
+out:
+ xproto_put(proto_table); /* ref count is inside the xpds now */
+ return ret;
+}
+
+static int xbus_initialize(xbus_t *xbus)
+{
+ int unit;
+ int subunit;
+ xpd_t *xpd;
+
+ for(unit = 0; unit < MAX_UNIT; unit++) {
+ xpd = xpd_byaddr(xbus, unit, 0);
+ if(!xpd)
+ continue;
+ if(run_initialize_registers(xpd) < 0) {
+ XPD_ERR(xpd, "Register Initialization failed\n");
+ goto err;
+ }
+ for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) {
+ xpd = xpd_byaddr(xbus, unit, subunit);
+ if(!xpd)
+ continue;
+ if(CALL_XMETHOD(card_init, xpd->xbus, xpd) < 0) {
+ XPD_ERR(xpd, "Card Initialization failed\n");
+ goto err;
+ }
+ //CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 0); /* Turn off all channels */
+ xpd->card_present = 1;
+ CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1); /* Turn on all channels */
+ XPD_INFO(xpd, "Initialized: %s\n", xpd->type_name);
+ xpd_post_init(xpd);
+ }
+ }
+ return 0;
+err:
+ for(unit = 0; unit < MAX_UNIT; unit++) {
+ for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) {
+ xpd = xpd_byaddr(xbus, unit, subunit);
+ if(!xpd)
+ xpd_free(xpd);
+ }
+ }
+ return -EINVAL;
+}
+
+/*
+ * This must be called from synchronous (non-interrupt) context
+ * it returns only when all XPD's on the bus are detected and
+ * initialized.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+void xbus_populate(struct work_struct *work)
+{
+ struct xbus_workqueue *worker = container_of(work, struct xbus_workqueue, xpds_init_work);
+#else
+void xbus_populate(void *data)
+{
+ struct xbus_workqueue *worker = data;
+#endif
+ xbus_t *xbus;
+ struct list_head *card;
+ struct list_head *next_card;
+ unsigned long flags;
+ int ret = 0;
+
+ xbus = worker->xbus;
+ if(!XBUS_GET(xbus)) {
+ XBUS_NOTICE(xbus, "Shutting down, aboring initialization\n");
+ return;
+ }
+ spin_lock_irqsave(&worker->worker_lock, flags);
+ list_for_each_safe(card, next_card, &worker->card_list) {
+ struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list);
+
+ list_del(card);
+ BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
+ /* Release/Reacquire locks around blocking calls */
+ spin_unlock_irqrestore(&xbus->worker->worker_lock, flags);
+ ret = new_card(xbus,
+ card_desc->xpd_addr.unit,
+ card_desc->type,
+ card_desc->subtype,
+ card_desc->numchips,
+ card_desc->ports_per_chip,
+ card_desc->ports,
+ card_desc->port_dir);
+ spin_lock_irqsave(&xbus->worker->worker_lock, flags);
+ KZFREE(card_desc);
+ if(ret)
+ break;
+ }
+ spin_unlock_irqrestore(&worker->worker_lock, flags);
+ xbus_initialize(xbus);
+ worker->xpds_init_done = 1;
+ ret = xbus_sysfs_create(xbus);
+ if(ret) {
+ XBUS_ERR(xbus, "SYSFS creation failed: %d\n", ret);
+ }
+ wake_up(&worker->wait_for_xpd_initialization);
+ /*
+ * Now request Astribank to start self_ticking.
+ * This is the last initialization command. So
+ * all others will reach the device before it.
+ */
+ xbus_request_sync(xbus, SYNC_MODE_PLL);
+ elect_syncer("xbus_poll(end)"); /* FIXME: try to do it later */
+ put_xbus(xbus); /* taken in AB_DESCRIPTION */
+ XBUS_PUT(xbus);
+}
+
+static void worker_destroy(struct xbus_workqueue *worker)
+{
+ xbus_t *xbus;
+ struct list_head *card;
+ struct list_head *next_card;
+ unsigned long flags;
+
+ if(!worker)
+ return;
+ spin_lock_irqsave(&worker->worker_lock, flags);
+ xbus = worker->xbus;
+ list_for_each_safe(card, next_card, &worker->card_list) {
+ struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list);
+
+ BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
+ list_del(card);
+ kfree(card_desc);
+ }
+ spin_unlock_irqrestore(&worker->worker_lock, flags);
+ if(xbus) {
+#ifdef CONFIG_PROC_FS
+ if(xbus->proc_xbus_dir && worker->proc_xbus_waitfor_xpds) {
+ XBUS_DBG(PROC, xbus, "Removing proc '%s'\n", PROC_XBUS_WAITFOR_XPDS);
+ remove_proc_entry(PROC_XBUS_WAITFOR_XPDS, xbus->proc_xbus_dir);
+ worker->proc_xbus_waitfor_xpds = NULL;
+ }
+#endif
+ XBUS_DBG(DEVICES, xbus, "detach worker\n");
+ xbus->worker = NULL;
+ }
+ if (worker->wq) {
+ DBG(DEVICES, "XBUS #%d: destroy workqueue\n", worker->xbus->num);
+ flush_workqueue(worker->wq);
+ destroy_workqueue(worker->wq);
+ worker->wq = NULL;
+ }
+ put_xbus(xbus); /* Taken in worker_new() */
+ KZFREE(worker);
+}
+
+/*
+ * Allocate a worker for the xbus including the nessessary workqueue.
+ * May call blocking operations, but only briefly (as we are called
+ * from xbus_new() which is called from khubd.
+ */
+static struct xbus_workqueue *worker_new(int xbus_num)
+{
+ struct xbus_workqueue *worker;
+ xbus_t *xbus;
+
+ xbus = get_xbus(xbus_num); /* release in worker_destroy */
+ BUG_ON(xbus->busname[0] == '\0'); /* No name? */
+ BUG_ON(xbus->worker != NULL); /* Hmmm... nested workers? */
+ XBUS_DBG(DEVICES, xbus, "\n");
+ worker = KZALLOC(sizeof(*worker), GFP_KERNEL);
+ if(!worker)
+ goto err;
+ worker->xbus = xbus;
+ /* poll related variables */
+ spin_lock_init(&worker->worker_lock);
+ INIT_LIST_HEAD(&worker->card_list);
+ init_waitqueue_head(&worker->wait_for_xpd_initialization);
+ worker->wq = create_singlethread_workqueue(xbus->busname);
+ if(!worker->wq) {
+ XBUS_ERR(xbus, "Failed to create worker workqueue.\n");
+ goto err;
+ }
+#ifdef CONFIG_PROC_FS
+ if(xbus->proc_xbus_dir) {
+ worker->proc_xbus_waitfor_xpds = create_proc_read_entry(
+ PROC_XBUS_WAITFOR_XPDS, 0444,
+ xbus->proc_xbus_dir,
+ xbus_read_waitfor_xpds,
+ xbus);
+ if (!worker->proc_xbus_waitfor_xpds) {
+ XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_WAITFOR_XPDS);
+ goto err;
+ }
+ worker->proc_xbus_waitfor_xpds->owner = THIS_MODULE;
+ }
+#endif
+ return worker;
+err:
+ worker_destroy(worker);
+ return NULL;
+}
+
+int xbus_activate(xbus_t *xbus)
+{
+ struct xbus_ops *ops;
+ struct xbus_workqueue *worker;
+
+ BUG_ON(!xbus);
+ ops = transportops_get(xbus);
+ BUG_ON(!ops);
+ worker = xbus->worker;
+ BUG_ON(!worker);
+ /* Sanity checks */
+ BUG_ON(!ops->xframe_send_pcm);
+ BUG_ON(!ops->xframe_send_cmd);
+ BUG_ON(!ops->alloc_xframe);
+ BUG_ON(!ops->free_xframe);
+ xpp_drift_init(xbus);
+ /*
+ * We start with timer based ticking
+ */
+ xbus_set_command_timer(xbus, 1);
+ xbus->transport.transport_running = 1; /* must be done after transport is valid */
+ XBUS_INFO(xbus, "[%s] Activating\n", xbus->label);
+ /*
+ * Make sure Astribank knows not to send us ticks.
+ */
+ xbus_request_sync(xbus, SYNC_MODE_NONE);
+ CALL_PROTO(GLOBAL, AB_REQUEST, xbus, NULL);
+ return 0;
+}
+
+void xbus_disconnect(xbus_t *xbus)
+{
+ int i;
+
+ BUG_ON(!xbus);
+ XBUS_INFO(xbus, "[%s] Disconnecting\n", xbus->label);
+ xbus_set_command_timer(xbus, 1);
+ xbus_request_sync(xbus, SYNC_MODE_NONE); /* no more ticks */
+ xbus_sysfs_remove(xbus); /* Device-Model */
+ for(i = 0; i < MAX_XPDS; i++) {
+ xpd_t *xpd = xpd_of(xbus, i);
+ if(!xpd)
+ continue;
+ if(xpd->xbus_idx != i) {
+ XBUS_ERR(xbus, "BUG: xpd->xbus_idx=%d != i=%d\n", xpd->xbus_idx, i);
+ continue;
+ }
+ xpd_disconnect(xpd);
+ }
+ XBUS_DBG(DEVICES, xbus, "Deactivating\n");
+ tasklet_kill(&xbus->receive_tasklet);
+ xframe_queue_clear(&xbus->receive_queue);
+ xbus_command_queue_clean(xbus);
+ xbus_command_queue_waitempty(xbus);
+ del_timer_sync(&xbus->command_timer);
+ xframe_queue_clear(&xbus->send_pool);
+ xframe_queue_clear(&xbus->receive_pool);
+ xframe_queue_clear(&xbus->pcm_tospan);
+ transportops_put(xbus);
+ transport_destroy(xbus);
+ elect_syncer("disconnect");
+ XBUS_DBG(DEVICES, xbus, "Deactivated (refcount_xbus=%d)\n", refcount_xbus(xbus->num));
+ if(atomic_dec_and_test(&xbus->xbus_ref_count)) {
+ XBUS_DBG(DEVICES, xbus, "Going to remove XBUS\n");
+ xbus_remove(xbus);
+ }
+}
+
+static xbus_t *xbus_alloc(void)
+{
+ unsigned long flags;
+ xbus_t *xbus;
+ int i;
+
+ xbus = KZALLOC(sizeof(xbus_t), GFP_KERNEL);
+ if(!xbus) {
+ ERR("%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ spin_lock_irqsave(&xbuses_lock, flags);
+ for(i = 0; i < MAX_BUSES; i++)
+ if(xbuses_array[i].xbus == NULL)
+ break;
+ if(i >= MAX_BUSES) {
+ ERR("%s: No free slot for new bus. i=%d\n", __FUNCTION__, i);
+ kfree(xbus);
+ xbus = NULL;
+ goto out;
+ }
+ /* Found empty slot */
+ xbus->num = i;
+ init_xbus(i, xbus);
+ xbus = get_xbus(i);
+ bus_count++;
+out:
+ spin_unlock_irqrestore(&xbuses_lock, flags);
+ return xbus;
+}
+
+
+static void xbus_free(xbus_t *xbus)
+{
+ unsigned long flags;
+ uint num;
+
+ if(!xbus)
+ return;
+ spin_lock_irqsave(&xbuses_lock, flags);
+ num = xbus->num;
+ BUG_ON(!xbuses_array[num].xbus);
+ BUG_ON(xbus != xbuses_array[num].xbus);
+ spin_unlock_irqrestore(&xbuses_lock, flags);
+#ifdef XPP_DEBUGFS
+ if(xbus->debugfs_dir) {
+ if(xbus->debugfs_file) {
+ XBUS_DBG(GENERAL, xbus, "Removing debugfs file\n");
+ debugfs_remove(xbus->debugfs_file);
+ }
+ XBUS_DBG(GENERAL, xbus, "Removing debugfs directory\n");
+ debugfs_remove(xbus->debugfs_dir);
+ }
+#endif
+#ifdef CONFIG_PROC_FS
+ if(xbus->proc_xbus_dir) {
+ if(xbus->proc_xbus_summary) {
+ XBUS_DBG(PROC, xbus, "Removing proc '%s'\n", PROC_XBUS_SUMMARY);
+ remove_proc_entry(PROC_XBUS_SUMMARY, xbus->proc_xbus_dir);
+ xbus->proc_xbus_summary = NULL;
+ }
+#ifdef PROTOCOL_DEBUG
+ if(xbus->proc_xbus_command) {
+ XBUS_DBG(PROC, xbus, "Removing proc '%s'\n", PROC_XBUS_COMMAND);
+ remove_proc_entry(PROC_XBUS_COMMAND, xbus->proc_xbus_dir);
+ xbus->proc_xbus_command = NULL;
+ }
+#endif
+ XBUS_DBG(PROC, xbus, "Removing proc directory\n");
+ remove_proc_entry(xbus->busname, xpp_proc_toplevel);
+ xbus->proc_xbus_dir = NULL;
+ }
+#endif
+ spin_lock_irqsave(&xbuses_lock, flags);
+ /*
+ * Return to xbus reference counts:
+ * - One from our caller: transport disconnect or xpp_close()
+ * - One from xbus_alloc()
+ */
+ put_xbus(xbus);
+ put_xbus(xbus);
+ if(!wait_for_xbus_release(xbus->num))
+ BUG(); /* Let's see what happens next... */
+ bus_count--;
+ XBUS_DBG(DEVICES, xbus, "Going to free... refcount_xbus=%d\n", refcount_xbus(num));
+ BUG_ON(refcount_xbus(num) != 0);
+ init_xbus(num, NULL);
+ spin_unlock_irqrestore(&xbuses_lock, flags);
+ KZFREE(xbus);
+}
+
+xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv)
+{
+ int err;
+ xbus_t *xbus = NULL;
+
+ BUG_ON(!ops);
+ XBUS_DBG(GENERAL, xbus, "allocate new xbus\n");
+ xbus = xbus_alloc();
+ if(!xbus)
+ return NULL;
+ transport_init(xbus, ops, max_send_size, priv);
+ spin_lock_init(&xbus->lock);
+ atomic_set(&xbus->xbus_ref_count, 1); /* a single ref */
+ snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%02d", xbus->num);
+ init_waitqueue_head(&xbus->command_queue_empty);
+ init_timer(&xbus->command_timer);
+ atomic_set(&xbus->pcm_rx_counter, 0);
+ xbus->min_tx_sync = INT_MAX;
+ xbus->min_rx_sync = INT_MAX;
+
+ xbus->num_xpds = 0;
+ xbus->sync_mode = SYNC_MODE_NONE;
+ init_rwsem(&xbus->in_use);
+ xbus_reset_counters(xbus);
+#ifdef CONFIG_PROC_FS
+ XBUS_DBG(PROC, xbus, "Creating xbus proc directory\n");
+ xbus->proc_xbus_dir = proc_mkdir(xbus->busname, xpp_proc_toplevel);
+ if(!xbus->proc_xbus_dir) {
+ XBUS_ERR(xbus, "Failed to create proc directory\n");
+ err = -EIO;
+ goto nobus;
+ }
+ xbus->proc_xbus_summary = create_proc_read_entry(PROC_XBUS_SUMMARY,
+ 0444, xbus->proc_xbus_dir,
+ xbus_read_proc,
+ (void *)((unsigned long)(xbus->num)));
+ if (!xbus->proc_xbus_summary) {
+ XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_SUMMARY);
+ err = -EIO;
+ goto nobus;
+ }
+ xbus->proc_xbus_summary->owner = THIS_MODULE;
+#ifdef PROTOCOL_DEBUG
+ xbus->proc_xbus_command = create_proc_entry(PROC_XBUS_COMMAND, 0200, xbus->proc_xbus_dir);
+ if (!xbus->proc_xbus_command) {
+ XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_COMMAND);
+ err = -EIO;
+ goto nobus;
+ }
+ xbus->proc_xbus_command->write_proc = proc_xbus_command_write;
+ xbus->proc_xbus_command->data = xbus;
+ xbus->proc_xbus_command->owner = THIS_MODULE;
+#endif
+#endif
+#ifdef XPP_DEBUGFS
+ xbus->debugfs_dir = debugfs_create_dir(xbus->busname, debugfs_root);
+ if(!xbus->debugfs_dir) {
+ XBUS_ERR(xbus, "Failed to create debugfs directory\n");
+ goto nobus;
+ }
+ xbus->debugfs_file = debugfs_create_file("dchannel", S_IFREG|S_IRUGO|S_IWUSR, xbus->debugfs_dir, xbus, &debugfs_operations);
+ if(!xbus->debugfs_file) {
+ XBUS_ERR(xbus, "Failed to create dchannel file\n");
+ goto nobus;
+ }
+#endif
+ xframe_queue_init(&xbus->command_queue, 10, 100, "command_queue", xbus);
+ xframe_queue_init(&xbus->receive_queue, 10, 50, "receive_queue", xbus);
+ xframe_queue_init(&xbus->send_pool, 10, 200, "send_pool", xbus);
+ xframe_queue_init(&xbus->receive_pool, 10, 50, "receive_pool", xbus);
+ xframe_queue_init(&xbus->pcm_tospan, 5, 10, "pcm_tospan", xbus);
+ tasklet_init(&xbus->receive_tasklet, receive_tasklet_func, (unsigned long)xbus);
+ /*
+ * Create worker after /proc/XBUS-?? so the directory exists
+ * before /proc/XBUS-??/waitfor_xpds tries to get created.
+ */
+ xbus->worker = worker_new(xbus->num);
+ if(!xbus->worker) {
+ ERR("Failed to allocate worker\n");
+ goto nobus;
+ }
+ return xbus;
+nobus:
+ xbus_free(xbus);
+ return NULL;
+}
+
+void xbus_remove(xbus_t *xbus)
+{
+ int i;
+
+ BUG_ON(TRANSPORT_RUNNING(xbus));
+ down_write(&xbus->in_use);
+
+ XBUS_INFO(xbus, "[%s] Removing\n", xbus->label);
+ for(i = 0; i < MAX_XPDS; i++) {
+ xpd_t *xpd = xpd_of(xbus, i);
+
+ if(xpd) {
+ if(xpd->xbus_idx != i) {
+ XBUS_ERR(xbus, "BUG: xpd->xbus_idx=%d != i=%d\n", xpd->xbus_idx, i);
+ continue;
+ }
+ XBUS_DBG(DEVICES, xbus, " Removing xpd #%d\n", i);
+ xpd_remove(xpd);
+ }
+ xbus->xpds[i] = NULL;
+ }
+ worker_destroy(xbus->worker);
+ xbus_free(xbus);
+}
+
+/*------------------------- Proc handling --------------------------*/
+
+void xbus_reset_counters(xbus_t *xbus)
+{
+ int i;
+
+ XBUS_DBG(GENERAL, xbus, "Reseting counters\n");
+ for(i = 0; i < XBUS_COUNTER_MAX; i++) {
+ xbus->counters[i] = 0;
+ }
+}
+
+#if CONFIG_PROC_FS
+
+static int xbus_fill_proc_queue(char *p, struct xframe_queue *q)
+{
+ int len;
+
+ len = sprintf(p,
+ "%-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n",
+ q->name,
+ q->steady_state_count,
+ q->count,
+ q->max_count,
+ q->worst_count,
+ q->overflows,
+ q->worst_lag_usec / 1000,
+ q->worst_lag_usec % 1000);
+ xframe_queue_clearstats(q);
+ return len;
+}
+
+static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ xbus_t *xbus;
+ struct xbus_workqueue *worker;
+ unsigned long flags;
+ int len = 0;
+ int i = (int)((unsigned long)data);
+
+ xbus = get_xbus(i);
+ if(!xbus)
+ goto out;
+ spin_lock_irqsave(&xbus->lock, flags);
+ worker = xbus->worker;
+
+ len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
+ xbus->busname,
+ xbus->location,
+ xbus->label,
+ (TRANSPORT_RUNNING(xbus)) ? "connected" : "missing"
+ );
+ len += sprintf(page + len, "\nxbus_ref_count=%d\n",
+ atomic_read(&xbus->xbus_ref_count)
+ );
+ len += xbus_fill_proc_queue(page + len, &xbus->send_pool);
+ len += xbus_fill_proc_queue(page + len, &xbus->receive_pool);
+ len += xbus_fill_proc_queue(page + len, &xbus->command_queue);
+ len += xbus_fill_proc_queue(page + len, &xbus->receive_queue);
+ len += xbus_fill_proc_queue(page + len, &xbus->pcm_tospan);
+ if(rx_tasklet) {
+ len += sprintf(page + len, "\ncpu_rcv_intr: ");
+ for_each_online_cpu(i)
+ len += sprintf(page + len, "%5d ", xbus->cpu_rcv_intr[i]);
+ len += sprintf(page + len, "\ncpu_rcv_tasklet: ");
+ for_each_online_cpu(i)
+ len += sprintf(page + len, "%5d ", xbus->cpu_rcv_tasklet[i]);
+ len += sprintf(page + len, "\n");
+ }
+ len += sprintf(page + len, "self_ticking: %d (last_tick at %ld)\n",
+ xbus->self_ticking, xbus->ticker.last_sample.tv.tv_sec);
+ len += sprintf(page + len, "xbus: pcm_rx_counter = %d, frag = %d\n",
+ atomic_read(&xbus->pcm_rx_counter), xbus->xbus_frag_count);
+ len += sprintf(page + len, "max_rx_process = %2ld.%ld ms\n",
+ xbus->max_rx_process / 1000,
+ xbus->max_rx_process % 1000);
+ xbus->max_rx_process = 0;
+ len += sprintf(page + len, "\nTRANSPORT: max_send_size=%d refcount=%d\n",
+ MAX_SEND_SIZE(xbus),
+ atomic_read(&xbus->transport.transport_refcount)
+ );
+ len += sprintf(page + len, "PCM Metrices:\n");
+ len += sprintf(page + len, "\tPCM TX: min=%ld max=%ld\n",
+ xbus->min_tx_sync, xbus->max_tx_sync);
+ len += sprintf(page + len, "\tPCM RX: min=%ld max=%ld\n",
+ xbus->min_rx_sync, xbus->max_rx_sync);
+ len += sprintf(page + len, "COUNTERS:\n");
+ for(i = 0; i < XBUS_COUNTER_MAX; i++) {
+ len += sprintf(page + len, "\t%-15s = %d\n",
+ xbus_counters[i].name, xbus->counters[i]);
+ }
+ len += sprintf(page + len, "<-- len=%d\n", len);
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ put_xbus(xbus);
+out:
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+
+}
+
+static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xbus_t *xbus = data;
+ struct xbus_workqueue *worker;
+ int ret;
+
+ if(!xbus)
+ goto out;
+ /* first handle special cases */
+ if(!count || off)
+ goto out;
+ /*
+ * worker is created before /proc/XBUS-??
+ * So by now it exists and initialized.
+ */
+ worker = xbus->worker;
+ BUG_ON(!worker);
+ XBUS_DBG(DEVICES, xbus,
+ "Waiting for card initialization of %d XPD's max %d seconds\n",
+ worker->num_units,
+ INITIALIZATION_TIMEOUT/HZ);
+ /*
+ * when polling is finished xbus_poll():
+ * - Unset worker->is_polling
+ * - Sets worker->count_xpds_to_initialize.
+ * So we wait until polling is finished (is_polling == 0) and:
+ * - No poll answers from Astribank (e.g: defective firmware).
+ * - Or no units to initialize (e.g: mini-AB with only main card).
+ * - Or we finished initializing all existing units.
+ * - Or A timeout passed.
+ */
+ ret = wait_event_interruptible_timeout(
+ worker->wait_for_xpd_initialization,
+ worker->xpds_init_done,
+ INITIALIZATION_TIMEOUT);
+ if(ret == 0) {
+ XBUS_ERR(xbus, "Card Initialization Timeout\n");
+ return ret;
+ } else if(ret < 0) {
+ XBUS_ERR(xbus, "Card Initialization Interrupted %d\n", ret);
+ return ret;
+ } else
+ XBUS_DBG(DEVICES, xbus,
+ "Finished initialization of %d XPD's in %d seconds.\n",
+ worker->num_units_initialized,
+ (INITIALIZATION_TIMEOUT - ret)/HZ);
+ spin_lock_irqsave(&xbus->lock, flags);
+ len += sprintf(page + len, "XPDS_READY: %s: %d/%d\n",
+ xbus->busname,
+ worker->num_units_initialized, worker->num_units);
+ spin_unlock_irqrestore(&xbus->lock, flags);
+out:
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+
+}
+
+#ifdef PROTOCOL_DEBUG
+static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ char *buf;
+ xbus_t *xbus = data;
+ char *p;
+ byte *pack_start;
+ byte *q;
+ xframe_t *xframe;
+ size_t len;
+ const size_t max_len = xbus->transport.max_send_size;
+ const size_t max_text = max_len * 3 + 10;
+
+ if(count > max_text) {
+ XBUS_ERR(xbus, "%s: line too long (%ld > %zd)\n", __FUNCTION__, count, max_len);
+ return -EFBIG;
+ }
+ /* 3 bytes per hex-digit and space */
+ buf = kmalloc(max_text, GFP_KERNEL);
+ if(!buf)
+ return -ENOMEM;
+ if(copy_from_user(buf, buffer, count)) {
+ count = -EINVAL;
+ goto out;
+ }
+ buf[count] = '\0';
+ XBUS_DBG(GENERAL, xbus, "count=%ld\n", count);
+ /*
+ * We replace the content of buf[] from
+ * ascii representation to packet content
+ * as the binary representation is shorter
+ */
+ q = pack_start = buf;
+ for(p = buf; *p;) {
+ int val;
+ char hexdigit[3];
+
+ while(*p && isspace(*p)) // skip whitespace
+ p++;
+ if(!(*p))
+ break;
+ if(!isxdigit(*p)) {
+ XBUS_ERR(xbus, "%s: bad hex value ASCII='0x%X' at position %ld\n",
+ __FUNCTION__, *p, (long)(p - buf));
+ count = -EINVAL;
+ goto out;
+ }
+ hexdigit[0] = *p++;
+ hexdigit[1] = '\0';
+ hexdigit[2] = '\0';
+ if(isxdigit(*p))
+ hexdigit[1] = *p++;
+ if(sscanf(hexdigit, "%2X", &val) != 1) {
+ XBUS_ERR(xbus, "%s: bad hex value '%s' at position %ld\n",
+ __FUNCTION__, hexdigit, (long)(p - buf));
+ count = -EINVAL;
+ goto out;
+ }
+ *q++ = val;
+ XBUS_DBG(GENERAL, xbus, "%3zd> '%s' val=%d\n", q - pack_start, hexdigit, val);
+ }
+ len = q - pack_start;
+ xframe = ALLOC_SEND_XFRAME(xbus);
+ if(!xframe) {
+ count = -ENOMEM;
+ goto out;
+ }
+ if(len > max_len)
+ len = max_len;
+ atomic_set(&xframe->frame_len, len);
+ memcpy(xframe->packets, pack_start, len); /* FIXME: checksum? */
+ dump_xframe("COMMAND", xbus, xframe, debug);
+ send_cmd_frame(xbus, xframe);
+out:
+ kfree(buf);
+ return count;
+}
+#endif
+
+
+static int read_proc_xbuses(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&xbuses_lock, flags);
+ for(i = 0; i < MAX_BUSES; i++) {
+ xbus_t *xbus = get_xbus(i);
+
+ if(xbus) {
+ len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s REFCOUNT=%d\n",
+ xbus->busname,
+ xbus->location,
+ xbus->label,
+ (TRANSPORT_RUNNING(xbus)) ? "connected" : "missing",
+ refcount_xbus(i) - 1
+ );
+ put_xbus(xbus);
+ }
+ }
+#if 0
+ len += sprintf(page + len, "<-- len=%d\n", len);
+#endif
+ spin_unlock_irqrestore(&xbuses_lock, flags);
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+
+}
+#endif
+
+static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, void *priv)
+{
+ BUG_ON(!xbus);
+ BUG_ON(!ops);
+ BUG_ON(!ops->xframe_send_pcm);
+ BUG_ON(!ops->xframe_send_cmd);
+ BUG_ON(!ops->alloc_xframe);
+ BUG_ON(!ops->free_xframe);
+ xbus->transport.ops = ops;
+ xbus->transport.max_send_size = max_send_size;
+ xbus->transport.priv = priv;
+ spin_lock_init(&xbus->transport.lock);
+ atomic_set(&xbus->transport.transport_refcount, 0);
+ init_waitqueue_head(&xbus->transport.transport_unused);
+}
+
+static void transport_destroy(xbus_t *xbus)
+{
+ int ret;
+
+ BUG_ON(!xbus);
+ xbus->transport.transport_running = 0;
+ XBUS_DBG(DEVICES, xbus, "Waiting... (transport_refcount=%d)\n",
+ atomic_read(&xbus->transport.transport_refcount));
+ ret = wait_event_interruptible(xbus->transport.transport_unused,
+ atomic_read(&xbus->transport.transport_refcount) == 0);
+ if(ret)
+ XBUS_ERR(xbus, "Waiting for transport_refcount interrupted!!!\n");
+ xbus->transport.ops = NULL;
+ xbus->transport.priv = NULL;
+}
+
+struct xbus_ops *transportops_get(xbus_t *xbus)
+{
+ struct xbus_ops *ops;
+
+ BUG_ON(!xbus);
+ atomic_inc(&xbus->transport.transport_refcount);
+ ops = xbus->transport.ops;
+ if(!ops)
+ atomic_dec(&xbus->transport.transport_refcount);
+ /* fall through */
+ return ops;
+}
+
+void transportops_put(xbus_t *xbus)
+{
+ struct xbus_ops *ops;
+
+ BUG_ON(!xbus);
+ ops = xbus->transport.ops;
+ BUG_ON(!ops);
+ if(atomic_dec_and_test(&xbus->transport.transport_refcount))
+ wake_up(&xbus->transport.transport_unused);
+}
+
+/*------------------------- Initialization -------------------------*/
+static void xbus_core_cleanup(void)
+{
+ finalize_xbuses_array();
+#ifdef XPP_DEBUGFS
+ if(debugfs_root) {
+ DBG(GENERAL, "Removing xpp from debugfs\n");
+ debugfs_remove(debugfs_root);
+ }
+#endif
+#ifdef CONFIG_PROC_FS
+ if(proc_xbuses) {
+ DBG(PROC, "Removing " PROC_XBUSES " from proc\n");
+ remove_proc_entry(PROC_XBUSES, xpp_proc_toplevel);
+ proc_xbuses = NULL;
+ }
+#endif
+}
+
+int __init xbus_core_init(void)
+{
+ int ret = 0;
+
+ initialize_xbuses_array();
+#ifdef PROTOCOL_DEBUG
+ INFO("FEATURE: with PROTOCOL_DEBUG\n");
+#endif
+#ifdef XPP_DEBUGFS
+ INFO("FEATURE: with XPP_DEBUGFS support\n");
+#endif
+#ifdef CONFIG_PROC_FS
+ proc_xbuses = create_proc_read_entry(PROC_XBUSES, 0444, xpp_proc_toplevel, read_proc_xbuses, NULL);
+ if (!proc_xbuses) {
+ ERR("Failed to create proc file %s\n", PROC_XBUSES);
+ ret = -EFAULT;
+ goto err;
+ }
+ proc_xbuses->owner = THIS_MODULE;
+#endif
+#ifdef XPP_DEBUGFS
+ DBG(GENERAL, "Creating debugfs xpp root\n");
+ debugfs_root = debugfs_create_dir("xpp", NULL);
+ if(!debugfs_root) {
+ ERR("Failed to create debugfs root\n");
+ ret = -EFAULT;
+ goto err;
+ }
+#endif
+ if((ret = register_xpp_bus()) < 0)
+ goto err;
+ return 0;
+err:
+ xbus_core_cleanup();
+ return ret;
+}
+
+
+void __exit xbus_core_shutdown(void)
+{
+ int i;
+
+ for(i = 0; i < MAX_BUSES; i++) {
+ xbus_t *xbus = get_xbus(i);
+
+ if(xbus) {
+ xbus_remove(xbus);
+ }
+ }
+ BUG_ON(bus_count);
+ unregister_xpp_bus();
+ xbus_core_cleanup();
+}
+
+EXPORT_SYMBOL(xpd_of);
+EXPORT_SYMBOL(xpd_byaddr);
+EXPORT_SYMBOL(get_xbus);
+EXPORT_SYMBOL(put_xbus);
+EXPORT_SYMBOL(xbus_new);
+EXPORT_SYMBOL(xbus_remove);
+EXPORT_SYMBOL(xbus_activate);
+EXPORT_SYMBOL(xbus_disconnect);
+EXPORT_SYMBOL(xbus_receive_xframe);
+EXPORT_SYMBOL(xbus_reset_counters);
+EXPORT_SYMBOL(xframe_next_packet);
+EXPORT_SYMBOL(dump_xframe);
+EXPORT_SYMBOL(send_pcm_frame);
+EXPORT_SYMBOL(send_cmd_frame);
+EXPORT_SYMBOL(xframe_init);
+EXPORT_SYMBOL(transportops_get);
+EXPORT_SYMBOL(transportops_put);
+EXPORT_SYMBOL(xbus_command_queue_tick);
+#ifdef XPP_DEBUGFS
+EXPORT_SYMBOL(xbus_log);
+#endif
diff --git a/drivers/dahdi/xpp/xbus-core.h b/drivers/dahdi/xpp/xbus-core.h
new file mode 100644
index 0000000..85fac80
--- /dev/null
+++ b/drivers/dahdi/xpp/xbus-core.h
@@ -0,0 +1,305 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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.
+ *
+ */
+#ifndef XBUS_CORE_H
+#define XBUS_CORE_H
+
+#include <linux/wait.h>
+#include <linux/interrupt.h> /* for tasklets */
+#include "xpd.h"
+#include "xframe_queue.h"
+#include "xbus-pcm.h"
+
+#define MAX_BUSES 32
+#define XFRAME_DATASIZE 512
+
+/* forward declarations */
+struct xbus_workqueue;
+#ifdef XPP_DEBUGFS
+struct debugfs_data;
+#endif
+
+#ifdef __KERNEL__
+
+struct xbus_ops {
+ int (*xframe_send_pcm)(xbus_t *xbus, xframe_t *xframe);
+ int (*xframe_send_cmd)(xbus_t *xbus, xframe_t *xframe);
+ xframe_t *(*alloc_xframe)(xbus_t *xbus, gfp_t gfp_flags);
+ void (*free_xframe)(xbus_t *xbus, xframe_t *xframe);
+};
+
+/*
+ * XBUS statistics counters
+ */
+enum {
+ XBUS_N_UNITS,
+ XBUS_N_TX_XFRAME_PCM,
+ XBUS_N_RX_XFRAME_PCM,
+ XBUS_N_TX_PACK_PCM,
+ XBUS_N_RX_PACK_PCM,
+ XBUS_N_TX_BYTES,
+ XBUS_N_RX_BYTES,
+ XBUS_N_TX_PCM_FRAG,
+ XBUS_N_RX_CMD,
+ XBUS_N_TX_CMD,
+};
+
+#define XBUS_COUNTER(xbus, counter) ((xbus)->counters[XBUS_N_ ## counter])
+
+#define C_(x) [ XBUS_N_ ## x ] = { #x }
+
+/* yucky, make an instance so we can size it... */
+static struct xbus_counters {
+ char *name;
+} xbus_counters[] = {
+ C_(UNITS),
+ C_(TX_XFRAME_PCM),
+ C_(RX_XFRAME_PCM),
+ C_(TX_PACK_PCM),
+ C_(RX_PACK_PCM),
+ C_(TX_BYTES),
+ C_(RX_BYTES),
+ C_(TX_PCM_FRAG),
+ C_(RX_CMD),
+ C_(TX_CMD),
+};
+
+#undef C_
+
+#define XBUS_COUNTER_MAX ARRAY_SIZE(xbus_counters)
+
+struct xbus_transport {
+ struct xbus_ops *ops;
+ void *priv;
+ ushort max_send_size;
+ bool transport_running; /* Hardware is functional */
+ atomic_t transport_refcount;
+ wait_queue_head_t transport_unused;
+ spinlock_t lock;
+};
+
+#define MAX_SEND_SIZE(xbus) ((xbus)->transport.max_send_size)
+#define TRANSPORT_RUNNING(xbus) ((xbus)->transport.transport_running)
+#define TRANSPORT_EXIST(xbus) ((xbus)->transport.ops != NULL)
+
+struct xbus_ops *transportops_get(xbus_t *xbus);
+void transportops_put(xbus_t *xbus);
+
+/*
+ * Encapsulate all poll related data of a single xbus.
+ */
+struct xbus_workqueue {
+ xbus_t *xbus;
+ struct workqueue_struct *wq;
+ struct work_struct xpds_init_work;
+ bool xpds_init_done;
+ struct list_head card_list;
+ int num_units;
+ int num_units_initialized;
+ wait_queue_head_t wait_for_xpd_initialization;
+ struct proc_dir_entry *proc_xbus_waitfor_xpds;
+ spinlock_t worker_lock;
+};
+
+/*
+ * Allocate/Free an xframe from pools of empty xframes.
+ * Calls to {get,put}_xframe are wrapped in
+ * the macros bellow, so we take/return it
+ * to the correct pool.
+ */
+xframe_t *get_xframe(struct xframe_queue *q);
+void put_xframe(struct xframe_queue *q, xframe_t *xframe);
+
+#define ALLOC_SEND_XFRAME(xbus) get_xframe(&(xbus)->send_pool)
+#define ALLOC_RECV_XFRAME(xbus) get_xframe(&(xbus)->receive_pool)
+#define FREE_SEND_XFRAME(xbus, xframe) put_xframe(&(xbus)->send_pool, (xframe))
+#define FREE_RECV_XFRAME(xbus, xframe) put_xframe(&(xbus)->receive_pool, (xframe))
+
+xbus_t *get_xbus(uint num);
+void put_xbus(xbus_t *xbus);
+
+/*
+ * An xbus is a transport layer for Xorcom Protocol commands
+ */
+struct xbus {
+ char busname[XBUS_NAMELEN]; /* set by xbus_new() */
+
+ /* low-level bus drivers set these 2 fields */
+ char location[XBUS_DESCLEN];
+ char label[LABEL_SIZE];
+ byte revision; /* Protocol revision */
+ struct xbus_transport transport;
+
+ int num;
+ struct xpd *xpds[MAX_XPDS];
+
+ struct xframe_queue command_queue;
+ wait_queue_head_t command_queue_empty;
+
+ struct xframe_queue send_pool; /* empty xframes for send */
+ struct xframe_queue receive_pool; /* empty xframes for receive */
+
+ /* tasklet processing */
+ struct xframe_queue receive_queue;
+ struct tasklet_struct receive_tasklet;
+ int cpu_rcv_intr[NR_CPUS];
+ int cpu_rcv_tasklet[NR_CPUS];
+
+ bool self_ticking;
+ enum sync_mode sync_mode;
+ struct timer_list command_timer;
+ unsigned int xbus_frag_count;
+ struct xframe_queue pcm_tospan;
+
+ struct xpp_ticker ticker; /* for tick rate */
+ struct xpp_drift drift; /* for tick offset */
+
+ atomic_t pcm_rx_counter;
+ unsigned int global_counter;
+
+ /* Device-Model */
+ struct device astribank;
+#define dev_to_xbus(dev) container_of(dev, struct xbus, astribank)
+
+ spinlock_t lock;
+ atomic_t xbus_ref_count; /* How many need this struct? */
+
+ /* PCM metrics */
+ struct timeval last_tx_sync;
+ struct timeval last_rx_sync;
+ unsigned long max_tx_sync;
+ unsigned long min_tx_sync;
+ unsigned long max_rx_sync;
+ unsigned long min_rx_sync;
+ unsigned long max_rx_process; /* packet processing time (usec) */
+#ifdef SAMPLE_TICKS
+#define SAMPLE_SIZE 1000
+ int sample_ticks[SAMPLE_SIZE];
+ bool sample_running;
+ int sample_pos;
+#endif
+
+ struct xbus_workqueue *worker;
+
+ /*
+ * Sync adjustment
+ */
+ int sync_adjustment;
+ int sync_adjustment_offset;
+ long pll_updated_at;
+
+ struct rw_semaphore in_use;
+#define XBUS_GET(xbus) down_read_trylock(&(xbus)->in_use)
+#define XBUS_PUT(xbus) up_read(&(xbus)->in_use)
+
+ int num_xpds;
+
+#ifdef XPP_DEBUGFS
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_file;
+ struct debugfs_data *debugfs_data;
+#endif
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc_xbus_dir;
+ struct proc_dir_entry *proc_xbus_summary;
+#ifdef PROTOCOL_DEBUG
+ struct proc_dir_entry *proc_xbus_command;
+#endif
+#endif
+
+ /* statistics */
+ int counters[XBUS_COUNTER_MAX];
+};
+#endif
+
+#define XFRAME_MAGIC 123456L
+
+struct xframe {
+ unsigned long xframe_magic;
+ struct list_head frame_list;
+ atomic_t frame_len;
+ xbus_t *xbus;
+ struct timeval tv_created;
+ struct timeval tv_queued;
+ struct timeval tv_submitted;
+ struct timeval tv_received;
+ /* filled by transport layer */
+ size_t frame_maxlen;
+ byte *packets; /* max XFRAME_DATASIZE */
+ byte *first_free;
+ void *priv;
+};
+
+void xframe_init(xbus_t *xbus, xframe_t *xframe, void *buf, size_t maxsize, void *priv);
+
+#define XFRAME_LEN(frame) atomic_read(&(frame)->frame_len)
+
+int xbus_core_init(void); /* Initializer */
+void xbus_core_shutdown(void); /* Terminator */
+
+#ifdef XPP_DEBUGFS
+/* Debugfs handling */
+int xbus_log(xbus_t *xbus, xpd_t *xpd, int direction, const void *buf, unsigned long len);
+#endif
+
+/* Frame handling */
+void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, int debug);
+int send_cmd_frame(xbus_t *xbus, xframe_t *xframe);
+
+/*
+ * Return pointer to next packet slot in the frame
+ * or NULL if the frame is full.
+ */
+xpacket_t *xframe_next_packet(xframe_t *xframe, int len);
+
+/* XBUS handling */
+
+/*
+ * Map: unit+subunit <--> index in xbus->xpds[]
+ */
+#define XPD_IDX(unit,subunit) ((unit) * MAX_SUBUNIT + (subunit))
+#define XBUS_UNIT(idx) ((idx) / MAX_SUBUNIT)
+#define XBUS_SUBUNIT(idx) ((idx) % MAX_SUBUNIT)
+
+xpd_t *xpd_of(const xbus_t *xbus, int xpd_num);
+xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit);
+xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv);
+void xbus_remove(xbus_t *xbus);
+int xbus_activate(xbus_t *xbus);
+void xbus_disconnect(xbus_t *xbus);
+void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+void xbus_populate(struct work_struct *work);
+#else
+void xbus_populate(void *data);
+#endif
+
+int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd);
+int xbus_unregister_xpd(xbus_t *xbus, xpd_t *xpd);
+
+/* sysfs */
+int register_xpp_bus(void);
+void unregister_xpp_bus(void);
+int xbus_sysfs_create(xbus_t *xbus);
+void xbus_sysfs_remove(xbus_t *xbus);
+
+#endif /* XBUS_CORE_H */
+
diff --git a/drivers/dahdi/xpp/xbus-pcm.c b/drivers/dahdi/xpp/xbus-pcm.c
new file mode 100644
index 0000000..6155f35
--- /dev/null
+++ b/drivers/dahdi/xpp/xbus-pcm.c
@@ -0,0 +1,1303 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2007, Xorcom
+ *
+ * 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/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+# warning "This module is tested only with 2.6 kernels"
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "xbus-pcm.h"
+#include "xbus-core.h"
+#include "xpp_zap.h"
+#include "zap_debug.h"
+#include "parport_debug.h"
+
+static const char rcsid[] = "$Id$";
+
+extern int debug;
+#ifdef XPP_EC_CHUNK
+#include "supress/ec_xpp.h"
+DEF_PARM_BOOL(xpp_ec, 0, 0444, "Do we use our own (1) or Zaptel's (0) echo canceller");
+#endif
+#ifdef OPTIMIZE_CHANMUTE
+static DEF_PARM_BOOL(optimize_chanmute, 1, 0644, "Optimize by muting inactive channels");
+#endif
+
+static DEF_PARM(int, disable_pcm, 0, 0644, "Disable all PCM transmissions");
+#ifdef DEBUG_PCMTX
+DEF_PARM(int, pcmtx, -1, 0644, "Forced PCM value to transmit (negative to disable)");
+DEF_PARM(int, pcmtx_chan, 0, 0644, "channel to force PCM value");
+#endif
+static DEF_PARM_BOOL(disable_pll_sync, 0, 0644, "Disable automatic adjustment of AB clocks");
+
+static xbus_t *syncer; /* current syncer */
+static atomic_t xpp_tick_counter = ATOMIC_INIT(0);
+static struct xpp_ticker zaptel_ticker;
+/*
+ * The ref_ticker points to the current referece tick source.
+ * I.e: one of our AB or zaptel_ticker
+ */
+static struct xpp_ticker *ref_ticker = NULL;
+static spinlock_t ref_ticker_lock = SPIN_LOCK_UNLOCKED;
+static bool force_zaptel_sync = 0; /* from "/proc/xpp/sync" */
+static xbus_t *global_ticker;
+static struct xpp_ticker global_ticks_series;
+
+#define PROC_SYNC "sync"
+#define BIG_TICK_INTERVAL 1000
+#define SYNC_ADJ_MAX 63 /* maximal firmware drift unit (63) */
+/*
+ * The USB bulk endpoints have a large jitter in the timing of frames
+ * from the AB to the ehci-hcd. This is because we cannot predict
+ * in which USB micro-frame our data passes. Each micro-frame is
+ * A 125 usec.
+ */
+#define SYNC_ADJ_QUICK 1000
+#define SYNC_ADJ_SLOW 10000
+
+#ifdef ZAPTEL_SYNC_TICK
+static unsigned int zaptel_tick_count = 0;
+#endif
+
+/*------------------------- SYNC Handling --------------------------*/
+
+static void send_drift(xbus_t *xbus, int drift);
+
+static void xpp_ticker_init(struct xpp_ticker *ticker)
+{
+ memset(ticker, 0, sizeof(*ticker));
+ do_gettimeofday(&ticker->last_sample.tv);
+ ticker->first_sample = ticker->last_sample;
+ ticker->cycle = SYNC_ADJ_QUICK;
+ spin_lock_init(&ticker->lock);
+}
+
+static int xpp_ticker_step(struct xpp_ticker *ticker, const struct timeval *t)
+{
+ unsigned long flags;
+ long usec;
+ bool cycled = 0;
+
+ spin_lock_irqsave(&ticker->lock, flags);
+ ticker->last_sample.tv = *t;
+ if((ticker->count % ticker->cycle) == ticker->cycle - 1) { /* rate adjust */
+ usec = (long)usec_diff(
+ &ticker->last_sample.tv,
+ &ticker->first_sample.tv);
+ ticker->first_sample = ticker->last_sample;
+ ticker->tick_period = usec / ticker->cycle;
+ cycled = 1;
+ }
+ ticker->count++;
+ spin_unlock_irqrestore(&ticker->lock, flags);
+ return cycled;
+}
+
+static inline void driftinfo_recalc(struct xpp_drift *driftinfo)
+{
+ driftinfo->delta_max = INT_MIN;
+ driftinfo->delta_min = INT_MAX;
+}
+
+/*
+ * No locking. It is called only from:
+ * - update_sync_master() in a globall spinlock protected code.
+ * - initalization.
+ */
+static inline void xbus_drift_clear(xbus_t *xbus)
+{
+ struct xpp_drift *driftinfo = &xbus->drift;
+
+ driftinfo_recalc(driftinfo);
+ driftinfo->calc_drift = 0;
+ xbus->ticker.cycle = SYNC_ADJ_QUICK;
+}
+
+void xpp_drift_init(xbus_t *xbus)
+{
+ memset(&xbus->drift, 0, sizeof(xbus->drift));
+ spin_lock_init(&xbus->drift.lock);
+ xpp_ticker_init(&xbus->ticker);
+ xbus->drift.wanted_offset = 500;
+ xbus_drift_clear(xbus);
+}
+
+#ifdef SAMPLE_TICKS
+static void sample_tick(xbus_t *xbus, int sample)
+{
+ if(!xbus->sample_running)
+ return;
+ if(xbus->sample_pos < SAMPLE_SIZE)
+ xbus->sample_ticks[xbus->sample_pos++] = sample;
+ else {
+ xbus->sample_running = 0;
+ xbus->sample_pos = 0;
+ }
+}
+#else
+#define sample_tick(x,y)
+#endif
+
+static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv)
+{
+ struct xpp_drift *driftinfo = &xbus->drift;
+ struct xpp_ticker *ticker = &xbus->ticker;
+ unsigned long flags;
+ bool cycled;
+
+ spin_lock_irqsave(&driftinfo->lock, flags);
+ cycled = xpp_ticker_step(&xbus->ticker, tv);
+ if(ref_ticker && syncer && xbus->sync_mode == SYNC_MODE_PLL) {
+ int new_delta_tick = ticker->count - ref_ticker->count;
+ int lost_ticks = new_delta_tick - driftinfo->delta_tick;
+
+ driftinfo->delta_tick = new_delta_tick;
+ if(lost_ticks) {
+ driftinfo->lost_ticks++;
+ driftinfo->lost_tick_count += abs(lost_ticks);
+ XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n",
+ lost_ticks,
+ (abs(lost_ticks) > 1) ? "s": "");
+ ticker->cycle = SYNC_ADJ_QUICK;
+ if(abs(lost_ticks) > 100)
+ ticker->count = ref_ticker->count;
+ } else {
+ long usec_delta;
+ bool nofix = 0;
+
+ usec_delta = (long)usec_diff(
+ &ticker->last_sample.tv,
+ &ref_ticker->last_sample.tv);
+ usec_delta -= driftinfo->wanted_offset;
+ sample_tick(xbus, usec_delta);
+ if(abs(usec_delta) > 300) {
+ /*
+ * We are close to the edge, send a brutal
+ * fix, and skip calculation until next time.
+ */
+ if(usec_delta > 0 && xbus->sync_adjustment > -SYNC_ADJ_MAX) {
+ XBUS_DBG(SYNC, xbus, "Pullback usec_delta=%ld\n", usec_delta);
+ send_drift(xbus, -SYNC_ADJ_MAX); /* emergency push */
+ }
+ if(usec_delta < 0 && xbus->sync_adjustment < SYNC_ADJ_MAX) {
+ XBUS_DBG(SYNC, xbus, "Pushback usec_delta=%ld\n", usec_delta);
+ send_drift(xbus, SYNC_ADJ_MAX); /* emergency push */
+ }
+ ticker->cycle = SYNC_ADJ_QUICK;
+ nofix = 1;
+ } else {
+ /* good data, use it */
+ if(usec_delta > driftinfo->delta_max)
+ driftinfo->delta_max = usec_delta;
+ if(usec_delta < driftinfo->delta_min)
+ driftinfo->delta_min = usec_delta;
+ }
+ if(!nofix && cycled) {
+ int offset = 0;
+
+ driftinfo->median = (driftinfo->delta_max + driftinfo->delta_min) / 2;
+ driftinfo->jitter = driftinfo->delta_max - driftinfo->delta_min;
+ if(abs(driftinfo->median) >= 150) { /* more than 1 usb uframe */
+ int factor = abs(driftinfo->median) / 125;
+
+ factor = 1 + (factor * 8000) / ticker->cycle;
+ if(driftinfo->median > 0)
+ offset = driftinfo->calc_drift - factor;
+ else
+ offset = driftinfo->calc_drift + factor;
+ /* for large median, push some more */
+ if(abs(driftinfo->median) >= 300) { /* more than 2 usb uframes */
+ ticker->cycle = SYNC_ADJ_QUICK;
+ XBUS_NOTICE(xbus,
+ "Back to quick: median=%d\n",
+ driftinfo->median);
+ }
+ } else {
+ ticker->cycle += 500;
+ if(ticker->cycle >= SYNC_ADJ_SLOW)
+ ticker->cycle = SYNC_ADJ_SLOW;
+ }
+ driftinfo->calc_drift = offset;
+ XBUS_DBG(SYNC, xbus,
+ "ADJ: min=%d max=%d jitter=%d median=%d offset=%d\n",
+ driftinfo->delta_min,
+ driftinfo->delta_max,
+ driftinfo->jitter,
+ driftinfo->median,
+ offset);
+ if(offset < -SYNC_ADJ_MAX)
+ offset = -SYNC_ADJ_MAX;
+ if(offset > SYNC_ADJ_MAX)
+ offset = SYNC_ADJ_MAX;
+ xbus->sync_adjustment_offset = offset;
+ if(xbus != syncer && xbus->sync_adjustment != offset)
+ send_drift(xbus, offset);
+ driftinfo_recalc(driftinfo);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&driftinfo->lock, flags);
+}
+
+const char *sync_mode_name(enum sync_mode mode)
+{
+ static const char *sync_mode_names[] = {
+ [SYNC_MODE_AB] = "AB",
+ [SYNC_MODE_NONE] = "NONE",
+ [SYNC_MODE_PLL] = "PLL",
+ [SYNC_MODE_QUERY] = "QUERY",
+ };
+ if(mode >= ARRAY_SIZE(sync_mode_names))
+ return NULL;
+ return sync_mode_names[mode];
+}
+
+static void xpp_set_syncer(xbus_t *xbus, bool on)
+{
+ if(syncer != xbus && on) {
+ XBUS_DBG(SYNC, xbus, "New syncer\n");
+ syncer = xbus;
+ } else if(syncer == xbus && !on) {
+ XBUS_DBG(SYNC, xbus, "Lost syncer\n");
+ syncer = NULL;
+ } else
+ XBUS_DBG(SYNC, xbus, "ignore %s (current syncer: %s)\n",
+ (on)?"ON":"OFF",
+ (syncer) ? syncer->busname : "NO-SYNC");
+}
+
+static void xbus_command_timer(unsigned long param)
+{
+ xbus_t *xbus = (xbus_t *)param;
+ struct timeval now;
+
+ BUG_ON(!xbus);
+ do_gettimeofday(&now);
+ xbus_command_queue_tick(xbus);
+ if(!xbus->self_ticking)
+ mod_timer(&xbus->command_timer, jiffies + 1); /* Must be 1KHz rate */
+}
+
+void xbus_set_command_timer(xbus_t *xbus, bool on)
+{
+ XBUS_DBG(SYNC, xbus, "%s\n", (on)?"ON":"OFF");
+ if(on) {
+ if(!timer_pending(&xbus->command_timer)) {
+ XBUS_DBG(SYNC, xbus, "add_timer\n");
+ xbus->command_timer.function = xbus_command_timer;
+ xbus->command_timer.data = (unsigned long)xbus;
+ xbus->command_timer.expires = jiffies + 1;
+ add_timer(&xbus->command_timer);
+ }
+ } else if(timer_pending(&xbus->command_timer)) {
+ XBUS_DBG(SYNC, xbus, "del_timer\n");
+ del_timer(&xbus->command_timer);
+ }
+}
+
+/*
+ * Called when the Astribank replies to a sync change request
+ */
+void got_new_syncer(xbus_t *xbus, enum sync_mode mode, int drift)
+{
+ unsigned long flags;
+
+ XBUS_DBG(SYNC, xbus, "Mode %s (%d), drift=%d (pcm_rx_counter=%d)\n",
+ sync_mode_name(mode), mode, drift, atomic_read(&xbus->pcm_rx_counter));
+ spin_lock_irqsave(&xbus->lock, flags);
+ xbus->sync_adjustment = (signed char)drift;
+ if(xbus->sync_mode == mode) {
+ XBUS_DBG(SYNC, xbus, "Already in mode '%s'. Ignored\n", sync_mode_name(mode));
+ goto out;
+ }
+ switch(mode) {
+ case SYNC_MODE_AB:
+ xbus->sync_mode = mode;
+ xbus_set_command_timer(xbus, 0);
+ xbus->self_ticking = 1;
+ xpp_set_syncer(xbus, 1);
+ global_ticker = xbus;
+ break;
+ case SYNC_MODE_PLL:
+ xbus->sync_mode = mode;
+ xbus_set_command_timer(xbus, 0);
+ xbus->self_ticking = 1;
+ xpp_set_syncer(xbus, 0);
+ global_ticker = xbus;
+ break;
+ case SYNC_MODE_NONE: /* lost sync source */
+ xbus->sync_mode = mode;
+ xbus_set_command_timer(xbus, 1);
+ xbus->self_ticking = 0;
+ xpp_set_syncer(xbus, 0);
+ break;
+ case SYNC_MODE_QUERY: /* ignore */
+ break;
+ default:
+ XBUS_ERR(xbus, "%s: unknown mode=0x%X\n", __FUNCTION__, mode);
+ }
+out:
+ spin_unlock_irqrestore(&xbus->lock, flags);
+}
+
+void xbus_request_sync(xbus_t *xbus, enum sync_mode mode)
+{
+ BUG_ON(!xbus);
+ XBUS_DBG(SYNC, xbus, "sent request (mode=%d)\n", mode);
+ CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, mode, 0);
+}
+
+static void reset_sync_counters(void)
+{
+ int i;
+
+ //DBG(SYNC, "%d\n", atomic_read(&xpp_tick_counter));
+ for(i = 0; i < MAX_BUSES; i++) {
+ xbus_t *xbus = get_xbus(i);
+
+ if(!xbus)
+ continue;
+ /*
+ * Don't send to non self_ticking Astribanks:
+ * - Maybe they didn't finish initialization
+ * - Or maybe they didn't answer us in the first place
+ (e.g: wrong firmware version, etc).
+ */
+ if (TRANSPORT_RUNNING(xbus) && xbus->self_ticking) {
+ if(XBUS_GET(xbus)) {
+ /* Reset sync LEDs once in a while */
+ CALL_PROTO(GLOBAL, RESET_SYNC_COUNTERS, xbus, NULL);
+ XBUS_PUT(xbus);
+ } else {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0)
+ XBUS_DBG(GENERAL, xbus,
+ "Dropped packet. Is shutting down. (%d)\n", rate_limit);
+ }
+ }
+ put_xbus(xbus);
+ }
+}
+
+static void send_drift(xbus_t *xbus, int drift)
+{
+ struct timeval now;
+ const char *msg;
+
+ BUG_ON(abs(drift) > SYNC_ADJ_MAX);
+ do_gettimeofday(&now);
+ if(drift > xbus->sync_adjustment)
+ msg = "up";
+ else
+ msg = "down";
+ XBUS_DBG(SYNC, xbus, "%sDRIFT adjust %s (%d) (last update %ld seconds ago)\n",
+ (disable_pll_sync) ? "Fake " : "",
+ msg, drift, now.tv_sec - xbus->pll_updated_at);
+ if(!disable_pll_sync)
+ CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_PLL, drift);
+ xbus->pll_updated_at = now.tv_sec;
+}
+
+static void global_tick(void)
+{
+ struct timeval now;
+
+ do_gettimeofday(&now);
+ atomic_inc(&xpp_tick_counter);
+ if((atomic_read(&xpp_tick_counter) % BIG_TICK_INTERVAL) == 0)
+ reset_sync_counters();
+ xpp_ticker_step(&global_ticks_series, &now);
+}
+
+#ifdef ZAPTEL_SYNC_TICK
+int zaptel_sync_tick(struct zt_span *span, int is_master)
+{
+ xpd_t *xpd = span->pvt;
+ static int redundant_ticks; /* for extra spans */
+ struct timeval now;
+
+ if(!force_zaptel_sync)
+ goto noop;
+ do_gettimeofday(&now);
+ BUG_ON(!xpd);
+ /*
+ * Detect if any of our spans is zaptel sync master
+ */
+ if(is_master) {
+ static int rate_limit;
+
+ if(xpd->xbus != syncer && ((rate_limit % 1003) == 0)) {
+ XPD_ERR(xpd,
+ "Zaptel master, but syncer=%s\n",
+ xpd->xbus->busname);
+ }
+ if((rate_limit % 5003) == 0)
+ XPD_NOTICE(xpd, "Zaptel master: ignore ZAPTEL sync\n");
+ rate_limit++;
+ goto noop;
+ }
+ /* Now we know for sure someone else is zaptel sync master */
+ if(syncer) {
+ static int rate_limit;
+
+ if((rate_limit++ % 5003) == 0)
+ XBUS_DBG(SYNC, syncer,
+ "Already a syncer, ignore ZAPTEL sync\n");
+ goto noop;
+ }
+ /* ignore duplicate calls from all our registered spans */
+ if((redundant_ticks++ % total_registered_spans()) != 0) {
+#if 0
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) < 16)
+ XPD_NOTICE(xpd, "boop (%d)\n", zaptel_tick_count);
+#endif
+ goto noop;
+ }
+ xpp_ticker_step(&zaptel_ticker, &now);
+ zaptel_tick_count++;
+ //flip_parport_bit(1);
+ return 0;
+noop:
+ return 0; /* No auto sync from zaptel */
+}
+#endif
+
+/*
+ * called from elect_syncer()
+ * if new_syncer is NULL, than we move all to SYNC_MODE_PLL
+ * for ZAPTEL sync.
+ */
+static void update_sync_master(xbus_t *new_syncer)
+{
+ const char *msg = (force_zaptel_sync) ? "ZAPTEL" : "NO-SYNC";
+ int i;
+ unsigned long flags;
+
+ DBG(SYNC, "%s => %s\n",
+ (syncer) ? syncer->busname : msg,
+ (new_syncer) ? new_syncer->busname : msg);
+ /*
+ * This global locking protects:
+ * - The ref_ticker so it won't be used while we change it.
+ * - The xbus_drift_clear() from corrupting driftinfo data.
+ */
+ spin_lock_irqsave(&ref_ticker_lock, flags);
+ if(syncer)
+ xbus_drift_clear(syncer); /* Clean old data */
+ if(new_syncer) {
+ XBUS_DBG(SYNC, new_syncer, "pcm_rx_counter=%d\n",
+ atomic_read(&new_syncer->pcm_rx_counter));
+ force_zaptel_sync = 0;
+ ref_ticker = &new_syncer->ticker;
+ xbus_drift_clear(new_syncer); /* Clean new data */
+ xbus_request_sync(new_syncer, SYNC_MODE_AB);
+ } else if(force_zaptel_sync) {
+ ref_ticker = &zaptel_ticker;
+ } else {
+ ref_ticker = NULL;
+ }
+ spin_unlock_irqrestore(&ref_ticker_lock, flags);
+ DBG(SYNC, "stop unwanted syncers\n");
+ /* Shut all down except the wanted sync master */
+ for(i = 0; i < MAX_BUSES; i++) {
+ xbus_t *xbus = get_xbus(i);
+ if(!xbus)
+ continue;
+ if(TRANSPORT_RUNNING(xbus) && xbus != new_syncer) {
+ if(xbus->self_ticking)
+ xbus_request_sync(xbus, SYNC_MODE_PLL);
+ else
+ XBUS_DBG(SYNC, xbus, "Not self_ticking yet. Ignore\n");
+ }
+ put_xbus(xbus);
+ }
+}
+
+void elect_syncer(const char *msg)
+{
+ int i;
+ int j;
+ uint timing_priority = 0;
+ xpd_t *best_xpd = NULL;
+ xbus_t *the_xbus = NULL;
+
+ for(i = 0; i < MAX_BUSES; i++) {
+ xbus_t *xbus = get_xbus(i);
+ if(!xbus)
+ continue;
+ if(!the_xbus)
+ the_xbus = xbus;
+ if (TRANSPORT_RUNNING(xbus)) {
+ for(j = 0; j < MAX_XPDS; j++) {
+ xpd_t *xpd = xpd_of(xbus, j);
+
+ if(!xpd || !xpd->card_present)
+ continue;
+ if(xpd->timing_priority > timing_priority) {
+ timing_priority = xpd->timing_priority;
+ best_xpd = xpd;
+ }
+ }
+ }
+ put_xbus(xbus);
+ }
+ if(best_xpd) {
+ the_xbus = best_xpd->xbus;
+ XPD_DBG(SYNC, best_xpd, "%s: elected with priority %d\n", msg, timing_priority);
+ } else if(the_xbus) {
+ XBUS_DBG(SYNC, the_xbus, "%s: elected\n", msg);
+ } else
+ DBG(SYNC, "%s: No more syncers\n", msg);
+ if(the_xbus != syncer)
+ update_sync_master(the_xbus);
+}
+
+/*
+ * This function is used by FXS/FXO. The pcm_mask argument signifies
+ * channels which should be *added* to the automatic calculation.
+ * Normally, this argument is 0.
+ *
+ * The caller should spinlock the XPD before calling it.
+ */
+void __pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask)
+{
+ int i;
+ int line_count = 0;
+
+ XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask);
+ /* Add/remove all the trivial cases */
+ pcm_mask |= xpd->offhook;
+ pcm_mask |= xpd->cid_on;
+ pcm_mask &= ~xpd->digital_signalling; /* No PCM in D-Channels */
+ pcm_mask &= ~xpd->digital_inputs;
+ pcm_mask &= ~xpd->digital_outputs;
+ for_each_line(xpd, i)
+ if(IS_SET(pcm_mask, i))
+ line_count++;
+ /*
+ * FIXME: Workaround a bug in sync code of the Astribank.
+ * Send dummy PCM for sync.
+ */
+ if(xpd->addr.unit == 0 && pcm_mask == 0) {
+ pcm_mask = BIT(0);
+ line_count = 1;
+ }
+ xpd->pcm_len = (line_count)
+ ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE
+ : 0L;
+ xpd->wanted_pcm_mask = pcm_mask;
+}
+
+/*
+ * A spinlocked version of __pcm_recompute()
+ */
+void pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&xpd->lock, flags);
+ __pcm_recompute(xpd, pcm_mask);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+}
+
+void fill_beep(u_char *buf, int num, int duration)
+{
+ bool alternate = (duration) ? (jiffies/(duration*1000)) & 0x1 : 0;
+ int which;
+ u_char *snd;
+
+ /*
+ * debug tones
+ */
+ static u_char beep[] = {
+ 0x7F, 0xBE, 0xD8, 0xBE, 0x80, 0x41, 0x24, 0x41, /* Dima */
+ 0x67, 0x90, 0x89, 0x90, 0xFF, 0x10, 0x09, 0x10, /* Izzy */
+ };
+ static u_char beep_alt[] = {
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, /* silence */
+ };
+ if(alternate) {
+ which = num % ARRAY_SIZE(beep_alt);
+ snd = &beep_alt[which];
+ } else {
+ which = num % ARRAY_SIZE(beep);
+ snd = &beep[which];
+ }
+ memcpy(buf, snd, ZT_CHUNKSIZE);
+}
+
+#ifdef XPP_EC_CHUNK
+/*
+ * Taken from zaptel.c
+ */
+static inline void xpp_ec_chunk(struct zt_chan *chan, unsigned char *rxchunk, const unsigned char *txchunk)
+{
+ int16_t rxlin;
+ int x;
+ unsigned long flags;
+
+ /* Perform echo cancellation on a chunk if necessary */
+ if (!chan->ec)
+ return;
+ spin_lock_irqsave(&chan->lock, flags);
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ rxlin = ZT_XLAW(rxchunk[x], chan);
+ rxlin = xpp_echo_can_update(chan->ec, ZT_XLAW(txchunk[x], chan), rxlin);
+ rxchunk[x] = ZT_LIN2X((int)rxlin, chan);
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+#endif
+
+static void do_ec(xpd_t *xpd)
+{
+#ifdef WITH_ECHO_SUPPRESSION
+ struct zt_chan *chans = xpd->span.chans;
+ int i;
+
+ /* FIXME: need to Echo cancel double buffered data */
+ for (i = 0;i < xpd->span.channels; i++) {
+ if(unlikely(IS_SET(xpd->digital_signalling, i))) /* Don't echo cancel BRI D-chans */
+ continue;
+ if(!IS_SET(xpd->wanted_pcm_mask, i)) /* No ec for unwanted PCM */
+ continue;
+#ifdef XPP_EC_CHUNK
+ /* even if defined, parameterr xpp_ec can override at run-time */
+ if (xpp_ec)
+ xpp_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]);
+ else
+#endif
+ zt_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]);
+ memcpy(xpd->ec_chunk2[i], xpd->ec_chunk1[i], ZT_CHUNKSIZE);
+ memcpy(xpd->ec_chunk1[i], chans[i].writechunk, ZT_CHUNKSIZE);
+ }
+#endif
+}
+
+#if 0
+/* Okay, now we get to the signalling. You have several options: */
+
+/* Option 1: If you're a T1 like interface, you can just provide a
+ rbsbits function and we'll assert robbed bits for you. Be sure to
+ set the ZT_FLAG_RBS in this case. */
+
+/* Opt: If the span uses A/B bits, set them here */
+int (*rbsbits)(struct zt_chan *chan, int bits);
+
+/* Option 2: If you don't know about sig bits, but do have their
+ equivalents (i.e. you can disconnect battery, detect off hook,
+ generate ring, etc directly) then you can just specify a
+ sethook function, and we'll call you with appropriate hook states
+ to set. Still set the ZT_FLAG_RBS in this case as well */
+int (*hooksig)(struct zt_chan *chan, zt_txsig_t hookstate);
+
+/* Option 3: If you can't use sig bits, you can write a function
+ which handles the individual hook states */
+int (*sethook)(struct zt_chan *chan, int hookstate);
+#endif
+
+int xpp_echocan(struct zt_chan *chan, int len)
+{
+#ifdef XPP_EC_CHUNK
+ if(len == 0) { /* shut down */
+ /* zaptel calls this also during channel initialization */
+ if(chan->ec) {
+ xpp_echo_can_free(chan->ec);
+ }
+ return 0;
+ }
+ if(chan->ec) {
+ ERR("%s: Trying to override an existing EC (%p)\n", __FUNCTION__, chan->ec);
+ return -EINVAL;
+ }
+ chan->ec = xpp_echo_can_create(len, 0);
+ if(!chan->ec) {
+ ERR("%s: Failed creating xpp EC (len=%d)\n", __FUNCTION__, len);
+ return -EINVAL;
+ }
+#endif
+ return 0;
+}
+
+static bool pcm_valid(xpd_t *xpd, xpacket_t *pack)
+{
+ xpp_line_t lines = RPACKET_FIELD(pack, GLOBAL, PCM_READ, lines);
+ int i;
+ int count = 0;
+ uint16_t good_len;
+
+ BUG_ON(!pack);
+ BUG_ON(XPACKET_OP(pack) != XPROTO_NAME(GLOBAL, PCM_READ));
+ /*
+ * Don't use for_each_line(xpd, i) here because for BRI it will
+ * ignore the channels of the other xpd's in the same unit.
+ */
+ for (i = 0; i < CHANNELS_PERXPD; i++)
+ if(IS_SET(lines, i))
+ count++;
+ /* FRAMES: include opcode in calculation */
+ good_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + count * 8;
+ if(XPACKET_LEN(pack) != good_len) {
+ static int rate_limit = 0;
+
+ XPD_COUNTER(xpd, RECV_ERRORS)++;
+ if((rate_limit++ % 1000) <= 10) {
+ XPD_ERR(xpd, "BAD PCM REPLY: packet_len=%d (should be %d), count=%d\n",
+ XPACKET_LEN(pack), good_len, count);
+ dump_packet("BAD PCM REPLY", pack, 1);
+ }
+ return 0;
+ }
+ return 1;
+}
+
+
+
+static inline void pcm_frame_out(xbus_t *xbus, xframe_t *xframe)
+{
+ unsigned long flags;
+ struct timeval now;
+ unsigned long usec;
+
+ spin_lock_irqsave(&xbus->lock, flags);
+ do_gettimeofday(&now);
+ if(unlikely(disable_pcm || !TRANSPORT_RUNNING(xbus)))
+ goto dropit;
+ if(XPACKET_ADDR_SYNC((xpacket_t *)xframe->packets)) {
+ usec = usec_diff(&now, &xbus->last_tx_sync);
+ xbus->last_tx_sync = now;
+ /* ignore startup statistics */
+ if(likely(atomic_read(&xbus->pcm_rx_counter) > BIG_TICK_INTERVAL)) {
+ if(abs(usec - 1000) > TICK_TOLERANCE) {
+ static int rate_limit;
+
+ if((rate_limit++ % 5003) == 0)
+ XBUS_DBG(SYNC, xbus, "Bad PCM TX timing(%d): usec=%ld.\n",
+ rate_limit, usec);
+ }
+ if(usec > xbus->max_tx_sync)
+ xbus->max_tx_sync = usec;
+ if(usec < xbus->min_tx_sync)
+ xbus->min_tx_sync = usec;
+ }
+ }
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ /* OK, really send it */
+ if(debug & DBG_PCM )
+ dump_xframe("TX_XFRAME_PCM", xbus, xframe, debug);
+ send_pcm_frame(xbus, xframe);
+ XBUS_COUNTER(xbus, TX_XFRAME_PCM)++;
+ return;
+dropit:
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ FREE_SEND_XFRAME(xbus, xframe);
+}
+
+/*
+ * Generic implementations of card_pcmfromspan()/card_pcmtospan()
+ * For FXS/FXO
+ */
+void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack)
+{
+ byte *pcm;
+ struct zt_chan *chans;
+ unsigned long flags;
+ int i;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ BUG_ON(!pack);
+ RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
+ pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
+ spin_lock_irqsave(&xpd->lock, flags);
+ chans = xpd->span.chans;
+ for (i = 0; i < xpd->channels; i++) {
+ if(IS_SET(lines, i)) {
+ if(SPAN_REGISTERED(xpd)) {
+#ifdef DEBUG_PCMTX
+ if(pcmtx >= 0 && pcmtx_chan == i)
+ memset((u_char *)pcm, pcmtx, ZT_CHUNKSIZE);
+ else
+#endif
+ memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE);
+ // fill_beep((u_char *)pcm, xpd->addr.subunit, 2);
+ } else
+ memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE);
+ pcm += ZT_CHUNKSIZE;
+ }
+ }
+ XPD_COUNTER(xpd, PCM_WRITE)++;
+ spin_unlock_irqrestore(&xpd->lock, flags);
+}
+
+void generic_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
+{
+ byte *pcm;
+ xpp_line_t pcm_mask;
+ unsigned long flags;
+ int i;
+
+ pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm);
+ pcm_mask = RPACKET_FIELD(pack, GLOBAL, PCM_READ, lines);
+ spin_lock_irqsave(&xpd->lock, flags);
+ if(!SPAN_REGISTERED(xpd))
+ goto out;
+ for (i = 0; i < xpd->channels; i++) {
+ volatile u_char *r = xpd->span.chans[i].readchunk;
+
+ if(!IS_SET(xpd->wanted_pcm_mask, i)) {
+ if(IS_SET(xpd->silence_pcm, i)) {
+ memset((u_char *)r, 0x7F, ZT_CHUNKSIZE); // SILENCE
+ memset(xpd->ec_chunk2[i], 0x7F, ZT_CHUNKSIZE);
+ memset(xpd->ec_chunk1[i], 0x7F, ZT_CHUNKSIZE);
+ }
+ continue;
+ }
+ pcm_mask &= ~xpd->mute_dtmf;
+ if(IS_SET(pcm_mask, i)) {
+ // memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG
+ // fill_beep((u_char *)r, 1, 1); // DEBUG: BEEP
+ memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
+ pcm += ZT_CHUNKSIZE;
+ } else {
+ memset((u_char *)r, 0x7F, ZT_CHUNKSIZE); // SILENCE
+ }
+ }
+out:
+ XPD_COUNTER(xpd, PCM_READ)++;
+ spin_unlock_irqrestore(&xpd->lock, flags);
+}
+
+static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe)
+{
+ byte *xframe_end;
+ xpacket_t *pack;
+ byte *p;
+ int ret = -EPROTO; /* Assume error */
+
+ if(debug & DBG_PCM)
+ dump_xframe("RX_XFRAME_PCM", xbus, xframe, debug);
+ /* handle content */
+
+ p = xframe->packets;
+ xframe_end = p + XFRAME_LEN(xframe);
+ do {
+ int len;
+ xpd_t *xpd;
+
+ pack = (xpacket_t *)p;
+ len = XPACKET_LEN(pack);
+ /* Sanity checks */
+ if(unlikely(XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_READ))) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0) {
+ XBUS_NOTICE(xbus,
+ "%s: Non-PCM packet within a PCM xframe. (%d)\n",
+ __FUNCTION__, rate_limit);
+ dump_xframe("In PCM xframe", xbus, xframe, debug);
+ }
+ goto out;
+ }
+ p += len;
+ if(p > xframe_end || len < RPACKET_HEADERSIZE) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0) {
+ XBUS_NOTICE(xbus,
+ "%s: Invalid packet length %d. (%d)\n",
+ __FUNCTION__, len, rate_limit);
+ dump_xframe("BAD LENGTH", xbus, xframe, debug);
+ }
+ goto out;
+ }
+ xpd = xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack));
+ if(unlikely(!xpd)) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0) {
+ notify_bad_xpd(__FUNCTION__, xbus, XPACKET_ADDR(pack), "RECEIVE PCM");
+ dump_xframe("Unknown XPD addr", xbus, xframe, debug);
+ }
+ goto out;
+ }
+ if(!pcm_valid(xpd, pack))
+ goto out;
+ if(SPAN_REGISTERED(xpd)) {
+ XBUS_COUNTER(xbus, RX_PACK_PCM)++;
+ CALL_XMETHOD(card_pcm_tospan, xbus, xpd, pack);
+ }
+ } while(p < xframe_end);
+ ret = 0; /* all good */
+ XBUS_COUNTER(xbus, RX_XFRAME_PCM)++;
+out:
+ FREE_RECV_XFRAME(xbus, xframe);
+ return ret;
+}
+
+static void xbus_tick(xbus_t *xbus)
+{
+ int i;
+ xpd_t *xpd;
+ xframe_t *xframe = NULL;
+ xpacket_t *pack = NULL;
+ size_t pcm_len;
+ bool sent_sync_bit = 0;
+
+ /*
+ * Update zaptel
+ */
+ for(i = 0; i < MAX_XPDS; i++) {
+ xpd = xpd_of(xbus, i);
+ if(xpd && SPAN_REGISTERED(xpd)) {
+#ifdef OPTIMIZE_CHANMUTE
+ int j;
+ xpp_line_t xmit_mask = xpd->wanted_pcm_mask;
+
+ xmit_mask |= xpd->silence_pcm;
+ xmit_mask |= xpd->digital_signalling;
+ for_each_line(xpd, j) {
+ xpd->chans[j].chanmute = (optimize_chanmute)
+ ? !IS_SET(xmit_mask, j)
+ : 0;
+ }
+#endif
+ /*
+ * calls to zt_transmit should be out of spinlocks, as it may call back
+ * our hook setting methods.
+ */
+ zt_transmit(&xpd->span);
+ }
+ }
+ /*
+ * Fill xframes
+ */
+ for(i = 0; i < MAX_XPDS; i++) {
+ if((xpd = xpd_of(xbus, i)) == NULL)
+ continue;
+ pcm_len = xpd->pcm_len;
+ if(SPAN_REGISTERED(xpd)) {
+ if(pcm_len && xpd->card_present) {
+ do {
+ // pack = NULL; /* FORCE single packet frames */
+ if(xframe && !pack) { /* FULL frame */
+ pcm_frame_out(xbus, xframe);
+ xframe = NULL;
+ XBUS_COUNTER(xbus, TX_PCM_FRAG)++;
+ }
+ if(!xframe) { /* Alloc frame */
+ xframe = ALLOC_SEND_XFRAME(xbus);
+ if (!xframe) {
+ static int rate_limit;
+
+ if((rate_limit++ % 3001) == 0)
+ XBUS_ERR(xbus,
+ "%s: failed to allocate new xframe\n",
+ __FUNCTION__);
+ return;
+ }
+ }
+ pack = xframe_next_packet(xframe, pcm_len);
+ } while(!pack);
+ XPACKET_INIT(pack, GLOBAL, PCM_WRITE, xpd->xbus_idx, 1, 0);
+ XPACKET_LEN(pack) = pcm_len;
+ if(!sent_sync_bit) {
+ XPACKET_ADDR_SYNC(pack) = 1;
+ sent_sync_bit = 1;
+ }
+ CALL_XMETHOD(card_pcm_fromspan, xbus, xpd, xpd->wanted_pcm_mask, pack);
+ XBUS_COUNTER(xbus, TX_PACK_PCM)++;
+ }
+ }
+ }
+ if(xframe) /* clean any leftovers */
+ pcm_frame_out(xbus, xframe);
+ /*
+ * Receive PCM
+ */
+ while((xframe = xframe_dequeue(&xbus->pcm_tospan)) != NULL) {
+ copy_pcm_tospan(xbus, xframe);
+ if(XPACKET_ADDR_SYNC((xpacket_t *)xframe->packets)) {
+ struct timeval now;
+ unsigned long usec;
+
+ do_gettimeofday(&now);
+ usec = usec_diff(&now, &xbus->last_rx_sync);
+ xbus->last_rx_sync = now;
+ /* ignore startup statistics */
+ if(likely(atomic_read(&xbus->pcm_rx_counter) > BIG_TICK_INTERVAL)) {
+ if(abs(usec - 1000) > TICK_TOLERANCE) {
+ static int rate_limit;
+
+ if((rate_limit++ % 5003) == 0)
+ XBUS_DBG(SYNC, xbus, "Bad PCM RX timing(%d): usec=%ld.\n",
+ rate_limit, usec);
+ }
+ if(usec > xbus->max_rx_sync)
+ xbus->max_rx_sync = usec;
+ if(usec < xbus->min_rx_sync)
+ xbus->min_rx_sync = usec;
+ }
+ }
+ }
+ for(i = 0; i < MAX_XPDS; i++) {
+ xpd = xpd_of(xbus, i);
+ if(!xpd || !xpd->card_present)
+ continue;
+ if(SPAN_REGISTERED(xpd)) {
+ do_ec(xpd);
+ zt_receive(&xpd->span);
+ }
+ xpd->silence_pcm = 0; /* silence was injected */
+ xpd->timer_count = xbus->global_counter;
+ /*
+ * Must be called *after* tx/rx so
+ * D-Chan counters may be cleared
+ */
+ CALL_XMETHOD(card_tick, xbus, xpd);
+ }
+}
+
+static void do_tick(xbus_t *xbus, const struct timeval *tv_received)
+{
+ int counter = atomic_read(&xpp_tick_counter);
+ unsigned long flags;
+
+ xbus_command_queue_tick(xbus);
+ if(global_ticker == xbus)
+ global_tick(); /* called from here or zaptel_sync_tick() */
+ spin_lock_irqsave(&ref_ticker_lock, flags);
+ xpp_drift_step(xbus, tv_received);
+ spin_unlock_irqrestore(&ref_ticker_lock, flags);
+ if(likely(xbus->self_ticking))
+ xbus_tick(xbus);
+ xbus->global_counter = counter;
+}
+
+void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe)
+{
+ if(!xframe_enqueue(&xbus->pcm_tospan, xframe)) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0)
+ XBUS_DBG(SYNC, xbus,
+ "Failed to enqueue received pcm frame. (%d)\n",
+ rate_limit);
+ FREE_RECV_XFRAME(xbus, xframe);
+ }
+ /*
+ * The sync_master bit is marked at the first packet
+ * of the frame, regardless of the XPD that is sync master.
+ * FIXME: what about PRI split?
+ */
+ if(XPACKET_ADDR_SYNC((xpacket_t *)xframe->packets)) {
+ do_tick(xbus, &xframe->tv_received);
+ atomic_inc(&xbus->pcm_rx_counter);
+ } else
+ xbus->xbus_frag_count++;
+}
+
+#ifdef CONFIG_PROC_FS
+static int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ struct timeval now;
+ unsigned int counter = atomic_read(&xpp_tick_counter);
+ unsigned long usec;
+
+ do_gettimeofday(&now);
+ len += sprintf(page + len, "# To modify sync source write into this file:\n");
+ len += sprintf(page + len, "# ZAPTEL - Another zaptel device provide sync\n");
+ len += sprintf(page + len, "# SYNC=nn - XBUS-nn provide sync\n");
+ len += sprintf(page + len, "# QUERY=nn - Query XBUS-nn for sync information (DEBUG)\n");
+ if(!syncer) {
+ if(force_zaptel_sync)
+ len += sprintf(page + len, "ZAPTEL\n");
+ else
+ len += sprintf(page + len, "NO-SYNC\n");
+ } else
+ len += sprintf(page + len, "SYNC=%02d\n", syncer->num);
+#ifdef ZAPTEL_SYNC_TICK
+ if(force_zaptel_sync) {
+ len += sprintf(page + len,
+ "Zaptel Reference Sync (%d registered spans):\n",
+ total_registered_spans());
+ len += sprintf(page + len, "\tzaptel_tick: #%d\n", zaptel_tick_count);
+ len += sprintf(page + len, "\ttick - zaptel_tick = %d\n",
+ counter - zaptel_tick_count);
+ } else {
+ len += sprintf(page + len,
+ "Zaptel Reference Sync Not activated\n");
+ }
+#endif
+ usec = usec_diff(&now, &global_ticks_series.last_sample.tv);
+ len += sprintf(page + len, "\ntick: #%d\n", counter);
+ len += sprintf(page + len,
+ "tick duration: %d usec (measured %ld.%ld msec ago)\n",
+ global_ticks_series.tick_period,
+ usec / 1000, usec % 1000);
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+}
+
+static int proc_sync_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ char buf[MAX_PROC_WRITE];
+ int xbus_num;
+ int xpd_num;
+ xbus_t *xbus;
+ xpd_t *xpd;
+
+ // DBG(SYNC, "%s: count=%ld\n", __FUNCTION__, count);
+ if(count >= MAX_PROC_WRITE)
+ return -EINVAL;
+ if(copy_from_user(buf, buffer, count))
+ return -EFAULT;
+ buf[count] = '\0';
+ if(strncmp("ZAPTEL", buf, 6) == 0) {
+ DBG(SYNC, "ZAPTEL\n");
+ force_zaptel_sync=1;
+ update_sync_master(NULL);
+ } else if(sscanf(buf, "SYNC=%d", &xbus_num) == 1) {
+ DBG(SYNC, "SYNC=%d\n", xbus_num);
+ if((xbus = get_xbus(xbus_num)) == NULL) {
+ ERR("No bus %d exists\n", xbus_num);
+ return -ENXIO;
+ }
+ update_sync_master(xbus);
+ put_xbus(xbus);
+ } else if(sscanf(buf, "QUERY=%d", &xbus_num) == 1) {
+ DBG(SYNC, "QUERY=%d\n", xbus_num);
+ if((xbus = get_xbus(xbus_num)) == NULL) {
+ ERR("No bus %d exists\n", xbus_num);
+ return -ENXIO;
+ }
+ CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_QUERY, 0);
+ put_xbus(xbus);
+ } else if(sscanf(buf, "%d %d", &xbus_num, &xpd_num) == 2) {
+ NOTICE("Using deprecated syntax to update %s file\n",
+ PROC_SYNC);
+ if(xpd_num != 0) {
+ ERR("Currently can only set sync for XPD #0\n");
+ return -EINVAL;
+ }
+ if((xbus = get_xbus(xbus_num)) == NULL) {
+ ERR("No bus %d exists\n", xbus_num);
+ return -ENXIO;
+ }
+ if((xpd = xpd_of(xbus, xpd_num)) == NULL) {
+ XBUS_ERR(xbus, "No xpd %d exists\n", xpd_num);
+ put_xbus(xbus);
+ return -ENXIO;
+ }
+ update_sync_master(xbus);
+ put_xbus(xbus);
+ } else {
+ ERR("%s: cannot parse '%s'\n", __FUNCTION__, buf);
+ count = -EINVAL;
+ }
+ return count;
+}
+
+static struct proc_dir_entry *top;
+
+#endif
+
+int xbus_pcm_init(struct proc_dir_entry *toplevel)
+{
+ int ret = 0;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *ent;
+#endif
+
+#ifdef OPTIMIZE_CHANMUTE
+ INFO("FEATURE: with CHANMUTE optimization (%sactivated)\n",
+ (optimize_chanmute)?"":"de");
+#endif
+#ifdef WITH_ECHO_SUPPRESSION
+ INFO("FEATURE: with ECHO_SUPPRESSION\n");
+#else
+ INFO("FEATURE: without ECHO_SUPPRESSION\n");
+#endif
+ if(xpp_ec)
+ INFO("FEATURE: with XPP_EC_CHUNK\n");
+ else
+ INFO("FEATURE: without XPP_EC_CHUNK\n");
+#ifdef ZAPTEL_SYNC_TICK
+ INFO("FEATURE: with sync_tick() from ZAPTEL\n");
+#else
+ INFO("FEATURE: without sync_tick() from ZAPTEL\n");
+#endif
+ xpp_ticker_init(&global_ticks_series);
+ xpp_ticker_init(&zaptel_ticker);
+#ifdef CONFIG_PROC_FS
+ top = toplevel;
+ ent = create_proc_entry(PROC_SYNC, 0644, top);
+ if(!ent) {
+ ret = -EFAULT;
+ goto err;
+ }
+ ent->read_proc = proc_sync_read;
+ ent->write_proc = proc_sync_write;
+ ent->data = NULL;
+#endif
+err:
+ return ret;
+}
+
+void xbus_pcm_shutdown(void)
+{
+#ifdef CONFIG_PROC_FS
+ DBG(GENERAL, "Removing '%s' from proc\n", PROC_SYNC);
+ remove_proc_entry(PROC_SYNC, top);
+#endif
+}
+
+
+EXPORT_SYMBOL(xbus_request_sync);
+EXPORT_SYMBOL(got_new_syncer);
+EXPORT_SYMBOL(elect_syncer);
+EXPORT_SYMBOL(xpp_echocan);
+#ifdef ZAPTEL_SYNC_TICK
+EXPORT_SYMBOL(zaptel_sync_tick);
+#endif
+EXPORT_SYMBOL(__pcm_recompute);
+EXPORT_SYMBOL(pcm_recompute);
+EXPORT_SYMBOL(generic_card_pcm_tospan);
+EXPORT_SYMBOL(generic_card_pcm_fromspan);
+#ifdef DEBUG_PCMTX
+EXPORT_SYMBOL(pcmtx);
+EXPORT_SYMBOL(pcmtx_chan);
+#endif
+
diff --git a/drivers/dahdi/xpp/xbus-pcm.h b/drivers/dahdi/xpp/xbus-pcm.h
new file mode 100644
index 0000000..3265f68
--- /dev/null
+++ b/drivers/dahdi/xpp/xbus-pcm.h
@@ -0,0 +1,134 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2007, Xorcom
+ *
+ * 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.
+ *
+ */
+
+/*
+ * This source module contains all the PCM and SYNC handling code.
+ */
+#ifndef XBUS_PCM_H
+#define XBUS_PCM_H
+
+#include "xdefs.h"
+#include <linux/proc_fs.h>
+#include <zaptel.h>
+
+#ifdef __KERNEL__
+
+enum sync_mode {
+ SYNC_MODE_NONE = 0x00,
+ SYNC_MODE_AB = 0x01, /* Astribank sync */
+ SYNC_MODE_PLL = 0x03, /* Adjust XPD's PLL according to HOST */
+ SYNC_MODE_QUERY = 0x80,
+};
+
+/*
+ * Abstract representation of timestamp.
+ * It would (eventually) replace the hard-coded
+ * timeval structs so we can migrate to better
+ * time representations.
+ */
+struct xpp_timestamp {
+ struct timeval tv;
+};
+
+/*
+ * A ticker encapsulates the timing information of some
+ * abstract tick source. The following tickers are used:
+ * - Each xbus has an embedded ticker.
+ * - There is one global zaptel_ticker to represent ticks
+ * of external zaptel card (in case we want to sync
+ * from other zaptel devices).
+ */
+struct xpp_ticker { /* for rate calculation */
+ int count;
+ int cycle;
+ struct xpp_timestamp first_sample;
+ struct xpp_timestamp last_sample;
+ int tick_period; /* usec/tick */
+ spinlock_t lock;
+};
+
+/*
+ * xpp_drift represent the measurements of the offset between an
+ * xbus ticker to a reference ticker.
+ */
+struct xpp_drift {
+ int wanted_offset; /* fixed */
+ int delta_tick; /* from ref_ticker */
+ int lost_ticks; /* occurances */
+ int lost_tick_count;
+ int delta_max;
+ int delta_min;
+ int median; /* (max + min) / 2 */
+ int jitter; /* max - min */
+ int calc_drift;
+ spinlock_t lock;
+};
+
+void xpp_drift_init(xbus_t *xbus);
+
+static inline long usec_diff(const struct timeval *tv1, const struct timeval *tv2)
+{
+ long diff_sec;
+ long diff_usec;
+
+ diff_sec = tv1->tv_sec - tv2->tv_sec;
+ diff_usec = tv1->tv_usec - tv2->tv_usec;
+ return diff_sec * 1000000 + diff_usec;
+}
+
+
+int xbus_pcm_init(struct proc_dir_entry *top);
+void xbus_pcm_shutdown(void);
+int send_pcm_frame(xbus_t *xbus, xframe_t *xframe);
+void pcm_recompute(xpd_t *xpd, xpp_line_t tmp_pcm_mask);
+void __pcm_recompute(xpd_t *xpd, xpp_line_t tmp_pcm_mask); /* non locking */
+void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe);
+void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack);
+void generic_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack);
+void fill_beep(u_char *buf, int num, int duration);
+const char *sync_mode_name(enum sync_mode mode);
+void xbus_set_command_timer(xbus_t *xbus, bool on);
+void xbus_request_sync(xbus_t *xbus, enum sync_mode mode);
+void got_new_syncer(xbus_t *xbus, enum sync_mode mode, int drift);
+int xbus_command_queue_tick(xbus_t *xbus);
+void xbus_reset_counters(xbus_t *xbus);
+void elect_syncer(const char *msg);
+int xpp_echocan(struct zt_chan *chan, int len);
+#ifdef ZAPTEL_SYNC_TICK
+int zaptel_sync_tick(struct zt_span *span, int is_master);
+#endif
+
+#ifdef XPP_EC_CHUNK
+extern int xpp_ec;
+#else
+#define xpp_ec 0
+#endif
+
+#ifdef DEBUG_PCMTX
+extern int pcmtx;
+extern int pcmtx_chan;
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* XBUS_PCM_H */
+
diff --git a/drivers/dahdi/xpp/xbus-sysfs.c b/drivers/dahdi/xpp/xbus-sysfs.c
new file mode 100644
index 0000000..87a58f1
--- /dev/null
+++ b/drivers/dahdi/xpp/xbus-sysfs.c
@@ -0,0 +1,427 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+# warning "This module is tested only with 2.6 kernels"
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#ifdef PROTOCOL_DEBUG
+#include <linux/ctype.h>
+#endif
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/delay.h> /* for msleep() to debug */
+#include "xpd.h"
+#include "xpp_zap.h"
+#include "xbus-core.h"
+#ifdef XPP_DEBUGFS
+#include "xpp_log.h"
+#endif
+#include "zap_debug.h"
+
+static const char rcsid[] = "$Id$";
+
+/* Command line parameters */
+extern int debug;
+
+
+/* Kernel versions... */
+/*
+ * Hotplug replaced with uevent in 2.6.16
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+#define OLD_HOPLUG_SUPPORT // for older kernels
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+#define DEVICE_ATTR_READER(name,dev,buf) \
+ ssize_t name(struct device *dev, struct device_attribute *attr, char *buf)
+#define DEVICE_ATTR_WRITER(name,dev,buf, count) \
+ ssize_t name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+#else
+#define DEVICE_ATTR_READER(name,dev,buf) \
+ ssize_t name(struct device *dev, char *buf)
+#define DEVICE_ATTR_WRITER(name,dev,buf, count) \
+ ssize_t name(struct device *dev, const char *buf, size_t count)
+#endif
+
+/*--------- Sysfs Bus handling ----*/
+static int xpp_bus_match(struct device *dev, struct device_driver *driver)
+{
+ DBG(GENERAL, "dev->bus_id = %s, driver->name = %s\n", dev->bus_id, driver->name);
+ return 1;
+}
+
+#ifdef OLD_HOPLUG_SUPPORT
+static int xpp_bus_hotplug(struct device *dev, char **envp, int envnum, char *buff, int bufsize)
+{
+ xbus_t *xbus;
+
+ if(!dev)
+ return -ENODEV;
+ xbus = dev_to_xbus(dev);
+ envp[0] = buff;
+ if(snprintf(buff, bufsize, "XBUS_NAME=%s", xbus->busname) >= bufsize)
+ return -ENOMEM;
+ envp[1] = NULL;
+ return 0;
+}
+#else
+
+#define XBUS_VAR_BLOCK \
+ do { \
+ XBUS_ADD_UEVENT_VAR("XPP_INIT_DIR=%s", initdir); \
+ XBUS_ADD_UEVENT_VAR("XBUS_NUM=%02d", xbus->num); \
+ XBUS_ADD_UEVENT_VAR("XBUS_NAME=%s", xbus->busname); \
+ } while(0)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+#define XBUS_ADD_UEVENT_VAR(fmt, val...) \
+ do { \
+ int err = add_uevent_var(envp, num_envp, &i, \
+ buffer, buffer_size, &len, \
+ fmt, val); \
+ if (err) \
+ return err; \
+ } while (0)
+
+static int xpp_bus_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+{
+ xbus_t *xbus;
+ int i = 0;
+ int len = 0;
+ extern char *initdir;
+
+ if(!dev)
+ return -ENODEV;
+ xbus = dev_to_xbus(dev);
+ DBG(GENERAL, "bus_id=%s xbus=%s\n", dev->bus_id, xbus->busname);
+ XBUS_VAR_BLOCK;
+ envp[i] = NULL;
+ return 0;
+}
+#else
+#define XBUS_ADD_UEVENT_VAR(fmt, val...) \
+ do { \
+ int err = add_uevent_var(kenv, fmt, val); \
+ if (err) \
+ return err; \
+ } while (0)
+
+static int xpp_bus_uevent(struct device *dev, struct kobj_uevent_env *kenv)
+{
+ xbus_t *xbus;
+ extern char *initdir;
+
+ if(!dev)
+ return -ENODEV;
+ xbus = dev_to_xbus(dev);
+ DBG(GENERAL, "bus_id=%s xbus=%s\n", dev->bus_id, xbus->busname);
+ XBUS_VAR_BLOCK;
+ return 0;
+}
+#endif
+
+#endif /* OLD_HOPLUG_SUPPORT */
+
+static void xpp_bus_release(struct device *dev)
+{
+ DBG(GENERAL, "\n");
+}
+
+static void xpp_dev_release(struct device *dev)
+{
+ xbus_t *xbus;
+
+ BUG_ON(!dev);
+ xbus = dev_to_xbus(dev);
+ XBUS_DBG(GENERAL, xbus, "\n");
+}
+
+static struct bus_type xpp_bus_type = {
+ .name = "astribanks",
+ .match = xpp_bus_match,
+#ifdef OLD_HOPLUG_SUPPORT
+ .hotplug = xpp_bus_hotplug,
+#else
+ .uevent = xpp_bus_uevent,
+#endif
+};
+
+static struct device xpp_bus = {
+ .bus_id = "xppbus",
+ .release = xpp_bus_release
+};
+
+static struct device_driver xpp_driver = {
+ .name = "xppdrv",
+ .bus = &xpp_bus_type,
+#ifndef OLD_HOPLUG_SUPPORT
+ .owner = THIS_MODULE
+#endif
+};
+
+int register_xpp_bus(void)
+{
+ int ret;
+
+ if((ret = bus_register(&xpp_bus_type)) < 0) {
+ ERR("%s: bus_register failed. Error number %d", __FUNCTION__, ret);
+ goto failed_bus;
+ }
+ if((ret = device_register(&xpp_bus)) < 0) {
+ ERR("%s: registration of xpp_bus failed. Error number %d",
+ __FUNCTION__, ret);
+ goto failed_busdevice;
+ }
+ if((ret = driver_register(&xpp_driver)) < 0) {
+ ERR("%s: driver_register failed. Error number %d", __FUNCTION__, ret);
+ goto failed_driver;
+ }
+ return 0;
+failed_driver:
+ device_unregister(&xpp_bus);
+failed_busdevice:
+ bus_unregister(&xpp_bus_type);
+failed_bus:
+ return ret;
+}
+
+void unregister_xpp_bus(void)
+{
+ driver_unregister(&xpp_driver);
+ device_unregister(&xpp_bus);
+ bus_unregister(&xpp_bus_type);
+}
+
+/*--------- Sysfs Device handling ----*/
+static DEVICE_ATTR_READER(connector_show, dev, buf)
+{
+ xbus_t *xbus;
+ int ret;
+
+ xbus = dev_to_xbus(dev);
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", xbus->location);
+ return ret;
+}
+
+static DEVICE_ATTR_READER(label_show, dev, buf)
+{
+ xbus_t *xbus;
+ int ret;
+
+ xbus = dev_to_xbus(dev);
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", xbus->label);
+ return ret;
+}
+
+static DEVICE_ATTR_READER(status_show, dev, buf)
+{
+ xbus_t *xbus;
+ int ret;
+
+ xbus = dev_to_xbus(dev);
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", (TRANSPORT_RUNNING(xbus))?"connected":"missing");
+ return ret;
+}
+
+static DEVICE_ATTR_READER(timing_show, dev, buf)
+{
+ xbus_t *xbus;
+ struct xpp_drift *driftinfo;
+ int len = 0;
+ struct timeval now;
+
+ do_gettimeofday(&now);
+ xbus = dev_to_xbus(dev);
+ driftinfo = &xbus->drift;
+ len += snprintf(buf + len, PAGE_SIZE - len, "DRIFT: %-3s", sync_mode_name(xbus->sync_mode));
+ if(xbus->sync_mode == SYNC_MODE_PLL) {
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ " %5d: jitter %4d median %4d calc_drift %3d lost (%4d,%4d) : ",
+ xbus->ticker.cycle,
+ driftinfo->jitter, driftinfo->median,
+ driftinfo->calc_drift,
+ driftinfo->lost_ticks, driftinfo->lost_tick_count);
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "DRIFT %3d %ld sec ago",
+ xbus->sync_adjustment,
+ (xbus->pll_updated_at == 0) ? 0 : now.tv_sec - xbus->pll_updated_at);
+ }
+ len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+ return len;
+}
+
+#ifdef SAMPLE_TICKS
+/*
+ * tick sampling: Measure offset from reference ticker:
+ * - Recording start when writing to:
+ * /sys/bus/astribanks/devices/xbus-??/samples
+ * - Recording ends when filling SAMPLE_SIZE ticks
+ * - Results are read from the same sysfs file.
+ * - Trying to read/write during recording, returns -EBUSY.
+ */
+static DEVICE_ATTR_READER(samples_show, dev, buf)
+{
+ xbus_t *xbus;
+ int len = 0;
+ int i;
+
+ xbus = dev_to_xbus(dev);
+ if(xbus->sample_running)
+ return -EBUSY;
+ for(i = 0; i < SAMPLE_SIZE; i++) {
+ if(len > PAGE_SIZE - 20)
+ break;
+ len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", xbus->sample_ticks[i]);
+ }
+ return len;
+}
+
+static DEVICE_ATTR_WRITER(samples_store, dev, buf, count)
+{
+ xbus_t *xbus;
+
+ xbus = dev_to_xbus(dev);
+ if(xbus->sample_running)
+ return -EBUSY;
+ memset(xbus->sample_ticks, 0, sizeof(*xbus->sample_ticks));
+ xbus->sample_pos = 0;
+ xbus->sample_running = 1;
+ return count;
+}
+#endif
+
+/*
+ * Clear statistics
+ */
+static DEVICE_ATTR_WRITER(cls_store, dev, buf, count)
+{
+ xbus_t *xbus;
+ struct xpp_drift *driftinfo;
+
+ xbus = dev_to_xbus(dev);
+ driftinfo = &xbus->drift;
+ driftinfo->lost_ticks = 0;
+ driftinfo->lost_tick_count = 0;
+ xbus->min_tx_sync = INT_MAX;
+ xbus->max_tx_sync = 0;
+ xbus->min_rx_sync = INT_MAX;
+ xbus->max_rx_sync = 0;
+#ifdef SAMPLE_TICKS
+ memset(xbus->sample_ticks, 0, sizeof(*xbus->sample_ticks));
+#endif
+ return count;
+}
+
+static DEVICE_ATTR(connector, S_IRUGO, connector_show, NULL);
+static DEVICE_ATTR(label, S_IRUGO, label_show, NULL);
+static DEVICE_ATTR(status, S_IRUGO, status_show, NULL);
+static DEVICE_ATTR(timing, S_IRUGO, timing_show, NULL);
+static DEVICE_ATTR(cls, S_IWUSR, NULL, cls_store);
+#ifdef SAMPLE_TICKS
+static DEVICE_ATTR(samples, S_IWUSR | S_IRUGO, samples_show, samples_store);
+#endif
+
+void xbus_sysfs_remove(xbus_t *xbus)
+{
+ struct device *astribank;
+
+ BUG_ON(!xbus);
+ XBUS_DBG(GENERAL, xbus, "\n");
+ astribank = &xbus->astribank;
+ BUG_ON(!astribank);
+ if(!astribank->driver_data)
+ return;
+ BUG_ON(astribank->driver_data != xbus);
+#ifdef SAMPLE_TICKS
+ device_remove_file(&xbus->astribank, &dev_attr_samples);
+#endif
+ device_remove_file(&xbus->astribank, &dev_attr_cls);
+ device_remove_file(&xbus->astribank, &dev_attr_timing);
+ device_remove_file(&xbus->astribank, &dev_attr_status);
+ device_remove_file(&xbus->astribank, &dev_attr_label);
+ device_remove_file(&xbus->astribank, &dev_attr_connector);
+ device_unregister(&xbus->astribank);
+}
+
+int xbus_sysfs_create(xbus_t *xbus)
+{
+ struct device *astribank;
+ int ret = 0;
+
+ BUG_ON(!xbus);
+ astribank = &xbus->astribank;
+ BUG_ON(!astribank);
+ XBUS_DBG(GENERAL, xbus, "\n");
+ device_initialize(astribank);
+ astribank->bus = &xpp_bus_type;
+ astribank->parent = &xpp_bus;
+ snprintf(astribank->bus_id, BUS_ID_SIZE, "xbus-%02d", xbus->num);
+ astribank->driver_data = NULL; /* override below */
+ astribank->release = xpp_dev_release;
+ ret = device_register(astribank);
+ if(ret) {
+ XBUS_ERR(xbus, "%s: device_add failed: %d\n", __FUNCTION__, ret);
+ goto out;
+ }
+ ret = device_create_file(astribank, &dev_attr_connector);
+ if(ret) {
+ XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
+ goto out;
+ }
+ ret = device_create_file(astribank, &dev_attr_label);
+ if(ret) {
+ XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
+ goto out;
+ }
+ ret = device_create_file(astribank, &dev_attr_status);
+ if(ret) {
+ XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
+ goto out;
+ }
+ ret = device_create_file(astribank, &dev_attr_timing);
+ if(ret) {
+ XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
+ goto out;
+ }
+ ret = device_create_file(astribank, &dev_attr_cls);
+ if(ret) {
+ XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
+ goto out;
+ }
+#ifdef SAMPLE_TICKS
+ ret = device_create_file(astribank, &dev_attr_samples);
+ if(ret) {
+ XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
+ goto out;
+ }
+#endif
+ astribank->driver_data = xbus; /* Everything is good */
+out:
+ return ret;
+}
diff --git a/drivers/dahdi/xpp/xdefs.h b/drivers/dahdi/xpp/xdefs.h
new file mode 100644
index 0000000..f928fd4
--- /dev/null
+++ b/drivers/dahdi/xpp/xdefs.h
@@ -0,0 +1,133 @@
+#ifndef XDEFS_H
+#define XDEFS_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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 "xpp_version.h"
+
+#ifdef __KERNEL__
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#else
+
+/* This is to enable user-space programs to include this. */
+
+#include <stdint.h>
+typedef uint8_t __u8;
+typedef uint32_t __u32;
+
+#include <stdio.h>
+
+#define DBG(fmt, ...) printf("DBG: %s: " fmt, __FUNCTION__, ## __VA_ARGS__)
+#define INFO(fmt, ...) printf("INFO: " fmt, ## __VA_ARGS__)
+#define NOTICE(fmt, ...) printf("NOTICE: " fmt, ## __VA_ARGS__)
+#define ERR(fmt, ...) printf("ERR: " fmt, ## __VA_ARGS__)
+#define __user
+
+struct list_head { struct list_head *next; struct list_head *prev; };
+
+#endif
+
+#define PACKED __attribute__((packed))
+
+#define ALL_LINES ((lineno_t)-1)
+
+#ifndef BIT /* added in 2.6.24 */
+#define BIT(i) (1UL << (i))
+#endif
+#define BIT_SET(x,i) ((x) |= BIT(i))
+#define BIT_CLR(x,i) ((x) &= ~BIT(i))
+#define IS_SET(x,i) (((x) & BIT(i)) != 0)
+#define BITMASK(i) (((u64)1 << (i)) - 1)
+
+#define MAX_PROC_WRITE 100 /* Largest buffer we allow writing our /proc files */
+#define CHANNELS_PERXPD 32 /* Depends on xpp_line_t and protocol fields */
+
+#define MAX_SPANNAME 20 /* From zaptel.h */
+#define MAX_SPANDESC 40 /* From zaptel.h */
+#define MAX_CHANNAME 40 /* From zaptel.h */
+
+#define XPD_NAMELEN 10 /* must be <= from maximal workqueue name */
+#define XPD_DESCLEN 20
+#define XBUS_NAMELEN 20 /* must be <= from maximal workqueue name */
+#define XBUS_DESCLEN 40
+#define LABEL_SIZE 20
+
+#define UNIT_BITS 3 /* Bit for Astribank unit number */
+#define SUBUNIT_BITS 3 /* Bit for Astribank subunit number */
+
+#define MAX_UNIT (1 << UNIT_BITS) /* 1 FXS + 3 FXS/FXO | 1 BRI + 3 FXS/FXO */
+#define MAX_SUBUNIT (1 << SUBUNIT_BITS) /* 8 port BRI */
+
+/*
+ * Compile time sanity checks
+ */
+#if MAX_UNIT > BIT(UNIT_BITS)
+#error "MAX_UNIT too large"
+#endif
+
+#if MAX_SUBUNIT > BIT(SUBUNIT_BITS)
+#error "MAX_SUBUNIT too large"
+#endif
+
+#define MAX_XPDS (MAX_UNIT*MAX_SUBUNIT)
+
+#define VALID_XPD_NUM(x) ((x) < MAX_XPDS && (x) >= 0)
+
+#define CHAN_BITS 5 /* 0-31 for E1 */
+
+typedef char *charp;
+typedef unsigned char byte;
+#ifdef __KERNEL__
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#define KMEM_CACHE_T kmem_cache_t
+#else
+#define KMEM_CACHE_T struct kmem_cache
+#endif
+
+#define KZALLOC(size, gfp) my_kzalloc(size, gfp)
+#define KZFREE(p) do { \
+ memset((p), 0, sizeof(*(p))); \
+ kfree(p); \
+ } while(0);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+typedef int bool;
+#endif
+#else
+typedef int bool;
+#endif
+typedef struct xbus xbus_t;
+typedef struct xpd xpd_t;
+typedef struct xframe xframe_t;
+typedef struct xpacket xpacket_t;
+typedef struct xops xops_t;
+typedef __u32 xpp_line_t; /* at most 31 lines for E1 */
+typedef byte lineno_t;
+typedef byte xportno_t;
+
+#define PORT_BROADCAST 255
+
+#endif /* XDEFS_H */
diff --git a/drivers/dahdi/xpp/xframe_queue.c b/drivers/dahdi/xpp/xframe_queue.c
new file mode 100644
index 0000000..7d9c098
--- /dev/null
+++ b/drivers/dahdi/xpp/xframe_queue.c
@@ -0,0 +1,269 @@
+#include "xframe_queue.h"
+#include "xbus-core.h"
+#include "zap_debug.h"
+
+extern int debug;
+
+static xframe_t *transport_alloc_xframe(xbus_t *xbus, gfp_t gfp_flags);
+static void transport_free_xframe(xbus_t *xbus, xframe_t *xframe);
+
+void xframe_queue_init(struct xframe_queue *q, unsigned int steady_state_count, unsigned int max_count, const char *name, void *priv)
+{
+ memset(q, 0, sizeof(*q));
+ spin_lock_init(&q->lock);
+ INIT_LIST_HEAD(&q->head);
+ q->max_count = XFRAME_QUEUE_MARGIN + max_count;
+ q->steady_state_count = XFRAME_QUEUE_MARGIN + steady_state_count;
+ q->name = name;
+ q->priv = priv;
+}
+
+void xframe_queue_clearstats(struct xframe_queue *q)
+{
+ q->worst_count = 0;
+ //q->overflows = 0; /* Never clear overflows */
+ q->worst_lag_usec = 0L;
+}
+
+static bool __xframe_enqueue(struct xframe_queue *q, xframe_t *xframe)
+{
+ int ret = 1;
+
+ if(q->count >= q->max_count) {
+ q->overflows++;
+ ret = 0;
+ goto out;
+ }
+ if(++q->count > q->worst_count)
+ q->worst_count = q->count;
+ list_add_tail(&xframe->frame_list, &q->head);
+ do_gettimeofday(&xframe->tv_queued);
+out:
+ return ret;
+}
+
+bool xframe_enqueue(struct xframe_queue *q, xframe_t *xframe)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&q->lock, flags);
+ ret = __xframe_enqueue(q, xframe);
+ spin_unlock_irqrestore(&q->lock, flags);
+ return ret;
+}
+
+static xframe_t *__xframe_dequeue(struct xframe_queue *q)
+{
+ xframe_t *frm = NULL;
+ struct list_head *h;
+ struct timeval now;
+ unsigned long usec_lag;
+
+ if(list_empty(&q->head))
+ goto out;
+ h = q->head.next;
+ list_del_init(h);
+ --q->count;
+ frm = list_entry(h, xframe_t, frame_list);
+ do_gettimeofday(&now);
+ usec_lag =
+ (now.tv_sec - frm->tv_queued.tv_sec)*1000*1000 +
+ (now.tv_usec - frm->tv_queued.tv_usec);
+ if(q->worst_lag_usec < usec_lag)
+ q->worst_lag_usec = usec_lag;
+out:
+ return frm;
+}
+
+xframe_t *xframe_dequeue(struct xframe_queue *q)
+{
+ unsigned long flags;
+ xframe_t *frm;
+
+ spin_lock_irqsave(&q->lock, flags);
+ frm = __xframe_dequeue(q);
+ spin_unlock_irqrestore(&q->lock, flags);
+ return frm;
+}
+void xframe_queue_disable(struct xframe_queue *q)
+{
+ q->max_count = 0;
+}
+
+void xframe_queue_clear(struct xframe_queue *q)
+{
+ xframe_t *xframe;
+ xbus_t *xbus = q->priv;
+ int i = 0;
+
+ xframe_queue_disable(q);
+ while((xframe = xframe_dequeue(q)) != NULL) {
+ transport_free_xframe(xbus, xframe);
+ i++;
+ }
+ XBUS_DBG(DEVICES, xbus, "%s: finished queue clear (%d items)\n", q->name, i);
+}
+
+uint xframe_queue_count(struct xframe_queue *q)
+{
+ return q->count;
+}
+
+/*------------------------- Frame Alloc/Dealloc --------------------*/
+
+static xframe_t *transport_alloc_xframe(xbus_t *xbus, gfp_t gfp_flags)
+{
+ struct xbus_ops *ops;
+ xframe_t *xframe;
+ unsigned long flags;
+
+ BUG_ON(!xbus);
+ ops = transportops_get(xbus);
+ if(unlikely(!ops)) {
+ XBUS_ERR(xbus, "Missing transport\n");
+ return NULL;
+ }
+ spin_lock_irqsave(&xbus->transport.lock, flags);
+ //XBUS_INFO(xbus, "%s (transport_refcount=%d)\n", __FUNCTION__, atomic_read(&xbus->transport.transport_refcount));
+ xframe = ops->alloc_xframe(xbus, gfp_flags);
+ if(!xframe) {
+ static int rate_limit;
+
+ if((rate_limit++ % 3001) == 0)
+ XBUS_ERR(xbus,
+ "Failed xframe allocation from transport (%d)\n",
+ rate_limit);
+ transportops_put(xbus);
+ /* fall through */
+ }
+ spin_unlock_irqrestore(&xbus->transport.lock, flags);
+ return xframe;
+}
+
+static void transport_free_xframe(xbus_t *xbus, xframe_t *xframe)
+{
+ struct xbus_ops *ops;
+ unsigned long flags;
+
+ BUG_ON(!xbus);
+ ops = xbus->transport.ops;
+ BUG_ON(!ops);
+ spin_lock_irqsave(&xbus->transport.lock, flags);
+ //XBUS_INFO(xbus, "%s (transport_refcount=%d)\n", __FUNCTION__, atomic_read(&xbus->transport.transport_refcount));
+ ops->free_xframe(xbus, xframe);
+ transportops_put(xbus);
+ spin_unlock_irqrestore(&xbus->transport.lock, flags);
+}
+
+static bool xframe_queue_adjust(struct xframe_queue *q)
+{
+ xbus_t *xbus;
+ xframe_t *xframe;
+ int delta;
+ unsigned long flags;
+ int ret = 0;
+
+ BUG_ON(!q);
+ xbus = q->priv;
+ BUG_ON(!xbus);
+ spin_lock_irqsave(&q->lock, flags);
+ delta = q->count - q->steady_state_count;
+ if(delta < -XFRAME_QUEUE_MARGIN) {
+ /* Increase pool by one frame */
+ //XBUS_INFO(xbus, "%s(%d): Allocate one\n", q->name, delta);
+ xframe = transport_alloc_xframe(xbus, GFP_ATOMIC);
+ if(!xframe) {
+ static int rate_limit;
+
+ if((rate_limit++ % 3001) == 0)
+ XBUS_ERR(xbus, "%s: failed frame allocation\n", q->name);
+ goto out;
+ }
+ if(!__xframe_enqueue(q, xframe)) {
+ static int rate_limit;
+
+ if((rate_limit++ % 3001) == 0)
+ XBUS_ERR(xbus, "%s: failed enqueueing frame\n", q->name);
+ transport_free_xframe(xbus, xframe);
+ goto out;
+ }
+ } else if(delta > XFRAME_QUEUE_MARGIN) {
+ /* Decrease pool by one frame */
+ //XBUS_INFO(xbus, "%s(%d): Free one\n", q->name, delta);
+ xframe = __xframe_dequeue(q);
+ if(!xframe) {
+ static int rate_limit;
+
+ if((rate_limit++ % 3001) == 0)
+ XBUS_ERR(xbus, "%s: failed dequeueing frame\n", q->name);
+ goto out;
+ }
+ transport_free_xframe(xbus, xframe);
+ }
+ ret = 1;
+out:
+ spin_unlock_irqrestore(&q->lock, flags);
+ return ret;
+}
+
+xframe_t *get_xframe(struct xframe_queue *q)
+{
+ xframe_t *xframe;
+ xbus_t *xbus;
+
+ BUG_ON(!q);
+ xbus = (xbus_t *)q->priv;
+ BUG_ON(!xbus);
+ xframe_queue_adjust(q);
+ xframe = xframe_dequeue(q);
+ if(!xframe) {
+ static int rate_limit;
+
+ if((rate_limit++ % 3001) == 0)
+ XBUS_ERR(xbus, "%s STILL EMPTY (%d)\n", q->name, rate_limit);
+ return NULL;
+ }
+ BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
+ atomic_set(&xframe->frame_len, 0);
+ xframe->first_free = xframe->packets;
+ do_gettimeofday(&xframe->tv_created);
+ /*
+ * If later parts bother to correctly initialize their
+ * headers, there is no need to memset() the whole data.
+ *
+ * ticket:403
+ *
+ * memset(xframe->packets, 0, xframe->frame_maxlen);
+ */
+ //XBUS_INFO(xbus, "%s\n", __FUNCTION__);
+ return xframe;
+}
+
+void put_xframe(struct xframe_queue *q, xframe_t *xframe)
+{
+ xbus_t *xbus;
+
+ BUG_ON(!q);
+ xbus = (xbus_t *)q->priv;
+ BUG_ON(!xbus);
+ //XBUS_INFO(xbus, "%s\n", __FUNCTION__);
+ BUG_ON(!TRANSPORT_EXIST(xbus));
+ if(unlikely(!xframe_enqueue(q, xframe))) {
+ XBUS_ERR(xbus, "Failed returning xframe to %s\n", q->name);
+ transport_free_xframe(xbus, xframe);
+ return;
+ }
+ xframe_queue_adjust(q);
+}
+
+
+EXPORT_SYMBOL(xframe_queue_init);
+EXPORT_SYMBOL(xframe_queue_clearstats);
+EXPORT_SYMBOL(xframe_enqueue);
+EXPORT_SYMBOL(xframe_dequeue);
+EXPORT_SYMBOL(xframe_queue_disable);
+EXPORT_SYMBOL(xframe_queue_clear);
+EXPORT_SYMBOL(xframe_queue_count);
+EXPORT_SYMBOL(get_xframe);
+EXPORT_SYMBOL(put_xframe);
diff --git a/drivers/dahdi/xpp/xframe_queue.h b/drivers/dahdi/xpp/xframe_queue.h
new file mode 100644
index 0000000..5612d65
--- /dev/null
+++ b/drivers/dahdi/xpp/xframe_queue.h
@@ -0,0 +1,34 @@
+#ifndef XFRAME_QUEUE_H
+#define XFRAME_QUEUE_H
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include "xdefs.h"
+
+#define XFRAME_QUEUE_MARGIN 10
+
+struct xframe_queue {
+ struct list_head head;
+ unsigned int count;
+ unsigned int max_count;
+ unsigned int steady_state_count;
+ spinlock_t lock;
+ const char *name;
+ void *priv;
+ /* statistics */
+ unsigned int worst_count;
+ unsigned int overflows;
+ unsigned long worst_lag_usec; /* since xframe creation */
+};
+
+void xframe_queue_init(struct xframe_queue *q,
+ unsigned int steady_state_count, unsigned int max_count,
+ const char *name, void *priv);
+__must_check bool xframe_enqueue(struct xframe_queue *q, xframe_t *xframe);
+__must_check xframe_t *xframe_dequeue(struct xframe_queue *q);
+void xframe_queue_clearstats(struct xframe_queue *q);
+void xframe_queue_disable(struct xframe_queue *q);
+void xframe_queue_clear(struct xframe_queue *q);
+uint xframe_queue_count(struct xframe_queue *q);
+
+#endif /* XFRAME_QUEUE_ */
diff --git a/drivers/dahdi/xpp/xpd.h b/drivers/dahdi/xpp/xpd.h
new file mode 100644
index 0000000..8c7c514
--- /dev/null
+++ b/drivers/dahdi/xpp/xpd.h
@@ -0,0 +1,226 @@
+#ifndef XPD_H
+#define XPD_H
+
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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 "xdefs.h"
+#include "xproto.h"
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+#include <linux/moduleparam.h>
+#ifdef XPP_DEBUGFS
+#ifndef CONFIG_DEBUG_FS
+#warning kernel does not include CONFIG_DEBUG_FS, canceling XPP_DEBUGFS support
+#undef XPP_DEBUGFS
+#else
+#include <linux/debugfs.h>
+#endif
+#endif
+#endif /* __KERNEL__ */
+
+#include <zaptel.h>
+
+#ifdef __KERNEL__
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+/* also added in RHEL kernels with the OpenInfiniband backport: */
+#if LINUX_VERSION_CODE != KERNEL_VERSION(2,6,9) || !defined(DEFINE_SPINLOCK)
+typedef unsigned gfp_t; /* Added in 2.6.14 */
+#endif
+#endif
+
+/*
+ * FIXME: Kludge for 2.6.19
+ * bool is now defined as a proper boolean type (gcc _Bool)
+ * but the command line parsing framework handles it as int.
+ */
+#define DEF_PARM_BOOL(name,init,perm,desc) \
+ int name = init; \
+ module_param(name, bool, perm); \
+ MODULE_PARM_DESC(name, desc " [default " #init "]")
+
+#define DEF_PARM(type,name,init,perm,desc) \
+ type name = init; \
+ module_param(name, type, perm); \
+ MODULE_PARM_DESC(name, desc " [default " #init "]")
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+/*
+ * Old 2.6 kernels had module_param_array() macro that receive the counter
+ * by value.
+ */
+#define DEF_ARRAY(type,name,count,init,desc) \
+ unsigned int name ## _num_values; \
+ type name[count] = { [0 ... ((count)-1)] = (init) }; \
+ module_param_array(name, type, name ## _num_values, 0644); \
+ MODULE_PARM_DESC(name, desc " ( 1-" __MODULE_STRING(count) ")")
+#else
+#define DEF_ARRAY(type,name,count,init,desc) \
+ unsigned int name ## _num_values; \
+ type name[count] = {[0 ... ((count)-1)] = init}; \
+ module_param_array(name, type, &name ## _num_values, 0644); \
+ MODULE_PARM_DESC(name, desc " ( 1-" __MODULE_STRING(count) ")")
+#endif
+#endif // __KERNEL__
+
+#define CARD_DESC_MAGIC 0xca9dde5c
+
+struct card_desc_struct {
+ struct list_head card_list;
+ u32 magic;
+ byte type; /* LSB: 1 - to_phone, 0 - to_line */
+ byte subtype;
+ struct xpd_addr xpd_addr;
+ byte numchips;
+ byte ports_per_chip;
+ byte ports;
+ byte port_dir;
+ struct xpd_addr ec_addr; /* echo canceler address */
+};
+
+typedef enum xpd_direction {
+ TO_PSTN = 0,
+ TO_PHONE = 1,
+} xpd_direction_t;
+
+#ifdef __KERNEL__
+
+/*
+ * XPD statistics counters
+ */
+enum {
+ XPD_N_PCM_READ,
+ XPD_N_PCM_WRITE,
+ XPD_N_RECV_ERRORS,
+};
+
+#define XPD_COUNTER(xpd, counter) ((xpd)->counters[XPD_N_ ## counter])
+
+#define C_(x) [ XPD_N_ ## x ] = { #x }
+
+/* yucky, make an instance so we can size it... */
+static struct xpd_counters {
+ char *name;
+} xpd_counters[] = {
+ C_(PCM_READ),
+ C_(PCM_WRITE),
+ C_(RECV_ERRORS),
+};
+
+#undef C_
+
+#define XPD_COUNTER_MAX (sizeof(xpd_counters)/sizeof(xpd_counters[0]))
+
+/*
+ * An XPD is a single Xorcom Protocol Device
+ */
+struct xpd {
+ char xpdname[XPD_NAMELEN];
+ struct zt_span span;
+ struct zt_chan *chans;
+ int channels;
+ xpd_type_t type;
+ const char *type_name;
+ byte subtype;
+ xpd_direction_t direction; /* TO_PHONE, TO_PSTN */
+ int subunits; /* all siblings */
+ xpp_line_t no_pcm; /* Temporary: disable PCM (for USB-1) */
+ xpp_line_t offhook; /* Actual chip state: 0 - ONHOOK, 1 - OFHOOK */
+ xpp_line_t cid_on;
+ xpp_line_t msg_waiting; /* Voice Mail Waiting Indication */
+ xpp_line_t digital_outputs; /* 0 - no, 1 - yes */
+ xpp_line_t digital_inputs; /* 0 - no, 1 - yes */
+ xpp_line_t digital_signalling; /* BRI signalling channels */
+ uint timing_priority; /* from 'span' directives in zapata.conf */
+
+ /* maintained by card drivers */
+ uint pcm_len; /* allocation length of PCM packet (dynamic) */
+ xpp_line_t wanted_pcm_mask;
+ xpp_line_t silence_pcm; /* inject silence during next tick */
+ xpp_line_t mute_dtmf;
+
+ bool ringing[CHANNELS_PERXPD];
+
+ xbus_t *xbus; /* The XBUS we are connected to */
+
+ spinlock_t lock;
+ atomic_t zt_registered; /* Am I fully registered with zaptel */
+ atomic_t open_counter; /* Number of open channels */
+
+ int flags;
+ bool blink_mode; /* for visual identification */
+#define DEFAULT_LED_PERIOD (1000/8) /* in tick */
+
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc_xpd_dir;
+ struct proc_dir_entry *proc_xpd_summary;
+ struct proc_dir_entry *proc_xpd_ztregister;
+ struct proc_dir_entry *proc_xpd_blink;
+ struct proc_dir_entry *proc_xpd_chipregs;
+#endif
+
+ int counters[XPD_COUNTER_MAX];
+
+ const xproto_table_t *xproto; /* Card level protocol table */
+ const xops_t *xops; /* Card level operations */
+ void *priv; /* Card level private data */
+ bool card_present;
+ reg_cmd_t requested_reply;
+ reg_cmd_t last_reply;
+
+ unsigned long last_response; /* in jiffies */
+ unsigned xbus_idx; /* index in xbus->xpds[] */
+ struct xpd_addr addr;
+ struct list_head xpd_list;
+ unsigned int timer_count;
+ /* Echo cancelation */
+ u_char ec_chunk1[CHANNELS_PERXPD][ZT_CHUNKSIZE];
+ u_char ec_chunk2[CHANNELS_PERXPD][ZT_CHUNKSIZE];
+};
+
+#define for_each_line(xpd,i) for((i) = 0; (i) < (xpd)->channels; (i)++)
+#define IS_BRI(xpd) ((xpd)->type == XPD_TYPE_BRI)
+#define TICK_TOLERANCE 500 /* usec */
+
+#ifdef DEBUG_SYNC_PARPORT
+void xbus_flip_bit(xbus_t *xbus, unsigned int bitnum0, unsigned int bitnum1);
+#else
+#define xbus_flip_bit(xbus, bitnum0, bitnum1)
+#endif
+
+static inline void *my_kzalloc(size_t size, gfp_t flags)
+{
+ void *p;
+
+ p = kmalloc(size, flags);
+ if(p)
+ memset(p, 0, size);
+ return p;
+}
+
+#endif
+
+#endif /* XPD_H */
diff --git a/drivers/dahdi/xpp/xpp_log.h b/drivers/dahdi/xpp/xpp_log.h
new file mode 100644
index 0000000..322b7f0
--- /dev/null
+++ b/drivers/dahdi/xpp/xpp_log.h
@@ -0,0 +1,52 @@
+#ifndef XPP_LOG_H
+#define XPP_LOG_H
+/*
+ * Written by Alexander Landau <landau.alex@gmail.com>
+ * Copyright (C) 2004-2007, Xorcom
+ *
+ * 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.
+ *
+ */
+
+#ifdef __KERNEL__
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#else
+
+/* This is to enable user-space programs to include this. */
+
+#include "xdefs.h"
+
+#endif
+
+#define XPP_LOG_MAGIC 0x10583ADE
+
+struct log_global_header {
+ __u32 magic;
+ __u32 version;
+} __attribute__((packed));
+
+struct log_header {
+ __u32 len;
+ __u32 time;
+ __u8 xpd_num;
+ __u8 direction;
+} __attribute__((packed));
+
+#endif
diff --git a/drivers/dahdi/xpp/xpp_usb.c b/drivers/dahdi/xpp/xpp_usb.c
new file mode 100644
index 0000000..2b633c6
--- /dev/null
+++ b/drivers/dahdi/xpp/xpp_usb.c
@@ -0,0 +1,1107 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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/version.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h> /* for udelay */
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <asm/timex.h>
+#include <linux/proc_fs.h>
+#include <linux/usb.h>
+#include "xpd.h"
+#include "xproto.h"
+#include "xbus-core.h"
+#include "xframe_queue.h"
+#ifdef DEBUG
+#include "card_fxs.h"
+#include "card_fxo.h"
+#endif
+#include "parport_debug.h"
+
+static const char rcsid[] = "$Id$";
+
+static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before zap_debug.h */
+static DEF_PARM(int, usb1, 0, 0644, "Allow using USB 1.1 interfaces");
+static DEF_PARM(uint, tx_sluggish, 2000, 0644, "A sluggish transmit (usec)");
+static DEF_PARM(uint, drop_pcm_after, 6, 0644, "Number of consecutive tx_sluggish to drop a PCM frame");
+
+#include "zap_debug.h"
+
+
+#define XUSB_PRINTK(level, xusb, fmt, ...) \
+ printk(KERN_ ## level "%s-%s: xusb-%d (%s) [%s]: " fmt, #level, \
+ THIS_MODULE->name, (xusb)->index, xusb->path, xusb->serial, ## __VA_ARGS__)
+
+#define XUSB_DBG(bits, xusb, fmt, ...) \
+ ((void)((debug & (DBG_ ## bits)) && XUSB_PRINTK(DEBUG, xusb, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)))
+#define XUSB_ERR(xusb, fmt, ...) XUSB_PRINTK(ERR, xusb, fmt, ## __VA_ARGS__)
+#define XUSB_NOTICE(xusb, fmt, ...) XUSB_PRINTK(NOTICE, xusb, fmt, ## __VA_ARGS__)
+#define XUSB_INFO(xusb, fmt, ...) XUSB_PRINTK(INFO, xusb, fmt, ## __VA_ARGS__)
+
+/* FIXME: A flag that was deprecated at some point, and rather useless */
+/* anyway. Only used in the code or-ed to other flags */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+# define URB_ASYNC_UNLINK 0
+#endif
+/* Get a minor range for your devices from the usb maintainer */
+#define USB_SKEL_MINOR_BASE 192
+
+#ifdef CONFIG_PROC_FS
+#define PROC_USBXPP_SUMMARY "xpp_usb"
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+# warning "This module is tested only with 2.6 kernels"
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+# undef USB_FIELDS_MISSING
+#else
+# define USB_FIELDS_MISSING
+
+# define USB_MAX_STRING 128
+# define USB_GET_STRING(udev,field,buf) \
+ do { \
+ if((udev)->descriptor.field) { \
+ char tmp[USB_MAX_STRING]; \
+ if(usb_string((udev), (udev)->descriptor.field, tmp, sizeof(tmp)) > 0) \
+ snprintf((buf), USB_MAX_STRING, "%s", tmp); \
+ } \
+ } while(0);
+# define USB_GET_IFACE_NAME(udev,iface,buf) \
+ do { \
+ if((iface)->desc.iInterface) { \
+ char tmp[USB_MAX_STRING]; \
+ if(usb_string((udev), (iface)->desc.iInterface, tmp, sizeof(tmp)) > 0) \
+ snprintf((buf), USB_MAX_STRING, "%s", tmp); \
+ } \
+ } while(0);
+#endif
+
+#ifdef DEBUG_PCM_TIMING
+static cycles_t stamp_last_pcm_read;
+static cycles_t accumulate_diff;
+#endif
+
+struct xusb_model_info;
+
+struct xusb_endpoint {
+ int ep_addr;
+ int max_size;
+ usb_complete_t callback;
+};
+
+enum xusb_dir {
+ XUSB_RECV = 0,
+ XUSB_SEND = 1,
+};
+
+static __must_check int xframe_send_pcm(xbus_t *xbus, xframe_t *xframe);
+static __must_check int xframe_send_cmd(xbus_t *xbus, xframe_t *xframe);
+static __must_check xframe_t *alloc_xframe(xbus_t *xbus, gfp_t flags);
+static void free_xframe(xbus_t *xbus, xframe_t *frm);
+
+static struct xbus_ops xusb_ops = {
+ .xframe_send_pcm = xframe_send_pcm,
+ .xframe_send_cmd = xframe_send_cmd,
+ .alloc_xframe = alloc_xframe,
+ .free_xframe = free_xframe,
+};
+
+enum {
+ XUSB_N_RX_FRAMES,
+ XUSB_N_TX_FRAMES,
+ XUSB_N_RX_ERRORS,
+ XUSB_N_TX_ERRORS,
+ XUSB_N_RCV_ZERO_LEN,
+};
+
+#define XUSB_COUNTER(xusb, counter) ((xusb)->counters[XUSB_N_ ## counter])
+
+#define C_(x) [ XUSB_N_ ## x ] = { #x }
+
+static struct xusb_counters {
+ char *name;
+} xusb_counters[] = {
+ C_(RX_FRAMES),
+ C_(TX_FRAMES),
+ C_(RX_ERRORS),
+ C_(TX_ERRORS),
+ C_(RCV_ZERO_LEN),
+};
+
+#undef C_
+
+#define XUSB_COUNTER_MAX ARRAY_SIZE(xusb_counters)
+
+#define MAX_PENDING_WRITES 100
+
+static KMEM_CACHE_T *xusb_cache = NULL;
+
+typedef struct xusb xusb_t;
+
+/*
+ * A uframe is our low level representation of a frame.
+ *
+ * It contains the metadata for the usb stack (a urb)
+ * and the metadata for the xbus-core (an xframe)
+ * as well as pointing to the data (transfer_buffer, transfer_buffer_length)
+ * directionality (send/receive) and ownership (xusb).
+ */
+struct uframe {
+ unsigned long uframe_magic;
+#define UFRAME_MAGIC 654321L
+ struct urb urb;
+ xframe_t xframe;
+ size_t transfer_buffer_length;
+ void *transfer_buffer; /* max XFRAME_DATASIZE */
+ xusb_t *xusb;
+};
+
+#define urb_to_uframe(urb) container_of(urb, struct uframe, urb)
+#define xframe_to_uframe(xframe) container_of(xframe, struct uframe, xframe)
+#define xusb_of(xbus) ((xusb_t *)((xbus)->transport.priv))
+
+#define USEC_BUCKET 100 /* usec */
+#define NUM_BUCKETS 15
+#define BUCKET_START (500/USEC_BUCKET) /* skip uninteresting */
+
+/*
+ * USB XPP Bus (a USB Device)
+ */
+struct xusb {
+ uint xbus_num;
+ struct usb_device *udev; /* save off the usb device pointer */
+ struct usb_interface *interface; /* the interface for this device */
+ unsigned char minor; /* the starting minor number for this device */
+ uint index;
+ char path[XBUS_DESCLEN]; /* a unique path */
+
+ struct xusb_model_info *model_info;
+ struct xusb_endpoint endpoints[2]; /* RECV/SEND endpoints */
+
+ int present; /* if the device is not disconnected */
+ atomic_t pending_writes; /* submited but not out yet */
+ atomic_t pending_reads; /* submited but not in yet */
+ struct semaphore sem; /* locks this structure */
+ int counters[XUSB_COUNTER_MAX];
+
+ /* metrics */
+ struct timeval last_tx;
+ unsigned int max_tx_delay;
+ uint usb_tx_delay[NUM_BUCKETS];
+ uint sluggish_debounce;
+ bool drop_next_pcm; /* due to sluggishness */
+ atomic_t pcm_tx_drops;
+ atomic_t usb_sluggish_count;
+
+#ifdef USB_FIELDS_MISSING
+ /* storage for missing strings in old kernels */
+ char manufacturer[USB_MAX_STRING];
+ char product[USB_MAX_STRING];
+ char serial[USB_MAX_STRING];
+ char interface_name[USB_MAX_STRING];
+#else
+ const char *manufacturer;
+ const char *product;
+ const char *serial;
+ const char *interface_name;
+#endif
+
+};
+
+static spinlock_t xusb_lock = SPIN_LOCK_UNLOCKED;
+static xusb_t *xusb_array[MAX_BUSES] = {};
+static unsigned bus_count = 0;
+
+
+/* prevent races between open() and disconnect() */
+static DECLARE_MUTEX (disconnect_sem);
+
+/*
+ * AsteriskNow kernel has backported the "lean" callback from 2.6.20
+ * to 2.6.19 without any macro to notify of this fact -- how lovely.
+ * Debian-Etch and Centos5 are using 2.6.18 for now (lucky for us).
+ * Fedora6 jumped from 2.6.18 to 2.6.20. So far luck is on our side ;-)
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+#define USB_PASS_CB(u) struct urb *u, struct pt_regs *regs
+#else
+#define USB_PASS_CB(u) struct urb *u
+#endif
+
+static void xpp_send_callback(USB_PASS_CB(urb));
+static void xpp_receive_callback(USB_PASS_CB(urb));
+static int xusb_probe (struct usb_interface *interface, const struct usb_device_id *id);
+static void xusb_disconnect (struct usb_interface *interface);
+static int xusb_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
+
+/*------------------------------------------------------------------*/
+
+/*
+ * Updates the urb+xframe metadata from the uframe information.
+ */
+static void uframe_recompute(struct uframe *uframe, enum xusb_dir dir)
+{
+ struct urb *urb = &uframe->urb;
+ xusb_t *xusb = uframe->xusb;
+ struct usb_device *udev = xusb->udev;
+ struct xusb_endpoint *xusb_ep = &xusb->endpoints[dir];
+ unsigned int ep_addr = xusb_ep->ep_addr;
+ usb_complete_t urb_cb = xusb_ep->callback;
+ unsigned int epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+ int pipe = usb_pipein(ep_addr)
+ ? usb_rcvbulkpipe(udev, epnum)
+ : usb_sndbulkpipe(udev, epnum);
+
+ BUG_ON(uframe->uframe_magic != UFRAME_MAGIC);
+ usb_fill_bulk_urb(urb, udev, pipe, uframe->transfer_buffer, uframe->transfer_buffer_length, urb_cb, uframe);
+ urb->transfer_flags = (URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK);
+}
+
+static xframe_t *alloc_xframe(xbus_t *xbus, gfp_t gfp_flags)
+{
+ struct uframe *uframe;
+ xusb_t *xusb;
+ void *p;
+ int size;
+ static int rate_limit;
+
+ BUG_ON(!xbus);
+ xusb = xusb_of(xbus);
+ BUG_ON(!xusb);
+ if(!xusb->present) {
+ if((rate_limit++ % 1003) == 0)
+ XUSB_ERR(xusb,
+ "abort allocations during device disconnect (%d)\n", rate_limit);
+ return NULL;
+ }
+ size = min(xusb->endpoints[XUSB_SEND].max_size, xusb->endpoints[XUSB_RECV].max_size);
+ uframe = kmem_cache_alloc(xusb_cache, gfp_flags);
+ if(!uframe) {
+ if((rate_limit++ % 1003) == 0)
+ XUSB_ERR(xusb, "frame allocation failed (%d)\n", rate_limit);
+ return NULL;
+ }
+ usb_init_urb(&uframe->urb);
+ p = usb_buffer_alloc(xusb->udev, size, gfp_flags, &uframe->urb.transfer_dma);
+ if(!p) {
+ if((rate_limit++ % 1003) == 0)
+ XUSB_ERR(xusb, "buffer allocation failed (%d)\n", rate_limit);
+ kmem_cache_free(xusb_cache, uframe);
+ return NULL;
+ }
+ uframe->uframe_magic = UFRAME_MAGIC;
+ uframe->transfer_buffer_length = size;
+ uframe->transfer_buffer = p;
+ uframe->xusb = xusb;
+ xframe_init(xbus, &uframe->xframe, uframe->transfer_buffer, uframe->transfer_buffer_length, uframe);
+ return &uframe->xframe;
+}
+
+static void free_xframe(xbus_t *xbus, xframe_t *xframe)
+{
+ struct uframe *uframe = xframe_to_uframe(xframe);
+ struct urb *urb = &uframe->urb;
+
+ BUG_ON(xbus->transport.priv != uframe->xusb);
+ //XUSB_INFO(uframe->xusb, "frame_free\n");
+ usb_buffer_free(urb->dev, uframe->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_dma);
+ memset(uframe, 0, sizeof(*uframe));
+ kmem_cache_free(xusb_cache, uframe);
+}
+
+/*------------------------------------------------------------------*/
+
+/*
+ * Actuall frame sending -- both PCM and commands.
+ */
+static int do_send_xframe(xbus_t *xbus, xframe_t *xframe)
+{
+ struct urb *urb;
+ xusb_t *xusb;
+ int ret = 0;
+ struct uframe *uframe;
+
+ BUG_ON(!xframe);
+ BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
+ xusb = xusb_of(xbus);
+ BUG_ON(!xusb);
+ if(!xusb->present) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0)
+ XUSB_ERR(xusb,
+ "abort do_send_xframe during device disconnect (%d)\n", rate_limit);
+ ret = -ENODEV;
+ goto failure;
+ }
+ /*
+ * If something really bad happend, do not overflow the USB stack
+ */
+ if(atomic_read(&xusb->pending_writes) > MAX_PENDING_WRITES) {
+ static int rate_limit;
+
+ if((rate_limit++ % 5000) == 0)
+ XUSB_ERR(xusb,
+ "USB device is totaly stuck. Dropping packets (#%d).\n",
+ rate_limit);
+ ret = -ENODEV;
+ goto failure;
+ }
+ uframe = xframe->priv;
+ BUG_ON(!uframe);
+ BUG_ON(uframe->uframe_magic != UFRAME_MAGIC);
+ uframe_recompute(uframe, XUSB_SEND);
+ urb = &uframe->urb;
+ BUG_ON(!urb);
+ /* update urb length */
+ urb->transfer_buffer_length = XFRAME_LEN(xframe);
+ do_gettimeofday(&xframe->tv_submitted);
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if(ret < 0) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1000) == 0)
+ XBUS_ERR(xbus, "%s: usb_submit_urb failed: %d\n",
+ __FUNCTION__, ret);
+ ret = -EBADF;
+ goto failure;
+ }
+// if (debug)
+// dump_xframe("USB_FRAME_SEND", xbus, xframe, debug);
+ atomic_inc(&xusb->pending_writes);
+ return 0;
+failure:
+ XUSB_COUNTER(xusb, TX_ERRORS)++;
+ FREE_SEND_XFRAME(xbus, xframe); /* return to pool */
+ return ret;
+}
+
+/*
+ * PCM wrapper
+ */
+static int xframe_send_pcm(xbus_t *xbus, xframe_t *xframe)
+{
+ xusb_t *xusb;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xframe);
+ xusb = xusb_of(xbus);
+ BUG_ON(!xusb);
+ if(xusb->drop_next_pcm) {
+ FREE_SEND_XFRAME(xbus, xframe); /* return to pool */
+ xusb->drop_next_pcm = 0;
+ return -EIO;
+ }
+ return do_send_xframe(xbus, xframe);
+}
+
+/*
+ * commands wrapper
+ */
+static int xframe_send_cmd(xbus_t *xbus, xframe_t *xframe)
+{
+ BUG_ON(!xbus);
+ BUG_ON(!xframe);
+ //XBUS_INFO(xbus, "%s:\n", __FUNCTION__);
+ return do_send_xframe(xbus, xframe);
+}
+
+/*
+ * get a urb from the receive_pool and submit it on the read endpoint.
+ */
+static bool xusb_listen(xusb_t *xusb)
+{
+ xbus_t *xbus = get_xbus(xusb->xbus_num);
+ xframe_t *xframe;
+ struct uframe *uframe;
+ int ret = 0;
+
+ BUG_ON(!xbus);
+ xframe = ALLOC_RECV_XFRAME(xbus);
+ if(!xframe) {
+ XBUS_ERR(xbus, "Empty receive_pool\n");
+ goto out;
+ }
+ uframe = xframe_to_uframe(xframe);
+ uframe_recompute(uframe, XUSB_RECV);
+ ret = usb_submit_urb(&uframe->urb, GFP_ATOMIC);
+ if(ret < 0) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1000) == 0)
+ XBUS_ERR(xbus, "%s: usb_submit_urb failed: %d\n",
+ __FUNCTION__, ret);
+ FREE_RECV_XFRAME(xbus, xframe);
+ goto out;
+ }
+ atomic_inc(&xusb->pending_reads);
+ ret = 1;
+out:
+ put_xbus(xbus);
+ return ret;
+}
+
+/*------------------------- XPP USB Bus Handling -------------------*/
+
+enum XUSB_MODELS {
+ MODEL_FPGA_XPD
+};
+
+static const struct xusb_model_info {
+ const char *desc;
+ int iface_num;
+ struct xusb_endpoint in;
+ struct xusb_endpoint out;
+} model_table[] = {
+ [MODEL_FPGA_XPD] = {
+ .iface_num = 0,
+ .in = { .ep_addr = 0x86 },
+ .out = { .ep_addr = 0x02 },
+ .desc = "FPGA_XPD"
+ },
+};
+
+/* table of devices that work with this driver */
+static const struct usb_device_id xusb_table [] = {
+ { USB_DEVICE(0xE4E4, 0x1132), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_FXS
+ { USB_DEVICE(0xE4E4, 0x1142), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_1141
+ { USB_DEVICE(0xE4E4, 0x1152), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_1151
+ { USB_DEVICE(0xE4E4, 0x1162), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_1161
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, xusb_table);
+
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver xusb_driver = {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+ .owner = THIS_MODULE,
+#endif
+ .name = "xpp_usb",
+ .probe = xusb_probe,
+ .disconnect = xusb_disconnect,
+ .id_table = xusb_table,
+};
+
+/*
+ * File operations needed when we register this driver.
+ * This assumes that this driver NEEDS file operations,
+ * of course, which means that the driver is expected
+ * to have a node in the /dev directory. If the USB
+ * device were for a network interface then the driver
+ * would use "struct net_driver" instead, and a serial
+ * device would use "struct tty_driver".
+ */
+static struct file_operations xusb_fops = {
+ /*
+ * The owner field is part of the module-locking
+ * mechanism. The idea is that the kernel knows
+ * which module to increment the use-counter of
+ * BEFORE it calls the device's open() function.
+ * This also means that the kernel can decrement
+ * the use-counter again before calling release()
+ * or should the open() function fail.
+ */
+ .owner = THIS_MODULE,
+};
+
+/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with devfs and the driver core
+ */
+static struct usb_class_driver xusb_class = {
+ .name = "usb/xpp_usb%d",
+ .fops = &xusb_fops,
+/* FIXME: The sysfs class interfase seems to have chaged around here */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+ .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
+#endif
+ .minor_base = USB_SKEL_MINOR_BASE,
+};
+
+/*
+ * Check that an endpoint's wMaxPacketSize attribute is 512. This
+ * indicates that it is a USB2's high speed end point.
+ *
+ * If it is 64, it means we have a USB1 controller. By default we do not
+ * support it and just fail the probe of the device. However if the user
+ * has set usb1=1, we continue and just put a notice.
+ *
+ * Returns true if all OK, false otherwise.
+ */
+static int check_usb1(struct usb_endpoint_descriptor *endpoint)
+{
+ const char *msg = (usb_pipein(endpoint->bEndpointAddress))?"input":"output";
+
+ if(endpoint->wMaxPacketSize >= sizeof(xpacket_t))
+ return 1;
+
+ if(usb1) {
+ NOTICE("USB1 endpoint detected: USB %s endpoint 0x%X support only wMaxPacketSize=%d.\n",
+ msg, endpoint->bEndpointAddress, endpoint->wMaxPacketSize);
+ return 1;
+ }
+ NOTICE("USB1 endpoint detected. Device disabled. To enable: usb1=1, and read docs. (%s, endpoint %d, size %d).\n",
+ msg, endpoint->bEndpointAddress, endpoint->wMaxPacketSize);
+ return 0;
+}
+
+/*
+ * set up the endpoint information
+ * check out the endpoints
+ * FIXME: Should be simplified (above 2.6.10) to use usb_dev->ep_in[0..16] and usb_dev->ep_out[0..16]
+ */
+static int set_endpoints(xusb_t *xusb, struct usb_host_interface *iface_desc, struct xusb_model_info *model_info)
+{
+ struct usb_endpoint_descriptor *endpoint;
+ struct xusb_endpoint *xusb_ep;
+ int ep_addr;
+ int i;
+
+#define BULK_ENDPOINT(ep) (((ep)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ ep_addr = endpoint->bEndpointAddress;
+
+ if(!BULK_ENDPOINT(endpoint)) {
+ DBG(DEVICES, "endpoint 0x%x is not bulk: mbAttributes=0x%X\n",
+ ep_addr, endpoint->bmAttributes);
+ continue;
+ }
+ if(usb_pipein(ep_addr)) { // Input
+ if(ep_addr == model_info->in.ep_addr) {
+ if (!check_usb1(endpoint))
+ return 0;
+ xusb_ep = &xusb->endpoints[XUSB_RECV];
+ xusb_ep->ep_addr = ep_addr;
+ xusb_ep->max_size = endpoint->wMaxPacketSize;
+ xusb_ep->callback = xpp_receive_callback;
+ }
+ } else { // Output
+ if(ep_addr == model_info->out.ep_addr) {
+ if (!check_usb1(endpoint))
+ return 0;
+ xusb_ep = &xusb->endpoints[XUSB_SEND];
+ xusb_ep->ep_addr = ep_addr;
+ xusb_ep->max_size = endpoint->wMaxPacketSize;
+ xusb_ep->callback = xpp_send_callback;
+ }
+ }
+ }
+ if (!xusb->endpoints[XUSB_RECV].ep_addr || !xusb->endpoints[XUSB_SEND].ep_addr) {
+ XUSB_ERR(xusb, "Couldn't find bulk-in or bulk-out endpoints\n");
+ return 0;
+ }
+ DBG(DEVICES, "in=0x%02X out=0x%02X\n", xusb->endpoints[XUSB_RECV].ep_addr, xusb->endpoints[XUSB_SEND].ep_addr);
+ return 1;
+}
+
+/*
+ * The USB stack before 2.6.10 seems to be a bit shoddy. It seems that when
+ * being called from the probe we may already have the lock to udev (the Usb DEVice).
+ * Thus we call the internal __usb_reset_device instead.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+#define DO_USB_RESET_DEVICE(dev) __usb_reset_device(dev)
+#else
+#define DO_USB_RESET_DEVICE(dev) usb_reset_device(dev)
+#endif
+
+/**
+ * xusb_probe
+ *
+ * Called by the usb core when a new device is connected that it thinks
+ * this driver might be interested in.
+ */
+static int xusb_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct usb_host_interface *iface_desc = usb_altnum_to_altsetting(interface, 0);
+ xusb_t *xusb = NULL;
+ struct xusb_model_info *model_info = (struct xusb_model_info*)id->driver_info;
+ struct proc_dir_entry *procsummary = NULL;
+ xbus_t *xbus = NULL;
+ unsigned long flags;
+ int retval = -ENOMEM;
+ int i;
+
+ DBG(DEVICES, "New XUSB device MODEL=%s\n", model_info->desc);
+ if(iface_desc->desc.bInterfaceNumber != model_info->iface_num) {
+ DBG(DEVICES, "Skip interface #%d != #%d\n",
+ iface_desc->desc.bInterfaceNumber, model_info->iface_num);
+ return -ENODEV;
+ }
+ if((retval = DO_USB_RESET_DEVICE(udev)) < 0) {
+ ERR("usb_reset_device failed: %d\n", retval);
+ goto probe_failed;
+ }
+ if (!model_info) {
+ ERR("Missing endpoint setup for this device %d:%d\n",
+ udev->descriptor.idVendor,udev->descriptor.idProduct);
+ retval = -ENODEV;
+ goto probe_failed;
+ }
+
+ /* allocate memory for our device state and initialize it */
+ xusb = KZALLOC(sizeof(xusb_t), GFP_KERNEL);
+ if (xusb == NULL) {
+ ERR("xpp_usb: Unable to allocate new xpp usb bus\n");
+ retval = -ENOMEM;
+ goto probe_failed;
+ }
+ init_MUTEX (&xusb->sem);
+ atomic_set(&xusb->pending_writes, 0);
+ atomic_set(&xusb->pending_reads, 0);
+ atomic_set(&xusb->pcm_tx_drops, 0);
+ atomic_set(&xusb->usb_sluggish_count, 0);
+ xusb->udev = udev;
+ xusb->interface = interface;
+ xusb->model_info = model_info;
+
+ if(!set_endpoints(xusb, iface_desc, model_info)) {
+ retval = -ENODEV;
+ goto probe_failed;
+ }
+#ifndef USB_FIELDS_MISSING
+ xusb->serial = udev->serial;
+ xusb->manufacturer = udev->manufacturer;
+ xusb->product = udev->product;
+ xusb->interface_name = iface_desc->string;
+#else
+ USB_GET_STRING(udev, iSerialNumber, xusb->serial);
+ USB_GET_STRING(udev, iManufacturer, xusb->manufacturer);
+ USB_GET_STRING(udev, iProduct, xusb->product);
+ USB_GET_IFACE_NAME(udev, iface_desc, xusb->interface_name);
+#endif
+ INFO("XUSB: %s -- %s -- %s\n",
+ xusb->manufacturer, xusb->product, xusb->interface_name);
+
+ /* allow device read, write and ioctl */
+ xusb->present = 1;
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata (interface, xusb);
+ retval = usb_register_dev (interface, &xusb_class);
+ if (retval) {
+ /* something prevented us from registering this driver */
+ ERR ("Not able to get a minor for this device.\n");
+ goto probe_failed;
+ }
+
+ xusb->minor = interface->minor;
+
+ /* let the user know what node this device is now attached to */
+ DBG(DEVICES, "USB XPP device now attached to minor %d\n", xusb->minor);
+ xbus = xbus_new(&xusb_ops, min(xusb->endpoints[XUSB_SEND].max_size, xusb->endpoints[XUSB_RECV].max_size), xusb);
+ if(!xbus) {
+ retval = -ENOMEM;
+ goto probe_failed;
+ }
+ spin_lock_irqsave(&xusb_lock, flags);
+ for(i = 0; i < MAX_BUSES; i++) {
+ if(xusb_array[i] == NULL)
+ break;
+ }
+ spin_unlock_irqrestore(&xusb_lock, flags);
+ if(i >= MAX_BUSES) {
+ ERR("xpp_usb: Too many XPP USB buses\n");
+ retval = -ENOMEM;
+ goto probe_failed;
+ }
+ usb_make_path(udev, xusb->path, XBUS_DESCLEN); // May trunacte... ignore
+ snprintf(xbus->location, XBUS_DESCLEN, "%s", xusb->path);
+ if(xusb->serial && xusb->serial[0])
+ snprintf(xbus->label, LABEL_SIZE, "usb:%s", xusb->serial);
+ xusb->index = i;
+ xusb_array[i] = xusb;
+ XUSB_DBG(DEVICES, xusb, "GOT XPP USB BUS: %s\n", xbus->location);
+
+#ifdef CONFIG_PROC_FS
+ DBG(PROC, "Creating proc entry " PROC_USBXPP_SUMMARY " in bus proc dir.\n");
+ procsummary = create_proc_read_entry(PROC_USBXPP_SUMMARY, 0444, xbus->proc_xbus_dir,
+ xusb_read_proc, xusb);
+ if (!procsummary) {
+ XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_USBXPP_SUMMARY);
+ // FIXME: better error handling
+ retval = -EIO;
+ goto probe_failed;
+ }
+ procsummary->owner = THIS_MODULE;
+#endif
+ bus_count++;
+ xusb->xbus_num = xbus->num;
+ /* prepare several pending frames for receive side */
+ for(i = 0; i < 10; i++)
+ xusb_listen(xusb);
+ xbus_activate(xbus);
+ return retval;
+probe_failed:
+ ERR("Failed to initialize xpp usb bus: %d\n", retval);
+ usb_set_intfdata (interface, NULL);
+ if(xusb) {
+ if(xusb->minor) { // passed registration phase
+ ERR("Calling usb_deregister_dev()\n");
+ usb_deregister_dev(interface, &xusb_class);
+ }
+ ERR("Removing failed xusb\n");
+ KZFREE(xusb);
+ }
+ if(xbus) {
+ if(procsummary) {
+ XBUS_DBG(PROC, xbus, "Remove proc_entry: " PROC_USBXPP_SUMMARY "\n");
+ remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir);
+ procsummary = NULL;
+ }
+ ERR("Calling xbus_disconnect()\n");
+ xbus_disconnect(xbus); // Blocking until fully deactivated!
+ }
+ return retval;
+}
+
+/**
+ * xusb_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ *
+ * This routine guarantees that the driver will not submit any more urbs
+ * by clearing dev->udev. It is also supposed to terminate any currently
+ * active urbs. Unfortunately, usb_bulk_msg(), used in xusb_read(), does
+ * not provide any way to do this. But at least we can cancel an active
+ * write.
+ */
+static void xusb_disconnect(struct usb_interface *interface)
+{
+ xusb_t *xusb;
+ xbus_t *xbus;
+ int minor;
+ int i;
+
+ DBG(DEVICES, "CALLED\n");
+ /* prevent races with open() */
+ down (&disconnect_sem);
+
+ xusb = usb_get_intfdata (interface);
+ xusb->present = 0;
+ xbus = get_xbus(xusb->xbus_num);
+
+ /* find our xusb */
+ for(i = 0; i < MAX_BUSES; i++) {
+ if(xusb_array[i] == xusb)
+ break;
+ }
+ BUG_ON(i >= MAX_BUSES);
+ xusb_array[i] = NULL;
+
+#ifdef CONFIG_PROC_FS
+ if(xbus->proc_xbus_dir) {
+ XBUS_DBG(PROC, xbus, "Remove proc_entry: " PROC_USBXPP_SUMMARY "\n");
+ remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir);
+ }
+#endif
+ /*
+ * put_xbus() would be called during xbus_disconnect()
+ */
+ xbus_disconnect(xbus); // Blocking until fully deactivated!
+ usb_set_intfdata (interface, NULL);
+
+ down (&xusb->sem);
+ minor = xusb->minor;
+
+ /* give back our minor */
+ usb_deregister_dev (interface, &xusb_class);
+
+ up (&xusb->sem);
+ DBG(DEVICES, "Semaphore released\n");
+ XUSB_INFO(xusb, "now disconnected\n");
+ KZFREE(xusb);
+
+ up (&disconnect_sem);
+}
+
+static void xpp_send_callback(USB_PASS_CB(urb))
+{
+ struct uframe *uframe = urb_to_uframe(urb);
+ xframe_t *xframe = &uframe->xframe;
+ xusb_t *xusb = uframe->xusb;
+ xbus_t *xbus = get_xbus(xusb->xbus_num);
+ struct timeval now;
+ long usec;
+ int writes = atomic_read(&xusb->pending_writes);
+ int i;
+
+ if(!xbus) {
+ XUSB_ERR(xusb, "Sent URB does not belong to a valid xbus anymore...\n");
+ return;
+ }
+ //flip_parport_bit(6);
+ atomic_dec(&xusb->pending_writes);
+ do_gettimeofday(&now);
+ xusb->last_tx = xframe->tv_submitted;
+ usec = usec_diff(&now, &xframe->tv_submitted);
+ if(usec > xusb->max_tx_delay)
+ xusb->max_tx_delay = usec;
+ i = usec / USEC_BUCKET;
+ if(i >= NUM_BUCKETS)
+ i = NUM_BUCKETS - 1;
+ xusb->usb_tx_delay[i]++;
+ if(unlikely(usec > tx_sluggish)) {
+ atomic_inc(&xusb->usb_sluggish_count);
+ if(xusb->sluggish_debounce++ > drop_pcm_after) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 500) /* skip first messages */
+ XUSB_NOTICE(xusb,
+ "Sluggish USB. Dropping next PCM frame (pending_writes=%d)\n",
+ writes);
+ atomic_inc(&xusb->pcm_tx_drops);
+ xusb->drop_next_pcm = 1;
+ xusb->sluggish_debounce = 0;
+ }
+ } else
+ xusb->sluggish_debounce = 0;
+ /* sync/async unlink faults aren't errors */
+ if (urb->status && !(urb->status == -ENOENT || urb->status == -ECONNRESET)) {
+ static int rate_limit;
+ if((rate_limit++ % 1000) < 10) {
+ XUSB_ERR(xusb,
+ "nonzero write bulk status received: %d (pending_writes=%d)\n",
+ urb->status, writes);
+ dump_xframe("usb-write-error", xbus, xframe, DBG_ANY);
+ }
+ XUSB_COUNTER(xusb, TX_ERRORS)++;
+ } else
+ XUSB_COUNTER(xusb, TX_FRAMES)++;
+ FREE_SEND_XFRAME(xbus, xframe);
+ if(!xusb->present)
+ XUSB_ERR(xusb, "A urb from non-connected device?\n");
+ put_xbus(xbus);
+}
+
+static void xpp_receive_callback(USB_PASS_CB(urb))
+{
+ struct uframe *uframe = urb_to_uframe(urb);
+ xframe_t *xframe = &uframe->xframe;
+ xusb_t *xusb = uframe->xusb;
+ xbus_t *xbus = get_xbus(xusb->xbus_num);
+ size_t size;
+ bool do_resubmit = 1;
+ bool is_inuse = 0;
+ struct timeval now;
+
+ do_gettimeofday(&now);
+ atomic_dec(&xusb->pending_reads);
+ if(!xbus) {
+ XUSB_ERR(xusb, "Received URB does not belong to a valid xbus anymore...\n");
+ return;
+ }
+ if(!XBUS_GET(xbus)) {
+ XUSB_ERR(xusb, "Dropping urb. Is shutting down.\n");
+ do_resubmit = 0;
+ goto err;
+ }
+ is_inuse = 1;
+ if(!xusb->present) {
+ do_resubmit = 0;
+ goto err;
+ }
+ if (urb->status) {
+ DBG(GENERAL, "nonzero read bulk status received: %d\n", urb->status);
+ XUSB_COUNTER(xusb, RX_ERRORS)++;
+ goto err;
+ }
+ size = urb->actual_length;
+ if(size == 0) {
+ static int rate_limit;
+
+ if((rate_limit++ % 5003) == 0)
+ XUSB_NOTICE(xusb, "Received a zero length URBs (%d)\n", rate_limit);
+ XUSB_COUNTER(xusb, RCV_ZERO_LEN)++;
+ goto err;
+ }
+ atomic_set(&xframe->frame_len, size);
+ xframe->tv_received = now;
+
+// if (debug)
+// dump_xframe("USB_FRAME_RECEIVE", xbus, xframe, debug);
+ XUSB_COUNTER(xusb, RX_FRAMES)++;
+ /* Send UP */
+ xbus_receive_xframe(xbus, xframe);
+end:
+ if(is_inuse)
+ XBUS_PUT(xbus);
+ if(do_resubmit)
+ xusb_listen(xusb);
+ put_xbus(xbus);
+ return;
+err:
+ FREE_RECV_XFRAME(xbus, xframe);
+ goto end;
+}
+
+
+/*------------------------- Initialization -------------------------*/
+
+static void xpp_usb_cleanup(void)
+{
+ if(xusb_cache) {
+ kmem_cache_destroy(xusb_cache);
+ xusb_cache = NULL;
+ }
+}
+
+static int __init xpp_usb_init(void)
+{
+ int ret;
+ //xusb_t *xusb;
+
+ INFO("revision %s\n", XPP_VERSION);
+ xusb_cache = kmem_cache_create("xusb_cache",
+ sizeof(xframe_t) + XFRAME_DATASIZE,
+ 0, 0,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+ NULL,
+#endif
+ NULL);
+ if(!xusb_cache) {
+ ret = -ENOMEM;
+ goto failure;
+ }
+
+ /* register this driver with the USB subsystem */
+ ret = usb_register(&xusb_driver);
+ if (ret) {
+ ERR("usb_register failed. Error number %d\n", ret);
+ goto failure;
+ }
+ return 0;
+failure:
+ xpp_usb_cleanup();
+ return ret;
+}
+
+
+static void __exit xpp_usb_shutdown(void)
+{
+ DBG(GENERAL, "\n");
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&xusb_driver);
+ xpp_usb_cleanup();
+}
+
+
+
+#ifdef CONFIG_PROC_FS
+
+static int xusb_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ int i;
+ //unsigned long stamp = jiffies;
+ xusb_t *xusb = data;
+ uint usb_tx_delay[NUM_BUCKETS];
+ const int mark_limit = tx_sluggish/USEC_BUCKET;
+
+ if(!xusb)
+ goto out;
+ // TODO: probably needs a per-xusb lock:
+ spin_lock_irqsave(&xusb_lock, flags);
+ len += sprintf(page + len, "Device: %03d/%03d\n",
+ xusb->udev->bus->busnum,
+ xusb->udev->devnum
+ );
+ len += sprintf(page + len, "USB: manufacturer=%s\n", xusb->manufacturer);
+ len += sprintf(page + len, "USB: product=%s\n", xusb->product);
+ len += sprintf(page + len, "USB: serial=%s\n", xusb->serial);
+ len += sprintf(page + len, "Minor: %d\nModel Info: %s\n",
+ xusb->minor, xusb->model_info->desc);
+ len += sprintf(page + len, "Endpoints:\n"
+ "\tIn: 0x%02X - Size: %d)\n"
+ "\tOut: 0x%02X - Size: %d)\n",
+ xusb->endpoints[XUSB_RECV].ep_addr,
+ xusb->endpoints[XUSB_RECV].max_size,
+ xusb->endpoints[XUSB_SEND].ep_addr,
+ xusb->endpoints[XUSB_SEND].max_size
+ );
+ len += sprintf(page + len, "\npending_writes=%d\n", atomic_read(&xusb->pending_writes));
+ len += sprintf(page + len, "pending_reads=%d\n", atomic_read(&xusb->pending_reads));
+ len += sprintf(page + len, "max_tx_delay=%d\n", xusb->max_tx_delay);
+ xusb->max_tx_delay = 0;
+#ifdef DEBUG_PCM_TIMING
+ len += sprintf(page + len, "\nstamp_last_pcm_read=%lld accumulate_diff=%lld\n", stamp_last_pcm_read, accumulate_diff);
+#endif
+ memcpy(usb_tx_delay, xusb->usb_tx_delay, sizeof(usb_tx_delay));
+ len += sprintf(page + len, "usb_tx_delay[%d,%d,%d]: ",
+ USEC_BUCKET, BUCKET_START, NUM_BUCKETS);
+ for(i = BUCKET_START; i < NUM_BUCKETS; i++) {
+ len += sprintf(page + len, "%6d ",
+ usb_tx_delay[i]);
+ if(i == mark_limit)
+ len += sprintf(page + len, "| ");
+ }
+ len += sprintf(page + len, "\nPCM_TX_DROPS: %5d (sluggish: %d)\n",
+ atomic_read(&xusb->pcm_tx_drops),
+ atomic_read(&xusb->usb_sluggish_count)
+ );
+ len += sprintf(page + len, "\nCOUNTERS:\n");
+ for(i = 0; i < XUSB_COUNTER_MAX; i++) {
+ len += sprintf(page + len, "\t%-15s = %d\n", xusb_counters[i].name, xusb->counters[i]);
+ }
+#if 0
+ len += sprintf(page + len, "<-- len=%d\n", len);
+#endif
+ spin_unlock_irqrestore(&xusb_lock, flags);
+out:
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+
+}
+
+#endif
+
+
+
+MODULE_DESCRIPTION("XPP USB Transport Driver");
+MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(XPP_VERSION);
+
+module_init(xpp_usb_init);
+module_exit(xpp_usb_shutdown);
diff --git a/drivers/dahdi/xpp/xpp_zap.c b/drivers/dahdi/xpp/xpp_zap.c
new file mode 100644
index 0000000..5ee7303
--- /dev/null
+++ b/drivers/dahdi/xpp/xpp_zap.c
@@ -0,0 +1,1087 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004, Xorcom
+ *
+ * Derived from ztdummy
+ *
+ * Copyright (C) 2002, Hermes Softlab
+ * Copyright (C) 2004, 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/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+# warning "This module is tested only with 2.6 kernels"
+#endif
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h> /* for udelay */
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <zaptel.h>
+#include "xbus-core.h"
+#include "xproto.h"
+#include "xpp_zap.h"
+#include "parport_debug.h"
+
+static const char rcsid[] = "$Id$";
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *xpp_proc_toplevel = NULL;
+#define PROC_DIR "xpp"
+#define PROC_XPD_ZTREGISTER "zt_registration"
+#define PROC_XPD_BLINK "blink"
+#define PROC_XPD_SUMMARY "summary"
+#endif
+
+#define MAX_QUEUE_LEN 10000
+#define DELAY_UNTIL_DIALTONE 3000
+
+DEF_PARM(int, debug, 0, 0644, "Print DBG statements");
+static DEF_PARM_BOOL(zap_autoreg, 0, 0644, "Register spans automatically (1) or not (0)");
+static DEF_PARM_BOOL(prefmaster, 0, 0644, "Do we want to be zaptel preferred sync master");
+// DEF_ARRAY(int, pcmtx, 4, 0, "Forced PCM values to transmit");
+
+#include "zap_debug.h"
+
+#ifdef DEBUG_SYNC_PARPORT
+/*
+ * Use parallel port to sample our PCM sync and diagnose quality and
+ * potential problems. A logic analizer or a scope should be connected
+ * to the data bits of the parallel port.
+ *
+ * Array parameter: Choose the two xbuses Id's to sample.
+ * This can be changed on runtime as well. Example:
+ * echo "3,5" > /sys/module/xpp/parameters/parport_xbuses
+ */
+static int parport_xbuses[2] = { 0, 1 };
+unsigned int parport_xbuses_num_values;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
+module_param_array(parport_xbuses, int, &parport_xbuses_num_values, 0577);
+#else
+module_param_array(parport_xbuses, int, parport_xbuses_num_values, 0577);
+#endif
+MODULE_PARM_DESC(parport_xbuses, "Id's of xbuses to sample (1-2)");
+
+/*
+ * Flip a single bit in the parallel port:
+ * - The bit number is either bitnum0 or bitnum1
+ * - Bit is selected by xbus number from parport_xbuses[]
+ */
+void xbus_flip_bit(xbus_t *xbus, unsigned int bitnum0, unsigned int bitnum1)
+{
+ int num = xbus->num;
+
+ if(num == parport_xbuses[0])
+ flip_parport_bit(bitnum0);
+ if(num == parport_xbuses[1])
+ flip_parport_bit(bitnum1);
+}
+EXPORT_SYMBOL(xbus_flip_bit);
+#endif
+
+static atomic_t num_registered_spans = ATOMIC_INIT(0);
+
+int total_registered_spans(void)
+{
+ return atomic_read(&num_registered_spans);
+}
+
+static int zaptel_register_xpd(xpd_t *xpd);
+static int zaptel_unregister_xpd(xpd_t *xpd);
+static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int proc_xpd_ztregister_read(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int proc_xpd_ztregister_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+static int proc_xpd_blink_read(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int proc_xpd_blink_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+
+/*------------------------- XPD Management -------------------------*/
+
+static void xpd_proc_remove(xbus_t *xbus, xpd_t *xpd)
+{
+#ifdef CONFIG_PROC_FS
+ if(xpd->proc_xpd_dir) {
+ chip_proc_remove(xbus, xpd);
+ if(xpd->proc_xpd_summary) {
+ XPD_DBG(PROC, xpd, "Removing proc '%s'\n", PROC_XPD_SUMMARY);
+ remove_proc_entry(PROC_XPD_SUMMARY, xpd->proc_xpd_dir);
+ xpd->proc_xpd_summary = NULL;
+ }
+ if(xpd->proc_xpd_ztregister) {
+ XPD_DBG(PROC, xpd, "Removing proc '%s'\n", PROC_XPD_ZTREGISTER);
+ remove_proc_entry(PROC_XPD_ZTREGISTER, xpd->proc_xpd_dir);
+ xpd->proc_xpd_ztregister = NULL;
+ }
+ if(xpd->proc_xpd_blink) {
+ XPD_DBG(PROC, xpd, "Removing proc '%s'\n", PROC_XPD_BLINK);
+ remove_proc_entry(PROC_XPD_BLINK, xpd->proc_xpd_dir);
+ xpd->proc_xpd_blink = NULL;
+ }
+ XPD_DBG(PROC, xpd, "Removing %s/%s proc directory\n",
+ xbus->busname, xpd->xpdname);
+ remove_proc_entry(xpd->xpdname, xbus->proc_xbus_dir);
+ xpd->proc_xpd_dir = NULL;
+ }
+#endif
+}
+
+static int xpd_proc_create(xbus_t *xbus, xpd_t *xpd)
+{
+#ifdef CONFIG_PROC_FS
+ XPD_DBG(PROC, xpd, "Creating proc directory\n");
+ xpd->proc_xpd_dir = proc_mkdir(xpd->xpdname, xbus->proc_xbus_dir);
+ if(!xpd->proc_xpd_dir) {
+ XPD_ERR(xpd, "Failed to create proc directory\n");
+ goto err;
+ }
+ xpd->proc_xpd_summary = create_proc_read_entry(PROC_XPD_SUMMARY, 0444, xpd->proc_xpd_dir,
+ xpd_read_proc, xpd);
+ if(!xpd->proc_xpd_summary) {
+ XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_XPD_SUMMARY);
+ goto err;
+ }
+ xpd->proc_xpd_summary->owner = THIS_MODULE;
+ xpd->proc_xpd_ztregister = create_proc_entry(PROC_XPD_ZTREGISTER, 0644, xpd->proc_xpd_dir);
+ if (!xpd->proc_xpd_ztregister) {
+ XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_XPD_ZTREGISTER);
+ goto err;
+ }
+ xpd->proc_xpd_ztregister->owner = THIS_MODULE;
+ xpd->proc_xpd_ztregister->data = xpd;
+ xpd->proc_xpd_ztregister->read_proc = proc_xpd_ztregister_read;
+ xpd->proc_xpd_ztregister->write_proc = proc_xpd_ztregister_write;
+ xpd->proc_xpd_blink = create_proc_entry(PROC_XPD_BLINK, 0644, xpd->proc_xpd_dir);
+ if (!xpd->proc_xpd_blink) {
+ XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_XPD_BLINK);
+ goto err;
+ }
+ xpd->proc_xpd_blink->owner = THIS_MODULE;
+ xpd->proc_xpd_blink->data = xpd;
+ xpd->proc_xpd_blink->read_proc = proc_xpd_blink_read;
+ xpd->proc_xpd_blink->write_proc = proc_xpd_blink_write;
+ if(chip_proc_create(xbus, xpd) < 0)
+ goto err;
+#endif
+ return 0;
+err:
+ xpd_proc_remove(xbus, xpd);
+ return -EFAULT;
+}
+
+void xpd_free(xpd_t *xpd)
+{
+ xbus_t *xbus = NULL;
+
+ if(!xpd)
+ return;
+ if(xpd->xproto)
+ xproto_put(xpd->xproto); /* was taken in xpd_alloc() */
+ xpd->xproto = NULL;
+ xbus = xpd->xbus;
+ if(!xbus)
+ return;
+ XPD_DBG(DEVICES, xpd, "\n");
+ xpd_proc_remove(xbus, xpd);
+ xbus_unregister_xpd(xbus, xpd);
+ KZFREE(xpd);
+}
+
+
+__must_check int xpd_common_init(xbus_t *xbus, xpd_t *xpd, int unit, int subunit, int subtype, int subunits)
+{
+ int ret;
+
+ MKADDR(&xpd->addr, unit, subunit);
+ xpd->xbus_idx = XPD_IDX(unit,subunit);
+ snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%1d%1d", unit, subunit);
+ xpd->subtype = subtype;
+ xpd->subunits = subunits;
+ xpd->offhook = 0;
+
+ /* For USB-1 disable some channels */
+ if(MAX_SEND_SIZE(xbus) < RPACKET_SIZE(GLOBAL, PCM_WRITE)) {
+ xpp_line_t no_pcm;
+
+ no_pcm = 0x7F | xpd->digital_outputs | xpd->digital_inputs;
+ xpd->no_pcm = no_pcm;
+ XBUS_NOTICE(xbus, "max xframe size = %d, disabling some PCM channels. no_pcm=0x%04X\n",
+ MAX_SEND_SIZE(xbus), xpd->no_pcm);
+ }
+ if((ret = xpd_proc_create(xbus, xpd)) < 0)
+ return ret;
+ xbus_register_xpd(xbus, xpd);
+ return 0;
+}
+
+/*
+ * Synchronous part of XPD detection.
+ * Called from xbus_poll()
+ */
+int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table,
+ int unit,
+ int subunit,
+ byte type,
+ byte subtype,
+ int subunits,
+ byte port_dir)
+{
+ xpd_t *xpd = NULL;
+ bool to_phone;
+ int ret = -EINVAL;
+
+ BUG_ON(type == XPD_TYPE_NOMODULE);
+ to_phone = BIT(subunit) & port_dir;
+ BUG_ON(!xbus);
+ xpd = xpd_byaddr(xbus, unit, subunit);
+ if(xpd) {
+ XPD_NOTICE(xpd, "XPD at %d%d already exists\n",
+ unit, subunit);
+ goto out;
+ }
+ xpd = proto_table->xops.card_new(xbus, unit, subunit, proto_table, subtype, subunits, to_phone);
+ if(!xpd) {
+ XBUS_NOTICE(xbus, "card_new(%d,%d,%d,%d,%d) failed. Ignored.\n",
+ unit, subunit, proto_table->type, subtype, to_phone);
+ goto err;
+ }
+out:
+ return 0;
+err:
+ if(xpd)
+ xpd_free(xpd);
+ return ret;
+}
+
+void xpd_post_init(xpd_t *xpd)
+{
+ XPD_DBG(DEVICES, xpd, "\n");
+ if(zap_autoreg)
+ zaptel_register_xpd(xpd);
+}
+
+#ifdef CONFIG_PROC_FS
+
+/**
+ * Prints a general procfs entry for the bus, under xpp/BUSNAME/summary
+ * @page TODO: figure out procfs
+ * @start TODO: figure out procfs
+ * @off TODO: figure out procfs
+ * @count TODO: figure out procfs
+ * @eof TODO: figure out procfs
+ * @data an xbus_t pointer with the bus data.
+ */
+static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ xpd_t *xpd = data;
+ xbus_t *xbus;
+ int i;
+
+ if(!xpd)
+ goto out;
+
+ xbus = xpd->xbus;
+ len += sprintf(page + len, "%s (%s, card %s, span %d)\n"
+ "timing_priority: %d\n"
+ "timer_count: %d span->mainttimer=%d\n"
+ ,
+ xpd->xpdname, xpd->type_name,
+ (xpd->card_present) ? "present" : "missing",
+ (SPAN_REGISTERED(xpd)) ? xpd->span.spanno : 0,
+ xpd->timing_priority,
+ xpd->timer_count, xpd->span.mainttimer
+ );
+ len += sprintf(page + len, "Address: U=%d S=%d\n", xpd->addr.unit, xpd->addr.subunit);
+ len += sprintf(page + len, "Subunits: %d\n", xpd->subunits);
+ len += sprintf(page + len, "Type: %d.%d\n\n", xpd->type, xpd->subtype);
+ len += sprintf(page + len, "pcm_len=%d\n\n", xpd->pcm_len);
+ len += sprintf(page + len, "wanted_pcm_mask=0x%04X\n\n", xpd->wanted_pcm_mask);
+ len += sprintf(page + len, "mute_dtmf=0x%04X\n\n", xpd->mute_dtmf);
+ len += sprintf(page + len, "STATES:");
+ len += sprintf(page + len, "\n\t%-17s: ", "output_relays");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%d ", IS_SET(xpd->digital_outputs, i));
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "input_relays");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%d ", IS_SET(xpd->digital_inputs, i));
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "offhook");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%d ", IS_SET(xpd->offhook, i));
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "cid_on");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%d ", IS_SET(xpd->cid_on, i));
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "msg_waiting");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%d ", IS_SET(xpd->msg_waiting, i));
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "ringing");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%d ", xpd->ringing[i]);
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "no_pcm");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%d ", IS_SET(xpd->no_pcm, i));
+ }
+#if 1
+ if(SPAN_REGISTERED(xpd)) {
+ len += sprintf(page + len, "\nPCM:\n | [readchunk] | [writechunk] | W D");
+ for_each_line(xpd, i) {
+ struct zt_chan *chans = xpd->span.chans;
+ byte rchunk[ZT_CHUNKSIZE];
+ byte wchunk[ZT_CHUNKSIZE];
+ byte *rp;
+ byte *wp;
+ int j;
+
+ if(IS_SET(xpd->digital_outputs, i))
+ continue;
+ if(IS_SET(xpd->digital_inputs, i))
+ continue;
+ if(IS_SET(xpd->digital_signalling, i))
+ continue;
+ rp = chans[i].readchunk;
+ wp = chans[i].writechunk;
+ memcpy(rchunk, rp, ZT_CHUNKSIZE);
+ memcpy(wchunk, wp, ZT_CHUNKSIZE);
+ len += sprintf(page + len, "\n port %2d> | ", i);
+ for(j = 0; j < ZT_CHUNKSIZE; j++) {
+ len += sprintf(page + len, "%02X ", rchunk[j]);
+ }
+ len += sprintf(page + len, " | ");
+ for(j = 0; j < ZT_CHUNKSIZE; j++) {
+ len += sprintf(page + len, "%02X ", wchunk[j]);
+ }
+ len += sprintf(page + len, " | %c",
+ (IS_SET(xpd->wanted_pcm_mask, i))?'+':' ');
+ len += sprintf(page + len, " %c",
+ (IS_SET(xpd->mute_dtmf, i))?'-':' ');
+ }
+ }
+#endif
+#if 0
+ if(SPAN_REGISTERED(xpd)) {
+ len += sprintf(page + len, "\nSignalling:\n");
+ for_each_line(xpd, i) {
+ struct zt_chan *chan = &xpd->span.chans[i];
+ len += sprintf(page + len, "\t%2d> sigcap=0x%04X sig=0x%04X\n", i, chan->sigcap, chan->sig);
+ }
+ }
+#endif
+ len += sprintf(page + len, "\nCOUNTERS:\n");
+ for(i = 0; i < XPD_COUNTER_MAX; i++) {
+ len += sprintf(page + len, "\t\t%-20s = %d\n",
+ xpd_counters[i].name, xpd->counters[i]);
+ }
+ len += sprintf(page + len, "<-- len=%d\n", len);
+out:
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+
+}
+
+#endif
+
+/*
+ * xpd_alloc - Allocator for new XPD's
+ *
+ */
+xpd_t *xpd_alloc(size_t privsize, const xproto_table_t *proto_table, int channels)
+{
+ xpd_t *xpd = NULL;
+ size_t alloc_size = sizeof(xpd_t) + privsize;
+ int type = proto_table->type;
+
+ BUG_ON(!proto_table);
+ DBG(DEVICES, "type=%d channels=%d (alloc_size=%zd)\n",
+ type, channels, alloc_size);
+ if(channels > CHANNELS_PERXPD) {
+ ERR("%s: type=%d: too many channels %d\n",
+ __FUNCTION__, type, channels);
+ goto err;
+ }
+
+ if((xpd = KZALLOC(alloc_size, GFP_KERNEL)) == NULL) {
+ ERR("%s: type=%d: Unable to allocate memory\n",
+ __FUNCTION__, type);
+ goto err;
+ }
+ xpd->priv = (byte *)xpd + sizeof(xpd_t);
+ spin_lock_init(&xpd->lock);
+ xpd->xbus = NULL;
+ xpd->xbus_idx = -1;
+ xpd->channels = channels;
+ xpd->chans = NULL;
+ xpd->card_present = 0;
+ xpd->offhook = 0x0; /* ONHOOK */
+ xpd->type = proto_table->type;
+ xpd->xproto = proto_table;
+ xpd->xops = &proto_table->xops;
+ xpd->digital_outputs = 0;
+ xpd->digital_inputs = 0;
+
+ atomic_set(&xpd->zt_registered, 0);
+ atomic_set(&xpd->open_counter, 0);
+
+ xpd->chans = kmalloc(sizeof(struct zt_chan)*xpd->channels, GFP_KERNEL);
+ if (xpd->chans == NULL) {
+ ERR("%s: Unable to allocate channels\n", __FUNCTION__);
+ goto err;
+ }
+ xproto_get(type); /* will be returned in xpd_free() */
+ return xpd;
+err:
+ if(xpd) {
+ if(xpd->chans)
+ kfree((void *)xpd->chans);
+ kfree(xpd);
+ }
+ return NULL;
+}
+
+/* FIXME: this should be removed once digium patch their zaptel.h
+ * I simply wish to avoid changing zaptel.h in the xpp patches.
+ */
+#ifndef ZT_EVENT_REMOVED
+#define ZT_EVENT_REMOVED (20)
+#endif
+
+void xpd_disconnect(xpd_t *xpd)
+{
+ unsigned long flags;
+
+ BUG_ON(!xpd);
+
+ spin_lock_irqsave(&xpd->lock, flags);
+ XPD_DBG(DEVICES, xpd, "(%p)\n", xpd->xproto);
+ if(!xpd->card_present) /* Multiple reports */
+ goto out;
+ xpd->card_present = 0;
+ if(SPAN_REGISTERED(xpd)) {
+ int i;
+
+ update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
+ /* TODO: Should this be done before releasing the spinlock? */
+ XPD_DBG(DEVICES, xpd, "Queuing ZT_EVENT_REMOVED on all channels to ask user to release them\n");
+ for (i=0; i<xpd->span.channels; i++)
+ zt_qevent_lock(&xpd->chans[i],ZT_EVENT_REMOVED);
+ }
+out:
+ spin_unlock_irqrestore(&xpd->lock, flags);
+}
+
+void xpd_remove(xpd_t *xpd)
+{
+ xbus_t *xbus;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ XPD_INFO(xpd, "Remove\n");
+ zaptel_unregister_xpd(xpd);
+ CALL_XMETHOD(card_remove, xbus, xpd);
+ xpd_free(xpd);
+}
+
+void update_xpd_status(xpd_t *xpd, int alarm_flag)
+{
+ struct zt_span *span = &xpd->span;
+
+ if(!SPAN_REGISTERED(xpd)) {
+ // XPD_NOTICE(xpd, "%s: XPD is not registered. Skipping.\n", __FUNCTION__);
+ return;
+ }
+ switch (alarm_flag) {
+ case ZT_ALARM_NONE:
+ xpd->last_response = jiffies;
+ break;
+ default:
+ // Nothing
+ break;
+ }
+ if(span->alarms == alarm_flag)
+ return;
+ span->alarms = alarm_flag;
+ zt_alarm_notify(span);
+ XPD_DBG(GENERAL, xpd, "Update XPD alarms: %s -> %02X\n", xpd->span.name, alarm_flag);
+}
+
+void update_line_status(xpd_t *xpd, int pos, bool to_offhook)
+{
+ zt_rxsig_t rxsig;
+
+ BUG_ON(!xpd);
+ if(to_offhook) {
+ BIT_SET(xpd->offhook, pos);
+ rxsig = ZT_RXSIG_OFFHOOK;
+ } else {
+ BIT_CLR(xpd->offhook, pos);
+ BIT_CLR(xpd->cid_on, pos);
+ rxsig = ZT_RXSIG_ONHOOK;
+ /*
+ * To prevent latest PCM to stay in buffers
+ * indefinitely, mark this channel for a
+ * single silence transmittion.
+ *
+ * This bit will be cleared on the next tick.
+ */
+ BIT_SET(xpd->silence_pcm, pos);
+ }
+ /*
+ * We should not spinlock before calling zt_hooksig() as
+ * it may call back into our xpp_hooksig() and cause
+ * a nested spinlock scenario
+ */
+ LINE_DBG(SIGNAL, xpd, pos, "rxsig=%s\n", (rxsig == ZT_RXSIG_ONHOOK) ? "ONHOOK" : "OFFHOOK");
+ if(SPAN_REGISTERED(xpd))
+ zt_hooksig(&xpd->chans[pos], rxsig);
+}
+
+#ifdef CONFIG_PROC_FS
+static int proc_xpd_ztregister_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xpd_t *xpd = data;
+
+ BUG_ON(!xpd);
+ spin_lock_irqsave(&xpd->lock, flags);
+
+ len += sprintf(page + len, "%d\n", SPAN_REGISTERED(xpd) ? xpd->span.spanno : 0);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+}
+
+static int proc_xpd_ztregister_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ xpd_t *xpd = data;
+ char buf[MAX_PROC_WRITE];
+ int zt_reg;
+ int ret;
+
+ BUG_ON(!xpd);
+ if(count >= MAX_PROC_WRITE)
+ return -EINVAL;
+ if(copy_from_user(buf, buffer, count))
+ return -EFAULT;
+ buf[count] = '\0';
+ ret = sscanf(buf, "%d", &zt_reg);
+ if(ret != 1)
+ return -EINVAL;
+ XPD_DBG(GENERAL, xpd, "%s\n", (zt_reg) ? "register" : "unregister");
+ if(zt_reg)
+ ret = zaptel_register_xpd(xpd);
+ else
+ ret = zaptel_unregister_xpd(xpd);
+ return (ret < 0) ? ret : count;
+}
+
+static int proc_xpd_blink_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xpd_t *xpd = data;
+
+ BUG_ON(!xpd);
+ spin_lock_irqsave(&xpd->lock, flags);
+
+ len += sprintf(page + len, "%d\n", xpd->blink_mode);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+}
+
+static int proc_xpd_blink_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ xpd_t *xpd = data;
+ char buf[MAX_PROC_WRITE];
+ char *endp;
+ unsigned blink;
+
+
+ BUG_ON(!xpd);
+ if(count >= MAX_PROC_WRITE)
+ return -EINVAL;
+ if(copy_from_user(buf, buffer, count))
+ return -EFAULT;
+ buf[count] = '\0';
+ if(count > 0 && buf[count-1] == '\n') /* chomp */
+ buf[count-1] = '\0';
+ blink = simple_strtoul(buf, &endp, 0);
+ if(*endp != '\0' || blink > 0xFFFF)
+ return -EINVAL;
+ XPD_DBG(GENERAL, xpd, "BLINK channels: 0x%X\n", blink);
+ xpd->blink_mode = blink;
+ return count;
+}
+
+#endif
+
+
+#define XPP_MAX_LEN 512
+
+/*------------------------- Zaptel Interfaces ----------------------*/
+
+
+/*
+ * Called from zaptel with spinlock held on chan. Must not call back
+ * zaptel functions.
+ */
+int xpp_open(struct zt_chan *chan)
+{
+#if 0
+ xpd_t *xpd = chan->pvt;
+ xbus_t *xbus = xpd->xbus;
+ int pos = chan->chanpos - 1;
+ unsigned long flags;
+#else
+ xpd_t *xpd;
+ xbus_t *xbus;
+ int pos;
+ unsigned long flags;
+
+ if (!chan) {
+ NOTICE("open called on a null chan\n");
+ return -EINVAL;
+ }
+ xpd = chan->pvt;
+ if (!xpd) {
+ NOTICE("open called on a chan with no pvt (xpd)\n");
+ return -EINVAL;
+ }
+ xbus = xpd->xbus;
+ if (!xbus) {
+ NOTICE("open called on a chan with no xbus\n");
+ return -EINVAL;
+ }
+ pos = chan->chanpos - 1;
+#endif
+
+ spin_lock_irqsave(&xbus->lock, flags);
+ atomic_inc(&xbus->xbus_ref_count);
+ atomic_inc(&xpd->open_counter);
+ if(IS_SET(xpd->digital_signalling, pos)) /* D-chan offhook */
+ BIT_SET(xpd->offhook, pos);
+ DBG(DEVICES, "chan=%d (xbus_ref_count=%d)\n",
+ pos, atomic_read(&xbus->xbus_ref_count));
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ if(xpd->xops->card_open)
+ xpd->xops->card_open(xpd, pos);
+ return 0;
+}
+
+int xpp_close(struct zt_chan *chan)
+{
+ xpd_t *xpd = chan->pvt;
+ xbus_t *xbus = xpd->xbus;
+ int pos = chan->chanpos - 1;
+ unsigned long flags;
+
+ spin_lock_irqsave(&xbus->lock, flags);
+ atomic_dec(&xpd->open_counter);
+ if(IS_SET(xpd->digital_signalling, pos)) /* D-chan onhook */
+ BIT_CLR(xpd->offhook, pos);
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ if(xpd->xops->card_close)
+ xpd->xops->card_close(xpd, pos);
+ XPD_DBG(GENERAL, xpd, "pid=%d: chan=%d (xbus_ref_count=%d)\n",
+ current->pid, pos, atomic_read(&xbus->xbus_ref_count));
+ if(atomic_dec_and_test(&xbus->xbus_ref_count))
+ xbus_remove(xbus);
+ return 0;
+}
+
+void report_bad_ioctl(const char *msg, xpd_t *xpd, int pos, unsigned int cmd)
+{
+ XPD_NOTICE(xpd, "%s: Bad ioctl\n", msg);
+ XPD_NOTICE(xpd, "ENOTTY: chan=%d cmd=0x%x\n", pos, cmd);
+ XPD_NOTICE(xpd, " IOC_TYPE=0x%02X\n", _IOC_TYPE(cmd));
+ XPD_NOTICE(xpd, " IOC_DIR=0x%02X\n", _IOC_DIR(cmd));
+ XPD_NOTICE(xpd, " IOC_NR=%d\n", _IOC_NR(cmd));
+ XPD_NOTICE(xpd, " IOC_SIZE=0x%02X\n", _IOC_SIZE(cmd));
+}
+
+int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
+{
+ xpd_t *xpd = chan->pvt;
+ int pos = chan->chanpos - 1;
+
+ if(!xpd) {
+ ERR("%s: channel in pos %d, was already closed. Ignore.\n",
+ __FUNCTION__, pos);
+ return -ENODEV;
+ }
+ switch (cmd) {
+ default:
+ /* Some span-specific commands before we give up: */
+ if (xpd->xops->card_ioctl != NULL) {
+ return xpd->xops->card_ioctl(xpd, pos, cmd, arg);
+ }
+ report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd);
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int xpp_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
+{
+ xpd_t *xpd = chan->pvt;
+ xbus_t *xbus;
+ int pos = chan->chanpos - 1;
+
+ if(!xpd) {
+ ERR("%s: channel in pos %d, was already closed. Ignore.\n",
+ __FUNCTION__, pos);
+ return -ENODEV;
+ }
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ DBG(SIGNAL, "Setting %s to %s (%d)\n", chan->name, txsig2str(txsig), txsig);
+ return CALL_XMETHOD(card_hooksig, xbus, xpd, pos, txsig);
+}
+
+/* Req: Set the requested chunk size. This is the unit in which you must
+ report results for conferencing, etc */
+int xpp_setchunksize(struct zt_span *span, int chunksize);
+
+/* Enable maintenance modes */
+int xpp_maint(struct zt_span *span, int cmd)
+{
+ xpd_t *xpd = span->pvt;
+ int ret = 0;
+#if 0
+ char loopback_data[] = "THE-QUICK-BROWN-FOX-JUMPED-OVER-THE-LAZY-DOG";
+#endif
+
+ DBG(GENERAL, "span->mainttimer=%d\n", span->mainttimer);
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ printk("XXX Turn off local and remote loops XXX\n");
+ break;
+ case ZT_MAINT_LOCALLOOP:
+ printk("XXX Turn on local loopback XXX\n");
+ break;
+ case ZT_MAINT_REMOTELOOP:
+ printk("XXX Turn on remote loopback XXX\n");
+ break;
+ case ZT_MAINT_LOOPUP:
+ printk("XXX Send loopup code XXX\n");
+ // CALL_XMETHOD(LOOPBACK_AX, xpd->xbus, xpd, loopback_data, ARRAY_SIZE(loopback_data));
+ break;
+ case ZT_MAINT_LOOPDOWN:
+ printk("XXX Send loopdown code XXX\n");
+ break;
+ case ZT_MAINT_LOOPSTOP:
+ printk("XXX Stop sending loop codes XXX\n");
+ break;
+ default:
+ ERR("XPP: Unknown maint command: %d\n", cmd);
+ ret = -EINVAL;
+ break;
+ }
+ if (span->mainttimer || span->maintstat)
+ update_xpd_status(xpd, ZT_ALARM_LOOPBACK);
+ return ret;
+}
+
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+/*
+ * If the watchdog detects no received data, it will call the
+ * watchdog routine
+ */
+static int xpp_watchdog(struct zt_span *span, int cause)
+{
+ static int rate_limit = 0;
+
+ if((rate_limit++ % 1000) == 0)
+ DBG(GENERAL, "\n");
+ return 0;
+}
+#endif
+
+/**
+ * Unregister an xpd from zaptel and release related resources
+ * @xpd The xpd to be unregistered
+ * @returns 0 on success, errno otherwise
+ *
+ * Checks that nobody holds an open channel.
+ *
+ * Called by:
+ * - User action through /proc
+ * - During xpd_remove()
+ */
+static int zaptel_unregister_xpd(xpd_t *xpd)
+{
+ unsigned long flags;
+
+ BUG_ON(!xpd);
+ spin_lock_irqsave(&xpd->lock, flags);
+
+ if(!SPAN_REGISTERED(xpd)) {
+ XPD_NOTICE(xpd, "Already unregistered\n");
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return -EIDRM;
+ }
+ update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
+ if(atomic_read(&xpd->open_counter)) {
+ XPD_NOTICE(xpd, "Busy (open_counter=%d). Skipping.\n", atomic_read(&xpd->open_counter));
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return -EBUSY;
+ }
+ mdelay(2); // FIXME: This is to give chance for transmit/receiveprep to finish.
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if(xpd->card_present)
+ xpd->xops->card_zaptel_preregistration(xpd, 0);
+ atomic_dec(&xpd->zt_registered);
+ atomic_dec(&num_registered_spans);
+ zt_unregister(&xpd->span);
+ if(xpd->card_present)
+ xpd->xops->card_zaptel_postregistration(xpd, 0);
+ return 0;
+}
+
+static int zaptel_register_xpd(xpd_t *xpd)
+{
+ struct zt_span *span;
+ xbus_t *xbus;
+ int cn;
+ const xops_t *xops;
+
+ BUG_ON(!xpd);
+ xops = xpd->xops;
+ xbus = xpd->xbus;
+
+ if (SPAN_REGISTERED(xpd)) {
+ XPD_ERR(xpd, "Already registered\n");
+ return -EEXIST;
+ }
+ cn = xpd->channels;
+ XPD_DBG(DEVICES, xpd, "Initializing span: %d channels.\n", cn);
+ memset(xpd->chans, 0, sizeof(struct zt_chan)*cn);
+ memset(&xpd->span, 0, sizeof(struct zt_span));
+
+ span = &xpd->span;
+ snprintf(span->name, MAX_SPANNAME, "%s/%s", xbus->busname, xpd->xpdname);
+ span->deflaw = ZT_LAW_MULAW; /* default, may be overriden by card_* drivers */
+ init_waitqueue_head(&span->maintq);
+ span->pvt = xpd;
+ span->channels = cn;
+ span->chans = xpd->chans;
+
+ span->open = xpp_open;
+ span->close = xpp_close;
+ span->flags = ZT_FLAG_RBS;
+ span->hooksig = xpp_hooksig; /* Only with RBS bits */
+ span->ioctl = xpp_ioctl;
+ span->maint = xpp_maint;
+#ifdef ZT_SPANSTAT_V2
+ /*
+ * This actually describe the zt_spaninfo version 3
+ * A bunch of unrelated data exported via a modified ioctl()
+ * What a bummer...
+ */
+ span->manufacturer = "Xorcom Inc."; /* OK, that's obvious */
+ /* span->spantype = "...."; set in card_zaptel_preregistration() */
+ /*
+ * Yes, this basically duplicates information available
+ * from the description field. If some more is needed
+ * why not add it there?
+ * OK, let's add to the kernel more useless info.
+ */
+ snprintf(span->devicetype, sizeof(span->devicetype) - 1,
+ "Astribank: Unit %x Subunit %x: %s",
+ XBUS_UNIT(xpd->xbus_idx), XBUS_SUBUNIT(xpd->xbus_idx),
+ xpd->type_name);
+ /*
+ * location is the only usefull new data item.
+ * For our devices it was available for ages via:
+ * - The legacy "/proc/xpp/XBUS-??/summary" (CONNECTOR=...)
+ * - The same info in "/proc/xpp/xbuses"
+ * - The modern "/sys/bus/astribanks/devices/xbus-??/connector" attribute
+ * So let's also export it via the newfangled "location" field.
+ */
+ snprintf(span->location, sizeof(span->location) - 1, "%s", xbus->location);
+ /*
+ * Who said a span and irq have 1-1 relationship?
+ * Also exporting this low-level detail isn't too wise.
+ * No irq's for you today!
+ */
+ span->irq = 0;
+#endif
+#ifdef ZAPTEL_SYNC_TICK
+ span->sync_tick = zaptel_sync_tick;
+#endif
+ if (xpp_ec)
+ span->echocan = xpp_echocan;
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+ span->watchdog = xpp_watchdog;
+#endif
+
+ snprintf(xpd->span.desc, MAX_SPANDESC, "Xorcom XPD #%02d/%1d%1d: %s",
+ xbus->num, xpd->addr.unit, xpd->addr.subunit, xpd->type_name);
+ XPD_DBG(GENERAL, xpd, "Registering span '%s'\n", xpd->span.desc);
+ xpd->xops->card_zaptel_preregistration(xpd, 1);
+ if(zt_register(&xpd->span, prefmaster)) {
+ XPD_ERR(xpd, "Failed to zt_register span\n");
+ return -ENODEV;
+ }
+ atomic_inc(&num_registered_spans);
+ atomic_inc(&xpd->zt_registered);
+ xpd->xops->card_zaptel_postregistration(xpd, 1);
+ /*
+ * Update zaptel about our state
+ */
+#if 0
+ /*
+ * FIXME: since asterisk didn't open the channel yet, the report
+ * is discarded anyway. OTOH, we cannot report in xpp_open or
+ * xpp_chanconfig since zaptel call them with a spinlock on the channel
+ * and zt_hooksig tries to acquire the same spinlock, resulting in
+ * double spinlock deadlock (we are lucky that RH/Fedora kernel are
+ * compiled with spinlock debugging).... tough.
+ */
+ for_each_line(xpd, cn) {
+ struct zt_chan *chans = xpd->span.chans;
+
+ if(IS_SET(xpd->offhook, cn)) {
+ LINE_NOTICE(xpd, cn, "Report OFFHOOK to zaptel\n");
+ zt_hooksig(&chans[cn], ZT_RXSIG_OFFHOOK);
+ }
+ }
+#endif
+ return 0;
+}
+
+/*------------------------- Proc debugging interface ---------------*/
+
+#ifdef CONFIG_PROC_FS
+
+#if 0
+static int xpp_zap_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+}
+#endif
+
+#endif
+
+/*------------------------- Initialization -------------------------*/
+
+static void do_cleanup(void)
+{
+#ifdef CONFIG_PROC_FS
+ if(xpp_proc_toplevel) {
+ DBG(GENERAL, "Removing '%s' from proc\n", PROC_DIR);
+ remove_proc_entry(PROC_DIR, NULL);
+ xpp_proc_toplevel = NULL;
+ }
+#endif
+}
+
+static int __init xpp_zap_init(void)
+{
+ int ret = 0;
+
+ INFO("revision %s MAX_XPDS=%d (%d*%d)\n", XPP_VERSION,
+ MAX_XPDS, MAX_UNIT, MAX_SUBUNIT);
+#ifdef CONFIG_ZAPATA_BRI_DCHANS
+ INFO("FEATURE: with BRISTUFF support\n");
+#else
+ INFO("FEATURE: without BRISTUFF support\n");
+#endif
+#ifdef CONFIG_PROC_FS
+ xpp_proc_toplevel = proc_mkdir(PROC_DIR, NULL);
+ if(!xpp_proc_toplevel) {
+ ret = -EIO;
+ goto err;
+ }
+#endif
+ ret = xbus_core_init();
+ if(ret) {
+ ERR("xbus_core_init failed (%d)\n", ret);
+ goto err;
+ }
+ ret = xbus_pcm_init(xpp_proc_toplevel);
+ if(ret) {
+ ERR("xbus_pcm_init failed (%d)\n", ret);
+ xbus_core_shutdown();
+ goto err;
+ }
+ return 0;
+err:
+ do_cleanup();
+ return ret;
+}
+
+static void __exit xpp_zap_cleanup(void)
+{
+ xbus_pcm_shutdown();
+ xbus_core_shutdown();
+ do_cleanup();
+}
+
+EXPORT_SYMBOL(debug);
+EXPORT_SYMBOL(xpd_common_init);
+EXPORT_SYMBOL(create_xpd);
+EXPORT_SYMBOL(xpd_post_init);
+EXPORT_SYMBOL(xpd_alloc);
+EXPORT_SYMBOL(xpd_free);
+EXPORT_SYMBOL(xpd_disconnect);
+EXPORT_SYMBOL(update_xpd_status);
+EXPORT_SYMBOL(update_line_status);
+EXPORT_SYMBOL(xpp_open);
+EXPORT_SYMBOL(xpp_close);
+EXPORT_SYMBOL(xpp_ioctl);
+EXPORT_SYMBOL(xpp_maint);
+EXPORT_SYMBOL(report_bad_ioctl);
+
+MODULE_DESCRIPTION("XPP Zaptel Driver");
+MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(XPP_VERSION);
+
+module_init(xpp_zap_init);
+module_exit(xpp_zap_cleanup);
diff --git a/drivers/dahdi/xpp/xpp_zap.h b/drivers/dahdi/xpp/xpp_zap.h
new file mode 100644
index 0000000..dd56657
--- /dev/null
+++ b/drivers/dahdi/xpp/xpp_zap.h
@@ -0,0 +1,53 @@
+#ifndef XPP_ZAP_H
+#define XPP_ZAP_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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 "xpd.h"
+#include "xproto.h"
+
+void xpd_disconnect(xpd_t *xpd);
+int xpd_common_init(xbus_t *xbus, xpd_t *xpd, int unit, int subunit, int subtype, int subunits);
+int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table,
+ int unit, int subunit, byte type, byte subtype, int subunits, byte port_dir);
+void xpd_post_init(xpd_t *xpd);
+xpd_t *xpd_alloc(size_t privsize, const xproto_table_t *proto_table, int channels);
+void xpd_free(xpd_t *xpd);
+void xpd_remove(xpd_t *xpd);
+void update_xpd_status(xpd_t *xpd, int alarm_flag);
+void update_line_status(xpd_t *xpd, int pos, bool good);
+int xpp_open(struct zt_chan *chan);
+int xpp_close(struct zt_chan *chan);
+int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg);
+int xpp_maint(struct zt_span *span, int cmd);
+void report_bad_ioctl(const char *msg, xpd_t *xpd, int pos, unsigned int cmd);
+int total_registered_spans(void);
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+
+extern struct proc_dir_entry *xpp_proc_toplevel;
+#endif
+
+#define SPAN_REGISTERED(xpd) atomic_read(&(xpd)->zt_registered)
+
+#endif /* XPP_ZAP_H */
diff --git a/drivers/dahdi/xpp/xproto.c b/drivers/dahdi/xpp/xproto.c
new file mode 100644
index 0000000..c3aa34e
--- /dev/null
+++ b/drivers/dahdi/xpp/xproto.c
@@ -0,0 +1,478 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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 "xpd.h"
+#include "xproto.h"
+#include "xpp_zap.h"
+#include "xbus-core.h"
+#include "zap_debug.h"
+#include <linux/module.h>
+#include <linux/delay.h>
+
+static const char rcsid[] = "$Id$";
+
+extern int debug;
+
+static const xproto_table_t *xprotocol_tables[XPD_TYPE_NOMODULE];
+
+#if MAX_UNIT*MAX_SUBUNIT > MAX_XPDS
+#error MAX_XPDS is too small
+#endif
+
+bool valid_xpd_addr(const struct xpd_addr *addr)
+{
+ return ((addr->subunit & ~BITMASK(SUBUNIT_BITS)) == 0) && ((addr->unit & ~BITMASK(UNIT_BITS)) == 0);
+}
+
+/*---------------- General Protocol Management ----------------------------*/
+
+const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, byte opcode)
+{
+ const xproto_entry_t *xe;
+
+ //DBG(GENERAL, "\n");
+ xe = &table->entries[opcode];
+ return (xe->handler != NULL) ? xe : NULL;
+}
+
+const xproto_entry_t *xproto_global_entry(byte opcode)
+{
+ const xproto_entry_t *xe;
+
+ xe = xproto_card_entry(&PROTO_TABLE(GLOBAL), opcode);
+ //DBG(GENERAL, "opcode=0x%X xe=%p\n", opcode, xe);
+ return xe;
+}
+
+xproto_handler_t xproto_global_handler(byte opcode)
+{
+ return xproto_card_handler(&PROTO_TABLE(GLOBAL), opcode);
+}
+
+static const xproto_table_t *xproto_table(xpd_type_t cardtype)
+{
+ if(cardtype >= XPD_TYPE_NOMODULE)
+ return NULL;
+ return xprotocol_tables[cardtype];
+}
+
+const xproto_table_t *xproto_get(xpd_type_t cardtype)
+{
+ const xproto_table_t *xtable;
+
+ if(cardtype >= XPD_TYPE_NOMODULE)
+ return NULL;
+ xtable = xprotocol_tables[cardtype];
+ if(!xtable) { /* Try to load the relevant module */
+ int ret = request_module(XPD_TYPE_PREFIX "%d", cardtype);
+ if(ret != 0) {
+ NOTICE("%s: Failed to load module for type=%d. exit status=%d.\n",
+ __FUNCTION__, cardtype, ret);
+ /* Drop through: we may be lucky... */
+ }
+ xtable = xprotocol_tables[cardtype];
+ }
+ if(xtable) {
+ BUG_ON(!xtable->owner);
+ DBG(GENERAL, "%s refcount was %d\n", xtable->name, module_refcount(xtable->owner));
+ if(!try_module_get(xtable->owner)) {
+ ERR("%s: try_module_get for %s failed.\n", __FUNCTION__, xtable->name);
+ return NULL;
+ }
+ }
+ return xtable;
+}
+
+void xproto_put(const xproto_table_t *xtable)
+{
+ BUG_ON(!xtable);
+ DBG(GENERAL, "%s refcount was %d\n", xtable->name, module_refcount(xtable->owner));
+ BUG_ON(module_refcount(xtable->owner) <= 0);
+ module_put(xtable->owner);
+}
+
+xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode)
+{
+ const xproto_entry_t *xe;
+
+ //DBG(GENERAL, "\n");
+ xe = xproto_card_entry(table, opcode);
+ return xe->handler;
+}
+
+void notify_bad_xpd(const char *funcname, xbus_t *xbus, const struct xpd_addr addr, const char *msg)
+{
+ XBUS_NOTICE(xbus, "%s: non-existing address (%1d%1d): %s\n",
+ funcname, addr.unit, addr.subunit, msg);
+}
+
+static int packet_process(xbus_t *xbus, xpacket_t *pack)
+{
+ byte op;
+ const xproto_entry_t *xe;
+ xproto_handler_t handler;
+ xproto_table_t *table;
+ xpd_t *xpd;
+ int ret = -EPROTO;
+
+ BUG_ON(!pack);
+ if(!valid_xpd_addr(&XPACKET_ADDR(pack))) {
+ if(printk_ratelimit()) {
+ XBUS_NOTICE(xbus, "%s: from %d%d: bad address.\n",
+ __FUNCTION__,
+ XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack));
+ dump_packet("packet_process -- bad address", pack, debug);
+ }
+ goto out;
+ }
+ op = XPACKET_OP(pack);
+ xpd = xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack));
+ /* XPD may be NULL (e.g: during bus polling */
+ xe = xproto_global_entry(op);
+ /*-------- Validations -----------*/
+ if(!xe) {
+ const xproto_table_t *xtable;
+
+ if(!xpd) {
+ if(printk_ratelimit()) {
+ XBUS_NOTICE(xbus, "%s: from %d%d opcode=0x%02X: no such global command.\n",
+ __FUNCTION__,
+ XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack), op);
+ dump_packet("packet_process -- no such global command", pack, 1);
+ }
+ goto out;
+ }
+ xtable = xproto_table(xpd->type);
+ if(!xtable) {
+ if(printk_ratelimit())
+ XPD_ERR(xpd, "%s: no protocol table (type=%d)\n",
+ __FUNCTION__,
+ xpd->type);
+ goto out;
+ }
+ xe = xproto_card_entry(xtable, op);
+ if(!xe) {
+ if(printk_ratelimit()) {
+ XPD_NOTICE(xpd, "%s: bad command (type=%d,opcode=0x%x)\n",
+ __FUNCTION__,
+ xpd->type, op);
+ dump_packet("packet_process -- bad command", pack, 1);
+ }
+ goto out;
+ }
+ }
+ table = xe->table;
+ BUG_ON(!table);
+ if(!table->packet_is_valid(pack)) {
+ if(printk_ratelimit()) {
+ ERR("xpp: %s: wrong size %d for opcode=0x%02X\n",
+ __FUNCTION__, XPACKET_LEN(pack), op);
+ dump_packet("packet_process -- wrong size", pack, debug);
+ }
+ goto out;
+ }
+ ret = 0; /* All well */
+ handler = xe->handler;
+ BUG_ON(!handler);
+ XBUS_COUNTER(xbus, RX_BYTES) += XPACKET_LEN(pack);
+ handler(xbus, xpd, xe, pack);
+out:
+ return ret;
+}
+
+static int xframe_receive_cmd(xbus_t *xbus, xframe_t *xframe)
+{
+ byte *xframe_end;
+ xpacket_t *pack;
+ byte *p;
+ int len;
+ int ret;
+
+ if(debug & DBG_COMMANDS)
+ dump_xframe("RX-CMD", xbus, xframe, DBG_ANY);
+ p = xframe->packets;
+ xframe_end = p + XFRAME_LEN(xframe);
+ do {
+ pack = (xpacket_t *)p;
+ len = XPACKET_LEN(pack);
+ /* Sanity checks */
+ if(unlikely(XPACKET_OP(pack) == XPROTO_NAME(GLOBAL,PCM_READ))) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0) {
+ XBUS_DBG(GENERAL, xbus, "A PCM packet within a Non-PCM xframe\n");
+ dump_xframe("In Non-PCM xframe", xbus, xframe, debug);
+ }
+ ret = -EPROTO;
+ goto out;
+ }
+ p += len;
+ if(p > xframe_end || len < RPACKET_HEADERSIZE) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0) {
+ XBUS_NOTICE(xbus, "Invalid packet length %d\n", len);
+ dump_xframe("BAD LENGTH", xbus, xframe, debug);
+ }
+ ret = -EPROTO;
+ goto out;
+ }
+ ret = packet_process(xbus, pack);
+ if(unlikely(ret < 0))
+ break;
+ } while(p < xframe_end);
+out:
+ FREE_RECV_XFRAME(xbus, xframe);
+ return ret;
+}
+
+int xframe_receive(xbus_t *xbus, xframe_t *xframe)
+{
+ int ret = 0;
+ struct timeval now;
+ struct timeval tv_received;
+ int usec;
+
+ if(XFRAME_LEN(xframe) < RPACKET_HEADERSIZE) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0) {
+ XBUS_NOTICE(xbus, "short xframe\n");
+ dump_xframe("short xframe", xbus, xframe, debug);
+ }
+ FREE_RECV_XFRAME(xbus, xframe);
+ return -EPROTO;
+ }
+ if(!XBUS_GET(xbus)) {
+ XBUS_DBG(GENERAL, xbus, "Dropped xframe. Is shutting down.\n");
+ return -ENODEV;
+ }
+ tv_received = xframe->tv_received;
+ /*
+ * We want to check that xframes do not mix PCM and other commands
+ */
+ if(XPACKET_IS_PCM((xpacket_t *)xframe->packets))
+ xframe_receive_pcm(xbus, xframe);
+ else {
+ XBUS_COUNTER(xbus, RX_CMD)++;
+ ret = xframe_receive_cmd(xbus, xframe);
+ }
+ /* Calculate total processing time */
+ do_gettimeofday(&now);
+ usec = (now.tv_sec - tv_received.tv_sec) * 1000000 +
+ now.tv_usec - tv_received.tv_usec;
+ if(usec > xbus->max_rx_process)
+ xbus->max_rx_process = usec;
+ XBUS_PUT(xbus);
+ return ret;
+}
+
+#define VERBOSE_DEBUG 1
+#define ERR_REPORT_LIMIT 20
+
+void dump_packet(const char *msg, const xpacket_t *packet, bool debug)
+{
+ byte op = XPACKET_OP(packet);
+ byte *addr = (byte *)&XPACKET_ADDR(packet);
+
+ if(!debug)
+ return;
+ printk(KERN_DEBUG "%s: XPD=%1X-%1X%c (0x%X) OP=0x%02X LEN=%d",
+ msg,
+ XPACKET_ADDR_UNIT(packet),
+ XPACKET_ADDR_SUBUNIT(packet),
+ (XPACKET_ADDR_SYNC(packet))?'+':' ',
+ *addr,
+ op,
+ XPACKET_LEN(packet));
+#if VERBOSE_DEBUG
+ {
+ int i;
+ byte *p = (byte *)packet;
+
+ printk(" BYTES: ");
+ for(i = 0; i < XPACKET_LEN(packet); i++) {
+ static int limiter = 0;
+
+ if(i >= sizeof(xpacket_t)) {
+ if(limiter < ERR_REPORT_LIMIT) {
+ ERR("%s: length overflow i=%d > sizeof(xpacket_t)=%lu\n",
+ __FUNCTION__, i+1, (long)sizeof(xpacket_t));
+ } else if(limiter == ERR_REPORT_LIMIT) {
+ ERR("%s: error packet #%d... squelsh reports.\n",
+ __FUNCTION__, limiter);
+ }
+ limiter++;
+ break;
+ }
+ if (debug)
+ printk("%02X ", p[i]);
+ }
+ }
+#endif
+ printk("\n");
+}
+
+void dump_reg_cmd(const char msg[], bool writing, xbus_t *xbus,
+ byte unit, xportno_t port, const reg_cmd_t *regcmd)
+{
+ char action;
+ char modifier;
+ char port_buf[MAX_PROC_WRITE];
+ char reg_buf[MAX_PROC_WRITE];
+ char data_buf[MAX_PROC_WRITE];
+
+ if(regcmd->bytes > sizeof(*regcmd) - 1) { /* The size byte is not included */
+ PORT_NOTICE(xbus, unit, port, "%s: %s: Too long: regcmd->bytes = %d\n",
+ __FUNCTION__, msg, regcmd->bytes);
+ return;
+ }
+ if(regcmd->is_multibyte) {
+ char buf[MAX_PROC_WRITE + 1];
+ int i;
+ int n = 0;
+ size_t len = regcmd->bytes;
+ const byte *p = REG_XDATA(regcmd);
+
+ buf[0] = '\0';
+ for(i = 0; i < len && n < MAX_PROC_WRITE; i++)
+ n += snprintf(&buf[n], MAX_PROC_WRITE - n, "%02X ", p[i]);
+ PORT_DBG(REGS, xbus, unit, port,
+ "UNIT-%d PORT-%d: Multibyte(eoframe=%d) %s[0..%zd]: %s%s\n",
+ unit, port, regcmd->eoframe,
+ msg, len-1, buf, (n >= MAX_PROC_WRITE)?"...":"");
+ return;
+ }
+ if(regcmd->bytes != sizeof(*regcmd) - 1) { /* The size byte is not included */
+ PORT_NOTICE(xbus, unit, port, "%s: %s: Wrong size: regcmd->bytes = %d\n",
+ __FUNCTION__, msg, regcmd->bytes);
+ return;
+ }
+ snprintf(port_buf, MAX_PROC_WRITE, "%d%s",
+ regcmd->portnum,
+ (REG_FIELD(regcmd, all_ports_broadcast)) ? "*" : "");
+ action = (REG_FIELD(regcmd, read_request)) ? 'R' : 'W';
+ modifier = 'D';
+ if(REG_FIELD(regcmd, do_subreg)) {
+ snprintf(reg_buf, MAX_PROC_WRITE, "%02X %02X",
+ REG_FIELD(regcmd, regnum),
+ REG_FIELD(regcmd, subreg));
+ modifier = 'S';
+ } else {
+ snprintf(reg_buf, MAX_PROC_WRITE, "%02X",
+ REG_FIELD(regcmd, regnum));
+ }
+ if(REG_FIELD(regcmd, read_request)) {
+ data_buf[0] = '\0';
+ } else if(REG_FIELD(regcmd, do_datah)) {
+ snprintf(data_buf, MAX_PROC_WRITE, "%02X %02X",
+ REG_FIELD(regcmd, data_low),
+ REG_FIELD(regcmd, data_high));
+ modifier = 'I';
+ } else {
+ snprintf(data_buf, MAX_PROC_WRITE, "%02X",
+ REG_FIELD(regcmd, data_low));
+ }
+ PORT_DBG(REGS, xbus, unit, port, "%s: %s %c%c %s %s\n",
+ msg, port_buf, action, modifier,
+ reg_buf, data_buf);
+}
+
+const char *xproto_name(xpd_type_t xpd_type)
+{
+ const xproto_table_t *proto_table;
+
+ BUG_ON(xpd_type >= XPD_TYPE_NOMODULE);
+ proto_table = xprotocol_tables[xpd_type];
+ if(!proto_table)
+ return NULL;
+ return proto_table->name;
+}
+
+#define CHECK_XOP(f) \
+ if(!(xops)->f) { \
+ ERR("%s: missing xmethod %s [%s (%d)]\n", __FUNCTION__, #f, name, type); \
+ return -EINVAL; \
+ }
+
+int xproto_register(const xproto_table_t *proto_table)
+{
+ int type;
+ const char *name;
+ const xops_t *xops;
+
+ BUG_ON(!proto_table);
+ type = proto_table->type;
+ name = proto_table->name;
+ if(type >= XPD_TYPE_NOMODULE) {
+ NOTICE("%s: Bad xproto type %d\n", __FUNCTION__, type);
+ return -EINVAL;
+ }
+ DBG(GENERAL, "%s (%d)\n", name, type);
+ if(xprotocol_tables[type])
+ NOTICE("%s: overriding registration of %s (%d)\n", __FUNCTION__, name, type);
+ xops = &proto_table->xops;
+ CHECK_XOP(card_new);
+ CHECK_XOP(card_init);
+ CHECK_XOP(card_remove);
+ CHECK_XOP(card_tick);
+ CHECK_XOP(card_pcm_fromspan);
+ CHECK_XOP(card_pcm_tospan);
+ CHECK_XOP(card_zaptel_preregistration);
+ CHECK_XOP(card_zaptel_postregistration);
+ CHECK_XOP(card_hooksig);
+ // CHECK_XOP(card_ioctl); // optional method -- call after testing
+ CHECK_XOP(card_register_reply);
+ CHECK_XOP(XPD_STATE);
+
+ xprotocol_tables[type] = proto_table;
+ return 0;
+}
+
+void xproto_unregister(const xproto_table_t *proto_table)
+{
+ int type;
+ const char *name;
+
+ BUG_ON(!proto_table);
+ type = proto_table->type;
+ name = proto_table->name;
+ DBG(GENERAL, "%s (%d)\n", name, type);
+ if(type >= XPD_TYPE_NOMODULE) {
+ NOTICE("%s: Bad xproto type %s (%d)\n", __FUNCTION__, name, type);
+ return;
+ }
+ if(!xprotocol_tables[type])
+ NOTICE("%s: xproto type %s (%d) is already unregistered\n", __FUNCTION__, name, type);
+ xprotocol_tables[type] = NULL;
+}
+
+EXPORT_SYMBOL(dump_packet);
+EXPORT_SYMBOL(dump_reg_cmd);
+EXPORT_SYMBOL(xframe_receive);
+EXPORT_SYMBOL(notify_bad_xpd);
+EXPORT_SYMBOL(valid_xpd_addr);
+EXPORT_SYMBOL(xproto_global_entry);
+EXPORT_SYMBOL(xproto_card_entry);
+EXPORT_SYMBOL(xproto_name);
+EXPORT_SYMBOL(xproto_register);
+EXPORT_SYMBOL(xproto_unregister);
diff --git a/drivers/dahdi/xpp/xproto.h b/drivers/dahdi/xpp/xproto.h
new file mode 100644
index 0000000..4691094
--- /dev/null
+++ b/drivers/dahdi/xpp/xproto.h
@@ -0,0 +1,292 @@
+#ifndef XPROTO_H
+#define XPROTO_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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 "xdefs.h"
+
+#ifdef __KERNEL__
+#include <linux/list.h>
+#include <linux/proc_fs.h>
+#include <zaptel.h>
+
+/*
+ * This must match the firmware protocol version
+ */
+#define XPP_PROTOCOL_VERSION 30
+
+struct xpd_addr {
+ uint8_t subunit:SUBUNIT_BITS;
+ uint8_t reserved:1;
+ uint8_t unit:UNIT_BITS;
+ uint8_t sync_master:1;
+} PACKED;
+
+#define MKADDR(p, u, s) do { \
+ (p)->unit = (u); \
+ (p)->subunit = (s); \
+ (p)->sync_master = 0; \
+ } while(0)
+
+struct xpacket_header {
+ uint16_t packet_len:10;
+ uint16_t reserved:1;
+ uint16_t is_pcm:1;
+ uint16_t pcmslot:4;
+ uint8_t opcode;
+ struct xpd_addr addr;
+} PACKED;
+
+#define XPACKET_OP(p) ((p)->head.opcode)
+#define XPACKET_LEN(p) ((p)->head.packet_len)
+#define XPACKET_IS_PCM(p) ((p)->head.is_pcm)
+#define XPACKET_PCMSLOT(p) ((p)->head.pcmslot)
+#define XPACKET_RESERVED(p) ((p)->head.reserved)
+#define XPACKET_ADDR(p) ((p)->head.addr)
+#define XPACKET_ADDR_UNIT(p) (XPACKET_ADDR(p).unit)
+#define XPACKET_ADDR_SUBUNIT(p) (XPACKET_ADDR(p).subunit)
+#define XPACKET_ADDR_SYNC(p) (XPACKET_ADDR(p).sync_master)
+#define XPACKET_ADDR_RESERVED(p) (XPACKET_ADDR(p).reserved)
+
+#define PROTO_TABLE(n) n ## _protocol_table
+
+/*
+ * The LSB of the type number signifies:
+ * 0 - TO_PSTN
+ * 1 - TO_PHONE
+ */
+#define XPD_TYPE_FXS 1 // TO_PHONE
+#define XPD_TYPE_FXO 2 // TO_PSTN
+#define XPD_TYPE_BRI 3 // TO_PSTN/TO_PHONE (from hardware)
+#define XPD_TYPE_PRI 4 // TO_PSTN/TO_PHONE (runtime)
+#define XPD_TYPE_NOMODULE 7
+
+typedef byte xpd_type_t;
+
+#define XPD_TYPE_PREFIX "xpd-type-"
+
+#define MODULE_ALIAS_XPD(type) \
+ MODULE_ALIAS(XPD_TYPE_PREFIX __stringify(type))
+
+#define PCM_CHUNKSIZE (CHANNELS_PERXPD * 8) /* samples of 8 bytes */
+
+bool valid_xpd_addr(const struct xpd_addr *addr);
+
+#define XPROTO_NAME(card,op) card ## _ ## op
+#define XPROTO_HANDLER(card,op) XPROTO_NAME(card,op ## _handler)
+#define XPROTO_CALLER(card,op) XPROTO_NAME(card,op ## _send)
+
+#define HANDLER_DEF(card,op) \
+ static int XPROTO_HANDLER(card,op) ( \
+ xbus_t *xbus, \
+ xpd_t *xpd, \
+ const xproto_entry_t *cmd, \
+ xpacket_t *pack)
+
+#define CALL_PROTO(card,op, ...) XPROTO_CALLER(card,op)( __VA_ARGS__ )
+
+#define DECLARE_CMD(card,op, ...) \
+ int CALL_PROTO(card, op, xbus_t *xbus, xpd_t *xpd, ## __VA_ARGS__ )
+
+#define HOSTCMD(card, op, ...) \
+ DECLARE_CMD(card, op, ## __VA_ARGS__ )
+
+#define RPACKET_NAME(card,op) XPROTO_NAME(RPACKET_ ## card, op)
+#define RPACKET_TYPE(card,op) struct RPACKET_NAME(card, op)
+
+#define DEF_RPACKET_DATA(card,op, ...) \
+ RPACKET_TYPE(card,op) { \
+ struct xpacket_header head; \
+ __VA_ARGS__ \
+ } PACKED
+#define RPACKET_HEADERSIZE sizeof(struct xpacket_header)
+#define RPACKET_FIELD(p,card,op,field) (((RPACKET_TYPE(card,op) *)(p))->field)
+#define RPACKET_SIZE(card,op) sizeof(RPACKET_TYPE(card,op))
+
+#define XENTRY(prototab,module,op) \
+ [ XPROTO_NAME(module,op) ] = { \
+ .handler = XPROTO_HANDLER(module,op), \
+ .datalen = RPACKET_SIZE(module,op), \
+ .name = #op, \
+ .table = &PROTO_TABLE(prototab) \
+ }
+
+#define XPACKET_INIT(p, card, op, to, pcm, pcmslot) \
+ do { \
+ XPACKET_OP(p) = XPROTO_NAME(card,op); \
+ XPACKET_LEN(p) = RPACKET_SIZE(card,op); \
+ XPACKET_IS_PCM(p) = (pcm); \
+ XPACKET_PCMSLOT(p) = (pcmslot); \
+ XPACKET_RESERVED(p) = 0; \
+ XPACKET_ADDR_UNIT(p) = XBUS_UNIT(to); \
+ XPACKET_ADDR_SUBUNIT(p) = XBUS_SUBUNIT(to); \
+ XPACKET_ADDR_SYNC(p) = 0; \
+ XPACKET_ADDR_RESERVED(p) = 0; \
+ } while(0)
+
+#define XFRAME_NEW_CMD(frm, p, xbus, card, op, to) \
+ do { \
+ int pack_len = RPACKET_SIZE(card,op); \
+ \
+ if(!TRANSPORT_RUNNING(xbus)) \
+ return -ENODEV; \
+ frm = ALLOC_SEND_XFRAME(xbus); \
+ if(!frm) \
+ return -ENOMEM; \
+ (p) = xframe_next_packet(frm, pack_len); \
+ if(!(p)) \
+ return -ENOMEM; \
+ XPACKET_INIT(p, card, op, to, 0, 0); \
+ } while(0)
+
+#endif
+
+/*--------------------------- register handling --------------------------------*/
+
+#define MULTIBYTE_MAX_LEN 5 /* FPGA firmware limitation */
+
+typedef struct reg_cmd {
+ byte bytes:3; /* Length (for Multibyte) */
+ byte eoframe:1; /* For BRI -- end of frame */
+ byte portnum:3; /* For port specific registers */
+ byte is_multibyte:1;
+ union {
+ struct {
+ byte reserved:4;
+ byte do_datah:1;
+ byte do_subreg:1;
+ byte read_request:1;
+ byte all_ports_broadcast:1;
+ byte regnum;
+ byte subreg;
+ byte data_low;
+ byte data_high;
+ } PACKED r;
+ /* For Write-Multibyte commands in BRI */
+ struct {
+ byte xdata[MULTIBYTE_MAX_LEN];
+ } PACKED d;
+ } PACKED alt;
+} PACKED reg_cmd_t;
+
+/* Shortcut access macros */
+#define REG_FIELD(regptr,member) ((regptr)->alt.r.member)
+#define REG_XDATA(regptr) ((regptr)->alt.d.xdata)
+
+#ifdef __KERNEL__
+/*--------------------------- protocol tables ----------------------------------*/
+
+typedef struct xproto_entry xproto_entry_t;
+typedef struct xproto_table xproto_table_t;
+
+typedef int (*xproto_handler_t)(
+ xbus_t *xbus,
+ xpd_t *xpd,
+ const xproto_entry_t *cmd,
+ xpacket_t *pack);
+
+const xproto_table_t *xproto_get(xpd_type_t cardtype);
+void xproto_put(const xproto_table_t *xtable);
+const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, byte opcode);
+xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode);
+
+const xproto_entry_t *xproto_global_entry(byte opcode);
+xproto_handler_t xproto_global_handler(byte opcode);
+
+#define CALL_XMETHOD(name, xbus, xpd, ...) \
+ (xpd)->xops->name(xbus, xpd, ## __VA_ARGS__ )
+
+struct xops {
+ xpd_t *(*card_new)(xbus_t *xbus, int unit, int subunit,
+ const xproto_table_t *proto_table, byte subtype, int subunits, bool to_phone);
+ int (*card_init)(xbus_t *xbus, xpd_t *xpd);
+ int (*card_remove)(xbus_t *xbus, xpd_t *xpd);
+ int (*card_tick)(xbus_t *xbus, xpd_t *xpd);
+ void (*card_pcm_fromspan)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack);
+ void (*card_pcm_tospan)(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack);
+ int (*card_zaptel_preregistration)(xpd_t *xpd, bool on);
+ int (*card_zaptel_postregistration)(xpd_t *xpd, bool on);
+ int (*card_hooksig)(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig);
+ int (*card_ioctl)(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg);
+ int (*card_open)(xpd_t *xpd, lineno_t pos);
+ int (*card_close)(xpd_t *xpd, lineno_t pos);
+ int (*card_register_reply)(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *reg);
+
+ int (*XPD_STATE)(xbus_t *xbus, xpd_t *xpd, bool on);
+};
+
+struct xproto_entry {
+ xproto_handler_t handler;
+ int datalen;
+ const char *name;
+ xproto_table_t *table;
+};
+
+struct xproto_table {
+ struct module *owner;
+ xproto_entry_t entries[256]; /* Indexed by opcode */
+ xops_t xops;
+ xpd_type_t type;
+ byte ports_per_subunit;
+ const char *name;
+ bool (*packet_is_valid)(xpacket_t *pack);
+ void (*packet_dump)(const char *msg, xpacket_t *pack);
+};
+
+#include "card_global.h"
+#include "card_fxs.h"
+#include "card_fxo.h"
+#include "card_bri.h"
+#include "card_pri.h"
+
+
+#define MEMBER(card,op) RPACKET_TYPE(card,op) RPACKET_NAME(card,op)
+
+struct xpacket {
+ struct xpacket_header head;
+ union {
+ MEMBER(GLOBAL, NULL_REPLY);
+ MEMBER(GLOBAL, PCM_WRITE);
+ MEMBER(GLOBAL, PCM_READ);
+ MEMBER(GLOBAL, SYNC_REPLY);
+ MEMBER(GLOBAL, ERROR_CODE);
+
+ MEMBER(FXS, SIG_CHANGED);
+ MEMBER(FXO, SIG_CHANGED);
+
+ byte data[0];
+ };
+ /* Last byte is chksum */
+} PACKED;
+
+void dump_packet(const char *msg, const xpacket_t *packet, bool debug);
+void dump_reg_cmd(const char msg[], bool writing, xbus_t *xbus, byte unit, xportno_t port, const reg_cmd_t *regcmd);
+int xframe_receive(xbus_t *xbus, xframe_t *xframe);
+void notify_bad_xpd(const char *funcname, xbus_t *xbus, const struct xpd_addr addr, const char *msg);
+int xproto_register(const xproto_table_t *proto_table);
+void xproto_unregister(const xproto_table_t *proto_table);
+const xproto_entry_t *xproto_global_entry(byte opcode);
+const char *xproto_name(xpd_type_t xpd_type);
+
+#endif /* __KERNEL__ */
+
+#endif /* XPROTO_H */
diff --git a/drivers/dahdi/xpp/zap_debug.c b/drivers/dahdi/xpp/zap_debug.c
new file mode 100644
index 0000000..e29e9dc
--- /dev/null
+++ b/drivers/dahdi/xpp/zap_debug.c
@@ -0,0 +1,91 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+# warning "This module is tested only with 2.6 kernels"
+#endif
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <zaptel.h>
+#include "zap_debug.h"
+#include "xdefs.h"
+
+static const char rcsid[] = "$Id$";
+
+#define P_(x) [ x ] = { .value = x, .name = #x, }
+static struct {
+ int value;
+ char *name;
+} poll_names[] = {
+ P_(POLLIN),
+ P_(POLLPRI),
+ P_(POLLOUT),
+ P_(POLLERR),
+ P_(POLLHUP),
+ P_(POLLNVAL),
+ P_(POLLRDNORM),
+ P_(POLLRDBAND),
+ P_(POLLWRNORM),
+ P_(POLLWRBAND),
+ P_(POLLMSG),
+ P_(POLLREMOVE)
+};
+#undef P_
+
+void dump_poll(int debug, const char *msg, int poll)
+{
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(poll_names); i++) {
+ if(poll & poll_names[i].value)
+ DBG(GENERAL, "%s: %s\n", msg, poll_names[i].name);
+ }
+}
+
+void alarm2str(int alarm, char *buf, int buflen)
+{
+ char *p = buf;
+ int left = buflen;
+ int i;
+ int n;
+
+ if(!alarm) {
+ snprintf(buf, buflen, "NONE");
+ return;
+ }
+ memset(buf, 0, buflen);
+ for(i = 0; i < 8; i++) {
+ if(left && (alarm & BIT(i))) {
+ n = snprintf(p, left, "%s,", alarmbit2str(i));
+ p += n;
+ left -= n;
+ }
+ }
+ if(p > buf) /* kill last comma */
+ *(p - 1) = '\0';
+}
+
+EXPORT_SYMBOL(dump_poll);
+EXPORT_SYMBOL(alarm2str);
diff --git a/drivers/dahdi/xpp/zap_debug.h b/drivers/dahdi/xpp/zap_debug.h
new file mode 100644
index 0000000..79aefdf
--- /dev/null
+++ b/drivers/dahdi/xpp/zap_debug.h
@@ -0,0 +1,201 @@
+#ifndef ZAP_DEBUG_H
+#define ZAP_DEBUG_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * 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 <zaptel.h> /* for zt_* defs */
+
+/* Debugging Macros */
+
+#define PRINTK(level, category, fmt, ...) \
+ printk(KERN_ ## level "%s%s-%s: " fmt, #level, category, THIS_MODULE->name, ## __VA_ARGS__)
+
+#define XBUS_PRINTK(level, category, xbus, fmt, ...) \
+ printk(KERN_ ## level "%s%s-%s: %s: " fmt, #level, \
+ category, THIS_MODULE->name, (xbus)->busname, ## __VA_ARGS__)
+
+#define XPD_PRINTK(level, category, xpd, fmt, ...) \
+ printk(KERN_ ## level "%s%s-%s: %s/%s: " fmt, #level, \
+ category, THIS_MODULE->name, (xpd)->xbus->busname, (xpd)->xpdname, ## __VA_ARGS__)
+
+#define LINE_PRINTK(level, category, xpd, pos, fmt, ...) \
+ printk(KERN_ ## level "%s%s-%s: %s/%s/%d: " fmt, #level, \
+ category, THIS_MODULE->name, (xpd)->xbus->busname, (xpd)->xpdname, (pos), ## __VA_ARGS__)
+
+#define PORT_PRINTK(level, category, xbus, unit, port, fmt, ...) \
+ printk(KERN_ ## level "%s%s-%s: %s UNIT=%d PORT=%d: " fmt, #level, \
+ category, THIS_MODULE->name, (xbus)->busname, (unit), (port), ## __VA_ARGS__)
+
+#define DBG(bits, fmt, ...) \
+ ((void)((debug & (DBG_ ## bits)) && PRINTK(DEBUG, "-" #bits, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)))
+#define INFO(fmt, ...) PRINTK(INFO, "", fmt, ## __VA_ARGS__)
+#define NOTICE(fmt, ...) PRINTK(NOTICE, "", fmt, ## __VA_ARGS__)
+#define WARNING(fmt, ...) PRINTK(WARNING, "", fmt, ## __VA_ARGS__)
+#define ERR(fmt, ...) PRINTK(ERR, "", fmt, ## __VA_ARGS__)
+
+#define XBUS_DBG(bits, xbus, fmt, ...) \
+ ((void)((debug & (DBG_ ## bits)) && XBUS_PRINTK(DEBUG, "-" #bits, xbus, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)))
+#define XBUS_INFO(xbus, fmt, ...) XBUS_PRINTK(INFO, "", xbus, fmt, ## __VA_ARGS__)
+#define XBUS_NOTICE(xbus, fmt, ...) XBUS_PRINTK(NOTICE, "", xbus, fmt, ## __VA_ARGS__)
+#define XBUS_ERR(xbus, fmt, ...) XBUS_PRINTK(ERR, "", xbus, fmt, ## __VA_ARGS__)
+
+#define XPD_DBG(bits, xpd, fmt, ...) \
+ ((void)((debug & (DBG_ ## bits)) && XPD_PRINTK(DEBUG, "-" #bits, xpd, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)))
+#define XPD_INFO(xpd, fmt, ...) XPD_PRINTK(INFO, "", xpd, fmt, ## __VA_ARGS__)
+#define XPD_NOTICE(xpd, fmt, ...) XPD_PRINTK(NOTICE, "", xpd, fmt, ## __VA_ARGS__)
+#define XPD_WARNING(xpd, fmt, ...) XPD_PRINTK(WARNING, "", xpd, fmt, ## __VA_ARGS__)
+#define XPD_ERR(xpd, fmt, ...) XPD_PRINTK(ERR, "", xpd, fmt, ## __VA_ARGS__)
+
+#define LINE_DBG(bits, xpd, pos, fmt, ...) \
+ ((void)((debug & (DBG_ ## bits)) && LINE_PRINTK(DEBUG, "-" #bits, xpd, pos, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)))
+#define LINE_NOTICE(xpd, pos, fmt, ...) LINE_PRINTK(NOTICE, "", xpd, pos, fmt, ## __VA_ARGS__)
+#define LINE_ERR(xpd, pos, fmt, ...) LINE_PRINTK(ERR, "", xpd, pos, fmt, ## __VA_ARGS__)
+
+#define PORT_DBG(bits, xbus, unit, port, fmt, ...) \
+ ((void)((debug & (DBG_ ## bits)) && PORT_PRINTK(DEBUG, "-" #bits, \
+ xbus, unit, port, "%s: " fmt, __FUNCTION__, ## __VA_ARGS__)))
+#define PORT_NOTICE(xbus, unit, port, fmt, ...) PORT_PRINTK(NOTICE, "", xbus, unit, port, fmt, ## __VA_ARGS__)
+#define PORT_ERR(xbus, unit, port, fmt, ...) PORT_PRINTK(ERR, "", xbus, unit, port, fmt, ## __VA_ARGS__)
+
+/*
+ * Bits for debug
+ */
+#define DBG_GENERAL BIT(0)
+#define DBG_PCM BIT(1)
+#define DBG_LEDS BIT(2)
+#define DBG_SYNC BIT(3)
+#define DBG_SIGNAL BIT(4)
+#define DBG_PROC BIT(5)
+#define DBG_REGS BIT(6)
+#define DBG_DEVICES BIT(7) /* instantiation/destruction etc. */
+#define DBG_COMMANDS BIT(8) /* All commands */
+#define DBG_ANY (~0)
+
+void dump_poll(int debug, const char *msg, int poll);
+
+static inline char *rxsig2str(zt_rxsig_t sig)
+{
+ switch(sig) {
+ case ZT_RXSIG_ONHOOK: return "ONHOOK";
+ case ZT_RXSIG_OFFHOOK: return "OFFHOOK";
+ case ZT_RXSIG_START: return "START";
+ case ZT_RXSIG_RING: return "RING";
+ case ZT_RXSIG_INITIAL: return "INITIAL";
+ }
+ return "Unknown rxsig";
+}
+
+static inline char *txsig2str(zt_txsig_t sig)
+{
+ switch(sig) {
+ case ZT_TXSIG_ONHOOK: return "TXSIG_ONHOOK";
+ case ZT_TXSIG_OFFHOOK: return "TXSIG_OFFHOOK";
+ case ZT_TXSIG_START: return "TXSIG_START";
+ case ZT_TXSIG_KEWL: return "TXSIG_KEWL"; /* Drop battery if possible */
+ }
+ return "Unknown txsig";
+}
+
+static inline char *event2str(int event)
+{
+ switch(event) {
+ case ZT_EVENT_NONE: return "NONE";
+ case ZT_EVENT_ONHOOK: return "ONHOOK";
+ case ZT_EVENT_RINGOFFHOOK: return "RINGOFFHOOK";
+ case ZT_EVENT_WINKFLASH: return "WINKFLASH";
+ case ZT_EVENT_ALARM: return "ALARM";
+ case ZT_EVENT_NOALARM: return "NOALARM";
+ case ZT_EVENT_ABORT: return "ABORT";
+ case ZT_EVENT_OVERRUN: return "OVERRUN";
+ case ZT_EVENT_BADFCS: return "BADFCS";
+ case ZT_EVENT_DIALCOMPLETE: return "DIALCOMPLETE";
+ case ZT_EVENT_RINGERON: return "RINGERON";
+ case ZT_EVENT_RINGEROFF: return "RINGEROFF";
+ case ZT_EVENT_HOOKCOMPLETE: return "HOOKCOMPLETE";
+ case ZT_EVENT_BITSCHANGED: return "BITSCHANGED";
+ case ZT_EVENT_PULSE_START: return "PULSE_START";
+ case ZT_EVENT_TIMER_EXPIRED: return "TIMER_EXPIRED";
+ case ZT_EVENT_TIMER_PING: return "TIMER_PING";
+ case ZT_EVENT_POLARITY: return "POLARITY";
+ }
+ return "Unknown event";
+}
+
+static inline char *hookstate2str(int hookstate)
+{
+ switch(hookstate) {
+ case ZT_ONHOOK: return "ZT_ONHOOK";
+ case ZT_START: return "ZT_START";
+ case ZT_OFFHOOK: return "ZT_OFFHOOK";
+ case ZT_WINK: return "ZT_WINK";
+ case ZT_FLASH: return "ZT_FLASH";
+ case ZT_RING: return "ZT_RING";
+ case ZT_RINGOFF: return "ZT_RINGOFF";
+ }
+ return "Unknown hookstate";
+}
+
+/* From zaptel.c */
+static inline char *sig2str(int sig)
+{
+ switch (sig) {
+ case ZT_SIG_FXSLS: return "FXSLS";
+ case ZT_SIG_FXSKS: return "FXSKS";
+ case ZT_SIG_FXSGS: return "FXSGS";
+ case ZT_SIG_FXOLS: return "FXOLS";
+ case ZT_SIG_FXOKS: return "FXOKS";
+ case ZT_SIG_FXOGS: return "FXOGS";
+ case ZT_SIG_EM: return "E&M";
+ case ZT_SIG_EM_E1: return "E&M-E1";
+ case ZT_SIG_CLEAR: return "Clear";
+ case ZT_SIG_HDLCRAW: return "HDLCRAW";
+ case ZT_SIG_HDLCFCS: return "HDLCFCS";
+ case ZT_SIG_HDLCNET: return "HDLCNET";
+ case ZT_SIG_SLAVE: return "Slave";
+ case ZT_SIG_CAS: return "CAS";
+ case ZT_SIG_DACS: return "DACS";
+ case ZT_SIG_DACS_RBS: return "DACS+RBS";
+ case ZT_SIG_SF: return "SF (ToneOnly)";
+ case ZT_SIG_NONE:
+ break;
+ }
+ return "Unconfigured";
+}
+
+static inline char *alarmbit2str(int alarmbit)
+{
+ /* from zaptel.h */
+ switch(1 << alarmbit) {
+ case ZT_ALARM_NONE: return "NONE";
+ case ZT_ALARM_RECOVER: return "RECOVER";
+ case ZT_ALARM_LOOPBACK: return "LOOPBACK";
+ case ZT_ALARM_YELLOW: return "YELLOW";
+ case ZT_ALARM_RED: return "RED";
+ case ZT_ALARM_BLUE: return "BLUE";
+ case ZT_ALARM_NOTOPEN: return "NOTOPEN";
+ }
+ return "UNKNOWN";
+}
+
+void alarm2str(int alarm, char *buf, int buflen);
+
+#endif /* ZAP_DEBUG_H */
diff --git a/drivers/dahdi/zaptel-base.c b/drivers/dahdi/zaptel-base.c
new file mode 100644
index 0000000..2c6a22e
--- /dev/null
+++ b/drivers/dahdi/zaptel-base.c
@@ -0,0 +1,7801 @@
+/*
+ * Zapata Telephony Interface Driver
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim@lambdatel.com>.
+ *
+ * Special thanks to Steve Underwood <steve@coppice.org>
+ * for substantial contributions to signal processing functions
+ * in zaptel and the zapata library.
+ *
+ * Yury Bokhoncovich <byg@cf1.ru>
+ * Adaptation for 2.4.20+ kernels (HDLC API was changed)
+ * The work has been performed as a part of our move
+ * from Cisco 3620 to IBM x305 here in F1 Group
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001 -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 "zconfig.h"
+#include "../version.h"
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/ctype.h>
+#include <linux/kmod.h>
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif /* CONFIG_DEVFS_FS */
+#ifdef CONFIG_ZAPATA_NET
+#include <linux/netdevice.h>
+#endif /* CONFIG_ZAPATA_NET */
+#include <linux/ppp_defs.h>
+#ifdef CONFIG_ZAPATA_PPP
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_ppp.h>
+#endif
+#include <asm/atomic.h>
+
+#ifndef CONFIG_OLD_HDLC_API
+#define NEW_HDLC_INTERFACE
+#endif
+
+#define __ECHO_STATE_MUTE (1 << 8)
+#define ECHO_STATE_IDLE (0)
+#define ECHO_STATE_PRETRAINING (1 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_STARTTRAINING (2 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_AWAITINGECHO (3 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_TRAINING (4 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_ACTIVE (5)
+
+/* #define BUF_MUNGE */
+
+/* Grab fasthdlc with tables */
+#define FAST_HDLC_NEED_TABLES
+#include "fasthdlc.h"
+
+#include "zaptel.h"
+
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+/* Get helper arithmetic */
+#include "arith.h"
+#if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP)
+#include <asm/i387.h>
+#endif
+
+#define hdlc_to_ztchan(h) (((struct zt_hdlc *)(h))->chan)
+#define dev_to_ztchan(h) (((struct zt_hdlc *)(dev_to_hdlc(h)->priv))->chan)
+#ifdef LINUX26
+#define ztchan_to_dev(h) ((h)->hdlcnetdev->netdev)
+#else
+#define ztchan_to_dev(h) (&((h)->hdlcnetdev->netdev.netdev))
+#endif
+
+/* macro-oni for determining a unit (channel) number */
+#define UNIT(file) MINOR(file->f_dentry->d_inode->i_rdev)
+
+/* names of tx level settings */
+static char *zt_txlevelnames[] = {
+"0 db (CSU)/0-133 feet (DSX-1)",
+"133-266 feet (DSX-1)",
+"266-399 feet (DSX-1)",
+"399-533 feet (DSX-1)",
+"533-655 feet (DSX-1)",
+"-7.5db (CSU)",
+"-15db (CSU)",
+"-22.5db (CSU)"
+} ;
+
+EXPORT_SYMBOL(zt_transcode_fops);
+EXPORT_SYMBOL(zt_init_tone_state);
+EXPORT_SYMBOL(zt_mf_tone);
+EXPORT_SYMBOL(zt_register);
+EXPORT_SYMBOL(zt_unregister);
+EXPORT_SYMBOL(__zt_mulaw);
+EXPORT_SYMBOL(__zt_alaw);
+#ifdef CONFIG_CALC_XLAW
+EXPORT_SYMBOL(__zt_lineartoulaw);
+EXPORT_SYMBOL(__zt_lineartoalaw);
+#else
+EXPORT_SYMBOL(__zt_lin2mu);
+EXPORT_SYMBOL(__zt_lin2a);
+#endif
+EXPORT_SYMBOL(zt_lboname);
+EXPORT_SYMBOL(zt_transmit);
+EXPORT_SYMBOL(zt_receive);
+EXPORT_SYMBOL(zt_rbsbits);
+EXPORT_SYMBOL(zt_qevent_nolock);
+EXPORT_SYMBOL(zt_qevent_lock);
+EXPORT_SYMBOL(zt_hooksig);
+EXPORT_SYMBOL(zt_alarm_notify);
+EXPORT_SYMBOL(zt_set_dynamic_ioctl);
+EXPORT_SYMBOL(zt_ec_chunk);
+EXPORT_SYMBOL(zt_ec_span);
+EXPORT_SYMBOL(zt_hdlc_abort);
+EXPORT_SYMBOL(zt_hdlc_finish);
+EXPORT_SYMBOL(zt_hdlc_getbuf);
+EXPORT_SYMBOL(zt_hdlc_putbuf);
+EXPORT_SYMBOL(zt_alarm_channel);
+EXPORT_SYMBOL(zt_register_chardev);
+EXPORT_SYMBOL(zt_unregister_chardev);
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_entries[ZT_MAX_SPANS];
+#endif
+
+/* Here are a couple important little additions for devfs */
+#ifdef CONFIG_DEVFS_FS
+static devfs_handle_t zaptel_devfs_dir;
+static devfs_handle_t channel;
+static devfs_handle_t pseudo;
+static devfs_handle_t ctl;
+static devfs_handle_t timer;
+#endif
+
+/* udev necessary data structures. Yeah! */
+#ifdef CONFIG_ZAP_UDEV
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+#define CLASS_DEV_CREATE(class, devt, device, name) \
+ class_device_create(class, NULL, devt, device, name)
+#else
+#define CLASS_DEV_CREATE(class, devt, device, name) \
+ class_device_create(class, devt, device, name)
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+static struct class *zap_class = NULL;
+#else
+static struct class_simple *zap_class = NULL;
+#define class_create class_simple_create
+#define class_destroy class_simple_destroy
+#define class_device_create class_simple_device_add
+#define class_device_destroy(a, b) class_simple_device_remove(b)
+#endif
+
+#endif /* CONFIG_ZAP_UDEV */
+
+
+/* There is a table like this in the PPP driver, too */
+
+static int deftaps = 64;
+
+#if !defined(LINUX26)
+static
+__u16 fcstab[256] =
+{
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+#endif
+
+static int debug;
+
+/* states for transmit signalling */
+typedef enum {ZT_TXSTATE_ONHOOK,ZT_TXSTATE_OFFHOOK,ZT_TXSTATE_START,
+ ZT_TXSTATE_PREWINK,ZT_TXSTATE_WINK,ZT_TXSTATE_PREFLASH,
+ ZT_TXSTATE_FLASH,ZT_TXSTATE_DEBOUNCE,ZT_TXSTATE_AFTERSTART,
+ ZT_TXSTATE_RINGON,ZT_TXSTATE_RINGOFF,ZT_TXSTATE_KEWL,
+ ZT_TXSTATE_AFTERKEWL,ZT_TXSTATE_PULSEBREAK,ZT_TXSTATE_PULSEMAKE,
+ ZT_TXSTATE_PULSEAFTER
+ } ZT_TXSTATE_t;
+
+typedef short sumtype[ZT_MAX_CHUNKSIZE];
+
+static sumtype sums[(ZT_MAX_CONF + 1) * 3];
+
+/* Translate conference aliases into actual conferences
+ and vice-versa */
+static short confalias[ZT_MAX_CONF + 1];
+static short confrev[ZT_MAX_CONF + 1];
+
+static sumtype *conf_sums_next;
+static sumtype *conf_sums;
+static sumtype *conf_sums_prev;
+
+static struct zt_span *master;
+static struct file_operations zt_fops;
+struct file_operations *zt_transcode_fops = NULL;
+
+static struct
+{
+ int src; /* source conf number */
+ int dst; /* dst conf number */
+} conf_links[ZT_MAX_CONF + 1];
+
+
+/* There are three sets of conference sum accumulators. One for the current
+sample chunk (conf_sums), one for the next sample chunk (conf_sums_next), and
+one for the previous sample chunk (conf_sums_prev). The following routine
+(rotate_sums) "rotates" the pointers to these accululator arrays as part
+of the events of sample chink processing as follows:
+
+The following sequence is designed to be looked at from the reference point
+of the receive routine of the master span.
+
+1. All (real span) receive chunks are processed (with putbuf). The last one
+to be processed is the master span. The data received is loaded into the
+accumulators for the next chunk (conf_sums_next), to be in alignment with
+current data after rotate_sums() is called (which immediately follows).
+Keep in mind that putbuf is *also* a transmit routine for the pseudo parts
+of channels that are in the REALANDPSEUDO conference mode. These channels
+are processed from data in the current sample chunk (conf_sums), being
+that this is a "transmit" function (for the pseudo part).
+
+2. rotate_sums() is called.
+
+3. All pseudo channel receive chunks are processed. This data is loaded into
+the current sample chunk accumulators (conf_sums).
+
+4. All conference links are processed (being that all receive data for this
+chunk has already been processed by now).
+
+5. All pseudo channel transmit chunks are processed. This data is loaded from
+the current sample chunk accumulators (conf_sums).
+
+6. All (real span) transmit chunks are processed (with getbuf). This data is
+loaded from the current sample chunk accumulators (conf_sums). Keep in mind
+that getbuf is *also* a receive routine for the pseudo part of channels that
+are in the REALANDPSEUDO conference mode. These samples are loaded into
+the next sample chunk accumulators (conf_sums_next) to be processed as part
+of the next sample chunk's data (next time around the world).
+
+*/
+
+#define DIGIT_MODE_DTMF 0
+#define DIGIT_MODE_MFR1 1
+#define DIGIT_MODE_PULSE 2
+#define DIGIT_MODE_MFR2_FWD 3
+#define DIGIT_MODE_MFR2_REV 4
+
+#include "digits.h"
+
+static struct zt_dialparams global_dialparams = {
+ .dtmf_tonelen = DEFAULT_DTMF_LENGTH,
+ .mfv1_tonelen = DEFAULT_MFR1_LENGTH,
+ .mfr2_tonelen = DEFAULT_MFR2_LENGTH,
+};
+
+static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit);
+
+#if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP)
+/* XXX kernel_fpu_begin() is NOT exported properly (in 2.4), so we have to make
+ a local version. Somebody fix this! XXX */
+
+#ifndef LINUX26
+static inline void __save_init_fpu( struct task_struct *tsk )
+{
+ if ( cpu_has_fxsr ) {
+ asm volatile( "fxsave %0 ; fnclex"
+ : "=m" (tsk->thread.i387.fxsave) );
+ } else {
+ asm volatile( "fnsave %0 ; fwait"
+ : "=m" (tsk->thread.i387.fsave) );
+ }
+ tsk->flags &= ~PF_USEDFPU;
+}
+
+static inline void zt_kernel_fpu_begin(void)
+{
+ struct task_struct *tsk = current;
+ if (tsk->flags & PF_USEDFPU) {
+ __save_init_fpu(tsk);
+ return;
+ }
+ clts();
+}
+#else
+#define zt_kernel_fpu_begin kernel_fpu_begin
+#endif /* LINUX26 */
+#endif
+
+static struct zt_timer {
+ int ms; /* Countdown */
+ int pos; /* Position */
+ int ping; /* Whether we've been ping'd */
+ int tripped; /* Whether we're tripped */
+ struct zt_timer *next; /* Linked list */
+ wait_queue_head_t sel;
+} *zaptimers = NULL;
+
+#ifdef DEFINE_SPINLOCK
+static DEFINE_SPINLOCK(zaptimerlock);
+static DEFINE_SPINLOCK(bigzaplock);
+#else
+static spinlock_t zaptimerlock = SPIN_LOCK_UNLOCKED;
+static spinlock_t bigzaplock = SPIN_LOCK_UNLOCKED;
+#endif
+
+struct zt_zone {
+ atomic_t refcount;
+ char name[40]; /* Informational, only */
+ int ringcadence[ZT_MAX_CADENCE];
+ struct zt_tone *tones[ZT_TONE_MAX];
+ /* Each of these is a circular list
+ of zt_tones to generate what we
+ want. Use NULL if the tone is
+ unavailable */
+ struct zt_tone dtmf[16]; /* DTMF tones for this zone, with desired length */
+ struct zt_tone dtmf_continuous[16]; /* DTMF tones for this zone, continuous play */
+ struct zt_tone mfr1[15]; /* MFR1 tones for this zone, with desired length */
+ struct zt_tone mfr2_fwd[15]; /* MFR2 FWD tones for this zone, with desired length */
+ struct zt_tone mfr2_rev[15]; /* MFR2 REV tones for this zone, with desired length */
+ struct zt_tone mfr2_fwd_continuous[16]; /* MFR2 FWD tones for this zone, continuous play */
+ struct zt_tone mfr2_rev_continuous[16]; /* MFR2 REV tones for this zone, continuous play */
+};
+
+static struct zt_span *spans[ZT_MAX_SPANS];
+static struct zt_chan *chans[ZT_MAX_CHANNELS];
+
+static int maxspans = 0;
+static int maxchans = 0;
+static int maxconfs = 0;
+static int maxlinks = 0;
+
+static int default_zone = -1;
+
+short __zt_mulaw[256];
+short __zt_alaw[256];
+
+#ifndef CONFIG_CALC_XLAW
+u_char __zt_lin2mu[16384];
+
+u_char __zt_lin2a[16384];
+#endif
+
+static u_char defgain[256];
+
+#ifdef DEFINE_RWLOCK
+static DEFINE_RWLOCK(zone_lock);
+static DEFINE_RWLOCK(chan_lock);
+#else
+static rwlock_t zone_lock = RW_LOCK_UNLOCKED;
+static rwlock_t chan_lock = RW_LOCK_UNLOCKED;
+#endif
+
+static struct zt_zone *tone_zones[ZT_TONE_ZONE_MAX];
+
+#define NUM_SIGS 10
+
+
+/* Echo cancellation */
+#if defined(ECHO_CAN_HPEC)
+#include "hpec/hpec_zaptel.h"
+#elif defined(ECHO_CAN_STEVE)
+#include "sec.h"
+#elif defined(ECHO_CAN_STEVE2)
+#include "sec-2.h"
+#elif defined(ECHO_CAN_KB1)
+#include "kb1ec.h"
+#elif defined(ECHO_CAN_MG2)
+#include "mg2ec.h"
+#elif defined(ECHO_CAN_JP1)
+#include "jpah.h"
+#endif
+
+static inline void rotate_sums(void)
+{
+ /* Rotate where we sum and so forth */
+ static int pos = 0;
+ conf_sums_prev = sums + (ZT_MAX_CONF + 1) * pos;
+ conf_sums = sums + (ZT_MAX_CONF + 1) * ((pos + 1) % 3);
+ conf_sums_next = sums + (ZT_MAX_CONF + 1) * ((pos + 2) % 3);
+ pos = (pos + 1) % 3;
+ memset(conf_sums_next, 0, maxconfs * sizeof(sumtype));
+}
+
+ /* return quiescent (idle) signalling states, for the various signalling types */
+static int zt_q_sig(struct zt_chan *chan)
+{
+int x;
+
+static unsigned int in_sig[NUM_SIGS][2] = {
+ { ZT_SIG_NONE, 0},
+ { ZT_SIG_EM, 0 | (ZT_ABIT << 8)},
+ { ZT_SIG_FXSLS,ZT_BBIT | (ZT_BBIT << 8)},
+ { ZT_SIG_FXSGS,ZT_ABIT | ZT_BBIT | ((ZT_ABIT | ZT_BBIT) << 8)},
+ { ZT_SIG_FXSKS,ZT_BBIT | ZT_BBIT | ((ZT_ABIT | ZT_BBIT) << 8)},
+ { ZT_SIG_FXOLS,0 | (ZT_ABIT << 8)},
+ { ZT_SIG_FXOGS,ZT_BBIT | ((ZT_ABIT | ZT_BBIT) << 8)},
+ { ZT_SIG_FXOKS,0 | (ZT_ABIT << 8)},
+ { ZT_SIG_SF, 0},
+ { ZT_SIG_EM_E1, ZT_DBIT | ((ZT_ABIT | ZT_DBIT) << 8) },
+ } ;
+
+ /* must have span to begin with */
+ if (!chan->span) return(-1);
+ /* if RBS does not apply, return error */
+ if (!(chan->span->flags & ZT_FLAG_RBS) ||
+ !chan->span->rbsbits) return(-1);
+ if (chan->sig == ZT_SIG_CAS)
+ return chan->idlebits;
+ for (x=0;x<NUM_SIGS;x++) {
+ if (in_sig[x][0] == chan->sig) return(in_sig[x][1]);
+ } return(-1); /* not found -- error */
+}
+
+#ifdef CONFIG_PROC_FS
+static char *sigstr(int sig)
+{
+ switch (sig) {
+ case ZT_SIG_FXSLS:
+ return "FXSLS";
+ case ZT_SIG_FXSKS:
+ return "FXSKS";
+ case ZT_SIG_FXSGS:
+ return "FXSGS";
+ case ZT_SIG_FXOLS:
+ return "FXOLS";
+ case ZT_SIG_FXOKS:
+ return "FXOKS";
+ case ZT_SIG_FXOGS:
+ return "FXOGS";
+ case ZT_SIG_EM:
+ return "E&M";
+ case ZT_SIG_EM_E1:
+ return "E&M-E1";
+ case ZT_SIG_CLEAR:
+ return "Clear";
+ case ZT_SIG_HDLCRAW:
+ return "HDLCRAW";
+ case ZT_SIG_HDLCFCS:
+ return "HDLCFCS";
+ case ZT_SIG_HDLCNET:
+ return "HDLCNET";
+ case ZT_SIG_HARDHDLC:
+ return "Hardware-assisted HDLC";
+ case ZT_SIG_MTP2:
+ return "MTP2";
+ case ZT_SIG_SLAVE:
+ return "Slave";
+ case ZT_SIG_CAS:
+ return "CAS";
+ case ZT_SIG_DACS:
+ return "DACS";
+ case ZT_SIG_DACS_RBS:
+ return "DACS+RBS";
+ case ZT_SIG_SF:
+ return "SF (ToneOnly)";
+ case ZT_SIG_NONE:
+ default:
+ return "Unconfigured";
+ }
+
+}
+
+static inline int fill_alarm_string(char *buf, int count, int alarms)
+{
+ int len = 0;
+
+ if (alarms > 0) {
+ if (alarms & ZT_ALARM_BLUE)
+ len += snprintf(buf + len, count - len, "BLUE ");
+ if (alarms & ZT_ALARM_YELLOW)
+ len += snprintf(buf + len, count - len, "YELLOW ");
+ if (alarms & ZT_ALARM_RED)
+ len += snprintf(buf + len, count - len, "RED ");
+ if (alarms & ZT_ALARM_LOOPBACK)
+ len += snprintf(buf + len, count - len, "LOOP ");
+ if (alarms & ZT_ALARM_RECOVER)
+ len += snprintf(buf + len, count - len, "RECOVERING ");
+ if (alarms & ZT_ALARM_NOTOPEN)
+ len += snprintf(buf + len, count - len, "NOTOPEN ");
+ }
+ if(len > 0) {
+ len--;
+ buf[len] = '\0'; /* strip last space */
+ }
+ return len;
+}
+
+static int zaptel_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int x, len = 0;
+ long span;
+
+ /* In Linux 2.6, this MUST NOT EXECEED 1024 bytes in one read! */
+
+ span = (long)data;
+
+ if (!span)
+ return 0;
+
+ if (spans[span]->name)
+ len += sprintf(page + len, "Span %ld: %s ", span, spans[span]->name);
+ if (spans[span]->desc)
+ len += sprintf(page + len, "\"%s\"", spans[span]->desc);
+ else
+ len += sprintf(page + len, "\"\"");
+
+ if(spans[span] == master)
+ len += sprintf(page + len, " (MASTER)");
+
+ if (spans[span]->lineconfig) {
+ /* framing first */
+ if (spans[span]->lineconfig & ZT_CONFIG_B8ZS)
+ len += sprintf(page + len, " B8ZS/");
+ else if (spans[span]->lineconfig & ZT_CONFIG_AMI)
+ len += sprintf(page + len, " AMI/");
+ else if (spans[span]->lineconfig & ZT_CONFIG_HDB3)
+ len += sprintf(page + len, " HDB3/");
+ /* then coding */
+ if (spans[span]->lineconfig & ZT_CONFIG_ESF)
+ len += sprintf(page + len, "ESF");
+ else if (spans[span]->lineconfig & ZT_CONFIG_D4)
+ len += sprintf(page + len, "D4");
+ else if (spans[span]->lineconfig & ZT_CONFIG_CCS)
+ len += sprintf(page + len, "CCS");
+ /* E1's can enable CRC checking */
+ if (spans[span]->lineconfig & ZT_CONFIG_CRC4)
+ len += sprintf(page + len, "/CRC4");
+ }
+
+ len += sprintf(page + len, " ");
+
+ /* list alarms */
+ len += fill_alarm_string(page + len, count - len, spans[span]->alarms);
+ if (spans[span]->syncsrc && (spans[span]->syncsrc == spans[span]->spanno))
+ len += sprintf(page + len, "ClockSource ");
+ len += sprintf(page + len, "\n");
+ if (spans[span]->bpvcount)
+ len += sprintf(page + len, "\tBPV count: %d\n", spans[span]->bpvcount);
+ if (spans[span]->crc4count)
+ len += sprintf(page + len, "\tCRC4 error count: %d\n", spans[span]->crc4count);
+ if (spans[span]->ebitcount)
+ len += sprintf(page + len, "\tE-bit error count: %d\n", spans[span]->ebitcount);
+ if (spans[span]->fascount)
+ len += sprintf(page + len, "\tFAS error count: %d\n", spans[span]->fascount);
+ if (spans[span]->irqmisses)
+ len += sprintf(page + len, "\tIRQ misses: %d\n", spans[span]->irqmisses);
+ if (spans[span]->timingslips)
+ len += sprintf(page + len, "\tTiming slips: %d\n", spans[span]->timingslips);
+ len += sprintf(page + len, "\n");
+
+
+ for (x=1;x<ZT_MAX_CHANNELS;x++) {
+ if (chans[x]) {
+ if (chans[x]->span && (chans[x]->span->spanno == span)) {
+ if (chans[x]->name)
+ len += sprintf(page + len, "\t%4d %s ", x, chans[x]->name);
+ if (chans[x]->sig) {
+ if (chans[x]->sig == ZT_SIG_SLAVE)
+ len += sprintf(page + len, "%s ", sigstr(chans[x]->master->sig));
+ else {
+ len += sprintf(page + len, "%s ", sigstr(chans[x]->sig));
+ if (chans[x]->nextslave && chans[x]->master->channo == x)
+ len += sprintf(page + len, "Master ");
+ }
+ }
+ if ((chans[x]->flags & ZT_FLAG_OPEN)) {
+ len += sprintf(page + len, "(In use) ");
+ }
+#ifdef OPTIMIZE_CHANMUTE
+ if ((chans[x]->chanmute)) {
+ len += sprintf(page + len, "(no pcm) ");
+ }
+#endif
+ len += fill_alarm_string(page + len, count - len, chans[x]->chan_alarms);
+ len += sprintf(page + len, "\n");
+ }
+ if (len <= off) { /* If everything printed so far is before beginning of request */
+ off -= len;
+ len = 0;
+ }
+ if (len > off+count) /* stop if we've already generated enough */
+ break;
+ }
+ }
+ if (len <= off) { /* If everything printed so far is before beginning of request */
+ off -= len;
+ len = 0;
+ }
+ *start = page + off;
+ len -= off; /* un-count any remaining offset */
+ if (len > count) len = count; /* don't return bytes not asked for */
+ return len;
+}
+#endif
+
+static int zt_first_empty_alias(void)
+{
+ /* Find the first conference which has no alias pointing to it */
+ int x;
+ for (x=1;x<ZT_MAX_CONF;x++) {
+ if (!confrev[x])
+ return x;
+ }
+ return -1;
+}
+
+static void recalc_maxconfs(void)
+{
+ int x;
+ for (x=ZT_MAX_CONF-1;x>0;x--) {
+ if (confrev[x]) {
+ maxconfs = x+1;
+ return;
+ }
+ }
+ maxconfs = 0;
+}
+
+static void recalc_maxlinks(void)
+{
+ int x;
+ for (x=ZT_MAX_CONF-1;x>0;x--) {
+ if (conf_links[x].src || conf_links[x].dst) {
+ maxlinks = x+1;
+ return;
+ }
+ }
+ maxlinks = 0;
+}
+
+static int zt_first_empty_conference(void)
+{
+ /* Find the first conference which has no alias */
+ int x;
+ for (x=ZT_MAX_CONF-1;x>0;x--) {
+ if (!confalias[x])
+ return x;
+ }
+ return -1;
+}
+
+static int zt_get_conf_alias(int x)
+{
+ int a;
+ if (confalias[x]) {
+ return confalias[x];
+ }
+
+ /* Allocate an alias */
+ a = zt_first_empty_alias();
+ confalias[x] = a;
+ confrev[a] = x;
+
+ /* Highest conference may have changed */
+ recalc_maxconfs();
+ return a;
+}
+
+static void zt_check_conf(int x)
+{
+ int y;
+
+ /* return if no valid conf number */
+ if (x <= 0) return;
+ /* Return if there is no alias */
+ if (!confalias[x])
+ return;
+ for (y=0;y<maxchans;y++) {
+ if (chans[y] && (chans[y]->confna == x) &&
+ ((chans[y]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONF ||
+ (chans[y]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFANN ||
+ (chans[y]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFMON ||
+ (chans[y]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFANNMON ||
+ (chans[y]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_REALANDPSEUDO))
+ return;
+ }
+ /* If we get here, nobody is in the conference anymore. Clear it out
+ both forward and reverse */
+ confrev[confalias[x]] = 0;
+ confalias[x] = 0;
+
+ /* Highest conference may have changed */
+ recalc_maxconfs();
+}
+
+/* enqueue an event on a channel */
+static void __qevent(struct zt_chan *chan, int event)
+{
+
+ /* if full, ignore */
+ if ((chan->eventoutidx == 0) && (chan->eventinidx == (ZT_MAX_EVENTSIZE - 1)))
+ return;
+ /* if full, ignore */
+ if (chan->eventinidx == (chan->eventoutidx - 1)) return;
+ /* save the event */
+ chan->eventbuf[chan->eventinidx++] = event;
+ /* wrap the index, if necessary */
+ if (chan->eventinidx >= ZT_MAX_EVENTSIZE) chan->eventinidx = 0;
+ /* wake em all up */
+ if (chan->iomask & ZT_IOMUX_SIGEVENT) wake_up_interruptible(&chan->eventbufq);
+ wake_up_interruptible(&chan->readbufq);
+ wake_up_interruptible(&chan->writebufq);
+ wake_up_interruptible(&chan->sel);
+ return;
+}
+
+void zt_qevent_nolock(struct zt_chan *chan, int event)
+{
+ __qevent(chan, event);
+}
+
+void zt_qevent_lock(struct zt_chan *chan, int event)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&chan->lock, flags);
+ __qevent(chan, event);
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/* sleep in user space until woken up. Equivilant of tsleep() in BSD */
+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 void calc_fcs(struct zt_chan *ss, int inwritebuf)
+{
+ int x;
+ unsigned int fcs=PPP_INITFCS;
+ unsigned char *data = ss->writebuf[inwritebuf];
+ int len = ss->writen[inwritebuf];
+ /* Not enough space to do FCS calculation */
+ if (len < 2)
+ return;
+ for (x=0;x<len-2;x++)
+ fcs = PPP_FCS(fcs, data[x]);
+ fcs ^= 0xffff;
+ /* Send out the FCS */
+ data[len-2] = (fcs & 0xff);
+ data[len-1] = (fcs >> 8) & 0xff;
+}
+
+static int zt_reallocbufs(struct zt_chan *ss, int j, int numbufs)
+{
+ unsigned char *newbuf, *oldbuf;
+ unsigned long flags;
+ int x;
+ /* Check numbufs */
+ if (numbufs < 2)
+ numbufs = 2;
+ if (numbufs > ZT_MAX_NUM_BUFS)
+ numbufs = ZT_MAX_NUM_BUFS;
+ /* We need to allocate our buffers now */
+ if (j) {
+ newbuf = kmalloc(j * 2 * numbufs, GFP_KERNEL);
+ if (!newbuf)
+ return (-ENOMEM);
+ memset(newbuf, 0, j * 2 * numbufs);
+ } else
+ newbuf = NULL;
+ /* Now that we've allocated our new buffer, we can safely
+ move things around... */
+ spin_lock_irqsave(&ss->lock, flags);
+ ss->blocksize = j; /* set the blocksize */
+ oldbuf = ss->readbuf[0]; /* Keep track of the old buffer */
+ ss->readbuf[0] = NULL;
+ if (newbuf) {
+ for (x=0;x<numbufs;x++) {
+ ss->readbuf[x] = newbuf + x * j;
+ ss->writebuf[x] = newbuf + (numbufs + x) * j;
+ }
+ } else {
+ for (x=0;x<numbufs;x++) {
+ ss->readbuf[x] = NULL;
+ ss->writebuf[x] = NULL;
+ }
+ }
+ /* Mark all buffers as empty */
+ for (x=0;x<numbufs;x++)
+ ss->writen[x] =
+ ss->writeidx[x]=
+ ss->readn[x]=
+ ss->readidx[x] = 0;
+
+ /* Keep track of where our data goes (if it goes
+ anywhere at all) */
+ if (newbuf) {
+ ss->inreadbuf = 0;
+ ss->inwritebuf = 0;
+ } else {
+ ss->inreadbuf = -1;
+ ss->inwritebuf = -1;
+ }
+ ss->outreadbuf = -1;
+ ss->outwritebuf = -1;
+ ss->numbufs = numbufs;
+ if (ss->txbufpolicy == ZT_POLICY_WHEN_FULL)
+ ss->txdisable = 1;
+ else
+ ss->txdisable = 0;
+
+ if (ss->rxbufpolicy == ZT_POLICY_WHEN_FULL)
+ ss->rxdisable = 1;
+ else
+ ss->rxdisable = 0;
+
+ spin_unlock_irqrestore(&ss->lock, flags);
+ if (oldbuf)
+ kfree(oldbuf);
+ return 0;
+}
+
+static int zt_hangup(struct zt_chan *chan);
+static void zt_set_law(struct zt_chan *chan, int law);
+
+/* Pull a ZT_CHUNKSIZE piece off the queue. Returns
+ 0 on success or -1 on failure. If failed, provides
+ silence */
+static int __buf_pull(struct confq *q, u_char *data, struct zt_chan *c, char *label)
+{
+ int oldoutbuf = q->outbuf;
+ /* Ain't nuffin to read */
+ if (q->outbuf < 0) {
+ if (data)
+ memset(data, ZT_LIN2X(0,c), ZT_CHUNKSIZE);
+ return -1;
+ }
+ if (data)
+ memcpy(data, q->buf[q->outbuf], ZT_CHUNKSIZE);
+ q->outbuf = (q->outbuf + 1) % ZT_CB_SIZE;
+
+ /* Won't be nuffin next time */
+ if (q->outbuf == q->inbuf) {
+ q->outbuf = -1;
+ }
+
+ /* If they thought there was no space then
+ there is now where we just read */
+ if (q->inbuf < 0)
+ q->inbuf = oldoutbuf;
+ return 0;
+}
+
+/* Returns a place to put stuff, or NULL if there is
+ no room */
+
+static u_char *__buf_pushpeek(struct confq *q)
+{
+ if (q->inbuf < 0)
+ return NULL;
+ return q->buf[q->inbuf];
+}
+
+static u_char *__buf_peek(struct confq *q)
+{
+ if (q->outbuf < 0)
+ return NULL;
+ return q->buf[q->outbuf];
+}
+
+#ifdef BUF_MUNGE
+static u_char *__buf_cpush(struct confq *q)
+{
+ int pos;
+ /* If we have no space, return where the
+ last space that we *did* have was */
+ if (q->inbuf > -1)
+ return NULL;
+ pos = q->outbuf - 1;
+ if (pos < 0)
+ pos += ZT_CB_SIZE;
+ return q->buf[pos];
+}
+
+static void __buf_munge(struct zt_chan *chan, u_char *old, u_char *new)
+{
+ /* Run a weighted average of the old and new, in order to
+ mask a missing sample */
+ int x;
+ int val;
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ val = x * ZT_XLAW(new[x], chan) + (ZT_CHUNKSIZE - x - 1) * ZT_XLAW(old[x], chan);
+ val = val / (ZT_CHUNKSIZE - 1);
+ old[x] = ZT_LIN2X(val, chan);
+ }
+}
+#endif
+/* Push something onto the queue, or assume what
+ is there is valid if data is NULL */
+static int __buf_push(struct confq *q, u_char *data, char *label)
+{
+ int oldinbuf = q->inbuf;
+ if (q->inbuf < 0) {
+ return -1;
+ }
+ if (data)
+ /* Copy in the data */
+ memcpy(q->buf[q->inbuf], data, ZT_CHUNKSIZE);
+
+ /* Advance the inbuf pointer */
+ q->inbuf = (q->inbuf + 1) % ZT_CB_SIZE;
+
+ if (q->inbuf == q->outbuf) {
+ /* No space anymore... */
+ q->inbuf = -1;
+ }
+ /* If they don't think data is ready, let
+ them know it is now */
+ if (q->outbuf < 0) {
+ q->outbuf = oldinbuf;
+ }
+ return 0;
+}
+
+static void reset_conf(struct zt_chan *chan)
+{
+ int x;
+ /* Empty out buffers and reset to initialization */
+ for (x=0;x<ZT_CB_SIZE;x++)
+ chan->confin.buf[x] = chan->confin.buffer + ZT_CHUNKSIZE * x;
+ chan->confin.inbuf = 0;
+ chan->confin.outbuf = -1;
+
+ for (x=0;x<ZT_CB_SIZE;x++)
+ chan->confout.buf[x] = chan->confout.buffer + ZT_CHUNKSIZE * x;
+ chan->confout.inbuf = 0;
+ chan->confout.outbuf = -1;
+}
+
+
+static inline int hw_echocancel_off(struct zt_chan *chan)
+{
+ struct zt_echocanparams ecp;
+
+ int ret = -ENODEV;
+ if (chan->span) {
+ if (chan->span->echocan) {
+ ret = chan->span->echocan(chan, 0);
+ } else if (chan->span->echocan_with_params) {
+ memset(&ecp, 0, sizeof(ecp)); /* Sets tap length to 0 */
+ ret = chan->span->echocan_with_params(chan, &ecp, NULL);
+ }
+ }
+ return ret;
+}
+
+static void close_channel(struct zt_chan *chan)
+{
+ unsigned long flags;
+ void *rxgain = NULL;
+ struct echo_can_state *ec = NULL;
+ int oldconf;
+ short *readchunkpreec;
+#ifdef CONFIG_ZAPATA_PPP
+ struct ppp_channel *ppp;
+#endif
+
+ /* XXX Buffers should be send out before reallocation!!! XXX */
+ if (!(chan->flags & ZT_FLAG_NOSTDTXRX))
+ zt_reallocbufs(chan, 0, 0);
+ spin_lock_irqsave(&chan->lock, flags);
+#ifdef CONFIG_ZAPATA_PPP
+ ppp = chan->ppp;
+ chan->ppp = NULL;
+#endif
+ ec = chan->ec;
+ chan->ec = NULL;
+ readchunkpreec = chan->readchunkpreec;
+ chan->readchunkpreec = NULL;
+ chan->curtone = NULL;
+ if (chan->curzone)
+ atomic_dec(&chan->curzone->refcount);
+ chan->curzone = NULL;
+ chan->cadencepos = 0;
+ chan->pdialcount = 0;
+ zt_hangup(chan);
+ chan->itimerset = chan->itimer = 0;
+ chan->pulsecount = 0;
+ chan->pulsetimer = 0;
+ chan->ringdebtimer = 0;
+ init_waitqueue_head(&chan->sel);
+ init_waitqueue_head(&chan->readbufq);
+ init_waitqueue_head(&chan->writebufq);
+ init_waitqueue_head(&chan->eventbufq);
+ init_waitqueue_head(&chan->txstateq);
+ chan->txdialbuf[0] = '\0';
+ chan->digitmode = DIGIT_MODE_DTMF;
+ chan->dialing = 0;
+ chan->afterdialingtimer = 0;
+ /* initialize IO MUX mask */
+ chan->iomask = 0;
+ /* save old conf number, if any */
+ oldconf = chan->confna;
+ /* initialize conference variables */
+ chan->_confn = 0;
+ if ((chan->sig & __ZT_SIG_DACS) != __ZT_SIG_DACS) {
+ chan->confna = 0;
+ chan->confmode = 0;
+ }
+ chan->confmute = 0;
+ /* release conference resource, if any to release */
+ if (oldconf) zt_check_conf(oldconf);
+ chan->gotgs = 0;
+ reset_conf(chan);
+
+ if (chan->gainalloc && chan->rxgain)
+ rxgain = chan->rxgain;
+
+ chan->rxgain = defgain;
+ chan->txgain = defgain;
+ chan->gainalloc = 0;
+ chan->eventinidx = chan->eventoutidx = 0;
+ chan->flags &= ~(ZT_FLAG_LOOPED | ZT_FLAG_LINEAR | ZT_FLAG_PPP | ZT_FLAG_SIGFREEZE);
+
+ zt_set_law(chan,0);
+
+ memset(chan->conflast, 0, sizeof(chan->conflast));
+ memset(chan->conflast1, 0, sizeof(chan->conflast1));
+ memset(chan->conflast2, 0, sizeof(chan->conflast2));
+
+ if (chan->span && chan->span->dacs && oldconf)
+ chan->span->dacs(chan, NULL);
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ hw_echocancel_off(chan);
+
+ if (rxgain)
+ kfree(rxgain);
+ if (ec)
+ echo_can_free(ec);
+ if (readchunkpreec)
+ kfree(readchunkpreec);
+
+#ifdef CONFIG_ZAPATA_PPP
+ if (ppp) {
+ tasklet_kill(&chan->ppp_calls);
+ skb_queue_purge(&chan->ppp_rq);
+ ppp_unregister_channel(ppp);
+ kfree(ppp);
+ }
+#endif
+
+}
+
+static int free_tone_zone(int num)
+{
+ struct zt_zone *z;
+
+ if ((num >= ZT_TONE_ZONE_MAX) || (num < 0))
+ return -EINVAL;
+
+ write_lock(&zone_lock);
+ z = tone_zones[num];
+ tone_zones[num] = NULL;
+ write_unlock(&zone_lock);
+ if (!z)
+ return 0;
+
+ if (atomic_read(&z->refcount)) {
+ /* channels are still using this zone so put it back */
+ write_lock(&zone_lock);
+ tone_zones[num] = z;
+ write_unlock(&zone_lock);
+
+ return -EBUSY;
+ } else {
+ kfree(z);
+
+ return 0;
+ }
+}
+
+static int zt_register_tone_zone(int num, struct zt_zone *zone)
+{
+ int res = 0;
+
+ if ((num >= ZT_TONE_ZONE_MAX) || (num < 0))
+ return -EINVAL;
+
+ write_lock(&zone_lock);
+ if (tone_zones[num]) {
+ res = -EINVAL;
+ } else {
+ res = 0;
+ tone_zones[num] = zone;
+ }
+ write_unlock(&zone_lock);
+
+ if (!res)
+ printk(KERN_INFO "Registered tone zone %d (%s)\n", num, zone->name);
+
+ return res;
+}
+
+static int start_tone(struct zt_chan *chan, int tone)
+{
+ int res = -EINVAL;
+
+ /* Stop the current tone, no matter what */
+ chan->tonep = 0;
+ chan->curtone = NULL;
+ chan->pdialcount = 0;
+ chan->txdialbuf[0] = '\0';
+ chan->dialing = 0;
+
+ if (tone == -1) {
+ /* Just stop the current tone */
+ res = 0;
+ } else if (!chan->curzone) {
+ static int __warnonce = 1;
+ if (__warnonce) {
+ __warnonce = 0;
+ /* The tonezones are loaded by ztcfg based on /etc/zaptel.conf. */
+ printk(KERN_WARNING "zaptel: Cannot start tones until tone zone is loaded.\n");
+ }
+ /* Note that no tone zone exists at the moment */
+ res = -ENODATA;
+ } else if ((tone >= 0 && tone <= ZT_TONE_MAX)) {
+ /* Have a tone zone */
+ if (chan->curzone->tones[tone]) {
+ chan->curtone = chan->curzone->tones[tone];
+ res = 0;
+ } else { /* Indicate that zone is loaded but no such tone exists */
+ res = -ENOSYS;
+ }
+ } else if (chan->digitmode == DIGIT_MODE_DTMF) {
+ if ((tone >= ZT_TONE_DTMF_BASE) && (tone <= ZT_TONE_DTMF_MAX)) {
+ chan->dialing = 1;
+ res = 0;
+ tone -= ZT_TONE_DTMF_BASE;
+ if (chan->curzone) {
+ /* Have a tone zone */
+ if (chan->curzone->dtmf_continuous[tone].tonesamples) {
+ chan->curtone = &chan->curzone->dtmf_continuous[tone];
+ res = 0;
+ } else {
+ /* Indicate that zone is loaded but no such tone exists */
+ res = -ENOSYS;
+ }
+ } else {
+ /* Note that no tone zone exists at the moment */
+ res = -ENODATA;
+ }
+ } else {
+ res = -EINVAL;
+ }
+ } else if (chan->digitmode == DIGIT_MODE_MFR2_FWD) {
+ if ((tone >= ZT_TONE_MFR2_FWD_BASE) && (tone <= ZT_TONE_MFR2_FWD_MAX)) {
+ res = 0;
+ tone -= ZT_TONE_MFR2_FWD_BASE;
+ if (chan->curzone) {
+ /* Have a tone zone */
+ if (chan->curzone->mfr2_fwd_continuous[tone].tonesamples) {
+ chan->curtone = &chan->curzone->mfr2_fwd_continuous[tone];
+ res = 0;
+ } else {
+ /* Indicate that zone is loaded but no such tone exists */
+ res = -ENOSYS;
+ }
+ } else {
+ /* Note that no tone zone exists at the moment */
+ res = -ENODATA;
+ }
+ } else {
+ res = -EINVAL;
+ }
+ } else if (chan->digitmode == DIGIT_MODE_MFR2_REV) {
+ if ((tone >= ZT_TONE_MFR2_REV_BASE) && (tone <= ZT_TONE_MFR2_REV_MAX)) {
+ res = 0;
+ tone -= ZT_TONE_MFR2_REV_BASE;
+ if (chan->curzone) {
+ /* Have a tone zone */
+ if (chan->curzone->mfr2_rev_continuous[tone].tonesamples) {
+ chan->curtone = &chan->curzone->mfr2_rev_continuous[tone];
+ res = 0;
+ } else {
+ /* Indicate that zone is loaded but no such tone exists */
+ res = -ENOSYS;
+ }
+ } else {
+ /* Note that no tone zone exists at the moment */
+ res = -ENODATA;
+ }
+ } else {
+ res = -EINVAL;
+ }
+ } else {
+ chan->dialing = 0;
+ res = -EINVAL;
+ }
+
+ if (chan->curtone)
+ zt_init_tone_state(&chan->ts, chan->curtone);
+
+ return res;
+}
+
+static int set_tone_zone(struct zt_chan *chan, int zone)
+{
+ int res = 0;
+ struct zt_zone *z;
+ unsigned long flags;
+
+ /* Do not call with the channel locked. */
+
+ if (zone == -1)
+ zone = default_zone;
+
+ if ((zone >= ZT_TONE_ZONE_MAX) || (zone < 0))
+ return -EINVAL;
+
+ read_lock(&zone_lock);
+
+ if ((z = tone_zones[zone])) {
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->curzone)
+ atomic_dec(&chan->curzone->refcount);
+
+ atomic_inc(&z->refcount);
+ chan->curzone = z;
+ chan->tonezone = zone;
+ memcpy(chan->ringcadence, z->ringcadence, sizeof(chan->ringcadence));
+ spin_unlock_irqrestore(&chan->lock, flags);
+ } else {
+ res = -ENODATA;
+ }
+
+ read_unlock(&zone_lock);
+
+ return res;
+}
+
+static void zt_set_law(struct zt_chan *chan, int law)
+{
+ if (!law) {
+ if (chan->deflaw)
+ law = chan->deflaw;
+ else
+ if (chan->span) law = chan->span->deflaw;
+ else law = ZT_LAW_MULAW;
+ }
+ if (law == ZT_LAW_ALAW) {
+ chan->xlaw = __zt_alaw;
+#ifdef CONFIG_CALC_XLAW
+ chan->lineartoxlaw = __zt_lineartoalaw;
+#else
+ chan->lin2x = __zt_lin2a;
+#endif
+ } else {
+ chan->xlaw = __zt_mulaw;
+#ifdef CONFIG_CALC_XLAW
+ chan->lineartoxlaw = __zt_lineartoulaw;
+#else
+ chan->lin2x = __zt_lin2mu;
+#endif
+ }
+}
+
+#ifdef CONFIG_DEVFS_FS
+static devfs_handle_t register_devfs_channel(struct zt_chan *chan, devfs_handle_t dir)
+{
+ char path[100];
+ char link[100];
+ char buf[50];
+ char tmp[100];
+ int link_offset = 0;
+ int tmp_offset = 0;
+ int path_offset = 0;
+ int err = 0;
+ devfs_handle_t chan_dev;
+ umode_t mode = S_IFCHR|S_IRUGO|S_IWUGO;
+ unsigned int flags = DEVFS_FL_AUTO_OWNER;
+
+ sprintf(path, "%d", chan->chanpos);
+ chan_dev = devfs_register(dir, path, flags, ZT_MAJOR, chan->channo, mode, &zt_fops, NULL);
+ if (!chan_dev) {
+ printk("zaptel: Something really bad happened. Unable to register devfs entry\n");
+ return NULL;
+ }
+
+ /* Set up the path of the destination of the link */
+ link_offset = devfs_generate_path(chan_dev, link, sizeof(link) - 1);
+ /* Now we need to strip off the leading "zap/". If we don't, then we build a broken symlink */
+ path_offset = devfs_generate_path(zaptel_devfs_dir, path, sizeof(path) - 1); /* We'll just "borrow" path for a second */
+ path_offset = strlen(path+path_offset);
+ link_offset += path_offset; /* Taking out the "zap" */
+ link_offset++; /* Add one more place for the '/'. The path generated does not contain the '/' we need to strip */
+
+ /* Set up the path of the file/link itself */
+ tmp_offset = devfs_generate_path(zaptel_devfs_dir, tmp, sizeof(tmp) - 1);
+ sprintf(buf, "/%d", chan->channo);
+ zap_copy_string(path, tmp+tmp_offset, sizeof(path));
+ strncat(path, buf, sizeof(path) - 1);
+
+ err = devfs_mk_symlink(NULL, path, DEVFS_FL_DEFAULT, link+link_offset, &chan->fhandle_symlink, NULL);
+ if (err != 0) {
+ printk("Problem with making devfs symlink: %d\n", err);
+ }
+
+ return chan_dev;
+}
+#endif /* CONFIG_DEVFS_FS */
+
+static int zt_chan_reg(struct zt_chan *chan)
+{
+ int x;
+ int res=0;
+ unsigned long flags;
+
+ write_lock_irqsave(&chan_lock, flags);
+ for (x=1;x<ZT_MAX_CHANNELS;x++) {
+ if (!chans[x]) {
+ spin_lock_init(&chan->lock);
+ chans[x] = chan;
+ if (maxchans < x + 1)
+ maxchans = x + 1;
+ chan->channo = x;
+ if (!chan->master)
+ chan->master = chan;
+ if (!chan->readchunk)
+ chan->readchunk = chan->sreadchunk;
+ if (!chan->writechunk)
+ chan->writechunk = chan->swritechunk;
+ zt_set_law(chan, 0);
+ close_channel(chan);
+ /* set this AFTER running close_channel() so that
+ HDLC channels wont cause hangage */
+ chan->flags |= ZT_FLAG_REGISTERED;
+ res = 0;
+ break;
+ }
+ }
+ write_unlock_irqrestore(&chan_lock, flags);
+ if (x >= ZT_MAX_CHANNELS)
+ printk(KERN_ERR "No more channels available\n");
+ return res;
+}
+
+char *zt_lboname(int x)
+{
+ if ((x < 0) || ( x > 7))
+ return "Unknown";
+ return zt_txlevelnames[x];
+}
+
+#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
+#endif
+
+#ifdef CONFIG_ZAPATA_NET
+#ifdef NEW_HDLC_INTERFACE
+static int zt_net_open(struct net_device *dev)
+{
+#ifdef LINUX26
+ int res = hdlc_open(dev);
+ struct zt_chan *ms = dev_to_ztchan(dev);
+#else
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct zt_chan *ms = hdlc_to_ztchan(hdlc);
+ int res = hdlc_open(hdlc);
+#endif
+
+/* if (!dev->hard_start_xmit) return res; is this really necessary? --byg */
+ if (res) /* this is necessary to avoid kernel panic when UNSPEC link encap, proven --byg */
+ return res;
+#else
+static int zt_net_open(hdlc_device *hdlc)
+{
+ struct zt_chan *ms = hdlc_to_ztchan(hdlc);
+ int res;
+#endif
+ if (!ms) {
+ printk("zt_net_open: nothing??\n");
+ return -EINVAL;
+ }
+ if (ms->flags & ZT_FLAG_OPEN) {
+ printk("%s is already open!\n", ms->name);
+ return -EBUSY;
+ }
+ if (!(ms->flags & ZT_FLAG_NETDEV)) {
+ printk("%s is not a net device!\n", ms->name);
+ return -EINVAL;
+ }
+ ms->txbufpolicy = ZT_POLICY_IMMEDIATE;
+ ms->rxbufpolicy = ZT_POLICY_IMMEDIATE;
+
+ res = zt_reallocbufs(ms, ZT_DEFAULT_MTU_MRU, ZT_DEFAULT_NUM_BUFS);
+ if (res)
+ return res;
+
+ fasthdlc_init(&ms->rxhdlc);
+ fasthdlc_init(&ms->txhdlc);
+ ms->infcs = PPP_INITFCS;
+
+ netif_start_queue(ztchan_to_dev(ms));
+
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("ZAPNET: Opened channel %d name %s\n", ms->channo, ms->name);
+#endif
+ return 0;
+}
+
+#ifdef LINUX26
+static int zt_register_hdlc_device(struct net_device *dev, const char *dev_name)
+{
+ int result;
+
+ if (dev_name && *dev_name) {
+ if ((result = dev_alloc_name(dev, dev_name)) < 0)
+ return result;
+ }
+ result = register_netdev(dev);
+ if (result != 0)
+ return -EIO;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,14)
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev); /* no carrier until DCD goes up */
+#endif
+ return 0;
+}
+#endif
+
+#ifdef NEW_HDLC_INTERFACE
+static int zt_net_stop(struct net_device *dev)
+{
+#ifdef LINUX26
+ hdlc_device *h = dev_to_hdlc(dev);
+ struct zt_hdlc *hdlc = h->priv;
+#else
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+#endif
+
+#else
+static void zt_net_close(hdlc_device *hdlc)
+{
+#endif
+ struct zt_chan *ms = hdlc_to_ztchan(hdlc);
+ if (!ms) {
+#ifdef NEW_HDLC_INTERFACE
+ printk("zt_net_stop: nothing??\n");
+ return 0;
+#else
+ printk("zt_net_close: nothing??\n");
+ return;
+#endif
+ }
+ if (!(ms->flags & ZT_FLAG_NETDEV)) {
+#ifdef NEW_HDLC_INTERFACE
+ printk("zt_net_stop: %s is not a net device!\n", ms->name);
+ return 0;
+#else
+ printk("zt_net_close: %s is not a net device!\n", ms->name);
+ return;
+#endif
+ }
+ /* Not much to do here. Just deallocate the buffers */
+ netif_stop_queue(ztchan_to_dev(ms));
+ zt_reallocbufs(ms, 0, 0);
+#ifdef LINUX26
+ hdlc_close(dev);
+#else
+#ifndef CONFIG_OLD_HDLC_API
+ hdlc_close(hdlc);
+#endif
+#endif
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+#ifdef NEW_HDLC_INTERFACE
+ return 0;
+#else
+ return;
+#endif
+}
+
+#ifdef NEW_HDLC_INTERFACE
+/* kernel 2.4.20+ has introduced attach function, dunno what to do,
+ just copy sources from dscc4 to be sure and ready for further mastering,
+ NOOP right now (i.e. really a stub) --byg */
+#ifdef LINUX26
+static int zt_net_attach(struct net_device *dev, unsigned short encoding,
+ unsigned short parity)
+#else
+static int zt_net_attach(hdlc_device *hdlc, unsigned short encoding,
+ unsigned short parity)
+#endif
+{
+/* struct net_device *dev = hdlc_to_dev(hdlc);
+ struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
+
+ if (encoding != ENCODING_NRZ &&
+ encoding != ENCODING_NRZI &&
+ encoding != ENCODING_FM_MARK &&
+ encoding != ENCODING_FM_SPACE &&
+ encoding != ENCODING_MANCHESTER)
+ return -EINVAL;
+
+ if (parity != PARITY_NONE &&
+ parity != PARITY_CRC16_PR0_CCITT &&
+ parity != PARITY_CRC16_PR1_CCITT &&
+ parity != PARITY_CRC32_PR0_CCITT &&
+ parity != PARITY_CRC32_PR1_CCITT)
+ return -EINVAL;
+
+ dpriv->encoding = encoding;
+ dpriv->parity = parity;*/
+ return 0;
+}
+#endif
+
+static struct zt_hdlc *zt_hdlc_alloc(void)
+{
+ struct zt_hdlc *tmp;
+ tmp = kmalloc(sizeof(struct zt_hdlc), GFP_KERNEL);
+ if (tmp) {
+ memset(tmp, 0, sizeof(struct zt_hdlc));
+ }
+ return tmp;
+}
+
+#ifdef NEW_HDLC_INTERFACE
+static int zt_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ /* FIXME: this construction seems to be not very optimal for me but I could find nothing better at the moment (Friday, 10PM :( ) --byg */
+/* struct zt_chan *ss = hdlc_to_ztchan(list_entry(dev, struct zt_hdlc, netdev.netdev));*/
+#ifdef LINUX26
+ struct zt_chan *ss = dev_to_ztchan(dev);
+ struct net_device_stats *stats = hdlc_stats(dev);
+#else
+ struct zt_chan *ss = (list_entry(dev, struct zt_hdlc, netdev.netdev)->chan);
+ struct net_device_stats *stats = &ss->hdlcnetdev->netdev.stats;
+#endif
+
+#else
+static int zt_xmit(hdlc_device *hdlc, struct sk_buff *skb)
+{
+ struct zt_chan *ss = hdlc_to_ztchan(hdlc);
+ struct net_device *dev = &ss->hdlcnetdev->netdev.netdev;
+ struct net_device_stats *stats = &ss->hdlcnetdev->netdev.stats;
+#endif
+ int retval = 1;
+ int x,oldbuf;
+ unsigned int fcs;
+ unsigned char *data;
+ unsigned long flags;
+ /* See if we have any buffers */
+ spin_lock_irqsave(&ss->lock, flags);
+ if (skb->len > ss->blocksize - 2) {
+ printk(KERN_ERR "zt_xmit(%s): skb is too large (%d > %d)\n", dev->name, skb->len, ss->blocksize -2);
+ stats->tx_dropped++;
+ retval = 0;
+ } else if (ss->inwritebuf >= 0) {
+ /* We have a place to put this packet */
+ /* XXX We should keep the SKB and avoid the memcpy XXX */
+ data = ss->writebuf[ss->inwritebuf];
+ memcpy(data, skb->data, skb->len);
+ ss->writen[ss->inwritebuf] = skb->len;
+ ss->writeidx[ss->inwritebuf] = 0;
+ /* Calculate the FCS */
+ fcs = PPP_INITFCS;
+ for (x=0;x<skb->len;x++)
+ fcs = PPP_FCS(fcs, data[x]);
+ /* Invert it */
+ fcs ^= 0xffff;
+ /* Send it out LSB first */
+ data[ss->writen[ss->inwritebuf]++] = (fcs & 0xff);
+ data[ss->writen[ss->inwritebuf]++] = (fcs >> 8) & 0xff;
+ /* Advance to next window */
+ oldbuf = ss->inwritebuf;
+ ss->inwritebuf = (ss->inwritebuf + 1) % ss->numbufs;
+
+ if (ss->inwritebuf == ss->outwritebuf) {
+ /* Whoops, no more space. */
+ ss->inwritebuf = -1;
+
+ netif_stop_queue(ztchan_to_dev(ss));
+ }
+ if (ss->outwritebuf < 0) {
+ /* Let the interrupt handler know there's
+ some space for us */
+ ss->outwritebuf = oldbuf;
+ }
+ dev->trans_start = jiffies;
+ stats->tx_packets++;
+ stats->tx_bytes += ss->writen[oldbuf];
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Buffered %d bytes to go out in buffer %d\n", ss->writen[oldbuf], oldbuf);
+ for (x=0;x<ss->writen[oldbuf];x++)
+ printk("%02x ", ss->writebuf[oldbuf][x]);
+ printk("\n");
+#endif
+ retval = 0;
+ /* Free the SKB */
+ dev_kfree_skb_any(skb);
+ }
+ spin_unlock_irqrestore(&ss->lock, flags);
+ return retval;
+}
+
+#ifdef NEW_HDLC_INTERFACE
+static int zt_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ return hdlc_ioctl(dev, ifr, cmd);
+}
+#else
+static int zt_net_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd)
+{
+ return -EIO;
+}
+#endif
+
+#endif
+
+#ifdef CONFIG_ZAPATA_PPP
+
+static int zt_ppp_xmit(struct ppp_channel *ppp, struct sk_buff *skb)
+{
+
+ /*
+ * If we can't handle the packet right now, return 0. If we
+ * we handle or drop it, return 1. Always free if we return
+ * 1 and never if we return 0
+ */
+ struct zt_chan *ss = ppp->private;
+ int x,oldbuf;
+ unsigned int fcs;
+ unsigned char *data;
+ long flags;
+ int retval = 0;
+
+ /* See if we have any buffers */
+ spin_lock_irqsave(&ss->lock, flags);
+ if (!(ss->flags & ZT_FLAG_OPEN)) {
+ printk("Can't transmit on closed channel\n");
+ retval = 1;
+ } else if (skb->len > ss->blocksize - 4) {
+ printk(KERN_ERR "zt_ppp_xmit(%s): skb is too large (%d > %d)\n", ss->name, skb->len, ss->blocksize -2);
+ retval = 1;
+ } else if (ss->inwritebuf >= 0) {
+ /* We have a place to put this packet */
+ /* XXX We should keep the SKB and avoid the memcpy XXX */
+ data = ss->writebuf[ss->inwritebuf];
+ /* Start with header of two bytes */
+ /* Add "ALL STATIONS" and "UNNUMBERED" */
+ data[0] = 0xff;
+ data[1] = 0x03;
+ ss->writen[ss->inwritebuf] = 2;
+
+ /* Copy real data and increment amount written */
+ memcpy(data + 2, skb->data, skb->len);
+
+ ss->writen[ss->inwritebuf] += skb->len;
+
+ /* Re-set index back to zero */
+ ss->writeidx[ss->inwritebuf] = 0;
+
+ /* Calculate the FCS */
+ fcs = PPP_INITFCS;
+ for (x=0;x<skb->len + 2;x++)
+ fcs = PPP_FCS(fcs, data[x]);
+ /* Invert it */
+ fcs ^= 0xffff;
+
+ /* Point past the real data now */
+ data += (skb->len + 2);
+
+ /* Send FCS out LSB first */
+ data[0] = (fcs & 0xff);
+ data[1] = (fcs >> 8) & 0xff;
+
+ /* Account for FCS length */
+ ss->writen[ss->inwritebuf]+=2;
+
+ /* Advance to next window */
+ oldbuf = ss->inwritebuf;
+ ss->inwritebuf = (ss->inwritebuf + 1) % ss->numbufs;
+
+ if (ss->inwritebuf == ss->outwritebuf) {
+ /* Whoops, no more space. */
+ ss->inwritebuf = -1;
+ }
+ if (ss->outwritebuf < 0) {
+ /* Let the interrupt handler know there's
+ some space for us */
+ ss->outwritebuf = oldbuf;
+ }
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Buffered %d bytes (skblen = %d) to go out in buffer %d\n", ss->writen[oldbuf], skb->len, oldbuf);
+ for (x=0;x<ss->writen[oldbuf];x++)
+ printk("%02x ", ss->writebuf[oldbuf][x]);
+ printk("\n");
+#endif
+ retval = 1;
+ }
+ spin_unlock_irqrestore(&ss->lock, flags);
+ if (retval) {
+ /* Get rid of the SKB if we're returning non-zero */
+ /* N.B. this is called in process or BH context so
+ dev_kfree_skb is OK. */
+ dev_kfree_skb(skb);
+ }
+ return retval;
+}
+
+static int zt_ppp_ioctl(struct ppp_channel *ppp, unsigned int cmd, unsigned long flags)
+{
+ return -EIO;
+}
+
+static struct ppp_channel_ops ztppp_ops =
+{
+ start_xmit: zt_ppp_xmit,
+ ioctl: zt_ppp_ioctl,
+};
+
+#endif
+
+static void zt_chan_unreg(struct zt_chan *chan)
+{
+ int x;
+ unsigned long flags;
+#ifdef CONFIG_ZAPATA_NET
+ if (chan->flags & ZT_FLAG_NETDEV) {
+#ifdef LINUX26
+ unregister_hdlc_device(chan->hdlcnetdev->netdev);
+ free_netdev(chan->hdlcnetdev->netdev);
+#else
+ unregister_hdlc_device(&chan->hdlcnetdev->netdev);
+#endif
+ kfree(chan->hdlcnetdev);
+ chan->hdlcnetdev = NULL;
+ }
+#endif
+ write_lock_irqsave(&chan_lock, flags);
+ if (chan->flags & ZT_FLAG_REGISTERED) {
+ chans[chan->channo] = NULL;
+ chan->flags &= ~ZT_FLAG_REGISTERED;
+ }
+#ifdef CONFIG_ZAPATA_PPP
+ if (chan->ppp) {
+ printk("HUH??? PPP still attached??\n");
+ }
+#endif
+ maxchans = 0;
+ for (x=1;x<ZT_MAX_CHANNELS;x++)
+ if (chans[x]) {
+ maxchans = x + 1;
+ /* Remove anyone pointing to us as master
+ and make them their own thing */
+ if (chans[x]->master == chan) {
+ chans[x]->master = chans[x];
+ }
+ if ((chans[x]->confna == chan->channo) &&
+ ((chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR ||
+ (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORTX ||
+ (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH ||
+ (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_RX_PREECHO ||
+ (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_TX_PREECHO ||
+ (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH_PREECHO ||
+ (chans[x]->confmode & ZT_CONF_MODE_MASK) == ZT_CONF_DIGITALMON)) {
+ /* Take them out of conference with us */
+ /* release conference resource if any */
+ if (chans[x]->confna) {
+ zt_check_conf(chans[x]->confna);
+ if (chans[x]->span && chans[x]->span->dacs)
+ chans[x]->span->dacs(chans[x], NULL);
+ }
+ chans[x]->confna = 0;
+ chans[x]->_confn = 0;
+ chans[x]->confmode = 0;
+ }
+ }
+ chan->channo = -1;
+ write_unlock_irqrestore(&chan_lock, flags);
+}
+
+static ssize_t zt_chan_read(struct file *file, char *usrbuf, size_t count, int unit)
+{
+ struct zt_chan *chan = chans[unit];
+ int amnt;
+ int res, rv;
+ int oldbuf,x;
+ unsigned long flags;
+ /* Make sure count never exceeds 65k, and make sure it's unsigned */
+ count &= 0xffff;
+ if (!chan)
+ return -EINVAL;
+ if (count < 1)
+ return -EINVAL;
+ for(;;) {
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->eventinidx != chan->eventoutidx) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -ELAST /* - chan->eventbuf[chan->eventoutidx]*/;
+ }
+ res = chan->outreadbuf;
+ if (chan->rxdisable)
+ res = -1;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ if (res >= 0) break;
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ rv = schluffen(&chan->readbufq);
+ if (rv) return (rv);
+ }
+ amnt = count;
+/* added */
+#if 0
+ if ((unit == 24) || (unit == 48) || (unit == 16) || (unit == 47)) {
+ int myamnt = amnt;
+ int x;
+ if (amnt > chan->readn[res])
+ myamnt = chan->readn[res];
+ printk("zt_chan_read(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d\n",
+ unit, chan->inwritebuf, chan->outwritebuf, myamnt);
+ printk("\t("); for (x = 0; x < myamnt; x++) printk((x ? " %02x" : "%02x"), (unsigned char)usrbuf[x]);
+ printk(")\n");
+ }
+#endif
+/* end addition */
+ if (chan->flags & ZT_FLAG_LINEAR) {
+ if (amnt > (chan->readn[res] << 1))
+ amnt = chan->readn[res] << 1;
+ if (amnt) {
+ /* There seems to be a max stack size, so we have
+ to do this in smaller pieces */
+ short lindata[128];
+ int left = amnt >> 1; /* amnt is in bytes */
+ int pos = 0;
+ int pass;
+ while(left) {
+ pass = left;
+ if (pass > 128)
+ pass = 128;
+ for (x=0;x<pass;x++)
+ lindata[x] = ZT_XLAW(chan->readbuf[res][x + pos], chan);
+ if (copy_to_user(usrbuf + (pos << 1), lindata, pass << 1))
+ return -EFAULT;
+ left -= pass;
+ pos += pass;
+ }
+ }
+ } else {
+ if (amnt > chan->readn[res])
+ amnt = chan->readn[res];
+ if (amnt) {
+ if (copy_to_user(usrbuf, chan->readbuf[res], amnt))
+ return -EFAULT;
+ }
+ }
+ spin_lock_irqsave(&chan->lock, flags);
+ chan->readidx[res] = 0;
+ chan->readn[res] = 0;
+ oldbuf = res;
+ chan->outreadbuf = (res + 1) % chan->numbufs;
+ if (chan->outreadbuf == chan->inreadbuf) {
+ /* Out of stuff */
+ chan->outreadbuf = -1;
+ if (chan->rxbufpolicy == ZT_POLICY_WHEN_FULL)
+ chan->rxdisable = 1;
+ }
+ if (chan->inreadbuf < 0) {
+ /* Notify interrupt handler that we have some space now */
+ chan->inreadbuf = oldbuf;
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ return amnt;
+}
+
+static ssize_t zt_chan_write(struct file *file, const char *usrbuf, size_t count, int unit)
+{
+ unsigned long flags;
+ struct zt_chan *chan = chans[unit];
+ int res, amnt, oldbuf, rv,x;
+ /* Make sure count never exceeds 65k, and make sure it's unsigned */
+ count &= 0xffff;
+ if (!chan)
+ return -EINVAL;
+ if (count < 1)
+ return -EINVAL;
+ for(;;) {
+ spin_lock_irqsave(&chan->lock, flags);
+ if ((chan->curtone || chan->pdialcount) && !(chan->flags & ZT_FLAG_PSEUDO)) {
+ chan->curtone = NULL;
+ chan->tonep = 0;
+ chan->dialing = 0;
+ chan->txdialbuf[0] = '\0';
+ chan->pdialcount = 0;
+ }
+ if (chan->eventinidx != chan->eventoutidx) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -ELAST;
+ }
+ res = chan->inwritebuf;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ if (res >= 0)
+ break;
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ /* Wait for something to be available */
+ rv = schluffen(&chan->writebufq);
+ if (rv)
+ return rv;
+ }
+
+ amnt = count;
+ if (chan->flags & ZT_FLAG_LINEAR) {
+ if (amnt > (chan->blocksize << 1))
+ amnt = chan->blocksize << 1;
+ } else {
+ if (amnt > chan->blocksize)
+ amnt = chan->blocksize;
+ }
+
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("zt_chan_write(unit: %d, res: %d, outwritebuf: %d amnt: %d\n",
+ unit, chan->res, chan->outwritebuf, amnt);
+#endif
+#if 0
+ if ((unit == 24) || (unit == 48) || (unit == 16) || (unit == 47)) {
+ int x;
+ printk("zt_chan_write/in(unit: %d, res: %d, outwritebuf: %d amnt: %d, txdisable: %d)\n",
+ unit, res, chan->outwritebuf, amnt, chan->txdisable);
+ printk("\t("); for (x = 0; x < amnt; x++) printk((x ? " %02x" : "%02x"), (unsigned char)usrbuf[x]);
+ printk(")\n");
+ }
+#endif
+
+ if (amnt) {
+ if (chan->flags & ZT_FLAG_LINEAR) {
+ /* There seems to be a max stack size, so we have
+ to do this in smaller pieces */
+ short lindata[128];
+ int left = amnt >> 1; /* amnt is in bytes */
+ int pos = 0;
+ int pass;
+ while(left) {
+ pass = left;
+ if (pass > 128)
+ pass = 128;
+ if (copy_from_user(lindata, usrbuf + (pos << 1), pass << 1))
+ return -EFAULT;
+ left -= pass;
+ for (x=0;x<pass;x++)
+ chan->writebuf[res][x + pos] = ZT_LIN2X(lindata[x], chan);
+ pos += pass;
+ }
+ chan->writen[res] = amnt >> 1;
+ } else {
+ if (copy_from_user(chan->writebuf[res], usrbuf, amnt))
+ return -EFAULT;
+ chan->writen[res] = amnt;
+ }
+ chan->writeidx[res] = 0;
+ if (chan->flags & ZT_FLAG_FCS)
+ calc_fcs(chan, res);
+ oldbuf = res;
+ spin_lock_irqsave(&chan->lock, flags);
+ chan->inwritebuf = (res + 1) % chan->numbufs;
+ if (chan->inwritebuf == chan->outwritebuf) {
+ /* Don't stomp on the transmitter, just wait for them to
+ wake us up */
+ chan->inwritebuf = -1;
+ /* Make sure the transmitter is transmitting in case of POLICY_WHEN_FULL */
+ chan->txdisable = 0;
+ }
+ if (chan->outwritebuf < 0) {
+ /* Okay, the interrupt handler has been waiting for us. Give them a buffer */
+ chan->outwritebuf = oldbuf;
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ if (chan->flags & ZT_FLAG_NOSTDTXRX && chan->span->hdlc_hard_xmit)
+ chan->span->hdlc_hard_xmit(chan);
+ }
+ return amnt;
+}
+
+static int zt_ctl_open(struct inode *inode, struct file *file)
+{
+ /* Nothing to do, really */
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static int zt_chan_open(struct inode *inode, struct file *file)
+{
+ /* Nothing to do here for now either */
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static int zt_ctl_release(struct inode *inode, struct file *file)
+{
+ /* Nothing to do */
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static int zt_chan_release(struct inode *inode, struct file *file)
+{
+ /* Nothing to do for now */
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
+static void set_txtone(struct zt_chan *ss,int fac, int init_v2, int init_v3)
+{
+ if (fac == 0)
+ {
+ ss->v2_1 = 0;
+ ss->v3_1 = 0;
+ return;
+ }
+ ss->txtone = fac;
+ ss->v1_1 = 0;
+ ss->v2_1 = init_v2;
+ ss->v3_1 = init_v3;
+ return;
+}
+
+static void zt_rbs_sethook(struct zt_chan *chan, int txsig, int txstate, int timeout)
+{
+static int outs[NUM_SIGS][5] = {
+/* We set the idle case of the ZT_SIG_NONE to this pattern to make idle E1 CAS
+channels happy. Should not matter with T1, since on an un-configured channel,
+who cares what the sig bits are as long as they are stable */
+ { ZT_SIG_NONE, ZT_ABIT | ZT_CBIT | ZT_DBIT, 0, 0, 0 }, /* no signalling */
+ { ZT_SIG_EM, 0, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* E and M */
+ { ZT_SIG_FXSLS, ZT_BBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* FXS Loopstart */
+ { ZT_SIG_FXSGS, ZT_BBIT | ZT_DBIT,
+#ifdef CONFIG_CAC_GROUNDSTART
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0, 0 }, /* FXS Groundstart (CAC-style) */
+#else
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, ZT_ABIT | ZT_CBIT, 0 }, /* FXS Groundstart (normal) */
+#endif
+ { ZT_SIG_FXSKS, ZT_BBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* FXS Kewlstart */
+ { ZT_SIG_FXOLS, ZT_BBIT | ZT_DBIT, ZT_BBIT | ZT_DBIT, 0, 0 }, /* FXO Loopstart */
+ { ZT_SIG_FXOGS, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_BBIT | ZT_DBIT, 0, 0 }, /* FXO Groundstart */
+ { ZT_SIG_FXOKS, ZT_BBIT | ZT_DBIT, ZT_BBIT | ZT_DBIT, 0,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT }, /* FXO Kewlstart */
+ { ZT_SIG_SF, ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_BBIT | ZT_CBIT | ZT_DBIT }, /* no signalling */
+ { ZT_SIG_EM_E1, ZT_DBIT, ZT_ABIT | ZT_BBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_DBIT, ZT_DBIT }, /* E and M E1 */
+ } ;
+ int x;
+
+ /* if no span, return doing nothing */
+ if (!chan->span) return;
+ if (!chan->span->flags & ZT_FLAG_RBS) {
+ printk("zt_rbs: Tried to set RBS hook state on non-RBS channel %s\n", chan->name);
+ return;
+ }
+ if ((txsig > 3) || (txsig < 0)) {
+ printk("zt_rbs: Tried to set RBS hook state %d (> 3) on channel %s\n", txsig, chan->name);
+ return;
+ }
+ if (!chan->span->rbsbits && !chan->span->hooksig) {
+ printk("zt_rbs: Tried to set RBS hook state %d on channel %s while span %s lacks rbsbits or hooksig function\n",
+ txsig, chan->name, chan->span->name);
+ return;
+ }
+ /* Don't do anything for RBS */
+ if (chan->sig == ZT_SIG_DACS_RBS)
+ return;
+ chan->txstate = txstate;
+
+ /* if tone signalling */
+ if (chan->sig == ZT_SIG_SF)
+ {
+ chan->txhooksig = txsig;
+ if (chan->txtone) /* if set to make tone for tx */
+ {
+ if ((txsig && !(chan->toneflags & ZT_REVERSE_TXTONE)) ||
+ ((!txsig) && (chan->toneflags & ZT_REVERSE_TXTONE)))
+ {
+ set_txtone(chan,chan->txtone,chan->tx_v2,chan->tx_v3);
+ }
+ else
+ {
+ set_txtone(chan,0,0,0);
+ }
+ }
+ chan->otimer = timeout * ZT_CHUNKSIZE; /* Otimer is timer in samples */
+ return;
+ }
+ if (chan->span->hooksig) {
+ if (chan->txhooksig != txsig) {
+ chan->txhooksig = txsig;
+ chan->span->hooksig(chan, txsig);
+ }
+ chan->otimer = timeout * ZT_CHUNKSIZE; /* Otimer is timer in samples */
+ return;
+ } else {
+ for (x=0;x<NUM_SIGS;x++) {
+ if (outs[x][0] == chan->sig) {
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Setting bits to %d for channel %s state %d in %d signalling\n", outs[x][txsig + 1], chan->name, txsig, chan->sig);
+#endif
+ chan->txhooksig = txsig;
+ chan->txsig = outs[x][txsig+1];
+ chan->span->rbsbits(chan, chan->txsig);
+ chan->otimer = timeout * ZT_CHUNKSIZE; /* Otimer is timer in samples */
+ return;
+ }
+ }
+ }
+ printk("zt_rbs: Don't know RBS signalling type %d on channel %s\n", chan->sig, chan->name);
+}
+
+static int zt_cas_setbits(struct zt_chan *chan, int bits)
+{
+ /* if no span, return as error */
+ if (!chan->span) return -1;
+ if (chan->span->rbsbits) {
+ chan->txsig = bits;
+ chan->span->rbsbits(chan, bits);
+ } else {
+ printk("Huh? CAS setbits, but no RBS bits function\n");
+ }
+ return 0;
+}
+
+static int zt_hangup(struct zt_chan *chan)
+{
+ int x,res=0;
+
+ /* Can't hangup pseudo channels */
+ if (!chan->span)
+ return 0;
+ /* Can't hang up a clear channel */
+ if (chan->flags & (ZT_FLAG_CLEAR | ZT_FLAG_NOSTDTXRX))
+ return -EINVAL;
+
+ chan->kewlonhook = 0;
+
+
+ if ((chan->sig == ZT_SIG_FXSLS) || (chan->sig == ZT_SIG_FXSKS) ||
+ (chan->sig == ZT_SIG_FXSGS)) chan->ringdebtimer = RING_DEBOUNCE_TIME;
+
+ if (chan->span->flags & ZT_FLAG_RBS) {
+ if (chan->sig == ZT_SIG_CAS) {
+ zt_cas_setbits(chan, chan->idlebits);
+ } else if ((chan->sig == ZT_SIG_FXOKS) && (chan->txstate != ZT_TXSTATE_ONHOOK)
+ /* if other party is already on-hook we shouldn't do any battery drop */
+ && !((chan->rxhooksig == ZT_RXSIG_ONHOOK) && (chan->itimer <= 0))) {
+ /* Do RBS signalling on the channel's behalf */
+ zt_rbs_sethook(chan, ZT_TXSIG_KEWL, ZT_TXSTATE_KEWL, ZT_KEWLTIME);
+ } else
+ zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_ONHOOK, 0);
+ } else {
+ /* Let the driver hang up the line if it wants to */
+ if (chan->span->sethook) {
+ if (chan->txhooksig != ZT_ONHOOK) {
+ chan->txhooksig = ZT_ONHOOK;
+ res = chan->span->sethook(chan, ZT_ONHOOK);
+ } else
+ res = 0;
+ }
+ }
+ /* if not registered yet, just return here */
+ if (!(chan->flags & ZT_FLAG_REGISTERED)) return res;
+ /* Mark all buffers as empty */
+ for (x = 0;x < chan->numbufs;x++) {
+ chan->writen[x] =
+ chan->writeidx[x]=
+ chan->readn[x]=
+ chan->readidx[x] = 0;
+ }
+ if (chan->readbuf[0]) {
+ chan->inreadbuf = 0;
+ chan->inwritebuf = 0;
+ } else {
+ chan->inreadbuf = -1;
+ chan->inwritebuf = -1;
+ }
+ chan->outreadbuf = -1;
+ chan->outwritebuf = -1;
+ chan->dialing = 0;
+ chan->afterdialingtimer = 0;
+ chan->curtone = NULL;
+ chan->pdialcount = 0;
+ chan->cadencepos = 0;
+ chan->txdialbuf[0] = 0;
+ return res;
+}
+
+static int initialize_channel(struct zt_chan *chan)
+{
+ int res;
+ unsigned long flags;
+ void *rxgain=NULL;
+ struct echo_can_state *ec=NULL;
+ if ((res = zt_reallocbufs(chan, ZT_DEFAULT_BLOCKSIZE, ZT_DEFAULT_NUM_BUFS)))
+ return res;
+
+ spin_lock_irqsave(&chan->lock, flags);
+
+ chan->rxbufpolicy = ZT_POLICY_IMMEDIATE;
+ chan->txbufpolicy = ZT_POLICY_IMMEDIATE;
+
+ /* Free up the echo canceller if there is one */
+ ec = chan->ec;
+ chan->ec = NULL;
+ chan->echocancel = 0;
+ chan->echostate = ECHO_STATE_IDLE;
+ chan->echolastupdate = 0;
+ chan->echotimer = 0;
+
+ chan->txdisable = 0;
+ chan->rxdisable = 0;
+
+ chan->digitmode = DIGIT_MODE_DTMF;
+ chan->dialing = 0;
+ chan->afterdialingtimer = 0;
+
+ chan->cadencepos = 0;
+ chan->firstcadencepos = 0; /* By default loop back to first cadence position */
+
+ /* HDLC & FCS stuff */
+ fasthdlc_init(&chan->rxhdlc);
+ fasthdlc_init(&chan->txhdlc);
+ chan->infcs = PPP_INITFCS;
+
+ /* Timings for RBS */
+ chan->prewinktime = ZT_DEFAULT_PREWINKTIME;
+ chan->preflashtime = ZT_DEFAULT_PREFLASHTIME;
+ chan->winktime = ZT_DEFAULT_WINKTIME;
+ chan->flashtime = ZT_DEFAULT_FLASHTIME;
+
+ if (chan->sig & __ZT_SIG_FXO)
+ chan->starttime = ZT_DEFAULT_RINGTIME;
+ else
+ chan->starttime = ZT_DEFAULT_STARTTIME;
+ chan->rxwinktime = ZT_DEFAULT_RXWINKTIME;
+ chan->rxflashtime = ZT_DEFAULT_RXFLASHTIME;
+ chan->debouncetime = ZT_DEFAULT_DEBOUNCETIME;
+ chan->pulsemaketime = ZT_DEFAULT_PULSEMAKETIME;
+ chan->pulsebreaktime = ZT_DEFAULT_PULSEBREAKTIME;
+ chan->pulseaftertime = ZT_DEFAULT_PULSEAFTERTIME;
+
+ /* Initialize RBS timers */
+ chan->itimerset = chan->itimer = chan->otimer = 0;
+ chan->ringdebtimer = 0;
+
+ init_waitqueue_head(&chan->sel);
+ init_waitqueue_head(&chan->readbufq);
+ init_waitqueue_head(&chan->writebufq);
+ init_waitqueue_head(&chan->eventbufq);
+ init_waitqueue_head(&chan->txstateq);
+
+ /* Reset conferences */
+ reset_conf(chan);
+
+ /* I/O Mask, etc */
+ chan->iomask = 0;
+ /* release conference resource if any */
+ if (chan->confna) zt_check_conf(chan->confna);
+ if ((chan->sig & __ZT_SIG_DACS) != __ZT_SIG_DACS) {
+ chan->confna = 0;
+ chan->confmode = 0;
+ if (chan->span && chan->span->dacs)
+ chan->span->dacs(chan, NULL);
+ }
+ chan->_confn = 0;
+ memset(chan->conflast, 0, sizeof(chan->conflast));
+ memset(chan->conflast1, 0, sizeof(chan->conflast1));
+ memset(chan->conflast2, 0, sizeof(chan->conflast2));
+ chan->confmute = 0;
+ chan->gotgs = 0;
+ chan->curtone = NULL;
+ chan->tonep = 0;
+ chan->pdialcount = 0;
+ if (chan->gainalloc && chan->rxgain)
+ rxgain = chan->rxgain;
+ chan->rxgain = defgain;
+ chan->txgain = defgain;
+ chan->gainalloc = 0;
+ chan->eventinidx = chan->eventoutidx = 0;
+ zt_set_law(chan,0);
+ zt_hangup(chan);
+
+ /* Make sure that the audio flag is cleared on a clear channel */
+ if ((chan->sig & ZT_SIG_CLEAR) || (chan->sig & ZT_SIG_HARDHDLC))
+ chan->flags &= ~ZT_FLAG_AUDIO;
+
+ if ((chan->sig == ZT_SIG_CLEAR) || (chan->sig == ZT_SIG_HARDHDLC))
+ chan->flags &= ~(ZT_FLAG_PPP | ZT_FLAG_FCS | ZT_FLAG_HDLC);
+
+ chan->flags &= ~ZT_FLAG_LINEAR;
+ if (chan->curzone) {
+ /* Take cadence from tone zone */
+ memcpy(chan->ringcadence, chan->curzone->ringcadence, sizeof(chan->ringcadence));
+ } else {
+ /* Do a default */
+ memset(chan->ringcadence, 0, sizeof(chan->ringcadence));
+ chan->ringcadence[0] = chan->starttime;
+ chan->ringcadence[1] = ZT_RINGOFFTIME;
+ }
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+ set_tone_zone(chan, -1);
+
+ hw_echocancel_off(chan);
+
+ if (rxgain)
+ kfree(rxgain);
+ if (ec)
+ echo_can_free(ec);
+ return 0;
+}
+
+static int zt_timing_open(struct inode *inode, struct file *file)
+{
+ struct zt_timer *t;
+ unsigned long flags;
+ t = kmalloc(sizeof(struct zt_timer), GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
+ /* Allocate a new timer */
+ memset(t, 0, sizeof(struct zt_timer));
+ init_waitqueue_head(&t->sel);
+ file->private_data = t;
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+ spin_lock_irqsave(&zaptimerlock, flags);
+ t->next = zaptimers;
+ zaptimers = t;
+ spin_unlock_irqrestore(&zaptimerlock, flags);
+ return 0;
+}
+
+static int zt_timer_release(struct inode *inode, struct file *file)
+{
+ struct zt_timer *t, *cur, *prev;
+ unsigned long flags;
+ t = file->private_data;
+ if (t) {
+ spin_lock_irqsave(&zaptimerlock, flags);
+ prev = NULL;
+ cur = zaptimers;
+ while(cur) {
+ if (t == cur)
+ break;
+ prev = cur;
+ cur = cur->next;
+ }
+ if (cur) {
+ if (prev)
+ prev->next = cur->next;
+ else
+ zaptimers = cur->next;
+ }
+ spin_unlock_irqrestore(&zaptimerlock, flags);
+ if (!cur) {
+ printk("Zap Timer: Not on list??\n");
+ return 0;
+ }
+ kfree(t);
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ }
+ return 0;
+}
+
+static int zt_specchan_open(struct inode *inode, struct file *file, int unit, int inc)
+{
+ int res = 0;
+
+ if (chans[unit] && chans[unit]->sig) {
+ /* Make sure we're not already open, a net device, or a slave device */
+ if (chans[unit]->flags & ZT_FLAG_NETDEV)
+ res = -EBUSY;
+ else if (chans[unit]->master != chans[unit])
+ res = -EBUSY;
+ else if ((chans[unit]->sig & __ZT_SIG_DACS) == __ZT_SIG_DACS)
+ res = -EBUSY;
+ else if (!test_and_set_bit(ZT_FLAGBIT_OPEN, &chans[unit]->flags)) {
+ unsigned long flags;
+ res = initialize_channel(chans[unit]);
+ if (res) {
+ /* Reallocbufs must have failed */
+ clear_bit(ZT_FLAGBIT_OPEN, &chans[unit]->flags);
+ return res;
+ }
+ spin_lock_irqsave(&chans[unit]->lock, flags);
+ if (chans[unit]->flags & ZT_FLAG_PSEUDO)
+ chans[unit]->flags |= ZT_FLAG_AUDIO;
+ if (chans[unit]->span && chans[unit]->span->open) {
+ res = chans[unit]->span->open(chans[unit]);
+ }
+ if (!res) {
+ chans[unit]->file = file;
+#ifndef LINUX26
+ if (inc)
+ MOD_INC_USE_COUNT;
+#endif
+ spin_unlock_irqrestore(&chans[unit]->lock, flags);
+ } else {
+ spin_unlock_irqrestore(&chans[unit]->lock, flags);
+ close_channel(chans[unit]);
+ clear_bit(ZT_FLAGBIT_OPEN, &chans[unit]->flags);
+ }
+ } else
+ res = -EBUSY;
+ } else
+ res = -ENXIO;
+ return res;
+}
+
+static int zt_specchan_release(struct inode *node, struct file *file, int unit)
+{
+ int res=0;
+ unsigned long flags;
+
+ if (chans[unit]) {
+ /* Chan lock protects contents against potentially non atomic accesses.
+ * So if the pointer setting is not atomic, we should protect */
+ spin_lock_irqsave(&chans[unit]->lock, flags);
+ chans[unit]->file = NULL;
+ spin_unlock_irqrestore(&chans[unit]->lock, flags);
+ close_channel(chans[unit]);
+ if (chans[unit]->span && chans[unit]->span->close)
+ res = chans[unit]->span->close(chans[unit]);
+ clear_bit(ZT_FLAGBIT_OPEN, &chans[unit]->flags);
+ } else
+ res = -ENXIO;
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ return res;
+}
+
+static struct zt_chan *zt_alloc_pseudo(void)
+{
+ struct zt_chan *pseudo;
+ unsigned long flags;
+ /* Don't allow /dev/zap/pseudo to open if there are no spans */
+ if (maxspans < 1)
+ return NULL;
+ pseudo = kmalloc(sizeof(struct zt_chan), GFP_KERNEL);
+ if (!pseudo)
+ return NULL;
+ memset(pseudo, 0, sizeof(struct zt_chan));
+ pseudo->sig = ZT_SIG_CLEAR;
+ pseudo->sigcap = ZT_SIG_CLEAR;
+ pseudo->flags = ZT_FLAG_PSEUDO | ZT_FLAG_AUDIO;
+ spin_lock_irqsave(&bigzaplock, flags);
+ if (zt_chan_reg(pseudo)) {
+ kfree(pseudo);
+ pseudo = NULL;
+ } else
+ sprintf(pseudo->name, "Pseudo/%d", pseudo->channo);
+ spin_unlock_irqrestore(&bigzaplock, flags);
+ return pseudo;
+}
+
+static void zt_free_pseudo(struct zt_chan *pseudo)
+{
+ unsigned long flags;
+ if (pseudo) {
+ spin_lock_irqsave(&bigzaplock, flags);
+ zt_chan_unreg(pseudo);
+ spin_unlock_irqrestore(&bigzaplock, flags);
+ kfree(pseudo);
+ }
+}
+
+static int zt_open(struct inode *inode, struct file *file)
+{
+ int unit = UNIT(file);
+ int ret = -ENXIO;
+ struct zt_chan *chan;
+ /* Minor 0: Special "control" descriptor */
+ if (!unit)
+ return zt_ctl_open(inode, file);
+ if (unit == 250) {
+ if (!zt_transcode_fops)
+ request_module("zttranscode");
+ if (zt_transcode_fops && zt_transcode_fops->open) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ if (zt_transcode_fops->owner) {
+ __MOD_INC_USE_COUNT (zt_transcode_fops->owner);
+#else
+ if (try_module_get(zt_transcode_fops->owner)) {
+#endif
+ ret = zt_transcode_fops->open(inode, file);
+ if (ret)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ __MOD_DEC_USE_COUNT (zt_transcode_fops->owner);
+#else
+ module_put(zt_transcode_fops->owner);
+#endif
+ }
+ return ret;
+ }
+ return -ENXIO;
+ }
+ if (unit == 253) {
+ if (maxspans) {
+ return zt_timing_open(inode, file);
+ } else {
+ return -ENXIO;
+ }
+ }
+ if (unit == 254)
+ return zt_chan_open(inode, file);
+ if (unit == 255) {
+ if (maxspans) {
+ chan = zt_alloc_pseudo();
+ if (chan) {
+ file->private_data = chan;
+ return zt_specchan_open(inode, file, chan->channo, 1);
+ } else {
+ return -ENXIO;
+ }
+ } else
+ return -ENXIO;
+ }
+ return zt_specchan_open(inode, file, unit, 1);
+}
+
+#if 0
+static int zt_open(struct inode *inode, struct file *file)
+{
+ int res;
+ unsigned long flags;
+ spin_lock_irqsave(&bigzaplock, flags);
+ res = __zt_open(inode, file);
+ spin_unlock_irqrestore(&bigzaplock, flags);
+ return res;
+}
+#endif
+
+static ssize_t zt_read(struct file *file, char *usrbuf, size_t count, loff_t *ppos)
+{
+ int unit = UNIT(file);
+ struct zt_chan *chan;
+
+ /* Can't read from control */
+ if (!unit) {
+ return -EINVAL;
+ }
+
+ if (unit == 253)
+ return -EINVAL;
+
+ if (unit == 254) {
+ chan = file->private_data;
+ if (!chan)
+ return -EINVAL;
+ return zt_chan_read(file, usrbuf, count, chan->channo);
+ }
+
+ if (unit == 255) {
+ chan = file->private_data;
+ if (!chan) {
+ printk("No pseudo channel structure to read?\n");
+ return -EINVAL;
+ }
+ return zt_chan_read(file, usrbuf, count, chan->channo);
+ }
+ if (count < 0)
+ return -EINVAL;
+
+ return zt_chan_read(file, usrbuf, count, unit);
+}
+
+static ssize_t zt_write(struct file *file, const char *usrbuf, size_t count, loff_t *ppos)
+{
+ int unit = UNIT(file);
+ struct zt_chan *chan;
+ /* Can't read from control */
+ if (!unit)
+ return -EINVAL;
+ if (count < 0)
+ return -EINVAL;
+ if (unit == 253)
+ return -EINVAL;
+ if (unit == 254) {
+ chan = file->private_data;
+ if (!chan)
+ return -EINVAL;
+ return zt_chan_write(file, usrbuf, count, chan->channo);
+ }
+ if (unit == 255) {
+ chan = file->private_data;
+ if (!chan) {
+ printk("No pseudo channel structure to read?\n");
+ return -EINVAL;
+ }
+ return zt_chan_write(file, usrbuf, count, chan->channo);
+ }
+ return zt_chan_write(file, usrbuf, count, unit);
+
+}
+
+static int zt_set_default_zone(int defzone)
+{
+ if ((defzone < 0) || (defzone >= ZT_TONE_ZONE_MAX))
+ return -EINVAL;
+ write_lock(&zone_lock);
+ if (!tone_zones[defzone]) {
+ write_unlock(&zone_lock);
+ return -EINVAL;
+ }
+ if ((default_zone != -1) && tone_zones[default_zone])
+ atomic_dec(&tone_zones[default_zone]->refcount);
+ atomic_inc(&tone_zones[defzone]->refcount);
+ default_zone = defzone;
+ write_unlock(&zone_lock);
+ return 0;
+}
+
+/* No bigger than 32k for everything per tone zone */
+#define MAX_SIZE 32768
+/* No more than 128 subtones */
+#define MAX_TONES 128
+
+/* The tones to be loaded can (will) be a mix of regular tones,
+ DTMF tones and MF tones. We need to load DTMF and MF tones
+ a bit differently than regular tones because their storage
+ format is much simpler (an array structure field of the zone
+ structure, rather an array of pointers).
+*/
+static int ioctl_load_zone(unsigned long data)
+{
+ struct zt_tone *samples[MAX_TONES] = { NULL, };
+ short next[MAX_TONES] = { 0, };
+ struct zt_tone_def_header th;
+ struct zt_tone_def td;
+ struct zt_zone *z;
+ struct zt_tone *t;
+ void *slab, *ptr;
+ int x;
+ size_t space;
+ size_t size;
+ int res;
+
+ if (copy_from_user(&th, (struct zt_tone_def_header *) data, sizeof(th)))
+ return -EFAULT;
+
+ data += sizeof(th);
+
+ if ((th.count < 0) || (th.count > MAX_TONES)) {
+ printk("Too many tones included\n");
+ return -EINVAL;
+ }
+
+ space = size = sizeof(*z) + th.count * sizeof(*t);
+
+ if (size > MAX_SIZE)
+ return -E2BIG;
+
+ if (!(z = ptr = slab = kmalloc(size, GFP_KERNEL)))
+ return -ENOMEM;
+
+ memset(slab, 0, size);
+
+ ptr += sizeof(*z);
+ space -= sizeof(*z);
+
+ zap_copy_string(z->name, th.name, sizeof(z->name));
+
+ for (x = 0; x < ZT_MAX_CADENCE; x++)
+ z->ringcadence[x] = th.ringcadence[x];
+
+ atomic_set(&z->refcount, 0);
+
+ for (x = 0; x < th.count; x++) {
+ enum {
+ REGULAR_TONE,
+ DTMF_TONE,
+ MFR1_TONE,
+ MFR2_FWD_TONE,
+ MFR2_REV_TONE,
+ } tone_type;
+
+ if (space < sizeof(*t)) {
+ kfree(slab);
+ printk("Insufficient tone zone space\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&td, (struct zt_tone_def *) data, sizeof(td))) {
+ kfree(slab);
+ return -EFAULT;
+ }
+
+ data += sizeof(td);
+
+ if ((td.tone >= 0) && (td.tone < ZT_TONE_MAX)) {
+ tone_type = REGULAR_TONE;
+
+ t = samples[x] = ptr;
+
+ space -= sizeof(*t);
+ ptr += sizeof(*t);
+
+ /* Remember which sample is next */
+ next[x] = td.next;
+
+ /* Make sure the "next" one is sane */
+ if ((next[x] >= th.count) || (next[x] < 0)) {
+ printk("Invalid 'next' pointer: %d\n", next[x]);
+ kfree(slab);
+ return -EINVAL;
+ }
+ } else if ((td.tone >= ZT_TONE_DTMF_BASE) &&
+ (td.tone <= ZT_TONE_DTMF_MAX)) {
+ tone_type = DTMF_TONE;
+ td.tone -= ZT_TONE_DTMF_BASE;
+ t = &z->dtmf[td.tone];
+ } else if ((td.tone >= ZT_TONE_MFR1_BASE) &&
+ (td.tone <= ZT_TONE_MFR1_MAX)) {
+ tone_type = MFR1_TONE;
+ td.tone -= ZT_TONE_MFR1_BASE;
+ t = &z->mfr1[td.tone];
+ } else if ((td.tone >= ZT_TONE_MFR2_FWD_BASE) &&
+ (td.tone <= ZT_TONE_MFR2_FWD_MAX)) {
+ tone_type = MFR2_FWD_TONE;
+ td.tone -= ZT_TONE_MFR2_FWD_BASE;
+ t = &z->mfr2_fwd[td.tone];
+ } else if ((td.tone >= ZT_TONE_MFR2_REV_BASE) &&
+ (td.tone <= ZT_TONE_MFR2_REV_MAX)) {
+ tone_type = MFR2_REV_TONE;
+ td.tone -= ZT_TONE_MFR2_REV_BASE;
+ t = &z->mfr2_rev[td.tone];
+ } else {
+ printk("Invalid tone (%d) defined\n", td.tone);
+ kfree(slab);
+ return -EINVAL;
+ }
+
+ t->fac1 = td.fac1;
+ t->init_v2_1 = td.init_v2_1;
+ t->init_v3_1 = td.init_v3_1;
+ t->fac2 = td.fac2;
+ t->init_v2_2 = td.init_v2_2;
+ t->init_v3_2 = td.init_v3_2;
+ t->modulate = td.modulate;
+
+ switch (tone_type) {
+ case REGULAR_TONE:
+ t->tonesamples = td.samples;
+ if (!z->tones[td.tone])
+ z->tones[td.tone] = t;
+ break;
+ case DTMF_TONE:
+ t->tonesamples = global_dialparams.dtmf_tonelen;
+ t->next = &dtmf_silence;
+ z->dtmf_continuous[td.tone] = *t;
+ z->dtmf_continuous[td.tone].next = &z->dtmf_continuous[td.tone];
+ break;
+ case MFR1_TONE:
+ switch (td.tone + ZT_TONE_MFR1_BASE) {
+ case ZT_TONE_MFR1_KP:
+ case ZT_TONE_MFR1_ST:
+ case ZT_TONE_MFR1_STP:
+ case ZT_TONE_MFR1_ST2P:
+ case ZT_TONE_MFR1_ST3P:
+ /* signaling control tones are always 100ms */
+ t->tonesamples = 100 * ZT_CHUNKSIZE;
+ break;
+ default:
+ t->tonesamples = global_dialparams.mfv1_tonelen;
+ break;
+ }
+ t->next = &mfr1_silence;
+ break;
+ case MFR2_FWD_TONE:
+ t->tonesamples = global_dialparams.mfr2_tonelen;
+ t->next = &dtmf_silence;
+ z->mfr2_fwd_continuous[td.tone] = *t;
+ z->mfr2_fwd_continuous[td.tone].next = &z->mfr2_fwd_continuous[td.tone];
+ break;
+ case MFR2_REV_TONE:
+ t->tonesamples = global_dialparams.mfr2_tonelen;
+ t->next = &dtmf_silence;
+ z->mfr2_rev_continuous[td.tone] = *t;
+ z->mfr2_rev_continuous[td.tone].next = &z->mfr2_rev_continuous[td.tone];
+ break;
+ }
+ }
+
+ for (x = 0; x < th.count; x++) {
+ if (samples[x])
+ samples[x]->next = samples[next[x]];
+ }
+
+ if ((res = zt_register_tone_zone(th.zone, z))) {
+ kfree(slab);
+ } else {
+ if ( -1 == default_zone ) {
+ zt_set_default_zone(th.zone);
+ }
+ }
+
+ return res;
+}
+
+void zt_init_tone_state(struct zt_tone_state *ts, struct zt_tone *zt)
+{
+ ts->v1_1 = 0;
+ ts->v2_1 = zt->init_v2_1;
+ ts->v3_1 = zt->init_v3_1;
+ ts->v1_2 = 0;
+ ts->v2_2 = zt->init_v2_2;
+ ts->v3_2 = zt->init_v3_2;
+ ts->modulate = zt->modulate;
+}
+
+struct zt_tone *zt_mf_tone(const struct zt_chan *chan, char digit, int digitmode)
+{
+ unsigned int tone_index;
+
+ if (!chan->curzone) {
+ static int __warnonce = 1;
+ if (__warnonce) {
+ __warnonce = 0;
+ /* The tonezones are loaded by ztcfg based on /etc/zaptel.conf. */
+ printk(KERN_WARNING "zaptel: Cannot get dtmf tone until tone zone is loaded.\n");
+ }
+ return NULL;
+ }
+
+ switch (digitmode) {
+ case DIGIT_MODE_DTMF:
+ switch (digit) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ tone_index = ZT_TONE_DTMF_0 + (digit - '0');
+ break;
+ case '*':
+ tone_index = ZT_TONE_DTMF_s;
+ break;
+ case '#':
+ tone_index = ZT_TONE_DTMF_p;
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ tone_index = ZT_TONE_DTMF_A + (digit - 'A');
+ case 'W':
+ return &tone_pause;
+ default:
+ return NULL;
+ }
+ return &chan->curzone->dtmf[tone_index - ZT_TONE_DTMF_BASE];
+ case DIGIT_MODE_MFR1:
+ switch (digit) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ tone_index = ZT_TONE_MFR1_0 + (digit - '0');
+ break;
+ case '*':
+ tone_index = ZT_TONE_MFR1_KP;
+ break;
+ case '#':
+ tone_index = ZT_TONE_MFR1_ST;
+ break;
+ case 'A':
+ tone_index = ZT_TONE_MFR1_STP;
+ break;
+ case 'B':
+ tone_index = ZT_TONE_MFR1_ST2P;
+ break;
+ case 'C':
+ tone_index = ZT_TONE_MFR1_ST3P;
+ break;
+ case 'W':
+ return &tone_pause;
+ default:
+ return NULL;
+ }
+ return &chan->curzone->mfr1[tone_index - ZT_TONE_MFR1_BASE];
+ case DIGIT_MODE_MFR2_FWD:
+ switch (digit) {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ tone_index = ZT_TONE_MFR2_FWD_1 + (digit - '1');
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ tone_index = ZT_TONE_MFR2_FWD_10 + (digit - 'A');
+ break;
+ case 'W':
+ return &tone_pause;
+ default:
+ return NULL;
+ }
+ return &chan->curzone->mfr2_fwd[tone_index - ZT_TONE_MFR2_FWD_BASE];
+ case DIGIT_MODE_MFR2_REV:
+ switch (digit) {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ tone_index = ZT_TONE_MFR2_REV_1 + (digit - '1');
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ tone_index = ZT_TONE_MFR2_REV_10 + (digit - 'A');
+ break;
+ case 'W':
+ return &tone_pause;
+ default:
+ return NULL;
+ }
+ return &chan->curzone->mfr2_rev[tone_index - ZT_TONE_MFR2_REV_BASE];
+ default:
+ return NULL;
+ }
+}
+
+static void __do_dtmf(struct zt_chan *chan)
+{
+ char c;
+
+ /* Called with chan->lock held */
+ while ((c = chan->txdialbuf[0])) {
+ memmove(chan->txdialbuf, chan->txdialbuf + 1, sizeof(chan->txdialbuf) - 1);
+ switch (c) {
+ case 'T':
+ chan->digitmode = DIGIT_MODE_DTMF;
+ chan->tonep = 0;
+ break;
+ case 'M':
+ chan->digitmode = DIGIT_MODE_MFR1;
+ chan->tonep = 0;
+ break;
+ case 'O':
+ chan->digitmode = DIGIT_MODE_MFR2_FWD;
+ chan->tonep = 0;
+ break;
+ case 'R':
+ chan->digitmode = DIGIT_MODE_MFR2_REV;
+ chan->tonep = 0;
+ break;
+ case 'P':
+ chan->digitmode = DIGIT_MODE_PULSE;
+ chan->tonep = 0;
+ break;
+ default:
+ if ((c != 'W') && (chan->digitmode == DIGIT_MODE_PULSE)) {
+ if ((c >= '0') && (c <= '9') && (chan->txhooksig == ZT_TXSIG_OFFHOOK)) {
+ chan->pdialcount = (c == '0') ? 10 : c - '0';
+ zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_PULSEBREAK,
+ chan->pulsebreaktime);
+ return;
+ }
+ } else {
+ chan->curtone = zt_mf_tone(chan, c, chan->digitmode);
+ chan->tonep = 0;
+ if (chan->curtone) {
+ zt_init_tone_state(&chan->ts, chan->curtone);
+ return;
+ }
+ }
+ }
+ }
+
+ /* Notify userspace process if there is nothing left */
+ chan->dialing = 0;
+ __qevent(chan, ZT_EVENT_DIALCOMPLETE);
+}
+
+static int zt_release(struct inode *inode, struct file *file)
+{
+ int unit = UNIT(file);
+ int res;
+ struct zt_chan *chan;
+
+ if (!unit)
+ return zt_ctl_release(inode, file);
+ if (unit == 253) {
+ return zt_timer_release(inode, file);
+ }
+ if (unit == 250) {
+ res = zt_transcode_fops->release(inode, file);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ if (zt_transcode_fops->owner)
+ __MOD_DEC_USE_COUNT (zt_transcode_fops->owner);
+#else
+ module_put(zt_transcode_fops->owner);
+#endif
+ return res;
+ }
+ if (unit == 254) {
+ chan = file->private_data;
+ if (!chan)
+ return zt_chan_release(inode, file);
+ else
+ return zt_specchan_release(inode, file, chan->channo);
+ }
+ if (unit == 255) {
+ chan = file->private_data;
+ if (chan) {
+ res = zt_specchan_release(inode, file, chan->channo);
+ zt_free_pseudo(chan);
+ } else {
+ printk("Pseudo release and no private data??\n");
+ res = 0;
+ }
+ return res;
+ }
+ return zt_specchan_release(inode, file, unit);
+}
+
+#if 0
+static int zt_release(struct inode *inode, struct file *file)
+{
+ /* Lock the big zap lock when handling a release */
+ unsigned long flags;
+ int res;
+ spin_lock_irqsave(&bigzaplock, flags);
+ res = __zt_release(inode, file);
+ spin_unlock_irqrestore(&bigzaplock, flags);
+ return res;
+}
+#endif
+
+
+void zt_alarm_channel(struct zt_chan *chan, int alarms)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->chan_alarms != alarms) {
+ chan->chan_alarms = alarms;
+ zt_qevent_nolock(chan, alarms ? ZT_EVENT_ALARM : ZT_EVENT_NOALARM);
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+void zt_alarm_notify(struct zt_span *span)
+{
+ int x;
+
+ span->alarms &= ~ZT_ALARM_LOOPBACK;
+ /* Determine maint status */
+ if (span->maintstat || span->mainttimer)
+ span->alarms |= ZT_ALARM_LOOPBACK;
+ /* DON'T CHANGE THIS AGAIN. THIS WAS DONE FOR A REASON.
+ The expression (a != b) does *NOT* do the same thing
+ as ((!a) != (!b)) */
+ /* if change in general state */
+ if ((!span->alarms) != (!span->lastalarms)) {
+ span->lastalarms = span->alarms;
+ for (x = 0; x < span->channels; x++)
+ zt_alarm_channel(&span->chans[x], span->alarms);
+ /* Switch to other master if current master in alarm */
+ for (x=1; x<maxspans; x++) {
+ if (spans[x] && !spans[x]->alarms && (spans[x]->flags & ZT_FLAG_RUNNING)) {
+ if(master != spans[x])
+ printk("Zaptel: Master changed to %s\n", spans[x]->name);
+ master = spans[x];
+ break;
+ }
+ }
+ }
+}
+
+#define VALID_SPAN(j) do { \
+ if ((j >= ZT_MAX_SPANS) || (j < 1)) \
+ return -EINVAL; \
+ if (!spans[j]) \
+ return -ENXIO; \
+} while(0)
+
+#define CHECK_VALID_SPAN(j) do { \
+ /* Start a given span */ \
+ if (get_user(j, (int *)data)) \
+ return -EFAULT; \
+ VALID_SPAN(j); \
+} while(0)
+
+#define VALID_CHANNEL(j) do { \
+ if ((j >= ZT_MAX_CHANNELS) || (j < 1)) \
+ return -EINVAL; \
+ if (!chans[j]) \
+ return -ENXIO; \
+} while(0)
+
+static int zt_timer_ioctl(struct inode *node, struct file *file, unsigned int cmd, unsigned long data, struct zt_timer *timer)
+{
+ int j;
+ unsigned long flags;
+ switch(cmd) {
+ case ZT_TIMERCONFIG:
+ get_user(j, (int *)data);
+ if (j < 0)
+ j = 0;
+ spin_lock_irqsave(&zaptimerlock, flags);
+ timer->ms = timer->pos = j;
+ spin_unlock_irqrestore(&zaptimerlock, flags);
+ break;
+ case ZT_TIMERACK:
+ get_user(j, (int *)data);
+ spin_lock_irqsave(&zaptimerlock, flags);
+ if ((j < 1) || (j > timer->tripped))
+ j = timer->tripped;
+ timer->tripped -= j;
+ spin_unlock_irqrestore(&zaptimerlock, flags);
+ break;
+ case ZT_GETEVENT: /* Get event on queue */
+ j = ZT_EVENT_NONE;
+ spin_lock_irqsave(&zaptimerlock, flags);
+ /* set up for no event */
+ if (timer->tripped)
+ j = ZT_EVENT_TIMER_EXPIRED;
+ if (timer->ping)
+ j = ZT_EVENT_TIMER_PING;
+ spin_unlock_irqrestore(&zaptimerlock, flags);
+ put_user(j,(int *)data);
+ break;
+ case ZT_TIMERPING:
+ spin_lock_irqsave(&zaptimerlock, flags);
+ timer->ping = 1;
+ wake_up_interruptible(&timer->sel);
+ spin_unlock_irqrestore(&zaptimerlock, flags);
+ break;
+ case ZT_TIMERPONG:
+ spin_lock_irqsave(&zaptimerlock, flags);
+ timer->ping = 0;
+ spin_unlock_irqrestore(&zaptimerlock, flags);
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int cmd, unsigned long data, int unit)
+{
+ union {
+ struct zt_gains gain;
+ struct zt_spaninfo spaninfo;
+ struct zt_params param;
+ } stack;
+ struct zt_chan *chan;
+ unsigned long flags;
+ unsigned char *txgain, *rxgain;
+ struct zt_chan *mychan;
+ int i,j;
+ int return_master = 0;
+ size_t size_to_copy;
+
+ switch(cmd) {
+ /* get channel parameters */
+ case ZT_GET_PARAMS_V1:
+ case ZT_GET_PARAMS:
+ size_to_copy = (cmd == ZT_GET_PARAMS_V1) ? sizeof(struct zt_params_v1) :
+ sizeof(struct zt_params);
+ if (copy_from_user(&stack.param, (struct zt_params *) data, size_to_copy))
+ return -EFAULT;
+
+ /* check to see if the caller wants to receive our master channel number */
+ if (stack.param.channo & ZT_GET_PARAMS_RETURN_MASTER) {
+ return_master = 1;
+ stack.param.channo &= ~ZT_GET_PARAMS_RETURN_MASTER;
+ }
+
+ /* Pick the right channo's */
+ if (!stack.param.channo || unit) {
+ stack.param.channo = unit;
+ }
+ /* Check validity of channel */
+ VALID_CHANNEL(stack.param.channo);
+ chan = chans[stack.param.channo];
+
+ /* point to relevant structure */
+ stack.param.sigtype = chan->sig; /* get signalling type */
+ /* return non-zero if rx not in idle state */
+ if (chan->span) {
+ j = zt_q_sig(chan);
+ if (j >= 0) { /* if returned with success */
+ stack.param.rxisoffhook = ((chan->rxsig & (j >> 8)) != (j & 0xff));
+ } else {
+ stack.param.rxisoffhook = ((chan->rxhooksig != ZT_RXSIG_ONHOOK) &&
+ (chan->rxhooksig != ZT_RXSIG_INITIAL));
+ }
+ } else if ((chan->txstate == ZT_TXSTATE_KEWL) || (chan->txstate == ZT_TXSTATE_AFTERKEWL))
+ stack.param.rxisoffhook = 1;
+ else
+ stack.param.rxisoffhook = 0;
+ if (chan->span && chan->span->rbsbits && !(chan->sig & ZT_SIG_CLEAR)) {
+ stack.param.rxbits = chan->rxsig;
+ stack.param.txbits = chan->txsig;
+ stack.param.idlebits = chan->idlebits;
+ } else {
+ stack.param.rxbits = -1;
+ stack.param.txbits = -1;
+ stack.param.idlebits = 0;
+ }
+ if (chan->span && (chan->span->rbsbits || chan->span->hooksig) &&
+ !(chan->sig & ZT_SIG_CLEAR)) {
+ stack.param.rxhooksig = chan->rxhooksig;
+ stack.param.txhooksig = chan->txhooksig;
+ } else {
+ stack.param.rxhooksig = -1;
+ stack.param.txhooksig = -1;
+ }
+ stack.param.prewinktime = chan->prewinktime;
+ stack.param.preflashtime = chan->preflashtime;
+ stack.param.winktime = chan->winktime;
+ stack.param.flashtime = chan->flashtime;
+ stack.param.starttime = chan->starttime;
+ stack.param.rxwinktime = chan->rxwinktime;
+ stack.param.rxflashtime = chan->rxflashtime;
+ stack.param.debouncetime = chan->debouncetime;
+ stack.param.channo = chan->channo;
+ stack.param.chan_alarms = chan->chan_alarms;
+
+ /* if requested, put the master channel number in the top 16 bits of the result */
+ if (return_master)
+ stack.param.channo |= chan->master->channo << 16;
+
+ stack.param.pulsemaketime = chan->pulsemaketime;
+ stack.param.pulsebreaktime = chan->pulsebreaktime;
+ stack.param.pulseaftertime = chan->pulseaftertime;
+ if (chan->span) stack.param.spanno = chan->span->spanno;
+ else stack.param.spanno = 0;
+ zap_copy_string(stack.param.name, chan->name, sizeof(stack.param.name));
+ stack.param.chanpos = chan->chanpos;
+ stack.param.sigcap = chan->sigcap;
+ /* Return current law */
+ if (chan->xlaw == __zt_alaw)
+ stack.param.curlaw = ZT_LAW_ALAW;
+ else
+ stack.param.curlaw = ZT_LAW_MULAW;
+
+ if (copy_to_user((struct zt_params *) data, &stack.param, size_to_copy))
+ return -EFAULT;
+
+ break;
+ /* set channel parameters */
+ case ZT_SET_PARAMS_V1:
+ case ZT_SET_PARAMS:
+ /* The difference between zt_params and zt_params_v1 is just the
+ * last field, which is read-only anyway. Thus we just read the
+ * size of the older struct.
+ */
+ if (copy_from_user(&stack.param, (struct zt_params *) data, sizeof(struct zt_params_v1)))
+ return -EFAULT;
+
+ stack.param.chan_alarms = 0; /* be explicit about the above */
+
+ /* Pick the right channo's */
+ if (!stack.param.channo || unit) {
+ stack.param.channo = unit;
+ }
+ /* Check validity of channel */
+ VALID_CHANNEL(stack.param.channo);
+ chan = chans[stack.param.channo];
+ /* point to relevant structure */
+ /* NOTE: sigtype is *not* included in this */
+ /* get timing stack.paramters */
+ chan->prewinktime = stack.param.prewinktime;
+ chan->preflashtime = stack.param.preflashtime;
+ chan->winktime = stack.param.winktime;
+ chan->flashtime = stack.param.flashtime;
+ chan->starttime = stack.param.starttime;
+ /* Update ringtime if not using a tone zone */
+ if (!chan->curzone)
+ chan->ringcadence[0] = chan->starttime;
+ chan->rxwinktime = stack.param.rxwinktime;
+ chan->rxflashtime = stack.param.rxflashtime;
+ chan->debouncetime = stack.param.debouncetime;
+ chan->pulsemaketime = stack.param.pulsemaketime;
+ chan->pulsebreaktime = stack.param.pulsebreaktime;
+ chan->pulseaftertime = stack.param.pulseaftertime;
+ break;
+ case ZT_GETGAINS: /* get gain stuff */
+ if (copy_from_user(&stack.gain,(struct zt_gains *) data,sizeof(stack.gain)))
+ return -EFAULT;
+ i = stack.gain.chan; /* get channel no */
+ /* if zero, use current channel no */
+ if (!i) i = unit;
+ /* make sure channel number makes sense */
+ if ((i < 0) || (i > ZT_MAX_CHANNELS) || !chans[i]) return(-EINVAL);
+
+ if (!(chans[i]->flags & ZT_FLAG_AUDIO)) return (-EINVAL);
+ stack.gain.chan = i; /* put the span # in here */
+ for (j=0;j<256;j++) {
+ stack.gain.txgain[j] = chans[i]->txgain[j];
+ stack.gain.rxgain[j] = chans[i]->rxgain[j];
+ }
+ if (copy_to_user((struct zt_gains *) data,&stack.gain,sizeof(stack.gain)))
+ return -EFAULT;
+ break;
+ case ZT_SETGAINS: /* set gain stuff */
+ if (copy_from_user(&stack.gain,(struct zt_gains *) data,sizeof(stack.gain)))
+ return -EFAULT;
+ i = stack.gain.chan; /* get channel no */
+ /* if zero, use current channel no */
+ if (!i) i = unit;
+ /* make sure channel number makes sense */
+ if ((i < 0) || (i > ZT_MAX_CHANNELS) || !chans[i]) return(-EINVAL);
+ if (!(chans[i]->flags & ZT_FLAG_AUDIO)) return (-EINVAL);
+
+ rxgain = kmalloc(512, GFP_KERNEL);
+ if (!rxgain)
+ return -ENOMEM;
+
+ stack.gain.chan = i; /* put the span # in here */
+ txgain = rxgain + 256;
+
+ for (j=0;j<256;j++) {
+ rxgain[j] = stack.gain.rxgain[j];
+ txgain[j] = stack.gain.txgain[j];
+ }
+
+ if (!memcmp(rxgain, defgain, 256) &&
+ !memcmp(txgain, defgain, 256)) {
+ if (rxgain)
+ kfree(rxgain);
+ spin_lock_irqsave(&chans[i]->lock, flags);
+ if (chans[i]->gainalloc)
+ kfree(chans[i]->rxgain);
+ chans[i]->gainalloc = 0;
+ chans[i]->rxgain = defgain;
+ chans[i]->txgain = defgain;
+ spin_unlock_irqrestore(&chans[i]->lock, flags);
+ } else {
+ /* This is a custom gain setting */
+ spin_lock_irqsave(&chans[i]->lock, flags);
+ if (chans[i]->gainalloc)
+ kfree(chans[i]->rxgain);
+ chans[i]->gainalloc = 1;
+ chans[i]->rxgain = rxgain;
+ chans[i]->txgain = txgain;
+ spin_unlock_irqrestore(&chans[i]->lock, flags);
+ }
+ if (copy_to_user((struct zt_gains *) data,&stack.gain,sizeof(stack.gain)))
+ return -EFAULT;
+ break;
+ case ZT_SPANSTAT_V1:
+ case ZT_SPANSTAT_V2:
+ case ZT_SPANSTAT:
+ size_to_copy = (cmd == ZT_SPANSTAT_V1) ? sizeof(struct zt_spaninfo_v1) :
+ (cmd == ZT_SPANSTAT_V2) ? sizeof(struct zt_spaninfo_v2) :
+ sizeof(struct zt_spaninfo);
+ if (copy_from_user(&stack.spaninfo, (struct zt_spaninfo *) data, size_to_copy))
+ return -EFAULT;
+ i = stack.spaninfo.spanno; /* get specified span number */
+ if ((i < 0) || (i >= maxspans)) return(-EINVAL); /* if bad span no */
+ if (i == 0) {
+ /* if to figure it out for this chan */
+ if (!chans[unit])
+ return -EINVAL;
+ i = chans[unit]->span->spanno;
+ }
+ if (!spans[i])
+ return -EINVAL;
+ stack.spaninfo.spanno = i; /* put the span # in here */
+ stack.spaninfo.totalspans = 0;
+ if (maxspans) stack.spaninfo.totalspans = maxspans - 1; /* put total number of spans here */
+ zap_copy_string(stack.spaninfo.desc, spans[i]->desc, sizeof(stack.spaninfo.desc));
+ zap_copy_string(stack.spaninfo.name, spans[i]->name, sizeof(stack.spaninfo.name));
+ stack.spaninfo.alarms = spans[i]->alarms; /* get alarm status */
+ stack.spaninfo.bpvcount = spans[i]->bpvcount; /* get BPV count */
+ stack.spaninfo.rxlevel = spans[i]->rxlevel; /* get rx level */
+ stack.spaninfo.txlevel = spans[i]->txlevel; /* get tx level */
+ stack.spaninfo.crc4count = spans[i]->crc4count; /* get CRC4 error count */
+ stack.spaninfo.ebitcount = spans[i]->ebitcount; /* get E-bit error count */
+ stack.spaninfo.fascount = spans[i]->fascount; /* get FAS error count */
+ stack.spaninfo.irqmisses = spans[i]->irqmisses; /* get IRQ miss count */
+ stack.spaninfo.syncsrc = spans[i]->syncsrc; /* get active sync source */
+ stack.spaninfo.totalchans = spans[i]->channels;
+ stack.spaninfo.numchans = 0;
+ for (j = 0; j < spans[i]->channels; j++) {
+ if (spans[i]->chans[j].sig)
+ stack.spaninfo.numchans++;
+ }
+ /* version 2 fields */
+ stack.spaninfo.lbo = spans[i]->lbo;
+ stack.spaninfo.lineconfig = spans[i]->lineconfig;
+ /* version 3 fields */
+ stack.spaninfo.irq = spans[i]->irq;
+ stack.spaninfo.linecompat = spans[i]->linecompat;
+ zap_copy_string(stack.spaninfo.lboname, zt_lboname(spans[i]->lbo), sizeof(stack.spaninfo.lboname));
+ if (spans[i]->manufacturer)
+ zap_copy_string(stack.spaninfo.manufacturer, spans[i]->manufacturer,
+ sizeof(stack.spaninfo.manufacturer));
+ if (spans[i]->devicetype)
+ zap_copy_string(stack.spaninfo.devicetype, spans[i]->devicetype, sizeof(stack.spaninfo.devicetype));
+ zap_copy_string(stack.spaninfo.location, spans[i]->location, sizeof(stack.spaninfo.location));
+ if (spans[i]->spantype)
+ zap_copy_string(stack.spaninfo.spantype, spans[i]->spantype, sizeof(stack.spaninfo.spantype));
+
+ if (copy_to_user((struct zt_spaninfo *) data, &stack.spaninfo, size_to_copy))
+ return -EFAULT;
+ break;
+ case ZT_CHANDIAG:
+ get_user(j, (int *)data); /* get channel number from user */
+ /* make sure its a valid channel number */
+ if ((j < 1) || (j >= maxchans))
+ return -EINVAL;
+ /* if channel not mapped, not there */
+ if (!chans[j])
+ return -EINVAL;
+
+ if (!(mychan = kmalloc(sizeof(*mychan), GFP_KERNEL)))
+ return -ENOMEM;
+
+ /* lock channel */
+ spin_lock_irqsave(&chans[j]->lock, flags);
+ /* make static copy of channel */
+ memcpy(mychan, chans[j], sizeof(*mychan));
+ /* release it. */
+ spin_unlock_irqrestore(&chans[j]->lock, flags);
+
+ printk(KERN_INFO "Dump of Zaptel Channel %d (%s,%d,%d):\n\n",j,
+ mychan->name,mychan->channo,mychan->chanpos);
+ printk(KERN_INFO "flags: %x hex, writechunk: %08lx, readchunk: %08lx\n",
+ (unsigned int) mychan->flags, (long) mychan->writechunk, (long) mychan->readchunk);
+ printk(KERN_INFO "rxgain: %08lx, txgain: %08lx, gainalloc: %d\n",
+ (long) mychan->rxgain, (long)mychan->txgain, mychan->gainalloc);
+ printk(KERN_INFO "span: %08lx, sig: %x hex, sigcap: %x hex\n",
+ (long)mychan->span, mychan->sig, mychan->sigcap);
+ printk(KERN_INFO "inreadbuf: %d, outreadbuf: %d, inwritebuf: %d, outwritebuf: %d\n",
+ mychan->inreadbuf, mychan->outreadbuf, mychan->inwritebuf, mychan->outwritebuf);
+ printk(KERN_INFO "blocksize: %d, numbufs: %d, txbufpolicy: %d, txbufpolicy: %d\n",
+ mychan->blocksize, mychan->numbufs, mychan->txbufpolicy, mychan->rxbufpolicy);
+ printk(KERN_INFO "txdisable: %d, rxdisable: %d, iomask: %d\n",
+ mychan->txdisable, mychan->rxdisable, mychan->iomask);
+ printk(KERN_INFO "curzone: %08lx, tonezone: %d, curtone: %08lx, tonep: %d\n",
+ (long) mychan->curzone, mychan->tonezone, (long) mychan->curtone, mychan->tonep);
+ printk(KERN_INFO "digitmode: %d, txdialbuf: %s, dialing: %d, aftdialtimer: %d, cadpos. %d\n",
+ mychan->digitmode, mychan->txdialbuf, mychan->dialing,
+ mychan->afterdialingtimer, mychan->cadencepos);
+ printk(KERN_INFO "confna: %d, confn: %d, confmode: %d, confmute: %d\n",
+ mychan->confna, mychan->_confn, mychan->confmode, mychan->confmute);
+ printk(KERN_INFO "ec: %08lx, echocancel: %d, deflaw: %d, xlaw: %08lx\n",
+ (long) mychan->ec, mychan->echocancel, mychan->deflaw, (long) mychan->xlaw);
+ printk(KERN_INFO "echostate: %02x, echotimer: %d, echolastupdate: %d\n",
+ (int) mychan->echostate, mychan->echotimer, mychan->echolastupdate);
+ printk(KERN_INFO "itimer: %d, otimer: %d, ringdebtimer: %d\n\n",
+ mychan->itimer, mychan->otimer, mychan->ringdebtimer);
+#if 0
+ if (mychan->ec) {
+ int x;
+ /* Dump the echo canceller parameters */
+ for (x=0;x<mychan->ec->taps;x++) {
+ printk(KERN_INFO "tap %d: %d\n", x, mychan->ec->fir_taps[x]);
+ }
+ }
+#endif
+ kfree(mychan);
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int (*zt_dynamic_ioctl)(unsigned int cmd, unsigned long data);
+
+void zt_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data))
+{
+ zt_dynamic_ioctl = func;
+}
+
+static void recalc_slaves(struct zt_chan *chan)
+{
+ int x;
+ struct zt_chan *last = chan;
+
+ /* Makes no sense if you don't have a span */
+ if (!chan->span)
+ return;
+
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Recalculating slaves on %s\n", chan->name);
+#endif
+
+ /* Link all slaves appropriately */
+ for (x=chan->chanpos;x<chan->span->channels;x++)
+ if (chan->span->chans[x].master == chan) {
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Channel %s, slave to %s, last is %s, its next will be %d\n",
+ chan->span->chans[x].name, chan->name, last->name, x);
+#endif
+ last->nextslave = x;
+ last = &chan->span->chans[x];
+ }
+ /* Terminate list */
+ last->nextslave = 0;
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Done Recalculating slaves on %s (last is %s)\n", chan->name, last->name);
+#endif
+}
+
+static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
+{
+ /* I/O CTL's for control interface */
+ int i,j;
+ int sigcap;
+ int res = 0;
+ int x,y;
+ struct zt_chan *newmaster;
+ unsigned long flags;
+ int rv;
+ switch(cmd) {
+ case ZT_INDIRECT:
+ {
+ struct zt_indirect_data ind;
+
+ if (copy_from_user(&ind, (struct zt_indirect_data *)data, sizeof(ind)))
+ return -EFAULT;
+ VALID_CHANNEL(ind.chan);
+ return zt_chan_ioctl(inode, file, ind.op, (unsigned long) ind.data, ind.chan);
+ }
+ case ZT_SPANCONFIG:
+ {
+ struct zt_lineconfig lc;
+
+ if (copy_from_user(&lc, (struct zt_lineconfig *)data, sizeof(lc)))
+ return -EFAULT;
+ VALID_SPAN(lc.span);
+ if ((lc.lineconfig & 0x07f0 & spans[lc.span]->linecompat) != (lc.lineconfig & 0x07f0))
+ return -EINVAL;
+ if (spans[lc.span]->spanconfig) {
+ spans[lc.span]->lineconfig = lc.lineconfig;
+ spans[lc.span]->lbo = lc.lbo;
+ spans[lc.span]->txlevel = lc.lbo;
+ spans[lc.span]->rxlevel = 0;
+
+ return spans[lc.span]->spanconfig(spans[lc.span], &lc);
+ }
+ return 0;
+ }
+ case ZT_STARTUP:
+ CHECK_VALID_SPAN(j);
+ if (spans[j]->flags & ZT_FLAG_RUNNING)
+ return 0;
+ if (spans[j]->startup)
+ res = spans[j]->startup(spans[j]);
+ if (!res) {
+ /* Mark as running and hangup any channels */
+ spans[j]->flags |= ZT_FLAG_RUNNING;
+ for (x=0;x<spans[j]->channels;x++) {
+ y = zt_q_sig(&spans[j]->chans[x]) & 0xff;
+ if (y >= 0) spans[j]->chans[x].rxsig = (unsigned char)y;
+ spin_lock_irqsave(&spans[j]->chans[x].lock, flags);
+ zt_hangup(&spans[j]->chans[x]);
+ spin_unlock_irqrestore(&spans[j]->chans[x].lock, flags);
+ spans[j]->chans[x].rxhooksig = ZT_RXSIG_INITIAL;
+ }
+ }
+ return 0;
+ case ZT_SHUTDOWN:
+ CHECK_VALID_SPAN(j);
+ if (spans[j]->shutdown)
+ res = spans[j]->shutdown(spans[j]);
+ spans[j]->flags &= ~ZT_FLAG_RUNNING;
+ return 0;
+ case ZT_CHANCONFIG:
+ {
+ struct zt_chanconfig ch;
+
+ if (copy_from_user(&ch, (struct zt_chanconfig *)data, sizeof(ch)))
+ return -EFAULT;
+ VALID_CHANNEL(ch.chan);
+ if (ch.sigtype == ZT_SIG_SLAVE) {
+ /* We have to use the master's sigtype */
+ if ((ch.master < 1) || (ch.master >= ZT_MAX_CHANNELS))
+ return -EINVAL;
+ if (!chans[ch.master])
+ return -EINVAL;
+ ch.sigtype = chans[ch.master]->sig;
+ newmaster = chans[ch.master];
+ } else if ((ch.sigtype & __ZT_SIG_DACS) == __ZT_SIG_DACS) {
+ newmaster = chans[ch.chan];
+ if ((ch.idlebits < 1) || (ch.idlebits >= ZT_MAX_CHANNELS))
+ return -EINVAL;
+ if (!chans[ch.idlebits])
+ return -EINVAL;
+ } else {
+ newmaster = chans[ch.chan];
+ }
+ spin_lock_irqsave(&chans[ch.chan]->lock, flags);
+#ifdef CONFIG_ZAPATA_NET
+ if (chans[ch.chan]->flags & ZT_FLAG_NETDEV) {
+ if (ztchan_to_dev(chans[ch.chan])->flags & IFF_UP) {
+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
+ printk(KERN_WARNING "Can't switch HDLC net mode on channel %s, since current interface is up\n", chans[ch.chan]->name);
+ return -EBUSY;
+ }
+#ifdef LINUX26
+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
+ unregister_hdlc_device(chans[ch.chan]->hdlcnetdev->netdev);
+ spin_lock_irqsave(&chans[ch.chan]->lock, flags);
+ free_netdev(chans[ch.chan]->hdlcnetdev->netdev);
+#else
+ unregister_hdlc_device(&chans[ch.chan]->hdlcnetdev->netdev);
+#endif
+ kfree(chans[ch.chan]->hdlcnetdev);
+ chans[ch.chan]->hdlcnetdev = NULL;
+ chans[ch.chan]->flags &= ~ZT_FLAG_NETDEV;
+ }
+#else
+ if (ch.sigtype == ZT_SIG_HDLCNET) {
+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
+ printk(KERN_WARNING "Zaptel networking not supported by this build.\n");
+ return -ENOSYS;
+ }
+#endif
+ sigcap = chans[ch.chan]->sigcap;
+ /* If they support clear channel, then they support the HDLC and such through
+ us. */
+ if (sigcap & ZT_SIG_CLEAR)
+ sigcap |= (ZT_SIG_HDLCRAW | ZT_SIG_HDLCFCS | ZT_SIG_HDLCNET | ZT_SIG_DACS);
+
+ if ((sigcap & ch.sigtype) != ch.sigtype)
+ res = -EINVAL;
+
+ if (!res && chans[ch.chan]->span->chanconfig)
+ res = chans[ch.chan]->span->chanconfig(chans[ch.chan], ch.sigtype);
+ if (chans[ch.chan]->master) {
+ /* Clear the master channel */
+ recalc_slaves(chans[ch.chan]->master);
+ chans[ch.chan]->nextslave = 0;
+ }
+ if (!res) {
+ chans[ch.chan]->sig = ch.sigtype;
+ if (chans[ch.chan]->sig == ZT_SIG_CAS)
+ chans[ch.chan]->idlebits = ch.idlebits;
+ else
+ chans[ch.chan]->idlebits = 0;
+ if ((ch.sigtype & ZT_SIG_CLEAR) == ZT_SIG_CLEAR) {
+ /* Set clear channel flag if appropriate */
+ chans[ch.chan]->flags &= ~ZT_FLAG_AUDIO;
+ chans[ch.chan]->flags |= ZT_FLAG_CLEAR;
+ } else {
+ /* Set audio flag and not clear channel otherwise */
+ chans[ch.chan]->flags |= ZT_FLAG_AUDIO;
+ chans[ch.chan]->flags &= ~ZT_FLAG_CLEAR;
+ }
+ if ((ch.sigtype & ZT_SIG_HDLCRAW) == ZT_SIG_HDLCRAW) {
+ /* Set the HDLC flag */
+ chans[ch.chan]->flags |= ZT_FLAG_HDLC;
+ } else {
+ /* Clear the HDLC flag */
+ chans[ch.chan]->flags &= ~ZT_FLAG_HDLC;
+ }
+ if ((ch.sigtype & ZT_SIG_HDLCFCS) == ZT_SIG_HDLCFCS) {
+ /* Set FCS to be calculated if appropriate */
+ chans[ch.chan]->flags |= ZT_FLAG_FCS;
+ } else {
+ /* Clear FCS flag */
+ chans[ch.chan]->flags &= ~ZT_FLAG_FCS;
+ }
+ if ((ch.sigtype & __ZT_SIG_DACS) == __ZT_SIG_DACS) {
+ /* Setup conference properly */
+ chans[ch.chan]->confmode = ZT_CONF_DIGITALMON;
+ chans[ch.chan]->confna = ch.idlebits;
+ if (chans[ch.chan]->span &&
+ chans[ch.chan]->span->dacs &&
+ chans[ch.idlebits] &&
+ chans[ch.chan]->span &&
+ (chans[ch.chan]->span->dacs == chans[ch.idlebits]->span->dacs))
+ chans[ch.chan]->span->dacs(chans[ch.chan], chans[ch.idlebits]);
+ } else if (chans[ch.chan]->span && chans[ch.chan]->span->dacs)
+ chans[ch.chan]->span->dacs(chans[ch.chan], NULL);
+ chans[ch.chan]->master = newmaster;
+ /* Note new slave if we are not our own master */
+ if (newmaster != chans[ch.chan]) {
+ recalc_slaves(chans[ch.chan]->master);
+ }
+ if ((ch.sigtype & ZT_SIG_HARDHDLC) == ZT_SIG_HARDHDLC) {
+ chans[ch.chan]->flags &= ~ZT_FLAG_FCS;
+ chans[ch.chan]->flags &= ~ZT_FLAG_HDLC;
+ chans[ch.chan]->flags |= ZT_FLAG_NOSTDTXRX;
+ } else
+ chans[ch.chan]->flags &= ~ZT_FLAG_NOSTDTXRX;
+
+ if ((ch.sigtype & ZT_SIG_MTP2) == ZT_SIG_MTP2)
+ chans[ch.chan]->flags |= ZT_FLAG_MTP2;
+ else
+ chans[ch.chan]->flags &= ~ZT_FLAG_MTP2;
+ }
+#ifdef CONFIG_ZAPATA_NET
+ if (!res &&
+ (newmaster == chans[ch.chan]) &&
+ (chans[ch.chan]->sig == ZT_SIG_HDLCNET)) {
+ chans[ch.chan]->hdlcnetdev = zt_hdlc_alloc();
+ if (chans[ch.chan]->hdlcnetdev) {
+/* struct hdlc_device *hdlc = chans[ch.chan]->hdlcnetdev;
+ struct net_device *d = hdlc_to_dev(hdlc); mmm...get it right later --byg */
+#ifdef LINUX26
+ chans[ch.chan]->hdlcnetdev->netdev = alloc_hdlcdev(chans[ch.chan]->hdlcnetdev);
+ if (chans[ch.chan]->hdlcnetdev->netdev) {
+ chans[ch.chan]->hdlcnetdev->chan = chans[ch.chan];
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
+ SET_MODULE_OWNER(chans[ch.chan]->hdlcnetdev->netdev);
+#endif
+ chans[ch.chan]->hdlcnetdev->netdev->irq = chans[ch.chan]->span->irq;
+ chans[ch.chan]->hdlcnetdev->netdev->tx_queue_len = 50;
+ chans[ch.chan]->hdlcnetdev->netdev->do_ioctl = zt_net_ioctl;
+ chans[ch.chan]->hdlcnetdev->netdev->open = zt_net_open;
+ chans[ch.chan]->hdlcnetdev->netdev->stop = zt_net_stop;
+ dev_to_hdlc(chans[ch.chan]->hdlcnetdev->netdev)->attach = zt_net_attach;
+ dev_to_hdlc(chans[ch.chan]->hdlcnetdev->netdev)->xmit = zt_xmit;
+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
+ /* Briefly restore interrupts while we register the device */
+ res = zt_register_hdlc_device(chans[ch.chan]->hdlcnetdev->netdev, ch.netdev_name);
+ spin_lock_irqsave(&chans[ch.chan]->lock, flags);
+ } else {
+ printk("Unable to allocate hdlc: *shrug*\n");
+ res = -1;
+ }
+#else /* LINUX26 */
+ chans[ch.chan]->hdlcnetdev->chan = chans[ch.chan];
+#ifndef HDLC_MAINTAINERS_ARE_MORE_STUPID_THAN_I_THOUGHT
+ chans[ch.chan]->hdlcnetdev->netdev.ioctl = zt_net_ioctl;
+#endif
+ chans[ch.chan]->hdlcnetdev->netdev.netdev.do_ioctl = zt_net_ioctl;
+#ifdef NEW_HDLC_INTERFACE
+ chans[ch.chan]->hdlcnetdev->netdev.netdev.open = zt_net_open;
+ chans[ch.chan]->hdlcnetdev->netdev.netdev.stop = zt_net_stop;
+ chans[ch.chan]->hdlcnetdev->netdev.xmit = zt_xmit;
+ chans[ch.chan]->hdlcnetdev->netdev.attach = zt_net_attach;
+#else
+ chans[ch.chan]->hdlcnetdev->netdev.open = zt_net_open;
+ chans[ch.chan]->hdlcnetdev->netdev.close = zt_net_close;
+ chans[ch.chan]->hdlcnetdev->netdev.set_mode = NULL;
+ chans[ch.chan]->hdlcnetdev->netdev.xmit = zt_xmit;
+#endif /* NEW_HDLC_INTERFACE */
+ chans[ch.chan]->hdlcnetdev->netdev.netdev.irq = chans[ch.chan]->span->irq;
+ chans[ch.chan]->hdlcnetdev->netdev.netdev.tx_queue_len = 50;
+ res = register_hdlc_device(&chans[ch.chan]->hdlcnetdev->netdev);
+#endif /* LINUX26 */
+ if (!res)
+ chans[ch.chan]->flags |= ZT_FLAG_NETDEV;
+ } else {
+ printk("Unable to allocate netdev: out of memory\n");
+ res = -1;
+ }
+ }
+#endif
+ if ((chans[ch.chan]->sig == ZT_SIG_HDLCNET) &&
+ (chans[ch.chan] == newmaster) &&
+ !(chans[ch.chan]->flags & ZT_FLAG_NETDEV))
+ printk("Unable to register HDLC device for channel %s\n", chans[ch.chan]->name);
+ if (!res) {
+ /* Setup default law */
+ chans[ch.chan]->deflaw = ch.deflaw;
+ /* Copy back any modified settings */
+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
+ if (copy_to_user((struct zt_chanconfig *)data, &ch, sizeof(ch)))
+ return -EFAULT;
+ spin_lock_irqsave(&chans[ch.chan]->lock, flags);
+ /* And hangup */
+ zt_hangup(chans[ch.chan]);
+ y = zt_q_sig(chans[ch.chan]) & 0xff;
+ if (y >= 0) chans[ch.chan]->rxsig = (unsigned char)y;
+ chans[ch.chan]->rxhooksig = ZT_RXSIG_INITIAL;
+ }
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Configured channel %s, flags %04x, sig %04x\n", chans[ch.chan]->name, chans[ch.chan]->flags, chans[ch.chan]->sig);
+#endif
+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
+ return res;
+ }
+ case ZT_SFCONFIG:
+ {
+ struct zt_sfconfig sf;
+
+ if (copy_from_user(&sf, (struct zt_chanconfig *)data, sizeof(sf)))
+ return -EFAULT;
+ VALID_CHANNEL(sf.chan);
+ if (chans[sf.chan]->sig != ZT_SIG_SF) return -EINVAL;
+ spin_lock_irqsave(&chans[sf.chan]->lock, flags);
+ chans[sf.chan]->rxp1 = sf.rxp1;
+ chans[sf.chan]->rxp2 = sf.rxp2;
+ chans[sf.chan]->rxp3 = sf.rxp3;
+ chans[sf.chan]->txtone = sf.txtone;
+ chans[sf.chan]->tx_v2 = sf.tx_v2;
+ chans[sf.chan]->tx_v3 = sf.tx_v3;
+ chans[sf.chan]->toneflags = sf.toneflag;
+ if (sf.txtone) /* if set to make tone for tx */
+ {
+ if ((chans[sf.chan]->txhooksig && !(sf.toneflag & ZT_REVERSE_TXTONE)) ||
+ ((!chans[sf.chan]->txhooksig) && (sf.toneflag & ZT_REVERSE_TXTONE)))
+ {
+ set_txtone(chans[sf.chan],sf.txtone,sf.tx_v2,sf.tx_v3);
+ }
+ else
+ {
+ set_txtone(chans[sf.chan],0,0,0);
+ }
+ }
+ spin_unlock_irqrestore(&chans[sf.chan]->lock, flags);
+ return res;
+ }
+ case ZT_DEFAULTZONE:
+ if (get_user(j,(int *)data))
+ return -EFAULT;
+ return zt_set_default_zone(j);
+ case ZT_LOADZONE:
+ return ioctl_load_zone(data);
+ case ZT_FREEZONE:
+ get_user(j, (int *) data);
+ return free_tone_zone(j);
+ case ZT_SET_DIALPARAMS:
+ {
+ struct zt_dialparams tdp;
+
+ if (copy_from_user(&tdp, (struct zt_dialparams *) data, sizeof(tdp)))
+ return -EFAULT;
+
+ if ((tdp.dtmf_tonelen <= 4000) || (tdp.dtmf_tonelen >= 10)) {
+ global_dialparams.dtmf_tonelen = tdp.dtmf_tonelen;
+ }
+ if ((tdp.mfv1_tonelen <= 4000) || (tdp.mfv1_tonelen >= 10)) {
+ global_dialparams.mfv1_tonelen = tdp.mfv1_tonelen;
+ }
+ if ((tdp.mfr2_tonelen <= 4000) || (tdp.mfr2_tonelen >= 10)) {
+ global_dialparams.mfr2_tonelen = tdp.mfr2_tonelen;
+ }
+
+ /* update the lengths in all currently loaded zones */
+ write_lock(&zone_lock);
+ for (j = 0; j < sizeof(tone_zones) / sizeof(tone_zones[0]); j++) {
+ struct zt_zone *z = tone_zones[j];
+
+ if (!z)
+ continue;
+
+ for (i = 0; i < sizeof(z->dtmf) / sizeof(z->dtmf[0]); i++) {
+ z->dtmf[i].tonesamples = global_dialparams.dtmf_tonelen * ZT_CHUNKSIZE;
+ }
+
+ /* for MFR1, we only adjust the length of the digits */
+ for (i = ZT_TONE_MFR1_0; i <= ZT_TONE_MFR1_9; i++) {
+ z->mfr1[i - ZT_TONE_MFR1_BASE].tonesamples = global_dialparams.mfv1_tonelen * ZT_CHUNKSIZE;
+ }
+
+ for (i = 0; i < sizeof(z->mfr2_fwd) / sizeof(z->mfr2_fwd[0]); i++) {
+ z->mfr2_fwd[i].tonesamples = global_dialparams.mfr2_tonelen * ZT_CHUNKSIZE;
+ }
+
+ for (i = 0; i < sizeof(z->mfr2_rev) / sizeof(z->mfr2_rev[0]); i++) {
+ z->mfr2_rev[i].tonesamples = global_dialparams.mfr2_tonelen * ZT_CHUNKSIZE;
+ }
+ }
+ write_unlock(&zone_lock);
+
+ dtmf_silence.tonesamples = global_dialparams.dtmf_tonelen * ZT_CHUNKSIZE;
+ mfr1_silence.tonesamples = global_dialparams.mfv1_tonelen * ZT_CHUNKSIZE;
+ mfr2_silence.tonesamples = global_dialparams.mfr2_tonelen * ZT_CHUNKSIZE;
+
+ break;
+ }
+ case ZT_GET_DIALPARAMS:
+ {
+ struct zt_dialparams tdp;
+
+ tdp = global_dialparams;
+ if (copy_to_user((struct zt_dialparams *) data, &tdp, sizeof(tdp)))
+ return -EFAULT;
+ break;
+ }
+ case ZT_GETVERSION:
+ {
+ struct zt_versioninfo vi;
+
+ memset(&vi, 0, sizeof(vi));
+ zap_copy_string(vi.version, ZAPTEL_VERSION, sizeof(vi.version));
+ echo_can_identify(vi.echo_canceller, sizeof(vi.echo_canceller) - 1);
+ if (copy_to_user((struct zt_versioninfo *) data, &vi, sizeof(vi)))
+ return -EFAULT;
+ break;
+ }
+ case ZT_MAINT: /* do maintenance stuff */
+ {
+ struct zt_maintinfo maint;
+ /* get struct from user */
+ if (copy_from_user(&maint,(struct zt_maintinfo *) data, sizeof(maint)))
+ return -EFAULT;
+ /* must be valid span number */
+ if ((maint.spanno < 1) || (maint.spanno > ZT_MAX_SPANS) || (!spans[maint.spanno]))
+ return -EINVAL;
+ if (!spans[maint.spanno]->maint)
+ return -ENOSYS;
+ spin_lock_irqsave(&spans[maint.spanno]->lock, flags);
+ /* save current maint state */
+ i = spans[maint.spanno]->maintstat;
+ /* set maint mode */
+ spans[maint.spanno]->maintstat = maint.command;
+ switch(maint.command) {
+ case ZT_MAINT_NONE:
+ case ZT_MAINT_LOCALLOOP:
+ case ZT_MAINT_REMOTELOOP:
+ /* if same, ignore it */
+ if (i == maint.command) break;
+ rv = spans[maint.spanno]->maint(spans[maint.spanno], maint.command);
+ spin_unlock_irqrestore(&spans[maint.spanno]->lock, flags);
+ if (rv) return rv;
+ spin_lock_irqsave(&spans[maint.spanno]->lock, flags);
+ break;
+ case ZT_MAINT_LOOPUP:
+ case ZT_MAINT_LOOPDOWN:
+ spans[maint.spanno]->mainttimer = ZT_LOOPCODE_TIME * ZT_CHUNKSIZE;
+ rv = spans[maint.spanno]->maint(spans[maint.spanno], maint.command);
+ spin_unlock_irqrestore(&spans[maint.spanno]->lock, flags);
+ if (rv) return rv;
+ rv = schluffen(&spans[maint.spanno]->maintq);
+ if (rv) return rv;
+ spin_lock_irqsave(&spans[maint.spanno]->lock, flags);
+ break;
+ default:
+ printk("zaptel: Unknown maintenance event: %d\n", maint.command);
+ }
+ zt_alarm_notify(spans[maint.spanno]); /* process alarm-related events */
+ spin_unlock_irqrestore(&spans[maint.spanno]->lock, flags);
+ break;
+ }
+ case ZT_DYNAMIC_CREATE:
+ case ZT_DYNAMIC_DESTROY:
+ if (zt_dynamic_ioctl)
+ return zt_dynamic_ioctl(cmd, data);
+ else {
+ request_module("ztdynamic");
+ if (zt_dynamic_ioctl)
+ return zt_dynamic_ioctl(cmd, data);
+ }
+ return -ENOSYS;
+#if defined(ECHO_CAN_HPEC)
+ case ZT_EC_LICENSE_CHALLENGE:
+ case ZT_EC_LICENSE_RESPONSE:
+ return hpec_license_ioctl(cmd, data);
+#endif /* defined(ECHO_CAN_HPEC) */
+ default:
+ return zt_common_ioctl(inode, file, cmd, data, 0);
+ }
+ return 0;
+}
+
+static int ioctl_zt_dial(struct zt_chan *chan, unsigned long data)
+{
+ struct zt_dialoperation *tdo;
+ unsigned long flags;
+ char *s;
+ int rv;
+
+ tdo = kmalloc(sizeof(*tdo), GFP_KERNEL);
+
+ if (!tdo)
+ return -ENOMEM;
+
+ if (copy_from_user(tdo, (struct zt_dialoperation *)data, sizeof(*tdo)))
+ return -EFAULT;
+ rv = 0;
+ /* Force proper NULL termination and uppercase entry */
+ tdo->dialstr[ZT_MAX_DTMF_BUF - 1] = '\0';
+ for (s = tdo->dialstr; *s; s++)
+ *s = toupper(*s);
+ spin_lock_irqsave(&chan->lock, flags);
+ if (!chan->curzone) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ /* The tone zones are loaded by ztcfg from /etc/zaptel.conf */
+ printk(KERN_WARNING "zaptel: Cannot dial until a tone zone is loaded.\n");
+ return -ENODATA;
+ }
+ switch (tdo->op) {
+ case ZT_DIAL_OP_CANCEL:
+ chan->curtone = NULL;
+ chan->dialing = 0;
+ chan->txdialbuf[0] = '\0';
+ chan->tonep = 0;
+ chan->pdialcount = 0;
+ break;
+ case ZT_DIAL_OP_REPLACE:
+ strcpy(chan->txdialbuf, tdo->dialstr);
+ chan->dialing = 1;
+ __do_dtmf(chan);
+ break;
+ case ZT_DIAL_OP_APPEND:
+ if (strlen(tdo->dialstr) + strlen(chan->txdialbuf) >= (ZT_MAX_DTMF_BUF - 1)) {
+ rv = -EBUSY;
+ break;
+ }
+ zap_copy_string(chan->txdialbuf + strlen(chan->txdialbuf), tdo->dialstr, ZT_MAX_DTMF_BUF - strlen(chan->txdialbuf));
+ if (!chan->dialing) {
+ chan->dialing = 1;
+ __do_dtmf(chan);
+ }
+ break;
+ default:
+ rv = -EINVAL;
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return rv;
+}
+
+static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit)
+{
+ struct zt_chan *chan = chans[unit];
+ union {
+ struct zt_bufferinfo bi;
+ struct zt_confinfo conf;
+ struct zt_ring_cadence cad;
+ } stack;
+ unsigned long flags, flagso;
+ int i, j, k, rv;
+ int ret, c;
+
+ if (!chan)
+ return -EINVAL;
+ switch(cmd) {
+ case ZT_DIALING:
+ spin_lock_irqsave(&chan->lock, flags);
+ j = chan->dialing;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ if (copy_to_user((int *)data,&j,sizeof(int)))
+ return -EFAULT;
+ return 0;
+ case ZT_DIAL:
+ return ioctl_zt_dial(chan, data);
+ case ZT_GET_BUFINFO:
+ stack.bi.rxbufpolicy = chan->rxbufpolicy;
+ stack.bi.txbufpolicy = chan->txbufpolicy;
+ stack.bi.numbufs = chan->numbufs;
+ stack.bi.bufsize = chan->blocksize;
+ /* XXX FIXME! XXX */
+ stack.bi.readbufs = -1;
+ stack.bi.writebufs = -1;
+ if (copy_to_user((struct zt_bufferinfo *)data, &stack.bi, sizeof(stack.bi)))
+ return -EFAULT;
+ break;
+ case ZT_SET_BUFINFO:
+ if (copy_from_user(&stack.bi, (struct zt_bufferinfo *)data, sizeof(stack.bi)))
+ return -EFAULT;
+ if (stack.bi.bufsize > ZT_MAX_BLOCKSIZE)
+ return -EINVAL;
+ if (stack.bi.bufsize < 16)
+ return -EINVAL;
+ if (stack.bi.bufsize * stack.bi.numbufs > ZT_MAX_BUF_SPACE)
+ return -EINVAL;
+ chan->rxbufpolicy = stack.bi.rxbufpolicy & 0x1;
+ chan->txbufpolicy = stack.bi.txbufpolicy & 0x1;
+ if ((rv = zt_reallocbufs(chan, stack.bi.bufsize, stack.bi.numbufs)))
+ return (rv);
+ break;
+ case ZT_GET_BLOCKSIZE: /* get blocksize */
+ put_user(chan->blocksize,(int *)data); /* return block size */
+ break;
+ case ZT_SET_BLOCKSIZE: /* set blocksize */
+ get_user(j,(int *)data);
+ /* cannot be larger than max amount */
+ if (j > ZT_MAX_BLOCKSIZE) return(-EINVAL);
+ /* cannot be less then 16 */
+ if (j < 16) return(-EINVAL);
+ /* allocate a single kernel buffer which we then
+ sub divide into four pieces */
+ if ((rv = zt_reallocbufs(chan, j, chan->numbufs)))
+ return (rv);
+ break;
+ case ZT_FLUSH: /* flush input buffer, output buffer, and/or event queue */
+ get_user(i,(int *)data); /* get param */
+ spin_lock_irqsave(&chan->lock, flags);
+ if (i & ZT_FLUSH_READ) /* if for read (input) */
+ {
+ /* initialize read buffers and pointers */
+ chan->inreadbuf = 0;
+ chan->outreadbuf = -1;
+ for (j=0;j<chan->numbufs;j++) {
+ /* Do we need this? */
+ chan->readn[j] = 0;
+ chan->readidx[j] = 0;
+ }
+ wake_up_interruptible(&chan->readbufq); /* wake_up_interruptible waiting on read */
+ wake_up_interruptible(&chan->sel); /* wake_up_interruptible waiting on select */
+ }
+ if (i & ZT_FLUSH_WRITE) /* if for write (output) */
+ {
+ /* initialize write buffers and pointers */
+ chan->outwritebuf = -1;
+ chan->inwritebuf = 0;
+ for (j=0;j<chan->numbufs;j++) {
+ /* Do we need this? */
+ chan->writen[j] = 0;
+ chan->writeidx[j] = 0;
+ }
+ wake_up_interruptible(&chan->writebufq); /* wake_up_interruptible waiting on write */
+ wake_up_interruptible(&chan->sel); /* wake_up_interruptible waiting on select */
+ /* if IO MUX wait on write empty, well, this
+ certainly *did* empty the write */
+ if (chan->iomask & ZT_IOMUX_WRITEEMPTY)
+ wake_up_interruptible(&chan->eventbufq); /* wake_up_interruptible waiting on IOMUX */
+ }
+ if (i & ZT_FLUSH_EVENT) /* if for events */
+ {
+ /* initialize the event pointers */
+ chan->eventinidx = chan->eventoutidx = 0;
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ break;
+ case ZT_SYNC: /* wait for no tx */
+ for(;;) /* loop forever */
+ {
+ spin_lock_irqsave(&chan->lock, flags);
+ /* Know if there is a write pending */
+ i = (chan->outwritebuf > -1);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ if (!i) break; /* skip if none */
+ rv = schluffen(&chan->writebufq);
+ if (rv) return(rv);
+ }
+ break;
+ case ZT_IOMUX: /* wait for something to happen */
+ get_user(chan->iomask,(int*)data); /* save mask */
+ if (!chan->iomask) return(-EINVAL); /* cant wait for nothing */
+ for(;;) /* loop forever */
+ {
+ /* has to have SOME mask */
+ ret = 0; /* start with empty return value */
+ spin_lock_irqsave(&chan->lock, flags);
+ /* if looking for read */
+ if (chan->iomask & ZT_IOMUX_READ)
+ {
+ /* if read available */
+ if ((chan->outreadbuf > -1) && !chan->rxdisable)
+ ret |= ZT_IOMUX_READ;
+ }
+ /* if looking for write avail */
+ if (chan->iomask & ZT_IOMUX_WRITE)
+ {
+ if (chan->inwritebuf > -1)
+ ret |= ZT_IOMUX_WRITE;
+ }
+ /* if looking for write empty */
+ if (chan->iomask & ZT_IOMUX_WRITEEMPTY)
+ {
+ /* if everything empty -- be sure the transmitter is enabled */
+ chan->txdisable = 0;
+ if (chan->outwritebuf < 0)
+ ret |= ZT_IOMUX_WRITEEMPTY;
+ }
+ /* if looking for signalling event */
+ if (chan->iomask & ZT_IOMUX_SIGEVENT)
+ {
+ /* if event */
+ if (chan->eventinidx != chan->eventoutidx)
+ ret |= ZT_IOMUX_SIGEVENT;
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ /* if something to return, or not to wait */
+ if (ret || (chan->iomask & ZT_IOMUX_NOWAIT))
+ {
+ /* set return value */
+ put_user(ret,(int *)data);
+ break; /* get out of loop */
+ }
+ rv = schluffen(&chan->eventbufq);
+ if (rv) return(rv);
+ }
+ /* clear IO MUX mask */
+ chan->iomask = 0;
+ break;
+ case ZT_GETEVENT: /* Get event on queue */
+ /* set up for no event */
+ j = ZT_EVENT_NONE;
+ spin_lock_irqsave(&chan->lock, flags);
+ /* if some event in queue */
+ if (chan->eventinidx != chan->eventoutidx)
+ {
+ j = chan->eventbuf[chan->eventoutidx++];
+ /* get the data, bump index */
+ /* if index overflow, set to beginning */
+ if (chan->eventoutidx >= ZT_MAX_EVENTSIZE)
+ chan->eventoutidx = 0;
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ put_user(j,(int *)data);
+ break;
+ case ZT_CONFMUTE: /* set confmute flag */
+ get_user(j,(int *)data); /* get conf # */
+ if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL);
+ spin_lock_irqsave(&bigzaplock, flags);
+ chan->confmute = j;
+ spin_unlock_irqrestore(&bigzaplock, flags);
+ break;
+ case ZT_GETCONFMUTE: /* get confmute flag */
+ if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL);
+ j = chan->confmute;
+ put_user(j,(int *)data); /* get conf # */
+ rv = 0;
+ break;
+ case ZT_SETTONEZONE:
+ get_user(j, (int *) data);
+ rv = set_tone_zone(chan, j);
+ return rv;
+ case ZT_GETTONEZONE:
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->curzone)
+ j = chan->tonezone;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ put_user(j, (int *) data);
+ break;
+ case ZT_SENDTONE:
+ get_user(j,(int *)data);
+ spin_lock_irqsave(&chan->lock, flags);
+ rv = start_tone(chan, j);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return rv;
+ case ZT_GETCONF: /* get conf stuff */
+ if (copy_from_user(&stack.conf,(struct zt_confinfo *) data,sizeof(stack.conf)))
+ return -EFAULT;
+ i = stack.conf.chan; /* get channel no */
+ /* if zero, use current channel no */
+ if (!i) i = chan->channo;
+ /* make sure channel number makes sense */
+ if ((i < 0) || (i > ZT_MAX_CONF) || (!chans[i])) return(-EINVAL);
+ if (!(chans[i]->flags & ZT_FLAG_AUDIO)) return (-EINVAL);
+ stack.conf.chan = i; /* get channel number */
+ stack.conf.confno = chans[i]->confna; /* get conference number */
+ stack.conf.confmode = chans[i]->confmode; /* get conference mode */
+ if (copy_to_user((struct zt_confinfo *) data,&stack.conf,sizeof(stack.conf)))
+ return -EFAULT;
+ break;
+ case ZT_SETCONF: /* set conf stuff */
+ if (copy_from_user(&stack.conf,(struct zt_confinfo *) data,sizeof(stack.conf)))
+ return -EFAULT;
+ i = stack.conf.chan; /* get channel no */
+ /* if zero, use current channel no */
+ if (!i) i = chan->channo;
+ /* make sure channel number makes sense */
+ if ((i < 1) || (i > ZT_MAX_CHANNELS) || (!chans[i])) return(-EINVAL);
+ if (!(chans[i]->flags & ZT_FLAG_AUDIO)) return (-EINVAL);
+ if ((stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR ||
+ (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORTX ||
+ (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH ||
+ (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_RX_PREECHO ||
+ (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_TX_PREECHO ||
+ (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH_PREECHO) {
+ /* Monitor mode -- it's a channel */
+ if ((stack.conf.confno < 0) || (stack.conf.confno >= ZT_MAX_CHANNELS) || !chans[stack.conf.confno]) return(-EINVAL);
+ } else {
+ /* make sure conf number makes sense, too */
+ if ((stack.conf.confno < -1) || (stack.conf.confno > ZT_MAX_CONF)) return(-EINVAL);
+ }
+
+ /* if taking off of any conf, must have 0 mode */
+ if ((!stack.conf.confno) && stack.conf.confmode) return(-EINVAL);
+ /* likewise if 0 mode must have no conf */
+ if ((!stack.conf.confmode) && stack.conf.confno) return (-EINVAL);
+ stack.conf.chan = i; /* return with real channel # */
+ spin_lock_irqsave(&bigzaplock, flagso);
+ spin_lock_irqsave(&chan->lock, flags);
+ if (stack.conf.confno == -1)
+ stack.conf.confno = zt_first_empty_conference();
+ if ((stack.conf.confno < 1) && (stack.conf.confmode)) {
+ /* No more empty conferences */
+ spin_unlock_irqrestore(&chan->lock, flags);
+ spin_unlock_irqrestore(&bigzaplock, flagso);
+ return -EBUSY;
+ }
+ /* if changing confs, clear last added info */
+ if (stack.conf.confno != chans[i]->confna) {
+ memset(chans[i]->conflast, 0, ZT_MAX_CHUNKSIZE);
+ memset(chans[i]->conflast1, 0, ZT_MAX_CHUNKSIZE);
+ memset(chans[i]->conflast2, 0, ZT_MAX_CHUNKSIZE);
+ }
+ j = chans[i]->confna; /* save old conference number */
+ chans[i]->confna = stack.conf.confno; /* set conference number */
+ chans[i]->confmode = stack.conf.confmode; /* set conference mode */
+ chans[i]->_confn = 0; /* Clear confn */
+ zt_check_conf(j);
+ zt_check_conf(stack.conf.confno);
+ if (chans[i]->span && chans[i]->span->dacs) {
+ if (((stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_DIGITALMON) &&
+ chans[stack.conf.confno]->span &&
+ chans[stack.conf.confno]->span->dacs == chans[i]->span->dacs &&
+ chans[i]->txgain == defgain &&
+ chans[i]->rxgain == defgain &&
+ chans[stack.conf.confno]->txgain == defgain &&
+ chans[stack.conf.confno]->rxgain == defgain) {
+ chans[i]->span->dacs(chans[i], chans[stack.conf.confno]);
+ } else {
+ chans[i]->span->dacs(chans[i], NULL);
+ }
+ }
+ /* if we are going onto a conf */
+ if (stack.conf.confno &&
+ ((stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONF ||
+ (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFANN ||
+ (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFMON ||
+ (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_CONFANNMON ||
+ (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_REALANDPSEUDO)) {
+ /* Get alias */
+ chans[i]->_confn = zt_get_conf_alias(stack.conf.confno);
+ }
+
+ if (chans[stack.conf.confno]) {
+ if ((stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_RX_PREECHO ||
+ (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITOR_TX_PREECHO ||
+ (stack.conf.confmode & ZT_CONF_MODE_MASK) == ZT_CONF_MONITORBOTH_PREECHO)
+ chans[stack.conf.confno]->readchunkpreec = kmalloc(sizeof(*chans[stack.conf.confno]->readchunkpreec) * ZT_CHUNKSIZE, GFP_ATOMIC);
+ else {
+ if (chans[stack.conf.confno]->readchunkpreec) {
+ kfree(chans[stack.conf.confno]->readchunkpreec);
+ chans[stack.conf.confno]->readchunkpreec = NULL;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+ spin_unlock_irqrestore(&bigzaplock, flagso);
+ if (copy_to_user((struct zt_confinfo *) data,&stack.conf,sizeof(stack.conf)))
+ return -EFAULT;
+ break;
+ case ZT_CONFLINK: /* do conf link stuff */
+ if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL);
+ if (copy_from_user(&stack.conf,(struct zt_confinfo *) data,sizeof(stack.conf)))
+ return -EFAULT;
+ /* check sanity of arguments */
+ if ((stack.conf.chan < 0) || (stack.conf.chan > ZT_MAX_CONF)) return(-EINVAL);
+ if ((stack.conf.confno < 0) || (stack.conf.confno > ZT_MAX_CONF)) return(-EINVAL);
+ /* cant listen to self!! */
+ if (stack.conf.chan && (stack.conf.chan == stack.conf.confno)) return(-EINVAL);
+ spin_lock_irqsave(&bigzaplock, flagso);
+ spin_lock_irqsave(&chan->lock, flags);
+ /* if to clear all links */
+ if ((!stack.conf.chan) && (!stack.conf.confno))
+ {
+ /* clear all the links */
+ memset(conf_links,0,sizeof(conf_links));
+ recalc_maxlinks();
+ spin_unlock_irqrestore(&chan->lock, flags);
+ spin_unlock_irqrestore(&bigzaplock, flagso);
+ break;
+ }
+ rv = 0; /* clear return value */
+ /* look for already existant specified combination */
+ for(i = 1; i <= ZT_MAX_CONF; i++)
+ {
+ /* if found, exit */
+ if ((conf_links[i].src == stack.conf.chan) &&
+ (conf_links[i].dst == stack.conf.confno)) break;
+ }
+ if (i <= ZT_MAX_CONF) /* if found */
+ {
+ if (!stack.conf.confmode) /* if to remove link */
+ {
+ conf_links[i].src = conf_links[i].dst = 0;
+ }
+ else /* if to add and already there, error */
+ {
+ rv = -EEXIST;
+ }
+ }
+ else /* if not found */
+ {
+ if (stack.conf.confmode) /* if to add link */
+ {
+ /* look for empty location */
+ for(i = 1; i <= ZT_MAX_CONF; i++)
+ {
+ /* if empty, exit loop */
+ if ((!conf_links[i].src) &&
+ (!conf_links[i].dst)) break;
+ }
+ /* if empty spot found */
+ if (i <= ZT_MAX_CONF)
+ {
+ conf_links[i].src = stack.conf.chan;
+ conf_links[i].dst = stack.conf.confno;
+ }
+ else /* if no empties -- error */
+ {
+ rv = -ENOSPC;
+ }
+ }
+ else /* if to remove, and not found -- error */
+ {
+ rv = -ENOENT;
+ }
+ }
+ recalc_maxlinks();
+ spin_unlock_irqrestore(&chan->lock, flags);
+ spin_unlock_irqrestore(&bigzaplock, flagso);
+ return(rv);
+ case ZT_CONFDIAG: /* output diagnostic info to console */
+ if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL);
+ get_user(j,(int *)data); /* get conf # */
+ /* loop thru the interesting ones */
+ for(i = ((j) ? j : 1); i <= ((j) ? j : ZT_MAX_CONF); i++)
+ {
+ c = 0;
+ for(k = 1; k < ZT_MAX_CHANNELS; k++)
+ {
+ /* skip if no pointer */
+ if (!chans[k]) continue;
+ /* skip if not in this conf */
+ if (chans[k]->confna != i) continue;
+ if (!c) printk("Conf #%d:\n",i);
+ c = 1;
+ printk("chan %d, mode %x\n",
+ k,chans[k]->confmode);
+ }
+ rv = 0;
+ for(k = 1; k <= ZT_MAX_CONF; k++)
+ {
+ if (conf_links[k].dst == i)
+ {
+ if (!c) printk("Conf #%d:\n",i);
+ c = 1;
+ if (!rv) printk("Snooping on:\n");
+ rv = 1;
+ printk("conf %d\n",conf_links[k].src);
+ }
+ }
+ if (c) printk("\n");
+ }
+ break;
+ case ZT_CHANNO: /* get channel number of stream */
+ put_user(unit,(int *)data); /* return unit/channel number */
+ break;
+ case ZT_SETLAW:
+ get_user(j, (int *)data);
+ if ((j < 0) || (j > ZT_LAW_ALAW))
+ return -EINVAL;
+ zt_set_law(chan, j);
+ break;
+ case ZT_SETLINEAR:
+ get_user(j, (int *)data);
+ /* Makes no sense on non-audio channels */
+ if (!(chan->flags & ZT_FLAG_AUDIO))
+ return -EINVAL;
+
+ if (j)
+ chan->flags |= ZT_FLAG_LINEAR;
+ else
+ chan->flags &= ~ZT_FLAG_LINEAR;
+ break;
+ case ZT_SETCADENCE:
+ if (data) {
+ /* Use specific ring cadence */
+ if (copy_from_user(&stack.cad, (struct zt_ring_cadence *)data, sizeof(stack.cad)))
+ return -EFAULT;
+ memcpy(chan->ringcadence, &stack.cad, sizeof(chan->ringcadence));
+ chan->firstcadencepos = 0;
+ /* Looking for negative ringing time indicating where to loop back into ringcadence */
+ for (i=0; i<ZT_MAX_CADENCE; i+=2 ) {
+ if (chan->ringcadence[i]<0) {
+ chan->ringcadence[i] *= -1;
+ chan->firstcadencepos = i;
+ break;
+ }
+ }
+ } else {
+ /* Reset to default */
+ chan->firstcadencepos = 0;
+ if (chan->curzone) {
+ memcpy(chan->ringcadence, chan->curzone->ringcadence, sizeof(chan->ringcadence));
+ /* Looking for negative ringing time indicating where to loop back into ringcadence */
+ for (i=0; i<ZT_MAX_CADENCE; i+=2 ) {
+ if (chan->ringcadence[i]<0) {
+ chan->ringcadence[i] *= -1;
+ chan->firstcadencepos = i;
+ break;
+ }
+ }
+ } else {
+ memset(chan->ringcadence, 0, sizeof(chan->ringcadence));
+ chan->ringcadence[0] = chan->starttime;
+ chan->ringcadence[1] = ZT_RINGOFFTIME;
+ }
+ }
+ break;
+ default:
+ /* Check for common ioctl's and private ones */
+ rv = zt_common_ioctl(inode, file, cmd, data, unit);
+ /* if no span, just return with value */
+ if (!chan->span) return rv;
+ if ((rv == -ENOTTY) && chan->span->ioctl)
+ rv = chan->span->ioctl(chan, cmd, data);
+ return rv;
+
+ }
+ return 0;
+}
+
+#ifdef CONFIG_ZAPATA_PPP
+/*
+ * This is called at softirq (BH) level when there are calls
+ * we need to make to the ppp_generic layer. We do it this
+ * way because the ppp_generic layer functions may not be called
+ * at interrupt level.
+ */
+static void do_ppp_calls(unsigned long data)
+{
+ struct zt_chan *chan = (struct zt_chan *) data;
+ struct sk_buff *skb;
+
+ if (!chan->ppp)
+ return;
+ if (chan->do_ppp_wakeup) {
+ chan->do_ppp_wakeup = 0;
+ ppp_output_wakeup(chan->ppp);
+ }
+ while ((skb = skb_dequeue(&chan->ppp_rq)) != NULL)
+ ppp_input(chan->ppp, skb);
+ if (chan->do_ppp_error) {
+ chan->do_ppp_error = 0;
+ ppp_input_error(chan->ppp, 0);
+ }
+}
+#endif
+
+static int ioctl_echocancel(struct zt_chan *chan, struct zt_echocanparams *ecp, void *data)
+{
+ struct echo_can_state *ec = NULL, *tec;
+ struct zt_echocanparam *params;
+ int ret;
+ unsigned long flags;
+
+ if (ecp->param_count > ZT_MAX_ECHOCANPARAMS)
+ return -E2BIG;
+
+ if (ecp->tap_length == 0) {
+ /* disable mode, don't need to inspect params */
+ spin_lock_irqsave(&chan->lock, flags);
+ tec = chan->ec;
+ chan->ec = NULL;
+ chan->echocancel = 0;
+ chan->echostate = ECHO_STATE_IDLE;
+ chan->echolastupdate = 0;
+ chan->echotimer = 0;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ hw_echocancel_off(chan);
+ if (tec)
+ echo_can_free(tec);
+
+ return 0;
+ }
+
+ /* if parameters were supplied and this channel's span provides an echocan,
+ but not one that takes params, then we must punt here and return an error */
+ if (ecp->param_count && chan->span && chan->span->echocan &&
+ !chan->span->echocan_with_params)
+ return -EINVAL;
+
+ params = kmalloc(sizeof(params[0]) * ZT_MAX_ECHOCANPARAMS, GFP_KERNEL);
+
+ if (!params)
+ return -ENOMEM;
+
+ /* enable mode, need the params */
+
+ if (copy_from_user(params, (struct zt_echocanparam *) data, sizeof(params[0]) * ecp->param_count)) {
+ ret = -EFAULT;
+ goto exit_with_free;
+ }
+
+ spin_lock_irqsave(&chan->lock, flags);
+ tec = chan->ec;
+ chan->ec = NULL;
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ if (tec)
+ echo_can_free(tec);
+
+ ret = -ENODEV;
+
+ /* attempt to use the span's echo canceler; fall back to built-in
+ if it fails (but not if an error occurs) */
+ if (chan->span) {
+ if (chan->span->echocan_with_params)
+ ret = chan->span->echocan_with_params(chan, ecp, params);
+ else if (chan->span->echocan)
+ ret = chan->span->echocan(chan, ecp->tap_length);
+ }
+
+ if (ret == -ENODEV) {
+ switch (ecp->tap_length) {
+ case 32:
+ case 64:
+ case 128:
+ case 256:
+ case 512:
+ case 1024:
+ break;
+ default:
+ ecp->tap_length = deftaps;
+ }
+
+ if ((ret = echo_can_create(ecp, params, &ec)))
+ goto exit_with_free;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ chan->echocancel = ecp->tap_length;
+ chan->ec = ec;
+ chan->echostate = ECHO_STATE_IDLE;
+ chan->echolastupdate = 0;
+ chan->echotimer = 0;
+ echo_can_disable_detector_init(&chan->txecdis);
+ echo_can_disable_detector_init(&chan->rxecdis);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ }
+
+exit_with_free:
+ kfree(params);
+ return ret;
+}
+
+static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit)
+{
+ struct zt_chan *chan = chans[unit];
+ unsigned long flags;
+ int j, rv;
+ int ret;
+ int oldconf;
+ void *rxgain=NULL;
+ struct echo_can_state *ec;
+
+ if (!chan)
+ return -ENOSYS;
+
+ switch(cmd) {
+ case ZT_SIGFREEZE:
+ get_user(j, (int *)data);
+ spin_lock_irqsave(&chan->lock, flags);
+ if (j) {
+ chan->flags |= ZT_FLAG_SIGFREEZE;
+ } else {
+ chan->flags &= ~ZT_FLAG_SIGFREEZE;
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ break;
+ case ZT_GETSIGFREEZE:
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->flags & ZT_FLAG_SIGFREEZE)
+ j = 1;
+ else
+ j = 0;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ put_user(j, (int *)data);
+ break;
+ case ZT_AUDIOMODE:
+ /* Only literal clear channels can be put in */
+ if (chan->sig != ZT_SIG_CLEAR) return (-EINVAL);
+ get_user(j, (int *)data);
+ if (j) {
+ spin_lock_irqsave(&chan->lock, flags);
+ chan->flags |= ZT_FLAG_AUDIO;
+ chan->flags &= ~(ZT_FLAG_HDLC | ZT_FLAG_FCS);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ } else {
+ /* Coming out of audio mode, also clear all
+ conferencing and gain related info as well
+ as echo canceller */
+ spin_lock_irqsave(&chan->lock, flags);
+ chan->flags &= ~ZT_FLAG_AUDIO;
+ /* save old conf number, if any */
+ oldconf = chan->confna;
+ /* initialize conference variables */
+ chan->_confn = 0;
+ chan->confna = 0;
+ if (chan->span && chan->span->dacs)
+ chan->span->dacs(chan, NULL);
+ chan->confmode = 0;
+ chan->confmute = 0;
+ memset(chan->conflast, 0, sizeof(chan->conflast));
+ memset(chan->conflast1, 0, sizeof(chan->conflast1));
+ memset(chan->conflast2, 0, sizeof(chan->conflast2));
+ ec = chan->ec;
+ chan->ec = NULL;
+ /* release conference resource, if any to release */
+ reset_conf(chan);
+ if (chan->gainalloc && chan->rxgain)
+ rxgain = chan->rxgain;
+ else
+ rxgain = NULL;
+
+ chan->rxgain = defgain;
+ chan->txgain = defgain;
+ chan->gainalloc = 0;
+ /* Disable any native echo cancellation as well */
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ hw_echocancel_off(chan);
+
+ if (rxgain)
+ kfree(rxgain);
+ if (ec)
+ echo_can_free(ec);
+ if (oldconf) zt_check_conf(oldconf);
+ }
+ break;
+ case ZT_HDLCPPP:
+#ifdef CONFIG_ZAPATA_PPP
+ if (chan->sig != ZT_SIG_CLEAR) return (-EINVAL);
+ get_user(j, (int *)data);
+ if (j) {
+ if (!chan->ppp) {
+ chan->ppp = kmalloc(sizeof(struct ppp_channel), GFP_KERNEL);
+ if (chan->ppp) {
+ struct echo_can_state *tec;
+ memset(chan->ppp, 0, sizeof(struct ppp_channel));
+ chan->ppp->private = chan;
+ chan->ppp->ops = &ztppp_ops;
+ chan->ppp->mtu = ZT_DEFAULT_MTU_MRU;
+ chan->ppp->hdrlen = 0;
+ skb_queue_head_init(&chan->ppp_rq);
+ chan->do_ppp_wakeup = 0;
+ tasklet_init(&chan->ppp_calls, do_ppp_calls,
+ (unsigned long)chan);
+ if ((ret = zt_reallocbufs(chan, ZT_DEFAULT_MTU_MRU, ZT_DEFAULT_NUM_BUFS))) {
+ kfree(chan->ppp);
+ chan->ppp = NULL;
+ return ret;
+ }
+
+ if ((ret = ppp_register_channel(chan->ppp))) {
+ kfree(chan->ppp);
+ chan->ppp = NULL;
+ return ret;
+ }
+ tec = chan->ec;
+ chan->ec = NULL;
+ chan->echocancel = 0;
+ chan->echostate = ECHO_STATE_IDLE;
+ chan->echolastupdate = 0;
+ chan->echotimer = 0;
+ /* Make sure there's no gain */
+ if (chan->gainalloc)
+ kfree(chan->rxgain);
+ chan->rxgain = defgain;
+ chan->txgain = defgain;
+ chan->gainalloc = 0;
+ chan->flags &= ~ZT_FLAG_AUDIO;
+ chan->flags |= (ZT_FLAG_PPP | ZT_FLAG_HDLC | ZT_FLAG_FCS);
+ hw_echocancel_off(chan);
+
+ if (tec)
+ echo_can_free(tec);
+ } else
+ return -ENOMEM;
+ }
+ } else {
+ chan->flags &= ~(ZT_FLAG_PPP | ZT_FLAG_HDLC | ZT_FLAG_FCS);
+ if (chan->ppp) {
+ struct ppp_channel *ppp = chan->ppp;
+ chan->ppp = NULL;
+ tasklet_kill(&chan->ppp_calls);
+ skb_queue_purge(&chan->ppp_rq);
+ ppp_unregister_channel(ppp);
+ kfree(ppp);
+ }
+ }
+#else
+ printk("Zaptel: Zaptel PPP support not compiled in\n");
+ return -ENOSYS;
+#endif
+ break;
+ case ZT_HDLCRAWMODE:
+ if (chan->sig != ZT_SIG_CLEAR) return (-EINVAL);
+ get_user(j, (int *)data);
+ chan->flags &= ~(ZT_FLAG_AUDIO | ZT_FLAG_HDLC | ZT_FLAG_FCS);
+ if (j) {
+ chan->flags |= ZT_FLAG_HDLC;
+ fasthdlc_init(&chan->rxhdlc);
+ fasthdlc_init(&chan->txhdlc);
+ }
+ break;
+ case ZT_HDLCFCSMODE:
+ if (chan->sig != ZT_SIG_CLEAR) return (-EINVAL);
+ get_user(j, (int *)data);
+ chan->flags &= ~(ZT_FLAG_AUDIO | ZT_FLAG_HDLC | ZT_FLAG_FCS);
+ if (j) {
+ chan->flags |= ZT_FLAG_HDLC | ZT_FLAG_FCS;
+ fasthdlc_init(&chan->rxhdlc);
+ fasthdlc_init(&chan->txhdlc);
+ }
+ break;
+ case ZT_ECHOCANCEL_PARAMS:
+ {
+ struct zt_echocanparams ecp;
+
+ if (!(chan->flags & ZT_FLAG_AUDIO))
+ return -EINVAL;
+ if (copy_from_user(&ecp, (struct zt_echocanparams *) data, sizeof(ecp)))
+ return -EFAULT;
+ data += sizeof(ecp);
+ if ((ret = ioctl_echocancel(chan, &ecp, (void *) data)))
+ return ret;
+ break;
+ }
+ case ZT_ECHOCANCEL:
+ {
+ struct zt_echocanparams ecp;
+
+ if (!(chan->flags & ZT_FLAG_AUDIO))
+ return -EINVAL;
+ get_user(j, (int *) data);
+ ecp.tap_length = j;
+ ecp.param_count = 0;
+ if ((ret = ioctl_echocancel(chan, &ecp, NULL)))
+ return ret;
+ break;
+ }
+ case ZT_ECHOTRAIN:
+ get_user(j, (int *)data); /* get pre-training time from user */
+ if ((j < 0) || (j >= ZT_MAX_PRETRAINING))
+ return -EINVAL;
+ j <<= 3;
+ if (chan->ec) {
+ /* Start pretraining stage */
+ chan->echostate = ECHO_STATE_PRETRAINING;
+ chan->echotimer = j;
+ } else
+ return -EINVAL;
+ break;
+ case ZT_SETTXBITS:
+ if (chan->sig != ZT_SIG_CAS)
+ return -EINVAL;
+ get_user(j,(int *)data);
+ zt_cas_setbits(chan, j);
+ rv = 0;
+ break;
+ case ZT_GETRXBITS:
+ put_user(chan->rxsig, (int *)data);
+ rv = 0;
+ break;
+ case ZT_LOOPBACK:
+ get_user(j, (int *)data);
+ spin_lock_irqsave(&chan->lock, flags);
+ if (j)
+ chan->flags |= ZT_FLAG_LOOPED;
+ else
+ chan->flags &= ~ZT_FLAG_LOOPED;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ rv = 0;
+ break;
+ case ZT_HOOK:
+ get_user(j,(int *)data);
+ if (chan->flags & ZT_FLAG_CLEAR)
+ return -EINVAL;
+ if (chan->sig == ZT_SIG_CAS)
+ return -EINVAL;
+ /* if no span, just do nothing */
+ if (!chan->span) return(0);
+ spin_lock_irqsave(&chan->lock, flags);
+ /* if dialing, stop it */
+ chan->curtone = NULL;
+ chan->dialing = 0;
+ chan->txdialbuf[0] = '\0';
+ chan->tonep = 0;
+ chan->pdialcount = 0;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ if (chan->span->flags & ZT_FLAG_RBS) {
+ switch (j) {
+ case ZT_ONHOOK:
+ spin_lock_irqsave(&chan->lock, flags);
+ zt_hangup(chan);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ break;
+ case ZT_OFFHOOK:
+ spin_lock_irqsave(&chan->lock, flags);
+ if ((chan->txstate == ZT_TXSTATE_KEWL) ||
+ (chan->txstate == ZT_TXSTATE_AFTERKEWL)) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EBUSY;
+ }
+ zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_DEBOUNCE, chan->debouncetime);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ break;
+ case ZT_RING:
+ case ZT_START:
+ spin_lock_irqsave(&chan->lock, flags);
+ if (!chan->curzone) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ printk(KERN_WARNING "zaptel: Cannot start tone until a tone zone is loaded.\n");
+ return -ENODATA;
+ }
+ if (chan->txstate != ZT_TXSTATE_ONHOOK) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EBUSY;
+ }
+ if (chan->sig & __ZT_SIG_FXO) {
+ ret = 0;
+ chan->cadencepos = 0;
+ ret = chan->ringcadence[0];
+ zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_RINGON, ret);
+ } else
+ zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_START, chan->starttime);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ if (file->f_flags & O_NONBLOCK)
+ return -EINPROGRESS;
+#if 0
+ rv = schluffen(&chan->txstateq);
+ if (rv) return rv;
+#endif
+ rv = 0;
+ break;
+ case ZT_WINK:
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->txstate != ZT_TXSTATE_ONHOOK) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EBUSY;
+ }
+ zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_PREWINK, chan->prewinktime);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ if (file->f_flags & O_NONBLOCK)
+ return -EINPROGRESS;
+ rv = schluffen(&chan->txstateq);
+ if (rv) return rv;
+ break;
+ case ZT_FLASH:
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->txstate != ZT_TXSTATE_OFFHOOK) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EBUSY;
+ }
+ zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_PREFLASH, chan->preflashtime);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ if (file->f_flags & O_NONBLOCK)
+ return -EINPROGRESS;
+ rv = schluffen(&chan->txstateq);
+ if (rv) return rv;
+ break;
+ case ZT_RINGOFF:
+ spin_lock_irqsave(&chan->lock, flags);
+ zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_ONHOOK, 0);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (chan->span->sethook) {
+ if (chan->txhooksig != j) {
+ chan->txhooksig = j;
+ chan->span->sethook(chan, j);
+ }
+ } else
+ return -ENOSYS;
+ break;
+#ifdef CONFIG_ZAPATA_PPP
+ case PPPIOCGCHAN:
+ if (chan->flags & ZT_FLAG_PPP)
+ return put_user(ppp_channel_index(chan->ppp), (int *)data) ? -EFAULT : 0;
+ else
+ return -EINVAL;
+ break;
+ case PPPIOCGUNIT:
+ if (chan->flags & ZT_FLAG_PPP)
+ return put_user(ppp_unit_number(chan->ppp), (int *)data) ? -EFAULT : 0;
+ else
+ return -EINVAL;
+ break;
+#endif
+ default:
+ return zt_chanandpseudo_ioctl(inode, file, cmd, data, unit);
+ }
+ return 0;
+}
+
+static int zt_prechan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit)
+{
+ struct zt_chan *chan = file->private_data;
+ int channo;
+ int res;
+
+ if (chan) {
+ printk("Huh? Prechan already has private data??\n");
+ }
+ switch(cmd) {
+ case ZT_SPECIFY:
+ get_user(channo,(int *)data);
+ if (channo < 1)
+ return -EINVAL;
+ if (channo > ZT_MAX_CHANNELS)
+ return -EINVAL;
+ res = zt_specchan_open(inode, file, channo, 0);
+ if (!res) {
+ /* Setup the pointer for future stuff */
+ chan = chans[channo];
+ file->private_data = chan;
+ /* Return success */
+ return 0;
+ }
+ return res;
+ default:
+ return -ENOSYS;
+ }
+ return 0;
+}
+
+static int zt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
+{
+ int unit = UNIT(file);
+ struct zt_chan *chan;
+ struct zt_timer *timer;
+
+ if (!unit)
+ return zt_ctl_ioctl(inode, file, cmd, data);
+
+ if (unit == 250)
+ return zt_transcode_fops->ioctl(inode, file, cmd, data);
+
+ if (unit == 253) {
+ timer = file->private_data;
+ if (timer)
+ return zt_timer_ioctl(inode, file, cmd, data, timer);
+ else
+ return -EINVAL;
+ }
+ if (unit == 254) {
+ chan = file->private_data;
+ if (chan)
+ return zt_chan_ioctl(inode, file, cmd, data, chan->channo);
+ else
+ return zt_prechan_ioctl(inode, file, cmd, data, unit);
+ }
+ if (unit == 255) {
+ chan = file->private_data;
+ if (!chan) {
+ printk("No pseudo channel structure to read?\n");
+ return -EINVAL;
+ }
+ return zt_chanandpseudo_ioctl(inode, file, cmd, data, chan->channo);
+ }
+ return zt_chan_ioctl(inode, file, cmd, data, unit);
+}
+
+int zt_register(struct zt_span *span, int prefmaster)
+{
+ int x;
+
+#ifdef CONFIG_PROC_FS
+ char tempfile[17];
+#endif
+ if (!span)
+ return -EINVAL;
+ if (span->flags & ZT_FLAG_REGISTERED) {
+ printk(KERN_ERR "Span %s already appears to be registered\n", span->name);
+ return -EBUSY;
+ }
+ for (x=1;x<maxspans;x++)
+ if (spans[x] == span) {
+ printk(KERN_ERR "Span %s already in list\n", span->name);
+ return -EBUSY;
+ }
+ for (x=1;x<ZT_MAX_SPANS;x++)
+ if (!spans[x])
+ break;
+ if (x < ZT_MAX_SPANS) {
+ spans[x] = span;
+ if (maxspans < x + 1)
+ maxspans = x + 1;
+ } else {
+ printk(KERN_ERR "Too many zapata spans registered\n");
+ return -EBUSY;
+ }
+ span->flags |= ZT_FLAG_REGISTERED;
+ span->spanno = x;
+ spin_lock_init(&span->lock);
+ if (!span->deflaw) {
+ printk("zaptel: Span %s didn't specify default law. Assuming mulaw, please fix driver!\n", span->name);
+ span->deflaw = ZT_LAW_MULAW;
+ }
+
+ if (span->echocan && span->echocan_with_params) {
+ printk("zaptel: Span %s implements both echocan and echocan_with_params functions, preserving only echocan_with_params, please fix driver!\n", span->name);
+ span->echocan = NULL;
+ }
+
+ for (x=0;x<span->channels;x++) {
+ span->chans[x].span = span;
+ zt_chan_reg(&span->chans[x]);
+ }
+
+#ifdef CONFIG_PROC_FS
+ sprintf(tempfile, "zaptel/%d", span->spanno);
+ proc_entries[span->spanno] = create_proc_read_entry(tempfile, 0444, NULL , zaptel_proc_read, (int *)(long)span->spanno);
+#endif
+
+#ifdef CONFIG_DEVFS_FS
+ {
+ char span_name[50];
+ sprintf(span_name, "span%d", span->spanno);
+ span->dhandle = devfs_mk_dir(zaptel_devfs_dir, span_name, NULL);
+ for (x = 0; x < span->channels; x++) {
+ struct zt_chan *chan = &span->chans[x];
+ chan->fhandle = register_devfs_channel(chan, chan->span->dhandle); /* Register our stuff with devfs */
+ }
+ }
+#endif /* CONFIG_DEVFS_FS */
+
+#ifdef CONFIG_ZAP_UDEV
+ for (x = 0; x < span->channels; x++) {
+ char chan_name[50];
+ if (span->chans[x].channo < 250) {
+ sprintf(chan_name, "zap%d", span->chans[x].channo);
+ CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, span->chans[x].channo), NULL, chan_name);
+ }
+ }
+#endif /* CONFIG_ZAP_UDEV */
+
+ if (debug)
+ printk("Registered Span %d ('%s') with %d channels\n", span->spanno, span->name, span->channels);
+ if (!master || prefmaster) {
+ master = span;
+ if (debug)
+ printk("Span ('%s') is new master\n", span->name);
+ }
+ return 0;
+}
+
+int zt_unregister(struct zt_span *span)
+{
+ int x;
+ int new_maxspans;
+ static struct zt_span *new_master;
+
+#ifdef CONFIG_PROC_FS
+ char tempfile[17];
+#endif /* CONFIG_PROC_FS */
+
+ if (!(span->flags & ZT_FLAG_REGISTERED)) {
+ printk(KERN_ERR "Span %s does not appear to be registered\n", span->name);
+ return -1;
+ }
+ /* Shutdown the span if it's running */
+ if (span->flags & ZT_FLAG_RUNNING)
+ if (span->shutdown)
+ span->shutdown(span);
+
+ if (spans[span->spanno] != span) {
+ printk(KERN_ERR "Span %s has spanno %d which is something else\n", span->name, span->spanno);
+ return -1;
+ }
+ if (debug)
+ printk("Unregistering Span '%s' with %d channels\n", span->name, span->channels);
+#ifdef CONFIG_PROC_FS
+ sprintf(tempfile, "zaptel/%d", span->spanno);
+ remove_proc_entry(tempfile, NULL);
+#endif /* CONFIG_PROC_FS */
+#ifdef CONFIG_DEVFS_FS
+ for (x = 0; x < span->channels; x++) {
+ devfs_unregister(span->chans[x].fhandle);
+ devfs_unregister(span->chans[x].fhandle_symlink);
+ }
+ devfs_unregister(span->dhandle);
+#endif /* CONFIG_DEVFS_FS */
+
+#ifdef CONFIG_ZAP_UDEV
+ for (x = 0; x < span->channels; x++) {
+ if (span->chans[x].channo < 250)
+ class_device_destroy(zap_class, MKDEV(ZT_MAJOR, span->chans[x].channo));
+ }
+#endif /* CONFIG_ZAP_UDEV */
+
+ spans[span->spanno] = NULL;
+ span->spanno = 0;
+ span->flags &= ~ZT_FLAG_REGISTERED;
+ for (x=0;x<span->channels;x++)
+ zt_chan_unreg(&span->chans[x]);
+ new_maxspans = 0;
+ new_master = master; /* FIXME: locking */
+ if (master == span)
+ new_master = NULL;
+ for (x=1;x<ZT_MAX_SPANS;x++) {
+ if (spans[x]) {
+ new_maxspans = x+1;
+ if (!new_master)
+ new_master = spans[x];
+ }
+ }
+ maxspans = new_maxspans;
+ if (master != new_master)
+ if (debug)
+ printk("%s: Span ('%s') is new master\n", __FUNCTION__,
+ (new_master)? new_master->name: "no master");
+ master = new_master;
+
+ return 0;
+}
+
+/*
+** This routine converts from linear to ulaw
+**
+** Craig Reese: IDA/Supercomputing Research Center
+** Joe Campbell: Department of Defense
+** 29 September 1989
+**
+** References:
+** 1) CCITT Recommendation G.711 (very difficult to follow)
+** 2) "A New Digital Technique for Implementation of Any
+** Continuous PCM Companding Law," Villeret, Michel,
+** et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
+** 1973, pg. 11.12-11.17
+** 3) MIL-STD-188-113,"Interoperability and Performance Standards
+** for Analog-to_Digital Conversion Techniques,"
+** 17 February 1987
+**
+** Input: Signed 16 bit linear sample
+** Output: 8 bit ulaw sample
+*/
+
+#define ZEROTRAP /* turn on the trap as per the MIL-STD */
+#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
+#define CLIP 32635
+
+#ifdef CONFIG_CALC_XLAW
+unsigned char
+#else
+static unsigned char __init
+#endif
+__zt_lineartoulaw(short sample)
+{
+ static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
+ int sign, exponent, mantissa;
+ unsigned char ulawbyte;
+
+ /* Get the sample into sign-magnitude. */
+ sign = (sample >> 8) & 0x80; /* set aside the sign */
+ if (sign != 0) sample = -sample; /* get magnitude */
+ if (sample > CLIP) sample = CLIP; /* clip the magnitude */
+
+ /* Convert from 16 bit linear to ulaw. */
+ sample = sample + BIAS;
+ exponent = exp_lut[(sample >> 7) & 0xFF];
+ mantissa = (sample >> (exponent + 3)) & 0x0F;
+ ulawbyte = ~(sign | (exponent << 4) | mantissa);
+#ifdef ZEROTRAP
+ if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */
+#endif
+ if (ulawbyte == 0xff) ulawbyte = 0x7f; /* never return 0xff */
+ return(ulawbyte);
+}
+
+#define AMI_MASK 0x55
+
+#ifdef CONFIG_CALC_XLAW
+unsigned char
+#else
+static inline unsigned char __init
+#endif
+__zt_lineartoalaw (short linear)
+{
+ int mask;
+ int seg;
+ int pcm_val;
+ static int seg_end[8] =
+ {
+ 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
+ };
+
+ pcm_val = linear;
+ if (pcm_val >= 0)
+ {
+ /* Sign (7th) bit = 1 */
+ mask = AMI_MASK | 0x80;
+ }
+ else
+ {
+ /* Sign bit = 0 */
+ mask = AMI_MASK;
+ pcm_val = -pcm_val;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ for (seg = 0; seg < 8; seg++)
+ {
+ if (pcm_val <= seg_end[seg])
+ break;
+ }
+ /* Combine the sign, segment, and quantization bits. */
+ return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask;
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline short int __init alaw2linear (uint8_t alaw)
+{
+ int i;
+ int seg;
+
+ alaw ^= AMI_MASK;
+ i = ((alaw & 0x0F) << 4);
+ seg = (((int) alaw & 0x70) >> 4);
+ if (seg)
+ i = (i + 0x100) << (seg - 1);
+ return (short int) ((alaw & 0x80) ? i : -i);
+}
+/*- End of function --------------------------------------------------------*/
+static void __init zt_conv_init(void)
+{
+ int i;
+
+ /*
+ * Set up mu-law conversion table
+ */
+ for(i = 0;i < 256;i++)
+ {
+ short mu,e,f,y;
+ static short etab[]={0,132,396,924,1980,4092,8316,16764};
+
+ mu = 255-i;
+ e = (mu & 0x70)/16;
+ f = mu & 0x0f;
+ y = f * (1 << (e + 3));
+ y += etab[e];
+ if (mu & 0x80) y = -y;
+ __zt_mulaw[i] = y;
+ __zt_alaw[i] = alaw2linear(i);
+ /* Default (0.0 db) gain table */
+ defgain[i] = i;
+ }
+#ifndef CONFIG_CALC_XLAW
+ /* set up the reverse (mu-law) conversion table */
+ for(i = -32768; i < 32768; i += 4)
+ {
+ __zt_lin2mu[((unsigned short)(short)i) >> 2] = __zt_lineartoulaw(i);
+ __zt_lin2a[((unsigned short)(short)i) >> 2] = __zt_lineartoalaw(i);
+ }
+#endif
+}
+
+static inline void __zt_process_getaudio_chunk(struct zt_chan *ss, unsigned char *txb)
+{
+ /* We transmit data from our master channel */
+ /* Called with ss->lock held */
+ struct zt_chan *ms = ss->master;
+ /* Linear representation */
+ short getlin[ZT_CHUNKSIZE], k[ZT_CHUNKSIZE];
+ int x;
+
+ /* Okay, now we've got something to transmit */
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ getlin[x] = ZT_XLAW(txb[x], ms);
+#ifndef NO_ECHOCAN_DISABLE
+ if (ms->ec) {
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ /* Check for echo cancel disabling tone */
+ if (echo_can_disable_detector_update(&ms->txecdis, getlin[x])) {
+ printk("zaptel Disabled echo canceller because of tone (tx) on channel %d\n", ss->channo);
+ ms->echocancel = 0;
+ ms->echostate = ECHO_STATE_IDLE;
+ ms->echolastupdate = 0;
+ ms->echotimer = 0;
+ echo_can_free(ms->ec);
+ ms->ec = NULL;
+ __qevent(ss, ZT_EVENT_EC_DISABLED);
+ break;
+ }
+ }
+ }
+#endif
+ if ((!ms->confmute && !ms->dialing) || (ms->flags & ZT_FLAG_PSEUDO)) {
+ /* Handle conferencing on non-clear channel and non-HDLC channels */
+ switch(ms->confmode & ZT_CONF_MODE_MASK) {
+ case ZT_CONF_NORMAL:
+ /* Do nuffin */
+ break;
+ case ZT_CONF_MONITOR: /* Monitor a channel's rx mode */
+ /* if a pseudo-channel, ignore */
+ if (ms->flags & ZT_FLAG_PSEUDO) break;
+ /* Add monitored channel */
+ if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
+ ACSS(getlin, chans[ms->confna]->getlin);
+ } else {
+ ACSS(getlin, chans[ms->confna]->putlin);
+ }
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
+ break;
+ case ZT_CONF_MONITORTX: /* Monitor a channel's tx mode */
+ /* if a pseudo-channel, ignore */
+ if (ms->flags & ZT_FLAG_PSEUDO) break;
+ /* Add monitored channel */
+ if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
+ ACSS(getlin, chans[ms->confna]->putlin);
+ } else {
+ ACSS(getlin, chans[ms->confna]->getlin);
+ }
+
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
+ break;
+ case ZT_CONF_MONITORBOTH: /* monitor a channel's rx and tx mode */
+ /* if a pseudo-channel, ignore */
+ if (ms->flags & ZT_FLAG_PSEUDO) break;
+ ACSS(getlin, chans[ms->confna]->putlin);
+ ACSS(getlin, chans[ms->confna]->getlin);
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
+ break;
+ case ZT_CONF_MONITOR_RX_PREECHO: /* Monitor a channel's rx mode */
+ /* if a pseudo-channel, ignore */
+ if (ms->flags & ZT_FLAG_PSEUDO)
+ break;
+
+ if (!chans[ms->confna]->readchunkpreec)
+ break;
+
+ /* Add monitored channel */
+ ACSS(getlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ?
+ chans[ms->confna]->readchunkpreec : chans[ms->confna]->putlin);
+ for (x = 0; x < ZT_CHUNKSIZE; x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
+
+ break;
+ case ZT_CONF_MONITOR_TX_PREECHO: /* Monitor a channel's tx mode */
+ /* if a pseudo-channel, ignore */
+ if (ms->flags & ZT_FLAG_PSEUDO)
+ break;
+
+ if (!chans[ms->confna]->readchunkpreec)
+ break;
+
+ /* Add monitored channel */
+ ACSS(getlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ?
+ chans[ms->confna]->putlin : chans[ms->confna]->readchunkpreec);
+ for (x = 0; x < ZT_CHUNKSIZE; x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
+
+ break;
+ case ZT_CONF_MONITORBOTH_PREECHO: /* monitor a channel's rx and tx mode */
+ /* if a pseudo-channel, ignore */
+ if (ms->flags & ZT_FLAG_PSEUDO)
+ break;
+
+ if (!chans[ms->confna]->readchunkpreec)
+ break;
+
+ ACSS(getlin, chans[ms->confna]->putlin);
+ ACSS(getlin, chans[ms->confna]->readchunkpreec);
+
+ for (x = 0; x < ZT_CHUNKSIZE; x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
+
+ break;
+ case ZT_CONF_REALANDPSEUDO:
+ /* This strange mode takes the transmit buffer and
+ puts it on the conference, minus its last sample,
+ then outputs from the conference minus the
+ real channel's last sample. */
+ /* if to talk on conf */
+ if (ms->confmode & ZT_CONF_PSEUDO_TALKER) {
+ /* Store temp value */
+ memcpy(k, getlin, ZT_CHUNKSIZE * sizeof(short));
+ /* Add conf value */
+ ACSS(k, conf_sums_next[ms->_confn]);
+ /* save last one */
+ memcpy(ms->conflast2, ms->conflast1, ZT_CHUNKSIZE * sizeof(short));
+ memcpy(ms->conflast1, k, ZT_CHUNKSIZE * sizeof(short));
+ /* get amount actually added */
+ SCSS(ms->conflast1, conf_sums_next[ms->_confn]);
+ /* Really add in new value */
+ ACSS(conf_sums_next[ms->_confn], ms->conflast1);
+ } else {
+ memset(ms->conflast1, 0, ZT_CHUNKSIZE * sizeof(short));
+ memset(ms->conflast2, 0, ZT_CHUNKSIZE * sizeof(short));
+ }
+ memset(getlin, 0, ZT_CHUNKSIZE * sizeof(short));
+ txb[0] = ZT_LIN2X(0, ms);
+ memset(txb + 1, txb[0], ZT_CHUNKSIZE - 1);
+ /* fall through to normal conf mode */
+ case ZT_CONF_CONF: /* Normal conference mode */
+ if (ms->flags & ZT_FLAG_PSEUDO) /* if pseudo-channel */
+ {
+ /* if to talk on conf */
+ if (ms->confmode & ZT_CONF_TALKER) {
+ /* Store temp value */
+ memcpy(k, getlin, ZT_CHUNKSIZE * sizeof(short));
+ /* Add conf value */
+ ACSS(k, conf_sums[ms->_confn]);
+ /* get amount actually added */
+ memcpy(ms->conflast, k, ZT_CHUNKSIZE * sizeof(short));
+ SCSS(ms->conflast, conf_sums[ms->_confn]);
+ /* Really add in new value */
+ ACSS(conf_sums[ms->_confn], ms->conflast);
+ memcpy(ms->getlin, getlin, ZT_CHUNKSIZE * sizeof(short));
+ } else {
+ memset(ms->conflast, 0, ZT_CHUNKSIZE * sizeof(short));
+ memcpy(getlin, ms->getlin, ZT_CHUNKSIZE * sizeof(short));
+ }
+ txb[0] = ZT_LIN2X(0, ms);
+ memset(txb + 1, txb[0], ZT_CHUNKSIZE - 1);
+ break;
+ }
+ /* fall through */
+ case ZT_CONF_CONFMON: /* Conference monitor mode */
+ if (ms->confmode & ZT_CONF_LISTENER) {
+ /* Subtract out last sample written to conf */
+ SCSS(getlin, ms->conflast);
+ /* Add in conference */
+ ACSS(getlin, conf_sums[ms->_confn]);
+ }
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
+ break;
+ case ZT_CONF_CONFANN:
+ case ZT_CONF_CONFANNMON:
+ /* First, add tx buffer to conf */
+ ACSS(conf_sums_next[ms->_confn], getlin);
+ /* Start with silence */
+ memset(getlin, 0, ZT_CHUNKSIZE * sizeof(short));
+ /* If a listener on the conf... */
+ if (ms->confmode & ZT_CONF_LISTENER) {
+ /* Subtract last value written */
+ SCSS(getlin, ms->conflast);
+ /* Add in conf */
+ ACSS(getlin, conf_sums[ms->_confn]);
+ }
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
+ break;
+ case ZT_CONF_DIGITALMON:
+ /* Real digital monitoring, but still echo cancel if desired */
+ if (!chans[ms->confna])
+ break;
+ if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
+ if (ms->ec) {
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(chans[ms->confna]->getlin[x], ms);
+ } else {
+ memcpy(txb, chans[ms->confna]->getraw, ZT_CHUNKSIZE);
+ }
+ } else {
+ if (ms->ec) {
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(chans[ms->confna]->putlin[x], ms);
+ } else {
+ memcpy(txb, chans[ms->confna]->putraw, ZT_CHUNKSIZE);
+ }
+ }
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ getlin[x] = ZT_XLAW(txb[x], ms);
+ break;
+ }
+ }
+ if (ms->confmute || (ms->echostate & __ECHO_STATE_MUTE)) {
+ txb[0] = ZT_LIN2X(0, ms);
+ memset(txb + 1, txb[0], ZT_CHUNKSIZE - 1);
+ if (ms->echostate == ECHO_STATE_STARTTRAINING) {
+ /* Transmit impulse now */
+ txb[0] = ZT_LIN2X(16384, ms);
+ ms->echostate = ECHO_STATE_AWAITINGECHO;
+ }
+ }
+ /* save value from last chunk */
+ memcpy(ms->getlin_lastchunk, ms->getlin, ZT_CHUNKSIZE * sizeof(short));
+ /* save value from current */
+ memcpy(ms->getlin, getlin, ZT_CHUNKSIZE * sizeof(short));
+ /* save value from current */
+ memcpy(ms->getraw, txb, ZT_CHUNKSIZE);
+ /* if to make tx tone */
+ if (ms->v1_1 || ms->v2_1 || ms->v3_1)
+ {
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ {
+ getlin[x] += zt_txtone_nextsample(ms);
+ txb[x] = ZT_LIN2X(getlin[x], ms);
+ }
+ }
+ /* This is what to send (after having applied gain) */
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ms->txgain[txb[x]];
+}
+
+static inline void __zt_getbuf_chunk(struct zt_chan *ss, unsigned char *txb)
+{
+ /* Called with ss->lock held */
+ /* We transmit data from our master channel */
+ struct zt_chan *ms = ss->master;
+ /* Buffer we're using */
+ unsigned char *buf;
+ /* Old buffer number */
+ int oldbuf;
+ /* Linear representation */
+ int getlin;
+ /* How many bytes we need to process */
+ int bytes = ZT_CHUNKSIZE, left;
+ int x;
+
+ /* Let's pick something to transmit. First source to
+ try is our write-out buffer. Always check it first because
+ its our 'fast path' for whatever that's worth. */
+ while(bytes) {
+ if ((ms->outwritebuf > -1) && !ms->txdisable) {
+ buf= ms->writebuf[ms->outwritebuf];
+ left = ms->writen[ms->outwritebuf] - ms->writeidx[ms->outwritebuf];
+ if (left > bytes)
+ left = bytes;
+ if (ms->flags & ZT_FLAG_HDLC) {
+ /* If this is an HDLC channel we only send a byte of
+ HDLC. */
+ for(x=0;x<left;x++) {
+ if (ms->txhdlc.bits < 8)
+ /* Load a byte of data only if needed */
+ fasthdlc_tx_load_nocheck(&ms->txhdlc, buf[ms->writeidx[ms->outwritebuf]++]);
+ *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc);
+ }
+ bytes -= left;
+ } else {
+ memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left);
+ ms->writeidx[ms->outwritebuf]+=left;
+ txb += left;
+ bytes -= left;
+ }
+ /* Check buffer status */
+ if (ms->writeidx[ms->outwritebuf] >= ms->writen[ms->outwritebuf]) {
+ /* We've reached the end of our buffer. Go to the next. */
+ oldbuf = ms->outwritebuf;
+ /* Clear out write index and such */
+ ms->writeidx[oldbuf] = 0;
+ ms->outwritebuf = (ms->outwritebuf + 1) % ms->numbufs;
+
+ if (!(ms->flags & ZT_FLAG_MTP2)) {
+ ms->writen[oldbuf] = 0;
+ if (ms->outwritebuf == ms->inwritebuf) {
+ /* Whoopsies, we're run out of buffers. Mark ours
+ as -1 and wait for the filler to notify us that
+ there is something to write */
+ ms->outwritebuf = -1;
+ if (ms->iomask & (ZT_IOMUX_WRITE | ZT_IOMUX_WRITEEMPTY))
+ wake_up_interruptible(&ms->eventbufq);
+ /* If we're only supposed to start when full, disable the transmitter */
+ if (ms->txbufpolicy == ZT_POLICY_WHEN_FULL)
+ ms->txdisable = 1;
+ }
+ } else {
+ if (ms->outwritebuf == ms->inwritebuf) {
+ ms->outwritebuf = oldbuf;
+ if (ms->iomask & (ZT_IOMUX_WRITE | ZT_IOMUX_WRITEEMPTY))
+ wake_up_interruptible(&ms->eventbufq);
+ /* If we're only supposed to start when full, disable the transmitter */
+ if (ms->txbufpolicy == ZT_POLICY_WHEN_FULL)
+ ms->txdisable = 1;
+ }
+ }
+ if (ms->inwritebuf < 0) {
+ /* The filler doesn't have a place to put data. Now
+ that we're done with this buffer, notify them. */
+ ms->inwritebuf = oldbuf;
+ }
+/* In the very orignal driver, it was quite well known to me (Jim) that there
+was a possibility that a channel sleeping on a write block needed to
+be potentially woken up EVERY time a buffer was emptied, not just on the first
+one, because if only done on the first one there is a slight timing potential
+of missing the wakeup (between where it senses the (lack of) active condition
+(with interrupts disabled) and where it does the sleep (interrupts enabled)
+in the read or iomux call, etc). That is why the write and iomux calls start
+with an infinite loop that gets broken out of upon an active condition,
+otherwise keeps sleeping and looking. The part in this code got "optimized"
+out in the later versions, and is put back now. */
+ if (!(ms->flags & (ZT_FLAG_NETDEV | ZT_FLAG_PPP))) {
+ wake_up_interruptible(&ms->writebufq);
+ wake_up_interruptible(&ms->sel);
+ if (ms->iomask & ZT_IOMUX_WRITE)
+ wake_up_interruptible(&ms->eventbufq);
+ }
+ /* Transmit a flag if this is an HDLC channel */
+ if (ms->flags & ZT_FLAG_HDLC)
+ fasthdlc_tx_frame_nocheck(&ms->txhdlc);
+#ifdef CONFIG_ZAPATA_NET
+ if (ms->flags & ZT_FLAG_NETDEV)
+ netif_wake_queue(ztchan_to_dev(ms));
+#endif
+#ifdef CONFIG_ZAPATA_PPP
+ if (ms->flags & ZT_FLAG_PPP) {
+ ms->do_ppp_wakeup = 1;
+ tasklet_schedule(&ms->ppp_calls);
+ }
+#endif
+ }
+ } else if (ms->curtone && !(ms->flags & ZT_FLAG_PSEUDO)) {
+ left = ms->curtone->tonesamples - ms->tonep;
+ if (left > bytes)
+ left = bytes;
+ for (x=0;x<left;x++) {
+ /* Pick our default value from the next sample of the current tone */
+ getlin = zt_tone_nextsample(&ms->ts, ms->curtone);
+ *(txb++) = ZT_LIN2X(getlin, ms);
+ }
+ ms->tonep+=left;
+ bytes -= left;
+ if (ms->tonep >= ms->curtone->tonesamples) {
+ struct zt_tone *last;
+ /* Go to the next sample of the tone */
+ ms->tonep = 0;
+ last = ms->curtone;
+ ms->curtone = ms->curtone->next;
+ if (!ms->curtone) {
+ /* No more tones... Is this dtmf or mf? If so, go to the next digit */
+ if (ms->dialing)
+ __do_dtmf(ms);
+ } else {
+ if (last != ms->curtone)
+ zt_init_tone_state(&ms->ts, ms->curtone);
+ }
+ }
+ } else if (ms->flags & ZT_FLAG_LOOPED) {
+ for (x = 0; x < bytes; x++)
+ txb[x] = ms->readchunk[x];
+ bytes = 0;
+ } else if (ms->flags & ZT_FLAG_HDLC) {
+ for (x=0;x<bytes;x++) {
+ /* Okay, if we're HDLC, then transmit a flag by default */
+ if (ms->txhdlc.bits < 8)
+ fasthdlc_tx_frame_nocheck(&ms->txhdlc);
+ *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc);
+ }
+ bytes = 0;
+ } else if (ms->flags & ZT_FLAG_CLEAR) {
+ /* Clear channels that are idle in audio mode need
+ to send silence; in non-audio mode, always send 0xff
+ so stupid switches won't consider the channel active
+ */
+ if (ms->flags & ZT_FLAG_AUDIO) {
+ memset(txb, ZT_LIN2X(0, ms), bytes);
+ } else {
+ memset(txb, 0xFF, bytes);
+ }
+ bytes = 0;
+ } else {
+ memset(txb, ZT_LIN2X(0, ms), bytes); /* Lastly we use silence on telephony channels */
+ bytes = 0;
+ }
+ }
+}
+
+static inline void rbs_itimer_expire(struct zt_chan *chan)
+{
+ /* the only way this could have gotten here, is if a channel
+ went onf hook longer then the wink or flash detect timeout */
+ /* Called with chan->lock held */
+ switch(chan->sig)
+ {
+ case ZT_SIG_FXOLS: /* if FXO, its definitely on hook */
+ case ZT_SIG_FXOGS:
+ case ZT_SIG_FXOKS:
+ __qevent(chan,ZT_EVENT_ONHOOK);
+ chan->gotgs = 0;
+ break;
+#if defined(EMFLASH) || defined(EMPULSE)
+ case ZT_SIG_EM:
+ case ZT_SIG_EM_E1:
+ if (chan->rxhooksig == ZT_RXSIG_ONHOOK) {
+ __qevent(chan,ZT_EVENT_ONHOOK);
+ break;
+ }
+ __qevent(chan,ZT_EVENT_RINGOFFHOOK);
+ break;
+#endif
+#ifdef FXSFLASH
+ case ZT_SIG_FXSKS:
+ if (chan->rxhooksig == ZT_RXSIG_ONHOOK) {
+ __qevent(chan, ZT_EVENT_ONHOOK);
+ break;
+ }
+#endif
+ /* fall thru intentionally */
+ default: /* otherwise, its definitely off hook */
+ __qevent(chan,ZT_EVENT_RINGOFFHOOK);
+ break;
+ }
+}
+
+static inline void __rbs_otimer_expire(struct zt_chan *chan)
+{
+ int len = 0;
+ /* Called with chan->lock held */
+
+ chan->otimer = 0;
+ /* Move to the next timer state */
+ switch(chan->txstate) {
+ case ZT_TXSTATE_RINGOFF:
+ /* Turn on the ringer now that the silent time has passed */
+ ++chan->cadencepos;
+ if (chan->cadencepos >= ZT_MAX_CADENCE)
+ chan->cadencepos = chan->firstcadencepos;
+ len = chan->ringcadence[chan->cadencepos];
+
+ if (!len) {
+ chan->cadencepos = chan->firstcadencepos;
+ len = chan->ringcadence[chan->cadencepos];
+ }
+
+ zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_RINGON, len);
+ __qevent(chan, ZT_EVENT_RINGERON);
+ break;
+
+ case ZT_TXSTATE_RINGON:
+ /* Turn off the ringer now that the loud time has passed */
+ ++chan->cadencepos;
+ if (chan->cadencepos >= ZT_MAX_CADENCE)
+ chan->cadencepos = 0;
+ len = chan->ringcadence[chan->cadencepos];
+
+ if (!len) {
+ chan->cadencepos = 0;
+ len = chan->curzone->ringcadence[chan->cadencepos];
+ }
+
+ zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_RINGOFF, len);
+ __qevent(chan, ZT_EVENT_RINGEROFF);
+ break;
+
+ case ZT_TXSTATE_START:
+ /* If we were starting, go off hook now ready to debounce */
+ zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_AFTERSTART, ZT_AFTERSTART_TIME);
+ wake_up_interruptible(&chan->txstateq);
+ break;
+
+ case ZT_TXSTATE_PREWINK:
+ /* Actually wink */
+ zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_WINK, chan->winktime);
+ break;
+
+ case ZT_TXSTATE_WINK:
+ /* Wink complete, go on hook and stabalize */
+ zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_ONHOOK, 0);
+ if (chan->file && (chan->file->f_flags & O_NONBLOCK))
+ __qevent(chan, ZT_EVENT_HOOKCOMPLETE);
+ wake_up_interruptible(&chan->txstateq);
+ break;
+
+ case ZT_TXSTATE_PREFLASH:
+ /* Actually flash */
+ zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_FLASH, chan->flashtime);
+ break;
+
+ case ZT_TXSTATE_FLASH:
+ zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_OFFHOOK, 0);
+ if (chan->file && (chan->file->f_flags & O_NONBLOCK))
+ __qevent(chan, ZT_EVENT_HOOKCOMPLETE);
+ wake_up_interruptible(&chan->txstateq);
+ break;
+
+ case ZT_TXSTATE_DEBOUNCE:
+ zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_OFFHOOK, 0);
+ /* See if we've gone back on hook */
+ if ((chan->rxhooksig == ZT_RXSIG_ONHOOK) && (chan->rxflashtime > 2))
+ chan->itimerset = chan->itimer = chan->rxflashtime * ZT_CHUNKSIZE;
+ wake_up_interruptible(&chan->txstateq);
+ break;
+
+ case ZT_TXSTATE_AFTERSTART:
+ zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_OFFHOOK, 0);
+ if (chan->file && (chan->file->f_flags & O_NONBLOCK))
+ __qevent(chan, ZT_EVENT_HOOKCOMPLETE);
+ wake_up_interruptible(&chan->txstateq);
+ break;
+
+ case ZT_TXSTATE_KEWL:
+ zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_AFTERKEWL, ZT_AFTERKEWLTIME);
+ if (chan->file && (chan->file->f_flags & O_NONBLOCK))
+ __qevent(chan, ZT_EVENT_HOOKCOMPLETE);
+ wake_up_interruptible(&chan->txstateq);
+ break;
+
+ case ZT_TXSTATE_AFTERKEWL:
+ if (chan->kewlonhook) {
+ __qevent(chan,ZT_EVENT_ONHOOK);
+ }
+ chan->txstate = ZT_TXSTATE_ONHOOK;
+ chan->gotgs = 0;
+ break;
+
+ case ZT_TXSTATE_PULSEBREAK:
+ zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_PULSEMAKE,
+ chan->pulsemaketime);
+ wake_up_interruptible(&chan->txstateq);
+ break;
+
+ case ZT_TXSTATE_PULSEMAKE:
+ if (chan->pdialcount)
+ chan->pdialcount--;
+ if (chan->pdialcount)
+ {
+ zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK,
+ ZT_TXSTATE_PULSEBREAK, chan->pulsebreaktime);
+ break;
+ }
+ chan->txstate = ZT_TXSTATE_PULSEAFTER;
+ chan->otimer = chan->pulseaftertime * ZT_CHUNKSIZE;
+ wake_up_interruptible(&chan->txstateq);
+ break;
+
+ case ZT_TXSTATE_PULSEAFTER:
+ chan->txstate = ZT_TXSTATE_OFFHOOK;
+ __do_dtmf(chan);
+ wake_up_interruptible(&chan->txstateq);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void __zt_hooksig_pvt(struct zt_chan *chan, zt_rxsig_t rxsig)
+{
+
+ /* State machines for receive hookstate transitions
+ called with chan->lock held */
+
+ if ((chan->rxhooksig) == rxsig) return;
+
+ if ((chan->flags & ZT_FLAG_SIGFREEZE)) return;
+
+ chan->rxhooksig = rxsig;
+#ifdef RINGBEGIN
+ if ((chan->sig & __ZT_SIG_FXS) && (rxsig == ZT_RXSIG_RING) &&
+ (!chan->ringdebtimer))
+ __qevent(chan,ZT_EVENT_RINGBEGIN);
+#endif
+ switch(chan->sig) {
+ case ZT_SIG_EM: /* E and M */
+ case ZT_SIG_EM_E1:
+ switch(rxsig) {
+ case ZT_RXSIG_OFFHOOK: /* went off hook */
+ /* The interface is going off hook */
+#ifdef EMFLASH
+ if (chan->itimer)
+ {
+ __qevent(chan,ZT_EVENT_WINKFLASH);
+ chan->itimerset = chan->itimer = 0;
+ break;
+ }
+#endif
+#ifdef EMPULSE
+ if (chan->itimer) /* if timer still running */
+ {
+ int plen = chan->itimerset - chan->itimer;
+ if (plen <= ZT_MAXPULSETIME)
+ {
+ if (plen >= ZT_MINPULSETIME)
+ {
+ chan->pulsecount++;
+
+ chan->pulsetimer = ZT_PULSETIMEOUT;
+ chan->itimerset = chan->itimer = 0;
+ if (chan->pulsecount == 1)
+ __qevent(chan,ZT_EVENT_PULSE_START);
+ }
+ }
+ break;
+ }
+#endif
+ /* set wink timer */
+ chan->itimerset = chan->itimer = chan->rxwinktime * ZT_CHUNKSIZE;
+ break;
+ case ZT_RXSIG_ONHOOK: /* went on hook */
+ /* This interface is now going on hook.
+ Check for WINK, etc */
+ if (chan->itimer)
+ __qevent(chan,ZT_EVENT_WINKFLASH);
+#if defined(EMFLASH) || defined(EMPULSE)
+ else {
+#ifdef EMFLASH
+ chan->itimerset = chan->itimer = chan->rxflashtime * ZT_CHUNKSIZE;
+
+#else /* EMFLASH */
+ chan->itimerset = chan->itimer = chan->rxwinktime * ZT_CHUNKSIZE;
+
+#endif /* EMFLASH */
+ chan->gotgs = 0;
+ break;
+ }
+#else /* EMFLASH || EMPULSE */
+ else {
+ __qevent(chan,ZT_EVENT_ONHOOK);
+ chan->gotgs = 0;
+ }
+#endif
+ chan->itimerset = chan->itimer = 0;
+ break;
+ default:
+ break;
+ }
+ break;
+ case ZT_SIG_FXSKS: /* FXS Kewlstart */
+ /* ignore a bit poopy if loop not closed and stable */
+ if (chan->txstate != ZT_TXSTATE_OFFHOOK) break;
+#ifdef FXSFLASH
+ if (rxsig == ZT_RXSIG_ONHOOK) {
+ chan->itimer = ZT_FXSFLASHMAXTIME * ZT_CHUNKSIZE;
+ break;
+ } else if (rxsig == ZT_RXSIG_OFFHOOK) {
+ if (chan->itimer) {
+ /* did the offhook occur in the window? if not, ignore both events */
+ if (chan->itimer <= ((ZT_FXSFLASHMAXTIME - ZT_FXSFLASHMINTIME) * ZT_CHUNKSIZE))
+ __qevent(chan, ZT_EVENT_WINKFLASH);
+ }
+ chan->itimer = 0;
+ break;
+ }
+#endif
+ /* fall through intentionally */
+ case ZT_SIG_FXSGS: /* FXS Groundstart */
+ if (rxsig == ZT_RXSIG_ONHOOK) {
+ chan->ringdebtimer = RING_DEBOUNCE_TIME;
+ chan->ringtrailer = 0;
+ if (chan->txstate != ZT_TXSTATE_DEBOUNCE) {
+ chan->gotgs = 0;
+ __qevent(chan,ZT_EVENT_ONHOOK);
+ }
+ }
+ break;
+ case ZT_SIG_FXOGS: /* FXO Groundstart */
+ if (rxsig == ZT_RXSIG_START) {
+ /* if havent got gs, report it */
+ if (!chan->gotgs) {
+ __qevent(chan,ZT_EVENT_RINGOFFHOOK);
+ chan->gotgs = 1;
+ }
+ }
+ /* fall through intentionally */
+ case ZT_SIG_FXOLS: /* FXO Loopstart */
+ case ZT_SIG_FXOKS: /* FXO Kewlstart */
+ switch(rxsig) {
+ case ZT_RXSIG_OFFHOOK: /* went off hook */
+ /* if asserti ng ring, stop it */
+ if (chan->txstate == ZT_TXSTATE_START) {
+ zt_rbs_sethook(chan,ZT_TXSIG_OFFHOOK, ZT_TXSTATE_AFTERSTART, ZT_AFTERSTART_TIME);
+ }
+ chan->kewlonhook = 0;
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Off hook on channel %d, itimer = %d, gotgs = %d\n", chan->channo, chan->itimer, chan->gotgs);
+#endif
+ if (chan->itimer) /* if timer still running */
+ {
+ int plen = chan->itimerset - chan->itimer;
+ if (plen <= ZT_MAXPULSETIME)
+ {
+ if (plen >= ZT_MINPULSETIME)
+ {
+ chan->pulsecount++;
+ chan->pulsetimer = ZT_PULSETIMEOUT;
+ chan->itimer = chan->itimerset;
+ if (chan->pulsecount == 1)
+ __qevent(chan,ZT_EVENT_PULSE_START);
+ }
+ } else
+ __qevent(chan,ZT_EVENT_WINKFLASH);
+ } else {
+ /* if havent got GS detect */
+ if (!chan->gotgs) {
+ __qevent(chan,ZT_EVENT_RINGOFFHOOK);
+ chan->gotgs = 1;
+ chan->itimerset = chan->itimer = 0;
+ }
+ }
+ chan->itimerset = chan->itimer = 0;
+ break;
+ case ZT_RXSIG_ONHOOK: /* went on hook */
+ /* if not during offhook debounce time */
+ if ((chan->txstate != ZT_TXSTATE_DEBOUNCE) &&
+ (chan->txstate != ZT_TXSTATE_KEWL) &&
+ (chan->txstate != ZT_TXSTATE_AFTERKEWL)) {
+ chan->itimerset = chan->itimer = chan->rxflashtime * ZT_CHUNKSIZE;
+ }
+ if (chan->txstate == ZT_TXSTATE_KEWL)
+ chan->kewlonhook = 1;
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void zt_hooksig(struct zt_chan *chan, zt_rxsig_t rxsig)
+{
+ /* skip if no change */
+ unsigned long flags;
+ spin_lock_irqsave(&chan->lock, flags);
+ __zt_hooksig_pvt(chan,rxsig);
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+void zt_rbsbits(struct zt_chan *chan, int cursig)
+{
+ unsigned long flags;
+ if (cursig == chan->rxsig)
+ return;
+
+ if ((chan->flags & ZT_FLAG_SIGFREEZE)) return;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ switch(chan->sig) {
+ case ZT_SIG_FXOGS: /* FXO Groundstart */
+ /* B-bit only matters for FXO GS */
+ if (!(cursig & ZT_BBIT)) {
+ __zt_hooksig_pvt(chan, ZT_RXSIG_START);
+ break;
+ }
+ /* Fall through */
+ case ZT_SIG_EM: /* E and M */
+ case ZT_SIG_EM_E1:
+ case ZT_SIG_FXOLS: /* FXO Loopstart */
+ case ZT_SIG_FXOKS: /* FXO Kewlstart */
+ if (cursig & ZT_ABIT) /* off hook */
+ __zt_hooksig_pvt(chan,ZT_RXSIG_OFFHOOK);
+ else /* on hook */
+ __zt_hooksig_pvt(chan,ZT_RXSIG_ONHOOK);
+ break;
+
+ case ZT_SIG_FXSKS: /* FXS Kewlstart */
+ case ZT_SIG_FXSGS: /* FXS Groundstart */
+ /* Fall through */
+ case ZT_SIG_FXSLS:
+ if (!(cursig & ZT_BBIT)) {
+ /* Check for ringing first */
+ __zt_hooksig_pvt(chan, ZT_RXSIG_RING);
+ break;
+ }
+ if ((chan->sig != ZT_SIG_FXSLS) && (cursig & ZT_ABIT)) {
+ /* if went on hook */
+ __zt_hooksig_pvt(chan, ZT_RXSIG_ONHOOK);
+ } else {
+ __zt_hooksig_pvt(chan, ZT_RXSIG_OFFHOOK);
+ }
+ break;
+ case ZT_SIG_CAS:
+ /* send event that something changed */
+ __qevent(chan, ZT_EVENT_BITSCHANGED);
+ break;
+
+ default:
+ break;
+ }
+ /* Keep track of signalling for next time */
+ chan->rxsig = cursig;
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+static inline void __zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk)
+{
+ short rxlin, txlin;
+ int x;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ss->lock, flags);
+
+ if (ss->readchunkpreec) {
+ /* Save a copy of the audio before the echo can has its way with it */
+ for (x = 0; x < ZT_CHUNKSIZE; x++)
+ /* We only ever really need to deal with signed linear - let's just convert it now */
+ ss->readchunkpreec[x] = ZT_XLAW(rxchunk[x], ss);
+ }
+
+ /* Perform echo cancellation on a chunk if necessary */
+ if (ss->ec) {
+#if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP)
+ zt_kernel_fpu_begin();
+#endif
+ if (ss->echostate & __ECHO_STATE_MUTE) {
+ /* Special stuff for training the echo can */
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ rxlin = ZT_XLAW(rxchunk[x], ss);
+ txlin = ZT_XLAW(txchunk[x], ss);
+ if (ss->echostate == ECHO_STATE_PRETRAINING) {
+ if (--ss->echotimer <= 0) {
+ ss->echotimer = 0;
+ ss->echostate = ECHO_STATE_STARTTRAINING;
+ }
+ }
+ if ((ss->echostate == ECHO_STATE_AWAITINGECHO) && (txlin > 8000)) {
+ ss->echolastupdate = 0;
+ ss->echostate = ECHO_STATE_TRAINING;
+ }
+ if (ss->echostate == ECHO_STATE_TRAINING) {
+ if (echo_can_traintap(ss->ec, ss->echolastupdate++, rxlin)) {
+#if 0
+ printk("Finished training (%d taps trained)!\n", ss->echolastupdate);
+#endif
+ ss->echostate = ECHO_STATE_ACTIVE;
+ }
+ }
+ rxlin = 0;
+ rxchunk[x] = ZT_LIN2X((int)rxlin, ss);
+ }
+ } else {
+#if !defined(ZT_EC_ARRAY_UPDATE)
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ rxlin = ZT_XLAW(rxchunk[x], ss);
+ rxlin = echo_can_update(ss->ec, ZT_XLAW(txchunk[x], ss), rxlin);
+ rxchunk[x] = ZT_LIN2X((int) rxlin, ss);
+ }
+#else /* defined(ZT_EC_ARRAY_UPDATE) */
+ short rxlins[ZT_CHUNKSIZE], txlins[ZT_CHUNKSIZE];
+ for (x = 0; x < ZT_CHUNKSIZE; x++) {
+ rxlins[x] = ZT_XLAW(rxchunk[x], ss);
+ txlins[x] = ZT_XLAW(txchunk[x], ss);
+ }
+ echo_can_array_update(ss->ec, rxlins, txlins);
+ for (x = 0; x < ZT_CHUNKSIZE; x++)
+ rxchunk[x] = ZT_LIN2X((int) rxlins[x], ss);
+#endif /* defined(ZT_EC_ARRAY_UPDATE) */
+ }
+#if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP)
+ kernel_fpu_end();
+#endif
+ }
+ spin_unlock_irqrestore(&ss->lock, flags);
+}
+
+void zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk)
+{
+ __zt_ec_chunk(ss, rxchunk, txchunk);
+}
+
+void zt_ec_span(struct zt_span *span)
+{
+ int x;
+ for (x = 0; x < span->channels; x++) {
+ if (span->chans[x].ec)
+ __zt_ec_chunk(&span->chans[x], span->chans[x].readchunk, span->chans[x].writechunk);
+ }
+}
+
+/* return 0 if nothing detected, 1 if lack of tone, 2 if presence of tone */
+/* modifies buffer pointed to by 'amp' with notched-out values */
+static inline int sf_detect (sf_detect_state_t *s,
+ short *amp,
+ int samples,long p1, long p2, long p3)
+{
+int i,rv = 0;
+long x,y;
+
+#define SF_DETECT_SAMPLES (ZT_CHUNKSIZE * 5)
+#define SF_DETECT_MIN_ENERGY 500
+#define NB 14 /* number of bits to shift left */
+
+ /* determine energy level before filtering */
+ for(i = 0; i < samples; i++)
+ {
+ if (amp[i] < 0) s->e1 -= amp[i];
+ else s->e1 += amp[i];
+ }
+ /* do 2nd order IIR notch filter at given freq. and calculate
+ energy */
+ for(i = 0; i < samples; i++)
+ {
+ x = amp[i] << NB;
+ y = s->x2 + (p1 * (s->x1 >> NB)) + x;
+ y += (p2 * (s->y2 >> NB)) +
+ (p3 * (s->y1 >> NB));
+ s->x2 = s->x1;
+ s->x1 = x;
+ s->y2 = s->y1;
+ s->y1 = y;
+ amp[i] = y >> NB;
+ if (amp[i] < 0) s->e2 -= amp[i];
+ else s->e2 += amp[i];
+ }
+ s->samps += i;
+ /* if time to do determination */
+ if ((s->samps) >= SF_DETECT_SAMPLES)
+ {
+ rv = 1; /* default to no tone */
+ /* if enough energy, it is determined to be a tone */
+ if (((s->e1 - s->e2) / s->samps) > SF_DETECT_MIN_ENERGY) rv = 2;
+ /* reset energy processing variables */
+ s->samps = 0;
+ s->e1 = s->e2 = 0;
+ }
+ return(rv);
+}
+
+static inline void __zt_process_putaudio_chunk(struct zt_chan *ss, unsigned char *rxb)
+{
+ /* We transmit data from our master channel */
+ /* Called with ss->lock held */
+ struct zt_chan *ms = ss->master;
+ /* Linear version of received data */
+ short putlin[ZT_CHUNKSIZE],k[ZT_CHUNKSIZE];
+ int x,r;
+
+ if (ms->dialing) ms->afterdialingtimer = 50;
+ else if (ms->afterdialingtimer) ms->afterdialingtimer--;
+ if (ms->afterdialingtimer && (!(ms->flags & ZT_FLAG_PSEUDO))) {
+ /* Be careful since memset is likely a macro */
+ rxb[0] = ZT_LIN2X(0, ms);
+ memset(&rxb[1], rxb[0], ZT_CHUNKSIZE - 1); /* receive as silence if dialing */
+ }
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ rxb[x] = ms->rxgain[rxb[x]];
+ putlin[x] = ZT_XLAW(rxb[x], ms);
+ }
+
+#ifndef NO_ECHOCAN_DISABLE
+ if (ms->ec) {
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ if (echo_can_disable_detector_update(&ms->rxecdis, putlin[x])) {
+ printk("zaptel Disabled echo canceller because of tone (rx) on channel %d\n", ss->channo);
+ ms->echocancel = 0;
+ ms->echostate = ECHO_STATE_IDLE;
+ ms->echolastupdate = 0;
+ ms->echotimer = 0;
+ echo_can_free(ms->ec);
+ ms->ec = NULL;
+ break;
+ }
+ }
+ }
+#endif
+ /* if doing rx tone decoding */
+ if (ms->rxp1 && ms->rxp2 && ms->rxp3)
+ {
+ r = sf_detect(&ms->rd,putlin,ZT_CHUNKSIZE,ms->rxp1,
+ ms->rxp2,ms->rxp3);
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
+ if (r) /* if something happened */
+ {
+ if (r != ms->rd.lastdetect)
+ {
+ if (((r == 2) && !(ms->toneflags & ZT_REVERSE_RXTONE)) ||
+ ((r == 1) && (ms->toneflags & ZT_REVERSE_RXTONE)))
+ {
+ __qevent(ms,ZT_EVENT_RINGOFFHOOK);
+ }
+ else
+ {
+ __qevent(ms,ZT_EVENT_ONHOOK);
+ }
+ ms->rd.lastdetect = r;
+ }
+ }
+ }
+
+ if (!(ms->flags & ZT_FLAG_PSEUDO)) {
+ memcpy(ms->putlin, putlin, ZT_CHUNKSIZE * sizeof(short));
+ memcpy(ms->putraw, rxb, ZT_CHUNKSIZE);
+ }
+
+ /* Take the rxc, twiddle it for conferencing if appropriate and put it
+ back */
+ if ((!ms->confmute && !ms->afterdialingtimer) ||
+ (ms->flags & ZT_FLAG_PSEUDO)) {
+ switch(ms->confmode & ZT_CONF_MODE_MASK) {
+ case ZT_CONF_NORMAL: /* Normal mode */
+ /* Do nothing. rx goes output */
+ break;
+ case ZT_CONF_MONITOR: /* Monitor a channel's rx mode */
+ /* if not a pseudo-channel, ignore */
+ if (!(ms->flags & ZT_FLAG_PSEUDO)) break;
+ /* Add monitored channel */
+ if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
+ ACSS(putlin, chans[ms->confna]->getlin);
+ } else {
+ ACSS(putlin, chans[ms->confna]->putlin);
+ }
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
+ break;
+ case ZT_CONF_MONITORTX: /* Monitor a channel's tx mode */
+ /* if not a pseudo-channel, ignore */
+ if (!(ms->flags & ZT_FLAG_PSEUDO)) break;
+ /* Add monitored channel */
+ if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
+ ACSS(putlin, chans[ms->confna]->putlin);
+ } else {
+ ACSS(putlin, chans[ms->confna]->getlin);
+ }
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
+ break;
+ case ZT_CONF_MONITORBOTH: /* Monitor a channel's tx and rx mode */
+ /* if not a pseudo-channel, ignore */
+ if (!(ms->flags & ZT_FLAG_PSEUDO)) break;
+ /* Note: Technically, saturation should be done at
+ the end of the whole addition, but for performance
+ reasons, we don't do that. Besides, it only matters
+ when you're so loud you're clipping anyway */
+ ACSS(putlin, chans[ms->confna]->getlin);
+ ACSS(putlin, chans[ms->confna]->putlin);
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
+ break;
+ case ZT_CONF_MONITOR_RX_PREECHO: /* Monitor a channel's rx mode */
+ /* if not a pseudo-channel, ignore */
+ if (!(ms->flags & ZT_FLAG_PSEUDO))
+ break;
+
+ if (!chans[ms->confna]->readchunkpreec)
+ break;
+
+ /* Add monitored channel */
+ ACSS(putlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ?
+ chans[ms->confna]->getlin : chans[ms->confna]->readchunkpreec);
+ for (x = 0; x < ZT_CHUNKSIZE; x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
+
+ break;
+ case ZT_CONF_MONITOR_TX_PREECHO: /* Monitor a channel's tx mode */
+ /* if not a pseudo-channel, ignore */
+ if (!(ms->flags & ZT_FLAG_PSEUDO))
+ break;
+
+ if (!chans[ms->confna]->readchunkpreec)
+ break;
+
+ /* Add monitored channel */
+ ACSS(putlin, chans[ms->confna]->flags & ZT_FLAG_PSEUDO ?
+ chans[ms->confna]->readchunkpreec : chans[ms->confna]->getlin);
+ for (x = 0; x < ZT_CHUNKSIZE; x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
+
+ break;
+ case ZT_CONF_MONITORBOTH_PREECHO: /* Monitor a channel's tx and rx mode */
+ /* if not a pseudo-channel, ignore */
+ if (!(ms->flags & ZT_FLAG_PSEUDO))
+ break;
+
+ if (!chans[ms->confna]->readchunkpreec)
+ break;
+
+ /* Note: Technically, saturation should be done at
+ the end of the whole addition, but for performance
+ reasons, we don't do that. Besides, it only matters
+ when you're so loud you're clipping anyway */
+ ACSS(putlin, chans[ms->confna]->getlin);
+ ACSS(putlin, chans[ms->confna]->readchunkpreec);
+ for (x = 0; x < ZT_CHUNKSIZE; x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
+
+ break;
+ case ZT_CONF_REALANDPSEUDO:
+ /* do normal conf mode processing */
+ if (ms->confmode & ZT_CONF_TALKER) {
+ /* Store temp value */
+ memcpy(k, putlin, ZT_CHUNKSIZE * sizeof(short));
+ /* Add conf value */
+ ACSS(k, conf_sums_next[ms->_confn]);
+ /* get amount actually added */
+ memcpy(ms->conflast, k, ZT_CHUNKSIZE * sizeof(short));
+ SCSS(ms->conflast, conf_sums_next[ms->_confn]);
+ /* Really add in new value */
+ ACSS(conf_sums_next[ms->_confn], ms->conflast);
+ } else memset(ms->conflast, 0, ZT_CHUNKSIZE * sizeof(short));
+ /* do the pseudo-channel part processing */
+ memset(putlin, 0, ZT_CHUNKSIZE * sizeof(short));
+ if (ms->confmode & ZT_CONF_PSEUDO_LISTENER) {
+ /* Subtract out previous last sample written to conf */
+ SCSS(putlin, ms->conflast2);
+ /* Add in conference */
+ ACSS(putlin, conf_sums[ms->_confn]);
+ }
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
+ break;
+ case ZT_CONF_CONF: /* Normal conference mode */
+ if (ms->flags & ZT_FLAG_PSEUDO) /* if a pseudo-channel */
+ {
+ if (ms->confmode & ZT_CONF_LISTENER) {
+ /* Subtract out last sample written to conf */
+ SCSS(putlin, ms->conflast);
+ /* Add in conference */
+ ACSS(putlin, conf_sums[ms->_confn]);
+ }
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
+ memcpy(ss->putlin, putlin, ZT_CHUNKSIZE * sizeof(short));
+ break;
+ }
+ /* fall through */
+ case ZT_CONF_CONFANN: /* Conference with announce */
+ if (ms->confmode & ZT_CONF_TALKER) {
+ /* Store temp value */
+ memcpy(k, putlin, ZT_CHUNKSIZE * sizeof(short));
+ /* Add conf value */
+ ACSS(k, conf_sums_next[ms->_confn]);
+ /* get amount actually added */
+ memcpy(ms->conflast, k, ZT_CHUNKSIZE * sizeof(short));
+ SCSS(ms->conflast, conf_sums_next[ms->_confn]);
+ /* Really add in new value */
+ ACSS(conf_sums_next[ms->_confn], ms->conflast);
+ } else
+ memset(ms->conflast, 0, ZT_CHUNKSIZE * sizeof(short));
+ /* rxc unmodified */
+ break;
+ case ZT_CONF_CONFMON:
+ case ZT_CONF_CONFANNMON:
+ if (ms->confmode & ZT_CONF_TALKER) {
+ /* Store temp value */
+ memcpy(k, putlin, ZT_CHUNKSIZE * sizeof(short));
+ /* Subtract last value */
+ SCSS(conf_sums[ms->_confn], ms->conflast);
+ /* Add conf value */
+ ACSS(k, conf_sums[ms->_confn]);
+ /* get amount actually added */
+ memcpy(ms->conflast, k, ZT_CHUNKSIZE * sizeof(short));
+ SCSS(ms->conflast, conf_sums[ms->_confn]);
+ /* Really add in new value */
+ ACSS(conf_sums[ms->_confn], ms->conflast);
+ } else
+ memset(ms->conflast, 0, ZT_CHUNKSIZE * sizeof(short));
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X((int)conf_sums_prev[ms->_confn][x], ms);
+ break;
+ case ZT_CONF_DIGITALMON:
+ /* if not a pseudo-channel, ignore */
+ if (!(ms->flags & ZT_FLAG_PSEUDO)) break;
+ /* Add monitored channel */
+ if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
+ memcpy(rxb, chans[ms->confna]->getraw, ZT_CHUNKSIZE);
+ } else {
+ memcpy(rxb, chans[ms->confna]->putraw, ZT_CHUNKSIZE);
+ }
+ break;
+ }
+ }
+}
+
+/* HDLC (or other) receiver buffer functions for read side */
+static inline void __putbuf_chunk(struct zt_chan *ss, unsigned char *rxb, int bytes)
+{
+ /* We transmit data from our master channel */
+ /* Called with ss->lock held */
+ struct zt_chan *ms = ss->master;
+ /* Our receive buffer */
+ unsigned char *buf;
+#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
+ /* SKB for receiving network stuff */
+ struct sk_buff *skb=NULL;
+#endif
+ int oldbuf;
+ int eof=0;
+ int abort=0;
+ int res;
+ int left, x;
+
+ while(bytes) {
+#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
+ skb = NULL;
+#endif
+ abort = 0;
+ eof = 0;
+ /* Next, figure out if we've got a buffer to receive into */
+ if (ms->inreadbuf > -1) {
+ /* Read into the current buffer */
+ buf = ms->readbuf[ms->inreadbuf];
+ left = ms->blocksize - ms->readidx[ms->inreadbuf];
+ if (left > bytes)
+ left = bytes;
+ if (ms->flags & ZT_FLAG_HDLC) {
+ for (x=0;x<left;x++) {
+ /* Handle HDLC deframing */
+ fasthdlc_rx_load_nocheck(&ms->rxhdlc, *(rxb++));
+ bytes--;
+ res = fasthdlc_rx_run(&ms->rxhdlc);
+ /* If there is nothing there, continue */
+ if (res & RETURN_EMPTY_FLAG)
+ continue;
+ else if (res & RETURN_COMPLETE_FLAG) {
+ /* Only count this if it's a non-empty frame */
+ if (ms->readidx[ms->inreadbuf]) {
+ if ((ms->flags & ZT_FLAG_FCS) && (ms->infcs != PPP_GOODFCS)) {
+ abort = ZT_EVENT_BADFCS;
+ } else
+ eof=1;
+ break;
+ }
+ continue;
+ } else if (res & RETURN_DISCARD_FLAG) {
+ /* This could be someone idling with
+ "idle" instead of "flag" */
+ if (!ms->readidx[ms->inreadbuf])
+ continue;
+ abort = ZT_EVENT_ABORT;
+ break;
+ } else {
+ unsigned char rxc;
+ rxc = res;
+ ms->infcs = PPP_FCS(ms->infcs, rxc);
+ buf[ms->readidx[ms->inreadbuf]++] = rxc;
+ /* Pay attention to the possibility of an overrun */
+ if (ms->readidx[ms->inreadbuf] >= ms->blocksize) {
+ if (!ss->span->alarms)
+ printk(KERN_WARNING "HDLC Receiver overrun on channel %s (master=%s)\n", ss->name, ss->master->name);
+ abort=ZT_EVENT_OVERRUN;
+ /* Force the HDLC state back to frame-search mode */
+ ms->rxhdlc.state = 0;
+ ms->rxhdlc.bits = 0;
+ ms->readidx[ms->inreadbuf]=0;
+ break;
+ }
+ }
+ }
+ } else {
+ /* Not HDLC */
+ memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left);
+ rxb += left;
+ ms->readidx[ms->inreadbuf] += left;
+ bytes -= left;
+ /* End of frame is decided by block size of 'N' */
+ eof = (ms->readidx[ms->inreadbuf] >= ms->blocksize);
+ if (eof && (ss->flags & ZT_FLAG_NOSTDTXRX)) {
+ eof = 0;
+ abort = ZT_EVENT_OVERRUN;
+ }
+ }
+ if (eof) {
+ /* Finished with this buffer, try another. */
+ oldbuf = ms->inreadbuf;
+ ms->infcs = PPP_INITFCS;
+ ms->readn[ms->inreadbuf] = ms->readidx[ms->inreadbuf];
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("EOF, len is %d\n", ms->readn[ms->inreadbuf]);
+#endif
+#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
+ if (ms->flags & (ZT_FLAG_NETDEV | ZT_FLAG_PPP)) {
+#ifdef CONFIG_ZAPATA_NET
+#endif /* CONFIG_ZAPATA_NET */
+ /* Our network receiver logic is MUCH
+ different. We actually only use a single
+ buffer */
+ if (ms->readn[ms->inreadbuf] > 1) {
+ /* Drop the FCS */
+ ms->readn[ms->inreadbuf] -= 2;
+ /* Allocate an SKB */
+#ifdef CONFIG_ZAPATA_PPP
+ if (!ms->do_ppp_error)
+#endif
+ skb = dev_alloc_skb(ms->readn[ms->inreadbuf]);
+ if (skb) {
+ /* XXX Get rid of this memcpy XXX */
+ memcpy(skb->data, ms->readbuf[ms->inreadbuf], ms->readn[ms->inreadbuf]);
+ skb_put(skb, ms->readn[ms->inreadbuf]);
+#ifdef CONFIG_ZAPATA_NET
+ if (ms->flags & ZT_FLAG_NETDEV) {
+#ifdef LINUX26
+ struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev);
+#else /* LINUX26 */
+ struct net_device_stats *stats = &ms->hdlcnetdev->netdev.stats;
+#endif /* LINUX26 */
+ stats->rx_packets++;
+ stats->rx_bytes += ms->readn[ms->inreadbuf];
+ }
+#endif
+
+ } else {
+#ifdef CONFIG_ZAPATA_NET
+ if (ms->flags & ZT_FLAG_NETDEV) {
+#ifdef LINUX26
+ struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev);
+#else /* LINUX26 */
+ struct net_device_stats *stats = &ms->hdlcnetdev->netdev.stats;
+#endif /* LINUX26 */
+ stats->rx_dropped++;
+ }
+#endif
+#ifdef CONFIG_ZAPATA_PPP
+ if (ms->flags & ZT_FLAG_PPP) {
+ abort = ZT_EVENT_OVERRUN;
+ }
+#endif
+#if 1
+#ifdef CONFIG_ZAPATA_PPP
+ if (!ms->do_ppp_error)
+#endif
+ printk("Memory squeeze, dropped one\n");
+#endif
+ }
+ }
+ /* We don't cycle through buffers, just
+ reuse the same one */
+ ms->readn[ms->inreadbuf] = 0;
+ ms->readidx[ms->inreadbuf] = 0;
+ } else
+#endif
+ {
+ /* This logic might confuse and astound. Basically we need to find
+ * the previous buffer index. It should be safe because, regardless
+ * of whether or not it has been copied to user space, nothing should
+ * have messed around with it since then */
+
+ int comparemessage;
+
+ if (ms->flags & ZT_FLAG_MTP2) {
+ comparemessage = (ms->inreadbuf - 1) & (ms->numbufs - 1);
+
+ res = memcmp(ms->readbuf[comparemessage], ms->readbuf[ms->inreadbuf], ms->readn[ms->inreadbuf]);
+ }
+
+ if ((ms->flags & ZT_FLAG_MTP2) && !res) {
+ /* Our messages are the same, so discard -
+ * Don't advance buffers, reset indexes and buffer sizes. */
+ ms->readn[ms->inreadbuf] = 0;
+ ms->readidx[ms->inreadbuf] = 0;
+ } else {
+ ms->inreadbuf = (ms->inreadbuf + 1) % ms->numbufs;
+ if (ms->inreadbuf == ms->outreadbuf) {
+ /* Whoops, we're full, and have no where else
+ to store into at the moment. We'll drop it
+ until there's a buffer available */
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Out of storage space\n");
+#endif
+ ms->inreadbuf = -1;
+ /* Enable the receiver in case they've got POLICY_WHEN_FULL */
+ ms->rxdisable = 0;
+ }
+ if (ms->outreadbuf < 0) { /* start out buffer if not already */
+ ms->outreadbuf = oldbuf;
+ }
+/* In the very orignal driver, it was quite well known to me (Jim) that there
+was a possibility that a channel sleeping on a receive block needed to
+be potentially woken up EVERY time a buffer was filled, not just on the first
+one, because if only done on the first one there is a slight timing potential
+of missing the wakeup (between where it senses the (lack of) active condition
+(with interrupts disabled) and where it does the sleep (interrupts enabled)
+in the read or iomux call, etc). That is why the read and iomux calls start
+with an infinite loop that gets broken out of upon an active condition,
+otherwise keeps sleeping and looking. The part in this code got "optimized"
+out in the later versions, and is put back now. */
+ if (!ms->rxdisable) { /* if receiver enabled */
+ /* Notify a blocked reader that there is data available
+ to be read, unless we're waiting for it to be full */
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Notifying reader data in block %d\n", oldbuf);
+#endif
+ wake_up_interruptible(&ms->readbufq);
+ wake_up_interruptible(&ms->sel);
+ if (ms->iomask & ZT_IOMUX_READ)
+ wake_up_interruptible(&ms->eventbufq);
+ }
+ }
+ }
+ }
+ if (abort) {
+ /* Start over reading frame */
+ ms->readidx[ms->inreadbuf] = 0;
+ ms->infcs = PPP_INITFCS;
+
+#ifdef CONFIG_ZAPATA_NET
+ if (ms->flags & ZT_FLAG_NETDEV) {
+#ifdef LINUX26
+ struct net_device_stats *stats = hdlc_stats(ms->hdlcnetdev->netdev);
+#else /* LINUX26 */
+ struct net_device_stats *stats = &ms->hdlcnetdev->netdev.stats;
+#endif /* LINUX26 */
+ stats->rx_errors++;
+ if (abort == ZT_EVENT_OVERRUN)
+ stats->rx_over_errors++;
+ if (abort == ZT_EVENT_BADFCS)
+ stats->rx_crc_errors++;
+ if (abort == ZT_EVENT_ABORT)
+ stats->rx_frame_errors++;
+ } else
+#endif
+#ifdef CONFIG_ZAPATA_PPP
+ if (ms->flags & ZT_FLAG_PPP) {
+ ms->do_ppp_error = 1;
+ tasklet_schedule(&ms->ppp_calls);
+ } else
+#endif
+
+ if ((ms->flags & ZT_FLAG_OPEN) && !ss->span->alarms)
+ /* Notify the receiver... */
+ __qevent(ss->master, abort);
+#if 0
+ printk("torintr_receive: Aborted %d bytes of frame on %d\n", amt, ss->master);
+#endif
+
+ }
+ } else /* No place to receive -- drop on the floor */
+ break;
+#ifdef CONFIG_ZAPATA_NET
+ if (skb && (ms->flags & ZT_FLAG_NETDEV))
+#ifdef NEW_HDLC_INTERFACE
+ {
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
+ skb->mac.raw = skb->data;
+#else
+ skb_reset_mac_header(skb);
+#endif
+ skb->dev = ztchan_to_dev(ms);
+#ifdef ZAP_HDLC_TYPE_TRANS
+ skb->protocol = hdlc_type_trans(skb, ztchan_to_dev(ms));
+#else
+ skb->protocol = htons (ETH_P_HDLC);
+#endif
+ netif_rx(skb);
+ }
+#else
+ hdlc_netif_rx(&ms->hdlcnetdev->netdev, skb);
+#endif
+#endif
+#ifdef CONFIG_ZAPATA_PPP
+ if (skb && (ms->flags & ZT_FLAG_PPP)) {
+ unsigned char *tmp;
+ tmp = skb->data;
+ skb_pull(skb, 2);
+ /* Make sure that it's addressed to ALL STATIONS and UNNUMBERED */
+ if (!tmp || (tmp[0] != 0xff) || (tmp[1] != 0x03)) {
+ /* Invalid SKB -- drop */
+ if (tmp)
+ printk("Received invalid SKB (%02x, %02x)\n", tmp[0], tmp[1]);
+ dev_kfree_skb_irq(skb);
+ } else {
+ skb_queue_tail(&ms->ppp_rq, skb);
+ tasklet_schedule(&ms->ppp_calls);
+ }
+ }
+#endif
+ }
+}
+
+static inline void __zt_putbuf_chunk(struct zt_chan *ss, unsigned char *rxb)
+{
+ __putbuf_chunk(ss, rxb, ZT_CHUNKSIZE);
+}
+
+static void __zt_hdlc_abort(struct zt_chan *ss, int event)
+{
+ if (ss->inreadbuf >= 0)
+ ss->readidx[ss->inreadbuf] = 0;
+ if ((ss->flags & ZT_FLAG_OPEN) && !ss->span->alarms)
+ __qevent(ss->master, event);
+}
+
+extern void zt_hdlc_abort(struct zt_chan *ss, int event)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&ss->lock, flags);
+ __zt_hdlc_abort(ss, event);
+ spin_unlock_irqrestore(&ss->lock, flags);
+}
+
+extern void zt_hdlc_putbuf(struct zt_chan *ss, unsigned char *rxb, int bytes)
+{
+ unsigned long flags;
+ int res;
+ int left;
+
+ spin_lock_irqsave(&ss->lock, flags);
+ if (ss->inreadbuf < 0) {
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("No place to receive HDLC frame\n");
+#endif
+ spin_unlock_irqrestore(&ss->lock, flags);
+ return;
+ }
+ /* Read into the current buffer */
+ left = ss->blocksize - ss->readidx[ss->inreadbuf];
+ if (left > bytes)
+ left = bytes;
+ if (left > 0) {
+ memcpy(ss->readbuf[ss->inreadbuf] + ss->readidx[ss->inreadbuf], rxb, left);
+ rxb += left;
+ ss->readidx[ss->inreadbuf] += left;
+ bytes -= left;
+ }
+ /* Something isn't fit into buffer */
+ if (bytes) {
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("HDLC frame isn't fit into buffer space\n");
+#endif
+ __zt_hdlc_abort(ss, ZT_EVENT_OVERRUN);
+ }
+ res = left;
+ spin_unlock_irqrestore(&ss->lock, flags);
+}
+
+extern void zt_hdlc_finish(struct zt_chan *ss)
+{
+ int oldreadbuf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ss->lock, flags);
+
+ if ((oldreadbuf = ss->inreadbuf) < 0) {
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("No buffers to finish\n");
+#endif
+ spin_unlock_irqrestore(&ss->lock, flags);
+ return;
+ }
+
+ if (!ss->readidx[ss->inreadbuf]) {
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Empty HDLC frame received\n");
+#endif
+ spin_unlock_irqrestore(&ss->lock, flags);
+ return;
+ }
+
+ ss->readn[ss->inreadbuf] = ss->readidx[ss->inreadbuf];
+ ss->inreadbuf = (ss->inreadbuf + 1) % ss->numbufs;
+ if (ss->inreadbuf == ss->outreadbuf) {
+ ss->inreadbuf = -1;
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Notifying reader data in block %d\n", oldreadbuf);
+#endif
+ ss->rxdisable = 0;
+ }
+ if (ss->outreadbuf < 0) {
+ ss->outreadbuf = oldreadbuf;
+ }
+
+ if (!ss->rxdisable) {
+ wake_up_interruptible(&ss->readbufq);
+ wake_up_interruptible(&ss->sel);
+ if (ss->iomask & ZT_IOMUX_READ)
+ wake_up_interruptible(&ss->eventbufq);
+ }
+ spin_unlock_irqrestore(&ss->lock, flags);
+}
+
+/* Returns 1 if EOF, 0 if data is still in frame, -1 if EOF and no buffers left */
+extern int zt_hdlc_getbuf(struct zt_chan *ss, unsigned char *bufptr, unsigned int *size)
+{
+ unsigned char *buf;
+ unsigned long flags;
+ int left = 0;
+ int res;
+ int oldbuf;
+
+ spin_lock_irqsave(&ss->lock, flags);
+ if (ss->outwritebuf > -1) {
+ buf = ss->writebuf[ss->outwritebuf];
+ left = ss->writen[ss->outwritebuf] - ss->writeidx[ss->outwritebuf];
+ /* Strip off the empty HDLC CRC end */
+ left -= 2;
+ if (left <= *size) {
+ *size = left;
+ res = 1;
+ } else
+ res = 0;
+
+ memcpy(bufptr, &buf[ss->writeidx[ss->outwritebuf]], *size);
+ ss->writeidx[ss->outwritebuf] += *size;
+
+ if (res) {
+ /* Rotate buffers */
+ oldbuf = ss->outwritebuf;
+ ss->writeidx[oldbuf] = 0;
+ ss->writen[oldbuf] = 0;
+ ss->outwritebuf = (ss->outwritebuf + 1) % ss->numbufs;
+ if (ss->outwritebuf == ss->inwritebuf) {
+ ss->outwritebuf = -1;
+ if (ss->iomask & (ZT_IOMUX_WRITE | ZT_IOMUX_WRITEEMPTY))
+ wake_up_interruptible(&ss->eventbufq);
+ /* If we're only supposed to start when full, disable the transmitter */
+ if (ss->txbufpolicy == ZT_POLICY_WHEN_FULL)
+ ss->txdisable = 1;
+ res = -1;
+ }
+
+ if (ss->inwritebuf < 0)
+ ss->inwritebuf = oldbuf;
+
+ if (!(ss->flags & (ZT_FLAG_NETDEV | ZT_FLAG_PPP))) {
+ wake_up_interruptible(&ss->writebufq);
+ wake_up_interruptible(&ss->sel);
+ if ((ss->iomask & ZT_IOMUX_WRITE) && (res >= 0))
+ wake_up_interruptible(&ss->eventbufq);
+ }
+ }
+ } else {
+ res = -1;
+ *size = 0;
+ }
+ spin_unlock_irqrestore(&ss->lock, flags);
+
+ return res;
+}
+
+
+static void process_timers(void)
+{
+ unsigned long flags;
+ struct zt_timer *cur;
+ spin_lock_irqsave(&zaptimerlock, flags);
+ cur = zaptimers;
+ while(cur) {
+ if (cur->ms) {
+ cur->pos -= ZT_CHUNKSIZE;
+ if (cur->pos <= 0) {
+ cur->tripped++;
+ cur->pos = cur->ms;
+ wake_up_interruptible(&cur->sel);
+ }
+ }
+ cur = cur->next;
+ }
+ spin_unlock_irqrestore(&zaptimerlock, flags);
+}
+
+static unsigned int zt_timer_poll(struct file *file, struct poll_table_struct *wait_table)
+{
+ struct zt_timer *timer = file->private_data;
+ unsigned long flags;
+ int ret = 0;
+ if (timer) {
+ poll_wait(file, &timer->sel, wait_table);
+ spin_lock_irqsave(&zaptimerlock, flags);
+ if (timer->tripped || timer->ping)
+ ret |= POLLPRI;
+ spin_unlock_irqrestore(&zaptimerlock, flags);
+ } else
+ ret = -EINVAL;
+ return ret;
+}
+
+/* device poll routine */
+static unsigned int
+zt_chan_poll(struct file *file, struct poll_table_struct *wait_table, int unit)
+{
+
+ struct zt_chan *chan = chans[unit];
+ int ret;
+ unsigned long flags;
+
+ /* do the poll wait */
+ if (chan) {
+ poll_wait(file, &chan->sel, wait_table);
+ ret = 0; /* start with nothing to return */
+ spin_lock_irqsave(&chan->lock, flags);
+ /* if at least 1 write buffer avail */
+ if (chan->inwritebuf > -1) {
+ ret |= POLLOUT | POLLWRNORM;
+ }
+ if ((chan->outreadbuf > -1) && !chan->rxdisable) {
+ ret |= POLLIN | POLLRDNORM;
+ }
+ if (chan->eventoutidx != chan->eventinidx)
+ {
+ /* Indicate an exception */
+ ret |= POLLPRI;
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ } else
+ ret = -EINVAL;
+ return(ret); /* return what we found */
+}
+
+static int zt_mmap(struct file *file, struct vm_area_struct *vm)
+{
+ int unit = UNIT(file);
+ if (unit == 250)
+ return zt_transcode_fops->mmap(file, vm);
+ return -ENOSYS;
+}
+
+static unsigned int zt_poll(struct file *file, struct poll_table_struct *wait_table)
+{
+ int unit = UNIT(file);
+ struct zt_chan *chan;
+
+ if (!unit)
+ return -EINVAL;
+
+ if (unit == 250)
+ return zt_transcode_fops->poll(file, wait_table);
+
+ if (unit == 253)
+ return zt_timer_poll(file, wait_table);
+
+ if (unit == 254) {
+ chan = file->private_data;
+ if (!chan)
+ return -EINVAL;
+ return zt_chan_poll(file, wait_table,chan->channo);
+ }
+ if (unit == 255) {
+ chan = file->private_data;
+ if (!chan) {
+ printk("No pseudo channel structure to read?\n");
+ return -EINVAL;
+ }
+ return zt_chan_poll(file, wait_table, chan->channo);
+ }
+ return zt_chan_poll(file, wait_table, unit);
+}
+
+static void __zt_transmit_chunk(struct zt_chan *chan, unsigned char *buf)
+{
+ unsigned char silly[ZT_CHUNKSIZE];
+ /* Called with chan->lock locked */
+#ifdef OPTIMIZE_CHANMUTE
+ if(likely(chan->chanmute))
+ return;
+#endif
+ if (!buf)
+ buf = silly;
+ __zt_getbuf_chunk(chan, buf);
+
+ if ((chan->flags & ZT_FLAG_AUDIO) || (chan->confmode)) {
+#ifdef CONFIG_ZAPTEL_MMX
+ zt_kernel_fpu_begin();
+#endif
+ __zt_process_getaudio_chunk(chan, buf);
+#ifdef CONFIG_ZAPTEL_MMX
+ kernel_fpu_end();
+#endif
+ }
+}
+
+static inline void __zt_real_transmit(struct zt_chan *chan)
+{
+ /* Called with chan->lock held */
+#ifdef OPTIMIZE_CHANMUTE
+ if(likely(chan->chanmute))
+ return;
+#endif
+ if (chan->confmode) {
+ /* Pull queued data off the conference */
+ __buf_pull(&chan->confout, chan->writechunk, chan, "zt_real_transmit");
+ } else {
+ __zt_transmit_chunk(chan, chan->writechunk);
+ }
+}
+
+static void __zt_getempty(struct zt_chan *ms, unsigned char *buf)
+{
+ int bytes = ZT_CHUNKSIZE;
+ int left;
+ unsigned char *txb = buf;
+ int x;
+ short getlin;
+ /* Called with ms->lock held */
+
+ while(bytes) {
+ /* Receive silence, or tone */
+ if (ms->curtone) {
+ left = ms->curtone->tonesamples - ms->tonep;
+ if (left > bytes)
+ left = bytes;
+ for (x=0;x<left;x++) {
+ /* Pick our default value from the next sample of the current tone */
+ getlin = zt_tone_nextsample(&ms->ts, ms->curtone);
+ *(txb++) = ZT_LIN2X(getlin, ms);
+ }
+ ms->tonep+=left;
+ bytes -= left;
+ if (ms->tonep >= ms->curtone->tonesamples) {
+ struct zt_tone *last;
+ /* Go to the next sample of the tone */
+ ms->tonep = 0;
+ last = ms->curtone;
+ ms->curtone = ms->curtone->next;
+ if (!ms->curtone) {
+ /* No more tones... Is this dtmf or mf? If so, go to the next digit */
+ if (ms->dialing)
+ __do_dtmf(ms);
+ } else {
+ if (last != ms->curtone)
+ zt_init_tone_state(&ms->ts, ms->curtone);
+ }
+ }
+ } else {
+ /* Use silence */
+ memset(txb, ZT_LIN2X(0, ms), bytes);
+ bytes = 0;
+ }
+ }
+
+}
+
+static void __zt_receive_chunk(struct zt_chan *chan, unsigned char *buf)
+{
+ /* Receive chunk of audio -- called with chan->lock held */
+ unsigned char waste[ZT_CHUNKSIZE];
+
+#ifdef OPTIMIZE_CHANMUTE
+ if(likely(chan->chanmute))
+ return;
+#endif
+ if (!buf) {
+ memset(waste, ZT_LIN2X(0, chan), sizeof(waste));
+ buf = waste;
+ }
+ if ((chan->flags & ZT_FLAG_AUDIO) || (chan->confmode)) {
+#ifdef CONFIG_ZAPTEL_MMX
+ zt_kernel_fpu_begin();
+#endif
+ __zt_process_putaudio_chunk(chan, buf);
+#ifdef CONFIG_ZAPTEL_MMX
+ kernel_fpu_end();
+#endif
+ }
+ __zt_putbuf_chunk(chan, buf);
+}
+
+static inline void __zt_real_receive(struct zt_chan *chan)
+{
+ /* Called with chan->lock held */
+#ifdef OPTIMIZE_CHANMUTE
+ if(likely(chan->chanmute))
+ return;
+#endif
+ if (chan->confmode) {
+ /* Load into queue if we have space */
+ __buf_push(&chan->confin, chan->readchunk, "zt_real_receive");
+ } else {
+ __zt_receive_chunk(chan, chan->readchunk);
+ }
+}
+
+int zt_transmit(struct zt_span *span)
+{
+ int x,y,z;
+ unsigned long flags;
+
+#if 1
+ for (x=0;x<span->channels;x++) {
+ spin_lock_irqsave(&span->chans[x].lock, flags);
+ if (span->chans[x].flags & ZT_FLAG_NOSTDTXRX) {
+ spin_unlock_irqrestore(&span->chans[x].lock, flags);
+ continue;
+ }
+ if (&span->chans[x] == span->chans[x].master) {
+ if (span->chans[x].otimer) {
+ span->chans[x].otimer -= ZT_CHUNKSIZE;
+ if (span->chans[x].otimer <= 0) {
+ __rbs_otimer_expire(&span->chans[x]);
+ }
+ }
+ if (span->chans[x].flags & ZT_FLAG_AUDIO) {
+ __zt_real_transmit(&span->chans[x]);
+ } else {
+ if (span->chans[x].nextslave) {
+ u_char data[ZT_CHUNKSIZE];
+ int pos=ZT_CHUNKSIZE;
+ /* Process master/slaves one way */
+ for (y=0;y<ZT_CHUNKSIZE;y++) {
+ /* Process slaves for this byte too */
+ z = x;
+ do {
+ if (pos==ZT_CHUNKSIZE) {
+ /* Get next chunk */
+ __zt_transmit_chunk(&span->chans[x], data);
+ pos = 0;
+ }
+ span->chans[z].writechunk[y] = data[pos++];
+ z = span->chans[z].nextslave;
+ } while(z);
+ }
+ } else {
+ /* Process independents elsewise */
+ __zt_real_transmit(&span->chans[x]);
+ }
+ }
+ if (span->chans[x].sig == ZT_SIG_DACS_RBS) {
+ if (chans[span->chans[x].confna]) {
+ /* Just set bits for our destination */
+ if (span->chans[x].txsig != chans[span->chans[x].confna]->rxsig) {
+ span->chans[x].txsig = chans[span->chans[x].confna]->rxsig;
+ span->rbsbits(&span->chans[x], chans[span->chans[x].confna]->rxsig);
+ }
+ }
+ }
+
+ }
+ spin_unlock_irqrestore(&span->chans[x].lock, flags);
+ }
+ if (span->mainttimer) {
+ span->mainttimer -= ZT_CHUNKSIZE;
+ if (span->mainttimer <= 0) {
+ span->mainttimer = 0;
+ if (span->maint)
+ span->maint(span, ZT_MAINT_LOOPSTOP);
+ span->maintstat = 0;
+ wake_up_interruptible(&span->maintq);
+ }
+ }
+#endif
+ return 0;
+}
+
+int zt_receive(struct zt_span *span)
+{
+ int x,y,z;
+ unsigned long flags, flagso;
+
+#if 1
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+ span->watchcounter--;
+#endif
+ for (x=0;x<span->channels;x++) {
+ if (span->chans[x].master == &span->chans[x]) {
+ spin_lock_irqsave(&span->chans[x].lock, flags);
+ if (span->chans[x].nextslave) {
+ /* Must process each slave at the same time */
+ u_char data[ZT_CHUNKSIZE];
+ int pos = 0;
+ for (y=0;y<ZT_CHUNKSIZE;y++) {
+ /* Put all its slaves, too */
+ z = x;
+ do {
+ data[pos++] = span->chans[z].readchunk[y];
+ if (pos == ZT_CHUNKSIZE) {
+ if(!(span->chans[x].flags & ZT_FLAG_NOSTDTXRX))
+ __zt_receive_chunk(&span->chans[x], data);
+ pos = 0;
+ }
+ z=span->chans[z].nextslave;
+ } while(z);
+ }
+ } else {
+ /* Process a normal channel */
+ if (!(span->chans[x].flags & ZT_FLAG_NOSTDTXRX))
+ __zt_real_receive(&span->chans[x]);
+ }
+ if (span->chans[x].itimer) {
+ span->chans[x].itimer -= ZT_CHUNKSIZE;
+ if (span->chans[x].itimer <= 0) {
+ rbs_itimer_expire(&span->chans[x]);
+ }
+ }
+ if (span->chans[x].ringdebtimer)
+ span->chans[x].ringdebtimer--;
+ if (span->chans[x].sig & __ZT_SIG_FXS) {
+ if (span->chans[x].rxhooksig == ZT_RXSIG_RING)
+ span->chans[x].ringtrailer = ZT_RINGTRAILER;
+ else if (span->chans[x].ringtrailer) {
+ span->chans[x].ringtrailer-= ZT_CHUNKSIZE;
+ /* See if RING trailer is expired */
+ if (!span->chans[x].ringtrailer && !span->chans[x].ringdebtimer)
+ __qevent(&span->chans[x],ZT_EVENT_RINGOFFHOOK);
+ }
+ }
+ if (span->chans[x].pulsetimer)
+ {
+ span->chans[x].pulsetimer--;
+ if (span->chans[x].pulsetimer <= 0)
+ {
+ if (span->chans[x].pulsecount)
+ {
+ if (span->chans[x].pulsecount > 12) {
+
+ printk("Got pulse digit %d on %s???\n",
+ span->chans[x].pulsecount,
+ span->chans[x].name);
+ } else if (span->chans[x].pulsecount > 11) {
+ __qevent(&span->chans[x], ZT_EVENT_PULSEDIGIT | '#');
+ } else if (span->chans[x].pulsecount > 10) {
+ __qevent(&span->chans[x], ZT_EVENT_PULSEDIGIT | '*');
+ } else if (span->chans[x].pulsecount > 9) {
+ __qevent(&span->chans[x], ZT_EVENT_PULSEDIGIT | '0');
+ } else {
+ __qevent(&span->chans[x], ZT_EVENT_PULSEDIGIT | ('0' +
+ span->chans[x].pulsecount));
+ }
+ span->chans[x].pulsecount = 0;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&span->chans[x].lock, flags);
+ }
+ }
+
+ if (span == master) {
+ /* Hold the big zap lock for the duration of major
+ activities which touch all sorts of channels */
+ spin_lock_irqsave(&bigzaplock, flagso);
+ /* Process any timers */
+ process_timers();
+ /* If we have dynamic stuff, call the ioctl with 0,0 parameters to
+ make it run */
+ if (zt_dynamic_ioctl)
+ zt_dynamic_ioctl(0,0);
+ for (x=1;x<maxchans;x++) {
+ if (chans[x] && chans[x]->confmode && !(chans[x]->flags & ZT_FLAG_PSEUDO)) {
+ u_char *data;
+ spin_lock_irqsave(&chans[x]->lock, flags);
+ data = __buf_peek(&chans[x]->confin);
+ __zt_receive_chunk(chans[x], data);
+ if (data)
+ __buf_pull(&chans[x]->confin, NULL,chans[x], "confreceive");
+ spin_unlock_irqrestore(&chans[x]->lock, flags);
+ }
+ }
+ /* This is the master channel, so make things switch over */
+ rotate_sums();
+ /* do all the pseudo and/or conferenced channel receives (getbuf's) */
+ for (x=1;x<maxchans;x++) {
+ if (chans[x] && (chans[x]->flags & ZT_FLAG_PSEUDO)) {
+ spin_lock_irqsave(&chans[x]->lock, flags);
+ __zt_transmit_chunk(chans[x], NULL);
+ spin_unlock_irqrestore(&chans[x]->lock, flags);
+ }
+ }
+ if (maxlinks) {
+#ifdef CONFIG_ZAPTEL_MMX
+ zt_kernel_fpu_begin();
+#endif
+ /* process all the conf links */
+ for(x = 1; x <= maxlinks; x++) {
+ /* if we have a destination conf */
+ if (((z = confalias[conf_links[x].dst]) > 0) &&
+ ((y = confalias[conf_links[x].src]) > 0)) {
+ ACSS(conf_sums[z], conf_sums[y]);
+ }
+ }
+#ifdef CONFIG_ZAPTEL_MMX
+ kernel_fpu_end();
+#endif
+ }
+ /* do all the pseudo/conferenced channel transmits (putbuf's) */
+ for (x=1;x<maxchans;x++) {
+ if (chans[x] && (chans[x]->flags & ZT_FLAG_PSEUDO)) {
+ unsigned char tmp[ZT_CHUNKSIZE];
+ spin_lock_irqsave(&chans[x]->lock, flags);
+ __zt_getempty(chans[x], tmp);
+ __zt_receive_chunk(chans[x], tmp);
+ spin_unlock_irqrestore(&chans[x]->lock, flags);
+ }
+ }
+ for (x=1;x<maxchans;x++) {
+ if (chans[x] && chans[x]->confmode && !(chans[x]->flags & ZT_FLAG_PSEUDO)) {
+ u_char *data;
+ spin_lock_irqsave(&chans[x]->lock, flags);
+ data = __buf_pushpeek(&chans[x]->confout);
+ __zt_transmit_chunk(chans[x], data);
+ if (data)
+ __buf_push(&chans[x]->confout, NULL, "conftransmit");
+ spin_unlock_irqrestore(&chans[x]->lock, flags);
+ }
+ }
+#ifdef ZAPTEL_SYNC_TICK
+ for (x=0;x<maxspans;x++) {
+ struct zt_span *s = spans[x];
+
+ if (s && s->sync_tick)
+ s->sync_tick(s, s == master);
+ }
+#endif
+ spin_unlock_irqrestore(&bigzaplock, flagso);
+ }
+#endif
+ return 0;
+}
+
+MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
+MODULE_DESCRIPTION("Zapata Telephony Interface");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+#ifdef MODULE_VERSION
+MODULE_VERSION(ZAPTEL_VERSION);
+#endif
+
+#ifdef LINUX26
+module_param(debug, int, 0644);
+module_param(deftaps, int, 0644);
+#else
+MODULE_PARM(debug, "i");
+MODULE_PARM(deftaps, "i");
+#endif
+
+static struct file_operations zt_fops = {
+ owner: THIS_MODULE,
+ llseek: NULL,
+ open: zt_open,
+ release: zt_release,
+ ioctl: zt_ioctl,
+ read: zt_read,
+ write: zt_write,
+ poll: zt_poll,
+ mmap: zt_mmap,
+ flush: NULL,
+ fsync: NULL,
+ fasync: NULL,
+};
+
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+static struct timer_list watchdogtimer;
+
+static void watchdog_check(unsigned long ignored)
+{
+ int x;
+ unsigned long flags;
+ static int wdcheck=0;
+
+ local_irq_save(flags);
+ for (x=0;x<maxspans;x++) {
+ if (spans[x] && (spans[x]->flags & ZT_FLAG_RUNNING)) {
+ if (spans[x]->watchcounter == ZT_WATCHDOG_INIT) {
+ /* Whoops, dead card */
+ if ((spans[x]->watchstate == ZT_WATCHSTATE_OK) ||
+ (spans[x]->watchstate == ZT_WATCHSTATE_UNKNOWN)) {
+ spans[x]->watchstate = ZT_WATCHSTATE_RECOVERING;
+ if (spans[x]->watchdog) {
+ printk("Kicking span %s\n", spans[x]->name);
+ spans[x]->watchdog(spans[x], ZT_WATCHDOG_NOINTS);
+ } else {
+ printk("Span %s is dead with no revival\n", spans[x]->name);
+ spans[x]->watchstate = ZT_WATCHSTATE_FAILED;
+ }
+ }
+ } else {
+ if ((spans[x]->watchstate != ZT_WATCHSTATE_OK) &&
+ (spans[x]->watchstate != ZT_WATCHSTATE_UNKNOWN))
+ printk("Span %s is alive!\n", spans[x]->name);
+ spans[x]->watchstate = ZT_WATCHSTATE_OK;
+ }
+ spans[x]->watchcounter = ZT_WATCHDOG_INIT;
+ }
+ }
+ local_irq_restore(flags);
+ if (!wdcheck) {
+ printk("Zaptel watchdog on duty!\n");
+ wdcheck=1;
+ }
+ mod_timer(&watchdogtimer, jiffies + 2);
+}
+
+static int __init watchdog_init(void)
+{
+ init_timer(&watchdogtimer);
+ watchdogtimer.expires = 0;
+ watchdogtimer.data =0;
+ watchdogtimer.function = watchdog_check;
+ /* Run every couple of jiffy or so */
+ mod_timer(&watchdogtimer, jiffies + 2);
+ return 0;
+}
+
+static void __exit watchdog_cleanup(void)
+{
+ del_timer(&watchdogtimer);
+}
+
+#endif
+
+int zt_register_chardev(struct zt_chardev *dev)
+{
+#ifdef CONFIG_DEVFS_FS
+ umode_t mode = S_IFCHR|S_IRUGO|S_IWUGO;
+#endif /* CONFIG_DEVFS_FS */
+
+#ifdef CONFIG_ZAP_UDEV
+ char udevname[strlen(dev->name) + 3];
+
+ strcpy(udevname, "zap");
+ strcat(udevname, dev->name);
+ CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, dev->minor), NULL, udevname);
+#endif /* CONFIG_ZAP_UDEV */
+
+#ifdef CONFIG_DEVFS_FS
+ dev->devfs_handle = devfs_register(zaptel_devfs_dir, dev->name, DEVFS_FL_DEFAULT, ZT_MAJOR, dev->minor, mode, &zt_fops, NULL);
+#endif /* CONFIG_DEVFS_FS */
+
+ return 0;
+}
+
+int zt_unregister_chardev(struct zt_chardev *dev)
+{
+#ifdef CONFIG_ZAP_UDEV
+ class_device_destroy(zap_class, MKDEV(ZT_MAJOR, dev->minor));
+#endif /* CONFIG_ZAP_UDEV */
+
+#ifdef CONFIG_DEVFS_FS
+ devfs_unregister(dev->devfs_handle);
+#endif /* CONFIG_DEVFS_FS */
+
+ return 0;
+}
+
+static int __init zt_init(void) {
+ int res = 0;
+
+#ifdef CONFIG_PROC_FS
+ proc_entries[0] = proc_mkdir("zaptel", NULL);
+#endif
+
+#ifdef CONFIG_ZAP_UDEV /* udev support functions */
+ zap_class = class_create(THIS_MODULE, "zaptel");
+ CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 253), NULL, "zaptimer");
+ CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 254), NULL, "zapchannel");
+ CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 255), NULL, "zappseudo");
+ CLASS_DEV_CREATE(zap_class, MKDEV(ZT_MAJOR, 0), NULL, "zapctl");
+#endif /* CONFIG_ZAP_UDEV */
+
+#ifdef CONFIG_DEVFS_FS
+ {
+ umode_t mode = S_IFCHR|S_IRUGO|S_IWUGO;
+
+ devfs_register_chrdev(ZT_MAJOR, "zaptel", &zt_fops);
+ if (!(zaptel_devfs_dir = devfs_mk_dir(NULL, "zap", NULL)))
+ return -EBUSY; /* This would be bad */
+ timer = devfs_register(zaptel_devfs_dir, "timer", DEVFS_FL_DEFAULT, ZT_MAJOR, 253, mode, &zt_fops, NULL);
+ channel = devfs_register(zaptel_devfs_dir, "channel", DEVFS_FL_DEFAULT, ZT_MAJOR, 254, mode, &zt_fops, NULL);
+ pseudo = devfs_register(zaptel_devfs_dir, "pseudo", DEVFS_FL_DEFAULT, ZT_MAJOR, 255, mode, &zt_fops, NULL);
+ ctl = devfs_register(zaptel_devfs_dir, "ctl", DEVFS_FL_DEFAULT, ZT_MAJOR, 0, mode, &zt_fops, NULL);
+ }
+#else
+ if ((res = register_chrdev(ZT_MAJOR, "zaptel", &zt_fops))) {
+ printk(KERN_ERR "Unable to register Zaptel character device handler on %d\n", ZT_MAJOR);
+ return res;
+ }
+#endif /* CONFIG_DEVFS_FS */
+
+ printk(KERN_INFO "Zapata Telephony Interface Registered on major %d\n", ZT_MAJOR);
+ printk(KERN_INFO "Zaptel Version: %s\n", ZAPTEL_VERSION);
+ echo_can_init();
+ zt_conv_init();
+ fasthdlc_precalc();
+ rotate_sums();
+ rwlock_init(&chan_lock);
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+ watchdog_init();
+#endif
+ return res;
+}
+
+static void __exit zt_cleanup(void) {
+ int x;
+
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("zaptel", NULL);
+#endif
+
+ printk(KERN_INFO "Zapata Telephony Interface Unloaded\n");
+ for (x = 0; x < ZT_TONE_ZONE_MAX; x++) {
+ if (tone_zones[x])
+ kfree(tone_zones[x]);
+ }
+
+#ifdef CONFIG_DEVFS_FS
+ devfs_unregister(timer);
+ devfs_unregister(channel);
+ devfs_unregister(pseudo);
+ devfs_unregister(ctl);
+ devfs_unregister(zaptel_devfs_dir);
+ devfs_unregister_chrdev(ZT_MAJOR, "zaptel");
+#else
+#ifdef CONFIG_ZAP_UDEV
+ class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 253)); /* timer */
+ class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 254)); /* channel */
+ class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 255)); /* pseudo */
+ class_device_destroy(zap_class, MKDEV(ZT_MAJOR, 0)); /* ctl */
+ class_destroy(zap_class);
+#endif /* CONFIG_ZAP_UDEV */
+ unregister_chrdev(ZT_MAJOR, "zaptel");
+#endif
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+ watchdog_cleanup();
+#endif
+
+ echo_can_shutdown();
+}
+
+module_init(zt_init);
+module_exit(zt_cleanup);
diff --git a/drivers/dahdi/zaptel.h b/drivers/dahdi/zaptel.h
new file mode 100644
index 0000000..81f7946
--- /dev/null
+++ b/drivers/dahdi/zaptel.h
@@ -0,0 +1,2107 @@
+/*
+ * Zapata Telephony Interface
+ *
+ * Written by Mark Spencer <markster@linux-suppot.net>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim@lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001 - 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.
+ */
+
+#ifndef _LINUX_ZAPTEL_H
+#define _LINUX_ZAPTEL_H
+
+#ifdef __KERNEL__
+#include "zconfig.h"
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#include <linux/config.h>
+#endif
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+
+#ifdef CONFIG_ZAPATA_NET
+#include <linux/hdlc.h>
+#endif
+
+#ifdef CONFIG_ZAPATA_PPP
+#include <linux/ppp_channel.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define LINUX26
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
+#define zap_pci_module pci_register_driver
+#else
+#define zap_pci_module pci_module_init
+#endif
+
+#ifdef LINUX26
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
+#define ZAP_IRQ_HANDLER(a) static irqreturn_t a(int irq, void *dev_id)
+#else
+#define ZAP_IRQ_HANDLER(a) static irqreturn_t a(int irq, void *dev_id, struct pt_regs *regs)
+#endif
+#else
+#define ZAP_IRQ_HANDLER(a) static void a(int irq, void *dev_id, struct pt_regs *regs)
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+#define ZAP_IRQ_SHARED IRQF_SHARED
+#define ZAP_IRQ_DISABLED IRQF_DISABLED
+#define ZAP_IRQ_SHARED_DISABLED IRQF_SHARED | IRQF_DISABLED
+#else
+#define ZAP_IRQ_SHARED SA_SHIRQ
+#define ZAP_IRQ_DISABLED SA_INTERRUPT
+#define ZAP_IRQ_SHARED_DISABLED SA_SHIRQ | SA_INTERRUPT
+#endif
+
+#include "ecdis.h"
+#include "fasthdlc.h"
+
+#ifdef CONFIG_DEVFS_FS
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#include <linux/devfs_fs_kernel.h>
+#else
+#undef CONFIG_DEVFS_FS
+//#warning "Zaptel doesn't support DEVFS in post 2.4 kernels. Disabling DEVFS in zaptel"
+#endif
+#endif /* CONFIG_DEVFS_FS */
+#endif /* __KERNEL__ */
+
+#include <linux/types.h>
+
+#ifndef ELAST
+#define ELAST 500
+#endif
+
+/* Per-span configuration values */
+#define ZT_CONFIG_TXLEVEL 7 /* bits 0-2 are tx level */
+
+/* Line configuration */
+/* These apply to T1 */
+#define ZT_CONFIG_D4 (1 << 4)
+#define ZT_CONFIG_ESF (1 << 5)
+#define ZT_CONFIG_AMI (1 << 6)
+#define ZT_CONFIG_B8ZS (1 << 7)
+/* These apply to E1 */
+#define ZT_CONFIG_CCS (1 << 8) /* CCS (ISDN) instead of CAS (Robbed Bit) */
+#define ZT_CONFIG_HDB3 (1 << 9) /* HDB3 instead of AMI (line coding) */
+#define ZT_CONFIG_CRC4 (1 << 10) /* CRC4 framing */
+#define ZT_CONFIG_NOTOPEN (1 << 16)
+
+/* Signalling types */
+#define ZT_SIG_BROKEN (1 << 31) /* The port is broken and/or failed initialization */
+
+#define __ZT_SIG_FXO (1 << 12) /* Never use directly */
+#define __ZT_SIG_FXS (1 << 13) /* Never use directly */
+
+#define ZT_SIG_NONE (0) /* Channel not configured */
+#define ZT_SIG_FXSLS ((1 << 0) | __ZT_SIG_FXS) /* FXS, Loopstart */
+#define ZT_SIG_FXSGS ((1 << 1) | __ZT_SIG_FXS) /* FXS, Groundstart */
+#define ZT_SIG_FXSKS ((1 << 2) | __ZT_SIG_FXS) /* FXS, Kewlstart */
+
+#define ZT_SIG_FXOLS ((1 << 3) | __ZT_SIG_FXO) /* FXO, Loopstart */
+#define ZT_SIG_FXOGS ((1 << 4) | __ZT_SIG_FXO) /* FXO, Groupstart */
+#define ZT_SIG_FXOKS ((1 << 5) | __ZT_SIG_FXO) /* FXO, Kewlstart */
+
+#define ZT_SIG_EM (1 << 6) /* Ear & Mouth (E&M) */
+
+/* The following are all variations on clear channel */
+
+#define __ZT_SIG_DACS (1 << 16)
+
+#define ZT_SIG_CLEAR (1 << 7) /* Clear channel */
+#define ZT_SIG_HDLCRAW ((1 << 8) | ZT_SIG_CLEAR) /* Raw unchecked HDLC */
+#define ZT_SIG_HDLCFCS ((1 << 9) | ZT_SIG_HDLCRAW) /* HDLC with FCS calculation */
+#define ZT_SIG_HDLCNET ((1 << 10) | ZT_SIG_HDLCFCS) /* HDLC Network */
+#define ZT_SIG_SLAVE (1 << 11) /* Slave to another channel */
+#define ZT_SIG_SF (1 << 14) /* Single Freq. tone only, no sig bits */
+#define ZT_SIG_CAS (1 << 15) /* Just get bits */
+#define ZT_SIG_DACS (__ZT_SIG_DACS | ZT_SIG_CLEAR) /* Cross connect */
+#define ZT_SIG_EM_E1 (1 << 17) /* E1 E&M Variation */
+#define ZT_SIG_DACS_RBS ((1 << 18) | __ZT_SIG_DACS) /* Cross connect w/ RBS */
+#define ZT_SIG_HARDHDLC ((1 << 19) | ZT_SIG_CLEAR)
+#define ZT_SIG_MTP2 ((1 << 20) | ZT_SIG_HDLCFCS) /* MTP2 support Need HDLC bitstuff and FCS calcuation too */
+
+/* tone flag values */
+#define ZT_REVERSE_RXTONE 1 /* reverse polarity rx tone logic */
+#define ZT_REVERSE_TXTONE 2 /* reverse polarity tx tone logic */
+
+#define ZT_ABIT 8
+#define ZT_BBIT 4
+#define ZT_CBIT 2
+#define ZT_DBIT 1
+
+#define ZT_MAJOR 196
+
+#define ZT_CODE 'J'
+
+/* Default chunk size for conferences and such -- static right now, might make
+ variable sometime. 8 samples = 1 ms = most frequent service interval possible
+ for a USB device */
+#define ZT_CHUNKSIZE 8
+#define ZT_MIN_CHUNKSIZE ZT_CHUNKSIZE
+#define ZT_DEFAULT_CHUNKSIZE ZT_CHUNKSIZE
+#define ZT_MAX_CHUNKSIZE ZT_CHUNKSIZE
+#define ZT_CB_SIZE 2
+
+#define ZT_MAX_BLOCKSIZE 8192
+#define ZT_DEFAULT_NUM_BUFS 2
+#define ZT_MAX_NUM_BUFS 32
+#define ZT_MAX_BUF_SPACE 32768
+
+#define ZT_DEFAULT_BLOCKSIZE 1024
+#define ZT_DEFAULT_MTR_MRU 2048
+
+#define ZT_POLICY_IMMEDIATE 0 /* Start play/record immediately */
+#define ZT_POLICY_WHEN_FULL 1 /* Start play/record when buffer is full */
+
+#define RING_DEBOUNCE_TIME 2000 /* 2000 ms ring debounce time */
+
+#define ZT_GET_PARAMS_RETURN_MASTER 0x40000000
+
+/* Extended attributes in lineconfig structure */
+#define ZT_SPANINFO_HAS_LINECONFIG
+#define ZT_SPANINFO_HAS_LBONAME
+
+struct zt_params_v1
+{
+ int channo; /* Channel number */
+ int spanno; /* Span itself */
+ int chanpos; /* Channel number in span */
+ int sigtype; /* read-only */
+ int sigcap; /* read-only */
+ int rxisoffhook; /* read-only */
+ int rxbits; /* read-only */
+ int txbits; /* read-only */
+ int txhooksig; /* read-only */
+ int rxhooksig; /* read-only */
+ int curlaw; /* read-only -- one of ZT_LAW_MULAW or ZT_LAW_ALAW */
+ int idlebits; /* read-only -- What is considered the idle state */
+ char name[40]; /* Name of channel */
+ int prewinktime;
+ int preflashtime;
+ int winktime;
+ int flashtime;
+ int starttime;
+ int rxwinktime;
+ int rxflashtime;
+ int debouncetime;
+ int pulsebreaktime;
+ int pulsemaketime;
+ int pulseaftertime;
+};
+
+typedef struct zt_params
+{
+ int channo; /* Channel number */
+ int spanno; /* Span itself */
+ int chanpos; /* Channel number in span */
+ int sigtype; /* read-only */
+ int sigcap; /* read-only */
+ int rxisoffhook; /* read-only */
+ int rxbits; /* read-only */
+ int txbits; /* read-only */
+ int txhooksig; /* read-only */
+ int rxhooksig; /* read-only */
+ int curlaw; /* read-only -- one of ZT_LAW_MULAW or ZT_LAW_ALAW */
+ int idlebits; /* read-only -- What is considered the idle state */
+ char name[40]; /* Name of channel */
+ int prewinktime;
+ int preflashtime;
+ int winktime;
+ int flashtime;
+ int starttime;
+ int rxwinktime;
+ int rxflashtime;
+ int debouncetime;
+ int pulsebreaktime;
+ int pulsemaketime;
+ int pulseaftertime;
+ __u32 chan_alarms; /* alarms on this channel */
+} ZT_PARAMS;
+
+struct zt_spaninfo_v1 {
+ int spanno; /* span number */
+ char name[20]; /* Name */
+ char desc[40]; /* Description */
+ int alarms; /* alarms status */
+ int txlevel; /* what TX level is set to */
+ int rxlevel; /* current RX level */
+ int bpvcount; /* current BPV count */
+ int crc4count; /* current CRC4 error count */
+ int ebitcount; /* current E-bit error count */
+ int fascount; /* current FAS error count */
+ int irqmisses; /* current IRQ misses */
+ int syncsrc; /* span # of current sync source, or 0 for free run */
+ int numchans; /* number of configured channels on this span */
+ int totalchans; /* total number of channels on the span */
+ int totaflspans; /* total number of spans in entire system */
+};
+
+struct zt_spaninfo_v2 {
+ int spanno; /* span number */
+ char name[20]; /* Name */
+ char desc[40]; /* Description */
+ int alarms; /* alarms status */
+ int txlevel; /* what TX level is set to */
+ int rxlevel; /* current RX level */
+ int bpvcount; /* current BPV count */
+ int crc4count; /* current CRC4 error count */
+ int ebitcount; /* current E-bit error count */
+ int fascount; /* current FAS error count */
+ int irqmisses; /* current IRQ misses */
+ int syncsrc; /* span # of current sync source, or 0 for free run */
+ int numchans; /* number of configured channels on this span */
+ int totalchans; /* total number of channels on the span */
+ int totalspans; /* total number of spans in entire system */
+ int lbo; /* line build out */
+ int lineconfig; /* framing/coding */
+};
+
+typedef struct zt_spaninfo {
+ int spanno; /* span number */
+ char name[20]; /* Name */
+ char desc[40]; /* Description */
+ int alarms; /* alarms status */
+ int txlevel; /* what TX level is set to */
+ int rxlevel; /* current RX level */
+ int bpvcount; /* current BPV count */
+ int crc4count; /* current CRC4 error count */
+ int ebitcount; /* current E-bit error count */
+ int fascount; /* current FAS error count */
+ int irqmisses; /* current IRQ misses */
+ int syncsrc; /* span # of current sync source, or 0 for free run */
+ int numchans; /* number of configured channels on this span */
+ int totalchans; /* total number of channels on the span */
+ int totalspans; /* total number of spans in entire system */
+ int lbo; /* line build out */
+ int lineconfig; /* framing/coding */
+ char lboname[40]; /* line build out in text form */
+ char location[40]; /* span's device location in system */
+ char manufacturer[40]; /* manufacturer of span's device */
+ char devicetype[40]; /* span's device type */
+ int irq; /* span's device IRQ */
+ int linecompat; /* signaling modes possible on this span */
+ char spantype[6]; /* type of span in text form */
+} ZT_SPANINFO;
+
+typedef struct zt_maintinfo
+{
+int spanno; /* span number 1-2 */
+int command; /* command */
+} ZT_MAINTINFO;
+
+typedef struct zt_confinfo
+{
+int chan; /* channel number, 0 for current */
+int confno; /* conference number */
+int confmode; /* conferencing mode */
+} ZT_CONFINFO;
+
+typedef struct zt_gains
+{
+int chan; /* channel number, 0 for current */
+unsigned char rxgain[256]; /* Receive gain table */
+unsigned char txgain[256]; /* Transmit gain table */
+} ZT_GAINS;
+
+typedef struct zt_lineconfig
+{
+int span; /* Which span number (0 to use name) */
+char name[20]; /* Name of span to use */
+int lbo; /* line build-outs */
+int lineconfig; /* line config parameters (framing, coding) */
+int sync; /* what level of sync source we are */
+} ZT_LINECONFIG;
+
+typedef struct zt_chanconfig
+{
+int chan; /* Channel we're applying this to (0 to use name) */
+char name[40]; /* Name of channel to use */
+int sigtype; /* Signal type */
+int deflaw; /* Default law (ZT_LAW_DEFAULT, ZT_LAW_MULAW, or ZT_LAW_ALAW */
+int master; /* Master channel if sigtype is ZT_SLAVE */
+int idlebits; /* Idle bits (if this is a CAS channel) or
+ channel to monitor (if this is DACS channel) */
+char netdev_name[16]; /*name for the hdlc network device*/
+} ZT_CHANCONFIG;
+
+typedef struct zt_sfconfig
+{
+int chan; /* Channel we're applying this to (0 to use name) */
+char name[40]; /* Name of channel to use */
+long rxp1; /* receive tone det. p1 */
+long rxp2; /* receive tone det. p2 */
+long rxp3; /* receive tone det. p3 */
+int txtone; /* Tx tone factor */
+int tx_v2; /* initial v2 value */
+int tx_v3; /* initial v3 value */
+int toneflag; /* Tone flags */
+} ZT_SFCONFIG;
+
+typedef struct zt_bufferinfo
+{
+int txbufpolicy; /* Policy for handling receive buffers */
+int rxbufpolicy; /* Policy for handling receive buffers */
+int numbufs; /* How many buffers to use */
+int bufsize; /* How big each buffer is */
+int readbufs; /* How many read buffers are full (read-only) */
+int writebufs; /* How many write buffers are full (read-only) */
+} ZT_BUFFERINFO;
+
+typedef struct zt_dialparams {
+ int mfv1_tonelen; /* MF R1 tone length for digits */
+ int dtmf_tonelen; /* DTMF tone length */
+ int mfr2_tonelen; /* MF R2 tone length */
+ int reserved[3]; /* Reserved for future expansion -- always set to 0 */
+} ZT_DIAL_PARAMS;
+
+typedef struct zt_dynamic_span {
+ char driver[20]; /* Which low-level driver to use */
+ char addr[40]; /* Destination address */
+ int numchans; /* Number of channels */
+ int timing; /* Timing source preference */
+ int spanno; /* Span number (filled in by zaptel) */
+} ZT_DYNAMIC_SPAN;
+
+/* Define the max # of outgoing DTMF, MFR1 or MFR2 digits to queue in-kernel */
+#define ZT_MAX_DTMF_BUF 256
+
+#define ZT_DIAL_OP_APPEND 1
+#define ZT_DIAL_OP_REPLACE 2
+#define ZT_DIAL_OP_CANCEL 3
+
+#define ZT_LAW_DEFAULT 0 /* Default law for span */
+#define ZT_LAW_MULAW 1 /* Mu-law */
+#define ZT_LAW_ALAW 2 /* A-law */
+
+typedef struct zt_dialoperation {
+ int op;
+ char dialstr[ZT_MAX_DTMF_BUF];
+} ZT_DIAL_OPERATION;
+
+
+typedef struct zt_indirect_data
+{
+int chan;
+int op;
+void *data;
+} ZT_INDIRECT_DATA;
+
+struct zt_versioninfo {
+ char version[80];
+ char echo_canceller[80];
+};
+
+struct zt_hwgain{
+ __s32 newgain; /* desired gain in dB but x10. -3.5dB would be -35 */
+ __u32 tx:1; /* 0=rx; 1=tx */
+};
+
+
+/* ioctl definitions */
+#define ZT_CODE 'J'
+
+/*
+ * Get Transfer Block Size.
+ */
+#define ZT_GET_BLOCKSIZE _IOR (ZT_CODE, 1, int)
+
+/*
+ * Set Transfer Block Size.
+ */
+#define ZT_SET_BLOCKSIZE _IOW (ZT_CODE, 2, int)
+
+/*
+ * Flush Buffer(s) and stop I/O
+ */
+#define ZT_FLUSH _IOW (ZT_CODE, 3, int)
+
+/*
+ * Wait for Write to Finish
+ */
+#define ZT_SYNC _IOW (ZT_CODE, 4, int)
+
+/*
+ * Get channel parameters
+ */
+#define ZT_GET_PARAMS_V1 _IOR (ZT_CODE, 5, struct zt_params_v1)
+#define ZT_GET_PARAMS _IOR (ZT_CODE, 5, struct zt_params)
+
+/*
+ * Get channel parameters
+ */
+#define ZT_SET_PARAMS_V1 _IOW (ZT_CODE, 6, struct zt_params_v1)
+#define ZT_SET_PARAMS _IOW (ZT_CODE, 6, struct zt_params)
+
+/*
+ * Set Hookswitch Status
+ */
+#define ZT_HOOK _IOW (ZT_CODE, 7, int)
+
+/*
+ * Get Signalling Event
+ */
+#define ZT_GETEVENT _IOR (ZT_CODE, 8, int)
+
+/*
+ * Wait for something to happen (IO Mux)
+ */
+#define ZT_IOMUX _IOWR (ZT_CODE, 9, int)
+
+/*
+ * Get Span Status
+ */
+#define ZT_SPANSTAT_V1 _IOWR (ZT_CODE, 10, struct zt_spaninfo_v1)
+#define ZT_SPANSTAT_V2 _IOWR (ZT_CODE, 10, struct zt_spaninfo_v2)
+#define ZT_SPANSTAT _IOWR (ZT_CODE, 10, struct zt_spaninfo)
+
+/*
+ * Set Maintenance Mode
+ */
+#define ZT_MAINT _IOW (ZT_CODE, 11, struct zt_maintinfo)
+
+/*
+ * Get Conference Mode
+ */
+#define ZT_GETCONF _IOWR (ZT_CODE, 12, struct zt_confinfo)
+
+/*
+ * Set Conference Mode
+ */
+#define ZT_SETCONF _IOWR (ZT_CODE, 13, struct zt_confinfo)
+
+/*
+ * Setup or Remove Conference Link
+ */
+#define ZT_CONFLINK _IOW (ZT_CODE, 14, struct zt_confinfo)
+
+/*
+ * Display Conference Diagnostic Information on Console
+ */
+#define ZT_CONFDIAG _IOR (ZT_CODE, 15, int)
+
+/*
+ * Get Channel audio gains
+ */
+#define ZT_GETGAINS _IOWR (ZT_CODE, 16, struct zt_gains)
+
+/*
+ * Set Channel audio gains
+ */
+#define ZT_SETGAINS _IOWR (ZT_CODE, 17, struct zt_gains)
+
+/*
+ * Set Line (T1) Configurations and start system
+ */
+#define ZT_SPANCONFIG _IOW (ZT_CODE, 18, struct zt_lineconfig)
+
+/*
+ * Set Channel Configuration
+ */
+#define ZT_CHANCONFIG _IOW (ZT_CODE, 19, struct zt_chanconfig)
+
+/*
+ * Set Conference to mute mode
+ */
+#define ZT_CONFMUTE _IOW (ZT_CODE, 20, int)
+
+/*
+ * Send a particular tone (see ZT_TONE_*)
+ */
+#define ZT_SENDTONE _IOW (ZT_CODE, 21, int)
+
+/*
+ * Set your region for tones (see ZT_TONE_ZONE_*)
+ */
+#define ZT_SETTONEZONE _IOW (ZT_CODE, 22, int)
+
+/*
+ * Retrieve current region for tones (see ZT_TONE_ZONE_*)
+ */
+#define ZT_GETTONEZONE _IOR (ZT_CODE, 23, int)
+
+/*
+ * Master unit only -- set default zone (see ZT_TONE_ZONE_*)
+ */
+#define ZT_DEFAULTZONE _IOW (ZT_CODE, 24, int)
+
+/*
+ * Load a tone zone from a zt_tone_def_header, see
+ * below...
+ */
+#define ZT_LOADZONE _IOW (ZT_CODE, 25, struct zt_tone_def_header)
+
+/*
+ * Free a tone zone
+ */
+#define ZT_FREEZONE _IOW (ZT_CODE, 26, int)
+
+/*
+ * Set buffer policy
+ */
+#define ZT_SET_BUFINFO _IOW (ZT_CODE, 27, struct zt_bufferinfo)
+
+/*
+ * Get current buffer info
+ */
+#define ZT_GET_BUFINFO _IOR (ZT_CODE, 28, struct zt_bufferinfo)
+
+/*
+ * Get dialing parameters
+ */
+#define ZT_GET_DIALPARAMS _IOR (ZT_CODE, 29, struct zt_dialparams)
+
+/*
+ * Set dialing parameters
+ */
+#define ZT_SET_DIALPARAMS _IOW (ZT_CODE, 30, struct zt_dialparams)
+
+/*
+ * Append, replace, or cancel a dial string
+ */
+#define ZT_DIAL _IOW (ZT_CODE, 31, struct zt_dialoperation)
+
+/*
+ * Set a clear channel into audio mode
+ */
+#define ZT_AUDIOMODE _IOW (ZT_CODE, 32, int)
+
+/*
+ * Enable or disable echo cancellation on a channel
+ *
+ * For ECHOCANCEL:
+ * The number is zero to disable echo cancellation and non-zero
+ * to enable echo cancellation. If the number is between 32
+ * and 1024, it will also set the number of taps in the echo canceller
+ *
+ * For ECHOCANCEL_PARAMS:
+ * The structure contains parameters that should be passed to the
+ * echo canceler instance for the selected channel.
+ */
+#define ZT_ECHOCANCEL _IOW (ZT_CODE, 33, int)
+#define ZT_ECHOCANCEL_PARAMS _IOW (ZT_CODE, 33, struct zt_echocanparams)
+
+/*
+ * Return a channel's channel number (useful for the /dev/zap/pseudo type interfaces
+ */
+#define ZT_CHANNO _IOR (ZT_CODE, 34, int)
+
+/*
+ * Return a flag indicating whether channel is currently dialing
+ */
+#define ZT_DIALING _IOR (ZT_CODE, 35, int)
+
+/* Numbers 60 to 90 are reserved for private use of low level hardware
+ drivers */
+
+/*
+ * Set a clear channel into HDLC w/out FCS checking/calculation mode
+ */
+#define ZT_HDLCRAWMODE _IOW (ZT_CODE, 36, int)
+
+/*
+ * Set a clear channel into HDLC w/ FCS mode
+ */
+#define ZT_HDLCFCSMODE _IOW (ZT_CODE, 37, int)
+
+/*
+ * Specify a channel on /dev/zap/chan -- must be done before any other ioctl's and is only
+ * valid on /dev/zap/chan
+ */
+#define ZT_SPECIFY _IOW (ZT_CODE, 38, int)
+
+/*
+ * Temporarily set the law on a channel to
+ * ZT_LAW_DEFAULT, ZT_LAW_ALAW, or ZT_LAW_MULAW. Is reset on close.
+ */
+#define ZT_SETLAW _IOW (ZT_CODE, 39, int)
+
+/*
+ * Temporarily set the channel to operate in linear mode when non-zero
+ * or default law if 0
+ */
+#define ZT_SETLINEAR _IOW (ZT_CODE, 40, int)
+
+/*
+ * Set a clear channel into HDLC w/ PPP interface mode
+ */
+#define ZT_HDLCPPP _IOW (ZT_CODE, 41, int)
+
+/*
+ * Set the ring cadence for FXS interfaces
+ */
+#define ZT_SETCADENCE _IOW (ZT_CODE, 42, struct zt_ring_cadence)
+
+/*
+ * Set the bits going out for CAS interface
+ */
+#define ZT_SETTXBITS _IOW (ZT_CODE, 43, int)
+
+
+/*
+ * Display Channel Diagnostic Information on Console
+ */
+#define ZT_CHANDIAG _IOR (ZT_CODE, 44, int)
+
+/*
+ * Obtain received signalling
+ */
+#define ZT_GETRXBITS _IOR (ZT_CODE, 45, int)
+
+/*
+ * Set Channel's SF Tone Configuration
+ */
+#define ZT_SFCONFIG _IOW (ZT_CODE, 46, struct zt_sfconfig)
+
+/*
+ * Set timer expiration (in samples)
+ */
+#define ZT_TIMERCONFIG _IOW (ZT_CODE, 47, int)
+
+/*
+ * Acknowledge timer expiration (number to acknowledge, or -1 for all)
+ */
+#define ZT_TIMERACK _IOW (ZT_CODE, 48, int)
+
+/*
+ * Get Conference to mute mode
+ */
+#define ZT_GETCONFMUTE _IOR (ZT_CODE, 49, int)
+
+/*
+ * Request echo training in some number of ms (with muting in the mean time)
+ */
+#define ZT_ECHOTRAIN _IOW (ZT_CODE, 50, int)
+
+/*
+ * Set on hook transfer for n number of ms -- implemnted by low level driver
+ */
+#define ZT_ONHOOKTRANSFER _IOW (ZT_CODE, 51, int)
+
+/*
+ * Queue Ping
+ */
+#define ZT_TIMERPING _IOW (ZT_CODE, 42, int) /* Should be 52, but works */
+
+/*
+ * Acknowledge ping
+ */
+#define ZT_TIMERPONG _IOW (ZT_CODE, 53, int)
+
+/*
+ * Set/get signalling freeze
+ */
+#define ZT_SIGFREEZE _IOW (ZT_CODE, 54, int)
+#define ZT_GETSIGFREEZE _IOR (ZT_CODE, 55, int)
+
+/*
+ * Do a channel IOCTL from the /dev/zap/ctl interface
+ */
+#define ZT_INDIRECT _IOWR (ZT_CODE, 56, struct zt_indirect_data)
+
+
+/*
+ * Get the version of Zaptel that is running, and a description
+ * of the compiled-in echo canceller (if any)
+ */
+#define ZT_GETVERSION _IOR(ZT_CODE, 57, struct zt_versioninfo)
+
+/*
+ * Put the channel in loopback mode (receive from the channel is
+ * transmitted back on the interface)
+ */
+#define ZT_LOOPBACK _IOW(ZT_CODE, 58, int)
+
+
+/*
+ * 60-80 are reserved for private drivers
+ * 80-85 are reserved for dynamic span stuff
+ */
+
+/*
+ * Create a dynamic span
+ */
+#define ZT_DYNAMIC_CREATE _IOWR (ZT_CODE, 80, struct zt_dynamic_span)
+
+/*
+ * Destroy a dynamic span
+ */
+#define ZT_DYNAMIC_DESTROY _IOW (ZT_CODE, 81, struct zt_dynamic_span)
+
+/*
+ * Set the HW gain for a device
+ */
+#define ZT_SET_HWGAIN _IOW (ZT_CODE, 86, struct zt_hwgain)
+
+/*
+ * Enable tone detection -- implemented by low level driver
+ */
+#define ZT_TONEDETECT _IOW (ZT_CODE, 91, int)
+
+/*
+ * Set polarity -- implemented by individual driver. 0 = forward, 1 = reverse
+ */
+#define ZT_SETPOLARITY _IOW (ZT_CODE, 92, int)
+
+/*
+ * Transcoder operations
+ */
+#define ZT_TRANSCODE_OP _IOWR(ZT_CODE, 93, int)
+
+/*
+ * VoiceMail Waiting Indication (WMWI) -- implemented by low-level driver.
+ * Value: number of waiting messages (hence 0: switch messages off).
+ */
+#define ZT_VMWI _IOWR(ZT_CODE, 94, int)
+
+/*
+ * Startup or Shutdown a span
+ */
+#define ZT_STARTUP _IOW (ZT_CODE, 99, int)
+#define ZT_SHUTDOWN _IOW (ZT_CODE, 100, int)
+
+#define ZT_TONE_ZONE_MAX 128
+
+#define ZT_TONE_ZONE_DEFAULT -1 /* To restore default */
+
+#define ZT_TONE_STOP -1
+#define ZT_TONE_DIALTONE 0
+#define ZT_TONE_BUSY 1
+#define ZT_TONE_RINGTONE 2
+#define ZT_TONE_CONGESTION 3
+#define ZT_TONE_CALLWAIT 4
+#define ZT_TONE_DIALRECALL 5
+#define ZT_TONE_RECORDTONE 6
+#define ZT_TONE_INFO 7
+#define ZT_TONE_CUST1 8
+#define ZT_TONE_CUST2 9
+#define ZT_TONE_STUTTER 10
+#define ZT_TONE_MAX 16
+
+#define ZT_TONE_DTMF_BASE 64
+#define ZT_TONE_MFR1_BASE 80
+#define ZT_TONE_MFR2_FWD_BASE 96
+#define ZT_TONE_MFR2_REV_BASE 112
+
+enum {
+ ZT_TONE_DTMF_0 = ZT_TONE_DTMF_BASE,
+ ZT_TONE_DTMF_1,
+ ZT_TONE_DTMF_2,
+ ZT_TONE_DTMF_3,
+ ZT_TONE_DTMF_4,
+ ZT_TONE_DTMF_5,
+ ZT_TONE_DTMF_6,
+ ZT_TONE_DTMF_7,
+ ZT_TONE_DTMF_8,
+ ZT_TONE_DTMF_9,
+ ZT_TONE_DTMF_s,
+ ZT_TONE_DTMF_p,
+ ZT_TONE_DTMF_A,
+ ZT_TONE_DTMF_B,
+ ZT_TONE_DTMF_C,
+ ZT_TONE_DTMF_D
+};
+
+#define ZT_TONE_DTMF_MAX ZT_TONE_DTMF_D
+
+enum {
+ ZT_TONE_MFR1_0 = ZT_TONE_MFR1_BASE,
+ ZT_TONE_MFR1_1,
+ ZT_TONE_MFR1_2,
+ ZT_TONE_MFR1_3,
+ ZT_TONE_MFR1_4,
+ ZT_TONE_MFR1_5,
+ ZT_TONE_MFR1_6,
+ ZT_TONE_MFR1_7,
+ ZT_TONE_MFR1_8,
+ ZT_TONE_MFR1_9,
+ ZT_TONE_MFR1_KP,
+ ZT_TONE_MFR1_ST,
+ ZT_TONE_MFR1_STP,
+ ZT_TONE_MFR1_ST2P,
+ ZT_TONE_MFR1_ST3P,
+};
+
+#define ZT_TONE_MFR1_MAX ZT_TONE_MFR1_ST3P
+
+enum {
+ ZT_TONE_MFR2_FWD_1 = ZT_TONE_MFR2_FWD_BASE,
+ ZT_TONE_MFR2_FWD_2,
+ ZT_TONE_MFR2_FWD_3,
+ ZT_TONE_MFR2_FWD_4,
+ ZT_TONE_MFR2_FWD_5,
+ ZT_TONE_MFR2_FWD_6,
+ ZT_TONE_MFR2_FWD_7,
+ ZT_TONE_MFR2_FWD_8,
+ ZT_TONE_MFR2_FWD_9,
+ ZT_TONE_MFR2_FWD_10,
+ ZT_TONE_MFR2_FWD_11,
+ ZT_TONE_MFR2_FWD_12,
+ ZT_TONE_MFR2_FWD_13,
+ ZT_TONE_MFR2_FWD_14,
+ ZT_TONE_MFR2_FWD_15,
+};
+
+#define ZT_TONE_MFR2_FWD_MAX ZT_TONE_MFR2_FWD_15
+
+enum {
+ ZT_TONE_MFR2_REV_1 = ZT_TONE_MFR2_REV_BASE,
+ ZT_TONE_MFR2_REV_2,
+ ZT_TONE_MFR2_REV_3,
+ ZT_TONE_MFR2_REV_4,
+ ZT_TONE_MFR2_REV_5,
+ ZT_TONE_MFR2_REV_6,
+ ZT_TONE_MFR2_REV_7,
+ ZT_TONE_MFR2_REV_8,
+ ZT_TONE_MFR2_REV_9,
+ ZT_TONE_MFR2_REV_10,
+ ZT_TONE_MFR2_REV_11,
+ ZT_TONE_MFR2_REV_12,
+ ZT_TONE_MFR2_REV_13,
+ ZT_TONE_MFR2_REV_14,
+ ZT_TONE_MFR2_REV_15,
+};
+
+#define ZT_TONE_MFR2_REV_MAX ZT_TONE_MFR2_REV_15
+
+#define ZT_MAX_CADENCE 16
+
+#define ZT_TONEDETECT_ON (1 << 0) /* Detect tones */
+#define ZT_TONEDETECT_MUTE (1 << 1) /* Mute audio in received channel */
+
+#define ZT_TRANSCODE_MAGIC 0x74a9c0de
+
+/* Operations */
+#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_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)
+
+typedef struct zt_transcode_header {
+ unsigned int srcfmt; /* See formats.h -- use TCOP_RESET when you change */
+ unsigned int srcoffset; /* In bytes -- written by user */
+ unsigned int srclen; /* In bytes -- written by user */
+ unsigned int srctimestamp; /* In samples -- written by user (only used if ZT_TCCONF_USETS is set) */
+ unsigned int srcseqno; /* In units -- written by user (only used if ZT_TCCONF_USESEQ is set) */
+
+ unsigned int dstfmt; /* See formats.h -- use TCOP_RESET when you change */
+ unsigned int dstoffset; /* In bytes -- written by user */
+ unsigned int dsttimestamp; /* In samples -- read by user */
+ unsigned int dstseqno; /* In units -- read by user (only used if ZT_TCCONF_USESEQ is set) */
+ unsigned int dstlen; /* In bytes -- read by user */
+ unsigned int dstsamples; /* In timestamp units -- read by user */
+
+ 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 */
+ 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 */
+} ZT_TRANSCODE_HEADER;
+
+struct zt_ring_cadence {
+ int ringcadence[ZT_MAX_CADENCE];
+};
+
+#define ZT_MAX_ECHOCANPARAMS 8
+
+struct zt_echocanparam {
+ char name[16];
+ __s32 value;
+};
+
+struct zt_echocanparams {
+ __u32 tap_length; /* 8 taps per millisecond */
+ __u32 param_count; /* number of parameters supplied */
+ /* immediately follow this structure with zt_echocanparam structures */
+ struct zt_echocanparam params[0];
+};
+
+struct zt_tone_def_header {
+ int count; /* How many samples follow */
+ int zone; /* Which zone we are loading */
+ int ringcadence[ZT_MAX_CADENCE]; /* Ring cadence in ms (0=on, 1=off, ends with 0 value) */
+ char name[40]; /* Informational name of zone */
+ /* Immediately follow the zt_tone_def_header by zt_tone_def's */
+};
+
+struct zt_tone_def { /* Structure for zone programming */
+ int tone; /* See ZT_TONE_* */
+ int next; /* What the next position in the cadence is
+ (They're numbered by the order the appear here) */
+ int samples; /* How many samples to play for this cadence */
+ /* Now come the constants we need to make tones */
+ int shift; /* How much to scale down the volume (2 is nice) */
+
+ /*
+ Calculate the next 6 factors using the following equations:
+ l = <level in dbm>, f1 = <freq1>, f2 = <freq2>
+ gain = pow(10.0, (l - 3.14) / 20.0) * 65536.0 / 2.0;
+
+ // Frequency factor 1
+ fac_1 = 2.0 * cos(2.0 * M_PI * (f1/8000.0)) * 32768.0;
+ // Last previous two samples
+ init_v2_1 = sin(-4.0 * M_PI * (f1/8000.0)) * gain;
+ init_v3_1 = sin(-2.0 * M_PI * (f1/8000.0)) * gain;
+
+ // Frequency factor 2
+ fac_2 = 2.0 * cos(2.0 * M_PI * (f2/8000.0)) * 32768.0;
+ // Last previous two samples
+ init_v2_2 = sin(-4.0 * M_PI * (f2/8000.0)) * gain;
+ init_v3_2 = sin(-2.0 * M_PI * (f2/8000.0)) * gain;
+ */
+ int fac1;
+ int init_v2_1;
+ int init_v3_1;
+ int fac2;
+ int init_v2_2;
+ int init_v3_2;
+ int modulate;
+
+};
+
+#ifdef __KERNEL__
+#endif /* KERNEL */
+
+/* Define the maximum block size */
+#define ZT_MAX_BLOCKSIZE 8192
+
+/* Define the default network block size */
+#define ZT_DEFAULT_MTU_MRU 2048
+
+/* Flush and stop the read (input) process */
+#define ZT_FLUSH_READ 1
+
+/* Flush and stop the write (output) process */
+#define ZT_FLUSH_WRITE 2
+
+/* Flush and stop both (input and output) processes */
+#define ZT_FLUSH_BOTH (ZT_FLUSH_READ | ZT_FLUSH_WRITE)
+
+/* Flush the event queue */
+#define ZT_FLUSH_EVENT 4
+
+/* Flush everything */
+#define ZT_FLUSH_ALL (ZT_FLUSH_READ | ZT_FLUSH_WRITE | ZT_FLUSH_EVENT)
+
+
+/* Value for ZT_HOOK, set to ON hook */
+#define ZT_ONHOOK 0
+
+/* Value for ZT_HOOK, set to OFF hook */
+#define ZT_OFFHOOK 1
+
+/* Value for ZT_HOOK, wink (off hook momentarily) */
+#define ZT_WINK 2
+
+/* Value for ZT_HOOK, flash (on hook momentarily) */
+#define ZT_FLASH 3
+
+/* Value for ZT_HOOK, start line */
+#define ZT_START 4
+
+/* Value for ZT_HOOK, ring line (same as start line) */
+#define ZT_RING 5
+
+/* Value for ZT_HOOK, turn ringer off */
+#define ZT_RINGOFF 6
+
+/* Ret. Value for GET/WAIT Event, no event */
+#define ZT_EVENT_NONE 0
+
+/* Ret. Value for GET/WAIT Event, Went Onhook */
+#define ZT_EVENT_ONHOOK 1
+
+/* Ret. Value for GET/WAIT Event, Went Offhook or got Ring */
+#define ZT_EVENT_RINGOFFHOOK 2
+
+/* Ret. Value for GET/WAIT Event, Got Wink or Flash */
+#define ZT_EVENT_WINKFLASH 3
+
+/* Ret. Value for GET/WAIT Event, Got Alarm */
+#define ZT_EVENT_ALARM 4
+
+/* Ret. Value for GET/WAIT Event, Got No Alarm (after alarm) */
+#define ZT_EVENT_NOALARM 5
+
+/* Ret. Value for GET/WAIT Event, HDLC Abort frame */
+#define ZT_EVENT_ABORT 6
+
+/* Ret. Value for GET/WAIT Event, HDLC Frame overrun */
+#define ZT_EVENT_OVERRUN 7
+
+/* Ret. Value for GET/WAIT Event, Bad FCS */
+#define ZT_EVENT_BADFCS 8
+
+/* Ret. Value for dial complete */
+#define ZT_EVENT_DIALCOMPLETE 9
+
+/* Ret Value for ringer going on */
+#define ZT_EVENT_RINGERON 10
+
+/* Ret Value for ringer going off */
+#define ZT_EVENT_RINGEROFF 11
+
+/* Ret Value for hook change complete */
+#define ZT_EVENT_HOOKCOMPLETE 12
+
+/* Ret Value for bits changing on a CAS / User channel */
+#define ZT_EVENT_BITSCHANGED 13
+
+/* Ret value for the beginning of a pulse coming on its way */
+#define ZT_EVENT_PULSE_START 14
+
+/* Timer event -- timer expired */
+#define ZT_EVENT_TIMER_EXPIRED 15
+
+/* Timer event -- ping ready */
+#define ZT_EVENT_TIMER_PING 16
+
+/* Polarity reversal event */
+#define ZT_EVENT_POLARITY 17
+
+/* Ring Begin event */
+#define ZT_EVENT_RINGBEGIN 18
+
+/* Echo can disabled event */
+#define ZT_EVENT_EC_DISABLED 19
+
+/* Channel was disconnected. Hint user to close channel */
+#define ZT_EVENT_REMOVED 20
+
+/* A neon MWI pulse was detected */
+#define ZT_EVENT_NEONMWI_ACTIVE 21
+
+/* No neon MWI pulses were detected over some period of time */
+#define ZT_EVENT_NEONMWI_INACTIVE 22
+
+#define ZT_EVENT_PULSEDIGIT (1 << 16) /* This is OR'd with the digit received */
+#define ZT_EVENT_DTMFDOWN (1 << 17) /* Ditto for DTMF key down event */
+#define ZT_EVENT_DTMFUP (1 << 18) /* Ditto for DTMF key up event */
+
+/* Flag Value for IOMUX, read avail */
+#define ZT_IOMUX_READ 1
+
+/* Flag Value for IOMUX, write avail */
+#define ZT_IOMUX_WRITE 2
+
+/* Flag Value for IOMUX, write done */
+#define ZT_IOMUX_WRITEEMPTY 4
+
+/* Flag Value for IOMUX, signalling event avail */
+#define ZT_IOMUX_SIGEVENT 8
+
+/* Flag Value for IOMUX, Do Not Wait if nothing to report */
+#define ZT_IOMUX_NOWAIT 0x100
+
+/* Alarm Condition bits */
+#define ZT_ALARM_NONE 0 /* No alarms */
+#define ZT_ALARM_RECOVER 1 /* Recovering from alarm */
+#define ZT_ALARM_LOOPBACK 2 /* In loopback */
+#define ZT_ALARM_YELLOW 4 /* Yellow Alarm */
+#define ZT_ALARM_RED 8 /* Red Alarm */
+#define ZT_ALARM_BLUE 16 /* Blue Alarm */
+#define ZT_ALARM_NOTOPEN 32
+/* Maintenance modes */
+#define ZT_MAINT_NONE 0 /* Normal Mode */
+#define ZT_MAINT_LOCALLOOP 1 /* Local Loopback */
+#define ZT_MAINT_REMOTELOOP 2 /* Remote Loopback */
+#define ZT_MAINT_LOOPUP 3 /* send loopup code */
+#define ZT_MAINT_LOOPDOWN 4 /* send loopdown code */
+#define ZT_MAINT_LOOPSTOP 5 /* stop sending loop codes */
+
+
+/* Conference modes */
+#define ZT_CONF_MODE_MASK 0xff /* mask for modes */
+#define ZT_CONF_NORMAL 0 /* normal mode */
+#define ZT_CONF_MONITOR 1 /* monitor mode (rx of other chan) */
+#define ZT_CONF_MONITORTX 2 /* monitor mode (tx of other chan) */
+#define ZT_CONF_MONITORBOTH 3 /* monitor mode (rx & tx of other chan) */
+#define ZT_CONF_CONF 4 /* conference mode */
+#define ZT_CONF_CONFANN 5 /* conference announce mode */
+#define ZT_CONF_CONFMON 6 /* conference monitor mode */
+#define ZT_CONF_CONFANNMON 7 /* conference announce/monitor mode */
+#define ZT_CONF_REALANDPSEUDO 8 /* real and pseudo port both on conf */
+#define ZT_CONF_DIGITALMON 9 /* Do not decode or interpret */
+#define ZT_CONF_MONITOR_RX_PREECHO 10 /* monitor mode (rx of other chan) - before echo can is done */
+#define ZT_CONF_MONITOR_TX_PREECHO 11 /* monitor mode (tx of other chan) - before echo can is done */
+#define ZT_CONF_MONITORBOTH_PREECHO 12 /* monitor mode (rx & tx of other chan) - before echo can is done */
+#define ZT_CONF_FLAG_MASK 0xff00 /* mask for flags */
+#define ZT_CONF_LISTENER 0x100 /* is a listener on the conference */
+#define ZT_CONF_TALKER 0x200 /* is a talker on the conference */
+#define ZT_CONF_PSEUDO_LISTENER 0x400 /* pseudo is a listener on the conference */
+#define ZT_CONF_PSEUDO_TALKER 0x800 /* pseudo is a talker on the conference */
+
+
+#define ZT_DEFAULT_WINKTIME 150 /* 150 ms default wink time */
+#define ZT_DEFAULT_FLASHTIME 750 /* 750 ms default flash time */
+
+#define ZT_DEFAULT_PREWINKTIME 50 /* 50 ms before wink */
+#define ZT_DEFAULT_PREFLASHTIME 50 /* 50 ms before flash */
+#define ZT_DEFAULT_STARTTIME 1500 /* 1500 ms of start */
+#define ZT_DEFAULT_RINGTIME 2000 /* 2000 ms of ring on (start, FXO) */
+#if 0
+#define ZT_DEFAULT_RXWINKTIME 250 /* 250ms longest rx wink */
+#endif
+#define ZT_DEFAULT_RXWINKTIME 300 /* 300ms longest rx wink (to work with the Atlas) */
+#define ZT_DEFAULT_RXFLASHTIME 1250 /* 1250ms longest rx flash */
+#define ZT_DEFAULT_DEBOUNCETIME 600 /* 600ms of FXS GS signalling debounce */
+#define ZT_DEFAULT_PULSEMAKETIME 50 /* 50 ms of line closed when dial pulsing */
+#define ZT_DEFAULT_PULSEBREAKTIME 50 /* 50 ms of line open when dial pulsing */
+#define ZT_DEFAULT_PULSEAFTERTIME 750 /* 750ms between dial pulse digits */
+
+#define ZT_MINPULSETIME (15 * 8) /* 15 ms minimum */
+
+#ifdef SHORT_FLASH_TIME
+#define ZT_MAXPULSETIME (80 * 8) /* we need 80 ms, not 200ms, as we have a short flash */
+#else
+#define ZT_MAXPULSETIME (200 * 8) /* 200 ms maximum */
+#endif
+
+#define ZT_PULSETIMEOUT ((ZT_MAXPULSETIME / 8) + 50)
+
+#define ZT_RINGTRAILER (50 * 8) /* Don't consider a ring "over" until it's been gone at least this
+ much time */
+
+#define ZT_LOOPCODE_TIME 10000 /* send loop codes for 10 secs */
+#define ZT_ALARMSETTLE_TIME 5000 /* allow alarms to settle for 5 secs */
+#define ZT_AFTERSTART_TIME 500 /* 500ms after start */
+
+#define ZT_RINGOFFTIME 4000 /* Turn off ringer for 4000 ms */
+#define ZT_KEWLTIME 500 /* 500ms for kewl pulse */
+#define ZT_AFTERKEWLTIME 300 /* 300ms after kewl pulse */
+
+#define ZT_MAX_PRETRAINING 1000 /* 1000ms max pretraining time */
+
+#define ZT_MAX_SPANS 128 /* Max, 128 spans */
+#define ZT_MAX_CHANNELS 1024 /* Max, 1024 channels */
+#define ZT_MAX_CONF 1024 /* Max, 1024 conferences */
+
+#ifdef FXSFLASH
+#define ZT_FXSFLASHMINTIME 450 /* min 450ms */
+#define ZT_FXSFLASHMAXTIME 550 /* max 550ms */
+#endif
+
+#ifdef __KERNEL__
+
+#include <linux/poll.h>
+
+#define ZT_MAX_EVENTSIZE 64 /* 64 events max in buffer */
+
+struct zt_span;
+struct zt_chan;
+
+struct zt_tone_state {
+ int v1_1;
+ int v2_1;
+ int v3_1;
+ int v1_2;
+ int v2_2;
+ int v3_2;
+ int modulate;
+};
+
+struct zt_chardev {
+ const char *name;
+ __u8 minor;
+#ifdef CONFIG_DEVFS_FS
+ devfs_handle_t devfs_handle;
+#endif
+};
+
+int zt_register_chardev(struct zt_chardev *dev);
+int zt_unregister_chardev(struct zt_chardev *dev);
+
+#ifdef CONFIG_ZAPATA_NET
+struct zt_hdlc {
+#ifdef LINUX26
+ struct net_device *netdev;
+#else
+ hdlc_device netdev;
+#endif
+ struct zt_chan *chan;
+};
+#endif
+
+/* Echo cancellation */
+struct echo_can_state;
+#if 0
+/* echo can API consists of these functions */
+void echo_can_init(void);
+void echo_chan_shutdown(void);
+void echo_can_identify(char *buf, size_t len);
+int echo_can_create(struct zt_echocanparams *ecp, struct zt_echocanparam *p, struct echo_can_state **ec);
+void echo_can_free(struct echo_can_state *ec);
+short echo_can_update(struct echo_can_state *ec, short iref, short isig);
+void echo_can_array_update(struct echo_can_state *ec, short *iref, short *isig);
+int echo_can_traintap(struct echo_can_state *ec, int pos, short val);
+#endif
+
+/* Conference queue stucture */
+struct confq {
+ u_char buffer[ZT_CHUNKSIZE * ZT_CB_SIZE];
+ u_char *buf[ZT_CB_SIZE];
+ int inbuf;
+ int outbuf;
+};
+
+typedef struct
+{
+ long x1;
+ long x2;
+ long y1;
+ long y2;
+ long e1;
+ long e2;
+ int samps;
+ int lastdetect;
+} sf_detect_state_t;
+
+struct zt_chan {
+#ifdef CONFIG_ZAPATA_NET
+ /* Must be first */
+ struct zt_hdlc *hdlcnetdev;
+#endif
+#ifdef CONFIG_ZAPATA_PPP
+ struct ppp_channel *ppp;
+ struct tasklet_struct ppp_calls;
+ int do_ppp_wakeup;
+ int do_ppp_error;
+ struct sk_buff_head ppp_rq;
+#endif
+ spinlock_t lock;
+ char name[40]; /* Name */
+ /* Specified by zaptel */
+ int channo; /* Zaptel Channel number */
+ int chanpos;
+ unsigned long flags;
+ long rxp1;
+ long rxp2;
+ long rxp3;
+ int txtone;
+ int tx_v2;
+ int tx_v3;
+ int v1_1;
+ int v2_1;
+ int v3_1;
+ int toneflags;
+ sf_detect_state_t rd;
+
+ struct zt_chan *master; /* Our Master channel (could be us) */
+ /* Next slave (if appropriate) */
+ int nextslave;
+
+ u_char *writechunk; /* Actual place to write to */
+ u_char swritechunk[ZT_MAX_CHUNKSIZE]; /* Buffer to be written */
+ u_char *readchunk; /* Actual place to read from */
+ u_char sreadchunk[ZT_MAX_CHUNKSIZE]; /* Preallocated static area */
+ short *readchunkpreec;
+
+ /* Pointer to tx and rx gain tables */
+ u_char *rxgain;
+ u_char *txgain;
+
+ /* Whether or not we have allocated gains or are using the default */
+ int gainalloc;
+
+ /* Specified by driver, readable by zaptel */
+ void *pvt; /* Private channel data */
+ struct file *file; /* File structure */
+
+
+ struct zt_span *span; /* Span we're a member of */
+ int sig; /* Signalling */
+ int sigcap; /* Capability for signalling */
+ __u32 chan_alarms; /* alarms status */
+
+ /* Used only by zaptel -- NO DRIVER SERVICEABLE PARTS BELOW */
+ /* Buffer declarations */
+ u_char *readbuf[ZT_MAX_NUM_BUFS]; /* read buffer */
+ int inreadbuf;
+ int outreadbuf;
+ wait_queue_head_t readbufq; /* read wait queue */
+
+ u_char *writebuf[ZT_MAX_NUM_BUFS]; /* write buffers */
+ int inwritebuf;
+ int outwritebuf;
+ wait_queue_head_t writebufq; /* write wait queue */
+
+ int blocksize; /* Block size */
+
+ int eventinidx; /* out index in event buf (circular) */
+ int eventoutidx; /* in index in event buf (circular) */
+ unsigned int eventbuf[ZT_MAX_EVENTSIZE]; /* event circ. buffer */
+ wait_queue_head_t eventbufq; /* event wait queue */
+
+ wait_queue_head_t txstateq; /* waiting on the tx state to change */
+
+ int readn[ZT_MAX_NUM_BUFS]; /* # of bytes ready in read buf */
+ int readidx[ZT_MAX_NUM_BUFS]; /* current read pointer */
+ int writen[ZT_MAX_NUM_BUFS]; /* # of bytes ready in write buf */
+ int writeidx[ZT_MAX_NUM_BUFS]; /* current write pointer */
+
+ int numbufs; /* How many buffers in channel */
+ int txbufpolicy; /* Buffer policy */
+ int rxbufpolicy; /* Buffer policy */
+ int txdisable; /* Disable transmitter */
+ int rxdisable; /* Disable receiver */
+
+
+ /* Tone zone stuff */
+ struct zt_zone *curzone; /* Zone for selecting tones */
+ int tonezone; /* Tone zone for this channel */
+ struct zt_tone *curtone; /* Current tone we're playing (if any) */
+ int tonep; /* Current position in tone */
+ struct zt_tone_state ts; /* Tone state */
+
+ /* Pulse dial stuff */
+ int pdialcount; /* pulse dial count */
+
+ /* Ring cadence */
+ int ringcadence[ZT_MAX_CADENCE];
+ int firstcadencepos; /* Where to restart ring cadence */
+
+ /* Digit string dialing stuff */
+ int digitmode; /* What kind of tones are we sending? */
+ char txdialbuf[ZT_MAX_DTMF_BUF];
+ int dialing;
+ int afterdialingtimer;
+ int cadencepos; /* Where in the cadence we are */
+
+ /* I/O Mask */
+ int iomask; /* I/O Mux signal mask */
+ wait_queue_head_t sel; /* thingy for select stuff */
+
+ /* HDLC state machines */
+ struct fasthdlc_state txhdlc;
+ struct fasthdlc_state rxhdlc;
+ int infcs;
+
+ /* Conferencing stuff */
+ int confna; /* conference number (alias) */
+ int _confn; /* Actual conference number */
+ int confmode; /* conference mode */
+ int confmute; /* conference mute mode */
+
+ /* Incoming and outgoing conference chunk queues for
+ communicating between zaptel master time and
+ other boards */
+ struct confq confin;
+ struct confq confout;
+
+ short getlin[ZT_MAX_CHUNKSIZE]; /* Last transmitted samples */
+ unsigned char getraw[ZT_MAX_CHUNKSIZE]; /* Last received raw data */
+ short getlin_lastchunk[ZT_MAX_CHUNKSIZE]; /* Last transmitted samples from last chunk */
+ short putlin[ZT_MAX_CHUNKSIZE]; /* Last received samples */
+ unsigned char putraw[ZT_MAX_CHUNKSIZE]; /* Last received raw data */
+ short conflast[ZT_MAX_CHUNKSIZE]; /* Last conference sample -- base part of channel */
+ short conflast1[ZT_MAX_CHUNKSIZE]; /* Last conference sample -- pseudo part of channel */
+ short conflast2[ZT_MAX_CHUNKSIZE]; /* Previous last conference sample -- pseudo part of channel */
+
+
+ /* Is echo cancellation enabled or disabled */
+ int echocancel;
+ struct echo_can_state *ec;
+ echo_can_disable_detector_state_t txecdis;
+ echo_can_disable_detector_state_t rxecdis;
+
+ int echostate; /* State of echo canceller */
+ int echolastupdate; /* Last echo can update pos */
+ int echotimer; /* Timer for echo update */
+
+ /* RBS timings */
+ int prewinktime; /* pre-wink time (ms) */
+ int preflashtime; /* pre-flash time (ms) */
+ int winktime; /* wink time (ms) */
+ int flashtime; /* flash time (ms) */
+ int starttime; /* start time (ms) */
+ int rxwinktime; /* rx wink time (ms) */
+ int rxflashtime; /* rx flash time (ms) */
+ int debouncetime; /* FXS GS sig debounce time (ms) */
+ int pulsebreaktime; /* pulse line open time (ms) */
+ int pulsemaketime; /* pulse line closed time (ms) */
+ int pulseaftertime; /* pulse time between digits (ms) */
+
+ /* RING debounce timer */
+ int ringdebtimer;
+
+ /* RING trailing detector to make sure a RING is really over */
+ int ringtrailer;
+
+ /* PULSE digit receiver stuff */
+ int pulsecount;
+ int pulsetimer;
+
+ /* RBS timers */
+ int itimerset; /* what the itimer was set to last */
+ int itimer;
+ int otimer;
+
+ /* RBS state */
+ int gotgs;
+ int txstate;
+ int rxsig;
+ int txsig;
+ int rxsigstate;
+
+ /* non-RBS rx state */
+ int rxhooksig;
+ int txhooksig;
+ int kewlonhook;
+
+ /* Idle signalling if CAS signalling */
+ int idlebits;
+
+ int deflaw; /* 1 = mulaw, 2=alaw, 0=undefined */
+ short *xlaw;
+#ifdef OPTIMIZE_CHANMUTE
+ int chanmute; /*!< no need for PCM data */
+#endif
+#ifdef CONFIG_CALC_XLAW
+ unsigned char (*lineartoxlaw)(short a);
+#else
+ unsigned char *lin2x;
+#endif
+
+#ifdef CONFIG_DEVFS_FS
+ devfs_handle_t fhandle; /* File handle in devfs for the channel */
+ devfs_handle_t fhandle_symlink;
+#endif /* CONFIG_DEVFS_FS */
+};
+
+/* defines for transmit signalling */
+typedef enum {
+ ZT_TXSIG_ONHOOK, /* On hook */
+ ZT_TXSIG_OFFHOOK, /* Off hook */
+ ZT_TXSIG_START, /* Start / Ring */
+ ZT_TXSIG_KEWL /* Drop battery if possible */
+} zt_txsig_t;
+
+typedef enum {
+ ZT_RXSIG_ONHOOK,
+ ZT_RXSIG_OFFHOOK,
+ ZT_RXSIG_START,
+ ZT_RXSIG_RING,
+ ZT_RXSIG_INITIAL
+} zt_rxsig_t;
+
+/* Span flags */
+#define ZT_FLAG_REGISTERED (1 << 0)
+#define ZT_FLAG_RUNNING (1 << 1)
+#define ZT_FLAG_RBS (1 << 12) /* Span uses RBS signalling */
+
+/* Channel flags */
+#define ZT_FLAG_DTMFDECODE (1 << 2) /* Channel supports native DTMF decode */
+#define ZT_FLAG_MFDECODE (1 << 3) /* Channel supports native MFr2 decode */
+#define ZT_FLAG_ECHOCANCEL (1 << 4) /* Channel supports native echo cancellation */
+
+#define ZT_FLAG_HDLC (1 << 5) /* Perform HDLC */
+#define ZT_FLAG_NETDEV (1 << 6) /* Send to network */
+#define ZT_FLAG_PSEUDO (1 << 7) /* Pseudo channel */
+#define ZT_FLAG_CLEAR (1 << 8) /* Clear channel */
+#define ZT_FLAG_AUDIO (1 << 9) /* Audio mode channel */
+
+#define ZT_FLAG_OPEN (1 << 10) /* Channel is open */
+#define ZT_FLAG_FCS (1 << 11) /* Calculate FCS */
+/* Reserve 12 for uniqueness with span flags */
+#define ZT_FLAG_LINEAR (1 << 13) /* Talk to user space in linear */
+#define ZT_FLAG_PPP (1 << 14) /* PPP is available */
+#define ZT_FLAG_T1PPP (1 << 15)
+#define ZT_FLAG_SIGFREEZE (1 << 16) /* Freeze signalling */
+#define ZT_FLAG_NOSTDTXRX (1 << 17) /* Do NOT do standard transmit and receive on every interrupt */
+#define ZT_FLAG_LOOPED (1 << 18) /* Loopback the receive data from the channel to the transmit */
+#define ZT_FLAG_MTP2 (1 << 19) /* Repeats last message in buffer and also discards repeating messages sent to us */
+
+/* This is a redefinition of the flags from above to allow use of the kernel atomic bit testing and changing routines.
+ * See the above descriptions for ZT_FLAG_.... for documentation about function. */
+enum {
+ ZT_FLAGBIT_REGISTERED = 0,
+ ZT_FLAGBIT_RUNNING = 1,
+ ZT_FLAGBIT_RBS = 12,
+ ZT_FLAGBIT_DTMFDECODE = 2,
+ ZT_FLAGBIT_MFDECODE = 3,
+ ZT_FLAGBIT_ECHOCANCEL = 4,
+ ZT_FLAGBIT_HDLC = 5,
+ ZT_FLAGBIT_NETDEV = 6,
+ ZT_FLAGBIT_PSEUDO = 7,
+ ZT_FLAGBIT_CLEAR = 8,
+ ZT_FLAGBIT_AUDIO = 9,
+ ZT_FLAGBIT_OPEN = 10,
+ ZT_FLAGBIT_FCS = 11,
+ ZT_FLAGBIT_LINEAR = 13,
+ ZT_FLAGBIT_PPP = 14,
+ ZT_FLAGBIT_T1PPP = 15,
+ ZT_FLAGBIT_SIGFREEZE = 16,
+ ZT_FLAGBIT_NOSTDTXRX = 17,
+ ZT_FLAGBIT_LOOPED = 18,
+ ZT_FLAGBIT_MTP2 = 19,
+};
+
+struct zt_span {
+ spinlock_t lock;
+ void *pvt; /* Private stuff */
+ char name[40]; /* Span name */
+ char desc[80]; /* Span description */
+ const char *spantype; /* span type in text form */
+ const char *manufacturer; /* span's device manufacturer */
+ char devicetype[80]; /* span's device type */
+ char location[40]; /* span device's location in system */
+ int deflaw; /* Default law (ZT_MULAW or ZT_ALAW) */
+ int alarms; /* Pending alarms on span */
+ int flags;
+ int irq; /* IRQ for this span's hardware */
+ int lbo; /* Span Line-Buildout */
+ int lineconfig; /* Span line configuration */
+ int linecompat; /* Span line compatibility */
+ int channels; /* Number of channels in span */
+ int txlevel; /* Tx level */
+ int rxlevel; /* Rx level */
+ int syncsrc; /* current sync src (gets copied here) */
+ unsigned int bpvcount; /* BPV counter */
+ unsigned int crc4count; /* CRC4 error counter */
+ unsigned int ebitcount; /* current E-bit error count */
+ unsigned int fascount; /* current FAS error count */
+
+ int maintstat; /* Maintenance state */
+ wait_queue_head_t maintq; /* Maintenance queue */
+ int mainttimer; /* Maintenance timer */
+
+ int irqmisses; /* Interrupt misses */
+
+ int timingslips; /* Clock slips */
+
+ struct zt_chan *chans; /* Member channel structures */
+
+ /* ==== Span Callback Operations ==== */
+ /* Req: Set the requested chunk size. This is the unit in which you must
+ report results for conferencing, etc */
+ int (*setchunksize)(struct zt_span *span, int chunksize);
+
+ /* Opt: Configure the span (if appropriate) */
+ int (*spanconfig)(struct zt_span *span, struct zt_lineconfig *lc);
+
+ /* Opt: Start the span */
+ int (*startup)(struct zt_span *span);
+
+ /* Opt: Shutdown the span */
+ int (*shutdown)(struct zt_span *span);
+
+ /* Opt: Enable maintenance modes */
+ int (*maint)(struct zt_span *span, int mode);
+
+#ifdef ZAPTEL_SYNC_TICK
+ /* Opt: send sync to spans */
+ int (*sync_tick)(struct zt_span *span, int is_master);
+#endif
+
+ /* ==== Channel Callback Operations ==== */
+ /* Opt: Set signalling type (if appropriate) */
+ int (*chanconfig)(struct zt_chan *chan, int sigtype);
+
+ /* Opt: Prepare a channel for I/O */
+ int (*open)(struct zt_chan *chan);
+
+ /* Opt: Close channel for I/O */
+ int (*close)(struct zt_chan *chan);
+
+ /* Opt: IOCTL */
+ int (*ioctl)(struct zt_chan *chan, unsigned int cmd, unsigned long data);
+
+ /* Opt: Native echo cancellation (simple) */
+ int (*echocan)(struct zt_chan *chan, int ecval);
+
+ int (*echocan_with_params)(struct zt_chan *chan, struct zt_echocanparams *ecp, struct zt_echocanparam *p);
+
+ /* Okay, now we get to the signalling. You have several options: */
+
+ /* Option 1: If you're a T1 like interface, you can just provide a
+ rbsbits function and we'll assert robbed bits for you. Be sure to
+ set the ZT_FLAG_RBS in this case. */
+
+ /* Opt: If the span uses A/B bits, set them here */
+ int (*rbsbits)(struct zt_chan *chan, int bits);
+
+ /* Option 2: If you don't know about sig bits, but do have their
+ equivalents (i.e. you can disconnect battery, detect off hook,
+ generate ring, etc directly) then you can just specify a
+ sethook function, and we'll call you with appropriate hook states
+ to set. Still set the ZT_FLAG_RBS in this case as well */
+ int (*hooksig)(struct zt_chan *chan, zt_txsig_t hookstate);
+
+ /* Option 3: If you can't use sig bits, you can write a function
+ which handles the individual hook states */
+ int (*sethook)(struct zt_chan *chan, int hookstate);
+
+ /* Opt: Dacs the contents of chan2 into chan1 if possible */
+ int (*dacs)(struct zt_chan *chan1, struct zt_chan *chan2);
+
+ /* Opt: Used to tell an onboard HDLC controller that there is data ready to transmit */
+ void (*hdlc_hard_xmit)(struct zt_chan *chan);
+
+ /* Used by zaptel only -- no user servicable parts inside */
+ int spanno; /* Span number for zaptel */
+ int offset; /* Offset within a given card */
+ int lastalarms; /* Previous alarms */
+
+#ifdef CONFIG_DEVFS_FS
+ devfs_handle_t dhandle; /* Directory name */
+#endif
+ /* If the watchdog detects no received data, it will call the
+ watchdog routine */
+ int (*watchdog)(struct zt_span *span, int cause);
+#ifdef CONFIG_ZAPTEL_WATCHDOG
+ int watchcounter;
+ int watchstate;
+#endif
+};
+
+struct zt_transcoder_channel {
+ void *pvt;
+ struct zt_transcoder *parent;
+ 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;
+ struct zt_transcode_header *tch;
+};
+
+#define ZT_TC_FLAG_BUSY (1 << 0)
+#define ZT_TC_FLAG_TRANSIENT (1 << 1)
+
+
+struct zt_transcoder {
+ struct zt_transcoder *next;
+ char name[80];
+ int numchannels;
+ unsigned int srcfmts;
+ unsigned int dstfmts;
+ int (*operation)(struct zt_transcoder_channel *channel, int op);
+ /* Transcoder channels */
+ struct zt_transcoder_channel channels[0];
+};
+
+#define ZT_WATCHDOG_NOINTS (1 << 0)
+
+#define ZT_WATCHDOG_INIT 1000
+
+#define ZT_WATCHSTATE_UNKNOWN 0
+#define ZT_WATCHSTATE_OK 1
+#define ZT_WATCHSTATE_RECOVERING 2
+#define ZT_WATCHSTATE_FAILED 3
+
+
+struct zt_dynamic_driver {
+ /* Driver name (e.g. Eth) */
+ char name[20];
+
+ /* Driver description */
+ char desc[80];
+
+ /* Create a new transmission pipe */
+ void *(*create)(struct zt_span *span, char *address);
+
+ /* Destroy a created transmission pipe */
+ void (*destroy)(void *tpipe);
+
+ /* Transmit a given message */
+ int (*transmit)(void *tpipe, unsigned char *msg, int msglen);
+
+ /* Flush any pending messages */
+ int (*flush)(void);
+
+ struct zt_dynamic_driver *next;
+};
+
+/* Receive a dynamic span message */
+void zt_dynamic_receive(struct zt_span *span, unsigned char *msg, int msglen);
+
+/* Register a dynamic driver */
+int zt_dynamic_register(struct zt_dynamic_driver *driver);
+
+/* Unregister a dynamic driver */
+void zt_dynamic_unregister(struct zt_dynamic_driver *driver);
+
+/* Receive on a span. The zaptel interface will handle all the calculations for
+ all member channels of the span, pulling the data from the readchunk buffer */
+int zt_receive(struct zt_span *span);
+
+/* Prepare writechunk buffers on all channels for this span */
+int zt_transmit(struct zt_span *span);
+
+/* Abort the buffer currently being receive with event "event" */
+void zt_hdlc_abort(struct zt_chan *ss, int event);
+
+/* Indicate to zaptel that the end of frame was received and rotate buffers */
+void zt_hdlc_finish(struct zt_chan *ss);
+
+/* Put a chunk of data into the current receive buffer */
+void zt_hdlc_putbuf(struct zt_chan *ss, unsigned char *rxb, int bytes);
+
+/* Get a chunk of data from the current transmit buffer. Returns -1 if no data
+ * is left to send, 0 if there is data remaining in the current message to be sent
+ * and 1 if the currently transmitted message is now done */
+int zt_hdlc_getbuf(struct zt_chan *ss, unsigned char *bufptr, unsigned int *size);
+
+
+/* Register a span. Returns 0 on success, -1 on failure. Pref-master is non-zero if
+ we should have preference in being the master device */
+int zt_register(struct zt_span *span, int prefmaster);
+
+/* Allocate / free memory for a transcoder */
+struct zt_transcoder *zt_transcoder_alloc(int numchans);
+void zt_transcoder_free(struct zt_transcoder *ztc);
+
+/* Register a transcoder */
+int zt_transcoder_register(struct zt_transcoder *tc);
+
+/* Unregister a transcoder */
+int zt_transcoder_unregister(struct zt_transcoder *tc);
+
+/* Alert a transcoder */
+int zt_transcoder_alert(struct zt_transcoder_channel *ztc);
+
+/* Unregister a span */
+int zt_unregister(struct zt_span *span);
+
+/* Gives a name to an LBO */
+char *zt_lboname(int lbo);
+
+/* Tell Zaptel about changes in received rbs bits */
+void zt_rbsbits(struct zt_chan *chan, int bits);
+
+/* Tell Zaptel abou changes in received signalling */
+void zt_hooksig(struct zt_chan *chan, zt_rxsig_t rxsig);
+
+/* Queue an event on a channel */
+void zt_qevent_nolock(struct zt_chan *chan, int event);
+
+/* Queue an event on a channel, locking it first */
+void zt_qevent_lock(struct zt_chan *chan, int event);
+
+/* Notify a change possible change in alarm status on a channel */
+void zt_alarm_channel(struct zt_chan *chan, int alarms);
+
+/* Notify a change possible change in alarm status on a span */
+void zt_alarm_notify(struct zt_span *span);
+
+/* Initialize a tone state */
+void zt_init_tone_state(struct zt_tone_state *ts, struct zt_tone *zt);
+
+/* Get a given MF tone struct, suitable for zt_tone_nextsample. */
+struct zt_tone *zt_mf_tone(const struct zt_chan *chan, char digit, int digitmode);
+
+/* Echo cancel a receive and transmit chunk for a given channel. This
+ should be called by the low-level driver as close to the interface
+ as possible. ECHO CANCELLATION IS NO LONGER AUTOMATICALLY DONE
+ AT THE ZAPTEL LEVEL. zt_ec_chunk will not echo cancel if it should
+ not be doing so. rxchunk is modified in-place */
+
+void zt_ec_chunk(struct zt_chan *chan, unsigned char *rxchunk, const unsigned char *txchunk);
+void zt_ec_span(struct zt_span *span);
+
+extern struct file_operations *zt_transcode_fops;
+
+/* Don't use these directly -- they're not guaranteed to
+ be there. */
+extern short __zt_mulaw[256];
+extern short __zt_alaw[256];
+#ifdef CONFIG_CALC_XLAW
+u_char __zt_lineartoulaw(short a);
+u_char __zt_lineartoalaw(short a);
+#else
+extern u_char __zt_lin2mu[16384];
+extern u_char __zt_lin2a[16384];
+#endif
+
+/* Used by dynamic zaptel -- don't use directly */
+void zt_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data));
+
+/* Used privately by zaptel. Avoid touching directly */
+struct zt_tone {
+ int fac1;
+ int init_v2_1;
+ int init_v3_1;
+
+ int fac2;
+ int init_v2_2;
+ int init_v3_2;
+
+ int tonesamples; /* How long to play this tone before
+ going to the next (in samples) */
+ struct zt_tone *next; /* Next tone in this sequence */
+
+ int modulate;
+};
+
+static inline short zt_tone_nextsample(struct zt_tone_state *ts, struct zt_tone *zt)
+{
+ /* follow the curves, return the sum */
+
+ int p;
+
+ ts->v1_1 = ts->v2_1;
+ ts->v2_1 = ts->v3_1;
+ ts->v3_1 = (zt->fac1 * ts->v2_1 >> 15) - ts->v1_1;
+
+ ts->v1_2 = ts->v2_2;
+ ts->v2_2 = ts->v3_2;
+ ts->v3_2 = (zt->fac2 * ts->v2_2 >> 15) - ts->v1_2;
+
+ /* Return top 16 bits */
+ if (!ts->modulate) return ts->v3_1 + ts->v3_2;
+ /* we are modulating */
+ p = ts->v3_2 - 32768;
+ if (p < 0) p = -p;
+ p = ((p * 9) / 10) + 1;
+ return (ts->v3_1 * p) >> 15;
+
+}
+
+static inline short zt_txtone_nextsample(struct zt_chan *ss)
+{
+ /* follow the curves, return the sum */
+
+ ss->v1_1 = ss->v2_1;
+ ss->v2_1 = ss->v3_1;
+ ss->v3_1 = (ss->txtone * ss->v2_1 >> 15) - ss->v1_1;
+ return ss->v3_1;
+}
+
+/* These are the right functions to use. */
+
+#define ZT_MULAW(a) (__zt_mulaw[(a)])
+#define ZT_ALAW(a) (__zt_alaw[(a)])
+#define ZT_XLAW(a,c) (c->xlaw[(a)])
+
+#ifdef CONFIG_CALC_XLAW
+#define ZT_LIN2MU(a) (__zt_lineartoulaw((a)))
+#define ZT_LIN2A(a) (__zt_lineartoalaw((a)))
+
+#define ZT_LIN2X(a,c) ((c)->lineartoxlaw((a)))
+
+#else
+/* Use tables */
+#define ZT_LIN2MU(a) (__zt_lin2mu[((unsigned short)(a)) >> 2])
+#define ZT_LIN2A(a) (__zt_lin2a[((unsigned short)(a)) >> 2])
+
+/* Manipulate as appropriate for x-law */
+#define ZT_LIN2X(a,c) ((c)->lin2x[((unsigned short)(a)) >> 2])
+
+#endif /* CONFIG_CALC_XLAW */
+
+#endif /* __KERNEL__ */
+
+/* The following is for the PCI RADIO interface only. This is specified in
+this file because external processes need to interact with the device.
+Some devices have private functions used for test/diagnostic only, but
+this is not the case here. */
+
+struct zt_radio_stat {
+ unsigned short ctcode_rx; /* code of currently received CTCSS
+ or DCS, 0 for none */
+ unsigned short ctclass; /* class of currently received CTCSS or
+ DCS code */
+ unsigned short ctcode_tx; /* code of currently encoded CTCSS or
+ DCS, 0 for none */
+ unsigned char radstat; /* status bits of radio */
+};
+
+#define RAD_SERIAL_BUFLEN 128
+
+struct zt_radio_param {
+ unsigned short radpar; /* param identifier */
+ unsigned short index; /* tone number */
+ int data; /* param */
+ int data2; /* param 2 */
+ unsigned char buf[RAD_SERIAL_BUFLEN];
+};
+
+
+/* Get current status IOCTL */
+#define ZT_RADIO_GETSTAT _IOR (ZT_CODE, 57, struct zt_radio_stat)
+/* Set a channel parameter IOCTL */
+#define ZT_RADIO_SETPARAM _IOW (ZT_CODE, 58, struct zt_radio_param)
+/* Get a channel parameter IOCTL */
+#define ZT_RADIO_GETPARAM _IOR (ZT_CODE, 59, struct zt_radio_param)
+
+
+/* Defines for Radio Status (zt_radio_stat.radstat) bits */
+
+#define ZT_RADSTAT_RX 1 /* currently "receiving " */
+#define ZT_RADSTAT_TX 2 /* currently "transmitting" */
+#define ZT_RADSTAT_RXCT 4 /* currently receiving continuous tone with
+ current settings */
+#define ZT_RADSTAT_RXCOR 8 /* currently receiving COR (irrelevant of COR
+ ignore) */
+#define ZT_RADSTAT_IGNCOR 16 /* currently ignoring COR */
+#define ZT_RADSTAT_IGNCT 32 /* currently ignoring CTCSS/DCS decode */
+#define ZT_RADSTAT_NOENCODE 64 /* currently blocking CTCSS/DCS encode */
+
+/* Defines for Radio Parameters (zt_radio_param.radpar) */
+
+#define ZT_RADPAR_INVERTCOR 1 /* invert the COR signal (0/1) */
+#define ZT_RADPAR_IGNORECOR 2 /* ignore the COR signal (0/1) */
+#define ZT_RADPAR_IGNORECT 3 /* ignore the CTCSS/DCS decode (0/1) */
+#define ZT_RADPAR_NOENCODE 4 /* block the CTCSS/DCS encode (0/1) */
+#define ZT_RADPAR_CORTHRESH 5 /* COR trigger threshold (0-7) */
+
+#define ZT_RADPAR_EXTRXTONE 6 /* 0 means use internal decoder, 1 means UIOA
+ logic true is CT decode, 2 means UIOA logic
+ false is CT decode */
+#define ZT_RADPAR_NUMTONES 7 /* returns maximum tone index (curently 15) */
+#define ZT_RADPAR_INITTONE 8 /* init all tone indexes to 0 (no tones) */
+#define ZT_RADPAR_RXTONE 9 /* CTCSS tone, (1-32) or DCS tone (1-777),
+ or 0 meaning no tone, set index also (1-15) */
+#define ZT_RADPAR_RXTONECLASS 10 /* Tone class (0-65535), set index also (1-15) */
+#define ZT_RADPAR_TXTONE 11 /* CTCSS tone (1-32) or DCS tone (1-777) or 0
+ to indicate no tone, to transmit
+ for this tone index (0-32, 0 disables
+ transmit CTCSS), set index also (0-15) */
+#define ZT_RADPAR_DEBOUNCETIME 12 /* receive indication debounce time,
+ milliseconds (1-999) */
+#define ZT_RADPAR_BURSTTIME 13 /* end of transmit with no CT tone in
+ milliseconds (0-999) */
+
+
+#define ZT_RADPAR_UIODATA 14 /* read/write UIOA and UIOB data. Bit 0 is
+ UIOA, bit 1 is UIOB */
+#define ZT_RADPAR_UIOMODE 15 /* 0 means UIOA and UIOB are both outputs, 1
+ means UIOA is input, UIOB is output, 2
+ means UIOB is input and UIOA is output,
+ 3 means both UIOA and UIOB are inputs. Note
+ mode for UIOA is overridden when in
+ EXTRXTONE mode. */
+
+#define ZT_RADPAR_REMMODE 16 /* Remote control data mode */
+ #define ZT_RADPAR_REM_NONE 0 /* no remote control data mode */
+ #define ZT_RADPAR_REM_RBI1 1 /* Doug Hall RBI-1 data mode */
+ #define ZT_RADPAR_REM_SERIAL 2 /* Serial Data, 9600 BPS */
+ #define ZT_RADPAR_REM_SERIAL_ASCII 3 /* Serial Ascii Data, 9600 BPS */
+
+#define ZT_RADPAR_REMCOMMAND 17 /* Remote conrtol write data block & do cmd */
+
+/* Data formats for capabilities and frames alike (from Asterisk) */
+/*! G.723.1 compression */
+#define ZT_FORMAT_G723_1 (1 << 0)
+/*! GSM compression */
+#define ZT_FORMAT_GSM (1 << 1)
+/*! Raw mu-law data (G.711) */
+#define ZT_FORMAT_ULAW (1 << 2)
+/*! Raw A-law data (G.711) */
+#define ZT_FORMAT_ALAW (1 << 3)
+/*! ADPCM (G.726, 32kbps) */
+#define ZT_FORMAT_G726 (1 << 4)
+/*! ADPCM (IMA) */
+#define ZT_FORMAT_ADPCM (1 << 5)
+/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
+#define ZT_FORMAT_SLINEAR (1 << 6)
+/*! LPC10, 180 samples/frame */
+#define ZT_FORMAT_LPC10 (1 << 7)
+/*! G.729A audio */
+#define ZT_FORMAT_G729A (1 << 8)
+/*! SpeeX Free Compression */
+#define ZT_FORMAT_SPEEX (1 << 9)
+/*! iLBC Free Compression */
+#define ZT_FORMAT_ILBC (1 << 10)
+/*! Maximum audio format */
+#define ZT_FORMAT_MAX_AUDIO (1 << 15)
+/*! Maximum audio mask */
+#define ZT_FORMAT_AUDIO_MASK ((1 << 16) - 1)
+
+#define ZT_RADPAR_DEEMP 18 /* Audio De-empahsis (on or off) */
+
+#define ZT_RADPAR_PREEMP 19 /* Audio Pre-empahsis (on or off) */
+
+#define ZT_RADPAR_RXGAIN 20 /* Audio (In to system) Rx Gain */
+
+#define ZT_RADPAR_TXGAIN 21 /* Audio (Out from system) Tx Gain */
+
+struct torisa_debug {
+ unsigned int txerrors;
+ unsigned int irqcount;
+ unsigned int taskletsched;
+ unsigned int taskletrun;
+ unsigned int taskletexec;
+ int span1flags;
+ int span2flags;
+};
+
+/* Special torisa ioctl */
+#define TORISA_GETDEBUG _IOW (ZT_CODE, 60, struct torisa_debug)
+
+/*!
+ \brief Size-limited null-terminating string copy.
+ \param dst The destination buffer
+ \param src The source string
+ \param size The size of the destination buffer
+ \return Nothing.
+
+ This is similar to \a strncpy, with two important differences:
+ - the destination buffer will \b always be null-terminated
+ - the destination buffer is not filled with zeros past the copied string length
+ These differences make it slightly more efficient, and safer to use since it will
+ not leave the destination buffer unterminated. There is no need to pass an artificially
+ reduced buffer size to this function (unlike \a strncpy), and the buffer does not need
+ to be initialized to zeroes prior to calling this function.
+*/
+static inline void zap_copy_string(char *dst, const char *src, unsigned int size)
+{
+ while (*src && size) {
+ *dst++ = *src++;
+ size--;
+ }
+ if (__builtin_expect(!size, 0))
+ dst--;
+ *dst = '\0';
+}
+
+#endif /* _LINUX_ZAPTEL_H */
diff --git a/drivers/dahdi/zconfig.h b/drivers/dahdi/zconfig.h
new file mode 100644
index 0000000..35056e3
--- /dev/null
+++ b/drivers/dahdi/zconfig.h
@@ -0,0 +1,197 @@
+/*
+ * Zaptel configuration options
+ *
+ */
+#ifndef _ZCONFIG_H
+#define _ZCONFIG_H
+
+#ifdef __KERNEL__
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#include <linux/config.h>
+#else
+#include <linux/autoconf.h>
+#endif
+#endif
+
+/* Zaptel compile time options */
+
+/*
+ * Uncomment if you have a European phone, or any other phone with a
+ * short flash time.
+ * This will stop the flash being mis-detected as a pulse dial "1" on
+ * phones with short flashes
+ */
+/* #define SHORT_FLASH_TIME */
+
+/*
+ * Uncomment to disable calibration and/or DC/DC converter tests
+ * (not generally recommended)
+ */
+/* #define NO_CALIBRATION */
+/* #define NO_DCDC */
+
+/*
+ * Boost ring voltage (Higher ring voltage, takes more power)
+ * Note: this only affects the wcfxsusb and wcusb drivers; all other
+ * drivers have a 'boostringer' module parameter.
+ */
+/* #define BOOST_RINGER */
+
+/*
+ * Define CONFIG_CALC_XLAW if you have a small number of channels and/or
+ * a small level 2 cache, to optimize for few channels
+ *
+ */
+/* #define CONFIG_CALC_XLAW */
+
+/*
+ * Define if you want MMX optimizations in zaptel
+ *
+ * Note: CONFIG_ZAPTEL_MMX is generally incompatible with AMD
+ * processors and can cause system instability!
+ *
+ */
+/* #define CONFIG_ZAPTEL_MMX */
+
+/** If defined: the user must define exactly one ECHO_CAN_ var: */
+#ifndef ECHO_CAN_FROMENV
+
+/*
+ * Pick your echo canceller: MARK2, MARK3, STEVE, or STEVE2 :)
+ *
+ */
+/* #define ECHO_CAN_STEVE */
+/* #define ECHO_CAN_STEVE2 */
+/* #define ECHO_CAN_KB1 */
+/* This is the new latest and greatest */
+#define ECHO_CAN_MG2
+
+/*
+ * This is only technically an "echo canceller"...
+ * It purposely drops 2 out of 3 samples and sounds horrible.
+ * You really only want this for testing "echo cancelled" audio.
+ */
+/* #define ECHO_CAN_JP1 */
+
+/*
+ * Uncomment for aggressive residual echo suppression under
+ * MARK2, KB1, and MG2 echo canceler
+ */
+/* #define AGGRESSIVE_SUPPRESSOR */
+#endif /* ifndef ECHO_CAN_FROMENV */
+/*
+ * Define to turn off the echo canceler disable tone detector,
+ * which will cause zaptel to ignore the 2100 Hz echo cancel disable
+ * tone.
+ */
+/* #define NO_ECHOCAN_DISABLE */
+
+/* udev support */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,1)
+#define CONFIG_ZAP_UDEV
+#endif
+
+/* We now use the linux kernel config to detect which options to use */
+/* You can still override them below */
+#if defined(CONFIG_HDLC) || defined(CONFIG_HDLC_MODULE)
+/* #define CONFIG_ZAPATA_NET */ /* NEVER implicitly turn on ZAPATA_NET */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,20)
+#define CONFIG_OLD_HDLC_API
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,23)
+/* Starting with 2.4.23 the kernel hdlc api changed again */
+/* Now we have to use hdlc_type_trans(skb, dev) instead of htons(ETH_P_HDLC) */
+#define ZAP_HDLC_TYPE_TRANS
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3)
+#define HDLC_MAINTAINERS_ARE_MORE_STUPID_THAN_I_THOUGHT
+#endif
+#endif
+#endif
+#ifdef CONFIG_PPP
+#define CONFIG_ZAPATA_PPP
+#endif
+
+/*
+ * Uncomment CONFIG_ZAPATA_NET to enable SyncPPP, CiscoHDLC, and Frame Relay
+ * support.
+ */
+/* #define CONFIG_ZAPATA_NET */
+
+/*
+ * Uncomment CONFIG_OLD_HDLC_API if your are compiling with ZAPATA_NET
+ * defined and you are using the old kernel HDLC interface (or if you get
+ * an error about ETH_P_HDLC while compiling).
+ */
+/* #define CONFIG_OLD_HDLC_API */
+
+/*
+ * Uncomment for Generic PPP support (i.e. ZapRAS)
+ */
+/* #define CONFIG_ZAPATA_PPP */
+/*
+ * Uncomment to enable "watchdog" to monitor if interfaces
+ * stop taking interrupts or otherwise misbehave
+ */
+/* #define CONFIG_ZAPTEL_WATCHDOG */
+
+/*
+ * Uncomment for Non-standard FXS groundstart start state (A=Low, B=Low)
+ * particularly for CAC channel bank groundstart FXO ports.
+ */
+/* #define CONFIG_CAC_GROUNDSTART */
+
+/*
+ * Uncomment if you happen have an early TDM400P Rev H which
+ * sometimes forgets its PCI ID to have wcfxs match essentially all
+ * subvendor ID's
+ */
+/* #define TDM_REVH_MATCHALL */
+
+/*
+ * Uncomment the following if you want to support E&M trunks being
+ * able to "flash" after going off-hook (dont ask why, just nod :-) ).
+ *
+ * NOTE: *DO NOT* Enable "EMFLASH" and "EMPULSE" at the same time!!
+ *
+ */
+/* #define EMFLASH */
+
+/*
+ * Uncomment the following if you want to support E&M trunks being
+ * able to recognize Dial Pulse digits. This can validly be enabled
+ * so that either Dial Pulse or DTMF/MF tones will be recognized, but
+ * the drawback is that the ONHOOK will take an extra {rxwinktime}
+ * to be recognized.
+ *
+ * NOTE: *DO NOT* Enable "EMFLASH" and "EMPULSE" at the same time!!
+ *
+ */
+/* #define EMPULSE */
+
+/*
+ * Comment out the following if you dont want events to indicate the
+ * beginning of an incoming ring. Most non-Asterisk applications will
+ * want this commented out.
+ */
+#define RINGBEGIN
+
+/*
+ * Uncomment the following if you need to support FXS Flash events.
+ * Most applications will want this commented out.
+ */
+/* #define FXSFLASH */
+
+/*
+ * Enable sync_tick() calls. Allows low-level drivers to synchronize
+ * their internal clocks to the zaptel master clock.
+ */
+#define ZAPTEL_SYNC_TICK
+
+/*
+ * Skip processing PCM if low-level driver won't use it anyway
+ */
+/* #define OPTIMIZE_CHANMUTE */
+
+#endif
diff --git a/drivers/dahdi/ztd-eth.c b/drivers/dahdi/ztd-eth.c
new file mode 100644
index 0000000..dfda1f0
--- /dev/null
+++ b/drivers/dahdi/ztd-eth.c
@@ -0,0 +1,451 @@
+/*
+ * Dynamic Span Interface for Zaptel (Ethernet Interface)
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ *
+ * Copyright (C) 2001, Linux Support Services, 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/netdevice.h>
+#include <linux/notifier.h>
+
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+
+#define ETH_P_ZTDETH 0xd00d
+
+struct ztdeth_header {
+ unsigned short subaddr;
+};
+
+/* We take the raw message, put it in an ethernet frame, and add a
+ two byte addressing header at the top for future use */
+#ifdef DEFINE_SPINLOCK
+static DEFINE_SPINLOCK(zlock);
+#else
+static spinlock_t zlock = SPIN_LOCK_UNLOCKED;
+#endif
+
+static struct sk_buff_head skbs;
+
+static struct ztdeth {
+ unsigned char addr[ETH_ALEN];
+ unsigned short subaddr; /* Network byte order */
+ struct zt_span *span;
+ char ethdev[IFNAMSIZ];
+ struct net_device *dev;
+ struct ztdeth *next;
+} *zdevs = NULL;
+
+struct zt_span *ztdeth_getspan(unsigned char *addr, unsigned short subaddr)
+{
+ unsigned long flags;
+ struct ztdeth *z;
+ struct zt_span *span = NULL;
+ spin_lock_irqsave(&zlock, flags);
+ z = zdevs;
+ while(z) {
+ if (!memcmp(addr, z->addr, ETH_ALEN) &&
+ z->subaddr == subaddr)
+ break;
+ z = z->next;
+ }
+ if (z)
+ span = z->span;
+ spin_unlock_irqrestore(&zlock, flags);
+ return span;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+static int ztdeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+#else
+static int ztdeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+#endif
+{
+ struct zt_span *span;
+ struct ztdeth_header *zh;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+ zh = (struct ztdeth_header *)skb_network_header(skb);
+#else
+ zh = (struct ztdeth_header *)skb->nh.raw;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9)
+ span = ztdeth_getspan(eth_hdr(skb)->h_source, zh->subaddr);
+#else
+ span = ztdeth_getspan(skb->mac.ethernet->h_source, zh->subaddr);
+#endif
+ if (span) {
+ skb_pull(skb, sizeof(struct ztdeth_header));
+ zt_dynamic_receive(span, (unsigned char *)skb->data, skb->len);
+ }
+ kfree_skb(skb);
+ return 0;
+}
+
+static int ztdeth_notifier(struct notifier_block *block, unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+ struct ztdeth *z;
+ unsigned long flags;
+ switch(event) {
+ case NETDEV_GOING_DOWN:
+ case NETDEV_DOWN:
+ spin_lock_irqsave(&zlock, flags);
+ z = zdevs;
+ while(z) {
+ /* Note that the device no longer exists */
+ if (z->dev == dev)
+ z->dev = NULL;
+ z = z->next;
+ }
+ spin_unlock_irqrestore(&zlock, flags);
+ break;
+ case NETDEV_UP:
+ spin_lock_irqsave(&zlock, flags);
+ z = zdevs;
+ while(z) {
+ /* Now that the device exists again, use it */
+ if (!strcmp(z->ethdev, dev->name))
+ z->dev = dev;
+ z = z->next;
+ }
+ spin_unlock_irqrestore(&zlock, flags);
+ break;
+ }
+ return 0;
+}
+
+static int ztdeth_transmit(void *pvt, unsigned char *msg, int msglen)
+{
+ struct ztdeth *z;
+ struct sk_buff *skb;
+ struct ztdeth_header *zh;
+ unsigned long flags;
+ struct net_device *dev;
+ unsigned char addr[ETH_ALEN];
+ unsigned short subaddr; /* Network byte order */
+
+ spin_lock_irqsave(&zlock, flags);
+ z = pvt;
+ if (z->dev) {
+ /* Copy fields to local variables to remove spinlock ASAP */
+ dev = z->dev;
+ memcpy(addr, z->addr, sizeof(z->addr));
+ subaddr = z->subaddr;
+ spin_unlock_irqrestore(&zlock, flags);
+ skb = dev_alloc_skb(msglen + dev->hard_header_len + sizeof(struct ztdeth_header) + 32);
+ if (skb) {
+ /* Reserve header space */
+ skb_reserve(skb, dev->hard_header_len + sizeof(struct ztdeth_header));
+
+ /* Copy message body */
+ memcpy(skb_put(skb, msglen), msg, msglen);
+
+ /* Throw on header */
+ zh = (struct ztdeth_header *)skb_push(skb, sizeof(struct ztdeth_header));
+ zh->subaddr = subaddr;
+
+ /* Setup protocol and such */
+ skb->protocol = __constant_htons(ETH_P_ZTDETH);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+ skb_set_network_header(skb, 0);
+#else
+ skb->nh.raw = skb->data;
+#endif
+ skb->dev = dev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ dev_hard_header(skb, dev, ETH_P_ZTDETH, addr, dev->dev_addr, skb->len);
+#else
+ if (dev->hard_header)
+ dev->hard_header(skb, dev, ETH_P_ZTDETH, addr, dev->dev_addr, skb->len);
+#endif
+ skb_queue_tail(&skbs, skb);
+ }
+ }
+ else
+ spin_unlock_irqrestore(&zlock, flags);
+ return 0;
+}
+
+
+static int ztdeth_flush(void)
+{
+ struct sk_buff *skb;
+
+ /* Handle all transmissions now */
+ while ((skb = skb_dequeue(&skbs))) {
+ dev_queue_xmit(skb);
+ }
+ return 0;
+}
+
+static struct packet_type ztdeth_ptype = {
+ type: __constant_htons(ETH_P_ZTDETH), /* Protocol */
+ dev: NULL, /* Device (NULL = wildcard) */
+ func: ztdeth_rcv, /* Receiver */
+};
+
+static int digit2int(char d)
+{
+ switch(d) {
+ case 'F':
+ case 'E':
+ case 'D':
+ case 'C':
+ case 'B':
+ case 'A':
+ return d - 'A' + 10;
+ case 'f':
+ case 'e':
+ case 'd':
+ case 'c':
+ case 'b':
+ case 'a':
+ return d - 'a' + 10;
+ case '9':
+ case '8':
+ case '7':
+ case '6':
+ case '5':
+ case '4':
+ case '3':
+ case '2':
+ case '1':
+ case '0':
+ return d - '0';
+ }
+ return -1;
+}
+
+static int hex2int(char *s)
+{
+ int res;
+ int tmp;
+ /* Gotta be at least one digit */
+ if (strlen(s) < 1)
+ return -1;
+ /* Can't be more than two */
+ if (strlen(s) > 2)
+ return -1;
+ /* Grab the first digit */
+ res = digit2int(s[0]);
+ if (res < 0)
+ return -1;
+ tmp = res;
+ /* Grab the next */
+ if (strlen(s) > 1) {
+ res = digit2int(s[1]);
+ if (res < 0)
+ return -1;
+ tmp = tmp * 16 + res;
+ }
+ return tmp;
+}
+
+static void ztdeth_destroy(void *pvt)
+{
+ struct ztdeth *z = pvt;
+ unsigned long flags;
+ struct ztdeth *prev=NULL, *cur;
+ spin_lock_irqsave(&zlock, flags);
+ cur = zdevs;
+ while(cur) {
+ if (cur == z) {
+ if (prev)
+ prev->next = cur->next;
+ else
+ zdevs = cur->next;
+ break;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+ spin_unlock_irqrestore(&zlock, flags);
+ if (cur == z) { /* Successfully removed */
+ printk("TDMoE: Removed interface for %s\n", z->span->name);
+ kfree(z);
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#else
+ module_put(THIS_MODULE);
+#endif
+ }
+}
+
+static void *ztdeth_create(struct zt_span *span, char *addr)
+{
+ struct ztdeth *z;
+ char src[256];
+ char tmp[256], *tmp2, *tmp3, *tmp4 = NULL;
+ int res,x;
+ unsigned long flags;
+
+ z = kmalloc(sizeof(struct ztdeth), GFP_KERNEL);
+ if (z) {
+ /* Zero it out */
+ memset(z, 0, sizeof(struct ztdeth));
+
+ /* Address should be <dev>/<macaddr>[/subaddr] */
+ zap_copy_string(tmp, addr, sizeof(tmp));
+ tmp2 = strchr(tmp, '/');
+ if (tmp2) {
+ *tmp2 = '\0';
+ tmp2++;
+ zap_copy_string(z->ethdev, tmp, sizeof(z->ethdev));
+ } else {
+ printk("Invalid TDMoE address (no device) '%s'\n", addr);
+ kfree(z);
+ return NULL;
+ }
+ if (tmp2) {
+ tmp4 = strchr(tmp2+1, '/');
+ if (tmp4) {
+ *tmp4 = '\0';
+ tmp4++;
+ }
+ /* We don't have SSCANF :( Gotta do this the hard way */
+ tmp3 = strchr(tmp2, ':');
+ for (x=0;x<6;x++) {
+ if (tmp2) {
+ if (tmp3) {
+ *tmp3 = '\0';
+ tmp3++;
+ }
+ res = hex2int(tmp2);
+ if (res < 0)
+ break;
+ z->addr[x] = res & 0xff;
+ } else
+ break;
+ if ((tmp2 = tmp3))
+ tmp3 = strchr(tmp2, ':');
+ }
+ if (x != 6) {
+ printk("TDMoE: Invalid MAC address in: %s\n", addr);
+ kfree(z);
+ return NULL;
+ }
+ } else {
+ printk("TDMoE: Missing MAC address\n");
+ kfree(z);
+ return NULL;
+ }
+ if (tmp4) {
+ int sub = 0;
+ int mul = 1;
+
+ /* We have a subaddr */
+ tmp3 = tmp4 + strlen (tmp4) - 1;
+ while (tmp3 >= tmp4) {
+ if (*tmp3 >= '0' && *tmp3 <= '9') {
+ sub += (*tmp3 - '0') * mul;
+ } else {
+ printk("TDMoE: Invalid subaddress\n");
+ kfree(z);
+ return NULL;
+ }
+ mul *= 10;
+ tmp3--;
+ }
+ z->subaddr = htons(sub);
+ }
+ z->dev = dev_get_by_name(
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ &init_net,
+#endif
+ z->ethdev);
+ if (!z->dev) {
+ printk("TDMoE: Invalid device '%s'\n", z->ethdev);
+ kfree(z);
+ return NULL;
+ }
+ z->span = span;
+ src[0] ='\0';
+ for (x=0;x<5;x++)
+ sprintf(src + strlen(src), "%02x:", z->dev->dev_addr[x]);
+ sprintf(src + strlen(src), "%02x", z->dev->dev_addr[5]);
+ printk("TDMoE: Added new interface for %s at %s (addr=%s, src=%s, subaddr=%d)\n", span->name, z->dev->name, addr, src, ntohs(z->subaddr));
+
+ spin_lock_irqsave(&zlock, flags);
+ z->next = zdevs;
+ zdevs = z;
+ spin_unlock_irqrestore(&zlock, flags);
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#else
+ if(!try_module_get(THIS_MODULE))
+ printk("TDMoE: Unable to increment module use count\n");
+#endif
+ }
+ return z;
+}
+
+static struct zt_dynamic_driver ztd_eth = {
+ "eth",
+ "Ethernet",
+ ztdeth_create,
+ ztdeth_destroy,
+ ztdeth_transmit,
+ ztdeth_flush
+};
+
+static struct notifier_block ztdeth_nblock = {
+ notifier_call: ztdeth_notifier,
+};
+
+static int __init ztdeth_init(void)
+{
+ dev_add_pack(&ztdeth_ptype);
+ register_netdevice_notifier(&ztdeth_nblock);
+ zt_dynamic_register(&ztd_eth);
+
+ skb_queue_head_init(&skbs);
+
+ return 0;
+}
+
+static void __exit ztdeth_exit(void)
+{
+ dev_remove_pack(&ztdeth_ptype);
+ unregister_netdevice_notifier(&ztdeth_nblock);
+ zt_dynamic_unregister(&ztd_eth);
+}
+
+MODULE_DESCRIPTION("Zaptel Dynamic TDMoE Support");
+MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(ztdeth_init);
+module_exit(ztdeth_exit);
diff --git a/drivers/dahdi/ztd-loc.c b/drivers/dahdi/ztd-loc.c
new file mode 100644
index 0000000..6486a2a
--- /dev/null
+++ b/drivers/dahdi/ztd-loc.c
@@ -0,0 +1,282 @@
+/*
+ * Dynamic Span Interface for Zaptel (Local Interface)
+ *
+ * Written by Nicolas Bougues <nbougues@axialys.net>
+ *
+ * Copyright (C) 2004, Axialys Interactive
+ *
+ * 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.
+ *
+ *
+ * Note : a zaptel source must exist prior to loading this driver
+ *
+ * Address syntax :
+ * <key>:<id>[:<monitor id>]
+ *
+ * As of now, keys and ids are single digit only
+ *
+ * One span may have up to one "normal" peer, and one "monitor" peer
+ *
+ * Example :
+ *
+ * Say you have two spans cross connected, a thrid one monitoring RX on the
+ * first one, a fourth one monitoring RX on the second one
+ *
+ * 1:0
+ * 1:1
+ * 1:2:0
+ * 1:3:1
+ *
+ * Contrary to TDMoE, no frame loss can occur.
+ *
+ * See bug #2021 for more details
+ *
+ */
+
+#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/netdevice.h>
+#include <linux/notifier.h>
+
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+
+#ifdef DEFINE_SPINLOCK
+static DEFINE_SPINLOCK(zlock);
+#else
+static spinlock_t zlock = SPIN_LOCK_UNLOCKED;
+#endif
+
+static struct ztdlocal {
+ unsigned short key;
+ unsigned short id;
+ struct ztdlocal *monitor_rx_peer; /* Indicates the peer span that monitors this span */
+ struct ztdlocal *peer; /* Indicates the rw peer for this span */
+ struct zt_span *span;
+ struct ztdlocal *next;
+} *zdevs = NULL;
+
+/*static*/ int ztdlocal_transmit(void *pvt, unsigned char *msg, int msglen)
+{
+ struct ztdlocal *z;
+ unsigned long flags;
+
+ spin_lock_irqsave(&zlock, flags);
+ z = pvt;
+ if (z->peer && z->peer->span) {
+ zt_dynamic_receive(z->peer->span, msg, msglen);
+ }
+ if (z->monitor_rx_peer && z->monitor_rx_peer->span) {
+ zt_dynamic_receive(z->monitor_rx_peer->span, msg, msglen);
+ }
+ spin_unlock_irqrestore(&zlock, flags);
+ return 0;
+}
+
+static int digit2int(char d)
+{
+ switch(d) {
+ case 'F':
+ case 'E':
+ case 'D':
+ case 'C':
+ case 'B':
+ case 'A':
+ return d - 'A' + 10;
+ case 'f':
+ case 'e':
+ case 'd':
+ case 'c':
+ case 'b':
+ case 'a':
+ return d - 'a' + 10;
+ case '9':
+ case '8':
+ case '7':
+ case '6':
+ case '5':
+ case '4':
+ case '3':
+ case '2':
+ case '1':
+ case '0':
+ return d - '0';
+ }
+ return -1;
+}
+
+/*static*/ void ztdlocal_destroy(void *pvt)
+{
+ struct ztdlocal *z = pvt;
+ unsigned long flags;
+ struct ztdlocal *prev=NULL, *cur;
+
+ spin_lock_irqsave(&zlock, flags);
+ cur = zdevs;
+ while(cur) {
+ if (cur->peer == z)
+ cur->peer = NULL;
+ if (cur->monitor_rx_peer == z)
+ cur->monitor_rx_peer = NULL;
+ cur = cur->next;
+ }
+ cur = zdevs;
+ while(cur) {
+ if (cur == z) {
+ if (prev)
+ prev->next = cur->next;
+ else
+ zdevs = cur->next;
+ break;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+ spin_unlock_irqrestore(&zlock, flags);
+ if (cur == z) {
+ printk("TDMoL: Removed interface for %s, key %d id %d\n", z->span->name, z->key, z->id);
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#else
+ module_put(THIS_MODULE);
+#endif
+ kfree(z);
+ }
+}
+
+/*static*/ void *ztdlocal_create(struct zt_span *span, char *address)
+{
+ struct ztdlocal *z, *l;
+ unsigned long flags;
+ int key = -1, id = -1, monitor = -1;
+
+ if (strlen(address) >= 3) {
+ if (address[1] != ':')
+ goto INVALID_ADDRESS;
+ key = digit2int(address[0]);
+ id = digit2int(address[2]);
+ }
+ if (strlen (address) == 5) {
+ if (address[3] != ':')
+ goto INVALID_ADDRESS;
+ monitor = digit2int(address[4]);
+ }
+
+ if (key == -1 || id == -1)
+ goto INVALID_ADDRESS;
+
+ z = kmalloc(sizeof(struct ztdlocal), GFP_KERNEL);
+ if (z) {
+ /* Zero it out */
+ memset(z, 0, sizeof(struct ztdlocal));
+
+ z->key = key;
+ z->id = id;
+ z->span = span;
+
+ spin_lock_irqsave(&zlock, flags);
+ /* Add this peer to any existing spans with same key
+ And add them as peers to this one */
+ for (l = zdevs; l; l = l->next)
+ if (l->key == z->key) {
+ if (l->id == z->id) {
+ printk ("TDMoL: Duplicate id (%d) for key %d\n", z->id, z->key);
+ goto CLEAR_AND_DEL_FROM_PEERS;
+ }
+ if (monitor == -1) {
+ if (l->peer) {
+ printk ("TDMoL: Span with key %d and id %d already has a R/W peer\n", z->key, z->id);
+ goto CLEAR_AND_DEL_FROM_PEERS;
+ } else {
+ l->peer = z;
+ z->peer = l;
+ }
+ }
+ if (monitor == l->id) {
+ if (l->monitor_rx_peer) {
+ printk ("TDMoL: Span with key %d and id %d already has a monitoring peer\n", z->key, z->id);
+ goto CLEAR_AND_DEL_FROM_PEERS;
+ } else {
+ l->monitor_rx_peer = z;
+ }
+ }
+ }
+ z->next = zdevs;
+ zdevs = z;
+ spin_unlock_irqrestore(&zlock, flags);
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#else
+ if(!try_module_get(THIS_MODULE))
+ printk("TDMoL: Unable to increment module use count\n");
+#endif
+
+ printk("TDMoL: Added new interface for %s, key %d id %d\n", span->name, z->key, z->id);
+ }
+ return z;
+
+CLEAR_AND_DEL_FROM_PEERS:
+ for (l = zdevs; l; l = l->next) {
+ if (l->peer == z)
+ l->peer = NULL;
+ if (l->monitor_rx_peer == z)
+ l->monitor_rx_peer = NULL;
+ }
+ kfree (z);
+ return NULL;
+
+INVALID_ADDRESS:
+ printk ("TDMoL: Invalid address %s\n", address);
+ return NULL;
+}
+
+static struct zt_dynamic_driver ztd_local = {
+ "loc",
+ "Local",
+ ztdlocal_create,
+ ztdlocal_destroy,
+ ztdlocal_transmit,
+ NULL /* flush */
+};
+
+/*static*/ int __init ztdlocal_init(void)
+{
+ zt_dynamic_register(&ztd_local);
+ return 0;
+}
+
+/*static*/ void __exit ztdlocal_exit(void)
+{
+ zt_dynamic_unregister(&ztd_local);
+}
+
+module_init(ztdlocal_init);
+module_exit(ztdlocal_exit);
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
diff --git a/drivers/dahdi/ztdummy.c b/drivers/dahdi/ztdummy.c
new file mode 100644
index 0000000..18f1e9f
--- /dev/null
+++ b/drivers/dahdi/ztdummy.c
@@ -0,0 +1,429 @@
+/*
+ * Dummy Zaptel Driver for Zapata Telephony interface
+ *
+ * Required: usb-uhci module and kernel > 2.4.4 OR kernel > 2.6.0
+ *
+ * Written by Robert Pleh <robert.pleh@hermes.si>
+ * 2.6 version by Tony Hoyle
+ * Unified by Mark Spencer <markster@digium.com>
+ * Converted to use RTC on i386 by Tony Mountifield <tony@softins.co.uk>
+ *
+ * Converted to use HighResTimers on i386 by Jeffery Palmer <jeff@triggerinc.com>
+ *
+ * Copyright (C) 2002, Hermes Softlab
+ * Copyright (C) 2004, 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.
+ *
+ */
+
+/*
+ * To use the high resolution timers, in your kernel CONFIG_HIGH_RES_TIMERS
+ * needs to be enabled (Processor type and features -> High Resolution
+ * Timer Support), and optionally HPET (Processor type and features ->
+ * HPET Timer Support) provides a better clock source.
+ */
+
+#include <linux/version.h>
+
+#ifndef VERSION_CODE
+# define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) )
+#endif
+
+
+#if LINUX_VERSION_CODE < VERSION_CODE(2,4,5)
+# error "This kernel is too old: not supported by this file"
+#endif
+
+/*
+ * NOTE: (only applies to kernel 2.6)
+ * If using an i386 architecture without a PC real-time clock,
+ * the #define USE_RTC should be commented out.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+#if LINUX_VERSION_CODE >= VERSION_CODE(2,6,13)
+/* The symbol hrtimer_forward is only exported as of 2.6.22: */
+#if defined(CONFIG_HIGH_RES_TIMERS) && LINUX_VERSION_CODE >= VERSION_CODE(2,6,22)
+#define USE_HIGHRESTIMER
+#else
+#define USE_RTC
+#endif
+#else
+#if 0
+#define USE_RTC
+#endif
+#endif
+#endif
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include "zaptel.h"
+#ifndef LINUX26
+#include <linux/usb.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#endif
+#ifdef LINUX26
+#ifdef USE_HIGHRESTIMER
+#include <linux/hrtimer.h>
+#endif
+#ifdef USE_RTC
+#include <linux/rtc.h>
+#endif
+#include <linux/moduleparam.h>
+#endif
+#include "ztdummy.h"
+
+
+static struct ztdummy *ztd;
+
+static int debug = 0;
+
+#ifdef LINUX26
+#ifdef USE_HIGHRESTIMER
+#define CLOCK_SRC "HRtimer"
+struct hrtimer zaptimer;
+#elif defined(USE_RTC)
+#define CLOCK_SRC "RTC"
+static int rtc_rate = 0;
+static int current_rate = 0;
+static int taskletpending = 0;
+static struct tasklet_struct ztd_tlet;
+static void ztd_tasklet(unsigned long data);
+#else /* Linux 2.6, but no RTC or HRTIMER used */
+#define CLOCK_SRC "Linux26"
+/* 2.6 kernel timer stuff */
+static struct timer_list timer;
+#endif
+#else
+#if LINUX_VERSION_CODE < VERSION_CODE(2,4,5)
+# error "This kernel is too old: not supported by this file"
+#endif
+#define CLOCK_SRC "UHCI"
+/* Old UCHI stuff */
+static uhci_desc_t *td;
+static uhci_t *s;
+static int monitor = 0;
+
+/* exported kernel symbols */
+extern int insert_td (uhci_t *s, uhci_desc_t *qh, uhci_desc_t* new, int flags);
+extern int alloc_td (uhci_t *s, uhci_desc_t ** new, int flags);
+extern int insert_td_horizontal (uhci_t *s, uhci_desc_t *td, uhci_desc_t* new);
+extern int unlink_td (uhci_t *s, uhci_desc_t *element, int phys_unlink);
+extern void fill_td (uhci_desc_t *td, int status, int info, __u32 buffer);
+extern void uhci_interrupt (int irq, void *__uhci, struct pt_regs *regs);
+extern int delete_desc (uhci_t *s, uhci_desc_t *element);
+extern uhci_t **uhci_devices;
+
+#endif
+
+
+#define ZAPTEL_RATE 1000 /* zaptel ticks per second */
+#define ZAPTEL_TIME (1000000 / ZAPTEL_RATE) /* zaptel tick time in us */
+#define ZAPTEL_TIME_NS (ZAPTEL_TIME * 1000) /* zaptel tick time in ns */
+
+/* Different bits of the debug variable: */
+#define DEBUG_GENERAL (1 << 0)
+#define DEBUG_TICKS (1 << 1)
+
+
+#ifdef LINUX26
+#ifdef USE_RTC
+static void update_rtc_rate(struct ztdummy *ztd)
+{
+ if (((rtc_rate & (rtc_rate - 1)) != 0) || (rtc_rate > 8192) || (rtc_rate < 2)) {
+ printk(KERN_NOTICE "Invalid RTC rate %d specified\n", rtc_rate);
+ rtc_rate = current_rate; /* Set default RTC rate */
+ }
+ if (!rtc_rate || (rtc_rate != current_rate)) {
+ rtc_control(&ztd->rtc_task, RTC_IRQP_SET, current_rate = (rtc_rate ? rtc_rate : 1024)); /* 1024 Hz */
+ printk(KERN_INFO "ztdummy: RTC rate is %d\n", rtc_rate);
+ ztd->counter = 0;
+ }
+}
+
+static void ztd_tasklet(unsigned long data)
+{
+ if (taskletpending)
+ update_rtc_rate((struct ztdummy *)ztd);
+ taskletpending = 0;
+}
+
+/* rtc_interrupt - called at 1024Hz from hook in RTC handler */
+static void ztdummy_rtc_interrupt(void *private_data)
+{
+ struct ztdummy *ztd = private_data;
+ unsigned long flags;
+
+ /* Is spinlock required here??? */
+ spin_lock_irqsave(&ztd->rtclock, flags);
+ ztd->counter += ZAPTEL_TIME;
+ while (ztd->counter >= current_rate) {
+ ztd->counter -= current_rate;
+ /* Update of RTC IRQ rate isn't possible from interrupt handler :( */
+ if (!taskletpending && (current_rate != rtc_rate)) {
+ taskletpending = 1;
+ tasklet_hi_schedule(&ztd_tlet);
+ }
+ zt_receive(&ztd->span);
+ zt_transmit(&ztd->span);
+ }
+ spin_unlock_irqrestore(&ztd->rtclock, flags);
+}
+#elif defined(USE_HIGHRESTIMER)
+static enum hrtimer_restart ztdummy_hr_int(struct hrtimer *htmr)
+{
+ unsigned long overrun;
+
+ /* Trigger Zaptel */
+ zt_receive(&ztd->span);
+ zt_transmit(&ztd->span);
+
+ /* Overrun should always return 1, since we are in the timer that
+ * expired.
+ * We should worry if overrun is 2 or more; then we really missed
+ * a tick */
+ overrun = hrtimer_forward(&zaptimer, htmr->expires,
+ ktime_set(0, ZAPTEL_TIME_NS));
+ if(overrun > 1) {
+ if(printk_ratelimit())
+ printk(KERN_NOTICE "ztdummy: HRTimer missed %lu ticks\n",
+ overrun - 1);
+ }
+
+ if(debug && DEBUG_TICKS) {
+ static int count = 0;
+ /* Printk every 5 seconds, good test to see if timer is
+ * running properly */
+ if (count++ % 5000 == 0)
+ printk(KERN_DEBUG "ztdummy: 5000 ticks from hrtimer\n");
+ }
+
+ /* Always restart the timer */
+ return HRTIMER_RESTART;
+}
+#else
+/* use kernel system tick timer if PC architecture RTC is not available */
+static void ztdummy_timer(unsigned long param)
+{
+ timer.expires = jiffies + 1;
+ add_timer(&timer);
+
+ ztd->counter += ZAPTEL_TIME;
+ while (ztd->counter >= HZ) {
+ ztd->counter -= HZ;
+ zt_receive(&ztd->span);
+ zt_transmit(&ztd->span);
+ }
+}
+#endif
+#else
+static void ztdummy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned short status;
+ unsigned int io_addr = s->io_addr;
+
+ status = inw (io_addr + USBSTS);
+ if (status != 0) { /* interrupt from our USB port */
+ static int check_int = 0;
+ zt_receive(&ztd->span);
+ zt_transmit(&ztd->span);
+ /* TODO: What's the relation between monitor and
+ * DEBUG_TICKS */
+ if (monitor && check_int) {
+ check_int = 1;
+ printk(KERN_NOTICE "ztdummy: interrupt triggered \n");
+ }
+ }
+ return;
+}
+#endif
+
+static int ztdummy_initialize(struct ztdummy *ztd)
+{
+ /* Zapata stuff */
+ sprintf(ztd->span.name, "ZTDUMMY/1");
+ snprintf(ztd->span.desc, sizeof(ztd->span.desc) - 1, "%s (source: " CLOCK_SRC ") %d", ztd->span.name, 1);
+ sprintf(ztd->chan.name, "ZTDUMMY/%d/%d", 1, 0);
+ zap_copy_string(ztd->span.devicetype, "Zaptel Dummy Timing Driver", sizeof(ztd->span.devicetype));
+ ztd->chan.chanpos = 1;
+ ztd->span.chans = &ztd->chan;
+ ztd->span.channels = 0; /* no channels on our span */
+ ztd->span.deflaw = ZT_LAW_MULAW;
+ init_waitqueue_head(&ztd->span.maintq);
+ ztd->span.pvt = ztd;
+ ztd->chan.pvt = ztd;
+ if (zt_register(&ztd->span, 0)) {
+ return -1;
+ }
+ return 0;
+}
+
+int init_module(void)
+{
+#ifdef LINUX26
+#ifdef USE_RTC
+ int err;
+#endif
+#else
+ int irq;
+#ifdef DEFINE_SPINLOCK
+ DEFINE_SPINLOCK(mylock);
+#else
+ spinlock_t mylock = SPIN_LOCK_UNLOCKED;
+#endif
+
+ if (uhci_devices==NULL) {
+ printk (KERN_ERR "ztdummy: Uhci_devices pointer error.\n");
+ return -ENODEV;
+ }
+ s=*uhci_devices; /* uhci device */
+ if (s==NULL) {
+ printk (KERN_ERR "ztdummy: No uhci_device found.\n");
+ return -ENODEV;
+ }
+#endif
+
+ ztd = kmalloc(sizeof(struct ztdummy), GFP_KERNEL);
+ if (ztd == NULL) {
+ printk(KERN_ERR "ztdummy: Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ memset(ztd, 0x0, sizeof(struct ztdummy));
+
+ if (ztdummy_initialize(ztd)) {
+ printk(KERN_ERR "ztdummy: Unable to intialize zaptel driver\n");
+ kfree(ztd);
+ return -ENODEV;
+ }
+
+#ifdef LINUX26
+ ztd->counter = 0;
+#ifdef USE_RTC
+ ztd->rtclock = SPIN_LOCK_UNLOCKED;
+ ztd->rtc_task.func = ztdummy_rtc_interrupt;
+ ztd->rtc_task.private_data = ztd;
+ err = rtc_register(&ztd->rtc_task);
+ if (err < 0) {
+ printk(KERN_ERR "ztdummy: Unable to register zaptel rtc driver\n");
+ zt_unregister(&ztd->span);
+ kfree(ztd);
+ return err;
+ }
+ /* Set default RTC interrupt rate to 1024Hz */
+ if (!rtc_rate)
+ rtc_rate = 1024;
+ update_rtc_rate(ztd);
+ rtc_control(&ztd->rtc_task, RTC_PIE_ON, 0);
+ tasklet_init(&ztd_tlet, ztd_tasklet, 0);
+#elif defined(USE_HIGHRESTIMER)
+ printk(KERN_DEBUG "ztdummy: Trying to load High Resolution Timer\n");
+ hrtimer_init(&zaptimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ printk(KERN_DEBUG "ztdummy: Initialized High Resolution Timer\n");
+
+ /* Set timer callback function */
+ zaptimer.function = ztdummy_hr_int;
+
+ printk(KERN_DEBUG "ztdummy: Starting High Resolution Timer\n");
+ hrtimer_start(&zaptimer, ktime_set(0, ZAPTEL_TIME_NS), HRTIMER_MODE_REL);
+ printk(KERN_INFO "ztdummy: High Resolution Timer started, good to go\n");
+#else
+ init_timer(&timer);
+ timer.function = ztdummy_timer;
+ timer.expires = jiffies + 1;
+ add_timer(&timer);
+#endif
+#else
+ irq=s->irq;
+ spin_lock_irq(&mylock);
+ free_irq(s->irq, s); /* remove uhci_interrupt temporaly */
+ if (request_irq (irq, ztdummy_interrupt, ZAP_IRQ_SHARED, "ztdummy", ztd)) {
+ spin_unlock_irq(&mylock);
+ err("Our request_irq %d failed!",irq);
+ kfree(ztd);
+ return -EIO;
+ } /* we add our handler first, to assure, that our handler gets called first */
+ if (request_irq (irq, uhci_interrupt, ZAP_IRQ_SHARED, s->uhci_pci->driver->name, s)) {
+ spin_unlock_irq(&mylock);
+ err("Original request_irq %d failed!",irq);
+ }
+ spin_unlock_irq(&mylock);
+
+ /* add td to usb host controller interrupt queue */
+ alloc_td(s, &td, 0);
+ fill_td(td, TD_CTRL_IOC, 0, 0);
+ insert_td_horizontal(s, s->int_chain[0], td); /* use int_chain[0] to get 1ms interrupts */
+#endif
+
+ if (debug)
+ printk(KERN_DEBUG "ztdummy: init() finished\n");
+ return 0;
+}
+
+
+void cleanup_module(void)
+{
+#ifdef LINUX26
+#ifdef USE_RTC
+ if (taskletpending) {
+ tasklet_disable(&ztd_tlet);
+ tasklet_kill(&ztd_tlet);
+ }
+ rtc_control(&ztd->rtc_task, RTC_PIE_OFF, 0);
+ rtc_unregister(&ztd->rtc_task);
+#elif defined(USE_HIGHRESTIMER)
+ /* Stop high resolution timer */
+ hrtimer_cancel(&zaptimer);
+#else
+ del_timer(&timer);
+#endif
+#else
+ free_irq(s->irq, ztd); /* disable interrupts */
+#endif
+ zt_unregister(&ztd->span);
+ kfree(ztd);
+#ifndef LINUX26
+ unlink_td(s, td, 1);
+ delete_desc(s, td);
+#endif
+ if (debug)
+ printk("ztdummy: cleanup() finished\n");
+}
+
+
+
+#ifdef LINUX26
+module_param(debug, int, 0600);
+#ifdef USE_RTC
+module_param(rtc_rate, int, 0600);
+#endif
+#else
+MODULE_PARM(debug, "i");
+#endif
+
+#ifndef LINUX26
+MODULE_PARM(monitor, "i");
+#endif
+MODULE_DESCRIPTION("Dummy Zaptel Driver");
+MODULE_AUTHOR("Robert Pleh <robert.pleh@hermes.si>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
diff --git a/drivers/dahdi/ztdummy.h b/drivers/dahdi/ztdummy.h
new file mode 100644
index 0000000..25e37c9
--- /dev/null
+++ b/drivers/dahdi/ztdummy.h
@@ -0,0 +1,152 @@
+/*
+ * Dummy Zaptel Driver for Zapata Telephony interface
+ *
+ * Written by Robert Pleh <robert.pleh@hermes.si>
+ *
+ * Copyright (C) 2002, Hermes Softlab
+ *
+ * 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/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,19)
+#define USB2420
+#endif
+
+struct ztdummy {
+ struct zt_span span;
+ struct zt_chan chan;
+#ifdef LINUX26
+ unsigned int counter;
+#ifdef USE_RTC
+ spinlock_t rtclock;
+ rtc_task_t rtc_task;
+#endif
+#endif
+};
+
+
+#ifndef LINUX26
+/* Uhci definitions and structures - from file usb-uhci.h */
+#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */
+#define USBSTS 2
+
+typedef enum {
+ TD_TYPE, QH_TYPE
+} uhci_desc_type_t;
+
+typedef struct {
+ __u32 link;
+ __u32 status;
+ __u32 info;
+ __u32 buffer;
+} uhci_td_t, *puhci_td_t;
+
+
+typedef struct {
+ __u32 head;
+ __u32 element; /* Queue element pointer */
+} uhci_qh_t, *puhci_qh_t;
+
+typedef struct {
+ union {
+ uhci_td_t td;
+ uhci_qh_t qh;
+ } hw;
+ uhci_desc_type_t type;
+ dma_addr_t dma_addr;
+ struct list_head horizontal;
+ struct list_head vertical;
+ struct list_head desc_list;
+ int last_used;
+} uhci_desc_t, *puhci_desc_t;
+
+typedef struct {
+ struct list_head desc_list; // list pointer to all corresponding TDs/QHs associated with this request
+ dma_addr_t setup_packet_dma;
+ dma_addr_t transfer_buffer_dma;
+ unsigned long started;
+#ifdef USB2420
+ struct urb *next_queued_urb; // next queued urb for this EP
+ struct urb *prev_queued_urb;
+#else
+ urb_t *next_queued_urb;
+ urb_t *prev_queued_urb;
+#endif
+ uhci_desc_t *bottom_qh;
+ uhci_desc_t *next_qh; // next helper QH
+ char use_loop;
+ char flags;
+} urb_priv_t, *purb_priv_t;
+
+struct virt_root_hub {
+ int devnum; /* Address of Root Hub endpoint */
+ void *urb;
+ void *int_addr;
+ int send;
+ int interval;
+ int numports;
+ int c_p_r[8];
+ struct timer_list rh_int_timer;
+};
+
+typedef struct uhci {
+ int irq;
+ unsigned int io_addr;
+ unsigned int io_size;
+ unsigned int maxports;
+ int running;
+
+ int apm_state;
+
+ struct uhci *next; // chain of uhci device contexts
+
+ struct list_head urb_list; // list of all pending urbs
+
+ spinlock_t urb_list_lock; // lock to keep consistency
+
+ int unlink_urb_done;
+ atomic_t avoid_bulk;
+
+ struct usb_bus *bus; // our bus
+
+ __u32 *framelist;
+ dma_addr_t framelist_dma;
+ uhci_desc_t **iso_td;
+ uhci_desc_t *int_chain[8];
+ uhci_desc_t *ls_control_chain;
+ uhci_desc_t *control_chain;
+ uhci_desc_t *bulk_chain;
+ uhci_desc_t *chain_end;
+ uhci_desc_t *td1ms;
+ uhci_desc_t *td32ms;
+ struct list_head free_desc;
+ spinlock_t qh_lock;
+ spinlock_t td_lock;
+ struct virt_root_hub rh; //private data of the virtual root hub
+ int loop_usage; // URBs using bandwidth reclamation
+
+ struct list_head urb_unlinked; // list of all unlinked urbs
+ long timeout_check;
+ int timeout_urbs;
+ struct pci_dev *uhci_pci;
+ struct pci_pool *desc_pool;
+ long last_error_time; // last error output in uhci_interrupt()
+} uhci_t, *puhci_t;
+#endif
diff --git a/drivers/dahdi/ztdynamic.c b/drivers/dahdi/ztdynamic.c
new file mode 100644
index 0000000..196d395
--- /dev/null
+++ b/drivers/dahdi/ztdynamic.c
@@ -0,0 +1,870 @@
+/*
+ * Dynamic Span Interface for Zaptel
+ *
+ * Written by Mark Spencer <markster@digium.com>
+ *
+ * Copyright (C) 2001, Linux Support Services, 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/interrupt.h>
+#include <linux/vmalloc.h>
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <zaptel/zaptel.h>
+#endif
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+/*
+ * Tasklets provide better system interactive response at the cost of the
+ * possibility of losing a frame of data at very infrequent intervals. If
+ * you are more concerned with the performance of your machine, enable the
+ * tasklets. If you are strict about absolutely no drops, then do not enable
+ * tasklets.
+ */
+
+#define ENABLE_TASKLETS
+
+/*
+ * Dynamic spans implemented using TDM over X with standard message
+ * types. Message format is as follows:
+ *
+ * Byte #: Meaning
+ * 0 Number of samples per channel
+ * 1 Current flags on span
+ * Bit 0: Yellow Alarm
+ * Bit 1: Sig bits present
+ * Bits 2-7: reserved for future use
+ * 2-3 16-bit counter value for detecting drops, network byte order.
+ * 4-5 Number of channels in the message, network byte order
+ * 6... 16-bit words, containing sig bits for each
+ * four channels, least significant 4 bits being
+ * the least significant channel, network byte order.
+ * the rest data for each channel, all samples per channel
+ before moving to the next.
+ */
+
+/* Arbitrary limit to the max # of channels in a span */
+#define ZT_DYNAMIC_MAX_CHANS 256
+
+#define ZTD_FLAG_YELLOW_ALARM (1 << 0)
+#define ZTD_FLAG_SIGBITS_PRESENT (1 << 1)
+#define ZTD_FLAG_LOOPBACK (1 << 2)
+
+#define ERR_NSAMP (1 << 16)
+#define ERR_NCHAN (1 << 17)
+#define ERR_LEN (1 << 18)
+
+EXPORT_SYMBOL(zt_dynamic_register);
+EXPORT_SYMBOL(zt_dynamic_unregister);
+EXPORT_SYMBOL(zt_dynamic_receive);
+
+#ifdef ENABLE_TASKLETS
+static int taskletrun;
+static int taskletsched;
+static int taskletpending;
+static int taskletexec;
+static int txerrors;
+static struct tasklet_struct ztd_tlet;
+
+static void ztd_tasklet(unsigned long data);
+#endif
+
+
+static struct zt_dynamic {
+ char addr[40];
+ char dname[20];
+ int err;
+ int usecount;
+ int dead;
+ long rxjif;
+ unsigned short txcnt;
+ unsigned short rxcnt;
+ struct zt_span span;
+ struct zt_chan *chans;
+ struct zt_dynamic *next;
+ struct zt_dynamic_driver *driver;
+ void *pvt;
+ int timing;
+ int master;
+ unsigned char *msgbuf;
+} *dspans;
+
+static struct zt_dynamic_driver *drivers = NULL;
+
+static int debug = 0;
+
+static int hasmaster = 0;
+#ifdef DEFINE_SPINLOCK
+static DEFINE_SPINLOCK(dlock);
+#else
+static spinlock_t dlock = SPIN_LOCK_UNLOCKED;
+#endif
+
+#ifdef DEFINE_RWLOCK
+static DEFINE_RWLOCK(drvlock);
+#else
+static rwlock_t drvlock = RW_LOCK_UNLOCKED;
+#endif
+
+static void checkmaster(void)
+{
+ unsigned long flags;
+ int newhasmaster=0;
+ int best = 9999999;
+ struct zt_dynamic *z, *master=NULL;
+ spin_lock_irqsave(&dlock, flags);
+ z = dspans;
+ while(z) {
+ if (z->timing) {
+ z->master = 0;
+ if (!(z->span.alarms & ZT_ALARM_RED) &&
+ (z->timing < best) && !z->dead) {
+ /* If not in alarm and they're
+ a better timing source, use them */
+ master = z;
+ best = z->timing;
+ newhasmaster = 1;
+ }
+ }
+ z = z->next;
+ }
+ hasmaster = newhasmaster;
+ /* Mark the new master if there is one */
+ if (master)
+ master->master = 1;
+ spin_unlock_irqrestore(&dlock, flags);
+ if (master)
+ printk("TDMoX: New master: %s\n", master->span.name);
+ else
+ printk("TDMoX: No master.\n");
+}
+
+static void ztd_sendmessage(struct zt_dynamic *z)
+{
+ unsigned char *buf = z->msgbuf;
+ unsigned short bits;
+ int msglen = 0;
+ int x;
+ int offset;
+
+ /* Byte 0: Number of samples per channel */
+ *buf = ZT_CHUNKSIZE;
+ buf++; msglen++;
+
+ /* Byte 1: Flags */
+ *buf = 0;
+ if (z->span.alarms & ZT_ALARM_RED)
+ *buf |= ZTD_FLAG_YELLOW_ALARM;
+ *buf |= ZTD_FLAG_SIGBITS_PRESENT;
+ buf++; msglen++;
+
+ /* Bytes 2-3: Transmit counter */
+ *((unsigned short *)buf) = htons((unsigned short)z->txcnt);
+ z->txcnt++;
+ buf++; msglen++;
+ buf++; msglen++;
+
+ /* Bytes 4-5: Number of channels */
+ *((unsigned short *)buf) = htons((unsigned short)z->span.channels);
+ buf++; msglen++;
+ buf++; msglen++;
+ bits = 0;
+ offset = 0;
+ for (x=0;x<z->span.channels;x++) {
+ offset = x % 4;
+ bits |= (z->chans[x].txsig & 0xf) << (offset << 2);
+ if (offset == 3) {
+ /* Write the bits when we have four channels */
+ *((unsigned short *)buf) = htons(bits);
+ buf++; msglen++;
+ buf++; msglen++;
+ bits = 0;
+ }
+ }
+
+ if (offset != 3) {
+ /* Finish it off if it's not done already */
+ *((unsigned short *)buf) = htons(bits);
+ buf++; msglen++;
+ buf++; msglen++;
+ }
+
+ for (x=0;x<z->span.channels;x++) {
+ memcpy(buf, z->chans[x].writechunk, ZT_CHUNKSIZE);
+ buf += ZT_CHUNKSIZE;
+ msglen += ZT_CHUNKSIZE;
+ }
+
+ z->driver->transmit(z->pvt, z->msgbuf, msglen);
+
+}
+
+static void __ztdynamic_run(void)
+{
+ unsigned long flags;
+ struct zt_dynamic *z;
+ struct zt_dynamic_driver *drv;
+ int y;
+ spin_lock_irqsave(&dlock, flags);
+ z = dspans;
+ while(z) {
+ if (!z->dead) {
+ /* Ignore dead spans */
+ for (y=0;y<z->span.channels;y++) {
+ /* Echo cancel double buffered data */
+ zt_ec_chunk(&z->span.chans[y], z->span.chans[y].readchunk, z->span.chans[y].writechunk);
+ }
+ zt_receive(&z->span);
+ zt_transmit(&z->span);
+ /* Handle all transmissions now */
+ ztd_sendmessage(z);
+ }
+ z = z->next;
+ }
+ spin_unlock_irqrestore(&dlock, flags);
+
+ read_lock(&drvlock);
+ drv = drivers;
+ while(drv) {
+ /* Flush any traffic still pending in the driver */
+ if (drv->flush) {
+ drv->flush();
+ }
+ drv = drv->next;
+ }
+ read_unlock(&drvlock);
+}
+
+#ifdef ENABLE_TASKLETS
+static void ztdynamic_run(void)
+{
+ if (!taskletpending) {
+ taskletpending = 1;
+ taskletsched++;
+ tasklet_hi_schedule(&ztd_tlet);
+ } else {
+ txerrors++;
+ }
+}
+#else
+#define ztdynamic_run __ztdynamic_run
+#endif
+
+void zt_dynamic_receive(struct zt_span *span, unsigned char *msg, int msglen)
+{
+ struct zt_dynamic *ztd = span->pvt;
+ int newerr=0;
+ unsigned long flags;
+ int sflags;
+ int xlen;
+ int x, bits, sig;
+ int nchans, master;
+ int newalarm;
+ unsigned short rxpos, rxcnt;
+
+
+ spin_lock_irqsave(&dlock, flags);
+ if (msglen < 6) {
+ spin_unlock_irqrestore(&dlock, flags);
+ newerr = ERR_LEN;
+ if (newerr != ztd->err) {
+ printk("Span %s: Insufficient samples for header (only %d)\n", span->name, msglen);
+ }
+ ztd->err = newerr;
+ return;
+ }
+
+ /* First, check the chunksize */
+ if (*msg != ZT_CHUNKSIZE) {
+ spin_unlock_irqrestore(&dlock, flags);
+ newerr = ERR_NSAMP | msg[0];
+ if (newerr != ztd->err) {
+ printk("Span %s: Expected %d samples, but receiving %d\n", span->name, ZT_CHUNKSIZE, msg[0]);
+ }
+ ztd->err = newerr;
+ return;
+ }
+ msg++;
+ sflags = *msg;
+ msg++;
+
+ rxpos = ntohs(*((unsigned short *)msg));
+ msg++;
+ msg++;
+
+ nchans = ntohs(*((unsigned short *)msg));
+ if (nchans != span->channels) {
+ spin_unlock_irqrestore(&dlock, flags);
+ newerr = ERR_NCHAN | nchans;
+ if (newerr != ztd->err) {
+ printk("Span %s: Expected %d channels, but receiving %d\n", span->name, span->channels, nchans);
+ }
+ ztd->err = newerr;
+ return;
+ }
+ msg++;
+ msg++;
+
+ /* Okay now we've accepted the header, lets check our message
+ length... */
+
+ /* Start with header */
+ xlen = 6;
+ /* Add samples of audio */
+ xlen += nchans * ZT_CHUNKSIZE;
+ /* If RBS info is there, add that */
+ if (sflags & ZTD_FLAG_SIGBITS_PRESENT) {
+ /* Account for sigbits -- one short per 4 channels*/
+ xlen += ((nchans + 3) / 4) * 2;
+ }
+
+ if (xlen != msglen) {
+ spin_unlock_irqrestore(&dlock, flags);
+ newerr = ERR_LEN | xlen;
+ if (newerr != ztd->err) {
+ printk("Span %s: Expected message size %d, but was %d instead\n", span->name, xlen, msglen);
+ }
+ ztd->err = newerr;
+ return;
+ }
+
+ bits = 0;
+
+ /* Record sigbits if present */
+ if (sflags & ZTD_FLAG_SIGBITS_PRESENT) {
+ for (x=0;x<nchans;x++) {
+ if (!(x%4)) {
+ /* Get new bits */
+ bits = ntohs(*((unsigned short *)msg));
+ msg++;
+ msg++;
+ }
+
+ /* Pick the right bits */
+ sig = (bits >> ((x % 4) << 2)) & 0xff;
+
+ /* Update signalling if appropriate */
+ if (sig != span->chans[x].rxsig)
+ zt_rbsbits(&span->chans[x], sig);
+
+ }
+ }
+
+ /* Record data for channels */
+ for (x=0;x<nchans;x++) {
+ memcpy(span->chans[x].readchunk, msg, ZT_CHUNKSIZE);
+ msg += ZT_CHUNKSIZE;
+ }
+
+ master = ztd->master;
+
+ rxcnt = ztd->rxcnt;
+ ztd->rxcnt = rxpos+1;
+
+ spin_unlock_irqrestore(&dlock, flags);
+
+ /* Check for Yellow alarm */
+ newalarm = span->alarms & ~(ZT_ALARM_YELLOW | ZT_ALARM_RED);
+ if (sflags & ZTD_FLAG_YELLOW_ALARM)
+ newalarm |= ZT_ALARM_YELLOW;
+
+ if (newalarm != span->alarms) {
+ span->alarms = newalarm;
+ zt_alarm_notify(span);
+ checkmaster();
+ }
+
+ /* Keep track of last received packet */
+ ztd->rxjif = jiffies;
+
+ /* note if we had a missing packet */
+ if (rxpos != rxcnt)
+ printk("Span %s: Expected seq no %d, but received %d instead\n", span->name, rxcnt, rxpos);
+
+ /* If this is our master span, then run everything */
+ if (master)
+ ztdynamic_run();
+
+}
+
+static void dynamic_destroy(struct zt_dynamic *z)
+{
+ /* Unregister span if appropriate */
+ if (z->span.flags & ZT_FLAG_REGISTERED)
+ zt_unregister(&z->span);
+
+ /* Destroy the pvt stuff if there */
+ if (z->pvt)
+ z->driver->destroy(z->pvt);
+
+ /* Free message buffer if appropriate */
+ if (z->msgbuf)
+ kfree(z->msgbuf);
+
+ /* Free channels */
+ if (z->chans)
+ vfree(z->chans);
+ /* Free z */
+ kfree(z);
+
+ checkmaster();
+}
+
+static struct zt_dynamic *find_dynamic(ZT_DYNAMIC_SPAN *zds)
+{
+ struct zt_dynamic *z;
+ z = dspans;
+ while(z) {
+ if (!strcmp(z->dname, zds->driver) &&
+ !strcmp(z->addr, zds->addr))
+ break;
+ z = z->next;
+ }
+ return z;
+}
+
+static struct zt_dynamic_driver *find_driver(char *name)
+{
+ struct zt_dynamic_driver *ztd;
+ ztd = drivers;
+ while(ztd) {
+ /* here's our driver */
+ if (!strcmp(name, ztd->name))
+ break;
+ ztd = ztd->next;
+ }
+ return ztd;
+}
+
+static int destroy_dynamic(ZT_DYNAMIC_SPAN *zds)
+{
+ unsigned long flags;
+ struct zt_dynamic *z, *cur, *prev=NULL;
+ spin_lock_irqsave(&dlock, flags);
+ z = find_dynamic(zds);
+ if (!z) {
+ spin_unlock_irqrestore(&dlock, flags);
+ return -EINVAL;
+ }
+ /* Don't destroy span until it is in use */
+ if (z->usecount) {
+ spin_unlock_irqrestore(&dlock, flags);
+ printk("Attempt to destroy dynamic span while it is in use\n");
+ return -EBUSY;
+ }
+ /* Unlink it */
+ cur = dspans;
+ while(cur) {
+ if (cur == z) {
+ if (prev)
+ prev->next = z->next;
+ else
+ dspans = z->next;
+ break;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+ spin_unlock_irqrestore(&dlock, flags);
+
+ /* Destroy it */
+ dynamic_destroy(z);
+
+ return 0;
+}
+
+static int ztd_rbsbits(struct zt_chan *chan, int bits)
+{
+ /* Don't have to do anything */
+ return 0;
+}
+
+static int ztd_open(struct zt_chan *chan)
+{
+ struct zt_dynamic *z;
+ z = chan->span->pvt;
+ if (z) {
+ if (z->dead)
+ return -ENODEV;
+ z->usecount++;
+ }
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#else
+ if(!try_module_get(THIS_MODULE))
+ printk("TDMoX: Unable to increment module use count\n");
+#endif
+ return 0;
+}
+
+static int ztd_chanconfig(struct zt_chan *chan, int sigtype)
+{
+ return 0;
+}
+
+static int ztd_close(struct zt_chan *chan)
+{
+ struct zt_dynamic *z;
+ z = chan->span->pvt;
+ if (z)
+ z->usecount--;
+ if (z->dead && !z->usecount)
+ dynamic_destroy(z);
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#else
+ module_put(THIS_MODULE);
+#endif
+ return 0;
+}
+
+static int create_dynamic(ZT_DYNAMIC_SPAN *zds)
+{
+ struct zt_dynamic *z;
+ struct zt_dynamic_driver *ztd;
+ unsigned long flags;
+ int x;
+ int bufsize;
+
+ if (zds->numchans < 1) {
+ printk("Can't be less than 1 channel (%d)!\n", zds->numchans);
+ return -EINVAL;
+ }
+ if (zds->numchans >= ZT_DYNAMIC_MAX_CHANS) {
+ printk("Can't create dynamic span with greater than %d channels. See ztdynamic.c and increase ZT_DYNAMIC_MAX_CHANS\n", zds->numchans);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&dlock, flags);
+ z = find_dynamic(zds);
+ spin_unlock_irqrestore(&dlock, flags);
+ if (z)
+ return -EEXIST;
+
+ /* XXX There is a silly race here. We check it doesn't exist, but
+ someone could create it between now and then and we'd end up
+ with two of them. We don't want to hold the spinlock
+ for *too* long though, especially not if there is a possibility
+ of kmalloc. XXX */
+
+
+ /* Allocate memory */
+ z = (struct zt_dynamic *)kmalloc(sizeof(struct zt_dynamic), GFP_KERNEL);
+ if (!z)
+ return -ENOMEM;
+
+ /* Zero it out */
+ memset(z, 0, sizeof(struct zt_dynamic));
+
+ /* Allocate other memories */
+ z->chans = vmalloc(sizeof(struct zt_chan) * zds->numchans);
+ if (!z->chans) {
+ dynamic_destroy(z);
+ return -ENOMEM;
+ }
+
+ /* Zero out channel stuff */
+ memset(z->chans, 0, sizeof(struct zt_chan) * zds->numchans);
+
+ /* Allocate message buffer with sample space and header space */
+ bufsize = zds->numchans * ZT_CHUNKSIZE + zds->numchans / 4 + 48;
+
+ z->msgbuf = kmalloc(bufsize, GFP_KERNEL);
+
+ if (!z->msgbuf) {
+ dynamic_destroy(z);
+ return -ENOMEM;
+ }
+
+ /* Zero out -- probably not needed but why not */
+ memset(z->msgbuf, 0, bufsize);
+
+ /* Setup parameters properly assuming we're going to be okay. */
+ zap_copy_string(z->dname, zds->driver, sizeof(z->dname));
+ zap_copy_string(z->addr, zds->addr, sizeof(z->addr));
+ z->timing = zds->timing;
+ sprintf(z->span.name, "ZTD/%s/%s", zds->driver, zds->addr);
+ sprintf(z->span.desc, "Dynamic '%s' span at '%s'", zds->driver, zds->addr);
+ z->span.channels = zds->numchans;
+ z->span.pvt = z;
+ z->span.deflaw = ZT_LAW_MULAW;
+ z->span.flags |= ZT_FLAG_RBS;
+ z->span.chans = z->chans;
+ z->span.rbsbits = ztd_rbsbits;
+ z->span.open = ztd_open;
+ z->span.close = ztd_close;
+ z->span.chanconfig = ztd_chanconfig;
+ for (x=0;x<zds->numchans;x++) {
+ sprintf(z->chans[x].name, "ZTD/%s/%s/%d", zds->driver, zds->addr, x+1);
+ z->chans[x].sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_FXSLS |
+ ZT_SIG_FXSKS | ZT_SIG_FXSGS | ZT_SIG_FXOLS |
+ ZT_SIG_FXOKS | ZT_SIG_FXOGS | ZT_SIG_SF |
+ ZT_SIG_DACS_RBS | ZT_SIG_CAS;
+ z->chans[x].chanpos = x + 1;
+ z->chans[x].pvt = z;
+ }
+
+ spin_lock_irqsave(&dlock, flags);
+ ztd = find_driver(zds->driver);
+ if (!ztd) {
+ /* Try loading the right module */
+ char fn[80];
+ spin_unlock_irqrestore(&dlock, flags);
+ sprintf(fn, "ztd-%s", zds->driver);
+ request_module(fn);
+ spin_lock_irqsave(&dlock, flags);
+ ztd = find_driver(zds->driver);
+ }
+ spin_unlock_irqrestore(&dlock, flags);
+
+
+ /* Another race -- should let the module get unloaded while we
+ have it here */
+ if (!ztd) {
+ printk("No such driver '%s' for dynamic span\n", zds->driver);
+ dynamic_destroy(z);
+ return -EINVAL;
+ }
+
+ /* Create the stuff */
+ z->pvt = ztd->create(&z->span, z->addr);
+ if (!z->pvt) {
+ printk("Driver '%s' (%s) rejected address '%s'\n", ztd->name, ztd->desc, z->addr);
+ /* Creation failed */
+ return -EINVAL;
+ }
+
+ /* Remember the driver */
+ z->driver = ztd;
+
+ /* Whee! We're created. Now register the span */
+ if (zt_register(&z->span, 0)) {
+ printk("Unable to register span '%s'\n", z->span.name);
+ dynamic_destroy(z);
+ return -EINVAL;
+ }
+
+ /* Okay, created and registered. add it to the list */
+ spin_lock_irqsave(&dlock, flags);
+ z->next = dspans;
+ dspans = z;
+ spin_unlock_irqrestore(&dlock, flags);
+
+ checkmaster();
+
+ /* All done */
+ return z->span.spanno;
+
+}
+
+#ifdef ENABLE_TASKLETS
+static void ztd_tasklet(unsigned long data)
+{
+ taskletrun++;
+ if (taskletpending) {
+ taskletexec++;
+ __ztdynamic_run();
+ }
+ taskletpending = 0;
+}
+#endif
+
+static int ztdynamic_ioctl(unsigned int cmd, unsigned long data)
+{
+ ZT_DYNAMIC_SPAN zds;
+ int res;
+ switch(cmd) {
+ case 0:
+ /* This is called just before rotation. If none of our
+ spans are pulling timing, then now is the time to process
+ them */
+ if (!hasmaster)
+ ztdynamic_run();
+ return 0;
+ case ZT_DYNAMIC_CREATE:
+ if (copy_from_user(&zds, (ZT_DYNAMIC_SPAN *)data, sizeof(zds)))
+ return -EFAULT;
+ if (debug)
+ printk("Dynamic Create\n");
+ res = create_dynamic(&zds);
+ if (res < 0)
+ return res;
+ zds.spanno = res;
+ /* Let them know the new span number */
+ if (copy_to_user((ZT_DYNAMIC_SPAN *)data, &zds, sizeof(zds)))
+ return -EFAULT;
+ return 0;
+ case ZT_DYNAMIC_DESTROY:
+ if (copy_from_user(&zds, (ZT_DYNAMIC_SPAN *)data, sizeof(zds)))
+ return -EFAULT;
+ if (debug)
+ printk("Dynamic Destroy\n");
+ return destroy_dynamic(&zds);
+ }
+
+ return -ENOTTY;
+}
+
+int zt_dynamic_register(struct zt_dynamic_driver *dri)
+{
+ unsigned long flags;
+ int res = 0;
+ write_lock_irqsave(&drvlock, flags);
+ if (find_driver(dri->name))
+ res = -1;
+ else {
+ dri->next = drivers;
+ drivers = dri;
+ }
+ write_unlock_irqrestore(&drvlock, flags);
+ return res;
+}
+
+void zt_dynamic_unregister(struct zt_dynamic_driver *dri)
+{
+ struct zt_dynamic_driver *cur, *prev=NULL;
+ struct zt_dynamic *z, *zp, *zn;
+ unsigned long flags;
+ write_lock_irqsave(&drvlock, flags);
+ cur = drivers;
+ while(cur) {
+ if (cur == dri) {
+ if (prev)
+ prev->next = cur->next;
+ else
+ drivers = cur->next;
+ break;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+ write_unlock_irqrestore(&drvlock, flags);
+ spin_lock_irqsave(&dlock, flags);
+ z = dspans;
+ zp = NULL;
+ while(z) {
+ zn = z->next;
+ if (z->driver == dri) {
+ /* Unlink */
+ if (zp)
+ zp->next = z->next;
+ else
+ dspans = z->next;
+ if (!z->usecount)
+ dynamic_destroy(z);
+ else
+ z->dead = 1;
+ } else {
+ zp = z;
+ }
+ z = zn;
+ }
+ spin_unlock_irqrestore(&dlock, flags);
+}
+
+struct timer_list alarmcheck;
+
+static void check_for_red_alarm(unsigned long ignored)
+{
+ unsigned long flags;
+ int newalarm;
+ int alarmchanged = 0;
+ struct zt_dynamic *z;
+ spin_lock_irqsave(&dlock, flags);
+ z = dspans;
+ while(z) {
+ newalarm = z->span.alarms & ~ZT_ALARM_RED;
+ /* If nothing received for a second, consider that RED ALARM */
+ if ((jiffies - z->rxjif) > 1 * HZ) {
+ newalarm |= ZT_ALARM_RED;
+ if (z->span.alarms != newalarm) {
+ z->span.alarms = newalarm;
+ zt_alarm_notify(&z->span);
+ alarmchanged++;
+ }
+ }
+ z = z->next;
+ }
+ spin_unlock_irqrestore(&dlock, flags);
+ if (alarmchanged)
+ checkmaster();
+
+ /* Do the next one */
+ mod_timer(&alarmcheck, jiffies + 1 * HZ);
+
+}
+
+int ztdynamic_init(void)
+{
+ zt_set_dynamic_ioctl(ztdynamic_ioctl);
+ /* Start process to check for RED ALARM */
+ init_timer(&alarmcheck);
+ alarmcheck.expires = 0;
+ alarmcheck.data = 0;
+ alarmcheck.function = check_for_red_alarm;
+ /* Check once per second */
+ mod_timer(&alarmcheck, jiffies + 1 * HZ);
+#ifdef ENABLE_TASKLETS
+ tasklet_init(&ztd_tlet, ztd_tasklet, 0);
+#endif
+ printk("Zaptel Dynamic Span support LOADED\n");
+ return 0;
+}
+
+void ztdynamic_cleanup(void)
+{
+#ifdef ENABLE_TASKLETS
+ if (taskletpending) {
+ tasklet_disable(&ztd_tlet);
+ tasklet_kill(&ztd_tlet);
+ }
+#endif
+ zt_set_dynamic_ioctl(NULL);
+ del_timer(&alarmcheck);
+ printk("Zaptel Dynamic Span support unloaded\n");
+}
+
+#ifdef LINUX26
+module_param(debug, int, 0600);
+#else
+MODULE_PARM(debug, "i");
+#endif
+MODULE_DESCRIPTION("Zaptel Dynamic Span Support");
+MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(ztdynamic_init);
+module_exit(ztdynamic_cleanup);
diff --git a/drivers/dahdi/zttranscode.c b/drivers/dahdi/zttranscode.c
new file mode 100644
index 0000000..6a441df
--- /dev/null
+++ b/drivers/dahdi/zttranscode.c
@@ -0,0 +1,491 @@
+/*
+ * Transcoder Interface for Zaptel
+ *
+ * Written by Mark Spencer <markster@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 <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/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/page-flags.h>
+#include <asm/io.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 LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+static int debug = 0;
+static struct zt_transcoder *trans;
+static spinlock_t translock = SPIN_LOCK_UNLOCKED;
+
+EXPORT_SYMBOL(zt_transcoder_register);
+EXPORT_SYMBOL(zt_transcoder_unregister);
+EXPORT_SYMBOL(zt_transcoder_alert);
+EXPORT_SYMBOL(zt_transcoder_alloc);
+EXPORT_SYMBOL(zt_transcoder_free);
+
+struct zt_transcoder *zt_transcoder_alloc(int numchans)
+{
+ struct zt_transcoder *ztc;
+ unsigned int x;
+ size_t size = sizeof(*ztc) + (sizeof(ztc->channels[0]) * numchans);
+
+ if (!(ztc = kmalloc(size, GFP_KERNEL)))
+ return NULL;
+
+ memset(ztc, 0, size);
+ strcpy(ztc->name, "<unspecified>");
+ ztc->numchannels = numchans;
+ for (x=0;x<ztc->numchannels;x++) {
+ 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;
+}
+
+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;
+}
+
+void zt_transcoder_free(struct zt_transcoder *ztc)
+{
+ kfree(ztc);
+}
+
+/* Register a transcoder */
+int zt_transcoder_register(struct zt_transcoder *tc)
+{
+ struct zt_transcoder *cur;
+ int res = -EBUSY;
+
+ spin_lock(&translock);
+ for (cur = trans; cur; cur = cur->next) {
+ if (cur == tc) {
+ spin_unlock(&translock);
+ return res;
+ }
+ }
+
+ tc->next = trans;
+ trans = tc;
+ printk("Registered codec translator '%s' with %d transcoders (srcs=%08x, dsts=%08x)\n",
+ tc->name, tc->numchannels, tc->srcfmts, tc->dstfmts);
+ res = 0;
+ spin_unlock(&translock);
+
+ return res;
+}
+
+/* Unregister a transcoder */
+int zt_transcoder_unregister(struct zt_transcoder *tc)
+{
+ struct zt_transcoder *cur, *prev;
+ int res = -EINVAL;
+
+ spin_lock(&translock);
+ for (cur = trans, prev = NULL; cur; prev = cur, cur = cur->next) {
+ if (cur == tc)
+ break;
+ }
+
+ if (!cur) {
+ spin_unlock(&translock);
+ return res;
+ }
+
+ if (prev)
+ prev->next = tc->next;
+ else
+ trans = tc->next;
+ tc->next = NULL;
+ printk("Unregistered codec translator '%s' with %d transcoders (srcs=%08x, dsts=%08x)\n",
+ tc->name, tc->numchannels, tc->srcfmts, tc->dstfmts);
+ res = 0;
+ spin_unlock(&translock);
+
+ return res;
+}
+
+/* Alert a transcoder */
+int zt_transcoder_alert(struct zt_transcoder_channel *ztc)
+{
+ if (debug)
+ printk("ZT Transcoder Alert!\n");
+ if (ztc->tch)
+ ztc->tch->status &= ~ZT_TC_FLAG_BUSY;
+ wake_up_interruptible(&ztc->ready);
+
+ return 0;
+}
+
+static int zt_tc_open(struct inode *inode, struct file *file)
+{
+ struct zt_transcoder_channel *ztc;
+ struct zt_transcode_header *zth;
+ struct page *page;
+
+ if (!(ztc = kmalloc(sizeof(*ztc), GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (!(zth = kmalloc(sizeof(*zth), GFP_KERNEL | GFP_DMA))) {
+ kfree(ztc);
+ return -ENOMEM;
+ }
+
+ memset(ztc, 0, sizeof(*ztc));
+ memset(zth, 0, sizeof(*zth));
+ ztc->flags = ZT_TC_FLAG_TRANSIENT | ZT_TC_FLAG_BUSY;
+ ztc->tch = zth;
+ if (debug)
+ printk("Allocated Transcoder Channel, header is at %p!\n", zth);
+ zth->magic = ZT_TRANSCODE_MAGIC;
+ file->private_data = ztc;
+ for (page = virt_to_page(zth);
+ page < virt_to_page((unsigned long) zth + sizeof(*zth));
+ page++)
+ SetPageReserved(page);
+
+ return 0;
+}
+
+static void ztc_release(struct zt_transcoder_channel *ztc)
+{
+ struct zt_transcode_header *zth = ztc->tch;
+ struct page *page;
+
+ if (!ztc)
+ return;
+
+ ztc->flags &= ~(ZT_TC_FLAG_BUSY);
+
+ 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)
+ printk("Released Transcoder!\n");
+}
+
+static int zt_tc_release(struct inode *inode, struct file *file)
+{
+ ztc_release(file->private_data);
+
+ return 0;
+}
+
+static int do_reset(struct zt_transcoder_channel **ztc)
+{
+ struct zt_transcoder_channel *newztc = NULL, *origztc = NULL;
+ struct zt_transcode_header *zth = (*ztc)->tch;
+ struct zt_transcoder *tc;
+ unsigned int x;
+ unsigned int match = 0;
+
+ if (((*ztc)->srcfmt != zth->srcfmt) ||
+ ((*ztc)->dstfmt != zth->dstfmt)) {
+ /* Find new transcoder */
+ spin_lock(&translock);
+ for (tc = trans; tc && !newztc; tc = tc->next) {
+ if (!(tc->srcfmts & zth->srcfmt))
+ continue;
+
+ if (!(tc->dstfmts & zth->dstfmt))
+ continue;
+
+ match = 1;
+ 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;
+ break;
+ }
+ }
+ spin_unlock(&translock);
+
+ if (!newztc)
+ return match ? -EBUSY : -ENOSYS;
+
+ /* Move transcoder header over */
+ origztc = (*ztc);
+ (*ztc) = newztc;
+ (*ztc)->tch = origztc->tch;
+ origztc->tch = NULL;
+ (*ztc)->flags |= (origztc->flags & ~(ZT_TC_FLAG_TRANSIENT));
+ ztc_release(origztc);
+ }
+
+ /* Actually reset the transcoder channel */
+ if ((*ztc)->parent && ((*ztc)->parent->operation))
+ return (*ztc)->parent->operation((*ztc), ZT_TCOP_ALLOCATE);
+
+ return -EINVAL;
+}
+
+static int wait_busy(struct zt_transcoder_channel *ztc)
+{
+ int ret;
+
+ for (;;) {
+ if (!(ztc->tch->status & ZT_TC_FLAG_BUSY))
+ return 0;
+ if ((ret = schluffen(&ztc->ready)))
+ return ret;
+ }
+}
+
+static int zt_tc_getinfo(unsigned long data)
+{
+ struct zt_transcode_info info;
+ unsigned int x;
+ struct zt_transcoder *tc;
+
+ if (copy_from_user(&info, (struct zt_transcode_info *) data, sizeof(info)))
+ return -EFAULT;
+
+ spin_lock(&translock);
+ for (tc = trans, x = info.tcnum; tc && x; tc = tc->next, x--);
+ spin_unlock(&translock);
+
+ if (!tc)
+ return -ENOSYS;
+
+ zap_copy_string(info.name, tc->name, sizeof(info.name));
+ info.numchannels = tc->numchannels;
+ info.srcfmts = tc->srcfmts;
+ info.dstfmts = tc->dstfmts;
+
+ return copy_to_user((struct zt_transcode_info *) data, &info, sizeof(info)) ? -EFAULT : 0;
+}
+
+static int zt_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
+{
+ int op;
+ int ret;
+ struct zt_transcoder_channel *ztc = file->private_data;
+
+ if (cmd != ZT_TRANSCODE_OP)
+ return -ENOSYS;
+
+ if (get_user(op, (int *) data))
+ return -EFAULT;
+
+ if (debug)
+ printk("ZT Transcode ioctl op = %d!\n", op);
+
+ switch(op) {
+ case ZT_TCOP_GETINFO:
+ ret = zt_tc_getinfo(data);
+ break;
+ 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;
+
+ ztc->tch->status |= ZT_TC_FLAG_BUSY;
+ if (!(ret = ztc->parent->operation(ztc, ZT_TCOP_TRANSCODE))) {
+ /* Wait for busy to go away if we're not non-blocking */
+ if (!(file->f_flags & O_NONBLOCK)) {
+ if (!(ret = wait_busy(ztc)))
+ ret = ztc->errorstatus;
+ }
+ } else
+ ztc->tch->status &= ~ZT_TC_FLAG_BUSY;
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ return ret;
+}
+
+static int zt_tc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct zt_transcoder_channel *ztc = file->private_data;
+ unsigned long physical;
+ int res;
+
+ if (!ztc)
+ return -EINVAL;
+
+ /* Do not allow an offset */
+ if (vma->vm_pgoff) {
+ if (debug)
+ printk("zttranscode: Attempted to mmap with offset!\n");
+ return -EINVAL;
+ }
+
+ if ((vma->vm_end - vma->vm_start) != sizeof(struct zt_transcode_header)) {
+ if (debug)
+ printk("zttranscode: Attempted to mmap with size %d != %zd!\n", (int) (vma->vm_end - vma->vm_start), sizeof(struct zt_transcode_header));
+ return -EINVAL;
+ }
+
+ physical = (unsigned long) virt_to_phys(ztc->tch);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
+ res = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT, sizeof(struct zt_transcode_header), PAGE_SHARED);
+#else
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ res = remap_page_range(vma->vm_start, physical, sizeof(struct zt_transcode_header), PAGE_SHARED);
+ #else
+ res = remap_page_range(vma, vma->vm_start, physical, sizeof(struct zt_transcode_header), PAGE_SHARED);
+ #endif
+#endif
+ if (res) {
+ if (debug)
+ printk("zttranscode: remap failed!\n");
+ return -EAGAIN;
+ }
+
+ if (debug)
+ printk("zttranscode: successfully mapped transcoder!\n");
+
+ return 0;
+}
+
+static unsigned int zt_tc_poll(struct file *file, struct poll_table_struct *wait_table)
+{
+ struct zt_transcoder_channel *ztc = file->private_data;
+
+ if (!ztc)
+ return -EINVAL;
+
+ poll_wait(file, &ztc->ready, wait_table);
+ return ztc->tch->status & ZT_TC_FLAG_BUSY ? 0 : POLLPRI;
+}
+
+static struct file_operations __zt_transcode_fops = {
+ owner: THIS_MODULE,
+ llseek: NULL,
+ open: zt_tc_open,
+ release: zt_tc_release,
+ ioctl: zt_tc_ioctl,
+ read: NULL,
+ write: NULL,
+ poll: zt_tc_poll,
+ mmap: zt_tc_mmap,
+ flush: NULL,
+ fsync: NULL,
+ fasync: NULL,
+};
+
+static struct zt_chardev transcode_chardev = {
+ .name = "transcode",
+ .minor = 250,
+};
+
+int zttranscode_init(void)
+{
+ int res;
+
+ if (zt_transcode_fops) {
+ printk("Whoa, zt_transcode_fops already set?!\n");
+ return -EBUSY;
+ }
+
+ zt_transcode_fops = &__zt_transcode_fops;
+
+ if ((res = zt_register_chardev(&transcode_chardev)))
+ return res;
+
+ printk("Zaptel Transcoder support loaded\n");
+
+ return 0;
+}
+
+void zttranscode_cleanup(void)
+{
+ zt_unregister_chardev(&transcode_chardev);
+
+ zt_transcode_fops = NULL;
+
+ printk("Zaptel Transcoder support unloaded\n");
+}
+
+#ifdef LINUX26
+module_param(debug, int, S_IRUGO | S_IWUSR);
+#else
+MODULE_PARM(debug, "i");
+#endif
+MODULE_DESCRIPTION("Zaptel Transcoder Support");
+MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(zttranscode_init);
+module_exit(zttranscode_cleanup);