/* * Zapata Telephony "Tormenta" ISA card LINUX driver, version 2.2 11/29/01 * * 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. * * Modified from original tor.c by Mark Spencer * original by Jim Dixon */ #include #include #include #include #include #include #include #include #include #include #ifdef STANDALONE_ZAPATA #include "zaptel.h" #include "torisa.h" #else #include #include #endif #ifdef LINUX26 #include #endif /* 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 OUTBIT 8 /* Status output bit (for external measurements) */ #define INTENA 4 /* Interrupt enable bit */ #define MASTERVAL 0x41 /* Enable E1 master clock on Rev. B board */ #define ENA16 0x80 /* 16 bit bus cycle enable bit */ #define TYPE_T1 1 /* is a T1 card */ #define TYPE_E1 2 /* is an E1 card */ #define E1SYNCSTABLETHRESH 15000 /* amount of samples needed for E1 Sync stability */ static int syncsrc; static int syncs[2]; static int debug; #define MASTERCLOCK (*clockvals) /* value for master clock */ /* clock values */ static u_char clockvals_t1[] = {MASTERVAL,0x12,0x22,MASTERVAL}; static u_char clockvals_e1[] = {MASTERVAL,0x13,0x23,MASTERVAL}; static u_char *clockvals; /* translations of data channels for 24 channels in a 32 bit PCM highway */ unsigned datxlt_t1[] = { 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 }; /* translations of data channels for 30/31 channels in a 32 bit PCM highway */ unsigned datxlt_e1[] = { 0, 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25,26,27,28,29,30,31 }; unsigned int *datxlt; /* 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 gives us the most flexibility in how long our interrupt latency is (note: Even with this, our interrupt latency must be between 4 and 28 microseconds!!!) Essentially we receive the interrupt just after the 24th channel is read. It will take us AT LEAST 30 microseconds to read it, but could take as much as 35 microseconds to read all the channels. In any case it's the very first thing we do in the interrupt handler. Worst case (30 microseconds) is that the MT8920 has only moved 7 channels. That's where the 6 comes from. */ static int chseq_t1[] = { 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,1,2,3,4,5 } ; static int chseq_e1[] = { 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,1,2,3,4,5 } ; static int *chseq; struct torisa_pvt { int span; }; static struct zt_span spans[2]; static struct zt_chan chans[64]; static struct torisa_pvt pvts[64]; static u_char txsigs[2][16]; static int loopupcnt[2]; static int loopdowncnt[2]; static int alarmtimer[2]; static int channels_per_span = 24; static int card_type = TYPE_T1; static int prefmaster = 0; static int spansstarted = 0; #ifdef DEFINE_RWLOCK static DEFINE_RWLOCK(torisa); #else static rwlock_t torisa = RW_LOCK_UNLOCKED; #endif static u_char readdata[2][64][ZT_MAX_CHUNKSIZE]; static u_char writedata[2][64][ZT_MAX_CHUNKSIZE]; static u_char last_ecwrite[2][32]; static int curread; static unsigned long base; volatile static unsigned short *maddr; static int irq; static unsigned int irqcount = 0; static unsigned int taskletsched = 0; static unsigned int taskletrun = 0; static unsigned int taskletexec = 0; /* set the control register */ static void setctlreg(unsigned char val) { volatile register char *cp; cp = (char *) &maddr[CTLREG]; *cp = val; } /* output a byte to one of the registers in one of the Dallas T-1 chips */ static void t1out(int spanno, int loc, unsigned char val) { register int n; volatile register char *cp; /* get the memory offset */ n = spanno << 9; /* point a char * at the address location */ cp = (char *) &maddr[DADDR + n]; *cp = loc; /* set address in T1 chip */ /* point a char * at the data location */ cp = (char *) &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(int spanno, int loc) { register int n; volatile register char *cp; /* get the memory offset */ n = spanno << 9; /* point a char * at the address location */ cp = (char *) &maddr[DADDR + n]; *cp = loc; /* set address in T1 chip */ cp = (char *) &maddr[DDATA + n]; /* point a char * at the data location */ return(*cp); } /* get input from the status register */ static unsigned char getctlreg(void) { register char *cp; cp = (char *) &maddr[CTLREG]; return(*cp); } static void set_clear(void) { int i,j,s; unsigned short val=0; for (s=0;s<2;s++) { for (i=0;ipvt; unsigned long flags; #if 0 printk("Setting bits to %x hex on channel %s\n", bits, chan->name); #endif if (card_type == TYPE_E1) { /* do it E1 way */ if (chan->chanpos > 30) return 0; /* cant do this for chan 31 */ n = chan->chanpos - 1; k = p->span; b = (n % 15) + 1; c = txsigs[k][b]; m = (n / 15) * 4; /* nibble selector */ c &= (15 << m); /* keep the other nibble */ c |= (bits & 15) << (4 - m); /* put our new nibble here */ txsigs[k][b] = c; /* output them into the chip */ t1out(k + 1,0x40 + b,c); return 0; } n = chan->chanpos - 1; k = p->span; 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 (bits & ZT_ABIT) c |= m; txsigs[k][b] = c; write_lock_irqsave(&torisa, flags); t1out(k + 1,0x70 + 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 (bits & ZT_BBIT) c |= m; /* save new signalling values */ txsigs[k][b] = c; /* output them into the chip */ t1out(k + 1,0x70 + b,c); b += 3; /* now points to c 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 (bits & ZT_CBIT) c |= m; /* save new signalling values */ txsigs[k][b] = c; /* output them into the chip */ t1out(k + 1,0x70 + b,c); b += 3; /* now points to d 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 (bits & ZT_DBIT) c |= m; /* save new signalling values */ txsigs[k][b] = c; /* output them into the chip */ t1out(k + 1,0x70 + b,c); write_unlock_irqrestore(&torisa, flags); return 0; } static inline int getspan(struct zt_span *span) { if (span == spans) return 1; if (span == spans + 1) return 2; return -1; } static int torisa_shutdown(struct zt_span *span) { int i; int tspan; int wasrunning; unsigned long flags; tspan = getspan(span); if (tspan < 0) { printk("TorISA: Span '%d' isn't us?\n", span->spanno); return -1; } write_lock_irqsave(&torisa, flags); wasrunning = span->flags & ZT_FLAG_RUNNING; span->flags &= ~ZT_FLAG_RUNNING; /* Zero out all registers */ for (i = 0; i< 0xff; i++) t1out(tspan, i, 0); if (wasrunning) spansstarted--; write_unlock_irqrestore(&torisa, flags); if (!spans[0].flags & ZT_FLAG_RUNNING && !spans[1].flags & ZT_FLAG_RUNNING) /* No longer in use, disable interrupts */ setctlreg(clockvals[syncsrc]); if (debug) printk("Span %d (%s) shutdown\n", span->spanno, span->name); return 0; } static int torisa_startup(struct zt_span *span) { unsigned long endjif; int i; int tspan; unsigned long flags; char *coding; char *framing; char *crcing; int alreadyrunning; tspan = getspan(span); if (tspan < 0) { printk("TorISA: Span '%d' isn't us?\n", span->spanno); return -1; } write_lock_irqsave(&torisa, flags); alreadyrunning = span->flags & ZT_FLAG_RUNNING; /* initialize the start value for the last ec buffer */ for(i = 0; i < span->channels; i++) { last_ecwrite[tspan - 1][i] = ZT_LIN2X(0,&span->chans[i]); } crcing = ""; if (card_type == TYPE_T1) { /* if its a T1 card */ if (!alreadyrunning) { setctlreg(MASTERCLOCK); /* Zero out all registers */ for (i = 0x20; i< 0x40; i++) t1out(tspan, i, 0); for (i = 0x60; i< 0x80; i++) t1out(tspan, i, 0); /* Full-on Sync required (RCR1) */ t1out(tspan, 0x2b, 8); /* RSYNC is an input (RCR2) */ t1out(tspan, 0x2c, 8); /* RBS enable (TCR1) */ t1out(tspan, 0x35, 0x10); /* TSYNC to be output (TCR2) */ t1out(tspan, 0x36, 4); /* Tx & Rx Elastic store, sysclk = 2.048 mhz, loopback controls (CCR1) */ t1out(tspan, 0x37, 0x8c); } /* Enable F bits pattern */ i = 0x20; if (span->lineconfig & ZT_CONFIG_ESF) i = 0x88; if (span->lineconfig & ZT_CONFIG_B8ZS) i |= 0x44; t1out(tspan, 0x38, i); if (i & 0x80) coding = "ESF"; else coding = "SF"; if (i & 0x40) framing = "B8ZS"; else { framing = "AMI"; t1out(tspan,0x7e,0x1c); /* F bits pattern (0x1c) into FDL register */ } t1out(tspan, 0x7c, span->txlevel << 5); if (!alreadyrunning) { /* LIRST to 1 in CCR3 */ t1out(tspan, 0x30, 1); /* Wait 100 ms */ endjif = jiffies + 10; write_unlock_irqrestore(&torisa, flags); while(jiffies < endjif); /* wait 100 ms */ write_lock_irqsave(&torisa, flags); t1out(tspan,0x30,0x40); /* set CCR3 to 0x40, resetting Elastic Store */ span->flags |= ZT_FLAG_RUNNING; spansstarted++; #if 0 printk("Enabling interrupts: %d\n", clockvals[syncsrc] | INTENA); #endif /* output the clock info and enable interrupts */ setctlreg(clockvals[syncsrc] | INTENA); } set_clear(); /* this only applies to a T1 */ } else { /* if its an E1 card */ u_char ccr1 = 0, tcr1 = 0; if (!alreadyrunning) { t1out(tspan,0x1a,4); /* CCR2: set LOTCMC */ for(i = 0; i <= 8; i++) t1out(tspan,i,0); for(i = 0x10; i <= 0x4f; i++) if (i != 0x1a) t1out(tspan,i,0); t1out(tspan,0x10,0x20); /* RCR1: Rsync as input */ t1out(tspan,0x11,6); /* RCR2: Sysclk=2.048 Mhz */ t1out(tspan,0x12,8); /* TCR1: TSiS mode */ } tcr1 = 8; /* base TCR1 value: TSis mode */ if (span->lineconfig & ZT_CONFIG_CCS) { ccr1 |= 8; /* CCR1: Rx Sig mode: CCS */ coding = "CCS"; } else { tcr1 |= 0x20; coding = "CAS"; } if (span->lineconfig & ZT_CONFIG_HDB3) { ccr1 |= 0x44; /* CCR1: TX and RX HDB3 */ framing = "HDB3"; } else framing = "AMI"; if (span->lineconfig & ZT_CONFIG_CRC4) { ccr1 |= 0x11; /* CCR1: TX and TX CRC4 */ crcing = "/CRC4"; } t1out(tspan,0x12,tcr1); t1out(tspan,0x14,ccr1); t1out(tspan, 0x18, 0x80); if (!alreadyrunning) { t1out(tspan,0x1b,0x8a); /* CCR3: LIRST & TSCLKM */ t1out(tspan,0x20,0x1b); /* TAFR */ t1out(tspan,0x21,0x5f); /* TNAFR */ t1out(tspan,0x40,0xb); /* TSR1 */ for(i = 0x41; i <= 0x4f; i++) t1out(tspan,i,0x55); for(i = 0x22; i <= 0x25; i++) t1out(tspan,i,0xff); /* Wait 100 ms */ endjif = jiffies + 10; write_unlock_irqrestore(&torisa, flags); while(jiffies < endjif); /* wait 100 ms */ write_lock_irqsave(&torisa, flags); t1out(tspan,0x1b,0x9a); /* CCR3: set also ESR */ t1out(tspan,0x1b,0x82); /* CCR3: TSCLKM only now */ /* output the clock info and enable interrupts */ setctlreg(clockvals[syncsrc] | INTENA); } } write_unlock_irqrestore(&torisa, flags); if (debug) { if (card_type == TYPE_T1) { if (alreadyrunning) printk("TorISA: Reconfigured span %d (%s/%s) LBO: %s\n", span->spanno, coding, framing, zt_lboname(span->txlevel)); else printk("TorISA: Startup span %d (%s/%s) LBO: %s\n", span->spanno, coding, framing, zt_lboname(span->txlevel)); } else { if (alreadyrunning) printk("TorISA: Reconfigured span %d (%s/%s%s) 120 ohms\n", span->spanno, coding, framing, crcing); else printk("TorISA: Startup span %d (%s/%s%s) 120 ohms\n", span->spanno, coding, framing, crcing); } } if (syncs[0] == span->spanno) printk("SPAN %d: Primary Sync Source\n",span->spanno); if (syncs[1] == span->spanno) printk("SPAN %d: Secondary Sync Source\n",span->spanno); return 0; } static int torisa_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) { if (debug) printk("TorISA: Configuring span %d\n", span->spanno); /* XXX We assume lineconfig is okay and shouldn't XXX */ span->lineconfig = lc->lineconfig; span->txlevel = lc->lbo; span->rxlevel = 0; span->syncsrc = syncsrc; /* remove this span number from the current sync sources, if there */ if (syncs[0] == span->spanno) syncs[0] = 0; if (syncs[1] == span->spanno) syncs[1] = 0; /* if a sync src, put it in proper place */ if (lc->sync) syncs[lc->sync - 1] = span->spanno; /* If we're already running, then go ahead and apply the changes */ if (span->flags & ZT_FLAG_RUNNING) return torisa_startup(span); return 0; } static int torisa_chanconfig(struct zt_chan *chan, int sigtype) { int alreadyrunning; unsigned long flags; alreadyrunning = chan->span->flags & ZT_FLAG_RUNNING; if (debug) { if (alreadyrunning) printk("TorISA: Reconfigured channel %d (%s) sigtype %d\n", chan->channo, chan->name, sigtype); else printk("TorISA: Configured channel %d (%s) sigtype %d\n", chan->channo, chan->name, sigtype); } write_lock_irqsave(&torisa, flags); if (alreadyrunning && (card_type == TYPE_T1)) set_clear(); write_unlock_irqrestore(&torisa, flags); return 0; } static int torisa_open(struct zt_chan *chan) { #ifndef LINUX26 MOD_INC_USE_COUNT; #endif return 0; } static int torisa_close(struct zt_chan *chan) { #ifndef LINUX26 MOD_DEC_USE_COUNT; #endif return 0; } static int torisa_maint(struct zt_span *span, int cmd) { int tspan = getspan(span); switch(cmd) { case ZT_MAINT_NONE: t1out(tspan,0x1a,4); /* clear system */ break; case ZT_MAINT_LOCALLOOP: t1out(tspan,0x1a,5); /* local loopback */ break; case ZT_MAINT_REMOTELOOP: t1out(tspan,0x37,6); /* remote loopback */ break; case ZT_MAINT_LOOPUP: if (card_type == TYPE_E1) return -ENOSYS; t1out(tspan,0x30,2); /* send loopup code */ break; case ZT_MAINT_LOOPDOWN: if (card_type == TYPE_E1) return -ENOSYS; t1out(tspan,0x30,4); /* send loopdown code */ break; case ZT_MAINT_LOOPSTOP: if (card_type == TYPE_T1) t1out(tspan,0x30,0); /* stop sending loopup code */ break; default: printk("torisa: Unknown maint command: %d\n", cmd); break; } return 0; } static int taskletpending; static struct tasklet_struct torisa_tlet; static void torisa_tasklet(unsigned long data) { int x,y; u_char mychunk[2][ZT_CHUNKSIZE]; taskletrun++; if (taskletpending) { taskletexec++; /* Perform receive data calculations. Reverse to run most likely master last */ if (spans[1].flags & ZT_FLAG_RUNNING) { /* Perform echo cancellation */ for (x=0;x> (j * 8)) & 0xff; readdata[curread][j * channels_per_span + n - 1][passno % ZT_CHUNKSIZE] = rxc; } } i = passno & 127; /* if an E1 card, do rx signalling for it */ if (i < 3 && (card_type == TYPE_E1)) { /* if an E1 card */ for(j = (i * 3); j < (i * 3) + 5; j++) { for(k = 1,x = j; k <= 2; k++,x += channels_per_span) { c = t1in(k,0x31 + j); rxc = c & 15; if (rxc != chans[x + 15].rxsig) { /* Check for changes in received bits */ if (!(chans[x + 15].sig & ZT_SIG_CLEAR)) zt_rbsbits(&chans[x + 15], rxc); } rxc = c >> 4; if (rxc != chans[x].rxsig) { /* Check for changes in received bits */ if (!(chans[x].sig & ZT_SIG_CLEAR)) zt_rbsbits(&chans[x], rxc); } } } } /* if a t1 card, do rx signalling for it */ if ((i < 6) && (card_type == TYPE_T1)) { k = (i / 3); /* get span */ n = (i % 3); /* get base */ abits = t1in(k + 1, 0x60 + n); bbits = t1in(k + 1, 0x63 + n); cbits = t1in(k + 1, 0x66 + n); dbits = t1in(k + 1, 0x69 + n); for (j=0; j< 8; j++) { /* Get channel number */ i = (k * 24) + (n * 8) + j; rxc = 0; if (abits & (1 << j)) rxc |= ZT_ABIT; if (bbits & (1 << j)) rxc |= ZT_BBIT; if (cbits & (1 << j)) rxc |= ZT_CBIT; if (dbits & (1 << j)) rxc |= ZT_DBIT; if (chans[i].rxsig != rxc) { /* Check for changes in received bits */ if (!(chans[i].sig & ZT_SIG_CLEAR)) zt_rbsbits(&chans[i], rxc); } } } if (!(passno & 0x7)) { for(i = 0; i < 2; i++) { /* if alarm timer, and it's timed out */ if (alarmtimer[i]) { if (!--alarmtimer[i]) { /* clear recover status */ spans[i].alarms &= ~ZT_ALARM_RECOVER; if (card_type == TYPE_T1) t1out(i + 1,0x35,0x10); /* turn off yel */ else t1out(i + 1,0x21,0x5f); /* turn off remote alarm */ zt_alarm_notify(&spans[i]); /* let them know */ } } } } i = passno & 511; if ((i == 100) || (i == 101)) { j = 0; /* clear this alarm status */ i -= 100; if (card_type == TYPE_T1) { c = t1in(i + 1,0x31); /* get RIR2 */ spans[i].rxlevel = c >> 6; /* get rx level */ t1out(i + 1,0x20,0xff); c = t1in(i + 1,0x20); /* get the status */ /* detect the code, only if we are not sending one */ if ((!spans[i].mainttimer) && (c & 0x80)) /* if loop-up code detected */ { /* set into remote loop, if not there already */ if ((loopupcnt[i]++ > 80) && (spans[i].maintstat != ZT_MAINT_REMOTELOOP)) { t1out(i + 1,0x37,0x9c); /* remote loopback */ spans[i].maintstat = ZT_MAINT_REMOTELOOP; } } else loopupcnt[i] = 0; /* detect the code, only if we are not sending one */ if ((!spans[i].mainttimer) && (c & 0x40)) /* if loop-down code detected */ { /* if in remote loop, get out of it */ if ((loopdowncnt[i]++ > 80) && (spans[i].maintstat == ZT_MAINT_REMOTELOOP)) { t1out(i + 1,0x37,0x8c); /* normal */ spans[i].maintstat = ZT_MAINT_NONE; } } else loopdowncnt[i] = 0; if (c & 3) /* if red alarm */ { j |= ZT_ALARM_RED; } if (c & 8) /* if blue alarm */ { j |= ZT_ALARM_BLUE; } } else { /* its an E1 card */ t1out(i + 1,6,0xff); c = t1in(i + 1,6); /* get the status */ if (c & 9) /* if red alarm */ { j |= ZT_ALARM_RED; } if (c & 2) /* if blue alarm */ { j |= ZT_ALARM_BLUE; } } /* only consider previous carrier alarm state */ spans[i].alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_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 (spans[i].lineconfig & ZT_CONFIG_NOTOPEN) { /* go thru all chans, and count # open */ for(n = 0,k = (i * channels_per_span); k < (i * channels_per_span) + channels_per_span; k++) { if ((chans[k].flags & ZT_FLAG_OPEN) || (chans[k].flags & ZT_FLAG_NETDEV)) n++; } /* if none open, set alarm condition */ if (!n) j |= ZT_ALARM_NOTOPEN; } /* if no more alarms, and we had some */ if ((!j) && spans[i].alarms) { alarmtimer[i] = ZT_ALARMSETTLE_TIME; } if (alarmtimer[i]) j |= ZT_ALARM_RECOVER; /* if going into alarm state, set yellow (remote) alarm */ if ((j) && (!spans[i].alarms)) { if (card_type == TYPE_T1) t1out(i + 1,0x35,0x11); else t1out(i + 1,0x21,0x7f); } if (c & 4) /* if yellow alarm */ j |= ZT_ALARM_YELLOW; if (spans[i].maintstat || spans[i].mainttimer) j |= ZT_ALARM_LOOPBACK; spans[i].alarms = j; zt_alarm_notify(&spans[i]); } if (!(passno % 8000)) /* even second boundary */ { /* do both spans */ for(i = 1; i <= 2; i++) { if (card_type == TYPE_T1) { /* add this second's BPV count to total one */ spans[i - 1].bpvcount += t1in(i,0x24) + (t1in(i,0x23) << 8); } else { /* add this second's BPV count to total one */ spans[i - 1].bpvcount += t1in(i,1) + (t1in(i,0) << 8); } } } /* re-evaluate active sync src */ mysyncsrc = 0; /* if primary sync specified, see if we can use it */ if (syncs[0]) { /* if no alarms, use it */ if (!(spans[syncs[0] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_LOOPBACK))) mysyncsrc = syncs[0]; } /* if we dont have one yet, and there is a secondary, see if we can use it */ if ((!mysyncsrc) && (syncs[1])) { /* if no alarms, use it */ if (!(spans[syncs[1] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_LOOPBACK))) mysyncsrc = syncs[1]; } /* on the E1 card, the PLL takes a bit of time to lock going between internal and external clocking. There needs to be some settle time before actually changing the source, otherwise it will oscillate between in and out of sync */ if (card_type == TYPE_E1) { /* if stable, add to count */ if (lastsyncsrc == mysyncsrc) mysynccnt++; else mysynccnt = 0; lastsyncsrc = mysyncsrc; /* if stable sufficiently long, change it */ if (mysynccnt >= E1SYNCSTABLETHRESH) { mysynccnt = 0; syncsrc = mysyncsrc; } } else syncsrc = mysyncsrc; /* otherwise on a T1 card, just use current value */ /* update sync src info */ spans[0].syncsrc = spans[1].syncsrc = syncsrc; /* If this is the last pass, then prepare the next set */ /* clear outbit, restore interrupt enable */ setctlreg(clockvals[syncsrc] | INTENA); #ifdef LINUX26 return IRQ_RETVAL(1); #endif } static int torisa_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) { struct torisa_debug td; switch(cmd) { case TORISA_GETDEBUG: td.txerrors = txerrors; td.irqcount = irqcount; td.taskletsched = taskletsched; td.taskletrun = taskletrun; td.taskletexec = taskletexec; td.span1flags = spans[0].flags; td.span2flags = spans[1].flags; if (copy_to_user((struct torisa_debug *)data, &td, sizeof(td))) return -EFAULT; return 0; default: return -ENOTTY; } return 0; } static int __init tor_init(void) { if (!base) { printk("Specify address with base=0xNNNNN\n"); return -EIO; } if (tor_probe()) { printk(KERN_ERR "No ISA tormenta card found at %05lx\n", base); return -EIO; } if (request_irq(irq, torisa_intr, SA_INTERRUPT, "torisa", NULL)) { printk(KERN_ERR "Unable to request tormenta IRQ %d\n", irq); return -EIO; } if (!request_mem_region(base, 4096, "Tormenta ISA")) { printk(KERN_ERR "Unable to request 4k memory window at %lx\n", base); free_irq(irq, NULL); return -EIO; } strcpy(spans[0].name, "TorISA/1"); strcpy(spans[0].desc, "ISA Tormenta Span 1"); spans[0].spanconfig = torisa_spanconfig; spans[0].chanconfig = torisa_chanconfig; spans[0].startup = torisa_startup; spans[0].shutdown = torisa_shutdown; spans[0].rbsbits = torisa_rbsbits; spans[0].maint = torisa_maint; spans[0].open = torisa_open; spans[0].close = torisa_close; spans[0].channels = channels_per_span; spans[0].chans = &chans[0]; spans[0].flags = ZT_FLAG_RBS; spans[0].linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF; spans[0].ioctl = torisa_ioctl; spans[0].irq = irq; init_waitqueue_head(&spans[0].maintq); strcpy(spans[1].name, "TorISA/2"); strcpy(spans[1].desc, "ISA Tormenta Span 2"); spans[1].spanconfig = torisa_spanconfig; spans[1].chanconfig = torisa_chanconfig; spans[1].startup = torisa_startup; spans[1].shutdown = torisa_shutdown; spans[1].rbsbits = torisa_rbsbits; spans[1].maint = torisa_maint; spans[1].open = torisa_open; spans[1].close = torisa_close; spans[1].channels = channels_per_span; spans[1].chans = &chans[channels_per_span]; spans[1].flags = ZT_FLAG_RBS; spans[1].linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF; spans[1].ioctl = torisa_ioctl; spans[1].irq = irq; if (card_type == TYPE_E1) { spans[0].deflaw = ZT_LAW_ALAW; spans[1].deflaw = ZT_LAW_ALAW; } else { spans[0].deflaw = ZT_LAW_MULAW; spans[1].deflaw = ZT_LAW_MULAW; } init_waitqueue_head(&spans[1].maintq); make_chans(); if (zt_register(&spans[0], prefmaster)) { printk(KERN_ERR "Unable to register span %s\n", spans[0].name); return -EIO; } if (zt_register(&spans[1], 0)) { printk(KERN_ERR "Unable to register span %s\n", spans[1].name); zt_unregister(&spans[0]); return -EIO; } tasklet_init(&torisa_tlet, torisa_tasklet, (long)0); printk("TORISA Loaded\n"); return 0; } static int __init set_tor_base(char *str) { base = simple_strtol(str, NULL, 0); return 1; } __setup("tor=", set_tor_base); static void __exit tor_exit(void) { free_irq(irq, NULL); release_mem_region(base, 4096); if (spans[0].flags & ZT_FLAG_REGISTERED) zt_unregister(&spans[0]); if (spans[1].flags & ZT_FLAG_REGISTERED) zt_unregister(&spans[1]); } MODULE_AUTHOR("Mark Spencer "); MODULE_DESCRIPTION("Tormenta ISA Zapata Telephony Driver"); #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); #endif #ifdef LINUX26 module_param(prefmaster, int, 0600); module_param(base, long, 0600); module_param(irq, int, 0600); module_param(syncsrc, int, 0600); module_param(debug, int, 0600); #else MODULE_PARM(prefmaster, "i"); MODULE_PARM(base, "i"); MODULE_PARM(irq, "i"); MODULE_PARM(syncsrc, "i"); MODULE_PARM(debug, "i"); #endif module_init(tor_init); module_exit(tor_exit);