Commit | Line | Data |
---|---|---|
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 | ||
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 */ | |
3f9af88b MK |
35 | |
36 | #ifdef notdef | |
37 | speeds aren't used, don't bother | |
586a8972 MK |
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 | }; | |
586a8972 MK |
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 | } ; | |
3f9af88b MK |
46 | #endif |
47 | ||
48 | int dktstart(); | |
586a8972 MK |
49 | |
50 | ||
51 | /* | |
52 | * DKT control messages | |
53 | */ | |
54 | #define D_BREAK 0110 | |
55 | #define D_DELAY 0100 | |
56 | ||
586a8972 MK |
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) { | |
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*/ | |
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 | ||
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 | ||
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 | */ | |
3f9af88b MK |
181 | dktread(dev, uio, flag) |
182 | dev_t dev; | |
586a8972 MK |
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)]; | |
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 |
200 | dktwrite(dev, uio, flag) |
201 | dev_t dev; | |
586a8972 MK |
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)]; | |
3f9af88b | 208 | return (*linesw[tp->t_line].l_write)(tp, uio, flag); |
586a8972 MK |
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); | |
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 | */ | |
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; | |
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 | */ | |
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); | |
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 | */ | |
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 | */ | |
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); | |
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); | |
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 | ||
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 |