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