xref: /csrg-svn/sys/kern/tty_subr.c (revision 1890)
132Sbill #include "../h/param.h"
232Sbill #include "../h/systm.h"
332Sbill #include "../h/conf.h"
432Sbill #include "../h/buf.h"
5*1890Swnj #include "../h/tty.h"
632Sbill 
732Sbill struct cblock {
8*1890Swnj 	struct	cblock *c_next;
932Sbill 	char	c_info[CBSIZE];
1032Sbill };
1132Sbill 
12*1890Swnj struct	cblock cfree[NCLIST];
13*1890Swnj struct	cblock *cfreelist;
1432Sbill 
15*1890Swnj int	cfreecount;
16*1890Swnj char	cwaiting;
17*1890Swnj 
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;
41*1890Swnj 			cfreecount += CBSIZE;
42*1890Swnj 			if (cwaiting) {
43*1890Swnj 				wakeup(&cwaiting);
44*1890Swnj 				cwaiting = 0;
45*1890Swnj 			}
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;
52*1890Swnj 			cfreecount += CBSIZE;
53*1890Swnj 			if (cwaiting) {
54*1890Swnj 				wakeup(&cwaiting);
55*1890Swnj 				cwaiting = 0;
56*1890Swnj 			}
5732Sbill 		}
5832Sbill 	}
5932Sbill 	splx(s);
6032Sbill 	return(c);
6132Sbill }
6232Sbill 
63*1890Swnj #if HAVTR > 0
64*1890Swnj trgetc(p)
65*1890Swnj register struct clist *p;
66*1890Swnj {
67*1890Swnj 	register struct cblock *bp;
68*1890Swnj 	register int c, s;
69*1890Swnj 
70*1890Swnj 	if (p->c_cc <= 0) {
71*1890Swnj 		c = -1;
72*1890Swnj 		p->c_cc = 0;
73*1890Swnj 		p->c_cf = NULL;
74*1890Swnj 	} else {
75*1890Swnj 		c = *p->c_cf++ & 0377;
76*1890Swnj 		if (--p->c_cc<=0) {
77*1890Swnj 			p->c_cf = NULL;
78*1890Swnj 		} else if (((int)p->c_cf & CROUND) == 0) {
79*1890Swnj 			bp = (struct cblock *)(p->c_cf);
80*1890Swnj 			bp--;
81*1890Swnj 			p->c_cf = bp->c_next->c_info;
82*1890Swnj 		}
83*1890Swnj 	}
84*1890Swnj 	return(c);
85*1890Swnj }
86*1890Swnj #endif
87*1890Swnj 
8832Sbill /*
8932Sbill  * copy clist to buffer.
9032Sbill  * return number of bytes moved.
9132Sbill  */
9232Sbill q_to_b(q, cp, cc)
9332Sbill register struct clist *q;
9432Sbill register char *cp;
9532Sbill {
9632Sbill 	register struct cblock *bp;
9732Sbill 	register int s;
9832Sbill 	char *acp;
9932Sbill 
10032Sbill 	if (cc <= 0)
10132Sbill 		return(0);
10232Sbill 	s = spl6();
10332Sbill 	if (q->c_cc <= 0) {
10432Sbill 		q->c_cc = 0;
10532Sbill 		q->c_cf = q->c_cl = NULL;
106*1890Swnj 		splx(s);
10732Sbill 		return(0);
10832Sbill 	}
10932Sbill 	acp = cp;
11032Sbill 	cc++;
11132Sbill 
11232Sbill 	while (--cc) {
11332Sbill 		*cp++ = *q->c_cf++;
11432Sbill 		if (--q->c_cc <= 0) {
11532Sbill 			bp = (struct cblock *)(q->c_cf-1);
11632Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
11732Sbill 			q->c_cf = q->c_cl = NULL;
11832Sbill 			bp->c_next = cfreelist;
11932Sbill 			cfreelist = bp;
120*1890Swnj 			cfreecount += CBSIZE;
121*1890Swnj 			if (cwaiting) {
122*1890Swnj 				wakeup(&cwaiting);
123*1890Swnj 				cwaiting = 0;
124*1890Swnj 			}
12532Sbill 			break;
12632Sbill 		}
12732Sbill 		if (((int)q->c_cf & CROUND) == 0) {
12832Sbill 			bp = (struct cblock *)(q->c_cf);
12932Sbill 			bp--;
13032Sbill 			q->c_cf = bp->c_next->c_info;
13132Sbill 			bp->c_next = cfreelist;
13232Sbill 			cfreelist = bp;
133*1890Swnj 			cfreecount += CBSIZE;
134*1890Swnj 			if (cwaiting) {
135*1890Swnj 				wakeup(&cwaiting);
136*1890Swnj 				cwaiting = 0;
137*1890Swnj 			}
13832Sbill 		}
13932Sbill 	}
14032Sbill 	splx(s);
14132Sbill 	return(cp-acp);
14232Sbill }
14332Sbill 
144*1890Swnj #if HAVTR > 0
14532Sbill /*
146*1890Swnj  * Traverse a clist copying its contents to a buffer.
147*1890Swnj  * q->cc and q->cf are updated with the current position
148*1890Swnj  * in the list, but bytes are not released to the freelist.
149*1890Swnj  */
150*1890Swnj trq_to_b(q, cp, cc)
151*1890Swnj register struct clist *q;
152*1890Swnj register char *cp;
153*1890Swnj register cc;
154*1890Swnj {
155*1890Swnj 	register struct cblock *bp;
156*1890Swnj 	char *acp;
157*1890Swnj 
158*1890Swnj 	if (cc <= 0)
159*1890Swnj 		return(0);
160*1890Swnj 	if (q->c_cc <= 0)
161*1890Swnj 		return(0);
162*1890Swnj 
163*1890Swnj 	acp = cp;
164*1890Swnj 	cc++;
165*1890Swnj 	while (--cc) {
166*1890Swnj 		*cp++ = *q->c_cf++;
167*1890Swnj 		if (((int)q->c_cf & CROUND) == 0) {
168*1890Swnj 			bp = (struct cblock *)(q->c_cf);
169*1890Swnj 			bp--;
170*1890Swnj 			q->c_cf = bp->c_next->c_info;
171*1890Swnj 		}
172*1890Swnj 		if (--q->c_cc <= 0)
173*1890Swnj 			break;
174*1890Swnj 	}
175*1890Swnj 	return(cp-acp);
176*1890Swnj }
177*1890Swnj #endif
178*1890Swnj 
179*1890Swnj 
180*1890Swnj /*
18132Sbill  * Return count of contiguous characters
18232Sbill  * in clist starting at q->c_cf.
18332Sbill  * Stop counting if flag&character is non-null.
18432Sbill  */
18532Sbill ndqb(q, flag)
18632Sbill register struct clist *q;
18732Sbill {
18832Sbill register cc;
18932Sbill int s;
19032Sbill 
19132Sbill 	s = spl6();
19232Sbill 	if (q->c_cc <= 0) {
19332Sbill 		cc = -q->c_cc;
19432Sbill 		goto out;
19532Sbill 	}
19632Sbill 	cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
19732Sbill 	cc -= (int)q->c_cf;
19832Sbill 	if (q->c_cc < cc)
19932Sbill 		cc = q->c_cc;
20032Sbill 	if (flag) {
20132Sbill 		register char *p, *end;
20232Sbill 
20332Sbill 		p = q->c_cf;
20432Sbill 		end = p;
20532Sbill 		end += cc;
20632Sbill 		while (p < end) {
20732Sbill 			if (*p & flag) {
208*1890Swnj 				cc = (int)p;
209*1890Swnj 				cc -= (int)q->c_cf;
21032Sbill 				break;
21132Sbill 			}
21232Sbill 			p++;
21332Sbill 		}
21432Sbill 	}
21532Sbill out:
21632Sbill 	splx(s);
21732Sbill 	return(cc);
21832Sbill }
21932Sbill 
220*1890Swnj 
221*1890Swnj 
22232Sbill /*
223*1890Swnj  * Flush cc bytes from q.
22432Sbill  */
22532Sbill ndflush(q, cc)
22632Sbill register struct clist *q;
22732Sbill register cc;
22832Sbill {
229*1890Swnj register struct cblock *bp;
230*1890Swnj char *end;
231*1890Swnj int rem;
23232Sbill register s;
23332Sbill 
23432Sbill 	s = spl6();
23532Sbill 	if (q->c_cc < 0) {
236*1890Swnj 		printf("neg q flush\n");
23732Sbill 		goto out;
23832Sbill 	}
23932Sbill 	if (q->c_cc == 0) {
24032Sbill 		goto out;
24132Sbill 	}
242*1890Swnj 	while (cc>0 && q->c_cc) {
243*1890Swnj 		bp = (struct cblock *)((int)q->c_cf & ~CROUND);
244*1890Swnj 		if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
245*1890Swnj 			end = q->c_cl;
246*1890Swnj 		} else {
247*1890Swnj 			end = (char *)((int)bp + sizeof (struct cblock));
248*1890Swnj 		}
249*1890Swnj 		rem = end - q->c_cf;
250*1890Swnj 		if (cc >= rem) {
251*1890Swnj 			cc -= rem;
252*1890Swnj 			q->c_cc -= rem;
25332Sbill 			q->c_cf = bp->c_next->c_info;
254*1890Swnj 			bp->c_next = cfreelist;
255*1890Swnj 			cfreelist = bp;
256*1890Swnj 			cfreecount += CBSIZE;
257*1890Swnj 			if (cwaiting) {
258*1890Swnj 				wakeup(&cwaiting);
259*1890Swnj 				cwaiting = 0;
260*1890Swnj 			}
26132Sbill 		} else {
262*1890Swnj 			q->c_cc -= cc;
263*1890Swnj 			q->c_cf += cc;
264*1890Swnj 			if (q->c_cc <= 0) {
265*1890Swnj 				bp->c_next = cfreelist;
266*1890Swnj 				cfreelist = bp;
267*1890Swnj 				cfreecount += CBSIZE;
268*1890Swnj 				if (cwaiting) {
269*1890Swnj 					wakeup(&cwaiting);
270*1890Swnj 					cwaiting = 0;
271*1890Swnj 				}
272*1890Swnj 			}
273*1890Swnj 			break;
27432Sbill 		}
275*1890Swnj 	}
276*1890Swnj 	if (q->c_cc <= 0) {
27732Sbill 		q->c_cf = q->c_cl = NULL;
278*1890Swnj 		q->c_cc = 0;
27932Sbill 	}
28032Sbill out:
28132Sbill 	splx(s);
28232Sbill }
283172Sbill 
284*1890Swnj 
28532Sbill putc(c, p)
28632Sbill register struct clist *p;
28732Sbill {
28832Sbill 	register struct cblock *bp;
28932Sbill 	register char *cp;
29032Sbill 	register s;
29132Sbill 
29232Sbill 	s = spl6();
29332Sbill 	if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
29432Sbill 		if ((bp = cfreelist) == NULL) {
29532Sbill 			splx(s);
29632Sbill 			return(-1);
29732Sbill 		}
29832Sbill 		cfreelist = bp->c_next;
299*1890Swnj 		cfreecount -= CBSIZE;
30032Sbill 		bp->c_next = NULL;
30132Sbill 		p->c_cf = cp = bp->c_info;
30232Sbill 	} else if (((int)cp & CROUND) == 0) {
30332Sbill 		bp = (struct cblock *)cp - 1;
30432Sbill 		if ((bp->c_next = cfreelist) == NULL) {
30532Sbill 			splx(s);
30632Sbill 			return(-1);
30732Sbill 		}
30832Sbill 		bp = bp->c_next;
30932Sbill 		cfreelist = bp->c_next;
310*1890Swnj 		cfreecount -= CBSIZE;
31132Sbill 		bp->c_next = NULL;
31232Sbill 		cp = bp->c_info;
31332Sbill 	}
31432Sbill 	*cp++ = c;
31532Sbill 	p->c_cc++;
31632Sbill 	p->c_cl = cp;
31732Sbill 	splx(s);
31832Sbill 	return(0);
31932Sbill }
32032Sbill 
321*1890Swnj 
322*1890Swnj 
32332Sbill /*
32432Sbill  * copy buffer to clist.
32532Sbill  * return number of bytes not transfered.
32632Sbill  */
32732Sbill b_to_q(cp, cc, q)
32832Sbill register char *cp;
32932Sbill struct clist *q;
33032Sbill register int cc;
33132Sbill {
33232Sbill 	register char *cq;
33332Sbill 	register struct cblock *bp;
33432Sbill 	register s, acc;
33532Sbill 
33632Sbill 	if (cc <= 0)
33732Sbill 		return(0);
33832Sbill 	acc = cc;
339*1890Swnj 
340*1890Swnj 
34132Sbill 	s = spl6();
34232Sbill 	if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
34332Sbill 		if ((bp = cfreelist) == NULL)
34432Sbill 			goto out;
34532Sbill 		cfreelist = bp->c_next;
346*1890Swnj 		cfreecount -= CBSIZE;
34732Sbill 		bp->c_next = NULL;
34832Sbill 		q->c_cf = cq = bp->c_info;
34932Sbill 	}
35032Sbill 
35132Sbill 	while (cc) {
35232Sbill 		if (((int)cq & CROUND) == 0) {
35332Sbill 			bp = (struct cblock *) cq - 1;
35432Sbill 			if ((bp->c_next = cfreelist) == NULL)
35532Sbill 				goto out;
35632Sbill 			bp = bp->c_next;
35732Sbill 			cfreelist = bp->c_next;
358*1890Swnj 			cfreecount -= CBSIZE;
35932Sbill 			bp->c_next = NULL;
36032Sbill 			cq = bp->c_info;
36132Sbill 		}
36232Sbill 		*cq++ = *cp++;
36332Sbill 		cc--;
36432Sbill 	}
36532Sbill out:
36632Sbill 	q->c_cl = cq;
36732Sbill 	q->c_cc += acc-cc;
36832Sbill 	splx(s);
36932Sbill 	return(cc);
37032Sbill }
37132Sbill 
372*1890Swnj char *
373*1890Swnj wb_to_q(cp, cc, q)
374*1890Swnj register char *cp;
375*1890Swnj register struct clist *q;
376*1890Swnj register cc;
377*1890Swnj {
378*1890Swnj char *f;
379*1890Swnj register s;
380*1890Swnj 
381*1890Swnj 	s = spl6();
382*1890Swnj 	while (cc > cfreecount) {
383*1890Swnj 		cwaiting = 1;
384*1890Swnj 		sleep(&cwaiting, TTOPRI);
385*1890Swnj 	}
386*1890Swnj 	if (q->c_cc==0) {
387*1890Swnj 		b_to_q(cp, cc, q);
388*1890Swnj 		f = q->c_cf;
389*1890Swnj 	} else {
390*1890Swnj 		(void) putc(*cp++, q);
391*1890Swnj 		f = q->c_cl;
392*1890Swnj 		f--;
393*1890Swnj 		b_to_q(cp, --cc, q);
394*1890Swnj 	}
395*1890Swnj 	splx(s);
396*1890Swnj 	return(f);
397*1890Swnj }
398*1890Swnj 
399*1890Swnj #ifdef notdef
400*1890Swnj char *
401*1890Swnj nb_to_q(cp, cc, q)
402*1890Swnj register char *cp;
403*1890Swnj register struct clist *q;
404*1890Swnj register cc;
405*1890Swnj {
406*1890Swnj char *f;
407*1890Swnj register s;
408*1890Swnj 
409*1890Swnj 	s = spl6();
410*1890Swnj 	if (cc > cfreecount) {
411*1890Swnj 		f = NULL;
412*1890Swnj 		goto out;
413*1890Swnj 	}
414*1890Swnj 	if (q->c_cc==0) {
415*1890Swnj 		b_to_q(cp, cc, q);
416*1890Swnj 		f = q->c_cf;
417*1890Swnj 	} else {
418*1890Swnj 		(void) putc(*cp++, q);
419*1890Swnj 		f = q->c_cl;
420*1890Swnj 		f--;
421*1890Swnj 		b_to_q(cp, --cc, q);
422*1890Swnj 	}
423*1890Swnj out:
424*1890Swnj 	splx(s);
425*1890Swnj 	return(f);
426*1890Swnj }
427*1890Swnj #endif
428*1890Swnj 
42932Sbill /*
430172Sbill  * Given a non-NULL pointter into the list (like c_cf which
431172Sbill  * always points to a real character if non-NULL) return the pointer
432172Sbill  * to the next character in the list or return NULL if no more chars.
433172Sbill  *
434172Sbill  * Callers must not allow getc's to happen between nextc's so that the
435172Sbill  * pointer becomes invalid.  Note that interrupts are NOT masked.
436172Sbill  */
437172Sbill char *
438172Sbill nextc(p, cp)
439172Sbill register struct clist *p;
440172Sbill register char *cp;
441172Sbill {
442172Sbill 
443172Sbill 	if (p->c_cc && ++cp != p->c_cl) {
444172Sbill 		if (((int)cp & CROUND) == 0)
445172Sbill 			return (((struct cblock *)cp)[-1].c_next->c_info);
446172Sbill 		return (cp);
447172Sbill 	}
448172Sbill 	return (0);
449172Sbill }
450172Sbill 
451172Sbill /*
452172Sbill  * Remove the last character in the list and return it.
453172Sbill  */
454172Sbill unputc(p)
455172Sbill register struct clist *p;
456172Sbill {
457172Sbill 	register struct cblock *bp;
458172Sbill 	register int c, s;
459172Sbill 	struct cblock *obp;
460172Sbill 
461172Sbill 	s = spl6();
462172Sbill 	if (p->c_cc <= 0)
463172Sbill 		c = -1;
464172Sbill 	else {
465172Sbill 		c = *--p->c_cl;
466172Sbill 		if (--p->c_cc <= 0) {
467172Sbill 			bp = (struct cblock *)p->c_cl;
468172Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
469172Sbill 			p->c_cl = p->c_cf = NULL;
470172Sbill 			bp->c_next = cfreelist;
471172Sbill 			cfreelist = bp;
472*1890Swnj 			cfreecount += CBSIZE;
473172Sbill 		} else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) {
474172Sbill 			p->c_cl = (char *)((int)p->c_cl & ~CROUND);
475172Sbill 			bp = (struct cblock *)p->c_cf;
476172Sbill 			bp = (struct cblock *)((int)bp & ~CROUND);
477172Sbill 			while (bp->c_next != (struct cblock *)p->c_cl)
478172Sbill 				bp = bp->c_next;
479172Sbill 			obp = bp;
480172Sbill 			p->c_cl = (char *)(bp + 1);
481172Sbill 			bp = bp->c_next;
482172Sbill 			bp->c_next = cfreelist;
483172Sbill 			cfreelist = bp;
484*1890Swnj 			cfreecount += CBSIZE;
485172Sbill 			obp->c_next = NULL;
486172Sbill 		}
487172Sbill 	}
488172Sbill 	splx(s);
489172Sbill 	return (c);
490172Sbill }
491172Sbill 
492172Sbill /*
493172Sbill  * Put the chars in the from que
494172Sbill  * on the end of the to que.
495172Sbill  *
496172Sbill  * SHOULD JUST USE q_to_b AND THEN b_to_q HERE.
497172Sbill  */
498172Sbill catq(from, to)
499172Sbill struct clist *from, *to;
500172Sbill {
501172Sbill 	register c;
502172Sbill 
503172Sbill 	while ((c = getc(from)) >= 0)
504172Sbill 		(void) putc(c, to);
505172Sbill }
506172Sbill 
507172Sbill /*
50832Sbill  * Initialize clist by freeing all character blocks, then count
50932Sbill  * number of character devices. (Once-only routine)
51032Sbill  */
51132Sbill cinit()
51232Sbill {
51332Sbill 	register int ccp;
51432Sbill 	register struct cblock *cp;
51532Sbill 	register struct cdevsw *cdp;
51632Sbill 
51732Sbill 	ccp = (int)cfree;
51832Sbill 	ccp = (ccp+CROUND) & ~CROUND;
519*1890Swnj 	for(cp=(struct cblock *)ccp; cp < &cfree[NCLIST-1]; cp++) {
52032Sbill 		cp->c_next = cfreelist;
52132Sbill 		cfreelist = cp;
522*1890Swnj 		cfreecount += CBSIZE;
52332Sbill 	}
52432Sbill 	ccp = 0;
52532Sbill 	for(cdp = cdevsw; cdp->d_open; cdp++)
52632Sbill 		ccp++;
52732Sbill 	nchrdev = ccp;
52832Sbill }
52932Sbill 
530*1890Swnj 
53132Sbill /*
53232Sbill  * integer (2-byte) get/put
53332Sbill  * using clists
53432Sbill  */
53532Sbill getw(p)
53632Sbill register struct clist *p;
53732Sbill {
53832Sbill 	register int s;
53932Sbill 
54032Sbill 	if (p->c_cc <= 1)
54132Sbill 		return(-1);
54232Sbill 	s = getc(p);
54332Sbill 	return(s | (getc(p)<<8));
54432Sbill }
54532Sbill 
546*1890Swnj #if HAVTR > 0
547*1890Swnj trgetw(p)
548*1890Swnj register struct clist *p;
549*1890Swnj {
550*1890Swnj 	register int w;
551*1890Swnj 
552*1890Swnj 	if (p->c_cc <=1)
553*1890Swnj 		return(-1);
554*1890Swnj 	w = trgetc(p);
555*1890Swnj 	return(w | (trgetc(p)<<8));
556*1890Swnj }
557*1890Swnj #endif
558*1890Swnj 
55932Sbill putw(c, p)
56032Sbill register struct clist *p;
56132Sbill {
56232Sbill 	register s;
56332Sbill 
56432Sbill 	s = spl6();
56532Sbill 	if (cfreelist==NULL) {
56632Sbill 		splx(s);
56732Sbill 		return(-1);
56832Sbill 	}
569130Sbill 	(void) putc(c, p);
570130Sbill 	(void) putc(c>>8, p);
57132Sbill 	splx(s);
57232Sbill 	return(0);
57332Sbill }
574