From 7e068801fbf82413ac0a5e63e586c268bd457434 Mon Sep 17 00:00:00 2001 From: tzafrir Date: Mon, 4 Feb 2008 23:00:48 +0000 Subject: Move kernel stuff to under kernel/ (merged branch /zaptel/team/tzafrir/move ) Closes issue #7117. git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@3793 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- kernel/xpp/.version | 1 + kernel/xpp/Changelog_xpp | 232 +++ kernel/xpp/Kbuild | 58 + kernel/xpp/Makefile | 7 + kernel/xpp/README.Astribank | 1131 ++++++++++++++ kernel/xpp/calibrate_slics | 308 ++++ kernel/xpp/card_bri.c | 1731 +++++++++++++++++++++ kernel/xpp/card_bri.h | 31 + kernel/xpp/card_fxo.c | 1218 +++++++++++++++ kernel/xpp/card_fxo.h | 45 + kernel/xpp/card_fxs.c | 1620 +++++++++++++++++++ kernel/xpp/card_fxs.h | 45 + kernel/xpp/card_global.c | 342 ++++ kernel/xpp/card_global.h | 94 ++ kernel/xpp/card_pri.c | 1673 ++++++++++++++++++++ kernel/xpp/card_pri.h | 32 + kernel/xpp/firmwares/FPGA_1141.hex | 658 ++++++++ kernel/xpp/firmwares/FPGA_1151.hex | 664 ++++++++ kernel/xpp/firmwares/FPGA_FXS.hex | 648 ++++++++ kernel/xpp/firmwares/LICENSE.firmware | 37 + kernel/xpp/firmwares/README | 19 + kernel/xpp/firmwares/USB_FW.hex | 223 +++ kernel/xpp/init_card_3_29 | 189 +++ kernel/xpp/init_card_4_29 | 165 ++ kernel/xpp/init_card_6_29 | 434 ++++++ kernel/xpp/init_card_7_29 | 434 ++++++ kernel/xpp/init_card_9_29 | 358 +++++ kernel/xpp/param_doc | 40 + kernel/xpp/parport_debug.c | 113 ++ kernel/xpp/parport_debug.h | 31 + kernel/xpp/utils/Makefile | 136 ++ kernel/xpp/utils/astribank_hook | 53 + kernel/xpp/utils/example_default_zaptel | 31 + kernel/xpp/utils/fpga_load.8 | 86 ++ kernel/xpp/utils/fpga_load.c | 1003 ++++++++++++ kernel/xpp/utils/genzaptelconf | 1195 ++++++++++++++ kernel/xpp/utils/genzaptelconf.8 | 326 ++++ kernel/xpp/utils/hexfile.c | 567 +++++++ kernel/xpp/utils/hexfile.h | 123 ++ kernel/xpp/utils/lszaptel | 108 ++ kernel/xpp/utils/print_modes.c | 44 + kernel/xpp/utils/test_parse.c | 35 + kernel/xpp/utils/xpp.rules | 13 + kernel/xpp/utils/xpp_blink | 130 ++ kernel/xpp/utils/xpp_fxloader | 245 +++ kernel/xpp/utils/xpp_fxloader.usermap | 10 + kernel/xpp/utils/xpp_modprobe | 10 + kernel/xpp/utils/xpp_sync | 226 +++ kernel/xpp/utils/zapconf | 576 +++++++ kernel/xpp/utils/zaptel-helper | 401 +++++ kernel/xpp/utils/zaptel_drivers | 9 + kernel/xpp/utils/zaptel_hardware | 164 ++ kernel/xpp/utils/zconf/Zaptel.pm | 68 + kernel/xpp/utils/zconf/Zaptel/Chans.pm | 187 +++ kernel/xpp/utils/zconf/Zaptel/Config/Defaults.pm | 54 + kernel/xpp/utils/zconf/Zaptel/Hardware.pm | 60 + kernel/xpp/utils/zconf/Zaptel/Hardware/PCI.pm | 204 +++ kernel/xpp/utils/zconf/Zaptel/Hardware/USB.pm | 116 ++ kernel/xpp/utils/zconf/Zaptel/Span.pm | 160 ++ kernel/xpp/utils/zconf/Zaptel/Utils.pm | 52 + kernel/xpp/utils/zconf/Zaptel/Xpp.pm | 183 +++ kernel/xpp/utils/zconf/Zaptel/Xpp/Line.pm | 59 + kernel/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm | 117 ++ kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm | 123 ++ kernel/xpp/utils/zt_registration | 125 ++ kernel/xpp/xbus-core.c | 1798 ++++++++++++++++++++++ kernel/xpp/xbus-core.h | 278 ++++ kernel/xpp/xbus-pcm.c | 1168 ++++++++++++++ kernel/xpp/xbus-pcm.h | 106 ++ kernel/xpp/xbus-sysfs.c | 273 ++++ kernel/xpp/xdefs.h | 131 ++ kernel/xpp/xframe_queue.c | 258 ++++ kernel/xpp/xframe_queue.h | 34 + kernel/xpp/xpd.h | 223 +++ kernel/xpp/xpp_log.h | 52 + kernel/xpp/xpp_usb.c | 1085 +++++++++++++ kernel/xpp/xpp_zap.c | 1049 +++++++++++++ kernel/xpp/xpp_zap.h | 49 + kernel/xpp/xproto.c | 446 ++++++ kernel/xpp/xproto.h | 306 ++++ kernel/xpp/zap_debug.c | 91 ++ kernel/xpp/zap_debug.h | 190 +++ 82 files changed, 27117 insertions(+) create mode 100644 kernel/xpp/.version create mode 100644 kernel/xpp/Changelog_xpp create mode 100644 kernel/xpp/Kbuild create mode 100644 kernel/xpp/Makefile create mode 100644 kernel/xpp/README.Astribank create mode 100755 kernel/xpp/calibrate_slics create mode 100644 kernel/xpp/card_bri.c create mode 100644 kernel/xpp/card_bri.h create mode 100644 kernel/xpp/card_fxo.c create mode 100644 kernel/xpp/card_fxo.h create mode 100644 kernel/xpp/card_fxs.c create mode 100644 kernel/xpp/card_fxs.h create mode 100644 kernel/xpp/card_global.c create mode 100644 kernel/xpp/card_global.h create mode 100644 kernel/xpp/card_pri.c create mode 100644 kernel/xpp/card_pri.h create mode 100644 kernel/xpp/firmwares/FPGA_1141.hex create mode 100644 kernel/xpp/firmwares/FPGA_1151.hex create mode 100644 kernel/xpp/firmwares/FPGA_FXS.hex create mode 100644 kernel/xpp/firmwares/LICENSE.firmware create mode 100644 kernel/xpp/firmwares/README create mode 100644 kernel/xpp/firmwares/USB_FW.hex create mode 100755 kernel/xpp/init_card_3_29 create mode 100755 kernel/xpp/init_card_4_29 create mode 100755 kernel/xpp/init_card_6_29 create mode 100755 kernel/xpp/init_card_7_29 create mode 100755 kernel/xpp/init_card_9_29 create mode 100755 kernel/xpp/param_doc create mode 100644 kernel/xpp/parport_debug.c create mode 100644 kernel/xpp/parport_debug.h create mode 100644 kernel/xpp/utils/Makefile create mode 100755 kernel/xpp/utils/astribank_hook create mode 100644 kernel/xpp/utils/example_default_zaptel create mode 100644 kernel/xpp/utils/fpga_load.8 create mode 100644 kernel/xpp/utils/fpga_load.c create mode 100755 kernel/xpp/utils/genzaptelconf create mode 100644 kernel/xpp/utils/genzaptelconf.8 create mode 100644 kernel/xpp/utils/hexfile.c create mode 100644 kernel/xpp/utils/hexfile.h create mode 100755 kernel/xpp/utils/lszaptel create mode 100644 kernel/xpp/utils/print_modes.c create mode 100644 kernel/xpp/utils/test_parse.c create mode 100644 kernel/xpp/utils/xpp.rules create mode 100755 kernel/xpp/utils/xpp_blink create mode 100644 kernel/xpp/utils/xpp_fxloader create mode 100644 kernel/xpp/utils/xpp_fxloader.usermap create mode 100644 kernel/xpp/utils/xpp_modprobe create mode 100755 kernel/xpp/utils/xpp_sync create mode 100755 kernel/xpp/utils/zapconf create mode 100644 kernel/xpp/utils/zaptel-helper create mode 100755 kernel/xpp/utils/zaptel_drivers create mode 100755 kernel/xpp/utils/zaptel_hardware create mode 100644 kernel/xpp/utils/zconf/Zaptel.pm create mode 100644 kernel/xpp/utils/zconf/Zaptel/Chans.pm create mode 100644 kernel/xpp/utils/zconf/Zaptel/Config/Defaults.pm create mode 100644 kernel/xpp/utils/zconf/Zaptel/Hardware.pm create mode 100644 kernel/xpp/utils/zconf/Zaptel/Hardware/PCI.pm create mode 100644 kernel/xpp/utils/zconf/Zaptel/Hardware/USB.pm create mode 100644 kernel/xpp/utils/zconf/Zaptel/Span.pm create mode 100644 kernel/xpp/utils/zconf/Zaptel/Utils.pm create mode 100644 kernel/xpp/utils/zconf/Zaptel/Xpp.pm create mode 100644 kernel/xpp/utils/zconf/Zaptel/Xpp/Line.pm create mode 100644 kernel/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm create mode 100644 kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm create mode 100755 kernel/xpp/utils/zt_registration create mode 100644 kernel/xpp/xbus-core.c create mode 100644 kernel/xpp/xbus-core.h create mode 100644 kernel/xpp/xbus-pcm.c create mode 100644 kernel/xpp/xbus-pcm.h create mode 100644 kernel/xpp/xbus-sysfs.c create mode 100644 kernel/xpp/xdefs.h create mode 100644 kernel/xpp/xframe_queue.c create mode 100644 kernel/xpp/xframe_queue.h create mode 100644 kernel/xpp/xpd.h create mode 100644 kernel/xpp/xpp_log.h create mode 100644 kernel/xpp/xpp_usb.c create mode 100644 kernel/xpp/xpp_zap.c create mode 100644 kernel/xpp/xpp_zap.h create mode 100644 kernel/xpp/xproto.c create mode 100644 kernel/xpp/xproto.h create mode 100644 kernel/xpp/zap_debug.c create mode 100644 kernel/xpp/zap_debug.h (limited to 'kernel/xpp') diff --git a/kernel/xpp/.version b/kernel/xpp/.version new file mode 100644 index 0000000..d658f52 --- /dev/null +++ b/kernel/xpp/.version @@ -0,0 +1 @@ +trunk-r5254 diff --git a/kernel/xpp/Changelog_xpp b/kernel/xpp/Changelog_xpp new file mode 100644 index 0000000..31684e0 --- /dev/null +++ b/kernel/xpp/Changelog_xpp @@ -0,0 +1,232 @@ +Thu Jan 10 2008 Oron Peled - 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 - 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 - 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 - 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 - 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_detect 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 - 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 - 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 - 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 - 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 - 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 '' (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 - 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 - 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 - 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 - 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 - 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 - xpp.r3517 + * genzaptelconf now uses ls for FXS lines by default . + * World-readable kernel parameters. + +Thu, 22 Feb 2007 Tzafrir Cohen - 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 - 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/kernel/xpp/Kbuild b/kernel/xpp/Kbuild new file mode 100644 index 0000000..9ec225f --- /dev/null +++ b/kernel/xpp/Kbuild @@ -0,0 +1,58 @@ +ifdef SUBDIRS + ZAPTEL_DIR = $(SUBDIRS) +else + ZAPTEL_DIR = $(M) +endif + +EXTRA_CFLAGS = $(XPP_LOCAL_CFLAGS) \ + -I$(ZAPTEL_DIR) \ + -DDEBUG \ + -DPOLL_DIGITAL_INPUTS \ + -DWITH_ECHO_SUPPRESSION \ + -DDEBUG_PCMTX \ + -DPROTOCOL_DEBUG \ + -g + # + +ifneq (,$(shell grep -w echo_can_state_t $(ZAPTEL_DIR)/zaptel.h)) +EXTRA_CFLAGS += -DZAPTEL_EC_TYPEDEF +endif + +obj-m += xpp.o xpd_fxs.o xpd_fxo.o xpd_pri.o + +HAS_BRISTUFF := $(shell cpp $(CPPFLAGS) -dM $(ZAPTEL_DIR)/zconfig.h | sed -n 's/^.*CONFIG_ZAPATA_BRI_DCHANS/y/p') + +# 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/kernel/xpp/Makefile b/kernel/xpp/Makefile new file mode 100644 index 0000000..00fc5ee --- /dev/null +++ b/kernel/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/kernel/xpp/README.Astribank b/kernel/xpp/README.Astribank new file mode 100644 index 0000000..342c6a9 --- /dev/null +++ b/kernel/xpp/README.Astribank @@ -0,0 +1,1131 @@ +Xorcom Astribank Documentation +============================== +Xorcom Team +$Revision$, $Date$ + +This file documents the Zaptel drivers for the Xorcom Channel Bank. +The drivers reside in a separate subdirectory, 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 +~~~~~~~~~~~~~~~~ +On zaptel 1.2 you will need to run the following extra step to build the +Astribank drivers, apart from the standard 'make': + + make -C xpp/utils install + +In order to build the user space utilities, you will need the libusb-dev +package on Debian (and derivatives like Ubuntu) or libusb-devel on RedHat +(and derivatives like CentOS/Trixbox). + +Apart from the standard 'make install' in the zaptel directory, +run: + + make -C xpp/utils install + +Though this should be done automatically on zaptel >= 1.4.1 . + +PRI Port Setup +~~~~~~~~~~~~~~ +A port in the PRI module can be either E1 (default) or T1. It can also be +either "TE" or "NT". + +TE:: + Use the bottom port (green LED) and don't invert any wiring. Hint to + higher layers that this will be the TE (CPE) 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 (Net) + side of the connection. + +The value XPP_PRI_SETUP in the init configuration file (see example +below) can be used to change those defaults. This value is a +whitelist-separated list of conditions. When a port is initialized it +checks those conditions and uses the firs 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. + + +Sample Configurations +--------------------- +We generally recommend to generate the configuration by using utility +genzaptelconf. The following reference configuration will work for a +system where Astribank devices are used. + + +[[sect-default]] +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 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 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 = bri_net_ptmp + ;signalling = bri_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 = bri_net_ptmp + ;signalling = bri_net + context = from-internal + group = 2,12 + channel => 25-47 + + group = 2,14 + channel => 73-95 + + +Please check, that the mailbox and callerid parameters generated by +genzaptelconf are good for you and change them if necessary. + + +If you have Astribank device with 8 FXS and 8FXO ports connected and set +up, then the Zaptel channels will be allocated as the following: + + root@rapid:~# cat /proc/zaptel/* + Span 1: XBUS-00/XPD-00 "Xorcom XPD #00/00: FXS" + + 1 XPP_FXS/00/00/0 FXOLS (In use) + 2 XPP_FXS/00/00/1 FXOLS (In use) + 3 XPP_FXS/00/00/2 FXOLS (In use) + 4 XPP_FXS/00/00/3 FXOLS (In use) + 5 XPP_FXS/00/00/4 FXOLS (In use) + 6 XPP_FXS/00/00/5 FXOLS (In use) + 7 XPP_FXS/00/00/6 FXOLS (In use) + 8 XPP_FXS/00/00/7 FXOLS (In use) + 9 XPP_OUT/00/00/8 FXOLS (In use) (no pcm) + 10 XPP_OUT/00/00/9 FXOLS (In use) (no pcm) + 11 XPP_IN/00/00/10 FXOLS (In use) (no pcm) + 12 XPP_IN/00/00/11 FXOLS (In use) (no pcm) + 13 XPP_IN/00/00/12 FXOLS (In use) (no pcm) + 14 XPP_IN/00/00/13 FXOLS (In use) (no pcm) + Span 2: XBUS-00/XPD-01 "Xorcom XPD #00/01: FXO" (MASTER) + + 15 XPP_FXO/00/01/0 FXSKS (In use) + 16 XPP_FXO/00/01/1 FXSKS (In use) (no pcm) + 17 XPP_FXO/00/01/2 FXSKS (In use) (no pcm) + 18 XPP_FXO/00/01/3 FXSKS (In use) (no pcm) + 19 XPP_FXO/00/01/4 FXSKS (In use) (no pcm) + 20 XPP_FXO/00/01/5 FXSKS (In use) (no pcm) + 21 XPP_FXO/00/01/6 FXSKS (In use) (no pcm) + 22 XPP_FXO/00/01/7 FXSKS (In use) (no pcm) + + + +/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. +----------------------------------------------------------- + + + + +Troubleshhoting +--------------- +The following commands provide useful information for debugging: + +* 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. + - 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. + +* 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. + +* Check the Zaptel 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) + +* Check the Asterisk 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: + (a) chan_zap.so is not even built. Check if the file exists: + + ls -l /usr/lib/asterisk/modules/chan_zap.so + + (b) 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` + + +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). + + +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 hotplugging 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 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 +hardwriting 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 + +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 initializaton +of an FXS XPD may take a few seconds. + + +Astribank in Sysfs +^^^^^^^^^^^^^^^^^^ +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. + + +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 unregisteres 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. Registeration should +generally always succeed. Unregistration may fail if a span is in use. + +You may choose to register the XPDs in Zaptel automatically, in order to +allow finer control of the process. 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 dialtone 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 toplevel 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. +(Note that the details of this interface are still potentially subject to +changes) + + +/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: + +:: + Make the Astribank XBUS- the sync source for other Astribanks. + +ZAPTEL:: + Make the astribanks synchronize with the Zaptel timing master span. + You probably ned 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 therms of Zaptel) there is folder /proc/XBUS-nn/XPD-mm. + + +/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 convient 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_*). + + +/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. + + +/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 recieved channels. + +NOLOCALLOOP:: + Ends local loop mode. + +Normally those are set by the PRI initialization script . See the +definition of XPP_PRI_SETUP in xref:sect-default[the sample Zaptel init +configuration file] . + +There are a bunch of other status files under /proc/xpp/. + + +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 systes with + multiple Astribanks. + +print_dbg (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. Tend 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 - procfs interface related messages. + * 64 - REGS - Reading and writing to chip registers. The driver produces + a lot of messages when the option is enabled. + + For example, + + echo 33 >/sys/modules/xpp/parameters/print_dbg + + 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 Wainting 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 or 0 + to disable. 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/kernel/xpp/calibrate_slics b/kernel/xpp/calibrate_slics new file mode 100755 index 0000000..c1e6064 --- /dev/null +++ b/kernel/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(){ + #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 60 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/kernel/xpp/card_bri.c b/kernel/xpp/card_bri.c new file mode 100644 index 0000000..998d22a --- /dev/null +++ b/kernel/xpp/card_bri.c @@ -0,0 +1,1731 @@ +/* + * Written by Oron Peled + * 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 +#include +#include +#include +#include "xpd.h" +#include "xproto.h" +#include "xpp_zap.h" +#include "card_bri.h" +#include "zap_debug.h" +#include "xpd.h" +#include "xbus-core.h" + +static const char rcsid[] = "$Id$"; + +#ifndef CONFIG_ZAPATA_BRI_DCHANS +#error CONFIG_ZAPATA_BRI_DCHANS is not defined +#endif + +DEF_PARM(int, print_dbg, 0, 0644, "Print DBG statements"); /* must be before zap_debug.h */ +DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in milliseconds (0 - disable)"); +DEF_PARM_BOOL(nt_keepalive, 1, 0644, "Force BRI_NT to keep trying connection"); +#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 + +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(xpd_type_t xpd_type, 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(xpd_type == XPD_TYPE_BRI_TE) { + if ((state < ST_RESET) || (state > ST_TE_LOST_FRAMING)) + p = "TE ???"; + else + p = te_names[state]; + } else { + if ((state < ST_RESET) || (state > ST_NT_DEACTIVTING)) + p = "NT ???"; + else + p = nt_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 TIMER_T1_MAX 2500 +#define HFC_TIMER_T3 8000 /* 8s activation timer T3 */ +#define HFC_TIMER_T4 500 /* 500ms deactivation timer T4 */ +#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 + +#define IS_NT(xpd) ((xpd)->type == XPD_TYPE_BRI_NT) + +/* 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 proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data); +static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, 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" + +#define VALID_CHIPSEL(x) ((x) == 0) + +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 *regfile; + 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 activation */ + int t4; /* timer 4 for deactivation */ + 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; + + reg_cmd_t requested_reply; + reg_cmd_t last_reply; + 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_NT); +static xproto_table_t PROTO_TABLE(BRI_TE); + + +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 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"); +} + +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 xpd_activation(xpd_t *xpd, bool on) +{ + struct BRI_priv_data *priv; + xbus_t *xbus; + + BUG_ON(!xpd); + priv = xpd->priv; + BUG_ON(!priv); + xbus = xpd->xbus; + XPD_DBG(SIGNAL, xpd, "%s\n", (on)?"ON":"OFF"); + switch(xpd->type) { + case XPD_TYPE_BRI_TE: + if(on) { + XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_TE\n"); + set_bit(HFC_L1_ACTIVATING, &priv->l1_flags); + write_state_register(xpd, STA_ACTIVATE); + priv->t3 = HFC_TIMER_T3; + } else { + XPD_DBG(SIGNAL, xpd, "HFC_L1_FORCE_DEACTIVATE_TE\n"); + write_state_register(xpd, STA_DEACTIVATE); + } + break; + case XPD_TYPE_BRI_NT: + if(on) { + XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_NT\n"); + priv->t1 = TIMER_T1_MAX; + set_bit(HFC_L1_ACTIVATING, &priv->l1_flags); + write_state_register(xpd, STA_ACTIVATE | V_SU_SET_G2_G3); + } else { + XPD_DBG(SIGNAL, xpd, "HFC_L1_DEACTIVATE_NT\n"); + write_state_register(xpd, STA_DEACTIVATE); + } + break; + default: + XPD_ERR(xpd, "%s: Bad xpd type %d\n", __FUNCTION__, xpd->type); + BUG(); + } +} + + +/* + * 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(print_dbg) + 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; +} + +static int send_bri_multibyte(xpd_t *xpd, byte *buf, int len, bool eoftx) +{ + xbus_t *xbus = xpd->xbus; + xframe_t *xframe; + xpacket_t *pack; + reg_cmd_t *reg_cmd; + int ret; + + BUG_ON(len < 0); + /* + * 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) { + XPD_ERR(xpd, "%s: len=%d is too long. dropping.\n", __FUNCTION__, len); + return -EINVAL; + } + XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->xbus_idx); + reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd); + reg_cmd->bytes = len; + reg_cmd->eoframe = eoftx; + reg_cmd->multibyte = 1; + if(len > 0) { + memcpy(REG_XDATA(reg_cmd), (byte *)buf, len); + } else { + XPD_DBG(REGS, xpd, "Magic Packet (eoftx=%d)\n", eoftx); + } +#ifdef XPP_DEBUGFS + xbus_log(xbus, xpd, 1, reg_cmd, sizeof(reg_cmd_t)); /* 1 = TX */ +#else + if(print_dbg) + dump_xframe("SEND_BRI_MULTI", xbus, xframe); +#endif + ret = send_cmd_frame(xbus, xframe); + if(ret < 0) + XPD_NOTICE(xpd, "%s: failed sending xframe\n", __FUNCTION__); + 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(!IS_NT(xpd)) { + static int rate_limit; + + if (priv->t3 > HFC_TIMER_OFF) { + /* timer expired ? */ + if (--priv->t3 == 0) { + if ((rate_limit % 1003) >= 5) + XPD_DBG(SIGNAL, xpd, "T3 expired\n"); + priv->t3 = HFC_TIMER_OFF; + clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags); + xpd_activation(xpd, 0); /* Deactivate TE */ + } + } + if (priv->t4 > HFC_TIMER_OFF) { + /* timer expired ? */ + if (--priv->t4 == 0) { + if ((rate_limit % 1003) >= 5) + XPD_DBG(SIGNAL, xpd, "T4 expired\n"); + priv->t4 = HFC_TIMER_OFF; + } + } + rate_limit++; + } + 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"); + xpd_activation(xpd, 1); + return 0; + } + if(print_dbg) + dump_dchan_packet(xpd, 1, priv->dchan_tbuf, len); + if(eoframe) + priv->txframe_begin = 1; + else + priv->txframe_begin = 0; + ret = send_bri_multibyte(xpd, priv->dchan_tbuf, len, eoframe); + 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 xpd_t *BRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, byte revision) +{ + 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 = (proto_table == &PROTO_TABLE(BRI_NT)) ? TO_PHONE : TO_PSTN; + xpd->revision = revision; + xpd->type_name = proto_table->name; + return xpd; +} + +static void clean_proc(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->regfile) { + XPD_DBG(PROC, xpd, "Removing registers file\n"); + priv->regfile->data = NULL; + remove_proc_entry(PROC_REGISTER_FNAME, xpd->proc_xpd_dir); + } + if(priv->bri_info) { + XPD_DBG(PROC, xpd, "Removing xpd BRI_INFO file\n"); + remove_proc_entry(PROC_BRI_INFO_FNAME, xpd->proc_xpd_dir); + } +#endif +} + +static int BRI_card_init(xbus_t *xbus, xpd_t *xpd) +{ + struct BRI_priv_data *priv; + int ret = 0; + + BUG_ON(!xpd); + XPD_DBG(GENERAL, xpd, "\n"); + priv = xpd->priv; +#ifdef CONFIG_PROC_FS + XPD_DBG(PROC, xpd, "Creating BRI_INFO file\n"); + 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); + ret = -ENOENT; + goto err; + } + priv->bri_info->owner = THIS_MODULE; + XPD_DBG(PROC, xpd, "Creating registers file\n"); + priv->regfile = create_proc_entry(PROC_REGISTER_FNAME, 0644, xpd->proc_xpd_dir); + if(!priv->regfile) { + XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_REGISTER_FNAME); + goto err; + } + priv->regfile->owner = THIS_MODULE; + priv->regfile->write_proc = proc_xpd_register_write; + priv->regfile->read_proc = proc_xpd_register_read; + priv->regfile->data = xpd; +#endif + priv->t1 = HFC_TIMER_OFF; + ret = run_initialize_registers(xpd); + if(ret < 0) + goto err; + XPD_DBG(PROC, xpd, "done\n"); + priv->initialized = 1; + return 0; +err: + clean_proc(xbus, xpd); + XPD_ERR(xpd, "Failed initializing registers (%d)\n", ret); + return ret; +} + +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"); + clean_proc(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; + } + 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->xproto->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); + } +} + +/* 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, 0, 0, 0, A_SU_RD_STA, 0, 0, 0); + + 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"); + xpd_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); + dchan_state(xpd, 0); + } + handle_leds(xbus, xpd); + tx_dchan(xpd); + /* Detect T1 timer expiry on NT */ + if(IS_NT(xpd) && !nt_keepalive) { + if (priv->t1 > HFC_TIMER_OFF) { + if (--priv->t1 == 0) { + XPD_DBG(SIGNAL, xpd, "T1 Expired. Deactivate NT\n"); + priv->t1 = HFC_TIMER_OFF; + clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags); + write_state_register(xpd, STA_DEACTIVATE); + } + } + } + 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); + write_state_register(xpd, 0); /* Enable L1 state machine */ + xpd_activation(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); + if(IS_NT(xpd)) + xpd_activation(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) +{ + BUG_ON(!xpd); + XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF"); + xpd_activation(xpd, on); + return 0; +} + +static /* 0x0F */ HOSTCMD(BRI, RING, lineno_t chan, bool on) +{ + XPD_ERR(xpd, "%s: Unsupported\n", __FUNCTION__); + return -ENOSYS; +} + +static /* 0x0F */ HOSTCMD(BRI, RELAY_OUT, byte which, bool on) +{ + XPD_ERR(xpd, "%s: Unsupported\n", __FUNCTION__); + return -ENOSYS; +} + +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, + 0, /* chipsel */ + 1, /* writing */ + 0, /* do_subreg */ + A_SU_WR_STA, /* regnum */ + 0, /* subreg */ + value, /* data_low */ + 0 /* data_high */ + ); + 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; + priv->reg30_ticks = 0; + priv->reg30_good = 1; + if((!IS_NT(xpd) && new_state.bits.v_su_sta == ST_TE_ACTIVATED) || + (IS_NT(xpd) && new_state.bits.v_su_sta == ST_NT_ACTIVATED)) { + if(!priv->layer1_up) { + layer1_state(xpd, 1); + update_xpd_status(xpd, ZT_ALARM_NONE); + } + } else { + /* + * Layer 1 disconnected + */ + if(priv->layer1_up) { + layer1_state(xpd, 0); + dchan_state(xpd, 0); + } + /* + * Do NOT notify Zaptel about the disconnection. + * If we do, Asterisk stops transmitting on the D-channel and + * we can't reactivate layer-1. + * Without the notification, Asterisk thinks that we are active + * (although the PSTN stopped layer-1) and on call setup, sends + * us D-channel data, which triggers the layer-1 activation. + */ +#if 0 + update_xpd_status(xpd, ZT_ALARM_RED); +#endif + } + if (priv->state_register.bits.v_su_sta == new_state.bits.v_su_sta) + return; /* same same */ + DBG(SIGNAL, "%02X ---> %02X\n", priv->state_register.reg, reg_x30); + XPD_DBG(SIGNAL, xpd, "%s%i\n", IS_NT(xpd)?"G":"F", new_state.bits.v_su_sta); + + if(!IS_NT(xpd)) { + /* disable T3 ? */ + if ((new_state.bits.v_su_sta <= ST_TE_DEACTIVATED) || (new_state.bits.v_su_sta >= ST_TE_ACTIVATED)) { + XPD_DBG(SIGNAL, xpd, "Disable T3 ?\n"); + priv->t3 = HFC_TIMER_OFF; + } + switch (new_state.bits.v_su_sta) { + case ST_TE_DEACTIVATED: /* F3 */ + XPD_DBG(SIGNAL, xpd, "State ST_TE_DEACTIVATED (F3)\n"); + if (test_and_clear_bit(HFC_L1_ACTIVATED, &priv->l1_flags)) + priv->t4 = HFC_TIMER_T4; + break; + case ST_TE_SIGWAIT: /* F4 */ + XPD_DBG(SIGNAL, xpd, "State ST_TE_SIGWAIT (F4)\n"); + break; + case ST_TE_IDENT: /* F5 */ + XPD_DBG(SIGNAL, xpd, "State ST_TE_IDENT (F5)\n"); + break; + case ST_TE_SYNCED: /* F6 */ + XPD_DBG(SIGNAL, xpd, "State ST_TE_SYNCED (F6)\n"); + break; + case ST_TE_ACTIVATED: /* F7 */ + XPD_DBG(SIGNAL, xpd, "State ST_TE_ACTIVATED (F7)\n"); + if (priv->t4 > HFC_TIMER_OFF) + priv->t4 = HFC_TIMER_OFF; + clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags); + set_bit(HFC_L1_ACTIVATED, &priv->l1_flags); + 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"); + priv->t4 = HFC_TIMER_OFF; + break; + default: + XPD_NOTICE(xpd, "Bad TE state: %d\n", new_state.bits.v_su_sta); + break; + } + + } else if(IS_NT(xpd)) { + 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); + priv->t1 = HFC_TIMER_OFF; + break; + case ST_NT_ACTIVATING: /* G2 */ + XPD_DBG(SIGNAL, xpd, "State ST_NT_ACTIVATING (G2)\n"); + xpd_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); + priv->t1 = HFC_TIMER_OFF; + break; + case ST_NT_DEACTIVTING: /* G4 */ + XPD_DBG(SIGNAL, xpd, "State ST_NT_DEACTIVTING (G4)\n"); + priv->t1 = HFC_TIMER_OFF; + break; + default: + XPD_NOTICE(xpd, "Bad NT state: %d\n", new_state.bits.v_su_sta); + break; + } + } else + XPD_ERR(xpd, "%s: Unknown xpd type %d\n", __FUNCTION__, xpd->type); + 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; + int ret; + + spin_lock_irqsave(&xpd->lock, flags); + priv = xpd->priv; + BUG_ON(!priv); + if(REG_FIELD(info, do_subreg)) { + XPD_DBG(REGS, xpd, "RS %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)); + } + if(info->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(&priv->requested_reply, regnum) == REG_FIELD(info, regnum) && + REG_FIELD(&priv->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) && + REG_FIELD(&priv->requested_reply, subreg) == REG_FIELD(info, subreg)) { + priv->last_reply = *info; + } + +end: + spin_unlock_irqrestore(&xpd->lock, flags); + return 0; +} + +static xproto_table_t PROTO_TABLE(BRI_NT) = { + .owner = THIS_MODULE, + .entries = { + /* Table Card Opcode */ + }, + .name = "BRI_NT", + .type = XPD_TYPE_BRI_NT, + .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, + + .RING = XPROTO_CALLER(BRI, RING), + .RELAY_OUT = XPROTO_CALLER(BRI, RELAY_OUT), + .XPD_STATE = XPROTO_CALLER(BRI, XPD_STATE), + }, + .packet_is_valid = bri_packet_is_valid, + .packet_dump = bri_packet_dump, +}; + +static xproto_table_t PROTO_TABLE(BRI_TE) = { + .owner = THIS_MODULE, + .entries = { + /* Table Card Opcode */ + }, + .name = "BRI_TE", + .type = XPD_TYPE_BRI_TE, + .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, + + .RING = XPROTO_CALLER(BRI, RING), + .RELAY_OUT = XPROTO_CALLER(BRI, RELAY_OUT), + .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_nt = NULL; + const xproto_entry_t *xe_te = NULL; + // DBG(GENERAL, "\n"); + xe_nt = xproto_card_entry(&PROTO_TABLE(BRI_NT), XPACKET_OP(pack)); + xe_te = xproto_card_entry(&PROTO_TABLE(BRI_TE), XPACKET_OP(pack)); + return xe_nt != NULL || xe_te != 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(xpd->type, 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); + 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; +} + +/* + * + * Direct/Indirect + * | + * | Reg# + * | | + * | | Data (only in Write) + * | | | + * | | +-+-+ + * v v v v + * FF WD 06 01 05 + * ^ ^ + * | | + * | Write/Read + * | + * Chan# + * + */ +static int handle_register_command(xpd_t *xpd, char *cmdline) +{ + unsigned chipsel; + unsigned data = 0; + unsigned xdata1 = 0; + unsigned xdata2 = 0; + char op; /* [W]rite, [R]ead */ + char reg_type; /* [D]irect, [S]ubregister */ + int reg_num; + int subreg; + int elements; + bool writing; + char *p; + reg_cmd_t regcmd; + xbus_t *xbus; + int ret = -EINVAL; + struct BRI_priv_data *priv; + byte buf[MAX_PROC_WRITE]; + + BUG_ON(!xpd); + xbus = xpd->xbus; + BUG_ON(!xbus); + priv = xpd->priv; + BUG_ON(!priv); + if((p = strchr(cmdline, '#')) != NULL) /* Truncate comments */ + *p = '\0'; + if((p = strchr(cmdline, ';')) != NULL) /* Truncate comments */ + *p = '\0'; + for(p = cmdline; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */ + ; + if(*p == '\0') + return 0; + + if(!XBUS_GET(xbus)) { + XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down.\n"); + return -EBUSY; + } + memset(buf, 0, MAX_PROC_WRITE); + elements = sscanf(cmdline, "%d %c%c %x %x %x %x %x", + &chipsel, + &op, ®_type, ®_num, + &subreg, + &data, &xdata1, &xdata2); + XPD_DBG(PROC, xpd, "'%s': %d %c%c %02X %02X %02X\n", cmdline, chipsel, op, reg_type, reg_num, subreg, data); + if(elements < 3) { // At least: chipsel, op, reg_type, reg_num + ERR("Not enough arguments: (%d args) '%s'\n", elements, cmdline); + goto out; + } + if(!VALID_CHIPSEL(chipsel)) { + ERR("Bad chip select number: %d\n", chipsel); + goto out; + } + REG_FIELD(®cmd, chipsel) = chipsel; + switch(op) { + case 'W': + writing = 1; + break; + case 'R': + writing = 0; + break; + default: + ERR("Unkown operation type '%c'\n", op); + goto out; + } + if( + (op == 'W' && reg_type == 'D' && elements != 5) || + (op == 'W' && reg_type == 'S' && elements != 6) || + (op == 'R' && reg_type == 'D' && elements != 4) || + (op == 'R' && reg_type == 'S' && elements != 4) + ) { + ERR("Bad number of elements: '%s' (%d elements): %d %c%c %02X %02X %02X\n", + cmdline, elements, + chipsel, op, reg_type, reg_num, subreg, data); + goto out; + } + switch(reg_type) { + case 'S': + REG_FIELD(®cmd, do_subreg) = 1; + REG_FIELD(®cmd, regnum) = reg_num; + REG_FIELD(®cmd, subreg) = subreg; + REG_FIELD(®cmd, data_low) = data; + break; + case 'D': + REG_FIELD(®cmd, do_subreg) = 0; + REG_FIELD(®cmd, regnum) = reg_num; + REG_FIELD(®cmd, subreg) = 0; + REG_FIELD(®cmd, data_low) = subreg; + break; + case 'M': /* Multi without eoftx */ + case 'm': /* Multi with eoftx */ + if(!writing) { + ERR("Read multibyte is not implemented\n"); + goto out; + } + elements -= 3; + REG_XDATA(®cmd)[0] = reg_num; + REG_XDATA(®cmd)[1] = subreg; + REG_XDATA(®cmd)[2] = data; + REG_XDATA(®cmd)[3] = xdata1; + REG_XDATA(®cmd)[4] = xdata2; + ret = send_bri_multibyte(xpd, REG_XDATA(®cmd), elements, (reg_type == 'm')); + goto out; + default: + ERR("Unkown register type '%c'\n", reg_type); + goto out; + } + regcmd.bytes = sizeof(regcmd) - 1; + REG_FIELD(®cmd, read_request) = writing; + REG_FIELD(®cmd, data_high) = 0; + priv->requested_reply = regcmd; + if(print_dbg) + dump_reg_cmd("BRI", ®cmd, 1); + ret = xpp_register_request(xpd->xbus, xpd, + REG_FIELD(®cmd, chipsel), + writing, + REG_FIELD(®cmd, do_subreg), + REG_FIELD(®cmd, regnum), + REG_FIELD(®cmd, subreg), + REG_FIELD(®cmd, data_low), + REG_FIELD(®cmd, data_high)); +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 = handle_register_command(xpd, buf); + if(ret < 0) + return ret; + msleep(1); + } + return count; +} + + +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; + struct BRI_priv_data *priv; + + if(!xpd) + return -ENODEV; + priv = xpd->priv; + BUG_ON(!priv); + spin_lock_irqsave(&xpd->lock, flags); + info = &priv->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", + REG_FIELD(info, chipsel), + 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", + REG_FIELD(info, chipsel), + 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; +} + +int __init card_bri_startup(void) +{ + DBG(GENERAL, "\n"); + + INFO("revision %s\n", XPP_VERSION); + xproto_register(&PROTO_TABLE(BRI_NT)); + xproto_register(&PROTO_TABLE(BRI_TE)); + return 0; +} + +void __exit card_bri_cleanup(void) +{ + DBG(GENERAL, "\n"); + xproto_unregister(&PROTO_TABLE(BRI_NT)); + xproto_unregister(&PROTO_TABLE(BRI_TE)); +} + +MODULE_DESCRIPTION("XPP BRI Card Driver"); +MODULE_AUTHOR("Oron Peled "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(XPP_VERSION); +MODULE_ALIAS_XPD(XPD_TYPE_BRI_NT); +MODULE_ALIAS_XPD(XPD_TYPE_BRI_TE); + +module_init(card_bri_startup); +module_exit(card_bri_cleanup); diff --git a/kernel/xpp/card_bri.h b/kernel/xpp/card_bri.h new file mode 100644 index 0000000..a7b69de --- /dev/null +++ b/kernel/xpp/card_bri.h @@ -0,0 +1,31 @@ +#ifndef CARD_BRI_H +#define CARD_BRI_H +/* + * Written by Oron Peled + * 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/kernel/xpp/card_fxo.c b/kernel/xpp/card_fxo.c new file mode 100644 index 0000000..cbe953b --- /dev/null +++ b/kernel/xpp/card_fxo.c @@ -0,0 +1,1218 @@ +/* + * Written by Oron Peled + * 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 +#include +#include +#include +#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$"; + +DEF_PARM(int, print_dbg, 0, 0644, "Print DBG statements"); +DEF_PARM(uint, poll_battery_interval, 500, 0644, "Poll battery interval in milliseconds (0 - disable)"); +DEF_PARM(uint, poll_power_denial_interval, 40, 0644, "Power denial detection poll interval in milliseconds (0 - disable)"); +#ifdef WITH_METERING +DEF_PARM(uint, poll_metering_interval, 500, 0644, "Poll metering interval in milliseconds (0 - disable)"); +#endif +DEF_PARM(int, ring_debounce, 50, 0644, "Number of ticks to debounce a false RING indication"); + +/* 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, +}; + +#define NUM_LEDS 1 +#define DELAY_UNTIL_DIALTONE 3000 + +#define POLREV_THRESHOLD 1000 /* minimum duration for polarity reversal detection (in ticks) */ +#define BAT_THRESHOLD 3 +#define BAT_DEBOUNCE 1000 /* compensate for battery voltage fluctuation (in ticks) */ + +/* Shortcuts */ +#define DAA_WRITE 1 +#define DAA_READ 0 +#define DAA_DIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL) \ + xpp_register_request((xbus), (xpd), (chipsel), (writing), 0, (reg), 0, (dL), 0) + +#define VALID_CHIPSEL(x) (((chipsel) >= 0 && (chipsel) <= 7) || (chipsel) == ALL_CHANS) + +/*---------------- FXO Protocol Commands ----------------------------------*/ + +static /* 0x0F */ DECLARE_CMD(FXO, XPD_STATE, bool on); +static /* 0x0F */ DECLARE_CMD(FXO, RING, lineno_t chan, bool on); +static /* 0x0F */ DECLARE_CMD(FXO, RELAY_OUT, byte which, 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 int proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data); +static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, void *data); +static int handle_register_command(xpd_t *xpd, char *cmdline); + +#define PROC_REGISTER_FNAME "slics" +#define PROC_FXO_INFO_FNAME "fxo_info" +#ifdef WITH_METERING +#define PROC_METERING_FNAME "metering_read" +#endif + +#define DAA_REG_RING 0x05 +#define DAA_REG_METERING 0x11 /* 17 */ +#define DAA_REG_CURRENT 0x1C /* 28 */ +#define DAA_REG_VBAT 0x1D /* 29 */ + +#define POWER_DENIAL_CURRENT 3 +#define POWER_DENIAL_TIME 80 /* ticks */ + +struct FXO_priv_data { + struct proc_dir_entry *regfile; +#ifdef WITH_METERING + struct proc_dir_entry *meteringfile; +#endif + struct proc_dir_entry *fxo_info; + uint poll_counter; + signed char battery_voltage[CHANNELS_PERXPD]; + xpp_line_t battery; + ushort battery_debounce[CHANNELS_PERXPD]; + xpp_line_t polarity; + ushort polarity_counter[CHANNELS_PERXPD]; + ushort current_counter[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 ----------------------------------*/ + +/* + * 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; + + 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 == ALL_CHANS) { + 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"); + ret = DAA_DIRECT_REQUEST(xbus, xpd, chan, DAA_WRITE, 0x20, on); +out: + return ret; +} + +static void handle_fxo_leds(xpd_t *xpd) +{ + int i; + unsigned long flags; + const enum fxo_leds color = LED_GREEN; + 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_each_line(xpd, i) { + if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i)) + continue; + if(xpd->blink_mode || IS_BLINKING(priv,i,color)) { + 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) { + BIT_CLR(xpd->cid_on, pos); + rxsig = ZT_RXSIG_RING; + } else { + 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. + */ + priv->battery_debounce[pos] = 0; + 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(!IS_SET(priv->battery, pos)) { + LINE_DBG(SIGNAL, xpd, pos, "WARNING: called while battery is off\n"); + } + spin_lock_irqsave(&xpd->lock, flags); + mark_ring(xpd, pos, 0, 0); // No more rings + value = (to_offhook) ? 0x09 : 0x08; /* Bit 3 is for CID */ + 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, DAA_REG_RING, value); + if(to_offhook) { + BIT_SET(xpd->offhook, pos); + } else { + BIT_CLR(xpd->offhook, pos); + 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 + spin_unlock_irqrestore(&xpd->lock, flags); + return ret; +} + +/*---------------- FXO: Methods -------------------------------------------*/ + +static xpd_t *FXO_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, byte revision) +{ + xpd_t *xpd = NULL; + int channels; + + 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->revision = revision; + xpd->type_name = proto_table->name; + return xpd; +} + +static void clean_proc(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 + if(priv->regfile) { + XPD_DBG(PROC, xpd, "Removing xpd DAA file\n"); + remove_proc_entry(PROC_REGISTER_FNAME, xpd->proc_xpd_dir); + priv->regfile->data = NULL; + } +#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_card_init(xbus_t *xbus, xpd_t *xpd) +{ + struct FXO_priv_data *priv; + int ret = 0; + int i; + + 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); + ret = -ENOENT; + 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); + ret = -ENOENT; + goto err; + } + priv->meteringfile->owner = THIS_MODULE; +#endif + XPD_DBG(PROC, xpd, "Creating DAAs file\n"); + priv->regfile = create_proc_entry(PROC_REGISTER_FNAME, 0644, xpd->proc_xpd_dir); + if(!priv->regfile) { + XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_REGISTER_FNAME); + ret = -ENOENT; + goto err; + } + priv->regfile->owner = THIS_MODULE; + priv->regfile->write_proc = proc_xpd_register_write; + priv->regfile->read_proc = proc_xpd_register_read; + priv->regfile->data = xpd; +#endif + ret = run_initialize_registers(xpd); + if(ret < 0) + goto err; + // Hanghup all lines + for_each_line(xpd, i) { + do_sethook(xpd, i, 0); + } + 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; +err: + clean_proc(xbus, xpd); + XPD_ERR(xpd, "Failed initializing registers (%d)\n", ret); + return ret; +} + +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"); + clean_proc(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"); + 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); + } + 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) { + 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; + + 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: + do_sethook(xpd, pos, 1); + break; + case ZT_TXSIG_ONHOOK: + 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 0; +} + +static int FXO_card_open(xpd_t *xpd, lineno_t chan) +{ + struct FXO_priv_data *priv; + + BUG_ON(!xpd); + priv = xpd->priv; + /* + * We pretend to have battery. If this is really the case + * than next calls to update_battery_status() won't change it. + * If we don't have battery, than on the next calls to + * update_battery_status() a battery_debounce[] cycle would start. + * Than, if no-battery is persistent, asterisk would be notified. + */ + BIT_SET(priv->battery, chan); + 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); + } +} + +static void poll_current(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_CURRENT, 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 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); + if(poll_power_denial_interval != 0 && (priv->poll_counter % poll_power_denial_interval) == 0) + poll_current(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); + priv->poll_counter++; + return 0; +} + +/* FIXME: based on data from from wctdm.h */ +#include +/* + * 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 -------------------------------------*/ + +/* 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; +} + +/* 0x0F */ HOSTCMD(FXO, RING, lineno_t chan, bool on) +{ + BUG_ON(!xbus); + BUG_ON(!xpd); + LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on) ? "on" : "off"); + return DAA_DIRECT_REQUEST(xbus, xpd, chan, DAA_WRITE, 0x40, (on)?0x04:0x01); +} + +/* 0x0F */ HOSTCMD(FXO, RELAY_OUT, byte which, bool on) +{ + return -ENOSYS; +} + +/*---------------- 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(!IS_SET(priv->battery, i)) { + LINE_DBG(SIGNAL, xpd, i, "SIG_CHANGED while battery is off.\n"); + // FIXME: allow dialing without battery polling... + // 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; +} + +#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 +static void update_battery_status(xpd_t *xpd, byte data_low, lineno_t chipsel) +{ + struct FXO_priv_data *priv; + byte bat = abs((signed char)data_low); + byte pol = IS_SET(data_low, 7); + int msec; + + + priv = xpd->priv; + BUG_ON(!priv); + priv->battery_voltage[chipsel] = data_low; + if(bat < BAT_THRESHOLD) { + /* + * Check for battery voltage fluctuations + */ + if(IS_SET(priv->battery, chipsel)) { + int milliseconds; + + milliseconds = priv->battery_debounce[chipsel]++ * + poll_battery_interval; + if(milliseconds > BAT_DEBOUNCE) { + LINE_DBG(SIGNAL, xpd, chipsel, "BATTERY OFF voltage=%d\n", bat); + BIT_CLR(priv->battery, chipsel); + if(SPAN_REGISTERED(xpd)) + zt_alarm_channel(&xpd->chans[chipsel], ZT_ALARM_RED); + } + + } + } else { + priv->battery_debounce[chipsel] = 0; + if(!IS_SET(priv->battery, chipsel)) { + LINE_DBG(SIGNAL, xpd, chipsel, "BATTERY ON voltage=%d\n", bat); + BIT_SET(priv->battery, chipsel); + if(SPAN_REGISTERED(xpd)) + zt_alarm_channel(&xpd->chans[chipsel], ZT_ALARM_NONE); + } + } + /* + * Handle reverse polarity + */ + if(IS_SET(priv->polarity, chipsel) == pol) { + /* same, same, nothing to see here, move on */ + priv->polarity_counter[chipsel] = 0; + return; + } + /* + * Track polarity reversals and debounce spikes. + * Only reversals with long duration count. + */ + msec = priv->polarity_counter[chipsel]++ * poll_battery_interval; + if (msec >= POLREV_THRESHOLD) { + LINE_DBG(SIGNAL, xpd, chipsel, "Polarity is %s\n", + (pol)?"Positive":"Negative"); + priv->polarity_counter[chipsel] = 0; + if (pol) + BIT_SET(priv->polarity, chipsel); + else + BIT_CLR(priv->polarity, chipsel); + /* polarity reversal during offhook should be reported to zaptel */ + if(IS_SET(xpd->offhook, chipsel)) { + /* Inform Zaptel */ + LINE_DBG(SIGNAL, xpd, chipsel, "Send ZT_EVENT_POLARITY\n"); + zt_qevent_lock(&xpd->chans[chipsel], ZT_EVENT_POLARITY); +#if 0 + /* + * These two lines hangup the channel (by sending a message to + * the firmware), and inform Zaptel that the line has been hung-up. + * They are not needed if Asterisk does the hangup after receiving + * a notification from Zaptel (which is sent by the above zt_qevent_lock(). + * Asterisk does that if it has "hanguponpolarityswitch=1" in zapata.conf. + */ + do_sethook(xpd, chipsel, 0); + update_line_status(xpd, chipsel, 0); + pcm_recompute(xpd, 0); +#endif + } + } +} + +static void update_power_denial(xpd_t *xpd, byte data_low, lineno_t chipsel) +{ + struct FXO_priv_data *priv; + + priv = xpd->priv; + BUG_ON(!priv); + if (IS_SET(xpd->offhook, chipsel) && data_low < POWER_DENIAL_CURRENT) { + /* Current dropped */ + priv->current_counter[chipsel]++; + if (priv->current_counter[chipsel] * poll_battery_interval >= POWER_DENIAL_TIME) { + LINE_DBG(SIGNAL, xpd, chipsel, "Power Denial Hangup\n"); + priv->current_counter[chipsel] = 0; + do_sethook(xpd, chipsel, 0); + update_line_status(xpd, chipsel, 0); + pcm_recompute(xpd, 0); + } + } else + priv->current_counter[chipsel] = 0; +} + +#ifdef WITH_METERING +#define BTD_BIT BIT(0) + +static void update_metering_state(xpd_t *xpd, byte data_low, lineno_t chipsel) +{ + 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, chipsel); + LINE_DBG(SIGNAL, xpd, chipsel, "METERING: %s [dL=0x%X] (%d)\n", + (metering_tone) ? "ON" : "OFF", + data_low, priv->metering_count[chipsel]); + if(metering_tone && !old_metering_tone) { + /* Rising edge */ + priv->metering_count[chipsel]++; + BIT_SET(priv->metering_tone_state, chipsel); + } else if(!metering_tone && old_metering_tone) + BIT_CLR(priv->metering_tone_state, chipsel); + if(metering_tone) { + /* Clear the BTD bit */ + data_low &= ~BTD_BIT; + DAA_DIRECT_REQUEST(xpd->xbus, xpd, chipsel, 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 chipsel; + + priv = xpd->priv; + BUG_ON(!priv); + chipsel = REG_FIELD(info, chipsel); + switch(REG_FIELD(info, regnum)) { + case DAA_REG_VBAT: + update_battery_status(xpd, REG_FIELD(info, data_low), chipsel); + break; + case DAA_REG_CURRENT: + update_power_denial(xpd, REG_FIELD(info, data_low), chipsel); + break; +#ifdef WITH_METERING + case DAA_REG_METERING: + update_metering_state(xpd, REG_FIELD(info, data_low), chipsel); + break; +#endif + } + LINE_DBG(REGS, xpd, chipsel, "%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", + .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, + + .RING = XPROTO_CALLER(FXO, RING), + .RELAY_OUT = XPROTO_CALLER(FXO, RELAY_OUT), + .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, "%3d ", i % 10); + } + 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, "%3d ", IS_SET(priv->ledstate[LED_GREEN], 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, "%3d ", IS_BLINKING(priv,i,LED_GREEN)); + } + len += sprintf(page + len, "\n\t%-17s: ", "battery"); + for_each_line(xpd, i) { + len += sprintf(page + len, "%3d ", IS_SET(priv->battery, i)); + } + len += sprintf(page + len, "\n\t%-17s: ", "polarity"); + for_each_line(xpd, i) { + len += sprintf(page + len, "%3d ", IS_SET(priv->polarity, i)); + } + len += sprintf(page + len, "\n\t%-17s: ", "polarity_counter"); + for_each_line(xpd, i) { + len += sprintf(page + len, "%3d ", priv->polarity_counter[i]); + } + len += sprintf(page + len, "\n\t%-17s: ", "battery_voltage"); + for_each_line(xpd, i) { + len += sprintf(page + len, "%3d ", priv->battery_voltage[i]); + } +#ifdef WITH_METERING + len += sprintf(page + len, "\n\t%-17s: ", "metering"); + for_each_line(xpd, i) { + len += sprintf(page + len, "%3d ", 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; +} + +/* + * + * Direct/Indirect + * | + * | Reg# + * | | + * | | Data (only in Write) + * | | | + * | | +-+-+ + * v v v v + * FF WD 06 01 05 + * ^ ^ + * | | + * | Write/Read + * | + * Chan# + * + */ +static int handle_register_command(xpd_t *xpd, char *cmdline) +{ + unsigned chipsel; + unsigned data_low = 0; + char op; /* [W]rite, [R]ead */ + char reg_type; /* [D]irect */ + int reg_num; + int elements; + bool writing; + char *p; + reg_cmd_t regcmd; + xbus_t *xbus; + int ret = -EINVAL; + + BUG_ON(!xpd); + xbus = xpd->xbus; + if((p = strchr(cmdline, '#')) != NULL) /* Truncate comments */ + *p = '\0'; + if((p = strchr(cmdline, ';')) != NULL) /* Truncate comments */ + *p = '\0'; + for(p = cmdline; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */ + ; + if(*p == '\0') + return 0; + + if(!XBUS_GET(xbus)) { + XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down.\n"); + return -EBUSY; + } + elements = sscanf(cmdline, "%d %c%c %x %x", + &chipsel, + &op, ®_type, ®_num, + &data_low); + XPD_DBG(PROC, xpd, "'%s': %d %c%c %02X %02X\n", cmdline, chipsel, op, reg_type, reg_num, data_low); + if(elements < 4) { // At least: chipsel, op, reg_type, reg_num + ERR("Not enough arguments: (%d args) '%s'\n", elements, cmdline); + goto out; + } + if(!VALID_CHIPSEL(chipsel)) { + ERR("Bad chipsel number: %d\n", chipsel); + goto out; + } + REG_FIELD(®cmd, chipsel) = chipsel; + REG_FIELD(®cmd, do_subreg) = 0; + switch(op) { + case 'W': + writing = 1; + break; + case 'R': + writing = 0; + break; + default: + ERR("Unkown operation type '%c'\n", op); + goto out; + } + switch(reg_type) { + case 'D': + REG_FIELD(®cmd, regnum) = reg_num; + REG_FIELD(®cmd, subreg) = 0; + break; + default: + ERR("Unkown register type '%c'\n", reg_type); + goto out; + } + if( + (op == 'W' && reg_type == 'D' && elements != 5) || + (op == 'R' && reg_type == 'D' && elements != 4) + ) { + ERR("%s: '%s' (%d elements): %d %c%c %02X %02X\n", __FUNCTION__, + cmdline, elements, + chipsel, op, reg_type, reg_num, data_low); + goto out; + } + regcmd.bytes = sizeof(regcmd) - 1; + REG_FIELD(®cmd, data_low) = data_low; + REG_FIELD(®cmd, data_high) = 0; + REG_FIELD(®cmd, read_request) = writing; + xpd->requested_reply = regcmd; + if(print_dbg) + dump_reg_cmd("FXO", ®cmd, 1); + ret = DAA_DIRECT_REQUEST(xpd->xbus, xpd, REG_FIELD(®cmd, chipsel), writing, REG_FIELD(®cmd, regnum), REG_FIELD(®cmd, data_low)); +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 = handle_register_command(xpd, buf); + if(ret < 0) + return ret; + msleep(1); + } + return count; +} + +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; + byte regnum; + + if(!xpd) + return -ENODEV; + spin_lock_irqsave(&xpd->lock, flags); + info = &xpd->last_reply; + regnum = REG_FIELD(info, regnum); + 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"); + len += sprintf(page + len, "#CH\tD/I\tReg.\tDL\n"); + len += sprintf(page + len, "%2d\tRD\t%02X\t%02X\n", + REG_FIELD(info, chipsel), + 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; +} + +#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 + +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; +} + +void __exit card_fxo_cleanup(void) +{ + xproto_unregister(&PROTO_TABLE(FXO)); +} + +MODULE_DESCRIPTION("XPP FXO Card Driver"); +MODULE_AUTHOR("Oron Peled "); +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/kernel/xpp/card_fxo.h b/kernel/xpp/card_fxo.h new file mode 100644 index 0000000..4d0bd25 --- /dev/null +++ b/kernel/xpp/card_fxo.h @@ -0,0 +1,45 @@ +#ifndef CARD_FXO_H +#define CARD_FXO_H +/* + * Written by Oron Peled + * 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, RING) = 0x0F, /* Write to DAA */ + XPROTO_NAME(FXO, LED) = 0x0F, /* Write to DAA */ + XPROTO_NAME(FXO, RELAY_OUT) = 0x0F, /* Write to DAA */ +}; + + +DEF_RPACKET_DATA(FXO, SIG_CHANGED, + byte type; /* unused -- we have it from DEV_DESC */ + 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/kernel/xpp/card_fxs.c b/kernel/xpp/card_fxs.c new file mode 100644 index 0000000..f2251e0 --- /dev/null +++ b/kernel/xpp/card_fxs.c @@ -0,0 +1,1620 @@ +/* + * Written by Oron Peled + * 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 +#include +#include +#include +#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$"; + +DEF_PARM(int, print_dbg, 0, 0644, "Print DBG statements"); /* must be before zap_debug.h */ +DEF_PARM(uint, poll_digital_inputs, 1000, 0644, "Poll Digital Inputs"); +DEF_PARM_BOOL(reversepolarity, 0, 0644, "Reverse Line Polarity"); +DEF_PARM_BOOL(vmwineon, 0, 0644, "Indicate voicemail to a neon lamp"); +DEF_PARM_BOOL(dtmf_detection, 0, 0644, "Do DTMF detection in hardware"); + +#ifdef ZT_VMWI +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,chipsel,writing,reg,dL) \ + xpp_register_request((xbus), (xpd), (chipsel), (writing), 0, (reg), 0, (dL), 0) +#define SLIC_INDIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL,dH) \ + xpp_register_request((xbus), (xpd), (chipsel), (writing), 1, 0x1E, (reg), (dL), (dH)) + +#define VALID_CHIPSEL(x) (((chipsel) >= 0 && (chipsel) <= 7) || (chipsel) == ALL_CHANS) + +/* 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 SLIC_REG_DTMF 0x18 /* 24 */ +#define SLIC_REG_VOLTAGE 0x42 /* 66 */ + +/*---------------- FXS Protocol Commands ----------------------------------*/ + +static /* 0x0F */ DECLARE_CMD(FXS, XPD_STATE, bool on); +static /* 0x0F */ DECLARE_CMD(FXS, RING, lineno_t chan, bool on); +static /* 0x0F */ DECLARE_CMD(FXS, RELAY_OUT, byte which, 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 int proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data); +static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, void *data); +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 { + struct proc_dir_entry *regfile; +#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) ? 0x06 : 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, SLIC_REG_VOLTAGE, 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 == ALL_CHANS) { + 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, 0x06, value); +out: + return ret; +} + +static void handle_fxs_leds(xpd_t *xpd) +{ + int i; + const enum fxs_leds colors[] = { LED_GREEN, LED_RED }; + int 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, i) || IS_SET(xpd->digital_inputs, i)) + continue; + if(xpd->blink_mode || 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); + } + + } + } +} + +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 xpd_t *FXS_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, byte revision) +{ + xpd_t *xpd = NULL; + int channels; + int regular_channels; + + 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->revision = revision; + xpd->type_name = proto_table->name; + return xpd; +} + +static void clean_proc(xbus_t *xbus, xpd_t *xpd) +{ + struct FXS_priv_data *priv; + + BUG_ON(!xpd); + priv = xpd->priv; +#ifdef CONFIG_PROC_FS + if(priv->regfile) { + XPD_DBG(PROC, xpd, "Removing xpd SLIC file\n"); + priv->regfile->data = NULL; + remove_proc_entry(PROC_REGISTER_FNAME, xpd->proc_xpd_dir); + priv->regfile = NULL; + } +#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_card_init(xbus_t *xbus, xpd_t *xpd) +{ + struct FXS_priv_data *priv; + int ret = 0; + int i; + + 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); + ret = -ENOENT; + 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); + ret = -ENOENT; + 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 + XPD_DBG(PROC, xpd, "Creating SLICs file\n"); + priv->regfile = create_proc_entry(PROC_REGISTER_FNAME, 0644, xpd->proc_xpd_dir); + if(!priv->regfile) { + XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_REGISTER_FNAME); + ret = -ENOENT; + goto err; + } + priv->regfile->owner = THIS_MODULE; + priv->regfile->write_proc = proc_xpd_register_write; + priv->regfile->read_proc = proc_xpd_register_read; + priv->regfile->data = xpd; +#endif + for_each_line(xpd, i) { + priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE; + } + ret = run_initialize_registers(xpd); + if(ret < 0) + goto err; + /* + * Setup ring timers + */ + /* Software controled ringing (for CID) */ + ret = SLIC_DIRECT_REQUEST(xbus, xpd, ALL_CHANS, SLIC_WRITE, 0x22, 0x00); /* Ringing Oscilator Control */ + if(ret < 0) + goto err; + 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); + return 0; +err: + clean_proc(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"); + clean_proc(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"); + 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); + } + 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 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, "digital output OFF\n"); + ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 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 = CALL_XMETHOD(RING, xbus, 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: + 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 = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1); + return ret; + } + ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1); // RING on + break; + case ZT_TXSIG_KEWL: + LINE_DBG(SIGNAL, xpd, pos, "KEWL START\n"); + 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); + BUG_ON(pos == ALL_CHANS); + 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 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 (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 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); + LINE_DBG(GENERAL, xpd, chan, "(is %shook)\n", (is_offhook)?"off":"on"); + /* + * 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; +} + +/* + * 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); + } +} + +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; + if (priv->lasttxhook[i] == FXS_LINE_POL_OHTRANS) { + enum fxs_state txhook = FXS_LINE_POL_ACTIVE; + /* Apply the change if appropriate */ + BIT_CLR(xpd->cid_on, i); + BIT_CLR(priv->search_fsk_pattern, i); + pcm_recompute(xpd, 0); + linefeed_control(xpd->xbus, xpd, i, txhook); + } + } + } + } + } +} + +/* + * 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(print_dbg) + printk(" %02X", writechunk[j]); + } + if(print_dbg) + 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); +#if 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 LEDs and zaptel with current state of line. + */ + if(IS_SET(xpd->offhook, i)) { + LINE_NOTICE(xpd, i, "Already offhook during open. OK.\n"); + MARK_ON(priv, i, LED_GREEN); + update_line_status(xpd, i, 1); + } else { + MARK_OFF(priv, i, LED_GREEN); + 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 -------------------------------------*/ + +/* 0x0F */ HOSTCMD(FXS, XPD_STATE, bool on) +{ + int i; + enum fxs_state value = (on) ? FXS_LINE_POL_ACTIVE : FXS_LINE_OPEN; + unsigned long flags; + struct FXS_priv_data *priv; + + BUG_ON(!xbus); + BUG_ON(!xpd); + priv = xpd->priv; + spin_lock_irqsave(&xpd->lock, flags); + XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); + for_each_line(xpd, i) + linefeed_control(xbus, xpd, i, value); + if(on) { + MARK_ON(priv, ALL_CHANS, LED_GREEN); + } else { + MARK_OFF(priv, ALL_CHANS, LED_GREEN); + } + spin_unlock_irqrestore(&xpd->lock, flags); + return 0; +} + +/* 0x0F */ HOSTCMD(FXS, RING, lineno_t chan, bool on) +{ + int ret = 0; + struct FXS_priv_data *priv; + enum fxs_state value = (on) ? FXS_LINE_RING : FXS_LINE_POL_ACTIVE; + + BUG_ON(!xbus); + BUG_ON(!xpd); + 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; +} + +/* 0x0F */ HOSTCMD(FXS, RELAY_OUT, byte which, bool on) +{ + int value; + int relay_channels[] = { 0, 4 }; + + BUG_ON(!xbus); + BUG_ON(!xpd); + XPD_DBG(SIGNAL, xpd, "RELAY_OUT: 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(xbus, xpd, relay_channels[which], SLIC_WRITE, 0x06, value); +} + +/*---------------- FXS: Astribank Reply Handlers --------------------------*/ + +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); + struct FXS_priv_data *priv; + int i; + unsigned long flags; + + BUG_ON(!xpd); + BUG_ON(xpd->direction != TO_PHONE); + priv = xpd->priv; + 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); + for_each_line(xpd, i) { + if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i)) + continue; + if(IS_SET(sig_toggles, 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(sig_status, 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 */ + spin_unlock_irqrestore(&xpd->lock, flags); + return 0; +} + +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(REG_FIELD(info, chipsel)); + + /* 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); + } + } + } +} + +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; + 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(!SPAN_REGISTERED(xpd)) + goto out; + /* + * Process digital inputs polling results + */ + if(xpd->xbus_idx == 0 && !indirect && regnum == 0x06) + process_digital_inputs(xpd, info); + if(!indirect && regnum == SLIC_REG_DTMF) { + byte val = REG_FIELD(info, data_low); + xpp_line_t lines = BIT(REG_FIELD(info, chipsel)); + +#if 0 + XPD_DBG(SIGNAL, xpd, "DTMF result lines=0x%04X val=%d\n", + lines, val); +#endif + process_dtmf(xpd, lines, val); + } +out: + /* 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", + .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, + + .RING = XPROTO_CALLER(FXS, RING), + .RELAY_OUT = XPROTO_CALLER(FXS, RELAY_OUT), + .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; +} + +/* + * + * Direct/Indirect + * | + * | Reg# + * | | + * | | Data (only in Write) + * | | | + * | | +-+-+ + * v v v v + * FF WD 06 01 05 + * ^ ^ + * | | + * | Write/Read + * | + * Chan# + * + */ +static int handle_register_command(xpd_t *xpd, char *cmdline) +{ + unsigned chipsel; + unsigned data_low = 0; + unsigned data_high = 0; + char op; /* [W]rite, [R]ead */ + char reg_type; /* [D]irect, [I]ndirect */ + int reg_num; + int elements; + bool writing; + char *p; + reg_cmd_t regcmd; + xbus_t *xbus; + int ret = -EINVAL; + + BUG_ON(!xpd); + xbus = xpd->xbus; + if((p = strchr(cmdline, '#')) != NULL) /* Truncate comments */ + *p = '\0'; + if((p = strchr(cmdline, ';')) != NULL) /* Truncate comments */ + *p = '\0'; + for(p = cmdline; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */ + ; + if(*p == '\0') + return 0; + if(!XBUS_GET(xbus)) { + XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down.\n"); + return -EBUSY; + } + elements = sscanf(cmdline, "%d %c%c %x %x %x", + &chipsel, + &op, ®_type, ®_num, + &data_low, + &data_high); + XPD_DBG(REGS, xpd, "'%s': %d %c%c %02X %02X %02X\n", cmdline, chipsel, op, reg_type, reg_num, data_low, data_high); + if(elements < 4) { // At least: chipsel, op, reg_type, reg_num + ERR("Not enough arguments: (%d args) '%s'\n", elements, cmdline); + goto out; + } + if(!VALID_CHIPSEL(chipsel)) { + ERR("Bad chipsel number: %d\n", chipsel); + goto out; + } + REG_FIELD(®cmd, chipsel) = chipsel; + switch(op) { + case 'W': + writing = 1; + break; + case 'R': + writing = 0; + break; + default: + ERR("Unkown operation type '%c'\n", op); + goto out; + } + switch(reg_type) { + case 'I': + REG_FIELD(®cmd, do_subreg) = 1; + REG_FIELD(®cmd, regnum) = 0x1E; // FIXME: card dependent... + REG_FIELD(®cmd, subreg) = reg_num; + break; + case 'D': + REG_FIELD(®cmd, do_subreg) = 0; + REG_FIELD(®cmd, regnum) = reg_num; + REG_FIELD(®cmd, subreg) = 0; + break; + default: + ERR("Unkown register type '%c'\n", reg_type); + goto out; + } + if( + (op == 'W' && reg_type == 'D' && elements != 5) || + (op == 'W' && reg_type == 'I' && elements != 6) || + (op == 'R' && reg_type == 'D' && elements != 4) || + (op == 'R' && reg_type == 'I' && elements != 4) + ) { + ERR("%s: '%s' (%d elements): %d %c%c %02X %02X %02X\n", __FUNCTION__, + cmdline, elements, + chipsel, op, reg_type, reg_num, data_low, data_high); + goto out; + } + regcmd.bytes = sizeof(regcmd) - 1; + REG_FIELD(®cmd, data_low) = data_low; + REG_FIELD(®cmd, data_high) = data_high; + REG_FIELD(®cmd, read_request) = writing; + xpd->requested_reply = regcmd; + if(print_dbg) + dump_reg_cmd("FXS", ®cmd, 1); + ret = xpp_register_request(xpd->xbus, xpd, + REG_FIELD(®cmd, chipsel), + writing, + REG_FIELD(®cmd, do_subreg), + REG_FIELD(®cmd, regnum), + REG_FIELD(®cmd, subreg), + REG_FIELD(®cmd, data_low), + REG_FIELD(®cmd, data_high)); +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 = handle_register_command(xpd, buf); + if(ret < 0) + return ret; + msleep(1); + } + return count; +} + +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; + byte regnum; + bool indirect; + + if(!xpd) + return -ENODEV; + spin_lock_irqsave(&xpd->lock, flags); + info = &xpd->last_reply; + indirect = (REG_FIELD(info, regnum) == 0x1E); + regnum = (indirect) ? REG_FIELD(info, subreg) : REG_FIELD(info, regnum); + 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"); + len += sprintf(page + len, "#CH\tD/I\tReg.\tDL DH\n"); + len += sprintf(page + len, "%2d\tR%c\t%02X\t%02X %02X\n", + REG_FIELD(info, chipsel), + (indirect)?'I':'D', + regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high)); + 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 != ALL_CHANS && 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 + +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; +} + +void __exit card_fxs_cleanup(void) +{ + xproto_unregister(&PROTO_TABLE(FXS)); +} + +MODULE_DESCRIPTION("XPP FXS Card Driver"); +MODULE_AUTHOR("Oron Peled "); +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/kernel/xpp/card_fxs.h b/kernel/xpp/card_fxs.h new file mode 100644 index 0000000..6a89228 --- /dev/null +++ b/kernel/xpp/card_fxs.h @@ -0,0 +1,45 @@ +#ifndef CARD_FXS_H +#define CARD_FXS_H +/* + * Written by Oron Peled + * 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, RING) = 0x0F, /* Write to SLIC */ + XPROTO_NAME(FXS, LED) = 0x0F, /* Write to SLIC */ + XPROTO_NAME(FXS, RELAY_OUT) = 0x0F, /* Write to SLIC */ +}; + + +DEF_RPACKET_DATA(FXS, SIG_CHANGED, + byte type; /* unused -- we have it from DEV_DESC */ + 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/kernel/xpp/card_global.c b/kernel/xpp/card_global.c new file mode 100644 index 0000000..05f4008 --- /dev/null +++ b/kernel/xpp/card_global.c @@ -0,0 +1,342 @@ +/* + * Written by Oron Peled + * 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 +#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"); + +extern int print_dbg; + +/*---------------- 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 ----------------------------------*/ + +/* 0x04 */ HOSTCMD(GLOBAL, DESC_REQ, int xpd_num) +{ + int ret = 0; + xframe_t *xframe; + xpacket_t *pack; + + if(!xbus) { + DBG(GENERAL, "NO XBUS\n"); + return -EINVAL; + } + XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, DESC_REQ, xpd_num); + XBUS_DBG(GENERAL, xbus, "to %1d%1d\n", XBUS_UNIT(xpd_num), XBUS_SUBUNIT(xpd_num)); + ret = send_cmd_frame(xbus, xframe); + XBUS_COUNTER(xbus, DESC_REQ)++; + return ret; +} + +int xpp_register_request(xbus_t *xbus, xpd_t *xpd, + byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high) +{ + 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, chipsel, "%c%c R%02X S%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->eoframe = 0; + reg_cmd->multibyte = 0; + REG_FIELD(reg_cmd, chipsel) = chipsel; + 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, data_low) = data_low; + REG_FIELD(reg_cmd, data_high) = data_high; + ret = send_cmd_frame(xbus, xframe); + 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, DEV_DESC) +{ + struct card_desc_struct *card_desc; + + BUG_ON(!xbus); + if((card_desc = KZALLOC(sizeof(struct card_desc_struct), GFP_ATOMIC)) == NULL) { + XBUS_ERR(xbus, "Card description allocation failed.\n"); + return -ENOMEM; + } + card_desc->magic = CARD_DESC_MAGIC; + INIT_LIST_HEAD(&card_desc->card_list); + card_desc->xbus = xbus; + card_desc->type = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, type); + card_desc->subtype = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, subtype); + card_desc->rev = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, rev); + card_desc->xpd_addr = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, head.addr); + card_desc->line_status = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, line_status); + XBUS_DBG(GENERAL, xbus, "XPD=%d%d type=%d.%d rev=%d line_status=0x%04X\n", + card_desc->xpd_addr.unit, + card_desc->xpd_addr.subunit, + card_desc->type, + card_desc->subtype, + card_desc->rev, + card_desc->line_status); + xbus_poller_notify(xbus, card_desc); + return 0; +} + +HANDLER_DEF(GLOBAL, REGISTER_REPLY) +{ + reg_cmd_t *reg = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REPLY, regcmd); + + if(!xpd) { + XBUS_NOTICE(xbus, "%s: received %s for non-existing unit (%1d%1d)\n", + __FUNCTION__, cmd->name, + XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); + return -EPROTO; + } + 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, print_dbg & 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 = RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, errorcode); + reg_cmd_t *bad_cmd; + char tmp_name[TMP_NAME_LEN]; + static long rate_limit; + + BUG_ON(!xbus); + if((rate_limit++ % 5003) > 200) + return 0; + 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 (rate_limit=%ld)\n", + tmp_name, cmd->name, errorcode, rate_limit); + switch(errorcode) { + case 1: + bad_cmd = &RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, info.bad_spi_cmd); + dump_packet("FIRMWARE: BAD_SPI_CMD", pack, 1); + break; + case 0xAB: + dump_packet("FIRMWARE: BAD_PACKET_LEN", pack, 1); + break; + default: + NOTICE("%s: FIRMWARE: %s UNKNOWN CODE = 0x%X\n", tmp_name, cmd->name, errorcode); + dump_packet("PACKET", 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, DEV_DESC ), + 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 xpdstr[MAX_ENV_STR]; + char unitstr[MAX_ENV_STR]; + char subunitstr[MAX_ENV_STR]; + char typestr[MAX_ENV_STR]; + char revstr[MAX_ENV_STR]; + char connectorstr[MAX_ENV_STR]; + char init_card[MAX_PATH_STR]; + char *argv[] = { + init_card, + NULL + }; + char *envp[] = { + busstr, + xpdstr, + unitstr, + subunitstr, + typestr, + revstr, + connectorstr, + NULL + }; + + BUG_ON(!xpd); + xbus = xpd->xbus; + if(!initdir || !initdir[0]) { + XPD_NOTICE(xpd, "Missing initdir parameter\n"); + return -EINVAL; + } + snprintf(busstr, MAX_ENV_STR, "XPD_BUS=%s", xbus->busname); + snprintf(xpdstr, MAX_ENV_STR, "XPD_NAME=%s", xpd->xpdname); + snprintf(unitstr, MAX_ENV_STR, "XPD_UNIT=%d", xpd->addr.unit); + snprintf(subunitstr, MAX_ENV_STR, "XPD_SUBUNIT=%d", xpd->addr.subunit); + snprintf(typestr, MAX_ENV_STR, "XPD_TYPE=%d", xpd->type); + snprintf(revstr, MAX_ENV_STR, "XPD_REVISION=%d", xpd->revision); + snprintf(connectorstr, MAX_ENV_STR, "XBUS_CONNECTOR=%s", xbus->busdesc); + if(snprintf(init_card, MAX_PATH_STR, "%s/init_card_%d_%d", + initdir, xpd->type, xpd->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(GENERAL, xpd, "running '%s' for type=%d revision=%d\n", + init_card, xpd->type, xpd->revision); + ret = call_usermodehelper(init_card, argv, envp, 1); + /* + * Carefully report results + */ + if(ret == 0) + XPD_DBG(GENERAL, 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); diff --git a/kernel/xpp/card_global.h b/kernel/xpp/card_global.h new file mode 100644 index 0000000..250f4f4 --- /dev/null +++ b/kernel/xpp/card_global.h @@ -0,0 +1,94 @@ +#ifndef CARD_GLOBAL_H +#define CARD_GLOBAL_H +/* + * Written by Oron Peled + * 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, DESC_REQ) = 0x04, + XPROTO_NAME(GLOBAL, DEV_DESC) = 0x05, + 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, +}; + +DEF_RPACKET_DATA(GLOBAL, NULL_REPLY); +DEF_RPACKET_DATA(GLOBAL, DESC_REQ); +DEF_RPACKET_DATA(GLOBAL, DEV_DESC, + byte rev; /* Revision number */ + byte type:4; /* LSB: 1 - to_phone, 0 - to_line */ + byte subtype:4; /* default 0 */ + xpp_line_t line_status; /* hook/ring status, depending on unit */ + ); +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; + union { + reg_cmd_t bad_spi_cmd; + } info; + ); + +/* 0x04 */ DECLARE_CMD(GLOBAL, DESC_REQ, int xpd_num); +/* 0x19 */ DECLARE_CMD(GLOBAL, SYNC_SOURCE, enum sync_mode mode, int drift); +/* 0x23 */ DECLARE_CMD(GLOBAL, RESET_SYNC_COUNTERS); + +int xpp_register_request(xbus_t *xbus, xpd_t *xpd, + byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high); +extern xproto_table_t PROTO_TABLE(GLOBAL); +int run_initialize_registers(xpd_t *xpd); + +#endif /* CARD_GLOBAL_H */ diff --git a/kernel/xpp/card_pri.c b/kernel/xpp/card_pri.c new file mode 100644 index 0000000..e055953 --- /dev/null +++ b/kernel/xpp/card_pri.c @@ -0,0 +1,1673 @@ +/* + * Written by Oron Peled + * 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 +#include +#include +#include +#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$"; + +DEF_PARM(int, print_dbg, 0, 0644, "Print DBG statements"); /* must be before zap_debug.h */ +DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in milliseconds (0 - disable)"); +#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 + +#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_SF \ + ) +#define PRI_BCHAN_SIGCAP ZT_SIG_CLEAR + + +/*---------------- 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 proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data); +static int proc_xpd_register_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); + +#define PROC_REGISTER_FNAME "slics" +#define PROC_PRI_INFO_FNAME "pri_info" + +#define VALID_CHIPSEL(x) ((x) == 0) + +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] = "Unknown", + [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_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 */ + + +struct PRI_priv_data { + bool is_nt; + struct proc_dir_entry *regfile; + struct proc_dir_entry *pri_info; + enum pri_protocol pri_protocol; + int deflaw; + unsigned int dchan_num; + bool initialized; + bool local_loopback; + reg_cmd_t requested_reply; + reg_cmd_t last_reply; + uint poll_noreplies; + uint layer1_replies; + byte reg_frs0; + byte reg_frs1; + bool layer1_up; + 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) +{ +#if 0 + XPD_DBG(GENERAL, xpd, "(%d%d): REG=0x%02X\n", + xpd->addr.unit, xpd->addr.subunit, + regnum); +#endif + return xpp_register_request( + xpd->xbus, xpd, + 0, /* chipsel */ + 0, /* writing */ + 1, /* do_subreg */ + regnum, + xpd->addr.subunit, /* subreg */ + 0, /* data_L */ + 0); /* data_H */ +} + + +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, + 0, /* chipsel */ + 1, /* writing */ + 1, /* do_subreg */ + regnum, + xpd->addr.subunit, /* subreg */ + val, /* data_L */ + 0); /* data_H */ +} + +static xpd_t *PRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, byte revision) +{ + xpd_t *xpd = NULL; + struct PRI_priv_data *priv; + int channels = min(31, CHANNELS_PERXPD); /* worst case */ + + XBUS_DBG(GENERAL, xbus, "\n"); + xpd = xpd_alloc(sizeof(struct PRI_priv_data), proto_table, channels); + if(!xpd) + return NULL; + priv = xpd->priv; + xpd->revision = revision; + 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() */ + return xpd; +} + +static void clean_proc(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->regfile) { + XPD_DBG(PROC, xpd, "Removing registers file\n"); + priv->regfile->data = NULL; + remove_proc_entry(PROC_REGISTER_FNAME, xpd->proc_xpd_dir); + } + 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 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; + byte rc0 = 0; /* FIXME: PCM offsets */ + + 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; + break; + case PRI_PROTO_T1: + deflaw = ZT_LAW_MULAW; + dchan_num = 24; + 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; + 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 + return 0; +} + +/* + * 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, bool is_master_mode) +{ + struct PRI_priv_data *priv; + byte lim0 = 0; + byte xsp = 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 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; + } + 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); + 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"); + set_master_mode(msg, xpd, is_nt); /* by default set master-mode from NT/TE */ + 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"), +}; + +/* + * 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; + const char *framingstr = ""; + const char *codingstr = ""; + const char *crcstr = ""; + byte fmr0 = 0; /* Dummy initilizations to */ + byte fmr2 = 0; /* silense false gcc warnings */ + byte fmr4 = 0x0C; + unsigned int bad_bits; + int i; + + BUG_ON(!xpd); + priv = xpd->priv; + /* + * validate + */ + bad_bits = lc->lineconfig & pri_linecompat(priv->pri_protocol); + bad_bits = bad_bits ^ lc->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%X 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(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. + */ + if(priv->pri_protocol == PRI_PROTO_E1) + fmr2 = REG_FMR2_E_AXRA | REG_FMR2_E_ALMF; /* 0x03 */ + else if(priv->pri_protocol == PRI_PROTO_T1) + fmr2 = REG_FMR2_T_SSP | REG_FMR2_T_AXRA; /* 0x22 */ + else if(priv->pri_protocol == PRI_PROTO_J1) { + XPD_ERR(xpd, "J1 unsupported yet\n"); + return -ENOSYS; + } + if(priv->local_loopback) + fmr2 |= REG_FMR2_E_PLB; + /* framing first */ + if (lc->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 (lc->lineconfig & ZT_CONFIG_AMI) { + framingstr = "AMI"; + fmr0 = REG_FMR0_E_XC1 | REG_FMR0_E_RC1; + } else if (lc->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 (lc->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 (lc->lineconfig & ZT_CONFIG_D4) { + codingstr = "D4"; + } else if (lc->lineconfig & ZT_CONFIG_CCS) { + codingstr = "CCS"; + /* do nothing */ + } + /* E1's can enable CRC checking */ + if (lc->lineconfig & ZT_CONFIG_CRC4) { + crcstr = "CRC4"; + fmr2 |= REG_FMR2_E_RFS1; + } + XPD_DBG(GENERAL, xpd, "[%s] lbo=%d lineconfig=%s/%s/%s %s (0x%X) sync=%d\n", + (priv->is_nt)?"NT":"TE", + lc->lbo, + framingstr, codingstr, crcstr, + (lc->lineconfig & ZT_CONFIG_NOTOPEN)?"YELLOW":"", + lc->lineconfig, + lc->sync); + span->lineconfig = lc->lineconfig; + xpd->timing_priority = lc->sync; + 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); + set_master_mode("spanconfig", xpd, xpd->timing_priority == 0); + elect_syncer("PRI-master_mode"); + return 0; +bad_lineconfig: + XPD_ERR(xpd, "Bad span configuration. Abort\n"); + return -EINVAL; +} + +/* + * 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 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; + xpd->xops = &proto_table->xops; +#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); + ret = -ENOENT; + 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; + XPD_DBG(PROC, xpd, "Creating registers file\n"); + priv->regfile = create_proc_entry(PROC_REGISTER_FNAME, 0644, xpd->proc_xpd_dir); + if(!priv->regfile) { + XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_REGISTER_FNAME); + ret = -ENOENT; + goto err; + } + priv->regfile->owner = THIS_MODULE; + priv->regfile->write_proc = proc_xpd_register_write; + priv->regfile->read_proc = proc_xpd_register_read; + priv->regfile->data = xpd; +#endif + /* Assume E1, changes later from user space */ + ret = set_pri_proto(xpd, PRI_PROTO_E1); + if(ret < 0) + goto err; + ret = run_initialize_registers(xpd); + if(ret < 0) + goto err; + /* + * initialization script should have set correct + * operating modes. + */ + if(!valid_pri_modes(xpd)) { + XPD_NOTICE(xpd, "PRI protocol not set\n"); + goto err; + } + XPD_DBG(GENERAL, xpd, "done\n"); + 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: + clean_proc(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"); + clean_proc(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; + } + 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"); + 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 { + byte *pcm; + + if(SPAN_REGISTERED(xpd)) { + pcm = (byte *)&xpd->span.chans[PRI_DCHAN_IDX(priv)].readchunk; + pcm[0] = 0x00; + pcm = (byte *)&xpd->span.chans[PRI_DCHAN_IDX(priv)].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(print_dbg & 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 /* 0x0F */ HOSTCMD(PRI, RING, lineno_t chan, bool on) +{ + XPD_ERR(xpd, "%s: Unsupported\n", __FUNCTION__); + return -ENOSYS; +} + +static /* 0x0F */ HOSTCMD(PRI, RELAY_OUT, byte which, bool on) +{ + XPD_ERR(xpd, "%s: Unsupported\n", __FUNCTION__); + return -ENOSYS; +} + +/* 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; + 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 subunit, byte data_low) +{ + struct PRI_priv_data *priv; + int alarms = 0; + + BUG_ON(!xpd); + priv = xpd->priv; + BUG_ON(!priv); + if(xpd->addr.subunit != subunit) { + XPD_NOTICE(xpd, "layer1_state got wrong subunit=%d. Ignored.\n", subunit); + return; + } + 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(!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); + } + priv->reg_frs0 = data_low; + priv->layer1_replies++; + XPD_DBG(REGS, xpd, "subunit=%d data_low=0x%02X\n", 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; + + spin_lock_irqsave(&xpd->lock, flags); + priv = xpd->priv; + BUG_ON(!priv); +#if 1 + if(print_dbg) + dump_reg_cmd("PRI", info, 0); +#endif + if(info->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, subreg), 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(&priv->requested_reply, regnum) == REG_FIELD(info, regnum) && + REG_FIELD(&priv->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) && + REG_FIELD(&priv->requested_reply, subreg) == REG_FIELD(info, subreg)) { + priv->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_xx", /* xpd->type_name is set in set_nt() */ + .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, + + .RING = XPROTO_CALLER(PRI, RING), + .RELAY_OUT = XPROTO_CALLER(PRI, RELAY_OUT), + .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; +} + +/* + * + * Direct/Indirect + * | + * | Reg# + * | | + * | | Data (only in Write) + * | | | + * | | +-+-+ + * v v v v + * FF WD 06 01 05 + * ^ ^ + * | | + * | Write/Read + * | + * Chan# + * + */ +static int handle_register_command(xpd_t *xpd, char *cmdline) +{ + unsigned chipsel; + unsigned data = 0; + unsigned xdata1 = 0; + unsigned xdata2 = 0; + char op; /* [W]rite, [R]ead */ + char reg_type; /* [D]irect, [S]ubregister */ + int reg_num; + int subreg; + int elements; + bool writing; + char *p; + reg_cmd_t regcmd; + xbus_t *xbus; + int ret = -EINVAL; + struct PRI_priv_data *priv; + byte buf[MAX_PROC_WRITE]; + + BUG_ON(!xpd); + xbus = xpd->xbus; + priv = xpd->priv; + BUG_ON(!priv); + if((p = strchr(cmdline, '#')) != NULL) /* Truncate comments */ + *p = '\0'; + if((p = strchr(cmdline, ';')) != NULL) /* Truncate comments */ + *p = '\0'; + for(p = cmdline; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */ + ; + if(*p == '\0') + return 0; + if(!XBUS_GET(xbus)) { + XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down.\n"); + return -EBUSY; + } + memset(buf, 0, MAX_PROC_WRITE); + elements = sscanf(cmdline, "%d %c%c %x %x %x %x %x", + &chipsel, + &op, ®_type, ®_num, + &subreg, + &data, &xdata1, &xdata2); + XPD_DBG(PROC, xpd, "'%s': %d %c%c %02X %02X %02X\n", cmdline, chipsel, op, reg_type, reg_num, subreg, data); + if(elements < 3) { // At least: chipsel, op, reg_type, reg_num + ERR("Not enough arguments: (%d args) '%s'\n", elements, cmdline); + goto out; + } + if(!VALID_CHIPSEL(chipsel)) { + ERR("Bad chip select number: %d\n", chipsel); + goto out; + } + REG_FIELD(®cmd, chipsel) = chipsel; + switch(op) { + case 'W': + writing = 1; + break; + case 'R': + writing = 0; + break; + default: + ERR("Unkown operation type '%c'\n", op); + goto out; + } + if( + (op == 'W' && reg_type == 'D' && elements != 5) || + (op == 'W' && reg_type == 'S' && elements != 6) || + (op == 'R' && reg_type == 'D' && elements != 4) || + (op == 'R' && reg_type == 'S' && elements != 5) + ) { + ERR("Bad number of elements: '%s' (%d elements): %d %c%c %02X %02X %02X\n", + cmdline, elements, + chipsel, op, reg_type, reg_num, subreg, data); + goto out; + } + switch(reg_type) { + case 'S': + REG_FIELD(®cmd, do_subreg) = 1; + REG_FIELD(®cmd, regnum) = reg_num; + REG_FIELD(®cmd, subreg) = subreg; + REG_FIELD(®cmd, data_low) = data; + XPD_DBG(PROC, xpd, "SUBREG\n"); + break; + case 'D': + REG_FIELD(®cmd, do_subreg) = 0; + REG_FIELD(®cmd, regnum) = reg_num; + REG_FIELD(®cmd, subreg) = 0; + REG_FIELD(®cmd, data_low) = subreg; + XPD_DBG(PROC, xpd, "DIRECT\n"); + break; + default: + ERR("Unkown register type '%c'\n", reg_type); + goto out; + } + regcmd.bytes = sizeof(regcmd) - 1; + REG_FIELD(®cmd, read_request) = writing; + REG_FIELD(®cmd, data_high) = 0; + priv->requested_reply = regcmd; + if(print_dbg) + dump_reg_cmd("PRI", ®cmd, 1); + ret = xpp_register_request(xpd->xbus, xpd, + REG_FIELD(®cmd, chipsel), + writing, + REG_FIELD(®cmd, do_subreg), + REG_FIELD(®cmd, regnum), + REG_FIELD(®cmd, subreg), + REG_FIELD(®cmd, data_low), + REG_FIELD(®cmd, data_high)); +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 = handle_register_command(xpd, buf); + if(ret < 0) + return ret; + msleep(1); + } + return count; +} + + +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; + struct PRI_priv_data *priv; + + if(!xpd) + return -ENODEV; + priv = xpd->priv; + BUG_ON(!priv); + spin_lock_irqsave(&xpd->lock, flags); + info = &priv->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", + REG_FIELD(info, chipsel), + 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", + REG_FIELD(info, chipsel), + 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; +} + +int __init card_pri_startup(void) +{ + DBG(GENERAL, "\n"); + + INFO("revision %s\n", XPP_VERSION); + xproto_register(&PROTO_TABLE(PRI)); + return 0; +} + +void __exit card_pri_cleanup(void) +{ + DBG(GENERAL, "\n"); + xproto_unregister(&PROTO_TABLE(PRI)); +} + +MODULE_DESCRIPTION("XPP PRI Card Driver"); +MODULE_AUTHOR("Oron Peled "); +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/kernel/xpp/card_pri.h b/kernel/xpp/card_pri.h new file mode 100644 index 0000000..dbe83c0 --- /dev/null +++ b/kernel/xpp/card_pri.h @@ -0,0 +1,32 @@ +#ifndef CARD_PRI_H +#define CARD_PRI_H +/* + * Written by Oron Peled + * 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/kernel/xpp/firmwares/FPGA_1141.hex b/kernel/xpp/firmwares/FPGA_1141.hex new file mode 100644 index 0000000..512df60 --- /dev/null +++ b/kernel/xpp/firmwares/FPGA_1141.hex @@ -0,0 +1,658 @@ +# +# $Id: FPGA_1141.hex 5122 2007-12-12 10:07:59Z dima $ +# +:020000040000FA +:80000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AD6FF4000782C0A006AD6FF4000782C0A006AD6FF4000782C0A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4455544455557475577775577675577775577765566665563625523235D2E37C2B5111155111155111155111C4 +:80008000155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111000000000000000000000000000000000000002552222552222552220025522225522200000000001AA1111AA1110025522200001AA1111AA111001AA11100001AA1111AA11100001AA1111AA1111AA113 +:80010000110000002552222552222F21F112122F21F112122552222552222552222552220000001AA111255222255222255222255222255222255222255222255222255222255222000000002F21F112122F21F1121200002552222552221AA1111AA1112552222F21F1121200001AA1112F21F1121200002F21F112122F21F112121AA100 +:80018000110025522225522200000000002552220000000025522225522200000000002552220000FFF9F99F9F7F78F8878700000000000000000000000000000000000000000000000000000000002552220000000025522225522200002552222552222552222552222552222552222552222552222552220025522200000000004F44D4 +:80020000F444444F44F44444000000004F44F444444F44F44444004F44F4444400004F44F444444F44F444440000004F44F444446F64F446466F64F44646000000004F48F884846F69F996962F21F11212000000CAACCC2F2DFDD2D22F21F112124F48F884842F21F11212004F4CFCC4C46F6DFDD6D62F21F1121200006F6DFDD6D66F6DF0 +:80028000FDD6D66F6DFDD6D6000000008AA8882F29F992922F21F112120000004F4CFCC4C46F6DFDD6D62F21F112128AA8882F21F11212004F4CFCC4C46F6DFDD6D62F21F1121200006F6DFDD6D6CFC5F55C5CBFBEFEEBEB006F6DFDD6D66F6DFDD6D6000000008F8CFCC8C8AFACFCCACA255222000000CFC4F44C4CCFC4F44C4C008F8C66 +:80030000FCC8C825522200CFC4F44C4CCFC4F44C4C000000CFC4F44C4CCFC4F44C4CCFC4F44C4C00000000CFCCFCCCCCCFCCFCCCCC000000008F84F44848AFA4F44A4A255222CFCCFCCCCC0000CFC4F44C4CEFE4F44E4E2552220000EFE4F44E4EEFE4F44E4EEFE4F44E4E00000000CFC8F88C8CCFC8F88C8C000000008F84F44848AFA4A9 +:80038000F44A4A255222CFC8F88C8C0000CFC4F44C4CEFE4F44E4E2552220000EFE4F44E4EEFE4F44E4EEFE4F44E4E00000000CFC8F88C8CCFC8F88C8C000000008F8CFCC8C8AFACFCCACA255222CFC8F88C8C0000CFCCFCCCCCEFECFCCECE2552220000EFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F88C8CCFCBFBBCBC3AA33379 +:800400000000008F8CFCC8C8AFADFDDADA2F21F11212CFC8F88C8C3AA33300CFCCFCCCCCEFEDFDDEDE2F21F112120000AFA9F99A9AFFFEFEEFEF00EFEDFDDEDEEFEDFDDEDEEFEDFDDEDE000000008AA888BAABBB3AA333000000CFCCFCCCCCEFEEFEEEEE2F22F222228AA8883AA33300CFCCFCCCCCEFEEFEEEEE2F22F222220000EFEEFEFD +:80048000EEEEEFEEFEEEEEEFEEFEEEEE000000004AA4441F14F44141155111000000CFCCFCCCCCFFFFFFFFFF3F33F333334AA44415511100CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000008F84F448489F95F559591F11F11111000000CFCCFCCCCCFFFEFEEFEF3F32F223238F84F448481F11AF +:80050000F1111100CFCCFCCCCCFFFEFEEFEF3F32F223230000FFFEFEEFEFFFFEFEEFEFFFFEFEEFEF00000000CFC4F44C4CFFF4F44F4F3553330000008F8CFCC8C8BFBFFFFBFB3F33F33333CFC4F44C4C35533300CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004554444F42F224242AA2220092 +:8005800000008F8CFCC8C8BFBFFFFBFB3F33F333334554442AA22200CFCCFCCCCCFFFFFFFFFF3F33F33333008F81F118189F9EFEE9E90000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004AA4446AA6662AA222000000CFCCFCCCCCFFFFFFFFFF3F33F333334AA4442AA22200CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFF8D +:80060000FFFFFFFFFFFFFFFFFF00000000CFC4F44C4CCFC6F66C6C2AA2220000008F8CFCC8C8BFBFFFFBFB3F33F33333CFC4F44C4C2AA22200CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F48F884846F68F886862552220000008F8CFCC8C8BFBFFFFBFB3F33F333334F48F884842552221B +:80068000008F8CFCC8C8BFBFFFFBFB3F33F333330000BFBFFFFBFBBFBFFFFBFBBFBFFFFBFB000000004F48F884846F68F88686255222000000CFCCFCCCCCFFFFFFFFFF3F33F333334F48F8848425522200CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F48F884846F68F8868625522200009B +:8007000000CFCCFCCCCCFFFFFFFFFF3F33F333334F48F8848425522200CFCCFCCCCCFFFFFFFFFF3F33F33333EAAEEE7F75F55757000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F44F444447F75F557573F31F11313000000CFC8F88C8CDFDBFBBDBD1F13F331314F44F444443F31F1131300CFC8F88C8CDFDBFBBDBD1F13F33105 +:80078000310000DFDBFBBDBDDFDBFBBDBDDFDBFBBDBD000000004F44F444445F55F555551F11F111110000008F8CFCC8C88F8FFFF8F83AA3334F44F444441F11F11111008F8CFCC8C88F8FFFF8F83AA33300008F8FFFF8F88F8FFFF8F88F8FFFF8F8000000004F44F444444F47F774743AA333000000CFCCFCCCCCDFDEFEEDED1F12F221F9 +:80080000214F44F444441F13F3313100CFCCFCCCCCCFCEFEECEC2AA2220000CFCEFEECECCFCEFEECECCFCEFEECEC000000004F44F444445F57F775751F13F33131000000CFCCFCCCCCCFCFFFFCFC3AA3334F44F444441F13F3313100CFCCFCCCCCCFCFFFFCFC3AA3330000CFCFFFFCFCCFCFFFFCFCCFCFFFFCFC00000000000000000000AE +:800880000000000000000000FFFBFBBFBF7F77F7777700008001000000000000000000000000004001000000000000000000000000DF8D07480000000000000000000000000000000000000000000000000000000000BE4E000000000000000000000000000000000000000000000000000000000000FFE40F480080010000000000000066 +:8009000000000000000040010000000000000000000000002F820C0000000000000000000000000000000000000000000000000000000000F04FFE8002004001008004148002800414800200008002800400002148400100800400002148000010F2A6CE000000000000000000000000000000000000000000000000000000000000FFE44F +:800980000F0000000000000000000000000000000000000000000000000000000000F04FFE80840180020000001002000010024001002100140000000028000014882880080088280028009A0F0080840100002001000000000000001200004001000040010000400100000000009F31094818148002800414182810820416012810A2115B +:800A000040012810A2414001002B11484001280048408188022148008828108204F05C6580840180020000001002000010024001002100140000000028000014882800008088020000EFF80F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000008827 +:800A800028000000280000F0B32B00002002000000100200002400000024120018000000002800000000000088000000FFA60A0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000200100000000000000000000000000F07CBE0000000000000000000000000000120039 +:800B00000000000000000020080000000000004F330B000000000000000000000000001002000000000022000000000000000000F04F4A000000000000002100000000000000000000000000000000220000000000005F2E060000000000000000000000000000000000000000000000000000000000F04FFE0000200200000000000000CE +:800B8000210000000000000000000000000000002028020000AF950C000000000000000000000000000000004002000000000000880000000000F09CC320010000002400000000800400000000400200220000200100000000008002004200EFDE0D00000000240000000000000000000010024002000000000000000080020000F0A3BEEA +:800C0000800100000000000000004800000000000000220000200100000088000000004800BF170E00000000A0110000000000000088008001000080010000000000000000002008F0AD1A000000000000000000000082000000000000000000000000000000000000A0430000800200000020040000000000002002800200000082000069 +:800C800000000000000000F0B25B8001382001002088021240022200828081024200200442000000282222800200200482002004200448F0A82C002002120000008001242002000000480000002200008002820000004200008004200442F01C39800118200200202802800400008220810200004A0242000000802202220000008200008A +:800D0000000000FFA70400000022108224020000200880022800000000000000000000220000000000800228F0293700000010013288000080218201482008000000001280028280022800008002200800000020045E4500000000902220020000800848000000000080012200000000000000000000800200FF150D000000190212C20098 +:800D8000008081220120222802000000000080082820020028200220080000002006DF770F800428000080014A01222002280082211218882816220880010080011200188800242004284200000042227016018004120060222800002A040000221002182120280318001828182448200380022024086214004800481002289F280328007D +:800E0000001800000000181800000000002200002242000000200A240000002800000000B0520C00A0210080322200588024A112800222001224001818202121A21422122420A112A0212A08C04288484214422004002004F0D53F20020020010012000000000088008028823222000000800100200810020000000080048022726D0620A5 +:800E80000448000000000000008002008008210000009021824210022028820200004002000000F01E712002208101800128800180088232882004A82024020082800182200480011812002200000000800400F0A19C0028000000280022980020010026820A28002200002022288908800A8800002100000028002A04008F2208208184F3 +:800F000002288001184A01208122010000182C01002082888128218802002004680022002800880080048004F084B6000000200800D2000000B2008800000000C882003081200A18202808800200A08400000000683FFA0D1220012800000012800288002800200820020000A21280828284042212800220020000282228228002E03C0480 +:800F800022111122184001002084011280018800222A04288081A4818001001848A04224182800240029020021103242488004F056742021210122002002002A04208804808202002824280018A04280022840222202280024220000280028200214F03CF700221C84011E2100A01200A0212021081A02121022820188290100241400244A +:80100000A0428001C042800424A0282424240011481002BF5A041AA1121A8185220200202185212102A0112A0A4A81CA822088022901488083A82A1D216A8A86E225A1212AA29228222B222822200820022213A2224A4481F441CB80A22115013A8112012AA21258223280A1881AA822182A2222A2682AA224A023A088008A248328AB4898 +:8010800082808AA1882012C242212121602840B2220248204221F27568209241A0233011A011A0214A88218C21A811CA812808A82921032226128226A1999A682300982442263222225A218884022228004A782212022B64424A04002BA5002601260126012021820400120028122848281A848204290518800198800100212004460200D2 +:801100002400820000142004F06C9DA0233AE313F221211F110A1F11818183A399187A051AA2185AA5A9AA28A29DFAAB335A24A626184AA4884A85E124B482A8B91F16E625BFA20A1AA145BAEA28BE2266242944B22202A0442F22B222F222222B222AA6426A066AF6F722A0333AA7331F13D3112AA211003AA199185A07A0995AA5AAAA09 +:801180000AFABBF2AB777A25A6BC184A8CA844F041632BA8BEB11F16E627B7E22AA2175AA5EF8EE22B624A82062AA222E024F6222225722232221B626E622B62B062F65AD9A0231F13B731031AD211A211121AA2319AA9444AA611189AA155AAABBB229ABDA2A866382AA4A25AB412A1995AAC895E532B912AFA71711F31B3A28EE223B3BB +:8012000012A1F7AAEB26B262E22216E2229222824E422F22B222F222222B222A22B662066AF67216A0331F13F131311AA1311F12F211111AA1313AA3991AA1551AA1111AA9551AA39B2AA2FB3AA3336AA7423AAA452B199AA9551AE137B732B321F271711F33B3A28EA2337AA5BBAAEB267242F2226227222F229222826E422F2252222FB1 +:801280002232222AA6662B26246AF65C1620022280010000000000200800820000280088200288422A082200A0922002000024C02280820400F0E1F900120022110022128084012088210280220322400200002A0822C011001082020030220080082C028084820422AFB3062AB41122B21122B611324219B26291212B961B682B9413B86D +:801300004229F24291222F142BF242B13AE414EB2AE414EA2264152F22E419E22264192CA4292CBC91C2521B29241B292B841B6923B481364219B64298212B8413B84228B24228B24228B242A842882E429776A0421AE612A42166A1212F14B11132621B282B921B692BA41B692B84322D811AF442A1B22DB123D312EA28C1B12E821CD8A6 +:8013800022E118E22261183CC1212DD21B29581B6929B88192921B2925B2810219F2428219A2A41B282928B24228B24228B24318B242EA22E4EB0A20080000800200210000000000000000004001008004000000008002000000501214EF760B2840014001402101C6024882002282281262284280220129880188222A01880000008200A0 +:80140000228800242280A428008082F418A520A138803111181E21294802A812240028190811180012008002202641622920120221100220062220420242C021148022866814702D0118CA1101121CA12121008AC2C222002819289281382C2122A34120A81230824A011328A2210042000020062228A2228024021488284E22882601CF97 +:80148000D8072228204101148234122041828408000080040022002022412219829282100221008200002440021C828402004248BBC50080013420822222010000000080034200A0242250222829010080220200002C8804482C080000002800702E0D228002282218121062121818888021024A8B21A4121220042021820128A012200284 +:80150000008A0228622A040000304228482880A8242A84F2476B0080022C022081828102128800001A0C1A04188004482002242880020028200822622C0200002442224228002A8406CF660B2220011428322824108101001222808221A22142002022032721281820012828002800A04842208418020000800A20F277792001000028265B +:801580008122016820224182820148322100160112D28800280040022082064800428A2222924240222224A2844221006FB7041C024222120010820420A882422800001002281A08602880A21214C2241901A0182981812102290240022A0822004800212242EDBC00001C010000800121001280321128822022A442102302122024012245 +:8016000092220020028008000000420000A880F2DB36902100262101220012184602A0411A8282036892002AA48230126888321242582419813122122383A12142A082802812A24820B22204488248A880F2F6918001200100193222488082280810021C012880024601142C0180222208288848882006221082240224000048284800283E +:8016800048471210218102002002001200C02212200212208208242846033063A01822A8304224280082190C42808442020040021002F081C9001100281100248A0210221882011221108281042082A812E818822A054001146886011411002440010022211002202404DFC60D808262132001160113A118802181210182221A82A2421832 +:801700004229A284422024028221C2200C9220E822A848224228482842800442806622482220F219EB000000282124121022220228002812409211211922081882184812800200B2001400000010424101200600002CF4D6C88081031828182C02350221204102A02100244280C112100200904228421A42C222D02222942220420223821D +:80178000220220042200C021282260FE8012818122112121820228280020021812002222221842183238321982044001160114902220A28214C0418084020010028004AF1C05114001001400889898102281081342E218222124088219210288881829010000001041411121140140018004000010F2248E008211002219D21231112A01BF +:80180000400200002412001022024246024810226421200E20241C02A048258204283022004800001426F2161F8002488008002820820838102102006210021823820800886011C800B0120C31240014002024440122A024226248211CF4873DA0219A33111E31923E312C622124188A6223C0121838A0B11AE112A9142F11A516222B226D +:8018800025B152A133BAAB132CA24F2B858AC482822D41BAB842A488248A82B2438622A4624A52311480E4246626224AA4622681F25172601217182A22A2221113E212B11121A882B81A232922A112268252223A862231C2885A8E542123A4642A8C21E22428A2443A19421191223D412681888466142A24B46246A2248084026014F0EBF3 +:80190000971411221400241691232F12F232A32B1182242123F121821A4261221A122286EA316228222AA24C4886F2D3112982A53315E1225A212CF321822F34F2218188196C383726311502481128228052222A32422CE426F4E1E414400100146032402201122C2881081C083C0A1C28C1212114400142218A028A028A12A228218A4291 +:801980002208400200200822000042003F4C06281B11A033221B13D021B332E32ABA828BA91B23B89213E11BFAB1B11F1B99323F3AF9A1911F11F5B2423F18F861711F13E311E413F5E1B316A2A9BA2B2FFA41E32BBB173B23FA41C1AA2AFCE1233D812A7243A12217121F28F8C3C1284A26A264C0426AA6442F36F67F5B143AB3F1B7112B +:801A0000A3733AB131B311F133323B112F28B892A12B9EB223B882B1B1E91B2BA2333F3AFAA3B12BAB1AF5A1533F3AA8EE7AE317E71DFDF1F38E8237121AEF14EF2AFAE3432F25FF11B33F2AFAE1612D822BA61F3EFAE3613F16F663216A56111F38F8E3C12AA2462AE226E422A2242B662AE222F62614B011F331713AA3333AF131113E1D +:801A8000323F31F332322F2BBB82ABB38AD322B812B181E913A3321E323F1ABB22B332A3DC1F36F5C2E22BC45AB151F5F1D23F3CFCB39326A1A55AFB41411F3EF413F33F315B223F1ED622B862FEE1632F16EE26F263211F16D61152111F14A44462624E626E426AB422A6666E624F6F41F131311F1BF711317AA3331F13F311113F33F372 +:801B000013312F2ABA92A93B9E822F2199121B33BEB11F18EA23D322F3A3911F13A7CD6E423F3EFE61E17AB171F7B1F23F3FFB33132F19AF541B5F1F3EF443E33F31F5B113373A1F14FC23222B6E1F3EFEE3633F36F263211F16764151111F14A4644AA6666E426E624AA6262AE632F66CFA2002222002200182002001112812301130816F +:801B8000281100421180A824208401218001001440010024481400400200002FCD0C260126019021261221223122800121321C21CB13224A0138484A3222142CA12C989012402244022440024240820448002304802424220442F01452C0411B21141B2146B311726293212F34B111F242931B212F2439112F2429F24293222F3429D21255 +:801C0000AB431CE922C4A12F2264112F22641D2E4296F122C29AF222C21B292EC21B292F22B891F262821B292B841B282F2498212F2498212B84112F2428F242A2222BA4222B842A84E822C4E4C0511B611CB511E23631112F3691216E1313E134B891E224BA91F24292824EB3222F3429CAB12B432D91AAC5B13DC21AFA23429237221248 +:801C80002F326C112F222CF122C11AF42281122F3238116E8219F26282282F3688E234BA816224E0240A4A2AB242B822B4426A22BF8A0A2088040000000010020000000000800800001C080000000000002280020000004001CF540A8AE112611211182D12281902200B2001628048A2824222388880321120242101182C2102290A92210D +:801D00003A082A0488484848428092424822288004346F160622821228800850221904664262244082818202A242802486344223828982288422A2412B248082A252422C8388CC22200824488A042223842422C2212AF42A9914A03C1361121286222212C241B86222460228200223E2288422238D229412A81A8C8239416022784A324236 +:801D8000288E1248882888C88842C24824684E2242424222244A6212286F4C042A112102241210410200252201482921882288820420246214218001A0211810A22880A2121AC6126880120280048220922248280048EFCA0C14001122602230420048000042320042481800210028181288A0821223022A0126022C882206800600484225 +:801E000020040020E23D0C1A021B922021D21201A08211360200212381880322286880242202182C64262A812101C2282032827682A248822B4228002924C882284890422A248402CFDE08289011A0212CA22121A028113221400223A5922820064A014222282063254E328A038220288281622820BA82A6482924A2241022682422004803 +:801E8000224200CF830C19018A120110012904200400008001A042220021000000122A213162800223C2720022280080048842484602482022627910012800240090123828488004800220B142222224A12423A4292242001800400282482148884082062220840A0022622100AFC90D222240012A812232220010224222128204281002E5 +:801F00002CA24320212C3812A248B042822684260821002C82840220024082020030C28846F25D38800111280080010014808881012921080000000000122848001821180014008842A02421480048424002800456091C0328116021222229024023041E42260278882212626022484823812328A581621842682C248281184201A223C4DA +:801F80006268248024843862002C22A2844846F2E3E80068142880021224122A81028220410200002848282242482821282034228001290C4602428008800600228004200488F052EF8002168183D2128102382218241800211288187032028022040000A012002424226022001A02620000B022042128422902212828CF2B0F1812280034 +:802000004042028228822088212228028282A23A04822C8184010000292202D0220A42880000232222041002202234224820F4E6D81412008012322211100126012511121262280028128014A224189082A8122D12282C458285044022824102282200002822102284222204DF430E902140012818282830820000182280A812002412580E +:80208000002A0412230212280080A281A0412128004248800200000010027FE20240611242114091321218322128000038120028284200220000002024A2A420042004200400000000284200F0971F2082A141180021008A0222801202210000804422024222008A8402240000368202268222140228482810220822002200E7E1100148D0 +:80210000806112404201148E1212128A8102008A820420080092C824808C984220189282880020A4280000000042000022703701800662132191111220112201202428282108200122C04238108264210020A32440824402002442808402002A8402004234422F1C431101481100401141718102821A0212382121128A8114022C2382882F +:80218000642100822F1221A9481A0848A0246E92708282C82248108202282120044830421C52851415F12121181AE52171316321255112E038681A888E1216E2210280A823AAA84A5E422CA24428A0189224A0389632422B6C27244221299622882E128222216280040021C042262224C2214AF42BFEA0325200171229F321212CA2138E47 +:80220000221B11233132271198236822249AA188282381A2842318B212E22294822B688A3132183A42A2C148AAA8886E42CAA3252CC2824A84062342427222A2A4A024A022294481F2652C2081F131211F16820229B13191211F13B922C2B21830422AB192ABBB212CA15138222AA5226E526AA52548122F23C4C22B222C2DA33A2F2AC2FE +:80228000227E12F032422123B6C2E62212A26642808622E22622A264484AA2462722EF264501000000344001200882000000202804422084080029081890820048244002244880044002800400006FCA09181F12721111D121F82322311B312B111F2BB9922942F292922F2CB682BAA2E229B9B2AB339E12EAAFD82F27B622E626B762E462 +:8023000027B692A9DD9AE926AEB35E722F28F812922AAAA8BEB27AA7772B648ABAA20A2B646632224AA464CABE42A6226AE416E62284A4662D224FB90F19F161611F13B1317311B23333333B233B131F3BB9B2AA222AEA28F9D2522F2BB992E129B8B2AB335AB5F2AFDD2C94427EB22B753EE22BDDEAAEFF1F35C5B25E712DA22DA22CA6A7 +:80238000A8BEB22B155E622B452BC62B8A2CB262E62692224AA444EEC22B646AA6461B666AB462A46626F289D314381D711E2119D321D323B233F131332F21F2B3323BB93ACBB22F29F1D2D22F28B8A2AABB2BABBAA99B2B5FDAE12CADE82EC22F26F672723AA3FFAAEB36BEE2EF25F7A2922F21B982A4A81E322BEE2BEF2B67AEA22BAAAE +:80240000212B622E222B644A042B8A2B6422666222222B446AE222F48CA5141F12F321711F13F131311F2BF2333337233F33F333333F3BFA33B13ADB22FA82122F2DFDB2B22B89BABBB2A3BBFAAE7FDAE526A2421E222F27F7F272FAEF26A6FE4E532F2EFF53722F22FB22F22F2ABAA2EA23F3C2C22F2FFE52422F26FCC2822F22B24266C5 +:80248000262B444A44F2A2822B646AE626E626A6666AA6226E42DF5E0E14C011400222122622290220412249228902200182102204002818100222302280082A0800008044020028A02400D04505902190212E12D0320114D032888201211022822281A34242002E424229A1282B42B02224652280042430421A9212482304216800004AE0 +:80250000082448A042008F240D1CB411021B21421B21272419F2421119F2429119F24291112F1429F24291222F3429D212A9424E912E424E812E4256E12264192EC296C1429AD222B491C2521B2925B29162241B6927241B28272419B24298612F2498412F2428F24282222B842A94822A84E82274560F1CB511061B21421B21272419F224 +:802580004213284E918AF242318AD212012F142BF24293A21CB1A2D412C1521CABC21E81272216E1226D112EC316D122BC81C2D21B612D821B292E121369241B282F2698212C98212C9A214E82222F2422D222288298422BA426F279920082480000000000288004000000800100000014000000000000008002800400001424D30218009C +:802600002E111602181542012583220400289A02A024000048002904702282C6421A8403001290220000208484E42802C0A228004826F242C2001B1A002092221AC6121C02242411E028220516A282A04912622904122712884E12488081098820126214221880A4A4298404882440022D4124424001EF4D06181B3C6013182D2218181286 +:802680002603232206C082328021682252125223240C26812854221912622D52124200182232002C28042282422C0AA02829C2424081F2EF860000002092612503145022112022244B2222240822001225228421045A02A08260226014100242688024844402243043100242245FFE0A18001100242002A04124488004009242000022C0FB +:802700004230228229012A81A2828220018200002282000000218242AA04486F570A19021C2342A2121C8845A2812C831A2349220168181984A818224A02422982015622212282988260212A11B2228123012E828282808428242886A2A4220028F01E7A80012219022A6118212220B182139192200162B04101122800228045E22261214A +:802780002A81A2A182A2182C229112B2128088282A2824088828282B84008A8482E49A091C021C0124004A41A218222C04422448001888C888A042C042222420240840820286820128006022000080044880222A2402F09578002280A1421448250200428008A84A082C4102232221081022C82280042C212226812201202802291802B0B3 +:80280000620820081120880880F82E9A00803121200200102112621200A0120028290420A1A4121220211181040048190AA014A0242084822402482A04209422902228F0AA16A014902100202382210220085810324248200848A0841420022082820800001221800100000000881C0800424242AF580E5860113260122229222142A142C4 +:802880008280853842281642828A8401481932121A428201228A15822281E2128811A214222282218004006A8888889422824A2226F4D9270068221162A014100200211B2820C2821A240420222488880480025A022022048005208881148224022B84200400200800827E850022601226D112911252214691422012128221C8929229329F +:80290000822818254202002901A028888E118082A2121812222200800800000080222804F0CF12803411008024044229A281A08420D22388024213A8240019A88211111391211823294102272824248A94822C0821502210022D821002211082180260221F5B0C0000422214200114428027011C2442012681C5812B421480010020AA128D +:8029800028130219011324341152114AB28122948142A08400000000827F4108140010010000002921288882810800000042202728044221C26014828022A248148A024081048822802482040082F0677D8022848224A2241A448213028A01A0212240028A0420220C2001220020280188281A1A8289A828882002200248000088682100A5 +:802A00008FEE0F42121A04100223061E421A084A982210022901218002182C0B108201002460282224A08120028008008002008002821002BF7A090048200400004880018218221400888621810214141414188622210200420020012100101201860286028824200CD01C05288228426011348096216028281A0C2424221AAC4210220269 +:802A800000212240022129012981B8820128228088820A20080000203221484021F8DE7300221C352100002001528002A01820022028084A21A4844223A4244A2164144AA22452C04150122081C4410020A8688088A4C2484828822D82486F934121621D2AC1412A7211B351E52432626E414AA4411AE824CC821B1A2ABA2203AEC2CAA857 +:802B000014382B85230452382B16225AB82228D712B242B282A18B2BAA288EE22CAA622CEA1A4692418692C12C2C7E8282E828041D426A021423F818A9A0448A2331212CB44247B312E421A5111146F2A26223A139282B111CF852C23B24242AE228A828243F3444F26143284E5282CE7238FE52126EC24AA3113A61121813186224882032 +:802B80000482004A14A2E68224CA6418A8BF810D1922C2214A7241210280D223B292A9984AA1182227211F2864291B38B021E21838311B421BAAD01121F11181122D12122F2888E83A98212543F3C2812B11F6A191AE41882E21822D81A602C8002A022ABA828C8888F4354610810120084800000000144001144814481C02000000000092 +:802C00001110011123161112314211230421100221D0120200F03E26141F14B411621222A0135E523E324AA1A81F1CED24FC42128E928E9233B1C1ACDF1F1431611F28AC641F151FB141E634F143511F35FD13416E624AA4645E722B771F35B2C2E434F8A2833F12B251F6F3F33F3FF923633B4637323F34F442423F16D822F442E227288C +:802C80002B8CCE622F2CBC42A68248F0C2C2DF6C0E4AB471E712B221E226F271322CE527A7161F1EFF8191242B3518243B331BDF1F17FD411113BE81FCE1611F1FBF13B141F4C1833F34F563D33F13E426A7DD1F15E624FF42C11F3DF2C3415EF32F3AF323611B232F21B372F3A1E11BC42F2AB8827881A1A42F28BCC22CE82CF8E2422F4C +:802D00002EFC6261EEA22B44A0CC9F630D6AB411E611F1212115F111111F31E123A3571F17F6C1D32F219CF28AED287912A12A1F1BE827E238A8AE3DE11AE91CED14F441C33F15F421633F17A667CAEC1DEB25B372E72DF6E3612E623F2ABAB1E333A1BB2BBF1B622E23EABE82081F3CAAC82B8882CEC22B6EEAEC2EB222BAC2084AFCABDE +:802D80005FF061411B73141F12F261A11F13F311517E727AF571713F387912B252A55C182F12A31AAAF86361AEE1EA8ADE31E814FD42613F34FC53433F3BB653E427A75DDE217EB21B771F3DA66E2E621F2AB2E1EB32A3463F3FB2A3EE38A8EE3F38F8C341CE828AFC828223A8CCEE422BCECE222BCA2BCC88CAFCFC7E2002002602182026 +:802E0000A248A049241A04122089A2482812288210028002800988800988909280092A08200882200800824200824F38032001286611714202181351220010022DB2482410029826023D424211122C242422F1224242A02121282220020088000048A0484A022882003FDC041CB511C2111B21421B212394612B1419B24299212B94112B89 +:802E80009413F2429113F2429113F242911B424E911F22C4A12E4216E12264192F226C192CA4292CB491C2431B29341B2966B3917642B381764293612F3498612F3498412F2428F24282222F242892A22A84E822F488B3C051681CB11122B4111292212B1419F24292112BB413B84231212939212B9413B24239232B941F2281E922CC811C +:802F00002B5296D1226C193CE419C2421AC2C39AC6439A62329A44A3684683E63488E6349A614E82224E82224E8222A82B4229A8428FA60220080000004001008002000010021800000040010080040000000000200400100225015F960E901180036E12421641013602808818022CA88480842304001002821A12A2122282822A088601D4 +:802F8000880046A2428200802848A24280260242243F4F0B46A12832A04240212284A38420612160216A016022009213128282810222800858298202AE112C12A1218002004288002822204CC281E018A242AF310430D120234482C4211C24A396212296C28230222C884402381A3C1221821800201221E314B22288AAA48AF22142A01A57 +:803000002022A4248820028800284AC82214C0412D221F14011C84A21220A261141200001800124A01882242001302223022A0821229081800C011821400400280840820CA224880840AA848EA0F226012005022112C0120D1228144012008114220840433021B4228881229810212212814120026020022400124A02422288A84024A0242 +:803080007F334181210180A22122222812180014C2142A94222306808A0200D02281042AA44227214A02221230822B822F2A1161262A143281298C14C24142802484222402228F710F00190220211223028011021C48A12429386220042A84042712242E114A022AA512382386112213512282299A2123A62421139A4213146224424A82BA +:80310000A242AA842602225EED14321200282C02281829210116621448002810012A0800002C0482242C040022001A886221002100880011004800004A024F1B0518481C218302801201190252141880848309282902C28A22022C4102800423020086220B2AA182000048C220C8A2E82C8484120200EF8701114800003012422180122280 +:8031800002212B82004223110224001A04880022529021482A84014800283944A2820048200400002908281FEA08100100142280A224520048002024028842480042112848184A010048C0120022008082042400008008002200EF5E051111162183422192221C84A261281A440120A2348A012B1A4A82C442A0241A847182822125C4120B +:8032000030414826822828A421A828622CA4824223842428B882C2824826028820F2221C8001000020612248141082C612B0420828480020880A142242002242222820C1521A22020025010088002A2484040022003F8F0C100148C0218003000020224102111001142411004A020048282C41A312113811001021022110420280322228B3 +:80328000422200504F004011111102002819C121100321181CB21252120000802401130115029682220340632412218220083022828038220010820480745B0A0000802101212400272124107182820110028002150220028A41020021A8212A0488882C8A081001110040A284282180049F440B80040010024A61154242222085420100D5 +:803300001220110222141602242008002C228484011E224A0242A82C0800400221002002F01996A0121120F2211222200222112A012CD1218289434282011C0120024826012024032331121221111280085021002214D01204224082044240F3E4A210010010210200211413024A01001382D2210129210221224810410100001B2482B0C9 +:803380001102808A220400800800282C0200485FE30C201241010018161201001420061C8241110200140010814142028A8202824814213823850480022100282100208482021F9F02190228808131112024A114181110111101008042012392211B4380212421018200400200183148222B840021000000004870BB0A00481228242800FB +:803400002100183840822A01001911924118803811221682A8848E2140611416828422022054124222111119120120924200902222AB3E001942D111F221223B12182C21913313810215D231B513E221C3213F317122D1310119A1221D221B226AC7212A61211D8229F822122F2BF333112CA3261591212383B11262382BE42E42282225CA +:8034800041E218283222242B6A00484E214AF44F7BB01182140116E121B222A221582693421B111AE211B112E22671A1F131122A9211121F13214122225413199123589AE529260830121A74A2F23212189EA24AA8A215A124E2250114212C82B22262242F24A224282A043FF804264121A241181416216224524E1166F3211321621C98BA +:8035000082214012023419541214127A64111425A114A8882CE212F48383184E411D22228E521B44A229D822D82172811271410224002A94422260227E7300000024200200224083440224400200000000100221100221100280044800000000000000F08FAB141A61122A7231513115B222A2326AF731311F12F351511F31513115E33365 +:80358000F31113257111E33252332A022F160617121D511F17F721314AD511A15C2B2229E221B373F721133B111F12A3112F29B392E5163222EAEE2CFC232335F181831F2C5C2225E22282A4224AA442A0448D2E141B116E612AF231111B221B133A82A3761F37F771711F15F511311731141F39F98181371117111F1353113B22E017E722 +:8036000022F2A3911F17F651F11F12F351513F18F9C1512B991E113E321B661F3AFF91913F12F321112F29BB72A76E2B6EAEE22F2CDE33F223211F38F8C1E3272225E222B242A4264E422B464AF662628B41141AA1422A723151311D132F12A3136AF751511B776E711F31D33351333F37F793933F32F223233E32212B23F0615117323F25 +:8036800012FA71717AE712F351511F18E933F3B2222F2BFA33333F37F7A3F33F13F121311D132F2AFB7272EEE22F2ABA22A2EE3F32D21352333F1CDC225222257222E222B242B6228684F455B6141B112AE612F2311115F331132F1382A1761F35F573717AB7115131357131F393813F127223E32313A232F061711F32F233A11B771F1F29 +:80370000E712F351533F1CED3637921F297811F371631F3AFB31133F12F321132F2BF3B272EEA22F26F6A2E22F2C5C323D2135F3E3C12F2252222E2223E222B242B662E624E626F6D797A0120080012E1112220048144032812412301110018012830210012A012A09002F12093C012E82601248224003340000A02420043F4F0E001428D8 +:8037800034194221612611182818112981843321002180414201563121D021214C2241022E1113410222D02281D422082C0824130880022B243042224073A90C481B21B01162241B21272619B24291212F2699212F2419F142932AF44293222F3429D212A9421CE922E414E82264112F2264192F2264192D429AD222B491D222B4915222B1 +:803800001B2923B49132421B682394612B841B282B84112B84222B84A22B842229A842882E425E5880B411061B2146B2116224114A91212F2419F142B2C0932AF44293224E93221CB922D412E922C1912AE811F8224296712262192D439E2129B49112B29156221B2923B49132421B2823942129B881B24292212B84222B84A22B84222921 +:80388000B82294822E421FCF0500000000000000002100000080018800004001000000000000002800000000003FE90A180012C011298162122812240000111932C2108322A2424022912129682220A12126A22180082824114042022CA268008004A29022298202F0CF5C0026210180021C014260125880512280911123040086220C428C +:8039000012800120240162181022498231A1602800408284820462422044019FDC0D184E2180018031218024012302122111169181294403A085828229652282260219810122424A08221234128A022D82224222244862808A94422D222A04F0EDF6008001B011122261122890214A010021222B1410228262224200190118004AE222210A +:80398000212241022C08101102248A02002004282200007F2C06000000002A812212011A04902200124200484200130200200C402101122C210120042100108204224248280022DF8242818222022AD121A21222109112868201183888384AC22213A2410020E414C242682984948228281AA6422818202A86C462282A044223044A0888A5 +:803A000088A280044A0A1FE603002280429132221AC22121191802002B8238808204808484844283964200882033211820012B42002222602400824280AA864248808AF2F28C14222200182200001A021252181A02A0422CC1214A010060142A04C04282682848422212A03818426823C442004224488008002820047F880B11488A21025A +:803A80002100208402203242488880288231421AA44812E02204221810210800002800C8A0484228282088248806008004885F370512481118002138282302A0812601222842003022001A0600824091211812808C050082306240024222212002208C0221003FBE070088001400008002008004000000001118A042C84821224A010018B1 +:803B00002823012400004242000022000048AF9F061901132102142118222302804101684A028800424280022A04A0421C2C94821A82A14800322818C8468224044A622448208A02A2004220F435F920082041028002482228883042808804221822188A24041429A128182022014220810424822428883022008A22044220240200821FEC +:803B80007107002812122A110200000000282028822202002682028001282024040042288A02004800000000001002F09F870000008002000000800A1C8241113141100100482242304100A82004C042808462221448C04200802422024800F0D53614821422280080020011001A02821A88022220A8348818001800202682210400400284 +:803C00002C0824222C024622C42240A2242C82A22400BF550214124800826200288002000030410090128880042880220800481480A6250014002200000000000000DFBE01384800202304222200140080084280082A8104220000802208A0488A0412200800284822280020248204004826F1EE550080042280014280034218800800883E +:803C8000203142282220120262224214141818200820810280040020240600484200F0184800800110022800100180012219328111111C08209441306138121388084882808204120029A82C1110024002240024A02428F06D2A80220962402201002002182002A0212224426221C81002002280260216022400000020020080040080028F +:803D00002C047F1B0392281C05280048282002800200928004A2238888038800001948218882088E612246014A22C28100002800002004902248FFC5072AA32D2A02282F22A1418002800280A18822321BD2E8A0AA3AA614226E21210080A8482219AA281A88A2882A418228A6AAAE8168222002B0220228226842E01684F4946C1412866B +:803D800021012A21A1222A26840222421A012A021F180A171230419062CA26A1222E61226A051BA64A24A2478E12482C82E21744926125E22442A2642E2248244AC4424A54224246A2424A82028E311081C1112A07282B142022A23215110132A0A818DE21F021A31CA59C1B8A882C4422A4311AE21A42A1284A84B941246C125A04B20053 +:803E00007061012124422004226890222B4230223FB90D1100204882040000000000480020410146116214400100423041221118112111211002211082140221100200F096D8141F1AB32162122A83A128006A26A2311D216A8481232272A1B181F1A1A11F1ABA61EC12B881B8E1A4661F16541117137AF481814AAEE6EAAE65BE622D815D +:803E8000AEA33F12B241F693B33F3C7C83728251223F3656222125F242422F26B262E622F222222B222A2622E222B6DC0E221B6326A13218BAA3212AA244283AF321214A8681A322881F12F1A1311F1A28F262411F1AB8A1BBE1F8E1E11F1686A8134AF4A1A16AAEE61BEE1F11F4B1E32D418E8335B141F692B22BCC1BA246D122F24361FF +:803F0000A0662F24B442A2666E622F22D22292222CB662A64248DD5CA0321B7314E02892222A82A466A0112AA26420A1888AF8B1A11F19F9A1E11BCC3BDFAE812EB14AF461C16E422B664AF46141EAE616A6A2AAFEC1B11F38B422FEA1A23B225E535AB5C2BCC1643815F163616AE624A6442B442AE624B462A6222C92222B66222AF68AB9 +:803F80008570A1B13163122AA2223AA3312AA6442AA21115F14141183AA1AA2AFA21B11F18F9A1C14AE416F481812EE14AACE61F16F6E1617AF75151EAAEE66AAEEEBAEB29BC22F281A23B224E435AF5C3C33BC64EA31D213F34B642E624A6442F22B462A6444E622B242E222B222B662A84F4C16CA0120000200200220012208822883225 +:804000008128124A0242008002282A082A0818800818A082200226010000288082840242D0E40B001828002B14000040010020418144A14800A82E4280240542208804C8200280242408484220840448800420042814DFB1011CB41142B11162241B292394612B1419B24299212B94112B94222F1429F242912AD412B931C4911F22E414B7 +:80408000F8214256F1234296F1214296C142DAC2421B2D3CB49142B391E234B1917242B381724293212F2498212F2418F142822AF44282222F242892822A84E822F41F4FC0411AC64119E226311190612B121B612B9419B2429B612B94222F1429F242912AD412B933D412F821521CF921821E81372296F1214296C1439E21249AE212A4E9 +:804100006925A3292F3621E834A1284693214E8219E2249A214E82224E82224E8222882B4229A842B78D0082200800000000280000000028008008410022144002000000000000280000000021F03C830024181400211124A888C04180014321612A882088A482284A2204468224020023AA418A810880820610228404294102438226081C +:80418000802248F23A4D008604324D220089081211A81082B8AA812802132684221201A0121A8201C8299342382088323481C281122E484883032200528B2D0020C444481CA4249F8C4201433C12142604218D81242886011B4220B8A2A1182A61224AC84288481A2AA24A2AA5121820382120A3829AA41438A0848CA21600268884622220 +:8042000080F422D8008830444A829442CF3A0600A02124000092A028248041480488130222281100004229A4242D124224008A92848400C068462201482081014CA24280048028F2DE9310140140922120119661214001290100181218000000100860229A322410A2212E11281400206481002100C0829242228812003645C311284CE8FC +:8042800022D11411B815C449508210121228548249492224C2442021F64AA2222D5523B216F4422412294482A112418880B144622313248992224E2232482D4246A21248282E8A8A11246A88225F93093114413821814C944860124012015602490952124304124AA28623B24411524A292601A84303441211902532130400422A314240FC +:8043000022219C822C8CCB841A3288228F7E4931142288C01527121C911161A7242400842181002128180024812411225844242C6621C032A082322A8144029868A3831242622442222063820082001F340830441042C421105284251C01259614411044948830148A82B28864C140281448143248252C91142136440456084002304828E2 +:80438000278244418A12E482A1828504288C21F1F49D00482D288C81C4148140018074288484682858428004214C04124C0C80C128484128211548044A020048221D94A0818C042044946224809222E3644212EFDF4F021045012528025810480814161802C01481A922C418440046C21844582228002A8401128C02C91114081280A141D9 +:804400006081400858608900416E35004141279141AD1185021F24111C2814DA43E568012381D44888B41C824C344445984446384A85642328CD22C3129265612E141A2222149444226928618866AA415084472A28842B58CCB232E8840241B7B21002A71220C42422100C1484008182461484411822B2486388008021D184248404181215 +:8044800018104498181608841C014A219128414A01874432281018D448031F85040085410340021001004145484C4804202404400120C8444C246C44230415440400444241C03289041984024902222342342844604184AF150A1240C4144901138101811819118311921221104A1C118A1474421298461602120028224216A8214C023EE7 +:8045000048000044840068182280C41888222280F1831720544210021229D422014484188021941800160543154481242464445684411225911465C2425240D2242281411806212400541024A14128441A48388849F2A44410814104465841403118105642131123011285012440A1211018941184411961818100381044C81810044A51A8 +:8045800084811348082888401204004C2802BF7F4122588211274418814311088593112440625213428801181123D114017094010084502843B2580254583024604412C0480010B142012244C0828D14800114FDE680459218951264541054182110084651284464A0412001101814028004514418104438242E44002991444112003028A1 +:804600004CC21218604218884B212818448D181004806194904819941400808582011C01255261C048485100160112414A010016884608124904220082A0420017424304508442290841D0A1021424001562844110161411183444004416412101118400118450821018429812282200502280114241C413C08181B08281280152814C81C9 +:8046800028F85BF64048A84181800148172440424482023490284502491204117911084002884051241115082C04118411161824C888150C2D31201404222290882962824F510816748868D187812D545F21D134F4414247A551164162212447C1856751F04C115439018341D4417458B44851488334522B44463A3A4B22A9716111C82867 +:804700002931444B451C22D4487184C81A3B44D091512422417AF3342829723A446452283F95031F1411145B14E084A41416D158414F36125C31531B12239316A75111A3D134569B1F1654A4473447886F41E424F912549CD1C909C01A5E254975447424A2214C51424E1A67C143D3485811942E8243B4A19224246D4489E88CA928CF83D2 +:80478000E389524C7787242CD422D124F14316D7B5857518D44A1113DA83D19831434D55AD425D1885F8211A27614D1256F4445449714151823551111241457494711EF444362F41F425421E243A43742CF6324B8C71148461B429B48898289D212F41E441F1D2541EA4C014CF4394948A9894AE18FFAD071100140000001200000060829B +:8048000060824604800448800558A042200218118111A11912922123843242304230423042100200812FFA447181734153398F21F558D97F11FC4A4E7F71F1535115F115131E125E545F35F11212BF23F3181AEFF3F25E56AF21B352F218197E7897A59FA4744CFA525A6FA5F55652CF64F5D7D76FE5F1363EE7E56F65F112111F11F319B8 +:804880001F2F7163F33FF1F67B763FB2D22BF267227E73BFBCFC6B4BEF64F544662F6FFFD4562F24B4C6BD54F79C98CDA849F116A45FA8447115F71D4E17711E568F45F5DF45EFE4751FFF5F59D5F111171F21B173F75551EFA1F33F35DFA1F13B398F35F51C367F31F369294FD5F5495BBFA4F4CE5A2FA5F596CE6F65F51C56EFEDFD5FB9 +:804900005F6FE3F37A3FAFF3F376141F57F7191FAFF3F3325B7FD1F35B567F94D4EBF3EBAF7F67F3CBC9BFE4F24E567F75F1F2F66F6DF172746FAEFB5EF8CFABF93EBC8F82D966FA449C7045D775D57D51648FE5F51356B5FE1717BF95F51919BFF1711BFB53716F65F11216BF22F31A1AFF91F1747B6F61F13D5D7F51E197F749191F24A1 +:80498000D4C9F8585CCFE1F55656BF71F5D1D38FB3F3763CEFE5F7165C1B314D643E16AFE1F33312BB35AF7555D2AFF6F147645E1FBF9EFE4A2AAB5457342F4F7CF4B646F6CED2EBFFCB99AF8AA89ACFCAFBCD2634777DDF61F113134765AFECF51B1EFFE4F11C1FFF95F51C159F31F11B123B757F35F43F1BFF73F3171EBF91E1B7F7140B +:804A000016FF93F137754FD5F54D4DDFB4F45E8DCFC5F59C1E6F65F51E16DFFDFD682F2FE7F37F7E3FE3F316644CF63C1E2F63F37716FF41F378776FD4F4681FBFFCFE1196BF8E5EACFF74F515172F6FED6BF176744FAEFB7EEAEF4BF9BE9CCFEAF9ACACBF7B052901618421484D1184452241424883441101154804301181001185048500 +:804A80001403413022501460125014501450140040414821890264828D24824482BEBA4042C41215885181211B412115182241013C31142041024E154118404528011224446D188B252456041A42428481A41412E08854188410044120421284618240F93A87C0421F4152281F417248F11124A3D441B24AF11124AB9419B24A19F54A92AA +:804B00004F82F44A9343F24A914782AF14F924484E954FA2E414F8264A56F1264AD6E1A2655D2EDA9E242E4A1F49C2421F49D228F1912C83F4912CA3F4812CAB141D24AB9419B24A3995AB9443B24A39342B94478229F9344889F9244A4F4D06ACF411648D421E24C7141F41324A1D24AB141F41F64A941D24ABB451AF64D984F448B341EF +:804B80008F149944AF1419F242954F82E114F926885E8167A2D6E1A261542E9B9E252E4A1FC9C24A1F49C6521FC92276913C6217C8AB161741AF467881B46AB195B24A3924AB9443BB4A792498926F83949A4F22F53DEB402808008200000080820100000021008008000014008400000000004400001002308400B0F40340C21415E21162 +:804C0000C4184601481994481A043018008C5428C181410026282471444282C13610C2882816046C81A2828C0417822AC99A70823141C08880C8281823840140F492EE10B1812312CC288615D4415112441885C1482584CC15178941C04219285448874411257A41041504118C83224235C2148445A2414712484148481222188E142124A3 +:804C8000434186B88CD24A041C44F8EA5B10E18C9314D43B43C961145D12194411DC812142E4816C111B8185447A4CC28A43142455298994414918237121B611028C52144B854679147A24A2C14D614845A16856522426A1524489483294EC2258486D1A0084CBAA0011230281191804C0444A81744802101488044001814588426241481C +:804D0000442112A428882821002042088C826188188214922100C012AA240442413F9D0C222861805141403844008A44234824C11412292302000010081229014B52838421BC2241941240D241A2148424484248241220422601002A04482727241691142601469418453115126AC1A13210981185C2E12618D822E1C8644F844398AC2725 +:804D80001616445484B042018A922822441A82D848F3A41810B6124A84888181042522B122FC4428274C238A0A7024F26BB930222215044415041C911412A28A1411D24181F112811A323823914C4A02402202444412124C87E481E2222C82911243512C2CC2148B2141C2002418A012224D6A8A14026860664FEE0919311429021AC4187B +:804E000015148CA424142A018308844916188232824B81814CB88C9241160C16189242E0820860412684C828B251422308214A818544424292C42911A4282A08007B4350424A811224A4821614423C8C1068C14126C2142948228A311429121428293425440048248C614247A2464234584931128818206821412412234208121884221019 +:804E8000827438E45201244A321818320020021D1813624A18412618081244291A0E7014D814CA12D081B138A42119522489440812427044B82821F42C128C8244584230284848408A418211C224127F840422108212E41831286011003042A116081243518440088486041088021062412280042228804214085048929884821883912226 +:804F000041008C286281F01C99244C82B31892144B211C1108167D88C411341A544249F12A16922CA1184423CB2C448D84C113321963321836AA42222E16C143869424842C61844B12421884437598C2828321B818C4421AD268112822288211B8D4068602212842284F22012210C828896881811018D44822514810088849C42440812451 +:804F8000D12411A8425022122A41B424618889C12C2B82842112248460810018901AF0482443F2B17420922418008121A426212201141820092088413AAC82003818A85048449024C0284228A02412299218A9328441128489428221022284221004429F350A848141441B41489180215112892111A8121914228881288441024282304119 +:805000008362241A7221886164182E12240022830882128B128008381012A41C4120849224F0EC8320088721100814004008846C04448210B2642889084410141224234242140A40044C81112801448482812E824440849112812361888E128440F8EE8800106121B08401442487414014111A984289110484211118A418910000284200B4 +:8050800044144CC14244D0484405A28180A418C99228499428411084248421FAD139304516084A81410A4008140010688100100A442200302C18450860880042239118254804418001481812821218002048048034129F3F0C1200504100B06101442D1C800180C8182041943882848445224408121A981134C412240012301240588441F8 +:805100002880210441241088252111048D4E00C0481098124E161821200148008247A1D042048490481004602252A18304181A460444282412888A31A22081080000444200A04232F07FCE203184502630829014244D2800A74146A414A514D24A414A140236480684224B144262A1235122102A8404A512048634145022222F2204257233 +:80518000A8642482A4A01444189489F4CB881001198632844124404492482504286180842221A418112111890198002321644485012C44144805850181482AA14A4004680000289128C4292CBA7F06137388E813219481A72125D882E121F1283AC1F0411521D029B84ED842E129816184C11E882544D848DA82D541D82497162F2B71268E +:805200007C286864278341472343E18344783844EA4A23E84218C26216A25147224F2443B84A029F8186F448488D174AE665055C74A4548D16D62491941667611B2245E425B11A11FA5416A7C56F81C112C783426F6C3A923F53AB484532424512E42667816E484B641CD124D182D624F1724227C48161AD1186D845098D8C5E68AC638E02 +:805280002D98242BB14467418654424D84CAF332144E21BE884BAE8021419236AFD1C44C1314744E3112354968818D482CE34C64898612FE1848C969888B329518CC193A721438688F2152889F2D341243F148441D1489D172C21647236B9483F91EC84F23B38CA183984B288744858CA4821E4A8F81AA141694244BC3817FBB0D139414A3 +:805300001143924110111411140148644854124448441A041A44854481410114800289021992141902193242282304632468246024602422462212280810F89EFD141F12E296F2393F1D13FFD4F454559F14F41911BF95F53A37FFB555BABFD4D48CD1A8F3189BAF91F178F8AFA17988E8A8F449C88F9EFE524B3D418FA2F673733F27F7BA +:8053800013725FB7F59F9BCF89BB34F3323EBF72F251633FB3F32F2CC5F55C6BEFEEF6FF6FE764EAB6F2B3DCB988F4DAD88FCDF95A1CED4C8F8EFE7CB84F8FF9B5D48FE8FB3C7C4BBB2F8EFEAF37141F12F2656D9FF3F31152FFF4F45F55FF55B51BF15B5BBFF3F35B5FBD19BFB3538E8FA1F71AD3EFF9F972FAEFC17D18F88C4EAF96FDF0 +:8054000039398D1B7D4DDFFAF77777FFEFFF5774DFB4F71F3BFF69FB34367F61F116162F24F6232D9FA1F16E67CFB1F2AF2DAFAFF6DE9EEFCBF73E448F45B7D8F39AFCCFC8FD5E7CEFC7F394DA6F83FFF4D84FDFF9D8BCEFC7B7B4EBA7FC85E5F065453AF4393F5F61F35F1D4F45F15959FD1CFFF6F43A16BFF5F51A1BBF95F74C1AEFE4D8 +:80548000F59F9EB781CFE6FF1298CFC8F9D898FFC1FD38B9DD1E37A4FFF4BA12F374472FA5F5745EEFEAF8BE854F41F3525A65FE76467D668FB1F11A12F762EFCB714FFFAEF48FA3F7BA78AFEBFB7A382F21FF86D4EFC17146F68AC8CFE1FED6ACCF43F55434AFC7F6B8BCEEF81B34145F53F53C559FF3F35636FFD5F15E1BFFD5F51E1CD6 +:80550000FFF5F53A3FBFB5D493F15B3B6FA5F17E5EFFE9FD9F9EEFE6FE56DCCFC5FDDC9CEDDD9F975FED77E4EFE5F85351CFFFF75A78CFE5F71E3EEF5BDDCCF27E7E6F61F57353FD24AFF3F35A16FFE3F1FFDD8FE5F9AAFECFE3F3FA3CAFADF9BA78EFA9F9CE9CEFC7F11656EFEBFB5EAE6FCDFEFC9C4F4DFB7C7CCFCBED82FD457F2002AD +:8055800000000020412201122482444024482449041092282189921283948442219014100218844909224042486281404864812001124A02EFF40C438802446D121E486041C024A140425848418971141812847124481144312287512154E05192824424444890184421446049454248A2282443114818528421848F44381481226FEF0559 +:805600004D421F41522C1FC132481F41364E1D24EB141D24AB9419F24A9251AF443935AF5439A42F547934F842B54F83E414F9244A4E854FA264114FA265192E4A96E5A2E449E2A2F491244F32F491248F32F1912487161F49766AF1816CEB141D64AF249961AF249945AF24B934F44AB24B42ABB44F8A94B24F8294984FA2B4630845D22E +:8056800081D624F1114483F41164E5D2C1961619D64AF91164ADA213D1483A35AF44B9A4D45AF334482F54FB36488F14F926528F54E922EC54E8A2615D266A592E4B8E252E528F49F2244B9E648F32E5497268E1497662F1816CEB1419764AD641F66A825B68AF24B9A4F448224B4A8BB44B4AA9BBA6941A4F22F5E9C440080000000000BE +:80570000000000000000008800800214008480048008220000800200000040017F514A2294112411404544C8481D121986791108D449245224124F832443082220B212D28441024881272230821F288431812584C22620116B882A019E42888484884528A14112430849F29E557011248831282ADD2233584712308440294485C41283C811 +:80578000488A4222B864886188214480F212888416A48210C8122230382C78942831144422434198228001267441289822144483C125819FDB0F4671410880FC16214CC521425B1867168D11264954944B4129189C828CF3A2128C82F1388260621AB218C898251894212185C2821B8427848F38428481229114B145383C28D2239828853F +:8058000024183C1246C112811428DBF69016122CD181A212104A1C0820A81411429028483849044B48000070240220C58828211222121882EB8216140622922400122072482188224134944C52847F3C071410420884831481C148244021482103C02113CA34221014080012238242428401401416911A4480324C00820042478142206456 +:8058800082444301A2BF680C6B341226E922C129715302423B128B25B28252427016781A61814C3148462422048B2449334AC14E1890582024BA44A13816E181C8421678974204A92C2415AAC11C216888282A38124A2884042BCFC05412111602A575480452130100582092142D188C61184A21044884A01221C128281800A21886240100 +:805900008C91122338244598C8428E12804C41C8882882A142002AD8AF4D3221702298289C02131201A3E6A285CB81881C642181111CB214322C438212042E48448C64211E48C04A445890443865F181182354844D13201402488112529624044AA22149B8442104BF6D031C31442C9228160B182225183213228F497282022144124728B1 +:80598000241688064243312449420410B221810184882626288125082021914428228200121E426A412458825216F2F932504242214014481464112850B2444C0389C22840B84C81D84A982824568A48022D98C3C1121165F28864C425158254C22120124E449214AC31381E448C0126180C242AD1424128B522040050214844100A100830 +:805A00004049C816102621220418818810489824400800122820C121C0284788188449042048281818064489012844F0E6E2C015442342F91E429014E962B12C12D881B21A78830E6C514823C18827C41AF484288361A44394264D22859638856281124C916A43F1268129A281671123E588C22CC116E841844598928E4C98818B21C38539 +:805A8000D568818863C4B03E0D21408242410C10023C01205128268812C41432A988840289088160484901272290840044218C02C082124110A2218112815042D04202384588C1425F72064210198924C1488CB2184408833124608649416845481428456821200448224A8882C48550A424881129211182021A0820294182718488C18657 +:805B00004B124301422212888FB20C8C022D224A02938201A082242211450884A2882D124482801804C40081867884022028483284438822018410442402490122230800224004121FF70600008420021004A4400228120026820140180645180200842E8421C42042823818881012144202648041040040280442DFD806A490411021589C +:805B8000221C1113B11A0CC92121281886866881140080682248A48C4502258284012041582410044394184A1288024B242034184210220110F2AD7E3081124126485C282084023C0224002722C032168282341248C04216084440826641408204849018A442808204428A0486948460C421478C8304214528F163CFC0288430422E4280C8 +:805C0000444AC2188C0840A81248128C2832892885447488040012120080112151827012018008834128416441A021308A30142001169412483FD50540E28204001890442AAC142A64848A92488C211862448008009810023084430121C444459214822141818841208862820090140000128882885F75071D442830112428C041404201DD +:805C80002B1898214C08218810A2614BC11002B06861484A02B08424E588222418282814DA28641CE0411418A8428A9448428004004004EFCC08A4814880825121C0321745281DC42449223842106C8243D88504848A8491448949028428894501488485811408428881308A2C684482192261828A01E025028221228E9CA0468788B53C8F +:805D0000536490528D122E54812DC12F26F214BE27A8AE884B9238AB138B486552388741C7412534866085268AC8222744944C58C94D2A21B7D12B112B835624428855648C6188A9C386511632AA122F4183A8222D124F4441A212DB9EC021C0238F82F448682F23633417962D286F2D7881DA89541A8D84A9F4122A29E8A4F44492A6BC58 +:805D800092DC84856D8848A4ED424B618F48F4A8CC48242F2BC4528B4964A6F2888A47A818CF84B8C878C77C18E84FF448222243F7421483A445CFE8B94424741228A5284D1CDAFCD6D250252F2122C2211352981E28297451F2217D8B3792424B114E328F4C7494FA84A42B239DB11F462222DC2CEC24F81C6490182F85014F23FA1ED447 +:805E000043B414F84284C849199518A5BA8244B2182A94864B835EC8A0C94FC8DBC4290447C14A4588A881F0AD1850414044418441440100002041840412004220044218422084218421044200184C14C2442148214823A248214821482148290240082F2D4DF161475FF5515D5F51F5484AEFF1731A5B9BAF83F12B19FF11F589321F5F77 +:805E80003D98EFCCF4DC1C8F8D7B68F85848CF27FDBA98CF4AFA8C88ED8629D8A831128F26F21612AFA6F2A6A4AF88D924F9CA8AAF2BEB2878165C158F69FC869665E628F4BFB7DE9AEFA1F936322F2BEB63D533D12AF63AB28FA1F95216AF89FD3C3DCFE7B754FDDCD8AFA7F64747F061657F43D799E281F56C4EEFF3F37A73AB73EF457B +:805F0000F5FBD1BF5BF9A932BFDFEFA8F88E8C8D1889B328F35CECCF26746BFABCB4CFCDF91E162B8CCFC849F838AA6FA9F9A2A26F4CF88A8F2D96AFE8F9F6BE6F68A8CDCF28F988C68F29D92A7C8AF2AFB72FE8F98A9CAFEAFFAAB22D327F51F81E926F62D3AE99166B98DFE3F37674EFC4ACD56E72EFFB0F5F32F4115795F31311CFE4A7 +:805F8000F45B7BFFD7F37F3FAF83F33F3D9F4DF591323F1DDF64F1DEDECFCEF2F8B8CFCEF8D858CFE3F9B89CEFCEFE1C5CCFC8FD84C48FA2FE366E2FA7B636FF785A6F63FD18CB6F21F5DECE2FABF3C2C21A5D848761AFACDD82F8C44EBF17F3D89AEF8DFDF2D6AF8FEF2577C3F5CAC6AF86FA5CDE2F45F1DAD8CFE1F13E7C2BD1DAED221F +:80600000F39FC9F065633F63D3FDF253391F96F47F7FFFF7F73F7DFFD5F5BDFD9F9BF1B13AFF9DFF1C1E6FCDFDECACCFCEFBECBCEFCDFFBCBEAFCFFDEEFCCFE4F54C5E2F2CFC7EEE6FE3F6F26A6F83FFFCDE2BD5EFE5FD1656AFEDFDF6766F6CFC16D4CFA8795AF6CEDE2FA4FCCC4EBF37F3DC9EEFCDFDF8FAAF2BEB2DFDD715CF2DFD6610 +:80608000AECFA4FD56144F6DFD5E5E6F43F61CDCCFC5AD229D2A200261702641782403260326016088A0482C22898204820010022181698102908210042908988440882828420812400800124E248281F01C8F204804283412904141134842581241853214105422224C391420082144218A52248241502244490818860882208148040023 +:806100008244C01441814121844604EFAC042CF4112485F2112C87161F41B24AD141F24A111D24AB9619B24A19B54A3924AF5439342F147B24D812F924481CF9244A8D814FA27418F1244A96E1A27498E5A2F49824ACF491242E421F49722CF29124EB161F49324E1F48B26AD141B26A9921AB9451AB9443B24A7924B8427B2498B24F82F8 +:8061800084FB244ACFE20CACD141D628D141D618E141F442111D2C65D1C1D24A3881AD2553F148A443D2527914F84A855782AF447926F848B12FA2E114F824925EA52E12D661A2C6E532E15CF224129F4DE2A2E149F42C4113B92CB191362E1B69E7121FC1F42A841F41962A59D61A99442D344B4929BA2494326F81D442FA344A7F5204DD +:806200008480040000008100280048002004210080080000140084800400000040040000000040016F1807800144232194322A018B4222390D488074C4C182902820E584014825423414884334841628822231141AA8822349289988842200204522082922B8124A0A4846A848FE271418A67121783229C2215036224531122608160E8A74 +:8062800062814C827384821544D428022E442883860224F012488165820218478220A61247221845484818C8844A614A8C5D48145AC888819E21C1EFE447014E29AC52781AE21462214F3201C73249B22321721C8222F881584C0A8F2862214B1483242334E2F01468824CD4247811CA48836221124E982C3284A018884D2A22C18481874E +:8063000046641A6C422F8A514819C3882532488F11CC845F360F1812141A023022208284E1880448A0424490324142C014A450244C022800A02124444302981E2881688B12800100188220282498821A948880C2485F5B034110022215681244411124150800304284288488100840E21112E21402C018200225024B82284AA128E0810298 +:806380003048908210284204A04144436244F03D5E804284421131122C912124B0A2248251628420D242225842222A34118396242F9254484425F44224361634544314C41412848612488A84285684218C25E4418488416885260C8CAA1420F69C7600442114143D18224C0214E8281245420870222C1824AA248381C424A4164E64422713 +:8064000044284CE1412444644140A482836428A01A28C4A3848198448112816082100842229F11074C02282002165112645022942400306260228400142648E21432212419846261819024249012890A236182488142008C344212822844834524E542B8241584F4E7C980240545014D1890188420C82244815642095982421841982122D9 +:8064800021184200282942841241A8484440982AC18489024E124F88021618088B24223022109842A025DFE50D2034184008414071440291C41F280300AC014502690841448A11931241005024918CC22442899122521AA22424160849A18260430045188421012F422164A1CF9F0800C0281A0228432211081A04211190144028120445C0 +:806500000846420C8D64214A51848421441880024100124501804408481212421A1208523024D0714D81041638212E18CC014C43C844884E1AD02128146A414FB221624221504143D262145423CC11A4252D288421C42AB1248892182D2889C2385E28556281242E9826C8188D14B058926C2646882165414996483F36068212400C302419 +:80658000841C411892218562811C1101104848758498280084422E420044414C1202484440B44241048C021A242408481800123810A84220F24ADEA01221209112872389C12C818592A883322880124808288128188012082180022148614125124404108202830441A9010040044B1238181885042B121F5A04C42830C844C024122823E8 +:806600000216062902127024187222144241410416042200844483821128C228A4800118184E148B1800F0C1221812188622846282A012F02EC7601B46429224161C24110860220041102242C124188C8282410884408802A4403818301600221612A441443042005800180022200840F8C97340C814110048003502414C440283322411E8 +:80668000219140544940D248820218848C42140840440318C440480184400584428424422548420228005F7B05404C225128430141288110088184000000220040682200842222004902840040449824610000849028442A0118C0184964124FE20C4121848C3222899224000028440010440400402282111202412722424984621200413D +:80670000252412042283241324031859A22144284444306C44321AF439720000410081248001006C0185551881120050128901224185044180014412840024004C045028818C1801242C0810D248022810D84408848A1202118825018122911001420026123C281284122400262206413829C11624C012181869018C1104846890288CC24B +:806780001284C04821C9014C0141F027BD40981848A02800290448212546840225023111120025042E128008258A61442814844048C2455094220046110244488C622290144042024221F0CA63A022CB68F03E1426EC214978187823B82862A8813C120C491266822E3526A43236C11785382C2C5126CFA2B42C7224E865B414B218524836 +:8068000025EA423114456461497112B448A4411CF48E22B301118D412E221E124F21E5227318D4847134C4282E212E284FB40455A61AA1A4871828CD2744D0A2A5225E288425C42AD426D24F128F5384911361222D2A2D24282942586225C84423F212224F416221A762212A721AD584F21134C3B41EE3458493A88B4547AC1A312CA37637 +:8068800016542236F28848C9F414141AF129EDA01127E11582B616736EBC32F124428D22505A27226584316AA3519934A487A1C02CE04102878222122489B32CB26A51C45D181047E8B1110E8312C42C464E484CE8823111A5D8424834884B722992322E1448A9F47BB8100111102114A114114A1181012C012C0118403214100541001202 +:80690000218001188011811181119112151812811881082C088880080000F0B247141F39F3622C1E1ADFF3F3FC795F65FF5B781F54F31B799F81B739F348599FD1F11E1EAF25F522329F93F33C3BDFB2F22E3E6F427215F53D39E7C24FC2722AFA3616AFA7EFA3F22E1A474219846291CB322AF2242345F527219F83F22D2917353F13F348 +:8069800051123F37FB9581AAFAD99DDFD1F991936F6AFB8A9AAFA3FB36BAEFE2F172543E187AF57A6A4FE44DE162F363659F91F12F3D8FB3FB1736BF47F76935AFA1F52B6ABFC6F62839BFD353CE8F84F421399F93F33D3B7FB2F22222A7A27751DF93F33A182B22EF6A1AF26AE8CFC3F22C3ECFE4F42C3D4D248FD2F22B273F72F26C6B08 +:806A0000CD1FFFF2F62926AFE2F26A6EFF53F37D3EAFE7FBB6A41F12F27878DFD1F991936F62F23A3A6F63F932BAEFE3F3565E6FC7A711AFA6F7CB31144B334F63F7353FCFF3F31912EF61F97E3B5F73963A8F84D2D8F2584B3D3165F64E4637319D199FB2F23B39AF82F33A38EF93F331358D18A42FA2782EFE6A6A87A3EFE2F136162F10 +:806A800031F41C3E16F835391F11F214763F63F2333687F1EFC3735CFC79722D5BEFEBF31A9C8F83F359395FF9D5AAE922D3AEF1EA7A4FABF33E1EAF47F53E18CFC6F4687ABF29075F7BF33676CFE3F33E3F9FA3F35E7EEF76F33C66BD19AFA7F34A698FB1D29FF31E1EEFE4F4332B7FD2F3292B7FD3F1363CEFC3F33F391F73F3281A6FB7 +:806B0000E2F226AEA5FAFA7AEFE3F22E3E6FE5F5727E1E36DFC3F3343E2F61F31E76BFE3F37B3E8F51F1383C9FD7F73D36EFF6F7FA3EBFD3FBB9B18F85F79D5F2D926F6AFA3E3A6F6FF7B63EEFE3F35C5CEF87F71C1E8F86F614ED40016F12012501144001140040044C125128803211280080125248B04812062120022170220245022202 +:806B80008C240280444348028D22200485044FD709221504118B1213011D24A7221518C828A10010382420912284408242082240428481E2A241846141C024896141238412421408890121433248224C31241826082E433F65022CF4112485F2112483F41124A3D4C1B26AF18124AB9419B24A19B54A7924F84A9143F2429347822D955FCA +:806C000082C4954FA2C4854FA2E451F2244A96E1A2E459E2A2E449C24A1F49C2421F4952281FC932481F49324A1F48B24AD141B24A9921AF2419B54A3934AB9443B242F9A44829FB2448B84FA2F4944CC04A1F4146F2116CC11B21811D24E11318DE41B24A1AB548BA25B44838244E8147821CF92748986FA2C5814DDA4E81478286C14A39 +:806C800096C54B96D5A4F491283CF4916C3CF4912CC7141B29E7141B29A7141F417248D541F24A3353F14A2443B24A21D242F1844829F91648886FA3F4D69340280800000000448082810200000080010000000040080000000040042800000000004F9C01223011842E5268302124998442094021328883844454488042C8421449A6240B +:806D00006228488C815128801184511886088921C48DCB285883084C018984B28421A11228844D2846F259B480F18314F0A612818218F0128849C8881219E45804868492A484424A62865D488828472281C721843024A827463AB824A42822886148C3964216A41248A92287210C4C32984841462435C41C44F4FA6580F2C619F0861A5E18 +:806D800028230E1123584322112655411CA28282C31628542C50948349627A4CE443344AB04472919816A400478424C18CB4241482748469224F8421A21258288D6489694116C4242E522042F6BA5F80011C8102808192188E48896881428A044189222814A4242E484A024A028942882202224AA2924E242A8982198148B84861412AE1DD +:806E0000C824E28904430880A248A041F084488744484EA6004001830289912121482284000021002044080045021812AC2404128002100481000020C2288112004A21181284118442F82AB9242443C3182332522269842454248CE819244402418B144B289A522C4044346C90481C849482493314C396266314043902287244C3922462A1 +:806E80004B288308184CD484312422288A24322C891204A77C4002182992422458683044C041001024B1842258482304604460C4480049036230464C020020044400A28388220100622C820C83122C12F8DFF624E044430989235284142304A33A9846C422002D48A02100E14426082C61181E4298469A5445EA41028424266144288B12FD +:806F00004426C82462444312382843751864421282302416342244187F74012AA112400289824661842C231A084054432A819328814B21881A042C0230181880082306498182C28289223121C821301C944A82B4822484814224083260447072061012844108800188804108008224422A286442224441469444409858800248A0844100FF +:806F80000020030020086082921A040020014F6D0611100900124031488448109A488B84C1901400002800264A140422001A02206141888C128802004A224858481084142862C24508005FE20617231A0212A1811290412C6B8A8110C244B74C8B382E128F4132A81A868292244722C04887418321218282841324341486C4A82E18208CD8 +:807000000285C441488678C42814A425C1828574180418F0A55D00501C0028621311C848A0418184814004424034844A0190444C1242C44882242848122A88C212001D282622011283A22846026083881A8422820246041FC906250200211008222002200884881082042220084800800420089A1284820122002002188011042220C21407 +:80708000414C722448A4422F520F16C424B0128201304400202C290100208429048248504812444844443220422412C22432009024802A28010044C01468488924815484EFB7072442208301812002284A48840800108281848228044985014248412800322604438122020022A24988A1124100203314424C8202812F2D07ED188F46A4A3 +:807100004425020046045044444BB22A2312880848C2242552229AA1118B888A68484004132188D28C58A88B646AA414009024004D14444B2228224C02442A4464A4E7212D463E54FFE8020000002002200100008185042008006042000020042002008222000000002028042021420440F4621310781288840400A0140041CC228302002A +:8071800012002502211898828800264431211C4298288C644448000082004144222800000025C22429B1D8098424481800000040048C0200000010021880684244442042410484284841A028000088442A888284880420044421288FE902298144021218000044800300000010061880080020414104860C482200000050448002004004E6 +:80720000201802186F1B0C001210222101000000480000000000800200004042042604228200000000000020040084411605A5384C12422244000041B024E28222023088124052222412A08B8A22082218131231218538188B44CA24248802800C4514382420220100401252281AF3367340D2888484140200524044544CA0220000001094 +:8072800092122A81018A0800411414508484224A0400820044444584A22242200880382421212E2C40041022018418001200100884002800000010044441C02220222201448008000088842044820430440028F0B3FF001280018001141210084820010000000000284820021004002008448002888820280400001004008F6C4442061AD9 +:8073000041321200B051011A112861848001841A010000224C226242702424A1224562222812124B2249AA82002004821028044A810480E44828D2C812F456EE10B2121182011A212182040030184250888D840082440000104404266444C0244F4288022028E84208008880A8882004802895244004D0360C18442423814394181880013E +:80738000508810080020020000222828489034A0224160422E248244A028A0288A088881008AA448234404424141222E24BF64042F22D222A2122B111229012C512329F812131F11B189F991898F84F888418F842454911148955C884E488F44F424444B242E24222E2480524445A6222F227212C2122B191AB88228E828592229F81213E8 +:807400001F11B188E999F848888B488F8424E4840448855C884AF68D8DF0262625A2123A2111021C5122213CF1111119ED897818F88841CA2464941501848588F4484445B444A22622448052424584F3262625A2321AA1812B8982502229C81B1B1119E889F818888B48CA244408405888483FA90100141100000000000000000000000028 +:807480000000401808000000848100000000000000F07D9C0040110100000000004042024002255222250240424202008481000081810000000000000000005F7A0E0014110000000010024002502224000024250885020040588840180810080081000000000000005F180D00141100000000400210020021240010028518080040085001 +:8075000088000010181808000000000000F0746C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000E7 +:8075800000005022212100240000002125021012020000008100000000000000000000EF7B0F0014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000CF +:80760000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F54080014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000E7 +:80768000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F54080014110000000000000000000000000000401808000000848100000000000000F07D9C0040110100000000000000000000000000008481000000401808000000DB +:8077000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F54080014110000000000000000000000000000401808000000848100000000000000F07D9C0040110100000000000000000000EB +:8077800000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F54080014110000000000000000000000000000401808000000848100000000000000F07DF4 +:807800009C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F540800141100000000000000000000000000004018FF +:8078800008000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F5408001411005D +:8079000000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C0040110100000000000000004042420200000040180800000084A4 +:8079800000000000000000009F54080014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C0040110100000000000000AE +:807A000000404242020000004018080000008400000000000000009F54080014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC70900141100000000000000000000000000004018080000008481000000000000DE +:807A800000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F54080014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000068 +:807B000000401808000000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F54080014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC70900A7 +:807B800014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F54080014110000000000000000000000000000401808000000848100000000000000F07D9C0040110100000000000000000000000000008481000011 +:807C00000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F54080014110000000000000000000000000000401808000000848100000000000000F07D9C0040110100000086 +:807C80000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F54080014110000000000000000000000000000401808000000848100005C +:807D00000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000002424400221212140020000400881008100000000000000000000FF680700141100000000000000A3 +:807D800000000000000000401808000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000020 +:807E000000009F54080014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000021212140020000002163 +:807E8000210081240000100800001008000000000000002F75090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000404242020000004018080000008400000000000000009F54080014110000000000002421404202004012425828000010088481001018088100000085 +:807F0000000000001FEF0D001411000000004002100200212400100285180800400850880000008181000000000000006F47080014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000073 +:807F8000000024242400002400401808001008818400000000000000009FC8050014110000000000002125120224210010120221A10000841048080000818100000000000000DFFB090014110000000000000000000000000000401808000000848100000000000000F07D9C0040110100000000000000004042420200000040180800008A +:80800000008400000000000000009F54080014110000000000002421404202004012425828000010088481008181101808000000000000F076DA00401101000000002400210010420200215088810000840085080000101808000000000000F07684004011010000000000000000000000000000848100000040180800000000000000DFCA +:80808000C7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000024242400002400004042020081818400000000841008000000000000F0731D004011010000000000002121002100002121840000100881840000101808000000000000F0BB1A00401101000000002512120200EB +:80810000240000002481240000818100810000841008000000000000F07EB60040110100000000000025022100000025028100008400848100000000000000000000F02C44004011010000000000401202240000502240185A220081008184810000848100000000000000F0BFA7004011010000000024242421000024000021855A2A24E1 +:8081800025020000818110181818181808000000000000D0840E0014110000000000000000000000000000401808000000848100000000000000F07D9C00401101000000002400002125121212121202A48548425A828484854808008100001008000000000000F04E9E0040110100000000004052222421251202002552222502A552227B +:80820000000081008100008400000000000000F0162A004011010000000024241012120221000050228184A542020000818400000000000000000000F0C431004011010000000000000000404242020000004018080000008400000000000000009F5408001411000000001002000021000000250A0000845088400800004018080000008B +:80828000000000F0573600401101000000000050220021250200502240180A00401808848100840000000000000000002FEB09001411000000000000100200212502240081002502100885480800000000000000000000F05C8D004011010000000000000000000000000000848100000040180800000000000000DFC709005011400100FC +:80830000000000000000000000000000848100000040180800000000000000DFD10A0010010000000024000040021012120224814002008481001008000081000000000000009FE707001411000000000000400240420200100210020084008100001048180800000000000070C50F001411000000000000000000000000000040180800CA +:808380000000848100000000000000F07D9C004011010000000024242400000024000040022400840081000040181808000000000000F042F400401101000000000040120224240000244058280000100810080040181808000000000000F0B857004011010000000024002100104202002150888140024008508800001018080000000014 +:808400000000004DEA004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C000015414101000000000000000000000000008481000000401808000000000000008F5A0200141100000000000000000024242453 +:80848000000000008481000000400800000000000000F04985004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000040424202000040020000244002400810080000848181000000000000002F440F001411000000000000242140420200400284850224001008100800401808000021 +:8085000000000000008F1C0D00104141010000002400210010420200215088810000840085080000811008000000000000F0D343004011010000000000000000000000000000848100000040180800000000000000DFC7090014110000000000000000000000000000401808000000848100000000000000F07D9C004011010000000000A2 +:80858000000000000000000000848100000040180800000000000000DFC7090010011400000040424202000000000000008181840081000040180800000000000000AFC8030050111400000000000000000000000000008481000000401808000000000000008F410C0014110000000000000000000000000000401808000000848100005B +:808600000000000000F07D9C004011010000000021000000100200000000005088000000401808000000000000008E3B004011010000000000000000404242020000004018080000008400000000000000009F5408001411000000000000244042020000244002000084000000008400000000000000008FBF040014100100000010024070 +:80868000022424242100400240420A40480800000040180800000000000000FFDA07001411000000000000250210020000212440180A008400401808008400000000000000004DCD0040110100000000240025022110022502002481104202000000000085088100000000000000BFD14B0116410148488C34242028225858442884805244 +:80870000482001128282A290928001224C282414420882C0482A1184240282202884C224C483A129892209126F6E061964848146591C45D824324866946417413832869884433224C921A329E8988E425646C2523830922388ED4489C484412AA4248146F8984441C364862AB814C4242A8112C4A443043A3424481A088F2CD148BC520C20 +:8087800011994531415443D428E6421484641120018800842822422044041E2226420218A0124B480080028884B0283128A0212200822200462821440842F074B700100800008088A281918948342C2828818A01181852A0480082201804444522464828B49404004A082009414CAC243034848222188378C8B452040040C84810148884AB +:8088000012044084020000288888860221181218211200C8000081802414243244412002000080810124241FBF09420000840022412092240010C4144C019800218200828028A48400428004004548240400220040342430242888881218AFDE0300180000000000004002000000000000004800000000002008000000000000E038043045 +:808880001181138134618C322881CC223E68C0114A08E01102218E48268818844C4A88832414626492A2121A44A282897318048AB41242B844822A88080000001648942442CF99054A031684C222168C1534442181141A143A18121A44A64387441644C4444224221846F5822CC042284902A0280044683624422408114281C3044AA818C8 +:80890000C0346A81B4288584F27EA9A0141883012E424B241E68492214AAC219866481CA21A14136B5127642EC8861C2434464242C82F12156868454224E242F482188A187B022382C874549A148234368442E8182888C044288208234182E1462628FC20B2211411B2170110884C14C1248C8121181000060448088844818088B242004DA +:808980002822000012222822448828801418048218C01432428C44041F7A0224001A02001181824E811962140043210420029028222002002081280144C800001084322848220012004A228122C22482001FA10A18542313F622182CC1348D441D1249E38201844898888328E2821164162AE44148E48482D48456846F8403E9C42243A678 +:808A000042222E144F11024983384422432538248A61368144D81E2C8CD142B244981448284348F4ABD600F01222228C021A120423C98128008A41B44888120819A4241241201614588224468C4824C62449E912014C024443A2168C4A2462161024381C5249A2844B21624014D4A20E18716041236121441784871143E2841371488104EE +:808A80001A0880332428B08C223268E08442B4240512282B25004A4204128842400462922481124A21722822312440A48282F07916206124200210542511818CA1144CC2854E1492181284A0812F4804C9048A156242A0144181A28241812212322882241C13E224210810028A41E82835144C22B1840423F1C2F260424A220241210020E9 +:808B000033822244280000284D484CC22220E843A4284A3218A8108232442601A31884028441004E8889528428208224820428424128482F81F2B347001014028B122688C228000081214E28CDA214800300508284444210488A84011A2284012011922420418404528B4884850210A8180080F46677302428433222806382599228A49878 +:808B800058C087424AB2188A2162C196840AC3B842A2242742CC222855422D284B243034484CA3212A4112C4242CC288244A8822358242A284CA31383624C1C4488B24DFF4091810024542180425A121812840C81496481611A84228490448854428848542188824A982908200B028214832114AE1C11608C0488116384250428A442402EF +:808C0000F011D7202101002444000010042800267124210121C31422A4614186180446244804402402008D44422E445110081046982490449044102412F22CD7C022C022322828208102221280021AA8824880C68400844430288004902489044C84448862424F2104C120748204AC12E4AC425628608889041012B854F295520050414490 +:808C800015C414442022020020840290241843225284904410044148488A240400448041A4C21031810040024304422141622002F09E6640810600481410814481120883822802001848214800888A054302812848D0840200004002602442830424002C444222224404CFD20F18182001E08182440884488004288848800480840428804A +:808D000024220210982842100800A8A8A0611002844822400822220020F814AD1052821E2848A1000041002228140000A0184800281200008100412004490281204412240280D12882C14244841A04422238F0FC6E2044840420814404184A02174418000012A8001008418860844880040084002810483241904690880080881404826554 +:808D8000088A24F299B840210221C02416814221440114402104004410044C02002800C90849821404004100908600188004484C2283424464434440F446D240081C8542012024046046A024430446644242882210021887248841901890181480422882044220088842264A2682228244424202484823A484AF1F4DC2438B41172147245C +:808E0000114B121CA1458714267429A14455A5446681AA2C424AB3E4614323143846425A058BC648448784878A424E444E44448B22442E244E128B44844E428AA4282A7528428EF4222A222149F44A4629FC46246249B2C4F8924680018B3240813251441158421200288A04193221688A09F028482E44848120E48426B844D14844084873 +:808E80004122188D4486A84437581D876F444488B86A65AC4D444D6A8D6287A449716462824992982AF739A830312F4243B53273286465CD24282A2284A2226688D1C124E342B82454441A982449F6444C10F424224D24437924AC124D44C84F828292244B24842841414BA24F283A246B34502A2784504A4AF142844B14274A224C82D5F9 +:808F000042A44625E41F08174410011190414991411819849141184118484C9141850444400444604120810888810000188421C081C082800888804888488848884808AFDC43736757B3B5FA1233E7D21F14D588F53421979357528F83E713F2314115F451554B67BE2417569F91F178984B914AC44C2A16F4286E2F81E3C6D688F52878ED +:808F80004F41F4A874CF48FA84C42AE246E242D244D244C3142F4AD24254677F75F9E624BE32AF22F29ADCE788EFADF52E2E2B9F6F6AF2D61AE7E4EF89FFACAC5E58CFC7F4947C246F62F15353FFE3F31736EFD6D455F129291B2387815F51F5393D13E143E251E145B574E64B7A21F139398F83A3B82B4485F84858428FA6FB12387EF879 +:809000002AF36C7C4F41F4297D4F48FAA4E54FC2D644F4646C45F424744D546FCAF6E2267F66F277776F4AF2F47E2FAEFEFABEE7ECEFEDF1EEAE6F6FF9A62E6FEBF78EAE6F69FFE6E44FC1F5283A7F8E4BB262F63566E5FD1436FFC3F375749FD5F564348F86F675349FD6A6364AB651F145414BB6EE644F57F144414F47B114B126F224D2 +:80908000244F4213F42CEEE5F83C3CC5F83C2C4F4BFA8C7DCFC4724CFC242C47444F42D644F214344F67F7EC2E4F62FEA6A66F21F926A42FE3F1AA8AAFA1D74CF81E14EF6AFA3E7EEF62FE5E166FECF836746F42F2DCD44FC6FDAF72243F16F73477EFF3F31636FFC7F73435CFC6F664749F96F664658F87A7745F14E614B454B544EB4EA7 +:80910000FE74554F56F6F4F44F49FB2424CFC6F64C4C4F44F47C6EEFC1F1AC2C4F46F67C6C4F4FFACCFD4FC4F66D6C4F46F64444CF4256447AF37C7E4FEEF2E4E67F6EFEF7F76F66FE3A1EA7A2CF8DFF4CCEEF65F56E66EFEFFF6EEEEF67F7642EEFCBFF6664CF4BFDA4EC8FE806230221B026012A01000000A048000042200442B0480279 +:80918000008B24224243222402430200240048C048248C0484244880840200CF1A0B48124722440042446220064200A02443621443881304414C02857424084882100844004180C1684AB8812202221002836482A180022324227424F16A75C0521F417228F2112487241F41324A1D24AB141D24AB9419B24A5985AB944782AF1439252F43 +:80920000147B24D812FB24481CF9244A1CF8244A16F1244A96E1A26459ACE449C24A1F49C2421F497228F291248B141F49324A1FC8F24A111D24AB9419B24A19B54A3924AB9443B2427924B842F92448984FA2F48EA4C04A1E64241ECC241E2C428CB24EC1282F44C9282F445B84ABB44782AF1419B14249D812F922482DB12E528D812E22 +:80928000D216F122CA87192E4216C1439E212CF4912C2CF491688D4217484AB19122E481F24A111B21A7441B21AF443311AB34322324B3426183297132086D585FEE050049040000004004280000000028008008800100000048200200004004280000000021F031A7808101263122812082A21828182034482A289A54608A00222088C4F1 +:809300001141100820D248A242322C1224826232458802180020110242223034802224FABE47241420238121A621992115222814928900A0828852288E4CA0422C243228802286222D2444220C28A0488CA1841A28A4242A0420088C0142228118C8A6018FE304184A2162222280024A233924462262148C822A9A74A09226C288221AE664 +:8093800024A8482E1144200611684E2C89266D26002226212C8AA414412082992218A04250842482489AC2F75012803111188C86F11128248028018628042088C848904400201208288428D80030223024284A6881E112802206004028042832182A840ACF1B0F2215044CA2161A8201218C168AA2849018842009928111814889082042DF +:809400004468412A6148808261410026028002168421A184008218806288428608AE4A7B9190142A81C21182A18062A14CE128E33184511AC84AE3A4C822A2224B2142824988424C9248624A92622B482AA1284443248ABA84B212D424A3529AB4C8E388A486AA049DC4C28CA5284B188A810149E244034FB60541132292214A2203C018FC +:80948000A18E1219821C31188CC482A28A2228013084884508262864842F2204448A322441A2884CE2224194428826684142BA04481088292122811424622C6FB504384C014CA181252821126247A9A24123112AAC2189841122732498418C88648240829424284CA1E13A08A0141624622848321AA252D24E882A09C2C7184A882D328466 +:809500009886088E284B1426F8FC6F202404284A3228F01622426C014662442181298802134A1892A650484886282192241E28CA2298228C62848230D8814889C8161C22847194C112984608881A2628B348032842F08819244CA12416161824C128C098C028284CA14820C21812001221A029412A1C1898124470280148458824614450E9 +:8095800024C06800224304209284284308890812460212DB2E8002301400108828020081602148144901838A01008042441802441882282100281222820042200880A114B01802E0822888086F9E052A84028B12421E282638262F84612222682B142784843AA84213A138842B124B2190A84984E281524827831E2450481AE28822228C71 +:809600003198284725824FA82582A4428A41220949A8C2F2A21EA889321862C8F078A6F08618D024413424001608161408204802A9015490888210048C04224425A82C2E82806444211044088C221201124621098C8421416481A041A882009F360942200128200284422448482184288A2502429A722228D882882831240084008668180B +:80968000AC842228682A82830200818128202102828128829A842228F817B500224142834543688142238104411C1101001A0823241108222284292212648421291296822424414002301824223018803248818180C822801188F4348560885284008A02230228C02841420021424284810022800424814A12480883044210088410082609 +:80970000088284C638488200224842483024F01674501200181489E114421152281225470816066028200620014280E444C14420288494122088032F8401499514415084424400444212818F22918826248481F15D8E008002224A01004A08002C0100282C0200282012D2280222840080140210120200280044200222A80000882324E823 +:8097800018F17D7EA06110C8512F8104121C02272246440700AC58481844894884480C4C08440020C2218718282A842428A32849A1212800A8824444280018204902882904CE9D40CC2A0049C821C148133614284C73585381141840B288C41220013A1C4202848042C24421825042608816A22800C4414C012F486428122410883242401D +:809800002802F08F3524228728C0220080840288008146882A88418268498C280A41224242898404008440222142B82801008182818A1214A841422A088410242824F2BFFD00C04140E1286435400936484481622183E141847838048422274181244288264484912289C361008C0158101474148A248284C4448002824044324818F0120A +:8098800024481FAF493222A69A2A182F48F588412E613E288B448B83424810F949198F8811A2182F86F882622F85B39AC32CAD2886B422C56A66D888926C8B86248BA4A14E282CF112822AD122FA142A8C72147214ECC252CC8E888B2444122A12A22184AB93CAE24129F56415CAD477025A3288145A5681248D1E271415937249C8333738 +:80990000942F9561212CBA84A185CF68A59447488843AA43496624439262656482ACD2437522B81446A24A2A11F8681823F234144C8242A2DA4B441E884B4883A414AA94184B22AC12528490482AF86C2AD04184D78451218F17B27133531D422E2846F63A72B3D26C056123F358C42E221A52888968828B918E822E8228874447416AE462 +:8099800024018F86E228E4BC98C22744826FA92AF98894428D1889148812B8A2E482D882F184484E888E8881CAD4A8FCE242AAAEA91AB1BF4452412444148604441844404802244110044190449044100621830116146241604140044400230427149012901248211618022141100445087F364E7181F15716EFB3F33D6A3F21F2BF2DDFCA +:809A0000D7F23C249F83F224348F88EF21F11B1815F151532F6A53EA6596662FE3FBF2B4CFCEBA24EAEEFEA2266F2AF23274CD26EF6293364F81E5A5F694B64F21F9BEA2AEB26FEBBABEBA94F8E4E4E761AF61F43D675F54F196FEEFAFFF62B22F44ED25744E7E2ABA3AEB2AFA666CEFD6F6A8284E448F4DF57CE6ED79246F65F11D3CCF14 +:809A800093F31F58DFE6F2FF3D9F96F439611F37F6A6A62F4A5E13BFB75755DF55F7A632AFEDF41696EF26FEEEAA2F6EFA6EBCCDA84F8FEE4EEE49E943F71C96EFE4F546584FA1F5574F4FCAFAEEE2CFA3F266766F63BEBEFABCE84F4FFF7E76EF62F63D67DF56D3EEFE6A6CEAF7E8F2EF65741AF868C88BB3AEAAEFC6D6CDD864F82E88E6 +:809B00008F45FD7CE42F3547D246B411E473F2392AFFF7F67363BFB7F2683ACFE6A7748FCFEF25F15A7AFF54F54D4FAFAAFBEEF84F24FD521E2FACBA96FFA6A8EEE48FAAFB86A26F22EA62F27C744FC2E6E3E627F6467FAF2CFEC2CCFEEA4F68FF82F2AFE8FA1294EFE8FA4C4CE5F476244E1A4FC8FEEAE45AECA1F29298CF4C38A88FAB99 +:809B8000FBA6A48FAFFF6E6AEFCFB3E2F6E4784BF6CF810D1F1DF71D262F53F25B189FAEF63F3FFFC6F62979DFF6F3EAAAAF8E7E41F1597B1D13AF37F5AABAEF8FCF962FE5F9C2AAEF88FEA2ACFEE48FAAFBE6E25EE6AFE7F7CA4C45ECE7F67862AFB4F5AEEC8FEBEFAFFE82F26F69FB98AE2F6DFBCEEECF81F33E3C6FC7F26C3ECFC9FFE7 +:809C0000EAE2AF8DF4D8E8CFEDFDDAD2ABC68FA3FBA6AC8FAFF9EAAE2BBBAF8AFAE4F86EB48FDC022A012E1180013C8124E2812402E081442149A2412CA24889220100A0241008830481002B82B022016941484228420886484208482C6281288242924282BFDA07000080062881122C8804842186C8A2102A08A2888688820443022A041B +:809C80002602C828488240B828283124100480220481800842260822001D16C0421F4152281F41B248F11124AB141F41B24AD141F24A9219B24A19B54A3924AF1439242F147924D812F924481CF9244A1CF8244A16F1245A96E1A265592EDA9E24ACF591242CF5912485F2912483F49124A3F48124AB161D24AB9419B24A9945AB94478305 +:809D0000AB9443BA42792498924F8284F9244AEFC90E1CB411068C66141D28A3C428A71419F242968CF248A559F24A924B422F1479A4F84211478A27146F82E414F9265A1CF824DA8D816F2264182FA26458BC6C48BCF4812CACF491648D421F497248F2916483E448F64A121D448D1619D648BB95F44AA247838B84222F246183882B43FD +:809D800029A8527FF60E848248100200004024C82400000000001800000040010000000000004480020080010025012FDC0B4800215281489053204CE2813488848E1200E08801008982E24402222A044008820012888281828922E3820846A842884820A448002BA52002C8DF3402B08201182832188820222282084521A44A43128202F3 +:809E00004A18040000602284802281E21132228116422492840049A882124281480022178C80A88414F0C4EB2074D208215289A2418813259284222BC340AC814A88021EA82440648328C60420820215282239282E124A8328018AE288028A32844F84A224A2484A2224042CA4E124E214884F990C00202122011002621068881448291231 +:809E80001402A048002002224224810000141028180E411A12088812428400882299088800484B88002008880080080000000000000000000000000000000000000000110010011400775E200231181285C4216228846B121C74118238828CB234A1483CB82151421A82F8854854428542A8241A047368488F82A5A400311816D148B441DD +:809F000088021E287F128144C2846B28841AA14A29484204A89E488D25B02242D281A141894864144C12C4282F1281F491828421839154422E87116B381A782838844E45221D228D18124A2C1803188F42822814C71412896A18669C249127121AF588828423A44149239282248E148B818C223818002008200880080000000000000000F7 +:809F8000000000000000000000000000110010011400FFF4024840031C0100002302148688A84229218881841181B32504000026285182441880410400484B12008281102841228812C4140082C04815071F22D124A3128D12282AA14247824E22C38721B448011C04221E6828A28AE682A448001CA4241E224A2335244CA4242249C2E49C +:80A00000803A248B526B1A8843B9549222D223280546D14825BC12BE4898448849644149B28902582229C1121322834604251C22D481918819280216084888622A2C0213A44216A2168B244C13CC241A42A486448810B882C2A4982E14218A31828304F04284422339844130844C41FCFF47302163C12381180026A8243A84034280C442C0 +:80A0800032AAA412A82A45299145008002122448428032148062424AB314241124249A488021C14189A1824B248C858488044AD27D4F2241B1483218C018000042322C082081681431CC4298426014228001112810012280588414144602830113214224024608284F82A814808101E084F3F22C004810A21420221301100C2283A98200C0 +:80A100008C01908211884230248800D081A28600128C8603D048248806444448AA21880400890B23622218187F8605280049021048982838964802C24C0484818A22A14800840042A8419011421882220088122832481800588D110020911200284200F07A68001128A3A21481848341889398835322488B49328908B67818A4484A48C133 +:80A18000884820051110A1245A2A0A9243E2139811284381244241041786888C28C4328F42286481B012862231486FA8062B121068412021826212200488824482D08154122281001984024C22422422410880020060248C96981A8481A214121848001812A8320020F2961D304218201208422501424B1442228911D212228421822808EE +:80A20000882348021C0240E1618829484104200820E421222228028018A282A04100420024427F7A0F12288142248082410A2822C8298888C1822E821224421C082822001126244801184B288A3185821123F811448A124534412741193222188A820422214901008249F2F6778001001334188180352881009028800122809182108806AA +:80A2800020242A04120020A421001200828C01A818688200880018188A8481F15D8F008014A8282830280024248901524048E4288458414212484C3842122812002100899221A113212198162220081810011828224C9142814880045F2B04868162114212211A8201124321C644424E1219E889B44988A1148021528120440286228884CF +:80A30000C242208821A2284A51411A34C14289832F1802601182423024E8828042B17846622280A2212086641481422A18A8182C018D1228180011280011A02412174416D141A848223A24044B41492402602118748411E8D012240A109288800112481F370FC012484008102202848E14A48DA18D814810422192221411005014114004EB +:80A38000004D814443082D42499842403424424142604880342444414884220044AF7E0E1120414801A04262818001C02122002084098A21022001124381011212121860414821A288004A48A818440025C288322028A22148E0A20784F021482094481088A1122C542880028308266E281880716A14A19428C82B52482904601821688CF4 +:80A40000948248002180210212444AA134148218248301002382F285A3241E22928B122A5421A9E7A2E2110483F1241C4AD22872DAF2313B2D91A6F254812B9A6E52221B128D2421493242472219E161A2884C18E221F18244445F48E944B984E844E724B414FE819627427E144F4A3A9829D14408AEA1B02E4894828D9820E2157442F413 +:80A480002E9F90127011E985D28824A6443B168F23A454E83E122B49118A3CB11ED8AFEAA241927D112719FA7949E11A041B71482EC12D511E531A84AE924F88EE2196221F41E129B81731824322C4EA2B112A8BA81C13F411524BA8CA7234F25844A23A042A91648F4F0217142E3228815E2184128D284E382E288725ADC84F84C998A3EC +:80A50000F44828A384C12329A88D4A48E18AE224A84246F172214B1C574553A8B8825F11A2174671B8C2232186A5165E214BB197188B441734FAF211622BC942221E5229F124184A84AB858AA2129F150E11100184211042180200144834400110045181450245021502241004101114111411121152812111211221504212002001002FDF +:80A580009B4DF3212337A1BF12F211319F364212D839F3637B6E7A8F2CD922135A33BF9111F321226F62F813113F3ABAE2FA6184EEE45F7EF482815F52F657753F76FCD643475C6F71F146C64F4BBAC27C74F575667565512E211F26F253136E472F7AFAE1B27F66D2ADF153631F75F4C3C29E822B57EFE4F4A2B26FC4F148885AA7CFFAD0 +:80A60000FE24426FB34ED231D113F421291E799FB5E581F17A5ABFB6F67B332E22CFAEF8E2FACB768D8A8F88E818F8D1DB7FF6F4A2E27F79FDE6263F57E14EFCF4766F7CFEA3F31F15F466E62F6CE774F5C4C54F56FEA6346F18F3E1E9EE633F2EBF33F2B1A17E773F68F8E3C23F7FFED2F37F79F2EA5F2F2EFEE3F73DC23F31B872F74ACD +:80A68000EA4F2AFA7C6C8F82EA2EBE72A4476F23F7B4C8243F32F23262B5F111119F96F272785E122B24BF96F66A682FEDDD22F39AAA1F3CF59B13AF37FF28BAFF76FDD6967F7EFBF7F53BD6DF13FF21534D873F12EE25F761474F1DF4C6455751DEC3BAFA46444FC7FD44C77F69FC97862F6BFBE4A77F4FFB51462D844F75F86A388D9F0A +:80A700003F15F7D1F33B54DABDF2FD5C5E6F6EFF4E1C8F84A8752BCEBAFB2412FFCD4BF221333B239F92F258399F97F732388F87F5383A9F17B732F5FADEAF2AFBDAFA5ED3AF89F93B38BFAEFF7E565F7FFF53D33F1FF77351DF1BFD24742F14FE31E14F65F4F5353F5DFF56D54F7DBDF2BFB2B397F3F4F51F6FF7B6766F3BF2B2A77F67C1 +:80A78000F7B636FE572F7EFFD1D27F69F3E9DA2F26FE45F33F24F5D1D16F4FFF5CFC4F6EFF7C7C8F83ABBB2B8AFED24B723F1B0B2A0121204288E18144E18144E28944820417892C124126282488228802421842514288424929A412A092F02481F02481481C08221A049224482CA2418922091228F01383602812A1281848C02880220252 +:80A800006089460242B6082A84014A410819A424224219290128B0418208256141632401928B86441C292884044198604422A048C0415D7BC0521F4152281F4132481FC1326A1D24AB141D2CAB9619B24A19F54A914B42AF1439242F147B24D852F924488D954FA2E454FA244A16F5244A9E252E4A96C54A9E242E4A1F49C2421F49522833 +:80A880001F4932481F49364A1F48B24AD1C1B66AB911B24A19B54A3934ABB443B242F9344829F92448984FAAF49941C04A1F4156281F4126F4112C8354414AF1812C8F4411F14AB441AF14BB24F44A91412F1469822D912F82949829C5912E881E818C24E98264599CE449C24B17C9ACB49156281B69811F49324A1B28A9D1C1F2429417F1 +:80A9000081AF441AB54A2BB14A79249812478329F9264829E9A8B58304000000200282400428000000002180018800004001008004000000400428200100008121F04CEF0022802102284602288C081B142B84608246327119826A581B421A0449B2235481D018A2241828B6084A3222188492824B41200148882212881008A2122908AEF1 +:80A9800018184AF2E528E024B2848121C2421E221485E181F282114A018219614810C8828E584E11528841682308902A00178449C84220A9182AA821431231222128632AA84352C8811E81882A28216886238E4401FF960E4E22560412482C233248A128C9041F2229BD848242E225BAA8B411FC8146CA9254122B283B288181850115F8D1 +:80AA000081248B69B0282CA2248CC274344E32806348C84B69222A25983182A28A4262822DE24EB81823F7CD4800281828260214112E121389094211403848111C218211012A4484443122282A2405102291929218828844002302A041888488842081A9480000BF360B2400280049410800122182241260820090418044914114A0212055 +:80AA8000C11280242402271220242982324213A89282244301003288AA84290A708E0928186F2291188363228CA63462278A228CC851844B491DAC602919EB1A21B724611887122844688594481F82C424C84E24282E141B8449C1884D128B82432218E419B228944113832CD881AC422A35844A12A44249E4443A245F480424100218242A +:80AB00002E481222238232981C0186140A831141013E44822E411C5214224100222002284092214D1246684A1024C9A819A1928869D88128A642824A9224C2412AC8249E732082B114D282C3282849E184829488002934881AB4A5012AB882A3387814148420C441848B529396149AD442A4424B411BC249C188A082122A88B24332416A3E +:80AB80004821848104184323A8842A216E44F0BDF90060C5843283AA21CA0210011614884422EE242221022180081CC1488B840088912AE581422164A280044A884A913112860400248938844A22018C3222A28BC1FF7E438104421C2304848741282E8884844C882931888444E210B14209224B4289034C691A42161141823C448284A0CC +:80AC0000482A01202328C21412601248205741421282292881F3DCF330120021808924D88204380011901412855181421284480000225289026844A02128111A9835800248A97444028384C8824112841422684304004544A31450482F122196188CF7244284898A021A98981847882F8659689E284A223198488A028094289E614AC28160 +:80AC8000814931882E514217221845818288E82522F1241240088611D48228E344A24178E8A2828B248F13090018841828608162D0184108114212B0216414408104E04472211898544028A1424AB22245A48280A829186822118F168884A941883042128F44082850488023D8D30E60888021C34184122A849448AC8221C9C8C02181224F +:80AD0000263181394291228219460188914E9898822184329C9221348C42248484C26142624448824921220148222098421F3A0A4842808244024210C222B04828042C24444262A400003127814222840048100100301280C31230419084E0228408C84A0942828800886F1508208941081A22120821120020A182812A98891480240A00C2 +:80AD800000184E21402822822106001A04A02100320018838502228A01802684FAAADD00100115085828801233422004800A48800190482220924800144021842A91888042242892829082114498001A18248122828108846FF30248442890281924840281228A010022800416082248828004888188848018810100160142008880888C70 +:80AE00000181812008928001F034490012A0124A01914A81420290848884844E812419EA6428230C8D11230430481B281628860AC22814282E428213521886882482828422842C882222820C1A2A3622F014E5001410012400294181454282111231122224221304178890812D224E8A262281126181460114401101218A2125083C8111AB +:80AE800002C042435428002C0400421F960430828942888801218184888AE224018888004A81088828C24A022860228A25C22222888024042289342882121812280000845A0818130227414E11F0A3DF40085800A219422824024C042816321D201C28A184304A1902908800B082014E1128881518C2485014481119228848C184823812DE +:80AF000000882001B02208EF910E4E4286882183A2E22B63812396433AED24F892425AE981E51BB222A1448AF527282A2CA6E21B8D2E228B542E62A03317381E596E889A14A198526E811C62224F11E286EE1423ACE89A292D0A4AA89CEBC382AA28B68168224B828E21486F9F0CE049311885283B11116AD628D1A8022B284D1829C482C1 +:80AF8000D5E888E6A868B68F1D3D418A1E0819582293E42246A9E383E621A3A62A8EF221738912E818914953A1811A87E11294E3E84AAA48E0CCA34621923A27A9712E11CAF821FF0019B42192319F84E5347148EB818126F2432A2E584A28388A2CFC41812A92AB242F191173C1F92A6B2F1CB4214278C8B888F84A181BA88308271C1734 +:80B0000083508117223B2127C68B188F28B423681239E25231429E561AF11848B01CAB31D842292BA4C4A9F2C3A8001C41480100241E48140040020000000000100211421100004222200243824423612248228A14022584148294220012F0BBC64052571AD119E42EF26323BF34B642A623BF17F3BEB28F23F382822F28F95A184FE4B324 +:80B0800032EB22F273F16FE4B482E51AF621A98FB37C2272617121E122F8715B2F23F3B2318FA1F1A2A21AF359518EA22559B92BDB8B159F8BF189C92D412B541F3EFC83A329E821CD525E182E22AFA1F24242211F28FFC2D24F46A6542BC41F34044E426FC41418E824F35332B7342181AB15AF6DF91A122F42AA98DEB84FE4B332EB2A19 +:80B10000F27BB9E5FE92922F12F669A98FA1F482C21F1AFD61432F26FC715BAFBBF3B2B18FB1F2C2225E511F85F581822F1454B92B888F85F119D89F95E11AA3541F1CEC4CE924F4F2B22CF9D89A2F2CF88A886AAE841F28FCD2D26F46A5DEDAFDB46BE024F417451AF139193AF2797ABF25F75A782B67BF96F2F2D62F26F682A22F21B860 +:80B1800042FC44742FA7DBA2F852DA6FE6FEB2712B6A8F9AFE29D9AE813B861B422CE42DFDD2E22B798F31FF82E21AF7F1F9CEF22B628D2B2BBBEF85F3ED389F9EFFE3E13BBD1F3FFA93A62BFFDABFC2F5C81A2B62CFC5A6662E222BF6EAFDA684BAADD8C6094E42FF517419F939391F1DF5597ABF249462AF87F569293F3DF992926BF52D +:80B200002DD22BD74F5EFF32BA2FAAFA5AF8EFF2FED3912B648F9EFE285A2F2CFC71C235F2E24A8FADFDFAFA2F1DEF25FFC2221BFF1BFF1F2EFE22619FB2B2B3FB78389F8F7FC9FBB3B33F27FB73A22BBF7E722BBD2B918F8DE927F75AFA2BEE4E922BEEEAFE3614BAA9D8CF7C05002A014028C248221A64228608009E4824842813A8244E +:80B280001142A02411288082A824188028044001148C848984A84800A04140088A0448004282FF360B481214E016D181921280311180A414124A38312C82F44A821220885221880048D08125E882044819828822024302223042282F12A14920084B4388A218B2422A8408AF92042CF511248D121F4132481F41324A1D24AB141D64AB9492 +:80B3000019B24A5985AB9443F24A9143F2429147822D914F82C4914FA2D418F8244A16F1244AD6F1214A96C54A9E24ACF4D1242E421F49F228821F49B26CF19124A3F48164AB161D24AB961B68AB9459B44A3924AF44B924B442F9244829FB244889F9244A1FEC0149D581D622F5112483F41124A7241D2446D241F648141D242BB45D289B +:80B38000AF2439248F5439342F1469822D856F82D418F926521CF824DA87114BC2D6F1224896D4B2E449D2B2F5C12C2AF4914CAF227C91B46C789114EA48366A15F42A941F49943859B64829F248944B42984D48B86F82D448D826F595330082000000000080020000009022800100000000008001000000842200000000002501ED982470 +:80B400000026A8218426488864411284002341028CA242871123229C18984A4A28126184A0212892841E8482221028216445428A6212122182181A0C3243A48482B28458AA61828FBF0112B200482B84121A42084AA214890442A28E1130248822480000A021161808682B28260A4416A221235824861128210D1C3248894891C8E01108A8 +:80B480004E1820224AA1487F4E04A02D843246E8882481751884B1242461A6802478B88146398266321888F28182B028C41884221F2946C8AC8908522D288A61443749421AA818245382B82839818988E318246484B8244A49A1C13F21022901224082128802108804122422004C2382888401204281012A01A0282C0143022C01801488C3 +:80B50000621612C048A04142C0148298902822B826F8FDD80000100800000018304800201404800100142200004028011902162404000081000000000000482F3A0220021C0212005220098B84A08122132922490268209221488044219481802204301400601248A04114292882091A049828C200436641F0AF150000191208000098C093 +:80B5800098200C1C09CA4114228621C22142142811421C082842001C034C219421488011118A22014200200890444C011FA30420020012004A010042608122200200000000480000108801410000004820088220011A8882048002422F180F2001001242001800800182000000200222000020220200400122180000008001302C00A0148E +:80B600002200BF590E00288122260318814A482824044181841A264284242204848004204502422220288202002CDA140436A22800008812000082A0824FF40F14004112810012001218000000521888001140840141008004000081830618004812008200421002201AF8382E0012102863824820A1C1202101448280034CA11488482818 +:80B6800081288001430580820400260189E283A4284C012602180088604142248025826A8AAD6C4001224430112112811088242401848148284820024001460400302242228088020040924120A186001220982800008200EFB9010000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000046 +:80B70000000000000000000000000000000000000000000000FFE40F8004000000400428000000002180018800004001400848000000004480020000001002183F5F0B0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F24 +:80B780000000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFDE +:80B80000E40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000069 +:80B8800000FFE40F00002200008800000000000000000088000041000000000000008200000000005EC28001003048000000B04821918840088800000024602240280128484C428208250400002200000082A0840020F83D22400125418202160240081E42101211418498241826080010480840241222040044124031488055141A0889C3 +:80B9000008C24160680021898288046FE70D19410280220400842011A21416918840188408000040082602221848224240A6811002004418228908C24410240829280220F816F400400121842C0100804442081144822812890200400821101418020043020045C148A04114820000002C088014282804BDDC4002212866410810882206A7 +:80B9800081200442844A618228000090288442489014822021024084114121382882462201482089128401444382089FE24401121E23812148D0820181982210889891B044011290411A8A4222041324C821493448661C1434844B811082321246F446121E4612284A880443044C25282C228401889F9E0F801132224248200126280A813C +:80BA000084821321044088220400409848C02143044648941449C8141046223141C8362288048014842921A841904418005B1240021C43CA218424848420250220840847854A8103119A8202292412A14842F01448490A808208A01211412D146D4818222BC14280042E444188223024882CF8B9C10022141A344821282006902826044078 +:80BA80007424B848A112481229068141142283442102342082B12174482402228B42622541981496048227128081028024912281127F5A095082802402840078490822008C010024226112428081A912002814124885212104281024410A4A420412108432122800B0820442DFE94C810100402881410187110029648400408102000020E5 +:80BB000004008C2112040000142304208108200260A4804CC4382281121A14F86DE4002342018952828C2321A2141181244289D44891281A64116823E24482114844A1412608228B122849A12414134184D221223264621825E8428488225912AC84A2B4418B122283A1E18CD128F4B7DF800120210400468192982800004484288001809A +:80BB80000480824501400220A142002044C8121588288101284024112202480042F0814600000014F022484210280400191341080022408184021210512800890141282002000048542161A0242445781262485084848242FF21412244022384018110020000008005002002110000408482050012144AE1110254542141400428144112D0 +:80BC00008800224B182A21F2D9A7A0122301188C022C12110842000014810014001C011021028001271141501410145441814508288303128011544248400444121A8804CF2402C021C0224262009028504842000022202201400184200200C02118180048301112001111214C0211122880A11422222221411F630D236822008C6412A0FB +:80BC800012A0120080014904196682121304844008111B241045C8444088420414448504471400260450144120514821414C4804441CF2341F00110010084262004E11802204892411012072111218E1818808000048411C812102142241C01125C411250340210100425820C222D0710A480012180000480028200228201188611421A031 +:80BD00001420042224468422016012180024382189044818001AC421441248802218147284F2FB17302100206281178620222404114211621942814201120084142814284414458802801101003998188120011431124684146224A04900430DEF4E0FA4C04215024200A1814064441C020000124810021848C810014812541944C4284426 +:80BD80004818440043E4540240A4144A021242492201230121218F18081E42335A222C24C4214682A14426084A0420467128C838264181E11152215081850178144144255844D054B111732444C44549D24E72422152C6283542F242142CD154D62422F1A6544C253C2E813CC8A21F3344722241012B1129B73884F24229AF82B248810475 +:80BE000026011453734131513813A1412A6411118F14F491282A14A1221761CD434D6158859C21B011015352B81B1985F44516321F2461413362115744724E44C52E24D944A5113E944B5843F6B84DA0242C0313723878417828E92204684698194E4419054A86E21244C83846018C4309484E2126011446E843A1271E511247422815A17F +:80BE8000111F430159D198F441214F51C41110E51194111AB142612163A4A34CBA84E24752423F5A4B0114002082E4220118481C011C0138190413011142001142115211121142001440011440C348344826023448800448248A041008F0FC51F023223D2B211F3114D818F219538D6AAF86F258785AB54134615E115A83D34CF528183A2E +:80BF0000F318181E11222A528A85D988E311A3922A52646F61D1CCF11454CFC7F7141447414FC4A2335F53A7132B9B4F43F32D272352252B322AE24151114F2152464D14AFA2BA12F924266D944D144F45E54EFED86CF023223FB656223F31F5685887129F33F53A5AAF87B368F65C5C9F81F1513446A1156AF56C548F92F2292987811F91 +:80BF8000317163F12828BF917148F8A8B81F17E312F331314F71F1471F6FD3F27474CFC7F71C1C57515D6D1B333AF71D1CFFDBFB3534CFE3B713F115462F63F323213B335D454F65F646144D16CFE2FF46D44F2FB292F936344F47F7D6D4AF914BF323221F32561317315AF449619F35F51272AF86F268688FC1F519591B6415A1151AF27E +:80C000005C4C8F96F731318F91E115B572F721318D188D498F92EE12E317F621211E173F71F14C5D8FC3F57C7C157924F431551B115F51F138183F5AF94946BF71F156366F267213F511133B7555F414466F21F45E1AEF8FBB92FD2466EF41983E4B554F64F529A5143F26F62B63357353E387F269219F37F76262AF86F238388F8454997B +:80C080005B441F1121A467CFD7F638399F93F319191F11F173719FB2D399F149491F97FE61717E611F1242F3475F6FC7F66C5CCFC7F7151D5F53F23D355F417155F51D1E7F7AFB4B4AFFF5F577767F76F713133F11B153F745545F77F54616AFA4F5FEFE4F4DFDC432EF49DB4CE226FAC4965FD30900001884228422846081200112400843 +:80C10000120028100880818201184249012290148001181200002041022001822021043F22078A9121008006B0420118484200481C22122881118142482182024012082800140040C12820D112215112101201481890822A941822421CF4519FC0421F41F228131F41326A1F41726AD241F24A111D24AB9419B64A19B54A3925AF143B245B +:80C180002F147924D812FB24481CF9254A1CF8244A16F1244A96E1A26459ACE449C24A1F49C2431F4952281F497248F19124A7241F48F24A131D2CAF249921AF2419B54AB924F44AB243BA42F92448A9F92448984FA2F4ACC450A24C762AF21144A3C624AF26D141B248D141D24AC92CABB449B24A19D1427B25F8428157822F145B861C19 +:80C20000FA275A4AF8259A5E8157A296F1254A871D45FB98252E4A86DCB4F491648D4396744CF1112C4F12E888F42E111D6CAF467911D41A9B45AF448BD44AD984F442142E48AD942F82C4142D582F83028400008400000000000000000018800800000000000000000044000000000000DB818022210118121019984148008C5414118469 +:80C28000188008138492412842109824108C92242B14511A7421C22424424121AC44812B28111125012118868212AC4960826E3DC041237822084551217460112B821331212F316418007A081A02848B8381846924D218014602582384118454424410D4680A1642F4882446D538A24A8502C7244B16668A2A12AC244187588AF44933A015 +:80C3000042569228C01416131461212A7414613272191445B13888218158286222567142249A11C042D084954149F14214C149F5412228644B424522C14459DA41CF88322614F1481443952A8A825A424FA2A48543A841DFB30834800114404358181328043486082004280017898184284881844C023022283041214441D028082484A1C4 +:80C3800060328A543841242246220126084181A6F842F60000122411240080014A8104450813081381028111541312984128844448874180A282440025014116080048904100303481B0482102487FD20B422912322283A541815A92581A28D4825422802D39888CA28129E8C1E41C82048E28482B42C0181A344A892AB4448848A4214932 +:80C400003288C2871140E241EC6B1401101A8D9C4C8243EE4894848E44448CFA682B0022A0218B1423012180A11400A08486088E29983969432E4140C12448C041382C258484644C2841384488111830186B1462314800416084E084088449042AF4EF6CC0422410021C14A861568848C24A4A31421249918800904888890487183CB2286F +:80C48000048181C48E288D1420884A2412B842184904888E1400D08344291C94B44392C45E842A18C48896064260218081C2244C224288925847222C24048A4144F11224102244A9281C83C5144393382A28C2781621A516563A11004110084004B028448C240180880152E02B0624263241226608A43489344411F02844842022648116CC +:80C5000008182912110418A221001412448712118887428AC241C088842D2184164604926128230262822384082223F1D3EA0012848140814428611212139282008A018042A842C014C8424085140356488808000041269422924A01308184C08100A8C3111238484A4138A83FFC0C24249991288346B14C523826D849021E29A51218A290 +:80C58000828A6181364A8886C245CB84CA82E236A11467138B211F83C818AAC11813853334294A3124A283A94240C481811259042288CD1282A99CC84AE18192A84F4202481A42021828244CA214482E11484A882424211444313418801101114441004222874422800C1C4144424C7211182811022C6888858684A342001820042F24082C +:80C600004821100A0000830148708A028014180490128185C1881189548481430811418440241854144450414410848181C254800149818801184308CF49020084242C460416022C0612100483012022250124481C4428E212B42264122B4820311429819411825021588B141A24813885908100490C882426028184F035F30040210222A9 +:80C680000010C88400104184882204205A18138A22E28214C18142450182904C1014014241418C04114211421880080041E0420481CFDE0D1428008C1278424B68246084814B24A8830810342452A0149824D02244012A54C2222F884421241802588281110048001081820C8A0524C0821084F8A15FA0282221222144A021A049A02188A1 +:80C70000C1863814820000B30222481782804388C745498148140448411100466141C121138441C844A64414C412C034418BC28C42F9FACC80042C0442800429042B8429DC220400837488A44800907212192181484251298481182480E4888104930881001112484C91821820014C45A82818007F9F072410184808814200844411584042 +:80C78000480412A0584286028C0114008800C9C4488A210188416015122158D228218A8462241A84242E88088008FF7E058004002210480811828410024428818608136816202208848890884908110015044248441008004A02C02480184404160812F03C4F40488226411148224403400C782800002004218418803852901290128714BF +:80C80000002F8801198588180810C454400528004448C08243821882F8765B002F2812D12262A22285E825521A2C581229B24938582902C9A8224C2B2144C8A1A7859D2115817448B64AF2A9AA257D847CD4F8444267414AEC14C1844F48543144571484446B585CE214B2C443B444B31645A45A8AD186C834A9DA14B188F85587A064626A +:80C88000856A824641344181B0287488AC8D69D6264818684888428E481AE111F818181968888B2585D811C2494511A4948D94818A9814D18288CF84F844481E14653414441B4519159816AAC884124D8467442CA3828664CAF0D9155021302283916ACD2A2CD482E524F452184ADC8845E2C8B589F8141C4A54CCCB424AC1C23B7E1F2E76 +:80C90000E412F26242A6F863212F83F5A1822F45F5E9C2A71148DCC15A23E149F8151115A1481F11D188B458B548F551818A31121DC15ACC44C24BDC522C684BE3E887958884AF180C1304111031221118158811815181188041C834000010682881B01882381800000000002184213022302212211221902292200192F0EBAE141553B3B9 +:80C98000A5F21233EF54D65F724AF232632731BF34B1DBFD7161171BC5F61939124B89CBCE8F47A591DED287837E71FECB2FBEFE4B4B1F17F773432FAEFD2A3BFF33DE4EF594CCCFF9F956D66F45F5551547414F58584CFF75715B7B4EF67664DFFEFFC3D23F32F38BCD4D166F687846F646444F64FDCACA6D966F4CF424344FC8D8A8F83A +:80CA0000A5CAE026F6434BB5F3123BEF54D457523B2FB3F242513F3CF9DFD48F23FEC2F47F71F59A1843B184A9EC8B9D1AA9DDBF82FA6169FEF89F1EFEE9EB1F97F75263AFBDF4E27FFF7EFFCE55CFC9FC989E2F85FD56545F49FD95144758CF44F45F57BF95D1C4F16476FFFEFFC39446F1C8CA6F64F44624CAB9C4FD4442EFA4F4A2A2BC +:80CA80006F265E46CFC8F818989F4C07242B629FB2B212F34D668F24F6494B2F22F34B4ABF29F88ADD6E388F8CF2DC94DD954F48F9CCC88B9B8B461AA9DDAF9FEF1FFF68788F82E6A2FC71212F26B5EAF4BA6EAF67F64251CFC1F1DCDE6FE9F9D2545F51F511915F48F8494E5F55B15AF548585E56AFC4EC44F9E1B19FBDBF46B194FD5446 +:80CB0000844F69B9E2FFD8DA6F62FBDEDC6F8CF59C188D18FFD20A1F36F629638FA2E2A1F36D4E1FB6F6484A6E7ABFA4F49B8AAF5DFC68F2FFBCFC8FCFEF49F88C98CF8CFCBCB88F4EA8D5DAFC28E98F9AFEA9F99FBEFE6AE38F96F76373BFBEF4FB673F7CED4CFD585C8FEDFDC6D62F4DF595941F49F981859FF4FC55543FA5D5CA81F590 +:80CB8000DDCF3F3DF9F3B19F8DFD54562F2FFD56844F2DF97674CFE5F53616CF8FFD565CCFC1F188988FF40E001410C4488004402308008480048A04824A028B2420048384A82400884200880048188C44220140A248A04900200800F048F5601A2042488146417842232854812449C481C084A2852421048901882281807222224818C820 +:80CC0000428218122018082522018A240429080021482D822242806A985F8D0C2CF4112485F2112487261F41324A1D24AB161D24AB9419B24A19B54A3924AF1439242F547B24D812F924488D914FAAD418F8264A87116FA2F498252ECA96C54A9E24ACF491242CF4912485F2912483F49124A3F4812CAB141D24AB9419B24A19B54A39248B +:80CC8000AB9443BA427B2498924F8A84F9A44A8FD201941E64AD414CF26A111E24A716442716CCF26E81282F34DA85B24838242F1458842F547A24F84A935782AD915F2A55185FA29D885D428D255FA26C584D4B9E214D4A1F89D2A4F49164CD431B29C7349E24C7341FC8F244121D288F7669418F347A11F848A6228D944B492F44A24338 +:80CD00002D846B4B25F4A458CF260B84000000000014000000000021800118000040010080040000004004280000000021F07C4F6022004303842881248C621494258201611748468861828318048C942C00138614082124831454218815480122856421876284821048698541428608C8888604F05C8B3044A6214241224324946D828CC0 +:80CD80008821CC8C18282438190219249289102134418186815441863844443C98A422412624430C3D444A7114315813874914A11430141A761A420446D984D4EC084E2413063641828142E882B482924D85239E161269D22498781393288AC4249C785298258A147141C8418314D181483448871819B8424A9821C024812D158B21E5F198 +:80CE0000448811835384941A2494884AF142824D824C18F814484FBA03242042048C1284541484881260880014005018001008422282401422144634265014442A411884344612181A8618A11441301428160820044F5F0326022712306811A3828661888042318181484604852462448032814200224A02824981824404110014E0244106 +:80CE8000D82A21818184A848348244602420348480F41D9430421483712A92158CD46184D168C2613C22492A3411242823288334384A22312886641449B712C4141CB46C8136884BA1581D241A7226F128824C933713A28243B22408254258428698482E12174243884484128CF89BF8A042111D38285F841179212C127C8281A22115924D +:80CF0000411941A224B02C21E4460190A144114582A24313A42D90284B841A44E1129125841431482998221E8410D282388484AB846C02869442412A4888D8190E254202252A229442298533683482818884484429082284683884C8485A22150485B42485A821412644028E221E244CC3318CD2489122184830428601124D214220144439 +:80CF80002474490A482044314251B0467332184811614323012937842E132A1132518D2210C4986D81812171D0A5E811964821818E42421F8162311E421C71A85418293E44441CC218E810182298821886280429F117C51092421E2183830248904143243828471A48128881002844231465144A918830648A0110C8841CC1214446180471 +:80D0000044A6A4412312A1212504482290822822168806887012F227439014288440084902001212814008008118224008284A62411884804124E1C2041218208202001022E2242158C246088A2124022391181E48812FAF082F4491228CC3192D28544C86B238D44864188B1287112321B162C18C3CC2182259A624156414CE287D688D34 +:80D0800016667497084718C3E441781A64124B412941C4124D328E3541AD221C784222A2122B856D88891482A3842B183A24213D1885F272B50040812204241E44250118118848818220C122121884814100800130182B1283A44280088F12912142B0681921E6410219148804869882228902A94828046F5A0A2D22811439C422C0220004 +:80D10000698881E3210824224B82374490185608828D2168484129C1C122282144C144444479082D28414413984246DC82081FA438848C12245862684604C450485FFC064021010046081212888128460400184220E21402002E881848418624894281041518A81200315048CC02484821422C0142C0888429048684F47FE220C422C9120C +:80D180003444517022041114001216288184088880511C4842124241487C146444C0141126242141048CE3421448043481904841301400800828F02BD4C02856049028280048406841902288411218122A61328412218814262222018CC4189E41111215B889E248240910AA24A0240011B0225828200222A0422432CC0D8A011825C8421B +:80D20000846081422944C2880018CC0248B24964188B4220112C14DC14B78431428A22848164181824114C41218845F221488388084821202975248282342844812AF896DE2490111447228016022188218004A542D1222492421C0214E880410270228841A4289C02402A84C462267C221108106244444110012470842838844841F08C8C +:80D28000810000148444478244008424848444D041130110089021001188148811000020814421C1142412121623A18592121602290824478112301285F4214F80C44281101649242361520044844489018283621C00830110B848413828A44287581028012230424424B031041260A18413418D0100294A8C6284F08EBD402212140842FC +:80D3000048812064182748981E24281100118418122B2446D88131212A0824131108D411C48C728184041C11D8214214C18485D14308C912928C41C84E1418228CB822A8C1FF3608246F991153414F86D683344638211DC5A7288A38CA18EB194931C22F41B87881F8282989A336228CD2387434B2C4F511A92F94E44218FA14AC4B44CFB8 +:80D38000486131CF424AE6219419AF58F21C212FC2BA62758CC4122F88E82C7944C4344F686129228AF9F22298CF8AD228A14B9FED043A9641CD27ED28218D218B22E5E42531D616911A4C7118C828A5ED51D6119162414A31321ECA5E61422AE21425E26EB184E214230F165111221E114F11B945F334284F82B122F41451281FA7BDC5CF +:80D40000FC58125D413F2961312B814AFD8664224DCC4E284CE4CCD244BB944632426E221E183C54684746EC648348281D8836E821DA4644B631F22412EAC4819F9FB711F84149D35889CF18F451888D2C2FF1924C1F61F98E485DEC8955C9125D2417AC33CA8425771162E49724D51D529A19548A8D48F78A85584624EFE49618C74A4240 +:80D480004B828784EFB50220024150246022502412A04124126C1241120141301410053901001901188001290125011C010014000000001A5418128112F0D9CA242F24F4131BDFB3F32226FF12D659B24AD44832125F525A3985F23AD88F81B11AB338F15255AAFBC2788E294F5BFF74443E384FC352448FE2F354594FE6B7A6D22AF24409 +:80D500002F2F46F424248FC4F49D941F62F275355F79F11564C763EF7BF96A68FFB7F61317FF61D1AAF11B5BBFF7F447D7EF81D966F146C26F67F9BE964F6BFB6C74CF43F764E44F44FC2DDE241E323F36F23B32211F12F623212B466D342B157F72FE83872729AF41FF1A182F81F132243F15F5E2A13F9FEF9BFABCFDEFD7F77C5D8F9245 +:80D580005319CFE2FA51574FE7F5D61EAFE1F1C5CFEFDEFE7C7CCFC4F4848D4F62F2B5675F79F115278763AF7AFA6E6EFFF3F73F3FFF7BF75AD6AF35F55BFBFFE5F91FBEEFE8F1C6D66F67BBF2BFACFF6C78EFC3F768E8EF86E62F4BF262421F33F4392B3F32F22B691F32F24F4D4F66F716547F76F38B9F2CF95AF88FA5B11AF138136FDD +:80D6000014E73EFBCB794FCEF3F9F93F9EFF75756E5997968FF2FA16595FF7F636B4EF71F88E8FAFD6F468648FC5F5919C1F62F232D51F38B117F32D2E7F7BFB4F4CFFF5F61237BF61FB8B1EBFB9F5DB6B7FB5FD1E9A6D1A6F2DF4E6E66FEFF9C4B6CF47F7EE6C4FCFFF6CBCCF22084E223F32F63F2395FF6D6BBFF6F26F4FEFE6F7565443 +:80D680006F76F78B9BAFA9F95ED2EFA4F11A1AFF33F353732F3FFBFBF95FDFFFF9F94FDFEF13F72849D7D2DFF2F273577FF7F5B79FBFF9F8DF5FEFCFF77C7CCFC5F595955F63F3B7B73F79F11737BFB3F3BFBF5FC7F71F3FFFD1F39DB7BF3DFD92139FBDFD5FDEDFE3D9EEF9D6D66F2EFEF4D27FEBFFFA78CF8CF6FCFACFCEF249A500505A +:80D700001484438224020014000040A448A048288242A024101831488092920080011C0824800124482486488144234102202804003F2C0B8A8502280042A01496049098D04821032289034E15225C0144481E244342C59228A0211021321100898112B81102288B94841812218242A2872422818A84C2482FF3024F22F41124C5F211243D +:80D78000C3F41124A3D641B24EF11124AB961B21AB9453B94A39A4AF543B242F547924D812F934481CF9A44A1CF8244A16F1245A96E1A26459ACE549C2DA1F49C2521F49D228F191248B841F49F24A111F48B24AD9C1B24A9921AB9453B84A3924AB9443B24AF92448A9F93448984FA2F46B65F0224A19965A1B21A7341E28E72617C1AFA7 +:80D8000026B111F26A8617818F64BA95764A32A1AF343B112F147B24D81AB936D41AF8A5528D115F22CC816F8261197FA27588F524138F58D224D9C1D2A4FD8164ED1213F94E9186D83ED941B246D9C1F24A951D242BB457882F447324F84A94322F64A8432D842B434CF8225ABFA30646084818000000000000400800100240040000404D +:80D8800001400800000000400428001008005012F0F4A4C041400C8C344C8CE2414281A8A133C158942B48582352822B48ADA42788264C044C8412B112C2218A94148D5425E244A22112C0144CC27C2C91288B244CC1128E4828601186D822384418206188784148EF7A4C52241B28135384195312165318624912228AD8425128814E81D6 +:80D900004C313114430748483449C4182C34544137222AC8181A3845A243C82814883782C84F18F14822471C20018924A1412AE8463846E384D148F838C185F4FB54244635634D29C9747142ED82D185034D224B1227127E825D1AC81AF423828761197C8BE2AE41344452518E44BCA1614D714C9C11AF44D3A2C1255922E3C478386412F5 +:80D98000CB25A9726238B5C14DD3C3282292188E124E92624F228D344616BA8875946941ADC2008001814834601682889281502884428033244426082034224002244C8208D852880044881381C8486E122024011914084C0844168838244AC2483F250249044100008C0212241E283440241102003014508142415484168465482C25A1C3 +:80DA000082174100004D81402311028503818285321430240089528442F099FC50124531232815B81994844887714EA88F190230118611E8C27598E588743B34944211A286954A122D158F241AA4126962424905572126126C412B164E184C94414B691A82A11423C4484C48B86C18C23E6496843A1C8CF89D6B7041044D2128818D114382 +:80DA8000886681CAC198320044833116824844414905143C441C545A560E9AB22284A2C111182881E018024429818BC11921814092182E882836584227412E888981F891152440071021048155322819124AD112C181C0681D1C89B82B810911833A84421981216A45444721433124495114254294146B4189954146D14224024A31428BEF +:80DB000084861C64446141608A414314F83D9D0010210248235182282E5C2814413125D414021D284100212A6432981912684540041C82216122901A1D1414816B282813C41166486425A0144423216924222422002F81F47DB250414B1410684325491835586038124B424969812C011098221AB28244044A0152252282D2412851842704 +:80DB800012181283042E84688490144845420C8449A214888118C219341489342429F187BF20820290411849020081892609A084560412204848112412263228A014296184284031C12052221216214842188129E22811082628164838234A08001F2C0F4D2149028076421B5C428B1466D4217221A84147314781CE221E4485512C2832FC +:80DC00008968424932E22D253AF41668214E246D11844FA1A2211C73418231247728721E898AC24616F149268E1826E228911C522F812A6324E22D421EC4424912F8413E0012148CD21421A1121528628189A8412C2808530122188088641411809888808221A852009092C0112885C22430118304A041814844B04868818122288480F4D4 +:80DC8000411D10044412812C1464929B211984B2894511083CB82484C4446022146A8881082154268418141204250444114338812C21C414221815683A41860427412CA818442AF188644B1C8A34842F22498206183041814A614542200441432802601880080028681024043A842181C1242C6441184C38424470818412010088B04408BE +:80DD00002843A2A4250210047F29063504C460114244403144184E18003044848C91148081A52114601442241854604528141609841684C3548811521116C4248844981110B4121834148C218281F86F1840288221022D3C818502248490182055122082021488241068431212412C0100482458880028002CE861243452181880C1120073 +:80DD80001288801142F8E76AA038388400902810A42928110044241B421411A0421302428841C119240220A2212244A01226816214432891244A2868541442244B1420012229B22421D228076F8B0B840017420000388100001828C04421496511008814800211281052141604190290112061442400216413113228868222121214624822 +:80DE00003018FFEC02002884222880032041721421810444002641048E4828220044002E4420041C068288802886228822024880024CA28400A0481002DBE320518410C81A14130200841008008422680012156218841348218851142511212491128E21511882281110616141122284590100201101819C02BFE506461881248106211589 +:80DE800094444C816442B0141236461881121442482D188021A2A4832224A4344B8414C8608480162481A421428813846A44822813881494448A8404482998661D7B4034814C8211D88BF52844CCD551C276284871442B2473E8967465D9147644A1121F12FC78181D118D291CD21654D576C5136E111A83A4533C8242F481A13F48D5117B +:80DF0000B581F231451394C146D2176418E13B193D1249ADA282641EC14F8AD484F8B8D1E3F93AA9B04262C287818FC1E283F464224D2195E28334588CF558211A7194781462362594482B131B1A4714421C882E36E54AA3C149B175DC26B446F474244D827FC1B55735151AB134F2D4844E564B244F287FD294947EA41B84174D49E84E28 +:80DF80004436C24F42BDF4F424325E847E24542ECCFF984AB235A5214931211F34032D184F13B244D11438781F8851D8184CC544C9A33846041B612B118E6223AA881664C26229C2241E241D84181F4422E412B8887B2484A8221A8869434F32F313648CE1228749F41C81324D162B21295B42A9A3584E2AB03A47014901452148810412B1 +:80E000002A082A0888801AC184114C2A8112215481D081C12419219811C2188222601240012E81400126018044012840020081A0246F564AB266F62521CFC2E212F268782B777F47F76D649FD4F4587C8F8DFDD91B33C9922BEC6B4CAF1DC5862F497984F5C1416A6594124E49CF8C559CC0954F41F994954F4EF634F44F61FD85664F419D +:80E08000FC85B44F4AF2A5F447445F4CFAE4667F6FFF92925F63A1111F38F89A9C1F68F98ABA67624F6DF9F4F62BBB6F54F48C84C5F48484474BBF5443B272F675758F43F228758F96F7787ABFC7F56D7D9FD5F5F8BC8FCDFFF97B2F4BC3822BFD4F7EF6FA594F74FCD3D1BE311F1EF4E2F18F1CF8A8918F1CFCE4C855F128AD2E811E9201 +:80E100007F7DED5EE645FD54D67FCFF715E45F4DBFB1FA85F41F44F2D5B54F6FF6F7F72F69F9B1B61B37CE42EF8AFA8585CFA8FB26364E124F6FFFB2B26F74F786B4EFC1FB14D46F4EFDBBF3F064645F53F734245F52B269F62172FFC6F37D3DDFD4F6D8FC8FC4F779F3BF91E3A8B142F864A2BF1771CCDF57F824A43AB922F4F1D9CAF569 +:80E1800049814F94F844418F86F665514F587594F526E54F43E728F7D7795EC55F5BFFB4A45F53FA54845F46F271727BFD1F2AF571532F63F18383AF8DFF9196BF8DFD24444F6FE927BFB2FF5652AF83F18EBC4BE8EEF47F9A4BF371515F53F7382C9FD4F169F19FA6F56F3CDFD6F371757E748F8DFF69FBEF81F3941A2BD75F72FA3F1DEA +:80E20000CFFBF153D15F57FF35951F13F3F9B197181F94F84585DF95F5B5711F16F4A1573F7DB522FE3474FE767F5FF771E55F5BFFB1A51F5FF3F1755F57F371277F5BFBF5F75F7EFF71733F3DFDDBF95D85DF9FBD24F7E4B26F2FFDA2F26F66F6B2B4CD7C4F21F7E4EE2FAE0F2220022C0141481486088240482648848422089200004616 +:80E280000442984A3222420029082A081820022420021440820400924A2288027F5D0D222042E822210128188041C81192244881821848188A04A2A04280410490922898D0122501822049A24120D9220829012182A04342100289033F3C032CF4112485F21124C3F41124A7241F41F64A121D24AF149921AB9451AB9443F24A9143F242F1 +:80E300009147832D914F82C4914FA2C4814FA264116FA265592FA2655DACE549C25A1F49C2421F4952281F49724AF29124AB841F48B24AD141B24AD981B24A19F54A9443B24A39242B94478229F92448984FA2F44B1750A61D64CD431E24141E68211FC116B881D458B181F4483453B8483195A714578A4E15178925D487D418F927128D7A +:80E38000915BC28D811945F125DA144D9B1CD2A47D11DCA4FD9144CD111B29C57391F44E811D24ED9115D45AF9812CA97395784A6581AF4438A44E1426D84AF926484CF986183D9D4028080000000000280000008A04000000000014000041000000004480024800000014F0DF2B243845331884554A48115C68822CE48144E2884102870B +:80E40000428A6182508280C381478281481AE28116E284D14241644243B242D82408A62681B8227C31C4A7D38395824012FC12C4281AAC164C384441C024ADEA90458A8252216046499322224D1196886889901C42112D2496B541E849A21C4820D843E4C25142714394212CBA483312001C6292188A74127C1411222128E2121571928D78 +:80E4800041225168452824FA2811B6C548BF8A0743239C229552942FC2C4374C42988743B15A688212161852694CF38518C6F21C8242621B81874A86BC243524578227441D4217414D6850288AF444212D284F29A248A748CE142D149E278DB52CE2137821D45271164224B34CB12EA5842E828D151EA116F47571D012D4419218000084E7 +:80E500004322B148082C6988444828822811289218003914D82221058B212E82126B124C028214802171229121004A81048618A849218210644422442E487FE80B2D4100128B141014612216A41280015C082C2882311481A214400110227422082EC2282AA8218812490110B144C14C221E48102184F44281D04231243024100448DDB734 +:80E5800080921663D34A1211C42949118A42312B3CF818811AD41AD9C183DDC23E82B6816182E24628E4D2C142CCFB148121004E1449941614114F28F228148D241119F3188543A221423016418CC54882C38664424AD384CA24FF2A042D6116C414496395302819C1282D244098118C4897191FC3B8123C424C91312A6882288C04164F93 +:80E600007288F2249121C68232A443A11890156C981422A016899B7C38002488124E1C2A188C84826282F034A140422252824054414121121F223121882D114A2908228F6A21388812148A448184823474812002524A123611806282853555855541001324B416C445831412843624414B4149B82474780E224B439125284204288429B1FB +:80E680001212322441183018412788A7422829136C88455828D2848845885114C48219826184108412225858148764442889E484820580AA4241C9D5424224F5F43C002CA4211E23702A9148D4292212312943421192212728462901912112809944812121124126AB1A1094232F8471322122E455C2222094821504211C0A2A28E2E4C17A +:80E7000088838292C2221E228F340141211084819412601190884200514C0C40048634482214481444422024022489222114C4828184A485E4212228220816134452244800008981044F41054127221E221CC32297621E489D249C22929931506149F14422AC188C392ACCE8846241844D881D4218AC243848444D224D128B2836F6116236 +:80E78000F01322C183F45C234D821636812A2848C21A8F14C8522686B43CA4A42638285E284CC242FF3F0322165418C4298104D0222131228C064031811819544A411C2291281328D4847848140249A121848B281001168488622230281D2846C24C2581621441208822181AE444318442221FCD0900213011258292211800244021742215 +:80E800009A2426A584A02143122424B82C142424618283414164884290824921E44A143814450848400881A0212800304800F038FBC0221817410060811200A8221890820030142644143818158844820800202589820212818504186200121244142003610010C444221AF49AC71041613149634119130133C42881002061417424100895 +:80E8800021282C629282418C5292A048A4800220D22401504889A24211118111415124442AC824846B422913086CF2979200228C14018128004581419184414183A89281203187822DC6001112888882008415426184001CD14862288814C04646646189A4212180842104C5823324F0378630A23440424882456224824A6921A4004503DA +:80E90000864206890420531210D2843322901125C284290421822188A1274444118B42604A1304C98491246928C48430428504845F5E0960832E4214004068425652418694818D122A088111888221178112884AC1C80040024B82128800122A983C8812814C8111445848002298004220218401D77DC01842404801812810815249124C7E +:80E980000A8008144180748A110110188191410048181A66124021E41441621110847152012714281420C4242812004249F65515901225240241895121811A8208885018812870880480982424C18A0298704198182849148801228D21003022482A051C022847A83C21082CC112CB21628023049FAF0A008CE4A18652414014943481C489 +:80EA000014A843919113012219B818C49123A2848951141B86132C62188A84C86100460B9B42204111012506144604683C0420046781221062212F7B081F23B2B25317C1241C711A61526B4223912483B21251436D144597AE4D822D21A1814F81D134FAF4638F9C52E14E244F343212841E928B28CED28B582CD221622BD5F18A5A5F28F7 +:80EA800095223F929211C5F4544455588119CC1A194B2488A2527E1289A6446A84F7AA9C3421918FA383B63161A11F8621E141F345B1BF8578817181F18C9A8B488E381D112F88E241C4267F41FEA824CC958313F284616B11AE889F94D118AB687C1DBE21621490A136EC51F23884CF842134143F245331ABA18F34513E9F5424F61692A6 +:80EB00002F2237544F44D8466241AF81913443F6924E806174F0331BE57529C4228D2A1374A8A41AAC998C143E829B83B654594B885B98CE183DC1835B8829BC4848B919A4A21F28744831441E2C1AB832E416D482A13843E484F21186CF49E5D606384E5568463C1427312AF244842E54AD2A8CF466184F4202167E3B0D400140582440E0 +:80EB8000420840628174164846481241264114111842941390121001214288501200601280A84100200148200112810012F01971343F31F1161CCF23F335211B33FF12F241417D159F94F448CABF9DFE91B33F13F11C923FD1B3264AD44CF28CAD9FBBF3FB3D8F84D858F16CEEBB889FB2712AFD65673B766E2A2F96EEE6B6E226F6B1B134 +:80EC00001F3AFAE3B9DFDAFAB56D1F14F49DA49F9CFCCDD7AFAEBE43F493913E322FCFDDFFF5C3E14F4CEC2BF826364F4AFA24262D564D344D24CFE3F2E4AB342F21F11556CF22F33D3B1F13F323319F14D54EF1486ABFBCFFEFFDBE333F13AB111F11FB22212EA26F48D2DDFAB93D9F97776AFC79D1CFEFBDA2FCE1C727125F77F76BF9FA +:80EC80008FA6FAE36B2FD2F65CDC8FAFF8B29B2F1AFAA1E9DFEAFA1FFF3F1CFC7D6E9FC7F4C9C7AFEAFE27753F1AEB32F2CEE8FFE4F5D3E14B446F28F826264F4EFA7C662F63D34682F23C6EA7A61417316F42F52C3E7F53F33B1DF772BF84D6F7F113111F3CFCF367BF33F39BB99F39F99B19AF2AFA8A38CF72F2A6A51EB3EF95FBDA89E9 +:80ED00004F1CF5C4D6BF3CFC2BABFFB3F32F6F3F3FF5D22BAF95FEE8EF2F86E6A7F5333B3D233BE8DFEAFABE2EAF44F759619F84F54C5EEFA3F34743BFFCF86B2BAFACFE4F1F7F58F9C4D42F2BFD26168F8FFD2C1E2E546D744F43F32C1E1F71457331F32516DFE2F33517DFD3712FFF6B797D1FBFB5F7FBFFBFFFFF3B33BFB8F89F1BBF22 +:80ED8000DAF8AF2BBFF8FAAFAF3F72F216B3AF1C7ED5F1F9D1CFECFDABC3EFB6FE3B3BFFF3F7F3F33FBDFADB6BAFEAFADEDEAFAFF833333D63BF2AFA2F2AFFF5FBEBFDDFFFFEDBDD9FF1F57A7E7F77F7F3BBBFB3F3DADAFFF4F1B7954BDD6F2BFD76724F8FF96C5E6F42F5167C4F41F36C7ADFC20C146012C011E0124108484008402541B8 +:80EE0000041041245148009028114A8218A81281001490145014200222204248A14174822C8204484A0200DFE104822849416822282412E0489212D02221C812C083431268822D112A844AC2A14D42811887112B42C22722A012C22501A3624125012991613011902142512148002143C1244F82041C74D7092CF41124A5F3112487241FFB +:80EE800041724AD241B24AD141F24A921B21AF243915AF74B924F44A9743F342934F83D452F924488D954FA2C4816FA264516FA265192FA265594D4A9E242D4A1F49C2421F49522A1F4932481F49324E1F48B24AD141B24AB911B24A19B54A3924AF4439242B94478229F92448984FA2F44AB7D022E441D63AF41124E3F4112CA11D642F21 +:80EF000014D141F22A951B618F547214D81AD884F44A91578327144F83541A7B428D916F82D118B9A5044F8261181FA265594D4B1E25A41FC8C2DA1E6485F3112460C165F3112C4F24F1812CAD961F48B2427A85B84A3134AF4429FB4A96478229F9364829E922F5AF184008000000008002280000000000008800004001008848000000AC +:80EF80000044800200000000F0B731244843416433441CD1220289C118BCC1A113F8884124844728628717B0489148C04A8C1234162269548226343242860221248621C828D081C48489B834B4121602484B842D84812186D88218E8C1022CE46F0F411348113C21637614E182016DA200842D148634D41864449F42B824C8258DC48286CF +:80F0000034498C9411801102882D1444D6852852268E1274499B38277240897248518421428E2443C224442B48484561429FA50B4456157414C8215C16B512C218C93217A82E89DBC14358C243986267924C78C47A2CA1485A78827884F244182E122485722412416248A5B645E824C822862259629F48E46338A543E62402268CE424C8D9 +:80F08000844C1274A49A8C2C3C187054E24C07290414195226122B1284249285124102A04918414A712188835448844CD28104114684012A218C0118C081448312A112848522D11A816214455842488D822200A14B424422DF3209002501105112A014281CB1114201180000409441442200D021344848A04282E041120298130100442023 +:80F1000081282124E1247814080012890220A23214611D2441818D122E188B1C1117A2C44221A44D424E84412E81C9E4A158488F1894248B49A0A487444D58C09285E226418261244AA8282483B28A028D11337699022FC294428C2411086084AD512C6A4CF014488148CF214502401418B822A148118522622413532146C2D44100981057 +:80F18000982412A0482005248C1462241A88748422082A38133019421E89D02A81C8581860244C4188C4A249014E148428AFE34E41C42525011215381BC071C11301814400197A444858C2C69541C32C82924C85D421B45808762202B0122602A9C1A8409221412143260442898148C8428D11203C288480F434361419C34A1312120C4017 +:80F200001112011245C218234282668820117442A124722C024881CC4202469238D41C04422B212B2124124890422C78884482028416C444244B388668CD2931144CF8CCE35042688351142C622287216217A3228E415042142A412448413C4831A5443114C48126E84601478185B412022D1116B483668413084D184A62286282381448E0 +:80F280008E24402424A1180021403812BD5600108403912200432151181886048641040016081009411480810644488002105824403126830142188C4A4888712202222005A800AF634972246122CF2132356C6232183B241E2827429E4116185249184532C419486C24165C85229B4243024698248D148B4345EA21F648124CD11436433A +:80F3000060224CD268E131C2448B342B48CE228CA8C2254868C15AE244C1128AB2487116A828164C76820F1840018184830225311110C112922113884208164881641441816D881CC258284502412884122A08AD911221482E8200121C418808244121A24C21A8841220F8B1660000280000400884405218164668A12A0400488C110410EB +:80F380001862822064448C74220800448722268232421E228C018D428B1C428100622062214816085F5A0512449413011E242972128432818072143888429142A216484962128486216A1924112214851244180141182442402804422813845341A11B1422400A12288420F29FFB208102100800130123012100000054A11440814289719E +:80F40000828141C1148582011824410040482A24724212011574110223440A00220048AFF10A2113818104209121A5C424840014122001222091482D88AA14C242A012C0C284004C81C481A0412A81C8141661422548948C00484C48A21481124004005FEC054440094781C04E158266428002608481424508844840028447288904488497 +:80F4800040F824482608224440240248260A2E122830588448200212100824F0D15A0080145822A4225028840024491241542840088014014821109421484E22002D41108212A2242428008884B0484142110888528828A0121870F44301460214100100A0128CA812816982092CC11120285842604842888314982445111402224724B0F8 +:80F50000240441F084281810240440028118208281012D2870780586348118C9C114124C0100280010A442800422484144E3344A608488424421003044004440081028018426010022AC8681424208148CF2ECB640684148205848405414245041841C220180025081833892221941180184184AA294142A18C218C0D98114241812851183 +:80F58000214304282C41584226425481C0182D2470DD42021F3E911846F48814224A333127444B2A22818343BA28F11144E083F41A28F44ADC122AF4C821418D9114DF18E216447B685884E544E9448281B11CE8867488742A72D89242142D281B1E8CF619128FB4749222B22AB238A7321A7122A81185A5264F23091E1486549189618151 +:80F600003D168743744F92529A382E821867182FC1F42C128CD4226312132211F58C9D57A22F72FE814AAB448C982899D27294584E628F6348E24856262865C42945F823544F86D3223764A57D19C24519C1592F84C21A27A427412E214953821649D8450441432171311B741C58266193417612D881421C7945C18883358C588185F9C834 +:80F680004824297DC83844ACB112D482F1E45449F342868CB141F6225855C2245C816322388C721872B8F81916686A71C418324C85E2450C88848331682E3224AFAB4D0234402148021C014D9280087C081C083C0888114411443110211121192119329821131C3281308124174824443412140041244110441104418187291416D6A2118F +:80F70000721D57539731EF85A6216F85C4A62BB91F19EB49F91496AF4DFDE5E49F8CFC44D63F9BA9AA1B445F88FC5CDCCFACFCC7C4C7641B154FD6A6BAAE925F4BEDA9F472FC5ED27F5DEC26F762A51CF889C1D7627F7AF8CFC51B669E91CD258F81D498E684F415145F55F73414EBDD2D442F48F82C3EA72226F4181C45FE8CDC3467410E +:80F780001E4816721F55DD1711CFE7E633F2524889FA9C949F13F3183C8F81B9D8FD756C9F85F464F41F9BB9A89A48AF88FCD8D88F8FADCECFECF41A58EFCBE582F1283EABDD2FD9E4C6FE48C19F9DFE81953EE54F53FA8DC59F2A781AF23A48DFCFFF7859EF46D6CAF218388FC6F711129F11F33416EF8DFD72742F4AF82C3EEFE271229A +:80F80000E443F314364FA9457316D45555884D167D15DD17EFC6F62437AF86E42BD1C2F81119284F69F14AC4CF52D74CF5E5772F81E993F3D9D9FF9CFC9CDDCFBEFFCFE5CF747C4BF17C7D9F92E237F2B76D4DDB6FC6E6ACF4564C5F3EFF36741F49F13934CFFBFB3636AF85F76168EFDDFF4979BFC7D591F651789F11F5111169F2DAF4A9 +:80F88000AB746BB98FA2F12E1CAF82518C2E1A8FB6457114F41D17BFA1F11E1CDFF1F91F1FEFC7F62437EFA6F6BA36AFC2FAB9B9C5FA9F16EF44FCBCFDCF61F5EF6F2F81F839399F9DFDCDCDDF59F5ED7FFFFCFE4FCFBF91F52D6D1F96F2F9AFFFDBC6DE2FE2F6FB7A3FBFFE42162F63B2B3F2FDB48FB3F3182AFFDFFEE9F8CFD4F75B79A7 +:80F90000BF97F71939DF94F74D45DF73F12E22AFEFFF6A786B9BDFE2F32A38AF82F13C38CFE2939A9014C011844D118443022284228400148C048C94280082819028009028418121831404223024844028628122482216081A44A341281E482890288002FF940F000024122411254204128502002C0118601415081588D82254182944B1D8 +:80F980002124144214026190128426222104255281508185821428011002188001DF9A082E421F417228F3112487361F41324A1F41F24E131F49F24A931B28AF243985AF3439A4AF3439A42F34F9A4482D954F82C4B14FA2C4816FA264114FA265192FA26D59ACFD98242DDA1F49D222FD9124AD821F49F24E821F49F24E821F48F24E9278 +:80FA00001F48F24A921B28AB9453F84A9243B24A39242B9447822B944F82A4944FA2F47ABAF0224B1E44EF2224316A1741A7141E6C811F41764A95218F54B314F24A14128F5433242D114F8384F336484EB46FA2C5942EC8442E58442E58442E5B8D242E5315ECA2F1116489F111248B141B218B1419B248A129CD828E24ABB45B28AF44FB +:80FA800031A48F4431A4AF447924E844F926488F44F9265ABFBD0F86280800000000000000002400001880080000140000580000000044800200000040015FB90D21411678215422CD111E21284482850140594A60421221814211414880042598421F64A3242904A82888F084128169D8A492A42C8232224A4238124844A88A028E2C8901 +:80FB0000D4C2058B4889F257D1144571A2F181248CC121227014D881622222279114983CD8840220A241C05C814181A34284431418C4382AB41614941126342843D229012CF114881E8140A1258115068CD12A55581880624616016F550B4433FE15A81829625328102DD28612236289F398224902214846721418944484AE18248992447A +:80FB80002E496F229429622E94C3621843B698D226629822AA31A6130813C22A8F424155422AE88D42F414A883F4245A6664941E289F5A042541041D2C34841CE1C122224861811411508420816281904181002944C412901480052904181044D824411C66812F228122A44180041658221508100298245FCB0E2081012211424822110082 +:80FC00004A8824042304428001284870264204008004248241000044818A5222008298480088220088268818F494E9144815062D2142A762502B91266628848411303412495412418631448241628418431322544222850426A741889031181862C041F08A428129C48687481A9248246265024810F8B8EC20440129229222608425216269 +:80FC8000288442004CA114481441924904442C342416440424442281C027180013216141680025E228C488884C4C040028104208449FA6078156861121544927241126181512C488662124121234421011A282481A62A8E0210248804444628843A448200240A8283304844123072D88384E88222D424488232648FAB1CF107512C126845A +:80FD00002824424513C4220081233144904821278C80480400001028C2828189020021453228804AD82A2128480A30128483B858322A2D2841A3C1444428EFD10230241130141605122218502240021022248291118C048002818301C02442006905280028004484C502808484842108008280C7442F720900701402284303209491819850 +:80FD80000012001841812842812400282E860020194802160224122112200500128141008240888401F06B1350411826C11436F4152243D114C12426A281A4832191442C1128B4921424C16842842240B818D2840A263248AE18815820018982A1281867818E4884108235588564882A94A821A416C81436B424F443E440D2415224842144 +:80FE00002006211A44032C082160249028128D8141001002002362480024442582522670220281901286140A242024D128098912A4844842F0F25D000000001120098221504250280000004128004528342410228128114214044384020000008240C882C01249941800242F81091141211694111F21024034428250288331188821C028E0 +:80FE800042842280044144188E247042284A6223100410823182232238422C480283088091188129080048F0791F00008021010023040029911200212014382220240244414141800A2D12400424002221822188212184880092841280110224FBCC50988F44B442345414260311448A7184D444B82EE28262C28642088902242512E2410D +:80FF0000A1114B898A38982A8CD22A1481817A185A88CB444E44424E16822220044554444B2A2A226281A49082274485522223A411EFD20B000021104202800481814210020082001004100422000000800100212C0A800424248100000000F022B910D882A414480000244014C62422280020012012D24221A1928A8208001C14416188CD +:80FF8000818C24A44182441800506241CC228202212001002129F1197B4008482941428421021042042800004842242421800188104488021400848084088200004004890280442824842812025FC44702581001000040042C0225282404001002188008244002140084A04100000000448002200400002180D18D040010014042020010B8 +:020000040001F9 +:800000000800218100000080020028180000000000002C08404208460821000000418B662485B848A41442001012014556446B222222180080440245A2111AE349282808001111118558888B44424AC1A20000504445B424322822428488002450241A9148405288A04420014002004544A82242408404002121411A018A080040511200DE +:800080008528A84420C118218840125844422B22000000212121C7C3001245224102840010020048109888000010046082492204000080014188801822080000001810084800001F930B12003022901200008180548280040000000000442002000012180000100200000010040000F064BC40224154132532122F2121120100217048A84C +:8001000044428CA8454800104404004C2402420020018A81887882022938822424A124850858295484480000F0E6F6248001122845025022259242A1854208904281200428004122261814022B2300800812208822216128888004A13042420012208802411F31022311E221C11200812502400284872429C4128141008210442492242873 +:80018000261494280024008061411A219884A92142020084465288248189084A041004E764F026222F21E222B11221B112012C512329F812131F31B189E989F848888F18F44848421F941481548985F844488F44F424444B244F4222E24202284556442E246F22F212222AA1191AB89229E828592229F812131F31B188E999F848888B48EF +:800200008F8424E48404488558884F84F43632F0262265A2123A211102142512D232F1111119F8918887818F18A44C42141501848588F44844C5B444A226220050424584F2262265E222A1131AB88228082512D232B11191819E8887818B48CA240400848588F4851800000000000000000000000000000000000000000000000000000097 +:80028000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000000000A0 +:800300000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000001F +:8003800000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000009F +:80040000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000001E +:800480000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000009E +:8005000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000001D +:80058000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000009D +:800600000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000001C +:8006800000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000009C +:80070000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000001B +:800780000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000009B +:8008000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000001A +:80088000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE009A +:800900000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04F17 +:80098000FE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000D8 +:800A0000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000000000000000000018 +:800A80000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000098 +:800B000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000000017 +:800B8000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000000097 +:800C00000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000016 +:800C800000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000096 +:800D0000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000015 +:800D80000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000095 +:800E000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000014 +:800E8000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000094 +:800F00000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000013 +:800F800000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000093 +:80100000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000012 +:801080000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0092 +:8011000000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE420 +:801180000F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000000000000000000074 +:80120000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000000000000000010 +:801280000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE142044C9481CD484042A1434142302440000F018261287248282842748822981D14811862132488364446084188041088C143414221222822C424442C4249A02128331161F980B2D419D1240110C4786AD162CB6C1721421E2123830 +:80130000845F246A4269D26A032EC22A297118C294482B436C62288283E982FC14C8882E8283A24210D828C4CE46346C1E262CA686442241C4412E4A49C2321225223B8A8AE484F832391032480044850444214B841820084621624284818246280888445200472141186E18822E8249829648004304498211329200418222438242042853 +:801380006089888CF464C814201162848190482B124C321335041482A82100322944225128CC21A48226241812A824490846C84800128D428A1102E0442246840181608400328E122821469A844F71024214001C044C02422822100441408213A2211200100220C18882841008000040684410044400004002231112820112F09AD3400196 +:80140000911120048C04002822411014421404290A8A01882582110218822004001008106884660880222242542440244204820012AFA20F000000000000000000000000000000200800000000000000000000000000B739D0214412282301A12D21169128A3C4A84224644D482B42416230824A82E19842024941E3818A21F51842001A8D +:801480004AA48183684919F48822422AC81418428A81114882283134822C8838442A1564E92410245362818B211744242810011440C82130328A6141260C9044814C04844562C42A388224C448A200265868449382254C988124882CE844312C21299C1662842841A47E6870430227221A321A38412D21292222A48200A5D4823422226A6C +:8015000049B2888286F1812885222451388F49D2846525830184CA12A418828BA1C3F48A249B245AE24431184E818229318823B52698124391822AD482A8424C43F227C8004489410484A714C01184A5416814005362244301434104904410440410A2282C0C61122A0881441410228808208108448424AAC41482102454849F9E022302C0 +:8015800060412144204102A0412C082111008148141518588544001008122210022200122C28081AB24C0822122724304284103442800181229DC1144532112F525112172119E2118256413C511825C9119486E149E288222BD268A1144CC6E490288561851CC4246F86C828161CB854B841C8112E94544C621366CB46C0228981A44817CB +:80160000818C81487418B2884118DA84922C4281AF1902211CD1124201221152443951288384412188031038141324624851843048195428A63418CC426A4990212210A428254984E1821808822724A488448143582881406484F094A4146C026C6141273145218312012531113C481863588B822A89628423D11CB44812C8249112302469 +:801680008984220148C681319454321CE128C6422846941262589C812144C81287214270343828C0285FA70C1C02902250481116C23842801284C51411A8424D42841421441C1604218D248613880283F3281122452125012883814161814014087144436144444187424008219F18434164411342140E2922622434114243185182901A52 +:80170000BC611147229821608182D42C81A521222503494841263A4245592343E142388224502480C61C228721850288812444284C3612DFCC0529C1224361918011545214811213115882100622288044581820024022048339681042A114282B822210D248528413A229190321822082723882088C01A0488FF50A7961431F4192362171 +:80178000C391226D218D613518E112417851921465B228D138371449B28244486C924C4A692136F48352223D982E48322943B32515328E39A2124F88938E154EE94268138B428CD1146881AD122A7488D6846842AD14898264241F7B0722105281C150141229819412482C48181881084E23841C011448184D82888C84428812728844C8D3 +:8018000024881AE2120165022A012A2111022502444342240384004C22F8CA6A80A421246CC12424221816682122248240084A08422241118B34004302A249014D68C941280112232121B188D32231185048883618E8814434142488A400AB2189D22818F8CE511014069112830181282882830181414311125C1480888DE8A20C14A81407 +:801880002088612882821A021C048C088B48803182280014A160838031441248004B242F4B02494203281C13012002609244551814488122183C29008013217248220A800500122817214548E24412544810644E81008C440400280081245F5B0100142446C4248092421608884601398802422110E2C2488101A487144511612711A21EF2 +:801900002D8400828382220C222902186012211682988A836142824C8168441E44F09F744001C038428C2524014444488004004D814068241E281012E888122108845284442244004149221188C134841784002DA48608490680A12CD0420885F169178004811124174281C344223868448602A430428126624841142F8881229842002056 +:801980001819C3B1124E11C81284302AD0820800400149422411848312B2182C1112D28B05244412003022108816D24102182113CAA11246C54292491484080070416814100489882812044842884882C886E4817C52E42124345280B188C4C445129448A0243F48021932112501850120262508428304821481682A280440112A84810410 +:801A000022200860164280021A0838448D41188C02294C082C08AB484129C288A01A4186F4E96C1484281A14024818008C244814E158124188C2818130485042903BC08846E8883111216214206282B0241403112220220536041E21814843820C00B092047FA70C46E14252282F916112763B284E785E184E4CA968B414C61CB528C86154 +:801A80005D1C1D2468C5A44B8D218FA463921D492D488D2C1A45F142384F8313F838A81741484C49F8242C5AF56CD244BF83026AE1A1F3D2118189F95E4876F494184F8929F212946B654A7488BB46B426064B627133D125D24DD6478261638932224B2C1BC3DB843553422D25A3E6129E88A3F42312496B452AF84222832266143F4AAAA8 +:801B0000E8CD43974C2D38584A87E311F429122F21F9A88833F16E184F28B544F1194C8F4CD888366675CA962D1AAB848F44B2C26DA8ACE8CAA314874A1BED1415E631C11183B25291582B24812AF498B22289A248C9F1888917A11B88872C4F1ED4E4E88C7C49FD859A2398888E349D211BC885F9511A1389FCB48486212ABB22F21424AB +:801B800093CC228E289A42F4A8884BA82A7421E2B16D4582C9CE242E424D244B268B18CB814F41CC2ADE9A006D118425415834840024841C41C817822C41C814C016001130828041140131202204C011100222488812224001444082442241048110681C24694408A14B649D273D41CD5418CF61B282B198AACDCF2CF49294172133F1489D +:801C0000A19EB54FEBFB26642E38C2DE8A3F14E482E593F13CBD5FCA7A91F383818D64FAAEA85F5DAEC95F5CFAA9A33F5B26FD81A18F8AFE21358AF84125CB241F14F9818955D188F5A4A42BBA4D122D82AFA2B26AA6B28F82F32C2CBF5543D222F4465A259242421D611D414F46D788F1ECF44F49AF21FAAE5D8F89FB99881B8DDEB5DE99 +:801C8000F14FCFFB2C6CBF8AFF51197E381F96E68AFD3159DFD7FFB5BD9F9DFC81518F9AF774EC8D38DFD5A6A84FC8FEACA85F537258F83161EF6BFE2B23AF8CFCD1B5CFC5F361B11F9FFF9D9FAFCCFDACAEABBB4F64F842C2AFABBB72BFEEF2A8B8CFC3D3D1091E161D4185BA2AF268688F22D39BD44CF458684F6DF28A1C9F1AFB88A8BE +:801D00009F2DBD8AD828F1CB888BBDCF98FEA4EEEFCBFF6229FE518FACF7CBC11F82EC14F4292D1FDFFFA1833F8FF93865BEB88F88FAD5EDBAFE34748F63719BF5C828BF9DFB82B23F7AFF1E38DFD4FAF8B44E899F99FB4545CFC9BDFEF9A2B26F2CF51692AFA4FF62F82B728D18CF42F7BF4C141E12BD76AD1ABF87726CFA2A3EBD69CF68 +:801D8000C6F7787A6F66FB3AFC9F8AFBC8EAFFBCFCBA9E3F22F1EBE8DF8CFEF9FB6FECF81A5CDF86F6F9D98FACFFCBCB3F83FC29498FDCF6D1FC9FBEFCF35BEFCBF634BC8F8AFB557DAAFB2D359FF1F11B1FABBEBF1FFFAEBEFFFBBFDEF74DB58FEEEF96FAD9F9DFDCFCDEDEE726EFEBFBB6F66F67FDCEECFAFFF468CF89F96C7C5B9A9003 +:801E00001460122082E412A1412220A24880446488008524B8480289028B24A024118D243048412022840100C0484D1284411260881484448AC4268022F948249244826F6E068683E22211C112152404E0881402341308F042A1821CA248253495422442118180D22189A29281988280E23269C82E12808832288266A24818922542886365 +:801E80008864C024228344D1FF074D421F41D23EF11124E7341F41724AD341F24A121D24AF249921AF343985AF743924AF7439242F747925D852F925481CF9244A1CF8264A16F5274A96F5274A96F5224A9E242D4A1F49C2421F49D23AF19124E3F69124A3F48124AB161D24AB9419F24A9151AF643924AF2439242B944782AD944F82940F +:801F0000984FA2F47CDDD082C464581E2C421E2C23D4C1B248D141F242948CE244FB8428AB1443F2429147824E91178229F92748987FA2C5814F826D111F82641D57A296E592645D4D4A9E2C9C94618DD39E24C71696744AE149762AC144AF549921ADB519F64A9343F24A924B4329A84229F92648986F22B5680A8480040010010000283C +:801F8000000000000000000000004008480000008281000000000000F0ED71403412257328021901802152821A0290516E845E8249B2146A8218284E14828502411D2C50216C4344C8188222206A58935941548984B48426220850484D828249A486CF220841004FF34791221B282E1411484644849125511A421158C182100884601C93D2 +:802000001471410428460832478489E482C8444AE21224F4811481A4688394421D2481842B48BB34831186941881A800E08864984CF21525C0265E22119722485C1484912145129C112255B811E8446AAC4CB21C18C8434E281E41D641229A442062142FE27581CC448B21992834C183988C1B49745483048F42986699BE2811944C8919CD +:8020800068468A92282592C8E021F2281F1012F124120012004991212A81120842800128229811444181107825285184201288A42422162412312A8C24D4413248482C28410210948282424308418918F4329E2002201118C11210A44981802808C026C081A084114E2530488428E044C21880311841822C4894929092004C8448186281B8 +:8021000040A814498482144A882A0241AB2614D052E22241C67164193214267A2428E91148C857C6644490988163C424488668C4863442E1393219284F82084B86837942942488C992281726882E9289A8424B162A24662198359C1812882E449A120C4C4CF8A2EC1424442E1249D18155412301C9B24AA98119091D142B844024892824D2 +:80218000028D814688984884222E1936684A124F8886A1484968488B81601923E823688CCA92444278241E82CB144528A284C386210A4344F8FF1F8032214022023CC214C02481C088C841436422849542B44498416644744C022D2425C144100812CD8241264262428332620041B0183222811884141A844102A6182C2218F4A84C30143C +:8022000022118042C1A42A5142111314B18441CC6840223212285124D41240140594286021488F117264B14251826400121074440826D818C8142442AF420132224890824078BF0511415A72220427814039284225281244815384230A11A012ACA2141D5440282124082A41184403303883C1624C938389128962224C8804221608C1A7C4 +:80228000648426C4184C012B298F3204105286301441824440C43284002428304822101204A0242621723412042004211810049110C814285084111821614180094B81122283944C485F380D5311E6C17222E421120185544A43B4587222085416D28432228D42141011D4149544685413B114728788A212484D42F01661182D2483712AF4 +:8023000051422D918991298147828718872912244F8174129418AF645284762421C54CE6F868440028250141163C241B212211251181493848C0822238222D342618180126C8244800C01AE08201292411042A413824444306239241244160824C28810B89728408F0AA5D00434224020084488D24004354A2A021190440F1A8114211408B +:80238000140400412342143644121A1211F1211411E044684A282022C218482939448E684100182082F26B24E045C2111009834424846224488140C444858431482C363410E46812082121006648A2412A5421482082064A2201818218C6C21282511488A094622088231CF435F55024244511E4228484042684042420840827222041082E +:8024000081414228621C04282148498834224C4612149848204C1CC888422024C488444A0242824A2254484644F8C86C00000032812654820022818C02002228242002430281442E489460694001111A14480220128221C5141012044224182222004A01428F5303CA820200115604184148800649C411424981A4921C44014041444804D1 +:802480008342818101A5420280123812804A8822088A14A248E0846888424182618225F1A31F24182301D1466881224242805248A028222598194608248C8A12411804904A421122424C4224C24C49C228124C032F1842614484120043041A18A4121A28212212026FA10F00120024241648DA28422454282888424140324144C1E68AC415 +:80250000422C8202214443811202141D2810460200481288811E84181C110118008890882382F8BDA61042622100282844212521A2422142800428914CB4440184262404282218B042880A6218004094422B86998144642C48135C822F8178220840088B69848A4424FC27DA4048944822244416AA21008125048E268722176241189088FE +:80258000904123042981F4448A8024048114A164D4D042142A51414A32145048C0248032144313040032901243F255B2E0426558355298812E4C4F81F1184E6CD422E42442784A4CEC6CF8562A2AF4384883344C2F57F6286CC8C7444B448D4233964E42C7E26B817E54242E211E211D41702824F12A4286F2CAC5DB53CF85A8418BD229D6 +:80260000F8488A1D564929A8299A810589A8854EE168ED1E244B2165A21119C262B9F322626B12239224228722226994269D11A71169023D1A495814CFD85282222D24CD6CA436EA14E45AD624D242F4424E3F46F53626455632AF2662514E84414644F4483C211F259516C71D914F25D684F548A44A6A852E628D5C4742C11D857042A2D5 +:8026800033C5742424247548A4248F8473699C4E4AC6428F2CB828E442F445144AE133E65BFE8918137461E222463764246A9241284E122F88B87412542C4AF12A214D284D1D4AB333F721388EA8AAB584682CAAA2492D882F5DE642F948842E48A24BFA9AB1A4E228E14EF872E600671284434248024100840044844048022840044421FD +:802700000010820200400100004018042041424803002001504812F0D78CD024F2213DFF3252422CFC1D15CF67F42E142D4815B128A266A3B648FC8AE42B444E42EF64F42321BF16BE922CE248A8631D452B322B224FC4E423538A9AFD984C3E52CD4ED5F5514327222E225F53F37D6F6F7BFAAF299FDEEA4FE76AF94ACA3F38FA1A9C9F80 +:802780009CFD491943B6D4A834CAF8CC9C8FAEF5CCE84E548E815F210C281F94F7313329E426F66767EF45F46C74CF65F54D674F42A266AD22AF4CAC882B442F27D766F323319F1CFFA2F8AF82B4E4B872F72161AEF42F46F26CAE2F27F34A281F1DF7B8BD7E56E5FF5D1F1F36F26242A15F71F51B5B6F59FC48899F9EFA28E88F6ADCCE36 +:80280000F481F1AFC2F3C9D99D394BDE4F49A964AAFAECFC8FA6F58AA86AA6D9BB242429F621719F32F22A289F96FE3F37EF65F426542F84D475F228648F86D428B2C2BC8EF87B7B8F85F57C141F13F7C3F12F89FDEB8D1F18AE721D412B8645FC444E2B516AA4D98FD1FD32568D4C1FD1F155455F42F421225F43F37D7E6F7BF2BBF99FFD +:802880001EF3E8FC8F6AF97A7E3F3ADA8AF6CDC9FFD5F8E4344F4EAB345AF9CC8C8F82B39AABD44F4CBB8844D224F22874EFA3F36A2C9FB656FFEFE5F424588F85D5FDF2282C8F8656A86F8CFC8888FFB6F76A7BEFE6F323331F3CFFA6F9DF9EEC3AEE82D711F472E4E7C4EFEEF21A5AAFA6F651F58FCBFB7256FD2C7E3D1F56F2254495E1 +:80290000F27B16BF83F516C5CF9DFF79BD8FCBFFB8D6AFC3F7B3F1EF81F3CCD7FFD3F1E4744FCAAB7DBAFBFCEC8F87B7DEEF47F7C4D56F470F43026302226022844502260224864822818254289285044C0242801212180129082302185012F0261190844888004022412188220812460142F0581700110046014148C14C06004188510063 +:802980002843C821481CD88484024426082A4404401201204208448322018C2202A9010018842082528420F2984EF024421F41F22E131F4132481F41B24ED141B24AD141B24A9921AB9451AF443924AF1439242F147924D812FB24485CF9244A8D855FA264155FA264192E4ADE252E4ADE24ACF4D1242E431F4952281F4932481F49364EAA +:802A00001FC8B24AD141F64A9219F64A9255F84A934B42AB944B422F44FB2448A9F924488DB44FA2F44B2950A24CC65217C1421D2CAF14B111B24AD141D252D981D64A9B4529FB24482F147935D812D984D412F926481CF923588D915FA2EC1578256A182E5AC6F5241383DCB4F1D12847321F89D42CB49152289E6C2B141F48D23EB19198 +:802A800056421B685CB381D658E182D448B91494A24B4A29B19684F2A25ABDA9608882480000008200100200000010021880080000000080040020020000280000000014A02C4046410324411453A241001B821281144962212A34814031287028528528253744212830162C12342212212240682262288C648830884608484942341488D3 +:802B0000248120E41478EE07429E227014828402401111921860652C4401805162384880044624122826146484818984192252A143A2244481887041825412241516AC818C3C68B04C0143C68183F2853B7044B2C151234381942680021512D4182AC25619D4528291228E1125C21289021A12E2480246B82224445441848D428F216221C9 +:802B80002889D2426686288B2428488861392854244E28AAB188B43C2468A1A42E441CA883FEFB002800214051414E1100121884008004411C82048C54582CC4256120022D58286182001400442182811D484284851241144404904400428CB4450E430241195222151408241142400100211188114A0210110844204418488202402201B1 +:802C000060221618420828805412704A4108001068824A02DF3E0F112607614712421C331C30443601D018A4184819461CE422114818584826C225814964421C322481842A141207167988014681416221C28502A400C82D882F385184D68A8201F0B89120524110121201CC41324452406114802412C8841F2261828484C100412002286D +:802C800084A9A242212524416818608112809162A448A13043C22D881C41A8C1842200AF7F01512C42D441C2274674310810611200819224191405200440C12A4D218143C44499120C001011C211812833144218820840038484308261A4228CA124F066E980648245186442115481480050C29128E12361440060613014C4141800406820 +:802D000052616D28255442814782002189166C11842121868C08A1811006418301219EC43016654901421800544604661184946250489179D28664128552818B21224146D248618289522185C12840C112812D112E411E281C218851822186082524324882104848088881A9D2BE0F00218D321400432212F111288100C9A1120000000069 +:802D800000512C4442044800200450241024C1214842C01118A14160228A2189B1188C0244BF634F62413742B01CF22244194135244C54411E288D238074520C83411BC5441008890254196585A722CC42638426185A5256062119D282D314B198763CE191C44A84312F881148CC8822AB818648688D8C0245F84BDF8004E5011400842686 +:802E00008144811458812447832594442C42C821435118418D244014061078244234241002CF1241440200250288122482460281D0422141241928E2E101200234114962211400A484220048001048914419C52814918086342A906A0041441825C1114E2813F1482210C8124A0883042024223444844100F01D7E1422C02222121024223E +:802E8000243646228502142830242CC7212A24C226C048281A44C824186811801491410042208421044220243A4282908800428289948848AEC75021C44008124844811414A14820060028E08441887444022D124651141E484242A021150480020068800640C668211C9C42439E424282C8100412BFA50942111116242404212004002C6F +:802F00001251422B41123414212100844C44022603160B00125021910024504342818119018100908A182443840826D87906464402214E2480011220011A4408304414531444410427274800421321144181044944450100212D44454121848CC2C380542248D08412120282282F8E0222442210E24122C42C2814892244041254124904DE +:802F80002C8442C821144F12F12441100494008181288422100100602410683844240020028486022582F83D75141200001425440144C026A44E21A041143012001314440440014112208262228422813260122E113224200A001111222800412848A324B4A90E43691A2011144861841422100143A44228444844680000280000144018D1 +:803000007844014240228204445081242018018288442CB848A1280044F0116B5081C041412220022306624644C12A2081C23100841312128101A81C528210229442221C64A249A1524001A01222825042818A1211928844006882239488EF450612473826C2116E11223E16A126C8212E2289D23A51843B722E161E2426741231269F8165 +:8030800026443422651894312A52BCAD21BCF443488D182E258D24157511F63321484813F4241A75742298A8A3B82251319F3878820144E14B424B844B2281C48D48CFDE0C1754A215712A56421F857146D141F24261172446485884B5423144414E315F22E13422D498D611F21C6599F42844501517421D581B34344AC4481B542E42853E +:8031000081D11152812926413141426CD828DA8A12622426A284222785A9E424AC888E422E32BE37144B72BD24284391644D24484F9284E142D449B563A4644A24F412614E515B414E649974227127F4744217246E231F15F242438F64A47556028B222A724552144B242A438AE116E233F142647AD618F492424E481F1CB4C4AC4419FC30 +:80318000C2E4AF8AA6CC8F4861AA27484E448B84CAF83E97004302C1302C4003404843480300441224400428504800298112120830249016200218D02441A81284188418008464128D250010F8D1981455D377F22E2F6F63D284F8352E7FF3F32C251F15F34444DF93F329488FA3F14F463F25F367173F55F544762F655576BD495D4D5F70 +:8032000056E432F46A68D7F6777627148F95F712288D688D6A2B664E6A2F46A4641B321F2132224AF271332F23F635629F83F428D83E72BFBBFF98DAAFA5B512F7E462C7A2AFA4F47A36AFA4B2A2F484C4CD8C8FAAFCEEB9145F71F14667E7F2EFE3F466CC5FE5F53F3D4FD2F251315D25DFF1F129288FA5F74F4E2B154F47F151555F71C9 +:80328000F147576F66F46A48F5FC45452E1267E66FFEF867472F16F878699F91F34161AFA2B262F6486A7FD6F465611B773F21B322E422F273732B725F63F63B482E52AFEBFF2B6BBFBAFE13D22B116F26F62E284AFC18988FACFEA2866F4CF44C8C8FAEE59543F144477D677F72F23B2A7F45F53D363FF3D77CB252F345259FF7F56B4B32 +:80330000AFA1D3EFF453127F71F1535147757F77F72647BF92F62F6D5F54D631F162223F167A656524BF95F52A7B3F32F622632B26EC7222FC24277F73F7123223E226F273236B517F12F522422F23FE22763F34FC82E23F38AC884F6EFEA6E66F6DFDFABEEFE4F2A6846B88CDC88FAAFF5BF6145F57D755F62D2F3F27F27774DF65F53BC3 +:803380007F2D2F2B375F56F2515F9FB6F25A5AF5FE51126F65F553554F77F377677F72F669699FD2F24565267262FA62AA77763F7EF26B7BAFB3F36361AFA2B222F22C2E7F56F225237F52F733232B261F22F263736F41F56577BFB2F4F2E2AFAAFF13D3AFB8DE33BC82F864E6EFCAFAD4D6EFE9F96F6E2F4EBE46D484FC286A8785C01148 +:803400003026D01281F4241248268144C24880440220810281114C024431442189921210020000290114A0124022280214402208922882205848F0D55DF02441404238681604C422702801403842C0354924342121002285014C1204224088424844C124001428214489011896182A81188442485684802444F88332F024421F41522C1FE5 +:8034800041326C1F41324A1D24AF34D1C1B24AD981F24A9255B84A3924AF143934AF747934F842914F83D458F9244A8DA14FA27418F5245A96E1A2F5D825ACE549D2A4F591242CF591248D121FC9B248F1916CEF14F1812CAB141D2CAB941D28AB9455B84A3924AB944783AB944F82949A4F8294984FA2F4B9A3C04A1AD638B411324813C2 +:803500007148F21124E3F4112C4E961E282F547A14F848A543F24A9113F3489147834E9527838F14D8A6F148912E828F14F8251AD6F1231A875C2D11CE254F8271D1D8A4F19164AF1275819C189E6CED131F88E612D1C1D442D9C1D622DB84D618B92494924F83D4429844ADB46F8284F926523F5F0D2088040000000048000000000000A7 +:8035800080080000140000480000000000280000000014F0EE990010080040110881200500185110054240112194291722148C2241420442421181002014354880088211820018430860841283F4ABE64032812424B025812288021110582120120949446811001014044400142002002250523C6251250460323021403648308841812C0A +:8036000002281428750A204C4A0249232298285084B0281411229219144354143448301111C66482542120114144314842134298435012695414466832493821A264830C8849D184C822248CC6111E28F7F440120100111001400118000041408801004440214261821424280000406412160400000011008100000048AEB1001604100625 +:803680005041222824110000100541004243428484022820842804001942214841081D48211100000024102211084241BF9F044032216B21197224A12821244028638145420291218C14D181145184904225C4443D448054812122811304003C91442C441D92414B242C24841808428484495448181588C928CF64054012512217424C82E8 +:803700001284121278123118412110581284418904CC94244842412504423C84280419041411114489449C48424AC24242002044189242164C08C845F8ECB2004C8162431021180322200200211141421414140025544268132402812012088002982D412415421153410088840040180418158821F216B550A42642712384042800210003 +:8037800015442201236824A641488802839482C0884A410865521820924410082592284400282608C8648200809821480010F294220080048434142884443129120428225082410024458801A082450828141400112C9428814C24048110018041EC12012522138404841281AD127735004480010010922832244051182012042334840033 +:803800004410180400220030224004405412282004860180040084112841824C046FC803442312D252C248142822A4441D22282551211361228A427A81028128402408C1CC4488722201C022114810584247861422204238818A054E11002B1287484862804144F27E4100441412002501218C92120010082449C4248CC4845048AC048481 +:80388000281800442508E04442C2240025421408468102502882240080028524384884DFF6090000903200212400101202200215022014120800101201000089C11244812100000010848404000000E0A94B01408141C141218024081611A42800A2C8822292C812228632A42215044D1245280242584343848401000026724502482414FF +:803900002124A02486820482D0220C8002282004289024800200222242002A24021C6412486248422A044848400800484220041002110000008888200448A788105118241118004414100415021282103212121480048100288188001444448C0C00190828888B844440228804A02422218B42868202E0B70600004042010000000000286F +:80398000220081220060182410020048000048000042002460820042000000CFE707288082C122C0221428C02800143B426120582141305122240081282851222905230255022400454283048024549440C44281C0420080045FAA021688211194812E1512188021842804121112281A6C1811301120FC2281881642014D48005843219161 +:803A0000142D312C219252C2868262222844D021623820982226C8292BA48302289B9814824B28C0212200282428C021002012128202222200134212092052218044050040020046044281144246C444002C04004214485D8D6096112A0518E032053342224244814221294C4622B1122C912A1CA4144C8484E48294414AC28285C188C06E +:803A80004824C8004818F061822068463582022004852284022304FF640A1AF688241A8323F241233E313D322E218E2289824216111324FAC2222C027AA8476A632497A222484E4487126E41BFC676221228051F21D524C1824D12861A32828AF862A36D42AB644E619552277908A304CE421FA4AEA62AE41884F41AC71422862112E21971 +:803B000062423724412C8431221E81428642E118922222BA98A21901141CE614FC42A1666122464A42218484E841210E23314239061B54A048405421C2428D4223E422AC428C121A426814F0B6DD501113437131D521B112052231436244135211217AB132E82499C42F14F135132F18E618F3184833A2284F68D488F29121687F48532455 +:803B80001A6C244D6D4F845444169C3112425E44282F4444A8263C086D414C645648F04222A322AA482B2460266F52060084A048001C019880091C081448340000825082448412352859849A42A828411B28611B28B081429221100120025440020085010028EF75081F16F6353D9F93F23C3C1F25F357173F17B623F23131BAF3FE782A38 +:803C0000F3C1D22F29F1C2415F79F382924F45F9E3C17F72F2A3D11F17F729316AD628F2ED676FC1F558D88F1BFD7C622FB3FB7A9AAF2AFC96581F5BFBF4944F6AF891133F3AEA2BFF36243F3DF9C7873F28FE21228FBC7C4153BB7724EFECBE42F4AAEA2AF2686AAFAEB2A2FC48486AA666AE6B141F16F6757D9F93F33C7C1F3B7327F7DD +:803C800063612B333AA32AEFCEF6A1B11F3EFF92132F3CF6B6B63F18F994B41F1EFE37351F3BFB73317E38AB378CF4AD5FFF5264982F9BFDB8AAFF32FE62C98F2BF9E2291F97F775155F5EEC2BF323633F15F5D5857E327F5EFA81C21F24F48CCF15F36B2B7764FFCCAE668FA8BC62D6A8F6AAAA2F2A5C8A6AE625F5AC56B061F4155516B6 +:803D0000F135151F11F716572F17B413513129F84A4C9AF851633B913F15FDB4B62BFE5F59ADDF5F53B331F553F19F11E92ECF2B1F32DA4EE4A6F6134B1F7CDD1AE4B8F6824AABF317915F75F386463EB23F31F1531367452F2BFF26A72F38FE23228FFCFC6223AD6B7774CFE83842AFAAFE2222AFA6F6CB8A2BC8AF86A62218AF4B4AF159 +:803D80005151DF51E511F155151F37F677572F1555333F33B112F96A4C17111F3DFE13933F37FDB7B72F2CFDD5F52BFF5F53F391913F15E9A5F9E8B38F36F679E37D4D1F33F3BBE39D333D4F9AE7A9B54FEC47F7D4B66F29F413932F27F3F2B26F6DF853536F5CE83AFE6362AFFAFE2323AFB47647F7AF8F2F22F28ACA2F26F62A6A8F2A88 +:803E0000BAA2FE2A282AE2267317061440011C012412000014400228130812281301138812011828188021941280011420022682840824408104C022800200008DCF0000122011022480210110021C082D82C08100201484024062442210845214289021904110011902004100006082212200AEAAC0421F4152281F41326A1F41324E1D0E +:803E800024EB141F48B64AB981B24A3985AB9443F24A9343F242B147822F14F924484E914FA2C4814FA264554FA2645D4FA26C59ACEC49D2A4FCD1244DC21F49D22CF891248B841FC9B24AF88124EB141D6CAB941B68AB9451AF443924AB944B4AAB944F82B442F9A448984FA2F474F47024D2C1B4287411382C4C742ED141F42E111F41EC +:803F00007422B411D44AB215561A3AD41AB814C4A54F82F4429565F848B16B128D912A7C583125874535F218253C7418C5421FC54298418915F148121D2CAB141F48D22AF181488D141F88F44A3686D838F3A448A9F1A44829B184B44231862B144FA8F1C4E6402808000000000028000000000018800800001400004800000000002800F8 +:803F80000000002501EFD404400400282128400200002400C2282100280080024A1204000021008092420000804411084082440244002C012008820000008002140000400822001100000024401802008044012004420020044200004814B0810C30C40080022800412810814202A084AC4222021A4221082820425421401A480280249404 +:804000002121003044A0421008400224244C4421F1E19800008200210010020000000000000000800400000000004220040010210442200400004F9901504100008002002800000010044004400284004002240000002004000000424100002002F043CB002A0114001001248420010040040000812146040000832402450121212821007F +:8040800000000000400890281008F0D5F50016051400601200A12218000041400400A4D024048400C0482902354402201202420000002014040026088C02D0840120020000000000000000004004000000000000100200000000000081000000F0D821800200400114210000820050140000100410880100000000002800404888088182B0 +:804100000080040000F05CA1002614080000484242810000001002000011410000001004004901184228000000400400002218F0C5E3000020020000140080110410040084000000000020040000000000001008000000008F41022244818042011121420000400415441402400840112401000080040043210248228484824008814420DA +:8041800004002200AFE3098002000020044641088218000000004100810000004004000012000000200800000080017F9D0B000000400800400100000000000000000000000000228840082800000080010012F0E1FC00000000000000001004000000000000000000000000000000000000000070AC01140000000000000000000082007D +:80420000000000000000000000000000000000000070F303110000000000000040040000000000000000000000000000000000000000F0184D000000000000000000000082000000000000000000000000000000000000A043000000000000000000000000000000000000000000000000000000380000E0EB0F0010084088044100000092 +:804280004400240000000020010000800100840000000000000000006FC60B0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000002400008840020000000000000000000000007B9C001001AB +:80430000000000000000000000400400000000000000000000000000000000009F7F070000000000000000000000000000000000000000000000000000000000F04FFE0040410800421004000010040000000000200188002180010084000000000000280000F0A8C500000040080000000000002100440010020000000000000000000091 +:804380000000180000B06C0E0000000000000000000000000000000000000000000000000000000000F04FFE0040010080045400004840040021004400100218808802218001884008000028840000800200009FD2010014000048405588281082044480022100448002214818808802214818448828842148408481421882041E14800244 +:80440000211A01445C0300000000000014000000000000000000000028000080080000002884000000001B72004001008004540000484084041002400400218001882810021880088400008042080000280000F0E2D1000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000D2 +:8044800000000000000000000000000000000000F04FFE0010020000000000281002008002000080028004000080044480022148400400214840040021EFA20A0000000000000000000000000000000000000000000000000000000000F04FFE000000000000400100000000000000000028000000008800000080420800000070820E0053 +:8045000000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000008002000000000000000000000000F07F4D00000000000040010000000000000000000000000080080000002884000000002FDBFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 +:11458000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B +:00000001FF diff --git a/kernel/xpp/firmwares/FPGA_1151.hex b/kernel/xpp/firmwares/FPGA_1151.hex new file mode 100644 index 0000000..5ecab69 --- /dev/null +++ b/kernel/xpp/firmwares/FPGA_1151.hex @@ -0,0 +1,664 @@ +# +# $Id: FPGA_1151.hex 5128 2007-12-13 14:30:31Z dima $ +# +:020000040000FA +:80000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AD6FF400038460A006AD6FF400038460A006AD6FF400038460A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4455544455557475577775577675577775577765566665563625523235D2E37C2B511115511115511115511136 +:80008000155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111000000000000000000000000000000000000002552222552222552220025522225522200000000001AA1111AA1110025522200001AA1111AA111001AA11100001AA1111AA11100001AA1111AA1111AA113 +:80010000110000002552222552222F21F112122F21F112122552222552222552222552220000001AA111255222255222255222255222255222255222255222255222255222255222000000002F21F112122F21F1121200002552222552221AA1111AA1112552222F21F1121200001AA1112F21F112121AA111002F21F112122F21F11212EF +:800180001AA11100255222255222000000000025522200000000255222255222000000000025522200001F1BFBB1B1755777000000000000000000000000001AA1111AA11100000000000000000000000000002552220000000025522225522200002552222552222552222552222552222552222552222552222552220025522200000066 +:8002000000004F44F444444F44F44444000000004554444F41F114141AA1114F44F4444400004F44F444444F44F444440000004F44F444446F64F446466F64F44646000000004F48F884846F69F996962F21F112120000004AA4442F25F552522F21F112124F48F884846F61F116164554444AA4446F65F556566F61F116164F41F1141411 +:800280004554446F65F556566F65F556566F65F55656000000008AA8882F29F992922F21F112120000004F44F444446F65F556562F21F112128AA8882F21F11212004F4CFCC4C46F6DFDD6D62F21F112122F21F11212006F6DFDD6D68AA888255222006F6DFDD6D66F6DFDD6D6000000008F8CFCC8C8AFACFCCACA255222000000455444CE +:80030000455444008F8CFCC8C8255222004F44F444444F44F444440000004F44F444444F44F444444F44F4444400000000CFCCFCCCCCCFCCFCCCCC000000008F88F88888AFA8F88A8A255222CFCCFCCCCCC55CCCC55CCCCAACCCEFECFCCECEE55EEEC55CCCC55CCCEFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F88C8CCFC8F88CB8 +:800380008C000000008F84F44848AFA4F44A4A255222CFC8F88C8CC55CCCC55CCCCAACCCEFECFCCECEE55EEEC55CCCC55CCCEFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F88C8CCFC8F88C8C000000008F84F44848AFA4F44A4A255222CFC8F88C8CC55CCCC55CCCCAACCCEFECFCCECEE55EEEC55CCCC55CCCEFECFCCECEEFECFCE8 +:80040000CECEEFECFCCECE00000000CFC8F88C8CCFCBFBBCBC3AA3330000008F84F44848AFA5F55A5A2F21F11212CFC8F88C8CCFC3F33C3CC55CCCCAACCCEFEDFDDEDEEFE1F11E1ECFC1F11C1CC55CCC4F4CFCC4C48F8BFBB8B800EFEDFDDEDEEFEDFDDEDEEFEDFDDEDE000000008AA8889AA9991AA111000000CFC4F44C4CEFE6F66E6E1A +:800480002F22F222228AA8883AA33300CFCCFCCCCCEFECFCCECE2552220000EFECFCCECEEFECFCCECEEFECFCCECE000000004AA4441F14F44141155111000000CFC8F88C8CFFFBFBBFBF3F33F333334AA44415511100CFCCFCCCCCFFFFFFFFFF3F33F3333315511100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000008F84F448489F95F51A +:8005000059591F11F11111000000CFC8F88C8CFFFAFAAFAF3F32F223238F84F448489F91F119198558884F4CFCC4C4FFFEFEEFEFBFB2F22B2B955999855888FFFEFEEFEFFFFEFEEFEFFFFEFEEFEF00000000CFC4F44C4CFFF4F44F4F3553330000008F88F88888BFBBFBBBBB3F33F33333CFC4F44C4CF55FFFC55CCCCAACCCFFFFFFFFFF9E +:80058000FFF3F33F3FD55DDDC55CCCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004554444F42F224242AA2220000008F8CFCC8C8BFBFFFFBFB3F33F333334554444F42F224244554448F8CFCC8C8FFFFFFFFFF7F73F337374F42F224244AA4446F6CFCC6C600455444FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004AA4446AA6662AB6 +:80060000A222000000CFC8F88C8CFFFBFBBFBF3F33F333334AA4442AA22200CFCCFCCCCCFFFFFFFFFF3F33F333332AA22200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000CFC4F44C4CCFC6F66C6C2AA2220000008F88F88888BFBBFBBBBB3F33F33333CFC4F44C4CCFC2F22C2CC55CCCCAACCCFFFFFFFFFFFFF3F33F3FCFC2F22C2CC571 +:800680005CCCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F48F884846F68F886862552220000008F84F44848BFB7F77B7B3F33F333334F48F88484255222008F8CFCC8C8BFBFFFFBFB3F33F333330000BFBFFFFBFBBFBFFFFBFBBFBFFFFBFB000000004F48F884846F68F88686255222000000CFC4F44C4CFFF7F77F7F3F33F33333C3 +:800700004F48F8848425522200CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F48F884846F68F88686255222000000CFC4F44C4CFFF7F77F7F3F33F333334F48F884846556664554448F8CFCC8C8FFFFFFFFFF7F73F337375F59F9959585588800655666455444FFFFFFFFFFFFFFFFFFFFFFC6 +:80078000FFFFFFFF000000004F44F444447F75F557573F31F11313000000CFC8F88C8CCFCBFBBCBC3AA3334F44F444443F31F1131300CFC8F88C8CCFCBFBBCBC3AA3330000CFCBFBBCBCCFCBFBBCBCCFCBFBBCBC000000004F44F444445F54F445451551110000008F8CFCC8C88F8FFFF8F83AA3334F44F444441F15F551514AA4448F88ED +:80080000F888888F8EFEE8E86AA6664AA4444AA4448F8EFEE8E88F8EFEE8E88F8EFEE8E8000000004F44F444444F47F774743AA333000000CFCCFCCCCCDFDEFEEDED1F12F221214F44F444441F17F771714AA444CFC8F88C8CCFCEFEECEC6AA6664AA4444AA444CFCEFEECECCFCEFEECECCFCEFEECEC000000004F44F444444F47F774740C +:800880003AA3330000008F8CFCC8C89F9FFFF9F91F13F331314F44F444441F17F771714AA4448F88F888888F8FFFF8F87AA7774AA4444AA4448F8FFFF8F88F8FFFF8F88F8FFFF8F80000000000000000000000000000000000008F8FFFF8F88F8DFDD8D800008001000000000000000000000000004001000000000000000000000000DF75 +:800900008D07480000000000000000000000140000000000000000000000000000000000F07472000000000000000000000000000000000000000000000000000000000000FFE40F48008001000000000000000040010000000014000000000000000000000000F0E6F40000000000000000000000000000000000000000000000000000D7 +:8009800000000000FFE40F2800001400004840012800484001280000002800480000108204140000484001002148000010F26B52000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE80840180020000001002000010024082 +:800A000001002100140000000028000080880200008828002800FF9C030080840100002001000000000000402101000014000000140000001400000000007028034818148002800414182810820416012810A21140012810A2414001002B11484001280048408188022148008828108204F05C65808401800200000010020000100240016A +:800A80000021001400000000280000808802000088280000F04EFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000210000002100180000000000000000000000280000F0994D000020020000002400000000000000180000000000200200008228000080080000D0C10C00000A +:800B0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000008001800100000000000000000000000000F0A149000080020000002400000024000000000000000000000000200800000000000078 +:800B8000EF8A0C000000000000000000000000002400000000000000000020020000000000D015020000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000002200000000000088280000F09AEA00000000000000000000000000240000000000000000000000009C +:800C000000000000F06646000000000000480000000000002002000025220200220000000000002008200200002F940C000000000000000000000000000000002100000000000000000000220000F0855400000000000048000000000000C022000010220200280000000000008008000000F0D59C0018000000002001009800000000405E +:800C80000118001100000080010000000000000000820067E5000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00400100240000180024000020011200002002000000000000000000004002000000CFE10500000000005F +:800D000080010000002001120000000000000000000000000000000000007DE10040010024000000400200000000000028000000000000000000000024000000F0CAFE000020820420824402002400000020040010210410020000008004000000000080024200F0823100200200184002200100400200000048A0240080040010020034F9 +:800D8000000000C20000280042004A22F8D8D9000000481800000040020000000000000042004002004003000000000000800400F03C270020022800C0224230120000240000800442204681042400000000200400008A040080022220046282EF214881040000200223011032220000006022008001420040010048004800002162200427 +:800E00000028280040410248CF2F0800A01248004041011301482880022200241120018002001C024001284212002800002602000000002480F8D4F5000014002224001248004082046022002004400100184800400200000048000000100280128104D06703420013022082427112814102480068800221281148002002000010012200EC +:800E8000002220A42460240020820280024220F8813700001242001002B011440200210022000000144800122A04002C04200100100280020010020000C0431FB80912800228A024112842288082040000201202182382210622264202C022808202201481229442138802800882008800A22A94828F8D0C10011902001224002B61250159 +:800F00004812222006004222482C04808484840490411118581122484A018012232408244227244A0242C800481F87041838002222002346021420042A1422020042200412800620026014222A140162208222022094218028A4822A0842288084C281CF3D05481021212481A3248022041304004818122A0540022002180010228203000D +:800F80002A01A0141002800800291802212182002C28F258BDA04211121842424828482C22324300000020020080A24226022248904100281CA424C0212800102232C100484A082304238402292A28F21AEF00222222000025022002210021480062484268482121482904290446818404C04160140020860842420042A084200430424804 +:80100000CF2C0C00001800005840021800622828000024004800222002002001001218428024220800202822026200F03D44001800806221420048C0427062220400425840022400220000000090214021020019042800200280082240017FAF0E001C05121A0400000028800252520010021880180218282AC1614081118104002D422863 +:801080002800828868002282228888422114F7C620041B3212621AA7567E622AA2622F22063521A444802681A232282344B24281A6216A662668222D4220A2262D61384A11F12121112E111E622B22F041A319AAA4A0888A784222B242282AA444486E218AE6CC021AE71341E11282244242219412F032632C8454226E420032A056484A45 +:80110000E42266242E429062422C26B423A7441B4113F261411681036A86226424428AE41C641860244E42AAA8A42CA4C42AAA82AAE818AC86AFA502902112181A23A421D02264244213A4242981A22123A6764AA544000023B242512212224AA122422820041B22362144A1452B12482B6222222AA48C4880F68242AA92228AE428A2242C +:8011800024217FDE0F4001000018C012C0138001180000122001211022011221122041011440010024400100002440020000D07E01821F1283A2324AA2231E222B232B212AB252F33123567242B2522327A3137AA1223AA1151AA1272B46423E526E622B562E125A25A1115AB15184B111F111311996413E1223C5222B441386A446A0844B +:801200004AE824B422E8247482E116A4C248C814DDDA80B47127A1525AA4534E422B472B457E122B552B433B272F25B11221A3477AA117284AB452A1554E224E429EB22B731EB22B542E127E525E216AA6261B671CB57137112E21687E722B552986B261C8A14AAEEE4A88BA62A48A6ABEA2BC6186BC22A6C46AFAF617A0551F11A4213A38 +:80128000A3246AE224F262322D622B732B241F36C3622F21B142C432583AA5117A273242E026F36242882E427E722B463E225AF6223120F471612AA3731E111119E621B37261262B441F1EA288EA8C2224E82CB622EC249EA3CA24B8A2A66AAAF24A2FA06F1B6317117A21A5175E522F22B14264262F25F163133B6427242B556E726AA5A0 +:80130000275AA7755A25A4444E224E421EA22F23F782222B4476E22794326AA6351F15C6311B711B331F1292615E722B372F2692221F1EE21AAAE6CAAE84AAF8E2622F2AB862BE22A8EEEAAACEEA6C1EAF160E1880011848184880044880044820818204000000008002200222A012601220822422280220088228821182288228823D2F67 +:801380000011008048022502244001250229820400000021100200230200144001002C01001482002400D012028004F02FC980B41162121B2166B11132621B212F36B111F262921B212F1439112B94322F1429F24291222F14AB424E912E421CFA22425E212F22E519E22265192D52DAC2521B292D531B29341B2946B1917642B381724267 +:8014000092612F1498212F3418F14282222F2428B2422892822AA4842E42CFCD0F2AA4412AB41122B6113262282B1619B26299214A9B214A29F24291222F1429F342A12B434E812AE514AAC25EA12E42DE212E42D6C143DE2148DAC2439AC6431B2946B19166141B282384E61498612DA119B642A8422B842AA4842A94822B424AE8226407 +:8014800012008248000000000028800400000090128008000000008004488001000080020000004001DF4B07820020042400004003A01242108304128004002200282C0200800200294102488200002426022848008048F28CBA20A42980012E1220C2422AD4222432428682542111284822132202226842001110832402271242290121A2 +:8015000060124E11264122A28426C18224C2003081282044A1245F7B4921A43C80012A01298224964222394482E6211281C241282C8203322A240828113023172422702221A4219042242E111A74228194228A64122A08239C2221E0188442021C88F2D1670000200421400224402208114210824401800448000020020024000040012013 +:80158000084002002002004880F4F3730020020000424821134102210082000000100121100100003C0814004800000034000000800842F09A76200220E2240228002130C2200C8002308128800242A0428022482282020028181642021180223C8100004A022800424228F0DCFD200228282C062200219093308221000011000042E0224F +:80160000048048222202708182321118101201803481100120040080042A046FA80300000000484821488004808208822820021001801201000000400242002888001002282002802804C0DB002212280028122C04C0420012488004224002184280A48486014081A821C01218822601A02100225021004888820024422420724C03008022 +:801680000480041448181420022280010046022C0110820800268104800411C84200501200E2224800428008884E22A0842F8C0500400100210024002100880020080082000012000000000000800400004002000082007FEF022002110022230129C412172400182A24880422884240824C8284C481180048001A94121C98A142200248BA +:80170000226014004888290882304282A0486E2F008081022004460100240000120000000000002022A81200000080012501A028214800420080A84260129F250B1222102121B21222922222002131882901282246118232812C44C123C0224821582800181419811201198922C46110011C84084222004248422229F4EEAE10010011137C +:8017800044210446024211422096229081008004800888110020A82920042B41002011024840011082084A2882188108F0566200140024000020B8120212002200182004222014218585021118421001001C02282440210421482024220442006234DF840D1100281142204422041314211422C48142214A120100B88048A12848800412C4 +:801800000030114248305125118108881188428842884288248880F84CB8A0343220A121321F25A212683248000000282A04258122B31244B112225222004A28A224268122828282022880862224A6244A0823282204A2222A2C263822AF15040038140040028880022908290288002A0821A82901802228220220280400110082000000E8 +:801880002100800200004817B80000000000242810422208210014001304581400E0281481044814000021C84200000020040042000024CF4A04228212226215021120880848886814424A2988C2421CC42288A2121CC6410028000022002012011448192ACA818004200800286014886F5D0400682008002420420128001111112128100D +:801900004281D5228408132208C0D1214229849141208435812400800428000000002114CF480A1F12242801171E15A2142D42422CADA41B1235C1428AD821A6248E82822C9421421F1CB6C2D823E421D912B2413222212A2502181344C1113F1243011F11F8211333A442114846812C988280268A0288C04142FFAF44A111968162111893 +:801980002F11342211232228DA32042D112B242333A11381DA11E11408181F23A4863714172426A3E44E82C6A1244AB6518EB663A42112286AA46C1AC4631C62146EA11D22461182A44E62A042EAA424A22E21229F6F03282AA2121B221AA2261F11A2362CB26212A22446A28C244225A16617366A7222B2216622288E212A26A2C11F1888 +:801A0000A16A281CA499238A81027041922118CA0A33A4E8A0C8114EC24288884AAC84882AB442EC24F882C2EDDE144218C011481C8184818481C411482CA1482C8184818401180000008840022E926022E0220122A092603220226812822088228822C821822882286FA2032A220319A7221D112AF211113A23E829F912322B11A0911E0D +:801A80002137111F18BB31FB31323F1DED14F43171EAFE21811F18E416E637FFE341281F3C5C22272B1E42171235723222712113F23181121B461B4415D11124E224744292624A8604424AA64428482CF253DA142E21CA84C2612E233D422F22F223432B229AED2BD933F622231ED22F21EF31F231211F18BDB1DB31F4E3C12F14F43171F3 +:801B00008E921F3AC8E32F37F742432F1EA4A21F3C5C322F28E128F4414135F3534315D313A444171D17384E433D411F12F481411F1CE412622C29A24C48CA84E21CA444238824FC8885A0671AA5121B317AF671132B6717342B66FAA9EC1F24B243B6D2B1C2F841712F14F4D1811F1EFF63213F18F853111F12E63EEF1EF841833F16F672 +:801B80003173EE43CE223F1ECC612BAF2BA51F32B641B633B613E22292221F1FBE91B662B662B681CAE11BA21F2CFE42822B886AAECA2AAA8A6AAECE2BA2AAEC22BEA14FF171719AA5331F15F371711F25F573711F35B562A6CC2F2FFF53732F34E624FC72D23F34F762611F1DFCE1F13F17F7A3811F15F321618E83EEC11F24F473711D64 +:801C0000431F3EE42AFAE3C12AB2F2B7F2F621631F16B633F723323F16F261611F1FF3A1326E633F12B6A1EE1AFEE1E18EA32F2CB8A2A8EEAAAEEEAAAAEEEAAEAEAAEE2EFE89AE00004002240082000010011348022800114231423110022004005012400114004001000000000000CE42400122400186210112211A5212122928511212A2 +:801C800030114212148210219451C0822820D1221881244102141B412C180140114102210000002004FF740E1CB41142B11162141B21271419B24291212B9419F2429313F84293A22F342BF24291222D91AAE414E922C4A12E4216E122E419E2226D192CA5292CBD91C2521B292CB19122B491F242921B28271419F6428219F6428119B4B9 +:801D00004228B242A8422B842229A842882E428F6A0A2A91415819A212482B1219B4229141298986AB68981B482DB1482DB1AAD412B182E414CB121CCAC21EA11D424AF2218256E13268192EC213E922B481E422349162112F12A84826B18134228AC4211B68218A94228A94228AB4423282288E422FC90E20880400000000800200000011 +:801D800000000028000000008004000024001480022800000014F08AD5200A1200282902000042000000130300221C984100822400222119022B288021858234414240021C04000048002860222BCF00822A08141414282234964181410230532CA6212416A1251A8414021C0118281965241842208401148819082C02828A34A129486220 +:801E0000242C048A04A814421C08EF324201C218001C32228042032044824222C52232267311021A249783C2190198283B1413D422210446A238E011846512A0424880C4212B8630422420842452214A4221B2C90C22A08240011428001C19810100144820013A04001100000028902100008882421121822C28480124482008820088F0D2 +:801E8000E8220000281420924124124612613400001A04120020021100000080082A08804281C48200008288102288082008A024F034AE200232124868112AC141004A018AA1844A93411488424882488842486810C12214224821484A211242011429828284480121404202482220C44100AF910E228001116819A2143C840118158221DB +:801F00008841A114881848884282408104142C0222482328A41400115021A22100C082002488002288481448F02F9500808223049021004239242428A42442142004002242422200100100A08228212811422022244801821042828804004222F0C8F6A0142218680013023021200388800240014022818B028008001400228210828C02A3 +:801F80002848004031424820081081022C0A48FF6701008024042001290420A8420023880422602480A584A041888228141C3242002422C22024012448A20082200462000046022CF2EDDD0000000028001210021061140000000000000042A02818001100008200880000240014200822D0D30912281222426012222419260188C85021E9 +:802000001B480022208481AAC2A04120881241820438249083884A82014A3842A8881582842404220020888642F24545800400002001001A120220024814000048000000A042A08280880200200200008800822304200282A042EF9D0F48721081C1110050121220582200922192211A2201E0280218808991916898B0410A4A83820C98BB +:802080002882281CA4821002828E2222282280226232F0546F8002282280024A82A4288002282002702201A0824022240A2200622004400200422011018821484800200482C0C28084B8540740218184044248008248482004424220922229046219924214001906222848006022284021822286220440032088280480C42123F49C2800F1 +:8021000000120012003042002002208202C8800800208404000048480011602242240080820800222022068288281F330800209121322822281B8228A2258224A8212A9C8324005E212AA9851CC461222822C22848628A8662188230218223C141213042468106212018024888802484BA83051800284290410042130800200818E0280398 +:802180008246D112A2182C41A194882246011C88818812218138211C0400110080B44218828814010000571C20228112014200240000102224011220094002A0148001181118148084018024828982E8280288800842483081800420F44F8120041240110120042120880410B2212488081410020000000028C02100800225D1226C28805A +:80220000084A088002A8808428CA81F0A829808182042242322022A44242422842C228241100906280014A0A288820410114208204B0820480042048A268200448601A0021F0436520A2511AA125A0412A05F042426A88082D42A0842B48211CCAB2281BC8682F21D2222A9441A0381CACA422A213671A623B6A22271A2212E6E222BE62C8 +:80228000AC62398C2A88384290A28AE21CEA12A4442BAA469322AFF6094A47A1222E11261121056E4213B88204272CA086C0224ED38632A28ADC12612C6AF4814125A3245A848422228488841A0190C14AE4249C418240226422482420A6466A044AA28848AEE162AF240A122A02111B746E3119A266282EA11B216A862C9442AAA7971B7A +:80230000223B13B032A1272E911C28A6E33E11AAA283EAF1115119A7758AB241E418A6111A82F281223F1AF3123125E128F2C381A2CAE424F8C2418AF882E282882AA4882842A0C8F501004021080040220840022048124122089210020088000040010000344002248200240000402108002F450B5AA2261219A62717161F16A2462A2217 +:80238000B4E24A12028AE821B162AE7726A1B34A64111F1BAAAA3F1A6A2C3F16A691AAAA5417131AA1CADAADE88AF8A1813AD311A6CC4AB433B382A2CC1712371AAA8EA8842F247822B262A4C66E41A0486A8444F1C53B20A5531AB121B2F1D611A1374AA42217342BE68E822BEE2F24B4C2EA2DB972F3D3B23B992F23B3D2FF53E11F137D +:80240000F6E1F31F36F441F33F17A751EAF641711F17E613A3FF7AF5E1E1CEA11F1FAF331F1AFAA1813F1BF8B3B1AEA22BAE3F16BA62ACEEAA6A242B2CEEC22BA82AA4CE4A2CB862A8EE4AA835A0642A26F311313E3115F13131E02626B2E2EA26F4C2A246A2CC4E422F26EE22E23AE822AAEE2F14F4F1B11F1EFB83811F34F86361A0BBFC +:802480001F11F131417E61AAA88C1BC81B881F1A0E1F18FAC1E3FEF23B112F2CFAE2E217323F1EA2EECEE229F8428227222BCE6AACA819A2C82BCC482AF27758A0553A21B331B371F751511F17A3446E62CEC22BE6242BEC25B2E2EC29BBF2FB13333F19F932322BFD1F15FDB1F11F3EFEA3C33F34F473711AA37F1F1DFF31617AA6FFFAC9 +:80250000FF6161CE811F1BAF331F1AFA81A12F1BFE3231EEA22BEE3F1AFAE3E1EAAEEC4EC22F2EF862C22928B2C18CAE886AAAEE6EA1FF4F0318800118C011480014004880044820A824132824A82411004220044200000000184888482248A048208802A0482800826F4102009021421180243481232408102228B4811402210015820837 +:8025800000804881A428C88AC28128B0814282E232084682E214082C080021800A208208EF8F032AB41142B11162141B212394212F24B191B24299212F2419B14229FA429313F242B3A22D91AAC4912E421CF8224216E12264192EC29E212CAC292CB4D1C2431B2925B2917242B2917242B3817242B381F2428219F24282112F1428B2426C +:8026000028F24281A22B842AA4842E427F6A092AA441481B2162122316B16231912316A1B41B282B94924EB113F142B1B22D112B491CAA521C89EC15CA521E212CED11C2D39E212CA52D3CB491C6D11B29421B6927148A62141B282394214A8AD212A8424AA84A2B84A22334224A6822AF4A012008000000000028180000000000000000FC +:8026800000000048000000000028004800004001AFCD0A20020038241C8154215AE81823084223C291208804422A2182080086A12400284248C02182210098A08410220200240048200240F2F7DB20611820098044220200482038812344826422260182108214022810A141107223E2340880A8482E82142C02804881D4214481022008D1 +:80270000821414A0E21412130C00184662212815A2142E8188A028E01C41A248241D2248823229A848214081061180744222240229AC48222B1822C224822222002C028004244001FF540480029280021142802821044632A121002A04800300008A021458282119C283118800821410021021944125010088804A01B0A509A021222002DE +:802780002240A2412001100210810828C021209441008024842144A2212428002901260200228200200848888008005F390E4A02185021D0212482A28214C224821C8C88A28121581420641C28282B244A8392212890822A01230E8800211908D0121C312270C2612C488A04228848428A84F4A4F42022A32180024200290DD8001488409F +:80280000031001281442222984031422208882622C00101292812110122108212400422A28082004EF3D06480040031D2222282814402238C2202289A8412260148A2492412248282A24C41248162231222882800122001B482C82028E414AA8844A0800C8428848DFAD0118002811002800C2285280C51242420040220192002C083240A5 +:80288000C11280210C12260218002022641286218C04210080C82240F23777000048420042245200880068801121244202A021808128880414201241021448428800002842000000A2002442229FAB0F001001001200121A1402000012002A2824148202280018428A2408128082810228242C04002100A048884082A2480067EA2001606F +:80290000121C04A02410A2816AA141A0412A95424A31118022AA14468282828132824A2281A41CA2111A08112AA1249228242C8422225612C80048204A22A86842249F2C0700000020011A24042908000080040080080080010021122C042A01210000201481084290828200280026F18926800211800142281021140124924A082492A000 +:802980001430813021E024421221A281806824428008003A0434482008800C284282000010F2986D00118002602311221023921280C4122C01002248482221240020082C248502428004222400280029840C0088422004800A5F250A4A02C011281C8102001800182021042280B212222104A043001200222D11A81128342248200620A27E +:802A000024222119042480024A62284A022E412F384D01280012200129810688C800A88820841202002C8142A18492820000188212200100828215024240220C209CC20000704C061A841221324119C64222258231412001487041A24227214229248812A24222162281862404422C02298242823212304100821082988311C28822242A9B +:802A800028084622F89E4500802201123100802284C881D022A2838A81A8121228C8348088C821860118111C018A0280820418218A868292432C2A04828012210262884072AA04004001002012011200200400008001142400122022028025810180820450221C0400002800000022E055011182280000A0412823A2384218002242421266 +:802B000088482C028004582023C41280011220A1181914022384388214404232414A082182292824C68188EF820F4081041382044A014800802A1902822C02201962162C2181180180226612429062800412222800200880028046B2214403822924F6C3F114621F18621213837111E1245312281B22327E82881622B122ADC12D128E521B +:802B80002B235AA1582225E22282B4533761BE51A21A8381AD11EE726A2382E124A2645AA7428E428ADC319A824A2AACC8422220AA2826014886E126322DE011221A8132314A32122223C2121F14A638181989E12DE212A28E294AB22238729E924A12A212242B1111582A94212B242C8218825B21A23623F24222464132E24E4125C2C29D +:802C000035E21888EE28A4241D42282BCC826E21887B3C8004281CE11482B521E421A6152F141442A14D82CEC2F0C21248724A8186BA41F621411D412F2822E21894821AAA846E4236B26134121B4912282B11182411A82B22F081222A14621439642C6ACAC22B862BCC222BA62CBC82F42A4B0014408104400214001220490124822400EE +:802C8000821001211001000021111811100100400124400200100100007F444C8194212AB221267A61F363212AA2445E132B55EAACCC1F14C4923F19B8E2A8932B574AA6AC6AA14426F24243CE425E324AE818A8884AC4622D222F24F1B1E18AA82315F18183317E321F15A5EC2BCCEEE11F16E22EAECC4823A4AE8AA8C4211B662BEA2A41 +:802D0000A8CE4AF4DD7D144AB461B621B231B631FB11232F2531222B241F25B113A1CEEAFF41D12CFB83832F2EBC52E72FBF72B7D2BB42AEEC6E132F36B422B972A3261F1CAD886AC4432F2632421F3FFF53111F15A4221F1BBF11F751735AA5C82BCE1F2CB661B2E2BE62C6422B64EAA8CA4AFE23E21F26BEA2BE62EA14A4CCDF3A4CB162 +:802D800041D61146F121116E511F36F163316E622B541F15B151A7E4CA7E81E129F922A23F1CACD72B574E622BEF2BDF4AF421723F34F442C25E521F15E119A8814A4513E226F491F11F1AAA732AE219487142F25353CEE223A822112F28F882E2299482E024E824BC62AAEE2BC829AC88AEE26E1A141B661B62111B151B771F35F75333E0 +:802E00002B662F24F343223B66EAAEFD1F11E927FDE2A23F3EFEC2E22F2BBB72B7F2AFE6EAEE36F6626327212F27A2271F1DAD8B6AE526F662622F24F4D2F22B9F3AF72121FEB13E713F36F65252CEC22BCC3F2CB663B6C2BCC2DE21B4A2A8AAEEE26EE22F26EE2EBEA2AEE6EEE18EC22B41A01240012E11E0128144A2411448A0410028CA +:802E80008022A1241228A024800242884218422220020029012A81A48240A248240048248E4128A02420045F6D0E1C0422004021512228228218A094122DA18A3442304280C8424641021B521280E22224453291204183523219C21240B2810428421188224E82602482208208B71980B41142B11162141B21272419F2421119F242931B31 +:802F0000212F3439912B94222F3429FA4293222D911B4A1CF921421CF8214216F1234296F1224296C1C29AC2C21B2D2D421B292CB99122B49136421B28271419F2428319F24282112F2428B24228B2422892822A84E822F4E58780B41186B411021A3642284A81B242B911A2B41B294A29F24291B22714A21CB1A384F921521CF921C21A00 +:802F8000B82164192E4216C1C39E212CBCD142B211C6D21B29881B6923A428271419F2428119A2A419B24228A284222B842229B82284E822E48F0D208804000000008002000000008004000000000080040000000021280000000014E06B0400108114011A22E1312821011220012142142A8921024262200222C022202222228321284852 +:8030000042014211C08288802C024282002028F4B963A014A68101322B8148002820AA41002C0618212C324122124A18032A418289B521218521C44146022816C142184A811422B8220C460221904180A4828691411CA2823E6820651E005E22118003199212226200282112C023CE122832123924A821282B184AB221B1411122C66122F2 +:803080001A22E1198494122B412442112B48822B82244A288284A4482AC8821344A1C29F13040018112029041892208921011A440223041C22018A042A040018202201C042200288408104822260240040010011800A8E8800002822112503292188A94820010050128242002014022200C22C04002440011428241002230424824240022D +:8031000088800880F4469E002222142412321848212962218286028AA3D298A04122424A2214314111B041888222A2812CA4848A81A18226823A1286A1244E813B8228E2420024288A8284024242F01DE20020C22124302212482988A385E02801824A8148218C86043041218042014A82062C04181041022333812133DC32A824824221BA +:8031800042242823880C824200E78C0028002813D1210129418208290880836A212001A04248904111A0482882248A018AC482122A88B28102800628A0248008002220028024F4B4C580250248502180417112023812A025304221268102821C8112229442C822424041A2424A212422042880021180262422044A08682024442284F26976 +:803200001F1001A05242804403111C02A08428220080044248482818923290321B521C0288283012528821188220C88282200A0000221042826824AF810322804201000042000020081A02A08180028A0414000042003188001480082024021400002120088282006F7105262102114234400233912118128A24612AA02114481282182473 +:803280002A28B413A412B05212A124242A7C2281A4211819089288806422E8148248C08280A228304220C4422E918005221A02203411144821280042602480228288E414A24242004828A0250020C58200302220021C280848008004488084288828F272BB8083A221C012281824242C6224244225420240426222402122149222212221D4 +:80330000282511E222E81812328221803162008A04001308860248290888482142A2485FB50900001904214A230480A281D88005408121212121021118E0120118005213A44122114200120040012123048A02000000F09DEE002081024001001814A01448000000280011001A041A280221192288A8411001114800C042202428A48422EC +:80338000822924040070D6030020011148122004420088222D41A0522B41141A34210048140000480000112400400142118280028820140200230AF0525E80011420D42184633446224192A12124822C244102260200207412120123848214238AD8220812299142A0422014C14100821502004800422240F14F83C06100421821102221A5 +:8034000088021239A8212301271218A041A04148406122828280A1121C01182C0411160229210100113413344228280080084820F2988C00186800000000188002224A223141804201C0118081044001208124232222C221200222228882806224000028A8C082887F1C02200200624A3222A0A423088E4120045012004828111D2280045E +:80348000A8B08124840248400140011C0428A0841062120021233C2288200480F494FB0080A41280010020220128002212002830428085E222084824225214601222342A0448A042113302A042008220E2248804281002C778B02104A03442230123C212E23AE82132122B448AB122312123A34236A26116218432433642A2C84A22D21224 +:8035000011A18923F89241DE621B12282D121976529141198C52113C54124A7482622C8A6E22C8290C2A0486A3846F5B0F38121A22031D431F269751808F7441E114BC81A8462C0218159112621943D121C44119E61132421994E11B254229B241E2244AC141121122192425044A042C84B8412C6226CA6A24424EC24A9822A0424F9F0DC8 +:80358000122AB221011E536A32125E222B4425D222B222E928E121D122A8452F2457312F25A1243921B63127467242B123E123B28261292E422B73223ED3112B922F217223E3153642282A83F223418AB281B881FA232390C2212934A28222286A8C0A2F9203111811001800120000200112100100000011000080092A091400B02201239B +:8036000002146032820024C022000080F23668501117142AB211C6413F32322237322B722F2C3CA23F39F9D3D2173429FB22222B662F23F352412F21B172A7666AE626F66362CE132F21E323B1D2E529FD33224E22DE624E422F31C8223F27E322F232521AE521F262423F1EEE1EAAA61BE64E436AFC4141288AF862E2EEE2EAAECC4AA623 +:8036800066AAAACC47F8145AF441411F12B311E635F53333373135F372722F2CFC82823F39F9F3B23F3CF492B22F22F372722F33F372732F25F5327229A4462F27F763622F24FD13132F23B9D2ED2DFF73322F34E225EF24FC32932F2AF633723F22F232323F31F532723F34F4E3E11F1EFC61E16ABE43B463F44141C82CF8E2E22BEE2B15 +:80370000EE4A24B4A2AAAAEEE2FF85031AF211711F1212E136F6333337373D132F26F7F2F22F2BF113133F3DFFC3932F28DD22F372723F27F753532F25B552B762E612C6133F36F642C33F31F172722F2FF792D33F33F252632F29F272623F39F873623F32F622233F33F142623F31B252F661632F16F6616119FCA1631BAC1F1444A28AB7 +:803780002BE26AA644CAAC642BEEEAACEEDF760B1F15A6113AB351E237F733333F35F413132F27F7E2E22F2EFCD3D33F3DFAD3932F2BF922322F27F772732F37F752522B673F16E632C7533F36F652423F31F1E2622F2EFEC2C33F37F652622F2BFBF2F23F3BFBF3723F23F323223F33F363611F17F771311F36F663411F16C6C23F2ABE69 +:80380000C3FE41412F24E42AFAE2E22B6E29A44442EAAACEEAFEBDB70000808164124822004814004810011200002811002800220040011480018024021440810482288200282024F82D2CC0411922122182542220249812282D928A6424220029219322C0112E4214260258922722168124D82234C1262201197242024613418162240051 +:80388000822724C08220248AAA424214571280B411021B21421B212394212B1419B24299212B94112B9413F2429113F2429113D212A9421CE922C4811F2264111F2264192E4296C1429AC2C21B292CBC9142B39122B49132421B282394212F3698212F1418F14282222F2428F242822229A842882E423F1F05481B61181B21421B212384B2 +:80390000724291212B941B282BB4112F1428D21228D2122BF2429129D412E922C5812E82122E42922E8296C1438AE222BC81C2C21B69241B29421B28230621282726824A12F14282222D82F042A222882B4A29E822F4DCD4008004000000008002000000100218000000000000480000000000280000000000AF8B032002224216214503A7 +:8039800086A221000030510048008A0220041810A28124201202142028222A04424001820000422088222424F6FB42145811005022190215822248611C824819268898C11B8313242681786291221904115A188102C88842404181CC114081388229248244C1422400C6C242822814F08DA380E4140222481721194211D3228801AA0448C2 +:803A0000221384B881A4841D422832123D22C213245121B081D1210268884213048681641840012C8884A2C214482400822C682A2A84E424F256BC80010024A01400282A18412108198409303180842828240200D800C0820040012AA82142E0240814004002806424480000AF5A030080220200A0212008B042010042824200002210019A +:803A800000482830110000182800800482421124602410020020F2248D144A2102111819018091816800230C8A81E419841131B1D28286A12800781981A986AA01A0822AA88234C0813C0C272A2C0814218058122CA48288202CAC8428B0B208001081C21100122E812888002182421448A034000022A02119210138001B1288101142915C +:803B000021218A1282042928348125714222160248800824AF8F0D1A8402281800001242002B484A21015A8831811CA81C8813A882001C0488AA848C028222A8001AA84824C08240010000822C08884A282482F283A6A0240048002002298124842884828288222E94112868808C311188208444014001003A84840824244602268302802A +:803B80000880C422402288F8EEEC14001A82A624182200A01820C18268200400001391A280011A2A0811142C2C22A22128422480818812212208822A08280082002C02E0F20D00800124004842100180C1122024012A0880042002804102005888212880024880044882304140020020082A045F56432106281A22C412200229A1494292CD +:803C00002C8881A1844AA24BB0A18102E288C01132824A9141808892711A22022C028A8144C242222B48152298C1A02800482C0200887FD90882800122200242481001484222210048004E312004280000214221C0822022210688281448A028000021800888224A0AEF350B90116014102102280000122002481308001302134281A2216F +:803C80001442D800228004A21A28442102248E22A0243041004221200C48AA04AFD507122022011200800828A8002711C023A08414146018825021146012209C82252105293811008A34911C962100822188118A04AA14120221008FFA078A0100001158A04200008014210C8028023200008282262102A042001C12212224044A0830420C +:803D000080C44188282304282A0428488A041480248804242890114A98118081024218E024018888002A1422250300141E621110E1212C22019A828802C811808A480288801C0221243FE90928802284C321180020860800222200220000221A4821220413042888181200132408400182000022682128422302001CF2D8EF140018304138 +:803D800000801621C841C82182001502864211813211181188133812112928C8811121882160211440011420822844210800400288005FC70120810424426800211C0119011820082A01184800D829B412944224405221142124208104423A08482024C422800221882400808288F8C61B202428110100005A0200200480091200200200D3 +:803E0000C0610000200800E81C0280222832228008002880088008884F6F0982224832A041142800242A052880C44128134CA184223981B44121A284001A24A12416212D92D219881432821442824248822122A024200400A2482129F4D4F2141A6519E014944114112A21F482114AF9219118181813A1448E5319A1991F14C1C113E81100 +:803E800031611F1126E511A48286E11EA4A816A2C2DA9182171116B162B911EA11B691E2149421CEC28ABC82021113F822422ABA8254228EA2298CE81282E81C08118A22A231423B356A324228621D421A223812246A021BA78AA844821982B28184043D633B3C1E51194222B48238D12F32A44523582186A246C24E1113E814A822226E0C +:803F00004180AC668A68242C22A4442223A6842726FEA38082A131111A82641128221B618AA2441BA4A086481F1208271617222928E212A1228EA3E60226F241224E521B911F2284D23283E22881A8BA1F11768291812AACA2AE42F042222CB862681C1C2894426A883822288A24A8482F6E0142222022581248211A142211A241211A1406 +:803F800022019A842209924282421901190819089800A012C081A092C0810040A24814482882248A04822880F27FC320A836181D611F36F6C342213E322F21F382822BCD2F2CFC72422F24B4927A13F1B2A33F1AFAF1E32B446E311B4415F191811F38BEE2F7227329E824B472E723BB72A7E44AE42FBFF2FF21B33F28F883422B111F1834 +:80400000B9812AA88827282F22F42242C81BC8CAEC24B482A8222B842B8829A2CCCAAC447FC646F141411A051F11A5E61F17EF25F512122B751F1EF8E1E13F3CFCC3E14AA4CC3F17F2B2A32F1AFEA1A32B4CEEA33F1656113F39FA83E16EE23F36F643623F36F673723F3BFB72716AEE2DE42ABDF2F7A1E32F2AFAB3D21B111F1CF841A135 +:804080001F1CEC1CFC4242212BA229B881F861E2272429B822FA42C227222B222BC4CAEC24FC8EAB147AA6512AF231111F17B751F541632B224AF641B1DED21F1EBF92AB54DED21F34F1A1F33F3AFF33F32F21BC52F963411F11E11EFD81633F32FA52732F15E435F472716EE32F1FA7A86E62BEF22F2DFD93D33F2BFAB3332F11FBF131B3 +:804100001F19BA81F8E12227282B4C2B628ABEC1EC3CFCE2E22F2EEC24B4C2E82CBA82BA22AA8A6EA2FF2844A15D1A011F15F131733F17A7441E122F25F763B1FEB21F1EFF92922B54DED21F34F1A1F33F38FDF3F32F2DB4D2F9E3C11F39F9E1F33F18E626F653733F25F4D3C33F29FD83C32F2FA7ABFE628EC22F2DF593933F3BF2D392A8 +:804180003BB31F1FFBD1C11F1CEC3EFCC2422B4C2BAA2B881BCC1F1EEC26BE62BAC2FCC2C22F26BE22AAE6AAEA26FA97FA0080012E13C01340023440834412818204114211102114221402184A021002001C082901226022822400828044022880222804BF6C0D14008081B62201228246B18104480014221C081C280A24A8C02122468122 +:8042000068182A2188A428481122114A38811081082210120110022C022148C041FF2C01581B21141B21421B21271419B24291212B9419B24219B14229F34291A22F1429DA12A94A1CE92AE414F8214216F1214296F121C296C1C29AC2C21B293CB49142B291E216B891B242B881F2428119F2428219F24281112F14A8422F242AB242285E +:8042800092822A84EA22F4E9E120A26126B11122B49152121912B211B26239912F24BB91C212A24623EB34218BBBA2D412E12A41E122E811A852122B82922DC31A82AC292BC21B492D121B214AB8119292282998212D82199222112F24A84224222522022B4229E822F4EFBD0082480000000000280000004410021800000000000000000A +:80430000000000800200000000B07E0B5424005222111361238C282481054428003061442884C2800418822826A842224C988123A32120B821A1280088800C0080016880022A812AF27A3D24129A0228471AA02822808113889819005D8219E1C823E811A2851986328100504121138441828484440593A2482C81816B24871B2426A84823 +:8043800024C0A2002824444081F48DEF3015CA1122E2418C32A11962211628C318EA911844221D841621C92115A668147A388182805141D0819621288E44172C3A745401141BA4221232423E894883A28610E2210A28404202224AF278131082026012001222824200110024D048A24838128B2400480082230258100280028E281892218B +:80440000822C082C080000808422422483089F25010080C21219468102200260880088800838A2004420642280288828850880021024A882008222821486880820812A0100824FF10F211681C2125B427012C4482E124A38813BA4271930149CA414888F41A2485324A428AE418E422C5641424B4B4E2156DA24046D223EC147341E812988 +:8044800089088713238488082328245C12468109E8D02212A8148B24F0F5242420218272728432128C26318219E82498818818871498881624082A883221462416E422A4184AA248006B282B184384A281824189212E08A028C813448808A0852210229568D0E90C1001183413541480228432231884448004898AE4542384888C18D21231 +:80450000046634818C91C62B41B0411271921102F0812200888221C0821C68149820C2822A410820F8B8F7001212190749011682D424842265483E448022C8121148612C82E124211C88C294801444B1820282002AB1ADA425924148A31814688444882822CA024932146024284CFA39149018200400182128129215A441228C0441448106 +:80458000322224CC84819221484A8891242114301A99218401488502002A3418602144800A800A28882CB21844E21C0D2C1414045A22024342018428800812320020284501450215428208A0412008000010648222008822200420210410624144421FC40A184C118482A512126722281E422E98001A0412B664611426B28422D71C843438 +:8046000062A115C254296924415288251821042A31848B2149712468228C1288E884034882284AAA2CC014604689C246BE31C042803111224420611444B011A6944338482200811A0480014C38214A023024408282290912D08162248280A48416140821820018C024222928E14421FAFD2F244A02A11428150824244826026C08001C52C0 +:80468000144225621446211864844E114631424678427441B4422888B8411287088E24835C185C84C44468C848811031842A9448884D8245688290246F510114952481818801C1441288424282461884312A124321CA28C0930018821B81002C81B22101E86B149012008CD24211082123024227A228A931244D284A22828408BFF90180F8 +:80470000224248281628C1423A64348C6A214C2422B28824B48862826800281964428954424827828C9412480029018A914820048384698C8D1216A252962838C8824212128D948021F5ACFC5021124829224474531411988484604212822480581200881446E86841886882202838882CC148C8442884A018A694222C0A440000522901E9 +:804780008248200250221F320BC612518140482214B1420184000029318231141D88A119D418840215088C34124508851208124E81864248129C1186D942322A27412342B81814E19102811285C4441A28816D585F82021A92241AA4211D2689022243C2222828828270286443436144524122328B4881AAE41288328822224814428A0229 +:80480000002044C8444004824C88084280446C15820021484FFE0A440041121184A11184A0142901A90D81830228884110220200803112112899092810042820812101412841004426042A382A484E8822F06A57144180C249416B14644604458194884241244246A418CCF241845CC19862A0284116180452228044022411212351424468 +:8048800012A02499B158C2129018882C0338D022218423042F5D0416A84148008021C12888196841A0254008422B8140082D8845D21441A282008282E098011184228A34E42AA1288288A0825048800A0000002398228B82AF5F0A3F72768495138F8143EC123654CD42CFC2B258A668814E8458216D4413D6187488F649E1EF98F2A82109 +:804900008F8484E9886A189B1322848F61B1248A59882E596A7265921486BA74D1C4BD8C62A32D328E246FA1F1442287834E988E5819FCA2B46394884B711AD262E783E518E822F461F430442B268F82D212F43922FFE1D121D5113241374A83B2F2BB863616ACE522728834436EE1A664421B44AE819B6A97525F2646734472C8B2246E84 +:80498000AD85A26A9345C24519D842F88A842364834F1CB82CB464F5A184BAC8F22B4119E81631182AF4343C66FAA4C88789421E424B24AFBF47A1111F81217121944442A5FC121C2D5249F9438B8CE421E14CB8E8D888F116FA4FEBFB17184FA1B141FD14881D3247E46F24D4C8E184D6CABE117DC298413F8DF452928E821F19BC92FA82 +:804A0000A26283C1628B2B1F74D849E74D781AB848D68A15922C87218FA97244F298284AF488842F64B164B888AA368E9C4FFE4D0100002400402249022412200882309120098210032908290922702201002A084D1190841004000024C02450282004F09A7F1447246F65F1141C9F93F39D17FF7B53CCDFF6F244141F37F63D218F2AAB4A +:804A8000D54F6DF884C4CF62F2286CF5BB39F1A697ED9C9F96F6ADCDDFBAFA838323F81E154F469E424F46F626646E72AF89F118383B91FEB41F58A222AA0A5B3BFE724F2DFBD2D27FB3DA8AF49A8A2BDE1F81F4D1614F46BE424EB458F132A4AAFF78E88DA86E644F924DF16563EFEBF71D2D8F81F15D15FF555ADFDFF6D357F1ED6C1FE4 +:804B0000DEBAF8EB4DFF8484CFC8FC3C348FE2F6BFEF3FD1F9AABAFF9CFD4348DFD2FCFFCFBFFEFC6BF85FC7F76C6C8F8DFD7CFC4F4EF6E8EBAFADF1DA788F99FDA4E55FDBF73EBC6F4AF6181C9FCEF4F87F2F6FFFDADEBF56FD18D4AF88F85A789F19F4891B6F4FFDD8D8CF8EBC5CF16E646FC7F7E2D88F81E165FEE67E344F21F51777FB +:804B80006F41F131311F1AF63B7157D41F16F24D3D1F74FD2BBD8FA5BFD2FFC4562BDDCF67F1F2FC5F73F3B3976F73F9FFBDBF97F7ADDDCFF8D97BF866866F55F17476EF4AF2E4426BBB8FB7F6FA3AAFA7FFB3F84F6FFFB7F58F81F1A4A62F42F2B53D8F87F7A4A22F2DFC87C18FE6F68A882BFD1B559F9DADF62BD44D4CCF8FFB26A6CF0A +:804C00008FFD6AE88D884DF44A4EF23577FF7BF317351F13F37979BF55F65F1FBF76F34F3FFFEFF7B3BBAFAFFBD6D26F6DFDDADAEF67F3EEEEFF7FFF5B9FAFEAFBDFDD9F9FFF25DFCFFEFEA3EDDFF7F67F7FEFE7F7F6FEEFE7FEF676AFAFFFE2388FAFFFB3FB7F7AF6BFB7AFA1F9F626AFCFFFD9C5CFF7FF6674EFEDFDDFDFAFAFFD8A8A9C +:804C8000AF85F5D9D99FBCFD66F6EFC4BDECFDECB8EFE6FEF6FCFEF88F8DDD44FFA6260030228440583448268144410840E68904135128401401110085048D24410000B0240129016981542490841608926081A048608144124C22A124F0BCEC4031111081E1411402E08864148028480430842324480188136844654811048844884A929B +:804D0000921B242A08888E24D081E2220888282D82282B841114439212803224A98804471A4FC1063CF4112485F21124A7241F41324A1D24AB141F48B24AB911B24A19B54A79A5F84A9143FA4291578A2D914F8AE414F9A44A1CF8254A16F1254A96F121CA96E5A2EC49E2A2F491243CF4912487221F49F24C821F49724EF18124EB941D8A +:804D800024AB9419F24A9251AF243924AB9443F242B64F82F442914F8284F9244AC7F3E0B2F41164CD421B21A7261F413262157C4AF2812487661B218DB259A684478A2D334F8AF44231478AAD212B4AAD254F2AC5214F828CFA2648F022C88D242DC38F4992C29E2C2D4A1F49C2C217C1CF24F8812443F41128EB84282D961D6CAF243BF2 +:804E0000854E324782AB9443F84216224E94678AA9F1A452BFE704848248000000004400000084000048180000002100401884040000000000A011000000008E39108452C12014342400866818AB42884491281B21B024B81876C1C43114444C24022D7811C02429081634812304212A884446784412881202C810084028088F446148891A +:804E800008DF930B2722922884CC48325868AB8645334840682892184634214224B04428811663445C02888B86888CD142A2426B166C021143116488C8892A741431482F1A0170C211E884A118386888583641F2177A24608D4D29B08444B61C2632489D847F8438222E8845C218326E1126E148C232741F4132117279A46811278313C894 +:804F0000282E861338224B25BB432E44211149CE444728B068384A4D2343E4122106390C12818AA1244D4A411648F2924B7024820284810048230AC04820C8814004428CA4848A044110C42448800C8C4104861402211240B84848041285228808818483248902989A840A6FA107100180C1242A41581C682A28814188081C6A8810111873 +:804F800001480016D52604488304B02408410028A02826E281044821908A1984419882484A2202412848BFE1064B24A0121882256324124812123B82244A41240130B498BAA4161F88342128212F8214B12DB4242122E98368252EC24A82CA3295B2942265882CA8A486A925214260141902891884E841221528F27FB1C06411208198243F +:805000002E42124588C1221818838508190A4B8219E98124C2884824E033642489C4242E48189E284B782F288426AA2199E24AA13484A31D32C82B24212D48008501424B42822818009FBE03002A011231294198412A84B92148024412308812A0821395411C8202A554414D21522008801204502220A882A086111880C8411C85328289D6 +:80508000082849C1448C22F6F76B50484883011A04282422951494180041A21219C428181A44428C49021AA283A9850316218DA2292F8A91128AD1812E81311447222A048052428E181E68981302422D44822E428E34A85F840A8015020089941140222862412F42A14131491A48A124E02128C1122A04807881024043628145410881486B +:80510000246024301416A2818344C44128A041200828EC08581FF7094A0140485848D04A222124118108109848418A01002024184431484443342468228200400446644A8A022006200800144301100200AFEE0758128C018C15A4428D15324681C128C0144391298B4987549B186858C0144E828E424416C158CE192A8582B52264884D08 +:8051800083127018448894844F28D6242261239828219CB51824A834162468442AF844A84B38888FED0C430821844058282821C42938112C094622C8248022019281800228264214462422B922A1212E8212881B284D121A82014386048C8428081200460221002E417F2C020020C24185D218028489CE881129524212250C101105178116 +:8052000044002D1E83820820951450848072282158410084188921AA21118152804396440084004E282FCB09800117443041245142C012200822002240CA448848888E411148A1C88121811A5412E81298A021884668431B248846084288848C22648CC0884324082E1412DF1B0E8280821134C428221256081018812848081A021741D0EA +:8052800041014420512200205142256241604422824B214C030011281E220010846122202223A242145F150544288014391219012524180270121218D81289149682C84B428A94442CA4421C88D485A448A4482E41488C84044820242CE444A88446344846A43428528B84304A4628548400F08661001614248111449218224440B84201BA +:8053000064004140146A43E0410884431604124A0912842100841840644118301C19044B81898402E2284C48088481C0F1A0422812284210C2224A81A21811E0441A410413B38931111911312315D28179A1D481B911348124E082441D41944281188382286188906C22407548014245022002109282482DC1200124442187194548041077 +:80538000880181882C314C840088882400008418430411862101B8888200A840088288CC0228A0218011621218226483F258CEA012824C41220149154804608115981143218121B124341880A4384004404114486422A01418823880684320449414C01418008C888812A4422012C449F0DC7A400C8C46918C2180C128004422CA120286C5 +:8054000014113842101292418921948410388485028712205A82A061424280C888101168C854284098188638112088311288EF1C032A61491AF221121F41D81358854B11C14C582895F2621A211B18448A911415D112F1474C9EE557451B4447741B4C2D6B7F91F45188DE469E5A6F21F578224B44EAA2154F183938824741EAF61848AED2 +:80548000C49AEC828EF5A9724B844A94C88BDA2E44A76E1CEC9296A82E284731E09A0949A21A641E4467844F45F52A2285F8627846A8111E11E015B814CA12EFC17818E362F314848E91C3C64147719DC845355C812D41854894288CD511D122BD82FC182882CBE22A66814B92CF15F148344E155F832AD5590226A824A781688146B43489 +:805500001164D2623ED5E04184B22CF144218D5385EA55F1222716F4A8728E88848F18F28D5625FE1E8813B461F25C889D4A169211AEB28A28F82A381F42A184C74849384A17866748A7A147C12AA242B81E11CAD944694C8445388D8344E9897518A82547C1CEB24D186F8E03862AB148FF8878AFAF0A100465C14845012410240848444C +:8055800084248A44144124480485140111441110040023022A088884002A08419214001200241028514890289F1A0C4AA61485FA15729FE5F14D1EBB641AA1158ABA8CD833F15B4E3F74F58AA88F88F8DAD885A8CE5F5CF88F89DFDFFE9D99CFC4542EEF2EE421F518D817985E5A4FC8FD145CCF6BF96C766F48A8CE9AA8888AED84EF8B33 +:80560000FB74544F4BF96CFC4F83F34161AAFAE8885E188BFD4763EF4CF8DE146F5FFF35344F43F13434BADD18F869D6B054A673CFE2F215768FA5F15E4F5E622B336B37DAF38C84B5F323447F71F53F1F8FA8F898989F92F2E8C5DFDCF88BC8FFCFFCB999DFF5FD888BFFB6FC7677AF917588FCC84ACFCDFD1C5DCFCBF97C7C6FE9B8F254 +:80568000AFEABAFAA8884F86EF87F37C5C4FCBF978F85FD3F379FD1F8AFAC9B95E588F8DFD84AEEFECFEDE3E9BEE4F43F33C346F43F3B8F88F87FD83F6E044C65487E15F61F35B4CDFE4B143E621F1525CCEE48D8E3D13BFB5F657D7FF91F99888AF8DFD1C185FBFFCD78DFF98F8FFFD5F19FDC4D4FD4B6F26FC53536F85F58541CF25FD22 +:80570000C4C6AF75F788FA6E726F83AFCE9AACABBABB78BFA8B3FCF7FCB48F85FD7D399F57FFE9218F8CFE5848DEC86E8A2FC4F8D6946FCFFFF4BC4FC2F2363CAEFC8F82FB9658F054644F43F33C2E7F75F35E5FFF75F553722F43F36E7C4F4DFF989EB5FB4F6BFFF9FD979F6FA8B852F57D7DCF5EFDDF8D7F55F4E5C55F5FF545D7CFFCD0 +:80578000FC6F4BEFB7F7464D5F5CF4CCC64F6DFD7876AFAFFF7A786BEFFAADA3BAF8B8888B7F8BFFCFCFFFF4FC8F8FFF75759F97FFE1789F9CAD45DEC86EEA2FC6FEF6F4CFCEFEF9F88F82F23C3CCFCAFF68D9B7FB0080012C810412204142482349012011180113080021812911881818044100A0828443028884001486080086C82416AB +:8058000048240880028D9B200841503415981E10A24818D02811D42A3884181508D04A094C61285451009601F02212E02221091A0280684149E841A2821741902120018021123234209118226F65082E521F41722CF21124C7141FC1766AD341F26A131F48B24AB981B24A19F54A96578AAF3439252F147BA4D852F924485CFB254A5CF868 +:80588000254A1E215FA264192FA26459ACE449E2A2F491246F22F49124CD831F49F248811F49326A1F48F24E911F41F24A9219F24A9153B14A3924AF2439242B94478329F924488B944FA2F41776F0244A1B4143E2C154141FC1722AD341F46C131788AF44F18124A9B385F24296478AAD138AE444F3A4482F5451862F54FBA41A4E844DB3 +:80590000825AEAA2645D2FA26814BCED4582F8D12C65F21144CDC21F4192881F49968A1D4469E941566A1AB642B395D42AB224D428B92494184B43A9B8A2B44AF1A41A1F5B0C00000000000080028008000028800100440000008480042200000000000084000014E04301402602678295942230184C81812401818148802252482AA5A4B7 +:805980004142604283245284AB242001520012182A91411221C82F81041C22045086424944481828B448918CEF9A05F0A211842D18242A95141F2249041324423A146042843088427651148092284C120280C6148B284686A42826E212018D84C014E0822831A42482196988C042A02138116A7134C821286F54072453C7222C017B123295 +:805A0000139A1849914522163816282281A0824247B34F12A5424B212AB484322242288F44B22211C116428B522413048741325601232ABD2C11C421B601244394424E341618C17249C251CBA16DBB00104A382C8C14261106184800814528048122428008814044087048E482280482221A822108441884248A442228648840088042184E +:805A8000E881942870FE05410000110081901880118428C181414C214251844A08812AC4240040C412004218448860241E244A082364812098981028110200448444F0C8E2E022815226842783A5522583028223B821018CD92C512426BA38388149618232494208904348848CBB2221A4254C2402222684484868422946A4242266018A08 +:805B000005808181C851481A2485B67F082E12226542C2329502210089292181D82408318D241C99349126EC461808221448C0124961211A044A02908482421E248A06290440C18812001212821B4144844422AFF905410081815041831228183221701864814CC1A8294904281800842CC46410688A2242224604124C2202854248A624AF +:805B8000418B5222CA22A148812C010080A4141A24F4EA661088448AE281562A3418218439D1A1014F82012088A4412840E28304235182278826A221449D1483212888C4416082481662428E4800241A444A0C2883222814684A44666281F0138400298501008C14883114001634A2521002001256028B1420A44820688440D241E2812270 +:805C000041A8521682C84400188A02A0141604A82021031236C116882E145F12080015441122822112994122001018480820441808800612001888801442821A82280180015628042282002D12812001134808B0A80810C2182CC2782CF218411A12F11148C019124CE9811458820040A814424824899442228AB244C18D167AA4021A7423 +:805C8000E2A1122E982928C5248B41188B2980C43200A012824068483634448C28F288D30012451341424842981A442F12012542088088A4142A84419838A44A02834122412801422E9840022051248008424829C14889092C48981A3A842183688318415F560945021042081504442228184098488141814C44A84142224A013044221879 +:805D000042442084018823054241810048008A01441982144C08402401F0625400001110C13A84108805482C0424199C11008413C3182C48021518F824489487388B848688284A41A4418E1C8890688122A24068948718908812828488180012E90B20226222A01222228C0122262201A0428B2122182828008C82820280848202120000E7 +:805D80001648428C02184004202101420018201442A2846FFE0B28480012101208118425289219120098198811124808194832182C0416C2189230C81218C04222821838488C018F14131892288C51A6002141001A04F6048284B04141311180814281C1125022C0120029226214184E2100814A224801420016A884481A02C80048006870 +:805E00002422230111244118004480015F8A054604414141CF2442344243512C11204164C12D841644DCE1014D18426381189441694864C12259014E186214842185128C7428042849C498444C0888421A88D22A48881898188C023EB900E08104843011002981842424A442158884847441487221082D49142110084424200228283444CF +:805E80002832104198284028514911008420010082F022A1006022224C110218800210184224042210420441262228482204648800E08401C0441281000056C412004418411225240481428984D492098CC1244C042842816CC4282341C1448002989B824826D82405412914951443B211086081428186210216682448E012214188D114F5 +:805F0000418842043884124280428C06218CF8EB8280A1484415D244714851962F87E1412112A1161E1229B41EF41A71CF4831514B422B5666F428684E461B783D812C9451891264C3AF6E4DA8818B43D81C1CD188E14648147848384885A58E13D122F917114B81526FC978429C82C084850C4A25F42CC440B428F22C223625F231348F10 +:805F80004313782CF8192C4E39872129764443B844E8173A2C19D338F216421711CB116E8947682F8272449C4429B7484218A27C8C1288B214034F81E697429C41184B73CD288D1A89528886DD98E324751CD224E18121B854F612482E88C89FDF0A495642122B2497A12C54214CD422D212B132944283D488E14661A83D488C7FDA7F1411 +:80600000D898B144E192522C224718A713278C87D55D1257118B8D85A89C1B2F1E122F247416F68A12CB983AA3231E2846E841B524668948991111A8128788AB2445081887218E183F3E045241B024014714844184454108400444402458681185145148214450481181718902400122151854811815287211988415A88284888488222C1E +:80608000289388228B8432818FD90E4AB524F2383A3D318FA1F63373AF95D2AE56AAB5AA644AE664744AB212F561832F86FC51122B143FD7F711595F92F629789D4D1D839FF6D633F433791F13F3313D9FB9F99818AAEE8AE21BA15D3E329FF3F383C11F4EF63D351F91F331111B355F56FA81A1273A33CA818F88FAAC284F8EF634B43B33 +:80610000DFDF48A22C2AA2D88BE8DB77A0327AF72C2A3D333F75F22362AD6BAD7AEFA3F12B2B6F44E624F752742F25F512363F3CFDD3DD1FA5F5725E3FB7B772F62B318F82F3F9F31F3AFA68EA3F32F27BF99F53F72977DFBBDF99B4F8FF78218F9BE7299452BF73F38781DFC6F634348B319F17F55D544B919EB4373AADA11F11F9D9F9CE +:80618000C7ECABC4EF43BBF2FD84248BE42B22BEF178AF2B065E444D448FE3D373711FFB77338FC7F22E7EAFE153EB1F76F662722B75EF25F55C1A7FB6F3FFF95F3FFFDFF1FFD7F714587FD2F7687DDFDCF5A7A2CFE4FC5F517F95B714F3313CAFFDFDE8E99AED8BFAB1B95E523F31F53A3C1F4AFAE8CDCF43E385B731E115F7E4744EE4E0 +:806200007EC33B754F4CC58AED8EEFE4F5BC162F84DE987864F8C2982E388F88FDAE61E047F63474CFE2F21737EFE1F177361E7EED7E6FE3F32F3FAFC1F7487A6B556F65F556567F7EFFFFFDDFF7F7777F5FF7F65549DFD2D3D9F3EDFF7F3AFA6C6EFF13F35F7DCFC5F7797EEFF9ED9AFED8D89F8FFAB1F92E623F33F33A36FFEBFAEEED2E +:806280004F43F369699F87E717B6A4F3F17B3F36FE42415F5CF5F9598FA4B96AF7BE142F9DD7CCF86C488F8FEF95D588FC18A600A01210023440224162812448241B4180044800100100218B240022812200C0113026400100200100484412000000EFAB05822012413311A1405281805428008481122C48A81426088450224028141518E0 +:8063000022A142C092502A4C0216180818CC1208A1604416D82262821084228221F22E92C0421F41722AF2112483F49124A7141D2CAB141D2CAF14D981B24A19F54A9143F24A9143FA4A934782AF14F924488D914FA2C4816FA27418F1244A87197FA27498D5A2E44DC24A1F49D224F49124C5F2912C83F4912CAB141FC9B24ED1C1B24A57 +:80638000D981B24A5985AB944782AF2439342B94478329F93448984FA2F4FA48F024481B6167221EC84F12D1817226F111286B161D282F56D9C1B24AAB21AF5428FA4AB713FA4A3613D24A3B33AD94AAF148B53F22DC48BA217188B427F588242D939E25ACE8C952B413DD2664C94E911FC8B622E1C9521616F86217CCE614F314482F141C +:806400007324F84A124B41A7444B41A33436A3D424F5F79C008004000024004400000000000000000000000080040000002001280000000014F0339130142514044661422210048C85C4181844002444844413444442141445012826448264424216815812901A0024E08481C528192425210484E9F21228CB2541C044BBE71420E8A24186 +:80648000415882D12C41C82110081062924A218269226280C2491D282212222741811849243148444ABA12D284311828295182308445322860210028001A48061AC411F08DA614444364A21415D848422151C21C325483B4282111362158222959282446019B4137824B28441163116843158295688364337A781289F5281212254862483C +:80650000857444C8283E41422004818F2158A42E1E181C2175FF062C0149014602C30200810000840044224E24C02440041621022290441044840C41842100001AB4220124121822002D2432424904418BFE8081022002241D448110889288844088016C1284028184001A12D14812012011044100840081C42112188221000020242934A9 +:80658000844A82F49CC62441642284D11624420AA32266111C51424A8142346488144964122826344484004881C562644344D2140151163422C042113B41B0240C4628A4811CA1B484988C08AD1410044BCD10868242C82900178481B02844E19118AA148118222225E142C42181C1460422148C44586880012711108111022C443848A057 +:80660000871288481A28A18284888288C18842F0565C805124004449612245423228200341801294448644042082028418302411C0442D44444441444183021071121542048C1402114A011846283152412684F46E86201444988A1828001412C844C8122419082116C814282CE44164121A06CE182191804194212140B822083C0C2C06BA +:806680004182244AA2248748811A02808403922480F5C3F47028B1220480180623721698485048E02288218234418240C81211AC28018200529490451813618810A44110384880954881857112D416C42425424808608285A228F01D922001A08282B48481002828A5C144810010210240280428C016100C52000024182081080049218111 +:8067000001C048890800100444F0DFEDB031144658821265092C6291124A4232486C4138A346621486C1142688D158F4488228404816B1144429E1421412012D824C1121D1288A04124D528382338267144B418358824628022E84848684F4E85F2088022880522A84418C84C8281CA848180090182280843121422252291148289144802F +:806780002181880292214881444A48A8141D4889415828008001890128B0850E002180028400100444488100200120044891888034234200D0429442C01140190600425180544110648888508400428443B57F4E111741140100D084210880A22818802128322C1B188282132828440C122244266111113024400A10450420810D21842A8D +:806800005122452231124282121E84F083682482224140841244110412004044488842840428281244800500324240941848001820914213045825284804218001894C2201006FD50484442321154A24C11490118119810180011011123284182312189D81B648820845C2411215C4A33034468A081E2890242012B188718C318890214CB8 +:806880000940042884AEFBB02424044413018444604840088228004D48002002490412418042040014460284202282120800208601A08118004608424814CF1A0580028096283048201489044C123845312222852402611382023021A0424042440244484810082144881032120061452818187482A4411086F4A976004148213014001017 +:80690000818128018088414128988E15A484881C58481C08234418448811982180110115041348381130819081303100488A8181388283788AF44AFF14308889C1118D848818810014882210844808242828841068424602868424084180044883220226126412E02264481FA2244102408244C64212004282AFF1078C9112400281442054 +:8069800001400428004058584254397443041813810D242082E414084048D41C7C4244810183529422186C18B8816288188480622868451802BF854981671D4146F6F4248241D4121F48D8D90132C826681425187418E424F482222E41472351937849F211458693134E242AF22448003447422B154CD882F684263C328A447447292FB161 +:806A0000FCC2321D828576A2548C8243656927AD25024D858AF823FB503247EA1E121E1115783CB418115C8446014E8128434814088426FA22A44B815FC842E41CE1125AD4CB14CB244E624840E74DF1454A5F84A36C8D2197828724371247411F92C6295B6646B521A28185C8884F21E82198886C989449A4B85AF4A8428D1CEBB52445A9 +:806A800084524A11A18C42AC144C8121B188C114301C4B988F11F1E8215D21C57821AD84CEC12EE845ACD1A083222F8AD8442194422751291441FC14235C1188311483B48881B3C8C1416F597181D189A3182F679118AF8486B954D48468854F24F4CDDA2084016186A8148442124F1428A184124E84844A28E14408642004441088012148 +:806B0000004A92148A1234814B1217886332812A7181281221321126628160812003328526422403EBC3341F28D16451E81F11F551514F48F34C444F44E44131811B5D4AA49DC2CF8CF644463F197981F1E541AEC2225F5CBC81F869C95F18F8C5437F11F524C6828F887824F46C4A2F23F188CA2BAA1F14F215951D883F68782EFF9597FB +:806B80007F887825F4989B3F1BB9D3BD93F992936F28F88D81AF6BFBD6D46D266F84F6E6A42BCACF8AAEEACF62D8FA4CD343E16652A81F31E54EC624CFC454444AE41CF44CCC8AA88EC28F86FC8D8F2BCC1F1EF6A1412BAE2B88FF9EFEA5E19F9AFDA1A8DFF4DC13F424462EE2CFC67624F4684B2722CFACFCA7EB2B8C5CFC288B5F78F8CA +:806C0000898A346F94F4CDC59FE5F5D2D52F7FF9D3939FE9FB8E86DF58FAB2B6EFCFFF46666D24AAB2A2F9CECC8EC8CFEE7D7245F341533E7687E17F51F111115EF48F45544C1E145F44FC595C8F88A8B14DC4CF84F48C8EBF11F945C55F16FCA2C23F1EFCE7E11B88DFCAF9CDC1DF34FC171957F2371CEFCCF864448FF4F6D6D6EFE25643 +:806C8000F76F4CFE34758E2D8F62F2ADAE6F71F34E694F46F6D9FA2F3BFB5AFD3BFF2F39F38F8FFF79F99A966F6FFF86866FC6F4EE8C2BE8ED584BD84F62F978EF341F5EE761F5181E7F75F13B355E74CFC1F15C5C1E145F51F9191C8F85A5394DC4C5F85D5FAB19DF52BA24FCE6A83F1CFCEDE95F1CF4EDCD5F9EFE4D4B3F85F5745E2E23 +:806D0000E2CFC6F66444CFE4F6D6D6EFE3F786C63F56E643F3BD3EDF6AFA282F2F23F3FFF8DF4EFE787F6F6FFF7BA83F1FFB9D8AEF68F8BF1F2FEBFBDE4E6F6CFCE6DECFEEBD82FB4C5C4FC2F7ECCE6FAB03230221808114C4488004488004190448904130814411100100410042214221008424108444820482249264400620088281F0DB +:806D80002618001E2410110C1816041301160810280184708418A2424282144D48422C61142004901420022E122843022B128422122128A901A19242802119228841F34485C0421F4152381F4132681FC1324A1FC1F24A111FC1F24A911B21AF143915AB944783AF1439342F347B34F842B54F83C4914FA2D418FA244A16F1245A9E212FAE +:806E0000A2E55DC25A9E244D5A1F49C2531F49D23AF1912CAF14F19124AF14F1812CAF14F19124AF34B911F24A915781AB944783AB9443F3429247822B944F83A4944FA2F4169940DA41561C1FC13668153C4A1D2CEF14D1C1F24A1528AF149325276426F84811512F6442C8A163D21AD8A4D558FA24D816D122DC18D2A2F48825B48F1968 +:806E8000D2A4F4812C3CB491543A1F88744A71917C4A7191FC4A1117812F74B111F448B14781AF147B34B84229F34A122E484A39322B944FA2714901208804000000008002000000000080480100400100001800000000800200000000F0FB32002841248744E094C242412E1883820387148128A02C4140142816C4444C229444424A4A65 +:806F0000853414222C642120028944A582A0872C31C81483088A219484430929018281874C6F48092753137832884A4294141E2826231411581A881694184F21028B2429A42428862CC428211C332128618B61274146D88281422598128424484181F42E482041024664812C914887458C28C4484E15F08E962430E144A8464CE415E22264 +:806F800045E48451842C11D881882303624D4A482483A2C212C3644A19B44422A22C4D43428361918364214A880383148512F888248D32C94CB12808C2A0184D182C4148B24898185AB8DD0A4F1201AB125022104C68322826C12814488544C8368228E0440285944428211A122114B61892144634222865012184244849084E1348204157 +:80700000024CE18144A64887449242604445F8AE7C00000020024228189018000080418802809428A0211852480040022400402141018304220000802802410042F0A898200122382843021662411088018081311C2142202117880248C063D028022481899424728AC182186888284826022B418081840C524082A241418A21F21FA100A6 +:807080008082824224622112001800800100842268844280842281D4280610D82844A4248200288228904825820118480098401284158425F234549018001280029044228D1430182212D068015880311280E28102124E2312002440C128182B148223C14112144822C06400A06820240222102208BF7E0F212A0140044112222A618212CF +:807100001E421E881818701209811168CC4288442184C22883A642852494224F24011A028138A024401118220414C0288C06102C048442AFCA0918008440440221232411518241100360882692288812422822000084902800008D218210110422422220416CA42001248022A1244197FC144501442800001400000026481C1404400444B3 +:807180000089022001100231B611524228252C0114841001841880110220084800BF230B65A121448441444562212C8266831458AB81164258A44D1983382815E84492148D4422148B2490282AB42854842722D0342533226561AA166C1144149187242242836181837412B83804C0884858626CF4A9CE800180020040210112A14130315C +:8072000000449022828902422220028C01304826021C28312820026220021400512012022441281008BF260F260120810100180040010014800128122822001248003024004424001180024001100148421018040048A0425FFC041228213C02382587312489013012401482222222113844002262264C2162422248833412001C31142494 +:8072800049914412190211850283141288140424369848414C069F150C1810823212001841180020420414A012106841222023922848222022263412004243010012141411008D42A0244844443018202424F6E431D089B2480213012E12150638844554447B232826022228806122272425A2131AA148164401430215559111855CA88FE7 +:8073000015A4441469B144022200455C474B222A1608810029724852622D261AF1C815240000000000168101110000800242800444221004230100000080020040010010080020022242F0759910C848422C044302802141144424820200120025825242386A29880800461141411868824848100422004441441C82420284005022D042C3 +:80738000716708A4800440010000442A810224180000108292148028028100264102AC22A44410220280041C4424A222000000484221485F720B80060000181041042A0280010000218001881100282814008C02480000000044902800000000218071380526022228000040210120110140040000420042000000002121220022000040D2 +:807400004118180140040000F026BF90228324240400005044C5B424022220011240D222642243019282824C86825111151153A887818344220400001145544443826482000060242542B614F196DF404888C44280022200107114E411B2210300008052242981A11288A8008026D2110250884CC4410000110050442868008412004012F6 +:80748000F287A8001014020018141214002100000000404104844400280024280022282110280200842494140000002084F4A7CB2001280000800180010000008004422240040000000000000000001400001008008004F099B9242821260460122021414111082581412201180022484F5202437241082E4489A2114A02A0222311420461 +:807500008002224811481184A71484105884004200445FB4092723222C022128001112181B111A11410100808204414A84A224B024028082840225622280823222228100501181508100001880044849F4AB1800002C0241808391111301A0111112184112004AA422504444281024322260222C02206222150241801241011008971424D5 +:80758000100828A0644324F4B4B4F0362225C2122B111221C0122592832F31F119111B98179987818F18F44848D09154111C548985F844688F44D444B444F22424224C02284554642E246F23D222E222B132A1812B88C0922592832F31F111119B98179987848B488F84244408488558884F84F423B4F0262265A2321A21210118259282DC +:80760000BCF1111319E989588889242444511148155889488F44D44CB444A226220028444584F326226D222AA1111A282988512229C8131F3191C19E888598484A24240448848588F67E1A000000848100000000000000000000000000000000000000000000000000009F820F0000401808000000000000000000000000000000000000F8 +:8076800000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F00004018080000000000000000000000003E +:8077000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F0000401808000000000000BD +:8077800000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F00004018083D +:8078000000000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F822B +:807880000F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F80000008481000000000000000000000000000000000000000000005D +:80790000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000BB +:80798000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F80000008481000000000000000000003B +:807A0000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000BA +:807A8000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F80000003F +:807B0000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000CA +:807B8000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F00004018080000000000000000000000000000000000000039 +:807C0000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000B8 +:807C8000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F00004018080000000000000038 +:807D0000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800B7 +:807D8000000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F97 +:807E0000000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F800000084810000000000000000000000000000000000000000000000E6 +:807E80000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F80000008481000000000000000000000000000000000036 +:807F00000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F800000084810000000000000000000000B5 +:807F80000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F80000008481000000000035 +:808000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F80000008435 +:808080008100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F0D9 +:8081000029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F00004018080000000000000000000000000000000000000000A3 +:808180000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F0000401808000000000000000000000000000033 +:808200000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F00004018080000000000000000B2 +:808280000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F0000401808000032 +:808300000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F0011 +:80838000000081848400000000000000000000000000000000000000000000000000BF46070000008100000000000000000000000000000000000000000000000000003F5A07000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000051 +:8084000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F80000008481000000000000000000000000000000000000B0 +:8084800000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F80000005088848400000000000000000000000000000000000000000000000000EF9805000040180800000000000000000000000000000000000000000000000000F029F800000084810000000000000000000000F9 +:808500000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000000854808000000000000000000000000000000000000000000000000005F530700004018080000000037 +:80858000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F800000010480800000000000000000000000000000000000000000000000000DE5800000050DE +:80860000884008000000000000000000000000000000000000000000000000F0FD74000000848100000000000000000000000000000000000000000000000000009F820F000040180800000000000000000000000000000000000000000000000000F029F8000000848100000000000000000000000000000000000000000000000000001E +:808680009F820F000040180800000000000000000000000000000000000000000000000000F029F800000084001008000000000000000000000000000000000000000000000000AF8A08000040180800000000000000000000000000000000000000000000000000F029F80000008481000000000000000000000000000000000000000086 +:808700000000000000009F824F0184001445C8184538242200005440442461218B2412100213820218B18B245951488144204441C94384438204200240642484409628282C0210F641A9902114154859C2C0262602174161284D38417026C2221B212D2E1362318189E124117452D221611125C91413E18422D4213649195481814845C879 +:80878000448D4247826F2492645132D912D81472249224A342662484818344F8FB4310014008C032261C92114410048002188391112E4840A2142446D1221101112822411B420089048064446CD224C226408131288016081008216024842FDB09280024448100442C02C01810114246012125C118844024322190184C2165448485C244AB +:8088000000141014020020224211181502AD22904226184818B4990300840041450800002241402202282212200100001421141901404801848C14111808486604404404302280022400F0A7121450181411150800284120021014046C120424002480011602848181481081440111848094480041000049424414840200F087BB00002094 +:808880000200008400000000000000000000200800800100140000000000001800001F180700443524022280E14182421801211A741398A5282825488C81820221B0428202A041813A840110C8114D121049518523342813642440020098491104F05F34B0149215188C12F4542924841052221800A4459824301247944C25142118A22432 +:808900004A518243013B254C31281E421144512AC11348298204AE4829484B01434892A4584B2426D8489242281E48287FFF09411D14188752281F440140323428161801A14994181F22A8126C02C344C12222222B41842367223611A412A43A0415A42187213C654248818DC2D4A523324188212D2423C46490BC29848281B2740B2A0147 +:808980004502418C622284185022004062812D2541D081F4481480210848104204421883841591140011201112611282421508490482189028C0144183049F8F0A00902100230223022240A34129810416088002448C942800230200482820A1122800242841B04208818224488140068D24002084F495AC9026282F1182712A22D281E477 +:808A00008225018CD18204844643785439824B25444791836C83502183A212483829D2A242EC8411C62523B48191163645C819842951843AA84832488CA8844AC8489E28245AF284488385A2821F3C0749829221135282213D284638328082041819041781122E444413022A21042032221A028D22488B416114529A12521470181124D1EF +:808A800042A418200184C248E4B281214B481248C83FC349023012122822421A0260A1811127842D1283D424948812901C4E88851468B28C2281042722504828604329426141388582121832882883AC2842231C28881438246A11C84828222FFC47D281D24205A02149D2A211D442424268C481830211469824885021181A025682184289 +:808B000088382429447422042227814A018A0113CA821210220200388812288319383689A812211FCF0416C841009011C02124114308122A2821420400410021128C08282C2101221384C844608436081244108838285301C048285042004124008CE2B904007024D11C148804141816012145C24882212503360885048924229248100304 +:808B80001812D0828201100141D08402214088218448B644215424200146C444484E3224126160124D4845D1A2742154341D1298106A481A34A18D441D22C02814443884422D288344EA113836214722228A32442981B111A281415B828E2EAC8198229C82210416F244924944B688D168C114CCC41446F8A94460121301442E111E281844 +:808C0000302250188C8441180A2512842841648180844202220052184654821A0210081800008418008E48448021028022A8242217D600C0212D428C1408004601284800C08800E0820100A889420412CC944420346C4B5844417062084B123024124322028C110285044A480442400C1FD30D902100111C044118601882819902682227EC +:808C80008849318242151814724218044180A881220000812E888841D01608220026021082811104481212002F4E04409423223183D282C42284901121106E818091266388024932148C420100651A0484CC1104412E5240428E188411042812104A885148000046C814F02219C042C018119042113024CA024229A1242191304830C8A327 +:808D000012918210081282190860494800AC04281A041C148808249698C880A8144AA824884A21014B814AC2483EE2104441C628004904400491846042E01204222220C2212E12430227C28410981C1082C4252A840290289021442C12110288182B86812325B14241A814488C08CF270DA4221001418CA21490282384214891816E1280B6 +:808D800012C818130800188D1412004200208161218816180A006081430824001240084148844420F1ACD380028149E4410421200181A2408404490186024186C8C8C188211CE841240414E04801426011448888194AC821A021160240450C824810440418F0C8BB004444848514611241C41150281B4224831204645024002810A421000D +:808E0000254442480C84005042004522024140223218124352423016004508005F94024E3C9042002144226882824C2481541484C4489B24481644548280012A08AC08824009404884D414D22208A0C182C88296058B682048048A2291228229C448DFDD056E1655343A2D28AFA1F4694227524E223A23044AD8187C41588D6E612F6E72F8 +:808E8000E8A8876E884A7829E588782898AB442E3147898D488C74147CAC46984859847684544A9BB44F887884C5814CC1144722ACD82268819BC14F24E4C1E824B9D4684446D88294D48F4468857E15002F12D2E1F2214515444108F021659B8C26EA8441E2130A4D1945F28C262972168CD254847244383440B485B94EF848811249041F +:808F00004A682419C1228421293A27492A92F1281B258869313AC3D44CC4444B514B118B2483A543F019A8906424457148724451C2DB644F42714CBC887812B18B3732ED452744CD1883D1425692CF28F528314D888B236721A6D6A87314CC422546A618848F4D7174EC417314F4326A4F83F8A2468D261F26D1C8B2B1B41C7A82B4B2B165 +:808F8000A8D12A61A8CCAB18278318298AF4141486D48491483FB305122011441844081A14C4486089C048441F810448441A149841448A1488058880A82418422A011800200442124220240882200AA2200AA2811F540D5AB412F11818CB228F85754DD98AF248488F81F1C98A2F28FC2322BFF7F5CBCA21AE82EF8BFD8CA85DC92B8A7FFA +:809000003DB96412E44CFCC88887A435F14CCA2F88E8ACFC93D12E42AFCFFD48481F1DADCC1F1D79A87AA1F548481F5AFA8BC95F1BF7D8F817546AF671738F8DD1D9F5C8624F2FF71A182F61FB1A38BEB6AFABF93C784F8BE383F21A12F054625F6256B93F33579A97B4FD288F82D28CF2A9AA7FE8B823FA49CFFFFCFC22251F38FC8A8ADA +:80908000EF8AF823892672C3F167288F8CFCEAF88FACF8EEAAFD29CFA5ED8CFCC4CEFFD9FDADCBAFCA68D41FDCEC6CFCA3EFE7285778CFA6F6E5E7BFDAFEB175CFEDFE7335CFE2F22B3BAFC5D3FDD4AEF2747EAFC3F31636AF85F7F4F6EF2BF91A448F81F57278FF52036E527F7254A87D249FA7F3676DAF94F464648F87F5ED8FAF7CFCC7 +:809100006BA2BFBDFFC78E31DF36F65F59CFEEFAE3C1CF8CF8B5F17F5AF8C1C14FEAF92A688FA2F87755C5FE828CECF8C3858F3CFADEFCCFC4F6757D4F66F297D58FAA72A3F52A2CBFDEF68BACDFDDFBD8B85F72FEAAACBFB3FBDABABFF1FCCACA4FADFD7EB8AFE5FCFE987E56AB65EB914F8DF9E898DFBC0B4E725F62F23D3F5F75F36CB2 +:809180002DDFF6F64F4D4F47F75C7C5F66FECBCEBFA7FFDFDBFFCCBC61F4347E7FF7F7EECCBFBEFC7E7E7F5BF7A4859F3AFAECCEEFE2F626AEFFD5F79C1E8E82AD8AFFDDF9DCB3EFC9FB19385F57E723F3BDB7CF2951FD8FC6F6AB2DBFD8FAD9BD8FADFBA7E7AFE8FADBDBEF8DF98FC5EFAEFCE4FAEF8DFDDEDEEF8FF97456EF84F6DEDCDF +:80920000CFABFFE8D88FB60C417022415832484184404801248C44454842480628C0248002287048141618141804430221844F22084150241220416281241E484440243148124482EF1E0F220084406812844A812224110A42A034224284892118489288604120081288128C2484214182020080A1212C889288860812881A94881E48603D +:80928000818B8486F16921C0421F4152281F4132481FC1724AF2112CAB141F41B26AB911B24A7915B84A7934F84A9147832F147934D81AF934481CF9A54A8D814FA264115FA265192EDA96C5CADE24ACF591242CF591248D121F49B248F19124AB141F49B24AD141B24A9921AB9451AB9443B24A39242B9447822D914F8294984FA2F4991A +:8093000015E0A2F41164C5F211644376117C22D2C1F22E121D24AF4258C12F14D385522257824C732598225782AD14778229F8251A85F4259A83F1278AF02148442D4B1E252D4A16CC4B1E64C5A36814C4A561C9A5C12C2D15CCD21A03AF743324AF247124F8421226C8946F82B44AF124525FFF0500492408000000002800200800008041 +:809380000484000000000000002002004480020000001022F4CCA31460428144400149624219220281830425486C82C91208874A9904C0248C142C42A2418F240121521243522485C48828001621028181442184844D4840D84864814628F222E57024424204C189628184844288110025A82430842361424F120970644842C21425C2C148 +:8094000084262C4AC48444222002224136C81488F08228189293281824012F881224B98466188974FF45016B248441849C4228C22C28490281C02821456882C183C2234F827848B13804276A8D4224A6416AC51F284146D44824B144421442684281601130AC83618ACC2818247148224878D4B234E888E485F226BD302410064180410C74 +:80948000198418018C14E28204439832414C0910046041452804282E488028210222C42A082A6141882821801111421818942841818C04F0B1178001418C52241638428C1604204801004400104888210A254881042A64440000002120420890881281114200602412284F8B04228921F2E653204601218302533A14896381232122114881 +:80950000341C8C91A836B68CF182444CC42446B825A4244F85322887644D18282D44C1421CB546E118120517C162DE222C4523B691727288984C83B422919443944450485842428F3A0C2A4401A14592181183D448C218A082191108439118895A2483388A842E14425125D8184458482D2426C244813011441414609326289E1282294111 +:80958000D183A148814238182985D648091A9218425F9D021810846282246E841E241224120010144804324C61444604A688A6422E142A24E481C4441084C4424A612A4140842461241528B6A8A142304481214B8441442A54484248226EB4344D184944140945522462214658942829860423A249241781C0214241CF24818A084049D866 +:809600008201842532512661841132A3328B424542D126611882A3914869024002150A248904BFC50E8C82150200141200418012181854824F1562422484890820918AC0688084C44921960884429811425082184AE284CA28160459A82440B81442354240C81423F44397001008419B42008B212504160821188904008302100140742CFC +:809680000292800888201222411C0428C0211608904900D022344410418102308CEFB5094C821152184122E021C22825088C21344A10FA82484E147782850284444C245A4A47228C16C942894942D828914126015D981B1221882D4819F122412F26C1888531124DC1630446284374422A1288918C1758B08241140CD0C1543648184C54D9 +:8097000018282190184B4218138221D218B2825412A40081204928C4488229A8212112407468D281024C9218866C129A1448488254424121007048C442AF45032084022002141181242218448608604840C428434AC284824827914110024282621220041284832842E2881648088460950000180080F4342300150422260450842083C8F7 +:809780001111902282830B212B8224142D282881458106A13CB4412802107832128112210B100A1348112B32892289028241005240F82FB73081004160484548A82447A822188800290228408202002121800126012100100225D2848804A1880014460290221218421884004A41F2BE2F402882240448421008182C18A428501423422194 +:809800007888819148271A9C84712188D41824480820440A19044840011304130843041304008336344290128440E4AB0124100813022400180000134208212450284846232224721851424314621628182F840268198812A1288C841284D2838411011111A9042D28CC14820484145FB646419C21152442040013048C18494804105484C4 +:8098800036889145844781431C0441848C38A884C088200970882411C8862489951A002142810081414018F2284422F0ECFD00C042800884148D16C0124091218388288868188922681888811568A400188089082441001486244401114241212E8200803812202149882108BE4CC02147881014082314D26242042622012147821421C0FE +:8099000012100400124482410086420A4882411C2804800400808441024100C044121038185F970845084D411C1491844144201C6248828972114211CE21A354144C012D44342ED425C4823C31418A64228CD4140414150C4C4418A1149388183142814485E1443258290527A4812181307242DF5C0E15F4814C87624AC22443784846D581 +:8099800029D468A4113B834F18D984E882AA829E8189A89C8E88C9D38B38AC446D2815F64D428D18476513AA8E26887842E22111E418E442F896598F145481211B88A961D825D132D411D1141493285088218CB91A041E21841ECE50144358142A34A9442D486127D26B8B2CE2180315B281F1842BCF42E23A32284F51D1E2F4C4654E67CA +:809A00006F9AF2C84665C92D4F1588EC14C6492F2CF648428C76C3B4611BB18992818CF348C41B664E181F82B24BC4461D886897887A7742E883B562D28C341EB07CC1886CD4314F61222E2111555414624195B844C318AB8885321B44A5534B255A4725FB2B223E81D081F949C21CB868B7125163A798AD883F218268C98342D812546263 +:809A80004551481B8A96D2B8586ACEC3D089A124A7842485BB145D2A4F48E565C1428CC1488B5683D58D05302450141044480240088414841001114413480446146144401421044229A82414288828804681C2811AC682288880A8412C28C18213918890A812F08644E02AF226288D2A6D6187E82B4C8FA4F449495E34DAB796A999AF4B9B +:809B00005974EFC9FB28289FA2F886865F49E9C6F43B188FD4A4998FCFFE81884E68CF81D5E8FC11522E431E528F82F41436224F5AF9D4744B2687C28F42B558F73CBFAF8AF8A68D8F84F6AC2E8F8B5328AFCDFD9C1EAF8DF374368F8FFBF83ADE12EFD5F19298CF4BAB511CF41CE7F024267F42D2EDD246F64C6E6DA48F84F449485E345D +:809B80008B64AFC2B3A2FB8BA44F68F89EBEA7A22B8A45F4B434CFCEF68E1CEF56F4349D6FEEFB8E8EFFFCFB155DCFA1FC14D28FAAFA1A5ABF92F87C5C8796EFC8FBD6767F2276ABFC893C9F89FF3CBEAF8EFCCEEC2F81F7AD2CDFCFB7C9FCDBF85FE9F19B18CF4FBBF8FBFC3CCF6DF1DE9EAFADFDDEDC3AF342529F320D2E267D6495FFDC +:809C0000272587EA6F46F4484AB5B853F5D4D49E963E31AF39533BEFC1F128893F32F8A2A1DFFBFB664FFF9BD9CEB294FB645757124FD6FE3E1AAD1D9FB9F5284B2F33F72A496F69DB8AF685CF7F6BD526F68AA98F41F1785BFFF9FBCBE8DFD8F86948DDAEBFD5F1EBA8BFB5F34686AF95F1D48EAF81F138BA2FB7F79F8EAF81F17E7CBAE9 +:809C8000AD54AF5842F1A5277D24D5FE6725DFF6F626248FA454E37F47F7E4F6AFAAFB3BB9FF39F88B83FFFBF9A6893F1AE81AFAB5B5EFDEFEDFFDDFD6F6BDFFCFF6F4AD47EFF7FE7E5FEFFDF597DF1FBEFE3BFBAFB6FCF6DE3F84F687CF7F6B7527F38FAD9FD9F9F9DBFFFFF9CBEAFFF9F1FB5AFFE6F85B1CBF86F2DB9A7F74F85B5BEF44 +:809D0000E7F3FAFAEFE6FE7E7AEFE1F1D2D8EF47E52BEAB4F43F58100414000084148A2422412348424846C82490281358488210131812181308800849012541C811C08284002484141648410816482221241108DF7E08224440444204C4C522412208504A0040668144604440D484041844482829048C0C290841808114220848145028ED +:809D8000A0148033248190128C24042F39096F22F41124C5F21124C3F41124A3D4C1B64AD141B24A9921AB9451AB944783AF1439242F147924D852F924484E954FA2E454F8244A16F5244AD6E5A2645DACE44DC2CA1F49C2421F4952281F49324A1F49364A1F48B24AD941B64A9921AB9453B14AB934B44A3934AB944782A9F93448984F21 +:809E0000A27497066D491B41E3F21168E7361F81522A1FC1A2161D2C2F44D9C1B2427B15F84AB15781AB145393121F82F4421436F842B51FA2E544EBA2EC55F2258AD6E4A26D554D594E216DDADE28B41F41D628F41124E3E489D61EA1616F34F81168AD941F4196BA1B41AF64AB43AD964B43A9A942AD942F81D442EB82F5F52520228824 +:809E80000400840000000000000000000000008814008400180000000080020000200825018FE80D22260194A149422231142283180AA4709468811391C3D34124C484C14CC24590212248482116E882014D8118244110A142221F42042342111228C11242100C304840F84BA300436882308184158CC6884728144078815485269245500F +:809F0000842632C18D24288A12C2228C11D4861894888B42212412482F483214884140388A102C2D1208484972141288210D41144847DF80625E2658A19C184488411C542481264858818D161E4514AB48BCF384438F423424369C244F18548247128CC84446D22916B8183218112F468951424041D882B84552244B3C26638281184C2261 +:809F800001168C41C248148B413F43010000C028458386A928AD8100535842A281125441008886022212244C028308122490C41024180462284008002024714246088A044100CFF607008280080088000000000000000000000000000000000000000010010011400170E705211E221D1885148442218652A243C24119016D82C44A05BE56 +:80A000008218A5E58188A24C144554212E29811A1431C2C016C9B4620A118F4151848A4A230625F82421198441F44E8A4818E02B88514A1E8828828FD10723628411859414A834622952814712488E128C28B41A9414E01A58212584F8183843C8454217221E298911A1882914C8184E242F220C11E042BD4C6218506684183E619F284874 +:80A0800028B412148421026C2981D284F44ECE00200880088008000000000000000000000000000000000000000011001001140097725024002863020014122A41082084C4124041180A00004484424001800D48001224200487243048804988891462888843220400CDB13043264544D481D42861D4118F4134C129A8419601DC98A325C6 +:80A1000078D8A4483245D194936883E4444288213129493168A82E1A41291814223385141064C314E0286282231451228931581098428448562CF668FF244642014932228C314A1149E538A118848830C9394CAA811C0C31431188946400811D2849410916684C90448091840046648224608C84D8842999488C1118784284044E14226FFF +:80A18000F60B54491204D3041504158824A2411C01412229914C6083C493A2428410C814184220A68228272182248032111502301499042C8212424122914282882284428448EF1A0C85225486441A042046280215423C220000821883028E142A21C88148128420420948880058411021C8161426440228E1C1F04214428460888028F46D +:80A200007AE780F24428101212085422248426E841D214048651842C84043F2108221C01883220381413E15114A218A5A2482C924C21A0184021081948E34122883122004C120481502A4F5805232401003410821424210120A11248182C614280088D421054214825010018100480A8121628624100804348981100809142244860424463 +:80A28000EFBB0C23362285148655389023891684E1A211784681C1A120A1C14C739A019AE2849282511B25482368411E218391125849384222CC381683C111406418E0284218FA118885642256E42441487482088E24C5F2848E0016140221004C0428A11118001287444825022882251401002951180049042C0888901228A02849391135 +:80A30000214CC21115C412412C01004E242044188274A30D4111405418110010010000A81244228C02894498848D814C4101608242488302001564811901508260448116044D128481A91248288404819042BF610D221280428204444D222094421840082A24020070220120824422222C01008604008212314242230800311002238832D3 +:80A3800082844E198848F06F7B0041141C35818902204124021004880016416481008313628481840043444814082200C14828100847888CD8491208001002002121817307248004604421902682232916420245022460241410081810A24812212541424112512212103288003088190100290249080000888812BFD70B8E241528721101 +:80A40000A4121D14001A048422184141418688A821B08442942121452884860610A12483548122308110A12481006548848112448601224508C088405812ADE3800141218504444901108131A4283A8811A412811B12902944112D42100425381120418105204109162165A6200214441C1848021280B848028042F4CFA400288C042032D0 +:80A48000282184200480130229145442400240082C82088A642480E8110200242428842302221220020082834208480068004FDD080080240643810214190200288001478411C511011564324185041A1489810228002814811440C288901145D11808206228A6A28200001881DF460C42444C2442042800414044AA28450245222C582CF9 +:80A500002A219482224941885882242288279827181440084812214CB4121204228342148A42084082014058821A72BC054F42E21851415C52E18F511444F418144D848F2AA2628723246F22F384862F217C24B222582865794888F88C3E43586AE3F6CA421AD1283243A722CD2812345035855A9BA7814AD2A851284849C224854A12DEF6 +:80A58000A261422BA8C1C2811E888894C3D1780D1A144EB224B57832644C92224726A04580D944C18C284B344CB21563921D141CD4B542D11B92541D4CA0284E414B59482A54188828281981F2C122346829F28C381E1155E818D2874818D82252A827A88846283422622D18FFF20AD041922C1355141D228B124D12281553114E1241823E +:80A600008051488A7D48FC45348F233A25833221ECE4860226F8424A3F8348F1D1A823F9214869022B19144B911CF53A4423E6C8D442D8C9F8B8111372184582FA88882AA12229A542818F88F4881262EFCA073024108414042112671282211220C12492A049441381124134810028989091400224A0120000A082601282144002002800A3 +:80A68000B048028B243FFA056E641F1252B96D448FA2F61D1DAFA1F22222AFC5F58787EFB848F2989C6F21F992B26D26AFA9F722622F25FFAA82EFA5F52C2CCFC8F8A8A4AFAAFA6A6AAF82D68AF83818AEE38FB9F1CAEAAF8CFE587A2F2252465F78781AF13B63BF97F67C3E8785E5FC9C1C5D1C9D32BF389A8AE5E68969A23AE12AFA5C61 +:80A700009C8F8A4A88AC95EF47F24A1EF064645FD2F62D2B7D45CFA4F61D3DAF83A222CFC4F682A7BFFCE824F4A8AC6D862F28D866F28A6E2F22D6A2F2AFAEFF7454CF1F98F8A7B45FDEEEAEFE4A48AFA4FC2848AEE285FB6A6BAF8DBF18F328284F62F2C7CD9791BF3BFEFBE94F65F17A2AE5FE3E345F4AFB98BEBF28D8AA5A6EAFA97BAA +:80A780002ABA1AF3A8AACFC5F9E8E885D88AFC78B8E7C41FDD036E645F5256E875F5787F5F57F71B292AF25C7A5D25B7C62B66AFA9FB1692EF89F92E2EEFAFB722FA5AD2EF5AFA5C59EFD6F68C854F52FB6CCBAFA6FE2A62AF86F4BA188FBEFEBA3B2F1AFEE8EAAF85E782021F397D1BF3ABA33F1EFE3636AF85F2CE6CCFC9F9A5BC9F6848 +:80A80000FB9BB18FA15BEE2F89E922F238388F8AFAFCFCBAEB81F52A685E58CFC6F7583FF064445F52F22D2F7F57F35C7FDFD1F33B2B2F43F35C7E5BA8BF9EBA72F79EBA6D86EFC9F9BEBEEFEFBF36FB7AFAFFCBFB5D5DFFC6F4A98B5FC2FA65CDCFA6FE6A6AAFAEB4F2F5F1F2BFBFB7B2EF2FBF1AE3A2F22222BF1B7F19FBFBBBBF8EFEC0 +:80A880007476AFA7F2CC668FCBF3A5BD8FB8FA9BB89F9159EE8FABB92AB218F9A8AACFCFAFBB8F81F5A8E88FAFFF6C6CAB4C00400100410000000000000000828F4412E2440281B04802420000144001C0484048220800844008008281F0F1B2308410044712601290141188C01240245162438271115842154854814C028125229411F0A9 +:80A9000022188304001224842CC1488D12009644414803242224A02484811048B16A0C4D421F41D22EF11124C7241FC1724AF21124EF24F19124AF34B911B24A19B54A3934AF543B352F147935D852F925481CF9A54A5CF8254A16F1244A96F1255A96D5A4E549D2A6F491242DC31F49D22EF1912483F49124A7141F48B24AF18164AF1451 +:80A980009921AF3419B54A3924AF4439242BB44782A9F924488B944FA2F4FAC4508419B62CF111484D121D288D121D2CC72217C98F6251C18B245789AB3484ADA5478A2968882F447286D842E3AA45F424DA16D1A4CC212E4A86C14B9AF222DA16D8A2B481F42AC21B218B8413394A13B14AD141F46A141B212BB41789ABB443F34A1212B5 +:80AA00004A71B4983A6B418B944D1257BC400800000000008002000000100200000000004008000000220000000000121008F02473144941941736C8244114871241830884488B94524126184BC48421424C1845AD4255D84A0415084124184492221A085C2144311481B66811521C185448AD26124A414408905826F8B3E7244AB28101ED +:80AA80002112154824F441222287286283110589511428B611BA54B2242881944220856221229746255884C1C04618C44CB12874311492C1184661821C8204214A318888298292148C4C9144FF6B4CC244472416F112281E24454114796164824D88266881479D4AD384712D8232112CE823644412635116E247348D2416722871215A85FC +:80AB000045D84811C8C26A514818CF11747411739411E896D985E111B2A144562CCB1623A114418942061E4847214F9D0A2A311141008414682482244842000015C8A6454824CA841934483018480046041042941480492402808401224800008928982280E188042E484F91092D1250228001221224B0689121188410411211021822288A +:80AB800000415022408852249249012A010081842440425C2811424042086064122840044FF50F193214448F41D242D2C211158531242D812542019CC13283C1782E482FBAC4415C416C162F486212E9942889312483B412C22A2C861E96224D23C952272E124923823111221A688833718441D248C22C284E2516A4A5124F82F88F291036 +:80AC0000711206AF21A2218911116121228A5312404848417852A1426213742441C4214414848400E0616283412D229022144154A31232222C51580083D812C18125423C284F24924141F26048DB2C3032401414544249C21410744368221901168193128C52A21788232191282CA4286C62442D228371247868022CA8168AB4140247225C +:80AC8000872281181E24001889D21229044484284160432A014961828B3C7048245541444C188814141204524C924858A121850224131454488D12248C9491160410C245A4005084425048418324022602422829012C6881362C01484149057FE34F422814482203008354221B18312F41F616829011C01482C012488031241188106485F1 +:80AD00004361122B42CC91914C64828314248401202884D218E2429884902A8830A4001210F26F57A0214124118E4222278129118101400881D08404452305842222484044622300C0848223542112182810E8421152124400108134144C5422814D2ACCC228A0824FC441C2544464344F2432282F8114141334813B1425DAA4C158918950 +:80AD8000544882421481818125C2491671146243561826944425BC43685412838122D448A14322232814A242D0168194ACE42E1A83CA2E26982C122A78D201221285418401241287241229014AA148241225245172122B1449D44222E244024400211247228B289812244C0244C1502C40C12422158C284822B14219C4146044122744F09A +:80AE00006D33243081B02291298012010042483042204483024028141A831111D1480222100840B228019E21C220133881278241244447249681088800008691D26F2D065883B1184475144274461882614810029238618423485982AC0644C0262081424242A4412E8446094902240088884E242F82119148A984094485C428428002280F +:80AE80001648586800C20042271211804431538121008412002001140012217012C5181884214004104A04188504502C2A4804122619484424481444C445F07F6A241602418100284914068162804608250430842318849E8483946C904CC0840016898262845988048420969144429013891441829AD2008042782842F4D3BD4042084AE7 +:80AF00000228841420030024220020110C00178114134431448C214221048582128422924C2140189822244490442143C422488A0200238221F8752F4028217115321414418412518480018C44844429044121842118218344012012465141922210081448426011614004001800008812D084F56F21604641A120868484922124482AD882 +:80AF800024C424412DA2506241214813448464482816D4228812424CC98182801484042A34A8824288004283E18C928230A883E48C11394881003F8C0B4486022502C21420120210241424810111484415189881502141A1110045229222400230492D211840112CA23426026908444100824C424401AF7E0884224C149888643044150442 +:80B000001941042800C140440244271144294184280247A4812948B5441844C88268295284C314941400C014D081522818124518992481426322F2179FB044A54985F274324AF142A1F7449F14E221B684724A0843A444874785F648189127444D488F4114E83224D91262249CE19E321887224CD1E1B186A28A4C121444D8D2CAA84CF86D +:80B0800028788F52D8A8F84E284E287082D6F8F878828D92CBC24B828F18685A4DA8784515B861022F41F28A2A4C51816F187621E2324276218561318F248A3582453212672125D32D82F88222D4D354C84DC82F4237162119F312486F121208ED44414E662F32D2283264F3B6C8D344E885942626552227B5CD48CA54C16F819232448CE8 +:80B1000011C444C5E89BE687F952BA24245C7116585A87E34D448C944449517119A5424447212D684B824C34841C516A4394478E1C7DC315761DD161D46D74267F8454A86BC48FC2F9412BB2228E9C23D229C5411E48C25D121F5B41F2A454785A91176718A664CD8F8C24C428872226D428F186442FC50A100421008426022A48C882C0F1 +:80B1800084842C68826C382124A242132234821002318A820141200221D0120822501448806422400180440485214124A1247E2C2456F27331F7D16F63F7781BFFB6F24A4A37247F53F124A51F38FC82822BDF4AE928FB8696CFEEFF62E22F27F9A2822BA8CF46F21C5CC7FAFFF8F24F4F7F75F56A692F2FFF8E8E77F96F27FEE6E66F6C4E +:80B20000F69EB42E22EEAAAD2AAFAAFEAE8CFE844F6DF6C6A48FEBF92A288F83F32A2A2B117FA1F95BD8C59C94CF42F214954F4FFF1C98CFC6A413CF55F437652447643F75F51F1FEFE2F37A7FFFF2D233F262226F41F114959ED6AFA4F412344F44F984B2CD1E6F66F764E37F77F9A6866BA8EF52F23D3DDFFAF1C7657F54FC5757EFF6E3 +:80B28000FE6762A5FA932FEFF7FEE6E26F6CFE96BC2AF2A2EAAF82F2ABEB7F4EE84FF8BCAEBFDFFBB5B64FE2F2181E8FA1F1323A65FFCAE84FC8F85ED8CF4EFA159C8F9FFF1C9CE5EC86B6CEFD29D9244F65F13276AF23F332322F67F16B2CAFA4F671335F77F5E765AFE34FE225F7D616EFA5FD2626EFE5F58723EFED53E463F26F6CDFC3 +:80B30000C3F7A5D77F54F647C65F77F736376F97F72E2E7FDFF55ADD6F6AFAC6E26FC9E926F6A2E68FAAFAA62FE75E8F4FFBACAEEF6EF2AB3DCFCAEAEFFBA2A8AF2CDBA7F84FCCCF82F36CD88B664FC1F9ECEC49FAE2ECBADBCCE392437256F61256EF43F33A365E549FC2D2ABF2783E7E523F5EF63AFA8FACBC14F1D416EFA7FDAAAEEFB8 +:80B38000E5F58E2BFFFDF3868E6BCECF94F45D5D9F7AFCCFEFFF94F43D3FEFFBF35F7BAFABFBF77FEFC5FDAAA66F6CFE96B46E66AF4AB8AAFAE527DFCAF2F8BC8FEAFAEFBFFFEEFFE6EE2FADFBE2BA8FAC5FF7FF4EFCB6B4EFC7BFE8FA149CCFCEDECCF8B49C4FAFFDAC8D9DD190129016844B125014501400400280C4244881828D24C046 +:80B40000241189125148118D244901224261422290848440B8246881434248628124845416C8244820180889021EBB002002A503244418D0120121A0141229312121482111004614223122D022014B527022485424702C024F1468414244A503830442800121490414444180F4BB8FC0421F4152281F41324A1F41764AD2C1B64AD141F2C6 +:80B480004A921D68AB9459F44A924782AF347925F84293478B2D915F8AC4914FA2C4816FA264117FA264192FA264594D5A9E242E5A1F49C2421F49D23AF19124AF14F99124E3F48124AF14D141F24A9319F64A9153F84A9143BA4AB9A4F44294478229F934484E944FAAD4A30A26BA11D62CF41124811F4116DA41B44CF18144AF42B9815E +:80B50000D648BA81B44A3BA48F1429EA1478A44871A658184B1A144F82ED117A2428C9CA8F49C2CB4CE2A25CC1ACFC8164811D648B841F49324A1992988E24AF4429B84A3B84A933A4A9618A2933342B842F8A8479B4FA36E360888248000000004400000080040000000000001840080000000000000048000040018F7407441341711A39 +:80B5800005124CA242478189E211568224194184522111150C3217828C8124468441381A63314248701422522424C503316E86862752382800884260C426881142744254844C39442FEC4D22748422011508C88448218C58214890422531422044481904A441244D4A00844B1283A24188152624024B12281110054B18312283145482243F +:80B60000CA2142984119018D41287FEA022564F816C15D1130248445085B213538621721463422195412DC1478217228417818A24286F644188485C21846B44182D52498292D444E22158E92212EC127483952812DA645018B82431442B84289116824455248C71962FF5F0B4812241028218CE624C1288B844002101102008911848144FF +:80B680000450221245A22184804144026041214414442001284210984489221252141B142014D4FA0500800228100110020000002184100400002440024004000000860400008008000021411004484F63098002250415022481C018C0189018285681822C6219481241D0A48621820118A01221121243012902112120018A0481808182C3 +:80B70000442451286084437824F88F330040C224C021211121100A00001981B2424818210444209612301220014B2100184C418202172800004A080020224482518450844CC8486FC20820020000400812608160812848002292441200C18002100210220100004100180030888001400424800426F49E46000044418CC24144800400135E +:80B780000800118810210400212820810141818200000080088800004004200112108402CFA8021460313012000000424002C44121008100800446422882022012642460222864441200000080088C08E0883448A0818481CF880300100825811108001800309200200110080084004821382112200244818002000088000000414449063F +:80B8000042F0D6551001508627419C6215850448800186012F480111821885810400214608324A134222822904205268800180088008884184004DC887444C1404E0E50C001C01240000004800218464000010084280528200B02411180423821206412888000000008220011228928B24841FFC0D0000000000000000000000000000006C +:80B880000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F8004000000400428000000002180018800004001400848000000004480020000001002183F5F0B0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000058 +:80B900000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000069 +:80B9800000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000E9 +:80BA0000000000000000000000000000000000000000000000000000000000FFE40F00800100000000000000000000000000000000400181000000000000008200F0B5C800004004100880024008890100C0481243042284002001402282043011000080020000004412204408001FE30F290280024216043082800C82100282268E150422 +:80BA8000403144118410048C220200230244221881111800348904000084450800847024020080420441812480820884301A00008C24314460420040040024222C840212201118812102304800004412414008009F6D0D230200808401200848200800828D261A44041021548181001889220200004581020000400300004018880410089D +:80BB00002F670B108141180200002160140011290880541884106144A490412002008002444014088D1113112208110000201202008304DF340665C224A51204284184411A8831D881834864C8514E2985D42838145199111448911C4146187C41C8228332844C48C5217494302141C0898715608B181D1A49CC16B04451488146242152FA +:80BB800048AF170141105824804244088602828008131821048297414481444100C0484C22241262484C12C521514548186151136118142001348664214012044418818574E704213D2423110A00408481315887148141E449D881123C4821941C41C1489467815C04818501260888400431804208A18B58F08128188C8114044B52818486 +:80BC000042A042E0CC0A125234006415260114404A548416881268411440382420684949288283514818460150411845C84812282A010041121D92648904281A24018824429289F8D4C3406A444009000041426062861184240800649018A04188318002244581C288100848602482004641084024B24801008A011042046783341906F01E +:80BC80002412A411811424800181008081229118404814048424434408116044209662804801417024020020880816181208384048081FA70933D64201354A1A143A1350144A5128A4591828C418360400265C4849684C44146B1281811C3142288147344A41840824430341001234608C83A4215283818908818668A87FE7051840E141CF +:80BD000002114501240000844C2182081C618185041800A428481A12044146848822028113212608282714C420C98228188421003280C414F05C9DC04628242880028C010084008362822046280A26044DC880111134181004896182008C1148941CE02401220014A5A44818800142188B818C149848BFBF0C2200142246981C549C7198F6 +:80BD8000A5812B21C02114128018446A185843011528021EA82829C2524A18D412D441895442207443C22141367442221818E22412482804968A614C424120F8EC35144004100480C2244008400441408419440400304820141C8814088014040060242608188142003823861882282204181244CF2B0A148041447818C412002A09854491 +:80BE0000186812149C424201001B24288A96149892002541511244008032332841444038212120082034C841821822828A22F815133082154414084C1488052D44A04228497488D484449141414840488448841204E0210422100180022A881802212829451802218C082181189084407A1471CA0648904A0090242200841088025048827C +:80BE800085220846841851181D484820618815C88C8118111C08180017828531484A18A114A01400102804104804F013C44084C4212412271150941518281301190900830130129812418221893A2222413E82F09241212C894501AC7118044800289088888A42420829110421800C1F3F0624A451A354820080018848888120048188CC2E +:80BF0000C48480C44841D0C1248428488444C4484C44441448048744201E8801CA01184A51844945044490181821AEBEC01180444404804484064445C26245421354343C026882211C825314888514D4144218C4414911D28199122A14A342181352484018410C2820284AE248046C210884DF9845E14475C43417253E1E71897223953470 +:80BF800067118E2A2E28248D418F42C241E5DDCCF1128BCB488A78449481815D814B2746B298FB1C182EC27F76D4266CC14F24A1C44F25B4122252186F24F7594583249B68BE292CF498C28AC1486A9D464ED887482B11484B8C47498F3858C25F870B43722142B32C44E483D144C11895F928C88B819B41811125C92411195A482C9A350B +:80C000009EA86E541F54E2E8D291E41265442E2445DC8861542F28544847311D1184843E1287CB67A21D45AD66C6B243714858824E482D1284878C2368844A6C49188F84A94283EC5845523125D8484261828F446481CB6516E44C8321E4C2F8449C5D82D78522CE435B2827C427445843F1A4C88B428D14D5FC244882BB29928F88B24CEA +:80C08000F133491F48E148D845F118227F484681F2243A47843658281C41C1A69A38182CF818246F2179A4B444713A0E1E184B81CF7C031A021A12843246304630463042E04421E84421EA44312118222008244654218008882880428102800829012190823022102218220222A042A042812F560C7E431AE3E1F128288F23F53F572F4540 +:80C10000F4652FBFB1D4EEBD5E7D53F18AD6CF68FC52536FDFFA82D32B42DFA5F338FA8F82A81D7AF32163FF16563867312FA1B228F26A64AF61F5226AABBBAF41F3B9B63B2315D722F225671F32F231239F14F2E6BEAF28FB31B39F97FF7AF2AFEBF8C89A8B144F26FAEAC2AFAFBFE6EB27FBD6148F8EFAB4BC4F6EE65A45F17146AFE4BC +:80C18000F6272E6FC3736EF83D5DCF25F56F2FF794CFCAEF477F53F1EAB6CF61F55A56EFCFFAE3BFEFDBF51C7F8FABFF288A2BBF5AF127377FA6F64EDC5F46F264EE4FC3F3EAEEAFE3D7F6F89E962F65F3BEBF2BFB1FB4F42A2AFFF3F7DBB93F73F26B22CF8EBB2AF37BEBFFF7BFF8FFBAACAFACF94A32EF8EFAE8CAEFE9B9C6ED23FBF67D +:80C2000038CE88CFEDFDFAEAAE65F044734D462E2EDFD2F2193DDF55F3541E3FD1F539355F56FAD99F1FB3E628FBDC9E6FADD9D7F52F236F6DF9FF9A8EEA8F89BFD2A57BDFDCFBA9ABEFD2FA14414F63F6A828AFEFF73BF2AFB1FD9AC62F47F451FE7F65FD3777EFE3F3A7A75FC6F667699FB3F6A4BCABFE3F1BF3D156DAB9DABECAF91885 +:80C2800092EF8EF898BAAFA8F886844D166F4AFE86944FCDFDAC9E7F8A47F34772ED467FE1F1171DFD2FFF55F33C7CDFB3F71E1F7F5FFBB9FB9FB3F684B24764EFE8FC2F7DF5FFCF8FFFFAFC8CEAAF89BFF6EE29FD6DAF3F9AFA7C6D5FF7F3F67A4F8BF3FAFEFFEBF7FEFEAF6DFC62463FBDFB5756FF32F63E3EFFFFFAFFFEDFF2F6796D81 +:80C30000EFCEFB68729FBFF6D95CAF8DF9DCE28F2CB9E8FCEC8AAF8DFF9C9E6F4FF77476EF897C8CFCBCAECFEEFDDBBD100425415824E022012623490240081548042008128314A1242144218D24318B246B128163024B929014842941581484881A44E181041A0496C824484CA2494C221128F89BD2202811241144182C1144A882840060 +:80C380005C185158518160444044D84828625584B02141842804421430241584C844A0682A180180490849D4280198102892884712C77CE032F41124C7221F41326E1F41324E1D24EB141D24AB941B21AB9453F14A9443F34AB553F342B557832DB15F82C4B14FA2E414F8254A16F5244A96E1A26459ACE449C24A1F49C2431F4952281FD7 +:80C40000497248F29124A7241F49F24A121D2CAF249921AF3419F54A9243B24A39242B9447822B944F82B448F9244A7502BCD541941C48ED1112E5F11124E582D278E949D23833118D36128D97126C7114989869D412F1245A1CE1A268514FA26C152E4A16E5B244E4827D91FC22489E44A5F2116487261748AF24F19124A724CCF24A16F7 +:80C480004CF24AB251AF241BB44A1BF442B245885B86ADB44D125F7D0F8480040000000080020000001002188008000041008488000000004004280000000021F03CD224400495041E4441644CB592469848188A4424A14158150440094784190800448303484E8C8426022081A8818E12621220981823318810181814A841288152C12CBB +:80C50000F855BA20318341901E911FA28133291480014483E4C8441424C81C62C0240021224531481164446041202588E24144088C41A2C2122998481AB48821E441A4349A242201856412F07DD7142D1257844485361856C43469D141F28221450830444F84B28481B544C181496124949048248A2142849418443354488130524628A2D3 +:80C5800081830926C8128AC682C97112E84A351842C14483A521403814478229D85A0B00101154818581B24AA141E0818421088C4404448428C024411C08105148130241C249810282184420B94201208188142818A8414A232824038C04F0A14100100C411100419082848840844414411101004146342444137248850824824084081407 +:80C60000281811102102A0412001400229A148201208BF130F25042A31111C042D458B128F3144091391422398C11419E424C1688D14174226B4C9611284D018049011578489C1485248296112B8541942C8318344E212F488221415588625A248848B3483321428414449FAF1F4100281204422049F644109184622B84568145364344230 +:80C680005D182611C488224528D28494218114942CB1482805181922922438113213041982181158C22442F0224A818E1410446C485F660941E0423111454151413608248815988200001217824084E2141125444401174492431408D02424081E8114148414812C82942823456121201828A11242282220E2DA042D4810880422007042FB +:80C70000140244A51284D884F442228A1162A2415D58814914E42802241046014249244408481612A868416022D084118818882182C1841216BA484848F464BE148444D012840418411D28141608C42A15D8828201198443230400308543223A4414762112D881D2421212A442460418004A28189422121228C4238401864604F04B54204F +:80C7800062221514941241156881005081C084190100818100E04402814242400800410032811181184126D81A0400120088524480082004CD2600282415A614C018811153144201CE1643B182C24CF081582B21178243B419D44806441B2443224A428502CC7441842252842671484448846214248812A321C118A262189890884E8C4024 +:80C80000B6CA0F2B4244E501C0241416742802894158288C5218842CA142218400446044844429046D48808502286D4212002C21A196C4A18A0684A02820D168914444924C0183043FDC094140551424104224113211A4181427414312981247111831202844AA422C116C8490494A1168212001004E112551288054181414C18C8C840288 +:80C880002A946840988882D0240B0084A121001C413181C3228812041110044142848484148400905C40285185682A141184312820010018E026181128248CA18142183828F025243014100400404228112257488912081B8181852241827C5851620014181816824112281481810180210186129814200881281800C0288400814FC70EA7 +:80C90000315B14A024B1280060441009822810420113081681024845628222142A4848012248880000422744518018420440148801004C2825C1228FD7028A62431100902843E4451225040023B14881081410041C081018044904521248244012488211410148830152148400880080080025F1452D4008324004411200110012008129A7 +:80C98000420415084114114870440340811412182102114078125221844D429304302148822212622881908828389F7D0B40C24A816042800280B3223812284E8411411200D80084C1008908135422850411125411282018AC122012143122A028460226028B4816022281F09459800100002744006A112211981240884114425486C38408 +:80CA00007141C244472249B1213814008021440212004248942C444402821EC10081C880012A0998248E3D4019A141439221009024502815045912B8641805982880181284032E8818110029488108178490511C0881431444222C6844803218822604442024544A84BFA74B039E239D182362222E22238451249E432F4462A96D128D1208 +:80CA8000848F2452A1816B11242D51F088484D424D242F64F62B14B967144F24D49AF45218811D482F16541385011A1159C84E722D462CC4195AA148CCA4489052DA092A812EDC8851D82AF2DDBB30154D442C72445CC30045C32D574415FA222189721474427481D854F82611116B83C3F4C6414B82D484835284AE87C11E111285E5818D +:80CB0000D51C3911AE329011822CC45215394CCD38BF485813F0A9A18F84A8D48F8AA2422B655ECC85B814A86DB662213F87095C931147518D231444CD245E247A81F338119B9416D811B83CF924558B1916C48D5CD1C1D888F9111393F44B4145A82147811F41B588F241122C1CE224025E441B114D2311FE193715E7411C7842F444429D +:80CB8000883DA14E1214C782884C22B28882D18AA382B885B87D4A02400800702481B42488446288448A04840081A24222441146044411861462482186641244144C82C824800228349A0210328429B214143294A1413014F0A8E1242B221F36F22B23BD4E55F42626AF84F4212117523DC37D922F22FA2B9D75F747414F44DC88F8A7A384 +:80CC0000A5F82C2A7FB5F4A5ADCF4A7A2EFE462BA67A32EA24BC9BF88CC27FB8E8ACF416866D8AFD52AE826F51F224227BEA8B24FF52F663276F46F2121E5FEAF2327237189FBF59EC8BFD8F62FA92966F68FCD6C8CFE2F23674CF47FFB498E7422FCF064F63B352F41C12BFF252136F62F24A4C5F55F531117F73D9EAF97A7A3F12F3972D +:80CC800093FFD1D38CF814923F7ADB73F1A2B63F91F5C78D9F1DFD34172D27CD9A67E3CFF5FD1A15CF25F5979B6FFDF416866FA6FEB7BA5F65F6776C55D217D598F73775FFF5714CFC7E3E7FE6F222651F38F8FBFFC7E4CF65F5AAA62F4CF8E4E4CF8FEEAAFAB2F8EF4EFEBCA8AF83F3B8F9143E244F63F63A33FFF2D277D266F24E485B0E +:80CD0000331F6676C7F7DA7E9F32FA1BBB65F6DBDD8BF78F88F8B7A33F315126EF8FFE179D5D85DFA6D577F226862F23F16E6BF7958FE1F58212EDD58F25F5AA363FA2F7E6C73F11F611163B994F47F45161E57D44F47C7E7FE4FC93D63F1ABAD99BC2CF6DB9E2BA94BD24F7F896AF8EA846EF8FFFB8BC8FA2F16241243F63F316444F23E4 +:80CD8000F32F2F3D236D26AFC4F465741F26F7E766AFADF5EBE3BFB9FB8A9EFFDEFD7CB4CFF9F9BFAFFFF1F18F9FFF1BFB55D51F1FFF685FED2FEFA3F23616EFFEF65A1D9FFDFDD35BAF81FC5C5EAFEEF7B3B23F35F63F641F63F3D391CFFFFC5B69FFD2F64C4CCFE5F5B7BE3F19FDA1A3FF9DFF46C48F85E9AFFBD6F26B768FEFBB7AF1D2 +:80CE0000F4DCCF8EEFEBFB2832D7F810041C012302A041204122011648210812441351489242001098114C123148188314021C0114C01150144800204801400812801408005FE70E47181054812641140445112146D818588489389585518130819044145538484189028384411102182848122068341618082344FC421148428442A034D9 +:80CE800012892A8309382679EF072CF4112485F2112C83F4112CE7241D24EF14D1C1F24A9219B24A5985AF643924AF147924F8429147822F14F924481CF9254A4E855FA264515FA264592E4A9E252D4A9E242FA2F491243CF4912485F3912483F49124A3F48124AF34F91124AF149921AB9451AF143934ABB44B4BAB94478229F9344898F5 +:80CF00004FA2F45439F0224A1F417422F2114CC7241F81726E42F86C131D4CAF64D941E2245385AF6411E4347B84F84A3343F242112F82D452F9245A4E956FA268456F827C98D486E459D296E449D2A67491DC86E449964E1F41324E1F49324A1F41F24E929AF248861F41F24AB243F94A2643D16AB8B4F44A8643F242946F8BD442F8248F +:80CF80005AAFAD0A000028000000180000000000001800000000002608001004000044008400000000F07616604100702244FA1528209481A962811CC4486B48A22A041C1188222464246044CD220050626292638423855128100A11842301A8421588148104B0280836044901FEA18072A45148004B429058224382018CC19483D184B1C9 +:80D000008C61C14312C45447912295C4418332414662428984C694301820581243E111A238808562828E421A94884A389160291AA821E028812C6E14CCF2C8F56041461548C22483F211241848471A6781837168D128945C4CB86818D814117864D21C05876514478ED12C048C34621D44301A8B121E4246417812628230418CE28142323E +:80D080007489F468811311813482188C4AE262A824128F41F26CBB20821204C044A18C2402228031948836C81443811284014A1221044A12C22440B422299944802891141982091810A2488882A04820892102924A216844F05946200218901C4422151414411261140012888028D118130400240044200144221004207124410820E481A6 +:80D10000021B41814003242AD44822039246046F8B0716062555A480324422562825233118C9C184895449D15B4294A024481C72440A1E4916C41276714188518216A812882352C28A82D126624963062B481314223483E08184921C82428B92488648F86FEE400431818564424916654142221C31484182811C18DD144C391828601245D0 +:80D1800058224649440484188082022125845861830200C81934128C3482305A7012B8288895284882F091A8A0122143512412002883C4112C011C9118411A54488082611246840442808121F132414E112485C41818498842282343E641D842867432081C04141480B2444224822969C484EBAA40A8124084443452413A44C198246483C6 +:80D200008244814431824E2C1224388A81C48890248480084C0120250148008C4822248466846CA41284484B8400448F41C8682A14F81A2450822195A443818414A30281118D214CB124096112840045C248414A4192842A05A2463C228311A11A1C2362E2F022489014103189448C014CB88884F42482106118D0220412281D93E01211E4 +:80D280000430121C1228416841281894141228E041220222400989824234481230144362824442008420052880023011001216889211A50100C444CF7B0D382F4211C83423C4252795C98344A9388D31A571162184A2418B2182842E147024098722812A352C26688423DA84F224182A91213A841228024391A8113B2C4CA46184B08AB12C +:80D3000048A1D22BC22C414874DAA4242E58C1EF6F0A25014501894148028B121654188061882C11055129B224048C84A14842434284241964411890845260412542A814001008811B414A8A044548048800844422AF980E4114459848C1224931285B123218001004C541F81441841C110180064219644140041840440291830444241693 +:80D380002442042315C8481044B81804412004445F83074A02114022440185328185A124184C3428150A2830254542286282418C2441088484448D444200114054222C041018B122010023140822412418845882FFE50EC024494104448118448420240432C1444461101424150410244828218181420800A04318388181A02881225012E3 +:80D400008CB2C2216181420018006FFB0100C0214C72182131442846144414288424A21200800421488C7122C4C84C021DC4842842448981288114E344084664221E448128215210D1282214961290448012F842F4A02800001422841004200241415084C048218534241E488081021088048C01000084222848233418181068C3000048BF +:80D480004082288814B8C14F429428D0480212001041490812800128811038622125841185C8480018C0211800134199148C542A1838302131184219032064488501120049F43415C04900141301109211202192D2288034121C214B8408A1B044418888010000811812C0521082B1880228004C0489220100E0830481C082BF13094041C8 +:80D5000008897224C82813022800C180A1128230482800183902A2181A084644B42815464424813214224C416442466C644C042A4822189854412258491484A481F09756C019442A041400100842C410944A4826882122E48201E90C8C21E54298228C3122C081141929C268801C81021210024E1885042C22022D180080241102AFCE0BFD +:80D580006E355F185288C13E232E598782D3C21C8F4FD2D11138584B14521F6221D248F2346C4416782BFC386845D488E6877554D488487428B918F4342A8F42D288A1311AD512C2893E46BAA251FE282E622FA164123377A278149A419D182DAA2B442FE28AE182A4118CA455483F1D429241874254174230184B2121261304484C0DA9F9 +:80D6000031142D94479189D881524649D424B158624487482AB4D121F152444D1419B414E44558C4A21B111A519CAF44F12E24AD5446EC44D165C12A8189C51223F214448D18C3C448474449A81522826F96064130349C56CD5D241CE184B31D521183E5867222C8444FC2F64868DF81E222B141B16CD4290F4E843F8254244D218CF32299 +:80D68000648D18434888E984511400502D3B344D422445B21EB12C92E889A17562A798688B1416A45156C4122F44948888CD8E3F4844214121013042704201698894820084001412540040416214241460181882200C821882188224100488482C08888028C18211880022B0EE0E7E651FD3F119151F52F459728F23B714F22C223F24F655 +:80D70000E173DB186E22AFCDFD585A2FA5F76F7EAF9A59151F1CF97837EFBE3C218F9AFC24273F16F4697D2B47AFF7FEE9EDF5FD25A98FC6FEB8FEEFD9F5B4B4DAEF8E7B88EC4AFA8686EFE5F1EEEC2F63F37E5A6D648F86B2A2F3FADC2DC2AFA5FFDED4CFACF96E32EFA5F5E7E4CD4CEAFEA8B84F4AEE4245F272641FD656591F53F56936 +:80D7800067CF62F7746AEF27F73632DFFEF781156E62AF8BFD585EAFE7F76F7EAF1B0B4F4DF97C7FEFDEFC6D44CFF8FE647B7F36F466E8FF97F67A2F9FDFFF9E94CFC7FF79EDFEB667CD8FC3A3751BFB8FC9F1387CE7A16F6DFB662E6F66F17E5EFFDBFF8CAC8F8FF3F8FCADCABFB4FC5E5EEFADF9BEB26F2DF9FABCCFE4B442F5C8D96F9D +:80D800004FFB6445343B764B6285F9212D5F93B777F32927BF56F6787D3F56FE59572F8FFB58784F65F54E4AFF82F7A8BBEFA2B1CAFD7D76FFCF7F2FF8BC991F86F7296AEFC6FE7C7ADFE7F65D5CEFCCFC343C8F9FF7FC3EEFC5F9343C5E722F2BB71AF811154F45F17E2EEFEBFA3636EFE5F5CDED9F77E327FBD8789F1CF45852EF65F53D +:80D88000D6944F4FFB787B7F62F2D6D4AF8DAC98CFEAEDAB4DF36335CF42F61C19DFD7F3296DFF46F3292D9F72F23F39FFD6FE595BAF8FFF58784F65F57E5AFF87F7BCBFFFF3F3FEFC9FE7F7FFF8DFC6F498B95FE6F6676C5F96F67C7ADFE7F7DDDCFFD4F47D7D8F9FF6D43E6FC5F9243CDEF23F3BF31A999FD5F1DE8E6F6FFB5E5E6F652B +:80D90000F75E5EDFD7F75836AF25FBDE7ABF3CD4BBF49EDEEFE5F53E762F27F33E3E6F4DFD7A78EEF3CFEE79EA01411004418C84C1480000E0814406401828112841048504449028202422048001225032008420486188A048148E48248608822001825FAE038211C0284304460189419418901812811A441484216144124E214548814466 +:80D98000D18525817418051644480419C212C42A6141C064C38694928A622484984198AA44944429098849F47E59C0421F4152381F417248F21124A7241D24EF24D141F26A9219B24A19B54A7925F84A9153F3429157822D954F82C4914FA2E414F8264A16F1264A96F1224A96C55ADE24ACF491242CF491248D121F49F248121F49324EB0 +:80DA00001F48B24AD141B24A9921AB9451AB9443F34AB243B242792498924F8284F9244A8FD40B3CC44C87324C76487111344C44CF14018F52D941F648B251ABB45788AF2431B52D2217882D14678A1CD184E514D88469112EC896E5A2E458C259DE252E4A1FCD42FA8164AD121F48C2121FC9724CB28132481D24AD9619F648A6518F24C2 +:80DA80003B348F243B248B844782B95B86A9D984F5BF19302280040000000080020000008821008008000014008400000080020000000000001470CB4A0241181504837112088524384A8E311602457A1438E8502443C824684392444A023041E3E18128B128212506C8182A89D8481994C8814E8892802421E188E4219244839A28842235 +:80DB0000281A82F4CECD4021487118C229637244514A56128452228D415B481448544B412283B21824688584304247228D242C6214222304832118312484161A2102494482C24212602824402A1124BC4841D418449CF62460441285D582B22471441866C44D8245825A82614912E85618447482D42484B218321C2C240C993636871C16AB +:80DB8000E28384D418928846E145321889311C2284904828430422888A8433481A08812E4226649187459F15021440214143D81241C812306813E114B18154384B41811A84628289A348468484024C121698122820810588A082822D81444AC84C2C2849A2411812A5022566828D248A9418A024F0E52920C2246144008002482642088453 +:80DC000040882282082061441008818C01414A9212420000000049C1444260221A044002884138304800D09604154421127A3E32482E844412218DC10018812F55D21484742C314887544E2483C2242B864222441F4522412182229742228023A921CE222CE221883298C082888E18111E66478129C448A2A29E48844CD8CB0E4992212964 +:80DC800042342C81430880E48442088C4132751524E6820899A4436822298284921446256114328027840200322216E44439228C09822100412D18486880E28108B0370B144444A5622148224C2211621821008184685041461814548441830C8181384122216824008083094E82282148C02258888B18142B2549584283A128838C14C817 +:80DD000084BFFB0E46C8112D2A8C449414003862100248848229041F81882121449812225C88044448848160C119850919818401801408848444B048811C048C88840144A9DADF0B4781444148D0180218100422442B12A021B024014A02211981118828013608108121046081812A3448138286A1610013C224290523E288C4242A81C2CE +:80DD8000848242219FB407280080455284914082410841141548583244448482414A022932212B2424004B2542002A4484981290188A0120C111420000201564812200F0492E40D425C124A1481655821C21F34422122942224468AB422697812812428D142810A64168C3314284C924D44824A12C3088290328F84AB11826419929A041EA +:80DE00004E1AA8C24B34478889238A18C4A8EEE5A052100849C12841840040084341115128128D144B41818214488932211C128202A0121218138461411C018B1417810000184824288054488083C4142044D18903244904428428400C00008442122816C9453024004B122881411256140123011268182820049A848104800419011B144C +:80DE80001A12042AA1828BA445483A24BFAE0B1A2411286124184CA2142C6448806421431448614410B841031485914124148111008181818922C129D01855420046C9281908DCC1A8601C00842E1883041882AA21F8FCBCC014140010442C3118263118228418302115381C90442422404911B5411141120880241441011681012612010C +:80DF00008B142200812884C0142410082904945F550425083048498224820280044880D148048A64819C41B1888401582B4222CB49803C1129240180ED418424A2940012A0141988210E114921048C981126881182B13A0A8200401845384849E2448114413848498882094C09884888422A0812211242992225010044844341280883082D +:80DF800080223844880032A80042A820746F0F420044161228C12112004E141021018144429064442C6442A0424908491481444891248426C86828460842892614420246222914C22200622A180226A8821FD90540A24100124221482618148A1A4442444583824A4801402888880281402342E8140121242642010019048483121101843B +:80E000008489010000B0D10C498281022A11C81290281281321818000022442984230148442242222218001084042A440281229018A04812858401842282828440C841818F410584269C589B124C840241414218444882C332888002811210228881A18425042180488198228412C88413850222A034184C04288B1C414890111981C9547E +:80E080002B18247F764EC2544FF94328F1283643E48481D48476A4F1144883A14185E8C1B247524866ECC4C51D5F44928D11874C288F5CF1454417416485C818258A65621F42B621E246E312F814481B182A2C24E21128B2D9AC332F4C28B953912CE5A4A8DE711BA8A351848F9B926A6A033248811B6412BB111E267D288F67715834487A +:80E100001993884749896C1219FB1C81ABA1DBE12F82A8638BC11CB221BC2782F2CC5149B342C442899128988F15A14DCB41997262A2458291CE688C21D45261841B711DC1C83E18621608814EF82BCA1CC91ACB793044213AD1C8F144482E2CC3F278148087B162E4A6B141951487C94D49193125625827142CB12565A4488F2331225ADD +:80E1800074A17139B1512CF14828C013E0A1D148531A4E3A2E7989B14BA4718CB2885C9C428549E481F728128F82E88321FA581442AE843FCC4E02002018861402690829485842822117882182149214864861A814A414A48220282208823081100111881110010092002011088141F025CF342B67AC52AAFFF3F45A665F57763A5CFFAFDA +:80E20000C6F726A2AFA8F8C3C32D5C7F74FC1E3AFFE1FA5E51DF34B743F47D7BF7845F53B379F75DC775F66D7BDF11F27E332F38FAB8BB8F1DFDEA6AAF81F818B22BE93E632BA54F41D811F6D9C99F1EFFC9D99D6BBF9FF7D193FF9DF969ABBFD1D821F942513E32EF8717E895F4981B2F21F13C349AFDF6CF8BB3147E662F457318FA2FD6 +:80E2800057EFC6F663776FE6F26D2FCFC5F72EAEEFC8F8D9D98F87F54FD3EFC4F75CECCFC5F5E5F3BF16F6ADEB7716DFDFFB7973FD85F5FDBFFBEF33B77CF74264AFB7F7FAF39FBAF35AC88F25FF9EEDBEE22F11FF2C8D9B8A9F94B4E9FFC9D99FA3F3FB791F29F9C3DD9FA4F96BF94E522B744F23F37E588F8AB9D9FD383B2F81F1BE140C +:80E30000BE58EEDA8FB54EF174644D66AFA1713FBF3EF27F6D4FE5D4FDF16C3ECFCBF37AFC9F94E5ACFF45D5AFC8F93CACCF6BDB5BF2C1CCDFB7F7FAC87F53E38DFC45D5AF88F867C14D4B5F52F61B792F33F7D851AF34FC3A389E3A2F81F291C26F517788D94DF2D9C99B9D1F97F7D1F2BF99F1591ABFDDF969BBBF95F3C89AAF8DF53CF2 +:80E380003AEF87F7A8388F87E6A3B172F7FAF84FC9EDA4F58D51342F23F6167487A1FFF7F17EEE5F17F7766CFFD7F7787ECF8AF26ABEBF95F5D8FA9FD4FDEEDE7FC7FEFCFF7FDEFFEDEDDFBFBEF7FCFDFD1FADFC65C51F2CFC3DCB2E486F52F6183FFEF3BFBFF748CBAF87E7ADF5E7AC7E627F51F3A92BCF4AFA59498BDD9F95F5F8F2BF5E +:80E400009DF5181ABF1FFF69FABF94DFA9F97AD14F23F37E688F8AFBD8F88F22F172788F83F5B4CC6E6BA72CA012008441001241844008404448844404002880024440941100B02421E412012200A08248E08824C248E081440140982812288228F03EA6904412242889A1418144A041421242168828E8546288188648A44198438A8204A3 +:80E480004B1214581AC21812841014C11284188C344812881288821882701488628120081E488148B7A8D022F41124A5F31124C7241F41724AD241F24E121D24AF349921AF245985AF64B925F44A9357822F147935D81AF925488D915FA2D418F8274A8F15F2264A87192FA264592D4ADE24ACF491242CF4912485F2912487241F49324A6C +:80E500001F48B24AD141B24A9921AB9453B14AB924F44A924B43AB944F82949A4F82C4944FA2F417F5D092F41164E5B311764C3311A543D43E01AF7441F4423384AF74BB35F44A9255D8227915988839F44A941F22D548D9273C186F227818F1224256F522491E2525F8112C2D481F45D22EF41124872617498F24F18124AF265141AF6452 +:80E58000D941F248B25B218D1243D22A3134A53224A9B122D442E982F5AFF3008248000000000028000000002180011908000000188480040000004004280000000014E0D401421443411408832361D21A689816381844C3318400448A024664428A022992246442284D7800244870117411164492288F242A2114381870828281B854E22D +:80E600002A04C0188118438274310216652A222474413028C024382D22344A681883711884321841C3A61220648446843118498101AD424E2C8B2119218502AC121811025FA10A2D822E5842821C0499A1348B49112A3941871187224D599044133A244D42814128831245F4358A8C322A4CB41C981C4981C21C4CEA22B45482A285842793 +:80E680004A43D2680118833649A992383B144A713458248B42257822A88429615A81AB1887222E44888A94241F85A852CE18182E925661115E2A6F5D0D1C0129014503892131289A02123C21482118080085044422424812604522161462440010C1114410312AF0481240A2412C2841A1412C024019088D24F02DAC80014100A012008007 +:80E7000001290818924C08AD2260442200004E2141802194148308282A082215084001221281820083044C088D84124018088F88044C522716D18642046489F426526A8182211548944428A149C42C224909854444C41412CC289228826AF128125694541812C0781E69389C541884822E49189C24A141A3B31C8C834888A14283E623069C +:80E78000641118A1001E24A0251A04121A18C814444948A842C9A224445084004C2521084212E81869B4A424214118E88184021598183048109818C02884CC8A08184A6282FF1D06324465C12444002D4A642238304200D82225526840A49200444126115448388932848991281A820128117819C2111D48223088132A6114425269E94178 +:80E800002C2141484888F4C771248418608260425012182602467888A48249048B18118228822CD441412302800A28302270848181E1C1928848E028A23425419C1415542138813088A021800292904EAF4B018444803448402182C2448042F4261220022D2424248C921822A11887483608B018242281442164448490494221863848002F +:80E880004400A2E022242984018951848C13F218FD000010025A1208218C010018251824011200420010043548848144180823021B2118164414A412008328014694184008200520047F7F082141C02A42282A94211A726432188322D824B14421F284182752822A91224A11458352841250815E242229C248862C6447223698195282ECC7 +:80E900009A58C11634881429E1C864812E48278128A0128971189438C3B4490B20011048C41384240048852248420812249088844A4308D048622240288105201162411C0845C2242B1419024021010082881A8481048242F034270043024322840246225484422824122B142678C294144285648428188584528421381222291102A01A79 +:80E9800020890100168C018841320010A8120012A08440F839FDC0421824808294280010AC414E1820D24105224538415B8316140182224824A414281008448246A448008902481885911A304282203182800888817084F2C6FD00000081424942182801221284831104222A1484012800200581820084801998982884843034844B12628D +:80EA0000184B21C048228182E08221913620F44A5E008484902844001E241A0212414C8A081681E891480148811001195118111E4115B228240311141148990113E113948900110014118094480022B04281F3759D2008248B24844285641410040085C114828100304840A421A280E44204624548116884260816840242418110020040A5 +:80EA80008261880029018C0418481F310521280044642C02A14221287044122822284584014D2842828F4401003200184681216484288044A8414448C048488C8289B12884A38122484A82490488BFC3073880050080018091484280140445C8116012601241406CC18100008880088820A8212848C024A88308421B8482808401002E88A3 +:80EB0000C352482B5C24108152814C0441C41A94211009844C085884C8CC014832895C484E228188288C0118411C034410B8240500008041081240048F410820845424F0AA93E0849214584100421AC2244A114824A124002262288001AF4804190549081544B289E182C471804428C421811E214223C2246E154714E0540868201C888407 +:80EB800038482508278A22F942A1248E341E123982342C2F44F642442F81F614742D481D485AB614F182EC5119B714B4919E5417484B3319A5A94F92DC84C4148C32281F83F18A81218E482AE4123D144D853E188F54314846F91E444D8546F1C81D8B358F2A32144AB142B834D2889918C28538928E1889CC586B44242B41318446F42899 +:80EC00002C30241D22CD149558488B14ACF141868B148DDE4F4198A845E141725CE944E4957A28BCC1C226B9B47C7811A4641D1C97868B26144B248ABC58B4888AC6118F4337611AE683D124CE4C1AA5B41126D8A82CE8860C3A85B92AA811CB82972A20323C22C78243E44454884F832126A6113A12D48834143A32C86E1C8FC67149A916 +:80EC80007284C742495448837254C8512D31A5E321A2711E148F813188118A43618B3E28C0388B166D241392811588E4199C598AA1654399924AF268484F44F6242C2F4CB2C50D00008400004008120014400181000000002128290100100115081150810020090082400882002029E417094F41D5D5F13C34DF7276427444764AFC6D3535 +:80ED00008D5CDF72941E1D118F467159F5DAE8D7C19F89BD88F8859187924FB3F4696D1F9FFE656DDF16F66C7E6F42F674223FF3F37B4B77713B444F4EEF96F779717AE7D5F138115F53B7C9FC4D5FFF96F6E5C22F5FADCEC7841F95C5D41D13AF8DF16C6C8B56CF64F57AB8FEF22F25F5ECEC85F832A8EFE6024F43F55575CFC3F32D6FF8 +:80ED8000EFC4F24C2EE5FE4F27EFC7F76D4FAF45F559598F847719FDD2C8DFC1F14958CFCBFBE1D95F97F37D7BFFD6F7B5F17F55F7296DCFEEBE36F73CCA27E3AFB77416FD71694F4BEF86F731791F17E751D118F23D6D9F8DFC4C2EAF86F4E5C22F1FFDF5358FC7F359591AE929F9DA38CFC7F668D84F65F5FAF8FEF22B77AF87FD141895 +:80EE00004E5C5E51A0515D558FA3D3FF7266742C5ECEDFF4D2CEF43D3FAF46F359118FA4F3DD9BEF8D7958F93C489F12F6B4988FD3F23469FF96B7C4FFE5F9CFCEF66DEB7F31F5266297F39FB7F4A4A64E414F4FAD77CE681F1EFE94D49F8BFB25248F9CFC5C5EEFC7F765662F56F7F5F59FDCFC79795AFB4153AF8DFD6C748B76CF6CBD8F +:80EE8000F2FBF8EA2BFF6FCFFFE8C88F82BB6C0C2AF635658FA3F34F2FEFC6F26C2EE5FC7D3FEFC5F52D2FAB379F95F1485ADFF4F5DE9CC7D5CF86F5EDED4FCFFD757DCF87F76F794F2AFFC175CFC8F66DEB7F31F5A74B9FF3F2784B4F5BEA96F4B4D48F86F791F1FAFF94149B89DFC7F3D8D9CFE5F13B79DFE7F762795FDFF3F8F89F97BF +:80EF0000A7D51F3DFDFBD9CFCFFFA8F84FEDBDF2FFF8FAAF8BFF74FCCF8FFD4CCCD50C00228461001A14C44820019E486089444844400485249828400489820118A01210042A014098141A2462816089006088288A049228D04822F88CBE3086282A413422C4C128611A2246881194824889228378310816E81402444342D48245712302EE +:80EF80008C088492412888841828C028C1408122341100389608148148189CF4EAD8C0531F41522A1F4132481FC1324A1D24AB141D24AB941F81B24A19F54A9253F24A9153F24A91478A2F14F924481CF9244A1CF8244A16F1244AD6F1224ADE252FA2E549D2A4F491243CF4912485F3912C87141F49726AF1812CAF34F11124AF249921E5 +:80F00000AB9451AF243924AB94478A2BB4478229F934484AF9244A1F350A4D5B1A563E1B6187321FC1724AD241F24A131D242F54E9C1F24AA349F24A9353B24A3925A939242F147926F842915FA2E514F925CA1E215F826C5D65E85CF2261BDE254D4ADE282E4BD6D43CE489724CA3698736CCF248931F41F64A171D64AF349B25AF34B17B +:80F0800024E4646982AF64F3244829F9364823F424182F88040000004400004400000010010000000000400100800400000000800200000000704F0B444D222244AF11342441948711813C51A119440840A84372330296688C4628C224478113C22C8C119426124906416C514918276143682250841AC8C922A36421C860E14D728E222EE9 +:80F100008243241494443743142C2668318C41C418114B242C721481288331128D118618160A4483644222228242901C1A3C64996281448911A2142212A042188F41A84986420C89E12178487418C22400438105856497F0CFBDF02442472438E14CB528117424D18153875961A2663112160884A12CD514C24A1EAC4E881A26684A89C14E +:80F180003DCB294E3417C2CC22D1B414684443D25AC1424B616B18C9B25248F41884578C2E127E884C414814DC22E74893E26724C9B4347454D2120A804221511A44148C04122C38111884148658423A84020028842848442044082941A412802101120098D028084048C2482F2429821104120081F0F5DB50244C921A0048458114241124 +:80F200000234501840213948A2288042684448812A54484112254224022A4C94169018488042028B1480080042848B243048438811E4C34102C0A54D1816F4221232C1831204C018814512042A248244C8189984A428444D7280658C4E2846A824238815021C1218012E14214C76889522C8422358248F219C286349B2842182B16818F860 +:80F28000B731106242DC5248809214CC54846C014048480D80232608C04889241AF4481222414DC88C7642682482302270261138114210C242152E064A3882418B418B244098168CA2188BE1F011FB5024909218433152271280020013110261148A142836288C61126044424982648520012D24221AA484441840083684C224888C810CB1 +:80F3000040C282D0C2292628140445F842B6400C282C14C1238481222D128A11514862A04843C1228301602445E814D1868812CC182AC81884848C0480C4281AD284A52518412E8423014C22261408E722112041B328C18890226F754342287319D412D64884A14200830228444712842230452002458A8303A02124817016E14235228E23 +:80F380002138172284512A0C81842170A40845AA211442882E88802461282281F0D824404204180047117B1248460489011258244810019B4A00444A4229C42420440224842112000022004E28480088218C011E4144C025A01482487F324E027035B82261C416D1927716A1242FA1068C0244182A98422604229368844C41A442224B2125 +:80F400002CE18832585CE1253228A123E116819224C442288514F21248C82828D21484E9F27288A0416CE388E38463884AE2F50D45E2410211258112C42840843911811B418384C41419D41A014A1294281F22D448D881B84878240824816528A4822824C0119AA21216088E2422CC028C5422844A21084100200870C3022442160210C44E +:80F4800029204391114A811484054E142A811414AC148424104464453C0120033244C04481448741444481C02422A2D0A444412401108452841441DF8602221001411B21414440840889011392218800107224B111341322930A268854818A44440D1200144A2204208C32422118839482842B8420244222844108DF41034015080040683F +:80F50000A21826284196111054413011844C6181846E8441488C4182A242902A18464841220112182913C82448706841081C68414228256481811A021425F8CFE52064821A942C8110A22180120210188E912844216A012121841306531401241F41244148031C440100008F142101181418211424450862408285A9947DB1200441224921 +:80F58000212212048DE24C18A91424422448801192688021024D42A0811218212412481858C41042044961284F18D2480A172490111018E2442184016088E0940E2C1141022064D11485141168428082C1848249C4248421468C440E8302A415C8483AA848C28CC244450828852412386830482183843148B048216984869114C9D8821966 +:80F600002412F45A4B24404241021C0148124180041041088941091011048501144260120060410011446220061504128018411C120281C041419044842F6B032F18215886137412298461221008854249440884284666422200108848D814081211811084F41422624F828441F8148236823214866121891281111448C41A4581450E25E7 +:80F6800015F231444008484482450842415A284124E211128429012112522271484C054A09002882460181842C810568480013480A4C84810243A112880060882B12244BEA3052C71A658412F661198351414D144B44298B8655452995191D14247F64352CCF44B124D2119199489D2A484B6911BFA1B424F228421A34551447411E64CD74 +:80F70000213283F56624521F8EF24565AF8898213A784A798C7246C49A8F461238214661442B1D87D2AD824FED4A62323F28D431D127645945F624284A518A8FDA7B88F8191825091755453414323659223E28AF15558845F64E25C6F45C198D922F82C131188CA31C2E14EF45A1127941F44C144D748371269E8C2F2B981427A6997211DD +:80F78000E251E52171DCE481F192986FC1F11CDECF8151C44F397644F437538005878187428D181AD651B12CA6233721471142C3F71A13CD289AFAEAC8CF44035E3C2954C14F45F4626817824BC21574416D15623F3DBC94588C8D68481F247448F1221A6826A85889C35589F121668B51CE59583D88959942614F44A464F022A281988C0B +:80F80000F18444A02520012044384420042200408144010044008200801108284128182840088418200288806881888028832882A842A04B814F2A4CF333122FB6F13A3A2F32F71CD8CF17E751F55557AFA5F546ECCF99FD797BBFE7F54643AF84F545C6EFDAEB63F31311186D52CFD3F714117FD456FD7F2AF757514FE5FD544727263F5D +:80F880003FFCE6266FCBFF3435DF17D471F4711F7F63F336644AF6D4E2AD68BF6CBCB2FFE9E1EF8BFBA2A2ABCD5BDD3B49EEF2AAFEFCFE3F2FFB36354FE7F34C243EA44F2576BD45F333123F33F53F3AEFB3F35E5CDF57F76D79DFF7F77A3EAFECFCDACD9FB4F47B68DFB5F54B58DFEFFE9E9D8FE7F77B794B76CF82F36F69DFD1F4755594 +:80F90000DFF6F42F66FFD5F574F6DFF7765AF8D1D37F7EFE96F4CFD7F7746C5E461F73F51F3EEFC3F2485AEFEDFF6A68FF6FFFBBD78F6FFF7EFCBFBEFF7BFF5FADFDD6F4AFEEFD72FEAFAFFC72B27F47F5FCBCEFC6F374FDCFEEFFF41B343F25C763AFE1F12E3FAF83F37C794F41F1797FAFA5F1CBEB3FD9FD797BBFA557BAEFC5D5FCF1E7 +:80F980006E7EFFB2B276E642D386F436751F53F7657EF7B23FF2FE73715FF6F6787B6E52BFBFFCE2B72FC8FF24245FD5F561531F72F7393F6F43F3484C4F2DBE36F7F3F76BFFDF5FFF72B4BF2EFB5BA85F4DFD1B58CF2EBD28FEFCDAEFB7FB3616AFCBFF8E9CCF47DE6CF13593343F25D733F31B1EEFF3F3BA78DFD7F71C7CDFB5F72E2E30 +:80FA0000FFFEFEFBF99FB7F75B7AF5FF5F5CCFF2F34E5AFFF7F77E7CCFC2F126187E75DFD3F7EDDEFFFEFC2B6FBF97F7EC3E9FB7F7787ABFADFDE2F7AFC9FD7D7C4F47F574525F72F33D3FEFC3D3E8F5DEFE6B77FFF7FFFEF2CF6FFF7274BF3AF95E3A5FFDFDFA59EF6DFD7A7EEFEDFD76366F6DFCB6FCCF48FB34BDCFECFE1739002042A6 +:80FA80006812804108841484341648A541A041850485044A0228902811811890168118901400901440021C486832841412348424128112200882AF320F145014107811044CA2128614024A0181418D823A24241232141445581861144B5210C2218C2801C04228148C62241E284342D824A12142288D124130148141819082168869887FE6 +:80FB00007B034F22F4112485F3112487241F41324E1D2CAB141D24AB9419B24A19F54A9153F24AB15B422F147924F842914F82C4954FAAE414F8244A16F1244A87194FA265594D4ADE24ACF491242D531F4952281FC932481FC9B26AF18124AF24D141B24AB911F24A9255F84A9243B34A39242B944F82B442F9B4488B944FAAF4CCAFF065 +:80FB800026481E44AD411F41724AF21124C7241D288B141F41F26A961D24ABB449D63A9945ABB45B4229F934482D916F82D452F9A45A1CF124CA1E816FA274C8F1241AD655949E216DCA8E282D5B1F4D925C1F8932421FC8B22AF98144AD121D648F44F911242DA25D688D924B4389B824B44269822F64698BAF44E12AB18C0B828200000D +:80FC0000000000800200000000008008001240010080040000000048000000005012F062D314164146098022C22425318C80384841486B6127222602854434181A1824021818444598162C0898A021166119D021C22CC3A28184A04823F2528889814904107818A28486A84A22EE5F2032B3384799671116151BE344F22251232182D818B8 +:80FC80007491041B49128B122AF5211826618281114C024B2413212422C214C44D312150C245420856D214A2428F68444849E228D4A4048B828F223481448052584978BD0F126F2CE381321525E412511A4427522D8D612850143C6F461BC32D3212467C31FE2811863818136248121E645361E42038128E19CF3221019B18491451421EA4 +:80FD0000644D814864CF28C4232A88715A04A8A48609248CC8C12721CD47601211148CC81144269221421A8621B848C848441221902832003841200200E0412242140422131106A3C22885A22183E28804848F24E188C48241812A0447812B84228D2443FA34DB001A0284224003426014A084008488222100004800812001802408860445 +:80FD80000082881504400200850214840010844808F0EB1D104511085863010000911522D4120C1144818AD24822020042274289E12228941883024812204288F12458988C128204A72880212414F218C241861218242208B778102402A0212110220410612424C28414248160C22800008400218480280400849018128421406228400828 +:80FE0000422186022484448100B7DA103111818924341414006054811B824814803824200A002905C8274283A12948121D6800478980029AB46438852820144218E422814441E8844184188488823812BD453023100A4461D022C23285212A0421840046C61580E844C841644582420820C488212B42001100C0282301200162A0412D886C +:80FE80008122C062B08841B8448142F276710080410414004042088214302112182229912200C0481012C42844271260814115C2124151214142126130481824000021A0249062821E44888FF90A80011502811214150811172294814825081481628418000024226400121028228242381980088125080084444C4408848122184008DF00 +:80FF0000E24A312318A34105411217221611BA8862162D8885815483D0617418C1328B284A8154244D4A103224C7224217A21889514826C1216952848711A0C11245628146A834701258428D442210E884E2A8C278437C2488F81C4C00005026154802831251124003812218126C820443480120121802452248A22400290134702C02244E +:80FF800084000042860884212A142201124A01BF3E0D004008440000140000000012200200000010082888000012244022180840185281002400840040F2E1B110D1520123111111011D2810185181450820684824001021627410084924112422082B1843D1124861288830122860212411244001883014304888C122EFEA0C3011241807 +:020000040001F9 +:80000000100510011400008018040022141849844808204104222C081282400220811A28512285111213010018848140582257EE5089AF44A444831401143028504C55B42DF228242200882412242552221AC3139AA888C04440D811D211187198588CAF14B441A49482254202004554444B228B2222801842042C348265A213CF210B3053 +:800080001200214C0100004001141012080000000040040000000000000010010000000000008F2705818C2484041021024014E448722881224808005022102291142AC88400181413486188818C2484041220024016C424378228008112002490122F1F0E84E02144018011518114924480220800002012129414828E810081284041029E +:80010000A48004214112002450418052810000001002EF770380040000004044810281000020180218800A280021140084804422013410120244800221100800100218BF1D062100180020011113080084000080080000000000001002002410082400145021424008000000F75B10B8482424041100004555444F822A26060000242542EB +:8001800026019604430822501111118558888B4452420010420245544C4B222A362100004002241AF1CC95008D184C8404000082805844112A0281840000242981A1112A88080040521121508848C8240010020045042A4202442002212512F29876241800000014004019111A01C084120000112828000022200140024C1882C2120011C7 +:8002000011114018080000004044F474F8002001238261110012000000000000401404812244000040020024000040022121102801810000002FD50F21001012412143482119718111234402410000004742441382022229031200106249822D2223816122100381214008814112220000DF5A49228121711203410014118881401128584B +:80028000888C08A0880045014B226042100840022121405222C012A11003213181467B4A012508000010F448610023C11480A2111B1115019815C18189784878810910880180124404C028414504228048C2822400185014242124241543411219810185080010042FEC0A6F22F212222E122B11122B11C0132592822F31F111119B888E32 +:80030000898F84F888418F8424F4414915C1419558884F84F448444F42B444F22424222E2480524445E642F326222D222E122B191AB88229C8122592831E111F11B189F991898F84B888F44848424E4880548885F844484FF6046F2252262AA1131200182592823CF1111319EC89D988B888A44C4214158154819588F44844C5B444A22291 +:800380002200405444286F22D226A8123AA1812B8882822592823CF1131119EC897818B888A4444200405888483F810B48420000008024040000000000000000000000000000000000000000000000F09359802484240420240400000000000000000000002024042084A4444200202424040000000000002FB80B484A04484200420020A4 +:800400000400000000000000008004428024240400A044004200000080088200004DB1800480040000424242000000000000000000A04400800442004A040000000000A088820000330948420000008024040000000000000000000000000000000000000000000000F09359802404000000484200000000000000000000000000000000CC +:8004800000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F093590000004200000000000000000000004848000042000080842404484800000088820000E0A40648420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000006D +:800500000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F09359802404420000800400000000000000000000000000202404000000000000000000B50B48420000008024040000000000000000000000000000000000000000000000F09359808C +:80058000240400000048420000000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F09359802404420000800400000000000000000000000000202404000000000000000000B50B48420000008024040000000000000000000000000000000000B6 +:80060000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F09359802404420000800400000000000000000000000000202404000000000000000000B50B484200000080240400000000000000D9 +:8006800000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F09359802404420000800400000000000000000000000000202404000000000000000000B50B484200000001 +:800700008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F0935980240442000080040000000000000000000000000020240400000000000022 +:80078000000000B50B48420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F093598024044200008004000000000000000000000000A0 +:8008000000202404000000000000000000B50B48420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F0935980240442000080040000D7 +:800880000000000000000000000000202404000000000000000000B50B48420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F09359C5 +:80090000802404420000800400000000000000000000000000202404000000000000000000B50B48420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F9905484200000080240400000000000000000000000000000000B2 +:8009800000000000000000F09359802404420000800400000000000000000000000000202404000000000000000000B50B48420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F9905484200000080240400000000000056 +:800A00000000000000000000000000000000000000F09359802404420000800400000000000000000000000000202404000000000000000000B50B48420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F9905484200007D +:800A8000008024040000000000000000000000000000000000000000000000F09359802404420000800400000000000000000000000000202404000000000000000000B50B48420000008024040000000000000000000000000000000000000000000000F093598024040000004842000000000000000000000000000000000000000000BC +:800B00000000003F990548420000008024040000000000000000000000000000000000000000000000F09359802404420000800400000000000000000000000000202404000000000000000000B50B48420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000D4 +:800B8000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F09359802404420000800400000000000000000000000000202404000000000000000000B50B48420000008024040000000000000000000000000000000000000000000000F0935980240400000048420054 +:800C000000000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F0935980044A0420040000000000000000000000000042422084840400420000000000000000FFBF07484200000080240400000000000000000000000000000000000000000000AA +:800C800000F0935980240400000048420000000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F09359802404420000800400000000000000000000000000202404000000000000000000B50B484200000080240400000000000000000000000053 +:800D00000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000000000000000000F0935900000000002004000000000000000048480020040000A0444800004200008008200800BFAE0548420000008024E4 +:800D8000040000000000000000000000000000000000000000000000F09359802404420000800400000000000000000000000000202404000000000000000000B50B200448420020240442000000000000000000004A0420240400A04400420000000088820000EF5B074800480000004242000000000000000000A04400800442004A0442 +:800E00000000000000A0888200001FBE0548420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F990548422004200442480000000000000000000000000000424200002004000000000000FFFB0C80048004000042420033 +:800E800000000000000000008084A444004A04004A8404484800000000008200F03D2980240400000048420000000000000000000000000000000000000000000000003F9905484220040000480000000000000000000000000000424200000000000000000050BB00428024042024044242000000000000000000004A0420240400A044BA +:800F0000004200000000888200001FEE014800480000004242000000000000000000A04400800442004A040000000000A0888200001FBE0548420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F990548000000004820B2 +:800F8000040000000000000000424200002004000042420000000020080082828FDA0720048004000042420000000000000000000048480048002084840400000000008800009FAC0E4242004200004820040000000000000080840442002004000020044200000080280800009FA904480048420000000000000000000000000080248418 +:801000000400008024040000000000820000DFC506004248420000484200000000000000000000A0440042000048428084240400000088820020F8912C0000200442424242424200000000000000002024A444000020042084044A24A444420000008A280800F03C62802404000000484200000000000000000000000000000000000000CD +:8010800000000000003F99054A848404200400004200000000000000000048428084A444484848002004424A040000008A0888888888EFF7070042004200004800000000000000000000A044424A84A4440080A4444A2484A44442000000008200F05A1800008004000000000000000000000020044A8484044800004248428024240400C8 +:801100000020882808001F4807484220040000480000000000000000000000000000424200000000000000000050BB004A044800000048420000000000000000004800800400008024040000000088000080B8590148428024048004000000000000000000000048428084240400484280040000000088820000BFA20142A0444A0400009C +:8011800000000000000000000000004248008004A04400008024040000000000E0AF0A48420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F9905484248004200002004000000000000000000420020044848002004202D +:8012000004000000820000B0B50148000000004248420000000000000000000020042024042084048004000000000000B0750E48420000008024040000000000000000000000000000000000000000000000F093598004200400004842420000000000000000202404000000004200200442000000820000D0530820042004008024240470 +:80128000000000000000000000A044004242000042004200000000888200007FAA0C4800480000202404000000000000000000A04400800442004A040000420000008A280800F0CEE580240400000048420000000000000000000000000000000000000000000000003F990548420000008024040000000000000000000000000000000013 +:8013000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F9905484220040000480000000000000000000000000000424200000000000000000050BB80240400000048420000000000000000000000000000000000000000000000003F9905480042000080242404000000000098 +:801380000000004242000000002004004220040000200800003D85004200420000484200000000000000000000A04400424200004200422004000080280800F0FA2F8004800400004220040000000000000000004A0400482004A0440000000000008A280800F0D49B802404000000484200000000000000000000000000000000000000B7 +:8014000000000000003F990548420000008024040000000000000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F990548000000004842000000000000000000424200000000200400000000002008008282AFDF0F4842000000802404000000000000FD +:801480000000000000000000000000000000000000F0935980240400000048420000000000000000000000000000000000000000000000003F9905A044000000802404000000000000000000000000480000000000000080080000F04BB2802404420000800400000000000000000000000000202404000000000000000000B50B480000FA +:801500000000480000000000000000000000422024040000422004000000000000002F57044800000000484200000000000000000000200442424A0400200420240400008008800880F8F4F78004004842008004000000000000000000004842800400004820044800000000802808008B7A0080240400004A0442000000000000000000C1 +:80158000A04442488004000020044820040000200800009F9D4D0184008CC1484149E422247824214861484C0A282C22E121120820083121883121889881882042490184484548B82638A41400C4C0224C420624122051828FB20D1416D381D129D4411464862648F424418092348415D22542341E57A2881B1AAB1896F8421249A81A1E13 +:801600002533F118849F48B129C12986446BD2113632189DC25C1CAC4A4B5242296443325C2378615684248B121E2E6AF12842894128F56AB80000800148842C2268128A3221601841C01854239111848341022822147D8282119312480A80820121806821464284020028E4008D24304A218981F193A14061211941924800483041448085 +:80168000D14808112C2212082528082B41411004124321A28144112685C211218998880049C484821C819111896814284489122207890189D4AB084001994411C42826440400000061641A826A221282408249B11248581882004048011142C04C8924022841C0244110024418200124E0E60E4018084483140448260440044D222200009F +:8017000082008882152201008C018288008484111744302481224880021004268201212200247B6F000000000000000000000000000000000000280000400800000000000000005F2B0F19414261C2114E2114154421C48129224102302820220216042C728428022E18872286D842C412224CD421210418162C94192495145484261852F7 +:8017800028701802296224248C0849A4812CF82A38108441522148831178421A9828121421256814441381721258225C059241482443562298E082482821812212022642189241AA219261923C117114938420118601182284412FB44111612115C22D13F42148248754A18394812229119243411782D022211263418828274C28418D1224 +:80180000872287288B48802321C14200ECC242181394A74145E88211538363D1864982624429110A43B61888D86D044901002112850114282C11018400182289024E1480111448A2242322094CC21A90441932228021115881608122198628011124C01200821800412FAE0900003411181004188424009260888112101108608242211E7E +:80188000242144222888122B8211002D12160448002412872480015084420010088F840A1B423D1218B014C2187C72249A58AE581C24C2898351141558C12981D84178212883C2814732001E24821E2127832741848903186C7821988C194A6844C3F1D4222E188C240A1221A3E122C832433248424982064E49805612002289D125119418 +:801900001CC6A814C08812411E89159882833894841484824483024C32942F31922C412688092B1A74118522628148813E828C2104462A512200209648404408EFA604141223014D131422AC22A421118C42434801448C01111C828342C121212C242102122B129028188068824CF8811241411E44468412B8820380C1188E2247832504F4 +:80198000422268F0BB1FC0287C02482424182100122244E3561A1C8228216121111008278E284184222002184311B122E4846282144C5424B04463924C616919C12200002722D04A41CC648185F2688A508212111B41008416044C948142CE1422580046582B2082A4122901458191661D86100100002784001221C421902244C68A429836 +:801A00001290428008288448221F34064830182841CC9141911C4288844141012444612012D884080084141212168251825082414711241D84120028944B4124284008812FC11204C921128201883FA34E0336158201C57241C219114628A8218E52142D48308487443D1828931214088C42751463C19E27B02351822C3114644B412259C0 +:801A80008AB1145426415C34251AE22A21181A7A1298364CC42216BC1662423889648ABEAAA042D0189121452291184422444E1148144D481C31212522412211E2888443A2842E88882A04180040186132101A017028E281F2481244211F8104008425028884A14D48005FAD0B200100205248448068883088151824382886F411882D81D2 +:801B0000448215144818413811824012088064229C324485C238D0826324264851821800448C43C81881282280F2F1DF0011E045420481001E84130110C584880028224119140218439812240016011A88243311A124152892818308178848C111000024009012458811F46D1600615012501428135281182119A3818814211CD124618180 +:801B80004400181001005018C04800111AA81813B18802102118411102402101801288014048F899FD80829248504812449042148B242426044941022531218249712851213E42411C01A6C182428C084A1218484881021B2410D22101B0414996480028C01821288004242FFB0F118140C831005C220211149441282484824D831181C6B1 +:801C00006889458118C81200200250821414248142208121341800272184111442002250188041E1D90E16A8242C2704288523018078822C8221212A31241212211833A28242400122184364A180A338221800244D212B822D21282C238184C12820E12221120212898122F2C9B400904800212180C12A49241412938815E8180200008062 +:801C800011082061184A88111288784222042C4882880482883D888280820528820022224810F8A88B209313288436681148184225412AC281122C02601824818B81232892481C8618B2188C52188B481A223A32412221001528981143942212281316648114128120215182286021CFE60A94441AE4111241140584C4184C84042194283F +:801D0000409824112A5122244447144B84671243A12125A1481CA1484098A1C82E814A088304488289C414484AA21448001028283122708B0E266247167241117112E4C2525683D44871C458A19E816D886DA1B7421DA18C7838FE87283B9128AC3B144F44F21C81124D611AD131E8F461A3ACB15AB421062E331F22028F36F6A284841EC7 +:801D8000E2242AF331883914F818511B1128A8278236C8322DA8878236E922F2D373141E21B12AB216E1129325F021222CA4211DD1299A27174199C1831823B285C994B48C651B2D383924D813F19A981F6AF838488B4BA0A82E2896F1311112AF18B84EB281F851393F397221F84B299D43A7484E3A3E181784E041F1381281A1853838F8 +:801E0000527018F82D3890114D318D188F82761CCC11F7141E185D3857B8AF21F2E85183E61861EB8638BA5F78C3218733C7489F5F18F161C78D891D4E4636212D21CA91818BD4AB438E92ECE12CF6838816F8A1CB84248B942F5CA1DA2F89E83465112F440446A146842C832183C17438447F69040000008441200200440000102808400C +:801E80000400000000420000C048C048220084200148208102002021F4FCD4143E123F97F3193B2F12F62C2FBFB3F17B5197128F63F241C14F1EFF6121BFF6F48A118F18EA13F33A19BE989E963F92F347D9BABBB1F9E1E33F18FA81135F15F561A15F17F451415F76F36AE22F2AB36AF6BCA62F3AE8925A11288F2CD46EB8DBFC5DD73FF4 +:801F000083F72361FF33F12B23BF57F441111D612AF7A882A1242F22B392E986A7667E62AD17143E323F13F7393B2F13F23C2FBF93F37977EF62F1121E4EC98FFEFF696BBFB4D47FF1173B1FB3F33A3B2FABFBBEBF3FA2F2D7DE3BBB9F8BFBF5E77D299FB1FC55433F37FA77733F36F6773F3FB7FE3232AFB1F2564F2F3FEF22F61A181F26 +:801F800012F62923EF63F31B81DF53F21179AB62AF67F129339F1757911F11A1328FABFB22222F21F13A32AF29BB4AA7772F26F52151F034362F22F73B3B3F33F22F2F2722BF77F52F2FEF67F65343AFD7FE4941BFB4F68E95CF18E812F23A9B2FEBF1B297BFB2D357F1FBF81B775F7AFBAFA3BD82DFD4F46122FFBBB253F47537AF37E225 +:80200000A1331A4FE9F8E2E21F1256198FA2F24A6AEF6FBFEAFA9D9FBF97FF21318FF7F56A72BF91F2415146A176AEA2212E222B329AF922382AA232AF71074F63F33232BFB3F3332BAFF3B223F27977FFF2F37E7EBFB7F77AFB8FB7F75BDBFF78F1BE9B8FB2FABABB6FEAFABEBF3FA2F21F9DBF8FF779685F7AFB272ABD4BDFF5F5F333FF +:80208000FFB3F36363FFF7F77A6B2FA1F31B2A67612F2FEF23F31A12BFB6F22A2BEF63FB69E1DFD7F67B798B33AFA3FD6872BF95F711191F15A5778FABFB3A382F23F32A388F89F93A383E328FA2F235AE4001186012844D13843492266189248214960817816C224834818113A8245048118129384823123822422D81C0118414C093600C +:80210000221E4826031416080012002800F04D82A0181F4152221638241082B244C128241A52184026C123860845581892206254354A84644413A225A025214280D222086AC848218CE214891288828144013826186281A3A4432894BF78072D421F41522C1F4132481F41324E1D2CAB141D24AF249921AB9453F14A9643F24A9543F24A16 +:8021800091478B2DB14F82C4954FA2C4854FA264116FA264192E5A96C54ADE24ACF491242CF59124E5F2912483F4916CA3F6812CAB141D24AB941F81B24A19B54A3934AF4439242BB4478229F934484CF9244A7F34056D4A1F41762CB21134481F41324E1D2CAB1615D44AD941B668B915F24A84228F543924AF147994D812D282C4B56F12 +:80220000A2C5954F8AC481ACE558F2245A96C14BDE2545FA81288CF59164C7221B29411FC9362E17C8AB141F48F242141FC1B24A9A25A93934AF4419B4427B2498922F83F442844FA2F564E1008004000000008002000000100218000000400100000000000000000000001002BF7B07114712111213110385D4254321289111B0826161B6 +:80228000461884E8C88241284C18214204AB61CC22011A48F812222071221808861148C3482C011542181592428A054981048190284F9E08288A012641584815022192601881E511814243122811014D18412442811F42412554A12E882C021442142486025223A183982718001A0412248125022D2A26486411242FB30D136246C031993A +:802300001101213D2411411C9111141ACA341518C688264442881942B18213E441723CE144D281B181221B1A297441421A083C011B2929C19161342A051821A94492148F24C22284128721CFA60330111440424C41CC12928882855284250123042196C81170485484801458214284508240A22121122282218A9418F04882001018158259 +:80238000C4924002814120F2CFB7200265032C01182814111C01A048141002850130144251104304814528044241422C8802440063B28114283848923440264104899244188022F2D3FC244411165885D411508116A2858988D1127112711438124498641AEA9885244978840810924429493C3223B3E211B44462112A817283081427430B +:802400002E8622241314FA188213688427A24F261174A262424901F0EA97D04212811143066012B0833511183C21512424A08184B8481A8415348C140049341C89C4122AB5B4C44448222264871890234E148D2680244421514152442B144CB2A224818122F233F100505AC1934181113811C08810C2C19921410454218F1118845818242F +:80248000101452288844230221604A3381210240B48322A828843F2811388A23582A89C224A164264404F0B247401812591484101C08890121168418F8188190128229140148188128A112118440D4410128222518594200C25410C8828C824231421882C0141622E288445428DF720746C9142D2421502813246882B048114834241682A2 +:8025000024C82412282168382D121024C1442C4852181211002146AC281C6244430222132224018B24444024952C882824288A81F29F47301200364254141A62482714618213012111104203832182488C34248C04303248224058484100002B212901304221110048122312E22408818904005F6947B3414154C25C431CB13754481782BD +:8025800087418C5C1A124181C8803382AD321382FE1844469224837412E8413493AC6492439118854404448C127642342670258224244918D814D422141492AC2978280283C49489B29A01241A643210421C08272480214122C81317812D82511848002810B824880828210044807222021C98212A21A1846032843428428021A394484C92 +:8026000021B148220AD0F40C401442744801118C0480114201141CC1128460138A0142484B2C4B4812211820482882028AA11231430C9048884C34441BE142009741006301804118B42871C80B1312814423025034184400223881441482D08244911421008429886284244CE4444368848A2614E181321A44411222890190A2C88F440844 +:802680001863012AC428422218823FA90A25C212D02244012D4918000040840144C48905001961428002188B82178A89018F4438811684418461821EC816CA24008184008448CC914C28274100418516F456C720A424911A021902A952481952492D634414222E4189722212543280D2284488052C9844804421488101001124444A024422 +:8027000041131202AB1200228001450248C0423EDB60284840088C119441F0831840081C08241214A082418122BC082A28E412384244321014A82110081111141115B4832188E4115821883902188400438182E112F8F579409418121524015230114582111121911584141218421418211849C9428470144188642118228AF44428118C1E +:80278000A421288A02004682A924841A046C2892E270428A62412342B67E0348444C0200222002E02208218008421344982288203221212800224CD88242114482281484088085C3284951218008104218342812002914F8C3561012512818490485865118100812816161C114C48031221F8861148001142C381515082CF844138445A2C2 +:80280000290011C11902118F19029011111281304829A1282C0281216BC660C1504181846C04442D4481D0481198648100168612C488412532841880D88448240848262118441884542246682564982C06C01646826284230660C463150421F01D44244F243492474149B1126421DB614D514511F411141592225C6C3143741A6A141E4566 +:802880004AB692A182167A12ED1AC2442B1245E544588A5AB14CA1A2EF15B448F8C4721AD368B124F219245E427F25C2843F81227282F1A1A21DC22F4C5C432BD287C3C5D2E885E7269224C752497B674261428557A2177485595884521FC5D35341E81498117B119FC2711881F119142B14C7324F22F814181F12B18DC4868B2A481B2E1C +:802900004F1B7541B526E8A832842E12824034333B9165F925142E4D4B1B4F72C4861E4821A791197118D92452242F423236E7872B112E141E4A86FCDA84D012B165D519723A38652A7442772B1EFA2888A5F23A28C54118D6417A25F5862ACD2A3F8158194CB248EC26BA44E42449FA128A85B8A4FB894F3AF4184C1FC8FA34761E84D7E3 +:802980001E948FA8A44C8F888291218B1CDF9DF761925AA53C85E82675189C525ED84A626845344818A7266DCB8092142849810228803244284A084A48A8842288118120241808104194118110088100228426416812404108122641486181A88488908848A81A043FCF4AF243213E3BAFB2F23B7E8FE8F22F6F3FD7F77374BFA4F4AAA6B3 +:802A0000FF96F6CBD8BFEDFD53185F4DFFE7F6ABBAFF869DBABB143F9CFD6D6D1F1CF971A14F7EFAC3133F11E121F9CB829FBDF88B97A5F6DEE68F8EF4A8A62F29F8B2AA8FB1E2B9E9A1F1A6BB6F62F2E2F32E263F5ED233F35293AF8B7984F845EA4FE6B6C6E827B192EDE8F2A2444F4EFEC4C44FF774814CF241255F7652B9F7E4BD2F9B +:802A8000FFE3F753541F71F17A7C9FF3F3BBBD9D1BAFA7F7C39BEFC8D8EEF14A58CFA2B912FBA8B27FFCFD4F4D17149F3CFBE7A73F36F2595B4F6DFDE6E25F7FFE5347AF77F6F6F6EEF32FEEFFD2C62F6DDD75F216145E5A6F2CFD22262F2EEFEAFF73757F78E72CED69BF16FDD6DA4F6DFDC68C6BBF2F8BFFA62C6F6AB4D6FD9C94CF6A62 +:802B0000E13E45F273566F7157EABF61F12A4C5F64F653543F45F12B3AEFECFC1A1CBF82F35B3A3F89FD191C65F61A18BFDEF58A3DBF98F8B3B9FFD3F3D4D41F1AEB7EDE22B862F66467FF3DFDF9E9DFDAFFECCFEF6FFECCE84FA1FE56427F7ADEFDF2B5BF9FCCF8F9EF7F67F6A7B71F4FFA23B43F74F33333BF81FF951DDDCCCFCAFB9409 +:802B8000D44F6AFF56748FE4BB72F326644F41F1A41E3FF84AF273565F71F73C3EFFE1F1B3555F65F773345FF1F11E1CDFF6F69B999F3EFF5A3A3D4BEFC8F8CECEEF87F7AD1F7F58F3E9AB7FDBFB3F3D4F4BFBC9CB7F7AF862628FA7F7F577FF37FFF9EB7F69FDFEFEEF6BFBEDFE6F6BFFF6627F7BFF1D3F7FDBFBBDFD5F7BFB73773F7A84 +:802C0000F9F9FD6F43F543F71F33FF1FDB7FD1F99FDF4F62F37E3C6F47F3AEFCEFC3BB72F33674CFC7F7AC8F3B96C0119016D022014D111E4824400134400744122008112048143248902861422B92816B823026302250249014124522098260890044128584440444F09E9610169118D01CE1414422511CD0280189018D1412348485971D +:802C8000448DB1128F5432A146048B216B4214D88D21411A02A0D211472296681215088A521A1966221B41421125E688D428234A220B823886F85FC4F024421F41F22C121F41F268111F41726AD241F26E111F48F66A921B68AF14B985F44A914F8AF44AB34B4AAF347B24D812F924488D914FA2D418F8244A16F5264A87592E5A8759ACF0 +:802D0000F49824ACF491242E421F497228F2912CA3F6912CA3F4812CAB141FC1B26AD981B24A7915B84A7924F84AB24782AF247924B84AF934484AFB244A6F5D044FA2B411F42C5212CB1613316A44CB121F49F42A848E4489BB84969A5F8994AA4B488BB447838D8563DA58F1265A8D914BC28D852E5A87482E528759BCF49824341FC91A +:802D8000E2A2F411642AE9C932281E2C29E8C8B24AF1112C2F46C82C2BB44F81B24A5984A97B24B8487924B8487916A8A46FA2B1CC048282480000000000280000000021008008002840010080040000004004000000005012E01F0BC0221508531601804181112128840112A48D838110C4644014880600243024844436C29288174100D1 +:802E0000C022002022880183622143180200D01CF2EB5190411B18242A014C91442501248420411FE8485381208192818922113481415991281911D84139282B81D0123142405C8230361608C06927888044064F2814382818C542286411F063AF10B1E141A8211D6419C144141814C34101C7348B21281651281E81A95221C9B224751289 +:802E80003485C3B825C12813011B8199B23648D82F21B54258862D15F012248428218B246388A24A4D12D02422318A18A4244216311A972D800425034044020021800930948110088800002004404814020022128884001800118100008E488143121214083024EF97082011021C11011A62141B411812A51104122D144838120042220045 +:802F0000444021B2D86282CA3222C01200108A1608216822122484004222188221A24624F2AF196051436213188934244F9162644002230685D1147444885C182094458A5284948B4822A3B428D148391460418484211B28248885A521008D4130128823162244E2C568822D882F22C428CBC36082E0490B15043B21301844DCA314141BCF +:802F800014244A111A1121A48183044A1124C244268144022A7195086668418C1E0A1902502D8C23041304422AA81440088B94A48F22A8122D882A8DA842222F9404184C0312469121D0248204298112514849341C6914810319841848C88822C914082E148A312860228059228800228481212B1270224282046162206422C122C1F0C99D +:8030000044D084016C028C426244921C021042B429218101478400800498200248460248118341943311453811280040048B12AA146849147048146C248420618840F65B7D248914417934210400524C9431484443465412440089611289189C18844328A5211148231392210012AC51482C2921018531118091224C02C126022280512262 +:80308000482604AFFE0F1922016041254598A400400888E088C24212124410248612444804188341C8448044A2420025010028210048212504008514040081C88F8145925119C1221D14464C57842E141661441A52827094011C42B21C2441044314B4284854484AA1211C51288B1225E48182342133741452283C2321014D2111181A969E +:803100006A2349558426144A5248182331488CC286CF74024382541C282E122004624081048CC4169668440016C82186B8480281224C8824945242485024122A81D4142108008429C128884002C048444F820400824448D7F16044492222149438291298122835481142312281211016180210086458647048022C42448201182642448864 +:803180001478120200A02180A1184784188A1188E882210AED7200218C84020028708104008A024346280A13122402130232882688342412004906004430448429044518621410588485440420024248E0A2F47C730018128345112101448C850E88800A491894814188844AA841008034882088A25893214821085024C42284528D42206B +:8032000024C441001092482A2411742408BF360613035014A1859428464508181E24422893149961100410942480014902121A0815482152144A08108808541684021400504180C112414184182C81F874BF2420C322868491121042982210022110022184A9110810084082C142403A1C246024004B212C2404255822420080D1844108F5 +:8032800041801898222240F8FF32008004C12C022C42512440A6242C864402C73440021008409C42882311983211A585147264280125C42842109488244244212081B422448401449012F04CDD50244C544811001001002A1888018885012008548200190811224C14051444841845880400C2421614020000812024C2141A2818C244DFAB +:803300005C0C828601408244024582F4441240924124D02464818512048181008091829012812112A1702304814227224449422832848504C430428422424CA452816141F085331484D041B4183221450130318C814214C528901140912190283046483890844A410880C8491B81534548810C14004091481A7262C5412F1112112651222A +:803380008129684286D82A28E23644A221A285D6617228F322282C127615F3B24416B222C24237842439D279F4162D24291BC82446B44882C2356E46AF48E226B4426221AB2256F622388512E641B1244AF6AA24AF84246E211E536CD41581E6C45544434464A427218F820D5E168F8D989466E2A94811F5C11449F2344115F41955256803 +:8034000086A554946F1C8639AA8E113B6E87D1633C49778815FC822CC14B8A8C0524414ED38B81CFE18459A1CD984E825DC517188885126C9441D1C9F12E2C212904149F11519B526F43A454474547C5ADA84F42A12229761F0146B61662938F8471145824321D232E188F24E3824163542C44C8C22668288D25C502948D48117084B8120F +:8034800021D182A118A7D21E8529F41D452B157E649116B442D42444D6E276422C7CC878683241AF2162841E16C78838412F28B2A837A42887E9CD886F990A8001004A0142800888800998224C299298228D952285214AA51214228691148B28A028A028499121B081021F8802199284288816088C44244A04801488048F5F4E53131F31C0 +:80350000512B39F6C86EBF75F3434B35EA25F383677F3DF55372BF6EFCDA5A3F39F166337F3FFFBA22373BBD2E2F99FBA1A115F198A91F18FAAD3B1F31F56222BFBAFF4B4B2F22FA2AAAAFAFFFE862EF4AFEE6E457DACFE27A26F36A677F5EFAEAEE6F72F3A2B1AE219F8DF7C383BB8875F74A786F26BF72AFAE2BEE6F74B122FF54544F19 +:803580004D4DF2BCE6342B331FF6762BF23B3BAFF5F74B2F3FB4F6436B2FB5F7C33F3F7EF7C3E2BF297BCA7A8AF2CF93DFB9F9BE2677BBBFC9FB9ABBEFCABA6CF6CAF91F18FAACAA6F27F643C33F3DFCB7E7AB91AFA2FACAEAFFAEF6577F3B771F1FF72CAEEFFAFEEEA55F54F6696DCEFB6F56F7C361EFDDF7C3C3BF8EFE4F4FEFC1F12E28 +:80360000962F67EF2AFCE2A46FF6F722FAEFC5F4D4D44F61F1E82F346F64F437773D22BF817348FE3B7FAFA6F67B7AAFA5F12BE23F61F1F3F1BF14F64BCBB734BF3DFC4353EFF6DD3EF29F9E2792EFC1F1F4B89D5826D1ECF872723F34B44AF1CECE3FF3F3BA3B6F6DF762E27FF5F767654F49F53DBD6F68F8E7E66D64FFD6F64A64BF4F1F +:80368000DB5CFE797C3F34B65B771FFA4B5C2FA6B472A267EFCFFF2E4A2F8FFB3EE84F49E92EFFD829346F61F13F773F21F31B3FA7FCFFD3F71A1ABFB3F35A5BBF67FB11123F36F6DB93BFB57D4BF35F437F3EFF2D9FFD2BF5FEBA99FFD3F3DC9A9D4826F12DAF6F61F4D2123F3FFF7636BFF1F1AA2A2F2CF562B27F75F5E3E44F4BF52DFF +:80370000AFE7E6FF62F64745EFCEFED8DCBF47D355FC7A7D3F34F65B78F7B1FF9555EA2F63F66446AFCAFE7E5E2F8FFB3E7C4F4BF9647E97F8C011C011842941E81241186481144081041D4844848504441287440060443048004181180000108454244880442248A14120011A44A448852448046B8120E241322216F44E111A7242128128 +:80378000813622482D1219D422014A11D1220118844200241210182251A2812C3441581285022542180889012B84288B14112544584210628229219838223F8D052CF411248D121F417248F11124EB141D24AF14F18124AB941F88B24A3985AB9443FA4AB143FA4AB5478AADB14F8AD458FB244A1CFA244A8F51F2245A9E252ECA8F59C214 +:80380000DA9E24ACFC91242CFC91248D931F497248F19124A7141FC8F24A111D24AF14B911B24A5985AB944782AF647924B8427924B84AF924484AF9244A8F3C05A41D648F22E14136481D24EB144CB24AF181242F46F9812C2BB45F88B24A3984AF142BF84AB54788A9BB82D44AFB845289D324DC48C2529E24ACFD88243CED49C2CB1F18 +:80388000C8C2DA1F48D624F9916C83F4912423F4812CEB141F41F24A841F81F24AB45D28A96982AF447124A8144782AB9463A2946FA2F12EE30082480000000000280000000021008008800140010080040000000000000000002501BF7B0E1001502818803242822C0134207428041800100400000023049024604A1822281489C1242021 +:8039000022018C21B2480142A622043028208C21F281281033A23016485D2881805114111B8184130480918410047270484432441285240216282411C811424068212C049C0446C8434820082144001A449684875214641F7706312F1C026331484D288032425938141B818511A124898291140024723054244328918C28231438412281BC +:8039800097425262264891482992412218116D4828AA05424C82044A61E245F22844167112F61C3A0000403211818001344082044120084110048480040020011604920020911244813048481810082182210080388120F2DF6A10421406005041004A286814004188C0838A44212804100410080040021844A0282C088144250200400809 +:803A00008421848100828564885F510B4E25331151121042B14211718201462378C2D11418528323184CA2181068C88618420241216D288800A8C082822C21643188A18C2881A482C014216381C8828281B04481082E532424572134004072544141A1848288884C584284884C187212014884240021A4248400200880282A341323186CEA +:803A80002812480064504280988200988398882F75021D641014012111408208137443C24111241D8210A9848882844C9888410044302482408222C186809182400AA1002A088C018D1282848181C04444F0E5BA60C4501484688042820220C48480820200248881800844491544C228200100401802448A321821100824861C02B0416286 +:803B0000C1809142493484F098B68002283504001110A868C04442288F2138882008A08238298108002212006082124827848144123084850110014449210841214604A428C01AAFB6051164842444141218142001212C084224852182024444904400840085128411120400001440140238200118813100880048F0A5B9144E25644D2837 +:803B8000B542440116C1218468B08244028B2186581A0082C3E241024B84A014C42682421884D1829214482512084CC1A1C5521410B811022F88311610B824544A496429E04402D0830880C4414462A01210029848A048A04821802A12220882908444008C01290100004004804918020000981022013048E04448F8E2BF00460C4088146B +:803C000048042F110C0048E06884048024422852862942024140489288240000829088182140081018088018082484301820F8E23114006125240210080021481CB28204208846220400428022A82441211230848384215424002001822181250200001082280440F8ED5440010000000041100400000024002100248120091002248810F9 +:803C8000480280289882000024004440040024F0225A1012134211626422104386C242001121D024028C02490220A22860220028002418460220044810022D82D042140444C82129082D82448841F0247400004110146211244184882480020000811008400841001008830824008048C81800000084004008008301F05A676044508448DC +:803D00005110694469848844020080022C021008C18088481214182A180A4810E8280484008608004C482808400884100821126F86010028144001208204211480880862A1A228A2290686022A8422224262441012E2410448100441004508E4002100424011022924D88C0563388100860214001400460213042120141808812221502207 +:803D800010281808814022280424408A484808444042480460888440065C01AFCD0F22274448A35487400441241454881C022100812502100249818228110422400118848004200148E0A814C88441E8002504448481708202D54E9242231CF2474147284191463842344634422DC23561222514A222842BA283E4427228722282A2882D13 +:803E000022418147A2A7828954288829B4C20D8E8827244C4898828486221804C0484442214608144696185489F8A7DB1415F68145C506444E424D29645D24535418114344222408648F2406212D8848457842C42822235246822427482538844216324224100A44AD8288894CAA84A542022C18B88258C8AC58861AD8143D12FF310C43F6 +:803E800052A428E4B79215149215242F49DC22C28211481F18CCC22A243C228D4A2E28818C52482E822682D468AB268B8128AC0925EAA14194484160888F25B198A1488558E2A1A7A845BC88182658C4855224A318484822F87D4DA024C028412843848281969468880000800888488848A848802481E449822408860486048604862444A8 +:803F00002444A484844A084A18A484418841884994884B41F0E21234777A7776243FA2766A7A61E194F471732B333BFA7F18F18B891D471F28D82134826EE22F2E74AAD88AB4EAF8C8888F8AB848E66CFA6A282B336F67FEF6BCFE943E864F6CFD888ACF88B81EFDD2D26FC8B88438862FACFC96944F49FC84C4CAFC4E84ABCC2B4CAFAC77 +:803F8000FC488E6F4CF4C446E7888FC4FC888CF7C8236C444F48F8C442CF2D0E4762FFF2F422267FF2F66A4F5F52E482F2616335F5C7D43F5AFBEAEA3F38FE838329B622EA2CFCE242AF8AE2AAFEEAAAAF86F268688FA5F7C2A6AF8EB352F7D4666FCEE26EF8BA8E9FBC7D84FE8C8B6FADFDD6D6674C4B886B8C4F6CFC56D49ED2AF28B4E1 +:80400000C27CCCDECAD8A8F86AEAC7AC2BA84D86EFAC7C8EDACAD8EDF8C68EEF8CA854DEC4EF444DF347673D47BFF2526FAD2E7D47EFB6F64B432F44F497C43F47F62B291F14B6C1F8C1C2272C2F22BA227868F8CAC8AD48A5F848488F8A8BF628AA2F27F62636AFEAB6A6F874624F787988FA888C2F84F5D4D62F28F4828625F2868EAF68 +:804080002DFD929227246F4CB882D4CAD882F84AA88E4A25D22658E2AFACD48ED886D8C6F48A885AF584127FEF44F1C567F557DBFF76F24A2F7774E5FA7B733F56F6D7C63B4DAFACFC43433F3CB8E2BC62FAC2C22BC687868FA6F6AAE8AF8AFA28288FACDF22F63AAA2B234F66F72E6E6F2BF97EC28FB859E69FE8B852ED2DD966F4828688 +:8041000023E82CFC16966F69794AF2C6842C5C8A8FACF44A288DCA676A2F6CF4CA4EAD8AE57888FE8248A5F89494CED6BF8D0326011440022623412161124002244800240000002128299128291108810021100225424842088200248224822482200882003FF90A24442415044C1444484244128128482142024018088141001004002DA2 +:8041800012400858000012008D821008A908008110082184009F780D2CF41124C5F21124C7141FC1324A1D24EB141D24AF249921AB9451AF1439A4AF5439A42F7479A4F842914F8AE454F9A44A4EA14FA27458F1244AD6E1A2645D2D4A9E24ACF491242CF4912485F2912C83F49164A3F48164AF24D141F64A921D68AB9459B44AB924B4A1 +:804200004AB924F442924782A9F9244889F9244A7F480FA41F45F22C421E28C3F61128A3F41124E3B211D642D8C1B6489B64AB9443FA4A154B4A2F54F3A4481C73A6C8356FA8D118F3248A8D814F2261182E189E25B49E21ACF49128ACB49146F29128811B29A11B28A991214CD981D2489B25A93924A939242B9447828B946B438B846F3B +:80428000AAF55C724028880400000000A028000000002180018800004001008004000000400428000000002501BFB70D82001110114201248810082502218008005048211002009800804806000000000000000000888440F29FC5008200000082190211004A08002141000000C02600210010028810028200880000200494200118402140 +:80430000D1984C01C608144003144012142102290A2124104402301A218230244082180124812442240000200841200200850112C0928114216FFD0D00000000821982088160240080080010042440022001008241820020080000002004000000007F6B01000000421048840121000010020014000000000000400444290840240429018E +:80438000210000100200007F6107100114001004002880241884089840048281400222144218008441120000800100200242211022020000844FA60410011100424481410021801824082B1800908184002122114812004084410464880044002110C242002110020040F81339000000000020810248000000410000000000008400000011 +:804400008001482021020000220000002F650700000000000000293188002100000000000000000000000000C048000000424800005FA307201208218121250800811011218454422A2408280080020040544221000028404481D84202200200008018140880013F3D060000000010E222040000001008008A0200400100000000000000B8 +:804480000010080000000000EFE206008110121812480268214031138608412A94888002A8000011000000002200118228009048840000884914088001476E002800002400008400806424100200002002004054260000001004244400220000000048000027DE00000014008400000000000000000000000080080000009028200200C092 +:804500002800180000F063DF000000000000000000000000000000000000000000000000000000000000FFE40F000000002400000000000000000000000000400200000000000000000010081F4406000000000000000000000000000000000000100200000000000000000000CFDC09000000002400000000000000000000000000000006 +:8045800000000000000000000081F063C50000840000000000000040020041000000000000000000000000000080020000DBC40000001008000000484004000000000000000000120040080000000000800100004F54030000000000000000000000000000000000000000000000000000000000F04FFE0000000000440000000000000054 +:804600000000000000000000000000000000000000F0634900000000000000000000000000400220018200000000000000000000000000F0EF63000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000210000000000000000000000004759000000400840040080B8 +:804680000441001002400400218001820000120000000000000000280000E0280E00400800000000000000000000000000001002000084000000000000180000F09536000000000000000000000000000000000000000000000000000000000000FFE40F000000004005008004440010024004002180018828100218800884000080420853 +:804700000000280000B014010014000048405588281082044480022100448002214818808802214818448828842148408481421882041E148002211A01445C03000040010080041400000000000000000000002800008008000000288400000000BF7405000000004005008004440010024004002180018828908280018840080000288492 +:804780000000800200003F6A0C0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0021001400004800800221000028000000280048000000484004281082044400108204440010F2448D0000000000000000000000000060 +:804800000000000000000000000000000000000000FFE40F00000000000014000000000000000000800200000080080080020084000000002F3A0A0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000008002000000000000280000000000004F7D0200000000000014E6 +:494880000000000000000000000000000000880000000084000000009FA3F7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 +:00000001FF diff --git a/kernel/xpp/firmwares/FPGA_FXS.hex b/kernel/xpp/firmwares/FPGA_FXS.hex new file mode 100644 index 0000000..1321a53 --- /dev/null +++ b/kernel/xpp/firmwares/FPGA_FXS.hex @@ -0,0 +1,648 @@ +# +# $Id: FPGA_1131.hex 5122 2007-12-12 10:07:59Z dima $ +# +:020000040000FA +:80000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AD6FF4000F8030A006AD6FF4000F8030A006AD6FF4000F8030A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4455544455557475577775577675577775577765566665563625523235D2E37C2B5111155111155111155111BF +:80008000155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111000000000000000000000000000000000000002552222552222552220025522225522200000000001AA1111AA1110025522200000000001AA1110000000000000000000000002552222552222F21F11211 +:80010000122F21F112122552222552222552222552220000001AA111255222255222255222255222255222255222255222255222255222255222000000002F21F112122F21F1121200002552222552221AA1111AA1112552222F21F1121200001AA1112F21F112121AA111002F21F112122F21F112121AA111002552222552220000000087 +:800180000025522200001AA1111AA111255222255222000000000025522200005F51F115151F1AFAA1A1000000000000000000000000001AA1111AA11100000000000000000000000000002552220000000025522225522200002552222552222552222552222552222552222552222552222552220025522200000000004AA4444AA44402 +:80020000000000004F44F444445F55F555551F11F111114F44F4444400004AA4444AA4440000004AA4442F24F442422F24F44242000000004554446F61F116162F21F11212000000CAACCC2F2DFDD2D22F21F112124F48F884846F61F116164554444AA4446F65F556566F61F116166F61F116164554446F65F556566F65F556566F65F559 +:80028000565600000000002F21F112122F21F112120000004F4CFCC4C46F6DFDD6D62F21F112128AA8882F21F11212004F44F444446F65F556562F21F112122F21F11212006F65F556563553336F6DFDD6D6006F65F556566F65F5565600000000CAACCC2F2CFCC2C2255222000000CFCCFCCCCCCFCCFCCCCC008F8CFCC8C8255222004FD0 +:800300004CFCC4C44F4CFCC4C40000004F4CFCC4C44F4CFCC4C44F4CFCC4C400000000CFC4F44C4CCFC4F44C4C000000008F8CFCC8C8AFACFCCACA255222CFCCFCCCCCC55CCCC55CCC4AA444EFE4F44E4EE55EEEC55CCCC55CCCEFE4F44E4EEFE4F44E4EEFE4F44E4E00000000CFC8F88C8CCFC8F88C8C000000008F8CFCC8C8AFACFCCAE0 +:80038000CA255222CFC8F88C8CC55CCCC55CCCCAACCCEFECFCCECEE55EEEC55CCCC55CCCEFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F88C8CCFC8F88C8C000000008F8CFCC8C8AFACFCCACA255222CFC8F88C8CC55CCCC55CCCCAACCCEFECFCCECEE55EEEC55CCCC55CCCEFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F85E +:800400008C8CCFCBFBBCBC3AA3330000008F8CFCC8C8AFADFDDADA2F21F11212CFC8F88C8CCFC3F33C3CC55CCCCAACCCEFEDFDDEDEEFE1F11E1ECFC1F11C1CC55CCC455444BFB7F77B7B00EFEDFDDEDEEFEDFDDEDEEFEDFDDEDE000000008AA8889AA9991AA111000000CFCCFCCCCCEFEEFEEEEE2F22F222228AA8883AA33300CFCCFCCC28 +:80048000CCEFECFCCECE2552220000EFECFCCECEEFECFCCECEEFECFCCECE000000004AA4441F14F44141155111000000CFCCFCCCCCFFFFFFFFFF3F33F333334AA44415511100CFCCFCCCCCFFFFFFFFFF3F33F3333315511100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000008F84F448489F95F559591F11F11111000000CFCCFCCCCCFF9B +:80050000FEFEEFEF3F32F223238F84F448489F91F119198558884F4CFCC4C4FFFEFEEFEFBFB2F22B2B955999855888FFFEFEEFEFFFFEFEEFEFFFFEFEEFEF00000000CFC4F44C4CFFF4F44F4F3553330000008F8CFCC8C8BFBFFFFBFB3F33F33333CFC4F44C4CF55FFFC55CCCCAACCCFFFFFFFFFFFFF3F33F3FF55FFFC55CCCFFFFFFFFFF03 +:80058000FFFFFFFFFFFFFFFFFFFF000000004554444F42F224242AA2220000008F8CFCC8C8BFBFFFFBFB3F33F333334554444F42F224244554448F8CFCC8C8FFFFFFFFFF7F73F337374554444AA44435533300455444FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004AA4446AA6662AA222000000CFCCFCCCCCFFFFFFFFFF3F33F33333ED +:800600004AA4442AA22200CFCCFCCCCCFFFFFFFFFF3F33F333332AA22200FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000CFC4F44C4CCFC6F66C6C2AA2220000008F8CFCC8C8BFBFFFFBFB3F33F33333CFC4F44C4CCFC2F22C2CC55CCCCAACCCFFFFFFFFFFFFF3F33F3FCFC2F22C2CC55CCCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000F1 +:80068000004F48F884846F68F886862552220000008F8CFCC8C8BFBFFFFBFB3F33F333334F48F88484255222008F8CFCC8C8BFBFFFFBFB3F33F333330000BFBFFFFBFBBFBFFFFBFBBFBFFFFBFB000000008AA8882F28F88282255222000000CFCCFCCCCCDFDFFFFDFD1F13F331314F48F88484255222008F8CFCC8C89F9FFFF9F91F13F35E +:80070000313100009F9FFFF9F99F9FFFF9F99F9FFFF9F9000000004F48F884846F68F88686255222000000CFCCFCCCCCFFFFFFFFFF3F33F333334F48F884846556664554448F8CFCC8C8FFFFFFFFFF7F73F337374F4FFFF4F4BFB2F22B2B00455444455444FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F44F444447F74F4474735530B +:8007800033000000CFC8F88C8CDFDBFBBDBD1F13F331314F44F444447F71F117174554448F88F88888DFDAFAADAD5F52F22525455444455444DFDAFAADADDFDAFAADADDFDAFAADAD000000004F44F444445F54F44545155111000000CFCCFCCCCCEFEFFFFEFE2F23F332324F44F444441F11F1111100CFCCFCCCCCCFCEFEECEC2AA222002A +:8008000000CFCEFEECECCFCEFEECECCFCEFEECEC000000004F44F444445F57F775751F13F33131000000CFCCFCCCCCFFFCFCCFCF3553334F44F444441F17F771714AA444CFC8F88C8CDFDCFCCDCD1F14F441414AA4444AA444DFDCFCCDCDDFDCFCCDCDDFDCFCCDCD000000004F44F444445F57F775751F13F33131000000CFCCFCCCCCDFF0 +:80088000DDFDDDDD1F11F111114F44F444441F17F771714AA444CFC8F88C8CDFDDFDDDDD1F15F551515AA5554AA444DFDDFDDDDDDFDDFDDDDDDFDDFDDDDD0000000000000000000000000000000000001F19F99191DFDBFBBDBD00008001000000000000000000000000004001000000000000000000000000DF8D0748000000000000000E +:8009000000000000000000000000000000000080020000000000F01B24000000000000000000000000000000000000000000000000000000000000FFE40F48008001000000000000000000000000004001000000000080020000000000F089A2000000000000000000000000000000000000000000000000000000000000FFE40F28000013 +:8009800014000048400128004840012800000028004800001082040000800400002148000010F2BA5E000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE80840180020000001002000010024001002100140000001480028E +:800A00000040818802000088280000F04CBE0000481800000012000000000000002001000014000000000000008002000000003F84054818148002800414182810820416012810A21140012810A2414001002B11484001280048408188022148008828108204F05C65808401800200000010020000100240010021001400000014800200F6 +:800A800040818802000088280000F04CBE000000000000000000000000000000000000000000000000000000000000FFE40F0000280000000021000000000000100280010000400100004081080000000000002F6D020000000000000000004002001100800100000000002200000000000082280000F0293D000000000000000000000095 +:800B000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000110000000000000000000000000000000000F0726D0000000000000000000000000000000000000011000000110000008088020000AFED030000000000009B +:800B80000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000230120010000008002000088000000000000F036AD00002002000000100200001002000000000000000000000000000000000000F0DB150000000040020000000000000000000000000000002002000014000000800842F03E +:800C00003C89000012000040020020C41212000000000000000000000000100100000000000000F07CB2000018000000210000901200000000000000000000000040010040010000008880045F960900000000100200208401000000000000000000000000280000000000000000E03A0F8001000000000000000000000000000000000034 +:800C8000000000280000400100002008F0C63F000000000000000000000000000000000000000000000000000000000000FFE40F000000000000200800000000000000000000000000000020040000000000B0440A001800000000000000820042000000001200008002290100002200000000008800008FF30A0000000000000000000062 +:800D00004200000000120000800200000000000000000000009F3901001800000000008200200800000000000000000029010000220048000000200800E0980D000000002240020030110020080020040000100200002100000000000000000000E0DA0B00188001002C0800000000000000000000000048A2000080022004480000000033 +:800D80004200F09C7F0020010000880000001800000000420000400200800A000022000042000000004800F09B5200002001002C02240000110080080000000000002004240000002004000000000000F06BB7800380220100001122230280081282249082C0110080140200800800200180082824002800008004005022EFA80E800200CB +:800E0000000080013A0812308200002180018001882011012002488880040000002848000000240070A40A0000001828000000800110A1280018480048808401A021004800880022000028000000000020F4653A80830200000010C1221A0812988218822221202104206524C21812802188220488884280024002220000004200002CF42B +:800E8000FE550000281880810280010000214021088210018888000080020000120088200200800400000000F0A33220822102000000000000280000214200880038220022003440A21200002268800400220000004248FF110B000000281C02291882188288031880111222082722242C8128822428250C82200882460128240000008043 +:800F0000020024808404F04D86000028002800A8000028222082288204100212180048000022800220080000800648224200808204007FD60C800212000010828182810218003082188821118E528028010012000012122001000000800200220000009FFF0FA021282001000016021200201201008004114213042A8484A428284081420E +:800F8000828A82220442800414000022002022041CD45D0F00000000800118800200002C020080210882110000001002000000280080020000002004AF420822112002001114001988C22182800114400121121800428098114820081B841B1211002286C28182002082022840022200002F520D0018800180021825820100180088884278 +:80100000001002A0810020030022303220238488060000004228008002006FFF0B00481C01001001400228802A8808800839188109982800001420018084018200210024E01412420200100221147FCD079011181382010024A21AA1883A21888201E031288A1462342C02211AA123484AAA113A2A82081BCA211BAB2B42B22830418262BF +:801080000020848284022180021442F7E4000038002A12011E92242B1110A182128814C0A223A48830122D415848988044A1140011303129418121A4888A02001B462111A0268002224A04006FAA062AA2232A222101E0125211212117222120A12A3AA32882211E81805C118E829A58128AE41623A8448A842228C3232C031A83A24A242A +:801100002934226800224823022302242823A2444A84F4E6DF0022A012000080082C08888022011180048A0419041828208821088214822B128218A08660246024601420042800C0220020E4A8012817111AF311218880F2212115B312B892F191119AD9112828AA8A171815F122A23F14A4CC1F14EC2CF842428215A1C61F1EACC41F1594 +:80118000AC6EAA8AE811F9C1411F19A22ABAAAC84AA4C43F1EEE2AFE42622B441F347443F141432B444E422124212382A44448F08DC580F251611AD11187012AF2212115F392122B993F31B912DB1128A8299A798141F222A23F1C9C421F14E42CFD42432BC41F11A1921F1C24FCC1D11F16AF2A86A1991F36FCE2D22AAB72EAADE64AF813 +:801200006161EEE22F2436421F34F443611F3494426E6229421292224E622B444829F4459980F231511AF31121002AF2212115F292122F21F111831A7B8181A81AAAF981811D832F22FA63612BC81F14EC28F98383297811A147171A8217116EE1A2821B111F14FC13612B82BAAAA8CAE62CF8E1E32BAA6A26E424D413F241432B446E42B2 +:801280002342522226B242B4428424F4F52D80F231713AF171311A092AF2212115F312922B193F39B112718181A82BBAA9881D832F22FAE3E18AF8C1C1CE823F3C1CF21111AAD31182F81191BE712A92811F11F9E1632F2BA73B7AA3DBEAEE28F863632BEA6A064E4237141F3494426E62294252222E222B662B442CA444860D0000002215 +:80130000402201922008000000002004422084282402888008260100000000000000004200D0AE0522122A0118004022480200208102248002001002182800980060221288A01200A08228000000280080024214EF14042AB41122B211A2141B212394212B1619F2629219B24239112B94322F142BF342B1322D912AC4912E421CEA2264A2 +:80138000112F22E519E222E519C2529AE222B4D1E222B491D222B191F262111B2923B481324219B26298212B84112B84222BA4222BA42229AA424AE822F4D42580B411C4411361141B212394212F1491212B9419F242B1112F1429FA428113B84238A129B8A384F1A152881B4A881D42821F2224C9439E212C244DB39186A4294631112F9C +:8014000024A828273419E224082F340A2F34082F24082F242892822B42296822BF6C0D2088040000240000000000000000800800000000800400000000000000000021F05EA100008082522248002400003200822800000021112001246A0828008002002200004200000028A04240F1A17E009200000020040024000040A22122824A0214 +:80148000422081A1241901202428840180A428488820880400004280040014F0E43F00D200C02280044210224202180082266223228272602C00186A11512120842824054848A848888088042A040042808442A224002BAF00002002240000000022000000000090110012A02C8002002800800200000000000000F0EC580000A01200123E +:80150000000000003081000000000028190818008008001800008A0240010000002820049FD608288002001800881200820022002100000018160200006A0138A012800228200820220400000000008FEC042880021A021200880000002814000000000022142001002880031A020082009041000000200248F0DBF8000000001200180082 +:8015800082008048020000001816028800A043800900002200A280020000000000D0710522002081082800002280018001002180010062409221200100001200820024282228140000002200F088A88001A02180010000A0820022822800212928C1130012240010012391218024080000000028002200001002F0D7FC000000824002009E +:8016000020010000922872000000008001000020012008280000000000000000AF67031A028001002221002001208208822223031824001268001B1200121902001880280800292202142002000000F078ED000028181200000088800120830142821001884002240012210080090080020000000000800200BF310CA0210000802202000A +:801680002430228880582200000023010029088800822225F1228100118828220028000020020000F0E21D8002148082C211180000181218111800004002423031824A081A08208482A1A40080080040410111004848200200F09EA900002004001828122C0121221022012522818101248260292C0100880040028288001012021002217A +:8017000021002110120270E20F00122820218101820080022A01221200822D8224822602001081A92428E01C028002484081C86300480024002A0400004FC10D1100800400281882882812002280810100122001009211008800A03823884142022824404202404202400200224E148002002001002001800A0000001002182813240214A8 +:8017800000000025011C0200248082621248281100000000E03107A012001902001440011CC1221120410114234491428813082A193182004282484248A2000012111411114228482280242434420000BF9A0920880120020088200100000018120000001800000082880000140000004021020028004001573B00800488000022800828E2 +:80180000802202204222911282291181081941A181E01421AA2414800486810848002C8444C16211002C02190410022FDF0928BA2221A2282AA2113A2122182121422251211286021400A0811C9821122C3812868181A8844AA64CAE61489AA882863181401331221D216E42141512512260222B262D431042013FB9062282002AA4111419 +:801880003011B8E02889B112B8232208141AF1321258988A04272C2A9132B234121F1908BAA48A224AD832C823821A481112A228172427241C3222230410B2428684120214F0DE5D1081C1113041008022A291701182012AA3323824701262111E122728B012F821411CA19C39089A0480DA21B1A1322219024AA8811B4223C22110A144CE +:801900001CF42221A04400420020F2443110A1121130812A110111221130112C081C0A1C083C8844A141142984820529044800122212271212141223044A088004000080020000F0DCA41415D1111151111F14F45161111F11F111111F13A99117181D9129F183911B821B998217183F1AFAD3D14AD411F1C1C3CE821326E126EE25F151B2 +:801980009115A144A0391E11172917321F3BFBB2B1CA54312F21DD22F423233F16F66163212F34F442423512E224F46242251202002E22CFCD06281F173611486AF45171111AA1311F11F39191988AFB81912B981B821B9B17181718BEB29AF983811F1DFDC1D3CAB8E1A8657E621F15F951111F11F151D1C29E911F1FE71DFED3F11F38EC +:801A0000FAB2B1DAFD515329FC81C33F1EDE11F261632B222F14E62414024AE426F462422F24542221A0223FB904221B531601881B671E111AA1312AFA1191921ABB82F88381AE21A81D81B022B312F113114AC5121DC31F12FA51512E321E5217181B55145AA5EC6E311D321F22E63AF2B3311E122BC41F197941F323232F36F663613F9E +:801A800012F643611D433553222B446E6229820421A022CF1A031D211B6316217421B1714781D111F311319A89F981931F31B112E11BA1931A59113F32B352051F11E124F483C13F12FA11217E623F19F512111F156518DABDC1FC61714E733F28E63BFBA3A14E422B911F187841F363633F32F263613F12F243411F34543325B242E42203 +:801B0000F462422F241412022AF2E348004001144001144021492149210982308142121001208401192884099880092A08001C0926814401800400480000002F5F0A26210120A24120212288012011228122812191120082108292111229410120022A082D11122C0800008002000022000040F1B17EA0421B212AB11122B611B262912115 +:801B80002B1619F242921B212F2419F14292222F342BF242B3222D913AC4912E421CF822421E212F2265192F2264192E429AE222B491E222B49152321B29421B2923B681324219B24298212B84112B84222B84222BA42229AA42882E4247B4809461481B2142133142112B14112B8419A2B4114A39212B94112B84222D913B424AA1124E99 +:801C0000811D82122A6C1C2662193C641D24D2349AC4419A42B191562219662419C282684EA3E03428E22428C2822A84B82294822CF48A29008248008001000000000000000000880000000000480000000000000000001002AF1B0A0000002001822081018800002882280000000018800100322822A0282002000000000000426012AF49 +:801C8000950960188082C1A2182822225A088214001260212412200129181211022C91A1800A820010120280280228008642822402142C880214F0BD6300C6012280022A81A28292204A2108128061221E82221212248211009083111A08882007230228800A8002222424422810C182244200BF7A0800001888290100421218000040023A +:801D0000004082081002181A022800002210220820020020080000800220F239E740010000206122820088008081041A040000001502210080010025011400000000820000002800481C012800808204421200182088888102822C0A2028021122800928802A82080082239822804802482100200888208804005F1A082800800220C43228 +:801D800082000082181820A8580000002214160200802108241182133822800880042008000088280048CFFB051100004280010012888200224280120288224001248220028A22020040020040021002008880088004008FFF0F000000002583A11200821800281824108282810280222891211142212200804202000048000022888840E9 +:801E0000821802F0AE48A0140020040000602200200220089082C01288200100108141022820018001100100000000001002245D5900000000200488004800140020040000110020012200980000000000220000000000002B9680040042008094123A682280842112810224800824882021820819022E429022382081422201400142226C +:801E80000000880024820024BFED0E1848000000250100200800800942800228881400181220018008000000000000200282000000CF9D0B402162140080220400004800202228110225020040020024001800202124021001008008002C0200007D33009041000000CA02282008222148250220880180918124001126621824288092A1B6 +:801F00001A1222938128A082190A11881120220282A800288F4203002004008001182110018005D02222083022E029022112241200005021502348141001002240012200002400F0DE1900001218122480022800101162225AA218003083D0210112008824E01102182121000014808848118108000088220021F079F50011281100281823 +:801F8000422B16200200180020A212821818222222860212221212282128002800800280028088082260224002009FD2071240010020022001400120018800100129010020021C421101120080210224288028C88240810888C0820021B08C040020410200008008004682248A8281681121141824001002108289012122601A004001009F +:8020000011240000002A0800EBF700002820012021010040222182311200000033088011A11280222802228001000028A0280020022820024021F21B4E200148800100288002C02213240600001123289211902100502388863111001429042601001C0A0090228088888848011012F265C92051112214009032128AA51128002D42187A40 +:80208000E1212ABA82A1911D111F2119029022D0223112381F2132122531223022222429E2128468121C42312182118200A82824142440015FCF0A00B051032901226A27A1222908171815B17284249412260220885231A6420212221622A2129E822C61212429F812118E51181100AA88E8122A48E118A8A8008828824081F28ADF8001AA +:802100001D21481A218102B062022200422C92222B521EA228A22B88143633223BB11F1261287081722391828A9A311A82D311C2212A3231282681B2A388E218023C9882312222AAA82A2B8A2BA2213022CF8F0D0000001002290829082908240012000010020020180200200813883181308110011110010000822400008F6F0912D01177 +:80218000F211611E822B11E023F352722BF79AEB2AFA82823D8119E822A3574AA49888F081811F18F821213551213593829AF9B1B317181E922B88AAA2AA8A98812EA33F3B38431B8C86F181233BA21B2226F121211592832F18A8228240F2A281AA0820F2C911A0114E4115F13171821E1225F212122B777EF22F2BFB22222F22D213F85E +:8022000041A12B332F27F7C2922B982BB3213F19F981811D131573A1523327282B111F3371A1E332BA82EA2BFAA2A22BAA1BE62EA39EC3FEA11F1C38818EA32F18D21192811CE212F283813BA8828AAAA28EA223AA8A002B222DA5A01119D411D21152312B111E122F23B372A77E3EB22F229222173837182F23B372632529A1AA3ADB13BC +:80228000F811111F3253221F223823241AF1212333F82283AE82AE2221E01276817212F3C2F16A9E8186D312AA22112E213CB283F882812A22A82270A231822120F269D9A0111D4115F171311F11E121B132A3223E722B7F3AABAA281738371A2B332B373E122B98BAAB911F19B911F921231F32F221823552221AF1B193172A2EA2BEB266 +:80230000BE222B232E222E611F2AF2F2A23B751BE61CE828B883B221EA18A82219FA83813B8AAAA2882AE2227A22B2A20220F22EF100601240022E120000400224122492200913091128212800213022B022012B82A082A092A0820020220800822880220800F03C62801121224121A112C012682E12000048382AC42290328009282410B1 +:802380002221021882888001250280048280820800880082200200F0868D80B411021B21421B212394212B141B282B941B282B9413F84293222F1429F34291222D912AC4912E421CF8224216E12265192EC296D122AC292CB491C2421B29341B294E111B292F14B181724291212F1498212F1418F14281222B84A22B842229A842882E420A +:80240000FF2E07481B61B01126B411324219B242B181B242B181B242A3282F1421E21429F24291222D912B421CA9521CB8218CE82264111F222CC1C39E212CB491C2421B693CB49162141B2827341B284691212F1498212F349A212F1428B2422872422282B82294822E422FCA078282000000000080020000000000800800001400004838 +:802480000000000000280000000025012F240C182800423342012448420000002001004002009042001888120080213912186024280000000000200420B2490D228A8111814882A14280C23142400210018224A0242042C22280029032888058121214882712196C120024242248402198212C02828882194201BFFB0612CA03A0482C2297 +:8025000021022B24284222240011204942A2242011A2282128002B211282142521611460191CC5116024220042221488190200E024C82114226FAA032280114112418104E01401000000000020022140220480089800C092282988024002230200002C0288820000BFF10700000022200400000088482880020010010000218088028001CF +:802580000024200210810800002C020000DFA80E48808202301218C082822118253281422022080080280821809622380022184022225212122322080021240023082008682022F241D68004282240A22112428288212C411221044A220222000011218012220120A821002828212C012928021041028008801A8202006F560D0000000015 +:802600000021008008888008002088080048282602200200230114200200242008240000200422223EE500002800000082200321888642221802292881188212018001008214002100004880042008000000212422F0F928800100800200001C2202200240012121002A0182320010010000482094120000000024280080042602F04685AC +:8026800000000000000010928200001200000000000042100224001002008800000000002800003D6980012002000020D8214202A08282256228100212882042810118003082110021202401428848000020020022212200EFC70A8084048002000080211802001C0120082428802802004800400200250200000088400200800480025FE7 +:80270000870B20044280B21104008221822008820000004022038008882488248880081C0829088830422410120200000000F0E6FC0000001821182110012A219812880029011812002188282240820420021840022A110120042A8404008004290400003F4C0E20812405002200212C02204202000022122902C0822400808202800218A6 +:802780002800808202820000220020221202F0D8B60028000000122811002800220010221102402204A082100218284E822800A82848002280820400302200200222FFBB021822208312322128200A2100004221122188A092242C28B222012382020040021128241002001002100200000000227F9C01A04158206112806421200112308F +:80280000120020025A0221000080040028281302288002288082A868102204212228282002C022F071DA0000001223850116012C0929031218128011A228230448002290122280040000001AA41A4248A0A44820044200280010023FC9041282003821800400000010412214022022080023281212020024220021002180020000000000D6 +:80288000424021E4BF0F228004002280022112802202200112101212820188000098144A182204C800802604002290614880042A44012221F0221D00B2A0352821722A26E2221131122124A0184A512246129282882E12282CD422B222C4222AC2222128E022C6226811A82722A228F2222A02A823842424242214A246146240011FC20187 +:8029000032CA24812412D113A2111063282C29A918234B22AA11212C6123184890822AC122882DC2126A8881AC81882B1A29488248F2328129A6842C84F422422A62242914022A840200296212F0E61A808103E021E1238365241A81DA12218213820314A01312583AA2A127288028312230A224882B223023422A22C12138428026ACA671 +:80298000C22C0411A0246022282A0222242AF6BC740000002603228028C18280088822204A8284A248B0828482A42148924892201922099220C81282002400400200001448800497DCA0225A032A062E113160212D232B998AB892C9822B999AF1F1732F2BBAD24DA2FF7AA5994AB4C2E42CF532126E422F2DED2DBD92AD495AED21FBF18C +:802A0000F1121F11E921F9928229F1E2E2AAA846EABEC25E222D2223F44343A0442E222F2616A2662AA6666A9622DFC40E3AA2711AA1231AD21293633A62213F38BA82B812B112E321B992A92A1F3DF5B2B22BFF2B332B992B137AE5256528AEB22F25F562C227222F22B292FDB1616AEE36FEF1F3BAF841C12CF892C22BDC2D222AA2EE1C +:802A80004AB4427622F222222B663F34A4646AE622F26262216E612E622B666AA622AFEB012AA273A0231E323E233B23183AE3385A222C91329AA1911AF951D32B337AD722B1A2BB32A3FD2CF982822EA22F26F432322D2221D24E916A66283F17B6E2FF2161863212AAF97272624AA4AC2F24D622D222B242F64343A0444AA4464AA444A5 +:802B00006A3242A0663F14082AA233A0331AF313313F11A3333E323F31B392B982D922F192122B91881F37FF12122B552B322BDC32BAE924ED2CEC235A222F2FF562422F2979D2F262B16AF6F1521F3FAE741D61BE322F2DF862522F23B3D2AFEC4AF642622B2429F242623F34B462A4664E422F26B642A6666A32422AA266BDB900008081 +:802B800001184002240000402201A024200442214229219412422200A01220022A8124022248800448002800800242D0CF07AAA121182002211A220221009012122812292311A24218002220022E12282A012E128001183042000000280020420228202402F0EC4980B411021B2166B211726292212B141B282F26B981B24239812F242989 +:802C0000FA4291222F3429D212A9421CEB22C4A12F22E411E222E419E2226C192CAC292DC21B292DC21B292D821B294E811B292F14B881B24298212B8419B24218B14228B24228B2422892822A84E822F4994D80B4118634114212259161421B282B8413B8423A812B8413AA84AAF44211AAC4812B4A1C89C5812C6D112EC2D6E122681CAB +:802C80001CE81CC282DAC2838AC6C39AE234A8281CB881F642821B284692212F248AC2812A94822A94822A94822B42882E4237D2008004000000002008000000008001880000000000480000000000280000000025017F5D09820018800116420112120088A08480250800001002004262000000292808808408000024240000280070C247 +:802D000008202A014082016012A04288122124221D22199831302190212128800224801102232212222A52212218200225222208002200288661141C64268FDC01200418C012002113022222248224A22C82854982021A12E22802A8002314110221304210022220240821222200242800C082144681F26F8D0028180080214101181A8443 +:802D800028012014C18113021110010000002A058022022AA8283C08182002248008240000221C82042CF4F89920028042021C813222122001200428121C32312100002400A092901200402209008008200800400100002800F059FA00262101A0522839016602483011C011C0A2004820023121301200322830724818F0128125E21108E9 +:802E00001E21888A02400200004268284800482F1D0C2828124082671139818217A241601142192182691218210050210018A02926A221301242182123113292601B88A20000400100228006006FD40D4001280028282100000000222113820428244002210012002A0420C9814001002008100200208484020042DFAE4A011480020024B8 +:802E800013018021228421020028191982C142183011248800803642C042200142000020840280048008882100F08613200142200500108201220088008E110021208801802202282008221200219012400242400129022200001002428EC5000014000048000040010000800400001280810140028001182008800C000000480028000029 +:802F0000AFEF064001281A040027212001200422001B18281C01184A084081818A81032446228294121229819492002304200220848284082E820080E4D906188014010060140012001C2108008088042480A881260200A02C0018484800008088241441020000000040F2D19B141130211860221890113021181200140027112601C8C074 +:802F800082281382B221844221210420052008341E212230832115021431140021A0240000DF6B0D120028001418408101288228001308201442E11481288108881A8888810811208C048810410114C02200000021002280F489126011141400400100271822805122101101183192882214C0111414100100884812909100188219288828 +:803000000224482088240400422228CF650DA02520041601199242284200281824122A0120011288C082882412484082438252212882282E8286022880D2239841422420823822420000F0DF2D0013011418338803286602008012110226110314601421141C014601484A6224D02182E22184811701131281122108111114202A02800212 +:8030800040D14B09228082218201128081821102202101182001122220282229220100180000000028000000000080222412022F1704001A840210124122288868212880080024C280148282218482288868288228428880021226020024402244023042200A2908001F8944218224012A1102C052200124181012414202111C04601800C6 +:803100008A810519042C82C212112C8A82841221018002142004222024022842005F2A01808204800228C011A0828032521230222001122F34082C81820880042A68114A918222211A94811818488222C82228822880880242C0421022F22988F01121F011113228371311321C353135A11229011AC311211F12B212C111984AE814B5425E +:80318000B82108211F1428088A85C1623AF2921213E428A22A19C4811AB212417181C2211B223CD23214022224422A2A82246212428DD320C251B04122031C92214E22292888C822232816D2310117322135F181111B881D4186B1B2C941BAB2128558112EC2AA081F166C3A2B921A21A22915D211F281822E811F226C184288171421A86F +:803200008A8606482B824A0424CB1814181B272A82C1122CB312C113124E333AAF29121E1225F21182128E12F011225AB4126421AE3229D211B23183F161A11B5D4AA82C2B112D522829A24529E81DFB21122F1229A62228822D823332412C5411822B8627224A84E22482022AF2CAFD140020023440214101228088C4828008880080027F +:803280002880028001214229012100C0122004460224400200240000004E2814387AA2111F11A1223B333B323E217AF733332BCCCE422B8127282B1929B191B9A3B2A2D222F1939119AD991F29FA82832F18A111988AFD91D11F18E92EEB27E72FEE28EC33E72EAA2A8E819E923D222F14B6A1EA1AFE21E2AEA11F14A6CC2C54122EA22B5E +:80330000EE4AA2AA2E222BEA4A0424BFC2041B221F16B231F131712AF33133E012E221F1B3B23BCE6EF22F297B8232822B993F19B9B27382F212123BD92BD9DAED38FBA2832B225AB7F1AFF51F1DFD81511F3CA911BEB3CAEC2DADDCAAABD9BEB23F21B251B681BA81FCA1C21BEE1D212BEE2B4429E228B8C2BE42B4A2EA22F2E2C22B44D9 +:8033800040B24748A1321F12F611311F11A3313B333B321F13F231323F3ABA82EA28F312B22D822B452F29A9112EA33F33F392923B512F1DFD91D1EEF32F38B821F871511F17F521511F19BD91E93FEF2FEF2FFFF1D31F2FEF2BAFAB1BA81F31F1A3B23B881BEE1BAA3F2EBAA3B841E61CFE4143312E222F26E624A4AA6E222BCC2B66E02C +:8034000022F24677141F13F321611B131F17A3323F33F333311F12F221323F3BFAA3812EB22F29D922B842F412122B991F33FB33332F29F913511F1DFD91D1EEE3273A1F12F25171FE711F14F3D1D11BD9FED32B993F2FFFD3D13F3DBDB2BDB27AD1F191133F2BBB93BA41BE81F8C3823BCC1D21CEE23F34742341F242422F24B4A2EA26E4 +:80348000B2E2BC42042E22AF1A0A2A01001800402109400230112412241242822008214218421880088842888008002A0124000048002448004A0228B04C0F14111428A021271212628A5212281880012521521240216914A64231213021821928C582C012823C0198121C8852128214C08128250314800842000014DF470D1CB41122B2F3 +:803500001162241B2127341B212F1491212F16B981B24239812F24A94A2F1429FA4291A22DB12AC4912E421CEA22E411F222429E212F2264192CA5292D421B292D521B2925B29162241B292F24B181724292212F2498212F2418B14228F24282222B842229A8424AE822F4767EC0411986A14146A12127145012282D9113A8B413B842A987 +:803580004A4E91A22F1429DA12B922C4912E521CC8D21E812C64192E4286E11264192213A9421369221B4946B211E224B881662619E42498614E2219E224084EA2E02422022B4229A8423F2E090048000000000000000000000080080000140000481800000000800200000000F0D8284011014001143682410228140028002128802164D5 +:80360000241021110320AC1421B08181021C01483A08400134282C44815422008A020022F0881B14200218481200000020810112230223C181481211150211122D912329011848A04111221C8102212121140011100220284482021422BF6A4D11A124004218111821100222802162212221235221521AE4311461181971123192181ABC3B +:80368000119412C091484621C211622A0925021430221B4235622400A0C224240028AD5300112041018082018042210100001288000021001429080048A012C0110010021440010000218200288002F7F500000000004826020088400200200800000011B0222809200218C091702201290821501240022008202428044F7C0C111432140B +:8037000032182E112312B22128180140012248221B42230128142D6220042988A18618301212190140012D112C08109221008211208284922222808278C30C1120438183C11228C0A1A2140000282022048840A22421006011CA222821012601001123D112088225120111101182A28426820200828F950B4001009021242004210019088F +:803780009042D02182012211004824824022632820210112111A4821121202281022080000208628064F5F0E188001241221200130221A04282200255122122002AE12200425A241200490514002240040821402130429829442284822006602F0FC4500480000008002002A0400280022211888182A44018230211C02242818128A0480ED +:803800006123400120322200228250223022212848BF64081400000028000000C012901200001100502262000048280000120080228808000000000000E01A0A1C011840821122020021424860230031211A021C818832622581220811288092421800002021724281083C42024823224A420223822602FF1C0982000000808102281800D9 +:80388000402203100228808828D4220429858224041B2120918212211226022C08800400488084020080F4383B40011212800520041448001848138224041811C8488012118102228084140100141602200A2280CA228E42282B2822002728248A0426F21ECB00141420110162601A29322248CA0210A22123813262C8141A0224C84E2244 +:80390000001C2424422286062410131113A1484A9842462204424821208C0400C29F890DAA2101282A2132231227226023240080021419021962122290215A08112822000012241A0222113819084021120142002006002004B7B8202402004248200120A4121422A0120000008001126011880012001021C21220880200828282148028CE +:803980006428800810024FA84F8104004021C121800228460280D2120415224231C24228422826612E1110A124421811233411211200C021E824C82414141C04A22868008042E17508001128000040030010314224720000214800880021800848200200800A0010014886821882142208824A0848BF530F002A01245022482924C4119889 +:803A00003041C01188806414482A414181C1414218E012A12C181222481D12821B8119E22221011093C290422400420021422A240282CFA904288A03122C2641032084842141C252182411236124808101421829824112018822382302222B8221223428601228C0210060228088228202A622F21F782019A14200281A26E121820124900D +:803A800022118001222001290A2E111CC8922081812143011602800500928224C02220881201904240029042F0AE34141AA32A1B232063126A86A724924AA2211AF242411B112B212B3425E11231623A21E21645A146CE411B112662131921A9B24AA51316029683FB113160281F18092622484291411F2C8C4282FA62C2248229081CBCCF +:803B0000827C930C1CB48141A1322CA25416335126F2224225F142C22F24348127326A64231B641B25482F24F64161A02419F221326E613F15D423E113E214A6451246A2562B472A718222F212313B8229B221B241F662413BCE3F26F4C282141BC4CA7E62A228EAE4268CB2A2AC244E22CF220562168121A1143F21921327222B511F143E +:803B8000F231122A8101423CD111E82391423C52119AB981AA52141A18A23828233821822A82D613D221922313532217221E31228E812F18C8A2288A8A125232238204290A2A242422E2FE0200004800001C88C482C0811A8488040012000000100200001880010000002440022482200840220882F0CC9C14AAF6212111782AFA61B317FE +:803C0000141F32A235CE222F28F162322F28FC93111B286E32AAFB611317362B334AF421A11F14A1471F12F421731F36F762A327313F1BF8D1D19A81A4652F247442F28282921F3161213F38F993311F3252333F36FC43211F16E624F842433D222F24BE42F462422B866E4282A8482CF68C95141AF551712A82A7B31F3AF3715137322B1E +:803C800026172C2F2AF1A2822F2EBE9331832F22F3B3B13D133F26F212323F347623F161414AA5628E626E623F18F292B33F13F2D1711F1AA3115E733F3515F2E3619E221F33E721F283B33F197921F323232F268CFAC1412F267A8242F242622B222B4A2B826E422AB262A6462CFA81D6B021F631611B112AA3462F2431421F3287E72140 +:803D0000FB52522F2FFA12723F15B951A5AE1F167761F131513AF751513984F16151226EE37E631F337313F3A3811F1FED1DA3665AF473712B333F182EAB1213F3B1B11F19FB21233F34F862C22B286AE62CFA43833F18ACE42B8C27262B882F26BCC29CA28AEC28F6EE8CB0B1F711611F11A1367AF741531B571F33A5772F25F972522B52 +:803D8000472F2DFF53913F35F5E2F23F37F553533F37F752723F15F723211F12A6442AE622FE71631F31F393B327131F1FE518A3371F27F673732B333F19E729F2613313F2B2B33F197921F323222F26BC82FAC141CEA22F2CB882B8C2FEE2A22F2EB282FAE2C22BEEEAAECE8EA28BB920022A01220040A241241280041210418204132814 +:803E00000442808201188021240222A09220021C0988820014480024480000002FE30500144002244818121450221301D02213C112122122184041421123312282A02124120025321121000011252208501200222C080060385F7E09581B21B091A2141B212B1619B262B181F262931B282B9413F94291A22F1429F242B1322DB12AC49138 +:803E80002E421CEA2264112E429E212F226C192CA4292CB491C2521B292CB19122B49132621B28272619F2628219F24282112B84222BA4222F242892822AA4842E421F410F581B61481B21181B612F1681F262118AF222131B684AA32825B1A194122AF442B113B2423B222D912E521CEA22ED1528E211F223C2D2349E212CA42D348AC612 +:803F0000431B2946B2917262A2282693612E8219E624BA8142A24A2B24222D828AA42423B842E222F4155E00824800000000148002000000000080080000140000480040080000800200000080022F520F80021480128586818111421188110A2123921111428052831190322901922D42A44211184094112941212402C0229200002228F7 +:803F80002031224A1224FA8DADD01261491681612182B01A1892C87038014249242792218A41A234A2C5010030411432114132203741281A0811708282C1228B82A04270C1C8912C064668242084E11488F4A1592413B1E42181218118F5528A9098200246C8266E187022A3821D1224C8441E22852148A21200135843A322641356218411 +:80400000C11240B182A421228B82222B8320B49102232222642126222588FA18A80040114182022818482C711148014A012880014E3122850110011D4216A1121248122142809284111C0124400280041788A042C0482420246244481FAD08480000402241C248250114001228112001A0244828002011012A0148005012002042081225A4 +:804080001201110020010000481FD406002713858251224194422A812225DC822148098041118801601C28B012442115282482239425200136D228C6191662228A043214863844482880C672A0144A82D8330C48F022118450221043E2821182A484A1881C214201148112008E41400219410162007021443211002994118C41221142410F +:80410000318149242402484A12822124F4A3B300003012103418424213221121018400121800624822222005588118223A240400A0218722830229A248B022018100208182014222825F650A1D2222382065211140312149D2810289A5242F4221A4212228412148804631338880266314842D182A24344444214C66222C02222741511189 +:80418000844842251882012448288CB448D23905804468822184408112489812442625082225229112812334184A0121482978120861411190116084402AC11448301188C301A0282022042828304222F0CDC100142112431201182031112001848440480122100141400800B480240441002200123C0242A0124221A0148C28242101C096 +:8042000014F0F16B4051128B213828161B011C12B9185292184E148E4826847212AA21293128428C014125915B24838152C14914B8429151414144244E244C923239826144182E1146280C322328A1121E22A02443B148F2556620821242B846013011A021141A021548628142221422446014484A022821C0421A122244888204248C8296 +:8042800021210427329285012460248C3448480042B048029F72440112188148842814008C24011692184088040018260128484818224A4204208421445112111001423228181C011502002A84A3421A028249F2691B200110418134188904C6092C048699412E122882188120048481803248001C42858E121145044341A8844EA4168C74 +:80430000044C14324938488222100420324848DFE90718118051189A12021C0240981400141048082B1226D12841118882611100304448112664211820284442C1282244118C1222A1122250262061221810F8F9B80028810020A42489141251438140314A1605130200A01214408148018042048888A8124E222682426234241502214C98 +:804380000110A481002D8288A012F0E9BF3084A021608214123400492624848421628442C041212100101102290114000022434192141CC1424400929886822C48612128C24968848008C6F1F1F11012042021028190486051002A2401100280133248108803240000492211010042848C021424260811810048812260418001EDF9201228 +:80440000414129D482A4422848004C08A7112188281C018A2224B482041B4260842B24229044708401148038A300824A6841421984E4110490428AA4816C8101C8428C4CF2BFE58024C121122812A130216082844588241221A12189041902931101589111C04400239244284828C06128D480024A6212A881948A2112FCA2182043840261 +:804480004CA2AD7021288284622140038427227022662128818C5423942E118324459142284A9121888413942242681421421E28314BC270112A1251211D121A08CC04295A214C052034842038228CF8D922141E451F48D11111A85684129344EB88D42484D4A861252B421F12F163119C91124AE81504581D1117122E225E421519A1425A +:80450000112CD244BA64A4815B48182F1832548B4487648A528466F164811F11FAC2D217248D82114A6D288F41BA12F382A23EB4A28F1AB564FC88DB242A42E183C238289B342B522E488B62F021281FB13B543B588F91714852847A74117928F822221F16F511A180764151118F2CE42112D454E4522448F424112CF387A72CD8716392FB +:804580003DE1375637272C94512F4625B314F811112F15DC44D242DA22A5824B414388A1A185D24E04183A02171197B12F23F4482B1C3243AF14324AA3544285B941F212E88F2132898B263C84A12187A48F827648C8588F82A31366B142A22443A44639B24162173253A3C21F21638AC9DC58B713F3922285D299D29A64882E12B28B1787 +:80460000478E47446E1848296E848E2C3D82200460128008246032E012888428C1A4482C8AC4A412880010180221280061800800210084450224860882200848448A44020083F4678614BE315F5363111D51173E3F35711A5112357381D199F883833F38C9822BE85FF8F89E952B922F28F986867F58EC11B5D8FF494946E936B452744154 +:80468000E135F5214157144F26F6A48246F4E1C51F7CF8D4B24F49F134752CF286A63F28F23A322F24F633723F35F57B13BF11F14A4A3F24F572A68F83F9382E2723EFA2F276546AE483D3EC74C54BF336355FD67638F929799FB57D8BF35A493F16D41BF6A1619FF4FA6323BF3187F8C8AAB7B4A7922F86F8B393EFE2F626462F15F5D977 +:80470000F89F9541E112EA14F459B95E531F1254155F72E268F82424DFDFED5DF995F85F59F934759D286F58FA81A67F65F153633F2DF5733737368F9AF2CA5B3F247752F6F8D267A56F2F754EFEF6D62B888F8BFF9C7E6784342B775F537739F92939B43F91F17863BF12F24B613F3EF243E7AF27F643311F2CF442C23F34F14B53BF1E16 +:80478000F64AC3AF86F231513F1CFD58589F967541F968EBBB6717343F35F5222457546E638E826F48F8754D5F57F697D76F48E87152BA6FECFE8FABFF33F342723F37FFDBDFBF3FF85BE3AF24FCD3936F67F27C488FCFFA72C2EFAEFBE6C42B448F8AFA4CDE4F3F4CF3F674DF5264931F96F3595BBF14F47A2BBF96F24B632F2EF24AEAD6 +:80480000AF2BFA5B519F3CF4629A6F7DF97E77BF1FF372F3AF8EAE533F1DFD59588F9663948FB6F67B798FBDE735E5427245F564678E866F4AFAF5DD5F5EFEBFB67F7BFB5227BFB3F1A6E7BFD8FA1D163F35B7D3FCFBFABF3FF9DBFB2FBDFDF3D36F6DB9FCFDD69C6F4FFD4C9C4F47BD12F978F8CFECBD730E410084264128C24800C0481E +:8048800014404208118113011183044A1211888112250442490898D012011C41D814A841141220011A442341648164924492008FA107239221100148211146518110D128011CA1421816480221124A42082A2404B02444914400B02444044C4282065022482410082058480000484294DE17C0421F41D228F111248F14F11124AB141D24B4 +:80490000AB141D24AF149921AF143915AB9443F24AB143F2429147832D914F82C4914FA2C4814FA264114FA264192E4A9E254D4A9E242E4A1F49C2C21F4952281F49B248F89124E7261F48F26E121D24AB9619B24A19B54A3924ABB443F242B6478229FB24488B944FA2D4580EBCC1648D53448F14C124AF14D141B2486148AF5429D81A4D +:80498000BB85B44A289ABA4B481CE988D412F8A6481CF9245A89F824C21E814FA224E8A2E459F2244996E4A27411DCB4BC11D628F81124CB841B29672617C8CF2661486E1417C8AF34B385B24811D42A2BD8685384B86D48ABB44F88D5520D8482480082200100008100000000210000000040016084800400000000800200000000F06BC0 +:804A0000B5902213638115841141D64866225028110014208384C22419912484304D001C22012F8104924210466241112180088311825222189C81A128482B82C9C9328184B246F275B1207182225282A01C89089564A26082185C119888428D22122422521228222211D043A414114324C222471212222241124D51A01468494438384A32 +:804A8000C844C820829442444A815A1443B2E34D22F3C2138B21A584C1418938225C421A7C28217314118188D628226162244A21215381A2112652414217851D44AA61268712446692244523C111884A91686149322A2B4816848AAA24222F88F414221E4289BA94B214724E0F800211A08141CC54282824001048888184021C332481E047 +:804B000044021021C512000044290118004C048081142881D181A41440A2484C0181002CF47B231002251251181118200481101A111A01113412208132212800134285211104221B2141111C41C8821222602400001D481484449022222800249F3B0E1C82E342012952828289613289912282205941367A219C2222872881A21100342221 +:804B8000188CC225812F222184058E2324283B8129217212A816884E812B82271129084823882246B44221A1484902CF520339822201118031181352A28482841958C122430214218003222810221148C51825067219D16142A21282243602002581D22201842484412A042B43122042D2510C60214722159228A581084818221082119245 +:804C000019353823228F211888C82111108132211D243820230422821414B72192C038788A243C8211821CC4418222244302228A1404AF560F1C248182A221354852857088A221E71112230329828142C824216911A412C288524283724802214D421008560434188460821AD22211C428844E389E48606C466242211261899118CF45075D +:804C8000D014241113420212154441382481848B2100A180042932288909CB828502008343039028414260414E2218122113441424214B04842082CC82896228442CB334014C111228014484D02A02004014911442642A8191288344018414264114221141481838112A21824208448CA44120A44111006024402881812804F06D4540D139 +:804D000014C13A1722188504455A2D868283124864214158CD22838195288745853488835849BC1414E28471315882E1A1122A912470146827C381E484E313248474183118CC814D9AC48B242F28662820941C2CF2A138F0845200122612512A13215281857211C812165818322480322421221C222224A221488942022004191224211271 +:804D800011028D1240624129818288148844024C2191B84308849734802211082818442F148222844601141014C42820223118439AA2211946922129C14214122CC24123C24149022D26844D221683022A48C122196228426512C41241282781228843F45D510024162242E2842202118B1A812C44A8182414B44A91684D825140117484C5 +:804E0000819923C0282052228484441211002880C28220A4281C48140388814B82184928841184F8C4771423182203188504810018121818A012436944100841108844018022822204411244400488408821113514181810A4A418902440C8444289F23712402802974189048344765892484481648041014081B1448254221CC412008461 +:804E8000141E8812114418111012B14111120154888314423441618E12200400488CE12201DFFC41012800A12041130140A142144880048844881E41114C04121480D1421204859428122302221621424204682064289216022CC12C252A882102848CF164FEC01E508200608212204182046818482CC218896482818C2A8C0290A8867977 +:804F0000421841810221219C4108411991428722485116041148202822A848200800E2DFF80122002D113C248C9442004888251858828881A228272C002584C8944A8A0811811622015094901400009611012D82190290841100801112848818E4960A1A7498010024121A6281241682522146084E22A2240050140021800410068C8681CA +:804F800003499822472128182B24484E34351828912280C1241AA416A302123AA82426013F1407254CA442872213280185C442004C818122329414C0131E4193032B14124611B2182827344121881CA284682D6811E84219341190883E821B12824C011CE61144044CC462535242867812086F7449C14282A3D212312369947887466A24BF +:805000007C72DE1161164E588B344F4DA8248F41D282F15448557D41BDC57F24A4442B493668A815BA15F421234E618FE2E262E13431114CC2922B64237111E169E111782BF1285E16A281255444CAB154F434D4EB814F62F112811AE2C4FF18198BC1DD11242E24AE3616381D8E418B9127811E519721AB51184E82EFA1719831121F1287 +:80508000F2268B2AF549412F42BA12B324042D635F78B841334919B638716A4C2411C4A93E242EB717111F42A2111563229CF2A7185E16271C1714172A16F2138259CC26A1EC82E262722434B8AE814FC4D2E4066B1137812CE3A272586A8647267D2A2D192688B41A0631245897492F84E822FA89128BC28B91748B8D212E812D21AF122A +:80510000F142618E232B112F823912AB45F16B44E3127425E78EB346366B4E668ABA15FAA2B41CF341F18E512F71B2A2E9A4A24E2B854B18AF840D6C662A1FE80F424008602284002C48888884884486442211088524010090283088208821088241826182184880041A049A44240182A04914828112812FEB45F134267FF363812F33D763 +:805180002882F3541C15F4682AAFABB3B67331F2AA841F19F18B1B1B89DB8B422465F6475549E21AFA25A14F4CEC2AE627F731E93F99FB727F6F57FE3888CFCEFEA81ABF37FD73B51FFDF8B3352F48BCC2FA61619F9CFEE8689F88DF4FD723FB33B33F11F555D15F14A7368F8EF518785AE544C6283AA7B14F23F2989A1427627F7666A1C1 +:805200009F3397698CF74C3C3F61F27B228FAAE36FF3F382AF8BFA9153BFB9F1B5D1DF3BF9AAA2AD2A6FAEF4DFDD6F8CEE5AFAA7A75F58EC2BF7787B1F1BF6B1F3EF6DFF57C59FA3F8E6EEB79A5FF7FD73A11F79FEB3312E462B753F38D89BF2DCDC9F88798FDC62DB33F133716F25FDD6544D24E7C5EF6DF376745F4DF656782F8BE78DF0 +:80528000FF8E3E2F444AF375675F737738FA2223AF16F66A326D5CDD458D6A2FA1FF7276FED2AB745E98BF95FDD397FFBDEDA6F37373EFF5F14655FFD8ABBB5F5AFBA5A52CFA72722FA3F6333A2FDAFA342587BA8FAFF57CCE4FF7E76FF792463F735B622F14F27372EFE9FEAFE5AF89FD69721F6CFF23B31F1DFF46D27B914F42FBE8D862 +:80530000EFE5BF92B844FFE4F8AF41FF18B4CF22FB4A3C341F74F42767A7A1AF37F37A73AFA6F34E7EFF75F44B6B8FA5FF7A7AAFA3F1DAF85EDABF95FDF757EF2FFDFAF2BFB777C6FFDCDD5FD9FBB1B75F7AFEA7A72F23F27B7BAFB3F6B3BBEFE1F115158FBAF1FA7ABFA7FD75575F2F7797F737B147642BFC3F39F95A7BFF7CFCBFBDFFE9 +:80538000FFF6D2F33F39B9D1FF53D33F59B986FBDED8EFADBFB6BAD6FED6F88FC2EFE1FB8CAAEFCE0314004001418C64121A64221E48141230812813883291448032814C028001714269111802185012D012811404471240012482141244844412004604EF3E0E27284425C228218C064CB22821012850811812852412A842A1484625A8DE +:805400008422832432582A0480924442408441642410688960C82911B1423114422004184885A44A89018F3C042CF51124CD121FC1326C1F41324A1D2CAB141F48B24AF98128AB9453B84A3924AF543934AF547924D81AF934488D954FA2C4814FA27418F1244A8F19F221CA96C5CA9E24ACFC91244DC21F49D22CF89124EB861FC9B26A3D +:80548000F98124AB141F41B26AB911B24AB915F44A9443B24A3B342BB44782A9F9344889F9244ADF4A094D181F41D636D5C1B26E7111A4141D2C8B141D244E141D2CA99345182E488D952E488F543924AD912B4A8D954F82C5815F823C185D4A8B211FA27418C4435CE282E4C1F2244B1B61C7221B21E3E6C17262F3912C89F11124AF427E +:80550000F89124A9B215F24A8643FA483243EB2472A498386B43A9F8A45ADFF20F00481E1200000000000000000000188008000014000000200800901800280000000025015FBB0212142123410A2D3816284211480112A4444588B282024228A028442190620041814981012D6290211119F221140000E01241984413B414822132122041 +:8055800009422AF4E3F210A1283628180270216495181C21E28401B028C1611644F11224004D584419248442848382336222C14444228921018149654329F1284425198804849062471119741814B24C6318815F990E111F24A2212D1250228362421D6819911C222A01242A511C441CD2424382C25C1EA44631C2604432224B21B364427F +:80560000165128482B24818092384426267168561C838224B441C2241249C31160298B341483F5227780018188818071118801141183241158844A2293822004004480322200202251844443022E11134151414A2101001311181428B142123142478121414A28F2ECCD108202901212801402B0119498164841C814415410CA48422004E7 +:8056800000890212650200241024612280410800864822F14814C01222187048348442223F5E477131542154D01852281D1C16081B4189322200414B81142E588CA2241601228461812D4C1144CB2481D048E1423184430218301436CA4C23631329E928A452488C8498D22B248D1248ABA52A081E2870960D262452528042781285116223 +:805700001580248141151CE4C4529442848904A44C048C0426B848C21224124361484C12820136D48213B82881830829048C0523A8213668244A6888882A81F2E6961439110170132811C848008D22139388812099111828263211A0240085124411144418442C020041124062651031128AB4188A14B2CCA1412D4224188B12434694480D +:80578000F09F69108401851274281104482941D1246111C3428421220218B22C6112C71321825662418CA114611281C512081860834220275283244C68848169132282C122411A0224B044F141C2A012488992224240480284845508228140981800602481124C8418A442412052124C2613084B841200A4814130684CA412233341582135 +:80580000828904648648C214188F7E0E48400100182962C2481240882441221484332C81C44142008400C088841880E221024120C11410AA25000000A490121210C44884842F8E072A811138284226911830662F84518140C844C1246289A1124483D24851849902D0A4E145C2145827C884844302324B1843A12148A42C15E8138482E42E +:805880008453822CC1128123D822024C42C448C9D148F4F8DB90446032104658242881807111D812418821113824608398481CD22464442004818092125E24AC8142024088614183C224A18C9482C01259242482E181C41412A908009E15244096154932498F440270482126028442A02142C03842A90118412C0240828153828420062690 +:80590000044146CA1C2921117A28246162818D82C954848B242288418849212414F4268C200124811210B14201B041414814382100220020522832218AC24200401204C03680138102441116848412C124130111301C212A08228A212AF43976242031191820054A8101842015288211C84423B4280146088141901A205218830144322038 +:80598000121491121820012A61812A810884444422842B214C428AA214284FD545D1A11401111414997121421111E15214413159C0128901003021901119342142801491455A424AD812048C120427228D41294212744A6341250223DD2221C424422FA128481C42D88A47217824312424811290285880128882048C2264428143A21283B1 +:805A0000018F22840442244168004144124C21410811226604130400904418224B94588E44B0440888F0BEA1F05428502841434329022819042E14B01192484222A014488914114204882006202381420180C8148C722204904869A148A12449844211082544482882312418FF530B004008200424A44D4AD02241420227812012480218B7 +:805A80001126011418480048149044100820E444111814084284119290C4800842200888AFE80B17628428181014082002469148189881282512842122220244896181820028121816248661422241228022022218328E142C28880118A3D14212B848D224A1A4CFEF0C84124828274480434818084C41820248C0580042131403581386DE +:805B0000321C411113446814482146082C85410125A484144324C8C422388C3482C04880044121F0374B1437668E256F41E1D1734D79647D39E21134411F92F63B2146D1815418BF82A8161E2A2CD648E6A4E1852512D8AAD251B221726179328AB121D1887312A8211B2529B214D344D294D148D6427326E6127682DC1AF31A361F11F2BE +:805B800012BA37B1A5F68483AFA2AA83CD248F81F326264CF422E89AB872E2BA051E617B111D28A7222F41B4194191281E68A14AD48BD422D182A5352D286AB5463112497428C2281C81B524F482D12B7149B422A46417178F14B46455484F25B54234988F43F2221A47314A7243B45C62444AF8424A484F4CE88CC9544B1947642F8DFD5F +:805C000064848F8C6D824B144F42C4442FF34B92148487324138484E386E1A8D114245A833874713C5418B41A187C36E188B23289F14B531722435424618A894455418214D14444F2265C217422A5121437161A811CFA1A1425F83B424F4289483AA124B41B7854E448C47F28242B09C7A98A4348F28F8A5790018844018844442480324C0 +:805C80001648022412201128011246041002181002001811981118111815C882130115081B414008802211281108702F49F215325FC3721CD667F41B189FC1B131B73BF27B389F9652149D132F465111DEE86AA672C57614F424348F82F339391F13731C5A37BFBCF5415B4FC4EC62F222231FB7F278284B234F62F21F451F56F6958D8F69 +:805D0000AAF83A5B2F17F735176F63F31415BEB51F3AB82A43F34B4DDFA4F4C3716D846F64F462762B76ED256B668E88BA73B4F22554245F63F36575C5D7D7F45D599FC5F539383F12F37B7B3F92D2D8D211F25822B5E9A9F82222AF87774EF4561CCFC6E2A2F33B391F13D3F95133BFBCF41143CFC3F224263F32F2792B9FD7E246E746F1 +:805D8000C74E4F47F7D5C5DFFBF83F762F16F77577BFF3F33B148FFBFB8787BF5AFBA3982F8BFB5249AF8CBD2EBFFAFF6EE66F8B7A86FCEE6C6F44F4B4346F28B93247F154766F43761A761FF65B1C1FD5F1787ABF27B31BF1282BA5FD4933BD7939B5CBFD7872AF84F34616EB45CF42F72838BF93F331395FB45535BFB4FC435B6FE4F43C +:805E000072663F37F66B7BAFD67214F424266FC3E442F295C49FB2F33E2E7B777B337FF6F3D4DE9F83F6DDDEBFD6E621F5CAE8DFA4F5C7DF6FE3F87E4EAFEEF7E232ED876BEE6F84B724E228F17D5A245F67F73775F771DFE4F27D7C9FC3F3796A3F27F57B7ABFB6D69AD231F35A52BF95F59A9AAFA2F67A386F44F17658CFC3F61838BF12 +:805E800093F521285FF4F42543BFA4FE1353EFE3F736263F37F65B7BAFD7E245E523F717571F57F7B4C58FE3F37A3C7F45F77477AFA7F7DED6BF87F6D4D7AF8FCFDABF91FF5C5FEFCCFD6EF4AF6DFD4EB6EF89FB1E9CEF8FFF4C5C3AF3C4824FC90B6130260048008004008C0448241A14A84189220100002142311002184218104408483D +:805F0000400882E0880484448E48208922089246043F9101828041188C921828294148C1681880418841C8242242130355887221321841282C018CA5240021E022012A01181A0216081281924432812A344284188420F85B71C0421F41D228F1112CC3F4912CA7241D24AB141FC1F24A911B21AB9455B84A3934AF143934AF347934D812CC +:805F8000F934481CF9244A5CF8244A16F1264A87192E5A96D5A2F49824ACF491242CF591248D121F49B248F1912CAB141FC9B24AD941B24AF91128AB9451AB944782AB9443F34AB44783A9F9244889F9244ACFE30FBCD541C4511FC1F246111F81521A1D6C2F16E1C1F24A851FC1F242A15788AF147914F84A8143F34A8547835CF836489D +:806000001CF8261A8D954B8216E1A271888565594D4B8F49F2244B8E284FA2C5648D128E244F24E1C8D22EE181722CC2242F66E9C1D22ABA14F24A9236F84A9443F14AA643D34A7A2698BA4F22759607108204000000008002000000000080080000140000480000000044000000000014F0C56F0000415028151844F814288341214581B7 +:8060800084D42821A125214C3361542490418B212E110049114818025A92921425012C9121004321612300122694162E541A522428434334442FF1025A32A2C011896557181B122B1411A0128150482C420481C902494188E212446424C0488F111268434A11E84611C32490244F8992848C911812A29C38481A286158141028189888420C +:806100008641D83B0E7622041C81E42221F1142189551C4568138B431181684D12128C962A64471295A4213374C491482E1146D81843943989018D262E416BB424411E8C643628012E849999682F4289919528211E4CA2D022E24166581E4CFFF10F80024489D1C1541810A22118006044100A1841381A0480021A12023018414225288506 +:8061800001141922224941882101120050144C21825184890800CFD20C2001442631112400682C318114400140C8224342742428148102508228481A82410410022B12280000811A6424128B14123441242200A90888ACF4F438244A032D232810028312D8B48122721238181A142FF14294218925278822C24A142D154224FC427264225A +:8062000022EC4231251B820027512963534212A1382214463894A021124C341462D28B42F0CE1CB0120613322213024008D3B122417113C818184581E16C81321E1A82822682462211022528B1125242484313E318022CC21123128184F142184218871190942128184C8491C29810F815F71480114204330129128846220AC04384508203 +:80628000803644478840115812548C24D24136224C24820843022B124024C13410081E222242894541C41222406482488B2C428FF20930248C52232444C02284441A0227412644C88141E4105A9424942E18A0284146D24821D12441A114108162252849425848481242811524542A48188200436483404218F8D34BC057485048121410C6 +:8063000092214220446C32512C02604124E024818251841748BC141421144241449818274146041C08AAC1144008874821824F184102182C8109C14622C2525F620D2051412885512844CC0189028400102851121C32640012822A4402830328839228A122412420C118122180A2214400401848048C0A428A419444608AD0147412D4210E +:8063800052498551A64436DC828282532818454371894256851F22714854964AD18121D248C2262CF4542A8751788C51281883D261C114274130351628CA54286E1884954242DA1CC4184C8861AA4A298211C42485F27C72A01828C1282911410214CC044881504822185042220028862814515800244C322287440022B022618824160C09 +:8064000012408488842849022041E481D448883448486DC4601413029142304213840428D04141181901111001112810011230431111001854111646213122452142011CB29154124829C8810022230846021A58282FAA0126444231128139811282714118261532426024B04612344410845138106824894152248744496264285024C058 +:8064800014B594142225582641582588084361C449D8427282A4248860486688F48BF96018400924C012182549D8281851188941E584C113182541110214142210438171421158A22825221111110A2842112253911415827411429111800718A88128442D24CF440D2C4184021248224C02222885041C921228002A816112602620242261 +:80650000A28462200512E0882284026848126223944886082C02822138200443250148828F1F0521241210322810083502469188482C1E41914143CC6819115114100515021144491234541C7228110414A9521E14411C41C821C0816011442CC884C0246382288442F17DBF00190284005428481816A1122124502400160280331280517A +:806580001220014A811849415424422136388156220826C222A04B44008E42C042418240848191446F124BA1421844E0146221421914280620912400401408441028118895584602108116820480011880028448426081442C0446082A08A0148C08B03C0A20285221165C8155481C82D181548248148C91284B582C6132444E22490410A1 +:80660000140313888303218220982214284011624412282568422C216844182306122305632242C2285F9D08AC014D4A4392818E4412100140041A624212282281244410D62C82512888890285026012640044484240548344166148842E441B412884410041128149318282CF570317134F28721BD1D9D2945A316C2236418D138628717E +:806680004956189BB267152F21F116214E8B4D14344D51AC1259D295429A58562173A24192122E241D9622411B128E424E3115F2222A93736AF881828C9C1B29FC17818CF548722F22F884A23AC4A41E34A81E918F64F64FB1803282AC8231422F84F937511D2CA3F163481D31AF9482E9857146A4321D254E16737342BB2421B225653119 +:806700004F2284B451F4E2832E421774CB449FC2F614221572AE78417111D78C721EF12A422F4AF141416CD151F4726C1B315EE21B156C7583B226A841212F443312CF84BC86E424B6A278364BF344521713474225F219528F413648ED539CA421A7661D5227915D4216D9A9A4841B428D341B423F44524116752418F112292F127111985C +:80678000336D581D1E61EE4469C5216D462B1227311F867315F44421C5F446214F21D31C71EC631A4523FC5C8586F4442476B484B8E411E2C331AC45F845550000430288200280248244A441A041A041890228A024A02480028120044288001044080000008200200800828304F0E145141F18F4212395F319735F7FF321269F86F2393FF3 +:806800003F17B721F3111A3F35F3BA915714AF193B445F59F96412DF7AFB7A1A2F1424F65D596F1454FC8FACF45B5BAF967D1AB922F2A5A38CB4D6FC52511F2CFC41463FB5B132E31BFF585EBFACFE43649D2EDD2EF5FEABBA9FA3DB23F54546CFA1F92AAA6F247426D622F826A26B2285D888FD2A6A6FC14FF171533F96F41937FF71F7B9 +:8068800077F71F69F5572CFFF3F37B711B335FA1F13A3BAFD95B54AF985B347F78F936377F7BFA3F1F6F17F576355F51F12537E5DFABF85B5BBFB7793AF967327F3858366BCD2F61F1CBC67F74F41757BFA3F3B9FBFD3FFFE8FA6F6DFFE7F75B1BBD1ABFFAFB31321F72F75556FFF1FB3E1E6F67F5E4666F68F826244F427686FCDCDCCF0F +:80690000EFF7B3EF243F41F42167644F73F377373F67F31F6E9FE3F77B3239F1597C1F35F2DAF3D734EF3D7D6FF3D7D57F76F1E7DFFFF7F347457F57F135154F32F34F4FBD8BBFB5F572733731AFB3F2EFE7A7B46F6DFD56527FFCFC87A65F71F73D337F3BFB5F5F7F7EFE4F4C9FF7F655767F74FE7B3E9FB7FBC3E27F7CF59B1BEFE3FBF2 +:80698000F6F66F66FC62D66F26FEDEE8AF85DCC4FD2C9E6FA641E169D56BF43B3E7F76F36F371F75F1776EFFF6F66A223F35F57B78BF97F7DFDBDFF5F5EFDDCFB7F5C7D76F76F7EFEFDFF7F777754F57F335355F725277BF92F27B7BBFBFF77361FFF7F38F87ED2E6F4DFD56127FFCFE87A77F51F32D1ADFBFFB3F3D7F7EFE6F6DFFF7F68B +:806A00005F59FF55FDFB9BBFBBFB93F35F7CFDF795EFEBFBF6F66F66FE66F66F4AEA89FF74CC4FC5FD6CFE2FC30243021884418449E18164221A048424844048044C2201128504004A122204002022A48220422882041245E289242201820020C122800200EFB2072905181321C42422848100122001322001433142414018281288012A9A +:806A800001262811044828496181008302412822844212E08304802801124CCA493F8B0A2CF4112485F2112483F41124A3D641B24AF18124AB9419B24A3915AB9443F34A9143F3429147822D914F82C4914FA2C4854FA2E411F2244A87192E4A96C55A9E24ACF491242CFD9124C5F2912483F49124AF24F18124AB141D24AB9419B24A1909 +:806B0000B54A3924AB9443B242792498924F8284F9244ABB23C04B1E64AD4313714AF2112487364CF24A111F48D27AA1488DB19AD43AB8B5D42AB8B5948A5994927D482B945D5A4E947FA2EC11D28538987F22644D6DD99E252D8A1E2C6D599E64E5B391F246839E2CED938E24AF14C124AD978E248F3493248F7439B4A536242D94478A24 +:806B80002F44312629F924583F6E04848248820000004014020000000021000000004001400848000000000028800400001002EF4C4B121403288418361CD88182023018161428112C25044601C02C8C0425012691141C52244D281622C28217421292411E252088912C18119812CA8126844284824804C3E21646A1524B18A32181613856 +:806C000082961172927122E811223888174815883281A52425722194C8241C5241421821D04AE182211564512E11824D216D2A6E11244F11E2817264C9421CE2814891441445AA218D422021061685F88B2A9042274D811284922F81D21898211B1269C2212249C1891843822524E4320460C12088441261611353418321B12B21B866888D +:806C8000624363741423A2288F41C42E43C381AA11044AB242512844282A48042769DFF60A4B121129818211918412A52218289198864854818113584A1230258B8426F24821554281810285E4A2E1441244E41211D13461882E11284D1116681248141648A1414E914588A2422021044C61822FCA0C1001001123423448008200000000A0 +:806D0000000042A41001118048448242013450182881442C0100AD9112002901880041C0424F36062440021054819013404271130818911A142342611414414712111B2442898218584184226041308484416021430450249122001C08484848832281664828F76200400210548241A301C0821C014009212214421440052E4821944049B0 +:806D8000348844B016126148154214C8224C142441548128990182200442838231248624F244FC00350800111C021C0464118C0212A0411400142444225661184228821041810284004608141284400221708224430123212408C0426024DF820E002485042250164562228418160250422E1827628015A484004622C4141820442415120B +:806E000004202182084218250110A248508170220818899128844241E05A4691141445081341038512C1D110028111001820220813122C481902121240280439E2480350282AC4184412150484218C41628144480030142042FCCE765021241902604100848140111101008C880183321820128C62A6493229C09222104212712222D81415 +:806E800001288224000025120440181824058400E792002563C2C1F02112502E45EBA2082711195183116132872818522E84831421F248821B24A3C7342A81B414888744641226D522233A152846C814172144508227282C51688351424688D148812141684285724C014D1140031C410411B0111408000085323420122889528444844482 +:806F000021858101250A25022909608823A4212C081400488111608240082E48858404412F3B091440014008110018008481410014221C02400220B1220422444828002415148802400221100A240000220060824224AF22091002122C8152420016D18308212C48C181215C48024411814601150C184912058846B48241C281C0121D1829 +:806F80001F2822F28118452812E8140125213111454808A41E48484840E817070011407228020020490288944D81D01448231244424802822C814404C041200888154468128601131802904300211144200248F0482240727507953A482021014114D02151D445B424E2A222420200C0232513B251A1118F59A88838284712441D814D61CB +:80700000395188B5BA48A4542F846122228951842942D84C51644F12A23232848410981A46522229B418F1A5BD0018100341120025022100200884121100400480420226028008000000241100800440210400120000441F1E0A818C2484041002214014E4E862828A12110800190821292181818808812810414118E881A414482400284F +:80708000212444618D24222842400800282129F12A7E50828004200122810044C0224002141140D22112024931248800001116014008481901411211842140042C1208230480041002BF52058004000000C084800200140000218041810800001D41008480040000211114441428400100001002185F620300121602180000408248020058 +:8071000000000014140044410000000000000000211424840000000010F4E7C5301883246424221002205844C5B42C2222021144114002241A3114921482005011105388818B5442422840020045544C6B222662860020042440A2114FC30B50884848000031200845042A12010000146121284B912E8888442200141501128588A85424D0 +:8071800011401102004514A92240480800216121CF570C211249010018210024008420116A88008800412002224200200800604188C012184002145018000044800400D08F06004001210000200810084001110011000000800200000000100110410280045622040000009F2E0321124414212150222180881858A8A18295518550118002 +:8072000012147424240210322823224402001816A41828E03151232558310084152244B24804A0440041F09F1C2400121270140250A18882D0A208823C518285210113180111114039244904000020018A61112455024012D223145228948D49008112000044CF380B121818358282B11221022424A18200118058118048414144D144A2A5 +:8072800022408482028A090012003012312641015019318314A25421452804800241CF6B016F22F212222E122B11122B11C0123592822F31F111139B989E888D888F18F44848D0915411488558884F84F448444F42B444F22424222E2480526445E442F226222F21A2129AA1812B99823C512229F812131F31B189699987848B488F8424CF +:80730000E48404488558884F84F47C3BF0262265A2123A211102142592822D131F1191811F89F818888F18242C44511150918588F44844C5B444A226220050424584F226226D822E123AA1812B8882822592822D131F1191819E88878189A444420040588848FFAA0A00000000000000000000000000000000000000000000000000000068 +:807380000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000000000002F +:8074000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000AE +:80748000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000002E +:807500000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000AD +:8075800000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000002D +:80760000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000AC +:807680000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000002C +:8077000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000AB +:80778000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000002B +:807800000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000AA +:8078800000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000002A +:80790000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000A9 +:807980000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0029 +:807A000000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE4B7 +:807A80000F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000000000000000000000B +:807B0000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000000000000000A7 +:807B80000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000027 +:807C000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000A6 +:807C8000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000026 +:807D00000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000A5 +:807D800000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000025 +:807E0000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000A4 +:807E80000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000024 +:807F000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000A3 +:807F8000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000023 +:808000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000A2 +:8080800000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000022 +:80810000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000A1 +:808180000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000021 +:8082000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFEA0 +:80828000000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F06D +:808300004FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000000000000000008F +:8083800000F04FFE000000000000000000000000000000000000000000000000000000000000FFE44F4181C21880412802301441E042210844D021A22186824228092398521111818188008D8246242241C1418C0547821E4848430212890180420280C222162825F13F7E242816495129D14485942E6362221AA221178845D824322163B0 +:8084000072124C37311F89B48241B8560817281626F912812B811F84B149E98428742198419C16988851468C65426D22422D24282655484E2745D842B234F42612522901842D4C5FA207211601301A4445481284810286880861403137142884810000881282828840021138C088874160C52C210422104128D4420267242052229018525D +:80848000EEB720C22818910010022C2281C115C1902126742804D08394828692C429B88164412131811218807424281641014242808452422132C30111842604452204812C44ECFB0A110000008422440022000000381200002311C211008501C8890840182804415048446800004C42022A81012812001FC30700150815148832240044F8 +:808500002800434202230129882881810110018C3812428D41816014800411118128280044204204002022810140F21E4800000000000000000000000000000000000000000014000000808101000000F0AA3820C122C3011881442A11821288921885238111E14132112C428994484188004428004C1462821D341211828664414826815B +:80858000621481A3C43810088110141408C024418D5234221601871187125C7212C84122257182C219103488E4008285A45811822A149248874527228C6D85212628084A58142830384044D8488882024287144644592400123604C11248EFCB4A21E13172144891188D214D1826031483681389511829111CE241E2183128278C4883DCAF +:8086000024028416022BA18C04469C8226F83184160482A816C444938238418C324A6AC14849141908444100452813F4243730220016681244211A642228254208418928410110C411118084887448342483C41220022044912160C100C02C2200841484101402184783004448FF48072228000000250140080012241114320060824211E8 +:808680004231109128003081241AC21160121121153828100214004100008800F0FAC6001695140042AB1290188D1127925260B18958349C02844D439CC2218D14148220614483C318882B1283A3212014942811211694184902104182886194AC14C48862A4184901F0D4F7001F4211044082033195020024824551831414163121148460 +:80870000850114481C8441312860811211468291191001215528023110011C4418122812B8824104F03BC120021800488190181817828B1470184128612240686684221624820C2C1134281628B81282822208262412912217418C814208402228416844418848001200FF88029584911148481440614410243518891154488814B3127AD4 +:8087800021088145091B18C02819211168138303288C018C048418102481014D11128084110C848183C1128C11F88BAD24814C0229051049042441002E4150124480018244430223A2181724008421110031848014229484B81C0240314484C02A80220162C042A042BFE64BA11200818C311A20018C92192800208121044B12C0881150CC +:808800008484201408131118B22821210290310081231149088C028C880148210000008F3848D14322C312818C651181433144892221C1181E41442196C4431781897321388855582C22942C841499183D182E18A93218312A01C0318143E883B82731188C41414938884E121883241118188825C168CF1606184414122484141100A58153 +:808880000684701508C02241884128118504142628010012221A0250282024014001A0611810086C02A0421810083F110312282232104208182884230600C0311C218192311C4109406B851CA4211412811088311119D21802D0818202221140010081200200202272CB0B428141811608008482004D488E4848850182004188188841181E +:8089000045210A40088430218A02008A022021281A28010043618449141804309C825FA601121008A0242142208401001098481C94411200C08A002400811118200440C4222A014484B0188828015270180212A041208102414F8F0E1400421044111414446164490187422290182240C48822D04109104981084001B0910220348810B1A5 +:8089800084020081840000208242240882CF41072022922822008021A2122884202182220283922980082184812A883249848B42848122482294238A44882232482211008908100280021A2282F2E98640088C24010018004004400184508400361835417042018114180000008810381222402802001100108808200221F01B2CC0644211 +:808A000048901C50488428128CC48C13A424481B8400904182144098881004818001482200208181823818001880488441888834580096081212DFE703000060220028302424008180C1482E4114890122148440018301141818193281102111491861158410418918810888C088002602006FC30A8C021C04263144414954144905C48026 +:808A8000024C6514C01C58002D14C01324884820012A68164A8841888104121841490800D4CCC4284004224C0230842728F0D3A1006A82C2281E284D2444811CF394245992289741207631A143121CF171383E948F89C9949718FF7848724C3D288B1289D518014A1498111BBA13117952A29D1922B198A88413484151518C18084AB428FA +:808B00009128A0A249A18A96F4DA1AA04640B83871282556874B1445A4548F84A18661CE481889F649281F96F44564484942F11D212C44984119F1C1811F117211018B33808A621126E1B33281267834716C18F488282E9115A889CB448260C825E84C6A424CD2A481D24883F2AEE4F0113484C712422CC142814C64832236C24A4E48D0AA +:808B80008DF444881CB18871384851991322C288D09A51228C46688817818CFC18286E49B681B48482F12838897288D811E3C2228332189568818961816B8183C1481A2422A18A122B825F9F0D1504150411421142118819841881088841A84188412843084100008220084288008008000098808984092C9944984588490884F0EAAF14E3 +:808C00001F1454D5D14711CFD5F44B2B6D444F51E554F28545CB4DBF34F4CBC5C2DF5DB768F5B5D54F4C71C5E846F4A594457D94F158444D846F2454476AB4B1E815A4819F84AE794EE88BA11B441BAD85F23B8B2B441F1BFA4C44474B8F84F79818CB1919F1D8DCDAEDA9D146F1D8D84BFD8F49514C4F6BD9C8B8B8F9B8A26D11F04464A7 +:808C80005F5616FD3C39CFD4F64F2FF7D4CFD1F514555F5AF78915AF2ABAEAFEC5458B7D8F1CFFDCDDCFCAF3E559CF94F68893EF42F23511FF2CF5838AAFF45D232F14EE99F8D8C91E895ED18F8FE716FE19381B441F899F389FB3B44AF799B9CFC4F7B4848F847F89D948F889918F4FBF48C4A84F48F9D8D84F86F62884818FABF98AAC06 +:808D00008B8A8BBB8EC6246F4796418FD2E2427265F62E6EF5FD5414DFC5D3CCFC796FAFAEBE4AF648C8DF55F5FCD48F83F524F11FC7A4CF13F326B8BE8C8FB4F58B8B6F24DC77F422489783CEC11B118F9CA67D4EE8BEA95F4EF794C495F3BBBBEFCCF495848F44F4B4AC4AF529A895F591888DB98F8454A8AB89CFC4BD287424F8B4B436 +:808D8000C5FCA284BE984F48F952FA343F15F225648D2D1E345F61D7FF56CE4B15DFC3F73DFD5E72AFA4F2CBE1DFD4AC53DF57F7F9D18F56FF715D9F9FFF3D1DBFDAFBB19F8FB4F4878DAFF5D4BBF4AB691F9BF948591F91F1C8488F8FF769E81F9BFBE5F4DF5BDB39F3F3B1CF4EFFBDBC9FD4F7B4AC6AF739B8957119F98C398F8D7D2814 +:808E00007A1AF2CE5C8F8F7D24A8BB2AF2BABCBE984F6AFB3A7B800122001004200100486081F01148209128128182813100899211811881002A012641A812844712842A081484C04840088C840228824C027FBB0A8002844D1228811241288302A100198402421508C081C081219043000042221308008221008604840014001002000011 +:808E80001886F19F93C0421F4152281F4932481F41324A1D24AB141D24AB941B21AB9451AB9443F24A9143F2429147822D914F82C4914FA2C4814FA264114FA265192E4A96C54ADE24ACF491242CF4912485F2912483F49124A3F49124AB141F41B24AB911B24AB915B44A3934AF44B934F442944F83D442F92448984FA2F4F343D0A2E4B5 +:808F00004156281E64811E2CA1CC921ACCF24A941AF24AB44781AB9413F24A91F04A9117822D913D482F14F1215A4E912E8A87115F226D1D2E4AD6E5B2645DACF5512C45DA41D628E541521C1D64AB141F49364A1F41764AF41124AF14B215364A32A7443A54423E4825F43648986F82F54B7B40084904001800004480024002000021005A +:808F80009088000040014008000000004004280000000021429F770919812221512490749028152821818164148C041D18442D184611C11184C21584814129D421840252143824848C8191412826414AC32889E11801482884002E144432C3A2284F2B0F22502422420084182B124E2860281628082C028C01211A021B4260821417A41ADB +:809000005C488C91482C0838418A514121CC829218200842130212811210240212421C24F4D4BB90114E28122B2144211A140822CB43209B1813240483C1182137241C32111A843C8419C1528DC14D4817211D4888428D212A6124554A782834418361128652212AC4211743124228814122124D126A118CFA9643200241200443028F22AA +:8090800071110812244888842C12416481200117827021081528018324022921112409121828221008811688088112003024004A82E4720A6302004722484110C2488302810084283289A8424A0800461402224614042622086022822144201934110020088414001220491484012F820318903281A9C1168AD18441218348C81216082DAF +:8091000016C5011594141D141411418242668B648212CC2631342B42460412A8296B129038268881082C315188614E9CC488224B2426889428445FA74D6243303230244212816087A880C11840564140849554004445021C1242644180839142008A81E8429121128362811288A081428958424C488C084A8A0210F4C8AA00008562A116A3 +:80918000968416160184818121248361822A918943C2811411A0484883243668F0244830A628492452222C8208821694210040C2111031582081C214C44CB418026E5560214112214840842802C11018E441329883822682D181984244469828821285342128425C0221442A588480C51483618441413014142C122C04811002803C888466 +:809200001F6E012604C0681608C02483111C051880228204002821802164C8800246186291200181A0422142800122831424288113888141242124420418BF1B0F13C4122216342449628183880412224848008061412823816191005049488444002281181A14826182C02480611120A24220840188185048108821F85852E011D642A128 +:8092800021A3E2C16442C1228150812289954443A11A83A625411819A11416C9486240EC423421CC82941822A1122A19A6212781524C02411741421A621A80B5180483C816188744284A1888F855993084106241228041AC16C418000084003822A90A44105884164118C842302480418404801264818B1412228480C41245081218000070 +:80930000458849F8E33D80042081018504404428538200890144404408006022220040184118010000484410280181821A14A1412004802807001F290118418D241008504230883A044282430441AA24044486041748004192484210088C2101208182B8491118C4614E34D081024214B02831282847821028A8429F54462208616280024A +:80938000100244842245084C1252128423082200254444384425C92211003024644111E484848009811800890143018083014C3818C4FF6D0E122922422631840083210400301E118C24341162134808008400121968212485048014414401501411000040448102C480B884829424F0517D00411850845828282228122116885422303887 +:8094000020023AC88416F82D822211182A24122422921400112A0118139A44302486118483010000800490284814AFF90E800241008041C4188418212921C11C41168C81012D18290224484CA28113018416081E282081E4A304121412812A8418C82C46A1284C812882D148080020F8A3E33024803428A28F48820100624A2804422AC85E +:809480004122536442D1284421142819148864871D144400192902206244801241B411541411C4460100004189240589F4884C008A41981221901850844830281048082485419C820089082A584184608211802402282251144788842A31288A2111081828C901A0144381014C61493844FEE970644A8245982484E04491324941624424E7 +:80950000380029829122839122123D249014214A18041686A283144C4864E1244946A21260514088E2144264112820422812A4128308A74C22AF220F6892A5F828262F89013845C61483D848C1324E6A2443F52C122CF22B545F94F2F2181D298B122C7884F42281226F8434142F86F431413D35442D28CB118A322525F533158E2A9F4305 +:8095800084322113684389BF3172887914F1494453212262424FC1E342B9E4E945F45C31CF86F41EA930348E242CF114184D244F82781488B63AA2243AA68621274C4CC128AB444D28A5843A8A478926752141521689E2C2991847A485CA41819C2863255384524421871484CD999D1145589C1B3113D48489C4A4124D1820D148D4844954 +:809600004CF41E97244E1667224F432234288F4552281A51844FC165A4AF8194188F81D18AF412854FD2611D3E5245F424964CDA8CC38A4D249D6436A54C1F11E24823F338B84741285D144CA321C57238E18CFB155CCF51E341A26C17474A21B22865111C81F148788B216AB88CE28132A8AA8CBAE70DA012A012A094200488C082122C21 +:8096800008A813810A89228122093388921181B08802822A0114A01284490922204288088884888088840854E04402424D5D70847626F41E2E6FA1F452C88F86744CFC6E2E2B644F48E68CE624A7CC8F2CB482F264563F5CFCEE473719BF3E15F2249455EDB2BA66545557528B615F5AFB29476F749CA24748CF43FAE4E41F74546216FA89 +:8097000023279F9D56D5515F58F885DC5F53F148681B18CE9857545D149AEB8CBC24B294A9E4CF88FD8C888F88F82868BFC2084F61F2466EE5FC366E6FC5DE88F26C3CEFE7D28A76CCFCDC4E2F2CBCE2BED4748EFAEECE6F6CFEAF4F7F3CF66747AD28E7C25D25CFE3B344B424DB4484FED5955F7EF85FF55D954748CD8CCFCFFF61476F16 +:80978000F4D475D233D2DFD4DDF42D1C5FD8F884E55F4BFAD8E49B2A1BBE5F48F885841AF1D8D8C742CFCBF97DFCCFEAF8CAD84F4DFBBEDCFB28246D266F43F7142665F652744F436261EFE2F652781EF48FC4F4E8F24E788D8A2F25F5EED6FF56F56EC72F17FDEFDF7F5AF92E945FDAF925BF7BCE5D855757DFD5F625259FFAFC7757EFBC +:80980000D8F2B4244BA3BEBC5D372F61761AFABAA6CFCDF63C3CCD2D5F59FB59185F5CF848441B919F8DB3D1F915143AA3DD4BCFCFC1F1484849B5B6F9A8488F82C5BA242F2DF61876EFC3F26E2EAD2CCFCDE763F33E7E2F81F75C9C8FE3B772F798BAAF81F9525AEFE7F5FFFFFFF7FD7FFFFFB7FDB7B18FCBF9B5B5CFFAFBC4C36F53F2BE +:809880003D7DDFD9F7DDDDDFF7F57F7FEFD8F2BC3CCF83FBB1BD5F72F23F77FFF1F19FB7FFD9FB3D3DDFC3F3B5B4CFCDFE7D7C8B759BA29F8DF71D5C5741BAFB7878CF4F7C2CF878FC8F4FFDEEFC4FEFFFA4DCEF3C072B123026844184221E484302800448248CC42419C42413D848024411286044A02419912849111804182002618440B7 +:80990000E81228286288A0494482289E488922812228045FE30A65022542A4165028C4428CF2281210082D141088D422011C28C284864834221041110421204204446182811B416041411A041118008081444458481A5448F03E26E022F4112487221F41B248F11124A3D441B24AD141F24A9219F24A9251AB9443F24AB143F242B147820F +:809980002DB14F82C4B14FA2D418F8264A1E216FA264192FA2E459C24A9E242D4A1F49C2421F49522C1F4932481F49324A1F48B24AD141B24A9921AB9451AB944B42AF44B924B4427924F842944F82E444F9244ACFE30747A21B418F22D141B448F11124AB141D24AB141D24AF64F91124AF249A258B9443F34AA143D21A7B34D812FA17DF +:809A00004829F224588F1491C68D216FA27D98F5224ADE252E4B8E242D5B5E2C4FB2A468CD53CCF268111F49326A1F48B24AC12CAD951D64ABB45D28A9A943AD842AF442944F82F44A1463F242B44FA2F56527402888040000004004400100000000188008000014202182080000000000000000005012F06BEB10022B1218244C022220E4 +:809A800041284201852521628119C22480926811405832428CB22401232104224A4145C821189014424115484838488C2484842168424014C824829EFC20A5285028812C24A1818314848441C88C21264C2882085218802204408D7842C82124004200100288A0218A2219C1111854144CC2A8541844424031449FB30852E6A22184212805 +:809B0000122A1118D4842462128728512E148183C281C0521A324832488728D0439488C426321121102874444128021024C6249445012E5884193464823034444D428426E54974940621001285C2442188421220111814488822813224002811001484282B521420044A820124111882181288928117819045008933850000004F440D00D0 +:809B80008280080088000000000000000000000000000000000000000010010011400170E705502219214114CC21624115BC22C161128E822518B85415E322486148841A9B4947586AC122129493C44823584C18284A2C92178FC184A82E145044250A2AC611859AA24AB42411E2210887481E18A8CAF42D2A90226638114C312C28544214 +:809C00004125AA1148268178821A98144827238A48A5114E289BC814444542B818031F943482812E1649928252196148499828146614648129A342348A184298148AA4832425A4112845F8AC72002008880080080000000000000000000000000000000000000000110010011400775E0012100111421781604122111001004814800398A3 +:809C800015081181209114404A342400822D111098411830421280144218A8494058484181924A48F8D5893426042642FC18248584212211A841A3E581745C021218169C888B161D48196114444110C24D91284364422A3112184616443428294112881B91818011691113152891922229A221428441DBDB34260428414902122270188424 +:809D00009212701102187048748831488B24A094851114110A9CA1124289024C026068118123612480098E11205581939159898481C1264942A8584E8844FF510D204112C9189524941912A01493B448C14C00181880C31119411104009744101444343629217144024C2142189118282D41001002A081D08218082A0110F8CE5F002394D2 +:809D800028806441301830481C17CD12001810044418CE12125681464168848C4428C141460228AF4423043880220118848481440028209414451218528483F1B8F120A225001828842200302400168822842202294872245128242A69210024404984028148812014082441447024820248108801006112127F960B4840C128103914E05B +:809E00008412428811CA4480186484122A114108000041200580024400401108002AA41418588004122002424880A484EF330C2229238282741954482A61862D481D488D21833146892109CB241828314E18112C0425911861608412812221446906841B128122002B614684A1142180840178431114028D548C78B7094850188418281842 +:809E800084002A21110220624480321498824C53814A22028C34482C0148462482820100428418106481818C02482012088034484180E46D08411100811412405841840091CC014061415E218489023445D8288142028522014508120015247411480224118148241005901444634288223148F0613D20011011C418488922025844410010 +:809F00004782C018284400240040A24A8D16408A215281242800329018008324911400200423C88820311A8140F25B5A0000498204701891162850811008100820818194148941280684A042404CC84260448415082810482441182A082480688400448694441282DFFB061128932214D14852818624021128CC8501814931284260844199 +:809F800023E252841184420480226411602484444846841482049012005821984400C81842308242FF21038A03109C34411A2202890228180022482621A2242A614248C302A2248F216222368224A44100224441188984C4386012428442444A8194442094748384B31684E414F182A74038244412004441811480854404462443041508CB +:80A000001429014342D48408001829018F1104800210A12144893248288281004C8121240222803816A3F273CF14411448260113270400284008468401101404120042421248C18420C2210084B0284488013304002120241801418AC18810082D88D021084A2234288168802204A0248C0112008024049052538224428224210342001230 +:80A08000425884400414184A210252884014A438184304410024889F4B0A84003018400C0083614480C21848C30214C021859142E01411D88448048032244D41241284112A3421289025D120048744821D228230881281203C882504CB31145B42821538115B368D389742148185F161288B34421CE145D188353885F82445283CB211D15D +:80A100001412C8255845F81A6229325223B142D644F211415823D2896242DD14683B341FD1D149A2442B312181D02371C3A4829A782488E1A271146A898FBD28F2BAA8C0241F561218C44C625AF7247284418B1136694143116C464D184F12A4247E158F82E59266434B2226686487244F8268E2848F24F3281487868B1427245845D484B0 +:80A18000A24442163A4A4D4A9558A88F81E888A881444935C44CC592C7488183C8844D54DEC8FFF5091A012E248FD6321857514558C83E241B224848CD58854898244E241B21125D4812C7444AF5435DEB44CF8AF232244E14CB118F22A24243A151A4124E2450193AF23919B02426E113A2444E544E424B444F14A8811E16C784DE446E7E +:80A20000E847456ABF4C0525F27938144245011C41480100140040840484441110011110012181290829010021422601146032601260221A4421488204800228009028DFE84F21D451D2CCD2DDE7C4F44165C7424F4254881F12F25C583A31184AB41CF164244FC6B654F138184F43F1341C4FC3B114312441CFE2D2ECF148228EAAAA3A57 +:80A280004AE3D54454288B5558474245F41444817E526F95F56C5C89F1482AEB8917141551357F11A3888F43FB1C344CF19CBC9AF95CD48E182CF2EC49E044E244D2CCD2CC66424F44564CCD6445F42424CF45B718F73834CB45CF81E243F374745B35CF837135F4545C77834B351B568782CFCAFE161487279E9AAFAAFA5852AF15C4489A +:80A300008FB4F45258588C54DCCF817418A1554F84F544544E19428F4CFCC9491F1EFEC5C14BECCAFDF8F4CF45ECCDFDC4CC4FC9F9DEDC4F88ED89F5DCD5147AF425658D28DFD1F35C4CDF56F66C2C4F4656CC5F53F3585C8F83F158784AF45C1C4FC6F65C7CC75797934F53F131116FD7F53551CFD2D111E2E2DEECF5686A2E228F83738B +:80A3800048F84C494544E285B512F72161D5FC111519F1717BBF95F579399F83E5A6F39A9C8F88A86455F393914B88CBFA4F43E346F528284F4AF94EC4CFC4E426FF74D7145F55D65556555FD7F3794DDFD7764DFD5C78CFC1F31D3D9F57B738F35C78CFC5F57C1C4F42F65C5CDFD7727DFD35359F15F77D5D5F57F76D4D9F92F224CEEF2C +:80A40000E3F57C481AF13A1A8FA7F55A58CFC4F7494A2B552B319F1252DD1F15F371733FB7F77B78DFD7F37153AF27F3DAD88F88EC2CFE17173F5BF9C4D4CF4EFFF4A4CFCFFD2C2C4FCAFC9CDCCFC1F9E8FA2FC60E221044382484436281002216081A0412281A84028922E1440289028744D048028324022014042280C148181E4820010F +:80A480004820482449A44885042049048F9A0C86112112011781202152C1183048109844C0481C2141954181411448286D12A0121225385820110214150C48251181E181941A001A54122A041290444A01C0417F330A3CF4112485F3112487141FC1764AD341F24A111D24AF149921AF1419F54A9143F24A9147822F147924D812F9244828 +:80A500001CF9244A1CF8264A87116FA2641D2FA264592D5A9E24ACF4D1242D421F4952281F497248F29124A7241F48F24A121F41F24A921B61AF2419F54A924B42AF2439242F2479A4989A4F8284F9244A6FAB0CACB11156281D64181FC1522A4C92181D24AF44A921AF448BB24A39242F14698229392429F9364829F9245A986F827C183F +:80A58000F126C85671226A586D5B9E24BCF4D12C2F22E44954289E64836649EB1686B4687191544A1F41B2489325AB944B424A19A4B4848D346F8284D926D5A60200480000008240042800000000000088008100140000000000004004280000000020F4B49C30240020449A1C19642324C0488CC1144283A4411243883815C04C44002850 +:80A60000228129641149042B424602248061CA2220F1211418304280A4484D5A87414B41A997488D249018F0A5AE003F28624181841F42018516189C1822406A211C01158885260622C028A0144508851412A2414D182D14523287424D234A11F4122487428984288521A418148022084301411483F4FA8D40661623113848851344C32AAC +:80A68000C12062C2CD124A31484883614C2ADC340566244128A843818146581253846482A394426A21E24162CC261462C35B25984725582A2431418CD1C2C1928B164E1847A2448483F513AB200241001E2489C14C18901A8C840124138111810128101884023024102611229156168401E1112B12B024018100008A84984428490441006C +:80A7000018F0824B4092214054224062C12244002C01188414843021142688C24842111261460581604D8052241A0240020080048008814B491812892368441A44048F984BD1526141828962838D41C4D05AD118D48272623A481D164631138C6E64C0444781B0C101112674227138223248636561224E122440C1324331242E4244242403 +:80A780001F22F1881118B9D121C145248F42044974422CD384C81850EFD04131228849F21A2248106692E42846784252241215F84128460A4E214D11284E218314012B21E3E1443248482C812474224282211242C22241004E111818881C1188D98482F1483489BC14E241484CF2747F10D241018110496C81693141812992181CC14129D9 +:80A8000021180441818198809425112C1241321C41432B01412681C1144C2204502228A718249C01671446B412042441428924015FA745E244622516182C4424012041A824124698141C0148243265682241818051218C1822A21216810448200438AC4104886A28024D1860844887241014082658824C81F1E79B004A027022048324612E +:80A880009128008243410147818484204A42C81226C88822128441501818D081A2215211812324C1644611284118844284018842182814294828E14A05400412103A24240040180A818448121A0420844144C44418481A024140240121C0140028882C62112011210820911C8C81041C0820F4AC8624441E2421C9D142524A8F41C41212EA +:80A90000328428A971541868818CE481C44232678268C445CA24C9D42123C138224181411866A1211853D128735802AE44823F83A4210082C3A4417012D448351822848200EFE20E2A0489014220028501C04888C015114C0189018880018100AC04411A822105100200E0410219860889711108001E48890842804AD84881749C0D5964F9 +:80A98000181844895494114FB21414141108644485851424140520044A026241480022004604412243241402290C2112884261182D426A88942280120A4D1A1F290C004008184418281800521321110226518129010068414D42200916021628C12220031210088305AB244C28049858001288800418009FF3042048342800421842148C1F +:80AA00006812811008111200A0410028002290522004004240041842210080881C6224C01441A086450243A4814AF8E798203124813143219618484C8282618121002633184601AC4261C210042688C842004604C064202182044C02162482239822400442302800A0921A28027FCA024C240112100441608480324252100AC1111304B040 +:80AA8000442A22448494142314843818288006C028188C94248448483880820C4CE142042A44B4289814228423F2AFF400282AC1226850840049828204604416148222D682612210924A4448002242268452144004800110012C213144184C11180420881188812C8424F4977E1429021032881A826482481961A500C018F0182400224914 +:80AB0000840400242848800200408282024400232242040040028284808D04818885F49BD4A0128222200222200100844180024822B011826241418092142818801301802184013024181004402401202C1104848E1180E81281F8E85E5082444D486412C681018148E041248102122E411818437442941C290218818821412410424102C8 +:80AB800025084C8422812406442CA12444182840A2414901418504A502FF554DB15434A42A3212AB91493134C741429B54848F86F21848407634341287128572116A142E444AE4C6E246242684013E528E448B15442E224E641A0318682E284CE282A5444E685AA371388B1145064B462B234E424786176896F4224C3EA14F82F4DB47249A +:80AC000027428E2147E11CA2264EC1CC85D348F534254A42A1144751CD18A5BB4C7345B42195385F623348451694248D4C1AF676C43A64443AD28202424311A221C321714C64258F4562624F43D16438A2DE82C24AB45489F84C5C188A949458DAE998D522F9E1F2C031169418C7E2CCF4312C87146E4B4B22F098112F2115E22421953181 +:80AC80001F92A4714E216F5694424F81A3B248D0247222C4222764103621384425A24643E24252441E52195422B825223844D0242CD122E461A188439BB87E48CBA2818572C8F483C714800118400120410100002400122412200100184218800122A0124218B024012E124002472212224082C4224828C024800228EF35470122CB212EAF +:80AD0000628414C5DC44D2CCF224258B4424AF84E444F44444A5B1220247448FA441F42C4CAAFA386844CFA4F126266F211C62236F68F81928454453461A64848F8112A44495FB1C4CC5BE145164008F84F48496684D528F8CFD54146E889788A285F81898CFC4F42AF314126E44CB22CF62F6645C6E414FC4F44434C784CFD2F26C248F7A +:80AD8000A6F26A6C4F44F44C6C2AF26F6D9F93F26464ED2C3F54F26E48FAFA7818F02CBA6F66D226BC62F664666F685A99457424764E9E428C54C84CE44651FD8558EC6AF414866EC48AF868A84F68D94446F29CEC188F84FD9C5C4BDCAF84A4FD4F8DFDACE41419A543CFA1F232288F85D419F22D48CF83F75C7C5F16F6494C2AF24868EF +:80AE000085FC4C4CA712BF96F664455FD7F3611B9D5DEFC1A5AA8F82D7C8F46CCE6F43B272A6414F63F49E8CAF91D244D264F2162C2B451AF418284B338F84F61B2BEFC57446B616F3C2762F49A3748F8DF786966F41F52652AF86F5FC1CEE888F9EF8B4942F8EAC924D36EF1A41B313A773CF21F37A32EFC7F17D255FC6E486F36C38DFCE +:80AE800092F2693E2F26F24E788FC4F4685E4762FFD6F374155FF7F3723BAFD1F73C7CFAFF6C5CCFC6F67C4E6F47F3F2722F23F37676EFCDFF7A794F42F224266FE7A3558B31CFC1F374348FC7F37F7FAF85F556762B772F6FBFF2AFFF8F8DFBC6D66F47F5E6B6EFCFFFE8388F8EFBFC3C4BFE7E78EEF84F2EFF3DBE10022210C44843C2F7 +:80AF000048221E4826A241C0484416C8248CC4261904A0246044A0242014221402201402004110A441800482A041449A041A442439489220D8F20A824C1248342213010015344828001811215150848B2441205248411086722402004014820244418C148612A64929818401215042862854844248C04A96083CF4112485F3112487141F04 +:80AF800041724AD341F24A111F48F24A9119F24A9351AF343924AF1439242F347924D812F924481CF9244A1CF8244A56F1244A96E1A26459ACE44DC25A1F4DD224F49124C5F2912487241F49724AF28124EF24F9112CAF249921AF2419F54A924B42AF24B924F4429247822D944F82C4944FA2F4D3E4C05A4CD628C5248B141F41724AE2A0 +:80B000004132481FC8F24A144CF24AB24D28AF24B925B4483935AF2438342D816F8B541A4F22C5914FA2EC14F8245A86E1A255586F326D5D2E1817CC6D5A1F48F6245217886A7181FC42111FC8B2667911F86A8415A4B45F88921A4994BA49A4B445C8B42D484CDBA6D52F0D004800001200400428000000000000000000140000000000CE +:80B08000002002280000008240017F2F028234128CF22B144C81D184124C92180050525E28841D5882124152899C44426042428991144B242089848211141638744C92424D411B121A2C52821221430C44C8A24482C04841AFDB43832208234112C9A8002014384889C142148052842E44844998111C024224180084428CC228200422266F +:80B1000004840040A41C428883084A0844838121012661848FD209297241226181275327518B21261C0C4945287618524137868193918478A44B414E915B43A048B0121448346819A4288C96281A644428C44A7328844434114E944F222464238938448841436482412C099CF21844FFC50B00242881848200100A812024012A141844240D +:80B18000180842C0242081410483010010861204211924029884888088048298120042246F4E0718000044000018000020041400000000840000001180020012000000800400000047828074170600004211A1112508A348480840460110C4114116140810028014C242430223813114A45912481102944121000080442244084282C4BF5D +:80B20000AF04000048340081241E888181004413041441131144440824100846020024111812814942981121501844008004008004C06860445F390E18000041841502000000240000001200000000486902183024241100004002000080440281402418D84B04112200212004805228001002840018804208424840081800000000002869 +:80B2800042121A28122808840044001008007F1A08001A0240080000001800120020230481840000490418208104A0210018184028A44842004888202102121A02229F290B0000004028012001104401400A002288008441002228000000804208842889010000204108002006CB9E4081020084480022800112448001241832628486187F +:80B30000284448084C0412208104A021208281048AC278C20080044183810289812284F22B8400A01210024088018502002111811008002820041004182822000000008C8261818901818A0484208801002081022FFA0B0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000015 +:80B380000000000000000000000000000000000000FFE40F8004000000400428000000002180018800004001400848000000004480020000001002183F5F0B0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000A8 +:80B4000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00006E +:80B48000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40FEE +:80B5000000000000000000000000000000000000000000008400002001000010084200F0D12E604100221290248904180011811210048111480080028041E618810400E041020011420044882800004A218841880940086E3F24284100100880120A8180150128830542260822800428A04260222200241084011082335822188001892825 +:80B5800041088820840200DF140C164404221230248C2402101841C811001038412A0428A0240018641CA92400001E244400118033484922212201838821212808422200F0DFCF302200008400241608001A04C0241E480081000080024A0230220010021840820412200800008C041281920081D09808408461412211411B410021124099 +:80B600008801211281820046618210840228002904418081824128628140282629A2410018480089084C51848141AF18022816424828018913C82C1AD428420211814C3121872449D6245594188460C4211C341219A4218B242E1284812223220800424C818421048890441C5848281E4C2A91588C26BC4401BFA606222031180084004662 +:80B68000022901141210622489A24815880183724802241828282A241448042282188480112424A2488004448884224A913848362888019EC2006C41488413E142F111484D281289022184814391211698444311069C0444414E21304118842B2121842829810280924818841A248122094819C144108C38184C7444D84844D4E54501428A +:80B7000083A112D08162812A018071248223041846081820C1421184221CF14812188924048394648430282367212A91448998882846382C28412A018341A2144A61881018C218129766202444044844405228260841891238141004840047281242B0A285028280422101288961448484102202224212C12200228D24C0342210021AF46A +:80B78000844FA012184012042A04284126480851001004493322840000400683212102211800004004000080C48448200820248802846E58A0251841244C1469842692286D288371281268941604CC44248121D1849811602266C122418183A4218B422A15222102D0820249E88822B22824A42181428624C122C924B184A3248C0840F8AF +:80B80000E2590090181A024CA21212002280110412008143922248C0480083C512C218004484282CE14192181247248400C02C00183048808B14082092182CF46DE680014C323149C12811441AA22100411142B01C9218818441212843048B42128302160884281E68208122A22162001B1431D0480C27448081041288188302003F1F0B85 +:80B88000242C1228044845181832420000182E182032144100841411000000200100901800444285C4584081216991260890844820014622F61BB4001810D2C1B2111411C8284127A1181884130221412440C8282280846182A024421842005E28480010881238420012A34608481008100C4141F0675900804208002004C08C6B8418A12E +:80B9000084402802290124154808112C840113044200301814000012C021400400824A2982210381008DC32018042001201164838036182021A11244896411328C02C4003048400820A12120850228004210018C018C024816280286584881806114AF17072E189012122143C14A402284022EC228B02114044400C048008004814818221A +:80B98000001A02A04112324840A842846218E084122892884AE14482C4248248F0528A0023433422422648249442244244210044811901C3524240011110C121111C11C118284840210184118D211041881681621486014858268401824120F25A4F80061851A9022449854188A11490118084240218005242801208220042000000814022 +:80BA00000810022210828408207428240600F06E2750848004111120421C042D8424282304003248841002CC35482A081618011A42410884428C048B414885118263D4704225A128608822008091882388F1A118C0328E226D188F32743AC4448794C7A5484AD222B2486B4814488B4447C1CD2449E39271380C265AD187848B42814E4802 +:80BA80007049E91191581A95283618A121818C13098558281782848FD16422921691288CB5C8A97543088B2343C891127FB30C2212F012145B348B1715D242A336AF21C518122F21F51A123F81E1A2A2221679282491162AA24490411E282E682E212D381A112181E28785A251833231221AB548A6446F95A4558B641B14BB648CE5842474 +:80BB000034282E2847424CF35C288885A4442B2225014B412F42E1639221941D294584741E7E242CF58242CB8611624F11B148A11256D86E04A5D818B34C4425D41111F8384148486E28228025A4148C31186E2857823419D11A7221E52AA211B7469B881EC8CAA841828F87EC42D584C188414AD4C702B0220161481C8144224122019E9B +:80BB80004824125C22410114128501000042208401222032411001842200122220022009C02480022098283F790F4F25F674141E221F13F355195F55F51913EF66F74C4C4E546B262F24F87ADC3F14B458F349551F57F528249FD6F5692B3F13E382F231191F9114D49155881F16041F14F419198F81F238288F827239A1661F97D299A212 +:80BC0000221F14B22152313F34D513F37D349FA5F76B7BB7168F81F1511126F8B8F8CF82FB6CDCCFCEEE8151888F89F96A68AF440C4F26F67476C7A29FB3F73D3DDF53F31D14EF47F37E5C6F47F77A7CAFA3FA52F41F35F453116E645E541F53F24175CFA7F21E14AB221F97F34959C9F4A1F98B229F92F829398D199F95F459598F82F382 +:80BC800068791D391F12A37789F2392187859B2697B437243F11F57D3D9FF5F5697BAB771AFD59112E288F8EFE2CA8CF84F9ECEC1E3A65FC1818AF83F3DC92F074626F43F73E2AFF91F257115F56F655596B76CF61D76CF77A3CAF84F95A783D13BF11D14CF1785CD7528F47B768A3333F92E287F3455D46F469E995F969691AF159411FF8 +:80BD000011F148798F87A6663E281F16A6418F83F338381F15F729689714B7B4BF95F37D351D66BFB6F65B719DD91D9926A8F78F86F3E8DC8F8EEF82D1C6F894D42AF781F2F054724F63F53C3E9FF7F15C3DDFD4F65919EF47F33E1C6F47F77A7AAFA3FB5ED89FB1F15B59DFD7F77C7C8FC1F27177FFF7F31E1C9F92E287F345458D459F64 +:80BD800093FC69419F9EF659599F15D411F178798F83B371F771717AA7519F12F239318F86B2697249734BFB7B79DFD7F361633F36B65AD799FD4991FEB87AFF3C38CF8AFBACE44FC3D3C6E825AD76AFA60F4110423822844D12844302400812701108118113D148028304830483048912210483A412C01140011C81048C44A14114160824 +:80BE00001A048A0484200100E0DB094B1A122A711104174120C1121E48229A76422241A1428921C1349032C02141812200285881182826282422018C22C24824B0280124684038484889B314A4A4412841464471CA072E521F41D22AF11124A3F41124AF34F11124AF24F11124AB941B29AF24B915F44A9243F34AB143F242914783AD91C3 +:80BE80004F82C4914FA2C4814FA264154FA2651D2FA264592E5A9E242E4A1F4DC2421F4952281F49326C1FC9324E1F49B26AF18124AB961B28AB9453B14A3924AB9443F242B4478229FB2448984FA2D4EF022E1A1F41D62AB11116CA24A7321F41724AF21124AF6638918F64F215688F2428D318BA24F442911F8194AA7F8394825FA285AF +:80BF0000F925CA4AF8255AD227A287592E539E25AC74D14CFA91648D421F4932649E28E7141F49326E1B28AF46E148F24A3143794A3124AB9422AF443BA429BB3684F1A65ACFCB0F000000000040040000000000000000004001000000000000000000000000F0456B800189418181815114182628B38804874484836188841D18280081E9 +:80BF800020025311889312588B522842424850422826C8186266180C13440A444528317848412A190CCA82F434773024B228459A48158822833214208205458122A341418C9114832AC1212006430228214112268C32262A61821240420852C198584A2189014149CA38462CA1831629F245CF9014522A51148904324C23923C4B218B86D3 +:80C000006A415C4189B288C1184391384D128483A12122AA044CA2122F21827171A412418934644A1126932812A984B64C11F414C116B82241741408833764CCF118C4A42AB198A4255F4E0422288184297111081118000048811228488501200A11001645082044082E48282128830240284208848024240912448228224C2188029F6615 +:80C080000A244400230218442110A82180144808845C22081242260855088042082228220011C1122268810012A0412150228002288648648142A41F13063624B21412CC148C7441BA69E11364A12800160B36C3C512421A24B6446213C027222B523899B4448195184626252664432826B11C14B454D224D585828406819A14282591640A +:80C1000098522B4144124AF2BC6F902425841254426085336414831182018D11211911143824808201283C62C218182847816083284268484C22024A11B44C92442D2CA02412252808482262AA8114548418F098B11418284911889348118F4231326082222044782832C1181CA41C484E246E118444112B4228998424054D423800135149 +:80C18000841E21262C268141810548E0244198121841C09A4A8121B428F4BE6AC02442455241C01B2880012227823885C318141221422260441223C4288951824D482842181E4920018B34623860814488804802492202422C4328248121428821F118F940E144018B12424048818231184981A2184128C3224521C188281461498431118F +:80C20000881A0870240122103844004412224142809E442A81C814212290684A129842481A669C80051D28402422A112800424844410086081422282490200204108460826044A02004042985860814160188004202C038180322483F81514C0214487427528E492911A8081C4282D18214D938901260E1324648A4B244711496442843741 +:80C280008149A592423058438202122228701C32182E58448845821C01C845028B42781E288944B84842C4A85EA9905412141A1204221B212212184C921884441782181A941832208802830488848130584302184AA2424418004488B04801228A86014A219382202483022B34486FDB0D00122004321004812A8121114818732418410146 +:80C30000004A020080024800482A818302920000444244484812418AA11600444781283622F2C5FF00C9024E28401488D228E1288265242C623818C0488651282602704A02485668148601911A28C4D11C984225810100004CC4414429018241144342C884412880280CEFCE0D0085124488810200000020A12100004898004C22711421C9 +:80C380008204114228812280026A182402008022012A0120220444C04242FE5700120090284C2481240148811A0259021100301211121812800622001C02424291481D28B021611422189C224C1104C200849260284618027F7B069222A415081048C82C8D84412284201112440890218005422C3844218062112282902120014982240115 +:80C40000423624051A0619614148A012281822258863127FD7068C06182C82162541842182220100C10041222B4100408224C24889042812C042608180A418124852192154221A021A8202824392444321E4814404F033A100604241840048808494821A04A08219819441218628241293138584014146882C8C6118A48400000028206817 +:80C4800014008E244004824820281802BFF30C32302420420822C0181200844130640080221324021CD21482420180038001484420422482C12200003048C0441A04432124041AF4B14240888104212A21C458683028449024892615CA4418424851332884012C38148D4420826812008C6412484896C168188470B4C1815C41A12888686F +:80C500009880386822282308DF2A011847898FE1E34214B814A2362E182AE22891244E32844D124285CB319D2D8511919243E127D132E424F448181AC2212811AE4142881F24B418E512E61182E212A15B47152A95441C644498121A61411CB8E4E48386AC831E188F2AB224E81813B2AC0F2828D08B92222E141E448D64ECA4278D482A23 +:80C58000A83496D988D242735E24941426628619914942145F697465F243D4475485A8111ED16AA2883D281218A0E1468132512E385E16CF3377D1C1314F1A14B4FC014E8443A6184D444F81D488E623A467ED2EA0432A312445E28654898528B55CD1C8A8172B418721E041B134FC21484B48172429C6612B468E852A032AC25547838F13 +:80C6000082A4664AAA2A9AC52166B2423169418748A82E5C2813B524B283D842B661041B984CE4419A148F49F344446AE24439C24A086F5E01800122482A012200B02228918248A81288848815089628048001809211802144012A113128199418488501458204408584A24900850428A0242F27064F41F114148D24AD4CDF74F65777EF78 +:80C68000C47264FC5C768F4AF212B2AFAAF9FAD82D88EF89FBD8EAAF8AD889F8D1DAAFBCF85A5A8F99F9B1AC25F82828477A7D178F917C49A1661B8A1B5BAAEE3FF712532B551F17F33838CF99FD984983F511195E192AF32FBB3F16374113E259F8D8DC7AF2D8D8C784CF8EEF4FDA88F43C7C1AA5ADCFB6034F41F15454CD36CF62F44D7F +:80C700004F7F77B522F36C3C4FE6F72CBC6F4AFB38388FC4D782F98E9A6FA6F62F299DC81FBDFDCA8B2F25F5F2F11FCAEFA4F52B294F7CFC7737FF91FD69696AB4F1EA1FACCEBEF3AF16B762F539713AF3B4B18F9FFD79617E187E298FE4F3E1E73F5EBA71B721F21491CFC4B434F65C788FC3F678E84BDDC5F87E345AA7DF8E9DA0333AAD +:80C78000F714262D2E9F34F6173F6F47F2743C4F67E74FF77ABC8F87F6587A8FA9F15C9ABFB6F6272557589F35FD422B3F1BBF12F1F9B58B368F86F62DCB7F31F5387957526E611F18EE1AAEAEEEE23FB7B753A7621F13B3B4FBDDF44E681F11F749311F22F3AFB83F5EEF13B711F391819F8DF974F4CFCFF9ECE84BFE8FCFFDA8C8EFCB23 +:80C80000AFCEEAFF6D1FA0313AF71C36CF66F2496B7FF3B352F37C1C4FE7F73CBCAFEDFFFAD8CFA5F4981ACFA5F9DFEF77525FDCF45DD52FB6F2FBF92B779F5BFF6862BF96F62DEB7F76F7BF695F56E414F6B1E1BAAEEE1F2EFA636B3B772AF23131CF8BFBBDD41F97A2579F16F26D7E7F7EFFA1E17E611B215F18F88DCC4F47AFF34F47B7 +:80C88000BF74FFFCFCCF4AFE7CF4AAAEBEAF2D042A010045024184800484400811448444A02480122114C224902800002A28840149014B124800A0482001001A8462894482890228F0BE3DB084819218CC726A6241A021E0C1021A12281128431141024E2119A4B490282084E144F221485222422C9121A0212280082AB1112466412382BF +:80C9000044015C014CA242B014048C84C341CBC7C0521F41F228121F4132681F41B66AD141F24A121D24AF26B911F24A9251AF143934AF143B24AF147B24D81AF9B4488F14F9244A1CF8244A16F1245A96E1A2E459C25ADE24ACF591242E421F49F228131FC97248F1916CEF14F1816CEF24D1C1B24AB981B64A9945AF44B934B44ABB249E +:80C98000B4427924D842F924484AFB244ABFFC04241F41F628121F4136281E64AB1215F44A121D248F62D941D2288BD2483924ADB143D212BB2594922B484E256D121CFA25CA125F222CF9214A4CD2A1EC5CC24A9E2C2E431F48C6421749421F4836468AF6461128AD951D64AB3449F442154B42A9BA24B44A69832D946F82E444F3845A1D +:80CA00007F190B0000000000400400000000100200000000140084002002000011000000000000C0270044384B128C41C933A012D081321812A0142A5C2848842823348480422882812282276142CCA8B48022210280A3821B21478218B042081348728428C9284028A1124149F2AD6F6042860240821102C42829E12812D8485141259919 +:80CA8000818117484C34852A44C8441B48A9A4241014A486482290242924029021172400584DE129A1128485B441A12444241AE64A84344C871346F83575106424B0140225E13102C1F0261189322A43C1438332814817884D621F4894A4846B2193E888222592241E64884C1668178582A6162830214E22282A91644B3443A1A126C88CFC +:80CB0000248B824B1885A216CE2424CB14225E24EF9E0A22442A0189618121A01228819218844CB181542884440048802494422800A025E04882C824000030118811893181258204114E1149042240A814228D1484FFB20B40D42201008901209198193448D048014A31258542482162144578481182021E2121005024C05240421408222B +:80CB80004800A028002C48C8A448008B84A084246FC246C2241280F2324215021F2224F1228630224014D22864822D4A4B42646694141A823222481E4841A9C42CA381324422488AA212260C3F4483D642E188922486DD22661483DC5818EC486181928E6C4A92244DE816C8242F2A0C6116446222722583218621F81882488124490166BB +:80CC0000581AC1211426C451C49C32428C048F13342284224228482A24618241278490164A0894B041C2C859586885F414885A984848882AACC126B241062224180010185122361432214241818934122E442946FC224418222682041A5224402E014164602928450253A3422889C224433862290884881A28022E8428665C848141EF1906 +:80CC8000021C012C028416119129846C52C1A38152624528144401284309847B842118809518008561848C028922748128415861281884C42A11240AA741828344469164849014843BED40384216658149D22202605100B042538124222301A99812B04403A9028CE1882402128CD414524288004AC122A02481163424203288CB61C098D3 +:80CD0000281622A1142A8101290644150120011C02002C011220220820C1481822642200902C004430482081391222604241890288008041816884210088C041004088E4CC083C81F111243D18C12F314271211823137232E22154784582654511212CE349B2444118342E80946416B84811D82CD148318822303449C2388B2415381436C6 +:80CD800014F824188CBA183AC8A9588298ABC14721124E34844AD28441E459090080220220911C44854588088122A1128DA24120021F8A0484898801202422BC224128028D830086342200C0114820C11400484A0200218CD41B0D502424201292122D12812784282308236484AF28042D12682911021002002C84215124502240022422F6 +:80CE0000482280A62180614A488941A481984227414A93141280085FD6030084812117818B24913081C0242302211D2483182C9141128C2258218400820000442250A444400C81402482828158221821B0222194828244102AF4A54C800440688283222122642222D01824044280322C8C2602100881009088A182228428442A8402814535 +:80CE80000823C14444202288188481088028188464484F3B41522114141C4211440110C841110022A0420082828821228800281002848424448890481AC2822C02822B81D82324080028A012242C022A2442F2FD76A02C100A183028182901244004C8888091128180A11824812100902480024100141088C22441410088581008222098E4 +:80CF00001838448021F495D400446021000028004410181808448001A121230980242201424C4431214058840081202284128602C11604822E988026248A0921CED4000010880148C044428004008894422812261182228809808281423824508400004420A828004A3122986021000060812100E30A450200482880A2422800440010288C +:80CF8000120421821008A98282342845486412501422C02881184440049AA442006088401404100418A2416FA84B4389C2422800484001412645C12841004028280A218240820C4042184499884008C82240622446522486024480C2840022822C24A22423048D646014675885420185B81867242F14E6283441D091A244C81F64BCA8186C +:80D00000E841A252BEA222A0218318A82420A11165986844518942F42A44883AE1487228F68262414F64E942AB518A0B4D884B882B988A84ACBC4D962F42A284EAA8448F144F93622C12117A536A1317A42E3126FA28254F227223734456A8265288A44F127362F289A8218A6128218812482AB8227384861442F82AA4274223588525D8B7 +:80D080008C44588266F4C2923AF654422B8226D28C7188C6143E228F21EB62A14123DDA4E841D72846F4B28E502550823E2A8B224D322216886184488A820487C48A8264E1CD585682D1988AF9A98A257AA20A4A56288782874257CAEB22944141288B2228C39224413E64233882CE242B449E821A211164421A62822AA61922184D825FD8 +:80D10000620A000040124132112C48C882C08240023482344001140020048221822182232238268220080030244840584210022184148440087F2E045F4656559FB2F219119F15371AAF84F43839AD41EF48F68F298F84EC5EB886F84A643BE62F1AFAB5B57F9DE911F9B3919D899F9BFBB8A92F9AEAAA9122688F8958A84FCEFE81828E6E +:80D18000AA86E62AEA2AFAE5A78AE288AEB94F22F28286AEA4CAF566246E722B268FA3516CE06BFB9ADA2CF788DAA5EC25FC68788BFA8B44AFE94CF345475FF6F62B2BAF81F548683F12F34B598F92F24A41FF5C768EFC6BE93F18BE867842FCC388AF18B8BCFBD6D88F9BFFB391AF89F9B8B88F9AEA9AEAAB99622EC2AFABF9AAAEF06CDF +:80D200006F4FEA7AA8FA2C2E2E221F7AFEA8288F82F2383EAFEA7A42F2E6B26F6EFDF6E22F4CE924F62AA2CD1A9EB22F6BFB3ADA2E52EE926F24FA4EEAAF86B4F8F95E56FF4748F222267D4595FB393BBF35F53B23B5F3183A3F23D266FC4367EE628F24DE2EF4CAC63F2EFEAAAB4FE37156F2F9BAAF99F9AAA89AF929BA3F28F828822B15 +:80D28000244E62AFA1F1828A6FC656BA6F6AD2EAFA262E2F22F2874729A83185F22E222F4CEC4DADFC4F46EE67BFA2F698386FC9E829F8B2B48F8FBB42F342427F6CF19E982B764E588CE5774AE374F42C66A5FA7B399F34F43A32AF27F7586ABFA7F26FEF2F64F4E363BFA47C4EFACACEBFAAFAAAAB57F36F67F2F9BAAF99F8B9B99AF9E3 +:80D30000A9AA3FA8F83A8A29E62AF6BABA2FE25246AFEEFEA226AFA2FA262E6F6A7A83D78AB838F3ACAE6F6AFA42446F6AF9E2F24F27B6B2ED2FF792B8ED984F43E96AFBFA982BBEAFAFFB76B26BB1AF8EECADFDC49E4FE10D00250126012AC148228C2422088A048C0416882281221908810090284908881004222002418443A2412A2807 +:80D3800029A2482009924C228122099228828FAE0247180084A9012110022B84501A10229822412B14269892126022004224C01250A48B2826A22826624840A88282250266C2242001450880084E824128489044BFAF012CF4112485F21124C7241F41724AF31124AF34D141F24A9319F24A9251AF243924AF74B924F4429347822D914FEE +:80D4000082C4914FA2C4814FA264154FA264192E4A96D5A2E449F2224A1F49F226421F49522E1F4932481F49324A1F48B26ED141F24A9219F64A9255F84A9643F24A9243F24294478229F924484CF9244A8FEA0B2E4A1F41F628421F4112FC116487141F41724EF181244E151F88F24A341B288B14418DB54B422F147924D81AF926481CF1 +:80D48000FB86581CF324CA5E214FA268112ECA5E259CEC41E292FC112C4BC21AD43CFC11248B941F41B24AF88124EB1619D26AD941E6249B218F6439244E924B424E9443B24239262D944F22758D0E84000000000000280000000000188008002044410400000000002002000000200825014F4103512D324181001C61211E211811848AD1 +:80D5000041028372A28C219482200426084902A0288444418830228092122C62822E843C0581C018814241122C4F8421A1C284C028A8BFE202484718831162218D112422902C2110A814811112C18434482A3848C04881E344412A13A1166481800228904100225B824981A882208918A881224141484B125C08C7AD504146532881701204 +:80D580006111382D314D1245416882588489B28E41C8422C48220E324668E848E088125A411F4116542A898222B62241E21482CA434085919C8328C214188B4286A41243B1444A2AD31438B25FE90A2CE441921480414802C0280098101281321481114230488420524811A012008200008012488481B22848042842828892290100424187 +:80D6000089023F4F0A80120481842140028044412814D1123821508444501820944610020040240218001150412C912149080020014026089088008AF46A7D903534847042C6116C0144472116D18241824169C1C4E979119451111800441038444C991620831474143147226189D24285F2C124128B2465C23160A18662148E5262148937 +:80D6800032944C93188B21227F51011524124A4298122901412D1412895421166814908427C253B14801181430444954284964492120818462214C81128422C124EE1423811242018100D24A120386C42C8C412874960A32114430449141210025230140D8C151921909454105840021009014201244544146012115D842141131214F8822 +:80D7000044B422011823D9120461828322A18120A3822FC208222A44140A0041680043224391142004430249412451C2824342A8128082611480448B24D541D218624282B02204450A88C28842257824280246A8412084F485C9109244A30200874216612124863814839A8484412608D048418829125282CA21034C21018333B125142C16 +:80D7800022542240081A02800725418414942418478800210024DF21094A11024116452415180628008100252491112260844842488448101B1808848C223211250418D01C41143C61B08801814100244AC1180060C1F0638FA04243D2C21266414489D2B4D12445628A20D148381C44C322816183C14D58188536C84E24841A721E618186 +:80D800001638288728C3722431717023668126184116942145FA188290884C84544289F1422818463812A0412CF46E21D022014048014B142002A0218918013042C0254118824A8204845A022002581A820425624190214196AC128C26A461308142824426C8244319084221A5045FA6084246044914084A1108182304C094433488141DD1 +:80D880008819C48824928E2840028C223422230C4C3218192928181198220092400CA82412442D1480048428412200FF8F07320020644220A252448001101281018C18810411848C1525418804221CC42400002E148524A124E0140380410142424A02522816A4845022F0267340024502181018842268418458C01849D1E21494126460F0 +:80D900004C48883448151C821134118210484484051B81884CC1448AE1488482040000182842848121812678860F0048186021801402812E82A0182221281820E81318A121248824281860284110C242112C6C489220348186C8442048242244411184089880419882415FE8018E1424244582528252161804248091446094183C44529462 +:80D9800042001C21628400201421C2281604172290238D421F4146841628420419A2411848414924921880432482F81AD9400200441100124F2481016512C1181008841880012364141B18884430124C12224102201288010000802221C8844422224341648110429422D77D10022041F82452902424302800104424684818424C01C4C0BB +:80DA0000844414842E542410C48600804134248035111111280014488084A1849024448148C1DF8804481441A03423446424424A0A60464246A21424524E824221418886180210124284C1920070221414122208851584A88188180082182684880822601A886FE34B421C840444108811042662CA002190428022A1281374131295242402 +:80DA8000881024011150C24115081C4C521428282238301244E0116211100210012821F0493D9016330869745C7E43324A4F8715F28414AD682B895823782E58814B552F249C118F48B58168418BA19FA8C4A53745C78283F4222456D626E122BB12731892842D841EE19EA86F16F214B44953418D31CCAA298A41120145246748BAF28C01 +:80DB000068124E2E8147B28D249F464FE226C442C0122AB32C0189F264442F21EA630127461F64285528BD888E1816F855885A96D417321A38498E4A3C11A41548157485648ACC41F5C4222D14C18FC1F8C2412E44CF97E5463C814CB812C4314AF845D41B944C36544A84D1D892142AC2E188AF2501165444456641481E644F8145A631F9 +:80DB80004A048FA232144B516CF5D655267215F5CAE225B32671C3F1845865F1A64245912327A14D426B983E2146516C6F1418722151243F72C112115E818A3A154B52222EA413A35116E31114B42297941AB824215B8682678A1FEB074A02008A044880D4240888482C88C4812A44A542142242A22022240222C221008230813081B08179 +:80DC0000048E48002008488004482048810448F0AB44C0263F7452622F61F41E2C7F13761A546C2B124F4ABF9CA1988E841F78BD8AF93EF7BF93F325241F8BF9A46F26F1A5451D311F3E762EF66E4E2D22CFC2B2B4E92FFD17B59EB22F437B18D256F8A6A53F15FA89A6AFB9EF5FBF21FAECEDDFDBFB9DBD8FE8923238CEC625F242514FD3 +:80DC800022B166F5B4144F42712CA842CFC6F66444CF8EF69848F044267D6D2465F4AC2CFFD7D64A7414F632726F4BFF98948E98C85F59FD38F27F61FD1E5D6F72F2B399DFC4FE45647F56F7ED5C9FA5DE7BF6EDFE6F63F11E3E4F6DB2F2FEB1911F2BFB36B49FE1F18B8D7F4AFAB5EC8E83FFF9F3F3F45F5BFFCDFCDFDDF399AD8FE8F25B +:80DD000086141AE12FFF96C66F44D764F746544F4EF1B818CFC3F22868EFC67428F8BE3CDE172427223F524432123AF63177CF61F12E362F42F1F4F6AFC1A199A81F7CDC6AF9DFD66FF17924F594FC7FE1F7D7347F54FC351D8FA4F7CE26FFF47C27DECEB294F7E1C73F51FBA4B5BEBE8F6159E27F6ADA23E67AFAAA3A3BCC1B37CED59FB7 +:80DD8000DBFF9595BEA62F41A122CA2EA45566B276F594D44FC37324784CFCAEECC7C2CF88FB5572E026742F55646741CFC6F67F7FEFE4F4363E2F27F7F6F6AF89E189FB42427F7CFC7E5E6FFCFD76FE7F62F8C7FE6FF4F466D55F57F55DFD8FA4F56AC6FFF7FC1F3FEFE1F176567F7EFEB7972F3AFBB6BE8FE1D9F2F8A2A7EF63FAB7A680 +:80DE0000EFF3F3F6F55F57FFC1D45F5FE74BEA6BFAB2B43AF3D1F1DEC44F47E526F676544F4DFDB8B8DFC27248F8ACEC8FA6F6ACBCFF250729010018842A4108122642081A44E28104160892301110111803219012A01290143026A012B022014B1212148422402149052812002880028F130A244465024582448294121E4421C01241208E +:80DE8000582849D422C8484282D084A484844028140463022D8A4426421446084C04CC049E2400184829B814048A9438C0148028F87556E022F4112485F2112483F41164A3D441F64E121D64AB9419F64A9259B44AB925F44AB15B422F54FB25482F14FBA4481CFB244A4EA14FA2E415F2245ADE212E4ADE252D4ADE24ACF4D1243CFC91A4 +:80DF0000248D831F49F248811F49F64A811FC8B64AF98164AF249961AB9459B44AB9A4B44AB9A4B442F9A4482B944F82A4944FAAD4350926EA41D638F4112483E641744ED141B62A91418D9419D64A9B658D915B42AF44BB2194B25F82E4447BA6E854F3265A4EB14FA2E854FA241ADE251F82E45D42EB5D42EAC5C28B1E648DC31E248F24 +:80DF800014E841D612D8C1F64A921FC8F648961F48F648B25B68AF24B9A49418AAF442944F8AB44AE18AF44A944FAAF56D1A4028081400000000800200000000800100000014000000000000402484020000220014F08173802413181229F34C226081421648029042244641028934843014106122144CE14861210030428E112308354201 +:80E00000B442820A482002818921981842C3E88411A82828488644F8DE3FD0426128444D9241D012D12401C52288815442478141854294141E244A514826410E2073428212F624122A7132C41426B445B222280285C6156822521288222C98194C981CC021CA42C8844116C1242F250B43210E4959182E121D7869618143949C162256423A +:80E0800044448110326C4F211494148502AA31121E424B82165442222B212751CD116E83CE22222127441E84286812324181328D9143795488F848112E88A66828449631149F260E2924512E1006411042180200AB14704213C4141288841C1244011C122611A221294184A4286140417428922142200488288D821008852422044C8244A1 +:80E1000064823FC70D2200284110C26C27221A0400001280C4A241442004422682024E242A84F2244812187024020000904122408212420848444825A448308428825FEA0841181E24A5D218C11C5606844581A212149662244B8441641364241304111059821374221A59823721B08692242614032D242C2A8232141252C68C2D29552440 +:80E180004328D8283A182A0528904C26F8AB27400426145A5A44584B248446242241819142183044299444230442904822682632482722122684E14122824242240210A4144249A4418A3142812148CC22E44204806884A23FCC0122181228181658422578229211200282244B4841E012184205144051A214A126354826C34A4B28405639 +:80E2000061808238222812142A918886228211C484828827A1184A2812942481BD2924222C44810215A8421214A0826110471418182288619810344A2F8952421200F08222854524518446A124CC12CE24B04402400211244849612143A1144034124C06222FFB0448690484A33426441421444A81D442830819E24214044149220421B02E +:80E280008901181C04441C22822292184E148062848C86114188248883044028048A345830125624F96485002218290110518256A814111E2842818C7412028991188C82C1AC121C42048322128611A81418821E4224204102448247812A911832841A3818208A3824006800847E8DE022942416F1221246382E5C54A38981611F252255BA +:80E30000C2481D186F8214BC1868821F8AD18492148D2343525289013112A5922828821A26B1143218A146986C5E2459C13818237938A1581698141A98422E4482442B21433544A6D89D082110420811221246C144E081061358682224123014448A0448894888A21246048E244965412A41D4320443C22463028884C0482240820426C89E +:80E380009412421E48422218F02EE42460412146A221444A524821428422C04284207228343226023024C0224C8804237142924426C22C44442D448C01224800C04812002011222128618230442A04841F810815240410284424A1412B181B81C09812B02411028554858E42163898151844186888821628EA812418222A3282874182A56C +:80E40000A448A14084024820082149228211820245083FF24B211402122D42361A982A7022E3244281044218C9164802382245A2242522143224001214124D3825024D2860444004262481812D2298141845820250688C1CE481C824A7381001AD4244004C22C128121110223D8481186044009A2402410048800A123041848840468888CB +:80E4800042014187481400A04829E24411E4449822184084F1B5486028C01A8418C01800481200C042418C8182014C1404430210B42424014384542860446844004220022844214A0120A885920043A121812845F8924714400180944430441826058041848102232512044AA21400002988624224444881006229062210A441818001805C +:80E500004C41028634282C0210025B4F001241302C1842404402268848C88842481420C98814002518A1841181902181298104100228258424081842488A12111484022840082B38004F8E0900181C41561824200228182D4410944241210049018004502410022480240220414224C2144442284A8A88D8822C84948480C8840049888A93 +:80E58000F1FFDD00C044412032124A924640584A848B282181214614229222822F28041845820840064C48B51198228490E21440A82436CC41814084814284040012803412286FFA0A426B488D1C2B414724550A4D184FA6B68191128F3282B1CCF18C824F22F424222FC47428B428A2738B14CE22A144CF549844CD4416382A4D24E5B504 +:80E6000042B51502242B126F8268424F8C624686BC24C2411AB34324B4C1B11489B824DC42A3214B631AF2E2324D884FC8D2A8F13ED414357111024D162F4272487438722AF212142F31F4212116D842C8884C754AB858F4283149D145F8C4882B228BD32CD22202E01E3A224D2423E48164E28FF4FC262A6B4C4B24281B2422121962C5A6 +:80E680004F43B18C2CA15A814666612F28B2943CA485526A1E44EAA1114CF2FACF5024186721918F81B532F7467C5E64E046F2984A218F8DE4217442E841D3C251242B612D1225F494C145B465548425724A562298CE122ED36E92CB812B124CAC228FE1C816ED822D444DCA4386F5482866AC98A829A8485B4C5E14224CE8C8F8241884E6 +:80E700004CB6283834DF2804000040020049082C08002C022484148446454841484168142568182528981282200882A11B48811110011B483081002008820020084FBD4651475F75F11E1EFFD1F51A38DFD1B236F21E14CF81F11D9B7F1AABBA29F18494CF8DFD3818EF43D3D9526EF5B293F998DC9F19F91F263B22C55E5D9F12F22737AC +:80E780008FAAF8C9C9EE663AFB1C8EEF4EEE24F4C21AEDAE4F48FE252D5FD3B3C8CE2945F531372B951F32F25BD94B111F31F136166F417934F4148623F25E18CFC7F73CBCAFA2D22D4651575F71751CFE1F1FEFC5F16D3F6FC2F22434CF87F77FF8FFD9FB82B8AF46F79494CF4DEF61F3465C8FE4547FFF6BFBBBF8BFDBFFB9B5DF21F33C +:80E800002D2A9FF8D939B46AF6AEBE87E2FFDDEE3FF674F64F64FC848EEEE22F2AD7AEF88C8E5F9EFEF5BD975447D2141F31F857D52E22AFCEFA81918AFB36B62F41F934248FA9FA3A3AEFA5F176348FCBF9382A2B47141F71F113576F61711FFF1A1EBFD1F112346F61B356F39735BFF9E122B292FB8496EFADF51A1CEFE7F23B3D6FE323 +:80E88000F196B18FC9F9F7D54F89FD247785DA75D8C6F46464CFE37337F3E412AFF4FF12389E7E4FE4E66CFC32722729BF9AAAEC8B35DF5EEE82F315341E3E3F5FEB26FA5AF84B111F31F932122BB84B934FA3792AFA5A28AF86FE38B88F22F3EF51141F71F111171E167F71F17E3EFF72F342266F61F356547F5FF79B1FAFA2B2D6FB94F4 +:80E9000096EFEFFD7A3EEFE4F46A6E3FF3F3B6972F4FFF6CDC5FD9F9247345F21C8E7D4F7F54F43436BFFBF8F676EFE5FF5E7EEFEFF7E4E64E642F21F3BA2A3F32B262F6F9B187444FC3F17D3C9FFAFBF2F4EEE2FF9CFA9591FE922F2ABB82BBB4F9B89AAFA3F25A682BEE8F8AFA283ABFFC0969012901418CB424412802221648E2880432 +:80E980001244846C0244924A0228200444A02422200243022A0122482248229628A248A041249220D9480285248802DFC20886016041214C724262414E1213412201478181482F240218C0B44800442542642290145269052D58442D42442C41044C024449810480118498442850284128488D1445E1FA0C2CF4112485F2112C87241F41CF +:80EA0000324A1D24AB141FC8F24A921B68AF1419F54A9243F24AB343F24A914F82F44A914F82D418F9244A8F14F8244A87154FA274D8F122CA87592DCA9E242DDA1F49C2C21F49D228F8912CAF24F8916CAB841FC8B24AF18124AB941B68AF2419B54A39B4AB944B4A2B944F8B94924F8A84F9A44A7FCC0FACE441C6431E2C87341E2487EA +:80EA8000141D242B141D28AD16688F549325AF2419F448B343F248914B42AF1439268D956F22F548914F227C58B1247858B1227418D512C4242D5B1FC1C24A1F4186E4C152221E6C4AE1C8F24A128E248D968E648F24D384B24839B4AB844B4A2B144F8B94826F8A94124FAAF51ADA40081800000000440000002200001400880000400139 +:80EB00004008000000004004280000000081F084DA403211144C4111C27322445602A11C91924889128202214C82022440544A4244295142472422984840828181514219628224222C1428714428F12488884508004608F0331A146714A2AC022AE442115E14871425A4412242C14D18133518C3C1441335525311384485822632141242DB +:80EB80002C0124839212644D11702612B418C2524D1216188828821CD22444C2442224C9A718436299F04F3424423B249121190433372347A446F61442281F22B48491188B2427812248486727446041212D66458879142285714502A98A15F4421923E16142963C1A64828C113284A3A21AC3C4548C9A4285042E4C8E1287428A61215D0E +:80EC000024501412221664221E24C14414124088416844130147816413011313881408284904244421282C014044021860321614C2284260244012C484222412801408EFBF064D114429014088110184181062810029030060824284408A420A8444244C02000040012011240160148200400884288444F048F740028816D12254241485A8 +:80EC8000321445022215882401845624A1411242C024230487244446A22483242211D442C414284C93864332141722E082E4489281188C3914DD124344E849A4822A5484131C48F45BB750618068314825381215C2144421109A1800844E14008022441442C22264304241221224444381C21282114111184C4614011B8188191144C8444E +:80ED0000822226048544F4D8282041941200441484102821128184012B1280A114184608262844C84884488C628424491284049024444C22612240A892881883C414458A049628C24884178C007F8B02859654858412082E1418212524B224289249488A01181048384A8442260C4160821284421E448B24412084912448441E444302E024 +:80ED8000481128D18601441E48B0824408231404BFAC45B228C442901A2210688816082D18A48743188423A242421044152215084D992100831441512A822E1385E424423218818110188142040018AA4134442052122184845F2B48212102901245028644810140512200C47014888301205822608258214469342800A02400602100E059 +:80EE00008104484A02118184881281421144181049E146F11422C1A7231A12D48471146A81298171A80216CA482AC9440045D84911288158C23598265829B218D41234284721839A254384622149522885241144081281183D1C8CA182D86C21E88412125484F0D4F9502200100823021444A3028D1319440289A2418D14328034488C84A5 +:80EE8000121408814185C44283842431221062814A0143C4284E11284A88060047818584344800481884CB1B400400421E284130182001008146043448800441480018481846945681382A9458903880054A0320012A044841E042C8248022218202286FB3083A448C822401223684421488218481C11141901C87122AD11815480150181A +:80EF0000140026828414081914814234414048140811288484818100004E821832F0E2FF00401882014082042324042400210000152441082C028100000000482420022180040012003068442384088882F071F5408884961C84C1A304282022321A4442141A020010024B2141C4C034608228002C414442C454280046841342C4940020CB +:80EF800004298882B82C21131812FC175660241048C128484800148C0489014249042119044C0400002A14018034220068008042212424384882482810C4148288A018203814A2F0A12460C14100481116140400009112301843C1142021840400800441444220024A022820042A2102908242214048981C82200600385F470400444362DD +:80F0000048430128448041084C9124504111845D188147821D2619C228261424D24826048183C4484001142001810081141044882484346866184898288C14E84E018286018480041444001400002400100142102121020000C424112C9221414160424141400130182441430200141840015B2D40084984912428120041C04C80420400E3 +:80F080002902002B2180031D84441F44C212A0121C524164CC4186142102228041084E14800248C0488143182E781A42F23E9C50448A3428718CF835484C25F3244815C4281386D441C1184C545845D112C4394F9417E234E454312426A4628B444658286A34224E4C2CA2441D12701504724E444D648A81011B44205148E1A6CC184C0827 +:80F100009BA8CAB128E8193328AFDB082A75811CC43C49C33647861D265024895128857814C24447144B1121C304E044F42C2481104CD554E212C224E08425A24115A4441F4282F22664196222224D268CD48DE84928421844C4C2C74885BAE87C6438288E188D4127C1EF81085612C42C8B418F47344812411E24A0451E481A11387417C7 +:80F180002126D221E1C1132D713DA9111B229C82931F13D344B544D566932889736CD986F326216D592392111C8473582832587022A165E945E884B54CA2E66AC6381E142FC1BA16E282C822EFF602280022480018A012482200001302112811281144150884121528452801121412204121010040010080044800A048A048F09E7E145E5B +:80F20000623F9452441D45474E57515AF625351E141F11A1269F1282F115155E544B26CF827326F746648F82F265664B448B616FC2762DFC2D2D4FC5F578F88F83F11C4E6D568D18CFC5F124266F66F546776B3575F534545AD544F41414CFC808346B8856F21A14C5F21E18AABAD8038F85F54D56EDDECFC6E486FD5A4A6F9345F15466AC +:80F280007D65C7C25D15CF867355AD655F52A3135F53F164649F12D2C8D355D14453418D1A2F63F1567CCFC3F37474BF84F41C444FC3F724245F1AFA646C9F96FE34344F65D466F52B39CFC7F7747FEFE4F746767F11F7171547421F16F6747445F49CBC8548FA424416F23A3885B25AB768E285E78AFA7878CFE4F486CCEFC6F6B8A88FEC +:80F30000A2F13E49146E423F12F42C2CDFD2F26C4CDFD3A1665F57E642F325258FC57151A131DFD1F144544F55F41D1F67727F55F768495F57F56E799F17E596F721215F52FA2D255F96E613D664D7EEF21221CFC2F23C3E3FC2F457477F72F617115F12B241F664648FC3F3E8EC8B119F3CFCC3E47E32AB31C5B652B5C4B8DCA9AE8F87C7 +:80F38000F548EEEFC5FB2ECC8D988FA8F9FC2B144F667423D54CF23D35CFCEF7757D7AF77165385D258FC7F77969CF81F11D1D4F427111F5393B37727F55F76D4D5F57F16D7DDF53F7257DDFD2F22585DF56F4F579CFD7F66476EFA6F21221CFC3F32D2E3FD4F677677F73535717121B754F475788CFCDFF18181FB4F443613E32AB31C5B5 +:80F40000F67E5CCF86F258788F8EFE78788FF9FBFEBCCFCAFFF8F88FA858AB800140884128024120420884804404008D246044400442002004202214062302002216080012004088628828124C0228F03C5C00002084828104202401A014C011112B14844E11C01111202214042E424422C0484CE2121401446220C44483A44846811218EF +:80F4800024348442A08480288128F89C35D022F4112485F21124A7241F41764AF2112CAF24F1116CAF269961AF249945AF247924F84A9143F2429147822DB14F82D418F9244A8D854FA27418F1265A871D2E5A8759ACE549C25A1F49C2521F49D228F19124AF24F19124AF24F18124EB141F41B24A9921AB9459F44A924B42AF24B924F4E2 +:80F500004294478A29F9A448984FA2F4871D7026F91164EF1224714EB3117644E3C17662F3114CAF72D841F44AB3688F747924B8427B24D842DB8494B26D48A9CB528DB4C88DA46D528B2C2E1287584D538E24BCE5C8C25A1F4896588E24EF34B181F248121D64CD921AF64A961D248F24BB15F648924B43AD924B43AF6438A48B146B4A2D +:80F58000AF44F1A4521F18018A240800000000000000000000800188000040011884000000000000280000000014F0E34C002220814121341448AB411440111C98821211221884130415121401372214C28503E04443C4214014449A2860424894CE19123911081812C08216088061424772E012B486511284E71285541421260121233150 +:80F600008223645184281246084E2410848442048B144C9214254424041A6441274238224A81742422D46881483248248864C9F288268161282246C42546F8A1ADC042D60481AD14809414502A51213B82CCD4A58188C1112812458A14C441218E15F0124135245D1C15044CA1145D224E281A92248314C2244E24C494D97918E21201605D +:80F6800083CB8270822461224364131AB61B0F26815212122651C1450366A14120410240880283044A1201C02400268852241022A4424418444180C16824E0242168244824864816C412842426084054847301002D1150124042180A2440031800400140084800D02324010000000028C50200201148081124C082C014008048F85491C024 +:80F700004212812D1140914143614121501881441001263442490143044048098111241223C6142081220245812682B426F81242248223C212004F81C248448E48288481122CF6F4CD806421191113413141A11221405181001120121204488004403241211022C614002800224C122224288591822782120027818C18B284048181888DAB +:80F7800042D50B248C442811029014E14042C826411800411C84415284008C51814068118051120089014A021594482870220621450824130226841464812210222172ED0A2820425182221280031142D094115812122C2292182034214CC2420000622508298412148401101282420385044E119088814321C2428218404848FA94ED24F2 +:80F8000049411441042501121185122802001241891109A9041830288419048301100216880200A302811004000018502281848420014901DF5208110084108814481822611131211018484114441414180828644400414A22012D420060410048781321044048A44120014884498801E0E145231194215508A7121A3418AC0183B1411297 +:80F88000521E81A711818D125D28814D4860838CC22289924444844E2290621289B3444204244783408874646111C1204458488C2531188182E041C81812F0124970240100A1006012842521412101C0141302431192441441830414211250482442241022015022202211820413019224412982344A16085048845FC10510110414001247 +:80F90000008502000018008418110000008100210000104A04204208009012100200000081229FE30B11001721106111100111C011259119210084440048100460C14181C024000012142443135612272130922100210084109C124412007787100140022081015029C0112111211800841021044400814048C22500001214242A5142507C +:80F980008221291802702202000023111442084F8C0F85B849E444E4144141410111504445B424E212B2280100844116522225A2111A210943518400154111518885F848424E4843440427121820514445B436A2220084504840921225A2139FEF0E00240000000000814002000000000000000000000070120414A124008485020000006B +:80FA000000F0AB6A10C848424800000054514C22820200005022901216949482880000111484818C24841402182210411644848202812001400229F196512484804411420410084044C821110020010021800188104408111C424242888144014011021041458202008420021002BF9603904200001001114480028400810010024901883D +:80FA800000004001C028242A44024002004004280000000021C014DFD7032001001001110040010000000010044411440000000060230018002400000000000000B02B04A18B4420041400004554444B2226712801400C40522225A2111A2129280800112811851AB84824A51410020050444534244822128141002440A2114FB60F5088B6 +:80FB00004C8414021100100155B44882020000002421111A818818021240D111021285984448002C014002D0C4828202100800212512F2C66A801102000014400110080081000040044922420800004022021200282400001481001C042100200841446FFC0300100200000091240018000000000000410028240024001002801212434291 +:80FB8000028542080020020070C906230144140040011100157848589924818100000000004420012228234282C11427212C42427122512200101A384140588812800840F417AE00124002411511414801911435010045280100414554544059241008282C0224233122260230140040513214401A02A141800200418F614E42124212129D +:80FC000012014001154111088001000000207224041004004082021212142129F112122C42582311A1A442811800200210048FCE0C6F22F212222E122B111221C0132592822F31F111119B98D659888F18F44848421F945411488558884F84F448444F42B444F22424222E2480524445E642F226222F21E222B112A1812B99C0932592828D +:80FC80001E111F11B189E999F848888B488F8424E48404488558884F84F4F1CFF0262265A2121A212101502229C8131F3191C19E8887818D414A2444511148155988688F44544C4B242A220280425444286F22D226A2123AA1812328082592823CF1131119EC897818B888A444420048848588F6C5B400000000004842282200000080228D +:80FD000002000000000000000000000000000000000000EF6E09000000008024842202002222220000000000000042422084A4444A2404004242000000000000E0F70400002002004842282A82220200220020020000480048208424240400004A0442000000000000006F220B0000282200802484022800000022222200000042004A0462 +:80FD800080044200A0440000000000000000F09854000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E090000002097 +:80FE0000024842000022000000000000484A840400000000808424848404000000000000AF910F0000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E0900000000802484220200000028220000000000000000B9 +:80FE800000000000000000000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F93090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248467 +:80FF000022020000002822000000000000000000000000000000000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F93090000000080248422020000002822000000000000000000000000000000000000F0EE960000000000484228220000008022020000000000000000000000000006 +:80FF80000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F93090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000801C +:020000040001F9 +:800000002202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F93090000000080248422020000002822000000000000000000000000000000000000F04F +:80008000EE96000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F9309000000008024842202000000282200000000E7 +:800100000000000000000000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F93090000000C +:800180000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE9600000000004842282200000080020000000000000000424242F1 +:800200000000000000000000005F93090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE9600000000004842282200BD +:800280000000800200000000000000004242420000000000000000005F93090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000003D +:800300000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F93090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E0900000000802484220200000028220074 +:800380000000000000000000000000000000000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F93090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E098A +:800400000000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F93090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000802202000000000000D9 +:80048000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F93090000000080248422020000002822000000000000000000000000000000000000F0EE9600000000004823 +:80050000422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F930900000000802484220200000028220000000000000000000000002E +:80058000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE960000000022802484022220020000000000000000200442484848002004000000000000005F2901000000008024842202D8 +:800600000000002822000000000000000000000000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE9600000000004842282200000080020000000000000000424242000000000000B8 +:800680000000005F93090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE960000002002802404000000002002000021 +:800700008084840400420000004A840400420000000000001F65080000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822000000800200000000000000004242420000000000000000005F9309000028220080240422282200002222200200000000A04420240400004A044200006A +:8007800000000000006FEA030000282200802484022800000020220200002004A04400482004004A040000000000000000BE44000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE96000000000048422822003D +:8008000000222082020000000000000000424242000042000000000000F0533E000000A022004842800228000000222200000000808424044A0400A04448484800000000000000BE7F000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002800000000000000002024E6 +:8008800024040000000000000000F0359900008022020048422082220200222220220200000000A04420240400004A0442000000000000009F41030000282200802484022800000020220200002004A04400482004004A040000000000000000BE44000000000048422822000000802202000000000000000000000000000000000000EFEC +:800900006E090000000080248422020000002822000000000000000000000000000000000000F0EE9600000000002A248602002002002820020000202424040020040000200400000000000000CF420B000080820280240422808202000022220000000000480048000042480000000000000000DF1A01000000008024242202220000802C +:800980000222000080A4444820042004000000424200000000000000AFCF010000200200484228802202000000000000000080A44400000080240400000000000000DF4A020000282200802406A02222000080220200000000004A04420000802484842404000000000000ADB800008022020048420020022222222222222200000042421E +:800A0000424A0400200400424848424A24040000000000F0784A000000000048422822000000802202000000000000000000000000000000000000EF6E0900002880828282A6242A820220020000200200002004484280A44448484848002024A444000000000000F0594600000020220248420022A022220000280000000000A0444A8423 +:800A8000A4440000484A2484A44442000000000000BF6C02000080A2220048420080020000000000002024044A8404480000208424842424040000000000F05B8A000000000048422822000000800200000000000000004242420000000000000000005F93090000000080A424A022280000008022020000480048004800000080240400F1 +:800B0000000000000000FFF70C00002822008024842282220200280000000000008024848424040080248404000000000000008FAE0200000000802424022A020000000000000000208404808424044A04008024040000000000F0AEC2000000000048422822000000802202000000000000000000000000000000000000EF6E09000000D4 +:800B80008084044228220000008022020000000000000000000000000000000000005FA70A0000000000422822002200000022000000420042004280848404004220040000000000003E98000000000048422800000000222822000000000020044242002084044800000000000000CF2F08000000008024842202000000282200000000FD +:800C00000000000000000000000000000000F0EE96000000000048422800000000282222000000424242000000420042004220040000000000F0D521000080220200484220022200008022220200000000A0442024040000422004000000000000F091F90000802202004842288002000020220200000042004A0480044200A04400004270 +:800C80000000000000006B8E000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE96000000004848A0442822000000802202000000000000000000000000000000000000FFCA0600000000802484220200000096 +:800D0000280000000000000000202424040000000000000000F03599000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248402000000802222020000202424040000200420042004420000000000005F1D020000282200802404222002000028220000000000A04420240400004220AD +:800D80000442000000000000FFDE02000028228004A044288002000020022200000042004A0480044200A0440000000000000000F09DF4000000000048422822000000802202000000000000000000000000000000000000EF6E090000000080248422020000002822000000000000000000000000000000000000F0EE9600000000004843 +:800E0000422822000000802202000000000000000000000000000000000000EF6E0900000080042262280000000028220000002024240400000000420000000000000000F0C1530000000080044A8422020000002822000000000000000000000000000000000000F03447000000000048422822000000802202000000000000000000000D +:800E80000000000000000000EF6E09000000008024042A02000000282200000048000000800400000000000000000000F03547000000000048422822000000800200000000000000004242420000000000000000005F930900000020024842280000220080020000000000200442000000420000000000000000FF9A0E000000A022A044B2 +:800F000028280000000028220000004800004220A444000020044242000000000000B02C04000080220280248402802202008002000000000048424800000048208404000000000000C0220000008002802404000000002A022200000042004A24044880240400208404420000000000006F4F044001482D5900849044610000112CE24135 +:800F80006241304812200110835143A1990181850225C12184808124628148484712804144C22424448761288902009F860A118C51839144C9D468E444D142341214D05811D441D24A5242153A282F25E22211C81243147232C1121483C1153019411C5281401AD118944DC48D546F22D4249224122297428143467822F41862282C612157 +:80100000122C7154F21D4A40811148E28164448440224104851144412142638221812D18D042042001418001C4223125912184111A044E3428295242110060446144504818250800BF3F051011924841002721441003181014082648A4142A04006033301111C480018501400281002418412023D218110885024628220212D024643D00D6 +:801080008414003044898494440044002952248001001212100224204111014008811140598450484862410000282449022122211682F17663000014118110040000804206160422290100215021C01A1181810000004844488442000026442402281823011200304900001400000000000000280000000000000000100400000000000027 +:8011000000000000F0F6F200400900D05242519484848B148185142C05126902440000241D181018022CC412200444812502002816688848004004416648028450844FE5084D42205212843D241605842A9151501250122114672294850220014115120113021A422813C411866412701201265184343024466112D02441E828022812CC2B +:80118000229124A2288773101462A240C225416511C93D8F140129445248411B144C7212792204440044002D18109832846662411691C41424160B2651481428366C846601109A2490248C819212C92282F23F498004141181C011280040D81841484348024018021800154211C12100204102801204240010021C0830142018024A52840E +:80120000008845F88E410040012552412184216012121C013014400816480100400821444522054441282111414082020000A01412250225026400128902CF760B11121818458951411A92248905508250A58CD48222D12C0281528B434042D24111044226781804184381C23218A5521485C4148B428CBA1202883082491168CA844618EC +:8012800018049E4487444F9D03141811505225122532244E1814183110816482188C124808360810C8154014648444444432213410522683321448100220D4223814212D8C21422141D04862448B5700202111D84101161802289018107C1E0284412311A1144840022512042CA4128C0118442838494148410489B2888203881812108800 +:801300004258848120A1C1816F4F02512B2415361448402882812212AC21128120123118418148521421841688B248224242019022B3922400122D242C41011884848331221608C41882008909125FD20D200484810000C4114B422800114A2141145834C122001D144348421198121CA121290181482021C241842850281923042644D651 +:8013800028A118402801618412AFE1470244205242A505100118000025028722002051489024904185044883028100001110180800414022C8918002414C01926044848D555025494254A44954522002411B218B42124052214AC2392781C484414914815218C37424382189342220321222114420E181D21442982290141352281612C574 +:8014000014AB12CC48A41820215148811FD9092140A321818481C0118C0200128180014440E5819438244441164132482283911283410223824201248C84110184A9819488928190121285248178842804DFC80F412C0224998212B2124481098865B2183842005C28C144408118C484548114288410094022493218901420496841818BBA +:8014800012001688424802890158C048F0337F14172214C041448591488551481C82521881548A121141229423222032110090140081320088400810C8148CC282400285826838118E1640022F28011AB81448F4E5137024011121284C8442865424872A28886081828B81C0848975820840482C68428C013084406811101212425424AC17 +:80150000281A1444041028418808C1440000846F550D8444584A8204800600448002C7222222006C214222022302222043180250861444100240111808148091262A013800874830442842FFD30510141216184812CC428D82818D9184A30812242E14882712401464528844C08481884100888019088C029E228082C82829C1281200187C +:801580008A4101184A412844F1D987241038242400C9013041402488322400C02881803112000040442462415022004436042244446C2842242614024311044100C1446144BF99088480041624822441240120B2146288137481440343884A91A2001188114098818249186448008490128001000019E85842111824481888886981F09CE8 +:801600001614200228603400812518041814586245588285043028102812088342A41200D058018420028425182461811284128460485084124B18418004481F840B8C51824880140426024942C2242128256468188025D8E28111028C819284218CD84284C28C94218184215C14DE120281C02100448002101288026C022918F8DF1314E8 +:801680005D11E7121E246E252B419F56744AFC3C1763F45C2D2F8A722B417C1AE983B2A47828FE21242E4CCFB8F48C8259A3321CD248D251025B2341BA66428F9A78883496A410922445D226D282B8187118DE1262211D2887A51B188E163E28AC5162160ACD1EC49AC4114D4C2FAE0A4CC22A10D2C4D284022D2885ED2848E288FB281250 +:801700005D862DD41F444361984F24B823D3423222004B882A5844869128A9D12C92145041A32818ECA351C21E1DC3F925884147CBC11A012391821D11C3B1148858EC124F24AE148F8F24E4EF4362224435C2428716241E624AC4423B12C1242B888A31CC8D437B996D12AB194E843E1816F98482DFC2415A8483D2CA61C845EC986841EF +:80178000A4BCD144F81392E4A5952883C2362F48A2A889C12CA386D2887815D944E848B828514C1AAB881AD1C4D84458285F6D0E1220011241800118800100608120412141011424142416416211241A0212301188132112612211221321329122122009A22003A220027F2A4691344FC1F324245F43F37958DF72F25E1CDF67F33B389FB3 +:801800001FFF9CB8BD21AFEAF89B93EF8DEF36F62321DF52F26467DD44D7C8C5F48D9DDFCAFAA9A4CD1C7FD3F337373FA3F3F8FE3FF8F31A3AEFE1F398988B994F69F982998FB9DB7BF51134FF51F19B99DF78B893FA89833F1DFE8882B791D79995F1A832EFCBF32E282B8B6D3C6F49A3334B118FA1F269A990155F91F731335F62F66934 +:80188000289FF3F34E4C9FA5F52F3EBFF7D7CAF1193BAFA8FA9B1BEF85FD7DBF75F33E367FE6F21D9ECFF8F83D2D9FBBFBB9BEAFFAFAAFAD7FD3F23632EFFBFA7C7CDFDBFB18BB8F49FA1A1A37795F71F9DAD98FB9F91F5FBF81F19812EFCBF98D8FF7C18F68F89E8C9F38F81A2EF5DF9BF29C1A6FC9F1AAA86F4BF81A386F25F7FE7C7E1D +:80190000784E721FFF457316D457F615177F72F24B6BFFF2F23F3DDFD3D799F1BDBDBFDAFB3B39BFB8FA1D1FBFB5F5EB6BFFD3535D6F37DF5EFC9C9CFF58D8DCF1A4B7E762FFD2FA342B4FE3733CFCFBF9C7C88FBB713EFE9C9A77B17F71D164F41D3EBFE2F31235EF43FB9ABEBFE2F31233EF62F35276AF2AFB9BBB77B8FFF8F89A1EEF3D +:80198000E9F92E1AAFA9FB961E6F4BF996944BBBCD1E4F814BF11527FF51F321237F56F25D5FBFF3F36F2FDFF7F74D4FBFFF778BFB3BBBBFB9F19F1FFFF5FCFFFFFFB3F33E327FA7FF3ADFEFC9F99E8C9F81F3A4B5C7C2CF82FA252A5FB3F3AC8CBF97F7A8BAAFABF9A884EFA17186F61496ED56BFA3F37F3EEFD3B3A8FBB9BBBFAAFB3E52 +:801A00003FAF62F33B3FBF3AFB9E9A6FF8F8AB8BEFE9F9B6BEEFEAF996B6EFE9B176F9FEFC9EC8CFE4F4B6AA302200302620C248438224022440A2492049269928128D24828504850410044918081004411006492891841220098444402449048324714804CB9F602815041564241187224414865832118931818911414228048D241200CB +:801A8000814128504880028140948210C228241AC2828AC2121A42A2682C29C8135028C092E044084234DDABC0421F4152281F41324C1F41324A1D24AB141D24AB9419B24A19B54A3934AF147934F84A9147832D914F82C4914FA2C4816FA264116FA264192FA264592D4A9E242D4A1F49C2421F4952281F497248F2912CA3F49124AB1454 +:801B00001FC1B24AF91128AB9453B14A3924AB9443B342792498924F8284F9244AFF6D0B2CF4116C85F21144411B21A3D441B24AD141F242941D24AB3451AF443B14AF547834F8428147832D816F82C4116D581CF924C816D1846415267898C5411E24BCF49824ACE441D62864498724962464C9AB1416F44A9416B44A3B152B244782A3C5 +:801B80003434AB944782216F8294124FA2752B090048008400000080020000001002428008000014008480040018000044800200000000F099480031151255144440CC11C22114188604257812342481261C26B241028998244144004412248480084410684181214C09200818002449D1229148D28A8124F4FB972446258A01A1224868BD +:801C0000290491281D48218631649944D24101824328C9882542022982D148C2A8A39292C0813012842120124114112C0118672880644110C4142688D41819F4D11F304513265141C5818244CA514E8241282E494C082786BD546440666826641D8379822A4A44247124E822D881F31282C0818246582C108812594243588441882A318464 +:801C80002120D142C1128B142CA1858C39543BF5502240032144C064008511C112C0814120D25861822088025024302200850440082412006041001C011840220148445042418BA42004FF1F0D004901008521411121224182142288118182D4180A0050228180D2227118C418800929084D131114B0421851220013581882244800441241 +:801D00004A212844F87ACF702112C521141351268A5322B0521A011216C9421415CABA24D44CC11142341548841122358817268E244885041594242598343E8C12B06A21153C12A911D24A11B18831184A31382662C2422828E79BD021428142211162191890A11100B4241C58218D1123D29434A81621042144A911A2431889948C48475D +:801D8000885016809121892A2138111210B212581829117112981842841283852804FFAA0340D4140114648C1252231A848221B142810489814A0216054051A10040C28A2E1523031880C82475CA1417413042A72648E11295028748200C124B12282D2442228CF23FA810241411C24A3011D01261846034B821C0149250848C11B14891FF +:801E00004447248C2872D8024200144682028934560010A82130122280624A6311D8427184E8460128800683F154EF80F1214400400481412417814382122C6122844C03442D16C011812692112348642828701A118441921842D3C8812224501242844189A143881820041212E1A420F53DE92415424234212002610040081058120019B2 +:801E8000018400800490482588C149000000122B2150168984818201008D413048212484800180F274C550412D24501248274211E5624184189922584216E8527192C8344062818CB14561442558122D488534C21290184582438251429391132815CA68241A64821088E81588F148148E4864160823A124A0242F980829115116288180F9 +:801F0000011448A5C14429414802008D154781544840A8A42212291438228714214200481249A82824442C31112212A0214E1245582850423A0432854408847D1A8002208432382281421305C02442230226521C138484A1421811302800482724A2800A40C2246903800390242024884422042E42A012F2208444F2ECA12420116481811B +:801F80001054224144816C81A421C88AC4484830822A84C18145F24182D0210231A251444324A124118814433A41860124200A12124B2C442C084349144212DC42A148FFD60410439823104188028C82824238142223E221425824C312023022101292242284E024088800C024212100881A02D0A2421442CA24121602000028AFDA4D225F +:802000002602814008548118491882C821154816A14229014841004904806C8811002C04144800141034412A614449812124228412181828542212222C24F8A75420582884240010123C84002841401A04C012202292442902442D5410064180312488858209C048234546810218008012040000841CF26B4F001A82A2612054481F84D249 +:8020800021444184928A28901440D183A6420021A2188521048812282C0100CC115221465141412C88044E884B42441289384888182988C3488021016F5647C11C002092162081A242309846B4826484CA324841800841331C41C1441C02481022061F42247422118124A842214413C2C2004C084C118484124424E9C4732834A4F0E13F00 +:802100004012512214A122214012B88204908100411828C11182442339842248181922012911641229A8124324984443488168841014024384817244422C04490220027F920F460848004601583302842D8C809281211929AA18C092422903181188861378649181282E812185412C0A24A04B4591821C0822660428122120924270428472 +:8021800054A287441FA846A3219718841CD288F2592465A2259FA2747218D2222AE21428B884E9527414B55176A8F212234B2B2C647A1D448CF645624F4448F123C21CF826764A84F621224AF28A2216B144DC11364D1EC16E7E6B482B9843F5D2724D14AD822AB3C82CA2C34AB6D2A8524E481E312B8CAF8B05212723701B02266142D5AF +:802200007144D15CFD88A88AF188887D428F94DE28B25998622F92F84214C846E441988665722431221B793F24D85831A250662F42E15C64494D843F6273A117D65274C212E2167A6CA4422A28E449D1A844F61C186C91124D6823F52234ACCC48FF7D086E4638ED226E5823D28255882FA2D5429221476487836F44E6497121F262446D93 +:802280003A97AE4D124DE84A81F4A1311B61EE81B11425F2A8684B255922ADAA1739815F3231614B88214E84BA5B451B881741282912A8614B4447446B222D66E37834E62251C4C1C7464F22F22A5400400C862404188001188001200912819220016044200112881288522041018190185018D01828918880688188800A888008817B2761 +:80230000347F76F63333CFA2F22D6B2F21D557F67D39DF83F77A6E1FDFFFB5B17AFF72C2AFB4FD4EFC1F1CF2C2427F5EFE61F3FFFEA26A4DE41D914F42FA6AAAEFC4B351F154754FE9FBD4FB7F19B972E767F33636AF3ABB13E1C6FB11361F38F2EB6A3F5E7684E9A3F3F95B3F51FBD9998F88A91FCD8C4F4DFDE466CFCBF336844F4CFC52 +:8023800088882F4CF57C58CFC9F9548A6F524DF341637FF1F72E2ADFB2E627F12767BFF3F73B7DAFF7F7FBFFFFBAEB27F75676BFB4FC4FCE9FB6B676F5E3E96EF37F7EF2B2326F44DC11F975F7BFB6DA9B38536F77FFB6A6FEF32F1BF8F6F55E264F5FFBF4FE7F7FEF47EB49F9C545DFBEF6DF1F7FDCF4B6FEFFF7FF1B9F7F7FF97232AF21 +:80240000A7F956866F4F7EEEBE36F922862F6E5CCEEFE5FD7E584F5AFCD4D21EDC346F64F43373BFF3F319137FF1F15B39CFC7F31D7CAFE6F6793D8F4AABD5AF84FEDC5DCFC5FDD5F17DC37F7FFF23B3FFF3BD22FE37515F1AFB8496AFA6F667C53AA2334FEBFA14FF67517E732F67F636763FAAFC13523F6AF73B3F9FBAF263E3BFD2F26C +:80248000D5D19F22F68183AFCAE264F852122F25F7CE4EEFC5FD74F6CF87F3E6244F44F82828AFC7F7FAF8CFC1F1C49A9F4C43E325F51F37BFF3F3793B7F73F97B3BEFE3F71F75AFF7F6FFDFAFEAEA2FFF1E4AFFFCF5CF5E5F3FFFF7D17F5DFF6BFBFFF7B9F2FF77715F1AFB6473FFBEFE27651F16E22FF7AEAECFF77F26F574766E665F14 +:8025000047F5A5D77F7BFDB376AFFBFBED2FFFB6FEB7F77F55F5BFF7FFF5FDF2762F6FF3FABAAFA5F7D256EFCFF57EDEEF85F1EE2E2F6EF6AEACEFC5F5FEB8CFD3F7C4DA2FF2062D11004042C811844722864861882484441F810480A2414213891201114A02426110024322A4822002254388A1412CA841008004124448004E2412008F9B +:80258000950B2C9421850214121870464148028314C11212467114D832688120C1858E4244A410912820C8828E2430812722442E81C44384929416B84AC124266281C048A514D44A032504213244F0ACB9C0421F4152281FC132681F41724AD241F24A111D24AF249921AB9451AF343934AF143B34AF147934D852F934481CF9244A1CF824 +:80260000244A16F1244A96F1224ADE254DCA9E24ACFC91244D421F49522C1F49324C1F49F26A121F48B24EF11124AB9419B24A19F54A924782AF2439242F24792498924F82A4944FA2F4C459C0421FC17622F2114C83F41124E3068B141D24AF4299418B9649B24A29734825F34A8513D142F236481CD8A685EBA26C512E4887592E4A56D4 +:80268000C48B1AC2CB1FC9C24A9A56281B6983A428AF1661488B1419F24A9419F24AB4512BB447828B9447828B944393986F8294986F22F56544A02882480000000044800200000010020000000014000048000000004480020010080025015FB40F5023441A1221045522C121100113112A836241251204164C042143341A004904214475 +:80270000238421921484004508850449230142200442181034C82840F1AB3214205881418113122302441A088711805128248D21126229812201A22312D4245128368232486810A41829382423116A22182881908221248504450221A1846044167144A8711424C2256C43201632252341211961411189C32A282C6221267412A212412399 +:8027800071A2624A4941022B14221904239418F01284EC82150823110C4CB316186264442830422C41484CCA44167156F8511C00111450181114004C0250181221122457818004458801C04281491178240225E84402442A090021CC02288100008442412400A0842200AF960826011450144001145012102A58128002A942E8440185041B +:8028000040088042082BC20020021812248429488C212122088444C03284448242861828D2584F228151846522014B216C6141C9011800814E28C4181AA44128442844416CC2241871182A68C1C01416921414442D218249C11418C188F012482498841E8CA149BC38941A8982C26481FDDC200285554251E01112341487410025881842BF +:8028800068821829B548A142414C4204444124264528D8860941D04212217122214862488C41848892C8C088414938224B84498248888826F262D124192101241240C4121124141200914A120489024C018440648229220112222A04121818408441D2488141C41812241830128189D12811C85A838166828544F8D3F9001A8401842412D1 +:80290000C03121822138AD14840047241810948818850449E32224022244812A042312686600423228004412608345018041028421894828F16E3924186CC4241321044009416014A81420E284084144130249022AC85840240818100C902A4282A1009011122484622A9448482302218006244C61217F3A0528111022514110029011817F +:802980000021120000C24484244200104224A821820012004912184218420813420821188582684200820048CF5B4221D361819212565825501A1E21415092182D11A1128C4C6641444F12DC48481498C2CC26042388A28189E2820C283826044D28843284394108948962818904288A6162C04A82814C21D4820A21901411001840021C8D +:802A000089845884200248000089138402286302414418442410022D826024200218442B12484612E52441582200222018081F21052912C522A444484481404C089081003840142401B8810016C82418C382088881408418043022201224012221842120B22818042392124C021F9706460200000011001C1811A441430481188140180496 +:802A800081444112000045082008008008928A41C42880822292184082A1818A018C01AF540780014355121586C2221C41028622C84288242648022E121004222112A110829126882170820CE141216441844425040010042247238604A22001A49DFA80221268128741234218173822182392282D883022486D1828218CA2A400862242E0 +:802B000002261AD4280124C22CA2281E222AC4262810028A82321230188932288546288138447064786832841FDF09440000844110844421010000100416044181402402800244C42018840448804224283114001004490240041A0240F832950081E484810083E481C21816482811210281411200200118901440040010341418801404F1 +:802B8000809914488218988048C6128280C11244C118F0E369248C5414484C21E2410211400140014122484881C4484C048889080018400448482284800490884042024E28000020042B8244881096245F840543698960123C01172126443224246028C016C012282C8292248C82A81228290121412528D1C222388A106282212A54424466 +:802C00000000209222284130144C82847244884422F5EABE4082C24420528129026110F34134214932A2412148A118238418622818A488876460212A6828664106A44CE9280681161A24022821449022212110222204904286F271D8246F44F19E3C85FA621815D881F4243117148D181F82D198018A7BCCB524D144E68412A41226A4420C +:802C80008D24188B82E0816281284F42019EBC2E8C8F885488444F41B8A88808C147A316E8487912A4222B2624241064E22FC10A4F4DE82229B148F5744483F37F171468134A7418F31C374743648782155348248BB1A4118626F228422A65611A33444F8438948AA2882961426D48122D1C10E644B2C638A4214D3429F2246425B28258E6 +:802D00004643B184DA62A8112A3B12C554428983E16282F3D424E74863C11845DAB602264231245D2423D23A52826D266F41F2462233F1A34335D122B8125E222B11A7E4ED28E5FA123CAAC4A416DAAA5264ED126C51A2CF23722662286D826CF412AA8E2227A5476227244CD24822E822A2144B1185082E28ACE8A2321647266F8839225A +:802D8000486ACB2C8D222F48FC2AD1000000422004422004800400000000100881001008000000840000888008888008800400004FD444F2576375FB2F2FFFE1F6EB6A8FA3771AFF3B1BFFB6F64F49A794AFA6FAE3D27F74FC96366D26EF67F762622D2AAD2A29F13C9C4F4AFA188AAF28DA2251226FE7F63636E5FE1212AFE8F2A6EEEF79 +:802E00008CF4B2B26F6BF3F63E65D66654666FE9F912162F2BFBF6726F42F358789E92AF2B594CC9F2ACA24B554F49F9D614EEB3AF89F97C3CCFC6F7ACE47F6548F25763FFB6F4272FFD7FEFEEF73E7EAF77F67B72FFA6F63B3BE7E4BFBFDBEBF9CFCF6F49DB66F25E7EAFE6F63A3EAFA2F22A3AEF8BB924FA8A9A2F28FAA2A22FA2B272DC +:802E8000FE3A3AEFE2F1B2127D27EFEEFECECFAF2BF3A6A66FCB57664F6252464F6BFB82822F2BF3F2F22F2BFBDEDC2E22AFE8FA8C8CCFC8F88EBA6F25F7B4B66F4BE92BF9BA9AEFC6F26C7CCF4F7E3446F157654D66FFF3F33F2EBFA2F67B33B7F1BFB7F7767AFFB2F23A3FAFAAF6C3F23F7DFDD1932F26F27E768F23D7AAF23E2EE7C17A +:802F0000EFCBF3B4B48FAAF9A2AAAD8E2FA1F1544EE7E1EFA2F212B2AFB9EBAEFECACA2FABFB36B26F6BFF26A66D26EFC2F2BAB4EFE9F9AEBC4BF74F48F9487EAFA1F19ABAEFE858CECD1ACF4DFD9C942F6EFED2932BDD6FC7F7686CCF6AFFCD15347F15F22C66BF93F37B3FAFA3F77B1FBFF3F23B3ECFA3F37F7B2F63F3BBFBFFA8F15FE4 +:802F8000DF3F3FF16222EFE7F77E7EAFC3F33E3EAFC3F3BEF8BE328FAAF8AAA8ED8E2FA1F1F66EAFE3F22E3E8FA9FB1ABBAFA6FECBCA2FA3FB8686EF6BFB26A66D22EFC2F2BCBCAFA8F83AB84F2FFF3636AFE7F7BABAEFA151EEE5FC2E3AEF2FFFB8B62F6FFDB6B66BF76FC6F46C4CCFEEFFFA93100661846D1148458114C448148E48149D +:8030000082544084442441240800400444189084800888B02408229084C0828226628924822008C02682850442826FC20122128501811A56221E68141E4823A24125024A01A5042D1200434124885822120023624125825224C012864442041E24252201860482184308922D26802101411826FAA132C0421F4152281F417248F11124A348 +:80308000D441B24AD141B24A9921AF145985AB944B43AF1439242F147924D812F924488D914FA2C4A14FA264114FA264192E4A96C54A8F49E2A2F491242CF491248D121F4932481F49326A1F48B24AD141B24A9921AB9451AF243924AF2439242B94478229FB2448984FA274DD032CF4116C85E24136481F41324A1F41B24AF11124AF4452 +:80310000E941B24A5B85ABB44B41AF1438342F1419F4429163D312D924D518D924FC18814D5A96E1227498C543DE252417C92E521FC8D628F19164421FC9B24A7181BC6AD141F24A841D242B9659B24239248B944782184D4829792688F3265A8D2B4028080000000044800200000010021880084200400140084800000000448002000015 +:80318000005012E017042417221014C81146049045248180441802C0124160C200002002401492346041002011C1329024200810084012B8148261820040F8834A1420887812012504110082152218B2810100482008184110044188221A088880088890A4C1880090240040145841440044D0484211F457AF0017AE2C68418444480046C1 +:80320000358491230A1002A0142186428C11048A01268428C282112A0888E08408491989084902491A0484412815044418264462C21425F2924A400210413211411100244082D418090010042200100400604160416041008012A421210000001008A52403840050841F59034054122002250224100288165818122903200222208202005B +:8032800010021810840290142800100190180000400400888281F0E491108501141118163911901812233111000012964228B1443114002542A241C0422C42041818602180711294122C0324821002C0164C5228A8208104A8F01A75101144112102351802242C01191108122B1200250844440010124222441204180010042C212151125C +:80330000244008001861818800C83028F04178406421001418181C01A9011888129100189822186A8121C222005200298201411A021229E121120422008218210044286422800182883092004284100210820190411001237242082A054168400218002400002410021022017022928412008931228051142C145828400424EF750528427E +:80338000110022485C2122C419284C02000045022480014F22882149180812400460110016040018101404E042092C2891284180612420C17E0000144043089445022400000000230200004230224002C240044400100200248648022410121184040000DFFC0A0015084083C4119C512413C1610020C248801422A22418C0822041782250 +:803400000A0041401441042301002B12446C3188508229082918F2482240820140D2890C220011212885422482140821112410024C03250440C2242004001221C224901200442C010029080018431122C114418744849044009FD20D8002121414110029011612281122110840C4140000000000124400C0240021004400214014020041C1 +:80348000210040043B73001410010000130894118E216082216728412880120220080044242200122812302280024034344004004400000021F0C7B5000010110821000040180850820000241800200112240000006021442100442001412428100400125024F0D13E0090114A02008F21022480010081800218241838800120084C1802A5 +:8035000000211A0812A08145021002400200803212121042845224AF170E002200000040010000001848180000224002000000008001002400004084012100000044AF94430100201122011100001C42212184810444000090820040240144124004000044005042800221400212801402EFDC04318004400210721202888716182888841C +:8035800000200840028008002100182828008012240850421220820343810840C41480019F9B0B8286011880011140080024840000008001B08201180000800121220020020040060000416100212114E0D7099C039994218211182903115041212814222124284428502280012E82408201885488448412495C422606210021401482427D +:80360000242821A12131684C5122F0A86A341882124213581334181113092417141E113302242C23C4144C8903001820012C51422241444412414B8144B6522482414512562420C21226B482D1425942244D1121C015F09D7960128215B131021229B133022D1B211D89853881811E18878421902449023A5122602A280012242901982B91 +:80368000212B2A2A434252462F42124244642212242512845144414981015E224974245124DFEF0411171289C21116112851282502111A31228542F928A22187482D3442122124189082F082127086041A4824810116042B1328002421168411524400602216B21242921416445242AD5F2001100889018901890998800998224CA9424C9C +:8037000028031200001220099A028A82218821882108000000122001322002222003BFF944D21393218F81A1519FA151AAA7913F117112FA921ABF19E1A1F1DBCA2B199F99F11812AF8FFFA624674A284F490B2A6221212B322B131E122F29F914161E961AFBA4B44F4BF386842B884F487884F694928EA4442F2858662546A6112B111E20 +:80378000124F2151444F2AB2B6FB34342F23D154F214744B67412CF2926B243D311F9557981F11B51141529A9FB1F1131B3FB9F18F151FB9F9F3F62B199F88F1989A2BFE4F6AF2B6144F44F684A62B221AC112212B2A23E329F192829E962F41F811B14F4BEB1BF31E1C23F2D4DC476869C4226F4A5A2265562265F616142F21F13232452F +:80380000526467682B884F436323284F61F776642AF21436DB4BA0231B621AF1181815F213133F13F21B1925F21A92AD162FA9F94B6A3F31D9BBF1BABAAF84B526B816A3884B132B113AC312212BA223E3217112F2949616F6B4154F48F314966FE3F316344F4BF714964F214144F486866544C4144C11C22265F216144F29B186F83414D0 +:803880006F6153666F42B446B53483B11B4EF233219F13E712F259191B119FB1F13B391F317113F31B9395F7131BFFADFE1B9AB5FA3A3AAF8CFC3C9A6B754BDD4B132B221A4112B2223A221E122F28E86151424F5BF194341F21F9363E6F4AFABC744D866B15BEB26F4A5A666544D266D14251222D226F21F116166F69B1B2FB34146F6187 +:80390000F312136F43F566741AD164F1157330226012843C416812841484348424404308001220010021282110064110046B1280012E121004241224400264001244124200F0111A60180000122400101211080085024C1184210100000024000012808261416128002144000000441012140244F052DAC0421F4152381F417248F11124C2 +:80398000A7241D24AB141F48B24AB981F24A9153B84A39A4AF343BA42F547BB4D852FB34481CFB244A1CF8244A16F1244A96E1A26C592DCA9E24ACFC91242CFD91248F22F99124EF24F99124AB841F48B26ED141F24A9219B24A19B54A3924AF4439242B94478229F924484CF9244AFF9706ACC464241E6C421FC132421D2C4AD1C1F24A8F +:803A0000144CB24A9365AB1441AF1483C43516D852F316481CFA265A1CF924CA16F1244A16E1826451BC6451AC54C1ACD54196581F41B248B11132481F48B24A9121AF44B911F248A453B14A2AB94A18B442598429F91248886D5A1EFA4008480000000000280000000021008008000014008480040000004004000000005012F0E9176002 +:803A80002822000084140018001121008001000000400200000000000021222141001200004C020000418FBB0E30818948011400181110010080010000000000002741800100188008180000000040023011440014F0192F00133688111001140043110114290218004002301220081042624111008120058220110221414160430010C25B +:803B000024131144021423F11D7E400200008180110100000080010000000000001200000000800200000000000000413FFA053011000081000000000022108401000000004002000000005041002100008028020000F0EC7C400200120015024140010000000000000041000043428801181012188421020018400418002122182841F03F +:803B800053684002001840082141100100002240840100001004009026840012240044121742002118400418882200122244E0BC0BC011000040010000000000000000000000008001001008000000000000212800007F760E00000000000000401802520000000010084100000000000000002C01008180088100F0A4551001004011027D +:803C00000080040021000021000000218004212100800100221004800800000040048218F0D636200200001100200200000041100484000000810000002100818400000000001200001800CF5B0411000010020028480050280049040084000000890421004002008428100480080000008840888101EFBD06220000111400000040020030 +:803C8000185042000000218140440200200100840000002C01008901100482007F5A0C0010040081000014000044100400001004000000200200008800A0120000840018004008BFE70F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000000000000D4 +:803D000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000210000002180010000000040080000000000800100006FB70E00000000000000000000000000000000002100000041 +:803D80000000000000000000004759000084008400000000000000000000000000000000000000000000000000001A0E0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000200100000000000000200200006F8C0800000000000000000000000000000000000070 +:803E00000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0040080000000000000000000000218001001002180040080000000000000000F05C4B00000040080000000000002100000000000000000000000000000000380000F05672000000000000000000000000C7 +:803E8000000000000000000000000000000000000000FFE40F000000004005000040040021004400100218808802218001884008000028840000800200004FB1070014000048405588281082044480022100448002214818808802214818448828842148408481421882041E148002211A01445C03000040010080045400004840040000D9 +:803F000040040000008002000088000000804208000000F0469900000000005400000044001002400400218001882810021880088400008042080000280000F0147B000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0044 +:803F80001002400100800400281082040028000000280048000000484004281082044400108204440010F28F41000000000000000000000000000000000000000000000000000000000000FFE40F0000000000005400400400000000440000800200000080080000002884000000002FDD0E000000000000000000000000000000000000BC +:804000000000000000000000000000F04FFE00000000000000004004000000000000002800000000000000000000000000BFF20A00000000000054000000000000400400000000000080080000002884000000006FCBFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08 +:01408000FF40 +:00000001FF diff --git a/kernel/xpp/firmwares/LICENSE.firmware b/kernel/xpp/firmwares/LICENSE.firmware new file mode 100644 index 0000000..b9bb89f --- /dev/null +++ b/kernel/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/kernel/xpp/firmwares/README b/kernel/xpp/firmwares/README new file mode 100644 index 0000000..e423aa6 --- /dev/null +++ b/kernel/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/kernel/xpp/firmwares/USB_FW.hex b/kernel/xpp/firmwares/USB_FW.hex new file mode 100644 index 0000000..01f7ce9 --- /dev/null +++ b/kernel/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/kernel/xpp/init_card_3_29 b/kernel/xpp/init_card_3_29 new file mode 100755 index 0000000..43dbb54 --- /dev/null +++ b/kernel/xpp/init_card_3_29 @@ -0,0 +1,189 @@ +#! /bin/sh +# +# Written by Oron Peled +# 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). +# 31 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). +# +# + +# ----------------------------------==== 8-channel FXS unit initialization ===----------------------------------------- + +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 [ "$DEBUG_CALIBRATION"=1 ]; then + LOGGER=":" +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/xpp_init_$XPD_NAME +## Altenativly, if you have multiple XBUS'es: +#exec 2> /tmp/xpp_init_$XBUS_NAME_$XPD_NAME +#set -x + +# redirect script output to the "slics" (registers command) file: +exec 1> "$XPP_BASE/$XPD_BUS/$XPD_NAME/slics" + +$LOGGER -p kern.info "$XPD_BUS/$XPD_NAME: Calibrating '$0'" + +"$INIT_DIR/calibrate_slics" + +$LOGGER -p kern.info "$XPD_BUS/$XPD_NAME: Continue '$0'" + +echo " +# Change SLICs states to "Open state"s (Off,all transfers tristated to avoid data collision), Voltage sense +31 WD 40 00 + +# Flush out energy accumulators +31 WI 58 00 00 +31 WI 59 00 00 +31 WI 5A 00 00 +31 WI 5B 00 00 +31 WI 5C 00 00 +31 WI 5D 00 00 +31 WI 5E 00 00 +31 WI 5F 00 00 +31 WI 61 00 00 +31 WI 58 00 00 +31 WI C1 00 00 +31 WI C2 00 00 +31 WI C3 00 00 +31 WI C4 00 00 +31 WI C5 00 00 +31 WI C6 00 00 +31 WI C7 00 00 +31 WI C8 00 00 +31 WI C9 00 00 +31 WI CA 00 00 +31 WI CB 00 00 +31 WI CC 00 00 +31 WI CD 00 00 +31 WI CE 00 00 +31 WI CF 00 00 +31 WI D0 00 00 +31 WI D1 00 00 +31 WI D2 00 00 +31 WI 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 +31 WD 03 00 +31 WD 05 00 + +# Audio path. (also initialize 0A and 0B here if necessary) +31 WD 08 00 +31 WD 09 00 + +# Automatic/Manual Control: defaults - Cancel Power Alarm +31 WD 43 1E + +# Loop Closure Debounce Interval +31 WD 45 0A + +# Ring Detect Debounce Interval +31 WD 46 47 + +# Battery Feed Control: Battery low (DCSW low) +31 WD 42 00 + +# Loop Current Limit +31 WD 47 00 + +31 WD 6C 01 + +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 + +#------ Metering tone +31 WI 17 61 15 # Amplitue Ramp-up +31 WI 18 61 15 # Max Amplitude +31 WI 19 FB 30 # Frequency +31 WD 2C 00 # Timer dL +31 WD 2D 03 # Timer dH + +# ------------------------------------- Initialization of direct registers -------------------------------------------- + +# Mode(8-bit,u-Law,1 PCLK ) setting, Loopbacks and Interrupts clear + +31 WD 01 29 +#31 WD 0E 00 + +#31 WD 15 00 +#31 WD 16 03 + +# Clear pending interrupts +31 WD 12 FF +31 WD 13 FF +31 WD 14 FF + +#31 WD 4A 34 +#31 WD 4B 10 +" | sed -e 's/[;#].*$//' -e '/^[ ]*$/d' + +$LOGGER -p kern.info "$XPD_BUS/$XPD_NAME: Ending '$0'" +exit 0 diff --git a/kernel/xpp/init_card_4_29 b/kernel/xpp/init_card_4_29 new file mode 100755 index 0000000..5dda0b2 --- /dev/null +++ b/kernel/xpp/init_card_4_29 @@ -0,0 +1,165 @@ +#! /bin/sh +# +# Written by Oron Peled +# 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. DAA select in decimal (range 0-7). +# 31 is a special value which means ALL DAAs (only some registers +# accept settings for ALL DAAs). +# 2. Command word: +# - RD Read Direct register. +# - WD Write Direct register. +# 3. Register number in hexadecimal. +# 4. Data byte in hexadecimal. (for WD command). +# + +# ----------------------------------==== 8-channel FXO unit initialization ===----------------------------------------- + +set -e + +opermode='FCC' + +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 [ "$DEBUG_CALIBRATION"=1 ]; then + LOGGER=":" +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/xpp_init_$XPD_NAME +## Altenativly, if you have multiple XBUS'es: +#exec 2> /tmp/xpp_init_$XBUS_NAME_$XPD_NAME +#set -x + +# redirect script output to the "slics" (registers command) file: +exec 1> "$XPP_BASE/$XPD_BUS/$XPD_NAME/slics" + +$LOGGER -p kern.info "$XPD_BUS/$XPD_NAME: Initializing '$0'" + +# Several countries (South Africa, UAE, anybody else) +# require a shorter delay: +case "$opermode" in +SOUTHAFRICA|UAE) echo 31 WD 17 2B;; +esac + +# Remove empty lines and commets. Not strictly necessary +# but works around some limitations of the proc interface: +echo " + + +31 WD 21 28 +31 WD 18 99 +31 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 -------------------- +31 WD 05 00 + +# Set tip to ring voltage to 3.5 volts while off-hook +# instead of default of 3.1 +31 WD 1A C0 +" | sed -e 's/[;#].*$//' -e '/^[ ]*$/d' + +# Turning off red LEDs +# Warning: do not send WD 31 20 A0 ! +for i in `seq 0 7`; do + echo "$i WD 20 A0" +done + +# based on fxo_modes from wctdm.c . +reg16=00; reg26=00; reg30=00; reg31=20; ring_osc=; ring_x=; +mode="$opermode" +if [ -r $INIT_DIR/init_fxo_modes ]; then + . $INIT_DIR/init_fxo_modes +fi +# Our register numbers are HEXADECIMAL! +echo " +31 WD 10 $reg16 +31 WD 1A $reg26 +31 WD 1E $reg30 +31 WD 1F $reg31 +" +# for the FXS: +#if [ "$ring_osc" != '' ]; then +# /bin/echo "31 WI __ $ring_osc" +#fi +#if [ "$ring_x" != '' ]; then +# /bin/echo "31 WI __ $ring_x" +#fi +$LOGGER -p kern.info "$XPD_BUS/$XPD_NAME: Ending '$0'" +exit 0 diff --git a/kernel/xpp/init_card_6_29 b/kernel/xpp/init_card_6_29 new file mode 100755 index 0000000..0da1f61 --- /dev/null +++ b/kernel/xpp/init_card_6_29 @@ -0,0 +1,434 @@ +#! /usr/bin/perl -w +use strict; + +# +# $Id$ +# + +# +# Written by Oron Peled +# 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: +# XPD_BUS - bus name +# XPD_NAME - xpd name +# XPD_UNIT - xpd unit number +# XPD_SUBUNIT - xpd subunit number +# XPD_TYPE - xpd type number (from protocol reply): +# 3 - FXS +# 4 - FXO +# 6 - BRI_TE +# 7 - BRI_NT +# XPD_REVISION - xpd revision number +# +# 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. +# - RS Read Sub-register. +# - WD Write Direct register. +# - WS Write Sub-register. +# 3. Register number in hexadecimal. +# 4. Subregister number in hexadecimal. (for RS and WS commands). +# 5. Data byte in hexadecimal. (for WD and WS commands only). +# + +package main; +use File::Basename; + +my $program = basename("$0"); +my $init_dir = dirname("$0"); +my $unit_id; + +sub logit { + print STDERR "$unit_id: @_\n"; +} + +# Arrange for error logging +if (-t STDERR) { + $unit_id = 'Interactive'; + logit "Interactive startup\n"; +} else { + $unit_id = "$ENV{XPD_BUS}/$ENV{XPD_NAME}"; + open (STDERR, "| logger -t $program -p kern.info") || die; + logit "Non Interactive startup\n"; +} + +package BRI; + +sub gen { + my $fmt = shift; + $| = 1; + printf "$fmt\n", @_; +} + +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}; + #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 "0 WD 02 04"; + BRI::gen "0 WD 50 00"; # disable PLL + BRI::gen "0 WD 51 02"; + BRI::gen "0 WD 52 06"; + BRI::gen "0 WD 53 04"; + BRI::gen "0 WD 50 01"; # Enable PLL + BRI::gen "0 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 "0 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 "0 WD 35 %02X", $port->{CTRL3}; # A_ST_CTRL3 + BRI::gen "0 WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0 + BRI::gen "0 WD 35 F8"; # A_ST_CTRL3 = set end of pulse control to 0xF8 + BRI::gen "0 WD 32 08"; # A_SU_CTRL1 = Ignore E-channel data + BRI::gen "0 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; + } + #logit "clk_dly=$clk_dly"; + BRI::gen "0 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 "0 WD 16 %02X", $portnum; # R_SU_SEL +} + +# zap_xhfc_su.c:281 +sub xhfc_selfifo { + if (@_ != 1 ) { + main::logit "ERROR: xhfc_selfifo() called with " . scalar(@_) . " parameters"; + exit 1; + } + my $fifonum = shift; + #logit "xhfc_selfifo($fifonum)"; + BRI::gen "0 WD 0F %02X", $fifonum; + # --> WAIT UNTIL (R_STATUS & M_BUSY) == 0 +} + +# zap_xhfc_su.c:295 +sub xhfc_resetfifo() { + #logit "xhfc_resetfifo()"; + # A_INC_RES_FIFO = M_RES_FIFO | M_RES_FIFO_ERR + BRI::gen "0 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 + + #logit "setup_fifo($fifonum)"; + xhfc_selfifo $fifonum; + # A_CON_HDLC: transparent mode selection + BRI::gen "0 WD FA %02X", $conhdlc; + # A_SUBCH_CFG: subchnl params + BRI::gen "0 WD FB %02X", $subcfg; + # A_FIFO_CTRL: FIFO Control Register + BRI::gen "0 WD FF %02X", $fifoctrl; + xhfc_resetfifo; + xhfc_selfifo $fifonum; # wait for busy is builtin in this command + BRI::gen "0 WD 10 %02X", $r_slot; # R_SLOT + BRI::gen "0 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)"; + #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 "0 WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0: V_B1_TX_EN | V_SU_MD | (NT/TE) + BRI::gen "0 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}; + #logit "xhfc_ph_command(portnum=$portnum)"; + if ("$cmd" eq "HFC_L1_ACTIVATE_TE") { + su_sel($portnum); # Select port + BRI::gen "0 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 "0 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 "0 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 "0 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}; + #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 "0 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; +use Getopt::Std; + +my %opts; +getopts('o:', \%opts); + +$ENV{XPP_BASE} = '/proc/xpp'; +my $cmd = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/command"; +my $output; +if ($opts{o}) { + $output = $opts{o}; +} else { + $ENV{XPD_BUS} || die "Missing XPD_BUS environment variable\n"; + $ENV{XPD_NAME} || die "Missing XPD_NAME environment variable\n"; + $ENV{XPD_TYPE} || die "Missing XPD_TYPE environment variable\n"; + $ENV{XPD_REVISION} || die "Missing XPD_REVISION environment variable\n"; + $output = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/$ENV{XPD_NAME}/slics"; +} + +open(REG, ">$output") || die "Failed to open '$output': $!\n"; +select REG; + +logit "Starting '$0'"; + +#------------------------------------------- Instance detection + +# zap_xhfc_su.c:895 +sub init_xhfc() { + #logit "init_xhfc()"; + BRI::gen "#--------------------------- init_xhfc"; + BRI::gen "0 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 "0 WD 00 08"; # R_CIRM = M_SRES (soft reset) + # --> WAIT 5u + BRI::gen "0 WD 00 00"; # R_CIRM = 0 (zero it to deactivate reset) + + # amplitude + BRI::gen "0 WD 46 80"; # R_PWM_MD: (PWM output mode register) + # PWM push to zero only + BRI::gen "0 WD 39 18"; # R_PWM1: (modulator register for PWM1) + # set duty cycle + + BRI::gen "0 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 "0 WD 0F 80"; + # set PCM !master mode + BRI::gen "0 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 "0 WS 14 98 20"; # R_PCM_MD1: V_PLL_ADJ + # (DPLL adjust speed) in the + # last slot of PCM frame + + BRI::gen "0 WD 4C 03"; # GPIOGPIO function (not PWM) on GPIO0 and GPIO1 pins + BRI::gen "0 WD 4A 03"; # Output enable for GPIO0 and GPIO1 pins +} + +my %port_type = ( + 6 => { 'BRI_NT' => 0 }, + 7 => { 'BRI_NT' => 1 } + ); + +# zap_xhfc_su.c:175 +sub main() { + #logit "main(): XPD_TYPE=$ENV{XPD_TYPE}"; + + $ENV{XPD_TYPE} || die "Missing XPD_TYPE environment variable\n"; + my $type = $port_type{$ENV{XPD_TYPE}}; + die "Bad XPD_TYPE=$ENV{XPD_TYPE}\n" unless $type; + die "Missing XPD_SUBUNIT information\n" unless defined($ENV{XPD_SUBUNIT}); + + # We must first turn off packet reception. + # + # Otherwise we mess with registers while the FPGA firmware tries to + # send us packets. + BRI::gen "0 Wm"; + + # Common initialization + if(($ENV{XPD_SUBUNIT} % 4) eq '0') { + # Turn off multi-byte packet reception before initialization started + my $chipnum = ($ENV{XPD_SUBUNIT} & 0x04) << 3; # Max 2 XHFC chips + for my $subunit (0 .. 3) { # 4 subunits per XHFC chip + my $addr = $chipnum | ($subunit << 3); + my $str = sprintf("0A 00 0F %02X C0 00 00 00 00 00\n", $addr); + open(CMD, ">$cmd") || die "Failed to open '$cmd': $!\n"; + print CMD $str; + close CMD; + } + init_xhfc; # zap_xhfc_su.c:1173 in setup_instance() + } + + # Port initialization + my $p = BRI::Port->new( + 'PORT_NUM' => $ENV{XPD_SUBUNIT}, + 'BRI_NT' => $type->{BRI_NT}, + 'PORT_MODE_UP' => 0, + 'PORT_MODE_EXCH' => 0 + ); + # zap_XHfc_su.c:1186 in setup_instance() + $p->init_su; + + $p->zthfc_startup; + + if(($ENV{XPD_SUBUNIT} % 4) eq 3) { + # Turn on multi-byte packet reception when ports initialization finished + my $chipnum = ($ENV{XPD_SUBUNIT} & 0x04) << 3; # Max 2 XHFC chips + for my $subunit (0 .. 3) { # 4 subunits per XHFC chip + my $addr = $chipnum | ($subunit << 3); + my $str = sprintf("0A 00 0F %02X 80 00 00 00 00 00\n", $addr); + open(CMD, ">$cmd") || die "Failed to open '$cmd': $!\n"; + print CMD $str; + close CMD; + } + } +} + +main; + +logit "Ending '$0'"; + +close REG; +close STDERR; +exit 0; diff --git a/kernel/xpp/init_card_7_29 b/kernel/xpp/init_card_7_29 new file mode 100755 index 0000000..255d50e --- /dev/null +++ b/kernel/xpp/init_card_7_29 @@ -0,0 +1,434 @@ +#! /usr/bin/perl -w +use strict; + +# +# $Id$ +# + +# +# Written by Oron Peled +# 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: +# XPD_BUS - bus name +# XPD_NAME - xpd name +# XPD_UNIT - xpd unit number +# XPD_SUBUNIT - xpd subunit number +# XPD_TYPE - xpd type number (from protocol reply): +# 3 - FXS +# 4 - FXO +# 6 - BRI_TE +# 7 - BRI_NT +# XPD_REVISION - xpd revision number +# +# 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. +# - RS Read Sub-register. +# - WD Write Direct register. +# - WS Write Sub-register. +# 3. Register number in hexadecimal. +# 4. Subregister number in hexadecimal. (for RS and WS commands). +# 5. Data byte in hexadecimal. (for WD and WS commands only). +# + +package main; +use File::Basename; + +my $program = basename("$0"); +my $init_dir = dirname("$0"); +my $unit_id; + +sub logit { + print STDERR "$unit_id: @_\n"; +} + +# Arrange for error logging +if (-t STDERR) { + $unit_id = 'Interactive'; + logit "Interactive startup\n"; +} else { + $unit_id = "$ENV{XPD_BUS}/$ENV{XPD_NAME}"; + open (STDERR, "| logger -t $program -p kern.info") || die; + logit "Non Interactive startup\n"; +} + +package BRI; + +sub gen { + my $fmt = shift; + $| = 1; + printf "$fmt\n", @_; +} + +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}; + #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 "0 WD 02 04"; + BRI::gen "0 WD 50 00"; # disable PLL + BRI::gen "0 WD 51 02"; + BRI::gen "0 WD 52 06"; + BRI::gen "0 WD 53 04"; + BRI::gen "0 WD 50 01"; # Enable PLL + BRI::gen "0 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 "0 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 "0 WD 35 %02X", $port->{CTRL3}; # A_ST_CTRL3 + BRI::gen "0 WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0 + BRI::gen "0 WD 35 F8"; # A_ST_CTRL3 = set end of pulse control to 0xF8 + BRI::gen "0 WD 32 08"; # A_SU_CTRL1 = Ignore E-channel data + BRI::gen "0 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; + } + #logit "clk_dly=$clk_dly"; + BRI::gen "0 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 "0 WD 16 %02X", $portnum; # R_SU_SEL +} + +# zap_xhfc_su.c:281 +sub xhfc_selfifo { + if (@_ != 1 ) { + main::logit "ERROR: xhfc_selfifo() called with " . scalar(@_) . " parameters"; + exit 1; + } + my $fifonum = shift; + #logit "xhfc_selfifo($fifonum)"; + BRI::gen "0 WD 0F %02X", $fifonum; + # --> WAIT UNTIL (R_STATUS & M_BUSY) == 0 +} + +# zap_xhfc_su.c:295 +sub xhfc_resetfifo() { + #logit "xhfc_resetfifo()"; + # A_INC_RES_FIFO = M_RES_FIFO | M_RES_FIFO_ERR + BRI::gen "0 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 + + #logit "setup_fifo($fifonum)"; + xhfc_selfifo $fifonum; + # A_CON_HDLC: transparent mode selection + BRI::gen "0 WD FA %02X", $conhdlc; + # A_SUBCH_CFG: subchnl params + BRI::gen "0 WD FB %02X", $subcfg; + # A_FIFO_CTRL: FIFO Control Register + BRI::gen "0 WD FF %02X", $fifoctrl; + xhfc_resetfifo; + xhfc_selfifo $fifonum; # wait for busy is builtin in this command + BRI::gen "0 WD 10 %02X", $r_slot; # R_SLOT + BRI::gen "0 WD D0 %02X", $a_sl_cfg; # A_SL_CFG + + #system("/bin/echo \"----=====NT\" \"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)"; + #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 "0 WD 31 %02X", $port->{CTRL0}; # A_SU_CTRL0: V_B1_TX_EN | V_SU_MD | (NT/TE) + BRI::gen "0 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}; + #logit "xhfc_ph_command(portnum=$portnum)"; + if ("$cmd" eq "HFC_L1_ACTIVATE_TE") { + su_sel($portnum); # Select port + BRI::gen "0 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 "0 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 "0 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 "0 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}; + #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 "0 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; +use Getopt::Std; + +my %opts; +getopts('o:', \%opts); + +$ENV{XPP_BASE} = '/proc/xpp'; +my $cmd = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/command"; +my $output; +if ($opts{o}) { + $output = $opts{o}; +} else { + $ENV{XPD_BUS} || die "Missing XPD_BUS environment variable\n"; + $ENV{XPD_NAME} || die "Missing XPD_NAME environment variable\n"; + $ENV{XPD_TYPE} || die "Missing XPD_TYPE environment variable\n"; + $ENV{XPD_REVISION} || die "Missing XPD_REVISION environment variable\n"; + $output = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/$ENV{XPD_NAME}/slics"; +} + +open(REG, ">$output") || die "Failed to open '$output': $!\n"; +select REG; + +logit "Starting '$0'"; + +#------------------------------------------- Instance detection + +# zap_xhfc_su.c:895 +sub init_xhfc() { + #logit "init_xhfc()"; + BRI::gen "#--------------------------- init_xhfc"; + BRI::gen "0 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 "0 WD 00 08"; # R_CIRM = M_SRES (soft reset) + # --> WAIT 5u + BRI::gen "0 WD 00 00"; # R_CIRM = 0 (zero it to deactivate reset) + + # amplitude + BRI::gen "0 WD 46 80"; # R_PWM_MD: (PWM output mode register) + # PWM push to zero only + BRI::gen "0 WD 39 18"; # R_PWM1: (modulator register for PWM1) + # set duty cycle + + BRI::gen "0 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 "0 WD 0F 80"; + # set PCM !master mode + BRI::gen "0 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 "0 WS 14 98 20"; # R_PCM_MD1: V_PLL_ADJ + # (DPLL adjust speed) in the + # last slot of PCM frame + + BRI::gen "0 WD 4C 03"; # GPIOGPIO function (not PWM) on GPIO0 and GPIO1 pins + BRI::gen "0 WD 4A 03"; # Output enable for GPIO0 and GPIO1 pins +} + +my %port_type = ( + 6 => { 'BRI_NT' => 0 }, + 7 => { 'BRI_NT' => 1 } + ); + +# zap_xhfc_su.c:175 +sub main() { + #logit "main(): XPD_TYPE=$ENV{XPD_TYPE}"; + + $ENV{XPD_TYPE} || die "Missing XPD_TYPE environment variable\n"; + my $type = $port_type{$ENV{XPD_TYPE}}; + die "Bad XPD_TYPE=$ENV{XPD_TYPE}\n" unless $type; + die "Missing XPD_SUBUNIT information\n" unless defined($ENV{XPD_SUBUNIT}); + + # We must first turn off packet reception. + # + # Otherwise we mess with registers while the FPGA firmware tries to + # send us packets. + BRI::gen "0 Wm"; + + # Common initialization + if(($ENV{XPD_SUBUNIT} % 4) eq '0') { + # Turn off multi-byte packet reception before initialization started + my $chipnum = ($ENV{XPD_SUBUNIT} & 0x04) << 3; # Max 2 XHFC chips + for my $subunit (0 .. 3) { # 4 subunits per XHFC chip + my $addr = $chipnum | ($subunit << 3); + my $str = sprintf("0A 00 0F %02X C0 00 00 00 00 00\n", $addr); + open(CMD, ">$cmd") || die "Failed to open '$cmd': $!\n"; + print CMD $str; + close CMD; + } + init_xhfc; # zap_xhfc_su.c:1173 in setup_instance() + } + + # Port initialization + my $p = BRI::Port->new( + 'PORT_NUM' => $ENV{XPD_SUBUNIT}, + 'BRI_NT' => $type->{BRI_NT}, + 'PORT_MODE_UP' => 0, + 'PORT_MODE_EXCH' => 0 + ); + # zap_XHfc_su.c:1186 in setup_instance() + $p->init_su; + + $p->zthfc_startup; + + if(($ENV{XPD_SUBUNIT} % 4) eq 3) { + # Turn on multi-byte packet reception when ports initialization finished + my $chipnum = ($ENV{XPD_SUBUNIT} & 0x04) << 3; # Max 2 XHFC chips + for my $subunit (0 .. 3) { # 4 subunits per XHFC chip + my $addr = $chipnum | ($subunit << 3); + my $str = sprintf("0A 00 0F %02X 80 00 00 00 00 00\n", $addr); + open(CMD, ">$cmd") || die "Failed to open '$cmd': $!\n"; + print CMD $str; + close CMD; + } + } +} + +main; + +logit "Ending '$0'"; + +close REG; +close STDERR; +exit 0; diff --git a/kernel/xpp/init_card_9_29 b/kernel/xpp/init_card_9_29 new file mode 100755 index 0000000..dd3b0a5 --- /dev/null +++ b/kernel/xpp/init_card_9_29 @@ -0,0 +1,358 @@ +#! /usr/bin/perl -w +use strict; + +# +# $Id$ +# + +# +# Written by Oron Peled +# 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: +# XPD_BUS - bus name +# XBUS_CONNECTOR - bus connector id string +# XPD_NAME - xpd name +# XPD_UNIT - xpd unit number +# XPD_TYPE - xpd type number (from protocol reply): +# 3 - FXS +# 4 - FXO +# 6 - BRI_TE +# 7 - BRI_NT +# 8 - PRI_TE +# 9 - PRI_NT +# XPD_REVISION - xpd revision number +# +# 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. +# 4. Subregister number in hexadecimal. (for RS and WS commands). +# 5. Data byte in hexadecimal. (for WD and WS commands only). +# + +package main; +use File::Basename; + +my $program = basename("$0"); +my $init_dir = dirname("$0"); +my $unit_id; + +sub logit { + print STDERR "$unit_id: @_\n"; +} + +# Arrange for error logging +if (-t STDERR) { + $unit_id = 'Interactive'; + logit "Interactive startup\n"; +} else { + $unit_id = "$ENV{XPD_BUS}/$ENV{XPD_NAME}"; + open (STDERR, "| logger -t $program -p kern.info") || die; + logit "Non Interactive startup\n"; +} + +package PRI; + +sub gen { + my $fmt = shift; + $| = 1; + printf "$fmt\n", @_; +} + +package PRI::Port; + +sub new { + my $pack = shift; + my $port = { @_ }; + bless $port, $pack; +} + +package main; +use Getopt::Std; +BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); } +use Zaptel::Config::Defaults; + +my %opts; +getopts('o:', \%opts); + +$ENV{XPP_BASE} = '/proc/xpp'; +#my $cmd = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/command"; +my $output; +if ($opts{o}) { + $output = $opts{o}; +} else { + $ENV{XPD_BUS} || die "Missing XPD_BUS environment variable\n"; + $ENV{XPD_NAME} || die "Missing XPD_NAME environment variable\n"; + $ENV{XPD_TYPE} || die "Missing XPD_TYPE environment variable\n"; + $ENV{XPD_REVISION} || die "Missing XPD_REVISION environment variable\n"; + $ENV{XBUS_CONNECTOR} || die "Missing XBUS_CONNECTOR environment variable\n"; + $output = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/$ENV{XPD_NAME}/slics"; +} + +sub write_pri_info { + my $pri_type = shift || die "Missing pri_type parameter"; + my $pri_proto = shift || die "Missing pri_proto parameter"; + my $info = "$ENV{XPP_BASE}/$ENV{XPD_BUS}/$ENV{XPD_NAME}/pri_info"; + + 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"; +} + +my @PRI_SETUP; + +sub set_defaults { + my @pri_specs; + my $match; + my $setup; + # 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 + logit "From $default_file: $setup_var=\n$setup_string\n"; + @pri_specs = split(/\s+/, $setup_string); + push(@pri_specs, 'NUM/*=TE,E1'); # Fall back default (last) + logit "pri_specs: @pri_specs"; +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}/$ENV{XPD_NAME}", + "NUM/$ENV{XPD_BUS}/$ENV{XPD_NAME}" + ); + foreach my $pattern (@patlist) { + #logit "testmatch: $pattern =~ $match"; + if($pattern =~ $match) { + logit "MATCH($i): '$match' setup=$setup"; + last SPEC; + } + } + } + die "No setup matching $ENV{XPD_BUS}/$ENV{XPD_NAME}\n" unless defined $setup; + @PRI_SETUP = split(/,/, $setup); + die "Bad setup string '$setup'\n" unless @PRI_SETUP; +} + +set_defaults; + +open(REG, ">$output") || die "Failed to open '$output': $!\n"; +select REG; + +logit "Starting '$0'"; + +PRI::gen "#--------------------------- start"; + +# 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; + +my $subunits_num = 4; +my $subunit = $ENV{XPD_SUBUNIT}; + +if($subunit eq 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 + + for(my $i = 0; $i < $subunits_num; $i++) { + PRI::gen "0 WS 26 $i BD"; # XPM0: Pulse Shape Programming for R1=18Ohms (0x54) + PRI::gen "0 WS 27 $i 03"; # XPM1: ...3V Pulse Level at the line (0x02) + PRI::gen "0 WS 28 $i 00"; # XPM2: ~XLT (transmit line is not in the high impedance state) + + # if (unchannelized) + #PRI::gen "0 WS 1F $i 22"; # LOOP (Channel Looback): + # ECLB (Enable Channel Loop-Back) + # CLA (Channel Address) + PRI::gen "0 WS 2B $i EF"; # IDL (Idle): + # If channel loopback is enabled than transmit this code on the outgoing + PRI::gen "0 WS 1F $i 00"; # LOOP (Channel Looback): + #if($i eq 0){ + # PRI::gen "0 WS 1F $i 00"; # LOOP (Channel Looback): + # # channels (XL1/XL2) + #}else { + # PRI::gen "0 WS 1F $i 20"; # LOOP (Channel Looback): + #} + + PRI::gen "0 WS 37 $i %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 "0 WS 3A $i 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 "0 WS 38 $i 0A"; # PCD: (Pulse Count Detection, LOS Detection after 176 consecutive 0s) + PRI::gen "0 WS 39 $i 15"; # PCR: (Pulse Count Recovery, LOS Recovery after 22 ones in PCD interval) + + # Configure system interface + PRI::gen "0 WS 3E $i 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 "0 WS 40 $i 04"; # SIC3: Edges for capture, Synchronous Pulse Receive @Rising Edge + PRI::gen "0 WS 41 $i 04"; # CMR4: RCLK is 8.192 MHz + PRI::gen "0 WS 43 $i 04"; # CMR5: TCLK is 8.192 MHz + PRI::gen "0 WS 44 $i 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 "0 WS 20 $i 9F"; # XSW: XSIS (Spare Bit For International Use fixed to 1), + # XY0, XY1, XY2, XY3, XY4 (Y0, Y1 and Y3-Bits fixed to 1) + + # cas = 0x1c; + # if (!(lineconfig & ZT_CONFIG_CCS)) + # cas |= 0x40; + + PRI::gen "0 WS 22 $i 00"; # XC0: (Transmit Counter Offset = 497/T=2) + PRI::gen "0 WS 23 $i 04"; # XC1: + + PRI::gen "0 WS 24 $i 00"; # RC0: (Receive Counter Offset = 497/T=2) + PRI::gen "0 WS 25 $i 05"; # RC1: + + my $sic2 = sprintf("%x", 0x00 | ($i << 1)); + + PRI::gen "0 WS 3F $i $sic2"; # SIC2: No FFS, no center receive elastic buffer, data active at phase ($sic >> 1) + + # enable the following interrupt sources + PRI::gen "0 WS 16 $i 00"; # IMR2 (Interrupt Mask Register2): Enable ALL + + PRI::gen "0 WS 17 $i 3F"; # IMR3 ~ES, ~SEC (Enable ES and SEC interrupts) + PRI::gen "0 WS 18 $i 00"; # IMR4: Enable ALL + + PRI::gen "0 WS 08 $i 04"; # IPC: SYNC is 8 Khz + + PRI::gen "0 WS 02 $i 51"; # CMDR (Command Register): RRES, XRES, SRES (Receiver/Transmitter reset) + PRI::gen "0 WS 02 $i 00"; # CMDR + + + # Configure interrupts + PRI::gen "0 WS 46 $i 40"; # GCR: Interrupt on Activation/Deactivation of AIX, LOS + + PRI::gen "0 WS 45 $i 00"; # CMR2: External sources for SYPR, SCLKR, SYPX, SCLKX for TX and RX. + #PRI::gen "0 WS 22 $i 00"; # XC0: Normal operation of Sa-bits + #PRI::gen "0 WS 23 $i 04"; # XC1: X=4 => T=4-X=0 offset + #PRI::gen "0 WS 24 $i 00"; # RC0: 0 offset + #PRI::gen "0 WS 25 $i 00"; # RC1: Remaining part of RC0 + + # Configure ports + PRI::gen "0 WD 85 80"; # GPC1 (Global Port Configuration 1): + #PRI::gen "0 WD 85 00"; # GPC1 (Global Port Configuration 1): + # SMM (System Interface Multiplex Mode) + PRI::gen "0 WS 80 $i 00"; # PC1: SYPR/SYPX provided to RPA/XPA inputs + + PRI::gen "0 WS 84 $i 31"; # PC5: XMFS active low, SCLKR is input, RCLK is output (unused) + PRI::gen "0 WS 86 $i 03"; # PC6: CLK1 is Tx Clock output, CLK2 is 8.192 Mhz from DCO-R + PRI::gen "0 WS 3B $i 00"; # Clear LCR1 - Loop Code Register 1 + + # printk("TE110P: Successfully initialized serial bus for card\n"); + + # Initialize PCM and SIG regs + PRI::gen "0 WS A0 $i 00"; # TSEO (Time Slot Even/Odd Select) + PRI::gen "0 WS A1 $i FF"; # TSBS (Time Slot Bit Select)- only selected bits are used for HDLC channel 1 + # in selected time slots + PRI::gen "0 WS 03 $i 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 "0 WS 09 $i 18"; # CCR1 (Common Configuration Register1) + # EITS (Enable Internal Time Slot 0 to 31 Signalling) + # ITF (Interframe Time Fill) + PRI::gen "0 WS 0A $i 04"; # CCR2 (Common Configuration Register2) + # RCRC (enable CRC - HDLC channel 1enable CRC - HDLC channel 1) + PRI::gen "0 WS 0C $i 00"; # RTR1 (Receive Time Slot register 1) + PRI::gen "0 WS 0D $i 00"; # RTR2 (Receive Time Slot register 2) + PRI::gen "0 WS 0E $i 00"; # RTR3 (Receive Time Slot register 3), TS16 (Enable time slot 16) + PRI::gen "0 WS 0F $i 00"; # RTR4 (Receive Time Slot register 4) + + PRI::gen "0 WS 10 $i 00"; # TTR1 (Transmit Time Slot register 1) + PRI::gen "0 WS 11 $i 00"; # TTR2 (Transmit Time Slot register 2) + PRI::gen "0 WS 12 $i 00"; # TTR3 (Transmit Time Slot register 3), TS16 (Enable time slot 16) + PRI::gen "0 WS 13 $i 00"; # TTR4 (Transmit Time Slot register 4) + + # configure the best performance of the Bipolar Violation detection for all four channels + PRI::gen "0 WS BD $i 00"; # BFR (Bugfix Register): ~BVP (Bipolar Violations), + # use Improved Bipolar Violation Detection instead + } + 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 WS 80 00 00"; # PC1 (Port configuration 1): RPB_1.SYPR , XPB_1.SYPX + PRI::gen "0 WS 81 00 0B"; # PC2 (Port configuration 2): RPB_1.GPOH (ResetID ), XPB_1.GPOL (MUX_SEL0) + PRI::gen "0 WS 82 00 9B"; # PC3 (Port configuration 3): RPC_1.GPI (nConfig0), XPC_1.GPOL (MUX_SEL1) + PRI::gen "0 WS 83 00 9B"; # PC4 (Port configuration 4): RPD_1.GPI (nConfig1), XPD_1.GPOL (MUX_SEL2) +} + + +#------------------------------------------- Instance detection + +logit "Ending '$0'"; + +close REG; + +write_pri_info @PRI_SETUP; + +close STDERR; +exit 0; diff --git a/kernel/xpp/param_doc b/kernel/xpp/param_doc new file mode 100755 index 0000000..5848728 --- /dev/null +++ b/kernel/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() { + 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/kernel/xpp/parport_debug.c b/kernel/xpp/parport_debug.c new file mode 100644 index 0000000..93049ef --- /dev/null +++ b/kernel/xpp/parport_debug.c @@ -0,0 +1,113 @@ +/* + * Written by Oron Peled + * 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 + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +# warning "This module is tested only with 2.6 kernels" +#endif + +#include +#include +#include +#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 "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("$Id:"); + +module_init(parallel_dbg_init); +module_exit(parallel_dbg_cleanup); diff --git a/kernel/xpp/parport_debug.h b/kernel/xpp/parport_debug.h new file mode 100644 index 0000000..138af99 --- /dev/null +++ b/kernel/xpp/parport_debug.h @@ -0,0 +1,31 @@ +#ifndef PARPORT_DEBUG_H +#define PARPORT_DEBUG_H +/* + * Written by Oron Peled + * 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/kernel/xpp/utils/Makefile b/kernel/xpp/utils/Makefile new file mode 100644 index 0000000..437b359 --- /dev/null +++ b/kernel/xpp/utils/Makefile @@ -0,0 +1,136 @@ +PEDANTIC = -ansi -pedantic -std=c99 + +RANLIB = ranlib +INSTALL = install +INSTALL_DATA = install -m 644 + +ZAPTEL_DIR ?= ../.. + +-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_?_*) ../calibrate_slics 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=$(ZAPTEL_DIR)/wctdm.c + +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) + perl -n -e 'print if (/^static struct fxo_mode {$$/ .. /};$$/)' $(WCTDM) >$@ + +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/kernel/xpp/utils/astribank_hook b/kernel/xpp/utils/astribank_hook new file mode 100755 index 0000000..351cd93 --- /dev/null +++ b/kernel/xpp/utils/astribank_hook @@ -0,0 +1,53 @@ +#! /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. +# +# This example script sets the sync source, and thus makes the call to +# xpp_sync in the init.d script unnecessary. + +set -e + +xpp_sync="/usr/sbin/xpp_sync" + +me=`basename $0` +INIT_DIR=`dirname $0` +XPP_BASE=/proc/xpp +export XPP_BASE +LOGGER="logger -s -t $me" +XPP_SYNC='auto' + +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" + +$LOGGER -p kern.info "$ACTION: $*. Setting sync to $XPP_SYNC." + +case "$ACTION" in +add) + "$xpp_sync" $XPP_SYNC + ;; +remove) + "$xpp_sync" $XPP_SYNC + ;; +*) + ;; +esac + +"$xpp_sync" | $LOGGER -p kern.info diff --git a/kernel/xpp/utils/example_default_zaptel b/kernel/xpp/utils/example_default_zaptel new file mode 100644 index 0000000..f60b651 --- /dev/null +++ b/kernel/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/kernel/xpp/utils/fpga_load.8 b/kernel/xpp/utils/fpga_load.8 new file mode 100644 index 0000000..412a839 --- /dev/null +++ b/kernel/xpp/utils/fpga_load.8 @@ -0,0 +1,86 @@ +.TH "FPGA_LOAD" "8" "16 April 2006" "" "" + +.SH NAME +ztcfg \- reads and loads zaptel.conf +.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 . +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/kernel/xpp/utils/fpga_load.c b/kernel/xpp/utils/fpga_load.c new file mode 100644 index 0000000..3d6bdbe --- /dev/null +++ b/kernel/xpp/utils/fpga_load.c @@ -0,0 +1,1003 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#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; + 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 + +void usage() +{ + fprintf(stderr, "Usage: %s -D {/proc/bus/usb|/dev/bus/usb}// [options...]\n", progname); + fprintf(stderr, "\tOptions:\n"); + fprintf(stderr, "\t\t[-r] # Reset the device\n"); + fprintf(stderr, "\t\t[-b ] # Output to \n"); + fprintf(stderr, "\t\t[-I ] # Input from \n"); + fprintf(stderr, "\t\t[-H ] # Output to ('-' 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/kernel/xpp/utils/genzaptelconf b/kernel/xpp/utils/genzaptelconf new file mode 100755 index 0000000..1435e9f --- /dev/null +++ b/kernel/xpp/utils/genzaptelconf @@ -0,0 +1,1195 @@ +#! /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 +# +# 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 +# + +# 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 ] [-e ] [-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 <$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 <$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 <$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. + echo "# channel $chan_num, WCTDM, no module." >> $zaptel_file + 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 <> ${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/kernel/xpp/utils/genzaptelconf.8 b/kernel/xpp/utils/genzaptelconf.8 new file mode 100644 index 0000000..c3f6f73 --- /dev/null +++ b/kernel/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 ] [-e ] + +.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 +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/kernel/xpp/utils/hexfile.c b/kernel/xpp/utils/hexfile.c new file mode 100644 index 0000000..2a01b3f --- /dev/null +++ b/kernel/xpp/utils/hexfile.c @@ -0,0 +1,567 @@ +/* + * Written by Oron Peled + * 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 +#include +#include +#include +#include +#include +#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/kernel/xpp/utils/hexfile.h b/kernel/xpp/utils/hexfile.h new file mode 100644 index 0000000..f8bf6a9 --- /dev/null +++ b/kernel/xpp/utils/hexfile.h @@ -0,0 +1,123 @@ +/* + * Written by Oron Peled + * 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 + +/* + * Some portability workarounds + */ +#ifdef _WINDOWS + +#include /* 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 +#include +#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/kernel/xpp/utils/lszaptel b/kernel/xpp/utils/lszaptel new file mode 100755 index 0000000..a836d98 --- /dev/null +++ b/kernel/xpp/utils/lszaptel @@ -0,0 +1,108 @@ +#! /usr/bin/perl -w +# +# Written by Oron Peled +# 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/kernel/xpp/utils/print_modes.c b/kernel/xpp/utils/print_modes.c new file mode 100644 index 0000000..6312bd1 --- /dev/null +++ b/kernel/xpp/utils/print_modes.c @@ -0,0 +1,44 @@ +#include + +#include "wctdm_fxomodes.h" + +int main() { + size_t i; + + printf("case \"$mode\" in\n"); + 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 !=0 ) { + snprintf(ring_osc, BUFSIZ, "; ring_osc=\"%02X %02X\"", + (fxo_modes[i].ring_osc)>>8, + (fxo_modes[i].ring_osc)&&0xFF + ); + } + if (fxo_modes[i].ring_x !=0 ) { + snprintf(ring_x, BUFSIZ, "; ring_x=\"%02X %02X\"", + (fxo_modes[i].ring_x)>>8, + (fxo_modes[i].ring_x)&&0xFF + ); + } + + printf("%s)\treg16=%02X; reg26=%02X; reg30=%02X; reg31=%02X%s%s;;\n", + fxo_modes[i].name, reg16, reg26, reg30, reg31, ring_osc, ring_x); + } + printf("esac\n"); + return 0; +} diff --git a/kernel/xpp/utils/test_parse.c b/kernel/xpp/utils/test_parse.c new file mode 100644 index 0000000..8ac2023 --- /dev/null +++ b/kernel/xpp/utils/test_parse.c @@ -0,0 +1,35 @@ +#include +#include +#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/kernel/xpp/utils/xpp.rules b/kernel/xpp/utils/xpp.rules new file mode 100644 index 0000000..794a9f0 --- /dev/null +++ b/kernel/xpp/utils/xpp.rules @@ -0,0 +1,13 @@ +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 +KERNEL=="xbus*" RUN+="/usr/share/zaptel/astribank_hook udev $kernel $sysfs{status} $sysfs{connector}" + diff --git a/kernel/xpp/utils/xpp_blink b/kernel/xpp/utils/xpp_blink new file mode 100755 index 0000000..8a96502 --- /dev/null +++ b/kernel/xpp/utils/xpp_blink @@ -0,0 +1,130 @@ +#! /usr/bin/perl -w +# +# Written by Oron Peled +# 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 | xpd [] | label /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/kernel/xpp/utils/zaptel_drivers b/kernel/xpp/utils/zaptel_drivers new file mode 100755 index 0000000..d7904c0 --- /dev/null +++ b/kernel/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/kernel/xpp/utils/zaptel_hardware b/kernel/xpp/utils/zaptel_hardware new file mode 100755 index 0000000..004a44b --- /dev/null +++ b/kernel/xpp/utils/zaptel_hardware @@ -0,0 +1,164 @@ +#! /usr/bin/perl -w +# +# Written by Oron Peled +# 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/kernel/xpp/utils/zconf/Zaptel.pm b/kernel/xpp/utils/zconf/Zaptel.pm new file mode 100644 index 0000000..a7e7d6c --- /dev/null +++ b/kernel/xpp/utils/zconf/Zaptel.pm @@ -0,0 +1,68 @@ +package Zaptel; +# +# Written by Oron Peled +# 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 channels objects: L. + +Zaptel hardware devices information: L. + +Xorcom Astribank -specific information: L. + +=cut + +1; diff --git a/kernel/xpp/utils/zconf/Zaptel/Chans.pm b/kernel/xpp/utils/zconf/Zaptel/Chans.pm new file mode 100644 index 0000000..b02bf24 --- /dev/null +++ b/kernel/xpp/utils/zconf/Zaptel/Chans.pm @@ -0,0 +1,187 @@ +package Zaptel::Chans; +# +# Written by Oron Peled +# 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 +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; +} + +1; diff --git a/kernel/xpp/utils/zconf/Zaptel/Config/Defaults.pm b/kernel/xpp/utils/zconf/Zaptel/Config/Defaults.pm new file mode 100644 index 0000000..1d11403 --- /dev/null +++ b/kernel/xpp/utils/zconf/Zaptel/Config/Defaults.pm @@ -0,0 +1,54 @@ +package Zaptel::Config::Defaults; +# +# Written by Oron Peled +# 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; + } + } + } + die "No default_file" unless $default_file; + my %vars = Zaptel::Config::Defaults::do_source($default_file, @vars); + return ($default_file, %vars); +} + +1; diff --git a/kernel/xpp/utils/zconf/Zaptel/Hardware.pm b/kernel/xpp/utils/zconf/Zaptel/Hardware.pm new file mode 100644 index 0000000..5af22f7 --- /dev/null +++ b/kernel/xpp/utils/zconf/Zaptel/Hardware.pm @@ -0,0 +1,60 @@ +package Zaptel::Hardware; +# +# Written by Oron Peled +# 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; + +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; +} + +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; +} + +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; +} + +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/kernel/xpp/utils/zconf/Zaptel/Hardware/PCI.pm b/kernel/xpp/utils/zconf/Zaptel/Hardware/PCI.pm new file mode 100644 index 0000000..45173d4 --- /dev/null +++ b/kernel/xpp/utils/zconf/Zaptel/Hardware/PCI.pm @@ -0,0 +1,204 @@ +package Zaptel::Hardware::PCI; +# +# Written by Oron Peled +# 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' }, + + # 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' }, + + # 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 = ; + close F; + chomp($str); + return $str; +} + +sub scan_devices($) { + my @devices; + + while() { + 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() { + 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/kernel/xpp/utils/zconf/Zaptel/Hardware/USB.pm b/kernel/xpp/utils/zconf/Zaptel/Hardware/USB.pm new file mode 100644 index 0000000..a2dc08f --- /dev/null +++ b/kernel/xpp/utils/zconf/Zaptel/Hardware/USB.pm @@ -0,0 +1,116 @@ +package Zaptel::Hardware::USB; +# +# Written by Oron Peled +# 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() { + 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/kernel/xpp/utils/zconf/Zaptel/Span.pm b/kernel/xpp/utils/zconf/Zaptel/Span.pm new file mode 100644 index 0000000..380dc7f --- /dev/null +++ b/kernel/xpp/utils/zconf/Zaptel/Span.pm @@ -0,0 +1,160 @@ +package Zaptel::Span; +# +# Written by Oron Peled +# 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; + +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)' + ); + +our $ZAPBRI_NET = 'bri_net'; +our $ZAPBRI_CPE = 'bri_cpe'; + +our $ZAPPRI_NET = 'pri_net'; +our $ZAPPRI_CPE = 'pri_cpe'; + +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 = ; + 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/) { + $self->{IS_DIGITAL} = 1; + $self->{IS_PRI} = 1; + $self->{PROTO} = "$1"; + $self->{TERMTYPE} = $2; + $self->{TYPE} = "$1_$2"; + if($self->{PROTO} eq 'E1') { + $self->{DCHAN_IDX} = 15; + $self->{BCHAN_LIST} = [ 0 .. 14, 16 .. 30 ]; + } elsif($self->{PROTO} eq 'T1') { + $self->{DCHAN_IDX} = 23; + $self->{BCHAN_LIST} = [ 0 .. 22 ]; + } else { + die "'$self->{PROTO}' unsupported yet"; + } + 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() { + chomp; + s/^\s*//; + s/\s*$//; + next unless /\S/; + my $c = Zaptel::Chans->new($self, $index, $_); + push(@channels, $c); + $index++; + } + close F; + @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/kernel/xpp/utils/zconf/Zaptel/Utils.pm b/kernel/xpp/utils/zconf/Zaptel/Utils.pm new file mode 100644 index 0000000..8d13ad7 --- /dev/null +++ b/kernel/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/kernel/xpp/utils/zconf/Zaptel/Xpp.pm b/kernel/xpp/utils/zconf/Zaptel/Xpp.pm new file mode 100644 index 0000000..8a2a6eb --- /dev/null +++ b/kernel/xpp/utils/zconf/Zaptel/Xpp.pm @@ -0,0 +1,183 @@ +package Zaptel::Xpp; +# +# Written by Oron Peled +# 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 = ; + 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() { + 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 + +For the documentation of xbus objects, see L. For +information about XPD objects, see L. + +General documentation can be found in the master package L. + +=cut + +1; diff --git a/kernel/xpp/utils/zconf/Zaptel/Xpp/Line.pm b/kernel/xpp/utils/zconf/Zaptel/Xpp/Line.pm new file mode 100644 index 0000000..e3e04f0 --- /dev/null +++ b/kernel/xpp/utils/zconf/Zaptel/Xpp/Line.pm @@ -0,0 +1,59 @@ +package Zaptel::Xpp::Line; +# +# Written by Oron Peled +# 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, ref($xpd); + $self->{XPD} = $xpd; + $self->{INDEX} = $index; + return $self; +} + +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': $!"; + while () { + chomp; + if($type eq 'FXO') { + if(s/^\s*battery\s*:\s*//) { + my @batt = split; + foreach my $l (@lines) { + die unless @batt; + $l->{BATTERY} = shift @batt; + } + die if @batt; + } + } + } + close F; +} + + +1; diff --git a/kernel/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm b/kernel/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm new file mode 100644 index 0000000..a5fcf1e --- /dev/null +++ b/kernel/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm @@ -0,0 +1,117 @@ +package Zaptel::Xpp::Xbus; +# +# Written by Oron Peled +# 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; + return $xpds[$xpdid]; +} + +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 = ; + 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/kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm b/kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm new file mode 100644 index 0000000..326aafd --- /dev/null +++ b/kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm @@ -0,0 +1,123 @@ +package Zaptel::Xpp::Xpd; +# +# Written by Oron Peled +# 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 = ; + 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 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 = ; + 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 = ; + 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() { + 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/kernel/xpp/utils/zt_registration b/kernel/xpp/utils/zt_registration new file mode 100755 index 0000000..3bdc642 --- /dev/null +++ b/kernel/xpp/utils/zt_registration @@ -0,0 +1,125 @@ +#! /usr/bin/perl -w +# +# Written by Oron Peled +# 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/kernel/xpp/xbus-core.c b/kernel/xpp/xbus-core.c new file mode 100644 index 0000000..790c12a --- /dev/null +++ b/kernel/xpp/xbus-core.c @@ -0,0 +1,1798 @@ +/* + * Written by Oron Peled + * 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 + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +# warning "This module is tested only with 2.6 kernels" +#endif + +#include +#include +#include +#include +#ifdef PROTOCOL_DEBUG +#include +#endif +#include +#include +#include /* 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$"; + +/* Defines */ +#define INITIALIZATION_TIMEOUT (60*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 print_dbg; +DEF_PARM(uint, poll_timeout, 1000, 0644, "Timeout (in jiffies) waiting for units to reply"); +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); + +/* + * Encapsulate all poll related data of a single xbus. + */ +struct xbus_poller { + /* + * Bus scanning + */ + uint xbus_num; + struct workqueue_struct *wq; + bool is_polling; + atomic_t count_poll_answers; + struct list_head poll_results; + wait_queue_head_t wait_for_polls; + + struct work_struct xpds_init_work; + + atomic_t count_xpds_to_initialize; + atomic_t count_xpds_initialized; + wait_queue_head_t wait_for_xpd_initialization; + struct proc_dir_entry *proc_xbus_waitfor_xpds; +}; + +/* 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); +} + +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); + } +} + +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 print_dbg = DBG_ANY; /* mask global print_dbg */ + + 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) +{ + 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(XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_READ) && + XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_WRITE)) + do_print = 1; + else if(print_dbg & 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, print_dbg); + } + num++; + pos = nextpos; + if(pos >= frm_len) + break; + } while(1); + spin_unlock_irqrestore(&serialize_dump_xframe, flags); +} + +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); + 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; + const char *msg = ""; + 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)) { + msg = "Dropped command xframe. Is shutting down."; + ret = -ENODEV; + goto err; + } + if(!xframe_enqueue(&xbus->command_queue, xframe)) { + XBUS_PUT(xbus); + msg = "Dropped command xframe. Cannot enqueue."; + ret = -E2BIG; + goto err; + } + return 0; +err: + if((rate_limit++ % 1003) == 0) { + XBUS_ERR(xbus, "%s\n", msg); + dump_xframe("send_cmd_frame", xbus, xframe); + } + 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; +} + +/* + * 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) +static void xbus_poll(struct work_struct *work) +{ + struct xbus_poller *poller = container_of(work, struct xbus_poller, xpds_init_work); +#else +static void xbus_poll(void *data) +{ + struct xbus_poller *poller = data; +#endif + int id; + int ret = 0; + unsigned long flags; + struct list_head *card; + struct list_head *next_card; + struct list_head removal_list; + struct list_head additions_list; + int count_removed; + int count_added; + xbus_t *xbus; + + BUG_ON(!poller); + xbus = get_xbus(poller->xbus_num); + if(!xbus) { + XBUS_ERR(xbus, "Aborting poll. XBUS #%d disappeared.\n", + poller->xbus_num); + return; + } + msleep(2); /* roundtrip for older polls */ + spin_lock_irqsave(&xbus->lock, flags); + XBUS_DBG(DEVICES, xbus, "\n"); + poller->is_polling = 1; + if(!XBUS_GET(xbus)) { + XBUS_ERR(xbus, "Aborting poll. Is shutting down.\n"); + goto out; + } + /* + * Send out the polls + */ + for(id = 0; id < MAX_XPDS; id++) { + if(!TRANSPORT_RUNNING(xbus)) + break; + XBUS_DBG(DEVICES, xbus, "Polling slot %d\n", id); + spin_unlock_irqrestore(&xbus->lock, flags); + ret = CALL_PROTO(GLOBAL, DESC_REQ, xbus, NULL, id); + spin_lock_irqsave(&xbus->lock, flags); + if(ret < 0) { + XBUS_ERR(xbus, "Failed sending DESC_REQ to XPD #%d\n", id); + goto out; + } + } + spin_unlock_irqrestore(&xbus->lock, flags); + /* + * Wait for replies + */ + XBUS_DBG(DEVICES, xbus, "Polled %d XPD's. Waiting for replies max %d jiffies\n", MAX_XPDS, poll_timeout); + ret = wait_event_interruptible_timeout(poller->wait_for_polls, atomic_read(&poller->count_poll_answers) >= MAX_XPDS, poll_timeout); + if(ret == 0) { + XBUS_ERR(xbus, "Poll timeout. Continuing anyway.\n"); + /* + * Continue processing. Maybe some units did reply. + */ + } else if(ret < 0) { + XBUS_ERR(xbus, "Poll interrupted %d\n", ret); + goto out; + } else + XBUS_DBG(DEVICES, xbus, "Poll finished in %d jiffies.\n", poll_timeout - ret); + /* + * Build removals/additions lists + */ + spin_lock_irqsave(&xbus->lock, flags); + INIT_LIST_HEAD(&removal_list); + INIT_LIST_HEAD(&additions_list); + count_removed = 0; + count_added = 0; + list_for_each_safe(card, next_card, &poller->poll_results) { + struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list); + byte type = card_desc->type; + xpd_t *xpd; + + BUG_ON(card_desc->magic != CARD_DESC_MAGIC); + /* + * Return the refcount we got in xbus_poller_notify() + * We are still protected by the refcount taken in + * the beginning of xbus_poll(). + */ + put_xbus(xbus); + xpd = xpd_byaddr(xbus, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit); + + if(xpd && type == XPD_TYPE_NOMODULE) { /* card removal */ + list_move_tail(card, &removal_list); + count_removed++; + } else if(!xpd && type != XPD_TYPE_NOMODULE) { /* card detection */ + if(card_desc->rev != XPP_PROTOCOL_VERSION) { + XBUS_NOTICE(xbus, "XPD at %d%d: type=%d.%d has bad firmware revision %d.%d\n", + card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit, + card_desc->type, card_desc->subtype, + card_desc->rev / 10, card_desc->rev % 10); + list_del(card); + kfree(card_desc); + continue; + } + XBUS_INFO(xbus, "Detected XPD at %d%d type=%d.%d Revision %d.%d\n", + card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit, + card_desc->type, card_desc->subtype, + card_desc->rev / 10, card_desc->rev % 10); + list_move_tail(card, &additions_list); + count_added++; + } else { /* same same */ + list_del(card); + kfree(card_desc); + } + } + poller->is_polling = 0; + /* + * We set this *after* poll is finished, so wait_for_xpd_initialization can + * tell we already know how many units we have. + */ + atomic_set(&poller->count_xpds_to_initialize, count_added); + spin_unlock_irqrestore(&xbus->lock, flags); + XBUS_INFO(xbus, "Poll results: removals=%d additions=%d\n", count_removed, count_added); + /* + * Process removals first + */ + list_for_each_safe(card, next_card, &removal_list) { + struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list); + xpd_t *xpd; + + list_del(card); + xpd = xpd_byaddr(xbus, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit); + if(xpd) + xpd_disconnect(xpd); + kfree(card); + } + /* + * Now process additions + */ + list_for_each_safe(card, next_card, &additions_list) { + struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list); + + list_del(card); + /* FIXME: card_detected() should have a return value for count_xpds_initialized */ + card_detected(card_desc); + atomic_inc(&poller->count_xpds_initialized); + } + /* Device-Model */ + if((ret = xbus_sysfs_create(xbus)) < 0) { + XBUS_ERR(xbus, "%s: xbus_sysfs_create() failed: %d\n", __FUNCTION__, ret); + goto out; + } + /* + * 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 */ +out: + poller->is_polling = 0; /* just for safety */ + XBUS_PUT(xbus); + wake_up(&poller->wait_for_xpd_initialization); + put_xbus(xbus); + return; +} + +void xbus_poller_notify(xbus_t *xbus, struct card_desc_struct *card_desc) +{ + struct xbus_poller *poller; + unsigned long flags; + + BUG_ON(!xbus); + poller = xbus->poller; + BUG_ON(!poller); + if(!poller->is_polling) { + XBUS_NOTICE(xbus, "%d%d replied not during poll. Ignore\n", + card_desc->xpd_addr.unit, + card_desc->xpd_addr.subunit); + kfree(card_desc); + return; + } + spin_lock_irqsave(&xbus->lock, flags); + if(card_desc->type == XPD_TYPE_NOMODULE) + XBUS_COUNTER(xbus, DEV_DESC_EMPTY)++; + else + XBUS_COUNTER(xbus, DEV_DESC_FULL)++; + atomic_inc(&poller->count_poll_answers); + list_add_tail(&card_desc->card_list, &poller->poll_results); + spin_unlock_irqrestore(&xbus->lock, flags); + /* + * Reference counting for the xbus. + * Would be returned in xbus_poll() + */ + xbus = get_xbus(xbus->num); + BUG_ON(!xbus); + /* + * wake_up only after exiting our critical section. + * We suspect that otherwise a spinlock nesting may occur + * and cause a panic (if spinlock debugging is compiled in). + */ + wake_up(&poller->wait_for_polls); + return; +} + +static void poller_destroy(struct xbus_poller *poller) +{ + xbus_t *xbus; + + if(!poller) + return; + xbus = get_xbus(poller->xbus_num); + if(xbus) { +#ifdef CONFIG_PROC_FS + if(xbus->proc_xbus_dir && poller->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); + poller->proc_xbus_waitfor_xpds = NULL; + } +#endif + XBUS_DBG(DEVICES, xbus, "detach poller\n"); + xbus->poller = NULL; + } + if (poller->wq) { + DBG(DEVICES, "XBUS #%d: destroy workqueue\n", poller->xbus_num); + flush_workqueue(poller->wq); + destroy_workqueue(poller->wq); + poller->wq = NULL; + } + put_xbus(xbus); + KZFREE(poller); +} + +/* + * Allocate a poller 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_poller *poller_new(xbus_t *xbus) +{ + struct xbus_poller *poller; + + BUG_ON(xbus->busname[0] == '\0'); /* No name? */ + BUG_ON(xbus->poller); /* Hmmm... overrun pollers? */ + XBUS_DBG(DEVICES, xbus, "\n"); + poller = KZALLOC(sizeof(*poller), GFP_KERNEL); + if(!poller) + goto err; + poller->xbus_num = xbus->num; + xbus->poller = poller; + /* poll related variables */ + atomic_set(&poller->count_poll_answers, 0); + atomic_set(&poller->count_xpds_to_initialize, 0); + atomic_set(&poller->count_xpds_initialized, 0); + INIT_LIST_HEAD(&poller->poll_results); + init_waitqueue_head(&poller->wait_for_polls); + init_waitqueue_head(&poller->wait_for_xpd_initialization); + poller->wq = create_singlethread_workqueue(xbus->busname); + if(!poller->wq) { + XBUS_ERR(xbus, "Failed to create poller workqueue.\n"); + goto err; + } +#ifdef CONFIG_PROC_FS + if(xbus->proc_xbus_dir) { + poller->proc_xbus_waitfor_xpds = create_proc_read_entry( + PROC_XBUS_WAITFOR_XPDS, 0444, + xbus->proc_xbus_dir, + xbus_read_waitfor_xpds, + xbus); + if (!poller->proc_xbus_waitfor_xpds) { + XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_WAITFOR_XPDS); + goto err; + } + poller->proc_xbus_waitfor_xpds->owner = THIS_MODULE; + } +#endif + return poller; +err: + poller_destroy(poller); + return NULL; +} + +/* + * Sends an xbus_poll() work to the poller workqueue of the given xbus. + */ +static int poller_dispatch(xbus_t *xbus) +{ + struct xbus_poller *poller = xbus->poller; + + if(!poller) { + XBUS_ERR(xbus, "missing poller\n"); + return 0; + } + /* Initialize the work. (adapt to kernel API changes). */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + INIT_WORK(&poller->xpds_init_work, xbus_poll); +#else + INIT_WORK(&poller->xpds_init_work, xbus_poll, poller); +#endif + /* Now send it */ + if(!queue_work(poller->wq, &poller->xpds_init_work)) { + XBUS_ERR(xbus, "Failed to queue xpd initialization work\n"); + return 0; + } + return 1; +} + +int xbus_activate(xbus_t *xbus) +{ + struct xbus_ops *ops; + struct xbus_poller *poller; + + BUG_ON(!xbus); + ops = transportops_get(xbus); + BUG_ON(!ops); + poller = xbus->poller; + BUG_ON(!poller); + /* 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_timing_init(&xbus->timing, xbus->busname); + /* + * 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); + /* Poll it */ + poller_dispatch(xbus); + 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_PLL); /* no more ticks */ + 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[0]); + xframe_queue_clear(&xbus->pcm_tospan[1]); + 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); + return NULL; + } + /* Found empty slot */ + xbus->num = i; + init_xbus(i, xbus); + xbus = get_xbus(i); + bus_count++; + 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 + poller_destroy(xbus->poller); +#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; + struct xbus_poller *poller; + + 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 *)(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, 200, "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[0], 5, 10, "pcm_tospan[0]", xbus); + xframe_queue_init(&xbus->pcm_tospan[1], 5, 10, "pcm_tospan[1]", xbus); + tasklet_init(&xbus->receive_tasklet, receive_tasklet_func, (unsigned long)xbus); + /* + * Create poller after /proc/XBUS-?? so the directory exists + * before /proc/XBUS-??/waitfor_xpds tries to get created. + */ + poller = poller_new(xbus); + if(!poller) { + ERR("Failed to allocate poller\n"); + xbus_free(xbus); + return NULL; + } + 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); + xbus_sysfs_remove(xbus); /* Device-Model */ + 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; + } + 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_poller *poller; + unsigned long flags; + int len = 0; + int i = (int)data; + struct timeval now; + + + xbus = get_xbus(i); + if(!xbus) + goto out; + spin_lock_irqsave(&xbus->lock, flags); + do_gettimeofday(&now); + poller = xbus->poller; + + len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n", + xbus->busname, + xbus->busdesc, + xbus->label, + (TRANSPORT_RUNNING(xbus)) ? "connected" : "missing" + ); + len += sprintf(page + len, "POLLS: %d/%d\n", + atomic_read(&poller->count_poll_answers), MAX_XPDS); + len += sprintf(page + len, "XPDS_READY: %d/%d\n", + atomic_read(&poller->count_xpds_initialized), + atomic_read(&poller->count_xpds_to_initialize)); + 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[0]); + len += xbus_fill_proc_queue(page + len, &xbus->pcm_tospan[1]); + 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\n", xbus->self_ticking); + 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, "\nSYNC: [%d] %-14s: DRIFT=%d %3ld sec ago\n", + xbus->sync_mode, sync_mode_name(xbus->sync_mode), xbus->sync_adjustment, + (xbus->pll_updated_at == 0) ? 0 : now.tv_sec - xbus->pll_updated_at); + len += sprintf(page + len, + "tick timing: avg = %3d usec stddev = %4d usec (count=%ld)\n", + xbus->timing.tick_avg, xbus->timing.tick_stddev, xbus->timing.timing_count); + len += sprintf(page + len, + "sync_offset_usec=%ld\n", xbus->sync_offset_usec); + 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); + /* reset statistics */ + xbus->min_tx_sync = INT_MAX; + xbus->max_tx_sync = 0; + xbus->min_rx_sync = INT_MAX; + xbus->max_rx_sync = 0; + 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_poller *poller; + int ret; + + if(!xbus) + goto out; + /* first handle special cases */ + if(!count || off) + goto out; + /* + * poller is created before /proc/XBUS-?? + * So by now it exists and initialized. + */ + poller = xbus->poller; + BUG_ON(!poller); + XBUS_DBG(DEVICES, xbus, + "Waiting for card initialization of %d XPD's max %d seconds\n", + atomic_read(&poller->count_xpds_to_initialize), INITIALIZATION_TIMEOUT/HZ); + /* + * when polling is finished xbus_poll(): + * - Unset poller->is_polling + * - Sets poller->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(poller->wait_for_xpd_initialization, + !poller->is_polling && ( + atomic_read(&poller->count_poll_answers) == 0 || + atomic_read(&poller->count_xpds_to_initialize) == 0 || + atomic_read(&poller->count_xpds_initialized) >= + atomic_read(&poller->count_xpds_to_initialize)), + 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", + atomic_read(&poller->count_xpds_initialized), + (INITIALIZATION_TIMEOUT - ret)/HZ); + spin_lock_irqsave(&xbus->lock, flags); + len += sprintf(page + len, "XPDS_READY: %s: %d/%d\n", + xbus->busname, + atomic_read(&poller->count_xpds_initialized), + atomic_read(&poller->count_xpds_to_initialize)); + 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 > %d)\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, "%3d> '%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); + 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->busdesc, + 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); +} + +void transport_destroy(xbus_t *xbus) +{ + int ret; + + BUG_ON(!xbus); + xbus->transport.transport_running = 0; + XBUS_INFO(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_poller_notify); +EXPORT_SYMBOL(xbus_command_queue_tick); +#ifdef XPP_DEBUGFS +EXPORT_SYMBOL(xbus_log); +#endif diff --git a/kernel/xpp/xbus-core.h b/kernel/xpp/xbus-core.h new file mode 100644 index 0000000..de6e859 --- /dev/null +++ b/kernel/xpp/xbus-core.h @@ -0,0 +1,278 @@ +/* + * Written by Oron Peled + * 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 +#include /* 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_poller; +#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_DESC_REQ, + XBUS_N_DEV_DESC_FULL, + XBUS_N_DEV_DESC_EMPTY, + 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_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_(DESC_REQ), + C_(DEV_DESC_FULL), + C_(DEV_DESC_EMPTY), + 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_(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); + +/* + * 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 busdesc[XBUS_DESCLEN]; + char label[LABEL_SIZE]; + 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[2]; /* double buffer */ + struct xpp_timing timing; + atomic_t pcm_rx_counter; + unsigned int global_counter; + long sync_offset_usec; + + /* 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) */ + + struct xbus_poller *poller; + + /* + * 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 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); + +void xbus_poller_notify(xbus_t *xbus, struct card_desc_struct *card_desc); +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/kernel/xpp/xbus-pcm.c b/kernel/xpp/xbus-pcm.c new file mode 100644 index 0000000..0b1e5d1 --- /dev/null +++ b/kernel/xpp/xbus-pcm.c @@ -0,0 +1,1168 @@ +/* + * Written by Oron Peled + * 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 + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +# warning "This module is tested only with 2.6 kernels" +#endif + +#include +#include +#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 print_dbg; +#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 +DEF_PARM_BOOL(optimize_chanmute, 1, 0644, "Optimize by muting inactive channels"); +#endif + +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 +DEF_PARM_BOOL(pcm_tasklet, 0, 0644, "Handle PCM in a tasklet (lower interrupt load)"); +#define PCM_TASKLET_DEPRECATION "\n" \ + "====================================================================\n" \ + "CONFIGURATION ERROR: 'pcm_tasklet' module parameter is deprecated!!!\n" \ + "====================================================================\n" + +static xbus_t *syncer; /* current syncer */ +static struct xpp_timing ref_sync; +static atomic_t xpp_tick_counter; +static const struct xpp_timing *global_ticker; /* increment xpp_tick_counter */ +static bool zaptel_syncer = 0; + +#define PROC_SYNC "sync" +#define BIG_TICK_INTERVAL 1000 +#define SYNC_ADJ_MIN (-30) /* minimal firmware drift unit */ +#define SYNC_ADJ_MAX 30 /* maximal firmware drift unit */ +#define SYNC_ADJ_FACTOR(x) ((x) / 30) /* average usec/drift_unit */ + +#ifdef ZAPTEL_SYNC_TICK +static unsigned int zaptel_tick_count = 0; +#endif + +/*------------------------- SYNC Handling --------------------------*/ + + +const char *sync_mode_name(enum sync_mode mode) +{ + static const char *sync_mode_names[] = { + [SYNC_MODE_AB] "SYNC_MODE_AB", + [SYNC_MODE_NONE] "SYNC_MODE_NONE", + [SYNC_MODE_PLL] "SYNC_MODE_PLL", + [SYNC_MODE_QUERY] "SYNC_MODE_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"); +} + +void xpp_timing_init(struct xpp_timing *timing, const char *name) +{ + memset(timing, 0, sizeof(*timing)); + do_gettimeofday(&timing->timing_val); + spin_lock_init(&timing->lock); + timing->name = name; +} + +#define XPP_TIMING_SAMPLES 50 +#define XPP_TIMING_TICKS 100 +#define XPP_TIMING_MAX_STDDEV 500 + +static void xpp_timing_tick(struct xpp_timing *timing, const struct timeval *val) +{ + long usec; + int diff_sec; + int diff_usec; + unsigned long flags; + + spin_lock_irqsave(&timing->lock, flags); + if((timing->timing_count % XPP_TIMING_TICKS) != 0) + goto out; + diff_sec = val->tv_sec - timing->timing_val.tv_sec; + diff_usec = val->tv_usec - timing->timing_val.tv_usec; + timing->timing_val = *val; + /* ignore first batch of samples */ + if(timing->timing_count < (XPP_TIMING_TICKS * XPP_TIMING_SAMPLES)) + goto out; + if(abs(diff_sec) > 2) { + static int rate_limit; + + if((rate_limit++ % 1003) == 0) + NOTICE("TIMING(%s): bad timing: diff_sec=%d\n", + timing->name, diff_sec); + goto out; + } + usec = diff_sec * 1000000 + diff_usec; + if(usec) + timing->tick_rate = XPP_TIMING_TICKS * 1000000 / usec; + usec -= 1000 * XPP_TIMING_TICKS; /* normalize */ + + timing->accumulated_usec += usec; + timing->accumulated_usec_sqr += usec * usec; + if((timing->timing_count % (XPP_TIMING_TICKS * XPP_TIMING_SAMPLES)) == 0) { + int avg; + int stddev; + + avg = timing->accumulated_usec / XPP_TIMING_SAMPLES; + stddev = (timing->accumulated_usec_sqr / XPP_TIMING_SAMPLES); + stddev = int_sqrt(stddev); + timing->accumulated_usec = 0; + timing->accumulated_usec_sqr = 0; + if(stddev > XPP_TIMING_MAX_STDDEV) { + static int rate_limit; + + if((rate_limit++ % 1003) == 0) + NOTICE("TIMING(%s): bad timing: stddev=%d avg=%d\n", + timing->name, stddev, avg); + goto out; + } + timing->tick_avg = avg; + timing->tick_stddev = stddev; + } +out: + timing->timing_count++; + if(timing == global_ticker) + atomic_inc(&xpp_tick_counter); + spin_unlock_irqrestore(&timing->lock, flags); +} + +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); + xbus->self_ticking = 0; + } + } else if(timer_pending(&xbus->command_timer)) { + xbus->self_ticking = 1; + 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, "%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 %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); + xpp_set_syncer(xbus, 1); + break; + case SYNC_MODE_PLL: + xbus->sync_mode = mode; + xbus_set_command_timer(xbus, 0); + xpp_set_syncer(xbus, 0); + break; + case SYNC_MODE_NONE: /* lost sync source */ + xbus->sync_mode = mode; + xbus_set_command_timer(xbus, 1); + 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; + if (TRANSPORT_RUNNING(xbus)) { + 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(drift < SYNC_ADJ_MIN || drift > SYNC_ADJ_MAX); + do_gettimeofday(&now); + if(drift > xbus->sync_adjustment) + msg = "up"; + else + msg = "down"; + XBUS_DBG(SYNC, xbus, "DRIFT adjust %s (%d) (last update %ld seconds ago)\n", + msg, drift, now.tv_sec - xbus->pll_updated_at); + CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_PLL, drift); + xbus->pll_updated_at = now.tv_sec; +} + +#ifdef ZAPTEL_SYNC_TICK +int zaptel_sync_tick(struct zt_span *span, int is_master) +{ + xpd_t *xpd = span->pvt; + struct timeval now; + static int redundant_ticks; /* for extra spans */ + + if(!zaptel_syncer) + goto noop; + 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; + } + do_gettimeofday(&now); + xpp_timing_tick(&ref_sync, &now); + zaptel_tick_count++; + flip_parport_bit(1); + return 0; +noop: + return 0; /* No auto sync from zaptel */ +} +#endif + + +static void sync_rate_adjust(xbus_t *xbus) +{ + int offset; + + xbus->sync_offset_usec = xbus->timing.tick_avg - ref_sync.tick_avg; + /* Calculate required PLL fix */ + offset = SYNC_ADJ_FACTOR(xbus->sync_offset_usec); + if(offset < SYNC_ADJ_MIN) + offset = SYNC_ADJ_MIN; + 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); +} + +/* + * 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 = (zaptel_syncer) ? "ZAPTEL" : "NO-SYNC"; + int i; + + DBG(SYNC, "%s => %s\n", + (syncer) ? syncer->busname : msg, + (new_syncer) ? new_syncer->busname : msg); + if(new_syncer) { + XBUS_DBG(SYNC, new_syncer, "pcm_rx_counter=%d\n", + atomic_read(&new_syncer->pcm_rx_counter)); + zaptel_syncer = 0; + global_ticker = &new_syncer->timing; + xbus_request_sync(new_syncer, SYNC_MODE_AB); + } else + global_ticker = &ref_sync; + 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) + 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; + + /* 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;xec, 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) +{ + struct zt_chan *chans = xpd->span.chans; + int i; + +#ifdef WITH_ECHO_SUPPRESSION + /* 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; +#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(print_dbg & DBG_PCM ) + dump_xframe("TX_XFRAME_PCM", xbus, xframe); + 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 + 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(print_dbg & DBG_PCM) + dump_xframe("RX_XFRAME_PCM", xbus, xframe); + /* 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); + } + 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); + } + 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); + } + 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 + */ + i = atomic_read(&xbus->pcm_rx_counter) & 1; + while((xframe = xframe_dequeue(&xbus->pcm_tospan[i])) != 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); + } +} + +void do_tick(xbus_t *xbus, struct timeval tv_received) +{ + int counter = atomic_read(&xpp_tick_counter); + + xbus_command_queue_tick(xbus); + xpp_timing_tick(&xbus->timing, &tv_received); + if(syncer == xbus) { + xpp_timing_tick(&ref_sync, &tv_received); + if((counter % BIG_TICK_INTERVAL) == 0) + reset_sync_counters(); + } + if((atomic_read(&xbus->pcm_rx_counter) % BIG_TICK_INTERVAL) == 0) { + if(xbus->sync_mode == SYNC_MODE_PLL) + sync_rate_adjust(xbus); + } + if(likely(xbus->self_ticking)) + xbus_tick(xbus); + xbus->global_counter = counter; +} + +void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe) +{ + int which = atomic_read(&xbus->pcm_rx_counter) & 1; + + if(!xframe_enqueue(&xbus->pcm_tospan[which], 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 +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(zaptel_syncer) + 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(zaptel_syncer) { + 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, &ref_sync.timing_val); + len += sprintf(page + len, "\ntick: #%d\n", counter); + len += sprintf(page + len, + "tick rate: %4d/second (measured %ld.%ld msec ago)\n", + ref_sync.tick_rate, + usec / 1000, usec % 1000); + if(pcm_tasklet) + len += sprintf(page + len, PCM_TASKLET_DEPRECATION); + 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"); + zaptel_syncer=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 +#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 + if(pcm_tasklet) + ERR(PCM_TASKLET_DEPRECATION); + xpp_timing_init(&ref_sync, "REF-SYNC"); +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); + diff --git a/kernel/xpp/xbus-pcm.h b/kernel/xpp/xbus-pcm.h new file mode 100644 index 0000000..79d0078 --- /dev/null +++ b/kernel/xpp/xbus-pcm.h @@ -0,0 +1,106 @@ +/* + * Written by Oron Peled + * 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 +#include + +#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, +}; + +/* + * A generic timing source. Encapsulates all sampling + * logic, average and standard deviation computation, + * tick_rate computation. + * + * Each xbus has embedded instance. + * Also there is a global instance for external reference + * syncing (e.g: from zaptel) + */ +struct xpp_timing { + const char *name; + struct timeval timing_val; + unsigned long timing_count; + long accumulated_usec; + long accumulated_usec_sqr; + int tick_avg; + int tick_stddev; + spinlock_t lock; + unsigned int tick_rate; +}; + +void xpp_timing_init(struct xpp_timing *timing, const char *name); + +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 + +#endif /* __KERNEL__ */ + +#endif /* XBUS_PCM_H */ + diff --git a/kernel/xpp/xbus-sysfs.c b/kernel/xpp/xbus-sysfs.c new file mode 100644 index 0000000..d45058e --- /dev/null +++ b/kernel/xpp/xbus-sysfs.c @@ -0,0 +1,273 @@ +/* + * Written by Oron Peled + * 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 + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +# warning "This module is tested only with 2.6 kernels" +#endif + +#include +#include +#include +#include +#ifdef PROTOCOL_DEBUG +#include +#endif +#include +#include +#include /* 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 print_dbg; + + +/* 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_FUNC(name,dev,buf) \ + ssize_t name(struct device *dev, struct device_attribute *attr, char *buf) +#else +#define DEVICE_ATTR_FUNC(name,dev,buf) \ + ssize_t name(struct device *dev, char *buf) +#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_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; + + if(!dev) + return -ENODEV; + xbus = dev_to_xbus(dev); + DBG(GENERAL, "bus_id=%s xbus=%s\n", dev->bus_id, xbus->busname); + XBUS_ADD_UEVENT_VAR("XBUS_NUM=%02d", xbus->num); + XBUS_ADD_UEVENT_VAR("XBUS_NAME=%s", xbus->busname); + envp[i] = NULL; + return 0; +} +#endif + +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_FUNC(connector_show, dev, buf) +{ + xbus_t *xbus; + int ret; + + xbus = dev_to_xbus(dev); + ret = snprintf(buf, PAGE_SIZE, "%s\n", xbus->busdesc); + return ret; +} + +static DEVICE_ATTR_FUNC(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_FUNC(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(connector, S_IRUGO, connector_show, NULL); +static DEVICE_ATTR(label, S_IRUGO, label_show, NULL); +static DEVICE_ATTR(status, S_IRUGO, status_show, NULL); + +void xbus_sysfs_remove(xbus_t *xbus) +{ + struct device *astribank; + + BUG_ON(!xbus); + XBUS_DBG(GENERAL, xbus, "\n"); + astribank = &xbus->astribank; + BUG_ON(!astribank); + 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; /* FIXME: add some usefull data */ + 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; + } +out: + return ret; +} diff --git a/kernel/xpp/xdefs.h b/kernel/xpp/xdefs.h new file mode 100644 index 0000000..2aec497 --- /dev/null +++ b/kernel/xpp/xdefs.h @@ -0,0 +1,131 @@ +#ifndef XDEFS_H +#define XDEFS_H +/* + * Written by Oron Peled + * 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 +#include + +#else + +/* This is to enable user-space programs to include this. */ + +#include +typedef uint8_t __u8; +typedef uint32_t __u32; + +#include + +#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) + +#define BIT(i) (1 << (i)) +#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 BIT(UNIT_BITS) /* 1 FXS + 3 FXS/FXO | 1 BRI + 3 FXS/FXO */ +#define MAX_SUBUNIT BIT(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-30 for E1, 31 = ALL_CHANS */ +#define ALL_CHANS BITMASK(CHAN_BITS) +#define MAX_CHAN (ALL_CHANS - 1) +#define VALID_CHAN_NUM(x) ((x) < MAX_CHAN) + +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; + +#endif /* XDEFS_H */ diff --git a/kernel/xpp/xframe_queue.c b/kernel/xpp/xframe_queue.c new file mode 100644 index 0000000..23dee0e --- /dev/null +++ b/kernel/xpp/xframe_queue.c @@ -0,0 +1,258 @@ +#include "xframe_queue.h" +#include "xbus-core.h" +#include "zap_debug.h" + +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; +} + +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_INFO(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) { + XBUS_ERR(xbus, "%s: failed frame allocation\n", q->name); + goto out; + } + if(!__xframe_enqueue(q, xframe)) { + 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) { + 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/kernel/xpp/xframe_queue.h b/kernel/xpp/xframe_queue.h new file mode 100644 index 0000000..5612d65 --- /dev/null +++ b/kernel/xpp/xframe_queue.h @@ -0,0 +1,34 @@ +#ifndef XFRAME_QUEUE_H +#define XFRAME_QUEUE_H + +#include +#include +#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/kernel/xpp/xpd.h b/kernel/xpp/xpd.h new file mode 100644 index 0000000..3187227 --- /dev/null +++ b/kernel/xpp/xpd.h @@ -0,0 +1,223 @@ +#ifndef XPD_H +#define XPD_H + +/* + * Written by Oron Peled + * 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 +#include +#include +#include +#include +#ifdef XPP_DEBUGFS +#ifndef CONFIG_DEBUG_FS +#warning kernel does not include CONFIG_DEBUG_FS, canceling XPP_DEBUGFS support +#undef XPP_DEBUGFS +#else +#include +#endif +#endif +#endif /* __KERNEL__ */ + +#include + +#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; + xbus_t *xbus; + byte rev; /* Revision number */ + byte type; /* LSB: 1 - to_phone, 0 - to_line */ + byte subtype; + struct xpd_addr xpd_addr; + xpp_line_t line_status; /* Initial line status (offhook) */ +}; + +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; + byte revision; /* Card revision */ + xpd_direction_t direction; /* TO_PHONE, TO_PSTN */ + 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; +#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_NT || (xpd)->type == XPD_TYPE_BRI_TE) +#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/kernel/xpp/xpp_log.h b/kernel/xpp/xpp_log.h new file mode 100644 index 0000000..322b7f0 --- /dev/null +++ b/kernel/xpp/xpp_log.h @@ -0,0 +1,52 @@ +#ifndef XPP_LOG_H +#define XPP_LOG_H +/* + * Written by Alexander Landau + * 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 +#include + +#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/kernel/xpp/xpp_usb.c b/kernel/xpp/xpp_usb.c new file mode 100644 index 0000000..785e713 --- /dev/null +++ b/kernel/xpp/xpp_usb.c @@ -0,0 +1,1085 @@ +/* + * Written by Oron Peled + * 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 +#include +#include +#include +#include +#include +#include +#include /* for udelay */ +#include +#include +#include +#include +#include +#include +#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$"; + +DEF_PARM(int, print_dbg, 0, 0644, "Print DBG statements"); /* must be before zap_debug.h */ +DEF_PARM(int, usb1, 0, 0644, "Allow using USB 1.1 interfaces"); +DEF_PARM(uint, tx_sluggish, 2000, 0644, "A sluggish transmit (usec)"); +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)((print_dbg & (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 int xframe_send_pcm(xbus_t *xbus, xframe_t *xframe); +static int xframe_send_cmd(xbus_t *xbus, xframe_t *xframe); +static 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 */ + 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); + kfree(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; +} + +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; + static int rate_limit; + + BUG_ON(!xframe); + BUG_ON(xframe->xframe_magic != XFRAME_MAGIC); + xusb = xusb_of(xbus); + BUG_ON(!xusb); + if(!xusb->present) { + 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) < 5) + XUSB_ERR(xusb, "failed submit_urb: %d\n", ret); + ret = -EBADF; + goto failure; + } +// if (print_dbg) +// dump_xframe("USB_FRAME_SEND", xbus, xframe); + 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) { + XBUS_ERR(xbus, "Failed to submit a receive urb\n"); + FREE_RECV_XFRAME(xbus, xframe); + goto out; + } + 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; +} + +/** + * 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; + } + + /* 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) + if((retval = __usb_reset_device(udev)) < 0) { +#else + if((retval = usb_reset_device(udev)) < 0) { +#endif + 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->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->busdesc, 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->busdesc); + +#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; + 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 + usb_deregister_dev(interface, &xusb_class); + kfree(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; + } + 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); + 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! + xusb->present = 0; + 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"); + kfree(xusb); + + up (&disconnect_sem); + XUSB_INFO(xusb, "now disconnected\n"); +} + +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); + 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; + + //flip_parport_bit(7); + if(!xbus) { + XUSB_ERR(xusb, "Received URB does not belong to a valid xbus anymore...\n"); + return; + } + if (urb->status) { + DBG(GENERAL, "nonzero read bulk status received: %d\n", urb->status); + XUSB_COUNTER(xusb, RX_ERRORS)++; + goto err; + } + if(!XBUS_GET(xbus)) { + XUSB_ERR(xusb, "Dropping urb. Is shutting down.\n"); + do_resubmit = 0; + goto err; + } + is_inuse = 1; + if(!xusb->present) { + XUSB_ERR(xusb, "A packet from non-connected device?\n"); + do_resubmit = 0; + 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); + do_gettimeofday(&xframe->tv_received); + +// if (print_dbg) +// dump_xframe("USB_FRAME_RECEIVE", xbus, xframe); + 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; + } +} + +int __init xpp_usb_init(void) +{ + int ret; + //xusb_t *xusb; + + INFO("revision %s [sizeof(uframe)=%d]\n", XPP_VERSION, sizeof(struct uframe)); + 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; +} + + +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, "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 "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(XPP_VERSION); + +module_init(xpp_usb_init); +module_exit(xpp_usb_shutdown); diff --git a/kernel/xpp/xpp_zap.c b/kernel/xpp/xpp_zap.c new file mode 100644 index 0000000..edaedf9 --- /dev/null +++ b/kernel/xpp/xpp_zap.c @@ -0,0 +1,1049 @@ +/* + * Written by Oron Peled + * 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 + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +# warning "This module is tested only with 2.6 kernels" +#endif + +#include +#include +#include +#include +#include +#include /* for udelay */ +#include +#include +#include +#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, print_dbg, 0, 0644, "Print DBG statements"); +DEF_PARM_BOOL(zap_autoreg, 0, 0644, "Register spans automatically (1) or not (0)"); +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); +static void xpd_free(xpd_t *xpd); + +static void xpd_free(xpd_t *xpd) +{ + xbus_t *xbus = NULL; + + if(!xpd) + return; + xbus = xpd->xbus; + if(!xbus) + return; + XPD_DBG(DEVICES, xpd, "\n"); +#ifdef CONFIG_PROC_FS + if(xpd->proc_xpd_dir) { + 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 proc directory\n"); + remove_proc_entry(xpd->xpdname, xbus->proc_xbus_dir); + xpd->proc_xpd_dir = NULL; + } +#endif + xbus_unregister_xpd(xbus, xpd); + if(xpd->xproto) + xproto_put(xpd->xproto); + xpd->xproto = NULL; + KZFREE(xpd); +} + + +/*------------------------- XPD Management -------------------------*/ + +/* + * Synchronous part of XPD detection. + * Called from xbus_poll() + */ +void card_detected(struct card_desc_struct *card_desc) +{ + xbus_t *xbus; + xpd_t *xpd = NULL; + byte type; + byte subtype; + int unit; + int subunit; + byte rev; + const xops_t *xops; + const xproto_table_t *proto_table; + + + BUG_ON(!card_desc); + BUG_ON(card_desc->magic != CARD_DESC_MAGIC); + xbus = card_desc->xbus; /* refcount held by xbus_poll() */ + type = card_desc->type; + subtype = card_desc->subtype; + unit = card_desc->xpd_addr.unit; + subunit = card_desc->xpd_addr.subunit; + rev = card_desc->rev; + BUG_ON(!xbus); + xpd = xpd_byaddr(xbus, unit, subunit); + if(xpd) { + if(type == XPD_TYPE_NOMODULE) { + XBUS_NOTICE(xbus, "XPD at %d%d removed\n", + unit, subunit); + BUG(); + goto out; + } + XPD_NOTICE(xpd, "XPD at %d%d already exists\n", + unit, subunit); + goto out; + } + if(type == XPD_TYPE_NOMODULE) { + XBUS_NOTICE(xbus, "XPD at %d%d Missing\n", + unit, subunit); + goto out; + } + proto_table = xproto_get(type); + if(!proto_table) { + XBUS_NOTICE(xbus, "XPD at %d%d: missing protocol table for type=%d. Ignored.\n", + unit, subunit, + type); + goto out; + } + xops = &proto_table->xops; + BUG_ON(!xops); + xpd = xops->card_new(xbus, unit, subunit, proto_table, subtype, rev); + if(!xpd) { + XBUS_NOTICE(xbus, "card_new(%d,%d,%d,%d,%d) failed. Ignored.\n", + unit, subunit, proto_table->type, subtype, rev); + xproto_put(proto_table); + goto err; + } + xpd->addr = card_desc->xpd_addr; + xpd->xbus_idx = XPD_IDX(unit,subunit); + snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%1d%1d", unit, subunit); + xpd->subtype = card_desc->subtype; + xpd->offhook = card_desc->line_status; + + /* 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); + } + xbus_register_xpd(xbus, 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; +#endif + if(CALL_XMETHOD(card_init, xbus, xpd) < 0) + goto err; + //CALL_XMETHOD(XPD_STATE, xbus, xpd, 0); /* Turn off all channels */ + xpd->card_present = 1; + CALL_XMETHOD(XPD_STATE, xbus, xpd, 1); /* Turn on all channels */ + XPD_INFO(xpd, "Initialized: %s\n", xpd->type_name); + + if(zap_autoreg) + zaptel_register_xpd(xpd); +out: + KZFREE(card_desc); + return; +err: + xpd_free(xpd); + goto out; +} + + +#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, "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; + + DBG(DEVICES, "type=%d channels=%d (alloc_size=%d)\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; + } + 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; ispan.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 +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; +} + +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]; + int blink; + 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", &blink); + if(ret != 1) + return -EINVAL; + XPD_DBG(GENERAL, xpd, "%s\n", (blink) ? "blink" : "unblink"); + 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 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 +} + +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; +} + +void __exit xpp_zap_cleanup(void) +{ + xbus_pcm_shutdown(); + xbus_core_shutdown(); + do_cleanup(); +} + +EXPORT_SYMBOL(print_dbg); +EXPORT_SYMBOL(card_detected); +EXPORT_SYMBOL(xpd_alloc); +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 "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(XPP_VERSION); + +module_init(xpp_zap_init); +module_exit(xpp_zap_cleanup); diff --git a/kernel/xpp/xpp_zap.h b/kernel/xpp/xpp_zap.h new file mode 100644 index 0000000..fee20c5 --- /dev/null +++ b/kernel/xpp/xpp_zap.h @@ -0,0 +1,49 @@ +#ifndef XPP_ZAP_H +#define XPP_ZAP_H +/* + * Written by Oron Peled + * 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); +void card_detected(struct card_desc_struct *card_desc); +xpd_t *xpd_alloc(size_t privsize, const xproto_table_t *proto_table, int channels); +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 + +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/kernel/xpp/xproto.c b/kernel/xpp/xproto.c new file mode 100644 index 0000000..d55949e --- /dev/null +++ b/kernel/xpp/xproto.c @@ -0,0 +1,446 @@ +/* + * Written by Oron Peled + * 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 +#include + +static const char rcsid[] = "$Id$"; + +extern int print_dbg; + +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); +} + +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); +} + +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, print_dbg); + } + 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, print_dbg); + } + 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; + + 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); + } + 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); + } + 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); + } + 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 + 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 print_dbg) +{ + byte op = XPACKET_OP(packet); + byte *addr = (byte *)&XPACKET_ADDR(packet); + + if(!print_dbg) + 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 (print_dbg) + printk("%02X ", p[i]); + } + } +#endif + printk("\n"); +} + +void dump_reg_cmd(const char msg[], const reg_cmd_t *regcmd, bool writing) +{ + char action; + byte chipsel; + + if(regcmd->bytes != sizeof(*regcmd) - 1) { /* The size byte is not included */ + NOTICE("%s: Wrong size: regcmd->bytes = %d\n", __FUNCTION__, regcmd->bytes); + return; + } + if(writing && (REG_FIELD(regcmd, chipsel) & 0x80)) + ERR("Sending register command with reading bit ON\n"); + action = (writing) ? 'W' : 'R'; + chipsel = REG_FIELD(regcmd, chipsel) & ~0x80; + if(REG_FIELD(regcmd, do_subreg)) { + DBG(GENERAL, "%s: %d %cS %02X %02X [%02X] # data_high=%X m=%d eof=%d\n", msg, chipsel, action, + REG_FIELD(regcmd, regnum), + REG_FIELD(regcmd, subreg), + REG_FIELD(regcmd, data_low), + REG_FIELD(regcmd, data_high), + regcmd->multibyte, regcmd->eoframe); + } else if(REG_FIELD(regcmd, regnum) == 0x1E) { + DBG(GENERAL, "%s: %d %cI %02X [%02X %02X] # m=%d eof=%d\n", msg, chipsel, action, + REG_FIELD(regcmd, subreg), + REG_FIELD(regcmd, data_low), + REG_FIELD(regcmd, data_high), + regcmd->multibyte, regcmd->eoframe); + } else { + DBG(GENERAL, "%s: %d %cD %02X [%02X] # data_high=%X m=%d eof=%d\n", msg, chipsel, action, + REG_FIELD(regcmd, regnum), + REG_FIELD(regcmd, data_low), + REG_FIELD(regcmd, data_high), + regcmd->multibyte, regcmd->eoframe); + } +} + +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); + CHECK_XOP(RING); + CHECK_XOP(RELAY_OUT); + + 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/kernel/xpp/xproto.h b/kernel/xpp/xproto.h new file mode 100644 index 0000000..f68fedf --- /dev/null +++ b/kernel/xpp/xproto.h @@ -0,0 +1,306 @@ +#ifndef XPROTO_H +#define XPROTO_H +/* + * Written by Oron Peled + * 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 +#include +#include + +/* + * This must match the firmware protocol version + */ +#define XPP_PROTOCOL_VERSION 29 + +struct xpd_addr { + uint8_t unit:UNIT_BITS; + uint8_t subunit:SUBUNIT_BITS; + uint8_t reserved:1; + uint8_t sync_master:1; +} PACKED; + +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 3 // TO_PHONE +#define XPD_TYPE_FXO 4 // TO_PSTN +#define XPD_TYPE_BRI_TE 6 // TO_PSTN +#define XPD_TYPE_BRI_NT 7 // TO_PHONE +#define XPD_TYPE_PRI 9 // TO_PSTN/TO_PHONE (runtime) +#define XPD_TYPE_NOMODULE 15 + +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 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, len); \ + if(!(p)) \ + return -ENOMEM; \ + XPACKET_INIT(p, card, op, to, 0, 0); \ + } while(0) + +#endif + +/*--------------------------- register handling --------------------------------*/ +/* + * After the opcode, there are always: + * * A size (in bytes) of the rest. Only 6 bits are counted: + * - The MSB signifies a multibyte write (to BRI fifo) + * - The MSB-1 signifies end of frame to multibyte writes in BRI. + * A normal register command (not multibyte) than contains: + * * A channel selector byte: + * - ALL_CHANS (currently 31) is a broadcast request to set a + * register for all channels. + * - Smaller numbers (0-30) represent the addressed channel number. + * - The MSB signifies: + * 1 - register [R]ead request + * 0 - register [W]rite request + * * Register number + * * Subregister number -- 0 when there is no subregister + * * Data low + * * Data high -- 0 for single byte registers (direct registers) + * A multibyte register command than contains a sequence of bytes. + */ + +#define MULTIBYTE_MAX_LEN 5 /* FPGA firmware limitation */ + +typedef struct reg_cmd { + byte bytes:6; + byte eoframe:1; /* For BRI -- end of frame */ + byte multibyte:1; /* For BRI -- fifo data */ + union { + struct { + byte chipsel:CHAN_BITS; /* chip select */ + byte reserved:1; + byte do_subreg:1; + byte read_request: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, byte revision); + 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); + int (*RING)(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on); + int (*RELAY_OUT)(xbus_t *xbus, xpd_t *xpd, byte which, 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; + 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, DESC_REQ); + MEMBER(GLOBAL, DEV_DESC); + 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 print_dbg); +void dump_reg_cmd(const char msg[], const reg_cmd_t *regcmd, bool writing); +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/kernel/xpp/zap_debug.c b/kernel/xpp/zap_debug.c new file mode 100644 index 0000000..bf54e62 --- /dev/null +++ b/kernel/xpp/zap_debug.c @@ -0,0 +1,91 @@ +/* + * Written by Oron Peled + * 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 + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +# warning "This module is tested only with 2.6 kernels" +#endif + +#include +#include +#include +#include +#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 print_dbg, 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/kernel/xpp/zap_debug.h b/kernel/xpp/zap_debug.h new file mode 100644 index 0000000..fb1ecc3 --- /dev/null +++ b/kernel/xpp/zap_debug.h @@ -0,0 +1,190 @@ +#ifndef ZAP_DEBUG_H +#define ZAP_DEBUG_H +/* + * Written by Oron Peled + * 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 /* 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 DBG(bits, fmt, ...) \ + ((void)((print_dbg & (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)((print_dbg & (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)((print_dbg & (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)((print_dbg & (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__) + +/* + * Bits for print_dbg + */ +#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) /* instanciation/destruction etc. */ +#define DBG_ANY (~0) + +void dump_poll(int print_dbg, 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 */ -- cgit v1.2.3