diff options
author | ache <ache@FreeBSD.org> | 1995-06-14 19:37:02 +0000 |
---|---|---|
committer | ache <ache@FreeBSD.org> | 1995-06-14 19:37:02 +0000 |
commit | 38b4136817368a83634c8339861616489175c107 (patch) | |
tree | 9d49653e062061d6e7c358b364d705ed7ad1cbbf /sys/i386/isa/rc.c | |
parent | 27d378a02a571f4c4d2d0056aa5bbe02639f045d (diff) | |
download | FreeBSD-src-38b4136817368a83634c8339861616489175c107.zip FreeBSD-src-38b4136817368a83634c8339861616489175c107.tar.gz |
Next version, many bugs fixed
Diffstat (limited to 'sys/i386/isa/rc.c')
-rw-r--r-- | sys/i386/isa/rc.c | 837 |
1 files changed, 479 insertions, 358 deletions
diff --git a/sys/i386/isa/rc.c b/sys/i386/isa/rc.c index 2892515..8eb0f93 100644 --- a/sys/i386/isa/rc.c +++ b/sys/i386/isa/rc.c @@ -33,7 +33,7 @@ #include "rc.h" #if NRC > 0 -/*#define RCDEBUG */ +/*#define RCDEBUG*/ #include <sys/param.h> #include <sys/systm.h> @@ -74,21 +74,21 @@ int rcioctl __P((dev_t, int, caddr_t, int, struct proc *)); #define rcin(port) RC_IN (nec, port) #define rcout(port,v) RC_OUT (nec, port, v) -/* Counter short for timeouts */ -static volatile int rcnt; +#define WAITFORCCR(u,c) rc_wait0(nec, (u), (c), __LINE__) +#define CCRCMD(u,c,cmd) WAITFORCCR((u), (c)); rcout(CD180_CCR, (cmd)) -#define WAITFORCCR { for (rcnt = 100000; rcin(CD180_CCR) && rcnt; rcnt--) ; } -#define CCRCMD(cmd) WAITFORCCR; rcout(CD180_CCR, cmd) - -#define RC_IBUFSIZE 512 -#define RC_OBUFSIZE 1024 +#define RC_IBUFSIZE 256 +#define RB_I_HIGH_WATER (TTYHOG - 2 * RC_IBUFSIZE) +#define RC_OBUFSIZE 512 #define RC_IHIGHWATER (3 * RC_IBUFSIZE / 4) #define INPUT_FLAGS_SHIFT (2 * RC_IBUFSIZE) #define LOTS_OF_EVENTS 64 -#define RC_TXTIMEO 30 /* 30 seconds wait if intr loss */ #define RC_FAKEID 0x10 +#define RC_PROBED 1 +#define RC_ATTACHED 2 + #define GET_UNIT(dev) (minor(dev) & 0x3F) #define CALLOUT(dev) (minor(dev) & 0x80) @@ -99,7 +99,7 @@ struct isa_driver rcdriver = { /* Per-board structure */ static struct rc_softc { - u_int rcb_probed; /* 1 if device probed */ + u_int rcb_probed; /* 1 - probed, 2 - attached */ u_int rcb_addr; /* Base I/O addr */ u_int rcb_unit; /* unit # */ u_char rcb_dtr; /* DTR status */ @@ -116,7 +116,6 @@ static struct rc_chans { u_char rc_cor2; /* options reg */ u_char rc_pendcmd; /* special cmd pending */ u_int rc_dtrwait; /* dtr timeout */ - long rc_txitime; /* time of last TX intr */ u_int rc_dcdwaits; /* how many waits DCD in open */ u_char rc_hotchar; /* end packed optimize */ struct tty *rc_tp; /* tty struct */ @@ -124,7 +123,6 @@ static struct rc_chans { u_char *rc_hiwat; /* hi-water mark */ u_char *rc_bufend; /* end of buffer */ u_char *rc_optr; /* ptr in output buf */ - u_char rc_ocnt; u_char *rc_obufend; /* end of output buf */ u_char rc_ibuf[4 * RC_IBUFSIZE]; /* input buffer */ u_char rc_obuf[RC_OBUFSIZE]; /* output buffer */ @@ -137,18 +135,18 @@ struct tty rc_tty[NRC * CD180_NCHAN]; int nrc_tty = NRC * CD180_NCHAN; /* Flags */ -#define RC_DTR_OFF 000001 /* DTR wait, for close/open */ -#define RC_ACTOUT 000002 /* Dial-out port active */ -#define RC_RTSFLOW 000004 /* RTS flow ctl enabled */ -#define RC_CTSFLOW 000010 /* CTS flow ctl enabled */ -#define RC_DORXFER 000020 /* RXFER event planned */ -#define RC_DOXXFER 000040 /* RXFER event planned */ -#define RC_MODCHG 000100 /* Modem status changed */ -#define RC_OSUSP 000200 /* Output suspended */ -#define RC_OSBUSY 000400 /* start() routine in progress */ -#define RC_WAS_BUFOVFL 001000 /* low-level buffer ovferflow */ -#define RC_WAS_SILOVFL 002000 /* silo buffer overflow */ -#define RC_SEND_RDY 004000 /* ready to send */ +#define RC_DTR_OFF 0x0001 /* DTR wait, for close/open */ +#define RC_ACTOUT 0x0002 /* Dial-out port active */ +#define RC_RTSFLOW 0x0004 /* RTS flow ctl enabled */ +#define RC_CTSFLOW 0x0008 /* CTS flow ctl enabled */ +#define RC_DORXFER 0x0010 /* RXFER event planned */ +#define RC_DOXXFER 0x0020 /* XXFER event planned */ +#define RC_MODCHG 0x0040 /* Modem status changed */ +#define RC_OSUSP 0x0080 /* Output suspended */ +#define RC_OSBUSY 0x0100 /* start() routine in progress */ +#define RC_WAS_BUFOVFL 0x0200 /* low-level buffer ovferflow */ +#define RC_WAS_SILOVFL 0x0400 /* silo buffer overflow */ +#define RC_SEND_RDY 0x0800 /* ready to send */ static struct speedtab rc_speedtab[] = { 0, 0, @@ -183,7 +181,7 @@ static int rc_rcsrt[16] = { }; /* Static prototypes */ -static void rc_hwreset __P((int, unsigned int)); +static void rc_hwreset __P((int, int, unsigned int)); static int rc_test __P((int, int)); static void rc_discard_output __P((struct rc_chans *)); static void rc_hardclose __P((struct rc_chans *)); @@ -191,9 +189,14 @@ static int rc_modctl __P((struct rc_chans *, int, int)); static void rc_start __P((struct tty *)); static int rc_param __P((struct tty *, struct termios *)); static void rc_registerdev __P((struct isa_device *id)); +static void rc_reinit __P((struct rc_softc *)); +#ifdef RCDEBUG +static void printrcflags(); +#endif static timeout_t rc_dtrwakeup; static timeout_t rc_wakeup; static void disc_optim __P((struct tty *tp, struct termios *t, struct rc_chans *)); +static void rc_wait0 __P((int nec, int unit, int chan, int line)); /**********************************************/ @@ -206,7 +209,6 @@ int rcprobe(dvp) if (dvp->id_unit > NRC) return 0; - rc_softc[dvp->id_unit].rcb_probed = 0; if (!RC_VALIDADDR(nec)) { printf("rc%d: illegal base address %x\n", nec); return 0; @@ -222,8 +224,9 @@ int rcprobe(dvp) /* Now, test the board more thoroughly, with diagnostic */ if (rc_test(nec, dvp->id_unit)) return 0; - rc_softc[dvp->id_unit].rcb_probed = 1; - return 1; + rc_softc[dvp->id_unit].rcb_probed = RC_PROBED; + + return 0xF; } static struct kern_devconf kdc_rc[NRC] = { { @@ -252,7 +255,6 @@ rc_registerdev(id) dev_attach(&kdc_rc[unit]); } -/* Test device, then attach */ int rcattach(dvp) struct isa_device *dvp; { @@ -260,9 +262,10 @@ int rcattach(dvp) struct rc_softc *rcb = &rc_softc[dvp->id_unit]; struct rc_chans *rc = &rc_chans[dvp->id_unit * CD180_NCHAN]; static int rc_wakeup_started = 0; + struct tty *tp; /* Thorooughly test the device */ - if (!rcb->rcb_probed) + if (rcb->rcb_probed != RC_PROBED) return 0; rcb->rcb_addr = nec; rcb->rcb_dtr = 0; @@ -282,12 +285,16 @@ int rcattach(dvp) rc->rc_flags = rc->rc_ier = rc->rc_msvr = 0; rc->rc_cor2 = rc->rc_pendcmd = 0; rc->rc_optr = rc->rc_obufend = rc->rc_obuf; - rc->rc_txitime = (~0UL >> 1); rc->rc_dtrwait = 3 * hz; - rc->rc_ocnt = 0; rc->rc_dcdwaits= 0; rc->rc_hotchar = 0; + tp = rc->rc_tp = &rc_tty[chan]; + ttychars(tp); + tp->t_lflag = tp->t_iflag = tp->t_oflag = 0; + tp->t_cflag = TTYDEF_CFLAG; + tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; } + rcb->rcb_probed = RC_ATTACHED; if (!rc_wakeup_started) { rc_wakeup((void *)NULL); rc_wakeup_started = 0; @@ -301,192 +308,214 @@ void rcintr(unit) { register struct rc_softc *rcb = &rc_softc[unit]; register struct rc_chans *rc; - register u_char val; - register u_int nec, bsr, iack, ucnt; - int good_data, resid; + register int nec, resid; + register u_char val, iack, bsr, ucnt, *optr; + int good_data, t_state; + if (rcb->rcb_probed != RC_ATTACHED) { + printf("rc%d: bogus interrupt\n", unit); + return; + } nec = rcb->rcb_addr; -possibly_more_intrs: bsr = ~(rcin(RC_BSR)); -#ifdef RCDEBUG - printf("rcintr: %d (%02x) %s %s %s %s\n", unit, bsr, - (bsr & RC_BSR_TOUT)?"TOUT":"", - (bsr & RC_BSR_RXINT)?"RXINT":"", - (bsr & RC_BSR_TXINT)?"TXINT":"", - (bsr & RC_BSR_MOINT)?"MOINT":""); -#endif - if (bsr & RC_BSR_RXINT) { - iack = rcin(RC_PILR_RX); -#ifdef RCDEBUG - printf("rxint iack = %02x\n", iack); -#endif - rc = rcb->rcb_baserc + (rcin(CD180_GICR) >> GICR_LSH); - ucnt = rcin(CD180_RDCR); - resid = 0; - good_data = (iack == (GIVR_IT_RGDI | RC_FAKEID)); -#ifdef RCDEBUG - printrcflags(rc, "rxint"); + if (!(bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT))) { + printf("rc%d: extra interrupt\n", unit); + rcout(CD180_EOIR, 0); + return; + } + + while (bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT)) { +#ifdef RCDEBUG_DETAILED + printf("rc%d: intr (%02x) %s%s%s%s\n", unit, bsr, + (bsr & RC_BSR_TOUT)?"TOUT ":"", + (bsr & RC_BSR_RXINT)?"RXINT ":"", + (bsr & RC_BSR_TXINT)?"TXINT ":"", + (bsr & RC_BSR_MOINT)?"MOINT":""); #endif - /* Do RTS flow control stuff */ - if ( (rc->rc_flags & RC_RTSFLOW) - || !rc->rc_tp - || !(rc->rc_tp->t_state & TS_ISOPEN)) { - if ( (!rc->rc_tp - || !(rc->rc_tp->t_state & TS_ISOPEN) - || (rc->rc_tp->t_state & TS_TBLOCK)) - && (rc->rc_msvr & MSVR_RTS)) - rcout(CD180_MSVR, - rc->rc_msvr &= ~MSVR_RTS); - else if (!(rc->rc_msvr & MSVR_RTS)) - rcout(CD180_MSVR, - rc->rc_msvr |= MSVR_RTS); + if (bsr & RC_BSR_TOUT) { + printf("rc%d: hardware failure, reset board\n", unit); + rcout(RC_CTOUT, 0); + rc_reinit(rcb); + return; } - - if (rc->rc_tp && (rc->rc_tp->t_state & TS_ISOPEN)) { - /* check for input buffer overflow */ - if ((rc->rc_iptr + ucnt) >= rc->rc_bufend) { - resid = ucnt; - ucnt = rc->rc_bufend - rc->rc_iptr; - resid -= ucnt; - if (!(rc->rc_flags & RC_WAS_BUFOVFL)) { - rc->rc_flags |= RC_WAS_BUFOVFL; - rc_scheduled_event++; - } + if (bsr & RC_BSR_RXINT) { + iack = rcin(RC_PILR_RX); + good_data = (iack == (GIVR_IT_RGDI | RC_FAKEID)); + if (!good_data && iack != (GIVR_IT_REI | RC_FAKEID)) { + printf("rc%d: fake rxint: %02x\n", unit, iack); + goto more_intrs; } - /* check foor good data */ - if (good_data) { - while (ucnt-- > 0) { - val = rcin(CD180_RDR); - rc->rc_iptr[0] = val; - rc->rc_iptr[INPUT_FLAGS_SHIFT] = 0; - rc->rc_iptr++; - rc_scheduled_event++; - if (rc->rc_hotchar != 0 && val == rc->rc_hotchar) - setsofttty(); - } - } else { - /* Store also status data */ - while (ucnt-- > 0) { - iack = rcin(CD180_RCSR); - if (iack & RCSR_TOUT) { - (void) rcin(CD180_RDR); - break; - } - if ( (iack & RCSR_OE) - && !(rc->rc_flags & RC_WAS_SILOVFL)) { - rc->rc_flags |= RC_WAS_SILOVFL; + rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH); + t_state = rc->rc_tp->t_state; + /* Do RTS flow control stuff */ + if ( (rc->rc_flags & RC_RTSFLOW) + || !(t_state & TS_ISOPEN) + ) { + if ( ( !(t_state & TS_ISOPEN) + || (t_state & TS_TBLOCK) + ) + && (rc->rc_msvr & MSVR_RTS) + ) + rcout(CD180_MSVR, + rc->rc_msvr &= ~MSVR_RTS); + else if (!(rc->rc_msvr & MSVR_RTS)) + rcout(CD180_MSVR, + rc->rc_msvr |= MSVR_RTS); + } + ucnt = rcin(CD180_RDCR) & 0xF; + resid = 0; + + if (t_state & TS_ISOPEN) { + /* check for input buffer overflow */ + if ((rc->rc_iptr + ucnt) >= rc->rc_bufend) { + resid = ucnt; + ucnt = rc->rc_bufend - rc->rc_iptr; + resid -= ucnt; + if (!(rc->rc_flags & RC_WAS_BUFOVFL)) { + rc->rc_flags |= RC_WAS_BUFOVFL; rc_scheduled_event++; } - val = rcin(CD180_RDR); - /* - Don't store PE if IGNPAR and BREAK if IGNBRK, - this hack allows "raw" tty optimization - works even if IGN* is set. - */ - if ( !(iack & (RCSR_PE|RCSR_FE|RCSR_BREAK)) - || (!(iack & (RCSR_PE|RCSR_FE)) - || !(rc->rc_tp->t_iflag & IGNPAR)) - && (!(iack & RCSR_BREAK) - || !(rc->rc_tp->t_iflag & IGNBRK))) { - if ( (iack & (RCSR_PE|RCSR_FE)) - && (rc->rc_tp->t_state & TS_CAN_BYPASS_L_RINT) - && ((iack & RCSR_FE) - || (iack & RCSR_PE) - && (rc->rc_tp->t_iflag & INPCK))) - val = 0; - else if (rc->rc_hotchar != 0 && val == rc->rc_hotchar) - setsofttty(); - rc->rc_iptr[0] = val; - rc->rc_iptr[INPUT_FLAGS_SHIFT] = iack; - rc->rc_iptr++; + } + optr = rc->rc_iptr; + /* check foor good data */ + if (good_data) { + while (ucnt-- > 0) { + val = rcin(CD180_RDR); + optr[0] = val; + optr[INPUT_FLAGS_SHIFT] = 0; + optr++; rc_scheduled_event++; + if (val != 0 && val == rc->rc_hotchar) + setsofttty(); + } + } else { + /* Store also status data */ + while (ucnt-- > 0) { + iack = rcin(CD180_RCSR); + if (iack & RCSR_Timeout) + break; + if ( (iack & RCSR_OE) + && !(rc->rc_flags & RC_WAS_SILOVFL)) { + rc->rc_flags |= RC_WAS_SILOVFL; + rc_scheduled_event++; + } + val = rcin(CD180_RDR); + /* + Don't store PE if IGNPAR and BREAK if IGNBRK, + this hack allows "raw" tty optimization + works even if IGN* is set. + */ + if ( !(iack & (RCSR_PE|RCSR_FE|RCSR_Break)) + || (!(iack & (RCSR_PE|RCSR_FE)) + || !(rc->rc_tp->t_iflag & IGNPAR)) + && (!(iack & RCSR_Break) + || !(rc->rc_tp->t_iflag & IGNBRK))) { + if ( (iack & (RCSR_PE|RCSR_FE)) + && (t_state & TS_CAN_BYPASS_L_RINT) + && ((iack & RCSR_FE) + || (iack & RCSR_PE) + && (rc->rc_tp->t_iflag & INPCK))) + val = 0; + else if (val != 0 && val == rc->rc_hotchar) + setsofttty(); + optr[0] = val; + optr[INPUT_FLAGS_SHIFT] = iack; + optr++; + rc_scheduled_event++; + } } } + rc->rc_iptr = optr; + rc->rc_flags |= RC_DORXFER; + } else + resid = ucnt; + /* Clear FIFO if necessary */ + while (resid-- > 0) { + if (!good_data) + iack = rcin(CD180_RCSR); + else + iack = 0; + if (iack & RCSR_Timeout) + break; + (void) rcin(CD180_RDR); } - rc->rc_flags |= RC_DORXFER; - } else - resid = ucnt; - /* Clear FIFO if necessary */ - while (resid-- > 0) { - if (!good_data) - iack = rcin(CD180_RCSR); - else - iack = 0; - (void) rcin(CD180_RDR); - if (iack & RCSR_TOUT) - break; + goto more_intrs; } - rcout(CD180_EOIR, 0); - goto possibly_more_intrs; - } - if (bsr & RC_BSR_MOINT) { - iack = rcin(CD180_MCR); - rc = rcb->rcb_baserc + (rcin(CD180_GICR) >> GICR_LSH); + if (bsr & RC_BSR_MOINT) { + iack = rcin(RC_PILR_MODEM); + if (iack != (GIVR_IT_MSCI | RC_FAKEID)) { + printf("rc%d: fake moint: %02x\n", unit, iack); + goto more_intrs; + } + rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH); + iack = rcin(CD180_MCR); + rc->rc_msvr = rcin(CD180_MSVR); + rcout(CD180_MCR, 0); #ifdef RCDEBUG - printrcflags(rc, "moint"); + printrcflags(rc, "moint"); #endif - rc->rc_msvr = rcin(CD180_MSVR); - if (rc->rc_flags & RC_CTSFLOW) { - if (rc->rc_msvr & MSVR_CTS) + if (rc->rc_flags & RC_CTSFLOW) { + if (rc->rc_msvr & MSVR_CTS) + rc->rc_flags |= RC_SEND_RDY; + else + rc->rc_flags &= ~RC_SEND_RDY; + } else rc->rc_flags |= RC_SEND_RDY; - else - rc->rc_flags &= ~RC_SEND_RDY; - } - if (iack & MCR_CDCHG) { - rc->rc_flags |= RC_MODCHG; - rc_scheduled_event += LOTS_OF_EVENTS; - setsofttty(); - } - rcout(CD180_EOIR, 0); - goto possibly_more_intrs; - } - if (bsr & RC_BSR_TXINT) { - rc = rcb->rcb_baserc + (rcin(CD180_GICR) >> GICR_LSH); - rc->rc_txitime = time.tv_sec; -#ifdef RCDEBUG - printrcflags(rc, "txint"); -#endif - if ( (rc->rc_flags & RC_OSUSP) - || !(rc->rc_flags & RC_SEND_RDY)) - goto skip; - ucnt = rc->rc_obufend - rc->rc_optr; - if (ucnt > CD180_NFIFO) - ucnt = CD180_NFIFO; - /* Handle breaks and other stuff */ - if (rc->rc_pendcmd) { - rcout(CD180_COR2, rc->rc_cor2 |= COR2_ETC); - rcout(CD180_TDR, CD180_C_ESC); - rcout(CD180_TDR, rc->rc_pendcmd); - rcout(CD180_COR2, rc->rc_cor2 &= ~COR2_ETC); - rc->rc_pendcmd = 0; - rcout(CD180_EOIR, 0); - goto possibly_more_intrs; + if ((iack & MCR_CDchg) && !(rc->rc_flags & RC_MODCHG)) { + rc_scheduled_event += LOTS_OF_EVENTS; + rc->rc_flags |= RC_MODCHG; + setsofttty(); + } + goto more_intrs; } - while (ucnt-- > 0) - rcout(CD180_TDR, *rc->rc_optr++); - - /* output completed? */ - if (rc->rc_optr >= rc->rc_obufend) { - rcout(CD180_IER, rc->rc_ier &= - ~(IER_TXRDY|IER_TXMPTY)); + if (bsr & RC_BSR_TXINT) { + iack = rcin(RC_PILR_TX); + if (iack != (GIVR_IT_TDI | RC_FAKEID)) { + printf("rc%d: fake txint: %02x\n", unit, iack); + goto more_intrs; + } + rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH); + if ( (rc->rc_flags & RC_OSUSP) + || !(rc->rc_flags & RC_SEND_RDY) + ) + goto more_intrs; + /* Handle breaks and other stuff */ + if (rc->rc_pendcmd) { + rcout(CD180_COR2, rc->rc_cor2 |= COR2_ETC); + rcout(CD180_TDR, CD180_C_ESC); + rcout(CD180_TDR, rc->rc_pendcmd); + rcout(CD180_COR2, rc->rc_cor2 &= ~COR2_ETC); + rc->rc_pendcmd = 0; + goto more_intrs; + } + optr = rc->rc_optr; + resid = rc->rc_obufend - optr; + if (resid > CD180_NFIFO) + resid = CD180_NFIFO; + while (resid-- > 0) + rcout(CD180_TDR, *optr++); + rc->rc_optr = optr; + + /* output completed? */ + if (optr >= rc->rc_obufend) { + rcout(CD180_IER, rc->rc_ier &= ~IER_TxRdy); #ifdef RCDEBUG - printf("tx intr disabled\n"); + printf("rc%d/%d: output completed\n", unit, rc->rc_chan); #endif - rc->rc_flags |= RC_DOXXFER; - rc_scheduled_event += LOTS_OF_EVENTS; - setsofttty(); + if (!(rc->rc_flags & RC_DOXXFER)) { + rc_scheduled_event += LOTS_OF_EVENTS; + rc->rc_flags |= RC_DOXXFER; + setsofttty(); + } + } } - skip: - rcout(CD180_EOIR, 0); - goto possibly_more_intrs; + more_intrs: + rcout(CD180_EOIR, 0); /* end of interrupt */ + rcout(RC_CTOUT, 0); + bsr = ~(rcin(RC_BSR)); } - rcout(RC_BSR, 0); /* -/- */ -#ifdef RCDEBUG - if (rc_scheduled_event) - printf("event scheduled unit %d\n", unit); -#endif } /* Feed characters to output buffer */ @@ -506,17 +535,15 @@ register struct tty *tp; else rc->rc_flags &= ~RC_OSUSP; /* Do RTS flow control stuff */ - if (rc->rc_flags & RC_RTSFLOW) { - if ((tp->t_state & TS_TBLOCK) && - (rc->rc_msvr & MSVR_RTS)) { - rcout(CD180_CAR, rc->rc_chan); - rcout(CD180_MSVR, - rc->rc_msvr &= ~MSVR_RTS); - } else if (!(rc->rc_msvr & MSVR_RTS)) { - rcout(CD180_CAR, rc->rc_chan); - rcout(CD180_MSVR, - rc->rc_msvr |= MSVR_RTS); - } + if ( (rc->rc_flags & RC_RTSFLOW) + && (tp->t_state & TS_TBLOCK) + && (rc->rc_msvr & MSVR_RTS) + ) { + rcout(CD180_CAR, rc->rc_chan); + rcout(CD180_MSVR, rc->rc_msvr &= ~MSVR_RTS); + } else if (!(rc->rc_msvr & MSVR_RTS)) { + rcout(CD180_CAR, rc->rc_chan); + rcout(CD180_MSVR, rc->rc_msvr |= MSVR_RTS); } enable_intr(); if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) @@ -524,17 +551,6 @@ register struct tty *tp; #ifdef RCDEBUG printrcflags(rc, "rcstart"); #endif - /* Checking for stale tx intrs */ - if ((rc->rc_ier & IER_TXRDY) && - (rc->rc_txitime - time.tv_sec) > RC_TXTIMEO) { - rc->rc_txitime = time.tv_sec; - printf("rc%d: chan %d: lost TX intr, reinit\n", - rc->rc_rcb->rcb_unit, rc->rc_chan); - /* try to re-initialize channel */ - rcout(CD180_CAR, rc->rc_chan); - CCRCMD(CCR_RESETCHAN); - (void) rc_param(rc->rc_tp, &rc->rc_tp->t_termios); - } if (tp->t_outq.c_cc <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; @@ -543,11 +559,10 @@ register struct tty *tp; selwakeup(&tp->t_wsel); } #ifdef RCDEBUG - printf("rcstart: q = %d olen = %d\n", + printf("rcstart: outq = %d obuf = %d\n", tp->t_outq.c_cc, rc->rc_obufend - rc->rc_optr); #endif - /* maybe we need to check for lost intrs here */ - if (rc->rc_optr < rc->rc_obufend) + if (tp->t_state & TS_BUSY) goto out; /* output still in progress ... */ if (tp->t_outq.c_cc > 0) { @@ -556,20 +571,16 @@ register struct tty *tp; tp->t_state |= TS_BUSY; ocnt = q_to_b(&tp->t_outq, rc->rc_obuf, sizeof rc->rc_obuf); disable_intr(); - rc->rc_ocnt = ocnt; rc->rc_optr = rc->rc_obuf; - rc->rc_obufend = rc->rc_optr + rc->rc_ocnt; + rc->rc_obufend = rc->rc_optr + ocnt; enable_intr(); - if ((rc->rc_ier & IER_TXRDY) == 0) { + if (!(rc->rc_ier & IER_TxRdy)) { #ifdef RCDEBUG - printf("rcstart: enable txint\n"); + printf("rc%d/%d: rcstart enable txint\n", rc->rc_rcb->rcb_unit, rc->rc_chan); #endif rcout(CD180_CAR, rc->rc_chan); - rcout(CD180_IER, rc->rc_ier |= IER_TXRDY); + rcout(CD180_IER, rc->rc_ier |= IER_TxRdy); } - } else { - rc->rc_ocnt = 0; - tp->t_flags &= ~TS_BUSY; } out: rc->rc_flags &= ~RC_OSBUSY; @@ -601,27 +612,31 @@ repeat: printrcflags(rc, "rcevent"); #endif if (rc->rc_flags & RC_WAS_BUFOVFL) { + disable_intr(); rc->rc_flags &= ~RC_WAS_BUFOVFL; rc_scheduled_event--; + enable_intr(); printf("rc%d/%d: interrupt-level buffer overflow\n", unit, chan); } if (rc->rc_flags & RC_WAS_SILOVFL) { + disable_intr(); rc->rc_flags &= ~RC_WAS_SILOVFL; rc_scheduled_event--; + enable_intr(); printf("rc%d/%d: silo overflow\n", unit, chan); } if (rc->rc_flags & RC_MODCHG) { + disable_intr(); rc->rc_flags &= ~RC_MODCHG; rc_scheduled_event -= LOTS_OF_EVENTS; - if (tp) - (*linesw[tp->t_line].l_modem)(tp, !!(rc->rc_msvr & MSVR_CD)); + enable_intr(); + (*linesw[tp->t_line].l_modem)(tp, !!(rc->rc_msvr & MSVR_CD)); } if (rc->rc_flags & RC_DORXFER) { - rc->rc_flags &= ~RC_DORXFER; - disable_intr(); + rc->rc_flags &= ~RC_DORXFER; eptr = rc->rc_iptr; if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) tptr = &rc->rc_ibuf[RC_IBUFSIZE]; @@ -639,11 +654,11 @@ repeat: rc->rc_hiwat = &rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER]; } - if ((rc->rc_flags & RC_RTSFLOW) - && !(rc->rc_msvr & MSVR_RTS) - && tp != NULL + if ( (rc->rc_flags & RC_RTSFLOW) && (tp->t_state & TS_ISOPEN) - && !(tp->t_state & TS_TBLOCK)) { + && !(tp->t_state & TS_TBLOCK) + && !(rc->rc_msvr & MSVR_RTS) + ) { rcout(CD180_CAR, chan); rcout(CD180_MSVR, rc->rc_msvr |= MSVR_RTS); @@ -652,13 +667,13 @@ repeat: } enable_intr(); - if (icnt <= 0 || !tp || !(tp->t_state & TS_ISOPEN)) + if (icnt <= 0 || !(tp->t_state & TS_ISOPEN)) goto done1; if ( linesw[tp->t_line].l_rint == ttyinput && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF)) && !(tp->t_state & TS_TBLOCK) - && (tp->t_rawq.c_cc + icnt) > RC_IHIGHWATER) { + && (tp->t_rawq.c_cc + icnt) > RB_I_HIGH_WATER) { int queue_full = 0; if ((tp->t_iflag & IXOFF) && @@ -695,7 +710,11 @@ repeat: done1: } if (rc->rc_flags & RC_DOXXFER) { - rc_discard_output(rc); + disable_intr(); + rc_scheduled_event -= LOTS_OF_EVENTS; + rc->rc_flags &= ~RC_DOXXFER; + rc->rc_tp->t_state &= ~TS_BUSY; + enable_intr(); (*linesw[tp->t_line].l_start)(tp); } } @@ -714,13 +733,14 @@ void rcstop(tp, rw) u_char *tptr, *eptr; #ifdef RCDEBUG - printf("rcstop %d/%d: %s%s\n", rc->rc_rcb->rcb_unit, rc->rc_chan, + printf("rc%d/%d: rcstop %s%s\n", rc->rc_rcb->rcb_unit, rc->rc_chan, (rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":""); #endif if (rw & FWRITE) rc_discard_output(rc); disable_intr(); if (rw & FREAD) { + rc->rc_flags &= ~RC_DORXFER; eptr = rc->rc_iptr; if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { tptr = &rc->rc_ibuf[RC_IBUFSIZE]; @@ -750,17 +770,19 @@ int rcopen(dev, flag, mode, p) unit = GET_UNIT(dev); if (unit >= NRC * CD180_NCHAN) return ENXIO; + if (rc_softc[unit / CD180_NCHAN].rcb_probed != RC_ATTACHED) + return ENXIO; rc = &rc_chans[unit]; - tp = rc->rc_tp = &rc_tty[unit]; + tp = rc->rc_tp; nec = rc->rc_rcb->rcb_addr; #ifdef RCDEBUG - printf("rcopen: dev %02x\n", dev); + printf("rc%d/%d: rcopen: dev %x\n", rc->rc_rcb->rcb_unit, unit, dev); #endif s = spltty(); again: while (rc->rc_flags & RC_DTR_OFF) { - error = tsleep(&rc->rc_dtrwait, TTIPRI | PCATCH, "rcdtr", 0); + error = tsleep(&(rc->rc_dtrwait), TTIPRI | PCATCH, "rcdtr", 0); if (error != 0) goto out; } @@ -791,31 +813,18 @@ again: tp->t_param = rc_param; tp->t_dev = dev; - if (tp->t_ispeed == 0) { - ttychars(tp); - tp->t_lflag = tp->t_iflag = tp->t_oflag = 0; - tp->t_cflag = TTYDEF_CFLAG; - tp->t_ispeed = tp->t_ospeed = 9600; - } if (CALLOUT(dev)) tp->t_cflag |= CLOCAL; else tp->t_cflag &= ~CLOCAL; - (void) rc_modctl(rc, TIOCM_DTR|TIOCM_RTS, DMSET); - error = rc_param(tp, &tp->t_termios); if (error) goto out; + (void) rc_modctl(rc, TIOCM_RTS|TIOCM_DTR, DMSET); ttsetwater(tp); - disable_intr(); - rcout(CD180_CAR, rc->rc_chan); - rc->rc_msvr = rcin(CD180_MSVR); - rcout(CD180_IER, rc->rc_ier |= IER_CD | IER_TXRDY | IER_RXD); - enable_intr(); - if ((rc->rc_msvr & MSVR_CD) || CALLOUT(dev)) (*linesw[tp->t_line].l_modem)(tp, 1); } @@ -853,6 +862,9 @@ int rcclose(dev, flag, mode, p) return ENXIO; rc = &rc_chans[unit]; tp = rc->rc_tp; +#ifdef RCDEBUG + printf("rc%d/%d: rcclose dev %x\n", rc->rc_rcb->rcb_unit, unit, dev); +#endif s = spltty(); (*linesw[tp->t_line].l_close)(tp, flag); rcstop(tp, FREAD | FWRITE); @@ -871,13 +883,16 @@ register struct rc_chans *rc; s = spltty(); rcout(CD180_CAR, rc->rc_chan); - /* Disable all intrs */ + /* Disable rx/tx intrs */ rcout(CD180_IER, rc->rc_ier = 0); - if ( tp->t_cflag & HUPCL + if ( (tp->t_cflag & HUPCL) || !(rc->rc_flags & RC_ACTOUT) && !(rc->rc_msvr & MSVR_CD) && !(tp->t_cflag & CLOCAL) - || !(tp->t_state & TS_ISOPEN)) { + || !(tp->t_state & TS_ISOPEN) + ) { + CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan); + WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan); (void) rc_modctl(rc, TIOCM_RTS, DMSET); if (rc->rc_dtrwait) { timeout(rc_dtrwakeup, rc, rc->rc_dtrwait); @@ -897,6 +912,7 @@ int rcread(dev, uio, flag) int flag; { struct tty *tp = rc_chans[GET_UNIT(dev)].rc_tp; + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); } @@ -907,23 +923,26 @@ int rcwrite(dev, uio, flag) int flag; { struct tty *tp = rc_chans[GET_UNIT(dev)].rc_tp; + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); } /* Reset the bastard */ -static void rc_hwreset(nec, chipid) - register int nec; +static void rc_hwreset(unit, nec, chipid) + register int unit, nec; unsigned int chipid; { - CCRCMD(CCR_HWRESET); /* Hardware reset */ + CCRCMD(unit, -1, CCR_HWRESET); /* Hardware reset */ DELAY(20000); - rcout(RC_BSR_TOUT, 0); /* Clear timeout */ + WAITFORCCR(unit, -1); + + rcout(RC_CTOUT, 0); /* Clear timeout */ rcout(CD180_GIVR, chipid); rcout(CD180_GICR, 0); /* Set Prescaler Registers (1 msec) */ - rcout(CD180_PPRL, (RC_OSCFREQ / 1000) & 0xFF); - rcout(CD180_PPRH, (RC_OSCFREQ / 1000) >> 8); + rcout(CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF); + rcout(CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8); /* Initialize Priority Interrupt Level Registers */ rcout(CD180_PILR1, RC_PILR_MODEM); @@ -931,7 +950,7 @@ static void rc_hwreset(nec, chipid) rcout(CD180_PILR3, RC_PILR_RX); /* Reset DTR */ - rcout(RC_DTR, ~0); + rcout(RC_DTREG, ~0); } /* Set channel parameters */ @@ -939,9 +958,9 @@ static int rc_param(tp, ts) register struct tty *tp; struct termios *ts; { - register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)]; + register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)]; register int nec = rc->rc_rcb->rcb_addr; - int idivs, odivs, s, val, cflag, iflag, lflag; + int idivs, odivs, s, val, cflag, iflag, lflag, inpflow; odivs = ttspeedtab(ts->c_ospeed, rc_speedtab); if (ts->c_ispeed == 0) @@ -952,20 +971,21 @@ static int rc_param(tp, ts) s = spltty(); + /* Select channel */ + rcout(CD180_CAR, rc->rc_chan); + /* If speed == 0, hangup line */ - if (ts->c_ospeed == 0) - rc_modctl(rc, TIOCM_DTR, DMBIC); - else - rc_modctl(rc, TIOCM_RTS|TIOCM_DTR, DMBIS); + if (ts->c_ospeed == 0) { + CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan); + WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan); + (void) rc_modctl(rc, TIOCM_DTR, DMBIC); + } tp->t_state &= ~TS_CAN_BYPASS_L_RINT; cflag = ts->c_cflag; iflag = ts->c_iflag; lflag = ts->c_lflag; - /* Select channel */ - rcout(CD180_CAR, rc->rc_chan); - if (idivs > 0) { rcout(CD180_RBPRL, idivs & 0xFF); rcout(CD180_RBPRH, idivs >> 8); @@ -976,7 +996,16 @@ static int rc_param(tp, ts) } /* set timeout value */ - rcout(CD180_RTPR, 0); + if (ts->c_ispeed > 0) { + int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1; + + if ( !(lflag & ICANON) + && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0 + && ts->c_cc[VTIME] * 10 > itm) + itm = ts->c_cc[VTIME] * 10; + + rcout(CD180_RTPR, itm <= 255 ? itm : 255); + } switch (cflag & CSIZE) { case CS5: val = COR1_5BITS; break; @@ -989,62 +1018,109 @@ static int rc_param(tp, ts) val |= COR1_NORMPAR; if (cflag & PARODD) val |= COR1_ODDP; + if (!(cflag & INPCK)) + val |= COR1_Ignore; } else - val |= COR1_IGNORE; + val |= COR1_Ignore; if (cflag & CSTOPB) val |= COR1_2SB; rcout(CD180_COR1, val); /* Set FIFO threshold */ - rcout(CD180_COR3, ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2); - CCRCMD(CCR_CORCHG1 | CCR_CORCHG3); + val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2; + inpflow = 0; + if ( (iflag & IXOFF) + && ( ts->c_cc[VSTOP] != _POSIX_VDISABLE + && ( ts->c_cc[VSTART] != _POSIX_VDISABLE + || (iflag & IXANY) + ) + ) + ) { + inpflow = 1; + val |= COR3_SCDE|COR3_FCT; + } + rcout(CD180_COR3, val); /* Initialize on-chip automatic flow control */ val = 0; - + rc->rc_flags &= ~(RC_CTSFLOW|RC_SEND_RDY); if (cflag & CCTS_OFLOW) { rc->rc_flags |= RC_CTSFLOW; - val |= COR2_CTSAE; - rc->rc_msvr = rcin(CD180_MSVR); - if (rc->rc_msvr & MSVR_CTS) - rc->rc_flags |= RC_SEND_RDY; - else - rc->rc_flags &= ~RC_SEND_RDY; - } - else + val |= COR2_CtsAE; + } else rc->rc_flags |= RC_SEND_RDY; - + if (tp->t_state & TS_TTSTOP) + rc->rc_flags |= RC_OSUSP; + else + rc->rc_flags &= ~RC_OSUSP; if (cflag & CRTS_IFLOW) rc->rc_flags |= RC_RTSFLOW; - - if (iflag & (IXON|IXOFF)) { - /* Initailize xon/xoff characters */ - rcout(CD180_SCHR1, ts->c_cc[CSTART]); - rcout(CD180_SCHR2, ts->c_cc[CSTOP]); - if (iflag & IXON) { - val |= COR2_TXIBE; - if (iflag & IXANY) - val |= COR2_IXM; - } + else + rc->rc_flags &= ~RC_RTSFLOW; + + if (inpflow) { + if (ts->c_cc[VSTART] != _POSIX_VDISABLE) + rcout(CD180_SCHR1, ts->c_cc[VSTART]); + rcout(CD180_SCHR2, ts->c_cc[VSTOP]); + val |= COR2_TxIBE; + if (iflag & IXANY) + val |= COR2_IXM; } - rcout(CD180_COR2, val); - CCRCMD(CCR_CORCHG2); + rcout(CD180_COR2, rc->rc_cor2 = val); + + CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, + CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); disc_optim(tp, ts, rc); /* modem ctl */ - rcout(CD180_MCOR1, MCOR1_CDZD); - rcout(CD180_MCOR2, MCOR2_CDOD); + val = cflag & CLOCAL ? 0 : MCOR1_CDzd; + if (cflag & CCTS_OFLOW) + val |= MCOR1_CTSzd; + rcout(CD180_MCOR1, val); - /* enable i/o and interrupts */ - CCRCMD(CCR_TXEN|CCR_RXEN); - rcout(CD180_IER, rc->rc_ier |= IER_CD | IER_RXD); + val = cflag & CLOCAL ? 0 : MCOR2_CDod; + if (cflag & CCTS_OFLOW) + val |= MCOR2_CTSod; + rcout(CD180_MCOR2, val); + /* enable i/o and interrupts */ + CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, + CCR_XMTREN | ((cflag & CREAD) ? CCR_RCVREN : CCR_RCVRDIS)); + WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan); + + rc->rc_ier = cflag & CLOCAL ? 0 : IER_CD; + if (cflag & CCTS_OFLOW) + rc->rc_ier |= IER_CTS; + if (cflag & CREAD) + rc->rc_ier |= IER_RxData; + if (tp->t_state & TS_BUSY) + rc->rc_ier |= IER_TxRdy; + if (ts->c_ospeed != 0) + rc_modctl(rc, TIOCM_DTR, DMBIS); + if ((cflag & CCTS_OFLOW) && (rc->rc_msvr & MSVR_CTS)) + rc->rc_flags |= RC_SEND_RDY; + rcout(CD180_IER, rc->rc_ier); (void) splx(s); return 0; } +/* Re-initialize board after bogus interrupts */ +static void rc_reinit(rcb) +struct rc_softc *rcb; +{ + register struct rc_chans *rc, *rce; + register int i, nec; + + nec = rcb->rcb_addr; + rc_hwreset(rcb->rcb_unit, nec, RC_FAKEID); + rc = &rc_chans[rcb->rcb_unit * CD180_NCHAN]; + rce = rc + CD180_NCHAN; + for (; rc < rce; rc++) + (void) rc_param(rc->rc_tp, &rc->rc_tp->t_termios); +} + int rcioctl(dev, cmd, data, flag, p) dev_t dev; int cmd, flag; @@ -1073,7 +1149,7 @@ struct proc *p; break; case TIOCSDTR: - (void) rc_modctl(rc, TIOCM_RTS|TIOCM_DTR, DMBIS); + (void) rc_modctl(rc, TIOCM_DTR, DMBIS); break; case TIOCCDTR: @@ -1125,27 +1201,41 @@ register struct rc_chans *rc; int bits, cmd; { register int nec = rc->rc_rcb->rcb_addr; - u_char *dtr = &rc->rc_rcb->rcb_dtr; - unsigned int msvr; + u_char *dtr = &rc->rc_rcb->rcb_dtr, msvr; rcout(CD180_CAR, rc->rc_chan); switch (cmd) { case DMSET: - rcout(CD180_MSVR, 0); - *dtr &= ~(1 << rc->rc_chan); - /* falltrough */ + rcout(RC_DTREG, (bits & TIOCM_DTR) ? + ~(*dtr |= 1 << rc->rc_chan) : + ~(*dtr &= ~(1 << rc->rc_chan))); + msvr = rcin(CD180_MSVR); + if (bits & TIOCM_RTS) + msvr |= MSVR_RTS; + else + msvr &= ~MSVR_RTS; + if (bits & TIOCM_DTR) + msvr |= MSVR_DTR; + else + msvr &= ~MSVR_DTR; + rcout(CD180_MSVR, msvr); + break; case DMBIS: + if (bits & TIOCM_DTR) + rcout(RC_DTREG, ~(*dtr |= 1 << rc->rc_chan)); + msvr = rcin(CD180_MSVR); if (bits & TIOCM_RTS) - rcout(CD180_MSVR, MSVR_RTS); + msvr |= MSVR_RTS; if (bits & TIOCM_DTR) - rcout(RC_DTR, ~(*dtr |= (1 << rc->rc_chan))); + msvr |= MSVR_DTR; + rcout(CD180_MSVR, msvr); break; case DMGET: - msvr = rcin(CD180_MSVR); bits = TIOCM_LE; + msvr = rc->rc_msvr = rcin(CD180_MSVR); if (msvr & MSVR_RTS) bits |= TIOCM_RTS; @@ -1155,15 +1245,24 @@ int bits, cmd; bits |= TIOCM_DSR; if (msvr & MSVR_DTR) bits |= TIOCM_DTR; + if (msvr & MSVR_CD) + bits |= TIOCM_CD; + if (~rcin(RC_RIREG) & (1 << rc->rc_chan)) + bits |= TIOCM_RI; return bits; case DMBIC: if (bits & TIOCM_DTR) - rcout(RC_DTR, ~(*dtr &= ~(1 << rc->rc_chan))); + rcout(RC_DTREG, ~(*dtr &= ~(1 << rc->rc_chan))); + msvr = rcin(CD180_MSVR); if (bits & TIOCM_RTS) - rcout(CD180_MSVR, 0); + msvr &= ~MSVR_RTS; + if (bits & TIOCM_DTR) + msvr &= ~MSVR_DTR; + rcout(CD180_MSVR, msvr); break; } + rc->rc_msvr = rcin(CD180_MSVR); return 0; } @@ -1181,9 +1280,6 @@ int rc_test(nec, unit) #define ERR(s) { \ printf("rc%d: ", unit); printf s ; printf("\n"); \ (void) splx(old_level); return 1; } -#define TWAITFORCCR \ - for (rcnt = 100000; rcin(CD180_CCR) && rcnt; rcnt--) ; \ - if (!rcnt) ERR(("Timeout waiting for zero CCR")) struct rtest { u_char txbuf[CD180_NFIFO]; /* TX buffer */ @@ -1192,24 +1288,22 @@ int rc_test(nec, unit) int txptr; /* TX pointer */ } tchans[CD180_NCHAN]; - old_level = splhigh(); + old_level = spltty(); chipid = RC_FAKEID; /* First, reset board to inital state */ - rc_hwreset(nec, chipid); + rc_hwreset(unit, nec, chipid); + + divs = RC_BRD(19200); /* Initialize channels */ for (chan = 0; chan < CD180_NCHAN; chan++) { - divs = RC_BRD(19200); - - TWAITFORCCR; - /* Select and reset channel */ rcout(CD180_CAR, chan); - rcout(CD180_CCR, CCR_RESETCHAN); - TWAITFORCCR; + CCRCMD(unit, chan, CCR_ResetChan); + WAITFORCCR(unit, chan); /* Set speed */ rcout(CD180_RBPRL, divs & 0xFF); @@ -1224,10 +1318,9 @@ int rc_test(nec, unit) rcout(CD180_COR1, COR1_NOPAR | COR1_8BITS | COR1_1SB); rcout(CD180_COR2, COR2_LLM); rcout(CD180_COR3, CD180_NFIFO); - TWAITFORCCR; - rcout(CD180_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); - TWAITFORCCR; - rcout(CD180_CCR, CCR_RXEN | CCR_TXEN); + CCRCMD(unit, chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); + CCRCMD(unit, chan, CCR_RCVREN | CCR_XMTREN); + WAITFORCCR(unit, chan); rcout(CD180_MSVR, MSVR_RTS); /* Fill TXBUF with test data */ @@ -1238,46 +1331,44 @@ int rc_test(nec, unit) tchans[chan].txptr = tchans[chan].rxptr = 0; /* Now, start transmit */ - rcout(CD180_IER, IER_TXMPTY | IER_RXD); + rcout(CD180_IER, IER_TxMpty|IER_RxData); } /* Pseudo-interrupt poll stuff */ for (rcnt = 10000; rcnt-- > 0; rcnt--) { - i = ~(rcin(RC_BSR)) & 0xF; + i = ~(rcin(RC_BSR)); if (i & RC_BSR_TOUT) ERR(("BSR timeout bit set\n")) - if (i & RC_BSR_TXINT) { + else if (i & RC_BSR_TXINT) { iack = rcin(RC_PILR_TX); if (iack != (GIVR_IT_TDI | chipid)) ERR(("Bad TX intr ack (%02x != %02x)\n", iack, GIVR_IT_TDI | chipid)); - chan = (rcin(CD180_GICR) >> 2) & 07; + chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH; /* If no more data to transmit, disable TX intr */ if (tchans[chan].txptr >= CD180_NFIFO) { iack = rcin(CD180_IER); - rcout(CD180_IER, iack & ~IER_TXMPTY); + rcout(CD180_IER, iack & ~IER_TxMpty); } else { for (iack = tchans[chan].txptr; iack < CD180_NFIFO; iack++) rcout(CD180_TDR, tchans[chan].txbuf[iack]); tchans[chan].txptr = iack; - rcout(CD180_EOIR, 0); } - - } - if (i & RC_BSR_RXINT) { - unsigned int ucnt; + rcout(CD180_EOIR, 0); + } else if (i & RC_BSR_RXINT) { + u_char ucnt; iack = rcin(RC_PILR_RX); if (iack != (GIVR_IT_RGDI | chipid) && iack != (GIVR_IT_REI | chipid)) ERR(("Bad RX intr ack (%02x != %02x)\n", iack, GIVR_IT_RGDI | chipid)) - chan = (rcin(CD180_GICR) >> 2) & 07; + chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH; ucnt = rcin(CD180_RDCR) & 0xF; while (ucnt-- > 0) { iack = rcin(CD180_RCSR); - if (iack & RCSR_TOUT) + if (iack & RCSR_Timeout) break; if (iack & 0xF) ERR(("Bad char chan %d (RCSR = %02X)\n", @@ -1290,13 +1381,19 @@ int rc_test(nec, unit) } rcout(CD180_EOIR, 0); } - rcout(RC_BSR, 0); + rcout(RC_CTOUT, 0); for (iack = chan = 0; chan < CD180_NCHAN; chan++) if (tchans[chan].rxptr >= CD180_NFIFO) iack++; if (iack == CD180_NCHAN) break; } + for (chan = 0; chan < CD180_NCHAN; chan++) { + /* Select and reset channel */ + rcout(CD180_CAR, chan); + CCRCMD(unit, chan, CCR_ResetChan); + } + if (!rcnt) ERR(("looses characters during local loopback\n")) /* Now, check data */ @@ -1310,24 +1407,35 @@ int rc_test(nec, unit) } #ifdef RCDEBUG - -int printrcflags(rc, comment) +static void printrcflags(rc, comment) struct rc_chans *rc; char *comment; { u_short f = rc->rc_flags; + register int nec = rc->rc_rcb->rcb_addr; - printf("rc %d/%d %s flags: %s%s%s%s%s%s%s%s%s\n", + printf("rc%d/%d: %s flags: %s%s%s%s%s%s%s%s%s%s%s%s\n", rc->rc_rcb->rcb_unit, rc->rc_chan, comment, (f & RC_DTR_OFF)?"DTR_OFF " :"", - (f & RC_ACTOUT) ?"ACTOUT ":"", - (f & RC_RTSFLOW)?"RTSFL " :"", - (f & RC_CTSFLOW)?"CTSFL " :"", - (f & RC_DORXFER)?"DORXF " :"", - (f & RC_DOXXFER)?"DOXXF " :"", - (f & RC_MODCHG) ?"MODC " :"", - (f & RC_OSUSP) ?"OSUSP " :""); - return 0; + (f & RC_ACTOUT) ?"ACTOUT " :"", + (f & RC_RTSFLOW)?"RTSFLOW " :"", + (f & RC_CTSFLOW)?"CTSFLOW " :"", + (f & RC_DORXFER)?"DORXFER " :"", + (f & RC_DOXXFER)?"DOXXFER " :"", + (f & RC_MODCHG) ?"MODCHG " :"", + (f & RC_OSUSP) ?"OSUSP " :"", + (f & RC_OSBUSY) ?"OSBUSY " :"", + (f & RC_WAS_BUFOVFL) ?"BUFOVFL " :"", + (f & RC_WAS_SILOVFL) ?"SILOVFL " :"", + (f & RC_SEND_RDY) ?"SEND_RDY":""); + + rcout(CD180_CAR, rc->rc_chan); + + printf("rc%d/%d: msvr %02x ier %02x ccsr %02x\n", + rc->rc_rcb->rcb_unit, rc->rc_chan, + rcin(CD180_MSVR), + rcin(CD180_IER), + rcin(CD180_CCSR)); } #endif /* RCDEBUG */ @@ -1364,8 +1472,8 @@ rc_discard_output(rc) rc->rc_flags &= ~RC_DOXXFER; } rc->rc_optr = rc->rc_obufend; - enable_intr(); rc->rc_tp->t_state &= ~TS_BUSY; + enable_intr(); } static void @@ -1410,4 +1518,17 @@ disc_optim(tp, t, rc) else rc->rc_hotchar = 0; } + +static void +rc_wait0(nec, unit, chan, line) + int nec, unit, chan, line; +{ + int rcnt; + + for (rcnt = 100; rcnt && rcin(CD180_CCR); rcnt--) + DELAY(15); + if (rcnt == 0) + printf("rc%d/%d: channel command timeout, rc.c line: %d\n", + unit, chan, line); +} #endif /* NRC */ |