xref: /csrg-svn/sys/kern/tty_subr.c (revision 172)
1*172Sbill /*	tty_subr.c	3.3	10/14/12	*/
232Sbill 
332Sbill #include "../h/param.h"
432Sbill #include "../h/tty.h"
532Sbill #include "../h/systm.h"
632Sbill #include "../h/conf.h"
732Sbill #include "../h/buf.h"
832Sbill 
932Sbill struct cblock {
1032Sbill 	struct cblock *c_next;
1132Sbill 	char	c_info[CBSIZE];
1232Sbill };
1332Sbill 
1432Sbill struct	cblock	cfree[NCLIST];
15*172Sbill int	cbad;
1632Sbill struct	cblock	*cfreelist;
1732Sbill 
1832Sbill /*
1932Sbill  * Character list get/put
2032Sbill  */
2132Sbill getc(p)
2232Sbill register struct clist *p;
2332Sbill {
2432Sbill 	register struct cblock *bp;
2532Sbill 	register int c, s;
2632Sbill 
2732Sbill 	s = spl6();
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;
4132Sbill 		} else if (((int)p->c_cf & CROUND) == 0){
4232Sbill 			bp = (struct cblock *)(p->c_cf);
4332Sbill 			bp--;
4432Sbill 			p->c_cf = bp->c_next->c_info;
4532Sbill 			bp->c_next = cfreelist;
4632Sbill 			cfreelist = bp;
4732Sbill 		}
4832Sbill 	}
4932Sbill 	splx(s);
5032Sbill 	return(c);
5132Sbill }
5232Sbill 
5332Sbill /*
5432Sbill  * copy clist to buffer.
5532Sbill  * return number of bytes moved.
5632Sbill  */
5732Sbill q_to_b(q, cp, cc)
5832Sbill register struct clist *q;
5932Sbill register char *cp;
6032Sbill {
6132Sbill 	register struct cblock *bp;
6232Sbill 	register int s;
6332Sbill 	char *acp;
6432Sbill 
6532Sbill 	if (cc <= 0)
6632Sbill 		return(0);
6732Sbill 	s = spl6();
6832Sbill 	if (q->c_cc <= 0) {
6932Sbill 		q->c_cc = 0;
7032Sbill 		q->c_cf = q->c_cl = NULL;
7132Sbill 		return(0);
7232Sbill 	}
7332Sbill 	acp = cp;
7432Sbill 	cc++;
7532Sbill 
7632Sbill 	while (--cc) {
7732Sbill 		*cp++ = *q->c_cf++;
7832Sbill 		if (--q->c_cc <= 0) {
7932Sbill 			bp = (struct cblock *)(q->c_cf-1);
8032Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
8132Sbill 			q->c_cf = q->c_cl = NULL;
8232Sbill 			bp->c_next = cfreelist;
8332Sbill 			cfreelist = bp;
8432Sbill 			break;
8532Sbill 		}
8632Sbill 		if (((int)q->c_cf & CROUND) == 0) {
8732Sbill 			bp = (struct cblock *)(q->c_cf);
8832Sbill 			bp--;
8932Sbill 			q->c_cf = bp->c_next->c_info;
9032Sbill 			bp->c_next = cfreelist;
9132Sbill 			cfreelist = bp;
9232Sbill 		}
9332Sbill 	}
9432Sbill 	splx(s);
9532Sbill 	return(cp-acp);
9632Sbill }
9732Sbill 
9832Sbill /*
9932Sbill  * Return count of contiguous characters
10032Sbill  * in clist starting at q->c_cf.
10132Sbill  * Stop counting if flag&character is non-null.
10232Sbill  */
10332Sbill ndqb(q, flag)
10432Sbill register struct clist *q;
10532Sbill {
10632Sbill register cc;
10732Sbill int s;
10832Sbill 
10932Sbill 	s = spl6();
11032Sbill 	if (q->c_cc <= 0) {
11132Sbill 		cc = -q->c_cc;
11232Sbill 		goto out;
11332Sbill 	}
11432Sbill 	cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
11532Sbill 	cc -= (int)q->c_cf;
11632Sbill 	if (q->c_cc < cc)
11732Sbill 		cc = q->c_cc;
11832Sbill 	if (flag) {
11932Sbill 		register char *p, *end;
12032Sbill 
12132Sbill 		p = q->c_cf;
12232Sbill 		end = p;
12332Sbill 		end += cc;
12432Sbill 		while (p < end) {
12532Sbill 			if (*p & flag) {
12632Sbill 				cc = (int)p - (int)q->c_cf;
12732Sbill 				break;
12832Sbill 			}
12932Sbill 			p++;
13032Sbill 		}
13132Sbill 	}
13232Sbill out:
13332Sbill 	splx(s);
13432Sbill 	return(cc);
13532Sbill }
13632Sbill 
13732Sbill /*
13832Sbill  * Update clist to show that cc characters
13932Sbill  * were removed.  It is assumed that cc < CBSIZE.
14032Sbill  */
14132Sbill ndflush(q, cc)
14232Sbill register struct clist *q;
14332Sbill register cc;
14432Sbill {
14532Sbill register s;
14632Sbill 
14732Sbill 	if (cc == 0)
14832Sbill 		return;
14932Sbill 	s = spl6();
15032Sbill 	if (q->c_cc < 0) {
15132Sbill 		if (q->c_cf != NULL) {
15232Sbill 			q->c_cc += cc;
15332Sbill 			q->c_cf += cc;
15432Sbill 			goto out;
15532Sbill 		}
15632Sbill 		q->c_cc = 0;
15732Sbill 		goto out;
15832Sbill 	}
15932Sbill 	if (q->c_cc == 0) {
16032Sbill 		goto out;
16132Sbill 	}
162*172Sbill 	if (cc > CBSIZE || cc <= 0) {
163*172Sbill 		cbad++;
164*172Sbill 		goto out;
165*172Sbill 	}
16632Sbill 	q->c_cc -= cc;
16732Sbill 	q->c_cf += cc;
16832Sbill 	if (((int)q->c_cf & CROUND) == 0) {
16932Sbill 		register struct cblock *bp;
17032Sbill 
17132Sbill 		bp = (struct cblock *)(q->c_cf) -1;
17232Sbill 		if (bp->c_next) {
17332Sbill 			q->c_cf = bp->c_next->c_info;
17432Sbill 		} else {
17532Sbill 			q->c_cf = q->c_cl = NULL;
17632Sbill 		}
17732Sbill 		bp->c_next = cfreelist;
17832Sbill 		cfreelist = bp;
17932Sbill 	} else
18032Sbill 	if (q->c_cc == 0) {
18132Sbill 		register struct cblock *bp;
18232Sbill 		q->c_cf = (char *)((int)q->c_cf & ~CROUND);
18332Sbill 		bp = (struct cblock *)(q->c_cf);
18432Sbill 		bp->c_next = cfreelist;
18532Sbill 		cfreelist = bp;
18632Sbill 		q->c_cf = q->c_cl = NULL;
18732Sbill 	}
18832Sbill out:
18932Sbill 	splx(s);
19032Sbill }
191*172Sbill 
192*172Sbill /*
193*172Sbill  * Put character c in queue p.
194*172Sbill  */
19532Sbill putc(c, p)
19632Sbill register struct clist *p;
19732Sbill {
19832Sbill 	register struct cblock *bp;
19932Sbill 	register char *cp;
20032Sbill 	register s;
20132Sbill 
20232Sbill 	s = spl6();
20332Sbill 	if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
20432Sbill 		if ((bp = cfreelist) == NULL) {
20532Sbill 			splx(s);
20632Sbill 			return(-1);
20732Sbill 		}
20832Sbill 		cfreelist = bp->c_next;
20932Sbill 		bp->c_next = NULL;
21032Sbill 		p->c_cf = cp = bp->c_info;
21132Sbill 	} else if (((int)cp & CROUND) == 0) {
21232Sbill 		bp = (struct cblock *)cp - 1;
21332Sbill 		if ((bp->c_next = cfreelist) == NULL) {
21432Sbill 			splx(s);
21532Sbill 			return(-1);
21632Sbill 		}
21732Sbill 		bp = bp->c_next;
21832Sbill 		cfreelist = bp->c_next;
21932Sbill 		bp->c_next = NULL;
22032Sbill 		cp = bp->c_info;
22132Sbill 	}
22232Sbill 	*cp++ = c;
22332Sbill 	p->c_cc++;
22432Sbill 	p->c_cl = cp;
22532Sbill 	splx(s);
22632Sbill 	return(0);
22732Sbill }
22832Sbill 
22932Sbill /*
23032Sbill  * copy buffer to clist.
23132Sbill  * return number of bytes not transfered.
23232Sbill  */
23332Sbill b_to_q(cp, cc, q)
23432Sbill register char *cp;
23532Sbill struct clist *q;
23632Sbill register int cc;
23732Sbill {
23832Sbill 	register char *cq;
23932Sbill 	register struct cblock *bp;
24032Sbill 	register s, acc;
24132Sbill 
24232Sbill 	if (cc <= 0)
24332Sbill 		return(0);
24432Sbill 	acc = cc;
24532Sbill 	s = spl6();
24632Sbill 	if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
24732Sbill 		if ((bp = cfreelist) == NULL)
24832Sbill 			goto out;
24932Sbill 		cfreelist = bp->c_next;
25032Sbill 		bp->c_next = NULL;
25132Sbill 		q->c_cf = cq = bp->c_info;
25232Sbill 	}
25332Sbill 
25432Sbill 	while (cc) {
25532Sbill 		if (((int)cq & CROUND) == 0) {
25632Sbill 			bp = (struct cblock *) cq - 1;
25732Sbill 			if ((bp->c_next = cfreelist) == NULL)
25832Sbill 				goto out;
25932Sbill 			bp = bp->c_next;
26032Sbill 			cfreelist = bp->c_next;
26132Sbill 			bp->c_next = NULL;
26232Sbill 			cq = bp->c_info;
26332Sbill 		}
26432Sbill 		*cq++ = *cp++;
26532Sbill 		cc--;
26632Sbill 	}
26732Sbill out:
26832Sbill 	q->c_cl = cq;
26932Sbill 	q->c_cc += acc-cc;
27032Sbill 	splx(s);
27132Sbill 	return(cc);
27232Sbill }
27332Sbill 
27432Sbill /*
275*172Sbill  * Given a non-NULL pointter into the list (like c_cf which
276*172Sbill  * always points to a real character if non-NULL) return the pointer
277*172Sbill  * to the next character in the list or return NULL if no more chars.
278*172Sbill  *
279*172Sbill  * Callers must not allow getc's to happen between nextc's so that the
280*172Sbill  * pointer becomes invalid.  Note that interrupts are NOT masked.
281*172Sbill  */
282*172Sbill char *
283*172Sbill nextc(p, cp)
284*172Sbill register struct clist *p;
285*172Sbill register char *cp;
286*172Sbill {
287*172Sbill 
288*172Sbill 	if (p->c_cc && ++cp != p->c_cl) {
289*172Sbill 		if (((int)cp & CROUND) == 0)
290*172Sbill 			return (((struct cblock *)cp)[-1].c_next->c_info);
291*172Sbill 		return (cp);
292*172Sbill 	}
293*172Sbill 	return (0);
294*172Sbill }
295*172Sbill 
296*172Sbill /*
297*172Sbill  * Remove the last character in the list and return it.
298*172Sbill  */
299*172Sbill unputc(p)
300*172Sbill register struct clist *p;
301*172Sbill {
302*172Sbill 	register struct cblock *bp;
303*172Sbill 	register int c, s;
304*172Sbill 	struct cblock *obp;
305*172Sbill 
306*172Sbill 	s = spl6();
307*172Sbill 	if (p->c_cc <= 0)
308*172Sbill 		c = -1;
309*172Sbill 	else {
310*172Sbill 		c = *--p->c_cl;
311*172Sbill 		if (--p->c_cc <= 0) {
312*172Sbill 			bp = (struct cblock *)p->c_cl;
313*172Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
314*172Sbill 			p->c_cl = p->c_cf = NULL;
315*172Sbill 			bp->c_next = cfreelist;
316*172Sbill 			cfreelist = bp;
317*172Sbill 		} else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) {
318*172Sbill 			p->c_cl = (char *)((int)p->c_cl & ~CROUND);
319*172Sbill 			bp = (struct cblock *)p->c_cf;
320*172Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
321*172Sbill 			while (bp->c_next != (struct cblock *)p->c_cl)
322*172Sbill 				bp = bp->c_next;
323*172Sbill 			obp = bp;
324*172Sbill 			p->c_cl = (char *)(bp + 1);
325*172Sbill 			bp = bp->c_next;
326*172Sbill 			bp->c_next = cfreelist;
327*172Sbill 			cfreelist = bp;
328*172Sbill 			obp->c_next = NULL;
329*172Sbill 		}
330*172Sbill 	}
331*172Sbill 	splx(s);
332*172Sbill 	return (c);
333*172Sbill }
334*172Sbill 
335*172Sbill /*
336*172Sbill  * Put the chars in the from que
337*172Sbill  * on the end of the to que.
338*172Sbill  *
339*172Sbill  * SHOULD JUST USE q_to_b AND THEN b_to_q HERE.
340*172Sbill  */
341*172Sbill catq(from, to)
342*172Sbill struct clist *from, *to;
343*172Sbill {
344*172Sbill 	register c;
345*172Sbill 
346*172Sbill 	while ((c = getc(from)) >= 0)
347*172Sbill 		(void) putc(c, to);
348*172Sbill }
349*172Sbill 
350*172Sbill /*
35132Sbill  * Initialize clist by freeing all character blocks, then count
35232Sbill  * number of character devices. (Once-only routine)
35332Sbill  */
35432Sbill cinit()
35532Sbill {
35632Sbill 	register int ccp;
35732Sbill 	register struct cblock *cp;
35832Sbill 	register struct cdevsw *cdp;
35932Sbill 
36032Sbill 	ccp = (int)cfree;
36132Sbill 	ccp = (ccp+CROUND) & ~CROUND;
36232Sbill 	for(cp=(struct cblock *)ccp; cp <= &cfree[NCLIST-1]; cp++) {
36332Sbill 		cp->c_next = cfreelist;
36432Sbill 		cfreelist = cp;
36532Sbill 	}
36632Sbill 	ccp = 0;
36732Sbill 	for(cdp = cdevsw; cdp->d_open; cdp++)
36832Sbill 		ccp++;
36932Sbill 	nchrdev = ccp;
37032Sbill }
37132Sbill 
37232Sbill /*
37332Sbill  * integer (2-byte) get/put
37432Sbill  * using clists
37532Sbill  */
37632Sbill /*
37732Sbill getw(p)
37832Sbill register struct clist *p;
37932Sbill {
38032Sbill 	register int s;
38132Sbill 
38232Sbill 	if (p->c_cc <= 1)
38332Sbill 		return(-1);
38432Sbill 	s = getc(p);
38532Sbill 	return(s | (getc(p)<<8));
38632Sbill }
38732Sbill */
38832Sbill 
38932Sbill putw(c, p)
39032Sbill register struct clist *p;
39132Sbill {
39232Sbill 	register s;
39332Sbill 
39432Sbill 	s = spl6();
39532Sbill 	if (cfreelist==NULL) {
39632Sbill 		splx(s);
39732Sbill 		return(-1);
39832Sbill 	}
399130Sbill 	(void) putc(c, p);
400130Sbill 	(void) putc(c>>8, p);
40132Sbill 	splx(s);
40232Sbill 	return(0);
40332Sbill }
404