tty_subr.c revision 1.1.4.1 1 /*
2 * Copyright (c) 1993 Theo de Raadt
3 * All rights reserved.
4 *
5 * Per Lindqvist <pgd (at) compuram.bbt.se> supplied an almost fully working
6 * set of true clist functions that this is very loosely based on.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Theo de Raadt.
19 * 4. The name of Theo de Raadt may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * $Id: tty_subr.c,v 1.1.4.1 1993/09/24 08:51:49 mycroft Exp $
23 */
24
25 #include "param.h"
26 #include "systm.h"
27 #include "buf.h"
28 #include "ioctl.h"
29 #include "tty.h"
30 #include "clist.h"
31 #include "malloc.h"
32
33 #include "machine/cpu.h"
34
35 /*
36 * At compile time, choose:
37 * There are two ways the TTY_QUOTE bit can be stored. If QBITS is
38 * defined we allocate an array of bits -- 1/8th as much memory but
39 * setbit(), clrbit(), and isset() take more cpu. If QBITS is
40 * undefined, we just use an array of bytes.
41 *
42 * If TTY_QUOTE functionality isn't required by a line discipline,
43 * it can free c_cq and set it to NULL. This speeds things up,
44 * and also does not use any extra memory. This is useful for (say)
45 * a SLIP line discipline that wants a 32K ring buffer for data
46 * but doesn't need quoting.
47 */
48 #define QBITS
49
50 #ifdef QBITS
51 #define QMEM(n) ((((n)-1)/NBBY)+1)
52 #else
53 #define QMEM(n) (n)
54 #endif
55
56
57 /*
58 * Initialize clists.
59 */
60 void
61 cinit()
62 {
63 }
64
65 /*
66 * Initialize a particular clist. Ok, they are really ring buffers,
67 * of the specified length, with/without quoting support.
68 */
69 int
70 clalloc(clp, size, quot)
71 struct clist *clp;
72 int size;
73 int quot;
74 {
75
76 MALLOC(clp->c_cs, u_char *, size, M_TTYS, M_WAITOK);
77 if (!clp->c_cs)
78 return (-1);
79 bzero(clp->c_cs, size);
80
81 if(quot) {
82 MALLOC(clp->c_cq, u_char *, QMEM(size), M_TTYS, M_WAITOK);
83 if (!clp->c_cq) {
84 FREE(clp->c_cs, M_TTYS);
85 return (-1);
86 }
87 bzero(clp->c_cs, QMEM(size));
88 } else
89 clp->c_cq = (u_char *)0;
90
91 clp->c_cf = clp->c_cl = (u_char *)0;
92 clp->c_ce = clp->c_cs + size;
93 clp->c_cn = size;
94 clp->c_cc = 0;
95 return (0);
96 }
97
98 void
99 clfree(clp)
100 struct clist *clp;
101 {
102 if(clp->c_cs)
103 FREE(clp->c_cs, M_TTYS);
104 if(clp->c_cq)
105 FREE(clp->c_cq, M_TTYS);
106 clp->c_cs = clp->c_cq = (u_char *)0;
107 }
108
109
110 /*
111 * Get a character from a clist.
112 */
113 int
114 getc(clp)
115 struct clist *clp;
116 {
117 register int c = -1;
118 int s;
119
120 s = spltty();
121 if (clp->c_cc == 0)
122 goto out;
123
124 c = *clp->c_cf & 0xff;
125 if (clp->c_cq) {
126 #ifdef QBITS
127 if (isset(clp->c_cq, clp->c_cf - clp->c_cs) )
128 c |= TTY_QUOTE;
129 #else
130 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
131 c |= TTY_QUOTE;
132 #endif
133 }
134 if (++clp->c_cf == clp->c_ce)
135 clp->c_cf = clp->c_cs;
136 if (--clp->c_cc == 0)
137 clp->c_cf = clp->c_cl = (u_char *)0;
138 out:
139 splx(s);
140 return c;
141 }
142
143 /*
144 * Copy clist to buffer.
145 * Return number of bytes moved.
146 */
147 int
148 q_to_b(clp, cp, count)
149 struct clist *clp;
150 u_char *cp;
151 int count;
152 {
153 register int cc;
154 u_char *p = cp;
155 int s;
156
157 s = spltty();
158 /* optimize this while loop */
159 while (count > 0 && clp->c_cc > 0) {
160 cc = clp->c_cl - clp->c_cf;
161 if (clp->c_cf >= clp->c_cl)
162 cc = clp->c_ce - clp->c_cf;
163 if (cc > count)
164 cc = count;
165 bcopy(clp->c_cf, p, cc);
166 count -= cc;
167 p += cc;
168 clp->c_cc -= cc;
169 clp->c_cf += cc;
170 if (clp->c_cf == clp->c_ce)
171 clp->c_cf = clp->c_cs;
172 }
173 if (clp->c_cc == 0)
174 clp->c_cf = clp->c_cl = (u_char *)0;
175 splx(s);
176 return p - cp;
177 }
178
179 /*
180 * Return count of contiguous characters in clist.
181 * Stop counting if flag&character is non-null.
182 */
183 ndqb(clp, flag)
184 struct clist *clp;
185 int flag;
186 {
187 int count = 0;
188 register int i;
189 register int cc;
190 int s;
191
192 s = spltty();
193 if ((cc = clp->c_cc) == 0 || flag == 0)
194 goto out;
195
196 i = clp->c_cf - clp->c_cs;
197 while (cc-- > 0 && (clp->c_cs[i++] & flag) == 0) {
198 count++;
199 if (i == clp->c_cn)
200 break;
201 }
202 out:
203 splx(s);
204 return count;
205 }
206
207 /*
208 * Flush count bytes from clist.
209 */
210 void
211 ndflush(clp, count)
212 struct clist *clp;
213 int count;
214 {
215 register int cc;
216 int s;
217
218 s = spltty();
219 if (count == clp->c_cc) {
220 clp->c_cc = 0;
221 clp->c_cf = clp->c_cl = (u_char *)0;
222 goto out;
223 }
224 /* optimize this while loop */
225 while (count > 0 && clp->c_cc > 0) {
226 cc = clp->c_cl - clp->c_cf;
227 if (clp->c_cf >= clp->c_cl)
228 cc = clp->c_ce - clp->c_cf;
229 if (cc > count)
230 cc = count;
231 count -= cc;
232 clp->c_cc -= cc;
233 clp->c_cf += cc;
234 if (clp->c_cf == clp->c_ce)
235 clp->c_cf = clp->c_cs;
236 }
237 if (clp->c_cc == 0)
238 clp->c_cf = clp->c_cl = (u_char *)0;
239 out:
240 splx(s);
241 }
242
243 /*
244 * Put a character into the output queue.
245 */
246 int
247 putc(c, clp)
248 int c;
249 struct clist *clp;
250 {
251 register u_char *q;
252 register int i;
253 int r = -1;
254 int s;
255
256 s = spltty();
257 if (clp->c_cc == clp->c_cn)
258 goto out;
259
260 if (clp->c_cc == 0) {
261 if (!clp->c_cs) {
262 #if defined(DIAGNOSTIC) || 1
263 printf("b_to_q: required clalloc\n");
264 #endif
265 if(clalloc(clp, 1024, 1)) {
266 out:
267 splx(s);
268 return -1;
269 }
270 }
271 clp->c_cf = clp->c_cl = clp->c_cs;
272 }
273
274 *clp->c_cl = c & 0xff;
275 i = clp->c_cl - clp->c_cs;
276 if (clp->c_cq) {
277 #ifdef QBITS
278 if (c & TTY_QUOTE)
279 setbit(clp->c_cq, i);
280 else
281 clrbit(clp->c_cq, i);
282 #else
283 q = clp->c_cq + i;
284 *q = (c & TTY_QUOTE) ? 1 : 0;
285 #endif
286 }
287 clp->c_cc++;
288 clp->c_cl++;
289 if (clp->c_cl == clp->c_ce)
290 clp->c_cl = clp->c_cs;
291 splx(s);
292 return 0;
293 }
294
295 #ifdef QBITS
296 /*
297 * optimized version of
298 *
299 * for (i = 0; i < len; i++)
300 * clrbit(cp, off + len);
301 */
302 void
303 clrbits(cp, off, len)
304 u_char *cp;
305 int off;
306 int len;
307 {
308 int sby, sbi, eby, ebi;
309 register int i;
310 u_char mask;
311
312 if(len==1) {
313 clrbit(cp, off);
314 return;
315 }
316
317 sby = off / NBBY;
318 sbi = off % NBBY;
319 eby = (off+len) / NBBY;
320 ebi = (off+len) % NBBY;
321 if (sby == eby) {
322 mask = ((1 << (ebi - sbi)) - 1) << sbi;
323 cp[sby] &= ~mask;
324 } else {
325 mask = (1<<sbi) - 1;
326 cp[sby++] &= mask;
327
328 mask = (1<<ebi) - 1;
329 cp[eby] &= ~mask;
330
331 for (i = sby; i < eby; i++)
332 cp[i] = 0x00;
333 }
334 }
335 #endif
336
337 /*
338 * Copy buffer to clist.
339 * Return number of bytes not transfered.
340 */
341 int
342 b_to_q(cp, count, clp)
343 u_char *cp;
344 int count;
345 struct clist *clp;
346 {
347 register int i, cc;
348 register u_char *p = cp;
349 int off, s;
350
351 if (count <= 0)
352 return 0;
353
354 s = spltty();
355 if (clp->c_cc == clp->c_cn)
356 goto out;
357
358 if (clp->c_cc == 0) {
359 if (!clp->c_cs) {
360 #if defined(DIAGNOSTIC) || 1
361 printf("b_to_q: required clalloc\n");
362 #endif
363 if(clalloc(clp, 1024, 1))
364 goto out;
365 }
366 clp->c_cf = clp->c_cl = clp->c_cs;
367 }
368
369 /* optimize this while loop */
370 while (count > 0 && clp->c_cc < clp->c_cn) {
371 cc = clp->c_ce - clp->c_cl;
372 if (clp->c_cf > clp->c_cl)
373 cc = clp->c_cf - clp->c_cl;
374 if (cc > count)
375 cc = count;
376 bcopy(p, clp->c_cl, cc);
377 if (clp->c_cq) {
378 #ifdef QBITS
379 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
380 #else
381 bzero(clp->c_cl - clp->c_cs + clp->c_cq, cc);
382 #endif
383 }
384 p += cc;
385 count -= cc;
386 clp->c_cc += cc;
387 clp->c_cl += cc;
388 if (clp->c_cl == clp->c_ce)
389 clp->c_cl = clp->c_cs;
390 }
391 out:
392 splx(s);
393 return count;
394 }
395
396 static int cc;
397
398 /*
399 * Given a non-NULL pointer into the clist return the pointer
400 * to the next character in the list or return NULL if no more chars.
401 *
402 * Callers must not allow getc's to happen between firstc's and getc's
403 * so that the pointer becomes invalid. Note that interrupts are NOT
404 * masked.
405 */
406 u_char *
407 nextc(clp, cp, c)
408 struct clist *clp;
409 register u_char *cp;
410 int *c;
411 {
412
413 if (clp->c_cf == cp) {
414 /*
415 * First time initialization.
416 */
417 cc = clp->c_cc;
418 }
419 if (cc == 0 || cp == NULL)
420 return NULL;
421 if (--cc == 0)
422 return NULL;
423 if (++cp == clp->c_ce)
424 cp = clp->c_cs;
425 *c = *cp & 0xff;
426 if (clp->c_cq) {
427 #ifdef QBITS
428 if (isset(clp->c_cq, cp - clp->c_cs))
429 *c |= TTY_QUOTE;
430 #else
431 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
432 *c |= TTY_QUOTE;
433 #endif
434 }
435 return cp;
436 }
437
438 /*
439 * Given a non-NULL pointer into the clist return the pointer
440 * to the first character in the list or return NULL if no more chars.
441 *
442 * Callers must not allow getc's to happen between firstc's and getc's
443 * so that the pointer becomes invalid. Note that interrupts are NOT
444 * masked.
445 *
446 * *c is set to the NEXT character
447 */
448 u_char *
449 firstc(clp, c)
450 struct clist *clp;
451 int *c;
452 {
453 int empty = 0;
454 register u_char *cp;
455 register int i;
456
457 cc = clp->c_cc;
458 if (cc == 0)
459 return NULL;
460 cp = clp->c_cf;
461 *c = *cp & 0xff;
462 if(clp->c_cq) {
463 #ifdef QBITS
464 if (isset(clp->c_cq, cp - clp->c_cs))
465 *c |= TTY_QUOTE;
466 #else
467 if (*(cp - clp->c_cs + clp->c_cq))
468 *c |= TTY_QUOTE;
469 #endif
470 }
471 return clp->c_cf;
472 }
473
474 /*
475 * Remove the last character in the clist and return it.
476 */
477 int
478 unputc(clp)
479 struct clist *clp;
480 {
481 unsigned int c = -1;
482 int s;
483
484 s = spltty();
485 if (clp->c_cc == 0)
486 goto out;
487
488 if (clp->c_cl == clp->c_cs)
489 clp->c_cl = clp->c_ce - 1;
490 else
491 --clp->c_cl;
492 clp->c_cc--;
493
494 c = *clp->c_cl & 0xff;
495 if (clp->c_cq) {
496 #ifdef QBITS
497 if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
498 c |= TTY_QUOTE;
499 #else
500 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
501 c | TTY_QUOTE;
502 #endif
503 }
504 if (clp->c_cc == 0)
505 clp->c_cf = clp->c_cl = (u_char *)0;
506 out:
507 splx(s);
508 return c;
509 }
510
511 /*
512 * Put the chars in the from queue on the end of the to queue.
513 */
514 void
515 catq(from, to)
516 struct clist *from, *to;
517 {
518 int c;
519
520 while ((c = getc(from)) != -1)
521 putc(c, to);
522 }
523