Пример #1
0
static void mark_ring(xpd_t *xpd, lineno_t pos, bool on, bool update_dahdi)
{
	struct FXO_priv_data *priv;

	priv = xpd->priv;
	BUG_ON(!priv);
	atomic_set(&priv->ring_debounce[pos], 0);	/* Stop debouncing */
	/*
	 * We don't want to check battery during ringing
	 * due to voltage fluctuations.
	 */
	reset_battery_readings(xpd, pos);
	if (on && !PHONEDEV(xpd).ringing[pos]) {
		LINE_DBG(SIGNAL, xpd, pos, "START\n");
		PHONEDEV(xpd).ringing[pos] = 1;
		priv->cidtimer[pos] = xpd->timer_count;
		MARK_BLINK(priv, pos, LED_GREEN, LED_BLINK_RING);
		if (update_dahdi)
			update_dahdi_ring(xpd, pos, on);
	} else if (!on && PHONEDEV(xpd).ringing[pos]) {
		LINE_DBG(SIGNAL, xpd, pos, "STOP\n");
		PHONEDEV(xpd).ringing[pos] = 0;
		priv->cidtimer[pos] = xpd->timer_count;
		if (IS_BLINKING(priv, pos, LED_GREEN))
			MARK_BLINK(priv, pos, LED_GREEN, 0);
		if (update_dahdi)
			update_dahdi_ring(xpd, pos, on);
	}
}
Пример #2
0
/*
 * LED control is done via DAA register 0x20
 */
static int do_led(xpd_t *xpd, lineno_t chan, __u8 which, bool on)
{
	int ret = 0;
	struct FXO_priv_data *priv;
	xbus_t *xbus;
	__u8 value;

	BUG_ON(!xpd);
	xbus = xpd->xbus;
	priv = xpd->priv;
	which = which % NUM_LEDS;
	if (IS_SET(PHONEDEV(xpd).digital_outputs, chan)
	    || IS_SET(PHONEDEV(xpd).digital_inputs, chan))
		goto out;
	if (chan == PORT_BROADCAST) {
		priv->ledstate[which] = (on) ? ~0 : 0;
	} else {
		if (on)
			BIT_SET(priv->ledstate[which], chan);
		else
			BIT_CLR(priv->ledstate[which], chan);
	}
	value = 0;
	value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]);
	value |= (on) ? BIT(0) : 0;
	value |= (on) ? BIT(1) : 0;
	LINE_DBG(LEDS, xpd, chan, "LED: which=%d -- %s\n", which,
		 (on) ? "on" : "off");
	ret = DAA_DIRECT_REQUEST(xbus, xpd, chan, DAA_WRITE, 0x20, value);
out:
	return ret;
}
Пример #3
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;
}
Пример #4
0
static void handle_fxo_leds(xpd_t *xpd)
{
	int i;
	unsigned long flags;
	const enum fxo_leds colors[] = { LED_GREEN, LED_RED };
	enum fxo_leds color;
	unsigned int timer_count;
	struct FXO_priv_data *priv;

	BUG_ON(!xpd);
	spin_lock_irqsave(&xpd->lock, flags);
	priv = xpd->priv;
	timer_count = xpd->timer_count;
	for (color = 0; color < ARRAY_SIZE(colors); color++) {
		for_each_line(xpd, i) {
			if (IS_SET(PHONEDEV(xpd).digital_outputs, i)
			    || IS_SET(PHONEDEV(xpd).digital_inputs, i))
				continue;
			/* Blinking? */
			if ((xpd->blink_mode & BIT(i)) || IS_BLINKING(priv, i, color)) {
				int mod_value = LED_COUNTER(priv, i, color);

				if (!mod_value)
					/* safety value */
					mod_value = DEFAULT_LED_PERIOD;
				// led state is toggled
				if ((timer_count % mod_value) == 0) {
					LINE_DBG(LEDS, xpd, i, "ledstate=%s\n",
						 (IS_SET
						  (priv->ledstate[color],
						   i)) ? "ON" : "OFF");
					if (!IS_SET(priv->ledstate[color], i))
						do_led(xpd, i, color, 1);
					else
						do_led(xpd, i, color, 0);
				}
			} else if (IS_SET(priv->ledcontrol[color], i)
				   && !IS_SET(priv->ledstate[color], i)) {
				do_led(xpd, i, color, 1);
			} else if (!IS_SET(priv->ledcontrol[color], i)
				   && IS_SET(priv->ledstate[color], i)) {
				do_led(xpd, i, color, 0);
			}
		}
	}
	spin_unlock_irqrestore(&xpd->lock, flags);
}
Пример #5
0
static int do_sethook(xpd_t *xpd, int pos, bool to_offhook)
{
	unsigned long flags;
	xbus_t *xbus;
	struct FXO_priv_data *priv;
	int ret = 0;
	__u8 value;

	BUG_ON(!xpd);
	/* We can SETHOOK state only on PSTN */
	BUG_ON(PHONEDEV(xpd).direction == TO_PHONE);
	xbus = xpd->xbus;
	priv = xpd->priv;
	BUG_ON(!priv);
	if (priv->battery[pos] != BATTERY_ON && to_offhook) {
		LINE_NOTICE(xpd, pos,
			    "Cannot take offhook while battery is off!\n");
		return -EINVAL;
	}
	spin_lock_irqsave(&xpd->lock, flags);
	mark_ring(xpd, pos, 0, 0);	// No more rings
	value = REG_DAA_CONTROL1_ONHM;	/* Bit 3 is for CID */
	if (to_offhook)
		value |= REG_DAA_CONTROL1_OH;
	LINE_DBG(SIGNAL, xpd, pos, "SETHOOK: value=0x%02X %s\n", value,
		 (to_offhook) ? "OFFHOOK" : "ONHOOK");
	if (to_offhook)
		MARK_ON(priv, pos, LED_GREEN);
	else
		MARK_OFF(priv, pos, LED_GREEN);
	ret =
	    DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, REG_DAA_CONTROL1,
			       value);
	mark_offhook(xpd, pos, to_offhook);
	switch (caller_id_style) {
	case CID_STYLE_ETSI_DTMF:
	case CID_STYLE_PASSTHROUGH:
		break;
	default:
		oht_pcm(xpd, pos, 0);
		break;
	}
#ifdef	WITH_METERING
	priv->metering_count[pos] = 0;
	priv->metering_tone_state = 0L;
	DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, DAA_REG_METERING, 0x2D);
#endif
	/* unstable during hook changes */
	reset_battery_readings(xpd, pos);
	if (to_offhook) {
		priv->power_denial_safezone[pos] = power_denial_safezone;
	} else {
		priv->power_denial_length[pos] = 0;
		priv->power_denial_safezone[pos] = 0;
	}
	priv->cidtimer[pos] = xpd->timer_count;
	spin_unlock_irqrestore(&xpd->lock, flags);
	return ret;
}
Пример #6
0
static DEVICE_ATTR_READER(span_show, dev, buf)
{
	xpd_t *xpd;
	unsigned long flags;
	int len = 0;

	BUG_ON(!dev);
	xpd = dev_to_xpd(dev);
	if (!xpd)
		return -ENODEV;
	spin_lock_irqsave(&xpd->lock, flags);
	len +=
	    sprintf(buf, "%d\n",
		    SPAN_REGISTERED(xpd) ? PHONEDEV(xpd).span.spanno : 0);
	spin_unlock_irqrestore(&xpd->lock, flags);
	return len;
}