xref: /csrg-svn/sys/kern/tty_subr.c (revision 2329)
1 /*	tty_subr.c	4.5	02/01/81	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/conf.h"
6 #include "../h/buf.h"
7 #include "../h/tty.h"
8 #include "tr.h"
9 
10 struct cblock {
11 	struct	cblock *c_next;
12 	char	c_info[CBSIZE];
13 };
14 
15 struct	cblock cfree[NCLIST];
16 struct	cblock *cfreelist;
17 
18 int	cfreecount;
19 char	cwaiting;
20 
21 /*
22  * Character list get/put
23  */
24 getc(p)
25 register struct clist *p;
26 {
27 	register struct cblock *bp;
28 	register int c, s;
29 
30 	s = spl6();
31 	if (p->c_cc <= 0) {
32 		c = -1;
33 		p->c_cc = 0;
34 		p->c_cf = p->c_cl = NULL;
35 	} else {
36 		c = *p->c_cf++ & 0377;
37 		if (--p->c_cc<=0) {
38 			bp = (struct cblock *)(p->c_cf-1);
39 			bp = (struct cblock *) ((int)bp & ~CROUND);
40 			p->c_cf = NULL;
41 			p->c_cl = NULL;
42 			bp->c_next = cfreelist;
43 			cfreelist = bp;
44 			cfreecount += CBSIZE;
45 			if (cwaiting) {
46 				wakeup(&cwaiting);
47 				cwaiting = 0;
48 			}
49 		} else if (((int)p->c_cf & CROUND) == 0){
50 			bp = (struct cblock *)(p->c_cf);
51 			bp--;
52 			p->c_cf = bp->c_next->c_info;
53 			bp->c_next = cfreelist;
54 			cfreelist = bp;
55 			cfreecount += CBSIZE;
56 			if (cwaiting) {
57 				wakeup(&cwaiting);
58 				cwaiting = 0;
59 			}
60 		}
61 	}
62 	splx(s);
63 	return(c);
64 }
65 
66 #if HAVTR > 0
67 trgetc(p)
68 register struct clist *p;
69 {
70 	register struct cblock *bp;
71 	register int c, s;
72 
73 	if (p->c_cc <= 0) {
74 		c = -1;
75 		p->c_cc = 0;
76 		p->c_cf = NULL;
77 	} else {
78 		c = *p->c_cf++ & 0377;
79 		if (--p->c_cc<=0) {
80 			p->c_cf = NULL;
81 		} else if (((int)p->c_cf & CROUND) == 0) {
82 			bp = (struct cblock *)(p->c_cf);
83 			bp--;
84 			p->c_cf = bp->c_next->c_info;
85 		}
86 	}
87 	return(c);
88 }
89 #endif
90 
91 /*
92  * copy clist to buffer.
93  * return number of bytes moved.
94  */
95 q_to_b(q, cp, cc)
96 register struct clist *q;
97 register char *cp;
98 {
99 	register struct cblock *bp;
100 	register int s;
101 	char *acp;
102 
103 	if (cc <= 0)
104 		return(0);
105 	s = spl6();
106 	if (q->c_cc <= 0) {
107 		q->c_cc = 0;
108 		q->c_cf = q->c_cl = NULL;
109 		splx(s);
110 		return(0);
111 	}
112 	acp = cp;
113 	cc++;
114 
115 	while (--cc) {
116 		*cp++ = *q->c_cf++;
117 		if (--q->c_cc <= 0) {
118 			bp = (struct cblock *)(q->c_cf-1);
119 			bp = (struct cblock *)((int)bp & ~CROUND);
120 			q->c_cf = q->c_cl = NULL;
121 			bp->c_next = cfreelist;
122 			cfreelist = bp;
123 			cfreecount += CBSIZE;
124 			if (cwaiting) {
125 				wakeup(&cwaiting);
126 				cwaiting = 0;
127 			}
128 			break;
129 		}
130 		if (((int)q->c_cf & CROUND) == 0) {
131 			bp = (struct cblock *)(q->c_cf);
132 			bp--;
133 			q->c_cf = bp->c_next->c_info;
134 			bp->c_next = cfreelist;
135 			cfreelist = bp;
136 			cfreecount += CBSIZE;
137 			if (cwaiting) {
138 				wakeup(&cwaiting);
139 				cwaiting = 0;
140 			}
141 		}
142 	}
143 	splx(s);
144 	return(cp-acp);
145 }
146 
147 #if HAVTR > 0
148 /*
149  * Traverse a clist copying its contents to a buffer.
150  * q->cc and q->cf are updated with the current position
151  * in the list, but bytes are not released to the freelist.
152  */
153 trq_to_b(q, cp, cc)
154 register struct clist *q;
155 register char *cp;
156 register cc;
157 {
158 	register struct cblock *bp;
159 	char *acp;
160 
161 	if (cc <= 0)
162 		return(0);
163 	if (q->c_cc <= 0)
164 		return(0);
165 
166 	acp = cp;
167 	cc++;
168 	while (--cc) {
169 		*cp++ = *q->c_cf++;
170 		if (((int)q->c_cf & CROUND) == 0) {
171 			bp = (struct cblock *)(q->c_cf);
172 			bp--;
173 			q->c_cf = bp->c_next->c_info;
174 		}
175 		if (--q->c_cc <= 0)
176 			break;
177 	}
178 	return(cp-acp);
179 }
180 #endif
181 
182 
183 /*
184  * Return count of contiguous characters
185  * in clist starting at q->c_cf.
186  * Stop counting if flag&character is non-null.
187  */
188 ndqb(q, flag)
189 register struct clist *q;
190 {
191 register cc;
192 int s;
193 
194 	s = spl6();
195 	if (q->c_cc <= 0) {
196 		cc = -q->c_cc;
197 		goto out;
198 	}
199 	cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
200 	cc -= (int)q->c_cf;
201 	if (q->c_cc < cc)
202 		cc = q->c_cc;
203 	if (flag) {
204 		register char *p, *end;
205 
206 		p = q->c_cf;
207 		end = p;
208 		end += cc;
209 		while (p < end) {
210 			if (*p & flag) {
211 				cc = (int)p;
212 				cc -= (int)q->c_cf;
213 				break;
214 			}
215 			p++;
216 		}
217 	}
218 out:
219 	splx(s);
220 	return(cc);
221 }
222 
223 
224 
225 /*
226  * Flush cc bytes from q.
227  */
228 ndflush(q, cc)
229 register struct clist *q;
230 register cc;
231 {
232 register struct cblock *bp;
233 char *end;
234 int rem;
235 register s;
236 
237 	s = spl6();
238 	if (q->c_cc < 0) {
239 		printf("neg q flush\n");
240 		goto out;
241 	}
242 	if (q->c_cc == 0) {
243 		goto out;
244 	}
245 	while (cc>0 && q->c_cc) {
246 		bp = (struct cblock *)((int)q->c_cf & ~CROUND);
247 		if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
248 			end = q->c_cl;
249 		} else {
250 			end = (char *)((int)bp + sizeof (struct cblock));
251 		}
252 		rem = end - q->c_cf;
253 		if (cc >= rem) {
254 			cc -= rem;
255 			q->c_cc -= rem;
256 			q->c_cf = bp->c_next->c_info;
257 			bp->c_next = cfreelist;
258 			cfreelist = bp;
259 			cfreecount += CBSIZE;
260 			if (cwaiting) {
261 				wakeup(&cwaiting);
262 				cwaiting = 0;
263 			}
264 		} else {
265 			q->c_cc -= cc;
266 			q->c_cf += cc;
267 			if (q->c_cc <= 0) {
268 				bp->c_next = cfreelist;
269 				cfreelist = bp;
270 				cfreecount += CBSIZE;
271 				if (cwaiting) {
272 					wakeup(&cwaiting);
273 					cwaiting = 0;
274 				}
275 			}
276 			break;
277 		}
278 	}
279 	if (q->c_cc <= 0) {
280 		q->c_cf = q->c_cl = NULL;
281 		q->c_cc = 0;
282 	}
283 out:
284 	splx(s);
285 }
286 
287 
288 putc(c, p)
289 register struct clist *p;
290 {
291 	register struct cblock *bp;
292 	register char *cp;
293 	register s;
294 
295 	s = spl6();
296 	if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
297 		if ((bp = cfreelist) == NULL) {
298 			splx(s);
299 			return(-1);
300 		}
301 		cfreelist = bp->c_next;
302 		cfreecount -= CBSIZE;
303 		bp->c_next = NULL;
304 		p->c_cf = cp = bp->c_info;
305 	} else if (((int)cp & CROUND) == 0) {
306 		bp = (struct cblock *)cp - 1;
307 		if ((bp->c_next = cfreelist) == NULL) {
308 			splx(s);
309 			return(-1);
310 		}
311 		bp = bp->c_next;
312 		cfreelist = bp->c_next;
313 		cfreecount -= CBSIZE;
314 		bp->c_next = NULL;
315 		cp = bp->c_info;
316 	}
317 	*cp++ = c;
318 	p->c_cc++;
319 	p->c_cl = cp;
320 	splx(s);
321 	return(0);
322 }
323 
324 
325 
326 /*
327  * copy buffer to clist.
328  * return number of bytes not transfered.
329  */
330 b_to_q(cp, cc, q)
331 register char *cp;
332 struct clist *q;
333 register int cc;
334 {
335 	register char *cq;
336 	register struct cblock *bp;
337 	register s, acc;
338 
339 	if (cc <= 0)
340 		return(0);
341 	acc = cc;
342 
343 
344 	s = spl6();
345 	if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
346 		if ((bp = cfreelist) == NULL)
347 			goto out;
348 		cfreelist = bp->c_next;
349 		cfreecount -= CBSIZE;
350 		bp->c_next = NULL;
351 		q->c_cf = cq = bp->c_info;
352 	}
353 
354 	while (cc) {
355 		if (((int)cq & CROUND) == 0) {
356 			bp = (struct cblock *) cq - 1;
357 			if ((bp->c_next = cfreelist) == NULL)
358 				goto out;
359 			bp = bp->c_next;
360 			cfreelist = bp->c_next;
361 			cfreecount -= CBSIZE;
362 			bp->c_next = NULL;
363 			cq = bp->c_info;
364 		}
365 		*cq++ = *cp++;
366 		cc--;
367 	}
368 out:
369 	q->c_cl = cq;
370 	q->c_cc += acc-cc;
371 	splx(s);
372 	return(cc);
373 }
374 
375 char *
376 wb_to_q(cp, cc, q)
377 register char *cp;
378 register struct clist *q;
379 register cc;
380 {
381 char *f;
382 register s;
383 
384 	s = spl6();
385 	while (cc > cfreecount) {
386 		cwaiting = 1;
387 		sleep(&cwaiting, TTOPRI);
388 	}
389 	if (q->c_cc==0) {
390 		b_to_q(cp, cc, q);
391 		f = q->c_cf;
392 	} else {
393 		(void) putc(*cp++, q);
394 		f = q->c_cl;
395 		f--;
396 		b_to_q(cp, --cc, q);
397 	}
398 	splx(s);
399 	return(f);
400 }
401 
402 #ifdef UCBIPC
403 char *
404 nb_to_q(cp, cc, q)
405 register char *cp;
406 register struct clist *q;
407 register cc;
408 {
409 char *f;
410 register s;
411 
412 	s = spl6();
413 	if (cc > cfreecount) {
414 		f = NULL;
415 		goto out;
416 	}
417 	if (q->c_cc==0) {
418 		b_to_q(cp, cc, q);
419 		f = q->c_cf;
420 	} else {
421 		(void) putc(*cp++, q);
422 		f = q->c_cl;
423 		f--;
424 		b_to_q(cp, --cc, q);
425 	}
426 out:
427 	splx(s);
428 	return(f);
429 }
430 #endif
431 
432 /*
433  * Given a non-NULL pointter into the list (like c_cf which
434  * always points to a real character if non-NULL) return the pointer
435  * to the next character in the list or return NULL if no more chars.
436  *
437  * Callers must not allow getc's to happen between nextc's so that the
438  * pointer becomes invalid.  Note that interrupts are NOT masked.
439  */
440 char *
441 nextc(p, cp)
442 register struct clist *p;
443 register char *cp;
444 {
445 
446 	if (p->c_cc && ++cp != p->c_cl) {
447 		if (((int)cp & CROUND) == 0)
448 			return (((struct cblock *)cp)[-1].c_next->c_info);
449 		return (cp);
450 	}
451 	return (0);
452 }
453 
454 /*
455  * Remove the last character in the list and return it.
456  */
457 unputc(p)
458 register struct clist *p;
459 {
460 	register struct cblock *bp;
461 	register int c, s;
462 	struct cblock *obp;
463 
464 	s = spl6();
465 	if (p->c_cc <= 0)
466 		c = -1;
467 	else {
468 		c = *--p->c_cl;
469 		if (--p->c_cc <= 0) {
470 			bp = (struct cblock *)p->c_cl;
471 			bp = (struct cblock *)((int)bp & ~CROUND);
472 			p->c_cl = p->c_cf = NULL;
473 			bp->c_next = cfreelist;
474 			cfreelist = bp;
475 			cfreecount += CBSIZE;
476 		} else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) {
477 			p->c_cl = (char *)((int)p->c_cl & ~CROUND);
478 			bp = (struct cblock *)p->c_cf;
479 			bp = (struct cblock *)((int)bp & ~CROUND);
480 			while (bp->c_next != (struct cblock *)p->c_cl)
481 				bp = bp->c_next;
482 			obp = bp;
483 			p->c_cl = (char *)(bp + 1);
484 			bp = bp->c_next;
485 			bp->c_next = cfreelist;
486 			cfreelist = bp;
487 			cfreecount += CBSIZE;
488 			obp->c_next = NULL;
489 		}
490 	}
491 	splx(s);
492 	return (c);
493 }
494 
495 /*
496  * Put the chars in the from que
497  * on the end of the to que.
498  *
499  * SHOULD JUST USE q_to_b AND THEN b_to_q HERE.
500  */
501 catq(from, to)
502 struct clist *from, *to;
503 {
504 	register c;
505 
506 	while ((c = getc(from)) >= 0)
507 		(void) putc(c, to);
508 }
509 
510 /*
511  * Initialize clist by freeing all character blocks, then count
512  * number of character devices. (Once-only routine)
513  */
514 cinit()
515 {
516 	register int ccp;
517 	register struct cblock *cp;
518 	register struct cdevsw *cdp;
519 
520 	ccp = (int)cfree;
521 	ccp = (ccp+CROUND) & ~CROUND;
522 	for(cp=(struct cblock *)ccp; cp < &cfree[NCLIST-1]; cp++) {
523 		cp->c_next = cfreelist;
524 		cfreelist = cp;
525 		cfreecount += CBSIZE;
526 	}
527 	ccp = 0;
528 	for(cdp = cdevsw; cdp->d_open; cdp++)
529 		ccp++;
530 	nchrdev = ccp;
531 }
532 
533 
534 /*
535  * integer (2-byte) get/put
536  * using clists
537  */
538 getw(p)
539 register struct clist *p;
540 {
541 	register int s;
542 
543 	if (p->c_cc <= 1)
544 		return(-1);
545 	s = getc(p);
546 	return(s | (getc(p)<<8));
547 }
548 
549 #if HAVTR > 0
550 trgetw(p)
551 register struct clist *p;
552 {
553 	register int w;
554 
555 	if (p->c_cc <=1)
556 		return(-1);
557 	w = trgetc(p);
558 	return(w | (trgetc(p)<<8));
559 }
560 #endif
561 
562 putw(c, p)
563 register struct clist *p;
564 {
565 	register s;
566 
567 	s = spl6();
568 	if (cfreelist==NULL) {
569 		splx(s);
570 		return(-1);
571 	}
572 	(void) putc(c, p);
573 	(void) putc(c>>8, p);
574 	splx(s);
575 	return(0);
576 }
577