Subject: Fix kd driver (kdcngetc/kdcnputc functions)
To: None <hls@oce.nl, port-sun3@netbsd.org>
From: Gordon W. Ross <gwr@jericho.mc.com>
List: port-sun3
Date: 12/17/1994 15:10:32
> > Besides this I have the following minor problem:
> > 
> >     Pressing 'L1-A' drops me into the debugger.
> > 
> >     Stopped at  _Debugger+0x6:  unlk    a6
> >     db>
> > 
> >     At this point NetBSD doesn't respond to any keys pressed on
> >     the keyboard!
> 
> Ugh.  I'm not sure this ever worked.  In sun3/dev/kd.c there is a
> kdcngetc routine that tries to use the PROM to read the keyboard
> (cheat) and the PROM quite likely requires the clock interupts at
> level 7 (NMI) enabled to poll the keyboard.  The "right" way to
> fix it is make kdcngetc poll just like zs.c:zscngetc() to get a
> scan code, then translate it (as done by kbd.c) then return it.
> 
> >     When I start NetBSD with -d, this also gets me into the debugger.
> >     In this case everything works fine!
> Really!  You mean, later L1-A then works correctly?  Hmmmm...

I tried this out, and just as you say, it was broken.  The PROM
can not read the console unless the NMI clock is turned on...

Here's a fix:

diff -rc sun3.orig/dev/kbd.c sun3/dev/kbd.c
*** sun3.orig/dev/kbd.c	Thu Dec 15 06:20:07 1994
--- sun3/dev/kbd.c	Sat Dec 17 03:41:46 1994
***************
*** 208,213 ****
--- 208,214 ----
  	void	(*k_open) __P((struct tty *));	/* enable dataflow */
  	void	(*k_close) __P((struct tty *));	/* disable dataflow */
  	int	k_evmode;		/* set if we should produce events */
+ 	int	k_isopen;		/* set if open has been done */
  	struct	kbd_state k_state;	/* ASCII decode state */
  	struct	evvar k_events;		/* event queue state */
  } kbd_softc;
***************
*** 215,223 ****
  /* Prototypes */
  void	kbd_ascii(struct tty *);
  void	kbd_serial(struct tty *, void (*)(), void (*)());
! int 	kbd_init(void);
! void	kbd_reset(struct kbd_state *);
! static	int kbd_translate(int, struct kbd_state *);
  void	kbd_rint(int);
  int	kbdopen(dev_t, int, int, struct proc *);
  int	kbdclose(dev_t, int, int, struct proc *);
--- 216,224 ----
  /* Prototypes */
  void	kbd_ascii(struct tty *);
  void	kbd_serial(struct tty *, void (*)(), void (*)());
! int 	kbd_iopen(void);
! void	kbd_reset(struct kbd_softc *);
! int kbd_translate(int);
  void	kbd_rint(int);
  int	kbdopen(dev_t, int, int, struct proc *);
  int	kbdclose(dev_t, int, int, struct proc *);
***************
*** 228,233 ****
--- 229,250 ----
  int	kbd_docmd(int, int);
  
  /*
+  * Initialization done by either kdcninit or kbd_iopen
+  */
+ void
+ kbd_init_tables()
+ {
+ 	struct kbd_state *ks;
+ 
+ 	ks = &kbd_softc.k_state;
+ 	if (ks->kbd_cur == NULL) {
+ 		ks->kbd_cur = kbd_unshifted;
+ 		ks->kbd_unshifted = kbd_unshifted;
+ 		ks->kbd_shifted = kbd_shifted;
+ 	}
+ }
+ 
+ /*
   * Attach the console keyboard ASCII (up-link) interface.
   * This is called by the "kd" (keyboard/display) driver to
   * tell this module where to send read-side data.
***************
*** 253,259 ****
  	k->k_open = iopen;
  	k->k_close = iclose;
  
! 	/* Now attach the Keyboard/Display (kd) pseudo-driver. */
  	kd_attach(1);	/* This calls kbd_ascii() */
  }
  
--- 270,279 ----
  	k->k_open = iopen;
  	k->k_close = iclose;
  
! 	/* Do this before any calls to kbd_rint(). */
! 	kbd_init_tables();
! 
! 	/* Now attach the (kd) pseudo-driver. */
  	kd_attach(1);	/* This calls kbd_ascii() */
  }
  
***************
*** 262,276 ****
   * This is called from kbdopen or kdopen (in kd.c)
   */
  int
! kbd_init()
  {
! 	register struct kbd_softc *k;
  	int error, s;
  
  	k = &kbd_softc;
  
  	/* Tolerate extra calls. */
! 	if (k->k_state.kbd_cur)
  		return (0);
  
  	/* Make sure "down" link (to zs1a) is established. */
--- 282,296 ----
   * This is called from kbdopen or kdopen (in kd.c)
   */
  int
! kbd_iopen()
  {
! 	struct kbd_softc *k;
  	int error, s;
  
  	k = &kbd_softc;
  
  	/* Tolerate extra calls. */
! 	if (k->k_isopen)
  		return (0);
  
  	/* Make sure "down" link (to zs1a) is established. */
***************
*** 285,297 ****
  	(void) ttyoutput(KBD_CMD_RESET, k->k_kbd);
  	(*k->k_kbd->t_oproc)(k->k_kbd);
  	/* The wakeup for this sleep is in kbd_reset(). */
! 	error = tsleep((caddr_t)&kbd_softc.k_state, PZERO | PCATCH,
  				   devopn, hz);
! 	if (error == EWOULDBLOCK)	/* no response */
! 		error = ENXIO;
  
  	if (error == 0)
! 	    k->k_state.kbd_cur = kbd_unshifted;
  
  	splx(s);
  	return error;
--- 305,319 ----
  	(void) ttyoutput(KBD_CMD_RESET, k->k_kbd);
  	(*k->k_kbd->t_oproc)(k->k_kbd);
  	/* The wakeup for this sleep is in kbd_reset(). */
! 	error = tsleep((caddr_t)k, PZERO | PCATCH,
  				   devopn, hz);
! 	if (error == EWOULDBLOCK) { 	/* no response */
! 		printf("keyboard not responding\n");
! 		error = EIO;
! 	}
  
  	if (error == 0)
! 		k->k_isopen = 1;
  
  	splx(s);
  	return error;
***************
*** 298,315 ****
  }
  
  void
! kbd_reset(register struct kbd_state *ks)
  {
  	/*
  	 * On first identification, wake up anyone waiting for type
  	 * and set up the table pointers.
  	 */
! 	if (ks->kbd_unshifted == NULL) {
! 		wakeup((caddr_t)ks);
! 		ks->kbd_unshifted = kbd_unshifted;
! 		ks->kbd_shifted = kbd_shifted;
! 		ks->kbd_cur = ks->kbd_unshifted;
! 	}
  
  	/* Restore keyclick, if necessary */
  	switch (ks->kbd_id) {
--- 320,338 ----
  }
  
  void
! kbd_reset(k)
! 	struct kbd_softc *k;
  {
+ 	struct kbd_state *ks;
+ 
+ 	ks = &k->k_state;
+ 
  	/*
  	 * On first identification, wake up anyone waiting for type
  	 * and set up the table pointers.
  	 */
! 	if (k->k_isopen == 0)
! 		wakeup((caddr_t)k);
  
  	/* Restore keyclick, if necessary */
  	switch (ks->kbd_id) {
***************
*** 335,345 ****
  /*
   * Turn keyboard up/down codes into ASCII.
   */
! static int
! kbd_translate(register int c, register struct kbd_state *ks)
  {
  	register int down;
  
  	if (ks->kbd_cur == NULL) {
  		/*
  		 * Do not know how to translate yet.
--- 358,370 ----
  /*
   * Turn keyboard up/down codes into ASCII.
   */
! int
! kbd_translate(register int c)
  {
+ 	register struct kbd_state *ks;
  	register int down;
  
+ 	ks = &kbd_softc.k_state;
  	if (ks->kbd_cur == NULL) {
  		/*
  		 * Do not know how to translate yet.
***************
*** 420,426 ****
  	if (k->k_state.kbd_takeid) {
  		k->k_state.kbd_takeid = 0;
  		k->k_state.kbd_id = c;
! 		kbd_reset(&k->k_state);
  		return;
  	}
  
--- 445,451 ----
  	if (k->k_state.kbd_takeid) {
  		k->k_state.kbd_takeid = 0;
  		k->k_state.kbd_id = c;
! 		kbd_reset(k);
  		return;
  	}
  
***************
*** 437,443 ****
  	 * open and we do not know its type.
  	 */
  	if (!k->k_evmode) {
! 		c = kbd_translate(c, &k->k_state);
  		if (c >= 0 && k->k_cons != NULL)
  			ttyinput(c, k->k_cons);
  		return;
--- 462,468 ----
  	 * open and we do not know its type.
  	 */
  	if (!k->k_evmode) {
! 		c = kbd_translate(c);
  		if (c >= 0 && k->k_cons != NULL)
  			ttyinput(c, k->k_cons);
  		return;
***************
*** 481,487 ****
  		return (EBUSY);
  	kbd_softc.k_events.ev_io = p;
  
! 	if ((error = kbd_init()) != 0) {
  		kbd_softc.k_events.ev_io = NULL;
  		return (error);
  	}
--- 506,512 ----
  		return (EBUSY);
  	kbd_softc.k_events.ev_io = p;
  
! 	if ((error = kbd_iopen()) != 0) {
  		kbd_softc.k_events.ev_io = NULL;
  		return (error);
  	}

diff -rc sun3.orig/dev/kd.c sun3/dev/kd.c
*** sun3.orig/dev/kd.c	Thu Dec 15 06:20:07 1994
--- sun3/dev/kd.c	Sat Dec 17 03:39:00 1994
***************
*** 90,97 ****
  	if (tp == NULL)
  		return ENXIO;
  
! 	if ((error = kbd_init()) != 0)
  		return (error);
  
  	tp->t_oproc = kdstart;
  	tp->t_param = kdparam;
--- 90,101 ----
  	if (tp == NULL)
  		return ENXIO;
  
! 	if ((error = kbd_iopen()) != 0) {
! #ifdef	DIAGNOSTIC
! 		printf("kd: kbd_iopen, error=%d\n", error);
! #endif
  		return (error);
+ 	}
  
  	tp->t_oproc = kdstart;
  	tp->t_param = kdparam;
***************
*** 232,242 ****
  
  /*
   * kd console support
-  *
-  * XXX - Using prom routines for now...
   */
  
! extern int zscnprobe_kbd();
  
  kdcnprobe(cp)
  	struct consdev *cp;
--- 236,244 ----
  
  /*
   * kd console support
   */
  
! extern int zscnprobe_kbd(), zscngetc(), kbd_translate();
  
  kdcnprobe(cp)
  	struct consdev *cp;
***************
*** 256,261 ****
--- 258,270 ----
  kdcninit(cp)
  	struct consdev *cp;
  {
+ 
+ 	/* This prepares zscngetc() */
+ 	zs_set_conschan(1, 0);
+ 
+ 	/* This prepares kbd_translate() */
+ 	kbd_init_tables();
+ 
  	mon_printf("console on kd0 (keyboard/display)\n");
  }
  
***************
*** 262,277 ****
  kdcngetc(dev)
  	dev_t dev;
  {
! 	int c, s;
  
! 	/* XXX - Does mon_may_getchar() require the NMI clock? */
! 	s = splhigh();
! 	do c = mon_may_getchar();
! 	while (c < 0);
! 	splx(s);
  
- 	if (c == '\r')
- 		c = '\n';
  	return (c);
  }
  
--- 271,283 ----
  kdcngetc(dev)
  	dev_t dev;
  {
! 	int c;
  
! 	do {
! 		c = zscngetc(0);
! 		c = kbd_translate(c);
! 	} while (c == -1);
  
  	return (c);
  }
  

diff -rc sun3.orig/dev/zs.c sun3/dev/zs.c
*** sun3.orig/dev/zs.c	Thu Dec 15 06:20:09 1994
--- sun3/dev/zs.c	Sat Dec 17 02:54:50 1994
***************
*** 457,476 ****
  	return (zscnprobe(cn, 1));
  }
  
! /* Attach as console.  Also set zs_conschan */
! int
! zscninit(struct consdev *cn)
  {
- 	int unit;
  	volatile struct zsdevice *addr;
  
! 	unit = minor(cn->cn_dev) & 1;
! 	addr = zsaddr[0];
! 	zs_conschan = ((unit == 0) ?
  				   &addr->zs_chan[CHAN_A] :
  				   &addr->zs_chan[CHAN_B] );
  
! 	mon_printf("console on zs0 (tty%c)\n", unit + 'a');
  }
  
  
--- 457,482 ----
  	return (zscnprobe(cn, 1));
  }
  
! /* Called by kdcninit() or below. */
! void
! zs_set_conschan(unit, ab)
! 	int unit, ab;
  {
  	volatile struct zsdevice *addr;
  
! 	addr = zsaddr[unit];
! 	zs_conschan = ((ab == 0) ?
  				   &addr->zs_chan[CHAN_A] :
  				   &addr->zs_chan[CHAN_B] );
+ }
  
! /* Attach as console.  Also set zs_conschan */
! int
! zscninit(struct consdev *cn)
! {
! 	int ab = minor(cn->cn_dev) & 1;
! 	zs_set_conschan(0, ab);
! 	mon_printf("console on zs0 (tty%c)\n", 'a' + ab);
  }
  
  
***************
*** 498,503 ****
--- 504,514 ----
  	ZS_DELAY();
  
  	splx(s);
+ 
+ 	/*
+ 	 * This is used by the kd driver to read scan codes,
+ 	 * so don't translate '\r' ==> '\n' here...
+ 	 */
  	return (c);
  }