Date: Thu, 28 Aug 1997 09:43:14 +0200 (CEST)
From: Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be>
To: Linux/m68k <linux-m68k@phil.uni-sb.de>
Subject: L68K: Serial console patches
Sender: owner-linux-m68k@phil.uni-sb.de
Reply-To: linux-m68k@phil.uni-sb.de


Finally the Serial Console[*] support is back (for Amiga)! These patches
include Miquel van Smoorenburg's latest serial console patches, bringing 2.1.x
to the useability level of our customized 2.0.x :-)

Notes:

  - /dev/console is no longer a soft link to the current console device but a
    real device with major 5 and minor 1. Don't forget to create this device
    node and to make sure it isn't altered by one of your startup scripts
    (hint for the Debianeses: /etc/rc.boot/0kbd).

  - Now you can specify multiple consoles, i.e.

	console=ttyS0 console=tty0

  - As before, you have to patch gpm to open /dev/tty0 instead of /dev/console
    if you enable the serial console. XFree 3.3 and higher are OK.

  - The (optional) baud argument isn't used on Amiga yet. Normally the port
    will be initialized by Amiboot/Amiga-Lilo.

Please also read Documentation/serial-console.txt.

Anyone who's willing to add support for other ports than the Amiga's builtin
serial port?

Do we still need the debug=xxx options?? debug=ser on Amiga is now completely
superceded by console=ttyS0. debug=mem can still be useful, though.

[*] For the ignorant: a Serial Console is something that differentiates your
    workstation from an ordinary PC.

--- linux-2.1.47/Documentation/Configure.help.orig	Tue Jul 29 19:59:01 1997
+++ linux-2.1.47/Documentation/Configure.help	Tue Aug 26 22:11:53 1997
@@ -4232,10 +4232,10 @@
 
 Console on virtual terminal
 CONFIG_VT_CONSOLE
-  If you enable this option, all kernel messages will be sent to the
-  device /dev/tty which corresponds to the virtual terminal you have
-  visible on your display. You should say Y here if you have no other
-  console device.
+  If you enable this option, by default all kernel messages will be sent
+  to the device /dev/tty0 which corresponds to the virtual terminal you
+  have visible on your display. You should say Y here unless you only
+  want to have the kernel messages output on a serial port.
 
 Standard/generic serial support
 CONFIG_SERIAL
@@ -4258,13 +4258,12 @@
 
 Console on serial port
 CONFIG_SERIAL_CONSOLE
-  If you enable this option, all kernel messages will be sent to the
-  device /dev/ttyS1 which corresponds to a serial port; this could be
-  useful if you attached a terminal or printer to that port. You can
-  use this in combination with console on virtual terminal, in which
-  case you get the output on both serial and display. Most people say
-  N here so that they can use the serial port for modem, mouse or some
-  other device.
+  If you enable this option, it is possible to use a serial port as the
+  console. By default still the virtual console will be used at the
+  system console but you can alter that using a kernel command line
+  option. If you don't have a VGA card installed the kernel will
+  automatically use /dev/ttyS0 as system console if this option is
+  enabled.
 
 Digi Intl. epca support
 CONFIG_DIGIEPCA
--- linux-2.1.47/Documentation/serial-console.txt.orig	Sun May 18 23:08:44 1997
+++ linux-2.1.47/Documentation/serial-console.txt	Tue Aug 26 22:11:53 1997
@@ -1,48 +1,65 @@
                        Linux Serial Console
 
-These examples are valid if you want to use /dev/ttyS1 (COM2)
-as the serial console. Replace as needed.
+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.
 
-1. Tell LILO to use the serial port.
+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.
+
+You can specify multiple console= options on the kernel command line.
+Output will appear on all of them. The first device will be used when
+you open /dev/console. So, for example:
+
+	console=tty0 console=ttyS1,9600
+
+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.
+
+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)
 
-2. Adjust to kernel flags for the new kernel,
+3. Adjust to kernel flags for the new kernel,
    again in lilo.conf (kernel section)
 
-   append = "console=1,9600,n8" 
-
-   (Note the extra comma needed if you want to supply parity/framing 
-   information.)
-
-3. Link /dev/console to the serial port.
+   append = "console=ttyS1,9600" 
 
-   Your probably want to save your old /dev/console (the "master" virtual
-   console). Check if it is a symbolic link first. If not, `mv' it to
-   `/dev/tty0':
-
-   ls -l /dev/console
-   mv /dev/console /dev/tty0
-
-   Now link the serial port you are going to use as the console to
-   /dev/console, for example ttyS1:
-
-   ln -s /dev/ttyS1 /dev/console
-
-   On some systems you might want to edit your bootup scripts to make sure
-   they don't reset this arrangement on boot. (On Debian, check
-   /etc/rc.boot/console and /etc/default/console). You probably also want
-   to put a getty on either /dev/console or /dev/ttyS1.
-
-4. Init and /dev/console.
-   Sysvinit will open /dev/console on boot. If this does not point
-   to the serial console device, the startup messages will be printed
-   to the wrong device. The kernel also passes the environment variable
-   "CONSOLE" to the init program. sysvinit-2.64 reckognizes this, and
-   opens that device instead. Boot scripts as mentioned in (3) can
-   also check this variable to see what device the system console is.
-   If CONSOLE is not set you can assume the console is /dev/tty0.
+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
@@ -51,28 +68,19 @@
 
 5. /dev/console and X
    Programs that want to do something with the virtual console usually
-   open /dev/console. XF86 does this, and probably SVGALIB as well.
-   IMO this is wrong; they should open /dev/tty0.
-   I have binary patched /usr/bin/X11/XF86_SVGA to use "tty0"
-   instead of "console".
-
-6. Notes.
-
-   If you compile the next little program, you will be able
-   to really "halt" the system. It will enter a little
-   monitor :)
-
-   main() { reboot(0xfee1dead, 672274793, 0xCDEF0123); }
-
-   This is just a call to the new "halt" function that later
-   kernels have. This is included the "halt" command of
-   the recent sysvinit versions.
-
-   The monitor will also be entered at a kernel panic, or
-   when you press "break". That last function does not
-   work at the moment I think, but it would be useful for
-   kernel debugging.  You don't have alt-scrollock on a serial
-   console to find out the current EIP...
+   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.
 
-Miquel van Smoorenburg <miquels@cistron.nl>, 21-Jun-1996
-Stephen C. Tweedie <sct@dcs.ed.ac.uk>, 23-Dec-1996
+Miquel van Smoorenburg <miquels@cistron.nl>, 15-Jun-1997
--- linux-2.1.47/arch/m68k/amiga/config.c.orig	Sun Aug  3 23:47:06 1997
+++ linux-2.1.47/arch/m68k/amiga/config.c	Wed Aug 27 20:42:38 1997
@@ -80,12 +80,10 @@
 extern void amiga_init_sound(void);
 static void amiga_savekmsg_init(void);
 static void amiga_mem_console_write(const char *b, unsigned int count);
-static void amiga_serial_console_write(const char *s, unsigned int count);
+void amiga_serial_console_write(const char *s, unsigned int count);
 static void amiga_debug_init(void);
 
-static struct console amiga_console_driver = {
-    NULL, NULL, amiga_wait_key
-};
+static struct console amiga_console_driver;
 
 #ifdef CONFIG_MAGIC_SYSRQ
 static int amiga_sysrq_keys[] = {
@@ -775,7 +773,7 @@
 	;
 }
 
-static void amiga_serial_console_write(const char *s, unsigned int count)
+void amiga_serial_console_write(const char *s, unsigned int count)
 {
     while (count--) {
 	if (*s == '\n')
@@ -790,16 +788,24 @@
     amiga_serial_console_write(s, strlen(s));
 }
 
+int amiga_serial_console_wait_key(void)
+{
+    int ch;
+
+    while (!(custom.intreqr & IF_RBF))
+	barrier();
+    ch = custom.serdatr & 0xff;
+    /* clear the interrupt, so that another character can be read */
+    custom.intreq = IF_RBF;
+    return ch;
+}
+
 void amiga_serial_gets(char *s, 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;
+	ch = amiga_serial_console_wait_key();
 
 	/* Check for backspace. */
 	if (ch == 8 || ch == 127) {
--- linux-2.1.47/arch/m68k/config.in.orig	Mon Aug 11 19:52:55 1997
+++ linux-2.1.47/arch/m68k/config.in	Wed Aug 27 21:21:26 1997
@@ -221,7 +221,9 @@
 comment 'Character devices'
 
 define_bool CONFIG_VT y
-define_bool CONFIG_VT_CONSOLE y
+if [ "$CONFIG_VT" = "y" ]; then
+  bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
+fi
 define_bool CONFIG_FB_CONSOLE y
 
 if [ "$CONFIG_ATARI" = "y" ]; then
@@ -258,7 +260,7 @@
 if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
      "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
      "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then
-  bool 'Serial console support' CONFIG_SERIAL_CONSOLE
+  bool 'Support for serial port console'' CONFIG_SERIAL_CONSOLE
 fi
 bool 'Support for user serial device modules' CONFIG_USERIAL
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
--- linux-2.1.47/drivers/char/n_tty.c.orig	Thu Jul 17 21:32:32 1997
+++ linux-2.1.47/drivers/char/n_tty.c	Tue Aug 26 22:14:41 1997
@@ -40,6 +40,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))
@@ -855,6 +856,7 @@
 	   check of the logic of this change. -- jlc */
 	/* don't stop on /dev/console */
 	if (file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
+	    file->f_dentry->d_inode->i_rdev != SYSCONS_DEV &&
 	    current->tty == tty) {
 		if (tty->pgrp <= 0)
 			printk("read_chan: tty->pgrp <= 0!\n");
@@ -1013,7 +1015,8 @@
 	int retval = 0;
 
 	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
-	if (L_TOSTOP(tty) && file->f_dentry->d_inode->i_rdev != CONSOLE_DEV) {
+	if (L_TOSTOP(tty) && file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
+	    file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) {
 		retval = tty_check_change(tty);
 		if (retval)
 			return retval;
--- linux-2.1.47/drivers/char/Config.in.orig	Tue Jul 29 19:59:12 1997
+++ linux-2.1.47/drivers/char/Config.in	Tue Aug 26 22:11:53 1997
@@ -6,7 +6,7 @@
 
 bool 'Virtual terminal' CONFIG_VT
 if [ "$CONFIG_VT" = "y" ]; then
-  bool 'Console on virtual terminal' CONFIG_VT_CONSOLE
+  bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
 fi
 tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
 bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
@@ -15,7 +15,7 @@
    bool '   Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
    bool '   Support special multiport boards' CONFIG_SERIAL_MULTIPORT
    bool '   Support the Bell Technologies HUB6 card' CONFIG_HUB6
-   bool '   Console on serial port' CONFIG_SERIAL_CONSOLE
+   bool '   Support for serial port console' CONFIG_SERIAL_CONSOLE
 fi
 bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
 if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
--- linux-2.1.47/drivers/char/console.c.orig	Mon Aug 11 23:45:21 1997
+++ linux-2.1.47/drivers/char/console.c	Tue Aug 26 22:11:54 1997
@@ -174,6 +174,7 @@
 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 void con_type_init_finish(void);
 extern int set_get_cmap(unsigned char *, int);
@@ -2372,16 +2373,24 @@
 	printing = 0;
 }
 
-static int vt_console_device(void)
+static kdev_t vt_console_device(struct console *c)
 {
-	return MKDEV(TTY_MAJOR, fg_console + 1);
+	return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
 }
 
-extern void keyboard_wait_for_keypress(void);
+extern int keyboard_wait_for_keypress(void);
 
 struct console vt_console_driver = {
-	vt_console_print, do_unblank_screen,
-        keyboard_wait_for_keypress, vt_console_device
+	"tty",
+	vt_console_print,
+	NULL,
+	vt_console_device,
+	keyboard_wait_for_keypress,
+	do_unblank_screen,
+	NULL,
+	CON_PRINTBUFFER,
+	0,
+	NULL
 };
 #endif
 
@@ -2462,6 +2471,9 @@
  *
  * Reads the information preserved by setup.s to determine the current display
  * type and sets everything accordingly.
+ *
+ * FIXME: return early if we don't _have_ a video card installed.
+ *
  */
 __initfunc(unsigned long con_init(unsigned long kmem_start))
 {
@@ -2615,7 +2627,7 @@
 	 * within the bus probing code... :-(
 	 */
 #ifdef CONFIG_VT_CONSOLE
-	if (video_type != VIDEO_TYPE_TGAC)
+	if (video_type != VIDEO_TYPE_TGAC && con_is_present())
 		register_console(&vt_console_driver);
 #endif
 
--- linux-2.1.47/drivers/char/keyboard.c.orig	Sun Aug  3 22:04:52 1997
+++ linux-2.1.47/drivers/char/keyboard.c	Tue Aug 26 22:11:54 1997
@@ -63,9 +63,10 @@
 
 struct wait_queue * keypress_wait = NULL;
 
-void keyboard_wait_for_keypress(void)
+int keyboard_wait_for_keypress(void)
 {
 	sleep_on(&keypress_wait);
+	return 0;
 }
 
 /*
--- linux-2.1.47/drivers/char/serial.c.orig	Tue Jul  8 22:51:04 1997
+++ linux-2.1.47/drivers/char/serial.c	Tue Aug 26 22:11:55 1997
@@ -46,6 +46,9 @@
 #include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -149,6 +152,10 @@
 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;
+static int serial_console_cflag;
+#endif
 
 static void autoconfig(struct serial_state * info);
 static void change_speed(struct async_struct *info);
@@ -2833,7 +2840,13 @@
 			*tty->termios = info->state->callout_termios;
 		change_speed(info);
 	}
-
+#ifdef CONFIG_SERIAL_CONSOLE
+	if (serial_console_cflag && sercons.index == line) {
+		tty->termios->c_cflag = serial_console_cflag;
+		serial_console_cflag = 0;
+		change_speed(info);
+	}
+#endif
 	info->session = current->session;
 	info->pgrp = current->pgrp;
 
@@ -3277,7 +3290,18 @@
 		       sizeof(struct rs_multiport_struct));
 #endif
 	}
-	
+#ifdef CONFIG_SERIAL_CONSOLE
+	/*
+	 *	The interrupt of the serial console port
+	 *	can't be shared.
+	 */
+	if (sercons.flags & CON_FIRST) {
+		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();
 
 	/* Initialize the tty_driver structure */
@@ -3479,23 +3503,17 @@
  */
 #ifdef CONFIG_SERIAL_CONSOLE
 
-#include <linux/console.h>
-
-/*
- * this defines the index into rs_table for the port to use
- */
-#ifndef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT	0
-#endif
-
 #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
 
 /* Wait for transmitter & holding register to empty */
 static inline void wait_for_xmitr(struct serial_state *ser)
 {
 	int lsr;
+	unsigned int tmout = 1000000;
+
 	do {
 		lsr = inb(ser->port + UART_LSR);
+		if (--tmout == 0) break;
 	} while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
 }
 
@@ -3503,13 +3521,13 @@
  * Print a string to the serial port trying not to disturb any possible
  * real use of the port...
  */
-static int serial_console_write(const char *s, unsigned count)
+static void serial_console_write(const char *s, unsigned count)
 {
 	struct serial_state *ser;
 	int ier;
 	unsigned i;
 
-	ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
+	ser = rs_table + sercons.index;
 	/*
 	 * First save the IER then disable the interrupts
 	 */
@@ -3538,8 +3556,6 @@
 	 */
 	wait_for_xmitr(ser);
 	outb(ier, ser->port + UART_IER);
-
-	return (0);
 }
 
 /*
@@ -3552,7 +3568,7 @@
 	int lsr;
 	int c;
 
-	ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
+	ser = rs_table + sercons.index;
 
 	/*
 	 * First save the IER then disable the interrupts so
@@ -3573,35 +3589,134 @@
 	return c;
 }
 
-static int serial_console_device(void)
+static kdev_t serial_console_device(struct console *c)
 {
-	return MKDEV(TTYAUX_MAJOR, 64 + CONFIG_SERIAL_CONSOLE_PORT);
+	return MKDEV(TTY_MAJOR, 64 + c->index);
 }
 
+/*
+ *	Setup initial baud/bits/parity.
+ */
+__initfunc(static void serial_console_setup(char *options))
+{
+	char *s;
+	int baud = 0, bits, parity;
+	int cflag = CREAD | HUPCL | CLOCAL;
+
+	bits = 8;
+	parity = 'n';
+
+	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 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;
+	}
+
+	serial_console_cflag = cflag;
+}
+
+static struct console sercons = {
+	"ttyS",
+	serial_console_write,
+	NULL,
+	serial_console_device,
+	serial_console_wait_key,
+	NULL,
+	serial_console_setup,
+	CON_PRINTBUFFER,
+	0,
+	NULL
+};
+
+/*
+ * This is here to set the speed etc. for a non-initialized
+ * line. We have no termios struct yet, so we just use "cflag".
+ */
 long serial_console_init(long kmem_start, long kmem_end)
 {
-	static struct console console = {
-		serial_console_write, 0,
-                serial_console_wait_key, serial_console_device
-	};
+	unsigned cval;
+	int	i;
+	int	quot = 0;
 	struct serial_state *ser;
+	
+	register_console(&sercons);
+	ser = rs_table + sercons.index;
+
+	i = serial_console_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 */
+	quot = BASE_BAUD / baud_table[i];
+
+	/* byte size and parity */
+	cval = serial_console_cflag & (CSIZE | CSTOPB);
+	cval >>= 4;
+	if (serial_console_cflag & PARENB)
+		cval |= UART_LCR_PARITY;
+	if (!(serial_console_cflag & PARODD))
+		cval |= UART_LCR_EPAR;
 
-	ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
+	/* Disable UART interrupts. */
+	outb(0, ser->port + UART_IER);
 
-	/* Disable all interrupts, it works in polled mode */
-	outb(0x00, ser->port + UART_IER); 
+	/* Set DTR and RTS high. */
+	outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
 
-	/*
-	 * now do hardwired init
-	 */
-	outb(0x03, ser->port + UART_LCR); /* No parity, 8 data bits, 1 stop */
-	outb(0x83, ser->port + UART_LCR); /* Access divisor latch */
-	outb(0x00, ser->port + UART_DLM); /* 9600 baud */
-	outb(0x0c, ser->port + UART_DLL);
-	outb(0x03, ser->port + UART_LCR); /* Done with divisor */
+	/* 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 */
 
-	register_console(&console);
 	return kmem_start;
 }
-
 #endif
--- linux-2.1.47/drivers/char/tga.c.orig	Sun Aug  3 23:47:08 1997
+++ linux-2.1.47/drivers/char/tga.c	Tue Aug 26 22:11:55 1997
@@ -443,6 +443,19 @@
 {
 }
 
+
+/*
+ *	See if we have a TGA card.
+ */
+__initfunc(int con_is_present())
+{
+	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,
--- linux-2.1.47/drivers/char/tty_io.c.orig	Tue Jul 29 19:59:18 1997
+++ linux-2.1.47/drivers/char/tty_io.c	Tue Aug 26 22:15:35 1997
@@ -90,6 +90,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
 
@@ -377,7 +378,8 @@
 			continue;
 		if (!filp->f_dentry->d_inode)
 			continue;
-		if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV)
+		if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV ||
+		    filp->f_dentry->d_inode->i_rdev == SYSCONS_DEV)
 			continue;
 		if (filp->f_op != &tty_fops)
 			continue;
@@ -627,7 +629,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 == SYSCONS_DEV ||
+			inode->i_rdev == CONSOLE_DEV);
 
 	if (is_console && redirect)
 		tty = redirect;
@@ -1178,13 +1185,20 @@
 		filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
 		/* noctty = 1; */
 	}
+#ifdef CONFIG_VT
 	if (device == CONSOLE_DEV) {
+		extern int fg_console;
+		device = MKDEV(TTY_MAJOR, fg_console + 1);
+		noctty = 1;
+	}
+#endif
+	if (device == SYSCONS_DEV) {
 		struct console *c = console_drivers;
 		while(c && !c->device)
 			c = c->next;
 		if (!c)
                         return -ENODEV;
-                device = c->device();
+                device = c->device(c);
 		noctty = 1;
 	}
 	minor = MINOR(device);
@@ -1366,7 +1380,8 @@
 
 static int tioccons(struct tty_struct *tty, struct tty_struct *real_tty)
 {
-	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;
@@ -1770,16 +1785,17 @@
 	 * set up the console device so that later boot sequences can 
 	 * inform about problems etc..
 	 */
-#ifdef CONFIG_SERIAL_CONSOLE
-	kmem_start = serial_console_init(kmem_start, kmem_end);
-#endif
 #ifdef CONFIG_VT
 	kmem_start = con_init(kmem_start);
 #endif
+#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
@@ -1810,17 +1826,28 @@
 	if (tty_register_driver(&dev_tty_driver))
 		panic("Couldn't register /dev/tty driver\n");
 
+	dev_syscons_driver = dev_tty_driver;
+	dev_syscons_driver.driver_name = "/dev/console";
+	dev_syscons_driver.name = dev_syscons_driver.driver_name + 5;
+	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");
+
+#ifdef CONFIG_VT
 	dev_console_driver = dev_tty_driver;
-	dev_console_driver.driver_name = "/dev/console";
+	dev_console_driver.driver_name = "/dev/tty0";
 	dev_console_driver.name = dev_console_driver.driver_name + 5;
 	dev_console_driver.major = TTY_MAJOR;
 	dev_console_driver.type = TTY_DRIVER_TYPE_SYSTEM;
 	dev_console_driver.subtype = SYSTEM_TYPE_CONSOLE;
 
 	if (tty_register_driver(&dev_console_driver))
-		panic("Couldn't register /dev/console driver\n");
+		panic("Couldn't register /dev/tty0 driver\n");
 
-#ifdef CONFIG_VT
 	kbd_init();
 #endif
 #ifdef CONFIG_ESPSERIAL  /* init ESP before rs, so rs doesn't see the port */
--- linux-2.1.47/drivers/char/vga.c.orig	Sun Aug  3 23:47:08 1997
+++ linux-2.1.47/drivers/char/vga.c	Tue Aug 26 22:11:56 1997
@@ -147,6 +147,31 @@
 		hide_cursor(currcons);
 }
 
+__initfunc(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 *)((ORIG_VIDEO_MODE == 7) ? 0xb0000 : 0xb8000);
+	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;
+}
+
 __initfunc(unsigned long
 con_type_init(unsigned long kmem_start, const char **display_desc))
 {
--- linux-2.1.47/drivers/char/m68kserial.c.orig	Sun Aug  3 22:04:53 1997
+++ linux-2.1.47/drivers/char/m68kserial.c	Tue Aug 26 23:22:29 1997
@@ -74,6 +74,9 @@
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
 #endif
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
 
 #include <asm/setup.h>
 #include <asm/system.h>
@@ -135,6 +138,10 @@
 static struct tty_struct *serial_table[NR_PORTS];
 static struct termios *serial_termios[NR_PORTS];
 static struct termios *serial_termios_locked[NR_PORTS];
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console sercons;
+static int serial_console_cflag;
+#endif
 
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
@@ -1282,6 +1289,13 @@
 			*tty->termios = info->callout_termios;
 		info->sw->change_speed(info);
 	}
+#ifdef CONFIG_SERIAL_CONSOLE
+	if (serial_console_cflag && sercons.index == line) {
+		tty->termios->c_cflag = serial_console_cflag;
+		serial_console_cflag = 0;
+		info->sw->change_speed(info);
+	}
+#endif
 
 	info->session = current->session;
 	info->pgrp = current->pgrp;
@@ -1375,6 +1389,18 @@
 
 	init_bh(SERIAL_BH, do_serial_bh);
 
+#ifdef CONFIG_SERIAL_CONSOLE
+	/*
+	 *	The interrupt of the serial console port
+	 *	can't be shared.
+	 */
+	if (sercons.flags & CON_FIRST) {
+		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();
 
 	/* Initialize the tty_driver structure */
@@ -1614,3 +1640,119 @@
 		printk("SERIAL: failed to unregister callout driver\n");
 }
 #endif /* MODULE */
+
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
+static kdev_t serial_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ *	Setup initial baud/bits/parity.
+ */
+__initfunc(static void serial_console_setup(char *options))
+{
+	char *s;
+	int baud = 0, bits, parity;
+	int cflag = CREAD | HUPCL | CLOCAL;
+
+	bits = 8;
+	parity = 'n';
+
+	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 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;
+	}
+
+	serial_console_cflag = cflag;
+}
+
+static struct console sercons = {
+	"ttyS",
+	NULL,			/* filled in by serial_console_init */
+	NULL,
+	serial_console_device,
+	NULL,			/* filled in by serial_console_init */
+	NULL,
+	serial_console_setup,
+	CON_PRINTBUFFER,
+	0,
+	NULL
+};
+
+extern void amiga_serial_console_write(const char *s, unsigned int count);
+extern int amiga_serial_console_wait_key(void);
+extern void amiga_init_serial_console(struct async_struct *info, int cflag);
+
+/*
+ * This is here to set the speed etc. for a non-initialized
+ * line. We have no termios struct yet, so we just use "cflag".
+ */
+long serial_console_init(long kmem_start, long kmem_end)
+{
+	/* Currently this supports the Amiga builtin port only */
+	if (MACH_IS_AMIGA && sercons.index == 0) {
+		sercons.write = amiga_serial_console_write;
+		sercons.wait_key = amiga_serial_console_wait_key;
+		register_console(&sercons);
+		/* no initialization yet */
+		/* amiga_init_serial_console(rs_table+sercons.index, */
+		/*			     serial_console_cflag); */
+	}
+	return kmem_start;
+}
+#endif
--- linux-2.1.47/drivers/char/abscon.c.orig	Mon Aug 11 19:52:55 1997
+++ linux-2.1.47/drivers/char/abscon.c	Tue Aug 26 22:54:46 1997
@@ -94,6 +94,12 @@
 	return -ENODEV;
 }
 
+__initfunc(int con_is_present(void))
+{
+    /* if abscon_probe() fails, this function is never called */
+    return 1;
+}
+
 __initfunc(unsigned long con_type_init(unsigned long kmem_start,
 				       const char **display_desc))
 {
--- linux-2.1.47/fs/proc/proc_tty.c.orig	Thu Apr 17 17:07:28 1997
+++ linux-2.1.47/fs/proc/proc_tty.c	Tue Aug 26 22:11:56 1997
@@ -49,8 +49,10 @@
 		case TTY_DRIVER_TYPE_SYSTEM:
 			if (p->subtype == SYSTEM_TYPE_TTY)
 				type = "system:/dev/tty";
-			else if (p->subtype == SYSTEM_TYPE_CONSOLE)
+			else if (p->subtype == SYSTEM_TYPE_SYSCONS)
 				type = "system:console";
+			else if (p->subtype == SYSTEM_TYPE_CONSOLE)
+				type = "system:vtmaster";
 			else
 				type = "system";
 			break;
--- linux-2.1.47/include/linux/console.h.orig	Sun Aug  3 23:47:08 1997
+++ linux-2.1.47/include/linux/console.h	Tue Aug 26 22:11:56 1997
@@ -62,36 +62,39 @@
 struct tty_struct;
 int tioclinux(struct tty_struct *tty, unsigned long arg);
 
-/* The interface for /dev/console(s) and printk output */
-
-struct console
+/*
+ *	Array of consoles built from command line options (console=)
+ */
+struct console_cmdline
 {
-	/*
-	 * This function should not return before the string is written.
-	 */
-	void (*write)(const char*, unsigned);
-
-        /* To unblank the console in case of panic */
-        void (*unblank)(void);
+	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];
 
-	/*
-         * 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);
+/*
+ *	The interface for a console, or any other device that
+ *	wants to capture console messages (printer driver?)
+ */
 
-	/*
-	 * Return the device to use when opening /dev/console. Only the
-	 * last registered console will do.
-	 */
-	int (*device)(void);
+#define CON_PRINTBUFFER	(1)
+#define CON_FIRST	(2)
+#define CON_ENABLED	(4)
 
-	/* 
-	 * For a linked list of consoles for multiple output. Any console
-         * not at the head of the list is used only for output.
-	 */
-	struct console *next;
+struct console
+{
+	char name[8];		/* Name of the driver, eg tty, ttyS, ttyR   */
+	void (*write)(const char*, unsigned);	/* Write string - blocking. */
+	int (*read)(const char*, unsigned);	/* Read string - blocking.  */
+	kdev_t (*device)(struct console *);	/* Return maj/min device    */
+	int (*wait_key)(void);	/* Wait for keypress			    */
+        void (*unblank)(void);	/* To unblank the console in case of panic  */
+	void (*setup)(char *);	/* Initialize speed etc.		    */
+	short flags;		/* CON_XXX defined above.		    */
+	short index;		/* ttyS0, ttyS1, ..			    */
+	struct console *next;	/* Next. Only the first one used for input  */
 };
 
 extern void register_console(struct console *);
--- linux-2.1.47/include/linux/tty_driver.h.orig	Wed Aug 20 21:24:02 1997
+++ linux-2.1.47/include/linux/tty_driver.h	Tue Aug 26 22:11:56 1997
@@ -194,10 +194,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
--- linux-2.1.47/init/main.c.orig	Sun Aug  3 23:47:09 1997
+++ linux-2.1.47/init/main.c	Tue Aug 26 22:19:01 1997
@@ -85,6 +85,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);
 #ifdef CONFIG_PRINTER
 extern void lp_setup(char *str, int *ints);
 #endif
@@ -229,15 +230,6 @@
 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
-#endif
-
 /*
  * Boot command-line arguments
  */
@@ -328,6 +320,7 @@
 	{ "swap=", swap_setup },
 	{ "buff=", buff_setup },
 	{ "panic=", panic_setup },
+	{ "console=", console_setup },
 #ifdef CONFIG_VT
 	{ "no-scroll", no_scroll },
 #endif
@@ -794,16 +787,6 @@
 			argv_init[++args] = line;
 		}
 	}
-#ifdef CONFIG_SERIAL_CONSOLE
-	if (serial_console)
-		console_env[17] = serial_console - 64 + '0';
-	else {
-		console_env[16] = '0';
-		console_env[17] = '\0';
-	}
-	if (envs < MAX_INIT_ENVS)
-		envp_init[++envs] = console_env;
-#endif
 	argv_init[args+1] = NULL;
 	envp_init[envs+1] = NULL;
 }
@@ -977,7 +960,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);
@@ -1061,8 +1044,8 @@
 
 	setup(1);
 	
-	if (open("/dev/console",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.\n");
 
 	(void) dup(0);
 	(void) dup(0);
--- linux-2.1.47/kernel/printk.c.orig	Sun May 18 23:10:41 1997
+++ linux-2.1.47/kernel/printk.c	Tue Aug 26 22:11:57 1997
@@ -53,6 +53,46 @@
 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 selected_console = 0;
+
+/*
+ *	Setup a list of consoles. Called from init/main.c
+ */
+__initfunc(void console_setup(char *str, int *ints))
+{
+	char *s;
+	int i;
+	struct console_cmdline *c;
+
+	for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
+		;
+	if (i == MAX_CMDLINECONSOLES)
+		return;
+	c = &console_cmdline[i];
+	selected_console = 1;
+
+	if (str[0] >= '0' && str[0] <= '9') {
+		strcpy(c->name, "ttyS");
+		strncpy(c->name + 4, str, sizeof(c->name) - 5);
+	} else
+		strncpy(c->name, str, sizeof(c->name) - 1);
+	if ((c->options = strchr(str, ',')) != NULL)
+		*(c->options++) = 0;
+#ifdef __sparc__
+	if (strcmp(str, "ttya"))
+		strcpy(c->name, "ttyS0");
+	if (strcmp(str, "ttyb"))
+		strcpy(c->name, "ttyS1");
+#endif
+
+	for(s = c->name; *s; s++)
+		if (*s >= '0' && *s <= '9')
+			break;
+	c->index = simple_strtoul(s, NULL, 10);
+	*s = 0;
+}
+
 
 /*
  * Commands to sys_syslog:
@@ -222,7 +262,7 @@
 		if (msg_level < console_loglevel && console_drivers) {
 			struct console *c = console_drivers;
 			while(c) {
-				if (c->write)
+				if ((c->flags & CON_ENABLED) && c->write)
 					c->write(msg, p - msg + line_feed);
 				c = c->next;
 			}
@@ -239,8 +279,9 @@
 {
 	struct console *c = console_drivers;
 	int len = strlen(s);
+
 	while(c) {
-		if (c->write)
+		if ((c->flags & CON_ENABLED) && c->write)
 			c->write(s, len);
 		c = c->next;
 	}
@@ -250,7 +291,7 @@
 {
 	struct console *c = console_drivers;
 	while(c) {
-		if (c->unblank)
+		if ((c->flags & CON_ENABLED) && c->unblank)
 			c->unblank();
 		c = c->next;
 	}
@@ -262,7 +303,7 @@
  * print any messages that were printed by the kernel before the
  * console driver was initialized.
  */
-__initfunc(void register_console(struct console * console))
+void register_console(struct console * console)
 {
 	int	i,j,len;
 	int	p = log_start;
@@ -270,9 +311,43 @@
 	signed char msg_level = -1;
 	char	*q;
 
-	console->next = console_drivers;
-	console_drivers = console;
+	/*
+	 *	See if we want to use this console driver.
+	 */
+	if (selected_console == 0) {
+		console->flags |= CON_ENABLED | CON_FIRST;
+		selected_console = 1;
+		if (console->setup)
+			console->setup(NULL);
+	}
+	for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) {
+		if (strcmp(console_cmdline[i].name, console->name) != 0)
+			continue;
+		console->flags |= CON_ENABLED;
+		console->index = console_cmdline[i].index;
+		if (i == 0)
+			console->flags |= CON_FIRST;
+		if (console->setup)
+			console->setup(console_cmdline[i].options);
+		break;
+	}
+
+	/*
+	 *	Put this console in the list - keep the
+	 *	preferred driver at the head of the list.
+	 */
+	if ((console->flags & CON_FIRST) || 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;

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

