xref: /csrg-svn/sys/kern/tty.c (revision 146)
1 /*	tty.c	3.3	10/14/12	*/
2 
3 /*
4  * general TTY subroutines
5  */
6 #include "../h/param.h"
7 #include "../h/systm.h"
8 #include "../h/dir.h"
9 #include "../h/user.h"
10 #include "../h/tty.h"
11 #include "../h/proc.h"
12 #include "../h/mx.h"
13 #include "../h/inode.h"
14 #include "../h/file.h"
15 #include "../h/reg.h"
16 #include "../h/conf.h"
17 #include "../h/buf.h"
18 
19 char	partab[];
20 
21 /*
22  * When running dz's using only SAE (silo alarm) on input
23  * it is necessary to call dzrint() at clock interrupt time.
24  * This is unsafe unless spl5()s in tty code are changed to
25  * spl6()s to block clock interrupts.  Note that the dh driver
26  * currently in use works the same way as the dz, even though
27  * we could try to more intelligently manage its silo.
28  * Thus don't take this out if you have no dz's unless you
29  * change clock.c and dhtimer().
30  */
31 #define	spl5	spl6
32 
33 /*
34  * Input mapping table-- if an entry is non-zero, when the
35  * corresponding character is typed preceded by "\" the escape
36  * sequence is replaced by the table value.  Mostly used for
37  * upper-case only terminals.
38  */
39 
40 char	maptab[] ={
41 	000,000,000,000,000,000,000,000,
42 	000,000,000,000,000,000,000,000,
43 	000,000,000,000,000,000,000,000,
44 	000,000,000,000,000,000,000,000,
45 	000,'|',000,000,000,000,000,'`',
46 	'{','}',000,000,000,000,000,000,
47 	000,000,000,000,000,000,000,000,
48 	000,000,000,000,000,000,000,000,
49 	000,000,000,000,000,000,000,000,
50 	000,000,000,000,000,000,000,000,
51 	000,000,000,000,000,000,000,000,
52 	000,000,000,000,000,000,'~',000,
53 	000,'A','B','C','D','E','F','G',
54 	'H','I','J','K','L','M','N','O',
55 	'P','Q','R','S','T','U','V','W',
56 	'X','Y','Z',000,000,000,000,000,
57 };
58 
59 
60 /*
61  * shorthand
62  */
63 #define	q1	tp->t_rawq
64 #define	q2	tp->t_canq
65 #define	q3	tp->t_outq
66 #define	q4	tp->t_un.t_ctlq
67 
68 #define	OBUFSIZ	100
69 
70 /*
71  * routine called on first teletype open.
72  * establishes a process group for distribution
73  * of quits and interrupts from the tty.
74  */
75 ttyopen(dev, tp)
76 dev_t dev;
77 register struct tty *tp;
78 {
79 	register struct proc *pp;
80 
81 	pp = u.u_procp;
82 	tp->t_dev = dev;
83 	if(pp->p_pgrp == 0) {
84 		u.u_ttyp = tp;
85 		u.u_ttyd = dev;
86 		if (tp->t_pgrp==0)
87 			tp->t_pgrp = pp->p_pid;
88 		pp->p_pgrp = tp->t_pgrp;
89 	}
90 	tp->t_state &= ~WOPEN;
91 	tp->t_state |= ISOPEN;
92 }
93 
94 
95 /*
96  * set default control characters.
97  */
98 ttychars(tp)
99 register struct tty *tp;
100 {
101 	tun.t_intrc = CINTR;
102 	tun.t_quitc = CQUIT;
103 	tun.t_startc = CSTART;
104 	tun.t_stopc = CSTOP;
105 	tun.t_eofc = CEOT;
106 	tun.t_brkc = CBRK;
107 	tp->t_erase = CERASE;
108 	tp->t_kill = CKILL;
109 }
110 
111 /*
112  * clean tp on last close
113  */
114 ttyclose(tp)
115 register struct tty *tp;
116 {
117 
118 	tp->t_pgrp = 0;
119 	wflushtty(tp);
120 	tp->t_state = 0;
121 }
122 
123 /*
124  * stty/gtty writearound
125  */
126 stty()
127 {
128 	u.u_arg[2] = u.u_arg[1];
129 	u.u_arg[1] = TIOCSETP;
130 	ioctl();
131 }
132 
133 gtty()
134 {
135 	u.u_arg[2] = u.u_arg[1];
136 	u.u_arg[1] = TIOCGETP;
137 	ioctl();
138 }
139 
140 /*
141  * Do nothing specific version of line
142  * discipline specific ioctl command.
143  */
144 nullioctl(tp, cmd, addr)
145 register struct tty *tp;
146 caddr_t addr;
147 {
148 
149 	return (cmd);
150 }
151 
152 /*
153  * ioctl system call
154  * Check legality, execute common code, and switch out to individual
155  * device routine.
156  */
157 ioctl()
158 {
159 	register struct file *fp;
160 	register struct inode *ip;
161 	register struct a {
162 		int	fdes;
163 		int	cmd;
164 		caddr_t	cmarg;
165 	} *uap;
166 	register dev_t dev;
167 	register fmt;
168 
169 	uap = (struct a *)u.u_ap;
170 	if ((fp = getf(uap->fdes)) == NULL)
171 		return;
172 	if (uap->cmd==FIOCLEX) {
173 		u.u_pofile[uap->fdes] |= EXCLOSE;
174 		return;
175 	}
176 	if (uap->cmd==FIONCLEX) {
177 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
178 		return;
179 	}
180 	ip = fp->f_inode;
181 	fmt = ip->i_mode & IFMT;
182 	if (fmt != IFCHR && fmt != IFMPC) {
183 		u.u_error = ENOTTY;
184 		return;
185 	}
186 	dev = ip->i_un.i_rdev;
187 	u.u_r.r_val1 = 0;
188 	(*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag);
189 }
190 
191 /*
192  * Common code for several tty ioctl commands
193  */
194 ttioccomm(com, tp, addr, dev)
195 register struct tty *tp;
196 caddr_t addr;
197 {
198 	unsigned t;
199 	struct ttiocb iocb;
200 	extern int nldisp;
201 	register s;
202 
203 	switch(com) {
204 
205 	/*
206 	 * get discipline number
207 	 */
208 	case TIOCGETD:
209 		t = tp->t_line;
210 		if (copyout((caddr_t)&t, addr, sizeof(t)))
211 			u.u_error = EFAULT;
212 		break;
213 
214 	/*
215 	 * set line discipline
216 	 */
217 	case TIOCSETD:
218 		if (copyin(addr, (caddr_t)&t, sizeof(t))) {
219 			u.u_error = EFAULT;
220 			break;
221 		}
222 		if (t >= nldisp) {
223 			u.u_error = ENXIO;
224 			break;
225 		}
226 		s = spl5();
227 		if (tp->t_line)
228 			(*linesw[tp->t_line].l_close)(tp);
229 		if (t)
230 			(*linesw[t].l_open)(dev, tp, addr);
231 		if (u.u_error==0)
232 			tp->t_line = t;
233 		splx(s);
234 		break;
235 
236 	/*
237 	 * prevent more opens on channel
238 	 */
239 	case TIOCEXCL:
240 		tp->t_state |= XCLUDE;
241 		break;
242 
243 	case TIOCNXCL:
244 		tp->t_state &= ~XCLUDE;
245 		break;
246 
247 	/*
248 	 * Set new parameters
249 	 */
250 	case TIOCSETP:
251 		wflushtty(tp);
252 	case TIOCSETN:
253 		if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
254 			u.u_error = EFAULT;
255 			return(1);
256 		}
257 		(void) spl5();
258 		while (canon(tp)>=0)
259 			;
260 		if ((tp->t_state&SPEEDS)==0) {
261 			tp->t_ispeed = iocb.ioc_ispeed;
262 			tp->t_ospeed = iocb.ioc_ospeed;
263 		}
264 		tp->t_erase = iocb.ioc_erase;
265 		tp->t_kill = iocb.ioc_kill;
266 		tp->t_flags = iocb.ioc_flags;
267 		(void) spl0();
268 		break;
269 
270 	/*
271 	 * send current parameters to user
272 	 */
273 	case TIOCGETP:
274 		iocb.ioc_ispeed = tp->t_ispeed;
275 		iocb.ioc_ospeed = tp->t_ospeed;
276 		iocb.ioc_erase = tp->t_erase;
277 		iocb.ioc_kill = tp->t_kill;
278 		iocb.ioc_flags = tp->t_flags;
279 		if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
280 			u.u_error = EFAULT;
281 		break;
282 
283 	/*
284 	 * Hang up line on last close
285 	 */
286 
287 	case TIOCHPCL:
288 		tp->t_state |= HUPCLS;
289 		break;
290 
291 	case TIOCFLUSH:
292 		flushtty(tp);
293 		break;
294 
295 	/*
296 	 * ioctl entries to line discipline
297 	 */
298 	case DIOCSETP:
299 	case DIOCGETP:
300 		if ((*linesw[tp->t_line].l_ioctl)(com, tp, addr))
301 			u.u_error = ENOTTY;
302 		break;
303 
304 	/*
305 	 * set and fetch special characters
306 	 */
307 	case TIOCSETC:
308 		if (copyin(addr, (caddr_t)&tun, sizeof(struct tc)))
309 			u.u_error = EFAULT;
310 		break;
311 
312 	case TIOCGETC:
313 		if (copyout((caddr_t)&tun, addr, sizeof(struct tc)))
314 			u.u_error = EFAULT;
315 		break;
316 
317 	default:
318 		return(0);
319 	}
320 	return(1);
321 }
322 
323 /*
324  * Wait for output to drain, then flush input waiting.
325  */
326 wflushtty(tp)
327 register struct tty *tp;
328 {
329 
330 	(void) spl5();
331 	while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
332 		(*tp->t_oproc)(tp);
333 		tp->t_state |= ASLEEP;
334 		sleep((caddr_t)&tp->t_outq, TTOPRI);
335 	}
336 	flushtty(tp);
337 	(void) spl0();
338 }
339 
340 /*
341  * flush all TTY queues
342  */
343 flushtty(tp)
344 register struct tty *tp;
345 {
346 	register s;
347 
348 	s = spl6();
349 	while (getc(&tp->t_canq) >= 0)
350 		;
351 	wakeup((caddr_t)&tp->t_rawq);
352 	wakeup((caddr_t)&tp->t_outq);
353 	tp->t_state &= ~TTSTOP;
354 	(*cdevsw[major(tp->t_dev)].d_stop)(tp);
355 	while (getc(&tp->t_outq) >= 0)
356 		;
357 	while (getc(&tp->t_rawq) >= 0)
358 		;
359 	tp->t_delct = 0;
360 	splx(s);
361 }
362 
363 
364 
365 /*
366  * transfer raw input list to canonical list,
367  * doing erase-kill processing and handling escapes.
368  * It waits until a full line has been typed in cooked mode,
369  * or until any character has been typed in raw mode.
370  */
371 canon(tp)
372 register struct tty *tp;
373 {
374 	register char *bp;
375 	char *bp1;
376 	register int c;
377 	int mc;
378 	int s;
379 
380 	if ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
381 	    || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
382 		return(-1);
383 	}
384 	s = spl0();
385 loop:
386 	bp = &canonb[2];
387 	while ((c=getc(&tp->t_rawq)) >= 0) {
388 		if ((tp->t_flags&(RAW|CBREAK))==0) {
389 			if (c==0377) {
390 				tp->t_delct--;
391 				break;
392 			}
393 			if (bp[-1]!='\\') {
394 				if (c==tp->t_erase) {
395 					if (bp > &canonb[2])
396 						bp--;
397 					continue;
398 				}
399 				if (c==tp->t_kill)
400 					goto loop;
401 				if (c==tun.t_eofc)
402 					continue;
403 			} else {
404 				mc = maptab[c];
405 				if (c==tp->t_erase || c==tp->t_kill)
406 					mc = c;
407 				if (mc && (mc==c || (tp->t_flags&LCASE))) {
408 					if (bp[-2] != '\\')
409 						c = mc;
410 					bp--;
411 				}
412 			}
413 		}
414 		*bp++ = c;
415 		if (bp>=canonb+CANBSIZ)
416 			break;
417 	}
418 	bp1 = &canonb[2];
419 	(void) b_to_q(bp1, bp-bp1, &tp->t_canq);
420 
421 	if (tp->t_state&TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
422 		if (putc(tun.t_startc, &tp->t_outq)==0) {
423 			tp->t_state &= ~TBLOCK;
424 			ttstart(tp);
425 		}
426 		tp->t_char = 0;
427 	}
428 
429 	splx(s);
430 	return(0);
431 }
432 
433 
434 /*
435  * block transfer input handler.
436  */
437 ttyrend(tp, pb, pe)
438 register struct tty *tp;
439 register char *pb, *pe;
440 {
441 	int	tandem;
442 
443 	tandem = tp->t_flags&TANDEM;
444 	if (tp->t_flags&RAW) {
445 		(void) b_to_q(pb, pe-pb, &tp->t_rawq);
446 		if (tp->t_chan)
447 			(void) sdata(tp->t_chan); else
448 			wakeup((caddr_t)&tp->t_rawq);
449 	} else {
450 		tp->t_flags &= ~TANDEM;
451 		while (pb < pe)
452 			ttyinput(*pb++, tp);
453 		tp->t_flags |= tandem;
454 	}
455 	if (tandem)
456 		ttyblock(tp);
457 }
458 
459 /*
460  * Place a character on raw TTY input queue, putting in delimiters
461  * and waking up top half as needed.
462  * Also echo if required.
463  * The arguments are the character and the appropriate
464  * tty structure.
465  */
466 ttyinput(c, tp)
467 register c;
468 register struct tty *tp;
469 {
470 	register int t_flags;
471 	register struct chan *cp;
472 
473 	tk_nin += 1;
474 	c &= 0377;
475 	t_flags = tp->t_flags;
476 	if (t_flags&TANDEM)
477 		ttyblock(tp);
478 	if ((t_flags&RAW)==0) {
479 		c &= 0177;
480 		if (tp->t_state&TTSTOP) {
481 			if (c==tun.t_startc) {
482 				tp->t_state &= ~TTSTOP;
483 				ttstart(tp);
484 				return;
485 			}
486 			if (c==tun.t_stopc)
487 				return;
488 			tp->t_state &= ~TTSTOP;
489 			ttstart(tp);
490 		} else {
491 			if (c==tun.t_stopc) {
492 				tp->t_state |= TTSTOP;
493 				(*cdevsw[major(tp->t_dev)].d_stop)(tp);
494 				return;
495 			}
496 			if (c==tun.t_startc)
497 				return;
498 		}
499 		if (c==tun.t_quitc || c==tun.t_intrc) {
500 			flushtty(tp);
501 			c = (c==tun.t_intrc) ? SIGINT:SIGQUIT;
502 			if (tp->t_chan)
503 				scontrol(tp->t_chan, M_SIG, c);
504 			else
505 				signal(tp->t_pgrp, c);
506 			return;
507 		}
508 		if (c=='\r' && t_flags&CRMOD)
509 			c = '\n';
510 	}
511 	if (tp->t_rawq.c_cc>TTYHOG) {
512 		flushtty(tp);
513 		return;
514 	}
515 	if (t_flags&LCASE && c>='A' && c<='Z')
516 		c += 'a'-'A';
517 	(void) putc(c, &tp->t_rawq);
518 	if (t_flags&(RAW|CBREAK)||(c=='\n'||c==tun.t_eofc||c==tun.t_brkc)) {
519 		if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
520 			tp->t_delct++;
521 		if ((cp=tp->t_chan)!=NULL)
522 			(void) sdata(cp); else
523 			wakeup((caddr_t)&tp->t_rawq);
524 	}
525 	if (t_flags&ECHO) {
526 		ttyoutput(c, tp);
527 		if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
528 			ttyoutput('\n', tp);
529 		ttstart(tp);
530 	}
531 }
532 
533 
534 /*
535  * Send stop character on input overflow.
536  */
537 ttyblock(tp)
538 register struct tty *tp;
539 {
540 	register x;
541 	x = q1.c_cc + q2.c_cc;
542 	if (q1.c_cc > TTYHOG) {
543 		flushtty(tp);
544 		tp->t_state &= ~TBLOCK;
545 	}
546 	if (x >= TTYHOG/2) {
547 		if (putc(tun.t_stopc, &tp->t_outq)==0) {
548 			tp->t_state |= TBLOCK;
549 			tp->t_char++;
550 			ttstart(tp);
551 		}
552 	}
553 }
554 
555 /*
556  * put character on TTY output queue, adding delays,
557  * expanding tabs, and handling the CR/NL bit.
558  * It is called both from the top half for output, and from
559  * interrupt level for echoing.
560  * The arguments are the character and the tty structure.
561  */
562 ttyoutput(c, tp)
563 register c;
564 register struct tty *tp;
565 {
566 	register char *colp;
567 	register ctype;
568 
569 	/*
570 	 * Ignore EOT in normal mode to avoid hanging up
571 	 * certain terminals.
572 	 * In raw mode dump the char unchanged.
573 	 */
574 	if ((tp->t_flags&RAW)==0) {
575 		c &= 0177;
576 		if ((tp->t_flags&CBREAK)==0 && c==CEOT)
577 			return;
578 	} else {
579 		tk_nout++;
580 		(void) putc(c, &tp->t_outq);
581 		return;
582 	}
583 
584 	/*
585 	 * Turn tabs to spaces as required
586 	 */
587 	if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
588 		c = 8 - (tp->t_col & 7);
589 		(void) b_to_q("        ", c, &tp->t_outq);
590 		tp->t_col += c;
591 		tk_nout += c;
592 		return;
593 	}
594 	tk_nout++;
595 	/*
596 	 * for upper-case-only terminals,
597 	 * generate escapes.
598 	 */
599 	if (tp->t_flags&LCASE) {
600 		colp = "({)}!|^~'`";
601 		while(*colp++)
602 			if(c == *colp++) {
603 				ttyoutput('\\', tp);
604 				c = colp[-2];
605 				break;
606 			}
607 		if ('a'<=c && c<='z')
608 			c += 'A' - 'a';
609 	}
610 	/*
611 	 * turn <nl> to <cr><lf> if desired.
612 	 */
613 	if (c=='\n' && tp->t_flags&CRMOD)
614 		ttyoutput('\r', tp);
615 	(void) putc(c, &tp->t_outq);
616 	/*
617 	 * Calculate delays.
618 	 * The numbers here represent clock ticks
619 	 * and are not necessarily optimal for all terminals.
620 	 * The delays are indicated by characters above 0200.
621 	 * In raw mode there are no delays and the
622 	 * transmission path is 8 bits wide.
623 	 */
624 	colp = &tp->t_col;
625 	ctype = partab[c];
626 	c = 0;
627 	switch (ctype&077) {
628 
629 	/* ordinary */
630 	case 0:
631 		(*colp)++;
632 
633 	/* non-printing */
634 	case 1:
635 		break;
636 
637 	/* backspace */
638 	case 2:
639 		if (*colp)
640 			(*colp)--;
641 		break;
642 
643 	/* newline */
644 	case 3:
645 		ctype = (tp->t_flags >> 8) & 03;
646 		if(ctype == 1) { /* tty 37 */
647 			if (*colp)
648 				c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
649 		} else
650 		if(ctype == 2) { /* vt05 */
651 			c = 6;
652 		}
653 		*colp = 0;
654 		break;
655 
656 	/* tab */
657 	case 4:
658 		ctype = (tp->t_flags >> 10) & 03;
659 		if(ctype == 1) { /* tty 37 */
660 			c = 1 - (*colp | ~07);
661 			if(c < 5)
662 				c = 0;
663 		}
664 		*colp |= 07;
665 		(*colp)++;
666 		break;
667 
668 	/* vertical motion */
669 	case 5:
670 		if(tp->t_flags & VTDELAY) /* tty 37 */
671 			c = 0177;
672 		break;
673 
674 	/* carriage return */
675 	case 6:
676 		ctype = (tp->t_flags >> 12) & 03;
677 		if(ctype == 1) { /* tn 300 */
678 			c = 5;
679 		} else if(ctype == 2) { /* ti 700 */
680 			c = 10;
681 		} else if(ctype == 3) { /* concept 100 */
682 			int i;
683 			for (i= *colp; i<9; i++)
684 				(void) putc(0177, &tp->t_outq);
685 		}
686 		*colp = 0;
687 	}
688 	if(c)
689 		(void) putc(c|0200, &tp->t_outq);
690 }
691 
692 /*
693  * Restart typewriter output following a delay
694  * timeout.
695  * The name of the routine is passed to the timeout
696  * subroutine and it is called during a clock interrupt.
697  */
698 ttrstrt(tp)
699 register struct tty *tp;
700 {
701 
702 	tp->t_state &= ~TIMEOUT;
703 	ttstart(tp);
704 }
705 
706 /*
707  * Start output on the typewriter. It is used from the top half
708  * after some characters have been put on the output queue,
709  * from the interrupt routine to transmit the next
710  * character, and after a timeout has finished.
711  */
712 ttstart(tp)
713 register struct tty *tp;
714 {
715 	register s;
716 
717 	s = spl5();
718 	if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
719 		(*tp->t_oproc)(tp);
720 	splx(s);
721 }
722 
723 /*
724  * Called from device's read routine after it has
725  * calculated the tty-structure given as argument.
726  */
727 ttread(tp)
728 register struct tty *tp;
729 {
730 register s;
731 
732 	if ((tp->t_state&CARR_ON)==0)
733 		return(-1);
734 	s = spl5();
735 	if (tp->t_canq.c_cc==0)
736 		while (canon(tp)<0)
737 			if (tp->t_chan==NULL) {
738 				sleep((caddr_t)&tp->t_rawq, TTIPRI);
739 			} else {
740 				splx(s);
741 				return(0);
742 			}
743 	splx(s);
744 	while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
745 			;
746 	return(tp->t_rawq.c_cc+tp->t_canq.c_cc);
747 }
748 
749 /*
750  * Called from the device's write routine after it has
751  * calculated the tty-structure given as argument.
752  */
753 caddr_t
754 ttwrite(tp)
755 register struct tty *tp;
756 {
757 	/*
758 	 * THE POSITIONING OF CP, CC, AND CE ARE CRITICAL
759 	 * AND MUST NOT BE CHANGED WITHOUT PATCHING
760 	 * THE 'ASM' INLINES BELOW.  WATCH OUT.
761 	 */
762 	register char *cp;
763 	register int cc, ce;
764 	register i;
765 	char obuf[OBUFSIZ];
766 
767 	if ((tp->t_state&CARR_ON)==0)
768 		return(NULL);
769 	while (u.u_count) {
770 		cc = MIN(u.u_count, OBUFSIZ);
771 		cp = obuf;
772 		iomove(cp, (unsigned)cc, B_WRITE);
773 		if (u.u_error)
774 			break;
775 		(void) spl5();
776 		while (tp->t_outq.c_cc > TTHIWAT) {
777 			ttstart(tp);
778 			tp->t_state |= ASLEEP;
779 			if (tp->t_chan) {
780 				u.u_base -= cc;
781 				u.u_offset -= cc;
782 				u.u_count += cc;
783 				(void) spl0();
784 				return((caddr_t)&tp->t_outq);
785 			}
786 			sleep((caddr_t)&tp->t_outq, TTOPRI);
787 		}
788 		(void) spl0();
789 		if (tp->t_flags&LCASE) {
790 			while (cc--)
791 				ttyoutput(*cp++,tp);
792 			continue;
793 		}
794 		while (cc) {
795 			if (tp->t_flags&RAW)
796 				ce=cc;
797 			else {
798 #ifdef VAX
799 				asm("	scanc	r9,(r10),_partab,$077");
800 				asm("	subl3	r0,r9,r8");
801 #else
802 				ce=0;
803 				while(((partab[*(cp+ce)]&077)==0)&&(ce<cc))
804 					ce++;
805 #endif
806 				if (ce==0) {
807 					ttyoutput(*cp++,tp);
808 					cc--;
809 					goto check;
810 				}
811 			}
812 			i=b_to_q(cp,ce,&tp->t_outq);
813 			ce-=i;
814 			tk_nout+=ce;
815 			tp->t_col+=ce;
816 			cp+=ce;
817 			cc-=ce;
818 			if (i == 0)
819 				continue;
820 check:
821 			if (tp->t_outq.c_cc > TTHIWAT) {
822 				(void) spl5();
823 				while (tp->t_outq.c_cc > TTHIWAT) {
824 					ttstart(tp);
825 					tp->t_state |= ASLEEP;
826 					sleep((caddr_t)&tp->t_outq, TTOPRI);
827 				}
828 				(void) spl0();
829 			}
830 		}
831 	}
832 	ttstart(tp);
833 	return(NULL);
834 }
835