From 7e4d7125a3bf6ca82a88e350b2b388ebb696f940 Mon Sep 17 00:00:00 2001 From: briggs Date: Sat, 8 Apr 1995 13:20:52 +0000 Subject: [PATCH] Back to previous version of the serial driver until we can figure out why the new one gets a lot of overflows and doesn't work on the IIsi or IIvx at all. --- sys/arch/mac68k/dev/ser.c | 1379 +++++++++------------------------- sys/arch/mac68k/dev/serreg.h | 269 ++----- 2 files changed, 438 insertions(+), 1210 deletions(-) diff --git a/sys/arch/mac68k/dev/ser.c b/sys/arch/mac68k/dev/ser.c index 5d2c1a90f7ce..b9eb6d2466e8 100644 --- a/sys/arch/mac68k/dev/ser.c +++ b/sys/arch/mac68k/dev/ser.c @@ -1,4 +1,4 @@ -/* $NetBSD: ser.c,v 1.17 1995/02/11 19:06:57 briggs Exp $ */ +/* $NetBSD: ser.c,v 1.18 1995/04/08 13:20:52 briggs Exp $ */ /* * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. @@ -66,87 +66,16 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Further disgusting kludges by Dave Leonard, - * redocumented z8530 stuff - * added break ioctls and detection - * attempt at bringing all chip ops together - * deepened s/w fifos to match chip's - * added TIOC[SG]FLAG - * farming/parity errors passed to discipline + * Hacked by Brad Parker, + * added CTS input flow control + * added DCD event detection + * added software fifo's * - * Hacked by Brad Parker, - * added CTS input flow control - * added DCD event detection - * added software fifo's + * Mac II serial device interface * - * Mac II serial device interface - * - * Information used in this source was gleaned from low-memory - * global variables in MacOS and the Advanced Micro Devices - * 1992 Data Book/Handbook. - * - * Also from the Zilog Scc User's manual for the z85x30 - * - *-- - * - * Notes on complying with appletalk (not yet in this module) - # - * unlike system 7 which requires a reboot when you change the - * usage of a port from serial to appletalk, it should be possible - * to re-configure the chip on the fly (just like old System 6s) - * - * This driver should be augmented to provide LLAP. - * - * To quote from a Zilog manual: - * "A majority of the difficult timing and all of the hardware interface - * problems crop up in the LLAP driver. These problems are so difficult - * that it makes sense to start writing such a driver by writing - * experimental routines that transmit and recieve frames." - * The manual then goes on to provide discussion and code for a z80181 - * based implementation. - * - * LLAP uses csma/ca and implementations with zilog's SCC put it into - * SDLC (synchronous) mode. ie each frame starts with a 01111110 sequence - * (which is why you sometimes see ~'s when localtalk kicks in on a - * dumb terminal) The frame ends with a sequence of 12 to 18 1's which - * the SCC interprets as a Abort sequence and loses sync. This is handy - * because you can prepare your packet then wait for the abort interrupt - * to send it. - * - * A faster way gets you to pulse the RTS line for at least one bit time - * and then idle it for at least 2 bit times to check for collision - * before sending. "This syncronisation is obtained by first enabling - * the hardware line so that an edge is detected by all the recievers on - * the network." It looks like the start of a clocking period. The - * other SCCs see the idle period shortly after and "assume the clock - * has been lost (missing clock bit set on RR10)". Zilog dont have an - * interrupt on RR10, so it must be polled. :( - * - * LLAP nodes have a dynamically allocated node ID. ie you get a random - * one then check to see if anyone else has got it by sending a lapENQ - * and if no-one winges withing 200 usec, then its yours. (You have to - * send a good couple of lapENQs in case the packet was lost, or the - * winging node was busy, etc) Node ID 0xFF is a broadcast address. - * - * The 200usec and stuff can be timed by the chip by setting a counter - * and getting an interrupt when it reaches zero. - * - * LLAP packets are made up of: - * - * 1 dest ID - * 1 source ID - * 1 LLAP type { 0x0 ... 0x7f, lapENQ, lapACK, lapRTS, lapCTS} - * 0-600 data - * 1 CRC (TxUnderrun Int.) - * 1 CRC - * 1 flag - * - * Init string template for LLAP: - * 4=0x20 1=0x00 2=0x00 3=0xcc 5=0x60 6=0x00 7=0x7e 8=0x01 - * 10=0xe0 11=0xf6 12=0x06 13=0x0 14=0x60 14=0xc0 14=0xa0 - * 14=0x20 14=0x01 3=0xcc 15=0x0 16=0x10 1=0x00 9=0x09 - * (go through this with a fine comb) - * + * Information used in this source was gleaned from low-memory + * global variables in MacOS and the Advanced Micro Devices + * 1992 Data Book/Handbook. */ #include "ser.h" @@ -168,230 +97,66 @@ #include +/*#define DEBUG*/ #undef DEBUG -/* #define DEBUG /**/ - -/*#define use_hw_flow*/ /* attempt to use hw flow control -buggy */ volatile unsigned char *sccA = (unsigned char *) 0x4000; -static void serstart __P((register struct tty *)); -static int serparam __P((register struct tty *, register struct termios *)); -static int serctl __P((dev_t dev, int bits, int how)); -extern int ser_intr __P((void)); +static void serstart __P((register struct tty *)); +static int serparam __P((register struct tty *, register struct termios *)); +static int serctl __P((dev_t dev, int bits, int how)); +extern int ser_intr __P((void)); -static int nser = NSER; -static int serdefaultrate = TTYDEF_SPEED; +static int ser_active = 0; +static int nser = NSER; +static int serdefaultrate = TTYDEF_SPEED; -struct tty *ser_tty[NSER]; +struct tty *ser_tty[NSER]; -extern struct tty *constty; +extern struct tty *constty; -#define UNIT(x) minor(x) +#define UNIT(x) minor(x) -/* - * This'll end up in a header file before (next) Christmas - */ - -/* - * This structure is persistent across open/closes and is - * zeroed only at init time - it is reliable as the current state - * of the serial channel. - */ - -#define SER_WRITEREG(unit,reg,bits) \ - ser_status[unit].wr[reg]=(bits),\ - SER_DOCNTL(unit,reg,bits) - -#define SERCTL_DTR 0x001 /* DTR */ -#define SERCTL_RTS 0x002 /* RTS */ -#define SERCTL_AUTO 0x004 /* chip level hardware flow control */ -#define SERCTL_DCD 0x008 /* DCD [readonly] */ -#define SERCTL_BRK 0x010 /* raise break */ -#define SERCTL_CTS 0x020 /* CTS [readonly] */ -#define SERCTL_BUSY 0x040 /* tx in progress [readonly] */ -#define SERCTL_INHIB 0X080 /* hardware inhibit of transmitter */ -#define SERCTL_INBRK 0x100 /* break recv'd before this char [ro]*/ - -/* writable bits */ -#define SERCTL_MASK ( /* bits that can be user modified */ \ - SERCTL_DTR| \ - SERCTL_RTS| \ - SERCTL_AUTO| \ - SERCTL_BRK| \ - SERCTL_INHIB| \ - 0) -/* - * NOTE: by some magical coincidence, SERCTL_{DCD,RTS} match up with - * SER_R0_{DCD,CTS}!!! This feature isn't used yet; but helps in debugging. - */ - -volatile struct ser_status { - unsigned char wr[16]; /* last register writes */ - - unsigned char ddcd, dcts; /* delta (change) flags */ - int oflo; /* s/w fifo over flow */ - int over; /* h/w fifo over flow */ - unsigned char intpend; /* number of sw ints pending */ - - int state; /* (intended|derived) state of chip */ + unsigned char ddcd, dcts; /* delta (change) flags */ + unsigned char dcd, cts; /* last state of signal */ + unsigned char dtr, rts; /* current state of signal */ + int oflo; /* s/w fifo over flow */ + int over; /* h/w fifo over flow */ + int flags; +#define SER_BUSY 0x01 } ser_status[NSER]; -#define SCC_INT 10 -#define SCC_SPEED 11 - -/* - * End of stuff for header file. - */ - -#ifdef DEBUG -/* - * This is one big printf that dumps all the interesting - * info about a serial port - */ - -/* DBG used to restrict debugging to a particular serial port */ -#define DBG(u) ((u)==0)/**/ - -/* fwd decl */ -static ser_apply_state(int); - -static void -ser_dbg( char*msg, int unit ) -{ - volatile struct ser_status *s = &ser_status[unit]; - struct tty *t = ser_tty[unit]; - - if (!DBG(unit)) return; - - if (!t) { /* sanity */ - printf("ser%d: %s (no attached tty)\n",unit,msg); - return; - } - - printf( "ser%d: %s %s%s" - " %s=(%s%s%s%s%s%s%s%s%s)" /*ser*/ - " %s=(%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)" /*tty*/ - " %s=(%s%s%s%s%s%s%s%s%s%s%s%s%s%s)" /*cflag*/ - "\n", - unit,msg, - - s->oflo?"oflo ":"", s->over?"over ":"", - - "ser", - s->state&SERCTL_BUSY?"busy ":"", - s->state&SERCTL_INHIB?"txinhib ":"", - s->state&SERCTL_INBRK?"inbrk ":"", - s->state&SERCTL_DTR?"DTR ":"", - s->state&SERCTL_RTS?"RTS ":"", - s->state&SERCTL_BRK?"BRK ":"", - s->state&SERCTL_DCD?"DCD ":"", - s->state&SERCTL_CTS?"CTS ":"", - s->state&SERCTL_AUTO?"AUTO ":"", - - "tty", - t->t_state&TS_ASLEEP ?"ASLEEP ":"", - t->t_state&TS_ASYNC ?"ASYNC ":"", - t->t_state&TS_BUSY ?"BUSY ":"", - t->t_state&TS_CARR_ON ?"CARR_ON ":"", - t->t_state&TS_FLUSH ?"FLUSH ":"", - t->t_state&TS_ISOPEN ?"ISOPEN ":"", - t->t_state&TS_TBLOCK ?"TBLOCK ":"", - t->t_state&TS_TIMEOUT ?"TIMEOUT ":"", - t->t_state&TS_TTSTOP ?"TTSTOP ":"", - t->t_state&TS_WOPEN ?"WOPEN ":"", - t->t_state&TS_XCLUDE ?"XCLUDE ":"", - t->t_state&TS_BKSL ?"BKSL ":"", - t->t_state&TS_CNTTB ?"CNTTB ":"", - t->t_state&TS_ERASE ?"ERASE ":"", - t->t_state&TS_LNCH ?"LNCH ":"", - t->t_state&TS_TYPEN ?"TYPEN ":"", - t->t_state&TS_LOCAL ?"LOCAL ":"", - - "cflag", - t->t_cflag&CIGNORE ?"CIGNORE ":"", - (t->t_cflag&CSIZE)==CS5?"CS5 ":"", - (t->t_cflag&CSIZE)==CS6?"CS6 ":"", - (t->t_cflag&CSIZE)==CS7?"CS7 ":"", - (t->t_cflag&CSIZE)==CS8?"CS8 ":"", - t->t_cflag&CSTOPB ?"CSTOPB ":"", - t->t_cflag&CREAD ?"CREAD ":"", - t->t_cflag&PARENB ?"PARENB ":"", - t->t_cflag&PARODD ?"PARODD ":"", - t->t_cflag&HUPCL ?"HUPCL ":"", - t->t_cflag&CLOCAL ?"CLOCAL ":"", - t->t_cflag&CRTSCTS ?"CRTSCTS ":"", - t->t_cflag&MDMBUF ?"MDMBUF ":"", - t->t_cflag&CHWFLOW ?"CHWFLOW ":"", - 0 ); - -} -#else -#define DBG(u) 0 -#endif DEBUG +#define SCC_INT 10 +#define SCC_SPEED 11 /* SCC initialization string from Steve Allen (wormey@eskimo.com) */ - static unsigned char ser_init_bytes[]={ - - 4, SER_W4_PARNONE| /* no parity */ - SER_W4_1SBIT| /* one stop bit async */ - SER_W4_CLKX16, /* clock = 16 * data rate */ - - 3, SER_W3_RX8DBITS, /* 8 bit data rx'd */ - /* dont enable RX yet */ - - 5, /*SER_W5_DTR| /* enable DTR */ - /*SER_W5_RTS| /* enable RTS */ - SER_W5_TX8DBITS, /* 8 data bits tx'd */ - /* TX disabled */ - - 9, SER_W9_NV| /* No vector set up yet */ - SER_W9_DLC, /* disable lower chain */ - /* do not enable master interrupt (mie) yet */ - - 10, SER_W10_NRZ, /* nrz mode */ - - 11, SER_W11_TXBR| /* source of tx clock is Baud rate gen */ - SER_W11_RXBR, /* source of rx clock is baud rate gen */ - - 12, 0x04, /* time constant LB. Will be replaced below */ - 13, 0x00, /* time constant HB. Will be replaced below */ - - 14, 0x00, /* don't enable the BR yet */ - - 5, /*SER_W5_DTR|*/ - /*SER_W5_RTS|*/ - SER_W5_TX8DBITS| - SER_W5_ENBTX, /* enable tx */ - - 3, SER_W3_RX8DBITS| - SER_W3_ENBRX, /* enable rx */ - - 0, 0x80, /* reset txCRC. XXX is this needed? */ - - 14, SER_W14_ENBBR, /* enable BR. DPLL not affected */ - - 1, 0x00, /* WAIT/DMA request, disable rx int */ - - 15, SER_W15_DCDINT| /* enable DCD, CTS and Break interrupts */ - SER_W15_CTSINT| - SER_W15_BRKINT, - - 0, SER_W0_RSTESINTS, /* reset ext/status ints */ - 0, SER_W0_RSTESINTS, /* twice */ - - 0xff,0xff, /* marker before interrupts are enabled */ - - 1, SER_W1_ENBTXINT| /* enable tx intertrupts */ - SER_W1_ENBRXINT, - /* SER_W1_ENBR1INT, /* and 1st rx */ - - 9, SER_W9_NV| - SER_W9_DLC| - SER_W9_MIE, /* globally enable interrupts */ + 4, 0x44, /* Transmit/Receive control. Select Async or Sync + mode and clock multiplier. */ + 3, 0xc0, /* select receiver control. Bit d0 (rx enable) + must be set to 0 at this time. */ + 5, 0xe2, /* select transmit control. Bit d3 (tx enable) + must be set to 0 at this time. */ + 9, 0x06, /* select interrupt control. Bit d3 (mie) + must be set to 0 at this time. */ + 10, 0x00, /* miscellaneous control. */ + 11, 0x50, /* clock control. */ + 12, 0x04, /* time constant LB. */ + 13, 0x00, /* time constant HB. */ + 14, 0x00, /* miscellaneous control. Bit d0 (BR gen enable) + must be set to 0 at this time. */ + 3, 0xc1, /* set d0 (rx enable). */ + 5, 0xea, /* set d3 (tx enable). */ + 0, 0x80, /* reset txCRC. */ + 14, 0x01, /* BR gen enable. Enable DPLL. */ + 1, 0x00, /* make sure DMA not set. */ + 15, 0x00, /* disable external interrupts. */ + 0, 0x10, /* reset ext/status twice. */ + 0, 0x10, + 1, 0x0a, /* enable rcv and xmit interrupts. */ + 9, 0x0e, /* enable master interrupt bit d3. */ }; extern int matchbyname(); @@ -399,15 +164,13 @@ extern int matchbyname(); static void serinit(int running_interrupts) { -static int initted=0; +static int initted=0; int bcount; int i, s, spd; - int unit; /* * Will be called twice if we're running a serial console. */ - if (initted++) return; @@ -417,38 +180,24 @@ static int initted=0; s = splhigh(); - SER_WRITEREG(0, 9, SER_W9_HWRESET); - - /* short delay after the hardware reset */ - /* take this time to init some structs */ - - for(unit=0;unit>8) & 0xff); - - if (ser_init_bytes[i]==0xff) { - if (!running_interrupts) break; - } else { - for(unit=0;unit= NSER ){ return (ENXIO); } - + ser_active |= 1 << unit; if (ser_tty[unit]) { tp = ser_tty[unit]; } else { @@ -512,41 +263,16 @@ seropen(dev_t dev, int flag, int mode, struct proc *p) /* serial device open code */ -#ifdef DEBUG - ser_dbg("seropen",unit); -#endif - /* - * set up the initial (unlatched) values of cts rts - * assumes that the port is quiescent until interrupts enabled - */ - - SER_DOCNTL(unit, 15, - ser_status[unit].wr[15] & ~(SER_W15_DCDINT|SER_W15_CTSINT) ); - reg0 = SER_STATUS(unit, 0); - SER_DOCNTL(unit, 15, ser_status[unit].wr[15]); - - ser_status[unit].state = 0; /* blam */ - - SER_WRITEREG(unit, 0, SER_W0_RSTESINTS); - - if (reg0 & SER_R0_DCD) { - ser_status[unit].state |= SERCTL_DCD; - tp->t_state |= TS_CARR_ON; - } - if (!/*!!?*/reg0 & SER_R0_CTS) /* kapow */ - ser_status[unit].state |= SERCTL_CTS; - - /* - * enable interrupts here - * because raising RTS/DTR later might - * trigger an external response - */ - - serctl(unit, 1, SCC_INT); + bzero((char *)&ser_status[unit], sizeof(struct ser_status)); /* turn on RTS & DTR */ + serctl(unit, SER_W5_RTS | SER_W5_DTR, DMSET); - serctl(unit, SERCTL_RTS|SERCTL_DTR, DMSET); + if(serctl(unit, 0, DMGET) & SER_R0_DCD) + tp->t_state |= TS_CARR_ON; + + /* enable interrupts */ + serctl(unit, 1, SCC_INT); /* end serial device open code */ @@ -554,20 +280,18 @@ seropen(dev_t dev, int flag, int mode, struct proc *p) while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && (tp->t_state & TS_CARR_ON) == 0) { tp->t_state |= TS_WOPEN; -#ifdef DEBUG - ser_dbg("seropen: sleeping",unit); -#endif if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ttopen, 0)) break; } (void) spl0(); -#ifdef DEBUG - ser_dbg("seropen: ok",unit); -#endif if (error == 0) error = (*linesw[tp->t_line].l_open)(dev, tp); +#if defined(DEBUG) + printf("ser: exiting seropen()\n"); +#endif + return (error); } @@ -579,28 +303,23 @@ serclose(dev_t dev, int flag, int mode, struct proc *p) register int unit; int s; +#if defined(DEBUG) + printf("ser: entered serclose()\n"); +#endif unit = UNIT(dev); tp = ser_tty[unit]; (*linesw[tp->t_line].l_close)(tp, flag); /* serial device close code */ -#ifdef DEBUG - ser_dbg("serclose",unit); -#endif + /* disable interrupts */ serctl(unit, 0, SCC_INT); - ser_status[unit].state &= ~SERCTL_BUSY; /* in case busy */ if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || (tp->t_state&TS_ISOPEN) == 0) - /* turn RTS and DTR off */ - serctl(unit, SERCTL_DTR|SERCTL_RTS, DMBIC); + serctl(unit, 0, DMSET); /* turn RTS and DTR off */ - /* ser_active &= ~(1 << unit); */ - -#ifdef DEBUG - ser_dbg("serclose: closed",unit); -#endif + ser_active &= ~(1 << unit); /* end of serial device close code */ ttyclose(tp); @@ -609,6 +328,9 @@ serclose(dev_t dev, int flag, int mode, struct proc *p) ser_tty[unit] = NULL; #endif +#if defined(DEBUG) + printf("ser: exiting serclose()\n"); +#endif return (0); } @@ -619,6 +341,9 @@ serread(dev, uio, flag) int flag; { register struct tty *tp = ser_tty[UNIT(dev)]; +#if defined(DEBUG) + printf("ser: called serread()\n"); +#endif return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); } @@ -632,13 +357,16 @@ serwrite(dev, uio, flag) int unit = UNIT(dev); register struct tty *tp = ser_tty[unit]; +#if defined(DEBUG) + printf("ser: called serwrite()\n"); +#endif return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); } /* private buffers used by driver at splscc() */ -#define INBUFLEN 256 -#define OUTBUFLEN 512 -static unsigned int ser_inbuf[NSER][INBUFLEN]; /* was unsigned char[] */ +#define INBUFLEN 128 +#define OUTBUFLEN 512 +static unsigned char ser_inbuf[NSER][INBUFLEN]; static volatile unsigned char ser_inlen[NSER] = {0,0}; static unsigned char ser_intail[NSER] = {0,0}; @@ -657,287 +385,95 @@ static volatile unsigned int ser_outtail[NSER] = {0,0}; extern int ser_intr(void) { - /* serial interrupt code */ -#define HWFIFO 3 /* depth of the hardware fifo */ - unsigned char r0o, reg0, reg1, reg2, reg3, r1[HWFIFO], c,cdpth; - unsigned int ch[HWFIFO]; - int s,reset_ext=0; - volatile int *state; - register int unit; + /* serial interrupt code */ + unsigned char reg0, reg1, ch, ch1, c, bits; + int s; + register int unit; - /* read status to reset SCC state machine */ + /* read status to reset SCC state machine */ + reg0 = SCCCNTL(0); - r0o = SCCCNTL(0); + /* reset port B vector to see who interrupted us */ + bits = SER_STATUS(1, 2) & 0x0e; + if (bits < 8) + unit = 1; + else + unit = 0; - /* port B's vector contains info on the interrupt */ + reg0 = SER_STATUS(unit, 0); + switch ((bits & 7) >> 1) { + case 0: /* tranmitter buffer empty */ + if (ser_outlen[unit] > 0) + { + c = ser_outbuf[unit][ser_outtail[unit]]; + ser_outtail[unit] = (ser_outtail[unit] + 1) % OUTBUFLEN; + SCCRDWR(unit) = c; + ser_outlen[unit]--; + } else { + SER_DOCNTL(unit, 0, SER_W0_RSTTXPND); + ser_status[unit].flags &= ~SER_BUSY; + setsoftserial(); + } + SER_DOCNTL(unit, 0, SER_W0_RSTIUS); + break; + case 1: /* ext/status change */ + if ((reg0 & SER_R0_DCD) && ser_status[unit].dcd == 0) + ser_status[unit].ddcd = 1; + else + if (!(reg0 & SER_R0_DCD) && ser_status[unit].dcd != 0) + ser_status[unit].ddcd = 1; + ser_status[unit].dcd = reg0 & SER_R0_DCD; - reg2 = SER_STATUS(1, 2); + if ((reg0 & SER_R0_CTS) && ser_status[unit].cts == 0) + ser_status[unit].dcts = 1; + else + if (!(reg0 & SER_R0_CTS) && ser_status[unit].cts != 0) + ser_status[unit].dcts = 1; + ser_status[unit].cts = reg0 & SER_R0_CTS; - switch (reg2 & SER_R2_CHANMASK) { - case SER_R2_CHANA: unit=0; break;/* channel that caused int */ - case SER_R2_CHANB: unit=1; break; + if (reg0 & SER_R0_TXUNDERRUN) + SER_DOCNTL(unit, 0, SER_W0_RSTTXUNDERRUN); + + SER_DOCNTL(unit, 0, SER_W0_RSTESINTS); + SER_DOCNTL(unit, 0, SER_W0_RSTIUS); + break; + case 2: /* recv char available */ + ch = SCCRDWR(unit); + c = 1; + if (SER_STATUS(unit, 0) & SER_R0_RXREADY) { + ch1 = SCCRDWR(unit); + c = 2; } - reg0 = SER_STATUS(unit, 0); - -#ifdef DEBUG - /*if (DBG(unit))printf("%02x%02x.",reg0,reg2);*/ -#endif - - state = &ser_status[unit].state; /* optimisation */ - - switch (reg2 & SER_R2_MASK) { - - case SER_R2_TX: /* tranmitter buffer empty */ - - if (ser_outlen[unit] == 0) { - SER_WRITEREG(unit, 0, SER_W0_RSTTXPND); - *state &= ~SERCTL_BUSY; - setsoftserial(); - ser_status[unit].intpend++; - } else { - c = ser_outbuf[unit][ser_outtail[unit]]; - ser_outtail[unit] = - (ser_outtail[unit] + 1) % OUTBUFLEN; - SCCRDWR(unit) = c; - ser_outlen[unit]--; - } - - /* - * Flow control - the Zilog way(TM) - * - * The zilog 85x30 has a magic feature called - * 'auto enable' which, in short, allows the CTS pin - * to enable/disable the TX line. However, in Zilog's - * infinite wisdom, 'auto enable' also forces you to - * have DCD {en,dis}able the RX. This is bad if you are - * in CLOCAL mode and are using CRTSCTS. - * - * The safest thing to do is just fall through to - * status check when we are doing flow control and - * there's an ext/change int pending - we use magic - * there... - */ - - if ( ser_tty[unit] && ser_tty[unit]->t_cflag&CRTSCTS) { - reg3 = SER_STATUS(1, 3); - if ( reg3 & (SER_R3_AIPES|SER_R3_BIPES) ) - goto check_status; - } - - break; - - case SER_R2_EXTCHG: /* ext/status change */ -check_status: - reset_ext++; - - /* cts */ - - /* XXX why???? - * for some bizarre reason, cts seems to be inverted - * this might be because the interrupt latches the - * previous value of the line? then why not for DCD? - */ - - if ( ! ((reg0^*state)&SER_R0_CTS)) { - - *state ^= SERCTL_CTS; - -#ifdef DEBUG - if (DBG(unit)) - printf("c%c",*state&SERCTL_CTS?'+':'-'); -#endif - if (*state & SERCTL_CTS) { - - /* cts is now on */ - - /* - * we turn on the txinhibit if needed - * here it can be turned off at an - * upper level - */ - if ( -#ifdef use_hw_flow - /* not on auto, but */ - !(*state&SERCTL_AUTO) && -#endif use_hw_flow - ser_tty[unit] && - ser_tty[unit]->t_cflag&CRTSCTS - /* doing flow control */ - ) { - serctl( unit, SERCTL_INHIB, - DMBIS ); /* blam */ - } - } else { - /* cts is now off */ - - /* we were inhibiting */ - if (*state & SERCTL_INHIB) { - *state&=~SERCTL_INHIB; - SER_DOCNTL( unit, 5, - ser_status[unit].wr[5] |= SER_W5_ENBTX ); - /* but not any more */ - } - } - ser_status[unit].dcts = 1; - } - - /* dcd */ - - if ( (!(reg0&SER_R0_DCD) && (*state&SERCTL_DCD)) - || ( (reg0&SER_R0_DCD) && !(*state&SERCTL_DCD))) { - -#ifdef DEBUG - if (DBG(unit)) - printf("d%c",reg0&SER_R0_DCD?'+':'-'); -#endif - - ser_status[unit].ddcd = 1; /* flag delta */ - - if (reg0&SER_R0_DCD) { - /* - * we have DCD - */ - - *state |= SERCTL_DCD; -#ifdef use_hw_flow - /* - * ... and need flow control - */ - if ( ser_tty[unit] - && ser_tty[unit]->t_cflag&CRTSCTS) { - /* TOO SLOW (but more understandable) */ - /* - serctl( unit, SERCTL_AUTO, DMBIS ); - serctl( unit, SERCTL_INHIB, DMBIC ); - */ - /* use the force, luke */ - *state &= ~SERCTL_INHIB; /* take that you scoundrel! */ - *state |= SERCTL_AUTO; /* and that! */ /* pow */ - SER_DOCNTL(unit,3,ser_status[unit].wr[3]|=SER_W3_AUTOEN); - SER_DOCNTL(unit,5,ser_status[unit].wr[5]&=~SER_W5_ENBTX); - /* blam */ - } -#endif use_hw_flow - } else { - /* - * we don't have DCD - */ - *state &= ~SERCTL_DCD; -#ifdef use_hw_flow - if (*state & SERCTL_AUTO) /* but, omigosh we need auto */ - { - /* we need to switch-over to manual inhibit */ - if (!(*state & SERCTL_CTS)){/* we have no cts */ - *state |= SERCTL_INHIB; /* so we need to inhibit tx */ - SER_DOCNTL(unit,5, - ser_status[unit].wr[5]|=SER_W5_ENBTX); - } - *state &= ~ SERCTL_AUTO; /* no more auto */ - SER_DOCNTL(unit,3,ser_status[unit].wr[3]&=~SER_W3_AUTOEN); - } -#endif use_hw_flow - } - } - - /* tx underrun */ - - if (reg0 & SER_R0_TXUNDERRUN) - SER_WRITEREG(unit, 0, SER_W0_RSTTXUNDERRUN); - - /* break */ - - if (reg0 & SER_R0_BREAK) { - /* - * breaks are now enqueued onto the receive queue - * and turned into a null with a framing error. - * XXX This seems to be broken XXX - * - * a point to note is that ext/stat interrupts are lower - * priority than tx or rx (at the scc level), but - * this should be okay - */ -#ifdef DEBUG - /*if (DBG(unit))*/ - printf("b"); -#endif - /* break leaves a null in the input fifo - this will be - * picked up when the break ends and sent to the disc */ - - *state |= SERCTL_INBRK; /* flag so that next rx knows is a brk */ - - } - - setsoftserial(); - ser_status[unit].intpend++; - - break; - - case SER_R2_RX: /* recv char available */ - - /* fast read of scc's hardware fifo - * this is actually a race between the cpu and the scc hardware - * that the cpu will most likely win - * - * We'll get an rxoverrun if our s/w buffer fills up first :( - */ - - for(c=0;c 1) { + if (ser_inlen[unit] < INBUFLEN) + ser_inbuf[unit][(ser_intail[unit] + (ser_inlen[unit]++)) % INBUFLEN] = ch1; + else ser_status[unit].oflo++; } + setsoftserial(); - if (reset_ext) SER_WRITEREG(unit, 0, SER_W0_RSTESINTS); - SER_WRITEREG(unit, 0, SER_W0_RSTIUS); + SER_DOCNTL(unit, 0, SER_W0_RSTIUS); + break; + case 3: /* spec recv condition */ + reg1 = SER_STATUS(unit, 1); + SCCRDWR(unit); /* flush fifo */ + if (reg1 & SER_R1_RXOVERRUN) + ser_status[unit].over++; + SER_DOCNTL(unit, 0, SER_W0_RSTERR); + SER_DOCNTL(unit, 0, SER_W0_RSTIUS); + break; + } - return(1); - /* end of serial interrupt code */ + return(1); + /* end of serial interrupt code */ } -/* - * serial software interrupt. do all the things we could - * not do at splscc(); - */ +/* serial software interrupt. do all the things we could + not do at splscc(); +*/ extern void sersir(void) @@ -945,108 +481,50 @@ sersir(void) int unit, s, c; register struct tty *tp; - for (unit = 0; unit < NSER; unit++) { + for (unit = 0; unit < 2; unit++) { if ((tp = ser_tty[unit]) == 0) continue; - if (!ser_status[unit].intpend) continue; -#ifdef DEBUG - /* if (DBG(unit)) printf(","); */ -#endif - s=splhigh(); - ser_status[unit].intpend--; - splx(s); - - /* - * check for change in CTS - * this done first when doing s/w crtscts flow - */ - - if (ser_status[unit].dcts) { - ser_status[unit].dcts = 0; - if ((tp->t_state & TS_ISOPEN) && (tp->t_flags & CRTSCTS)){ - if (ser_status[unit].state & SERCTL_CTS) { - tp->t_state &= ~TS_TTSTOP; - - /* - * next 3 lines not needed when AUTO flow is on, - * but it doesn't hurt - */ - serctl(unit, SERCTL_INHIB, DMBIC ); - - serstart(tp); - } else { - tp->t_state |= TS_TTSTOP; - } - } -#ifdef DEBUG - ser_dbg("cts",unit); -#endif - } - - /* - * check for overflows - */ + /* check for overflows */ if (ser_status[unit].oflo || ser_status[unit].over) { - int ooflo; s = splhigh(); - ooflo = ser_status[unit].oflo; ser_status[unit].oflo = 0; ser_status[unit].over = 0; splx(s); - /* where's _our_ flow control? */ - printf("ser%d: silo overflow, oflo = %d\n",unit,ooflo); if (tp->t_state & TS_ISOPEN) (*linesw[tp->t_line].l_rint)('#', tp); } - - /* - * check for change in DCD - */ - + /* check for change in DCD */ if (ser_status[unit].ddcd) { - s = splhigh(); ser_status[unit].ddcd = 0; splx(s); + if (0) { + if (ser_status[unit].dcd) + tp->t_state |= TS_CARR_ON; + else + tp->t_state &= ~TS_CARR_ON; - /* - * the sun3 (and sparc) ports also have a 8530 (zs) - * and in that code, the authors winge about the - * zilog hardware flow control braindeath syndrome. - * [when dcd goes low with hw flow tx is disabled] - * Their solution is to turn hfc off when dcd goes - * off. We do similar, but instead, allow a software - * flow control that tx and rx interrupts try to - * figure out - */ -#ifdef use_hw_flow - if (ser_status[unit].state & SERCTL_DCD) { - tp->t_state |= TS_CARR_ON; - if (tp->t_cflag&CRTSCTS) - serctl( tp->t_dev, SERCTL_AUTO, DMBIS ); - } else { - tp->t_state &= ~TS_CARR_ON; - if (tp->t_cflag&CRTSCTS) - serctl( tp->t_dev, SERCTL_AUTO, DMBIC ); + (*linesw[tp->t_line].l_modem)(tp, + ser_status[unit].dcd ? 1 : 0); } -#endif use_hw_flow - -#ifdef DEBUG - ser_dbg("carrier",unit); -#endif - (*linesw[tp->t_line].l_modem)(tp, - (ser_status[unit].state & SERCTL_DCD) ? 1 : 0); - } - - /* - * drain input fifo - */ + /* check for change in CTS */ + if (ser_status[unit].dcts) { + s = splhigh(); + ser_status[unit].dcts = 0; + splx(s); + if ((tp->t_state & TS_ISOPEN) && + (tp->t_flags & CRTSCTS)) { + tp->t_state &= ~TS_TTSTOP; + serstart(tp); + } else + tp->t_state |= TS_TTSTOP; + } + /* drain input fifo */ while (ser_inlen[unit] > 0) { if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) { setsoftserial(); - ser_status[unit].intpend++; break; } s = splhigh(); @@ -1054,21 +532,15 @@ sersir(void) ser_intail[unit] = (ser_intail[unit] + 1) % INBUFLEN; ser_inlen[unit]--; splx(s); -#ifdef DEBUG - if ( c&(TTY_FE|TTY_PE) || !c) - printf("ser%d: l_rint( %x, )\n", unit, c); -#endif if (tp->t_state & TS_ISOPEN) (*linesw[tp->t_line].l_rint)(c, tp); } - /* - * fill output fifo - */ + /* fill output fifo */ if (ser_outlen[unit] == 0) { if (tp->t_line) (*linesw[tp->t_line].l_start)(tp); else - serstart(tp); + serstart(tp); } } } @@ -1080,10 +552,10 @@ serioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) register int unit = UNIT(dev); register int error; - if (unit>NSER) return ENOTTY; - +#if defined(DEBUG) + printf("ser: entering ioctl()\n"); +#endif tp = ser_tty[unit]; - error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); if (error >= 0) return (error); @@ -1092,190 +564,111 @@ serioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) return (error); switch (cmd) { +#if 0 + case TIOCSBRK: /* turn break on */ + dca->dca_cfcr |= CFCR_SBREAK; + break; - case TIOCSBRK: /* turn break on */ - (void) serctl(dev, SERCTL_BRK, DMBIS); + case TIOCCBRK: /* turn break off */ + dca->dca_cfcr &= ~CFCR_SBREAK; + break; +#endif + case TIOCSDTR: /* set DTR */ + (void) serctl(dev, SER_W5_DTR | SER_W5_RTS, DMBIS); + break; + + case TIOCCDTR: /* clear DTR */ + (void) serctl(dev, SER_W5_DTR | SER_W5_RTS, DMBIC); + break; + + case TIOCMSET: /* set modem control bits */ + (void) serctl(dev, *(int *)data, DMSET); + break; + + case TIOCMBIS: /* OR bits on */ + (void) serctl(dev, *(int *)data, DMBIS); + break; + + case TIOCMBIC: /* AND bits off */ + (void) serctl(dev, *(int *)data, DMBIC); + break; + + case TIOCMGET: /* get modem bits */ + *(int *)data = serctl(dev, 0, DMGET); + break; + + case TIOCGFLAGS: + { + int bits = 0; + + *(int *)data = bits; break; - - case TIOCCBRK: /* turn break off */ - (void) serctl(dev, SERCTL_BRK, DMBIC); - break; - - case TIOCSDTR: /* set DTR */ - (void) serctl(dev, SERCTL_DTR | SERCTL_RTS, DMBIS); - break; - - case TIOCCDTR: /* clear DTR */ - (void) serctl(dev, SERCTL_DTR | SERCTL_RTS, DMBIC); - break; - - case TIOCGFLAGS: - { - int bits = 0; - - if (!tp) return(ENOTTY); - - /* - * the (possibly incorrect) strategy here is - * to keep the tty structure up to date - * with TIOC flags - */ - - if (tp->t_cflag&CLOCAL) { - bits|=TIOCFLAG_CLOCAL; - bits|=TIOCFLAG_SOFTCAR; - } - - if (tp->t_cflag&CRTSCTS) - bits|=TIOCFLAG_CRTSCTS; - - if (tp->t_cflag&MDMBUF) - bits|=TIOCFLAG_MDMBUF; - - - *(int *)data = bits; - break; - } + } case TIOCSFLAGS: - { - int userbits, driverbits = 0; + { + int userbits, driverbits = 0; - if (!tp) return(ENOTTY); - error = suser(p->p_ucred, &p->p_acflag); - if (error != 0) - return (EPERM); - - userbits = *(int *)data; - - if (userbits&(TIOCFLAG_CLOCAL|TIOCFLAG_SOFTCAR)) - tp->t_cflag |= CLOCAL; - else - tp->t_cflag &=~CLOCAL; - - if (userbits&TIOCFLAG_CRTSCTS) - tp->t_cflag |= CRTSCTS; - else - tp->t_cflag &=~CRTSCTS; - - if (userbits&TIOCFLAG_MDMBUF) - tp->t_cflag |= MDMBUF; - else - tp->t_cflag &=~MDMBUF; - - break; - } - -#ifdef allow_fiddle - case TIOCMSET: /* set modem control bits */ - (void) serctl(dev, *(int *)data, DMSET); + error = suser(p->p_ucred, &p->p_acflag); + if (error != 0) + return (EPERM); + userbits = *(int *)data; break; + } - case TIOCMBIS: /* OR bits on */ - (void) serctl(dev, *(int *)data, DMBIS); - break; - - case TIOCMBIC: /* AND bits off */ - (void) serctl(dev, *(int *)data, DMBIC); - break; - - case TIOCMGET: /* get modem bits */ - *(int *)data = serctl(dev, 0, DMGET); - break; -#endif allow_fiddle - - default: - return (ENOTTY); + default: +#if defined(DEBUG) + printf("ser%d: unknown ioctl(,0x%x,)\n", UNIT(dev), cmd); +#endif + return (ENOTTY); } +#if defined(DEBUG) + printf("ser: exiting ioctl()\n"); +#endif return (0); } static int -ser_apply_state( int unit ) +ser_calc_regs(int unit, int cflag, unsigned char *preg3, unsigned char *preg4, + unsigned char *preg5) { - int s, state = ser_status[unit].state; - struct tty*tp = ser_tty[unit]; unsigned char r3, r4, r5; - /* - * Here, we read the status bits from ser_status.state - * and write to write registers 3 4 and 5. - * In addition, we look at the tty struct (if any) - * and set up some stuff using that too. Basically, - * we bring the scc into line with what the flags are - */ - - r3 = r4 = r5 = 0; - - r4 |= SER_W4_CLKX16; /* XXX not the case with appletalk */ - - if (state&SERCTL_DTR) r5 |= SER_W5_DTR; - if (state&SERCTL_RTS) r5 |= SER_W5_RTS; - if (state&SERCTL_BRK) r5 |= SER_W5_BREAK; - - if (tp) { - - if (tp->t_cflag&CREAD) - r3 |= SER_W3_ENBRX; - - switch (tp->t_cflag&CSIZE) { - case CS5: - r3 |= SER_W3_RX5DBITS; - r5 |= SER_W5_TX5DBITS; - break; - case CS6: - r3 |= SER_W3_RX6DBITS; - r5 |= SER_W5_TX6DBITS; - break; - case CS7: - r3 |= SER_W3_RX7DBITS; - r5 |= SER_W5_TX7DBITS; - break; - case CS8: - r3 |= SER_W3_RX8DBITS; - r5 |= SER_W5_TX8DBITS; - break; - } - - if (tp->t_cflag & PARENB) - r4 |= (tp->t_cflag & PARODD)?SER_W4_PARODD:SER_W4_PAREVEN; - if (tp->t_cflag & CSTOPB) - r4 |= SER_W4_2SBIT; - else - r4 |= SER_W4_1SBIT; -#ifdef use_hw_flow - if (tp->t_cflag & CRTSCTS && state&SERCTL_DCD) - state|=SERCTL_AUTO; -#endif - if (tp->t_cflag & CRTSCTS && !state&SERCTL_CTS) - state|=SERCTL_INHIB; - } else { - /* we don't have a tty struct */ - r4 |= SER_W4_1SBIT; /* arbitary default of 8N1 */ + r3 = SER_W3_ENBRX; + r5 = SER_W5_ENBTX; + if (ser_status[unit].dtr) + r5 |= SER_W5_DTR; + if (ser_status[unit].rts) + r5 |= SER_W5_RTS; + switch (cflag&CSIZE) { + case CS5: + r3 |= SER_W3_RX5DBITS; + r5 |= SER_W5_TX5DBITS; + break; + case CS6: + r3 |= SER_W3_RX6DBITS; + r5 |= SER_W5_TX6DBITS; + break; + case CS7: + r3 |= SER_W3_RX7DBITS; + r5 |= SER_W5_TX7DBITS; + break; + case CS8: r3 |= SER_W3_RX8DBITS; r5 |= SER_W5_TX8DBITS; + break; } - - s = splhigh(); - - /* next two are fairly volatile */ - - if (!(state&SERCTL_INHIB)) - r5 |= SER_W5_ENBTX; -#ifdef use_hw_flow - if (state&SERCTL_AUTO) - r3 |= SER_W3_AUTOEN; -#endif - -#ifdef DEBUG - if (DBG(unit)) - printf("ser%d: apply w3<-%02x w4<-%02x w5<-%02x\n",unit,r3,r4,r5); - ser_dbg("apply",unit); -#endif - SER_WRITEREG(unit, 3, r3); - SER_WRITEREG(unit, 4, r4); - SER_WRITEREG(unit, 5, r5); - splx(s); + r4 = 0; + if(cflag & PARENB) + r4 |= (cflag & PARODD) ? SER_W4_PARODD : SER_W4_PAREVEN; + if(cflag & CSTOPB) + r4 |= SER_W4_2SBIT; + else + r4 |= SER_W4_1SBIT; + + *preg3 = r3; + *preg4 = r4; + *preg5 = r5; } static int @@ -1287,32 +680,44 @@ serparam(register struct tty *tp, register struct termios *t) int ospeed = t->c_ospeed; int s; +#if defined(DEBUG) + printf("ser: entering serparam()\n"); +#endif /* check requested parameters */ - if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)){ + if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)){ printf("ser: serparam() returning EINVAL\n"); - return (EINVAL); + return (EINVAL); } - /* and copy to tty */ - tp->t_ispeed = t->c_ispeed; - tp->t_ospeed = t->c_ospeed; - tp->t_cflag = cflag; + /* and copy to tty */ + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = cflag; /* Start of serial specific param code */ - if (ospeed == 0) { - serctl(unit, SERCTL_DTR , DMBIC); /* hang up line */ + if(ospeed == 0) { + serctl(unit, 0, DMSET); /* hang up line */ return(0); } serctl(unit, ospeed, SCC_SPEED); +/* + ser_calc_regs(unit, cflag, ®3, ®4, ®5); - ser_apply_state( unit ); - - /* serctl(unit, 1, SCC_INT); */ /* why? it should already be on */ - serctl(unit, SERCTL_DTR | SERCTL_RTS, DMSET); + s = splhigh(); + SER_DOCNTL(unit, 3, reg3); + SER_DOCNTL(unit, 4, reg4); + SER_DOCNTL(unit, 5, reg5); + splx(s); +*/ + serctl(unit, 1, SCC_INT); + serctl(unit, SER_W5_DTR | SER_W5_RTS, DMSET); /* End of serial specific param code */ +#if defined(DEBUG) + printf("ser: exiting serparam()\n"); +#endif return (0); } @@ -1325,7 +730,7 @@ serstart(register struct tty *tp) unit = UNIT(tp->t_dev); s = spltty(); if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) { - goto out; + goto out; } if (tp->t_outq.c_cc <= tp->t_lowat) { if (tp->t_state&TS_ASLEEP) { @@ -1335,12 +740,11 @@ serstart(register struct tty *tp) selwakeup(&(tp->t_wsel)); } if (tp->t_outq.c_cc == 0 || (tp->t_state & TS_BUSY) || - (ser_status[unit].state & SERCTL_BUSY)) { - goto out; - } + (ser_status[unit].flags & SER_BUSY)) + goto out; tp->t_state |= TS_BUSY; - if (ser_outlen[unit] == 0){ + if(ser_outlen[unit] == 0){ first_char = (char)getc(&tp->t_outq); need_start = 1; } else @@ -1354,7 +758,7 @@ serstart(register struct tty *tp) space = OUTBUFLEN - ser_outlen[unit]; splx(s1); - while (tp->t_outq.c_cc && space > 0) { + while(tp->t_outq.c_cc && space > 0) { /* note that getc goes spltty() */ c = getc(&tp->t_outq); /* protect s/w fifo at splhigh() */ @@ -1364,12 +768,12 @@ serstart(register struct tty *tp) splx(s1); space--; } - tp->t_state &= ~TS_BUSY; + if (need_start) { s1 = splhigh(); - ser_status[unit].state |= SERCTL_BUSY; - SCCRDWR(unit) = first_char; /* to start chain */ + ser_status[unit].flags |= SER_BUSY; + SCCRDWR(unit) = first_char; /* to start chain */ splx(s1); } @@ -1386,15 +790,17 @@ serstop(register struct tty *tp, int flag) { register int s; -#ifdef DEBUG - ser_dbg("serstop",UNIT(tp->t_dev)); +#if defined(DEBUG) + printf("ser: entering serstop()\n"); #endif - s = spltty(); if (tp->t_state & TS_BUSY) { if ((tp->t_state&TS_TTSTOP)==0) tp->t_state |= TS_FLUSH; } +#if defined(DEBUG) + printf("ser: exiting serstop()\n"); +#endif splx(s); } @@ -1407,73 +813,39 @@ serctl(dev_t dev, int bits, int how) /* run at splhigh so we don't get interrupted by i/o */ s = splhigh(); switch (how) { - case DMSET: - ser_status[unit].state = - (ser_status[unit].state & ~SERCTL_MASK)| - (bits&SERCTL_MASK); - ser_apply_state(unit); - break; - case DMBIS: - ser_status[unit].state = - (ser_status[unit].state)|(bits&SERCTL_MASK); - ser_apply_state(unit); - break; + case DMSET: + ser_status[unit].dtr = bits & SER_W5_DTR; + ser_status[unit].rts = bits & SER_W5_RTS; + SER_DOCNTL(unit, 5, bits | 0x68); + break; - case DMBIC: - ser_status[unit].state = - (ser_status[unit].state)&~(bits&SERCTL_MASK); - ser_apply_state(unit); - break; + case DMBIS: + break; - case DMGET: - bits = ser_status[unit].state; - break; + case DMBIC: + break; - case SCC_INT: -#ifdef DEBUG - if (DBG(unit)) - printf("ser%d: %s interrupts\n",unit, - bits?"enabling":"disabling"); -#endif - if (bits) { - /* - * Why not a channel reset? - * This would mean sending the initialisation string - * with a bit of a (tiny) delay after the chan reset - * In addition, cts/dcd might change which an - * external device plugged in might object to. - * - * soft-resetting all the flaggy bits should - * do the trick - */ - SER_WRITEREG(unit, 0, SER_W0_RSTESINTS| - SER_W0_RSTTXUNDERRUN); - SER_WRITEREG(unit, 0, SER_W0_RSTERR); - SER_WRITEREG(unit, 0, SER_W0_RSTIUS); - SER_WRITEREG(unit, 1, - SER_W1_ENBEXTINT | - /*either*/ SER_W1_ENBRXINT | - /*or*/ /*SER_W1_ENBR1INT |*/ - SER_W1_ENBTXINT | - 0); - SER_WRITEREG(unit, 15, - SER_W15_DCDINT| - SER_W15_CTSINT| - SER_W15_BRKINT| - 0); - ser_apply_state(unit); /* turn all the other stuff on */ - } else { - SER_WRITEREG(unit, 1, 0); /* disables all interrupts */ - SER_WRITEREG(unit, 15, 0); - } - break; - - case SCC_SPEED: - SER_WRITEREG(unit, 12, SERBRD(bits) & 0xff); - SER_WRITEREG(unit, 13, (SERBRD(bits) >> 8) & 0xff); - break; + case DMGET: + bits = SER_STATUS(unit, 0); + break; + /* */ + case SCC_INT: + if (bits) { + SER_DOCNTL(unit, 0, SER_W0_RSTERR); + SER_DOCNTL(unit, 0, SER_W0_RSTIUS); + SER_DOCNTL(unit, 1, + SER_W1_ENBEXTINT | + SER_W1_ENBRXINT | + SER_W1_ENBTXINT); + } else + SER_DOCNTL(unit, 1, 0); + break; + case SCC_SPEED: + SER_DOCNTL(unit, 12, SERBRD(bits) & 0xff); + SER_DOCNTL(unit, 13, (SERBRD(bits) >> 8) & 0xff); + break; } (void) splx(s); @@ -1484,23 +856,23 @@ serctl(dev_t dev, int bits, int how) * Console functions. */ -dev_t mac68k_serdev; +dev_t mac68k_serdev; sercnprobe(struct consdev *cp) { int maj, unit; for (maj = 0 ; maj < nchrdev ; maj++) { - if (cdevsw[maj].d_open == seropen) { - break; - } + if (cdevsw[maj].d_open == seropen) { + break; + } } if (maj == nchrdev) - goto nosercon; + goto nosercon; cp->cn_pri = CN_NORMAL; /* Lower than CN_INTERNAL */ if (mac68k_machine.serial_console & 0x01) - cp->cn_pri = CN_REMOTE; /* Higher than CN_INTERNAL */ + cp->cn_pri = CN_REMOTE; /* Higher than CN_INTERNAL */ unit = (mac68k_machine.serial_console & 0x02) ? 1 : 0; @@ -1513,7 +885,7 @@ nosercon: if (mac68k_machine.serial_boot_echo) { /* major number doesn't really matter. */ mac68k_serdev = makedev(maj, 0); - serinit(1); + serinit(1); } return 0; @@ -1521,29 +893,28 @@ nosercon: sercninit(struct consdev *cp) { - serinit(1); + serinit(1); } sercngetc(dev_t dev) { - int unit, c; + int unit, c; - unit = UNIT(dev); + unit = UNIT(dev); - while (!(SER_STATUS(unit, 0) & SER_R0_RXREADY)); - c = SCCRDWR(unit); - SER_STATUS(unit, 0) = SER_W0_RSTESINTS; + while (!(SER_STATUS(unit, 0) & SER_R0_RXREADY)); + c = SCCRDWR(unit); + SER_STATUS(unit, 0) = SER_W0_RSTESINTS; - return c; + return c; } sercnputc(dev_t dev, int c) { - int unit; + int unit; - unit = UNIT(dev); + unit = UNIT(dev); -gray_bar(); - while (!(SER_STATUS(unit, 0) & SER_R0_TXREADY)); - SCCRDWR(unit) = c; + while (!(SER_STATUS(unit, 0) & SER_R0_TXREADY)); + SCCRDWR(unit) = c; } diff --git a/sys/arch/mac68k/dev/serreg.h b/sys/arch/mac68k/dev/serreg.h index 1d5054aa78ce..fa544f63050e 100644 --- a/sys/arch/mac68k/dev/serreg.h +++ b/sys/arch/mac68k/dev/serreg.h @@ -1,9 +1,9 @@ -/* $NetBSD: serreg.h,v 1.6 1995/02/11 19:06:59 briggs Exp $ */ +/* $NetBSD: serreg.h,v 1.7 1995/04/08 13:20:56 briggs Exp $ */ /* - * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, - * Michael L. Finch, Bradley A. Grantham, and - * Lawrence A. Kesteloot + * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, + * Michael L. Finch, Bradley A. Grantham, and + * Lawrence A. Kesteloot * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -16,7 +16,7 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the Alice Group. + * This product includes software developed by the Alice Group. * 4. The names of the Alice Group or any of its members may not be used * to endorse or promote products derived from this software without * specific prior written permission. @@ -32,220 +32,77 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * Mac II serial device interface * - * Mac II serial device interface - * - * Information used in this source was gleaned from low-memory - * global variables in MacOS and the Advanced Micro Devices - * 1992 Data Book/Handbook. + * Information used in this source was gleaned from low-memory + * global variables in MacOS and the Advanced Micro Devices + * 1992 Data Book/Handbook. */ /* Gleaned from MacOS */ -extern volatile unsigned char *sccA; +extern volatile unsigned char *sccA; -/* - * Following information taken from Zilog's SCC User manal(1992) and the - * Zilog up and Peripherals databook (vol1/1992) - * - * Interrupt Source Priority: - * channel A rx -highest - * channel A tx - * channel A ext/status - * channel B rx - * channel B tx - * channel B ext/status -lowest - * - */ +#define SER_W0_RSTESINTS 0x10 /* Reset ext/status interrupts */ +#define SER_W0_ENBRXRDY 0x20 /* Enable interrupt on next receive */ +#define SER_W0_RSTTXPND 0x28 /* Reset transmit interrupt pending */ +#define SER_W0_RSTERR 0x30 /* Reset error */ +#define SER_W0_RSTIUS 0x38 /* Reset highest interrupt pending */ +#define SER_W0_RSTTXUNDERRUN 0xc0 /* Reset transmit underrun/EOM latch */ -/* - * Write register 0 (Command Register) - */ - -#define SER_W0_RSTESINTS 0x10 /* Reset ext/status interrupts */ - /* after an ext/status interrupt the - * status bits are latched into RR0 - * This re-enables the bits and allows - * further interrupts due to ext/status - * change - */ -#define SER_W0_ENBRXRDY 0x20 /* Enable interrupt on next receive */ - /* if using interrupt on 1st rx'd char - * then this is used to reactivate - * ints on rx after youve read the rx - * fifo, otherwise you get another int - * straight away if there's another - * rx char in the fifo - */ -#define SER_W0_RSTTXPND 0x28 /* Reset transmit interrupt pending */ - /* used when there are no more chars - * to be sent. used to stop the tx'er - * from int'ing when the tx buffer - * becomes empty (with tx ints enabl'd) - */ -#define SER_W0_RSTERR 0x30 /* Reset error */ - /* resets error bits in RR1. the datum - * assoc'd with the error is held in - * rx fifo and is lost after this cmd - */ -#define SER_W0_RSTIUS 0x38 /* Reset highest interrupt pending */ - /* used as the last cmd in an interrupt - * service: lets lower priority - * interrupts to request service - */ -#define SER_W0_RSTTXUNDERRUN 0xc0 /* Reset transmit underrun/EOM latch */ - /* when TX underrun/eom latch has been - * reset, the scc sends an abort and - * flag on underrun. this command resets - * that latch. - */ -/* - * Write register 1 (tx/rx interrupt and data transfer mode definition) - */ +#define SER_W1_ENBEXTINT 0x01 /* Enable external int */ +#define SER_W1_ENBTXINT 0x02 /* Enable transmit ready interrupt */ +#define SER_W1_ENBR1INT 0x08 /* Rx Int on first char/special cond */ +#define SER_W1_ENBRXINT 0x10 /* Rx Int on all chars/special cond */ -#define SER_W1_ENBEXTINT 0x01 /* Enable external int */ -#define SER_W1_ENBTXINT 0x02 /* Enable transmit ready interrupt */ -#define SER_W1_PARISSPEC 0x04 /* parity err is a special cond */ -#define SER_W1_ENBR1INT 0x08 /* Rx Int on first char/special cond */ -#define SER_W1_ENBRXINT 0x10 /* Rx Int on all chars/special cond */ +#define SER_W3_ENBRX 0x01 /* Enable reception */ +#define SER_W3_RX5DBITS 0x00 /* Receive 5 data bits */ +#define SER_W3_RX6DBITS 0x80 /* Receive 6 data bits */ +#define SER_W3_RX7DBITS 0x40 /* Receive 7 data bits */ +#define SER_W3_RX8DBITS 0xC0 /* Receive 8 data bits */ -/* - * Write register 2 (interrupt vector) - see WR9 - */ +#define SER_W4_PARNONE 0x00 /* No parity */ +#define SER_W4_PARODD 0x01 /* Odd parity */ +#define SER_W4_PAREVEN 0x03 /* Even parity */ +#define SER_W4_1SBIT 0x04 /* 1 stop bit */ +#define SER_W4_2SBIT 0x0c /* 2 stop bits */ -/* - * Write register 3 (rx parameters and Control) - * can read from RR9 with extended read option on (for eSCC) - */ +#define SER_W5_RTS 0x02 /* RTS enable */ +#define SER_W5_ENBTX 0x08 /* Enable transmission */ +#define SER_W5_BREAK 0x10 /* Send break */ +#define SER_W5_TX5DBITS 0x00 /* Send 5 data bits */ +#define SER_W5_TX6DBITS 0x40 /* Send 6 data bits */ +#define SER_W5_TX7DBITS 0x20 /* Send 7 data bits */ +#define SER_W5_TX8DBITS 0x60 /* Send 8 data bits */ +#define SER_W5_DTR 0x80 /* DTR enable */ -#define SER_W3_ENBRX 0x01 /* rx enable */ -#define SER_W3_AUTOEN 0x20 /* auto enable */ - /* causes CTS to become the tx - * enable and DCD to become the rx - * enable. - */ -#define SER_W3_RX5DBITS 0x00 /* Receive 5 data bits */ -#define SER_W3_RX6DBITS 0x80 /* Receive 6 data bits */ -#define SER_W3_RX7DBITS 0x40 /* Receive 7 data bits */ -#define SER_W3_RX8DBITS 0xC0 /* Receive 8 data bits */ +#define SER_W9_HWRESET 0xC0 /* Force Hardware Reset */ +#define SER_W9_NV 0x02 /* There is no interrupt vector */ +#define SER_W9_DLC 0x04 /* Disable lower interrupt chain */ +#define SER_W9_MIE 0x08 /* Enable master interrupt */ -/* - * Write Register 4 (tx/rx misc param and modes) - */ +#define SER_W10_NRZ 0x00 /* Set NRZ encoding */ +#define SER_W11_TXBR 0x80 /* Transmit clock is BR generator */ +#define SER_W11_RXBR 0x40 /* Receive clock is BR generator */ +#define SER_W14_ENBBR 0x01 /* Enable BR generator */ +#define SER_W15_ABRTINT 0x80 /* Abort pending interrups */ -#define SER_W4_PARNONE 0x00 /* No parity */ -#define SER_W4_PARODD 0x01 /* Odd parity */ -#define SER_W4_PAREVEN 0x03 /* Even parity */ -#define SER_W4_1SBIT 0x04 /* 1 stop bit */ -#define SER_W4_2SBIT 0x0c /* 2 stop bits */ -#define SER_W4_CLKX1 0x00 /* clock rate = data rate */ -#define SER_W4_CLKX16 0x40 /* clock rate = 16 * data rate */ -#define SER_W4_CLKX32 0x80 /* clock rate = 32 * data rate */ -#define SER_W4_CLKX64 0xc0 /* clock rate = 64 * data rate */ +#define SER_R0_RXREADY 0x01 /* Received character available */ +#define SER_R0_TXREADY 0x04 /* Ready to transmit character */ +#define SER_R0_DCD 0x08 /* Carrier detect */ +#define SER_R0_CTS 0x20 /* Clear to send */ +#define SER_R0_TXUNDERRUN 0x40 /* Tx Underrun/EOM */ -/* - * Write Register 5 (Tx params and control) - */ +#define SER_R1_RXOVERRUN 0x20 +#define SER_R1_PARITYERR 0x10 +#define SER_R1_CRCERR 0x40 +#define SER_R1_ENDOFFRAME 0x80 -#define SER_W5_RTS 0x02 /* RTS enable */ -#define SER_W5_ENBTX 0x08 /* Enable transmission */ -#define SER_W5_BREAK 0x10 /* Send break */ -#define SER_W5_TX5DBITS 0x00 /* Send 5 data bits */ -#define SER_W5_TX6DBITS 0x40 /* Send 6 data bits */ -#define SER_W5_TX7DBITS 0x20 /* Send 7 data bits */ -#define SER_W5_TX8DBITS 0x60 /* Send 8 data bits */ -#define SER_W5_DTR 0x80 /* DTR enable */ +#define SERBRD(x) (mac68k_machine.sccClkConst / (x) - 2) +#define SCCCNTL(unit) (sccA[2 - ((unit) << 1)]) +#define SCCRDWR(unit) (sccA[6 - ((unit) << 1)]) -/* - * Write register 8 (Transmit buffer) - */ - -/* - * Write Register 9 (Master interrupt control) - */ -#define SER_W9_ARESET 0x80 /* reset channel A */ -#define SER_W9_BRESET 0x40 /* reset channel A */ -#define SER_W9_HWRESET ( SER_W9_ARESET | SER_W9_BRESET ) /* both */ -#define SER_W9_NV 0x02 /* There is no interrupt vector */ -#define SER_W9_DLC 0x04 /* Disable lower interrupt chain */ -#define SER_W9_MIE 0x08 /* Enable master interrupt */ - /* (MIE is cleared on a HWRESET) */ - -/* Write Register 10 (Misc tx/rx control bits */ - -#define SER_W10_NRZ 0x00 /* Set NRZ encoding */ -#define SER_W10_URFLG 0x04 /* abort/flag on underrun (sdlc only) */ - -/* Write Register 11 (Clock mode control) */ - -#define SER_W11_TXBR 0x10 /* Transmit clock is BR generator */ -#define SER_W11_RXBR 0x40 /* Receive clock is BR generator */ - -/* Write Register 12 (Lower byte of baud constant) - * Write Register 13 (Upper byte of baud constant) - * Write Register 14 (Misc control of baud) - * - * The baud constant is computed by: - * - * Baud constant = ( clock_freq / ( 2* desired_rate * BR_clk_period )) - 2 - */ - -#define SERBRD(x) (mac68k_machine.sccClkConst / (x) -2 ) - -#define SER_W14_ENBBR 0x01 /* Enable BR generator */ - -/* - * Write Register 15 (Ext/ststus interrupt control) - */ - -#define SER_W15_DCDINT 0x08 /* enable DCD interrupts */ -#define SER_W15_CTSINT 0x20 /* enable CTS interrupts */ -#define SER_W15_BRKINT 0x80 /* Abort pending interrups */ - -/* - * Read Register 0 (tx/rx buffer status & ext status) - */ - -#define SER_R0_RXREADY 0x01 /* Received character available */ -#define SER_R0_TXREADY 0x04 /* Ready to transmit character */ -#define SER_R0_DCD 0x08 /* Carrier detect */ -#define SER_R0_CTS 0x20 /* Clear to send */ -#define SER_R0_TXUNDERRUN 0x40 /* Tx Underrun/EOM */ -#define SER_R0_BREAK 0x80 /* Break/abort */ - -#define SER_R1_RXOVERRUN 0x20 -#define SER_R1_PARITYERR 0x10 -#define SER_R1_CRCERR 0x40 -#define SER_R1_ENDOFFRAME 0x80 - -/* - * Read Register 2 - * channel A: is contents of WR2 - * channel B: is status of an interrupt (low here if WR9 appropriate) - */ - -#define SER_R2_MASK 0x06 /* what kind of int was it */ -#define SER_R2_TX 0x00 /* tx buffer empty */ -#define SER_R2_EXTCHG 0x02 /* external/status change */ -#define SER_R2_RX 0x04 /* rx char avail */ -#define SER_R2_SPEC 0x06 /* special recv condition */ - -#define SER_R2_CHANMASK 0x08 /* which channell caused int */ -#define SER_R2_CHANA 0x08 -#define SER_R2_CHANB 0x00 - -/* only from channel A */ -#define SER_R3_BIPES 0x01 /* chanB ext/stat interrupt pending */ -#define SER_R3_BIPTX 0x02 /* chanB tx ip */ -#define SER_R3_BIPRX 0x04 /* chanB rx ip */ -#define SER_R3_AIPES 0x08 /* chanA ext/stat interrupt pending */ -#define SER_R3_AIPTX 0x10 /* chanA tx ip */ -#define SER_R3_AIPRX 0x20 /* chanA rx ip */ - -#define SCCCNTL(unit) (sccA[2 - ((unit) << 1)]) -#define SCCRDWR(unit) (sccA[6 - ((unit) << 1)]) - -#define SER_DOCNTL(unit, reg, val) \ - SCCCNTL(unit) = (reg), SCCCNTL(unit) = (val) -#define SER_STATUS(unit, reg) \ - (SCCCNTL(unit) = (reg), SCCCNTL(unit)) +#define SER_DOCNTL(unit, reg, val) \ + {SCCCNTL(unit) = (reg); SCCCNTL(unit) = (val);} +#define SER_STATUS(unit, reg) \ + (SCCCNTL(unit) = (reg), SCCCNTL(unit))