|
|
GNU Mach 1.0
/*
* 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 [email protected]
* 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*/
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.