From 5ccad649b6fbb917cecf9530ba64814459dfe565 Mon Sep 17 00:00:00 2001 From: jim Date: Wed, 22 Dec 2004 04:44:26 +0000 Subject: Changed out VHDL code so that interrupt handling would be much more efficient and fully handle all functions git-svn-id: http://svn.digium.com/svn/zaptel/trunk@513 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- pciradio.c | 550 +++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 298 insertions(+), 252 deletions(-) (limited to 'pciradio.c') diff --git a/pciradio.c b/pciradio.c index 3351bb7..84e2507 100755 --- a/pciradio.c +++ b/pciradio.c @@ -37,9 +37,8 @@ /* Latency tests: -Without driver: 308208 -Without int: 304096 (1.3 %) -With PL check: 267722 (13.2 % -- will be much improved with new Xilinx) +Without driver: 308496 +With driver: 303826 (1.5 %) */ @@ -90,11 +89,6 @@ With PL check: 267722 (13.2 % -- will be much improved with new Xilinx) #define RAD_REGBASE 0xc0 -#define BIT_CS (1 << 2) -#define BIT_SCLK (1 << 3) -#define BIT_SDI (1 << 4) -#define BIT_SDO (1 << 5) - #define RAD_CTCSSMASK 0xf #define RAD_CTCSSOTHER 0xf #define RAD_CTCSSVALID 0x10 @@ -103,16 +97,6 @@ With PL check: 267722 (13.2 % -- will be much improved with new Xilinx) #define RAD_GOTRX_DEBOUNCE_TIME 75 -/* bits for port 0 in */ -#define MX828_DOUT 0x10 /* Data from MX828 */ -/* bits for port 0 out */ -#define MX828_DIN 0x2 /* Data to MX828 */ -#define MX828_CS0 0x10 /* MX828 CS Channel 0 */ -#define MX828_CS1 0x20 /* MX828 CS Channel 1 */ -#define MX828_CS2 0x40 /* MX828 CS Channel 2 */ -#define MX828_CS3 0x80 /* MX828 CS Channel 3 */ -#define MX828_SCLK 0x1 /* MX828 Serial Clock */ - /* * MX828 Commands */ @@ -134,6 +118,22 @@ With PL check: 267722 (13.2 % -- will be much improved with new Xilinx) #define MX828_IRQ_FLAG 0x8F /* R */ +struct encdec +{ + unsigned char state; /* 0 = idle */ + int chan; + unsigned char req[NUM_CHANS]; + unsigned char dcsrx[NUM_CHANS]; + unsigned char ctrx[NUM_CHANS]; + unsigned char dcstx[NUM_CHANS]; + unsigned char cttx[NUM_CHANS]; + unsigned char saudio_ctrl[NUM_CHANS]; + unsigned char saudio_setup[NUM_CHANS]; + unsigned char txcode[NUM_CHANS]; + int myindex[NUM_CHANS]; +} ; + + struct pciradio { struct pci_dev *dev; struct zt_span span; @@ -145,9 +145,9 @@ struct pciradio { int freeregion; int nchans; spinlock_t lock; - unsigned char p0save; - unsigned char p1save; - unsigned char p2save; + spinlock_t rbilock; + unsigned char pasave; + unsigned char pfsave; unsigned long ioaddr; dma_addr_t readdma; dma_addr_t writedma; @@ -164,6 +164,7 @@ struct pciradio { int debouncetime[NUM_CHANS]; int bursttime[NUM_CHANS]; int bursttimer[NUM_CHANS]; + unsigned char remmode[NUM_CHANS]; unsigned short present_code[NUM_CHANS]; unsigned short last_code[NUM_CHANS]; unsigned short rxcode[NUM_CHANS][NUM_CODES + 1]; @@ -178,6 +179,9 @@ struct pciradio { #define RADMODE_NOENCODE 32 unsigned char corthresh[NUM_CHANS]; struct zt_chan chans[NUM_CHANS]; + unsigned char mx828_addr; + struct encdec encdec; + unsigned long lastremcmd; }; @@ -449,35 +453,25 @@ static unsigned char __pciradio_getcreg(struct pciradio *rad, unsigned char reg) return inb(rad->ioaddr + RAD_REGBASE + ((reg & 0xf) << 2)); } -static void wait_just_a_bit(int foo) -{ - long newjiffies; - newjiffies = jiffies + foo; - while(jiffies < newjiffies); -} - -/* -* Output a byte to the MX828 PL encoder/decoder chip -*/ -void mx828_set_serdata(struct pciradio *rad,int bit) +void rbi_out(struct pciradio *rad, int n, unsigned char *rbicmd) { - rad->p0save &= ~MX828_DIN; - if(bit) - rad->p0save |= MX828_DIN; - __pciradio_setcreg(rad,0,rad->p0save); +int x; +DECLARE_WAIT_QUEUE_HEAD(mywait); + + + spin_lock(&rad->rbilock); + while(__pciradio_getcreg(rad,0xc) & 2) interruptible_sleep_on_timeout(&mywait,2); + /* enable and address RBI serializer */ + __pciradio_setcreg(rad,0xf,rad->pfsave | (n << 4) | 0x40); + /* output commands */ + for(x = 0; x < 5; x++) __pciradio_setcreg(rad,0xc,rbicmd[x]); + /* output it */ + __pciradio_setcreg(rad,0xb,1); + spin_unlock(&rad->rbilock); + return; } -void mx828_wiggle_sclk(struct pciradio *rad) -{ - rad->p0save &= ~MX828_SCLK; /* SCLK 1 -> 0 */ - __pciradio_setcreg(rad,0,rad->p0save); - udelay(1); - rad->p0save |= MX828_SCLK; /* SCLK 0 -> 1 */ - __pciradio_setcreg(rad,0,rad->p0save); - udelay(1); -} - /* * Output a command to the MX828 over the serial bus @@ -487,192 +481,156 @@ void mx828_wiggle_sclk(struct pciradio *rad) void mx828_command(struct pciradio *rad,int channel, unsigned char command, unsigned char *byte1, unsigned char *byte2) { - int i, param = 1, wr = 1, word = 0; - unsigned char byte; - if(channel > 3) return; - /* Pull the transfer info from the command code */ - - switch(command){ - case MX828_GEN_RESET: /* Commands with no param */ - param = 0; - break; - - case MX828_SAUDIO_CTRL: /* 8 bit write commands */ - case MX828_SAUDIO_SETUP: - case MX828_DCS1: - case MX828_DCS2: - case MX828_DCS3: - case MX828_IRQ_MASK: - case MX828_GEN_CTRL: - case MX828_GPT: - break; - - case MX828_SAUDIO_STATUS: /* 8 bit read commands */ - case MX828_IRQ_FLAG: - case 0: - wr = 0; - break; + rad->mx828_addr = channel; + __pciradio_setcreg(rad,0,channel); + if (byte1) __pciradio_setcreg(rad,1,*byte1); + if (byte2) __pciradio_setcreg(rad,2,*byte2); + __pciradio_setcreg(rad,3,command); + +} - case MX828_TX_TONE: /* 16 bit write commands */ - case MX828_RX_TONE: - case MX828_AUD_CTRL: - case MX828_SELCALL: - word = 1; - break; +void mx828_command_wait(struct pciradio *rad,int channel, unsigned char command, unsigned char *byte1, unsigned char *byte2) +{ +unsigned int flags; +DECLARE_WAIT_QUEUE_HEAD(mywait); - default: + for(;;) + { + spin_lock_irqsave(&rad->lock,flags); + if ((!(__pciradio_getcreg(rad,0xc) & 1)) && + (!(rad->encdec.state))) + { + mx828_command(rad,channel,command,byte1,byte2); + spin_unlock_irqrestore(&rad->lock,flags); return; + } + spin_unlock_irqrestore(&rad->lock,flags); + interruptible_sleep_on_timeout(&mywait,5); } - - - mx828_set_serdata(rad,1); /* Start with data = 1 */ - - udelay(2); - - /* Set the proper CS */ +} - byte = (unsigned char ) 1 << (channel + 4); - - rad->p0save |= (MX828_CS0 | MX828_CS1 | MX828_CS2 | MX828_CS3); - rad->p0save &= ~byte; - __pciradio_setcreg(rad,0,rad->p0save); - - udelay(2); - - /* Output the command byte */ +static void _do_encdec(struct pciradio *rad, int n) +{ +int i; +unsigned char byte1,byte2; - byte = command; - - for( i = 0 ; i < 8 ; i++){ - udelay(2); - mx828_set_serdata(rad,0x80 & byte); /* MSB first */ - byte <<= 1; - mx828_wiggle_sclk(rad); - } - if(param){ - udelay(4); - if(wr){ - byte = *byte1; - for( i = 0 ; i < 8 ; i++){ - udelay(2); - mx828_set_serdata(rad,0x80 & byte); - byte <<= 1; - mx828_wiggle_sclk(rad); - } - if(word){ - udelay(4); - byte = *byte2; - for( i = 0 ; i < 8 ; i++){ - udelay(2); - mx828_set_serdata(rad,0x80 & byte); - byte <<= 1; - mx828_wiggle_sclk(rad); - } + /* return doing nothing if busy */ + if (__pciradio_getcreg(rad,0xc) & 1) return; + switch(rad->encdec.state) + { + case 0: + if (!rad->encdec.req[n]) return; + rad->encdec.req[n] = 0; + rad->encdec.dcsrx[n] = 0; + rad->encdec.ctrx[n] = 0; + rad->encdec.dcstx[n] = 0; + rad->encdec.cttx[n] = 0; + rad->encdec.myindex[n] = 0; + rad->encdec.req[n] = 0; + rad->encdec.chan = n; + + /* if something in code 0 for rx, is DCS */ + if (rad->rxcode[n][0]) rad->encdec.dcsrx[n] = 1; + else { /* otherwise, if something in other codes, is CT rx */ + for(i = 1; i <= NUM_CODES; i++) + { + if (rad->rxcode[n][1]) rad->encdec.ctrx[n] = 1; } + } + /* get index for tx code. Will be 0 if not receiving a CT */ + rad->encdec.myindex[n] = 0; + if (rad->gotrx[n] && rad->encdec.ctrx[n] && (rad->present_code[n])) + rad->encdec.myindex[n] = rad->present_code[n]; + /* get actual tx code from array */ + rad->encdec.txcode[n] = rad->txcode[n][rad->encdec.myindex[n]]; + if (rad->encdec.txcode[n] & 0x8000) rad->encdec.dcstx[n] = 1; + else if (rad->encdec.txcode[n]) rad->encdec.cttx[n] = 1; + if (rad->radmode[n] & RADMODE_NOENCODE) + rad->encdec.dcstx[n] = rad->encdec.cttx[n] = 0; + if ((!rad->gottx[n]) || rad->bursttimer[n]) + rad->encdec.dcstx[n] = rad->encdec.cttx[n] = 0; + rad->encdec.saudio_ctrl[n] = 0; + rad->encdec.saudio_setup[n] = 0; + rad->encdec.state = 1; + break; + case 1: + if (rad->encdec.dcstx[rad->encdec.chan] && (!rad->encdec.dcsrx[rad->encdec.chan])) /* if to transmit DCS */ + { + rad->encdec.saudio_setup[rad->encdec.chan] |= 3; + rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x80; + byte1 = dcstable[rad->encdec.txcode[rad->encdec.chan] & 0x7fff].b1; + mx828_command(rad,rad->encdec.chan, MX828_DCS1, &byte1, &byte2 ); + rad->encdec.state = 2; + break; + } + rad->encdec.state = 4; + break; + case 2: + byte1 = dcstable[rad->encdec.txcode[rad->encdec.chan] & 0x7fff].b2; + mx828_command(rad,rad->encdec.chan, MX828_DCS2, &byte1, &byte2 ); + rad->encdec.state = 3; + break; + case 3: + byte1 = dcstable[rad->encdec.txcode[rad->encdec.chan] & 0x7fff].b3; + mx828_command(rad,rad->encdec.chan, MX828_DCS3, &byte1, &byte2 ); + rad->encdec.state = 4; + break; + case 4: + if (rad->encdec.cttx[rad->encdec.chan]) + { + rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x80; + byte1 = cttable_tx[rad->encdec.txcode[rad->encdec.chan]].b1; + byte2 = cttable_tx[rad->encdec.txcode[rad->encdec.chan]].b2; + mx828_command(rad,rad->encdec.chan, MX828_TX_TONE, &byte1, &byte2 ); } - else { /* rd */ - byte = 0; - for( i = 0 ; i < 8 ; i++){ - mx828_wiggle_sclk(rad); - byte <<= 1; - udelay(2); - if(__pciradio_getcreg(rad,0) & MX828_DOUT) - byte |= 0x01; - } - *byte1 = byte; - if(word){ - byte = 0; - udelay(4); - for( i = 0 ; i < 8 ; i++){ - mx828_wiggle_sclk(rad); - byte <<= 1; - udelay(2); - if(__pciradio_getcreg(rad,0) & MX828_DOUT) - byte |= 0x01; - } - *byte2 = byte; - } - + rad->encdec.state = 5; + break; + case 5: + if (rad->encdec.dcsrx[rad->encdec.chan]) + { + rad->encdec.saudio_setup[rad->encdec.chan] |= 1; + rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x41; + byte1 = dcstable[rad->rxcode[rad->encdec.chan][0]].b1; + mx828_command(rad,rad->encdec.chan, MX828_DCS1, &byte1, &byte2 ); + rad->encdec.state = 6; + break; } - } - - udelay(4); - - /* Release chip selects */ - rad->p0save |= (MX828_CS0 | MX828_CS1 | MX828_CS2 | MX828_CS3); - __pciradio_setcreg(rad,0,rad->p0save); -} - - -static void _set_encdec(struct pciradio *rad, int n) -{ -int i,myindex; -char dcsrx = 0, ctrx = 0, dcstx = 0, cttx = 0; -unsigned char byte1,byte2,saudio_ctrl,saudio_setup; -unsigned short txcode; - - - /* if something in code 0 for rx, is DCS */ - if (rad->rxcode[n][0]) dcsrx = 1; - else { /* otherwise, if something in other codes, is CT rx */ - for(i = 1; i <= NUM_CODES; i++) + rad->encdec.state = 8; + break; + case 6: + byte1 = dcstable[rad->rxcode[rad->encdec.chan][0]].b2; + mx828_command(rad,rad->encdec.chan, MX828_DCS2, &byte1, &byte2 ); + rad->encdec.state = 7; + break; + case 7: + byte1 = dcstable[rad->rxcode[rad->encdec.chan][0]].b3; + mx828_command(rad,rad->encdec.chan, MX828_DCS3, &byte1, &byte2 ); + rad->encdec.state = 8; + break; + case 8: + if (rad->encdec.ctrx[rad->encdec.chan]) { - if (rad->rxcode[n][1]) ctrx = 1; + rad->encdec.saudio_setup[rad->encdec.chan] |= 0x80; + rad->encdec.saudio_ctrl[rad->encdec.chan] |= 0x60; } - } - /* get index for tx code. Will be 0 if not receiving a CT */ - myindex = 0; - if (rad->gotrx[n] && ctrx && (rad->present_code[n])) myindex = rad->present_code[n]; - /* get actual tx code from array */ - txcode = rad->txcode[n][myindex]; - if (txcode & 0x8000) dcstx = 1; else if (txcode) cttx = 1; - if (rad->radmode[n] & RADMODE_NOENCODE) dcstx = cttx = 0; - if ((!rad->gottx[n]) || rad->bursttimer[n]) dcstx = cttx = 0; - saudio_ctrl = 0; - saudio_setup = 0; - if (dcstx && (!dcsrx)) /* if to transmit DCS */ - { - saudio_setup |= 3; - saudio_ctrl |= 0x80; - byte1 = dcstable[txcode & 0x7fff].b1; - mx828_command(rad,n, MX828_DCS1, &byte1, &byte2 ); - byte1 = dcstable[txcode & 0x7fff].b2; - mx828_command(rad,n, MX828_DCS2, &byte1, &byte2 ); - byte1 = dcstable[txcode & 0x7fff].b3; - mx828_command(rad,n, MX828_DCS3, &byte1, &byte2 ); - } - if (cttx) - { - saudio_ctrl |= 0x80; - byte1 = cttable_tx[txcode].b1; - byte2 = cttable_tx[txcode].b2; - mx828_command(rad,n, MX828_TX_TONE, &byte1, &byte2 ); - } - if (dcsrx) - { - saudio_setup |= 1; - saudio_ctrl |= 0x41; - byte1 = dcstable[rad->rxcode[n][0]].b1; - mx828_command(rad,n, MX828_DCS1, &byte1, &byte2 ); - byte1 = dcstable[rad->rxcode[n][0]].b2; - mx828_command(rad,n, MX828_DCS2, &byte1, &byte2 ); - byte1 = dcstable[rad->rxcode[n][0]].b3; - mx828_command(rad,n, MX828_DCS3, &byte1, &byte2 ); - } - if (ctrx) - { - saudio_setup |= 0x80; - saudio_ctrl |= 0x60; + byte1 = rad->encdec.saudio_setup[rad->encdec.chan]; + mx828_command(rad,rad->encdec.chan, MX828_SAUDIO_SETUP, &byte1, &byte2 ); + rad->encdec.state = 9; + break; + case 9: + byte1 = rad->encdec.saudio_ctrl[rad->encdec.chan]; + mx828_command(rad,rad->encdec.chan, MX828_SAUDIO_CTRL, &byte1, &byte2 ); + rad->encdec.state = 10; + break; + case 10: + rad->encdec.chan = 0; + rad->encdec.state = 0; + break; } - byte1 = saudio_setup; - mx828_command(rad,n, MX828_SAUDIO_SETUP, &byte1, &byte2 ); - byte1 = saudio_ctrl; - mx828_command(rad,n, MX828_SAUDIO_CTRL, &byte1, &byte2 ); - return; } static inline void pciradio_transmitprep(struct pciradio *rad, unsigned char ints) @@ -767,10 +725,15 @@ static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (ints & 0x0f) { rad->intcount++; x = rad->intcount % rad->nchans; - mx828_command(rad, x, MX828_SAUDIO_STATUS, &byte1, &byte2); + /* freeze */ + __pciradio_setcreg(rad,0,rad->mx828_addr | 4); + /* read SAUDIO_STATUS for the proper channel */ + byte1 = __pciradio_getcreg(rad,x); + /* thaw */ + __pciradio_setcreg(rad,0,rad->mx828_addr); rad->saudio_status[x] = byte1; /* get COR input */ - byte2 = __pciradio_getcreg(rad,0); + byte2 = __pciradio_getcreg(rad,9); /* get bit for this channel */ gotcor = byte2 & (1 << x); if (rad->radmode[x] & RADMODE_INVERTCOR) gotcor = !gotcor; @@ -805,18 +768,22 @@ static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs) } else if (gotslowctcss) rad->present_code[x] = (byte1 & RAD_CTCSSMASK) + 1; if (rad->radmode[x] & RADMODE_EXTTONE) { - unsigned mask = 1 << (x + 4); + unsigned mask = 1 << (x + 4); /* they're on the UIOB's */ unsigned char byteuio; + /* set UIOB as input */ + byteuio = __pciradio_getcreg(rad,0xe); + byteuio |= mask; + __pciradio_setcreg(rad,0xe,byteuio); /* get UIO input */ - byteuio = __pciradio_getcreg(rad,1); + byteuio = __pciradio_getcreg(rad,8); if (rad->radmode[x] & RADMODE_EXTINVERT) gotctcss = gotslowctcss = ((byteuio & mask) == 0); else gotctcss = gotslowctcss = ((byteuio & mask) != 0); } rad->gotct[x] = gotslowctcss; - if (rad->radmode[x] & RADMODE_IGNORECT) + if ((rad->radmode[x] & RADMODE_IGNORECT) || (!ctcss)) { gotctcss = 1; gotslowctcss = 1; @@ -830,9 +797,10 @@ static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs) rad->gotrx[x] = gotrx; if (rad->present_code[x] != rad->last_code[x]) { - _set_encdec(rad,x); + rad->encdec.req[x] = 1; rad->last_code[x] = rad->present_code[x]; } + _do_encdec(rad,x); for(x = 0; x < rad->nchans; x++) { unsigned char mask = 1 << x; @@ -842,22 +810,22 @@ static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (rad->gottx[x]) { rad->bursttimer[x] = 0; - rad->p1save |= mask; - __pciradio_setcreg(rad, 1, rad->p1save); + rad->pasave |= mask; + __pciradio_setcreg(rad, 0xa, rad->pasave); } else { if (!rad->bursttime[x]) { - rad->p1save &= ~mask; - __pciradio_setcreg(rad, 1, rad->p1save); + rad->pasave &= ~mask; + __pciradio_setcreg(rad, 0xa, rad->pasave); } else { rad->bursttimer[x] = rad->bursttime[x]; } } - _set_encdec(rad,x); + rad->encdec.req[x] = 1; rad->lasttx[x] = rad->gottx[x]; } if (rad->bursttimer[x]) @@ -867,8 +835,8 @@ static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned char mask = 1 << x; - rad->p1save &= ~mask; - __pciradio_setcreg(rad, 1, rad->p1save); + rad->pasave &= ~mask; + __pciradio_setcreg(rad, 0xa, rad->pasave); } } @@ -881,9 +849,9 @@ static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs) unsigned char mask; mask = 1 << (x + 4); - rad->p1save &= ~mask; - if (gotctcss) rad->p1save |= mask; - __pciradio_setcreg(rad, 1, rad->p1save); + rad->pasave &= ~mask; + if (gotctcss) rad->pasave |= mask; + __pciradio_setcreg(rad, 0xa, rad->pasave); if (rad->gotrx[x] != rad->gotrx1[x]) { @@ -901,7 +869,7 @@ static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (debug) printk("Chan %d lost rx\n",x + 1); zt_qevent_lock(&rad->chans[x], ZT_EVENT_ONHOOK); } - _set_encdec(rad,x); + rad->encdec.req[x] = 1; } rad->gotrx1[x] = rad->gotrx[x]; } @@ -920,13 +888,14 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long { int i,mycode; unsigned long flags; - unsigned char byte1,byte2; + unsigned char byte1,byte2,mask; union { struct zt_radio_stat s; struct zt_radio_param p; } stack; struct pciradio *rad = chan->pvt; + DECLARE_WAIT_QUEUE_HEAD(mywait); switch (cmd) { case ZT_RADIO_GETPARAM: @@ -997,6 +966,21 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long case ZT_RADPAR_BURSTTIME: stack.p.data = rad->bursttime[chan->chanpos - 1]; break; + case ZT_RADPAR_UIODATA: + stack.p.data = 0; + byte1 = __pciradio_getcreg(rad,8); + if (byte1 & (1 << (chan->chanpos - 1))) stack.p.data |= 1; + if (byte1 & (1 << (chan->chanpos + 3))) stack.p.data |= 2; + break; + case ZT_RADPAR_UIOMODE: + stack.p.data = 0; + byte1 = __pciradio_getcreg(rad,0xe); + if (byte1 & (1 << (chan->chanpos - 1))) stack.p.data |= 1; + if (byte1 & (1 << (chan->chanpos + 3))) stack.p.data |= 2; + break; + case ZT_RADPAR_REMMODE: + stack.p.data = rad->remmode[chan->chanpos - 1]; + break; default: spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; @@ -1038,6 +1022,8 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long return -EINVAL; } rad->corthresh[chan->chanpos - 1] = stack.p.data; + byte1 = 0xc0 | (rad->corthresh[chan->chanpos - 1] << 2); + mx828_command_wait(rad,chan->chanpos - 1, MX828_GEN_CTRL, &byte1, &byte2); break; case ZT_RADPAR_EXTRXTONE: if (stack.p.data) @@ -1061,11 +1047,11 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long { /* set to no encode/decode */ byte1 = 0; - mx828_command(rad,chan->chanpos - 1, MX828_SAUDIO_CTRL, &byte1, &byte2 ); + mx828_command_wait(rad,chan->chanpos - 1, MX828_SAUDIO_CTRL, &byte1, &byte2 ); /* set rx tone to none */ byte1 = i << 4; byte2 = 0; - mx828_command(rad,chan->chanpos - 1, MX828_RX_TONE, &byte1, &byte2 ); + mx828_command_wait(rad,chan->chanpos - 1, MX828_RX_TONE, &byte1, &byte2 ); } case ZT_RADPAR_RXTONE: if (!stack.p.index) /* if RX DCS mode */ @@ -1080,7 +1066,7 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long return -EINVAL; } rad->rxcode[chan->chanpos - 1][0] = mycode; - _set_encdec(rad,chan->chanpos - 1); + rad->encdec.req[chan->chanpos - 1] = 1; break; } if ((stack.p.index < 1) || (stack.p.index > NUM_CODES)) { @@ -1095,10 +1081,10 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long rad->rxcode[chan->chanpos - 1][stack.p.index] = mycode; byte1 = cttable_rx[mycode].b1 | ((stack.p.index - 1) << 4); byte2 = cttable_rx[mycode].b2; - mx828_command(rad,chan->chanpos - 1, MX828_RX_TONE, &byte1, &byte2 ); + mx828_command_wait(rad,chan->chanpos - 1, MX828_RX_TONE, &byte1, &byte2 ); /* zot out DCS one if there */ rad->rxcode[chan->chanpos - 1][0] = 0; - _set_encdec(rad,chan->chanpos - 1); + rad->encdec.req[chan->chanpos - 1] = 1; break; case ZT_RADPAR_RXTONECLASS: if ((stack.p.index < 1) || (stack.p.index > NUM_CODES)) { @@ -1122,7 +1108,7 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long } if (stack.p.data & 0x8000) mycode |= 0x8000; rad->txcode[chan->chanpos - 1][stack.p.index] = mycode; - _set_encdec(rad,chan->chanpos - 1); + rad->encdec.req[chan->chanpos - 1] = 1; break; case ZT_RADPAR_DEBOUNCETIME: rad->debouncetime[chan->chanpos - 1] = stack.p.data; @@ -1130,6 +1116,53 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long case ZT_RADPAR_BURSTTIME: rad->bursttime[chan->chanpos - 1] = stack.p.data; break; + case ZT_RADPAR_UIODATA: + spin_lock_irqsave(&rad->lock,flags); + byte1 = __pciradio_getcreg(rad,8); + byte1 &= ~(1 << (chan->chanpos - 1)); + byte1 &= ~(1 << (chan->chanpos + 3)); + if (stack.p.data & 1) byte1 |= (1 << (chan->chanpos - 1)); + if (stack.p.data & 2) byte1 |= (1 << (chan->chanpos + 3)); + __pciradio_setcreg(rad,8,byte1); + spin_unlock_irqrestore(&rad->lock,flags); + break; + case ZT_RADPAR_UIOMODE: + spin_lock_irqsave(&rad->lock,flags); + byte1 = __pciradio_getcreg(rad,0xe); + byte1 &= ~(1 << (chan->chanpos - 1)); + byte1 &= ~(1 << (chan->chanpos + 3)); + if (stack.p.data & 1) byte1 |= (1 << (chan->chanpos - 1)); + if (stack.p.data & 2) byte1 |= (1 << (chan->chanpos + 3)); + __pciradio_setcreg(rad,0xe,byte1); + spin_unlock_irqrestore(&rad->lock,flags); + break; + case ZT_RADPAR_REMMODE: + rad->remmode[chan->chanpos - 1] = stack.p.data; + break; + case ZT_RADPAR_REMCOMMAND: + i = 0; + /* set UIOA and UIOB for output */ + spin_lock_irqsave(&rad->lock,flags); + byte1 = __pciradio_getcreg(rad,0xe); + mask = (1 << (chan->chanpos - 1)) | + (1 << (chan->chanpos + 3)); + byte2 = byte1 & (~mask); + i = (byte2 != byte1); + __pciradio_setcreg(rad,0xe,byte2); + byte1 = __pciradio_getcreg(rad,8); + mask = 1 << (chan->chanpos - 1); + byte2 = byte1 | mask; + i = (byte2 != byte1); + __pciradio_setcreg(rad,8,byte2); + spin_unlock_irqrestore(&rad->lock,flags); + if (i || (jiffies < rad->lastremcmd + 10)) + interruptible_sleep_on_timeout(&mywait,10); + rad->lastremcmd = jiffies; + if (rad->remmode[chan->chanpos - 1]) + { + rbi_out(rad,chan->chanpos - 1,(unsigned char *)&stack.p.data); + } + break; default: spin_unlock_irqrestore(&rad->lock,flags); return -EINVAL; @@ -1243,7 +1276,7 @@ static int pciradio_hooksig(struct zt_chan *chan, zt_txsig_t txsig) break; } if (debug) - printk("pciradio: Setting Radio hook state to %d\n", txsig); + printk("pciradio: Setting Radio hook state to %d on chan %d\n", txsig, chan->chanpos); return 0; } @@ -1280,6 +1313,13 @@ static int pciradio_initialize(struct pciradio *rad) return 0; } +static void wait_just_a_bit(int foo) +{ + long newjiffies; + newjiffies = jiffies + foo; + while(jiffies < newjiffies); +} + static int pciradio_hardware_init(struct pciradio *rad) { unsigned char byte1,byte2; @@ -1367,11 +1407,16 @@ unsigned long endjif; printk("Xilinx Chip successfully loaded, configured and started!!\n"); - rad->p0save = 0xf0; - __pciradio_setcreg(rad,0,rad->p0save); + rad->pasave = 0; + __pciradio_setcreg(rad,0xa,rad->pasave); + + __pciradio_setcreg(rad,8,0); + __pciradio_setcreg(rad,9,0x55); + __pciradio_setcreg(rad,0xe,0); + rad->pfsave = 0; + __pciradio_setcreg(rad,0xf,rad->pfsave); + - rad->p1save = 0; - __pciradio_setcreg(rad,1,rad->p1save); /* Back to normal, with automatic DMA wrap around */ outb(0x30 | 0x01, rad->ioaddr + RAD_CNTL); @@ -1402,20 +1447,20 @@ unsigned long endjif; for(x = 0; x < rad->nchans; x++) { - mx828_command(rad,x, MX828_GEN_RESET, &byte1, &byte2 ); + mx828_command_wait(rad,x, MX828_GEN_RESET, &byte1, &byte2 ); byte1 = 0x3f; byte2 = 0x3f; - mx828_command(rad,x, MX828_AUD_CTRL, &byte1, &byte2 ); + mx828_command_wait(rad,x, MX828_AUD_CTRL, &byte1, &byte2 ); byte1 = 0; - mx828_command(rad,x, MX828_SAUDIO_SETUP, &byte1, &byte2 ); + mx828_command_wait(rad,x, MX828_SAUDIO_SETUP, &byte1, &byte2 ); byte1 = 0; - mx828_command(rad,x, MX828_SAUDIO_CTRL, &byte1, &byte2 ); - byte1 = 0xc0; - mx828_command(rad,x, MX828_GEN_CTRL, &byte1, &byte2); + mx828_command_wait(rad,x, MX828_SAUDIO_CTRL, &byte1, &byte2 ); + byte1 = 0xc8; /* default COR thresh is 2 */ + mx828_command_wait(rad,x, MX828_GEN_CTRL, &byte1, &byte2); + rad->corthresh[x] = 2; } - return 0; } @@ -1489,6 +1534,7 @@ static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_de ifaces[x] = rad; memset(rad, 0, sizeof(struct pciradio)); spin_lock_init(&rad->lock); + spin_lock_init(&rad->rbilock); rad->nchans = 4; rad->ioaddr = pci_resource_start(pdev, 0); rad->dev = pdev; -- cgit v1.2.3