[comp.sys.ibm.pc.rt] Patch to asych driver IBM/4.3

brunner@bullhead.uucp (07/22/89)

Subject: Fix for multiport asychronous driver
Index: /sys/caio/asy.c IBM/4.3

Description:
	Several problems exist with the December release of
	the multiport asychronous driver (rcsid 12.0):
	interrupts are lost, interrupts are not lost but
	characters are, buffers overflow, and spurious
	interrupts are generated. These problems are have
	been reported in several APARs, and degrade the
	performance of uucp, slip, tip, etc.

Fix:
	Apply these patchs to the files:

	/sys/ca/{autoconf.c, clock.c, machparam.h, trap.c}
	/sys/caio/{asy.c, asyreg.h}
	/sys/conf/param.c
	/sys/sys/kern_clock.c

	Note that this may be accomplished easiest from /sys,
	using the -p1 flag to patch, e.g.,

		patch -p1 < this_file

	A known timing bug is introduced with this fix for
	the 6150, due to a 2.4% error in the clock rate.
	This bug will be corrected in a following patch.

diff -r -c2 sys.ship/ca/autoconf.c sys.new/ca/autoconf.c
*** sys.ship/ca/autoconf.c	Wed Dec 14 18:23:39 1988
--- sys.new/ca/autoconf.c	Tue Jul 11 12:49:10 1989
***************
*** 12,15 ****
--- 12,17 ----
  #endif
  
+ 
+ #include <syslog.h>
  #include "reg.h"
  #include "pte.h"
***************
*** 219,223 ****
  		DEBUGF(autodebug & 0x01, printf("autoconf interrupt: level %x irq %d\n", int_level, int_irq));
  	} else {
! 		printf("Stray Interrupt! level=%d info=%x", s & 07, info);
  		if (iodebug & 0x01)
  			printf(" icscs=%x iar=%x", icscs, iar);
--- 221,225 ----
  		DEBUGF(autodebug & 0x01, printf("autoconf interrupt: level %x irq %d\n", int_level, int_irq));
  	} else {
! 		log(LOG_WARNING, "Stray Interrupt! level=%d info=%x", s & 07, info);
  		if (iodebug & 0x01)
  			printf(" icscs=%x iar=%x", icscs, iar);
***************
*** 577,581 ****
  			}
  		}
! 		printf("8259 (%x) IRQ %d: %s ", i, irq, s ? "no SLIH" : "unclaimed");
  	}
  	i = devunk((int)table, iar, icscs);
--- 579,583 ----
  			}
  		}
! 		log(LOG_WARNING, "8259 (%x) IRQ %d: %s ", i, irq, s ? "no SLIH" : "unclaimed");
  	}
  	i = devunk((int)table, iar, icscs);
***************
*** 783,787 ****
  		if (*t == addr && addr != (caddr_t) PROBE_NULL)
  			return (PROBE_BAD); /* oops, already in use */
- 	*t = addr;			  /* device found - remember it's address */
  	if (id->idr_probe == 0) {
  		DEBUGF(autodebug, printf("no probe routine - ignored\n"));
--- 785,788 ----
***************
*** 798,801 ****
--- 799,803 ----
  /* fall thru */
  	case PROBE_NOINT:
+ 		*t = addr;	  /* device found - remember it's address */
  		break;
  	default:
diff -r -c2 sys.ship/ca/clock.c sys.new/ca/clock.c
*** sys.ship/ca/clock.c	Fri Dec  9 14:46:06 1988
--- sys.new/ca/clock.c	Tue Jul 11 12:48:01 1989
***************
*** 14,17 ****
--- 14,18 ----
  /*     clock.c 6.1     83/07/29        */
  
+ 
  #include "param.h"
  #include "time.h"
***************
*** 117,122 ****
  {
  
! 	if (tick * hz != MICROSECSEC)
  		panic("MICROSECSEC % hz not 0");
  
  	if (phz)
--- 118,125 ----
  {
  
! 	if (tick * hz != MICROSECSEC) {
! 		printf("startrtclock: hz = %d\ntick= %d\n", hz, tick);
  		panic("MICROSECSEC % hz not 0");
+ 	}
  
  	if (phz)
***************
*** 156,160 ****
  }
  
! #if defined(ATR) && !defined(GPROF)
  /*
   * adjust the tick count to account for the incorrect tick frequency
--- 159,163 ----
  }
  
! #if !defined(GPROF)
  /*
   * adjust the tick count to account for the incorrect tick frequency
***************
*** 161,165 ****
   * on the 6152
   */
! #define HZ	64		/* number of clock tics/second */
  adjtick()
  {
--- 164,168 ----
   * on the 6152
   */
! #define HZ	100		/* number of clock tics/second */
  adjtick()
  {
diff -r -c2 sys.ship/ca/machparam.h sys.new/ca/machparam.h
*** sys.ship/ca/machparam.h	Fri Dec  9 14:47:21 1988
--- sys.new/ca/machparam.h	Tue Jul 11 12:50:27 1989
***************
*** 11,15 ****
  static char *rcsidca_param = "$Header: V1.3,v 1.1 89/07/14 15:15:50 brunner Locked $";
  #endif
- 
  /*
   * IMPORTANT NOTE:
--- 11,14 ----
***************
*** 101,110 ****
  char	ccr_default;		/* default value for CCR */
  
! #ifndef ATR
! #define spltty() spl1()
! #define splttl() spl5()
! #else 
! #define spltty() spl5()
! #endif ATR
  #define splclock() spl6()
  #define splbio()	_spl1()
--- 100,105 ----
  char	ccr_default;		/* default value for CCR */
  
! #define splttl() spl4()
! #define spltty() spl4()
  #define splclock() spl6()
  #define splbio()	_spl1()
diff -r -c2 sys.ship/ca/trap.c sys.new/ca/trap.c
*** sys.ship/ca/trap.c	Fri Dec  9 14:45:57 1988
--- sys.new/ca/trap.c	Tue Jul 11 12:48:41 1989
***************
*** 11,15 ****
  static char *rcsid = "$Header: V1.3,v 1.1 89/07/14 15:15:50 brunner Locked $";
  #endif
- 
  #if defined(DEBUG) && !defined(SYSCALLTRACE)
  #define SYSCALLTRACE
--- 11,14 ----
***************
*** 707,716 ****
  			softkls();
  		}
- #if NASY > 0
- 		if (softlevel & SOFT_ASY) {
- 			softlevel &= ~SOFT_ASY;
- 			softasy();
- 		}
- #endif NASY
  #if NPSP > 0
  		if (softlevel & SOFT_PSP) {
--- 706,709 ----
diff -r -c2 sys.ship/caio/asy.c sys.new/caio/asy.c
*** sys.ship/caio/asy.c	Fri Dec  9 14:50:57 1988
--- sys.new/caio/asy.c	Tue Jul 11 12:52:24 1989
***************
*** 11,15 ****
  static char *rcsid = "$Header: V1.3,v 1.1 89/07/14 15:15:50 brunner Locked $";
  #endif
- 
  /*
   * Multiport asynchronous driver
--- 11,14 ----
***************
*** 17,20 ****
--- 16,20 ----
  #include "asy.h"
  #if NASY > 0
+ 
  #include "../h/param.h"
  #include "../h/conf.h"
***************
*** 28,31 ****
--- 28,32 ----
  #include "../h/file.h"
  #include "../machine/debug.h"
+ #include <syslog.h>
  
  #ifdef ATR
***************
*** 102,108 ****
    */
  #define NPORTS	4		/* number of serial port per multiport card */
! #define MAXUNIT (NASY * NPORTS)	/* total number of ports configured */
  struct cbuf asycbuf[MAXUNIT];
- struct clist asyxclist;
   /*
    * Terminology:
--- 103,109 ----
    */
  #define NPORTS	4		/* number of serial port per multiport card */
! #define MAXCTLR 6		/* total ctrl cards */
! #define MAXUNIT 18		/* total number of ports configured */
  struct cbuf asycbuf[MAXUNIT];
   /*
    * Terminology:
***************
*** 134,144 ****
  #define PORT(unit)		((unit) & 0x03)
  #define PORTMASK(port)		((1 << (port)) & 0x0f) 
  struct tty asy[MAXUNIT];
! int	nasy = MAXUNIT;
  
  #if NAP > 0
  int asyoutc();
  #endif
! int asystart(), ttrstrt(), asyattach(), asyprobe(), asyint();
  
  /* following is a hokey test for a quad card */
--- 135,161 ----
  #define PORT(unit)		((unit) & 0x03)
  #define PORTMASK(port)		((1 << (port)) & 0x0f) 
+ 
+ 
  struct tty asy[MAXUNIT];
! /* Average new into old with aging factor time */
! #define	ave(smooth, cnt, time) \
! 	smooth = ((time - 1) * (smooth) + (cnt)) / (time)
! #define	FASTTIMER	(hz/100) /* scan rate with silos on */
! #define	SLOWTIMER	(hz)    /* scan rate without silos on */
! int	asysilos = 0;		/* mask of ports with silo in use */
! int	asytimeout = 0;		/* mask ports with enq timeout set */
! int	asychars[MAXUNIT];	/* recent input count */
! int	asyinchars[MAXUNIT];	/* previous input count */
! int	asyrate[MAXUNIT];	/* smoothed input count */
! int	asyhighrate = 100;	/* silo on if dhchars >= dhhighrate */
! int     asylowrate = 15;
! int 	asyfasttimers = 0;  /*DEBUG*/
! static short timerstarted;
  
+ 
  #if NAP > 0
  int asyoutc();
  #endif
! int asystart(), ttrstrt(), asyattach(), asyprobe(), asyint(), asytimer();
  
  /* following is a hokey test for a quad card */
***************
*** 201,212 ****
  	BADD_ADDR, BADD_ADDR, BADD_ADDR, BADD_ADDR, /* 12 - 15 */
  };
- #define ASYFIFO	1	    /* RT can have FIFO cards */
  #endif IBMRTPC
  
! char asysoftCAR[NASY];	    /*  software carrier detect  */
! #ifdef ASYFIFO
! unsigned char asysoftFIFO[NASY];	/*  software - FIFO mode */
! #define fifomode 0xff 
! #endif 
  
  struct iocc_device *asydinfo[NASY];
--- 218,225 ----
  	BADD_ADDR, BADD_ADDR, BADD_ADDR, BADD_ADDR, /* 12 - 15 */
  };
  #endif IBMRTPC
  
! char asysoftCAR[NASY];	    		/*  software carrier detect  */
! unsigned char asysoftFIFO[MAXUNIT];	/*  software - FIFO mode */
  
  struct iocc_device *asydinfo[NASY];
***************
*** 230,233 ****
--- 243,247 ----
  
  	DEBUGF(ttydebug, printf("asyprobe(%x):\n", addr));
+ 	
  
  	if (isquad(asyp)) {
***************
*** 290,293 ****
--- 304,308 ----
  	register int ctlr = iod->iod_unit;
  	register int port;  /* line number on this ctlr */
+ 	register int saveiir;
  	register struct asydevice *addr = ASY_ADDR(iod->iod_addr);
  
***************
*** 300,310 ****
  		tp->t_cbufp = &asycbuf[UNIT(ctlr,port)];
  		tp->t_state = 0;
  		if (!isquad(addr))
  			break;	       /* only one port per PC card */
  	}
- 	asysoftCAR[iod->iod_unit] = iod->iod_flags; /* carrier detect */
  }
  
- 
  /*ARGSUSED*/
  asyopen(dev, flag)
--- 315,337 ----
  		tp->t_cbufp = &asycbuf[UNIT(ctlr,port)];
  		tp->t_state = 0;
+ 		/* these instructions have no effect on non-FIFO card */
+ 		/* clear fifos */
+ 		IOOUT(&addr->fcr, FCR_FCR1|FCR_FCR2);
+  		/* enable FIFO mode, interrupt at 14 chars */
+  		IOOUT(&addr->fcr,
+ 			FCR_FCR0|FCR_FCR6|FCR_FCR7);
+ 		saveiir=IOIN(&addr->iir) ;
+  		if (saveiir & (IIR_FIFO1 | IIR_FIFO2)) {
+  			++asysoftFIFO[UNIT(ctlr,port)];	
+ 		}
+ 		else
+ 			asysoftFIFO[UNIT(ctlr,port)] = 0;
+ 				
+ 		asysoftCAR[iod->iod_unit] = iod->iod_flags; /* carrier detect */
  		if (!isquad(addr))
  			break;	       /* only one port per PC card */
  	}
  }
  
  /*ARGSUSED*/
  asyopen(dev, flag)
***************
*** 313,321 ****
  	register struct tty *tp;
  	register int unit = minor(dev);
! 	register int s, error;
  	register struct asydevice *asyaddr;
  	register struct iocc_device *iod;
  	int ctlr = CTLR(unit);
-  	register unsigned char saveiir;
  
  	DEBUGF(ttydebug & SHOW_OPEN, printf("asyopen%x: \n", unit));
--- 340,347 ----
  	register struct tty *tp;
  	register int unit = minor(dev);
! 	register int s, msrbits, error;
  	register struct asydevice *asyaddr;
  	register struct iocc_device *iod;
  	int ctlr = CTLR(unit);
  
  	DEBUGF(ttydebug & SHOW_OPEN, printf("asyopen%x: \n", unit));
***************
*** 346,383 ****
   
  		asyparam(unit);
- 		/* turn DTR RTS on */
- 		IOOUT(&asyaddr->mcr, MCR_IEN | MCR_DTR | MCR_RTS);
  
  		/* enable receive, line, modem and transmit interrupts */
  		IOOUT(&asyaddr->ier, IER_DR | IER_LSR | IER_MSR | IER_THRE);
! 
! #ifdef ASYFIFO
!  		/* enable FIFO mode */
!                 /* This has no effect for a non-buffered card. */
!  		IOOUT(&asyaddr->fcr, FCR_FCR0);
! #endif ASYFIFO
!  
  		(void) splx(s);
  	} 
- 
  	s = spl_asy();
  	/* wait for carrier to come up */
- 	/* check if modem control is on or the carrier is up */
- 	if ( ( (IOIN(&asyaddr->msr)) & MSR_DCD) ||
-  	     ( asysoftCAR[ctlr] & PORTMASK(PORT(unit)) ) ) {
-  	      		tp->t_state |= TS_CARR_ON;
-  			saveiir=IOIN(&asyaddr->iir) ;
- #ifdef ASYFIFO
-  			if (saveiir & (IIR_FIFO1 | IIR_FIFO2)) {
-  			asysoftFIFO[ctlr] = fifomode;	
-  			DEBUGF(ttydebug & SHOW_OPEN,
-  				printf("asyopen - fifomode\n"));
- 			}
- #endif ASYFIFO
-  		}
- 
  	while ( (tp->t_state & TS_CARR_ON) == 0 ) {
  		tp->t_state |= TS_WOPEN;
! 		sleep((caddr_t) & tp->t_rawq, TTIPRI);
  	}
  	(void) splx(s);
--- 372,401 ----
   
  		asyparam(unit);
  
+       	    	if (asysoftFIFO[unit]) {
+ 			/* flush FIFO */
+ 			IOOUT(&asyaddr->fcr, FCR_FCR1|FCR_FCR2);
+  			/* enable FIFO mode, interrupt at 1 chars */
+  			IOOUT(&asyaddr->fcr, FCR_FCR0);
+ 		}
  		/* enable receive, line, modem and transmit interrupts */
  		IOOUT(&asyaddr->ier, IER_DR | IER_LSR | IER_MSR | IER_THRE);
! 		/* turn DTR RTS on */
!      		if (isquad(asyaddr))
! 			IOOUT(&asyaddr->mcr, MCR_DTR | MCR_RTS);
! 		else
! 			IOOUT(&asyaddr->mcr, MCR_IEN | MCR_DTR | MCR_RTS);
  		(void) splx(s);
  	} 
  	s = spl_asy();
+ 	/* check if carrier is or up modem is on */
+ 	msrbits = IOIN(&asyaddr->msr);
+ 	if ((msrbits & MSR_DCD) || 
+  	     ( asysoftCAR[ctlr] & PORTMASK(PORT(unit)) ) ) 
+  		tp->t_state |= TS_CARR_ON;
  	/* wait for carrier to come up */
  	while ( (tp->t_state & TS_CARR_ON) == 0 ) {
  		tp->t_state |= TS_WOPEN;
! 		sleep((caddr_t) &tp->t_rawq, TTIPRI);
  	}
  	(void) splx(s);
***************
*** 389,392 ****
--- 407,414 ----
  	DEBUGF(ttydebug & SHOW_OPEN, printf(" ldisc=%x, flags=%x, state=%x\n",
  		tp->t_line, tp->t_flags, tp->t_state ));
+ 	if (timerstarted == 0) {
+ 		timeout(asytimer, (caddr_t) 0, SLOWTIMER);
+ 		++timerstarted;
+ 	}
  	return ( error );
  }
***************
*** 406,411 ****
--- 428,436 ----
  
  	tp->t_state |= TS_CLOSE;		/* close in progress */
+ 	asychars[unit] = 0;
+ 	asysilos &= ~(1 << unit);
  
  	timeout(asycls, tp, asyouttime(tp));	/* set timeout for close */
+ 
  	(*linesw[tp->t_line].l_close)(tp);
  	IOOUT(&asyaddr->lcr, IOIN(&asyaddr->lcr) & ~LCR_SETB);  /* clr break */
***************
*** 412,416 ****
  	if ((tp->t_state&(TS_WOPEN|TS_HUPCLS))||(tp->t_state&TS_ISOPEN)==0) {
  		IOOUT(&asyaddr->ier, ~(IER_DR | IER_LSR | IER_MSR) );
! 		IOOUT(&asyaddr->mcr, MCR_IEN);
   		IOOUT(&asyaddr->fcr, ~(FCR_FCR0));
  		DEBUGF(ttydebug & SHOW_OPEN, 
--- 437,444 ----
  	if ((tp->t_state&(TS_WOPEN|TS_HUPCLS))||(tp->t_state&TS_ISOPEN)==0) {
  		IOOUT(&asyaddr->ier, ~(IER_DR | IER_LSR | IER_MSR) );
!      		if (isquad(asyaddr))
! 			IOOUT(&asyaddr->mcr, 0);
! 		else
! 			IOOUT(&asyaddr->mcr, MCR_IEN);
   		IOOUT(&asyaddr->fcr, ~(FCR_FCR0));
  		DEBUGF(ttydebug & SHOW_OPEN, 
***************
*** 425,429 ****
--- 453,515 ----
  }
  
+ int asyfasttimers, asytransitions, asyslowtimers, asybogons;  /*DEBUG*/
  /*
+  * At software clock interrupt time, check status.
+  * Empty all the asy silos that are in use, and decide whether
+  * to turn any silos off or on.
+  */
+ asytimer()
+ {
+ 	register int unit = 0, s;
+ 	static int timercalls;
+ 	register struct tty *tp;
+ 	register struct asydevice *asyaddr;
+ 
+ 	if (asysilos) {
+ 		s = spl_asy();
+ 		asyfasttimers++;		/*DEBUG*/
+ 		timercalls++;
+ 		for (unit = 0; unit < MAXUNIT; unit++)
+ 			if (asysilos & (1 << unit)) {
+ 			   tp = &asy[unit];
+ 			   asychars[unit] += asyrint(unit, tp,
+ 					(struct asydevice *)tp->t_addr);
+ 			}
+ 		splx(s);
+ 	}
+ 	if ((asysilos == 0) || ((timercalls+=FASTTIMER) >= SLOWTIMER)) {
+ 		asyslowtimers++;		/*DEBUG*/
+ 		timercalls = 0;
+ 		for (unit = 0; unit < MAXUNIT; unit++) {
+ 		    ave(asyrate[unit], asychars[unit], 8);
+ 		    if ((asychars[unit] >= asyhighrate) &&
+ 		      ((asysilos & (1 << unit)) == 0)) {
+ 			asysilos |= (1 << unit);
+ 			asytransitions++;		/*DEBUG*/
+       	    		if (asysoftFIFO[unit]) {
+ 			   	tp = &asy[unit];
+ 				asyaddr = (struct asydevice *)tp->t_addr;
+  				/* FIFO mode, trigger at 14 chars */
+  				IOOUT(&asyaddr->fcr,
+ 					FCR_FCR0|FCR_FCR6|FCR_FCR7);
+ 			}
+ 		    } else if ((asysilos & (1 << unit)) &&
+ 		      (asyrate[unit] < asylowrate)) {
+ 			asysilos &= ~(1 << unit);
+       	    		if (asysoftFIFO[unit]) {
+ 			   	tp = &asy[unit];
+ 				asyaddr = (struct asydevice *)tp->t_addr;
+  				/* FIFO mode, trigger at 1 char */
+  				IOOUT(&asyaddr->fcr, FCR_FCR0);
+ 			}
+ 		    }
+ 		    asychars[unit] = 0;
+ 		}
+ 	}
+ 	timeout(asytimer, (caddr_t) 0, asysilos? FASTTIMER: SLOWTIMER);
+ }
+ 
+ 
+ /*
   * return an overestimate of the number of clock ticks it will take
   * to output the remaining output after close has started
***************
*** 450,454 ****
  	if (tp->t_state & TS_CLOSE) {		/* if close in progress */
  		ttyflush(tp, FREAD|FWRITE);
! 		tp->t_state &= ~TS_CLOSE;		/* close in progress */
  	}
  	(void) splx(s);
--- 536,540 ----
  	if (tp->t_state & TS_CLOSE) {		/* if close in progress */
  		ttyflush(tp, FREAD|FWRITE);
! 		tp->t_state = 0;
  	}
  	(void) splx(s);
***************
*** 455,458 ****
--- 541,545 ----
  }
  
+ 
  /*ARGSUSED*/
  asyread(dev, uio)
***************
*** 524,531 ****
  		break;
  	case TIOCSDTR:		       /* Set DTR and RTS */
! 		IOOUT(&asyaddr->mcr, MCR_IEN | MCR_DTR | MCR_RTS);
  		break;
  	case TIOCCDTR:		       /* Clear DTR and RTS */
! 		IOOUT(&asyaddr->mcr, MCR_IEN);
  		break;
   	case TIOCSETT:		       /* Set trigger level */
--- 611,624 ----
  		break;
  	case TIOCSDTR:		       /* Set DTR and RTS */
!      		if (isquad(asyaddr))
! 			IOOUT(&asyaddr->mcr, MCR_DTR | MCR_RTS);
! 		else
! 			IOOUT(&asyaddr->mcr, MCR_IEN | MCR_DTR | MCR_RTS);
  		break;
  	case TIOCCDTR:		       /* Clear DTR and RTS */
!      		if (isquad(asyaddr))
! 			IOOUT(&asyaddr->mcr, 0);
! 		else
! 			IOOUT(&asyaddr->mcr, MCR_IEN);
  		break;
   	case TIOCSETT:		       /* Set trigger level */
***************
*** 541,546 ****
   				else 
    					trigger_bits = (FCR_FCR7 | FCR_FCR6);
!  			
!  		IOOUT(&asyaddr->fcr, (FCR_FCR0 | FCR_FCR3 | trigger_bits));
   		break;	
  	default:
--- 634,638 ----
   				else 
    					trigger_bits = (FCR_FCR7 | FCR_FCR6);
!  		IOOUT(&asyaddr->fcr, (FCR_FCR0 | trigger_bits));
   		break;	
  	default:
***************
*** 599,603 ****
  	register int ctlr;
  {
- 	register unsigned char port;
  	register int unit = UNIT(ctlr,0);
  	register struct asydevice *asyaddr = ASY_ADDR(asydinfo[ctlr]->iod_addr);
--- 691,694 ----
***************
*** 604,608 ****
  	register struct tty *tp;
  	register unsigned char saveiir;
! 	register int i, didit = 0;
  
  #ifdef ATR
--- 695,701 ----
  	register struct tty *tp;
  	register unsigned char saveiir;
! 	register unsigned char port = 0;
! 	register char c;
! 	register int counter;
  
  #ifdef ATR
***************
*** 617,687 ****
  	DEBUGF(ttydebug & SHOW_INTR,printf("asyint%d: addr=%x ",unit,asyaddr));
  #ifdef IBMRTPC
! 	if (isquad(asyaddr)) {
! 		port = IOIN(&asyaddr->ppir);
  		DEBUGF(ttydebug & SHOW_INTR, printf("port=%x ",port));
! 		for ( i = 0 ; i < NPORTS ; i++, unit++ ) {
! 			if (port & PORTMASK(i) ) {
! 				tp = &asy[unit];
! 				asyaddr = (struct asydevice *)tp->t_addr;
! 				while (((saveiir=IOIN(&asyaddr->iir))&IIR_PEND)==0) {
! 					DEBUGF(ttydebug & SHOW_REGS, 
! 					    printf("saveiir=%x\n", saveiir));
! 					switch (saveiir & IIR_MASK) {
! 					case IIR_LSR:
! 					case IIR_CTI:
! 					case IIR_RXB:
! 						asyrint(unit, tp, asyaddr);
! 						didit++;
! 						break;
! 					case IIR_TXB:
! 						asyxint(unit, tp, asyaddr);
! 						didit++;
! 						break;
! 					case IIR_MSR:
! 						asymint(unit, tp, asyaddr);
! 						didit++;
! 						break;
! 					default:
! 						printf("asy%d:iir=%x\n",unit,saveiir);
! 						break;
! 					}
! 				}
  			}
  		}
! 		if (!isquad(asyaddr)) {
! 		    if ( didit )
! 			IOOUT(asyreset[asydinfo[ctlr]->iod_irq & 0xf], 0);
! 		    }
! 	} else 
  #endif IBMRTPC
! 	{
! 		tp = &asy[unit];
! 		asyaddr = (struct asydevice *)tp->t_addr;
! 		while (( (saveiir=IOIN(&asyaddr->iir) ) & IIR_PEND) == 0) {
! 			switch (saveiir & IIR_MASK) {
! 			case IIR_LSR:
! 			case IIR_RXB:
! 				asyrint(unit, tp, asyaddr);
! 				didit++;
! 				break;
! 			case IIR_TXB:
! 				asyxint(unit, tp, asyaddr);
! 				didit++;
! 			break;
! 			case IIR_MSR:
! 				asymint(unit, tp, asyaddr);
! 				didit++;
! 				break;
! 			default:
! 				printf("asy%d:iir=%x\n",unit,saveiir);
! 				break;
  			}
  		}
! 	}
! 	DEBUGF(ttydebug & SHOW_INTR, printf("didit=%x\n",didit ));
! 	return( didit == 0 );
  }
  
  /*ARGSUSED*/
  asyrint(unit, tp, asyaddr)
  	register int unit;
--- 710,793 ----
  	DEBUGF(ttydebug & SHOW_INTR,printf("asyint%d: addr=%x ",unit,asyaddr));
  #ifdef IBMRTPC
!      	if (isquad(asyaddr)) {
!     		port = IOIN(&asyaddr->ppir);
!     		port &= 0x0F;
  		DEBUGF(ttydebug & SHOW_INTR, printf("port=%x ",port));
! 		if (0 == port) {
! 			saveiir = IOIN(&asyaddr->iir);
! 			if ((0xC0 & saveiir)||(0x01 == saveiir))
! 				;
! 			else {
! 				log(LOG_WARNING,
! 			     "asyint: no ppir, saveiir = %x\n",
! 					saveiir);
  			}
+ 			return(0);
  		}
! portselect:
! 		if (port & PORT_A) {
! 	    		unit = UNIT(ctlr,0);
! 			port &= ~PORT_A;
! 		}
! 		else if (port & PORT_B) {
! 	    		unit = UNIT(ctlr,1);
! 			port &= ~PORT_B;
! 		}
! 		else if (port & PORT_C) {
! 	    		unit = UNIT(ctlr,2);
! 			port &= ~PORT_C;
! 		}
! 		else if (port & PORT_D) {
! 	    		unit = UNIT(ctlr,3);
! 			port &= ~PORT_D;
! 		}
! 		else {
! 	    		unit = UNIT(ctlr,0);
! 			printf("asyint: Bogus port = %x\n", port);
! 		}
! 	}
  #endif IBMRTPC
! 	tp = &asy[unit];
! 	asyaddr = (struct asydevice *)tp->t_addr;
! 	saveiir = IOIN(&asyaddr->iir);
! 	if (IIR_PEND & saveiir) { 
! 		++asybogons;
! 		return(0);
! 	}
!      	counter = asychars[unit];
! 	do {
! 		switch (saveiir & IIR_MASK) {
! 		   case IIR_RXB:
!      			while (IOIN(&asyaddr->lsr) & LSR_DR) {
! 				c = IOIN(&asyaddr->rxb);
! 				(*linesw[tp->t_line].l_rint)(c,tp);
! 				++counter;
  			}
+      			break;
+      		   case IIR_LSR:
+      		   case IIR_CTI:
+      			counter += asyrint(unit, tp, asyaddr);
+      			break;
+      		   case IIR_TXB:
+      			asyxint(unit, tp, asyaddr);
+      			break;
+      		   case IIR_MSR:
+      			asymint(unit, tp, asyaddr);
+      			break;
+ 		   default:
+ 			printf("asy%d:iir=%x\n",unit,saveiir);
+ 			break;
  		}
! 	} while (((saveiir=IOIN(&asyaddr->iir))&IIR_PEND)==0);
!      	asychars[unit] = counter;
! #ifdef IBMRTPC
! 	if ((port) && isquad(asyaddr))
! 		goto portselect; /*more than one port pending*/
! #endif
! 	return(0);
  }
  
  /*ARGSUSED*/
+ int
  asyrint(unit, tp, asyaddr)
  	register int unit;
***************
*** 689,693 ****
  	register struct asydevice *asyaddr;
  {
! 	register int c, err;
  	register char savelsr;
  	int charcount = 0;
--- 795,799 ----
  	register struct asydevice *asyaddr;
  {
! 	register int c;
  	register char savelsr;
  	int charcount = 0;
***************
*** 728,750 ****
  
  			if (savelsr & LSR_OR)
! 				printf("asy%d: overrun error\n", unit );
  			DEBUGF(ttydebug & SHOW_CHARS, 
  				printf("GOT -> (%c) (%x)\n", c, c));
  		} /* end if errors */
! 		DEBUGF(ttydebug & SHOW_REGS, printf("TTYBUF\n")); 
! 		charcount++;
! 		CPUT( tp->t_cbufp, c, err );
! 		if ( err ) {
! 			printf("asy%d: cbuf full\n", unit ); 
! 			break;
! 		}
  	        } /* end else */
  	} /* end while */
- 	if ( charcount ) {
- 		TTY_ENQUEUE( &ttyintrq, tp );
- 		setsoftTTY();
- 	}
  	DEBUGF(ttydebug & SHOW_INTR, 
  		printf("asy%d: charcount=%d\n",unit,charcount));
  }
  
--- 834,849 ----
  
  			if (savelsr & LSR_OR)
! 				log(LOG_WARNING, "asy%d: overrun\n", unit);
  			DEBUGF(ttydebug & SHOW_CHARS, 
  				printf("GOT -> (%c) (%x)\n", c, c));
  		} /* end if errors */
! 		(*linesw[tp->t_line].l_rint)(c,tp);
  	        } /* end else */
+ 		if (charcount > 32)
+ 			break; /* DEBUG */
  	} /* end while */
  	DEBUGF(ttydebug & SHOW_INTR, 
  		printf("asy%d: charcount=%d\n",unit,charcount));
+ 	return(charcount);
  }
  
***************
*** 755,767 ****
  	register struct asydevice *asyaddr;
  {
- 
  	DEBUGF(ttydebug & SHOW_INTR, printf("asyxint%d: ", unit));
- #ifdef IBMRTPC
- 	char c = (char) unit; 
- 	putc(c, &asyxclist);
- 	setsoftASY();
- 	return; 
- #else 
-  
  #if NAP > 0
  	if (tp->t_line == APLDISC) {
--- 854,858 ----
***************
*** 778,818 ****
  	}
  	DEBUGF(ttydebug & SHOW_INTR, printf("asyxint end\n"));
- #endif IBMRTPC
  }
-  
- #ifdef IBMRTPC
- softasy()
- {
- 	register struct tty *tp;
- 	char unit;
-    	register int s = spl5();	
- 	register struct asydevice *asyaddr;
-  
- 	unit = getc(&asyxclist); 
- 	(void) splx(s);
- 	s = spl_asy();
- 	tp = &asy[unit]; 
- 	asyaddr = (struct asydevice *)tp->t_addr;
-  
- #if NAP > 0
- 	if (tp->t_line == APLDISC) {
- 	DEBUGF(ttydebug & SHOW_INTR, printf("calling AP xint \n"));
- 	(*linesw[tp->t_line].l_start)(tp);
- 	} else 
- #endif NAP
- 	{
- 		tp->t_state &= ~TS_BUSY;
- 		if (tp->t_line)
- 			(*linesw[tp->t_line].l_start)(tp);
- 		else
- 			asystart(tp);
- 	}
- 	DEBUGF(ttydebug & SHOW_INTR, printf("asyxint end\n"));
- 	 
- 	(void) splx(s);
- }
- #endif IBMRTPC
  
- 
  asystart(tp)
  	register struct tty *tp;
--- 869,874 ----
***************
*** 819,823 ****
  {
  	register struct asydevice *asyaddr = (struct asydevice *)tp->t_addr;
!  	register int c, s;
  
  	DEBUGF(ttydebug & SHOW_IO, printf("asystart addr=%x\n", asyaddr));
--- 875,880 ----
  {
  	register struct asydevice *asyaddr = (struct asydevice *)tp->t_addr;
!  	register int i, s;
!  	register int c = 0;
  
  	DEBUGF(ttydebug & SHOW_IO, printf("asystart addr=%x\n", asyaddr));
***************
*** 830,852 ****
  	 * if it's currently active, or delaying, no need to do anything.
  	 */
! 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
  	}
-  		DEBUGF(ttydebug & SHOW_CHARS, 
-  			printf("asystart - non-fifomode/n"));
-  		while (IOIN(&asyaddr->lsr) & LSR_THRE) { 
-  			if ((tp->t_outq.c_cc <= 0) || (c = getc(&tp->t_outq)) == -1) {
-  				goto out1;
-  			}
-  			DEBUGF(ttydebug & SHOW_CHARS,
-  				printf("put (%c) (%x)\n", (char)(c), (char)(c) ));
-  			if ( tp->t_flags & (RAW | LITOUT) || (c <= 0177) ) {
-  				IOOUT(&asyaddr->txb, c);
-  			} else {
-  				timeout(ttrstrt, (caddr_t)tp, (c & 0177));
-  				tp->t_state |= TS_TIMEOUT;
-  				DEBUGF(ttydebug & SHOW_CHARS,printf("asystart timeout\n"));
-  				goto out1;
-  			}
-  		} /* end of while */
  	tp->t_state |= TS_BUSY;
  	DEBUGF(ttydebug & SHOW_REGS, printf("asystart: enable TX int\n"));
--- 887,921 ----
  	 * if it's currently active, or delaying, no need to do anything.
  	 */
! 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
! 		goto out2;
!  	if (IOIN(&asyaddr->lsr) & LSR_THRE) {
!       	    /* unit = tp - asy */
!       	    if ((asysoftFIFO[tp - asy]) &&
!        		(tp->t_flags & (RAW | LITOUT))) {
!       		for (i=0; i<9; i++) {
!        			if (tp->t_outq.c_cc <= 0)
!        				goto out1;
! 			if ((c = getc(&tp->t_outq)) == -1)
!        				goto out1;
!        			IOOUT(&asyaddr->txb, c);
!       	    	}
! 	    }
!        	
!             do {
! 		if ((tp->t_outq.c_cc <= 0) || (c = getc(&tp->t_outq)) == -1)
!                  	goto out1;
!                  DEBUGF(ttydebug & SHOW_CHARS,
!                  	printf("put (%c) (%x)\n", (char)(c), (char)(c) ));
!                  if ( tp->t_flags & (RAW | LITOUT) || (c <= 0177) ) 
!                      IOOUT(&asyaddr->txb, c);
!                  else {
!                      timeout(ttrstrt, (caddr_t)tp, (c & 0177));
!                      tp->t_state |= TS_TIMEOUT;
!                      DEBUGF(ttydebug & SHOW_CHARS,
! 				printf("asystart timeout\n"));
!                      goto out1;
! 	        }
! 	    } while (IOIN(&asyaddr->lsr) & LSR_THRE);
  	}
  	tp->t_state |= TS_BUSY;
  	DEBUGF(ttydebug & SHOW_REGS, printf("asystart: enable TX int\n"));
***************
*** 896,900 ****
  			DEBUGF( ttydebug & SHOW_INTR,printf("Carrier detect "));
  			if ((tp->t_state & TS_CARR_ON) == 0) {
! 				wakeup((caddr_t) & tp->t_rawq);
  				tp->t_state |= TS_CARR_ON;
  			}
--- 971,976 ----
  			DEBUGF( ttydebug & SHOW_INTR,printf("Carrier detect "));
  			if ((tp->t_state & TS_CARR_ON) == 0) {
! 				wakeup((caddr_t) &tp->t_rawq);
! 			        (*linesw[tp->t_line].l_modem)(tp, 1);
  				tp->t_state |= TS_CARR_ON;
  			}
***************
*** 906,909 ****
--- 982,986 ----
  				ttyflush(tp, FREAD | FWRITE);
  			}
+ 			(*linesw[tp->t_line].l_modem)(tp, 0);
  			tp->t_state &= ~TS_CARR_ON;
  		}
***************
*** 911,915 ****
  	DEBUGF(ttydebug & SHOW_INTR, printf("asymint end\n"));
  }
- 
  
  asyselect(dev, rw)
--- 988,991 ----
diff -r -c2 sys.ship/caio/asyreg.h sys.new/caio/asyreg.h
*** sys.ship/caio/asyreg.h	Fri Dec  9 14:50:59 1988
--- sys.new/caio/asyreg.h	Tue Jul 11 12:54:01 1989
***************
*** 39,43 ****
  #define IIR_PEND	0x01	/* This Bit is 0 when an interrupt is pending */
  #define IIR_CTI		0x0c	/* Character timeout - FIFO mode only */
! #define IIR_MASK	0x07	/* Mask off just the meaningful bits in iir */
  /* Interrupt types in oder of priority (high to low) */
  #define IIR_LSR		0x06	/* Line Status (Some error condition) */
--- 39,43 ----
  #define IIR_PEND	0x01	/* This Bit is 0 when an interrupt is pending */
  #define IIR_CTI		0x0c	/* Character timeout - FIFO mode only */
! #define IIR_MASK	0x0F	/* Mask off just the meaningful bits in iir */
  /* Interrupt types in oder of priority (high to low) */
  #define IIR_LSR		0x06	/* Line Status (Some error condition) */
***************
*** 92,96 ****
  #define MSR_DDCD	0x08	/* Delta Data Carrier Detect (DRLSD) */
  #define MSR_CTS		0x10	/* Clear To Send */
! #define MSR_DSD		0x20	/* Data Set Ready */
  #define MSR_RI		0x40	/* Ring Indicator */
  #define MSR_DCD 	0x80	/* Data Carrier Detect (RLSD) */
--- 92,96 ----
  #define MSR_DDCD	0x08	/* Delta Data Carrier Detect (DRLSD) */
  #define MSR_CTS		0x10	/* Clear To Send */
! #define MSR_DSR		0x20	/* Data Set Ready */
  #define MSR_RI		0x40	/* Ring Indicator */
  #define MSR_DCD 	0x80	/* Data Carrier Detect (RLSD) */
***************
*** 103,105 ****
  
  #define spl_asy()	_spl3()
- 
--- 103,104 ----
diff -r -c2 sys.ship/conf/param.c sys.new/conf/param.c
*** sys.ship/conf/param.c	Fri Dec  9 14:53:03 1988
--- sys.new/conf/param.c	Tue Jul 11 12:51:27 1989
***************
*** 67,71 ****
  #endif
  #ifdef ibm032
! #define HZ 64
  #endif
  #ifdef	ibm370
--- 67,71 ----
  #endif
  #ifdef ibm032
! #define HZ 100
  #endif
  #ifdef	ibm370
diff -r -c2 sys.ship/sys/kern_clock.c sys.new/sys/kern_clock.c
*** sys.ship/sys/kern_clock.c	Fri Dec  9 15:05:04 1988
--- sys.new/sys/kern_clock.c	Tue Jul 11 12:54:43 1989
***************
*** 135,139 ****
  	}
  
! #if defined(ATR) && !defined(GPROF)
  	adjtick();
  #endif
--- 135,139 ----
  	}
  
! #if !defined(GPROF)
  	adjtick();
  #endif

Eric Brunner
uunet!ibmsupt!brunner

brunner@bullhead.uucp (11/17/89)

Subject: Patch for multiport asychronous driver
Index: /sys/caio/asy.c, IBM/4.3

Description:
	A bug was introduced in V1.3 limiting minor device numbers.
	I/O on /dev/ttyc1 results in a trap.

Fix:
	Apply the following patch:

*** asy.c	Wed Nov 15 14:33:41 1989
--- asy.c.fix	Wed Nov 15 14:33:10 1989
***************
*** 102,109 ****
    *			-----------
    */
  #define NPORTS	4		/* number of serial port per multiport card */
! #define MAXCTLR 6		/* total ctrl cards */
! #define MAXUNIT 18		/* total number of ports configured */
  struct cbuf asycbuf[MAXUNIT];
   /*
    * Terminology:
--- 102,108 ----
    *			-----------
    */
  #define NPORTS	4		/* number of serial port per multiport card */
! #define MAXUNIT (NASY * NPORTS)	/* total number of ports configured */
  struct cbuf asycbuf[MAXUNIT];
   /*
    * Terminology:

Eric Brunner, Consultant, IBM AWD Palo Alto	(415) 855-4486
inet: brunner@monet.berkeley.edu
uucp: uunet!ibmsupt!brunner	

brunner@bullhead.uucp (11/17/89)

Subject: Patch for multiport asychronous driver
Index: /sys/caio/asy.c, IBM/4.3

Description:
	The watchdog close timer expires too early. In the case of
	the IBM Proprinter at 9600 bps this causes the last few
	lines of output to be lost.
Fix:
	Apply the following patch:

*** asy.c	Tue Nov 14 15:11:57 1989
--- asy.c.fix	Tue Nov 14 15:20:27 1989
***************
*** 520,526 ****
  asyouttime(tp)
  register struct tty *tp;
  {
! 	return (hz + 3 * hz * tp->t_outq.c_cc / (2 * asyoutputrate[tp->t_ospeed]));
  }
  
  /*
--- 520,527 ----
  asyouttime(tp)
  register struct tty *tp;
  {
! 	return (18 * hz * (1 + tp->t_outq.c_cc / asyoutputrate[tp->t_ospeed]));
! 
  }
  
  /*

Eric Brunner, Consultant, IBM AWD Palo Alto	(415) 855-4486
inet: brunner@monet.berkeley.edu
uucp: uunet!ibmsupt!brunner