예제 #1
0
/*
 * Synchronous part of XPD detection.
 * Called from xbus_poll()
 */
int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table,
		int unit,
		int subunit,
		byte type,
		byte subtype,
		int subunits,
		byte port_dir)
{
	xpd_t			*xpd = NULL;
	bool			to_phone;
	int			ret = -EINVAL;

	BUG_ON(type == XPD_TYPE_NOMODULE);
	to_phone = BIT(subunit) & port_dir;
	BUG_ON(!xbus);
	xpd = xpd_byaddr(xbus, unit, subunit);
	if(xpd) {
		XPD_NOTICE(xpd, "XPD at %d%d already exists\n",
			unit, subunit);
		goto out;
	}
	xpd = proto_table->xops.card_new(xbus, unit, subunit, proto_table, subtype, subunits, to_phone);
	if(!xpd) {
		XBUS_NOTICE(xbus, "card_new(%d,%d,%d,%d,%d) failed. Ignored.\n",
			unit, subunit, proto_table->type, subtype, to_phone);
		goto err;
	}
out:
	return 0;
err:
	if(xpd)
		xpd_free(xpd);
	return ret;
}
예제 #2
0
static xpd_t *FXO_card_new(xbus_t *xbus, int unit, int subunit,
			   const xproto_table_t *proto_table, __u8 subtype,
			   int subunits, int subunit_ports, bool to_phone)
{
	xpd_t *xpd = NULL;
	int channels;

	if (to_phone) {
		XBUS_NOTICE(xbus,
			"XPD=%d%d: try to instanciate FXO with "
			"reverse direction\n",
			unit, subunit);
		return NULL;
	}
	if (subtype == 2)
		channels = min(2, subunit_ports);
	else
		channels = min(8, subunit_ports);
	xpd =
	    xpd_alloc(xbus, unit, subunit, subtype, subunits,
		      sizeof(struct FXO_priv_data), proto_table, channels);
	if (!xpd)
		return NULL;
	PHONEDEV(xpd).direction = TO_PSTN;
	xpd->type_name = "FXO";
	if (fxo_proc_create(xbus, xpd) < 0)
		goto err;
	return xpd;
err:
	xpd_free(xpd);
	return NULL;
}
예제 #3
0
__must_check int xpd_common_init(xbus_t *xbus, xpd_t *xpd, int unit, int subunit, int subtype, int subunits)
{
	int	ret;

	MKADDR(&xpd->addr, unit, subunit);
	xpd->xbus_idx = XPD_IDX(unit,subunit);
	snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%1d%1d", unit, subunit);
	xpd->subtype = subtype;
	xpd->subunits = subunits;
	xpd->offhook = 0;

	/* For USB-1 disable some channels */
	if(MAX_SEND_SIZE(xbus) < RPACKET_SIZE(GLOBAL, PCM_WRITE)) {
		xpp_line_t	no_pcm;

		no_pcm = 0x7F | xpd->digital_outputs | xpd->digital_inputs;
		xpd->no_pcm = no_pcm;
		XBUS_NOTICE(xbus, "max xframe size = %d, disabling some PCM channels. no_pcm=0x%04X\n",
				MAX_SEND_SIZE(xbus), xpd->no_pcm);
	}
	if((ret = xpd_proc_create(xbus, xpd)) < 0)
		return ret;
	xbus_register_xpd(xbus, xpd);
	return 0;
}
예제 #4
0
static int xframe_receive_cmd(xbus_t *xbus, xframe_t *xframe)
{
	byte		*xframe_end;
	xpacket_t	*pack;
	byte		*p;
	int		len;
	int		ret;

	if(debug & DBG_COMMANDS)
		dump_xframe("RX-CMD", xbus, xframe, DBG_ANY);
	p = xframe->packets;
	xframe_end = p + XFRAME_LEN(xframe);
	do {
		pack = (xpacket_t *)p;
		len = XPACKET_LEN(pack);
		/* Sanity checks */
		if(unlikely(XPACKET_OP(pack) == XPROTO_NAME(GLOBAL,PCM_READ))) {
			static int	rate_limit;

			if((rate_limit++ % 1003) == 0) {
				XBUS_DBG(GENERAL, xbus, "A PCM packet within a Non-PCM xframe\n");
				dump_xframe("In Non-PCM xframe", xbus, xframe, debug);
			}
			ret = -EPROTO;
			goto out;
		}
		p += len;
		if(p > xframe_end || len < RPACKET_HEADERSIZE) {
			static int	rate_limit;

			if((rate_limit++ % 1003) == 0) {
				XBUS_NOTICE(xbus, "Invalid packet length %d\n", len);
				dump_xframe("BAD LENGTH", xbus, xframe, debug);
			}
			ret = -EPROTO;
			goto out;
		}
		ret = packet_process(xbus, pack);
		if(unlikely(ret < 0))
			break;
	} while(p < xframe_end);
out:
	FREE_RECV_XFRAME(xbus, xframe);
	return ret;
}
예제 #5
0
static DEVICE_ATTR_WRITER(xbus_state_store, dev, buf, count)
{
	xbus_t *xbus;

	xbus = dev_to_xbus(dev);
	XBUS_DBG(GENERAL, xbus, "%s\n", buf);
	if (strncmp(buf, "stop", 4) == 0)
		xbus_deactivate(xbus);
	else if (XBUS_IS(xbus, IDLE) && strncmp(buf, "start", 5) == 0)
		xbus_activate(xbus);
	else {
		XBUS_NOTICE(xbus,
			    "%s: Illegal action %s in state %s. Ignored.\n",
			    __func__, buf, xbus_statename(XBUS_STATE(xbus)));
		return -EINVAL;
	}
	return count;
}
예제 #6
0
int xframe_receive(xbus_t *xbus, xframe_t *xframe)
{
	int		ret = 0;
	struct timeval	now;
	struct timeval	tv_received;
	int		usec;

	if(XFRAME_LEN(xframe) < RPACKET_HEADERSIZE) {
		static int	rate_limit;

		if((rate_limit++ % 1003) == 0) {
			XBUS_NOTICE(xbus, "short xframe\n");
			dump_xframe("short xframe", xbus, xframe, debug);
		}
		FREE_RECV_XFRAME(xbus, xframe);
		return -EPROTO;
	}
	if(!XBUS_FLAGS(xbus, CONNECTED)) {
		XBUS_DBG(GENERAL, xbus, "Dropped xframe. Is shutting down.\n");
		return -ENODEV;
	}
	tv_received = xframe->tv_received;
	/*
	 * We want to check that xframes do not mix PCM and other commands
	 */
	if(XPACKET_IS_PCM((xpacket_t *)xframe->packets)) {
		if(!XBUS_IS(xbus, READY))
			FREE_RECV_XFRAME(xbus, xframe);
		else
			xframe_receive_pcm(xbus, xframe);
	} else {
		XBUS_COUNTER(xbus, RX_CMD)++;
		ret = xframe_receive_cmd(xbus, xframe);
	}
	/* Calculate total processing time */
	do_gettimeofday(&now);
	usec = (now.tv_sec - tv_received.tv_sec) * 1000000 +
		now.tv_usec - tv_received.tv_usec;
	if(usec > xbus->max_rx_process)
		xbus->max_rx_process = usec;
	return ret;
}
예제 #7
0
static int packet_process(xbus_t *xbus, xpacket_t *pack)
{
	byte			op;
	const xproto_entry_t	*xe;
	xproto_handler_t	handler;
	xproto_table_t		*table;
	xpd_t			*xpd;
	int			ret = -EPROTO;

	BUG_ON(!pack);
	if(!valid_xpd_addr(&XPACKET_ADDR(pack))) {
		if(printk_ratelimit()) {
			XBUS_NOTICE(xbus, "%s: from %d%d: bad address.\n",
					__FUNCTION__,
					XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack));
			dump_packet("packet_process -- bad address", pack, debug);
		}
		goto out;
	}
	op = XPACKET_OP(pack);
	xpd = xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack));
	/* XPD may be NULL (e.g: during bus polling */
	xe = xproto_global_entry(op);
	/*-------- Validations -----------*/
	if(!xe) {
		const xproto_table_t *xtable;
		
		if(!xpd) {
			if(printk_ratelimit()) {
				XBUS_NOTICE(xbus, "%s: from %d%d opcode=0x%02X: no such global command.\n",
						__FUNCTION__,
						XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack), op);
				dump_packet("packet_process -- no such global command", pack, 1);
			}
			goto out;
		}
		xtable = xproto_table(xpd->type);
		if(!xtable) {
			if(printk_ratelimit())
				XPD_ERR(xpd, "%s: no protocol table (type=%d)\n",
					__FUNCTION__,
					xpd->type);
			goto out;
		}
		xe = xproto_card_entry(xtable, op);
		if(!xe) {
			if(printk_ratelimit()) {
				XPD_NOTICE(xpd, "%s: bad command (type=%d,opcode=0x%x)\n",
					__FUNCTION__,
					xpd->type, op);
				dump_packet("packet_process -- bad command", pack, 1);
			}
			goto out;
		}
	}
	table = xe->table;
	BUG_ON(!table);
	if(!table->packet_is_valid(pack)) {
		if(printk_ratelimit()) {
			ERR("xpp: %s: wrong size %d for opcode=0x%02X\n",
					__FUNCTION__, XPACKET_LEN(pack), op);
			dump_packet("packet_process -- wrong size", pack, debug);
		}
		goto out;
	}
	ret = 0;	/* All well */
	handler = xe->handler;
	BUG_ON(!handler);
	XBUS_COUNTER(xbus, RX_BYTES) += XPACKET_LEN(pack);
	handler(xbus, xpd, xe, pack);
out:
	return ret;
}
예제 #8
0
void notify_bad_xpd(const char *funcname, xbus_t *xbus, const struct xpd_addr addr, const char *msg)
{
	XBUS_NOTICE(xbus, "%s: non-existing address (%1d%1d): %s\n",
			funcname, addr.unit, addr.subunit, msg);
}
예제 #9
0
static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe)
{
	byte		*xframe_end;
	xpacket_t	*pack;
	byte		*p;
	int		ret = -EPROTO;	/* Assume error */

	if(debug & DBG_PCM)
		dump_xframe("RX_XFRAME_PCM", xbus, xframe, debug);
	/* handle content */

	p = xframe->packets;
	xframe_end = p + XFRAME_LEN(xframe);
	do {
		int		len;
		xpd_t		*xpd;

		pack = (xpacket_t *)p;
		len = XPACKET_LEN(pack);
		/* Sanity checks */
		if(unlikely(XPACKET_OP(pack) != XPROTO_NAME(GLOBAL,PCM_READ))) {
			static int	rate_limit;

			if((rate_limit++ % 1003) == 0) {
				XBUS_NOTICE(xbus,
					"%s: Non-PCM packet within a PCM xframe. (%d)\n",
					__FUNCTION__, rate_limit);
				dump_xframe("In PCM xframe", xbus, xframe, debug);
			}
			goto out;
		}
		p += len;
		if(p > xframe_end || len < RPACKET_HEADERSIZE) {
			static int	rate_limit;

			if((rate_limit++ % 1003) == 0) {
				XBUS_NOTICE(xbus,
					"%s: Invalid packet length %d. (%d)\n",
					__FUNCTION__, len, rate_limit);
				dump_xframe("BAD LENGTH", xbus, xframe, debug);
			}
			goto out;
		}
		xpd = xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack));
		if(unlikely(!xpd)) {
			static int	rate_limit;

			if((rate_limit++ % 1003) == 0) {
				notify_bad_xpd(__FUNCTION__, xbus, XPACKET_ADDR(pack), "RECEIVE PCM");
				dump_xframe("Unknown XPD addr", xbus, xframe, debug);
			}
			goto out;
		}
		if(!pcm_valid(xpd, pack))
			goto out;
		if(SPAN_REGISTERED(xpd)) {
			XBUS_COUNTER(xbus, RX_PACK_PCM)++;
			CALL_XMETHOD(card_pcm_tospan, xbus, xpd, pack);
		}
	} while(p < xframe_end);
	ret = 0;	/* all good */
	XBUS_COUNTER(xbus, RX_XFRAME_PCM)++;
out:
	FREE_RECV_XFRAME(xbus, xframe);
	return ret;
}
예제 #10
0
static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv)
{
	struct xpp_drift	*driftinfo = &xbus->drift;
	struct xpp_ticker	*ticker = &xbus->ticker;
	unsigned long		flags;
	bool			cycled;

	spin_lock_irqsave(&driftinfo->lock, flags);
	cycled = xpp_ticker_step(&xbus->ticker, tv);
	if(ref_ticker && syncer && xbus->sync_mode == SYNC_MODE_PLL) {
		int	new_delta_tick = ticker->count - ref_ticker->count;
		int	lost_ticks = new_delta_tick - driftinfo->delta_tick;

		driftinfo->delta_tick = new_delta_tick;
		if(lost_ticks) {
			driftinfo->lost_ticks++;
			driftinfo->lost_tick_count += abs(lost_ticks);
			XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n",
				lost_ticks,
				(abs(lost_ticks) > 1) ? "s": "");
			ticker->cycle = SYNC_ADJ_QUICK;
			if(abs(lost_ticks) > 100)
				ticker->count = ref_ticker->count;
		} else {
			long	usec_delta;
			bool	nofix = 0;

			usec_delta = (long)usec_diff(
					&ticker->last_sample.tv,
					&ref_ticker->last_sample.tv);
			usec_delta -= driftinfo->wanted_offset;
			sample_tick(xbus, usec_delta);
			if(abs(usec_delta) > 300) {
				/*
				 * We are close to the edge, send a brutal
				 * fix, and skip calculation until next time.
				 */
				if(usec_delta > 0 && xbus->sync_adjustment > -SYNC_ADJ_MAX) {
					XBUS_DBG(SYNC, xbus, "Pullback usec_delta=%ld\n", usec_delta);
					send_drift(xbus, -SYNC_ADJ_MAX);	/* emergency push */
				}
				if(usec_delta < 0 && xbus->sync_adjustment < SYNC_ADJ_MAX) {
					XBUS_DBG(SYNC, xbus, "Pushback usec_delta=%ld\n", usec_delta);
					send_drift(xbus, SYNC_ADJ_MAX);		/* emergency push */
				}
				ticker->cycle = SYNC_ADJ_QUICK;
				nofix = 1;
			} else {
				/* good data, use it */
				if(usec_delta > driftinfo->delta_max)
					driftinfo->delta_max = usec_delta;
				if(usec_delta < driftinfo->delta_min)
					driftinfo->delta_min = usec_delta;
			}
			if(!nofix && cycled) {
				int	offset = 0;

				driftinfo->median = (driftinfo->delta_max + driftinfo->delta_min) / 2;
				driftinfo->jitter = driftinfo->delta_max - driftinfo->delta_min;
				if(abs(driftinfo->median) >= 150) {	/* more than 1 usb uframe */
					int	factor = abs(driftinfo->median) / 125;

					factor = 1 + (factor * 8000) / ticker->cycle;
					if(driftinfo->median > 0)
						offset = driftinfo->calc_drift - factor;
					else
						offset = driftinfo->calc_drift + factor;
					/* for large median, push some more */
					if(abs(driftinfo->median) >= 300) {	/* more than 2 usb uframes */
						ticker->cycle = SYNC_ADJ_QUICK;
						XBUS_NOTICE(xbus,
								"Back to quick: median=%d\n",
								driftinfo->median);
					}
				} else {
					ticker->cycle += 500;
					if(ticker->cycle >= SYNC_ADJ_SLOW)
						ticker->cycle = SYNC_ADJ_SLOW;
				}
				driftinfo->calc_drift = offset;
				XBUS_DBG(SYNC, xbus,
						"ADJ: min=%d max=%d jitter=%d median=%d offset=%d\n",
						driftinfo->delta_min,
						driftinfo->delta_max,
						driftinfo->jitter,
						driftinfo->median,
						offset);
				if(offset < -SYNC_ADJ_MAX)
					offset = -SYNC_ADJ_MAX;
				if(offset > SYNC_ADJ_MAX)
					offset = SYNC_ADJ_MAX;
				xbus->sync_adjustment_offset = offset;
				if(xbus != syncer && xbus->sync_adjustment != offset)
					send_drift(xbus, offset);
				driftinfo_recalc(driftinfo);
			}
		}
	}
	spin_unlock_irqrestore(&driftinfo->lock, flags);
}