/* * BSD Telephony Of Mexico "Tormenta" card driver, version 1.4 12/23/00 * * * Working with the "Tormenta ISA" Card * * * Part of the "Zapata" Computer Telephony Technology. * * See http://www.bsdtelephony.com.mx * * * The technologies, software, hardware, designs, drawings, scheumatics, board * layouts and/or artwork, concepts, methodologies (including the use of all * of these, and that which is derived from the use of all of these), all other * intellectual properties contained herein, and all intellectual property * rights have been and shall continue to be expressly for the benefit of all * mankind, and are perpetually placed in the public domain, and may be used, * copied, and/or modified by anyone, in any manner, for any legal purpose, * without restriction. * * Version History: * * 1.4 12/23/00 * Added FXO Loopstart and Groundstart support. Added Conference Mute mode. * * 1.3 11/19/00 * Added 'NOTOPEN' alarm functionality. * * 1.1 11/7/00 * Updated version to correspond with release. No significant changes made. * * 1.0 11/6/00 * Changed memory map to correspond with the real ISA PC card. * * 0.6 11/4/00 * Added TOR_TXSTATE_AFTERSTART, so that there is a pause after * starting a ground-start trunk. * * 0.5 11/3/00 * Added CORRECT support for ESF and B8ZS (gosh, it sure does HELP to * put the RECEIVER in the correct mode, too!!). Also found rather * annoying bug in the Dallas 2151Q chip (or could be a board noise * problem). Occasionally, accesses to the chip (reads and writes) for * some random reason cause CRC errors on the transmit output, thus * making ESF mode useless. */ /* Driver Documentation This is a somewhat unusual driver. Most of the work takes place in the interrupt routine (buffer handling, board I/O, switching, conferencing, timing, signalling handling, etc). In addition, its not exactly a character device, and its not exactly a block device (explained later). INTERRUPT ROUTINE Every 125 microseconds (8000 times a second), the Tormenta card generates a hardware interrupt to the processor. At this time, the computer responds to this interrupt, and does the following: Reads in 48 samples (1 per channel) of speech data from the T-1 channels. Does processing for various switching and conferencing modes (moves audio data around, etc). Adds samples to read buffers. Gets samples from write buffers. Writes out 48 samples (1 per channel) of speech data to the T-1 channels. Every 8 interrupts (1000 times a second), the various timers are checked for activity and time-outs. A timer that times-out has a service routine associated with it that gets executed. Every 512 interrupts (15.625 times a second), signalling bits are looked at, processed, handled (by associated routines), and written as appropriate. Also, alarm status is looked at, and handled accordingly. BUFFERS, READING, AND WRITING Each channel contains 2 read and 2 write buffers. In this implementation, primarily for the purpose of speed, efficiency, and low overhead, the buffers are handled in the following manner: A buffer has 3 states: empty, being filled, and full. In the case of the write buffers, instead of usual buffer processing, where a buffer is incrementally filled until full, a write buffer in this implementation is considered full when any block (including a blocksize of 1) is written to it. Only 1 buffer at a time may be written to. Therefore, the device really only should be written to at the full current blocksize (less would not be efficient use of the buffering system). The idea is to be able to fill (write to) a buffer, and have that one being emptied while you fill (write to) the other buffer. In the case of the read buffers, instead of usual buffer processing, where a buffer is incrementally emptied until totally empty, a full read buffer in this implementation is fully emptied when a read occurs, regardless whether the read transfer all or part of the size of the read buffer. Therefore, the device really only should be read from at the full current blocklize (less would lose data). The idea is to read from a full buffer while the other read buffer is being filled. Both read and write calls are interrupted by an event happening (see events below). If an event happens, the call fails with ELAST as the error (indicating a pending event that must be read out of the event buffer). DATA FLOW, SWITCHING, AND CONFERENCING A channel's data normally flows from the received sample from the T-1 channel into the read buffer, and from the write buffer to the transmitted sample on the T-1 channel. This implementation allows for various modifications to the above data flow concept (see related figures for archetecture detail). These various "conference" modes allow for monitoring, switching, and conferencing with many variations. EVENT BUFFERS AND HANDLING Every channel has an event buffer associated with it. There are a number of occurrences that an application need to be notified of, such as a channel going off hook (or ringing), a channel going on hook (disconnecting), a channel winking, a carrier alarm condition, or a lack of carrier alarm condition. When each of these events occur, notification of such is inserted into an event buffer (queue), and then can be read out of the buffer in the order in which it (or they) happened. If a read or write system call is in progress, it is interrupted and fails with an ELAST error code (indicating that there is a pending event that must be read out of the buffer). Events are read out of the buffer using the TOR_GETEVENT ioctl. I/O MULTIPLEXING (aka 'select' on steriods) For applications that need to do several I/O operations simultaneously on a single channel, the TOR_IOMUX ioctl is available to allow this to happen efficiently. You specify a mask of things that you wish to look for, such as read available, write space availiable, write empty, or event pending. Upon return, the mask is set to indicate which of these things took place and caused the call to return. IOCTL's The 'tor' driver supports the following IOCTL's: Get Transfer Block Size TOR_GET_BLOCKSIZE int * -- location (pointer) to which to return current blocksize in integer Set Transfer Block Size. TOR_SET_BLOCKSIZE int * -- pointer to integer containing new blocksize Flush Buffer(s) and stop I/O TOR_FLUSH int * -- pointer to integer mask indicating what to flush Wait for Write to Finish TOR_SYNC void Get channel parameters TOR_GET_PARAMS struct tor_params * -- pointer to struct to contain current channel parameters Set channel parameters TOR_SET_PARAMS struct tor_params * -- pointer to struct which contains new channel parameters Set Hookswitch Status TOR_HOOK int * -- New hookswitch state Get Signalling Event TOR_GETEVENT int * -- pointer to integer in which the event is returned Wait for something to happen TOR_IOMUX int * -- enters with pointer to integer mask specifying desired things to wait for. Exits after writing integer mask (at same location) of what it found. Get Span Status TOR_SPANSTAT struct tor_spaninfo * -- Pointer to span info structure. Enter with desired span number filled in spanno (or 0 for current), exits with all span infomation filled in. Set Maintenance (Loopback) Mode TOR_MAINT struct tor_maintinfo * -- Pointer to maint info structure. Enter with desired span number filled in spanno (or 0 for current), and desired maintenance mode filled in. Get Conference Mode TOR_GETCONF struct tor_confinfo * -- Pointer to conf info structure. Enter with channel number filled in (0 for current). Exits with conf info structure filled in. Set Conference Mode TOR_SETCONF struct tor_confinfo * -- Pointer to conf info structure. Enter with channel number filled in (0 for current), and conf number, and conf mode. Setup or Remove Conference Link TOR_CONFLINK struct tor_confinfo * -- Pointer to conf info structure. In this case, channel number is filled in with the desired conference number to listen to. Confn is filled in with the desired conference number that is to listen to the conference specified in channel number. Fill-in confmode non- zero to create the specified link, or zero to delete (break) the specified link. Display Conference Diagnostic Information on Console TOR_CONFDIAG int * -- Pointer to integer, 0 specifies all conferences, non-zero specifies a particular conference only. Get Receive and Transmit Gains (linear) TOR_GETGAINS struct gains * -- Pointer to tor_gains structure. Enter with channel number filled in (0 for current), and returns channel, and rx & tx gains (linear, not db). Set Receive and Transmit Gains (linear) TOR_SETGAINS struct gains * -- Pointer to tor_gains structure. Enter with channel number filled in (0 for current), and rx & tx gains (linear, not db). Set CONFMUTE mode TOR_CONFMUTE int * -- Pointer to integer of new CONFMUTE mode value for current line. This IOCTL is really designed for internal library use only. See zap.c about CONFMUTE mode. For detailed information of the IOCTL's and their various arguments and parameters, see the 'tor.h' header file. Possible error codes returned from IOCTL's: EINVAL -- Invalid or out of range argument specified. EEXIST -- Specified conference link already exists. ENOSPC -- No space available to additional conference link. ENOENT -- No such conference link (can not locate specified link). HARDWARE ARCHETECTURE The hardware is a 16 bit memory-mapped ISA bus card. It uses both 8 bit and 16 bit memory cycles, specified by a 16 bit enable line in the control register. The Mitel MT8920 STPA chips are accessed (in parallel) with 16 bit memory accesses, and everything else on the card uses 8 bit memory accesses. There is a control register (output) that contains the following: Timing genrator (MT8941 DPLL) mode control (MS0,MS1). Interrupt enable. Outbit (the output bit that is brought out for exernal measurement). Receive clock control/enable for both T-1 chips. 16 bit memory access enable. Reading from the status (control) register contains the following: Interrupt pending. The MT8920 STPA chips must be accessed in 16 bit mode, where the 16 bit memory access enable bit on the control register is true. All other accesses must be done in 8 bit mode, where the 16 bit memory access enable bit is false. The timing (syncronization source) is controlled by a combination of the mode select bits on the MT8941 DPLL, and the receive clock control/enable bits for the two T-1 chips. The two Dallas T-1 chips reside at 2 address blocks, one for the data memory (with the ALE line not asserted), and one for the address memory (with the ALE line asserted). Reading and/or writing from/to the Dallas T-1 chips requires two operations. First is a write of the internal chip register address to the address memory, then a read/write from/to the data memory. This is required because of the Dallas chip's pseudo- multiplexed data/address bus. See the Dallas DS2151Q chip documentation for more information. */ #include "tor.h" #if NTOR > 0 #include "opt_devfs.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef DEVFS #include #endif /* DEVFS */ #include #include #include #include #include #include /* Board address offsets (specified in word (not byte) offsets) */ #define DDATA 0 /* Data I/O Register */ #define DADDR 0x100 /* Dallas Card Address Reg., 0x200 in byte offset higher */ #define CTLREG 0x100 /* Control/Status Reg., 0x200 in byte offset */ /* Control register bits */ #define MASTERCLOCK 0 /* Value for Master Clock */ #define OUTBIT 8 /* Status output bit (for external measurements) */ #define INTENA 4 /* Interrupt enable bit */ #define ENA16 0x80 /* 16 bit bus cycle enable bit */ /* size of event buffer */ #define TOR_MAX_EVENTSIZE 64 /* 64 events max */ /* defines for transmit signalling */ enum {TOR_TXSIG_ONHOOK,TOR_TXSIG_OFFHOOK,TOR_TXSIG_START} ; /* states for transmit signalling */ enum {TOR_TXSTATE_ONHOOK,TOR_TXSTATE_OFFHOOK,TOR_TXSTATE_START, TOR_TXSTATE_PREWINK,TOR_TXSTATE_WINK,TOR_TXSTATE_PREFLASH, TOR_TXSTATE_FLASH,TOR_TXSTATE_DEBOUNCE,TOR_TXSTATE_AFTERSTART} ; /* signalling bits */ #define TOR_ABIT 8 #define TOR_BBIT 4 /* per-channel software structure */ static struct tor_softc { u_long flags; /* flags (you expected something else ??) */ u_short *maddr; /* io base address of card */ #ifdef DEVFS void *devfs_token; /* devfs token */ #endif /* the following are only meaningful to units other then the base (0) */ struct selinfo sel; /* thingy for select stuff */ int blocksize; /* transfer blocksize */ int sigtype; /* signaling type */ int prewinktime; /* pre-wink time (ms) */ int preflashtime; /* pre-flash time (ms) */ int winktime; /* wink time (ms) */ int flashtime; /* flash time (ms) */ int starttime; /* start time (ms) */ int rxwinktime; /* rx wink time (ms) */ int rxflashtime; /* rx flash time (ms) */ int debouncetime; /* FXS GS sig debounce time (ms) */ u_char readbuf[2][TOR_MAX_BLOCKSIZE]; /* read buffer */ u_char writebuf[2][TOR_MAX_BLOCKSIZE]; /* write buffers */ u_char eventbuf[TOR_MAX_EVENTSIZE]; /* event circ. buffer */ int readn[2]; /* # of bytes ready in read buf */ int readidx[2]; /* current read pointer */ int writen[2]; /* # of bytes ready in write buf */ int writeidx[2]; /* current write pointer */ int eventinidx; /* out index in event buf (circular) */ int eventoutidx; /* in index in event buf (circular) */ u_int itimer; /* timer for in signalling */ u_int otimer; /* timer for out signalling */ u_char rxsig; /* last rx signalling received */ int txstate; /* transmit state */ int iomask; /* I/O Mux signal mask */ short rxlin; /* last received sample */ short txlin; /* last transmitted sample */ short conflast; /* last sample written to conf */ int confn; /* conference number */ int confmode; /* conference mode */ int confmute; /* conference mute mode */ float rxgain; /* receive gain */ float txgain; /* transmit gain */ int gotgs; /* got ground-start flag (FXO GS) */ } tor_softc[NTOR]; static u_char txsigs[2][6]; /* transmit signal byte array save (copy of whats in chips) */ /* per-channel gain translation tables */ u_char rxgainx[NTOR][256]; /* receive gain translate table */ u_char txgainx[NTOR][256]; /* transmit gain translate table */ /* per-span span variables */ static u_int alarms[2]; /* alarm state for spans */ static u_int lastalarms[2]; /* last alarm state for spans */ static int maints[2]; /* maint stat for spans */ static u_int alarmtimer[2]; /* alarm timer */ static u_int mainttimer[2]; /* maintance functions (loop codes) timer */ static u_char txlevels[2]; /* set tx level */ static u_int lineconfig[2]; /* line configurations */ static u_int bpvcounts[2]; /* BPV counters */ /* sync sources. [0] is primary and [1] is secondary */ static u_char syncs[2]; /* sync source info */ /* conference accumulators */ static short conf_sums[NCONF + 1]; /* current conference sums */ static short conf_presums[NCONF + 1]; /* next conference sums */ static short conf_prev[NCONF + 1]; /* last conference sums */ /* conference links */ static struct { int src; /* source conf number */ int dst; /* dst conf number */ } conf_links[NCONF + 1]; static u_char syncsrc; /* active sync src */ /* the conversion tables get pre-loaded (for speed reasons) */ static short mulaw[256]; /* mulaw conversion table */ static u_char lin2mu[65536]; /* linear conversion table */ /* flags in softc */ #define OPEN 1 /* channel is open */ #define ALIVE 2 /* channel is alive */ #define PSEUDO 4 /* is a pseudo-channel */ /* macro-oni for determining a unit (channel) number */ #define UNIT(dev) minor(dev) /* function declarations */ static int tor_probe(struct isa_device *id); static int tor_attach(struct isa_device *id); /* driver structure that the kernel loader needs to hook into the driver */ struct isa_driver tordriver = {tor_probe, tor_attach, "tor"}; /* declarations for functions that are part of standard isa driver archetecture */ static d_open_t tor_open; static d_close_t tor_close; static d_read_t tor_read; static d_write_t tor_write; static d_ioctl_t tor_ioctl; static int tor_select(dev_t dev, int rw, struct proc *p); /* declarations for local functions (only used in this driver) */ static void tor_sethook(int chan, int what); static void setctlreg(unsigned char val); static unsigned char getctlreg(void); static void t1out(int spanno,int loc,unsigned char val); static unsigned char t1in(int spanno,int loc); static unsigned char linear2ulaw(short sample); /* our assigned major device number */ #define CDEV_MAJOR 234 /* array for DEVSW functionality (if used) */ static struct cdevsw tor_cdevsw = { tor_open, tor_close, tor_read, tor_write, tor_ioctl, nostop, nullreset, nodevtotty, tor_select, nommap, NULL, "tor", NULL, -1 }; /* declare interrupt handler */ static ointhand2_t torintr; /* translations of data channels for 24 channels in a 32 bit PCM highway */ unsigned datxlt[] = { 0, 1 ,2 ,3 ,5 ,6 ,7 ,9 ,10,11,13,14,15,17,18,19,21,22,23,25,26,27,29,30,31 }; /* this is just GROSS!! This is the order that the data (audio) channels get scanned in. This was done in this rather poopy manner because when outputting (and inputting) a sine wave, such as in the case of TDD, any repeated samples (because of PCM bus contention) will result in nasty-sounding distortion. The Mitel STPA chips (MT8920) have a contention mechanism, which results in a situation where, if the processor accesses a timeslot that is currently being transmitted or received, it will HOLD the bus until it is done with the timeslot. This means that there can be cases where we are trying to write to a timeslot, and its already outputting the same value as the last one (since we didnt get there in time), and in a sine-wave output, distortion will occur. In any other output, it will be utterly un-noticeable. So, what we do is use a pattern that statistically will have the least likelyhood of there being contention, based upon the timing of the timeslots being output, the speed at which the processor outputs them on the ISA bus, and typical other latency factors such as interrupts from other devices (like disk or network). */ int chseq[] = { 12,6,13,10,7,9,22,8,11,21,24,20,23,19,5,18,4,17,3,16,2,15,1,14 } ; /* quiescent (idle) signalling states, for the various signalling types */ static u_char q_sig[4] = {0,0,TOR_BBIT,TOR_ABIT | TOR_BBIT} ; /* clock values */ u_char clockvals[] = {0,0x12,0x22,0}; /* names of tx level settings */ char *txlevelnames[] = { "0 db (CSU)/0-133 feet (DSX-1)", "133-266 feet (DSX-1)", "266-399 feet (DSX-1)", "399-533 feet (DSX-1)", "533-655 feet (DSX-1)", "-7.5db (CSU)", "-15db (CSU)", "-22.5db (CSU)" } ; /* names of sync sources */ char *syncsrcnames[] = { "NONE (FREE-RUN)", "SPAN 1", "SPAN 2", "NONE (FREE-RUN)" } ; /* set the control register */ static void setctlreg(val) unsigned char val; { register char *cp; cp = (char *) &tor_softc[0].maddr[CTLREG]; *cp = val; } /* get input from the status register */ static unsigned char getctlreg(void) { register char *cp; cp = (char *) &tor_softc[0].maddr[CTLREG]; return(*cp); } /* output a byte to one of the registers in one of the Dallas T-1 chips */ static void t1out(spanno,loc,val) int spanno; /* span number (1,2) */ int loc; /* address within the Dallas T-1 chip */ unsigned char val; /* value to write there */ { register int n; register char *cp; /* get the memory offset */ n = spanno << 9; /* point a char * at the address location */ cp = (char *) &tor_softc[0].maddr[DADDR + n]; *cp = loc; /* set address in T1 chip */ /* point a char * at the data location */ cp = (char *) &tor_softc[0].maddr[DDATA + n]; *cp = val; /* out the value */ } /* get a byte from one of the registers in one of the Dallas T-1 chips */ static unsigned char t1in(spanno,loc) int spanno; /* span number (1,2) */ int loc; /* address within the Dallas T-1 chip */ { register int n; register char *cp; /* get the memory offset */ n = spanno << 9; /* point a char * at the address location */ cp = (char *) &tor_softc[0].maddr[DADDR + n]; *cp = loc; /* set address in T1 chip */ cp = (char *) &tor_softc[0].maddr[DDATA + n]; /* point a char * at the data location */ return(*cp); } /* enqueue an event on a channel */ static void qevent(int chan, int event) { struct tor_softc *ss = (struct tor_softc *)&tor_softc[chan]; /* if full, ignore */ if ((ss->eventoutidx == 0) && (ss->eventinidx == (TOR_MAX_EVENTSIZE - 1))) return; /* if full, ignore */ if (ss->eventoutidx == (ss->eventinidx - 1)) return; /* save the event */ ss->eventbuf[ss->eventinidx++] = event; /* wrap the index, if necessary */ if (ss->eventinidx >= TOR_MAX_EVENTSIZE) ss->eventinidx = 0; /* wake em all up */ if (ss->iomask & TOR_IOMUX_SIGEVENT) wakeup(ss->eventbuf); wakeup(ss->readbuf); wakeup(ss->writebuf); return; } /* do processing to determine if an alarm-associated event needs to be sent to associated channels */ static void alarm_notify(void) { int i,j,k; /* go thru both spans */ for(i = 0; i < 2; i++) { alarms[i] &= ~TOR_ALARM_LOOPBACK; /* determine current maint status */ if (maints[i] || mainttimer[i]) alarms[i] |= TOR_ALARM_LOOPBACK; /* if change in general state */ if ((!alarms[i]) != (!lastalarms[i])) { lastalarms[i] = alarms[i]; /* save state */ /* get associated event */ if (!alarms[i]) /* if no more alarms */ j = TOR_EVENT_NOALARM; else j = TOR_EVENT_ALARM; /* send to all the chans */ for(k = 1; k <= 24; k++) { /* if channel open, send event */ /* if (tor_softc[(i * 24) + k].flags & OPEN) */ qevent((i * 24) + k,j); } } } return; } /* device probe routine .. determines if the Tormenta device is present in the system */ static int tor_probe(struct isa_device *devp) { int i,status; u_char c1,c2; struct tor_softc *ss=(struct tor_softc *)&tor_softc[devp->id_unit]; status = 0; /* default status return is 'not present' */ ss->flags = 0; /* zero flags */ /* set this temporarily so that the IO macros will work */ ss->maddr = (u_short *)devp->id_maddr; if (!devp->id_unit) /* if is master */ { /* initialize control register */ setctlreg(MASTERCLOCK); /* init all the registers in first T-1 chip to 0 */ for(i = 0x20; i < 0x40; i++) t1out(1,i,0); /* set register to 0 */ for(i = 0x60; i < 0x80; i++) t1out(1,i,0); /* set register to 0 */ /* simple test that will fail if tried in an array of standard memory */ /* put an 0x55 here */ t1out(1,0x2b,0x55); /* put an 0xaa here */ t1out(1,0x2c,0xaa); /* get input from first location */ c1 = t1in(1,0x2b); /* get input from second location */ c2 = t1in(1,0x2c); /* see if we read back what we put in */ if ((c1 == 0x55) && (c2 == 0xaa)) { status = 1; /* found */ ss->flags |= ALIVE; } } else /* return as there, only if the master is there */ { status = 0; /* if master was alive, all children are set to alive, also */ if (tor_softc[0].flags & ALIVE) { ss->flags |= ALIVE; status = 1; } } /* clear it here */ ss->maddr = 0; return(status); } /* driver attach routine */ static int tor_attach(struct isa_device *devp) { int i,j,unit; struct tor_softc *ss= &tor_softc[unit = devp->id_unit]; /* initialize blocksize */ ss->blocksize = TOR_MAX_BLOCKSIZE; if (!unit) /* if master unit */ { /* set card's memory base address */ ss->maddr = (u_short *)devp->id_maddr; devp->id_ointr = torintr; /* attach interrupt */ /* initialize all of the system variables */ bzero(txsigs,sizeof(txsigs)); bzero(alarms,sizeof(alarms)); bzero(lastalarms,sizeof(lastalarms)); bzero(maints,sizeof(maints)); bzero(txlevels,sizeof(txlevels)); bzero(alarmtimer,sizeof(alarmtimer)); bzero(mainttimer,sizeof(mainttimer)); bzero(bpvcounts,sizeof(bpvcounts)); bzero(syncs,sizeof(syncs)); bzero(conf_sums,sizeof(conf_sums)); bzero(conf_presums,sizeof(conf_presums)); bzero(conf_prev,sizeof(conf_prev)); bzero(conf_links,sizeof(conf_links)); /* initialize control register */ setctlreg(MASTERCLOCK); /* get the tx level information from the flags */ txlevels[0] = devp->id_flags & 7; txlevels[1] = (devp->id_flags >> 8) & 7; /* get the lineconfig info also */ lineconfig[0] = devp->id_flags & 0x70; lineconfig[1] = (devp->id_flags >> 8) & 0x70; /* get the sync source information from the flags */ syncs[0] = (devp->id_flags >> 16) & 3; syncs[1] = (devp->id_flags >> 20) & 3; /* enable 16 bit memory cycles (so we can access STPA chips) */ setctlreg(MASTERCLOCK | ENA16); /* init both STPA's to all silence */ for(i = 0; i < 32; i++) tor_softc[0].maddr[i] = 0x7f7f; /* disable 16 bit memory cycles */ setctlreg(MASTERCLOCK); /* init both T1 chips */ for(j = 1; j <= 2; j++) { printf("Span %d: ",j); /* init all the registers to 0 */ for(i = 0x20; i < 0x40; i++) t1out(j,i,0); /* set register to 0 */ for(i = 0x60; i < 0x80; i++) t1out(j,i,0); /* set register to 0 */ t1out(j,0x2b,8); /* set RCR1 to 8, full-on sync required */ t1out(j,0x2c,8); /* set RCR2 to 8, RSYNC is an input */ t1out(j,0x35,0x10); /* set TCR1 to 0x10 (RBS enable) */ /* note also set bit 0 in TCR1 to send yellow alarm */ t1out(j,0x36,4); /* set TCR2 to 4, TSYNC to be output */ t1out(j,0x37,0x8c); /* set CCR1 to 0x8c, Tx & Rx elastic store and sysclk = 2.048 mhz. Loopback controls are here also */ /* set CCR2 to 0x20, Enable F bits pattern */ i = 0x20; /* if ESF, set accordingly */ if (devp->id_flags & (TOR_CONFIG_ESF << ((j - 1) * 8))) i = 0x88; /* if B8ZS, add that, too */ if (devp->id_flags & (TOR_CONFIG_B8ZS << ((j - 1) * 8))) i |= 0x44; t1out(j,0x38,i); /* output to CCR2 */ /* print line coding type */ if (i & 0x40) printf("B8ZS "); else printf("AMI "); /* print framing type */ if (i & 0x80) { printf("ESF "); } else { printf("D4 (SF) "); t1out(j,0x7e,0x1c); /* F bits pattern (0x1c) into FDL register */ } /* set LICR to 0 plus tx build-out */ t1out(j,0x7c,txlevels[j - 1] << 5); printf(", Line build-out: %s\n", txlevelnames[txlevels[j - 1]]); /* report if the NOTOPEN functionality is enabled */ if (lineconfig[j - 1] & TOR_CONFIG_NOTOPEN) printf(" Will assert Yellow Alarm if no chans. open\n"); t1out(j,0x30,1); /* set LIRST to 1 in CCR3 */ DELAY(100000); /* delay 100 ms */ t1out(j,0x30,0x40); /* set CCR3 to 0x40, resetting Elastic Store */ } printf("Primary Sync Source: %s\n",syncsrcnames[syncs[0]]); printf("Secondary Sync Source: %s\n",syncsrcnames[syncs[1]]); /* enable interrupts and set clock value */ syncsrc = 0; /* start with free-run */ if (syncs[0]) syncsrc = syncs[0]; /* if we have primary, use it */ else if (syncs[1]) syncsrc = syncs[1]; /* otherwise, if we have secondary, use it */ /* output the clock info and enable interrupts */ setctlreg(clockvals[syncsrc] | INTENA); /* * Set up mu-law conversion table */ for(i = 0;i < 256;i++) { short mu,e,f,y; static short etab[]={0,132,396,924,1980,4092,8316,16764}; mu = 255-i; e = (mu & 0x70)/16; f = mu & 0x0f; y = f * (1 << (e + 3)); y += etab[e]; if (mu & 0x80) y = -y; mulaw[i] = y; } /* set up the reverse (mu-law) conversion table */ for(i = 0; i < 65536; i++) { lin2mu[i] = linear2ulaw(i - 32768); } } else { /* for non-master units, just copy the IO base */ ss->maddr = tor_softc[0].maddr; /* get signalling type from flags */ ss->sigtype = devp->id_flags & 0xff; /* if a pseudo-type (from flags), set PSEUDO flag */ if (devp->id_flags & TOR_PSEUDO) ss->flags |= PSEUDO; /* initialize timers */ ss->itimer = ss->otimer = 0; ss->txstate = TOR_TXSTATE_ONHOOK; /* put on hook */ tor_sethook(unit,TOR_TXSIG_ONHOOK); /* initialize to quiescent signalling value (what one would expect to see from an idle trunk) */ ss->rxsig = q_sig[ss->sigtype]; /* initialize IO MUX mask */ ss->iomask = 0; /* initialize conference variables */ ss->confn = 0; ss->confmode = 0; ss->confmute = 0; ss->conflast = 0; ss->rxgain = 0.0; ss->txgain = 0.0; ss->gotgs = 0; /* init the translation tables */ for(i = 0; i < 256; i++) txgainx[unit][i] = rxgainx[unit][i] = i; } #ifdef DEVFS ss->devfs_token = devfs_add_devswf(&tor_cdevsw, unit, DV_CHR, 0, 0, 0644, "tor%d", unit); #endif return 1; } /* device open routine */ static int tor_open(dev_t dev, int flags, int fmt, struct proc *p) { struct tor_softc *ss = (struct tor_softc *)&tor_softc[UNIT(dev)]; int i,s; /* if device not present, cant do I/O */ if((ss->flags & ALIVE) == 0) return ENXIO; /* if already open, cant do it again */ if(ss->flags & OPEN) return EBUSY; s = splhigh(); /* no interrupts here */ ss->flags |= OPEN; /* set open flag */ /* set default blocksize */ ss->blocksize = TOR_MAX_BLOCKSIZE; /* set up default timing parameters */ ss->prewinktime = TOR_DEFAULT_PREWINKTIME; ss->preflashtime = TOR_DEFAULT_PREFLASHTIME; ss->winktime = TOR_DEFAULT_WINKTIME; ss->flashtime = TOR_DEFAULT_FLASHTIME; if ((ss->sigtype == TOR_FXOLS) || (ss->sigtype == TOR_FXOGS)) ss->starttime = TOR_DEFAULT_RINGTIME; else ss->starttime = TOR_DEFAULT_STARTTIME; ss->rxwinktime = TOR_DEFAULT_RXWINKTIME; ss->debouncetime = TOR_DEFAULT_DEBOUNCETIME; /* initialize buffers and pointers */ ss->readn[0] = ss->readn[1] = 0; ss->readidx[0] = ss->readidx[1] = 0; ss->writen[0] = ss->writen[1] = 0; ss->writeidx[0] = ss->writeidx[1] = 0; ss->eventinidx = ss->eventoutidx = 0; /* initialize timers */ ss->itimer = ss->otimer = 0; /* initialize transmit signlling state */ ss->txstate = TOR_TXSTATE_ONHOOK; /* start with channel on hook */ tor_sethook(UNIT(dev),TOR_TXSIG_ONHOOK); /* initialize the 'select' structure */ ss->sel.si_flags = 0; ss->sel.si_pid = 0; /* initialize the IO MUX mask */ ss->iomask = 0; /* initialize the conference variables */ ss->confn = 0; ss->confmode = 0; ss->confmute = 0; ss->conflast = 0; ss->rxgain = 0.0; ss->txgain = 0.0; ss->gotgs = 0; /* init the translation tables */ for(i = 0; i < 256; i++) txgainx[UNIT(dev)][i] = rxgainx[UNIT(dev)][i] = i; splx(s); /* restore interrupt state */ return 0; } /* device close routine */ static int tor_close(dev_t dev, int flags, int fmt, struct proc *p) { struct tor_softc *ss = (struct tor_softc *)&tor_softc[UNIT(dev)]; int i,s; s = splhigh(); /* no interrupts here */ ss->flags &= ~OPEN; /* clear channel open flag */ /* force channel (and signalling state) on hook */ ss->txstate = TOR_TXSTATE_ONHOOK; tor_sethook(UNIT(dev),TOR_TXSIG_ONHOOK); /* initialize channel timers */ ss->itimer = ss->otimer = 0; /* initialize 'select' structure */ ss->sel.si_flags = 0; ss->sel.si_pid = 0; /* initialize IO MUX mask */ ss->iomask = 0; /* initialize conference variables */ ss->confn = 0; ss->confmode = 0; ss->confmute = 0; ss->conflast = 0; ss->rxgain = 0.0; ss->txgain = 0.0; ss->gotgs = 0; /* init the translation tables */ for(i = 0; i < 256; i++) txgainx[UNIT(dev)][i] = rxgainx[UNIT(dev)][i] = i; splx(s); /* restore interrupt state */ return 0; } /* device write routine */ static int tor_write(dev_t dev, struct uio *uio, int ioflag) { int s,amnt,buf,rv; struct tor_softc *ss = (struct tor_softc *)&tor_softc[UNIT(dev)]; /* fail if invalid byte count */ if (uio->uio_resid < 1) return(EINVAL); buf = -1; /* loop until we have a buffer to use */ while(buf == -1) { s = splhigh(); /* mask ints for a moment */ /* return if event pending */ if (ss->eventinidx != ss->eventoutidx) { splx(s); return(ELAST); } /* find an un-used one, if possible */ if (!ss->writen[0]) buf = 0; else if (!ss->writen[1]) buf = 1; if (buf >= 0) /* if we found one */ { /* dont do it if other buffer is full, but not in progress yet */ if ((ss->writeidx[1 - buf] == 0) && (ss->writen[1 - buf] > 0)) buf = -1; } /* if we found one, allocate it */ if (buf >= 0) { ss->writen[buf] = -1; ss->writeidx[buf] = 0; } splx(s); if (buf >= 0) break; /* if found one */ /* sleep until we have one to use */ rv = tsleep(ss->writebuf,25 | PCATCH,"torout",0); if (rv) return(rv); } /* figure out how many to actually transfer */ amnt = uio->uio_resid; /* limit to max blocksize */ if (amnt > TOR_MAX_BLOCKSIZE) amnt = TOR_MAX_BLOCKSIZE; if (amnt) /* if there is any */ { if (rv = uiomove((caddr_t)ss->writebuf[buf], amnt, uio)) { /* if had an error */ ss->writen[buf] = 0; /* de-allocate it */ return(rv); } ss->writen[buf] = amnt; /* set value, activating it */ } return(0); } /* device read routine */ static int tor_read(dev_t dev, struct uio *uio, int ioflag) { int s,amnt,buf,rv; struct tor_softc *ss = (struct tor_softc *)&tor_softc[UNIT(dev)]; /* fail if invalid byte count */ if (uio->uio_resid < 1) return(EINVAL); buf = -1; /* loop until we have a buffer to use */ while(buf == -1) { s = splhigh(); /* mask ints for a moment */ /* return if event pending */ if (ss->eventinidx != ss->eventoutidx) { splx(s); return(ELAST); } /* find a used one, if possible */ if (ss->readn[0] > 0) buf = 0; else if (ss->readn[1] > 0) buf = 1; /* if overflow */ if ((buf == 0) && (ss->readn[1] > 0)) { /* zot both buffers */ ss->readidx[0] = ss->readidx[1] = 0; ss->readn[0] = ss->readn[1] = 0; buf = -1; } splx(s); if (buf >= 0) break; /* if found one */ /* sleep until we have one to use */ rv = tsleep(ss->readbuf,25 | PCATCH,"torin",0); if (rv) return(rv); } /* figure out how many to actually transfer */ amnt = uio->uio_resid; /* limit to how many in buffer */ if (amnt > ss->readn[buf]) amnt = ss->readn[buf]; rv = 0; if (amnt) rv = uiomove((caddr_t)ss->readbuf[buf], amnt, uio); s = splhigh(); ss->readidx[buf] = 0; ss->readn[buf] = 0; /* de-allocate it */ splx(s); return(rv); } /* device ioctl routine */ static int tor_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { int i,j,k,s,rv,ret; u_char c; struct tor_softc *ss = (struct tor_softc *)&tor_softc[UNIT(dev)]; struct tor_params *paramp; struct tor_maintinfo *maintp; struct tor_spaninfo *spanp; struct tor_confinfo *confp; struct tor_gains *gainp; if(!data) return(EINVAL); switch(cmd) { case TOR_GET_BLOCKSIZE: /* get blocksize */ *((int *)data) = ss->blocksize; /* return block size */ break; case TOR_SET_BLOCKSIZE: /* set blocksize */ /* cannot be larger then buffers */ if (*((int *)data) > TOR_MAX_BLOCKSIZE) return(EINVAL); /* cannot be less then 16 */ if (*((int *)data) < 16) return(EINVAL); ss->blocksize = *((int *)data); /* set the blocksize */ break; case TOR_GET_PARAMS: /* get channel timing parameters */ /* point to relevant structure */ paramp = (struct tor_params *) data; paramp->sigtype = ss->sigtype; /* get signalling type */ /* get various timers */ paramp->prewinktime = ss->prewinktime; paramp->preflashtime = ss->preflashtime; paramp->winktime = ss->winktime; paramp->flashtime = ss->flashtime; paramp->starttime = ss->starttime; paramp->rxwinktime = ss->rxwinktime; paramp->debouncetime = ss->debouncetime; break; case TOR_SET_PARAMS: /* set channel timing paramters */ /* point to relevant structure */ paramp = (struct tor_params *)data; /* NOTE: sigtype is *not* included in this */ /* get timing paramters */ ss->prewinktime = paramp->prewinktime; ss->preflashtime = paramp->preflashtime; ss->winktime = paramp->winktime; ss->flashtime = paramp->flashtime; ss->starttime = paramp->starttime; ss->rxwinktime = paramp->rxwinktime; ss->debouncetime = paramp->debouncetime; break; case TOR_FLUSH: /* flush input buffer, output buffer, and/or event queue */ s = splhigh(); /* no interrupts here */ i = *((int *)data); /* get param */ if (i & TOR_FLUSH_READ) /* if for read (input) */ { /* initialize read buffers and pointers */ ss->readn[0] = ss->readn[1] = 0; ss->readidx[0] = ss->readidx[1] = 0; wakeup(ss->readbuf); /* wakeup waiting on read */ selwakeup(&ss->sel); /* wakeup waiting on select */ } if (i & TOR_FLUSH_WRITE) /* if for write (output) */ { /* initialize write buffers and pointers */ ss->writen[0] = ss->writen[1] = 0; ss->writeidx[0] = ss->writeidx[1] = 0; wakeup(ss->writebuf); /* wakeup waiting on write */ selwakeup(&ss->sel); /* wakeup waiting on select */ /* if IO MUX wait on write empty, well, this certainly *did* empty the write */ if (ss->iomask & TOR_IOMUX_WRITEEMPTY) wakeup(ss->eventbuf); /* wakeup waiting on IOMUX */ } if (i & TOR_FLUSH_EVENT) /* if for events */ { /* initialize the event pointers */ ss->eventinidx = ss->eventoutidx = 0; } splx(s); /* restore interrupt state */ break; case TOR_SYNC: /* wait for no tx */ for(;;) /* loop forever */ { s = splhigh(); /* disable interrupts */ /* get amt. of write pending */ i = ss->writen[0] + ss->writen[1]; splx(s); /* restore interrupt state */ if (!i) break; /* skip if none */ rv = tsleep(ss->writebuf,25 | PCATCH,"torsyn",0); /* wait on it */ if (rv) return(rv); /* return if error */ } break; case TOR_GETEVENT: /* Get event on queue */ s = splhigh(); /* disable interrupts */ /* set up for no event */ *((int *)data) = TOR_EVENT_NONE; /* if some event in queue */ if (ss->eventinidx != ss->eventoutidx) { /* get the data, bump index */ *((int *)data) = ss->eventbuf[ss->eventoutidx++]; /* if index overflow, set to beginning */ if (ss->eventoutidx >= TOR_MAX_EVENTSIZE) ss->eventoutidx = 0; } splx(s); /* restore interrupt state */ break; case TOR_IOMUX: /* wait for something to happen */ ss->iomask = *((int*)data); /* save mask */ if (!ss->iomask) return(EINVAL); /* cant wait for nothing */ for(;;) /* loop forever */ { /* has to have SOME mask */ ret = 0; /* start with empty return value */ s = splhigh(); /* no interrupts here */ /* if looking for read */ if (ss->iomask & TOR_IOMUX_READ) { /* if read available */ if (ss->readn[0] || ss->readn[1]) ret |= TOR_IOMUX_READ; } /* if looking for write avail */ if (ss->iomask & TOR_IOMUX_WRITE) { /* if at least 1 write buffer avail */ if (((!ss->writen[0]) && (!((!ss->writeidx[1]) && (ss->writen[1] > 0)))) || ((!ss->writen[1]) && (!((!ss->writeidx[0]) && (ss->writen[0] > 0))))) ret |= TOR_IOMUX_WRITE; } /* if looking for write empty */ if (ss->iomask & TOR_IOMUX_WRITEEMPTY) { /* if everything empty */ if ((!ss->writen[0]) && (!ss->writen[1]) && (!ss->writeidx[0]) && (!ss->writeidx[1])) ret |= TOR_IOMUX_WRITEEMPTY; } /* if looking for signalling event */ if (ss->iomask & TOR_IOMUX_SIGEVENT) { /* if event */ if (ss->eventinidx != ss->eventoutidx) ret |= TOR_IOMUX_SIGEVENT; } splx(s); /* restore interrupt state */ /* if something to return, or not to wait */ if (ret || (ss->iomask & TOR_IOMUX_NOWAIT)) { /* set return value */ *((int*)data) = ret; break; /* get out of loop */ } rv = tsleep(ss->eventbuf,25 | PCATCH,"tormux",0); /* wait on it */ if (rv) return(rv); /* if error, return */ } /* clear IO MUX mask */ ss->iomask = 0; break; case TOR_HOOK: /* set hookswitch state */ /* if not in right state, return busy */ if ((*((int *)data) != TOR_ONHOOK) && (ss->txstate != TOR_TXSTATE_ONHOOK) && (ss->txstate != TOR_TXSTATE_OFFHOOK) && (ss->txstate != TOR_TXSTATE_DEBOUNCE)) return EBUSY; switch(*((int *)data)) { case TOR_ONHOOK: /* put on hook */ s = splhigh(); tor_sethook(UNIT(dev),TOR_TXSIG_ONHOOK); ss->otimer = 0; /* clear timer */ ss->txstate = TOR_TXSTATE_ONHOOK; splx(s); break; case TOR_OFFHOOK: /* take off hook */ s = splhigh(); tor_sethook(UNIT(dev),TOR_TXSIG_OFFHOOK); ss->otimer = ss->debouncetime; /* set for debounce timeout */ ss->txstate = TOR_TXSTATE_DEBOUNCE; splx(s); break; case TOR_START: /* has to be onhook for this to work */ if (ss->txstate != TOR_TXSTATE_ONHOOK) return EBUSY; s = splhigh(); tor_sethook(UNIT(dev),TOR_TXSIG_START); ss->otimer = ss->starttime; /* initialize timer */ ss->txstate = TOR_TXSTATE_START; splx(s); rv = tsleep(&ss->txstate,25 | PCATCH,"torsig",0); /* wait on it */ if (rv) return(rv); /* return if error */ break; case TOR_WINK: /* wink */ /* has to be onhook for this to work */ if (ss->txstate != TOR_TXSTATE_ONHOOK) return EBUSY; s = splhigh(); ss->otimer = ss->prewinktime; /* initialize timer */ ss->txstate = TOR_TXSTATE_PREWINK; splx(s); rv = tsleep(&ss->txstate,25 | PCATCH,"torsig",0); /* wait on it */ if (rv) return(rv); /* return if error */ break; case TOR_FLASH: /* flash */ /* has to be offhook for this to work */ if (ss->txstate != TOR_TXSTATE_OFFHOOK) return EBUSY; s = splhigh(); ss->otimer = ss->preflashtime; /* initialize timer */ ss->txstate = TOR_TXSTATE_PREFLASH; splx(s); rv = tsleep(&ss->txstate,25 | PCATCH,"torsig",0); /* wait on it */ if (rv) return(rv); break; default: break; } break; case TOR_MAINT: /* do maintence stuff */ /* must only do this on master device */ if (UNIT(dev)) return(EINVAL); /* point to useful struct */ maintp = (struct tor_maintinfo *) data; /* must be valid span number */ if ((maintp->spanno < 1) || (maintp->spanno > 2)) return(EINVAL); s = splhigh(); /* disable ints */ /* save current maint state */ i = maints[maintp->spanno - 1]; /* set maint mode */ maints[maintp->spanno - 1] = maintp->command; switch(maintp->command) { case TOR_MAINT_NONE: /* if same, ignore it */ if (i == TOR_MAINT_NONE) break; t1out(maintp->spanno,0x37,0x8c); /* clear system */ break; case TOR_MAINT_LOCALLOOP: /* if same, ignore it */ if (i == TOR_MAINT_LOCALLOOP) break; t1out(maintp->spanno,0x37,0xcc); /* local loopback */ break; case TOR_MAINT_REMOTELOOP: /* if same, ignore it */ if (i == TOR_MAINT_REMOTELOOP) break; t1out(maintp->spanno,0x37,0x9c); /* remote loopback */ break; case TOR_MAINT_LOOPUP: t1out(maintp->spanno,0x30,2); /* send loopup code */ mainttimer[maintp->spanno - 1] = TOR_LOOPCODE_TIME; rv = tsleep(&mainttimer[maintp->spanno - 1], 25 | PCATCH,"torcod",0); /* wait on it */ if (rv) return(rv); break; case TOR_MAINT_LOOPDOWN: t1out(maintp->spanno,0x30,4); /* send loopdown code */ mainttimer[maintp->spanno - 1] = TOR_LOOPCODE_TIME; rv = tsleep(&mainttimer[maintp->spanno - 1], 25 | PCATCH,"torcod",0); /* wait on it */ if (rv) return(rv); break; } alarm_notify(); /* process alarm-related events */ splx(s); break; case TOR_SPANSTAT: /* get alarm stuff */ /* point to useful struct */ spanp = (struct tor_spaninfo *) data; i = spanp->spanno; /* get specified span number */ if ((i < 0) || (i > 2)) return(EINVAL); /* if bad span no */ if (i == 0) /* if to figure it out for this chan */ { /* cant do this for master */ if (!UNIT(dev)) return(EINVAL); /* calculate it */ i = ((UNIT(dev) - 1) / 24) + 1; } spanp->spanno = i; /* put the span # in here */ spanp->alarms = alarms[i - 1]; s = splhigh(); /* no interrupts here */ t1out(i,0x31,0xff); c = t1in(i,0x31); /* get RIR2 */ spanp->bpvcount = bpvcounts[i - 1]; splx(s); /* restore interrupt state */ spanp->rxlevel = c >> 6; /* get rx level */ spanp->txlevel = txlevels[i - 1]; /* get tx level */ spanp->syncsrc = syncsrc; /* get active sync source */ break; case TOR_GETCONF: /* get conf stuff */ /* point to useful struct */ confp = (struct tor_confinfo *) data; i = confp->chan; /* get channel no */ /* if zero, use current channel no */ if (!i) i = UNIT(dev); /* make sure channel number makes sense */ if ((i < 0) || (i > NTOR)) return(EINVAL); /* make sure conf number makes sense, too */ if ((confp->confno < 0) || (confp->confno > NTOR)) return(EINVAL); confp->chan = i; /* get channel number */ confp->confno = tor_softc[i].confn; /* get conference number */ confp->confmode = tor_softc[i].confmode; /* get conference mode */ break; case TOR_SETCONF: /* set conf stuff */ /* point to useful struct */ confp = (struct tor_confinfo *) data; i = confp->chan; /* get channel no */ /* if zero, use current channel no */ if (!i) i = UNIT(dev); /* make sure channel number makes sense */ if ((i < 1) || (i > NTOR)) return(EINVAL); /* make sure conf number makes sense, too */ if ((confp->confno < 0) || (confp->confno > NCONF)) return(EINVAL); /* if taking off of any conf, must have 0 mode */ if ((!confp->confno) && confp->confmode) return(EINVAL); confp->chan = i; /* return with real channel # */ s = splhigh(); /* cant interrupt */ /* if changing confs, clear last added info */ if (confp->confno != tor_softc[i].confn) tor_softc[i].conflast = 0; tor_softc[i].confn = confp->confno; /* set conference number */ tor_softc[i].confmode = confp->confmode; /* set conference mode */ splx(s); /* restore interrupt status */ break; case TOR_CONFLINK: /* do conf link stuff */ /* point to useful struct */ confp = (struct tor_confinfo *) data; /* check sanity of arguments */ if ((confp->chan < 0) || (confp->chan > NCONF)) return(EINVAL); if ((confp->confno < 0) || (confp->confno > NCONF)) return(EINVAL); /* cant listen to self!! */ if (confp->chan && (confp->chan == confp->confno)) return(EINVAL); s = splhigh(); /* if to clear all links */ if ((!confp->chan) && (!confp->confno)) { /* clear all the links */ bzero(conf_links,sizeof(conf_links)); splx(s); break; } rv = 0; /* clear return value */ /* look for already existant specified combination */ for(i = 1; i <= NCONF; i++) { /* if found, exit */ if ((conf_links[i].src == confp->chan) && (conf_links[i].dst == confp->confno)) break; } if (i <= NCONF) /* if found */ { if (!confp->confmode) /* if to remove link */ { conf_links[i].src = conf_links[i].dst = 0; } else /* if to add and already there, error */ { rv = EEXIST; } } else /* if not found */ { if (confp->confmode) /* if to add link */ { /* look for empty location */ for(i = 1; i <= NCONF; i++) { /* if empty, exit loop */ if ((!conf_links[i].src) && (!conf_links[i].dst)) break; } /* if empty spot found */ if (i <= NCONF) { conf_links[i].src = confp->chan; conf_links[i].dst = confp->confno; } else /* if no empties -- error */ { rv = ENOSPC; } } else /* if to remove, and not found -- error */ { rv = ENOENT; } } splx(s); return(rv); case TOR_CONFDIAG: /* output diagnostic info to console */ j = *((int *)data); /* get conf # */ /* loop thru the interesting ones */ for(i = ((j) ? j : 1); i <= ((j) ? j : NCONF); i++) { c = 0; for(k = 1; k < NTOR; k++) { /* skip if not in this conf */ if (tor_softc[k].confn != i) continue; if (!c) printf("Conf #%d:\n",i); c = 1; printf("chan %d, mode %x\n", k,tor_softc[k].confmode); } rv = 0; for(k = 1; k <= NCONF; k++) { if (conf_links[k].dst == i) { if (!c) printf("Conf #%d:\n",i); c = 1; if (!rv) printf("Snooping on:\n"); rv = 1; printf("conf %d\n",conf_links[k].src); } } if (c) printf("\n"); } break; case TOR_GETGAINS: /* get gain stuff */ /* point to useful struct */ gainp = (struct tor_gains *) data; i = gainp->chan; /* get channel no */ /* if zero, use current channel no */ if (!i) i = UNIT(dev); /* make sure channel number makes sense */ if ((i < 0) || (i > NTOR)) return(EINVAL); gainp->chan = i; /* put the span # in here */ gainp->txgain = ss->txgain; /* get tx gain */ gainp->rxgain = ss->rxgain; /* get rx gain */ break; case TOR_SETGAINS: /* set gain stuff */ /* point to useful struct */ gainp = (struct tor_gains *) data; i = gainp->chan; /* get channel no */ /* if zero, use current channel no */ if (!i) i = UNIT(dev); /* make sure channel number makes sense */ if ((i < 0) || (i > NTOR)) return(EINVAL); gainp->chan = i; /* put the span # in here */ /* generate translate table for rx gain */ tor_softc[i].rxgain = gainp->rxgain; /* save it */ for(j = 0; j < 256; j++) { /* mult float of linear value by gain and conv to int */ k = (int)(((float) mulaw[j]) * gainp->rxgain); /* clip it */ if (k > 32767) k = 32767; if (k < -32767) k = -32767; /* back to mulaw and in table */ rxgainx[i][j] = lin2mu[k + 32768]; } /* generate translate table for tx gain */ tor_softc[i].txgain = gainp->txgain; /* save it */ for(j = 0; j < 256; j++) { /* mult float of linear value by gain and conv to int */ k = (int)(((float) mulaw[j]) * gainp->txgain); /* clip it */ if (k > 32767) k = 32767; if (k < -32767) k = -32767; /* back to mulaw and in table */ txgainx[i][j] = lin2mu[k + 32768]; } break; case TOR_CONFMUTE: /* Set Conference mute mode */ ss->confmute = *((int *)data); /* get flag */ break; default: return ENOTTY; } return 0; } /* device select routine */ static int tor_select(dev_t dev, int rw, struct proc *p) { struct tor_softc *ss = (struct tor_softc *)&tor_softc[UNIT(dev)]; int s,ret; s = splhigh(); if (rw == FWRITE) /* if for write */ { /* if at least 1 write buffer avail */ if (((!ss->writen[0]) && (!((!ss->writeidx[1]) && (ss->writen[1] > 0)))) || ((!ss->writen[1]) && (!((!ss->writeidx[0]) && (ss->writen[0] > 0))))) { ret = 1; } else { selrecord(p, &ss->sel); ret = 0; } } /* otherwise, it was for read */ if (ss->readn[0] || ss->readn[1]) /* if something to read */ { ret = 1; } else { selrecord(p, &ss->sel); ret = 0; } splx(s); return(ret); } /* set hookswitch state routine */ static void tor_sethook(int chan, int what) { int i,k,n,b,s; u_char m,c; static int outs[6][3] = { { 0, 0, 0 }, /* no sig */ { 0, TOR_ABIT | TOR_BBIT,TOR_ABIT | TOR_BBIT }, /* E and M */ { TOR_BBIT, TOR_ABIT | TOR_BBIT, TOR_ABIT | TOR_BBIT }, /* FXS Loopstart */ { TOR_BBIT, TOR_ABIT | TOR_BBIT, TOR_ABIT }, /* FXS Groundstart */ { TOR_BBIT, TOR_BBIT, 0 }, /* FXO Loopstart */ { TOR_ABIT | TOR_BBIT, TOR_BBIT, 0 } /* FXO Groundstart */ } ; /* ignore if a pseudo-device */ if (tor_softc[chan].flags & PSEUDO) return; /* make sure its valid */ if ((chan < 1) || (chan > NTOR)) return; i = (chan - 1); k = (i / 24); /* get span number */ n = (i % 24); /* get channel number */ b = (n / 8); /* get byte number */ m = 1 << (n & 7); /* get mask */ c = txsigs[k][b]; c &= ~m; /* clear mask bit */ /* set mask bit, if bit is to be set */ if (outs[tor_softc[chan].sigtype][what] & TOR_ABIT) c |= m; txsigs[k][b] = c; s = splhigh(); /* no interrupts here */ t1out(k + 1,0x70 + b,c); t1out(k + 1,0x76 + b,c); b += 3; /* now points to b bit stuff */ /* get current signalling values */ c = txsigs[k][b]; c &= ~m; /* clear mask bit */ /* set mask bit, if bit is to be set */ if (outs[tor_softc[chan].sigtype][what] & TOR_BBIT) c |= m; /* save new signalling values */ txsigs[k][b] = c; /* output them into the chip */ t1out(k + 1,0x70 + b,c); t1out(k + 1,0x76 + b,c); splx(s); /* restore interrupt state */ return; } /* process change in receive signalling */ static void rxchange(int chan, u_char cursig) { struct tor_softc *ss = (struct tor_softc *)&tor_softc[chan]; /* if A bit has changed */ if ((ss->rxsig & TOR_ABIT) != (cursig & TOR_ABIT)) { switch(ss->sigtype) { case TOR_EM: /* E and M */ if (cursig & TOR_ABIT) /* went off hook */ { /* set wink timer */ ss->itimer = ss->rxwinktime; } else /* went on hook */ { if (ss->itimer) /* if timer still going */ qevent(chan,TOR_EVENT_WINKFLASH); else qevent(chan,TOR_EVENT_ONHOOK); ss->itimer = 0; } break; case TOR_FXSGS: /* FXS Groundstart */ if (cursig & TOR_ABIT) /* if went on hook */ { /* if not during offhook debounce time */ if (ss->txstate != TOR_TXSTATE_DEBOUNCE) qevent(chan,TOR_EVENT_ONHOOK); } break; case TOR_FXOLS: /* FXO Loopstart */ case TOR_FXOGS: /* FXO Groundstart */ if (cursig & TOR_ABIT) /* if went off hook */ { /* if asserting ring, stop it */ if (ss->txstate == TOR_TXSTATE_START) { tor_sethook(chan,TOR_TXSIG_OFFHOOK); ss->otimer = TOR_AFTERSTART_TIME; ss->txstate = TOR_TXSTATE_AFTERSTART; } if (ss->itimer) /* if timer still running */ qevent(chan,TOR_EVENT_WINKFLASH); else { /* if havent got GS detect */ if (!ss->gotgs) { qevent(chan,TOR_EVENT_RINGOFFHOOK); ss->gotgs = 1; ss->itimer = 0; } } ss->itimer = 0; } if (!(cursig & TOR_ABIT)) /* if went on hook */ { /* if not during offhook debounce time */ if (ss->txstate != TOR_TXSTATE_DEBOUNCE) { ss->itimer = ss->rxflashtime; } } break; default: break; } } /* if B bit has changed */ if ((ss->rxsig & TOR_BBIT) != (cursig & TOR_BBIT)) { switch(ss->sigtype) { case TOR_FXSLS: /* FXS Loopstart */ case TOR_FXSGS: /* FXS Groundstart */ if (cursig & TOR_BBIT) /* if trailing edge of ring */ qevent(chan,TOR_EVENT_RINGOFFHOOK); break; case TOR_FXOGS: /* FXO Groundstart */ if (!(cursig & TOR_BBIT)) /* if ground detected */ { /* if havent got gs, report it */ if (!ss->gotgs) { qevent(chan,TOR_EVENT_RINGOFFHOOK); ss->gotgs = 1; } } break; default: break; } } return; } /* process input time-out */ static void do_itimer(int chan) { struct tor_softc *ss = (struct tor_softc *)&tor_softc[chan]; /* the only way this could have gotten here, is if a channel went off hook longer then the wink or flash detect timeout */ switch(ss->sigtype) { case TOR_FXOLS: /* if FXO, its definitely on hook */ case TOR_FXOGS: qevent(chan,TOR_EVENT_ONHOOK); ss->gotgs = 0; break; default: /* otherwise, its definitely off hook */ qevent(chan,TOR_EVENT_RINGOFFHOOK); break; } } static void do_otimer(int chan) { struct tor_softc *ss = (struct tor_softc *)&tor_softc[chan]; switch(ss->txstate) { case TOR_TXSTATE_START: /* was starting */ tor_sethook(chan,TOR_TXSIG_OFFHOOK); ss->otimer = TOR_AFTERSTART_TIME; ss->txstate = TOR_TXSTATE_AFTERSTART; break; case TOR_TXSTATE_PREWINK: /* was pre-wink */ tor_sethook(chan,TOR_TXSIG_OFFHOOK); ss->otimer = ss->winktime; ss->txstate = TOR_TXSTATE_WINK; break; case TOR_TXSTATE_WINK: /* was wink */ tor_sethook(chan,TOR_TXSIG_ONHOOK); ss->otimer = 0; ss->txstate = TOR_TXSTATE_ONHOOK; wakeup(&ss->txstate); break; case TOR_TXSTATE_PREFLASH: /* was pre-flash */ tor_sethook(chan,TOR_TXSIG_ONHOOK); ss->otimer = ss->flashtime; ss->txstate = TOR_TXSTATE_FLASH; break; case TOR_TXSTATE_FLASH: /* was flash */ tor_sethook(chan,TOR_TXSIG_OFFHOOK); ss->otimer = 0; ss->txstate = TOR_TXSTATE_OFFHOOK; wakeup(&ss->txstate); break; case TOR_TXSTATE_DEBOUNCE: /* was debounce */ ss->otimer = 0; ss->txstate = TOR_TXSTATE_OFFHOOK; break; case TOR_TXSTATE_AFTERSTART: /* was after start */ ss->otimer = 0; ss->txstate = TOR_TXSTATE_OFFHOOK; wakeup(&ss->txstate); break; default: break; } return; } /* define code for processing transmit sample, used within interrupt routine */ #define TORINTR_TRANSMIT \ { \ /* skip if not open */ \ /* if (!(tor_softc[i].flags & OPEN)) continue; */ \ buf = -1; \ /* if both have data, look for one in progress */ \ if ((tor_softc[i].writen[0] > 0) && (tor_softc[i].writen[1] > 0)) \ { \ if (tor_softc[i].writeidx[0] > 0) buf = 0; \ else if (tor_softc[i].writeidx[1] > 0) buf = 1; \ } \ else /* find the only one with data */ \ { \ if (tor_softc[i].writen[0] > 0) buf = 0; \ else if (tor_softc[i].writen[1] > 0) buf = 1; \ } \ gottx = 1; \ txc = 0x7f; /* default tx char */ \ if (buf >= 0) /* if we have a buffer to do */ \ { \ /* wakeup on first char out, also */ \ if (!tor_softc[i].writeidx[buf]) \ { \ wakeup(tor_softc[i].writebuf); \ selwakeup(&tor_softc[i].sel); \ if (tor_softc[i].iomask & TOR_IOMUX_WRITE) \ wakeup(&tor_softc[i].eventbuf); \ } \ /* get transmit char, and bump buffer index */ \ txc = tor_softc[i].writebuf[buf][tor_softc[i].writeidx[buf]++]; \ /* if last char */ \ if (tor_softc[i].writeidx[buf] >= tor_softc[i].writen[buf]) \ { \ /* initialize buffer */ \ tor_softc[i].writeidx[buf] = 0; \ tor_softc[i].writen[buf] = 0; \ /* wake anyone up that is sleeping */ \ wakeup(tor_softc[i].writebuf); \ selwakeup(&tor_softc[i].sel); \ if (tor_softc[i].iomask & (TOR_IOMUX_WRITE | TOR_IOMUX_WRITEEMPTY)) \ wakeup(&tor_softc[i].eventbuf); \ } \ } \ /* okay, the byte from the tx buffer for this channel \ is now in txc */ \ /* take the value in txc, twiddle it for conf stuff, \ and put it back into txc */ \ txlin = mulaw[txc]; \ switch (tor_softc[i].confmode & TOR_CONF_MODE_MASK) \ { \ case TOR_CONF_NORMAL: /* normal mode */ \ /* do nothing here. let the tx buffer go to output */ \ txc = lin2mu[txlin + 32768]; \ break; \ case TOR_CONF_MONITOR: /* monitor a channel's rx mode */ \ /* add monitored channel to tx */ \ txlin += tor_softc[tor_softc[i].confn].rxlin; \ /* clip it */ \ if (txlin > 32767) txlin = 32767; \ if (txlin < -32767) txlin = 32767; \ txc = lin2mu[txlin + 32768]; \ break; \ case TOR_CONF_MONITORTX: /* monitor a channel's tx mode */ \ /* add monitored channel to tx */ \ txlin += tor_softc[tor_softc[i].confn].txlin; \ /* clip it */ \ if (txlin > 32767) txlin = 32767; \ if (txlin < -32767) txlin = 32767; \ txc = lin2mu[txlin + 32768]; \ break; \ case TOR_CONF_MONITORBOTH: /* monitor a channel's rx and tx mode */ \ /* add monitored channel to tx */ \ txlin += tor_softc[tor_softc[i].confn].rxlin + \ tor_softc[tor_softc[i].confn].txlin; \ /* clip it */ \ if (txlin > 32767) txlin = 32767; \ if (txlin < -32767) txlin = 32767; \ txc = lin2mu[txlin + 32768]; \ break; \ case TOR_CONF_CONF: /* normal conference mode */ \ case TOR_CONF_CONFMON: /* conference monitor mode */ \ /* if a listener on the conf */ \ if (tor_softc[i].confmode & TOR_CONF_LISTENER) \ { \ /* subtract out last sample written to conf */ \ txlin -= tor_softc[i].conflast; \ /* add in conf */ \ txlin += conf_sums[tor_softc[i].confn]; \ } \ /* clip it */ \ if (txlin > 32767) txlin = 32767; \ if (txlin < -32767) txlin = 32767; \ txc = lin2mu[txlin + 32768]; \ break; \ case TOR_CONF_CONFANN: /* conference with announce mode */ \ case TOR_CONF_CONFANNMON: /* conference with announce \ and monitor mode */ \ /* first, add tx buffer to conf */ \ txlin += conf_presums[tor_softc[i].confn]; \ /* clip it */ \ if (txlin > 32767) txlin = 32767; \ if (txlin < -32767) txlin = 32767; \ conf_presums[tor_softc[i].confn] = (short) txlin; \ /* now, start with silence */ \ txlin = 0; \ /* if a listener on the conf */ \ if (tor_softc[i].confmode & TOR_CONF_LISTENER) \ { \ /* subtract out last sample written to conf */ \ txlin -= tor_softc[i].conflast; \ /* add in conf */ \ txlin += conf_sums[tor_softc[i].confn]; \ } \ /* clip it */ \ if (txlin > 32767) txlin = 32767; \ if (txlin < -32767) txlin = 32767; \ txc = lin2mu[txlin + 32768]; \ break; \ } \ tor_softc[i].txlin = txlin; \ } /* define code for processing receive sample, used within interrupt routine */ #define TORINTR_RECEIVE \ { \ /* skip if not open */ \ /* if (!(tor_softc[i].flags & OPEN)) continue; */ \ buf = -1; \ /* if both in progress, look for one that is not done */ \ if ((tor_softc[i].readidx[0] > 0) && (tor_softc[i].readidx[1] > 0)) \ { \ if (tor_softc[i].readn[0] == 0) buf = 0; \ else if (tor_softc[i].readn[1] == 0) buf = 1; \ } \ else /* otherwise, find one that is in progress maybe */ \ { \ /* if first one, set it so */ \ if ((tor_softc[i].readidx[0] > 0) && \ (tor_softc[i].readn[0] == 0)) buf = 0; \ /* if second one, set it so */ \ else if ((tor_softc[i].readidx[1] > 0) && \ (tor_softc[i].readn[1] == 0)) buf = 1; \ } \ if (buf < 0) /* if none found in progress and not full, \ try for one that is not in progress and is not full */ \ { \ if (tor_softc[i].readn[0] == 0) buf = 0; \ else if (tor_softc[i].readn[1] == 0) buf = 1; \ } \ /* get rx value in linear and save last received linear value */ \ rxlin = (int)(tor_softc[i].rxlin = mulaw[rxc]); \ /* take the value in rxc, twiddle it for conf stuff, \ and put it back into rxc and linear into rxlin */ \ /* use TOR_CONF_NORMAL if muted */ \ switch ((tor_softc[i].confmute) ? TOR_CONF_NORMAL : \ (tor_softc[i].confmode & TOR_CONF_MODE_MASK)) \ { \ case TOR_CONF_NORMAL: /* normal mode */ \ case TOR_CONF_MONITOR: /* monitor a channel's rx mode */ \ case TOR_CONF_MONITORTX: /* monitor a channel's tx mode */ \ case TOR_CONF_MONITORBOTH: /* monitor a channel's rx and tx mode */ \ /* do nothing here. let the rx buffer go to output */ \ break; \ case TOR_CONF_CONF: /* normal conference mode */ \ case TOR_CONF_CONFANN: /* conference announce mode */ \ /* if a talker on the conf */ \ if (tor_softc[i].confmode & TOR_CONF_TALKER) \ { \ k = rxlin; /* store temp value */ \ /* add conf value */ \ k += (int)conf_sums[tor_softc[i].confn]; \ if (k > 32767) k = 32767; \ if (k < -32767) k = 32767; \ /* get the amount we actually added */ \ tor_softc[i].conflast = \ ((short)k) - conf_sums[tor_softc[i].confn]; \ /* really add in new value */ \ conf_sums[tor_softc[i].confn] += \ tor_softc[i].conflast; \ } else tor_softc[i].conflast = 0; \ /* leave rxc un-modified */ \ break; \ case TOR_CONF_CONFMON: /* conference monitor mode */ \ case TOR_CONF_CONFANNMON: /* conference announce/monitor mode */ \ /* if a talker on the conf */ \ if (tor_softc[i].confmode & TOR_CONF_TALKER) \ { \ k = rxlin; /* store temp value */ \ /* subtract out last one */ \ conf_sums[tor_softc[i].confn] -= \ tor_softc[i].conflast; \ /* add conf value */ \ k += (int)conf_sums[tor_softc[i].confn]; \ if (k > 32767) k = 32767; \ if (k < -32767) k = 32767; \ /* get the amount we actually added */ \ tor_softc[i].conflast = \ ((short)k) - conf_sums[tor_softc[i].confn]; \ /* really add in new value */ \ conf_sums[tor_softc[i].confn] += \ tor_softc[i].conflast; \ } else tor_softc[i].conflast = 0; \ /* leave the conference sum in rxc */ \ rxc = lin2mu[(int)conf_prev[tor_softc[i].confn] + 32768]; \ break; \ } \ if (buf >= 0) \ { \ tor_softc[i].readbuf[buf][tor_softc[i].readidx[buf]++] \ = rxc; \ /* if last char */ \ if (tor_softc[i].readidx[buf] >= tor_softc[i].blocksize) \ { \ /* terminate buffer */ \ tor_softc[i].readn[buf] = tor_softc[i].blocksize; \ /* wake anyone up that is sleeping */ \ wakeup(tor_softc[i].readbuf); \ selwakeup(&tor_softc[i].sel); \ if (tor_softc[i].iomask & TOR_IOMUX_READ) \ wakeup(&tor_softc[i].eventbuf); \ } \ } \ } /* * Interrupt procedure. */ static void torintr(int unit) { unsigned char txc,rxc,gottx,abits,bbits,c; unsigned short rxword[25],txword; int buf,i,n,n1,j,k,s,txlin,rxlin; static u_int ictr,loopupcnt[2],loopdowncnt[2]; s = splhigh(); /* make sure its a real interrupt for us */ if (!(getctlreg() & 1)) /* if not, just return */ { splx(s); return; } /* set outbit and put int 16 bit bus mode, reset interrupt enable */ setctlreg(clockvals[syncsrc] | OUTBIT | ENA16); /* zero out the pre-sum accumulators */ bzero(conf_presums,sizeof(conf_presums)); /* Do the transmit, go thru all the chans */ /* do the receive for all chans, both spans */ for(n1 = 0; n1 < 24; n1++) { n = chseq[n1]; gottx = 0; txword = 0; /* go thru both spans */ for(j = 0; j < 2; j++) { i = n + (j * 24); /* calc chan number */ /* if no such channel */ if (i > NTOR) break; /* skip if pseudo */ if (tor_softc[i].flags & PSEUDO) continue; /* enter the transmit stuff with i being channel number, leaving with txc being character to transmit */ TORINTR_TRANSMIT txword |= txgainx[i][txc] << (j * 8); } /* write it out */ tor_softc[0].maddr[DDATA + datxlt[n]] = txword; rxword[n] = tor_softc[0].maddr[DDATA + datxlt[n]]; /* get rx word */ } /* do transmit routine for all the pseudo-channels */ for(i = 1; i < NTOR; i++) { /* skip if not psuedo */ if (!(tor_softc[i].flags & PSEUDO)) continue; TORINTR_TRANSMIT } /* process all the conf links */ for(i = 1; i <= NCONF; i++) { /* if we have a destination conf */ if (j = conf_links[i].dst) { /* get sum of us and them */ rxlin = conf_sums[conf_links[i].src] + conf_presums[j]; /* clip it..... clip it good.. da da da da da.. da da da da */ if (rxlin > 32767) rxlin = 32767; if (rxlin < -32767) rxlin = -32767; /* put it back into accumulator */ conf_presums[j] = rxlin; } } /* copy conf pre_sums into sums (thus initializing sums) */ for(i = 1; i <= NCONF; i++) { conf_prev[i] = conf_sums[i]; conf_sums[i] = conf_presums[i]; } /* do the receive for all chans, both spans */ for(n = 1; n <= 24; n++) { if (n > NTOR) continue; /* if no more, keep going */ /* go thru both spans */ for(j = 0; j < 2; j++) { i = n + (j * 24); /* calc chan number */ /* if no such channel */ if (i > NTOR) break; /* skip if pseudo */ if (tor_softc[i].flags & PSEUDO) continue; /* get rx byte out of word */ rxc = rxgainx[i][(rxword[n] >> (j * 8)) & 0xff] ; TORINTR_RECEIVE } } /* do receive routine for all the pseudo-channels */ for(i = 1; i < NTOR; i++) { /* skip if not psuedo */ if (!(tor_softc[i].flags & PSEUDO)) continue; rxc = 0x7f; TORINTR_RECEIVE } setctlreg(clockvals[syncsrc] | OUTBIT); /* clear 16 bit mode */ /* bump ictr, and see if its divisible by 8 */ ictr++; if ((ictr & 7) == 0) /* do stuff every millisecond */ { /* go thru all the chans */ for(i = 1; i < NTOR; i++) { /* skip if not open */ /* if (!(tor_softc[i].flags & OPEN)) continue; */ /* skip if pseudo */ if (tor_softc[i].flags & PSEUDO) continue; /* if itimer to process, do it */ if (tor_softc[i].itimer && (!--tor_softc[i].itimer)) do_itimer(i); /* if otimer to process, do it */ if (tor_softc[i].otimer && (!--tor_softc[i].otimer)) do_otimer(i); } for(i = 0; i < 2; i++) { /* if maint time, and it's timed out */ if (mainttimer[i] && (!--mainttimer[i])) { t1out(i + 1,0x30,0); /* stop sending code */ alarm_notify(); wakeup(&mainttimer[i]); } /* if alarm timer, and it's timed out */ if (alarmtimer[i] && (!--alarmtimer[i])) { /* clear recover status */ alarms[i] &= ~TOR_ALARM_RECOVER; t1out(i + 1,0x35,0x10); /* turn off yel */ alarm_notify(); /* let them know */ } } } i = ictr & 511; if (i < 6) /* do the signalling stuff */ { k = (i / 3); /* get span */ n = (i % 3); /* get base */ abits = t1in(k + 1,0x60 + n); bbits = t1in(k + 1,0x63 + n); /* go thru all the chans represented */ for(j = 0; j < 8; j++) { /* calculate real channel number */ i = (k * 24) + (n * 8) + j + 1; /* if channel not existant, skip */ if (i >= NTOR) break; /* skip if not open */ /* if (!(tor_softc[i].flags & OPEN)) continue; */ /* assemble the sig bits into one byte */ rxc = 0; if (abits & (1 << j)) rxc |= TOR_ABIT; if (bbits & (1 << j)) rxc |= TOR_BBIT; /* process it */ if (tor_softc[i].rxsig != rxc) rxchange(i,rxc); tor_softc[i].rxsig = rxc; } } i = ictr & 511; if ((i == 100) || (i == 101)) { j = 0; /* clear this alarm status */ i -= 100; t1out(i + 1,0x20,0xff); c = t1in(i + 1,0x20); /* get the status */ /* detect the code, only if we are not sending one */ if ((!mainttimer[i]) && (c & 0x80)) /* if loop-up code detected */ { /* set into remote loop, if not there already */ if ((loopupcnt[i]++ > 80) && (maints[i] != TOR_MAINT_REMOTELOOP)) { t1out(i + 1,0x37,0x9c); /* remote loopback */ maints[i] = TOR_MAINT_REMOTELOOP; } } else loopupcnt[i] = 0; /* detect the code, only if we are not sending one */ if ((!mainttimer[i]) && (c & 0x40)) /* if loop-down code detected */ { /* if in remote loop, get out of it */ if ((loopdowncnt[i]++ > 80) && (maints[i] == TOR_MAINT_REMOTELOOP)) { t1out(i + 1,0x37,0x8c); /* normal */ maints[i] = TOR_MAINT_NONE; } } else loopdowncnt[i] = 0; if (c & 3) /* if red alarm */ { j |= TOR_ALARM_RED; } if (c & 8) /* if blue alarm */ { j |= TOR_ALARM_BLUE; } /* only consider previous carrier alarm state (and NOTOPEN) */ alarms[i] &= (TOR_ALARM_RED | TOR_ALARM_BLUE | TOR_ALARM_NOTOPEN); n = 1; /* set to 1 so will not be in yellow alarm if we dont care about open channels */ /* if to have yellow alarm if nothing open */ if (lineconfig[i] & TOR_CONFIG_NOTOPEN) { /* go thru all chans, and count # open */ for(n = 0,k = (i * 24) + 1; k <= (i * 24) + 24; k++) { if (tor_softc[k].flags & OPEN) n++; } /* if none open, set alarm condition */ if (!n) j |= TOR_ALARM_NOTOPEN; } /* if no more alarms, and we had some */ if ((!j) && alarms[i]) { alarmtimer[i] = TOR_ALARMSETTLE_TIME; } if (alarmtimer[i]) j |= TOR_ALARM_RECOVER; /* if going into alarm state, set yellow alarm */ if ((j) && (!alarms[i])) t1out(i + 1,0x35,0x11); if (c & 4) /* if yellow alarm */ j |= TOR_ALARM_YELLOW; if (maints[i] || mainttimer[i]) j |= TOR_ALARM_LOOPBACK; alarms[i] = j; } alarm_notify(); if (!(ictr % 8000)) /* even second boundary */ { /* do both spans */ for(i = 1; i <= 2; i++) { /* add this second's BPV count to total one */ bpvcounts[i - 1] += t1in(i,0x24) + (t1in(i,0x23) << 8); } } /* re-evaluate active sync src */ syncsrc = 0; /* if primary sync specified, see if we can use it */ if (syncs[0]) { /* if no alarms, use it */ if (!(alarms[syncs[0] - 1] & (TOR_ALARM_RED | TOR_ALARM_BLUE | TOR_ALARM_LOOPBACK))) syncsrc = syncs[0]; } /* if we dont have one yet, and there is a secondary, see if we can use it */ if ((!syncsrc) && (syncs[1])) { /* if no alarms, use it */ if (!(alarms[syncs[1] - 1] & (TOR_ALARM_RED | TOR_ALARM_BLUE | TOR_ALARM_LOOPBACK))) syncsrc = syncs[1]; } /* clear outbit, restore interrupt enable */ setctlreg(clockvals[syncsrc] | INTENA); splx(s); } static tor_devsw_installed = 0; static void tor_drvinit(void *unused) { dev_t dev; if( ! tor_devsw_installed ) { dev = makedev(CDEV_MAJOR, 0); cdevsw_add(&dev,&tor_cdevsw, NULL); tor_devsw_installed = 1; } } SYSINIT(tordev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,tor_drvinit,NULL) /* ** This routine converts from linear to ulaw ** ** Craig Reese: IDA/Supercomputing Research Center ** Joe Campbell: Department of Defense ** 29 September 1989 ** ** References: ** 1) CCITT Recommendation G.711 (very difficult to follow) ** 2) "A New Digital Technique for Implementation of Any ** Continuous PCM Companding Law," Villeret, Michel, ** et al. 1973 IEEE Int. Conf. on Communications, Vol 1, ** 1973, pg. 11.12-11.17 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards ** for Analog-to_Digital Conversion Techniques," ** 17 February 1987 ** ** Input: Signed 16 bit linear sample ** Output: 8 bit ulaw sample */ #define ZEROTRAP /* turn on the trap as per the MIL-STD */ #define BIAS 0x84 /* define the add-in bias for 16 bit samples */ #define CLIP 32635 static unsigned char linear2ulaw(short sample) { static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; int sign, exponent, mantissa; unsigned char ulawbyte; /* Get the sample into sign-magnitude. */ sign = (sample >> 8) & 0x80; /* set aside the sign */ if (sign != 0) sample = -sample; /* get magnitude */ if (sample > CLIP) sample = CLIP; /* clip the magnitude */ /* Convert from 16 bit linear to ulaw. */ sample = sample + BIAS; exponent = exp_lut[(sample >> 7) & 0xFF]; mantissa = (sample >> (exponent + 3)) & 0x0F; ulawbyte = ~(sign | (exponent << 4) | mantissa); #ifdef ZEROTRAP if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */ #endif return(ulawbyte); } #endif /* NTOR */