SRI-NOSC/dmr/ffille
etty.c Q H#
/* Revision - New handshake handler */
/*
* general TTY subroutines
*/
#include "param.h"
#include "systm.h"
#include "user.h"
/*#include "userx.h"*/
#include "tty.h"
#include "proc.h"
/*#include "procx.h"*/
#include "inode.h"
/*#include "inodex.h"*/
#include "file.h"
/*#include "filex.h"*/
#include "reg.h"
#include "conf.h"
#define DLDELAY 4
/*
* The actual structure of a clist block manipulated by
* getc and putc (mch.s)
*/
struct cblock {
struct cblock *c_next;
char info[6];
};
/* Structure to select one char out of queue */
struct {
char q_char;
};
/* The character lists-- space for 6*NCLIST characters */
struct cblock cfree[NCLIST];
/* List head for unused character blocks. */
struct cblock *cfreelist;
/*
* structure of device registers for KL, DL, and DC
* interfaces-- more particularly, those for which the
* SSTART bit is off and can be treated by general routines
* (that is, not DH).
*/
struct {
int ttrcsr;
int ttrbuf;
int tttcsr;
int tttbuf;
};
/*
* routine called on first teletype open.
* establishes a process group for distribution
* of quits and interrupts from the tty.
*/
ttyopen(dev, atp)
struct tty *atp;
{
register struct proc *pp;
register struct tty *tp;
pp = u.u_procp;
tp = atp;
if(pp->p_pgrp == 0) {
pp->p_pgrp = pp->p_pid;
u.u_ttyp = tp;
u.u_ttyd = dev;
tp->t_pgrp = pp->p_pid;
}
if ((tp->t_state & ISOPEN) == 0)
{
tp->t_asize = TTACK;
tp->t_enq = CENQ;
tp->t_ack = CACK;
tp->t_esc = CESC;
tp->t_cntla = CSPEC;
tp->t_freeze = CFREEZE;
tp->t_thaw = CTHAW;
tp->t_hold = CHOLD;
tp->t_release = CREL;
tp->t_retype = CRETYPE;
tp->t_clear = CCLEAR;
tp->t_silent = CSILENT;
tp->t_atime = 60;
tp->t_alwat = (tp->t_asize&0377) >> 1;
}
tp->t_state =& ~WOPEN;
tp->t_state =| ISOPEN;
}
/*
* The routine implementing the gtty system call.
* Just call lower level routine and pass back values.
*/
gtty()
{
int v[3];
register *up, *vp;
vp = v;
sgtty(vp);
if (u.u_error)
return;
up = u.u_arg[0];
suword(up, *vp++);
suword(++up, *vp++);
suword(++up, *vp++);
}
/*
* The routine implementing the stty system call.
* Read in values and call lower level.
*/
stty()
{
register int *up;
up = u.u_arg[0];
u.u_arg[0] = fuword(up);
u.u_arg[1] = fuword(++up);
u.u_arg[2] = fuword(++up);
sgtty(0);
}
/*
* Stuff common to stty and gtty.
* Check legality and switch out to individual
* device routine.
* v is 0 for stty; the parameters are taken from u.u_arg[].
* c is non-zero for gtty and is the place in which the device
* routines place their information.
*/
sgtty(v)
int *v;
{
register struct file *fp;
register struct inode *ip;
if ((fp = getf(u.u_ar0[R0])) == NULL)
return;
ip = fp->f_inode;
if ((ip->i_mode&IFMT) != IFCHR) {
u.u_error = ENOTTY;
return;
}
(*cdevsw[ip->i_addr[0].d_major].d_sgtty)(ip->i_addr[0], v);
}
/*
* Wait for output to drain, then flush input waiting.
*/
wflushtty(atp)
struct tty *atp;
{
register struct tty *tp;
tp = atp;
spl5();
while (tp->t_outq.c_cc) {
tp->t_state =| ASLEEP;
sleep(&tp->t_outq, TTOPRI);
}
flushtty(tp);
spl0();
}
/*
* Initialize clist by freeing all character blocks, then count
* number of character devices. (Once-only routine)
*/
cinit()
{
register int ccp;
register struct cblock *cp;
register struct cdevsw *cdp;
ccp = cfree;
for (cp=(ccp+07)&~07; cp <= &cfree[NCLIST-1]; cp++) {
cp->c_next = cfreelist;
cfreelist = cp;
}
ccp = 0;
for(cdp = cdevsw; cdp->d_open; cdp++)
ccp++;
nchrdev = ccp;
}
/*
* flush all TTY queues
*/
flushtty(atp)
struct tty *atp;
{
register struct tty *tp;
register int sps;
sps = PS->integ;
spl5();
tp = atp;
while (getc(&tp->t_canq) >= 0);
while (getc(&tp->t_outq) >= 0);
wakeup(&tp->t_canq);
wakeup(&tp->t_outq);
PS->integ = sps;
}
/*
* Place a character on can TTY input queue, putting in delimiters
* and waking up top half as needed.
* Also echo if required.
* The arguments are the character and the appropriate
* tty structure.
*/
/* Echo places a character on the appropriate tty's output queue, and starts
* it up. Also, some processing to output certain control characters is done */
echo(ac,atp)
register struct tty *atp;
{
if (ac < 0 || ((atp->t_flags & ECHO) == 0)) return;
if (ac <= 037 && (ac < 07 || ac > 012))
{
echo ('^',atp);
ac =+ 0100;
}
ttyoutput(ac,atp);
ttstart(atp);
}
echostr(s,tp)
register char *s;
register struct tty *tp;
{
if ((tp->t_flags & ECHO) == 0) return;
while(*s) putc(*s++,&tp->t_outq);
ttstart(tp);
}
ttcursor(x,y,tp)
register struct tty *tp;
{
if ((tp->t_flags & ECHO) == 0) return;
echostr("\033Y",tp); /* escape sequence */
putc(x+040,&tp->t_outq); /* row */
putc(y+040,&tp->t_outq); /* col */
putc(0201,&tp->t_outq); /* vt52 delay */
ttstart(tp);
tp->t_col = y;
}
ttretype(tp)
register struct tty *tp;
{
register cptr;
cptr = tp->t_llf; /* start from end of last line */
/* if ((cptr = tp->t_llf) == 0)
cptr = tp->t_canq.c_cf; */
if (tp->t_canq.c_cc)
while (cptr != tp->t_canq.c_cl) {
if ((cptr & 07) == 0)
if ( (cptr = &((cptr - 010)->c_next->info[0]))
== tp->t_canq.c_cl )
break;
echo(cptr->q_char,tp);
cptr++;
}
}
char *tterase "\b \b";
char *ttclear "\033H\033J";
char *ttforw "\033C";
char *ttkill "\033K";
ttyinput(ac,atp)
struct tty *atp;
{
register int t_flags, c;
register struct tty *tp;
int cptr;
int cano; /* type of terminal */
/* tk_nin =+ 1;*/
tp = atp; c=ac&0377; t_flags = tp->t_flags; /* Load registers */
if ((tp->t_flag2 & LITIN) == 0) c =& 0177;
if (tp->t_flag2 & (RACK | WACK))
{ if ((tp->t_flag2 & WACK) && (c == (tp->t_ack & 0377)))
{
tp->t_acnt = tp->t_asize;
wakeup(&tp->t_acnt);
return;
}
if ((tp->t_flag2 & RACK) && (c == (tp->t_enq & 0377)))
{
if ((tp->t_canq.c_cc <= tp->t_alwat) || /* ack if possible */
(tp->t_llf == tp->t_canq.c_cf))
{
putc(tp->t_ack,&tp->t_outq);
ttstart(tp);
}
else
tp->t_state =| ENQRCV;
return;
}
if (tp->t_state & ESCRCV)
{
tp->t_state =& ~ESCRCV;
switch(c)
{
case CESC1: c = tp->t_enq; break;
case CESC2: c = tp->t_ack; break;
}
}
else if (c == (tp->t_esc & 0377))
{
tp->t_state =| ESCRCV;
return;
}
}
if ((tp->t_flag2 & WHOLD) && !(tp->t_state & HELD)
&& (tp->t_canq.c_cc >= tp->t_asize))
{ /* send a HOLD character */
tp->t_state =| HELD;
putc(tp->t_hold, &tp->t_outq);
ttstart(tp);
}
if (tp->t_flag2 & LITIN) /* Literal input */
{
if (tp->t_canq.c_cc >= TTYHOG) return;
putc(c,&tp->t_canq);
tp->t_llf = tp->t_canq.c_cl; /* set llf */
wakeup(&tp->t_canq); /* wake up!! */
return;
}
if (t_flags & CRMOD)
if (c == '\r') c = '\n';
/* following misfeature flushed 5/15/79 --KLH
else if (c == '\n') c = '\r' */
if (((c==tp->t_intr) || (c==tp->t_quit) || (c==tp->t_cntla))
&& ((tp->t_flag2 & EEI) || ((t_flags & RAW) == 0)))
{
if (c == tp->t_intr)
signal (tp->t_pgrp,SIGINT);
else
signal (tp->t_pgrp, c==tp->t_quit?SIGQIT:SIGSPC);
flushtty (tp);
tp->t_state =& ~FROZEN; /* signals thaw tty */
echo(c,tp);
echo('\n',tp);
return;
}
if (tp->t_canq.c_cc >= TTYHOG) {
if (t_flags & RAW) return;
if ((c != tp->t_erase) && (c != tp->t_kill)) return;
}
switch(tp->t_cano) {
case TC_GT40:
case TC_TERM:
case TC_VT52:
cano = 1;
break;
default:
cano = 0;
break;
}
if (t_flags & LCASE && c >= 'A' && c <= 'Z') /* Convert to lower case if necessary */
c =+ 'a' - 'A' ;
if (t_flags & RAW)
{
putc(c,&tp->t_canq);
}
else if (c == tp->t_erase)
{
c = -1;
if ((tp->t_llf != tp->t_canq.c_cl ) &&
((c = unputc(&tp->t_canq)) >= 0))
if (cano) { /* special terminals */
switch (partab[c] & 077) {
case 1: /* non - printing */
if (c <= 012 && c >= 07) break;
case 5:
case 6:
echostr(tterase,tp);
tp->t_col--;
case 0: /* normal */
echostr(tterase,tp);
tp->t_col--;
break;
case 2:
echostr(ttforw,tp);
tp->t_col++;
break;
case 4:
ttcursor(0136,tp->t_delpos,tp);
ttretype(tp);
break;
}
c = -1;
/* normal printing terminal delete */
} else
if ((tp->t_state & ERMODE) == 0)
{
echo('\\',tp);
tp->t_state =| ERMODE;
}
}
else
{
if (tp->t_state & ERMODE) /* If in erase mode, */
{
echo('\\',tp); /* echo '\' to indicate out of erase mode */
tp->t_state =& ~ERMODE; /* and turn it off */
}
if (c == tp->t_retype)
{
if (cano) ttcursor(0136,tp->t_delpos,tp);
else {
echo(c,tp);
echo('\n',tp);
}
ttretype(tp);
c = -1;
}
else if (c == tp->t_kill)
{
if (cano) {
ttcursor(0136,tp->t_delpos,tp);
echostr(ttkill,tp);
} else {
echo (c,atp);
echo('\n',tp);
}
while ((tp->t_llf != tp->t_canq.c_cl) &&
(unputc(&tp->t_canq) > 0)) ; /* flush till empty or end-of-line */
c = -1;
}
else if (c == tp->t_EOT) /* End of file indicator */
{
putc(c,&tp->t_canq);
c = -2;
}
else if (c == tp->t_silent)
{
flushtty(tp);
echo (c,tp); echo ('\n',tp); echo ('\n',tp);
if (tp->t_flag2 & SILENT)
tp->t_flag2 =& ~SILENT;
else tp->t_flag2 =| SILENT;
}
else if (c == tp->t_clear)
{
if (cano) echostr(ttclear,tp);
else {
echo(c,tp);
echo('\n',tp);
}
ttretype(tp);
tp->t_delpos = 0;
c = -1;
}
else if (c == tp->t_freeze)
{ tp->t_state =| FROZEN; /* freeze the screen */
return;
}
else if (c == tp->t_thaw)
{ tp->t_state =& ~FROZEN; /* wakeup output */
wakeup(&tp->t_outq);
return;
}
else
putc(c,&tp->t_canq); /* Anything else goes straight to can queue */
}
echo(c,tp); /* Echo the character */
if (tp->t_canq.c_cc == 1 || (tp->t_llf&07) == 0)
tp->t_llf = tp->t_canq.c_cf; /* Initialize t_llf */
if (t_flags & RAW || c == '\n' || c == -2) /* If line delimiter, wake up canan() */
{
tp->t_delpos = 0; /* for kill processing */
tp->t_llf = tp->t_canq.c_cl;
wakeup(&tp->t_canq);
}
return; /* (Implied return anyway) */
}
/*
* put character on TTY output queue, adding delays,
* expanding tabs, and handling the CR/NL bit.
* It is called both from the top half for output, and from
* interrupt level for echoing.
* The arguments are the character and the tty structure.
*/
ttyoutput(ac, tp)
struct tty *tp;
{
register int c;
register struct tty *rtp;
register char *colp;
int ctype,sps;
/* tk_nout =+ 1;*/
rtp = tp;
c = ac;
if (rtp->t_flag2 & SILENT) return(0);
if ((rtp->t_flag2 & (RACK | WACK))
&& ((c == tp->t_enq) || (c == tp->t_ack) ||
(c == tp->t_esc)))
{
if (putc(rtp->t_esc,&rtp->t_outq)) return(1);
if (c == rtp->t_enq) c = CESC1;
else if (c == rtp->t_ack) c = CESC2;
}
if (rtp->t_flag2 & LITOUT) /* Literal output */
{
if (putc(c, &rtp->t_outq))
return(1);
else
{
if (rtp->t_acnt) rtp->t_acnt--;
return(0);
}
}
c =& 0177;
/*
* Ignore EOT in normal mode to avoid hanging up
* certain terminals.
*/
if (c==004 && (rtp->t_flags&(RAW|WACK|RACK))==0)
return(0);
/*
* Turn tabs to spaces as required
*/
if (c=='\t' && rtp->t_flags&XTABS) {
do
if (ttyoutput(' ', rtp)) return(1);
while (rtp->t_col&07);
return(0);
}
/*
* for upper-case-only terminals,
* generate escapes.
*/
if (rtp->t_flags&LCASE) {
colp = "({)}!|^~'`";
while(*colp++)
if(c == *colp++) {
if (ttyoutput('\\', rtp)) return(1);
c = colp[-2];
break;
}
if ('a'<=c && c<='z')
c =+ 'A' - 'a';
}
/*
* turn <nl> to <cr><lf> if desired.
*/
if (c=='\n') if (ttyoutput('\r', rtp)) return(1);
if (putc(c, &rtp->t_outq)) return(1); /* put char in buffer */
if (rtp->t_acnt) rtp->t_acnt--;
/*
* Calculate delays.
* The numbers here represent clock ticks
* and are not necessarily optimal for all terminals.
* The delays are indicated by characters above 0200,
* thus (unfortunately) restricting the transmission
* path to 7 bits.
*/
colp = &rtp->t_col;
ctype = partab[c];
c = 0;
switch (ctype&077) {
/* ordinary */
case 0:
(*colp)++;
/* non-printing */
case 1:
break;
/* backspace */
case 2:
if (*colp)
(*colp)--;
break;
/* newline */
case 3:
ctype = (rtp->t_flags >> 8) & 03;
if(ctype == 1) { /* tty 37 */
if (*colp)
c = max((*colp>>4) + 3, 6);
} else
if(ctype == 2) { /* vt05 */
c = 6;
}
*colp = 0;
break;
/* tab */
case 4:
ctype = (rtp->t_flags >> 10) & 03;
if(ctype == 1) { /* tty 37 */
c = 1 - (*colp | ~07);
if(c < 5)
c = 0;
}
*colp =| 07;
(*colp)++;
break;
/* vertical motion */
case 5:
if(rtp->t_flags & VTDELAY) /* tty 37 */
c = 0177;
break;
/* carriage return */
case 6:
ctype = (rtp->t_flags >> 12) & 03;
if(ctype == 1) { /* tn 300 */
c = 5;
} else
if(ctype == 2) { /* ti 700 */
c = 10;
}
*colp = 0;
}
if(c) putc(c|0200, &rtp->t_outq); /* put in delay unless zero */
return(0); /* we always return 0 here because if inserting
the delay char fails, we can just ignore. */
}
/*
* Restart typewriter output following a delay
* timeout.
* The name of the routine is passed to the timeout
* subroutine and it is called during a clock interrupt.
*/
ttrstrt(atp)
{
register struct tty *tp;
tp = atp;
tp->t_state =& ~TIMEOUT;
ttstart(tp);
}
/*
* Start output on the typewriter. It is used from the top half
* after some characters have been put on the output queue,
* from the interrupt routine to transmit the next
* character, and after a timeout has finished.
* If the SSTART bit is off for the tty the work is done here,
* using the protocol of the single-line interfaces (KL, DL, DC);
* otherwise the address word of the tty structure is
* taken to be the name of the device-dependent startup routine.
*/
ttstart(atp)
struct tty *atp;
{
register int *addr, c;
int sps;
register struct tty *tp;
struct { int (*func)(); };
tp = atp;
addr = tp->t_addr;
if (tp->t_state&SSTART) {
(*addr.func)(tp);
return;
}
sps = PS->integ;
spl5();
if ((addr->tttcsr&DONE)==0 || tp->t_state&TIMEOUT)
return;
if ((c=getc(&tp->t_outq)) >= 0) {
if (tp->t_flag2 & LITOUT) /* Literal output */
addr->tttbuf = c;
else if (c<=0177)
addr->tttbuf = c | (partab[c]&0200);
else {
timeout(ttrstrt, tp, (c&0177) + DLDELAY);
tp->t_state =| TIMEOUT;
}
}
PS->integ = sps;
}
/*
* Called from device's read routine after it has
* calculated the tty-structure given as argument.
* The pc is backed up for the duration of this call.
* In case of a caught interrupt, an RTI will re-execute.
*/
ttread(atp)
struct tty *atp;
{
register struct tty *tp;
register int c;
tp = atp;
tp->t_flag2 =& ~SILENT;
spl5();
while ((tp->t_canq.c_cc == 0) || (tp->t_llf == tp->t_canq.c_cf))
{
if ((tp->t_state & CARR_ON) == 0)
return;
sleep(&tp->t_canq,TTIPRI);
}
spl0();
while ((tp->t_canq.c_cf) && (tp->t_llf != tp->t_canq.c_cf))
{
c = getc (&tp->t_canq);
if (tp->t_canq.c_cc <= tp->t_alwat)
{
if ((tp->t_flag2 & RACK) && (tp->t_state & ENQRCV))
{
tp->t_state =& ~ENQRCV;
while (putc(tp->t_ack, &tp->t_outq)) sleep(&lbolt,22);
ttstart(tp);
}
if ((tp->t_flag2 & WHOLD) && (tp->t_state & HELD))
{
tp ->t_state =& ~HELD;
while (putc(tp->t_release, &tp->t_outq)) sleep(&lbolt,22);
ttstart(tp);
}
}
if (tp->t_flags & RAW)
{
passc(c);
break;
}
if ((c == tp->t_EOT) || passc(c) < 0 || c == '\n')
break;
}
}
/*
* wakes up process waiting for an acknowledge if the
* ACKWAIT bit in t_state is still set.
*/
ttywakeup(atp)
register struct tty *atp;
{
if (atp->t_state & ACKWAIT)
{
atp->t_state =& ~ACKWAIT;
wakeup(&atp->t_acnt);
}
}
/*
* Called from the device's write routine after it has
* calculated the tty-structure given as argument.
*/
ttwrite(atp)
struct tty *atp;
{
register struct tty *tp;
register int c;
tp = atp;
if ((tp->t_state&CARR_ON)==0)
return;
while ((c=cpass())>=0) {
spl5();
while(tp->t_state & FROZEN)
sleep(&tp->t_outq, TTOPRI); /* wait for thaw */
while (tp->t_outq.c_cc > TTHIWAT) {
ttstart(tp);
tp->t_state =| ASLEEP;
sleep(&tp->t_outq, TTOPRI);
}
while((tp->t_flag2 & WACK) && (tp->t_acnt == 0))
{
while (putc(tp->t_enq, &tp->t_outq)) sleep(&lbolt,22);
ttstart(tp);
if ((tp->t_state & ACKWAIT) == 0)
{
timeout(ttywakeup,tp,tp->t_atime);
tp->t_state =| ACKWAIT;
}
sleep(&tp->t_acnt,TTOPRI);
}
spl0();
while (ttyoutput(c, tp)) sleep(&lbolt, 21);
}
tp->t_delpos = tp->t_col;
ttstart(tp);
}
/*
* Common code for gtty and stty functions on typewriters.
* If v is non-zero then gtty is being done and information is
* passed back therein;
* if it is zero stty is being done and the input information is in the
* u_arg array.
*/
ttystty(atp, av)
int *atp, *av;
{
register *tp, *v;
tp = atp;
if(v = av) {
*v++ = tp->t_speeds;
v->lobyte = tp->t_erase;
v->hibyte = tp->t_kill;
v[1] = tp->t_flags;
return(1);
}
wflushtty(tp);
v = u.u_arg;
tp->t_speeds = *v++;
tp->t_erase = v->lobyte;
tp->t_kill = v->hibyte;
tp->t_flags = v[1];
return(0);
}
/* common code for ttymode handlers */
ttmode(atp,acp)
int *acp;
char atp[];
/* Rather than considering atp as a pointer to a tty structure, it is treated
* as an array of bytes, so that the individual bytes can be referenced as an
* offset from the base, rather than being individually selected via ->.
*/
{
register bn,bits;
register int *cp;
cp = acp;
bits = (*cp) & TBITS; /* extract argument bits
*/
if ((bn = (((*cp)&TBYTNUM)>>8)) > TMAXBN) /* extract byte number, and check for validity */
{
u.u_error = EINVAL; /* invalid argument */
return(1);
}
if ((*cp) & TFLUSH) wflushtty(atp); /* request to flush buffer first*/
*cp = ((*cp) & 0177400) + (atp[TFIXOFS+bn] & 0377); /* current value placed in *cp */
switch((*cp) & TCNTL) /* control bits */
{
case TCLEAR: /* bit clear */
atp[TFIXOFS + bn] =& ~bits;
break;
case TSET: /* bit set */
atp[TFIXOFS + bn] =| bits;
break;
case TREPLAC:
atp[TFIXOFS + bn] = bits; /* replace */
case TGET: ; /* just get it. (done anyway) */
}
if (((*cp)&TCNTL != TGET) && (bn<6)) /* if speeds or mode changed, return 0. (for dhttymd) */
return(0);
return(1);
}
)dh.c C#
/*
* DH-11 driver
* This driver calls on the DHDM driver.
* If the DH has no DM11-BB, then the latter will
* be fake. To insure loading of the correct DM code,
* lib2 should have dhdm.o, dh.o and dhfdm.o in that order.
*
* This driver was modified to allow the use of multiple
* DH11s. To avail yourself of this feature (or to disable
* it) you should do the following:
*
* In this module: Initialize the global array dhaddrs with
* the base addresses for your dh11s. Initialize NDH11
* to the total number of dh11 ports in your system.
* Dimension dhsar to the number of dh11s you have.
*
* In l.s: When you initialize the interrupt vectors for
* your dh11s, add to each interrupt PS a dh11 index (0
* for the first dh11, 1 for the second etc). This
* number will be used to index into dhaddrs to
* determine which set of registers caused the
* interrupt. It allows all sets of dh registers to use
* the same interrupt routines.
*
* globals:
*
* dhaddrs contains base addresses for the various dh11s in the
* system.
*
* dhsar contains (for each dh11) a copy of the bar as it
* was last known to be.
*
* history:
*
* Initially a Release six driver.
* Modified by Dennis L. Mumaugh for multiple DH/DM support
* 15 April 1977
* Thanks to Mark Kampe (UCLA) for assistance
*/
#include "param.h"
#include "conf.h"
#include "user.h"
/*#include "userx.h"*/
#include "tty.h"
#include "proc.h"
#ifdef DNTTY
#include "baudot.h" /* DN: file containing baudot mapping tables */
#define VRTMO 20+20 /* 60'ths of sec to wait for dropping RTS */
#define IDLTMO (15*60*60)&077777 /* 60'ths of sec to sleep between idle chks */
#endif DNTTY
#ifndef NDH11
#define NDH11 32 /* number of lines */
#endif NDH11
#define DHNCH 8 /* max number of DMA chars */
struct tty dh11[NDH11];
/*
* Place from which to do DMA on output
*/
char dh_clist[NDH11][DHNCH];
/*
* Used to communicate the number of lines to the DM
*/
int ndh11 NDH11;
/*
* Hardware control bits
*/
#ifdef DNTTY
#define BITS5 00 /* DN: for Baudot terms */
#endif DNTTY
#define BITS6 01
#define BITS7 02
#define BITS8 03
#define TWOSB 04
#define PENABLE 020
#define OPAR 040 /* Old DEC manuals wrongly say this sets EVEN parity.*/
#define HDUPLX 040000
#define IENABLE 030100
#define PERROR 010000
#define FRERROR 020000
#define XINT 0100000
#define SSPEED 7 /* standard speed: 300 baud */
/*
* DM control bits
*/
#define TURNON 03 /* CD lead + line enable */
#define TURNOFF 01 /* line enable */
#define RQS 04 /* request to send */
#define XCLUDE 0200 /* exclusive-use flag against open */
/*
* Software copy of last dhbar
*/
int dhsar[2];
struct dhregs {
int dhcsr;
int dhnxch;
int dhlpr;
int dhcar;
int dhbcr;
int dhbar;
int dhbreak;
int dhsilo;
};
int dhaddrs[2] { 0760020, 0760040 };
#ifdef DNTTY
int dnidlflg; /* Set when idle timeout rtn activated */
#endif DNTTY
/*
* Open a DH11 line.
*/
dhopen(dev, flag)
{
register struct tty *tp;
register struct dhregs *dhaddr;
extern dhstart();
#ifdef DNTTY
extern dnidltmo();
if(dnidlflg == 0) {
dnidlflg++;
timeout(dnidltmo, 0, IDLTMO);
}
#endif DNTTY
if (dev.d_minor >= NDH11) {
u.u_error = ENXIO;
return;
}
dhaddr = dhaddrs[ dev.d_minor >> 4 ];
tp = &dh11[dev.d_minor];
tp->t_addr = dhstart;
tp->t_dev = dev;
dhaddr->dhcsr =| IENABLE;
tp->t_state =| WOPEN|SSTART;
if ((tp->t_state&ISOPEN) == 0) {
tp->t_erase = CERASE;
tp->t_kill = CKILL;
tp->t_quit = CQUIT; /* I'm not sure this is the best */
tp->t_intr = CINTR; /* place to set these up but... */
tp->t_EOT = CEOT;
tp->t_speeds = SSPEED | (SSPEED<<8);
tp->t_flags = ODDP|EVENP|ECHO;
#ifdef DNTTY
tp->t_dnflgs = 0;
tp->t_ioct = 1;
/* DN: following line is complete crock to turn off modem
* control for the first DH. It would be unnecessary if
* there was some decent way to set TTY parameters BEFORE
* the open attempt, or if system itself knew more about
* its hardwired line parameters. Can just use null modems,
* but it would sure be nice to have things set right from
* the start.
*/
/* if(dev.d_minor>>4 == 0) tp->t_flags =| DUMC; */
/* another big crock */
if((dev.d_minor&017) < 5) tp->t_flags =| DUMC;
#endif DNTTY
dhparam(tp);
} else if (tp->t_state&XCLUDE && u.u_uid!=0) {
u.u_error = EBUSY;
return;
}
dmopen(dev);
ttyopen(dev, tp);
}
/*
* Close a DH11 line.
*/
dhclose(dev)
{
register struct tty *tp;
tp = &dh11[dev.d_minor];
if (tp->t_flags&HUPCL)
dmctl(dev, TURNOFF);
tp->t_state =& (CARR_ON|SSTART);
#ifdef DNTTY
tp->t_dnflgs =& ~(TMOCTS|TMORTS);
#endif DNTTY
wflushtty(tp);
}
/*
* Read from a DH11 line.
*/
dhread(dev)
{
ttread(&dh11[dev.d_minor]);
}
/*
* write on a DH11 line
*/
dhwrite(dev)
{
ttwrite(&dh11[dev.d_minor]);
}
/*
* DH11 receiver interrupt.
*/
dhrint(dev)
int dev;
{
register struct tty *tp;
register int c;
register struct dhregs *dhaddr;
dhaddr = dhaddrs[dev];
while ((c = dhaddr->dhnxch) < 0) { /* char. present */
tp = &dh11[ (dev<<4) | ((c>>8) & 017) ];
if (tp >= &dh11[NDH11])
continue;
if((tp->t_state&ISOPEN)==0) {
wakeup(tp);
continue;
}
if (c&PERROR)
if ((tp->t_flags&(EVENP|ODDP))==EVENP
|| (tp->t_flags&(EVENP|ODDP))==ODDP )
continue;
if (c&FRERROR) /* break */
if (tp->t_flags&RAW)
c = 0; /* null (for getty) */
else
c = tp->t_intr; /* intr */
#ifdef DNTTY
if (tp->t_dnflgs&BAUDOT){
tp->t_ioct++; /* Bump to mark non-idle */
c = bditab[(c&037)|(tp->t_dnflgs&FIGS ? 040 : 0)]&0377;
/* printf("(I:%o,%o)",ac&0177,c); /* Debug */
switch(c) {
case FIGSCHR: tp->t_dnflgs =| FIGS; continue;
case LETSCHR: tp->t_dnflgs =& ~FIGS; continue;
case 015:
if(tp->t_dnflgs&LICLF){c = 012; break;}
else {tp->t_dnflgs=| LICCR; continue;}
case 012:
if(tp->t_dnflgs&LICCR) break;
else {tp->t_dnflgs=| LICLF; continue;}
}
tp->t_dnflgs =& ~(LICCR | LICLF);
}
#endif DNTTY
ttyinput(c, tp);
}
}
/*
* stty/gtty for DH11
*/
dhsgtty(dev, av)
int *av;
{
register struct tty *tp;
register struct dhregs *dhaddr;
register int *mod;
tp = &dh11[dev.d_minor];
/*
* Special weirdness.
* On stty, if the input speed is 15 (EXT B)
* then the output speed selects a special function.
* The stored modes are not affected.
*/
if (av==0 && (mod=u.u_arg)[0].lobyte==15) {
dhaddr = dhaddrs[dev.d_minor>>4];
switch (mod[0].hibyte) {
/*
* Set break
*/
case 1:
dhaddr->dhbreak =| 1<<(dev.d_minor&017);
return;
/*
* Clear break
*/
case 2:
dhaddr->dhbreak =& ~(1<<(dev.d_minor&017));
return;
/*
* Turn on request to send
*/
case 3:
dmctl(dev, TURNON|RQS);
return;
/*
* Turn off request to send
*/
case 4:
dmctl(dev, TURNON);
return;
/*
* Prevent opens on channel
*/
case 5:
tp->t_state =| XCLUDE;
return;
}
return;
}
if (ttystty(tp, av))
return;
dhparam(tp);
}
/*
* Set parameters from open or stty into the DH hardware
* registers.
*/
dhparam(atp)
struct tty *atp;
{
register struct tty *tp;
register int lpr;
register struct dhregs *dhaddr;
tp = atp;
spl5();
dhaddr = dhaddrs[ tp->t_dev.d_minor >> 4 ];
dhaddr->dhcsr.lobyte = (tp->t_dev.d_minor&017) | IENABLE;
/*
* Hang up line?
*/
if (tp->t_speeds.lobyte==0) {
tp->t_flags =| HUPCL;
dmctl(tp->t_dev, TURNOFF);
return;
}
lpr = (tp->t_speeds.hibyte<<10) | (tp->t_speeds.lobyte<<6);
switch (tp->t_speeds.lobyte) {
#ifdef DNTTY
case BEXTA: /* DN: Crock - Ext A implies baudot */
lpr =| BITS5|TWOSB; /* 5 bits with 1.5 stop bits */
tp->t_dnflgs =| BAUDOT; /* State of FIGS undefined */
break;
#endif DNTTY
case B134: /* 134.5 baud */
lpr =| BITS6|PENABLE|HDUPLX;
break;
case B110: /* 110 baud */
lpr =| TWOSB; /* fall thru to continue */
default:
if (tp->t_flags&EVENP)
if (tp->t_flags&ODDP) lpr =| BITS8;
else lpr =| BITS7|PENABLE;
else lpr =| BITS7|OPAR|PENABLE;
}
dhaddr->dhlpr = lpr;
spl0();
}
/*
* DH11 transmitter interrupt.
* Restart each line which used to be active but has
* terminated transmission since the last interrupt.
*/
dhxint(dev)
int dev;
{
register struct tty *tp;
register ttybit, bar;
struct dhregs *dhaddr;
dhaddr = dhaddrs[dev];
bar = dhsar[dev] & ~dhaddr->dhbar;
dhaddr->dhcsr =& ~XINT;
ttybit = 1;
for (tp = &dh11[dev<<4]; bar; tp++) {
if(bar&ttybit) {
dhsar[dev] =& ~ttybit;
bar =& ~ttybit;
tp->t_state =& ~BUSY;
dhstart(tp);
}
ttybit =<< 1;
}
}
/*
* Start (restart) transmission on the given DH11 line.
*/
dhstart(atp)
struct tty *atp;
{
extern ttrstrt();
#ifdef DNTTY
extern dnrstrt(),dnrtsoff(); /* timeout routines */
#endif DNTTY
register c, nch;
register struct tty *tp;
int sps, dev;
struct dhregs *dhaddr;
char *cp;
sps = PS->integ;
spl5();
tp = atp;
dev = tp-dh11;
dhaddr = dhaddrs[ dev.d_minor >> 4 ];
/*
* If it's currently active, or delaying,
* no need to do anything.
*/
if (tp->t_state&(TIMEOUT|BUSY))
goto out;
/* Commented out; too MIT specific.
* It has been cvted for multi DH/DM tho. --KLH 5/15/79
*/
#ifdef COMMENT
/*
* This routine hacks our line printer. Namely it checks
* if the line printer is busy (dmsecrcv) and if it is,
* goes away for a while.
*/
if ((tp->t_flag2 & SECRX) && dmsecrcv(dev)) {
timeout(ttrstrt, tp, 60);
tp->t_state =| TIMEOUT;
goto out;
}
#endif COMMENT
/*
* t_char is a delay indicator which may have been
* left over from the last start.
* Arrange for the delay.
*/
if ((c = tp->t_char)
#ifdef DNTTY
&& ((c >= 0200) || (!(tp->t_dnflgs&BAUDOT)))
#endif DNTTY
) {
tp->t_char = 0;
timeout(ttrstrt, tp, (c&0177)+6);
tp->t_state =| TIMEOUT;
goto out;
}
#ifdef DNTTY
redo:
#endif DNTTY
cp = dh_clist[dev.d_minor];
nch = 0;
#ifdef DNTTY
if (tp->t_dnflgs&BAUDOT) {
if (!(tp->t_dnflgs&CTS)) { /* If can't send, */
if (dmaskcts(dev)) { /* ask politely */
tp->t_dnflgs =| CTS; /* Won! */
tp->t_dnflgs =& ~TMOCTS; /*may be pending*/
printf(">"); /* Debug crock */
}
else { /* Barf, wait a second. */
if((tp->t_dnflgs&TMOCTS) == 0) {
tp->t_dnflgs =| TMOCTS;
timeout(dnrstrt, tp, 60);
}
goto out;
}
}
if (c = tp->t_char) { /* Holds extra output char */
tp->t_char = 0;
*cp++ = c;
nch--;
}
}
#endif DNTTY
/*
* Copy DHNCH characters, or up to a delay indicator,
* to the DMA area.
*/
while (nch > -DHNCH && (c = getc(&tp->t_outq))>=0) {
if (c >= 0200 && (tp->t_flag2 & LITOUT)==0) {
tp->t_char = c;
break;
}
#ifdef DNTTY
if (tp->t_dnflgs&BAUDOT) {
if ((c = bdtcvt(c,tp)) < 0)
continue; /* May want to flush char */
*cp++ = c;
if ((--nch > -DHNCH) && tp->t_char) {
c = tp->t_char;
tp->t_char = 0;
} /* Drop thru to store */
else continue; /* Already stored char so skip */
}
#endif DNTTY
*cp++ = c;
nch--;
}
/*
* If the writer was sleeping on output overflow,
* wake him when low tide is reached.
*/
if (tp->t_outq.c_cc<=TTLOWAT && tp->t_state&ASLEEP) {
tp->t_state =& ~ASLEEP;
wakeup(&tp->t_outq);
}
/*
* If any characters were set up, start transmission;
* otherwise, check for possible delay.
*/
if (nch) {
dhaddr->dhcsr.lobyte = (dev.d_minor & 017) | IENABLE;
dhaddr->dhcar = cp+nch;
dhaddr->dhbcr = nch;
c = 1 << (dev.d_minor & 017);
dhaddr->dhbar =| c;
dhsar[dev.d_minor>>4] =|c;
tp->t_state =| BUSY;
#ifdef DNTTY
tp->t_dnflgs =& ~(TMOCTS);
tp->t_ioct++; /* Bump IO cnt to mark non-idle */
#endif DNTTY
} else if ((c = tp->t_char)
#ifdef DNTTY
&& ((c >= 0200) || (!(tp->t_dnflgs&BAUDOT)))
#endif DNTTY
) {
tp->t_char = 0;
timeout(ttrstrt, tp, (c&0177)+6);
tp->t_state =| TIMEOUT;
}
#ifdef DNTTY
/* This code contrives to turn off DN modem's RTS lead after
* the last char has left the DH. We cannot turn it off after
* the output-complete interrupt because 2 chars are still in the
* UART, and we can't pad out the delay because baudot terms
* have no padding character... so set up a demon to check things
* after 2 char times (2*(1/6 sec)) have passed.
*/
/* New additional crock: try to ensure that when output
* is done, tty is left in LETS mode rather than FIGS. No
* attempt at extra buffering or optimization is done here,
* because the speeds are so slow (6cps) it is highly probable
* that when the output queue becomes empty, the user program
* really has nothing more to send. We'll see.
*/
else if (tp->t_dnflgs&BAUDOT) {
if(tp->t_dnflgs&FIGS){ /* Crock */
tp->t_char = LETSCHR; /* " */
tp->t_dnflgs =& ~FIGS; /* " */
goto redo; /* " */
} /* " */
/* Now arrange to turn off RTS */
if(tp->t_dnflgs&TMORTS)
outtime(dnrtsoff, tp); /* Remove existing timeout*/
else tp->t_dnflgs =| TMORTS;
timeout(dnrtsoff, tp, VRTMO); /* after last char leaves DH */
}
#endif DNTTY
out:
PS->integ = sps;
}
/* ttymode handler for dh11 */
dhttymd(dev,acp)
int *acp;
{
register struct tty *tp;
tp = &dh11[dev.d_minor];
if (ttmode(tp, acp)) return;
dhparam(tp);
}
/*
* DN Baudot TTY support - output conversion
*/
#ifdef DNTTY
/* All ASCII transformations now done -- Hack baudot here
* if necessary (note LCASE should have done some work too)
*/
bdtcvt(ac,atp)
int ac;
struct tty *atp;
{
register struct tty *tp;
register int c;
tp = atp;
c = ac;
if (c >= 0140) c =& 0137; /* At this point, be merciless about case. */
if(c < 040) /* If a control char, check special cases */
switch (c) {
case '\r': c = 0210; break;
case '\n': c = 0202; break;
case 007: c = 053; break; /* ^G - bell */
case 006: c = FIGSCHR; break; /* ^F - force FIGS */
case 014: c = LETSCHR; break; /* ^L - force LETS */
default: return(-1);
}
else c = bdotab[c-040]&0377;
/* printf("(O:%o,%o)\n",ac,c); /* Debug */
if (c&0200) {
if(c==NOCH) c = 04; /* for now, cvt randoms to SP */
switch (c) {
case FIGSCHR: tp->t_dnflgs=|FIGS; break;
case LETSCHR: tp->t_dnflgs=& ~FIGS; break;
case 0202: /* Special crock for LF */
tp->t_char = LETSCHR&037;/* Follow with LETS */
tp->t_dnflgs=& ~FIGS;
break;
}
return(c&037);
}
if(c&040 && !(tp->t_dnflgs&FIGS)) { /* Wants FIGS and not in? */
tp->t_char = c&037; /* Store char */
tp->t_dnflgs =| FIGS;
return(FIGSCHR&037);
}
if(!(c&040) && tp->t_dnflgs&FIGS) { /* Wants LETS and not in? */
tp->t_char = c&037; /* Store char */
tp->t_dnflgs =& ~FIGS;
return(LETSCHR&037);
}
return(c&037);
}
#endif DNTTY
/*
* DN Baudot TTY support - timeout routines
*/
/* Both of these routines are called with spl = 5 from the clock
* interrupt routine, so need not worry about DH or DM interrupts.
* Likewise, they won't be executed if already at some int level,
* so DH/DM int level rtns don't need to worry about these either.
*/
#ifdef DNTTY
dnrstrt(atp)
struct tty *atp;
{
extern dnrstrt();
register struct tty *tp;
tp = atp;
printf("X"); /* Debug hack */
if (tp->t_dnflgs&TMOCTS) /* Still need CTS check? */
if((tp->t_state&ISOPEN) == 0) { /* For redundant safety */
tp->t_dnflgs =& ~TMOCTS;
return;
}
if(tp->t_state&BUSY || dmaskcts(tp->t_dev)) {
tp->t_dnflgs =& ~TMOCTS;
tp->t_dnflgs =| CTS;
dhstart(tp);
}
else timeout(dnrstrt, tp, 60);
}
dnrtsoff(atp)
struct tty *atp;
{
register struct tty *tp;
tp = atp;
if (tp->t_dnflgs&TMORTS) {
tp->t_dnflgs =& ~TMORTS;
if (!(tp->t_state&BUSY)) {
dmrtsoff(tp->t_dev);
tp->t_dnflgs =& ~CTS;
printf("O"); /* Debug hack */
}
}
}
#endif DNTTY
/*
* "outtime" - DN addition.
* The reverse of the "timeout" kernel routine; removes
* an entry from the clock queue.
* Called with the same params as timeout, except the third
* argument isn't furnished. If outtime finds an entry with
* the same argument and function, it will remove it.
* It is even safe to call this while the clock routine is
* hacking the queue; it checks for imminent execution and
* substitutes a null routine if so.
* It doesn't look for more than one entry, although it could.
* (remove the break and ensure p1 is preserved during entry flush).
*/
#ifdef DNTTY
#include "systm.h"
outtime(fun, arg)
{
extern nullrtn();
register struct callo *p1, *p2;
register a;
int s;
a = arg;
p1 = &callout[0];
s = PS->integ;
spl7();
while(p1->c_func != 0) {
if(p1->c_arg == a && p1->c_func == fun) {
if(p1->c_time <= 0) p1->c_func = &nullrtn;
else {
p2 = p1++;
while(p2->c_func = p1->c_func) {
p2->c_time = p1->c_time;
p2->c_arg = p1->c_arg;
p1++; p2++;
}
}
break;
}
p1++;
}
PS->integ = s;
}
nullrtn(dummy)
{
}
#endif DNTTY
/**/
/* Idle timeout routine -- called every IDLTMO ticks
* to see if any lines have been inactive too long & need hangup.
*/
#ifdef DNTTY
dnidltmo()
{ register i;
register struct tty *tp;
for (tp = &dh11[0]; tp < &dh11[NDH11]; tp++)
if(tp->t_dnflgs&BAUDOT)
{ if ((tp->t_state&CARR_ON) && (tp->t_ioct == 0))
dhclose(tp->t_dev);
tp->t_ioct = 0;
}
timeout(dnidltmo, 0, IDLTMO);
}
#endif DNTTY
dhdm.c % 3#
/*
* DM-BB driver
*
* This driver has been modified to support multiple DM11s,
* in order to avail yourself of it you must do the
* following.
*
* In this module:
* Initialize the array dmaddrs to contain the base
* addresses of your DM11s.
*
* In l.s:
* When you set up the interrupt vectors for the
* DM11s, you should add a DM11 index number to the
* interrupt PS for each vector (0 for the first
* one, 1 for the second, etc.) This index will be
* passed to the interrupt routine so that it can
* tell which DM11 caused the interrupt. This is
* done so that one interrupt routine can service
* the interrupts from all of the DM11s.
*
* globals:
* dmaddrs array of pointers to the sets of dm11 registers.
*
* history:
*
* Started out as a standard release 6 DM11 driver.
* Modified for Multi DM support by Dennis L. Mumaugh
* 15 April 1977
* Thanks to Mark Kampe (UCLA) for assistance.
*/
#include "param.h"
#include "tty.h"
#include "conf.h"
int dmaddrs[2] {0170500, 0170510};
struct tty dh11[];
int ndh11; /* Set by dh.c to number of lines */
#define BUSY 020 /* for CSR, not line status reg */
#define SECRX 020
#define DONE 0200
#define SCENABL 040
#define CLSCAN 01000
#define TURNON 03 /* CD lead, line enable */
#define TURNOFF 1 /* line enable only */
#define CARRIER 0100
#ifdef DNTTY
#define DMRTS 04
#define DMCTS 040
#endif DNTTY
struct dmregs {
int dmcsr;
int dmlstat;
};
/*
* Turn on the line associated with the (DH) device dev.
*/
dmopen(dev)
{
register struct tty *tp;
register struct dmregs *dmaddr;
dmaddr = dmaddrs[dev.d_minor >> 4];
tp = &dh11[dev.d_minor];
dmaddr->dmcsr = dev.d_minor&017;
if (tp->t_flags&DUMC){ /* KLH: if don't want modem ctl, */
dmaddr->dmlstat = 0; /* turn it off for line */
tp->t_state =| CARR_ON; /* pretend carrier's on */
dmaddr->dmcsr = IENABLE|SCENABL;
return;
}
dmaddr->dmlstat = TURNON;
if (dmaddr->dmlstat&CARRIER)
tp->t_state =| CARR_ON;
dmaddr->dmcsr = IENABLE|SCENABL;
spl5();
while ((tp->t_state&CARR_ON)==0)
sleep(&tp->t_canq, TTIPRI);
spl0();
}
/*
* If a DH line has the HUPCL mode,
* turn off carrier when it is closed.
*/
/* This routine is obsoleted by existence of DMCTL. --KLH 5/15/79
* dmclose(dev)
* {
* register struct tty *tp;
* register struct dmregs *dmaddr;
*
* dmaddr = dmaddrs[dev.d_minor>>4];
* tp = &dh11[dev.d_minor];
* if (tp->t_flags&HUPCL) {
* dmaddr->dmcsr = dev.d_minor&017;
* dmaddr->dmlstat = TURNOFF;
* dmaddr->dmcsr = IENABLE|SCENABL;
* }
* }
*/
/*
* Dump control bits into the DM registers.
*/
dmctl(dev, bits)
{
register struct dmregs *dmaddr;
dmaddr = dmaddrs[dev.d_minor>>4];
dmaddr->dmcsr = dev.d_minor&017;
dmaddr->dmlstat = bits;
dmaddr->dmcsr = IENABLE|SCENABL;
}
/*
* DM11 interrupt.
* Mainly, deal with carrier transitions.
*/
dmint(dev)
int dev;
{
register struct tty *tp;
register struct dmregs *dmaddr;
dmaddr = dmaddrs[dev];
if (dmaddr->dmcsr&DONE) {
tp = &dh11[ (dev<<4) | (dmaddr->dmcsr&017) ];
if (tp < &dh11[ndh11]) {
#ifdef DNTTY
if (dmaddr->dmlstat&DMCTS) tp->t_dnflgs =| CTS;
else tp->t_dnflgs =& ~CTS;
#endif DNTTY
wakeup(tp);
if ((dmaddr->dmlstat&CARRIER)==0) {
if ((tp->t_state&WOPEN)==0) {
signal(tp->t_pgrp, SIGHUP);
dmaddr->dmlstat = 0;
flushtty(tp);
}
tp->t_state =& ~CARR_ON;
} else
tp->t_state =| CARR_ON;
}
dmaddr->dmcsr = IENABLE|SCENABL;
}
}
/* This is the MIT routine "dmsecrcv" which isn't needed, hence
* commented out. It has been converted for multiple DH/DM's however.
* --KLH 5/15/79
*/
#ifdef COMMENT
dmsecrcv(dev)
int dev;
{ register int ans;
register struct dmregs *dmaddr;
dmaddr = dmaddrs[dev.d_minor>>4];
dmaddr->dmcsr =& ~SCENABL;
while (dmaddr->dmcsr & BUSY);
dmaddr->dmcsr =& ~017;
dmaddr->dmcsr =| dev.d_minor&017;
dmaddr->dmlstat =| TURNOFF;
ans = dmaddr->dmlstat & SECRX;
dmaddr->dmcsr =| SCENABL;
return(ans);
}
#endif COMMENT
/*
* DN Modem support
*/
#ifdef DNTTY
/* Assert RTS for line and return state of CTS lead after suitable
* delay for modem signal propagation.
* This is called only from dhstart at spl 5, so needn't worry about
* DH or timeout interrupts.
*/
dmaskcts(dev)
int dev;
{
register struct dmregs *dmaddr;
register int flag;
dmaddr = dmaddrs[dev.d_minor>>4];
dmaddr->dmcsr = dev.d_minor&017;
dmaddr->dmlstat =| DMRTS;
flag = dmaddr->dmlstat&DMCTS;
dmaddr->dmcsr = IENABLE | SCENABL;
return(flag);
}
/* Turn off RTS for specified line */
dmrtsoff(dev)
int dev;
{
register struct dmregs *dmaddr;
dmaddr = dmaddrs[dev.d_minor>>4];
dmaddr->dmcsr = dev.d_minor&017;
dmaddr->dmlstat =& ~DMRTS;
dmaddr->dmcsr = IENABLE | SCENABL;
}
#endif DNTTY
*dhfdm.c d #
/*
*/
/*
* DM-BB fake driver
*/
#include "tty.h"
#include "conf.h"
struct tty dh11[];
dmopen(dev)
{
register struct tty *tp;
tp = &dh11[dev.d_minor];
tp->t_state =| CARR_ON;
}
dmclose(dev)
{
}