xref: /csrg-svn/sys/kern/tty_subr.c (revision 2329)
1*2329Swnj /*	tty_subr.c	4.5	02/01/81	*/
21892Swnj 
332Sbill #include "../h/param.h"
432Sbill #include "../h/systm.h"
532Sbill #include "../h/conf.h"
632Sbill #include "../h/buf.h"
71890Swnj #include "../h/tty.h"
81950Swnj #include "tr.h"
932Sbill 
1032Sbill struct cblock {
111890Swnj 	struct	cblock *c_next;
1232Sbill 	char	c_info[CBSIZE];
1332Sbill };
1432Sbill 
151890Swnj struct	cblock cfree[NCLIST];
161890Swnj struct	cblock *cfreelist;
1732Sbill 
181890Swnj int	cfreecount;
191890Swnj char	cwaiting;
201890Swnj 
2132Sbill /*
2232Sbill  * Character list get/put
2332Sbill  */
2432Sbill getc(p)
2532Sbill register struct clist *p;
2632Sbill {
2732Sbill 	register struct cblock *bp;
2832Sbill 	register int c, s;
2932Sbill 
3032Sbill 	s = spl6();
3132Sbill 	if (p->c_cc <= 0) {
3232Sbill 		c = -1;
3332Sbill 		p->c_cc = 0;
3432Sbill 		p->c_cf = p->c_cl = NULL;
3532Sbill 	} else {
3632Sbill 		c = *p->c_cf++ & 0377;
3732Sbill 		if (--p->c_cc<=0) {
3832Sbill 			bp = (struct cblock *)(p->c_cf-1);
3932Sbill 			bp = (struct cblock *) ((int)bp & ~CROUND);
4032Sbill 			p->c_cf = NULL;
4132Sbill 			p->c_cl = NULL;
4232Sbill 			bp->c_next = cfreelist;
4332Sbill 			cfreelist = bp;
441890Swnj 			cfreecount += CBSIZE;
451890Swnj 			if (cwaiting) {
461890Swnj 				wakeup(&cwaiting);
471890Swnj 				cwaiting = 0;
481890Swnj 			}
4932Sbill 		} else if (((int)p->c_cf & CROUND) == 0){
5032Sbill 			bp = (struct cblock *)(p->c_cf);
5132Sbill 			bp--;
5232Sbill 			p->c_cf = bp->c_next->c_info;
5332Sbill 			bp->c_next = cfreelist;
5432Sbill 			cfreelist = bp;
551890Swnj 			cfreecount += CBSIZE;
561890Swnj 			if (cwaiting) {
571890Swnj 				wakeup(&cwaiting);
581890Swnj 				cwaiting = 0;
591890Swnj 			}
6032Sbill 		}
6132Sbill 	}
6232Sbill 	splx(s);
6332Sbill 	return(c);
6432Sbill }
6532Sbill 
661890Swnj #if HAVTR > 0
671890Swnj trgetc(p)
681890Swnj register struct clist *p;
691890Swnj {
701890Swnj 	register struct cblock *bp;
711890Swnj 	register int c, s;
721890Swnj 
731890Swnj 	if (p->c_cc <= 0) {
741890Swnj 		c = -1;
751890Swnj 		p->c_cc = 0;
761890Swnj 		p->c_cf = NULL;
771890Swnj 	} else {
781890Swnj 		c = *p->c_cf++ & 0377;
791890Swnj 		if (--p->c_cc<=0) {
801890Swnj 			p->c_cf = NULL;
811890Swnj 		} else if (((int)p->c_cf & CROUND) == 0) {
821890Swnj 			bp = (struct cblock *)(p->c_cf);
831890Swnj 			bp--;
841890Swnj 			p->c_cf = bp->c_next->c_info;
851890Swnj 		}
861890Swnj 	}
871890Swnj 	return(c);
881890Swnj }
891890Swnj #endif
901890Swnj 
9132Sbill /*
9232Sbill  * copy clist to buffer.
9332Sbill  * return number of bytes moved.
9432Sbill  */
9532Sbill q_to_b(q, cp, cc)
9632Sbill register struct clist *q;
9732Sbill register char *cp;
9832Sbill {
9932Sbill 	register struct cblock *bp;
10032Sbill 	register int s;
10132Sbill 	char *acp;
10232Sbill 
10332Sbill 	if (cc <= 0)
10432Sbill 		return(0);
10532Sbill 	s = spl6();
10632Sbill 	if (q->c_cc <= 0) {
10732Sbill 		q->c_cc = 0;
10832Sbill 		q->c_cf = q->c_cl = NULL;
1091890Swnj 		splx(s);
11032Sbill 		return(0);
11132Sbill 	}
11232Sbill 	acp = cp;
11332Sbill 	cc++;
11432Sbill 
11532Sbill 	while (--cc) {
11632Sbill 		*cp++ = *q->c_cf++;
11732Sbill 		if (--q->c_cc <= 0) {
11832Sbill 			bp = (struct cblock *)(q->c_cf-1);
11932Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
12032Sbill 			q->c_cf = q->c_cl = NULL;
12132Sbill 			bp->c_next = cfreelist;
12232Sbill 			cfreelist = bp;
1231890Swnj 			cfreecount += CBSIZE;
1241890Swnj 			if (cwaiting) {
1251890Swnj 				wakeup(&cwaiting);
1261890Swnj 				cwaiting = 0;
1271890Swnj 			}
12832Sbill 			break;
12932Sbill 		}
13032Sbill 		if (((int)q->c_cf & CROUND) == 0) {
13132Sbill 			bp = (struct cblock *)(q->c_cf);
13232Sbill 			bp--;
13332Sbill 			q->c_cf = bp->c_next->c_info;
13432Sbill 			bp->c_next = cfreelist;
13532Sbill 			cfreelist = bp;
1361890Swnj 			cfreecount += CBSIZE;
1371890Swnj 			if (cwaiting) {
1381890Swnj 				wakeup(&cwaiting);
1391890Swnj 				cwaiting = 0;
1401890Swnj 			}
14132Sbill 		}
14232Sbill 	}
14332Sbill 	splx(s);
14432Sbill 	return(cp-acp);
14532Sbill }
14632Sbill 
1471890Swnj #if HAVTR > 0
14832Sbill /*
1491890Swnj  * Traverse a clist copying its contents to a buffer.
1501890Swnj  * q->cc and q->cf are updated with the current position
1511890Swnj  * in the list, but bytes are not released to the freelist.
1521890Swnj  */
1531890Swnj trq_to_b(q, cp, cc)
1541890Swnj register struct clist *q;
1551890Swnj register char *cp;
1561890Swnj register cc;
1571890Swnj {
1581890Swnj 	register struct cblock *bp;
1591890Swnj 	char *acp;
1601890Swnj 
1611890Swnj 	if (cc <= 0)
1621890Swnj 		return(0);
1631890Swnj 	if (q->c_cc <= 0)
1641890Swnj 		return(0);
1651890Swnj 
1661890Swnj 	acp = cp;
1671890Swnj 	cc++;
1681890Swnj 	while (--cc) {
1691890Swnj 		*cp++ = *q->c_cf++;
1701890Swnj 		if (((int)q->c_cf & CROUND) == 0) {
1711890Swnj 			bp = (struct cblock *)(q->c_cf);
1721890Swnj 			bp--;
1731890Swnj 			q->c_cf = bp->c_next->c_info;
1741890Swnj 		}
1751890Swnj 		if (--q->c_cc <= 0)
1761890Swnj 			break;
1771890Swnj 	}
1781890Swnj 	return(cp-acp);
1791890Swnj }
1801890Swnj #endif
1811890Swnj 
1821890Swnj 
1831890Swnj /*
18432Sbill  * Return count of contiguous characters
18532Sbill  * in clist starting at q->c_cf.
18632Sbill  * Stop counting if flag&character is non-null.
18732Sbill  */
18832Sbill ndqb(q, flag)
18932Sbill register struct clist *q;
19032Sbill {
19132Sbill register cc;
19232Sbill int s;
19332Sbill 
19432Sbill 	s = spl6();
19532Sbill 	if (q->c_cc <= 0) {
19632Sbill 		cc = -q->c_cc;
19732Sbill 		goto out;
19832Sbill 	}
19932Sbill 	cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
20032Sbill 	cc -= (int)q->c_cf;
20132Sbill 	if (q->c_cc < cc)
20232Sbill 		cc = q->c_cc;
20332Sbill 	if (flag) {
20432Sbill 		register char *p, *end;
20532Sbill 
20632Sbill 		p = q->c_cf;
20732Sbill 		end = p;
20832Sbill 		end += cc;
20932Sbill 		while (p < end) {
21032Sbill 			if (*p & flag) {
2111890Swnj 				cc = (int)p;
2121890Swnj 				cc -= (int)q->c_cf;
21332Sbill 				break;
21432Sbill 			}
21532Sbill 			p++;
21632Sbill 		}
21732Sbill 	}
21832Sbill out:
21932Sbill 	splx(s);
22032Sbill 	return(cc);
22132Sbill }
22232Sbill 
2231890Swnj 
2241890Swnj 
22532Sbill /*
2261890Swnj  * Flush cc bytes from q.
22732Sbill  */
22832Sbill ndflush(q, cc)
22932Sbill register struct clist *q;
23032Sbill register cc;
23132Sbill {
2321890Swnj register struct cblock *bp;
2331890Swnj char *end;
2341890Swnj int rem;
23532Sbill register s;
23632Sbill 
23732Sbill 	s = spl6();
23832Sbill 	if (q->c_cc < 0) {
2391890Swnj 		printf("neg q flush\n");
24032Sbill 		goto out;
24132Sbill 	}
24232Sbill 	if (q->c_cc == 0) {
24332Sbill 		goto out;
24432Sbill 	}
2451890Swnj 	while (cc>0 && q->c_cc) {
2461890Swnj 		bp = (struct cblock *)((int)q->c_cf & ~CROUND);
2471890Swnj 		if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
2481890Swnj 			end = q->c_cl;
2491890Swnj 		} else {
2501890Swnj 			end = (char *)((int)bp + sizeof (struct cblock));
2511890Swnj 		}
2521890Swnj 		rem = end - q->c_cf;
2531890Swnj 		if (cc >= rem) {
2541890Swnj 			cc -= rem;
2551890Swnj 			q->c_cc -= rem;
25632Sbill 			q->c_cf = bp->c_next->c_info;
2571890Swnj 			bp->c_next = cfreelist;
2581890Swnj 			cfreelist = bp;
2591890Swnj 			cfreecount += CBSIZE;
2601890Swnj 			if (cwaiting) {
2611890Swnj 				wakeup(&cwaiting);
2621890Swnj 				cwaiting = 0;
2631890Swnj 			}
26432Sbill 		} else {
2651890Swnj 			q->c_cc -= cc;
2661890Swnj 			q->c_cf += cc;
2671890Swnj 			if (q->c_cc <= 0) {
2681890Swnj 				bp->c_next = cfreelist;
2691890Swnj 				cfreelist = bp;
2701890Swnj 				cfreecount += CBSIZE;
2711890Swnj 				if (cwaiting) {
2721890Swnj 					wakeup(&cwaiting);
2731890Swnj 					cwaiting = 0;
2741890Swnj 				}
2751890Swnj 			}
2761890Swnj 			break;
27732Sbill 		}
2781890Swnj 	}
2791890Swnj 	if (q->c_cc <= 0) {
28032Sbill 		q->c_cf = q->c_cl = NULL;
2811890Swnj 		q->c_cc = 0;
28232Sbill 	}
28332Sbill out:
28432Sbill 	splx(s);
28532Sbill }
286172Sbill 
2871890Swnj 
28832Sbill putc(c, p)
28932Sbill register struct clist *p;
29032Sbill {
29132Sbill 	register struct cblock *bp;
29232Sbill 	register char *cp;
29332Sbill 	register s;
29432Sbill 
29532Sbill 	s = spl6();
29632Sbill 	if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
29732Sbill 		if ((bp = cfreelist) == NULL) {
29832Sbill 			splx(s);
29932Sbill 			return(-1);
30032Sbill 		}
30132Sbill 		cfreelist = bp->c_next;
3021890Swnj 		cfreecount -= CBSIZE;
30332Sbill 		bp->c_next = NULL;
30432Sbill 		p->c_cf = cp = bp->c_info;
30532Sbill 	} else if (((int)cp & CROUND) == 0) {
30632Sbill 		bp = (struct cblock *)cp - 1;
30732Sbill 		if ((bp->c_next = cfreelist) == NULL) {
30832Sbill 			splx(s);
30932Sbill 			return(-1);
31032Sbill 		}
31132Sbill 		bp = bp->c_next;
31232Sbill 		cfreelist = bp->c_next;
3131890Swnj 		cfreecount -= CBSIZE;
31432Sbill 		bp->c_next = NULL;
31532Sbill 		cp = bp->c_info;
31632Sbill 	}
31732Sbill 	*cp++ = c;
31832Sbill 	p->c_cc++;
31932Sbill 	p->c_cl = cp;
32032Sbill 	splx(s);
32132Sbill 	return(0);
32232Sbill }
32332Sbill 
3241890Swnj 
3251890Swnj 
32632Sbill /*
32732Sbill  * copy buffer to clist.
32832Sbill  * return number of bytes not transfered.
32932Sbill  */
33032Sbill b_to_q(cp, cc, q)
33132Sbill register char *cp;
33232Sbill struct clist *q;
33332Sbill register int cc;
33432Sbill {
33532Sbill 	register char *cq;
33632Sbill 	register struct cblock *bp;
33732Sbill 	register s, acc;
33832Sbill 
33932Sbill 	if (cc <= 0)
34032Sbill 		return(0);
34132Sbill 	acc = cc;
3421890Swnj 
3431890Swnj 
34432Sbill 	s = spl6();
34532Sbill 	if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
34632Sbill 		if ((bp = cfreelist) == NULL)
34732Sbill 			goto out;
34832Sbill 		cfreelist = bp->c_next;
3491890Swnj 		cfreecount -= CBSIZE;
35032Sbill 		bp->c_next = NULL;
35132Sbill 		q->c_cf = cq = bp->c_info;
35232Sbill 	}
35332Sbill 
35432Sbill 	while (cc) {
35532Sbill 		if (((int)cq & CROUND) == 0) {
35632Sbill 			bp = (struct cblock *) cq - 1;
35732Sbill 			if ((bp->c_next = cfreelist) == NULL)
35832Sbill 				goto out;
35932Sbill 			bp = bp->c_next;
36032Sbill 			cfreelist = bp->c_next;
3611890Swnj 			cfreecount -= CBSIZE;
36232Sbill 			bp->c_next = NULL;
36332Sbill 			cq = bp->c_info;
36432Sbill 		}
36532Sbill 		*cq++ = *cp++;
36632Sbill 		cc--;
36732Sbill 	}
36832Sbill out:
36932Sbill 	q->c_cl = cq;
37032Sbill 	q->c_cc += acc-cc;
37132Sbill 	splx(s);
37232Sbill 	return(cc);
37332Sbill }
37432Sbill 
3751890Swnj char *
3761890Swnj wb_to_q(cp, cc, q)
3771890Swnj register char *cp;
3781890Swnj register struct clist *q;
3791890Swnj register cc;
3801890Swnj {
3811890Swnj char *f;
3821890Swnj register s;
3831890Swnj 
3841890Swnj 	s = spl6();
3851890Swnj 	while (cc > cfreecount) {
3861890Swnj 		cwaiting = 1;
3871890Swnj 		sleep(&cwaiting, TTOPRI);
3881890Swnj 	}
3891890Swnj 	if (q->c_cc==0) {
3901890Swnj 		b_to_q(cp, cc, q);
3911890Swnj 		f = q->c_cf;
3921890Swnj 	} else {
3931890Swnj 		(void) putc(*cp++, q);
3941890Swnj 		f = q->c_cl;
3951890Swnj 		f--;
3961890Swnj 		b_to_q(cp, --cc, q);
3971890Swnj 	}
3981890Swnj 	splx(s);
3991890Swnj 	return(f);
4001890Swnj }
4011890Swnj 
402*2329Swnj #ifdef UCBIPC
4031890Swnj char *
4041890Swnj nb_to_q(cp, cc, q)
4051890Swnj register char *cp;
4061890Swnj register struct clist *q;
4071890Swnj register cc;
4081890Swnj {
4091890Swnj char *f;
4101890Swnj register s;
4111890Swnj 
4121890Swnj 	s = spl6();
4131890Swnj 	if (cc > cfreecount) {
4141890Swnj 		f = NULL;
4151890Swnj 		goto out;
4161890Swnj 	}
4171890Swnj 	if (q->c_cc==0) {
4181890Swnj 		b_to_q(cp, cc, q);
4191890Swnj 		f = q->c_cf;
4201890Swnj 	} else {
4211890Swnj 		(void) putc(*cp++, q);
4221890Swnj 		f = q->c_cl;
4231890Swnj 		f--;
4241890Swnj 		b_to_q(cp, --cc, q);
4251890Swnj 	}
4261890Swnj out:
4271890Swnj 	splx(s);
4281890Swnj 	return(f);
4291890Swnj }
4301890Swnj #endif
4311890Swnj 
43232Sbill /*
433172Sbill  * Given a non-NULL pointter into the list (like c_cf which
434172Sbill  * always points to a real character if non-NULL) return the pointer
435172Sbill  * to the next character in the list or return NULL if no more chars.
436172Sbill  *
437172Sbill  * Callers must not allow getc's to happen between nextc's so that the
438172Sbill  * pointer becomes invalid.  Note that interrupts are NOT masked.
439172Sbill  */
440172Sbill char *
441172Sbill nextc(p, cp)
442172Sbill register struct clist *p;
443172Sbill register char *cp;
444172Sbill {
445172Sbill 
446172Sbill 	if (p->c_cc && ++cp != p->c_cl) {
447172Sbill 		if (((int)cp & CROUND) == 0)
448172Sbill 			return (((struct cblock *)cp)[-1].c_next->c_info);
449172Sbill 		return (cp);
450172Sbill 	}
451172Sbill 	return (0);
452172Sbill }
453172Sbill 
454172Sbill /*
455172Sbill  * Remove the last character in the list and return it.
456172Sbill  */
457172Sbill unputc(p)
458172Sbill register struct clist *p;
459172Sbill {
460172Sbill 	register struct cblock *bp;
461172Sbill 	register int c, s;
462172Sbill 	struct cblock *obp;
463172Sbill 
464172Sbill 	s = spl6();
465172Sbill 	if (p->c_cc <= 0)
466172Sbill 		c = -1;
467172Sbill 	else {
468172Sbill 		c = *--p->c_cl;
469172Sbill 		if (--p->c_cc <= 0) {
470172Sbill 			bp = (struct cblock *)p->c_cl;
471172Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
472172Sbill 			p->c_cl = p->c_cf = NULL;
473172Sbill 			bp->c_next = cfreelist;
474172Sbill 			cfreelist = bp;
4751890Swnj 			cfreecount += CBSIZE;
476172Sbill 		} else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) {
477172Sbill 			p->c_cl = (char *)((int)p->c_cl & ~CROUND);
478172Sbill 			bp = (struct cblock *)p->c_cf;
479172Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
480172Sbill 			while (bp->c_next != (struct cblock *)p->c_cl)
481172Sbill 				bp = bp->c_next;
482172Sbill 			obp = bp;
483172Sbill 			p->c_cl = (char *)(bp + 1);
484172Sbill 			bp = bp->c_next;
485172Sbill 			bp->c_next = cfreelist;
486172Sbill 			cfreelist = bp;
4871890Swnj 			cfreecount += CBSIZE;
488172Sbill 			obp->c_next = NULL;
489172Sbill 		}
490172Sbill 	}
491172Sbill 	splx(s);
492172Sbill 	return (c);
493172Sbill }
494172Sbill 
495172Sbill /*
496172Sbill  * Put the chars in the from que
497172Sbill  * on the end of the to que.
498172Sbill  *
499172Sbill  * SHOULD JUST USE q_to_b AND THEN b_to_q HERE.
500172Sbill  */
501172Sbill catq(from, to)
502172Sbill struct clist *from, *to;
503172Sbill {
504172Sbill 	register c;
505172Sbill 
506172Sbill 	while ((c = getc(from)) >= 0)
507172Sbill 		(void) putc(c, to);
508172Sbill }
509172Sbill 
510172Sbill /*
51132Sbill  * Initialize clist by freeing all character blocks, then count
51232Sbill  * number of character devices. (Once-only routine)
51332Sbill  */
51432Sbill cinit()
51532Sbill {
51632Sbill 	register int ccp;
51732Sbill 	register struct cblock *cp;
51832Sbill 	register struct cdevsw *cdp;
51932Sbill 
52032Sbill 	ccp = (int)cfree;
52132Sbill 	ccp = (ccp+CROUND) & ~CROUND;
5221890Swnj 	for(cp=(struct cblock *)ccp; cp < &cfree[NCLIST-1]; cp++) {
52332Sbill 		cp->c_next = cfreelist;
52432Sbill 		cfreelist = cp;
5251890Swnj 		cfreecount += CBSIZE;
52632Sbill 	}
52732Sbill 	ccp = 0;
52832Sbill 	for(cdp = cdevsw; cdp->d_open; cdp++)
52932Sbill 		ccp++;
53032Sbill 	nchrdev = ccp;
53132Sbill }
53232Sbill 
5331890Swnj 
53432Sbill /*
53532Sbill  * integer (2-byte) get/put
53632Sbill  * using clists
53732Sbill  */
53832Sbill getw(p)
53932Sbill register struct clist *p;
54032Sbill {
54132Sbill 	register int s;
54232Sbill 
54332Sbill 	if (p->c_cc <= 1)
54432Sbill 		return(-1);
54532Sbill 	s = getc(p);
54632Sbill 	return(s | (getc(p)<<8));
54732Sbill }
54832Sbill 
5491890Swnj #if HAVTR > 0
5501890Swnj trgetw(p)
5511890Swnj register struct clist *p;
5521890Swnj {
5531890Swnj 	register int w;
5541890Swnj 
5551890Swnj 	if (p->c_cc <=1)
5561890Swnj 		return(-1);
5571890Swnj 	w = trgetc(p);
5581890Swnj 	return(w | (trgetc(p)<<8));
5591890Swnj }
5601890Swnj #endif
5611890Swnj 
56232Sbill putw(c, p)
56332Sbill register struct clist *p;
56432Sbill {
56532Sbill 	register s;
56632Sbill 
56732Sbill 	s = spl6();
56832Sbill 	if (cfreelist==NULL) {
56932Sbill 		splx(s);
57032Sbill 		return(-1);
57132Sbill 	}
572130Sbill 	(void) putc(c, p);
573130Sbill 	(void) putc(c>>8, p);
57432Sbill 	splx(s);
57532Sbill 	return(0);
57632Sbill }
577