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