# /* ** DH-11 driver */ #include "../defines.h" #include "../param.h" #include "../conf.h" #include "../user.h" #include "../tty.h" #include "../proc.h" /* ** Configuration definitions */ #define DHADDR 0160060 /* device address */ #define NDH11 16 /* number of lines */ #define DHNCH 8 /* max number of DMA chars */ #define DHSILO 32 /* silo interrupt level must be 0 1 2 4 8 16 or 32 */ #define DHRATE 2 /* scan rate */ #define DHSOPEN 0xe0d5 /* single open lines */ /* ** Tty structures */ struct tty dh11[NDH11]; /* ** Place from which to do DMA on output */ char dh_clist[NDH11][DHNCH]; /* ** Miscellaneous Data */ int dhsar; /* Software copy of last dhbar */ int dhscanning; /* Is receiver scanning running */ int dhopenl; /* Bit set for each open line */ /* ** Hardware register layout */ struct dhregs { int dhcsr; int dhnxch; int dhlpr; int dhcar; int dhbcr; int dhbar; int dhbreak; int dhsilo; }; /* ** Hardware control bits */ #define BITS6 01 #define BITS7 02 #define BITS8 03 #define TWOSB 04 #define PENABLE 020 #define OPAR 040 #define HDUPLX 040000 #define IENABLE 0030100 #define MCLEAR 0004000 #define PERROR 0010000 #define FRERROR 0020000 #define XINT 0100000 #define SSPEED 13 /* standard speed: 9600 baud */ /* ** Open a DH11 line. */ dhopen(dev, flag) { register struct tty *tp; extern dhstart(), dhscan(); if (dev.d_minor >= NDH11) { u.u_error = ENXIO; return; } if ( DHSOPEN & dhopenl & (1<<dev.d_minor) ) { u.u_error = EOPENFAIL; return; } tp = &dh11[dev.d_minor]; spl5(); if(dhopenl == 0) { DHADDR->dhcsr = MCLEAR; DHADDR->dhcsr = IENABLE; DHADDR->dhsilo = DHSILO; } if ((tp->t_state&ISOPEN) == 0) { tp->t_addr = dhstart; tp->t_dev = dev; tp->t_state =| ISOPEN|CARR_ON|SSTART; tp->t_erase = CERASE; tp->t_kill = CKILL; tp->t_speeds = SSPEED | (SSPEED<<8); tp->t_flags = ODDP|EVENP|ECHO|XTABS|CRMOD; dhopenl =| 1<<dev.d_minor; dhparam(tp); } if ( dhscanning == 0 ) dhscan(); spl0(); if (u.u_procp->p_ttyp == 0) u.u_procp->p_ttyp = tp; } /* ** Close a DH11 line. */ dhclose(dev) { register struct tty *tp; tp = &dh11[dev.d_minor]; wflushtty(tp); tp->t_state = SSTART; if((dhopenl =& ~(1<<dev.d_minor)) == 0) DHADDR->dhcsr = 0; } /* ** 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 input scanning */ dhscan() { register struct tty * tp; if(dhopenl) { dhscanning = timeout(dhscan, 0, DHRATE); dhrint(); for ( tp = dh11 ; tp < &dh11[NDH11] ; tp++ ) if ( (tp->t_state & TIMEOUT) && --tp->t_char <= 0 ) { tp->t_char = 0; tp->t_state =& ~TIMEOUT; dhstart(tp); } } else dhscanning = 0; } /* ** DH11 receiver interrupt. */ dhrint() { register struct tty *tp; register int c; while ((c = DHADDR->dhnxch) < 0) { /* char. present */ tp = &dh11[(c>>8)&017]; if((tp->t_state&ISOPEN)==0 || (c&PERROR)) { wakeup(tp); continue; } if (c&FRERROR) /* break */ if (tp->t_flags&RAW) c = 0; /* null (for getty) */ else c = 0177; /* DEL (intr) */ if ( c & PERROR ) /* parity */ continue; /* ignored */ ttyinput(c, tp); } } /* ** stty/gtty for DH11 */ dhsgtty(dev, av) int *av; { register struct tty *tp; register r; tp = &dh11[dev.d_minor]; if (ttystty(tp, av)) return; spl5(); dhparam(tp); spl0(); } /* ** Set parameters from open or stty into the DH hardware ** registers. */ dhparam(atp) struct tty *atp; { register struct tty *tp; register int lpr; tp = atp; lpr = (tp->t_speeds.hibyte<<10) | (tp->t_speeds.lobyte<<6); if (tp->t_flags&EVENP) if (tp->t_flags&ODDP) lpr =| BITS8; else lpr =| BITS7|PENABLE; else if ( tp->t_flags&ODDP ) lpr =| BITS7|OPAR|PENABLE; else lpr =| BITS8; if (tp->t_speeds.lobyte == 3) /* 110 baud */ lpr =| TWOSB; delay(5); /* delay while controller flushes */ DHADDR->dhcsr.lobyte = tp->t_dev.d_minor | IENABLE; DHADDR->dhlpr = lpr; } /* ** DH11 transmitter interrupt. ** Restart each line which used to be active but has ** terminated transmission since the last interrupt. */ dhxint() { register struct tty *tp; register ttybit, bar; bar = dhsar & ~DHADDR->dhbar; DHADDR->dhcsr =& ~XINT; ttybit = 1; for (tp = dh11; bar; tp++) { if(bar&ttybit) { dhsar =& ~ttybit; bar =& ~ttybit; tp->t_state =& ~BUSY; dhstart(tp); } ttybit =<< 1; } } /* ** Start (restart) transmission on the given DH11 line. */ dhstart(tp) register struct tty *tp; { extern ttrstrt(); register c, nch; char *cp; /* ** If it's currently active, or delaying, ** no need to do anything. */ if (tp->t_state&(TIMEOUT|BUSY)) return; /* ** 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) { tp->t_char = (((c&0177)+(DHRATE-1))/DHRATE)+1; tp->t_state =| TIMEOUT; return; } cp = dh_clist[tp->t_dev.d_minor]; nch = 0; /* ** 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_flags != RAW) { tp->t_char = c; break; } *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 = tp->t_dev.d_minor | IENABLE; DHADDR->dhcar = cp+nch; DHADDR->dhbcr = nch; c = 1<<tp->t_dev.d_minor; DHADDR->dhbar =| c; dhsar =| c; tp->t_state =| BUSY; } else if (c = tp->t_char) { tp->t_char = (((c&0177)+(DHRATE-1))/DHRATE)+1; tp->t_state =| TIMEOUT; } }