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