From d18a439c45a0300519463b14c76e282bbf3eddec Mon Sep 17 00:00:00 2001 From: markster Date: Sat, 27 Oct 2001 20:51:21 +0000 Subject: Version 0.1.0 from FTP git-svn-id: http://svn.digium.com/svn/zaptel/trunk@17 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- torisa.c | 902 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 902 insertions(+) create mode 100755 torisa.c (limited to 'torisa.c') diff --git a/torisa.c b/torisa.c new file mode 100755 index 0000000..c4fa92d --- /dev/null +++ b/torisa.c @@ -0,0 +1,902 @@ +/* + * Zapata Telephony "Tormenta" ISA card LINUX driver, version 2.0 X/X/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 + +/* 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 */ + +/* signalling bits */ +#define TOR_ABIT 8 +#define TOR_BBIT 4 + +static int syncsrc; + +static int syncs[2]; + +static int debug; + +/* clock values */ +static u_char clockvals[] = {0,0x12,0x22,0}; + +/* 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 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[] = + { 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,1,2,3,4,5 } ; + +struct torisa_pvt { + int span; +}; + +static struct zt_span spans[2]; +static struct zt_chan chans[48]; +static struct torisa_pvt pvts[48]; +static u_char txsigs[2][6]; +static int loopupcnt[2]; +static int loopdowncnt[2]; +static int alarmtimer[2]; + +static int prefmaster = 0; + +static int spansstarted = 0; + +static rwlock_t torisa; + +static u_char readdata[2][48][ZT_MAX_CHUNKSIZE]; +static u_char writedata[2][48][ZT_MAX_CHUNKSIZE]; +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;i<24;i++) { + j = (i/8); + if (spans[s].chans[i].flags & ZT_FLAG_CLEAR) + val |= 1 << (i % 8); + + if ((i % 8)==7) { +#if 0 + printk("Putting %d in register %02x on span %d\n", + val, 0x39 + j, 1 + s); +#endif + t1out(1 + s, 0x39 + j, val); + val = 0; + } + } + } + +} + +/* device probe routine .. determines if the Tormenta device is present in + the system */ +static int +tor_probe(void) +{ + int i,status; + u_char c1,c2; + maddr = phys_to_virt(base); + + status = -1; /* default status return is 'not present' */ + + /* 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)) + { + /* Try to get the irq if the user didn't specify one */ + if (irq < 1) { + autoirq_setup(0); + setctlreg(MASTERCLOCK|INTENA); + /* Wait a jiffie -- that's plenty of time */ + irq = autoirq_report(5); + } + /* disable interrupts having gotten one */ + setctlreg(MASTERCLOCK); + if (irq == 2) + irq = 9; + if (irq) { + /* init both STPA's to all silence */ + for(i = 0; i < 32; i++) maddr[i] = 0x7f7f; + + status = 0; /* found */ + if (debug) + printk("ISA Tormenta Card found at base addr 0x%lx, irq %d\n",base,irq); + } else + printk("ISA Tormenta Card found at base addr 0x%lx, but unable to determine IRQ. Try using irq= option\n", base); + } + return status; +} + +static void make_chans(void) +{ + int x,y; + int c; + for (x=0;x<2;x++) + for (y=0;y<24;y++) { + c = x * 24 + y; + sprintf(chans[c].name, "TorISA/%d/%d", x + 1, y + 1); + chans[c].sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_FXSLS | ZT_SIG_FXSGS | ZT_SIG_FXSKS | + ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_FXOKS; + chans[c].pvt = &pvts[c]; + pvts[c].span = x; + chans[c].chanpos = y + 1; + } + +} + +static int torisa_rbsbits(struct zt_chan *chan, int bits) +{ + u_char m,c; + int k,n,b; + struct torisa_pvt *p = chan->pvt; + unsigned int flags; +#if 0 + printk("Setting bits to %d on channel %s\n", bits, chan->name); +#endif + 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); + 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 (bits & ZT_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); + 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 int 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 = 0x20; i< 0x40; i++) + t1out(tspan, i, 0); + for (i = 0x60; i< 0x80; 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 int flags; + char *coding; + char *framing; + 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; + + 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(); + + write_unlock_irqrestore(&torisa, flags); + + if (debug) { + 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)); + } + 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 int 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) + set_clear(); + write_unlock_irqrestore(&torisa, flags); + return 0; +} + +static int torisa_open(struct zt_chan *chan) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int torisa_close(struct zt_chan *chan) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +static int torisa_maint(struct zt_span *span, int cmd) +{ + int tspan = getspan(span); + + switch(cmd) { + case ZT_MAINT_NONE: + t1out(tspan,0x37,0x8c); /* clear system */ + break; + case ZT_MAINT_LOCALLOOP: + t1out(tspan,0x37,0xcc); /* local loopback */ + break; + case ZT_MAINT_REMOTELOOP: + t1out(tspan,0x37,0x9c); /* remote loopback */ + break; + case ZT_MAINT_LOOPUP: + t1out(tspan,0x30,2); /* send loopup code */ + break; + case ZT_MAINT_LOOPDOWN: + t1out(tspan,0x30,4); /* send loopdown code */ + break; + case ZT_MAINT_LOOPSTOP: + 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) +{ + + taskletrun++; + if (taskletpending) { + taskletexec++; + /* Perform receive data calculations. Reverse to run most + likely master last */ + if (spans[1].flags & ZT_FLAG_RUNNING) + zt_receive(&spans[1]); + if (spans[0].flags & ZT_FLAG_RUNNING) + zt_receive(&spans[0]); + + /* Prepare next set for transmission */ + if (spans[1].flags & ZT_FLAG_RUNNING) + zt_transmit(&spans[1]); + if (spans[0].flags & ZT_FLAG_RUNNING) + zt_transmit(&spans[0]); + } + taskletpending = 0; +} + +static int txerrors; + +static void torisa_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + static unsigned int passno = 0; + int n, n1, i, j, k, x; + static unsigned short rxword[25],txword[25]; + unsigned char txc, rxc, c; + unsigned char abits, bbits; + + + irqcount++; + + /* 1. Do all I/O Immediately -- Normally we would ask for + the transmission first, but because of the incredibly + tight timing we're lucky to be able to do the I/O + at this point */ + + /* make sure its a real interrupt for us */ + if (!(getctlreg() & 1)) /* if not, just return */ + { + return; + } + + /* set outbit and put int 16 bit bus mode, reset interrupt enable */ + setctlreg(clockvals[syncsrc] | OUTBIT | ENA16); + +#if 0 + if (!passno) + printk("Interrupt handler\n"); +#endif + + /* Do the actual transmit and receive in poopy order */ + for(n1 = 0; n1 < 24; n1++) + { + n = chseq[n1]; + maddr[DDATA + datxlt[n]] = txword[n]; + rxword[n] = maddr[DDATA + datxlt[n]]; /* get rx word */ + } + + setctlreg(clockvals[syncsrc] | OUTBIT); /* clear 16 bit mode */ + + + /* Calculate the transmit, go thru all the chans */ + for(n1 = 0; n1 < 24; n1++) + { + n = chseq[n1]; + txword[n] = 0; + /* go thru both spans */ + for(j = 0; j < 2; j++) + { + /* enter the transmit stuff with i being channel number, + leaving with txc being character to transmit */ + txc = writedata[curread][j * 24 + n-1][passno % ZT_CHUNKSIZE]; + txword[n] |= txc << (j * 8); + } + } + + + /* do the receive for all chans, both spans */ + for(n1 = 0; n1 < 24; n1++) + { + n = chseq[n1]; + /* go thru both spans */ + for(j = 0; j <= 1; j++) + { + i = n + (j * 24); /* calc chan number */ + rxc = (rxword[n] >> (j * 8)) & 0xff; + readdata[curread][j * 24 + n - 1][passno % ZT_CHUNKSIZE] = rxc; + } + } + + i = passno & 511; + if (i < 6) { + k = (i / 3); /* get span */ + n = (i % 3); /* get base */ + abits = t1in(k + 1, 0x60 + n); + bbits = t1in(k + 1, 0x63 + 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 (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; + t1out(i + 1,0x35,0x10); /* turn off yel */ + zt_alarm_notify(&spans[i]); /* let them know */ + } + } + } + } + + i = passno & 511; + if ((i == 100) || (i == 101)) + { + j = 0; /* clear this alarm status */ + i -= 100; + 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; + } + /* 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 * 24); k < (i * 24) + 24; 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 alarm */ + if ((j) && (!spans[i].alarms)) t1out(i + 1,0x35,0x11); + 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++) + { + /* add this second's BPV count to total one */ + spans[i - 1].bpvcount += 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 (!(spans[syncs[0] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE | + ZT_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 (!(spans[syncs[1] - 1].alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE | + ZT_ALARM_LOOPBACK))) syncsrc = syncs[1]; + } + /* update sync src info */ + spans[0].syncsrc = spans[1].syncsrc = syncsrc; + /* If this is the last pass, then prepare the next set */ + if ((passno % ZT_CHUNKSIZE) == (ZT_CHUNKSIZE - 1)) { + /* Swap buffers */ + for (x = 0;x<48;x++) { + chans[x].readchunk = readdata[curread][x]; + chans[x].writechunk = writedata[curread][x]; + } + /* Lets work with the others now which presumably have been filled */ + curread = 1 - curread; + if (!taskletpending) { + taskletpending = 1; + taskletsched++; + tasklet_hi_schedule(&torisa_tlet); + } else { + txerrors++; + } + + } + passno++; + /* clear outbit, restore interrupt enable */ + setctlreg(clockvals[syncsrc] | INTENA); +} + + +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 = 24; + 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 = 24; + spans[1].chans = &chans[24]; + 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; + 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"); +MODULE_PARM(prefmaster, "i"); +MODULE_PARM(base, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(syncsrc, "i"); +MODULE_PARM(debug, "i"); + +module_init(tor_init); +module_exit(tor_exit); -- cgit v1.2.3