📄 ztdynamic.c
字号:
/* * Dynamic Span Interface for Zaptel * * Written by Mark Spencer <markster@linux-support.net> * * Copyright (C) 2001, Linux Support Services, Inc. * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <linux/kernel.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/kmod.h>#include <linux/sched.h>#include <linux/interrupt.h>#ifdef CONFIG_DEVFS_FS#include <linux/devfs_fs_kernel.h>#endif#ifdef STANDALONE_ZAPATA#include "zaptel.h"#else#include <linux/zaptel.h>#endif#ifdef LINUX26#include <linux/moduleparam.h>#endif/* * Tasklets provide better system interactive response at the cost of the * possibility of losing a frame of data at very infrequent intervals. If * you are more concerned with the performance of your machine, enable the * tasklets. If you are strict about absolutely no drops, then do not enable * tasklets. */#define ENABLE_TASKLETS/* * Dynamic spans implemented using TDM over X with standard message * types. Message format is as follows: * * Byte #: Meaning * 0 Number of samples per channel * 1 Current flags on span * Bit 0: Yellow Alarm * Bit 1: Sig bits present * Bits 2-7: reserved for future use * 2-3 16-bit counter value for detecting drops, network byte order. * 4-5 Number of channels in the message, network byte order * 6... 16-bit words, containing sig bits for each * four channels, least significant 4 bits being * the least significant channel, network byte order. * the rest data for each channel, all samples per channel before moving to the next. *//* Arbitrary limit to the max # of channels in a span */#define ZT_DYNAMIC_MAX_CHANS 256#define ZTD_FLAG_YELLOW_ALARM (1 << 0)#define ZTD_FLAG_SIGBITS_PRESENT (1 << 1)#define ZTD_FLAG_LOOPBACK (1 << 2)#define ERR_NSAMP (1 << 16)#define ERR_NCHAN (1 << 17)#define ERR_LEN (1 << 18)EXPORT_SYMBOL(zt_dynamic_register);EXPORT_SYMBOL(zt_dynamic_unregister);EXPORT_SYMBOL(zt_dynamic_receive);#ifdef ENABLE_TASKLETSstatic int taskletrun;static int taskletsched;static int taskletpending;static int taskletexec;static int txerrors;static struct tasklet_struct ztd_tlet;static void ztd_tasklet(unsigned long data);#endifstatic struct zt_dynamic { char addr[40]; char dname[20]; int err; int alarm; int usecount; int dead; long rxjif; unsigned short txcnt; unsigned short rxcnt; struct zt_span span; struct zt_chan *chans; struct zt_dynamic *next; struct zt_dynamic_driver *driver; void *pvt; int timing; int master; unsigned char *msgbuf;} *dspans;static struct zt_dynamic_driver *drivers = NULL;static int debug = 0;static int hasmaster = 0;static spinlock_t dlock = SPIN_LOCK_UNLOCKED;static void checkmaster(void){ unsigned long flags; int newhasmaster=0; int best = 9999999; struct zt_dynamic *z, *master=NULL; spin_lock_irqsave(&dlock, flags); z = dspans; while(z) { if (z->timing) { if (z->timing) { z->master = 0; newhasmaster = 1; if (!z->alarm && (z->timing < best) && !z->dead) { /* If not in alarm and they're a better timing source, use them */ master = z; best = z->timing; } } } z = z->next; } hasmaster = newhasmaster; /* Mark the new master if there is one */ if (master) master->master = 1; spin_unlock_irqrestore(&dlock, flags); if (master) printk("TDMoX: New master: %s\n", master->span.name); else printk("TDMoX: No master.\n");}static void ztd_sendmessage(struct zt_dynamic *z){ unsigned char *buf = z->msgbuf; unsigned short bits; int msglen = 0; int x; int offset; /* Byte 0: Number of samples per channel */ *buf = ZT_CHUNKSIZE; buf++; msglen++; /* Byte 1: Flags */ *buf = 0; if (z->alarm & ZT_ALARM_RED) *buf |= ZTD_FLAG_YELLOW_ALARM; *buf |= ZTD_FLAG_SIGBITS_PRESENT; buf++; msglen++; /* Bytes 2-3: Transmit counter */ *((unsigned short *)buf) = htons((unsigned short)z->txcnt); z->txcnt++; buf++; msglen++; buf++; msglen++; /* Bytes 4-5: Number of channels */ *((unsigned short *)buf) = htons((unsigned short)z->span.channels); buf++; msglen++; buf++; msglen++; bits = 0; offset = 0; for (x=0;x<z->span.channels;x++) { offset = x % 4; bits |= (z->chans[x].txsig & 0xf) << (offset << 2); if (offset == 3) { /* Write the bits when we have four channels */ *((unsigned short *)buf) = htons(bits); buf++; msglen++; buf++; msglen++; bits = 0; } } if (offset != 3) { /* Finish it off if it's not done already */ *((unsigned short *)buf) = htons(bits); buf++; msglen++; buf++; msglen++; } for (x=0;x<z->span.channels;x++) { memcpy(buf, z->chans[x].writechunk, ZT_CHUNKSIZE); buf += ZT_CHUNKSIZE; msglen += ZT_CHUNKSIZE; } z->driver->transmit(z->pvt, z->msgbuf, msglen); }static void __ztdynamic_run(void){ unsigned long flags; struct zt_dynamic *z; int y; spin_lock_irqsave(&dlock, flags); z = dspans; while(z) { if (!z->dead) { /* Ignore dead spans */ for (y=0;y<z->span.channels;y++) { /* Echo cancel double buffered data */ zt_ec_chunk(&z->span.chans[y], z->span.chans[y].readchunk, z->span.chans[y].writechunk); } zt_receive(&z->span); zt_transmit(&z->span); /* Handle all transmissions now */ ztd_sendmessage(z); } z = z->next; } spin_unlock_irqrestore(&dlock, flags);}#ifdef ENABLE_TASKLETSstatic void ztdynamic_run(void){ if (!taskletpending) { taskletpending = 1; taskletsched++; tasklet_hi_schedule(&ztd_tlet); } else { txerrors++; }}#else#define ztdynamic_run __ztdynamic_run#endifvoid zt_dynamic_receive(struct zt_span *span, unsigned char *msg, int msglen){ struct zt_dynamic *ztd = span->pvt; int newerr=0; unsigned long flags; int sflags; int xlen; int x, bits, sig; int nchans, master; int newalarm; unsigned short rxpos; spin_lock_irqsave(&dlock, flags); if (msglen < 6) { spin_unlock_irqrestore(&dlock, flags); newerr = ERR_LEN; if (newerr != ztd->err) { printk("Span %s: Insufficient samples for header (only %d)\n", span->name, msglen); } ztd->err = newerr; return; } /* First, check the chunksize */ if (*msg != ZT_CHUNKSIZE) { spin_unlock_irqrestore(&dlock, flags); newerr = ERR_NSAMP | msg[0]; if (newerr != ztd->err) { printk("Span %s: Expected %d samples, but receiving %d\n", span->name, ZT_CHUNKSIZE, msg[0]); } ztd->err = newerr; return; } msg++; sflags = *msg; msg++; rxpos = ntohs(*((unsigned short *)msg)); msg++; msg++; nchans = ntohs(*((unsigned short *)msg)); if (nchans != span->channels) { spin_unlock_irqrestore(&dlock, flags); newerr = ERR_NCHAN | nchans; if (newerr != ztd->err) { printk("Span %s: Expected %d channels, but receiving %d\n", span->name, span->channels, nchans); } ztd->err = newerr; return; } msg++; msg++; /* Okay now we've accepted the header, lets check our message length... */ /* Start with header */ xlen = 6; /* Add samples of audio */ xlen += nchans * ZT_CHUNKSIZE; /* If RBS info is there, add that */ if (sflags & ZTD_FLAG_SIGBITS_PRESENT) { /* Account for sigbits -- one short per 4 channels*/ xlen += ((nchans + 3) / 4) * 2; } if (xlen != msglen) { spin_unlock_irqrestore(&dlock, flags); newerr = ERR_LEN | xlen; if (newerr != ztd->err) { printk("Span %s: Expected message size %d, but was %d instead\n", span->name, xlen, msglen); } ztd->err = newerr; return; } bits = 0; /* Record sigbits if present */ if (sflags & ZTD_FLAG_SIGBITS_PRESENT) { for (x=0;x<nchans;x++) { if (!(x%4)) { /* Get new bits */ bits = ntohs(*((unsigned short *)msg)); msg++; msg++; } /* Pick the right bits */ sig = (bits >> ((x % 4) << 2)) & 0xff; /* Update signalling if appropriate */ if (sig != span->chans[x].rxsig) zt_rbsbits(&span->chans[x], sig); } } /* Record data for channels */ for (x=0;x<nchans;x++) { memcpy(span->chans[x].readchunk, msg, ZT_CHUNKSIZE); msg += ZT_CHUNKSIZE; } master = ztd->master; spin_unlock_irqrestore(&dlock, flags); /* Check for Yellow alarm */ newalarm = span->alarms & ~(ZT_ALARM_YELLOW | ZT_ALARM_RED); if (sflags & ZTD_FLAG_YELLOW_ALARM) newalarm |= ZT_ALARM_YELLOW; if (newalarm != span->alarms) { span->alarms = newalarm; zt_alarm_notify(span); } /* Keep track of last received packet */ ztd->rxjif = jiffies; /* If this is our master span, then run everything */ if (master) ztdynamic_run(); }static void dynamic_destroy(struct zt_dynamic *z){ /* Unregister span if appropriate */ if (z->span.flags & ZT_FLAG_REGISTERED) zt_unregister(&z->span); /* Destroy the pvt stuff if there */ if (z->pvt) z->driver->destroy(z->pvt); /* Free message buffer if appropriate */ if (z->msgbuf) kfree(z->msgbuf); /* Free channels */ if (z->chans); kfree(z->chans); /* Free z */ kfree(z); checkmaster();}static struct zt_dynamic *find_dynamic(ZT_DYNAMIC_SPAN *zds){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -