📄 zaptel.c
字号:
data[0] = (fcs & 0xff); data[1] = (fcs >> 8) & 0xff; /* Account for FCS length */ ss->writen[ss->inwritebuf]+=2; /* Advance to next window */ oldbuf = ss->inwritebuf; ss->inwritebuf = (ss->inwritebuf + 1) % ss->numbufs; if (ss->inwritebuf == ss->outwritebuf) { /* Whoops, no more space. */ ss->inwritebuf = -1; } if (ss->outwritebuf < 0) { /* Let the interrupt handler know there's some space for us */ ss->outwritebuf = oldbuf; }#if CONFIG_ZAPATA_DEBUG printk("Buffered %d bytes (skblen = %d) to go out in buffer %d\n", ss->writen[oldbuf], skb->len, oldbuf); for (x=0;x<ss->writen[oldbuf];x++) printk("%02x ", ss->writebuf[oldbuf][x]); printk("\n");#endif retval = 1; } spin_unlock_irqrestore(&ss->lock, flags); if (retval) { /* Get rid of the SKB if we're returning non-zero */ /* N.B. this is called in process or BH context so dev_kfree_skb is OK. */ dev_kfree_skb(skb); } return retval;}static int zt_ppp_ioctl(struct ppp_channel *ppp, unsigned int cmd, unsigned long flags){ return -EIO;}static struct ppp_channel_ops ztppp_ops ={ start_xmit: zt_ppp_xmit, ioctl: zt_ppp_ioctl,};#endifstatic void zt_chan_unreg(struct zt_chan *chan){ int x; unsigned long flags;#ifdef CONFIG_ZAPATA_NET if (chan->flags & ZT_FLAG_NETDEV) {#ifdef LINUX26 unregister_hdlc_device(chan->hdlcnetdev->netdev); free_netdev(chan->hdlcnetdev->netdev);#else unregister_hdlc_device(&chan->hdlcnetdev->netdev);#endif kfree(chan->hdlcnetdev); chan->hdlcnetdev = NULL; }#endif write_lock_irqsave(&chan_lock, flags); if (chan->flags & ZT_FLAG_REGISTERED) { chans[chan->channo] = NULL; chan->flags &= ~ZT_FLAG_REGISTERED; }#ifdef CONFIG_ZAPATA_PPP if (chan->ppp) { printk("HUH??? PPP still attached??\n"); }#endif maxchans = 0; for (x=1;x<ZT_MAX_CHANNELS;x++) if (chans[x]) { maxchans = x + 1; /* Remove anyone pointing to us as master and make them their own thing */ if (chans[x]->master == chan) { chans[x]->master = chans[x]; } if ((chans[x]->confna == chan->channo) && (((chans[x]->confmode >= ZT_CONF_MONITOR) && (chans[x]->confmode <= ZT_CONF_MONITORBOTH)) || (chans[x]->confmode == ZT_CONF_DIGITALMON))) { /* Take them out of conference with us */ /* release conference resource if any */ if (chans[x]->confna) zt_check_conf(chans[x]->confna); chans[x]->confna = 0; chans[x]->_confn = 0; chans[x]->confmode = 0; } } chan->channo = -1; write_unlock_irqrestore(&chan_lock, flags);}static ssize_t zt_chan_read(struct file *file, char *usrbuf, size_t count, int unit){ struct zt_chan *chan = chans[unit]; int amnt; int res, rv; int oldbuf,x; unsigned long flags; /* Make sure count never exceeds 65k, and make sure it's unsigned */ count &= 0xffff; if (!chan) return -EINVAL; if (count < 1) return -EINVAL; for(;;) { spin_lock_irqsave(&chan->lock, flags); if (chan->eventinidx != chan->eventoutidx) { spin_unlock_irqrestore(&chan->lock, flags); return -ELAST; } res = chan->outreadbuf; if (chan->rxdisable) res = -1; spin_unlock_irqrestore(&chan->lock, flags); if (res >= 0) break; if (file->f_flags & O_NONBLOCK) return -EAGAIN; rv = schluffen(&chan->readbufq); if (rv) return (rv); } amnt = count; if (chan->flags & ZT_FLAG_LINEAR) { if (amnt > (chan->readn[chan->outreadbuf] << 1)) amnt = chan->readn[chan->outreadbuf] << 1; if (amnt) { /* There seems to be a max stack size, so we have to do this in smaller pieces */ short lindata[128]; int left = amnt >> 1; /* amnt is in bytes */ int pos = 0; int pass; while(left) { pass = left; if (pass > 128) pass = 128; for (x=0;x<pass;x++) lindata[x] = ZT_XLAW(chan->readbuf[chan->outreadbuf][x + pos], chan); if (copy_to_user(usrbuf + (pos << 1), lindata, pass << 1)) return -EFAULT; left -= pass; pos += pass; } } } else { if (amnt > chan->readn[chan->outreadbuf]) amnt = chan->readn[chan->outreadbuf]; if (amnt) { if (copy_to_user(usrbuf, chan->readbuf[chan->outreadbuf], amnt)) return -EFAULT; } } spin_lock_irqsave(&chan->lock, flags); chan->readidx[chan->outreadbuf] = 0; chan->readn[chan->outreadbuf] = 0; oldbuf = chan->outreadbuf; chan->outreadbuf = (chan->outreadbuf + 1) % chan->numbufs; if (chan->outreadbuf == chan->inreadbuf) { /* Out of stuff */ chan->outreadbuf = -1; if (chan->rxbufpolicy == ZT_POLICY_WHEN_FULL) chan->rxdisable = 1; } if (chan->inreadbuf < 0) { /* Notify interrupt handler that we have some space now */ chan->inreadbuf = oldbuf; } spin_unlock_irqrestore(&chan->lock, flags); return amnt;}static ssize_t zt_chan_write(struct file *file, const char *usrbuf, size_t count, int unit){ unsigned long flags; struct zt_chan *chan = chans[unit]; int res, amnt, oldbuf, rv,x; /* Make sure count never exceeds 65k, and make sure it's unsigned */ count &= 0xffff; if (!chan) return -EINVAL; if (count < 1) return -EINVAL; for(;;) { spin_lock_irqsave(&chan->lock, flags); if ((chan->curtone || chan->pdialcount) && !(chan->flags & ZT_FLAG_PSEUDO)) { chan->curtone = NULL; chan->tonep = 0; chan->dialing = 0; chan->txdialbuf[0] = '\0'; chan->pdialcount = 0; } if (chan->eventinidx != chan->eventoutidx) { spin_unlock_irqrestore(&chan->lock, flags); return -ELAST; } res = chan->inwritebuf; spin_unlock_irqrestore(&chan->lock, flags); if (res >= 0) break; if (file->f_flags & O_NONBLOCK) return -EAGAIN; /* Wait for something to be available */ rv = schluffen(&chan->writebufq); if (rv) return rv; } amnt = count; if (chan->flags & ZT_FLAG_LINEAR) { if (amnt > (chan->blocksize << 1)) amnt = chan->blocksize << 1; } else { if (amnt > chan->blocksize) amnt = chan->blocksize; }#if CONFIG_ZAPATA_DEBUG printk("zt_chan_write(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d\n", unit, chan->inwritebuf, chan->outwritebuf, amnt);#endif if (amnt) { if (chan->flags & ZT_FLAG_LINEAR) { /* There seems to be a max stack size, so we have to do this in smaller pieces */ short lindata[128]; int left = amnt >> 1; /* amnt is in bytes */ int pos = 0; int pass; while(left) { pass = left; if (pass > 128) pass = 128; if (copy_from_user(lindata, usrbuf + (pos << 1), pass << 1)) return -EFAULT; left -= pass; for (x=0;x<pass;x++) chan->writebuf[chan->inwritebuf][x + pos] = ZT_LIN2X(lindata[x], chan); pos += pass; } chan->writen[chan->inwritebuf] = amnt >> 1; } else { copy_from_user(chan->writebuf[chan->inwritebuf], usrbuf, amnt); chan->writen[chan->inwritebuf] = amnt; } chan->writeidx[chan->inwritebuf] = 0; if (chan->flags & ZT_FLAG_FCS) calc_fcs(chan); oldbuf = chan->inwritebuf; spin_lock_irqsave(&chan->lock, flags); chan->inwritebuf = (chan->inwritebuf + 1) % chan->numbufs; if (chan->inwritebuf == chan->outwritebuf) { /* Don't stomp on the transmitter, just wait for them to wake us up */ chan->inwritebuf = -1; /* Make sure the transmitter is transmitting in case of POLICY_WHEN_FULL */ chan->txdisable = 0; } if (chan->outwritebuf < 0) { /* Okay, the interrupt handler has been waiting for us. Give them a buffer */ chan->outwritebuf = oldbuf; } spin_unlock_irqrestore(&chan->lock, flags); } return amnt;}static int zt_ctl_open(struct inode *inode, struct file *file){ /* Nothing to do, really */#ifndef LINUX26 MOD_INC_USE_COUNT;#endif return 0;}static int zt_chan_open(struct inode *inode, struct file *file){ /* Nothing to do here for now either */#ifndef LINUX26 MOD_INC_USE_COUNT;#endif return 0;}static int zt_ctl_release(struct inode *inode, struct file *file){ /* Nothing to do */#ifndef LINUX26 MOD_DEC_USE_COUNT;#endif return 0;}static int zt_chan_release(struct inode *inode, struct file *file){ /* Nothing to do for now */#ifndef LINUX26 MOD_DEC_USE_COUNT;#endif return 0;}static void set_txtone(struct zt_chan *ss,int fac, int init_v2, int init_v3){ if (fac == 0) { ss->v2_1 = 0; ss->v3_1 = 0; return; } ss->txtone = fac; ss->v1_1 = 0; ss->v2_1 = init_v2; ss->v3_1 = init_v3; return;}static void zt_rbs_sethook(struct zt_chan *chan, int txsig, int txstate, int timeout){static int outs[NUM_SIGS][5] = {/* We set the idle case of the ZT_SIG_NONE to this pattern to make idle E1 CASchannels happy. Should not matter with T1, since on an un-configured channel, who cares what the sig bits are as long as they are stable */ { ZT_SIG_NONE, ZT_ABIT | ZT_CBIT | ZT_DBIT, 0, 0, 0 }, /* no signalling */ { ZT_SIG_EM, 0, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* E and M */ { ZT_SIG_FXSLS, ZT_BBIT | ZT_DBIT, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* FXS Loopstart */ { ZT_SIG_FXSGS, ZT_BBIT | ZT_DBIT, #ifdef CONFIG_CAC_GROUNDSTART ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0, 0 }, /* FXS Groundstart (CAC-style) */#else ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, ZT_ABIT | ZT_CBIT, 0 }, /* FXS Groundstart (normal) */#endif { ZT_SIG_FXSKS, ZT_BBIT | ZT_DBIT, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* FXS Kewlstart */ { ZT_SIG_FXOLS, ZT_BBIT | ZT_DBIT, ZT_BBIT | ZT_DBIT, 0, 0 }, /* FXO Loopstart */ { ZT_SIG_FXOGS, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, ZT_BBIT | ZT_DBIT, 0, 0 }, /* FXO Groundstart */ { ZT_SIG_FXOKS, ZT_BBIT | ZT_DBIT, ZT_BBIT | ZT_DBIT, 0, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT }, /* FXO Kewlstart */ { ZT_SIG_SF, ZT_BBIT | ZT_CBIT | ZT_DBIT, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, ZT_BBIT | ZT_CBIT | ZT_DBIT }, /* no signalling */ { ZT_SIG_EM_E1, ZT_DBIT, ZT_ABIT | ZT_BBIT | ZT_DBIT, ZT_ABIT | ZT_BBIT | ZT_DBIT, ZT_DBIT }, /* E and M E1 */ } ; int x; /* if no span, return doing nothing */ if (!chan->span) return; if (!chan->span->flags & ZT_FLAG_RBS) { printk("zt_rbs: Tried to set RBS hook state on non-RBS channel %s\n", chan->name); return; } if ((txsig > 3) || (txsig < 0)) { printk("zt_rbs: Tried to set RBS hook state %d (> 3) on channel %s\n", txsig, chan->name); return; } if (!chan->span->rbsbits && !chan->span->hooksig) { printk("zt_rbs: Tried to set RBS hook state %d on channel %s while span %s lacks rbsbits or hooksig function\n", txsig, chan->name, chan->span->name); return; } /* Don't do anything for RBS */ if (chan->sig == ZT_SIG_DACS_RBS) return; chan->txstate = txstate; /* if tone signalling */ if (chan->sig == ZT_SIG_SF) { chan->txhooksig = txsig; if (chan->txtone) /* if set to make tone for tx */ { if ((txsig && !(chan->toneflags & ZT_REVERSE_TXTONE)) || ((!txsig) && (chan->toneflags & ZT_REVERSE_TXTONE))) { set_txtone(chan,chan->txtone,chan->tx_v2,chan->tx_v3); } else { set_txtone(chan,0,0,0); } } chan->otimer = timeout * 8; /* Otimer is timer in samples */ return; } if (chan->span->hooksig) { chan->txhooksig = txsig; chan->span->hooksig(chan, txsig); chan->otimer = timeout * 8; /* Otimer is timer in samples */ return; } else { for (x=0;x<NUM_SIGS;x++) { if (outs[x][0] == chan->sig) {#if CONFIG_ZAPATA_DEBUG printk("Setting bits to %d for channel %s state %d in %d signalling\n", outs[x][txsig + 1], chan->name, txsig, chan->sig);#endif chan->txhooksig = txsig; chan->txsig = outs[x][txsig+1]; chan->span->rbsbits(chan, chan->txsig); chan->otimer = timeout * 8; /* Otimer is timer in samples */ return; } } } printk("zt_rbs: Don't know RBS signalling type %d on channel %s\n", chan->sig, chan->name);}static int zt_cas_setbits(struct zt_chan *chan, int bits){ /* if no span, return as error */ if (!chan->span) return -1; if (chan->span->rbsbits) { chan->txsig = bits; chan->span->rbsbits(chan, bits); } else { printk("Huh? CAS setbits, but no RBS bits function\n"); } return 0;}static int zt_hangup(struct zt_chan *chan){ int x,res=0; /* Can't hangup pseudo channels */ if (!chan->span) return 0; /* Can't hang up a clear channel */ if (chan->flags & ZT_FLAG_CLEAR) return -EINVAL; chan->kewlonhook = 0; if ((chan->sig == ZT_SIG_FXSLS) || (chan->sig == ZT_SIG_FXSKS) || (chan->sig == ZT_SIG_FXSGS)) chan->ringdebtimer = RING_DEBOUNCE_TIME; 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) res = chan->span->sethook(chan, ZT_ONHOOK); } /* if not registered yet, just return here */ if (!(chan->flags & ZT_FLAG_REGISTERED)) return res; /* Mark all buffers as empty */ for (x = 0;x < chan->numbufs;x++) { chan->writen[x] = chan->writeidx[x]= chan->readn[x]= chan->readidx[x] = 0; } if (chan->readbuf[0]) { chan->inreadbuf = 0; chan->inwritebuf = 0; } else { chan->inreadbuf = -1; chan->inwritebuf = -1; } chan->outreadbuf = -1; chan->outwritebuf = -1; chan->dialing = 0; chan->afterdialingtimer = 0; chan->curtone = NULL; chan->pdialcount = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -