From 46962b1907b7c476a969e898f682e82405ef317e Mon Sep 17 00:00:00 2001 From: mattf Date: Tue, 10 Jan 2006 22:06:29 +0000 Subject: Commits for HardHDLC API in zaptel (#5313) git-svn-id: http://svn.digium.com/svn/zaptel/trunk@887 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- zaptel.c | 273 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 244 insertions(+), 29 deletions(-) (limited to 'zaptel.c') diff --git a/zaptel.c b/zaptel.c index 4ccd3e8..1dad83d 100644 --- a/zaptel.c +++ b/zaptel.c @@ -174,6 +174,10 @@ EXPORT_SYMBOL(zt_alarm_notify); EXPORT_SYMBOL(zt_set_dynamic_ioctl); EXPORT_SYMBOL(zt_ec_chunk); EXPORT_SYMBOL(zt_ec_span); +EXPORT_SYMBOL(zt_hdlc_abort); +EXPORT_SYMBOL(zt_hdlc_finish); +EXPORT_SYMBOL(zt_hdlc_getbuf); +EXPORT_SYMBOL(zt_hdlc_putbuf); #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_entries[ZT_MAX_SPANS]; @@ -499,6 +503,8 @@ static char *sigstr(int sig) return "HDLCFCS"; case ZT_SIG_HDLCNET: return "HDLCNET"; + case ZT_SIG_HARDHDLC: + return "Hardware-assisted HDLC"; case ZT_SIG_SLAVE: return "Slave"; case ZT_SIG_CAS: @@ -971,7 +977,9 @@ static void close_channel(struct zt_chan *chan) struct ppp_channel *ppp; #endif - zt_reallocbufs(chan, 0, 0); + /* XXX Buffers should be send out before reallocation!!! XXX */ + if (!(chan->flags & ZT_FLAG_NOSTDTXRX)) + zt_reallocbufs(chan, 0, 0); spin_lock_irqsave(&chan->lock, flags); #ifdef CONFIG_ZAPATA_PPP ppp = chan->ppp; @@ -1670,7 +1678,7 @@ static ssize_t zt_chan_read(struct file *file, char *usrbuf, size_t count, int u spin_lock_irqsave(&chan->lock, flags); if (chan->eventinidx != chan->eventoutidx) { spin_unlock_irqrestore(&chan->lock, flags); - return -ELAST; + return -ELAST /* - chan->eventbuf[chan->eventoutidx]*/; } res = chan->outreadbuf; if (chan->rxdisable) @@ -1683,6 +1691,20 @@ static ssize_t zt_chan_read(struct file *file, char *usrbuf, size_t count, int u if (rv) return (rv); } amnt = count; +/* added */ +#if 0 + if ((unit == 24) || (unit == 48) || (unit == 16) || (unit == 47)) { + int myamnt = amnt; + int x; + if (amnt > chan->readn[chan->outreadbuf]) + myamnt = chan->readn[chan->outreadbuf]; + printk("zt_chan_read(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d\n", + unit, chan->inwritebuf, chan->outwritebuf, myamnt); + printk("\t("); for (x = 0; x < myamnt; x++) printk((x ? " %02x" : "%02x"), (unsigned char)usrbuf[x]); + printk(")\n"); + } +#endif +/* end addition */ if (chan->flags & ZT_FLAG_LINEAR) { if (amnt > (chan->readn[chan->outreadbuf] << 1)) amnt = chan->readn[chan->outreadbuf] << 1; @@ -1782,6 +1804,15 @@ static ssize_t zt_chan_write(struct file *file, const char *usrbuf, size_t count printk("zt_chan_write(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d\n", unit, chan->inwritebuf, chan->outwritebuf, amnt); #endif +#if 0 + if ((unit == 24) || (unit == 48) || (unit == 16) || (unit == 47)) { + int x; + printk("zt_chan_write/in(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d, txdisable: %d)\n", + unit, chan->inwritebuf, chan->outwritebuf, amnt, chan->txdisable); + printk("\t("); for (x = 0; x < amnt; x++) printk((x ? " %02x" : "%02x"), (unsigned char)usrbuf[x]); + printk(")\n"); + } +#endif if (amnt) { if (chan->flags & ZT_FLAG_LINEAR) { @@ -1826,6 +1857,9 @@ static ssize_t zt_chan_write(struct file *file, const char *usrbuf, size_t count chan->outwritebuf = oldbuf; } spin_unlock_irqrestore(&chan->lock, flags); + + if (chan->flags & ZT_FLAG_NOSTDTXRX && chan->span->hdlc_hard_xmit) + chan->span->hdlc_hard_xmit(chan); } return amnt; } @@ -2000,7 +2034,7 @@ static int zt_hangup(struct zt_chan *chan) if (!chan->span) return 0; /* Can't hang up a clear channel */ - if (chan->flags & ZT_FLAG_CLEAR) + if (chan->flags & (ZT_FLAG_CLEAR | ZT_FLAG_NOSTDTXRX)) return -EINVAL; chan->kewlonhook = 0; @@ -2150,11 +2184,11 @@ static int initialize_channel(struct zt_chan *chan) zt_set_law(chan,0); zt_hangup(chan); - /* Make sure that the audio flag is cleared on a clear channel */ - if (chan->sig & ZT_SIG_CLEAR) + /* Make sure that the audio flag is cleared on a clear channel */ + if ((chan->sig & ZT_SIG_CLEAR) || (chan->sig & ZT_SIG_HARDHDLC)) chan->flags &= ~ZT_FLAG_AUDIO; - if (chan->sig == ZT_SIG_CLEAR) + if ((chan->sig == ZT_SIG_CLEAR) || (chan->sig == ZT_SIG_HARDHDLC)) chan->flags &= ~(ZT_FLAG_PPP | ZT_FLAG_FCS | ZT_FLAG_HDLC); chan->flags &= ~ZT_FLAG_LINEAR; @@ -2796,10 +2830,11 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c struct zt_params param; } stack; struct zt_chan *chan; + unsigned long flags; + unsigned char *txgain, *rxgain; #ifdef ALLOW_CHAN_DIAG /* This structure is huge and will bork a 4k stack */ struct zt_chan mychan; - unsigned long flags; #endif int i,j; int return_master = 0; @@ -2937,30 +2972,39 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c /* make sure channel number makes sense */ if ((i < 0) || (i > ZT_MAX_CHANNELS) || !chans[i]) return(-EINVAL); if (!(chans[i]->flags & ZT_FLAG_AUDIO)) return (-EINVAL); - if (!chans[i]->gainalloc) { - chans[i]->rxgain = kmalloc(512, GFP_KERNEL); - if (!chans[i]->rxgain) { - chans[i]->rxgain = defgain; - return -ENOMEM; - } else { - chans[i]->gainalloc = 1; - chans[i]->txgain = chans[i]->rxgain + 256; - } - } + + rxgain = kmalloc(512, GFP_KERNEL); + if (!rxgain) + return -ENOMEM; + stack.gain.chan = i; /* put the span # in here */ + txgain = rxgain + 256; + for (j=0;j<256;j++) { - chans[i]->rxgain[j] = stack.gain.rxgain[j]; - chans[i]->txgain[j] = stack.gain.txgain[j]; + rxgain[j] = stack.gain.rxgain[j]; + txgain[j] = stack.gain.txgain[j]; } - if (!memcmp(chans[i]->rxgain, defgain, 256) && - !memcmp(chans[i]->txgain, defgain, 256)) { - /* This is really just a normal gain, so - deallocate the memory and go back to defaults */ + + if (!memcmp(rxgain, defgain, 256) && + !memcmp(txgain, defgain, 256)) { + if (rxgain) + kfree(rxgain); + spin_lock_irqsave(&chans[i]->lock, flags); if (chans[i]->gainalloc) kfree(chans[i]->rxgain); + chans[i]->gainalloc = 0; chans[i]->rxgain = defgain; chans[i]->txgain = defgain; - chans[i]->gainalloc = 0; + spin_unlock_irqrestore(&chans[i]->lock, flags); + } else { + /* This is a custom gain setting */ + spin_lock_irqsave(&chans[i]->lock, flags); + if (chans[i]->gainalloc) + kfree(chans[i]->rxgain); + chans[i]->gainalloc = 1; + chans[i]->rxgain = rxgain; + chans[i]->txgain = txgain; + spin_unlock_irqrestore(&chans[i]->lock, flags); } if (copy_to_user((struct zt_gains *) data,&stack.gain,sizeof(stack.gain))) return -EFAULT; @@ -3262,6 +3306,12 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd if (newmaster != chans[ch.chan]) { recalc_slaves(chans[ch.chan]->master); } + if ((ch.sigtype & ZT_SIG_HARDHDLC) == ZT_SIG_HARDHDLC) { + chans[ch.chan]->flags &= ~ZT_FLAG_FCS; + chans[ch.chan]->flags &= ~ZT_FLAG_HDLC; + chans[ch.chan]->flags |= ZT_FLAG_NOSTDTXRX; + } else + chans[ch.chan]->flags &= ~ZT_FLAG_NOSTDTXRX; } #ifdef CONFIG_ZAPATA_NET if (!res && @@ -5791,7 +5841,8 @@ static inline void __zt_process_putaudio_chunk(struct zt_chan *ss, unsigned char } } -static inline void __zt_putbuf_chunk(struct zt_chan *ss, unsigned char *rxb) +/* HDLC (or other) receiver buffer functions for read side */ +static inline void __putbuf_chunk(struct zt_chan *ss, unsigned char *rxb, int bytes) { /* We transmit data from our master channel */ /* Called with ss->lock held */ @@ -5808,8 +5859,6 @@ static inline void __zt_putbuf_chunk(struct zt_chan *ss, unsigned char *rxb) int res; int left, x; - int bytes = ZT_CHUNKSIZE; - while(bytes) { #if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP) skb = NULL; @@ -5875,6 +5924,10 @@ static inline void __zt_putbuf_chunk(struct zt_chan *ss, unsigned char *rxb) bytes -= left; /* End of frame is decided by block size of 'N' */ eof = (ms->readidx[ms->inreadbuf] >= ms->blocksize); + if (eof && (ss->flags & ZT_FLAG_NOSTDTXRX)) { + eof = 0; + abort = ZT_EVENT_OVERRUN; + } } if (eof) { /* Finished with this buffer, try another. */ @@ -6059,6 +6112,162 @@ out in the later versions, and is put back now. */ } } +static inline void __zt_putbuf_chunk(struct zt_chan *ss, unsigned char *rxb) +{ + __putbuf_chunk(ss, rxb, ZT_CHUNKSIZE); +} + +extern void zt_hdlc_putbuf(struct zt_chan *ss, unsigned char *rxb, int bytes) +{ + unsigned long flags; + int res; + int left; + + spin_lock_irqsave(&ss->lock, flags); + if (ss->inreadbuf < 0) { +#ifdef CONFIG_ZAPATA_DEBUG + printk("No place to receive HDLC frame\n"); +#endif + spin_unlock_irqrestore(&ss->lock, flags); + return; + } + /* Read into the current buffer */ + left = ss->blocksize - ss->readidx[ss->inreadbuf]; + if (left > bytes) + left = bytes; + if (left > 0) { + memcpy(ss->readbuf[ss->inreadbuf] + ss->readidx[ss->inreadbuf], rxb, left); + rxb += left; + ss->readidx[ss->inreadbuf] += left; + bytes -= left; + } + /* Something isn't fit into buffer */ + if (bytes) { +#ifdef CONFIG_ZAPATA_DEBUG + printk("HDLC frame isn't fit into buffer space\n"); +#endif + zt_hdlc_abort(ss, ZT_EVENT_OVERRUN); + } + res = left; + spin_unlock_irqrestore(&ss->lock, flags); +} + +extern void zt_hdlc_abort(struct zt_chan *ss, int event) +{ + unsigned long flags; + spin_lock_irqsave(&ss->lock, flags); + if (ss->inreadbuf >= 0) + ss->readidx[ss->inreadbuf] = 0; + if ((ss->flags & ZT_FLAG_OPEN) && !ss->span->alarms) + __qevent(ss->master, event); + spin_unlock_irqrestore(&ss->lock, flags); +} + +extern void zt_hdlc_finish(struct zt_chan *ss) +{ + int oldreadbuf; + unsigned long flags; + + spin_lock_irqsave(&ss->lock, flags); + + if ((oldreadbuf = ss->inreadbuf) < 0) { +#ifdef CONFIG_ZAPATA_DEBUG + printk("No buffers to finish\n"); +#endif + spin_unlock_irqrestore(&ss->lock, flags); + return; + } + + if (!ss->readidx[ss->inreadbuf]) { +#ifdef CONFIG_ZAPATA_DEBUG + printk("Empty HDLC frame received\n"); +#endif + spin_unlock_irqrestore(&ss->lock, flags); + return; + } + + ss->readn[ss->inreadbuf] = ss->readidx[ss->inreadbuf]; + ss->inreadbuf = (ss->inreadbuf + 1) % ss->numbufs; + if (ss->inreadbuf == ss->outreadbuf) { + ss->inreadbuf = -1; +#if CONFIG_ZAPATA_DEBUG + printk("Notifying reader data in block %d\n", oldreadbuf); +#endif + ss->rxdisable = 0; + } + if (ss->outreadbuf < 0) { + ss->outreadbuf = oldreadbuf; + } + + if (!ss->rxdisable) { + wake_up_interruptible(&ss->readbufq); + wake_up_interruptible(&ss->sel); + if (ss->iomask & ZT_IOMUX_READ) + wake_up_interruptible(&ss->eventbufq); + } + spin_unlock_irqrestore(&ss->lock, flags); +} + +/* Returns 1 if EOF, 0 if data is still in frame, -1 if EOF and no buffers left */ +extern int zt_hdlc_getbuf(struct zt_chan *ss, unsigned char *bufptr, unsigned int *size) +{ + unsigned char *buf; + unsigned long flags; + int left = 0; + int res; + int oldbuf; + + spin_lock_irqsave(&ss->lock, flags); + if (ss->outwritebuf > -1) { + buf = ss->writebuf[ss->outwritebuf]; + left = ss->writen[ss->outwritebuf] - ss->writeidx[ss->outwritebuf]; + /* Strip off the empty HDLC CRC end */ + left -= 2; + if (left <= *size) { + *size = left; + res = 1; + } else + res = 0; + + memcpy(bufptr, &buf[ss->writeidx[ss->outwritebuf]], *size); + ss->writeidx[ss->outwritebuf] += *size; + + if (res) { + /* Rotate buffers */ + oldbuf = ss->outwritebuf; + ss->writeidx[oldbuf] = 0; + ss->writen[oldbuf] = 0; + ss->outwritebuf = (ss->outwritebuf + 1) % ss->numbufs; + if (ss->outwritebuf == ss->inwritebuf) { + ss->outwritebuf = -1; + if (ss->iomask & (ZT_IOMUX_WRITE | ZT_IOMUX_WRITEEMPTY)) + wake_up_interruptible(&ss->eventbufq); + /* If we're only supposed to start when full, disable the transmitter */ + if (ss->txbufpolicy == ZT_POLICY_WHEN_FULL) + ss->txdisable = 1; + res = -1; + } + + if (ss->inwritebuf < 0) + ss->inwritebuf = oldbuf; + + if (!(ss->flags & (ZT_FLAG_NETDEV | ZT_FLAG_PPP))) { + wake_up_interruptible(&ss->writebufq); + wake_up_interruptible(&ss->sel); + if ((ss->iomask & ZT_IOMUX_WRITE) && (res >= 0)) + wake_up_interruptible(&ss->eventbufq); + } + } + } else { + res = -1; + *size = 0; + } + spin_unlock_irqrestore(&ss->lock, flags); + + return res; +} + + static void process_timers(void) { unsigned long flags; @@ -6271,6 +6480,10 @@ int zt_transmit(struct zt_span *span) #if 1 for (x=0;xchannels;x++) { spin_lock_irqsave(&span->chans[x].lock, flags); + if (span->chans[x].flags & ZT_FLAG_NOSTDTXRX) { + spin_unlock_irqrestore(&span->chans[x].lock, flags); + continue; + } if (&span->chans[x] == span->chans[x].master) { if (span->chans[x].otimer) { span->chans[x].otimer -= ZT_CHUNKSIZE; @@ -6352,7 +6565,8 @@ int zt_receive(struct zt_span *span) do { data[pos++] = span->chans[z].readchunk[y]; if (pos == ZT_CHUNKSIZE) { - __zt_receive_chunk(&span->chans[x], data); + if(!(span->chans[x].flags & ZT_FLAG_NOSTDTXRX)) + __zt_receive_chunk(&span->chans[x], data); pos = 0; } z=span->chans[z].nextslave; @@ -6360,7 +6574,8 @@ int zt_receive(struct zt_span *span) } } else { /* Process a normal channel */ - __zt_real_receive(&span->chans[x]); + if (!(span->chans[x].flags & ZT_FLAG_NOSTDTXRX)) + __zt_real_receive(&span->chans[x]); } if (span->chans[x].itimer) { span->chans[x].itimer -= ZT_CHUNKSIZE; -- cgit v1.2.3