summaryrefslogtreecommitdiff
path: root/xpp/card_fxs.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-09-14 22:29:36 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-09-14 22:29:36 +0000
commitc91b2cd29653da525d1a37cf680f4a75b2d3b208 (patch)
treef26185291a7ebb24902a2737d6e5b1fed75bb8c1 /xpp/card_fxs.c
parent236601045ee0a95930414d8d5f822d9a61054aae (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.c139
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", &regcmd, 1);
- ret = CALL_PROTO(FXS, REGISTER_REQUEST, xpd->xbus, xpd,
+ ret = xpp_register_request(xpd->xbus, xpd,
REG_FIELD(&regcmd, chipsel),
writing,
REG_FIELD(&regcmd, do_subreg),