📄 zaptel.c
字号:
tone_zones[x] = NULL; return 0;}static int free_tone_zone(int num){ struct zt_zone *z; if ((num < 0) || (num >= ZT_TONE_ZONE_MAX)) return -EINVAL; write_lock(&zone_lock); z = tone_zones[num]; tone_zones[num] = NULL; write_unlock(&zone_lock); kfree(z); return 0;}static int zt_register_tone_zone(int num, struct zt_zone *zone){ int res=0; if ((num >= ZT_TONE_ZONE_MAX) || (num < 0)) return -EINVAL; write_lock(&zone_lock); if (tone_zones[num]) { res = -EINVAL; } else { res = 0; tone_zones[num] = zone; } write_unlock(&zone_lock); if (!res) printk(KERN_INFO "Registered tone zone %d (%s)\n", num, zone->name); return res;}static int start_tone(struct zt_chan *chan, int tone){ int res = -EINVAL; /* Stop the current tone, no matter what */ chan->tonep = 0; chan->curtone = NULL; chan->pdialcount = 0; chan->txdialbuf[0] = '\0'; chan->dialing = 0; if ((tone >= ZT_TONE_MAX) || (tone < -1)) return -EINVAL; /* Just wanted to stop the tone anyway */ if (tone < 0) return 0; if (chan->curzone) { /* Have a tone zone */ if (chan->curzone->tones[tone]) { chan->curtone = chan->curzone->tones[tone]; res = 0; } else /* Indicate that zone is loaded but no such tone exists */ res = -ENOSYS; } else /* Note that no tone zone exists at the moment */ res = -ENODATA; if (chan->curtone) zt_init_tone_state(&chan->ts, chan->curtone); return res;}static int set_tone_zone(struct zt_chan *chan, int zone){ int res=0; /* Assumes channel is already locked */ if ((zone >= ZT_TONE_ZONE_MAX) || (zone < -1)) return -EINVAL; read_lock(&zone_lock); if (zone == -1) { zone = default_zone; } if (tone_zones[zone]) { chan->curzone = tone_zones[zone]; chan->tonezone = zone; memcpy(chan->ringcadence, chan->curzone->ringcadence, sizeof(chan->ringcadence)); } else { res = -ENODATA; } read_unlock(&zone_lock); return res;}static void zt_set_law(struct zt_chan *chan, int law){ if (!law) { if (chan->deflaw) law = chan->deflaw; else if (chan->span) law = chan->span->deflaw; else law = ZT_LAW_MULAW; } if (law == ZT_LAW_ALAW) { chan->xlaw = __zt_alaw;#ifdef CONFIG_CALC_XLAW chan->lineartoxlaw = __zt_lineartoalaw;#else chan->lin2x = __zt_lin2a;#endif } else { chan->xlaw = __zt_mulaw;#ifdef CONFIG_CALC_XLAW chan->lineartoxlaw = __zt_lineartoulaw;#else chan->lin2x = __zt_lin2mu;#endif }}#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t register_devfs_channel(struct zt_chan *chan, devfs_handle_t dir){ char path[100]; char link[100]; char buf[50]; char tmp[100]; int link_offset = 0; int tmp_offset = 0; int path_offset = 0; int err = 0; devfs_handle_t chan_dev; umode_t mode = S_IFCHR|S_IRUGO|S_IWUGO; unsigned int flags = DEVFS_FL_AUTO_OWNER; sprintf(path, "%d", chan->chanpos); chan_dev = devfs_register(dir, path, flags, ZT_MAJOR, chan->channo, mode, &zt_fops, NULL); if (!chan_dev) { printk("zaptel: Something really bad happened. Unable to register devfs entry\n"); return NULL; } /* Set up the path of the destination of the link */ link_offset = devfs_generate_path(chan_dev, link, sizeof(link) - 1); /* Now we need to strip off the leading "zap/". If we don't, then we build a broken symlink */ path_offset = devfs_generate_path(zaptel_devfs_dir, path, sizeof(path) - 1); /* We'll just "borrow" path for a second */ path_offset = strlen(path+path_offset); link_offset += path_offset; /* Taking out the "zap" */ link_offset++; /* Add one more place for the '/'. The path generated does not contain the '/' we need to strip */ /* Set up the path of the file/link itself */ tmp_offset = devfs_generate_path(zaptel_devfs_dir, tmp, sizeof(tmp) - 1); sprintf(buf, "/%d", chan->channo); strncpy(path, tmp+tmp_offset, sizeof(path) - 1); strncat(path, buf, sizeof(path) - 1); err = devfs_mk_symlink(NULL, path, DEVFS_FL_DEFAULT, link+link_offset, &chan->fhandle_symlink, NULL); if (err != 0) { printk("Problem with making devfs symlink: %d\n", err); } return chan_dev;}#endif /* CONFIG_DEVFS_FS */static int zt_chan_reg(struct zt_chan *chan){ int x; int res=0; unsigned long flags; write_lock_irqsave(&chan_lock, flags); for (x=1;x<ZT_MAX_CHANNELS;x++) { if (!chans[x]) { spin_lock_init(&chan->lock); chans[x] = chan; if (maxchans < x + 1) maxchans = x + 1; chan->channo = x; if (!chan->master) chan->master = chan; if (!chan->readchunk) chan->readchunk = chan->sreadchunk; if (!chan->writechunk) chan->writechunk = chan->swritechunk; zt_set_law(chan, 0); close_channel(chan); /* set this AFTER running close_channel() so that HDLC channels wont cause hangage */ chan->flags |= ZT_FLAG_REGISTERED; res = 0; break; } } write_unlock_irqrestore(&chan_lock, flags); if (x >= ZT_MAX_CHANNELS) printk(KERN_ERR "No more channels available\n"); return res;}char *zt_lboname(int x){ if ((x < 0) || ( x > 7)) return "Unknown"; return zt_txlevelnames[x];}#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)#endif#ifdef CONFIG_ZAPATA_NET#ifdef NEW_HDLC_INTERFACEstatic int zt_net_open(struct net_device *dev){#ifdef LINUX26 int res = hdlc_open(dev); struct zt_chan *ms = dev_to_ztchan(dev);#else hdlc_device *hdlc = dev_to_hdlc(dev); struct zt_chan *ms = hdlc_to_ztchan(hdlc); int res = hdlc_open(hdlc);#endif /* if (!dev->hard_start_xmit) return res; is this really necessary? --byg */ if (res) /* this is necessary to avoid kernel panic when UNSPEC link encap, proven --byg */ return res;#elsestatic int zt_net_open(hdlc_device *hdlc){ struct zt_chan *ms = hdlc_to_ztchan(hdlc); int res;#endif if (!ms) { printk("zt_net_open: nothing??\n"); return -EINVAL; } if (ms->flags & ZT_FLAG_OPEN) { printk("%s is already open!\n", ms->name); return -EBUSY; } if (!(ms->flags & ZT_FLAG_NETDEV)) { printk("%s is not a net device!\n", ms->name); return -EINVAL; } ms->txbufpolicy = ZT_POLICY_IMMEDIATE; ms->rxbufpolicy = ZT_POLICY_IMMEDIATE; res = zt_reallocbufs(ms, ZT_DEFAULT_MTU_MRU, ZT_DEFAULT_NUM_BUFS); if (res) return res; fasthdlc_init(&ms->rxhdlc); fasthdlc_init(&ms->txhdlc); ms->infcs = PPP_INITFCS;#ifndef LINUX26 MOD_INC_USE_COUNT;#endif #if CONFIG_ZAPATA_DEBUG printk("ZAPNET: Opened channel %d name %s\n", ms->channo, ms->name);#endif return 0;}#ifdef NEW_HDLC_INTERFACEstatic int zt_net_stop(struct net_device *dev){ hdlc_device *hdlc = dev_to_hdlc(dev);#elsestatic void zt_net_close(hdlc_device *hdlc){#endif struct zt_chan *ms = hdlc_to_ztchan(hdlc); if (!ms) {#ifdef NEW_HDLC_INTERFACE printk("zt_net_stop: nothing??\n"); return 0;#else printk("zt_net_close: nothing??\n"); return;#endif } if (!(ms->flags & ZT_FLAG_NETDEV)) {#ifdef NEW_HDLC_INTERFACE printk("zt_net_stop: %s is not a net device!\n", ms->name); return 0;#else printk("zt_net_close: %s is not a net device!\n", ms->name); return;#endif } /* Not much to do here. Just deallocate the buffers */ zt_reallocbufs(ms, 0, 0);#ifdef LINUX26 hdlc_close(dev);#else hdlc_close(hdlc);#endif #ifndef LINUX26 MOD_DEC_USE_COUNT;#endif #ifdef NEW_HDLC_INTERFACE return 0;#else return;#endif}#ifdef NEW_HDLC_INTERFACE/* kernel 2.4.20+ has introduced attach function, dunno what to do, just copy sources from dscc4 to be sure and ready for further mastering, NOOP right now (i.e. really a stub) --byg */#ifdef LINUX26static int zt_net_attach(struct net_device *dev, unsigned short encoding, unsigned short parity)#else static int zt_net_attach(hdlc_device *hdlc, unsigned short encoding, unsigned short parity)#endif{/* struct net_device *dev = hdlc_to_dev(hdlc); struct dscc4_dev_priv *dpriv = dscc4_priv(dev); if (encoding != ENCODING_NRZ && encoding != ENCODING_NRZI && encoding != ENCODING_FM_MARK && encoding != ENCODING_FM_SPACE && encoding != ENCODING_MANCHESTER) return -EINVAL; if (parity != PARITY_NONE && parity != PARITY_CRC16_PR0_CCITT && parity != PARITY_CRC16_PR1_CCITT && parity != PARITY_CRC32_PR0_CCITT && parity != PARITY_CRC32_PR1_CCITT) return -EINVAL; dpriv->encoding = encoding; dpriv->parity = parity;*/ return 0;}#endif static struct zt_hdlc *zt_hdlc_alloc(void){ struct zt_hdlc *tmp; tmp = kmalloc(sizeof(struct zt_hdlc), GFP_KERNEL); if (tmp) { memset(tmp, 0, sizeof(struct zt_hdlc)); } return tmp;}#ifdef NEW_HDLC_INTERFACEstatic int zt_xmit(struct sk_buff *skb, struct net_device *dev){ /* FIXME: this construction seems to be not very optimal for me but I could find nothing better at the moment (Friday, 10PM :( ) --byg *//* struct zt_chan *ss = hdlc_to_ztchan(list_entry(dev, struct zt_hdlc, netdev.netdev));*/#ifdef LINUX26 struct zt_chan *ss = dev_to_ztchan(dev); struct net_device_stats *stats = hdlc_stats(dev);#else struct zt_chan *ss = (list_entry(dev, struct zt_hdlc, netdev.netdev)->chan); struct net_device_stats *stats = &ss->hdlcnetdev->netdev.stats;#endif #elsestatic int zt_xmit(hdlc_device *hdlc, struct sk_buff *skb){ struct zt_chan *ss = hdlc_to_ztchan(hdlc); struct net_device *dev = &ss->hdlcnetdev->netdev.netdev; struct net_device_stats *stats = &ss->hdlcnetdev->netdev.stats;#endif int retval = 1; int x,oldbuf; unsigned int fcs; unsigned char *data; unsigned long flags; /* See if we have any buffers */ spin_lock_irqsave(&ss->lock, flags); if (skb->len > ss->blocksize - 2) { printk(KERN_ERR "zt_xmit(%s): skb is too large (%d > %d)\n", dev->name, skb->len, ss->blocksize -2); stats->tx_dropped++; retval = 0; } else if (ss->inwritebuf >= 0) { /* We have a place to put this packet */ /* XXX We should keep the SKB and avoid the memcpy XXX */ data = ss->writebuf[ss->inwritebuf]; memcpy(data, skb->data, skb->len); ss->writen[ss->inwritebuf] = skb->len; ss->writeidx[ss->inwritebuf] = 0; /* Calculate the FCS */ fcs = PPP_INITFCS; for (x=0;x<skb->len;x++) fcs = PPP_FCS(fcs, data[x]); /* Invert it */ fcs ^= 0xffff; /* Send it out LSB first */ data[ss->writen[ss->inwritebuf]++] = (fcs & 0xff); data[ss->writen[ss->inwritebuf]++] = (fcs >> 8) & 0xff; /* 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; } dev->trans_start = jiffies; stats->tx_packets++; stats->tx_bytes += ss->writen[oldbuf];#if CONFIG_ZAPATA_DEBUG printk("Buffered %d bytes to go out in buffer %d\n", ss->writen[oldbuf], oldbuf); for (x=0;x<ss->writen[oldbuf];x++) printk("%02x ", ss->writebuf[oldbuf][x]); printk("\n");#endif retval = 0; /* Free the SKB */ dev_kfree_skb_any(skb); } spin_unlock_irqrestore(&ss->lock, flags); return retval;}#ifdef NEW_HDLC_INTERFACEstatic int zt_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ return hdlc_ioctl(dev, ifr, cmd);}#elsestatic int zt_net_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd){ return -EIO;}#endif#endif#ifdef CONFIG_ZAPATA_PPPstatic int zt_ppp_xmit(struct ppp_channel *ppp, struct sk_buff *skb){ /* * If we can't handle the packet right now, return 0. If we * we handle or drop it, return 1. Always free if we return * 1 and never if we return 0 */ struct zt_chan *ss = ppp->private; int x,oldbuf; unsigned int fcs; unsigned char *data; long flags; int retval = 0; /* See if we have any buffers */ spin_lock_irqsave(&ss->lock, flags); if (!(ss->flags & ZT_FLAG_OPEN)) { printk("Can't transmit on closed channel\n"); retval = 1; } else if (skb->len > ss->blocksize - 4) { printk(KERN_ERR "zt_ppp_xmit(%s): skb is too large (%d > %d)\n", ss->name, skb->len, ss->blocksize -2); retval = 1; } else if (ss->inwritebuf >= 0) { /* We have a place to put this packet */ /* XXX We should keep the SKB and avoid the memcpy XXX */ data = ss->writebuf[ss->inwritebuf]; /* Start with header of two bytes */ /* Add "ALL STATIONS" and "UNNUMBERED" */ data[0] = 0xff; data[1] = 0x03; ss->writen[ss->inwritebuf] = 2; /* Copy real data and increment amount written */ memcpy(data + 2, skb->data, skb->len); ss->writen[ss->inwritebuf] += skb->len; /* Re-set index back to zero */ ss->writeidx[ss->inwritebuf] = 0; /* Calculate the FCS */ fcs = PPP_INITFCS; for (x=0;x<skb->len + 2;x++) fcs = PPP_FCS(fcs, data[x]); /* Invert it */ fcs ^= 0xffff; /* Point past the real data now */ data += (skb->len + 2); /* Send FCS out LSB first */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -