xref: /csrg-svn/sys/kern/tty_subr.c (revision 17097)
1 /*	tty_subr.c	6.3	84/08/29	*/
2 
3 #include "param.h"
4 #include "systm.h"
5 #include "conf.h"
6 #include "buf.h"
7 #include "tty.h"
8 #include "clist.h"
9 
10 char	cwaiting;
11 
12 /*
13  * Character list get/put
14  */
15 getc(p)
16 	register struct clist *p;
17 {
18 	register struct cblock *bp;
19 	register int c, s;
20 
21 	s = spl5();
22 	if (p->c_cc <= 0) {
23 		c = -1;
24 		p->c_cc = 0;
25 		p->c_cf = p->c_cl = NULL;
26 	} else {
27 		c = *p->c_cf++ & 0377;
28 		if (--p->c_cc<=0) {
29 			bp = (struct cblock *)(p->c_cf-1);
30 			bp = (struct cblock *) ((int)bp & ~CROUND);
31 			p->c_cf = NULL;
32 			p->c_cl = NULL;
33 			bp->c_next = cfreelist;
34 			cfreelist = bp;
35 			cfreecount += CBSIZE;
36 			if (cwaiting) {
37 				wakeup(&cwaiting);
38 				cwaiting = 0;
39 			}
40 		} else if (((int)p->c_cf & CROUND) == 0){
41 			bp = (struct cblock *)(p->c_cf);
42 			bp--;
43 			p->c_cf = bp->c_next->c_info;
44 			bp->c_next = cfreelist;
45 			cfreelist = bp;
46 			cfreecount += CBSIZE;
47 			if (cwaiting) {
48 				wakeup(&cwaiting);
49 				cwaiting = 0;
50 			}
51 		}
52 	}
53 	splx(s);
54 	return(c);
55 }
56 
57 /*
58  * copy clist to buffer.
59  * return number of bytes moved.
60  */
61 q_to_b(q, cp, cc)
62 	register struct clist *q;
63 	register char *cp;
64 {
65 	register struct cblock *bp;
66 	register int s;
67 	char *acp;
68 
69 	if (cc <= 0)
70 		return(0);
71 	s = spl5();
72 	if (q->c_cc <= 0) {
73 		q->c_cc = 0;
74 		q->c_cf = q->c_cl = NULL;
75 		splx(s);
76 		return(0);
77 	}
78 	acp = cp;
79 	cc++;
80 
81 	while (--cc) {
82 		*cp++ = *q->c_cf++;
83 		if (--q->c_cc <= 0) {
84 			bp = (struct cblock *)(q->c_cf-1);
85 			bp = (struct cblock *)((int)bp & ~CROUND);
86 			q->c_cf = q->c_cl = NULL;
87 			bp->c_next = cfreelist;
88 			cfreelist = bp;
89 			cfreecount += CBSIZE;
90 			if (cwaiting) {
91 				wakeup(&cwaiting);
92 				cwaiting = 0;
93 			}
94 			break;
95 		}
96 		if (((int)q->c_cf & CROUND) == 0) {
97 			bp = (struct cblock *)(q->c_cf);
98 			bp--;
99 			q->c_cf = bp->c_next->c_info;
100 			bp->c_next = cfreelist;
101 			cfreelist = bp;
102 			cfreecount += CBSIZE;
103 			if (cwaiting) {
104 				wakeup(&cwaiting);
105 				cwaiting = 0;
106 			}
107 		}
108 	}
109 	splx(s);
110 	return(cp-acp);
111 }
112 
113 /*
114  * Return count of contiguous characters
115  * in clist starting at q->c_cf.
116  * Stop counting if flag&character is non-null.
117  */
118 ndqb(q, flag)
119 	register struct clist *q;
120 {
121 	register cc;
122 	int s;
123 
124 	s = spl5();
125 	if (q->c_cc <= 0) {
126 		cc = -q->c_cc;
127 		goto out;
128 	}
129 	cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
130 	cc -= (int)q->c_cf;
131 	if (q->c_cc < cc)
132 		cc = q->c_cc;
133 	if (flag) {
134 		register char *p, *end;
135 
136 		p = q->c_cf;
137 		end = p;
138 		end += cc;
139 		while (p < end) {
140 			if (*p & flag) {
141 				cc = (int)p;
142 				cc -= (int)q->c_cf;
143 				break;
144 			}
145 			p++;
146 		}
147 	}
148 out:
149 	splx(s);
150 	return(cc);
151 }
152 
153 
154 
155 /*
156  * Flush cc bytes from q.
157  */
158 ndflush(q, cc)
159 	register struct clist *q;
160 	register cc;
161 {
162 	register struct cblock *bp;
163 	char *end;
164 	int rem, s;
165 
166 	s = spl5();
167 	if (q->c_cc <= 0) {
168 		goto out;
169 	}
170 	while (cc>0 && q->c_cc) {
171 		bp = (struct cblock *)((int)q->c_cf & ~CROUND);
172 		if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
173 			end = q->c_cl;
174 		} else {
175 			end = (char *)((int)bp + sizeof (struct cblock));
176 		}
177 		rem = end - q->c_cf;
178 		if (cc >= rem) {
179 			cc -= rem;
180 			q->c_cc -= rem;
181 			q->c_cf = bp->c_next->c_info;
182 			bp->c_next = cfreelist;
183 			cfreelist = bp;
184 			cfreecount += CBSIZE;
185 			if (cwaiting) {
186 				wakeup(&cwaiting);
187 				cwaiting = 0;
188 			}
189 		} else {
190 			q->c_cc -= cc;
191 			q->c_cf += cc;
192 			if (q->c_cc <= 0) {
193 				bp->c_next = cfreelist;
194 				cfreelist = bp;
195 				cfreecount += CBSIZE;
196 				if (cwaiting) {
197 					wakeup(&cwaiting);
198 					cwaiting = 0;
199 				}
200 			}
201 			break;
202 		}
203 	}
204 	if (q->c_cc <= 0) {
205 		q->c_cf = q->c_cl = NULL;
206 		q->c_cc = 0;
207 	}
208 out:
209 	splx(s);
210 }
211 
212 
213 putc(c, p)
214 	register struct clist *p;
215 {
216 	register struct cblock *bp;
217 	register char *cp;
218 	register s;
219 
220 	s = spl5();
221 	if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
222 		if ((bp = cfreelist) == NULL) {
223 			splx(s);
224 			return(-1);
225 		}
226 		cfreelist = bp->c_next;
227 		cfreecount -= CBSIZE;
228 		bp->c_next = NULL;
229 		p->c_cf = cp = bp->c_info;
230 	} else if (((int)cp & CROUND) == 0) {
231 		bp = (struct cblock *)cp - 1;
232 		if ((bp->c_next = cfreelist) == NULL) {
233 			splx(s);
234 			return(-1);
235 		}
236 		bp = bp->c_next;
237 		cfreelist = bp->c_next;
238 		cfreecount -= CBSIZE;
239 		bp->c_next = NULL;
240 		cp = bp->c_info;
241 	}
242 	*cp++ = c;
243 	p->c_cc++;
244 	p->c_cl = cp;
245 	splx(s);
246 	return(0);
247 }
248 
249 
250 
251 /*
252  * copy buffer to clist.
253  * return number of bytes not transfered.
254  */
255 b_to_q(cp, cc, q)
256 	register char *cp;
257 	struct clist *q;
258 	register int cc;
259 {
260 	register char *cq;
261 	register struct cblock *bp;
262 	register s, acc;
263 
264 	if (cc <= 0)
265 		return(0);
266 	acc = cc;
267 
268 
269 	s = spl5();
270 	if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
271 		if ((bp = cfreelist) == NULL)
272 			goto out;
273 		cfreelist = bp->c_next;
274 		cfreecount -= CBSIZE;
275 		bp->c_next = NULL;
276 		q->c_cf = cq = bp->c_info;
277 	}
278 
279 	while (cc) {
280 		if (((int)cq & CROUND) == 0) {
281 			bp = (struct cblock *) cq - 1;
282 			if ((bp->c_next = cfreelist) == NULL)
283 				goto out;
284 			bp = bp->c_next;
285 			cfreelist = bp->c_next;
286 			cfreecount -= CBSIZE;
287 			bp->c_next = NULL;
288 			cq = bp->c_info;
289 		}
290 		*cq++ = *cp++;
291 		cc--;
292 	}
293 out:
294 	q->c_cl = cq;
295 	q->c_cc += acc-cc;
296 	splx(s);
297 	return(cc);
298 }
299 
300 /*
301  * Given a non-NULL pointter into the list (like c_cf which
302  * always points to a real character if non-NULL) return the pointer
303  * to the next character in the list or return NULL if no more chars.
304  *
305  * Callers must not allow getc's to happen between nextc's so that the
306  * pointer becomes invalid.  Note that interrupts are NOT masked.
307  */
308 char *
309 nextc(p, cp)
310 	register struct clist *p;
311 	register char *cp;
312 {
313 
314 	if (p->c_cc && ++cp != p->c_cl) {
315 		if (((int)cp & CROUND) == 0)
316 			return (((struct cblock *)cp)[-1].c_next->c_info);
317 		return (cp);
318 	}
319 	return (0);
320 }
321 
322 /*
323  * Remove the last character in the list and return it.
324  */
325 unputc(p)
326 	register struct clist *p;
327 {
328 	register struct cblock *bp;
329 	register int c, s;
330 	struct cblock *obp;
331 
332 	s = spl5();
333 	if (p->c_cc <= 0)
334 		c = -1;
335 	else {
336 		c = *--p->c_cl;
337 		if (--p->c_cc <= 0) {
338 			bp = (struct cblock *)p->c_cl;
339 			bp = (struct cblock *)((int)bp & ~CROUND);
340 			p->c_cl = p->c_cf = NULL;
341 			bp->c_next = cfreelist;
342 			cfreelist = bp;
343 			cfreecount += CBSIZE;
344 		} else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) {
345 			p->c_cl = (char *)((int)p->c_cl & ~CROUND);
346 			bp = (struct cblock *)p->c_cf;
347 			bp = (struct cblock *)((int)bp & ~CROUND);
348 			while (bp->c_next != (struct cblock *)p->c_cl)
349 				bp = bp->c_next;
350 			obp = bp;
351 			p->c_cl = (char *)(bp + 1);
352 			bp = bp->c_next;
353 			bp->c_next = cfreelist;
354 			cfreelist = bp;
355 			cfreecount += CBSIZE;
356 			obp->c_next = NULL;
357 		}
358 	}
359 	splx(s);
360 	return (c);
361 }
362 
363 /*
364  * Put the chars in the from que
365  * on the end of the to que.
366  *
367  * SHOULD JUST USE q_to_b AND THEN b_to_q HERE.
368  */
369 catq(from, to)
370 	struct clist *from, *to;
371 {
372 	register c;
373 
374 	while ((c = getc(from)) >= 0)
375 		(void) putc(c, to);
376 }
377 
378 /*
379  * Integer (short) get/put
380  * using clists
381  */
382 typedef	short word_t;
383 union chword {
384 	word_t	word;
385 	struct {
386 		char	Ch[sizeof (word_t)];
387 	} Cha;
388 #define	ch	Cha.Ch
389 };
390 
391 getw(p)
392 	register struct clist *p;
393 {
394 	register int i;
395 	union chword x;
396 
397 	if (p->c_cc < sizeof (word_t))
398 		return (-1);
399 	for (i = 0; i < sizeof (word_t); i++)
400 		x.ch[i] = getc(p);
401 	return (x.word);
402 }
403 
404 putw(c, p)
405 	register struct clist *p;
406 {
407 	register s;
408 	register int i;
409 	union chword x;
410 
411 	s = spl5();
412 	if (cfreelist==NULL) {
413 		splx(s);
414 		return(-1);
415 	}
416 	x.word = c;
417 	for (i = 0; i < sizeof (word_t); i++)
418 		(void) putc(x.ch[i], p);
419 	splx(s);
420 	return (0);
421 }
422