diff options
Diffstat (limited to 'xpp/card_fxs.c')
-rw-r--r-- | xpp/card_fxs.c | 315 |
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); |