Bell 32V development
[unix-history] / usr / src / slowsys / sys / dz.c
/*
* DZ-11 Driver
*/
# include "../h/param.h"
# include "../h/tty.h"
# include "../h/uba.h"
# include "../h/proc.h"
# include "../h/dir.h"
# include "../h/file.h"
# include "../h/inode.h"
# include "../h/user.h"
# include "../h/conf.h"
# define DZADDR (UBA0_DEV + 0160100)
# define NDZ (1*8)
# define BITS7 020
# define BITS8 030
# define TWOSB 040
# define PENABLE 0100
# define OPAR 0200
# define MSE 040 /* Master Scan Enable */
# define RIE 0100 /* Receiver Interrupt Enable */
# define TIE 040000 /* Transmit interrupt enable */
# define DZ_IEN (MSE+RIE+TIE)
# define PERROR 010000
# define FRERROR 020000
# define SSPEED 7 /* std speed = 300 baud */
# define dzlpr dzrbuf
# define dzmsr dzbrk
# define ON 1
# define OFF 0
struct tty dz_tty[NDZ] ;
int dz_cnt = { NDZ } ;
struct dzregs {
short dzcsr ;
short dzrbuf ;
char dztcr ;
char dzdtr ;
char dztbuf ;
char dzbrk ;
} ;
struct dzregs *dz_addr[] = {
(struct dzregs *)(DZADDR),
(struct dzregs *)(DZADDR+010),
(struct dzregs *)(DZADDR+020),
(struct dzregs *)(DZADDR+030)
} ;
char dz_timer ;
char dz_speeds[] = {
0, 020 , 021 , 022 , 023 , 024 , 0, 025,
026 , 027 , 030 , 032 , 034 , 036 , 0 , 0,
} ;
dzopen(d,flag)
{
register struct tty *tp ;
register dev ;
extern dzstart() , dzscan() ;
dev = minor(d);
if (dev >= dz_cnt) {
u.u_error = ENXIO ;
return ;
}
if (dz_timer == 0) {
dz_timer++ ;
timeout(dzscan,0,60) ;
}
tp = &dz_tty[dev] ;
tp->t_addr = ((struct dzregs *)DZADDR) + (dev>>3);
tp->t_oproc = dzstart ;
tp->t_iproc = NULL;
tp->t_state |= WOPEN ;
if ((tp->t_state & ISOPEN) == 0) {
tp->t_erase = CERASE ;
tp->t_kill = CKILL ;
tp->t_ospeed = tp->t_ispeed = SSPEED ;
tp->t_flags = ODDP|EVENP|ECHO|HUPCLS ;
dzparam(dev) ;
}
else
if (tp->t_state&XCLUDE && u.u_uid != 0) {
u.u_error = EBUSY ;
return ;
}
dzmodem(dev,ON) ;
spl5() ;
while ((tp->t_state & CARR_ON) == 0) {
tp->t_state |= WOPEN ;
sleep(&tp->t_rawq,TTIPRI) ;
}
spl0() ;
(*linesw[tp->t_line].l_open)(d,tp);
}
/* */
dzclose(d)
{
register struct tty *tp ;
register dev ;
dev = minor(d);
tp = &dz_tty[dev] ;
(*linesw[tp->t_line].l_close)(tp);
if (tp->t_flags & HUPCLS)
dzmodem(dev,OFF) ;
ttyclose(tp);
}
/* */
dzread(d)
{
register struct tty *tp;
tp = &dz_tty[minor(d)];
(*linesw[tp->t_line].l_read)(tp);
}
/* */
dzwrite(d)
{
register struct tty *tp;
tp = &dz_tty[minor(d)];
(*linesw[tp->t_line].l_write)(tp);
}
/* */
dzrint(dev)
{
register struct tty *tp ;
register int c ;
register struct dzregs *dzaddr ;
dzaddr = dz_addr[dev] ;
while ((c = dzaddr->dzrbuf) < 0) { /* char present */
tp = &dz_tty[((c>>8)&07)|(dev<<3)] ;
if (tp >= &dz_tty[dz_cnt]) continue ;
if ((tp->t_state & ISOPEN) == 0) {
wakeup(&tp->t_rawq) ;
continue ;
}
if (c & FRERROR) /* framing error = break */
if (tp->t_flags & RAW) c = 0 ; /* null for getty */
else c = 0177 ; /* DEL = interrupt */
if (c & PERROR) /* parity error */
if (((tp->t_flags & (EVENP|ODDP)) == EVENP)
|| ((tp->t_flags & (EVENP|ODDP)) == ODDP))
continue ;
(*linesw[tp->t_line].l_rint)(c,tp);
}
}
/* */
dzioctl(dev,cmd,addr,flag)
caddr_t addr;
dev_t dev;
{
register struct tty *tp;
tp = &dz_tty[minor(dev)];
if (ttioccomm(cmd,tp,addr,dev)) {
if (cmd==TIOCSETP || cmd==TIOCSETN)
dzparam(minor(dev));
} else
u.u_error = ENOTTY;
}
/* */
dzparam(dev)
{
register struct tty *tp ;
register struct dzregs *dzaddr ;
register short lpr ;
tp = &dz_tty[dev] ;
dzaddr = dz_addr[dev>>3] ;
dzaddr->dzcsr = DZ_IEN ;
if (tp->t_ispeed == 0) { /* hang up line */
dzmodem(dev,OFF) ;
return ;
}
lpr = (dz_speeds[tp->t_ispeed]<<8) | (dev & 07) ;
if (tp->t_flags & RAW) lpr |= BITS8 ;
else lpr |= (BITS7|PENABLE) ;
if ((tp->t_flags & EVENP) == 0) lpr |= OPAR ;
if (tp->t_ispeed == 3) /* 110 baud */
lpr |= TWOSB ; /* 2 stop bits */
dzaddr->dzlpr = lpr ;
}
/* */
dzxint(dev)
dev_t dev;
{
register struct tty *tp ;
register struct dzregs *dzaddr ;
register unit ;
dzaddr = dz_addr[dev] ;
while (dzaddr->dzcsr < 0) { /* Transmit Ready is on */
unit = (dzaddr->dzcsr >> 8) & 07 ;
tp = &dz_tty[(dev<<3) | unit] ;
/* the following is an attempt to fix what appears
to be a DZ hardware bug which causes the system
to loop here. Transmitting the NUL should not
cause too many problems.... */
if ((dzaddr->dztcr & (1<<unit)) == 0 ) {
printf("dzxint,line=%d\n", unit);
dzaddr->dztbuf = 0;
continue;
}
if (tp->t_state & BUSY) {
dzaddr->dztbuf = tp->t_char ; /* output the char */
tp->t_state &= ~BUSY ;
if (tp->t_line)
(*linesw[tp->t_line].l_start)(tp);
else
dzstart(tp);
continue ;
}
unit = (1<<unit) ;
dzaddr->dztcr &= (~unit) ; /* Transmit enable off */
}
}
/* */
dzstart(tp)
register struct tty *tp ;
{
register unit , c ;
register struct dzregs *dzaddr ;
extern ttrstrt() ;
int sps ;
unit = tp - dz_tty ;
dzaddr = dz_addr[unit>>3] ;
unit = 1<<(unit&07) ;
sps = spl5() ;
if (tp->t_state & (TIMEOUT|BUSY|TTSTOP)) {
splx(sps) ;
return ;
}
if ((c = getc(&tp->t_outq)) >= 0) {
if (c >= 0200 && (tp->t_flags&RAW) == 0) {
dzaddr->dztcr &= ~unit ;
tp->t_state |= TIMEOUT ;
timeout(ttrstrt,tp,(c&0177)+6) ;
}
else {
tp->t_char = c ;
tp->t_state |= BUSY ;
dzaddr->dztcr |= unit ;
}
if (tp->t_outq.c_cc <= TTLOWAT && tp->t_state&ASLEEP) {
tp->t_state &= ~ASLEEP ;
wakeup(&tp->t_outq) ;
}
}
splx(sps) ;
}
/* */
dzmodem(dev,flag)
register int dev;
{
register struct dzregs *dzaddr ;
register char bit ;
dzaddr = dz_addr[dev>>3] ;
bit = 1<<(dev&07) ;
if (flag == OFF) dzaddr->dzdtr &= ~bit ;
else dzaddr->dzdtr |= bit ;
}
/* */
dzscan()
{
register i ;
register struct dzregs *dzaddr ;
register bit ;
register struct tty *tp ;
extern dzscan() ;
for (i = 0 ; i < dz_cnt ; i++) {
dzaddr = dz_addr[i>>3] ;
tp = &dz_tty[i] ;
bit = 1<<(i&07) ;
if (dzaddr->dzmsr & bit) { /* carrier present */
if ((tp->t_state & CARR_ON) == 0) {
wakeup(&tp->t_rawq) ;
tp->t_state |= CARR_ON ;
}
}
else {
if ((tp->t_state & CARR_ON)) { /* carrier lost */
signal(tp->t_pgrp,SIGHUP) ;
dzaddr->dzdtr &= ~bit ;
flushtty(tp) ;
}
tp->t_state &= ~CARR_ON ;
}
}
timeout(dzscan,0,2*60) ;
}