Date: Mon, 31 Mar 1997 15:47:52 +0200 (MET DST)
From: Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be>
To: linux-m68k@phil.uni-sb.de
Subject: Re: L68K: Serial console enhancement
In-Reply-To: <d37mivc6uu.fsf@cern.ch>
Sender: owner-linux-m68k@phil.uni-sb.de
Reply-To: linux-m68k@phil.uni-sb.de

On 26 Mar 1997, Jes Sorensen wrote:
>>>>>> "Geert" == Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be> writes:
>
>Geert>   - Serial console:
>
>Geert>       o Kernel command line option `console=xxx'. Currently
>Geert> only the Amiga builtin serial port (`console=0') is
>Geert> supported. Explicitly setting of the serial parameters isn't
>Geert> implemented yet.
>
>I might be missing something here, but isn't console=/dev/ttyS0 better
>than just console=0? This will allow this parameter to be useable for
>other things, for instance if people use multiple displays on the same
>box.

And So I Did.

This is an updated version of my previous patch (i.e. undo my previous patch
first!).  New features:

  - console=xxx. Recognized are

      o /dev/tty?: normal consoles

      o /dev/ttyS?: serial consoles (/dev/ttyS0 is first serial port)

    Default is /dev/tty1. And $CONSOLE is now _always_ set for init.

    /dev/ttyS0 still only works for the Amiga builtin serial port.

  - amiga_ser now recognizes BREAK. If the serial port is active and you
    press BREAK on your terminal, you'll be dropped in the kernel monitor
    (cfr. Sun).

Internals:

  - `int serial_console' is replaced by `kdev_t console_dev', also on Sparc.
    We have to discuss this with the guys of the other architectures later.

TODO:

  - Support for other serial ports (Atari, MFC, IOext)

  - Multi frame buffer device support. This can use e.g. console=/dev/tty2 too.

Can someone else take a look at the serial stuff? In the mean time I'll clean
up the frame buffer interface. I think it would be nice if tty i would appear
on frame buffer i%numfb. And all frame buffer drivers for Amiga gfx boards
should be decoupled from amifb and be reentrant (i.e. support more than one
board).

--- linux-2.1.29/arch/sparc/kernel/setup.c.orig.real	Tue Mar 18 23:47:28 1997
+++ linux-2.1.29/arch/sparc/kernel/setup.c	Mon Mar 31 13:37:33 1997
@@ -24,6 +24,7 @@
 #include <linux/string.h>
 #include <linux/blk.h>
 #include <linux/init.h>
+#include <linux/console.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -248,14 +249,35 @@
 
 extern int root_mountflags;
 
-extern void register_console(void (*proc)(const char *));
-
 char saved_command_line[256];
 char reboot_command[256];
 enum sparc_cpu sparc_cpu_model;
 
 struct tt_entry *sparc_ttable;
 
+static void ap1000_console_write(const char *s, unsigned int count)
+{
+	/* TODO: should print `count' characters */
+	prom_printf(s);
+}
+
+static void ap1000_console_wait_key(void)
+{
+	return;
+}
+
+static int ap1000_console_device(void)
+{
+	return 0;
+}
+
+static struct console ap1000_printk_console = {
+	ap1000_console_write,
+	ap1000_console_wait_key,
+	ap1000_console_device,
+	NULL
+};
+
 static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
 
 __initfunc(void setup_arch(char **cmdline_p,
@@ -310,7 +332,7 @@
 		printk("SUN4U\n");
 		break;
 	case ap1000:
-		register_console((void (*) (const char *))prom_printf);
+		register_console(ap1000_printk_console);
 		printk("AP1000\n");
 		packed = 1;
 		break;
@@ -402,9 +424,8 @@
 	*memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
 #endif
 	{
-		extern int serial_console;  /* in console.c, of course */
 #if !CONFIG_SUN_SERIAL
-		serial_console = 0;
+		console_dev = MKDEV(TTYAUX_MAJOR, 1);
 #else
 		switch (console_fb) {
 		case 0: /* Let get our io devices from prom */
@@ -412,20 +433,20 @@
 				int idev = prom_query_input_device();
 				int odev = prom_query_output_device();
 				if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
-					serial_console = 0;
+					console_dev = MKDEV(TTYAUX_MAJOR, 1);
 				} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
-					serial_console = 1;
+					console_dev = MKDEV(TTYAUX_MAJOR, 64);
 				} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
-					serial_console = 2;
+					console_dev = MKDEV(TTYAUX_MAJOR, 65);
 				} else {
 					prom_printf("Inconsistent console\n");
 					prom_halt();
 				}
 			}
 			break;
-		case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
-		case 2: serial_console = 1; break; /* Force ttya as console */
-		case 3: serial_console = 2; break; /* Force ttyb as console */
+		case 1: console_dev = MKDEV(TTYAUX_MAJOR, 1); break; /* Force one of the framebuffers as console */
+		case 2: console_dev = MKDEV(TTYAUX_MAJOR, 64); break; /* Force ttya as console */
+		case 3: console_dev = MKDEV(TTYAUX_MAJOR, 65); break; /* Force ttyb as console */
 		}
 #endif
 	}
--- linux-2.1.29/arch/m68k/amiga/config.c.orig.real	Tue Mar 18 23:50:05 1997
+++ linux-2.1.29/arch/m68k/amiga/config.c	Tue Mar 25 21:36:41 1997
@@ -78,9 +78,11 @@
 extern struct consw fb_con;
 extern struct fb_info *amiga_fb_init(long *);
 extern void zorro_init(void);
-static void ami_savekmsg_init(void);
-static void ami_mem_print(const char *b);
-static void amiga_debug_init(void);
+static void amiga_savekmsg_init(void);
+static void amiga_mem_console_write(const char *b, unsigned int count);
+void amiga_serial_console_write(const char *s, unsigned int count);
+static void (*amiga_debug_init(void))(const char*, unsigned int);
+
 extern void amiga_video_setup(char *, int *);
 
 extern void (*kd_mksound)(unsigned int, unsigned int);
@@ -354,7 +356,7 @@
 
   /* initialize only once here, not every time the debug level is raised */
   if (!strcmp( m68k_debug_device, "mem" ))
-    ami_savekmsg_init();
+    amiga_savekmsg_init();
 
   /*
    * if it is an A3000, set the magic bit that forces
@@ -611,33 +613,6 @@
     }
 }
 
-void ami_serial_print (const char *str)
-{
-    while (*str) {
-        if (*str == '\n') {
-            custom.serdat = (unsigned char)'\r' | 0x100;
-            while (!(custom.serdatr & 0x2000))
-                ;
-        }
-        custom.serdat = (unsigned char)*str++ | 0x100;
-        while (!(custom.serdatr & 0x2000))
-            ;
-    }
-}
-
-static void amiga_debug_init (void)
-{
-    extern void (*debug_print_proc)(const char *);
-
-    if (!strcmp( m68k_debug_device, "ser" )) {
-        /* no initialization required (?) */
-        debug_print_proc = ami_serial_print;
-    } else if (!strcmp( m68k_debug_device, "mem" )) {
-        /* already initialized by config_amiga() (needed only once) */
-        debug_print_proc = ami_mem_print;
-    }
-}
-
 void dbprintf(const char *fmt , ...)
 {
 	static char buf[1024];
@@ -719,12 +694,13 @@
 
 }
 
-extern void *amiga_chip_alloc(long size);
 
+    /*
+     *  Debugging
+     */
 
 #define SAVEKMSG_MAXMEM		128*1024
 
-
 #define SAVEKMSG_MAGIC1		0x53415645	/* 'SAVE' */
 #define SAVEKMSG_MAGIC2		0x4B4D5347	/* 'KMSG' */
 
@@ -738,8 +714,15 @@
 
 static struct savekmsg *savekmsg = NULL;
 
+static void amiga_mem_console_write(const char *s, unsigned int count)
+{
+    if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) {
+        memcpy(savekmsg->data+savekmsg->size, s, count);
+        savekmsg->size += count;
+    }
+}
 
-static void ami_savekmsg_init(void)
+static void amiga_savekmsg_init(void)
 {
     savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM);
     savekmsg->magic1 = SAVEKMSG_MAGIC1;
@@ -748,18 +731,87 @@
     savekmsg->size = 0;
 }
 
+static void amiga_serial_putc(char c)
+{
+    custom.serdat = (unsigned char)c | 0x100;
+    while (!(custom.serdatr & 0x2000))
+	;
+}
+
+void amiga_serial_console_write(const char *s, unsigned int count)
+{
+    while (count--) {
+	if (*s == '\n')
+	    amiga_serial_putc('\r');
+	amiga_serial_putc(*s++);
+    }
+}
+
+#ifdef CONFIG_SERIAL_CONSOLE
+void amiga_serial_puts(const char *s)
+{
+    amiga_serial_console_write(s, strlen(s));
+}
 
-static void ami_mem_print(const char *b)
+void amiga_serial_gets(char *s, int len)
 {
-    int len;
+    int ch, cnt = 0;
+
+    while (1) {
+	while (!(custom.intreqr & IF_RBF))
+	    barrier();
+	ch = custom.serdatr & 0xff;
+	/* clear the interrupt, so that another character can be read */
+	custom.intreq = IF_RBF;
+
+	/* Check for backspace. */
+	if (ch == 8 || ch == 127) {
+	    if (cnt == 0) {
+		amiga_serial_putc('\007');
+		continue;
+	    }
+	    cnt--;
+	    amiga_serial_puts("\010 \010");
+	    continue;
+	}
+
+	/* Check for enter. */
+	if (ch == 10 || ch == 13)
+	    break;
+
+	/* See if line is too long. */
+	if (cnt >= len + 1) {
+	    amiga_serial_putc(7);
+	    cnt--;
+	    continue;
+	}
 
-    for (len = 0; b[len]; len++);
-    if (savekmsg->size+len <= SAVEKMSG_MAXMEM) {
-        memcpy(savekmsg->data+savekmsg->size, b, len);
-        savekmsg->size += len;
+	/* Store and echo character. */
+	s[cnt++] = ch;
+	amiga_serial_putc(ch);
     }
+    /* Print enter. */
+    amiga_serial_puts("\r\n");
+    s[cnt] = 0;
+}
+#endif
+
+static void (*amiga_debug_init(void))(const char*, unsigned int)
+{
+    if (!strcmp( m68k_debug_device, "ser" )) {
+        /* no initialization required (?) */
+        return(amiga_serial_console_write);
+    } else if (!strcmp( m68k_debug_device, "mem" )) {
+        /* already initialized by config_amiga() (needed only once) */
+        return(amiga_mem_console_write);
+    }
+    return(NULL);
 }
 
+
+    /*
+     *  Amiga specific parts of /proc
+     */
 
 static void amiga_get_model(char *model)
 {
--- linux-2.1.29/arch/m68k/atari/config.c.orig.real	Tue Mar 18 23:50:08 1997
+++ linux-2.1.29/arch/m68k/atari/config.c	Tue Mar 25 20:29:26 1997
@@ -52,6 +52,8 @@
 u_long atari_mch_cookie;
 struct atari_hw_present atari_hw_present;
 
+extern char m68k_debug_device[];
+
 static void atari_sched_init(void (*)(int, void *, struct pt_regs *));
 /* atari specific keyboard functions */
 extern int atari_keyb_init(void);
@@ -84,7 +86,7 @@
 static void atari_waitbut (void);
 extern struct consw fb_con;
 extern struct fb_info *atari_fb_init(long *);
-static void atari_debug_init (void);
+static void (*atari_debug_init(void))(const char*, unsigned int);
 extern void atari_video_setup(char *, int *);
 
 /* Can be set somewhere, if a SCC master reset has already be done and should
@@ -911,12 +913,12 @@
     mfp.usart_dta = c;
 }
 
-void ata_mfp_print (const char *str)
+static void ata_mfp_console_write (const char *str, unsigned int count)
 {
-    for( ; *str; ++str ) {
+    while (count--) {
 	if (*str == '\n')
 	    ata_mfp_out( '\r' );
-	ata_mfp_out( *str );
+	ata_mfp_out( *str++ );
     }
 }
 
@@ -929,12 +931,12 @@
     scc.cha_b_data = c;
 }
 
-void ata_scc_print (const char *str)
+static void ata_scc_console_write (const char *str, unsigned int count)
 {
-    for( ; *str; ++str ) {
+    while (cout--) {
 	if (*str == '\n')
 	    ata_scc_out( '\r' );
-	ata_scc_out( *str );
+	ata_scc_out( *str++ );
     }
 }
 
@@ -959,20 +961,20 @@
     return( 1 );
 }
 
-void ata_par_print (const char *str)
+static void ata_par_console_write (const char *str, unsigned int count)
 {
     static int printer_present = 1;
 
     if (!printer_present)
 	return;
 
-    for( ; *str; ++str ) {
+    while (count--) {
 	if (*str == '\n')
 	    if (!ata_par_out( '\r' )) {
 		printer_present = 0;
 		return;
 	    }
-	if (!ata_par_out( *str )) {
+	if (!ata_par_out( *str++ )) {
 	    printer_present = 0;
 	    return;
 	}
@@ -980,15 +982,12 @@
 }
 
 
-static void atari_debug_init( void )
+static void (*atari_debug_init(void))(const char*, unsigned int)
 {
-    extern void (*debug_print_proc)(const char *);
-    extern char m68k_debug_device[];
-    
 #ifdef CONFIG_KGDB
 	/* if the m68k_debug_device is used by the GDB stub, do nothing here */
 	if (kgdb_initialized)
-		return;
+		return(NULL);
 #endif
 
     if (!strcmp( m68k_debug_device, "ser" )) {
@@ -1007,7 +1006,7 @@
 	mfp.tim_dt_d   = 2;     /* 9600 bps */
 	mfp.tim_ct_cd |= 0x01;  /* start timer D, 1:4 */
 	mfp.trn_stat  |= 0x01;  /* enable TX */
-	debug_print_proc = ata_mfp_print;
+	return(ata_mfp_console_write);
     }
     else if (!strcmp( m68k_debug_device, "ser2" )) {
 	/* SCC Modem2 serial port */
@@ -1033,7 +1032,7 @@
 	    scc.cha_b_ctrl = *p++;
 	    MFPDELAY();
 	}
-	debug_print_proc = ata_scc_print;
+	return(ata_scc_console_write);
     }
     else if (!strcmp( m68k_debug_device, "par" )) {
 	/* parallel printer */
@@ -1044,14 +1043,13 @@
 	sound_ym.wd_data = 0;          /* no char */
 	sound_ym.rd_data_reg_sel = 14; /* select port A */
 	sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
-	debug_print_proc = ata_par_print;
+	return(ata_par_console_write);
     }
-    else
-	debug_print_proc = NULL;
+    return(NULL);
 }
 
 
-void ata_serial_print (const char *str)
+void ata_serial_print(const char *str)
 {
   int c;
 
--- linux-2.1.29/arch/m68k/kernel/setup.c.orig.real	Wed Mar 19 20:09:08 1997
+++ linux-2.1.29/arch/m68k/kernel/setup.c	Sun Mar 23 22:32:53 1997
@@ -56,9 +56,10 @@
 char saved_command_line[CL_SIZE];
 
 /* setup some dummy routines */
-static void dummy_waitbut(void)
-{
-}
+static void dummy_func(void)
+{}
+#define dummy_waitbut	dummy_func
+#define dummy_wait_key	dummy_func
 
 void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *));
 /* machine dependent keyboard functions */
@@ -81,17 +82,13 @@
 void (*waitbut)(void) = dummy_waitbut;
 struct fb_info *(*mach_fb_init)(long *);
 long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-void (*mach_debug_init)(void);
+void (*(*mach_debug_init)(void))(const char*, unsigned int) = NULL;
 void (*mach_video_setup) (char *, int *);
 #ifdef CONFIG_BLK_DEV_FD
 int (*mach_floppy_init) (void) = NULL;
 void (*mach_floppy_setup) (char *, int *) = NULL;
 void (*mach_floppy_eject) (void) = NULL;
 #endif
-#ifdef CONFIG_SERIAL_CONSOLE
-extern int serial_console;
-void (*mach_console_setup) (char *, int *) = NULL;
-#endif /* CONFIG_SERIAL_CONSOLE */
 
 extern int amiga_parse_bootinfo(const struct bi_record *);
 extern int atari_parse_bootinfo(const struct bi_record *);
@@ -102,10 +99,6 @@
 extern void config_sun3(void);
 extern void config_apollo(void);
 
-extern void register_console(void (*proc)(const char *));
-extern void ami_serial_print(const char *str);
-extern void ata_serial_print(const char *str);
-
 #define MASK_256K 0xfffc0000
 
 
@@ -164,12 +157,6 @@
 	int i;
 	char *p, *q;
 
-	/* machtype is set up by head.S, thus we know our gender */
-	if (MACH_IS_AMIGA)
-		register_console(ami_serial_print);
-	if (MACH_IS_ATARI)
-		register_console(ata_serial_print);
-
 	/* The bootinfo is located right after the kernel bss */
 	m68k_parse_bootinfo((const struct bi_record *)&_end);
 
@@ -333,16 +320,25 @@
 
 }
 
-#ifdef CONFIG_SERIAL_CONSOLE
-void console_setup(char *options, int *ints)
+
+static int debug_console_device(void)
 {
-    serial_console = ints[1] + 64;	/* callout_driver.minor_start */
-    if (mach_console_setup) {
-	/* initialize serial port, if necessary */
-	mach_console_setup(options, ints);
-    }
+    return 0;
 }
-#endif /* CONFIG_SERIAL_CONSOLE */
+
+static struct console debug_printk_console = {
+    NULL,
+    dummy_wait_key,
+    debug_console_device,
+    NULL
+};
+
+void m68k_debug_init(void)
+{
+    if (mach_debug_init && (debug_printk_console.write = mach_debug_init()))
+	register_console(&debug_printk_console);
+}
+
 
 int get_hardware_list(char *buffer)
 {
--- linux-2.1.29/arch/m68k/kernel/traps.c.orig.real	Tue Mar 18 23:50:14 1997
+++ linux-2.1.29/arch/m68k/kernel/traps.c	Sun Mar 23 22:32:53 1997
@@ -140,11 +140,13 @@
 }
 
 
+extern void m68k_debug_init(void);
+
 static inline void console_verbose(void)
 {
 	extern int console_loglevel;
 	console_loglevel = 15;
-	mach_debug_init();
+	m68k_debug_init();
 }
 
 static char *vec_names[] = {
--- linux-2.1.29/drivers/char/tga.c.orig.real	Thu Mar 20 21:04:07 1997
+++ linux-2.1.29/drivers/char/tga.c	Mon Mar 31 13:39:38 1997
@@ -38,8 +38,7 @@
 #include "selection.h"
 #include "console_macros.h"
 
-extern void register_console(void (*proc)(const char *));
-extern void console_print(const char *);
+extern struct console con_printk_console;
 
 /* TGA hardware description (minimal) */
 /*
@@ -486,7 +485,8 @@
 	/*
 	 * FINALLY, we can register TGA as console (whew!)
 	 */
-	register_console(console_print);
+	if (MINOR(console_dev) < 64)
+		register_console(&con_printk_console);
 }
 
 unsigned char PLLbits[7] = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
--- linux-2.1.29/drivers/char/console.c.orig.real	Mon Mar 24 21:40:28 1997
+++ linux-2.1.29/drivers/char/console.c	Mon Mar 31 13:41:14 1997
@@ -20,7 +20,6 @@
  *     'unsigned long con_init(unsigned long)'
  *     'int con_open(struct tty_struct *tty, struct file * filp)'
  *     'void con_write(struct tty_struct * tty)'
- *     'void console_print(const char * b)'
  *     'void update_screen(int new_console)'
  *
  *     'void do_blank_screen(int)'
@@ -140,14 +139,6 @@
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
 #endif
 
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(__sparc__)
-int serial_console = 0;
-#endif
-
-#ifdef __mc68000__
-extern int serial_debug;
-#endif /* __mc68000__ */
-
 struct tty_driver console_driver;
 static int console_refcount;
 static struct tty_struct *console_table[MAX_NR_CONSOLES];
@@ -170,7 +161,6 @@
 static void reset_terminal(int currcons, int do_clear);
 extern void reset_vc(unsigned int new_console);
 extern void vt_init(void);
-extern void register_console(void (*proc)(const char *));
 extern void vesa_blank(void);
 extern void vesa_powerdown(void);
 extern void compute_shiftstate(void);
@@ -342,7 +332,7 @@
 #include <linux/serial_reg.h>
 
 extern int serial_echo_init (int base);
-extern int serial_echo_print (const char *s);
+extern int serial_echo_print (const char *s, unsigned int count);
 
 /*
  * this defines the address for the port to which printk echoing is done
@@ -368,10 +358,9 @@
  * mechanism without modifying the rest of the code.
  */
 int
-serial_echo_print(const char *s)
+serial_echo_print(const char *s, unsigned int count)
 {
 	int     lsr, ier;
-	int     i;
 
 	if (!serial_echo_port) return (0);
 
@@ -384,14 +373,15 @@
 	/*
 	 * Now, do each character
 	 */
-	for (i = 0; *s; i++, s++) {
+	while (count--) {
+		char c = *s++;
 		WAIT_FOR_XMITR;
 
 		/* Send the character out. */
-		serial_echo_outb(*s, UART_TX);
+		serial_echo_outb(c, UART_TX);
 
 		/* if a LF, also do CR... */
-		if (*s == 10) {
+		if (c == 10) {
 			WAIT_FOR_XMITR;
 			serial_echo_outb(13, UART_TX);
 		}
@@ -2338,15 +2328,15 @@
 	}
 }
 
-void console_print(const char * b)
+static void con_printk(const char * b, unsigned int count)
 {
 	int currcons = fg_console;
 	unsigned char c;
 	static int printing = 0;
 #ifdef CONFIG_ABSTRACT_CONSOLE
 	const char *start = b;
-	ushort count      = 0;
-	ushort myx        = x;
+	ushort cnt = 0;
+	ushort myx = x;
 #endif /* CONFIG_ABSTRACT_CONSOLE */
 
 #if CONFIG_AP1000
@@ -2367,7 +2357,7 @@
 	}
 
 #ifdef CONFIG_SERIAL_ECHO
-        serial_echo_print(b);
+        serial_echo_print(b, count);
 #endif /* CONFIG_SERIAL_ECHO */
 
 #ifdef CONFIG_ABSTRACT_CONSOLE
@@ -2376,11 +2366,12 @@
 
 	/* Contrived structure to try to emulate original need_wrap behaviour
 	 * Problems caused when we have need_wrap set on '\n' character */
-	while ((c = *(b++)) != 0) {
+	while (count--) {
+		c = *b++;
 		if (c == 10 || c == 13 || c == 8 || need_wrap) {
-			if ((count = b - start - 1) > 0) {
-				sw->con_putcs(vc_cons[currcons].d, start, count, y, x);
-				x += count;
+			if ((cnt = b - start - 1) > 0) {
+				sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
+				x += cnt;
 				if (need_wrap)
 					x--;
 			}
@@ -2409,16 +2400,17 @@
 		pos+=2;
 		myx++;
 	}
-	if ((count = b - start -1) > 0) {
-		sw->con_putcs(vc_cons[currcons].d, start, count, y, x);
-		x += count;
+	if ((cnt = b - start) > 0) {
+		sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
+		x += cnt;
 		if (x == video_num_columns) {
 			x--;
 			need_wrap = 1;
 		}
 	}
 #else /* !CONFIG_ABSTRACT_CONSOLE */
-	while ((c = *(b++)) != 0) {
+	while (count--) {
+		c = *b++;
 		if (c == 10 || c == 13 || need_wrap) {
 			if (c != 13)
 				lf(currcons);
@@ -2444,6 +2436,22 @@
 	printing = 0;
 }
 
+static void dummy_wait_key(void)
+{}
+
+static int con_dev(void)
+{
+	return MKDEV(TTY_MAJOR, 1);
+}
+
+/* needed by tga.c */
+struct console con_printk_console = {
+	con_printk,
+	dummy_wait_key,
+	con_dev,
+	NULL
+};
+
 /*
  * con_throttle and con_unthrottle are only used for
  * paste_selection(), which has to stuff in a large number of
@@ -2528,12 +2536,12 @@
 	unsigned int currcons = 0;
 
 #ifdef __sparc__
-	if (serial_console) {
+	if (MINOR(console_dev) >= 64) {
 		fg_console = 0;
 
 #if CONFIG_SUN_SERIAL
-		rs_cons_hook(0, 0, serial_console);
-		rs_cons_hook(0, 1, serial_console);
+		rs_cons_hook(0, 0, console_dev-MKDEV(TTYAUX_MAJOR, 64));
+		rs_cons_hook(0, 1, console_dev-MKDEV(TTYAUX_MAJOR, 64));
 #endif
 
 		return kmem_start;
@@ -2667,13 +2675,7 @@
 
 	con_type_init_finish();
 
-	if (1
-#ifdef CONFIG_SERIAL_CONSOLE
-	    && !serial_console
-#endif /* CONFIG_SERIAL_CONSOLE */
-#ifdef __mc68000__
-	    && !serial_debug
-#endif /* __mc68000__ */
+	if (MINOR(console_dev) < 64
 #ifndef CONFIG_ABSTRACT_CONSOLE
 	/*
 	 * can't register TGA yet, because PCI bus probe has *not* taken
@@ -2684,7 +2686,7 @@
 	    && video_type != VIDEO_TYPE_TGAC
 #endif /* !CONFIG_ABSTRACT_CONSOLE */
 	    )
-	    register_console(console_print);
+	    register_console(&con_printk_console);
 
 	init_bh(CONSOLE_BH, console_bh);
 	return kmem_start;
--- linux-2.1.29/drivers/char/m68kserial.c.orig.real	Wed Mar 19 20:01:36 1997
+++ linux-2.1.29/drivers/char/m68kserial.c	Mon Mar 31 13:44:25 1997
@@ -73,6 +73,10 @@
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
 #endif
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#include <linux/kmon.h>
+#endif
 
 #include <asm/setup.h>
 #include <asm/system.h>
@@ -107,6 +111,14 @@
 struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
 
+#ifdef CONFIG_SERIAL_CONSOLE
+struct async_struct *serial_console_info = NULL;
+struct console serial_printk_console;
+static void init_serial_console(struct async_struct *info, unsigned int cflag);
+static unsigned int serial_console_cflag = 0;
+struct kmon_struct serial_kmon;
+#endif
+
 /* serial subtype definitions */
 #define SERIAL_TYPE_NORMAL	1
 #define SERIAL_TYPE_CALLOUT	2
@@ -1490,6 +1502,28 @@
 	} /* end switch on machine type */
 #endif
 
+#ifdef CONFIG_SERIAL_CONSOLE
+	/* TODO: This should be moved to the different *_init() functions, */
+	/* or can it be done device-independently (e.g. in SERIALSWITCH)???? */
+	/* Or maybe in register_serial()?? */
+	if (MINOR(console_dev) >= 64) {
+	    /* Currently this supports the Amiga builtin port only */
+	    if (MACH_IS_AMIGA) {
+		extern void amiga_serial_console_write(const char *s, unsigned int count);
+		extern void amiga_serial_gets(char *s, int len);
+		extern void amiga_serial_puts(const char *s);
+
+		init_serial_console(serial_console_info, serial_console_cflag);
+		serial_printk_console.write = amiga_serial_console_write;
+		register_console(&serial_printk_console);
+		serial_kmon.cons_gets = amiga_serial_gets;
+		serial_kmon.cons_puts = amiga_serial_puts;
+		serial_kmon.cons_enable = NULL;
+		serial_kmon.cons_disable = NULL;
+		register_monitor_io(&serial_kmon);
+	    }
+	}
+#endif
 	return 0;
 }
 
@@ -1590,6 +1624,97 @@
 	printk(KERN_INFO "tty%02d unloaded\n", info->line);
 	restore_flags(flags);
 }
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+static void init_serial_console(struct async_struct *info, unsigned int cflag)
+{
+	/* Nothing to be done yet */
+	/* TODO: implement this (in device dependent part??) */
+}
+
+/* Serial console setup. Called from linux/init/main.c */
+void serial_setup(char *str, int *ints)
+{
+	char *s;
+	int baud, bits, parity;
+	int cflag = CREAD | HUPCL | CLOCAL;
+
+	/* Sanity check. */
+	if (ints[0] > 3 || ints[1] > 3) return;
+
+	/* Get baud, bits and parity */
+	baud = 2400;
+	bits = 8;
+	parity = 'n';
+	if (ints[2]) baud = ints[2];
+	if ((s = strchr(str, ','))) {
+		do {
+			s++;
+		} while(*s >= '0' && *s <= '9');
+		if (*s) parity = *s++;
+		if (*s) bits   = *s - '0';
+	}
+
+	/* Now construct a cflag setting. */
+	switch (baud) {
+		case 1200:
+			cflag |= B1200;
+			break;
+		case 4800:
+			cflag |= B4800;
+			break;
+		case 9600:
+			cflag |= B9600;
+			break;
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+		case 2400:
+		default:
+			cflag |= B2400;
+			break;
+	}
+	switch (bits) {
+		case 7:
+			cflag |= CS7;
+			break;
+		default:
+		case 8:
+			cflag |= CS8;
+			break;
+	}
+	switch (parity) {
+		case 'o': case 'O':
+			cflag |= PARODD;
+			break;
+		case 'e': case 'E':
+			cflag |= PARENB;
+			break;
+	}
+
+	serial_console_info = &rs_table[ints[1]];
+	serial_console_cflag = cflag;
+}
+
+static int serial_console_device(void)
+{
+    return console_dev;
+}
+
+struct console serial_printk_console = {
+    NULL,
+    NULL,
+    serial_console_device,
+    NULL
+};
+
+struct kmon_struct serial_kmon;
+
+#endif /* CONFIG_SERIAL_CONSOLE */
 
 #ifdef MODULE
 int init_module(void)
--- linux-2.1.29/drivers/char/Config.in.orig.real	Mon Mar 24 21:39:06 1997
+++ linux-2.1.29/drivers/char/Config.in	Mon Mar 24 21:36:25 1997
@@ -5,6 +5,9 @@
 comment 'Character devices'
 
 tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
+if [ "$CONFIG_SERIAL" = y ]; then
+   bool 'Serial console support' CONFIG_SERIAL_CONSOLE
+fi
 bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
 if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
    bool '   Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
--- linux-2.1.29/drivers/char/serial.c.orig.real	Tue Mar 18 23:47:39 1997
+++ linux-2.1.29/drivers/char/serial.c	Sun Mar 30 22:51:42 1997
@@ -45,11 +45,18 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#include <linux/kmon.h>
+#endif
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <asm/irq.h>
+#endif
 
 static char *serial_name = "Serial driver";
 static char *serial_version = "4.24";
@@ -59,6 +66,16 @@
 static struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
 
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console serial_printk_console;
+static struct async_struct *serial_console_info = NULL;
+static void init_serial_console(struct async_struct *, unsigned int);
+static unsigned int serial_console_cflag = 0;
+static void serial_console_write(const char *s, unsigned int count);
+static void register_serial_monio(void);
+static int serial_console_int_disabled = 0;
+#endif
+
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
@@ -463,7 +480,8 @@
 }
 
 static _INLINE_ void receive_chars(struct async_struct *info,
-				 int *status)
+				 int *status,
+				 struct pt_regs * regs)
 {
 	struct tty_struct *tty = info->tty;
 	unsigned char ch;
@@ -513,6 +531,10 @@
 #ifdef SERIAL_DEBUG_INTR
 				printk("handling break....");
 #endif
+#ifdef CONFIG_SERIAL_CONSOLE
+			if (info == serial_console_info)
+				kernel_monitor(regs, "break", NULL);
+#endif
 				*tty->flip.flag_buf_ptr = TTY_BREAK;
 				if (info->flags & ASYNC_SAK)
 					do_SAK(tty);
@@ -699,7 +721,7 @@
 		printk("status = %x...", status);
 #endif
 		if (status & UART_LSR_DR)
-			receive_chars(info, &status);
+			receive_chars(info, &status, regs);
 		check_modem_status(info);
 		if (status & UART_LSR_THRE)
 			transmit_chars(info, 0);
@@ -763,7 +785,7 @@
 		printk("status = %x...", status);
 #endif
 		if (status & UART_LSR_DR)
-			receive_chars(info, &status);
+			receive_chars(info, &status, regs);
 		check_modem_status(info);
 		if (status & UART_LSR_THRE)
 			transmit_chars(info, 0);
@@ -826,7 +848,7 @@
 		printk("status = %x...", status);
 #endif
 		if (status & UART_LSR_DR)
-			receive_chars(info, &status);
+			receive_chars(info, &status, regs);
 		check_modem_status(info);
 		if (status & UART_LSR_THRE)
 			transmit_chars(info, 0);
@@ -3325,6 +3347,14 @@
 		       state->port, state->irq,
 		       uart_config[state->type].name);
 	}
+#ifdef CONFIG_SERIAL_CONSOLE
+	if (MINOR(console_dev) >= 64) {
+		init_serial_console(serial_console_info, serial_console_cflag);
+		serial_printk_console.write = serial_console_write;
+		register_console(&serial_printk_console);
+		register_serial_monio();
+	}
+#endif
 	return 0;
 }
 
@@ -3391,6 +3421,302 @@
 	printk(KERN_INFO "tty%02d unloaded\n", state->line);
 	restore_flags(flags);
 }
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+/*
+ * This is here to set the speed etc. for a non-initialized
+ * line. We also ALWAYS disable FIFO processing for simplicity.
+ * It will get enabled as soon as some process does an open()
+ * on the serial device.
+ * We have no termios struct yet, so we just pass "cflag".
+ */
+static void init_serial_console(struct async_struct *info, unsigned int cflag)
+{
+	unsigned short port;
+	unsigned cval,fcr;
+	int	i;
+	int	quot = 0;
+	unsigned long flags;
+
+	/* Calculate speed divisor. */
+	if (!(port = info->port))
+		return;
+
+	info->normal_termios.c_cflag = cflag;
+
+	i = cflag & CBAUD;
+	if (i & CBAUDEX) {
+		i &= ~CBAUDEX;
+		if (i == 1 || i == 2) i += 15;
+	}
+	/* We do not support baudrates of 0. */
+	if (!baud_table[i]) i = 13; /* 9600 */
+
+	if (baud_table[i] == 134)
+		quot = (2*info->baud_base / 269);
+	else
+		quot = info->baud_base / baud_table[i];
+
+	/* byte size and parity */
+	cval = cflag & (CSIZE | CSTOPB);
+	cval >>= 4;
+	if (cflag & PARENB)
+		cval |= UART_LCR_PARITY;
+	if (!(cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+
+	/* We do not support FIFO mode, so clear the buffers. */
+	if (info->type == PORT_16650 || info->type == PORT_16550A)
+		fcr = UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
+	else
+		fcr = 0;
+
+	/* Right, program the UART. */
+	save_flags(flags); cli();
+
+	/* Clear ports to be sure. */
+	(void) serial_inp(info, UART_LSR);
+	(void) serial_inp(info, UART_RX);
+	(void) serial_inp(info, UART_IIR);
+	(void) serial_inp(info, UART_MSR);
+
+	/* Disable UART interrupts. */
+	serial_out(info, UART_IER, 0);
+
+	/* Set DTR and RTS high. */
+	serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+
+	/* And set speed. */
+	serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
+	serial_outp(info, UART_DLL, quot & 0xff);	/* LS of divisor */
+	serial_outp(info, UART_DLM, quot >> 8);		/* MS of divisor */
+	serial_outp(info, UART_LCR, cval);		/* reset DLAB */
+	serial_outp(info, UART_FCR, fcr); 	/* set fcr */
+
+	(void)serial_in(info, UART_RX);    /* read data port to reset things */
+
+	restore_flags(flags);
+}
+
+/* Serial console setup. Called from linux/init/main.c */
+void serial_setup(char *str, int *ints)
+{
+	char *s;
+	int baud, bits, parity;
+	int cflag = CREAD | HUPCL | CLOCAL;
+
+	/* Sanity check. */
+	if (ints[0] > 3 || ints[1] > 3) return;
+
+	/* Get baud, bits and parity */
+	baud = 2400;
+	bits = 8;
+	parity = 'n';
+	if (ints[2]) baud = ints[2];
+	if ((s = strchr(str, ','))) {
+		do {
+			s++;
+		} while(*s >= '0' && *s <= '9');
+		if (*s) parity = *s++;
+		if (*s) bits   = *s - '0';
+	}
+
+	/* Now construct a cflag setting. */
+	switch(baud) {
+		case 1200:
+			cflag |= B1200;
+			break;
+		case 4800:
+			cflag |= B4800;
+			break;
+		case 9600:
+			cflag |= B9600;
+			break;
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+		case 2400:
+		default:
+			cflag |= B2400;
+			break;
+	}
+	switch(bits) {
+		case 7:
+			cflag |= CS7;
+			break;
+		default:
+		case 8:
+			cflag |= CS8;
+			break;
+	}
+	switch(parity) {
+		case 'o': case 'O':
+			cflag |= PARODD;
+			break;
+		case 'e': case 'E':
+			cflag |= PARENB;
+			break;
+	}
+
+	serial_console_info = &rs_table[ints[1]];
+	serial_console_cflag = cflag;
+}
+
+/* Stop interrupts. */
+static void serial_console_int_disable(void)
+{
+  if (serial_console_int_disabled) return;
+
+  /* First turn off interrupt on the controller. */
+  if (serial_console_info->tty && serial_console_info->irq)
+	disable_irq(serial_console_info->irq);
+
+  /* Now turn off interrupts on the UART. */
+  serial_out(serial_console_info, UART_IER, 0);
+
+  (void)serial_in(serial_console_info, UART_RX); /* read data port to reset */
+  serial_console_int_disabled = 1;
+}
+
+/* Retart interrupts. */
+static void serial_console_int_enable(void)
+{
+  if (!serial_console_int_disabled) return;
+
+  /* First turn on interrupts on the UART. */
+  serial_out(serial_console_info, UART_IER, serial_console_info->IER);
+
+  /* Now turn on interrupt on the controller. */
+  if (serial_console_info->tty && serial_console_info->irq)
+	enable_irq(serial_console_info->irq);
+
+  serial_console_int_disabled = 0;
+}
+
+/* Wait for transmitter register to empty. */
+static int serial_wait_thre(void)
+{
+	unsigned int tmout = 1000000;
+
+	while(!(serial_inp(serial_console_info, UART_LSR) & UART_LSR_THRE))
+		if (--tmout == 0) break;
+	return(tmout ? 0 : -1);
+}
+
+/* Send one character. */
+static int serial_send_one(unsigned char c)
+{
+	/* Wait for transmit register to empty. */
+	if (serial_wait_thre() < 0) return(-1);
+
+	serial_outp(serial_console_info, UART_TX, c);
+
+	return(0);
+}
+
+/* Send string. */
+static void serial_send_str(const char *b)
+{
+	unsigned char *ptr = (unsigned char *)b;
+
+	for(; *ptr; ptr++) {
+		/* Send CR if needed. */
+		if (*ptr == '\n') serial_send_one('\r');
+	
+		/* And output one character. */
+		if (serial_send_one(*ptr) < 0) break;
+	}
+	(void) serial_wait_thre();
+}
+
+/*
+ * Serial console output.
+ * This one is used by printk().
+ */
+static void serial_console_write(const char *s, unsigned int count)
+{
+	unsigned char *ptr = (unsigned char *)s;
+
+	/* Sanity check. */
+	if (serial_console_info->port == 0) return;
+
+	/* Turn off interrupts etc. */
+	serial_console_int_disable();
+
+	/* Print the data. */
+	while (count--) {
+		/* Send CR if needed. */
+		if (*ptr == '\n')
+			serial_send_one('\r');
+	
+		/* And output one character. */
+		if (serial_send_one(*ptr++) < 0)
+			break;
+	}
+	(void) serial_wait_thre();
+
+	/* And re-init serial port. */
+	serial_console_int_enable();
+}
+
+/* Read one line from the input. */
+static void serial_gets(char *s, int len)
+{
+  int ch, cnt = 0;
+
+  while(1) {
+	/* Get character. */
+	while(!(serial_inp(serial_console_info, UART_LSR) & UART_LSR_DR))
+		;
+	ch = serial_inp(serial_console_info, UART_RX);
+
+	/* Check for backspace. */
+	if (ch == 8 || ch == 127) {
+		if (cnt == 0) {
+			serial_send_one('\007');
+			continue;
+		}
+		cnt--;
+		serial_send_str("\010 \010");
+		continue;
+	}
+
+	/* Check for enter. */
+	if (ch == 10 || ch == 13) break;
+
+	/* See if line is too long. */
+	if (cnt >= len + 1) {
+		serial_send_one(7);
+		cnt--;
+		continue;
+	}
+
+	/* Store and echo character. */
+	s[cnt++] = ch;
+	serial_send_one(ch);
+  }
+  /* Print enter. */
+  serial_send_str("\r\n");
+  s[cnt] = 0;
+}
+
+static void register_serial_monio(void)
+{
+  struct kmon_struct km;
+
+  km.cons_gets = serial_gets;
+  km.cons_puts = serial_send_str;
+  km.cons_enable = serial_console_int_disable;
+  km.cons_disable = serial_console_int_enable;
+
+  register_monitor_io(&km);
+}
+
+#endif /* CONFIG_SERIAL_CONSOLE */
 
 #ifdef MODULE
 int init_module(void)
--- linux-2.1.29/drivers/char/amiga_ser.c.orig.real	Tue Mar 18 23:50:18 1997
+++ linux-2.1.29/drivers/char/amiga_ser.c	Mon Mar 31 13:46:17 1997
@@ -6,12 +6,13 @@
  *
  * Modifications by Matthias Welwarsky <Matthias.Welwarsky@ppp.th-darmstadt.de>
  * - fixed reentrancy problem in ser_tx_int()
- * 
+ *
  * 27/04/96 - Jes Soerensen: Upgraded for Linux-1.3.x.
  * 02/09/96 - Jes Soerensen: Moved the {request,free}_irq call for
  *            AMIGA_VERTB interrupts into the init/deinit funtions as
  *            there is no reason to service the ser_vbl_int when the
  *            serial port is not in use.
+ * 30/04/96 - Geert Uytterhoeven: Added incoming BREAK detection
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file COPYING in the main directory of this archive
@@ -113,7 +114,7 @@
     /* B38400 */ 38400,
     /* B57600 */ 57600
 };
-	
+
 static __inline__ void ser_DTRoff(void)
 {
     ciab.pra |= SER_DTR; /* active low */
@@ -162,11 +163,11 @@
 static struct async_struct *amiga_info;
 
 int amiga_serinit( void )
-{	
+{
 	unsigned long flags;
 	struct serial_struct req;
 	struct async_struct *info;
-	
+
 	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL))
 		return -ENODEV;
 
@@ -178,7 +179,7 @@
 		return -EBUSY;
 	}
     info = &rs_table[line];
-	
+
     save_flags (flags);
     cli();
 
@@ -201,23 +202,29 @@
      */
     ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
     ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
-    
+
     info->sw   = &amiga_ser_switch;
 
     return 0;
 }
 
+
 static void ser_rx_int(int irq, void *data, struct pt_regs *fp)
 {
       struct async_struct *info = data;
-      int ch;
+      int ch, err;
 
       ch = custom.serdatr;
 
       custom.intreq = IF_RBF;
 
-      rs_receive_char(info, ch & 0xff, 
-		      ch & SDR_OVRUN ? TTY_OVERRUN : 0);
+      if ((ch & 0x1ff) == 0)
+	   err = TTY_BREAK;
+      else if (ch & SDR_OVRUN)
+	   err = TTY_OVERRUN;
+      else
+	   err = 0;
+      rs_receive_char(info, ch & 0xff, err, fp);
 }
 
 static void ser_tx_int( int irq, void *data, struct pt_regs *fp)
@@ -245,7 +252,7 @@
 
 
 static void ser_init( struct async_struct *info )
-{	
+{
 	request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0,
 		    "serial status", amiga_info);
 
@@ -314,7 +321,7 @@
     unsigned	cflag, baud, chsize, stopb, parity, aflags;
     unsigned	div = 0;
     int realbaud;
-	
+
     if (!info->tty || !info->tty->termios) return;
 
     cflag  = info->tty->termios->c_cflag;
@@ -429,7 +436,7 @@
 	ser_DTRoff();
     else if (new_dtr == 1)
 	ser_DTRon();
-    
+
     if (new_rts == 0)
 	ser_RTSoff();
     else if (new_rts == 1)
--- linux-2.1.29/drivers/char/atari_MFPser.c.orig.real	Tue Mar 18 23:50:19 1997
+++ linux-2.1.29/drivers/char/atari_MFPser.c	Tue Mar 25 21:17:39 1997
@@ -252,7 +252,7 @@
 
 /*	save_flags(flags);
 	cli(); */
-	rs_receive_char (info, ch, err);
+	rs_receive_char (info, ch, err, fp);
 /*	restore_flags(flags); */
 }
 
@@ -279,7 +279,7 @@
 
 /*	save_flags(flags);
 	cli(); */
-	rs_receive_char (info, ch, err);
+	rs_receive_char (info, ch, err, fp);
 /*	restore_flags(flags); */
 }
 
--- linux-2.1.29/drivers/char/atari_MIDI.c.orig.real	Tue Mar 18 23:50:19 1997
+++ linux-2.1.29/drivers/char/atari_MIDI.c	Tue Mar 25 21:20:20 1997
@@ -52,7 +52,7 @@
 			err = TTY_FRAME;
 		if (stat & ACIA_OVRN)
 			err = TTY_OVERRUN;
-		rs_receive_char (midi_info, ch, err);
+		rs_receive_char (midi_info, ch, err, NULL);
 	}
 	if (acia.mid_ctrl & ACIA_TDRE) {
 
--- linux-2.1.29/drivers/char/atari_SCC.c.orig.real	Tue Mar 18 23:50:20 1997
+++ linux-2.1.29/drivers/char/atari_SCC.c	Tue Mar 25 21:18:12 1997
@@ -540,7 +540,7 @@
 #if DEBUG & DEBUG_INT
 	printk( "SCC ch %d rx int: char %02x\n", CHANNR(info), ch );
 #endif
-	rs_receive_char (info, ch, 0);
+	rs_receive_char (info, ch, 0, fp);
 #if DEBUG & DEBUG_OVERRUNS
 	{ int channel = CHANNR(info);
 	  if (++SCC_ch_cnt[channel] == 10000) {
@@ -595,7 +595,7 @@
 		else
 			err = 0;
 
-		rs_receive_char (info, ch, err);
+		rs_receive_char (info, ch, err, fp);
 
 		/* Overrun and parity errors have to be cleared
 		   manually, else the condition persists for the next
--- linux-2.1.29/drivers/char/ser_ioext.c.orig.real	Wed Mar 19 23:33:18 1997
+++ linux-2.1.29/drivers/char/ser_ioext.c	Tue Mar 25 21:18:34 1997
@@ -301,7 +301,7 @@
   #if DEBUG_IRQ
               printk("rs_receive_char(ch=%02X, err=%02X)\n", ch, err);
   #endif
-              rs_receive_char(info, ch, err);
+              rs_receive_char(info, ch, err, regs);
               got++;
               lsr = uart->LSR;
             }
--- linux-2.1.29/drivers/char/ser_mfc.c.orig.real	Wed Mar 19 23:16:57 1997
+++ linux-2.1.29/drivers/char/ser_mfc.c	Tue Mar 25 21:18:51 1997
@@ -229,7 +229,7 @@
 	    err |= TTY_PARITY;
 	  if ((status & SR_OVERRUN) != 0)
 	    err |= TTY_OVERRUN;
-	  rs_receive_char(rs_table + lines[i], ch, err);
+	  rs_receive_char(rs_table + lines[i], ch, err, fp);
 	  status = dp->pa.sr_csr.sr;
 	} 
       }
@@ -246,7 +246,7 @@
 	    err |= TTY_PARITY;
 	  if ((status & SR_OVERRUN) != 0)
 	    err |= TTY_OVERRUN;
-	  rs_receive_char(rs_table + lines[i + 1], ch, err);
+	  rs_receive_char(rs_table + lines[i + 1], ch, err, fp);
 	  status = dp->pb.sr_csr.sr;
 	} 
       }
--- linux-2.1.29/drivers/sbus/char/sunserial.c.orig.real	Tue Mar 18 23:47:49 1997
+++ linux-2.1.29/drivers/sbus/char/sunserial.c	Sun Mar 30 22:51:44 1997
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/console.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -996,14 +997,20 @@
 	return;
 }
 
+static void zs_console_print(const char *p)
+{
+	zs_con_printk(p, strlen(p));
+}
+
 /*
- * zs_console_print is registered for printk.
+ * zs_con_printk is registered for printk.
  */
-static void zs_console_print(const char *p)
+static void zs_con_printk(const char *p, unsigned int count)
 {
 	char c;
 
-	while((c=*(p++)) != 0) {
+	while (count--) {
+		c = *p++;
 		if(c == '\n')
 			rs_put_char('\r');
 		rs_put_char(c);
@@ -1875,12 +1882,11 @@
 	int channel, stop;
 	int carrier = 0;
 	int rtsdtr = 1;
-	extern int serial_console;
 
-	if (!serial_console)
+	if (MINOR(console_dev) < 64)
 		return;
 
-	if (serial_console == 1) {
+	if (console_dev = MKDEV(TTYAUX_MAJOR, 64)) {
 		mode_prop[3] = 'a';
 		cd_prop[3] = 'a';
 		dtr_prop[3] = 'a';
@@ -2031,7 +2037,20 @@
 	termios->c_cflag = cflag;
 }
 
-extern void register_console(void (*proc)(const char *));
+static void dummy_wait_key(void)
+{}
+
+static int zs_con_dev(void)
+{
+	return MKDEV(TTY_MAJOR, 1);
+}
+
+static struct console zs_printk_console = {
+	zs_con_printk,
+	dummy_wait_key,
+	zs_con_dev,
+	NULL
+};
 
 static inline void
 rs_cons_check(struct sun_serial *ss, int channel)
@@ -2057,7 +2076,7 @@
 			extern void serial_finish_init (void (*)(const char *));
 
 			serial_finish_init (zs_console_print);
-			register_console(zs_console_print);
+			register_console(&zs_printk_console);
 			consout_registered = 1;
 		}
 	}
--- linux-2.1.29/drivers/sbus/char/suncons.c.orig.real	Tue Mar 18 23:47:48 1997
+++ linux-2.1.29/drivers/sbus/char/suncons.c	Sun Mar 30 22:51:43 1997
@@ -64,6 +64,7 @@
 #include <linux/types.h>
 #include <linux/version.h>
 #include <linux/proc_fs.h>
+#include <linux/console.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -99,11 +100,9 @@
 void sun_hw_hide_cursor(void);
 void sun_hw_set_cursor(int,int);
 
-extern void register_console(void (*proc)(const char *));
 extern void console_print(const char *);
 extern void putconsxy(int, char *);
 extern unsigned char vga_font[];
-extern int serial_console;
 char *console_fb_path = NULL; /* Set in setup.c */
 
 /* The following variables describe a Sparc console. */
@@ -403,7 +402,7 @@
 	int currcons = 0;
 	unsigned short *ush;
 
-	if (serial_console)
+	if (MINOR(console_dev) >= 64)
 		return;
 	if (con_type == FBTYPE_SUNLEO) {
 		int rects [4];
@@ -452,7 +451,7 @@
         video_type = VIDEO_TYPE_SUN;
         *display_desc = "SUN";
 
-	if (!serial_console) {
+	if (MINOR(console_dev) < 64)
 		/* If we fall back to PROM then our output have to remain readable. */
 		prom_putchar('\033');  prom_putchar('[');  prom_putchar('H');
 
@@ -1197,7 +1196,7 @@
 __initfunc(unsigned long sun_console_init(unsigned long memory_start))
 {
 	int i, j;
-	if(serial_console)
+	if(MINOR(console_dev) >= 64)
 		return memory_start;
 
 	fbinfo = (fbinfo_t *)memory_start;
--- linux-2.1.29/include/linux/console.h.orig.real	Thu Mar 20 21:02:20 1997
+++ linux-2.1.29/include/linux/console.h	Sun Mar 30 22:52:12 1997
@@ -146,6 +146,40 @@
 
 #endif /* CONFIG_ABSTRACT_CONSOLE */
 
+/* The interface for /dev/console(s) and printk output */
+/* wait_key and device aren't used yet, but device MUST be filled in! */
+
+struct console
+{
+	/*
+	 * This function should not return before the string is written.
+	 */
+	void (*write)(const char*, unsigned int);
+
+	/*
+         * Only the console that was registered last with wait_key !=
+	 * NULL will be used. This blocks until there is a character
+	 * to give back, it does not schedule.
+         */
+	void (*wait_key)(void);
+
+	/*
+	 * Return the device to use when opening /dev/console. Only the
+	 * last registered console will do.
+	 */
+	int (*device)(void);
+
+	/* 
+	 * For a linked list of consoles for multiple output. Also
+	 * makes it easier to have a special console.
+	 */
+	struct console *next;
+};
+
+extern void register_console(struct console *);
+extern struct console *console_drivers;
+extern kdev_t console_dev;
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_CONSOLE_H_ */
--- linux-2.1.29/include/linux/kmon.h.orig.real	Sun Mar 23 21:52:19 1997
+++ linux-2.1.29/include/linux/kmon.h	Sun Mar 23 22:32:53 1997
@@ -0,0 +1,23 @@
+#ifndef _LINUX_KMON_H
+#define _LINUX_KMON_H
+
+/*
+ * 'kmon.h' contains the dispatch structure for the
+ * kernel monitor.
+ */
+
+struct kmon_struct {
+  void (*cons_gets)(char *s, int len);
+  void (*cons_puts)(const char *);
+  void (*cons_enable)(void);
+  void (*cons_disable)(void);
+  int (*kmonitor)(struct pt_regs *);
+};
+
+extern struct kmon_struct kmonitor;
+
+extern void register_monitor_io(struct kmon_struct *);
+int (*register_monitor(int (*newmon)(struct pt_regs *)))(struct pt_regs *);
+extern int kernel_monitor(struct pt_regs *, char *prompt, char *pmsg);
+
+#endif
--- linux-2.1.29/include/asm-m68k/machdep.h.orig.real	Tue Mar 18 23:50:41 1997
+++ linux-2.1.29/include/asm-m68k/machdep.h	Sun Mar 23 22:32:53 1997
@@ -36,10 +36,9 @@
 extern void (*waitbut)(void);
 extern struct fb_info *(*mach_fb_init)(long *);
 extern long mach_max_dma_address;
-extern void (*mach_debug_init)(void);
+extern void (*(*mach_debug_init)(void))(const char*, unsigned int);
 extern void (*mach_video_setup)(char *, int *);
 extern void (*mach_floppy_setup)(char *, int *);
 extern void (*mach_floppy_eject)(void);
-extern void (*mach_console_setup)(char *, int *);
 
 #endif /* _M68K_MACHDEP_H */
--- linux-2.1.29/include/asm-m68k/serial.h.orig.real	Wed Mar 19 00:15:23 1997
+++ linux-2.1.29/include/asm-m68k/serial.h	Tue Mar 25 21:23:49 1997
@@ -191,6 +191,12 @@
 #include <linux/termios.h>
 #include <linux/tqueue.h>
 
+#include <linux/config.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/kmon.h>
+extern struct async_struct *serial_console_info;
+#endif
+
 /*
  * Counters of the input lines (CTS, DSR, RI, CD) interrupts
  */
@@ -291,7 +297,8 @@
 }
 
 static __inline__ void rs_receive_char( struct async_struct *info,
-					    int ch, int err )
+					    int ch, int err,
+					    struct pt_regs * regs )
 {
 	struct tty_struct *tty = info->tty;
 	
@@ -299,6 +306,10 @@
 		return;
 	tty->flip.count++;
 	if (err == TTY_BREAK) {
+#ifdef CONFIG_SERIAL_CONSOLE
+		if (info == serial_console_info)
+			kernel_monitor(regs, "break", NULL);
+#endif
 		if (info->flags & ASYNC_SAK)
 			do_SAK(tty);
 	}
--- linux-2.1.29/init/main.c.orig.real	Wed Mar 19 21:22:01 1997
+++ linux-2.1.29/init/main.c	Mon Mar 31 01:19:40 1997
@@ -59,7 +59,7 @@
 #endif
 
 #ifdef __mc68000__
-#include <asm/machdep.h>
+extern void m68k_debug_init(void);
 #endif /* __mc68000__ */
 
 extern char _stext, _etext;
@@ -215,13 +215,11 @@
 extern void ipc_init(void);
 #endif
 
-#if defined(__sparc__) || defined(CONFIG_SERIAL_CONSOLE)
-extern int serial_console;
-#ifdef CONFIG_SERIAL_CONSOLE
-extern void console_setup(char *str, int *ints);
 static char console_env[] = "CONSOLE=/dev/ttySx";
-static char *console_dev  = console_env + 8;
-#endif
+static char *console_path  = console_env + 8;
+kdev_t console_dev = MKDEV(TTYAUX_MAJOR, 1);
+#ifdef CONFIG_SERIAL_CONSOLE
+extern void serial_setup(char *str, int *ints);
 #endif
 
 /*
@@ -250,8 +248,6 @@
 int root_mountflags = MS_RDONLY;
 char *execute_command = NULL;
 
-int serial_debug = 0;
-
 #ifdef CONFIG_ROOT_NFS
 char nfs_root_name[NFS_ROOT_NAME_LEN] = { "default" };
 char nfs_root_addrs[NFS_ROOT_ADDRS_LEN] = { "" };
@@ -260,7 +256,8 @@
 extern void dquot_init(void);
 
 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
-static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
+static char * envp_init[MAX_INIT_ENVS+3] = { "HOME=/", "TERM=linux",
+					     console_env, NULL, };
 
 char *get_options(char *str, int *ints)
 {
@@ -496,9 +493,6 @@
 #ifdef CONFIG_WDT
 	{ "wdt=", wdt_setup },
 #endif
-#ifdef CONFIG_SERIAL_CONSOLE
-	{ "console=", console_setup },
-#endif
 	{ 0, 0 }
 };
 
@@ -665,6 +659,40 @@
 	ROOT_DEV = to_kdev_t(base + simple_strtoul(line,NULL,base?10:16));
 }
 
+static void parse_console_dev(char * line)
+{
+	int base = 0;
+	static struct dev_name_struct {
+		const char *name;
+		const int num;
+	} devices[] = {
+		{ "ttyS",    MKDEV(TTYAUX_MAJOR, 64) },
+		{ "tty",     MKDEV(TTYAUX_MAJOR, 0) },
+		{ NULL, 0 }
+	};
+
+	if (strncmp(line,"/dev/",5) == 0) {
+		struct dev_name_struct *dev = devices;
+		line += 5;
+		do {
+			int len = strlen(dev->name);
+			if (strncmp(line,dev->name,len) == 0) {
+				line += len;
+				base = dev->num;
+				break;
+			}
+			dev++;
+		} while (dev->name);
+	}
+	console_dev = to_kdev_t(base + simple_strtoul(line,NULL,base?10:16));
+#ifdef CONFIG_SERIAL_CONSOLE
+	if (MAJOR(console_dev) == TTYAUX_MAJOR && MINOR(console_dev) >= 64) {
+		int ints[11];
+		serial_setup(get_options(line, ints), ints);
+	}
+#endif
+}
+
 /*
  * This is a simple kernel command line parsing function: it parses
  * the command line, and fills in the arguments/environment to init
@@ -683,7 +711,8 @@
 	if (!*line)
 		return;
 	args = 0;
-	envs = 1;	/* TERM is set to 'linux' by default */
+	envs = 2;	/* TERM is set to 'linux' by default */
+			/* CONSOLE is set too */
 	next = line;
 	while ((line = next) != NULL) {
 		if ((next = strchr(line,' ')) != NULL)
@@ -729,19 +758,19 @@
 		if (!strcmp(line,"debug")) {
 			console_loglevel = 10;
 #ifdef __mc68000__
-			mach_debug_init();
+			m68k_debug_init();
 #endif /* __mc68000__ */
 			continue;
 		}
-		if (!strcmp(line,"serdebug")) {
-			serial_debug = 1;
-			continue;
-		}
 		if (!strncmp(line,"init=",5)) {
 			line += 5;
 			execute_command = line;
 			continue;
 		}
+		if (!strncmp(line,"console=",8)) {
+			parse_console_dev(line+8);
+			continue;
+		}
 		if (checksetup(line))
 			continue;
 		
@@ -759,16 +788,11 @@
 			argv_init[++args] = line;
 		}
 	}
-#ifdef CONFIG_SERIAL_CONSOLE
-	if (serial_console)
-		console_env[17] = serial_console - 64 + '0';
-	else {
-		console_env[16] = '0';
+	if (MINOR(console_dev) < 64) {
+		console_env[16] = MINOR(console_dev) + '0';
 		console_env[17] = '\0';
-	}
-	if (envs < MAX_INIT_ENVS)
-		envp_init[++envs] = console_env;
-#endif
+	} else
+		console_env[17] = MINOR(console_dev) - 64 + '0';
 	argv_init[args+1] = NULL;
 	envp_init[envs+1] = NULL;
 }
@@ -970,18 +994,14 @@
 static int open_console(void)
 {
 #ifdef __sparc__
-        if (serial_console == 1)
+        if (console_dev == MKDEV(TTYAUX_MAJOR, 64))
                 return open("/dev/cua0", O_RDWR, 0);
-        if (serial_console == 2)
+        if (console_dev == MKDEV(TTYAUX_MAJOR, 65))
                 return open("/dev/cua1", O_RDWR, 0);
 #endif
-#ifdef CONFIG_SERIAL_CONSOLE
-	if (serial_console) {
-		int i = open(console_dev, O_RDWR, 0);
-		if (i >= 0)
-			return i;
-	}
-#endif
+	int i = open(console_path, O_RDWR, 0);
+	if (i >= 0)
+		return i;
 	return open("/dev/tty1", O_RDWR, 0);
 }
 
--- linux-2.1.29/kernel/printk.c.orig.real	Tue Mar 18 23:50:49 1997
+++ linux-2.1.29/kernel/printk.c	Mon Mar 31 13:31:29 1997
@@ -23,6 +23,7 @@
 #include <linux/tty_driver.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/console.h>
 
 #include <asm/uaccess.h>
 
@@ -30,8 +31,6 @@
 
 static char buf[1024];
 
-extern void console_print(const char *);
-
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
 
@@ -43,11 +42,7 @@
 struct wait_queue * log_wait = NULL;
 int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
 
-#ifdef __mc68000__
-#include <asm/machdep.h>
-void (*debug_print_proc)(const char *) = 0;
-#endif
-static void (*console_print_proc)(const char *) = 0;
+struct console *console_drivers = NULL;
 static char log_buf[LOG_BUF_LEN];
 static unsigned long log_start = 0;
 static unsigned long logged_chars = 0;
@@ -158,10 +153,6 @@
 		if (len < MINIMUM_CONSOLE_LOGLEVEL)
 			len = MINIMUM_CONSOLE_LOGLEVEL;
 		console_loglevel = len;
-#ifdef __mc68000__
-		if (len == 8)
-			mach_debug_init();
-#endif
 		error = 0;
 		break;
 	default:
@@ -217,20 +208,14 @@
 			if (*p == '\n')
 				break;
 		}
-		if (msg_level < console_loglevel && console_print_proc) {
-			char tmp = p[1];
-			p[1] = '\0';
-			(*console_print_proc)(msg);
-			p[1] = tmp;
-		}
-#ifdef __mc68000__
-		if ((msg_level == 0 || console_loglevel >= 8) && debug_print_proc) {
-			char tmp = p[1];
-			p[1] = '\0';
-			(*debug_print_proc)(msg);
-			p[1] = tmp;
+		if (msg_level < console_loglevel && console_drivers) {
+			struct console *c = console_drivers;
+			while (c) {
+				if (c->write)
+					c->write(msg, p - msg + 1);
+				c = c->next;
+			}
 		}
-#endif
 		if (*p == '\n')
 			msg_level = -1;
 	}
@@ -239,21 +224,52 @@
 	return i;
 }
 
+void console_print(const char *s)
+{
+	struct console *c = console_drivers;
+	int len = strlen(s);
+	while (c) {
+		if (c->write)
+			c->write(s, len);
+		c = c->next;
+	}
+}
+
 /*
  * The console driver calls this routine during kernel initialization
  * to register the console printing procedure with printk() and to
  * print any messages that were printed by the kernel before the
- * console driver was initialized.
+ * console driver was initialized. If a console of the same device
+ * exists, it is replaced by the new struct.
  */
-void register_console(void (*proc)(const char *))
+void register_console(struct console * console)
 {
-	int	i,j;
+	int	i, j, len;
 	int	p = log_start;
 	char	buf[16];
 	signed char msg_level = -1;
 	char	*q;
+	struct console *c, *prev;
+
+	/*
+	 *  Remove duplicates...
+	 */
+	for (c = console_drivers, prev = NULL; c != NULL;
+	     prev = c, c = c->next) {
+		if (c->device() == console->device()) {
+			if (prev == NULL)
+				console_drivers = c->next;
+			else
+				prev->next = c->next;
+			break;
+		}
+	}
 
-	console_print_proc = proc;
+	/*
+	 *  Register new console
+	 */
+	console->next = console_drivers;
+	console_drivers = console;
 
 	for (i=0,j=0; i < log_size; i++) {
 		buf[j++] = log_buf[p];
@@ -262,12 +278,15 @@
 			continue;
 		buf[j] = 0;
 		q = buf;
+		len = j;
 		if (msg_level < 0) {
 			msg_level = buf[1] - '0';
 			q = buf + 3;
+			len -= 3;
 		}
 		if (msg_level < console_loglevel)
-			(*proc)(q);
+			if (console->write)
+				console->write(q, len);
 		if (buf[j-1] == '\n')
 			msg_level = -1;
 		j = 0;
--- linux-2.1.29/kernel/kmon.c.orig.real	Sun Mar 23 21:52:18 1997
+++ linux-2.1.29/kernel/kmon.c	Mon Mar 31 14:11:53 1997
@@ -0,0 +1,143 @@
+/*
+ *  linux/kernel/kmon.c
+ *
+ *  Copyright (C) 1995 Miquel van Smoorenburg
+ *
+ *  These are the basic routines for a simple kernel monitor,
+ *  needed when we use a serial console.
+ *
+ *  One can register an external monitor with
+ *  register_monitor, it returns a pointer to the previous
+ *  function. The monitor will be called with interrupts
+ *  disabled, and it can use kmonitor.cons_gets and
+ *  kmonitor.cons_puts to do I/O.
+ *
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kmon.h>
+
+#define cputs kmonitor.cons_puts
+#define cgets kmonitor.cons_gets
+
+struct kmon_struct kmonitor = {
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+};
+
+/*
+ * Register the drivers for monitor input and output.
+ */
+void register_monitor_io(struct kmon_struct *km)
+{
+	kmonitor.cons_gets = km->cons_gets;
+	kmonitor.cons_puts = km->cons_puts;
+	kmonitor.cons_enable = km->cons_enable;
+	kmonitor.cons_disable = km->cons_disable;
+}
+
+/*
+ * Register the kernel monitor itself.
+ */
+int (*register_monitor(int (*newmon)(struct pt_regs *)))(struct pt_regs *)
+{
+	int (*omon)(struct pt_regs *);
+
+	omon = kmonitor.kmonitor;
+	kmonitor.kmonitor = newmon;
+
+	return omon;
+}
+
+/*
+ * Help for the "monitor".
+ */
+static void kernel_monitor_help(void)
+{
+	cputs("Linux serial monitor v0.1\n");
+	cputs("b    boot\n");
+	cputs("c    continue\n");
+	cputs("m    show memory\n");
+	cputs("p    show panic message\n");
+	cputs("s    show state\n");
+	cputs("r    show registers\n");
+}
+
+/*
+ * This is the kernel monitor.
+ */
+int kernel_monitor(struct pt_regs * regs, char *prompt, char *pmsg)
+{
+	unsigned long flags;
+	char s[64];
+	extern void hard_reset_now(void);
+	extern void show_mem(void);
+	extern void show_state(void);
+	extern void show_regs(struct pt_regs *);
+
+	/* Sanity check. */
+	if (cgets == NULL || cputs == NULL)
+		return -1;
+
+	/* Enable special console puts/gets code. */
+	if (kmonitor.cons_enable)
+		(*kmonitor.cons_enable)();
+
+	/* Turn off interrupts. */
+	save_flags(flags); cli();
+
+	/* See if another monitor has been registered. */
+	if (kmonitor.kmonitor) {
+		(*kmonitor.kmonitor)(regs);
+	} else {
+
+		/* Say hello to the crowd. */
+		cputs("Linux serial monitor v0.1\n");
+	
+		while(1) {
+			if (prompt) cputs(prompt);
+			cputs("> ");
+			cgets(s, 64);
+			if (*s == 0) continue;
+			if (strcmp(s, "c") == 0)
+				break;
+			else if (strcmp(s, "b") == 0)
+				hard_reset_now();
+			else if (strcmp(s, "m") == 0)
+				show_mem();
+			else if (strcmp(s, "s") == 0)
+				show_state();
+			else if (strcmp(s, "r") == 0) {
+				if (regs)
+					show_regs(regs);
+				else
+					cputs("No register data available\n");
+			} else if (strcmp(s, "p") == 0) {
+				if (pmsg) {
+					cputs(pmsg);
+					cputs("\n");
+				} else
+					cputs("No panic message available\n");
+			} else
+				kernel_monitor_help();
+		}
+	}
+
+	/* Turn on interrupts. */
+	restore_flags(flags);
+
+	/* Disable special console puts/gets code. */
+	if (kmonitor.cons_disable)
+		(*kmonitor.cons_disable)();
+
+	return 0;
+}
--- linux-2.1.29/kernel/Makefile.orig.real	Wed Jan 10 08:27:39 1996
+++ linux-2.1.29/kernel/Makefile	Sun Mar 23 22:32:53 1997
@@ -19,6 +19,10 @@
 OX_OBJS = ksyms.o
 endif
 
+ifeq ($(CONFIG_SERIAL_CONSOLE),y)
+O_OBJS += kmon.o
+endif
+
 include $(TOPDIR)/Rules.make
 
 sched.o: sched.c
--- linux-2.1.29/kernel/panic.c.orig.real	Tue Mar 18 23:50:49 1997
+++ linux-2.1.29/kernel/panic.c	Sun Mar 23 22:32:53 1997
@@ -14,9 +14,13 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/smp.h>
+#include <linux/config.h>
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/kmon.h>
+#endif   
 
 asmlinkage void sys_sync(void);	/* it's really int */
 extern void hard_reset_now(void);
@@ -74,6 +78,11 @@
 	kgdb_abort();
 #endif
 	sti();
+#ifdef CONFIG_SERIAL_CONSOLE
+	for(;;)
+		kernel_monitor(NULL, "panic", buf);
+#else
 	for(;;);
+#endif
 }
 
--- linux-2.1.29/kernel/sys.c.orig.real	Sun Feb 16 22:25:15 1997
+++ linux-2.1.29/kernel/sys.c	Sun Mar 23 22:32:53 1997
@@ -27,6 +27,9 @@
 #include <linux/apm_bios.h>
 #endif
 #include <linux/notifier.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/kmon.h>
+#endif          
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -226,6 +229,10 @@
 	else if (flag == 0xCDEF0123) {
 		/* SMP: We need to lock during the shutdown still */
 		lock_kernel();
+#ifdef CONFIG_SERIAL_CONSOLE
+		if (kernel_monitor(NULL, "halt", NULL) == 0)
+			return(0);
+#endif
 		printk(KERN_EMERG "System halted\n");
 #ifdef __sparc__
 		halt_now();

Greetings,

						Geert

--
Geert Uytterhoeven                     Geert.Uytterhoeven@cs.kuleuven.ac.be
Wavelets, Linux/m68k on Amiga          http://www.cs.kuleuven.ac.be/~geert/
Department of Computer Science -- Katholieke Universiteit Leuven -- Belgium

