diff options
-rw-r--r-- | drivers/sgi/char/sgiserial.c | 319 |
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; +} + + |