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