Subject: Possible fix for ADB hang on IIcx, SE/30, et. al...
To: port-mac68k Mailing List <port-mac68k@NetBSD.ORG>
From: Colin Wood <cwood@ichips.intel.com>
List: port-mac68k
Date: 01/11/1998 13:30:00
Ok, I've come up with a somewhat weird solution to the ADB hanging problem
which seems to only affect those machines with direty ROM's (i.e. the
SE/30, II, IIx, and IIcx...although I've only seen problems reported on
the IIcx and SE/30).  The manifestation of this problem is twofold:

1) Sometime after NetBSD 1.2.x, these machines would hang during boot if
they didn't have both a keyboard and a mouse attached.

2) Kernels from Nov 7, 1997 onward would hang these machines if an
extended keyboard is attached.

Note that this problem only seems to affect kernels using MRG_ADB.  The
HWDIRECT method appears to be immune.

Anyway, I've attached a fix below (of course, you might as well just
compile with HWDIRECT ADB support) and I'd like to see if it fixes for
everyone having the problem.  I've tested situation (1) on my SE/30, and
it seems to work.  (I haven't tried (2) yet).

Just incase you're interested, the problem was that (on these machines at
least), the hardware seems to create a "ghost" keyboard or mouse when none
is attached.  On newer machines, a subsequent probe of these devices
indicates that they are not really there.  However, for those machines
listed above, a probe of the non-existant device hangs in an infinite loop
awaiting a reply.  The reason why this has only shown up since 1.2 is that
the extended mouse support performs this kind of probe.  The Nov. 7 change
is a result of another probe added to support non-EMP Logitech mice.

The way the fix works is to schedule a 2 second interrupt before going
into the possibly infinite while() loop.  The interrupt handler resets the
while loop condition so the loop test fails.  Normally, the timeout(9)
function could have been used, but during this particular part of boot,
the real-time clock hasn't been initialized quite yet, so I had to set up
my own timer.

Anyway, if you compile you're own kernels and prefer MRG_ADB for some
reason over HWDIRECT, please try the patch below and let me know how it
goes.

Later.

-- 
Colin Wood                                 cwood@ichips.intel.com
Component Design Engineer - MD6                 Intel Corporation
-----------------------------------------------------------------
I speak only on my own behalf, not for my employer.

*** adbsys.c.orig	Sat Jan 10 18:45:22 1998
--- adbsys.c	Sun Jan 11 13:12:37 1998
***************
*** 195,200 ****
--- 195,269 ----
  
  static volatile int extdms_done;
  
+ /* #define ADB_DEBUG */
+ 
+ static void     adb_timer2_irq __P((void *));
+ 
+ static void
+ adb_timer2_irq(dummy)
+ 	void *dummy;
+ {
+ 	extdms_done = 1;
+ }
+ 
+ #define ACR_T2ENB	0x20
+ 
+ static void    adbop_timeout __P((void));
+ 
+ static void
+ adbop_timeout(void)
+ {
+ #define TWOSEC		(120 * (int)((((100000000L / HZ) * 100) / 12766)))
+ #define TWOSECH		((TWOSEC >> 8) & 0xff)    /* high byte */
+ #define TWOSECL		(TWOSEC & 0xff)           /* low byte */
+ 
+ 	/* be certain clock interrupts are off */
+ 	via_reg(VIA1, vIER) = V1IF_T2;
+ 
+ 	/* set up service routine */
+ 	via1_register_irq(VIA1_T2, adb_timer2_irq, NULL);
+ 
+ 	/* set timer enable bit */
+ 	/*via_reg(VIA1, vACR) |= ACR_T2ENB;*/
+ 
+ 	/* clear then enable clock interrupt. */
+ 	via_reg(VIA1, vIFR) |= V1IF_T2;
+ 	via_reg(VIA1, vIER) = 0x80 | V1IF_T2;
+ 
+ 	/* set VIA timer 2 counter started for 2 * 60 Hz */
+ 	via_reg(VIA1, vT2C) = TWOSECL; 
+ 	via_reg(VIA1, vT2CH) = TWOSECH; 
+ 
+ 	return;
+ }
+ 
+ static void	via1_noint __P((void *));
+ 
+ static void
+ via1_noint(bitnum)
+         void *bitnum;
+ {
+         printf("via1_noint(%d)\n", (int) bitnum);
+ }
+ 
+ static void	adbop_timeout __P((void));
+ 
+ static void
+ adbop_untimeout(void)
+ {
+ 	/* Disable timer and interrupts and reset service routine */
+ 	/*via_reg(VIA1, vACR) &= ~ACR_T2ENB;*/
+ 	via_reg(VIA1, vIER) = V1IF_T2;
+ 
+ 	via1_register_irq(VIA1_T2, (void (*)(void *))via1_noint, NULL);
+ 	
+ 	/* reset timers to 0 */
+ 	via_reg(VIA1, vT2C) = 0;
+ 	via_reg(VIA1, vT2CH) = 0;
+ 
+ 	return;
+ }
+ 
  /*
   * initialize extended mouse - probes devices as
   * described in _Inside Macintosh, Devices_.
***************
*** 208,218 ****
--- 277,298 ----
  	short cmd;
  	u_char buffer[9];
  
+ #ifdef ADB_DEBUG
+         printf("adb: beginning extended mouse initialization\n");
+         printf("adb: probing %d devices\n", totaladbs);
+ #endif
  	for (adbindex = 1; adbindex <= totaladbs; adbindex++) {
+ #ifdef ADB_DEBUG
+ 		printf("adb: probing address %d\n", adbindex);
+ #endif
  		/* Get the ADB information */
  		adbaddr = GetIndADB(&adbdata, adbindex);
  		if (adbdata.origADBAddr == ADBADDR_MS &&
  		    (adbdata.devType == ADBMS_USPEED)) {
+ #ifdef ADB_DEBUG
+ 			printf("adb: initializing Microspeed Mouse\n");
+ #endif
+ 
  			/* Found MicroSpeed Mouse Deluxe Mac */
  			cmd = ((adbaddr<<4)&0xF0)|0x9;	/* listen 1 */
  
***************
*** 250,264 ****
  		    (   adbdata.devType == ADBMS_100DPI
  		     || adbdata.devType == ADBMS_200DPI)) {
  			/* found a mouse */
  			cmd = ((adbaddr << 4) & 0xf0) | 0x3;
  
  			extdms_done = 0;
  			cmd = (cmd & 0xf3) | 0x0c; /* talk command */
  			ADBOp((Ptr)buffer, (Ptr)extdms_complete,
  			      (Ptr)&extdms_done, cmd);
  			while (!extdms_done)
  				/* busy wait until done */;
! 
  			/* Attempt to initialize Extended Mouse Protocol */
  			buffer[2] = '\004'; /* make handler ID 4 */
  			extdms_done = 0;
--- 330,372 ----
  		    (   adbdata.devType == ADBMS_100DPI
  		     || adbdata.devType == ADBMS_200DPI)) {
  			/* found a mouse */
+ #ifdef ADB_DEBUG
+ 			if (adbdata.devType == ADBMS_100DPI)
+ 				printf("adb: found 100dpi mouse\n");
+ 			if (adbdata.devType == ADBMS_200DPI)
+ 				printf("adb: found 200dpi mouse\n");
+ #endif
+ 
  			cmd = ((adbaddr << 4) & 0xf0) | 0x3;
  
  			extdms_done = 0;
  			cmd = (cmd & 0xf3) | 0x0c; /* talk command */
+ #ifdef ADB_DEBUG
+ 			printf("adb: installing timeout...\n");
+ #endif
+ 			adbop_timeout();
+ #ifdef ADB_DEBUG
+ 			printf("adb: sending talk R3 command...\n");
+ #endif
  			ADBOp((Ptr)buffer, (Ptr)extdms_complete,
  			      (Ptr)&extdms_done, cmd);
+ #ifdef ADB_DEBUG
+ 			printf("adb: waiting for reply...\n");
+ #endif
  			while (!extdms_done)
  				/* busy wait until done */;
! #ifdef ADB_DEBUG
! 			printf("adb: removing timeout...\n");
! #endif
! 			adbop_untimeout();
! 			if (extdms_done > 0) {
! #ifdef ADB_DEBUG
! 				printf("adb: extdms_init timed out!\n");
! #endif
! 				return;
! 			}
! 			
! 	
  			/* Attempt to initialize Extended Mouse Protocol */
  			buffer[2] = '\004'; /* make handler ID 4 */
  			extdms_done = 0;
***************
*** 395,405 ****
  				break;
                          case ADB_EXTKBD:
  				extdms_done = 0;
! 				cmd=(((adbaddr<<4) &0xf0) | 0x0d ); /* talk R1 */
  				ADBOp((Ptr)buffer, (Ptr)extdms_complete,
  					(Ptr)&extdms_done, cmd);
  				while (!extdms_done);
  					/* busy wait until done */
  				if (buffer[1]==0x9a && buffer[2]==0x20 )
  					printf("Mouseman (non-EMP) pseudo keyboard");
  				else
--- 503,516 ----
  				break;
                          case ADB_EXTKBD:
  				extdms_done = 0;
! 				adbop_timeout();
! 				cmd=(((adbaddr<<4) &0xf0) | 0x0d );
! 					/* talk R1 */
  				ADBOp((Ptr)buffer, (Ptr)extdms_complete,
  					(Ptr)&extdms_done, cmd);
  				while (!extdms_done);
  					/* busy wait until done */
+ 				adbop_untimeout();
  				if (buffer[1]==0x9a && buffer[2]==0x20 )
  					printf("Mouseman (non-EMP) pseudo keyboard");
  				else
***************
*** 452,462 ****
--- 563,579 ----
  			break;
  		case ADBADDR_REL:
  			extdms_done = 0;
+ 			adbop_timeout();
  			/* talk register 3 */
  			ADBOp((Ptr)buffer, (Ptr)extdms_complete,
  			      (Ptr)&extdms_done, (adbaddr << 4) | 0xf);
  			while (!extdms_done)
  				/* busy-wait until done */;
+ 			adbop_untimeout();
+ 			if (extdms_done > 0) {
+ 				printf("ghost mouse");
+ 				break;
+ 			}
  			devtype=buffer[2];
  			switch (devtype) {
  			case ADBMS_100DPI: