summaryrefslogtreecommitdiff
path: root/xpp/card_fxs.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/card_fxs.c')
-rw-r--r--xpp/card_fxs.c315
1 files changed, 256 insertions, 59 deletions
diff --git a/xpp/card_fxs.c b/xpp/card_fxs.c
index 5e5674b..af12cd2 100644
--- a/xpp/card_fxs.c
+++ b/xpp/card_fxs.c
@@ -29,11 +29,12 @@
#include "xpp_zap.h"
#include "card_fxo.h"
#include "zap_debug.h"
+#include "xbus-core.h"
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 */
+DEF_PARM(int, print_dbg, 0, 0600, "Print DBG statements"); /* must be before zap_debug.h */
+DEF_PARM_BOOL(poll_digital_inputs, 1, 0600, "Poll Digital Inputs"); /* must be before zap_debug.h */
/* Signaling is opposite (fxo signalling for fxs card) */
#if 1
@@ -64,14 +65,13 @@ static /* 0x0F */ DECLARE_CMD(FXS, REGISTER_REQUEST, byte chipsel, bool writing,
#define SLIC_DIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL) \
CALL_PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 0, (reg), 0, (dL), 0)
#define SLIC_INDIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL,dH) \
- PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 1, (reg), 0, (dL), (dH))
+ CALL_PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 1, 0x1E, (reg), (dL), (dH))
#define VALID_CHIPSEL(x) (((chipsel) >= 0 && (chipsel) <= 7) || (chipsel) == ALL_CHANS)
/*---------------- FXS Protocol Commands ----------------------------------*/
static /* 0x0F */ DECLARE_CMD(FXS, XPD_STATE, bool on);
-static /* 0x0F */ DECLARE_CMD(FXS, CHAN_CID, lineno_t chan);
static /* 0x0F */ DECLARE_CMD(FXS, RING, lineno_t chan, bool on);
static /* 0x0F */ DECLARE_CMD(FXS, RELAY_OUT, byte which, bool on);
@@ -80,6 +80,7 @@ static void fxs_packet_dump(const char *msg, xpacket_t *pack);
static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
static int proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data);
static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos);
#define PROC_REGISTER_FNAME "slics"
#define PROC_FXS_INFO_FNAME "fxs_info"
@@ -89,9 +90,23 @@ struct FXS_priv_data {
struct proc_dir_entry *fxs_info;
xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */
- int blinking[NUM_LEDS][CHANNELS_PERXPD];
+ xpp_line_t found_fsk_pattern;
+ xpp_line_t msg_waiting;
+ int led_counter[NUM_LEDS][CHANNELS_PERXPD];
};
+/*
+ * LED counter values:
+ * n>1 : BLINK every n'th tick
+ */
+#define LED_COUNTER(priv,pos,color) ((priv)->led_counter[color][pos])
+#define IS_BLINKING(priv,pos,color) (LED_COUNTER(priv,pos,color) > 0)
+#define MARK_BLINK(priv,pos,color,t) ((priv)->led_counter[color][pos] = (t))
+#define MARK_OFF(priv,pos,color) do { BIT_CLR((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0)
+#define MARK_ON(priv,pos,color) do { BIT_SET((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0)
+
+#define LED_BLINK_RING (1000/8) /* in ticks */
+
/*---------------- FXS: Static functions ----------------------------------*/
static int do_chan_power(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on)
{
@@ -103,10 +118,6 @@ static int do_chan_power(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on)
return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x42, value);
}
-#define IS_BLINKING(priv,pos,color) ((priv)->blinking[color][pos] != 0)
-#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:
* 7 6 5 4 3 2 1 0
@@ -137,7 +148,7 @@ static const int led_register_vals[] = { BIT(4), BIT(1), BIT(0) };
/*
* pos can be:
* - A line number
- * - ALL_LINES
+ * - ALL_LINES. This is not valid anymore since 8-Jan-2007.
*/
static int do_led(xpd_t *xpd, lineno_t chan, byte which, bool on)
{
@@ -147,6 +158,7 @@ static int do_led(xpd_t *xpd, lineno_t chan, byte which, bool on)
xbus_t *xbus;
BUG_ON(!xpd);
+ BUG_ON(chan == ALL_LINES);
xbus = xpd->xbus;
priv = xpd->priv;
which = which % NUM_LEDS;
@@ -186,9 +198,13 @@ static void handle_fxs_leds(xpd_t *xpd)
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
+ if(xpd->blink_mode || IS_BLINKING(priv, i, color)) { // Blinking
+ int mod_value = LED_COUNTER(priv, i, color);
+
+ if(!mod_value)
+ mod_value = DEFAULT_LED_PERIOD; /* safety value */
// led state is toggled
- if((timer_count % LED_BLINK_PERIOD) == 0) {
+ if((timer_count % mod_value) == 0) {
DBG("%s/%s/%d ledstate=%s\n", xpd->xbus->busname, xpd->xpdname, i,
(IS_SET(priv->ledstate[color], i))?"ON":"OFF");
if(!IS_SET(priv->ledstate[color], i)) {
@@ -207,6 +223,21 @@ static void handle_fxs_leds(xpd_t *xpd)
}
}
+static int do_callerid(xbus_t *xbus, xpd_t *xpd, lineno_t chan)
+{
+ int ret = 0;
+ int i;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, chan);
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, FXS_LINE_CID);
+ for_each_line(xpd, i)
+ xpd->lasttxhook[i] = FXS_LINE_CID;
+ return ret;
+}
+
+
/*---------------- FXS: Methods -------------------------------------------*/
static xpd_t *FXS_card_new(xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, byte revision)
@@ -254,6 +285,7 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
{
struct FXS_priv_data *priv;
int ret = 0;
+ int i;
BUG_ON(!xpd);
priv = xpd->priv;
@@ -289,6 +321,18 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
if(ret < 0)
goto err;
DBG("%s/%s: done\n", xbus->busname, xpd->xpdname);
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 0);
+ do_led(xpd, i, LED_RED, 0);
+ }
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 1);
+ msleep(50);
+ }
+ for_each_line(xpd, i) {
+ do_led(xpd, i, LED_GREEN, 0);
+ msleep(50);
+ }
return 0;
err:
clean_proc(xbus, xpd);
@@ -312,8 +356,6 @@ static int FXS_card_zaptel_preregistration(xpd_t *xpd, bool on)
xbus_t *xbus;
struct FXS_priv_data *priv;
int i;
- unsigned long flags;
- const enum fxs_leds color = (on) ? LED_GREEN : LED_RED;
BUG_ON(!xpd);
xbus = xpd->xbus;
@@ -337,12 +379,9 @@ static int FXS_card_zaptel_preregistration(xpd_t *xpd, bool on)
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);
- msleep(50);
+ MARK_ON(priv, i, LED_GREEN);
+ msleep(4);
}
return 0;
}
@@ -352,7 +391,6 @@ 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;
@@ -361,8 +399,10 @@ static int FXS_card_zaptel_postregistration(xpd_t *xpd, bool on)
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);
- msleep(50);
+ MARK_OFF(priv, i, LED_GREEN);
+ msleep(2);
+ MARK_OFF(priv, i, LED_RED);
+ msleep(2);
}
return 0;
}
@@ -387,6 +427,8 @@ int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
return ret;
}
ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0); // RING off
+ if (!IS_SET(xpd->offhook, pos))
+ start_stop_vm_led(xbus, xpd, pos);
#if 0
switch(chan->sig) {
case ZT_SIG_EM:
@@ -403,7 +445,7 @@ int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
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
+ ret = do_callerid(xpd->xbus, xpd, pos); // CALLER ID
}
xpd->ringing[pos] = 0;
#if 0
@@ -438,6 +480,107 @@ int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
return ret;
}
+#ifdef VMWI_IOCTL
+/*
+ * Private ioctl()
+ * We don't need it now, since we detect vmwi via FSK patterns
+ */
+static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
+{
+ struct FXS_priv_data *priv;
+ xbus_t *xbus;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+
+ if (pos < 0 || pos >= xpd->channels) {
+ NOTICE("%s/%s: Bad channel number %d in %s(), cmd=%u\n", xbus->busname, xpd->xpdname, pos, __FUNCTION__, cmd);
+ return -EINVAL;
+ }
+
+ switch (cmd) {
+ case _IOW(ZT_CODE, 60, int): /* message-waiting led control */
+ /* Digital inputs/outputs don't have VM leds */
+ if (IS_SET(xpd->digital_inputs | xpd->digital_outputs, pos))
+ return 0;
+ if (arg)
+ BIT_SET(priv->msg_waiting, pos);
+ else
+ BIT_CLR(priv->msg_waiting, pos);
+ return 0;
+ }
+ return -ENOTTY;
+}
+#endif
+
+static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
+{
+ int ret = 0;
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+
+ if (on) {
+ /* A write to register 0x40 will now turn on/off the VM led */
+ 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);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x19);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0xE0);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x01);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0xF0);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x05);
+ 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 */
+ 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);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00);
+ 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);
+}
+
+static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos)
+{
+ bool on;
+
+ if (IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos))
+ return;
+ on = IS_SET(((struct FXS_priv_data *)xpd->priv)->msg_waiting, pos);
+ DBG("%s/%s/%d %s\n", xbus->busname, xpd->xpdname, pos, (on)?"ON":"OFF");
+ set_vm_led_mode(xbus, xpd, pos, on);
+ do_chan_power(xbus, xpd, pos, on);
+ SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x40, (on) ? 0x04 : 0x01);
+}
+
+static int FXS_chan_onhooktransfer(xbus_t *xbus, xpd_t *xpd, lineno_t chan, int millies)
+{
+ int ret = 0;
+
+ BUG_ON(!xpd);
+ BUG_ON(chan == ALL_CHANS);
+ DBG("%s/%s/%d: (%d millies)\n", xbus->busname, xpd->xpdname, chan, millies);
+ xpd->ohttimer[chan] = millies << 3;
+ xpd->idletxhookstate[chan] = FXS_LINE_CID; /* OHT mode when idle */
+ if (xpd->lasttxhook[chan] == FXS_LINE_ENABLED) {
+ /* Apply the change if appropriate */
+ ret = do_callerid(xpd->xbus, xpd, chan); // CALLER ID
+ }
+ start_stop_vm_led(xbus, xpd, chan);
+ return ret;
+}
+
/*
* INPUT polling is done via SLIC register 0x06 (same as LEDS):
* 7 6 5 4 3 2 1 0
@@ -460,6 +603,65 @@ static void poll_inputs(xbus_t *xbus, xpd_t *xpd)
}
}
+#ifndef VMWI_IOCTL
+/*
+ * Detect Voice Mail Waiting Indication
+ */
+static void detect_vmwi(xpd_t *xpd)
+{
+ struct FXS_priv_data *priv;
+ xbus_t *xbus;
+ static const byte FSK_COMMON_PATTERN[] = { 0xA8, 0x49, 0x22, 0x3B, 0x9F, 0xFF, 0x1F, 0xBB };
+ 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;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ for_each_line(xpd, i) {
+ byte *writechunk = xpd->span.chans[i].writechunk;
+
+ if(IS_SET(xpd->offhook | xpd->cid_on | xpd->digital_inputs | xpd->digital_outputs, i))
+ continue;
+#if 0
+ if(i == 0 && writechunk[0] != 0x7F) {
+ int j;
+
+ DBG("%s/%s/%d: MSG:", xbus->busname, xpd->xpdname, i);
+ for(j = 0; j < ZT_CHUNKSIZE; j++) {
+ printk(" %02X", writechunk[j]);
+ }
+ printk("\n");
+ }
+#endif
+ if(unlikely(memcmp(writechunk, FSK_COMMON_PATTERN, ZT_CHUNKSIZE) == 0))
+ BIT_SET(priv->found_fsk_pattern, i);
+ else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) {
+ BIT_CLR(priv->found_fsk_pattern, i);
+ if(memcmp(writechunk, FSK_ON_PATTERN, ZT_CHUNKSIZE) == 0) {
+ DBG("%s/%s/%d: MSG WAITING ON\n", xbus->busname, xpd->xpdname, i);
+ BIT_SET(priv->msg_waiting, i);
+ start_stop_vm_led(xbus, xpd, i);
+ } else if(memcmp(writechunk, FSK_OFF_PATTERN, ZT_CHUNKSIZE) == 0) {
+ DBG("%s/%s/%d: MSG WAITING OFF\n", xbus->busname, xpd->xpdname, i);
+ BIT_CLR(priv->msg_waiting, i);
+ start_stop_vm_led(xbus, xpd, i);
+ } else {
+ int j;
+
+ NOTICE("%s/%s/%d: MSG WAITING Unexpected:", xbus->busname, xpd->xpdname, i);
+ for(j = 0; j < ZT_CHUNKSIZE; j++) {
+ printk(" %02X", writechunk[j]);
+ }
+ printk("\n");
+ }
+ }
+ }
+}
+#endif
+
static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
{
static int rate_limit = 0;
@@ -476,6 +678,10 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
}
#endif
handle_fxs_leds(xpd);
+#ifndef VMWI_IOCTL
+ if(SPAN_REGISTERED(xpd))
+ detect_vmwi(xpd);
+#endif
return 0;
}
@@ -484,6 +690,7 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
/* 0x0F */ HOSTCMD(FXS, REGISTER_REQUEST, byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high)
{
int ret = 0;
+ xframe_t *xframe;
xpacket_t *pack;
reg_cmd_t *reg_cmd;
@@ -491,7 +698,7 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
DBG("NO XBUS\n");
return -EINVAL;
}
- XPACKET_NEW(pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id);
+ XFRAME_NEW(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id);
#if 0
DBG("%s/%s/%d: %c%c R%02X S%02X %02X %02X\n",
xbus->busname, xpd->xpdname, chipsel,
@@ -500,7 +707,6 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
regnum, subreg, data_low, data_high);
#endif
reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd);
- pack->datalen = sizeof(*reg_cmd);
reg_cmd->bytes = sizeof(*reg_cmd) - 1; // do not count the 'bytes' field
REG_FIELD(reg_cmd, chipsel) = chipsel;
REG_FIELD(reg_cmd, read_request) = (writing) ? 0 : 1;
@@ -509,7 +715,7 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
REG_FIELD(reg_cmd, subreg) = subreg;
REG_FIELD(reg_cmd, data_low) = data_low;
REG_FIELD(reg_cmd, data_high) = data_high;
- ret = packet_send(xbus, pack);
+ ret = xframe_send(xbus, xframe);
return ret;
}
@@ -530,29 +736,14 @@ static /* 0x0F */ HOSTCMD(FXS, XPD_STATE, bool on)
for_each_line(xpd, i)
xpd->lasttxhook[i] = value;
if(on) {
- MARK_LED(priv, ALL_CHANS, LED_GREEN, LED_ON);
+ MARK_ON(priv, ALL_CHANS, LED_GREEN);
} else {
- MARK_LED(priv, ALL_CHANS, LED_GREEN, LED_OFF);
+ MARK_OFF(priv, ALL_CHANS, LED_GREEN);
}
spin_unlock_irqrestore(&xpd->lock, flags);
return ret;
}
-static /* 0x0F */ HOSTCMD(FXS, CHAN_CID, lineno_t chan)
-{
- int ret = 0;
- int i;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, chan);
- ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, FXS_LINE_CID);
- for_each_line(xpd, i)
- xpd->lasttxhook[i] = FXS_LINE_CID;
- return ret;
-}
-
-
static /* 0x0F */ HOSTCMD(FXS, RING, lineno_t chan, bool on)
{
int ret = 0;
@@ -563,14 +754,15 @@ static /* 0x0F */ HOSTCMD(FXS, RING, lineno_t chan, bool on)
BUG_ON(!xpd);
DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, chan, (on) ? "on" : "off");
priv = xpd->priv;
+ set_vm_led_mode(xbus, xpd, chan, 0);
do_chan_power(xbus, xpd, chan, on); // Power up (for ring)
ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, value);
xpd->lasttxhook[chan] = value;
if(on) {
- MARK_BLINK(priv,chan,LED_GREEN,LED_BLINK);
+ MARK_BLINK(priv, chan, LED_GREEN, LED_BLINK_RING);
} else {
if(IS_BLINKING(priv, chan, LED_GREEN))
- MARK_BLINK(priv,chan,LED_GREEN,0);
+ MARK_BLINK(priv, chan, LED_GREEN, 0);
}
return ret;
}
@@ -605,10 +797,6 @@ HANDLER_DEF(FXS, SIG_CHANGED)
BUG_ON(xpd->direction != TO_PHONE);
priv = xpd->priv;
DBG("%s/%s: (PHONE) sig_toggles=0x%04X sig_status=0x%04X\n", xbus->busname, xpd->xpdname, sig_toggles, sig_status);
- if(!SPAN_REGISTERED(xpd)) {
- NOTICE("%s: %s/%s is not registered. Skipping.\n", __FUNCTION__, xbus->busname, xpd->xpdname);
- return -ENODEV;
- }
#if 0
Is this needed?
for_each_line(xpd, i) {
@@ -622,15 +810,16 @@ HANDLER_DEF(FXS, SIG_CHANGED)
continue;
if(IS_SET(sig_toggles, i)) {
xpd->ringing[i] = 0; // No more ringing...
- MARK_BLINK(priv,i,LED_GREEN,0);
+ MARK_BLINK(priv, i, LED_GREEN, 0);
if(IS_SET(sig_status, i)) {
DBG("%s/%s/%d: OFFHOOK\n", xbus->busname, xpd->xpdname, i);
- MARK_LED(priv,i,LED_GREEN,LED_ON);
+ MARK_ON(priv, i, LED_GREEN);
update_line_status(xpd, i, 1);
} else {
DBG("%s/%s/%d: ONHOOK\n", xbus->busname, xpd->xpdname, i);
- MARK_LED(priv,i,LED_GREEN,LED_OFF);
+ MARK_OFF(priv, i, LED_GREEN);
update_line_status(xpd, i, 0);
+ start_stop_vm_led(xbus, xpd, i);
}
}
}
@@ -648,7 +837,7 @@ HANDLER_DEF(FXS, REGISTER_REPLY)
if(!xpd) {
NOTICE("%s: received %s for non-existing xpd: %d\n",
- __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
+ __FUNCTION__, cmd->name, XPD_NUM(pack->addr));
return -EPROTO;
}
spin_lock_irqsave(&xpd->lock, flags);
@@ -720,14 +909,16 @@ xproto_table_t PROTO_TABLE(FXS) = {
.card_zaptel_postregistration = FXS_card_zaptel_postregistration,
.card_hooksig = FXS_card_hooksig,
.card_tick = FXS_card_tick,
+ .chan_onhooktransfer = FXS_chan_onhooktransfer,
+#ifdef VMWI_IOCTL
+ .card_ioctl = FXS_card_ioctl,
+#endif
.RING = XPROTO_CALLER(FXS, RING),
.RELAY_OUT = XPROTO_CALLER(FXS, RELAY_OUT),
.XPD_STATE = XPROTO_CALLER(FXS, XPD_STATE),
- .CHAN_CID = XPROTO_CALLER(FXS, CHAN_CID),
.SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
- .PCM_WRITE = XPROTO_CALLER(GLOBAL, PCM_WRITE),
},
.packet_is_valid = fxs_packet_is_valid,
.packet_dump = fxs_packet_dump,
@@ -738,7 +929,7 @@ static bool fxs_packet_is_valid(xpacket_t *pack)
const xproto_entry_t *xe;
// DBG("\n");
- xe = xproto_card_entry(&PROTO_TABLE(FXS), pack->content.opcode);
+ xe = xproto_card_entry(&PROTO_TABLE(FXS), pack->opcode);
return xe != NULL;
}
@@ -781,10 +972,10 @@ static int proc_fxs_info_read(char *page, char **start, off_t off, int count, in
if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
len += sprintf(page + len, "%d ", IS_SET(priv->ledcontrol[led], i));
}
- len += sprintf(page + len, "\n\t%-17s: ", "blinking");
+ len += sprintf(page + len, "\n\t%-17s: ", "led_counter");
for_each_line(xpd, i) {
if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
- len += sprintf(page + len, "%d ", IS_BLINKING(priv,i,led));
+ len += sprintf(page + len, "%d ", LED_COUNTER(priv,i,led));
}
len += sprintf(page + len, "\n");
}
@@ -988,13 +1179,18 @@ static int proc_xpd_register_read(char *page, char **start, off_t off, int count
int __init card_fxs_startup(void)
{
- INFO("%s\n", THIS_MODULE->name);
+ INFO("%s revision %s\n", THIS_MODULE->name, XPP_VERSION);
#ifdef POLL_DIGITAL_INPUTS
INFO("FEATURE: %s with DIGITAL INPUTS support (%s activated)\n",
THIS_MODULE->name, (poll_digital_inputs) ? "is" : "is not");
#else
INFO("FEATURE: %s without DIGITAL INPUTS support\n", THIS_MODULE->name);
#endif
+#ifdef VMWI_IOCTL
+ INFO("FEATURE: %s VMWI_IOCTL\n", THIS_MODULE->name);
+#else
+ INFO("FEATURE: %s NO VMWI_IOCTL\n", THIS_MODULE->name);
+#endif
xproto_register(&PROTO_TABLE(FXS));
return 0;
}
@@ -1007,6 +1203,7 @@ void __exit card_fxs_cleanup(void)
MODULE_DESCRIPTION("XPP FXS Card Driver");
MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
MODULE_LICENSE("GPL");
+MODULE_VERSION(XPP_VERSION);
MODULE_ALIAS_XPD(XPD_TYPE_FXS);
module_init(card_fxs_startup);