diff options
author | Thomas Bushnell <thomas@gnu.org> | 1997-02-25 21:28:37 +0000 |
---|---|---|
committer | Thomas Bushnell <thomas@gnu.org> | 1997-02-25 21:28:37 +0000 |
commit | f07a4c844da9f0ecae5bbee1ab94be56505f26f7 (patch) | |
tree | 12b07c7e578fc1a5f53dbfde2632408491ff2a70 /chips/serial_console.c | |
download | gnumach-f07a4c844da9f0ecae5bbee1ab94be56505f26f7.tar.gz gnumach-f07a4c844da9f0ecae5bbee1ab94be56505f26f7.tar.bz2 gnumach-f07a4c844da9f0ecae5bbee1ab94be56505f26f7.zip |
Initial source
Diffstat (limited to 'chips/serial_console.c')
-rw-r--r-- | chips/serial_console.c | 694 |
1 files changed, 694 insertions, 0 deletions
diff --git a/chips/serial_console.c b/chips/serial_console.c new file mode 100644 index 00000000..7b15dd4c --- /dev/null +++ b/chips/serial_console.c @@ -0,0 +1,694 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: serial_console.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 7/91 + * + * Console driver for serial-line based consoles. + */ + +#include <constty.h> +#if NCONSTTY > 0 +#include <bm.h> +#include <platforms.h> + +#include <mach_kdb.h> + +#include <machine/machspl.h> /* spl definitions */ +#include <device/io_req.h> +#include <device/tty.h> +#include <sys/syslog.h> + +#include <chips/busses.h> +#include <chips/screen_defs.h> +#include <chips/serial_defs.h> + +#ifdef DECSTATION +#include <mips/prom_interface.h> +#define find_rconsole(p) dec_check_rcline(p) +#define CONSOLE_SERIAL_LINE_NO 3 +#endif /*DECSTATION*/ + +#ifdef VAXSTATION +#define find_rconsole(p) +#define cnputc ser_putc +#define cngetc ser_getc +#define cnpollc ser_pollc +#define cnmaygetc ser_maygetc +#define CONSOLE_SERIAL_LINE_NO 3 +#endif /*VAXSTATION*/ + +#ifdef FLAMINGO +#define CONSOLE_SERIAL_LINE_NO 3 +#endif + +#ifndef CONSOLE_SERIAL_LINE_NO +#define CONSOLE_SERIAL_LINE_NO 0 +#endif + +/* Size this as max possible number of lines in any serial chip we might use */ +static struct tty console_tty_data[NCONSTTY]; +struct tty *console_tty[NCONSTTY]; /* exported */ + +#define DEFAULT_SPEED B9600 +#define DEFAULT_FLAGS (TF_EVENP|TF_ODDP|TF_ECHO) + + +/* + * A machine MUST have a console. In our case + * things are a little complicated by the graphic + * display: people expect it to be their "console", + * but we'd like to be able to live without it. + * This is not to be confused with the "rconsole" thing: + * that just duplicates the console I/O to + * another place (for debugging/logging purposes). + * + * There is then another historical kludge: if + * there is a graphic display it is assumed that + * the minor "1" is the mouse, with some more + * magic attached to it. And again, one might like to + * use the serial line 1 as a regular one. + * + */ +#define user_console 0 + +int console = 0; + +int (*console_probe)() = 0, + (*console_param)() = 0, + (*console_start)() = 0, + (*console_putc)() = 0, + (*console_getc)() = 0, + (*console_pollc)() = 0, + (*console_mctl)() = 0, + (*console_softCAR)() = 0; + +/* + * Lower-level (internal) interfaces, for printf and gets + */ +int cnunit = 0; /* which unit owns the 'console' */ +int cnline = 0; /* which line of that unit */ +int rcline = 3; /* alternate, "remote console" line */ + +rcoff() +{ + spl_t s = splhigh(); + cnpollc(FALSE); + rcline = 0; + cnpollc(TRUE); + splx(s); +} + +rcputc(c) +{ + if (rcline) + (*console_putc)( cnunit, rcline, c); +} + +cnputc(c) +{ +#if NBM > 0 + if (SCREEN_ISA_CONSOLE()) { + /* this does its own rcputc */ + screen_blitc(SCREEN_CONS_UNIT(), c); + } else +#endif NBM > 0 + { + rcputc(c); + (*console_putc)( cnunit, cnline, c);/* insist on a console still */ + } + if (c == '\n') + cnputc('\r'); +} + +cngetc() +{ + return (*console_getc)( cnunit, cnline, TRUE, FALSE); +} + +cnpollc(bool) +{ + (*console_pollc)(cnunit, bool); +} + + +/* Debugger support */ +cnmaygetc() +{ + return (*console_getc)( cnunit, cnline, FALSE, FALSE); +} + + +#if NBM > 0 +boolean_t +screen_captures(line) + register int line; +{ + return (SCREEN_ISA_CONSOLE() && + ((line == SCREEN_LINE_KEYBOARD) || + (line == SCREEN_LINE_POINTER))); +} +#endif + +/* + * Higher level (external) interface, for GP use + */ + + +/* + * This is basically a special form of autoconf, + * to get printf() going before true autoconf. + */ +cons_find(tube) + boolean_t tube; +{ + static struct bus_device d; + register int i; + struct tty *tp; + + for (i = 0; i < NCONSTTY; i++) + console_tty[i] = &console_tty_data[i]; + /* the hardware device will set tp->t_addr for valid ttys */ + + d.unit = 0; + + if ((console_probe == 0) || + ((*console_probe)(0, &d) == 0)) { + /* we have no console, but maybe that's ok */ +#if defined(DECSTATION) || defined(FLAMINGO) + /* no, it is not */ + dprintf("%s", "no console!\n"); + halt(); +#endif + return 0; + } + + /* + * Remote console line + */ + find_rconsole(&rcline); + + /* + * Console always on unit 0. Fix if you need to + */ + cnunit = 0; + +#if NBM > 0 + if (tube && screen_probe(0)) { + + /* associate screen to console iff */ + if (console == user_console) + screen_console = cnunit | SCREEN_CONS_ENBL; + cnline = SCREEN_LINE_KEYBOARD; + + /* mouse and keybd */ + tp = console_tty[SCREEN_LINE_KEYBOARD]; + tp->t_ispeed = B4800; + tp->t_ospeed = B4800; + tp->t_flags = TF_LITOUT|TF_EVENP|TF_ECHO|TF_XTABS|TF_CRMOD; + tp->t_dev = SCREEN_LINE_KEYBOARD; + (*console_param)(tp, SCREEN_LINE_KEYBOARD); + + tp = console_tty[SCREEN_LINE_POINTER]; + tp->t_ispeed = B4800; + tp->t_ospeed = B4800; + tp->t_flags = TF_LITOUT|TF_ODDP; + tp->t_dev = SCREEN_LINE_POINTER; + (*console_param)(tp, SCREEN_LINE_POINTER); + /* console_scan will turn on carrier */ + + } else { +#endif NBM > 0 + /* use non-graphic console as console */ + cnline = CONSOLE_SERIAL_LINE_NO; + + tp = console_tty[cnline]; + tp->t_ispeed = B9600; + tp->t_ospeed = B9600; + tp->t_flags = TF_LITOUT|TF_EVENP|TF_ECHO|TF_XTABS|TF_CRMOD; + (*console_softCAR)(cnunit, cnline, TRUE); + console = cnline; + tp->t_dev = console; + (*console_param)(tp, SCREEN_LINE_OTHER); +#if NBM > 0 + } + + /* + * Enable rconsole interrupts for KDB + */ + if (tube && rcline != cnline) { + tp = console_tty[rcline]; + tp->t_ispeed = B9600; + tp->t_ospeed = B9600; + tp->t_flags = TF_LITOUT|TF_EVENP|TF_ECHO|TF_XTABS|TF_CRMOD; + tp->t_dev = rcline; + (*console_softCAR)(cnunit, rcline, TRUE); + (*console_param)(tp, SCREEN_LINE_OTHER); + } else + rcline = 0; +#endif NBM > 0 +} + +/* + * Open routine + */ +extern int + cons_start(struct tty *), + cons_stop(struct tty *, int), + cons_mctl(struct tty *, int, int); + +cons_open(dev, flag, ior) + int dev; + int flag; + io_req_t ior; +{ + register struct tty *tp; + register int ttyno; + + if (dev == user_console) + dev = console; + + ttyno = dev; + if (ttyno >= NCONSTTY) + return D_NO_SUCH_DEVICE; + tp = console_tty[ttyno]; + + /* But was it there at probe time */ + if (tp->t_addr == 0) + return D_NO_SUCH_DEVICE; + + tp->t_start = cons_start; + tp->t_stop = cons_stop; + tp->t_mctl = cons_mctl; + +#if NBM > 0 + if (screen_captures(ttyno)) + screen_open(SCREEN_CONS_UNIT(), ttyno==SCREEN_LINE_KEYBOARD); +#endif NBM > 0 + + if ((tp->t_state & TS_ISOPEN) == 0) { + if (tp->t_ispeed == 0) { + tp->t_ispeed = DEFAULT_SPEED; + tp->t_ospeed = DEFAULT_SPEED; + tp->t_flags = DEFAULT_FLAGS; + } + tp->t_dev = dev; + (*console_param)(tp, ttyno); + } + + return (char_open(dev, tp, flag, ior)); +} + + +/* + * Close routine + */ +cons_close(dev, flag) + int dev; +{ + register struct tty *tp; + register int ttyno; + spl_t s; + + if (dev == user_console) + dev = console; + + ttyno = dev; + +#if NBM > 0 + if (screen_captures(ttyno)) + screen_close(SCREEN_CONS_UNIT(), ttyno==SCREEN_LINE_KEYBOARD); +#endif NBM > 0 + + tp = console_tty[ttyno]; + + s = spltty(); + simple_lock(&tp->t_lock); + + ttyclose(tp); + + simple_unlock(&tp->t_lock); + splx(s); +} + +cons_read(dev, ior) + int dev; + register io_req_t ior; +{ + register struct tty *tp; + register ttyno; + + if (dev == user_console) + dev = console; + + ttyno = dev; +#if NBM > 0 + if (SCREEN_ISA_CONSOLE() && (ttyno == SCREEN_LINE_POINTER)) + return screen_read(SCREEN_CONS_UNIT(), ior); +#endif NBM > 0 + + tp = console_tty[ttyno]; + return char_read(tp, ior); +} + + +cons_write(dev, ior) + int dev; + register io_req_t ior; +{ + register struct tty *tp; + register ttyno; + + if (dev == user_console) + dev = console; + + ttyno = dev; +#if NBM > 0 + if (screen_captures(ttyno)) + return screen_write(SCREEN_CONS_UNIT(), ior); +#endif NBM > 0 + + tp = console_tty[ttyno]; + return char_write(tp, ior); +} + +/* + * Start output on a line + */ +cons_start(tp) + register struct tty *tp; +{ + spl_t s; + + s = spltty(); + if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) + goto out; + + if (tp->t_outq.c_cc == 0) + goto out; + + tp->t_state |= TS_BUSY; + + (*console_start)(tp); + +out: + splx(s); +} + +/* + * Stop output on a line. + */ +cons_stop(tp, flag) + register struct tty *tp; +{ + register spl_t s; + + s = spltty(); + if (tp->t_state & TS_BUSY) { + if ((tp->t_state&TS_TTSTOP)==0) + tp->t_state |= TS_FLUSH; + } + splx(s); +} + + +/* + * Modem control + */ +cons_mctl( + struct tty *tp, + int bits, + int how) +{ + return (*console_mctl)(tp->t_dev, bits, how); +} + +/* + * Abnormal close + */ +cons_portdeath(dev, port) + int dev; + mach_port_t port; +{ + if (dev == user_console) + dev = console; + return (tty_portdeath(console_tty[dev], port)); +} + +/* + * Get/Set status rotuines + */ +io_return_t +cons_get_status(dev, flavor, data, status_count) + int dev; + dev_flavor_t flavor; + int * data; /* pointer to OUT array */ + unsigned int *status_count; /* out */ +{ + register struct tty *tp; + register int ttyno; + + if (dev == user_console) + dev = console; + + ttyno = dev; + +#if NBM > 0 + if (screen_captures(ttyno) && + (screen_get_status(SCREEN_CONS_UNIT(), + flavor, data, status_count) == D_SUCCESS)) + return D_SUCCESS; +#endif NBM > 0 + + tp = console_tty[ttyno]; + + switch (flavor) { + case TTY_MODEM: + /* Take all bits */ + *data = (*console_mctl)(dev, -1, DMGET); + *status_count = 1; + break; + default: + return (tty_get_status(tp, flavor, data, status_count)); + } + return (D_SUCCESS); +} + +io_return_t +cons_set_status(dev, flavor, data, status_count) + int dev; + dev_flavor_t flavor; + int * data; + unsigned int status_count; +{ + register struct tty *tp; + register int ttyno; + + if (dev == user_console) + dev = console; + + ttyno = dev; + +#if NBM > 0 + if (screen_captures(ttyno) && + (screen_set_status(SCREEN_CONS_UNIT(), + flavor, data, status_count) == D_SUCCESS)) + return D_SUCCESS; +#endif NBM > 0 + + tp = console_tty[ttyno]; + + switch (flavor) { + case TTY_MODEM: + if (status_count < TTY_MODEM_COUNT) + return (D_INVALID_OPERATION); + (void) (*console_mctl)(dev, *data, DMSET); + break; + + case TTY_SET_BREAK: + (void) (*console_mctl)(dev, TM_BRK, DMBIS); + break; + + case TTY_CLEAR_BREAK: + (void) (*console_mctl)(dev, TM_BRK, DMBIC); + break; + + case TTY_STATUS: + { + register int error = D_SUCCESS; + struct tty_status *tsp; + + /* + * Defend from noise. The cshell... + */ + tsp = (struct tty_status *)data; + if ((tsp->tt_ispeed != tp->t_ispeed) || + (tsp->tt_ospeed != tp->t_ospeed) || + (tsp->tt_breakc != tp->t_breakc) || + ((tsp->tt_flags & ~TF_HUPCLS) != tp->t_flags)) { + + error = tty_set_status(tp, flavor, data, status_count); + if (error == 0) { + spl_t s = spltty(); + tp->t_state &= ~(TS_BUSY|TS_FLUSH); + (*console_param)(tp, ttyno); + splx(s); + } + } else + if (tsp->tt_flags & TF_HUPCLS) + tp->t_state |= TS_HUPCLS; + return (error); + } + default: + return (tty_set_status(tp, flavor, data, status_count)); + } + return (D_SUCCESS); +} + + +/* + * A simple scheme to dispatch interrupts. + * + * This deals with the fairly common case where we get an + * interrupt on each rx/tx character. A more elaborate + * scheme [someday here too..] would handle instead many + * characters per interrupt, perhaps using a DMA controller + * or a large SILO. Note that it is also possible to simulate + * a DMA chip with 'pseudo-dma' code that runs directly down + * in the interrupt routine. + */ + +/* + * We just received a character, ship it up for further processing. + * Arguments are the tty number for which it is meant, a flag that + * indicates a keyboard or mouse is potentially attached to that + * tty (-1 if not), the character proper stripped down to 8 bits, + * and an indication of any error conditions associated with the + * receipt of the character. + * We deal here with rconsole input handling and dispatching to + * mouse or keyboard translation routines. cons_input() does + * the rest. + */ +#if MACH_KDB +int l3break = 0x10; /* dear old ^P, we miss you so bad. */ +#endif MACH_KDB + +cons_simple_rint(ttyno, line, c, err) + int line; + int c; +{ + /* + * Rconsole. Drop in the debugger on break or ^P. + * Otherwise pretend input came from keyboard. + */ + if (rcline && ttyno == rcline) { +#if MACH_KDB + if ((err & CONS_ERR_BREAK) || + ((c & 0x7f) == l3break)) + return gimmeabreak(); +#endif /* MACH_KDB */ + ttyno = console; + goto process_it; + } + +#if NBM > 0 + if (screen_captures(line)) { + if (line == SCREEN_LINE_POINTER) + return mouse_input(SCREEN_CONS_UNIT(), c); + if (line == SCREEN_LINE_KEYBOARD) { + c = lk201_rint(SCREEN_CONS_UNIT(), c, FALSE, FALSE); + if (c == -1) + return; /* shift or bad char */ + } + } +#endif NBM > 0 +process_it: + cons_input(ttyno, c, err); +} + +/* + * Send along a character on a tty. If we were waiting for + * this char to complete the open procedure do so; check + * for errors; if all is well proceed to ttyinput(). + */ +cons_input(ttyno, c, err) +{ + register struct tty *tp; + + tp = console_tty[ttyno]; + + if ((tp->t_state & TS_ISOPEN) == 0) { + tt_open_wakeup(tp); + return; + } + if (err) { + if (err & CONS_ERR_OVERRUN) + log(LOG_WARNING, "sl%d: silo overflow\n", ttyno); + + if (err & CONS_ERR_PARITY) + if (((tp->t_flags & (TF_EVENP|TF_ODDP)) == TF_EVENP) + || ((tp->t_flags & (TF_EVENP|TF_ODDP)) == TF_ODDP)) + return; + if (err & CONS_ERR_BREAK) /* XXX autobaud XXX */ + c = tp->t_breakc; + } + ttyinput(c, tp); +} + +/* + * Transmission of a character is complete. + * Return the next character or -1 if none. + */ +cons_simple_tint(ttyno, all_sent) + boolean_t all_sent; +{ + register struct tty *tp; + + tp = console_tty[ttyno]; + if ((tp->t_addr == 0) || /* not probed --> stray */ + (tp->t_state & TS_TTSTOP)) + return -1; + + if (all_sent) { + tp->t_state &= ~TS_BUSY; + if (tp->t_state & TS_FLUSH) + tp->t_state &= ~TS_FLUSH; + + cons_start(tp); + } + + if (tp->t_outq.c_cc == 0 || (tp->t_state&TS_BUSY)==0) + return -1; + + return getc(&tp->t_outq); +} + + + + + +#endif /*NCONSTTY > 0*/ |