+/*
+* 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) ;
+}