diff -Naur zaptel.orig/zaptel.c zaptel/zaptel.c --- zaptel.orig/zaptel.c 2004-06-25 19:54:13.000000000 +0300 +++ zaptel/zaptel.c 2004-06-25 19:54:24.000000000 +0300 @@ -185,6 +185,10 @@ }; static int debug; +static int pulse_pause = 800; +static int pulse_make = 60; +static int pulse_break = 40; + /* states for transmit signalling */ typedef enum {ZT_TXSTATE_ONHOOK,ZT_TXSTATE_OFFHOOK,ZT_TXSTATE_START, @@ -256,6 +260,7 @@ #define DIGIT_MODE_DTMF 0 #define DIGIT_MODE_MFV1 1 +#define DIGIT_MODE_PULSE 2 #include "digits.h" @@ -878,6 +883,8 @@ struct ppp_channel *ppp; #endif + if(chan->outbound_pulse_timer.function) + del_timer(&chan->outbound_pulse_timer); zt_reallocbufs(chan, 0, 0); spin_lock_irqsave(&chan->lock, flags); #ifdef CONFIG_ZAPATA_PPP @@ -2016,6 +2023,12 @@ chan->ringcadence[0] = chan->starttime; chan->ringcadence[1] = ZT_RINGOFFTIME; } + /* initialize pulse stuff */ + chan->pulse_enqueued = 0; + chan->current_pulse = 0; + chan->pulse_state = SENDING_PAUSE; + init_timer(&chan->outbound_pulse_timer); + spin_unlock_irqrestore(&chan->lock, flags); if (rxgain) @@ -2434,6 +2447,166 @@ return NULL; } +void zt_sethook(struct zt_chan *chan, int state ) +{ + unsigned long flags; + switch(state) + { + case (ZT_ONHOOK): + spin_lock_irqsave(&chan->lock, flags); + if (chan->span->flags & ZT_FLAG_RBS) { + if (chan->sig == ZT_SIG_CAS) { + zt_cas_setbits(chan, chan->idlebits); + } else if ((chan->sig == ZT_SIG_FXOKS) && + (chan->txstate != ZT_TXSTATE_ONHOOK)) { + /* Do RBS signalling on the channel's behalf */ + zt_rbs_sethook(chan, ZT_TXSIG_KEWL, ZT_TXSTATE_KEWL, ZT_KEWLTIME); + } else + zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, + ZT_TXSTATE_ONHOOK, 0); + } else { + /* Let the driver hang up the line if it wants to */ + if (chan->span->sethook) + chan->span->sethook(chan, ZT_ONHOOK); + } + spin_unlock_irqrestore(&chan->lock, flags); + break; + + case (ZT_OFFHOOK): + spin_lock_irqsave(&chan->lock, flags); + zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_DEBOUNCE, + chan->debouncetime); + spin_unlock_irqrestore(&chan->lock, flags); + break; + default: + break; + } +} + + + +/* PULSE timer routine */ +static void pulse_timer(unsigned long arg) +{ + struct zt_chan * chan = (struct zt_chan *) arg; + + if(!chan->dialing) + return; + if(chan->pulse_state == BREAK_PULSE) + { + if(!chan->current_pulse) + { + /* 0.8s */ + zt_sethook(chan, ZT_OFFHOOK); + chan->pulse_state = SENDING_PAUSE; + chan->outbound_pulse_timer.function = pulse_timer; + chan->outbound_pulse_timer.data = (unsigned long)chan; + chan->outbound_pulse_timer.expires = + (pulse_pause*HZ)/1000 + jiffies; + add_timer(&chan->outbound_pulse_timer); + return; + } + } + + if(chan->pulse_state != MAKE_PULSE) + { + if(!chan->current_pulse) + { + /* check if we have more digits to send */ + if(chan->pulse_enqueued > 0) + { + chan->current_pulse = chan->pulses[0]; + chan->pulse_enqueued--; + if(chan->pulse_enqueued) + memmove(chan->pulses, chan->pulses + 1, + chan->pulse_enqueued); + /* echo cancelation pause 0.5s*/ + if(chan->current_pulse == 13) + { + chan->current_pulse = 0; + chan->pulse_state = SENDING_PAUSE; + chan->outbound_pulse_timer.function = pulse_timer; + chan->outbound_pulse_timer.data = (unsigned long)chan; + chan->outbound_pulse_timer.expires = + (500*HZ)/1000 + jiffies; + add_timer(&chan->outbound_pulse_timer); + return; + } + + } else + { + chan->dialing = 0; + __qevent(chan, ZT_EVENT_DIALCOMPLETE); + return; + } + } + + zt_sethook(chan, ZT_ONHOOK); + + /* 0.06s - default */ + chan->pulse_state = MAKE_PULSE; + chan->outbound_pulse_timer.function = pulse_timer; + chan->outbound_pulse_timer.data = (unsigned long)chan; + chan->outbound_pulse_timer.expires = + (pulse_make*HZ)/1000 + jiffies; + add_timer(&chan->outbound_pulse_timer); + } else + if(chan->pulse_state == MAKE_PULSE) + { + /* 0.04s - default */ + chan->pulse_state = BREAK_PULSE; + + if(chan->current_pulse) + chan->current_pulse--; + + zt_sethook(chan, ZT_OFFHOOK); + chan->outbound_pulse_timer.function = pulse_timer; + chan->outbound_pulse_timer.data = (unsigned long)chan; + chan->outbound_pulse_timer.expires = + (pulse_break*HZ)/1000 + jiffies; + add_timer(&chan->outbound_pulse_timer); + } +} + +static void __do_pulse(struct zt_chan *chan, char c) +{ + switch(c) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + chan->pulses[chan->pulse_enqueued++] = c - '0'; + break; + case '0': + chan->pulses[chan->pulse_enqueued++] = 10; + break; + case '*': + chan->pulses[chan->pulse_enqueued++] = 11; + break; + case '#': + chan->pulses[chan->pulse_enqueued++] = 12; + break; + case 'w': + case 'W': + chan->pulses[chan->pulse_enqueued++] = 13; + break; + default: + break; + } + + if(debug) + printk("enqueed %d\n", chan->pulses[chan->pulse_enqueued-1]); + + /* Notify userspace process if there is nothing left */ +} + + + static void __do_dtmf(struct zt_chan *chan) { char c; @@ -2468,6 +2641,64 @@ __qevent(chan, ZT_EVENT_DIALCOMPLETE); } +static void __do_dial(struct zt_chan *chan) +{ + char c; + /* Called with chan->lock held */ + + + while (strlen(chan->txdialbuf)) { + c = chan->txdialbuf[0]; + /* Skooch */ + memmove(chan->txdialbuf, chan->txdialbuf + 1, sizeof(chan->txdialbuf) - 1); + switch(c) { + case 'T': + case 't': + chan->digitmode = DIGIT_MODE_DTMF; + chan->tonep = 0; + break; + case 'M': + case 'm': + chan->digitmode = DIGIT_MODE_MFV1; + chan->tonep = 0; + break; + case 'P': + case 'p': + chan->digitmode = DIGIT_MODE_PULSE; + chan->tonep = 0; + break; + + default: + if(chan->digitmode != DIGIT_MODE_PULSE) + { + chan->curtone = + zt_dtmf_tone(c, (chan->digitmode == DIGIT_MODE_MFV1)); + chan->tonep = 0; + /* All done */ + if (chan->curtone) { + zt_init_tone_state(&chan->ts, chan->curtone); + return; + } + } else + { + __do_pulse(chan, c); + } + } + } + + if(chan->digitmode == DIGIT_MODE_PULSE) + { + chan->outbound_pulse_timer.function = pulse_timer; + chan->outbound_pulse_timer.data = (unsigned long)chan; + chan->outbound_pulse_timer.expires = (pulse_pause*HZ)/1000 + + jiffies; + add_timer(&chan->outbound_pulse_timer); + + } +} + + + static int zt_release(struct inode *inode, struct file *file) { int unit = UNIT(file); @@ -3250,7 +3481,7 @@ case ZT_DIAL_OP_REPLACE: strcpy(chan->txdialbuf, tdo.dialstr); chan->dialing = 1; - __do_dtmf(chan); + __do_dial(chan); break; case ZT_DIAL_OP_APPEND: if (strlen(tdo.dialstr) + strlen(chan->txdialbuf) >= ZT_MAX_DTMF_BUF) @@ -3262,7 +3493,7 @@ if (!chan->dialing) { chan->dialing = 1; - __do_dtmf(chan); + __do_dial(chan); } break; default: diff -Naur zaptel.orig/zaptel.h zaptel/zaptel.h --- zaptel.orig/zaptel.h 2004-06-25 19:54:13.000000000 +0300 +++ zaptel/zaptel.h 2004-06-25 19:54:24.000000000 +0300 @@ -132,6 +132,17 @@ #define ZT_DEFAULT_NUM_BUFS 2 #define ZT_MAX_NUM_BUFS 32 #define ZT_MAX_BUF_SPACE 32768 +#define ZT_MAX_PULSE_QUEUE 255 + +/* pulse - 0.06s */ +#define MAKE_PULSE 1 +/* gap - 0.04s + * 1 digit == 0.1s + */ +#define BREAK_PULSE 2 +/* pause between digits - 0.8s */ +#define SENDING_PAUSE 3 + #define ZT_DEFAULT_BLOCKSIZE 1024 #define ZT_DEFAULT_MTR_MRU 2048 @@ -927,6 +938,13 @@ int toneflags; sf_detect_state_t rd; + /* PULSE dialing stuff */ + unsigned char pulses[ZT_MAX_PULSE_QUEUE]; + unsigned char current_pulse; + int pulse_enqueued; + int pulse_state; + struct timer_list outbound_pulse_timer; + struct zt_chan *master; /* Our Master channel (could be us) */ /* Next slave (if appropriate) */ int nextslave;