diff options
author | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-09-14 22:29:36 +0000 |
---|---|---|
committer | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-09-14 22:29:36 +0000 |
commit | c91b2cd29653da525d1a37cf680f4a75b2d3b208 (patch) | |
tree | f26185291a7ebb24902a2737d6e5b1fed75bb8c1 /xpp/card_fxs.c | |
parent | 236601045ee0a95930414d8d5f822d9a61054aae (diff) |
New xpp release (Xorcom rev 4648):
* New firmware protocol version: 2.8 .
* New firmwares fix input ports offhook.
* Cleanup INFO() messages during module loading.
* USB: Receive queue with TASKLETS [r4600]. Controlled by rx_tasklet
parameter to xpp_usb module (can be changed in runtime).
* The pcm_tasklet parameter in xpp module is deprecated:
- Does not actually do anything.
- If set during module loading, shows an ERR() message.
- Also appears in /proc/xpp/sync
* FXS: Hardware DTMF detection by default, can be disabled
by setting dtmf_detection=0 parameter to xpd_fxs.
PCM is muted when DTMF key is pressed.
* zapconf:
- Can now generate users.conf compatible with asterisk-gui.
- Optional command-line arguments denoting which files to generate.
Possible values are 'zaptel', 'zapata' and 'users'.
- Defaults to creating zaptel and zapata.
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@3019 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/card_fxs.c')
-rw-r--r-- | xpp/card_fxs.c | 139 |
1 files changed, 59 insertions, 80 deletions
diff --git a/xpp/card_fxs.c b/xpp/card_fxs.c index 67cff65..bc282b4 100644 --- a/xpp/card_fxs.c +++ b/xpp/card_fxs.c @@ -37,7 +37,7 @@ DEF_PARM(int, print_dbg, 0, 0644, "Print DBG statements"); /* must be before zap DEF_PARM(uint, poll_digital_inputs, 1000, 0644, "Poll Digital Inputs"); DEF_PARM_BOOL(reversepolarity, 0, 0644, "Reverse Line Polarity"); DEF_PARM_BOOL(vmwineon, 0, 0644, "Indicate voicemail to a neon lamp"); -DEF_PARM_BOOL(dtmf_detection, 0, 0644, "Do DTMF detection in hardware"); +DEF_PARM_BOOL(dtmf_detection, 1, 0644, "Do DTMF detection in hardware"); #ifdef ZT_VMWI DEF_PARM_BOOL(vmwi_ioctl, 0, 0644, "Asterisk support VMWI notification via ioctl"); @@ -63,14 +63,13 @@ enum fxs_leds { #define NUM_LEDS 2 -static /* 0x0F */ DECLARE_CMD(FXS, REGISTER_REQUEST, byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high); /* Shortcuts */ #define SLIC_WRITE 1 #define SLIC_READ 0 #define SLIC_DIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL) \ - CALL_PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 0, (reg), 0, (dL), 0) + xpp_register_request((xbus), (xpd), (chipsel), (writing), 0, (reg), 0, (dL), 0) #define SLIC_INDIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL,dH) \ - CALL_PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 1, 0x1E, (reg), (dL), (dH)) + xpp_register_request((xbus), (xpd), (chipsel), (writing), 1, 0x1E, (reg), (dL), (dH)) #define VALID_CHIPSEL(x) (((chipsel) >= 0 && (chipsel) <= 7) || (chipsel) == ALL_CHANS) @@ -89,9 +88,10 @@ enum fxs_state { #define FXS_LINE_POL_ACTIVE ((reversepolarity) ? FXS_LINE_REV_ACTIVE : FXS_LINE_ACTIVE) #define FXS_LINE_POL_OHTRANS ((reversepolarity) ? FXS_LINE_REV_OHTRANS : FXS_LINE_OHTRANS) +/* + * DTMF detection + */ #define DTMF_REGISTER 0x18 /* 24 */ -#define POLL_DTMF_INTERVAL 20 /* ticks */ - /*---------------- FXS Protocol Commands ----------------------------------*/ @@ -126,7 +126,6 @@ struct FXS_priv_data { xpp_line_t search_fsk_pattern; xpp_line_t found_fsk_pattern; xpp_line_t update_offhook_state; - xpp_line_t dtmf_keypressed; int led_counter[NUM_LEDS][CHANNELS_PERXPD]; int ohttimer[CHANNELS_PERXPD]; #define OHT_TIMER 6000 /* How long after RING to retain OHT */ @@ -500,7 +499,7 @@ static int FXS_card_zaptel_postregistration(xpd_t *xpd, bool on) return 0; } -int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig) +static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig) { struct FXS_priv_data *priv; int ret = 0; @@ -630,8 +629,12 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a if (IS_SET(xpd->digital_inputs | xpd->digital_outputs, pos)) return 0; /* Nothing to do */ BIT_CLR(xpd->cid_on, pos); - BIT_SET(priv->search_fsk_pattern, pos); - pcm_recompute(xpd, xpd->offhook | xpd->cid_on | priv->search_fsk_pattern); + if(priv->lasttxhook[pos] == FXS_LINE_POL_ACTIVE) { + priv->ohttimer[pos] = OHT_TIMER; + priv->idletxhookstate[pos] = FXS_LINE_POL_OHTRANS; + BIT_SET(priv->search_fsk_pattern, pos); + pcm_recompute(xpd, xpd->offhook | xpd->cid_on | priv->search_fsk_pattern); + } if(!IS_SET(xpd->offhook, pos)) start_stop_vm_led(xbus, xpd, pos); return 0; @@ -642,7 +645,30 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a (val & ZT_TONEDETECT_ON) ? "ON" : "OFF", (val & ZT_TONEDETECT_MUTE) ? "MUTE" : "NO-MUTE", (dtmf_detection ? "YES" : "NO")); - return (dtmf_detection) ? 0 : -ENOTTY; + if(!dtmf_detection) { + SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x17, 0); + return -ENOTTY; + } else { + /* Enable DTMF interrupts (XPD will notify when DTMF will be detected) */ + SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x17, 1); + return 0; + } + case ZT_SETPOLARITY: + if (get_user(val, (int __user *)arg)) + return -EFAULT; + /* Can't change polarity while ringing or when open */ + if (priv->lasttxhook[pos] == FXS_LINE_RING || priv->lasttxhook[pos] == FXS_LINE_OPEN) { + LINE_ERR(xpd, pos, "ZT_SETPOLARITY: %s Cannot change when lasttxhook=0x%X\n", + (val)?"ON":"OFF", priv->lasttxhook[pos]); + return -EINVAL; + } + LINE_DBG(SIGNAL, xpd, pos, "ZT_SETPOLARITY: %s\n", (val)?"ON":"OFF"); + if ((val && !reversepolarity) || (!val && reversepolarity)) + priv->lasttxhook[pos] |= FXS_LINE_RING; + else + priv->lasttxhook[pos] &= ~FXS_LINE_RING; + linefeed_control(xbus, xpd, pos, priv->lasttxhook[pos]); + return 0; #ifdef ZT_VMWI case ZT_VMWI: /* message-waiting led control */ if (get_user(val, (int __user *)arg)) @@ -770,17 +796,7 @@ static void poll_inputs(xpd_t *xpd) } } -static void poll_dtmf(xpd_t *xpd) -{ - int i; - - for_each_line(xpd, i) { - if(IS_SET(xpd->offhook, i)) - SLIC_DIRECT_REQUEST(xpd->xbus, xpd, i, SLIC_READ, DTMF_REGISTER, 0); - } -} - -void handle_linefeed(xpd_t *xpd) +static void handle_linefeed(xpd_t *xpd) { struct FXS_priv_data *priv; int i; @@ -802,6 +818,7 @@ void handle_linefeed(xpd_t *xpd) enum fxs_state txhook = FXS_LINE_POL_ACTIVE; /* Apply the change if appropriate */ BIT_CLR(xpd->cid_on, i); + BIT_CLR(priv->search_fsk_pattern, i); pcm_recompute(xpd, xpd->offhook | xpd->cid_on); linefeed_control(xpd->xbus, xpd, i, txhook); } @@ -923,45 +940,13 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd) if(SPAN_REGISTERED(xpd)) { if(vmwineon && !vmwi_ioctl) detect_vmwi(xpd); /* Detect via FSK modulation */ - if(dtmf_detection && - (xpd->timer_count % POLL_DTMF_INTERVAL) == 0) - poll_dtmf(xpd); } return 0; } /*---------------- FXS: HOST COMMANDS -------------------------------------*/ -/* 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; - - if(!xbus) { - DBG(GENERAL, "NO XBUS\n"); - return -EINVAL; - } - XFRAME_NEW(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->xbus_idx); - LINE_DBG(REGS, xpd, chipsel, "%c%c R%02X S%02X %02X %02X\n", - (writing)?'W':'R', - (do_subreg)?'S':'D', - regnum, subreg, data_low, data_high); - reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, 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; - REG_FIELD(reg_cmd, do_subreg) = do_subreg; - REG_FIELD(reg_cmd, regnum) = regnum; - REG_FIELD(reg_cmd, subreg) = subreg; - REG_FIELD(reg_cmd, data_low) = data_low; - REG_FIELD(reg_cmd, data_high) = data_high; - ret = send_cmd_frame(xbus, xframe); - return ret; -} - -static /* 0x0F */ HOSTCMD(FXS, XPD_STATE, bool on) +/* 0x0F */ HOSTCMD(FXS, XPD_STATE, bool on) { int i; enum fxs_state value = (on) ? FXS_LINE_POL_ACTIVE : FXS_LINE_OPEN; @@ -984,7 +969,7 @@ static /* 0x0F */ HOSTCMD(FXS, XPD_STATE, bool on) return 0; } -static /* 0x0F */ HOSTCMD(FXS, RING, lineno_t chan, bool on) +/* 0x0F */ HOSTCMD(FXS, RING, lineno_t chan, bool on) { int ret = 0; struct FXS_priv_data *priv; @@ -1006,7 +991,7 @@ static /* 0x0F */ HOSTCMD(FXS, RING, lineno_t chan, bool on) return ret; } -static /* 0x0F */ HOSTCMD(FXS, RELAY_OUT, byte which, bool on) +/* 0x0F */ HOSTCMD(FXS, RELAY_OUT, byte which, bool on) { int value; int relay_channels[] = { 0, 4 }; @@ -1047,7 +1032,6 @@ HANDLER_DEF(FXS, SIG_CHANGED) for_each_line(xpd, i) { if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i)) continue; - BIT_CLR(priv->dtmf_keypressed, i); /* no dtmf history */ if(IS_SET(sig_toggles, i)) { xpd->ringing[i] = 0; /* No more ringing... */ #ifdef WITH_METERING @@ -1101,19 +1085,19 @@ static const char dtmf_digits[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#', 'A', 'B', 'C', 'D' }; -void process_dtmf(xpd_t *xpd, const reg_cmd_t *info) +static void process_dtmf(xpd_t *xpd, const reg_cmd_t *info) { int i; byte val = REG_FIELD(info, data_low); xpp_line_t lines = BIT(REG_FIELD(info, chipsel)); byte digit; - bool on = val & 0x10; + bool is_down = val & 0x10; struct FXS_priv_data *priv; priv = xpd->priv; val &= 0xF; if(val <= 0) { - if(on) + if(is_down) XPD_NOTICE(xpd, "Bad DTMF value %d. Ignored\n", val); return; } @@ -1121,40 +1105,35 @@ void process_dtmf(xpd_t *xpd, const reg_cmd_t *info) digit = dtmf_digits[val]; for_each_line(xpd, i) { if(IS_SET(lines, i)) { - if(on && !IS_SET(priv->dtmf_keypressed, i)) { - LINE_DBG(SIGNAL, xpd, i, "DTMF digit %2d PRESSED (%d)\n", digit, val); - BIT_SET(priv->dtmf_keypressed, i); - if(dtmf_detection) + if(dtmf_detection) { + LINE_DBG(SIGNAL, xpd, i, "DTMF digit %s (val=%d) '%c'\n", + (is_down)?"DOWN":"UP", val, digit); + if(is_down) { + BIT_SET(xpd->mute_dtmf, i); zt_qevent_lock(&xpd->chans[i], ZT_EVENT_DTMFDOWN | digit); - } else if(!on && IS_SET(priv->dtmf_keypressed, i)) { - LINE_DBG(SIGNAL, xpd, i, "DTMF digit %2d RELEASED\n", digit); - BIT_CLR(priv->dtmf_keypressed, i); - if(dtmf_detection) + } else { zt_qevent_lock(&xpd->chans[i], ZT_EVENT_DTMFUP | digit); + BIT_CLR(xpd->mute_dtmf, i); + } } break; } } } -HANDLER_DEF(FXS, REGISTER_REPLY) +static int FXS_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info) { - reg_cmd_t *info = &RPACKET_FIELD(pack, FXS, REGISTER_REPLY, reg_cmd); unsigned long flags; struct FXS_priv_data *priv; byte regnum; bool indirect; - if(!xpd) { - notify_bad_xpd(__FUNCTION__, xbus, pack->addr, cmd->name); - return -EPROTO; - } spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; BUG_ON(!priv); indirect = (REG_FIELD(info, regnum) == 0x1E); regnum = (indirect) ? REG_FIELD(info, subreg) : REG_FIELD(info, regnum); - XPD_DBG(REGS, xpd, "REGISTER_REPLY: %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n", + XPD_DBG(REGS, xpd, "%s reg_num=0x%X, dataL=0x%X dataH=0x%X\n", (indirect)?"I":"D", regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high)); if(!SPAN_REGISTERED(xpd)) @@ -1178,12 +1157,11 @@ out: return 0; } -xproto_table_t PROTO_TABLE(FXS) = { +static xproto_table_t PROTO_TABLE(FXS) = { .owner = THIS_MODULE, .entries = { /* Prototable Card Opcode */ XENTRY( FXS, FXS, SIG_CHANGED ), - XENTRY( FXS, FXS, REGISTER_REPLY ), }, .name = "FXS", .type = XPD_TYPE_FXS, @@ -1200,6 +1178,7 @@ xproto_table_t PROTO_TABLE(FXS) = { .card_open = FXS_card_open, .card_close = FXS_card_close, .card_ioctl = FXS_card_ioctl, + .card_register_reply = FXS_card_register_reply, .RING = XPROTO_CALLER(FXS, RING), .RELAY_OUT = XPROTO_CALLER(FXS, RELAY_OUT), @@ -1214,7 +1193,7 @@ static bool fxs_packet_is_valid(xpacket_t *pack) const xproto_entry_t *xe; // DBG(GENERAL, "\n"); - xe = xproto_card_entry(&PROTO_TABLE(FXS), pack->opcode); + xe = xproto_card_entry(&PROTO_TABLE(FXS), XPACKET_OP(pack)); return xe != NULL; } @@ -1401,7 +1380,7 @@ static int handle_register_command(xpd_t *xpd, char *cmdline) xpd->requested_reply = regcmd; if(print_dbg) dump_reg_cmd("FXS", ®cmd, 1); - ret = CALL_PROTO(FXS, REGISTER_REQUEST, xpd->xbus, xpd, + ret = xpp_register_request(xpd->xbus, xpd, REG_FIELD(®cmd, chipsel), writing, REG_FIELD(®cmd, do_subreg), |