Index: fxotune.c =================================================================== --- fxotune.c (revision 1332) +++ fxotune.c (working copy) @@ -130,6 +130,7 @@ short inbuf[BUFFER_LENGTH]; int lowest = 0; float acim_results[16]; + ZT_HOOK_DATA hook_data; if (debug && !outfile) { if (!(outfile = fopen("fxotune.vals", "w"))) { @@ -164,8 +165,10 @@ fprintf(stderr, "Unable to set buffer information!\n"); return -1; } - x = ZT_OFFHOOK; - if (ioctl(whichzap, ZT_HOOK, &x)) { + hook_data.x = ZT_OFFHOOK; + hook_data.polarity = 0; + *hook_data.dtmfCidData=0; + if (ioctl(whichzap, ZT_HOOK, &hook_data)) { fprintf(stderr, "Cannot bring fd %d off hook", whichzap); return -1; } @@ -189,15 +192,20 @@ if (needtoreset > 8) { /* Do line hookstate reset */ x = ZT_ONHOOK; + hook_data.x = ZT_ONHOOK; + hook_data.polarity = 0; + *hook_data.dtmfCidData=0; - if (ioctl(whichzap, ZT_HOOK, &x)) { + if (ioctl(whichzap, ZT_HOOK, &hook_data)) { fprintf(stderr, "Unable to hang up fd %d\n", whichzap); return -1; } sleep(2); - x = ZT_OFFHOOK; - if (ioctl(whichzap, ZT_HOOK, &x)) { + hook_data.x = ZT_OFFHOOK; + hook_data.polarity = 0; + *hook_data.dtmfCidData=0; + if (ioctl(whichzap, ZT_HOOK, &hook_data)) { fprintf(stderr, "Cannot bring fd %d off hook", whichzap); return -1; } Index: zaptel.c =================================================================== --- zaptel.c (revision 1332) +++ zaptel.c (working copy) @@ -229,7 +229,8 @@ ZT_TXSTATE_FLASH,ZT_TXSTATE_DEBOUNCE,ZT_TXSTATE_AFTERSTART, ZT_TXSTATE_RINGON,ZT_TXSTATE_RINGOFF,ZT_TXSTATE_KEWL, ZT_TXSTATE_AFTERKEWL,ZT_TXSTATE_PULSEBREAK,ZT_TXSTATE_PULSEMAKE, - ZT_TXSTATE_PULSEAFTER + ZT_TXSTATE_PULSEAFTER,ZT_TXSTATE_CID_1,ZT_TXSTATE_CID_2, + ZT_TXSTATE_CID_FINAL } ZT_TXSTATE_t; typedef short sumtype[ZT_MAX_CHUNKSIZE]; @@ -2606,7 +2607,14 @@ } /* Notify userspace process if there is nothing left */ chan->dialing = 0; - __qevent(chan, ZT_EVENT_DIALCOMPLETE); + + /* Check so that we don't do a caller-ID event. */ + if (chan->txstate != ZT_TXSTATE_CID_1 + && chan->txstate != ZT_TXSTATE_CID_2 + && chan->txstate != ZT_TXSTATE_CID_FINAL) + { + __qevent(chan, ZT_EVENT_DIALCOMPLETE); + } } static int zt_release(struct inode *inode, struct file *file) @@ -3975,7 +3983,9 @@ int oldconf; void *rxgain=NULL; echo_can_state_t *ec, *tec; + ZT_HOOK_DATA hook_data; + if (!chan) return -ENOSYS; @@ -4215,7 +4225,9 @@ rv = 0; break; case ZT_HOOK: - get_user(j,(int *)data); + if (copy_from_user(&hook_data, (ZT_HOOK_DATA *) data, sizeof(ZT_HOOK_DATA))) + return -EFAULT; + j=hook_data.x; if (chan->flags & ZT_FLAG_CLEAR) return -EINVAL; if (chan->sig == ZT_SIG_CAS) @@ -4252,13 +4264,28 @@ spin_lock_irqsave(&chan->lock, flags); if (chan->txstate != ZT_TXSTATE_ONHOOK) { spin_unlock_irqrestore(&chan->lock, flags); + printk("ZT_RING/ZT_START EBUSY\n"); return -EBUSY; } if (chan->sig & __ZT_SIG_FXO) { - ret = 0; chan->cadencepos = 0; - ret = chan->ringcadence[0]; - zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_RINGON, ret); + + /* If we shall reverse the polarity before CID do that now. */ + if (hook_data.polarity == 1) { + ret=1; + chan->span->ioctl(chan, ZT_SETPOLARITY_KS, (unsigned long)&ret); + } + + /* If we have CallerID string to send as DTMF. */ + if (strlen(hook_data.dtmfCidData) > 0) { + strcpy(chan->txdialbuf, hook_data.dtmfCidData); + ret=200; + zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_CID_1, ret); + } else { + chan->cadencepos = 0; + ret = chan->ringcadence[0]; + zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_RINGON, ret); + } } else zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_START, chan->starttime); spin_unlock_irqrestore(&chan->lock, flags); @@ -5067,11 +5094,55 @@ static inline void __rbs_otimer_expire(struct zt_chan *chan) { int len = 0; + int x; /* Called with chan->lock held */ chan->otimer = 0; /* Move to the next timer state */ switch(chan->txstate) { + case ZT_TXSTATE_CID_1: /* Send DTMF tones. */ + chan->dialing = 1; + __do_dtmf(chan); + x=1; + chan->span->ioctl(chan, ZT_AUDIO_XMIT_CTL_KS, (unsigned long)&x); + len=200; + zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_CID_2, len); + break; + + case ZT_TXSTATE_CID_2: + if (chan->dialing == 1) { + /* Still sending - wait some more. + TODO: Infinite loop check? */ + + /* We seem to need to do the ZT_AUDIO_XMIT_CTL_KS every time + in order to be able to transmit the DTMF tones. */ + x=1; + chan->span->ioctl(chan, ZT_AUDIO_XMIT_CTL_KS, (unsigned long)&x); + + len=200; + zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_CID_2, len); + } else { + /* wait before switch back of polarity. */ + len=300; + zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_CID_FINAL, len); + } + break; + + case ZT_TXSTATE_CID_FINAL: + /* Switch back polarity and wait another 100ms before sending + first ring. */ + x=0; + chan->span->ioctl(chan, ZT_AUDIO_XMIT_CTL_KS, (unsigned long)&x); + /* We don't really need to check polarity flag here, + * since resetting the polarity should be harmless here. + */ + x=0; + chan->span->ioctl(chan, ZT_SETPOLARITY_KS, (unsigned long)&x); + chan->cadencepos = 0; + len = chan->ringcadence[0]; + zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_RINGON, len); + break; + case ZT_TXSTATE_RINGOFF: /* Turn on the ringer now that the silent time has passed */ ++chan->cadencepos; @@ -5100,7 +5171,7 @@ len = chan->curzone->ringcadence[chan->cadencepos]; } - zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_RINGOFF, len); + zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_RINGOFF, len); __qevent(chan, ZT_EVENT_RINGEROFF); break; Index: zaptel.h =================================================================== --- zaptel.h (revision 1332) +++ zaptel.h (working copy) @@ -336,7 +336,17 @@ void *data; } ZT_INDIRECT_DATA; +/* + * \brief Struct for passing hook data, polarity flag + * and caller-ID to zaptel driver. + */ +typedef struct zt_hook_data { + int x; /* Hook operation */ + int polarity; /* '1'=Polarity switch before caller-ID, '0' no switch. */ + char dtmfCidData[ZT_MAX_DTMF_BUF]; /* DTMF caller-ID string. */ +} ZT_HOOK_DATA; + /* ioctl definitions */ #define ZT_CODE 'J' @@ -654,6 +664,23 @@ */ #define ZT_SETPOLARITY _IOW (ZT_CODE, 92, int) +/* + * Control audio xmit. 0 = Off, 1 = On + */ +#define ZT_AUDIO_XMIT_CTL _IOW (ZT_CODE, 93, int) + +/* + * Set polarity -- implemented by individual driver. 0 = forward, 1 = reverse + * When called from kernel space (there is probably a better method to do this...) + */ +#define ZT_SETPOLARITY_KS _IOW (ZT_CODE, 94, int) + +/* + * Control audio xmit. 0 = Off, 1 = On + * When called from kernel space (there is probably a better method to do this...) + */ +#define ZT_AUDIO_XMIT_CTL_KS _IOW (ZT_CODE, 95, int) + /* * Startup or Shutdown a span */ Index: wctdm.c =================================================================== --- wctdm.c (revision 1332) +++ wctdm.c (working copy) @@ -1725,6 +1725,8 @@ struct wctdm_echo_coefs echoregs; struct wctdm *wc = chan->pvt; int x; + int ks=0; + switch (cmd) { case ZT_ONHOOKTRANSFER: if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) @@ -1745,15 +1747,27 @@ wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook); } break; + case ZT_SETPOLARITY_KS: + ks=1; case ZT_SETPOLARITY: - if (get_user(x, (int *)data)) - return -EFAULT; - if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) + if (ks == 0) { + if (get_user(x, (int *)data)) { + printk("ZT_SETPOLARITY: EFAULT x=%d\n", x); + return -EFAULT; + } + } else { + x=*(int *)data; + } + if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) { + printk("ZT_SETPOLARITY: EINVAL(1)\n"); return -EINVAL; + } /* Can't change polarity while ringing or when open */ if ((wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x04) || - (wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x00)) + (wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x00)) { + printk("ZT_SETPOLARITY: EINVAL(2)\n"); return -EINVAL; + } if ((x && !reversepolarity) || (!x && reversepolarity)) wc->mod[chan->chanpos - 1].fxs.lasttxhook |= 0x04; @@ -1761,6 +1775,24 @@ wc->mod[chan->chanpos - 1].fxs.lasttxhook &= ~0x04; wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook); break; + + case ZT_AUDIO_XMIT_CTL_KS: + ks=1; + case ZT_AUDIO_XMIT_CTL: + if (ks == 0) { + if (get_user(x, (int *)data)) { + printk("ZT_AUDIO_XMIT_CTL: EFAULT x=%d\n", x); + return -EFAULT; + } + } else { + x=*(int *)data; + } + regop.indirect=0; + regop.reg=64; + regop.val=(x == 0 ? 5 : 6) & 0xff; + wctdm_setreg(wc, chan->chanpos - 1, regop.reg, regop.val); + break; + case WCTDM_GET_STATS: if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { stats.tipvolt = wctdm_getreg(wc, chan->chanpos - 1, 80) * -376; @@ -1830,6 +1862,7 @@ } break; + default: return -ENOTTY; } Index: wctdm.h =================================================================== --- wctdm.h (revision 1332) +++ wctdm.h (working copy) @@ -67,3 +67,4 @@ #endif /* _WCTDM_H */ +