Subject: BREAK and magic SysRq handling for Z8530

From: "Maciej W. Rozycki" <[email-masked]>
Date: Mon, 7 Aug 2000 17:56:52 +0200 (MET DST)

Hi,

 It appears our current Z8530 driver lacks BREAK support.  It also has the
unfortunate side effect magic SysRq wouldn't work either, if we had it. 
Not anymore!  The following patch adds both features to our Z8530 driver. 
It also allows the magic SysRq hack to be compiled-in (i.e. no more
linking errors) even if no virtual terminal driver is build, which is
suitable for certain configurations, including mine.

 Comments are welcomed, as usually.

  Maciej

-- 
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: [email-masked], PGP key available        +

diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/drivers/char/keyboard.c linux-mips-2.4.0-test5-20000731/drivers/char/keyboard.c
--- linux-mips-2.4.0-test5-20000731.macro/drivers/char/keyboard.c	Thu Feb 24 05:26:36 2000
+++ linux-mips-2.4.0-test5-20000731/drivers/char/keyboard.c	Sun Aug  6 09:15:46 2000
@@ -158,7 +158,6 @@
 
 #ifdef CONFIG_MAGIC_SYSRQ
 static int sysrq_pressed;
-int sysrq_enabled = 1;
 #endif
 
 static struct pm_dev *pm_kbd = NULL;
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/drivers/char/serial.c linux-mips-2.4.0-test5-20000731/drivers/char/serial.c
--- linux-mips-2.4.0-test5-20000731.macro/drivers/char/serial.c	Mon Jul 24 04:26:06 2000
+++ linux-mips-2.4.0-test5-20000731/drivers/char/serial.c	Sun Aug  6 09:21:03 2000
@@ -597,7 +597,8 @@
 				printk("handling break....");
 #endif
 #if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
-				if (info->line == sercons.index) {
+				if (info->line == sercons.index
+				    && sysrq_enabled) {
 					if (!break_pressed) {
 						break_pressed = jiffies;
 						goto ignore_char;
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/drivers/char/sysrq.c linux-mips-2.4.0-test5-20000731/drivers/char/sysrq.c
--- linux-mips-2.4.0-test5-20000731.macro/drivers/char/sysrq.c	Tue Mar 28 04:26:29 2000
+++ linux-mips-2.4.0-test5-20000731/drivers/char/sysrq.c	Sun Aug  6 09:17:58 2000
@@ -33,6 +33,8 @@
 /* Machine specific power off function */
 void (*sysrq_power_off)(void) = NULL;
 
+int sysrq_enabled = 1;
+
 EXPORT_SYMBOL(sysrq_power_off);
 
 /* Send a signal to all user processes */
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/drivers/sbus/char/sunkbd.c linux-mips-2.4.0-test5-20000731/drivers/sbus/char/sunkbd.c
--- linux-mips-2.4.0-test5-20000731.macro/drivers/sbus/char/sunkbd.c	Sat Jul 15 04:26:34 2000
+++ linux-mips-2.4.0-test5-20000731/drivers/sbus/char/sunkbd.c	Sun Aug  6 09:16:21 2000
@@ -177,9 +177,6 @@
 static struct pt_regs * pt_regs;
 
 #ifdef CONFIG_MAGIC_SYSRQ
-#ifndef CONFIG_PCI
-int sysrq_enabled = 1;
-#endif
 unsigned char sun_sysrq_xlate[128] =
 	"\0\0\0\0\0\201\202\212\203\213\204\214\205\0\206\0"	/* 0x00 - 0x0f */
 	"\207\210\211\0\0\0\0\0\0\0\0\0\0\03312"		/* 0x10 - 0x1f */
diff -u --recursive --new-file linux-mips-2.4.0-test5-20000731.macro/drivers/tc/zs.c linux-mips-2.4.0-test5-20000731/drivers/tc/zs.c
--- linux-mips-2.4.0-test5-20000731.macro/drivers/tc/zs.c	Sat Jul  8 04:26:53 2000
+++ linux-mips-2.4.0-test5-20000731/drivers/tc/zs.c	Sun Aug  6 13:34:43 2000
@@ -6,6 +6,7 @@
  *
  * DECstation changes
  * Copyright (C) 1998 Harald Koerfgen ([email-masked])
+ * Copyright (C) 2000 Maciej W. Rozycki ([email-masked])
  *
  * For the rest of the code the original Copyright applies:
  * Copyright (C) 1996 Paul Mackerras ([email-masked])
@@ -50,6 +51,9 @@
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#endif
 
 #include "zs.h"
 
@@ -75,6 +79,10 @@
 #ifdef CONFIG_SERIAL_CONSOLE
 static struct console sercons;
 #endif
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) \
+    && !defined(MODULE)
+static unsigned long break_pressed; /* break, really ... */
+#endif
 
 #ifdef CONFIG_KGDB
 struct dec_zschannel *zs_kgdbchan;
@@ -302,6 +310,8 @@
  * -----------------------------------------------------------------------
  */
 
+static int tty_break;	/* Set whenever BREAK condition is detected.  */
+
 /*
  * This routine is used by the interrupt handler to schedule
  * processing in the software interrupt portion of the driver.
@@ -320,7 +330,7 @@
 	struct tty_struct *tty = info->tty;
 	unsigned char ch, stat, flag;
 
-	while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) {
+	while ((read_zsreg(info->zs_channel, R0) & Rx_CH_AV) != 0) {
 
 		stat = read_zsreg(info->zs_channel, R1);
 		ch = read_zsdata(info->zs_channel);
@@ -330,13 +340,53 @@
 			if (ch == 0x03 || ch == '$')
 				breakpoint();
 			if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
-				write_zsreg(info->zs_channel, 0, ERR_RES);
+				write_zsreg(info->zs_channel, R0, ERR_RES);
 			return;
 		}
 #endif
 		if (!tty)
 			continue;
 
+		if (tty_break) {
+			tty_break = 0;
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
+			if (info->line == sercons.index && sysrq_enabled) {
+				if (!break_pressed) {
+					break_pressed = jiffies;
+					goto ignore_char;
+				}
+				break_pressed = 0;
+			}
+#endif
+			flag = TTY_BREAK;
+			if (info->flags & ZILOG_SAK)
+				do_SAK(tty);
+		} else {
+			if (stat & Rx_OVR) {
+				flag = TTY_OVERRUN;
+			} else if (stat & FRM_ERR) {
+				flag = TTY_FRAME;
+			} else if (stat & PAR_ERR) {
+				flag = TTY_PARITY;
+			} else
+				flag = 0;
+			if (flag)
+				/* reset the error indication */
+				write_zsreg(info->zs_channel, R0, ERR_RES);
+		}
+
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
+		if (break_pressed && info->line == sercons.index) {
+			if (ch != 0 &&
+			    time_before(jiffies, break_pressed + HZ*5)) {
+				handle_sysrq(ch, regs, NULL, NULL);
+				break_pressed = 0;
+				goto ignore_char;
+			}
+			break_pressed = 0;
+		}
+#endif
+
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
 			static int flip_buf_ovf;
 			++flip_buf_ovf;
@@ -348,26 +398,17 @@
 			if (flip_max_cnt < tty->flip.count)
 				flip_max_cnt = tty->flip.count;
 		}
-		if (stat & Rx_OVR) {
-			flag = TTY_OVERRUN;
-		} else if (stat & FRM_ERR) {
-			flag = TTY_FRAME;
-		} else if (stat & PAR_ERR) {
-			flag = TTY_PARITY;
-		} else
-			flag = 0;
-		if (flag)
-			/* reset the error indication */
-			write_zsreg(info->zs_channel, 0, ERR_RES);
+
 		*tty->flip.flag_buf_ptr++ = flag;
 		*tty->flip.char_buf_ptr++ = ch;
+	ignore_char:
 	}
 	tty_flip_buffer_push(tty);
 }
 
 static void transmit_chars(struct dec_serial *info)
 {
-	if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
+	if ((read_zsreg(info->zs_channel, R0) & Tx_BUF_EMP) == 0)
 		return;
 	info->tx_active = 0;
 
@@ -380,7 +421,7 @@
 	}
 
 	if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) {
-		write_zsreg(info->zs_channel, 0, RES_Tx_P);
+		write_zsreg(info->zs_channel, R0, RES_Tx_P);
 		return;
 	}
 	/* Send char */
@@ -395,15 +436,22 @@
 
 static _INLINE_ void status_handle(struct dec_serial *info)
 {
-	unsigned char status;
+	unsigned char stat;
 
 	/* Get status from Read Register 0 */
-	status = read_zsreg(info->zs_channel, 0);
+	stat = read_zsreg(info->zs_channel, R0);
+
+	if (stat & BRK_ABRT) {
+#ifdef SERIAL_DEBUG_INTR
+		printk("handling break....");
+#endif
+		tty_break = 1;
+	}
 
 	/* FIXEM: Check for DCD transitions */
-	if (((status ^ info->read_reg_zero) & DCD) != 0
+	if (((stat ^ info->read_reg_zero) & DCD) != 0
 	    && info->tty && !C_CLOCAL(info->tty)) {
-		if (status & DCD) {
+		if (stat & DCD) {
 			wake_up_interruptible(&info->open_wait);
 		} else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
 			if (info->tty)
@@ -420,7 +468,7 @@
 		 * The DCD bit doesn't seem to be inverted
 		 * like this.
 		 */
-		if ((status & CTS) != 0) {
+		if ((stat & CTS) != 0) {
 			if (info->tx_stopped) {
 				info->tx_stopped = 0;
 				if (!info->tx_active)
@@ -432,8 +480,8 @@
 	}
 
 	/* Clear status condition... */
-	write_zsreg(info->zs_channel, 0, RES_EXT_INT);
-	info->read_reg_zero = status;
+	write_zsreg(info->zs_channel, R0, RES_EXT_INT);
+	info->read_reg_zero = stat;
 }
 
 /*
@@ -459,7 +507,7 @@
 		shift = 0;	/* Channel B */
 
 	for (;;) {
-		zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift; 
+		zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift; 
 		if ((zs_intreg & CHAN_IRQMASK) == 0)
 			break;

---

From: "Gleb O. Raiko" <[email-masked]>
Date: Wed, 09 Aug 2000 12:08:51 +0400

Maciej,

> suitable for certain configurations, including mine.

Have you tested the patch? The problem isn't in the patch itself, but as
I see the zs driver is broken for a long time. At least, I used to patch
heavily this driver for my Baget taht has 2 zs chips on board. Harald
has the plans to implement new version of the driver, but I guess he is
busy all the time. Or have I missed a cleanup of the driver ?

Also, changes in sunkbd.c, keyboard.c, and serial.c isn't a good idea.
:-)

Regards,
Gleb.

---

From: "Maciej W. Rozycki" <[email-masked]>
Date: Wed, 9 Aug 2000 11:38:37 +0200 (MET DST)

Gleb,

> Have you tested the patch? The problem isn't in the patch itself, but as

 Sure I did, to an extent I was able to.  No problems noticed.

> heavily this driver for my Baget taht has 2 zs chips on board. Harald

 Well, the driver seems to work good enough for now to use a serial
console.  And the SysRq support is an absolute must when trying to debug a
locked-up kernel -- the lack of this support is a sign for me nobody is
currently working on DECstations at the moment. 

> busy all the time. Or have I missed a cleanup of the driver ?

 Hmm, I haven't noticed any, either.  Fixing the driver is actually on my
TODO list -- all the 8530 drivers present in Linux currently need to be
merged into a single one.  Also DMA and synchronous mode support has to be
implemented.  It's not on the top of my list, though.

> Also, changes in sunkbd.c, keyboard.c, and serial.c isn't a good idea.

 It's actually the reverse. ;-)  Without these (oh well, sunkbd.c is for
completeness, indeed) you cannot compile-in the magic SysRq support if you
do not include the virtual terminal driver.  This is an unnecessary
limitation -- I don't want the VT (well, actually I would, if I had a
driver for my console, but I haven't, yet). 

 Such changes actually went into the Linus' 2.4.0-test6-pre* (but not mine
-- someone overtook me, and he also missed one bit ;-) ).

  Maciej

---

From: Ralf Baechle <[email-masked]>
Date: Wed, 9 Aug 2000 18:13:57 +0200

> -- someone overtook me, and he also missed one bit ;-) ).

That probably where Prumpf's changes; I recently discussed various problem
with SysRq with him.  I guess he only tried to fix the HP part of the
problem.

  Ralf