[zaptel-commits] tzafrir: branch 1.4 r4590 - /branches/1.4/kernel/xpp/

SVN commits to the Zaptel project zaptel-commits at lists.digium.com
Sun Nov 30 06:10:03 CST 2008


Author: tzafrir
Date: Sun Nov 30 06:10:03 2008
New Revision: 4590

URL: http://svn.digium.com/view/zaptel?view=rev&rev=4590
Log:
xpp: PCM changes and related bugfixes.

* Power-denial signalling is now sent to Zaptel to decide if we're LS or
  KS (and not hang up ourselves always).
* Fix card_fxo's caller_id_style=1 (FSK).
* Macro XPD_CHAN: s/xpd->chans[i]/XPD_CHAN(xpd, i)/  to reduce diff from DAHDI.


Modified:
    branches/1.4/kernel/xpp/.version
    branches/1.4/kernel/xpp/card_bri.c
    branches/1.4/kernel/xpp/card_fxo.c
    branches/1.4/kernel/xpp/card_fxs.c
    branches/1.4/kernel/xpp/card_pri.c
    branches/1.4/kernel/xpp/xbus-pcm.c
    branches/1.4/kernel/xpp/xbus-pcm.h
    branches/1.4/kernel/xpp/xpd.h
    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

Modified: branches/1.4/kernel/xpp/.version
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/xpp/.version?view=diff&rev=4590&r1=4589&r2=4590
==============================================================================
--- branches/1.4/kernel/xpp/.version (original)
+++ branches/1.4/kernel/xpp/.version Sun Nov 30 06:10:03 2008
@@ -1,1 +1,1 @@
-trunk-r6058
+branch-rel-6171-r6408

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=4590&r1=4589&r2=4590
==============================================================================
--- branches/1.4/kernel/xpp/card_bri.c (original)
+++ branches/1.4/kernel/xpp/card_bri.c Sun Nov 30 06:10:03 2008
@@ -208,7 +208,6 @@
 	bool				reg30_good;
 	uint				reg30_ticks;
 	bool				layer1_up;
-	xpp_line_t			card_pcm_mask;
 
 	/*
 	 * D-Chan: buffers + extra state info.
@@ -460,8 +459,8 @@
 #ifdef XPP_DEBUGFS
 	xbus_log(xbus, xpd, 0, regcmd, sizeof(reg_cmd_t));		/* 0 = RX */
 #endif
-	dchan = &xpd->span.chans[2];
-	if(!IS_SET(xpd->offhook, 2)) {	/* D-chan is used? */
+	dchan = XPD_CHAN(xpd, 2);
+	if(!IS_OFFHOOK(xpd, 2)) {	/* D-chan is used? */
 		static int rate_limit;
 
 		if((rate_limit++ % 1000) == 0)
@@ -534,7 +533,7 @@
 	BUG_ON(!priv);
 	if(!SPAN_REGISTERED(xpd) || !(xpd->span.flags & ZT_FLAG_RUNNING))
 		return 0;
-	dchan = &xpd->chans[2];
+	dchan = XPD_CHAN(xpd, 2);
 	len = dchan->bytes2transmit;	/* dchan's hdlc package len */
 	eoframe = dchan->eoftx;		/* dchan's end of frame */
 	dchan->bytes2transmit = 0;
@@ -659,9 +658,6 @@
 {
 	xbus_t			*xbus;
 	struct BRI_priv_data	*priv;
-	xpp_line_t		tmp_pcm_mask;
-	int			tmp_pcm_len;
-	unsigned long		flags;
 	int			i;
 	
 	BUG_ON(!xpd);
@@ -680,7 +676,7 @@
 	xpd->span.deflaw = ZT_LAW_ALAW;
 	BIT_SET(xpd->digital_signalling, 2);	/* D-Channel */
 	for_each_line(xpd, i) {
-		struct zt_chan	*cur_chan = &xpd->chans[i];
+		struct zt_chan	*cur_chan = XPD_CHAN(xpd, i);
 
 		XPD_DBG(GENERAL, xpd, "setting BRI channel %d\n", i);
 		snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%02d/%1d%1d/%d",
@@ -705,35 +701,11 @@
 		} else
 			cur_chan->sigcap = BRI_BCHAN_SIGCAP;
 	}
-	xpd->offhook = BIT(0) | BIT(1);	/* 2*bchan */
-
-	/*
-	 * Compute PCM lentgh and mask
-	 * We know all cards have been initialized until now
-	 */
-	tmp_pcm_mask = 0;
-	if(xpd->addr.subunit == 0) {
-		int	line_count = 0;
-
-		for(i = 0; i < MAX_SUBUNIT; i++) {
-			xpd_t	*sub_xpd = xpd_byaddr(xbus, xpd->addr.unit, i);
-			if(sub_xpd) {
-				tmp_pcm_mask |= PCM_SHIFT(sub_xpd->wanted_pcm_mask, i);
-				line_count += 2;
-			}
-		}
-		tmp_pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t)  +  line_count * ZT_CHUNKSIZE;
-	} else
-		tmp_pcm_len = 0;
-	spin_lock_irqsave(&xpd->lock, flags);
-	xpd->pcm_len = tmp_pcm_len;
-	xpd->wanted_pcm_mask = xpd->offhook;
-	priv->card_pcm_mask = tmp_pcm_mask;
+	CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0);
 	xpd->span.spanconfig = bri_spanconfig;
 	xpd->span.chanconfig = bri_chanconfig;
 	xpd->span.startup = bri_startup;
 	xpd->span.shutdown = bri_shutdown;
-	spin_unlock_irqrestore(&xpd->lock, flags);
 	return 0;
 }
 
@@ -943,15 +915,38 @@
 	return 0;
 }
 
+static int BRI_card_open(xpd_t *xpd, lineno_t pos)
+{
+	struct BRI_priv_data	*priv;
+
+	BUG_ON(!xpd);
+	priv = xpd->priv;
+	if(pos == 2) {
+		LINE_DBG(SIGNAL, xpd, pos, "OFFHOOK the whole span\n");
+		BIT_SET(xpd->offhook_state, 0);
+		BIT_SET(xpd->offhook_state, 1);
+		BIT_SET(xpd->offhook_state, 2);
+		CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0);
+	}
+	return 0;
+}
+
 static int BRI_card_close(xpd_t *xpd, lineno_t pos)
 {
-	struct zt_chan	*chan = &xpd->span.chans[pos];
+	struct zt_chan	*chan = XPD_CHAN(xpd, pos);
 
 	/* Clear D-Channel pending data */
 	chan->bytes2receive = 0;
 	chan->eofrx = 0;
 	chan->bytes2transmit = 0;
 	chan->eoftx = 0;
+	if(pos == 2) {
+		LINE_DBG(SIGNAL, xpd, pos, "ONHOOK the whole span\n");
+		BIT_CLR(xpd->offhook_state, 0);
+		BIT_CLR(xpd->offhook_state, 1);
+		BIT_CLR(xpd->offhook_state, 2);
+		CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0);
+	}
 	return 0;
 }
 
@@ -1031,7 +1026,7 @@
 	// Turn on all channels
 	CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1);
 	if(SPAN_REGISTERED(xpd)) {
-		dchan = &span->chans[2];
+		dchan = XPD_CHAN(xpd, 2);
 		span->flags |= ZT_FLAG_RUNNING;
 		/*
 		 * Zaptel (wrongly) assume that D-Channel need HDLC decoding
@@ -1066,14 +1061,74 @@
 	return 0;
 }
 
-static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t wanted_lines, xpacket_t *pack)
+void BRI_card_pcm_recompute(xbus_t *xbus, xpd_t *xpd, xpp_line_t dont_care)
+{
+	int		i;
+	int		line_count;
+	xpp_line_t	pcm_mask;
+	xpd_t		*main_xpd;
+	unsigned long	flags;
+
+	BUG_ON(!xpd);
+	main_xpd = xpd_byaddr(xbus, xpd->addr.unit, 0);
+	if(!main_xpd) {
+		XPD_DBG(DEVICES, xpd, "Unit 0 is already gone. Ignore request\n");
+		return;
+	}
+	/*
+	 * We calculate all subunits, so use the main lock
+	 * as a mutex for the whole operation.
+	 */
+	spin_lock_irqsave(&main_xpd->lock_recompute_pcm, flags);
+	line_count = 0;
+	pcm_mask = 0;
+	for(i = 0; i < MAX_SUBUNIT; i++) {
+		xpd_t		*sub_xpd = xpd_byaddr(xbus, main_xpd->addr.unit, i);
+
+		if(sub_xpd) {
+			xpp_line_t	lines =
+				sub_xpd->offhook_state & ~sub_xpd->digital_signalling;
+
+			if(lines) {
+				pcm_mask |= PCM_SHIFT(lines, i);
+				line_count += 2;
+			}
+			/* subunits have fake pcm_len and wanted_pcm_mask */
+			if(i > 0) {
+				sub_xpd->pcm_len = 0;
+				sub_xpd->wanted_pcm_mask = lines;
+			}
+		}
+	}
+	/*
+	 * FIXME: Workaround a bug in sync code of the Astribank.
+	 *        Send dummy PCM for sync.
+	 */
+	if(main_xpd->addr.unit == 0 && line_count == 0) {
+		pcm_mask = BIT(0);
+		line_count = 1;
+	}
+	/*
+	 * The main unit account for all subunits (pcm_len and wanted_pcm_mask).
+	 */
+	main_xpd->pcm_len = (line_count)
+		? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE
+		: 0L;
+	main_xpd->wanted_pcm_mask = pcm_mask;
+	XPD_DBG(SIGNAL, main_xpd, "pcm_len=%d wanted_pcm_mask=0x%X (%s)\n",
+		main_xpd->pcm_len, main_xpd->wanted_pcm_mask,
+		xpd->xpdname);
+	spin_unlock_irqrestore(&main_xpd->lock_recompute_pcm, flags);
+}
+
+static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
 {
 	byte		*pcm;
-	struct zt_chan	*chans;
 	unsigned long	flags;
 	int		i;
 	int		subunit;
 	xpp_line_t	pcm_mask = 0;
+	xpp_line_t	wanted_lines;
 
 
 	BUG_ON(!xbus);
@@ -1087,18 +1142,20 @@
 		if(!tmp_xpd || !tmp_xpd->card_present)
 			continue;
 		spin_lock_irqsave(&tmp_xpd->lock, flags);
-		chans = tmp_xpd->span.chans;
+		wanted_lines = tmp_xpd->wanted_pcm_mask;
 		for_each_line(tmp_xpd, i) {
+			struct zt_chan	*chan = XPD_CHAN(tmp_xpd, i);
+
 			if(IS_SET(wanted_lines, i)) {
 				if(SPAN_REGISTERED(tmp_xpd)) {
 #ifdef	DEBUG_PCMTX
-					int	channo = tmp_xpd->span.chans[i].channo;
+					int	channo = chan->channo;
 
 					if(pcmtx >= 0 && pcmtx_chan == channo)
 						memset((u_char *)pcm, pcmtx, ZT_CHUNKSIZE);
 					else
 #endif
-						memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE);
+						memcpy((u_char *)pcm, chan->writechunk, ZT_CHUNKSIZE);
 				} else
 					memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE);
 				pcm += ZT_CHUNKSIZE;
@@ -1142,7 +1199,7 @@
 			volatile u_char	*r;
 
 			if(IS_SET(tmp_mask, i)) {
-				r = tmp_xpd->span.chans[i].readchunk;
+				r = XPD_CHAN(tmp_xpd, i)->readchunk;
 				// memset((u_char *)r, 0x5A, ZT_CHUNKSIZE);	// DEBUG
 				memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
 				pcm += ZT_CHUNKSIZE;
@@ -1395,9 +1452,11 @@
 		.card_zaptel_postregistration	= BRI_card_zaptel_postregistration,
 		.card_hooksig	= BRI_card_hooksig,
 		.card_tick	= BRI_card_tick,
+		.card_pcm_recompute	= BRI_card_pcm_recompute,
 		.card_pcm_fromspan	= BRI_card_pcm_fromspan,
 		.card_pcm_tospan	= BRI_card_pcm_tospan,
 		.card_ioctl	= BRI_card_ioctl,
+		.card_open	= BRI_card_open,
 		.card_close	= BRI_card_close,
 		.card_register_reply	= BRI_card_register_reply,
 

Modified: branches/1.4/kernel/xpp/card_fxo.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/xpp/card_fxo.c?view=diff&rev=4590&r1=4589&r2=4590
==============================================================================
--- branches/1.4/kernel/xpp/card_fxo.c (original)
+++ branches/1.4/kernel/xpp/card_fxo.c Sun Nov 30 06:10:03 2008
@@ -175,6 +175,27 @@
 
 /*---------------- FXO: Static functions ----------------------------------*/
 
+static const char *power2str(enum power_state pw)
+{
+	switch(pw) {
+		case POWER_UNKNOWN:	return "UNKOWN";
+		case POWER_OFF:		return "OFF";
+		case POWER_ON:		return "ON";
+	}
+	return NULL;
+}
+
+static void power_change(xpd_t *xpd, int portno, enum power_state pw)
+{
+	struct FXO_priv_data	*priv;
+
+	priv = xpd->priv;
+	LINE_DBG(SIGNAL, xpd, portno, "power: %s -> %s\n",
+			power2str(priv->power[portno]),
+			power2str(pw));
+	priv->power[portno] = pw;
+}
+
 static void reset_battery_readings(xpd_t *xpd, lineno_t pos)
 {
 	struct FXO_priv_data	*priv = xpd->priv;
@@ -265,30 +286,15 @@
 
 static void update_zap_ring(xpd_t *xpd, int pos, bool on)
 {
-	zt_rxsig_t	rxsig;
-
-	BUG_ON(!xpd);
-	if(on) {
-		if(caller_id_style == CID_STYLE_BELL) {
-			LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: off\n");
-			BIT_CLR(xpd->cid_on, pos);
-		}
-		rxsig = ZT_RXSIG_RING;
-	} else {
-		if(caller_id_style == CID_STYLE_BELL) {
-			LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: on\n");
-			BIT_SET(xpd->cid_on, pos);
-		}
-		rxsig = ZT_RXSIG_OFFHOOK;
-	}
-	pcm_recompute(xpd, 0);
+	BUG_ON(!xpd);
+	if(caller_id_style == CID_STYLE_BELL)
+		oht_pcm(xpd, pos, !on);
 	/*
 	 * We should not spinlock before calling zt_hooksig() as
 	 * it may call back into our xpp_hooksig() and cause
 	 * a nested spinlock scenario
 	 */
-	if(SPAN_REGISTERED(xpd))
-		zt_hooksig(&xpd->chans[pos], rxsig);
+	notify_rxsig(xpd, pos, (on) ? ZT_RXSIG_RING : ZT_RXSIG_OFFHOOK);
 }
 
 static void mark_ring(xpd_t *xpd, lineno_t pos, bool on, bool update_zap)
@@ -349,15 +355,9 @@
 	else
 		MARK_OFF(priv, pos, LED_GREEN);
 	ret = DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, REG_DAA_CONTROL1, value);
-	if(to_offhook) {
-		BIT_SET(xpd->offhook, pos);
-	} else {
-		BIT_CLR(xpd->offhook, pos);
-	}
-	if(caller_id_style != CID_STYLE_ETSI_DTMF) {
-		LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: off\n");
-		BIT_CLR(xpd->cid_on, pos);
-	}
+	mark_offhook(xpd, pos, to_offhook);
+	if(caller_id_style != CID_STYLE_ETSI_DTMF)
+		oht_pcm(xpd, pos, 0);
 #ifdef	WITH_METERING
 	priv->metering_count[pos] = 0;
 	priv->metering_tone_state = 0L;
@@ -366,7 +366,7 @@
 	reset_battery_readings(xpd, pos);	/* unstable during hook changes */
 	priv->power_denial_safezone[pos] = (to_offhook) ? POWER_DENIAL_SAFEZONE : 0;
 	if(!to_offhook)
-		priv->power[pos] = POWER_UNKNOWN;
+		power_change(xpd, pos, POWER_UNKNOWN);
 	priv->cidtimer[pos] = xpd->timer_count;
 	spin_unlock_irqrestore(&xpd->lock, flags);
 	return ret;
@@ -469,10 +469,11 @@
 	for_each_line(xpd, i) {
 		do_sethook(xpd, i, 0);
 		priv->polarity[i] = POL_UNKNOWN;	/* will be updated on next battery sample */
+		priv->polarity_debounce[i] = 0;
 		priv->battery[i] = BATTERY_UNKNOWN;	/* will be updated on next battery sample */
 		priv->power[i] = POWER_UNKNOWN;	/* will be updated on next battery sample */
 		if(caller_id_style == CID_STYLE_ETSI_DTMF)
-			BIT_SET(xpd->cid_on, i);
+			oht_pcm(xpd, i, 1);
 	}
 	XPD_DBG(GENERAL, xpd, "done\n");
 	for_each_line(xpd, i) {
@@ -486,7 +487,7 @@
 		do_led(xpd, i, LED_GREEN, 0);
 		msleep(50);
 	}
-	pcm_recompute(xpd, 0);
+	CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0);
 	return 0;
 }
 
@@ -519,7 +520,7 @@
 	xpd->span.spantype = "FXO";
 #endif 
 	for_each_line(xpd, i) {
-		struct zt_chan	*cur_chan = &xpd->chans[i];
+		struct zt_chan	*cur_chan = XPD_CHAN(xpd, i);
 
 		XPD_DBG(GENERAL, xpd, "setting FXO channel %d\n", i);
 		snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXO/%02d/%1d%1d/%d",
@@ -585,7 +586,6 @@
 				txsig2str(txsig), txsig);
 			return -EINVAL;
 	}
-	pcm_recompute(xpd, 0);
 	return ret;
 }
 
@@ -602,11 +602,11 @@
 				break;
 			case BATTERY_OFF:
 				LINE_DBG(SIGNAL, xpd, chan, "Send ZT_ALARM_RED\n");
-				zt_alarm_channel(&xpd->chans[chan], ZT_ALARM_RED);
+				zt_alarm_channel(XPD_CHAN(xpd, chan), ZT_ALARM_RED);
 				break;
 			case BATTERY_ON:
 				LINE_DBG(SIGNAL, xpd, chan, "Send ZT_ALARM_NONE\n");
-				zt_alarm_channel(&xpd->chans[chan], ZT_ALARM_NONE);
+				zt_alarm_channel(XPD_CHAN(xpd, chan), ZT_ALARM_NONE);
 				break;
 		}
 	}
@@ -636,7 +636,7 @@
 	int	i;
 
 	for_each_line(xpd, i) {
-		if (IS_SET(xpd->offhook, i))
+		if (IS_OFFHOOK(xpd, i))
 			DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_METERING, 0);
 	}
 }
@@ -689,7 +689,7 @@
 				DAA_DIRECT_REQUEST(xpd->xbus, xpd, i, DAA_READ, DAA_REG_CURRENT, 0);
 			}
 		}
-		if(IS_SET(priv->maybe_power_denial, i) && !xpd->ringing[i] && IS_SET(xpd->offhook, i)) {
+		if(IS_SET(priv->maybe_power_denial, i) && !xpd->ringing[i] && IS_OFFHOOK(xpd, i)) {
 			/*
 			 * Ring detection by the firmware takes some time.
 			 * Therefore we delay our decision until we are
@@ -700,9 +700,10 @@
 				LINE_DBG(SIGNAL, xpd, i, "Power Denial Hangup\n");
 				priv->power_denial_delay[i] = 0;
 				BIT_CLR(priv->maybe_power_denial, i);
-				do_sethook(xpd, i, 0);
-				update_line_status(xpd, i, 0);
-				pcm_recompute(xpd, 0);
+				/*
+				 * Let Asterisk decide what to do
+				 */
+				notify_rxsig(xpd, i, ZT_RXSIG_ONHOOK);
 			}
 		} else {
 			priv->power_denial_delay[i] = 0;
@@ -731,7 +732,7 @@
 	timer_count = xpd->timer_count;
 	for_each_line(xpd, portno) {
 		/* Skip offhook and ringing ports */
-		if(IS_SET(xpd->offhook, portno) || xpd->ringing[portno])
+		if(IS_OFFHOOK(xpd, portno) || xpd->ringing[portno])
 			continue;
 		if(IS_SET(priv->cidfound, portno)) {
 			if(timer_count > priv->cidtimer[portno] + 4000) {
@@ -743,7 +744,7 @@
 			continue;
 		}
 		if(timer_count > priv->cidtimer[portno] + 400) {
-			struct zt_chan	*chan = &xpd->span.chans[portno];
+			struct zt_chan	*chan = XPD_CHAN(xpd, portno);
 			int		sample;
 			int		i;
 
@@ -922,8 +923,11 @@
 				priv->battery[portno] = BATTERY_OFF;
 				if(SPAN_REGISTERED(xpd))
 					zap_report_battery(xpd, portno);
-				priv->polarity[portno] = POL_UNKNOWN;	/* What's the polarity ? */
-				priv->power[portno] = POWER_UNKNOWN;	/* What's the current ? */
+				/* What's the polarity ? */
+				priv->polarity[portno] = POL_UNKNOWN;
+				priv->polarity_debounce[portno] = 0;
+				/* What's the current ? */
+				power_change(xpd, portno, POWER_UNKNOWN);
 				/*
 				 * Stop further processing for now
 				 */
@@ -976,7 +980,7 @@
 	msec = priv->polarity_debounce[portno]++ * poll_battery_interval;
 	if (msec >= POLREV_THRESHOLD) {
 		priv->polarity_debounce[portno] = 0;
-		if(pol != POL_UNKNOWN) {
+		if(pol != POL_UNKNOWN && priv->polarity[portno] != POL_UNKNOWN) {
 			char	*polname = NULL;
 
 			if(pol == POL_POSITIVE)
@@ -993,14 +997,12 @@
 			 * 2. In some countries used to report caller-id during onhook
 			 *    but before first ring.
 			 */
-			if(caller_id_style == CID_STYLE_ETSI_FSK) {
-				LINE_DBG(SIGNAL, xpd, portno, "Caller-ID PCM: on\n");
-				BIT_SET(xpd->cid_on, portno);	/* will be cleared on ring/offhook */
-			}
+			if(caller_id_style == CID_STYLE_ETSI_FSK)
+				oht_pcm(xpd, portno, 1);	/* will be cleared on ring/offhook */
 			if(SPAN_REGISTERED(xpd)) {
 				LINE_DBG(SIGNAL, xpd, portno,
 					"Send ZT_EVENT_POLARITY: %s\n", polname);
-				zt_qevent_lock(&xpd->chans[portno], ZT_EVENT_POLARITY);
+				zt_qevent_lock(XPD_CHAN(xpd, portno), ZT_EVENT_POLARITY);
 			}
 		}
 		priv->polarity[portno] = pol;
@@ -1024,7 +1026,7 @@
 	 * During ringing, current is not stable.
 	 * During onhook there should not be current anyway.
 	 */
-	if(xpd->ringing[portno] || !IS_SET(xpd->offhook, portno))
+	if(xpd->ringing[portno] || !IS_OFFHOOK(xpd, portno))
 		goto ignore_it;
 	/*
 	 * Power denial with no battery voltage is meaningless
@@ -1036,15 +1038,16 @@
 		goto ignore_it;
 	if(data_low < POWER_DENIAL_CURRENT) {
 		if(priv->power[portno] == POWER_ON) {
-			LINE_DBG(SIGNAL, xpd, portno, "power: ON -> OFF\n");
-			priv->power[portno] = POWER_OFF;
+			power_change(xpd, portno, POWER_OFF);
 			priv->power_denial_minimum[portno] = POWER_DENIAL_TIME;
 		}
 	} else {
-		LINE_DBG(SIGNAL, xpd, portno, "power: ON\n");
-		priv->power[portno] = POWER_ON;
-		priv->power_denial_minimum[portno] = 0;
-		update_line_status(xpd, portno, 1);
+		if(priv->power[portno] != POWER_ON) {
+			power_change(xpd, portno, POWER_ON);
+			priv->power_denial_minimum[portno] = 0;
+			/* We are now OFFHOOK */
+			hookstate_changed(xpd, portno, 1);
+		}
 	}
 	return;
 ignore_it:
@@ -1135,6 +1138,7 @@
 		.card_zaptel_postregistration	= FXO_card_zaptel_postregistration,
 		.card_hooksig	= FXO_card_hooksig,
 		.card_tick	= FXO_card_tick,
+		.card_pcm_recompute	= generic_card_pcm_recompute,
 		.card_pcm_fromspan	= generic_card_pcm_fromspan,
 		.card_pcm_tospan	= generic_card_pcm_tospan,
 		.card_ioctl	= FXO_card_ioctl,

Modified: branches/1.4/kernel/xpp/card_fxs.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/xpp/card_fxs.c?view=diff&rev=4590&r1=4589&r2=4590
==============================================================================
--- branches/1.4/kernel/xpp/card_fxs.c (original)
+++ branches/1.4/kernel/xpp/card_fxs.c Sun Nov 30 06:10:03 2008
@@ -172,6 +172,21 @@
 	BUG_ON(!xpd);
 	LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on) ? "up" : "down");
 	return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_BATTERY, value);
+}
+
+static void vmwi_search(xpd_t *xpd, lineno_t pos, bool on)
+{
+	struct FXS_priv_data	*priv;
+
+	priv = xpd->priv;
+	BUG_ON(!xpd);
+	if(vmwineon && on) {
+		LINE_DBG(SIGNAL, xpd, pos, "START\n");
+		BIT_SET(priv->search_fsk_pattern, pos);
+	} else {
+		LINE_DBG(SIGNAL, xpd, pos, "STOP\n");
+		BIT_CLR(priv->search_fsk_pattern, pos);
+	}
 }
 
 /*
@@ -286,7 +301,7 @@
 
 	priv = xpd->priv;
 	for_each_line(xpd, i) {
-		if(IS_SET(xpd->offhook, i))
+		if(IS_OFFHOOK(xpd, i))
 			MARK_ON(priv, i, LED_GREEN);
 		else
 			MARK_OFF(priv, i, LED_GREEN);
@@ -438,7 +453,7 @@
 		msleep(50);
 	}
 	restore_leds(xpd);
-	pcm_recompute(xpd, 0);
+	CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0);
 	/*
 	 * We should query our offhook state long enough time after we
 	 * set the linefeed_control()
@@ -483,7 +498,7 @@
 	xpd->span.spantype = "FXS";
 #endif 
 	for_each_line(xpd, i) {
-		struct zt_chan	*cur_chan = &xpd->chans[i];
+		struct zt_chan	*cur_chan = XPD_CHAN(xpd, i);
 
 		XPD_DBG(GENERAL, xpd, "setting FXS channel %d\n", i);
 		if(IS_SET(xpd->digital_outputs, i)) {
@@ -540,19 +555,18 @@
 		BIT_SET(xpd->mute_dtmf, pos);
 	else
 		BIT_CLR(xpd->mute_dtmf, pos);
-}
-
-static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
+	CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0);	/* already spinlocked */
+}
+
+static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, bool msg_waiting)
 {
 	int	ret = 0;
 	BUG_ON(!xbus);
 	BUG_ON(!xpd);
 
-	LINE_DBG(SIGNAL, xpd, pos, "%s%s\n", (on)?"ON":"OFF", (vmwineon)?"":" (Ignored)");
-	if (!vmwineon)
-		return 0;
-	if (on) {
+	if (vmwineon && msg_waiting) {
 		/* A write to register 0x40 will now turn on/off the VM led */
+		LINE_DBG(SIGNAL, xpd, pos, "NEON\n");
 		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xE8, 0x03);
 		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xEF, 0x7B);
 		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x9F, 0x00);
@@ -565,6 +579,7 @@
 		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x46);
 	} else {
 		/* A write to register 0x40 will now turn on/off the ringer */
+		LINE_DBG(SIGNAL, xpd, pos, "RINGER\n");
 		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0x00, 0x00);
 		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0x60, 0x01);
 		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0xF0, 0x7E);
@@ -576,7 +591,6 @@
 		ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00);
 		ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36);
 	}
-
 	return (ret ? -EPROTO : 0);
 }
 
@@ -586,7 +600,7 @@
 	bool		on;
 
 	BUG_ON(!xpd);
-	if (!vmwineon || IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos))
+	if (IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos))
 		return;
 	priv = xpd->priv;
 	on = IS_SET(xpd->msg_waiting, pos);
@@ -655,17 +669,16 @@
 		return 0;
 	}
 	if(SPAN_REGISTERED(xpd))
-		chan = &xpd->span.chans[pos];
+		chan = XPD_CHAN(xpd, pos);
 	switch(txsig) {
 		case ZT_TXSIG_ONHOOK:
 			spin_lock_irqsave(&xpd->lock, flags);
 			xpd->ringing[pos] = 0;
-			BIT_CLR(xpd->cid_on, pos);
-			BIT_CLR(priv->search_fsk_pattern, pos);
+			oht_pcm(xpd, pos, 0);
+			vmwi_search(xpd, pos, 0);
 			BIT_CLR(priv->want_dtmf_events, pos);
 			BIT_CLR(priv->want_dtmf_mute, pos);
 			__do_mute_dtmf(xpd, pos, 0);
-			__pcm_recompute(xpd, 0);	/* already spinlocked */
 			spin_unlock_irqrestore(&xpd->lock, flags);
 			if(IS_SET(xpd->digital_outputs, pos)) {
 				LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output OFF\n", txsig2str(txsig));
@@ -678,11 +691,11 @@
 				 */
 				LINE_DBG(SIGNAL, xpd, pos, "KEWL STOP\n");
 				linefeed_control(xbus, xpd, pos, FXS_LINE_POL_ACTIVE);
-				if(IS_SET(xpd->offhook, pos))
+				if(IS_OFFHOOK(xpd, pos))
 					MARK_ON(priv, pos, LED_GREEN);
 			}
 			ret = send_ring(xpd, pos, 0);			// RING off
-			if (!IS_SET(xpd->offhook, pos))
+			if (!IS_OFFHOOK(xpd, pos))
 				start_stop_vm_led(xbus, xpd, pos);
 			txhook = priv->lasttxhook[pos];
 			if(chan) {
@@ -706,8 +719,7 @@
 			}
 			txhook = priv->lasttxhook[pos];
 			if(xpd->ringing[pos]) {
-				BIT_SET(xpd->cid_on, pos);
-				pcm_recompute(xpd, 0);
+				oht_pcm(xpd, pos, 1);
 				txhook = FXS_LINE_OHTRANS;
 			}
 			xpd->ringing[pos] = 0;
@@ -725,9 +737,8 @@
 			break;
 		case ZT_TXSIG_START:
 			xpd->ringing[pos] = 1;
-			BIT_CLR(xpd->cid_on, pos);
-			BIT_CLR(priv->search_fsk_pattern, pos);
-			pcm_recompute(xpd, 0);
+			oht_pcm(xpd, pos, 0);
+			vmwi_search(xpd, pos, 0);
 			if(IS_SET(xpd->digital_outputs, pos)) {
 				LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output ON\n", txsig2str(txsig));
 				ret = relay_out(xpd, pos, 1);
@@ -782,14 +793,15 @@
 			LINE_DBG(SIGNAL, xpd, pos, "ZT_ONHOOKTRANSFER (%d millis)\n", val);
 			if (IS_SET(xpd->digital_inputs | xpd->digital_outputs, pos))
 				return 0;	/* Nothing to do */
-			BIT_CLR(xpd->cid_on, pos);
+			oht_pcm(xpd, pos, 1);	/* Get ready of VMWI FSK tones */
 			if(priv->lasttxhook[pos] == FXS_LINE_POL_ACTIVE) {
-				priv->ohttimer[pos] = OHT_TIMER;
+				priv->ohttimer[pos] = val;
 				priv->idletxhookstate[pos] = FXS_LINE_POL_OHTRANS;
-				BIT_SET(priv->search_fsk_pattern, pos);
-				pcm_recompute(xpd, priv->search_fsk_pattern);
-			}
-			if(!IS_SET(xpd->offhook, pos))
+				vmwi_search(xpd, pos, 1);
+				CALL_XMETHOD(card_pcm_recompute, xbus, xpd, priv->search_fsk_pattern);
+				LINE_DBG(SIGNAL, xpd, pos, "Start OHT_TIMER. wanted_pcm_mask=0x%X\n", xpd->wanted_pcm_mask);
+			}
+			if(vmwineon && !IS_OFFHOOK(xpd, pos))
 				start_stop_vm_led(xbus, xpd, pos);
 			return 0;
 		case ZT_TONEDETECT:
@@ -808,7 +820,6 @@
 				BIT_CLR(priv->want_dtmf_events, pos);
 				BIT_CLR(priv->want_dtmf_mute, pos);
 				__do_mute_dtmf(xpd, pos, 0);
-				__pcm_recompute(xpd, 0);	/* already spinlocked */
 				spin_unlock_irqrestore(&xpd->lock, flags);
 				return -ENOTTY;
 			}
@@ -840,7 +851,6 @@
 			} else {
 				BIT_CLR(priv->want_dtmf_mute, pos);
 				__do_mute_dtmf(xpd, pos, 0);
-				__pcm_recompute(xpd, 0);
 			}
 			spin_unlock_irqrestore(&xpd->lock, flags);
 			return 0;
@@ -886,12 +896,10 @@
 static int FXS_card_open(xpd_t *xpd, lineno_t chan)
 {
 	struct FXS_priv_data	*priv;
-	bool			is_offhook;
-
-	BUG_ON(!xpd);
-	priv = xpd->priv;
-	is_offhook = IS_SET(xpd->offhook, chan);
-	if(is_offhook)
+
+	BUG_ON(!xpd);
+	priv = xpd->priv;
+	if(IS_OFFHOOK(xpd, chan))
 		LINE_NOTICE(xpd, chan, "Already offhook during open. OK.\n");
 	else
 		LINE_DBG(SIGNAL, xpd, chan, "is onhook\n");
@@ -957,10 +965,10 @@
 			if (priv->ohttimer[i]) {
 				priv->ohttimer[i]--;
 				if (!priv->ohttimer[i]) {
+					LINE_DBG(SIGNAL, xpd, i, "ohttimer expired\n");
 					priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE;
-					BIT_CLR(xpd->cid_on, i);
-					BIT_CLR(priv->search_fsk_pattern, i);
-					pcm_recompute(xpd, 0);
+					oht_pcm(xpd, i, 0);
+					vmwi_search(xpd, i, 0);
 					if (priv->lasttxhook[i] == FXS_LINE_POL_OHTRANS) {
 						/* Apply the change if appropriate */
 						linefeed_control(xpd->xbus, xpd, i, FXS_LINE_POL_ACTIVE);
@@ -996,16 +1004,23 @@
 	static const byte	FSK_ON_PATTERN[] = { 0xA2, 0x2C, 0x1F, 0x2C, 0xBB, 0xA1, 0xA5, 0xFF };
 	static const byte	FSK_OFF_PATTERN[] = { 0xA2, 0x2C, 0x28, 0xA5, 0xB1, 0x21, 0x49, 0x9F };
 	int			i;
+	xpp_line_t		ignore_mask;
 
 	BUG_ON(!xpd);
 	xbus = xpd->xbus;
 	priv = xpd->priv;
 	BUG_ON(!priv);
+	ignore_mask =
+		xpd->offhook_state |
+		~xpd->oht_pcm_pass |
+		~priv->search_fsk_pattern |
+		xpd->digital_inputs |
+		xpd->digital_outputs;
 	for_each_line(xpd, i) {
-		struct zt_chan	*chan = &xpd->span.chans[i];
+		struct zt_chan	*chan = XPD_CHAN(xpd, i);
 		byte		*writechunk = chan->writechunk;
 
-		if(IS_SET(xpd->offhook | xpd->cid_on | xpd->digital_inputs | xpd->digital_outputs, i))
+		if(IS_SET(ignore_mask, i))
 			continue;
 #if 0
 		if(writechunk[0] != 0x7F && writechunk[0] != 0) {
@@ -1020,10 +1035,12 @@
 				printk("\n");
 		}
 #endif
-		if(unlikely(mem_equal(writechunk, FSK_COMMON_PATTERN, ZT_CHUNKSIZE)))
+		if(unlikely(mem_equal(writechunk, FSK_COMMON_PATTERN, ZT_CHUNKSIZE))) {
+			LINE_DBG(SIGNAL, xpd, i, "Found common FSK pattern. Start looking for ON/OFF patterns.\n");
 			BIT_SET(priv->found_fsk_pattern, i);
-		else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) {
+		} else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) {
 			BIT_CLR(priv->found_fsk_pattern, i);
+			oht_pcm(xpd, i, 0);
 			if(unlikely(mem_equal(writechunk, FSK_ON_PATTERN, ZT_CHUNKSIZE))) {
 				LINE_DBG(SIGNAL, xpd, i, "MSG WAITING ON\n");
 				BIT_SET(xpd->msg_waiting, i);
@@ -1060,25 +1077,27 @@
 #endif
 	handle_fxs_leds(xpd);
 	handle_linefeed(xpd);
-	if(priv->update_offhook_state) {	/* set in FXS_card_open() */
-		int	i;
+	/*
+	 * Hack alert (FIXME):
+	 *   Asterisk did FXS_card_open() and we wanted to report
+	 *   offhook state. However, the channel is spinlocked by zaptel
+	 *   so we marked it in the priv->update_offhook_state mask and
+	 *   now we take care of notification to zaptel and Asterisk
+	 */
+	if(priv->update_offhook_state) {
+		zt_rxsig_t	rxsig;
+		int		i;
 
 		for_each_line(xpd, i) {
 			if(!IS_SET(priv->update_offhook_state, i))
 				continue;
-			/*
-			 * Update zaptel with current state of line.
-			 */
-			if(IS_SET(xpd->offhook, i)) {
-				update_line_status(xpd, i, 1);
-			} else {
-				update_line_status(xpd, i, 0);
-			}
+			rxsig = IS_OFFHOOK(xpd, i) ? ZT_RXSIG_OFFHOOK : ZT_RXSIG_ONHOOK;
+			notify_rxsig(xpd, i, rxsig);	/* Notify after open() */
 			BIT_CLR(priv->update_offhook_state, i);
 		}
 	}
 	if(SPAN_REGISTERED(xpd)) {
-		if(vmwineon && !vmwi_ioctl)
+		if(vmwineon && !vmwi_ioctl && priv->search_fsk_pattern)
 			detect_vmwi(xpd);	/* Detect via FSK modulation */
 	}
 	return 0;
@@ -1127,11 +1146,11 @@
 			if(IS_SET(offhook, i)) {
 				LINE_DBG(SIGNAL, xpd, i, "OFFHOOK\n");
 				MARK_ON(priv, i, LED_GREEN);
-				update_line_status(xpd, i, 1);
+				hookstate_changed(xpd, i, 1);
 			} else {
 				LINE_DBG(SIGNAL, xpd, i, "ONHOOK\n");
 				MARK_OFF(priv, i, LED_GREEN);
-				update_line_status(xpd, i, 0);
+				hookstate_changed(xpd, i, 0);
 			}
 			/*
 			 * Must switch to low power. In high power, an ONHOOK
@@ -1140,7 +1159,6 @@
 			do_chan_power(xbus, xpd, i, 0);
 		}
 	}
-	__pcm_recompute(xpd, 0);	/* in a spinlock */
 }
 
 HANDLER_DEF(FXS, SIG_CHANGED)
@@ -1182,12 +1200,12 @@
 			BIT_CLR(lines, channo);
 			BIT_SET(lines, newchanno);
 			xpd->ringing[newchanno] = 0;			// Stop ringing. No leds for digital inputs.
-			if(offhook && !IS_SET(xpd->offhook, newchanno)) {		// OFFHOOK
+			if(offhook && !IS_OFFHOOK(xpd, newchanno)) {		// OFFHOOK
 				LINE_DBG(SIGNAL, xpd, newchanno, "OFFHOOK\n");
-				update_line_status(xpd, newchanno, 1);
-			} else if(!offhook && IS_SET(xpd->offhook, newchanno)) {	// ONHOOK
+				hookstate_changed(xpd, newchanno, 1);
+			} else if(!offhook && IS_OFFHOOK(xpd, newchanno)) {	// ONHOOK
 				LINE_DBG(SIGNAL, xpd, newchanno, "ONHOOK\n");
-				update_line_status(xpd, newchanno, 0);
+				hookstate_changed(xpd, newchanno, 0);
 			}
 		}
 	}
@@ -1253,11 +1271,10 @@
 		__do_mute_dtmf(xpd, portnum, 1);
 	else
 		__do_mute_dtmf(xpd, portnum, 0);
-	__pcm_recompute(xpd, 0);	/* XPD is locked */
 	if(want_event)  {
 		int	event = (key_down) ? ZT_EVENT_DTMFDOWN : ZT_EVENT_DTMFUP;
 
-		zt_qevent_lock(&xpd->chans[portnum], event | digit);
+		zt_qevent_lock(XPD_CHAN(xpd, portnum), event | digit);
 	}
 }
 
@@ -1334,6 +1351,7 @@
 		.card_zaptel_postregistration	= FXS_card_zaptel_postregistration,
 		.card_hooksig	= FXS_card_hooksig,
 		.card_tick	= FXS_card_tick,
+		.card_pcm_recompute	= generic_card_pcm_recompute,
 		.card_pcm_fromspan	= generic_card_pcm_fromspan,
 		.card_pcm_tospan	= generic_card_pcm_tospan,
 		.card_open	= FXS_card_open,

Modified: branches/1.4/kernel/xpp/card_pri.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/xpp/card_pri.c?view=diff&rev=4590&r1=4589&r2=4590
==============================================================================
--- branches/1.4/kernel/xpp/card_pri.c (original)
+++ branches/1.4/kernel/xpp/card_pri.c Sun Nov 30 06:10:03 2008
@@ -1037,7 +1037,7 @@
 	xpd->span.linecompat = pri_linecompat(priv->pri_protocol);
 	xpd->span.deflaw = priv->deflaw;
 	for_each_line(xpd, i) {
-		struct zt_chan	*cur_chan = &xpd->chans[i];
+		struct zt_chan	*cur_chan = XPD_CHAN(xpd, i);
 		bool		is_dchan = i == PRI_DCHAN_IDX(priv);
 
 		XPD_DBG(GENERAL, xpd, "setting PRI channel %d (%s)\n", i,
@@ -1053,7 +1053,7 @@
 		} else
 			cur_chan->sigcap = PRI_BCHAN_SIGCAP;
 	}
-	xpd->offhook = xpd->wanted_pcm_mask;
+	xpd->offhook_state = xpd->wanted_pcm_mask;
 	xpd->span.spanconfig = pri_spanconfig;
 	xpd->span.chanconfig = pri_chanconfig;
 	xpd->span.startup = pri_startup;
@@ -1102,9 +1102,9 @@
 		if(SPAN_REGISTERED(xpd) && d >= 0 && d < xpd->channels) {
 			byte	*pcm;
 
-			pcm = (byte *)xpd->span.chans[d].readchunk;
+			pcm = (byte *)XPD_CHAN(xpd, d)->readchunk;
 			pcm[0] = 0x00;
-			pcm = (byte *)xpd->span.chans[d].writechunk;
+			pcm = (byte *)XPD_CHAN(xpd, d)->writechunk;
 			pcm[0] = 0x00;
 		}
 		XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n");
@@ -1233,7 +1233,7 @@
 
 static int PRI_card_close(xpd_t *xpd, lineno_t pos)
 {
-	//struct zt_chan	*chan = &xpd->span.chans[pos];
+	//struct zt_chan	*chan = XPD_CHAN(xpd, pos);
 	dchan_state(xpd, 0);
 	return 0;
 }
@@ -1342,13 +1342,13 @@
  * send 31 channels to the device, but they should be called 1-31 rather
  * than 0-30 .
  */
-static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack)
+static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
 {
 	struct PRI_priv_data	*priv;
 	byte			*pcm;
-	struct zt_chan		*chans;
 	unsigned long		flags;
 	int			i;
+	xpp_line_t		wanted_lines;
 	int			physical_chan;
 	int			physical_mask = 0;
 
@@ -1359,9 +1359,11 @@
 	BUG_ON(!priv);
 	pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
 	spin_lock_irqsave(&xpd->lock, flags);
-	chans = xpd->span.chans;
+	wanted_lines = xpd->wanted_pcm_mask;
 	physical_chan = 0;
 	for_each_line(xpd, i) {
+		struct zt_chan	*chan = XPD_CHAN(xpd, i);
+
 		if(priv->pri_protocol == PRI_PROTO_E1) {
 			/* In E1 - Only 0'th channel is unused */
 			if(i == 0) {
@@ -1373,28 +1375,28 @@
 				physical_chan++;
 			}
 		}
-		if(IS_SET(lines, i)) {
+		if(IS_SET(wanted_lines, i)) {
 			physical_mask |= BIT(physical_chan);
 			if(SPAN_REGISTERED(xpd)) {
 #ifdef	DEBUG_PCMTX
-				int	channo = xpd->span.chans[i].channo;
+				int	channo = XPD_CHAN(xpd, i)->channo;
 
 				if(pcmtx >= 0 && pcmtx_chan == channo)
 					memset((u_char *)pcm, pcmtx, ZT_CHUNKSIZE);
 				else
 #endif
-					memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE);
+					memcpy((u_char *)pcm, chan->writechunk, ZT_CHUNKSIZE);
 				if(i == PRI_DCHAN_IDX(priv)) {
-					if(priv->dchan_tx_sample != chans[i].writechunk[0]) {
-						priv->dchan_tx_sample = chans[i].writechunk[0];
+					if(priv->dchan_tx_sample != chan->writechunk[0]) {
+						priv->dchan_tx_sample = chan->writechunk[0];
 						priv->dchan_tx_counter++;
-					} else if(chans[i].writechunk[0] == 0xFF)
+					} else if(chan->writechunk[0] == 0xFF)
 						dchan_state(xpd, 0);
 					else
-						chans[i].writechunk[0] = 0xFF;	/* Clobber for next tick */
+						chan->writechunk[0] = 0xFF;	/* Clobber for next tick */
 				}
 			} else
-				memset((u_char *)pcm, ZT_XLAW(0, (&chans[i])), ZT_CHUNKSIZE);
+				memset((u_char *)pcm, ZT_XLAW(0, chan), ZT_CHUNKSIZE);
 			pcm += ZT_CHUNKSIZE;
 		}
 		physical_chan++;
@@ -1418,7 +1420,6 @@
 {
 	struct PRI_priv_data	*priv;
 	byte			*pcm;
-	struct zt_chan		*chans;
 	xpp_line_t		physical_mask;
 	unsigned long		flags;
 	int			i;
@@ -1431,7 +1432,6 @@
 	pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm);
 	physical_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines);
 	spin_lock_irqsave(&xpd->lock, flags);
-	chans = xpd->span.chans;
 	logical_chan = 0;
 	for (i = 0; i < CHANNELS_PERXPD; i++) {
 		volatile u_char	*r;
@@ -1458,9 +1458,8 @@
 				dchan_state(xpd, 0);
 		}
 		if(IS_SET(physical_mask, i)) {
-			r = chans[logical_chan].readchunk;
+			r = XPD_CHAN(xpd, logical_chan)->readchunk;
 			// memset((u_char *)r, 0x5A, ZT_CHUNKSIZE);	// DEBUG
-			// fill_beep((u_char *)r, 1, 1);	// DEBUG: BEEP
 			memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
 			pcm += ZT_CHUNKSIZE;
 		}
@@ -1576,9 +1575,9 @@
 			rsnum, chan1+1, chan2+1, priv->cas_rs_e[pos], data_low);
 		if(SPAN_REGISTERED(xpd)) {
 			if(old1 != new1)
-				zt_rbsbits(&xpd->span.chans[chan1], new1);
+				zt_rbsbits(XPD_CHAN(xpd, chan1), new1);
 			if(old2 != new2)
-				zt_rbsbits(&xpd->span.chans[chan2], new2);
+				zt_rbsbits(XPD_CHAN(xpd, chan2), new2);
 		}
 		priv->dchan_rx_counter++;
 		priv->cas_rs_e[pos] = data_low;
@@ -1657,6 +1656,7 @@
 		.card_zaptel_postregistration	= PRI_card_zaptel_postregistration,
 		.card_hooksig	= PRI_card_hooksig,
 		.card_tick	= PRI_card_tick,
+		.card_pcm_recompute	= generic_card_pcm_recompute,
 		.card_pcm_fromspan	= PRI_card_pcm_fromspan,
 		.card_pcm_tospan	= PRI_card_pcm_tospan,
 		.card_ioctl	= PRI_card_ioctl,

Modified: branches/1.4/kernel/xpp/xbus-pcm.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/kernel/xpp/xbus-pcm.c?view=diff&rev=4590&r1=4589&r2=4590
==============================================================================
--- branches/1.4/kernel/xpp/xbus-pcm.c (original)
+++ branches/1.4/kernel/xpp/xbus-pcm.c Sun Nov 30 06:10:03 2008
@@ -580,19 +580,18 @@
  * This function is used by FXS/FXO. The pcm_mask argument signifies
  * channels which should be *added* to the automatic calculation.
  * Normally, this argument is 0.
- *
- * The caller should spinlock the XPD before calling it.
  */
-void __pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask)
+void generic_card_pcm_recompute(xbus_t *xbus, xpd_t *xpd, xpp_line_t pcm_mask)
 {
 	int		i;
 	int		line_count = 0;
-
-	XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask);
+	unsigned long	flags;
+
+	spin_lock_irqsave(&xpd->lock_recompute_pcm, flags);
+	//XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask);
 	/* Add/remove all the trivial cases */
-	pcm_mask |= xpd->offhook;
-	pcm_mask |= xpd->cid_on;
-	pcm_mask &= ~xpd->digital_signalling;	/* No PCM in D-Channels */
+	pcm_mask |= xpd->offhook_state;
+	pcm_mask |= xpd->oht_pcm_pass;
 	pcm_mask &= ~xpd->digital_inputs;
 	pcm_mask &= ~xpd->digital_outputs;
 	for_each_line(xpd, i)
@@ -610,18 +609,9 @@
 		? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE
 		: 0L;
 	xpd->wanted_pcm_mask = pcm_mask;
-}
-
-/*
- * A spinlocked version of __pcm_recompute()
- */
-void pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask)
-{
-	unsigned long	flags;
-
-	spin_lock_irqsave(&xpd->lock, flags);
-	__pcm_recompute(xpd, pcm_mask);
-	spin_unlock_irqrestore(&xpd->lock, flags);
+	XPD_DBG(SIGNAL, xpd, "pcm_len=%d wanted_pcm_mask=0x%X\n",
+		xpd->pcm_len, xpd->wanted_pcm_mask);
+	spin_unlock_irqrestore(&xpd->lock_recompute_pcm, flags);
 }
 
 void fill_beep(u_char *buf, int num, int duration)
@@ -676,11 +666,12 @@
 static void do_ec(xpd_t *xpd)
 {
 #ifdef WITH_ECHO_SUPPRESSION
-	struct zt_chan	*chans = xpd->span.chans;
 	int		i;
 
 	/* FIXME: need to Echo cancel double buffered data */
 	for (i = 0;i < xpd->span.channels; i++) {
+		struct zt_chan	*chan = XPD_CHAN(xpd, i);
+
 		if(unlikely(IS_SET(xpd->digital_signalling, i)))	/* Don't echo cancel BRI D-chans */
 			continue;
 		if(!IS_SET(xpd->wanted_pcm_mask, i))			/* No ec for unwanted PCM */
@@ -688,12 +679,12 @@
 #ifdef XPP_EC_CHUNK 
 		/* even if defined, parameterr xpp_ec can override at run-time */
 		if (xpp_ec)
-			xpp_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]);
+			xpp_ec_chunk(chan, chan->readchunk, xpd->ec_chunk2[i]);
 		else
 #endif
-			zt_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]);
+			zt_ec_chunk(chan, chan->readchunk, xpd->ec_chunk2[i]);
 		memcpy(xpd->ec_chunk2[i], xpd->ec_chunk1[i], ZT_CHUNKSIZE);
-		memcpy(xpd->ec_chunk1[i], chans[i].writechunk, ZT_CHUNKSIZE);
+		memcpy(xpd->ec_chunk1[i], chan->writechunk, ZT_CHUNKSIZE);
 	}
 #endif
 }
@@ -821,31 +812,33 @@
  * Generic implementations of card_pcmfromspan()/card_pcmtospan()
  * For FXS/FXO
  */
-void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack)
+void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
 {
 	byte		*pcm;
-	struct zt_chan	*chans;
 	unsigned long	flags;
+	xpp_line_t	wanted_lines;
 	int		i;
 
 	BUG_ON(!xbus);
 	BUG_ON(!xpd);
 	BUG_ON(!pack);
-	RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
+	wanted_lines = xpd->wanted_pcm_mask;
+	RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = wanted_lines;
 	pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
 	spin_lock_irqsave(&xpd->lock, flags);
-	chans = xpd->span.chans;
 	for (i = 0; i < xpd->channels; i++) {
-		if(IS_SET(lines, i)) {
+		struct zt_chan	*chan = XPD_CHAN(xpd, i);
+
+		if(IS_SET(wanted_lines, i)) {
 			if(SPAN_REGISTERED(xpd)) {
 #ifdef	DEBUG_PCMTX
-				int     channo = xpd->span.chans[i].channo;
+				int	channo = chan->channo;
 
 				if(pcmtx >= 0 && pcmtx_chan == channo)
 					memset((u_char *)pcm, pcmtx, ZT_CHUNKSIZE);
 				else
 #endif
-					memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE);
+					memcpy((u_char *)pcm, chan->writechunk, ZT_CHUNKSIZE);
 			} else
 				memset((u_char *)pcm, 0x7F, ZT_CHUNKSIZE);
 			pcm += ZT_CHUNKSIZE;
@@ -874,7 +867,7 @@
 	if(!SPAN_REGISTERED(xpd))
 		goto out;
 	for (i = 0; i < xpd->channels; i++) {
-		volatile u_char	*r = xpd->span.chans[i].readchunk;
+		volatile u_char	*r = XPD_CHAN(xpd, i)->readchunk;
 		bool		got_data = IS_SET(pcm_mask, i);
 
 		if(got_data && !IS_SET(pcm_mute, i)) {
@@ -974,7 +967,6 @@
 	xpd_t		*xpd;
 	xframe_t	*xframe = NULL;

[... 410 lines stripped ...]



More information about the zaptel-commits mailing list