xref: /csrg-svn/sys/kern/tty_subr.c (revision 23391)
1*23391Smckusick /*
2*23391Smckusick  * Copyright (c) 1982 Regents of the University of California.
3*23391Smckusick  * All rights reserved.  The Berkeley software License Agreement
4*23391Smckusick  * specifies the terms and conditions for redistribution.
5*23391Smckusick  *
6*23391Smckusick  *	@(#)tty_subr.c	6.10 (Berkeley) 06/08/85
7*23391Smckusick  */
81892Swnj 
917097Sbloom #include "param.h"
1017097Sbloom #include "systm.h"
1117097Sbloom #include "buf.h"
1217576Sbloom #include "ioctl.h"
1317097Sbloom #include "tty.h"
1417097Sbloom #include "clist.h"
1532Sbill 
161890Swnj char	cwaiting;
171890Swnj 
1832Sbill /*
1932Sbill  * Character list get/put
2032Sbill  */
2132Sbill getc(p)
2212754Ssam 	register struct clist *p;
2332Sbill {
2432Sbill 	register struct cblock *bp;
2532Sbill 	register int c, s;
2632Sbill 
2717542Skarels 	s = spltty();
2832Sbill 	if (p->c_cc <= 0) {
2932Sbill 		c = -1;
3032Sbill 		p->c_cc = 0;
3132Sbill 		p->c_cf = p->c_cl = NULL;
3232Sbill 	} else {
3332Sbill 		c = *p->c_cf++ & 0377;
3432Sbill 		if (--p->c_cc<=0) {
3532Sbill 			bp = (struct cblock *)(p->c_cf-1);
3632Sbill 			bp = (struct cblock *) ((int)bp & ~CROUND);
3732Sbill 			p->c_cf = NULL;
3832Sbill 			p->c_cl = NULL;
3932Sbill 			bp->c_next = cfreelist;
4032Sbill 			cfreelist = bp;
411890Swnj 			cfreecount += CBSIZE;
421890Swnj 			if (cwaiting) {
431890Swnj 				wakeup(&cwaiting);
441890Swnj 				cwaiting = 0;
451890Swnj 			}
4632Sbill 		} else if (((int)p->c_cf & CROUND) == 0){
4732Sbill 			bp = (struct cblock *)(p->c_cf);
4832Sbill 			bp--;
4932Sbill 			p->c_cf = bp->c_next->c_info;
5032Sbill 			bp->c_next = cfreelist;
5132Sbill 			cfreelist = bp;
521890Swnj 			cfreecount += CBSIZE;
531890Swnj 			if (cwaiting) {
541890Swnj 				wakeup(&cwaiting);
551890Swnj 				cwaiting = 0;
561890Swnj 			}
5732Sbill 		}
5832Sbill 	}
5932Sbill 	splx(s);
6032Sbill 	return(c);
6132Sbill }
6232Sbill 
6332Sbill /*
6432Sbill  * copy clist to buffer.
6532Sbill  * return number of bytes moved.
6632Sbill  */
6732Sbill q_to_b(q, cp, cc)
689761Ssam 	register struct clist *q;
699761Ssam 	register char *cp;
7032Sbill {
7132Sbill 	register struct cblock *bp;
7232Sbill 	register int s;
7317542Skarels 	register nc;
7432Sbill 	char *acp;
7532Sbill 
7632Sbill 	if (cc <= 0)
7732Sbill 		return(0);
7817542Skarels 	s = spltty();
7932Sbill 	if (q->c_cc <= 0) {
8032Sbill 		q->c_cc = 0;
8132Sbill 		q->c_cf = q->c_cl = NULL;
821890Swnj 		splx(s);
8332Sbill 		return(0);
8432Sbill 	}
8532Sbill 	acp = cp;
8632Sbill 
8717542Skarels 	while (cc) {
8817542Skarels 		nc = sizeof(struct cblock) - ((int)q->c_cf & CROUND);
8917542Skarels 		nc = MIN(nc, cc);
9017542Skarels 		nc = MIN(nc, q->c_cc);
9117542Skarels 		(void) bcopy(q->c_cf, cp, (unsigned)nc);
9217542Skarels 		q->c_cf += nc;
9317542Skarels 		q->c_cc -= nc;
9417542Skarels 		cc -= nc;
9517542Skarels 		cp += nc;
9617542Skarels 		if (q->c_cc <= 0) {
9717542Skarels 			bp = (struct cblock *)(q->c_cf - 1);
9832Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
9932Sbill 			q->c_cf = q->c_cl = NULL;
10032Sbill 			bp->c_next = cfreelist;
10132Sbill 			cfreelist = bp;
1021890Swnj 			cfreecount += CBSIZE;
1031890Swnj 			if (cwaiting) {
1041890Swnj 				wakeup(&cwaiting);
1051890Swnj 				cwaiting = 0;
1061890Swnj 			}
10732Sbill 			break;
10832Sbill 		}
10932Sbill 		if (((int)q->c_cf & CROUND) == 0) {
11032Sbill 			bp = (struct cblock *)(q->c_cf);
11132Sbill 			bp--;
11232Sbill 			q->c_cf = bp->c_next->c_info;
11332Sbill 			bp->c_next = cfreelist;
11432Sbill 			cfreelist = bp;
1151890Swnj 			cfreecount += CBSIZE;
1161890Swnj 			if (cwaiting) {
1171890Swnj 				wakeup(&cwaiting);
1181890Swnj 				cwaiting = 0;
1191890Swnj 			}
12032Sbill 		}
12132Sbill 	}
12232Sbill 	splx(s);
12332Sbill 	return(cp-acp);
12432Sbill }
12532Sbill 
12632Sbill /*
12732Sbill  * Return count of contiguous characters
12832Sbill  * in clist starting at q->c_cf.
12932Sbill  * Stop counting if flag&character is non-null.
13032Sbill  */
13132Sbill ndqb(q, flag)
1329761Ssam 	register struct clist *q;
13332Sbill {
1349761Ssam 	register cc;
1359761Ssam 	int s;
13632Sbill 
13717542Skarels 	s = spltty();
13832Sbill 	if (q->c_cc <= 0) {
13932Sbill 		cc = -q->c_cc;
14032Sbill 		goto out;
14132Sbill 	}
14232Sbill 	cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
14332Sbill 	cc -= (int)q->c_cf;
14432Sbill 	if (q->c_cc < cc)
14532Sbill 		cc = q->c_cc;
14632Sbill 	if (flag) {
14732Sbill 		register char *p, *end;
14832Sbill 
14932Sbill 		p = q->c_cf;
15032Sbill 		end = p;
15132Sbill 		end += cc;
15232Sbill 		while (p < end) {
15332Sbill 			if (*p & flag) {
1541890Swnj 				cc = (int)p;
1551890Swnj 				cc -= (int)q->c_cf;
15632Sbill 				break;
15732Sbill 			}
15832Sbill 			p++;
15932Sbill 		}
16032Sbill 	}
16132Sbill out:
16232Sbill 	splx(s);
16332Sbill 	return(cc);
16432Sbill }
16532Sbill 
1661890Swnj 
1671890Swnj 
16832Sbill /*
1691890Swnj  * Flush cc bytes from q.
17032Sbill  */
17132Sbill ndflush(q, cc)
17212754Ssam 	register struct clist *q;
17312754Ssam 	register cc;
17432Sbill {
17512754Ssam 	register struct cblock *bp;
17612754Ssam 	char *end;
17712754Ssam 	int rem, s;
17832Sbill 
17917542Skarels 	s = spltty();
18010749Seric 	if (q->c_cc <= 0) {
18132Sbill 		goto out;
18232Sbill 	}
1831890Swnj 	while (cc>0 && q->c_cc) {
1841890Swnj 		bp = (struct cblock *)((int)q->c_cf & ~CROUND);
1851890Swnj 		if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
1861890Swnj 			end = q->c_cl;
1871890Swnj 		} else {
1881890Swnj 			end = (char *)((int)bp + sizeof (struct cblock));
1891890Swnj 		}
1901890Swnj 		rem = end - q->c_cf;
1911890Swnj 		if (cc >= rem) {
1921890Swnj 			cc -= rem;
1931890Swnj 			q->c_cc -= rem;
19432Sbill 			q->c_cf = bp->c_next->c_info;
1951890Swnj 			bp->c_next = cfreelist;
1961890Swnj 			cfreelist = bp;
1971890Swnj 			cfreecount += CBSIZE;
1981890Swnj 			if (cwaiting) {
1991890Swnj 				wakeup(&cwaiting);
2001890Swnj 				cwaiting = 0;
2011890Swnj 			}
20232Sbill 		} else {
2031890Swnj 			q->c_cc -= cc;
2041890Swnj 			q->c_cf += cc;
2051890Swnj 			if (q->c_cc <= 0) {
2061890Swnj 				bp->c_next = cfreelist;
2071890Swnj 				cfreelist = bp;
2081890Swnj 				cfreecount += CBSIZE;
2091890Swnj 				if (cwaiting) {
2101890Swnj 					wakeup(&cwaiting);
2111890Swnj 					cwaiting = 0;
2121890Swnj 				}
2131890Swnj 			}
2141890Swnj 			break;
21532Sbill 		}
2161890Swnj 	}
2171890Swnj 	if (q->c_cc <= 0) {
21832Sbill 		q->c_cf = q->c_cl = NULL;
2191890Swnj 		q->c_cc = 0;
22032Sbill 	}
22132Sbill out:
22232Sbill 	splx(s);
22332Sbill }
224172Sbill 
2251890Swnj 
22632Sbill putc(c, p)
22712754Ssam 	register struct clist *p;
22832Sbill {
22932Sbill 	register struct cblock *bp;
23032Sbill 	register char *cp;
23132Sbill 	register s;
23232Sbill 
23317542Skarels 	s = spltty();
23432Sbill 	if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
23532Sbill 		if ((bp = cfreelist) == NULL) {
23632Sbill 			splx(s);
23732Sbill 			return(-1);
23832Sbill 		}
23932Sbill 		cfreelist = bp->c_next;
2401890Swnj 		cfreecount -= CBSIZE;
24132Sbill 		bp->c_next = NULL;
24232Sbill 		p->c_cf = cp = bp->c_info;
24332Sbill 	} else if (((int)cp & CROUND) == 0) {
24432Sbill 		bp = (struct cblock *)cp - 1;
24532Sbill 		if ((bp->c_next = cfreelist) == NULL) {
24632Sbill 			splx(s);
24732Sbill 			return(-1);
24832Sbill 		}
24932Sbill 		bp = bp->c_next;
25032Sbill 		cfreelist = bp->c_next;
2511890Swnj 		cfreecount -= CBSIZE;
25232Sbill 		bp->c_next = NULL;
25332Sbill 		cp = bp->c_info;
25432Sbill 	}
25532Sbill 	*cp++ = c;
25632Sbill 	p->c_cc++;
25732Sbill 	p->c_cl = cp;
25832Sbill 	splx(s);
25932Sbill 	return(0);
26032Sbill }
26132Sbill 
2621890Swnj 
2631890Swnj 
26432Sbill /*
26532Sbill  * copy buffer to clist.
26632Sbill  * return number of bytes not transfered.
26732Sbill  */
26832Sbill b_to_q(cp, cc, q)
26912754Ssam 	register char *cp;
27012754Ssam 	struct clist *q;
27112754Ssam 	register int cc;
27232Sbill {
27332Sbill 	register char *cq;
27432Sbill 	register struct cblock *bp;
27517542Skarels 	register s, nc;
27617542Skarels 	int acc;
27732Sbill 
27832Sbill 	if (cc <= 0)
27917542Skarels 		return(0);
28017542Skarels 	acc = cc;
28117542Skarels 	s = spltty();
28217542Skarels 	if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
28317542Skarels 		if ((bp = cfreelist) == NULL)
28417542Skarels 			goto out;
28517542Skarels 		cfreelist = bp->c_next;
28617542Skarels 		cfreecount -= CBSIZE;
28717542Skarels 		bp->c_next = NULL;
28817542Skarels 		q->c_cf = cq = bp->c_info;
28917542Skarels 	}
29017542Skarels 
29117542Skarels 	while (cc) {
29232Sbill 		if (((int)cq & CROUND) == 0) {
29317542Skarels 			bp = (struct cblock *) cq - 1;
29417542Skarels 			if ((bp->c_next = cfreelist) == NULL)
29517542Skarels 				goto out;
29632Sbill 			bp = bp->c_next;
29732Sbill 			cfreelist = bp->c_next;
2981890Swnj 			cfreecount -= CBSIZE;
29932Sbill 			bp->c_next = NULL;
30017542Skarels 			cq = bp->c_info;
30132Sbill 		}
30217542Skarels 		nc = MIN(cc, sizeof(struct cblock) - ((int)cq & CROUND));
30317542Skarels 		(void) bcopy(cp, cq, (unsigned)nc);
30417542Skarels 		cp += nc;
30517542Skarels 		cq += nc;
30617542Skarels 		cc -= nc;
30732Sbill 	}
30817542Skarels out:
30917542Skarels 	q->c_cl = cq;
31017542Skarels 	q->c_cc += acc - cc;
31117542Skarels 	splx(s);
31217368Ssam 	return (cc);
31332Sbill }
31432Sbill 
31532Sbill /*
316172Sbill  * Given a non-NULL pointter into the list (like c_cf which
317172Sbill  * always points to a real character if non-NULL) return the pointer
318172Sbill  * to the next character in the list or return NULL if no more chars.
319172Sbill  *
320172Sbill  * Callers must not allow getc's to happen between nextc's so that the
321172Sbill  * pointer becomes invalid.  Note that interrupts are NOT masked.
322172Sbill  */
323172Sbill char *
324172Sbill nextc(p, cp)
32512754Ssam 	register struct clist *p;
32612754Ssam 	register char *cp;
327172Sbill {
328172Sbill 
329172Sbill 	if (p->c_cc && ++cp != p->c_cl) {
330172Sbill 		if (((int)cp & CROUND) == 0)
331172Sbill 			return (((struct cblock *)cp)[-1].c_next->c_info);
332172Sbill 		return (cp);
333172Sbill 	}
334172Sbill 	return (0);
335172Sbill }
336172Sbill 
337172Sbill /*
338172Sbill  * Remove the last character in the list and return it.
339172Sbill  */
340172Sbill unputc(p)
34112754Ssam 	register struct clist *p;
342172Sbill {
343172Sbill 	register struct cblock *bp;
344172Sbill 	register int c, s;
345172Sbill 	struct cblock *obp;
346172Sbill 
34717542Skarels 	s = spltty();
348172Sbill 	if (p->c_cc <= 0)
349172Sbill 		c = -1;
350172Sbill 	else {
351172Sbill 		c = *--p->c_cl;
352172Sbill 		if (--p->c_cc <= 0) {
353172Sbill 			bp = (struct cblock *)p->c_cl;
354172Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
355172Sbill 			p->c_cl = p->c_cf = NULL;
356172Sbill 			bp->c_next = cfreelist;
357172Sbill 			cfreelist = bp;
3581890Swnj 			cfreecount += CBSIZE;
359172Sbill 		} else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) {
360172Sbill 			p->c_cl = (char *)((int)p->c_cl & ~CROUND);
361172Sbill 			bp = (struct cblock *)p->c_cf;
362172Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
363172Sbill 			while (bp->c_next != (struct cblock *)p->c_cl)
364172Sbill 				bp = bp->c_next;
365172Sbill 			obp = bp;
366172Sbill 			p->c_cl = (char *)(bp + 1);
367172Sbill 			bp = bp->c_next;
368172Sbill 			bp->c_next = cfreelist;
369172Sbill 			cfreelist = bp;
3701890Swnj 			cfreecount += CBSIZE;
371172Sbill 			obp->c_next = NULL;
372172Sbill 		}
373172Sbill 	}
374172Sbill 	splx(s);
375172Sbill 	return (c);
376172Sbill }
377172Sbill 
378172Sbill /*
379172Sbill  * Put the chars in the from que
380172Sbill  * on the end of the to que.
381172Sbill  */
382172Sbill catq(from, to)
38312754Ssam 	struct clist *from, *to;
384172Sbill {
38517542Skarels 	char bbuf[CBSIZE*4];
38617542Skarels 	register s, c;
387172Sbill 
38817542Skarels 	s = spltty();
38917542Skarels 	if (to->c_cc == 0) {
39017542Skarels 		*to = *from;
39117542Skarels 		from->c_cc = 0;
39217542Skarels 		from->c_cf = NULL;
39317542Skarels 		from->c_cl = NULL;
39417542Skarels 		splx(s);
39517542Skarels 		return;
39617542Skarels 	}
39717542Skarels 	splx(s);
39817542Skarels 	while (from->c_cc > 0) {
39917542Skarels 		c = q_to_b(from, bbuf, sizeof bbuf);
40017542Skarels 		(void) b_to_q(bbuf, c, to);
40117542Skarels 	}
402172Sbill }
403172Sbill 
40417542Skarels #ifdef unneeded
405172Sbill /*
4069761Ssam  * Integer (short) get/put
40732Sbill  * using clists
40832Sbill  */
40917542Skarels typedef	u_short word_t;
4109761Ssam 
41132Sbill getw(p)
4128955Sroot 	register struct clist *p;
41332Sbill {
41417542Skarels 	register int s, c;
41517542Skarels 	register struct cblock *bp;
41632Sbill 
41717542Skarels 	if (p->c_cc <= 1)
41817542Skarels 		return(-1);
41917542Skarels 	if (p->c_cc & 01) {
42017542Skarels 		c = getc(p);
42117542Skarels 		return(c | (getc(p)<<8));
42217542Skarels 	}
42317542Skarels 	s = spltty();
42417542Skarels 	c = *((word_t *)p->c_cf);
42517542Skarels 	p->c_cf += sizeof(word_t);
42617542Skarels 	p->c_cc -= sizeof(word_t);
42717542Skarels 	if (p->c_cc <= 0) {
42817542Skarels 		bp = (struct cblock *)(p->c_cf-1);
42917542Skarels 		bp = (struct cblock *) ((int)bp & ~CROUND);
43017542Skarels 		p->c_cf = NULL;
43117542Skarels 		p->c_cl = NULL;
43217542Skarels 		bp->c_next = cfreelist;
43317542Skarels 		cfreelist = bp;
43417542Skarels 		cfreecount += CBSIZE;
43517542Skarels 		if (cwaiting) {
43617542Skarels 			wakeup(&cwaiting);
43717542Skarels 			cwaiting = 0;
43817542Skarels 		}
43917542Skarels 	} else if (((int)p->c_cf & CROUND) == 0) {
44017542Skarels 		bp = (struct cblock *)(p->c_cf);
44117542Skarels 		bp--;
44217542Skarels 		p->c_cf = bp->c_next->c_info;
44317542Skarels 		bp->c_next = cfreelist;
44417542Skarels 		cfreelist = bp;
44517542Skarels 		cfreecount += CBSIZE;
44617542Skarels 		if (cwaiting) {
44717542Skarels 			wakeup(&cwaiting);
44817542Skarels 			cwaiting = 0;
44917542Skarels 		}
45017542Skarels 	}
45117542Skarels 	splx(s);
45217542Skarels 	return (c);
45332Sbill }
45432Sbill 
45532Sbill putw(c, p)
4568955Sroot 	register struct clist *p;
45717542Skarels 	word_t c;
45832Sbill {
45932Sbill 	register s;
46017542Skarels 	register struct cblock *bp;
46117542Skarels 	register char *cp;
46232Sbill 
46317542Skarels 	s = spltty();
46432Sbill 	if (cfreelist==NULL) {
46532Sbill 		splx(s);
46632Sbill 		return(-1);
46732Sbill 	}
46817542Skarels 	if (p->c_cc & 01) {
46917542Skarels 		(void) putc(c, p);
47017542Skarels 		(void) putc(c>>8, p);
47117542Skarels 	} else {
47217542Skarels 		if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
47317542Skarels 			if ((bp = cfreelist) == NULL) {
47417542Skarels 				splx(s);
47517542Skarels 				return (-1);
47617542Skarels 			}
47717542Skarels 			cfreelist = bp->c_next;
47817542Skarels 			cfreecount -= CBSIZE;
47917542Skarels 			bp->c_next = NULL;
48017542Skarels 			p->c_cf = cp = bp->c_info;
48117542Skarels 		} else if (((int)cp & CROUND) == 0) {
48217542Skarels 			bp = (struct cblock *)cp - 1;
48317542Skarels 			if ((bp->c_next = cfreelist) == NULL) {
48417542Skarels 				splx(s);
48517542Skarels 				return (-1);
48617542Skarels 			}
48717542Skarels 			bp = bp->c_next;
48817542Skarels 			cfreelist = bp->c_next;
48917542Skarels 			cfreecount -= CBSIZE;
49017542Skarels 			bp->c_next = NULL;
49117542Skarels 			cp = bp->c_info;
49217542Skarels 		}
49317542Skarels 		*(word_t *)cp = c;
49417542Skarels 		p->c_cl = cp + sizeof(word_t);
49517542Skarels 		p->c_cc += sizeof(word_t);
49617542Skarels 	}
49732Sbill 	splx(s);
4989761Ssam 	return (0);
49932Sbill }
50017542Skarels #endif unneeded
501