summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Bogendoerfer <tsbogend@alpha.franken.de>1998-09-26 12:22:34 +0000
committerThomas Bogendoerfer <tsbogend@alpha.franken.de>1998-09-26 12:22:34 +0000
commitbb891111126d978e543061f1d54f0b7b549608aa (patch)
tree75ca8f3c0e964b100c85a37c2add2a25e67cd5cb
parenta67c5a22c06daf961ce64bca514d4553acfc14f5 (diff)
made serial console working and compatible to pc version (console=ttyS1 works
now). Attention: The serial ports on the Indy are reversed, serial 1 is ttyS1 and serial 2 is ttyS0
-rw-r--r--drivers/sgi/char/sgiserial.c319
1 files changed, 233 insertions, 86 deletions
diff --git a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c
index 4e7b4e56a..79ca43471 100644
--- a/drivers/sgi/char/sgiserial.c
+++ b/drivers/sgi/char/sgiserial.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/console.h>
+#include <linux/init.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -30,8 +31,6 @@
#include "sgiserial.h"
-int serial_console;
-
#define NUM_SERIAL 1 /* One chip on board. */
#define NUM_CHANNELS (NUM_SERIAL * 2)
@@ -55,19 +54,6 @@ static int zs_cons_chanout = 0;
static int zs_cons_chanin = 0;
struct sgi_serial *zs_consinfo = 0;
-static struct console sgi_console_driver = {
- "debug",
- NULL, /* write */
- NULL, /* read */
- NULL, /* device */
- NULL, /* wait_key */
- NULL, /* unblank */
- NULL, /* setup */
- CON_PRINTBUFFER,
- -1,
- 0,
- NULL
-};
static unsigned char kgdb_regs[16] = {
0, 0, 0, /* write 0, 1, 2 */
(Rx8 | RxENABLE), /* write 3 */
@@ -82,6 +68,22 @@ static unsigned char kgdb_regs[16] = {
(DCDIE) /* write 15 */
};
+static unsigned char zscons_regs[16] = {
+ 0, /* write 0 */
+ (EXT_INT_ENAB | INT_ALL_Rx), /* write 1 */
+ 0, /* write 2 */
+ (Rx8 | RxENABLE), /* write 3 */
+ (X16CLK), /* write 4 */
+ (DTR | Tx8 | TxENAB), /* write 5 */
+ 0, 0, 0, /* write 6, 7, 8 */
+ (NV | MIE), /* write 9 */
+ (NRZ), /* write 10 */
+ (TCBR | RCBR), /* write 11 */
+ 0, 0, /* BRG time constant, write 12 + 13 */
+ (BRENABL), /* write 14 */
+ (DCDIE | CTSIE | TxUIE | BRKIE) /* write 15 */
+};
+
#define ZS_CLOCK 3672000 /* Zilog input clock rate */
DECLARE_TASK_QUEUE(tq_serial);
@@ -973,63 +975,6 @@ static void rs_fair_output(void)
return;
}
-/*
- * zs_console_print is registered for printk.
- */
-
-static void zs_console_print(struct console *co, const char *str, unsigned int count)
-{
-
- while(count--) {
- if(*str == '\n')
- rs_put_char('\r');
- rs_put_char(*str++);
- }
-
- /* Comment this if you want to have a strict interrupt-driven output */
- rs_fair_output();
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
- struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
- return;
-
- if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !info->xmit_buf)
- return;
-
- /* Enable transmitter */
- save_flags(flags); cli();
- info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
- info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
- write_zsreg(info->zs_channel, 1, info->curregs[1]);
- info->curregs[5] |= TxENAB;
- info->pendregs[5] |= TxENAB;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
-
- /*
- * Send a first (bootstrapping) character. A best solution is
- * to call transmit_chars() here which handles output in a
- * generic way. Current transmit_chars() not only transmits,
- * but resets interrupts also what we do not desire here.
- * XXX Discuss with David.
- */
- if (info->zs_channel->control & Tx_BUF_EMP) {
- volatile unsigned char junk;
-
- /* Send char */
- udelay(2);
- info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
- junk = ioc_icontrol->istat0;
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- }
- restore_flags(flags);
-}
static int rs_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
@@ -1119,6 +1064,47 @@ static void rs_flush_buffer(struct tty_struct *tty)
(tty->ldisc.write_wakeup)(tty);
}
+static void rs_flush_chars(struct tty_struct *tty)
+{
+ struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+ return;
+
+ if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+ !info->xmit_buf)
+ return;
+
+ /* Enable transmitter */
+ save_flags(flags); cli();
+ info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+ info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+ write_zsreg(info->zs_channel, 1, info->curregs[1]);
+ info->curregs[5] |= TxENAB;
+ info->pendregs[5] |= TxENAB;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+
+ /*
+ * Send a first (bootstrapping) character. A best solution is
+ * to call transmit_chars() here which handles output in a
+ * generic way. Current transmit_chars() not only transmits,
+ * but resets interrupts also what we do not desire here.
+ * XXX Discuss with David.
+ */
+ if (info->zs_channel->control & Tx_BUF_EMP) {
+ volatile unsigned char junk;
+
+ /* Send char */
+ udelay(2);
+ info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
+ junk = ioc_icontrol->istat0;
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt--;
+ }
+ restore_flags(flags);
+}
+
/*
* ------------------------------------------------------------
* rs_throttle()
@@ -1747,18 +1733,6 @@ rs_cons_check(struct sgi_serial *ss, int channel)
zs_consinfo = ss;
- /* Register the console output putchar, if necessary */
- if((zs_cons_chanout == channel)) {
- o = 1;
- /* double whee.. */
-
- if(!consout_registered) {
- sgi_console_driver.write = zs_console_print;
- register_console(&sgi_console_driver);
- consout_registered = 1;
- }
- }
-
/* If this is console input, we handle the break received
* status interrupt on this line to mean prom_halt().
@@ -1993,9 +1967,9 @@ rs_cons_hook(int chip, int out, int line)
if(chip)
panic("rs_cons_hook called with chip not zero");
- if(line != 1 && line != 2)
+ if(line != 0 && line != 1)
panic("rs_cons_hook called with line not ttya or ttyb");
- channel = line - 1;
+ channel = line;
if(!zs_chips[chip]) {
zs_chips[chip] = get_zs(chip);
/* Two channels per chip */
@@ -2044,3 +2018,176 @@ rs_kgdb_hook(int tty_num)
udelay(5);
ZS_CLEARFIFO(zs_kgdbchan);
}
+
+static void zs_console_write(struct console *co, const char *str, unsigned int count)
+{
+
+ while(count--) {
+ if(*str == '\n')
+ rs_put_char('\r');
+ rs_put_char(*str++);
+ }
+
+ /* Comment this if you want to have a strict interrupt-driven output */
+ rs_fair_output();
+}
+
+static int zs_console_wait_key(struct console *con)
+{
+ sleep_on(&keypress_wait);
+ return 0;
+}
+
+static kdev_t zs_console_device(struct console *con)
+{
+ return MKDEV(TTY_MAJOR, 64 + con->index);
+}
+
+
+__initfunc(static int zs_console_setup(struct console *con, char *options))
+{
+ struct sgi_serial *info;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int cflag = CREAD | HUPCL | CLOCAL;
+ char *s;
+ int i, brg;
+
+ 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;
+ }
+ con->cflag = cflag;
+
+ rs_cons_hook(0, 0, con->index);
+ info = zs_soft + con->index;
+ info->is_cons = 1;
+
+ printk("Console: ttyS%d (Zilog8530)\n", info->line);
+
+ i = con->cflag & CBAUD;
+ if (con->cflag & CBAUDEX) {
+ i &= ~CBAUDEX;
+ con->cflag &= ~CBAUDEX;
+ }
+ info->zs_baud = baud;
+
+ switch (con->cflag & CSIZE) {
+ case CS5:
+ zscons_regs[3] = Rx5 | RxENABLE;
+ zscons_regs[5] = Tx5 | TxENAB;
+ break;
+ case CS6:
+ zscons_regs[3] = Rx6 | RxENABLE;
+ zscons_regs[5] = Tx6 | TxENAB;
+ break;
+ case CS7:
+ zscons_regs[3] = Rx7 | RxENABLE;
+ zscons_regs[5] = Tx7 | TxENAB;
+ break;
+ default:
+ case CS8:
+ zscons_regs[3] = Rx8 | RxENABLE;
+ zscons_regs[5] = Tx8 | TxENAB;
+ break;
+ }
+ zscons_regs[5] |= DTR;
+
+ if (con->cflag & PARENB)
+ zscons_regs[4] |= PAR_ENA;
+ if (!(con->cflag & PARODD))
+ zscons_regs[4] |= PAR_EVEN;
+
+ if (con->cflag & CSTOPB)
+ zscons_regs[4] |= SB2;
+ else
+ zscons_regs[4] |= SB1;
+
+ brg = BPS_TO_BRG(baud, ZS_CLOCK / info->clk_divisor);
+ zscons_regs[12] = brg & 0xff;
+ zscons_regs[13] = (brg >> 8) & 0xff;
+ memcpy(info->curregs, zscons_regs, sizeof(zscons_regs));
+ memcpy(info->pendregs, zscons_regs, sizeof(zscons_regs));
+ load_zsregs(info->zs_channel, zscons_regs);
+ ZS_CLEARERR(info->zs_channel);
+ ZS_CLEARFIFO(info->zs_channel);
+ return 0;
+}
+
+static struct console sgi_console_driver = {
+ "ttyS",
+ zs_console_write, /* write */
+ NULL, /* read */
+ zs_console_device, /* device */
+ zs_console_wait_key, /* wait_key */
+ NULL, /* unblank */
+ zs_console_setup, /* setup */
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+
+/*
+ * Register console.
+ */
+__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+{
+ register_console(&sgi_console_driver);
+ return kmem_start;
+}
+
+