pass flags from device close to l_close
[unix-history] / usr / src / sys / vax / datakit / dktty.c
CommitLineData
586a8972
MK
1/*
2 * Datakit terminal driver
3 * SCCSID[] = "@(#)dktty.c 1.8 Garage 84/05/14"
fcd82046 4 * "@(#)dktty.c 1.6 (Berkeley) %G%"
586a8972
MK
5 */
6
7#include "dktty.h"
8#if NDKTTY>0
9#include "datakit.h"
10
b28b3a13
KB
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"
586a8972
MK
25#include "dkit.h"
26#include "dk.h"
27#include "dkdev.h"
28
29extern int dk_nchan;
30extern struct dkdev dkdev[];
31
32struct tty dkt[NDATAKIT];
33caddr_t dktibuf[NDATAKIT]; /* Input buffer pointers */
34int dktpaused[NDATAKIT]; /* delays for no output mbuf */
3f9af88b
MK
35
36#ifdef notdef
37speeds aren't used, don't bother
586a8972
MK
38int 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};
586a8972
MK
42static char dkt_tmr[16] = {
43 15, 15, 15, 15, 15, 15, 15, 15,
44 15, 9, 6, 4, 2, 1, 15, 15
45} ;
3f9af88b
MK
46#endif
47
48int dktstart();
586a8972
MK
49
50
51/*
52 * DKT control messages
53 */
54#define D_BREAK 0110
55#define D_DELAY 0100
56
586a8972
MK
57extern 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 */
67dktopen(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) {
3f9af88b
MK
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);
586a8972
MK
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*/
117dktclose(dev, flag)
118dev_t dev;
119int 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
fcd82046 144 (*linesw[tp->t_line].l_close)(tp, flag);
586a8972
MK
145 if (devDEBUG) log(LOG_ERR, "DKT_clos(%x)\n",dev);
146 dv->d_prot &= ~DpTTY;
147 tp->t_state &= ~TS_CARR_ON;
3f9af88b 148#ifdef notdef
586a8972
MK
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 }
3f9af88b 154#endif
586a8972
MK
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);
e9036de0 168 return (0);
586a8972
MK
169}
170
171static
172dktcflush(tp)
173 struct tty *tp;
174{
175 ttyflush(tp, (FREAD|FWRITE)) ;
176}
177
178/*
179 * Read from a DKT line.
180 */
3f9af88b
MK
181dktread(dev, uio, flag)
182dev_t dev;
586a8972
MK
183struct 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)];
3f9af88b 190 err = (*linesw[tp->t_line].l_read)(tp, uio, flag);
586a8972
MK
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 */
3f9af88b
MK
200dktwrite(dev, uio, flag)
201dev_t dev;
586a8972
MK
202struct uio *uio;
203{
204 register struct tty *tp;
205
206 if (devDEBUG) log(LOG_ERR, "dktwrite(%x)\n",dev);
207 tp = &dkt[minor(dev)];
3f9af88b 208 return (*linesw[tp->t_line].l_write)(tp, uio, flag);
586a8972
MK
209}
210
211/*
212 * Receive a packet
213 */
214/*ARGSUSED*/
215dktrcv(tp, chan, resid, rmode, rctl)
216register 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);
3f9af88b
MK
238 if (c==D_BREAK)
239 (*linesw[tp->t_line].l_rint)(TTY_FE, tp) ;
586a8972
MK
240 }
241 }
242 dktfcon(tp) ;
243}
244
245
246/*
247 * Input flow control: queue another receive unless to many chars waiting
248 */
249dktfcon(tp)
250register 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;
3f9af88b 259 if (x >= TTYHOG/2 && (!(tp->t_lflag&ICANON) || tp->t_canq.c_cc))
586a8972
MK
260 return;
261 (void) dk_recv(d, dktibuf[d], MLEN,
3f9af88b 262#ifdef notdef
586a8972 263 DKR_BLOCK | DKR_TIME | (dkt_tmr[tp->t_ispeed]<<8),
3f9af88b
MK
264#endif
265 DKR_BLOCK | DKR_TIME | (1<<8),
586a8972
MK
266 dktrcv, (caddr_t) tp) ;
267}
268
269/*
270 * stty/gtty for DKT
271 */
272dktioctl(dev, cmd, data, flag)
273caddr_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);
e9036de0 283 if (error >= 0)
586a8972 284 return (error);
586a8972
MK
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 */
299dktstart(tp)
300register 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 */
3f9af88b 325 if (tp->t_outq.c_cc<=tp->t_lowat) {
586a8972
MK
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 }
3f9af88b 351 if (1 || !(tp->t_oflag&OPOST))
586a8972
MK
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);
384out: ;
385 splx(s) ;
386}
387
388dktxpack(chan, cmd)
389char 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*/
396dktstop(tp, rw)
397register 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
415dktshut(tp)
416register struct tty *tp;
417{
418 if (tpDEBUG) log(LOG_ERR, "dktshut %d\n", tp-dkt);
e9036de0
MK
419 if ((tp->t_state&TS_ISOPEN) && (tp->t_state&TS_CARR_ON))
420 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
586a8972
MK
421 tp->t_state &= ~TS_CARR_ON;
422 ttyflush(tp, (FREAD|FWRITE)) ;
423 dk_cmd((tp - dkt), DKC_FLUSH);
424}
425
426
427dktxdun(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