xref: /csrg-svn/sys/kern/tty_subr.c (revision 1892)
1*1892Swnj /*	tty_subr.c	4.3	12/16/80	*/
2*1892Swnj 
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"
832Sbill 
932Sbill struct cblock {
101890Swnj 	struct	cblock *c_next;
1132Sbill 	char	c_info[CBSIZE];
1232Sbill };
1332Sbill 
141890Swnj struct	cblock cfree[NCLIST];
151890Swnj struct	cblock *cfreelist;
1632Sbill 
171890Swnj int	cfreecount;
181890Swnj char	cwaiting;
191890Swnj 
2032Sbill /*
2132Sbill  * Character list get/put
2232Sbill  */
2332Sbill getc(p)
2432Sbill register struct clist *p;
2532Sbill {
2632Sbill 	register struct cblock *bp;
2732Sbill 	register int c, s;
2832Sbill 
2932Sbill 	s = spl6();
3032Sbill 	if (p->c_cc <= 0) {
3132Sbill 		c = -1;
3232Sbill 		p->c_cc = 0;
3332Sbill 		p->c_cf = p->c_cl = NULL;
3432Sbill 	} else {
3532Sbill 		c = *p->c_cf++ & 0377;
3632Sbill 		if (--p->c_cc<=0) {
3732Sbill 			bp = (struct cblock *)(p->c_cf-1);
3832Sbill 			bp = (struct cblock *) ((int)bp & ~CROUND);
3932Sbill 			p->c_cf = NULL;
4032Sbill 			p->c_cl = NULL;
4132Sbill 			bp->c_next = cfreelist;
4232Sbill 			cfreelist = bp;
431890Swnj 			cfreecount += CBSIZE;
441890Swnj 			if (cwaiting) {
451890Swnj 				wakeup(&cwaiting);
461890Swnj 				cwaiting = 0;
471890Swnj 			}
4832Sbill 		} else if (((int)p->c_cf & CROUND) == 0){
4932Sbill 			bp = (struct cblock *)(p->c_cf);
5032Sbill 			bp--;
5132Sbill 			p->c_cf = bp->c_next->c_info;
5232Sbill 			bp->c_next = cfreelist;
5332Sbill 			cfreelist = bp;
541890Swnj 			cfreecount += CBSIZE;
551890Swnj 			if (cwaiting) {
561890Swnj 				wakeup(&cwaiting);
571890Swnj 				cwaiting = 0;
581890Swnj 			}
5932Sbill 		}
6032Sbill 	}
6132Sbill 	splx(s);
6232Sbill 	return(c);
6332Sbill }
6432Sbill 
651890Swnj #if HAVTR > 0
661890Swnj trgetc(p)
671890Swnj register struct clist *p;
681890Swnj {
691890Swnj 	register struct cblock *bp;
701890Swnj 	register int c, s;
711890Swnj 
721890Swnj 	if (p->c_cc <= 0) {
731890Swnj 		c = -1;
741890Swnj 		p->c_cc = 0;
751890Swnj 		p->c_cf = NULL;
761890Swnj 	} else {
771890Swnj 		c = *p->c_cf++ & 0377;
781890Swnj 		if (--p->c_cc<=0) {
791890Swnj 			p->c_cf = NULL;
801890Swnj 		} else if (((int)p->c_cf & CROUND) == 0) {
811890Swnj 			bp = (struct cblock *)(p->c_cf);
821890Swnj 			bp--;
831890Swnj 			p->c_cf = bp->c_next->c_info;
841890Swnj 		}
851890Swnj 	}
861890Swnj 	return(c);
871890Swnj }
881890Swnj #endif
891890Swnj 
9032Sbill /*
9132Sbill  * copy clist to buffer.
9232Sbill  * return number of bytes moved.
9332Sbill  */
9432Sbill q_to_b(q, cp, cc)
9532Sbill register struct clist *q;
9632Sbill register char *cp;
9732Sbill {
9832Sbill 	register struct cblock *bp;
9932Sbill 	register int s;
10032Sbill 	char *acp;
10132Sbill 
10232Sbill 	if (cc <= 0)
10332Sbill 		return(0);
10432Sbill 	s = spl6();
10532Sbill 	if (q->c_cc <= 0) {
10632Sbill 		q->c_cc = 0;
10732Sbill 		q->c_cf = q->c_cl = NULL;
1081890Swnj 		splx(s);
10932Sbill 		return(0);
11032Sbill 	}
11132Sbill 	acp = cp;
11232Sbill 	cc++;
11332Sbill 
11432Sbill 	while (--cc) {
11532Sbill 		*cp++ = *q->c_cf++;
11632Sbill 		if (--q->c_cc <= 0) {
11732Sbill 			bp = (struct cblock *)(q->c_cf-1);
11832Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
11932Sbill 			q->c_cf = q->c_cl = NULL;
12032Sbill 			bp->c_next = cfreelist;
12132Sbill 			cfreelist = bp;
1221890Swnj 			cfreecount += CBSIZE;
1231890Swnj 			if (cwaiting) {
1241890Swnj 				wakeup(&cwaiting);
1251890Swnj 				cwaiting = 0;
1261890Swnj 			}
12732Sbill 			break;
12832Sbill 		}
12932Sbill 		if (((int)q->c_cf & CROUND) == 0) {
13032Sbill 			bp = (struct cblock *)(q->c_cf);
13132Sbill 			bp--;
13232Sbill 			q->c_cf = bp->c_next->c_info;
13332Sbill 			bp->c_next = cfreelist;
13432Sbill 			cfreelist = bp;
1351890Swnj 			cfreecount += CBSIZE;
1361890Swnj 			if (cwaiting) {
1371890Swnj 				wakeup(&cwaiting);
1381890Swnj 				cwaiting = 0;
1391890Swnj 			}
14032Sbill 		}
14132Sbill 	}
14232Sbill 	splx(s);
14332Sbill 	return(cp-acp);
14432Sbill }
14532Sbill 
1461890Swnj #if HAVTR > 0
14732Sbill /*
1481890Swnj  * Traverse a clist copying its contents to a buffer.
1491890Swnj  * q->cc and q->cf are updated with the current position
1501890Swnj  * in the list, but bytes are not released to the freelist.
1511890Swnj  */
1521890Swnj trq_to_b(q, cp, cc)
1531890Swnj register struct clist *q;
1541890Swnj register char *cp;
1551890Swnj register cc;
1561890Swnj {
1571890Swnj 	register struct cblock *bp;
1581890Swnj 	char *acp;
1591890Swnj 
1601890Swnj 	if (cc <= 0)
1611890Swnj 		return(0);
1621890Swnj 	if (q->c_cc <= 0)
1631890Swnj 		return(0);
1641890Swnj 
1651890Swnj 	acp = cp;
1661890Swnj 	cc++;
1671890Swnj 	while (--cc) {
1681890Swnj 		*cp++ = *q->c_cf++;
1691890Swnj 		if (((int)q->c_cf & CROUND) == 0) {
1701890Swnj 			bp = (struct cblock *)(q->c_cf);
1711890Swnj 			bp--;
1721890Swnj 			q->c_cf = bp->c_next->c_info;
1731890Swnj 		}
1741890Swnj 		if (--q->c_cc <= 0)
1751890Swnj 			break;
1761890Swnj 	}
1771890Swnj 	return(cp-acp);
1781890Swnj }
1791890Swnj #endif
1801890Swnj 
1811890Swnj 
1821890Swnj /*
18332Sbill  * Return count of contiguous characters
18432Sbill  * in clist starting at q->c_cf.
18532Sbill  * Stop counting if flag&character is non-null.
18632Sbill  */
18732Sbill ndqb(q, flag)
18832Sbill register struct clist *q;
18932Sbill {
19032Sbill register cc;
19132Sbill int s;
19232Sbill 
19332Sbill 	s = spl6();
19432Sbill 	if (q->c_cc <= 0) {
19532Sbill 		cc = -q->c_cc;
19632Sbill 		goto out;
19732Sbill 	}
19832Sbill 	cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
19932Sbill 	cc -= (int)q->c_cf;
20032Sbill 	if (q->c_cc < cc)
20132Sbill 		cc = q->c_cc;
20232Sbill 	if (flag) {
20332Sbill 		register char *p, *end;
20432Sbill 
20532Sbill 		p = q->c_cf;
20632Sbill 		end = p;
20732Sbill 		end += cc;
20832Sbill 		while (p < end) {
20932Sbill 			if (*p & flag) {
2101890Swnj 				cc = (int)p;
2111890Swnj 				cc -= (int)q->c_cf;
21232Sbill 				break;
21332Sbill 			}
21432Sbill 			p++;
21532Sbill 		}
21632Sbill 	}
21732Sbill out:
21832Sbill 	splx(s);
21932Sbill 	return(cc);
22032Sbill }
22132Sbill 
2221890Swnj 
2231890Swnj 
22432Sbill /*
2251890Swnj  * Flush cc bytes from q.
22632Sbill  */
22732Sbill ndflush(q, cc)
22832Sbill register struct clist *q;
22932Sbill register cc;
23032Sbill {
2311890Swnj register struct cblock *bp;
2321890Swnj char *end;
2331890Swnj int rem;
23432Sbill register s;
23532Sbill 
23632Sbill 	s = spl6();
23732Sbill 	if (q->c_cc < 0) {
2381890Swnj 		printf("neg q flush\n");
23932Sbill 		goto out;
24032Sbill 	}
24132Sbill 	if (q->c_cc == 0) {
24232Sbill 		goto out;
24332Sbill 	}
2441890Swnj 	while (cc>0 && q->c_cc) {
2451890Swnj 		bp = (struct cblock *)((int)q->c_cf & ~CROUND);
2461890Swnj 		if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
2471890Swnj 			end = q->c_cl;
2481890Swnj 		} else {
2491890Swnj 			end = (char *)((int)bp + sizeof (struct cblock));
2501890Swnj 		}
2511890Swnj 		rem = end - q->c_cf;
2521890Swnj 		if (cc >= rem) {
2531890Swnj 			cc -= rem;
2541890Swnj 			q->c_cc -= rem;
25532Sbill 			q->c_cf = bp->c_next->c_info;
2561890Swnj 			bp->c_next = cfreelist;
2571890Swnj 			cfreelist = bp;
2581890Swnj 			cfreecount += CBSIZE;
2591890Swnj 			if (cwaiting) {
2601890Swnj 				wakeup(&cwaiting);
2611890Swnj 				cwaiting = 0;
2621890Swnj 			}
26332Sbill 		} else {
2641890Swnj 			q->c_cc -= cc;
2651890Swnj 			q->c_cf += cc;
2661890Swnj 			if (q->c_cc <= 0) {
2671890Swnj 				bp->c_next = cfreelist;
2681890Swnj 				cfreelist = bp;
2691890Swnj 				cfreecount += CBSIZE;
2701890Swnj 				if (cwaiting) {
2711890Swnj 					wakeup(&cwaiting);
2721890Swnj 					cwaiting = 0;
2731890Swnj 				}
2741890Swnj 			}
2751890Swnj 			break;
27632Sbill 		}
2771890Swnj 	}
2781890Swnj 	if (q->c_cc <= 0) {
27932Sbill 		q->c_cf = q->c_cl = NULL;
2801890Swnj 		q->c_cc = 0;
28132Sbill 	}
28232Sbill out:
28332Sbill 	splx(s);
28432Sbill }
285172Sbill 
2861890Swnj 
28732Sbill putc(c, p)
28832Sbill register struct clist *p;
28932Sbill {
29032Sbill 	register struct cblock *bp;
29132Sbill 	register char *cp;
29232Sbill 	register s;
29332Sbill 
29432Sbill 	s = spl6();
29532Sbill 	if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
29632Sbill 		if ((bp = cfreelist) == NULL) {
29732Sbill 			splx(s);
29832Sbill 			return(-1);
29932Sbill 		}
30032Sbill 		cfreelist = bp->c_next;
3011890Swnj 		cfreecount -= CBSIZE;
30232Sbill 		bp->c_next = NULL;
30332Sbill 		p->c_cf = cp = bp->c_info;
30432Sbill 	} else if (((int)cp & CROUND) == 0) {
30532Sbill 		bp = (struct cblock *)cp - 1;
30632Sbill 		if ((bp->c_next = cfreelist) == NULL) {
30732Sbill 			splx(s);
30832Sbill 			return(-1);
30932Sbill 		}
31032Sbill 		bp = bp->c_next;
31132Sbill 		cfreelist = bp->c_next;
3121890Swnj 		cfreecount -= CBSIZE;
31332Sbill 		bp->c_next = NULL;
31432Sbill 		cp = bp->c_info;
31532Sbill 	}
31632Sbill 	*cp++ = c;
31732Sbill 	p->c_cc++;
31832Sbill 	p->c_cl = cp;
31932Sbill 	splx(s);
32032Sbill 	return(0);
32132Sbill }
32232Sbill 
3231890Swnj 
3241890Swnj 
32532Sbill /*
32632Sbill  * copy buffer to clist.
32732Sbill  * return number of bytes not transfered.
32832Sbill  */
32932Sbill b_to_q(cp, cc, q)
33032Sbill register char *cp;
33132Sbill struct clist *q;
33232Sbill register int cc;
33332Sbill {
33432Sbill 	register char *cq;
33532Sbill 	register struct cblock *bp;
33632Sbill 	register s, acc;
33732Sbill 
33832Sbill 	if (cc <= 0)
33932Sbill 		return(0);
34032Sbill 	acc = cc;
3411890Swnj 
3421890Swnj 
34332Sbill 	s = spl6();
34432Sbill 	if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
34532Sbill 		if ((bp = cfreelist) == NULL)
34632Sbill 			goto out;
34732Sbill 		cfreelist = bp->c_next;
3481890Swnj 		cfreecount -= CBSIZE;
34932Sbill 		bp->c_next = NULL;
35032Sbill 		q->c_cf = cq = bp->c_info;
35132Sbill 	}
35232Sbill 
35332Sbill 	while (cc) {
35432Sbill 		if (((int)cq & CROUND) == 0) {
35532Sbill 			bp = (struct cblock *) cq - 1;
35632Sbill 			if ((bp->c_next = cfreelist) == NULL)
35732Sbill 				goto out;
35832Sbill 			bp = bp->c_next;
35932Sbill 			cfreelist = bp->c_next;
3601890Swnj 			cfreecount -= CBSIZE;
36132Sbill 			bp->c_next = NULL;
36232Sbill 			cq = bp->c_info;
36332Sbill 		}
36432Sbill 		*cq++ = *cp++;
36532Sbill 		cc--;
36632Sbill 	}
36732Sbill out:
36832Sbill 	q->c_cl = cq;
36932Sbill 	q->c_cc += acc-cc;
37032Sbill 	splx(s);
37132Sbill 	return(cc);
37232Sbill }
37332Sbill 
3741890Swnj char *
3751890Swnj wb_to_q(cp, cc, q)
3761890Swnj register char *cp;
3771890Swnj register struct clist *q;
3781890Swnj register cc;
3791890Swnj {
3801890Swnj char *f;
3811890Swnj register s;
3821890Swnj 
3831890Swnj 	s = spl6();
3841890Swnj 	while (cc > cfreecount) {
3851890Swnj 		cwaiting = 1;
3861890Swnj 		sleep(&cwaiting, TTOPRI);
3871890Swnj 	}
3881890Swnj 	if (q->c_cc==0) {
3891890Swnj 		b_to_q(cp, cc, q);
3901890Swnj 		f = q->c_cf;
3911890Swnj 	} else {
3921890Swnj 		(void) putc(*cp++, q);
3931890Swnj 		f = q->c_cl;
3941890Swnj 		f--;
3951890Swnj 		b_to_q(cp, --cc, q);
3961890Swnj 	}
3971890Swnj 	splx(s);
3981890Swnj 	return(f);
3991890Swnj }
4001890Swnj 
4011890Swnj #ifdef notdef
4021890Swnj char *
4031890Swnj nb_to_q(cp, cc, q)
4041890Swnj register char *cp;
4051890Swnj register struct clist *q;
4061890Swnj register cc;
4071890Swnj {
4081890Swnj char *f;
4091890Swnj register s;
4101890Swnj 
4111890Swnj 	s = spl6();
4121890Swnj 	if (cc > cfreecount) {
4131890Swnj 		f = NULL;
4141890Swnj 		goto out;
4151890Swnj 	}
4161890Swnj 	if (q->c_cc==0) {
4171890Swnj 		b_to_q(cp, cc, q);
4181890Swnj 		f = q->c_cf;
4191890Swnj 	} else {
4201890Swnj 		(void) putc(*cp++, q);
4211890Swnj 		f = q->c_cl;
4221890Swnj 		f--;
4231890Swnj 		b_to_q(cp, --cc, q);
4241890Swnj 	}
4251890Swnj out:
4261890Swnj 	splx(s);
4271890Swnj 	return(f);
4281890Swnj }
4291890Swnj #endif
4301890Swnj 
43132Sbill /*
432172Sbill  * Given a non-NULL pointter into the list (like c_cf which
433172Sbill  * always points to a real character if non-NULL) return the pointer
434172Sbill  * to the next character in the list or return NULL if no more chars.
435172Sbill  *
436172Sbill  * Callers must not allow getc's to happen between nextc's so that the
437172Sbill  * pointer becomes invalid.  Note that interrupts are NOT masked.
438172Sbill  */
439172Sbill char *
440172Sbill nextc(p, cp)
441172Sbill register struct clist *p;
442172Sbill register char *cp;
443172Sbill {
444172Sbill 
445172Sbill 	if (p->c_cc && ++cp != p->c_cl) {
446172Sbill 		if (((int)cp & CROUND) == 0)
447172Sbill 			return (((struct cblock *)cp)[-1].c_next->c_info);
448172Sbill 		return (cp);
449172Sbill 	}
450172Sbill 	return (0);
451172Sbill }
452172Sbill 
453172Sbill /*
454172Sbill  * Remove the last character in the list and return it.
455172Sbill  */
456172Sbill unputc(p)
457172Sbill register struct clist *p;
458172Sbill {
459172Sbill 	register struct cblock *bp;
460172Sbill 	register int c, s;
461172Sbill 	struct cblock *obp;
462172Sbill 
463172Sbill 	s = spl6();
464172Sbill 	if (p->c_cc <= 0)
465172Sbill 		c = -1;
466172Sbill 	else {
467172Sbill 		c = *--p->c_cl;
468172Sbill 		if (--p->c_cc <= 0) {
469172Sbill 			bp = (struct cblock *)p->c_cl;
470172Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
471172Sbill 			p->c_cl = p->c_cf = NULL;
472172Sbill 			bp->c_next = cfreelist;
473172Sbill 			cfreelist = bp;
4741890Swnj 			cfreecount += CBSIZE;
475172Sbill 		} else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) {
476172Sbill 			p->c_cl = (char *)((int)p->c_cl & ~CROUND);
477172Sbill 			bp = (struct cblock *)p->c_cf;
478172Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
479172Sbill 			while (bp->c_next != (struct cblock *)p->c_cl)
480172Sbill 				bp = bp->c_next;
481172Sbill 			obp = bp;
482172Sbill 			p->c_cl = (char *)(bp + 1);
483172Sbill 			bp = bp->c_next;
484172Sbill 			bp->c_next = cfreelist;
485172Sbill 			cfreelist = bp;
4861890Swnj 			cfreecount += CBSIZE;
487172Sbill 			obp->c_next = NULL;
488172Sbill 		}
489172Sbill 	}
490172Sbill 	splx(s);
491172Sbill 	return (c);
492172Sbill }
493172Sbill 
494172Sbill /*
495172Sbill  * Put the chars in the from que
496172Sbill  * on the end of the to que.
497172Sbill  *
498172Sbill  * SHOULD JUST USE q_to_b AND THEN b_to_q HERE.
499172Sbill  */
500172Sbill catq(from, to)
501172Sbill struct clist *from, *to;
502172Sbill {
503172Sbill 	register c;
504172Sbill 
505172Sbill 	while ((c = getc(from)) >= 0)
506172Sbill 		(void) putc(c, to);
507172Sbill }
508172Sbill 
509172Sbill /*
51032Sbill  * Initialize clist by freeing all character blocks, then count
51132Sbill  * number of character devices. (Once-only routine)
51232Sbill  */
51332Sbill cinit()
51432Sbill {
51532Sbill 	register int ccp;
51632Sbill 	register struct cblock *cp;
51732Sbill 	register struct cdevsw *cdp;
51832Sbill 
51932Sbill 	ccp = (int)cfree;
52032Sbill 	ccp = (ccp+CROUND) & ~CROUND;
5211890Swnj 	for(cp=(struct cblock *)ccp; cp < &cfree[NCLIST-1]; cp++) {
52232Sbill 		cp->c_next = cfreelist;
52332Sbill 		cfreelist = cp;
5241890Swnj 		cfreecount += CBSIZE;
52532Sbill 	}
52632Sbill 	ccp = 0;
52732Sbill 	for(cdp = cdevsw; cdp->d_open; cdp++)
52832Sbill 		ccp++;
52932Sbill 	nchrdev = ccp;
53032Sbill }
53132Sbill 
5321890Swnj 
53332Sbill /*
53432Sbill  * integer (2-byte) get/put
53532Sbill  * using clists
53632Sbill  */
53732Sbill getw(p)
53832Sbill register struct clist *p;
53932Sbill {
54032Sbill 	register int s;
54132Sbill 
54232Sbill 	if (p->c_cc <= 1)
54332Sbill 		return(-1);
54432Sbill 	s = getc(p);
54532Sbill 	return(s | (getc(p)<<8));
54632Sbill }
54732Sbill 
5481890Swnj #if HAVTR > 0
5491890Swnj trgetw(p)
5501890Swnj register struct clist *p;
5511890Swnj {
5521890Swnj 	register int w;
5531890Swnj 
5541890Swnj 	if (p->c_cc <=1)
5551890Swnj 		return(-1);
5561890Swnj 	w = trgetc(p);
5571890Swnj 	return(w | (trgetc(p)<<8));
5581890Swnj }
5591890Swnj #endif
5601890Swnj 
56132Sbill putw(c, p)
56232Sbill register struct clist *p;
56332Sbill {
56432Sbill 	register s;
56532Sbill 
56632Sbill 	s = spl6();
56732Sbill 	if (cfreelist==NULL) {
56832Sbill 		splx(s);
56932Sbill 		return(-1);
57032Sbill 	}
571130Sbill 	(void) putc(c, p);
572130Sbill 	(void) putc(c>>8, p);
57332Sbill 	splx(s);
57432Sbill 	return(0);
57532Sbill }
576