marks@elec.uq.oz (Mark Schulz) (09/22/88)
Please reply to hannam.uq.oz . I'm using someone elses account to send
this.
echo x - ioctl.c
sed 's/^X//' >ioctl.c <<'*-*-END-of-ioctl.c-*-*'
X/* ioctl.c - get/set character device modes
X *
X * Modifications:
X * 18/9/88 - Modified for new tty driver & improved efficiency of
X * code produced.
X */
X
X#include "lib.h"
X#include <minix/com.h>
X#include <sgtty.h>
X
Xtypedef union {
X long l;
X struct {int i0, i1;} i;
X struct {char c0,c1,c2,c3;} c;
X } olong;
X
Xunion ioctl_struct {
X struct sgttyb *argp;
X struct tchars *argt;
X int *argi;
X char *argc;
X};
X
XPUBLIC int ioctl(fd, request, u)
Xint fd;
Xint request;
Xunion ioctl_struct u;
X{
X olong tmp;
X int n;
X
X M.TTY_REQUEST = request;
X M.TTY_LINE = fd;
X
X switch(request) {
X case TIOCGETP:
X n = callx(FS, IOCTL);
X tmp.l = M.TTY_FLAGS;
X u.argp->sg_flags = tmp.i.i0;
X tmp.l = M.TTY_SPEK;
X u.argp->sg_ospeed = tmp.c.c3; /* Non - compat with old */
X u.argp->sg_ispeed = tmp.c.c2;
X u.argp->sg_erase = tmp.c.c1;
X u.argp->sg_kill = tmp.c.c0;
X return n;
X
X case TIOCSETN:
X case TIOCSETP:
X tmp.i.i1 = 0;
X tmp.i.i0 = u.argp->sg_flags;
X M.TTY_FLAGS = tmp.l;
X tmp.c.c3 = u.argp->sg_ospeed;
X tmp.c.c2 = u.argp->sg_ispeed;
X tmp.c.c1 = u.argp->sg_erase;
X tmp.c.c0 = u.argp->sg_kill;
X M.TTY_SPEK = tmp.l;
X break;
X
X case TIOCGETC:
X n = callx(FS, IOCTL);
X tmp.l = M.TTY_SPEK;
X u.argt->t_intrc = tmp.c.c3;
X u.argt->t_quitc = tmp.c.c2;
X u.argt->t_startc = tmp.c.c1;
X u.argt->t_stopc = tmp.c.c0;
X tmp.l = M.TTY_FLAGS;
X u.argt->t_eofc = tmp.c.c1;
X u.argt->t_brkc = tmp.c.c0;
X return n;
X
X case TIOCSETC:
X tmp.c.c3 = u.argt->t_intrc;
X tmp.c.c2 = u.argt->t_quitc;
X tmp.c.c1 = u.argt->t_startc;
X tmp.c.c0 = u.argt->t_stopc;
X M.TTY_SPEK = tmp.l;
X tmp.i.i1 = 0;
X tmp.c.c1 = u.argt->t_eofc;
X tmp.c.c0 = u.argt->t_brkc;
X M.TTY_FLAGS = tmp.l;
X break;
X
X case FIONREAD:
X case TIOCMODG:
X case TIOCGETM:
X n= callx(FS, IOCTL);
X *u.argi = (unsigned) M.TTY_FLAGS;
X return n;
X
X case TIOCMODS:
X case TIOCSETM:
X M.TTY_FLAGS = (unsigned long) *u.argi;
X break;
X
X case TIOCSTI:
X M.TTY_FLAGS = (unsigned long) *u.argc;
X break;
X
X case TIOCSBRK:
X case TIOCCBRK:
X case TIOCSDTR:
X case TIOCCDTR:
X case TIOCSMLB:
X case TIOCCMLB:
X case TIOCSTART:
X case TIOCSTOP:
X break;
X
X default:
X errno = -(EINVAL);
X return -1;
X }
X return callx(FS, IOCTL);
X}
*-*-END-of-ioctl.c-*-*
echo x - login.c
sed 's/^X//' >login.c <<'*-*-END-of-login.c-*-*'
X/* login - log into the system Author: Andrew Hannam
X *
X * Modifications:
X * 21/9/88 - Added wtmp support as in V1.3
X *
X * BUGS:
X * Doesn't handle LCASE detection.
X * Doesn't kill parent process's.
X */
X
X#include <signal.h>
X#include <sgtty.h>
X#include <pwd.h>
X#include <sys/stat.h>
X
X#define NULL (char *) 0
X
X/* default files */
X#define DEFSH "/bin/sh"
X#define WTMPFILE "/usr/adm/wtmp"
X
X/* default INT, QUIT, START, STOP, EOF, BRK chars (for the login process) */
Xstruct tchars tchars = {-1, -1, 021, 023, 004, -1};
X#define DEFKILL '@'
X#define DEFERASE '\b'
X
X/* The following chars need to be changed before exec'ing the shell */
X#define DEFINT 0177
X#define DEFQUIT 034
X
X/* The following flags are used by login, passwd & the user process */
X#define FLAGMASK (ANYP|ODDP|EVENP)
X#define LOGINFLAGS ECHO|XTABS|CRTERA|DECCTQ|CRMOD|CRTKIL
X#define PASSWDFLAGS CRMOD|DECCTQ
X#define USERFLAGS ECHO|XTABS|CRTERA|DECCTQ|CRMOD|CRTKIL|CTLECH
X
Xchar Aname[16] = "-";
Xchar Epath[] = "PATH=:/bin:/usr/bin";
Xchar Ehome[64] = "HOME=";
Xchar Euser[24] = "USER=";
Xchar Eterm[] = "TERM=minix";
Xchar Eshell[64] = "SHELL=";
X
Xchar *arge[]= { Epath, Ehome, Euser, Eterm, Eshell, (char *) 0 };
Xchar *argp[]= { Aname, (char *)0 };
Xchar ttyname[] = "tty?";
X#define TDIGIT 3
Xchar *wtmpfile = WTMPFILE;
X#define WTMPSIZE 8
X
Xchar *crypt();
Xstruct passwd *getpwnam();
X
Xmain()
X{
Xstatic char buf[30],
X buf1[30];
X int n, n1, bad;
Xstatic struct stat statbuf;
Xstatic struct sgttyb args;
Xstatic struct passwd *pwd;
X
X /* Make sure the file system is valid (in case we wish to reboot) */
X sync();
X
X /* Get current modes and set default chars for login */
X ioctl(0, TIOCGETP, &args);
X ioctl(0, TIOCSETC, &tchars);
X args.sg_kill = DEFKILL;
X args.sg_erase = DEFERASE;
X
X /* Set up signals to defaults */
X for(n = 1; n <= NR_SIGS; ++n) signal(n, SIG_DFL);
X
X /* Look up /dev/tty number. */
X fstat(0, &statbuf);
X ttyname[TDIGIT] = '0' + statbuf.st_rdev & 0377;
X
X /* Check for login, passwd until sucessful */
X for (;;) {
X /* Get login name */
X bad = 0;
X args.sg_flags &= FLAGMASK;
X args.sg_flags |= LOGINFLAGS;
X ioctl (0, TIOCSETP, &args);
X do {
X write(1,"login: ",7);
X n = read (0, buf, 30);
X } while (n < 2);
X buf[n - 1] = 0;
X /* Look up login/passwd. */
X if ((pwd = getpwnam (buf)) == 0)
X bad++;
X /* Get passwd */
X if (bad || strlen (pwd->pw_passwd) != 0) {
X args.sg_flags &= FLAGMASK;
X args.sg_flags |= CRMOD|DECCTQ;
X ioctl (0, TIOCSETP, &args);
X write(1,"Password: ",10);
X n1 = read (0, buf1, 30);
X buf1[n1 - 1] = 0;
X write(1,"\n",1);
X if (bad) crypt(buf1,"*");
X if (bad || strcmp (pwd->pw_passwd, crypt(buf1, pwd->pw_passwd))) {
X write (1,"Login incorrect\n",16);
X continue;
X }
X }
X
X/* Successful login. */
X /* Creat wmtp entry. */
X wtmp(ttyname, pwd->pw_name);
X /* Set up directories and uid,gid */
X chdir("/");
X setgid (pwd->pw_gid);
X setuid (pwd->pw_uid);
X chdir (pwd->pw_dir);
X /* Set up environment, params & shell */
X strcat(Ehome,pwd->pw_dir);
X strcat(Euser,pwd->pw_name);
X if (!pwd->pw_shell || !*pwd->pw_shell)
X pwd->pw_shell = DEFSH;
X strcat(Eshell,pwd->pw_shell);
X strcat(Aname,rindex(pwd->pw_shell,'/')+1);
X /* Set up tty modes */
X args.sg_flags &= FLAGMASK;
X args.sg_flags |= USERFLAGS;
X ioctl(0, TIOCSETP, &args);
X tchars.t_intrc = DEFINT;
X tchars.t_quitc = DEFQUIT;
X ioctl(0, TIOCSETC, &tchars);
X /* Do the exec */
X execve(pwd->pw_shell, argp, arge);
X write(1,"exec failure\n",13);
X }
X}
X
Xwtmp(tty, name)
X{
X/* Make an entry in wtmp file. */
X
X int i, fd;
X long t, time();
X char ttybuff[WTMPSIZE], namebuff[WTMPSIZE];
X
X fd = open(wtmpfile, 2);
X if (fd < 0) return; /* if wtmp does not exist, no accounting */
X lseek(fd, 0L, 2); /* append to file */
X
X for (i = 0; i < WTMPSIZE; i++) {
X ttybuff[i] = 0;
X namebuff[i] = 0;
X }
X strncpy(ttybuff, tty, 8);
X strncpy(namebuff, name, 8);
X time(&t);
X write(fd, ttybuff, WTMPSIZE);
X write(fd, namebuff, WTMPSIZE);
X write(fd, &t, sizeof(t));
X close(fd);
X}
*-*-END-of-login.c-*-*
echo x - stty.c
sed 's/^X//' >stty.c <<'*-*-END-of-stty.c-*-*'
X/* stty - set terminal mode Author: Andy Tanenbaum
X * Modifications:
X * 21/9/88 - Added support for new tty driver
X */
X
X#include <sgtty.h>
X
Xchar *on[] = {"-tabs", "cbreak", "raw", "-nl", "echo"
X ,"prterase", "crtbs", "crterase", "crtkill"
X ,"ctlecho", "decctq", "lcase"};
Xchar *off[]= {"tabs", "", "", "nl", "-echo", "", "", ""
X ,"-crtkill", "-ctlecho", "-decctq", ""};
Xchar *speed[]= {"45.5", "50", "75", "110", "134.5", "150", "200"
X ,"300", "600", "1200", "1800", "2000", "2400"
X ,"4800", "9600", "19.2K", "38.4K", "57.6K", "115.2K"};
Xchar *speed2[]= {"19200", "38400", "57600", "115200"};
X
X#define SPEED2 15
X#define NO_SPEEDS NO_BAUDS
X
X#define match(s1,s2) (!strcmp(s1,s2))
X
Xstruct sgttyb args;
Xstruct tchars tch;
Xunsigned term_mod;
X
X/* Chars for reset */
X#define KILL '@' /* @ */
X#define ERASE '\b' /* CTRL-H */
X#define STARTC 021 /* CTRL-Q */
X#define STOPC 023 /* CTRL-S */
X#define QUITC 034 /* CTRL-\ */
X#define EOFC 004 /* CTRL-D */
X#define DELC 0177 /* DEL */
X
X#define FD 0 /* what file descriptor to use */
X
Xint k;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X
X /* stty with no arguments just reports on current status. */
X ioctl(FD, TIOCGETP, &args);
X ioctl(FD, TIOCGETC, &tch);
X ioctl(FD, TIOCGETM, &term_mod);
X if (argc == 1) {
X report();
X exit(0);
X }
X
X /* Process the options specified. */
X k = 1;
X while (k < argc) {
X option(argv[k], k+1 < argc ? argv[k+1] : "");
X k++;
X }
X ioctl(FD, TIOCSETP, &args);
X ioctl(FD, TIOCSETC, &tch);
X ioctl(FD, TIOCSETM, &term_mod);
X exit(0);
X}
X
X
X
Xreport()
X{
X int mode;
X
X
X mode = args.sg_flags;
X pr(mode&XTABS, 0);
X pr(mode&CBREAK, 1);
X pr(mode&RAW, 2);
X pr(mode&CRMOD,3);
X pr(mode&ECHO,4);
X pr(mode&PRTERA,5);
X pr(mode&CRTBS,6);
X pr(mode&CRTERA,7);
X pr(mode&CRTKIL,8);
X pr(mode&CTLECH,9);
X pr(mode&DECCTQ,10);
X pr(mode&LCASE,11);
X prints("\n");
X if (term_mod&D_SERIAL)
X prints("serial: ");
X else if (term_mod&D_CONSOLE)
X prints("console: ");
X else prints("tty type unknown: ");
X prints(" input @ %s",args.sg_ispeed ? speed[args.sg_ispeed - 1]:"????");
X if (term_mod&D_SERIAL) {
X if (term_mod&RX_XONXOFF)
X prints(" %c xonxoff ", '5' + (term_mod&SER_DATABITS));
X else
X prints(" %c hardware", '5' + (term_mod&SER_DATABITS));
X }
X prints("\toutput @ %s",args.sg_ispeed ? speed[args.sg_ospeed - 1]:"????");
X if (term_mod&D_SERIAL) {
X if (term_mod&TX_XONXOFF)
X prints(" %c xonxoff", '5' + (term_mod&SER_DATABITS));
X else
X prints(" %c hardware", '5' + (term_mod&SER_DATABITS));
X }
X prints("\n\nkill = ");prctl(args.sg_kill);
X prints("\nerase = "); prctl(args.sg_erase);
X prints("\nint = "); prctl(tch.t_intrc);
X prints("\nquit = "); prctl(tch.t_quitc);
X prints("\nstop = "); prctl(tch.t_stopc);
X prints("\nstart = "); prctl(tch.t_startc);
X prints("\neof = "); prctl(tch.t_eofc);
X prints("\n");
X}
X
Xpr(f, n)
Xint f,n;
X{
X if (f)
X prints("%s ",on[n]);
X else
X prints("%s ",off[n]);
X}
X
Xoption(opt, next)
Xchar *opt, *next;
X{
X register spe;
X static char inflag= 0, outflag= 0;
X if (match(opt, "-tabs")) {args.sg_flags |= XTABS; return;}
X if (match(opt, "-raw")) {args.sg_flags &= ~RAW; return;}
X if (match(opt, "-cbreak")) {args.sg_flags &= ~CBREAK; return;}
X if (match(opt, "-echo")) {args.sg_flags &= ~ECHO; return;}
X if (match(opt, "-nl")) {args.sg_flags |= CRMOD; return;}
X if (match(opt, "-prterase")) {args.sg_flags &= ~PRTERA; return;}
X if (match(opt, "-crtbs")) {args.sg_flags &= ~CRTBS; return;}
X if (match(opt, "-crterase")) {args.sg_flags &= ~CRTERA; return;}
X if (match(opt, "-crtkill")) {args.sg_flags &= ~CRTKIL; return;}
X if (match(opt, "-ctlecho")) {args.sg_flags &= ~CTLECH; return;}
X if (match(opt, "-decctq")) {args.sg_flags &= ~DECCTQ; return;}
X if (match(opt, "-lcase")) {args.sg_flags &= ~LCASE; return;}
X if (match(opt, "tabs")) {args.sg_flags &= ~XTABS; return;}
X if (match(opt, "raw")) {args.sg_flags |= RAW; return;}
X if (match(opt, "cbreak")) {args.sg_flags |= CBREAK; return;}
X if (match(opt, "echo")) {args.sg_flags |= ECHO; return;}
X if (match(opt, "nl")) {args.sg_flags &= ~CRMOD; return;}
X if (match(opt, "prterase")) {args.sg_flags &= ~(CRTBS|CRTERA);
X args.sg_flags |= PRTERA; return;}
X if (match(opt, "crtbs")) {args.sg_flags &= ~(PRTERA|CRTERA);
X args.sg_flags |= CRTBS; return;}
X if (match(opt, "crterase")) {args.sg_flags &= ~(PRTERA|CRTBS);
X args.sg_flags |= CRTERA; return;}
X if (match(opt, "crtkill")) {args.sg_flags |= CRTKIL; return;}
X if (match(opt, "ctlecho")) {args.sg_flags |= CTLECH; return;}
X if (match(opt, "decctq")) {args.sg_flags |= DECCTQ; return;}
X if (match(opt, "lcase")) {args.sg_flags |= LCASE; return;}
X if (match(opt, "kill")) {args.sg_kill = *next; k++; return;}
X if (match(opt, "erase")) {args.sg_erase = *next; k++; return;}
X if (match(opt, "int")) {tch.t_intrc = *next; k++; return;}
X if (match(opt, "quit")) {tch.t_quitc = *next; k++; return;}
X if (match(opt, "start")) {tch.t_startc = *next; k++; return;}
X if (match(opt, "stop")) {tch.t_stopc = *next; k++; return;}
X if (match(opt, "eof")) {tch.t_eofc = *next; k++; return;}
X
X if (match(opt, "default") || match(opt,"reset")) {
X args.sg_flags = ECHO|CRMOD|XTABS|CRTERA|CTLECH|DECCTQ|CRTKIL;
X args.sg_kill = KILL;
X args.sg_erase = ERASE;
X tch.t_intrc = DELC;
X tch.t_quitc = QUITC;
X tch.t_startc = STARTC;
X tch.t_stopc = STOPC;
X tch.t_eofc = EOFC;
X return;
X }
X
X if (match(opt,"input")) {inflag++ ; outflag = 0; return;}
X if (match(opt,"output")) {outflag++; inflag = 0; return;}
X if (term_mod&D_SERIAL) {
X if (atoi(opt) >= 5 && atoi(opt) <= 8) {
X term_mod &= ~SER_DATABITS;
X term_mod |= atoi(opt) - 5; return;
X }
X if (match(opt,"xonxoff") || match(opt,"-hardware")) {
X if (!outflag) term_mod |= RX_XONXOFF;
X if (!inflag) term_mod |= TX_XONXOFF;
X return;
X }
X if (match(opt,"-xonxoff") || match(opt,"hardware")) {
X if (!outflag) term_mod &= ~RX_XONXOFF;
X if (!inflag) term_mod &= ~TX_XONXOFF;
X return;
X }
X }
X
X for(spe=0;spe < NO_SPEEDS;spe++)
X if (match(opt,speed[spe])) break;
X if (spe >= NO_SPEEDS)
X for (spe=SPEED2;spe < NO_SPEEDS;spe++)
X if (match(opt,speed2[spe-SPEED2])) break;
X if (spe < NO_SPEEDS) {
X if (!outflag) args.sg_ispeed= spe+1;
X if (!inflag) args.sg_ospeed= spe+1;
X return;
X }
X
X std_err("unknown mode: ");
X std_err(opt);
X std_err("\n");
X
X}
X
Xprctl(c)
Xchar c;
X{
X if (c < ' ')
X prints("^%c", 'A' - 1 + c);
X else if (c == 0177)
X prints("DEL");
X else
X prints("%c", c);
X}
*-*-END-of-stty.c-*-*
echo x - term.c
sed 's/^X//' >term.c <<'*-*-END-of-term.c-*-*'
X/* term - terminal simulator Author: Andy Tanenbaum
X * Modififications:
X * 21/9/88 - Added support for new tty driver
X */
X
X/* This program allows the user to turn a MINIX system into a dumb
X * terminal to communicate with a remote computer over a modem. It
X * forks into two processes. The parent sits in a tight loop copying
X * from the keyboard to the modem. The child sits in a tight loop
X * copying from the modem to the screen.
X *
X * Example usage:
X * term : 1200 baud, 8 bits/char, no parity
X * term 9600 7 even : 9600 baud, 7 bits/char, even parity
X * term odd 300 7 : 300 baud, 7 bits/char, odd parity
X */
X
X#include <signal.h>
X#include <sgtty.h>
X
X#define NCHECKS 10
X#define BAD -1
X#define GOOD 1
X#define MODEM "/dev/tty1" /* special file attached to the modem */
X#define ESC 033 /* character to hit to leave simulator */
X#define LIMIT 3 /* how often do you have to hit ESC to exit*/
X#define CHUNK 1024 /* how much to read at once */
X
Xint modem, pid; /* file descriptor for modem */
X
Xchar *speed1[]= {"45.5", "50", "75", "110", "134.5", "150", "200"
X ,"300", "600", "1200", "1800", "2000", "2400"
X ,"4800", "9600", "19.2K", "38.4K", "57.6K", "115.2K"};
Xchar *speed2[]= {"19200", "38400", "57600", "115200"};
X
X#define SPEED2 15
X#define NO_SPEEDS NO_BAUDS
X#define match(s1,s2) (!strcmp(s1,s2))
X
Xstruct sgttyb sgtty, sgsave1, sgsave2;
Xunsigned modsave1;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X
X sync();
X modem = open(MODEM, 2);
X if (modem < 0) {
X printf("Can't open modem on %s\n", MODEM);
X exit(1);
X }
X set_uart(argc, argv);
X
X /* Main body of the terminal simulator. */
X if ( (pid = fork()))
X copy(0, modem, ESC); /* copy from stdin to modem */
X else
X copy(modem, 1, -1); /* copy from modem to stdout */
X}
X
Xset_uart(argc, argv)
Xint argc;
Xchar *argv[];
X{
X/* Set up the UART parameters. */
X
X int i, k, modstat
X , speed, parity, bits, handsh;
X
X ioctl(modem, TIOCGETM, &modstat);
X modsave1 = modstat;
X if (!(modstat&D_SERIAL))
X error("term will only run on serial lines\n");
X
X ioctl(modem, TIOCGETP, &sgtty);
X sgsave1 = sgtty; /* modem parameters saved */
X /* Get defaults */
X parity = sgtty.sg_flags & (ODDP|EVENP|ANYP|NONEP);
X bits = modstat&SER_DATABITS;
X handsh = modstat&(RX_XONXOFF|TX_XONXOFF);
X speed = sgtty.sg_ispeed;
X
X /* Examine all the parameters and check for validity. */
X for (i = 1; i < argc; i++) {
X if (match(argv[i], "even")) {parity = EVENP; continue;}
X if (match(argv[i], "odd")) {parity = ODDP; continue;}
X if (match(argv[i], "any")) {parity = ANYP; continue;}
X if (match(argv[i], "none")) {parity = NONEP; continue;}
X
X if (match(argv[i], "xonxoff")) {handsh = TX_XONXOFF|RX_XONXOFF;
X continue;}
X if (match(argv[i], "hardware")) {handsh = 0; continue;}
X
X k = atoi(argv[i]);
X if (k >= 5 && k <= 8) {
X bits = k - 5;
X continue;
X }
X
X speed = validity(argv[i]);
X if (speed == BAD) {
X printf("Invalid parameter: %s\n", argv[i]);
X error("Usage: term [baudrate] [data_bits] [parity] [handshaking]\n");
X }
X }
X
X /* Set the modem parameters. */
X modstat &= ~(SER_DATABITS|TX_XONXOFF|RX_XONXOFF);
X modstat |= bits | handsh;
X ioctl(modem, TIOCSETM, &modstat);
X sgtty.sg_ispeed = sgtty.sg_ospeed = speed;
X sgtty.sg_flags = RAW | parity;
X ioctl(modem, TIOCSETP, &sgtty);
X
X /* Fetch the keyboard parameters, save them, and set new ones. */
X ioctl(0, TIOCGETP, &sgtty);
X sgsave2 = sgtty; /* modem parameters */
X sgtty.sg_flags = (sgtty.sg_flags&(ANYP|EVENP|ODDP|NONEP)) | RAW;
X ioctl(0, TIOCSETP, &sgtty);
X}
X
X
Xint validity(s)
Xchar *s;
X{
X/* Check speed parameter for legality. */
X
X int i;
X
X for (i = 0; i < NO_BAUDS; i++) {
X if (match(s, speed1[i])) return(i+1);
X }
X for (i = 0; i < NO_BAUDS - SPEED2 ; i++) {
X if (match(s, speed2[i])) return(i+SPEED2+1);
X }
X return(BAD);
X}
X
X
Xcopy(in, out, end)
Xint in, out, end;
X{
X/* Copy from the keyboard to the modem or vice versa. If the end character
X * is seen LIMIT times in a row, quit. For the traffic from the modem, the
X * end character is -1, which cannot occur since the characters from the
X * modem are unsigned integers in the range 0 to 255.
X */
X
X int t, count, state = 0;
X char buf[CHUNK], *p;
X
X while (1) {
X if ( (count = read(in, buf, CHUNK)) < 0) {
X printf("Can't read from modem\r\n");
X quit();
X }
X
X if (end > 0) {
X for (p = &buf[0]; p < &buf[count]; p++) {
X t = *p & 0377; /* t is unsigned int 0 - 255 */
X if (t == end) {
X if (++state == LIMIT) quit();
X } else {
X state = 0;
X }
X }
X }
X write(out, buf, count);
X }
X}
X
Xerror(s)
Xchar *s;
X{
X printf("%s", s);
X exit(1);
X}
X
Xquit()
X{
X ioctl(modem, TIOCSETP, &sgsave1);
X ioctl(modem, TIOCSETM, &modsave1);
X ioctl(0, TIOCSETP, &sgsave2);
X if (getpid() != pid) kill(pid, SIGINT);
X exit(0);
X}
X
*-*-END-of-term.c-*-*
echo x - xonxoff.c
sed 's/^X//' >xonxoff.c <<'*-*-END-of-xonxoff.c-*-*'
X#include <sgtty.h>
X
Xmain(argc,argv)
Xchar *argv[];
X{
Xint i;
X
X if (argc > 2 || (argc == 2 && *argv[1] != 't' && *argv[1] != 'r')) {
X printf("Usage: %s [t|r]\n",*argv);
X exit(1);
X }
X ioctl(0,TIOCGETM, &i);
X if (!(i&D_SERIAL)) {
X printf("This is not a serial line: device = 0x%x mode = 0x%x\n"
X ,i>>8, i&0xFF);
X exit(1);
X }
X
X if (argc == 2) {
X if (*argv[1] == 't') i |= TX_XONXOFF;
X else i |= RX_XONXOFF;
X } else i ^= (TX_XONXOFF|RX_XONXOFF);
X
X ioctl(0,TIOCSETM, &i);
X ioctl(0,TIOCGETM, &i);
X if (i&TX_XONXOFF)
X printf("TX now in XONXOFF handshaking\n");
X else
X printf("TX now in HARDWARE handshaking\n");
X if (i&RX_XONXOFF)
X printf("RX now in XONXOFF handshaking\n");
X else
X printf("RX now in HARDWARE handshaking\n");
X}
*-*-END-of-xonxoff.c-*-*
echo x - tty1.c
sed 's/^X//' >tty1.c <<'*-*-END-of-tty1.c-*-*'
X/* tty1.c - device independant code for tty driver
X *
X * Written by: A.Hannam (Feb 1988)
X *
X * Modifications:
X * 21/8/88 - Modified for MINIX V1.3 on IBM-PC
X */
X
X/* This file contains the high level terminal driver and is device independant.
X * It accepts characters to be printed from programs, process's them and then
X * passes them on to the raw (device dependant) output routines. It also
X * accepts input from raw (device dependant) routines, process's them acording
X * to the modes set by ioctl, and queues it for programs.
X * This file contains 3 main entry points: tty_task(), sigchar() and putc().
X * tty_task - takes messages to do work from readers, writers and interrupt
X * service routines.
X * sigchar - used to send signals from the keyboard. (Special for F10)
X * putc - used in the printf routine for the kernel.
X *
X * The valid messages and their parameters are:
X *
X * TTY_CHAR_INT: interrupt routines have produced char(s)
X * TTY_O_DONE: interrupt routines need more charactors to output
X * TTY_READ: a process wants to read from a terminal
X * TTY_WRITE: a process wants to write on a terminal
X * TTY_IOCTL: a process wants to change a terminal's parameters
X * TTY_SETPGRP: a process wants to change a terminal's process group
X * CANCEL: terminate a previous incomplete system call immediately
X *
X * m_type TTY_LINE PROC_NR COUNT TTY_SPEK TTY_FLAGS ADDRESS
X * ---------------------------------------------------------------------------
X * | TTY_CHAR_INT|minor dev| | | | |array ptr|
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_O_DONE |minor dev| | | | | |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_READ |minor dev| proc nr | count | | | buf ptr |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_WRITE |minor dev| proc nr | count | | | buf ptr |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_IOCTL |minor dev| proc nr |func code|erase etc| flags | |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | TTY_SETGPRP |minor dev| proc nr | pgrp | | | |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | CANCEL |minor dev| proc nr | | | | |
X * ---------------------------------------------------------------------------
X */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "../h/sgtty.h"
X#include "../h/signal.h"
X#include "../h/callnr.h"
X#include "type.h"
X#include "const.h"
X#include "proc.h"
X
X#define HIGH_LEVEL
X#include "tty.h"
X
XPUBLIC tty_entry tty_struct[NR_TTYS]; /* The tty tables */
XPUBLIC void tty_task(), putc(); /* Public routines */
XPUBLIC void do_nothing(), sigchar(), rs_flush();
X
Xextern int lock();
Xextern void restore();
Xextern char get_byte();
X
X
X#define TAB_SIZE 8 /* distance between tabs (must be pwr of 2) */
X
X#define ERASE_CHAR '\b' /* default erase character */
X#define KILL_CHAR '@' /* default kill character */
X#define INTR_CHAR 0177 /* default interrupt character */
X#define QUIT_CHAR 034 /* default quit characterc (CTRL-\) */
X#define XOFF_CHAR 023 /* default x-off character (CTRL-S) */
X#define XON_CHAR 021 /* default x-on character (CTRL-Q) */
X#define EOT_CHAR 004 /* default EOF character (CTRL-D) */
X#define BRK_CHAR '\n' /* default delimiter (\n) (not used) */
X#define WORD_MASK 0xFFFF /* mask for 16 bits */
X#define OFF_MASK 0x000F /* mask for 4 bits */
X
X /* Our private routines */
XPRIVATE void tty_bad(), tty_init(), do_charint(), proc_ints()
X ,echo(), do_read(), do_ioctl(), do_cancel(), do_write()
X ,tty_reply(), out_chars(), do_setpgrp();
XPRIVATE bool do_cooked(), in_char();
XPRIVATE unsigned chuck();
XPRIVATE int rd_chars();
X
XPRIVATE charfbuf tty_copy_buf; /* copy buf used to avoid races */
XPRIVATE message c_mess; /* used by the clock in flushing */
X
X/*===========================================================================*
X * tty_task *
X *===========================================================================*/
XPUBLIC void tty_task()
X{
X/* Main routine of the terminal task. */
X
X message tty_mess; /* buffer for all incoming messages */
X register tty_entry *tp;
X
X tty_init(); /* initialize */
X while (TRUE) {
X receive(ANY, &tty_mess);
X if (tty_mess.TTY_LINE < 0 || tty_mess.TTY_LINE > NR_TTYS-1) {
X tty_bad(&tty_mess);
X continue;
X }
X tp = &tty_struct[tty_mess.TTY_LINE];
X switch(tty_mess.m_type) {
X
X /* Hardware Interrupts */
X case TTY_CHAR_INT:
X case TTY_O_DONE: proc_ints(); break;
X
X /* Software Interrupts */
X case TTY_READ: do_read(tp, &tty_mess); break;
X case TTY_WRITE: do_write(tp, &tty_mess); break;
X case TTY_IOCTL: do_ioctl(tp, &tty_mess); break;
X case TTY_SETPGRP: do_setpgrp(tp, &tty_mess); break;
X case CANCEL : do_cancel(tp, &tty_mess); break;
X default: tty_bad(&tty_mess);
X }
X }
X}
X
X
X/*===========================================================================*
X * tty_init *
X *===========================================================================*/
XPRIVATE void tty_init()
X{
X/* Initialize all the terminals and tty_tables */
X
X register tty_entry *tp;
X register i;
X
X /* Prepare the clock tasks message (so it is a legal message) */
X c_mess.TTY_LINE = 0; /* Has to point to a valid tty (any) */
X c_mess.m_type = TTY_CHAR_INT; /* Could also have been TTY_O_DONE */
X
X /* Initialize the TTY structure */
X for (tp = &tty_struct[0],i=0; i < NR_TTYS; tp++,i++) {
X bufinit(tp->tty_inbuf);
X tp->tty_lfct = 0;
X tp->tty_writers = 0;
X tp->tty_state = 0;
X tp->tty_ddmod = 0;
X tp->tty_mode = CRMOD|XTABS|ECHO|CRTERA|CTLECH|CRTKIL|DECCTQ;
X tp->tty_erase = ERASE_CHAR;
X tp->tty_kill = KILL_CHAR;
X tp->tty_intr = INTR_CHAR;
X tp->tty_quit = QUIT_CHAR;
X tp->tty_xon = XON_CHAR;
X tp->tty_xoff = XOFF_CHAR;
X tp->tty_eof = EOT_CHAR;
X tp->tty_brk = BRK_CHAR;
X (*dev_init[i])(tp);
X }
X}
X
X/*===========================================================================*
X * tty_bad *
X *===========================================================================*/
XPRIVATE void tty_bad(p)
Xmessage *p;
X{
X /* dump out bad tty messages */
X#ifdef DEBUG
X register char *q= (char *)p;
X register x;
X
X printf("\nIllegal TTY message:\n");
X#ifdef DEBUG2
X for(x=1; x <= sizeof(*p); x++) {
X printf("0x%x ", (*q++) & 0xFF);
X if( x%8 == 0) printf("\n");
X }
X printf("\n");
X printf("m_type= %d, source= %d, TTY_LINE= %d, PROC_NR= %d\n"
X ,p->m_type,p->m_source,p->TTY_LINE,p->PROC_NR);
X printf("COUNT= %d, ADDRESS= 0x%x\n",p->COUNT,p->ADDRESS);
X printf("\tor ...\n");
X#endif DEBUG2
X printf("m_type= %d, dest= %d, PROC_NR= %d, STATUS= %d\n"
X ,p->m_type,p->m_source,p->REP_PROC_NR,p->REP_STATUS);
X printf("flags= %D, spek= %D\n",p->TTY_FLAGS,p->TTY_SPEK);
X#else
X printf("m_type = %d\n",p->m_type);
X panic("TTY",p->TTY_LINE);
X#endif DEBUG
X}
X
X/*===========================================================================*
X * rs_flush *
X *===========================================================================*/
XPUBLIC void rs_flush()
X{
X/* The clock task has recieved notification that input or output flushing is
X * needed. This is a general routine unlike the one in the original (V1.3)
X * tty which was specific to the rs232 lines. This should probably be
X * renamed to something more meaningful but will suffice at present.
X * Simply send an interrupt message for the tty.
X */
X interrupt(TTY, &c_mess);
X flush_flag = 0;
X}
X
X/*===========================================================================*
X * proc_ints *
X *===========================================================================*/
XPRIVATE void proc_ints()
X{
X/* This routine process's hardware interrupts. It is needed as MINIX can only
X * handle one interrupt per task at a time. This means interrupts can be lost.
X * This solution simply says that an interrupt has occured (it doesn't matter
X * whose) and the state of the work needed is stored else where (in the
X * tty_struct). It is a bad problem with a horrible solution. Still it works.
X */
Xregister tty_entry *tp;
Xregister flags;
X
X /* Some one needs some flushing - find out who and do it. */
X for(tp= &tty_struct[0]; tp < &tty_struct[NR_TTYS]; tp++) {
X flags = lock();
X if (tp->tty_state & IN_FLUSH) {
X tp->tty_state &= ~IN_FLUSH;
X restore(flags);
X do_charint(tp); /* This tty has some input */
X flags = lock();
X }
X if (tp->tty_state & OUT_FLUSH) {
X tp->tty_state &= ~OUT_FLUSH;
X restore(flags);
X out_chars(tp); /* This tty needs some output */
X continue;
X }
X restore(flags);
X }
X}
X
X/*===========================================================================*
X * do_charint *
X *===========================================================================*/
XPRIVATE void do_charint(tp)
Xregister tty_entry *tp;
X{
X/* A character has been typed. If a character is typed and the tty task is
X * not able to service it immediately, the character is accumulated within
X * the low level tty driver. A call to this routine may thus have to process
X * several characters.
X */
X
X register unsigned char *count;
X register char *copy_ptr;
X int r_val;
X
X
X/* We have to copy the chars in the device fbuf so we can process them */
X r_val= lock(); /* prevent races by disabling int's */
X count = &(tp->tty_fbuf->count); /* how many chars to transfer */
X if (*count == 0) { /* check the count is valid */
X restore(r_val);
X return;
X }
X /* copy using bcopy(from,to,count) */
X bcopy(tp->tty_fbuf,&tty_copy_buf, *count);
X tty_copy_buf.count= *count; /* copy the no of chars */
X *count= 0; /* clear the device fbuf */
X restore(r_val); /* re-enable interrupts */
X
X /* notify the low level routine for flow control reasons */
X (*tp->tty_devempty)(tp);
X
X /* Loop on the accumulated characters, processing each in turn. */
X copy_ptr = tty_copy_buf.b;
X /* process the char, queue and echo it */
X while (tty_copy_buf.count--)
X if (in_char(tp, *copy_ptr++) && tp->tty_inleft) {
X /* TTY buffer is full, try transfering to user. */
X r_val= rd_chars(tp,1); /* force the reader to accept chars */
X if (r_val != SUSPEND) /* reader could be satisfied */
X tty_reply(REVIVE, (int) tp->tty_incaller
X , (int) tp->tty_inproc, r_val);
X tty_copy_buf.count++; /* try the char again */
X copy_ptr--;
X }
X
X /* See if user can be satisfied. */
X if (tp->tty_inleft) {
X r_val= rd_chars(tp,0); /* don't force reader to take chars */
X if (r_val != SUSPEND) /* reader could be satisfied */
X tty_reply(REVIVE, (int) tp->tty_incaller
X , (int) tp->tty_inproc, r_val);
X }
X}
X
X
X/*===========================================================================*
X * in_char *
X *===========================================================================*/
XPRIVATE bool in_char(tp, ch)
Xregister tty_entry *tp; /* tty on which the char arrived */
Xint ch; /* code for character that arrived */
X{
X/* A character has just been typed in. Process, save, and echo it.
X Returns TRUE if buffers full else FALSE */
X
X register mode;
X char c;
X unsigned col;
X charpos chp;
X
X ch &= 0xFF; /* make sure only 8 bits */
X mode = tp->tty_mode; /* speed up access to mode bits */
X
X do {
X /* The translate routine returns unsigned. The lower byte is the
X ascii char, the upper byte (except for the MARKER (top) bit)
X may be used for the translate routines use.
X If the top byte == 0 then this is a single char,
X else it is the start of a sequence.
X The next call of a sequence is passed the previous result
X as a parameter. The first call to translate always has the
X top byte set to 0.
X If the MARKER is set then this char is to be ignored and
X if in a sequence then the sequence ends.
X */
X if (tp->tty_state & TRANSLATE) /* Translate the char to ascii */
X if( (ch = (*tp->tty_devtrans)(ch))&MARKER) break;
X
X c= ch & 0xFF; /* We now have an 8-bit ascii char */
X
X /* From now on the MARKER bit is used to indicate EOF */
X
X
X /* Processing for COOKED and CBREAK mode contains special checks. */
X if (!(mode&RAW)) {
X
X /* 7-bit chars except in raw mode or if an 8 bit terminal */
X if (!(tp->tty_state&COK8BIT)) c &= 0177;
X
X /* LCASE processing must come first */
X if ((mode&LCASE) && c >= 'A' && c <= 'Z') c += 'a'-'A';
X
X /* Handle erase, kill and escape processing etc. (cooked mode only) */
X if (!(mode&CBREAK)) {
X
X /* See if the last char was escaped */
X if (tp->tty_state&ESCAPED) {
X
X /* Previous character was backslash. */
X tp->tty_state &= ~ESCAPED; /* turn escaping off */
X
X /* If necessary store the escape previously skipped over */
X if (c != tp->tty_erase && c != tp->tty_kill && c != '\\' &&
X c != tp->tty_eof && bufnfull(tp->tty_inbuf)) {
X chp.ch= '\\'; chp.col= tp->tty_column-1;
X putobj(tp->tty_inbuf, chp);
X }
X
X /* Last char wasn't escaped - do erase, kill etc processing ...
X * Care must be taken as whether to use echo() or do_cooked()
X * as they have different results in the CTLECH case. Where it
X * doesn't matter use echo() as it can be considered safer.
X */
X } else {
X
X /* ERASE processing (rub out of last character). */
X if (c == tp->tty_erase) {
X /* del last char, doing echo if possible */
X if ((col=chuck(tp)) != 0xFFFF && mode&ECHO) {
X if (mode&(CRTBS|CRTERA)) {
X col= col >>8; /* get column */
X do {
X do_cooked(tp,'\b',ECHO_OUT);
X if (mode&CRTERA) {
X echo(tp, ' ');
X do_cooked(tp, '\b', ECHO_OUT);
X }
X } while(tp->tty_column > col);
X } else if (tp->tty_mode&PRTERA) {
X echo(tp,'\\');
X echo(tp,(char)ch);
X echo(tp,'/');
X } else echo(tp,tp->tty_erase);
X }
X continue; /* Don't store a char */
X } else /* End of ERASE processing */
X
X /* KILL processing (remove current line). */
X if (c == tp->tty_kill) {
X /* Only do fancy kill if echo on */
X if (tp->tty_mode&CRTKIL && mode&ECHO) {
X while((col= chuck(tp)) != 0xFFFF) {
X col= col >>8;
X do {
X do_cooked(tp,'\b',ECHO_OUT);
X echo(tp,' ');
X do_cooked(tp,'\b',ECHO_OUT);
X } while(tp->tty_column > col);
X }
X } else { /* Simple kill */
X while(chuck(tp) != 0xFFFF);
X echo(tp, tp->tty_kill);
X echo (tp, '\n');
X }
X continue; /* Don't store a char */
X } else /* End of KILL processing */
X
X /* ESCAPE processing (backslash). */
X if (c == '\\') {
X tp->tty_state |= ESCAPED;
X echo(tp, c);
X continue; /* Don't store the '\' */
X } else /* End of ESCAPE processing */
X
X /* EOF processing.
X * It is stored in the text as MARKER, and counts as a
X * line feed in terms of knowing whether a full line
X * has been typed already.
X */
X if (c == tp->tty_eof)
X ch |= MARKER; /* End of EOF processing */
X
X } /* End of Escape processing */
X } /* End of Cooked processing */
X
X /* Both COOKED and CBREAK modes come here; first map CR to LF. */
X if (c == '\r' && (mode&CRMOD)) c = '\n';
X
X /* Check for interrupt character. */
X if (c == tp->tty_intr) {
X sigchar(tp, SIGINT);
X continue; /* Don't store a char */
X }
X
X /* Check for quit character. */
X if (c == tp->tty_quit) {
X sigchar(tp, SIGQUIT);
X continue; /* Don't store a char */
X }
X
X /* Check for and process CTRL-Q (terminal start). */
X if (c == tp->tty_xon
X || (tp->tty_state&INHIBITED && !(mode&DECCTQ))) {
X tp->tty_state &= ~INHIBITED;
X out_chars(tp); /* resume output */
X continue; /* Don't store a char */
X }
X
X /* Check for and process CTRL-S (terminal stop). */
X if (c == tp->tty_xoff) {
X tp->tty_state |= INHIBITED;
X continue; /* Don't store a char */
X }
X } /* End of Cooked, Cbreak processing */
X
X /* All 3 modes come here. */
X if (bufnfull(tp->tty_inbuf)) { /* discard char if buffer full */
X if (c == '\n' || (ch&MARKER)) /* count line feeds */
X tp->tty_lfct++;
X /* save the character in the input queue */
X if (ch&MARKER) {
X chp.ch= chp.col= 0xFF;
X putobj(tp->tty_inbuf,chp);
X } else {
X chp.ch= c; chp.col= tp->tty_column;
X putobj(tp->tty_inbuf,chp);
X echo(tp, c);
X }
X }
X
X /* Continue with macro type keys (translate on) */
X } while( (ch &= ~MARKER) & 0xFF00 );
X return buffull(tp->tty_inbuf);
X}
X
X/*===========================================================================*
X * sigchar *
X *===========================================================================*/
XPUBLIC void sigchar(tp, sig)
Xregister tty_entry *tp; /* pointer to tty_struct */
Xint sig; /* SIGNAL to send */
X{
X/* Process a signal generated by the tty (key or otherwise) */
X
X tp->tty_state &= ~INHIBITED; /* do implied CRTL-Q */
X bufinit(tp->tty_inbuf); /* discard input */
X tp->tty_lfct = 0;
X (*tp->tty_devclr)(tp); /* discard output */
X
X /* Send signal if the process group is valid - (or console KILL all) */
X /* At the moment tty_pgrp stores a slot num, not a proc group num. */
X if (tp->tty_pgrp || sig == SIGKILL)
X cause_sig(tp->tty_pgrp, sig);
X}
X
X
X/*===========================================================================*
X * echo *
X *===========================================================================*/
XPRIVATE void echo(tp, c)
Xregister tty_entry *tp; /* terminal on which to echo */
Xregister char c; /* character to echo */
X{
X/* Echo a character on the terminal. */
X
X if ( (tp->tty_mode & ECHO) == 0) return; /* if no echoing, don't echo */
X
X if ((tp->tty_mode&(CTLECH|RAW))==CTLECH) {
X if (c&128) {
X echo(tp,'|');
X c -= 128;
X }
X if (c<' ' && c!='\n' && c!='\t' && c!='\r') {
X echo(tp,'^');
X c += '@';
X } else if (c==127) {
X echo(tp,'^');
X c= '?';
X }
X }
X do_cooked(tp,(char) c,ECHO_OUT);
X}
X
X
X/*===========================================================================*
X * chuck *
X *===========================================================================*/
XPRIVATE unsigned chuck(tp)
Xregister tty_entry *tp; /* from which tty should chars be removed */
X{
X/* Delete one character from the input queue. Used for erase and kill.
X * Return 0xFFFF if there are no more chars to return
X * else return char in lower byte and its screen column in upper byte.
X */
X
X int prev;
X charpos val;
X
X /* If input queue is empty, don't delete anything. */
X if (bufempty(tp->tty_inbuf))
X return 0xFFFF;
X
X /* Don't delete '\n' or MARKER (eof). */
X prev = (tp->tty_inbuf.in ? tp->tty_inbuf.in-1 : bufsize(tp->tty_inbuf)-1);
X val= tp->tty_inbuf.b[prev];
X if (val.ch == '\n' || (val.ch== 0xFF && val.col== 0xFF))
X return 0xFFFF;
X
X /* char erasure was possible */
X tp->tty_inbuf.in = prev;
X tp->tty_inbuf.count--;
X return( (unsigned)val.ch | (((unsigned)val.col)<<8));
X}
X
X
X/*===========================================================================*
X * do_read *
X *===========================================================================*/
XPRIVATE void do_read(tp, m_ptr)
Xregister tty_entry *tp; /* pointer to tty struct */
Xmessage *m_ptr; /* pointer to message sent to the task */
X{
X/* A process wants to read from a terminal. */
X
Xphys_bytes phys_add;
Xextern phys_bytes umap();
X
X /* Perform Validity checks on the read request */
X
X /* Must have between 1 and MAXINT chars */
X if (m_ptr->COUNT & 0x8000 || m_ptr->COUNT == 0) {
X tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_BAD_ADDR);
X return;
X }
X
X /* Check the address given to see if it is valid */
X if ( (phys_add= umap(proc_addr(m_ptr->PROC_NR),D,(vir_bytes) m_ptr->ADDRESS
X ,(vir_bytes) m_ptr->COUNT)) == 0) {
X tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, E_BAD_ADDR);
X return;
X }
X
X /* if someone else is hanging, give up */
X if (tp->tty_inleft > 0) {
X tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_TRY_AGAIN);
X return;
X }
X
X /* Read is valid - Set up the read */
X
X /* Copy information from the message to the tty struct. */
X tp->tty_incaller = m_ptr->m_source;
X tp->tty_inproc = m_ptr->PROC_NR;
X tp->tty_inleft = m_ptr->COUNT;
X tp->tty_inoffset = phys_add & OFF_MASK;
X tp->tty_inseg = (phys_add >> 4) & WORD_MASK;
X tp->tty_incum = 0;
X
X /* Flush any chars in the output routine buffers */
X (*tp->tty_devflush)(tp);
X
X /* Try to get chars. This call either gets enough, or gets nothing. */
X tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, rd_chars(tp,0));
X}
X
X
X/*===========================================================================*
X * rd_chars *
X *===========================================================================*/
XPRIVATE int rd_chars(tp,force)
Xregister tty_entry *tp; /* pointer to terminal to read from */
Xint force; /* the user must accept as many chars as he can */
X{
X/* Try to send some data from the tty buffers to the user.
X * Returns SUSPEND if more chars have to be read to complete the
X * read request else returns the total number of chars transfered to the
X * user.
X */
X
X register buf_ct;
X unsigned char enough;
X bool cooked;
X charpos chp;
X
X if (bufempty(tp->tty_inbuf)) /* Only put chars if there are some */
X return(SUSPEND);
X
X cooked = !(tp->tty_mode & (RAW|CBREAK)); /* TRUE iff COOKED mode */
X
X if (!force && !tp->tty_lfct && cooked) /* Only transfer chars if */
X return(SUSPEND); /* read finishable or forced */
X
X /* We can try to complete this read request now */
X
X enough = 0;
X
X /* What is the maximum chars we can transfer at the moment */
X buf_ct = MIN(tp->tty_inleft, bufcount(tp->tty_inbuf));
X
X while(buf_ct--) {
X /* Get a char from the buffer */
X chp = getobj(tp->tty_inbuf);
X advgetobj(tp->tty_inbuf);
X /* Check for EOF or lf char */
X if (chp.ch == '\n' || (chp.ch==0xFF && chp.col==0xFF)) {
X tp->tty_lfct--;
X /* Finish looping if not nl in uncooked mode */
X if (cooked || chp.ch == 0xFF) {
X enough = chp.ch;
X buf_ct= 0;
X }
X }
X
X /* Send it if it isn't an EOF */
X if (enough != 0xFF) {
X put_byte(tp->tty_inseg,tp->tty_inoffset++,chp.ch);
X tp->tty_inleft--;
X tp->tty_incum++;
X }
X }
X
X /* Does that satisfy the read request ? */
X if (enough || !cooked || tp->tty_inleft==0) {
X tp->tty_inleft= 0; /* No more chars needed */
X return tp->tty_incum;
X }
X return(SUSPEND);
X}
X
X/*===========================================================================*
X * do_write *
X *===========================================================================*/
XPRIVATE void do_write(tp, m_ptr)
Xregister tty_entry *tp; /* pointer to tty struct */
Xmessage *m_ptr; /* pointer to message sent to the task */
X{
X/* A process wants to write on a terminal. */
X
X register struct writers *tpw;
X phys_bytes phys_add;
X int wr;
X extern phys_bytes umap();
X
X /* Check the address given to see if it is valid */
X if ( (phys_add= umap(proc_addr(m_ptr->PROC_NR),D,(vir_bytes) m_ptr->ADDRESS
X ,(vir_bytes) m_ptr->COUNT)) == 0) {
X tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, E_BAD_ADDR);
X return;
X }
X
X /* Check that we have room for more writers */
X if ( (wr=tp->tty_writers) >= MAX_WRITERS) {
X tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, E_TRY_AGAIN);
X return;
X }
X
X /* Copy message parameters to the tty structure. */
X tpw= &tp->w[tp->tty_writers++];
X tpw->otcaller = m_ptr->m_source;
X tpw->outproc = m_ptr->PROC_NR;
X tpw->offset = phys_add & OFF_MASK;
X tpw->seg = (phys_add >> 4) & WORD_MASK;
X tpw->outleft = m_ptr->COUNT;
X if (wr == 0) {
X tp->tty_state |= WAITING; /* a new writer always needs a reply */
X tp->tty_cum= 0;
X }
X
X /* O/S writes are already suspended waiting for reply, so don't
X * send message telling them to suspend.
X */
X if (tpw->outproc >= LOW_USER)
X tty_reply(TASK_REPLY,tpw->otcaller,tpw->outproc,SUSPEND);
X if (wr == 0) out_chars(tp);
X}
X
Xtypedef union {
X long l;
X struct {int i0, i1;} i;
X struct {char c0,c1,c2,c3;} c;
X } olong;
X
X/*===========================================================================*
X * do_ioctl *
X *===========================================================================*/
XPRIVATE void do_ioctl(tp, m_ptr)
Xregister tty_entry *tp; /* pointer to tty_struct */
Xmessage *m_ptr; /* pointer to message sent to task */
X{
X/* Perform IOCTL on this terminal.
X * The V1.3 ioctl was inconsistant in the way it got and put fields,
X * particularly with sg_i/ospeed. The new is consistant.
X * Programs that used the old ioctl will not work as the ioctl calls have
X * different values for TIOCSETP etc. The old calls will return EINVAL.
X * Any programs that set the number of bits in V1.3 will have to be
X * rewritten (not just recompiled) as those fields are being used for other
X * purposes and this function has been shifted to the TIOC(SET/GET)M call.
X */
X
X olong flags, erki;
X register r = m_ptr->TTY_REQUEST;
X int stat = OK;
X
X if (r&IOC_IN) {
X flags.l = m_ptr->TTY_FLAGS;
X erki.l = m_ptr->TTY_SPEK;
X switch(r) {
X case TIOCSETP: /* Set erase, kill, and flags. */
X case TIOCSETN:
X tp->tty_mode = flags.i.i0; /* 16 bit flags at present */
X /* Take care when setting speed fields */
X if (erki.c.c3)
X tp->tty_ospeed = erki.c.c3;
X if (erki.c.c2)
X tp->tty_ispeed = erki.c.c2;
X tp->tty_erase = erki.c.c1;
X tp->tty_kill = erki.c.c0;
X /* Any device dependant stuff */
X (*tp->tty_devioctl)(tp,m_ptr);
X break;
X
X case TIOCSETC: /* Set intr, quit, xon, xoff, eof (brk not used). */
X tp->tty_intr = erki.c.c3;
X tp->tty_quit = erki.c.c2;
X tp->tty_xon = erki.c.c1;
X tp->tty_xoff = erki.c.c0;
X tp->tty_eof = flags.c.c1;
X tp->tty_brk = flags.c.c0;
X break;
X
X case TIOCSETM: /* Set device dependant flags */
X tp->tty_ddmod = flags.i.i0;
X /* Any device dependant stuff */
X (*tp->tty_devioctl)(tp, m_ptr);
X break;
X
X case TIOCSTI: /* Simulate terminal input */
X erki.c.c0 = tp->tty_state & TRANSLATE; /* save trns flag */
X tp->tty_state &= ~TRANSLATE; /* turn off inp trns */
X in_char(tp, flags.c.c0); /* put char in the Q */
X tp->tty_state |= erki.c.c0; /* restore trns flag */
X break;
X
X case TIOCMODS: /* raw device hanles these */
X (*tp->tty_devioctl)(tp, m_ptr);
X break;
X
X default:
X stat = EINVAL;
X break;
X }
X }
X
X if (r&IOC_OUT) {
X flags.l = erki.l = 0;
X switch(r) {
X case TIOCGETP: /* Get erase, kill, and flags. */
X flags.i.i0 = tp->tty_mode;
X erki.c.c3 = tp->tty_ospeed;
X erki.c.c2 = tp->tty_ispeed;
X erki.c.c1 = tp->tty_erase;
X erki.c.c0 = tp->tty_kill;
X break;
X
X case TIOCGETC: /* Get intr, quit, xon, xoff, eof. */
X erki.c.c3 = tp->tty_intr;
X erki.c.c2 = tp->tty_quit;
X erki.c.c1 = tp->tty_xon;
X erki.c.c0 = tp->tty_xoff;
X flags.c.c1 = tp->tty_eof;
X flags.c.c0 = tp->tty_brk;
X break;
X
X case TIOCGETM: /* Set device dependant flags */
X flags.i.i0 = tp->tty_ddmod;
X break;
X
X case FIONREAD: /* Returns number of chars to read */
X flags.i.i0 = (unsigned) tp->tty_inbuf.count;
X break;
X
X case TIOCMODG: /* raw device handles these */
X (*tp->tty_devioctl)(tp, &m_ptr);
X flags.l = m_ptr->TTY_FLAGS;
X erki.l = m_ptr->TTY_SPEK;
X break;
X
X default:
X /* Check for device dependant handling */
X stat = EINVAL;
X break;
X }
X }
X
X if ((r&(IOC_IN|IOC_OUT)) == IOC_VOID)
X switch (r) {
X case TIOCSTOP: /* stop output, like ^S */
X tp->tty_state |= INHIBITED;
X break;
X
X case TIOCSTART: /* start output, like ^Q */
X tp->tty_state &= ~INHIBITED;
X out_chars(tp); /* restart output */
X break;
X
X case TIOCSBRK: /* the raw devices handle these */
X case TIOCCBRK:
X case TIOCSDTR:
X case TIOCCDTR:
X case TIOCSMLB:
X case TIOCCMLB:
X (*tp->tty_devioctl)(tp, m_ptr);
X break;
X
X default:
X stat = EINVAL;
X break;
X }
X
X /* Send a reply */
X tty_reply(TASK_REPLY,m_ptr->m_source, m_ptr->PROC_NR, stat, flags.l, erki.l);
X}
X
X
X/*===========================================================================*
X * do_cancel *
X *===========================================================================*/
XPRIVATE void do_cancel(tp, m_ptr)
Xregister tty_entry *tp; /* pointer to tty_struct */
Xmessage *m_ptr; /* pointer to message sent to task */
X{
X/* A signal has been sent to a process that is hanging trying to read or write.
X * The pending read or write must be finished off immediately.
X */
X register writer,reader;
X
X /* Find out if it is trying to write */
X
X for(writer=0; writer<tp->tty_writers ; writer++)
X if (m_ptr->PROC_NR == tp->w[writer].outproc) break;
X
X /* Find out if it is the current reader */
X reader= tp->tty_inproc==m_ptr->PROC_NR && tp->tty_inleft != 0;
X
X /* First check to see if the process is a reader or writer with an unfinished
X * request. If it is not, don't reply (to avoid race conditions).
X */
X if ( !reader && writer>=tp->tty_writers ) return;
X
X /* If it is a reader then ... */
X if (reader) {
X bufinit(tp->tty_inbuf); /* discard all input */
X tp->tty_inleft= 0;
X }
X
X /* If it the current writer then discard output & complete IO */
X if (writer == 0) {
X (*tp->tty_devclr)(tp); /* clear the output stream */
X tp->w[0].outleft = 0; /* simulate end of write */
X tp->tty_state &= ~WAITING; /* but don't reply. */
X tp->tty_state &= ~INHIBITED; /* do an implied ^Q */
X /* now send real reply */
X tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINTR);
X out_chars(tp); /* restart output */
X return;
X }
X /* If a writer, but not current then just dequeue it */
X if (writer < tp->tty_writers)
X for(tp->tty_writers-- ; writer < tp->tty_writers ; writer++)
X tp->w[writer]=tp->w[writer+1];
X
X /* send EINTR responce to writer */
X tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINTR);
X}
X
X
X/*===========================================================================*
X * out_chars *
X *===========================================================================*/
XPRIVATE void out_chars(tp)
Xregister tty_entry *tp;
X{
X/* Get chars from a process and insert into the cooked stream.
X * Also arrange for next writer when this one completes.
X */
X register i;
X
X /* Safety line: check that there are writers */
X if (tp->tty_writers == 0) return;
X /* While there are writers remaining ... */
X while(TRUE) {
X /* Try to send all the chars if the terminal is not inhibited */
X if (!(tp->tty_state&INHIBITED)) while(tp->w[0].outleft) {
X tp->w[0].outleft--;
X tp->tty_cum++;
X /* Stop when raw devices have enough chars - ^S processing
X * is in the low level output routines so the stop occurs
X * immediately and not when its buffer finally empties.
X */
X if (do_cooked(tp
X ,(char) get_byte(tp->w[0].seg,tp->w[0].offset++),WRITE_OUT))
X break;
X }
X
X /* Return if there is nothing more to do at present */
X if (tp->w[0].outleft) return;
X
X /* Write is finished. Flush output buffers. */
X (*tp->tty_devflush)(tp);
X
X /* Wake up this process */
X if (tp->tty_state & WAITING) /* send reply if needed */
X tty_reply(REVIVE,tp->w[0].otcaller,tp->w[0].outproc,tp->tty_cum);
X
X /* Start next writer (if any) */
X for(i=1; i < tp->tty_writers ; i++)
X tp->w[i-1]= tp->w[i];
X if (--tp->tty_writers == 0) {
X tp->tty_state &= ~WAITING; /* no more writers */
X return;
X }
X tp->tty_state |= WAITING; /* new writer wants reply */
X }
X}
X
X/*===========================================================================*
X * do_cooked *
X *===========================================================================*/
XPRIVATE bool do_cooked(tp,c,prio)
Xregister tty_entry *tp;
Xchar c;
X{
X/* Process a char according to COOKED flags etc.
X * prio = ECHO_OUT for non stopable stream & WRITE_OUT for normal IO.
X * Returns status as given by the low level routine.
X */
Xregister val;
X
X /* Maintain some estimation of the current column (for XTAB,CTLECH etc).
X * Do XTAB, CRMOD, LCASE output processing (if not in RAW mode).
X * The current column must be estimated even in RAW mode as the console
X * uses this estimation to calculate real locations.
X * Set a special flag so the console can tell when to do backspace wrap.
X */
X if (c < ' ')
X switch(c) {
X case '\t': /* TAB - do XTAB processing */
X if ((tp->tty_mode&(XTABS|RAW))==XTABS) {
X do {
X val= do_cooked(tp,' ',prio);
X } while (tp->tty_column & (TAB_SIZE-1));
X return val;
X }
X /* Assume the terminal does tabs of TAB_SIZE */
X tp->tty_column = (tp->tty_column + TAB_SIZE) & ~(TAB_SIZE-1);
X break;
X case '\n': /* LINEFEED - do CRMOD processing */
X if ((tp->tty_mode&(CRMOD|RAW))==CRMOD)
X do_cooked(tp,'\r',prio);
X break;
X case '\r': /* CR - set column = 0 */
X tp->tty_column = 0;
X break;
X case '\b': /* BS - decr column if valid, check BS wrap */
X if (tp->tty_column) tp->tty_column--;
X else tp->tty_state |= BS_WRAP;
X break;
X }
X else { /* Normal char (incr column) */
X tp->tty_column++;
X /* LCASE processing */
X if ((tp->tty_mode&(LCASE|RAW))==LCASE && c >= 'a' && c <= 'z')
X c -= 'a' - 'A';
X }
X
X /* Now do raw device output */
X return (*tp->tty_devraw)(tp,c,prio);
X}
X
X/*===========================================================================*
X * tty_reply *
X *===========================================================================*/
XPRIVATE void tty_reply(code, replyee, proc_nr, status, extra, other)
Xint code; /* TASK_REPLY or REVIVE */
Xint replyee; /* destination address for the reply */
Xint proc_nr; /* to whom should the reply go? */
Xint status; /* reply code */
Xlong extra; /* extra value */
Xlong other; /* used for IOCTL replies */
X{
X/* Send a reply to a process that wanted to read or write data. */
X
X message tty_mess;
X
X tty_mess.m_type = code;
X tty_mess.REP_PROC_NR = proc_nr;
X tty_mess.REP_STATUS = status;
X tty_mess.TTY_FLAGS = extra; /* used by IOCTL for flags (mode) */
X tty_mess.TTY_SPEK = other; /* used by IOCTL for erase and kill chars */
X send(replyee, &tty_mess);
X}
X
X
X/*===========================================================================*
X * do_nothing *
X *===========================================================================*/
XPUBLIC void do_nothing()
X{
X}
X
X
X/*===========================================================================*
X * putc *
X *===========================================================================*/
XPUBLIC void putc(c)
Xchar c; /* character to print */
X{
X/* This procedure is used by the version of printf() that is linked with
X * the kernel itself. The one in the library sends a message to FS, which is
X * not what is needed for printing within the kernel. This version just queues
X * the character and starts the output.
X */
X
X do_cooked(&tty_struct[0], c, WRITE_OUT);
X}
X
X/*===========================================================================*
X * do_setpgrp *
X *===========================================================================*/
XPRIVATE void do_setpgrp(tp, m_ptr)
Xregister tty_entry *tp; /* pointer to tty struct */
Xmessage *m_ptr; /* pointer to message sent to task */
X{
X/* A control process group has changed.
X * At the moment this is really a slot number not a process number */
X
X tp->tty_pgrp = m_ptr->TTY_PGRP;
X tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK);
X}
*-*-END-of-tty1.c-*-*
exitmarks@elec.uq.oz (Mark Schulz) (09/22/88)
echo x - tty2.c
sed 's/^X//' >tty2.c <<'*-*-END-of-tty2.c-*-*'
X/* tty2.c - device dependant code for console tty driver (IBM-PC)
X *
X * Written by: A.Hannam (Feb 1988)
X *
X * Modifications:
X * 28/8/88 - Modified for MINIX V1.3 on IBM-PC
X * Added scan-code translation & macro sequences
X * 5/9/88 - Added a significant portion of ANSI sequences
X * Fixed EGA code
X */
X
X#include "../h/const.h"
X#include "../h/sgtty.h"
X#include "../h/type.h"
X#include "../h/signal.h"
X#include "../h/com.h"
X#include "const.h"
X
X#ifdef HIGH_LEVEL
X#undef HIGH_LEVEL
X#endif
X
X#include "tty.h"
X
X/* Now begins the code and data for the device-dependent tty drivers. */
X
X/*****************************************************************************/
X/******************************* CONSOLE DRIVER ******************************/
X/*****************************************************************************/
X
XPUBLIC int scan_code; /* scancode for '=' to test if olivetti */
XPUBLIC int color; /* 1 if console is color, 0 if it is mono */
XPUBLIC int vid_mask; /* 037777 for color (16K) or 07777 for mono */
XPUBLIC int vid_retrace; /* how many words to display per burst */
XPUBLIC unsigned vid_base; /* base of video ram (0xB000 or 0xB800) */
X
XPUBLIC void int_con(), init_con();
X
Xextern int pc_at;
Xextern int lock();
Xextern void do_nothing(), sigchar(), reboot(), wreboot(), restore()
X , vid_write(), vid_fill(), vid_fmove(), vid_bmove();
X
XPRIVATE bool rout_con();
XPRIVATE unsigned trans_con();
XPRIVATE void ofl_con(), scroll_screen(), move_to(), do_escape()
X , set_6845(), beep_on(), dset_con(), parse_escape(), set_leds()
X , beep_off(), check_reboot();
X
X
X/* Definitions used by the console driver. */
X#define COLOR_BASE 0xB800 /* video ram paragraph for color display */
X#define MONO_BASE 0xB000 /* video ram address for mono display */
X#define C_VID_MASK 0x3FFF /* mask for 16K video RAM */
X#define M_VID_MASK 0x0FFF /* mask for 4K video RAM */
X#define C_RETRACE 0x0180 /* maximum words to display at once (cga) */
X#define M_RETRACE 0x7FFF /* maximum words to display at once (mono) */
X#define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */
X#define B_TIME 3 /* length of CTRL-G beep in ticks */
X#define BLANK 0x0700 /* default blank color */
X#define GO_FORWARD 0 /* scroll forward */
X#define GO_BACKWARD 1 /* scroll backward */
X#define TIMER2 0x42 /* I/O port for timer channel 2 */
X#define TIMER3 0x43 /* I/O port for timer channel 3 */
X#define KEYBD 0x60 /* I/O port for keyboard data */
X#define PORT_B 0x61 /* I/O port for 8255 port B */
X#define KBIT 0x80 /* bit used to ack characters to keyboard */
X#define LED_CODE 0xED /* command to keyboard to set LEDs */
X#define LED_DELAY 0x80 /* device dependent delay needed */
X#define MAX_ESC_PARMS 2 /* no. of escape sequence parameters allowed */
X#define FAST_BAUD B115200 /* console looks like a term at this speed */
X#define BEEPING DD_FLAG1 /* flag in tty struct when console beeping */
X#define REBOOT DD_FLAG2 /* flag in tty struct when about to reboot */
X
X#define LINE_WIDTH 80 /* # characters on a line */
X#define SCR_LINES 25 /* # lines on the screen */
X
X#define ESC 033 /* ESC for use in ansi term sequences */
X#define XOFF_CHAR 0x13 /* xoff char that these routines can decode */
X
X#define OLIVETTI_EQUAL 12 /* scan code for '=' on olivetti (13 on IBM) */
X#define CTRL_S 31 /* scan code for letter S (for CRTL-S) */
X#define DEL_CODE 83 /* code for DEL for in CTRL-ALT-DEL reboot */
X#define FUNC_KEY 58 /* codes above this belong to function keys */
X#define F10 68 /* scan code for function key F10 */
X#define TOP_ROW 14 /* codes below this are shifted if CTRL */
X#define NUM_PAD 70 /* codes above this belong to the number pad */
X#define NUM_PGDN 81 /* code for pgdn key on number pad */
X
X/* Constants relating to the video RAM and 6845. */
X#define M_6845 0x3B0 /* port for 6845 mono */
X#define C_6845 0x3D0 /* port for 6845 color */
X#define EGA 0x3C0 /* port for EGA card */
X#define INDEX 4 /* 6845's index register */
X#define DATA 5 /* 6845's data register */
X#define CUR_SIZE 10 /* 6845's cursor size register */
X#define VID_ORG 12 /* 6845's origin register */
X#define CURSOR 14 /* 6845's cursor register */
X
X/* Global variables used by the console driver. */
XPRIVATE message c_mess; /* message used for console input chars */
X
XPRIVATE bool shift1, shift2; /* keep track of key statii */
XPRIVATE bool capslock, numlock;
XPRIVATE bool control, alt;
X
XPRIVATE char c_estate; /* 0=normal, 1=ESC, 2=ESC[ etc */
XPRIVATE int c_enum[MAX_ESC_PARMS]; /* list of escape parameters */
XPRIVATE int * c_p_enum; /* pointer to current escape param */
XPRIVATE int c_row; /* the current row for the console */
XPRIVATE int c_attr; /* the current character atrribute */
XPRIVATE unsigned c_blank; /* blanking character and attribute */
XPRIVATE int c_org; /* origin of the screen in video ram */
XPRIVATE int c_vid; /* current cursor pos in video ram */
XPRIVATE int c_port; /* I/O port for accessing 6845 */
XPRIVATE char * c_key_sh; /* translation tables - shifted keys */
XPRIVATE char * c_key_ush; /* - unshifted keys */
XPRIVATE char c_s_col; /* saved cursor column */
XPRIVATE char c_s_row; /* saved cursor row */
X
X/* Scan codes to ASCII for unshifted keys */
XPRIVATE char unsh[] = {
X 0,ESC,'1','2','3','4','5','6','7','8','9','0','-','=','\b','\t',
X 'q','w','e','r','t','y','u','i','o','p','[',']',015,0202,'a','s',
X 'd','f','g','h','j','k','l',';',047,0140,0200,0134,'z','x','c','v',
X 'b','n','m',',','.','/',0201,'*',0203,' ',0204,0241,0242,0243,0244,0245,
X 0246,0247,0250,0251,0252,0205,0210,0267,0270,0271,0211,0264,0265,0266,0214,
X 0261,0262,0263,0260,0177
X};
X
X/* Scan codes to ASCII for shifted keys */
XPRIVATE char sh[] = {
X 0,ESC,'!','@','#','$','%','^','&','*','(',')','_','+','\b','\t',
X 'Q','W','E','R','T','Y','U','I','O','P','{','}',015,0202,'A','S',
X 'D','F','G','H','J','K','L',':',042,'~',0200,'|','Z','X','C','V',
X 'B','N','M','<','>','?',0201,'*',0203,' ',0204,0221,0222,0223,0224,0225,
X 0226,0227,0230,0231,0232,0204,0213,'7','8','9','-','4','5','6','+','1',
X '2','3','0','.'
X};
X
X/* Scan codes to ASCII for Olivetti M24 for unshifted keys. */
XPRIVATE char unm24[] = {
X 0,ESC,'1','2','3','4','5','6','7','8','9','0','-','^','\b','\t',
X 'q','w','e','r','t','y','u','i','o','p','@','[','\r',0202,'a','s',
X 'd','f','g','h','j','k','l',';',':',']',0200,'\\','z','x','c','v',
X 'b','n','m',',','.','/',0201,'*',0203,' ',0204,0241,0242,0243,0244,0245,
X 0246,0247,0250,0251,0252,023,0210,0267,0270,0271,0211,0264,0265,0266,0214,0261,
X 0262,0263,0207,0177,0271,014,0212,'\r',0264,0262,0266,0270,032,0213,0274,'/',
X 0253,0254,0255,0256,0257,0215,0216,0217
X};
X
X/* Scan codes to ASCII for Olivetti M24 for shifted keys. */
XPRIVATE char m24[] = {
X 0,ESC,'!','"','#','$','%','&',047,'(',')','_','=','~','\b','\t',
X 'Q','W','E','R' ,'T','Y','U','I','O','P',0140,'{','\r',0202,'A','S',
X 'D','F','G','H','J','K','L','+','*','}',0200,'|','Z','X','C','V',
X 'B','N','M','<','>','?',0201,'*',0203,' ',0204,0221,0222,0223,0224,0225,
X 0226,0227,0230,0231,0232,0270,023,'7','8','9',0211,'4','5','6',0214,'1',
X '2','3','0','.',' ',014,0272,'\r','\b','\n','\f',036,032,0273,' ','/',
X 0233,0234,0235,0236,0237,0275,0276,0277
X};
X
XPRIVATE char *fn_macros[4][10]= {
X { /* no shift, control or alt - ANSI Fn Keys */
X "\033OS","\033OT","\033OU","\033OV","\033OW",
X "\033OP","\033OQ","\033OR","\033OX","\033OY"
X },{ /* shift, no control or alt - (empty) */
X 0,0,0,0,0,0,0,0,0,0
X },{ /* control, no shift or alt - (empty) */
X 0,0,0,0,0,0,0,0,0,0
X },{ /* control & shift, no alt - (empty) */
X 0,0,0,0,0,0,0,0,0,0
X}};
X
XPRIVATE char *fn_a_macros[2][10]= {
X { /* alt, no shift or control - Useful Strings */
X "ls -al ","ls -al\n","mount /dev/","umount /dev/",
X "dosdir -l ","dosdir -l 1\n","doswrite -a 1 ","doswrite 1 ",
X "dosread -a 1 ","dosread 1 "
X },{ /* alt & shift, no control - Useful Strings */
X 0,0,0,0,0,0,0,0,0,"\nexit\n"
X}};
X
XPRIVATE char *arrow_macros[]= {
X "[H","[A","[V","[S","[D","[G","[C","[T","[Y","[B","[U"
X };
X
XPRIVATE charfbuf con_inbuf;
X
X#define CONS_RAM_WORDS 256
XPRIVATE int cons_ramqueue[CONS_RAM_WORDS];
XPRIVATE int cons_rwords;
X
X/*===========================================================================*
X * init_con *
X *===========================================================================*/
XPUBLIC void init_con(tp)
Xregister tty_entry *tp;
X{
X
X c_mess.TTY_LINE= CON1; /* The interrupt message */
X c_mess.m_type= TTY_CHAR_INT; /* Could have been TTY_O_DONE */
X
X /* Tell the EGA card, if any, to simulate a 16K CGA card. */
X port_out(EGA + INDEX, 4); /* register select */
X port_out(EGA + DATA, 1); /* no extended memory to be used */
X
X
X tp->tty_devraw= rout_con;
X tp->tty_devclr= ofl_con;
X tp->tty_devflush= ofl_con;
X tp->tty_devioctl= dset_con;
X tp->tty_devtrans= trans_con;
X tp->tty_devempty= check_reboot;
X
X /* console requires translation and always gives 8 bits */
X tp->tty_state |= TRANSLATE|COK8BIT;
X tp->tty_ddmod |= CON_COOK8|CON_WRAP|D_CONSOLE;
X tp->tty_ispeed= tp->tty_ospeed = FAST_BAUD;
X
X tp->tty_fbuf = &con_inbuf;
X fbufinit(con_inbuf);
X
X /* Set parameters based on this particular machine */
X if (color&1) { /* What mode is the console in ? */
X vid_base = COLOR_BASE;
X vid_mask = C_VID_MASK;
X c_port = C_6845;
X vid_retrace = C_RETRACE;
X } else {
X vid_base = MONO_BASE;
X vid_mask = M_VID_MASK;
X c_port = M_6845;
X vid_retrace = M_RETRACE;
X }
X if (scan_code == OLIVETTI_EQUAL) {
X c_key_sh= m24;
X c_key_ush= unm24;
X } else {
X c_key_sh= sh;
X c_key_ush = unsh;
X }
X
X c_blank = c_attr = BLANK; /* attribute byte for screen */
X cons_rwords = 0; /* initialize buffer */
X c_estate = 0; /* ESC state is 0 */
X c_s_col = c_s_row = 0; /* The saved cursor pos is home */
X set_6845(CUR_SIZE, 23); /* set cursor shape (old = 31) */
X set_6845(VID_ORG, c_org = 0); /* use page 0 of video ram */
X move_to(0,SCR_LINES-1); /* move cursor to bottom left corner */
X}
X
X
X/*===========================================================================*
X * int_con *
X *===========================================================================*/
XPUBLIC void int_con()
X{
X/* A keyboard interrupt has occurred. Process it. (Interrupts are off) */
X
X int val, c;
X
X /* Fetch the character from the keyboard hardware and acknowledge it. */
X port_in(KEYBD, &c); /* get the scan code for the key struck */
X port_in(PORT_B, &val); /* strobe the keyboard to ack the char */
X port_out(PORT_B, val | KBIT); /* strobe the bit high */
X port_out(PORT_B, val); /* now strobe it low */
X
X /* If Keyboard Locked then discard char */
X if (tty_struct[CON1].tty_ddmod&CON_LOCK) {
X port_out(INT_CTL, ENABLE);
X return;
X }
X
X /* The IBM keyboard interrupts twice per key, once when depressed, once when
X * released. Filter out the latter, ignoring all but the shift-type keys.
X * The shift-type keys, 29, 42, 54, 56, 58, and 69 must be processed normally.
X */
X if (c > 0200)
X switch(c) {
X case 29 + 0200: case 42 + 0200:
X case 54 + 0200: case 56 + 0200:
X case 58 + 0200: case 69 + 0200:
X break;
X default: /* re-enable interrupts */
X port_out(INT_CTL, ENABLE);
X return; /* don't call tty_task() */
X }
X
X /* Check for CTRL-ALT-DEL, and if found set a flag. */
X if (control && alt && c == DEL_CODE)
X tty_struct[CON1].tty_state |= REBOOT;
X
X/* Check to see if character is CTRL-S, to stop output. Setting xoff
X * to anything other than CTRL-S will not be detected here, but will
X * be detected later, in the driver. A general routine to detect any
X * xoff character here would be complicated since we only have the
X * scan code here, not the ASCII character. This is just done to
X * improve responce.
X */
X if ( !(tty_struct[CON1].tty_mode & RAW)
X && tty_struct[CON1].tty_xoff == XOFF_CHAR
X && control && c == CTRL_S ) {
X tty_struct[CON1].tty_state |= INHIBITED;
X port_out(INT_CTL, ENABLE);
X return;
X }
X
X
X /* Store the character in memory so the task can get at it later. */
X if ( bufnfull(con_inbuf) ) {
X putfobj(con_inbuf,c); /* Enough room so store the char */
X }
X
X /* Inform other routines that we have chars available */
X tty_struct[CON1].tty_state |= IN_FLUSH;
X flush_flag |= IN_FLUSH;
X
X /* Build and send the int message to tty task only if absolutly necessary */
X if (bufcount(con_inbuf) >= CHAR_BUF_THRESHOLD) {
X interrupt(TTY, &c_mess);
X }
X
X port_out(INT_CTL, ENABLE); /* re-enable 8259A controller */
X}
X
X/*===========================================================================*
X * dset_con *
X *===========================================================================*/
XPRIVATE void dset_con(tp, m)
Xregister tty_entry *tp;
Xregister message *m;
X{
X switch (m->TTY_REQUEST) {
X case TIOCSETN:
X case TIOCSETP:
X /* Console baud rate is always fast */
X tp->tty_ispeed= tp->tty_ospeed= FAST_BAUD;
X break;
X
X case TIOCSETM:
X /* Ensure modes are valid - if something looks
X * suspicious then don't allow keyboard lock.
X */
X if (!(tp->tty_ddmod & D_CONSOLE))
X tp->tty_ddmod &= ~CON_LOCK;
X tp->tty_ddmod &= (CON_COOK8|CON_LOCK|CON_WRAP|CON_INSERT);
X tp->tty_ddmod |= D_CONSOLE;
X /* Process the device dependant modes */
X if (tp->tty_ddmod & CON_COOK8)
X tp->tty_state |= COK8BIT;
X else
X tp->tty_state &= ~COK8BIT;
X break;
X
X case TIOCMODG:
X /* This looks like an operating terminal */
X m->TTY_FLAGS = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS
X |TIOCM_CAR|TIOCM_DSR;
X m->TTY_SPEK = 0;
X break;
X
X /* Ignore all other ioctl calls */
X }
X}
X
X
X/*===========================================================================*
X * rout_con *
X *===========================================================================*/
XPRIVATE bool rout_con(tp, c, prio)
Xregister tty_entry *tp; /* pointer to tty struct */
Xchar c; /* character to be output */
X{
X/* Output a character on the console. Priority order is ...
X * Handle control codes,
X * Handle escape sequences
X * Handle normal chars
X *
X * This allows control code processing to occur without disturbing
X * escape sequences.
X */
X
X if (c < ' ') switch(c) { /* Handle control codes */
X
X /* Cancel a escape sequence and beep */
X case 0x18: /* CAN & SUB */
X case 0x1A:
X if (!c_estate) break;
X c_estate = 0;
X
X /* ring the bell */
X case 007: /* BEL */
X ofl_con();
X beep_on(BEEP_FREQ,B_TIME);
X break;
X
X /* BackSpace - with EOL wrap - (left) */
X case '\b': /* BS */
X if (tp->tty_state & BS_WRAP) {
X tp->tty_state &= ~BS_WRAP;
X if (c_row != 0 && tp->tty_ddmod&CON_WRAP) {
X c_row--;
X tp->tty_column= LINE_WIDTH - 1;
X }
X }
X move_to(tp->tty_column, c_row);
X break;
X
X /* Tab Handling - don't bother clearing space */
X case '\t': /* HT */
X move_to(tp->tty_column, c_row);
X break;
X
X /* line feed (down) */
X case '\n': /* NL */
X if (c_row >= SCR_LINES-1)
X scroll_screen(GO_FORWARD);
X else
X c_row++;
X move_to(tp->tty_column, c_row);
X break;
X
X /* vertical tab - (up) */
X case 0x0B: /* VT */
X c_row--;
X move_to(tp->tty_column, c_row);
X break;
X
X /* form feed - (right) */
X case 0x0C: /* FF */
X move_to(tp->tty_column+1, c_row);
X break;
X
X /* carriage return */
X case '\r': /* CR */
X move_to(0, c_row);
X break;
X
X /* ESC - start of an escape sequence */
X case ESC: /* ESC */
X c_estate = 0;
X parse_escape(c);
X break;
X
X /* All other control codes are ignored */
X
X } else if (c_estate != 0) { /* Handle Escape Sequences */
X parse_escape(c);
X } else { /* Normal Chars */
X /* printable chars are stored in outqueue */
X /* They are being used as words (not bytes) */
X if (cons_rwords >= CONS_RAM_WORDS) ofl_con();
X
X if (tp->tty_column < LINE_WIDTH)
X cons_ramqueue[cons_rwords++] = c_attr | (unsigned)c;
X else if (tp->tty_ddmod&CON_WRAP) { /* Long Lines */
X cons_ramqueue[cons_rwords++] = c_attr | (unsigned)c;
X move_to(0, c_row); /* Implied \r */
X rout_con(tp,'\n',prio); /* Implied \n */
X }
X }
X
X /* Handle ^S processing and ECHO_OUT priority */
X if (tp->tty_state&INHIBITED || prio==ECHO_OUT) ofl_con();
X return (tp->tty_state&INHIBITED);
X}
X
X/*===========================================================================*
X * scroll_screen *
X *===========================================================================*/
XPRIVATE void scroll_screen(dir)
Xint dir; /* GO_FORWARD or GO_BACKWARD */
X{
X register offset;
X
X /* Hardware Scrolling. It is up to the video routines to ensure the screen is
X * written in such a way that scrolling over the ram boundary works on
X * both CGA,MONO (which support ram wrap) and EGA (which may not support
X * ram wrap).
X */
X ofl_con(); /* Flush the output stream */
X if (dir == GO_FORWARD) { /* Calculate the new video origin */
X c_org += 2 * LINE_WIDTH;
X c_org &= vid_mask;
X offset = c_org + 2*(SCR_LINES-1)*LINE_WIDTH;
X } else {
X c_org -= 2 * LINE_WIDTH;
X c_org &= vid_mask;
X offset = c_org;
X }
X
X /* Blank the new line at top or bottom. */
X vid_fill(c_blank, offset, LINE_WIDTH);
X set_6845(VID_ORG, c_org >> 1); /* 6845 thinks in words */
X}
X
X/*===========================================================================*
X * ofl_con *
X *===========================================================================*/
XPRIVATE void ofl_con()
X{
X/* Have the characters in 'outqueue' transferred to the screen. */
Xregister unsigned i;
X
X if (cons_rwords == 0) return;
X
X /* Do insert mode processing */
X if (tty_struct[CON1].tty_ddmod&CON_INSERT) {
X i = c_org + c_row*2*LINE_WIDTH + (2*LINE_WIDTH-2); /* end of line */
X vid_bmove(i - cons_rwords*2, i
X , LINE_WIDTH - MIN(tty_struct[CON1].tty_column,LINE_WIDTH));
X }
X
X /* Write the chars to the screen */
X vid_write(cons_ramqueue, c_vid, cons_rwords);
X
X /* Update the video parameters and cursor. */
X c_vid += 2*cons_rwords;
X set_6845(CURSOR, c_vid >> 1); /* cursor counts in words */
X cons_rwords = 0;
X}
X
X
X/*===========================================================================*
X * move_to *
X *===========================================================================*/
XPRIVATE void move_to(x, y)
Xint x; /* column (0 <= x <= 79) */
Xint y; /* c_row (0 <= y <= 24, 0 at top) */
X{
X/* Move the cursor to (x, y). */
X
X ofl_con(); /* flush any pending characters */
X x = between(0, x, LINE_WIDTH-1); /* ensure x & y are valid */
X y = between(0, y, SCR_LINES -1);
X tty_struct[CON1].tty_column = x; /* set x co-ordinate */
X c_row = y; /* set y co-ordinate */
X c_vid = c_org + y*2*LINE_WIDTH + 2*x;
X set_6845(CURSOR, c_vid >> 1); /* cursor counts in words */
X}
X
X/*===========================================================================*
X * set_6845 *
X *===========================================================================*/
XPRIVATE void set_6845(reg, val)
Xregister reg; /* which register pair to set */
Xregister val; /* 16-bit value to set it to */
X{
X/* Set a register pair inside the 6845.
X * Registers 10-11 control the format of the cursor (how high it is, etc).
X * Registers 12-13 tell the 6845 where in video ram to start (in WORDS)
X * Registers 14-15 tell the 6845 where to put the cursor (in WORDS)
X *
X * Note that registers 12-15 work in words, i.e. 0x0000 is the top left
X * character, but 0x0001 (not 0x0002) is the next character. This addressing
X * is different from the way the 8088 addresses the video ram, where 0x0002
X * is the address of the next character.
X */
X port_out(c_port + INDEX, reg); /* set the index register */
X port_out(c_port + DATA, (val>>8) & BYTE); /* output high byte */
X port_out(c_port + INDEX, reg + 1); /* again */
X port_out(c_port + DATA, val&BYTE); /* output low byte */
X}
X
X
X/*===========================================================================*
X * beep_on *
X *===========================================================================*/
XPRIVATE void beep_on(f,d)
Xregister f; /* this value determines beep frequency */
Xregister d; /* this value is the time to sound in ticks */
X{
X/* Making a beeping sound on the speaker (output for CRTL-G). This routine
X * works by turning on the bits in port B of the 8255 chip that drive the
X * speaker and sending a clock message to time the beep.
X */
X int x, s;
X message m;
X
X if (tty_struct[CON1].tty_state & BEEPING) return;
X s = lock(); /* disable interrupts */
X port_out(TIMER3,0xB6); /* set up timer channel 2 mode */
X port_out(TIMER2, f&BYTE); /* load low-order bits of frequency in timer */
X port_out(TIMER2,(f>>8)&BYTE); /* now high-order bits of frequency in timer */
X port_in(PORT_B,&x); /* acquire status of port B */
X port_out(PORT_B, x|3); /* turn bits 0 and 1 on to beep */
X tty_struct[CON1].tty_state |= BEEPING;
X restore(s); /* re-enable interrupts */
X
X m.m_type = SET_ALARM; /* set up the duration */
X m.CLOCK_PROC_NR = TTY;
X m.DELTA_TICKS = d; /* beep for d ticks */
X m.FUNC_TO_CALL = (int (*)()) beep_off; /* func to switch off beep */
X sendrec(CLOCK, &m);
X}
X
X/*===========================================================================*
X * beep_off *
X *===========================================================================*/
XPRIVATE void beep_off()
X{
X/* Turn off the beep on the speaker (output for CRTL-G). This routine
X * is called only by the CLOCK task.
X */
Xint s,x;
X
X s = lock(); /* disable interrupts */
X port_in(PORT_B, &x); /* get status of port B */
X port_out(PORT_B, x & 0xFFFC); /* turn bits 0 and 1 off to stop beep */
X tty_struct[CON1].tty_state &= ~BEEPING;
X restore(s); /* restore interrupts */
X}
X
X
X/*===========================================================================*
X * func_key *
X *===========================================================================*/
XPRIVATE func_key(ch)
Xchar ch; /* scan code for a function key */
X{
X/* This procedure traps function keys for debugging purposes. When MINIX is
X * fully debugged, it should be removed.
X */
X
X switch (ch) {
X
X case FUNC_KEY+1: /* print process table */
X p_dmp();
X break;
X
X case FUNC_KEY+2: /* print memory map */
X map_dmp();
X break;
X
X case FUNC_KEY+3: /* Switch between EGA (with no */
X color ^= 2; /* retrace checking) and CGA/MONO. */
X printf("\n\rVideo Card = %s\n\r"
X ,(color&2 ? "EGA": (color&1 ? "CGA":"MONO")));
X break; /* This is useful to control the */
X /* scrolling speed of EGA cards. */
X
X#ifdef AM_KERNEL
X#ifndef NONET
X case FUNC_KEY+4: /* re-initialise the ethernet card */
X net_init();
X break;
X#endif NONET
X#endif AM_KERNEL
X
X case FUNC_KEY+9: /* kill all process */
X sigchar(&tty_struct[CON1], SIGKILL);
X break;
X }
X}
X
X/*===========================================================================*
X * trans_con *
X *===========================================================================*/
XPRIVATE unsigned trans_con(c)
Xunsigned c; /* scan code of key just struck or released */
X{
X/* This routine handles the console keyboard scan-code to ascii conversion.
X * It has some ANSI sequences and various macros hardwired to certain keys.
X * E.g. Arrow keys and Function Keys. At the moment there is no way to
X * change the macros at run-time but lator the console output routines
X * may define ANSI sequences to do this.
X * This is a general translation routine with no hardware dependancies
X * except for keyboard leds (on an AT).
X * Note: The type of scan-code translation (Olivetti or IBM) is determined
X * during initialization (not here).
X */
X
X unsigned char code;
X bool make;
X static char *seq_str= "";
X
X /* Do Macro Key Sequences (including ANSI keys) */
X switch (c>>8) {
X case 0: /* Non Macro Key */
X break;
X case 1: /* Macro String */
X if (*seq_str)
X return *seq_str++ | 0x100;
X return MARKER;
X default: /* Unknown - ignore */
X return MARKER;
X }
X
X /* Start a Arrow Key ANSI macro */
X if (c > NUM_PAD && c <= NUM_PGDN && !((shift1|shift2)^numlock)) {
X seq_str= arrow_macros[c - (NUM_PAD+1)];
X return ESC | 0x100; /* Send the escape */
X }
X
X /* Start a Funtion Key macro */
X if(c > FUNC_KEY && c <= F10) {
X if (control && alt) { /* Special CONSOLE DEBUG routines */
X func_key(c);
X return MARKER;
X }
X
X /* Handle other combinations of shift, control & alt */
X /* There is no possiblility of control when alt is on */
X seq_str= (alt ? fn_a_macros[shift1|shift2]
X : fn_macros[shift1|shift2|(control<<1)]) [c - (FUNC_KEY+1)];
X if (*seq_str)
X return *seq_str++ | 0x100;
X return MARKER;
X }
X
X make = !(c & 0200); /* 1 when key depressed, 0 when key released */
X c &= 0177; /* high-order bit set on key release */
X
X /* Standard IBM keyboard. Do shift processing */
X code = ((shift1 | shift2)^ (
X /* Check capslock for alpha */
X (capslock && c_key_ush[c] >= 'a' && c_key_ush[c] <= 'z') ||
X /* Check numlock for number pad */
X (c > NUM_PAD && numlock) ))
X ? c_key_sh[c] : c_key_ush[c];
X if (control && c < TOP_ROW) code = c_key_sh[c]; /* CTRL-(top row) */
X
X /* Process ordinary keys, i.e. not shift, control, alt, etc. */
X if (code < 0200 || code > 0205) {
X if (!make) return MARKER; /* key release */
X if (control) code &= 037;
X if (alt) code |= 0200; /* alt key ORs 0200 into code */
X return code;
X }
X
X /* Table entries 0200 - 0205 denote special actions. */
X switch(code - 0200) {
X case 0: shift1 = make; break; /* shift key on left */
X case 1: shift2 = make; break; /* shift key on right*/
X case 2: control = make; break; /* control */
X case 3: alt = make; break; /* alt key */
X case 4: if (make) capslock = 1-capslock;
X set_leds(); break; /* caps lock */
X case 5: if (make) numlock = 1-numlock;
X set_leds(); break; /* num lock */
X }
X return MARKER; /* No high level processing to do */
X}
X
X/*===========================================================================*
X * escape *
X *===========================================================================*/
XPRIVATE void parse_escape(c)
Xchar c; /* next character in escape sequence */
X{
X/* Parse and build an escape sequence.
X * Formats understood ...
X *
X * ESC char : state = 0x01
X * ESC '[' [num] char : state = 0x02
X *
X * where num is from 1 to MAX_ESC_PARMS decimal strings seperated by ';'s.
X * more than MAX_ESC_PARMS decimal strings are ignored.
X */
Xregister i;
X
X /* This char is not printable but the column has been incremented */
X /* fix this by decrementing it */
X tty_struct[CON1].tty_column--;
X
X if (c_estate == 0) { /* ESC seen - initialize sequence */
X c_estate = 1;
X c_p_enum = c_enum;
X for(i=0; i<MAX_ESC_PARMS ; i++)
X c_enum[i] = 0;
X return;
X }
X
X if (c_estate == 2) { /* Only allow numbers in "ESC [" seq */
X if (c >= '0' && c <= '9') {
X if (c_p_enum < &c_enum[MAX_ESC_PARMS])
X *c_p_enum = *c_p_enum * 10 + (c - '0');
X return;
X }
X /* Start a new number in sequence */
X if (c == ';') {
X if (c_p_enum < &c_enum[MAX_ESC_PARMS])
X c_p_enum++;
X return;
X }
X }
X
X /* A char has arrived - process it */
X switch (c_estate) {
X case 0x01: /* "ESC char" sequence */
X if (c == '[') { /* "ESC '['" sequence is starting */
X c_estate = 0x02;
X return;
X }
X break;
X
X case 0x02: /* "ESC '[' [num] char" sequence */
X break;
X
X default: /* illegal state */
X c_estate = 0;
X return;
X }
X
X /* A syntacticly valid ESC sequence has arrived - process it */
X do_escape(c);
X c_estate = 0; /* The sequence is finished */
X}
X
X
X/*===========================================================================*
X * do_escape *
X *===========================================================================*/
XPRIVATE void do_escape(c)
Xchar c; /* next character in escape sequence */
X{
X/* The following ANSI escape sequences are currently supported:
X * ESC D index the screen
X * ESC M reverse index the screen
X * ESC E next line
X * ESC 7 save cursor position
X * ESC 8 restore cursor position
X * ESC [ n A Cursor Up [default 1]
X * ESC [ n B Cursor Down [default 1]
X * ESC [ n C Cursor Right [default 1]
X * ESC [ n D Cursor Left [default 1]
X * ESC [ y ; x f move cursor to (x, y) [default (1,1)]
X * ESC [ y ; x H move cursor to (x, y) [default (1,1)]
X * ESC [ n J clear a section of screen [default 0]
X * n: 0 = cursor to bottom of screen
X * 1 = cursor to top of screen
X * 2 = top to bottom of screen
X * ESC [ n K clear a section of line [default 0]
X * n: 0 = cursor to end of line
X * 1 = cursor to start of line
X * 2 = start to end of line
X * ESC [ n L insert n lines at cursor [default 1]
X * ESC [ n M delete n lines at cursor [default 1]
X * ESC [ n @ insert n chars at cursor [default 1]
X * ESC [ n P delete n chars at cursor [default 1]
X * ESC [ n h set mode [default 0]
X * ESC [ n l reset mode [default 0]
X * n: 2 = Keyboard Lock [pwr up Off]
X * 4 = Insert Mode [pwr up Off]
X * 7 = Auto Wrap [pwr up ON]
X * ESC [ n m set the screen rendition [default 0]
X * n: 0 = normal
X * 1 = bold
X * 4 = underline
X * 5 = blink
X * 7 = reverse
X */
Xregister unsigned i, j;
X
X switch (c_estate) {
X case 0x01: /* ESC char */
X switch (c) {
X case 'M': /* Reverse Index */
X if (c_row == 0)
X scroll_screen(GO_BACKWARD);
X else {
X c_row--;
X move_to(tty_struct[CON1].tty_column, c_row);
X }
X return;
X
X case '7':
X c_s_row = c_row;
X c_s_col = tty_struct[CON1].tty_column;
X return;
X
X case '8':
X move_to(c_s_col, c_s_row);
X return;
X
X case 'E':
X move_to(0, c_row);
X case 'D':
X rout_con(&tty_struct[CON1],'\n',ECHO_OUT);
X return;
X
X default: /* Illegal ESC char sequence */
X return;
X }
X
X case 0x02: /* ESC '[' [num] char */
X switch (c) {
X case 'A': /* Cursor Up */
X move_to(tty_struct[CON1].tty_column
X , c_row - MAX(1,c_enum[0]));
X return;
X case 'B': /* Cursor Down */
X move_to(tty_struct[CON1].tty_column
X , c_row + MAX(1,c_enum[0]));
X return;
X case 'C': /* Cursor Right */
X move_to(tty_struct[CON1].tty_column + MAX(1,c_enum[0])
X , c_row);
X return;
X case 'D': /* Cursor Left */
X move_to(tty_struct[CON1].tty_column + MAX(1,c_enum[0])
X , c_row);
X return;
X
X case 'f': /* Position cursor */
X case 'H':
X move_to(c_enum[1]-1, c_enum[0]-1);
X return;
X
X case 'J':
X ofl_con(); /* Flush pending chars */
X switch (c_enum[0]) {
X case 1: /* Clear start of screen to cursor */
X vid_fill(c_blank, c_org
X , c_row * LINE_WIDTH
X + tty_struct[CON1].tty_column + 1);
X return;
X case 2: /* Clear entire screen */
X vid_fill(c_blank, c_org, SCR_LINES*LINE_WIDTH);
X return;
X case 0: /* Clear cursor to end of screen*/
X vid_fill(c_blank, c_vid
X , (SCR_LINES - c_row) * LINE_WIDTH
X - tty_struct[CON1].tty_column);
X return;
X }
X return;
X
X case 'K':
X ofl_con(); /* Flush pending chars */
X switch(c_enum[0]) {
X case 0: /* Clear cursor to end of line */
X vid_fill(c_blank, c_vid
X ,LINE_WIDTH - tty_struct[CON1].tty_column);
X return;
X case 1: /* Clear start of line to cursor */
X vid_fill(c_blank, c_org + c_row*2*LINE_WIDTH
X , tty_struct[CON1].tty_column + 1);
X return;
X case 2: /* Clear entire line */
X vid_fill(c_blank, c_org + c_row*2*LINE_WIDTH
X , LINE_WIDTH);
X return;
X }
X return;
X
X case 'L': /* Insert Lines */
X ofl_con(); /* Flush pending chars */
X
X i = between(1,c_enum[0],SCR_LINES - c_row); /* No. lines */
X j = c_org + (SCR_LINES*LINE_WIDTH*2-2); /* end of screen */
X
X /* Do the line moving */
X vid_bmove(j - i*2*LINE_WIDTH, j
X , (SCR_LINES - c_row - i)*LINE_WIDTH);
X
X /* Clear the inserted lines */
X vid_fill(c_blank, c_org + c_row*2*LINE_WIDTH
X , i*LINE_WIDTH);
X return;
X
X case 'M': /* Delete Lines */
X ofl_con(); /* Flush pending chars */
X
X i = between(1,c_enum[0],SCR_LINES - c_row); /* No. lines */
X j = c_org + c_row*2*LINE_WIDTH; /* Destination */
X
X /* Do the line moving */
X vid_fmove(j + i*2*LINE_WIDTH, j
X , (SCR_LINES - c_row - i)*LINE_WIDTH);
X
X /* Clear the new lines */
X vid_fill(c_blank, c_org + (SCR_LINES - i)*LINE_WIDTH*2
X , i*LINE_WIDTH);
X return;
X
X case '@': /* Insert Chars */
X ofl_con(); /* Flush pending chars */
X
X i = between(1,c_enum[0] /* No. chars */
X ,LINE_WIDTH - tty_struct[CON1].tty_column);
X j = c_org + c_row*2*LINE_WIDTH /* end of line */
X + (2*LINE_WIDTH-2);
X
X /* Do the char moving */
X vid_bmove(j - i*2, j
X , LINE_WIDTH - tty_struct[CON1].tty_column);
X
X /* Clear the new chars */
X vid_fill(c_blank, c_vid, i);
X return;
X
X case 'P': /* Delete Chars */
X ofl_con(); /* Flush pending chars */
X
X i = between(1,c_enum[0] /* No. chars */
X ,LINE_WIDTH - tty_struct[CON1].tty_column);
X j = c_org + c_row*2*LINE_WIDTH /* Destination */
X + tty_struct[CON1].tty_column;
X
X /* Do the char moving */
X vid_fmove(j + i*2, j
X , LINE_WIDTH - tty_struct[CON1].tty_column - i);
X
X /* Clear the new chars */
X vid_fill(c_blank, c_org + (c_row+1)*LINE_WIDTH*2 - i*2, i);
X return;
X
X case 'h': /* Set mode */
X switch (c_enum[0]) {
X case 2: /* Keyboard Lock */
X tty_struct[CON1].tty_ddmod |= CON_LOCK;
X return;
X case 4: /* Insert Mode */
X tty_struct[CON1].tty_ddmod |= CON_INSERT;
X return;
X case 7: /* Auto Wrap */
X tty_struct[CON1].tty_ddmod |= CON_WRAP;
X return;
X }
X return;
X
X case 'l': /* Reset mode */
X switch (c_enum[0]) {
X case 2: /* Keybaord Unlock */
X tty_struct[CON1].tty_ddmod &= ~CON_LOCK;
X return;
X case 4: /* Overwrite Mode */
X tty_struct[CON1].tty_ddmod &= ~CON_INSERT;
X return;
X case 7: /* No Auto Wrap */
X tty_struct[CON1].tty_ddmod &= ~CON_WRAP;
X return;
X }
X return;
X
X case 'm': /* Set graphic rendition */
X switch (c_enum[0]) {
X case 1: /* BOLD (light green on black) */
X c_attr = 0x0A00;
X return;
X
X case 4: /* UNDERLINE (blue on red) */
X c_attr = 0x4100;
X return;
X
X case 5: /* BLINKING (light grey on black) */
X c_attr = 0x8700;
X return;
X
X case 7: /* REVERSE (black on light grey) */
X c_attr = 0x7000;
X return;
X
X default: c_attr = 0x0700;
X return;
X }
X
X default: /* Illegal ESC [ sequence */
X return;
X }
X
X default: /* Illegal state */
X return;
X }
X}
X
X/*===========================================================================*
X * set_leds *
X *===========================================================================*/
XPRIVATE void set_leds()
X{
X/* Set the LEDs on the caps lock and num lock keys */
X
X int leds, dummy, i;
X
X if (pc_at == 0) return; /* PC/XT doesn't have LEDs */
X leds = (numlock<<1) | (capslock<<2); /* encode LED bits */
X port_out(KEYBD, LED_CODE); /* prepare keyboard to accept LED values */
X port_in(KEYBD, &dummy); /* keyboard sends ack; accept it */
X for (i = 0; i < LED_DELAY; i++) ; /* delay needed */
X port_out(KEYBD, leds); /* give keyboard LED values */
X port_in(KEYBD, &dummy); /* keyboard sends ack; accept it */
X}
X
X/*===========================================================================*
X * check_reboot *
X *===========================================================================*/
XPRIVATE void check_reboot()
X{
X/* High Level Reboot (Here because int routines can't print) */
X
X if (tty_struct[CON1].tty_state & REBOOT) {
X printf("\r\n\033[H\033[J\033[12;27HPress any key to Reboot :");
X ofl_con(); /* Flush the string */
X wreboot();
X }
X}
*-*-END-of-tty2.c-*-*
echo x - tty3.c
sed 's/^X//' >tty3.c <<'*-*-END-of-tty3.c-*-*'
X/* tty3.c - device dependant code for RS232 tty driver (using 8250)
X *
X * Written by: A.Hannam (Feb 1988)
X *
X * Modifications:
X * 7/9/88 - Modified for MINIX V1.3 on IBM-PC
X * Improved interrupt handling
X * Improved efficiency of compiled code
X * 19/9/88 - Added flow control (handshaking) & many ioctl calls
X */
X
X#include "../h/const.h"
X#include "../h/sgtty.h"
X#include "../h/type.h"
X#include "../h/signal.h"
X#include "../h/com.h"
X#include "const.h"
X
X#ifdef HIGH_LEVEL
X#undef HIGH_LEVEL
X#endif
X
X#include "tty.h"
X
X/* Now begins the code and data for the device-dependent tty drivers. */
X
X/*****************************************************************************/
X/**************************** 8250 SERIAL DRIVER *****************************/
X/*****************************************************************************/
X
X#if NR_8250S < 1
XError:- 8250 Driver: "NR_8250S" < 1
X#endif
X
XPUBLIC void int_8250(), init_8250();
X
Xextern void do_nothing(), restore();
Xextern int lock();
X
XPRIVATE bool rout_8250();
XPRIVATE void dset_8250(), oclr_8250(), iflow_8250();
X
X /* Some space and variables for the raw Output routines */
XGEN_S_BUF_TYPE(char,128)
XGEN_S_BUF_TYPE(char,32)
X
X#define BUSY DD_FLAG1 /* 1 when tty busy on output */
X#define RX_FLOW DD_FLAG2 /* 1 when input doing flow cntrl */
X#define TX_FLOW DD_FLAG3 /* 1 when output doing flow cntrl */
X
X#define WOUT_THRESHOLD 4 /* when to start trying to get more chars */
X#define XONCHAR 17 /* ^Q to restart with XONXOFF control */
X#define XOFFCHAR 19 /* ^S to stop with XONXOFF control */
X
X /* interrupt identification register bits */
X#define IPENDING 1 /* 1 when no interrupt pending */
X#define ITYPEMASK 6 /* mask to isolate interrupt causes */
X#define RXREADY 4 /* reciever is ready interrupt */
X#define TXREADY 2 /* transmitter ready interrupt */
X#define LSTATUS 6 /* line status event interrupt */
X#define MSTATUS 0 /* modem status event interrupt */
X /* line control register bits */
X/* bits 0,1 are number of databits as defined in sgtty.h */
X/* bit 2 is the number of stopbits as defined in sgtty.h */
X#define P_ENABLE 8 /* enable parity bit */
X#define P_EVEN 16 /* even parity bit */
X#define P_STICK 32 /* the parity sticks to 1 on P_EVEN else 0 */
X#define P_BRK 64 /* break enable bit */
X#define P_BAUD 128 /* set up for baud divisor input */
X /* line status register bits */
X#define L_DR 1 /* data recieved status bit */
X#define L_OE 2 /* overrun error status bit */
X#define L_PE 4 /* parity error status bit */
X#define L_FE 8 /* framing error status bit */
X#define L_BI 16 /* break detected status bit */
X#define L_HRE 32 /* holding reg empty status bit */
X#define L_TE 64 /* transmitter empty status bit */
X /* interrupt enable register bits */
X#define I_DR 1 /* enable recieved data interrupt */
X#define I_TE 2 /* enable transmit reg empty interrupt */
X#define I_LS 4 /* reciever line status interrupt */
X#define I_MS 8 /* modem status interrupt */
X /* modem control register bits */
X#define M_DTR 1 /* DTR output bit */
X#define M_RTS 2 /* RTS output bit */
X#define M_OUT1 4 /* OUT1 output bit */
X#define M_OUT2 8 /* OUT2 output bit */
X#define M_LOOP 16 /* enable loopback mode bit */
X /* modem status register bits */
X#define M_CTSC 1 /* CTS input has changed bit */
X#define M_DSRC 2 /* DSR input has changed bit */
X#define M_RIT 4 /* RI input (low to high transition) bit */
X#define M_DCDC 8 /* DCD input has changed bit */
X#define M_CTS 16 /* CTS input bit */
X#define M_DSR 32 /* DSR input bit */
X#define M_RI 64 /* RI input bit */
X#define M_DCD 128 /* DCD input bit */
X
XPRIVATE message mess_8250; /* our message buffer */
XPRIVATE char modem_bits; /* bits for RTS, CTS status etc. */
X
XPRIVATE struct rs_struct {
X int ldata; /* Tx/Rx data register */
X int lreg; /* Line control register */
X int intreg; /* Interrupt control register */
X int intid; /* Interrupt status register */
X int baud; /* Register (& +1) for baud */
X int lstat; /* Line status register */
X int modreg; /* Modem line control register */
X int mstat; /* Modem status register */
X char32 eout; /* Pointer to the echo out buffer */
X char128 wout; /* Pointer to the write out buffer */
X charfbuf in; /* Pointer to the input buffer */
X } rs[NR_8250S] = {{
X 0x3F8, 0x3FB, 0x3F9, 0x3FA, 0x3F8, 0x3FD, 0x3FC, 0x3FE
X , {"",0,0,0}, {"",0,0,0}, {"",0}
X#if NR_8250S >= 2
X },{
X 0x2F8, 0x2FB, 0x2F9, 0x2FA, 0x2F8, 0x2FD, 0x2FC, 0x2FE
X , {"",0,0,0}, {"",0,0,0}, {"",0}
X#endif
X#if NR_8250S >= 3
XError:- Need Extra port tables for COM3 ...
X#endif
X }};
X
X/*===========================================================================*
X * init_8250 *
X *===========================================================================*/
XPUBLIC void init_8250(tp)
Xregister tty_entry *tp;
X{
Xregister i = tp - &tty_struct[COM1];
X
X mess_8250.TTY_LINE= COM1; /* The interrupt message */
X mess_8250.m_type= TTY_CHAR_INT; /* Could have been TTY_O_DONE */
X
X tp->tty_devraw= rout_8250;
X tp->tty_devclr= oclr_8250;
X tp->tty_devflush= do_nothing;
X tp->tty_devioctl= dset_8250;
X tp->tty_devtrans= (unsigned (*)()) do_nothing;
X tp->tty_devempty= iflow_8250;
X
X#ifdef NXONXOFF
X /* 8 Data, 1 Stop bits, No Parity, Hardware handshaking */
X tp->tty_ddmod= D_SERIAL | SER_8DATA;
X#else
X /* 8 Data, 1 Stop bits, No Parity, XONXOFF handshaking */
X tp->tty_ddmod = D_SERIAL | SER_8DATA | TX_XONXOFF | RX_XONXOFF;
X#endif
X tp->tty_mode &= ~(EVENP|ODDP);
X
X#ifdef SLOW
X tp->tty_ispeed = tp->tty_ospeed = B1200;
X#else
X tp->tty_ispeed = tp->tty_ospeed = B4800;
X#endif
X
X tp->tty_fbuf = &rs[i].in;
X fbufinit(rs[i].in);
X bufinit(rs[i].wout);
X bufinit(rs[i].eout);
X modem_bits = (M_DTR|M_RTS|M_OUT2); /* DTR, RTS on, ints enabled */
X
X dset_8250(tp, 0);
X}
X
X
X
X/*===========================================================================*
X * int_8250 *
X *===========================================================================*/
XPUBLIC void int_8250(unit)
X{ /* Interrupts are off */
X /* Called when an interrupt occurs on the RS232 a port */
Xchar c;
Xregister tty_entry *tp= &tty_struct[COM1+unit];
Xregister struct rs_struct *r = &rs[unit];
X
X /* Ignore any interrupts on lines we don't know about */
X if (unit >= NR_8250S) return;
X
X while(TRUE) {
X port_in(r->intid, &c);
X
X if (c&IPENDING) break; /* no interrupt to process */
X
X switch (c & ITYPEMASK) {
X case RXREADY: /* Get a character */
X port_in(r->ldata,&c);
X
X /* Store the char if possible */
X if ( bufnfull(r->in) ) {
X /* Enough room so store the char */
X putfobj(r->in,c);
X }
X
X /* Tell other routines we have chars available */
X tp->tty_state |= IN_FLUSH;
X flush_flag |= IN_FLUSH;
X
X /* Send the int message to tty task only if abs. needed */
X if (bufcount(r->in) >= CHAR_BUF_THRESHOLD) {
X /* Do Flow Control */
X tp->tty_state |= RX_FLOW;
X if (tp->tty_ddmod & RX_XONXOFF)
X /* jam a ^S into the output stream */
X port_out(r->ldata,XOFFCHAR);
X else {
X /* hardware hanshaking */
X modem_bits &= ~M_DTR;
X port_out(r->modreg,modem_bits);
X }
X interrupt(TTY, &mess_8250);
X }
X /* The high level routine must turn back on the flow control */
X break;
X
X case TXREADY: /* Transmit more data */
X /* XT and some clones generate spurious ints */
X port_in(r->lstat,&c);
X if (!(c&L_HRE)) break;
X
X tp->tty_state &= ~BUSY; /* Assume port now free */
X
X /* Get data from the echo stream */
X if (bufnempty(r->eout)) {
X port_out(r->ldata,getobj(r->eout));
X advgetobj(r->eout);
X tp->tty_state |= BUSY;
X break;
X }
X
X /* If inhibited don't get data from write stream */
X if (tp->tty_state&(INHIBITED|TX_FLOW)) break;
X
X /* get data from write stream */
X if (bufnempty(r->wout)) {
X port_out(r->ldata,getobj(r->wout));
X advgetobj(r->wout);
X tp->tty_state |= BUSY;
X }
X
X /* If nearly empty make an attempt at getting more */
X if (bufcount(r->wout) <= WOUT_THRESHOLD
X && tp->tty_writers) {
X tp->tty_state |= OUT_FLUSH;
X flush_flag |= OUT_FLUSH;
X }
X
X /* No more data available, urgently try to get more */
X if (bufempty(r->wout) && tp->tty_writers) {
X tp->tty_state |= OUT_FLUSH;
X interrupt(TTY,&mess_8250);
X }
X break;
X
X case LSTATUS: /* line status event */
X port_in(r->lstat, &c); /* disabled */
X break;
X
X case MSTATUS: /* modem status event */
X port_in(r->mstat, &c);
X /* XONXOFF output flow cntrl in device indep driver */
X if (tp->tty_ddmod & TX_XONXOFF) break;
X
X if ((c&(M_CTS|M_DSR)) == (M_CTS|M_DSR))
X tp->tty_state &= ~TX_FLOW;
X else
X tp->tty_state |= TX_FLOW;
X break;
X }
X }
X port_out(INT_CTL,ENABLE);
X}
X
X
X/*===========================================================================*
X * rout_8250 *
X *===========================================================================*/
XPRIVATE bool rout_8250(tp,c,prio)
Xregister tty_entry *tp;
Xchar c;
X{
X/* Fill up the buffers in FIFO manner according to the priority */
Xint save_st;
Xregister struct rs_struct *r = &rs[tp - &tty_struct[COM1]];
X
X save_st = lock();
X /* If not busy then send echo's straight to the hardware */
X if (!(tp->tty_state&BUSY) && (prio==ECHO_OUT)) {
X port_out(r->ldata,c);
X tp->tty_state |= BUSY;
X restore(save_st);
X return 0;
X }
X
X /* Transmitter currently busy or char in write stream. Queue it FIFO */
X /* If ECHO_OUT and not enough space then try in write stream */
X if (prio==ECHO_OUT && bufnfull(r->eout)) {
X putobj(r->eout,c);
X restore(save_st);
X return 0;
X }
X
X /* Place in write stream if there is enough room */
X if (bufnfull(r->wout)) {
X putobj(r->wout,c);
X }
X
X /* If still not busy try to restart IO.
X * This is subject to characters being writable (^S processing).
X */
X if (!(tp->tty_state&(INHIBITED|BUSY|TX_FLOW)) && bufnempty(r->wout)) {
X port_out(r->ldata,getobj(r->wout));
X advgetobj(r->wout);
X tp->tty_state |= BUSY;
X }
X
X /* Warn the user if the stream is filling up */
X restore(save_st);
X return (prio==ECHO_OUT
X || (int)bufcount(r->wout) >= (int)bufsize(r->wout)*7/8);
X}
X
Xstatic unsigned char SBHigh[]= {0,9,9,6,4,3,3,2,1,0,0,0,0,0,0,0,0,0,0,0}
X ,SBLow[]={0,0xE4,0,0,0x17,0x59,0,0x40,0x80,0xC0
X ,0x60,0x40,0x3A,0x30,0x18,0xC,6,3,2,1};
X
X/*===========================================================================*
X * dset_8250 *
X *===========================================================================*/
XPRIVATE void dset_8250(tp, m)
Xregister tty_entry *tp;
Xmessage *m;
X{
Xint c, save_st;
Xregister struct rs_struct *r = &rs[tp - &tty_struct[COM1]];
X
X/* set baud rate, bits/char, etc
X */
X if (m)
X switch(m->TTY_REQUEST) {
X case TIOCSETN:
X case TIOCSETP:
X /* Don't support split baud */
X tp->tty_ospeed= tp->tty_ispeed;
X break;
X
X case TIOCSETM:
X /* Only keep Valid Mode bits */
X tp->tty_ddmod &= SER_2STOP|SER_DATABITS|RX_XONXOFF|TX_XONXOFF;
X tp->tty_ddmod |= D_SERIAL;
X break;
X
X case TIOCMODS:
X port_in(r->modreg, &c);
X c &= ~(M_DTR|M_RTS);
X if (((int)m->TTY_FLAGS) & TIOCM_DTR) c |= M_DTR;
X if (((int)m->TTY_FLAGS) & TIOCM_RTS) c |= M_RTS;
X port_out(r->modreg, c);
X return;
X
X case TIOCMODG:
X port_in(r->modreg, &c);
X m->TTY_FLAGS = (long)((unsigned) TIOCM_LE
X | ((c&M_DTR) ? TIOCM_DTR : 0)
X | ((c&M_RTS) ? TIOCM_RTS : 0));
X port_in(r->mstat, &c);
X m->TTY_FLAGS |= (long)((unsigned) ((c&M_CTS) ? TIOCM_CTS : 0)
X | ((c&M_DCD) ? TIOCM_CAR : 0)
X | ((c&M_DSR) ? TIOCM_DSR : 0)
X | ((c&M_RI ) ? TIOCM_RNG : 0));
X m->TTY_SPEK = 0;
X return;
X
X case TIOCSBRK:
X port_in(r->lreg, &c);
X c |= P_BRK;
X port_out(r->lreg, c);
X return;
X
X case TIOCCBRK:
X port_in(r->lreg, &c);
X c &= ~P_BRK;
X port_out(r->lreg, c);
X return;
X
X case TIOCSDTR:
X port_in(r->modreg, &c);
X c |= M_DTR;
X port_out(r->modreg, c);
X return;
X
X case TIOCCDTR:
X port_in(r->modreg, &c);
X c &= ~M_DTR;
X port_out(r->modreg, c);
X return;
X
X case TIOCSMLB:
X port_in(r->modreg, &c);
X c |= M_LOOP;
X port_out(r->modreg, c);
X return;
X
X case TIOCCMLB:
X port_in(r->modreg, &c);
X c &= ~M_LOOP;
X port_out(r->modreg, c);
X return;
X
X default: /* Ignore all other ioctl calls */
X return;
X }
X
X /* set up c with line control params i.e. data,stop,parity */
X c = tp->tty_ddmod & (SER_2STOP|SER_DATABITS);
X if (tp->tty_mode&ANYP) {
X c |= P_ENABLE;
X if (tp->tty_mode&EVENP) c |= P_EVEN;
X }
X
X /* Now set according to the modes */
X save_st = lock();
X
X port_out(r->lreg,P_BAUD); /* Set up for baud */
X port_out(r->baud+1,SBHigh[tp->tty_ospeed]); /* set Baud rate */
X port_out(r->baud,SBLow[tp->tty_ospeed]);
X
X port_out(r->lreg,c); /* set data, stop & parity */
X
X port_in(r->lstat, &c); /* Clear any data from controller */
X if (c & L_DR) port_in(r->ldata,&c);
X
X port_in(r->mstat,&c); /* Check output flow control */
X tp->tty_state &= ~TX_FLOW;
X if (!(tp->tty_ddmod&TX_XONXOFF) && (c&(M_CTS|M_DSR)) != (M_CTS|M_DSR))
X tp->tty_state |= TX_FLOW;
X
X if (tp->tty_state & RX_FLOW) { /* cancel input flow control */
X modem_bits |= M_DTR; /* set up DTR etc */
X port_out(r->ldata,XONCHAR); /* jam ^Q in output */
X tp->tty_state &= ~RX_FLOW;
X }
X port_out(r->modreg,modem_bits);
X if (tp->tty_ddmod&TX_XONXOFF)
X port_out(r->intreg, I_DR|I_TE ); /* TX & RX ints */
X else
X port_out(r->intreg, I_DR|I_TE|I_MS); /* TX, RX & MS ints */
X
X restore(save_st);
X}
X
X/*===========================================================================*
X * oclr_8250 *
X *===========================================================================*/
XPRIVATE void oclr_8250(tp)
Xregister tty_entry *tp;
X{
Xint save_st;
Xregister struct rs_struct *r = &rs[tp - &tty_struct[COM1]];
X
X save_st = lock();
X bufinit(r->eout);
X bufinit(r->wout);
X restore(save_st);
X}
X
X/*===========================================================================*
X * iflow_8250 *
X *===========================================================================*/
XPRIVATE void iflow_8250(tp)
Xregister tty_entry *tp;
X{
X/* The input buffers have been cleared ...
X * Handle flow control for the input stream
X */
X if (tp->tty_state & RX_FLOW) {
X if (tp->tty_ddmod & RX_XONXOFF) /* XON-XOFF handshaking */
X rout_8250(tp, XONCHAR, ECHO_OUT);
X else { /* Hardware handshaking */
X modem_bits |= M_DTR;
X port_out(rs[tp - &tty_struct[COM1]].modreg,modem_bits);
X }
X tp->tty_state &= ~RX_FLOW;
X }
X}
*-*-END-of-tty3.c-*-*
exit