Пример #1
0
static void update_dahdi_ring(xpd_t *xpd, int pos, bool on)
{
	dahdi_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 = DAHDI_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 = DAHDI_RXSIG_OFFHOOK;
	}
	pcm_recompute(xpd, 0);
	/*
	 * We should not spinlock before calling dahdi_hooksig() as
	 * it may call back into our xpp_hooksig() and cause
	 * a nested spinlock scenario
	 */
	if(SPAN_REGISTERED(xpd))
		dahdi_hooksig(&xpd->chans[pos], rxsig);
}
Пример #2
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);
	}
}
Пример #3
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;
	byte			value;

	BUG_ON(!xpd);
	BUG_ON(xpd->direction == TO_PHONE);		// We can SETHOOK state only on PSTN
	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);
	if(to_offhook) {
		BIT_SET(xpd->offhook, pos);
	} else {
		BIT_CLR(xpd->offhook, pos);
	}
	if(caller_id_style != CID_STYLE_PASS_ALWAYS) {
		LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: off\n");
		BIT_CLR(xpd->cid_on, pos);
	}
#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
	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;
	spin_unlock_irqrestore(&xpd->lock, flags);
	return ret;
}
Пример #4
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;
}
Пример #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 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;
}
Пример #7
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);
}