[zaptel-commits] trunk r1204 - in /trunk/xpp: ./ utils/

zaptel-commits at lists.digium.com zaptel-commits at lists.digium.com
Thu Jul 6 06:47:05 MST 2006


Author: tzafrir
Date: Thu Jul  6 08:47:05 2006
New Revision: 1204

URL: http://svn.digium.com/view/zaptel?rev=1204&view=rev
Log:
Tons of updates to the Astribank (xpp) driver:
* xpd_fxo.ko (FXO span) is now operational
* 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.

Removed:
    trunk/xpp/cmd2inc
Modified:
    trunk/xpp/   (props changed)
    trunk/xpp/Makefile
    trunk/xpp/README.Astribank
    trunk/xpp/card_fxo.c
    trunk/xpp/card_fxo.h
    trunk/xpp/card_fxs.c
    trunk/xpp/card_fxs.h
    trunk/xpp/card_global.c
    trunk/xpp/card_global.h
    trunk/xpp/init_data_3_19.cmd
    trunk/xpp/init_data_3_20.cmd
    trunk/xpp/init_data_4_20.cmd
    trunk/xpp/slic.h
    trunk/xpp/utils/FPGA_FXS.hex
    trunk/xpp/utils/Makefile
    trunk/xpp/utils/genzaptelconf
    trunk/xpp/utils/hexfile.c
    trunk/xpp/utils/xpp_fxloader
    trunk/xpp/xbus-core.c
    trunk/xpp/xbus-core.h
    trunk/xpp/xdefs.h
    trunk/xpp/xpd.h
    trunk/xpp/xpp_usb.c
    trunk/xpp/xpp_zap.c
    trunk/xpp/xpp_zap.h
    trunk/xpp/xproto.c
    trunk/xpp/xproto.h
    trunk/xpp/zap_debug.c
    trunk/xpp/zap_debug.h

Propchange: trunk/xpp/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Thu Jul  6 08:47:05 2006
@@ -3,4 +3,3 @@
 *.o.cmd
 *.ko.cmd
 *.mod.c
-init_data_*.inc

Modified: trunk/xpp/Makefile
URL: http://svn.digium.com/view/zaptel/trunk/xpp/Makefile?rev=1204&r1=1203&r2=1204&view=diff
==============================================================================
--- trunk/xpp/Makefile (original)
+++ trunk/xpp/Makefile Thu Jul  6 08:47:05 2006
@@ -1,30 +1,9 @@
-EXTRA_CFLAGS	= -I$(SUBDIRS) -DDEBUG -DWITH_ECHO_SUPPRESSION # -DHARD_CODED_INIT # -DOLD_CARD # -DWITH_RBS
+EXTRA_CFLAGS	= -I$(SUBDIRS) -DDEBUG -DPOLL_DIGITAL_INPUTS -DWITH_ECHO_SUPPRESSION -DWITH_RBS -DSTANDALONE_ZAPATA
 
-obj-m			= xpp.o xpd_fxs.o xpd_fxo.o xpp_usb.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
 
-GENERATE_INIT_DATA	:= 1
-INIT_DATA		= init_data_3_19.inc init_data_3_20.inc init_data_4_19.inc init_data_4_20.inc
-clean-files		:= $(INIT_DATA)
-
-cmd2inc=$(src)/cmd2inc
-
-define run_cmd2inc
-if [ ! -x $(cmd2inc) ]; then chmod +x $(cmd2inc); fi
-$(cmd2inc) $^ $@
-endef
-
-ifeq	($(GENERATE_INIT_DATA),1)
-
-$(obj)/%.inc: $(src)/%.cmd
-	@echo "Generating $@"
-	@$(run_cmd2inc)
-
-init_data: $(INIT_DATA)
-
-$(obj)/card_fxs.o: $(obj)/init_data_3_19.inc $(obj)/init_data_3_20.inc
-$(obj)/card_fxo.o: $(obj)/init_data_4_19.inc $(obj)/init_data_4_20.inc
-
-endif
+ctags:
+	ctags *.[ch]

Modified: trunk/xpp/README.Astribank
URL: http://svn.digium.com/view/zaptel/trunk/xpp/README.Astribank?rev=1204&r1=1203&r2=1204&view=diff
==============================================================================
--- trunk/xpp/README.Astribank (original)
+++ trunk/xpp/README.Astribank Thu Jul  6 08:47:05 2006
@@ -35,6 +35,13 @@
 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/
 
@@ -44,6 +51,14 @@
 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:
 """"""""""""""""""""""""

Modified: trunk/xpp/card_fxo.c
URL: http://svn.digium.com/view/zaptel/trunk/xpp/card_fxo.c?rev=1204&r1=1203&r2=1204&view=diff
==============================================================================
--- trunk/xpp/card_fxo.c (original)
+++ trunk/xpp/card_fxo.c Thu Jul  6 08:47:05 2006
@@ -34,6 +34,15 @@
 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,
@@ -44,39 +53,19 @@
 
 /*---------------- FXO Protocol Commands ----------------------------------*/
 
-/* 0x0F */ DECLARE_CMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on);
-/* 0x0F */ DECLARE_CMD(FXO, CHAN_CID, xpp_line_t lines);
-/* 0x0F */ DECLARE_CMD(FXO, RING, int pos, bool on);
-/* 0x0F */ DECLARE_CMD(FXO, SETHOOK, int pos, bool offhook);
-/* 0x0F */ DECLARE_CMD(FXO, RELAY_OUT, byte which, bool on);
-/* 0x0F */ DECLARE_CMD(FXO, DAA_INIT);
-/* 0x0F */ DECLARE_CMD(FXO, DAA_QUERY, int pos, byte reg_num);
+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);
-
-#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[] = {
-#ifdef	OLD_CARD
-#include "init_data_4_19.inc"
-#else
-#include "init_data_4_20.inc"
-#endif
-};
-#undef	S_
+static int process_slic_cmdline(xpd_t *xpd, char *cmdline);
 
 #define	PROC_DAA_FNAME		"slics"
 #define	PROC_FXO_INFO_FNAME	"fxo_info"
@@ -126,7 +115,7 @@
 			BIT_CLR(priv->ledstate[which], pos);
 		}
 	}
-	if(!(lines & xpd->enabled_chans))	// Ignore disabled channels
+	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);
@@ -151,7 +140,7 @@
 	spin_lock_irqsave(&xpd->lock, flags);
 	priv = xpd->priv;
 	timer_count = xpd->timer_count;
-	for_each_enabled_line(xpd, i) {
+	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)) {
@@ -172,10 +161,16 @@
 
 static void do_sethook(xpd_t *xpd, int pos, bool offhook)
 {
-	unsigned long	flags;
+	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);
@@ -228,6 +223,7 @@
 {
 	struct FXO_priv_data	*priv;
 	int			ret = 0;
+	int			i;
 
 	BUG_ON(!xpd);
 	priv = xpd->priv;
@@ -237,41 +233,34 @@
 	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 out;
-	}
+		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);
-		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;
 #endif
-#ifdef HARD_CODED_INIT
-	CALL_PROTO(FXO, DAA_INIT, xbus, xpd);
-#else
 	ret = run_initialize_registers(xpd);
 	if(ret < 0)
-		goto out;
-#endif
-	if(xpd->direction == TO_PSTN) {
-		int	i;
-
-		// Hanghup all lines
-		for_each_enabled_line(xpd, i) {
-			init_waitqueue_head(&xpd->txstateq[i]);
-			do_sethook(xpd, i, 0);
-		}
-	}
-out:
-	if(ret < 0) {
-		clean_proc(xbus, xpd);
-		ERR("%s/%s: Failed initializing registers (%d)\n", xbus->busname, xpd->xpdname, ret);
-	} else {
-		DBG("done: %s/%s\n", xbus->busname, xpd->xpdname);
-	}
+		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;
 }
 
@@ -286,12 +275,12 @@
 	return 0;
 }
 
-static int FXO_card_zaptel_registration(xpd_t *xpd, bool on)
+static int FXO_card_zaptel_preregistration(xpd_t *xpd, bool on)
 {
 	xbus_t			*xbus;
 	struct FXO_priv_data	*priv;
+	int			i;
 	unsigned long		flags;
-	int			i;
 
 	BUG_ON(!xpd);
 	xbus = xpd->xbus;
@@ -299,42 +288,80 @@
 	priv = xpd->priv;
 	BUG_ON(!priv);
 	DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on);
-	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(50);
-		}
-		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(50);
-		}
-	} else {
-		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(100);
-			spin_lock_irqsave(&xpd->lock, flags);
-			do_led(xpd, i, LED_GREEN, LED_OFF);
-			spin_unlock_irqrestore(&xpd->lock, flags);
-		}
-	}
-	return 0;
-}
-
+	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;
+	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. 
-		 * Can be ignored for an FXS line
-		 */
+		/* On-hook, off-hook: The PBX is playing a phone on an FXO line.  */
 		case ZT_ONHOOK:
 			do_sethook(xpd, pos, 0);
 			break;
@@ -353,7 +380,7 @@
 			WARN("No code yet\n");
 			break;
 		case ZT_RING:
-			DBG("%s/%s/%d: (ringing[%d]=%d)\n", xbus->busname, xpd->xpdname, pos, pos, xpd->ringing[pos]);
+			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");
@@ -361,12 +388,13 @@
 	}
 	return ret;
 }
+#endif
 
 static void poll_battery(xbus_t *xbus, xpd_t *xpd)
 {
 	int	i;
 
-	for_each_enabled_line(xpd, i) {
+	for_each_line(xpd, i) {
 		CALL_PROTO(FXO, DAA_QUERY, xbus, xpd, i, DAA_VBAT_REGISTER);
 	}
 }
@@ -374,23 +402,75 @@
 
 static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
 {
-	static int		rate_limit = 0;
+	static unsigned		rate_limit = 0;
 	struct FXO_priv_data	*priv;
 
 	BUG_ON(!xpd);
 	priv = xpd->priv;
 	BUG_ON(!priv);
 	rate_limit++;
-	if((rate_limit % 100) == 0) {
+	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 -------------------------------------*/
 
-/* 0x0F */ HOSTCMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on)
+static /* 0x0F */ HOSTCMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on)
 {
 	unsigned long		flags;
 	int	ret = 0;
@@ -398,19 +478,18 @@
 
 	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");
 	if(on) {
-		for_each_enabled_line(xpd, i) {
+		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_enabled_line(xpd, i) {
+		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);
@@ -420,32 +499,31 @@
 	return ret;
 }
 
-/* 0x0F */ HOSTCMD(FXO, CHAN_CID, xpp_line_t lines)
+static /* 0x0F */ HOSTCMD(FXO, CHAN_CID, int pos)
 {
 	int		ret = 0;
+	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);
 	return ret;
 }
 
 
-/* 0x0F */ HOSTCMD(FXO, RING, int pos, bool on)
+static /* 0x0F */ HOSTCMD(FXO, RING, int pos, bool on)
 {
 	int		ret = 0;
 	xpacket_t	*pack;
 	slic_cmd_t	*sc;
-	xpp_line_t	mask = (1 << pos);
+	xpp_line_t	mask = BIT(pos);
 	int		len;
 
 	BUG_ON(!xbus);
 	BUG_ON(!xpd);
-	mask &= xpd->enabled_chans;	// Ignore disabled channels
 	if(!mask) {
 		return 0;
 	}
@@ -459,7 +537,7 @@
 	return ret;
 }
 
-/* 0x0F */ HOSTCMD(FXO, SETHOOK, int pos, bool offhook)
+static /* 0x0F */ HOSTCMD(FXO, SETHOOK, int pos, bool offhook)
 {
 	int		ret = 0;
 	xpacket_t	*pack;
@@ -470,56 +548,26 @@
 
 	BUG_ON(!xbus);
 	BUG_ON(!xpd);
-	value = (offhook) ? 0x01 : 0x00;
+	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);
-	if(!IS_SET(xpd->enabled_chans, pos))
-		goto out;
 	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);
-out:
 	spin_unlock_irqrestore(&xpd->lock, flags);
 	return ret;
 }
 
-/* 0x0F */ HOSTCMD(FXO, RELAY_OUT, byte which, bool on)
+static /* 0x0F */ HOSTCMD(FXO, RELAY_OUT, byte which, bool on)
 {
 	return -ENOSYS;
 }
 
-/* 0x0F */ HOSTCMD(FXO, DAA_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 DAA\n");
-	for(i = 0; i < ARRAY_SIZE(slic_init_data); i++) {
-		source = &slic_init_data[i];
-		XPACKET_NEW(pack, xbus, FXO, DAA_INIT, xpd->id);
-		RPACKET_FIELD(pack, FXO, DAA_INIT, lines) = source->lines;
-
-		slic = &RPACKET_FIELD(pack, FXO, DAA_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("DAA", pack, print_dbg);
-		packet_send(xbus, pack);
-		mdelay(1);	// FIXME: check with Dima
-	}
-	return ret;
-}
-
-/* 0x0F */ HOSTCMD(FXO, DAA_QUERY, int pos, byte reg_num)
+static /* 0x0F */ HOSTCMD(FXO, DAA_QUERY, int pos, byte reg_num)
 {
 	int	ret = 0;
 	xpacket_t	*pack;
@@ -588,22 +636,16 @@
 
 		if(abs(info->data_low) < BAT_THRESHOLD) {
 			priv->battery &= ~lines;
-			// DBG("BATTERY OFF (%04X) = %d\n", lines, info->data_low);
+			// DBG("%s/%s: BATTERY OFF (%04X) = %d\n", xpd->xbus->busname, xpd->xpdname, lines, info->data_low);
 		} else {
 			priv->battery |= lines;
-			// DBG("BATTERY ON  (%04X) = %d\n", lines, info->data_low);
+			// 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) || IS_SET(xpd->hookstate, i))
-				continue;
-#if 0
-			/* FIXME: We don't want to affect the whole span */
-			if(IS_SET(priv->battery, i))
-				update_xpd_status(xpd, ZT_ALARM_NONE);
-			else
-				update_xpd_status(xpd, ZT_ALARM_RED);
-#endif
+			if(IS_SET(changed_lines, i)) {
+				update_line_status(xpd, i, IS_SET(priv->battery, i));
+			}
 		}
 	}
 #if 0
@@ -635,9 +677,15 @@
 		.card_new	= FXO_card_new,
 		.card_init	= FXO_card_init,
 		.card_remove	= FXO_card_remove,
-		.card_zaptel_registration	= FXO_card_zaptel_registration,
+		.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),
@@ -676,7 +724,8 @@
 	struct FXO_priv_data	*priv;
 	int			i;
 
-	BUG_ON(!xpd);
+	if(!xpd)
+		return -ENODEV;
 	spin_lock_irqsave(&xpd->lock, flags);
 	priv = xpd->priv;
 	BUG_ON(!priv);
@@ -830,9 +879,8 @@
 	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_DAA", &sc);
@@ -852,7 +900,8 @@
 	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)

Modified: trunk/xpp/card_fxo.h
URL: http://svn.digium.com/view/zaptel/trunk/xpp/card_fxo.h?rev=1204&r1=1203&r2=1204&view=diff
==============================================================================
--- trunk/xpp/card_fxo.h (original)
+++ trunk/xpp/card_fxo.h Thu Jul  6 08:47:05 2006
@@ -51,10 +51,6 @@
 	xpp_line_t	lines;
 	slic_reply_t	info;
 	);
-DEF_RPACKET_DATA(FXO, DAA_INIT,
-	xpp_line_t      lines;
-	slic_data_t     slic_data;
-	);
 DEF_RPACKET_DATA(FXO, DAA_WRITE,
 	slic_cmd_t	slic_cmd;
 	);

Modified: trunk/xpp/card_fxs.c
URL: http://svn.digium.com/view/zaptel/trunk/xpp/card_fxs.c?rev=1204&r1=1203&r2=1204&view=diff
==============================================================================
--- trunk/xpp/card_fxs.c (original)
+++ trunk/xpp/card_fxs.c Thu Jul  6 08:47:05 2006
@@ -34,15 +34,21 @@
 static const char rcsid[] = "$Id$";
 
 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	(MASK_BITS(LINES_DIGI_OUT) << LINES_REGULAR)
-#define	MASK_DIGI_INP	(MASK_BITS(LINES_DIGI_INP) << (LINES_REGULAR + LINES_DIGI_OUT))
+#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,
@@ -52,14 +58,27 @@
 
 #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 ----------------------------------*/
 
 static /* 0x0F */ DECLARE_CMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on);
-static /* 0x0F */ DECLARE_CMD(FXS, CHAN_CID, xpp_line_t lines);
+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_INIT);
 static /* 0x0F */ DECLARE_CMD(FXS, SLIC_QUERY, int pos, byte reg_num);
 
 static bool fxs_packet_is_valid(xpacket_t *pack);
@@ -67,26 +86,6 @@
 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[] = {
-#ifdef	OLD_CARD
-#include "init_data_3_19.inc"
-#else
-#include "init_data_3_20.inc"
-#endif
-};
-#undef	S_
 
 #define	PROC_SLIC_FNAME		"slics"
 #define	PROC_FXS_INFO_FNAME	"fxs_info"
@@ -111,7 +110,6 @@
 
 	BUG_ON(!xbus);
 	BUG_ON(!xpd);
-	lines &= xpd->enabled_chans;	// Ignore disabled channels
 	if(!lines) {
 		return 0;
 	}
@@ -132,8 +130,8 @@
 }
 
 #define	IS_BLINKING(priv,pos,color)	((priv)->blinking[color][pos] != 0)
-#define	DO_BLINK(priv,pos,color,val)	((priv)->blinking[color][pos] = (val))
-#define	DO_LED(priv,pos,color,val)	((val)?BIT_SET((priv)->ledcontrol[color],(pos)):BIT_CLR((priv)->ledcontrol[color],(pos)))
+#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:
@@ -195,7 +193,7 @@
 			BIT_CLR(priv->ledstate[which], pos);
 		}
 	}
-	if(!(lines & xpd->enabled_chans))	// Ignore disabled channels
+	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);
@@ -222,11 +220,11 @@
 	struct FXS_priv_data	*priv;
 
 	BUG_ON(!xpd);
-	priv = xpd->priv;
 	spin_lock_irqsave(&xpd->lock, flags);
+	priv = xpd->priv;
 	timer_count = xpd->timer_count;
 	for(color = 0; color < ARRAY_SIZE(colors); color++) {
-		for_each_enabled_line(xpd, i) {
+		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
@@ -282,6 +280,7 @@
 #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) {
@@ -304,31 +303,45 @@
 	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 out;
-	}
+		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);
 		ret = -ENOENT;
-		goto out;
-	}
+		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
-#ifdef HARD_CODED_INIT
-	CALL_PROTO(FXS, SLIC_INIT, xbus, xpd);
+	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
-	ret = run_initialize_registers(xpd);
-#endif
-out:
-	if(ret < 0) {
-		clean_proc(xbus, xpd);
-		ERR("%s/%s: Failed initializing registers (%d)\n", xbus->busname, xpd->xpdname, ret);
-	} else {
-		DBG("done: %s/%s\n", xbus->busname, xpd->xpdname);
-	}
+	/* 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;
 }
 
@@ -343,46 +356,139 @@
 	return 0;
 }
 
-static int FXS_card_zaptel_registration(xpd_t *xpd, bool on)
+static int FXS_card_zaptel_preregistration(xpd_t *xpd, bool on)
 {
 	xbus_t			*xbus;
 	struct FXS_priv_data	*priv;
+	int			i;
 	unsigned long		flags;
-	int	i;
+	const enum fxs_leds     color = (on) ? LED_GREEN : LED_RED;
 
 	BUG_ON(!xpd);
 	xbus = xpd->xbus;
-	priv = xpd->priv;
 	BUG_ON(!xbus);
-	DBG("%s/%s: %s\n", xbus->busname, xpd->xpdname, (on)?"on":"off");
-	if(on) {
-		spin_lock_irqsave(&xpd->lock, flags);
-		do_led(xpd, ALL_LINES, LED_GREEN, LED_OFF);
-		spin_unlock_irqrestore(&xpd->lock, flags);
-		for_each_enabled_line(xpd, i) {
-			DO_LED(priv,i,LED_GREEN,LED_ON);
-			mdelay(50);
+	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);
 		}
-		for_each_enabled_line(xpd, i) {
-			DO_LED(priv,i,LED_GREEN,LED_OFF);
-			mdelay(50);
-		}
-	} else {
-		spin_lock_irqsave(&xpd->lock, flags);
-		do_led(xpd, ALL_LINES, LED_RED, LED_OFF);
-		spin_unlock_irqrestore(&xpd->lock, flags);
-		for_each_enabled_line(xpd, i) {
-			DO_LED(priv,i,LED_RED,LED_ON);
-			mdelay(50);
-		}
-		for_each_enabled_line(xpd, i) {
-			DO_LED(priv,i,LED_RED,LED_OFF);
-			mdelay(50);
-		}
+		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);
+	}
+	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;
@@ -417,7 +523,7 @@
 			DBG("%s/%s/%d: fall through ZT_OFFHOOK\n", xbus->busname, xpd->xpdname, pos);
 			// Fall through
 		case ZT_OFFHOOK:
-			DBG("%s/%s/%d: ignoring (PHONE)\n", xbus->busname, xpd->xpdname, pos);
+			DBG("%s/%s/%d: ZT_OFFHOOK (ignoring for PHONES)\n", xbus->busname, xpd->xpdname, pos);
 			break;
 		case ZT_WINK:
 			WARN("No code yet\n");
@@ -426,7 +532,7 @@
 			WARN("No code yet\n");
 			break;
 		case ZT_RING:
-			DBG("%s/%s/%d: ringing[%d]=%d\n", xbus->busname, xpd->xpdname, pos, pos, xpd->ringing[pos]);
+			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;
@@ -448,6 +554,7 @@
 	}
 	return ret;
 }
+#endif
 
 /*
  * INPUT polling is done via SLIC register 0x06 (same as LEDS):
@@ -463,6 +570,7 @@
 {
 	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];
 
@@ -478,9 +586,13 @@
 	BUG_ON(!xpd);
 	priv = xpd->priv;
 	BUG_ON(!priv);
-	if((rate_limit++ % 1000) == 0) {
-		poll_inputs(xbus, xpd);
-	}
+#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;
 }
@@ -499,11 +611,14 @@
 
 	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, value);
@@ -522,20 +637,21 @@
 	return ret;
 }
 
-static /* 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, FXS_LINE_CID);
@@ -552,14 +668,13 @@
 	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);
 	priv = xpd->priv;
-	mask &= xpd->enabled_chans;	// Ignore disabled channels
 	if(!mask) {
 		return 0;
 	}
@@ -573,10 +688,10 @@
 
 	packet_send(xbus, pack);
 	if(on) {
-		DO_BLINK(priv,pos,LED_GREEN,LED_BLINK);
+		MARK_BLINK(priv,pos,LED_GREEN,LED_BLINK);
 	} else {
 		if(IS_BLINKING(priv, pos, LED_GREEN))
-			DO_BLINK(priv,pos,LED_GREEN,0);
+			MARK_BLINK(priv,pos,LED_GREEN,0);
 	}
 	return ret;
 }
@@ -617,33 +732,6 @@
 	return ret;
 }
 
-static /* 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(1);	// FIXME: check with Dima
-	}
-	return ret;
-}
-
 static /* 0x0F */ HOSTCMD(FXS, SLIC_QUERY, int pos, byte reg_num)
 {
 	int	ret = 0;
@@ -683,7 +771,7 @@
 	}
 #if 0
 	Is this needed?
-	for_each_enabled_line(xpd, i) {
+	for_each_line(xpd, i) {
 		if(IS_SET(sig_toggles, i))
 			do_chan_power(xpd->xbus, xpd, BIT(i), 0);		// Power down (prevent overheating!!!)
 	}
@@ -695,15 +783,15 @@
 			struct zt_chan *chan = &xpd->span.chans[i];
 
 			xpd->ringing[i] = 0;		// No more ringing...
-			DO_BLINK(priv,i,LED_GREEN,0);
+			MARK_BLINK(priv,i,LED_GREEN,0);
 			if(IS_SET(sig_status, i)) {
 				DBG("OFFHOOK: channo=%d\n", chan->channo);
-				DO_LED(priv,i,LED_GREEN,LED_ON);
+				MARK_LED(priv,i,LED_GREEN,LED_ON);
 				BIT_SET(xpd->hookstate, i);
 				zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
 			} else {
 				DBG("ONHOOK channo=%d\n", chan->channo);
-				DO_LED(priv,i,LED_GREEN,LED_OFF);
+				MARK_LED(priv,i,LED_GREEN,LED_OFF);
 				BIT_CLR(xpd->hookstate, i);
 				zt_hooksig(chan, ZT_RXSIG_ONHOOK);
 			}
@@ -770,7 +858,6 @@
 	return 0;
 }
 
-
 xproto_table_t PROTO_TABLE(FXS) = {
 	.owner = THIS_MODULE,
 	.entries = {
@@ -784,8 +871,13 @@
 		.card_new	= FXS_card_new,
 		.card_init	= FXS_card_init,
 		.card_remove	= FXS_card_remove,
-		.card_zaptel_registration	= FXS_card_zaptel_registration,
+		.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),
@@ -826,7 +918,8 @@
 	int			i;
 	int			led;
 
-	BUG_ON(!xpd);
+	if(!xpd)
+		return -ENODEV;
 	spin_lock_irqsave(&xpd->lock, flags);
 	priv = xpd->priv;
 	BUG_ON(!priv);
@@ -984,9 +1077,8 @@
 	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);
@@ -1006,7 +1098,8 @@
 	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)
@@ -1032,6 +1125,12 @@
 int __init card_fxs_startup(void)
 {
 	INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION);

[... 3312 lines stripped ...]


More information about the zaptel-commits mailing list