[zaptel-commits] tzafrir: branch 1.4 r4266 - in /branches/1.4: ./ kernel/xpp/ kernel/xpp/firmw...

SVN commits to the Zaptel project zaptel-commits at lists.digium.com
Tue May 13 16:08:11 CDT 2008


Author: tzafrir
Date: Tue May 13 16:08:09 2008
New Revision: 4266

URL: http://svn.digium.com/view/zaptel?view=rev&rev=4266
Log:
xpp r5723: Includes, among others:
* New firmware protocol version: 3.0 .
* New numbers for the device types: (e.g. in card_init* scripts)
  - FXS: 1 (was: 3)
  - FXO: 2 (was: 4)
  - BRI: 3 (was: 6 for TE, 7 for NT)
  - PRI: 4 (was: 9)
* Init scripts of FXS and FXO modules are now written in Perl as well
  (be sure to have File::Basename, e.g: perl-modules in Debian).
* calibrate_slics merged into init_card_1_30 .
* Module parameter print_dbg replaced with debug . Same meaning.
* init_fxo_modes removed: content moved into init_card_2_30, verified
  at build time.
* Code tested with sparse. Most warnings were fixed.
* Set ZT_SIG_DACS for the bchans in the PRI and BRI modules to not get
  ignored by ztscan.
* Handle null config_desc we get from some crazy USB controllers.
* genzaptelconf: Fix reporting of empty slots in list mode.
* xpp_blink can now blink a single analog port.
* "slics" has been renamed "chipregs".
* Fixed a small typo in fpga_load(8).
* Fixed bashism in xpp_fxloader.

Merged revisions 4264 via svnmerge from 
http://svn.digium.com/svn/zaptel/branches/1.2

Added:
    branches/1.4/kernel/xpp/init_card_1_30
      - copied unchanged from r4264, branches/1.2/xpp/init_card_1_30
    branches/1.4/kernel/xpp/init_card_2_30
      - copied unchanged from r4264, branches/1.2/xpp/init_card_2_30
    branches/1.4/kernel/xpp/init_card_3_30
      - copied unchanged from r4264, branches/1.2/xpp/init_card_3_30
    branches/1.4/kernel/xpp/init_card_4_30
      - copied unchanged from r4264, branches/1.2/xpp/init_card_4_30
Removed:
    branches/1.4/kernel/xpp/init_card_3_29
    branches/1.4/kernel/xpp/init_card_4_29
    branches/1.4/kernel/xpp/init_card_6_29
    branches/1.4/kernel/xpp/init_card_7_29
    branches/1.4/kernel/xpp/init_card_9_29
Modified:
    branches/1.4/   (props changed)
    branches/1.4/kernel/xpp/.version
    branches/1.4/kernel/xpp/Changelog_xpp
    branches/1.4/kernel/xpp/README.Astribank
    branches/1.4/kernel/xpp/card_bri.c
    branches/1.4/kernel/xpp/card_fxo.c
    branches/1.4/kernel/xpp/card_fxo.h
    branches/1.4/kernel/xpp/card_fxs.c
    branches/1.4/kernel/xpp/card_fxs.h
    branches/1.4/kernel/xpp/card_global.c
    branches/1.4/kernel/xpp/card_global.h
    branches/1.4/kernel/xpp/card_pri.c
    branches/1.4/kernel/xpp/firmwares/FPGA_1141.hex
    branches/1.4/kernel/xpp/firmwares/FPGA_1151.hex
    branches/1.4/kernel/xpp/firmwares/FPGA_FXS.hex
    branches/1.4/kernel/xpp/utils/Makefile
    branches/1.4/kernel/xpp/utils/fpga_load.8
    branches/1.4/kernel/xpp/utils/fpga_load.c
    branches/1.4/kernel/xpp/utils/genzaptelconf
    branches/1.4/kernel/xpp/utils/print_modes.c
    branches/1.4/kernel/xpp/utils/xpp_blink
    branches/1.4/kernel/xpp/utils/xpp_fxloader
    branches/1.4/kernel/xpp/utils/xpp_modprobe
    branches/1.4/kernel/xpp/utils/zconf/Zaptel/Chans.pm
    branches/1.4/kernel/xpp/utils/zconf/Zaptel/Xpp/Line.pm
    branches/1.4/kernel/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm
    branches/1.4/kernel/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm
    branches/1.4/kernel/xpp/xbus-core.c
    branches/1.4/kernel/xpp/xbus-core.h
    branches/1.4/kernel/xpp/xbus-pcm.c
    branches/1.4/kernel/xpp/xbus-sysfs.c
    branches/1.4/kernel/xpp/xdefs.h
    branches/1.4/kernel/xpp/xframe_queue.c
    branches/1.4/kernel/xpp/xpd.h
    branches/1.4/kernel/xpp/xpp_usb.c
    branches/1.4/kernel/xpp/xpp_zap.c
    branches/1.4/kernel/xpp/xpp_zap.h
    branches/1.4/kernel/xpp/xproto.c
    branches/1.4/kernel/xpp/xproto.h
    branches/1.4/kernel/xpp/zap_debug.c
    branches/1.4/kernel/xpp/zap_debug.h

Propchange: branches/1.4/
------------------------------------------------------------------------------
Binary property 'branch-1.2-merged' - no diff available.

Modified: branches/1.4/kernel/xpp/.version
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/xpp/.version?view=diff&rev=4266&r1=4265&r2=4266
==============================================================================
--- branches/1.4/kernel/xpp/.version (original)
+++ branches/1.4/kernel/xpp/.version Tue May 13 16:08:09 2008
@@ -1,1 +1,1 @@
-trunk-r5566
+trunk-r5723

Modified: branches/1.4/kernel/xpp/Changelog_xpp
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/xpp/Changelog_xpp?view=diff&rev=4266&r1=4265&r2=4266
==============================================================================
--- branches/1.4/kernel/xpp/Changelog_xpp (original)
+++ branches/1.4/kernel/xpp/Changelog_xpp Tue May 13 16:08:09 2008
@@ -1,3 +1,27 @@
+Tue, 13 May 2008 Oron Peled <oron at actcom.co.il> - xpp.r5723
+  * [A temporary changelog. More to come]
+  * New firmware protocol version: 3.0 .
+  * New numbers for the device types: (e.g. in card_init* scripts)
+    - FXS: 1 (was: 3)
+    - FXO: 2 (was: 4)
+    - BRI: 3 (was: 6 for TE, 7 for NT)
+    - PRI: 4 (was: 9)
+  * Init scripts of FXS and FXO modules are now written in Perl as well
+    (be sure to have File::Basename, e.g: perl-modules in Debian).
+  * calibrate_slics merged into init_card_1_30 .
+  * Module parameter print_dbg replaced with debug . Same meaning.
+  * init_fxo_modes removed: content moved into init_card_2_30, verified
+    at build time.
+  * Code tested with sparse. Most warnings were fixed.
+  * Set ZT_SIG_DACS for the bchans in the PRI and BRI modules to not get
+    ignored by ztscan.
+  * Handle null config_desc we get from some crazy USB controllers.
+  * genzaptelconf: Fix reporting of empty slots in list mode.
+  * xpp_blink can now blink a single analog port.
+  * "slics" has been renamed "chipregs".
+  * Fixed a small typo in fpga_load(8).
+  * Fixed bashism in xpp_fxloader.
+
 Thu, 20 Mar 2008 Oron Peled <oron at actcom.co.il> - xpp.r5566
   * Build:
     - Zaptel >= 1.4.9 is migrating to storing kernel stuff in zaptel/kernel/*

Modified: branches/1.4/kernel/xpp/README.Astribank
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/xpp/README.Astribank?view=diff&rev=4266&r1=4265&r2=4266
==============================================================================
--- branches/1.4/kernel/xpp/README.Astribank (original)
+++ branches/1.4/kernel/xpp/README.Astribank Tue May 13 16:08:09 2008
@@ -588,6 +588,62 @@
 once a new call needs to be made.
 
 
+Both default and sysconfig Exist
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.Symptoms:
+The firmware fails to load. Manually running xpp_fxloader gives:
+
+  Both '/etc/default/zaptel' and '/etc/sysconfig/zaptel' exist
+
+Alternatively: an initialization script fails and gives the error
+
+  An '/etc/default/zaptel' collides with 'etc/sysconfig/zaptel'
+
+.Cause:
+/etc/default/<service name> is the place used in Debian-based 
+systems for initialization scripts. /etc/sysconfig/<service name> is
+used in Redhat and similar for the same purpose. For historical reasons
+many of our programs read configuration from there: either from
+/etc/default/zaptel or from /etc/sysconfig/zaptel .
+
+The problem is what to do if both of those exist. Selecting an arbitrary
+one can lead to unexpected results. Likewise sourcing both of them.
+Therefore we prefer to fail in a noisy and expected way. In the future
+we will probably me to reading configuration from a file under /etc/zaptel .
+
+.Fix:
+Remove one of those two. There should be no reason to have both on the
+same system.
+
+
+Astribank not initialized: Premature packet end
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.Symptoms:
+After upgrading to Zaptel 1.4.12 / 1.2.25 the initialization of the
+Astribank times out. In the logs you see:
+
+  kernel: NOTICE-xpp: XBUS-00(00): FIRMWARE: ERROR_CODE CODE = 0x3 (Premature packet end) 
+
+.Cause:
+When an Astribank is detected, the driver asks it what is its version
+and what components it has. Normally if the version of the firmware and
+of the driver does not match the driver gives an ugly message and fails
+the initialization.
+
+However in the change of the protocol between versions 2.9 (29) and 3.0
+(30), the response that the new driver recieves from a device with the
+old version is now considered to be an illegal packet and gets
+discarded. As a result, the Astribank waits till time-out for the
+initilization to end.
+
+.Fix:
+Reset the firmware of the Astribank by either:
+
+  /usr/share/zaptel/xpp_fxloader reset
+
+or disconnecting it from the power and reconnecting it.
+
+
 Reference
 ---------
 LEDs Indication
@@ -1254,7 +1310,7 @@
   separate tasklets. This should probably help on higher-end systems with
   multiple Astribanks.
 
-print_dbg (all modules)::
+debug (all modules)::
   It will make the driver to print tons of debugging messages. You can 
   set/unset the parameter at run-time.
 
@@ -1274,7 +1330,7 @@
 
   For example,
 
-    echo 33 >/sys/modules/xpp/parameters/print_dbg 
+    echo 33 >/sys/modules/xpp/parameters/debug 
 
   forces module xpp to print general debugging messages (1) and procfs
   debugging messages (32).

Modified: branches/1.4/kernel/xpp/card_bri.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/xpp/card_bri.c?view=diff&rev=4266&r1=4265&r2=4266
==============================================================================
--- branches/1.4/kernel/xpp/card_bri.c (original)
+++ branches/1.4/kernel/xpp/card_bri.c Tue May 13 16:08:09 2008
@@ -31,7 +31,6 @@
 #include "xpp_zap.h"
 #include "card_bri.h"
 #include "zap_debug.h"
-#include "xpd.h"
 #include "xbus-core.h"
 
 static const char rcsid[] = "$Id$";
@@ -40,9 +39,9 @@
 #error CONFIG_ZAPATA_BRI_DCHANS is not defined
 #endif
 
-DEF_PARM(int, print_dbg, 0, 0644, "Print DBG statements");	/* must be before zap_debug.h */
-DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in milliseconds (0 - disable)");
-DEF_PARM_BOOL(nt_keepalive, 1, 0644, "Force BRI_NT to keep trying connection");
+static DEF_PARM(int, debug, 0, 0644, "Print DBG statements");	/* must be before zap_debug.h */
+static DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in milliseconds (0 - disable)");
+static DEF_PARM_BOOL(nt_keepalive, 1, 0644, "Force BRI_NT to keep trying connection");
 
 enum xhfc_states {
 	ST_RESET		= 0,	/* G/F0	*/
@@ -61,7 +60,7 @@
 	ST_NT_DEACTIVTING	= 4,	/* G4	*/
 };
 
-static const char *xhfc_state_name(xpd_type_t xpd_type, enum xhfc_states state)
+static const char *xhfc_state_name(bool is_nt, enum xhfc_states state)
 {
 	const char	*p;
 
@@ -84,16 +83,16 @@
 		_E(NT_DEACTIVTING),
 	};
 #undef	_E
-	if(xpd_type == XPD_TYPE_BRI_TE) {
+	if(is_nt) {
+		if ((state < ST_RESET) || (state > ST_NT_DEACTIVTING))
+			p = "NT ???";
+		else
+			p = nt_names[state];
+	} else {
 		if ((state < ST_RESET) || (state > ST_TE_LOST_FRAMING))
 			p = "TE ???";
 		else
 			p = te_names[state];
-	} else {
-		if ((state < ST_RESET) || (state > ST_NT_DEACTIVTING))
-			p = "NT ???";
-		else
-			p = nt_names[state];
 	}
 	return p;
 }
@@ -106,9 +105,8 @@
 
 #define HFC_L1_ACTIVATING	1
 #define HFC_L1_ACTIVATED	2
-#define	TIMER_T1_MAX		2500
+#define	HFC_TIMER_T1		2500
 #define	HFC_TIMER_T3		8000	/* 8s activation timer T3 */
-#define	HFC_TIMER_T4		500	/* 500ms deactivation timer T4 */
 #define	HFC_TIMER_OFF		-1	/* timer disabled */
 
 #define	A_SU_WR_STA		0x30	/* ST/Up state machine register		*/
@@ -145,9 +143,10 @@
 					ZT_SIG_CAS	| \
 					ZT_SIG_SF	  \
 				)
-#define	BRI_BCHAN_SIGCAP	ZT_SIG_CLEAR
-
-#define	IS_NT(xpd)		((xpd)->type == XPD_TYPE_BRI_NT)
+#define	BRI_BCHAN_SIGCAP	(ZT_SIG_CLEAR | ZT_SIG_DACS)
+
+#define	IS_NT(xpd)		((xpd)->direction == TO_PHONE)
+#define	BRI_PORT(xpd)		((xpd)->addr.subunit)
 
 /* shift in PCM highway */
 #define	SUBUNIT_PCM_SHIFT	4
@@ -159,8 +158,6 @@
 static bool bri_packet_is_valid(xpacket_t *pack);
 static void bri_packet_dump(const char *msg, xpacket_t *pack);
 static int proc_bri_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
-static int proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data);
-static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
 static int bri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc);
 static int bri_chanconfig(struct zt_chan *chan, int sigtype);
 static int bri_startup(struct zt_span *span);
@@ -168,8 +165,6 @@
 
 #define	PROC_REGISTER_FNAME	"slics"
 #define	PROC_BRI_INFO_FNAME	"bri_info"
-
-#define	VALID_CHIPSEL(x)	((x) == 0)
 
 enum led_state {
 	BRI_LED_OFF		= 0x0,
@@ -204,13 +199,11 @@
 #define	DCHAN_BUFSIZE	MAX_DFRAME_LEN_L1
 
 struct BRI_priv_data {
-	struct proc_dir_entry		*regfile;
 	struct proc_dir_entry		*bri_info;
 	su_rd_sta_t			state_register;
 	bool				initialized;
-	int				t1; /* timer 1 for NT deactivation */
-	int				t3; /* timer 3 for activation */
-	int				t4; /* timer 4 for deactivation */
+	int				t1;	/* timer 1 for NT deactivation */
+	int				t3;	/* timer 3 for TE activation */
 	ulong				l1_flags;
 	bool				reg30_good;
 	uint				reg30_ticks;
@@ -225,8 +218,6 @@
 	byte				dchan_tbuf[DCHAN_BUFSIZE];
 	bool				txframe_begin;
 
-	reg_cmd_t			requested_reply;
-	reg_cmd_t			last_reply;
 	uint				tick_counter;
 	uint				poll_counter;
 	uint				dchan_tx_counter;
@@ -239,8 +230,7 @@
 	enum led_state			ledstate[NUM_LEDS];
 };
 
-static xproto_table_t	PROTO_TABLE(BRI_NT);
-static xproto_table_t	PROTO_TABLE(BRI_TE);
+static xproto_table_t	PROTO_TABLE(BRI);
 
 
 DEF_RPACKET_DATA(BRI, SET_LED,	/* Set one of the LED's */
@@ -300,17 +290,13 @@
 	dump_hex_buf(xpd, msgbuf, buf, len);
 }
 
-static void layer1_state(xpd_t *xpd, bool up)
-{
-	struct BRI_priv_data	*priv;
-
-	BUG_ON(!xpd);
-	priv = xpd->priv;
-	BUG_ON(!priv);
-	if(priv->layer1_up == up)
-		return;
-	priv->layer1_up = up;
-	XPD_DBG(SIGNAL, xpd, "STATE CHANGE: Layer1 %s\n", (up)?"UP":"DOWN");
+static void set_bri_timer(xpd_t *xpd, const char *name, int *bri_timer, int value)
+{
+	if(value == HFC_TIMER_OFF)
+		XPD_DBG(SIGNAL, xpd, "Timer %s DISABLE\n", name);
+	else
+		XPD_DBG(SIGNAL, xpd, "Timer %s: set to %d\n", name, value);
+	*bri_timer = value;
 }
 
 static void dchan_state(xpd_t *xpd, bool up)
@@ -333,42 +319,113 @@
 	}
 }
 
-static void xpd_activation(xpd_t *xpd, bool on)
+static void layer1_state(xpd_t *xpd, bool up)
+{
+	struct BRI_priv_data	*priv;
+
+	BUG_ON(!xpd);
+	priv = xpd->priv;
+	BUG_ON(!priv);
+	if(priv->layer1_up == up)
+		return;
+	priv->layer1_up = up;
+	XPD_DBG(SIGNAL, xpd, "STATE CHANGE: Layer1 %s\n", (up)?"UP":"DOWN");
+	if(!up)
+		dchan_state(xpd, 0);
+}
+
+static void te_activation(xpd_t *xpd, bool on)
 {
 	struct BRI_priv_data	*priv;
 	xbus_t			*xbus;
+	byte			curr_state;
 
 	BUG_ON(!xpd);
 	priv = xpd->priv;
 	BUG_ON(!priv);
+	curr_state = priv->state_register.bits.v_su_sta;
 	xbus = xpd->xbus;
 	XPD_DBG(SIGNAL, xpd, "%s\n", (on)?"ON":"OFF");
-	switch(xpd->type) {
-		case XPD_TYPE_BRI_TE:
-			if(on) {
-				XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_TE\n");
+	if(on) {
+		if(curr_state == ST_TE_DEACTIVATED) {
+			XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_TE\n");
+			set_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
+			write_state_register(xpd, STA_ACTIVATE);
+			set_bri_timer(xpd, "T3", &priv->t3, HFC_TIMER_T3);
+		} else {
+			XPD_DBG(SIGNAL, xpd,
+				"HFC_L1_ACTIVATE_TE (state %d, ignored)\n",
+				curr_state);
+		}
+	} else {	/* happen only because of T3 expiry */
+		switch (curr_state) {
+			case ST_TE_DEACTIVATED:		/* F3	*/
+			case ST_TE_SYNCED:		/* F6	*/
+			case ST_TE_ACTIVATED:		/* F7	*/
+				XPD_DBG(SIGNAL, xpd,
+					"HFC_L1_FORCE_DEACTIVATE_TE (state %d, ignored)\n",
+					curr_state);
+				break;
+			case ST_TE_SIGWAIT:		/* F4	*/
+			case ST_TE_IDENT:		/* F5	*/
+			case ST_TE_LOST_FRAMING:	/* F8	*/
+				XPD_DBG(SIGNAL, xpd, "HFC_L1_FORCE_DEACTIVATE_TE\n");
+				write_state_register(xpd, STA_DEACTIVATE);
+				break;
+			default:
+				XPD_NOTICE(xpd, "Bad TE state: %d\n", curr_state);
+				break;
+		}
+	}
+}
+
+static void nt_activation(xpd_t *xpd, bool on)
+{
+	struct BRI_priv_data	*priv;
+	xbus_t			*xbus;
+	byte			curr_state;
+
+	BUG_ON(!xpd);
+	priv = xpd->priv;
+	BUG_ON(!priv);
+	curr_state = priv->state_register.bits.v_su_sta;
+	xbus = xpd->xbus;
+	XPD_DBG(SIGNAL, xpd, "%s\n", (on)?"ON":"OFF");
+	if(on) {
+		switch(curr_state) {
+			case ST_RESET:			/* F/G 0 */
+			case ST_NT_DEACTIVATED:		/* G1 */
+			case ST_NT_DEACTIVTING:		/* G4 */
+				XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_NT\n");
+				set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_T1);
 				set_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
 				write_state_register(xpd, STA_ACTIVATE);
-				priv->t3 = HFC_TIMER_T3;
-			} else {
-				XPD_DBG(SIGNAL, xpd, "HFC_L1_FORCE_DEACTIVATE_TE\n");
-				write_state_register(xpd, STA_DEACTIVATE);
-			}
-			break;
-		case XPD_TYPE_BRI_NT:
-			if(on) {
-				XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_NT\n");
-				priv->t1 = TIMER_T1_MAX;
-				set_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
-				write_state_register(xpd, STA_ACTIVATE | V_SU_SET_G2_G3);
-			} else {
+				break;
+			case ST_NT_ACTIVATING:		/* G2 */
+			case ST_NT_ACTIVATED:		/* G3 */
+				XPD_DBG(SIGNAL, xpd,
+						"HFC_L1_ACTIVATE_NT (in state %d, ignored)\n",
+						curr_state);
+				break;
+		}
+	} else {
+		switch(curr_state) {
+			case ST_RESET:			/* F/G 0 */
+			case ST_NT_DEACTIVATED:		/* G1 */
+			case ST_NT_DEACTIVTING:		/* G4 */
+				XPD_DBG(SIGNAL, xpd,
+						"HFC_L1_DEACTIVATE_NT (in state %d, ignored)\n",
+						curr_state);
+				break;
+			case ST_NT_ACTIVATING:		/* G2 */
+			case ST_NT_ACTIVATED:		/* G3 */
 				XPD_DBG(SIGNAL, xpd, "HFC_L1_DEACTIVATE_NT\n");
 				write_state_register(xpd, STA_DEACTIVATE);
-			}
-			break;
-		default:
-			XPD_ERR(xpd, "%s: Bad xpd type %d\n", __FUNCTION__, xpd->type);
-			BUG();
+				break;
+			default:
+				XPD_NOTICE(xpd, "Bad NT state: %d\n", curr_state);
+				break;
+		}
 	}
 }
 
@@ -445,7 +502,7 @@
 		ret = -EPROTO;
 		goto drop;
 	}
-	if(print_dbg)
+	if(debug)
 		dump_dchan_packet(xpd, 0, dchan_buf, idx /* - 3 */);	/* Print checksum? */
 	/* 
 	 * Tell Zaptel that we received idx-1 bytes. They include the data and a 2-byte checksum.
@@ -462,47 +519,6 @@
 	return ret;
 }
 
-static int send_bri_multibyte(xpd_t *xpd, byte *buf, int len, bool eoftx)
-{
-	xbus_t		*xbus = xpd->xbus;
-	xframe_t	*xframe;
-	xpacket_t	*pack;
-	reg_cmd_t	*reg_cmd;
-	int		ret;
-
-	BUG_ON(len < 0);
-	/*
-	 * Zero length multibyte is legal and has special meaning for the
-	 * firmware:
-	 *   eoftx==1: Start sending us D-channel packets.
-	 *   eoftx==0: Stop sending us D-channel packets.
-	 */
-	if(len > MULTIBYTE_MAX_LEN) {
-		XPD_ERR(xpd, "%s: len=%d is too long. dropping.\n", __FUNCTION__, len);
-		return -EINVAL;
-	}
-	XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->xbus_idx);
-	reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd);
-	reg_cmd->bytes = len;
-	reg_cmd->eoframe = eoftx;
-	reg_cmd->multibyte = 1;
-	if(len > 0) {
-		memcpy(REG_XDATA(reg_cmd), (byte *)buf, len);
-	} else {
-		XPD_DBG(REGS, xpd, "Magic Packet (eoftx=%d)\n", eoftx);
-	}
-#ifdef XPP_DEBUGFS
-	xbus_log(xbus, xpd, 1, reg_cmd, sizeof(reg_cmd_t));	/* 1 = TX */
-#else
-	if(print_dbg)
-		dump_xframe("SEND_BRI_MULTI", xbus, xframe, print_dbg);
-#endif
-	ret = send_cmd_frame(xbus, xframe);
-	if(ret < 0)
-		XPD_NOTICE(xpd, "%s: failed sending xframe\n", __FUNCTION__);
-	return ret;
-}
-
 /*
  * D-Chan transmit
  */
@@ -516,29 +532,6 @@
 
 	priv = xpd->priv;
 	BUG_ON(!priv);
-	if(!IS_NT(xpd)) {
-		static int	rate_limit;
-
-		if (priv->t3 > HFC_TIMER_OFF) {
-			/* timer expired ? */
-			if (--priv->t3 == 0) {
-				if ((rate_limit % 1003) >= 5)
-					XPD_DBG(SIGNAL, xpd, "T3 expired\n");
-				priv->t3 = HFC_TIMER_OFF;
-				clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
-				xpd_activation(xpd, 0);		/* Deactivate TE */
-			}
-		}
-		if (priv->t4 > HFC_TIMER_OFF) {
-			/* timer expired ? */
-			if (--priv->t4 == 0) {
-				if ((rate_limit % 1003) >= 5)
-					XPD_DBG(SIGNAL, xpd, "T4 expired\n");
-				priv->t4 = HFC_TIMER_OFF;
-			}
-		}
-		rate_limit++;
-	}
 	if(!SPAN_REGISTERED(xpd) || !(xpd->span.flags & ZT_FLAG_RUNNING))
 		return 0;
 	dchan = &xpd->chans[2];
@@ -556,16 +549,20 @@
 	}
 	if(!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags) && !test_bit(HFC_L1_ACTIVATING, &priv->l1_flags)) {
 		XPD_DBG(SIGNAL, xpd, "Want to transmit: Kick D-Channel transmiter\n");
-		xpd_activation(xpd, 1);
+		if(xpd->direction == TO_PSTN)
+			te_activation(xpd, 1);
+		else
+			nt_activation(xpd, 1);
 		return 0;
 	}
-	if(print_dbg)
+	if(debug)
 		dump_dchan_packet(xpd, 1, priv->dchan_tbuf, len);
 	if(eoframe)
 		priv->txframe_begin = 1;
 	else
 		priv->txframe_begin = 0;
-	ret = send_bri_multibyte(xpd, priv->dchan_tbuf, len, eoframe);
+	ret = send_multibyte_request(xpd->xbus, xpd->addr.unit, xpd->addr.subunit,
+			eoframe, priv->dchan_tbuf, len);
 	if(ret < 0)
 		XPD_NOTICE(xpd, "%s: failed sending xframe\n", __FUNCTION__);
 	if(eoframe)
@@ -576,7 +573,44 @@
 
 /*---------------- BRI: Methods -------------------------------------------*/
 
-static xpd_t *BRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, byte revision)
+static void bri_proc_remove(xbus_t *xbus, xpd_t *xpd)
+{
+	struct BRI_priv_data	*priv;
+
+	BUG_ON(!xpd);
+	priv = xpd->priv;
+	XPD_DBG(PROC, xpd, "\n");
+#ifdef	CONFIG_PROC_FS
+	if(priv->bri_info) {
+		XPD_DBG(PROC, xpd, "Removing '%s'\n", PROC_BRI_INFO_FNAME);
+		remove_proc_entry(PROC_BRI_INFO_FNAME, xpd->proc_xpd_dir);
+	}
+#endif
+}
+
+static int bri_proc_create(xbus_t *xbus, xpd_t *xpd)
+{
+	struct BRI_priv_data	*priv;
+
+	BUG_ON(!xpd);
+	priv = xpd->priv;
+	XPD_DBG(PROC, xpd, "\n");
+#ifdef	CONFIG_PROC_FS
+	XPD_DBG(PROC, xpd, "Creating '%s'\n", PROC_BRI_INFO_FNAME);
+	priv->bri_info = create_proc_read_entry(PROC_BRI_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_bri_info_read, xpd);
+	if(!priv->bri_info) {
+		XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_BRI_INFO_FNAME);
+		goto err;
+	}
+	priv->bri_info->owner = THIS_MODULE;
+#endif
+	return 0;
+err:
+	bri_proc_remove(xbus, xpd);
+	return -EINVAL;
+}
+
+static xpd_t *BRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, bool to_phone)
 {
 	xpd_t		*xpd = NULL;
 	int		channels = min(3, CHANNELS_PERXPD);
@@ -585,71 +619,29 @@
 	xpd = xpd_alloc(sizeof(struct BRI_priv_data), proto_table, channels);
 	if(!xpd)
 		return NULL;
-	xpd->direction = (proto_table == &PROTO_TABLE(BRI_NT)) ? TO_PHONE : TO_PSTN;
-	xpd->revision = revision;
-	xpd->type_name = proto_table->name;
+	xpd->direction = (to_phone) ? TO_PHONE : TO_PSTN;
+	xpd->type_name = (to_phone) ? "BRI_NT" : "BRI_TE";
+	if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0)
+		goto err;
+	if(bri_proc_create(xbus, xpd) < 0)
+		goto err;
 	return xpd;
-}
-
-static void clean_proc(xbus_t *xbus, xpd_t *xpd)
-{
-	struct BRI_priv_data	*priv;
-
-	BUG_ON(!xpd);
-	priv = xpd->priv;
-	XPD_DBG(PROC, xpd, "\n");
-#ifdef	CONFIG_PROC_FS
-	if(priv->regfile) {
-		XPD_DBG(PROC, xpd, "Removing registers file\n");
-		priv->regfile->data = NULL;
-		remove_proc_entry(PROC_REGISTER_FNAME, xpd->proc_xpd_dir);
-	}
-	if(priv->bri_info) {
-		XPD_DBG(PROC, xpd, "Removing xpd BRI_INFO file\n");
-		remove_proc_entry(PROC_BRI_INFO_FNAME, xpd->proc_xpd_dir);
-	}
-#endif
+err:
+	xpd_free(xpd);
+	return NULL;
 }
 
 static int BRI_card_init(xbus_t *xbus, xpd_t *xpd)
 {
 	struct BRI_priv_data	*priv;
-	int			ret = 0;
 
 	BUG_ON(!xpd);
 	XPD_DBG(GENERAL, xpd, "\n");
 	priv = xpd->priv;
-#ifdef	CONFIG_PROC_FS
-	XPD_DBG(PROC, xpd, "Creating BRI_INFO file\n");
-	priv->bri_info = create_proc_read_entry(PROC_BRI_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_bri_info_read, xpd);
-	if(!priv->bri_info) {
-		XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_BRI_INFO_FNAME);
-		ret = -ENOENT;
-		goto err;
-	}
-	priv->bri_info->owner = THIS_MODULE;
-	XPD_DBG(PROC, xpd, "Creating registers file\n");
-	priv->regfile = create_proc_entry(PROC_REGISTER_FNAME, 0644, xpd->proc_xpd_dir);
-	if(!priv->regfile) {
-		XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_REGISTER_FNAME);
-		goto err;
-	}
-	priv->regfile->owner = THIS_MODULE;
-	priv->regfile->write_proc = proc_xpd_register_write;
-	priv->regfile->read_proc = proc_xpd_register_read;
-	priv->regfile->data = xpd;
-#endif
-	priv->t1 = HFC_TIMER_OFF;
-	ret = run_initialize_registers(xpd);
-	if(ret < 0)
-		goto err;
-	XPD_DBG(PROC, xpd, "done\n");
+	set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF);
+	write_state_register(xpd, 0);	/* Enable L1 state machine */
 	priv->initialized = 1;
 	return 0;
-err:
-	clean_proc(xbus, xpd);
-	XPD_ERR(xpd, "Failed initializing registers (%d)\n", ret);
-	return ret;
 }
 
 static int BRI_card_remove(xbus_t *xbus, xpd_t *xpd)
@@ -659,7 +651,7 @@
 	BUG_ON(!xpd);
 	priv = xpd->priv;
 	XPD_DBG(GENERAL, xpd, "\n");
-	clean_proc(xbus, xpd);
+	bri_proc_remove(xbus, xpd);
 	return 0;
 }
 
@@ -692,7 +684,7 @@
 
 		XPD_DBG(GENERAL, xpd, "setting BRI channel %d\n", i);
 		snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%02d/%1d%1d/%d",
-				xpd->xproto->name, xbus->num,
+				xpd->type_name, xbus->num,
 				xpd->addr.unit, xpd->addr.subunit, i);
 		cur_chan->chanpos = i + 1;
 		cur_chan->pvt = xpd;
@@ -832,6 +824,42 @@
 	}
 }
 
+static void handle_bri_timers(xpd_t *xpd)
+{
+	struct BRI_priv_data	*priv;
+
+	BUG_ON(!xpd);
+	priv = xpd->priv;
+	BUG_ON(!priv);
+	if(IS_NT(xpd)) {
+		if (priv->t1 > HFC_TIMER_OFF) {
+			if (--priv->t1 == 0) {
+				set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF);
+				if(!nt_keepalive) {
+					if(priv->state_register.bits.v_su_sta == ST_NT_ACTIVATING) {	/* G2 */
+						XPD_DBG(SIGNAL, xpd, "T1 Expired. Deactivate NT\n");
+						clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
+						nt_activation(xpd, 0);	/* Deactivate NT */
+					} else
+						XPD_DBG(SIGNAL, xpd,
+							"T1 Expired. (state %d, ignored)\n",
+							priv->state_register.bits.v_su_sta);
+				}
+			}
+		}
+	} else {
+		if (priv->t3 > HFC_TIMER_OFF) {
+			/* timer expired ? */
+			if (--priv->t3 == 0) {
+				XPD_DBG(SIGNAL, xpd, "T3 expired. Deactivate TE\n");
+				set_bri_timer(xpd, "T3", &priv->t3, HFC_TIMER_OFF);
+				clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
+				te_activation(xpd, 0);		/* Deactivate TE */
+			}
+		}
+	}
+}
+
 /* Poll the register ST/Up-State-machine Register, to see if the cable
  * if a cable is connected to the port.
  */
@@ -847,13 +875,23 @@
 	if(poll_interval != 0 && (priv->tick_counter % poll_interval) == 0) {
 		// XPD_DBG(GENERAL, xpd, "%d\n", priv->tick_counter);
 		priv->poll_counter++;
-		xpp_register_request(xbus, xpd, 0, 0, 0, A_SU_RD_STA, 0, 0, 0);
+		xpp_register_request(xbus, xpd,
+				BRI_PORT(xpd),	/* portno	*/
+				0,		/* writing	*/
+				A_SU_RD_STA,	/* regnum	*/
+				0,		/* do_subreg	*/
+				0,		/* subreg	*/
+				0,		/* data_low	*/
+				0,		/* do_datah	*/
+				0,		/* data_high	*/
+				0		/* should_reply	*/
+				);
 
 		if(IS_NT(xpd) && nt_keepalive &&
 			!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags) &&
 			!test_bit(HFC_L1_ACTIVATING, &priv->l1_flags)) {
 			XPD_DBG(SIGNAL, xpd, "Kick NT D-Channel\n");
-			xpd_activation(xpd, 1);
+			nt_activation(xpd, 1);
 		}
 	}
 	/* Detect D-Channel disconnect heuristic */
@@ -876,21 +914,10 @@
 		XPD_ERR(xpd, "Lost state tracking for %d ticks\n", priv->reg30_ticks);
 		priv->reg30_good = 0;
 		layer1_state(xpd, 0);
-		dchan_state(xpd, 0);
 	}
 	handle_leds(xbus, xpd);
+	handle_bri_timers(xpd);
 	tx_dchan(xpd);
-	/* Detect T1 timer expiry on NT */
-	if(IS_NT(xpd) && !nt_keepalive) {
-		if (priv->t1 > HFC_TIMER_OFF) {
-			if (--priv->t1 == 0) {
-				XPD_DBG(SIGNAL, xpd, "T1 Expired. Deactivate NT\n");
-				priv->t1 = HFC_TIMER_OFF;
-				clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
-				write_state_register(xpd, STA_DEACTIVATE);
-			}
-		}
-	}
 	priv->tick_counter++;
 	priv->reg30_ticks++;
 	return 0;
@@ -1003,8 +1030,6 @@
 	XPD_DBG(GENERAL, xpd, "STARTUP\n");
 	// Turn on all channels
 	CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1);
-	write_state_register(xpd, 0);	/* Enable L1 state machine */
-	xpd_activation(xpd, 1);
 	if(SPAN_REGISTERED(xpd)) {
 		dchan = &span->chans[2];
 		span->flags |= ZT_FLAG_RUNNING;
@@ -1038,8 +1063,6 @@
 	XPD_DBG(GENERAL, xpd, "SHUTDOWN\n");
 	// Turn off all channels
 	CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 0);
-	if(IS_NT(xpd))
-		xpd_activation(xpd, 0);
 	return 0;
 }
 
@@ -1134,22 +1157,21 @@
 
 static /* 0x0F */ HOSTCMD(BRI, XPD_STATE, bool on)
 {
-	BUG_ON(!xpd);
+	struct BRI_priv_data	*priv;
+
+	BUG_ON(!xpd);
+	priv = xpd->priv;
 	XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF");
-	xpd_activation(xpd, on);
+	if(on) {
+		if(!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags)) {
+			if(xpd->direction == TO_PSTN)
+				te_activation(xpd, 1);
+			else
+				nt_activation(xpd, 1);
+		}
+	} else if(IS_NT(xpd))
+		nt_activation(xpd, 0);
 	return 0;
-}
-
-static /* 0x0F */ HOSTCMD(BRI, RING, lineno_t chan, bool on)
-{
-	XPD_ERR(xpd, "%s: Unsupported\n", __FUNCTION__);
-	return -ENOSYS;
-}
-
-static /* 0x0F */ HOSTCMD(BRI, RELAY_OUT, byte which, bool on)
-{
-	XPD_ERR(xpd, "%s: Unsupported\n", __FUNCTION__);
-	return -ENOSYS;
 }
 
 static /* 0x33 */ HOSTCMD(BRI, SET_LED, enum bri_led_names which_led, enum led_state to_led_state)
@@ -1182,13 +1204,15 @@
 
 	XPD_DBG(REGS, xpd, "value = 0x%02X\n", value);
 	ret = xpp_register_request(xpd->xbus, xpd,
-			0,		/* chipsel	*/
+			BRI_PORT(xpd),	/* portno	*/
 			1,		/* writing	*/
+			A_SU_WR_STA,	/* regnum	*/
 			0,		/* do_subreg	*/
-			A_SU_WR_STA,	/* regnum	*/
 			0,		/* subreg	*/
 			value,		/* data_low	*/
-			0		/* data_high	*/
+			0,		/* do_datah	*/
+			0,		/* data_high	*/
+			0		/* should_reply	*/
 			);
 	return ret;
 }
@@ -1209,105 +1233,87 @@
 		return;
 	}
 	new_state.reg = reg_x30;
+	if(new_state.bits.v_su_t2_exp) {
+		XPD_NOTICE(xpd, "T2 Expired\n");
+	}
 	priv->reg30_ticks = 0;
 	priv->reg30_good = 1;
-	if((!IS_NT(xpd) && new_state.bits.v_su_sta == ST_TE_ACTIVATED) ||
-		(IS_NT(xpd) && new_state.bits.v_su_sta == ST_NT_ACTIVATED)) {
-		if(!priv->layer1_up) {
-			layer1_state(xpd, 1);
-			update_xpd_status(xpd, ZT_ALARM_NONE);
-		}
-	} else {
-		/*
-		 * Layer 1 disconnected
-		 */
-		if(priv->layer1_up) {
-			layer1_state(xpd, 0);
-			dchan_state(xpd, 0);
-		}
-		/*
-		 * Do NOT notify Zaptel about the disconnection.
-		 * If we do, Asterisk stops transmitting on the D-channel and
-		 * we can't reactivate layer-1.
-		 * Without the notification, Asterisk thinks that we are active
-		 * (although the PSTN stopped layer-1) and on call setup, sends
-		 * us D-channel data, which triggers the layer-1 activation.
-		 */
-#if 0
-		update_xpd_status(xpd, ZT_ALARM_RED);
-#endif
-	}
 	if (priv->state_register.bits.v_su_sta == new_state.bits.v_su_sta)
 		return;	/* same same */
-	DBG(SIGNAL, "%02X ---> %02X\n", priv->state_register.reg, reg_x30);
-	XPD_DBG(SIGNAL, xpd, "%s%i\n", IS_NT(xpd)?"G":"F", new_state.bits.v_su_sta);
-
+	XPD_DBG(SIGNAL, xpd, "%02X ---> %02X (info0=%d) (%s%i)\n",
+		priv->state_register.reg,
+		reg_x30,
+		new_state.bits.v_su_info0,
+		IS_NT(xpd)?"G":"F",
+		new_state.bits.v_su_sta);
 	if(!IS_NT(xpd)) {
-		/* disable T3 ? */
-		if ((new_state.bits.v_su_sta <= ST_TE_DEACTIVATED) || (new_state.bits.v_su_sta >= ST_TE_ACTIVATED)) {
-			XPD_DBG(SIGNAL, xpd, "Disable T3 ?\n");
-			priv->t3 = HFC_TIMER_OFF;
-		}
 		switch (new_state.bits.v_su_sta) {
 			case ST_TE_DEACTIVATED:		/* F3 */
 				XPD_DBG(SIGNAL, xpd, "State ST_TE_DEACTIVATED (F3)\n");
-				if (test_and_clear_bit(HFC_L1_ACTIVATED, &priv->l1_flags))
-					priv->t4 = HFC_TIMER_T4;
+				clear_bit(HFC_L1_ACTIVATED, &priv->l1_flags);
+				layer1_state(xpd, 0);
 				break;
 			case ST_TE_SIGWAIT:		/* F4	*/
 				XPD_DBG(SIGNAL, xpd, "State ST_TE_SIGWAIT (F4)\n");
+				layer1_state(xpd, 0);
 				break;
 			case ST_TE_IDENT:		/* F5	*/
 				XPD_DBG(SIGNAL, xpd, "State ST_TE_IDENT (F5)\n");
+				layer1_state(xpd, 0);
 				break;
 			case ST_TE_SYNCED:		/* F6	*/
 				XPD_DBG(SIGNAL, xpd, "State ST_TE_SYNCED (F6)\n");
+				layer1_state(xpd, 0);
 				break;
 			case ST_TE_ACTIVATED:		/* F7 */
 				XPD_DBG(SIGNAL, xpd, "State ST_TE_ACTIVATED (F7)\n");
-				if (priv->t4 > HFC_TIMER_OFF)
-					priv->t4 = HFC_TIMER_OFF;
+				set_bri_timer(xpd, "T3", &priv->t3, HFC_TIMER_OFF);
 				clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
 				set_bit(HFC_L1_ACTIVATED, &priv->l1_flags);
+				layer1_state(xpd, 1);
 				update_xpd_status(xpd, ZT_ALARM_NONE);
 				break;
-
 			case ST_TE_LOST_FRAMING:	/* F8 */
 				XPD_DBG(SIGNAL, xpd, "State ST_TE_LOST_FRAMING (F8)\n");
-				priv->t4 = HFC_TIMER_OFF;
+				layer1_state(xpd, 0);
 				break;
 			default:
 				XPD_NOTICE(xpd, "Bad TE state: %d\n", new_state.bits.v_su_sta);
 				break;
 		}
 
-	} else if(IS_NT(xpd)) {
+	} else {
 		switch (new_state.bits.v_su_sta) {
 			case ST_NT_DEACTIVATED:		/* G1 */
 				XPD_DBG(SIGNAL, xpd, "State ST_NT_DEACTIVATED (G1)\n");
 				clear_bit(HFC_L1_ACTIVATED, &priv->l1_flags);
-				priv->t1 = HFC_TIMER_OFF;
+				set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF);
+				layer1_state(xpd, 0);
 				break;
 			case ST_NT_ACTIVATING:		/* G2 */
 				XPD_DBG(SIGNAL, xpd, "State ST_NT_ACTIVATING (G2)\n");
-				xpd_activation(xpd, 1);
+				layer1_state(xpd, 0);
+				if(!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags))
+					nt_activation(xpd, 1);
 				break;
 			case ST_NT_ACTIVATED:		/* G3 */
 				XPD_DBG(SIGNAL, xpd, "State ST_NT_ACTIVATED (G3)\n");
 				clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
 				set_bit(HFC_L1_ACTIVATED, &priv->l1_flags);
-				priv->t1 = HFC_TIMER_OFF;
+				set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF);
+				layer1_state(xpd, 1);
+				update_xpd_status(xpd, ZT_ALARM_NONE);
 				break;
 			case ST_NT_DEACTIVTING:		/* G4 */
 				XPD_DBG(SIGNAL, xpd, "State ST_NT_DEACTIVTING (G4)\n");
-				priv->t1 = HFC_TIMER_OFF;
+				set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF);
+				layer1_state(xpd, 0);
 				break;
 			default:
 				XPD_NOTICE(xpd, "Bad NT state: %d\n", new_state.bits.v_su_sta);
 				break;
 		}
-	} else
-		XPD_ERR(xpd, "%s: Unknown xpd type %d\n", __FUNCTION__, xpd->type);
+	}
 	priv->state_register.reg = new_state.reg;
 }
 
@@ -1315,20 +1321,37 @@
 {
 	unsigned long		flags;
 	struct BRI_priv_data	*priv;
+	struct xpd_addr		addr;
+	xpd_t			*orig_xpd;
 	int			ret;
 
+	/* Map UNIT + PORTNUM to XPD */
+	orig_xpd = xpd;
+	addr.unit = orig_xpd->addr.unit;
+	addr.subunit = info->portnum;
+	xpd = xpd_byaddr(xbus, addr.unit, addr.subunit);
+	if(!xpd) {
+		static int	rate_limit;
+
+		if((rate_limit++ % 1003) < 5)
+			notify_bad_xpd(__FUNCTION__, xbus, addr , orig_xpd->xpdname);
+		return -EPROTO;
+	}
 	spin_lock_irqsave(&xpd->lock, flags);
 	priv = xpd->priv;
 	BUG_ON(!priv);
 	if(REG_FIELD(info, do_subreg)) {
-		XPD_DBG(REGS, xpd, "RS %02X %02X %02X\n",
+		XPD_DBG(REGS, xpd, "RI %02X %02X %02X\n",
 				REG_FIELD(info, regnum), REG_FIELD(info, subreg), REG_FIELD(info, data_low));
 	} else {
 		if (REG_FIELD(info, regnum) != A_SU_RD_STA)
 			XPD_DBG(REGS, xpd, "RD %02X %02X\n",
 					REG_FIELD(info, regnum), REG_FIELD(info, data_low));
-	}
-	if(info->multibyte) {
+		else
+			XPD_DBG(REGS, xpd, "Got SU_RD_STA=%02X\n",
+					REG_FIELD(info, data_low));
+	}
+	if(info->is_multibyte) {
 		XPD_DBG(REGS, xpd, "Got Multibyte: %d bytes, eoframe: %d\n",
 				info->bytes, info->eoframe);
 		ret = rx_dchan(xpd, info);
@@ -1345,10 +1368,10 @@
 
 	/* Update /proc info only if reply relate to the last slic read request */
 	if(
-			REG_FIELD(&priv->requested_reply, regnum) == REG_FIELD(info, regnum) &&
-			REG_FIELD(&priv->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) &&
-			REG_FIELD(&priv->requested_reply, subreg) == REG_FIELD(info, subreg)) {
-		priv->last_reply = *info;
+			REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) &&
+			REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) &&
+			REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) {
+		xpd->last_reply = *info;
 	}
 	
 end:
@@ -1356,13 +1379,14 @@
 	return 0;
 }
 
-static xproto_table_t PROTO_TABLE(BRI_NT) = {
+static xproto_table_t PROTO_TABLE(BRI) = {
 	.owner = THIS_MODULE,
 	.entries = {
 		/*	Table	Card	Opcode		*/
 	},
-	.name = "BRI_NT",
-	.type = XPD_TYPE_BRI_NT,
+	.name = "BRI",	/* protocol name */
+	.ports_per_subunit = 1,
+	.type = XPD_TYPE_BRI,
 	.xops = {
 		.card_new	= BRI_card_new,
 		.card_init	= BRI_card_init,
@@ -1377,51 +1401,18 @@
 		.card_close	= BRI_card_close,
 		.card_register_reply	= BRI_card_register_reply,
 
-		.RING		= XPROTO_CALLER(BRI, RING),
-		.RELAY_OUT	= XPROTO_CALLER(BRI, RELAY_OUT),
 		.XPD_STATE	= XPROTO_CALLER(BRI, XPD_STATE),
 	},
 	.packet_is_valid = bri_packet_is_valid,
 	.packet_dump = bri_packet_dump,
 };
 
-static xproto_table_t PROTO_TABLE(BRI_TE) = {
-	.owner = THIS_MODULE,
-	.entries = {
-		/*	Table	Card	Opcode		*/
-	},
-	.name = "BRI_TE",
-	.type = XPD_TYPE_BRI_TE,
-	.xops = {
-		.card_new	= BRI_card_new,
-		.card_init	= BRI_card_init,
-		.card_remove	= BRI_card_remove,
-		.card_zaptel_preregistration	= BRI_card_zaptel_preregistration,
-		.card_zaptel_postregistration	= BRI_card_zaptel_postregistration,
-		.card_hooksig	= BRI_card_hooksig,
-		.card_tick	= BRI_card_tick,
-		.card_pcm_fromspan	= BRI_card_pcm_fromspan,
-		.card_pcm_tospan	= BRI_card_pcm_tospan,
-		.card_ioctl	= BRI_card_ioctl,
-		.card_close	= BRI_card_close,
-		.card_register_reply	= BRI_card_register_reply,
-
-		.RING		= XPROTO_CALLER(BRI, RING),
-		.RELAY_OUT	= XPROTO_CALLER(BRI, RELAY_OUT),
-		.XPD_STATE	= XPROTO_CALLER(BRI, XPD_STATE),
-	},
-	.packet_is_valid = bri_packet_is_valid,
-	.packet_dump = bri_packet_dump,
-};
-
 static bool bri_packet_is_valid(xpacket_t *pack)
 {
-	const xproto_entry_t	*xe_nt = NULL;
-	const xproto_entry_t	*xe_te = NULL;
+	const xproto_entry_t	*xe = NULL;
 	// DBG(GENERAL, "\n");
-	xe_nt = xproto_card_entry(&PROTO_TABLE(BRI_NT), XPACKET_OP(pack));
-	xe_te = xproto_card_entry(&PROTO_TABLE(BRI_TE), XPACKET_OP(pack));
-	return xe_nt != NULL || xe_te != NULL;
+	xe = xproto_card_entry(&PROTO_TABLE(BRI), XPACKET_OP(pack));
+	return xe != NULL;
 }
 
 static void bri_packet_dump(const char *msg, xpacket_t *pack)
@@ -1449,15 +1440,18 @@
 		len += sprintf(page + len, "%c%d %-15s -- fr_sync=%d t2_exp=%d info0=%d g2_g3=%d\n",
 					IS_NT(xpd)?'G':'F',
 					priv->state_register.bits.v_su_sta,
-					xhfc_state_name(xpd->type, priv->state_register.bits.v_su_sta),
+					xhfc_state_name(IS_NT(xpd), priv->state_register.bits.v_su_sta),
 					priv->state_register.bits.v_su_fr_sync,
 					priv->state_register.bits.v_su_t2_exp,
 					priv->state_register.bits.v_su_info0,
 					priv->state_register.bits.v_g2_g3);
 	} else
 		len += sprintf(page + len, "Unkown\n");
-	if(IS_NT(xpd))
+	if(IS_NT(xpd)) {
 		len += sprintf(page + len, "T1 Timer: %d\n", priv->t1);
+	} else {
+		len += sprintf(page + len, "T3 Timer: %d\n", priv->t3);
+	}
 	len += sprintf(page + len, "Tick Counter: %d\n", priv->tick_counter);
 	len += sprintf(page + len, "Last Poll Reply: %d ticks ago\n", priv->reg30_ticks);
 	len += sprintf(page + len, "reg30_good=%d\n", priv->reg30_good);
@@ -1487,244 +1481,26 @@
 	return len;
 }
 
-/*
- *
- * Direct/Indirect
- *     |
- *     | Reg#
- *     | |
- *     | |  Data (only in Write)
- *     | |    |
- *     | |  +-+-+
- *     v v  v   v
- * FF WD 06 01 05
- * ^  ^
- * |  |
- * |  Write/Read
- * |
- * Chan#
- *
- */
-static int handle_register_command(xpd_t *xpd, char *cmdline)
-{
-	unsigned		chipsel;
-	unsigned		data = 0;
-	unsigned		xdata1 = 0;
-	unsigned		xdata2 = 0;
-	char			op;		/* [W]rite, [R]ead */
-	char			reg_type;	/* [D]irect, [S]ubregister */
-	int			reg_num;
-	int			subreg;
-	int			elements;
-	bool			writing;
-	char			*p;
-	reg_cmd_t		regcmd;
-	xbus_t			*xbus;
-	int			ret = -EINVAL;
-	struct BRI_priv_data	*priv;
-	byte			buf[MAX_PROC_WRITE];
-
-	BUG_ON(!xpd);
-	xbus = xpd->xbus;
-	BUG_ON(!xbus);
-	priv = xpd->priv;
-	BUG_ON(!priv);
-	if((p = strchr(cmdline, '#')) != NULL)	/* Truncate comments */
-		*p = '\0';
-	if((p = strchr(cmdline, ';')) != NULL)	/* Truncate comments */
-		*p = '\0';

[... 10976 lines stripped ...]



More information about the zaptel-commits mailing list