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