schreiner@iravcl.ira.uka.de (09/29/89)
This is my RS232 version for the ST. It needs no extra task because it is *very* similar to those of PC MINIX 1.3. It works with echo up to 9600, but without echo at 9600 it isn't fast enough to get every incoming character in time. At 4800 this works too. Speed tests are made with a second ST as source/drain. Serveral sources which must change outside the kernel are addded too. E.g. install ioctl.o in libc.a before linking login(1), init(1) and stty(1). For those without patch there is an additional shar archive at the end of this posting containing normal diff's instead of cdiffs. Without Ralf Wenk, using a friends account ------------------ Cut here -------------------------------------------- echo x - login.c sed 's/^X//' > login.c << '/' X/* login - log into the system Author: Patrick van Kleef */ X X/* Peter S. Housel Jan. 1988 X * - Set up $USER, $HOME and $TERM. X * - Set signals to SIG_DFL. X * X * Terrence W. Holm June 1988 X * - Allow a username as an optional argument. X * - Time out if a password is not typed within 30 seconds. X * - Perform a dummy delay after a bad username is entered. X * - Cause a failure on bad PW_SHELL fields. 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#define WTMPSIZE 8 X#define DIGIT 3 X Xextern char *crypt(); Xextern struct passwd *getpwnam(); Xextern long time(); Xextern long lseek(); Xint Time_out(); X Xint time_out; X Xchar user[ 32 ]; Xchar logname[ 35 ]; Xchar home[ 64 ]; Xchar shell[ 64 ]; X Xchar *env[] = { X user, X logname, X home, X shell, X NULL X}; X X Xmain( argc, argv ) Xint argc; Xchar *argv[]; X{ X char name[30]; X char password[30]; X int bad; X int n; X int ttynr; X struct sgttyb args; X struct passwd *pwd; X struct stat statbuf; X X /* Reset some of the line parameters in case they have been mashed */ X if ( ioctl(0, TIOCGETP, &args) < 0 ) exit( 1 ); X X args.sg_kill = '@'; X args.sg_erase = '\b'; X args.sg_flags = (args.sg_flags & 01700) | XTABS | CRMOD | ECHO; X ioctl (0, TIOCSETP, &args); X X /* Get login name and passwd. */ X for (;;) { X bad = 0; X X if ( argc > 1 ) { X strcpy( name, argv[1] ); X argc = 1; X } else { X do { X n = read (0, name, 30); X } while (n < 2); X name[n - 1] = 0; X } X X /* Look up login/passwd. */ X if ((pwd = getpwnam (name)) == 0) bad++; X X /* If login name wrong or password exists, ask for pw. */ X if (bad || strlen (pwd->pw_passwd) != 0) { X args.sg_flags &= ~ECHO; X ioctl (0, TIOCSETP, &args); X X time_out = 0; X signal( SIGALRM, Time_out ); X alarm( 30 ); X X n = read (0, password, 30); X X alarm( 0 ); X if ( time_out ) { X n = 1; X bad++; X } X X password[n - 1] = 0; X write(1,\N,1); X args.sg_flags |= ECHO; X ioctl (0, TIOCSETP, &args); X X if (bad && crypt(password, AAAA) || X strcmp (pwd->pw_passwd, crypt(password, pwd->pw_passwd))) { X continue; X } X } X X /* Check if the system is going down */ X strcmp( name, ROOT ) != 0 ) { X continue; X } X X X /* Look up /dev/tty number. */ X fstat(0, &statbuf); X ttynr = statbuf.st_rdev & 0377; X ttyname[DIGIT] = '0' + ttynr; X X /* Write login record to /usr/adm/wtmp */ X wtmp(ttyname, name); X X setgid( pwd->pw_gid ); X setuid( pwd->pw_uid ); X X if (pwd->pw_shell[0]) sh = pwd->pw_shell; X X /* Set the environment */ X strcat( user, name ); X strcat( logname, name ); X strcat( home, pwd->pw_dir ); X strcat( shell, sh ); X X chdir( pwd->pw_dir ); X X /* Reset signals to default values. */ X X for ( n = 1; n <= NR_SIGS; ++n ) X signal( n, SIG_DFL ); X X execle( sh, X exit(1); X } X} X X X XTime_out( ) X{ X time_out = 1; X} X Xwtmp(tty, name) Xchar *tty, *name; X{ X/* Make an entry in /usr/adm/wtmp. */ 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, WTMPSIZE); X strncpy(namebuff, name, WTMPSIZE); X time(&t); X write(fd, ttybuff, WTMPSIZE); X write(fd, namebuff, WTMPSIZE); X write(fd, &t, sizeof(t)); X close(fd); X} / echo x - stty.c sed 's/^X//' > stty.c << '/' X/* stty - set terminal mode Author: Andy Tanenbaum */ X X#include <sgtty.h> Xint k; X Xstruct sgttyb args; Xstruct tchars tch; X 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 speed(s) args.sg_ispeed = s; args.sg_ospeed = s X#define clr1 args.sg_flags &= ~(BITS5 | BITS6 | BITS7 | BITS8) X#define clr2 args.sg_flags &= ~(EVENP | ODDP) X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X X /* stty with no arguments just reports on current status. */ X ioctl(0, TIOCGETP, &args); X ioctl(0, TIOCGETC, &tch); 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(0, TIOCSETP, &args); X ioctl(0, TIOCSETC, &tch); X exit(0); X} X X X Xreport() X{ X int mode; X char ispeed; X X mode = args.sg_flags; X ispeed = args.sg_ispeed; 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 if (ispeed > 0) { X /* Print # bits/char and parity */ X X /* Print line speed. */ X switch(ispeed) { X case B110 : prints(110); break; X case B300 : prints(300); break; X case B600 : prints(600); break; X case B1200: prints(1200); break; X case B2400: prints(2400); break; X case B4800: prints(4800); break; X case B9600: prints(9600); break; X (ispeed + '0'):(ispeed + 'A' - 10)); X } X } X prints(\N); X} X Xpr(f, n) Xint f,n; X{ X if (f) X else X} X Xoption(opt, next) Xchar *opt, *next; X{ X X if (match(opt, TABS)) {args.sg_flags |= XTABS; return;} X if (match(opt, EVEN)) {clr2; args.sg_flags |= EVENP; return;} X if (match(opt, ODD)) {clr2; args.sg_flags |= ODDP; 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 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 X if (match(opt, 5)) {clr1; args.sg_flags |= BITS5; return;} X if (match(opt, 6)) {clr1; args.sg_flags |= BITS6; return;} X if (match(opt, 7)) {clr1; args.sg_flags |= BITS7; return;} X if (match(opt, 8)) {clr1; args.sg_flags |= BITS8; return;} X X if (match(opt, 110)) {speed(B110); return;} X if (match(opt, 300)) {speed(B300); return;} X if (match(opt, 1200)) {speed(B1200); return;} X if (match(opt, 2400)) {speed(B2400); return;} X if (match(opt, 4800)) {speed(B4800); return;} X if (match(opt, 9600)) {speed(B9600); return;} X X if (match(opt, DEFAULT)) { X args.sg_flags = ECHO | CRMOD | XTABS | BITS8; X args.sg_ispeed = B1200; X args.sg_ospeed = B1200; X args.sg_kill = '@'; X args.sg_erase = '\b'; 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 std_err(opt); X std_err(\N); X X} X Xint match(s1, s2) Xchar *s1, *s2; X{ X X while (1) { X if (*s1 == 0 && *s2 == 0) return(1); X if (*s1 == 0 || *s2 == 0) return(0); X if (*s1 != *s2) return(0); X s1++; X s2++; X } X} X Xprctl(c) Xchar c; X{ X if (c < ' ') X else if (c == 0177) X prints(DEL); X else X prints(%C, c); X} / echo x - ioctl.c sed 's/^X//' > ioctl.c << '/' X#include <minix/com.h> X#include <sgtty.h> X XPUBLIC int ioctl(fd, request, u) Xint fd; Xint request; Xunion { X struct sgttyb *argp; X struct tchars *argt; X} u; X X{ X int n; X long erase, kill, intr, quit, xon, xoff, eof, brk; X X M.TTY_REQUEST = request; X M.TTY_LINE = fd; X X switch(request) { X case TIOCSETP: X erase = u.argp->sg_erase & 0377; X kill = u.argp->sg_kill & 0377; X M.TTY_SPEK = (erase << 8) | kill; X M.TTY_FLAGS = u.argp->sg_flags; X M.TTY_FLAGS |= (( u.argp->sg_ospeed << 8 ) | u.argp->sg_ispeed ) << 16L; X n = callx(FS, IOCTL); X return(n); X X case TIOCSETC: X intr = u.argt->t_intrc & 0377; X quit = u.argt->t_quitc & 0377; X xon = u.argt->t_startc & 0377; X xoff = u.argt->t_stopc & 0377; X eof = u.argt->t_eofc & 0377; X brk = u.argt->t_brkc & 0377; /* not used at the moment */ X M.TTY_SPEK = (intr<<24) | (quit<<16) | (xon<<8) | (xoff<<0); X M.TTY_FLAGS = (eof<<8) | (brk<<0); X n = callx(FS, IOCTL); X return(n); X X case TIOCGETP: X n = callx(FS, IOCTL); X u.argp->sg_erase = (M.TTY_SPEK >> 8) & 0377; X u.argp->sg_kill = (M.TTY_SPEK >> 0) & 0377; X u.argp->sg_flags = M.TTY_FLAGS; X u.argp->sg_ospeed = M.TTY_FLAGS >> 24; X u.argp->sg_ispeed = M.TTY_FLAGS >> 16; X return(n); X X case TIOCGETC: X n = callx(FS, IOCTL); X u.argt->t_intrc = (M.TTY_SPEK >> 24) & 0377; X u.argt->t_quitc = (M.TTY_SPEK >> 16) & 0377; X u.argt->t_startc = (M.TTY_SPEK >> 8) & 0377; X u.argt->t_stopc = (M.TTY_SPEK >> 0) & 0377; X u.argt->t_eofc = (M.TTY_FLAGS >> 8) & 0377; X u.argt->t_brkc = (M.TTY_FLAGS >> 8) & 0377; X return(n); X X default: X n = -1; X errno = -(EINVAL); X return(n); X } X} X / echo x - init.c sed 's/^X//' > init.c << '/' X/* This process is the father (mother) of all MINIX user processes. When X * MINIX comes up, this is process 2. It executes the /etc/rc shell file and X * then reads the /etc/ttys file to find out which terminals need a login X * process. The ttys file consists of 3-character lines as follows: X * abc X * where X * a = 0 (line disabled = no shell), 1 (enabled = shell started) X * b = a-r defines UART paramers (baud, bits, parity), 0 for console X * c = line number X * X * The letters a-r correspond to the 18 entries of the uart table below. X * For example, 'a' is 110 baud, 8 bits, no parity; 'b' is 300 baud, 8 bits, X * no parity; 'j' is 2400 baud, 7 bits, even parity; etc. X * X * If the file /usr/adm/wtmp exists and is writable, init (with help from X * login) maintains login accounting used by who(1). X */ X X X#define PIDSLOTS 10 X#define NPARAMSETS 18 X#define STACKSIZE 256 X#define DIGIT 8 X#define OFFSET 5 X#define SHELL 1 X#define NOPARAMS -100 X#define WTMPSIZE 8 X Xextern long time(); Xextern long lseek(); X Xstruct uart { X int baud; X int flags; X} uart[NPARAMSETS] = { X B110, BITS8, /* 110 baud, 8 bits, no parity */ X B300, BITS8, /* 300 baud, 8 bits, no parity */ X B1200, BITS8, /* 1200 baud, 8 bits, no parity */ X B2400, BITS8, /* 2400 baud, 8 bits, no parity */ X B4800, BITS8, /* 4800 baud, 8 bits, no parity */ X B9600, BITS8, /* 9600 baud, 8 bits, no parity */ X X B110, BITS7 | EVENP, /* 110 baud, 7 bits, even parity */ X B300, BITS7 | EVENP, /* 300 baud, 7 bits, even parity */ X B1200, BITS7 | EVENP, /* 1200 baud, 7 bits, even parity */ X B2400, BITS7 | EVENP, /* 2400 baud, 7 bits, even parity */ X B4800, BITS7 | EVENP, /* 4800 baud, 7 bits, even parity */ X B9600, BITS7 | EVENP, /* 9600 baud, 7 bits, even parity */ X X B110, BITS7 | ODDP, /* 110 baud, 7 bits, odd parity */ X B300, BITS7 | ODDP, /* 300 baud, 7 bits, odd parity */ X B1200, BITS7 | ODDP, /* 1200 baud, 7 bits, odd parity */ X B2400, BITS7 | ODDP, /* 2400 baud, 7 bits, odd parity */ X B4800, BITS7 | ODDP, /* 4800 baud, 7 bits, odd parity */ X B9600, BITS7 | ODDP /* 9600 baud, 7 bits, odd parity */ X}; X Xint pid[PIDSLOTS]; /* pids of init's own children */ Xint save_params[PIDSLOTS]; Xint pidct; Xextern int errno; X Xchar stack[STACKSIZE]; Xchar *stackpt = &stack[STACKSIZE]; X Xstruct sgttyb args; X X Xmain() X{ X char line[10]; /* /etc/ttys lines should be 3 chars */ X int rc, tty, k, status, ttynr, ct, i, params, shell; X X /* Carry out /etc/rc. */ X sync(); /* force buffers out onto RAM disk */ X X /* Execute the /etc/rc file. */ X if (fork()) { X /* Parent just waits. */ X wait(&k); X } else { X /* Child exec's the shell to do the work. */ X exit(-2); /* impossible */ X } X X /* Make the /usr/adm/wtmp entry. */ X wtmp(~,"); /* log system reboot */ X X /* Read the /etc/ttys file and fork off login processes. */ X /* Process /etc/ttys file. */ X while ( (ct = read(0, line, 4)) == 4) { X /* Extract and check the 3 characters on each line. */ X shell = line[0] - '0'; /* 0, 1, 2 for disabled, sh, no sh */ X params = line[1] - 'a'; /* selects UART parameters */ X ttynr = line[2] - '0'; /* line number */ X if (shell <= 0 || shell > 1) continue; X if (line[1] == '0') params = NOPARAMS; X else if (params < 0 || params > NPARAMSETS) continue; X if (ttynr < 0 || ttynr > PIDSLOTS) continue; X X save_params[ttynr] = params; X startup(ttynr, params); X } X } else { X while (1) ; /* just hang -- system cannot be started */ X } X close(tty); X X /* All the children have been forked off. Wait for someone to terminate. X * Note that it might be a child, in which case a new login process must be X * spawned off, or it might be somebody's orphan, in which case ignore it. X * First ignore all signals. X */ X for (i = 1; i <= NR_SIGS; i++) signal(i, SIG_IGN); X X while (1) { X sync(); X k = wait(&status); X pidct--; X X /* Search to see which line terminated. */ X for (i = 0; i < PIDSLOTS; i++) { X if (pid[i] == k) { X name[DIGIT] = '0' + i; X wtmp(&name[OFFSET], "); X startup(i, save_params[i]); X } X } X } X} X X Xstartup(linenr, params) Xint linenr, params; X{ X/* Fork off a process for the indicated line. */ X X int k, n; X X if ( (k = fork()) != 0) { X /* Parent */ X pid[linenr] = k; X pidct++; X } else { X /* Child */ X close(0); /* /etc/ttys may be open */ X name[DIGIT] = '0' + linenr; X if (open(name, 2) != 0) exit(-3); /* standard input */ X if (open(name, 2) != 1) exit(-3); /* standard output */ X if (open(name, 2) != 2) exit(-3); /* standard error */ X X X /* Set line parameters. */ X if (params != NOPARAMS) { X n = ioctl(0, TIOCGETP, &args); /* get parameters */ X args.sg_ispeed = uart[params].baud; X args.sg_ospeed = uart[params].baud; X args.sg_flags = CRMOD | XTABS | ECHO | uart[params].flags; X n = ioctl(0, TIOCSETP, &args); X } X X /* Try to exec login, or in an emergency, exec the shell. */ X return; /* impossible */ X } X} X Xwtmp(tty, name) Xchar *tty, *name; X{ X/* Make an entry in /usr/adm/wtmp. */ 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, WTMPSIZE ); X strncpy(namebuff, name, WTMPSIZE ); X time(&t); X write(fd, ttybuff, WTMPSIZE); X write(fd, namebuff, WTMPSIZE); X write(fd, &t, sizeof(t)); X close(fd); X} / echo x - strs232.c sed 's/^X//' > strs232.c << '/' X#ifdef ATARI_ST X/* The ST MINIX RS232 driver code. X * Ralf Wenk last update: Fri Sep 29 13:04:22 1989 X * X * Supports 5 to 8 data bits, even, odd, or none parity and several speeds X * between 50 and 19200 baud. Character translation is done according to X * the given mode. SIGHUP generated if BREAK detected. X * Dummy iob interrupt handler. X * X * Synchronous mode and hardware hand-shake are not suported. X * Speeds over 4800 are only usefull as login tty. X */ X X/* The MFP interrupts, it values and handlers: X * X * 00 01 02 03 03 02 0 0 X * pia iob iob iob tim clk acia dma X * BUSY DCD CTS GPUDONE T-D SYS-CLK KBD FDC/ACIA X * X * 01 03 02 01 00 00 06 07 X * tim sia sia sia sia tim iob iob X * T-B TERR TRDY RERR RRDY T-A RI MONO X */ X X X X/* The siaint() interrupt handler values */ X#define RRDY 0 /* serial Receiver ReaDY (=Full) */ X#define RERR 1 /* serial Receiver ERRor */ X#define TRDY 2 /* serial Transmitter ReaDY (=Empty) */ X#define TERR 3 /* serial Transmitter ERRor Int */ X X/* some values used by the code */ X#define OUT_SIZE 256 /* size of output translation buffer */ X#define SPARE 32 /* room for echo, must be greater one tabsize */ X#define IN_SIZE (2*MAX_OVERRUN+2) /* size of interrupt input buffer */ X#define OFLOW 5 /* # of chars to allow little buffer overflow */ X#define TRESHOLD ((IN_SIZE-2*OFLOW-2)/2) X /* # of chars to accumulate before msg */ X#define DATA_LEN 8 /* how much to shift sg_mode for len */ X#define SYN 0x16 /* The sync character */ X#define NONE 0 /* parity */ X#define ODD 1 /* or ... */ X#define EVEN 2 /* or ... */ X#define DEF_BAUD B1200 /* default baud rate */ X X#define DEBUG(x) /* x */ X X XEXTERN struct tty_struct tty_struct[]; XPRIVATE char baud_table[] = { X 3, 96, /* 50 bd # 0 */ X 3, 64, /* 75 bd # 1 */ X 1, 175, /* 110 bd # 2 */ X 1, 143, /* 134 bd # 3 */ X 1, 128, /* 150 bd # 4 */ X 1, 64, /* 300 bd # 5 */ X 1, 96, /* 200 bd # 6 */ X 1, 32, /* 600 bd # 7 */ X 1, 16, /* 1200 bd # 8 */ X 1, 11, /* 1800 bd # 9 */ X 1, 10, /* 2000 bd # 10 */ X 1, 8, /* 2400 bd # 11 */ X 1, 5, /* 3600 bd # 12 */ X 1, 4, /* 4800 bd # 13 */ X 1, 2, /* 9600 bd # 14 */ X 1, 1, /* 19200 bd # 15 */ X }; XPRIVATE struct tty_struct *tp; XPRIVATE message rs232_rm; /* used when chars arrived */ XPRIVATE message rs232_wm; /* used when output done */ XPRIVATE int t_err_ok; /* the next tx-error is legal */ XPRIVATE int t_state; /* transmitter state */ XPRIVATE int rs_busy; /* RS232 output is ... */ XPRIVATE char rs_translate[OUT_SIZE]; /* translation buffer for output */ XPRIVATE char *rs_next; /* next char to output */ XPRIVATE char *rs_ulimit; /* max fill pos. of transl. buffer */ XPRIVATE int rs_left; /* # of chars left in buffer */ XPRIVATE int rs_column; /* column on tty */ XPRIVATE char rsbuf[IN_SIZE]; /* input interrupt buffer */ X XPUBLIC int output_done; X X X/*===========================================================================* X * tx_err * X *===========================================================================*/ X/* A transmitter error occured */ XPRIVATE void tx_err () X{ X register int val; X X t_state = MFP->mf_tsr; X val = MFP->mf_udr; X} /* tx_err */ X X X/*===========================================================================* X * rx_err * X *===========================================================================*/ X/* A receiver error occured */ XPRIVATE void rx_err () X{ X register int val; X register int r_state; X void RxD(); X X r_state = MFP->mf_rsr; /* why ? */ X RxD(); /* get the char, possible garbage */ X if ( r_state & R_BREAK ) /* break seen ? */ X sigchar( tp, SIGHUP ); /* the other side has hung up */ X} /* rx_err */ X X X/*===========================================================================* X * rs_flush * X *===========================================================================*/ X/* Flush the tty_driver_buf by sending a message to TTY. This procedure can X * be triggered locally, when a character arrives, or by the clock task. X * The interrupt message is build by rs232init(). X */ XPUBLIC void rs_flush () X{ X if ( rsbuf[0] ) /* something to flush ? */ X interrupt( TTY, &rs232_rm ); /* send a message to the tty task */ X} /* rs_flush */ X X X/*===========================================================================* X * RxD * X *===========================================================================*/ X/* Fetch the data from the UART and store it so the TTY task can get at it X * later. Before the buffer overflows the data is thrown away. X */ XPRIVATE void RxD () X{ X register int r0; X register char c; X X c = MFP->mf_udr; /* get data from MFP */ X r0 = rsbuf[0]; X if ( r0 < rsbuf[1] ) /* room enough to store it ? */ X { X rsbuf[0] = ++r0; /* increment counter */ X r0 <<= 1; /* each entry contains two bytes */ X rsbuf[r0] = c; /* store the data */ X if ( r0 >= TRESHOLD ) /* must we send a message ? */ X rs_flush(); /* send TTY task a message */ X } X} /* RxD */ X X X/*===========================================================================* X * rs_write_int * X *===========================================================================*/ X/* An output ready interrupt has occurred, or a write has been done to an idle X * line. In both cases, start the output. X */ XPRIVATE void rs_write_int () X{ X while ( rs_left > 0 ) /* some char to output ? */ X { X MFP->mf_udr = *rs_next++; /* write it to UART */ X rs_left--; /* decrement counter */ X if ( ~MFP->mf_tsr & T_EMPTY) /* char in process ? */ X return; /* yes, return */ X } X if ( rs_left == 0 ) X { X t_err_ok = TRUE; /* causes an legal error */ X rs_busy = FALSE; /* nothing more to do */ X rs_next = rs_translate; /* prepare data pointer */ X if ( tp->tty_outleft > 0 ) X rs_write( tp ); /* fill the translation buffer again */ X else if ( tp->tty_waiting == WAITING ) /* tell tty only if neccesary */ X { X tp->tty_waiting = COMPLETED; /* mark this line as done */ X output_done++; /* prepare for fs-msg problems */ X interrupt( TTY, &rs232_wm ); /* send TTY task a message */ X } X } X} /* rs_write_int */ X X X/*===========================================================================* X * siaint * X *===========================================================================*/ X/* If some data arrives or has been send the MFP generates an interrupt which X * calls this function. Receiver and transmitter errors also came here. X */ XPUBLIC void siaint ( which ) Xint which; X{ X /* X * The next statements should e something like switch() {...} X * but ACK produces so slow code for this and so i decide ... X */ X if ( which == RRDY ) /* receiver ready ? */ X { X RxD(); X } X else if ( which == TRDY ) /* transmitter ready ? */ X { X rs_write_int(); X } X else if ( which == RERR ) /* receiver error ? */ X { X rx_err(); X } X else if ( ! t_err_ok ) /* unexpected transmitter error ? */ X { X tx_err(); X } X} /* siaint */ X X X/*===========================================================================* X * translate * X *===========================================================================*/ X/* Some characters output to RS-232 lines need special processing, such as X * tab expansion and LF to CR+CF mapping. These things are done here. X */ XPRIVATE void translate ( mode, c ) Xint mode; Xregister char c; X{ X register char *cptr; X X cptr = rs_next + rs_left; X if ( c == '\b' ) /* ack's switch() is too slow so i decided... */ X rs_column -= 2; /* it's incremented below */ X else if ( c == '\r' ) X rs_column = -1; /* it's incremented below */ X else if ( c == '\n' && ( mode & CRMOD )) X { /* has LF to be mapped to CR + LF ? */ X *cptr++ = '\r'; X rs_left++; X rs_column = -1; /* it's incremented below */ X } X else if ( c == '\t' ) X { X if ( mode & XTABS ) X { X c = ' '; /* Tabs must be expanded */ X do X { X *cptr++ = c; X rs_left++; X } X while ((++rs_column & 7 ) != 7 ); /* on Tabs the lower 3 bits are 0 */ X } X else /* Tabs are send to the terminal hardware */ X { X rs_column &= ~7; /* force to mod 8 */ X rs_column += 7; /* next tab position minus 1 */ X } X } X *cptr = c; /* copy char to translation buffer */ X rs_left++; /* one more to output */ X rs_column++; /* update column */ X} /* translate */ X X X/*===========================================================================* X * rs_write * X *===========================================================================*/ X/* Copy as much data as possible to the output queue, then start I/O if X * necessary. X */ XPRIVATE rs_write ( tp ) Xregister struct tty_struct *tp; X{ X register char c; X X if ( tp->tty_inhibited == RUNNING ) X { X /* While there is still data to output and there is still room in buf, copy*/ X while ( tp->tty_outleft > 0 && rs_next + rs_left < rs_ulimit ) X { X tp->tty_outleft--; X tp->tty_cum++; /* update cumulative total */ X c = *(( char *)tp->tty_phys)++; /* get one byte */ X if ( c < ' ' ) X translate( tp->tty_mode, c ); /* insert in output buffer */ X else X { /* avoid function call */ X *( rs_next + rs_left ) = c; /* direct insertion */ X rs_left++; X rs_column++; X } X } X if ( ! rs_busy ) /* is the terminal idle ? */ X { X rs_busy = TRUE; /* mark it as busy */ X rs_write_int(); /* and start it */ X } X } X} /* rs_write */ X X X/*===========================================================================* X * rs_echo * X *===========================================================================*/ X/* Only called if tty mode is echo */ XPRIVATE rs_echo ( tp, c ) Xregister struct tty_struct *tp; Xchar c; X{ X register int s; X X/* See if there is room to store a character, and if so, do it. */ X if ( rs_next + rs_left < &rs_translate[OUT_SIZE] ) X { X s = lock(); X translate( tp->tty_mode, c ); X restore( s ); X if ( ! rs_busy ) /* is the terminal idle ? */ X { X rs_busy = TRUE; /* mark it as busy */ X rs_write_int(); /* and start it */ X } X } X} /* rs_echo */ X X X/*===========================================================================* X * start_rs232 * X *===========================================================================*/ XPRIVATE int start_rs232 ( tp ) Xstruct tty_struct *tp; X{ X t_state = OK; X rs_write( tp ); X return( 0 ); X} /* start_rs232 */ X X X/*===========================================================================* X * rs232_sig * X *===========================================================================*/ X/* called at SIGINT, SIGQUIT or SIGKILL. It resets the RS232 output and is X * only necessary because RS232 uses his own (translation) buffer for output. X */ XPUBLIC void rs232_sig () X{ X rs_left = 0; X rs_busy = FALSE; X rs_next = rs_translate; X} /* rs232_sig */ X X X/*===========================================================================* X * set_speed * X *===========================================================================*/ XPRIVATE void set_speed ( in_baud, out_baud, data_bits, parity, stop_bits ) Xint in_baud; /* input speed: index into baud_table */ Xint out_baud; /* must be same as input speed here => ignored */ Xint data_bits; /* 5, 6, 7 or 8 */ Xint parity; /* EVEN, ODD or NONE */ Xint stop_bits; /* 1 or 2 */ X{ X register int s; X register int line_ctrl; X X X line_ctrl = 0; X s = lock(); X rs_left = 0; /* it makes no sense to output */ X rs_busy = FALSE; /* something old after changeing */ X rs_next = rs_translate; /* the RS232 parameters, right ? */ X t_err_ok = TRUE; /* disabeling transmitter causes it */ X MFP->mf_rsr &= ( ~R_ENA ); /* disable receiver */ X MFP->mf_tsr = ( T_TRI & ~T_ENA ); /* disable & quiet output tristate */ X MFP->mf_tcdcr &= ( 0xf0 | T_STOP ); /* stop timer D only */ X in_baud <<= 1; /* each value uses two entries */ X MFP->mf_tcdcr |= 0x0f & baud_table[in_baud]; /* set new delay */ X in_baud++; X MFP->mf_tddr = baud_table[in_baud]; /* set new count */ X if ( parity != NONE ) X { X line_ctrl = U_PAR; X if ( parity == EVEN ) X line_ctrl |= U_EVEN; X } X switch ( stop_bits ) X { X case 2 : X line_ctrl |= U_ST2; X break; X case 1 : X default : X line_ctrl |= U_ST1; X break; X } X switch ( data_bits ) X { X case 5 : X line_ctrl |= U_D5; X break; X case 6 : X line_ctrl |= U_D6; X break; X case 7 : X line_ctrl |= U_D7; X break; X case 8 : X default : X line_ctrl |= U_D8; X break; X } X line_ctrl |= U_Q16; X MFP->mf_ucr = line_ctrl; X MFP->mf_rsr |= R_ENA; /* enable receiver */ X MFP->mf_tsr |= T_ENA; /* enable transmitter */ X restore( s ); X} /* set_speed */ X X X/*===========================================================================* X * set_uart * X *===========================================================================*/ XPUBLIC void set_uart ( mode, speed ) Xint mode; /* sgtty.h sg_mode word */ Xint speed; /* low byte is input speed, high is output */ X{ X /* X * prepare the UART parameters X * on ATARI ST the input and output speeds are always the same X * so we use always the input speed X */ X register int parity, data_bits; X X speed &= 0xff; X if ( speed == B0 ) /* B0 means BREAK */ X { X MFP->mf_tsr |= T_BREAK; /* send BREAK when udr is empty */ X } X else X { X if ( speed < B50 ) X speed = B50; X else if ( speed > B19200 ) X speed = B19200; X speed--; /* the index is one to high, correct it */ X parity = NONE; X if ( mode & EVENP ) X parity = EVEN; X else if ( mode & ODDP ) X parity = ODD; X data_bits = 5 + (( mode >> DATA_LEN ) & 0x3 ); X set_speed( speed, speed, data_bits, parity, 1 ); X } X} /* set_uart */ X X X/*===========================================================================* X * rs232init * X *===========================================================================*/ XPUBLIC void rs232init() X{ X register int index; X X output_done = 0; /* line is idle */ X tp = &tty_struct[RS232]; /* set the Rs232 tty_struct pointer */ X tp->tty_start = start_rs232; X tp->tty_echo = rs_echo; X/* tp->tty_mode |= BITS8; /* CRMOD | XTABS | ECHO | BITS8 */ X tp->tty_mode = RAW | BITS8; X tp->tty_speed = ( DEF_BAUD << 8 ) | DEF_BAUD; X for ( index = 3; index < IN_SIZE; index += 2 ) X rsbuf[index] = RS232; /* prefill the originating line no */ X rsbuf[0] = 0; /* buffer is empty */ X rsbuf[1] = TRESHOLD + OFLOW; /* max filling size */ X rs_ulimit = &rs_translate[OUT_SIZE-SPARE]; /* set upper filling limit */ X rs_column = 0; /* first column */ X rs232_rm.m_type = TTY_CHAR_INT; /* receiver message is always */ X rs232_rm.ADDRESS = rsbuf; /* the same, so set it up here */ X rs232_wm.m_type = TTY_O_DONE; /* sender message is always */ X rs232_wm.TTY_LINE = RS232; /* same, (which line is finished) */ X/* MFP->mf_scr = SYN; /* just for fun : sync char */ X/* MFP->mf_rsr = R_STRIP; /* strip enable */ X set_uart( tp->tty_mode, tp->tty_speed ); X} /* rs232init */ X X X/* The iob() interrupt handler values */ X#define DCD 1 /* serial Data Carrier Detected */ X#define CTS 2 /* serial Clear To Send */ X#define RI 6 /* serial Ring Indicator */ X#define GPUDONE 3 /* Grafic Process Unit DONE ( blitter ) */ X#define MONO 7 /* MONOchrome monitor detect */ X X/*===========================================================================* X * iob * X *===========================================================================*/ XPUBLIC void iob ( which ) Xint which; X{ X register char *cptr; X X /* ack's switch is too slow so i decided ... */ X if ( which == RI ) /* ring indicator ? */ X { X cptr = RI; X } X else if ( which == CTS ) /* clear to send ? */ X { X cptr = CTS; X } X else if ( which == DCD ) /* data carrier detected ? */ X { X cptr = DCD; X } X else if ( which == MONO ) /* monitor changed ? */ X { X cptr = MONO; X } X else /* must be GPU */ X cptr = GPU; X} /* iob */ X X#endif ATARI_ST / echo x - sgtty.h sed 's/^X//' > sgtty.h << '/' X/* Data structures for IOCTL. */ X Xstruct sgttyb { X char sg_ispeed; /* input speed */ X char sg_ospeed; /* output speed */ X char sg_erase; /* erase character */ X char sg_kill; /* kill character */ X int sg_flags; /* mode flags */ X}; X Xstruct tchars { X char t_intrc; /* SIGINT char */ X char t_quitc; /* SIGQUIT char */ X char t_startc; /* start output (initially CTRL-Q) */ X char t_stopc; /* stop output (initially CTRL-S) */ X char t_eofc; /* EOF (initially CTRL-D) */ X char t_brkc; /* input delimiter (like nl) */ X}; X X/* Field names */ X#define XTABS 0006000 /* do tab expansion */ X#define BITS8 0001400 /* 8 bits/char */ X#define BITS7 0001000 /* 7 bits/char */ X#define BITS6 0000400 /* 6 bits/char */ X#define BITS5 0000000 /* 5 bits/char */ X#define EVENP 0000200 /* even parity */ X#define ODDP 0000100 /* odd parity */ X#define RAW 0000040 /* enable raw mode */ X#define CRMOD 0000020 /* map lf to cr + lf */ X#define ECHO 0000010 /* echo input */ X#define CBREAK 0000002 /* enable cbreak mode */ X#define COOKED 0000000 /* neither CBREAK nor RAW */ X X/* Line speeds */ X#define B0 0xff /* sends BREAK */ X#define B50 0x01 X#define B75 0x02 X#define B110 0x03 X#define B134 0x04 X#define B150 0x05 X#define B200 0x06 X#define B300 0x07 X#define B600 0x08 X#define B1200 0x09 X#define B1800 0x0a X#define B2000 0x0b X#define B2400 0x0c X#define B3600 0x0d X#define B4800 0x0e X#define B9600 0x0f X#define B19200 0x10 X#define EXTA B19200 X#define EXTB 0x00 X X#define TIOCGETP (('t'<<8) | 8) X#define TIOCSETP (('t'<<8) | 9) X#define TIOCGETC (('t'<<8) | 18) X#define TIOCSETC (('t'<<8) | 17) / echo x - Makefile.cdif sed 's/^X//' > Makefile.cdif << '/' X*** /usr/src/sys/kernel/Makefile Fri Sep 29 13:09:53 1989 X--- Makefile Wed Sep 20 23:10:24 1989 X*************** X*** 8,14 **** X OBJ = stmpx.o stmain.o proc.o system.o stshadow.o \ X tty.o clock.o memory.o stdma.o stfloppy.o stwini.o \ X stcon.o stkbd.o stvdu.o stfnt.o stprint.o \ X! table.o stdmp.o X HDR = ../h/callnr.h ../h/com.h ../h/const.h ../h/error.h \ X ../h/sgtty.h ../h/signal.h ../h/type.h \ X const.h glo.h proc.h tty.h type.h \ X--- 8,14 ---- X OBJ = stmpx.o stmain.o proc.o system.o stshadow.o \ X tty.o clock.o memory.o stdma.o stfloppy.o stwini.o \ X stcon.o stkbd.o stvdu.o stfnt.o stprint.o \ X! table.o stdmp.o strs232.o X HDR = ../h/callnr.h ../h/com.h ../h/const.h ../h/error.h \ X ../h/sgtty.h ../h/signal.h ../h/type.h \ X const.h glo.h proc.h tty.h type.h \ / echo x - clock.c.cdif sed 's/^X//' > clock.c.cdif << '/' X*** /usr/src/sys/kernel/clock.c Fri Sep 29 13:09:54 1989 X--- clock.c Sun May 28 23:01:32 1989 X*************** X*** 199,204 **** X--- 199,206 ---- X X #ifdef ATARI_ST X kb_timer(); /* keyboard repeat */ X+ if ((( int )realtime & 3 ) == 0 ) /* call only every 4th tick */ X+ rs_flush(); /* flush RS232 buffer */ X #endif ATARI_ST X X /* If a user process has been running too long, pick another one. */ / echo x - stmain.c.cdif sed 's/^X//' > stmain.c.cdif << '/' X*** /usr/src/sys/kernel/stmain.c Fri Sep 29 13:10:06 1989 X--- stmain.c Fri Sep 22 22:16:30 1989 X*************** X*** 226,233 **** X /* X * initialize MFP X */ X! MFP->mf_ierb |= (IB_DINT|IB_AINT|IB_TIMC|IB_PBSY); X! MFP->mf_imrb |= (IB_DINT|IB_AINT|IB_TIMC|IB_PBSY); X /* X * interrupts to vectors 0x40 to 0x4F X * automatic end-of-interrupt mode X--- 226,235 ---- X /* X * initialize MFP X */ X! MFP->mf_iera |= (IA_SRI|IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); X! MFP->mf_imra |= (IA_SRI|IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); X! MFP->mf_ierb |= (IB_DINT|IB_AINT|IB_TIMC|IB_SCTS|IB_SDCD|IB_PBSY); X! MFP->mf_imrb |= (IB_DINT|IB_AINT|IB_TIMC|IB_SCTS|IB_SDCD|IB_PBSY); X /* X * interrupts to vectors 0x40 to 0x4F X * automatic end-of-interrupt mode X*************** X*** 259,267 **** X * temporary stuff * X *===========================================================================*/ X timint(t) {fake_int(TIMINT, t);} X! siaint(t) {fake_int(SIAINT, t);} X! mdiint(t) {fake_int(MDIINT, t);} X! iob(t) {fake_int(IOB, t);} X X fake_int(s, t) char *s; { X--- 261,267 ---- X * temporary stuff * X *===========================================================================*/ X timint(t) {fake_int(TIMINT, t);} X! mdiint(t) {fake_int(MDIINT, t);} X X fake_int(s, t) char *s; { / echo x - tty.c.cdif sed 's/^X//' > tty.c.cdif << '/' X*** /usr/src/sys/kernel/tty.c Fri Sep 29 13:10:18 1989 X--- tty.c Sat Sep 23 01:45:19 1989 X*************** X*** 47,52 **** X--- 47,53 ---- X X+ EXTERN int output_done; X PUBLIC struct tty_struct tty_struct[NR_TTYS]; X X /*===========================================================================* X*************** X*** 64,76 **** X receive(ANY, &tty_mess); X tp = &tty_struct[tty_mess.TTY_LINE]; X switch(tty_mess.m_type) { X! case TTY_CHAR_INT: do_charint(&tty_mess); break; 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- case TTY_O_DONE: /* reserved for future use (RS-232 terminals)*/ X default: tty_reply(TASK_REPLY, tty_mess.m_source, X tty_mess.PROC_NR, EINVAL, 0L, 0L); X } X--- 65,129 ---- X receive(ANY, &tty_mess); X tp = &tty_struct[tty_mess.TTY_LINE]; X switch(tty_mess.m_type) { X! case TTY_O_DONE: X! case TTY_CHAR_INT: X! /* The TTY task can generate two kinds of interrupts: X! * - a character has been typed on the console or an X! * RS232 line X! * - an RS232 line has completed a write request (on X! * behalf of a user) X! * If either interrupt happens and the TTY task is idle, X! * the task gets the interrupt message immediately and X! * processes it. However, if the TTY task is busy, a bit X! * is set in 'busy_map' and the message pointer stored. X! * If multiple messages happen, the bit is only set once. X! * No input data is lost even if this happens because all X! * the input messages say is that there is some input. X! * The actual input is in the tty_driver_buf array, so X! * losing a message just means that when the one interrupt- X! * generated message is given to the TTY task, it will find X! * multiple characters in tty_driver_buf. X! * X! * The introduction of RS232 lines has complicated this X! * situation somewhat. Now a message can mean that some X! * RS232 line has finished transmitting all the output X! * given to it. If a character is typed at the instant X! * an RS232 line finishes, one of the two messages may be X! * overwritten because MINIX only provides single buffering X! * for interrupt messages (in proc.c). To avoid losing X! * information, whenever an RS232 line finishes, the flag X! * tty_waiting is set to COMPLETED and kept that way until X! * its completion is processed and a message sent to FS X! * saying that output is done. The number of RS232 lines in X! * COMPLETED state is kept in output_done, which is checked X! * on each interrupt, so that a lost TTY_O_DONE line X! * completion interrupt will be quickly recovered. X! * X! * In short, when this procedure is called, it can check X! * for RS232 line done by inspecting output_done and it X! * can check for characters in the input buffer by X! * inspecting tty_driver_buf[0]. Thus losing a message to X! * the TTY task is not serious because the underlying X! * conditions are explicitly checked for on each interrupt. X! */ X! X! /* First check to see if the RS232 line has completed. */ X! if ( output_done > 0 ) X! /* If a message is sent to FS for X! * RS232 done, don't process any X! * input characters now for fear X! * of sending a second message to X! * FS, which would be lost. X! */ X! do_o_done(tp); X! else X! do_charint( &tty_mess ); X! break; 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_reply(TASK_REPLY, tty_mess.m_source, X tty_mess.PROC_NR, EINVAL, 0L, 0L); X } X*************** X*** 100,106 **** X copy_ptr = tty_copy_buf; /* ptr to shadow array where chars copied */ X n = *ptr; /* how many chars have been accumulated */ X count = n; /* save the character count */ X! n = n + n; /* each char occupies 2 bytes */ X ptr += 2; /* skip count field at start of array */ X while (n-- > 0) X *copy_ptr++ = *ptr++; /* copy the array to safety */ X--- 153,159 ---- X copy_ptr = tty_copy_buf; /* ptr to shadow array where chars copied */ X n = *ptr; /* how many chars have been accumulated */ X count = n; /* save the character count */ X! n <<= 1; /* each char occupies 2 bytes */ X ptr += 2; /* skip count field at start of array */ X while (n-- > 0) X *copy_ptr++ = *ptr++; /* copy the array to safety */ X*************** X*** 292,298 **** X int code, caller; X X if (tp->tty_inleft > 0) { /* if someone else is hanging, give up */ X! tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_TRY_AGAIN,0L,0L); X return; X } X X--- 345,351 ---- X int code, caller; X X if (tp->tty_inleft > 0) { /* if someone else is hanging, give up */ X! tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO, 0L, 0L); X return; X } X X*************** X*** 390,405 **** X { X /* A command has terminated (possibly due to DEL). Tell caller. */ X X! int replyee, caller; X X tp->tty_outleft = 0; X #ifdef ATARI_ST X (proc_addr(tp->tty_outproc))->p_physio = 0; /* enable (un)shadowing */ X #endif X if (tp->tty_waiting == NOT_WAITING) return; X! replyee = (int) tp->tty_otcaller; X! caller = (int) tp->tty_outproc; X! tty_reply(TASK_REPLY, replyee, caller, code, 0L, 0L); X tp->tty_waiting = NOT_WAITING; X } X X--- 443,459 ---- X { X /* A command has terminated (possibly due to DEL). Tell caller. */ X X! int result, replyee, caller; X X tp->tty_outleft = 0; X #ifdef ATARI_ST X (proc_addr(tp->tty_outproc))->p_physio = 0; /* enable (un)shadowing */ X #endif X if (tp->tty_waiting == NOT_WAITING) return; X! result = ( tp == &tty_struct[RS232] ? REVIVE : TASK_REPLY ); X! replyee = (int) tp->tty_otcaller; X! caller = (int) tp->tty_outproc; X! tty_reply(result, replyee, caller, code, 0L, 0L); X tp->tty_waiting = NOT_WAITING; X } X X*************** X*** 416,421 **** X--- 470,482 ---- X vir_bytes out_vir, out_left; X struct proc *rp; X extern phys_bytes umap(); X+ int caller, replyee; X+ X+ /* If the slot is already in use, better return an error than mess it up. */ X+ /* if (tp->tty_outleft > 0) { /* if someone else is hanging, give up */ X+ /* tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO, 0L, 0L); X+ return; X+ }*/ X X /* Copy message parameters to the tty structure. */ X tp->tty_otcaller = m_ptr->m_source; X*************** X*** 441,446 **** X--- 502,517 ---- X /* Copy characters from the user process to the terminal. */ X if ((*tp->tty_start)(tp)) /* copy data to queue and start I/O */ X finish(tp, tp->tty_cum); X+ X+ /* If output is for a bitmapped terminal as the ATARI ST console, the output- X+ * routine will return at once so there is no need to suspend the caller, X+ * on ascii terminals however, the call is suspended and later revived. X+ */ X+ if (m_ptr->TTY_LINE == RS232) { X+ caller = (int) tp->tty_outproc; X+ replyee = (int) tp->tty_otcaller; X+ tty_reply(TASK_REPLY, replyee, caller, SUSPEND, 0L, 0L); X+ } X } X X X*************** X*** 465,470 **** X--- 536,548 ---- X tp->tty_erase = (char) ((m_ptr->TTY_SPEK >> 8) & BYTE); /* erase */ X tp->tty_kill = (char) ((m_ptr->TTY_SPEK >> 0) & BYTE); /* kill */ X tp->tty_mode = (int) m_ptr->TTY_FLAGS; /* mode word */ X+ if ( m_ptr->TTY_LINE == RS232 ) X+ { /* set the new speed only if it's legal, store it temp here */ X+ int new_speed; X+ new_speed = ( int )( m_ptr->TTY_FLAGS >> 16 ); X+ if ( new_speed ) tp->tty_speed = new_speed; X+ set_uart( tp->tty_mode, tp->tty_speed ); X+ } X break; X X case TIOCSETC: X*************** X*** 481,487 **** X erase = ((long) tp->tty_erase) & BYTE; X kill = ((long) tp->tty_kill) & BYTE; X erki = (erase << 8) | kill; X! flags = (long) tp->tty_mode; X break; X X case TIOCGETC: X--- 559,565 ---- X erase = ((long) tp->tty_erase) & BYTE; X kill = ((long) tp->tty_kill) & BYTE; X erki = (erase << 8) | kill; X! flags = ((long) tp->tty_speed << 16 ) | (long) tp->tty_mode; X break; X X case TIOCGETC: X*************** X*** 585,590 **** X--- 663,669 ---- X tp->tty_intail = tp->tty_inqueue; X tp->tty_incount = 0; X tp->tty_lfct = 0; X+ if ( tp == &tty_struct[RS232] ) rs232_sig(); /* only RS232 */ X if (tp->tty_pgrp) X cause_sig(tp->tty_pgrp, sig); X } X*************** X*** 616,623 **** X--- 695,721 ---- X case CONSOLE: X coninit(); X break; X+ case RS232: X+ rs232init(); X+ break; X default: X } X } X } X+ X+ X+ /*===========================================================================* X+ * do_o_done * X+ *===========================================================================*/ X+ PRIVATE do_o_done( tp ) X+ register struct tty_struct *tp; /* pointer to tty struct */ X+ { X+ /* A write request on the RS232 line has completed. Send FS a message. */ X+ X+ if ( tp->tty_waiting == COMPLETED ) X+ { X+ finish( tp, tp->tty_cum ); X+ output_done--; X+ } X+ } / echo x - tty.h.cdif sed 's/^X//' > tty.h.cdif << '/' X*** /usr/src/sys/kernel/tty.h Fri Sep 29 13:10:20 1989 X--- tty.h Tue May 30 23:19:21 1989 X*************** X*** 1,11 **** X! #define NR_TTYS 1 /* how many terminals can system handle */ X! #define CONSOLE 0 /* line number for console */ X #define OPERATOR (-1) /* handle CTRL-ALT-PFX sequences */ X X #define TTY_IN_BYTES 200 /* input queue size */ X #define TAB_SIZE 8 /* distance between tabs */ X #define TAB_MASK 07 /* mask for tty_column when tabbing */ X! #define MAX_OVERRUN 16 /* size of overrun input buffer */ X X #define ERASE_CHAR '\b' /* default erase character */ X #define KILL_CHAR '@' /* default kill character */ X--- 1,12 ---- X! #define NR_TTYS 2 /* how many terminals can system handle */ X! #define CONSOLE 0 /* line number for console */ X! #define RS232 1 /* line number for serial-io */ X #define OPERATOR (-1) /* handle CTRL-ALT-PFX sequences */ X X #define TTY_IN_BYTES 200 /* input queue size */ X #define TAB_SIZE 8 /* distance between tabs */ X #define TAB_MASK 07 /* mask for tty_column when tabbing */ X! #define MAX_OVERRUN 126 /* size of overrun input buffer */ X X #define ERASE_CHAR '\b' /* default erase character */ X #define KILL_CHAR '@' /* default kill character */ X*************** X*** 30,35 **** X--- 31,37 ---- X X /* Terminal parameters and status. */ X int tty_mode; /* terminal mode set by IOCTL */ X+ int tty_speed; /* low_byte is ispeed; high byte is ospeed */ X char tty_escaped; /* 1 when '\' just seen, else 0 */ X char tty_inhibited; /* 1 when CTRL-S just seen (stops output) */ X char tty_waiting; /* 1 when output process waiting for reply */ X*************** X*** 64,68 **** X #define STOPPED 1 /* CTRL-S has been typed to stop the tty */ X #define NOT_WAITING 0 /* no output process is hanging */ X #define WAITING 1 /* an output process is waiting for a reply */ X! X! EXTERN struct tty_struct tty_struct[]; X--- 66,71 ---- X #define STOPPED 1 /* CTRL-S has been typed to stop the tty */ X #define NOT_WAITING 0 /* no output process is hanging */ X #define WAITING 1 /* an output process is waiting for a reply */ X! #define COMPLETED 2 /* output done; send completion message */ X! X! EXTERN struct tty_struct tty_struct[]; / echo x - diffs.shar sed 's/^X//' > diffs.shar << '/' Xecho x - Makefile.diff Xsed 's/^X//' > Makefile.diff << '/' XX11c11 XX< table.o stdmp.o XX--- XX> table.o stdmp.o strs232.o X/ Xecho x - clock.c.diff Xsed 's/^X//' > clock.c.diff << '/' XX201a202,203 XX> if ((( int )realtime & 3 ) == 0 ) /* call only every 4th tick */ XX> rs_flush(); /* flush RS232 buffer */ X/ Xecho x - stmain.c.diff Xsed 's/^X//' > stmain.c.diff << '/' XX229,230c229,232 XX< MFP->mf_ierb |= (IB_DINT|IB_AINT|IB_TIMC|IB_PBSY); XX< MFP->mf_imrb |= (IB_DINT|IB_AINT|IB_TIMC|IB_PBSY); XX--- XX> MFP->mf_iera |= (IA_SRI|IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); XX> MFP->mf_imra |= (IA_SRI|IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); XX> MFP->mf_ierb |= (IB_DINT|IB_AINT|IB_TIMC|IB_SCTS|IB_SDCD|IB_PBSY); XX> MFP->mf_imrb |= (IB_DINT|IB_AINT|IB_TIMC|IB_SCTS|IB_SDCD|IB_PBSY); XX262,264c264 XX< siaint(t) {fake_int(SIAINT, t);} XX< mdiint(t) {fake_int(MDIINT, t);} XX< iob(t) {fake_int(IOB, t);} XX--- XX> mdiint(t) {fake_int(MDIINT, t);} X/ Xecho x - tty.c.diff Xsed 's/^X//' > tty.c.diff << '/' XX49a50 XX> EXTERN int output_done; XX67c68,121 XX< case TTY_CHAR_INT: do_charint(&tty_mess); break; XX--- XX> case TTY_O_DONE: XX> case TTY_CHAR_INT: XX> /* The TTY task can generate two kinds of interrupts: XX> * - a character has been typed on the console or an XX> * RS232 line XX> * - an RS232 line has completed a write request (on XX> * behalf of a user) XX> * If either interrupt happens and the TTY task is idle, XX> * the task gets the interrupt message immediately and XX> * processes it. However, if the TTY task is busy, a bit XX> * is set in 'busy_map' and the message pointer stored. XX> * If multiple messages happen, the bit is only set once. XX> * No input data is lost even if this happens because all XX> * the input messages say is that there is some input. XX> * The actual input is in the tty_driver_buf array, so XX> * losing a message just means that when the one interrupt- XX> * generated message is given to the TTY task, it will find XX> * multiple characters in tty_driver_buf. XX> * XX> * The introduction of RS232 lines has complicated this XX> * situation somewhat. Now a message can mean that some XX> * RS232 line has finished transmitting all the output XX> * given to it. If a character is typed at the instant XX> * an RS232 line finishes, one of the two messages may be XX> * overwritten because MINIX only provides single buffering XX> * for interrupt messages (in proc.c). To avoid losing XX> * information, whenever an RS232 line finishes, the flag XX> * tty_waiting is set to COMPLETED and kept that way until XX> * its completion is processed and a message sent to FS XX> * saying that output is done. The number of RS232 lines in XX> * COMPLETED state is kept in output_done, which is checked XX> * on each interrupt, so that a lost TTY_O_DONE line XX> * completion interrupt will be quickly recovered. XX> * XX> * In short, when this procedure is called, it can check XX> * for RS232 line done by inspecting output_done and it XX> * can check for characters in the input buffer by XX> * inspecting tty_driver_buf[0]. Thus losing a message to XX> * the TTY task is not serious because the underlying XX> * conditions are explicitly checked for on each interrupt. XX> */ XX> XX> /* First check to see if the RS232 line has completed. */ XX> if ( output_done > 0 ) XX> /* If a message is sent to FS for XX> * RS232 done, don't process any XX> * input characters now for fear XX> * of sending a second message to XX> * FS, which would be lost. XX> */ XX> do_o_done(tp); XX> else XX> do_charint( &tty_mess ); XX> break; XX73d126 XX< case TTY_O_DONE: /* reserved for future use (RS-232 terminals)*/ XX103c156 XX< n = n + n; /* each char occupies 2 bytes */ XX--- XX> n <<= 1; /* each char occupies 2 bytes */ XX295c348 XX< tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_TRY_AGAIN,0L,0L); XX--- XX> tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO, 0L, 0L); XX393c446 XX< int replyee, caller; XX--- XX> int result, replyee, caller; XX400,402c453,456 XX< replyee = (int) tp->tty_otcaller; XX< caller = (int) tp->tty_outproc; XX< tty_reply(TASK_REPLY, replyee, caller, code, 0L, 0L); XX--- XX> result = ( tp == &tty_struct[RS232] ? REVIVE : TASK_REPLY ); XX> replyee = (int) tp->tty_otcaller; XX> caller = (int) tp->tty_outproc; XX> tty_reply(result, replyee, caller, code, 0L, 0L); XX418a473,479 XX> int caller, replyee; XX> XX> /* If the slot is already in use, better return an error than mess it up. */ XX> /* if (tp->tty_outleft > 0) { /* if someone else is hanging, give up */ XX> /* tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO, 0L, 0L); XX> return; XX> }*/ XX443a505,514 XX> XX> /* If output is for a bitmapped terminal as the ATARI ST console, the output- XX> * routine will return at once so there is no need to suspend the caller, XX> * on ascii terminals however, the call is suspended and later revived. XX> */ XX> if (m_ptr->TTY_LINE == RS232) { XX> caller = (int) tp->tty_outproc; XX> replyee = (int) tp->tty_otcaller; XX> tty_reply(TASK_REPLY, replyee, caller, SUSPEND, 0L, 0L); XX> } XX467a539,545 XX> if ( m_ptr->TTY_LINE == RS232 ) XX> { /* set the new speed only if it's legal, store it temp here */ XX> int new_speed; XX> new_speed = ( int )( m_ptr->TTY_FLAGS >> 16 ); XX> if ( new_speed ) tp->tty_speed = new_speed; XX> set_uart( tp->tty_mode, tp->tty_speed ); XX> } XX484c562 XX< flags = (long) tp->tty_mode; XX--- XX> flags = ((long) tp->tty_speed << 16 ) | (long) tp->tty_mode; XX587a666 XX> if ( tp == &tty_struct[RS232] ) rs232_sig(); /* only RS232 */ XX618a698,700 XX> case RS232: XX> rs232init(); XX> break; XX623a706,721 XX> XX> XX> /*===========================================================================* XX> * do_o_done * XX> *===========================================================================*/ XX> PRIVATE do_o_done( tp ) XX> register struct tty_struct *tp; /* pointer to tty struct */ XX> { XX> /* A write request on the RS232 line has completed. Send FS a message. */ XX> XX> if ( tp->tty_waiting == COMPLETED ) XX> { XX> finish( tp, tp->tty_cum ); XX> output_done--; XX> } XX> } X/ Xecho x - tty.h.diff Xsed 's/^X//' > tty.h.diff << '/' XX1,2c1,3 XX< #define NR_TTYS 1 /* how many terminals can system handle */ XX< #define CONSOLE 0 /* line number for console */ XX--- XX> #define NR_TTYS 2 /* how many terminals can system handle */ XX> #define CONSOLE 0 /* line number for console */ XX> #define RS232 1 /* line number for serial-io */ XX8c9 XX< #define MAX_OVERRUN 16 /* size of overrun input buffer */ XX--- XX> #define MAX_OVERRUN 126 /* size of overrun input buffer */ XX32a34 XX> int tty_speed; /* low_byte is ispeed; high byte is ospeed */ XX67,68c69,71 XX< XX< EXTERN struct tty_struct tty_struct[]; XX--- XX> #define COMPLETED 2 /* output done; send completion message */ XX> XX> EXTERN struct tty_struct tty_struct[]; X/ / exit 0