xref: /csrg-svn/sys/vax/datakit/dktty.c (revision 38624)
1*38624Skarels /*
2*38624Skarels  *  Datakit terminal driver
3*38624Skarels  *	SCCSID[] = "@(#)dktty.c	1.8 Garage 84/05/14"
4*38624Skarels  */
5*38624Skarels 
6*38624Skarels #include "dktty.h"
7*38624Skarels #if NDKTTY>0
8*38624Skarels #include "datakit.h"
9*38624Skarels 
10*38624Skarels #include "param.h"
11*38624Skarels #include "../machine/pte.h"
12*38624Skarels #include "syslog.h"
13*38624Skarels #include "errno.h"
14*38624Skarels #include "signal.h"
15*38624Skarels #include "conf.h"
16*38624Skarels #include "dir.h"
17*38624Skarels #include "user.h"
18*38624Skarels #include "proc.h"
19*38624Skarels #include "ioctl.h"
20*38624Skarels #include "tty.h"
21*38624Skarels #include "file.h"
22*38624Skarels #include "mbuf.h"
23*38624Skarels #include "uio.h"
24*38624Skarels #include "kernel.h"
25*38624Skarels #include "dkit.h"
26*38624Skarels #include "dk.h"
27*38624Skarels #include "dkdev.h"
28*38624Skarels 
29*38624Skarels extern int		dk_nchan;
30*38624Skarels extern struct dkdev	dkdev[];
31*38624Skarels 
32*38624Skarels struct tty	dkt[NDATAKIT];
33*38624Skarels caddr_t	dktibuf[NDATAKIT];	/* Input buffer pointers */
34*38624Skarels int	dktpaused[NDATAKIT];	/* delays for no output mbuf */
35*38624Skarels int	dktdelay[] = {		/* Time to wait on close before dropping line */
36*38624Skarels 	4, 15, 15, 15, 15, 15, 15, 8,		/* B0-B300 */
37*38624Skarels 	4, 2, 2, 2, 1, 1, 1, 1
38*38624Skarels };
39*38624Skarels 
40*38624Skarels int	dktstart();
41*38624Skarels 
42*38624Skarels static char dkt_tmr[16] = {
43*38624Skarels 	15, 15, 15, 15, 15, 15, 15, 15,
44*38624Skarels 	15, 9, 6, 4, 2, 1, 15, 15
45*38624Skarels } ;
46*38624Skarels 
47*38624Skarels 
48*38624Skarels /*
49*38624Skarels  * DKT control messages
50*38624Skarels  */
51*38624Skarels #define	D_BREAK	0110
52*38624Skarels #define	D_DELAY	0100
53*38624Skarels 
54*38624Skarels #define	DKTSPEED	B9600
55*38624Skarels #define	DKTFLAGS	(EVENP|ODDP|ECHO)
56*38624Skarels 
57*38624Skarels extern int dkdebug ;
58*38624Skarels 
59*38624Skarels #define	DEBUG	(dkdebug < 512)
60*38624Skarels #define devDEBUG 	(minor(dev) >= dkdebug)
61*38624Skarels #define chanDEBUG 	(chan >= dkdebug)
62*38624Skarels #define tpDEBUG 	((tp - dkt) >= dkdebug)
63*38624Skarels 
64*38624Skarels /*
65*38624Skarels  * Open a DKT line.
66*38624Skarels  */
67*38624Skarels dktopen(dev, flag)
68*38624Skarels {
69*38624Skarels 	register struct tty	*tp;
70*38624Skarels 	register struct dkdev	*dv;
71*38624Skarels 	register		d;
72*38624Skarels 	int chan;
73*38624Skarels 
74*38624Skarels 	d = minor(dev);
75*38624Skarels 	if (d >= dk_nchan) {
76*38624Skarels 		if (DEBUG) log(LOG_ERR, "dkt_open(%d) error\n", dev);
77*38624Skarels 		return ENXIO;
78*38624Skarels 	}
79*38624Skarels 	tp = &dkt[d];
80*38624Skarels 	if ((tp->t_state&TS_XCLUDE) && u.u_uid!=0)
81*38624Skarels 		return (EBUSY);
82*38624Skarels 	if (!dktibuf[d]) {
83*38624Skarels 		struct mbuf *mb;
84*38624Skarels 		mb = m_get(M_WAIT, DKMT_ITTY);
85*38624Skarels 		if (mb == NULL) return ENOBUFS;
86*38624Skarels 		dktibuf[d] = mtod(mb, caddr_t);
87*38624Skarels 	}
88*38624Skarels 	if ((chan = dk_open(d, (int (*)()) NULL)) < 0) {
89*38624Skarels 		return -chan;
90*38624Skarels 	}
91*38624Skarels 
92*38624Skarels 	tp->t_oproc = dktstart;
93*38624Skarels 	tp->t_state |= (TS_WOPEN|TS_CARR_ON);
94*38624Skarels 	dv = &dkdev[d];
95*38624Skarels 	if ((tp->t_state&TS_ISOPEN) == 0) {
96*38624Skarels 		ttychars(tp) ;
97*38624Skarels 		if (tp->t_ispeed == 0) {
98*38624Skarels 			tp->t_ispeed = tp->t_ospeed = DKTSPEED;
99*38624Skarels 			tp->t_flags = DKTFLAGS;
100*38624Skarels 		}
101*38624Skarels 		if (devDEBUG) log(LOG_ERR, "DKT_open(%x,%o)\n",dev,flag);
102*38624Skarels 	}
103*38624Skarels 	dktfcon(tp);
104*38624Skarels 	if (devDEBUG) log(LOG_ERR, "DKT_open(%x, %x) ok\n", dev, tp);
105*38624Skarels 	dv->d_prot |= DpTTY;
106*38624Skarels 	return (*linesw[tp->t_line].l_open)(dev, tp);
107*38624Skarels }
108*38624Skarels 
109*38624Skarels /*
110*38624Skarels  * Close a DKT line.
111*38624Skarels  */
112*38624Skarels /*ARGSUSED*/
113*38624Skarels dktclose(dev, flag)
114*38624Skarels dev_t dev;
115*38624Skarels int  flag;
116*38624Skarels {
117*38624Skarels 	register struct tty	*tp;
118*38624Skarels 	register struct dkdev	*dv;
119*38624Skarels 	register int	d, s;
120*38624Skarels 	extern int dktcflush(), dktrcv(), wakeup();
121*38624Skarels 
122*38624Skarels 	d = minor(dev);
123*38624Skarels 	tp = &dkt[d];
124*38624Skarels 	dv = &dkdev[d];
125*38624Skarels 	/*
126*38624Skarels 	 * If called from exit(), give output 30 seconds to drain.
127*38624Skarels 	 * Otherwise let output drain first.
128*38624Skarels 	 */
129*38624Skarels 	if(u.u_signal[SIGKILL] == SIG_IGN){
130*38624Skarels 		s = spl5();
131*38624Skarels 		timeout(dktcflush, (caddr_t) tp, 30*hz);
132*38624Skarels 		ttywflush(tp) ;
133*38624Skarels 		untimeout(dktcflush, (caddr_t) tp);
134*38624Skarels 		tp->t_state &= ~TS_CARR_ON;
135*38624Skarels 		if(dv->d_prot == DpTTY)	/* no other protocols open */
136*38624Skarels 			dk_reset(d);
137*38624Skarels 		splx(s);
138*38624Skarels 	}
139*38624Skarels 
140*38624Skarels 	(*linesw[tp->t_line].l_close)(tp);
141*38624Skarels 	if (devDEBUG) log(LOG_ERR, "DKT_clos(%x)\n",dev);
142*38624Skarels 	dv->d_prot &= ~DpTTY;
143*38624Skarels 	tp->t_state &= ~TS_CARR_ON;
144*38624Skarels 	/* Wait for output to drain on far end */
145*38624Skarels 	if (dktdelay[tp->t_ispeed] > 0) {
146*38624Skarels 		timeout(wakeup, (caddr_t) tp, dktdelay[tp->t_ispeed] * hz);
147*38624Skarels 		sleep((caddr_t) tp, TTIPRI);
148*38624Skarels 	}
149*38624Skarels 	if(!dv->d_prot){
150*38624Skarels 		(void) dk_close(d);
151*38624Skarels 		(void) dk_takedown(d);
152*38624Skarels 		dv->d_state = 0;
153*38624Skarels 	}
154*38624Skarels 	else (void) dk_rabort(d, dktrcv, (caddr_t) tp);
155*38624Skarels 	ttyclose(tp);
156*38624Skarels 	s = spl5();
157*38624Skarels 	if (dktibuf[d]) {
158*38624Skarels 		(void) m_free(dtom(dktibuf[d]));
159*38624Skarels 		dktibuf[d] = NULL;
160*38624Skarels 	}
161*38624Skarels 	splx(s);
162*38624Skarels }
163*38624Skarels 
164*38624Skarels static
165*38624Skarels dktcflush(tp)
166*38624Skarels 	struct tty *tp;
167*38624Skarels {
168*38624Skarels 	ttyflush(tp, (FREAD|FWRITE)) ;
169*38624Skarels }
170*38624Skarels 
171*38624Skarels /*
172*38624Skarels  * Read from a DKT line.
173*38624Skarels  */
174*38624Skarels dktread(dev, uio)
175*38624Skarels struct uio *uio;
176*38624Skarels {
177*38624Skarels 	register struct tty *tp;
178*38624Skarels 	int err;
179*38624Skarels 
180*38624Skarels 	if (devDEBUG) log(LOG_ERR, "dktread(%x) %d\n", dev, uio->uio_resid) ;
181*38624Skarels 	tp = &dkt[minor(dev)];
182*38624Skarels 	err = (*linesw[tp->t_line].l_read)(tp, uio);
183*38624Skarels 	if (devDEBUG)
184*38624Skarels 		log(LOG_ERR, "dktread done(%x) %d err=%d\n", dev, uio->uio_resid, err) ;
185*38624Skarels 	dktfcon(tp);
186*38624Skarels 	return err;
187*38624Skarels }
188*38624Skarels 
189*38624Skarels /*
190*38624Skarels  * Write on a DKT line
191*38624Skarels  */
192*38624Skarels dktwrite(dev, uio)
193*38624Skarels struct uio *uio;
194*38624Skarels {
195*38624Skarels 	register struct tty *tp;
196*38624Skarels 
197*38624Skarels 	if (devDEBUG) log(LOG_ERR, "dktwrite(%x)\n",dev);
198*38624Skarels 	tp = &dkt[minor(dev)];
199*38624Skarels 	return (*linesw[tp->t_line].l_write)(tp, uio);
200*38624Skarels }
201*38624Skarels 
202*38624Skarels /*
203*38624Skarels  * Receive a packet
204*38624Skarels  */
205*38624Skarels /*ARGSUSED*/
206*38624Skarels dktrcv(tp, chan, resid, rmode, rctl)
207*38624Skarels register struct tty *tp ;
208*38624Skarels {
209*38624Skarels 	register c ;
210*38624Skarels 	register char *cp ;
211*38624Skarels 	register count ;
212*38624Skarels 
213*38624Skarels 	if ((rmode & DKR_ABORT) || (dk_status(chan) & DK_RESET)) {
214*38624Skarels 		dktshut(tp) ;
215*38624Skarels 		return ;
216*38624Skarels 	}
217*38624Skarels 	/* Process input data */
218*38624Skarels 	if (tp->t_state&TS_ISOPEN) {
219*38624Skarels 		cp = dktibuf[tp-dkt];
220*38624Skarels 		count = MLEN - resid ;
221*38624Skarels 		if (count) {
222*38624Skarels 			do {
223*38624Skarels 				/* Should really do parity checking... */
224*38624Skarels 				(*linesw[tp->t_line].l_rint)((*cp++)&0377, tp) ;
225*38624Skarels 			} while (--count);
226*38624Skarels 		}
227*38624Skarels 		if ((c = (rctl & 0377)) != 0) {
228*38624Skarels 			if (chanDEBUG) log(LOG_ERR, "DKT_ctl 0%o on %d\n",c,chan);
229*38624Skarels 			if (c==D_BREAK) {
230*38624Skarels 				/*
231*38624Skarels 				 * At framing error (break) generate
232*38624Skarels 				 * a null (in raw mode, for getty), or a
233*38624Skarels 				 * interrupt (in cooked/cbreak mode).
234*38624Skarels 				 */
235*38624Skarels 				if (tp->t_flags&RAW)
236*38624Skarels 					c = 0;
237*38624Skarels 				else
238*38624Skarels 					c = tp->t_intrc;
239*38624Skarels 				(*linesw[tp->t_line].l_rint)(c, tp) ;
240*38624Skarels 			}
241*38624Skarels 		}
242*38624Skarels 	}
243*38624Skarels 	dktfcon(tp) ;
244*38624Skarels }
245*38624Skarels 
246*38624Skarels 
247*38624Skarels /*
248*38624Skarels  * Input flow control:  queue another receive unless to many chars waiting
249*38624Skarels  */
250*38624Skarels dktfcon(tp)
251*38624Skarels register struct tty *tp;
252*38624Skarels {
253*38624Skarels 	register int d = tp - dkt;
254*38624Skarels 	register x;
255*38624Skarels 
256*38624Skarels 	if ((dk_status(d) & (DK_RCV|DK_OPEN)) != DK_OPEN)
257*38624Skarels 		return ;
258*38624Skarels 	if (dktibuf[d] == NULL) return;
259*38624Skarels 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
260*38624Skarels 	if (x >= TTYHOG/2 && (tp->t_delct>0 || (tp->t_flags&(RAW|CBREAK))))
261*38624Skarels 		return;
262*38624Skarels 	(void) dk_recv(d, dktibuf[d], MLEN,
263*38624Skarels 	    DKR_BLOCK | DKR_TIME | (dkt_tmr[tp->t_ispeed]<<8),
264*38624Skarels 	    dktrcv, (caddr_t) tp) ;
265*38624Skarels }
266*38624Skarels 
267*38624Skarels /*
268*38624Skarels  * stty/gtty for DKT
269*38624Skarels  */
270*38624Skarels dktioctl(dev, cmd, data, flag)
271*38624Skarels caddr_t data;
272*38624Skarels {
273*38624Skarels 	register struct tty *tp;
274*38624Skarels 	int error;
275*38624Skarels 
276*38624Skarels 	tp = &dkt[minor(dev)];
277*38624Skarels 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
278*38624Skarels 	if (error >= 0)
279*38624Skarels 		return error;
280*38624Skarels 	error = ttioctl(tp, cmd, data, flag);
281*38624Skarels 	if (error >= 0) {
282*38624Skarels 		if (tp->t_ispeed == 0) {
283*38624Skarels 			tp->t_state &= ~TS_CARR_ON;
284*38624Skarels 			if (devDEBUG) log(LOG_ERR, "DKT_ioctl carr off\n");
285*38624Skarels 			gsignal(tp->t_pgrp, SIGHUP);
286*38624Skarels 			gsignal(tp->t_pgrp, SIGCONT);
287*38624Skarels 		}
288*38624Skarels 		return (error);
289*38624Skarels 	}
290*38624Skarels 
291*38624Skarels 	switch(cmd) {
292*38624Skarels 		case TIOCSBRK:
293*38624Skarels 			dktxpack(tp-dkt, D_BREAK) ;
294*38624Skarels 			return 0;
295*38624Skarels 		case TIOCCBRK:
296*38624Skarels 			return 0;
297*38624Skarels 	}
298*38624Skarels 	return ENOTTY;
299*38624Skarels }
300*38624Skarels 
301*38624Skarels /*
302*38624Skarels  * Start (restart) transmission on the given DKT line.
303*38624Skarels  */
304*38624Skarels dktstart(tp)
305*38624Skarels register struct tty *tp;
306*38624Skarels {
307*38624Skarels 	register d;
308*38624Skarels 	char delay;
309*38624Skarels 	extern dktxdun() ;
310*38624Skarels 	int s, c;
311*38624Skarels 	register int nch;
312*38624Skarels 	register struct mbuf *m;
313*38624Skarels 	extern ttrstrt();
314*38624Skarels 
315*38624Skarels 	d = tp - dkt;
316*38624Skarels 	s = spl5() ;
317*38624Skarels 
318*38624Skarels #ifdef notdef
319*38624Skarels 	if (dk_status(d) & DK_SPND)
320*38624Skarels 		dk_cmd(d, DKC_RSME) ;
321*38624Skarels #endif
322*38624Skarels 
323*38624Skarels 	if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT))
324*38624Skarels 		goto out;
325*38624Skarels 
326*38624Skarels 	/*
327*38624Skarels 	 * If the writer was sleeping on output overflow,
328*38624Skarels 	 * wake the process when low tide is reached.
329*38624Skarels 	 */
330*38624Skarels 	if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
331*38624Skarels 		if (tp->t_state&TS_ASLEEP) {
332*38624Skarels 			tp->t_state &= ~TS_ASLEEP;
333*38624Skarels 			wakeup((caddr_t)&tp->t_outq);
334*38624Skarels 		}
335*38624Skarels 		if (tp->t_wsel) {
336*38624Skarels 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
337*38624Skarels 			tp->t_wsel = 0;
338*38624Skarels 			tp->t_state &= ~TS_WCOLL;
339*38624Skarels 		}
340*38624Skarels 	}
341*38624Skarels 	/*
342*38624Skarels 	 * Now restart transmission unless the output queue is
343*38624Skarels 	 * empty.
344*38624Skarels 	 */
345*38624Skarels 	if (tp->t_outq.c_cc == 0)
346*38624Skarels 		goto out;
347*38624Skarels 
348*38624Skarels 	m = m_get(M_DONTWAIT, DKMT_OTTY);
349*38624Skarels 	if (m == NULL) {
350*38624Skarels 		/* No buffers; arrange to retry in .5 seconds */
351*38624Skarels 		dktpaused[d]++;
352*38624Skarels 		tp->t_state |= TS_TIMEOUT;
353*38624Skarels 		timeout(ttrstrt, (caddr_t) tp, hz/2);
354*38624Skarels 		goto out;
355*38624Skarels 	}
356*38624Skarels 	if (tp->t_flags & (RAW|LITOUT))
357*38624Skarels 		nch = ndqb(&tp->t_outq, 0);
358*38624Skarels 	else {
359*38624Skarels 		nch = ndqb(&tp->t_outq, 0200);
360*38624Skarels 		/*
361*38624Skarels 		 * If first thing on queue is a delay process it.
362*38624Skarels 		 */
363*38624Skarels 		if (nch == 0) {
364*38624Skarels 			nch = getc(&tp->t_outq);
365*38624Skarels 			c = MIN((nch & 0xff) + 6, 0x7f);
366*38624Skarels 			delay = D_DELAY;
367*38624Skarels 			if (tpDEBUG)
368*38624Skarels 				log(LOG_ERR, "DKT_delay %d\n", c) ;
369*38624Skarels 			while (c) {
370*38624Skarels 				delay++;
371*38624Skarels 				c >>= 1;
372*38624Skarels 			}
373*38624Skarels 			if (dk_xmit(d, (struct mbuf *) NULL, 1, delay, dktxdun, (caddr_t) 0))
374*38624Skarels 				tp->t_state |= TS_BUSY;
375*38624Skarels 			(void) m_free(m);
376*38624Skarels 			goto out;
377*38624Skarels 		}
378*38624Skarels 	}
379*38624Skarels 	/*
380*38624Skarels 	 * If characters to transmit, restart transmission.
381*38624Skarels 	 */
382*38624Skarels 	if (nch) {
383*38624Skarels 		bcopy((caddr_t)tp->t_outq.c_cf, mtod(m, caddr_t), (unsigned) nch);
384*38624Skarels 		m->m_len = nch;
385*38624Skarels 		if (dk_xmit(d, m, 1, 0, dktxdun, (caddr_t) nch))
386*38624Skarels 			tp->t_state |= TS_BUSY;
387*38624Skarels 	}
388*38624Skarels 	else (void) m_free(m);
389*38624Skarels out: ;
390*38624Skarels 	splx(s) ;
391*38624Skarels }
392*38624Skarels 
393*38624Skarels dktxpack(chan, cmd)
394*38624Skarels char cmd;
395*38624Skarels {
396*38624Skarels 	(void) dk_xmit(chan, (struct mbuf *) NULL, 1, cmd, (int (*)()) 0, (caddr_t) 0);
397*38624Skarels 	if (chanDEBUG) log(LOG_ERR, "DKT_sent %o on %d\n",cmd&0377,chan);
398*38624Skarels }
399*38624Skarels 
400*38624Skarels /*ARGSUSED*/
401*38624Skarels dktstop(tp, rw)
402*38624Skarels register struct tty *tp;
403*38624Skarels {
404*38624Skarels 	register int s, d;
405*38624Skarels 
406*38624Skarels 	d = tp - dkt;
407*38624Skarels 	s = spl5();
408*38624Skarels 	if (tp->t_state & TS_BUSY) {
409*38624Skarels #ifdef notdef
410*38624Skarels 		dk_cmd(d, DKC_SPND);
411*38624Skarels #endif
412*38624Skarels 		if ((tp->t_state & TS_TTSTOP) == 0) {
413*38624Skarels 			tp->t_state |= TS_FLUSH;
414*38624Skarels 			dk_cmd(d, DKC_FLUSH);
415*38624Skarels 		}
416*38624Skarels }
417*38624Skarels 	splx(s);
418*38624Skarels }
419*38624Skarels 
420*38624Skarels dktshut(tp)
421*38624Skarels register struct tty *tp;
422*38624Skarels {
423*38624Skarels 	if (tpDEBUG) log(LOG_ERR, "dktshut %d\n", tp-dkt);
424*38624Skarels 	if ((tp->t_state&TS_ISOPEN) && (tp->t_state&TS_CARR_ON)) {
425*38624Skarels 		if (tpDEBUG) log(LOG_ERR, "DKT_sighup %d\n",tp->t_pgrp);
426*38624Skarels 		gsignal(tp->t_pgrp, SIGHUP);
427*38624Skarels 		gsignal(tp->t_pgrp, SIGCONT);
428*38624Skarels 	}
429*38624Skarels 	tp->t_state &= ~TS_CARR_ON;
430*38624Skarels 	ttyflush(tp, (FREAD|FWRITE)) ;
431*38624Skarels 	dk_cmd((tp - dkt), DKC_FLUSH);
432*38624Skarels }
433*38624Skarels 
434*38624Skarels 
435*38624Skarels dktxdun(cnt, chan)
436*38624Skarels {
437*38624Skarels 	register struct tty *tp ;
438*38624Skarels 
439*38624Skarels 	tp = &dkt[chan];
440*38624Skarels 	if (tp->t_state & TS_FLUSH) tp->t_state &= ~TS_FLUSH;
441*38624Skarels 	else ndflush(&tp->t_outq, cnt);
442*38624Skarels 	tp->t_state &= ~TS_BUSY;
443*38624Skarels 	if (tp->t_line)
444*38624Skarels 		(*linesw[tp->t_line].l_start)(tp);
445*38624Skarels 	else
446*38624Skarels 		dktstart(tp);
447*38624Skarels }
448*38624Skarels #endif
449