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