summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-07-08 00:43:31 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-07-08 00:43:31 +0000
commitec6b220aa7a334ccbd0fcb41d35c66560fc78a11 (patch)
tree8ee3f2338f95b3fa67f8512adb8fe4842643c391
parent4e4b79bf56f6477b65973c869e5a8936aea27864 (diff)
xpp Release 1.1.0 :
* FPGA firmware now loaded from PC (for newer models) * Driver for the FXO module (xpd_fxo.ko) * Moved most userspace files to the subdirectory utils (see also next commit) * Explicit license for firmware files * Optionally avoid auto-registration * Registers initializations code is done by a userspace script. * Remove obsolete .inc initialization files (we use user-space init) * Added an install target to the utils dir. * Updated README.Astribank accordingly. * Using RBS signalling, as caller ID did not work well otherwise. * Better handling of USB protocol errors. * Fixed some procfs-related races. * per-card-module ioctls. * fxotune support. * opermode support (set through /etc/default/zaptel for now) * Userspace initialization script can also read registers. * Power calibration works (and implemented in perl) * some fine-tuning to the regster initialization parameters. * Leds turn on before registration and turn off after it. git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@1212 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rw-r--r--xpp/FPGA_XPD.hex243
-rw-r--r--xpp/LICENSE.firmware37
-rw-r--r--xpp/Makefile12
-rw-r--r--xpp/README.Astribank88
-rw-r--r--xpp/card_fxo.c946
-rw-r--r--xpp/card_fxo.h61
-rw-r--r--xpp/card_fxs.c873
-rw-r--r--xpp/card_fxs.h24
-rw-r--r--xpp/card_global.c57
-rw-r--r--xpp/card_global.h7
-rw-r--r--xpp/cards.c394
-rw-r--r--xpp/cards.h23
-rwxr-xr-xxpp/gen_slic_init37
-rw-r--r--xpp/init_data_3_19.cmd169
-rw-r--r--xpp/init_data_3_20.cmd170
-rw-r--r--xpp/init_data_4_19.cmd69
-rw-r--r--xpp/init_data_4_20.cmd60
-rwxr-xr-xxpp/initialize_registers39
-rw-r--r--xpp/slic.c49
-rw-r--r--xpp/slic.h28
-rw-r--r--xpp/slic_init.inc65
-rwxr-xr-xxpp/sync.sh31
-rw-r--r--xpp/utils/FPGA_FXS.hex543
-rw-r--r--xpp/utils/Makefile50
-rw-r--r--xpp/utils/USB_1130.hex309
-rw-r--r--xpp/utils/USB_8613.hex301
-rw-r--r--xpp/utils/fpga_load.872
-rw-r--r--xpp/utils/fpga_load.c822
-rwxr-xr-xxpp/utils/genzaptelconf955
-rw-r--r--xpp/utils/genzaptelconf.8258
-rw-r--r--xpp/utils/hexfile.c360
-rw-r--r--xpp/utils/hexfile.h120
-rw-r--r--xpp/utils/test_parse.c34
-rw-r--r--xpp/utils/xpp_fxloader163
-rw-r--r--xpp/utils/xpp_fxloader.usermap (renamed from xpp/xpp_fxloader.usermap)2
-rw-r--r--xpp/utils/xpp_modprobe (renamed from xpp/xpp_modprobe)6
-rw-r--r--xpp/xbus-core.c874
-rw-r--r--xpp/xbus-core.h56
-rw-r--r--xpp/xdefs.h74
-rw-r--r--xpp/xpd.h178
-rw-r--r--xpp/xpp_fxloader24
-rw-r--r--xpp/xpp_proto.c1044
-rw-r--r--xpp/xpp_proto.h188
-rw-r--r--xpp/xpp_usb.c445
-rw-r--r--xpp/xpp_zap.c1649
-rw-r--r--xpp/xpp_zap.h60
-rw-r--r--xpp/xproto.c88
-rw-r--r--xpp/xproto.h97
-rw-r--r--xpp/zap_debug.c73
-rw-r--r--xpp/zap_debug.h119
50 files changed, 8436 insertions, 4010 deletions
diff --git a/xpp/FPGA_XPD.hex b/xpp/FPGA_XPD.hex
deleted file mode 100644
index 094f2c9..0000000
--- a/xpp/FPGA_XPD.hex
+++ /dev/null
@@ -1,243 +0,0 @@
-:0A0B3C000001020203030404050592
-:100546005010C0C0F9A4B0999282F880988883C6EA
-:03055600A1868EED
-:1002B700E4F513F512F511F510C203C200C202C22C
-:1002C700011206377E077F008E238F24752B077553
-:1002D7002C1275210775221C752907752A4A752D59
-:1002E70007752E78EE54C070030203B875140075B5
-:1002F70015808E168F17C374C09FFF74079ECF2477
-:1003070002CF3400FEE48F0F8E0EF50DF50CF50BC2
-:10031700F50AF509F508AF0FAE0EAD0DAC0CAB0B3A
-:10032700AA0AA909A808C3120B205033E517250B01
-:10033700F582E516350AF583E0FFE515250BF5820D
-:10034700E514350AF583EFF0E50B2401F50BE435E9
-:100357000AF50AE43509F509E43508F50880B78593
-:10036700142385152474002480FF740734FFFEC30B
-:10037700E52C9FF52CE52B9EF52BC3E5269FF5264F
-:10038700E5259EF525C3E5289FF528E5279EF52752
-:10039700C3E5229FF522E5219EF521C3E52A9FF5B6
-:1003A7002AE5299EF529C3E52E9FF52EE52D9EF515
-:1003B7002DD2E843D82090E668E0440BF090E65C45
-:1003C700E0443DF0000000000000E4F5A20000005A
-:1003D700D2AF90E680E020E105D2041206D090E685
-:1003E70080E054F7F0538EF8C20390E6C2E054FB66
-:1003F700F000000000000090E6187410F000000004
-:1004070090E61A7408F000000090E6017403F0000B
-:100417000000300105120080C2013003F5120B5AAB
-:1004270050F0C203120A7B20001690E682E030E704
-:1004370004E020E1EF90E682E030E604E020E0E42B
-:080447001209FC120B5C80CAD3
-:0B0B310090E50DE030E402C322D32267
-:1000800090E6B9E0700302013F1470030201BC2442
-:10009000FE700302023F24FB700302013914700357
-:1000A00002013314700302012714700302012D248E
-:1000B0000560030202A3120B5E40030202AF90E64A
-:1000C000BBE024FE602714603824FD601114602713
-:1000D00024067050E52390E6B3F0E524803C120B33
-:1000E00031503EE52B90E6B3F0E52C802DE52590D0
-:1000F000E6B3F0E5268023E52790E6B3F0E5288017
-:100100001990E6BAE0FF120A28AA06A9077B01EABD
-:10011000494B600DEE90E6B3F0EF90E6B4F00202CA
-:10012000AF02029E02029E120B0E0202AF120B4E93
-:100130000202AF120B460202AF120AFC0202AF1219
-:100140000B6040030202AF90E6B8E0247F60151414
-:10015000601924027063A200E43325E0FFA202E4E8
-:10016000334F8041E490E740F0803F90E6BCE0549C
-:100170007EFF7E00E0D394807C0040047D018002FD
-:100180007D00EC4EFEED4F243CF582740B3EF58372
-:10019000E493FF3395E0FEEF24A1FFEE34E68F8277
-:1001A000F583E0540190E740F0E4A3F090E68AF094
-:1001B00090E68B7402F00202AF02029E120B6240C4
-:1001C000030202AF90E6B8E024FE6016240260034A
-:1001D0000202AF90E6BAE0B40105C2000202AF022B
-:1001E000029E90E6BAE0705590E6BCE0547EFF7E39
-:1001F00000E0D394807C0040047D0180027D00EC0F
-:100200004EFEED4F243CF582740B3EF583E493FFE4
-:100210003395E0FEEF24A1FFEE34E68F82F583E014
-:1002200054FEF090E6BCE05480131313541FFFE01B
-:10023000540F2F90E683F0E04420F08072805F122C
-:100240000B64506B90E6B8E024FE60192402704EF7
-:1002500090E6BAE0B40104D200805490E6BAE064BB
-:1002600002604C803990E6BCE0547EFF7E00E0D313
-:1002700094807C0040047D0180027D00EC4EFEED08
-:100280004F243CF582740B3EF583E493FF3395E0F5
-:10029000FEEF24A1FFEE34E68F82F583800D90E619
-:1002A000A08008120A53500790E6A0E04401F090A5
-:0602B000E6A0E04480F02E
-:0102B6002225
-:03003300020B5667
-:040B560053D8EF324F
-:100700001201000200000040E4E411220000010296
-:1007100000010A06000200000040010009022E004C
-:1007200001010080320904000004FF0000000705F9
-:10073000020200020007050402000200070586020B
-:100740000002000705880200020009022E000101D4
-:100750000080320904000004FF00000007050202C7
-:100760004000000705040240000007058602400023
-:100770000007058802400000040309041C0341002F
-:100780007300740072006900620061006E006B000B
-:10079000320030003000360028035800500044007A
-:1007A00028004200610073006500640020006F00B3
-:1007B0006E002000410058005500500050002900F4
-:0207C000000037
-:100559005010B0C0F9A4B0999282F880988883C6E7
-:10056900A1868E4110ABFF4110AD004110AEFF4195
-:0705790010AC004110AF00BF
-:1006370090E600E054E74410F000000090E60474F0
-:1006470080F00000007406F0000000E4F0000000F5
-:1006570090E610F090E611F000000090E613F0002D
-:10066700000090E615F090E61074A0F090E611F007
-:1006770000000000000090E61274AAF0000000904D
-:10068700E61474EAF000000090E6047480F00000BD
-:10069700007404F0000000E4F000000090E64974E4
-:1006A70082F0000000F000000090E6187410F000DF
-:1006B700000090E61A7408F090E6917480F000004C
-:0906C70000F000000043AF012225
-:020B5A00D322A4
-:020B5C00D322A2
-:020B5E00D322A0
-:080B460090E6BAE0F51BD32292
-:100AFC0090E740E51BF0E490E68AF090E68B04F07A
-:020B0C00D322F2
-:080B4E0090E6BAE0F51AD3228B
-:100B0E0090E740E51AF0E490E68AF090E68B04F068
-:020B1E00D322E0
-:020B6000D3229E
-:020B6200D3229C
-:020B6400D3229A
-:100A530090E6B9E0242F600D04701990E604E0FFDE
-:100A6300430780800890E604E0FF53077F000000FF
-:070A7300EFF08002D322C363
-:010A7A002259
-:100AA000C0E0C083C082D2015391EF90E65D740133
-:080AB000F0D082D083D0E032C7
-:100AD000C0E0C083C0825391EF90E65D7404F0D013
-:060AE00082D083D0E03259
-:100AE600C0E0C083C0825391EF90E65D7402F0D0FF
-:060AF60082D083D0E03243
-:1009C600C0E0C083C082852925852A2685268285A2
-:1009D6002583A37402F08521278522288528828510
-:1009E6002783A37407F05391EF90E65D7410F0D05F
-:0609F60082D083D0E03244
-:100AB800C0E0C083C082D2035391EF90E65D740812
-:080AC800F0D082D083D0E032AF
-:1007C200C0E0C083C08290E680E030E7208521252A
-:1007D200852226852682852583A37402F085292712
-:1007E200852A28852882852783A37407F05391EFF1
-:0D07F20090E65D7420F0D082D083D0E0321C
-:0106FF0032C8
-:0107FF0032C7
-:010B6600325C
-:010B6700325B
-:010B6800325A
-:010B69003259
-:010B6A003258
-:010B6B003257
-:010B6C003256
-:010B6D003255
-:010B6E003254
-:010B6F003253
-:010B70003252
-:010B71003251
-:010B72003250
-:010B7300324F
-:010B7400324E
-:010B7500324D
-:010B7600324C
-:010B7700324B
-:010B7800324A
-:010B79003249
-:010B7A003248
-:010B7B003247
-:010B7C003246
-:010B7D003245
-:010B7E003244
-:010B7F003243
-:010B80003242
-:010B81003241
-:010B82003240
-:010B8300323F
-:010B8400323E
-:010B8500323D
-:10098A00C0E0C083C08290E6D1E09010ACF090E65F
-:10099A00D0E4F000000090E6D17402F000000053A9
-:1009AA0091BF00000090E66104F000000090E69913
-:0C09BA0004F075BB06D082D083D0E03280
-:010B8600323C
-:03004300020800B0
-:03005300020800A0
-:10080000020AA000020AE600020AD000020AB800AA
-:100810000209C6000207C2000206FF000207FF002D
-:10082000020B6600020B6700020B6800020B6900F6
-:10083000020B6A00020B6B00020B6C00020B6D00D6
-:10084000020B6E000207FF00020B6F00020B70002C
-:10085000020B7100020B7200020B7300020B74009A
-:10086000020B75000207FF000207FF000207FF00EE
-:10087000020B7600020B7700020B7800020B790066
-:10088000020B7A00020B7B00020B7C00020B7D0046
-:10089000020B7E00020B7F00020B8000020B810026
-:1008A000020B8200020B8300020B8400020B850006
-:0808B00002098A00020B860018
-:1009FC0090E682E030E004E020E60B90E682E03006
-:100A0C00E119E030E71590E680E04401F07F147EB8
-:0C0A1C000012094490E680E054FEF02235
-:1006D00030040990E680E0440AF0800790E680E06C
-:1006E0004408F07FDC7E0512094490E65D74FFF05B
-:0F06F00090E65FF05391EF90E680E054F7F02230
-:020A2800A9071C
-:100A2A00AE2DAF2E8F828E83A3E064037017AD01C3
-:100A3A0019ED7001228F828E83E07C002FFDEC3E3F
-:080A4A00FEAF0580DFE4FEFFB2
-:010A52002281
-:100A7B0090E682E044C0F090E681F04387010000ED
-:040A8B000000002245
-:100944008E188F1990E600E054187012E5192401EE
-:10095400FFE43518C313F518EF13F519801590E665
-:1009640000E05418FFBF100BE51925E0F519E51850
-:1009740033F518E5191519AE18700215184E6005EF
-:06098400120A8F80EE2232
-:100A8F007400F58690FDA57C05A3E582458370F97A
-:010A9F002234
-:1005800060801000011113213C01010703030305E2
-:10059000010000000C0D0C0C0E0E0E0E410000367A
-:1005A0000900003F010A013B0101010701010201AD
-:1005B0000000000002020000020202024049004066
-:1005C0000000003F010101010101010700000000DE
-:1005D000000000000E0E0E0E0E0E0E0E00000000AB
-:1005E0000000003F0139010101010107000302027F
-:1005F000020202020E0E0E0E0E0E0E0E002D000056
-:100600000000003F60241087000000000000000090
-:1006100000000000000000000000833611170004F5
-:10062000030201813616170004030201471080E01F
-:0606300000000ECE4E009A
-:10044F0090E60174CEF090E6F574FFF0901080E026
-:10045F0090E6F3F0901081E090E6C3F0901082E008
-:10046F0090E6C1F0901083E090E6C2F0901085E026
-:10047F0090E6C0F0901086E090E6F4F075AF077448
-:10048F0010F59A7400F59B759DE4E4F59EFF90E6D8
-:10049F007BE090E67CF00FBF80F490E67174FFF084
-:1004AF00F5B490E672E04480F043B680000000E4BB
-:1004BF0090E6C4F000000090E6C5F0901087E09041
-:1004CF00E6C6F0901088E090E6C7F0901089E090B3
-:1004DF00E6C8F090108AE090E6C9F090108BE0909B
-:1004EF00E6CAF090108CE090E6CBF090108DE09083
-:1004FF00E6CCF090108EE090E6CDF000000090E694
-:10050F00D27401F000000090E6E204F00000000059
-:10051F00000090E6EB14F000000000000000000067
-:10052F0090E6C0F090E6C1F090E6247408F0000069
-:06053F0000E490E625F047
-:010545002293
-:030000000208B83B
-:0C08B800787FE4F6D8FD75812E0208FF61
-:100B2000EB9FF5F0EA9E42F0E99D42F0E89C45F02B
-:010B300022A2
-:1008C4000202B7E493A3F8E493A34003F68001F291
-:1008D40008DFF48029E493A3F85407240CC8C33335
-:1008E400C4540F4420C8834004F456800146F6DF04
-:1008F400E4800B0102040810204080900546E47E49
-:10090400019360BCA3FF543F30E509541FFEE493F8
-:10091400A360010ECF54C025E060A840B8E493A3BF
-:10092400FAE493A3F8E493A3C8C582C8CAC583CAEA
-:10093400F0A3C8C582C8CAC583CADFE9DEE780BEA2
-:0106360000C3
-:00000001FF
diff --git a/xpp/LICENSE.firmware b/xpp/LICENSE.firmware
new file mode 100644
index 0000000..b9bb89f
--- /dev/null
+++ b/xpp/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/xpp/Makefile b/xpp/Makefile
index 1207332..cce22ad 100644
--- a/xpp/Makefile
+++ b/xpp/Makefile
@@ -1,5 +1,9 @@
-EXTRA_CFLAGS = -I$(src)/.. -DSOFT_SIMULATOR=0
+EXTRA_CFLAGS = -I$(SUBDIRS) -DDEBUG -DPOLL_DIGITAL_INPUTS -DWITH_ECHO_SUPPRESSION -DWITH_RBS
-obj-m = xpd_fxs.o xpp.o xpp_usb.o
-xpp-y += xproto.o card_global.o xpp_zap.o zap_debug.o
-xpd_fxs-y += card_fxs.o slic.o
+obj-m = xpp.o xpp_usb.o xpd_fxs.o xpd_fxo.o
+xpp-y += xbus-core.o xpp_zap.o xproto.o card_global.o
+xpd_fxs-y += card_fxs.o slic.o
+xpd_fxo-y += card_fxo.o slic.o
+
+ctags:
+ ctags *.[ch]
diff --git a/xpp/README.Astribank b/xpp/README.Astribank
index aa24371..f6f995c 100644
--- a/xpp/README.Astribank
+++ b/xpp/README.Astribank
@@ -5,15 +5,63 @@ The drivers reside in a separate subdirectory, xpp/ .
Building and Installation:
"""""""""""""""""""""""""
Building and installation is basically like the normal procedure of
-installing Zaptel. Follow the rest of the documentation here.
+installing Zaptel with some additions.
-In addition, the file xpp/xpp_modprobe contains modprobe settings. It
-should be copied verbatim into /etc/modprobe.conf or (better) copied to
-/etc/modprobe.d/ . If you fail to do so, xpp_usb.ko will fail to load
-xpd_fxs.ko and as a result will not detect your Astribank.
-
-Loading Firmware
+Building drivers:
""""""""""""""""
+From the toplevel zaptel directory run a command similar to (I used line
+continuation to prevent line wrapping):
+
+ $ make \
+ KSRC=/usr/src/kernel-headers-2.6.12-1-386 \
+ KVERS=2.6.12-1-386 \
+ XPPMOD=xpp/ \
+ EC_TYPE=CAN_KB1
+
+ - The KSRC= points to a configured kernel source tree.
+ - The KVERS= should match the relevant tree version.
+ - The XPPMOD= instructs the Zaptel Makefile to descend into the xpp/
+ subdirectory. The slash (/) in the end is mandatory.
+ - The EC_TYPE= select the echo canceler.
+
+Building firmware utilities:
+"""""""""""""""""""""""""""
+Then you should compile the firmware loading utilities. Simply go
+to the zaptel/xpp/utils and run make.
+
+Those who don't use prepackaged drivers should make sure they also
+install the (externally available) fxload utility.
+
+Installation:
+""""""""""""
+
+apart from the standard 'make install' in the zaptel directory,
+run:
+
+ make -C xpp/utils install
+
+Alternatively, do the following manually:
+
+All firmware files should be copied to a new directory:
+ /usr/share/zaptel/
+
+The xpp_fxloader and xpp_fxloader.usbmap should be copied to:
+ /etc/hotplug/usb/
+
+In addition, the file xpp/xpp_modprobe contains optional modprobe settings.
+It may be copied verbatim into /etc/modprobe.conf or (better) copied to
+/etc/modprobe.d/ .
+
+
+Note that loading through udev is not yet provided. Run
+
+ /etc/hotplug/usb/xpp_fxloader xppdetect
+
+to load firmware.
+
+
+Loading Firmware Details:
+""""""""""""""""""""""""
The Astribank needs a firmware loaded into it. Without the firmware,
the device will appear in lsusb with vendor ID 04b4 and product ID 8613
The firmware is provided in the Intel hex format. It can be loaded using
@@ -21,12 +69,11 @@ the program fxload, which is typically part of the package 'fxload' or
'hotplug-utils' .
To load the firmware automatically using the standard hotplug script,
-place xpp/xpp_fxloader and xpp/xpp_fxloader.usermap in /etc/hotplug/usb
-and place xpp/FPGA_XPD.hex in /etc/xortel (or edit xpp_fxloader
-accordingly).
+place xpp/utils/xpp_fxloader and xpp/utils/xpp_fxloader.usermap in
+/etc/hotplug/usb and place xpp/utils/*.hex in /usr/share/zaptel .
Alternatively, xpp_fxloader when given the parameter 'xppdetect' will load
-the firmware from /etc/xortel/FPGA_XPD.hex . You can use it to load the
+the firmwares from /usr/share/zaptel/ . You can use it to load the
firmware manually.
You should then get in lsusb the vendor ID e4e4 and device ID 2121
@@ -128,6 +175,25 @@ file.
(There are a bunch of other status files under /proc/xpp/ )
+Useful Module Parameters:
+""""""""""""""""""""""""
+zap_autoreg: (xpp)
+Register spans automatically (1) or not (0). Default: 1.
+Unsetting this could be useful if you have several Astribanks and you
+want to set their registration order manually using zt_registration in
+the /proc interface.
+
+initialize_registers (xpd_fxs)
+The script that is run to initilize registers of the device. The default is
+/usr/share/zaptel/initialize_registers .
+Setting this value could be useful if that location is inconvient for you.
+
+print_dbg: (all modules)
+It will make the driver print tons of debugging messages. Can be sometime
+even handy, but overly-verbose in the case of xpp_usb. Can be safely
+set/unset at run-time using /sys/modules .
+
+
BTW: XPP here does not stand for X Printing Panel, XML Pull Parser,
X-Windows Phase Plane or XML Professional Publisher. It is simply the
diff --git a/xpp/card_fxo.c b/xpp/card_fxo.c
new file mode 100644
index 0000000..d383e5d
--- /dev/null
+++ b/xpp/card_fxo.c
@@ -0,0 +1,946 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <version.h> /* For zaptel version */
+#include "xpd.h"
+#include "xproto.h"
+#include "xpp_zap.h"
+#include "card_fxo.h"
+#include "zap_debug.h"
+
+static const char rcsid[] = "$Id$";
+
+DEF_PARM(int, print_dbg, 0, "Print DBG statements"); /* must be before zap_debug.h */
+DEF_PARM(uint, poll_battery_interval, 100, "Poll battery interval in milliseconds");
+DEF_PARM(bool, report_battery, 0, "Report battery status to zaptel");
+
+/* 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
+
+/*---------------- FXO Protocol Commands ----------------------------------*/
+
+static /* 0x0F */ DECLARE_CMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on);
+static /* 0x0F */ DECLARE_CMD(FXO, CHAN_CID, int pos);
+static /* 0x0F */ DECLARE_CMD(FXO, RING, int pos, bool on);
+static /* 0x0F */ DECLARE_CMD(FXO, SETHOOK, int pos, bool offhook);
+static /* 0x0F */ DECLARE_CMD(FXO, RELAY_OUT, byte which, bool on);
+static /* 0x0F */ DECLARE_CMD(FXO, DAA_QUERY, int pos, byte reg_num);
+
+static bool fxo_packet_is_valid(xpacket_t *pack);
+static void fxo_packet_dump(xpacket_t *pack);
+static int proc_fxo_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data);
+static int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+static int process_slic_cmdline(xpd_t *xpd, char *cmdline);
+
+#define PROC_DAA_FNAME "slics"
+#define PROC_FXO_INFO_FNAME "fxo_info"
+
+struct FXO_priv_data {
+ struct proc_dir_entry *xpd_slic;
+ struct proc_dir_entry *fxo_info;
+ slic_reply_t requested_reply;
+ slic_reply_t last_reply;
+ xpp_line_t battery;
+ xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
+ int blinking[NUM_LEDS][CHANNELS_PERXPD];
+};
+
+/*---------------- FXO: Static functions ----------------------------------*/
+
+#define IS_BLINKING(priv,pos,color) ((priv)->blinking[color][pos] != 0)
+#define DO_BLINK(priv,pos,color,val) ((priv)->blinking[color][pos] = (val))
+
+/*
+ * LED control is done via DAA register 0x20
+ */
+static int do_led(xpd_t *xpd, lineno_t pos, byte which, bool on)
+{
+ int ret = 0;
+ xpacket_t *pack;
+ slic_cmd_t *sc;
+ int len;
+ struct FXO_priv_data *priv;
+ xpp_line_t lines;
+ xbus_t *xbus;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ which = which % NUM_LEDS;
+ if(IS_SET(xpd->digital_outputs, pos) || IS_SET(xpd->digital_inputs, pos))
+ goto out;
+ if(pos == ALL_LINES) {
+ lines = ~0;
+ priv->ledstate[which] = (on) ? ~0 : 0;
+ } else {
+ lines = BIT(pos);
+ if(on) {
+ BIT_SET(priv->ledstate[which], pos);
+ } else {
+ BIT_CLR(priv->ledstate[which], pos);
+ }
+ }
+ if(!lines) // Nothing to do
+ goto out;
+ DBG("%s/%s: LED: lines=0x%04X which=%d -- %s\n", xbus->busname, xpd->xpdname, lines, which, (on) ? "on" : "off");
+ XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
+ sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
+ len = slic_cmd_direct_write(sc, lines, 0x20, on);
+ // DBG("LED pack: line=%d %s\n", i, (on)?"on":"off");
+ pack->datalen = len;
+ packet_send(xbus, pack);
+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(IS_BLINKING(priv,i,color)) {
+ // led state is toggled
+ if((timer_count % LED_BLINK_PERIOD) == 0) {
+ DBG("%s/%s/%d: led_state=%s\n", xpd->xbus->busname, xpd->xpdname, i,
+ (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);
+ }
+ }
+ }
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+}
+
+static void do_sethook(xpd_t *xpd, int pos, bool offhook)
+{
+ unsigned long flags;
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xpd);
+ BUG_ON(xpd->direction == TO_PHONE); // We can SETHOOK state only on PSTN
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(!IS_SET(priv->battery, pos)) {
+ DBG("%s/%s/%d: WARNING: called while battery is off\n", xpd->xbus->busname, xpd->xpdname, pos);
+ }
+ spin_lock_irqsave(&xpd->lock, flags);
+ xpd->ringing[pos] = 0; // No more rings
+ CALL_XMETHOD(SETHOOK, xpd->xbus, xpd, pos, offhook);
+ if(offhook) {
+ BIT_SET(xpd->hookstate, pos);
+ } else {
+ BIT_CLR(xpd->hookstate, pos);
+ xpd->delay_until_dialtone[pos] = 0;
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if(offhook)
+ wake_up_interruptible(&xpd->txstateq[pos]);
+}
+
+/*---------------- FXO: Methods -------------------------------------------*/
+
+static xpd_t *FXO_card_new(xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, byte revision)
+{
+ xpd_t *xpd = NULL;
+ int channels = min(8, CHANNELS_PERXPD);
+
+ xpd = xpd_alloc(sizeof(struct FXO_priv_data), xbus, xpd_num, proto_table, channels, revision);
+ if(!xpd)
+ return NULL;
+ xpd->direction = TO_PSTN;
+ xpd->revision = revision;
+ return xpd;
+}
+
+static void clean_proc(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ DBG("%s/%s\n", xbus->busname, xpd->xpdname);
+#ifdef CONFIG_PROC_FS
+ if(priv->xpd_slic) {
+ DBG("Removing xpd DAA file %s/%s\n", xbus->busname, xpd->xpdname);
+ remove_proc_entry(PROC_DAA_FNAME, xpd->proc_xpd_dir);
+ }
+ if(priv->fxo_info) {
+ DBG("Removing xpd FXO_INFO file %s/%s\n", xbus->busname, xpd->xpdname);
+ remove_proc_entry(PROC_FXO_INFO_FNAME, xpd->proc_xpd_dir);
+ }
+#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
+ DBG("Creating FXO_INFO file for %s/%s\n", xbus->busname, xpd->xpdname);
+ 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) {
+ ERR("Failed to create proc '%s' for %s/%s\n", PROC_FXO_INFO_FNAME, xbus->busname, xpd->xpdname);
+ ret = -ENOENT;
+ goto err;
+ }
+ priv->fxo_info->owner = THIS_MODULE;
+ DBG("Creating DAAs file for %s/%s\n", xbus->busname, xpd->xpdname);
+ priv->xpd_slic = create_proc_entry(PROC_DAA_FNAME, 0644, xpd->proc_xpd_dir);
+ if(!priv->xpd_slic) {
+ ERR("Failed to create proc file for DAAs of %s/%s\n", xbus->busname, xpd->xpdname);
+ ret = -ENOENT;
+ goto err;
+ }
+ priv->xpd_slic->owner = THIS_MODULE;
+ priv->xpd_slic->write_proc = proc_xpd_slic_write;
+ priv->xpd_slic->read_proc = proc_xpd_slic_read;
+ priv->xpd_slic->data = xpd;
+#endif
+ ret = run_initialize_registers(xpd);
+ if(ret < 0)
+ goto err;
+ // Hanghup all lines
+ for_each_line(xpd, i) {
+ init_waitqueue_head(&xpd->txstateq[i]);
+ do_sethook(xpd, i, 0);
+ }
+ DBG("done: %s/%s\n", xbus->busname, xpd->xpdname);
+ return 0;
+err:
+ clean_proc(xbus, xpd);
+ ERR("%s/%s: Failed initializing registers (%d)\n", xbus->busname, xpd->xpdname, 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;
+ DBG("%s/%s\n", xbus->busname, xpd->xpdname);
+ 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;
+ unsigned long flags;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on);
+ snprintf(xpd->span.desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: FXO", xbus->num, xpd->id);
+ for_each_line(xpd, i) {
+ struct zt_chan *cur_chan = &xpd->chans[i];
+
+ DBG("setting FXO channel %d\n", i);
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXO/%d/%d/%d", xbus->num, xpd->id, i);
+ cur_chan->chanpos = i + 1;
+ cur_chan->pvt = xpd;
+ cur_chan->sigcap = FXO_DEFAULT_SIGCAP;
+ }
+ spin_lock_irqsave(&xpd->lock, flags);
+ do_led(xpd, ALL_LINES, LED_GREEN, LED_OFF);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, LED_ON);
+ mdelay(50);
+ }
+ 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);
+ DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on);
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, LED_OFF);
+ mdelay(50);
+ }
+ return 0;
+}
+
+#ifdef WITH_RBS
+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);
+ DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, pos, 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:
+ NOTICE("Can't set tx state to %s (%d)\n", txsig2str(txsig), txsig);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+#else
+int FXO_card_sethook(xbus_t *xbus, xpd_t *xpd, int pos, int hookstate)
+{
+ int ret = 0;
+ struct FXO_priv_data *priv;
+
+ DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, pos, hookstate2str(hookstate));
+ switch(hookstate) {
+ /* On-hook, off-hook: The PBX is playing a phone on an FXO line. */
+ case ZT_ONHOOK:
+ do_sethook(xpd, pos, 0);
+ break;
+ case ZT_START:
+ DBG("%s/%s/%d: fall through ZT_OFFHOOK\n", xbus->busname, xpd->xpdname, pos);
+ xpd->delay_until_dialtone[pos] = DELAY_UNTIL_DIALTONE;
+ // Fall through
+ case ZT_OFFHOOK:
+ do_sethook(xpd, pos, 1);
+ wait_event_interruptible(xpd->txstateq[pos], xpd->delay_until_dialtone[pos] <= 0);
+ break;
+ case ZT_WINK:
+ WARN("No code yet\n");
+ break;
+ case ZT_FLASH:
+ WARN("No code yet\n");
+ break;
+ case ZT_RING:
+ DBG("%s/%s/%d: ZT_RING: %d\n", xbus->busname, xpd->xpdname, pos, xpd->ringing[pos]);
+ break;
+ case ZT_RINGOFF:
+ WARN("No code yet\n");
+ break;
+ }
+ return ret;
+}
+#endif
+
+static void poll_battery(xbus_t *xbus, xpd_t *xpd)
+{
+ int i;
+
+ for_each_line(xpd, i) {
+ CALL_PROTO(FXO, DAA_QUERY, xbus, xpd, i, DAA_VBAT_REGISTER);
+ }
+}
+
+
+static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
+{
+ static unsigned rate_limit = 0;
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ rate_limit++;
+ if(poll_battery_interval != 0 && (rate_limit % poll_battery_interval) == 0) {
+ poll_battery(xbus, xpd);
+ }
+ handle_fxo_leds(xpd);
+ return 0;
+}
+
+/* FIXME: based on data from from wctdm.h */
+#include <wctdm.h>
+static const int echotune_reg[] = {30,45,46,47,58,49,50,51,52};
+union echotune {
+ /* "coeff 0" is acim */
+ unsigned char coeff[sizeof(echotune_reg)];
+ struct wctdm_echo_coefs wctdm_struct;
+};
+
+static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
+{
+ union echotune echoregs;
+ int i,ret;
+
+ BUG_ON(!xpd);
+ DBG("cmd: 0x%x, expecting: 0x%x, pos=%d.\n", cmd, WCTDM_SET_ECHOTUNE, pos);
+ switch (cmd) {
+ case WCTDM_SET_ECHOTUNE:
+ DBG("-- Setting echo registers: \n");
+ /* first off: check if this span is fxs. If not: -EINVALID */
+ if (copy_from_user(&echoregs.wctdm_struct,
+ (struct wctdm_echo_coefs*)arg, sizeof(echoregs.wctdm_struct)))
+ return -EFAULT;
+
+ /* Set the ACIM register */
+ /* quick and dirty registers writing: */
+ for (i=0; i<sizeof(echotune_reg); i++) {
+ char buf[22];
+ xpp_line_t lines = BIT(pos);
+ sprintf(buf, "%02X %02X %02X %02X WD %2X %2X",
+ (lines & 0xFF),
+ ((lines >> 8) & 0xFF),
+ ((lines >> 16) & 0xFF),
+ ((lines >> 24) & 0xFF),
+ echotune_reg[i],echoregs.coeff[i]
+ );
+ /* FIXME: code duplicated from proc_xpd_register_write */
+ ret = process_slic_cmdline(xpd, buf);
+ if(ret < 0)
+ return ret;
+ mdelay(1);
+ }
+
+ DBG("-- Set echo registers successfully\n");
+
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+/*---------------- FXO: HOST COMMANDS -------------------------------------*/
+
+static /* 0x0F */ HOSTCMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on)
+{
+ unsigned long flags;
+ int ret = 0;
+ int i;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ if(!lines) {
+ return 0;
+ }
+ DBG("Channel Activation: 0x%4X %s\n", lines, (on) ? "on" : "off");
+ if(on) {
+ for_each_line(xpd, i) {
+ spin_lock_irqsave(&xpd->lock, flags);
+ do_led(xpd, i, LED_GREEN, LED_ON);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ mdelay(20);
+ }
+ for_each_line(xpd, i) {
+ spin_lock_irqsave(&xpd->lock, flags);
+ do_led(xpd, i, LED_GREEN, LED_OFF);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ mdelay(20);
+ }
+ }
+ return ret;
+}
+
+static /* 0x0F */ HOSTCMD(FXO, CHAN_CID, int pos)
+{
+ int ret = 0;
+ xpp_line_t lines = BIT(pos);
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ if(!lines) {
+ return 0;
+ }
+ DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, pos);
+ return ret;
+}
+
+
+static /* 0x0F */ HOSTCMD(FXO, RING, int pos, bool on)
+{
+ int ret = 0;
+ xpacket_t *pack;
+ slic_cmd_t *sc;
+ xpp_line_t mask = BIT(pos);
+ int len;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ if(!mask) {
+ return 0;
+ }
+ DBG("%s/%s/%d %s\n", xpd->xbus->busname, xpd->xpdname, pos, (on) ? "on" : "off");
+ XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
+ sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
+ len = slic_cmd_direct_write(sc, mask, 0x40, (on)?0x04:0x01);
+ pack->datalen = len;
+
+ packet_send(xbus, pack);
+ return ret;
+}
+
+static /* 0x0F */ HOSTCMD(FXO, SETHOOK, int pos, bool offhook)
+{
+ int ret = 0;
+ xpacket_t *pack;
+ slic_cmd_t *sc;
+ int len;
+ unsigned long flags;
+ bool value;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ value = (offhook) ? 0x09 : 0x08;
+ // value |= BIT(3); /* Bit 3 is for CID */
+ DBG("%s/%s/%d: SETHOOK: value=0x%02X %s\n", xbus->busname, xpd->xpdname, pos, value, (offhook)?"OFFHOOK":"ONHOOK");
+ spin_lock_irqsave(&xpd->lock, flags);
+ XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
+ sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
+ len = slic_cmd_direct_write(sc, BIT(pos), 0x05, value);
+ pack->datalen = len;
+ packet_send(xbus, pack);
+ do_led(xpd, pos, LED_GREEN, (offhook)?LED_ON:LED_OFF);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return ret;
+}
+
+static /* 0x0F */ HOSTCMD(FXO, RELAY_OUT, byte which, bool on)
+{
+ return -ENOSYS;
+}
+
+static /* 0x0F */ HOSTCMD(FXO, DAA_QUERY, int pos, byte reg_num)
+{
+ int ret = 0;
+ xpacket_t *pack;
+ slic_cmd_t *sc;
+ int len;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ // DBG("\n");
+ XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
+ sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
+ len = slic_cmd_direct_read(sc, BIT(pos), reg_num);
+
+ pack->datalen = len;
+
+ packet_send(xbus, pack);
+ return ret;
+}
+
+/*---------------- FXO: Astribank Reply Handlers --------------------------*/
+
+HANDLER_DEF(FXO, SIG_CHANGED)
+{
+ xpp_line_t sig_status = RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_status);
+ xpp_line_t sig_toggles = RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_toggles);
+ unsigned long flags;
+ int i;
+
+ if(!xpd) {
+ NOTICE("%s: received %s for non-existing xpd: %d\n",
+ __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
+ return -EPROTO;
+ }
+ DBG("%s/%s: (PSTN) sig_toggles=0x%04X sig_status=0x%04X\n", xpd->xbus->busname, xpd->xpdname, sig_toggles, sig_status);
+ spin_lock_irqsave(&xpd->lock, flags);
+ for_each_line(xpd, i) {
+ if(IS_SET(sig_status, i)) {
+ xpd->ringing[i] = 1;
+ } else {
+ xpd->ringing[i] = 0;
+ }
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return 0;
+}
+
+HANDLER_DEF(FXO, DAA_REPLY)
+{
+ slic_reply_t *info = &RPACKET_FIELD(pack, FXO, DAA_REPLY, info);
+ xpp_line_t lines = RPACKET_FIELD(pack, FXO, DAA_REPLY, lines);
+ unsigned long flags;
+ struct FXO_priv_data *priv;
+
+ if(!xpd) {
+ NOTICE("%s: received %s for non-existing xpd: %d\n",
+ __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
+ return -EPROTO;
+ }
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ if(!info->indirect && info->reg_num == DAA_VBAT_REGISTER) {
+ xpp_line_t last_batt_on = priv->battery;
+ xpp_line_t changed_lines;
+ int i;
+
+ if(abs(info->data_low) < BAT_THRESHOLD) {
+ priv->battery &= ~lines;
+ // DBG("%s/%s: BATTERY OFF (%04X) = %d\n", xpd->xbus->busname, xpd->xpdname, lines, info->data_low);
+ } else {
+ priv->battery |= lines;
+ // DBG("%s/%s: BATTERY ON (%04X) = %d\n", xpd->xbus->busname, xpd->xpdname, lines, info->data_low);
+ }
+ changed_lines = last_batt_on ^ priv->battery;
+ for_each_line(xpd, i) {
+ if(IS_SET(changed_lines, i)) {
+ update_line_status(xpd, i, IS_SET(priv->battery, i));
+ }
+ }
+ }
+#if 0
+ DBG("DAA_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
+ xpd->id, (info->indirect)?"I":"D",
+ info->reg_num, info->data_low, info->data_high);
+#endif
+
+ /* Update /proc info only if reply relate to the last slic read request */
+ if(priv->requested_reply.indirect == info->indirect &&
+ priv->requested_reply.reg_num == info->reg_num) {
+ priv->last_reply = *info;
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return 0;
+}
+
+
+xproto_table_t PROTO_TABLE(FXO) = {
+ .owner = THIS_MODULE,
+ .entries = {
+ /* Card Opcode */
+ XENTRY( FXO, SIG_CHANGED ),
+ XENTRY( FXO, DAA_REPLY ),
+ },
+ .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,
+#ifdef WITH_RBS
+ .card_hooksig = FXO_card_hooksig,
+#else
+ .card_sethook = FXO_card_sethook,
+#endif
+ .card_tick = FXO_card_tick,
+ .card_ioctl = FXO_card_ioctl,
+
+ .RING = XPROTO_CALLER(FXO, RING),
+ .SETHOOK = XPROTO_CALLER(FXO, SETHOOK),
+ .RELAY_OUT = XPROTO_CALLER(FXO, RELAY_OUT),
+ .CHAN_ENABLE = XPROTO_CALLER(FXO, CHAN_ENABLE),
+ .CHAN_CID = XPROTO_CALLER(FXO, CHAN_CID),
+
+ .SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
+ .PCM_WRITE = XPROTO_CALLER(GLOBAL, PCM_WRITE),
+ },
+ .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("\n");
+ xe = xproto_card_entry(&PROTO_TABLE(FXO), pack->content.opcode);
+ return xe != NULL;
+}
+
+static void fxo_packet_dump(xpacket_t *pack)
+{
+ DBG("\n");
+}
+
+/*------------------------- 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, "%d ", 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, "%d ", 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, "%d ", IS_BLINKING(priv,i,LED_GREEN));
+ }
+ len += sprintf(page + len, "\n\t%-17s: ", "battery");
+ for_each_line(xpd, i) {
+ len += sprintf(page + len, "%d ", IS_SET(priv->battery, i));
+ }
+ len += sprintf(page + len, "\n");
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if (len <= off+count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+}
+
+
+static int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xpd_t *xpd = data;
+ slic_reply_t *info;
+ struct FXO_priv_data *priv;
+
+ BUG_ON(!xpd);
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ 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, "DAA_REPLY: %s reg_num=0x%X, dataH=0x%X dataL=0x%X\n",
+ (info->indirect)?"I":"D",
+ info->reg_num, info->data_high, 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;
+}
+
+/*
+ * Direct/Indirect
+ * v
+ * FF FF FF FF WD 06 1
+ * ^---------^ ^ Reg
+ * | Write/Read
+ * |
+ * DAA #
+ */
+static int parse_slic_cmd(const char *buf, slic_cmd_t *sc, slic_reply_t *requested_reply)
+{
+ char op; /* [W]rite, [R]ead */
+ char reg_type; /* [D]irect, [I]ndirect */
+ int s1, s2, s3, s4;
+ int reg_num;
+ int data_low, data_high;
+ xpp_line_t lines;
+ int ret;
+
+ ret = sscanf(buf, "%x %x %x %x %c%c %x %x %x",
+ &s1, &s2, &s3, &s4, &op, &reg_type, &reg_num, &data_high, &data_low);
+ lines = (s4 << 24) | (s3 << 16) | (s2 << 8) | (s1);
+ switch(op) {
+ case 'R':
+ if(reg_type == 'D' && ret == 7) {
+ // DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num);
+ ret = slic_cmd_direct_read(sc, lines, reg_num);
+ if(requested_reply) {
+ requested_reply->indirect = 0;
+ requested_reply->reg_num = reg_num;
+ }
+ } else if(reg_type == 'I' && ret == 7) {
+ // DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num);
+ ret = slic_cmd_indirect_read(sc, lines, reg_num);
+ if(requested_reply) {
+ requested_reply->indirect = 1;
+ requested_reply->reg_num = reg_num;
+ }
+ } else {
+ NOTICE("%s: Bad read input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
+ goto err;
+ }
+ break;
+ case 'W':
+ if(reg_type == 'D' && ret == 8) {
+ // DBG("0x%X 0x%X 0x%X 0x%X %c %x %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high);
+ ret = slic_cmd_direct_write(sc, lines, reg_num, data_high);
+ } else if(reg_type == 'I' && ret == 9) {
+ // DBG("0x%X 0x%X 0x%X 0x%X %c %x %X %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high, data_low);
+ ret = slic_cmd_indirect_write(sc, lines, reg_num, data_low, data_high);
+ } else {
+ NOTICE("%s: Bad write input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
+ goto err;
+ }
+ break;
+ default:
+ NOTICE("%s: Bad input: ret=%d buf='%s' op=%c\n", __FUNCTION__, ret, buf, op);
+ goto err;
+ }
+ return ret;
+err:
+ return -EINVAL;
+}
+
+static int process_slic_cmdline(xpd_t *xpd, char *cmdline)
+{
+ xbus_t *xbus;
+ struct FXO_priv_data *priv;
+ slic_cmd_t sc;
+ xpacket_t *pack;
+ char *p;
+ int len = strlen(cmdline);
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->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;
+ len = parse_slic_cmd(p, &sc, &priv->requested_reply);
+ if(len < 0)
+ return len;
+ if(!sc.lines) {
+ NOTICE("%s: no channels are marked. Skip.\n", __FUNCTION__);
+ return 0;
+ }
+ dump_slic_cmd("WRITE_DAA", &sc);
+ XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
+ RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd) = sc;
+ pack->datalen = len;
+ packet_send(xbus, pack);
+ return 0;
+}
+
+static int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ xpd_t *xpd = data;
+ const int LINE_LEN = 500;
+ char buf[LINE_LEN];
+ char *p;
+ int i;
+ int ret;
+
+ if(!xpd)
+ return -ENODEV;
+ for(i = 0; i < count; /* noop */) {
+ for(p = buf; p < buf + LINE_LEN; 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 + LINE_LEN)
+ return -E2BIG;
+ *p = '\0';
+ ret = process_slic_cmdline(xpd, buf);
+ if(ret < 0)
+ return ret;
+ mdelay(1);
+ }
+ return count;
+}
+
+
+int __init card_fxo_startup(void)
+{
+ INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION);
+ 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 <oron@actcom.co.il>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ZAPTEL_VERSION);
+MODULE_ALIAS_XPD(XPD_TYPE_FXO);
+
+module_init(card_fxo_startup);
+module_exit(card_fxo_cleanup);
diff --git a/xpp/card_fxo.h b/xpp/card_fxo.h
new file mode 100644
index 0000000..762f47b
--- /dev/null
+++ b/xpp/card_fxo.h
@@ -0,0 +1,61 @@
+#ifndef CARD_FXO_H
+#define CARD_FXO_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "xpd.h"
+#include "slic.h"
+
+enum fxo_opcodes {
+ XPROTO_NAME(FXO, SIG_CHANGED) = 0x06,
+/**/
+ XPROTO_NAME(FXO, DAA_WRITE) = 0x0F, /* Write to DAA */
+ XPROTO_NAME(FXO, CHAN_ENABLE) = 0x0F, /* Write to DAA */
+ XPROTO_NAME(FXO, CHAN_CID) = 0x0F, /* Write to DAA */
+ XPROTO_NAME(FXO, RING) = 0x0F, /* Write to DAA */
+ XPROTO_NAME(FXO, SETHOOK) = 0x0F, /* Write to DAA */
+ XPROTO_NAME(FXO, LED) = 0x0F, /* Write to DAA */
+ XPROTO_NAME(FXO, RELAY_OUT) = 0x0F, /* Write to DAA */
+ XPROTO_NAME(FXO, DAA_INIT) = 0x0F, /* Write to DAA */
+ XPROTO_NAME(FXO, DAA_QUERY) = 0x0F, /* Write to DAA */
+/**/
+ XPROTO_NAME(FXO, DAA_REPLY) = 0x10,
+};
+
+
+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 */
+ );
+DEF_RPACKET_DATA(FXO, DAA_REPLY, /* Get status of a single DAA (for debugging) */
+ xpp_line_t lines;
+ slic_reply_t info;
+ );
+DEF_RPACKET_DATA(FXO, DAA_WRITE,
+ slic_cmd_t slic_cmd;
+ );
+
+#define DAA_VBAT_REGISTER 29
+#define BAT_THRESHOLD 3
+
+#endif /* CARD_FXO_H */
diff --git a/xpp/card_fxs.c b/xpp/card_fxs.c
index 37c0229..41b503e 100644
--- a/xpp/card_fxs.c
+++ b/xpp/card_fxs.c
@@ -1,6 +1,6 @@
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -23,65 +23,232 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/delay.h>
+#include <version.h> /* For zaptel version */
#include "xpd.h"
#include "xproto.h"
#include "xpp_zap.h"
-#include <linux/delay.h>
+#include "card_fxo.h"
+#include "zap_debug.h"
static const char rcsid[] = "$Id$";
-static const char revision[] = "$Revision$";
DEF_PARM(int, print_dbg, 0, "Print DBG statements"); /* must be before zap_debug.h */
+DEF_PARM(bool, poll_digital_inputs, 1, "Poll Digital Inputs"); /* must be before zap_debug.h */
+
+/* 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_REGULAR 8
#define LINES_DIGI_OUT 2
#define LINES_DIGI_INP 4
-#define MASK_BITS(b) ((1U << (b)) - 1)
+#define MASK_DIGI_OUT (BITMASK(LINES_DIGI_OUT) << LINES_REGULAR)
+#define MASK_DIGI_INP (BITMASK(LINES_DIGI_INP) << (LINES_REGULAR + LINES_DIGI_OUT))
+
+enum fxs_leds {
+ LED_GREEN,
+ LED_RED,
+ OUTPUT_RELAY,
+};
-#define MASK_DIGI_OUT (MASK_BITS(LINES_DIGI_OUT) << LINES_REGULAR)
-#define MASK_DIGI_INP (MASK_BITS(LINES_DIGI_INP) << (LINES_REGULAR + LINES_DIGI_OUT))
+#define NUM_LEDS 2
+
+static int SLIC_DIRECT_REQUEST(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, byte reg, byte dL)
+{
+ xpacket_t *pack;
+ slic_cmd_t *sc;
+ int len;
+
+ XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
+ sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
+ len = slic_cmd_direct_write(sc, lines, reg, dL);
+ pack->datalen = len;
+ packet_send(xbus, pack);
+ return 0;
+}
/*---------------- FXS Protocol Commands ----------------------------------*/
-/* 0x0F */ DECLARE_CMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on);
-/* 0x0F */ DECLARE_CMD(FXS, CHAN_POWER, xpp_line_t lines, bool on);
-/* 0x0F */ DECLARE_CMD(FXS, CHAN_CID, xpp_line_t lines);
-/* 0x0F */ DECLARE_CMD(FXS, RING, int pos, bool on);
-/* 0x0F */ DECLARE_CMD(FXS, SETHOOK, xpp_line_t hook_status);
-/* 0x0F */ DECLARE_CMD(FXS, LED, xpp_line_t lines, byte which, bool on);
-/* 0x0F */ DECLARE_CMD(FXS, RELAY_OUT, byte which, bool on);
-/* 0x0F */ DECLARE_CMD(FXS, SLIC_INIT);
-/* 0x0F */ DECLARE_CMD(FXS, SLIC_QUERY, int pos, byte reg_num);
+static /* 0x0F */ DECLARE_CMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on);
+static /* 0x0F */ DECLARE_CMD(FXS, CHAN_CID, int pos);
+static /* 0x0F */ DECLARE_CMD(FXS, RING, int pos, bool on);
+static /* 0x0F */ DECLARE_CMD(FXS, SETHOOK, int pos, bool offhook);
+static /* 0x0F */ DECLARE_CMD(FXS, RELAY_OUT, byte which, bool on);
+static /* 0x0F */ DECLARE_CMD(FXS, SLIC_QUERY, int pos, byte reg_num);
static bool fxs_packet_is_valid(xpacket_t *pack);
static void fxs_packet_dump(xpacket_t *pack);
+static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
static int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data);
static int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
-#define S_(s,l,...) \
- { \
- .lines = s, \
- { \
- .len = l, \
- .data = { __VA_ARGS__ }, \
- } \
- }
-struct slic_init_data {
- xpp_line_t lines;
- slic_data_t slic_data;
-} slic_init_data[] = {
-#include "slic_init.inc"
-};
-#undef S_
-
#define PROC_SLIC_FNAME "slics"
+#define PROC_FXS_INFO_FNAME "fxs_info"
struct FXS_priv_data {
- struct proc_dir_entry *xpd_slic;
- slic_reply_t last_reply;
+ struct proc_dir_entry *xpd_slic;
+ struct proc_dir_entry *fxs_info;
+ slic_reply_t requested_reply;
+ slic_reply_t last_reply;
+ xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
+ xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */
+ int blinking[NUM_LEDS][CHANNELS_PERXPD];
};
+/*---------------- FXS: Static functions ----------------------------------*/
+static int do_chan_power(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, bool on)
+{
+ int ret = 0;
+ xpacket_t *pack;
+ slic_cmd_t *sc;
+ int len;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ if(!lines) {
+ return 0;
+ }
+ DBG("%s/%s: 0x%04X %s\n", xbus->busname, xpd->xpdname, lines, (on) ? "up" : "down");
+ XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
+ sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
+ if(on) {
+ // Power up
+ len = slic_cmd_direct_write(sc, lines, 0x42, 0x06);
+ } else {
+ // Power down
+ len = slic_cmd_direct_write(sc, lines, 0x42, 0x00);
+ }
+ pack->datalen = len;
+
+ packet_send(xbus, pack);
+ return ret;
+}
+
+#define IS_BLINKING(priv,pos,color) ((priv)->blinking[color][pos] != 0)
+#define MARK_BLINK(priv,pos,color,val) ((priv)->blinking[color][pos] = (val))
+#define MARK_LED(priv,pos,color,val) ((val)?BIT_SET((priv)->ledcontrol[color],(pos)):BIT_CLR((priv)->ledcontrol[color],(pos)))
+
+/*
+ * 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
+ */
+static int do_led(xpd_t *xpd, lineno_t pos, byte which, bool on)
+{
+ int ret = 0;
+ xpacket_t *pack;
+ slic_cmd_t *sc;
+ int len;
+ int value;
+ struct FXS_priv_data *priv;
+ xpp_line_t lines;
+ xbus_t *xbus;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ which = which % NUM_LEDS;
+ if(IS_SET(xpd->digital_outputs, pos) || IS_SET(xpd->digital_inputs, pos))
+ goto out;
+ if(pos == ALL_LINES) {
+ lines = ~0;
+ priv->ledstate[which] = (on) ? ~0 : 0;
+ } else {
+ lines = BIT(pos);
+ if(on) {
+ BIT_SET(priv->ledstate[which], pos);
+ } else {
+ BIT_CLR(priv->ledstate[which], pos);
+ }
+ }
+ if(!lines) // Nothing to do
+ goto out;
+ DBG("%s/%s: LED: lines=0x%04X which=%d -- %s\n", xbus->busname, xpd->xpdname, lines, 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];
+ XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
+ sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
+ len = slic_cmd_direct_write(sc, lines, 0x06, value);
+ pack->datalen = len;
+ packet_send(xbus, pack);
+
+out:
+ return ret;
+}
+
+static void handle_fxs_leds(xpd_t *xpd)
+{
+ int i;
+ unsigned long flags;
+ const enum fxs_leds colors[] = { LED_GREEN, LED_RED };
+ int color;
+ unsigned int timer_count;
+ struct FXS_priv_data *priv;
+
+ BUG_ON(!xpd);
+ spin_lock_irqsave(&xpd->lock, flags);
+ priv = xpd->priv;
+ timer_count = xpd->timer_count;
+ for(color = 0; color < ARRAY_SIZE(colors); color++) {
+ for_each_line(xpd, i) {
+ if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
+ continue;
+ if(IS_BLINKING(priv, i, color)) { // Blinking
+ // led state is toggled
+ if((timer_count % LED_BLINK_PERIOD) == 0) {
+ DBG("%s/%s/%d ledstate=%s\n", xpd->xbus->busname, xpd->xpdname, i,
+ (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);
+}
+
/*---------------- FXS: Methods -------------------------------------------*/
static xpd_t *FXS_card_new(xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, byte revision)
@@ -100,29 +267,82 @@ static xpd_t *FXS_card_new(xbus_t *xbus, int xpd_num, const xproto_table_t *prot
xpd->digital_inputs = MASK_DIGI_INP;
}
xpd->direction = TO_PHONE;
+ xpd->revision = revision;
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->xpd_slic) {
+ DBG("Removing xpd SLIC file %s/%s\n", xbus->busname, xpd->xpdname);
+ priv->xpd_slic->data = NULL;
+ remove_proc_entry(PROC_SLIC_FNAME, xpd->proc_xpd_dir);
+ }
+ if(priv->fxs_info) {
+ DBG("Removing xpd FXS_INFO file %s/%s\n", xbus->busname, xpd->xpdname);
+ remove_proc_entry(PROC_FXS_INFO_FNAME, xpd->proc_xpd_dir);
+ }
+#endif
+}
+
static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
{
struct FXS_priv_data *priv;
+ int ret = 0;
BUG_ON(!xpd);
priv = xpd->priv;
- CALL_PROTO(FXS, SLIC_INIT, xbus, xpd);
#ifdef CONFIG_PROC_FS
+ DBG("Creating FXS_INFO file for %s/%s\n", xbus->busname, xpd->xpdname);
+ 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) {
+ ERR("Failed to create proc '%s' for %s/%s\n", PROC_FXS_INFO_FNAME, xbus->busname, xpd->xpdname);
+ ret = -ENOENT;
+ goto err;
+ }
+ priv->fxs_info->owner = THIS_MODULE;
DBG("Creating SLICs file for %s/%s\n", xbus->busname, xpd->xpdname);
priv->xpd_slic = create_proc_entry(PROC_SLIC_FNAME, 0644, xpd->proc_xpd_dir);
if(!priv->xpd_slic) {
ERR("Failed to create proc file for SLICs of %s/%s\n", xbus->busname, xpd->xpdname);
- goto out;
+ ret = -ENOENT;
+ goto err;
}
+ priv->xpd_slic->owner = THIS_MODULE;
priv->xpd_slic->write_proc = proc_xpd_slic_write;
priv->xpd_slic->read_proc = proc_xpd_slic_read;
priv->xpd_slic->data = xpd;
-out:
#endif
+ ret = run_initialize_registers(xpd);
+ if(ret < 0)
+ goto err;
+ /*
+ * Setup ring timers
+ */
+#ifdef WITH_RBS
+ /* Software controled ringing (for CID) */
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x22, 0x00); /* Ringing Oscilator Control */
+#else
+ /* Hardware controled ringing (no CID) */
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x30, 0x80); /* Active timer low byte */
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x31, 0x3E); /* Active timer high byte */
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x32, 0x80); /* Inactive timer low byte */
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x33, 0x3E); /* Inactive timer high byte */
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x22, 0x18); /* Ringing Oscilator Control */
+#endif
+ if(ret < 0)
+ goto err;
+ DBG("%s/%s: done\n", xbus->busname, xpd->xpdname);
return 0;
+err:
+ clean_proc(xbus, xpd);
+ ERR("%s/%s: Failed initializing registers (%d)\n", xbus->busname, xpd->xpdname, ret);
+ return ret;
}
static int FXS_card_remove(xbus_t *xbus, xpd_t *xpd)
@@ -132,15 +352,210 @@ static int FXS_card_remove(xbus_t *xbus, xpd_t *xpd)
BUG_ON(!xpd);
priv = xpd->priv;
DBG("%s/%s\n", xbus->busname, xpd->xpdname);
-#ifdef CONFIG_PROC_FS
- if(priv->xpd_slic) {
- DBG("Removing xpd SLIC file %s/%s\n", xbus->busname, xpd->xpdname);
- remove_proc_entry(PROC_SLIC_FNAME, xpd->proc_xpd_dir);
+ 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;
+ unsigned long flags;
+ const enum fxs_leds color = (on) ? LED_GREEN : LED_RED;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on);
+ snprintf(xpd->span.desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: FXS", xbus->num, xpd->id);
+ for_each_line(xpd, i) {
+ struct zt_chan *cur_chan = &xpd->chans[i];
+
+ DBG("setting FXS channel %d\n", i);
+ if(IS_SET(xpd->digital_outputs, i)) {
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_OUT/%d/%d/%d", xbus->num, xpd->id, i);
+ } else if(IS_SET(xpd->digital_inputs, i)) {
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%d/%d/%d", xbus->num, xpd->id, i);
+ } else {
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXS/%d/%d/%d", xbus->num, xpd->id, i);
+ }
+ cur_chan->chanpos = i + 1;
+ cur_chan->pvt = xpd;
+ cur_chan->sigcap = FXS_DEFAULT_SIGCAP;
+ }
+ spin_lock_irqsave(&xpd->lock, flags);
+ do_led(xpd, ALL_LINES, color, LED_OFF);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ for_each_line(xpd, i) {
+ MARK_LED(priv, i, color, LED_ON);
+ mdelay(50);
+ }
+ return 0;
+}
+
+static int FXS_card_zaptel_postregistration(xpd_t *xpd, bool on)
+{
+ xbus_t *xbus;
+ struct FXS_priv_data *priv;
+ int i;
+ const enum fxs_leds color = (on) ? LED_GREEN : LED_RED;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on);
+ for_each_line(xpd, i) {
+ MARK_LED(priv, i, color, LED_OFF);
+ mdelay(50);
}
-#endif
return 0;
}
+#ifdef WITH_RBS
+int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
+{
+ int ret = 0;
+
+ DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, pos, txsig2str(txsig));
+ BUG_ON(xpd->direction != TO_PHONE);
+ if (IS_SET(xpd->digital_inputs, pos)) {
+ DBG("Ignoring signal sent to digital input line\n");
+ return 0;
+ }
+ switch(txsig) {
+ case ZT_TXSIG_ONHOOK:
+ xpd->ringing[pos] = 0;
+ BIT_CLR(xpd->cid_on, pos);
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ DBG("%s/%s/%d: digital output OFF\n", xbus->busname, xpd->xpdname, pos);
+ ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
+ return ret;
+ }
+ ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0); // RING off
+#if 0
+ switch(chan->sig) {
+ case ZT_SIG_EM:
+ case ZT_SIG_FXOKS:
+ case ZT_SIG_FXOLS:
+ xpd->lasttxhook[pos] = xpd->idletxhookstate[pos];
+ break;
+ case ZT_SIG_FXOGS:
+ xpd->lasttxhook[pos] = FXS_LINE_TIPOPEN;
+ break;
+ }
+#endif
+ break;
+ case ZT_TXSIG_OFFHOOK:
+ if(xpd->ringing[pos]) {
+ BIT_SET(xpd->cid_on, pos);
+ ret = CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, pos); // CALLER ID
+ }
+ xpd->ringing[pos] = 0;
+#if 0
+ switch(chan->sig) {
+ case ZT_SIG_EM:
+ xpd->lasttxhook[pos] = FXS_LINE_REV_ACTIVE;
+ break;
+ default:
+ xpd->lasttxhook[pos] = xpd->idletxhookstate[pos];
+ break;
+ }
+#endif
+ break;
+ case ZT_TXSIG_START:
+ xpd->lasttxhook[pos] = FXS_LINE_RING;
+ xpd->ringing[pos] = 1;
+ BIT_CLR(xpd->cid_on, pos);
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ DBG("%s/%s/%d: %s digital output ON\n", xbus->busname, xpd->xpdname, pos, 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:
+ xpd->lasttxhook[pos] = FXS_LINE_DISABLED;
+ break;
+ default:
+ NOTICE("%s: Can't set tx state to %s (%d)\n", __FUNCTION__, txsig2str(txsig), txsig);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+#else
+int FXS_card_sethook(xbus_t *xbus, xpd_t *xpd, int pos, int hookstate)
+{
+ int ret = 0;
+
+ DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, pos, hookstate2str(hookstate));
+ switch(hookstate) {
+ /* On-hook, off-hook: The PBX is playing a phone on an FXO line.
+ * Can be ignored for an FXS line
+ */
+ case ZT_ONHOOK:
+ if(IS_SET(xpd->digital_inputs, pos)) {
+ NOTICE("%s: Trying to ONHOOK a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
+ ret = -EINVAL;
+ break;
+ }
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ DBG("%s/%s/%d: digital output OFF\n", xbus->busname, xpd->xpdname, pos);
+ ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
+ break;
+ }
+ xpd->ringing[pos] = 0;
+ DBG("%s/%s/%d: stop ringing\n", xbus->busname, xpd->xpdname, pos);
+#if 1 // FIXME: Not needed -- verify
+ ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0); // RING off
+#endif
+ if(ret) {
+ DBG("ZT_ONHOOK(stop ring) Failed: ret=0x%02X\n", ret);
+ break;
+ }
+ break;
+ case ZT_START:
+ DBG("%s/%s/%d: fall through ZT_OFFHOOK\n", xbus->busname, xpd->xpdname, pos);
+ // Fall through
+ case ZT_OFFHOOK:
+ DBG("%s/%s/%d: ZT_OFFHOOK (ignoring for PHONES)\n", xbus->busname, xpd->xpdname, pos);
+ break;
+ case ZT_WINK:
+ WARN("No code yet\n");
+ break;
+ case ZT_FLASH:
+ WARN("No code yet\n");
+ break;
+ case ZT_RING:
+ DBG("%s/%s/%d: ZT_RING: %d\n", xbus->busname, xpd->xpdname, pos, xpd->ringing[pos]);
+ if(IS_SET(xpd->digital_inputs, pos)) {
+ NOTICE("%s: Trying to RING a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
+ return -EINVAL;
+ }
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ DBG("%s/%s/%d: digital output ON\n", xbus->busname, xpd->xpdname, pos);
+ ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
+ return ret;
+ }
+ xpd->ringing[pos] = 1;
+ ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1); // RING on
+ if(ret) {
+ DBG("ZT_RING Failed: ret=0x%02X\n", ret);
+ }
+ break;
+ case ZT_RINGOFF:
+ WARN("No code yet\n");
+ break;
+ }
+ return ret;
+}
+#endif
+
/*
* INPUT polling is done via SLIC register 0x06 (same as LEDS):
* 7 6 5 4 3 2 1 0
@@ -155,6 +570,7 @@ static void poll_inputs(xbus_t *xbus, xpd_t *xpd)
{
int i;
+ BUG_ON(xpd->id != 0); // Only unit #0 has digital inputs
for(i = 0; i < ARRAY_SIZE(input_channels); i++) {
int pos = input_channels[i];
@@ -164,177 +580,129 @@ static void poll_inputs(xbus_t *xbus, xpd_t *xpd)
static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
{
- static int rate_limit = 0;
+ static int rate_limit = 0;
+ struct FXS_priv_data *priv;
- if((rate_limit++ % 1000) == 0) {
- poll_inputs(xbus, xpd);
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+#if POLL_DIGITAL_INPUTS
+ if(poll_digital_inputs && xpd->id == 0) {
+ if((rate_limit++ % 1000) == 0) {
+ poll_inputs(xbus, xpd);
+ }
}
+#endif
+ handle_fxs_leds(xpd);
return 0;
}
/*---------------- FXS: HOST COMMANDS -------------------------------------*/
-/* 0x0F */ HOSTCMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on)
+static /* 0x0F */ HOSTCMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on)
{
int ret = 0;
xpacket_t *pack;
slic_cmd_t *sc;
int len;
+ enum fxs_state value = (on) ? 0x01 : 0x00;
+ unsigned long flags;
+ int i;
BUG_ON(!xbus);
BUG_ON(!xpd);
- lines &= xpd->enabled_chans; // Ignore disabled channels
if(!lines) {
return 0;
}
DBG("Channel Activation: 0x%4X %s\n", lines, (on) ? "on" : "off");
+ // Make sure we use normal (low battery) power
+ for_each_line(xpd, i)
+ if (BIT_SET(lines,i))
+ do_chan_power(xbus, xpd, BIT(i), 0);
XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
- len = slic_cmd_direct_write(sc, lines, 0x40, (on)?0x01:0x00);
+ len = slic_cmd_direct_write(sc, lines, 0x40, value);
pack->datalen = len;
+ for_each_line(xpd, i)
+ xpd->lasttxhook[i] = value;
packet_send(xbus, pack);
- return ret;
-}
-
-/* 0x0F */ HOSTCMD(FXS, CHAN_POWER, xpp_line_t lines, bool on)
-{
- int ret = 0;
- xpacket_t *pack;
- slic_cmd_t *sc;
- int len;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- lines &= xpd->enabled_chans; // Ignore disabled channels
- if(!lines) {
- return 0;
- }
- DBG("Channel Power: 0x%04X %s\n", lines, (on) ? "up" : "down");
- XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
- sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
+ spin_lock_irqsave(&xpd->lock, flags);
if(on) {
- // Power up
- len = slic_cmd_direct_write(sc, lines, 0x42, 0x06);
+ do_led(xpd, ALL_LINES, LED_GREEN, LED_ON);
} else {
- // Power down
- len = slic_cmd_direct_write(sc, lines, 0x42, 0x00);
+ do_led(xpd, ALL_LINES, LED_GREEN, LED_OFF);
}
- pack->datalen = len;
-
- packet_send(xbus, pack);
+ spin_unlock_irqrestore(&xpd->lock, flags);
return ret;
}
-/* 0x0F */ HOSTCMD(FXS, CHAN_CID, xpp_line_t lines)
+static /* 0x0F */ HOSTCMD(FXS, CHAN_CID, int pos)
{
int ret = 0;
xpacket_t *pack;
slic_cmd_t *sc;
+ int i;
+ xpp_line_t lines = BIT(pos);
BUG_ON(!xbus);
BUG_ON(!xpd);
- lines &= xpd->enabled_chans; // Ignore disabled channels
if(!lines) {
return 0;
}
- DBG("Channel CID: 0x%04X\n", lines);
+ DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, pos);
+ //do_chan_power(xbus, xpd, BIT(pos), 0); // Low battery for normal (non-ring) operation
XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
- pack->datalen = slic_cmd_direct_write(sc, lines, 0x40, 0x02);
+ pack->datalen = slic_cmd_direct_write(sc, lines, 0x40, FXS_LINE_CID);
packet_send(xbus, pack);
+ for_each_line(xpd, i)
+ xpd->lasttxhook[i] = FXS_LINE_CID;
return ret;
}
-/* 0x0F */ HOSTCMD(FXS, RING, int pos, bool on)
+static /* 0x0F */ HOSTCMD(FXS, RING, int pos, bool on)
{
int ret = 0;
+ struct FXS_priv_data *priv;
xpacket_t *pack;
slic_cmd_t *sc;
- xpp_line_t mask = (1 << pos);
+ xpp_line_t mask = BIT(pos);
int len;
+ enum fxs_state value = (on) ? 0x04 : 0x01;
BUG_ON(!xbus);
BUG_ON(!xpd);
- mask &= xpd->enabled_chans; // Ignore disabled channels
+ priv = xpd->priv;
if(!mask) {
return 0;
}
- DBG("%s pos=%d %s\n", xpd->xpdname, pos, (on) ? "on" : "off");
+ DBG("%s/%s/%d %s\n", xbus->busname, xpd->xpdname, pos, (on) ? "on" : "off");
+ do_chan_power(xbus, xpd, BIT(pos), on); // Power up (for ring)
XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
- len = slic_cmd_direct_write(sc, mask, 0x40, (on)?0x04:0x01);
+ len = slic_cmd_direct_write(sc, mask, 0x40, value);
+ xpd->lasttxhook[pos] = value;
pack->datalen = len;
packet_send(xbus, pack);
+ if(on) {
+ MARK_BLINK(priv,pos,LED_GREEN,LED_BLINK);
+ } else {
+ if(IS_BLINKING(priv, pos, LED_GREEN))
+ MARK_BLINK(priv,pos,LED_GREEN,0);
+ }
return ret;
}
-/* 0x0F */ HOSTCMD(FXS, SETHOOK, xpp_line_t hook_status)
+static /* 0x0F */ HOSTCMD(FXS, SETHOOK, int pos, bool offhook)
{
- DBG("\n");
+ BUG(); // Should never be called
return 0;
}
-/*
- * LED control is done via SLIC register 0x06:
- * 7 6 5 4 3 2 1 0
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- * | MR | MG | MB | R | OG | OB | G | B |
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- *
- * B - BLUE LED (0 - OFF, 1 - ON)
- * G - GREEN LED (0 - OFF, 1 - ON)
- * OB - Output BLUE (this line is output)
- * OG - Output GREEN (this line is output)
- * R - RED LED (0 - OFF, 1 - ON)
- * MB - Mask BLUE. (1 - B effect the BLUE LED)
- * MR - Mask RED. (1 - R effect the RED LED)
- * MG - Mask GREEN. (1 - G effect the GREEN LED)
- *
- * The BLUE LED (actually a relay out) is connected to line 0 and 4 only.
- */
-
-// GREEN RED BLUE
-static const int led_mask[NUM_LEDS] = { BIT(7), BIT(6), BIT(5) };
-static const int led_vals[NUM_LEDS] = { BIT(4), BIT(1), BIT(0) };
-
-/* 0x0F */ HOSTCMD(FXS, LED, xpp_line_t lines, byte which, bool on)
-{
- int ret = 0;
- xpacket_t *pack;
- slic_cmd_t *sc;
- int len;
- int value;
- int i;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- lines &= xpd->enabled_chans; // Ignore disabled channels
- if(!lines) {
- return 0;
- }
- DBG("LED: lines=0x%04X which=%d -- %s\n", lines, which, (on) ? "on" : "off");
- which = which % NUM_LEDS;
- value = BIT(2) | BIT(3);
- value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[which]);
- if(on)
- value |= led_vals[which];
- for(i = 0; i < CHANNELS_PERXPD; i++) {
- if(!IS_SET(lines, i))
- continue;
- XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
- sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
- len = slic_cmd_direct_write(sc, lines, 0x06, value);
- DBG("LED pack: line=%d value=0x%04X\n", i, value);
- pack->datalen = len;
- packet_send(xbus, pack);
- }
- return ret;
-}
-
-/* 0x0F */ HOSTCMD(FXS, RELAY_OUT, byte which, bool on)
+static /* 0x0F */ HOSTCMD(FXS, RELAY_OUT, byte which, bool on)
{
int ret = 0;
xpacket_t *pack;
@@ -351,9 +719,9 @@ static const int led_vals[NUM_LEDS] = { BIT(4), BIT(1), BIT(0) };
which = which % ARRAY_SIZE(relay_channels);
lines = BIT(relay_channels[which]);
value = BIT(2) | BIT(3);
- value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[LED_BLUE]);
+ value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[OUTPUT_RELAY]);
if(on)
- value |= led_vals[LED_BLUE];
+ value |= led_register_vals[OUTPUT_RELAY];
XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
len = slic_cmd_direct_write(sc, lines, 0x06, value);
@@ -364,34 +732,7 @@ static const int led_vals[NUM_LEDS] = { BIT(4), BIT(1), BIT(0) };
return ret;
}
-/* 0x0F */ HOSTCMD(FXS, SLIC_INIT)
-{
- int ret = 0;
- xpacket_t *pack;
- slic_data_t *slic;
- struct slic_init_data *source;
- int i;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- DBG("INITIALIZING SLIC\n");
- for(i = 0; i < ARRAY_SIZE(slic_init_data); i++) {
- source = &slic_init_data[i];
- XPACKET_NEW(pack, xbus, FXS, SLIC_INIT, xpd->id);
- RPACKET_FIELD(pack, FXS, SLIC_INIT, lines) = source->lines;
-
- slic = &RPACKET_FIELD(pack, FXS, SLIC_INIT, slic_data);
- slic->len = source->slic_data.len;
- memcpy(slic->data, source->slic_data.data, source->slic_data.len);
- pack->datalen = sizeof(xpp_line_t) + slic->len + 1;
-// dump_packet("SLIC", pack, print_dbg);
- packet_send(xbus, pack);
- mdelay(10); // FIXME: check with Dima
- }
- return ret;
-}
-
-/* 0x0F */ HOSTCMD(FXS, SLIC_QUERY, int pos, byte reg_num)
+static /* 0x0F */ HOSTCMD(FXS, SLIC_QUERY, int pos, byte reg_num)
{
int ret = 0;
xpacket_t *pack;
@@ -400,7 +741,7 @@ static const int led_vals[NUM_LEDS] = { BIT(4), BIT(1), BIT(0) };
BUG_ON(!xbus);
BUG_ON(!xpd);
- DBG("\n");
+ // DBG("\n");
XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
len = slic_cmd_direct_read(sc, BIT(pos), reg_num);
@@ -416,31 +757,45 @@ static const int led_vals[NUM_LEDS] = { BIT(4), BIT(1), BIT(0) };
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;
- if(!xpd) {
- NOTICE("%s: received %s for non-existing xpd: %d\n",
- __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
- return -EPROTO;
+ BUG_ON(!xpd);
+ BUG_ON(xpd->direction != TO_PHONE);
+ priv = xpd->priv;
+ DBG("%s/%s: (PHONE) sig_toggles=0x%04X sig_status=0x%04X\n", xbus->busname, xpd->xpdname, sig_toggles, sig_status);
+ if(!SPAN_REGISTERED(xpd)) {
+ NOTICE("%s: %s/%s is not registered. Skipping.\n", __FUNCTION__, xbus->busname, xpd->xpdname);
+ return -ENODEV;
}
- if(xpd->direction == TO_PHONE) { /* Hook state changes */
- DBG("%s (PHONE) sig_status=0x%04X\n", xpd->xpdname, sig_status);
- xpp_check_hookstate(xpd, sig_status);
- } else { /* TO_PSTN - line ring changes */
- unsigned long flags;
- int i;
-
- DBG("%s (PSTN) sig_status=0x%04X\n", xpd->xpdname, sig_status);
- spin_lock_irqsave(&xpd->lock, flags);
- for(i = 0; i < xpd->channels; i++) {
+#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
+ 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)) {
+ struct zt_chan *chan = &xpd->span.chans[i];
+
+ xpd->ringing[i] = 0; // No more ringing...
+ MARK_BLINK(priv,i,LED_GREEN,0);
if(IS_SET(sig_status, i)) {
- xpd->ringing[i] = RINGS_NUM*2;
- zt_hooksig(&xpd->chans[i], ZT_RXSIG_OFFHOOK);
+ DBG("OFFHOOK: channo=%d\n", chan->channo);
+ MARK_LED(priv,i,LED_GREEN,LED_ON);
+ BIT_SET(xpd->hookstate, i);
+ zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
} else {
- zt_hooksig(&xpd->chans[i], ZT_RXSIG_ONHOOK);
- xpd->ringing[i] = 0;
+ DBG("ONHOOK channo=%d\n", chan->channo);
+ MARK_LED(priv,i,LED_GREEN,LED_OFF);
+ BIT_CLR(xpd->hookstate, i);
+ zt_hooksig(chan, ZT_RXSIG_ONHOOK);
}
}
- spin_unlock_irqrestore(&xpd->lock, flags);
}
return 0;
}
@@ -460,52 +815,75 @@ HANDLER_DEF(FXS, SLIC_REPLY)
spin_lock_irqsave(&xpd->lock, flags);
priv = xpd->priv;
BUG_ON(!priv);
+#if 0
DBG("SLIC_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
xpd->id, (info->indirect)?"I":"D",
info->reg_num, info->data_low, info->data_high);
- priv->last_reply = *info;
+#endif
if(xpd->id == 0 && info->indirect == 0 && info->reg_num == 0x06) { /* Digital Inputs Poll Result */
int i;
bool offhook = (info->data_low & 0x1) == 0;
/* Map SLIC number into line number */
for(i = 0; i < ARRAY_SIZE(input_channels); i++) {
- int channo = input_channels[i];
- int newchanno;
+ int channo = input_channels[i];
+ int newchanno;
+ struct zt_chan *chan;
if(IS_SET(lines, channo)) {
newchanno = LINES_REGULAR + LINES_DIGI_OUT + i;
BIT_CLR(lines, channo);
BIT_SET(lines, newchanno);
- phone_hook(xpd, newchanno, offhook);
+ chan = &xpd->span.chans[newchanno];
+ xpd->ringing[newchanno] = 0; // Stop ringing. No leds for digital inputs.
+ if(offhook && !IS_SET(xpd->hookstate, newchanno)) { // OFFHOOK
+ DBG("OFFHOOK: channo=%d\n", chan->channo);
+ BIT_SET(xpd->hookstate, newchanno);
+ zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
+ } else if(!offhook && IS_SET(xpd->hookstate, newchanno)) { // ONHOOK
+ DBG("ONHOOK channo=%d\n", chan->channo);
+ BIT_CLR(xpd->hookstate, newchanno);
+ zt_hooksig(chan, ZT_RXSIG_ONHOOK);
+ }
}
}
}
+
+ /* Update /proc info only if reply relate to the last slic read request */
+ if(priv->requested_reply.indirect == info->indirect &&
+ priv->requested_reply.reg_num == info->reg_num) {
+ priv->last_reply = *info;
+ }
spin_unlock_irqrestore(&xpd->lock, flags);
return 0;
}
-
xproto_table_t PROTO_TABLE(FXS) = {
+ .owner = THIS_MODULE,
.entries = {
/* Card Opcode */
XENTRY( FXS, SIG_CHANGED ),
XENTRY( FXS, SLIC_REPLY ),
},
.name = "FXS",
- .type = XPD_TYPE(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,
+#ifdef WITH_RBS
+ .card_hooksig = FXS_card_hooksig,
+#else
+ .card_sethook = FXS_card_sethook,
+#endif
.card_tick = FXS_card_tick,
.RING = XPROTO_CALLER(FXS, RING),
.SETHOOK = XPROTO_CALLER(FXS, SETHOOK),
- .LED = XPROTO_CALLER(FXS, LED),
.RELAY_OUT = XPROTO_CALLER(FXS, RELAY_OUT),
.CHAN_ENABLE = XPROTO_CALLER(FXS, CHAN_ENABLE),
- .CHAN_POWER = XPROTO_CALLER(FXS, CHAN_POWER),
.CHAN_CID = XPROTO_CALLER(FXS, CHAN_CID),
.SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
@@ -519,7 +897,7 @@ static bool fxs_packet_is_valid(xpacket_t *pack)
{
const xproto_entry_t *xe;
- DBG("\n");
+ // DBG("\n");
xe = xproto_card_entry(&PROTO_TABLE(FXS), pack->content.opcode);
return xe != NULL;
}
@@ -531,6 +909,57 @@ static void fxs_packet_dump(xpacket_t *pack)
/*------------------------- 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, "\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, "%d ", i % 10);
+ }
+ 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: ", "blinking");
+ for_each_line(xpd, i) {
+ if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
+ len += sprintf(page + len, "%d ", IS_BLINKING(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;
+}
+
static int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0;
@@ -570,7 +999,7 @@ static int proc_xpd_slic_read(char *page, char **start, off_t off, int count, in
* |
* SLIC #
*/
-static int parse_slic_cmd(const char *buf, slic_cmd_t *sc)
+static int parse_slic_cmd(const char *buf, slic_cmd_t *sc, slic_reply_t *requested_reply)
{
char op; /* [W]rite, [R]ead */
char reg_type; /* [D]irect, [I]ndirect */
@@ -588,9 +1017,17 @@ static int parse_slic_cmd(const char *buf, slic_cmd_t *sc)
if(reg_type == 'D' && ret == 7) {
// DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num);
ret = slic_cmd_direct_read(sc, lines, reg_num);
+ if(requested_reply) {
+ requested_reply->indirect = 0;
+ requested_reply->reg_num = reg_num;
+ }
} else if(reg_type == 'I' && ret == 7) {
// DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num);
ret = slic_cmd_indirect_read(sc, lines, reg_num);
+ if(requested_reply) {
+ requested_reply->indirect = 1;
+ requested_reply->reg_num = reg_num;
+ }
} else {
NOTICE("%s: Bad read input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
goto err;
@@ -619,14 +1056,16 @@ err:
static int process_slic_cmdline(xpd_t *xpd, char *cmdline)
{
- xbus_t *xbus;
- slic_cmd_t sc;
- xpacket_t *pack;
- char *p;
- int len = strlen(cmdline);
+ xbus_t *xbus;
+ struct FXS_priv_data *priv;
+ slic_cmd_t sc;
+ xpacket_t *pack;
+ char *p;
+ int len = strlen(cmdline);
BUG_ON(!xpd);
xbus = xpd->xbus;
+ priv = xpd->priv;
if((p = strchr(cmdline, '#')) != NULL) /* Truncate comments */
*p = '\0';
if((p = strchr(cmdline, ';')) != NULL) /* Truncate comments */
@@ -635,12 +1074,11 @@ static int process_slic_cmdline(xpd_t *xpd, char *cmdline)
;
if(*p == '\0')
return 0;
- len = parse_slic_cmd(p, &sc);
+ len = parse_slic_cmd(p, &sc, &priv->requested_reply);
if(len < 0)
return len;
- sc.lines &= xpd->enabled_chans; // Ignore disabled channels
if(!sc.lines) {
- NOTICE("%s: no enabled channels are marked. Skip.\n", __FUNCTION__);
+ NOTICE("%s: no channels are marked. Skip.\n", __FUNCTION__);
return 0;
}
dump_slic_cmd("WRITE_SLIC", &sc);
@@ -660,7 +1098,8 @@ static int proc_xpd_slic_write(struct file *file, const char __user *buffer, uns
int i;
int ret;
- BUG_ON(!xpd);
+ if(!xpd)
+ return -ENODEV;
for(i = 0; i < count; /* noop */) {
for(p = buf; p < buf + LINE_LEN; p++) { /* read a line */
if(i >= count)
@@ -677,6 +1116,7 @@ static int proc_xpd_slic_write(struct file *file, const char __user *buffer, uns
ret = process_slic_cmdline(xpd, buf);
if(ret < 0)
return ret;
+ mdelay(1);
}
return count;
}
@@ -684,7 +1124,13 @@ static int proc_xpd_slic_write(struct file *file, const char __user *buffer, uns
int __init card_fxs_startup(void)
{
- INFO("%s revision %s\n", THIS_MODULE->name, revision);
+ INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION);
+#ifdef POLL_DIGITAL_INPUTS
+ INFO("FEATURE: %s with DIGITAL INPUTS support (%s activated)\n",
+ THIS_MODULE->name, (poll_digital_inputs) ? "is" : "is not");
+#else
+ INFO("FEATURE: %s without DIGITAL INPUTS support\n", THIS_MODULE->name);
+#endif
xproto_register(&PROTO_TABLE(FXS));
return 0;
}
@@ -697,7 +1143,8 @@ void __exit card_fxs_cleanup(void)
MODULE_DESCRIPTION("XPP FXS Card Driver");
MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
MODULE_LICENSE("GPL");
-MODULE_VERSION("$Id$");
+MODULE_VERSION(ZAPTEL_VERSION);
+MODULE_ALIAS_XPD(XPD_TYPE_FXS);
module_init(card_fxs_startup);
module_exit(card_fxs_cleanup);
diff --git a/xpp/card_fxs.h b/xpp/card_fxs.h
index 503b34e..1d81810 100644
--- a/xpp/card_fxs.h
+++ b/xpp/card_fxs.h
@@ -2,7 +2,7 @@
#define CARD_FXS_H
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -25,6 +25,24 @@
#include "xpd.h"
#include "slic.h"
+enum fxs_opcodes {
+ XPROTO_NAME(FXS, SIG_CHANGED) = 0x06,
+/**/
+ XPROTO_NAME(FXS, SLIC_WRITE) = 0x0F, /* Write to SLIC */
+ XPROTO_NAME(FXS, CHAN_ENABLE) = 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, SETHOOK) = 0x0F, /* Write to SLIC */
+ XPROTO_NAME(FXS, LED) = 0x0F, /* Write to SLIC */
+ XPROTO_NAME(FXS, RELAY_OUT) = 0x0F, /* Write to SLIC */
+ XPROTO_NAME(FXS, SLIC_INIT) = 0x0F, /* Write to SLIC */
+ XPROTO_NAME(FXS, SLIC_QUERY) = 0x0F, /* Write to SLIC */
+/**/
+ XPROTO_NAME(FXS, SLIC_REPLY) = 0x10,
+};
+
+
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 */
@@ -34,10 +52,6 @@ DEF_RPACKET_DATA(FXS, SLIC_REPLY, /* Get status of a single SLIC (for debugging)
xpp_line_t lines;
slic_reply_t info;
);
-DEF_RPACKET_DATA(FXS, SLIC_INIT,
- xpp_line_t lines;
- slic_data_t slic_data;
- );
DEF_RPACKET_DATA(FXS, SLIC_WRITE,
slic_cmd_t slic_cmd;
);
diff --git a/xpp/card_global.c b/xpp/card_global.c
index 8b73f6e..dda4480 100644
--- a/xpp/card_global.c
+++ b/xpp/card_global.c
@@ -1,6 +1,6 @@
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -24,6 +24,7 @@
#include "xpd.h"
#include "xpp_zap.h"
#include "xproto.h"
+#include "zap_debug.h"
#include <linux/module.h>
static const char rcsid[] = "$Id$";
@@ -61,13 +62,10 @@ static void global_packet_dump(xpacket_t *pack);
byte *pcm;
byte *start_pcm;
int i;
- extern ulong pcm_gen;
BUG_ON(!xbus);
BUG_ON(!xpd);
- lines &= xpd->enabled_chans;
- if(pcm_gen != 0)
- return 0;
+ lines &= ~xpd->no_pcm;
// if(lines == 0)
// return 0;
@@ -81,7 +79,7 @@ static void global_packet_dump(xpacket_t *pack);
XPACKET_NEW(pack, xbus, GLOBAL, PCM_WRITE, xpd->id);
RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
start_pcm = pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
- for(i = 0; i < CHANNELS_PERXPD; i++) {
+ for_each_line(xpd, i) {
if(IS_SET(lines, i)) {
memcpy(pcm, (byte *)buf, ZT_CHUNKSIZE);
pcm += ZT_CHUNKSIZE;
@@ -116,32 +114,44 @@ static void global_packet_dump(xpacket_t *pack);
/*---------------- GLOBAL: Astribank Reply Handlers -----------------------*/
+HANDLER_DEF(GLOBAL, NULL_REPLY)
+{
+ DBG("got len=%d\n", pack->datalen);
+ return 0;
+}
+
HANDLER_DEF(GLOBAL, DEV_DESC)
{
byte rev = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, rev);
byte type = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, type);
xpp_line_t line_status = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, line_status);
- int xpd_num = XPD_NUM(pack->content.addr);
+ xpd_addr_t xpd_addr = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, addr);
struct card_desc_struct *card_desc;
+ unsigned long flags;
- DBG("xpd=%d type=%d rev=%d line_status=0x%04X\n",
- xpd_num, type, rev, line_status);
+ BUG_ON(!xbus);
if((card_desc = kmalloc(sizeof(struct card_desc_struct), GFP_ATOMIC)) == NULL) {
ERR("%s: Card description allocation failed.\n", __FUNCTION__);
return -ENOMEM;
}
memset(card_desc, 0, sizeof(struct card_desc_struct));
card_desc->magic = CARD_DESC_MAGIC;
+ INIT_LIST_HEAD(&card_desc->card_list);
card_desc->xbus = xbus;
card_desc->type = type;
card_desc->rev = rev;
- card_desc->xpd_num = xpd_num;
- INIT_WORK(&card_desc->work, card_detected, card_desc);
- DBG("Queueing xpp_worker for xpd %d\n", xpd_num);
- if(!queue_work(xpp_worker, &card_desc->work)) {
- ERR("Failed to queue card description work\n");
- return -EINVAL;
- }
+ card_desc->xpd_addr = xpd_addr;
+ spin_lock_irqsave(&xbus->lock, flags);
+ DBG("xpd=%d-%d type=%d rev=%d line_status=0x%04X\n",
+ xpd_addr.unit, xpd_addr.subunit, type, rev, line_status);
+ if(type == XPD_TYPE_NOMODULE)
+ XBUS_COUNTER(xbus, DEV_DESC_EMPTY)++;
+ else
+ XBUS_COUNTER(xbus, DEV_DESC_FULL)++;
+ atomic_inc(&xbus->count_poll_answers);
+ wake_up(&xbus->wait_for_polls);
+ list_add_tail(&card_desc->card_list, &xbus->poll_results);
+ spin_unlock_irqrestore(&xbus->lock, flags);
return 0;
}
@@ -155,6 +165,7 @@ HANDLER_DEF(GLOBAL, PCM_READ)
unsigned long flags;
int i;
+ BUG_ON(!xbus);
if(!xpd) {
#if 0
int xpd_num = XPD_NUM(pack->content.addr);
@@ -177,7 +188,7 @@ HANDLER_DEF(GLOBAL, PCM_READ)
}
/* Copy PCM and put each channel in its index */
- for (i = 0; i < CHANNELS_PERXPD; i++) {
+ for_each_line(xpd, i) {
if(IS_SET(lines, i)) {
memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
//memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG
@@ -195,12 +206,19 @@ HANDLER_DEF(GLOBAL, PCM_READ)
HANDLER_DEF(GLOBAL, SYNC_REPLY)
{
+ byte mask = RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, mask);
+ bool setit = mask & 0x01;
+
+ BUG_ON(!xbus);
if(!xpd) {
int xpd_num = XPD_NUM(pack->content.addr);
NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
return -EPROTO;
}
- DBG("SYNC_REPLY: 0x%X\n", RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, mask));
+ DBG("%s/%s: SYNC_REPLY: 0x%X %s\n", xpd->xbus->busname, xpd->xpdname,
+ mask, (setit) ? "SET SYNC MASTER" : "");
+ if(setit)
+ sync_master_is(xpd);
return 0;
}
@@ -208,6 +226,7 @@ HANDLER_DEF(GLOBAL, SYNC_REPLY)
xproto_table_t PROTO_TABLE(GLOBAL) = {
.entries = {
/* Card Opcode */
+ XENTRY( GLOBAL, NULL_REPLY ),
XENTRY( GLOBAL, DEV_DESC ),
XENTRY( GLOBAL, PCM_READ ),
XENTRY( GLOBAL, SYNC_REPLY ),
@@ -239,7 +258,7 @@ static bool pcm_valid(xpd_t *xpd, xpacket_t *pack)
BUG_ON(!pack);
BUG_ON(pack->content.opcode != XPROTO_NAME(GLOBAL, PCM_READ));
- for (i = 0; i < CHANNELS_PERXPD; i++)
+ for_each_line(xpd, i)
if(IS_SET(lines, i))
count++;
if(pack->datalen != (sizeof(xpp_line_t) + count * 8)) {
diff --git a/xpp/card_global.h b/xpp/card_global.h
index 377487c..5ab8124 100644
--- a/xpp/card_global.h
+++ b/xpp/card_global.h
@@ -2,7 +2,7 @@
#define CARD_GLOBAL_H
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -24,6 +24,7 @@
#include "xdefs.h"
+DEF_RPACKET_DATA(GLOBAL, NULL_REPLY);
DEF_RPACKET_DATA(GLOBAL, DESC_REQ);
DEF_RPACKET_DATA(GLOBAL, DEV_DESC,
byte rev; /* Revision number */
@@ -31,11 +32,11 @@ DEF_RPACKET_DATA(GLOBAL, DEV_DESC,
xpp_line_t line_status; /* hook/ring status, depending on unit */
);
DEF_RPACKET_DATA(GLOBAL, PCM_WRITE,
- xpp_line_t lines; // Must be 0xFF
+ xpp_line_t lines;
byte pcm[PCM_CHUNKSIZE];
);
DEF_RPACKET_DATA(GLOBAL, PCM_READ,
- xpp_line_t lines; // Must be 0xFF
+ xpp_line_t lines;
byte pcm[PCM_CHUNKSIZE];
);
DEF_RPACKET_DATA(GLOBAL, SYNC_SOURCE,
diff --git a/xpp/cards.c b/xpp/cards.c
deleted file mode 100644
index dec0570..0000000
--- a/xpp/cards.c
+++ /dev/null
@@ -1,394 +0,0 @@
-#include <linux/module.h>
-#include "xpd.h"
-#include "xpp_zap.h"
-#include "xpp_proto.h"
-#include "cards.h"
-
-static char rcsid[] = "$Id$";
-
-extern int print_dbg;
-#include "zap_debug.h"
-
-#define MAX_SLIC_REGISTERS 100
-
-struct FXS_private_data {
- slic_reply_t last_slic_reply;
-};
-
-/*------------------------- FXS Functions --------------------------*/
-int FXS_card_new(xpd_t *xpd)
-{
- xpd->direction = TO_PHONE;
- xpd->channels = min(8, CHANNELS_PERXPD);
- if(xpd->id == 0) {
- DBG("First XPD detected. Initialize digital outputs\n");
- xpd->channels += 2;
- xpd->digital_outputs = BIT(8) | BIT(9); // Two extra channels
- }
- return 0;
-}
-
-int FXS_card_remove(xpd_t *xpd)
-{
- return 0;
-}
-
-static int FXS_card_startup(struct zt_span *span)
-{
- DBG("\n");
- return 0;
-}
-
-/*
- * Called only for 'span' keyword in /etc/zaptel.conf
- */
-static int FXS_card_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
-{
- xpd_t *xpd = span->pvt;
-
- DBG("%s\n", xpd->xpdname);
- return 0;
-}
-
-/* Set signalling type (if appropriate) */
-static int FXS_card_chanconfig(struct zt_chan *chan, int sigtype)
-{
- DBG("channel %d (%s), sigtype %d.\n", chan->channo, chan->name, sigtype);
- dump_sigtype(print_dbg, " ", 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 FXS_card_shutdown(struct zt_span *span)
-{
- xpd_t *xpd = span->pvt;
-
- DBG("%s\n", xpd->xpdname);
- return 0;
-}
-
-static int FXS_card_sethook(struct zt_chan *chan, int hookstate)
-{
- int pos = chan->chanpos - 1;
- xpd_t *xpd = chan->pvt;
- xbus_t *xbus;
- int ret = 0;
-
- if(!xpd) {
- ERR("%s: channel=%d without an XPD!\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- xbus = xpd->xbus;
- // DBG("%s (%d) (old=0x%04X, hook-command=%d)\n", chan->name, pos, xpd->hookstate, hookstate);
- switch(hookstate) {
- /* On-hook, off-hook: The PBX is playing a phone on an FXO line.
- * Can be ignored for an FXS line
- */
- case ZT_ONHOOK:
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_ONHOOK %s digital output OFF\n", chan->name);
- ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
- return ret;
- }
- DBG("ZT_ONHOOK: %s hookstate=0x%04X (stop ringing pos=%d)\n", chan->name, xpd->hookstate, pos);
- xpd->ringing[pos] = 0;
-#if 1 // FIXME: Not needed -- verify
- ret = CALL_PROTO(RING, xbus, xpd, pos, 0); // RING off
-#endif
- ret = CALL_PROTO(LED, xpd->xbus, xpd, BIT(pos), LED_GREEN, 0);
- ret = CALL_PROTO(CHAN_POWER, xbus, xpd, BIT(pos), 0); // Power down (prevent overheating!!!)
- if(ret) {
- DBG("ZT_ONHOOK(stop ring) Failed: ret=0x%02X\n", ret);
- break;
- }
- break;
- case ZT_START:
- DBG("ZT_START: %s hookstate=0x%04X (fall through ZT_OFFHOOK)\n", chan->name, xpd->hookstate);
- // Fall through
- case ZT_OFFHOOK:
- DBG("ZT_OFFHOOK: %s hookstate=0x%04X -- ignoring (FXS)\n", chan->name, xpd->hookstate);
- break;
- case ZT_WINK:
- DBG("ZT_WINK %s\n", chan->name);
- break;
- case ZT_FLASH:
- DBG("ZT_FLASH %s\n", chan->name);
- break;
- case ZT_RING:
- DBG("ZT_RING %s pos=%d (ringing[pos]=%d)\n", chan->name, pos, xpd->ringing[pos]);
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_ONHOOK %s digital output ON\n", chan->name);
- ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
- return ret;
- }
- xpd->ringing[pos] = RINGS_NUM*2;
- ret = CALL_PROTO(CHAN_POWER, xbus, xpd, (1 << pos), 1); // Power up (for ring)
- ret = CALL_PROTO(RING, xbus, xpd, pos, 1); // RING on
- if(ret) {
- DBG("ZT_RING Failed: ret=0x%02X\n", ret);
- }
- break;
- case ZT_RINGOFF:
- DBG("ZT_RINGOFF %s\n", chan->name);
- break;
- default:
- DBG("UNKNOWN hookstate=0x%X\n", hookstate);
- }
- return ret;
-}
-
-static int FXS_card_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- default:
- return xpp_ioctl(chan, cmd, arg);
- }
- return 0;
-}
-
-#if 0
-int FXS_zaptel_setup(xpd_t *xpd)
-{
- struct zt_chan *cur_chan;
- struct zt_span *span;
- xbus_t *xbus;
- int i;
- int cn;
-
- BUG_ON(!xpd);
-
- sigfxs = ! (xpd->direction == TO_PHONE); /* signaling is opposite */
- cn = xpd->channels;
- DBG("Initializing span: xpd %d have %d channels.\n", xpd->id, cn);
-
- xpd->chans = kmalloc(sizeof(struct zt_chan)*cn, GFP_ATOMIC);
- if (xpd->chans == NULL) {
- ERR("xpd: Unable to allocate channels\n");
- return -ENOMEM;
- }
- memset(xpd->chans, 0, sizeof(struct zt_chan)*cn);
- memset(&xpd->span, 0, sizeof(struct zt_span));
-
- span = &xpd->span;
- xbus = xpd->xbus;
- snprintf(span->name, MAX_SPANNAME, "%s/%s",
- xbus->busname, xpd->xpdname);
- {
- char tmp[MAX_SPANNAME];
- struct xpd_sim *sim = &xbus->sim[xpd->id];
-
- if(sim->simulated)
- snprintf(tmp, MAX_SPANNAME, " (sim to=%d)", sim->loopto);
- else
- tmp[0] = '\0';
-
- snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: %s%s",
- xbus->num, xpd->id,
- (xpd->direction == TO_PHONE) ? "FXS" : "FXO",
- tmp
- );
- }
- for(i = 0; i < cn; i++) {
-
- cur_chan = &xpd->chans[i];
- DBG("setting channel %d\n", i);
- snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXS/%d-%d", xpd->id, i);
- cur_chan->chanpos = i + 1;
- cur_chan->pvt = xpd;
- cur_chan->sigcap =
-#if 1
- ZT_SIG_FXOKS |
- ZT_SIG_FXOLS |
- ZT_SIG_FXOGS |
-#else
- ZT_SIG_SF |
- ZT_SIG_EM |
-#endif
- 0;
- }
- span->deflaw = ZT_LAW_MULAW;
- init_waitqueue_head(&span->maintq);
- span->pvt = xpd;
- span->channels = cn;
- span->chans = xpd->chans;
-
- span->startup = FXS_xpp_startup;
- span->shutdown = FXS_xpp_shutdown;
- span->spanconfig = FXS_xpp_spanconfig;
- span->chanconfig = FXS_xpp_chanconfig;
- span->open = xpp_open;
- span->close = xpp_close;
-#ifdef WITH_RBS
- span->flags = ZT_FLAG_RBS;
- span->hooksig = xpp_hooksig; /* Only with RBS bits */
-#else
- span->sethook = FXS_xpp_sethook;
-#endif
- span->ioctl = FXS_xpp_ioctl;
- span->maint = xpp_maint;
-#ifdef CONFIG_ZAPTEL_WATCHDOG
- span->watchdog = xpp_watchdog;
-#endif
-
- return 0;
-}
-#endif
-
-int FXS_zaptel_cleanup(xpd_t *xpd)
-{
- return 0;
-}
-
-/*------------------------- FXO Functions --------------------------*/
-static int FXO_card_new(xpd_t *xpd)
-{
- xpd->direction = TO_TRUNK;
- xpd->channels = min(8, CHANNELS_PERXPD);
- return 0;
-}
-
-static int FXO_card_remove(xpd_t *xpd)
-{
- return 0;
-}
-
-static int FXO_card_startup(struct zt_span *span)
-{
- DBG("\n");
- return 0;
-}
-
-/*
- * Called only for 'span' keyword in /etc/zaptel.conf
- */
-static int FXO_card_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
-{
- xpd_t *xpd = span->pvt;
-
- DBG("%s\n", xpd->xpdname);
- return 0;
-}
-
-/* Set signalling type (if appropriate) */
-static int FXO_card_chanconfig(struct zt_chan *chan, int sigtype)
-{
- DBG("channel %d (%s), sigtype %d.\n", chan->channo, chan->name, sigtype);
- dump_sigtype(print_dbg, " ", 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 FXO_card_shutdown(struct zt_span *span)
-{
- xpd_t *xpd = span->pvt;
-
- DBG("%s\n", xpd->xpdname);
- return 0;
-}
-
-
-static int FXO_card_sethook(struct zt_chan *chan, int hookstate)
-{
- int pos = chan->chanpos - 1;
- xpd_t *xpd = chan->pvt;
- xbus_t *xbus;
- int ret = 0;
-
- BUG_ON(!xpd);
- xbus = xpd->xbus;
- // DBG("%s (%d) (old=0x%04X, hook-command=%d)\n", chan->name, pos, xpd->hookstate, hookstate);
- switch(hookstate) {
- /* On-hook, off-hook: The PBX is playing a phone on an FXO line.
- * Can be ignored for an FXS line
- */
- case ZT_ONHOOK:
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_ONHOOK %s digital output OFF\n", chan->name);
- ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
- return ret;
- }
- DBG("ZT_ONHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
- xpd->ringing[pos] = 0;
- BIT_CLR(xpd->hookstate, pos);
- ret = CALL_PROTO(SETHOOK, xbus, xpd, xpd->hookstate);
- if(ret) {
- DBG("ZT_ONHOOK Failed: ret=0x%02X\n", ret);
- break;
- }
- break;
- case ZT_START:
- DBG("ZT_START: %s hookstate=0x%04X (fall through ZT_OFFHOOK)\n", chan->name, xpd->hookstate);
- // Fall through
- case ZT_OFFHOOK:
- DBG("ZT_OFFHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
- BIT_SET(xpd->hookstate, pos);
- xpd->ringing[pos] = 0;
- ret = CALL_PROTO(SETHOOK, xbus, xpd, xpd->hookstate);
- if(ret) {
- DBG("ZT_OFFHOOK Failed: ret=0x%02X\n", ret);
- break;
- }
- break;
- case ZT_WINK:
- DBG("ZT_WINK %s\n", chan->name);
- break;
- case ZT_FLASH:
- DBG("ZT_FLASH %s\n", chan->name);
- break;
- case ZT_RING:
- DBG("ZT_RING %s pos=%d (ringing[pos]=%d)\n", chan->name, pos, xpd->ringing[pos]);
- break;
- case ZT_RINGOFF:
- DBG("ZT_RINGOFF %s\n", chan->name);
- break;
- default:
- DBG("UNKNOWN hookstate=0x%X\n", hookstate);
- }
- return ret;
-}
-
-static int FXO_card_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- default:
- return xpp_ioctl(chan, cmd, arg);
- }
- return 0;
-}
-
-
-/*------------------------- Function table -------------------------*/
-
-#define DEF_(t) \
- [XPD_TYPE_ ## t] { \
- .card_new = t ## _card_new, \
- .card_remove = t ## _card_remove, \
- .card_startup = t ## _card_startup, \
- .card_shutdown = t ## _card_shutdown, \
- .card_spanconfig = t ## _card_spanconfig, \
- .card_chanconfig = t ## _card_chanconfig, \
- .card_sethook = t ## _card_sethook, \
- .card_ioctl = t ## _card_ioctl, \
- }
-
-xops_t xpd_card_ops[XPD_TYPE_NOMODULE] = {
- DEF_(FXS),
- DEF_(FXO)
-};
-
-xops_t *get_xops(xpd_type_t xpd_type)
-{
- if(xpd_type >= XPD_TYPE_NOMODULE)
- return NULL;
- return &xpd_card_ops[xpd_type];
-}
diff --git a/xpp/cards.h b/xpp/cards.h
deleted file mode 100644
index 26e53f0..0000000
--- a/xpp/cards.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef CARDS_H
-#define CARDS_H
-
-#include "xpd.h"
-
-struct xpd_card_ops {
- int (*card_new)(xpd_t *xpd);
- int (*card_remove)(xpd_t *xpd);
-#if 0
- int (*zaptel_setup)(xpd_t *xpd);
- int (*zaptel_cleanup)(xpd_t *xpd);
-#endif
- int (*card_startup)(struct zt_span *span);
- int (*card_shutdown)(struct zt_span *span);
- int (*card_spanconfig)(struct zt_span *span, struct zt_lineconfig *lc);
- int (*card_chanconfig)(struct zt_chan *chan, int sigtype);
- int (*card_sethook)(struct zt_chan *chan, int hookstate);
- int (*card_ioctl)(struct zt_chan *chan, unsigned int cmd, unsigned long arg);
-};
-
-xops_t *get_xops(xpd_type_t xpd_type);
-
-#endif /* CARDS_H */
diff --git a/xpp/gen_slic_init b/xpp/gen_slic_init
deleted file mode 100755
index f102c33..0000000
--- a/xpp/gen_slic_init
+++ /dev/null
@@ -1,37 +0,0 @@
-#! /usr/bin/perl -w
-
-use strict;
-
-my $input;
-my $header;
-my $comment;
-
-@ARGV == 2 or die "Usage: $0 <infile> <outfile>\n";
-$input = $ARGV[0];
-$header = $ARGV[1];
-open(IF, "$input") or die "Failed to write '$input': $!\n";
-open(HF, ">$header") or die "Failed to write '$header': $!\n";
-
-while(<IF>) {
- chomp;
- undef $comment;
- s/\r//; # CRLF -> LF
- if(s/\s*[;#]\s*(.*?)$//) { # Comments
- $comment = $1;
- }
- if(/^\s*$/) { # Empty lines
- next;
- }
- my ($slic0, $slic1, $slic2, $slic3, $len, @data) = split;
- die "Bad input (len=$len)" if hex($len) != @data;
- my $slic = "$slic3$slic2$slic1$slic0";
- die "Bad slic address '$slic'" if length($slic) != 8;
- grep(s/\w+/0x$&/g, ($slic, $len, @data));
- my $str = join(", ", @data);
- print HF "S_($slic,\t$len,\t$str),\t";
-} continue {
- if(defined($comment)) {
- print HF "// $comment";
- }
- print HF "\n";
-}
diff --git a/xpp/init_data_3_19.cmd b/xpp/init_data_3_19.cmd
new file mode 100644
index 0000000..69bdb80
--- /dev/null
+++ b/xpp/init_data_3_19.cmd
@@ -0,0 +1,169 @@
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2006, Xorcom
+#
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# See the file LICENSE in the top level of this tarball.
+#
+
+;
+; $Id$
+;
+; SLICS CMD Reg High Low
+
+; ----------------------------------==== 8-channel FXS unit initialization ===-----------------------------------------
+; INTERNAL PS
+; Change SLICs states to "Open state"s (Off,all transfers tristated to avoid data collision), Voltage sense
+
+FF 00 00 00 WD 40 00
+FF 00 00 00 WD 6C 01
+
+; ------------------------------------- Initialization of indirect registers ------------------------------------------
+
+FF 00 00 00 WI 00 55 C2
+FF 00 00 00 WI 01 51 E6
+FF 00 00 00 WI 02 4B 85
+FF 00 00 00 WI 03 49 37
+
+FF 00 00 00 WI 04 33 33
+FF 00 00 00 WI 05 02 02
+FF 00 00 00 WI 06 02 02
+FF 00 00 00 WI 07 01 98
+
+FF 00 00 00 WI 08 01 98
+FF 00 00 00 WI 09 06 11
+FF 00 00 00 WI 0A 02 02
+FF 00 00 00 WI 0B 00 E5
+
+FF 00 00 00 WI 0C 0A 1C
+FF 00 00 00 WI 0D 7B 30
+FF 00 00 00 WI 0E 00 63
+FF 00 00 00 WI 0F 00 00
+
+FF 00 00 00 WI 10 78 70
+FF 00 00 00 WI 11 00 7D
+FF 00 00 00 WI 12 00 00
+FF 00 00 00 WI 13 00 00
+
+FF 00 00 00 WI 14 7E F0
+FF 00 00 00 WI 15 01 60
+FF 00 00 00 WI 16 00 00
+FF 00 00 00 WI 17 20 00
+
+FF 00 00 00 WI 18 20 00
+FF 00 00 00 WI 19 00 00
+FF 00 00 00 WI 1A 40 00
+FF 00 00 00 WI 1B 40 00
+
+FF 00 00 00 WI 1C 18 00
+FF 00 00 00 WI 1D 40 00
+FF 00 00 00 WI 1E 10 00
+FF 00 00 00 WI 1F 00 80
+
+FF 00 00 00 WI 20 0F F4
+FF 00 00 00 WI 21 6E 7E
+FF 00 00 00 WI 22 0F F4
+FF 00 00 00 WI 23 88 00
+
+FF 00 00 00 WI 24 03 20
+FF 00 00 00 WI 25 00 12
+FF 00 00 00 WI 26 00 12
+FF 00 00 00 WI 27 00 12
+
+FF 00 00 00 WI 28 0C 00
+FF 00 00 00 WI 29 0C 00
+FF 00 00 00 WI 2B 08 00
+
+FF 00 00 00 WI 63 00 DA
+FF 00 00 00 WI 64 6B 60
+FF 00 00 00 WI 65 00 74
+FF 00 00 00 WI 66 79 C0
+
+FF 00 00 00 WI 67 11 20
+FF 00 00 00 WI 68 3B E0
+
+; ------------------------------------- Initialization of direct registers --------------------------------------------
+
+; Mode(8-bit,u-Law,1 PCLK ) setting, Loopbacks and Interrupts clear
+
+FF 00 00 00 WD 01 29
+FF 00 00 00 WD 08 00
+FF 00 00 00 WD 09 00
+FF 00 00 00 WD 0E 00
+
+FF 00 00 00 WD 15 00
+FF 00 00 00 WD 16 03
+FF 00 00 00 WD 17 00
+FF 00 00 00 WD 12 FF
+FF 00 00 00 WD 13 FF
+FF 00 00 00 WD 14 FF
+
+; Automatic/Manual Control: defaults - Cancel Power Alarm
+FF 00 00 00 WD 43 1E
+
+FF 00 00 00 WD 4A 31
+FF 00 00 00 WD 4B 10
+
+; Battery Feed Control: Battery low (DCSW low)
+FF 00 00 00 WD 42 00
+
+; Slic Calibration
+FF 00 00 00 WD 61 1F
+FF 00 00 00 WD 60 5F
+
+; Loop Closure Debounce Interval
+FF 00 00 00 WD 45 0A
+
+; Ring Detect Debounce Interval
+FF 00 00 00 WD 46 0B
+
+; Loop Current Limit
+FF 00 00 00 WD 47 07
+
+; Setting of SLICs offsets
+
+01 00 00 00 WD 02 01
+01 00 00 00 WD 03 00
+01 00 00 00 WD 04 01
+01 00 00 00 WD 05 00
+
+02 00 00 00 WD 02 09
+02 00 00 00 WD 03 00
+02 00 00 00 WD 04 09
+02 00 00 00 WD 05 00
+
+04 00 00 00 WD 02 11
+04 00 00 00 WD 03 00
+04 00 00 00 WD 04 11
+04 00 00 00 WD 05 00
+
+08 00 00 00 WD 02 19
+08 00 00 00 WD 03 00
+08 00 00 00 WD 04 19
+08 00 00 00 WD 05 00
+
+10 00 00 00 WD 02 21
+10 00 00 00 WD 03 00
+10 00 00 00 WD 04 21
+10 00 00 00 WD 05 00
+
+20 00 00 00 WD 02 29
+20 00 00 00 WD 03 00
+20 00 00 00 WD 04 29
+20 00 00 00 WD 05 00
+
+40 00 00 00 WD 02 31
+40 00 00 00 WD 03 00
+40 00 00 00 WD 04 31
+40 00 00 00 WD 05 00
+
+80 00 00 00 WD 02 39
+80 00 00 00 WD 03 00
+80 00 00 00 WD 04 39
+80 00 00 00 WD 05 00
diff --git a/xpp/init_data_3_20.cmd b/xpp/init_data_3_20.cmd
new file mode 100644
index 0000000..203a39d
--- /dev/null
+++ b/xpp/init_data_3_20.cmd
@@ -0,0 +1,170 @@
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2006, Xorcom
+#
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# See the file LICENSE in the top level of this tarball.
+#
+
+;
+; $Id$
+;
+; SLICS CMD Reg High Low
+
+; ----------------------------------==== 8-channel FXS unit initialization ===-----------------------------------------
+; INTERNAL PS
+; Change SLICs states to "Open state"s (Off,all transfers tristated to avoid data collision), Voltage sense
+
+FF 00 00 00 WD 40 00
+FF 00 00 00 WD 6C 01
+
+; ------------------------------------- Initialization of indirect registers ------------------------------------------
+
+FF 00 00 00 WI 00 55 C2
+FF 00 00 00 WI 01 51 E6
+FF 00 00 00 WI 02 4B 85
+FF 00 00 00 WI 03 49 37
+
+FF 00 00 00 WI 04 33 33
+FF 00 00 00 WI 05 02 02
+FF 00 00 00 WI 06 02 02
+FF 00 00 00 WI 07 01 98
+
+FF 00 00 00 WI 08 01 98
+FF 00 00 00 WI 09 06 11
+FF 00 00 00 WI 0A 02 02
+FF 00 00 00 WI 0B 00 E5
+
+FF 00 00 00 WI 0C 0A 1C
+FF 00 00 00 WI 0D 7B 30
+FF 00 00 00 WI 0E 00 63
+FF 00 00 00 WI 0F 00 00
+
+FF 00 00 00 WI 10 78 70
+FF 00 00 00 WI 11 00 7D
+FF 00 00 00 WI 12 00 00
+FF 00 00 00 WI 13 00 00
+
+FF 00 00 00 WI 14 7E F0
+FF 00 00 00 WI 15 01 60
+FF 00 00 00 WI 16 00 00
+FF 00 00 00 WI 17 20 00
+
+FF 00 00 00 WI 18 20 00
+FF 00 00 00 WI 19 00 00
+FF 00 00 00 WI 1A 40 00
+FF 00 00 00 WI 1B 40 00
+
+FF 00 00 00 WI 1C 18 00
+FF 00 00 00 WI 1D 40 00
+FF 00 00 00 WI 1E 10 00
+FF 00 00 00 WI 1F 00 80
+
+FF 00 00 00 WI 20 0F F4
+FF 00 00 00 WI 21 6E 7E
+FF 00 00 00 WI 22 0F F4
+FF 00 00 00 WI 23 88 00
+
+FF 00 00 00 WI 24 03 20
+FF 00 00 00 WI 25 00 12
+FF 00 00 00 WI 26 00 12
+FF 00 00 00 WI 27 00 12
+
+FF 00 00 00 WI 28 0C 00
+FF 00 00 00 WI 29 0C 00
+FF 00 00 00 WI 2B 08 00
+
+FF 00 00 00 WI 63 00 DA
+FF 00 00 00 WI 64 6B 60
+FF 00 00 00 WI 65 00 74
+FF 00 00 00 WI 66 79 C0
+
+FF 00 00 00 WI 67 11 20
+FF 00 00 00 WI 68 3B E0
+
+; ------------------------------------- Initialization of direct registers --------------------------------------------
+
+; Mode(8-bit,u-Law,1 PCLK ) setting, Loopbacks and Interrupts clear
+
+FF 00 00 00 WD 01 29
+FF 00 00 00 WD 08 00
+FF 00 00 00 WD 09 00
+FF 00 00 00 WD 0E 00
+
+FF 00 00 00 WD 15 00
+FF 00 00 00 WD 16 03
+FF 00 00 00 WD 17 00
+FF 00 00 00 WD 12 FF
+FF 00 00 00 WD 13 FF
+FF 00 00 00 WD 14 FF
+
+; Automatic/Manual Control: defaults - Cancel Power Alarm
+FF 00 00 00 WD 43 1E
+
+FF 00 00 00 WD 4A 31
+FF 00 00 00 WD 4B 10
+
+; Battery Feed Control: Battery low (DCSW low)
+FF 00 00 00 WD 42 00
+
+; Slic Calibration
+FF 00 00 00 WD 61 1F
+FF 00 00 00 WD 60 5F
+
+; Loop Closure Debounce Interval
+FF 00 00 00 WD 45 0A
+
+; Ring Detect Debounce Interval
+FF 00 00 00 WD 46 0B
+
+; Loop Current Limit
+FF 00 00 00 WD 47 07
+
+; Setting of SLICs offsets
+
+# New card initialization
+01 00 00 00 WD 02 00
+01 00 00 00 WD 03 00
+01 00 00 00 WD 04 00
+01 00 00 00 WD 05 00
+
+02 00 00 00 WD 02 08
+02 00 00 00 WD 03 00
+02 00 00 00 WD 04 08
+02 00 00 00 WD 05 00
+
+04 00 00 00 WD 02 10
+04 00 00 00 WD 03 00
+04 00 00 00 WD 04 10
+04 00 00 00 WD 05 00
+
+08 00 00 00 WD 02 18
+08 00 00 00 WD 03 00
+08 00 00 00 WD 04 18
+08 00 00 00 WD 05 00
+
+10 00 00 00 WD 02 20
+10 00 00 00 WD 03 00
+10 00 00 00 WD 04 20
+10 00 00 00 WD 05 00
+
+20 00 00 00 WD 02 28
+20 00 00 00 WD 03 00
+20 00 00 00 WD 04 28
+20 00 00 00 WD 05 00
+
+40 00 00 00 WD 02 30
+40 00 00 00 WD 03 00
+40 00 00 00 WD 04 30
+40 00 00 00 WD 05 00
+
+80 00 00 00 WD 02 38
+80 00 00 00 WD 03 00
+80 00 00 00 WD 04 38
+80 00 00 00 WD 05 00
diff --git a/xpp/init_data_4_19.cmd b/xpp/init_data_4_19.cmd
new file mode 100644
index 0000000..3223fb7
--- /dev/null
+++ b/xpp/init_data_4_19.cmd
@@ -0,0 +1,69 @@
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2006, Xorcom
+#
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# See the file LICENSE in the top level of this tarball.
+#
+
+;
+; $Id$
+;
+; DAA's CMD Reg High Low
+
+; ----------------------------------==== 8-channel FXO unit initialization ===-----------------------------------------
+
+FF FF 00 00 WD 21 28
+FF FF 00 00 WD 18 99
+FF FF 00 00 WD 06 00
+
+; ----------- DAA PCM start offset ----------
+
+01 00 00 00 WD 22 01
+01 00 00 00 WD 23 00
+01 00 00 00 WD 24 01
+01 00 00 00 WD 25 00
+
+02 00 00 00 WD 22 09
+02 00 00 00 WD 23 00
+02 00 00 00 WD 24 09
+02 00 00 00 WD 25 00
+
+04 00 00 00 WD 22 11
+04 00 00 00 WD 23 00
+04 00 00 00 WD 24 11
+04 00 00 00 WD 25 00
+
+08 00 00 00 WD 22 19
+08 00 00 00 WD 23 00
+08 00 00 00 WD 24 19
+08 00 00 00 WD 25 00
+
+10 00 00 00 WD 22 21
+10 00 00 00 WD 23 00
+10 00 00 00 WD 24 21
+10 00 00 00 WD 25 00
+
+20 00 00 00 WD 22 29
+20 00 00 00 WD 23 00
+20 00 00 00 WD 24 29
+20 00 00 00 WD 25 00
+
+40 00 00 00 WD 22 31
+40 00 00 00 WD 23 00
+40 00 00 00 WD 24 31
+40 00 00 00 WD 25 00
+
+80 00 00 00 WD 22 39
+80 00 00 00 WD 23 00
+80 00 00 00 WD 24 39
+80 00 00 00 WD 25 00
+
+; ----------- DAA ONHOOK --------------------
+FF FF 00 00 WD 05 00
diff --git a/xpp/init_data_4_20.cmd b/xpp/init_data_4_20.cmd
new file mode 100644
index 0000000..1b3fde2
--- /dev/null
+++ b/xpp/init_data_4_20.cmd
@@ -0,0 +1,60 @@
+#
+# Written by Oron Peled <oron@actcom.co.il>
+# Copyright (C) 2006, Xorcom
+#
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# See the file LICENSE in the top level of this tarball.
+#
+
+;
+; $Id$
+;
+; DAA's CMD Reg High Low
+
+; Start with a software reset:
+FF FF 00 00 WD 01 80
+
+; ----------------------------------==== 8-channel FXO unit initialization ===-----------------------------------------
+
+FF FF 00 00 WD 21 28
+; 99 also sets ring validation
+;FF FF 00 00 WD 18 99
+FF FF 00 00 WD 06 00
+
+; ----------- DAA PCM start offset ----------
+
+FF FF 00 00 WD 23 00
+FF FF 00 00 WD 25 00
+
+01 00 00 00 WD 22 00
+01 00 00 00 WD 24 00
+
+02 00 00 00 WD 22 08
+02 00 00 00 WD 24 08
+
+04 00 00 00 WD 22 10
+04 00 00 00 WD 24 10
+
+08 00 00 00 WD 22 18
+08 00 00 00 WD 24 18
+
+10 00 00 00 WD 22 20
+10 00 00 00 WD 24 20
+
+20 00 00 00 WD 22 28
+20 00 00 00 WD 24 28
+
+40 00 00 00 WD 22 30
+40 00 00 00 WD 24 30
+
+80 00 00 00 WD 22 38
+80 00 00 00 WD 24 38
+
+; ----------- DAA ONHOOK --------------------
+FF FF 00 00 WD 05 08
diff --git a/xpp/initialize_registers b/xpp/initialize_registers
new file mode 100755
index 0000000..35386ce
--- /dev/null
+++ b/xpp/initialize_registers
@@ -0,0 +1,39 @@
+#! /bin/sh
+# XPD_BUS - bus name
+# XPD_NAME - xpd name
+# XPD_TYPE - xpd type number (from protocol reply):
+# 3 - FXS
+# 4 - FXO
+# XPD_REVISION - xpd revision number
+
+set -e
+
+LOGGER="logger -i -t `basename $0`"
+
+INIT_DIR=`dirname $0`
+BASE=/proc/xpp
+
+SLICS="$BASE/$XPD_BUS/$XPD_NAME/slics"
+FILE="$INIT_DIR/init_data_${XPD_TYPE}_${XPD_REVISION}.cmd"
+
+if [ ! -f "$SLICS" ]; then
+ $LOGGER "missing slics file '$SLICS'"
+ exit 1
+fi
+
+if [ ! -f "$FILE" ]; then
+ $LOGGER "missing register initialization file '$FILE'"
+ exit 1
+fi
+
+case "$XPD_TYPE" in
+3|4)
+ cat "$FILE" > "$SLICS"
+ ;;
+*)
+ $LOGGER "Unknown type '$XPD_TYPE'"
+ exit 2
+esac
+$LOGGER "Wrote '$FILE' into '$SLICS'"
+
+exit 0
diff --git a/xpp/slic.c b/xpp/slic.c
index fd718a5..b019766 100644
--- a/xpp/slic.c
+++ b/xpp/slic.c
@@ -1,6 +1,6 @@
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -30,6 +30,9 @@ static const char rcsid[] = "$Id$";
extern int print_dbg;
#include "zap_debug.h"
+
+DEF_PARM(charp,initialize_registers, "/usr/share/zaptel/initialize_registers", "The script to initialize detected cards slics");
+
#else
#include <stdio.h>
#endif
@@ -120,6 +123,50 @@ void dump_slic_cmd(const char msg[], slic_cmd_t *sc)
#ifdef __KERNEL__
+#define MAX_ENV_STR 20
+
+int run_initialize_registers(xpd_t *xpd)
+{
+ int ret;
+ xbus_t *xbus;
+ char busstr[MAX_ENV_STR];
+ char xpdstr[MAX_ENV_STR];
+ char typestr[MAX_ENV_STR];
+ char revstr[MAX_ENV_STR];
+ char *argv[] = {
+ initialize_registers,
+ NULL
+ };
+ char *envp[] = {
+ busstr,
+ xpdstr,
+ typestr,
+ revstr,
+ NULL
+ };
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ if(!initialize_registers || !initialize_registers[0]) {
+ NOTICE("%s/%s: No runtime register initialization\n", xbus->busname, xpd->xpdname);
+ return 0;
+ }
+ DBG("%s/%s: running: '%s'\n", xbus->busname, xpd->xpdname, initialize_registers);
+ snprintf(busstr, MAX_ENV_STR, "XPD_BUS=%s", xbus->busname);
+ snprintf(xpdstr, MAX_ENV_STR, "XPD_NAME=%s", xpd->xpdname);
+ snprintf(typestr, MAX_ENV_STR, "XPD_TYPE=%d", xpd->type);
+ snprintf(revstr, MAX_ENV_STR, "XPD_REVISION=%d", xpd->revision);
+ DBG("%s/%s: type=%d revision=%d\n", xbus->busname, xpd->xpdname, xpd->type, xpd->revision);
+ ret = call_usermodehelper(initialize_registers, argv, envp, 1);
+ if(ret != 0) {
+ ERR("%s/%s: Failed running '%s' (errno %d, sig=%d)\n",
+ xbus->busname, xpd->xpdname, initialize_registers,
+ ((unsigned)ret >> 8) & 0xFF, ret & 0xFF);
+ ret = -EFAULT;
+ }
+ return ret;
+}
+
EXPORT_SYMBOL(slic_cmd_direct_write);
EXPORT_SYMBOL(slic_cmd_direct_read);
EXPORT_SYMBOL(slic_cmd_indirect_write);
diff --git a/xpp/slic.h b/xpp/slic.h
index 76f2d6e..ea49441 100644
--- a/xpp/slic.h
+++ b/xpp/slic.h
@@ -1,5 +1,26 @@
#ifndef SLIC_H
#define SLIC_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
#include "xdefs.h"
@@ -46,12 +67,6 @@ typedef struct slic_reply {
(slic_reg)->reg_data = data; \
} while(0);
-/* OLD SLIC_INIT data */
-typedef struct slic_data {
- byte len;
- byte data[40];
-} __attribute__((packed)) slic_data_t;
-
/*------------------------------ SLIC Initializers -------------------------*/
@@ -60,6 +75,7 @@ int slic_cmd_direct_read(slic_cmd_t *sc, xpp_line_t lines, byte reg);
int slic_cmd_indirect_write(slic_cmd_t *sc, xpp_line_t lines, byte reg, byte data_low, byte data_high);
int slic_cmd_indirect_read(slic_cmd_t *sc, xpp_line_t lines, byte reg);
void dump_slic_cmd(const char msg[], slic_cmd_t *sc);
+int run_initialize_registers(xpd_t *xpd);
#endif /* SLIC_H */
diff --git a/xpp/slic_init.inc b/xpp/slic_init.inc
deleted file mode 100644
index 5f118b8..0000000
--- a/xpp/slic_init.inc
+++ /dev/null
@@ -1,65 +0,0 @@
-// ----------------------------------==== 8-channel FXS unit initialization ===-----------------------------------------
-
-// INTERNAL PS
-// Change SLICs states to "Open state"s (Off,all transfers tristated to avoid data collision), Voltage sense
-S_(0x000000FF, 0x04, 0x40, 0x00, 0x6C, 0x01),
-
-
-// ------------------------------------- Initialization of indirect registers ------------------------------------------
-S_(0x000000FF, 0x02, 0x40, 0x00),
-S_(0x000000FF, 0x18, 0x1C, 0xC2, 0x1D, 0x55, 0x1E, 0x00, 0x1C, 0xE6, 0x1D, 0x51, 0x1E, 0x01, 0x1C, 0x85, 0x1D, 0x4B, 0x1E, 0x02, 0x1C, 0x37, 0x1D, 0x49, 0x1E, 0x03),
-S_(0x000000FF, 0x18, 0x1C, 0x33, 0x1D, 0x33, 0x1E, 0x04, 0x1C, 0x02, 0x1D, 0x02, 0x1E, 0x05, 0x1C, 0x02, 0x1D, 0x02, 0x1E, 0x06, 0x1C, 0x98, 0x1D, 0x01, 0x1E, 0x07),
-S_(0x000000FF, 0x18, 0x1C, 0x98, 0x1D, 0x01, 0x1E, 0x08, 0x1C, 0x11, 0x1D, 0x06, 0x1E, 0x09, 0x1C, 0x02, 0x1D, 0x02, 0x1E, 0x0A, 0x1C, 0xE5, 0x1D, 0x00, 0x1E, 0x0B),
-S_(0x000000FF, 0x18, 0x1C, 0x1C, 0x1D, 0x0A, 0x1E, 0x0C, 0x1C, 0x30, 0x1D, 0x7B, 0x1E, 0x0D, 0x1C, 0x63, 0x1D, 0x00, 0x1E, 0x0E, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x0F),
-
-S_(0x000000FF, 0x18, 0x1C, 0x70, 0x1D, 0x78, 0x1E, 0x10, 0x1C, 0x7D, 0x1D, 0x00, 0x1E, 0x11, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x12, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x13),
-S_(0x000000FF, 0x18, 0x1C, 0xF0, 0x1D, 0x7E, 0x1E, 0x14, 0x1C, 0x60, 0x1D, 0x01, 0x1E, 0x15, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x16, 0x1C, 0x00, 0x1D, 0x20, 0x1E, 0x17),
-S_(0x000000FF, 0x18, 0x1C, 0x00, 0x1D, 0x20, 0x1E, 0x18, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x19, 0x1C, 0x00, 0x1D, 0x40, 0x1E, 0x1A, 0x1C, 0x00, 0x1D, 0x40, 0x1E, 0x1B),
-S_(0x000000FF, 0x18, 0x1C, 0x00, 0x1D, 0x18, 0x1E, 0x1C, 0x1C, 0x00, 0x1D, 0x40, 0x1E, 0x1D, 0x1C, 0x00, 0x1D, 0x10, 0x1E, 0x1E, 0x1C, 0x80, 0x1D, 0x00, 0x1E, 0x1F),
-
-S_(0x000000FF, 0x18, 0x1C, 0xF4, 0x1D, 0x0F, 0x1E, 0x20, 0x1C, 0x7E, 0x1D, 0x6E, 0x1E, 0x21, 0x1C, 0xF4, 0x1D, 0x0F, 0x1E, 0x22, 0x1C, 0x00, 0x1D, 0x88, 0x1E, 0x23),
-S_(0x000000FF, 0x18, 0x1C, 0x20, 0x1D, 0x03, 0x1E, 0x24, 0x1C, 0x12, 0x1D, 0x00, 0x1E, 0x25, 0x1C, 0x12, 0x1D, 0x00, 0x1E, 0x26, 0x1C, 0x12, 0x1D, 0x00, 0x1E, 0x27),
-S_(0x000000FF, 0x12, 0x1C, 0x00, 0x1D, 0x0C, 0x1E, 0x28, 0x1C, 0x00, 0x1D, 0x0C, 0x1E, 0x29, 0x1C, 0x00, 0x1D, 0x08, 0x1E, 0x2B),
-
-S_(0x000000FF, 0x18, 0x1C, 0xDA, 0x1D, 0x00, 0x1E, 0x63, 0x1C, 0x60, 0x1D, 0x6B, 0x1E, 0x64, 0x1C, 0x74, 0x1D, 0x00, 0x1E, 0x65, 0x1C, 0xC0, 0x1D, 0x79, 0x1E, 0x66),
-S_(0x000000FF, 0x0C, 0x1C, 0x20, 0x1D, 0x11, 0x1E, 0x67, 0x1C, 0xE0, 0x1D, 0x3B, 0x1E, 0x68),
-
-// ------------------------------------- Initialization of direct registers --------------------------------------------
-
-// Mode(8-bit,u-Law,1 PCLK ) setting, Loopbacks and Interrupts clear
-// --Temporary digital loopback
-S_(0x000000FF, 0x08, 0x01, 0x29, 0x08, 0x00, 0x09, 0x00, 0x0E, 0x00),
-S_(0x000000FF, 0x0C, 0x15, 0x00, 0x16, 0x03, 0x17, 0x00, 0x12, 0xFF, 0x13, 0xFF, 0x14, 0xFF),
-
-// Ring timers settings
-S_(0x000000FF, 0x06, 0x30, 0x80, 0x31, 0x3E, 0x32, 0x80),
-S_(0x000000FF, 0x02, 0x33, 0x3E),
-S_(0x000000FF, 0x02, 0x22, 0x18),
-
-// Battery feed control(DCSW), Automatic control of Ring Trip and Loop Closure, VBATH, VBATL
-S_(0x000000FF, 0x02, 0x42, 0x00),
-S_(0x000000FF, 0x02, 0x43, 0x1E),
-S_(0x000000FF, 0x04, 0x4A, 0x31, 0x4B, 0x10),
-
-S_(0x000000FF, 0x02, 0x45, 0x0A),
-S_(0x000000FF, 0x02, 0x46, 0x0B),
-S_(0x000000FF, 0x02, 0x47, 0x07),
-
-
-// Setting of SLICs offsets
-S_(0x00000001, 0x08, 0x02, 0x01, 0x03, 0x00, 0x04, 0x01, 0x05, 0x00),
-S_(0x00000002, 0x08, 0x02, 0x09, 0x03, 0x00, 0x04, 0x09, 0x05, 0x00),
-S_(0x00000004, 0x08, 0x02, 0x11, 0x03, 0x00, 0x04, 0x11, 0x05, 0x00),
-S_(0x00000008, 0x08, 0x02, 0x19, 0x03, 0x00, 0x04, 0x19, 0x05, 0x00),
-S_(0x00000010, 0x08, 0x02, 0x21, 0x03, 0x00, 0x04, 0x21, 0x05, 0x00),
-S_(0x00000020, 0x08, 0x02, 0x29, 0x03, 0x00, 0x04, 0x29, 0x05, 0x00),
-S_(0x00000040, 0x08, 0x02, 0x31, 0x03, 0x00, 0x04, 0x31, 0x05, 0x00),
-S_(0x00000080, 0x08, 0x02, 0x39, 0x03, 0x00, 0x04, 0x39, 0x05, 0x00),
-
-// Change SLICs states to "Normal state"s (On, after offsets are set already)
-
-
-S_(0x000000FF, 0x02, 0x40, 0x1),
-S_(0x000000FF, 0x02, 0x42, 0x06),
-// -------------------------------------------------------------
-
diff --git a/xpp/sync.sh b/xpp/sync.sh
deleted file mode 100755
index 1cac283..0000000
--- a/xpp/sync.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-
-set -e
-
-SVN_ROOT=/home/tzafrir/Proj/Svn
-XORTEL_DIR=$SVN_ROOT/xpp-zaptel/trunk/xortel
-XPP_DIR=$SVN_ROOT/xpp-zaptel/trunk/zaptel/xpp
-TARGET_DIR=xpp
-FIRMWARE=$SVN_ROOT/fpgafirmware/init.dat
-
-curdir=$PWD
-cd $XORTEL_DIR
- cd ..; svn update;
- cd xortel
- make FIRMWARE="$FIRMWARE" ../zaptel/xpp/slic_init.inc
-cd $curdir
-
-cp -a $XORTEL_DIR/FPGA_XPD.hex ${TARGET_DIR}/
-cp -a $XORTEL_DIR/xpd.h ${TARGET_DIR}/
-cp -a $XORTEL_DIR/xpp_zap.[ch] ${TARGET_DIR}/
-cp -a $XORTEL_DIR/xproto.[ch] ${TARGET_DIR}/
-cp -a $XORTEL_DIR/xdefs.h ${TARGET_DIR}/
-cp -a $XORTEL_DIR/xpp_usb.c ${TARGET_DIR}/
-cp -a $XORTEL_DIR/zap_debug.[ch] ${TARGET_DIR}/
-cp -a $XORTEL_DIR/slic.[ch] ${TARGET_DIR}/
-cp -a $XORTEL_DIR/card_*.[ch] ${TARGET_DIR}/
-cp -a $XORTEL_DIR/xpp_fxloader{,.usermap} ${TARGET_DIR}/
-cp -a $XORTEL_DIR/xpp_modprobe ${TARGET_DIR}/
-cp -a $XORTEL_DIR/gen_slic_init ${TARGET_DIR}/
-cp -a $XPP_DIR/Makefile ${TARGET_DIR}/
-cp -a $XPP_DIR/slic_init.inc ${TARGET_DIR}/
diff --git a/xpp/utils/FPGA_FXS.hex b/xpp/utils/FPGA_FXS.hex
new file mode 100644
index 0000000..4ec2790
--- /dev/null
+++ b/xpp/utils/FPGA_FXS.hex
@@ -0,0 +1,543 @@
+#
+# Description : ECHO suppressor included
+# $Id: FPGA_FXS.hex 1492 2006-06-29 10:50:25Z dima $
+#
+:020000040000FA
+:80000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6AD6FF4000985E08006AD6FF4000985E08006AD6FF4000985E080000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4455544455557475577775577675577775577765566665563625523235D2E37C2B5111155111155111155111D4
+:80008000155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111155111000000000000000000000000000000000000002552222552222552220025522225522200000000001AA1111AA1110025522200000000001AA1110000000000000000000000002552222552222F21F11211
+:80010000122F21F112122552222552222552222552221AA1111AA111001AA1112552222552222F21F112122F21F112122552222552222F21F112122F21F112122F21F11212255222000000002F21F112122F21F1121200002552222552221AA1111AA1112552222F21F1121200001AA1112F21F1121200002F21F112122F21F112121AA102
+:800180001100255222255222000000000025522200001AA1111AA11125522200255222000025522200000000CFC6F66C6C4F42F22424000000000000000000000000001AA1111AA111000000000000000000000000000025522200000000255222255222000025522225522225522225522225522225522225522225522225522200255257
+:800200002200000000004AA4444AA444000000004F44F444445F55F555551F11F111114F44F4444400004AA4444AA4440000004AA4442F24F442422F24F44242000000004F48F884846F69F996962F21F11212000000CAACCC2F2DFDD2D22F21F112124F48F884842F21F11212004F4CFCC4C46F6DFDD6D62F21F1121200006F6DFDD6D6F1
+:800280006F6DFDD6D66F6DFDD6D6000000008AA8882F29F992922F21F112120000004F4CFCC4C46F6DFDD6D62F21F112128AA8882F21F11212004F4CFCC4C46F6DFDD6D62F21F1121200006F6DFDD6D65F53F33535EFEFFFFEFE006F6DFDD6D66F6DFDD6D6000000008AA8882F28F88282255222000000CFCCFCCCCCCFCCFCCCCC008F8C99
+:80030000FCC8C8255222004F48F884844F48F884840000004F48F884844F48F884844F48F8848400000000CFCCFCCCCCCFCCFCCCCC000000008F8CFCC8C8AFACFCCACA255222CFCCFCCCCC0000CFCCFCCCCCEFECFCCECE2552220000EFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F88C8CCFC8F88C8C000000008F8CFCC8C8AFACC9
+:80038000FCCACA255222CFC8F88C8C0000CFCCFCCCCCEFECFCCECE2552220000EFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F88C8CCFC8F88C8C000000008F8CFCC8C8AFACFCCACA255222CFC8F88C8C0000CFCCFCCCCCEFECFCCECE2552220000EFECFCCECEEFECFCCECEEFECFCCECE00000000CFC8F88C8CCFCBFBBCBC3AA33321
+:800400000000008F8CFCC8C8AFAFFFFAFA2F23F33232CFC8F88C8C3AA33300CFCCFCCCCCEFEFFFFEFE2F23F3323200009F92F229296F62F2262600EFEFFFFEFEEFEFFFFEFEEFEFFFFEFE000000008AA888BAABBB3AA333000000CFCCFCCCCCEFECFCCECE2552228AA8883AA33300CFCCFCCCCCEFEEFEEEEE2F22F222220000EFEEFEEEEE51
+:80048000EFEEFEEEEEEFEEFEEEEE000000004AA4441F14F44141155111000000CFCCFCCCCCFFFFFFFFFF3F33F333334AA44415511100CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000008F84F448489F95F559591F11F11111000000CFCCFCCCCCFFFEFEEFEF3F32F223238F84F448481F11F11189
+:800500001100CFCCFCCCCCFFFEFEEFEF3F32F223230000FFFEFEEFEFFFFEFEEFEFFFFEFEEFEF00000000CFC4F44C4CFFF4F44F4F3553330000008F8CFCC8C8BFBFFFFBFB3F33F33333CFC4F44C4C35533300CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004554444F42F224242AA22200000094
+:800580008F8CFCC8C8BFBFFFFBFB3F33F333334554442AA22200CFCCFCCCCCFFFFFFFFFF3F33F3333300FFF1F11F1F1F1FFFF1F10000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004AA4446AA6662AA222000000CFCCFCCCCCFFFFFFFFFF3F33F333334AA4442AA22200CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFF8F
+:80060000FFFFFFFFFFFFFF00000000CFC4F44C4CCFC6F66C6C2AA2220000008F8CFCC8C8BFBFFFFBFB3F33F33333CFC4F44C4C2AA22200CFCCFCCCCCFFFFFFFFFF3F33F333330000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F48F884846F68F886862552220000008F8CFCC8C8BFBFFFFBFB3F33F333334F48F88484255222008F8A
+:800680008CFCC8C8BFBFFFFBFB3F33F333330000BFBFFFFBFBBFBFFFFBFBBFBFFFFBFB000000008AA8882F28F88282255222000000CFCCFCCCCCDFDFFFFDFD1F13F331314F48F88484255222008F8CFCC8C89F9FFFF9F91F13F3313100009F9FFFF9F99F9FFFF9F99F9FFFF9F9000000004F48F884846F68F88686255222000000CFCCFC7C
+:80070000CCCCFFFFFFFFFF3F33F333334F48F8848425522200CFCCFCCCCCFFFFFFFFFF3F33F33333CFCEFEECECBFBCFCCBCB000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000004F44F444447F74F44747355333000000CFCCFCCCCCDFDFFFFDFD1F13F331314F44F444443F31F1131300CFCCFCCCCCDFDEFEEDED1F12F221210000DF3B
+:80078000DEFEEDEDDFDEFEEDEDDFDEFEEDED000000004F44F444445F54F44545155111000000CFCCFCCCCCEFEFFFFEFE2F23F332324F44F444441F11F1111100CFCCFCCCCCCFCEFEECEC2AA2220000CFCEFEECECCFCEFEECECCFCEFEECEC000000004F44F444444F47F774743AA333000000CFCCFCCCCCFFFCFCCFCF3553334F44F4444454
+:800800001F13F3313100CFCCFCCCCCCFCCFCCCCC000000CFCCFCCCCCCFCCFCCCCCCFCCFCCCCC000000004F44F444444F47F774743AA333000000CFCCFCCCCCDFDDFDDDDD1F11F111114F44F444441F13F3313100CFCCFCCCCCCFCDFDDCDC1AA1110000CFCDFDDCDCCFCDFDDCDCCFCDFDDCDC000000000000000000000000000000000000B8
+:800880009F9CFCC9C9CFC1F11C1C000048180000000000000000000000000000000000000000000000000000002F8D02000000000000000000000000000000140000000000000080020000000000F0DBD7000000000000000000000000000000000000000000000000000000000000FFE40F00808401000000000000000000000000140015
+:80090000000000000000800200000000007046010000000000000000000000000000000000000000000000000000000000F04FFE800200400100800414800280041480020000800280040000214840010080041400108204000021BF26050000000000000000000000000000000000000000000000000000000000F04FFE000000000000E4
+:80098000000000000000000000000000000000000000000000000000FFE40F481800280000000021000000210014001002400100000080020000882880080088280000F0D136000048180000001200000000000000200100001400000014000000148002000000002F49054818148002800414182810820416012810A21140012810A241E3
+:800A00004001002B11484001280048408188022148008828108204F05C65808401800200000010020000100240010021001400000000280000808802000088280000F04EFE000000000000000000000000000000000000000000000000000000000000FFE40F000028000000000000000000140000000000000000000000000000000000E8
+:800A8000F017D400000000000000210000400200004022018001000000800200008200000082220000F0F9BC000000000000000000000000000000000000000000000000000020080000F0CEBE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000000000F1
+:800B00000000000020020000EF1C04000000000000000000000000000000000000002002000000000000000000EFBC0E000000000000000000400200110020010000000000000000000000000000007B69000020020000000000000000000000000000000000000080080000000000005F8A0E00000000000010020000000000400200120A
+:800B80000000000000000000000000000000CFD90F000000000024000000000000000000000000000000000000000000200800F07F8C200100381002001800000024001200000000000000400100000000000000000000D04F0E00001224000012000000100200000000000000001400000000000000000000006F9B0C1800200200001002
+:800C000002000000200100000000000000000000000000000000880000AF3C0D000000000000000014004200000000000000000000002002000000000000004FEF0D0000000000000000000000000000000000000000000000000000000000F04FFE800100000000000000000000000000000000000000000000000000000000E027080041
+:800C800000004800000000000000000000000000000000000000000000000000004F160D0000004800000000000000000000000000000000000000000000000000004F160D1800000000000000000000000000000000000000000000000000000000007E82000000000000000000000000000000000000000000000000000000000000FF69
+:800D0000E40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000020020000000000000000000000000000000000000000000000F2
+:800D800042002F3F0B0042000000000000000000000000000000000000000000000000000000007F7E05002200000000000000000000000000000000000000000000000000000000BFA90A002200008002000000000000000000000000000000000000000000000048006F770D000000000000000000000000000000000000000000000081
+:800E0000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000000014
+:800E80000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000094
+:800F00000000000000000000004001EFE10300480000000000280000000021800188000040010080040000000080020000110021F01338000000000000000000000000000000000000000000000000000000400140013FE10A000000000000000000000000000000000000000000000000000000004001EFE103000000000000000000004F
+:800F800000000000000000000000000000000000000000F04FFE00002008480000000000000000000000000000000000000000000000000000FF53030000004AA44400000000000000000000000000000000000000000000001400007FEF0DA0448024084AA44400002A022800004012022B11A098800800150114004A0448000000002ADE
+:801000000228000011242110F2368900480000000000280000000021800188000040010080040000000080020000001002D0FB06800442000000002820020000104282011A088200400111004820040000008002220000002124D02E0A0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000F6
+:801080000000000000000000000000000000000000000000000000FFE40F481B21B01122B411324219B24291212B9419B24219B14229F24291222F1429D212A9421CE922C4812E4216E12264192E4296C1429AC2421B292CB49142B29122B49132421B282394212B8419B24218B14228B24228B2422892822A84E822B42C01481B61481B38
+:8011000021421B212119B64291212B9419B2429B212B94222F1429F24291222D912B422D912E521CE922EC11E82264192E4296C1439E212CB491C2421B692CB49122B49132421B282394212B8419B2429A212B84222B84222B842229B82294822E421F690B2088040000000080020000001002188008000014000048000000000028000089
+:8011800000002501E3060000000000000000000000000000000000000000000000000000000000F04FFE00822008000000000000000000000000000000000000000000000000110040015FBA0B200C0000000020020000002400122008000011000042000000000022000000400214B0F2030020080000000000000000000000000000003F
+:80120000000000000000000000140000E097070000000000000000000000000000000000000000000000000000000000F04FFE00280000000000000000000000000000000000000000000000000000002200CF110C20020000000000000000000000000000000000000000000000000000000017110000000000000000000000000000001F
+:80128000000000000000000000000000002002F0489E00000000000000001001000000000000001200000000000000000000000000FFBE030000000000000000000000000000000000000000000000000000000000F04FFE000000000080040000000000000000000000000000000000000000000000F09538000000000000000040010054
+:8013000000000000000000000000000000000000000000F0DAC6000000000020040000000000000000000012000000000000000000000000005ECF000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000004B
+:8013800000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000008F
+:80140000000000000000000000000000000000000000000000000000FFE40F20080000000000000000000000000000000000000000000000000000001470630300488008000000800200000010021880080000140000480000000000280000100110023F2606200820080000000000000000000000000000000000000000000000000040C2
+:80148000018F730E20080000000000000000000000000000000000000000000000000040014001EF36090000000000000000000000000000000000000000000000000000000000F04FFE000020080000000000000000000000000000000000000000000000000000F0141A0000000000000000000000000000000000000000000000000080
+:801500000000000000FFE40FA0448084080000002A022800004012022B11A098800800150114004A0448000000002A02280000401202219F2F0480040000000080020000001002188008000014000048000000000028000000002100BD6F00482004000000800222000000212418A0812008001410018004420000000028200200001042C4
+:8015800002EDA2000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE80B411021B21421B212394212B1419B24299212B94112B94222F1429F24291222D912AC4912E421CE82264112E4296E12264192CA4292CB491C2421BF1
+:8016000029241B29421B2923B481324219B24298212B84112B84222B84222B842229A842882E42CB1280B41186B41122B411324219B24291212B9419B2429B212B94222F1429F24291222D912B422D912E521CE922EC11E82264192E4296C1439E212CB491C2421B692CB49122B49132421B282394212B8419B2429A212B84222B84222BBF
+:80168000842229B82294822E425F26082088040000000080020000001002188008000014000048000000000028000000002541B1AF0C0000000000000000000000000000000000000000000000000000000000F04FFE802208008882000000000000000000000000000000000000000000001001004001DFC70528C20000000000220000FE
+:8017000000400220018200001001002004000000002002001001400214708C09000080880800000000000000000000000000000000000000000000000000F0A7F8000000000000000000000000000000000000000000000000000000000000FFE40F0000000000180000000000000000000000000000000000000000000000008FFF060084
+:801780000000000012000000000000000000000000000000000000000000000000EF89080000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000140000200400000000000000000000000000000080F2BB490000000000000000000000000000000000000000000000000000000000006C
+:80180000FFE40F000000000000000000004200000000000000000000000000000000000000FFE10D000000000000000000400100004800000000000000000000000000000000222FBB05000000000000000000004200000000000000000000000000000000000000FFE10D000000000000000000000000000000000000000000000000007E
+:8018800000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000000000008A
+:80190000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000000000000000001414FFED0F0048000000000028000000002180018800004001FD
+:8019800000800400000000800200000010022FD40F000000000000000000000000000000000000000000000000000000004001EFE103000000000000000000000000000000000000000000000000000000004001EFE1030000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000058
+:801A00000000000000000000000000000000000000FFE40F000082000000000000000000000000000000000000000000000000400100F0198A004A044888000000A022800200002421B012018A09880050114001A0448004000000A02280020040411202214F2F0D80040000000080020000001002188008000014000048000000000028CE
+:801A8000000000002100BD6F00482004000000800222000000212418A081200800141001800442000000002820020000104202EDA2000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE80B411021B21421B212394212B1484
+:801B000019B24299212B94112B94222F1429F24291222D912AC4912E421CE82264112E4296E12264192CA4292CB491C2421B29241B29421B2923B481324219B24298212B84112B84222B84222B842229A842882E42CB1280B41186B41122B411324219B24291212B9419B2429B212B94222F1429F24291222D912B422D912E521CE922EC9D
+:801B800011E82264192E4296C1439E212CB491C2421B692CB49122B49132421B282394212B8419B2429A212B84222B84222B842229B82294822E425F26088282480000000000280000000021800188000040010080040000000080020000005012F08E81000000000000000000000000000000000000000000000000000000000000FFE4FB
+:801C00000F208801200800000000000000000000000000000000000000000000000010C121F0DD8200C20000000000220000004002200182000010010020040000000020020000002440012B3F0080018008000000000000000000000000000000000000000000000000408102BF6A0400000000000000000000000000000000000000005B
+:801C8000000000000000000000F04FFE00180000000000000000000000000000002002400100000000000000A028142820024E1C0000000000000000000000000000000000004001000000000000002048810200FE820012000000000000000000000000000000200200000000000000000028002002AB3F0014000000200800000000004C
+:801D0000000000000000000000000000000000000000001F2503180000000000004001000000000000000000000000000000200200000000005F840E0000000000000000000000000000000000000000000000000000000000F04FFE80110100000082000000000000000000000000000000000000000000000000F06E770000000000008A
+:801D8000004001000000000000000000000000000000000000000000F0E3FF000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000AF
+:801E00000000000000000000000000000000000000000000002002000000008F9C090000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000022F0443E000000000000000000000000000000000000000000000000800200000000F0689CC5
+:801E8000008A01000000000000000000000000000000000000000000000028000000C021F043210080048200000000280000000021800188000040010080040000000080020000142012023F910E2008800800000000000000000000000000000000000000000000000014206212F0126900820000000000000000000000000000000000F0
+:801F0000000000000000A0220000004001FF360A200100000000000000000000000000000000000000000000000000000028F0E14B000000000000000000000000000000000000000000000000000000000000FFE40FA01100000000000000000000000000000000000000000000000000001480A222F0CCF3005A0548000000002A022815
+:801F800000004012022B11A098800800150114004A0448000000002A0228000040120221CF8804A05100000000002800000000218001880000400100800400000000800200000090222A025F280FA0512004000000800222000000212418A081200800141001800442000000002820020010012124F05A3700000000000000000000000044
+:80200000000000000000000000000000000000000000FFE40F820000000000000000000000000000000000000000000000000000000000FFFA07481B21B01122B411324219B24291212B9419B24219B14229F24291222F1429D212A9421CE922C4812E4216E12264192E4296C1429AC2421B292CB49142B29122B49132421B282394212BF6
+:802080008419B24218B14228B24228B2422892822A84EA22F42DDA809461581B21421B212394212B1419B24299212BB419B24229F24291222F1429D212B922D412E922C5912EC21E812E4296E12264193CE419C2421B292CB491C6421B29421B2923B481324219B24298212BA4112BA4222B84222B842229984229E822D4270D00480000E4
+:8021000000000028000000002180018800004001200248000000000028000000002501EB5920080000000000000000000000002400000000000000000000000000000000EFFC0120082008002200000080020000480000002002000000008001000000008800001114F0D9DF004200880000002002000000240012200800201201002004C3
+:80218000000000002002282008002440013BB7000000002002000000280000200400100200000000000018000000000000001400EF660D8002288082010000000000002800000000000000000022000000000000000000F0A9FF000000000000000000000000000000000000220000000000000000002004006F3C0A000000180000000066
+:802200000000000000000000000022008002000000000000000000B7930028800228000000000000002200000000000000000000000000000000004200F0F1F9000000000000200200220000000000000000000000002002220000140028004800F065AB00000000000020020000000080010000000000000000000000220000000000F09F
+:802280009D8B000000000000000000A0120000000000000000000000000000000000000000FC050000000000000000222003000000000000000000000028800200400180020000F012BF000000000000000000000000000000000000000000000000000000004200F04BCE00000020010000000000000000000000000012000020010000F1
+:80230000000000000000286F640720022022012002200200000028008002000028000020010000120000000000002004007A05008002288002000000000000000000000000000000000000000000000000005F34030000000000000000000000000000000000000000000000000000000000F04FFE000020080022000000280028008002EF
+:802380000000000000200100001200000000002222200442147D9D80010000120000008002000000000000000000000000000000000000000000B02B0E2822280000228082220200002820022820020028222822000000000000000000000000800442BA0312000012000000282828000000000022000000000000000000000000000000B1
+:802400000022BFBE06004800000000002800002800902280018800004001008004800100000028000028003042F0CB9E002800008002288002000022002002000022200200800100001A010000000000222800484681F696288001008021010000000000280080020000000000A0110000A0110000000000000000F08AE2A02122282222A4
+:802480003218222A02282222A0222200222A0220A2222002208222020000000000000000000020024A044822FBA4000080022800220000008002002800000000000000000000000000000000004220D4BF0A2AA2222A022222122A2202A02200002A0228A02228A0222AA222002AA2222A0200121200001A8101000000000022800420746A
+:80250000EF083AA266A0622232122A02A0222A820228A02200E02212022B332AA2BAA0A22AA2222A521140A1111AA14480041A010000A0228002A022224012022B227FCB0A1AA1622A0228183A022AA2222AA2222800A0222AA2222AA2222B222A82A1222A0AA0222AA22214001AA1114800A01100000028000020024AB442A4444AF41C24
+:80258000D2A0232A066A82A2113A02282AA2222A0220022AA222222AA22223E22282A1223A0AAAA2222A021410A1111A810442A011000000282002A0222220B442E424A462CFA2041800008001000000000000280080020028800200000000000000000000000000F01DE82002000000002200002200000000000000000000000000000018
+:80260000000000000000149F310B481B21221B21621B212396212B1419B24299212B94112B94222F1429F24291222D912AC4912E421CE82264112E4296E12264192CA4292CB491C2421B29241B29421B2923B481324219B24298212B84112B84222B84222B842229A842882E428F2508481B6148132134112314B16211B14299212B9619A6
+:80268000B24229F242B1F042B1222D9129D412EB22C5912EC21EA12E4296E12264193CE419C2421B282CB591C6421B29421B282B141B282394212B8419B2429A212B84222B84B0422AB24238222B8426F2D72900800400000000800200000010021880080000140000480000000000280048000010022DCD00180000000000000000000081
+:802700002002000000000000000000000000000022000022479E0000000020210112290100220028000000424082010020022480822102000000000000004001AF9D07200500000000303280022800222400322088043012100120024200200200002002000028400280F2D15D000000008021011200000000000000000000000010828220
+:80278000010000000000000000008F4E0E0000000000000000000042000000000022800100000000000000000000004A82F4A14600000080010000400220020014180000221200420000184002001800000000002848280000BF490F0000001800000024000000480000202201000000180021001800000000000028002A84F4F39600004E
+:802800000000000000002002001118000000004828200100000000000000002082040000BD3D001800120000480032000028000020210448000000004242000000000022000000002002BF5C030000000088002828002200002228200100000000000042000000002002000000004870B80C18000000A028000000008200000000000000F6
+:80288000000000800200002002000000280020F8AF9600000000004880820120022A080028004280040000000000800200008002000000280020B8BC0518120018002002000000000028000000000000004800000000000000000000A024F02CC200820000000018008001000000800100000020010000122800000000000022000000BB13
+:802900002900000000000000200200000000000000000000004280020000000000000000F083E200828002282228800200200220020000000000220000000000A0240000000000000048009E6900120000120000002800000000001800000020820280828402002880022800200200220020D23C0818800180010000000000002004000068
+:80298000422001120000222082040020028082040028004828001425038001000000000000000000480000002002000020022220020022220000280080020028DF2C080000200200280080020000000000000000000000482002000000002800000000D0E10620080020010000120000000000000000008002000000188002200200002056
+:802A000002002200BF2F0E82802402000000002800000000218021812806002214000048002002000080020080048014029A0A20080000002812000000280048000080042002000000A014000000000022002842420014D05E01A01800800200008001000000008001182002008002002220021280022222220080022280022280F24B8E8F
+:802A8000202121A12220A33122200200A0230000004800008024812221A2122880828282A6222AA2622228282828420022220022224A0422AF150A000082180000000000000000000000000000220000000000000000000000007FCA0F9AA1113A03A0A2002A02001A0100A0222A024A04200118A0661A013A8302002AA222A022A0110088
+:802B00002AA222004A04282AA2222AA2226AA6662A02F04488A0115AA53348A0232AA2222A02001A0328002AA22240120229018AA8446AAE11A0331D21E012A2222AA2622AA262283AA3222A022A8282A26480A2222AA2222A026E622B22B022F28BC2A0111A0500882AA22200001A030000004A14021880086AA611A0112E2100A0222AB9
+:802B8000A6222AA2221A81022AA2222AA2224A06A0222AA222A0662AB222022A9291A0191AA5114282183AA32200001A0122000000212400884AA46E1A011AE1120211002AA2226A82A2332AA2222AA222A0224A0422A0222A022AA2222B22242AF2634A000082000000000000000000000000000000000000200200220000800200000033
+:802C0000FD6500120000000000000000000000000000200200222002800220020000002800800260122F250F481B21B01122B411324219B242B111B24299212B9413B14229F24291222F1429D212A9421CE922C4812E4216E12264192E4296C1429AC2521B292CB49142B291A2141B2923B481364219B24298212B84112B84222B84222BAA
+:802C8000842229A842882E42DFCB0B481B612A341162112B16112B1613B142B911B2423A112BA4222F1429F24291222F1439222D912E521CE922EC15682286C1529E213CE519E22235912CB49146B281A6141B292B141B282394212B8419B2429A212B84222B842229AA422B842392A22E42FB410082480000A200008002000014002100B3
+:802D000080080000140000000000000080020000280021F078420000223200208101120020141418A44200840000001A0218A0142001220000604400008880014088040028AF6307388A01814440341243089042E08104208105400C6830484008261204222200000080820122421008000000A22048018FAD0A1A220D83922400181812CD
+:802D8000002218004489412446024628812408209216B0112222052084022022012604102802000081422400224F46050000185024308440A241C048808481045048800281100820020000180000002084040082200100A22008F0DAE700100222602200400200000020420400004400210000280000000000000000004470480481F0CF70
+:802E00003E10044C0141184112494801008140581481458844082848810022414428492202108402810010088820011608842011280300F062FD100400281241204801000084511084140800000044002822800222000010080018608110081884200481F028E400244C0144C02218414002100800818428412022140841225042224100D9
+:802E800010044008000082000000004438C100F0EAA32481608180047014628441180080014442405424844143C12800840040048100410000490240444428031281802102001889F278ED10A84200414C010040042840082110184802821250488052828022010028000026084481400483028400890210480842BDDA401116042C010011
+:802F0000004002414800410000004221840084168822020000000000A081001800443018200241F0EDB8401112044D521860214618840121448905444484C41098844146588284872281818C012200284100104844441884116881901840C4381A02228141816FAB04214C92180044400400000010820440040028410000284B124008009A
+:802F80000080220200880012400810088180A142CF8F0900444124100280020046044B24444604524122400400608122000000120000448001841004124181508420819814E0C40500248001440000480085040041800124001004001002400200410081410000181018C81441608800818AF19B9E244184000040140884422084210442C0
+:80300000200400400C100484240044100200C412000000002812001888C18880F8B1B40043844102414400480081100420024100210043012200443024240044412120222202860426141804C02481C4008584028FF609C241004002222280040010A42141800180020044101C4404408211440400008441444088528444100810281808E4
+:8030800094BA0E00450A842D44890244442820C224000022400441800100101802000000101244080000841A42180800004048F41E970000301400430483028142001004410049021810044400224302100400401818A421800218A0282008202801C08470A901004006200289022688C2180020228202002644440800444922011004413E
+:8031000000250200853414C018811216C814411004441241006FDB092D1C8004441800418440048C828492482044041002491188080020621200848024121428020060488002008428C02C10023FEB0D18828721644B11651262448D2442814A5488474412422262F044141634244352444504442881C962422D2400246144442912BE28D9
+:8031800021E24293144C028E184CF114881E14C5781854CC4391881849781CC9885FA84D5242C145048116B42412742428A222814A41684445D444D244A22200803212504441414C61824321125464449014502444C4CD284508490883721848044C5984406C884D28812604AF430949C444105662428584028D2C4688228254842AB64857
+:80320000817444A4414128445088160844454846022A02234104244008448116048D18209218C7822002899A148F4168C8884B18A90E522011226824204418C448C048800448800440040000002821001004000041001288802881288128832842240BA285E4AA074F45F414148FE1C1548F85A419EF86B46484F248646AA6265A754CF489
+:80328000444466F47C5C4F46F264644F45E16131242212D04851440045F614144F42F22424241E1665544445F62626A558C8CFC2D28C52444F4AFA9C988D888E884FC8F98CACC5FC84848FC8DACCF22CA88F8AF828AC4F4AFA24A84F4A034741474C85BA12F5C8582B55E538248F8484D244F268283E74C5D44464428FC1F524244F427487
+:803300001464412302295188CFC858444C4844F434345F52F2242434AFA151464E4C45F62666A55888CF82F23C3845B424F2181C8F81E9CADAC47118FCB4BC4F4BFB84A4CD2C8F837B285A4E47482BB2F735F044544D4485CE16C7C14F65752E7C2484F248648FC6A6268F85774CF444444746CFC735644F46E445E1413126439214D04894
+:803380005844004F62F214164F52722444F2121E65D44454646F62125A48CFC2F22C2C4F41F124248FC17188F818B8CD1CCD1C8F8BEB4353488F4AF82C888F89DBCAE848F82C983DA4244F44B584F4181A2F65F14A5E6F69518E4F46F4684C8FC2F2486C8F86F25C78C3A4444F46F25C7C4B264B464F45E141F124244D264554888D8C459E
+:80340000748444F4242E6F63F322212A52216FE15146CD44B06252C885F4242CCFC3F314144F4AEA81F19818CF81FB849CCFC1F11C1C4F495944CF4AB83CF99CB8ED8CCFEAFA2C881EEA10040065024382044822000000C02412440040044450484120020021001042382410240886089244964864888504814004BE8B0000444200302832
+:8034800000848140044C02100422004008002244412800614441000016180400890144121800120040F17F75C0421F4152281F41724AF21124A3D441B24AD1C1B24AD981B64AF91548AB944F82F44A914B422F14F924482D914F82C4914FA2C4814FA264114FA2E419E2A2E559C24A9E24ACF491242CF491248D121F4932681F49B24AF15E
+:803500009124AB141D24AB961B21AB9453B14A3934AB9443B34279B498924F8B84F9A44ABFEF0725DA41C6421D2C27241FC1B242D1C1B246D181D242F9116C29FB156829F834482D914F82D412F924482D912F82D452F9245A1CF924CA1E814D4A8E218CE558D2B2E559D2A4F48128ACF591648F22F59124C3B691B24AF19124A3F611242C
+:80358000AF46F81124ABA453B14A3A14AB9443B142688925F49648A18E525F5206208804000000400400000000000080080000140084800400000000000000000021701E0C18218C0329410A80D248942283018021342400001024229228602144182A84028D3400182311C8148141580083820940282412084C4134888912F8D5FA008250
+:803600009084451264611E2881388C017048449C1C84416B14CC3448818904834416A442104824914C806423410030148C41C814848044984818828C88548481C04414F0841B00C2814532146548D48223C2444B1220D248341C4E1C4C12941443C442003248872A4142253418421383441C882304106441169858418149A241831218081B
+:80368000288184855424451868819F59042C012A8108901210E881126A8100008130428481848744902841A012004C0285A412422416941284188441800181828084A14889884424018A84027FAB0900002C0118100423220112404824018428412840441828028042025800100249A1610000000044800200424508D0CD022B1212615094
+:8037000012153424256C22411822124449A8148C824482714884C14C00293264448D42CC7144B8164248043214288922021A3238224238488182888C41648449921887421862F0BB5F242800242441504228412AA1121230845698241260814F846241430664814C66428061A44D128442804211124884211208802304888218C0484118A1
+:8037800045188406AF9F0E121861C011142E1481442121004C01108844020081002884608425CC24286041200128283268182A8122041008418443022281621608F0FA8F9029254404408592184042A1241212C14C813444C0282412901884202291684129018485C42258456881811A12141888247118A41210341C83688244864854841B
+:803800000028CDFAD0480189A121122212211840941128C12092228D12602464C44CA112491224B148321218283022214385A2124604892482882308448042882431841800248D844448DEA5244800108401471241444018822405004C01844028542281104494288446142402002838448321021088883482002848C01481281220F883D0
+:80388000B1F0443341812AC1144D1132E5211144C152B014944C2221562C6186444508482D286528E2A1F65824165C8246C42C43A242124C8231288F4461832E888903C0982C815884C9B418E2840A8644C4248608485FAF0D2190140028A0214110D28182418831144A022504A1128D14264804124120A22124508216BC2224312C1222F3
+:8039000044004A688180068021483414894118381444A2D7DA20A4284128200243C2148480810200430124800100008C11424248041A7262382480020040483484824028041884C0145A022800223FA101260425281118211122D4620248844E242D44412522324828004C24041072640242100212124C6481184289222204838212082A78
+:803980000880110400411218885F5A074362480021482D41000000844922145884201462441A0442404A982444904446280200281604008A12048228844284002281288A4104F04F842440420246244124912242422152800142218001103228248304006023504200304449C1284004A01441128381219884856488808858248C08F01C22
+:803A0000B8002222214E9211254272440884832404102404482C82228481241294422A1488046241184902490160C24200E28128888189214124C1841200908C41AB4D008120021628022002002301214120022011041818441812268804004243022002122E4C8305100843840200604242815220F2BBDB00400483025268248448128082
+:803A80000440386464A0144518481208004221252881430625480844188430248C818E08824420B944C8381024524830885F490E428684022933228531142846622140080040182285240123034210D4864624342448422001005084418309CC8422A8218B818200206812898CC811F0D35150A2C048166448CC9824481241402ED1C29280
+:803B0000122B412981B424012828A1818B34A14B850030148114C41A6486282A24614462224200C0348052488284844964840021F0E8B780748434282B214DC88FB291741AB228B16C162A14582A4C55261E54CF82F428422B5723A446CB14818B448F21247166F2244A25E4C314921483B31483C7442A62414FC372485C88123EA4874AF4
+:803B80008B828B984BDA478C1E8847488CC12CCE88148FC7BA8A6D91845D4F24288F289222442B351F4158694D466744258894582B714F84116644E7A44AB24682024FC1E1C1F422228C024E5C128F44B24884711498626D742E4643B214A2112A37483A22342C8E184B249A021E2881C74816F88484CB832E546EA84145C48149F84A2478
+:803C000070662652E42E1287622B2427172B161E62644E12278146CA4436A24150424C41A273005E48267246582E8D642371247A44E24666C7462A64448F8241140C49F42464CEFCCB448C4CE88332481A8991988384B114924482169814AAF2A34B00211004450324844048420812608124844008002144180090120080010018100420E1
+:803C80000100124400120085040044AF270B45D644F2282AAFA1F35A689F85765AA8166F66F746461A21F44A426F65F546666F64D54EA442AF27D12AD122F168788C51A88F84E4A4F51A5AEFE3F51E1EEFA2B224D6EC7476566665F65664457814D4CCC4488FC1D388F4A8E8CFCCFA84A4CF889A184EC8CF8DFD18B88D8C4F44F4B4BC4FDA
+:803D00004FFFA481488BDD8F89F9AEA8AF69024D244FC4F6282EAFA3F55A6C9FA7F71B2829F36672ED466F41B148E567F74A4E2F64F446566D4C4F82F67852A985F16A688D58AF827128F888CE2F21F522A6AFE5F52E28CD48DFF1F776766D258FE6B256F67478CFC3F224248FC7F7783C8D488F8AFBFC344F46F6A8AC8D888FC3F9D8D8C2
+:803D80008F88F9889C8FCCFCBCB8CFCEEF1AFE88CAEFCDF59C9C2AF3ABF1F034766F4246D6CEB14AF75B6DAF85E626F67E6ECF64F6585452AF25F256564F64E424F51E544F46F6727A2F22D68AB122D388F1687A2B444F44FC1C5AEFE3F53C1EEFE2F234768FD4F65E2CEFE5F6367E6F45F434744F41F33C3C8F82F43C3CCD4CCFC9FCD887
+:803E0000C88F8AFA88AC8F88F3C8E8CFC5F59898CD8CCFC4FC3C3C4F4FFFEC88AABCD2FD8898CF8ABBF74BE263F32A622F62F27E3EAF67F73B37BFF1F34676EFA7F76E62AF45F54812EFA5F75E5E2D466D52EFC1F52E6C2FA7F532628F83F13474CD5A8FA6742AFA4ECCEF21F5BA76CFE7F72C62EFE5F55E7D6F45F75F7C7E7A6F45F43CDD
+:803E800074CFC3A333CFC7F77C3C4E688FCCFBFCFC8FC6FEA8A88F8BFBDCF8CFCDFD949CCD1CCFC5F5B898CFCCFCECECAAFEC6548F88B924F291CFB02401002F2AC1484D1248472248A041241E482440C4486C22A1241244A0242094128F441232484B1283B42421B424012210C448418443A2482286089E48608844124C229828928524F4
+:803F000068EA200822841001281800004944848401420030488481840040C8241058A2009014128016A8418908202904409888844A084282608AD9012CF4112485F2112487241F41724AD341B24AD141B24A9921AB945781AB9443F34A9147822F147924D812F924481CFB244A1CF8244A16F1245A96E1A26459ACE549C24A1F49C2521F0E
+:803F80004952281F49B24CF19124A3F69124AB141F41B24AB911B24A19B54A3924AB944B422B94478329F92448984FA2B49B0C2D481F41D62EB411724CA221A7341D2C2B141FC1F242961D2C8BB45F81B24A3834AF347934E81439242D9169D412FB24581CF922CA8D854FA265192E5896D5B2E559C24A1FC9C2521F49C6421F49B24CF1EC
+:804000009124AB161749AB141F41F24A941F41B24A9B21AF443934A9B824B44A29D342F9264829E9A2F54DC200800400000040042800000000000088000040014008480000000000280000000014F0B5FC2012229114299428214484288905842C24A842464A1C1A0C8112812246046B142142224AC3128082632A8041481468418B21C18B
+:80408000288A230881424241428B42428044A2C980A41890828B824CA54289641149248802859414448082C4421A84044E2420C214830281248572847868925400364A24041A044CA41E2784C058418A7429A481848B29921AD2C16211428FEB0D48232461688BA4382A1438194B244D88282287641E246224C127842CE4212484B1380414
+:804100004B2C16F45C221088D223473E488384A3A42F81F21244461824C1148F42E547984E3A281F846482CA11E8812664244D2856A1418F940222122412C04C214C04A01410088841832402450884108402100248402869221E2400000083044028028190884D411084688B381440F24F53000020C22424400200004412290246018084A5
+:804180000200812A01411A0244001810223128A0120082808488849844004C88840181412F88044941629129321485B1142261428CC12283256141904216CC4826088C024C14FC8268C4628554228331482183341848202311249158644A3124422232831141B828185848848CE8C2042A1CF84547104412186241C12634122416C8228CE3
+:8042000024C1142400F0284110882452284618246441212381048C0448800120315822C0248A04428309814B288181449024A02444C7F720011621823221183024001200412CB52C31480028604444A2818362825084872310C41820C12212169428C0164A0120A2213041888C04418CE8849858308884B7D340C242002698142A94364C5B
+:8042800042C41493A6218C344418524508222446042A8592884112491214C2648428239148122E88281062442036284480120A44220050224E381698485B6F248B244885F112285012438164112885048C1204295242406824858282941C2534C42C9168A0122230448C483618256441200418424B1818441228D2001A3C288318C14288A6
+:80430000442AF866D4C0110010221218084602184200002C014148840042404804C01818211248800243014489322800208209818A0116A41219250810F42369242A1452812E1A83D214E34221C4352616282135444924B21244426862844C8634242F4462448C61C54982B322C142C48C3952181E241A182414142434B4228083B11A049A
+:804380008A215F48898994C2F816948C9F9C0E9C012502247048E2C10248181D6881842412444781802444088C048444230241814B124222442D42302C1A42028B168C22648100888281412083220184812AF417120012004822512942142294180090121082132852482422448608C64484418882E242844354224400234418481488127E
+:80440000024441A048169444302884182AF4F3160060614A0252A902284827824827818C7212140C424110024B4148A446C2C8248C410284AC414204382418224163468224A618422A2804898C4248180C4B388928F8DA552044884108444651628429012249022221212B12002A0142444841188A0200004440444214C46200400446CABC
+:804480002244908442841841A2124082F1C1C34004C014100142569428180028439418433444212A118404000018A042441008821844280028306A818504862484888402282001182508AFC5082B4842830210120C2822482961812921011240942280012B41248944026C126421494222C5220070181224112418088A0123089018448873
+:804500001A484408C2F0DC3D200148D0423241C022002822000000848554828123219224904C2024324412612622018C010043A44143014394284C2484044C2A3848304826042554487F33058444442B6142A0128C0142704802C4604410982220444404811602282508261888141824028512041082A2121A2274180400200366088843FA
+:8045800092224AF8E4BB1082215248222C028152122100242034444189058D5242004800842A24944243242321088012082810021841224C110420A4288002C012183FCF0A45188804444C01164418C41844A0212E482484322041841152242849B21498541088021C04C018638224220481526282504880E28104854404482C419862F005
+:80460000A61E242186C8346D1246944195D26CF338124C61842A86018D424D1245E266B27CA122AF247714447244E4846422CB44472983E266711464428D2449A42143514AE3D248C2642F47E446F4224645A876C9F142A8414A5C484F82973C8F85C94C6E4C47A18FCAB21C35C46F84014B458D14D088A6226F71F12461424F84B418B40B
+:8046800012F75212A9F21E1A2B1289B44284C128254AE884C1142942F616C425A2C66D668CD6A27614E2A77432F88686B024C22267A1668272166A882A648866DA28B482182418E8C4E84AB22818982812CAEA81FBC9474024753C624749A42627C127832D242F263228857814084F457252DC48B11E5442CB11474389B454E423B42C728C
+:8047000048E8C1C13C4E1830688D68184E362AC1361E1244185024818B358F44731CA4E92AE14447B444A58CAA14B44491B42A9914269A426E14004184404801450245020044842416480244004004008504810010180461302440420816180424406481004492008110F8AF7C242B114E1C4D1E6F63F71E1EF5BE5AF75864AF85F55A7C33
+:80478000CFA1D12AF32212EFA1D1827244FC1614CFC2F17E46ED1AA7A385FC54544F25548AEF6EF716426F25F612526F63F31A5AEFE3F332742F26F6BAB62F23E24252A8A5FE46443AF36E262F67B4EAEE4FF65C688F86B2F2BD94ADEC4B99CFCCFC3CA88F86F6CC854F48FAA4BC4F43FF76683793242B111E584F61F11634CFE1F31F3E8B
+:80480000BB75EFC7F75A482B76AD3EAD3AAD3EAFA151822167456F43F37E4EAFA2F37A58EFC4F414544F6654AAEFEEF75616EF62FD3252EF67F72E4EFFF7F75676AF76F6A2BE2D166E6EE4AFE2F446646F47F37E74EF46F4AAA48F4AF25864AF87B7F2BBD4FDC4C84F49F9BC9C4F8BBAFCF65C148AFABEBC3AFF34646346B252D544F53CAC
+:804880003EEF63F326245F33F37A7C8FE5F752322F45F7685C8FA6B61AF31C16AF8151ECEFC5F12416EFC7F51C1EAB63AFC4E544F54452EB62EF66FE165CCFA7B776F47466EF41F53C3F2F47F6726A6FCBEB23F226648FA1D3CEF254544F67F56E6E2F66F7FAF84F4FF7F87C8FA6B6D2FFC4C48BDDCB9DCFCEFC3CBC8F84FDEDEC4FCBFB77
+:80490000A6BC4F4BFFE4788B2F246F44D44CF1383EAFA37346F63737FFF3F33E3E2F27F76676AFA4F74A3AED12E761E7E125F65E1EAFA3F37E7AEFE3F33E7CCFC4F454544F66F46E6EEFE7FE561EEFEEF5764EEFE7F62666EFF7F77676FFE6F6B6966F63F32E666FE3F36E2E6F65F57616EFE7F77E7EEFCDFFAC6CDE72AFA7B752F744446C
+:80498000CFC5F5DCDC4FCDF5F4FCCFCFFF5C1CCFC9FBBCBC4FCDFF445CDD48800143024B1AB0248124A2414008004844488D24B0480246048B2460446044188B2400222002188081048C04860896088A049240182811084A2278DC088200A014133148842B141E482304181608482502188418120044202122010080C5242AE141921A44B7
+:804A000022108232649A42A248206844324A1884A24998A220F8FB26C0421F4152281F4132481F41724ED341F24A121D24AB9419B24A19F54A9243F34A9343F242914F82D412F924481CF9244A5CF8244A1E214FA264592E4A96C54A9E244D4A1F49D224FC9124E5F2912487241F49324A1FC8B24ED1C1F24A9219B24A19F54A9443B24A9D
+:804A800039242F447924989A4F8384F9244ADF5B0B4D421D68581FC132481E24C7341D24EF2491212F46D9C1B2489B214E964783AF3438242F14E982C4956F82C4916F82C5954DC88F11B2247C98A54296E192759891441FC9D2A4FC9164EB421F497248B291B248D181B24ED1C1F26A96118F449B252F446982AB94437B424498BA2F8317
+:804B000094882F22F5B9914008480000000000280000000000188008410040010080040000000080020000004001DF5A022011588158842111F0244A60818120C448A145222222794428932828225084001E4429220222103228188024E2482406284281A01C8744424B184828828A01F056251442330838893234907C3814560818428C81
+:804B80009824128B5218444122008582944230228B2C2212121E421228122CA128821A22842221781208C84460281220BA888434489611F4FC2460241F8441E882B448C21421130246764428B12881A468874625D8843132419666442AA12189B2C282D46808262837131A829518224AC1288A23A84248C81888E148E220C58423C58448B6
+:804C000068C6E2816C1947218FEB0E003011188C021E4C2AD1818241081008182A042260824008240028C84422408242022C012021C22462A012101884C84820816A8800005FD80D40240200000018800110140200302481482002848041440200221082022840048021088200202124432441048F6E0C49322188A9A3124832AF246122C9
+:804C800043459812C018907270423244669448524284A912622448668242288381911221221A622818452223087A08488064844DD2228A0488A847844286F8D895302426A52823818324023044248081014907426314045E24488C44224282C4222845C812120000188A02206148A0E112888034488E1228984218808114F815B300008954
+:804D00000280F14A122823C118124048022121A0248C0484248C024881481280021682312228230223C1262200004220084C044820CAA4461C24F8E2173048488C18688190484D2200651868812A042142274280642281490100AC01002504222184182A04604100108412048A862808880000A212F0B96F30284812416285012188284154
+:804D800080524A90382584C44870184204640028461402822084F822188A9242A082222A0118C0824B4818288C140484182A1414C444828CF8AA75C012284F12881144A21281839C1818002084185828124301006822424218812B24841694122004122129012026A2C1400800A01862888281888400A764A016283601CB43144A71288403
+:804E0000E42241088CD1840421CD428762584CE1814218E4648282B468A114A12A74826C612C052AC52212B0128AA3122A041E442AC84812C2814182890E2A5C4849B8682899888FA80524106CC140782A02A18418842420648B214881481084010010062100282C089828211004A021889082008A84280192001004D02801A0180040425D
+:804E800022810426025220E46102482582A414002880128214A23421108245082118218041280280242822011284221A2488288218F83ACA2024045200844200C028200420140800182442422004100242482120012082048004C8208204C82A084C04008001FF2107200800001216020024206181AC01802404002123240100100224305D
+:804F00004218008022042008800820048882820080F281494008482024814402B012066152A100201504305241000018800112800100124004808422880842004AA8140000001F730F481820180818004842008004208101001842200200184B4180034800208224822222A4422002188083088604888A82C8216F430A00004682542200B6
+:804F800040C24483446821E0847228449218121614322A48816229A412212848B012248315D8220121424242008400886A812804008004F06619000000888084850183014008C04222240021000080C44280214402100418200100808824142408402481041812823F23098482008258420018181A2441082400280021420042224C03805E
+:80500000240100243800C9C144180000102804420080028301F09BB6401888040012002724456842222D12B04882311242120021242C438209804202146024848004001004804404280012824800882192BE7420A4598085447242E225C152482E521A74186221218F21F368425AE122022440A266422F86B6622192422C2231422B44429E
+:805080001E4821A981B132839424484A84A46283A4A88AA4948AAC42D04488A88A822AC311AAFA265180240830C82B94582140B25AB22201585AD58224B12CA4112D1C29911452259C42241E624AE42391522E14582CE12185A3551606244156A4244442428822281A24A431CAAC58432D048AA888F05BB4008400A041168824B55211F494
+:80510000482A4B56A7848568422D1825BA42A4455A248145C222004901722F2424A121212724242816028B142AC5182A028AA848428314A412CAC8184A8205881E481283F163C600180080090024844048020024002004100200002100100241200222200222200200281200004A02286FAB069A21A411488FA4FC52122F2155222B144ADF
+:80518000F45E12AFA2F34A1487842F21F362222B364F46F62232A7A12F215144488FA2A6628FA2F422126F66F222222F26F63434242F2252228B224D462FA6F322222D12AFC2D244A1224F46A222F06C68706888F1D4F492EAFA14144F45ADAA8A7888A8BAD0ED0C1A41A811488F84E421B14235122B1129F162142B762B1623943A7E22B3
+:805200002B776F47B432D3AA91426F41A5118FA7E722F2A8DA2B124F666E216E624F63F251432E624E437E3A4F61B572E72392528FC6F644542AF664242A86FCECEC888FC4AADC4F4CAD88FA7A44F454D42ACA82AF89A8BB29B1A2075AA5511A018FA4F45252AFA5751ABA52E524F44A26AFA2B24A7348FA1A1A2F23F65A584FE6F7223276
+:80528000AFA5B41251461AF1283A2B428FA2FE12526F67F222222F23F346443CF472722F21F132681E426F62F722322F23F37E2C4F47A3274F46A2666AFAA8AC2AF248688AF99494FAABAE4D441AA1A28AF8EAE8AAABB29F1F06DAB518A111428FACF452D2AFA5751AFA52522F25F57A32AFA2F34A3AAFA1F12A122F23F67A7AEFE6B562FE
+:80530000735ABA42F144144AF5687A2726AFA7FC32526F6FF652522F27F776762F31F532723F24F572722D426F63F732322F27F37E6C4F43A3454F46A2666AFAE8EC6AF64C488AF9C4D4EAAABF4F44F454D46A8EF8FAE8BEB2AAFA65AA0000004800A04180041A048C0416081A0412422004420018421842184218008081941448A048205D
+:80538000084880041A048200003FAC051880012001122420021810A2414A022100002428A021002428002400122228224422200222004004A8008028884AF1878DC0521F41D228F111248B141F41B24AD141F64A121D24AB9419F24A9251AB9443F24A9743F2429147822D954F82C4914FA2C4856FA264114FA264192E4A96D5A2E449C256
+:805400004A1F49D222F4912487221F4932681F49326A1FC8B26AD141B26A9921AB9451AB9443B24A7BA4B8427B24B842F9344889FB244AAF630CACF511648D521D244AD14192181D648F24D141F242941D2C4EB25D28AB9443F2489722AF547B24E854F926488D952F22D558B926EC11E882E45D72246A192F9264592E4A17C96F82F491A0
+:80548000448B421F4932641F89326E1788AB161D24AF42D9C1B64AFB8528AB1443B2426A882D344D48ABB46782A9FAB4427DDC4028880400000000800200000000800188000040010080040000004004000000001002FEA3A0140081831488410884D0820152001A2424062604002200904240A2422D38415860220042284881412A6482BA
+:80550000200198800868284782200ABFC60C602800282024012981011884410010A814162814845422622A212123040068802461418C0118243248418A014812428084928C424A08144CF6675280648C21904881528C4142582416283248412025344812362614E4212432E238301242241B2428B048015244898124032391444CF43488F3
+:80558000A0421852A04822CC0A87268028F3C2A680014028020020810118120000284881000000184A024032184B42808492120020C42880028001880020A4424C082849F436A100001068C1000018112180018504424130248004240000206241804242040080C14883042A01000028222093982280F4E87E0021188901408822210480E2
+:80560000014880E4842281928870150829C2641A3468222A242121228421818202683210242102002084C4884984049048868872220610028160810012001002421004008908168934222E428084A242803224007022840228121285240528002084E4821884246381628C28B4C505004A2111481488024218452121820189C468524C02C1
+:8056800026440412411AC4280018181248898301482084024881281200220020068018082AF1A16820224204E084A224444A02840090442006404808A028001048C848008001480000008C0418860818882008184220014283F835F600200180211102220000200149420840548483240248002812001084A12122808281023028304842A8
+:805700001841302420022AA42480F6DB28004002120000420000181044C11400180000224180110832002280012002008002004008288C5148002A01DFEF012822160212468815A4242200004118625962810012100800001E688C012A81011AA2213800320060828A0252124184222AC118411AA4241A94682F8E0C0041001A62220048AF
+:805780008100A01440044484814185A44A28A02445180800004448002002228C0412818C04822048044A42880228827A0222000028000042004800834408004880040000200180012212000018800100810080082088821408DFFD0D1260410010048C32280052000010042800224122C9121484442824810200208111088002A081908864
+:80580000004212481A1488220CAF710C12305400284110480841182A0410084120022032145048444148890112228120812401810028001038A8008218425A08908818BFA80C8D288B444A2404008082D24454444B622A22024881002442A0151A212B020090418051888D288B444A24240112200141982AA22222200400872268481AE10F
+:80588000B10F000000200200008400000000000020020000000000000000000080240442480000BFE20A818CA4144800000044414C228202830418485022901216C4B48288003814111484818C24840400280044414C22C228100800502290127FFC0B84800440040000448428424810080010021880180400400140081A240120014200F8
+:805900004480020000001002BFD304A054002001005044A0221008000000B0140100104408420085084A0500180000002A42080081122008A0118FEC0D008001441800000000002004000020820200000000000000000010084800002008005FA40A188B444142221200004514B82482242234488480042445A211281282824484221011B9
+:805980005188B04884212402000010B424022200000024241AF18994405888484A04000000444584E28282010000109212181E14A8A80000141440D88885A44480012200404C84A2220000001012B25B0900000020020010080000000010041048840400002001800180010000002025C488180000F0E6F3001212002001000040880400DF
+:805A00000000004400002800000000000000000048000042480000BF4F0C000020A11100008110084840288404100441436282444C44A822000012A01100181228480000460818C08842A08800F06B542081A11100440000008442813048810000504426848202418120040000800112000000816084428C0418480000BF47072041248131
+:805A80009214A022000081844E484AC148202104000044B0240222180000A0112081021822001008004842811A240400F0F94D7026B212A2122B111229012C5122881E1317118B98967948F888414E48421D4911489518F8444887444F42B444E24222C224805244412A7226B212A2122B111AB882092C5922881E1317118B9896F94888D1
+:805B00008B484E48428C04488518E884F479B1F0262245A21232122118182592821CB11191819E8883D118246484941D4148848588F44844C14B246226448482425444282F2242A212321A38828A81512229C8111B1119E88938188B48C2464888844458884877F600000000000000000000000000000000000000000000000000000000C4
+:805B80000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000047
+:805C000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000C6
+:805C8000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000046
+:805D00000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000C5
+:805D800000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000045
+:805E0000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000C4
+:805E80000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000044
+:805F000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000C3
+:805F8000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000043
+:806000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000C2
+:8060800000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000042
+:80610000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000C1
+:806180000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000041
+:8062000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFEC0
+:80628000000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F08D
+:806300004FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000000000000000000000AF
+:8063800000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000000000000000003F
+:80640000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000000000BE
+:806480000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000003E
+:8065000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000BD
+:80658000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000003D
+:806600000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000BC
+:8066800000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000003C
+:80670000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000BB
+:806780000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000003B
+:8068000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000BA
+:80688000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000003A
+:806900000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000B9
+:8069800000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000039
+:806A0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40FB8
+:806A80000000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FF2B
+:806B0000E40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000000000000000000B6
+:806B800000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0084004588842121A24220E14201444C064800892221210140048981A124831428142804C048180000008222000080A249280092EF8B0C2AA41416984842C14F82F424484644C4242284442A443824C9F328141AA6410081441AA2121C
+:806C000018406881324226280456688130488994684E2862722A8112084A628622728321A2818CA91C846FAF09A0411008444902A04241128130448422412004124008222011081A0200001E4890484281842280210100628400200283893418AF9409228001C4481843251424021A0220048C45889278004084E142011884488B243028D7
+:806C8000420016081800202402A88902208422C518C80092D0D70148810000428100801244248212848201001800000000400880040020A442482842000000208222210980F8236A00108884444828C224000000440049220100180000801128212414080010084008200200800200800200EFC90100000000000000000000000000000077
+:806D00000000000000000000000000000000F04FFE0024842021040028181AA214418441422E1418C4200200804124C14820041A8402248C22C3486848281220E48208908420240280282221F29A42001240B448828212241122048181422244001822460841814022A2422094221800004400848400A01818892514884248988430148C74
+:806D80000548CFDE0C008430784A220218284A218355484243024C83C11C288C0600C012A0258C44228601280025A8218C8496482818A0948C2B04C928122882084B188C22A142FF9409201142040044240010088160440000004181004302200480050043024008000090184800428444001A04708C05400428004128421008810000840D
+:806E000081222800478240280428481224822011A42149280116048C060048888C04004302484A0100AF850869818293121813022001881C0200D08421A2844883344445088984421898442848212A110C7214222880A6128092284A2182018488478212C122A0244B82687EEB402422B22201002800834841080016C4288A044842814445
+:806E800080821468442848241281122644010042128400428019480845088442422228F07D819012441220C12144A0140022000084102836284444833248848420228411A28241A0141AC2A41A021E24224A823228186280048822431384222134844AF211253028288B1200000042440010484C0845084044048743222281C048418381DC
+:806F0000A1214981842103CC02482024A618C014C38804438202224921A141F0FE2890184880012884126688C2448B4100002A6141C024248C828202812004430280022281304428428002004490284200C800160482004D750021902848844122008428100C00006082200142442001100884000010088181000081423018A84034242094
+:806F8000584820F4D223602322123628C428C1128C04893438400C818CC214C02428224B2180C624B01804C952841289218302184B1226C848C0282024864828C44480224C044902C98104ADCB003028000028226880041018840185048145082A51488428004840880216840400434228040018901886B84821C824224C22C1948218485C
+:807000004F1D07400428604228844C420442004004200441C145881428110841100400004810440880024A420880014C028D3418440022289B9D2004281810082800004280042002002200188C22440800490420040028124849048001206488C41880A848928200F0FDA38003506281814604201488020028414200008002000081402834
+:80708000828424144408442881411A94144228C382E14401891D88020012985BCC001A024064248181448004101418881404C40041811044A84248480048892112848281A1524441100C00100420029028A04A82425FE70A4126682282002242102432480080020042421008284180C224814A026084200484448022840442188480248418
+:8071000001D8C0584280029F250D108401892102A04240084840848402855448004A0284C0444008814D484480628220026084223028842282400C8C2205008A2224088F960924101424024200200444424014188802444508892424250200008122004034280081411230484C0660814C1444F4C81444412848285BFAA0212081826264BD
+:80718000814A02282828004181224932288022222222922822812E48282302284C524880221248182482228402C048008C04628C22820420F4841C408C91445662410000004490248904409844688148290458908443044084D21804E082014C84C1640080628828460C4A02824782102434343012F04694702484A3312A72141498288BD5
+:80720000622684A2248B2248C0448782288145B42CD444B22412EC82A642C32136644D28F0244442859848A0362A3414C7435E482AB624C2244AA217684840D484F17414CCE442F314244FC2E6460180F27C45C022C1E04181526427C2424922E482A4444142414B242AF4442483648481C0648146C8284D4889D64844424868465E284C07
+:807280008414A4228CB128224438648B4349A4124E28CB2449514889B4F8E289AC548A81AA823AAB929D15A015367424D626F42A186E684A4428544481205444878444C126E8824684D4C864864289E242D5484228766888F22C446843B268428452C8284D14C5F44844C01C8F887248B828C8488F8DA4458E2849314C8F8A38584B484A5E
+:80730000A6484AF4186F0000002410040000004484008100001008850400102401120040088440A88212888008288400208102F0F1DBF044666D1C4D266F617548FC2C4EAF84B268A2644F4434448F844254444554444F44F44464CFC4726CF82828CFC4F4244C1A24A2748D688F86B448F4686A6F46A6444F82F22C6C4B364A43B834F3E7
+:807380003464CFC5F5484CCFC6F64C6CCFC3F7BC2C878F8F82F2C8CCCFCCF4842C4F4DF9C8B44F45FE5494CDAC4D346AA611BAF85922F024266FC4D664F23666EFC6746CF64A488D284B644F42E244A4226E644F44F44C6CCD2C814F42F24C68C7C2CFE6F66E68CFC2B67225A2BE8D688F823C6C87A66F46F641417AF37C7DCF86D744F159
+:8074000074744F42F23C24C7C54742C5FC4C4CCF47F7FC24CFCFF2A8A88FCA7E84748CFCBC944F4BFB44644FCEDCCC7A44B662A6BB2B66FF170E4F64F736546CF23636EFE5F12E6EEFC4F26C2C4B644F44E446A2244A56444F84F46444CF44F64C64CF46726CF82C2CEF46F62C4C6A25B248FE2864CFC6F64C64CFE6F666648D2DCFC5F769
+:807480007C7C4F86F654644F42F41C344F41F25C4CCFC4E446F63C3C7E388F87EBC7F3A8A84E68CFC4FC14D44F45FF54B44F44BE44FE2CBC4BFA2BFF7AA59ACF25044F66F72A644D266F67F27E7EEFE6F26A688D284B644F42A2662AB2445644CFC6F42C2CCF44F66C64CFC67624FC6C6CEF46F62C6E4AA7227AFA6868CFCEF66864CF6695
+:80750000F46E6CCFD4F64464DFC676247814F43474CD24CF43F27C4CC7C245F41C1CCFC7F37C8C8FC7F72828CF8CFE5C88CFC1FC3CFC4F47FF4464CFCEFE2CBC4F4CBDF2EF2FADEE3F53092A012A01618C04844382244208484484284881200442A0246044B04812B448024243223424100441001064882286089E48449E48A041280080E3
+:8075800022F827F1100440848112820200004190442042044CE2821408812281202442848462820044418C32482822CC1484220483044443912841424382A848C0419FF9042CF4112485F2112487241F41324A1D6CAB141D24AB9419B64A19B54A3924AF547924F84A914F82D412F924481CF9244A8D814FA27418F1244A96E1A26459AC36
+:80760000E449C24A1F49C2421F4952281F4932481FC9324A1FC8B26AD1C1B24A9921AB9451AB9443B24A7BA4B842793498924F8284FB244A2D5FC04A1F41D62AF4112487241F4112D481B64AD141D24AD941B64A9B25AB94222F547924D81AB924D412F926482D954FA2D518F824C28F11E82264592E4896D5B2E418C24A1FC8C24A1F4826
+:80768000D628F491244AF1912C23F4912C23F2114CAF449921AF449B25AB94412BB4478AAB14478329F8164829FA245A9FEC0284444800000000002800000000001880080000140000480000000044000000000021F06635002444100400488142800414228D442240148402490249024822832212822205005024004784A0428085220401
+:807700004E844C4248A4412624B8448182F282230040884192148D212E444588020010085041E084C1284141462802842290448044042C22040048808862819028901844004230288426B828781811F4752D0042A1486041990290284304224021D2844405502C2614248332A4846228262C32432604898224046442202882034F8582B2E8
+:8077800028044B844902443028872287472E1816F45A1C0010245124004C364C002004810022F0144828004D4800008004005810020000C30483040018410083048B3441888220F29D67009016282E129014100881004004546044C02441004048A45228430222003024282112004160244862A08420040028402482029F540BA0122810D0
+:8078000084023034222092582901498112C228C18400602442388141219014184901232101244322C22842902818460848806482818B48226288C1F0B92600F022149034221604C3221228D2280144445722E0844248080048278444464804C01412494142A412006922120C488100822084942881C820844A08AF5A0B80032824008001C1
+:8078800000481220011044C424410000322A6122430222008003211200224890626AC14842480000898262423024F01D89B048816482122002413845489438282314943A20114474120241182684C21284A9111402181624220142281E4449214204402484220428478C102C42414484F6EAB850484304414C080021424C218403120049A9
+:807900000442A4C4381884402812042800101488E144011008188C414404293284C19822C458C0422800AFEE0FC0222022C81422220000400410048032641800400441801344242222018A0280029048828381822208000088811998188449F82BE860414D22008023922460848023C1444436084A0166B422658141C0242604C14D184C86
+:807980003126442A213334A02818201124925892438162248249588422E658844B8428824B214149F886F1800483E241124404B0224184C14824C012401444048514840381301827222002004180211184326416084481848002482049048941284418A842BD6A008280210180040028200110042249022141220044466244000000284331
+:807A000002002C92242200C82800201A480C80088142EF2C0218812428C024426045001222442741229012200143222301E02221C31226220180012001122818128004002200001014448282083F7206200C400400004092142002183821800100201202002064412001C02228001A44842202420020088168220042F04C55E0A2614240C3
+:807A80000412444E244084040010043024004012A412414812484200282289020000000010048002802902840060822F9E050030445248004248800424802482020041222200402412044004282248200622430220CE8800004400608C88828814CEFA0020028A4204262403842A418201122100282604009024440090242A11224184012C
+:807B0000480000000081414420212802200422F044A6000000181A0200220030449014102201C014414022024381114284011800122002000042004880820300222800AFCB06308422C0842E824A0180A2210044809228440028280000522880818304001863811304418004424028046880022082828422F4AA86408882848382D484924A
+:807B80001820018D44498122C154101814C4141821C034128848212A4432241C8202842248182001224A0260468023A14145082210481822F2263D00822A42E44A91B4EF410148122A2282024C11F424344311B224912422499114266442416E124F4764652A43624118CC227264A422292142F62434802282B428044304B0284A84A22439
+:807C00008225C82148F77920F1A66C90245A62444843A7244B24E024C11418E045148A8242E4426141282E2480A2531A0222446B432A2223A2211218168422034B42A0848A4828044AA1819281F0288C898EBE28B828F2826A8003B07211A4436AC26C4B1190581E6843711636762A63212E1A47421A2291263606284D122F44924629916A
+:807C80007223E1449214281AC11238126A02381A84A2466887444A922412284B7ACCE182E2420422228A24F4441D00001882800400120000004412000000004400000000220000200200000000000000F0C8DD2078440C4F41A1644F67FE1A4889E746E744D58C1268424F61F156344F64721AD48893124F41F314164322F1162445D46472
+:807D000091244E461AF534361E124F655546701464216FC682F134742847415E146E24A0ACCF8EFA282826F444545AE34AF5BC9CC782419F8AB8E8FCE8C8AE882781AF29063AD2C4044F41A3E54F67F37A6C8B146E742E348D4C8B731E344F61F156144D66EF41D188F326144F41723434264F43F2242447424F68DB44E226AE514F67F31B
+:807D800014165F74F636241E21CFC3E321F32674184F41034F43F354344F46A222428FCEEA86A6644D145AE14BF7BC9CC5B844F468688F28F86A48EEC82E38AD3150444F4256444F43A3544F65FE5A488B744F47F744548FC4B74884F214144F456127E7618FE3F316144F41C3346B221AF1241426D464F8266465B626F716762B554F75B2
+:807E0000554670147C24F626641AF134341AF314144F47F564644AA4A88FCE5E88284F44A5153ED4CFC3F92C24CFC4F4C8C98BCCAF8EFEA8888F84F5246AF0A424CF427224F414147E744F65F37A788B364F47F764748F86B378D324F1121667454F63F71E368FE2F326144F41F224244B224F43732464424F63FA26746F6EF636746F67BB
+:807E8000F756544F751536114FC1F124266F43A3334F41A3334F43F374744F46A666EAFEE8E8844AD444A115BEF4CFCB5BCCCFC4F4E8E88BAAAF8EFEE8E88F84F463FC00200249012AA1410020011200288002208102004604428002002002222002222002228400A04828800228A024F0F2810028220028414C04282248004449440430E5
+:807F0000340000442212221222444112000000001844000042004B48880010C84800DF4E032CF41124A5F21124AB141F41324A1D64AB141F41F24A9219B24A19B54A3934AF1439242F547924D812F924485CF9244A1CF8244A16F1244A96E1A26459ACE449C24A1F49E222F591248D121F49724AF29124A3F68124AB141D24AB9419B24A85
+:807F800019B54A3924AB9443B2427924D842F92448984FA2F4DADCD0A4F51164ED421F41F24A121F4116DAC1B66EF11144AF64D8C1F24AB259F2489243F34A8336E8547824D812F922482D954FA2C5B14F82EC11F8224896F52248C6F5221B96F5264A17C84FA2B591D62EF58124EF24F181248B121F48B64AF18164AF44D941B64ABB159F
+:80800000F24A9443B3426882AD944F8AF44294678AA9D9A4F521B7402808000000004480020020010000188008000014008480040000200800000000004001AF6F0F4132411810A42180220490485220024C2422010046428402280068214C228402004004184481002024A494C80089185C480046F8BC3E2027284284A461824382084217
+:80808000002001008082C2244100484046242481020020430200802224822802880030242222C24214F033BFE045224D24012288202834446046421800208243624241522182606280241691243028A01600410044832412242206D24A0828C0242C04141AF4DB2C00282244421E442AC124220010280122904400280040A4420044203103
+:808100002280040024008081028008A048001094A8848D844840F8761A002008880080080000000000000000000000000000000000000000110010011400775EA024231245A412894223544245A8312AC48182608169A1482A0874188F810248C2748588A245843398484D146A820871442A91684E83104298242AD418294808619AA5823E
+:80818000186487812849F89ED350224A1241A412C942251446AA22483C0129688149B181A4821485E68181A288444944034E211E4811235888184E442D822811442A912C5C281444B822A3413C281842B814A1482A884136188C025F5201008280080088000000000000000000000000000000000000000010010011400170E705210000A9
+:80820000A01268C50218480044484C010020820244222822442004200200006302224880240400802424088E482088085F580E4C024426721C622100E08284060020014A82024024C444222024E124324422262414241406642820440428888A2205100480F4448880266684F0CE3F7022044428A991121842414AA21600004841282200D1
+:808280004122414C228282612444422842441004444024140480280A00802424F84488898C824C085F760F000041242828854208480044181248002022240480249224482241802214022422290228422848425200410048004822C8F0424E30482AA421814004211222108C120A22400200290200222200002823216422120000100400E7
+:808300008C188402001008841288A082DFD2048D2648802244E84402284604498213042021040021414C010022009041441064244C6622004A81020010044312A482C241000084705C0950242001002A01008200481823042222000000400216044480220400284800282614040088008001424048046F5A01472426A6212E1842C14A025D
+:808380006042302812E148181A44022880020022800200414168224A1182922242582222444186081044848A5C48C0481281C4A85F140E22000050241AA21248200800222148280040140480420249012E42126044214C02001004220000820020010082004FC603410050842249012190222800000022004180820290264200200443022D
+:808400000000442822124C04C8624848208226A125424C08183B6A20024C122404222848430244428094414222421122193421614044D42194218084020022C0220000482822880041884B848880082A084688B4E40A4A22022902442800800465420200842022242282014823044323140428428082228282868224810668288004800448
+:80848000484934188A1404BDB900100490184C14140440148802482100100121111122172120842242624400140044206412004081388400220028002008EF9C088212A042E024112803490100428061424A11840200490210A22420024100004841000010040080B884221404182021246C124FD146022100200A8001182084430458A0B9
+:8085000016009042484C924413011211442A44044C4444844434144C4224844464484448411443A282488443C1C44110F49E77002688020042468882042002000014466142114410411114044814000000000040046A086811008024282C2802007FFF0F424042040018441842229012298563828D320020040022281230141A32112264D3
+:80858000C04400285200220048200848004C8282020048BD317012081A4482049044624A0244418C2202000013942671114C11810C15040020844228C241122621644440012244800200000010025F120B4F22A4294CF222244638444A3428C042204236426815A2268C011B224326025D554CC22713D4421684C4252AD242064534242641
+:80860000A4224F4262426E244CC43436C52411EA38414744424B244B68223AB874A44443D81498144FEE4EB242121824143238CD241AD744F334144A857244A811413A94188B234E3146014E415F52A422111B421AB7647153A51212486245A242204434125E5148114890C422484BA8C84848224AEC8485B834AB44C262BFB40818222E88
+:8086800012414984B3227144A6464A2242A242A42B144A9144426B42D031D6458212722431446517A1724F1432641D14414A84D24186420128414B26624A26B6C48E82045B8AA6A48449A2284C63884C9848484FF306442200002002000010445184144100000000000020021001111001111001111001000084400884F0162CF044726FD9
+:808700008583F322262F44E462B356F678684B555AB45425E2E6F4564C6F45E715F6755557712B551F16F625271F14E614F667651F16C4331F77B563F731151F56F371613A056E263F14F441411F5232213E514E711F14E644E656C24115B1C4FA81211F5E2CF481C12AAE6E4F46A2DD8F8BFAD888878C8E88CF83F26548246F26F7367895
+:8087800049F32666AFC4F4283EA7854B557E747AE74525E2E4F6525A2B554F57F57151DFF3F376745F56F661613D611D215F57F761611F38FA37133BF65F13F761757AB631D744F46167A5F844641FD4F625243E314F557141F141614F57E317F565251F5CAC6A8A5E55CAFC64C4EAF464248F8FFFB8A84F6F7E86E48CF86E28CF570D6C80
+:80880000F312742CF32226EFC2F27C7E2F44F678683AB354E64383F24862A7212B551B658F93F17C4E7F57F721215F52F243611F14F465751F16F661E73F31F532743AF331755F57F634552AE262F6666C4AD64146F134341B544F42D251E245F17534AA7A41A5A64AAE8C5F54A4224F48FCB4948F85F574449A9882CDC44F86F7A8FC24EB
+:808880002D36AF41D124F34626EFC6F63C3EAF86E647A7715E343A83F24C42AF25F516541B574FD7E5A3F173715F56B421D655D615F265745F16F665E33F31B1F6A7371F55F774644F53F764241F66F6262C5F54F4296445F534345F47F725254AF674345F45F52565CAAAAC1F1C7C45F5C4C44F42F2E4E44F47A1BFCFCFF8ECEC6F4CFC30
+:808900008CC64F86F6233AB024012A01238214048004400244484C82C42411446044114E242014C224114A22022242002220822482048220088A048A84A24889A2418B248283047F9809A228242862B028811604220084004A02302130254C02302510C424A021000000000000004A0888822088220812188048F165ABE022F41124C5F27B
+:80898000112483F41124A7261D24AF24D141F24A9219B24A19F54A9253F24A9157822F147924D812F924481CF9244A1CF8244A16F1244A96F1224A96E5A2E449D2A2F491243CF4912485F39124A7141F49724AF18124AF14D141F24A9119F24A9151AF143924AB9443B242792498924F8284F9244AAFBA0727A21F41D62EB411724CF2113E
+:808A00002C87261F4172687211D468D841B648BB15F64A8253E3247835A8844F82F4429167822D914FA2C5914FA2CC815F8225FC261A96F1244BD651869E286FB2A469CD438AF24E119A724EA129EF1281F66A954CF24AB128AF5429F24A9443F34294A6D842F922482D94AE5A3F9B088480040000420044000000000000188008800140FF
+:808A8000014008480000000044000000000021F0BF5410922425C834C32421322220820100420000138202004002C014809224224F2401A021412694644449441444048001004449C28422414C62434974F304462258240090121044042A2401812001A312042A64412E44C0244226263224182444A0612A14020084601242488222C89065
+:808B0000C441880046088CC481F0FFBF80346681C0441622932240142462433048200184282C2222E141024338426C922426A4121D26281889C4624A4184E24442C8441C42141424A21E00414004842449A41A43F568B9100265E241120800412818480000002912054844482002200100444D421A02284004444024848408004E84C084B5
+:808B8000224CA84244264804CFDF08200128004014A42100002042240100120010010018003024000012188400424800428220024881120081F01D6A00434206491684A2123880A61242189016222822148C766811080028F021146C7624280152681228224448281922828282044008C084A041412684944442FF55078041064C44044C34
+:808C0000818223842284016B1244384011F8284100400120A225278212905448200220813221A02448004200224908C0148024045B68004902282820823214208201002002282086110800226051444100222818206241488420022242008608004289054302C4485F7C0D814382024220A41280912218281142003800902218485648042C
+:808C8000324148142021224722A324184C04688184448924044C04C918040042443822BD3E10824494242002C02446044384312820628510982800412D241220850420D1410210880142258422418831418182412888202201824460844812CFC30324002052422800002810020045220190180000918126381821814004001301840028B9
+:808D00000040010012100422180048DF834A028092242822686042642818102824C2586C018C028983018C048B412E182250128118443220012564C6188C86415884481420043A48442498244A11A86170FF0D86C22441602444A021A04180C61211002092180040B4240441144885C45812430222422C81E2122101008C6214908848300A
+:808D800084508418000049042AF48DE124282A010028180020810600301400284004104408302C00200211C018122220426442144848620000448084120CC1F0B72E40022C0228446042263424C0140024382228221880C3240041182840081218000011184C122404461404440011001200202424F5E9B520088002180000221818001876
+:808E000021800200180000302C2081020000121084011004000000004C011004F059FC000000C0241812182014848201806181606320624120111424011004432101C04520011214A024304141110000C0440040F4AE7300168242222201444C0248002141A02100001840041400182023810214800528C02C4889028D24280010842118EF
+:808E80001828024440F14357404428014480041222182082020040A42100A4000022000012004081260100200210018C420100004C268404DF1E03252242026042200200284002002211800141400414471111490100000040110141111508408802001200001004CF3908200822004442000012128002124220021800414508800200006D
+:808F00000080041828412220041411000048800490449B4340488264244328880210244204282A011081618430243184181588D9810181114001124D18800485018180048942148802100830440021149FE10A218728122CA22A1841184391145AA254006301282A01263824674226494C54894CF1141C8D1426081260411F111124812120
+:808F800031184F41F11C44D01956488189145C18008D9430444144484D454F44F4667C4024CB2222414F414884E6420122223012282CA213125A228183C214184114412E2149524832441A0280A1141438174289024D24444B6428142601511810688166A442463448F0276C2426923223924225A4226A732484E24282A1214B13C0123AC9
+:809000004194214F928127A1114F21120447418711113629C111382A010015F811241B4245212276293164226A3461104101208184364C4180F178FE4004442200480080040041244301518100000011004440044440C4114414004814488004004110041E4814844008FF1B0E2CF236344F61F326644CF23434584D241E344D243AA36786
+:809080003654642F21F134264B215F51F175558F87F3343636F41D19418558448F81F1111D1F1151C45F52A3324F4353445F51515145FC34355F53F321218F83A3228FC6F6292885A8669F925641D5CD21449E948781C7C14B222E28C5187854F89ADBD066F276744F63D34616F434342AF714344D241E344F42A2331E3665F616164D1646
+:809100004B111F13F371514F47A3326743DFD1D1CC51C85F58F818195FC3FB1C118F82F211115F53F324241E119F9151514FC1B531A2228F83F3282CCF83F36C6C1F1252C8CFC6F269299FC252DD55E541F1989CC7C112DFC2E2E6F64E4C85F4461C8BC4F024266F4367222B2245E443A3554F42B214D144E247A7761A7314D646B136F304
+:8091800032343E311B448F87F334346D34DD3D495188DD8D8F91F1311D1F12E281F1313147513A03179149F111551E113AD344F23C3C4AF6292CDD2CC5EC44D699D611529955054B998D184D144B2289944E8C94544F1C022F22F232723E32272645B434E345F524244F43B124E245A3364F217112921269F112142E315F45F45C3C3AE305
+:8092000043F33D39C55CC8DD8DCD195FCBF13C31CFC2F211113E214F435345179149F119155F43F23534CD2DCFC3F34C68DFD2F26525C5FC686C9F96D69D52DD15A111CF89D9CCF148184F42F22824EF44E4E4F44444DF740B430223022302411222122212002041044480220100408481921428490149014901189014800143024048012F
+:8092800014001008830481F091C420880244412800181604281812642218802141343489014018081220018021011260418190181934482004814004852441840400F05376D022F4112487221F4132481F41324A1D64AB141D24AB9419B64A19F54A9243F34A9143F24A9147822D914F82C4914FA2C4854FA264114FA27498E5A26459AC56
+:80930000E449C24A1F49C2421F49D228F1912483F49124E3F48164AF14D141B64A9961AB9451AB9443B24A39342B944F82D442F924484CF9244A4F370F2FA2D441F62852174183D641B22AD141B64AD141D24AD941F64AB259F24A9243F348915392BA4B422D917F8294922E5A5CF925CA1AF8214A87491F2264492E4B96C54A9E2CBCE475
+:8093800048F628539674687191346E8AD41AD141F66A941D44ABB459B24A39B4AB144393828CD442FB22482F44E9A2354E008004000000400400000000000080080000004008000000004004280000000025017F3602962202414981022AD48421321200184212160481445CC16480022230284D21D04201908841808201261104004008C8
+:80940000120042009028288482F0FB810086240800980041808201001128608240A841844141001A04004C042084110480011400004241400493024442881483E2650412660448412892624126341428262481844101847015528458324443088149034C1141C4888160854301001001100C2E544120042830242E424061837FB50F2420D9
+:80948000488401008901218001004C21024782A0424008222062142400424084840260121604000000004150814008868808DF7F0E00400412800200800100000000000020020080020011000000004200480000000080C42800288002490244200200800820820412002E4C2822008004488024211402008094241A0488280088418828B8
+:809500001244203284445F5A020040044B21604200001820088022041800C3022820024200280010030080442404C200004480821104604841A80022800200002200000000000080240200008004421242000000281800222024088800002820F4A3230000000080010000001200008002840050482A04288100002800000000000082805A
+:8095800004008200DF594D828282420816081008000000002024814208411054480010840100004084010042000041100400408424F2314A0000000018008400401102000014800200000000000012410018002800000000400400F0A6DC80024008890140088400002100202401262812045048A0242082010080018021012002001024E8
+:809600001884044400003F6D0721282200001218000040011800001302100844504800418100002244410000480000000000308442223C0D0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F80040000004004280000002B
+:80968000002180018800004001400848000000004480020000001002183F5F0B0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000006A
+:80970000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE008B
+:809780000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000100400000000280000000000000000000000480000000000000000C4
+:809800008F6E0E00000040080000000000001004000000220000400240040020080000200A200400F0815B0041188011280200110000000010048400400848400200000020028004001200800840084220047E2A004400004008000000000000100400000000000024004C02200482000020A882000000F0EF8D0080011884220040010084
+:8098800000000044100800812004282100000000000000120000008148422004EF620500000018008400002002803214000010140800800400181A1284220280046800000000282A0410089F570DA02180A2418C01224160812200000044284C82246182260441604622130443644212002200224A820200A048000026A84188898804487F
+:809900001BAB000080842101000000200210042800220084208602424822002A21220280840248008200002228C2811008830DA012808241082244818321020000809234444212814C12440444601440148481014480828282042800480000814A2182280442AEB80042001008188400800248004180024420241204220011134404A042FD
+:809980002004280000228AA42444624818420080240CF01924004344082244002005C18B210000120000001200000011202212880400000000C024200100000020F15AF8800100008400418428000048000040058082040040044004001800222848120000000032220084F0B49280018180124408844345688212800448188002501442B3
+:809A0000284C2204001142004C2202800120222224810420240148808102C884F05531004400400812000081000041001004000022001044240248002002008082880620240180024200F0C6E8000018100C000000812014040000000000801404450800280042000020049048000030480022F051AB0022104804208212080028280010A0
+:809A80001C011018011018A424281005404141014A1291412004141C02C011848400000020F4FCAB0000001841412A0449820280040000100441000040040000000000000000484200488100004822AFE50B00204204001828002228B0451225021008486880044828004262814848804408224218428C05220080428822260228006F1DF6
+:809B00000B8248608440C828815618088484812200000000800442100480440480040040210452301438168421812121014A2121011CF4BC552021A14100001220040000411044040028800100004844801668820000C0214228004442800248000022009F3504282228223820110400000010C121004001228413044C9248190683922825
+:809B800084131201282866A1241001111312111858818382A2424822284828F0AFE900102831184C312489034A32288400000000402422010000445428000000110080014A0148000080813118004A015F8D0F26082A04200200004C022848198202800210624418802854411148C0418064822248008460828002CC011C428141C84881BC
+:809C0000208411028FEB0128F228814B3187C1442E345A436842890284224B4441491208844470248404008CE25462544D21474685A8440028116822808281826382814295A1216AC4588185081AE31224B435048032283E288149B1182291482A12688281A0641F4212410113024189840280F424444F143421484E448C8694281D411C4E
+:809C8000022A12B14126F4515842835515905483A11226D888A1266AA147182238489F66043220A114442843528C228B4428801208145C22524400142AB25144E8141428644249146482812815A1262290484641996180D611A5421B71421D5984890183818423862484F2BD8C004088410884E08104844008480044841426484148414893
+:809D000041C8218450850000005018501810281128011E481412200112202124016F17071AA33189A233CCF134342E2C47415E58488CA222260C284D2445F4212581911B22C7C29D21DF42B221528895511DF028288F86E646E646A6446AA6662A52882AF261681F96F649499F16F768689F94B529F221291215D199F128288F83B228223E
+:809D8000E58622A5263AA222EFD6092AE282A6223AB234F224244F43F324344A21B424A2224480C22445A4229511F9292AFD2D9D21FF47F729289F9C5C19DF165C8C9FD2F26D6D1F16F64C6C8D488F84A4662A56889D491F96F661699F94F449414AF4414195F521298D2895D99952888F8252886A628446B262A2442B555F7608221AF7A6
+:809E000028283E38CD1C8F43F32C2CC7438F87B728F6282C8B228D2881504445F4252545E812528877524D2C4F5657CC1F144CB864F44D495F46A644CFD6F66C644AE482A6221F12F6212185A8228197141F92A3371D119F51D791A73117919F91F128388F87D388A1558D187AB362A513188F290FB028F228288F83F33C3CCF83F32C2CBD
+:809E8000CFC3F378788F84F6282C8F82528C8528564445F5242455ED1202ED2C5D2F4F5657448F845C914B4E5F14F4296D5D45CFD6F66C6C8D481D486A7621F129291F16F221619F167249F151595AF159599F13F731798F85F118191F93F138388F87F778787AF778787AB372E723A7549FBB042220024901490100220000C024001008D1
+:809F00004220142114411494282004421400004081044822004814840028800228F05D432008002A0118281848000042110000003024000042A024430200222002800600408102008489A242A04200281CF46C2EC0421F4152281F41B248F11124A3F41124AB141D64AB9419B24A19B54AB924F44A9143F242B147822D914F82C4914FA2DD
+:809F8000C4814FA264114FA264194FA26459ACE449C24A1F49C2421F4952281F4932481F49724AF18124AB141D24AB9419B24A9945AF143924AB9443B24A792498924F8284F9244A5F2A08ACD541C6521FC1A2141FC132421FC132421D4C2F44D9C1B262D985929A4B42AF1419F14A945392B23F82D44AFB255289F924C28F11D824F4980B
+:80A00000215F2264494D4B8F19E2227491CC4A1F49C6439E2C46F1912C271617C9271617C12D841FC1F642A15F81F64A8143B34A3834AB8443B342783698824D5A3F850C840040028400004480020000001002008800000000840000000000000000000010029F2404B0220129830428001800001045148112212104282241202424212430
+:80A080000222414812002242424818001C0448002848CA822201128394C700821200841200100883040020022284288044A84230244382922148C144162202182084C228281024084A08802209008334141C28F234A9004A22B122211428010045088B4280424424822262A1222061824B2C80E242A4121B42190249921C424A012024C245
+:80A10000282812414968142A0480A2924288281E4A441876F898FE402201002002200100001110011180042A040049040048850430228001224842480000884800004A02208108476400302200000000000000000084282A042242481004301820011024611215382884201108004008220000003F9509806181188CC13832C0182A012230
+:80A180008024211219E8840248380011842812222026239444221A0228282004326285015248830882004880041A22F23A15001283218121A31200220020042814844608200240618248421084A41246082822001091498CB218221409121008830880044280032FFE0C408202818100898101220018400822209418282A048022810222ED
+:80A200008031441218C024382200202211888424080022000080F27E43004810084088021880412812840300834208B048220500842840840118814142803518480020084422816A61820022808122F51D11004880228101180018411826084028840100812081045200904144892212283248814004490148304816644200806182108809
+:80A2800002127B362001000022608142A0240000200230140080022002442082044112002820828202180020082004001220048DF820011008002A412824018C410800283028160481682248804288024C96148141184481838231244AC2148085086048842266088430183862F0B8B6000028181283021812A0610044328148181008406F
+:80A3000028048005410042221A0228004216082800C04818001A041228220080B4930A188C021A06188002A0412001812212208184060000848021820118421828181200400818C126080000284400488001CE478002288422842884400820020022001880028110080048448410080000840060442842120022128412A0218002F0996701
+:80A3800000208284011088C128000018008092281280022004004008410060822002262404101824220448282818000080B6220A84000028000000800148200220844488840180048480840222228004100838000080020022008004B0E4078A021008812838001220018022031241800220040018281885840118A0251830242042182834
+:80A4000024618300000020810440F12BB120012001000080040028002248182800802114880444484248422004480080044C0528482868A0420000282002FFD30D008190281281102801120020011281002004102844081843A212B02801180000002002004C0180018418802102F0DA2300280012220012188001128981011822830280B3
+:80A4800002480010381C15684126A42120012248263428A012284420242404421881802282A45222CF56098480840200182002448984020010082014A21418184A0820A442221C042A440848104894288304628354488022048122000021F073E420628889E28294181638288483618158128B1420218523F128188C25A1248C3248B04822
+:80A50000152824B164F714246AF1142489218121242152848B22488C9238C4485E181842685AC1281684A1232AA54414421F860AA022A0142A9228B038028B1280818231282A03384AA2214A84840440081078187448F8144C423E686AA2418B332A81241264843AF444446A6484A04248800289021828A016F0F92EA03120B21822A112DB
+:80A5800028181828522021C118202322312C2A2222A2414A044E488C8441E81295282A2584A12200D04842BC28921832C9F228348B624304422AB428E1820120A4221AA2225F2D0100842284400816080020240100008002004210082800410020020041008400200148281220011200F043CEA0236AA222381E18E082A2238CA1114AA5ED
+:80A60000118F81A14587817AA7332AF338388D584D544AA44420D4880489F418188FC1F15515188FC4F158181AA7551AA1232A322883F268488B62CCD644F278788F8222A5444A84B428B228A223A0417AA5576AF6E4FBA0232E68842A8682A2223A83A1114F45A5118FC1A3548F85A5333AA3118F83F338584F6131428F84F44A584AF4F5
+:80A6800088C848C88F81F1181C1F51F1191D8FC1F358193E785AE581A5222AF22824CF42F268488F83F714744D648FC7F72828284A24A42783B228A2222AC2622B555AB562F7E18BA0232AF628288D388F83B318F328288B238F81B138E341A1118F85A6111AA1763AA3133E188F83F754542B448021A4C44E488F84F418188F44F5151560
+:80A700004F11E145F138181E685AA5513222CD28CB228F84F64878CFC5754CF4785C8F82A3354AA4442AF7383889A1332AA1132B463AA572FF350490288F82B268F238388F8153888F81F318188F83E341A111CF8585A1553AA1111AF118188F83F754542B4624A0444AFC48488F8CF41818CF47F5151D4FD1E341F339183AA7558B313ACE
+:80A7800021D2C8F22C2C8F86F67878CFC5F76C6C7E788F83A711A0447AF738188F81A1333AA3752B663E522AF67569A0120080010000000040089028120000810010889128224220840122302420A241438224C2488004008428A024A024F072F120082220022A21212201800118800318844A028B2484C0484220941480654526280128C0
+:80A800001810481808400400002A140800428041F18DD7C0421F417228F2112483F41124A3F41124AB141D24AB9419B24A3915AB9443F24A9143F2429147822D914F82C4B14FA2E414F8244A16F1244A96E1A2E459D2A4E449C24A1F49E222F4912485F29124C3F49124A3F48124AB141D24AB9419B24A19B54AB924B44A3B242F4479249D
+:80A8800098924F8284F9244ABFA209ACF4116426F2116C421FC132421FC132421D2CAD941D64ABB45F81B24A3924AF1439242D912E482D956D482DB14FA2E514F9248A8F11F8244296D1A5A4294D4B8F59C24A1FC9E2A2F481448D521F49324C1F49324A1F48B242F1112CAF44F91124ABA459B24AB934B44A3A342F447834B842F8364830
+:80A9000029F9245A1F310F848004000000400400000000100200880000400140080000000000000000000021F061250029014C022800222220014820828126812414082800004200002218441008441884401C08124200220000809424F0B3C900A2CCC2124840A821844038288C81014200418416248222A4246280226142904410180404
+:80A9800022448921227441A421008384648120741234348D6448414B4160114B24AF6F0B20C528414222842AC1282245688236280428186041424502221A04C20048001304899218444A12084C2264145048814118360846922412452844E421044B211E4497A8408212A4212100000012200148A04240A8142608224A220222124302410A
+:80AA000000440041160812C11A023048484200124CA24200444820F25B9E0028210020028110880200220081A024200442000022444183014A220220B12441240680042044082220C21449840281B0A701001200228023011A1408200449942822284422282A84820628388004624112882A010028440084C84800904416C488A8208584D5
+:80AA800024F2E56600281800222880014A8102202412C42822222022A6424868802283820456188422A22180312422220048000030249028438A84242404AFDB0B0021000038811048080080048130640020020000444128A01488002011644400814A28244408484C21881184038128BF1A06A042A0120048810028402C024028040000C6
+:80AB000080C48881004860443088488220044C010020842444041A044200008A0183F51DF300482820020048004244222002414008444820018A2404850428490410882401604181121008402402004B1488184800127FD404246011004034148418000084814100121248200400000012184400000000202301180000001240082608CFCD
+:80AB8000EB051042A112226044C96184182800102812684490181248800484898404CC0476C45482420012406441811812568804001A044241828084992883F4EC6900282A010000008014084048040010240442000000004508880080010022001A0400001A84211108002F3A0B000028000028008100000020820420420400412002002A
+:80AC00000081418004401414884408838404000000424FE40C00810081890181302800008120120800488044080000488184480000008198485800180080210441188011F4FD6100009028180000000000100420120848224842843044002014880400000084A014801404418100000084EF680560462004200100008002008140080020B9
+:80AC800004800240044C0242400420848404188444408401808484010020F11A11308484200100000020140880028305818092688182444120048C3448000044848304C048000000004200840000AF1A42420884608128844008844480440800A024000000884822C084490200002004C04860414412202104200100430112E0E5072280E1
+:80AD000094283018302830884318180C101808408818A8840000800448008088080000804188051889140858100418802104CA4AC2244100002220020010882202812810280A10C814432482648242444842001054840060844008008C84030018444924246445BFF90B8428482041040000448002200A8004422302188100282002548197
+:80AD800040088C04000048004480820400004018024D12244D24834898282AF3182C3E188126B828588481000028898282A422484A22A422CE1445142C44CC2466742404200C8147448984E484A4D1C3F1145416842191184688A14520D18431148C2191147FB608224420010000A082008428840020146888C0488B4441422A02209464A9
+:80AE0000895488CE4800448420048484848448C784CC0444B04404444248484C74FE0B214B6281428781188128811008C784831438288B82C48F847128C88883A6C22284858884A4624B464B488446A8440041451828048183E444354858802584A7448C0118C014A01483F5775400001820020000800484400848892218288802810000C2
+:80AE800041008188008441484008844100842001000000004F724152464485F838388CF23C2C87838F8272287828F888A88D2800818F82E288DA88E285A766224EC8F068686E484F84F444444744F068688EA4CFC6E2C202CAAC445048F0484848833418468CA1155AB158A5555AA1554AF45454F01C1D4F44F418585AF544447FAF415223
+:80AF0000444FC656888F835788CFC37138A822878287824CD288B268068912F888888D285AF7486885B24AAC46AF8527F4CC144F44F424446AF46C68CEE4DFD6F464448F947448288444D8C474482864844A3448CF45E145A1158B771E585AA7444AF41454F01D1C4F65F51A585AF546441F5D487226F4246485F838388F81F23C3C8F83EF
+:80AF8000F128288F82F228288FC8DA88821258888B228F88EA82E287F76868EAFC42C8C88F82E786F444CC4F447444A4628FC2E648FE6C4D47C68F84E48CA88C4885048F8484B448B4C8ECCCAC511E14F058785AA5444AA4444F45A511CF81F15454AF81A5444D544EC52467424F4256883AD388F23C3C87838F82A2228F82D288D288B21E
+:80B0000048B448742858888F88F828287AF728688F8EFC4AC86EC28F86E786F45CCC4F44F424646AF66C6CCEE4CFD6F664249F84E484A44450CCC7C48F84A4448F84B4C8FCCCCCCFC5A5111AF158785E187AA5444AF454541AF11C1C4F45F51A585E524F44F4A68D30260000200222000000800228100828100846044A02284322044200D2
+:80B080004008008C040000480000004400F09FC62008818440981884811008810080024008A024004800004E24224484000044800490148C0412890120A1141218121880014F2E0B2CF4112487221F41B248F11124A3D441B24AD141B26A9921AB9451AB9443F24A9143F34A95478AAD914F82C4914FA2D418F8244A87114FA264194FA263
+:80B100006459ACF49824ACF491244D421F49522C1FC932481F49364A1FC8B24EF1112CAB941D28AB9455F84A944782AF447924B842792498924F8294984FA2B43904ACF41164872215B46CF11124A3D441B24AF18124AF465141ABB459B24A79A4F84A1136D85AB8A4F44AB163DA1AF924528DB14F22FC18812E4287594F227418D534FC89
+:80B1800098252CF4112C4DCA1B694D421F8922F4916C23D4C1B246F9112C2D841D6C2BB45F81D242E982F4429426F84A944782AB9463B24AF9241A5F9C0E84800400000000800200000010021880080000140000000000000080020000008125013FBB0D4441800200441008402804004440A824814248C024400846A824008120240200D6
+:80B2000000428384081200001816284C240242411F970F2048040084120081201888018902C1005084284142285084284122004604C0288100818022840248428144838444014D18874494F06158403444442200844C0181C19088838403844484E02214984448444B1C2210EC84A242190281C1424AC228000048424A9824124242894293
+:80B280008414881454A4C3D4183414EF2F02000000000000000028404408102802224008400400420040081008830200000089A1411C083800F01B942002211048088481000000008444A0148481844200000049410420020000622004008882008845188884024A027F970D4A01C02212228C81026A21E884010010AC42818306522A0560
+:80B30000286230649024432202440060828332284008414B81A01812008D14CCA22C4A02488904C83F94051800102A028181528884000041688448121E4866182804800444414400000040084608488604988A81084D1849F284680068424888DFFF044A02212818818981022280050010481834284280012868902480222243140422C02E
+:80B38000288C2202281084010000C088906842402822F477FF802146A41248002218818484162402811400C48128002828200220424444C442858241889228421200442042A41283240130882826A81489A46177D14022542880084183010042442A0422400824103838211200440000004483084280018446C44822818941742408228203
+:80B400008001488230181F5E44020081860C008142121884100C4841442001004884180000222422000000002820840500001244800100F07A66D0220185B618C24840A421128184464888442C92410085361889C238A02481124C0200282422488001228C216481418C6444818C024D1880A381448B8128424A0183F4F3D1002800410043
+:80B48000848148181218008450844400000022000028414441442D82100822006880A2141200830400209128828324E2B2098001A02484802402428021A14189011212008002812004004984A141C01412188141C447844218008184008322044C0896240240F4F44A80022812808401A01622481008A04200A012188002004E321088221C
+:80B500002402289024A0214820018002280048418988042A04484222EF2D4E020000100218180000000010045822002001122200440042002112002848200648000000100440F84B88200148109818818906488032688183122821022242006082462A04A400004C34488C02200428188081C1148364422880911400189884002B4120888E
+:80B58000012003008062821241420084802201840000200240346C4480314444C0244C84E1820448008004484130A44C232A1488054F6B078420018190382222004481188100180080142204802104462426015200A021004880258288010080848104800920F423C38042880200481800124200A0142A142484042858808404181AC418E2
+:80B6000012802582828193441098280020C4882A08882008848248288800AF1D02232482A161181200004420018004480012001842008542021084C2264841200218412822200F004A28084308444144821441AFFF0F16488404604222A04180644148281A242201124242212180128808891204281412448C12C85418220048288042A4E1
+:80B68000182818188C14881401422388F1A43CB022E749A12290288D5689B32824A4428982B548B45881B418B428A61180A344482A06878430428CD388D4C2E243F254144E4447433E644B444C61C32F41C244160C586AA4962AF328284B74808DE188994C4CE845C754C246C1242F350A12898281C21860854A810142221E28848F878110
+:80B70000A11149A211442C2282012A76488824E4211204844B322443E442713488332422CB222828128A74180488C88441160462AE81BA8AC4C1814F314F0220A1513AE4812282A2235AB3242595140066288424A6441AE185011A06481AE12394128B414B442A26A1748CA12128414AF15C184AB4782587A2218CAC8420A8245EC4C3E47D
+:80B78000CE981441418D88184B411D4520240222208204482001008002800480220110080081490141003024302484490100608800200848448A040020F48D89242B114741008788CD2C8F86F66828A0118F87A7778D188F81F148488F84F558184F47A3331AA1118F83A7554A048CA4448D582F25B55AE544F4585C4AF644666F41E34523
+:80B80000053AA12283F474348F84A4555AA7758B3189A299CAA4514F41F51454AABA34F33495CFCBD988A8D94F42F2CAC5243AF314742A825688C5FC28288F83A355528FC7A6778F86F518188F87F768588F86F274347AA65524AF8724A145818BDDF0189A2FA57522EC42F4595D4B644F71F4766C4E444B441E344D648D442E3887845A72
+:80B88000A5315AE7CDA7EC9AAB4CDAF154544F4165484B7B5F4BFB9C9EAF88A8DD6F46F32C99242B774F41A7221AF24888CF45F368686AA2555AF1486C1AF748785E588B448F86F178384F45A5517AA542AF82A6774A054EC85AF4387A2FA5F75E584E448FD5E544E664F4161C5E144CF434142AF258684F45F758184AA2446AF558548B3F
+:80B9000064DAABCC5AF5C4D44F8DBDE4BE34F384944F49F94AC89AFD2474CE82242B764F41A3225AF35818CFC5F3786887867AA5378F83A7738F85F518188F87F468588F87F374747AA7576AF47A583AA15687828F85AC458FAFF7527A6FC3E346F7585D4F47F775666F47E745D544E642F374248FC5F6447C8F86A7764AA3778F8FBDE866
+:80B98000AE9DCAACDD4F45F5DC9CCF4CB8F4FFF4F4FEF4AF8CEC2DFD44646FC502218001188C842121028004480000200120048120849128292124024B12A0120090148422482248228E488004480044928D248200AF15070000424883020080140889A14180840100422200004240142404461424118422840212200100001285240200E1
+:80BA00008420F236CCE022F4112487221F417268F21124A3D441B24AF11124AB9419B24A19B54A3924AF143B242F147924D852FB34481CF9244A8D814FA264116FA27498F1244A9E254D4A9E24ACF491244F22F49124C7221FC9324E1FC9B24AF18124AB141D24AB941D28AB9451AB944782AB9443F2429447822B944F8294984FA2F4B565
+:80BA80007E7024FA114487221F41746C321183D441B64AF11164AF467811BC4A9A25AB94412F144BF842B54D48ADB563D312FA245A8F14B924F818816FA27498D124F488254D539E214D481FC97226BA91342C1FC936461F88B242F1812CAB141D242F44F1112CABB45B292B844782AD1432257424B84A7936B84AF92452CFE70184824871
+:80BB00000000000000280000000000188008008044010080040000000000000000002501DFC5062C34142001A18004A280842401208284B21C2401490240224468242081115228282441003024424142430882000092414441184142289F940A188A6242C11A828202128440081001008C014A2204002284424332284E22224624440428CE
+:80BB8000242002222A044E28228B42888004221312A142224049F46621C042430F16EC224188228431A84142220000423846EC230420018602D02464821217234C64848D2424660400432214042E8441222220048A23024C6622C049321FCC0418302400280000402824410128102801484C022032488C84024A120224004002222082263C
+:80BC0000C448228E48880000455141801104414BE90011001800A01200001028010000200400008004240000440000401488A2840000000022A884004F8E0F2A8112C23428623064608428000022818B1480829628002002628012241444B4240422902C8012E48423B28C24810580B18424688148433144432642F4D8B18041024923822C
+:80BC8000064A221288020081186084002A0448000048801224440444C0245048200242228C88810400428880044CC46C00178C2062120012004118480000804228012260820080022880041012A42400200240C43C8166A484120012860489012E142A082241BF410A184A0181844004848110C82800301100810084481A146886890442AF
+:80BD000048C9C228289028E08532288481284444C12122CCA8821258460480210A3212FFBA0F2004304422004AA21400284881C048420000004B214002488002480089840421444C41882181223A48442A010030144C064024F175FD0000122001000000000028221741800C8100200281208101000080028A24220400480022824483028B
+:80BD8000842A18088FA3091800814784324160848410488814088924028D15800C814C1668A48B2420247418E482250248C038A3C2248D148C8E6144C18AB248C24888181A260489816282A84781B0C8032001120000221A040000C0114828001088048002428428220020020081004C828112028812004C18C4244B418880029FD60C21EC
+:80BE000022212222002222208212088480228424240268000020D2844248180410840428810020840C89280800004084812828F41B6500106884420040088311084608810000000010080000004828400400E08482034483811308200228281A021812F0966140224102902842002200002002000080648220028304424C04008022020040
+:80BE80008D2428006848200400810080A84200BC4302200181000042008006002A044A022280440826880200482810480848800240B8188208883694882008490818482036A43FE30FC222802284042210880148840048000000480048282002284884220022008004430428424842008A04480000F09A32404898424008001840080000CB
+:80BF000000282002208101008004410000000000000044008A028004402408122F340F28801288026842288012480884812200008422840020841434288082044122000081528181411200168822011888AA8101F03881C012121800480040080000002228000022812289142804448F4234440040248224820266684349220492460800C9
+:80BF8000004C1AA4429A34E4EFC7082628E482046082268864842A042604282828842094288012021881A800A0244001C028818C2402000084A22E44818A0288A08482426210028FF6022B328B2A2F82F328486A86A6262AA42689E283A222008528A22220A266E08222D4880228228B6448CD642AE244362446084128812A220226B81845
+:80C00000727844AC46BE585E88A012288084E1489D44D2C8F076CEC04229211142688248288961861860848C844238486842A022A06248850885084A22724854844C86A4222826AC224828228B248CC5784BCE452894148F84882888E9488AB224E24881AB174F4452AF24602581288183142844881458888183048902626884002007873F
+:80C08000824A668220D484342842406842490440982C48624189A2A1A88B688A14A8824628A484127AAA4282BAFCDC6D2014024008004820018C04848004000010088110081024042002430222848024820486286281200882288A04122041F4CB99241AE52242A8228784878485A8265E184008878685588885784828A2468F84048578E4
+:80C1000028F838282E2826A8466E286AE64686D484D4445688C0245088228558884E482AF23C2C4F42D288FCC8F88B4CF01898A0D14AA4914F45F97494EAAA6B2AF253B2241AF1726285B828F248488F84F248486AB2189128C59C288D2C85D888722858882AA2228D4824AF82F26848AF83A7228BAA8B228BE62AE646964C5FD2F42424FB
+:80C180008F944448E442D68822528887828B4489F77824C57468FCE8985E688CF41818A051481AF174B44F61B982A9672F46F73129245E522E62818B226E688F86F648482AE287A3668F43B328E284D68854888F82F268682AA4448F8404AF827228A876842E882AE286A2646E644E4C4D6D4D648F84E482C2244B6285A822855888842A74
+:80C20000F234344F4AE2C8E88CBBC8AF888F81A92A9AAD4EFAF95414FE442BAEBABFE4F5B74F245E722F2296288B228F86F668688F84A6228F87F768688F43B328F24C488D4883F228288F86A6624AF66848F02A288FA6A472848F82FA28288F8EA6646E64C7C64D2D4D249F84A422444F42D288A222008F82D288F33C3CCFC8EA8EEA8E7A
+:80C28000FB98988F88FC9898AAA2D9AAAC9F4F47FBF4F42BBAFEF24F4EF47BDA80010080044800000000002880024210084280024241000020020022120000C048008004824420043F320182901A10880400841884810084002082220284008100484484284828430200C028814883C2448326010080220280A342384712CFC3022D421F67
+:80C3000041522A1F41324A1FC1324A1D24AB141F41B24A9921AB9455B84A7924F84A9143F2429147822D914F82D418F9244A8D814FA27418F1244A87194FA2645DACE449E2A2F491244F22F4912487221F49324C1FC9326A1F48B64AF11164AB961F81B24A5985AB9443B24A7924F842B4478329F93448984FA2F4C4ABF0224A1F41362A89
+:80C380001FC136621FC132621FC1B26AF1116CAF46D8C1B242DB85B6427924F842B14F82D41A3924AD916B42AD914D528DB14DC28F11FA244287194F22F4D82526FB98252E4217C94FA2B491E42274913C441F89326A1FC8941E1FC9F6628417C12B245F89B24278B4B84268892F44FA344829FA3648214FAAF523AD0080040080020044F5
+:80C400008002000000108202800800001400000000000000000000000021F0FCA200222210042220026284124812A024008428812242004302800442222A04100460894A32480020332888186082460818A0282084E2520E4A2208802112AC42A0422002002890188022A46820128406186826282221042242204282041A62444288C220CB
+:80C480000442484449084430641441BEB2A0244A023014224982822292248322838481223618C02826828AA24341A24302304830512842892264442880011E2800884BA4222A24814448148411642A43044B21CF130B00220010880448420000000020C448008004184A22820242220000B04A8826C4444280418808A04283240800224211
+:80C50000702A0800000000628400000000A18002000081004828000040042082120800421A04848100008C0400F0AD528092124542025218180028284008582884200452284A12280681269238848086022061423014A061A042E2282E88488A84A8284328136448833224812E489F560C2412441082240110082200002800482200222041
+:80C580000284222D6889026228004C21022A21220468CA22B628058120988440C444222884684FF706224002200118628002400852401A082025821488440880010000004410048303002088243C8828A021C08884414078E8464204846180020043C12428283018402801008B421281128095144800808106898231444144228001802646
+:80C60000A24926084200823081422272350A200489324482204208C41228812002484142A4004A22010084002840088304460842C0218100860CA082812A688283024822492221D1D404001A820149C844181A24048480150448810012008002100842304822212200A0210020C24820010000424220420110F4A7E840042E18EB124280E5
+:80C6800084321842E082014849819248102424212291682880D44881240489A212812848128149C24422206284A06922D2891888A242892688868882B144B2D307210010C42441124216342800161808E0810410C848000012100880042B422002411200266181008100008A140800284984022F250D1E24412241836182830230242A040B
+:80C7000042108886C4282A8102281008422268120080052844001226042200A084888818000080E9842804E02D0C0044284C941430141A8204484C011A0400000000001200452842880218001800C100424110288222AA840022800188F0B5978082222201812122841800200442004018180A2820220220220200840000830180021028B5
+:80C7800028014E182001A018004858AF320B425240082149031018C8248042041088041604184244800400480000482A01412002418088018042849388382A01A0218183D23E0E1E44402482220683C2242238224880C12826A812802382E386012818122A21921830585A02001200001A04004788C08812220000802C04F0C36600004C0B
+:80C80000911A444608200442A0218C0420A441810020040084442001200200488082C2282604444004200180281128312843A2241BD8004723844084011281411008002004814242481028A442414008844C0243810481490141161424B444A2434A9248308848E818261888722884286888EE5E102208A0822502201118488822210218E5
+:80C8800000423A24A1248004800100008084840422424200184A086A010018810014286012F08BDA4008488084941441482044044A0260421A5448128181A524A212B0488884A121482214782284224934141840146842121844A028861868481668480082A3056DCEF014544F69D248D24421272436282E144F4411984844529048C018D9
+:80C9000089F248485AA7118741684B4490541830244848481818488902124A32144744284D144A8CA44C281A28A822848C0B11A0288F12F92868BE98A0248A34248B238AD76A87F21434288D288CE382024852228B128362C532C782A3E282668222B02862831E18123668433880024245041E18448B234742224F4161818381B888B17870
+:80C98000A2D9818116AC18CBC4D88E294AF8CD5530222A0124C57E34F81E1C7058A8426A24A44718CD784AE244A6655838C0684A3148287A26A56443D288A3248D28723E646E4843A4131AD1447324E4820646A8648AB2CCCBA883094DD846E84929A3B23E88BE3866B84484F1ECD9244042080048A04120010043014508413014814321F8
+:80CA0000140449014084614418460444182002188400002200411004438812143814F05293244F62F23236EF82F23436EFE8F236242F42F26C6C8F84F22C2C8F84A666424D144D244F42B27CF128248F47F22C248F86F4687C2E4C4F46A6224F42F22C748F82F63C2C8FC3F23474C5FC24645AF444444B444B2247414F43725CFC1C3C4D02
+:80CA8000284E484B33AAAA911AA19945F4DC1CCFC3F31418CCE248781CBD98FCE4644FCDFDFCCC8FCA42E247F6787C246D24CFC8F63664EFC3F26C7CCFC1F33C3C8FC4A4664E24188F84F524244B172E747E34CF47F36C5EAFC6E3C2F1643C4F42A2FA8B73CFC2FE38288FC3F2646495A93345F5644C4B444F8757444F43F36C2CC5EC848C
+:80CB0000E486A637AAF8549C3AF31838888F88F13C3CCB993E348FC1713CFD14462BCC8F8AFCBECC3DAEF042543E748F82F23426AF47F67E24ED3CCFC1F12C64CF46E647A76628188785CF86F6787C8F82B36CB128F67C7CAF86F734688B764F44A4E689F53868CD1CCF82F2185C8D492AF674444E484E442E644741437154ECC1D3CCF2A4
+:80CB800044444F47F764644E446A87AB119AB9ACCB9C9EB84B1287834FC7FDEAE88F8DFDECD8CFB50C2F45F71876AFA2F21E3CCFC5F77E2CEFC1F32C3C4F41F33C3C8B778B2643D444F15C1CCF86F6785C2AF76418CFC7E786F56A384F83F56C4C6AA4C7CF43F1BC6C8F8333348FC7F554753AB771F5644446E443F714144F41F1743C4FEF
+:80CC0000C3F37C7C4F46F674744F4EFDC8DC4AD588A1914F48B9BCDBC8E883F32C18C7C18F83F4FAF8CFEBF9ECD8EB6380010049C14849411844088C041A048480041281120000008011081024040090148422482008860892608820912892448281F02AD2800400401424018400008004B048018148C0488024014008A021224249041853
+:80CC800044C12800221A24048901421608848100224441BF2E052CF411248D121F4132481F41324A1F41B24AD141B24AB911B24A3915AB9443F24A9147822F147934D81AF934484E914FA2C4814FA264114FA265192E4A96C54A9E24ACF591242E521F49D228F1912483F49124A3F48124AB141D24AB9419B24A19B54A3924ABB443B24216
+:80CD0000792498924F8284F9244A5F1D0B4F82F411446B521FC1726AF2112483F21164AB121F41F66A841F41B24ABB11F24A94322F546B822F546B83ADB52B432F54EBA2C5B5ACFC58A52E1A9E254D4ACE214D1BDE21ACF1912C2E5A1F49F62852174983F481646B141F89B24E9121AF465941ABB419F24A9422AF442BFA421445B84ABB4A
+:80CD800036B442F8241AA73E402888040000004004280000000021008008000014000000000000400428000000405412D0BB0E208203902C498102181222184281A04180042004A4008112202104322084A2121618040028848422200488462802009228008FAB0AA018880012008304008304441880A2214A62822218222200224424006E
+:80CE00002168225200202101800598C088800189046081D081C511F0E69900C28A012061418084911428221088A141222A25428284A1212322480841124811386889A6434A618141002022054B12A0488012A824008C61293E411C21F119AB001A2202C02C801208008B1448440000488922028400A0124002240000280018120081848802
+:80CE80001008984881000084002F110480228202288002288002002242224A082002430200222002000000004200000000000000003048F076BFB024111214342412482002120020042608001200200243032604222002224822002001284822000042202882040082427F660A26022800120028800100008304428001000043020022002C
+:80CF000080022200480028422800004880888204008C041FCB07498112C4244C82828402289024282024822222082002438202122226240220022004008001000000000000002088F49CFA00440044208402002800420012802202208822021200002220040000000000008446010084000081BF294A020000C12001400818002818488406
+:80CF8000200144008002844248000044284F2102004A0200004800188422103C1822004F780F0012000000000010841404008C0400410081000000000041260480018002000000004008425FFB0F40240100481800202201484A82814428C21840042828288481484800804484F21422412604680020024240018400C1122230485FA90723
+:80D00000210010440C2800810040044412004A02204804800100800200000000120000402824012281104808F032FA00444120020000000000002800004004004480020000000000000000000010482804004F110D2880C22441002002220000002241004312240243020000000000000000000000000000800448CF1505282042840200AE
+:80D080002280128402008002004C020000100422000000000000000000000084840080E4EE0A30444422440000504445B424A2222200604240024132414B2800001001100842000000004120020000002C8404125FE60B4122002200000000000000000000000000000000000000000000000000802444F81DA510C8484384044100004451
+:80D10000444422280000002502292181298808222214111484818C24840400004014C424222800002054229012AFEE0784800400000040042800002002902222188088020040014008480000000044800200400840180A6FDF012880420422000044A022000000000000220000000000000000000000000000810020F47D720041400400B9
+:80D18000280000000000000000000022000000000000000000000000008142005FBA01851428240428000041B02402220000002662222021212A8A0200111110182824040000004141222200000024A4F07E7C40C828484800000040C424282A0240040010128281818808280014144048888404000000444428280000008421216F23011B
+:80D200000020024100000000000000008002000080020000000000000000000010080048842F190D2820020000000000000000004100000000000000000000000000000010480880F4A9BDA0222E24100441000000000010042820322400202202200200000000000000000000508820648440F82716003024442002280000000000000091
+:80D28000282200802202280000000000000000000000008598484688D4140245042828224C02000000000000000028800280A2220000000000000000000000008508904883F4ECC770269226182B119012C0122582E8317111A1889659888E414E48D09114815489C14A764854444B244F4222E24202284514A4226722212AB11281B88203
+:80D30000092C5922881E1317118A689985A8484E48C048805488814E484F79076F2242A23212122180512229C8111B1119E88818D818242444591148C48588E4441494244322420428444584F222222418121A388282182592821CB11191818E88818924244408488485C848DF59090000000000000000000000000000000000000000004A
+:80D380000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000CF
+:80D4000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000004E
+:80D48000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000CE
+:80D500000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000004D
+:80D5800000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000CD
+:80D60000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000004C
+:80D680000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000CC
+:80D7000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000004B
+:80D78000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000CB
+:80D800000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F004A
+:80D8800000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE4D9
+:80D900000F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000000000000000000002C
+:80D98000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000000000000000000000000C9
+:80DA00000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000048
+:80DA800000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000C8
+:80DB0000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000000047
+:80DB80000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000000000000000000000000C7
+:80DC000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000000046
+:80DC8000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000000000000000000000000C6
+:80DD00000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000045
+:80DD800000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000C5
+:80DE0000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000000044
+:80DE80000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE0000000000000000C4
+:80DF000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000000043
+:80DF8000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE00000000C3
+:80E000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000042
+:80E0800000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFEC2
+:80E10000000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F08E
+:80E180004FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F00000000000000000000000000000000000000000000000000000000B1
+:80E2000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000000000000040
+:80E28000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000000000C0
+:80E300000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000000000000000000000000000003F
+:80E3800000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0000410000224100004428440000000000000000000000000000000000000000B0B80C80020041414441440049421404449024000041440000000000000000000000000000001008812F370880020000442042040006
+:80E40000004144220000000000000000000000000000000000001008817F450E0000414100440000000010040010140400000000000000000000000000000000F0A1570000000000001004444428000000000000000000000000000000000000000000AF1A0B00000044004400284400000000000000000000000000000000000000000014
+:80E4800000F05CF3000000000000000000000080020000000000000000000000000000000000F0289400100400411800000000224044C44426040080040042120000000080020000000000000081E09F0100002844280041800385044C01440022400448C1206242400800482800800120040000880088008324042281FF8E080000408456
+:80E5000082010000C4402442044143C2244400C44822430283840100220020012800000082008200892404002FF20700412002410044A021002001400442002004000000004200000080040000000000009028845F420E4004200200002A21911884A0410081221004A0240000002608000000008002282280480812200832880026F8C23C
+:80E5800021802282624212623822844220060028228982C44C16A821688904282AE441A2246862124222422220828302188904001A042084062A848A24B4682826748804C02422432282A2212800A0411648082A0426881408440022224226242486322880828402802202800420820184A04180A22872C0A84AC268AF28062200802104E1
+:80E60000102884230200122210386489A112688C2404221222808421040080220180C128200248888084024A08802C04F0EA3EB04801842200901820848182222405008128404818A8218001844262A01228C302681684A2241252288842482200414088214484E1840248ADE310880480240200281084022002181A0880024212C9024C4F
+:80E6800004180020341880040000200410842902800200004A013F240A1002120018280040088608C048002043840144003200182A048024040000281A04000046280141E082014A0860825FED041221800120912880226182C0C848288324918820932812484444182A41880428383044422244802481A443888004904849018C02584410
+:80E700009A3468428B428F8A03481088228402128004008001001822101448886282904480A12548A0421A02808122022A01424880820900441289020018F0E52A008412002002128C220244201508002284484884A04180A3242822A0124800848022018082A41258A02880010018800C80F8E44C00800480820448802581841228222164
+:80E7800094180028004884180041121281410080442804004008384008844A28326858008388E4B306A0210042000000220022008448008420028004286082428440082812003A2405200100008280042A8CA42448F0B54EC06800282800280041481228442026222261432002180089149848102814082081C41828000084821044684891
+:80E80000228400C01400F086162004004800002200000089A41248008100001248001228200242320010881208424181828220220C48180040B1460680024A028C44888242C8280028C0181248800400E084022081052001124820848426014200A021C6042001122081A2180082EFB4084024020000001008002A0400228C044E1848000B
+:80E88000818180024412460850480000800488C01418209818400840A8848870C90C28000042108802000062000048422A0428834208220042482022048021240480046888428008820080088868425D81400868C0282248408804C42268844A6142896143200223021848C810984881811C82814308481840088C228428C4AC802202C48A
+:80E900001A4404201202DF55092AC21800488B2483E282A22287828F4102807418A824892494486A21014A048C1228B428A4224B228981B22862864A02007A86322842890668488F869A1489A82889D18834588B44C2882A681C8ABC94034A8482223448220080044232A0243E5852226684344C89068B426A4488E481638446A8268FC190
+:80E9800045B8140748832441A815181A6282F0F888A81A856888128CA288481E242AFED4588A9228F0B67D0026A4122AA222484A048B41282A7438C844B02414E842F318781A83E28266862E3828814AE58121B41894481628A451811E48E0C383911848468824A444184B1D828A0249A98A4E1428181A014A842CF4A8BD400400844028B3
+:80EA000044284428240141701408478120010000180044184418444084018901890181100881128141100445088440085F28034F42A2233AA2222AA226228B664AA4246E487AA5154D444D244F46B234E242F238248B374FC7B768F638388F82F668288F84A1444AE483F5484C4F45F744444D144CF254144F44E48352882A47E881F11816
+:80EA8000188944F868B88F85B11849F81C1CCF41F12CACCF85E54FEDCFFD6868C7C485E886F448C86FE70D4F42E287A6232A56888F8624B268A6466E284FC2A2335A8384F44434CB146E748F42F34C6424A7828F85F16A788F86F6C8981AA4F78F87F5486C4F45F661615AE455F6347C4F44A4638D188F83B238E282F2682883B448A4B7D9
+:80EB0000CFCBB398B928A2199E184F4BFB5C188FCFE9CFF97C3C5E92236C8AAF8CB9FF01484F432481F268286AB248B62872489868CC82A3344846F86C387E346AF554187E38CF47B36AA6337887848F84AC514AF43818CF86E641E514E483B354E6C5A1444F4336188F83A3458B118B156E68A0B78F45E9838B8BB898F92CA88FC5FDF873
+:80EB8000C8CBDF6E684D142BE68BCE4ED84FF50E4AF63C64326AF248688F86B648B6287268F828688FC2F268784A81F44C4CCF86F3681C6AF744784FC7F73818AF82F2583A8F86B668F458C81AF4F8788F87F56C683E644FD7A7235B653E744AF434241E183AA2678B777E386E684AF478B8FEBCBEB89ADB88F8949C4BBB8FCDFDB888CB32
+:80EC0000DF4FC3FB58D82BE68F2AEC8C7C8C0D0000802402002200004880041008830400421008838431482004000048002009822001822008820020F86B6A20080000000020010012004A01184883441808128420022005001200181242002004008812818200184888142796C0421F41D228F1112483F41124A3F41164AB161F41B64AA6
+:80EC8000B911B64AB915B44A3934AF1439342F147934D812F924481CF9244A1CF8244A16F1245A9E212E4A96C55A9E24ACF591242E421F49F228121F49B268F19124AB141F48B26AD141B64A9921AB9451AB9443B24A3B242BB4478229FB2448984FA2B4D8062E421D688F22751124761114F2116423F2116C2D841B61ADB41B61AB9416D7
+:80ED0000F842B1122F146B812DB16F81D412FB245A8F14FB24C21E814FA2E51DE2A265192E5B96E1A27591E822F591488F227591B4687191B46A7181B46AD141F46A9411AF449A21AB9490BA48298A94B269B442FB24524F4908848004000000400428000000002100800800001400848004000000124480020000001002375200001200E4
+:80ED8000480080041304812088832502830242246280024242A0120048280020422842089A048142200200828242008F4B0142A68482021820032128001842421A049082A0418082040010480A2024020044808404488280028842A041281828806258E05D01424B24224800A0210043061984C128A058385821242A053A44220A00841099
+:80EE00002101892284024C042242288C04498462824A88061828A02886823284123D1500001A02124240020000424800200A84004248200248831482820400008014082088090020220418004800BF740B2C81021280840122282A4108120018002242224E24004B4289822141081800009012128082012280084A2808000000824222EF03
+:80EE80007B0F422003242A6182188041A2148144C38403328A06124325A14228C042C0668016222684A5252800188004004800A0188A9248488A4408481A026F5E0380A2120029C328122218101288112482218204182E1478282022141254822E422004486A81020020012200208888811888844C088A2483D2EA04522120014218002235
+:80EF0000388B144034481280212A2224148484C2448922A161001228481240822181812204004A084280882204000042F078DB200440824428C1242220512428181042A8144921044212841210044812128001A014004301006A0142E084888304000028880046F42231004243024118000090542800180080831102CA618480A4422100EC
+:80EF800020041A122822040088202102412800B07428240A8002221E9D204122812201C01280012881481883220100000043420420410428A024420012A0124B142E444182200280088A410820048002274A80014383C24420912400E02641A814100890143800B04868C64160265820014A210452004381B244813414822210084880F8F6
+:80F00000748842A2208802448784800421901216081223228101002C2193181A04481848180060440049012220A22580820118B02488868124A24818822001002A0480A2429D8920810218180029228121024100120010042200802214341420218421841302800220818404482800688004002008E0C60B24C022C022200424008081359F
+:80F0800042002248000028202482034344C41244C125A442250412491234444184004C881804418C9884824382140441FF2C0D2A240122002242212812222B244818000000000044004422002002283224003822288002100400008088288428F24B18100218808402002C81440420022305A12C811182130421124800000081006912848C
+:80F100004608101444880840240420044400482F1B0A8A8104800260220000424002244228C01400122001492124210200208103000000888842800488482004800214EDF200800429040048E042654220012C042448002189042E184238A0124258121A042301484880240400480082200880220800C2A0CD002422004824602240820196
+:80F180002120210118418CA4149044421008002444246026424412214444C44C02000030680000208408F0C66380220200222200222460212422005A02001A82012828002838264218D2820300221082028181902822308890C881008800A086BFC60F841858280080846224E041042852214221221642142426C21480382281210014003E
+:80F200008C11B21654840022101404448C8402C084400482482D44F09E1A2412EE32223866A2242E222CC422A025226CD122C422236121232112C45C2321D344644226A412124C31342C022D422B123A241562218C1114382C22844288C24120A24482A288A084AA64584AF2F99EA014211A1102002B26421A83D522A3245AB162A5142B79
+:80F2800044222F84C116614B5242128CA6645AA224C992624B425E1E497144D8868192246F4213624643C2144D48CD442289840A86BC48C88C8F844CE444C4A44144C044CFF5092A2281622278224830322F227426A2411A041224184E6268121682C2782A422241F826143AA4141A1122D128C2222F22E56701474229E64483C624D04453
+:80F300006882228B8C424926480482828AA4844A2CFAC82B24C012800121000012200100008460816081400AA4C01A448C4104441844181008180000000041100441100441706D0B5E622F21B112E2233292291262226E6227242AB272B352B142A5742D122F21F112122F27D6AEF15A58CFC4A5338D2AAD2AA5FA2242CD6CEB31AF61F361
+:80F380001434EFC1711E6C426F42D366F1123227E1655E44CFC3F3581C4FC45244CFC8A8AA8F8AFA88884D8CCFCC5CC44B448FC2EA445454CAEC46E644F4A4A4CF4744B242E687E723B332A22B2B642D222E226E6227262F62F272322B754AE525F552522F21F13212AFA7F61E1A2F25F514348FA3F328784AE62AFA2A4ACFC3FF5E74AFA1
+:80F4000063F356769F95F558484E47EFC5F556562F25F7363E6FE2722CFC7474CFC57144FC4444CFCCFC64648F8EFEC8EC8CF888A845BC44F428AC4E445F48F8C4C62F46E644FCF6B4EDD4242B251AA5333E322F25C5222CE422E426F652222F67F672122B755AE525F552522F25F11232AF87F654522B556F47F53838382E244EC28F879E
+:80F48000F446644FE3F354728FC7F752518F85F47C582FE2B342F516566F61D36EF24664CFC2F34C5C4FC4F64C4CCFCCFCE8EC8F8EFC88A88CF8C88845F848CC8F86BEC4AC444F44BC22B644A47ADFE70B5AF338722F23B332E327E724E624E626E626F672322F27F672322B454AE525F552522F25F572727AF6585AAF85F536343AF32899
+:80F50000688FE6F662E27AF4FE7C4FE6F76462AFE7F754458F85F47D7A2FE3B342F514744F63F32E26EFC6B664F74C5C4FC4F64C4CCF8CFC686C8F8EFCCC488CF8AC8C4F88F8C8CC8F86BEC4FC44C44ABC62F6C4C24F4EF76B83800100184880440226A241804422410285221128314820048170480480012014022B128423C2481800829F
+:80F580002200008220088A0400F0497D80042A014A010025024A012D12A014202411028004304820812481140810A2212A04403442444128418008884880040048808428788E0E2F22F41124AD121F41F26A121F41326A1F41B24AF11124AB941B21AB9451AB9443F24A9143F2429147832D914F83C4914FA2C4816FA2E451F2264A96F1E3
+:80F60000265A96D5A6E549D2A4F491244D521F49D228F191248B141F49B24AF18124AB161D24AB9419B24A19F54A9443F24A9443F2429447822DB44F82C4944FA2D4CC012F82F41164A9D541726AF2112483F61124A3F21144AF44F81124ABA459B24A3924AF1419D412EB83D452F816482DA58CC5B56F82EC51DA86E418F22658CE216D38
+:80F680001B8F1DD224F181284D5A1B688D521F48B248F1812429F1816C2B121D6C2D941D6C2BB417882F4463822D942E482F446B822DB42F82F442B42E1ADF680F848248008001000080020000001002008800004001400848000000004400000000002501EF15072002438181512220011228240028209242A01200420020220100250211
+:80F70000000000002200008100000084803284F0213300828821484902284843220458414024011822800228C048004022138602184828241002008002200882006018004814224E8E00C22C3814486C02801514248211868282818221E2220120038A0428182011210281484240020022004160CA200800828124708421F3283B002800AA
+:80F780001812242880A214200410043042002280048400408252261022012824000000280000000014002A04707E0A00000000004230480000208404002E4800000028211004410012000024820042E014080042008008EFBB0A232412C2120041802402200148226420810228482012024CC21461188128481022022C021846848824823C
+:80F80000A886920028241C4888984848814AF2D2712448001221002084220489012052248081022260862800263414441A42084100280021124C846824A8884A280142002100800448CF120A2012020044000020044800202404800410020021108222042504A01200000020A284908128C081462838489088281FC9494143020021400461
+:80F8800024400221100252486410524184218014440410811202414100440041424130440041001008414444D059074862004424101212120428000060884812210000008100D041012901481265021800448014048064240048002508446F6507401401802181014A81621100000000000040440221404404442400002444482120042001
+:80F9000008004162008002F0FE9980140640042141212D122218100221008849240111101284046508446042258401415022641848C04442000041422180044184005F540C1428250124122C21014810110200A041830421404408006100102441026180410444244440248484084240A4428100434254244F590624004022040000702479
+:80F98000011504004C040045021002000010041002244111404404000041100400414100D0920D4210428204490454423041481C440220041004004002004114240000800424000088800888458248C4840082414338889F5F05002400115043000010420100000044000041400241100200002100004400000000000040E47C0914000018
+:80FA000048214840040080044582040040420200100241002400248004440042400445020000002482006F3F0824484464001054242004006C020041000000400200450200401404001004000088000040080081F0C92B100248000014424124421400304100100400004004009046000000000080088880C88480088888812120F845C854
+:80FA8000201414024642614420220422B04102002024140200501240131115014014140240410100214860441114C084442F4408444918444478C30782824400000000000010040000004042820424003042400400210060444142000020240400848444BF340B25081C0414408104212415C4422848400224480031800119180111104469
+:80FB000001400A484110044124602854C024140040280800F0BFC5242562281092423114651414421252716074214512522442650441214012D2245412541552444D4200004054214400414446044908244D84904481888E8A65788818D442014A644841641446D244E414C422432444A144271411402404480000210021004501444C545D
+:80FB80002241443041214141502243840810D41408100250444C18042F54061123545260241C241461544C041B642819B424044681E444040074405212341505555242242121442546026542014445A4448A48B2C118F1838444824F44E84CC888474800448FC8F873AE100111000080148216022141214914121412041100100111000099
+:80FC000000501240012110820482218221822182218658128444005FC948A34445557475F642C34E421F44E474F422246D442B662D434E421F64F447656556774D466F44F446424554554544425211F0474665545455556425F246462464755555507424405222F042C21F3CE4287883E5787884A2444768E5FC8C84CFC8F884844B888F6B
+:80FC8000A8F8A14F343F14F4444D4515E53CE424D461F4424546F264666F6642F322657F44F447474177546B446D446F6454443555442F2141A29825F246C66554555553572F44E43454A8F0414D5595426546026425A2442F645C311F125A756DA74F28E824F88686ED8CCFC8F88C8ECFC8F884824F69F9E141243F14D444546575F64236
+:80FD0000411B441D415F74F426674D444E461F12D611B642F447464B447D4569D466A4446554465585018835F1424375575755577625F2464484646D4445545775544624214E42412F44FCC3418A7A81E5183886CE4223788CFE82862D842B888AF88C1CBF7B42F34242ED465514D732F4434237343D414E416F46F642443F32F645231DDA
+:80FD8000445F54B442F445474A74449644654454752C51223F3158333F3C547775577765B342F44342255A22AD466576475757654456424E424B4C2BCC37181F387A87F5A4852B88CAE828F88E8EFF68F88A8C6514F48C96FF29032110068014844401008044032440820400000040140120140200002501414002244824400244400485A2
+:80FE0000245848F0B18B80040023043400442111213042000000002400502240420410064004000000201401410046124422084110F41E91D034F4112485F3112487141F41324A1D24AB141D24AB9419B24A19B54A3924AF1439242F147924D812F924481CF9244A1CF8244A16F1244A96E1A26459ACE449C24A1F49C2421F4952281F496F
+:80FE80007248F29124A7241F48B24AD141B64A9921AB9451AB9443B24A39242B94478229F924484CF9244A4F5F0B4D4B1AD638E4417248F11124A3D441921A1D44AD941D44ABB451ABB453D21AB924F4429147822D917F8284F9265A1CF925CA5A78252AE9A26459BCE419C24A1FC9C2489E648D439A7248B3917248F2812489B181D64A5D
+:80FF0000B181F64A344B28AF1431A4A9B1A4B442712498926F82D442F92458A307848248000000004480020000001002188009420040014008480000000000280000000025015FEB0C640011000000000025010021000000001002441004000061000000008A0482444200440081246F4A0F20481284582110140200005042100400004424
+:80FF8000401442144402100225042100400600440000000010088114C11FA24741240C7188004121100426043542044502400260416048214400411121100A219044000040140422800842004012483114DFC60424000011210000000000000000000024442400444004400240140200004A0810040045081048789E07000000000000245D
+:020000040001F9
+:80000000840000000000000000000000000000001002000000880000F0E9D90000218001008302220000004841614290444002C04400004004241004004200820014004810180800F04CBC0040020000800228240000800421421004240000000000004400800480081001200489180800F02F4E000000120010080081000040140480040C
+:8000800000304400004004100200004002000000000000F066E5000000008241212481400200240010020010080000000000000000001812001811000000183FB90B910021400114004100000000002100001008400421000010020040041004002140020000443F7A0100002200290C0000401808210000000044000000000044411200CE
+:80010000000000004001000080F25DEB1001108202100240024002844002000000404408100421000010840100440020010040020000221F140700001001195424008400814002000000008100000000004502000000200140220100000041BF3E0E000000000000000000004100000000000000000000000000000000000000AFC40F00E6
+:800180004100008424004002004008640044440000100400210010020000000020010010280100A0AE00000021000000000000000000000000000000000000008001000000120000F0B3870000000081001008841048040040044044044400000000000000000000184400128081211108EF150C000000000044000000001002000000003B
+:80020000000000000000008001000000000000FF4D0800000000100444000000108204000000000000000000000000000020010000009F7D044400708804410000210024002410441414140240044421100240020000000018000020018041410812F09A9600820000008400000044002400210000000000000000000000000000000020DD
+:800280000114F0177940084800000000448042044400004840C414444C48440400140084800400002001448022014412000021F06DB100820086041008000081104A042424244C5444410045044441240000000000000018001880011289C111804109DF6B052008004044582800810010048421216914044441444044020000001002003C
+:800300000000002081018001121E18C011F043824004411018020044412124400441004544042440140441410000212400000000A011120010044C01120000F0D4B64004444044420C4481100AA1504A1002000000400224442440022400000000000012301420018414846081F073480045141454884554C4455CA84554AAA55A8A6552C3
+:80038000EAA51A4A1A52666F44445444214144401642566225022552222502210000001A21A1111A51444514E441A1118B1189A1118F81518885F892E450444FC4149444C55C448181855A4465048F8252AE2D2445544CA42145F444444F4454642B11F0849445D46458662544543150128548E28414820400001AF114141AE1438381126B
+:8004000044A4118B118F11F1181AA5082B113F3C0A45844404C50C818145568825042C528C25048556822465F646446554444D1445C4822512421216444102842448210000001AE14101281AA1114B11441A61811AF11818211A81F143C800CD444442855A66E55C8845568825568A8D2A412762E55C6C254852266F44F4444445D644514C
+:80048000444F615866676865145424254112415A228914220400001AE141014922F134144B111E141AE181A1111AF11A188FA181F1DF7100001004004184400840440884244004440000000000000000000000000000200112008170220482000000000010080000100448004002002150224002240000000000000000000000E0E10F2C72
+:80050000F4112485F2112483F41124A3D441F24A121D24AF249921AF2419F54A9243F24A9343F2429147822D914F82C4914FA2C4814FA264114FA264192E4A96C54A9E24ACF491242CF4912485F2912483F49124A3F48124AB141D24AB9419B24A19B54A3924AB9443B242792498924F8284F9244AAF6A0E4D4A1B61CD421B2187241FC129
+:8005800032441D282F24D1C1F242961D2C2F24DB85F2429226F84A9743F2429147822D916F82D412E9A2C5952ECA1E852E4A96F5244A96C14B9E25ACF4912CACF491648D421F4932481F49324A1F48B24AF11124AF44F91124ABA41B21AF4428F34A8443B24A3924A9B93694824FA2F514FE40084800000000448002000000100218800832
+:8006000000001400848004000000400428000000002501EF5A0D82000010084002000000000000000000000000002800000080010000000000005F870B2008000000000020010000480000004602000000000000000000000000001140015FF50B2004001008401204228001000024001220084800100110084228000000100422000000D2
+:80068000400314121FDE0E000000000000000000004200000024000000000000000080010000000000002F160B00240000004001000000000000000000000000000000820000000000000040F82F580000002400120000000000840000000021100222000000002100208101180000100800F0AC7F004002002100400100000000000000E8
+:800700004002240022000000002100808101180000000040F84A3C00000000200100000000400800000000000000000000200800000000008400003FF401000000000000000000000000000000001002440000000000000000000000414FCE07004412100200003100120000004800001004844100000022000000000018000000848001E9
+:8007800077DA00000000100100000000000000000000180000000000002004000000000000F0AC230040240121001100250100000000000000444098140021002002000080040000000040081844EFB30500000000000000180000004800000000000010040000000000200100000000F07BA34004100400810011000000000000004004CC
+:80080000000000000000000000000000000000705B06000000000000000000240000400800002400000000000000000000000000001BAC000000000000000000000000000000000000000000000000000000000000FFE40F000000000000000000100200100800002400000000000000000000000000009F270D000000000000000000003D
+:8008800000000000000000000000000000000000000000F04FFE00008400000000000000000000000000000000000084000000840000000000F07DAB004001000040010000000000000000001800002120010000000000000080020000AF2501000000810000000000000000000000000000000000000000000000180000F0F7B5000000AF
+:80090000000000000000000000000000000000000000000000000000000000FFE40F0010010000000000000000000000000000000000000000000000000000008F8301000000000000000000400200000000000000000000000000000000000000EFFA0F000000000000000000000000002400000000000000000000000000000000EFE232
+:8009800009001411008100000000000000000040022001000020010084000000810000800300009F6F0300400800001400000000002100000000000010020000000000000000000000F0E6BA000000000000000000000000000000000000000000000000000000000000FFE40F0014000000540000004400100240040021800188281002B4
+:800A00001880088400008042080000280000F0B25D004001008004548588022148400428100240042810828401882810828441848842188204441828842148E041012810A21140C435000000000080044400004840040000400400000080020000880000008002000000001D2A004001000040050000400400210044001002188088022136
+:800A80008001884008000028840000800200002FDB050000000000000000000000000000000000000000000000000000000000F04FFE000000000000000000000000000000000000000000000000000000000000FFE40F0021000000800400281082040028000000280048000000484004281082044400108204440010B23F0A00000000CB
+:800B000000000000000000000000000000000000000000000000000000F04FFE004001000000004400000044000000440000800200008800000000002800000000F0C36D000000000000000000000000000000000000000000000000000000000000FFE40F00140000000000000000000000000000800200008800000000000000000000C9
+:550B8000EF880A00000000000044000000440000004400000000000000000000002800000000D0B2F3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFF72
+:00000001FF
diff --git a/xpp/utils/Makefile b/xpp/utils/Makefile
new file mode 100644
index 0000000..d840333
--- /dev/null
+++ b/xpp/utils/Makefile
@@ -0,0 +1,50 @@
+PEDANTIC = -ansi -pedantic -std=c99
+
+CC = gcc
+RANLIB = ranlib
+INSTALL = install
+INSTALL_DATA = install -m 644
+
+BINDIR = /usr/sbin
+DATADIR = /usr/share/zaptel
+MANDIR = /usr/share/man/man8
+HOTPLUG_USB_DIR = /etc/hotplug/usb
+
+DATA_FILES = $(wildcard ../init_data_*.cmd *.hex)
+
+CFLAGS = -g -Wall $(EXTRA_CFLAGS)
+
+TARGETS = libhexfile.a fpga_load test_parse
+
+all: $(TARGETS)
+
+install: all
+ $(INSTALL) -d $(DESTDIR)$(BINDIR)
+ $(INSTALL) genzaptelconf fpga_load $(DESTDIR)$(BINDIR)/
+ $(INSTALL) -d $(DESTDIR)$(DATADIR)
+ $(INSTALL_DATA) $(DATA_FILES) $(DESTDIR)$(DATADIR)/
+ $(INSTALL) ../initialize_registers $(DESTDIR)$(DATADIR)/
+ $(INSTALL) -d $(DESTDIR)$(MANDIR)
+ $(INSTALL_DATA) fpga_load.8 genzaptelconf.8 $(DESTDIR)$(MANDIR)/
+ $(INSTALL) -d $(DESTDIR)$(HOTPLUG_USB_DIR)
+ $(INSTALL_DATA) xpp_fxloader.usermap $(DESTDIR)$(HOTPLUG_USB_DIR)/
+ $(INSTALL) xpp_fxloader $(DESTDIR)$(HOTPLUG_USB_DIR)/
+
+libhexfile.a: hexfile.o
+ $(AR) cru $@ $^
+ $(RANLIB) $@
+
+fpga_load: fpga_load.o libhexfile.a
+ $(CC) -L. -o $@ $@.o $(EXTRA_LIBS) -lhexfile -lusb
+
+hexfile.o: hexfile.c hexfile.h
+ $(CC) $(CFLAGS) $(PEDANTIC) -c $*.c
+
+test_parse.o: test_parse.c hexfile.h
+ $(CC) $(CFLAGS) $(PEDANTIC) -c $*.c
+
+test_parse: test_parse.o libhexfile.a
+ $(CC) -L. -o $@ $@.o $(EXTRA_LIBS) -lhexfile -lusb
+
+clean:
+ $(RM) *.o $(TARGETS)
diff --git a/xpp/utils/USB_1130.hex b/xpp/utils/USB_1130.hex
new file mode 100644
index 0000000..5f97b5f
--- /dev/null
+++ b/xpp/utils/USB_1130.hex
@@ -0,0 +1,309 @@
+#
+# $Id: USB_1130.hex 1124 2006-05-02 09:42:14Z zohar $
+#
+:100E2800000102030405060708090A0B0C0D0E0F42
+:080E380041001000410011000F
+:1009B80090E600E054E74410F000000090E604746C
+:1009C80080F00000007406F0000000E4F000000071
+:1009D80090E6107420F000000090E611F00000008E
+:1009E80090E61274A2F000000090E61374A0F000E4
+:1009F800000090E61474E2F000000090E61574E040
+:100A0800F000000090E6047480F00000007404F028
+:100A1800000000E4F000000090E6497482F0000055
+:100A280000F000000090E6187410F000000090E656
+:100A38001A740CF000000090E619E054FEF0000073
+:100A48000090E61BE054FEF000000090E6917480F0
+:100A5800F0000000F000000090E695F0000000F0C3
+:070A680000000043AF012272
+:1005A10078007C007D017BFF7A0E79287E007F1028
+:1005B1001204FBC205E5AA30E2030206E2E5AA3015
+:1005C100E7030206E275310075320490F400E0247D
+:1005D100FE700302067524FA700302069124F87076
+:1005E100030206BA240F60030206BE90FC007401E8
+:1005F100F090F401E090FC01F090F402E090FC0234
+:10060100F0D2B690F401E0701AA3E0701630B01386
+:1006110074C0120D44C2B67F08120D4AD2B67F08CB
+:10062100120D4A30B04690E694E0FE90E695E07CEB
+:10063100002400FFEC3ECF24FCCF34FFFE7B017A87
+:10064100F47904120AFB501C90FC0330B4117408B5
+:10065100F07FE87E03120D4C7403120D44806A741E
+:1006610004F0806590FC037402F0805D90FC0374DB
+:1006710001F0805590FC007402F0E4A3F0A3F03087
+:10068100B406A37410F0804190FC037420F080390B
+:1006910075310075321190FC007408F07A007B000E
+:1006A1007D017F50120D9E7F50120BCC7AFC7B0195
+:1006B1007D107F50120D828010D202800C753100A6
+:1006C10075320190FC0074AAF0E53190E69CF000CF
+:1006D1000000E53290E69DF000000090E695748000
+:0106E100F028
+:0106E20022F5
+:0C0D440090E601F07F147E007D007C0032
+:100D50008F368E358D348C33783374FF120583ECE7
+:060D60004D4E4F70F3221E
+:0A0AFB008E338F348B358A3689372D
+:100B0500E4F538F539C3E5399534E538953350338F
+:100B1500AB35AA36A937853982853883120521FF79
+:100B2500E4FEC2B2EF1392B7EFC313FFD2B20EBE0B
+:100B350008F0C2B220B002C3220539E53970C605F6
+:040B45003880C2D35F
+:010B49002289
+:02004100D322C8
+:02004E00D322BB
+:02005000D322B9
+:080E460090E6BAE0F53BD3226F
+:1007EB0090E740E53BF0E490E68AF090E68B04F06E
+:0207FB00D32207
+:080E4E0090E6BAE0F53AD32268
+:100E160090E740E53AF0E490E68AF090E68B04F03D
+:020E2600D322D5
+:0207FD00D32205
+:0208FB00D32206
+:0208FD00D32204
+:100CF70090E6B9E0242F600D04701990E604E0FF38
+:100D0700430780800890E604E0FF53077F00000058
+:070D1700EFF08002D322C3BC
+:010D1E0022B2
+:100DBA00C0E0C083C082D2015391EF90E65D740116
+:080DCA00F0D082D083D0E032AA
+:100DEA00C0E0C083C0825391EF90E65D7404F0D0F6
+:060DFA0082D083D0E0323C
+:100E0000C0E0C083C0825391EF90E65D7402F0D0E1
+:060E100082D083D0E03225
+:100C0400C0E0C083C08285130F85141085108285CF
+:100C14000F83A37402F0850B11850C128512828553
+:100C24001183A37407F05391EF90E65D7410F0D034
+:060C340082D083D0E03203
+:100DD200C0E0C083C082D2045391EF90E65D7408F4
+:080DE200F0D082D083D0E03292
+:1008BE00C0E0C083C08290E680E030E720850B0F59
+:1008CE00850C10851082850F83A37402F085131199
+:1008DE00851412851282851183A37407F05391EF4C
+:0D08EE0090E65D7420F0D082D083D0E0321F
+:01003200329B
+:01004A003283
+:01005200327B
+:0107FF0032C7
+:0108FF0032C6
+:010E5E003261
+:010E5F003260
+:010E6000325F
+:010E6100325E
+:010E6200325D
+:010E6300325C
+:010E6400325B
+:010E6500325A
+:010E66003259
+:010E67003258
+:010E68003257
+:010E69003256
+:010E6A003255
+:010E6B003254
+:010E6C003253
+:010E6D003252
+:010E6E003251
+:010E6F003250
+:010E7000324F
+:010E7100324E
+:010E7200324D
+:010E7300324C
+:010E7400324B
+:010E7500324A
+:010E76003249
+:010E77003248
+:010E78003247
+:010E79003246
+:010E7A003245
+:100B9000C0E0C083C08290E6D1E0900010F090E603
+:100BA000D0E4F000000090E6D17402F000000053A1
+:100BB00091BF00000090E66104F000000090E6990B
+:0C0BC00004F075BB06D082D083D0E03278
+:010E7B003244
+:100D66001201000200000040E4E43211000001021A
+:0C0D760000010001020203030404050553
+:050E40000308FF0D6630
+:10028D00E4F52CF52BF52AF529C204C200C203C2F0
+:10029D0001C202D2B675B5C4D2B61209B8120E5645
+:1002AD007E087F008E0D8F0E751508751612750B55
+:1002BD0008750C1C75130875144A75170875187890
+:1002CD00EE54C07003020398752D00752E808E2F8D
+:1002DD008F30C374BC9FFF74089ECF2402CF3400AF
+:1002ED00FEE48F288E27F526F525F524F523F52236
+:1002FD00F521AF28AE27AD26AC25AB24AA23A92224
+:10030D00A821C31205705031AE23AF24E5302FF56F
+:10031D0082E52F3EF583E0FDE52E2FF582E52D3E9E
+:10032D00F583EDF0EF2401F524E43EF523E43522C9
+:10033D00F522E43521F52180B9852D0D852E0E741C
+:10034D00002480FF740834FFFEC3E5169FF516E503
+:10035D00159EF515C3E5109FF510E50F9EF50FC31E
+:10036D00E5129FF512E5119EF511C3E50C9FF50CF5
+:10037D00E50B9EF50BC3E5149FF514E5139EF513E0
+:10038D00C3E5189FF518E5179EF517D2E843D82059
+:10039D0090E668E0440BF090E65CE0443DF0000030
+:1003AD0000E4F5A2000000D2AF90E680E020E10568
+:1003BD00D20512000390E680E054F7F0538EF8C298
+:1003CD00041205A130022190E680E054FDF0E054C6
+:1003DD00F7F0750D0D750E66D20512000390E680CF
+:1003ED00E04402F0C204C202300105120056C201FF
+:1003FD003004CE12004150C9C204120D1F20001648
+:10040D0090E682E030E704E020E1EF90E682E03014
+:0E041D00E604E020E0E4120CA012004E80A3E2
+:0B00360090E50DE030E402C322D3226D
+:1000560090E6B9E0700302011514700302019224C0
+:10006600FE700302021524FB700302010F147003D5
+:100076000201091470030200FD1470030201032437
+:10008600056003020279120050400302028590E6E1
+:10009600BBE024FE602A14603B24FD601114602A34
+:1000A60024067050E50D90E6B3F0E50E803C120094
+:1000B60036503EE51590E6B3F0E516802D02027443
+:1000C600E50F90E6B3F0E5108020E51190E6B3F079
+:1000D600E512801690E6BAE0FF120CCCAA06A90734
+:1000E600EA49600DEE90E6B3F0EF90E6B4F0020256
+:1000F60085020274020274120E16020285120E4E58
+:10010600020285120E460202851207EB02028512D2
+:1001160007FD400302028590E6B8E0247F601514CF
+:10012600601924027063A200E43325E0FFA203E411
+:10013600334F8041E490E740F0803F90E6BCE054C6
+:100146007EFF7E00E0D394807C0040047D01800227
+:100156007D00EC4EFEED4F2478F582740D3EF5835E
+:10016600E493FF3395E0FEEF24A1FFEE34E68F82A1
+:10017600F583E0540190E740F0E4A3F090E68AF0BE
+:1001860090E68B7402F00202850202741208FB40AC
+:100196000302028590E6B8E024FE6016240260039E
+:1001A60002028590E6BAE0B40105C20002028502A9
+:1001B600027490E6BAE0705590E6BCE0547EFF7E8D
+:1001C60000E0D394807C0040047D0180027D00EC39
+:1001D6004EFEED4F2478F582740D3EF583E493FFD1
+:1001E6003395E0FEEF24A1FFEE34E68F82F583E03F
+:1001F60054FEF090E6BCE05480131313541FFFE046
+:10020600540F2F90E683F0E04420F08072805F1256
+:1002160008FD506B90E6B8E024FE60192402704E8B
+:1002260090E6BAE0B40104D200805490E6BAE064E5
+:1002360002604C803990E6BCE0547EFF7E00E0D33D
+:1002460094807C0040047D0180027D00EC4EFEED32
+:100256004F2478F582740D3EF583E493FF3395E0E1
+:10026600FEEF24A1FFEE34E68F82F583800D90E643
+:10027600A08008120CF7500790E6A0E04401F09029
+:06028600E6A0E04480F058
+:01028C00224F
+:0300330002004682
+:0400460053D8EF326A
+:100CA00090E682E030E004E020E60B90E682E0305F
+:100CB000E119E030E71590E680E04401F07F147E12
+:0C0CC00000120B4A90E680E054FEF02287
+:1000030030050990E680E0440AF0800790E680E03E
+:100013004408F07FDC7E05120B4A90E65D74FFF026
+:0F00230090E65FF05391EF90E680E054F7F02203
+:080E5600E4F51ED2E9D2AF223F
+:100BCC00AD0790E678E020E6F9C2E990E678E044DB
+:100BDC0080F0ED25E090E679F090E678E030E0F9F1
+:100BEC0090E678E04440F090E678E020E6F990E674
+:080BFC0078E030E1D6D2E922D5
+:100C6E00AC0790E678E020E6F9E51E702390E67872
+:100C7E00E04480F0EC25E090E679F08D19AF03A901
+:100C8E0007751A018A1B891CE4F51D751E01D322F6
+:020C9E00C3226F
+:100C3A00AC0790E678E020E6F9E51E702590E678A4
+:100C4A00E04480F0EC25E0440190E679F08D19AF9C
+:100C5A0003A907751A018A1B891CE4F51D751E0371
+:040C6A00D322C322AC
+:03004B000206E3C7
+:1006E300C0E0C083C082C085C084C086758600C058
+:1006F300D075D000C000C001C002C003C006C0074F
+:1007030090E678E030E206751E060207CD90E678A3
+:10071300E020E10CE51E64026006751E070207CDAA
+:10072300E51E24FE605F14603624FE70030207BEDC
+:1007330024FC70030207CA240860030207CDAB1A26
+:10074300AA1BA91CAF1D051D8F82758300120521ED
+:1007530090E679F0E51D65197070751E05806B9044
+:10076300E679E0AB1AAA1BA91CAE1D8E8275830025
+:1007730012054E751E02E5196401704E90E678E08D
+:100783004420F08045E51924FEB51D0790E678E086
+:100793004420F0E51914B51D0A90E678E04440F0D2
+:1007A300751E0090E679E0AB1AAA1BA91CAE1D8E3C
+:1007B3008275830012054E051D800F90E678E04494
+:1007C30040F0751E008003751E005391DFD007D0E3
+:1007D30006D003D002D001D000D0D0D086D084D0B0
+:0807E30085D082D083D0E03202
+:020CCC00A90776
+:100CCE00AE17AF188F828E83A3E064037017AD0149
+:100CDE0019ED7001228F828E83E07C002FFDEC3E99
+:080CEE00FEAF0580DFE4FEFF0C
+:010CF60022DB
+:100D8200120C3AE51E24FA600E146006240770F372
+:0C0D9200D322E4F51ED322E4F51ED32288
+:100D9E00120C6EE51E24FA600E146006240770F322
+:0C0DAE00D322E4F51ED322E4F51ED3226C
+:100D1F0090E682E044C0F090E681F0438701000046
+:040D2F00000000229E
+:100B4A008E318F3290E600E054187012E53224019B
+:100B5A00FFE43531C313F531EF13F532801590E612
+:100B6A0000E05418FFBF100BE53225E0F532E531FD
+:100B7A0033F531E5321532AE31700215314E60056A
+:060B8A00120D3380EE2283
+:100D33007400F58690FDA57C05A3E582458370F9D3
+:010D4300228D
+:100800001201000200000040E4E431110000010286
+:1008100000010A06000200000040010009022E004B
+:1008200001010080320904000004FF0000000705F8
+:10083000020200020007050402000200070586020A
+:100840000002000705880200020009022E000101D3
+:100850000080320904000004FF00000007050202C6
+:100860004000000705040240000007058602400022
+:10087000000705880240000004030904180358001B
+:100880006F00720063006F006D0020004C00740068
+:1008900064002E0028035800500044002800420045
+:1008A000610073006500640020006F006E0020008E
+:0E08B000410058005500500050002900000083
+:03004300020900AF
+:030053000209009F
+:10090000020DBA00020E0000020DEA00020DD20034
+:10091000020C04000208BE000200320002004A007D
+:10092000020052000207FF000208FF00020E5E00F4
+:10093000020E5F00020E6000020E6100020E6200F5
+:10094000020E630002004A00020E6400020E6500FF
+:10095000020E6600020E6700020E6800020E6900B9
+:10096000020E6A0002004A0002004A0002004A0029
+:10097000020E6B00020E6C00020E6D00020E6E0085
+:10098000020E6F00020E7000020E7100020E720065
+:10099000020E7300020E7400020E7500020E760045
+:1009A000020E7700020E7800020E7900020E7A0025
+:0809B000020B9000020E7B0017
+:03000000020A6F82
+:0C0A6F00787FE4F6D8FD75813B020AB6E2
+:10042B00E709F608DFFA8046E709F208DFFA803EB3
+:10043B0088828C83E709F0A3DFFA8032E309F608A0
+:10044B00DFFA8078E309F208DFFA807088828C8308
+:10045B00E309F0A3DFFA806489828A83E0A3F608BC
+:10046B00DFFA805889828A83E0A3F208DFFA804C96
+:10047B0080D280FA80C680D4806980F2803380106D
+:10048B0080A680EA809A80A880DA80E280CA8033D6
+:10049B0089828A83ECFAE493A3C8C582C8CCC5834E
+:1004AB00CCF0A3C8C582C8CCC583CCDFE9DEE7801E
+:1004BB000D89828A83E493A3F608DFF9ECFAA9F09D
+:1004CB00EDFB2289828A83ECFAE0A3C8C582C8CCF3
+:1004DB00C583CCF0A3C8C582C8CCC583CCDFEADE0C
+:1004EB00E880DB89828A83E493A3F208DFF980CC6E
+:1004FB0088F0EF60010E4E60C388F0ED2402B40467
+:10050B000050B9F582EB2402B4040050AF2323450D
+:06051B00822390047B73B3
+:10052100BB010CE58229F582E5833AF583E022508F
+:1005310006E92582F8E622BBFE06E92582F8E222D9
+:0D054100E58229F582E5833AF583E49322F3
+:10054E00F8BB010DE58229F582E5833AF583E8F0E3
+:10055E00225006E92582C8F622BBFE05E92582C88F
+:02056E00F22277
+:10057000EB9FF5F0EA9E42F0E99D42F0E89C45F0E1
+:010580002258
+:100581007401FF3395E0FEFDFC080808E6CF2FF665
+:1005910018E6CE3EF618E6CD3DF618E6CC3CF6223E
+:100A7B0002028DE493A3F8E493A34003F68001F202
+:100A8B0008DFF48029E493A3F85407240CC8C3337C
+:100A9B00C4540F4420C8834004F456800146F6DF4B
+:100AAB00E4800B0102040810204080900E38E47E95
+:100ABB00019360BCA3FF543F30E509541FFEE49340
+:100ACB00A360010ECF54C025E060A840B8E493A307
+:100ADB00FAE493A3F8E493A3C8C582C8CAC583CA32
+:100AEB00F0A3C8C582C8CAC583CADFE9DEE780BEEA
+:010E450000AC
+:00000001FF
+ \ No newline at end of file
diff --git a/xpp/utils/USB_8613.hex b/xpp/utils/USB_8613.hex
new file mode 100644
index 0000000..424c072
--- /dev/null
+++ b/xpp/utils/USB_8613.hex
@@ -0,0 +1,301 @@
+:100E0700000102030405060708090A0B0C0D0E0F63
+:080E1700410010004100110030
+:1009B80090E600E054E74410F000000090E604746C
+:1009C80080F00000007406F0000000E4F000000071
+:1009D80090E6107420F000000090E611F00000008E
+:1009E80090E61274A2F000000090E61374A0F000E4
+:1009F800000090E61474E2F000000090E61574E040
+:100A0800F000000090E6047480F00000007404F028
+:100A1800000000E4F000000090E6497482F0000055
+:100A280000F000000090E6187410F000000090E656
+:100A38001A7408F090E6917480F0000000F000004D
+:100A48000090E695F0000000F000000043AF01229E
+:1005B30078007C007D017BFF7A0E79077E007F1037
+:1005C30012050DC204E5AA30E2030206E9E5AA30EA
+:1005D300E7030206E975310075320490F400E02464
+:1005E300FE700302068024FA700302069C2407604F
+:1005F300030206C590FC007401F090F401E090FC46
+:1006030001F090F402E090FC02F0D2B690F401E025
+:10061300701AA3E0701630B01374C0120D2DC2B659
+:100623007F08120D33D2B67F08120D3330B04690D7
+:10063300E694E0FE90E695E07C002400FFEC3ECFDC
+:1006430024FCCF34FFFE7B017AF47904120AE450D0
+:100653001C90FC0330B4117408F07FE87E03120D84
+:10066300357403120D2D80667404F0806190FC03D1
+:100673007402F0805990FC037401F0805190FC00E7
+:100683007402F0E4A3F0A3F030B406A37410F08076
+:100693003D90FC037420F080357531007532119064
+:1006A300FC007408F07A007B007D017F50120D6B13
+:1006B3007F50120BB57AFC7B017D107F50120D4FDA
+:1006C300800C75310075320190FC0074AAF0E5319D
+:1006D30090E69CF0000000E53290E69DF0000000FB
+:0606E30090E6957480F022
+:0106E90022EE
+:0C0D2D0090E601F07F147E007D007C0049
+:100D39008F368E358D348C33783374FF120595ECEC
+:060D49004D4E4F70F32235
+:0A0AE4008E338F348B358A36893744
+:100AEE00E4F538F539C3E5399534E53895335033A7
+:100AFE00AB35AA36A937853982853883120533FF7F
+:100B0E00E4FEC2B2EF1392B7EFC313FFD2B20EBE22
+:100B1E0008F0C2B220B002C3220539E53970C6050D
+:040B2E003880C2D376
+:010B320022A0
+:02004100D322C8
+:02004E00D322BB
+:02005000D322B9
+:080E200090E6BAE0F51DD322B3
+:100DE30090E740E51DF0E490E68AF090E68B04F08E
+:020DF300D32209
+:080E280090E6BAE0F51CD322AC
+:100DF50090E740E51CF0E490E68AF090E68B04F07D
+:020E0500D322F6
+:0207FC00D32206
+:0207FE00D32204
+:0208FB00D32206
+:100CE00090E6B9E0242F600D04701990E604E0FF4F
+:100CF000430780800890E604E0FF53077F00000070
+:070D0000EFF08002D322C3D3
+:010D070022C9
+:100D8700C0E0C083C082D2015391EF90E65D740149
+:080D9700F0D082D083D0E032DD
+:100DB700C0E0C083C0825391EF90E65D7404F0D029
+:060DC70082D083D0E0326F
+:100DCD00C0E0C083C0825391EF90E65D7402F0D015
+:060DDD0082D083D0E03259
+:100BED00C0E0C083C08285100C85110D850D8285F6
+:100BFD000C83A37402F085080E85090F850F82857D
+:100C0D000E83A37407F05391EF90E65D7410F0D04E
+:060C1D0082D083D0E0321A
+:100D9F00C0E0C083C082D2035391EF90E65D740828
+:080DAF00F0D082D083D0E032C5
+:1008BE00C0E0C083C08290E680E030E72085080C5F
+:1008CE0085090D850D82850C83A37402F085100EAB
+:1008DE0085110F850F82850E83A37407F05391EF58
+:0D08EE0090E65D7420F0D082D083D0E0321F
+:01003200329B
+:01004A003283
+:01005200327B
+:0108FD0032C8
+:0108FE0032C7
+:0108FF0032C6
+:010E38003287
+:010E39003286
+:010E3A003285
+:010E3B003284
+:010E3C003283
+:010E3D003282
+:010E3E003281
+:010E3F003280
+:010E4000327F
+:010E4100327E
+:010E4200327D
+:010E4300327C
+:010E4400327B
+:010E4500327A
+:010E46003279
+:010E47003278
+:010E48003277
+:010E49003276
+:010E4A003275
+:010E4B003274
+:010E4C003273
+:010E4D003272
+:010E4E003271
+:010E4F003270
+:010E5000326F
+:010E5100326E
+:010E5200326D
+:010E5300326C
+:100B7900C0E0C083C08290E6D1E0900010F090E61A
+:100B8900D0E4F000000090E6D17402F000000053B8
+:100B990091BF00000090E66104F000000090E69922
+:0C0BA90004F075BB06D082D083D0E0328F
+:010E5400326B
+:0A07F20000010202030304040505E0
+:10028D00E4F52CF52BF52AF529C203C200C202C2F2
+:10029D0001D2B675B5C4D2B61209B8120E307E08A9
+:1002AD007F008E0A8F0B751208751312750808756D
+:1002BD00091C75100875114A751408751578EE54DA
+:1002CD00C07003020396752D00752E808E2F8F3012
+:1002DD00C374BC9FFF74089ECF2402CF3400FEE48C
+:1002ED008F288E27F526F525F524F523F522F52102
+:1002FD00AF28AE27AD26AC25AB24AA23A922A82171
+:10030D00C31205825031AE23AF24E5302FF582E5BF
+:10031D002F3EF583E0FDE52E2FF582E52D3EF5838D
+:10032D00EDF0EF2401F524E43EF523E43522F5222A
+:10033D00E43521F52180B9852D0A852E0B74002415
+:10034D0080FF740834FFFEC3E5139FF513E5129E7D
+:10035D00F512C3E50D9FF50DE50C9EF50CC3E50FEC
+:10036D009FF50FE50E9EF50EC3E5099FF509E5080E
+:10037D009EF508C3E5119FF511E5109EF510C3E537
+:10038D00159FF515E5149EF514D2E843D82090E697
+:10039D0068E0440BF090E65CE0443DF0000000E4C2
+:1003AD00F5A2000000D2AFD20412000390E680E067
+:1003BD0054F7F0538EF8C20390E6C2E054FBF00000
+:1003CD00000000000090E619E054FEF000000090DF
+:1003DD00E61BE054FEF000000090E6187410F000EB
+:1003ED00000090E61A740CF0000000000000000000
+:1003FD000090E6017403F01205B3300105120056AA
+:10040D00C2013003F212004150EDC203120D08205B
+:10041D00001690E682E030E704E020E1EF90E682FE
+:10042D00E030E604E020E0E4120C8912004E80C7B3
+:0B00360090E50DE030E402C322D3226D
+:1000560090E6B9E0700302011514700302019224C0
+:10006600FE700302021524FB700302010F147003D5
+:100076000201091470030200FD1470030201032437
+:10008600056003020279120050400302028590E6E1
+:10009600BBE024FE602A14603B24FD601114602A34
+:1000A60024067050E50A90E6B3F0E50B803C12009A
+:1000B60036503EE51290E6B3F0E513802D02027449
+:1000C600E50C90E6B3F0E50D8020E50E90E6B3F082
+:1000D600E50F801690E6BAE0FF120CB5AA06A9074E
+:1000E600EA49600DEE90E6B3F0EF90E6B4F0020256
+:1000F60085020274020274120DF5020285120E28A0
+:10010600020285120E20020285120DE302028512FA
+:1001160007FC400302028590E6B8E0247F601514D0
+:10012600601924027063A200E43325E0FFA202E412
+:10013600334F8041E490E740F0803F90E6BCE054C6
+:100146007EFF7E00E0D394807C0040047D01800227
+:100156007D00EC4EFEED4F24F2F58274073EF583EA
+:10016600E493FF3395E0FEEF24A1FFEE34E68F82A1
+:10017600F583E0540190E740F0E4A3F090E68AF0BE
+:1001860090E68B7402F00202850202741207FE40AA
+:100196000302028590E6B8E024FE6016240260039E
+:1001A60002028590E6BAE0B40105C20002028502A9
+:1001B600027490E6BAE0705590E6BCE0547EFF7E8D
+:1001C60000E0D394807C0040047D0180027D00EC39
+:1001D6004EFEED4F24F2F58274073EF583E493FF5D
+:1001E6003395E0FEEF24A1FFEE34E68F82F583E03F
+:1001F60054FEF090E6BCE05480131313541FFFE046
+:10020600540F2F90E683F0E04420F08072805F1256
+:1002160008FB506B90E6B8E024FE60192402704E8D
+:1002260090E6BAE0B40104D200805490E6BAE064E5
+:1002360002604C803990E6BCE0547EFF7E00E0D33D
+:1002460094807C0040047D0180027D00EC4EFEED32
+:100256004F24F2F58274073EF583E493FF3395E06D
+:10026600FEEF24A1FFEE34E68F82F583800D90E643
+:10027600A08008120CE0500790E6A0E04401F09040
+:06028600E6A0E04480F058
+:01028C00224F
+:0300330002004682
+:0400460053D8EF326A
+:100C890090E682E030E004E020E60B90E682E03076
+:100C9900E119E030E71590E680E04401F07F147E29
+:0C0CA90000120B3390E680E054FEF022B5
+:1000030030040990E680E0440AF0800790E680E03F
+:100013004408F07FDC7E05120B3390E65D74FFF03D
+:0F00230090E65FF05391EF90E680E054F7F02203
+:080E3000E4F51BD2E9D2AF2268
+:100BB500AD0790E678E020E6F9C2E990E678E044F2
+:100BC50080F0ED25E090E679F090E678E030E0F908
+:100BD50090E678E04440F090E678E020E6F990E68B
+:080BE50078E030E1D6D2E922EC
+:100C5700AC0790E678E020E6F9E51B702390E6788C
+:100C6700E04480F0EC25E090E679F08D16AF03A91B
+:100C7700077517018A188919E4F51A751B01D3221C
+:020C8700C32286
+:100C2300AC0790E678E020E6F9E51B702590E678BE
+:100C3300E04480F0EC25E0440190E679F08D16AFB6
+:100C430003A9077517018A188919E4F51A751B0397
+:040C5300D322C322C3
+:03004B000206EAC0
+:1006EA00C0E0C083C082C085C084C086758600C051
+:1006FA00D075D000C000C001C002C003C006C00748
+:10070A0090E678E030E206751B060207D490E67898
+:10071A00E020E10CE51B64026006751B070207D4A2
+:10072A00E51B24FE605F14603624FE70030207C5D1
+:10073A0024FC70030207D1240860030207D4AB1714
+:10074A00AA18A919AF1A051A8F82758300120533E0
+:10075A0090E679F0E51A65167070751B05806B9046
+:10076A00E679E0AB17AA18A919AE1A8E827583002A
+:10077A00120560751B02E5166401704E90E678E07A
+:10078A004420F08045E51624FEB51A0790E678E085
+:10079A004420F0E51614B51A0A90E678E04440F0D1
+:1007AA00751B0090E679E0AB17AA18A919AE1A8E44
+:1007BA0082758300120560051A800F90E678E0447E
+:1007CA0040F0751B008003751B005391DFD007D0E2
+:1007DA0006D003D002D001D000D0D0D086D084D0A9
+:0807EA0085D082D083D0E032FB
+:020CB500A9078D
+:100CB700AE14AF158F828E83A3E064037017AD0166
+:100CC70019ED7001228F828E83E07C002FFDEC3EB0
+:080CD700FEAF0580DFE4FEFF23
+:010CDF0022F2
+:100D4F00120C23E51B24FA600E146006240770F3BF
+:0C0D5F00D322E4F51BD322E4F51BD322C1
+:100D6B00120C57E51B24FA600E146006240770F36F
+:0C0D7B00D322E4F51BD322E4F51BD322A5
+:100D080090E682E044C0F090E681F043870100005D
+:040D180000000022B5
+:100B33008E318F3290E600E054187012E5322401B2
+:100B4300FFE43531C313F531EF13F532801590E629
+:100B530000E05418FFBF100BE53225E0F532E53114
+:100B630033F531E5321532AE31700215314E600581
+:060B7300120D1C80EE22B1
+:100D1C007400F58690FDA57C05A3E582458370F9EA
+:010D2C0022A4
+:03004300020900AF
+:030053000209009F
+:10090000020D8700020DCD00020DB700020D9F0001
+:10091000020BED000208BE000200320002004A0095
+:10092000020052000208FD000208FE000208FF005B
+:10093000020E3800020E3900020E3A00020E3B0091
+:10094000020E3C0002004A00020E3D00020E3E0074
+:10095000020E3F00020E4000020E4100020E420055
+:10096000020E430002004A0002004A0002004A0050
+:10097000020E4400020E4500020E4600020E470021
+:10098000020E4800020E4900020E4A00020E4B0001
+:10099000020E4C00020E4D00020E4E00020E4F00E1
+:1009A000020E5000020E5100020E5200020E5300C1
+:0809B000020B7900020E540055
+:100800001201000200000040E4E411220000010295
+:1008100000010A06000200000040010009022E004B
+:1008200001010080320904000004FF0000000705F8
+:10083000020200020007050402000200070586020A
+:100840000002000705880200020009022E000101D3
+:100850000080320904000004FF00000007050202C6
+:100860004000000705040240000007058602400022
+:10087000000705880240000004030904180358001B
+:100880006F00720063006F006D0020004C00740068
+:1008900064002E0028035800500044002800420045
+:1008A000610073006500640020006F006E0020008E
+:0E08B000410058005500500050002900000083
+:03000000020A5899
+:0C0A5800787FE4F6D8FD758139020A9F12
+:10043D00E709F608DFFA8046E709F208DFFA803EA1
+:10044D0088828C83E709F0A3DFFA8032E309F6088E
+:10045D00DFFA8078E309F208DFFA807088828C83F6
+:10046D00E309F0A3DFFA806489828A83E0A3F608AA
+:10047D00DFFA805889828A83E0A3F208DFFA804C84
+:10048D0080D280FA80C680D4806980F2803380105B
+:10049D0080A680EA809A80A880DA80E280CA8033C4
+:1004AD0089828A83ECFAE493A3C8C582C8CCC5833C
+:1004BD00CCF0A3C8C582C8CCC583CCDFE9DEE7800C
+:1004CD000D89828A83E493A3F608DFF9ECFAA9F08B
+:1004DD00EDFB2289828A83ECFAE0A3C8C582C8CCE1
+:1004ED00C583CCF0A3C8C582C8CCC583CCDFEADEFA
+:1004FD00E880DB89828A83E493A3F208DFF980CC5C
+:10050D0088F0EF60010E4E60C388F0ED2402B40454
+:10051D000050B9F582EB2402B4040050AF232345FB
+:06052D00822390048D738F
+:10053300BB010CE58229F582E5833AF583E022507D
+:1005430006E92582F8E622BBFE06E92582F8E222C7
+:0D055300E58229F582E5833AF583E49322E1
+:10056000F8BB010DE58229F582E5833AF583E8F0D1
+:10057000225006E92582C8F622BBFE05E92582C87D
+:02058000F22265
+:10058200EB9FF5F0EA9E42F0E99D42F0E89C45F0CF
+:010592002246
+:100593007401FF3395E0FEFDFC080808E6CF2FF653
+:1005A30018E6CE3EF618E6CD3DF618E6CC3CF6222C
+:100A640002028DE493A3F8E493A34003F68001F219
+:100A740008DFF48029E493A3F85407240CC8C33393
+:100A8400C4540F4420C8834004F456800146F6DF62
+:100A9400E4800B0102040810204080900E17E47ECD
+:100AA400019360BCA3FF543F30E509541FFEE49357
+:100AB400A360010ECF54C025E060A840B8E493A31E
+:100AC400FAE493A3F8E493A3C8C582C8CAC583CA49
+:100AD400F0A3C8C582C8CAC583CADFE9DEE780BE01
+:010E1F0000D2
+:00000001FF
diff --git a/xpp/utils/fpga_load.8 b/xpp/utils/fpga_load.8
new file mode 100644
index 0000000..09dd5aa
--- /dev/null
+++ b/xpp/utils/fpga_load.8
@@ -0,0 +1,72 @@
+.TH "FPGA_LOAD" "8" "16 April 2006" "" ""
+
+.SH NAME
+ztcfg \- reads and loads zaptel.conf
+.SH SYNOPSIS
+
+.B fpga_load
+[\fB-g\fR|\fB-d\fR] [\fB-v\fR] \fB-D\fR/proc/bus/usb/\fIBUS/DEV\fR
+
+.B fpga_load
+[\fB-g\fR] [\fB-v\fR] \fB-D\fR/proc/bus/usb/\fIBUS/DEV\fR \fB-I \fIfirmware.hex\fR [\fB-b \fIdump.bin\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 -d
+.I dump.bin
+.RS
+Before writing firmware, bump the processed binary file to
+.I dump.bin\fR.
+.RE
+
+.B -d
+.RS
+Print Version number bytes from eeprom (to standard output). Implies -g.
+.RE
+
+.B -D
+.I DEVICE
+.RS
+Required. The device to read from/write to. This is normally
+/proc/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).
+.RE
+
+.B -g
+.RS
+Dump all eeprom data to standard error.
+.RE
+
+.B -I
+.I fireware_file
+.RS
+The firmware file to write to the device.
+.RE
+
+.B -v
+.RS
+Be verobse.
+.RE
+
+.B -h
+.RS
+Displays usage message.
+.RE
+
+.SH SEE ALSO
+fxload(8), lsusb(8)
+
+.SH AUTHOR
+This manual page was written by Tzafrir Cohen <tzafrir.cohen@xorcom.com> .
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/xpp/utils/fpga_load.c b/xpp/utils/fpga_load.c
new file mode 100644
index 0000000..098b980
--- /dev/null
+++ b/xpp/utils/fpga_load.c
@@ -0,0 +1,822 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <usb.h>
+#include "hexfile.h"
+
+static const char rcsid[] = "$Id$";
+
+#define ERR(fmt, arg...) fprintf(stderr, "%s: ERROR: " fmt, progname, ## arg)
+#define INFO(fmt, arg...) fprintf(stderr, "%s: " fmt, progname, ## arg)
+
+static int verbose = LOG_WARNING;
+static char *progname;
+
+#define MAX_HEX_LINES 2000
+#define PACKET_SIZE 512
+#define EEPROM_SIZE 16
+#define SERIAL_SIZE 8
+
+enum fpga_load_packet_types {
+ STATUS_REPLY = 0x01,
+ DATA_PACKET = 0x01,
+#ifdef XORCOM_INTERNAL
+ EEPROM_SET = 0x04,
+#endif
+ EEPROM_GET = 0x08,
+ RENUMERATE = 0x10,
+ 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 serial[SERIAL_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
+};
+
+int my_usb_device(struct usb_device *dev, usb_dev_handle *handle);
+
+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";
+ }
+}
+
+int path_of_dev(char buf[], unsigned int buflen, struct usb_device *dev)
+{
+ return snprintf(buf, buflen, "/proc/bus/usb/%s/%s", dev->bus->dirname, dev->filename);
+}
+
+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 prefix[] = "/proc/bus/usb/";
+ const int prefix_len = strlen(prefix);
+ const char *p;
+ int bnum;
+ int dnum;
+ int ret;
+
+ assert(path != NULL);
+ if(strncmp(prefix, path, prefix_len) != 0) {
+ ERR("wrong path: '%s'\n", path);
+ return NULL;
+ }
+ p = path + prefix_len;
+ ret = sscanf(p, "%d/%d", &bnum, &dnum);
+ if(ret != 2) {
+ ERR("wrong path tail: '%s'\n", p);
+ return NULL;
+ }
+ sprintf(dirname, "%03d", bnum);
+ sprintf(filename, "%03d", dnum);
+ for (bus = usb_busses; bus; bus = bus->next) {
+ if(strcmp(bus->dirname, dirname) != 0)
+ continue;
+ for (dev = bus->devices; dev; dev = dev->next) {
+ if(strcmp(dev->filename, filename) == 0)
+ 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);
+}
+
+/* My device parameters */
+#define MY_INTERFACE 0
+#define MY_CONFIG 1
+#define MY_ENDPOINTS 4
+
+#define MY_EP_OUT 0x04
+#define MY_EP_IN 0x88
+
+#define TIMEOUT 5000
+
+static const int my_endpoints[MY_ENDPOINTS] = {
+ 0x02,
+ 0x04,
+ 0x86,
+ 0x88
+};
+
+void usb_cleanup(usb_dev_handle *handle)
+{
+ if(usb_release_interface(handle, MY_INTERFACE) != 0) {
+ ERR("Releasing interface: usb: %s\n", usb_strerror());
+ }
+ if(usb_close(handle) != 0) {
+ ERR("Closing device: usb: %s\n", usb_strerror());
+ }
+}
+
+void print_bcd_ver(const struct myeeprom *eeprom)
+{
+ /* In this case, print only the version. Also note that this
+ * is an output, and sent to stdout
+ */
+ printf("%d.%03d\n", eeprom->release_major, eeprom->release_minor);
+ return;
+}
+
+void dump_eeprom(const struct myeeprom *eeprom)
+{
+ const uint8_t *data = eeprom->serial;
+
+ INFO("Source: 0x%02X\n", eeprom->source);
+ INFO("Vendor: 0x%04X\n", eeprom->vendor);
+ INFO("Product: 0x%04X\n", eeprom->product);
+ INFO("Release: %d.%03d\n", eeprom->release_major, eeprom->release_minor);
+ INFO("Data: 0x[%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X]\n",
+ data[0], data[1], data[2], data[3],
+ data[4], data[5], data[6], data[7]);
+}
+
+void dump_packet(const char *buf, int len)
+{
+ int i;
+
+ for(i = 0; i < len; i++)
+ INFO("dump: %2d> 0x%02X\n", i, (uint8_t)buf[i]);
+}
+
+#ifdef XORCOM_INTERNAL
+int eeprom_set(struct usb_dev_handle *handle, const struct myeeprom *eeprom)
+{
+ int ret;
+ int len;
+ char buf[PACKET_SIZE];
+ struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+
+ if(verbose >= LOG_INFO)
+ INFO("%s Start...\n", __FUNCTION__);
+ assert(handle != NULL);
+ phead->header.op = EEPROM_SET;
+ memcpy(&phead->d.eeprom_set.data, eeprom, EEPROM_SIZE);
+ len = sizeof(phead->d.eeprom_set) + sizeof(phead->header.op);
+ if(verbose >= LOG_INFO) {
+ INFO("%s write %d bytes\n", __FUNCTION__, len);
+ dump_packet((char *)phead, len);
+ }
+ ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_write failed (%d)\n", ret);
+ return ret;
+ } else if(ret != len) {
+ ERR("usb: bulk_write short write (%d)\n", ret);
+ return -EFAULT;
+ }
+ ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_read failed (%d)\n", ret);
+ return ret;
+ } else if(ret == 0)
+ return 0;
+ phead = (struct fpga_packet_header *)buf;
+ if(phead->header.op == BAD_COMMAND) {
+ ERR("BAD_COMMAND\n");
+ return -EINVAL;
+ } else if(phead->header.op != EEPROM_SET) {
+ ERR("Got unexpected reply op=%d\n", phead->header.op);
+ return -EINVAL;
+ }
+ if(verbose >= LOG_INFO) {
+ INFO("%s read %d bytes\n", __FUNCTION__, ret);
+ dump_packet(buf, ret);
+ }
+ return 0;
+}
+#endif
+
+int eeprom_get(struct usb_dev_handle *handle, struct myeeprom *eeprom)
+{
+ int ret;
+ int len;
+ char buf[PACKET_SIZE];
+ struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+
+ assert(handle != NULL);
+ if(verbose >= LOG_INFO)
+ INFO("%s Start...\n", __FUNCTION__);
+ phead->header.op = EEPROM_GET;
+ len = sizeof(phead->header.op); /* warning: sending small packet */
+ if(verbose >= LOG_INFO) {
+ INFO("%s write %d bytes\n", __FUNCTION__, len);
+ dump_packet(buf, len);
+ }
+ ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_write failed (%d)\n", ret);
+ return ret;
+ } else if(ret != len) {
+ ERR("usb: bulk_write short write (%d)\n", ret);
+ return -EFAULT;
+ }
+ ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_read failed (%d)\n", ret);
+ return ret;
+ } else if(ret == 0)
+ return 0;
+ phead = (struct fpga_packet_header *)buf;
+ if(phead->header.op == BAD_COMMAND) {
+ ERR("BAD_COMMAND\n");
+ return -EINVAL;
+ } else if(phead->header.op != EEPROM_GET) {
+ ERR("Got unexpected reply op=%d\n", phead->header.op);
+ return -EINVAL;
+ }
+ if(verbose >= LOG_INFO) {
+ INFO("%s read %d bytes\n", __FUNCTION__, ret);
+ dump_packet(buf, ret);
+ }
+ memcpy(eeprom, &phead->d.eeprom_get.data, EEPROM_SIZE);
+ return 0;
+}
+
+int send_hexline(struct usb_dev_handle *handle, 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(handle != NULL);
+ assert(hexline != NULL);
+ len = hexline->d.content.header.ll; /* don't send checksum */
+ data = hexline->d.content.tt_data.data;
+ if(hexline->d.content.header.tt != TT_DATA) {
+ ERR("Bad record %d type = %d\n", seq, hexline->d.content.header.tt);
+ return -EINVAL;
+ }
+ phead->header.op = DATA_PACKET;
+ phead->d.data_packet.seq = seq;
+ phead->d.data_packet.reserved = 0x00;
+ memcpy(phead->d.data_packet.data, data, len);
+ len += sizeof(phead);
+ if(verbose >= LOG_INFO)
+ INFO("%04d+\r", seq);
+ ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_write failed (%d)\n", ret);
+ return ret;
+ } else if(ret != len) {
+ ERR("usb: bulk_write short write (%d)\n", ret);
+ return -EFAULT;
+ }
+ ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_read failed (%d)\n", ret);
+ return ret;
+ } else if(ret == 0)
+ return 0;
+ if(verbose >= LOG_INFO)
+ INFO("%04d-\r", seq);
+ phead = (struct fpga_packet_header *)buf;
+ if(phead->header.op != STATUS_REPLY) {
+ ERR("Got unexpected reply op=%d\n", phead->header.op);
+ 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);
+ if(verbose >= LOG_INFO)
+ dump_packet(buf, ret);
+ return -EPROTO;
+ default:
+ ERR("Unknown status reply %d\n", status);
+ if(verbose >= LOG_INFO)
+ dump_packet(buf, ret);
+ return -EPROTO;
+ }
+ return 0;
+}
+
+//. returns > 0 - ok, the number of lines sent
+//. returns < 0 - error number
+int send_splited_hexline(struct usb_dev_handle *handle, 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;
+
+ 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( handle, extraline, seq+linessent );
+ // cleanups
+ free(extraline);
+ extra_offset += this_line;
+ bytesleft -= this_line;
+ if (status)
+ return status;
+ linessent++;
+ }
+ return linessent;
+}
+
+int my_usb_device(struct usb_device *dev, usb_dev_handle *handle)
+{
+ 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;
+ char iManufacturer[BUFSIZ];
+ char iProduct[BUFSIZ];
+ int ret;
+ int i;
+
+ assert(dev != NULL);
+ dev_desc = &dev->descriptor;
+ config_desc = dev->config;
+ interface = config_desc->interface;
+ iface_desc = interface->altsetting;
+ if(verbose >= LOG_INFO)
+ INFO("Vendor:Product=%04X:%04X Class=%d (endpoints=%d)\n",
+ dev_desc->idVendor, dev_desc->idProduct, dev_desc->bDeviceClass, iface_desc->bNumEndpoints);
+ if(iface_desc->bInterfaceClass != 0xFF) {
+ ERR("Wrong Interface class %d\n", iface_desc->bInterfaceClass);
+ return -EINVAL;
+ }
+ if(iface_desc->bInterfaceNumber != MY_INTERFACE) {
+ ERR("Wrong Interface number %d\n", iface_desc->bInterfaceNumber);
+ return -EINVAL;
+ }
+ if(iface_desc->bNumEndpoints != MY_ENDPOINTS) {
+ ERR("Wrong number of endpoints: %d\n", iface_desc->bNumEndpoints);
+ return -EINVAL;
+ }
+ endpoint = iface_desc->endpoint;
+ for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) {
+ if(endpoint->bEndpointAddress != my_endpoints[i]) {
+ ERR("Wrong endpoint %d: address = 0x%X\n", i, endpoint->bEndpointAddress);
+ return -EINVAL;
+ }
+ 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 -EINVAL;
+ }
+ }
+ }
+ if(usb_reset(handle) != 0) {
+ ERR("Reseting device: usb: %s\n", usb_strerror());
+ }
+ if(usb_set_configuration(handle, MY_CONFIG) != 0) {
+ ERR("usb: %s\n", usb_strerror());
+ return -EINVAL;
+ }
+ if(usb_claim_interface(handle, MY_INTERFACE) != 0) {
+ ERR("usb: %s\n", usb_strerror());
+ return -EINVAL;
+ }
+ if(usb_resetep(handle, MY_EP_OUT) != 0) {
+ ERR("usb: %s\n", usb_strerror());
+ return -EINVAL;
+ }
+ if(usb_resetep(handle, MY_EP_IN) != 0) {
+ ERR("usb: %s\n", usb_strerror());
+ return -EINVAL;
+ }
+ ret = get_usb_string(iManufacturer, BUFSIZ, dev_desc->iManufacturer, handle);
+ ret = get_usb_string(iProduct, BUFSIZ, dev_desc->iProduct, handle);
+ if(verbose >= LOG_INFO)
+ INFO("iManufacturer=%s iProduct=%s\n", iManufacturer, iProduct);
+ return 0;
+}
+
+int renumerate_device(struct usb_dev_handle *handle)
+{
+ char buf[PACKET_SIZE];
+ struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+ int ret;
+
+ assert(handle != NULL);
+ if(verbose >= LOG_INFO)
+ INFO("Renumerating\n");
+ phead->header.op = RENUMERATE;
+ ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, 1, TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_write failed (%d)\n", ret);
+ return ret;
+ } else if(ret != 1) {
+ ERR("usb: bulk_write short write (%d)\n", ret);
+ return -EFAULT;
+ }
+ return 0;
+}
+
+int fpga_load(struct usb_dev_handle *handle, const struct hexdata *hexdata)
+{
+ unsigned int i;
+ int ret;
+ int finished = 0;
+
+ assert(handle != NULL);
+ if(verbose >= LOG_INFO)
+ INFO("Start...\n");
+
+ 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) {
+ INFO("End of data\n");
+ finished = 1;
+ continue;
+ }
+ if((ret = send_hexline(handle, hexline, i)) != 0) {
+ perror("Failed sending hexline");
+ return 0;
+ }
+ }
+ if(verbose >= LOG_INFO)
+ INFO("Finished...\n");
+ return 1;
+}
+
+int fpga_load_usb1(struct usb_dev_handle *handle, const struct hexdata *hexdata)
+{
+ unsigned int i,j=0;
+ int ret;
+ int finished = 0;
+
+ assert(handle != NULL);
+ if(verbose >= LOG_INFO)
+ INFO("Start...\n");
+
+ // 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) {
+ INFO("End of data\n");
+ finished = 1;
+ continue;
+ }
+
+ if((ret = send_splited_hexline(handle, hexline, j, 60)) < 0) {
+ perror("Failed sending hexline (splitting did not help)");
+ return 0;
+ }
+ j += ret;
+ }
+ if(verbose >= LOG_INFO)
+ INFO("Finished...\n");
+ return 1;
+}
+
+#include <getopt.h>
+
+void usage()
+{
+ fprintf(stderr, "Usage: %s -D /proc/bus/usb/<bus>/<dev> [options...]\n", progname);
+ fprintf(stderr, "\tOptions:\n");
+ fprintf(stderr, "\t\t[-b <binfile>] # output to <binfile>\n");
+ fprintf(stderr, "\t\t[-d] # Get device version from eeprom\n");
+ fprintf(stderr, "\t\t[-I <hexfile>] # Input from <hexfile>\n");
+ fprintf(stderr, "\t\t[-g] # Get eeprom from device\n");
+ 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[-S serial] # Set Serial. 8 comma separated numbers\n");
+ 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);
+}
+
+int hasUSB2( struct usb_device *dev )
+{
+ if (dev->config->interface->altsetting->endpoint->wMaxPacketSize != 512)
+ return 0;
+ else
+ return 1;
+}
+
+// usb_interface_descriptor->usb_endpoint_descriptor.wMaxPacketSize
+
+int main(int argc, char *argv[])
+{
+ struct usb_device *dev;
+ usb_dev_handle *handle;
+ const char *devpath = NULL;
+ const char *binfile = NULL;
+ const char *hexfile = NULL;
+ struct hexdata *hexdata = NULL;
+ struct myeeprom eeprom_buf;
+ int opt_read_eeprom = 0;
+ int opt_print_bcdver_only = 0;
+#ifdef XORCOM_INTERNAL
+ int opt_write_eeprom = 0;
+ char *vendor = NULL;
+ char *source = NULL;
+ int is_source_given = 0;
+ char *product = NULL;
+ char *release = NULL;
+ char *serial = NULL;
+ uint8_t serial_buf[SERIAL_SIZE];
+ const char options[] = "b:C:dD:ghI:vV:P:R:S:";
+#else
+ const char options[] = "b:dD:ghI:v";
+#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;
+ break;
+ case 'b':
+ binfile = optarg;
+ break;
+ case 'd':
+ opt_print_bcdver_only = 1;
+ opt_read_eeprom = 1;
+ break;
+ case 'g':
+ opt_read_eeprom = 1;
+ break;
+ case 'I':
+ hexfile = optarg;
+ break;
+#ifdef XORCOM_INTERNAL
+ case 'V':
+ vendor = optarg;
+ break;
+ case 'C':
+ source = optarg;
+ is_source_given = 1;
+ break;
+ case 'P':
+ product = optarg;
+ break;
+ case 'R':
+ release = optarg;
+ break;
+ case 'S':
+ serial = optarg;
+ {
+ int i;
+ char *p;
+ unsigned long val;
+
+ p = strtok(serial, ",");
+ for(i = 0; i < SERIAL_SIZE && p; i++) {
+ val = strtoul(p, NULL, 0);
+ if(val > 0xFF) {
+ ERR("Value #%d for -S option is too large (%lu)\n", i+1, val);
+ usage();
+ }
+ serial_buf[i] = val;
+ p = strtok(NULL, ",");
+ }
+ if(i < SERIAL_SIZE) {
+ ERR("got only %d values for -S option. Need %d\n", i, SERIAL_SIZE);
+ usage();
+ }
+ }
+
+ break;
+#endif
+ case 'v':
+ verbose++;
+ break;
+ case 'h':
+ default:
+ ERR("Unknown option '%c'\n", c);
+ usage();
+ }
+ }
+
+ if (optind != argc) {
+ usage();
+ }
+ if(hexfile) {
+ parse_hexfile_set_reporting(parse_report_func);
+ hexdata = parse_hexfile(hexfile, MAX_HEX_LINES);
+ if(!hexdata) {
+ ERR("Bailing out\n");
+ exit(1);
+ }
+ if(binfile) {
+ dump_binary(hexdata, binfile);
+ return 0;
+ }
+ }
+ if(!devpath) {
+ ERR("Missing device path\n");
+ usage();
+ }
+ if(verbose)
+ INFO("Startup %s\n", devpath);
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ dev = dev_of_path(devpath);
+ if(!dev) {
+ ERR("Bailing out\n");
+ exit(1);
+ }
+ handle = usb_open(dev);
+ if(!handle) {
+ ERR("Failed to open usb device '%s/%s': %s\n", dev->bus->dirname, dev->filename, usb_strerror());
+ return -ENODEV;
+ }
+ if(my_usb_device(dev, handle)) {
+ ERR("Foreign usb device '%s/%s'\n", dev->bus->dirname, dev->filename);
+ ret = -ENODEV;
+ goto dev_err;
+ }
+
+ if(hexdata) {
+ int status;
+
+ if (hasUSB2(dev))
+ status = fpga_load(handle, hexdata);
+ else {
+ INFO("Warning: working on a low end USB1 backend\n");
+ status = fpga_load_usb1(handle, hexdata);
+ }
+
+ if(!status) {
+ ERR("FPGA loading failed\n");
+ ret = -ENODEV;
+ goto dev_err;
+ }
+ ret = renumerate_device(handle);
+ if(ret < 0) {
+ ERR("Renumeration failed: errno=%d\n", ret);
+ goto dev_err;
+ }
+ }
+#ifdef XORCOM_INTERNAL
+ if(vendor || product || release || serial || source )
+ opt_read_eeprom = opt_write_eeprom = 1;
+#endif
+ if(opt_read_eeprom) {
+ ret = eeprom_get(handle, &eeprom_buf);
+ if(ret < 0) {
+ ERR("Failed reading eeprom: %d\n", ret);
+ goto dev_err;
+ }
+ if (opt_print_bcdver_only)
+ print_bcd_ver(&eeprom_buf);
+ else
+ dump_eeprom(&eeprom_buf);
+ }
+#ifdef XORCOM_INTERNAL
+ if(opt_write_eeprom) {
+ // FF: address source is from device. C0: from eeprom
+ if (is_source_given)
+ eeprom_buf.source = strtoul(source, NULL, 0);
+ else
+ eeprom_buf.source = 0xC0;
+ if(vendor)
+ eeprom_buf.vendor = strtoul(vendor, NULL, 0);
+ if(product)
+ eeprom_buf.product = strtoul(product, NULL, 0);
+ if(release) {
+ int release_major = 0;
+ int release_minor = 0;
+
+ sscanf(release, "%d.%d", &release_major, &release_minor);
+ eeprom_buf.release_major = release_major;
+ eeprom_buf.release_minor = release_minor;
+ }
+ if(serial) {
+ memcpy(eeprom_buf.serial, serial_buf, SERIAL_SIZE);
+ }
+ dump_eeprom(&eeprom_buf);
+ ret = eeprom_set(handle, &eeprom_buf);
+ if(ret < 0) {
+ ERR("Failed writing eeprom: %d\n", ret);
+ goto dev_err;
+ }
+ }
+#endif
+ if(verbose)
+ INFO("Exiting\n");
+dev_err:
+ usb_cleanup(handle);
+ return ret;
+}
diff --git a/xpp/utils/genzaptelconf b/xpp/utils/genzaptelconf
new file mode 100755
index 0000000..1763427
--- /dev/null
+++ b/xpp/utils/genzaptelconf
@@ -0,0 +1,955 @@
+#! /bin/bash
+
+# genzaptelconf: generate as smartly as you can:
+# /etc/zaptel.conf
+# /etc/asterisk/zapata-channels.conf (to be #include-d into zapata.conf)
+# update:
+# With '-M' /etc/modules (list of modules to load)
+#
+# Copyright (C) 2005 by Xorcom <support@xorcom.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# If you have any technical questions, contact
+# Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+#
+
+# The script uses a number of bash-specific features
+# TODO: either ditch them or convert to perl
+# Don't override variables here. Override them in /etc/default/zaptel
+#
+# 0.5.3:
+# * Experimental support for Sangoma analog cards (A20x)
+# * Support OpenVox A1200P (A TDM400P clone refactored)
+# * Fixed timeout for Astribank load
+# * Delete unsuccessfully-probe modules
+# * Pass callerid from trunks
+# 0.5.2:
+# * Now it should detect most PRI cards and even wcusb
+# 0.5.1:
+# * Initial support for ztgsm (Junghanns's PCI GSM card)
+# * Wait for the xpp module to register if just loaded
+# 0.5.0:
+# * Not trying to read from zaptel channels: we can run genzaptelconf even
+# with asterisk up.
+# * Don't add ztdummy to the list of detected modules
+# 0.4.4:
+# * remove ztdummy when rewriting modules file
+# * Better ISDN PRI behaviour in Israel (il)
+# 0.4.3:
+# * Added -F: to disable writing about FXS ports in zapata.conf
+# * if we have an astribank: start zaptel rather than simple ztcfg (xpd sync)
+# 0.4.2:
+# * support for digital input/output ports of Astribank
+# * Different ISDN parameters for the Netherlands (nl)
+# * unload zaptel and its dependencies, not a hard-coded list
+# * hence we can reduce the list of modules
+
+# /etc/default/zaptel may override the following variables
+VERSION=0.5.3
+VERSION_FULL="$VERSION $Id$"
+lc_country=us
+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 'immediate=yes' for Asteribank input channels and 'immediate=no'
+# for others. Note that if an Astribank is not detected, the script
+# will set this to "no", so you can safely leave it as "yes".
+set_immediate=yes
+
+ZAPCONF_FILE=/etc/zaptel.conf
+ZAPATA_FILE=/etc/asterisk/zapata-channels.conf
+ZAPTEL_BOOT=/etc/default/zaptel
+MODLIST_FILE=/etc/modules
+exten_base_dir=/etc/asterisk/extensions-phones.d
+exten_defs_file=/etc/asterisk/extensions-defs.conf
+ZTCFG=/sbin/ztcfg
+
+# a temporary directory. Created when the switch -r is parsed on getopts
+# and deleted in the end on update_extensions_defs
+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="zaphfc qozap ztgsm wctdm wctdm24xxp wcfxo wcfxs pciradio tor2 torisa wct1xxp wct4xxp wcte11xp wanpipe wcusb xpp_usb"
+
+# read default configuration from /etc/default/zaptel
+if [ -r $ZAPTEL_BOOT ]; then . $ZAPTEL_BOOT; fi
+
+# 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
+fxsdisable=no
+rapid_extens=''
+# global: current extension number in extensions list. Should only be
+# changed in print_pattern:
+rapid_cur_exten=1
+# set the TRUNK in extensidialplan dialplan defs file rapid_conf_mode=no
+
+die() {
+ echo "$@" >&2
+ exit 1
+}
+
+say() {
+ if [ "$verbose" = no ]; then
+ return
+ fi
+ echo "$@" >&2
+}
+
+run_ztcfg() {
+ if [ "$verbose" = no ]; then
+ $ztcfg_cmd "$@"
+ else
+ say "Reconfiguring identified channels"
+ $ztcfg_cmd -vv "$@"
+ fi
+}
+
+update_module_list() {
+ 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"
+}
+
+do_update() {
+ if [ ! -d `dirname ${ZAPTEL_BOOT}` ]
+ then
+ return
+ fi
+ sed -i.bak "s/^$1=.*\$/$1=\"$2\"/" ${ZAPTEL_BOOT}
+ if ! grep -q "^$1=" ${ZAPTEL_BOOT}; then
+ echo "$1=\"$2\"" >> ${ZAPTEL_BOOT}
+ fi
+}
+
+update_extensions_defs() {
+ if [ "$rapid_conf_mode" = 'yes' ]
+ then
+ say "DEBUG: Updating dialplan defs file $exten_defs_file"
+ if [ "`echo $tmp_dir/fxo_* | grep -v '*'`" != '' ]
+ then
+ trunk_nums=`cat $tmp_dir/fxo_* | sort -n | xargs`
+ say "Configuring TRUNK to be [first of] zaptel channels: $trunk_nums"
+ trunk_dev=`echo $trunk_nums| sed -e 's/ /\\\\\\&/g' -e 's/[0-9a-zA-Z]\+/Zap\\\\\\/&/g'`
+ echo >&2 sed -i "s/^TRUNK.*=>.*/TRUNK => $trunk_dev/" $exten_defs_file
+ sed -i "s/^TRUNK.*=>.*/TRUNK => $trunk_dev/" $exten_defs_file
+ if ! grep -q "^TRUNK =>" $exten_defs_file; then
+ trunk_dev=`echo $trunk_nums| sed -e 's/ /&/g' -e 's/[0-9a-zA-Z]*/Zap\\/&/g'`
+ echo "TRUNK => $trunk_dev" >> $exten_defs_file
+ fi
+ else
+ say "Warning: No FXO channel for trunk. Moving on."
+ fi
+ if [ "`echo $tmp_dir/fxs_* | grep -v '*'`" != '' ]
+ then
+ fxs_nums=`cat $tmp_dir/fxs_* | sort -n | xargs`
+ zap_nums=`grep '^[^;].*Zap/\${CHAN_ZAP_' $exten_base_dir/*.conf | \
+ sed -e 's/.*Zap\/\${CHAN_ZAP_\([0-9]*\)}.*/\1/' | sort -u | xargs`
+ say "Configuring channels: $fxs_nums as channel placeholders: $zap_nums"
+ j=1
+ for i in $zap_nums
+ do
+ chan=`echo $fxs_nums | awk "{print \\$$i}"`
+ if [ "$chan" = '' ]
+ then
+ # if the result is empty, we probably got past the last one.
+ # bail out.
+ say "Warning: No FXS channel for CHAN_ZAP_$i. Moving on"
+ break
+ fi
+ say "DEBUG: setting channel $chan to placeholder $i"
+ if grep -q "^CHAN_ZAP_$i " $exten_defs_file
+ then
+ sed -i -e "s/^CHAN_ZAP_$i .*/CHAN_ZAP_$i => Zap\/$chan/" $exten_defs_file
+ else
+ echo "CHAN_ZAP_$i => Zap/$chan" >> $exten_defs_file
+ fi
+ done
+ fi
+ # cleaning up the temp dir
+ fi
+ if [ -d "$tmp_dir" ]; then rm -rf "$tmp_dir"; fi
+}
+
+check_for_astribank(){
+ if ! grep -q XPP_IN/ /proc/zaptel/* 2>/dev/null
+ then
+ # we only get here is if we find no Astribank input channels
+ # in /proc/zaptel . Hence we can safely disable their special settings:
+ set_immediate=no
+ fi
+}
+
+usage() {
+ program=`basename $0`
+
+ echo >&2 "$program: generate zaptel.conf and zapata.conf"
+ echo >&2 "(version $VERSION_FULL)"
+ echo >&2 "usage:"
+ echo >&2 " $program [-sdv] [-m k|l|g] [-c <country_code>] [-r |-e <base_exten>] "
+ echo >&2 " $program [-sdv] -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"
+ echo >&2 " -v: verbose"
+ echo >&2 " -s: Don't fail if asterisk is running. Stop it"
+ echo >&2 " -r: rapid configuration mode: configure Zaptel FXS channels from "
+ echo >&2 " existing Rapid extension files. FXOs will all be TRUNK "
+}
+
+# $1: channel number
+print_pattern() {
+ local astbank_type=''
+ 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='ks'
+ if [ "$lc_country" = il ] && [ "$sig" = 'fxs' ]
+ then method=ls
+ fi
+ case "$mode" in
+ zaptel)
+ # 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:
+ if [ "$astbank_type" != '' ]; then echo "# astbanktype: $astbank_type"; fi
+ echo "${sig}$method=$chan"
+ ;;
+ list) echo $chan $sig $astbanktype;;
+ zapata)
+ # zap2amp will rewrite those from zaptel.conf and hints there
+ if [ "$fxsdisable" = 'yes' ] && [ $sig = 'fxo' ]; then return; fi
+
+ echo "signalling=${sig}_$method"
+ 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 option -E was given, get configuration from current extension
+ if [ "$rapid_conf_mode" = 'yes' ]
+ then
+ rap_exten=`echo $rapid_extens |awk "{print \\$$rapid_cur_exten}"`
+ if [ "$rap_exten" != '' ]
+ then
+ rap_cfgfile="$exten_base_dir/$rap_exten.conf"
+ if [ -r "$rap_exten" ]
+ then
+ cfg_exten=$rap_exten
+ # the vmbox is the third parameter to stdexten
+ rap_vmbox=`grep '^[^;].*Macro(stdexten' $rap_exten | cut -d, -f3 \
+ | cut -d')' -f1 | tr -d -c '0-9@a-zA-Z'`
+ if [ "$rap_vmbox" ]!= '' ; then cfg_vmbox=$rap_vmbox; fi
+ fi
+ fi
+ rapid_cur_exten=$(($rapid_cur_exten + 1))
+ fi
+
+ 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>"
+ echo "mailbox=$exten"
+ if [ "$group_manual" != "yes" ]
+ then
+ echo "group=$group_phones"
+ fi
+ if [ "$context_manual" != "yes" ]
+ then
+ if [ "$astbank_type" != '' ];
+ then
+ context_var_name=context_$astbank_type
+ echo context=${!context_var_name}
+ else
+ echo "context=$context_phones"
+ fi
+ fi
+ else # this is an FXO (trunk/phone: FXO signalling)
+ # we have may have set it. So reset it:
+ echo "callerid=asrecieved"
+ echo "mailbox="
+ if [ "$group_manual" != "yes" ]
+ then
+ echo "group=$group_lines"
+ fi
+ if [ "$context_manual" != "yes" ]
+ then
+ echo "context=$context_lines"
+ fi
+ if [ "$lc_country" = 'uk' ]
+ then
+ echo "cidsignalling=v23"
+ case $line in
+ *WCFXO*) echo "cidstart=history";;
+ *) echo "cidstart=polarity";; #a TDM400
+ esac
+ fi
+ echo ";;; line=\"$line\""
+ # if kewlstart is not used, busydetect has to be employed:
+ if [ "$method" = 'ls' ]
+ then echo 'busydetect=yes'
+ else echo 'busydetect=no'
+ fi
+ fi
+
+ if [ "$set_immediate" = 'yes' ]
+ then
+ if [ "$astbank_type" = 'input' ]
+ then echo 'immediate=yes'
+ else echo 'immediate=no'
+ fi
+ fi
+ echo "channel => $chan"
+ echo ""
+
+ # Keep a note of what channels we have identified
+ say "DEBUG: adding to channels list: channel: $chan, sig: $sig"
+ case "$sig" in
+ fxs)
+ echo $chan >$tmp_dir/fxo_$chan
+ say "DEBUG: FXO list now contains: `cat $tmp_dir/fxo_* |xargs`"
+ ;;
+ fxo)
+ echo $chan >$tmp_dir/fxs_$chan
+ say "DEBUG: FXS list now contains: `cat $tmp_dir/fxs_* |xargs`"
+ ;;
+ esac
+ ;;
+ 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 , ' '`
+ # old versions of xpd_fxs actually depend on xpp, but forget to tell it.
+ # bug has already been fixed but the code will remain here for a while
+ # just in case
+ 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() {
+ if
+ pids="$(pgrep asterisk)"
+ [ "$pids" != '' ]
+ then
+ die "Before unloading -- STOP asterisk (pids=$pids)."
+ fi
+ say "Unloading zaptel modules:"
+ unload_module zaptel
+ say ''
+}
+
+# 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: replace this loop with 'cat /proc/xpp/XBUS-*/waitfor_xpds
+ success=0
+ for i in `seq 30`; do
+ if ! grep -q 0 /proc/xpp/*/*/zt_registration 2>/dev/null
+ then
+ # There are either no XPDs or all of them are
+ # registered. Nothing to do
+ success=1
+ break
+ fi
+ sleep 1
+ done
+ if [ "$success" = 0 ]; then
+ echo 1>&2 "$0: WARNING: some XPD's are not registered yet (timeout)"
+ fi
+ fi
+}
+
+detect() {
+ unload_modules
+ load_modules
+ modlist="$probed_modules"
+ #for i in $ALL_MODULES
+ #do
+ # if lsmod | grep "^$i *" > /dev/null; then
+ # modlist="$modlist $i"
+ # fi
+ #done
+ modlist="$(echo $modlist)" # clean spaces
+ if [ "$do_module_list" = yes ]
+ then
+ say "Updating '${MODLIST_FILE}'"
+ update_module_list "$modlist"
+ fi
+ if echo $modlist | grep -q xpp_usb; then wait_for_xpp; fi
+}
+
+# TODO: kill this function. It is now unreferenced from anywhere.
+check_tdm_sigtype() {
+ chan_num=$1
+ sig_type=$2
+ mode=$3
+
+ case "$sig_type" in
+ fxs)chan_sig_type=fxo;;
+ fxo)chan_sig_type=fxs;;
+ esac
+
+# print_pattern $chan_num $chan_sig_type $mode
+
+ # if you get syntax error from this line, make sure you use 'bash'
+ # rather than 'sh'
+ $ztcfg_cmd -c <(print_pattern $chan_num $chan_sig_type zaptel) 2>/dev/null \
+ || return 1
+ if head -c1 /dev/zap/$chan_num >/dev/null 2>/dev/null
+ then
+ print_pattern $chan_num $chan_sig_type $mode
+ return 0
+ else
+ return 1
+ fi
+}
+
+# output a list of extensions that need a channel
+get_rapid_extens() {
+ if [ "$rapid_conf_mode" = 'yes' ]
+ then
+ rapid_extens=`grep -l '^[^;].*Zap/\${CHAN_ZAP_' $exten_base_dir/*.conf 2>/dev/null | \
+ rev | cut -d/ -f1 | cut -d. -f2- | rev | xargs`
+ say "Need to configure extensions: $rapid_extens"
+ fi
+}
+
+genconf() {
+ local mode=$1
+
+ # reset FXO list (global)
+ #say "DEBUG: resetting channels lists"
+ rm -f $tmp_dir/fx{s,o}_*
+
+ if [ "$mode" = 'zapata' ]
+ then
+ rem_char=';'
+ else
+ rem_char='#'
+ fi
+
+ spanlist=`echo /proc/zaptel/* | grep -v '\*'`
+
+ #if [ "$spanlist" == "" ]; then
+ # die "No zapata interfaces in /proc/zaptel"
+ #fi
+
+
+ case "$mode" in
+ zaptel)
+ cat <<EOF
+# 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
+ ;;
+ zapata)
+ cat <<EOF
+; 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'.
+ #
+ # This approach failed with the T1 card we have: the read operation simply
+ # hung.
+ #
+ # 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`
+ echo ""
+ # stuff that needs to be remembered accross lines (for PRI support)
+ echo "$rem_char $title"
+ echo '-1' >$tmp_dir/span_begin
+ echo '-1' >$tmp_dir/span_end
+ echo '1' >$tmp_dir/span_timing
+ echo '1' >$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 echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[NT\]\ |octoBRI \[NT\] |HFC-S PCI A ISDN.* \[NT\] )'
+ then
+ echo 'nt' >$tmp_dir/span_termtype
+ else
+ if echo $title | egrep -q '((quad|octo)BRI PCI ISDN Card.* \[TE\]\ |octoBRI \[TE\] |HFC-S PCI A ISDN.* \[TE\] )'
+ then
+ echo 'te' >$tmp_dir/span_termtype
+ fi
+ 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/*)
+ # this can be either FXS or FXO
+ maybe_fxs=0
+ maybe_fxo=0
+ $ztcfg_cmd -c <(print_pattern $chan_num fxo zaptel) &>/dev/null && maybe_fxs=1
+ $ztcfg_cmd -c <(print_pattern $chan_num fxs zaptel) &>/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 "$rem_char channel $chan_num, WCTDM, no module."
+ 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/*)
+ print_pattern $chan_num fxs $mode || \
+ echo "$rem_char channel $chan_num, WCFXO, inactive."
+ ;;
+ *WCUSB/*)
+ print_pattern $chan_num fxo $mode
+ ;;
+ *XPP_FXO/*)
+ print_pattern $chan_num fxs $mode
+ ;;
+ *XPP_FXS/*)
+ print_pattern $chan_num fxo $mode
+ ;;
+ *XPP_OUT/*)
+ print_pattern -a output $chan_num fxo $mode
+ ;;
+ *XPP_IN/*)
+ print_pattern -a input $chan_num fxo $mode
+ ;;
+ *ZTHFC*/*|*ztqoz*/*|*ztgsm/*|*TE4/*|*TE2/*|*WCT1/*|*Tor2/*|*TorISA/*) # should also be used for other PRI channels
+ if [ "`cat $tmp_dir/span_begin`" = "-1" ]
+ then
+ echo $chan_num >$tmp_dir/span_begin
+ echo $span_num >$tmp_dir/span_num
+ case "$line" in
+ *ZTHFC*/*|*ztqoz*/*)
+ echo 'ccs' >$tmp_dir/span_framing
+ echo 'euroisdn' >$tmp_dir/span_switchtype
+ if [ "`cat $tmp_dir/span_termtype`" = 'nt' 2>/dev/null ]
+ then
+ echo 'bri_net' >$tmp_dir/span_signalling
+ else
+ echo 'bri_cpe' >$tmp_dir/span_signalling
+ fi
+ ;;
+ *ztgsm*/*)
+ echo 'ccs' >$tmp_dir/span_framing
+ # what switch type? Any meaning to it?
+ echo 'gsm' >$tmp_dir/span_signalling
+ ;;
+ *TE4/*|*TE2/*|*WCT1/*|*Tor2/*|*TorISA/*)
+ echo 'esf' >$tmp_dir/span_framing
+ echo 'b8zs' >$tmp_dir/span_coding
+ echo 'national' >$tmp_dir/span_switchtype
+ echo 'pri_cpe' >$tmp_dir/span_signalling
+ # 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 'ami' >$tmp_dir/span_framing
+ echo 'ccs' >$tmp_dir/span_coding
+ #echo 'crc4' >$tmp_dir/span_yellow
+ #echo 'euroisdn' >$tmp_dir/span_switchtype
+ #echo 'pri_cpe' >$tmp_dir/span_signalling
+ ;;
+ il)
+ echo 'hdb3' >$tmp_dir/span_framing
+ echo 'ccs' >$tmp_dir/span_coding
+ echo 'crc4' >$tmp_dir/span_yellow
+ echo 'euroisdn' >$tmp_dir/span_switchtype
+ esac
+ ;;
+ esac
+ fi
+ # span_lastd is always the one before last
+ # channel. span_bchan is the last:
+ echo $chan_num >$tmp_dir/span_end
+ ;;
+ '') ;; # Empty line (after span header)
+ *) echo "$rem_char ??: $line";;
+ esac
+ done
+ if [ "`cat $tmp_dir/span_begin`" != -1 ]
+ then # write PRI span ocnfig:
+ # 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
+ if [ "$span_yellow" != '' ]; then span_yellow=",$span_yellow"; fi
+ # 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"
+ ;;
+ esac
+ case "$mode" in
+ zaptel)
+ echo span=$span_num,$span_timing,$span_lbo,$span_framing,$span_coding$span_yellow
+ if [ "$span_termtype" != '' ]
+ then echo "# termtype: $span_termtype"
+ fi
+ echo bchan=$bchans
+ echo dchan=$dchan
+ ;;
+ zapata)
+ 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>"
+ #echo "mailbox=$exten"
+ if [ "$group_manual" != "yes" ]
+ then
+ echo "group=$group_phones"
+ fi
+ if [ "$context_manual" != "yes" ]
+ then
+ echo "context=$context_phones"
+ fi
+ else # we have may have set it. So reset it:
+ echo "callerid=asrecieved"
+ #echo "mailbox="
+ if [ "$group_manual" != "yes" ]
+ then
+ echo "group=$group_lines"
+ fi
+ if [ "$context_manual" != "yes" ]
+ then
+ echo "context=$context_lines"
+ fi
+ fi
+ fi
+ echo "switchtype = $span_switchtype"
+ echo "signalling = $span_signalling"
+ echo "channel => $bchans"
+ ;;
+ list)
+ echo BRI/PRI: chans: $bchans, control: $dchan
+ ;;
+ esac
+ fi
+ done
+
+ if [ "$mode" = 'zaptel' ]
+ then
+ cat <<EOF
+
+# Global data
+
+EOF
+ echo "loadzone = $loadzone"
+ echo "defaultzone = $defaultzone"
+ fi
+
+ if [ "$mode" = 'zapata' ] || [ "$mode" = 'list' ]
+ then
+ update_extensions_defs
+ fi
+}
+
+while getopts 'c:de:Fhlm:Mrsuv' 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 ;;
+ v) verbose=yes ;;
+ l) mode='list' ;;
+ M) do_module_list=yes; do_detect=yes ;;
+ s) force_stop_ast=yes ;;
+ r)
+ rapid_conf_mode=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 -t` || \
+ 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
+ /etc/init.d/asterisk 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 1
+ fi
+fi
+
+if [ "$do_unload" = yes ]
+then
+ unload_modules
+ exit
+fi
+
+if [ "$do_detect" = yes ]
+then
+ detect
+fi
+
+if [ "$mode" = list ]; then
+ genconf list
+else
+ check_for_astribank
+ get_rapid_extens
+ say "Generating '${ZAPCONF_FILE}'"
+ mv "${ZAPCONF_FILE}" "${ZAPCONF_FILE}.bak"
+ genconf zaptel > "${ZAPCONF_FILE}"
+ say "Generating '${ZAPATA_FILE}'"
+ mv "${ZAPATA_FILE}" "${ZAPATA_FILE}.bak"
+ genconf zapata > "${ZAPATA_FILE}"
+ if [ "$set_immediate" = 'yes' ] && [ -x /etc/init.d/zaptel ]
+ then /etc/init.d/zaptel start
+ else run_ztcfg
+ fi
+fi
+
+if [ "$tmp_dir" != '' ]
+then
+ rm -rf "$tmp_dir"
+fi
+
+if [ "$force_stop_ast" = 'yes' ]
+then
+ if [ -x /etc/init.d/asterisk ]
+ then
+ /etc/init.d/asterisk start 1>&2
+ fi
+fi
+
+# if in verbose mode: verify that asterisk is running
+if [ "$verbose" != 'no' ] && [ "$force_stop_ast" = 'yes' ]
+ 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=2:
diff --git a/xpp/utils/genzaptelconf.8 b/xpp/utils/genzaptelconf.8
new file mode 100644
index 0000000..0ec62a2
--- /dev/null
+++ b/xpp/utils/genzaptelconf.8
@@ -0,0 +1,258 @@
+.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
+[-sdv] [-c <country_code>] [-r |-e <base_exten>] [ -F ]
+
+.B genzaptelconf
+[-sdv] -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
+(HFC, 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
+Try to guess a useful
+.I zapata-channels
+configuration for Xorcom Rapid .
+.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.
+
+By default the script will check if asterisk is running and alert if so.
+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
+.SH FILES
+.I /etc/zaptel.conf
+.RS
+The configuration file used by
+.I ztcfg
+to configure zaptel devices. re-written by
+.I genzaptelconf
+.RE
+
+.I /etc/zaptel.conf.bak
+.RS
+When
+.I zaptel.conf
+The original zaptel.conf
+.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.
+.RE
+
+.I /etc/asterisk/zapata-channels.conf.bak
+.RS
+The backup copy of
+.I zapata-channels.conf
+.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.
+Some of the variables that can be set in /etc/default/zaptel and affect
+genzaptelconf:
+
+.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
+.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
+.RE
+
+.I /etc/modules.bak
+.RS
+The backup copy of
+.I /etc/modules
+.RE
+
+.SH "SEE ALSO"
+ztcfg(8) asterisk(8).
+
+.SH "AUTHOR"
+This manual page was written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/xpp/utils/hexfile.c b/xpp/utils/hexfile.c
new file mode 100644
index 0000000..f6e4149
--- /dev/null
+++ b/xpp/utils/hexfile.c
@@ -0,0 +1,360 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2006, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "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 && (buf[last] == '\n' || buf[last] == '\r'))
+ buf[last--] = '\0';
+}
+
+int 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;
+}
+
+static int update_hexline(struct hexdata *hexdata, char *buf)
+{
+ int ret;
+ unsigned int ll, offset, tt;
+ char *p;
+ struct hexline *hexline;
+ unsigned int i;
+ int allocsize;
+ unsigned int last_line = hexdata->last_line;
+
+ if(hexdata->got_eof) {
+ if(report_func)
+ report_func(LOG_ERR, "Extranous data after EOF record\n");
+ return -EINVAL;
+ }
+ if(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, "Bad EOF record len = %d\n", ll);
+ return -EINVAL;
+ }
+ if(offset != 0) {
+ if(report_func)
+ report_func(LOG_ERR, "Bad EOF record offset = %d\n", offset);
+ return -EINVAL;
+ }
+ hexdata->got_eof = 1;
+ break;
+ case TT_EXT_SEG: /* Unimplemented */
+ case TT_START_SEG: /* Unimplemented */
+ case TT_EXT_LIN: /* Unimplemented */
+ case TT_START_LIN: /* Unimplemented */
+ return 1;
+ default:
+ if(report_func)
+ report_func(LOG_ERR, "Unknown record type %d\n", tt);
+ return -EINVAL;
+ }
+ buf += 8; /* Skip header */
+ ll++; /* include the checksum for now */
+ allocsize = sizeof(struct hexline) + ll;
+ if((hexline = (struct hexline *)malloc(allocsize)) == NULL) {
+ if(report_func)
+ report_func(LOG_ERR, "No more memory for hexfile lines\n");
+ return -EINVAL;
+ }
+ memset(hexline, 0, allocsize);
+ hexline->d.content.header.ll = ll;
+ hexline->d.content.header.offset = offset;
+ hexline->d.content.header.tt = tt;
+ hexdata->lines[last_line++] = hexline;
+ p = buf;
+ for(i = 0; i < ll; i++) {
+ 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;
+ }
+ hexline->d.content.header.ll--; /* Fix the checksum */
+ if(checksum(hexline) != 0) {
+ if(report_func)
+ report_func(LOG_ERR, "Bad checksum\n");
+ return -EINVAL;
+ }
+ 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, FILE *outfile)
+{
+ uint8_t ll;
+ uint16_t offset;
+ uint8_t tt;
+ uint8_t old_chksum;
+ uint8_t new_chksum;
+ uint8_t *data;
+ unsigned int i;
+ unsigned int j;
+
+ 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;
+ }
+ ll = line->d.content.header.ll;
+ offset = line->d.content.header.offset;
+ tt = line->d.content.header.tt;
+ fprintf(outfile, ":%02X%04X%02X", ll, offset, tt);
+ data = line->d.content.tt_data.data;
+ for(j = 0; j < ll; j++) {
+ fprintf(outfile, "%02X", data[j]);
+ }
+ old_chksum = data[ll];
+ data[ll] = 0;
+ new_chksum = 0xFF - checksum(line) + 1;
+ data[ll] = old_chksum;
+ assert(new_chksum == old_chksum);
+ fprintf(outfile, "%02X\n", new_chksum);
+ }
+ return 0;
+}
+
+int dump_hexfile2(struct hexdata *hexdata, FILE *outfile, uint8_t maxwidth)
+{
+ uint8_t ll;
+ uint8_t tt;
+ uint8_t new_chksum;
+ uint8_t *data;
+ unsigned int i;
+ unsigned int j;
+
+ if (maxwidth <= sizeof(hexdata->lines[0]->d.content.header) ){
+ if(report_func)
+ report_func(LOG_ERR, "Line width too small %d\n", maxwidth);
+ return -EINVAL;
+ }
+
+ for(i = 0; i <= hexdata->last_line; i++) {
+ struct hexline *line = hexdata->lines[i];
+ struct hexline *extraline;
+ int allocsize;
+ int bytesleft = 0;
+ int extra_offset = 0;
+ unsigned int this_line = 0;
+
+ if(!line) {
+ if(report_func)
+ report_func(LOG_ERR, "Missing line at #%d\n", i);
+ return -EINVAL;
+ }
+ ll = line->d.content.header.ll;
+ bytesleft = ll;
+ /* split the line into several lines */
+ tt = line->d.content.header.tt;
+ while (bytesleft > 0) {
+ this_line = (bytesleft >= maxwidth) ? maxwidth : bytesleft;
+ allocsize = sizeof(struct hexline) + this_line + 1;
+ /* generate the new line */
+ if((extraline = (struct hexline *)malloc(allocsize)) == NULL) {
+ if(report_func)
+ report_func(LOG_ERR, "No more memory for hexfile lines\n");
+ return -EINVAL;
+ }
+ memset( extraline, 0, allocsize );
+ extraline->d.content.header.ll = this_line;
+ extraline->d.content.header.offset = line->d.content.header.offset + extra_offset;
+ extraline->d.content.header.tt = tt;
+ memcpy( extraline->d.content.tt_data.data, line->d.content.tt_data.data+extra_offset, this_line);
+ new_chksum = 0xFF - checksum(extraline) + 1;
+ /* print it */
+ data = extraline->d.content.tt_data.data;
+ fprintf(outfile, ":%02X%04X%02X", extraline->d.content.header.ll, extraline->d.content.header.offset, tt);
+ for(j = 0; j < this_line; j++) {
+ fprintf(outfile, "%02X", data[j]);
+ }
+ fprintf(outfile, "%02X\n", new_chksum);
+ /* cleanups */
+ free( extraline);
+ extra_offset += this_line;
+ bytesleft -= this_line;
+ }
+ }
+ return 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 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;
+ }
+ line = 0;
+ while(fgets(buf, BUFSIZ, fp)) {
+ line++;
+ if(buf[0] == '\0') {
+ if(report_func)
+ report_func(LOG_ERR, "Short line at %s:%d\n", fname, line);
+ goto err;
+ }
+ chomp(buf);
+ if(buf[0] == '#') {
+ if(report_func)
+ report_func(LOG_INFO, "Comment '%s'\n", buf + 1);
+ continue;
+ }
+ if(buf[0] != ':') {
+ if(report_func)
+ report_func(LOG_ERR, "Line begins with 0x%X at %s:%d\n", buf[0], fname, line);
+ goto err;
+ }
+ if((ret = update_hexline(hexdata, buf + 1)) < 0) {
+ if(report_func)
+ report_func(LOG_ERR, "Failed parsing %s at line: %d\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;
+ if(hexline->d.content.header.tt == TT_EOF) {
+ if(report_func)
+ report_func(LOG_INFO, "\ndump: good EOF record");
+ continue;
+ }
+ 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);
+ }
+ }
+ if(report_func)
+ report_func(LOG_INFO, "\nDump finished\n");
+ fclose(fp);
+}
+
diff --git a/xpp/utils/hexfile.h b/xpp/utils/hexfile.h
new file mode 100644
index 0000000..c7f5df0
--- /dev/null
+++ b/xpp/utils/hexfile.h
@@ -0,0 +1,120 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2006, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef PARSE_HEXFILE_H
+#define PARSE_HEXFILE_H
+
+#include <stdarg.h>
+
+/*
+ * Some portability workarounds
+ */
+#ifdef _WINDOWS
+
+#include <windows.h> /* for UCHAR USHORT */
+typedef UCHAR uint8_t;
+typedef USHORT uint16_t;
+#define PACKED
+#define sscanf sscanf_s
+#define ZERO_SIZE 1
+
+/* From /usr/include/syslog.h */
+#define LOG_EMERG 0 /* system is unusable */
+#define LOG_ALERT 1 /* action must be taken immediately */
+#define LOG_CRIT 2 /* critical conditions */
+#define LOG_ERR 3 /* error conditions */
+#define LOG_WARNING 4 /* warning conditions */
+#define LOG_NOTICE 5 /* normal but significant condition */
+#define LOG_INFO 6 /* informational */
+#define LOG_DEBUG 7 /* debug-level messages */
+
+#ifdef __cplusplus
+# define __BEGIN_DECLS extern "C" {
+# define __END_DECLS }
+#else
+# define __BEGIN_DECLS
+# define __END_DECLS
+#endif
+
+#elif __GNUC__
+
+#include <stdint.h>
+#include <syslog.h>
+#define PACKED __attribute__((packed))
+#define ZERO_SIZE 1
+
+#else
+
+#error "Cannot compile on this platform"
+
+#endif
+
+/* Record types in hexfile */
+enum {
+ TT_DATA = 0,
+ TT_EOF = 1,
+ TT_EXT_SEG = 2,
+ TT_START_SEG = 3,
+ TT_EXT_LIN = 4,
+ TT_START_LIN = 5,
+ TT_NO_SUCH_TT
+};
+
+#pragma pack(1)
+struct hexline {
+ union {
+ uint8_t raw[ZERO_SIZE];
+ struct content {
+ struct header {
+ uint8_t ll; /* len */
+ uint16_t offset; /* offset */
+ uint8_t tt; /* type */
+ } PACKED header;
+ struct tt_data {
+ uint8_t data[ZERO_SIZE];
+ } tt_data;
+ } PACKED content;
+ } d;
+} PACKED;
+#pragma pack()
+
+struct hexdata {
+ unsigned int maxlines;
+ unsigned int last_line;
+ int got_eof;
+ 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, FILE *outfile);
+int dump_hexfile2(struct hexdata *hexdata, FILE *outfile, uint8_t maxwidth);
+void dump_binary(struct hexdata *hexdata, const char *outfile);
+__END_DECLS
+
+#endif
diff --git a/xpp/utils/test_parse.c b/xpp/utils/test_parse.c
new file mode 100644
index 0000000..bdcdea7
--- /dev/null
+++ b/xpp/utils/test_parse.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include "hexfile.h"
+
+static void default_report_func(int level, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ vfprintf(stderr, msg, ap);
+ va_end(ap);
+}
+
+int main(int argc, char *argv[])
+{
+ struct hexdata *hd;
+ int i;
+
+ if(argc < 2) {
+ fprintf(stderr, "Usage: program hexfile...\n");
+ return 1;
+ }
+ parse_hexfile_set_reporting(default_report_func);
+ for(i = 1; i < argc; i++) {
+ hd = parse_hexfile(argv[i], 2000);
+ if(!hd) {
+ fprintf(stderr, "Parsing failed\n");
+ return 1;
+ }
+ dump_hexfile2(hd, stdout, 60 );
+ free_hexdata(hd);
+ }
+ return 0;
+}
diff --git a/xpp/utils/xpp_fxloader b/xpp/utils/xpp_fxloader
new file mode 100644
index 0000000..ca29fd2
--- /dev/null
+++ b/xpp/utils/xpp_fxloader
@@ -0,0 +1,163 @@
+#!/bin/sh
+
+# xpp_fxload: load XPP firmware
+#
+# This script can be run manually or from hotplug.
+#
+# Firmware files should be located in $FIRMWARE_DIR which defaults:
+# 1. /usr/share/zaptel
+# 2. Can be overidden by setting $FIRMWARE_DIR in the environment
+# 3. Can be overidden by setting $FIRMWARE_DIR in /etc/default/zaptel
+#
+# Manual Run
+# ##########
+#
+# path/to/xpp_fxloader xppdetect
+#
+# Make sure the firmware files are in $FIRMWARE_DIR
+#
+#
+# Hotplg Run
+# ##########
+#
+# 1. Copy this file and the file xpp_fxloader.usermap to /etc/hotplug/usb/
+# 2. tail -f /var/log/messages...
+#
+#
+# Written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+# Copyright (C) 2006, Xorcom
+#
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+set -e
+
+me=`basename $0`
+DEFAULTS="/etc/default/zaptel"
+
+if [ -t 2 ]; then
+ LOGGER="logger -i -t '$me' -s"
+else
+ LOGGER="logger -i -t '$me'"
+fi
+
+if [ -r "$DEFAULTS" ]; then
+ . "$DEFAULTS"
+fi
+
+FIRMWARE_DIR="${FIRMWARE_DIR:-/usr/share/zaptel}"
+
+FIRM_FXS=$FIRMWARE_DIR/FPGA_FXS.hex
+REENUM_SLEEP_TIME=3 # only used on manual runs
+
+FPGA_LOAD="/usr/sbin/fpga_load"
+
+find_dev() {
+ v_id=$1
+ p_id=$2
+
+ lsusb | tr -d : | awk "/ ID $v_id$p_id/{printf \"/proc/bus/usb/%s/%s \",\$2,\$4}"
+}
+
+do_fxload() {
+ ( fxload -t fx2 $* 2>&1 1>/dev/null || exit 1 ) | $LOGGER
+}
+
+load_fw() {
+ v_id=$1
+ p_id=$2
+ fw=$3
+
+ devices=`find_dev $v_id $p_id`
+ for dev in $devices
+ do
+ $LOGGER "USB Firmware $FIRMWARE_DIR/$fw into $dev"
+ do_fxload -D $dev -I $FIRMWARE_DIR/$fw || exit 1
+ done
+
+ # Allow time for reenumeration: This only matters in the manual case.
+ if [ "$devices" != '' ]; then sleep $REENUM_SLEEP_TIME; fi
+}
+
+hexfile_version() {
+ hexfile=$1
+
+ grep '$Id:' "$hexfile" | sed -e 's/^.*$Id: *[^ ]\+ *//' -e 's/ .*$//'
+}
+
+load_fpga() {
+ v_id=$1
+ p_id=$2
+ fw=$3
+
+ devices=`find_dev $v_id $p_id`
+ for dev in $devices
+ do
+ card_ver=`$FPGA_LOAD -d -D $dev`
+ firm_ver=`hexfile_version $FIRMWARE_DIR/$fw`
+
+ $LOGGER "FPGA Firmware $FIRMWARE_DIR/$fw into $dev"
+ $FPGA_LOAD -D "$dev" -I "$FIRMWARE_DIR/$fw" 2>&1 >/dev/null | $LOGGER
+ status=$PIPESTATUS
+ if [ $status != 0 ]; then
+ echo "fpga_load failed with status $status" | $LOGGER
+ exit 77
+ fi
+ done
+}
+
+#########################
+##
+## Manual run
+##
+
+# to run manually, pass the parameter 'xppdetect'
+if [ "$1" = 'xppdetect' ]; then
+ echo "--------- FIRMWARE LOADING"
+ load_fw 04b4 8613 USB_8613.hex
+ load_fw e4e4 1130 USB_1130.hex
+ load_fpga e4e4 1131 FPGA_FXS.hex
+
+ sleep 3 # Let it stabilize
+ echo "--------- FIRMWARE IS LOADED"
+ exit $?
+fi
+
+#########################
+##
+## Hotplug run
+##
+
+if [ "$ACTION" = "add" ] && [ -f "$DEVICE" ]
+then
+ $LOGGER "Trying to find what to do for product $PRODUCT, device $DEVICE"
+ prod_id=`echo "$PRODUCT" | cut -d/ -f2`
+ case "$PRODUCT" in
+ 4b4/8613/*|e4e4/1130/*|e4e4/1140/*)
+ FIRM_USB="$FIRMWARE_DIR/USB_$prod_id.hex"
+ $LOGGER "Loading firmware '$FIRM_USB' into '$DEVICE'"
+ do_fxload -D "$DEVICE" -I "$FIRM_USB"
+ ;;
+ e4e4/1131/*|e4e4/1141/*)
+ if [ "$prod_id" = 1131 ]; then
+ FIRM_FPGA="$FIRMWARE_DIR/FPGA_FXS.hex" # Legacy
+ else
+ FIRM_FPGA="$FIRMWARE_DIR/FPGA_$prod_id.hex"
+ fi
+ $FPGA_LOAD -D "$DEVICE" -I "$FIRM_FPGA" 2>&1 >/dev/null | $LOGGER
+ ;;
+ esac
+fi
diff --git a/xpp/xpp_fxloader.usermap b/xpp/utils/xpp_fxloader.usermap
index 1989af9..bdfa861 100644
--- a/xpp/xpp_fxloader.usermap
+++ b/xpp/utils/xpp_fxloader.usermap
@@ -1,2 +1,4 @@
# module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info
xpp_fxloader 0x0003 0x04b4 0x8613 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
+xpp_fxloader 0x0003 0xe4e4 0x1130 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
+xpp_fxloader 0x0003 0xe4e4 0x1131 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
diff --git a/xpp/xpp_modprobe b/xpp/utils/xpp_modprobe
index 52d76b2..76c1f7d 100644
--- a/xpp/xpp_modprobe
+++ b/xpp/utils/xpp_modprobe
@@ -2,9 +2,9 @@
#options zaptel debug=1
#options wcfxo debug=1
#options xpp print_dbg=1
+#options xpp_usb print_dbg=1
+#options xpd_fxs print_dbg=1
+#options xpd_fxo print_dbg=1
# For pre-loading of card modules (e.g: xpp_fxs)
#install xpp_usb /sbin/modprobe xpd_fxs && /sbin/modprobe --ignore-install xpp_usb
-
-# For auto loading of card modules
-alias xpd-type-3 xpd_fxs
diff --git a/xpp/xbus-core.c b/xpp/xbus-core.c
new file mode 100644
index 0000000..5a85f8b
--- /dev/null
+++ b/xpp/xbus-core.c
@@ -0,0 +1,874 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+# warning "This module is tested only with 2.6 kernels"
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/device.h>
+#include <linux/delay.h> /* for mdelay() to debug */
+#include "xpd.h"
+#include "xpp_zap.h"
+#include "xbus-core.h"
+#include "zap_debug.h"
+
+static const char rcsid[] = "$Id$";
+
+/* Defines */
+#define POLL_TIMEOUT (MAX_XPDS) /* in jiffies */
+#define PROC_XBUSES "xbuses"
+#define PROC_XBUS_SUMMARY "summary"
+#define PROC_XBUS_WAITFOR_XPDS "waitfor_xpds"
+
+/* Command line parameters */
+extern int print_dbg;
+extern int max_queue_len;
+
+/* Forward declarations */
+#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
+
+static DEVICE_ATTR_FUNC(connector_show, dev, buf);
+static DEVICE_ATTR_FUNC(status_show, dev, buf);
+
+static int xbus_poll(void *data);
+static void xbus_release(struct device *dev);
+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);
+
+/* Data structures */
+struct workqueue_struct *xpp_worker = NULL;
+static spinlock_t xbuses_lock = SPIN_LOCK_UNLOCKED;
+static xbus_t *xbuses_array[MAX_BUSES] = {};
+static int bus_count = 0;
+static struct proc_dir_entry *proc_xbuses = NULL;
+
+static DEVICE_ATTR(connector, S_IRUGO, connector_show, NULL);
+static DEVICE_ATTR(status, S_IRUGO, status_show, NULL);
+
+/*------------------------- Packet Handling ------------------------*/
+static kmem_cache_t *packet_cache = NULL;
+static atomic_t xpacket_count = ATOMIC_INIT(0);
+
+/**
+ * Allocates a new XPP packet.
+ * @xbus The XPP bus in which the packet will flow (for counters
+ * maintenance)
+ * @flags Flags for kernel memory allocation.
+ * @returns A pointer to the new packet, or NULL in case of failure.
+ *
+ *
+ * Packet allocation/deallocation:
+ * Sent packets:
+ * - Allocated by protocol commands
+ * - Deallocated by xmus_xmitter
+ * Receive packets:
+ * - Allocated/deallocated by xbus_xmiter
+ */
+xpacket_t *xbus_packet_new(xbus_t *xbus, int flags)
+{
+ xpacket_t *pack;
+
+ /* To avoid races we increament counter in advance and decrement it later
+ * in case of failure */
+ atomic_inc(&xbus->packet_counter);
+ //DBG("Incremented packet_counter of bus %s (new packet) to %d\n",
+ // xbus->busname, atomic_read(&xbus->packet_counter));
+ pack = kmem_cache_alloc(packet_cache, flags);
+ if (pack) {
+ memset(pack, 0, sizeof(xpacket_t));
+ atomic_inc(&xpacket_count);
+ } else {
+ atomic_dec(&xbus->packet_counter);
+ //DBG("Decremented packet_counter of bus %s (failed new packet) to %d\n",
+ // xbus->busname, atomic_read(&xbus->packet_counter));
+ }
+ return pack;
+}
+
+void xbus_packet_free(xbus_t *xbus, xpacket_t *p)
+{
+ kmem_cache_free(packet_cache, p);
+ atomic_dec(&xpacket_count);
+ atomic_dec(&xbus->packet_counter);
+ //DBG("Decremented packet_counter of bus %s (freed packet) to %d\n",
+ // xbus->busname, atomic_read(&xbus->packet_counter));
+}
+
+/*------------------------- Packet Queues --------------------------*/
+void init_xbus_packet_queue(packet_queue_t *q, const char name[])
+{
+ INIT_LIST_HEAD(&q->head);
+ spin_lock_init(&q->lock);
+ q->count = 0;
+ q->worst_count = 0;
+ q->overflows = 0;
+ snprintf(q->qname, XPD_NAMELEN, "%s", name);
+}
+
+#if 0
+/*
+ * Assume the queue is locked
+ */
+void __dump_packet_queue(const char *msg, packet_queue_t *q)
+{
+ xpacket_t *tmp;
+
+ list_for_each_entry(tmp, &q->head, list) {
+ dump_packet(msg, tmp);
+ }
+}
+#endif
+
+void drain_xbus_packet_queue(xbus_t *xbus, packet_queue_t *q)
+{
+ unsigned long flags;
+ xpacket_t *pack;
+ xpacket_t *next;
+
+ spin_lock_irqsave(&q->lock, flags);
+ DBG("queue=%s count=%d\n", q->qname, q->count);
+ DBG(" total packets count=%d\n", atomic_read(&xpacket_count));
+ list_for_each_entry_safe(pack, next, &q->head, list) {
+ list_del(&pack->list);
+ q->count--;
+ xbus->ops->packet_free(xbus, pack);
+ }
+ if(q->count != 0)
+ ERR("drain_xbus_packet_queue: queue %s still has %d packets\n",
+ q->qname, q->count);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+void xbus_enqueue_packet(xbus_t *xbus, packet_queue_t *q, xpacket_t *pack)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ if(q->count >= max_queue_len) {
+ static unsigned long last_notice = 0; // rate limit
+
+ if((jiffies - last_notice) < HZ) {
+ NOTICE("xbus_enqueue_packet: dropping packet (queue len = %d, max=%d)\n",
+ q->count, max_queue_len);
+ last_notice = jiffies;
+ }
+ q->overflows++;
+ xbus->ops->packet_free(xbus, pack);
+ goto out;
+ }
+ list_add_tail(&pack->list, &q->head);
+ q->count++;
+
+ if(q->count > q->worst_count)
+ q->worst_count = q->count;
+
+ if(q->count < max_queue_len/100 && q->worst_count > q->count) // Decay worst_count
+ q->worst_count--;
+
+ // dump_packet("ENQUEUED", pack, print_dbg);
+out:
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+xpacket_t *xbus_dequeue_packet(packet_queue_t *q)
+{
+ unsigned long flags;
+ struct list_head *p;
+ xpacket_t *pack = NULL;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ if(list_empty(&q->head)) {
+ // DBG("LIST EMPTY (count=%d)\n", q->count);
+ goto out;
+ }
+ p = q->head.next;
+ list_del(p);
+ q->count--;
+ pack = list_entry(p, xpacket_t, list);
+ // dump_packet("DEQUEUED", pack, print_dbg);
+out:
+ spin_unlock_irqrestore(&q->lock, flags);
+ return pack;
+}
+
+
+/*------------------------- Bus Management -------------------------*/
+xbus_t *xbus_of(int xbus_num)
+{
+ if(xbus_num < 0 || xbus_num >= MAX_BUSES)
+ return NULL;
+ return xbuses_array[xbus_num];
+}
+
+xpd_t *xpd_of(xbus_t *xbus, int xpd_num)
+{
+ if(!VALID_XPD_NUM(xpd_num))
+ return NULL;
+ return xbus->xpds[xpd_num];
+}
+
+int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd)
+{
+ unsigned int xpd_num = xpd->id;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&xbus->lock, flags);
+ if(!VALID_XPD_NUM(xpd_num)) {
+ ERR("%s: Bad xpd_num = %d\n", xbus->busname, xpd_num);
+ ret = -EINVAL;
+ goto out;
+ }
+ if(xbus->xpds[xpd_num] != NULL) {
+ xpd_t *other = xbus->xpds[xpd_num];
+
+ ERR("%s: xpd_num=%d is occupied by %p (%s)\n",
+ xbus->busname, xpd_num, other, other->xpdname);
+ ret = -EINVAL;
+ goto out;
+ }
+ xbus->xpds[xpd_num] = xpd;
+ 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->id;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&xbus->lock, flags);
+ if(!VALID_XPD_NUM(xpd_num)) {
+ ERR("%s: Bad xpd_num = %d\n", xbus->busname, xpd_num);
+ ret = -EINVAL;
+ goto out;
+ }
+ if(xbus->xpds[xpd_num] != xpd) {
+ xpd_t *other = xbus->xpds[xpd_num];
+
+ ERR("%s: xpd_num=%d is occupied by %p (%s)\n",
+ xbus->busname, xpd_num, other, other->xpdname);
+ ret = -EINVAL;
+ goto out;
+ }
+ xbus->xpds[xpd_num] = NULL;
+ xbus->num_xpds--;
+ xpd->xbus = NULL;
+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.
+ */
+static int xbus_poll(void *data)
+{
+ int id;
+ int ret;
+ 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;
+ int xpd_num;
+ xbus_t *xbus = data;
+
+ spin_lock_irqsave(&xbus->lock, flags);
+ DBG("%s\n", xbus->busname);
+
+ /*
+ * Send out the polls
+ */
+ atomic_set(&xbus->count_poll_answers, 0);
+ for(id = 0; id < MAX_XPDS; id++) {
+ if(!xbus->hardware_exists)
+ break;
+ // DBG(" Polling slot %d %s\n", id, xbus->busname);
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ ret = CALL_PROTO(GLOBAL, DESC_REQ, xbus, NULL, id);
+ spin_lock_irqsave(&xbus->lock, flags);
+ if(ret < 0) {
+ NOTICE("xpp: %s: Failed sending DESC_REQ to XPD #%d\n", __FUNCTION__, id);
+ break;
+ }
+ mdelay(1); /* FIXME: debugging for Dima */
+ }
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ DBG("%s: Polled %d XPD's. Waiting for replies\n", xbus->busname, MAX_XPDS);
+ ret = wait_event_timeout(xbus->wait_for_polls, atomic_read(&xbus->count_poll_answers) >= MAX_XPDS, POLL_TIMEOUT);
+ if(ret < 0) {
+ ERR("%s: Poll timeout %d\n", xbus->busname, ret);
+ return ret;
+ }
+ DBG("%s: Poll finished. Start processing.\n", xbus->busname);
+ 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, &xbus->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);
+ xpd_num = xpd_addr2num(&card_desc->xpd_addr);
+ xpd = xpd_of(xbus, xpd_num);
+
+ 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 */
+ list_move_tail(card, &additions_list);
+ count_added++;
+ } else { /* same same */
+ list_del(card);
+ kfree(card_desc);
+ }
+ }
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ INFO("%s: Poll results: removals=%d additions=%d\n", xbus->busname, count_removed, count_added);
+ 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_num = xpd_addr2num(&card_desc->xpd_addr);
+ xpd = xpd_of(xbus, xpd_num);
+ if(xpd)
+ xpd_disconnect(xpd);
+ kfree(card);
+ }
+ 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);
+ card_detected(card_desc);
+ }
+ complete_all(&xbus->xpds_initialized);
+ return 0;
+}
+
+
+void xbus_activate(xbus_t *xbus)
+{
+ xbus_ops_t *ops;
+
+ BUG_ON(!xbus);
+ ops = xbus->ops;
+ BUG_ON(!ops);
+ BUG_ON(!xbus->priv);
+ /* Sanity checks */
+ BUG_ON(!ops->packet_send);
+ BUG_ON(!ops->packet_new || !ops->packet_free);
+ xbus->hardware_exists = 1;
+ DBG("Activating: %s\n", xbus->busname);
+ /* Poll it */
+ INIT_WORK(&xbus->xpds_init_work, (void (*)(void *))xbus_poll, (void *)xbus);
+ if(!queue_work(xpp_worker, &xbus->xpds_init_work)) {
+ ERR("Failed to queue xpd initialization work\n");
+ /* FIXME: need to return error */
+ }
+}
+
+void xbus_disconnect(xbus_t *xbus)
+{
+ int i;
+
+ BUG_ON(!xbus);
+ DBG("%s\n", xbus->busname);
+ xbus->hardware_exists = 0;
+ for(i = 0; i < MAX_XPDS; i++) {
+ xpd_t *xpd = xpd_of(xbus, i);
+ if(!xpd)
+ continue;
+ if(xpd->id != i) {
+ ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
+ continue;
+ }
+ xpd_disconnect(xpd);
+ }
+ DBG("%s (deactivated)\n", xbus->busname);
+ if(xbus->open_counter == 0) {
+ xbus_remove(xbus);
+ }
+}
+
+static xbus_t *xbus_alloc(void)
+{
+ unsigned long flags;
+ xbus_t *xbus;
+ int i;
+
+ xbus = kmalloc(sizeof(xbus_t), GFP_KERNEL);
+ if(!xbus) {
+ ERR("%s: out of memory\n", __FUNCTION__);
+ return NULL;
+ }
+ memset(xbus, 0, sizeof(xbus_t));
+ spin_lock_irqsave(&xbuses_lock, flags);
+ for(i = 0; i < MAX_BUSES; i++)
+ if(xbuses_array[i] == 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 */
+ xbuses_array[i] = xbus;
+ xbus->num = i;
+ bus_count++;
+ spin_unlock_irqrestore(&xbuses_lock, flags);
+ return xbus;
+}
+
+
+static void xbus_free(xbus_t *xbus)
+{
+ unsigned long flags;
+
+ if(!xbus)
+ return;
+ spin_lock_irqsave(&xbuses_lock, flags);
+ BUG_ON(xbus != xbus_of(xbus->num));
+ xbuses_array[xbus->num] = NULL;
+ bus_count--;
+ spin_unlock_irqrestore(&xbuses_lock, flags);
+#ifdef CONFIG_PROC_FS
+ if(xbus->proc_xbus_dir) {
+ if(xbus->proc_xbus_summary) {
+ DBG("Removing proc '%s' for %s\n", PROC_XBUS_SUMMARY, xbus->busname);
+ remove_proc_entry(PROC_XBUS_SUMMARY, xbus->proc_xbus_dir);
+ xbus->proc_xbus_summary = NULL;
+ }
+ if(xbus->proc_xbus_waitfor_xpds) {
+ DBG("Removing proc '%s' for %s\n", PROC_XBUS_WAITFOR_XPDS, xbus->busname);
+ remove_proc_entry(PROC_XBUS_WAITFOR_XPDS, xbus->proc_xbus_dir);
+ xbus->proc_xbus_waitfor_xpds = NULL;
+ }
+ DBG("Removing proc directory %s\n", xbus->busname);
+ remove_proc_entry(xbus->busname, xpp_proc_toplevel);
+ xbus->proc_xbus_dir = NULL;
+ }
+#endif
+ device_remove_file(&xbus->the_bus, &dev_attr_status);
+ device_remove_file(&xbus->the_bus, &dev_attr_connector);
+ device_unregister(&xbus->the_bus);
+ kfree(xbus);
+}
+
+static void xbus_release(struct device *dev)
+{
+ xbus_t *xbus;
+
+ BUG_ON(!dev);
+ xbus = dev->driver_data;
+ DBG("%s\n", xbus->busname);
+}
+
+
+xbus_t *xbus_new(xbus_ops_t *ops)
+{
+ int err;
+ xbus_t *xbus = NULL;
+
+ BUG_ON(!ops);
+ xbus = xbus_alloc();
+ if(!xbus)
+ return NULL;
+
+ /* Init data structures */
+ spin_lock_init(&xbus->lock);
+ snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%d", xbus->num);
+ INFO("New xbus: %s\n", xbus->busname);
+ init_waitqueue_head(&xbus->packet_cache_empty);
+ atomic_set(&xbus->packet_counter, 0);
+ atomic_set(&xbus->count_poll_answers, 0);
+ init_waitqueue_head(&xbus->wait_for_polls);
+ init_rwsem(&xbus->in_use);
+ INIT_LIST_HEAD(&xbus->poll_results);
+ init_completion(&xbus->xpds_initialized);
+ xbus->num_xpds = 0;
+ xbus_reset_counters(xbus);
+
+ /* Device-Model */
+ snprintf(xbus->the_bus.bus_id, BUS_ID_SIZE, "xbus-%d", xbus->num);
+ xbus->the_bus.driver_data = xbus;
+ xbus->the_bus.release = xbus_release;
+
+ err = device_register(&xbus->the_bus);
+ if(err) {
+ ERR("%s: device_register failed: %d\n", __FUNCTION__, err);
+ goto nobus;
+ }
+ err = device_create_file(&xbus->the_bus, &dev_attr_connector);
+ if(err) {
+ ERR("%s: device_create_file failed: %d\n", __FUNCTION__, err);
+ goto nobus;
+ }
+ err = device_create_file(&xbus->the_bus, &dev_attr_status);
+ if(err) {
+ ERR("%s: device_create_file failed: %d\n", __FUNCTION__, err);
+ goto nobus;
+ }
+
+#ifdef CONFIG_PROC_FS
+ DBG("Creating xbus proc directory %s.\n",xbus->busname);
+ xbus->proc_xbus_dir = proc_mkdir(xbus->busname, xpp_proc_toplevel);
+ if(!xbus->proc_xbus_dir) {
+ ERR("Failed to create proc directory for xbus %s\n", xbus->busname);
+ err = -EIO;
+ goto nobus;
+ }
+ xbus->proc_xbus_summary = create_proc_read_entry(PROC_XBUS_SUMMARY, 0444, xbus->proc_xbus_dir,
+ xbus_read_proc, xbus);
+ if (!xbus->proc_xbus_summary) {
+ ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_SUMMARY, xbus->busname);
+ err = -EIO;
+ goto nobus;
+ }
+ xbus->proc_xbus_summary->owner = THIS_MODULE;
+ xbus->proc_xbus_waitfor_xpds = create_proc_read_entry(PROC_XBUS_WAITFOR_XPDS, 0444, xbus->proc_xbus_dir,
+ xbus_read_waitfor_xpds, xbus);
+ if (!xbus->proc_xbus_waitfor_xpds) {
+ ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_WAITFOR_XPDS, xbus->busname);
+ err = -EIO;
+ goto nobus;
+ }
+ xbus->proc_xbus_waitfor_xpds->owner = THIS_MODULE;
+#endif
+ /* Sanity checks */
+ if(!ops->packet_send) {
+ ERR("%s: missing mandatory handler: packet_send\n", __FUNCTION__);
+ goto nobus;
+ }
+ if(!ops->packet_new || !ops->packet_free) {
+ NOTICE("%s: Using default packet allocators\n", __FUNCTION__);
+ ops->packet_new = xbus_packet_new;
+ ops->packet_free = xbus_packet_free;
+ }
+
+ xbus->ops = ops;
+ return xbus;
+nobus:
+ xbus_free(xbus);
+ return NULL;
+}
+
+void xbus_remove(xbus_t *xbus)
+{
+ int i;
+ int ret;
+
+ BUG_ON(!xbus);
+ DBG("%s\n", xbus->busname);
+
+ /* Block until no one use */
+ down_write(&xbus->in_use);
+
+ INFO("Removing xbus(%d) %s\n", xbus->num, xbus->busname);
+ for(i = 0; i < MAX_XPDS; i++) {
+ xpd_t *xpd = xpd_of(xbus, i);
+
+ if(xpd) {
+ if(xpd->id != i) {
+ ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
+ continue;
+ }
+ DBG(" Removing xpd id=%d\n", xpd->id);
+ xpd_remove(xpd);
+ }
+ xbus->xpds[i] = NULL;
+ }
+ ret = wait_event_interruptible(xbus->packet_cache_empty,
+ atomic_read(&xbus->packet_counter) == 0);
+ if(ret) {
+ ERR("waiting for packet_cache_empty interrupted!!!\n");
+ }
+ xbus_free(xbus);
+}
+
+/*------------------------- Proc handling --------------------------*/
+
+void xbus_reset_counters(xbus_t *xbus)
+{
+ int i;
+
+ DBG("Reseting counters of %s\n", xbus->busname);
+ for(i = 0; i < XBUS_COUNTER_MAX; i++) {
+ xbus->counters[i] = 0;
+ }
+}
+
+#if CONFIG_PROC_FS
+static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xbus_t *xbus = data;
+ int i;
+
+ if(!xbus)
+ goto out;
+ spin_lock_irqsave(&xbus->lock, flags);
+
+ len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
+ xbus->busname,
+ xbus->busdesc,
+ (xbus->hardware_exists) ? "connected" : "missing",
+ xbus->bus_type
+ );
+ len += sprintf(page + len, "POLLS: %d/%d\n", atomic_read(&xbus->count_poll_answers), MAX_XPDS);
+ len += sprintf(page + len, "XPDS_READY: %s\n", (xbus->xpds_initialized.done) ? "YES" : "NO");
+ len += sprintf(page + len, "\nmax_packet_size=%d open_counter=%d packet_count=%d\n",
+ xbus->max_packet_size,
+ xbus->open_counter,
+ atomic_read(&xbus->packet_counter)
+ );
+ len += sprintf(page + len, "COUNTERS:\n");
+ for(i = 0; i < XBUS_COUNTER_MAX; i++) {
+ len += sprintf(page + len, "\t%-15s = %d\n",
+ xbus_counters[i].name, xbus->counters[i]);
+ }
+ len += sprintf(page + len, "<-- len=%d\n", len);
+ spin_unlock_irqrestore(&xbus->lock, flags);
+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;
+ int i;
+
+ if(!xbus)
+ goto out;
+ i = wait_for_completion_interruptible_timeout(&xbus->xpds_initialized, 40*HZ);
+ if(i < 0) {
+ NOTICE("PID=%d waiting for XPDS initialization failed: %d\n", current->pid, i);
+ return i;
+ }
+ spin_lock_irqsave(&xbus->lock, flags);
+ len += sprintf(page + len, "XPDS_READY: %s\n", (xbus->xpds_initialized.done) ? "YES" : "NO");
+ 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;
+
+}
+
+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 = xbus_of(i);
+
+ if(xbus) {
+ len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
+ xbus->busname,
+ xbus->busdesc,
+ (xbus->hardware_exists) ? "connected" : "missing",
+ xbus->bus_type
+ );
+ }
+ }
+#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
+
+/*------------------------- Initialization -------------------------*/
+
+static DEVICE_ATTR_FUNC(connector_show, dev, buf)
+{
+ xbus_t *xbus;
+ int ret;
+
+ xbus = dev->driver_data;
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", xbus->busdesc);
+ return ret;
+}
+
+static DEVICE_ATTR_FUNC(status_show, dev, buf)
+{
+ xbus_t *xbus;
+ int ret;
+
+ xbus = dev->driver_data;
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", (xbus->hardware_exists)?"connected":"missing");
+ return ret;
+}
+
+static int xbus_match(struct device *dev, struct device_driver *driver)
+{
+ DBG("dev->bus_id = %s, driver->name = %s\n", dev->bus_id, driver->name);
+ return strncmp(dev->bus_id, driver->name, strlen(driver->name)) == 0;
+}
+
+#if 0
+/* Hotplug replaced with uevent in 2.6.16 */
+static int xbus_hotplug(struct device *device, char **envp, int envnum, char *buff, int bufsize)
+{
+ envp[0] = buff;
+ if(snprintf(buff, bufsize, "XBUS_VERSION=%s", revision) >= bufsize)
+ return -ENOMEM;
+ envp[1] = NULL;
+ return 0;
+}
+#endif
+
+struct bus_type xbus_bus_type = {
+ .name = "xbus",
+ .match = xbus_match,
+/* FIXME: Hotplug replaced with uevent in 2.6.16 */
+#if 0
+ .hotplug = xbus_hotplug,
+#endif
+};
+
+static void xbus_core_cleanup(void)
+{
+ if (xpp_worker) {
+ flush_workqueue(xpp_worker);
+ destroy_workqueue(xpp_worker);
+ xpp_worker = NULL;
+ }
+#ifdef CONFIG_PROC_FS
+ if(proc_xbuses)
+ remove_proc_entry(PROC_XBUSES, xpp_proc_toplevel);
+#endif
+ if(packet_cache)
+ kmem_cache_destroy(packet_cache);
+}
+
+int __init xbus_core_init(void)
+{
+ int ret;
+
+ packet_cache = kmem_cache_create("xpp_packets",
+ sizeof(xpacket_t),
+ 0, 0,
+ NULL, NULL);
+ if(!packet_cache) {
+ return -ENOMEM;
+ }
+ xpp_worker = create_singlethread_workqueue("xppworker");
+ if(!xpp_worker) {
+ ERR("Failed to create card detector workqueue.\n");
+ xbus_core_cleanup();
+ return -ENOMEM;
+ }
+#ifdef CONFIG_PROC_FS
+ proc_xbuses = create_proc_read_entry(PROC_XBUSES, 0444, xpp_proc_toplevel, read_proc_xbuses, 0);
+ if (!proc_xbuses) {
+ ERR("Failed to create proc file %s\n", PROC_XBUSES);
+ xbus_core_cleanup();
+ return -EFAULT;
+ }
+ proc_xbuses->owner = THIS_MODULE;
+#endif
+ ret = bus_register(&xbus_bus_type);
+ if(ret) {
+ ERR("%s: bus_register failed. Error number %d", __FUNCTION__, ret);
+ xbus_core_cleanup();
+ return ret;
+ }
+ return 0;
+}
+
+
+void __exit xbus_core_shutdown(void)
+{
+ int i;
+
+ for(i = 0; i < MAX_BUSES; i++) {
+ xbus_t *xbus = xbus_of(i);
+ if(xbus)
+ xbus_remove(xbus);
+ }
+ BUG_ON(bus_count);
+ bus_unregister(&xbus_bus_type);
+ xbus_core_cleanup();
+}
+
+EXPORT_SYMBOL(xpd_of);
+EXPORT_SYMBOL(xbus_new);
+EXPORT_SYMBOL(xbus_remove);
+EXPORT_SYMBOL(xbus_activate);
+EXPORT_SYMBOL(xbus_disconnect);
+EXPORT_SYMBOL(xbus_reset_counters);
diff --git a/xpp/xbus-core.h b/xpp/xbus-core.h
new file mode 100644
index 0000000..780c1b6
--- /dev/null
+++ b/xpp/xbus-core.h
@@ -0,0 +1,56 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef XBUS_CORE_H
+#define XBUS_CORE_H
+
+#include "xpd.h"
+
+#define MAX_BUSES 16
+
+int xbus_core_init(void); /* Initializer */
+void xbus_core_shutdown(void); /* Terminator */
+
+/* Packet handling */
+xpacket_t *xbus_packet_new(xbus_t *xbus, int flags);
+void xbus_packet_free(xbus_t *xbus, xpacket_t *p);
+
+/* packet queues */
+void init_xbus_packet_queue(packet_queue_t *q, const char name[]);
+void drain_xbus_packet_queue(xbus_t *xbus, packet_queue_t *q);
+void xbus_enqueue_packet(xbus_t *xbus, packet_queue_t *q, xpacket_t *pack);
+xpacket_t *xbus_dequeue_packet(packet_queue_t *q);
+
+/* XBUS handling */
+xbus_t *xbus_of(int xbus_num);
+xpd_t *xpd_of(xbus_t *xbus, int xpd_num);
+xbus_t *xbus_new(xbus_ops_t *ops);
+void xbus_remove(xbus_t *xbus);
+void xbus_activate(xbus_t *xbus);
+void xbus_disconnect(xbus_t *xbus);
+
+void xbus_reset_counters(xbus_t *xbus);
+
+int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd);
+int xbus_unregister_xpd(xbus_t *xbus, xpd_t *xpd);
+
+#endif /* XBUS_CORE_H */
+
diff --git a/xpp/xdefs.h b/xpp/xdefs.h
index 8c902bd..491e7b6 100644
--- a/xpp/xdefs.h
+++ b/xpp/xdefs.h
@@ -2,7 +2,7 @@
#define XDEFS_H
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -26,15 +26,10 @@
#include <linux/kernel.h>
-#define DBG(fmt, ...) \
- ((print_dbg) && printk(KERN_DEBUG "DBG-%s: %s: " fmt, \
- THIS_MODULE->name, __FUNCTION__, ## __VA_ARGS__))
-#define INFO(fmt, ...) printk(KERN_INFO "INFO-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
-#define NOTICE(fmt, ...) printk(KERN_NOTICE "NOTICE-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
-#define ERR(fmt, ...) printk(KERN_ERR "ERR-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
-
#else
+/* This is to enable user-space programs to include this. */
+
#include <stdint.h>
typedef uint32_t __u32;
@@ -50,33 +45,58 @@ struct list_head { struct list_head *next; struct list_head *prev; };
#endif
-typedef char *charp;
-typedef unsigned char byte;
-typedef int bool;
-typedef struct xbus xbus_t;
-typedef struct xpd xpd_t;
-typedef struct xpacket_raw xpacket_raw_t;
-typedef struct xpacket xpacket_t;
-typedef struct xops xops_t;
-typedef __u32 xpp_line_t; /* at most 31 lines for E1 */
+#define PACKED __attribute__((packed))
+#define ALL_LINES ((lineno_t)-1)
-#define BIT_SET(x,i) ((x) |= (1 << (i)))
-#define BIT_CLR(x,i) ((x) &= ~(1 << (i)))
-#define IS_SET(x,i) (((x) & (1 << (i))) != 0)
#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) (BIT(i) - 1)
+
+#define CHANNELS_PERXPD 30 /* 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 UNIT_BITS 4 /* Bit for Astribank unit number */
+#define SUBUNIT_BITS 4 /* Bit for Astribank subunit number */
-#undef SUPPORT_USB1
+#define MAX_UNIT 4 /* 1 FXS + 3 FXS/FXO */
+#define MAX_SUBUNIT 1 /* Firmware does not support subunits yet */
-#ifdef SUPPORT_USB1
/*
- * packet size <= 64 bytes:
- * ZT_CHUNKSIZE * 7 channels + header size <= 64
+ * Compile time sanity checks
*/
-#define CHANNELS_PERXPD 7 /* 7 * ZT_CHUNKSIZE + header <= 64 bytes */
-#else
-#define CHANNELS_PERXPD 30 /* Depends on xpp_line_t and protocol fields */
+#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)
+
+typedef char *charp;
+typedef unsigned char byte;
+typedef int bool;
+typedef struct xbus xbus_t;
+typedef struct xpd xpd_t;
+typedef struct xpacket_raw xpacket_raw_t;
+typedef struct xpacket xpacket_t;
+typedef struct xops xops_t;
+typedef __u32 xpp_line_t; /* at most 31 lines for E1 */
+typedef int lineno_t;
+
#endif /* XDEFS_H */
diff --git a/xpp/xpd.h b/xpp/xpd.h
index 1576274..4de2510 100644
--- a/xpp/xpd.h
+++ b/xpp/xpd.h
@@ -3,7 +3,7 @@
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -28,6 +28,7 @@
#ifdef __KERNEL__
#include <linux/kernel.h>
+#include <linux/device.h>
#include <asm/atomic.h>
#include <asm/semaphore.h>
#include <linux/moduleparam.h>
@@ -61,20 +62,6 @@
#endif // __KERNEL__
-#define MAX_SPANNAME 20
-#define MAX_SPANDESC 40
-#define MAX_CHANNAME 20
-
-#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
-
-/* Hardware does not check bank_num yet. So only 4 cards can be used */
-#define MAX_XPDS 4 // 1 FXS + 2 E1/T1 + 1 (Quad * E1/T1)
-
-#define VALID_XPD_NUM(x) ((x) < MAX_XPDS && (x) >= 0)
-
typedef struct xbus_ops xbus_ops_t;
typedef enum xbus_type {
@@ -100,15 +87,17 @@ struct xbus_ops {
void (*packet_free)(xbus_t *xbus, xpacket_t *p);
};
+/*
+ * XBUS statistics counters
+ */
enum {
XBUS_N_DESC_REQ,
- XBUS_N_DEV_DESC,
+ XBUS_N_DEV_DESC_FULL,
+ XBUS_N_DEV_DESC_EMPTY,
XBUS_N_PCM_WRITE,
XBUS_N_PCM_READ,
XBUS_N_TX_BYTES,
XBUS_N_RX_BYTES,
- XBUS_N_SOFTSIM_PACKETS,
- XBUS_N_SIM_PACKETS,
};
#define XBUS_COUNTER(xbus, counter) ((xbus)->counters[XBUS_N_ ## counter])
@@ -120,68 +109,76 @@ static struct xbus_counters {
char *name;
} xbus_counters[] = {
C_(DESC_REQ),
- C_(DEV_DESC),
+ C_(DEV_DESC_FULL),
+ C_(DEV_DESC_EMPTY),
C_(PCM_WRITE),
C_(PCM_READ),
C_(TX_BYTES),
C_(RX_BYTES),
- C_(SOFTSIM_PACKETS),
- C_(SIM_PACKETS),
};
#undef C_
#define XBUS_COUNTER_MAX ARRAY_SIZE(xbus_counters)
-struct xpd_sim {
- bool simulated;
- bool softloop_xpd;
- int loopto;
- xpd_type_t xpd_type;
- xpp_line_t hookstate;
+#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 */
+ xpd_addr_t xpd_addr;
};
+/*
+ * An xbus is a transport layer for Xorcom Protocol commands
+ */
struct xbus {
- char busname[XBUS_NAMELEN]; /* only xbus_new set this */
- char busdesc[XBUS_DESCLEN]; /* lowlevel drivers set this */
- int num;
- xbus_ops_t *ops;
- struct xpd *xpds[MAX_XPDS];
+ char busname[XBUS_NAMELEN]; /* only xbus_new set this */
+ char busdesc[XBUS_DESCLEN]; /* lowlevel drivers set this */
+ int num;
+ xbus_ops_t *ops;
+ struct xpd *xpds[MAX_XPDS];
+ int max_packet_size;
- /* Simulator data */
- xbus_type_t bus_type;
-#if SOFT_SIMULATOR
- struct xpd_sim sim[MAX_XPDS];
- struct workqueue_struct *sim_workqueue;
- struct work_struct sim_work; // workqueue job for running simulator
- packet_queue_t sim_packet_queue;
-#endif
+ /* Device-Model */
+ struct device the_bus;
- spinlock_t lock;
-
- bool hardware_exists; /* Hardware is functional */
- int open_counter; /* Number of open channels */
- atomic_t packet_counter; /* Allocated packets */
- wait_queue_head_t packet_cache_empty;
+ /* Simulator data */
+ xbus_type_t bus_type;
- struct timer_list poll_timer;
- struct rw_semaphore in_use;
- int num_xpds;
- void *priv; /* Pointer to transport level data structures */
+ spinlock_t lock;
-#ifdef XPP_PACKET_LOG
- struct cyclic_buff *packet_log;
-#endif
+ bool hardware_exists; /* Hardware is functional */
+ int open_counter; /* Number of open channels */
+ atomic_t packet_counter; /* Allocated packets */
+ wait_queue_head_t packet_cache_empty;
+
+ struct timer_list poll_timer;
+ /*
+ * Bus scanning
+ */
+ atomic_t count_poll_answers;
+ struct list_head poll_results;
+ wait_queue_head_t wait_for_polls;
+ struct work_struct xpds_init_work;
+ struct completion xpds_initialized;
+
+ struct rw_semaphore in_use;
+ int num_xpds;
+ void *priv; /* Pointer to transport level data structures */
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_xbus_dir;
struct proc_dir_entry *proc_xbus_summary;
+ struct proc_dir_entry *proc_xbus_waitfor_xpds;
#endif
/* statistics */
int counters[XBUS_COUNTER_MAX];
-
};
#endif
@@ -190,15 +187,11 @@ typedef enum xpd_direction {
TO_PSTN = 1,
} xpd_direction_t;
-#define LINE_BITS (sizeof(xpp_line_t)*8)
-
-
#ifdef __KERNEL__
-#define BIT_SET(x,i) ((x) |= (1 << (i)))
-#define BIT_CLR(x,i) ((x) &= ~(1 << (i)))
-#define IS_SET(x,i) (((x) & (1 << (i))) != 0)
-#define BIT(i) (1 << (i))
+/*
+ * XPD statistics counters
+ */
enum {
XPD_N_PCM_READ,
XPD_N_PCM_WRITE,
@@ -222,60 +215,74 @@ static struct xpd_counters {
#define XPD_COUNTER_MAX (sizeof(xpd_counters)/sizeof(xpd_counters[0]))
-enum leds {
- LED_GREEN,
- LED_RED,
- LED_BLUE,
-};
+#define LED_BLINK_PERIOD (HZ/8)
-#define NUM_LEDS 3
+#define LED_ON 1
+#define LED_OFF 0
+#define LED_BLINK (-LED_BLINK_PERIOD)
+/* Values of SLIC register 0x40 */
+enum fxs_state {
+ FXS_LINE_DISABLED = 0x00,
+ FXS_LINE_ENABLED = 0x01,
+ FXS_LINE_CID = 0x02,
+ FXS_LINE_TIPOPEN = 0x03, /* For GroundStart signalling */
+ FXS_LINE_RING = 0x04,
+ FXS_LINE_REV_ACTIVE = 0x05
+};
+
+/*
+ * 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;
+ byte revision; /* Card revision */
xpd_direction_t direction; /* TO_PHONE, TO_PSTN */
- xpp_line_t enabled_chans; /* hardware activation: 0 - off, 1 - on */
- xpp_line_t hookstate; /* 0 - ONHOOK, 1 - OFHOOK */
- xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
+ xpp_line_t no_pcm; /* Temporary: disable PCM (for USB-1) */
+ xpp_line_t hookstate; /* Actual chip state: 0 - ONHOOK, 1 - OFHOOK */
+ xpp_line_t cid_on;
xpp_line_t digital_outputs; /* 0 - no, 1 - yes */
xpp_line_t digital_inputs; /* 0 - no, 1 - yes */
- int ringing[CHANNELS_PERXPD];
- bool ringer_on[CHANNELS_PERXPD]; /* For ring toggling */
- bool led_on[CHANNELS_PERXPD]; /* For led toggling */
- int lasttxhook[CHANNELS_PERXPD];
+ int ringing[CHANNELS_PERXPD];
+ bool ringer_on[CHANNELS_PERXPD]; /* For ring toggling */
+
+ wait_queue_head_t txstateq[CHANNELS_PERXPD]; /* waiting on the tx state to change */
+ int delay_until_dialtone[CHANNELS_PERXPD];
- struct work_struct xpd_post_init;
- xbus_t *xbus;
+ enum fxs_state lasttxhook[CHANNELS_PERXPD];
+ int idletxhookstate[CHANNELS_PERXPD]; /* IDLE changing hook state */
+ int ohttimer[CHANNELS_PERXPD];
+
+ xbus_t *xbus; /* The XBUS we are connected to */
spinlock_t lock;
- atomic_t open_counter; /* Number of open channels */
+ atomic_t open_counter; /* Number of open channels */
int flags;
- unsigned int board_flags;
-#define XPD_BOARD_LOOPBACK 1
-
#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;
#endif
- // Bit numbers of board_flags
int counters[XPD_COUNTER_MAX];
- const xops_t *xops; /* Card level operations */
- void *priv; /* Card level private data */
- atomic_t card_present;
+ 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;
unsigned int recv_errors;
unsigned int seq_errors;
unsigned long last_response; /* in jiffies */
unsigned id;
+ xpd_addr_t addr;
struct list_head xpd_list;
unsigned int timer_count;
volatile u_char *writechunk; /* Double-word aligned write memory */
@@ -285,6 +292,9 @@ struct xpd {
u_char ec_chunk2[CHANNELS_PERXPD][ZT_CHUNKSIZE];
};
+#define for_each_line(xpd,i) \
+ for((i) = 0; (i) < (xpd)->channels; (i)++)
+
#endif
#endif /* XPD_H */
diff --git a/xpp/xpp_fxloader b/xpp/xpp_fxloader
deleted file mode 100644
index a46c156..0000000
--- a/xpp/xpp_fxloader
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-
-FIRMWARE="/etc/xortel/FPGA_XPD.hex"
-me=`basename $0`
-
-# to run manually, pass the parameter 'xppdetect'
-V_ID=04b4
-P_ID=8613
-if [ "$1" = 'xppdetect' ]; then
- DEVICES=`lsusb | tr -d : | awk "/ ID $V_ID$P_ID /{printf \"/proc/bus/usb/%s/%s \",\\$2,\\$4}"`
- echo "Loading firmware for $DEVICES"
- for dev in $DEVICES
- do
- fxload -t fx2 -D $dev -I $FIRMWARE
- done
- exit 0
-fi
-
-if [ "$ACTION" = "add" ] && [ -f "$DEVICE" ]
-then
- logger -i -t "$me" "Loading firmware '$FIRMWARE' into '$DEVICE'"
- fxload -t fx2 -D "$DEVICE" -I "$FIRMWARE" || exit 1
-fi
-
diff --git a/xpp/xpp_proto.c b/xpp/xpp_proto.c
deleted file mode 100644
index b020caf..0000000
--- a/xpp/xpp_proto.c
+++ /dev/null
@@ -1,1044 +0,0 @@
-#include <linux/module.h>
-#include <linux/delay.h> /* for udelay */
-#include "xpd.h"
-#include "xpp_proto.h"
-#include "xpp_zap.h"
-
-static char rcsid[] = "$Id$";
-
-extern int print_dbg;
-#include "zap_debug.h"
-
-typedef struct xpp_command xpp_command_t;
-typedef int (*xpp_handler_t)(xbus_t *xbus, int id, xpp_command_t *cmd, xpacket_t *packet);
-
-struct xpp_command {
- xpp_opcode_t opcode;
- unsigned int header_size;
- bool varsize;
- const char *name;
- const char *desc;
- xpp_handler_t handler;
-};
-
-#define S_(s,l,...) \
- { \
- .lines = s, \
- { \
- .len = l, \
- .data = { __VA_ARGS__ }, \
- } \
- }
-
-struct slic_init_data {
- xpp_line_t lines;
- slic_data_t slic_data;
-} slic_init_data[] = {
-#include "slic_init.inc"
-};
-
-static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack);
-static int simulate_xpd(xbus_t *xbus, int xpd_num, xpacket_t *sent_packet);
-static bool pcm_valid(xpd_t *xpd, xpacket_t *reply);
-
-#define NEW_PACKET(p, xbus, name, to) \
- do { \
- p = xbus->ops->packet_new(xbus, GFP_ATOMIC); \
- if(!p) \
- return -ENOMEM; \
- PACKET_INIT(p, name); \
- XPD_ADDR_SET(p->content.addr, to); \
- } while(0);
-
-/*------------------------- SLIC Handling --------------------------*/
-
-int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = 0;
- unsigned long flags;
- xpd_t *xpd = data;
- //slic_reply_t *info;
-
- BUG_ON(!xpd);
- spin_lock_irqsave(&xpd->lock, flags);
-#if 0
- info = (slic_reply_t *)&xpd->slic_info;
- len += sprintf(page + len, "SLIC_REPLY: %s reg_num=0x%X, dataH=0x%X dataL=0x%X\n",
- (info->indirect)?"I":"D",
- info->reg_num, info->data_high, info->data_low);
-#endif
- spin_unlock_irqrestore(&xpd->lock, flags);
- if (len <= off+count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
- return len;
-}
-
-static int parse_slic_cmd(const char *buf, slic_cmd_t *sc)
-{
- char op; /* [W]rite, [R]ead */
- char reg_type; /* [D]irect, [I]ndirect */
- int s1, s2, s3, s4;
- int reg_num;
- int data_low, data_high;
- xpp_line_t lines;
- int ret;
-
- ret = sscanf(buf, "%x %x %x %x %c%c %x %x %x",
- &s1, &s2, &s3, &s4, &op, &reg_type, &reg_num, &data_high, &data_low);
- lines = (s4 << 24) | (s3 << 16) | (s2 << 8) | (s1);
- switch(op) {
- case 'R':
- if(reg_type == 'D' && ret == 7) {
- // DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num);
- ret = slic_cmd_direct_read(sc, lines, reg_num);
- } else if(reg_type == 'I' && ret == 7) {
- // DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num);
- ret = slic_cmd_indirect_read(sc, lines, reg_num);
- } else {
- NOTICE("%s: Bad read input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
- goto err;
- }
- break;
- case 'W':
- if(reg_type == 'D' && ret == 8) {
- // DBG("0x%X 0x%X 0x%X 0x%X %c %x %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high);
- ret = slic_cmd_direct_write(sc, lines, reg_num, data_high);
- } else if(reg_type == 'I' && ret == 9) {
- // DBG("0x%X 0x%X 0x%X 0x%X %c %x %X %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high, data_low);
- ret = slic_cmd_indirect_write(sc, lines, reg_num, data_low, data_high);
- } else {
- NOTICE("%s: Bad write input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
- goto err;
- }
- break;
- default:
- NOTICE("%s: Bad input: ret=%d buf='%s' op=%c\n", __FUNCTION__, ret, buf, op);
- goto err;
- }
- return ret;
-err:
- return -EINVAL;
-}
-
-static int process_slic_cmdline(xpd_t *xpd, char *cmdline)
-{
- xbus_t *xbus;
- slic_cmd_t sc;
- xpacket_t *pack_tx;
- char *p;
- int len = strlen(cmdline);
-
- 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;
- len = parse_slic_cmd(p, &sc);
- if(len < 0)
- return len;
- sc.lines &= xpd->enabled_chans; // Ignore disabled channels
- if(!sc.lines) {
- NOTICE("%s: no enabled channels are marked. Skip.\n", __FUNCTION__);
- return 0;
- }
- dump_slic_cmd("WRITE_SLIC", &sc);
- NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
- PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd) = sc;
- pack_tx->datalen = len;
- packet_send(xbus, pack_tx);
- return 0;
-}
-
-int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
-{
- xpd_t *xpd = data;
- const int LINE_LEN = 500;
- char buf[LINE_LEN];
- char *p;
- int i;
- int ret;
-
- BUG_ON(!xpd);
- for(i = 0; i < count; /* noop */) {
- for(p = buf; p < buf + LINE_LEN; 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 + LINE_LEN)
- return -E2BIG;
- *p = '\0';
- ret = process_slic_cmdline(xpd, buf);
- if(ret < 0)
- return ret;
- }
- return count;
-}
-
-
-
-/*------------------------- Protocol Functions ---------------------*/
-
-#define HOSTCMD(name, ...) \
- DECLARE_CMD(name, ## __VA_ARGS__ ); \
- EXPORT_SYMBOL(xpp_proto_ ## name); \
- DECLARE_CMD(name, ## __VA_ARGS__ )
-
-
-/* 0x04 */ HOSTCMD(DESC_REQ, int xpd_num)
-{
- int ret = 0;
- xpacket_t *pack_tx;
-
- DBG("\n");
- if(!xbus) {
- DBG("NO XBUS\n");
- return -EINVAL;
- }
- NEW_PACKET(pack_tx, xbus, DESC_REQ, xpd_num);
- DBG("calling packet_send for a DESC_REQ packet.\n");
- ret = packet_send(xbus, pack_tx);
- DBG("after packet_send, updating counter (ret=%d)\n", ret);
- XBUS_COUNTER(xbus, DESC_REQ)++;
- return ret;
-}
-
-/* 0x0F */ HOSTCMD(CHAN_POWER, xpp_line_t lines, bool on)
-{
- int ret = 0;
- xpacket_t *pack_tx;
- slic_cmd_t *sc;
- int len;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- lines &= xpd->enabled_chans; // Ignore disabled channels
- if(!lines) {
- return 0;
- }
- DBG("Channel Power: 0x%04X %s\n", lines, (on) ? "up" : "down");
- NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
- sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
- if(on) {
- // Power up
- len = slic_cmd_direct_write(sc, lines, 0x42, 0x06);
- } else {
- // Power down
- len = slic_cmd_direct_write(sc, lines, 0x42, 0x00);
- }
- pack_tx->datalen = len;
-
- packet_send(xbus, pack_tx);
- return ret;
-}
-
-/* 0x0F */ HOSTCMD(CHAN_ENABLE, xpp_line_t lines, bool on)
-{
- int ret = 0;
- xpacket_t *pack_tx;
- slic_cmd_t *sc;
- int len;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- lines &= xpd->enabled_chans; // Ignore disabled channels
- if(!lines) {
- return 0;
- }
- DBG("Channel Activation: 0x%4X %s\n", lines, (on) ? "on" : "off");
- NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
- sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
- len = slic_cmd_direct_write(sc, lines, 0x40, (on)?0x01:0x00);
- pack_tx->datalen = len;
-
- packet_send(xbus, pack_tx);
- return ret;
-}
-
-/* 0x0F */ HOSTCMD(RING, int pos, bool on)
-{
- int ret = 0;
- xpacket_t *pack_tx;
- slic_cmd_t *sc;
- xpp_line_t mask = (1 << pos);
- int len;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- mask &= xpd->enabled_chans; // Ignore disabled channels
- if(!mask) {
- return 0;
- }
- DBG("%s pos=%d %s\n", xpd->xpdname, pos, (on) ? "on" : "off");
- NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
- sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
- len = slic_cmd_direct_write(sc, mask, 0x40, (on)?0x04:0x01);
- pack_tx->datalen = len;
-
- packet_send(xbus, pack_tx);
- return ret;
-}
-
-/* 0x0F */ HOSTCMD(SETHOOK, xpp_line_t hook_status)
-{
- int ret = 0;
- xpacket_t *pack_tx;
- slic_cmd_t *sc;
- int len;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- hook_status &= xpd->enabled_chans; // Ignore disabled channels
- if(!hook_status) {
- return 0;
- }
- DBG("New hook_status: %d\n", hook_status);
- NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
- sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
- /* FIXME: This is fake, until Dima implements FXO */
- len = slic_cmd_direct_write(sc, hook_status, 0x02, 0x00);
- pack_tx->datalen = len;
-
- packet_send(xbus, pack_tx);
- return ret;
-}
-
-/*
- * LED control is done via SLIC register 0x06:
- * 7 6 5 4 3 2 1 0
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- * | MR | MG | MB | R | OG | OB | G | B |
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- *
- * B - BLUE LED (0 - OFF, 1 - ON)
- * G - GREEN LED (0 - OFF, 1 - ON)
- * OB - Output BLUE (this line is output)
- * OG - Output GREEN (this line is output)
- * R - RED LED (0 - OFF, 1 - ON)
- * MB - Mask BLUE. (1 - B effect the BLUE LED)
- * MR - Mask RED. (1 - R effect the RED LED)
- * MG - Mask GREEN. (1 - G effect the GREEN LED)
- *
- * The BLUE LED (actually a relay out) is connected to line 0 and 4 only.
- */
-
-// GREEN RED BLUE
-static int led_mask[NUM_LEDS] = { BIT(6), BIT(7), BIT(5) };
-static int led_vals[NUM_LEDS] = { BIT(1), BIT(4), BIT(0) };
-
-/* 0x0F */ HOSTCMD(LED, xpp_line_t lines, byte which, bool on)
-{
- int ret = 0;
- xpacket_t *pack_tx;
- slic_cmd_t *sc;
- int len;
- int value;
- int i;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- lines &= xpd->enabled_chans; // Ignore disabled channels
- if(!lines) {
- return 0;
- }
- DBG("LED: lines=0x%04X which=%d -- %s\n", lines, which, (on) ? "on" : "off");
- which = which % NUM_LEDS;
- value = BIT(2) | BIT(3);
- value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[which]);
- if(on)
- value |= led_vals[which];
- for(i = 0; i < CHANNELS_PERXPD; i++) {
- if(!IS_SET(lines, i))
- continue;
- NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
- sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
- len = slic_cmd_direct_write(sc, lines, 0x06, value);
- DBG("LED pack: line=%d value=0x%04X\n", i, value);
- pack_tx->datalen = len;
- packet_send(xbus, pack_tx);
- }
- return ret;
-}
-
-/* 0x0F */ HOSTCMD(RELAY_OUT, byte which, bool on)
-{
- int ret = 0;
- xpacket_t *pack_tx;
- slic_cmd_t *sc;
- int len;
- int value;
- xpp_line_t lines;
- int relay_channels[] = { 0, 4 };
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
-
- DBG("RELAY_OUT: which=%d -- %s\n", which, (on) ? "on" : "off");
- which = which % ARRAY_SIZE(relay_channels);
- lines = BIT(relay_channels[which]);
- value = BIT(2) | BIT(3);
- value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[LED_BLUE]);
- if(on)
- value |= led_vals[LED_BLUE];
- NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
- sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
- len = slic_cmd_direct_write(sc, lines, 0x06, value);
-
- DBG("RELAY_OUT pack: line=%d value=0x%04X\n", lines, value);
- pack_tx->datalen = len;
- packet_send(xbus, pack_tx);
- return ret;
-}
-
-/* 0x0F */ HOSTCMD(SLIC_INIT)
-{
- int ret = 0;
- xpacket_t *pack_tx;
- slic_data_t *slic;
- struct slic_init_data *source;
- int i;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- DBG("INITIALIZING SLIC\n");
- for(i = 0; i < ARRAY_SIZE(slic_init_data); i++) {
- source = &slic_init_data[i];
- NEW_PACKET(pack_tx, xbus, SLIC_INIT, xpd->id);
- PACKET_FIELD(pack_tx, SLIC_INIT, lines) = source->lines;
-
- slic = &PACKET_FIELD(pack_tx, SLIC_INIT, slic_data);
- slic->len = source->slic_data.len;
- memcpy(slic->data, source->slic_data.data, source->slic_data.len);
- pack_tx->datalen = sizeof(xpp_line_t) + slic->len + 1;
-// dump_packet("SLIC", pack_tx, print_dbg);
- packet_send(xbus, pack_tx);
- mdelay(10); // FIXME: Temporary -- Dima need to fix it
- }
- return ret;
-}
-
-/* 0x0F */ HOSTCMD(SLIC_QUERY, int pos, byte reg_num)
-{
- int ret = 0;
- xpacket_t *pack_tx;
- slic_cmd_t *sc;
- int len;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
- sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
- len = slic_cmd_direct_read(sc, (1<<pos), reg_num);
-
- pack_tx->datalen = len;
-
- packet_send(xbus, pack_tx);
- return ret;
-}
-
-/* 0x11 */ HOSTCMD(PCM_WRITE, xpp_line_t lines, volatile byte *buf)
-{
- int ret = 0;
- xpacket_t *pack_tx;
- byte *pcm;
- byte *start_pcm;
- int i;
- extern ulong pcm_gen;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- lines &= xpd->enabled_chans;
- // DBG("PCM_WRITE\n");
- if(pcm_gen != 0)
- return 0;
-// if(lines == 0)
-// return 0;
-
- /*
- * FIXME: Workaround a bug in sync code of the Astribank.
- * Send dummy PCM for sync.
- */
- if(lines == 0)
- lines = BIT(0);
-
- NEW_PACKET(pack_tx, xbus, PCM_WRITE, xpd->id);
- PACKET_FIELD(pack_tx, PCM_WRITE, lines) = lines;
- start_pcm = pcm = PACKET_FIELD(pack_tx, PCM_WRITE, pcm);
- for(i = 0; i < CHANNELS_PERXPD; i++) {
- if(IS_SET(lines, i)) {
- memcpy(pcm, (byte *)buf, ZT_CHUNKSIZE);
- pcm += ZT_CHUNKSIZE;
- }
- buf += ZT_CHUNKSIZE;
- }
- pack_tx->datalen = sizeof(xpp_line_t) + (pcm - start_pcm);
- packet_send(xbus, pack_tx);
- XPD_COUNTER(xpd, PCM_WRITE)++;
- XBUS_COUNTER(xbus, PCM_WRITE)++;
- return ret;
-}
-
-/* 0x13 */ HOSTCMD(PCM_GEN, xpp_line_t lines, volatile byte *buf)
-{
- xpacket_t *pack_tx;
- bool gen_seq = ((lines != 0) && (buf != NULL));
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- lines &= xpd->enabled_chans; // Ignore disabled channels
- if(!lines) {
- return 0;
- }
- DBG("PCM_GEN lines=0x%04X %s\n", lines, (gen_seq) ? "seq" : "off");
- NEW_PACKET(pack_tx, xbus, PCM_GEN, xpd->id);
- PACKET_FIELD(pack_tx, PCM_GEN, lines) = lines;
- if(gen_seq) {
- PACKET_FIELD(pack_tx, PCM_GEN, gen) = 0;
- memcpy(&PACKET_FIELD(pack_tx, PCM_GEN, pcm_seq), (byte *)buf, ZT_CHUNKSIZE);
- } else {
- PACKET_FIELD(pack_tx, PCM_GEN, gen) = 2;
- }
- packet_send(xbus, pack_tx);
- return 0;
-}
-
-/*
- * Sync source is controled by a mask byte to 0x19 command:
- * 7 6 5 4 3 2 1 0
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- * | | | | | | | RW | AB |
- * +-----+-----+-----+-----+-----+-----+-----+-----+
- *
- * RW - Read or set (0 - Write, 1 - Read)
- * AB - This Astribank provide sync (0 - no, 1 - yes)
- *
- */
-
-/* 0x19 */ HOSTCMD(SYNC_SOURCE, bool setit, bool is_master)
-{
- xpacket_t *pack_tx;
- byte mask = 0;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- if(is_master)
- mask |= BIT(0);
- if(!setit)
- mask |= BIT(1);
- DBG("SYNC_SOURCE %s setit=%s is_master=%s (mask=0x%X)\n",
- xpd->xpdname, (setit)?"yes":"no", (is_master)?"yes":"no", mask);
- NEW_PACKET(pack_tx, xbus, SYNC_SOURCE, xpd->id);
- PACKET_FIELD(pack_tx, SYNC_SOURCE, mask) = mask;
- packet_send(xbus, pack_tx);
- return 0;
-}
-
-/* 0x31 */ HOSTCMD(LOOPBACK_AX, byte *data, unsigned int size)
-{
- xpacket_t *pack_tx;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- DBG("LOOPBACK_AX %d bytes\n", size);
- NEW_PACKET(pack_tx, xbus, LOOPBACK_AX, xpd->id);
- memcpy(&PACKET_FIELD(pack_tx, LOOPBACK_AX, data), data, size);
- packet_send(xbus, pack_tx);
- return 0;
-}
-
-/*------------------------- Protocol Simulator ---------------------*/
-
-
-static int simulate_xpd(xbus_t *xbus, int xpd_num, xpacket_t *sent_packet)
-{
- xpacket_t *pack = sent_packet;
- struct xpd_sim *xpd_sim;
- struct xpd_sim *loopto_sim;
- xpp_opcode_t opcode;
- int dest_xpd_num;
- int ret = 0;
-
- // Sanity checks
- BUG_ON(!xbus);
- BUG_ON(xpd_num > MAX_XPDS || xpd_num < 0);
- BUG_ON(!sent_packet);
- BUG_ON(!xbus->sim[xpd_num].simulated);
-
- XBUS_COUNTER(xbus, SIM_PACKETS)++;
- xpd_sim = &xbus->sim[xpd_num];
- opcode = pack->content.opcode;
- dest_xpd_num = xpd_sim->loopto;
- loopto_sim = &xbus->sim[dest_xpd_num];
-// DBG("before: addr=%d, opcode=0x%X\n", xpd_num, opcode);
- switch(opcode) {
- case XPP_DESC_REQ:
- DBG("SIM DESC_REQ (xpd_num=%d)\n", xpd_num);
- PACKET_INIT(pack, DEV_DESC);
- PACKET_FIELD(pack, DEV_DESC, type) = xpd_sim->xpd_type;
- dest_xpd_num = xpd_num; // Reply as the original XPD
- break;
- case XPP_PCM_WRITE:
- PACKET_INIT(pack, PCM_READ);
- XPD_ADDR_SET(pack->content.addr, dest_xpd_num);
- break;
- case XPP_SLIC_WRITE:
-#if FINISHED_DECODING_SLICS
- slic_cmd_t *sc;
- int len;
-
- sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
- lines = sc->lines;
- bool slic_write = ! (slic->data[0] & 0x80);
- int slic_reg = slic->data[0] & ~0x80;
-
- if(slic->len == 2 && slic_write && slic_reg == 0x40) { // RING
- bool on = (slic->data[1] == 0x04);
- if(on) {
- loopto_sim->hookstate |= lines;
- } else {
- loopto_sim->hookstate &= ~lines;
- }
-
- DBG("SIM RING to: xpd=%d (type=%d): (%s) ringing=0x%04X lines=0x%04X\n", dest_xpd_num, loopto_sim->xpd_type,
- (on)?"on":"off", loopto_sim->hookstate, lines);
- PACKET_INIT(pack, SIG_CHANGED);
- PACKET_FIELD(pack, SIG_CHANGED, type) = loopto_sim->xpd_type;
- PACKET_FIELD(pack, SIG_CHANGED, sig_status) = loopto_sim->hookstate;
- PACKET_FIELD(pack, SIG_CHANGED, sig_toggles) = lines;
- dump_packet("SIM RING TO", pack, print_dbg);
- break;
- } else if(slic->len == 1 && slic_write && slic_reg == 0x02) { // SETHOOK
- DBG("SIM SETHOOK: xpd=%d: hookstate=0x%04X lines=0x%04X\n", dest_xpd_num, loopto_sim->hookstate, lines);
- PACKET_INIT(pack, SIG_CHANGED);
- PACKET_FIELD(pack, SIG_CHANGED, type) = loopto_sim->xpd_type;
- PACKET_FIELD(pack, SIG_CHANGED, sig_status) = lines;
- PACKET_FIELD(pack, SIG_CHANGED, sig_toggles) = loopto_sim->hookstate ^ lines;
- loopto_sim->hookstate = lines;
- break;
- } else if(slic->len == 2 && slic_write && slic_reg == 0x06) { // LED
- DBG("SIM LED: xpd=%d: 0x%04X=%s\n", xpd_num, lines, (0x10)? "on" : "off");
- ret = 0;
- goto junk;
- } else if(slic->len == 2 && ! slic_write) { // SLIC_QUERY
- DBG("SIM SLIC_QUERY: xpd=%d: register=0x%02X\n", xpd_num, slic_reg);
- ret = 0;
- goto junk;
- } else if(slic->len >= 4) { // INITIALIZATION?
- DBG("SIM INITIALIZATION? xpd=%d len=%d\n", xpd_num, slic->len);
- ret = 0;
- goto junk;
- }
- NOTICE("%s: xpd=%d: SLIC_WRITE: len=%d\n", __FUNCTION__, xpd_num, slic->len);
-#endif
- dump_packet("BAD SLIC_WRITE", pack, print_dbg);
- // FALL THROUGH
- default:
- NOTICE("%s: xpd=%d: CANNOT SIMULATE OPCODE=0x%02X\n",
- __FUNCTION__, xpd_num, opcode);
-// dump_packet("BAD OPCODE", pack, print_dbg);
- ret = -EINVAL;
- goto junk;
- }
-// DBG("after reversing: addr=%d, opcode=0x%X\n", xpd_num, pack->header.opcode);
- return packet_process(xbus, dest_xpd_num, pack);
-junk:
- xbus->ops->packet_free(xbus, pack);
- return ret;
-}
-
-#define VERBOSE_DEBUG 1
-#define ERR_REPORT_LIMIT 20
-
-void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg)
-{
- xpp_opcode_t op = (byte)packet->content.opcode;
-
- if(!print_dbg)
- return;
- DBG("%s: @0x%02X OP=0x%02X flags=0x%02X LEN=%d\n",
- msg,
- XPD_NUM(packet->content.addr),
- op,
- (byte)packet->flags,
- (byte)packet->datalen);
-#if VERBOSE_DEBUG
- {
- int i;
- byte *p = packet->content.raw;
-
- for(i = 0; i < packet->datalen; i++) {
- static int limiter = 0;
-
- if(i >= sizeof(xpp_packet_r_t)) {
- if(limiter < ERR_REPORT_LIMIT) {
- ERR("dump_packet: length overflow i=%d > sizeof(xpp_packet_r_t)=%d\n",
- i+1, sizeof(xpp_packet_r_t));
- } else if(limiter == ERR_REPORT_LIMIT) {
- ERR("dump_packet: error packet #%d... squelsh reports.\n", limiter);
- }
- limiter++;
- break;
- }
- DBG(" %2d> %02X\n", i+1, p[i]);
- }
- }
-#endif
-}
-
-/*------------------------- Reply Handlers -------------------------*/
-
-#define HANDLER_DEF(name) \
- int CALL_PROTO(name, xbus_t *xbus, int xpd_num, xpp_command_t *cmd, xpacket_t *reply)
-
-/*
-static HANDLER_DEF(notimp)
-{
- NOTICE("xpp protocol error: command %s is not implemented yet\n", cmd->name);
- return -EPROTO;
-}
-*/
-static HANDLER_DEF(DEV_DESC)
-{
- byte type = PACKET_FIELD(reply, DEV_DESC, type) & 0x7; // 3 LSB's
- byte rev = PACKET_FIELD(reply, DEV_DESC, rev);
- xpp_line_t line_status = PACKET_FIELD(reply, DEV_DESC, line_status);
- xpd_t *xpd = xpd_of(xbus, xpd_num);
-
- if(xpd) {
- NOTICE("Received DEV_DESC packet for an existing xpd %s of type %d\n",
- xpd->xpdname, type);
- return 0;
- }
- XBUS_COUNTER(xbus, DEV_DESC)++;
- DBG("xpd=%d type=%d rev=%d line_status=0x%04X\n", xpd_num, type, rev, line_status);
- switch(type) {
- case XPD_TYPE_FXS:
- break;
- case XPD_TYPE_FXO:
- break;
- case XPD_TYPE_NOMODULE:
- DBG("No module at address=%d\n", xpd_num);
- return 0;
- default:
- NOTICE("DEV_DESC: unkown type=%d\n", type);
- return -EPROTO;
- }
- if((xpd = xpd_new(xbus, xpd_num, type, rev)) == NULL) {
- NOTICE("xpd_new failed\n");
- }
- xpp_check_hookstate(xpd, line_status);
- return 0;
-}
-
-/**
- * Handle signalling
- */
-static HANDLER_DEF(SIG_CHANGED)
-{
- xpd_t *xpd = xpd_of(xbus, xpd_num);
- xpp_line_t sig_status = PACKET_FIELD(reply, SIG_CHANGED, sig_status);
-
- if(!xpd) {
- NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
- return -EPROTO;
- }
- if(xpd->direction == TO_PHONE) { /* Hook state changes */
- DBG("%s (PHONE) sig_status=0x%04X\n", xpd->xpdname, sig_status);
- xpp_check_hookstate(xpd, sig_status);
- } else { /* TO_TRUNK - line ring changes */
- unsigned long flags;
- int i;
-
- DBG("%s (TRUNK) sig_status=0x%04X\n", xpd->xpdname, sig_status);
- spin_lock_irqsave(&xpd->lock, flags);
- for(i = 0; i < xpd->channels; i++) {
- if(IS_SET(sig_status, i)) {
- xpd->ringing[i] = RINGS_NUM*2;
- zt_hooksig(&xpd->chans[i], ZT_RXSIG_OFFHOOK);
- } else {
- zt_hooksig(&xpd->chans[i], ZT_RXSIG_ONHOOK);
- xpd->ringing[i] = 0;
- }
- }
- spin_unlock_irqrestore(&xpd->lock, flags);
- }
- return 0;
-}
-
-static HANDLER_DEF(SLIC_REPLY)
-{
- slic_reply_t *info = &PACKET_FIELD(reply, SLIC_REPLY, info);
- xpd_t *xpd = xpd_of(xbus, xpd_num);
- unsigned long flags;
-
- if(!xpd) {
- NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
- return -EPROTO;
- }
- spin_lock_irqsave(&xpd->lock, flags);
- DBG("SLIC_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
- xpd_num, (info->indirect)?"I":"D",
- info->reg_num, info->data_low, info->data_high);
- spin_unlock_irqrestore(&xpd->lock, flags);
- return 0;
-}
-
-static HANDLER_DEF(PCM_READ)
-{
- /* FIXME: work around temporary hardware bug */
- xpd_num = 0;
-
- xpp_line_t lines = PACKET_FIELD(reply, PCM_READ, lines);
- const byte *pcm = PACKET_FIELD(reply, PCM_READ, pcm);
- xpd_t *xpd = xpd_of(xbus, xpd_num);
- volatile u_char *readchunk;
- volatile u_char *r;
- unsigned long flags;
- int i;
-
- if(!xpd) {
- NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
- return -EPROTO;
- }
- // DBG("lines=0x%04X\n", lines);
-
- if(!pcm_valid(xpd, reply)) {
- return -EPROTO;
- }
- spin_lock_irqsave(&xpd->lock, flags);
- if (xpd->timer_count & 1) {
- /* First part */
- r = readchunk = xpd->readchunk;
- } else {
- r = readchunk = xpd->readchunk + ZT_CHUNKSIZE * CHANNELS_PERXPD;
- }
-
- /* Copy PCM and put each channel in its index */
- for (i = 0; i < CHANNELS_PERXPD; i++) {
- if(IS_SET(lines, i)) {
- memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
- //memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG
- pcm += ZT_CHUNKSIZE;
- }
- r += ZT_CHUNKSIZE;
- }
-
- XPD_COUNTER(xpd, PCM_READ)++;
- XBUS_COUNTER(xpd->xbus, PCM_READ)++;
- spin_unlock_irqrestore(&xpd->lock, flags);
- if(xpd->id == 0)
- xpp_tick(0);
- return 0;
-}
-
-static HANDLER_DEF(SYNC_REPLY)
-{
- xpd_t *xpd = xpd_of(xbus, xpd_num);
-
- if(!xpd) {
- NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
- return -EPROTO;
- }
- DBG("SYNC_REPLY: 0x%X\n", PACKET_FIELD(reply, SYNC_REPLY, mask));
- return 0;
-}
-
-static HANDLER_DEF(LOOPBACK_XA)
-{
- xpd_t *xpd = xpd_of(xbus, xpd_num);
-
- if(!xpd) {
- NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
- return -EPROTO;
- }
- dump_packet("LOOPBACK_XA", reply, print_dbg);
- CALL_PROTO(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 0); // FIXME: Find usage for extra LED
- return 0;
-}
-
-static HANDLER_DEF(DIAG_FE)
-{
- dump_packet("DIAG_FE", reply, print_dbg);
- return 0;
-}
-
-static const xpp_packet_r_t FOR_SIZE_CALC; // Ugly hack, so we have something to sizeof()
-
-#define C_(op,var,txt) \
- [ XPP_##op ] { \
- .opcode = XPP_##op, \
- .varsize = var, \
- .header_size = sizeof(FOR_SIZE_CALC.cmd_##op), \
- .name = #op, \
- .desc = txt, \
- .handler = PROTO_FUNC(op) \
- }
-
-static xpp_command_t xpp_commands[] = {
- /* OP V DESCRIPTION */
- C_( DEV_DESC, 0, "Device description reply"),
- C_( SIG_CHANGED, 0, "Signaling change (hookstate/ringing)"),
- C_( SLIC_REPLY, 0, "Reply to slic state"),
- C_( PCM_READ, 1, "Read PCM data"),
- C_( SYNC_REPLY, 0, "SYNC_REPLY"),
- C_( LOOPBACK_XA, 1, "LOOPBACK Reply"),
- C_( DIAG_FE, 1, "DIAG FE Opcode"),
-};
-
-#undef C_
-
-static unsigned int xpp_max_opcode(void)
-{
- return ARRAY_SIZE(xpp_commands);
-}
-
-static bool xpp_valid_opcode(xpp_opcode_t op)
-{
- if(op <= 0 || op >= xpp_max_opcode())
- return 0;
- return xpp_commands[op].opcode != XPP_NOTIMP;
-}
-
-static xpp_command_t *xpp_command(xpp_opcode_t op)
-{
- if(!xpp_valid_opcode(op))
- return 0;
- return &xpp_commands[op];
-}
-
-static bool xpp_valid_size(xpp_opcode_t op, xpacket_t *pack)
-{
- xpp_command_t *cmd = xpp_command(op);
- unsigned int hsize = cmd->header_size;
- unsigned int size = pack->datalen;
- int varsize = cmd->varsize;
-
- // ERR("op=%d hsize=%d size=%d\n", op, hsize, size);
- return (hsize == size) ||
- (varsize && size <= sizeof(struct xpp_packet_r));
-}
-
-static bool pcm_valid(xpd_t *xpd, xpacket_t *reply)
-{
- xpp_opcode_t op;
- xpp_command_t *cmd;
- xpp_line_t lines = PACKET_FIELD(reply, PCM_READ, lines);
- int i;
- int count = 0;
-
- BUG_ON(!reply);
- op = reply->content.opcode;
- cmd = xpp_command(op);
- if(!cmd) {
- ERR("xpp: %s -- bad command op=0x%02X\n", __FUNCTION__, op);
- return 0;
- }
- for (i = 0; i < CHANNELS_PERXPD; i++)
- if(IS_SET(lines, i))
- count++;
- if(reply->datalen != (sizeof(xpp_line_t) + count * 8)) {
- static int rate_limit = 0;
-
- XPD_COUNTER(xpd, RECV_ERRORS)++;
- if((rate_limit++ % 1000) <= 10) {
- ERR("BAD PCM REPLY: reply->datalen=%d, count=%d\n", reply->datalen, count);
- }
- return 0;
- }
- return 1;
-}
-
-int packet_receive(xbus_t *xbus, xpacket_t *pack)
-{
- int xpd_num = XPD_NUM(pack->content.addr);
-
- if(!VALID_XPD_NUM(xpd_num)) {
- dump_packet("martian packet", pack, print_dbg);
- xbus->ops->packet_free(xbus, pack);
- return -EPROTO;
- }
- if(xbus->sim[xpd_num].simulated) {
- //dump_packet("packet_receive -> simulate", pack, print_dbg);
- return simulate_xpd(xbus, xpd_num, pack);
- } else {
- //dump_packet("packet_receive -> process", pack, print_dbg);
- return packet_process(xbus, xpd_num, pack);
- }
-}
-
-static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack)
-{
- xpp_opcode_t op;
- xpp_command_t *cmd;
- xpp_handler_t handler;
- int ret = 0;
-
- BUG_ON(!pack);
- op = pack->content.opcode;
- cmd = xpp_command(op);
- /*-------- Validations -----------*/
- if(!cmd) {
- ERR("xpp: %s -- bad command op=0x%02X\n", __FUNCTION__, op);
- dump_packet("packet_process -- bad command", pack, print_dbg);
- ret = -EPROTO;
- goto out;
- }
- if(!xpp_valid_size(op, pack)) {
- ERR("xpp: %s: wrong size %d for op=0x%02X\n",
- __FUNCTION__, pack->datalen, op);
- dump_packet("packet_process -- wrong size", pack, print_dbg);
- ret = -EPROTO;
- goto out;
- }
- handler = cmd->handler;
- BUG_ON(!handler);
- XBUS_COUNTER(xbus, RX_BYTES) += pack->datalen;
- handler(xbus, xpd_num, cmd, pack);
-out:
- xbus->ops->packet_free(xbus, pack);
- return ret;
-}
-
-
-void process_sim_queue(void *data)
-{
- xbus_t *xbus = data;
- xpacket_t *pack;
-
-// DBG("\n");
- BUG_ON(!xbus);
- while((pack = xbus_dequeue_packet(&xbus->sim_packet_queue)) != NULL) {
-// DBG("pack->addr=0x%X pack->opcode=0x%X\n", XPD_NUM(pack->addr), pack->header.opcode);
- packet_receive(xbus, pack);
- }
-}
-
-/**
- * processes a packet recieved from the lower-level.
- * @xbus the data bus
- * @pack the handled packet
- * @returns return status (0 for success).
- *
- * Should not be blocking.
- * Has separate handling for PCM packets (direct write) and command packets (queued)
- */
-
-EXPORT_SYMBOL(dump_packet);
-EXPORT_SYMBOL(packet_receive);
-EXPORT_SYMBOL(proc_xpd_slic_read);
-EXPORT_SYMBOL(proc_xpd_slic_write);
diff --git a/xpp/xpp_proto.h b/xpp/xpp_proto.h
deleted file mode 100644
index 46713d5..0000000
--- a/xpp/xpp_proto.h
+++ /dev/null
@@ -1,188 +0,0 @@
-#ifndef XPP_PROTO_H
-#define XPP_PROTO_H
-
-#include "xpd.h"
-#include "slic.h"
-#ifdef __KERNEL__
-#include <linux/list.h>
-#endif
-
-#define PCM_CHUNKSIZE (CHANNELS_PERXPD * ZT_MAX_CHUNKSIZE)
-
-typedef enum xpp_opcode {
- XPP_NOTIMP = 0x00,
-//
- XPP_DESC_REQ = 0x04,
- XPP_DEV_DESC = 0x05,
-//
- XPP_SIG_CHANGED = 0x06,
-//
- XPP_SLIC_WRITE = 0x0F, // Write to SLIC
- XPP_CHAN_ENABLE = 0x0F, // Write to SLIC
- XPP_CHAN_POWER = 0x0F, // Write to SLIC
- XPP_RING = 0x0F, // Write to SLIC
- XPP_SETHOOK = 0x0F, // Write to SLIC
- XPP_LED = 0x0F, // Write to SLIC
- XPP_RELAY_OUT = 0x0F, // Write to SLIC
- XPP_SLIC_INIT = 0x0F, // Write to SLIC
- XPP_SLIC_QUERY = 0x0F, // Write to SLIC
-//
- XPP_SLIC_REPLY = 0x10,
-//
- XPP_PCM_WRITE = 0x11,
- XPP_PCM_READ = 0x12,
-//
- XPP_PCM_GEN = 0x13,
-//
- XPP_SYNC_SOURCE = 0x19,
- XPP_SYNC_REPLY = 0x1A,
-//
- XPP_LOOPBACK_AX = 0x31,
- XPP_LOOPBACK_XA = 0x32,
- XPP_DIAG_FE = 0xFE,
-} xpp_opcode_t;
-
-/*------------------------- PROTOCOL COMMANDS ----------------------*/
-
-#define XPP_MAX_DATA 50
-
-typedef struct slic_data {
- byte len;
- byte data[40];
-} __attribute__((packed)) slic_data_t;
-
-#define PROTO_FUNC(name) xpp_proto_ ## name
-#define CALL_PROTO(name, ...) PROTO_FUNC(name)( __VA_ARGS__ )
-#define DECLARE_CMD(name, ...) \
- int CALL_PROTO(name, xbus_t *xbus, xpd_t *xpd, ## __VA_ARGS__ )
-
-/* 0x04 */ DECLARE_CMD(DESC_REQ, int xpd_num);
-/* 0x0F */ DECLARE_CMD(CHAN_ENABLE, xpp_line_t lines, bool on);
-/* 0x0F */ DECLARE_CMD(CHAN_POWER, xpp_line_t lines, bool on);
-/* 0x0F */ DECLARE_CMD(RING, int pos, bool on);
-/* 0x0F */ DECLARE_CMD(SETHOOK, xpp_line_t hook_status);
-/* 0x0F */ DECLARE_CMD(LED, xpp_line_t lines, byte which, bool on);
-/* 0x0F */ DECLARE_CMD(RELAY_OUT, byte which, bool on);
-/* 0x0F */ DECLARE_CMD(SLIC_INIT);
-/* 0x0F */ DECLARE_CMD(SLIC_QUERY, int pos, byte reg_num);
-/* 0x11 */ DECLARE_CMD(PCM_WRITE, xpp_line_t hookstate, volatile byte *buf);
-/* 0x13 */ DECLARE_CMD(PCM_GEN, xpp_line_t lines, volatile byte *buf);
-/* 0x19 */ DECLARE_CMD(SYNC_SOURCE, bool setit, bool is_master);
-/* 0x31 */ DECLARE_CMD(LOOPBACK_AX, byte *data, unsigned int size);
-
-#define H_(op, ...) struct { \
- __VA_ARGS__ \
- } __attribute__((packed)) cmd_##op
-
-/*
- * This struct must be packed exactly as the wire
- * representation of the packet header after the
- * XPD address byte
- */
-typedef struct xpp_packet_r {
- byte opcode;
- xpp_addr_t addr;
- union {
-
- H_(NOTIMP);
- H_(DESC_REQ);
- H_(DEV_DESC,
- byte rev; /* Revision number */
- byte type;
- xpp_line_t line_status; /* hook/ring status, depending on unit */
- );
-
- H_(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 */
- );
-
- H_(SLIC_INIT,
- xpp_line_t lines;
- slic_data_t slic_data;
- );
- H_(SLIC_WRITE,
- slic_cmd_t slic_cmd;
- );
- H_(SLIC_REPLY, /* Get status of a single SLIC (for debugging) */
- xpp_line_t lines;
- slic_reply_t info;
- );
-
- H_(PCM_WRITE,
- xpp_line_t lines; // Must be 0xFF
- byte pcm[PCM_CHUNKSIZE];
- );
- H_(PCM_READ,
- xpp_line_t lines; // Must be 0xFF
- byte pcm[PCM_CHUNKSIZE];
- );
-
- H_(PCM_GEN,
- xpp_line_t lines;
- byte gen;
- byte pcm_seq[ZT_CHUNKSIZE];
- );
-
- H_(SYNC_SOURCE,
- byte mask;
- );
- H_(SYNC_REPLY,
- byte mask;
- );
-
- H_(LOOPBACK_AX,
- byte data[XPP_MAX_DATA]; // FIXME: what data size?
- );
- H_(LOOPBACK_XA,
- byte data[XPP_MAX_DATA]; // FIXME: what data size?
- );
- H_(DIAG_FE);
- unsigned char raw[0];
- };
-} __attribute__((packed)) xpp_packet_r_t;
-#undef H_
-
-#ifdef __KERNEL__
-
-enum {
- XPP_PACKET_FIREANDFORGET = 0x1,
-};
-
-/**
- * The packet that will actually be sent on the wire.
- *
- * TODO: not a good medium-level abstrction
- */
-struct xpp_packet {
- struct xpp_packet_r content;
- unsigned int flags;
- size_t datalen;
- struct list_head list;
-};
-
-#define DATA_LEN(p, name) \
- sizeof(p->content.cmd_ ## name)
-
-#define PACKET_LEN(p) \
- ((p)->datalen + sizeof(xpp_addr_t) + 1)
-
-#define PACKET_INIT(p, name) \
- p->content.opcode = XPP_ ## name; \
- p->datalen = DATA_LEN(p, name)
-
-#define PACKET_FIELD(p, name, field) \
- p->content.cmd_ ## name.field
-
-void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg);
-void enqueue_xmit(xbus_t *xbus, xpacket_t *pack);
-void process_sim_queue(void *xbus);
-int validate_reply(xpacket_t *reply);
-int packet_receive(xbus_t *xbus, xpacket_t *pack);
-int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
-int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data);
-
-#endif
-
-#endif /* XPP_PROTO_H */
diff --git a/xpp/xpp_usb.c b/xpp/xpp_usb.c
index 83eee1a..4f81680 100644
--- a/xpp/xpp_usb.c
+++ b/xpp/xpp_usb.c
@@ -1,6 +1,6 @@
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -30,6 +30,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
+#include <linux/interrupt.h>
#include <linux/delay.h> /* for udelay */
#include <linux/seq_file.h>
#include <asm/uaccess.h>
@@ -37,11 +38,16 @@
#include <asm/timex.h>
#include <linux/proc_fs.h>
#include <linux/usb.h>
+#include <version.h> /* For zaptel version */
#include "xpd.h"
#include "xproto.h"
-#include "xpp_zap.h"
+#include "xbus-core.h"
+#ifdef DEBUG
+#include "card_fxs.h"
+#include "card_fxo.h"
+#endif
-static const char revision[] = "$Revision$";
+static const char rcsid[] = "$Id$";
DEF_PARM(int, print_dbg, 0, "Print DBG statements"); /* must be before zap_debug.h */
@@ -52,13 +58,11 @@ DEF_PARM(int, print_dbg, 0, "Print DBG statements"); /* must be before zap_debug
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
# define URB_ASYNC_UNLINK 0
#endif
-
#define USBDEV_MAX 10
/* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE 192
#ifdef CONFIG_PROC_FS
-#define PROC_XBUSES "xpp_usb"
#define PROC_USBXPP_SUMMARY "xpp_usb"
#endif
@@ -70,8 +74,9 @@ static cycles_t accumulate_diff;
struct xusb_model_info;
struct xusb_endpoint {
- int epnum;
- int max_size;
+ int ep_addr;
+ int max_size;
+ usb_complete_t callback;
};
static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack);
@@ -110,18 +115,24 @@ static struct xusb_counters {
#define XUSB_COUNTER_MAX ARRAY_SIZE(xusb_counters)
+#define MAX_PENDING_WRITES 100
+
+enum xusb_dir {
+ XUSB_RECV = 0,
+ XUSB_SEND = 1,
+};
+
/*
* USB XPP Bus (a USB Device)
*/
-struct xpp_usb_bus {
+typedef struct xpp_usb_bus {
xbus_t *xbus;
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 */
struct xusb_model_info *model_info;
- struct xusb_endpoint ep_in;
- struct xusb_endpoint ep_out;
+ struct xusb_endpoint endpoints[2]; /* RECV/SEND endpoints */
struct urb *read_urb;
@@ -129,12 +140,13 @@ struct xpp_usb_bus {
int present; /* if the device is not disconnected */
int reading; /* is the read_urb reading (listening) */
+ atomic_t pending_writes; /* submited but not out yet */
struct semaphore sem; /* locks this structure */
int counters[XUSB_COUNTER_MAX];
-};
+} xusb_t;
static spinlock_t xusb_lock = SPIN_LOCK_UNLOCKED;
-static struct xpp_usb_bus *xusb_array[USBDEV_MAX] = {};
+static xusb_t *xusb_array[USBDEV_MAX] = {};
static unsigned bus_count = 0;
@@ -153,7 +165,7 @@ static int xusb_release (struct inode *inode, struct file *file);
static void xusb_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
#endif
static void xpp_urb_delete(struct urb *urb);
-static struct urb *xpp_urb_new(struct xpp_usb_bus *dev, unsigned int ep_addr, size_t size, usb_complete_t urb_cb);
+static struct urb *xpp_urb_new(xusb_t *dev, enum xusb_dir dir, size_t size);
static void xpp_send_callback(struct urb *urb, struct pt_regs *regs);
static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs);
@@ -208,42 +220,34 @@ void xusb_packet_free(xbus_t *xbus, xpacket_t *p)
//DBG("Decremented packet_counter of bus %s (freed packet) to %d\n",
// xbus->busname, atomic_read(&xbus->packet_counter));
}
+
#endif
-static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack)
+#ifndef DEBUG
+
+#define packet_debug(m, x, p)
+
+#else
+
+static void packet_debug(const char msg[], xusb_t *xusb, xpacket_t *pack)
{
- struct xpp_usb_bus *xusb = xbus->priv;
- struct urb *urb;
- int ret = 0;
- size_t size;
+ char title[XBUS_DESCLEN];
- BUG_ON(!pack);
- if(!xusb->present) {
- NOTICE("tried to send packets to non-exitant USB device. Ignored\n");
- goto error;
- }
-#if SOFT_SIMULATOR
- {
- int toxpd = XPD_NUM(pack->content.addr);
-
- if (xbus->sim[toxpd].softloop_xpd) {
- // "send" through loopback queue
- //DBG("%s: ENQUEUE toxpd=%d, opcode=%X\n", xbus->busname, toxpd, pack->content.opcode);
- XBUS_COUNTER(xbus, SOFTSIM_PACKETS)++;
- xbus_enqueue_packet(xbus, &xbus->sim_packet_queue, pack);
- ret = queue_work(xbus->sim_workqueue, &xbus->sim_work);
- if(ret < 0) {
- ERR("%s: queue_work failed with %d (ignoring)\n", __FUNCTION__, ret);
- goto error;
- }
- }
- return 0;
- }
+ if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_READ)) {
+#ifdef DEBUG_PCM_TIMING
+ /*
+ * DEBUG: high-res timing of PCM_READ to PCM_WRITE
+ */
+ stamp_last_pcm_read = get_cycles();
#endif
- size = min(PACKET_LEN(pack), (size_t)xusb->ep_out.max_size);
- if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) {
- XUSB_COUNTER(xusb, PCM_WRITES)++;
-
+#if 0
+ // fill_beep((u_char *)&PACKET_FIELD(pack, PCM_READS, pcm), 2); // Debugging BEEP
+ static int rate_limit;
+ if((rate_limit++ % 1000) < 10)
+ dump_packet("USB RECEIVE PCM", pack, print_dbg);
+#endif
+ return;
+ } else if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) {
#ifdef DEBUG_PCM_TIMING
/*
* DEBUG: high-res timing of PCM_READ to PCM_WRITE
@@ -253,50 +257,96 @@ static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack)
#endif
#if 0
static int rate_limit;
- if((rate_limit++ % 1009) < 3) {
+ if((rate_limit++ % 1000) < 10)
dump_packet("USB SEND PCM", pack, print_dbg);
- }
#endif
- } else {
- dump_packet("USB_PACKET_SEND", pack, print_dbg);
+ return;
+ } else if(pack->content.opcode == XPROTO_NAME(FXS, SLIC_WRITE)) {
+ slic_cmd_t *sc;
+
+ sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
+ if(sc->bytes == 2 && sc->content.direct.reg_num == 0x06 && sc->content.direct.read) /* ignore SLIC_QUERY */
+ return;
+ if(sc->bytes == 2 && sc->content.direct.reg_num == DAA_VBAT_REGISTER && sc->content.direct.read) /* ignore DAA_QUERY */
+ return;
+ } else if(pack->content.opcode == XPROTO_NAME(FXS, SLIC_REPLY)) {
+ return;
+ }
+ snprintf(title, XBUS_DESCLEN, "%s: %s", msg, xusb->xbus->busname);
+ dump_packet(title, pack, print_dbg);
+}
+#endif
+
+static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack)
+{
+ xusb_t *xusb;
+ struct urb *urb;
+ int ret = 0;
+ size_t size;
+ struct xusb_endpoint *xusb_ep;
+
+ BUG_ON(!pack);
+ BUG_ON(!xbus);
+ xusb = xbus->priv;
+ BUG_ON(!xusb);
+ if(!xusb->present) {
+ NOTICE("tried to send packets to non-exitant USB device. Ignored\n");
+ ret = -ENODEV;
+ goto out;
}
- urb = xpp_urb_new(xusb, xusb->ep_out.epnum, size, xpp_send_callback);
+ size = PACKET_LEN(pack);
+ xusb_ep = &xusb->endpoints[XUSB_SEND];
+ urb = xpp_urb_new(xusb, XUSB_SEND, size);
if (!urb) {
ERR("No free urbs available\n");
ret = -ENOMEM;
- goto error;
+ goto out;
}
+ packet_debug("USB_PACKET_SEND", xusb, pack);
/* FIXME: FIXME: FIXME: we use copy+free until low-level drivers allocate memory themselves */
memcpy(urb->transfer_buffer, &pack->content, size);
- xbus->ops->packet_free(xbus, pack);
- ret = usb_submit_urb(urb, GFP_KERNEL);
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
if(ret < 0) {
- ERR("%s: failed submit_urb\n", __FUNCTION__);
- XUSB_COUNTER(xusb, TX_ERRORS)++;
+ ERR("%s: failed submit_urb: %d\n", __FUNCTION__, ret);
xpp_urb_delete(urb);
- return -EBADF;
+ ret = -EBADF;
+ goto out;
}
- return 0;
-error:
+ atomic_inc(&xusb->pending_writes);
+ if(atomic_read(&xusb->pending_writes) > MAX_PENDING_WRITES) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1000) < 10)
+ ERR("%s: %s: more than %d pending writes. Dropping.\n", __FUNCTION__, xbus->busname, MAX_PENDING_WRITES);
+ ret = -ENODEV;
+ }
+ if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE))
+ XUSB_COUNTER(xusb, PCM_WRITES)++;
+out:
+ if(ret < 0)
+ XUSB_COUNTER(xusb, TX_ERRORS)++;
xbus->ops->packet_free(xbus, pack); // FIXME: eventually will be done in the urb callback
return ret;
}
static void xpp_urb_delete(struct urb *urb)
{
+ BUG_ON(!urb);
// DBG("%s: (%d) %p %X", __FUNCTION__, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma);
usb_buffer_free (urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer,
urb->transfer_dma);
- usb_free_urb (urb);
+ usb_free_urb(urb);
}
-static struct urb *xpp_urb_new(struct xpp_usb_bus *dev, unsigned int ep_addr, size_t size, usb_complete_t urb_cb)
-
+static struct urb *xpp_urb_new(xusb_t *xusb, enum xusb_dir dir, size_t size)
{
- struct usb_device *udev = dev->udev;
+ 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;
struct urb *urb;
unsigned char *buffer; /* the buffer to send data */
unsigned int epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK;
@@ -304,6 +354,8 @@ static struct urb *xpp_urb_new(struct xpp_usb_bus *dev, unsigned int ep_addr, si
? usb_rcvbulkpipe(udev, epnum)
: usb_sndbulkpipe(udev, epnum);
+ if(size > xusb_ep->max_size)
+ return NULL;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
err("No free urbs available");
@@ -326,32 +378,36 @@ static struct urb *xpp_urb_new(struct xpp_usb_bus *dev, unsigned int ep_addr, si
usb_free_urb(urb);
return NULL;
}
- usb_fill_bulk_urb(urb, udev, pipe, buffer, size, urb_cb, dev);
+ usb_fill_bulk_urb(urb, udev, pipe, buffer, size, urb_cb, xusb);
return urb;
}
/*------------------------- XPP USB Bus Handling -------------------*/
-static struct xusb_model_info {
+#define XUSB_MODEL(ep_in,ep_out,type,str) \
+ { \
+ .in = { .ep_addr = (ep_in) }, \
+ .out = { .ep_addr = (ep_out) }, \
+ .bus_type = (type), \
+ .desc = (str) \
+ }
+
+static const struct xusb_model_info {
const char *desc;
struct xusb_endpoint in;
struct xusb_endpoint out;
xbus_type_t bus_type;
} model_table[] = {
- { .in = { .epnum = 0x86 }, .out = { .epnum = 0x2 }, .bus_type = FIRMWARE_LOOPBACK, .desc = "bulkloop.hex" },
- { .in = { .epnum = 0x86 }, .out = { .epnum = 0x2 }, .bus_type = FIRMWARE_LOOPBACK, .desc = "FPGA_bulkloop.hex" },
- { .in = { .epnum = 0x86 }, .out = { .epnum = 0x2 }, .bus_type = FIRMWARE_XPP, .desc = "FPGA_XPD.hex" },
+ XUSB_MODEL(0x86, 0x02, FIRMWARE_LOOPBACK, "bulkloop.hex"),
+ XUSB_MODEL(0x86, 0x02, FIRMWARE_LOOPBACK, "FPGA_bulkloop.hex"),
+ XUSB_MODEL(0x86, 0x02, FIRMWARE_XPP, "FPGA_XPD.hex"),
};
/* table of devices that work with this driver */
-static struct usb_device_id xusb_table [] = {
+static const struct usb_device_id xusb_table [] = {
// { USB_DEVICE(0x04B4, 0x8613) }, // default of cypress
- { USB_DEVICE(0x0547, 0x1002), .driver_info=(int)&model_table[0] }, // bulkloop.hex
-// { USB_DEVICE(0x04B4, 0x1004), .driver_info=(int)&model_table[1] }, // FPGA_bulkloop.hex
-// { USB_DEVICE(0x04B4, 0x1004), .driver_info=(int)&model_table[2] }, // FIXME: temporary test for Dima
- { USB_DEVICE(0xE4E4, 0x2211), .driver_info=(int)&model_table[2] }, // FPGA_XPD.hex
- //{ USB_DEVICE(0x0548, 0x1) },
- //{ USB_DEVICE(0x062a, 0x0) },
+ { USB_DEVICE(0xE4E4, 0x2211), .driver_info=(kernel_ulong_t)&model_table[2] }, // FPGA_XPD.hex
+ { USB_DEVICE(0xE4E4, 0x1132), .driver_info=(kernel_ulong_t)&model_table[2] }, // FPGA_XPD.hex
/* "Gadget Zero" firmware runs under Linux */
//{ USB_DEVICE(0x0525, 0xa4a0) },
{ } /* Terminating entry */
@@ -363,7 +419,7 @@ 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,
+ .owner = THIS_MODULE,
#endif
.name = "xpp_usb",
.probe = xusb_probe,
@@ -412,10 +468,12 @@ static struct usb_class_driver xusb_class = {
* 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(struct xpp_usb_bus *xusb, struct usb_interface *interface, struct xusb_model_info *model_info)
+static int set_endpoints(xusb_t *xusb, struct usb_interface *interface, struct xusb_model_info *model_info)
{
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
+ struct xusb_endpoint *xusb_ep;
+ int ep_addr;
int i;
iface_desc = &interface->altsetting[0];
@@ -425,37 +483,40 @@ static int set_endpoints(struct xpp_usb_bus *xusb, struct usb_interface *interfa
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
- int epnum = endpoint->bEndpointAddress;
+ ep_addr = endpoint->bEndpointAddress;
if(!BULK_ENDPOINT(endpoint)) {
DBG("endpoint 0x%x is not bulk: mbAttributes=0x%X\n",
- epnum, endpoint->bmAttributes);
+ ep_addr, endpoint->bmAttributes);
continue;
}
- if(epnum & USB_DIR_IN) { // Input
- if(epnum == model_info->in.epnum) {
+ if(usb_pipein(ep_addr)) { // Input
+ if(ep_addr == model_info->in.ep_addr) {
if(endpoint->wMaxPacketSize < sizeof(xpacket_raw_t)) {
- ERR("USB input endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", epnum, endpoint->wMaxPacketSize);
- break;
+ NOTICE("USB input endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", ep_addr, endpoint->wMaxPacketSize);
}
- xusb->ep_in.epnum = epnum;
- xusb->ep_in.max_size = endpoint->wMaxPacketSize;
+ 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(epnum == model_info->out.epnum) {
+ } else { // Output
+ if(ep_addr == model_info->out.ep_addr) {
if(endpoint->wMaxPacketSize < sizeof(xpacket_raw_t)) {
- ERR("USB output endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", epnum, endpoint->wMaxPacketSize);
- break;
+ NOTICE("USB output endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", ep_addr, endpoint->wMaxPacketSize);
}
- xusb->ep_out.epnum = epnum;
- xusb->ep_out.max_size = endpoint->wMaxPacketSize;
+ 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->ep_in.epnum || !xusb->ep_out.epnum) {
+ if (!xusb->endpoints[XUSB_RECV].ep_addr || !xusb->endpoints[XUSB_SEND].ep_addr) {
ERR("Couldn't find bulk-in or bulk-out endpoints\n");
return 0;
}
+ DBG("in=0x%02X out=0x%02X\n", xusb->endpoints[XUSB_RECV].ep_addr, xusb->endpoints[XUSB_SEND].ep_addr);
return 1;
}
@@ -468,10 +529,11 @@ static int set_endpoints(struct xpp_usb_bus *xusb, struct usb_interface *interfa
static int xusb_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(interface);
- struct xpp_usb_bus *xusb = NULL;
+ xusb_t *xusb = NULL;
struct xusb_model_info *model_info = (struct xusb_model_info*)id->driver_info;
- struct proc_dir_entry *procsummary;
- xbus_t *xbus;
+ struct proc_dir_entry *procsummary = NULL;
+ xbus_t *xbus = NULL;
+ struct xusb_endpoint *xusb_ep;
unsigned long flags;
int retval = -ENOMEM;
int i;
@@ -490,15 +552,16 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
}
/* allocate memory for our device state and initialize it */
- xusb = kmalloc(sizeof(struct xpp_usb_bus), GFP_KERNEL);
+ xusb = kmalloc(sizeof(xusb_t), GFP_KERNEL);
if (xusb == NULL) {
ERR("xpp_usb: Unable to allocate new xpp usb bus\n");
retval = -ENOMEM;
goto probe_failed;
}
- memset(xusb, 0, sizeof(struct xpp_usb_bus));
+ memset(xusb, 0, sizeof(xusb_t));
init_MUTEX (&xusb->sem);
+ atomic_set(&xusb->pending_writes, 0);
xusb->udev = udev;
xusb->interface = interface;
xusb->model_info = model_info;
@@ -507,12 +570,14 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
retval = -ENODEV;
goto probe_failed;
}
- xusb->read_urb = xpp_urb_new(xusb, xusb->ep_in.epnum, xusb->ep_in.max_size, xpp_receive_callback);
+ xusb_ep = &xusb->endpoints[XUSB_RECV];
+ xusb->read_urb = xpp_urb_new(xusb, XUSB_RECV, xusb_ep->max_size);
if (!xusb->read_urb) {
ERR("No free urbs available\n");
retval = -ENOMEM;
goto probe_failed;
}
+
/* allow device read, write and ioctl */
xusb->present = 1;
@@ -521,7 +586,7 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
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.");
+ ERR ("Not able to get a minor for this device.\n");
goto probe_failed;
}
@@ -531,33 +596,31 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
INFO ("USB XPP device now attached to minor %d\n", xusb->minor);
/* Allocate high level structures */
- xbus = xbus_new((model_info->bus_type == FIRMWARE_LOOPBACK) ? ~0 : 0);
+ xbus = xbus_new(&xusb_ops);
if(!xbus) {
retval = -ENOMEM;
goto probe_failed;
}
- xusb->xbus = xbus;
- xbus->priv = xusb;
xbus->bus_type = model_info->bus_type;
+ xbus->max_packet_size = min(xusb->endpoints[XUSB_SEND].max_size , xusb->endpoints[XUSB_RECV].max_size);
spin_lock_irqsave(&xusb_lock, flags);
for(i = 0; i < USBDEV_MAX; i++) {
if(xusb_array[i] == NULL)
break;
}
+ spin_unlock_irqrestore(&xusb_lock, flags);
if(i >= USBDEV_MAX) {
ERR("xpp_usb: Too many XPP USB buses\n");
retval = -ENOMEM;
goto probe_failed;
}
- spin_unlock_irqrestore(&xusb_lock, flags);
{
char path[XBUS_DESCLEN];
usb_make_path(udev, path, XBUS_DESCLEN); // May trunacte... ignore
snprintf(xbus->busdesc, XBUS_DESCLEN, "%s", path);
}
- xbus->ops = &xusb_ops;
DBG("GOT XPP USB BUS #%d: %s (type=%d)\n", i, xbus->busdesc, xbus->bus_type);
@@ -568,20 +631,22 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
DBG("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);
- //xbus->procsummary = 1; // temporary: not 0, for the condition below
if (!procsummary) {
ERR("Failed to create proc read entry for xbus %s\n", xbus->busname);
// FIXME: better error handling
retval = -EIO;
goto probe_failed;
}
+ procsummary->owner = THIS_MODULE;
#endif
+ bus_count++;
retval = usb_submit_urb(xusb->read_urb, GFP_ATOMIC);
if(retval < 0) {
ERR("%s: Failed to submit the receive URB errno=%d\n", __FUNCTION__, retval);
}
- bus_count++;
- xbus_activate(xusb->xbus);
+ xusb->xbus = xbus;
+ xbus->priv = xusb;
+ xbus_activate(xbus);
return retval;
probe_failed:
ERR("Failed to initialize xpp usb bus: %d\n", retval);
@@ -593,6 +658,13 @@ probe_failed:
usb_deregister_dev(interface, &xusb_class);
kfree(xusb);
}
+ if(xbus) {
+ if(procsummary) {
+ DBG("Remove proc_entry: " PROC_USBXPP_SUMMARY "\n");
+ remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir);
+ }
+ xbus_disconnect(xbus); // Blocking until fully deactivated!
+ }
return retval;
}
@@ -609,7 +681,7 @@ probe_failed:
*/
static void xusb_disconnect(struct usb_interface *interface)
{
- struct xpp_usb_bus *xusb;
+ xusb_t *xusb;
xbus_t *xbus;
int minor;
int i;
@@ -636,7 +708,7 @@ static void xusb_disconnect(struct usb_interface *interface)
}
#endif
xusb->present = 0;
- xbus_deactivate(xbus); // Blocking until fully deactivated!
+ xbus_disconnect(xbus); // Blocking until fully deactivated!
down (&xusb->sem);
@@ -645,6 +717,7 @@ static void xusb_disconnect(struct usb_interface *interface)
/* give back our minor */
usb_deregister_dev (interface, &xusb_class);
+ /* terminate an ongoing read */
/* terminate an ongoing write */
// FIXME: Does it really kill pending URB's?
@@ -657,59 +730,71 @@ static void xusb_disconnect(struct usb_interface *interface)
kfree(xusb);
up (&disconnect_sem);
- INFO("XUSB #%d now disconnected", minor);
+ INFO("XUSB #%d now disconnected\n", minor);
}
static void xpp_send_callback(struct urb *urb, struct pt_regs *regs)
{
- struct xpp_usb_bus *xusb = (struct xpp_usb_bus *)urb->context;
+ xusb_t *xusb = (xusb_t *)urb->context;
xbus_t *xbus = xusb->xbus;
BUG_ON(!xbus);
+ atomic_dec(&xusb->pending_writes);
/* 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)
- DBG("nonzero read bulk status received: %d", urb->status);
+ DBG("nonzero read bulk status received: %d\n", urb->status);
XUSB_COUNTER(xusb, TX_ERRORS)++;
}
+ xpp_urb_delete(urb);
if(!xusb->present) {
ERR("A packet from non-connected device?\n");
return;
}
- xpp_urb_delete(urb);
/* allow device read, write and ioctl */
XUSB_COUNTER(xusb, TX_PACKETS)++;
}
static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs)
{
- struct xpp_usb_bus *xusb = (struct xpp_usb_bus *)urb->context;
- xbus_t *xbus = xusb->xbus;
-
- xpacket_t *pack;
- size_t size;
- int retval;
+ xusb_t *xusb = (xusb_t *)urb->context;
+ xbus_t *xbus;
+ xpacket_t *pack;
+ size_t size;
+ int retval;
+ bool do_resubmit = 1;
+ bool is_inuse = 0;
- BUG_ON(!xbus);
+ BUG_ON(!xusb);
+ xbus = xusb->xbus;
+ if(!xbus) {
+ NOTICE("spurious URB\n");
+ return;
+ }
if (urb->status) {
- /* sync/async unlink faults aren't errors */
- if (!(urb->status == -EOVERFLOW || urb->status == -EMSGSIZE)) {
- ERR("Dropped connection due to bad URB status: %d\n", urb->status);
- return;
- } else {
- DBG("nonzero read bulk status received: %d\n", urb->status);
- goto end;
+ DBG("nonzero read bulk status received: %d\n", urb->status);
+ XUSB_COUNTER(xusb, RX_ERRORS)++;
+ /* Free old URB, allocate a fresh one */
+ if(xusb->read_urb)
+ xpp_urb_delete(xusb->read_urb);
+ xusb->read_urb = xpp_urb_new(xusb, XUSB_RECV, xusb->endpoints[XUSB_RECV].max_size);
+ if (!xusb->read_urb) {
+ ERR("URB allocation failed\n");
+ do_resubmit = 0;;
}
+ goto end;
}
if(!down_read_trylock(&xbus->in_use)) {
ERR("%s: xbus is going down\n", __FUNCTION__);
- return;
+ do_resubmit = 0;
+ goto end;
}
+ is_inuse = 1;
if(!xusb->present) {
ERR("A packet from non-connected device?\n");
- up_read(&xbus->in_use);
- return;
+ do_resubmit = 0;
+ goto end;
}
pack = xbus->ops->packet_new(xbus, GFP_ATOMIC);
if(!pack) {
@@ -723,42 +808,21 @@ static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs)
pack->datalen = size - sizeof(xpd_addr_t) - 1; // opcode size
// DBG("datalen of new packet: %d\n", pack->datalen);
- // Send UP
- if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_READ)) {
+ packet_debug("USB_PACKET_RECEIVE", xusb, pack);
+ XUSB_COUNTER(xusb, RX_PACKETS)++;
+ if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_READ))
XUSB_COUNTER(xusb, PCM_READS)++;
-
-#ifdef DEBUG_PCM_TIMING
- /*
- * DEBUG: high-res timing of PCM_READ to PCM_WRITE
- */
- stamp_last_pcm_read = get_cycles();
-#endif
- // fill_beep((u_char *)&PACKET_FIELD(pack, PCM_READS, pcm), 2); // Debugging BEEP
-#if 0
- static int rate_limit;
- if((rate_limit++ % 1000) == 0)
- dump_packet("USB RECEIVE PCM", pack, print_dbg);
-#endif
- } else if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) { // FIRMWARE_LOOPBACK
-#if 0
- static int rate_limit;
- if((rate_limit++ % 1000) == 0)
- dump_packet("USB RECEIVE (LOOPBACK) PCM", pack, print_dbg);
-#endif
- } else {
- char title[XBUS_DESCLEN];
-
- snprintf(title, XBUS_DESCLEN, "USB_PACKET_RECEIVE callback (%s)", xbus->busname);
- dump_packet(title, pack, print_dbg);
- }
+ // Send UP
packet_receive(xbus, pack);
- XUSB_COUNTER(xusb, RX_PACKETS)++;
end:
- up_read(&xbus->in_use);
- retval = usb_submit_urb(urb, GFP_KERNEL);
- if (retval < 0) {
- ERR("failed re-submitting read urb, error %d\n", retval);
- return;
+ if(is_inuse)
+ up_read(&xbus->in_use);
+ if(do_resubmit) {
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval < 0) {
+ ERR("failed re-submitting read urb, error %d\n", retval);
+ return;
+ }
}
}
@@ -768,14 +832,14 @@ end:
int __init xpp_usb_init(void)
{
int result;
- //struct xpp_usb_bus *xusb;
+ //xusb_t *xusb;
- INFO("%s revision %s\n", THIS_MODULE->name, revision);
+ INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION);
/* register this driver with the USB subsystem */
result = usb_register(&xusb_driver);
if (result) {
- ERR("usb_register failed. Error number %d", result);
+ ERR("usb_register failed. Error number %d\n", result);
return result;
}
return 0;
@@ -784,34 +848,7 @@ int __init xpp_usb_init(void)
void __exit xpp_usb_cleanup(void)
{
- int i, j;
-
DBG("\n");
- for(i = 0; i < USBDEV_MAX; i++) {
- xbus_t *xbus;
-
- if(xusb_array[i] == NULL)
- continue;
- xbus = xusb_array[i]->xbus;
- if(!xbus) {
- ERR("%s: missing xbus. Skipping\n", __FUNCTION__);
- continue;
- }
- for(j = 0; j < MAX_XPDS; j++) {
- xpd_t *xpd = xpd_of(xbus, j);
-
- if(xpd) {
- if(xpd->id != j) {
- ERR("%s: BUG: xpd->id=%d != j=%d\n", __FUNCTION__, xpd->id, j);
- continue;
- }
-#if 0 // FIXME: retest after new driver start working
- CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, 0xFF, 0); // Disable all hardware channels
- CALL_XMETHOD(LED, xbus, xpd, 0xFF, 1, 0); // FIXME: Show activated channels
-#endif
- }
- }
- }
/* deregister this driver with the USB subsystem */
usb_deregister(&xusb_driver);
}
@@ -822,31 +859,31 @@ void __exit xpp_usb_cleanup(void)
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 len = 0;
+ unsigned long flags;
+ int i;
//unsigned long stamp = jiffies;
- struct xpp_usb_bus *xusb = data;
+ xusb_t *xusb = data;
if(!xusb)
goto out;
// TODO: probably needs a per-xusb lock:
spin_lock_irqsave(&xusb_lock, flags);
- int i;
-
len += sprintf(page + len, "device: %d, #altsettings: %d, minor: %d\n"
- "\tBus Type:%d (Model Info: %s)\n"
- "\tIn: 0x%02X - Size: %d\n"
- "\tOut: 0x%02X - Size: %d\n",
+ "\tModel Info: Bus Type=%d (%s)\n"
+ "\tIn: 0x%02X - Size: %d)\n"
+ "\tOut: 0x%02X - Size: %d)\n",
xusb->udev->devnum,
xusb->interface->num_altsetting,
xusb->minor,
xusb->model_info->bus_type,
xusb->model_info->desc,
- xusb->ep_in.epnum,
- xusb->ep_in.max_size,
- xusb->ep_out.epnum,
- xusb->ep_out.max_size
+ 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));
#ifdef DEBUG_PCM_TIMING
len += sprintf(page + len, "\nstamp_last_pcm_read=%lld accumulate_diff=%lld\n", stamp_last_pcm_read, accumulate_diff);
#endif
@@ -878,7 +915,7 @@ out:
MODULE_DESCRIPTION("XPP USB Driver");
MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
MODULE_LICENSE("GPL");
-MODULE_VERSION("$Id$");
+MODULE_VERSION(ZAPTEL_VERSION);
module_init(xpp_usb_init);
module_exit(xpp_usb_cleanup);
diff --git a/xpp/xpp_zap.c b/xpp/xpp_zap.c
index 8e7937b..fc61af0 100644
--- a/xpp/xpp_zap.c
+++ b/xpp/xpp_zap.c
@@ -33,245 +33,66 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
+#include <linux/device.h>
#include <linux/init.h>
#include <linux/delay.h> /* for udelay */
#include <linux/workqueue.h>
#include <linux/proc_fs.h>
-#include <zaptel.h>
+
+#include "zaptel.h"
+
+#include <version.h> /* For zaptel version */
+#include "xbus-core.h"
#include "xproto.h"
#include "xpp_zap.h"
-static char revision[] = "$Revision$";
+static const char rcsid[] = "$Id$";
#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *xpp_procdir = NULL;
+struct proc_dir_entry *xpp_proc_toplevel = NULL;
#define PROC_DIR "xpp"
-#define PROC_XBUSES "xbuses"
#define PROC_SYNC "sync"
-#define PROC_XBUS_SUMMARY "summary"
#define PROC_XPD_ZTREGISTER "zt_registration"
#define PROC_XPD_SUMMARY "summary"
#endif
-#undef WITH_RBS
-//#define WITH_RBS
-
#define XPP_CTL_MAJOR 42
-#define MAX_BUSES 16
#define MAX_QUEUE_LEN 10000
-#define LED_BLINK_PERIOD (HZ/8)
#define SAMPLE_TICKS 10000
+#define DELAY_UNTIL_DIALTONE 3000
-static spinlock_t xbuses_lock = SPIN_LOCK_UNLOCKED;
-static xbus_t *xbuses_array[MAX_BUSES] = {};
-static int bus_count = 0;
static struct timer_list xpp_timer;
-xpd_t *sync_master = NULL; // Start with host based sync
+static xpd_t *sync_master = NULL; // Start with host based sync
static unsigned int xpp_timer_count = 0;
static unsigned int xpp_last_jiffies = 0;
-struct workqueue_struct *xpp_worker = NULL;
-
-static LIST_HEAD(xpd_list);
DEF_PARM(int, print_dbg, 0, "Print DBG statements");
DEF_PARM(int, max_queue_len, MAX_QUEUE_LEN, "Maximum Queue Length.");
-DEF_PARM(int, xbus_err_disable_bus, 1000, "Number of errors needed to disable bus");
-DEF_PARM(int, ignore_xpds, 0, "a bitmask of xpd numbers to ignore");
-#ifdef SOFT_SIMULATOR
-DEF_PARM(ulong, softloop_xpds, 0, "a bitmask of software xpd numbers");
-#endif
-DEF_PARM(ulong, pcm_gen, 0, "a bitmask of line numbers for hardware tone generator");
-
-DEF_ARRAY(ulong, enabled_channels, MAX_XPDS, ~0, "Enabled channels for each xpd");
+DEF_PARM(bool, have_sync_bus, 0, "True if all Astribank(TM) devices are connected via a sync-cable");
+DEF_PARM(bool, zap_autoreg, 1, "Register spans automatically (1) or not (0)");
#include "zap_debug.h"
+#ifdef XPP_EC_CHUNK
+#include "echo_supress/ec_xpp.h"
+#endif
-static int xpd_zaptel_register(xpd_t *xpd);
-static int xpd_zaptel_unregister(xpd_t *xpd);
-static void xbus_remove(xbus_t *xbus);
-static void xpd_blink_leds(xpd_t *xpd);
+static int zaptel_register_xpd(xpd_t *xpd);
+static int zaptel_unregister_xpd(xpd_t *xpd);
static void xpp_ring_generate(xpd_t *xpd);
static void xpp_transmitprep(xpd_t *xpd);
static void xpp_receiveprep(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);
-xbus_t *xbus_of(int xbus_num);
-static void xpd_cleanup(xpd_t *xpd);
-static void xpd_card_disable(xpd_t *xpd);
-static void update_xpd_status(xpd_t *xpd, int alarm_flag);
-
-#define SPAN_REGISTERED(xpd) ((xpd)->span.flags & ZT_FLAG_REGISTERED)
-
-/*------------------------- Packet Handling ------------------------*/
-static kmem_cache_t *packet_cache = NULL;
-static atomic_t xpacket_count = ATOMIC_INIT(0);
-
-void card_detected(void *data)
-{
- struct card_desc_struct *card_desc = (struct card_desc_struct *)data;
- xbus_t *xbus;
- xpd_t *xpd;
- int xpd_num;
- byte type;
- 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;
- xpd_num = card_desc->xpd_num;
- type = card_desc->type;
- rev = card_desc->rev;
- BUG_ON(!xbus);
- DBG("%s: xpd_num=%d type=%d rev=%d\n", xbus->busname, xpd_num, type, rev);
- xpd = xpd_of(xbus, xpd_num);
- if(xpd) {
- if(type == XPD_TYPE(NOMODULE)) {
- NOTICE("%s: xpd #%d: removed\n", __FUNCTION__, xpd_num);
- xpd_card_disable(xpd);
- goto out;
- }
- NOTICE("%s: xpd #%d: already exists\n", __FUNCTION__, xpd_num);
- goto out;
- }
- if(type == XPD_TYPE(NOMODULE)) {
- DBG("No module at address=%d\n", xpd_num);
- goto out;
- }
- proto_table = get_xproto_table(type);
- if(!proto_table) {
- NOTICE("%s: xpd #%d: missing protocol table for type=%d. Ignored.\n", __FUNCTION__, xpd_num, type);
- goto out;
- }
- xops = &proto_table->xops;
- BUG_ON(!xops);
- xpd = xops->card_new(xbus, xpd_num, proto_table, rev);
- if(!xpd) {
- NOTICE("card_new(%s,%d,%d,%d) failed. Ignored.\n", xbus->busname, xpd_num, proto_table->type, rev);
- goto out;
- }
-#if 0
- /*
- * Is it nessessary?
- */
- if(xpd->type == XPD_TYPE_FXO) {
- int i;
-
- for(i = 0; i < xpd->channels; i++) {
- zt_hooksig(&xpd->chans[i], ZT_RXSIG_ONHOOK);
- }
- }
-#endif
-#ifdef CONFIG_PROC_FS
- DBG("Creating xpd proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
- xpd->proc_xpd_dir = proc_mkdir(xpd->xpdname, xbus->proc_xbus_dir);
- if(!xpd->proc_xpd_dir) {
- ERR("Failed to create proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
- 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) {
- ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_SUMMARY, xbus->busname, xpd->xpdname);
- goto err;
- }
- xpd->proc_xpd_ztregister = create_proc_entry(PROC_XPD_ZTREGISTER, 0644, xpd->proc_xpd_dir);
- if (!xpd->proc_xpd_ztregister) {
- ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_ZTREGISTER, xbus->busname, xpd->xpdname);
- goto err;
- }
- 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;
-#endif
- list_add(&xpd->xpd_list, &xpd_list);
- xbus->xpds[xpd->id] = xpd;
- xbus->num_xpds++;
- CALL_XMETHOD(card_init, xbus, xpd);
- // Turn off all channels
- CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, 0xFF, 0);
-// CALL_XMETHOD(LED, xbus, xpd, 0xFF, LED_RED, 0); // FIXME: Show activated channels
- // Turn on enabled channels
- CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, xpd->enabled_chans, 1);
- atomic_set(&xpd->card_present, 1);
- xpd_zaptel_register(xpd);
-#if 0
- // FIXME: not yet initialized...
- xpp_check_hookstate(xpd, line_status);
-#endif
-
-out:
- memset(card_desc, 0, sizeof(struct card_desc_struct));
- kfree(card_desc);
- return;
-err:
- xpd_cleanup(xpd);
- goto out;
-}
-
-/**
- * Allocates a new XPP packet.
- * @xbus The XPP bus in which the packet will flow (for counters
- * maintenance)
- * @flags Flags for kernel memory allocation.
- * @returns A pointer to the new packet, or NULL in case of failure.
- *
- *
- * Packet allocation/deallocation:
- * Sent packets:
- * - Allocated by protocol commands
- * - Deallocated by xmus_xmitter
- * Receive packets:
- * - Allocated/deallocated by xbus_xmiter
- */
-xpacket_t *softloop_packet_new(xbus_t *xbus, int flags)
-{
- xpacket_t *pack;
-
- /* To avoid races we increament counter in advance and decrement it later
- * in case of failure */
- atomic_inc(&xbus->packet_counter);
- //DBG("Incremented packet_counter of bus %s (new packet) to %d\n",
- // xbus->busname, atomic_read(&xbus->packet_counter));
- pack = kmem_cache_alloc(packet_cache, flags);
- if (pack) {
- memset(pack, 0, sizeof(xpacket_t));
- atomic_inc(&xpacket_count);
- } else {
- atomic_dec(&xbus->packet_counter);
- //DBG("Decremented packet_counter of bus %s (failed new packet) to %d\n",
- // xbus->busname, atomic_read(&xbus->packet_counter));
- }
- return pack;
-}
-
-void softloop_packet_free(xbus_t *xbus, xpacket_t *p)
-{
- kmem_cache_free(packet_cache, p);
- atomic_dec(&xpacket_count);
- atomic_dec(&xbus->packet_counter);
- //DBG("Decremented packet_counter of bus %s (freed packet) to %d\n",
- // xbus->busname, atomic_read(&xbus->packet_counter));
-}
-
-int call_proto(xbus_t *xbus, xpacket_t *pack)
-{
- const xproto_entry_t *xe;
- int toxpd = XPD_NUM(pack->content.addr);
- xpd_t *xpd = xpd_of(xbus, toxpd);
-
- xe = find_xproto_entry(xpd, pack->content.opcode);
- return 0;
-}
+static void xpd_free(xpd_t *xpd);
static void external_sync(xpd_t *the_xpd)
{
int i, j;
- DBG("SYNC %s\n", (the_xpd) ? "EXTERNAL" : "HOST");
+ DBG("SYNC %s (%s sync cable)\n", (the_xpd)?"Astribanks":"HOST", (have_sync_bus)?"with":"without");
+ // Shut all down
for(i = 0; i < MAX_BUSES; i++) {
xbus_t *xbus = xbus_of(i);
if(!xbus)
@@ -279,21 +100,26 @@ static void external_sync(xpd_t *the_xpd)
if (!xbus->hardware_exists)
continue;
for(j = 0; j < MAX_XPDS; j++) {
- xpd_t *xpd = xbus->xpds[j];
- if(xpd)
- CALL_XMETHOD(SYNC_SOURCE, xbus, xpd, 1, (the_xpd != NULL));
+ xpd_t *xpd = xpd_of(xbus, j);
+ if(xpd) {
+ CALL_XMETHOD(SYNC_SOURCE, xbus, xpd, 1, 0);
+ }
}
}
+ if(the_xpd)
+ CALL_XMETHOD(SYNC_SOURCE, the_xpd->xbus, the_xpd, 1, 1);
}
-void set_sync_master(xpd_t *xpd)
+void sync_master_is(xpd_t *xpd)
{
- DBG("SYNC: %s => %s\n",
+ DBG("SYNC MASTER CHANGED: %s => %s\n",
(sync_master) ? sync_master->xpdname : "HOST",
- (xpd) ? xpd->xpdname : "HOST"
- );
+ (xpd) ? xpd->xpdname : "HOST");
sync_master = xpd;
- if(!sync_master) {
+ if(xpd) { // XPD
+ del_timer_sync(&xpp_timer);
+ xpp_tick((unsigned long)xpd);
+ } else { // HOST
external_sync(NULL);
if(!timer_pending(&xpp_timer)) {
xpp_timer.function = xpp_tick;
@@ -301,10 +127,6 @@ void set_sync_master(xpd_t *xpd)
xpp_timer.expires = jiffies + 1; /* Must be 1KHz rate */
add_timer(&xpp_timer);
}
- } else {
- del_timer_sync(&xpp_timer);
- external_sync(xpd);
- xpp_tick((unsigned long)xpd);
}
}
@@ -337,43 +159,49 @@ void xpp_tick(unsigned long param)
continue;
if (!xbus->hardware_exists)
continue;
+ if(!down_read_trylock(&xbus->in_use)) {
+ DBG("Dropped packet. %s is in_use\n", xbus->busname);
+ continue;
+ }
#if 0
if(xbus->open_counter == 0)
continue; // optimize, but zttool loopback won't function
#endif
for(j = 0; j < MAX_XPDS; j++) {
- xpd_t *xpd = xbus->xpds[j];
+ xpd_t *xpd = xpd_of(xbus, j);
if(!xpd)
continue;
- if(!atomic_read(&xpd->card_present))
+ if(!xpd->card_present)
continue;
xpd->timer_count++;
CALL_XMETHOD(card_tick, xbus, xpd);
if(!SPAN_REGISTERED(xpd))
continue;
- xpd_blink_leds(xpd);
if(xpd->direction == TO_PSTN)
xpp_ring_generate(xpd);
xpp_transmitprep(xpd);
xpp_receiveprep(xpd);
}
+ up_read(&xbus->in_use);
}
}
#if HZ != 1000
-#warning This module will not be usable since the kernel HZ setting is not 1000 ticks per second.
+#warning "xpp_timer must be sampled EXACTLY 1000/per second"
#endif
-static void xpd_cleanup(xpd_t *xpd)
+static void xpd_free(xpd_t *xpd)
{
xbus_t *xbus = NULL;
if(!xpd)
return;
xbus = xpd->xbus;
- xpd_card_disable(xpd);
+ if(!xbus)
+ return;
DBG("%s/%s\n", xbus->busname, xpd->xpdname);
+ xbus_unregister_xpd(xbus, xpd);
#ifdef CONFIG_PROC_FS
if(xpd->proc_xpd_dir) {
if(xpd->proc_xpd_summary) {
@@ -391,109 +219,149 @@ static void xpd_cleanup(xpd_t *xpd)
xpd->proc_xpd_dir = NULL;
}
#endif
+ if(xpd->writechunk)
+ kfree((void *)xpd->writechunk);
+ xpd->writechunk = NULL;
+ if(xpd->xproto)
+ xproto_put(xpd->xproto);
+ xpd->xproto = NULL;
+ kfree(xpd);
}
-void init_xbus_packet_queue(packet_queue_t *q, const char name[])
-{
- INIT_LIST_HEAD(&q->head);
- spin_lock_init(&q->lock);
- q->count = 0;
- q->worst_count = 0;
- q->overflows = 0;
- snprintf(q->qname, XPD_NAMELEN, "%s", name);
-}
-#if 0
-/*
- * Assume the queue is locked
- */
-void __dump_packet_queue(const char *msg, packet_queue_t *q)
-{
- xpacket_t *tmp;
+/*------------------------- XPD Management -------------------------*/
- list_for_each_entry(tmp, &q->head, list) {
- dump_packet(msg, tmp);
- }
-}
-#endif
+#define REV(x,y) (10 * (x) + (y))
+static byte good_revs[] = {
+ REV(1,9),
+ REV(2,0),
+};
+#undef REV
-void drain_xbus_packet_queue(xbus_t *xbus, packet_queue_t *q)
+static bool good_rev(byte rev)
{
- unsigned long flags;
- xpacket_t *pack;
- xpacket_t *next;
-
- spin_lock_irqsave(&q->lock, flags);
- DBG("queue=%s count=%d\n", q->qname, q->count);
- DBG(" total packets count=%d\n", atomic_read(&xpacket_count));
- list_for_each_entry_safe(pack, next, &q->head, list) {
- list_del(&pack->list);
- q->count--;
- xbus->ops->packet_free(xbus, pack);
- }
- if(q->count != 0)
- ERR("drain_xbus_packet_queue: queue %s still has %d packets\n",
- q->qname, q->count);
- spin_unlock_irqrestore(&q->lock, flags);
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(good_revs); i++) {
+ if(good_revs[i] == rev)
+ return 1;
+ }
+ return 0;
}
-void xbus_enqueue_packet(xbus_t *xbus, packet_queue_t *q, xpacket_t *pack)
+/*
+ * Synchronous part of XPD detection.
+ * Called from xbus_poll()
+ */
+void card_detected(struct card_desc_struct *card_desc)
{
- unsigned long flags;
-
- spin_lock_irqsave(&q->lock, flags);
+ xbus_t *xbus;
+ xpd_t *xpd = NULL;
+ int xpd_num;
+ byte type;
+ byte rev;
+ const xops_t *xops;
+ const xproto_table_t *proto_table;
- if(q->count >= max_queue_len) {
- static unsigned long last_notice = 0; // rate limit
- if((jiffies - last_notice) < HZ) {
- NOTICE("xbus_enqueue_packet: dropping packet (queue len = %d, max=%d)\n",
- q->count, max_queue_len);
- last_notice = jiffies;
+ BUG_ON(!card_desc);
+ BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
+ xbus = card_desc->xbus;
+ xpd_num = xpd_addr2num(&card_desc->xpd_addr);
+ type = card_desc->type;
+ rev = card_desc->rev;
+ BUG_ON(!xbus);
+ if(!good_rev(rev)) {
+ NOTICE("%s: New XPD #%d (%d-%d) type=%d has bad firmware revision %d.%d\n", xbus->busname,
+ xpd_num, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit,
+ type, rev / 10, rev % 10);
+ goto err;
+ }
+ INFO("%s: New XPD #%d (%d-%d) type=%d Revision %d.%d\n", xbus->busname,
+ xpd_num, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit,
+ type, rev / 10, rev % 10);
+ xpd = xpd_of(xbus, xpd_num);
+ if(xpd) {
+ if(type == XPD_TYPE_NOMODULE) {
+ NOTICE("%s: xpd #%d: removed\n", __FUNCTION__, xpd_num);
+ BUG();
+ goto out;
}
- q->overflows++;
- xbus->ops->packet_free(xbus, pack);
+ NOTICE("%s: xpd #%d: already exists\n", __FUNCTION__, xpd_num);
goto out;
}
- list_add_tail(&pack->list, &q->head);
- q->count++;
-
- if(q->count > q->worst_count)
- q->worst_count = q->count;
-
- if(q->count < max_queue_len/100 && q->worst_count > q->count) // Decay worst_count
- q->worst_count--;
-
- // dump_packet("ENQUEUED", pack, print_dbg);
-out:
- spin_unlock_irqrestore(&q->lock, flags);
-}
-
-xpacket_t *xbus_dequeue_packet(packet_queue_t *q)
-{
- unsigned long flags;
- struct list_head *p;
- xpacket_t *pack = NULL;
+ if(type == XPD_TYPE_NOMODULE) {
+ DBG("No module at address=%d\n", xpd_num);
+ goto out;
+ }
+ proto_table = xproto_get(type);
+ if(!proto_table) {
+ NOTICE("%s: xpd #%d: missing protocol table for type=%d. Ignored.\n", __FUNCTION__, xpd_num, type);
+ goto out;
+ }
+ xops = &proto_table->xops;
+ BUG_ON(!xops);
+ xpd = xops->card_new(xbus, xpd_num, proto_table, rev);
+ if(!xpd) {
+ NOTICE("card_new(%s,%d,%d,%d) failed. Ignored.\n", xbus->busname, xpd_num, proto_table->type, rev);
+ goto err;
+ }
+ xpd->addr = card_desc->xpd_addr;
- spin_lock_irqsave(&q->lock, flags);
+ /* For USB-1 disable some channels */
+ if(xbus->max_packet_size < RPACKET_SIZE(GLOBAL, PCM_WRITE)) {
+ xpp_line_t no_pcm;
- if(list_empty(&q->head)) {
- // DBG("LIST EMPTY (count=%d)\n", q->count);
- goto out;
+ no_pcm = 0x7F | xpd->digital_outputs | xpd->digital_inputs;
+ xpd->no_pcm = no_pcm;
+ NOTICE("%s: max packet size = %d, disabling some PCM channels. no_pcm=0x%04X\n",
+ xbus->busname, xbus->max_packet_size, xpd->no_pcm);
+ }
+#ifdef CONFIG_PROC_FS
+ DBG("Creating xpd proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
+ xpd->proc_xpd_dir = proc_mkdir(xpd->xpdname, xbus->proc_xbus_dir);
+ if(!xpd->proc_xpd_dir) {
+ ERR("Failed to create proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
+ goto err;
}
- p = q->head.next;
- list_del(p);
- q->count--;
- pack = list_entry(p, xpacket_t, list);
- // dump_packet("DEQUEUED", pack, print_dbg);
+ 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) {
+ ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_SUMMARY, xbus->busname, xpd->xpdname);
+ 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) {
+ ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_ZTREGISTER, xbus->busname, xpd->xpdname);
+ 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;
+#endif
+ xbus_register_xpd(xbus, xpd);
+ if(CALL_XMETHOD(card_init, xbus, xpd) < 0)
+ goto err;
+ // Turn off all channels
+ CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, ~0, 0);
+ xpd->card_present = 1;
+ // Turn on all channels
+ CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, ALL_LINES, 1);
+
+ if(zap_autoreg)
+ zaptel_register_xpd(xpd);
out:
- spin_unlock_irqrestore(&q->lock, flags);
- return pack;
+ memset(card_desc, 0, sizeof(struct card_desc_struct));
+ kfree(card_desc);
+ return;
+err:
+ xpd_free(xpd);
+ goto out;
}
-/*------------------------- XPD Management -------------------------*/
-
#ifdef CONFIG_PROC_FS
/**
@@ -510,83 +378,78 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
int len = 0;
xpd_t *xpd = data;
xbus_t *xbus;
-#if SOFT_SIMULATOR
- struct xpd_sim *sim;
-#endif
- int channels;
int i;
if(!xpd)
goto out;
xbus = xpd->xbus;
-#if SOFT_SIMULATOR
- sim = &xbus->sim[xpd->id];
-#endif
- channels = xpd->channels;
- len += sprintf(page + len, "%s (%s ,card %s, span_registered=%s)%s\n"
+ len += sprintf(page + len, "%s (%s ,card %s, span %s) %s\n"
"timer_count: %d span->mainttimer=%d\n"
,
xpd->xpdname, xproto_name(xpd->type),
- (atomic_read(&xpd->card_present))?"present":"missing",
- (SPAN_REGISTERED(xpd))?"yes":"no",
- (xpd == sync_master) ? " SYNCER" : "",
+ (xpd->card_present) ? "present" : "missing",
+ (SPAN_REGISTERED(xpd)) ? "registered" : "NOT registered",
+ (xpd == sync_master) ? "SYNC MASTER" : "SYNC SLAVE",
xpd->timer_count, xpd->span.mainttimer
);
len += sprintf(page + len, "STATES:");
- len += sprintf(page + len, "\n\t%-17s: ", "enabled");
- for(i = 0; i < channels; i++) {
- len += sprintf(page + len, "%d ", IS_SET(xpd->enabled_chans, i));
- }
len += sprintf(page + len, "\n\t%-17s: ", "output_relays");
- for(i = 0; i < channels; i++) {
+ 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(i = 0; i < channels; i++) {
+ for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(xpd->digital_inputs, i));
}
len += sprintf(page + len, "\n\t%-17s: ", "hookstate");
- for(i = 0; i < channels; i++) {
+ for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(xpd->hookstate, i));
}
- len += sprintf(page + len, "\n\t%-17s: ", "ring-state");
- for(i = 0; i < channels; i++) {
- len += sprintf(page + len, "%d ", xpd->lasttxhook[i]);
- }
len += sprintf(page + len, "\n\t%-17s: ", "ringing");
- for(i = 0; i < channels; i++) {
+ for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", xpd->ringing[i]);
}
#if 1
if(SPAN_REGISTERED(xpd)) {
- len += sprintf(page + len, "\nreadchunk: ");
- for(i = 0; i < channels; i++) {
+ len += sprintf(page + len, "\nPCM:\n | [readchunk] | [writechunk] | delay");
+ for_each_line(xpd, i) {
struct zt_chan *chans = xpd->span.chans;
- byte chunk[ZT_CHUNKSIZE];
+ byte rchunk[ZT_CHUNKSIZE];
+ byte wchunk[ZT_CHUNKSIZE];
+ byte *rp;
+ byte *wp;
int j;
- memcpy(chunk, chans[i].readchunk, ZT_CHUNKSIZE);
- len += sprintf(page + len, "\n\tport %2d> ", i);
+ if(IS_SET(xpd->digital_outputs, i))
+ continue;
+ if(IS_SET(xpd->digital_inputs, i))
+ continue;
+#if 1
+ rp = chans[i].readchunk;
+ wp = chans[i].writechunk;
+#else
+ rp = (byte *)xpd->readchunk + (ZT_CHUNKSIZE * i);
+ wp = chans[i].writechunk;
+#endif
+ 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 ", chunk[j]);
+ len += sprintf(page + len, "%02X ", rchunk[j]);
}
- }
- }
-#endif
-#if SOFT_SIMULATOR
- if(sim->simulated) {
- len += sprintf(page + len, "\nSIMULATED (xpd_type=%d, loopto=%d):", sim->xpd_type, sim->loopto);
- len += sprintf(page + len, "\n\t%-17s: ", "hookstate");
- for(i = 0; i < channels; i++) {
- len += sprintf(page + len, "%d ", IS_SET(sim->hookstate, i));
+ len += sprintf(page + len, " | ");
+ for(j = 0; j < ZT_CHUNKSIZE; j++) {
+ len += sprintf(page + len, "%02X ", wchunk[j]);
+ }
+ len += sprintf(page + len, " | %d ", xpd->delay_until_dialtone[i]);
}
}
#endif
#if 0
if(SPAN_REGISTERED(xpd)) {
len += sprintf(page + len, "\nSignalling:\n");
- for(i = 0; i < channels; i++) {
+ 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);
}
@@ -620,10 +483,11 @@ out:
xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, int channels, byte revision)
{
xpd_t *xpd = NULL;
+ size_t pcm_size;
size_t alloc_size = sizeof(xpd_t) + privsize;
+ int i;
- INFO("New XPD #%d (Revision %d.%d) detected on xbus %s\n",
- xpd_num, revision / 10, revision % 10, xbus->busname);
+ DBG("%s: xpd #%d\n", xbus->busname, xpd_num);
if(!VALID_XPD_NUM(xpd_num)) {
ERR("%s: illegal xpd id = %d\n", __FUNCTION__, xpd_num);
goto err;
@@ -645,14 +509,19 @@ xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_
xpd->id = xpd_num;
xpd->channels = channels;
xpd->chans = NULL;
- atomic_set(&xpd->card_present, 0);
+ xpd->card_present = 0;
snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%d", xpd_num);
xpd->hookstate = 0x0; /* ONHOOK */
xpd->type = proto_table->type;
+ xpd->xproto = proto_table;
xpd->xops = &proto_table->xops;
- xpd->enabled_chans = enabled_channels[xpd_num];
xpd->digital_outputs = 0;
xpd->digital_inputs = 0;
+
+ for_each_line(xpd, i) {
+ xpd->idletxhookstate[i] = FXS_LINE_ENABLED; /* By default, don't send on hook */
+ }
+
atomic_set(&xpd->open_counter, 0);
xpd->chans = kmalloc(sizeof(struct zt_chan)*xpd->channels, GFP_KERNEL);
@@ -660,33 +529,61 @@ xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_
ERR("%s: Unable to allocate channels\n", __FUNCTION__);
goto err;
}
- /* 8 channels, double buffer, Read/Write */
- int need = ZT_MAX_CHUNKSIZE * CHANNELS_PERXPD * 2 * 2;
- if((xpd->writechunk = kmalloc(need, GFP_KERNEL)) == NULL) {
+ pcm_size = ZT_MAX_CHUNKSIZE * CHANNELS_PERXPD * 2; /* Double Buffer */
+ alloc_size = pcm_size * 2; /* Read/Write */
+ if((xpd->writechunk = kmalloc(alloc_size, GFP_KERNEL)) == NULL) {
ERR("%s: Unable to allocate memory for writechunks\n", __FUNCTION__);
goto err;
}
/* Initialize Write/Buffers to all blank data */
- memset((void *)xpd->writechunk, 0x00, need);
- xpd->readchunk = xpd->writechunk + ZT_CHUNKSIZE * CHANNELS_PERXPD * 2;
+ memset((void *)xpd->writechunk, 0x00, alloc_size);
+ xpd->readchunk = xpd->writechunk + pcm_size;
return xpd;
err:
- if(xpd->chans)
- kfree((void *)xpd->chans);
- if(xpd->writechunk)
- kfree((void *)xpd->writechunk);
- if(xpd)
+ if(xpd) {
+ if(xpd->chans)
+ kfree((void *)xpd->chans);
+ if(xpd->writechunk)
+ kfree((void *)xpd->writechunk);
kfree(xpd);
+ }
return NULL;
}
-static void xpd_card_disable(xpd_t *xpd)
+/* 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);
- atomic_set(&xpd->card_present, 0);
- if(SPAN_REGISTERED(xpd))
+
+ // TODO: elect a new sync master
+ if(sync_master == xpd)
+ sync_master_is(NULL);
+
+ spin_lock_irqsave(&xpd->lock, flags);
+ DBG("%s/%s (%p)\n", xpd->xbus->busname, xpd->xpdname, 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? */
+ DBG("Queuing ZT_EVENT_REMOVED on all channels to ask user to release them\n");
+ for (i=0; i<xpd->span.channels; i++)
+ zt_qevent_lock(&xpd->chans[i],ZT_EVENT_REMOVED);
+ }
+out:
+ spin_unlock_irqrestore(&xpd->lock, flags);
}
void xpd_remove(xpd_t *xpd)
@@ -695,23 +592,14 @@ void xpd_remove(xpd_t *xpd)
BUG_ON(!xpd);
xbus = xpd->xbus;
- INFO("Remove XPD #%d from xbus=%s\n", xpd->id, xbus->busname);
-#if 0
- // TODO: elect a new sync master
- if(sync_master == xpd)
- set_sync_master(NULL);
-#endif
- xpd_zaptel_unregister(xpd);
- xbus->xpds[xpd->id] = NULL;
- list_del(&xpd->xpd_list);
- xbus->num_xpds--;
+ INFO("%s: Remove XPD #%d from\n", xbus->busname, xpd->id);
+
+ zaptel_unregister_xpd(xpd);
CALL_XMETHOD(card_remove, xbus, xpd);
- xpd_cleanup(xpd);
- kfree((void *)xpd->writechunk);
- kfree(xpd);
+ xpd_free(xpd);
}
-static void update_xpd_status(xpd_t *xpd, int alarm_flag)
+void update_xpd_status(xpd_t *xpd, int alarm_flag)
{
struct zt_span *span = &xpd->span;
@@ -734,78 +622,16 @@ static void update_xpd_status(xpd_t *xpd, int alarm_flag)
DBG("Update XPD alarms: %s -> %02X\n", xpd->span.name, alarm_flag);
}
-void phone_hook(xpd_t *xpd, int channo, bool offhook)
+void update_line_status(xpd_t *xpd, int pos, bool good)
{
- struct zt_chan *chan = &xpd->span.chans[channo];
+ struct zt_chan *chan;
- if(offhook && !IS_SET(xpd->hookstate, channo)) { // OFFHOOK
- DBG("OFFHOOK: channo=%d\n", chan->channo);
- xpd->ringing[channo] = 0;
- BIT_SET(xpd->hookstate, channo);
+ BUG_ON(!xpd);
+ chan = &xpd->chans[pos];
+ if(good)
zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
- if(!IS_SET(xpd->digital_outputs, channo) && !IS_SET(xpd->digital_inputs, channo)) {
- CALL_XMETHOD(CHAN_POWER, xpd->xbus, xpd, BIT(channo), 0); // Power down (prevent overheating!!!)
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(channo), LED_GREEN, 1);
- }
- } else if(!offhook && IS_SET(xpd->hookstate, channo)) { // ONHOOK
- DBG("ONHOOK channo=%d\n", chan->channo);
- xpd->ringing[channo] = 0;
- BIT_CLR(xpd->hookstate, channo);
+ else
zt_hooksig(chan, ZT_RXSIG_ONHOOK);
- if(!IS_SET(xpd->digital_outputs, channo) && !IS_SET(xpd->digital_inputs, channo)) {
- CALL_XMETHOD(CHAN_POWER, xpd->xbus, xpd, BIT(channo), 0); // Power down (prevent overheating!!!)
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(channo), LED_GREEN, 0);
- }
- }
-}
-
-void xpp_check_hookstate(xpd_t *xpd, xpp_line_t fxs_off_hook)
-{
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&xpd->lock, flags);
- if(xpd->direction != TO_PHONE) {
- ERR("%s: %s: Only PHONE can report hookstate changes\n", __FUNCTION__, xpd->xpdname);
- goto out;
- }
- if(!SPAN_REGISTERED(xpd)) {
- NOTICE("%s: %s is not registered. Skipping.\n", __FUNCTION__, xpd->xpdname);
- goto out;
- }
- DBG("%s: hookstate=0x%04X fxs_off_hook=0x%04X\n", xpd->xpdname, xpd->hookstate, fxs_off_hook);
- for(i = 0; i < xpd->channels; i++) {
- phone_hook(xpd, i, IS_SET(fxs_off_hook, i));
- }
-out:
- spin_unlock_irqrestore(&xpd->lock, flags);
-}
-
-static void xpd_blink_leds(xpd_t *xpd)
-{
- int i;
- unsigned long flags;
-
- BUG_ON(!xpd);
-
- spin_lock_irqsave(&xpd->lock, flags);
- for(i = 0; i < xpd->channels; i++) {
- if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
- continue;
- if(xpd->ringing[i]) {
- // led state is toggled
- if((xpd->timer_count % LED_BLINK_PERIOD) == 0) {
- DBG("%s pos=%d ringing=%d led_on=%d\n", xpd->xpdname, i, xpd->ringing[i], xpd->led_on[i]);
- if(xpd->ringing[i] && xpd->led_on[i]) {
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 1);
- } else {
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
- }
- xpd->led_on[i] = !xpd->led_on[i];
- }
- }
- }
- spin_unlock_irqrestore(&xpd->lock, flags);
}
static void xpp_ring_generate(xpd_t *xpd)
@@ -829,7 +655,7 @@ static void xpp_ring_generate(xpd_t *xpd)
* Ring detect logic:
* fxo_power is toggled
*/
- for(i = 0; i < xpd->channels; i++) {
+ for_each_line(xpd, i) {
if(xpd->ringing[i] || xpd->ringer_on[i]) {
// ring state is only changed once per second:
if((xpd->timer_count % 1000) == 0) {
@@ -839,10 +665,7 @@ static void xpp_ring_generate(xpd_t *xpd)
} else {
zt_hooksig(&xpd->chans[i], ZT_RXSIG_RING);
}
- xpd->ringing[i]--;
xpd->ringer_on[i] = !xpd->ringer_on[i];
- if (xpd->ringing[i] < 0)
- xpd->ringing[i]=0;
}
}
}
@@ -850,98 +673,13 @@ out:
spin_unlock_irqrestore(&xpd->lock, flags);
}
-/*------------------------- Bus Management -------------------------*/
-
-xbus_t *xbus_of(int xbus_num)
-{
- if(xbus_num < 0 || xbus_num >= MAX_BUSES)
- return NULL;
- return xbuses_array[xbus_num];
-}
-
-xpd_t *xpd_of(xbus_t *xbus, int xpd_num)
-{
- if(!VALID_XPD_NUM(xpd_num))
- return NULL;
- return xbus->xpds[xpd_num];
-}
-
-void xbus_reset_counters(xbus_t *xbus)
-{
- int i;
-
- DBG("Reseting counters of %s\n", xbus->busname);
- for(i = 0; i < XBUS_COUNTER_MAX; i++) {
- xbus->counters[i] = 0;
- }
-// xbus->xmit_queue.worst_count = 0;
-// xbus->xmit_queue.overflows = 0;
-}
-
#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 xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = 0;
- unsigned long flags;
- xbus_t *xbus = data;
- int i;
-
- if(!xbus)
- goto out;
- spin_lock_irqsave(&xbus->lock, flags);
-
- len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
- xbus->busname,
- xbus->busdesc,
- (xbus->hardware_exists) ? "connected" : "missing",
- xbus->bus_type
- );
- len += sprintf(page + len, "open_counter=%d packet_count=%d\n",
- xbus->open_counter,
- atomic_read(&xbus->packet_counter)
- );
-#if SOFT_SIMULATOR
- len += sprintf(page + len, "XPDS SIM\n");
- for(i = 0; i < MAX_XPDS; i++) {
- struct xpd_sim *sim = &xbus->sim[i];
- xpd_t *xpd = xpd_of(xbus, i);
- len += sprintf(page + len, "\t%d> ignored=%d simulated=%d softloop_xpd=%d loopto=%d instanciated=%s\n",
- i, IS_SET(ignore_xpds, i), sim->simulated, sim->softloop_xpd, sim->loopto, (xpd) ? "yes" : "no");
- }
-#endif
- len += sprintf(page + len, "COUNTERS:\n");
- for(i = 0; i < XBUS_COUNTER_MAX; i++) {
- len += sprintf(page + len, "\t%-15s = %d\n",
- xbus_counters[i].name, xbus->counters[i]);
- }
- len += sprintf(page + len, "<-- len=%d\n", len);
- spin_unlock_irqrestore(&xbus->lock, flags);
-out:
- if (len <= off+count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
- return len;
-
-}
-
int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- int len = 0;
+ int len = 0;
+ unsigned int xpp_timer_rate;
+ unsigned int now;
len += sprintf(page + len, "# To modify sync source write into this file:\n");
len += sprintf(page + len, "# HOST - For host based sync\n");
@@ -952,8 +690,8 @@ int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, voi
else
len += sprintf(page + len, "%s/%s\n", sync_master->xbus->busname, sync_master->xpdname);
len += sprintf(page + len, "tick: #%d\n", xpp_timer_count);
- unsigned int xpp_timer_rate = 0;
- unsigned int now = jiffies;
+ xpp_timer_rate = 0;
+ now = jiffies;
if(now - xpp_last_jiffies > 0) {
xpp_timer_rate = ((xpp_timer_count % SAMPLE_TICKS) * 1000) / (now - xpp_last_jiffies);
len += sprintf(page + len, "tick rate: %4d/second (average over %d seconds)\n", xpp_timer_rate, SAMPLE_TICKS/HZ);
@@ -971,7 +709,6 @@ int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, voi
static int proc_sync_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
- DBG("%s: count=%ld\n", __FUNCTION__, count);
const int NUM_SIZE = 100;
char buf[NUM_SIZE];
int xbus_num;
@@ -979,31 +716,47 @@ static int proc_sync_write(struct file *file, const char __user *buffer, unsigne
xbus_t *xbus;
xpd_t *xpd;
int ret;
+ bool setit;
+ // DBG("%s: count=%ld\n", __FUNCTION__, count);
if(count >= NUM_SIZE)
return -EINVAL;
if(copy_from_user(buf, buffer, count))
return -EFAULT;
buf[count] = '\0';
if(strncmp("HOST", buf, 4) == 0) {
- set_sync_master(NULL);
+ sync_master_is(NULL);
goto out;
}
- ret = sscanf(buf, "%d %d", &xbus_num, &xpd_num);
- if(ret != 2)
+ ret = sscanf(buf, "%d %d %d", &xbus_num, &xpd_num, &setit);
+ if(ret == 2) {
+ // For backward compatibility: before query was introduced,
+ // only two parameters were possible
+ setit = 1;
+ ret = 3;
+ }
+ if(ret != 3 || (setit != 0 && setit != 1)) {
+ ERR("Bad format for SYNC.\n");
+ ERR("Usage: <bus_num> <xpd_num> <0/1> # 0 - QUERY, 1 - SET\n");
return -EINVAL;
- DBG("%s: %d/%d\n", __FUNCTION__, xbus_num, xpd_num);
- if(xbus_num >= MAX_BUSES)
+ }
+ if(xbus_num >= MAX_BUSES) {
+ ERR("Invalid xbus number %d\n", xbus_num);
return -EINVAL;
+ }
xbus = xbus_of(xbus_num);
- if(!xbus)
+ if(!xbus) {
+ ERR("No bus %d exists\n", xbus_num);
return -EINVAL;
+ }
xpd = xpd_of(xbus, xpd_num);
if(!xpd) {
ERR("%s: XPD number %d does not exist\n", __FUNCTION__, xpd_num);
return -ENXIO;
}
- set_sync_master(xpd);
+ DBG("%s: %d/%d %s\n", __FUNCTION__, xbus_num, xpd_num, (setit)?"SET":"QUERY");
+ if(setit)
+ external_sync(xpd);
out:
return count;
}
@@ -1050,9 +803,9 @@ static int proc_xpd_ztregister_write(struct file *file, const char __user *buffe
DBG("%s: %s/%s %s\n", __FUNCTION__,
xpd->xbus->busname, xpd->xpdname, (zt_reg) ? "register" : "unregister");
if(zt_reg)
- ret = xpd_zaptel_register(xpd);
+ ret = zaptel_register_xpd(xpd);
else
- ret = xpd_zaptel_unregister(xpd);
+ ret = zaptel_unregister_xpd(xpd);
return (ret < 0) ? ret : count;
}
@@ -1119,279 +872,6 @@ error:
return ret;
}
-static void xbus_poll(xbus_t *xbus, int probe_all)
-{
- int id;
- int ret;
- xpd_t **xpds;
- xpd_t *xpd;
-
- DBG("%s (probe_all=%d)\n", xbus->busname, probe_all);
- xpds = xbus->xpds;
- for(id = 0; id < MAX_XPDS; id++) {
- if(!xbus->hardware_exists)
- break;
- xpd = xpd_of(xbus, id);
- if(!probe_all) {
- if(!xpd) {
- DBG(" Skipping XPD #%d is MISSING\n", id);
- continue;
- }
- if(!atomic_read(&xpd->card_present)) {
- DBG(" Skipping XPD #%d not present\n", id);
- continue;
- }
- if(time_after(xpd->last_response+20, jiffies)) {
- DBG(" SKIP DESC_REQ\n");
- continue;
- }
- }
- if(IS_SET(ignore_xpds, id)) { /* skip xpds */
- DBG(" Ignoring XPD #%d\n", id);
- continue;
- }
- DBG(" Polling slot %d %s\n", id, xbus->busname);
- ret = CALL_PROTO(GLOBAL, DESC_REQ, xbus, NULL, id);
- if(ret < 0) {
- NOTICE("xpp: %s: Failed sending DESC_REQ to XPD #%d\n", __FUNCTION__, id);
- }
- }
-}
-
-void process_xbus_poll(void *data) {
- xbus_t *xbus = (xbus_t*) data;
-
- ERR("%s: issuing xbus_poll\n", __FUNCTION__);
- xbus_poll(xbus, 1);
-}
-
-
-#if SOFT_SIMULATOR
-/*
- * Assume xbus->lock is held
- */
-static void simulator_setup(xbus_t *xbus, ulong sim_xpds)
-{
- int i;
- int last_fxo = 0;
- bool first = 1;
-
- DBG("%s: sim_xpds=0x%lX\n", xbus->busname, sim_xpds);
- for(i = 0; i < MAX_XPDS; i++) {
- if (!IS_SET(sim_xpds, i) || xbus->sim[i].simulated)
- continue;
- if (first) {
- last_fxo=i;
- } else {
- // setting simulated twice here: in case of odd number of simulated XPDs
- xbus->sim[i].xpd_type = XPD_TYPE_FXO;
- xbus->sim[i].loopto = last_fxo;
- xbus->sim[i].simulated = 1;
- xbus->sim[last_fxo].xpd_type = XPD_TYPE_FXS;
- xbus->sim[last_fxo].loopto = i;
- xbus->sim[last_fxo].simulated = 1;
-
- }
- if(IS_SET(softloop_xpds, i))
- xbus->sim[i].softloop_xpd = 1;
- xbus->sim[i].hookstate = 0;
-
- first = !first;
- }
-}
-#endif
-
-void xbus_activate(xbus_t *xbus)
-{
- xbus_ops_t *ops;
-
- BUG_ON(!xbus);
- ops = xbus->ops;
- BUG_ON(!ops);
- BUG_ON(!xbus->priv);
- /* Sanity checks */
- if(!ops->packet_send) {
- ERR("%s: missing mandatory handler: packet_send=\n", __FUNCTION__);
- return;
- }
- if(!ops->packet_new || !ops->packet_free) {
- ops->packet_new = softloop_packet_new;
- ops->packet_free = softloop_packet_free;
- }
-
- xbus->hardware_exists = 1;
- DBG("Activating: %s\n", xbus->busname);
- /* Poll it */
- xbus_poll(xbus, 1);
-}
-
-void xbus_deactivate(xbus_t *xbus)
-{
- int i;
-
- BUG_ON(!xbus);
- DBG("%s\n", xbus->busname);
- xbus->hardware_exists = 0;
- for(i = 0; i < MAX_XPDS; i++) {
- xpd_t *xpd = xpd_of(xbus, i);
- if(!xpd)
- continue;
- if(xpd->id != i) {
- ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
- continue;
- }
- xpd_card_disable(xpd);
- }
- down_write(&xbus->in_use);
- DBG("%s (deactivated)\n", xbus->busname);
- if(xbus->open_counter == 0) {
- xbus_remove(xbus);
- }
-}
-
-
-static void xbus_cleanup(xbus_t *xbus)
-{
- BUG_ON(!xbus);
-#ifdef CONFIG_PROC_FS
- if(xbus->proc_xbus_dir) {
- if(xbus->proc_xbus_summary) {
- DBG("Removing proc '%s' for %s\n", PROC_XBUS_SUMMARY, xbus->busname);
- remove_proc_entry(PROC_XBUS_SUMMARY, xbus->proc_xbus_dir);
- xbus->proc_xbus_summary = NULL;
- }
- DBG("Removing proc directory %s\n", xbus->busname);
- remove_proc_entry(xbus->busname, xpp_procdir);
- xbus->proc_xbus_dir = NULL;
- }
-#endif
- kfree(xbus);
-}
-
-xbus_t *xbus_new(ulong loopback_xpds)
-{
- unsigned long flags;
- int xbus_num;
- int err;
- xbus_t *xbus;
-
- xbus = kmalloc(sizeof(xbus_t), GFP_KERNEL);
- if(!xbus)
- return NULL;
- memset(xbus, 0, sizeof(xbus_t));
-
- spin_lock_irqsave(&xbuses_lock, flags);
- for(xbus_num = 0; xbus_num < MAX_BUSES; xbus_num++)
- if(xbuses_array[xbus_num] == NULL)
- break;
- if(xbus_num >= MAX_BUSES) {
- spin_unlock_irqrestore(&xbuses_lock, flags);
- err = -ENOMEM;
- goto nobus;
- }
- /* Found empty slot */
- xbuses_array[xbus_num] = xbus;
- bus_count++;
- spin_unlock_irqrestore(&xbuses_lock, flags);
-
- /* Init data structures */
- spin_lock_init(&xbus->lock);
- snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%d", xbus_num);
- INFO("New xbus: %s\n", xbus->busname);
- init_waitqueue_head(&xbus->packet_cache_empty);
- atomic_set(&xbus->packet_counter, 0);
- init_rwsem(&xbus->in_use);
- xbus->num = xbus_num;
- xbus->num_xpds = 0;
-#if SOFT_SIMULATOR
- xbus->sim_workqueue = create_singlethread_workqueue(xbus->busname);
- if(!xbus->sim_workqueue) {
- ERR("Failed to create workqueue for xbus %s\n", xbus->busname);
- err = -ENOMEM;
- goto nobus;
- }
- init_xbus_packet_queue(&xbus->sim_packet_queue, "SIM_PACKET_QUEUE");
- INIT_WORK(&xbus->sim_work, process_sim_queue, xbus);
- simulator_setup(xbus, loopback_xpds); // Hardware loopback must use simulator
- simulator_setup(xbus, softloop_xpds); // Add the soft loopback to the simulated set
-#endif
- xbus_reset_counters(xbus);
-#ifdef CONFIG_PROC_FS
- DBG("Creating xbus proc directory %s.\n",xbus->busname);
- xbus->proc_xbus_dir = proc_mkdir(xbus->busname, xpp_procdir);
- if(!xbus->proc_xbus_dir) {
- ERR("Failed to create proc directory for xbus %s\n", xbus->busname);
- err = -EIO;
- goto nobus;
- }
- xbus->proc_xbus_summary = create_proc_read_entry(PROC_XBUS_SUMMARY, 0444, xbus->proc_xbus_dir,
- xbus_read_proc, xbus);
- if (!xbus->proc_xbus_summary) {
- ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_SUMMARY, xbus->busname);
- err = -EIO;
- goto nobus;
- }
-#endif
- return xbus;
-nobus:
- spin_lock_irqsave(&xbuses_lock, flags);
- xbuses_array[xbus_num] = NULL;
- bus_count--;
- spin_unlock_irqrestore(&xbuses_lock, flags);
- xbus_cleanup(xbus);
- return NULL;
-}
-
-static void xbus_remove(xbus_t *xbus)
-{
- int i;
- unsigned long flags;
-
- BUG_ON(!xbus);
- DBG("%s\n", xbus->busname);
- spin_lock_irqsave(&xbuses_lock, flags);
- BUG_ON(xbus != xbus_of(xbus->num));
- xbuses_array[xbus->num] = NULL;
- bus_count--;
- spin_unlock_irqrestore(&xbuses_lock, flags);
-#if SOFT_SIMULATOR
- if(xbus->sim_workqueue) {
- cancel_delayed_work(&xbus->sim_work);
- }
-#endif
- INFO("Removing xbus(%d) %s\n", xbus->num, xbus->busname);
- for(i = 0; i < MAX_XPDS; i++) {
- xpd_t *xpd = xpd_of(xbus, i);
-
- if(xpd) {
- const xops_t *xops = xpd->xops;
-
- if(xpd->id != i) {
- ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
- continue;
- }
- BUG_ON(!xops);
- DBG(" Removing xpd id=%d\n", xpd->id);
- xpd_remove(xpd);
- }
- xbus->xpds[i] = NULL;
- }
-#if SOFT_SIMULATOR
- if(xbus->sim_workqueue) {
- flush_workqueue(xbus->sim_workqueue);
- destroy_workqueue(xbus->sim_workqueue);
- xbus->sim_workqueue = NULL;
- }
- drain_xbus_packet_queue(xbus, &xbus->sim_packet_queue);
-#endif
- int ret = wait_event_interruptible(xbus->packet_cache_empty,
- atomic_read(&xbus->packet_counter) == 0);
- if(ret) {
- ERR("waiting for packet_cache_empty interrupted!!!\n");
- }
- xbus_cleanup(xbus);
-}
-
#define XPP_MAX_LEN 512
@@ -1407,12 +887,12 @@ static void xpp_transmitprep(xpd_t *xpd)
int i;
int channels = xpd->channels;
struct zt_chan *chans = xpd->span.chans;
+ unsigned long flags;
+ spin_lock_irqsave(&xpd->lock, flags);
// if((xpd->timer_count % PREP_REPORT_RATE) < 10)
// DBG("%d\n", xpd->timer_count);
-// if(xpd->hookstate == 0)
-// return;
if (xpd->timer_count & 1) {
/* First part */
w = writechunk = xpd->writechunk /* + 1 */;
@@ -1422,18 +902,26 @@ static void xpp_transmitprep(xpd_t *xpd)
zt_transmit(&xpd->span);
for (i = 0; i < channels; i++) {
- if(IS_SET(xpd->hookstate, i)) {
+ if (xpd->delay_until_dialtone[i] > 0) {
+ xpd->delay_until_dialtone[i]--;
+ if (xpd->delay_until_dialtone[i] <= 0) {
+ xpd->delay_until_dialtone[i] = 0;
+ wake_up_interruptible(&xpd->txstateq[i]);
+ }
+ }
+ if(IS_SET(xpd->hookstate, i) || IS_SET(xpd->cid_on, i)) {
memcpy((u_char *)w, chans[i].writechunk, ZT_CHUNKSIZE);
// fill_beep((u_char *)w, 5);
}
w += ZT_CHUNKSIZE;
}
- if(xpd->hookstate != 0 || sync_master == xpd || !sync_master) {
- ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate, writechunk);
+// if(xpd->hookstate != 0 || sync_master != xpd) {
+ ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate | xpd->cid_on, writechunk);
if(ret < 0) {
DBG("failed to write PCM %d\n", ret);
}
- }
+// }
+ spin_unlock_irqrestore(&xpd->lock, flags);
}
void fill_beep(u_char *buf, int duration)
@@ -1446,20 +934,46 @@ void fill_beep(u_char *buf, int duration)
static u_char beep[] = {
// 0x7F, 0xBE, 0xD8, 0xBE, 0x80, 0x41, 0x24, 0x41, /* Dima */
// 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, /* silence */
- 0x67, 0x90, 0x89, 0x90, 0xFF, 0x10, 0x09, 0x10, /* Izzy */
+// 0x67, 0x90, 0x89, 0x90, 0xFF, 0x10, 0x09, 0x10, /* Izzy */
// 0x67, 0xCD, 0xC5, 0xCD, 0xFF, 0x49, 0x41, 0x49, /* Dima 2 */
-// 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, /* silence */
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, /* silence */
};
memcpy(buf, &beep[(which*8) % ARRAY_SIZE(beep)], 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)
+{
+ short rxlin;
+ int x;
+ unsigned long flags;
+
+ /* Perform echo cancellation on a chunk if necessary */
+ if (!chan->ec)
+ return;
+ spin_lock_irqsave(&chan->lock, flags);
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ rxlin = ZT_XLAW(rxchunk[x], chan);
+ rxlin = xpp_echo_can_update(chan->ec, ZT_XLAW(txchunk[x], chan), rxlin);
+ rxchunk[x] = ZT_LIN2X((int)rxlin, chan);
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+#endif
+
+
static void xpp_receiveprep(xpd_t *xpd)
{
volatile u_char *readchunk;
int i;
int channels = xpd->channels;
struct zt_chan *chans = xpd->span.chans;
+ unsigned long flags;
+ spin_lock_irqsave(&xpd->lock, flags);
// if((xpd->timer_count % PREP_REPORT_RATE) == 0)
// DBG("%d\n", xpd->timer_count);
@@ -1472,20 +986,29 @@ static void xpp_receiveprep(xpd_t *xpd)
for (i = 0; i < channels; i++) {
if(IS_SET(xpd->hookstate, i)) {
+ // memset((u_char *)readchunk, 0x5A, ZT_CHUNKSIZE); // DEBUG
+ // fill_beep((u_char *)readchunk, 1); // DEBUG: BEEP
memcpy(chans[i].readchunk, (u_char *)readchunk, ZT_CHUNKSIZE);
+ } else {
+ memset(chans[i].readchunk, 0x7F, ZT_CHUNKSIZE); // SILENCE
}
readchunk += ZT_CHUNKSIZE;
}
-#if 0
+#if WITH_ECHO_SUPPRESSION
/* FIXME: need to Echo cancel double buffered data */
for (i = 0;i < xpd->span.channels; i++) {
+#ifdef XPP_EC_CHUNK
+ xpp_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]);
+#else
zt_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]);
+#endif
memcpy(xpd->ec_chunk2[i], xpd->ec_chunk1[i], ZT_CHUNKSIZE);
memcpy(xpd->ec_chunk1[i], chans[i].writechunk, ZT_CHUNKSIZE);
}
#endif
zt_receive(&xpd->span);
+ spin_unlock_irqrestore(&xpd->lock, flags);
}
static int xpp_startup(struct zt_span *span)
@@ -1540,13 +1063,18 @@ int xpp_close(struct zt_chan *chan)
spin_lock_irqsave(&xbus->lock, flags);
xbus->open_counter--;
atomic_dec(&xpd->open_counter);
+ if(xpd->direction == TO_PHONE) { /* Hangup phone */
+ xpd->idletxhookstate[chan->chanpos - 1] = FXS_LINE_ENABLED;
+ }
if (!xbus->hardware_exists && xbus->open_counter == 0)
should_remove = 1;
spin_unlock_irqrestore(&xbus->lock, flags);
DBG("chan=%d (open_counter=%d, should_remove=%d)\n", chan->chanpos, xbus->open_counter, should_remove);
- if(should_remove)
+ if(should_remove) {
+ DBG("Going to remove: %s\n", xbus->busname);
xbus_remove(xbus);
+ }
return 0;
}
@@ -1560,10 +1088,11 @@ int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
case ZT_ONHOOKTRANSFER:
if (get_user(x, (int *)arg))
return -EFAULT;
- if (xpd->lasttxhook[pos] == 0x1) {
+ xpd->ohttimer[pos] = x << 3;
+ xpd->idletxhookstate[pos] = FXS_LINE_CID; /* OHT mode when idle */
+ if (xpd->lasttxhook[pos] == FXS_LINE_ENABLED) {
/* Apply the change if appropriate */
- xpd->lasttxhook[pos] = 0x2;
- // CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, BIT(pos)); // CALLER ID
+ CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, pos); // CALLER ID
}
DBG("xpd=%d: ZT_ONHOOKTRANSFER (%d millis) chan=%d\n", xpd->id, x, pos);
return -ENOTTY;
@@ -1574,6 +1103,13 @@ int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
xpd->id, pos, (x & ZT_TONEDETECT_ON), (x & ZT_TONEDETECT_MUTE));
return -ENOTTY;
default:
+ /* Some span-specific commands before we give up: */
+ if (xpd->xops->card_ioctl != NULL) {
+ x = xpd->xops->card_ioctl(xpd, pos, cmd, arg);
+ if (x != -ENOTTY)
+ return x;
+ }
+
DBG("ENOTTY: chan=%d cmd=0x%x\n", pos, cmd);
DBG(" IOC_TYPE=0x%02X\n", _IOC_TYPE(cmd));
DBG(" IOC_DIR=0x%02X\n", _IOC_DIR(cmd));
@@ -1590,109 +1126,15 @@ 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;
- int ret = 0;
-
- if(!xpd) {
- ERR("%s: channel=%d without an XPD!\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- xbus = xpd->xbus;
-
- if (txsig == ZT_TXSIG_START) {
- if(xpd->direction == TO_PHONE) {
- // A PHONE line: ZT_START will be treated as ZT_RING
- DBG("Got ZT_START for PHONE channel %d, treated as ZT_RING\n", pos);
- //hookstate = ZT_TXSIG_RING;
- if(IS_SET(xpd->digital_inputs, pos)) {
- NOTICE("%s: Trying to RING a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_RING %s digital output ON\n", chan->name);
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
- return ret;
- }
- xpd->ringing[pos] = RINGS_NUM*2;
- DBG("ZT_RING %s ringing=%d\n", chan->name, xpd->ringing[pos]);
- ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1); // RING on
- if(ret) {
- DBG("ZT_RING Failed: ret=0x%02X\n", ret);
- return ret;
- }
- return ret;
- } else { /* TO_PSTN */
- // An FXO line: ZT_START will be treated as ZT_OFFHOOK
- DBG("Got ZT_START for FXO channel %d, treated as ZT_OFFHOOK\n", pos);
- txsig = ZT_TXSIG_OFFHOOK;
- }
- }
- switch(txsig) {
- case ZT_TXSIG_START:
- DBG("ZT_TXSIG_START: (doing OFFHOOK) %s (chan->dialing=%d)\n", chan->name, chan->dialing);
- break;
- /* Fall through */
- case ZT_TXSIG_OFFHOOK:
- DBG("ZT_TXSIG_OFFHOOK: %s hookstate=0x%04X\n", chan->name, xpd->hookstate);
- BIT_SET(xpd->hookstate, pos);
- xpd->ringing[pos] = 0;
- if(IS_SET(xpd->digital_inputs, pos)) {
- NOTICE("%s: Trying to OFFHOOK a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_TXSIG_OFFHOOK %s digital output OFF\n", chan->name);
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
- return ret;
- }
- ret = CALL_XMETHOD(SETHOOK, xbus, xpd->id, xpd->hookstate);
- if(ret) {
- DBG("ZT_TXSIG_OFFHOOK Failed: ret=0x%02X\n", ret);
- break;
- }
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
- break;
- //DBG("ZT_TXSIG_OFFHOOK %d\n", pos);
- //BIT_SET(xpd->hookstate, pos);
- //break;
- case ZT_TXSIG_KEWL:
- DBG("ZT_TXSIG_KEWL (doing ONHOOK): %d.\n", pos);
- break;
- /* Fall through */
- case ZT_TXSIG_ONHOOK:
- DBG("ZT_TXSIG_ONHOOK: %s hookstate=0x%04X\n", chan->name, xpd->hookstate);
- xpd->ringing[pos] = 0;
- if(IS_SET(xpd->digital_inputs, pos)) {
- NOTICE("%s: Trying to ONHOOK a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_TXSIG_ONHOOK %s digital output OFF\n", chan->name);
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
- return ret;
- }
- BIT_CLR(xpd->hookstate, pos);
- ret = CALL_XMETHOD(SETHOOK, xbus, xpd->id, xpd->hookstate);
- if(ret) {
- DBG("ZT_ONHOOK Failed: ret=0x%02X\n", ret);
- break;
- }
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
- break;
- //DBG("ZT_TXSIG_ONHOOK: %d\n", pos);
- //BIT_CLR(xpd->hookstate, pos);
- //break;
- default:
- DBG("hooksig: unkown txsig=%d on channel %d\n", txsig, pos);
- return -EINVAL;
- }
- //ret = CALL_XMETHOD(SETHOOK, xbus, xpd->id, xpd->hookstate);
- //if(ret) {
- // DBG("ZT_TXSIG_START Failed: ret=0x%02X\n", ret);
- //}
- return ret;
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ DBG("Setting %s to %s (%d)\n", chan->name, txsig2str(txsig), txsig);
+ return CALL_XMETHOD(card_hooksig, xbus, xpd, pos, txsig);
}
-#endif
+
+#else
static int xpp_sethook(struct zt_chan *chan, int hookstate)
{
@@ -1701,102 +1143,15 @@ static int xpp_sethook(struct zt_chan *chan, int hookstate)
xbus_t *xbus;
int ret = 0;
- if(!xpd) {
- ERR("%s: channel=%d without an XPD!\n", __FUNCTION__, pos);
- return -EINVAL;
- }
+ BUG_ON(!xpd);
xbus = xpd->xbus;
DBG("%s (%d) (old=0x%04X, hook-command=%d)\n", chan->name, pos, xpd->hookstate, hookstate);
- switch(hookstate) {
- /* On-hook, off-hook: The PBX is playing a phone on an FXO line.
- * Can be ignored for an FXS line
- */
- case ZT_ONHOOK:
- if(IS_SET(xpd->digital_inputs, pos)) {
- NOTICE("%s: Trying to ONHOOK a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_ONHOOK %s digital output OFF\n", chan->name);
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
- return ret;
- }
- if(xpd->direction == TO_PHONE) { /* Stop ring */
- DBG("ZT_ONHOOK: %s hookstate=0x%04X (stop ringing pos=%d)\n", chan->name, xpd->hookstate, pos);
- xpd->ringing[pos] = 0;
-#if 1 // FIXME: Not needed -- verify
- ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0); // RING off
-#endif
- xpd->lasttxhook[pos] = 1;
- ret = CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(pos), LED_GREEN, 0);
- ret = CALL_XMETHOD(CHAN_POWER, xbus, xpd, BIT(pos), 0); // Power down (prevent overheating!!!)
- if(ret) {
- DBG("ZT_ONHOOK(stop ring) Failed: ret=0x%02X\n", ret);
- break;
- }
- } else {
- DBG("ZT_ONHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
- xpd->ringing[pos] = 0;
- BIT_CLR(xpd->hookstate, pos);
- ret = CALL_XMETHOD(SETHOOK, xbus, xpd, xpd->hookstate);
- if(ret) {
- DBG("ZT_ONHOOK Failed: ret=0x%02X\n", ret);
- break;
- }
- }
- break;
- case ZT_START:
- DBG("ZT_START: %s hookstate=0x%04X (fall through ZT_OFFHOOK)\n", chan->name, xpd->hookstate);
- // Fall through
- case ZT_OFFHOOK:
- if(xpd->direction == TO_PHONE) {
- DBG("ZT_OFFHOOK: %s hookstate=0x%04X -- ignoring (PHONE)\n", chan->name, xpd->hookstate);
- break;
- }
- DBG("ZT_OFFHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
- BIT_SET(xpd->hookstate, pos);
- xpd->ringing[pos] = 0;
- ret = CALL_XMETHOD(SETHOOK, xbus, xpd, xpd->hookstate);
- if(ret) {
- DBG("ZT_OFFHOOK Failed: ret=0x%02X\n", ret);
- break;
- }
- break;
- case ZT_WINK:
- DBG("ZT_WINK %s\n", chan->name);
- break;
- case ZT_FLASH:
- DBG("ZT_FLASH %s\n", chan->name);
- break;
- case ZT_RING:
- DBG("ZT_RING %s pos=%d (ringing[pos]=%d)\n", chan->name, pos, xpd->ringing[pos]);
- if(xpd->direction == TO_PHONE) {
- if(IS_SET(xpd->digital_inputs, pos)) {
- NOTICE("%s: Trying to RING a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_ONHOOK %s digital output ON\n", chan->name);
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
- return ret;
- }
- xpd->ringing[pos] = RINGS_NUM*2;
- ret = CALL_XMETHOD(CHAN_POWER, xbus, xpd, BIT(pos), 1); // Power up (for ring)
- ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1); // RING on
- if(ret) {
- DBG("ZT_RING Failed: ret=0x%02X\n", ret);
- }
- }
- break;
- case ZT_RINGOFF:
- DBG("ZT_RINGOFF %s\n", chan->name);
- break;
- default:
- DBG("UNKNOWN hookstate=0x%X\n", hookstate);
- }
+ ret = CALL_XMETHOD(card_sethook, xpd->xbus, xpd, pos, hookstate);
return ret;
}
+#endif
+
/* 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);
@@ -1815,7 +1170,6 @@ int xpp_maint(struct zt_span *span, int cmd)
switch(cmd) {
case ZT_MAINT_NONE:
printk("XXX Turn off local and remote loops XXX\n");
- CALL_XMETHOD(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 0); // FIXME: Find usage for extra LED
break;
case ZT_MAINT_LOCALLOOP:
printk("XXX Turn on local loopback XXX\n");
@@ -1825,12 +1179,10 @@ int xpp_maint(struct zt_span *span, int cmd)
break;
case ZT_MAINT_LOOPUP:
printk("XXX Send loopup code XXX\n");
- CALL_XMETHOD(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 1); // FIXME: Find usage for extra LED
// 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");
- CALL_XMETHOD(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 0); // FIXME: Find usage for extra LED
break;
case ZT_MAINT_LOOPSTOP:
printk("XXX Stop sending loop codes XXX\n");
@@ -1848,8 +1200,7 @@ int xpp_maint(struct zt_span *span, int cmd)
/* Set signalling type (if appropriate) */
static int xpp_chanconfig(struct zt_chan *chan, int sigtype)
{
- DBG("channel %d (%s), sigtype %d.\n", chan->channo, chan->name, sigtype);
- dump_sigtype(print_dbg, " ", sigtype);
+ DBG("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?)
@@ -1878,6 +1229,29 @@ int (*hooksig)(struct zt_chan *chan, zt_txsig_t hookstate);
int (*sethook)(struct zt_chan *chan, int hookstate);
#endif
+#ifdef XPP_EC_CHUNK
+static int xpp_echocan(struct zt_chan *chan, int len)
+{
+ 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;
+ }
+ return 0;
+}
+#endif
+
#ifdef CONFIG_ZAPTEL_WATCHDOG
/*
* If the watchdog detects no received data, it will call the
@@ -1904,33 +1278,40 @@ static int xpp_watchdog(struct zt_span *span, int cause)
* - User action through /proc
* - During xpd_remove()
*/
-static int xpd_zaptel_unregister(xpd_t *xpd)
+static int zaptel_unregister_xpd(xpd_t *xpd)
{
+ unsigned long flags;
+
BUG_ON(!xpd);
+ spin_lock_irqsave(&xpd->lock, flags);
if(!SPAN_REGISTERED(xpd)) {
NOTICE("%s: %s is already unregistered\n", __FUNCTION__, xpd->xpdname);
+ spin_unlock_irqrestore(&xpd->lock, flags);
return -EIDRM;
}
if(sync_master == xpd)
- set_sync_master(NULL); // FIXME: it's better to elect a new prince
+ sync_master_is(NULL); // FIXME: it's better to elect a new prince
update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
if(atomic_read(&xpd->open_counter)) {
NOTICE("%s: %s is busy (open_counter=%d). Skipping.\n", __FUNCTION__, xpd->xpdname, 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);
zt_unregister(&xpd->span);
+ if(xpd->card_present)
+ xpd->xops->card_zaptel_postregistration(xpd, 0);
return 0;
}
-static int xpd_zaptel_register(xpd_t *xpd)
+static int zaptel_register_xpd(xpd_t *xpd)
{
- struct zt_chan *cur_chan;
struct zt_span *span;
xbus_t *xbus;
- int sigfxs;
- int i;
int cn;
const xops_t *xops;
@@ -1941,7 +1322,6 @@ static int xpd_zaptel_register(xpd_t *xpd)
ERR("xpd %s already registered\n", xpd->xpdname);
return -EEXIST;
}
- sigfxs = ! (xpd->direction == TO_PHONE); /* signaling is opposite */
cn = xpd->channels;
DBG("Initializing span: xpd %d have %d channels.\n", xpd->id, cn);
@@ -1950,59 +1330,7 @@ static int xpd_zaptel_register(xpd_t *xpd)
span = &xpd->span;
xbus = xpd->xbus;
- snprintf(span->name, MAX_SPANNAME, "%s/%s",
- xbus->busname, xpd->xpdname);
- {
- char tmp[MAX_SPANNAME];
-#if SOFT_SIMULATOR
- struct xpd_sim *sim = &xbus->sim[xpd->id];
-
- if(sim->simulated)
- snprintf(tmp, MAX_SPANNAME, " (sim to=%d)", sim->loopto);
- else
-#endif
- tmp[0] = '\0';
-
- snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: %s%s",
- xbus->num, xpd->id,
- (xpd->direction == TO_PHONE) ? "FXS" : "FXO",
- tmp
- );
- }
- for(i = 0; i < cn; i++) {
-
- cur_chan = &xpd->chans[i];
- DBG("setting channel %d (sigfxs=%d)\n", i, sigfxs);
- if(IS_SET(xpd->digital_outputs, i)) {
- snprintf(cur_chan->name, MAX_CHANNAME, "XPP_OUT/%d-%d", xpd->id, i);
- } else if(IS_SET(xpd->digital_inputs, i)) {
- snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%d-%d", xpd->id, i);
- } else {
- snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%d-%d", (sigfxs) ? "FXO" : "FXS", xpd->id, i);
- }
- cur_chan->chanpos = i + 1;
- cur_chan->pvt = xpd;
- if (sigfxs)
- cur_chan->sigcap =
-#if 1
- ZT_SIG_FXSKS |
- ZT_SIG_FXSLS |
-#else
- ZT_SIG_SF |
-#endif
- 0;
- else
- cur_chan->sigcap =
-#if 1
- ZT_SIG_FXOKS |
- ZT_SIG_FXOLS |
- ZT_SIG_FXOGS |
-#else
- ZT_SIG_SF |
- ZT_SIG_EM |
-#endif
- 0;
- }
+ snprintf(span->name, MAX_SPANNAME, "%s/%s", xbus->busname, xpd->xpdname);
span->deflaw = ZT_LAW_MULAW;
init_waitqueue_head(&span->maintq);
span->pvt = xpd;
@@ -2023,67 +1351,28 @@ static int xpd_zaptel_register(xpd_t *xpd)
#endif
span->ioctl = xpp_ioctl;
span->maint = xpp_maint;
+#ifdef XPP_EC_CHUNK
+ span->echocan = xpp_echocan;
+#endif
#ifdef CONFIG_ZAPTEL_WATCHDOG
span->watchdog = xpp_watchdog;
#endif
- DBG("Finished span_load: ZT_FLAG_RUNNING=%d\n", span->flags & ZT_FLAG_RUNNING);
-
DBG("Registering span of %s.\n", xpd->xpdname);
+ xpd->xops->card_zaptel_preregistration(xpd, 1);
if(zt_register(&xpd->span, 1)) {
xbus_t *xbus = xpd->xbus;
- ERR("Failed to zt_register of span of xpd %s.\n", xpd->xpdname);
- xbus->xpds[xpd->id] = NULL;
- list_del(&xpd->xpd_list);
- xbus->num_xpds--;
+ ERR("%s/%s: Failed to zt_register span\n", xbus->busname, xpd->xpdname);
return -ENODEV;
}
-// if(xpd->id == 0)
-// set_sync_master(xpd);
-
+ xpd->xops->card_zaptel_postregistration(xpd, 1);
return 0;
}
-
/*------------------------- Proc debugging interface ---------------*/
#ifdef CONFIG_PROC_FS
-static int xpp_zap_read_proc(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 = xbus_of(i);
-
- if(xbus) {
- len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
- xbus->busname,
- xbus->busdesc,
- (xbus->hardware_exists) ? "connected" : "missing",
- xbus->bus_type
- );
- }
- }
-#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;
-
-}
-
#if 0
static int xpp_zap_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
@@ -2097,6 +1386,7 @@ static int xpp_zap_write_proc(struct file *file, const char __user *buffer, unsi
#define MINOR_XBUS_NUM(m) ((m) >> 4)
#define MINOR_XPD_NUM(m) ((m) & 0xF);
+#if 0
static int xpp_sys_open (struct inode * inode, struct file * file)
{
xbus_t *xbus;
@@ -2164,7 +1454,7 @@ static ssize_t xpp_sys_write (struct file * file, const char __user * buf,
if (copy_from_user (pack_tx->content.raw, buf, count)) {
return -EFAULT;
}
- XPD_ADDR_SET(pack_tx->content.addr, xpdnum);
+ xpd_set_addr(&pack_tx->content.addr, xpdnum);
pack_tx->datalen = count;
// pack_tx->flags |= XPP_PACKET_FIREANDFORGET;
DBG("sending op=%d to %d\n", pack_tx->content.opcode, xpdnum);
@@ -2186,6 +1476,7 @@ static struct file_operations xpp_fops = {
.release = xpp_sys_release,
};
+#endif
/*------------------------- Initialization -------------------------*/
@@ -2193,42 +1484,47 @@ static void do_cleanup(void)
{
if(timer_pending(&xpp_timer))
del_timer_sync(&xpp_timer);
+#if 0
unregister_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name);
+#endif
#ifdef CONFIG_PROC_FS
- remove_proc_entry(PROC_SYNC, xpp_procdir);
- remove_proc_entry(PROC_XBUSES, xpp_procdir);
- if(xpp_procdir) {
+ remove_proc_entry(PROC_SYNC, xpp_proc_toplevel);
+ if(xpp_proc_toplevel) {
remove_proc_entry(PROC_DIR, NULL);
}
#endif
- if (xpp_worker) {
- flush_workqueue(xpp_worker);
- destroy_workqueue(xpp_worker);
- xpp_worker = NULL;
- }
- kmem_cache_destroy(packet_cache);
}
int __init xpp_zap_init(void)
{
- INFO("%s revision %s\n", THIS_MODULE->name, revision);
+ int ret;
+ struct proc_dir_entry *ent;
+
+ INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION);
+#ifdef WITH_RBS
+ INFO("FEATURE: %s (RBS signalling)\n", THIS_MODULE->name);
+#else
+ INFO("FEATURE: %s (NO RBS signalling)\n", THIS_MODULE->name);
+#endif
+#if WITH_ECHO_SUPPRESSION
+ INFO("FEATURE: %s (with ECHO_SUPPRESSION)\n", THIS_MODULE->name);
+#else
+ INFO("FEATURE: %s (without ECHO_SUPPRESSION)\n", THIS_MODULE->name);
+#endif
+#ifdef XPP_EC_CHUNK
+ INFO("FEATURE: %s (with XPP_EC_CHUNK)\n", THIS_MODULE->name);
+#else
+ INFO("FEATURE: %s (without XPP_EC_CHUNK)\n", THIS_MODULE->name);
+#endif
- packet_cache = kmem_cache_create("xpp_packets",
- sizeof(xpacket_t),
- 0, 0,
- NULL, NULL);
- if(!packet_cache) {
- return -ENOMEM;
- }
#ifdef CONFIG_PROC_FS
- xpp_procdir = proc_mkdir(PROC_DIR, NULL);
- if(!xpp_procdir) {
+ xpp_proc_toplevel = proc_mkdir(PROC_DIR, NULL);
+ if(!xpp_proc_toplevel) {
do_cleanup();
return -EIO;
}
- struct proc_dir_entry *ent;
- ent = create_proc_entry(PROC_SYNC, 0644, xpp_procdir);
+ ent = create_proc_entry(PROC_SYNC, 0644, xpp_proc_toplevel);
if(!ent) {
do_cleanup();
return -EFAULT;
@@ -2236,67 +1532,42 @@ int __init xpp_zap_init(void)
ent->read_proc = proc_sync_read;
ent->write_proc = proc_sync_write;
ent->data = NULL;
- ent = create_proc_read_entry(PROC_XBUSES, 0444, xpp_procdir, xpp_zap_read_proc, 0);
- if (!ent) {
- do_cleanup();
- return -EFAULT;
- }
#endif
- xpp_worker = create_singlethread_workqueue("xppworker");
- if(!xpp_worker) {
- ERR("Failed to create card detector workqueue.\n");
+ ret = xbus_core_init();
+ if(ret) {
+ ERR("xbus_core_init failed (%d)\n", ret);
do_cleanup();
- return -ENOMEM;
+ return ret;
}
+#if 0
if (register_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name, &xpp_fops)) {
printk (KERN_WARNING "%s: unable to get major %d\n", THIS_MODULE->name, XPP_CTL_MAJOR);
do_cleanup();
return -EIO;
}
+#endif
/* Only timer init. We add it only *after* zt_register */
init_timer(&xpp_timer);
- set_sync_master(NULL); /* Internal ticking */
+ sync_master_is(NULL); /* Internal ticking */
return 0;
}
void __exit xpp_zap_cleanup(void)
{
-// unsigned long flags;
- int i;
-
- for(i = 0; i < MAX_BUSES; i++) {
- xbus_t *xbus = xbus_of(i);
- if(!xbus)
- continue;
- xbus_remove(xbus);
- }
-// spin_lock_irqsave(&xbuses_lock, flags);
- if(bus_count) {
- ERR("%s: bus_count=%d!\n", __FUNCTION__, bus_count);
- }
-// spin_unlock_irqrestore(&xbuses_lock, flags);
+ xbus_core_shutdown();
do_cleanup();
}
EXPORT_SYMBOL(print_dbg);
EXPORT_SYMBOL(card_detected);
EXPORT_SYMBOL(xpd_alloc);
-EXPORT_SYMBOL(xbus_activate);
-EXPORT_SYMBOL(xbus_deactivate);
-EXPORT_SYMBOL(xpd_of);
-EXPORT_SYMBOL(xbus_new);
-EXPORT_SYMBOL(xbus_remove);
-EXPORT_SYMBOL(xbus_reset_counters);
+EXPORT_SYMBOL(xpd_disconnect);
EXPORT_SYMBOL(packet_send);
+EXPORT_SYMBOL(update_xpd_status);
+EXPORT_SYMBOL(update_line_status);
EXPORT_SYMBOL(fill_beep);
-EXPORT_SYMBOL(xbus_enqueue_packet);
-EXPORT_SYMBOL(xbus_dequeue_packet);
-EXPORT_SYMBOL(init_xbus_packet_queue);
-EXPORT_SYMBOL(drain_xbus_packet_queue);
-EXPORT_SYMBOL(phone_hook);
-EXPORT_SYMBOL(xpp_check_hookstate);
EXPORT_SYMBOL(xpp_tick);
EXPORT_SYMBOL(xpp_open);
EXPORT_SYMBOL(xpp_close);
@@ -2306,7 +1577,7 @@ EXPORT_SYMBOL(xpp_maint);
MODULE_DESCRIPTION("XPP Zaptel Driver");
MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
MODULE_LICENSE("GPL");
-MODULE_VERSION("$Id$");
+MODULE_VERSION(ZAPTEL_VERSION);
module_init(xpp_zap_init);
module_exit(xpp_zap_cleanup);
diff --git a/xpp/xpp_zap.h b/xpp/xpp_zap.h
index 068f648..4d884ad 100644
--- a/xpp/xpp_zap.h
+++ b/xpp/xpp_zap.h
@@ -1,58 +1,54 @@
#ifndef XPP_ZAP_H
#define XPP_ZAP_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
#include <linux/workqueue.h>
#include "xpd.h"
#include "xproto.h"
-xpacket_t *xpacket_new(xbus_t *xbus, int flags);
-void xpacket_free(xbus_t *xbus, xpacket_t *p);
-
-/* packet queues */
-void init_xbus_packet_queue(packet_queue_t *q, const char name[]);
-void drain_xbus_packet_queue(xbus_t *xbus, packet_queue_t *q);
-void xbus_enqueue_packet(xbus_t *xbus, packet_queue_t *q, xpacket_t *pack);
-xpacket_t *xbus_dequeue_packet(packet_queue_t *q);
-
-xbus_t *xbus_new(ulong loopback_xpds);
-void xbus_activate(xbus_t *xbus);
-void xbus_deactivate(xbus_t *xbus);
-
-void xbus_reset_counters(xbus_t *xbus);
+void xpd_disconnect(xpd_t *xpd);
int packet_send(xbus_t *xbus, xpacket_t *pack_tx);
-void phone_hook(xpd_t *xpd, int channo, bool offhook);
-void xpp_check_hookstate(xpd_t *xpd, xpp_line_t fxs_off_hook);
-xpd_t *xpd_of(xbus_t *xbus, int xpd_num);
-void card_detected(void *data);
+void card_detected(struct card_desc_struct *card_desc);
xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, int channels, byte revision);
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);
void fill_beep(u_char *buf, int duration);
void xpp_tick(unsigned long param);
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 sync_master_is(xpd_t *xpd);
-#define CARD_DESC_MAGIC 0xca9dde5c
-
-struct card_desc_struct {
- struct work_struct work;
- u32 magic;
- xbus_t *xbus;
- byte rev; /* Revision number */
- byte type; /* LSB: 1 - to_phone, 0 - to_line */
- byte xpd_num;
-};
extern struct workqueue_struct *xpp_worker;
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
-extern struct proc_dir_entry *xpp_procdir;
+extern struct proc_dir_entry *xpp_proc_toplevel;
#endif
-extern xpd_t *sync_master;
-// Number of rings our simulated phone will ring:
-#define RINGS_NUM 3
+#define SPAN_REGISTERED(xpd) ((xpd)->span.flags & ZT_FLAG_REGISTERED)
#endif /* XPP_ZAP_H */
diff --git a/xpp/xproto.c b/xpp/xproto.c
index 5a0d5c6..7e6dd56 100644
--- a/xpp/xproto.c
+++ b/xpp/xproto.c
@@ -1,6 +1,6 @@
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -23,6 +23,8 @@
#include "xpd.h"
#include "xproto.h"
#include "xpp_zap.h"
+#include "xbus-core.h"
+#include "zap_debug.h"
#include <linux/module.h>
static const char rcsid[] = "$Id$";
@@ -32,26 +34,25 @@ static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack);
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 xpd_addr_t *addr)
{
- return ((addr->bank_num & ~0x1) == 0) && ((addr->card_id & ~0x3) == 0);
+ return ((addr->subunit & ~0x1) == 0) && ((addr->unit & ~0x3) == 0);
}
int xpd_addr2num(const xpd_addr_t *addr)
{
BUG_ON(!valid_xpd_addr(addr));
- return addr->bank_num * 4 + addr->card_id;
+ return addr->unit + addr->subunit * MAX_UNIT;
}
void xpd_set_addr(xpd_addr_t *addr, int xpd_num)
{
- if(xpd_num < 4) {
- addr->card_id = xpd_num;
- addr->bank_num = 0;
- } else {
- addr->card_id = xpd_num % 4;
- addr->bank_num = xpd_num / 4;
- }
+ addr->unit = xpd_num % MAX_UNIT;
+ addr->subunit = xpd_num / MAX_UNIT;
}
@@ -75,7 +76,7 @@ const xproto_entry_t *xproto_global_entry(byte opcode)
return xe;
}
-const xproto_handler_t xproto_global_handler(byte opcode)
+xproto_handler_t xproto_global_handler(byte opcode)
{
return xproto_card_handler(&PROTO_TABLE(GLOBAL), opcode);
}
@@ -87,7 +88,7 @@ const xproto_table_t *xproto_table(xpd_type_t cardtype)
return xprotocol_tables[cardtype];
}
-const xproto_table_t *get_xproto_table(xpd_type_t cardtype)
+const xproto_table_t *xproto_get(xpd_type_t cardtype)
{
const xproto_table_t *xtable;
@@ -95,18 +96,34 @@ const xproto_table_t *get_xproto_table(xpd_type_t cardtype)
return NULL;
xtable = xprotocol_tables[cardtype];
if(!xtable) { /* Try to load the relevant module */
- int ret = request_module("xpd-type-%d", cardtype);
+ 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 luck... */
+ /* Drop through: we may be lucky... */
}
xtable = xprotocol_tables[cardtype];
}
+ if(xtable) {
+ BUG_ON(!xtable->owner);
+ DBG("%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;
}
-const xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode)
+void xproto_put(const xproto_table_t *xtable)
+{
+ BUG_ON(!xtable);
+ DBG("%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;
@@ -115,7 +132,7 @@ const xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opc
return xe->handler;
}
-const xproto_entry_t *find_xproto_entry(xpd_t *xpd, byte opcode)
+static const xproto_entry_t *find_xproto_entry(xpd_t *xpd, byte opcode)
{
const xproto_entry_t *xe;
@@ -136,18 +153,6 @@ const xproto_entry_t *find_xproto_entry(xpd_t *xpd, byte opcode)
return xe;
}
-const xops_t *get_xops(xpd_type_t xpd_type)
-{
- const xproto_table_t *proto_table;
-
- if(xpd_type >= XPD_TYPE_NOMODULE)
- return NULL;
- proto_table = xprotocol_tables[xpd_type];
- if(!proto_table)
- return NULL;
- return &proto_table->xops;
-}
-
int packet_receive(xbus_t *xbus, xpacket_t *pack)
{
int xpd_num;
@@ -161,7 +166,7 @@ int packet_receive(xbus_t *xbus, xpacket_t *pack)
return -EPROTO;
}
xpd_num = XPD_NUM(pack->content.addr);
-#if SOFT_SIMULATOR
+#ifdef SOFT_SIMULATOR
if(xbus->sim[xpd_num].simulated) {
//dump_packet("packet_receive -> simulate", pack, print_dbg);
return simulate_xpd(xbus, xpd_num, pack);
@@ -189,7 +194,8 @@ static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack)
xe = find_xproto_entry(xpd, op);
/*-------- Validations -----------*/
if(!xe) {
- ERR("xpp: %s -- bad command op=0x%02X\n", __FUNCTION__, op);
+ ERR("xpp: %s: %s unit #%d: bad command op=0x%02X\n",
+ __FUNCTION__, xbus->busname, xpd_num, op);
dump_packet("packet_process -- bad command", pack, print_dbg);
ret = -EPROTO;
goto out;
@@ -221,10 +227,10 @@ void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg)
if(!print_dbg)
return;
- DBG("%s: @0x%1X%1X OP=0x%02X LEN=%d\n",
+ DBG("%s: U=0x%1X S=0x%1X OP=0x%02X LEN=%d\n",
msg,
- packet->content.addr.bank_num,
- packet->content.addr.card_id,
+ packet->content.addr.unit,
+ packet->content.addr.subunit,
op,
(byte)packet->datalen);
#if VERBOSE_DEBUG
@@ -256,7 +262,7 @@ const char *xproto_name(xpd_type_t xpd_type)
{
const xproto_table_t *proto_table;
- BUG_ON(xpd_type >= XPD_TYPE(NOMODULE));
+ BUG_ON(xpd_type >= XPD_TYPE_NOMODULE);
proto_table = xprotocol_tables[xpd_type];
if(!proto_table)
return NULL;
@@ -278,7 +284,7 @@ int xproto_register(const xproto_table_t *proto_table)
BUG_ON(!proto_table);
type = proto_table->type;
name = proto_table->name;
- if(type >= XPD_TYPE(NOMODULE)) {
+ if(type >= XPD_TYPE_NOMODULE) {
NOTICE("%s: Bad xproto type %d\n", __FUNCTION__, type);
return -EINVAL;
}
@@ -290,14 +296,20 @@ int xproto_register(const xproto_table_t *proto_table)
CHECK_XOP(card_init);
CHECK_XOP(card_remove);
CHECK_XOP(card_tick);
+ CHECK_XOP(card_zaptel_preregistration);
+ CHECK_XOP(card_zaptel_postregistration);
+#ifdef WITH_RBS
+ CHECK_XOP(card_hooksig);
+#else
+ CHECK_XOP(card_sethook);
+#endif
+ // CHECK_XOP(card_ioctl); // optional method -- call after testing
CHECK_XOP(SYNC_SOURCE);
CHECK_XOP(PCM_WRITE);
CHECK_XOP(CHAN_ENABLE);
- CHECK_XOP(CHAN_POWER);
CHECK_XOP(CHAN_CID);
CHECK_XOP(RING);
CHECK_XOP(SETHOOK);
- CHECK_XOP(LED);
CHECK_XOP(RELAY_OUT);
xprotocol_tables[type] = proto_table;
@@ -313,7 +325,7 @@ void xproto_unregister(const xproto_table_t *proto_table)
type = proto_table->type;
name = proto_table->name;
DBG("%s (%d)\n", name, type);
- if(type >= XPD_TYPE(NOMODULE)) {
+ if(type >= XPD_TYPE_NOMODULE) {
NOTICE("%s: Bad xproto type %s (%d)\n", __FUNCTION__, name, type);
return;
}
diff --git a/xpp/xproto.h b/xpp/xproto.h
index a369a6b..4fcc81a 100644
--- a/xpp/xproto.h
+++ b/xpp/xproto.h
@@ -2,7 +2,7 @@
#define XPROTO_H
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -26,31 +26,39 @@
#ifdef __KERNEL__
#include <linux/list.h>
+#include <zaptel.h>
#endif
-#define XPD_TYPE(n) XPD_TYPE_ ## n
#define PROTO_TABLE(n) n ## _protocol_table
-typedef enum xpd_type {
- XPD_TYPE(FXO) = 0x02,
- XPD_TYPE(FXS) = 0x03,
- XPD_TYPE(NOMODULE) = 0x0F,
-} xpd_type_t;
+/*
+ * 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_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 LINE_BITS (sizeof(xpp_line_t)*8)
#define PCM_CHUNKSIZE (CHANNELS_PERXPD * 8) /* samples of 8 bytes */
typedef struct xpd_addr {
- byte card_id:4;
- byte bank_num:4;
-} __attribute__((packed)) xpd_addr_t;
+ byte unit:UNIT_BITS;
+ byte subunit:SUBUNIT_BITS;
+} PACKED xpd_addr_t;
bool valid_xpd_addr(const xpd_addr_t *addr);
int xpd_addr2num(const xpd_addr_t *addr);
void xpd_set_addr(xpd_addr_t *addr, int xpd_num);
#define XPD_NUM(x) xpd_addr2num(&x)
-#define XPD_ADDR_SET(x,val) xpd_set_addr(&x, val)
#define MAX_XPACKET_DATALEN 100
#define XPROTO_NAME(card,op) card ## _ ## op
@@ -82,11 +90,12 @@ void xpd_set_addr(xpd_addr_t *addr, int xpd_num);
byte opcode; \
xpd_addr_t addr; \
__VA_ARGS__ \
- } __attribute__((packed))
+ } PACKED
#define RPACKET_CAST(p,card,op) ((RPACKET_TYPE(card,op) *)p)
#define RPACKET_FIELD(p,card,op,field) (RPACKET_CAST(p,card,op)->field)
#define RPACKET_SIZE(card,op) sizeof(RPACKET_TYPE(card,op))
+#define RPACKET_DATALEN(card,op) (RPACKET_SIZE(card,op) - sizeof(xpd_addr_t) - 1)
#define PACKET_LEN(p) \
((p)->datalen + sizeof(xpd_addr_t) + 1)
@@ -94,7 +103,7 @@ void xpd_set_addr(xpd_addr_t *addr, int xpd_num);
#define XENTRY(card,op) \
[ XPROTO_NAME(card,op) ] { \
.handler = XPROTO_HANDLER(card,op), \
- .datalen = RPACKET_SIZE(card,op), \
+ .datalen = RPACKET_DATALEN(card,op), \
.name = #op, \
.table = &PROTO_TABLE(card) \
}
@@ -103,7 +112,7 @@ void xpd_set_addr(xpd_addr_t *addr, int xpd_num);
#define XPACKET_INIT(p, card, op) \
do { \
p->content.opcode = XPROTO_NAME(card,op); \
- p->datalen = RPACKET_SIZE(card,op); \
+ p->datalen = RPACKET_DATALEN(card,op); \
} while(0)
#define XPACKET_NEW(p, xbus, card, op, to) \
@@ -112,7 +121,7 @@ void xpd_set_addr(xpd_addr_t *addr, int xpd_num);
if(!p) \
return -ENOMEM; \
XPACKET_INIT(p, card, op); \
- XPD_ADDR_SET(p->content.addr, to); \
+ xpd_set_addr(&p->content.addr, to); \
} while(0);
typedef struct xproto_entry xproto_entry_t;
@@ -124,14 +133,13 @@ typedef int (*xproto_handler_t)(
const xproto_entry_t *cmd,
xpacket_t *pack);
-const xproto_entry_t *find_xproto_entry(xpd_t *xpd, byte opcode);
-
-const xproto_table_t *get_xproto_table(xpd_type_t cardtype);
+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);
-const xproto_handler_t xproto_card_handler(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);
-const xproto_handler_t xproto_global_handler(byte opcode);
+xproto_handler_t xproto_global_handler(byte opcode);
#define CALL_XMETHOD(name, xbus, xpd, ...) \
(xpd)->xops->name(xbus, xpd, ## __VA_ARGS__ )
@@ -141,23 +149,25 @@ struct xops {
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);
+ int (*card_zaptel_preregistration)(xpd_t *xpd, bool on);
+ int (*card_zaptel_postregistration)(xpd_t *xpd, bool on);
+#ifdef WITH_RBS
+ int (*card_hooksig)(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig);
+#else
+ int (*card_sethook)(xbus_t *xbus, xpd_t *xpd, int pos, int hookstate);
+#endif
+ int (*card_ioctl)(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg);
int (*SYNC_SOURCE)(xbus_t *xbus, xpd_t *xpd, bool setit, bool is_master);
int (*PCM_WRITE)(xbus_t *xbus, xpd_t *xpd, xpp_line_t hookstate, volatile byte *buf);
int (*CHAN_ENABLE)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, bool on);
- int (*CHAN_POWER)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, bool on);
- int (*CHAN_CID)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines);
+ int (*CHAN_CID)(xbus_t *xbus, xpd_t *xpd, int pos);
int (*RING)(xbus_t *xbus, xpd_t *xpd, int pos, bool on);
- int (*SETHOOK)(xbus_t *xbus, xpd_t *xpd, xpp_line_t hook_status);
- int (*LED)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, byte which, bool on);
+ int (*SETHOOK)(xbus_t *xbus, xpd_t *xpd, int pos, bool offhook);
int (*RELAY_OUT)(xbus_t *xbus, xpd_t *xpd, byte which, bool on);
};
-const xops_t *get_xops(xpd_type_t xpd_type);
-
-#undef XMETHOD
-
struct xproto_entry {
xproto_handler_t handler;
int datalen;
@@ -166,6 +176,7 @@ struct xproto_entry {
};
struct xproto_table {
+ struct module *owner;
xproto_entry_t entries[255]; /* Indexed by opcode */
xops_t xops;
xpd_type_t type;
@@ -176,8 +187,10 @@ struct xproto_table {
#include "card_global.h"
#include "card_fxs.h"
+#include "card_fxo.h"
enum opcodes {
+ XPROTO_NAME(GLOBAL, NULL_REPLY) = 0xFE,
XPROTO_NAME(GLOBAL, DESC_REQ) = 0x04,
XPROTO_NAME(GLOBAL, DEV_DESC) = 0x05,
/**/
@@ -186,21 +199,6 @@ enum opcodes {
/**/
XPROTO_NAME(GLOBAL, SYNC_SOURCE) = 0x19,
XPROTO_NAME(GLOBAL, SYNC_REPLY) = 0x1A,
-
- XPROTO_NAME(FXS, SIG_CHANGED) = 0x06,
-/**/
- XPROTO_NAME(FXS, SLIC_WRITE) = 0x0F, /* Write to SLIC */
- XPROTO_NAME(FXS, CHAN_ENABLE) = 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, SETHOOK) = 0x0F, /* Write to SLIC */
- XPROTO_NAME(FXS, LED) = 0x0F, /* Write to SLIC */
- XPROTO_NAME(FXS, RELAY_OUT) = 0x0F, /* Write to SLIC */
- XPROTO_NAME(FXS, SLIC_INIT) = 0x0F, /* Write to SLIC */
- XPROTO_NAME(FXS, SLIC_QUERY) = 0x0F, /* Write to SLIC */
-/**/
- XPROTO_NAME(FXS, SLIC_REPLY) = 0x10,
};
@@ -210,6 +208,7 @@ struct xpacket_raw {
byte opcode;
xpd_addr_t addr;
union {
+ MEMBER(GLOBAL, NULL_REPLY);
MEMBER(GLOBAL, DESC_REQ);
MEMBER(GLOBAL, DEV_DESC);
MEMBER(GLOBAL, PCM_WRITE);
@@ -218,15 +217,21 @@ struct xpacket_raw {
MEMBER(FXS, SIG_CHANGED);
MEMBER(FXS, SLIC_REPLY);
+ MEMBER(FXS, SLIC_WRITE);
+
+ MEMBER(FXO, SIG_CHANGED);
+ MEMBER(FXO, DAA_REPLY);
+ MEMBER(FXO, DAA_WRITE);
byte data[0];
};
-} __attribute__((packed));
+} PACKED;
struct xpacket {
xpacket_raw_t content;
- size_t datalen;
+ int datalen;
struct list_head list;
+ void *packet_priv;
};
void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg);
diff --git a/xpp/zap_debug.c b/xpp/zap_debug.c
index a5d7915..f20e14d 100644
--- a/xpp/zap_debug.c
+++ b/xpp/zap_debug.c
@@ -1,6 +1,6 @@
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -28,7 +28,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
-#include <zaptel.h>
+#include "zaptel.h"
#include "zap_debug.h"
static const char rcsid[] = "$Id$";
@@ -63,74 +63,5 @@ void dump_poll(int print_dbg, const char *msg, int poll)
}
}
-#define E_(x) [ x ] = { .value = x, .name = #x, }
-static struct {
- int value;
- char *name;
-} zt_event_names[] = {
- E_(ZT_EVENT_NONE),
- E_(ZT_EVENT_ONHOOK),
- E_(ZT_EVENT_RINGOFFHOOK),
- E_(ZT_EVENT_WINKFLASH),
- E_(ZT_EVENT_ALARM),
- E_(ZT_EVENT_NOALARM),
- E_(ZT_EVENT_ABORT),
- E_(ZT_EVENT_OVERRUN),
- E_(ZT_EVENT_BADFCS),
- E_(ZT_EVENT_DIALCOMPLETE),
- E_(ZT_EVENT_RINGERON),
- E_(ZT_EVENT_RINGEROFF),
- E_(ZT_EVENT_HOOKCOMPLETE),
- E_(ZT_EVENT_BITSCHANGED),
- E_(ZT_EVENT_PULSE_START),
- E_(ZT_EVENT_TIMER_EXPIRED),
- E_(ZT_EVENT_TIMER_PING),
- E_(ZT_EVENT_POLARITY)
-};
-#undef E_
-
-char *event2str(int event)
-{
- BUG_ON(event > ARRAY_SIZE(zt_event_names));
- return zt_event_names[event].name;
-}
-
-#define S_(x) [ x ] = { .value = x, .name = #x, }
-static struct {
- int value;
- char *name;
-} zt_sig_types[] = {
- S_(ZT_SIG_NONE),
- S_(ZT_SIG_FXSLS),
- S_(ZT_SIG_FXSGS),
- S_(ZT_SIG_FXSKS),
- S_(ZT_SIG_FXOLS),
- S_(ZT_SIG_FXOGS),
- S_(ZT_SIG_FXOKS),
- S_(ZT_SIG_EM),
- S_(ZT_SIG_CLEAR),
- S_(ZT_SIG_HDLCRAW),
- S_(ZT_SIG_HDLCFCS),
- S_(ZT_SIG_HDLCNET),
- S_(ZT_SIG_SLAVE),
- S_(ZT_SIG_SF),
- S_(ZT_SIG_CAS),
- S_(ZT_SIG_DACS),
- S_(ZT_SIG_EM_E1),
- S_(ZT_SIG_DACS_RBS)
-};
-#undef S_
-
-void dump_sigtype(int print_dbg, const char *msg, int sigtype)
-{
- int i;
-
- for(i = 0; i < ARRAY_SIZE(zt_sig_types); i++) {
- if(sigtype == zt_sig_types[i].value)
- DBG("%s: %s\n", msg, zt_sig_types[i].name);
- }
-}
EXPORT_SYMBOL(dump_poll);
-EXPORT_SYMBOL(event2str);
-EXPORT_SYMBOL(dump_sigtype);
diff --git a/xpp/zap_debug.h b/xpp/zap_debug.h
index 3f4651a..6d8ac36 100644
--- a/xpp/zap_debug.h
+++ b/xpp/zap_debug.h
@@ -1,16 +1,125 @@
#ifndef ZAP_DEBUG_H
#define ZAP_DEBUG_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/* Debugging Macros */
#define DBG(fmt, ...) \
- ((print_dbg) && printk(KERN_DEBUG "DBG-%s: %s: " fmt, \
- THIS_MODULE->name, __FUNCTION__, ## __VA_ARGS__))
+ ((void)((print_dbg) && printk(KERN_DEBUG "DBG-%s: %s: " fmt, \
+ THIS_MODULE->name, __FUNCTION__, ## __VA_ARGS__)))
#define INFO(fmt, ...) printk(KERN_INFO "INFO-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
#define NOTICE(fmt, ...) printk(KERN_NOTICE "NOTICE-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
+#define WARN(fmt, ...) printk(KERN_WARNING "WARN-%s: %s: " fmt, THIS_MODULE->name, __FUNCTION__, ## __VA_ARGS__)
#define ERR(fmt, ...) printk(KERN_ERR "ERR-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
-
void dump_poll(int print_dbg, const char *msg, int poll);
-char *event2str(int event);
-void dump_sigtype(int print_dbg, const char *msg, int sigtype);
+
+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";
+}
#endif /* ZAP_DEBUG_H */