patch-2.1.71 linux/drivers/char/serial.c
Next file: linux/drivers/char/specialix.c
Previous file: linux/drivers/char/n_tty.c
Back to the patch index
Back to the overall index
- Lines: 325
- Date:
Wed Dec 3 15:21:57 1997
- Orig file:
v2.1.70/linux/drivers/char/serial.c
- Orig date:
Tue Dec 2 09:49:39 1997
diff -u --recursive --new-file v2.1.70/linux/drivers/char/serial.c linux/drivers/char/serial.c
@@ -49,6 +49,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>
@@ -152,6 +155,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 serial_state * info);
static void change_speed(struct async_struct *info);
@@ -2752,7 +2758,13 @@
*tty->termios = info->state->callout_termios;
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;
@@ -3195,7 +3207,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 */
@@ -3398,53 +3421,51 @@
*/
#ifdef CONFIG_SERIAL_CONSOLE
-#include <linux/console.h>
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
/*
- * this defines the index into rs_table for the port to use
+ * Wait for transmitter & holding register to empty
*/
-#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);
}
/*
- * Print a string to the serial port trying not to disturb any possible
- * real use of the port...
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
*/
-static void serial_console_write(const char *s, unsigned count)
+static void serial_console_write(struct console *co, const char *s,
+ unsigned count)
{
struct serial_state *ser;
int ier;
unsigned i;
- ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
+ ser = rs_table + co->index;
/*
- * First save the IER then disable the interrupts
+ * First save the IER then disable the interrupts
*/
ier = inb(ser->port + UART_IER);
outb(0x00, ser->port + UART_IER);
/*
- * Now, do each character
+ * Now, do each character
*/
for (i = 0; i < count; i++, s++) {
wait_for_xmitr(ser);
- /* Send the character out. */
+ /*
+ * Send the character out.
+ * If a LF, also do CR...
+ */
outb(*s, ser->port + UART_TX);
-
- /* if a LF, also do CR... */
if (*s == 10) {
wait_for_xmitr(ser);
outb(13, ser->port + UART_TX);
@@ -3452,29 +3473,29 @@
}
/*
- * Finally, Wait for transmitter & holding register to empty
- * and restore the IER
+ * 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
+ * Receive character from the serial port
*/
-static void serial_console_wait_key(void)
+static int serial_console_wait_key(struct console *co)
{
struct serial_state *ser;
int ier;
int lsr;
int c;
- ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
+ 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.
+ * 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);
@@ -3484,39 +3505,142 @@
} while (!(lsr & UART_LSR_DR));
c = inb(ser->port + UART_RX);
- /* Restore the interrupts */
+ /*
+ * Restore the interrupts
+ */
outb(ier, ser->port + UART_IER);
+
+ 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);
}
-long serial_console_init(long kmem_start, long kmem_end)
+/*
+ * Setup initial baud/bits/parity. We do two things here:
+ * - construct a cflag setting for the first rs_open()
+ * - initialize the serial port
+ */
+__initfunc(static void serial_console_setup(struct console *co, char *options))
{
- static struct console console = {
- serial_console_write, 0,
- serial_console_wait_key, serial_console_device
- };
struct serial_state *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';
+ }
- ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
+ /*
+ * 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;
- /* Disable all interrupts, it works in polled mode */
- outb(0x00, ser->port + UART_IER);
+ /*
+ * Divisor, bytesize and parity
+ */
+ ser = rs_table + co->index;
+ quot = BASE_BAUD / 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;
/*
- * now do hardwired init
+ * Disable UART interrupts, set DTR and RTS high
+ * and set speed.
*/
- 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 */
+ outb(0, ser->port + UART_IER);
+ outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
+ 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;
}
+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.
+ */
+__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+{
+ register_console(&sercons);
+ return kmem_start;
+}
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov