diff -ruN linux-2.0.37.vanilla/Documentation/serial-console.txt linux-2.0.37/Documentation/serial-console.txt
--- linux-2.0.37.vanilla/Documentation/serial-console.txt	Thu Jan  1 01:00:00 1970
+++ linux-2.0.37/Documentation/serial-console.txt	Wed Jun  2 17:30:09 1999
@@ -0,0 +1,94 @@
+                       Linux Serial Console
+
+It is possible to specify multiple devices for console output. You can
+define a new kernel command line option to select which device(s) to
+use for console output.
+
+The format of this option is:
+
+	console=device,options
+
+	device:		tty0 for the foreground virtual console
+			ttyX for any other virtual console
+			ttySx for a serial port
+
+	options:	depend on the driver. For the serial port this
+			defines the baudrate/parity/bits of the port,
+			in the format BBBBPN, where BBBB is the speed,
+			P is parity (n/o/e), and N is bits. Default is
+			9600n8. The maximum baudrate is 115200.
+
+You can specify multiple console= options on the kernel command line.
+Output will appear on all of them. The last device will be used when
+you open /dev/console. So, for example:
+
+	console=ttyS1,9600 console=tty0
+
+defines that opening /dev/console will get you the current foreground
+virtual console, and kernel messages will appear on both the VGA
+console and the 2nd serial port (ttyS1 or COM2) at 9600 baud.
+
+Note that you can only define one console per device type (serial, video).
+
+If no console device is specified, the first device found capable of
+acting as a system console will be used. At this time, the system
+first looks for a VGA card and then for a serial port. So if you don't
+have a VGA card in your system the first serial port will automatically
+become the console.
+
+You will need to create a new device to use /dev/console. The official
+/dev/console is now character device 5,1.
+
+Here's an example that will use /dev/ttyS1 (COM2) as the console.
+Replace the sample values as needed.
+
+1. Create /dev/console (real console) and /dev/tty0 (master virtual
+   console):
+
+   cd /dev
+   rm -f console tty0
+   mknod -m 622 console c 5 1
+   mknod -m 622 tty0 c 4 0
+
+2. LILO can also take input from a serial device. This is a very
+   useful option. To tell LILO to use the serial port:
+   In lilo.conf (global section): 
+
+   serial  = 1,9600n8 (ttyS1, 9600 bd, no parity, 8 bits)
+
+3. Adjust to kernel flags for the new kernel,
+   again in lilo.conf (kernel section)
+
+   append = "console=ttyS1,9600" 
+
+4. Init and /etc/ioctl.save
+
+   Sysvinit remembers its stty settings in a file in /etc, called
+   `/etc/ioctl.save'. REMOVE THIS FILE before using the serial
+   console for the first time, because otherwise init will probably
+   set the baudrate to 38400 (baudrate of the virtual console).
+
+5. /dev/console and X
+   Programs that want to do something with the virtual console usually
+   open /dev/console. If you have created the new /dev/console device,
+   and your console is NOT the virtual console some programs will fail.
+   Those are programs that want to access the VT interface, and use
+   /dev/console instead of /dev/tty0. Some of those programs are:
+
+   Xfree86, svgalib, gpm, SVGATextMode
+
+   I have binary patched the above mentioned programs to use "tty0"
+   instead of "console".  This will be reported to the maintainers of
+   said programs.
+
+   Note that if you boot without a console= option (or with
+   console=/dev/tty0), /dev/console is the same as /dev/tty0. In that
+   case everything will still work.
+
+6. Thanks
+
+   Thanks to Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be>
+   for porting the patches from 2.1.4x to 2.1.6x for taking care of
+   the integration of these patches into m68k, ppc and alpha.
+
+Miquel van Smoorenburg <miquels@cistron.nl>, 21-Mar-1998
diff -ruN linux-2.0.37.vanilla/drivers/char/Config.in linux-2.0.37/drivers/char/Config.in
--- linux-2.0.37.vanilla/drivers/char/Config.in	Wed Jun  2 17:16:00 1999
+++ linux-2.0.37/drivers/char/Config.in	Wed Jun  2 17:30:09 1999
@@ -10,6 +10,9 @@
 		bool '  PCI serial support' CONFIG_SERIAL_PCI
 	fi
 fi
+if [ "$CONFIG_SERIAL" = "y" ]; then
+  bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+fi
 bool 'Digiboard PC/Xx Support' CONFIG_DIGI
 tristate 'Cyclades async mux support' CONFIG_CYCLADES
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -ruN linux-2.0.37.vanilla/drivers/char/console.c linux-2.0.37/drivers/char/console.c
--- linux-2.0.37.vanilla/drivers/char/console.c	Thu Jun  4 22:54:48 1998
+++ linux-2.0.37/drivers/char/console.c	Wed Jun  2 17:30:09 1999
@@ -18,7 +18,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)'
@@ -92,6 +91,7 @@
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
+#include <linux/console.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -145,13 +145,13 @@
 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_unblank(void);
 extern void vesa_powerdown(void);
 extern void compute_shiftstate(void);
 extern void reset_palette(int currcons);
 extern void set_palette(void);
+extern int con_is_present(void);
 extern unsigned long con_type_init(unsigned long, const char **);
 extern int set_get_cmap(unsigned char *, int);
 extern int set_get_font(unsigned char *, int, int);
@@ -1854,7 +1854,7 @@
 	}
 }
 
-void console_print(const char * b)
+static void vt_console_print(struct console *co, const char * b)
 {
 	int currcons = fg_console;
 	unsigned char c;
@@ -1902,6 +1902,27 @@
 	printing = 0;
 }
 
+static kdev_t vt_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
+}
+
+extern int keyboard_wait_for_keypress(struct console *);
+
+struct console vt_console_driver = {
+        "tty",
+        vt_console_print,
+        NULL,
+        vt_console_device,
+        keyboard_wait_for_keypress,
+        do_unblank_screen,
+        NULL,
+        CON_PRINTBUFFER,
+        -1,
+        0,
+        NULL
+};
+
 /*
  * con_throttle and con_unthrottle are only used for
  * paste_selection(), which has to stuff in a large number of
@@ -2103,8 +2124,8 @@
 	 * initialization and register_console() event from
 	 * within the bus probing code... :-(
 	 */
-	if (video_type != VIDEO_TYPE_TGAC)
-		register_console(console_print);
+	if (video_type != VIDEO_TYPE_TGAC && con_is_present())
+		register_console(&vt_console_driver);
 
 	init_bh(CONSOLE_BH, console_bh);
 	return kmem_start;
diff -ruN linux-2.0.37.vanilla/drivers/char/keyboard.c linux-2.0.37/drivers/char/keyboard.c
--- linux-2.0.37.vanilla/drivers/char/keyboard.c	Wed Jun  2 17:16:00 1999
+++ linux-2.0.37/drivers/char/keyboard.c	Wed Jun  2 17:30:09 1999
@@ -159,6 +159,15 @@
 /* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
 static struct pt_regs * pt_regs;
 
+struct wait_queue * keypress_wait = NULL;
+struct console;
+
+int keyboard_wait_for_keypress(struct console *co)
+{
+        sleep_on(&keypress_wait);
+	return 0;
+}
+
 static inline void kb_wait(void)
 {
 	int i;
diff -ruN linux-2.0.37.vanilla/drivers/char/n_tty.c linux-2.0.37/drivers/char/n_tty.c
--- linux-2.0.37.vanilla/drivers/char/n_tty.c	Thu Aug  7 18:34:37 1997
+++ linux-2.0.37/drivers/char/n_tty.c	Wed Jun  2 17:30:09 1999
@@ -39,6 +39,7 @@
 #include <asm/bitops.h>
 
 #define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
+#define SYSCONS_DEV  MKDEV(TTYAUX_MAJOR,1)
 
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
@@ -780,6 +781,7 @@
 	   check of the logic of this change. -- jlc */
 	/* don't stop on /dev/console */
 	if (file->f_inode->i_rdev != CONSOLE_DEV &&
+	    file->f_inode->i_rdev != SYSCONS_DEV &&
 	    current->tty == tty) {
 		if (tty->pgrp <= 0)
 			printk("read_chan: tty->pgrp <= 0!\n");
@@ -938,7 +940,8 @@
 	int retval = 0;
 
 	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
-	if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) {
+	if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV &&
+			     file->f_inode->i_rdev != SYSCONS_DEV) {
 		retval = tty_check_change(tty);
 		if (retval)
 			return retval;
diff -ruN linux-2.0.37.vanilla/drivers/char/serial.c linux-2.0.37/drivers/char/serial.c
--- linux-2.0.37.vanilla/drivers/char/serial.c	Wed Jun  2 17:16:01 1999
+++ linux-2.0.37/drivers/char/serial.c	Wed Jun  2 17:30:09 1999
@@ -45,6 +45,9 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
 
 #ifdef CONFIG_SERIAL_PCI
 #include <linux/pci.h>
@@ -120,6 +123,9 @@
 static volatile int rs_irq_triggered;
 static volatile int rs_triggered;
 static int rs_wild_int_mask;
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console sercons;
+#endif
 
 static void autoconfig(struct async_struct * info);
 static void change_speed(struct async_struct *info);
@@ -2562,6 +2568,14 @@
 		change_speed(info);
 	}
 
+#ifdef CONFIG_SERIAL_CONSOLE
+	if (sercons.cflag && sercons.index == line) {
+		tty->termios->c_cflag = sercons.cflag;
+		sercons.cflag = 0;
+		change_speed(info);
+        }
+#endif
+
 	info->session = current->session;
 	info->pgrp = current->pgrp;
 
@@ -3125,7 +3139,20 @@
 		IRQ_timeout[i] = 0;
 		memset(&rs_multiport[i], 0, sizeof(struct rs_multiport_struct));
 	}
-	
+
+#ifdef CONFIG_SERIAL_CONSOLE
+	/*
+	 *	The interrupt of the serial console port
+	 *	can't be shared.
+	 */
+	if (sercons.flags & CON_CONSDEV) {
+		for(i = 0; i < NR_PORTS; i++)
+			if (i != sercons.index &&
+			    rs_table[i].irq == rs_table[sercons.index].irq)
+				rs_table[i].irq = 0;
+	}
+#endif
+
 	show_serial_version();
 #ifdef CONFIG_SERIAL_PCI
 		probe_serial_pci();
@@ -3301,3 +3328,235 @@
 	}
 }
 #endif /* MODULE */
+
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ *	Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct async_struct *ser)
+{
+	int lsr;
+	unsigned int tmout = 1000000;
+
+	do {
+		lsr = inb(ser->port + UART_LSR);
+		if (--tmout == 0) break;
+	} while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
+}
+
+/*
+ *	Print a string to the serial port trying not to disturb
+ *	any possible real use of the port...
+ */
+static void serial_console_write(struct console *co, const char *s)
+{
+	struct async_struct *ser;
+	int ier;
+
+	ser = rs_table + co->index;
+	/*
+	 *	First save the IER then disable the interrupts
+	 */
+	ier = inb(ser->port + UART_IER);
+	outb(0x00, ser->port + UART_IER);
+
+	/*
+	 *	Now, do each character
+	 */
+	for (; *s; s++) {
+		wait_for_xmitr(ser);
+
+		/*
+		 *	Send the character out.
+		 *	If a LF, also do CR...
+		 */
+		outb(*s, ser->port + UART_TX);
+		if (*s == 10) {
+			wait_for_xmitr(ser);
+			outb(13, ser->port + UART_TX);
+		}
+	}
+
+	/*
+	 *	Finally, Wait for transmitter & holding register to empty
+	 * 	and restore the IER
+	 */
+	wait_for_xmitr(ser);
+	outb(ier, ser->port + UART_IER);
+}
+
+/*
+ *	Receive character from the serial port
+ */
+static int serial_console_wait_key(struct console *co)
+{
+	struct async_struct *ser;
+	int ier;
+	int lsr;
+	int c;
+
+	ser = rs_table + co->index;
+
+	/*
+	 *	First save the IER then disable the interrupts so
+	 *	that the real driver for the port does not get the
+	 *	character.
+	 */
+	ier = inb(ser->port + UART_IER);
+	outb(0x00, ser->port + UART_IER);
+
+	do {
+		lsr = inb(ser->port + UART_LSR);
+	} while (!(lsr & UART_LSR_DR));
+	c = inb(ser->port + UART_RX);
+
+	/*
+	 *	Restore the interrupts
+	 */
+	outb(ier, ser->port + UART_IER);
+
+	return c;
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ *	Setup initial baud/bits/parity. We do two things here:
+ *	- construct a cflag setting for the first rs_open()
+ *	- initialize the serial port
+ *	Return non-zero if we didn't find a serial port.
+ */
+static int serial_console_setup(struct console *co, char *options)
+{
+	struct async_struct *ser;
+	unsigned cval;
+	int	baud = 9600;
+	int	bits = 8;
+	int	parity = 'n';
+	int	cflag = CREAD | HUPCL | CLOCAL;
+	int	quot = 0;
+	char	*s;
+
+	if (options) {
+		baud = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s) parity = *s++;
+		if (*s) bits   = *s - '0';
+	}
+
+	/*
+	 *	Now construct a cflag setting.
+	 */
+	switch(baud) {
+		case 1200:
+			cflag |= B1200;
+			break;
+		case 2400:
+			cflag |= B2400;
+			break;
+		case 4800:
+			cflag |= B4800;
+			break;
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+		case 57600:
+			cflag |= B57600;
+			break;
+		case 115200:
+			cflag |= B115200;
+			break;
+		case 9600:
+		default:
+			cflag |= B9600;
+			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;
+	}
+	co->cflag = cflag;
+
+	/*
+	 *	Divisor, bytesize and parity
+	 */
+	ser = rs_table + co->index;
+	quot = ser->baud_base / baud;
+	cval = cflag & (CSIZE | CSTOPB);
+#if defined(__powerpc__) || defined(__alpha__)
+	cval >>= 8;
+#else /* !__powerpc__ && !__alpha__ */
+	cval >>= 4;
+#endif /* !__powerpc__ && !__alpha__ */
+	if (cflag & PARENB)
+		cval |= UART_LCR_PARITY;
+	if (!(cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+
+	/*
+	 *	Disable UART interrupts, set DTR and RTS high
+	 *	and set speed.
+	 */
+	outb(cval | UART_LCR_DLAB, ser->port + UART_LCR);	/* set DLAB */
+	outb(quot & 0xff, ser->port + UART_DLL);	/* LS of divisor */
+	outb(quot >> 8, ser->port + UART_DLM);		/* MS of divisor */
+	outb(cval, ser->port + UART_LCR);		/* reset DLAB */
+	outb(0, ser->port + UART_IER);
+	outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
+
+	/*
+	 *	If we read 0xff from the LSR, there is no UART here.
+	 */
+	if (inb(ser->port + UART_LSR) == 0xff)
+		return -1;
+	return 0;
+}
+
+static struct console sercons = {
+	"ttyS",
+	serial_console_write,
+	NULL,
+	serial_console_device,
+	serial_console_wait_key,
+	NULL,
+	serial_console_setup,
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+/*
+ *	Register console.
+ */
+long serial_console_init(long kmem_start, long kmem_end)
+{
+	register_console(&sercons);
+	return kmem_start;
+}
+#endif
diff -ruN linux-2.0.37.vanilla/drivers/char/tga.c linux-2.0.37/drivers/char/tga.c
--- linux-2.0.37.vanilla/drivers/char/tga.c	Wed Jun  2 17:16:01 1999
+++ linux-2.0.37/drivers/char/tga.c	Wed Jun  2 17:37:16 1999
@@ -38,8 +38,7 @@
 #include "selection.h"
 #include "console_struct.h"
 
-extern void register_console(void (*proc)(const char *));
-extern void console_print(const char *);
+extern struct console vt_console_driver;
 extern void set_palette (void); /* vga.c */
 
 /* TGA hardware description (minimal) */
@@ -442,6 +441,19 @@
 }
 
 /*
+ *	See if we have a TGA card.
+ */
+int con_is_present()
+{
+	unsigned char pci_bus, pci_devfn;
+	int status;
+
+	status = pcibios_find_device (PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA,
+				      0, &pci_bus, &pci_devfn);
+	return (status == PCIBIOS_DEVICE_NOT_FOUND) ? 0 : 1;
+}
+
+/*
  * video init code, called from within the PCI bus probing code;
  * when TGA console is configured, at the end of the probing code,
  * we call here to look for a TGA device, and proceed...
@@ -484,7 +496,14 @@
 	}
 	tga_init_video();
 	tga_clear_screen();
-
+#if 0 /* FIXME */
+	/*
+	 *	Hey, where did register_console go? Besides, we need
+	 *	to register &tga_console_driver I think. Oh well
+	 *	probably noone runs an Alpha with TGA anymore ?
+	 */
+	register_console(&vt_console_driver);
+#endif
 }
 
 unsigned char PLLbits[7] = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
diff -ruN linux-2.0.37.vanilla/drivers/char/tty_io.c linux-2.0.37/drivers/char/tty_io.c
--- linux-2.0.37.vanilla/drivers/char/tty_io.c	Wed Jun  2 17:16:01 1999
+++ linux-2.0.37/drivers/char/tty_io.c	Wed Jun  2 17:30:09 1999
@@ -59,6 +59,7 @@
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
+#include <linux/console.h>
 #include <linux/timer.h>
 #include <linux/ctype.h>
 #include <linux/kd.h>
@@ -82,6 +83,7 @@
 
 #define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
 #define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
+#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1)
 
 #undef TTY_DEBUG_HANGUP
 
@@ -108,7 +110,6 @@
 int want_console = -1;
 int kmsg_redirect = 0;
 struct tty_struct * redirect = NULL;
-struct wait_queue * keypress_wait = NULL;
 char vt_dont_switch = 0;
 
 static void initialize_tty_struct(struct tty_struct *tty);
@@ -373,7 +374,9 @@
 {
 	int i;
 	struct file * filp;
+	struct file * cons_filp = NULL;
 	struct task_struct *p;
+	int closecount = 0, n;
 
 	if (!tty)
 		return;
@@ -385,10 +388,14 @@
 			continue;
 		if (!filp->f_inode)
 			continue;
-		if (filp->f_inode->i_rdev == CONSOLE_DEV)
+		if (filp->f_inode->i_rdev == CONSOLE_DEV ||
+		    filp->f_inode->i_rdev == SYSCONS_DEV) {
+			cons_filp = filp;
 			continue;
+		}
 		if (filp->f_op != &tty_fops)
 			continue;
+		closecount++;
 		tty_fasync(filp->f_inode, filp, 0);
 		filp->f_op = fops;
 	}
@@ -437,7 +444,11 @@
 	tty->ctrl_status = 0;
 	if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
 		*tty->termios = tty->driver.init_termios;
-	if (tty->driver.hangup)
+	if (cons_filp) {
+		if (tty->driver.close)
+			for (n = 0; n < closecount; n++)
+				tty->driver.close(tty, cons_filp);
+	} else if (tty->driver.hangup)
 		(tty->driver.hangup)(tty);
 }
 
@@ -687,7 +698,8 @@
 
 void wait_for_keypress(void)
 {
-	sleep_on(&keypress_wait);
+	struct console *c = console_drivers;
+	if (c) c->wait_key(c);
 }
 
 void stop_tty(struct tty_struct *tty)
@@ -804,7 +816,12 @@
 	int is_console;
 	struct tty_struct * tty;
 
-	is_console = (inode->i_rdev == CONSOLE_DEV);
+	/*
+	 *	For now, we redirect writes from /dev/console as
+	 *	well as /dev/tty0.
+	 */
+	is_console = (inode->i_rdev == CONSOLE_DEV ||
+		      inode->i_rdev == SYSCONS_DEV);
 
 	if (is_console && redirect)
 		tty = redirect;
@@ -1357,6 +1374,15 @@
 		device = MKDEV(TTY_MAJOR, fg_console+1);
 		noctty = 1;
 	}
+	if (device == SYSCONS_DEV) {
+		struct console *c = console_drivers;
+		while(c && !c->device)
+			c = c->next;
+		if (!c)
+			 return -ENODEV;
+		device = c->device(c);
+		noctty = 1;
+	}
 	minor = MINOR(device);
 	
 	retval = init_dev(device, &tty);
@@ -1585,7 +1611,8 @@
 			real_tty->winsize = tmp_ws;
 			return 0;
 		case TIOCCONS:
-			if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE) {
+			if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE ||
+			    tty->driver.type == TTY_DRIVER_TYPE_SYSCONS) {
 				if (!suser())
 					return -EPERM;
 				redirect = NULL;
@@ -2008,10 +2035,15 @@
 	 * set up the console device so that later boot sequences can 
 	 * inform about problems etc..
 	 */
-	return con_init(kmem_start);
+	kmem_start = con_init(kmem_start);
+#ifdef CONFIG_SERIAL_CONSOLE
+	kmem_start = serial_console_init(kmem_start, kmem_end);
+#endif
+	return kmem_start;
 }
 
-static struct tty_driver dev_tty_driver, dev_console_driver;
+static struct tty_driver dev_tty_driver, dev_console_driver,
+	dev_syscons_driver;
 
 /*
  * Ok, now we can initialize the rest of the tty devices and can count
@@ -2039,12 +2071,22 @@
 	if (tty_register_driver(&dev_tty_driver))
 		panic("Couldn't register /dev/tty driver\n");
 
+	dev_syscons_driver = dev_tty_driver;
+	dev_syscons_driver.name = "console";
+	dev_syscons_driver.major = TTYAUX_MAJOR;
+	dev_syscons_driver.minor_start = 1;
+	dev_syscons_driver.type = TTY_DRIVER_TYPE_SYSTEM;
+	dev_syscons_driver.subtype = SYSTEM_TYPE_SYSCONS;
+
+	if (tty_register_driver(&dev_syscons_driver))
+		panic("Couldn't register /dev/console driver\n");
+	
 	dev_console_driver = dev_tty_driver;
-	dev_console_driver.name = "console";
+	dev_console_driver.name = "tty0";
 	dev_console_driver.major = TTYAUX_MAJOR;
 
 	if (tty_register_driver(&dev_console_driver))
-		panic("Couldn't register /dev/console driver\n");
+		panic("Couldn't register /dev/tty0 driver\n");
 	
 	kbd_init();
 #ifdef CONFIG_SERIAL
diff -ruN linux-2.0.37.vanilla/drivers/char/vga.c linux-2.0.37/drivers/char/vga.c
--- linux-2.0.37.vanilla/drivers/char/vga.c	Tue May  7 06:50:53 1996
+++ linux-2.0.37/drivers/char/vga.c	Wed Jun  2 17:30:09 1999
@@ -136,6 +136,31 @@
 	restore_flags(flags);
 }
 
+int con_is_present(void)
+{
+	unsigned short saved;
+	unsigned short *p;
+
+	/*
+	 *	Find out if there is a graphics card present.
+	 *	Are there smarter methods around?
+	 */
+	p = (unsigned short *) video_mem_base;
+	saved = scr_readw(p);
+	scr_writew(0xAA55, p);
+	if (scr_readw(p) != 0xAA55) {
+		scr_writew(saved, p);
+		return 0;
+	}
+	scr_writew(0x55AA, p);
+	if (scr_readw(p) != 0x55AA) {
+		scr_writew(saved, p);
+		return 0;
+	}
+	scr_writew(saved, p);
+	return 1;
+}
+
 unsigned long
 con_type_init(unsigned long kmem_start, const char **display_desc)
 {
diff -ruN linux-2.0.37.vanilla/include/linux/console.h linux-2.0.37/include/linux/console.h
--- linux-2.0.37.vanilla/include/linux/console.h	Mon May 20 06:54:29 1996
+++ linux-2.0.37/include/linux/console.h	Wed Jun  2 17:30:09 1999
@@ -16,6 +16,8 @@
 
 #define NPAR 16
 
+struct vc_data;
+#if 0
 struct vc_data {
 	unsigned long	vc_screenbuf_size;
 	unsigned short	vc_num;			/* Console number */
@@ -80,6 +82,7 @@
 	struct consw 	*vc_sw;
 	/* additional information is in vt_kern.h */
 };
+#endif
 
 /*
  * this is what the terminal answers to a ESC-Z or csi0c query.
@@ -120,5 +123,45 @@
 #define CM_DRAW     (1)
 #define CM_ERASE    (2)
 #define CM_MOVE     (3)
+
+/*
+ *	Array of consoles built from command line options (console=)
+ */
+struct console_cmdline
+{
+	char	name[8];			/* Name of the driver	    */
+	int	index;				/* Minor dev. to use	    */
+	char	*options;			/* Options for the driver   */
+};
+#define MAX_CMDLINECONSOLES 8
+extern struct console_cmdline console_list[MAX_CMDLINECONSOLES];
+
+/*
+ *	The interface for a console, or any other device that
+ *	wants to capture console messages (printer driver?)
+ */
+
+#define CON_PRINTBUFFER	(1)
+#define CON_CONSDEV	(2) /* Last on the command line */
+#define CON_ENABLED	(4)
+
+struct console
+{
+	char	name[8];
+	void	(*write)(struct console *, const char *);
+	int	(*read)(struct console *, const char *, unsigned);
+	kdev_t	(*device)(struct console *);
+	int	(*wait_key)(struct console *);
+	void	(*unblank)(void);
+	int	(*setup)(struct console *, char *);
+	short	flags;
+	short	index;
+	int	cflag;
+	struct	 console *next;
+};
+
+extern void register_console(struct console *);
+extern int unregister_console(struct console *);
+extern struct console *console_drivers;
 
 #endif /* linux/console.h */
diff -ruN linux-2.0.37.vanilla/include/linux/tty.h linux-2.0.37/include/linux/tty.h
--- linux-2.0.37.vanilla/include/linux/tty.h	Tue Dec  2 23:18:11 1997
+++ linux-2.0.37/include/linux/tty.h	Wed Jun  2 17:30:09 1999
@@ -330,6 +330,7 @@
 /* serial.c */
 
 extern int  rs_open(struct tty_struct * tty, struct file * filp);
+extern long serial_console_init(long kmem_start, long kmem_end);
 
 /* pty.c */
 
diff -ruN linux-2.0.37.vanilla/include/linux/tty_driver.h linux-2.0.37/include/linux/tty_driver.h
--- linux-2.0.37.vanilla/include/linux/tty_driver.h	Tue Dec  2 23:18:11 1997
+++ linux-2.0.37/include/linux/tty_driver.h	Wed Jun  2 17:30:09 1999
@@ -177,10 +177,12 @@
 #define TTY_DRIVER_TYPE_SERIAL		0x0003
 #define TTY_DRIVER_TYPE_PTY		0x0004
 #define TTY_DRIVER_TYPE_SCC		0x0005	/* scc driver */
+#define TTY_DRIVER_TYPE_SYSCONS		0x0006
 
 /* system subtypes (magic, used by tty_io.c) */
 #define SYSTEM_TYPE_TTY			0x0001
 #define SYSTEM_TYPE_CONSOLE		0x0002
+#define SYSTEM_TYPE_SYSCONS		0x0003
 
 /* pty subtypes (magic, used by tty_io.c) */
 #define PTY_TYPE_MASTER			0x0001
diff -ruN linux-2.0.37.vanilla/init/main.c linux-2.0.37/init/main.c
--- linux-2.0.37.vanilla/init/main.c	Wed Jun  2 17:16:02 1999
+++ linux-2.0.37/init/main.c	Wed Jun  2 17:30:09 1999
@@ -81,6 +81,7 @@
 extern void panic_setup(char *str, int *ints);
 extern void bmouse_setup(char *str, int *ints);
 extern void msmouse_setup(char *str, int *ints);
+extern void console_setup(char *str, int *ints);
 extern void lp_setup(char *str, int *ints);
 extern void eth_setup(char *str, int *ints);
 extern void xd_setup(char *str, int *ints);
@@ -308,6 +309,7 @@
 	{ "swap=", swap_setup },
 	{ "buff=", buff_setup },
 	{ "panic=", panic_setup },
+	{ "console=", console_setup },
 	{ "no-scroll", no_scroll },
 #ifdef CONFIG_BUGi386
 	{ "no-hlt", no_halt },
@@ -1043,7 +1045,7 @@
 {
 	close(0);close(1);close(2);
 	setsid();
-	(void) open("/dev/tty1",O_RDWR,0);
+	(void) open("/dev/console",O_RDWR,0);
 	(void) dup(0);
 	(void) dup(0);
 	return execve(shell, argv, envp);
@@ -1056,7 +1058,7 @@
 
 	close(0);close(1);close(2);
 	setsid();
-	(void) open("/dev/tty1",O_RDWR,0);
+	(void) open("/dev/console",O_RDWR,0);
 	(void) dup(0);
 	(void) dup(0);
 	return execve(shell, argv, envp_init);
@@ -1136,9 +1138,8 @@
 	 *	attached (Sparc effectively does).
 	 */
 
-	if ((open("/dev/tty1",O_RDWR,0) < 0) &&
-	    (open("/dev/ttyS0",O_RDWR,0) < 0))
-		printk("Unable to open an initial console.\n");
+	if (open("/dev/console",O_RDWR,0) < 0)
+		printk("WARNING: Unable to open an initial console (/dev/console).\n");
 			
 	(void) dup(0);
 	(void) dup(0);
diff -ruN linux-2.0.37.vanilla/kernel/panic.c linux-2.0.37/kernel/panic.c
--- linux-2.0.37.vanilla/kernel/panic.c	Wed Jun  2 17:16:02 1999
+++ linux-2.0.37/kernel/panic.c	Wed Jun  2 17:30:09 1999
@@ -17,7 +17,7 @@
 
 asmlinkage void sys_sync(void);	/* it's really int */
 extern void hard_reset_now(void);
-extern void do_unblank_screen(void);
+extern void unblank_console(void);
 extern void DAC960_Finalize(void);
 extern void gdth_halt(void);
 extern int C_A_D;
@@ -45,7 +45,7 @@
 	else
 		sys_sync();
 
-	do_unblank_screen();
+	unblank_console();
 
 	if (panic_timeout > 0)
 	{
diff -ruN linux-2.0.37.vanilla/kernel/printk.c linux-2.0.37/kernel/printk.c
--- linux-2.0.37.vanilla/kernel/printk.c	Fri Jun  7 10:54:06 1996
+++ linux-2.0.37/kernel/printk.c	Wed Jun  2 17:30:09 1999
@@ -22,13 +22,12 @@
 #include <linux/mm.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
+#include <linux/console.h>
 
 #define LOG_BUF_LEN	8192
 
 static char buf[1024];
 
-extern void console_print(const char *);
-
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
 
@@ -40,10 +39,66 @@
 struct wait_queue * log_wait = NULL;
 int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
 
-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;
+struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
+static int preferred_console = -1;
+
+
+/*
+ *	Setup a list of consoles. Called from init/main.c
+ */
+void console_setup(char *str, int *ints)
+{
+	struct console_cmdline *c;
+	char name[sizeof(c->name)];
+	char *s, *options;
+	int i, idx;
+
+	/*
+	 *	Decode str into name, index, options.
+	 */
+	if (str[0] >= '0' && str[0] <= '9') {
+		strcpy(name, "ttyS");
+		strncpy(name + 4, str, sizeof(name) - 5);
+	} else
+		strncpy(name, str, sizeof(name) - 1);
+	name[sizeof(name) - 1] = 0;
+	if ((options = strchr(str, ',')) != NULL)
+		*(options++) = 0;
+#ifdef __sparc__
+	if (!strcmp(str, "ttya"))
+		strcpy(name, "ttyS0");
+	if (!strcmp(str, "ttyb"))
+		strcpy(name, "ttyS1");
+#endif
+	for(s = name; *s; s++)
+		if (*s >= '0' && *s <= '9')
+			break;
+	idx = simple_strtoul(s, NULL, 10);
+	*s = 0;
+
+	/*
+	 *	See if this tty is not yet registered, and
+	 *	if we have a slot free.
+	 */
+	for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
+		if (strcmp(console_cmdline[i].name, name) == 0 &&
+			  console_cmdline[i].index == idx) {
+				preferred_console = i;
+				return;
+		}
+	if (i == MAX_CMDLINECONSOLES)
+		return;
+	preferred_console = i;
+	c = &console_cmdline[i];
+	memcpy(c->name, name, sizeof(c->name));
+	c->options = options;
+	c->index = idx;
+}
+
 
 /*
  * Commands to sys_syslog:
@@ -190,10 +245,16 @@
 			if (*p == '\n')
 				break;
 		}
-		if (msg_level < console_loglevel && console_print_proc) {
+		if (msg_level < console_loglevel && console_drivers) {
+			struct console *c = console_drivers;
 			char tmp = p[1];
+
 			p[1] = '\0';
-			(*console_print_proc)(msg);
+			while(c) {
+				if ((c->flags & CON_ENABLED) && c->write)
+					c->write(c, msg);
+				c = c->next;
+			}
 			p[1] = tmp;
 		}
 		if (*p == '\n')
@@ -204,13 +265,34 @@
 	return i;
 }
 
+void console_print(const char *s)
+{
+	struct console *c = console_drivers;
+
+	while(c) {
+		if ((c->flags & CON_ENABLED) && c->write)
+			c->write(c, s);
+		c = c->next;
+	}
+}
+
+void unblank_console(void)
+{
+	struct console *c = console_drivers;
+	while(c) {
+		if ((c->flags & CON_ENABLED) && c->unblank)
+			c->unblank();
+		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.
  */
-void register_console(void (*proc)(const char *))
+void register_console(struct console * console)
 {
 	int	i,j;
 	int	p = log_start;
@@ -218,8 +300,62 @@
 	char	msg_level = -1;
 	char	*q;
 
-	console_print_proc = proc;
+	/*
+	 *	See if we want to use this console driver. If we
+	 *	didn't select a console we take the first one
+	 *	that registers here.
+	 */
+	if (preferred_console < 0) {
+		if (console->index < 0)
+			console->index = 0;
+		if (console->setup == NULL ||
+		    console->setup(console, NULL) == 0) {
+			console->flags |= CON_ENABLED | CON_CONSDEV;
+			preferred_console = 0;
+		}
+	}
+
+	/*
+	 *	See if this console matches one we selected on
+	 *	the command line.
+	 */
+	for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) {
+		if (strcmp(console_cmdline[i].name, console->name) != 0)
+			continue;
+		if (console->index >= 0 &&
+		    console->index != console_cmdline[i].index)
+			continue;
+		if (console->index < 0)
+			console->index = console_cmdline[i].index;
+		if (console->setup &&
+		    console->setup(console, console_cmdline[i].options) != 0)
+			break;
+		console->flags |= CON_ENABLED;
+		console->index = console_cmdline[i].index;
+		if (i == preferred_console)
+			console->flags |= CON_CONSDEV;
+		break;
+	}
+
+	if (!(console->flags & CON_ENABLED))
+		return;
 
+	/*
+	 *	Put this console in the list - keep the
+	 *	preferred driver at the head of the list.
+	 */
+	if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
+		console->next = console_drivers;
+		console_drivers = console;
+	} else {
+		console->next = console_drivers->next;
+		console_drivers->next = console;
+	}
+	if ((console->flags & CON_PRINTBUFFER) == 0) return;
+
+	/*
+	 *	Print out buffered log messages.
+	 */
 	for (i=0,j=0; i < log_size; i++) {
 		buf[j++] = log_buf[p];
 		p++; p &= LOG_BUF_LEN-1;
@@ -232,11 +368,30 @@
 			q = buf + 3;
 		}
 		if (msg_level < console_loglevel)
-			(*proc)(q);
+			console->write(console, q);
 		if (buf[j-1] == '\n')
 			msg_level = -1;
 		j = 0;
 	}
+}
+
+int unregister_console(struct console * console)
+{
+        struct console *a,*b;
+	
+	if (console_drivers == console) {
+		console_drivers=console->next;
+		return (0);
+	}
+	for (a=console_drivers->next, b=console_drivers ;
+	     a; b=a, a=b->next) {
+		if (a == console) {
+			b->next = a->next;
+			return 0;
+		}  
+	}
+	
+	return (1);
 }
 
 /*
